@davidwells/extract-deps 0.0.4 → 0.0.6

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 (61) hide show
  1. package/.claude/settings.local.json +7 -1
  2. package/examples/verify-basic.js +45 -0
  3. package/examples/verify-build-graph.js +58 -0
  4. package/examples/verify-build-order.js +113 -0
  5. package/examples/verify-find-dependents.js +74 -0
  6. package/examples/verify-impact-analysis.js +97 -0
  7. package/examples/verify-package-entries.js +74 -0
  8. package/package.json +6 -2
  9. package/src/dep-graph.js +337 -0
  10. package/src/get-cjs-exports.js +112 -7
  11. package/src/get-imports.js +1 -0
  12. package/src/utils.js +1 -1
  13. package/src/vendor/inspect-parameters-declaration.js +282 -0
  14. package/src/verify-package-entries.js +228 -0
  15. package/tests/dep-graph.test.js +358 -0
  16. package/tests/fixtures/cjs-broken-example/index.js +8 -0
  17. package/tests/fixtures/cjs-broken-example/one.js +9 -0
  18. package/tests/fixtures/cjs-broken-example/package.json +7 -0
  19. package/tests/fixtures/cjs-broken-example/sub-folder/sub-sub-folder/three.js +6 -0
  20. package/tests/fixtures/cjs-broken-example/sub-folder/two.js +8 -0
  21. package/tests/fixtures/cjs-deep-example/d-one.js +10 -0
  22. package/tests/fixtures/cjs-deep-example/d-sub-folder/d-sub-sub-folder/d-three.js +7 -0
  23. package/tests/fixtures/cjs-deep-example/d-sub-folder/d-two-a.js +8 -0
  24. package/tests/fixtures/cjs-deep-example/d-sub-folder/d-two-b.js +8 -0
  25. package/tests/fixtures/cjs-deep-example/d-sub-folder/d-two.js +8 -0
  26. package/tests/fixtures/cjs-deep-example/index.js +8 -0
  27. package/tests/fixtures/cjs-deep-example/package.json +15 -0
  28. package/tests/fixtures/cjs-example/index.js +8 -0
  29. package/tests/fixtures/cjs-example/one.js +9 -0
  30. package/tests/fixtures/cjs-example/package.json +7 -0
  31. package/tests/fixtures/cjs-example/sub-folder/sub-sub-folder/three.js +6 -0
  32. package/tests/fixtures/cjs-example/sub-folder/two.js +8 -0
  33. package/tests/fixtures/cjs-parent.js +5 -0
  34. package/tests/fixtures/esm-broken-fixture/index.js +8 -0
  35. package/tests/fixtures/esm-broken-fixture/one.js +9 -0
  36. package/tests/fixtures/esm-broken-fixture/package.json +15 -0
  37. package/tests/fixtures/esm-broken-fixture/sub-folder/sub-sub-folder/three.js +6 -0
  38. package/tests/fixtures/esm-broken-fixture/sub-folder/sub-sub-folder-two/deep.js +6 -0
  39. package/tests/fixtures/esm-broken-fixture/sub-folder/sub-sub-folder-two/even-deeper/wow-deep.js +5 -0
  40. package/tests/fixtures/esm-broken-fixture/sub-folder/two.js +8 -0
  41. package/tests/fixtures/esm-broken-fixture/valid.js +7 -0
  42. package/tests/fixtures/esm-fixture/index.js +8 -0
  43. package/tests/fixtures/esm-fixture/one.js +9 -0
  44. package/tests/fixtures/esm-fixture/package.json +11 -0
  45. package/tests/fixtures/esm-fixture/sub-folder/sub-sub-folder/three.js +6 -0
  46. package/tests/fixtures/esm-fixture/sub-folder/two.js +8 -0
  47. package/tests/get-cjs-exports.test.js +171 -0
  48. package/tests/get-imports.test.js +4 -1
  49. package/tests/manual/broken-cjs.js +38 -0
  50. package/tests/manual/broken-esm.js +37 -0
  51. package/tests/verify-package-entries.test.js +272 -0
  52. package/types/dep-graph.d.ts +22 -0
  53. package/types/dep-graph.d.ts.map +1 -0
  54. package/types/get-cjs-exports.d.ts +35 -0
  55. package/types/get-cjs-exports.d.ts.map +1 -0
  56. package/types/get-exports.d.ts +3 -1
  57. package/types/get-exports.d.ts.map +1 -1
  58. package/types/index.d.ts +7 -3
  59. package/types/index.d.ts.map +1 -1
  60. package/types/utils.d.ts +2 -1
  61. package/types/utils.d.ts.map +1 -1
