@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.
Files changed (38) hide show
  1. package/examples/verify-basic.js +43 -0
  2. package/examples/verify-build-graph.js +58 -0
  3. package/examples/verify-build-order.js +113 -0
  4. package/examples/verify-find-dependents.js +74 -0
  5. package/examples/verify-impact-analysis.js +97 -0
  6. package/package.json +5 -1
  7. package/src/dep-graph.js +277 -0
  8. package/src/get-cjs-exports.js +3 -30
  9. package/src/get-exports.js +38 -40
  10. package/src/utils.js +41 -1
  11. package/tests/dep-graph.test.js +213 -0
  12. package/tests/fixtures/cjs-deep-example/d-one.js +10 -0
  13. package/tests/fixtures/cjs-deep-example/d-sub-folder/d-sub-sub-folder/d-three.js +7 -0
  14. package/tests/fixtures/cjs-deep-example/d-sub-folder/d-two-a.js +8 -0
  15. package/tests/fixtures/cjs-deep-example/d-sub-folder/d-two-b.js +8 -0
  16. package/tests/fixtures/cjs-deep-example/d-sub-folder/d-two.js +8 -0
  17. package/tests/fixtures/cjs-deep-example/index.js +8 -0
  18. package/tests/fixtures/cjs-example/index.js +8 -0
  19. package/tests/fixtures/cjs-example/one.js +9 -0
  20. package/tests/fixtures/cjs-example/sub-folder/sub-sub-folder/three.js +6 -0
  21. package/tests/fixtures/cjs-example/sub-folder/two.js +8 -0
  22. package/tests/fixtures/cjs-parent.js +5 -0
  23. package/tests/fixtures/esm-fixture/index.js +8 -0
  24. package/tests/fixtures/esm-fixture/one.js +9 -0
  25. package/tests/fixtures/esm-fixture/sub-folder/sub-sub-folder/three.js +6 -0
  26. package/tests/fixtures/esm-fixture/sub-folder/two.js +8 -0
  27. package/tests/get-cjs-exports.test.js +53 -1
  28. package/tests/get-exports.test.js +162 -10
  29. package/types/dep-graph.d.ts +22 -0
  30. package/types/dep-graph.d.ts.map +1 -0
  31. package/types/get-cjs-exports.d.ts +35 -0
  32. package/types/get-cjs-exports.d.ts.map +1 -0
  33. package/types/get-exports.d.ts +3 -1
  34. package/types/get-exports.d.ts.map +1 -1
  35. package/types/index.d.ts +7 -3
  36. package/types/index.d.ts.map +1 -1
  37. package/types/utils.d.ts +2 -1
  38. package/types/utils.d.ts.map +1 -1
@@ -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 = extractExportDefName(sanitizedCompleteValue)
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
 
@@ -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 = functionName
60
- exportValue = `function ${functionName}`
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 = className
63
- exportValue = `class ${className}`
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
- exportName = extractExportName(otherValue)
75
+ exportDefinitionName = extractExportName(otherValue)
76
+ exportName = ''
66
77
  exportValue = otherValue
78
+ completeLine = line
67
79
  }
68
-
69
- exportStatements.push({
70
- line: line.trim(),
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()
@@ -0,0 +1,10 @@
1
+ const { two, three } = require('./d-sub-folder/d-two')
2
+ const { twoA } = require('./d-sub-folder/d-two-a')
3
+ const { twoB } = require('./d-sub-folder/d-two-b')
4
+ const one = 'one'
5
+
6
+ module.exports = {
7
+ one,
8
+ two,
9
+ three
10
+ }
@@ -0,0 +1,7 @@
1
+ const { parent } = require('../../../cjs-parent')
2
+
3
+ const three = 'three'
4
+
5
+ module.exports = {
6
+ three
7
+ }
@@ -0,0 +1,8 @@
1
+ const { three } = require('./d-sub-sub-folder/d-three')
2
+
3
+ const twoA = 'twoA'
4
+
5
+ module.exports = {
6
+ twoA,
7
+ three
8
+ }
@@ -0,0 +1,8 @@
1
+ const { three } = require('./d-sub-sub-folder/d-three')
2
+
3
+ const twoB = 'twoB'
4
+
5
+ module.exports = {
6
+ twoB,
7
+ three
8
+ }
@@ -0,0 +1,8 @@
1
+ const { three } = require('./d-sub-sub-folder/d-three')
2
+
3
+ const two = 'twoB'
4
+
5
+ module.exports = {
6
+ two,
7
+ three
8
+ }
@@ -0,0 +1,8 @@
1
+ const lodash = require('lodash')
2
+ const { one, two, three } = require('./d-one')
3
+
4
+ module.exports = {
5
+ one,
6
+ two,
7
+ three
8
+ }
@@ -0,0 +1,8 @@
1
+ const lodash = require('lodash')
2
+ const { one, two, three } = require('./one')
3
+
4
+ module.exports = {
5
+ one,
6
+ two,
7
+ three
8
+ }
@@ -0,0 +1,9 @@
1
+ const { two, three } = require('./sub-folder/two')
2
+
3
+ const one = 'one'
4
+
5
+ module.exports = {
6
+ one,
7
+ two,
8
+ three
9
+ }
@@ -0,0 +1,6 @@
1
+
2
+ const three = 'three'
3
+
4
+ module.exports = {
5
+ three
6
+ }
@@ -0,0 +1,8 @@
1
+ const { three } = require('./sub-sub-folder/three')
2
+
3
+ const two = 'two'
4
+
5
+ module.exports = {
6
+ two,
7
+ three
8
+ }
@@ -0,0 +1,5 @@
1
+ const parent = 'parent'
2
+
3
+ module.exports = {
4
+ parent
5
+ }
@@ -0,0 +1,8 @@
1
+ import lodash from 'lodash'
2
+ import { one, two, three } from './one.js'
3
+
4
+ export {
5
+ one,
6
+ two,
7
+ three
8
+ }
@@ -0,0 +1,9 @@
1
+ import { two, three } from './sub-folder/two.js'
2
+
3
+ const one = 'one'
4
+
5
+ export {
6
+ one,
7
+ two,
8
+ three
9
+ }
@@ -0,0 +1,6 @@
1
+
2
+ const three = 'three'
3
+
4
+ export {
5
+ three
6
+ }
@@ -0,0 +1,8 @@
1
+ import { three } from './sub-sub-folder/three.js'
2
+
3
+ const two = 'two'
4
+
5
+ export {
6
+ two,
7
+ three
8
+ }
@@ -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()