@davidwells/extract-deps 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/examples/verify-basic.js +43 -0
- package/examples/verify-build-graph.js +58 -0
- package/examples/verify-build-order.js +113 -0
- package/examples/verify-find-dependents.js +74 -0
- package/examples/verify-impact-analysis.js +97 -0
- package/package.json +5 -1
- package/src/dep-graph.js +277 -0
- package/src/get-cjs-exports.js +3 -30
- package/src/get-exports.js +38 -40
- package/src/utils.js +41 -1
- package/tests/dep-graph.test.js +213 -0
- package/tests/fixtures/cjs-deep-example/d-one.js +10 -0
- package/tests/fixtures/cjs-deep-example/d-sub-folder/d-sub-sub-folder/d-three.js +7 -0
- package/tests/fixtures/cjs-deep-example/d-sub-folder/d-two-a.js +8 -0
- package/tests/fixtures/cjs-deep-example/d-sub-folder/d-two-b.js +8 -0
- package/tests/fixtures/cjs-deep-example/d-sub-folder/d-two.js +8 -0
- package/tests/fixtures/cjs-deep-example/index.js +8 -0
- package/tests/fixtures/cjs-example/index.js +8 -0
- package/tests/fixtures/cjs-example/one.js +9 -0
- package/tests/fixtures/cjs-example/sub-folder/sub-sub-folder/three.js +6 -0
- package/tests/fixtures/cjs-example/sub-folder/two.js +8 -0
- package/tests/fixtures/cjs-parent.js +5 -0
- package/tests/fixtures/esm-fixture/index.js +8 -0
- package/tests/fixtures/esm-fixture/one.js +9 -0
- package/tests/fixtures/esm-fixture/sub-folder/sub-sub-folder/three.js +6 -0
- package/tests/fixtures/esm-fixture/sub-folder/two.js +8 -0
- package/tests/get-cjs-exports.test.js +53 -1
- package/tests/get-exports.test.js +162 -10
- package/types/dep-graph.d.ts +22 -0
- package/types/dep-graph.d.ts.map +1 -0
- package/types/get-cjs-exports.d.ts +35 -0
- package/types/get-cjs-exports.d.ts.map +1 -0
- package/types/get-exports.d.ts +3 -1
- package/types/get-exports.d.ts.map +1 -1
- package/types/index.d.ts +7 -3
- package/types/index.d.ts.map +1 -1
- package/types/utils.d.ts +2 -1
- package/types/utils.d.ts.map +1 -1
package/src/get-cjs-exports.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Extracts CommonJS module.exports and exports patterns from JavaScript code
|
|
2
2
|
|
|
3
|
-
const { getNames } = require('./utils')
|
|
3
|
+
const { getNames, extractExportName } = require('./utils')
|
|
4
4
|
|
|
5
5
|
// Matches: module.exports = ... or exports = module.exports = ...
|
|
6
6
|
// https://regex101.com/r/example/cjs-1
|
|
@@ -54,33 +54,6 @@ function getCjsExports(code) {
|
|
|
54
54
|
return allExports.sort((a, b) => a.index - b.index)
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
function extractExportDefName(exportValue) {
|
|
58
|
-
// Handle function declarations
|
|
59
|
-
if (exportValue.includes('function') && !exportValue.includes('=>')) {
|
|
60
|
-
const match = exportValue.match(/function\s+([\w$]+)/)
|
|
61
|
-
return match ? match[1] : 'anonymous'
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Handle class declarations
|
|
65
|
-
if (exportValue.includes('class')) {
|
|
66
|
-
const match = exportValue.match(/class\s+([\w$]+)/)
|
|
67
|
-
return match ? match[1] : 'anonymous'
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Handle arrow functions
|
|
71
|
-
if (exportValue.includes('=>')) {
|
|
72
|
-
return 'anonymous'
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Handle object/array literals
|
|
76
|
-
if (exportValue.startsWith('{') || exportValue.startsWith('[')) {
|
|
77
|
-
return 'literal'
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Handle simple values
|
|
81
|
-
return exportValue.trim()
|
|
82
|
-
}
|
|
83
|
-
|
|
84
57
|
function extractCompleteValue(text, startIndex) {
|
|
85
58
|
const firstChar = text[startIndex]
|
|
86
59
|
|
|
@@ -176,7 +149,7 @@ function getModuleExportsAssignment(originalText = '', sanitizedText = originalT
|
|
|
176
149
|
}
|
|
177
150
|
}
|
|
178
151
|
|
|
179
|
-
const exportDefName =
|
|
152
|
+
const exportDefName = extractExportName(sanitizedCompleteValue)
|
|
180
153
|
|
|
181
154
|
// Determine export type based on sanitized patterns
|
|
182
155
|
let exportType = 'default'
|
|
@@ -203,7 +176,7 @@ function getModuleExportsAssignment(originalText = '', sanitizedText = originalT
|
|
|
203
176
|
const definitions = getNames(sanitizedCompleteValue, 'definition')
|
|
204
177
|
if (definitions) {
|
|
205
178
|
exportStatement.definitions = definitions
|
|
206
|
-
exportStatement.keys = definitions.destructuredParameters.map(param => param.name)
|
|
179
|
+
exportStatement.keys = definitions.destructuredParameters.map(param => param.name.replace(/,+$/, ''))
|
|
207
180
|
}
|
|
208
181
|
}
|
|
209
182
|
|
package/src/get-exports.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const { getNames } = require('./utils')
|
|
1
|
+
const { getNames, extractExportName } = require('./utils')
|
|
2
2
|
|
|
3
3
|
// https://regex101.com/r/example/1
|
|
4
|
-
const EXPORT_DEFAULT_REGEX = /export\s+default\s+(?:function\s+([\w$]+)|class\s+([\w$]+)|([\w$]+|\([^)]*\)\s*=>|{[\s\S]*?}|\[[\s\S]*?\]|[\w$]+(?:\s*[+\-*/%]\s*[\w$]+)*))/gm
|
|
4
|
+
const EXPORT_DEFAULT_REGEX = /export\s+default\s+(?:(?:async\s+)?function\s+([\w$]+)|class\s+([\w$]+)|([\w$]+|\([^)]*\)\s*=>|{[\s\S]*?}|\[[\s\S]*?\]|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*`|[\w$]+(?:\s*[+\-*/%]\s*[\w$]+)*))/gm
|
|
5
5
|
// https://regex101.com/r/example/2
|
|
6
6
|
const EXPORT_NAMED_REGEX = /export\s+(?:const|let|var|function|class|async\s+function)\s+([\w$]+)/gm
|
|
7
7
|
// https://regex101.com/r/example/3
|
|
@@ -53,27 +53,52 @@ function getDefaultExports(targetText = '') {
|
|
|
53
53
|
var result
|
|
54
54
|
while((result = EXPORT_DEFAULT_REGEX.exec(targetText)) !== null) {
|
|
55
55
|
const [ line, functionName, className, otherValue ] = result
|
|
56
|
-
let exportName, exportValue
|
|
57
|
-
|
|
56
|
+
let exportName, exportValue, exportDefinitionName, completeLine
|
|
57
|
+
|
|
58
58
|
if (functionName) {
|
|
59
|
-
exportName =
|
|
60
|
-
|
|
59
|
+
exportName = ''
|
|
60
|
+
exportDefinitionName = functionName
|
|
61
|
+
// Extract complete line from original text (including parameters)
|
|
62
|
+
const lineStart = result.index
|
|
63
|
+
const lineEnd = targetText.indexOf('\n', lineStart)
|
|
64
|
+
completeLine = targetText.substring(lineStart, lineEnd === -1 ? targetText.length : lineEnd).trim()
|
|
65
|
+
exportValue = completeLine.replace(/^export\s+default\s+/, '')
|
|
61
66
|
} else if (className) {
|
|
62
|
-
exportName =
|
|
63
|
-
|
|
67
|
+
exportName = ''
|
|
68
|
+
exportDefinitionName = className
|
|
69
|
+
// Extract complete line from original text
|
|
70
|
+
const lineStart = result.index
|
|
71
|
+
const lineEnd = targetText.indexOf('\n', lineStart)
|
|
72
|
+
completeLine = targetText.substring(lineStart, lineEnd === -1 ? targetText.length : lineEnd).trim()
|
|
73
|
+
exportValue = completeLine.replace(/^export\s+default\s+/, '')
|
|
64
74
|
} else {
|
|
65
|
-
|
|
75
|
+
exportDefinitionName = extractExportName(otherValue)
|
|
76
|
+
exportName = ''
|
|
66
77
|
exportValue = otherValue
|
|
78
|
+
completeLine = line
|
|
67
79
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
line:
|
|
80
|
+
|
|
81
|
+
const exportStatement = {
|
|
82
|
+
line: completeLine.trim(),
|
|
71
83
|
exportType: 'default',
|
|
72
84
|
exportName,
|
|
85
|
+
exportDefinitionName,
|
|
73
86
|
exportValue: exportValue.trim(),
|
|
74
87
|
index: result.index,
|
|
75
88
|
isExport: true
|
|
76
|
-
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Parse object literals to extract definitions and keys
|
|
92
|
+
const trimmedValue = exportValue.trim()
|
|
93
|
+
if (trimmedValue.startsWith('{') && trimmedValue.endsWith('}')) {
|
|
94
|
+
const definitions = getNames(trimmedValue, 'definition')
|
|
95
|
+
if (definitions) {
|
|
96
|
+
exportStatement.definitions = definitions
|
|
97
|
+
exportStatement.keys = definitions.destructuredParameters.map(param => param.name.replace(/,+$/, ''))
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
exportStatements.push(exportStatement)
|
|
77
102
|
}
|
|
78
103
|
return exportStatements
|
|
79
104
|
}
|
|
@@ -200,33 +225,6 @@ function getAssertionExports(targetText = '') {
|
|
|
200
225
|
return exportStatements
|
|
201
226
|
}
|
|
202
227
|
|
|
203
|
-
function extractExportName(exportValue) {
|
|
204
|
-
// Handle function declarations
|
|
205
|
-
if (exportValue.includes('function') && !exportValue.includes('=>')) {
|
|
206
|
-
const match = exportValue.match(/function\s+([\w$]+)/)
|
|
207
|
-
return match ? match[1] : 'anonymous'
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// Handle class declarations
|
|
211
|
-
if (exportValue.includes('class')) {
|
|
212
|
-
const match = exportValue.match(/class\s+([\w$]+)/)
|
|
213
|
-
return match ? match[1] : 'anonymous'
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Handle arrow functions
|
|
217
|
-
if (exportValue.includes('=>')) {
|
|
218
|
-
return 'anonymous'
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Handle object/array literals
|
|
222
|
-
if (exportValue.startsWith('{') || exportValue.startsWith('[')) {
|
|
223
|
-
return 'literal'
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Handle simple values
|
|
227
|
-
return exportValue.trim()
|
|
228
|
-
}
|
|
229
|
-
|
|
230
228
|
function parseExportsList(exportsList) {
|
|
231
229
|
const exports = []
|
|
232
230
|
const items = exportsList.split(',').map(item => item.trim())
|
package/src/utils.js
CHANGED
|
@@ -155,8 +155,48 @@ function getNames(names, aliasKey = 'alias') {
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
|
|
158
|
+
function extractExportName(exportValue) {
|
|
159
|
+
// Handle function declarations
|
|
160
|
+
if (exportValue.includes('function') && !exportValue.includes('=>')) {
|
|
161
|
+
const match = exportValue.match(/function\s+([\w$]+)/)
|
|
162
|
+
return match ? match[1] : 'anonymous'
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Handle class declarations
|
|
166
|
+
if (exportValue.includes('class')) {
|
|
167
|
+
const match = exportValue.match(/class\s+([\w$]+)/)
|
|
168
|
+
return match ? match[1] : 'anonymous'
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Handle arrow functions
|
|
172
|
+
if (exportValue.includes('=>')) {
|
|
173
|
+
return 'anonymous'
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Handle object/array literals
|
|
177
|
+
if (exportValue.startsWith('{')) {
|
|
178
|
+
return 'literal-object'
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (exportValue.startsWith('[')) {
|
|
182
|
+
return 'literal-array'
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (exportValue.match(/^\d+$/)) {
|
|
186
|
+
return 'literal-number'
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (exportValue.match(/^['"]/)) {
|
|
190
|
+
return 'literal-string'
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Handle simple values
|
|
194
|
+
return exportValue.trim()
|
|
195
|
+
}
|
|
196
|
+
|
|
158
197
|
module.exports = {
|
|
159
198
|
isRelativeImport,
|
|
160
199
|
isRelativeImportWithQuotes,
|
|
161
|
-
getNames
|
|
200
|
+
getNames,
|
|
201
|
+
extractExportName
|
|
162
202
|
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
// Build and verify dependency graph
|
|
2
|
+
const { test } = require('uvu')
|
|
3
|
+
const assert = require('uvu/assert')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
const { depGraph, resolveDepPaths } = require('../src/dep-graph.js')
|
|
6
|
+
|
|
7
|
+
const CJS_FIXTURE_PATH = path.resolve(__dirname, './fixtures/cjs-example/index.js')
|
|
8
|
+
const ESM_FIXTURE_PATH = path.resolve(__dirname, './fixtures/esm-fixture/index.js')
|
|
9
|
+
const CJS_DEEP_FIXTURE_PATH = path.resolve(__dirname, './fixtures/cjs-deep-example/index.js')
|
|
10
|
+
|
|
11
|
+
test('should build graph by default', () => {
|
|
12
|
+
const graph = depGraph(CJS_FIXTURE_PATH)
|
|
13
|
+
assert.ok(graph instanceof Map, 'Should return a Map by default')
|
|
14
|
+
assert.ok(graph.size > 0, 'Graph should not be empty')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('should verify by default', () => {
|
|
18
|
+
assert.not.throws(() => {
|
|
19
|
+
depGraph(CJS_FIXTURE_PATH)
|
|
20
|
+
}, 'Should verify imports by default')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('should build graph for valid CJS fixture', () => {
|
|
24
|
+
const graph = depGraph(CJS_FIXTURE_PATH)
|
|
25
|
+
|
|
26
|
+
assert.ok(graph instanceof Map, 'Should return a Map')
|
|
27
|
+
assert.ok(graph.size > 0, 'Graph should not be empty')
|
|
28
|
+
|
|
29
|
+
const entries = Array.from(graph.keys())
|
|
30
|
+
const hasIndexFile = entries.some(key => key.includes('cjs-example/index.js'))
|
|
31
|
+
assert.ok(hasIndexFile, 'Graph should include the index.js file')
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('should build graph for valid ESM fixture', () => {
|
|
35
|
+
const graph = depGraph(ESM_FIXTURE_PATH)
|
|
36
|
+
|
|
37
|
+
assert.ok(graph instanceof Map, 'Should return a Map')
|
|
38
|
+
assert.ok(graph.size > 0, 'Graph should not be empty')
|
|
39
|
+
|
|
40
|
+
const entries = Array.from(graph.keys())
|
|
41
|
+
const hasIndexFile = entries.some(key => key.includes('esm-fixture/index.js'))
|
|
42
|
+
assert.ok(hasIndexFile, 'Graph should include the index.js file')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('should return undefined when buildGraph is false', () => {
|
|
46
|
+
const result = depGraph(CJS_FIXTURE_PATH, { buildGraph: false })
|
|
47
|
+
assert.is(result, undefined, 'Should return undefined when buildGraph is false')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('should build correct dependency graph for CJS fixture', () => {
|
|
51
|
+
const graph = depGraph(CJS_FIXTURE_PATH)
|
|
52
|
+
|
|
53
|
+
const indexPath = Array.from(graph.keys()).find(key => key.includes('cjs-example/index.js'))
|
|
54
|
+
assert.ok(indexPath, 'Should have index.js in graph')
|
|
55
|
+
|
|
56
|
+
const indexDeps = graph.get(indexPath)
|
|
57
|
+
assert.ok(Array.isArray(indexDeps), 'Dependencies should be an array')
|
|
58
|
+
assert.is(indexDeps.length, 1, 'index.js should have 1 dependency')
|
|
59
|
+
|
|
60
|
+
const hasOneDep = indexDeps.some(dep => dep.includes('one.js'))
|
|
61
|
+
assert.ok(hasOneDep, 'index.js should depend on one.js')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('should build correct dependency graph for ESM fixture', () => {
|
|
65
|
+
const graph = depGraph(ESM_FIXTURE_PATH)
|
|
66
|
+
|
|
67
|
+
const indexPath = Array.from(graph.keys()).find(key => key.includes('esm-fixture/index.js'))
|
|
68
|
+
assert.ok(indexPath, 'Should have index.js in graph')
|
|
69
|
+
|
|
70
|
+
const indexDeps = graph.get(indexPath)
|
|
71
|
+
assert.ok(Array.isArray(indexDeps), 'Dependencies should be an array')
|
|
72
|
+
assert.is(indexDeps.length, 1, 'index.js should have 1 dependency')
|
|
73
|
+
|
|
74
|
+
const hasOneDep = indexDeps.some(dep => dep.includes('one.js'))
|
|
75
|
+
assert.ok(hasOneDep, 'index.js should depend on one.js')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('should include all files in graph', () => {
|
|
79
|
+
const graph = depGraph(CJS_FIXTURE_PATH)
|
|
80
|
+
|
|
81
|
+
const filePaths = Array.from(graph.keys())
|
|
82
|
+
|
|
83
|
+
// Should have index, one, two, three
|
|
84
|
+
assert.ok(filePaths.some(p => p.includes('index.js')), 'Should include index.js')
|
|
85
|
+
assert.ok(filePaths.some(p => p.includes('one.js')), 'Should include one.js')
|
|
86
|
+
assert.ok(filePaths.some(p => p.includes('two.js')), 'Should include two.js')
|
|
87
|
+
assert.ok(filePaths.some(p => p.includes('three.js')), 'Should include three.js')
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test('should handle files with no dependencies', () => {
|
|
91
|
+
const graph = depGraph(CJS_FIXTURE_PATH)
|
|
92
|
+
|
|
93
|
+
const threePath = Array.from(graph.keys()).find(key => key.includes('three.js'))
|
|
94
|
+
assert.ok(threePath, 'Should have three.js in graph')
|
|
95
|
+
|
|
96
|
+
const threeDeps = graph.get(threePath)
|
|
97
|
+
assert.ok(Array.isArray(threeDeps), 'Dependencies should be an array')
|
|
98
|
+
assert.is(threeDeps.length, 0, 'three.js should have no dependencies')
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
test('should skip verification when verifyGraph is false', () => {
|
|
102
|
+
const graph = depGraph(CJS_FIXTURE_PATH, { verifyGraph: false })
|
|
103
|
+
|
|
104
|
+
assert.ok(graph instanceof Map, 'Should return a Map')
|
|
105
|
+
assert.ok(graph.size > 0, 'Graph should not be empty')
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
test('should work with all options combined', () => {
|
|
109
|
+
const graph = depGraph(CJS_FIXTURE_PATH, {
|
|
110
|
+
buildGraph: true,
|
|
111
|
+
verifyGraph: false,
|
|
112
|
+
throwOnFirstError: false
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
assert.ok(graph instanceof Map, 'Should return a Map')
|
|
116
|
+
assert.ok(graph.size > 0, 'Graph should not be empty')
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
// resolveDepPaths tests
|
|
120
|
+
test('resolveDepPaths should return an array', () => {
|
|
121
|
+
const deps = resolveDepPaths(CJS_FIXTURE_PATH)
|
|
122
|
+
assert.ok(Array.isArray(deps), 'Should return an array')
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
test('resolveDepPaths should return deduplicated paths', () => {
|
|
126
|
+
const deps = resolveDepPaths(CJS_DEEP_FIXTURE_PATH)
|
|
127
|
+
const uniqueDeps = [...new Set(deps)]
|
|
128
|
+
|
|
129
|
+
assert.is(deps.length, uniqueDeps.length, 'Should not have duplicate paths')
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
test('resolveDepPaths should include all files from graph', () => {
|
|
133
|
+
const graph = depGraph(CJS_FIXTURE_PATH)
|
|
134
|
+
const deps = resolveDepPaths(CJS_FIXTURE_PATH)
|
|
135
|
+
|
|
136
|
+
assert.is(deps.length, graph.size, 'Should have same number of files as graph')
|
|
137
|
+
|
|
138
|
+
// All graph keys should be in deps
|
|
139
|
+
for (const key of graph.keys()) {
|
|
140
|
+
assert.ok(deps.includes(key), `Should include ${path.basename(key)}`)
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
test('resolveDepPaths should return paths in topological order (dependencies first)', () => {
|
|
145
|
+
const deps = resolveDepPaths(CJS_FIXTURE_PATH)
|
|
146
|
+
|
|
147
|
+
// Find indices
|
|
148
|
+
const threeIdx = deps.findIndex(p => p.includes('three.js'))
|
|
149
|
+
const twoIdx = deps.findIndex(p => p.includes('two.js'))
|
|
150
|
+
const oneIdx = deps.findIndex(p => p.includes('one.js'))
|
|
151
|
+
const indexIdx = deps.findIndex(p => p.includes('index.js'))
|
|
152
|
+
|
|
153
|
+
// three.js has no dependencies, should come first
|
|
154
|
+
assert.ok(threeIdx < twoIdx, 'three.js should come before two.js')
|
|
155
|
+
assert.ok(twoIdx < oneIdx, 'two.js should come before one.js')
|
|
156
|
+
assert.ok(oneIdx < indexIdx, 'one.js should come before index.js')
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
test('resolveDepPaths should work with ESM fixtures', () => {
|
|
160
|
+
const deps = resolveDepPaths(ESM_FIXTURE_PATH)
|
|
161
|
+
|
|
162
|
+
assert.ok(Array.isArray(deps), 'Should return an array')
|
|
163
|
+
assert.ok(deps.length > 0, 'Should have dependencies')
|
|
164
|
+
|
|
165
|
+
// Check files are included
|
|
166
|
+
assert.ok(deps.some(p => p.includes('index.js')), 'Should include index.js')
|
|
167
|
+
assert.ok(deps.some(p => p.includes('one.js')), 'Should include one.js')
|
|
168
|
+
assert.ok(deps.some(p => p.includes('two.js')), 'Should include two.js')
|
|
169
|
+
assert.ok(deps.some(p => p.includes('three.js')), 'Should include three.js')
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
test('resolveDepPaths should have entry point last', () => {
|
|
173
|
+
const deps = resolveDepPaths(CJS_FIXTURE_PATH)
|
|
174
|
+
const lastFile = deps[deps.length - 1]
|
|
175
|
+
|
|
176
|
+
assert.ok(lastFile.includes('index.js'), 'Entry point (index.js) should be last')
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
test('resolveDepPaths should have leaf nodes first', () => {
|
|
180
|
+
const deps = resolveDepPaths(CJS_FIXTURE_PATH)
|
|
181
|
+
const firstFile = deps[0]
|
|
182
|
+
|
|
183
|
+
// three.js has no dependencies - it's a leaf node
|
|
184
|
+
assert.ok(firstFile.includes('three.js'), 'Leaf node (three.js) should be first')
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
test('resolveDepPaths should handle complex graphs with shared dependencies', () => {
|
|
188
|
+
const deps = resolveDepPaths(CJS_DEEP_FIXTURE_PATH)
|
|
189
|
+
|
|
190
|
+
// Should be deduplicated
|
|
191
|
+
const uniqueDeps = [...new Set(deps)]
|
|
192
|
+
assert.is(deps.length, uniqueDeps.length, 'Should deduplicate shared dependencies')
|
|
193
|
+
|
|
194
|
+
// Find d-three.js which is shared by d-two.js, d-two-a.js, d-two-b.js
|
|
195
|
+
const threeIdx = deps.findIndex(p => p.includes('d-three.js'))
|
|
196
|
+
const twoIdx = deps.findIndex(p => p.includes('d-two.js'))
|
|
197
|
+
const twoAIdx = deps.findIndex(p => p.includes('d-two-a.js'))
|
|
198
|
+
const twoBIdx = deps.findIndex(p => p.includes('d-two-b.js'))
|
|
199
|
+
|
|
200
|
+
// d-three.js should come before all files that depend on it
|
|
201
|
+
assert.ok(threeIdx < twoIdx, 'd-three.js should come before d-two.js')
|
|
202
|
+
assert.ok(threeIdx < twoAIdx, 'd-three.js should come before d-two-a.js')
|
|
203
|
+
assert.ok(threeIdx < twoBIdx, 'd-three.js should come before d-two-b.js')
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
test('resolveDepPaths should pass options to depGraph', () => {
|
|
207
|
+
const deps = resolveDepPaths(CJS_FIXTURE_PATH, { verifyGraph: false })
|
|
208
|
+
|
|
209
|
+
assert.ok(Array.isArray(deps), 'Should work with options')
|
|
210
|
+
assert.ok(deps.length > 0, 'Should return dependencies')
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
test.run()
|
|
@@ -36,7 +36,7 @@ module.exports = () => {}
|
|
|
36
36
|
assert.equal(classExport.exportValue, 'class MyClass {}')
|
|
37
37
|
|
|
38
38
|
// Check object literal
|
|
39
|
-
const objectExport = foundExports.find(exp => exp.exportDefinitionName === 'literal')
|
|
39
|
+
const objectExport = foundExports.find(exp => exp.exportDefinitionName === 'literal-object')
|
|
40
40
|
assert.ok(objectExport, 'Should find object literal export')
|
|
41
41
|
assert.equal(objectExport.exportValue, "{ foo: 'bar' }")
|
|
42
42
|
|
|
@@ -536,4 +536,56 @@ module.exports = {
|
|
|
536
536
|
assert.ok(foundExports[0].keys.includes('environment'), 'Keys should include environment')
|
|
537
537
|
})
|
|
538
538
|
|
|
539
|
+
|
|
540
|
+
test('lambda function default object', () => {
|
|
541
|
+
const code = `
|
|
542
|
+
const handler = async event => {
|
|
543
|
+
return {
|
|
544
|
+
statusCode: 200,
|
|
545
|
+
body: JSON.stringify(
|
|
546
|
+
{
|
|
547
|
+
message: 'yo function',
|
|
548
|
+
input: event,
|
|
549
|
+
},
|
|
550
|
+
null,
|
|
551
|
+
2
|
|
552
|
+
),
|
|
553
|
+
};
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
module.exports = {
|
|
557
|
+
handler,
|
|
558
|
+
}
|
|
559
|
+
`
|
|
560
|
+
|
|
561
|
+
const foundExports = getCjsExports(code)
|
|
562
|
+
console.log('foundExports', foundExports)
|
|
563
|
+
|
|
564
|
+
assert.ok(foundExports.length === 1, 'Should find 1 export')
|
|
565
|
+
assert.ok(foundExports[0].keys, 'Should have keys array')
|
|
566
|
+
assert.equal(foundExports[0].keys.length, 1, 'Should have 1 key')
|
|
567
|
+
assert.equal(foundExports[0].keys[0], 'handler', 'Key should be "handler" without trailing comma')
|
|
568
|
+
})
|
|
569
|
+
|
|
570
|
+
test('lambda function default function inline', () => {
|
|
571
|
+
const code = `
|
|
572
|
+
module.exports = async function handler(event) {
|
|
573
|
+
return {
|
|
574
|
+
statusCode: 200,
|
|
575
|
+
body: JSON.stringify({
|
|
576
|
+
message: 'yo function',
|
|
577
|
+
input: event,
|
|
578
|
+
}, null, 2),
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
`
|
|
582
|
+
|
|
583
|
+
const foundExports = getCjsExports(code)
|
|
584
|
+
console.log('foundExports', foundExports)
|
|
585
|
+
|
|
586
|
+
assert.ok(foundExports.length === 1, 'Should find 1 export')
|
|
587
|
+
assert.equal(foundExports[0].exportType, 'default', 'exportType should be default')
|
|
588
|
+
assert.equal(foundExports[0].exportName, '', 'exportName should empty because it default function')
|
|
589
|
+
})
|
|
590
|
+
|
|
539
591
|
test.run()
|