@@ -0,0 +1,337 @@
1
+ // Build dependency graph and optionally verify imports
2
+ const path = require('path')
3
+ const fs = require('fs')
4
+ const { pathToFileURL, fileURLToPath } = require('url')
5
+ const { resolve: resolveImport } = require('@dual-bundle/import-meta-resolve')
6
+ const { extractDeps } = require('./index')
7
+
8
+ function fsExistsSync(path) {
9
+ try {
10
+ fs.accessSync(path, fs.constants.F_OK)
11
+ return true
12
+ } catch (error) {
13
+ return false
14
+ }
15
+ }
16
+
17
+ /**
18
+ * Resolve a relative import to an actual file path
19
+ * @param {string} baseDir - Directory containing the importing file
20
+ * @param {string} importPath - The relative import path
21
+ * @returns {string|null} - Resolved file path or null if not found
22
+ */
23
+ function resolveImportPath(baseDir, importPath) {
24
+ const possibleExtensions = ['.js', '.mjs', '.ts', '.json', '']
25
+
26
+ // Try direct file resolution
27
+ for (const ext of possibleExtensions) {
28
+ const testPath = path.resolve(baseDir, importPath + ext)
29
+ if (fsExistsSync(testPath)) {
30
+ return testPath
31
+ }
32
+ }
33
+
34
+ // Try directory with index file
35
+ const indexExtensions = ['/index.js', '/index.mjs', '/index.ts']
36
+ for (const indexExt of indexExtensions) {
37
+ const testPath = path.resolve(baseDir, importPath + indexExt)
38
+ if (fsExistsSync(testPath)) {
39
+ return testPath
40
+ }
41
+ }
42
+
43
+ return null
44
+ }
45
+
46
+ /**
47
+ * Verify that imported values are exported from a file
48
+ * @param {object} dep - Dependency object with import info
49
+ * @param {object} targetDeps - Extracted deps from the target file
50
+ * @param {string} targetPath - Path to the target file
51
+ * @param {string} sourcePath - Path to the file doing the importing
52
+ * @param {Array<Error>} errors - Array to collect errors
53
+ * @param {boolean} throwOnFirstError - Whether to throw immediately on first error
54
+ */
55
+ function verifyImportedValuesExist(dep, targetDeps, targetPath, sourcePath, errors, throwOnFirstError) {
56
+ // Check if this is a destructured import
57
+ if (dep.definitions && dep.definitions.expectsDestructuring && dep.definitions.destructuredParameters) {
58
+ const importedNames = dep.definitions.destructuredParameters.map(p => p.name.replace(/,$/, ''))
59
+
60
+ // Check CommonJS exports
61
+ const exportedNames = new Set()
62
+ if (targetDeps.moduleExports && targetDeps.moduleExports.length > 0) {
63
+ for (const exp of targetDeps.moduleExports) {
64
+ if (exp.exportType === 'named') {
65
+ exportedNames.add(exp.exportName)
66
+ } else if (exp.exportType === 'default' && exp.keys) {
67
+ exp.keys.forEach(key => exportedNames.add(key))
68
+ }
69
+ }
70
+ }
71
+
72
+ // Check ESM exports
73
+ if (targetDeps.exports && targetDeps.exports.length > 0) {
74
+ for (const exp of targetDeps.exports) {
75
+ const exportedName = exp.exportAlias || exp.exportName
76
+ if (exportedName) {
77
+ exportedNames.add(exportedName)
78
+ }
79
+ }
80
+ }
81
+
82
+ // Verify each imported name is exported
83
+ for (const importedName of importedNames) {
84
+ if (!exportedNames.has(importedName)) {
85
+ const type = (dep.line.indexOf('import') !== -1 ? 'Import' : 'Require')
86
+ const error = new Error(
87
+ `\n${type} "${importedName}" not found from statement:\n` +
88
+ `${dep.line}\n` +
89
+ `in "${sourcePath} file.\n\n` +
90
+ `The "${importedName}" value is not exported from file "${targetPath}".\n\n` +
91
+ `Available exports: ${Array.from(exportedNames).join(', ') || 'none'}`
92
+ )
93
+ if (throwOnFirstError) {
94
+ throw error
95
+ }
96
+ errors.push(error)
97
+ }
98
+ }
99
+ }
100
+ // For non-destructured imports, just verify there's a default export
101
+ else {
102
+ const hasDefaultExport =
103
+ (targetDeps.moduleExports && targetDeps.moduleExports.length > 0) ||
104
+ (targetDeps.exports && targetDeps.exports.some(exp => exp.exportType === 'default'))
105
+
106
+ if (!hasDefaultExport) {
107
+ const error = new Error(
108
+ `Import not found: "${targetPath}" does not have a default export.\n` +
109
+ `Import statement: ${dep.line}\n` +
110
+ `Importing from: ${sourcePath}`
111
+ )
112
+ if (throwOnFirstError) {
113
+ throw error
114
+ }
115
+ errors.push(error)
116
+ }
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Recursively build dependency graph and optionally validate imports
122
+ * @param {string} filePath - File to process
123
+ * @param {Array<Error>} errors - Array to collect errors
124
+ * @param {boolean} throwOnFirstError - Whether to throw immediately on first error
125
+ * @param {boolean} verify - Whether to verify imports/exports
126
+ * @param {boolean} verifyNodeModules - Whether to verify node_modules can be resolved
127
+ * @param {Map<string, string[]>|null} graph - Optional map to collect dependency graph
128
+ * @param {Set} visited - Set of already-visited file paths to avoid cycles
129
+ */
130
+ function buildGraphRecursively(
131
+ filePath,
132
+ errors,
133
+ throwOnFirstError,
134
+ verify,
135
+ verifyNodeModules,
136
+ graph = null,
137
+ visited = new Set(),
138
+ ) {
139
+ // Avoid infinite loops
140
+ const normalizedPath = fs.realpathSync(filePath)
141
+ if (visited.has(normalizedPath)) {
142
+ return
143
+ }
144
+ visited.add(normalizedPath)
145
+
146
+ // Initialize graph entry for this file if building graph
147
+ if (graph !== null && !graph.has(normalizedPath)) {
148
+ graph.set(normalizedPath, [])
149
+ }
150
+
151
+ // Read and extract deps from this file
152
+ const content = fs.readFileSync(filePath, 'utf8')
153
+ const deps = extractDeps(content)
154
+
155
+ // Collect all relative dependencies
156
+ const relativeDeps = []
157
+ if (deps.requires && deps.requires.length > 0) {
158
+ relativeDeps.push(...deps.requires.filter(req => req.isRelative))
159
+ }
160
+ if (deps.imports && deps.imports.length > 0) {
161
+ relativeDeps.push(...deps.imports.filter(imp => imp.isRelative))
162
+ }
163
+
164
+ // Collect all non-relative dependencies (node_modules)
165
+ const nodeModuleDeps = []
166
+ if (verifyNodeModules) {
167
+ if (deps.requires && deps.requires.length > 0) {
168
+ nodeModuleDeps.push(...deps.requires.filter(req => !req.isRelative))
169
+ }
170
+ if (deps.imports && deps.imports.length > 0) {
171
+ nodeModuleDeps.push(...deps.imports.filter(imp => !imp.isRelative))
172
+ }
173
+ }
174
+
175
+ // Process each relative dependency
176
+ const fileDir = path.dirname(filePath)
177
+ for (const dep of relativeDeps) {
178
+ const { from, line } = dep
179
+
180
+ // Resolve the import path
181
+ const resolvedPath = resolveImportPath(fileDir, from)
182
+
183
+ if (!resolvedPath) {
184
+ const error = new Error(
185
+ `"${line}" could not be resolved in ${filePath}\n\n` +
186
+ `Fix by ensuring "${path.resolve(fileDir, from)}" exists and is valid.`
187
+ )
188
+ if (throwOnFirstError) {
189
+ throw error
190
+ }
191
+ errors.push(error)
192
+ continue
193
+ }
194
+
195
+ // Add edge to graph if building
196
+ if (graph !== null) {
197
+ const normalizedResolvedPath = fs.realpathSync(resolvedPath)
198
+ graph.get(normalizedPath).push(normalizedResolvedPath)
199
+ }
200
+
201
+ // Verify imports if verification is enabled
202
+ if (verify) {
203
+ // Extract deps from the imported file
204
+ const targetContent = fs.readFileSync(resolvedPath, 'utf8')
205
+ const targetDeps = extractDeps(targetContent)
206
+
207
+ // Verify the imported values are exported
208
+ verifyImportedValuesExist(dep, targetDeps, resolvedPath, filePath, errors, throwOnFirstError)
209
+ }
210
+
211
+ // Recursively process the imported file
212
+ buildGraphRecursively(resolvedPath, errors, throwOnFirstError, verify, verifyNodeModules, graph, visited)
213
+ }
214
+
215
+ // Verify node_modules dependencies if enabled
216
+ if (verifyNodeModules && nodeModuleDeps.length > 0) {
217
+ const parentURL = pathToFileURL(filePath).href
218
+
219
+ for (const dep of nodeModuleDeps) {
220
+ const { from, line } = dep
221
+
222
+ try {
223
+ // Try to resolve the module using Node's resolution algorithm
224
+ const resolved = resolveImport(from, parentURL)
225
+ //console.log('resolved', resolved)
226
+ // If we get here, the module resolved successfully
227
+ } catch (error) {
228
+ const err = new Error(
229
+ `"${line}" could not be resolved in ${filePath}\n\n` +
230
+ `The package "${from}" is not installed or cannot be found.\n` +
231
+ `Run "npm install ${from}" to fix this issue.\n\n` +
232
+ `Resolution error: ${error.message}`
233
+ )
234
+ if (throwOnFirstError) {
235
+ throw err
236
+ }
237
+ errors.push(err)
238
+ }
239
+ }
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Build dependency graph for a file and its dependencies
245
+ * @param {string} filePath - File to analyze
246
+ * @param {object} options - Options
247
+ * @param {boolean} [options.buildGraph] - If true, build and return dependency graph. Default: true
248
+ * @param {boolean} [options.verifyGraph] - If true, verify imports/exports. Default: true
249
+ * @param {boolean} [options.verifyNodeModules] - If true, verify node_modules packages can be resolved. Default: false
250
+ * @param {boolean} [options.throwOnFirstError] - If true, throw immediately on first error. Default: false
251
+ * @returns {Map<string, string[]>|undefined} - Dependency graph where keys are file paths and values are arrays of dependency paths. Returns undefined if buildGraph is false.
252
+ */
253
+ function depGraph(filePath, options = {}) {
254
+ const {
255
+ buildGraph = true,
256
+ verifyGraph = true,
257
+ verifyNodeModules = false,
258
+ throwOnFirstError = false,
259
+ } = options
260
+ const errors = []
261
+ const graph = buildGraph ? new Map() : null
262
+
263
+ buildGraphRecursively(filePath, errors, throwOnFirstError, verifyGraph, verifyNodeModules, graph)
264
+
265
+ if (errors.length > 0) {
266
+ const errorMessage = errors.map((err, idx) => `Dep graph error:\n ${err.message}`).join('\n')
267
+ throw new Error(
268
+ `Found ${errors.length} validation error${errors.length === 1 ? '' : 's'}:\n\n${errorMessage}`
269
+ )
270
+ }
271
+
272
+ if (buildGraph) {
273
+ return graph
274
+ }
275
+ }
276
+
277
+
278
+ /**
279
+ * Get all dependency file paths in build order (dependencies first), deduplicated
280
+ * @param {string} filePath - Entry file path
281
+ * @param {object} options - Options to pass to depGraph
282
+ * @returns {string[]} - Array of unique dependency file paths in topological order
283
+ */
284
+ function resolveDepPaths(filePath, options = {}) {
285
+ const graph = depGraph(filePath, options)
286
+
287
+ // Calculate in-degree (number of dependencies) for each file
288
+ const inDegree = new Map()
289
+ for (const [file, deps] of graph) {
290
+ inDegree.set(file, deps.length)
291
+ }
292
+
293
+ // Queue of files with no dependencies (can be processed first)
294
+ const queue = []
295
+ for (const [file, degree] of inDegree) {
296
+ if (degree === 0) {
297
+ queue.push(file)
298
+ }
299
+ }
300
+
301
+ const buildOrder = []
302
+
303
+ while (queue.length > 0) {
304
+ const file = queue.shift()
305
+ buildOrder.push(file)
306
+
307
+ // Find all files that depend on this file and decrement their in-degree
308
+ for (const [dependent, deps] of graph) {
309
+ if (deps.includes(file)) {
310
+ const newDegree = inDegree.get(dependent) - 1
311
+ inDegree.set(dependent, newDegree)
312
+ if (newDegree === 0) {
313
+ queue.push(dependent)
314
+ }
315
+ }
316
+ }
317
+ }
318
+
319
+ return buildOrder
320
+ }
321
+
322
+
323
+ if (require.main === module) {
324
+ const entry = path.resolve(__dirname, '../tests/fixtures/cjs-deep-example/index.js')
325
+ const graph = depGraph(entry, {
326
+ verifyNodeModules: false,
327
+ throwOnFirstError: true
328
+ })
329
+ console.log('graph', graph)
330
+ const depPathsProper = resolveDepPaths(entry)
331
+ console.log('depPathsProper', depPathsProper)
332
+ }
333
+
334
+ module.exports = {
335
+ depGraph,
336
+ resolveDepPaths
337
+ }
@@ -8,17 +8,22 @@ const MODULE_EXPORTS_ASSIGNMENT_REGEX = /^(?!\s*\/\/)(?!\s*\/\*)\s*(?:exports\s*
8
8
 
9
9
  // Matches: module.exports.propertyName = ... or module.exports['propertyName'] = ...
10
10
  // https://regex101.com/r/example/cjs-2
11
- const MODULE_EXPORTS_PROPERTY_REGEX = /module\.exports(?:\.([\w$]+)|\[['"]([^'"]+)['"]\])\s*=\s*(.+?)(?=\s*(?:module\.exports|exports\.|\/\/|\/\*|$))/gs
11
+ const MODULE_EXPORTS_PROPERTY_REGEX = /module\.exports(?:\.([\w$]+)|\[['"]([^'"]+)['"]\])\s*=\s*(.+?)(?=\n\s*\n|(?:module\.exports|exports\.|Object\.defineProperty|\/\/|\/\*|$))/gs
12
12
 
13
13
  // Matches: exports.propertyName = ... or exports['propertyName'] = ...
14
14
  // https://regex101.com/r/example/cjs-3
15
- const EXPORTS_PROPERTY_REGEX = /(?<!module\.)exports(?:\.([\w$]+)|\[['"]([^'"]+)['"]\])\s*=\s*(.+?)(?=\s*(?:module\.exports|exports\.|\/\/|\/\*|$))/gs
15
+ const EXPORTS_PROPERTY_REGEX = /(?<!module\.)exports(?:\.([\w$]+)|\[['"]([^'"]+)['"]\])\s*=\s*(.+?)(?=\n\s*\n|(?:module\.exports|exports\.|Object\.defineProperty|\/\/|\/\*|$))/gs
16
16
 
17
17
  function stripComments(code) {
18
18
  let result = code
19
19
 
20
- // Remove single-line comments but preserve newlines
21
- result = result.replace(/\/\/.*$/gm, '')
20
+ // Remove single-line comments but preserve string positions
21
+ // This is critical: we must preserve the exact length of the string so that
22
+ // indices found in sanitized text match indices in original text
23
+ result = result.replace(/\/\/(.*)$/gm, (match, commentText) => {
24
+ // Replace // and comment text with spaces (same length as original)
25
+ return ' ' + ' '.repeat(commentText.length)
26
+ })
22
27
 
23
28
  // Remove multi-line comments but preserve line structure
24
29
  result = result.replace(/\/\*[\s\S]*?\*\//g, (match) => {
@@ -36,13 +41,22 @@ function getCjsExports(code) {
36
41
  const assignmentExports = getModuleExportsAssignment(code, sanitizedCode)
37
42
  const modulePropertyExports = getModuleExportsProperty(code, sanitizedCode)
38
43
  const propertyExports = getExportsProperty(code, sanitizedCode)
39
- const objectAssignExports = getObjectAssignExports(code, sanitizedCode)
44
+
45
+ // Quick pre-checks to avoid expensive regex operations when not needed
46
+ const objectAssignExports = sanitizedCode.includes('Object.assign')
47
+ ? getObjectAssignExports(code, sanitizedCode)
48
+ : []
49
+
50
+ const definePropertyExports = sanitizedCode.includes('Object.defineProperty')
51
+ ? getDefinePropertyExports(code, sanitizedCode)
52
+ : []
40
53
 
41
54
  /*
42
55
  console.log('assignmentExports', assignmentExports)
43
56
  console.log('modulePropertyExports', modulePropertyExports)
44
57
  console.log('propertyExports', propertyExports)
45
58
  console.log('objectAssignExports', objectAssignExports)
59
+ console.log('definePropertyExports', definePropertyExports)
46
60
  /** */
47
61
 
48
62
  const allExports = []
@@ -50,6 +64,7 @@ function getCjsExports(code) {
50
64
  .concat(modulePropertyExports)
51
65
  .concat(propertyExports)
52
66
  .concat(objectAssignExports)
67
+ .concat(definePropertyExports)
53
68
 
54
69
  return allExports.sort((a, b) => a.index - b.index)
55
70
  }
@@ -283,7 +298,81 @@ function getObjectAssignExports(originalText = '', sanitizedText = originalText)
283
298
  return exportStatements
284
299
  }
285
300
 
286
- if(require.main === module) {
301
+ function getDefinePropertyExports(originalText = '', sanitizedText = originalText) {
302
+ let exportStatements = []
303
+
304
+ // Find all Object.defineProperty calls with module or exports
305
+ // Matches: Object.defineProperty(module, 'exports', ...) or Object.defineProperty(exports, 'propertyName', ...)
306
+ const definePropertyPattern = /Object\.defineProperty\s*\(\s*(module|exports)\s*,\s*['"]([^'"]+)['"]/g
307
+ var result
308
+
309
+ while((result = definePropertyPattern.exec(sanitizedText)) !== null) {
310
+ const target = result[1]
311
+ const propertyName = result[2]
312
+
313
+ // Find the opening parenthesis of Object.defineProperty
314
+ const openParenIndex = result.index + result[0].indexOf('(')
315
+
316
+ // Balance parentheses to find the complete Object.defineProperty call
317
+ let depth = 0
318
+ let i = openParenIndex
319
+ let completeCall = ''
320
+
321
+ while (i < originalText.length) {
322
+ const char = originalText[i]
323
+ if (char === '(') depth++
324
+ else if (char === ')') {
325
+ depth--
326
+ if (depth === 0) {
327
+ completeCall = originalText.substring(result.index, i + 1)
328
+ break
329
+ }
330
+ }
331
+ i++
332
+ }
333
+
334
+ if (!completeCall) {
335
+ continue
336
+ }
337
+
338
+ // Try to extract the getter function if present
339
+ // Matches: get: functionName or get: () => ... or get() { ... }
340
+ const getterMatch = completeCall.match(/get\s*:\s*(\w+)|get\s*:\s*(\([^)]*\)\s*=>)|get\s*\(/)
341
+ let getterValue = ''
342
+ if (getterMatch) {
343
+ if (getterMatch[1]) {
344
+ // Named function: get: functionName
345
+ getterValue = getterMatch[1]
346
+ } else if (getterMatch[2]) {
347
+ // Arrow function: get: () =>
348
+ getterValue = 'arrow function'
349
+ } else {
350
+ // Method: get() { ... }
351
+ getterValue = 'getter method'
352
+ }
353
+ }
354
+
355
+ // Determine if this is a module.exports or property export
356
+ const isModuleExports = target === 'module' && propertyName === 'exports'
357
+
358
+ const exportStatement = {
359
+ line: completeCall.trim(),
360
+ exportType: isModuleExports ? 'default' : 'named',
361
+ exportName: isModuleExports ? '' : propertyName,
362
+ exportValue: completeCall, // Original text with comments
363
+ exportDefinitionName: getterValue || propertyName,
364
+ index: result.index,
365
+ isExport: true,
366
+ isDefineProperty: true
367
+ }
368
+
369
+ exportStatements.push(exportStatement)
370
+ }
371
+
372
+ return exportStatements
373
+ }
374
+
375
+ if (require.main === module) {
287
376
  const code = `
288
377
  // module.exports assignment
289
378
  module.exports = function hello() {}
@@ -309,6 +398,21 @@ module.exports.MyClass = class MyClass {}
309
398
  // exports properties
310
399
  exports.foo = function() {}
311
400
  exports.bar = 'bar'
401
+
402
+ // Object.defineProperty exports
403
+ function assembleStyles() {
404
+ return { color: 'red' }
405
+ }
406
+
407
+ Object.defineProperty(module, 'exports', {
408
+ enumerable: true,
409
+ get: assembleStyles
410
+ })
411
+
412
+ Object.defineProperty(exports, 'myProperty', {
413
+ enumerable: true,
414
+ get: () => 'value'
415
+ })
312
416
  `
313
417
 
314
418
  const exportsFound = getCjsExports(code)
@@ -320,5 +424,6 @@ module.exports = {
320
424
  getModuleExportsAssignment,
321
425
  getModuleExportsProperty,
322
426
  getExportsProperty,
323
- getObjectAssignExports
427
+ getObjectAssignExports,
428
+ getDefinePropertyExports
324
429
  }
@@ -52,6 +52,7 @@ function getTypeImports(targetText = '') {
52
52
  importName: (importName || '').trim(),
53
53
  index: result.index,
54
54
  isImport: true,
55
+ isTypeImport: true,
55
56
  isRelative: isRelativeImport(importPath)
56
57
  })
57
58
  }
package/src/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- const { inspectParameters, getParametersNames } = require('inspect-parameters-declaration')
1
+ const { inspectParameters, getParametersNames } = require('./vendor/inspect-parameters-declaration')
2
2
 
3
3
  function isRelativeImport(importLocation) {
4
4
  return !!importLocation.match(/^\./)