Skip to content

Commit ae9ef73

Browse files
committed
refactor(test): validate bundled dependencies against package.json dependencies
- Update bundle validation to read package.json dependencies field - When dependencies is empty (as it should be for library packages), ensure no external packages are bundled inline - When dependencies exist, validate each one remains external (not bundled) - For ESM bundles, detects bundled code by checking for absence of external import statements This ensures the validation is based on the package's actual dependency configuration rather than a hardcoded list.
1 parent 2245c53 commit ae9ef73

1 file changed

Lines changed: 79 additions & 33 deletions

File tree

test/bundle-validation.test.mts

Lines changed: 79 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -44,35 +44,83 @@ function hasAbsolutePaths(content: string): {
4444
}
4545

4646
/**
47-
* Check if content is missing external dependencies (they should be import/require statements).
48-
* External dependencies should NOT be bundled inline.
47+
* Check if bundle contains inlined dependencies.
48+
* Reads package.json dependencies and ensures they are NOT bundled inline.
4949
*/
50-
function checkExternalDependencies(content: string): {
51-
missingImports: string[]
52-
hasAllImports: boolean
53-
} {
54-
// Dependencies that should be external (as import/require statements).
55-
const externalDeps = ['@socketsecurity/lib']
56-
57-
const missingImports: string[] = []
58-
59-
for (const dep of externalDeps) {
60-
// Check if the bundle has import or require() statements for this dependency.
61-
// ESM: import { foo } from "@socketsecurity/lib"
62-
// CJS: require("@socketsecurity/lib")
63-
const importPattern = new RegExp(
64-
`(?:import\\s+.*?from\\s+["']${dep.replace('/', '\\/')}|require\\(["']${dep.replace('/', '\\/')}["']\\))`,
65-
)
66-
const hasImport = importPattern.test(content)
67-
68-
if (!hasImport) {
69-
missingImports.push(dep)
50+
async function checkBundledDependencies(content: string): Promise<{
51+
bundledDeps: string[]
52+
hasNoBundledDeps: boolean
53+
}> {
54+
// Read package.json to get runtime dependencies.
55+
const pkgJsonPath = path.join(packagePath, 'package.json')
56+
const pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, 'utf8'))
57+
const dependencies = pkgJson.dependencies || {}
58+
59+
const bundledDeps: string[] = []
60+
61+
// If we have NO dependencies, check that no external packages are bundled.
62+
if (Object.keys(dependencies).length === 0) {
63+
// Look for signs of bundled npm packages in ESM format.
64+
// Bundled ESM packages have patterns like:
65+
// - import { x } from "inline-bundled-code"
66+
// - Functions from external packages inlined directly.
67+
const bundledPackagePatterns = [
68+
// Socket packages that should always be external.
69+
/@socketsecurity\/lib/,
70+
/@socketsecurity\/packageurl-js/,
71+
/@socketsecurity\/sdk/,
72+
/@socketsecurity\/registry/,
73+
]
74+
75+
for (const pattern of bundledPackagePatterns) {
76+
// For ESM bundles, check if imports are to external packages (good)
77+
// vs having the code inlined (bad).
78+
// Look for: import ... from "@socketsecurity/lib" (external - good)
79+
// vs: no imports but code from the package is present (bundled - bad).
80+
const hasExternalImport = new RegExp(
81+
`import\\s+.*?from\\s+["']${pattern.source}`,
82+
).test(content)
83+
84+
// If no external import found, check if package code might be bundled.
85+
// This is a heuristic - look for multiple characteristic functions.
86+
if (!hasExternalImport) {
87+
// Check for signs of bundled code from this package.
88+
// This would mean the package wasn't properly externalized.
89+
const bundlePattern = new RegExp(
90+
`(?:var|const|let)\\s+\\w+.*${pattern.source}`,
91+
)
92+
93+
if (bundlePattern.test(content)) {
94+
bundledDeps.push(pattern.source)
95+
}
96+
}
97+
}
98+
} else {
99+
// If we have dependencies, check that they remain external (not bundled).
100+
for (const dep of Object.keys(dependencies)) {
101+
const escapedDep = dep.replace(/[/\\^$*+?.()|[\]{}]/g, '\\$&')
102+
103+
// Check if dependency is properly external.
104+
const hasExternalImport = new RegExp(
105+
`import\\s+.*?from\\s+["']${escapedDep}`,
106+
).test(content)
107+
108+
// If no external import, it might be bundled.
109+
if (!hasExternalImport) {
110+
const bundlePattern = new RegExp(
111+
`(?:var|const|let)\\s+\\w+.*${escapedDep}`,
112+
)
113+
114+
if (bundlePattern.test(content)) {
115+
bundledDeps.push(dep)
116+
}
117+
}
70118
}
71119
}
72120

73121
return {
74-
missingImports,
75-
hasAllImports: missingImports.length === 0,
122+
bundledDeps,
123+
hasNoBundledDeps: bundledDeps.length === 0,
76124
}
77125
}
78126

@@ -95,24 +143,22 @@ describe('Bundle validation', () => {
95143
)
96144
})
97145

98-
it('should have external dependencies as import/require statements', async () => {
146+
it('should not bundle dependencies inline (validate against package.json dependencies)', async () => {
99147
const indexPath = path.join(distPath, 'index.mjs')
100148
const content = await fs.readFile(indexPath, 'utf8')
101149

102-
const result = checkExternalDependencies(content)
150+
const result = await checkBundledDependencies(content)
103151

104-
if (!result.hasAllImports) {
105-
console.error(
106-
'Missing import/require statements for external dependencies:',
107-
)
108-
for (const dep of result.missingImports) {
152+
if (!result.hasNoBundledDeps) {
153+
console.error('Found bundled dependencies (should be external):')
154+
for (const dep of result.bundledDeps) {
109155
console.error(` - ${dep}`)
110156
}
111157
}
112158

113159
expect(
114-
result.hasAllImports,
115-
'All external dependencies should be import/require statements, not bundled inline',
160+
result.hasNoBundledDeps,
161+
'Dependencies from package.json should be external, not bundled inline',
116162
).toBe(true)
117163
})
118164
})

0 commit comments

Comments
 (0)