@davidwells/extract-deps 0.0.5 → 0.0.7
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/.claude/settings.local.json +7 -1
- package/examples/verify-basic.js +2 -0
- package/examples/verify-package-entries.js +74 -0
- package/package.json +2 -2
- package/src/dep-graph.js +82 -14
- package/src/get-cjs-exports.js +112 -7
- package/src/get-imports.js +1 -0
- package/src/utils.js +1 -1
- package/src/vendor/inspect-parameters-declaration.js +282 -0
- package/src/verify-package-entries.js +228 -0
- package/tests/dep-graph.test.js +172 -0
- package/tests/fixtures/cjs-broken-example/index.js +8 -0
- package/tests/fixtures/cjs-broken-example/one.js +9 -0
- package/tests/fixtures/cjs-broken-example/package.json +7 -0
- package/tests/fixtures/cjs-broken-example/sub-folder/sub-sub-folder/three.js +6 -0
- package/tests/fixtures/cjs-broken-example/sub-folder/two.js +8 -0
- package/tests/fixtures/cjs-deep-example/package.json +15 -0
- package/tests/fixtures/cjs-example/package.json +7 -0
- package/tests/fixtures/dir-index-example/entry.js +6 -0
- package/tests/fixtures/dir-index-example/shared-pkg/index.js +4 -0
- package/tests/fixtures/esm-broken-fixture/index.js +8 -0
- package/tests/fixtures/esm-broken-fixture/one.js +9 -0
- package/tests/fixtures/esm-broken-fixture/package.json +15 -0
- package/tests/fixtures/esm-broken-fixture/sub-folder/sub-sub-folder/three.js +6 -0
- package/tests/fixtures/esm-broken-fixture/sub-folder/sub-sub-folder-two/deep.js +6 -0
- package/tests/fixtures/esm-broken-fixture/sub-folder/sub-sub-folder-two/even-deeper/wow-deep.js +5 -0
- package/tests/fixtures/esm-broken-fixture/sub-folder/two.js +8 -0
- package/tests/fixtures/esm-broken-fixture/valid.js +7 -0
- package/tests/fixtures/esm-fixture/package.json +11 -0
- package/tests/get-cjs-exports.test.js +171 -0
- package/tests/get-imports.test.js +4 -1
- package/tests/manual/broken-cjs.js +38 -0
- package/tests/manual/broken-esm.js +37 -0
- package/tests/verify-package-entries.test.js +272 -0
package/examples/verify-basic.js
CHANGED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Verify package.json entry points
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const { getPackageEntryPoints, verifyPackageEntries } = require('../src/verify-package-json-entries')
|
|
4
|
+
|
|
5
|
+
const pkgPath = path.resolve(__dirname, '../package.json')
|
|
6
|
+
|
|
7
|
+
console.log('=== Extract All Package Entry Points ===\n')
|
|
8
|
+
const entryPoints = getPackageEntryPoints(pkgPath)
|
|
9
|
+
console.log(`Found ${entryPoints.length} entry points:\n`)
|
|
10
|
+
entryPoints.forEach(ep => {
|
|
11
|
+
console.log(` ${ep.field}: ${ep.path}`)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
console.log('\n=== Verify Entries and Collect Dependencies ===\n')
|
|
15
|
+
const results = verifyPackageEntries(pkgPath, {
|
|
16
|
+
collectDeps: true, // Collect dependency paths
|
|
17
|
+
verifyGraph: false // Skip verification (faster, for CI use case)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
console.log('Results per entry point:\n')
|
|
21
|
+
results.entryPoints.forEach(ep => {
|
|
22
|
+
const status = ep.valid ? '✓' : '✗'
|
|
23
|
+
console.log(`${status} ${ep.field}`)
|
|
24
|
+
if (ep.deps) {
|
|
25
|
+
console.log(` ${ep.deps.length} dependencies`)
|
|
26
|
+
}
|
|
27
|
+
if (ep.error) {
|
|
28
|
+
console.log(` Error: ${ep.error.message}`)
|
|
29
|
+
}
|
|
30
|
+
console.log()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
console.log(`\n=== Summary ===`)
|
|
34
|
+
console.log(`Total entry points: ${results.entryPoints.length}`)
|
|
35
|
+
console.log(`Valid: ${results.entryPoints.filter(ep => ep.valid).length}`)
|
|
36
|
+
console.log(`Errors: ${results.errors.length}`)
|
|
37
|
+
console.log(`Total unique dependencies across all entry points: ${results.allDeps.size}`)
|
|
38
|
+
|
|
39
|
+
if (results.allDeps.size > 0) {
|
|
40
|
+
console.log('\n=== All Dependencies (for git change tracking) ===')
|
|
41
|
+
const allDeps = Array.from(results.allDeps)
|
|
42
|
+
allDeps.forEach(dep => {
|
|
43
|
+
console.log(` ${path.relative(process.cwd(), dep)}`)
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
console.log('\n=== Example: CI Use Case ===')
|
|
48
|
+
console.log(`
|
|
49
|
+
// In your CI script, you can use this to check if any deps changed:
|
|
50
|
+
const { verifyPackageEntries } = require('extract-deps/verify-package-json-entries')
|
|
51
|
+
const { execSync } = require('child_process')
|
|
52
|
+
|
|
53
|
+
const pkgPath = './package.json'
|
|
54
|
+
const results = verifyPackageEntries(pkgPath, { verifyGraph: false })
|
|
55
|
+
|
|
56
|
+
// Get all unique dependency file paths
|
|
57
|
+
const allDepPaths = Array.from(results.allDeps)
|
|
58
|
+
|
|
59
|
+
// Check which ones changed in git
|
|
60
|
+
const changedFiles = execSync('git diff --name-only HEAD~1 HEAD')
|
|
61
|
+
.toString()
|
|
62
|
+
.split('\\n')
|
|
63
|
+
.filter(Boolean)
|
|
64
|
+
|
|
65
|
+
const changedDeps = allDepPaths.filter(dep => {
|
|
66
|
+
const relativePath = path.relative(process.cwd(), dep)
|
|
67
|
+
return changedFiles.includes(relativePath)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
console.log(\`Changed dependencies: \${changedDeps.length}\`)
|
|
71
|
+
if (changedDeps.length > 0) {
|
|
72
|
+
console.log('Need to rebuild/retest')
|
|
73
|
+
}
|
|
74
|
+
`)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@davidwells/extract-deps",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "Get imports and requires from a codebase without AST",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"release:major": "npm version major && npm publish"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"
|
|
25
|
+
"@dual-bundle/import-meta-resolve": "^4.2.1"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"typescript": "^5.7.3",
|
package/src/dep-graph.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Build dependency graph and optionally verify imports
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const fs = require('fs')
|
|
4
|
+
const { pathToFileURL, fileURLToPath } = require('url')
|
|
5
|
+
const { resolve: resolveImport } = require('@dual-bundle/import-meta-resolve')
|
|
4
6
|
const { extractDeps } = require('./index')
|
|
5
7
|
|
|
6
8
|
function fsExistsSync(path) {
|
|
@@ -12,6 +14,14 @@ function fsExistsSync(path) {
|
|
|
12
14
|
}
|
|
13
15
|
}
|
|
14
16
|
|
|
17
|
+
function isFileSync(filePath) {
|
|
18
|
+
try {
|
|
19
|
+
return fs.statSync(filePath).isFile()
|
|
20
|
+
} catch (error) {
|
|
21
|
+
return false
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
15
25
|
/**
|
|
16
26
|
* Resolve a relative import to an actual file path
|
|
17
27
|
* @param {string} baseDir - Directory containing the importing file
|
|
@@ -21,10 +31,10 @@ function fsExistsSync(path) {
|
|
|
21
31
|
function resolveImportPath(baseDir, importPath) {
|
|
22
32
|
const possibleExtensions = ['.js', '.mjs', '.ts', '.json', '']
|
|
23
33
|
|
|
24
|
-
// Try direct file resolution
|
|
34
|
+
// Try direct file resolution (must be a file, not directory)
|
|
25
35
|
for (const ext of possibleExtensions) {
|
|
26
36
|
const testPath = path.resolve(baseDir, importPath + ext)
|
|
27
|
-
if (
|
|
37
|
+
if (isFileSync(testPath)) {
|
|
28
38
|
return testPath
|
|
29
39
|
}
|
|
30
40
|
}
|
|
@@ -80,10 +90,12 @@ function verifyImportedValuesExist(dep, targetDeps, targetPath, sourcePath, erro
|
|
|
80
90
|
// Verify each imported name is exported
|
|
81
91
|
for (const importedName of importedNames) {
|
|
82
92
|
if (!exportedNames.has(importedName)) {
|
|
93
|
+
const type = (dep.line.indexOf('import') !== -1 ? 'Import' : 'Require')
|
|
83
94
|
const error = new Error(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
`
|
|
95
|
+
`\n${type} "${importedName}" not found from statement:\n` +
|
|
96
|
+
`${dep.line}\n` +
|
|
97
|
+
`in "${sourcePath} file.\n\n` +
|
|
98
|
+
`The "${importedName}" value is not exported from file "${targetPath}".\n\n` +
|
|
87
99
|
`Available exports: ${Array.from(exportedNames).join(', ') || 'none'}`
|
|
88
100
|
)
|
|
89
101
|
if (throwOnFirstError) {
|
|
@@ -119,10 +131,19 @@ function verifyImportedValuesExist(dep, targetDeps, targetPath, sourcePath, erro
|
|
|
119
131
|
* @param {Array<Error>} errors - Array to collect errors
|
|
120
132
|
* @param {boolean} throwOnFirstError - Whether to throw immediately on first error
|
|
121
133
|
* @param {boolean} verify - Whether to verify imports/exports
|
|
134
|
+
* @param {boolean} verifyNodeModules - Whether to verify node_modules can be resolved
|
|
122
135
|
* @param {Map<string, string[]>|null} graph - Optional map to collect dependency graph
|
|
123
136
|
* @param {Set} visited - Set of already-visited file paths to avoid cycles
|
|
124
137
|
*/
|
|
125
|
-
function buildGraphRecursively(
|
|
138
|
+
function buildGraphRecursively(
|
|
139
|
+
filePath,
|
|
140
|
+
errors,
|
|
141
|
+
throwOnFirstError,
|
|
142
|
+
verify,
|
|
143
|
+
verifyNodeModules,
|
|
144
|
+
graph = null,
|
|
145
|
+
visited = new Set(),
|
|
146
|
+
) {
|
|
126
147
|
// Avoid infinite loops
|
|
127
148
|
const normalizedPath = fs.realpathSync(filePath)
|
|
128
149
|
if (visited.has(normalizedPath)) {
|
|
@@ -148,6 +169,17 @@ function buildGraphRecursively(filePath, errors, throwOnFirstError, verify, grap
|
|
|
148
169
|
relativeDeps.push(...deps.imports.filter(imp => imp.isRelative))
|
|
149
170
|
}
|
|
150
171
|
|
|
172
|
+
// Collect all non-relative dependencies (node_modules)
|
|
173
|
+
const nodeModuleDeps = []
|
|
174
|
+
if (verifyNodeModules) {
|
|
175
|
+
if (deps.requires && deps.requires.length > 0) {
|
|
176
|
+
nodeModuleDeps.push(...deps.requires.filter(req => !req.isRelative))
|
|
177
|
+
}
|
|
178
|
+
if (deps.imports && deps.imports.length > 0) {
|
|
179
|
+
nodeModuleDeps.push(...deps.imports.filter(imp => !imp.isRelative))
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
151
183
|
// Process each relative dependency
|
|
152
184
|
const fileDir = path.dirname(filePath)
|
|
153
185
|
for (const dep of relativeDeps) {
|
|
@@ -185,7 +217,34 @@ function buildGraphRecursively(filePath, errors, throwOnFirstError, verify, grap
|
|
|
185
217
|
}
|
|
186
218
|
|
|
187
219
|
// Recursively process the imported file
|
|
188
|
-
buildGraphRecursively(resolvedPath, errors, throwOnFirstError, verify, graph, visited)
|
|
220
|
+
buildGraphRecursively(resolvedPath, errors, throwOnFirstError, verify, verifyNodeModules, graph, visited)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Verify node_modules dependencies if enabled
|
|
224
|
+
if (verifyNodeModules && nodeModuleDeps.length > 0) {
|
|
225
|
+
const parentURL = pathToFileURL(filePath).href
|
|
226
|
+
|
|
227
|
+
for (const dep of nodeModuleDeps) {
|
|
228
|
+
const { from, line } = dep
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
// Try to resolve the module using Node's resolution algorithm
|
|
232
|
+
const resolved = resolveImport(from, parentURL)
|
|
233
|
+
//console.log('resolved', resolved)
|
|
234
|
+
// If we get here, the module resolved successfully
|
|
235
|
+
} catch (error) {
|
|
236
|
+
const err = new Error(
|
|
237
|
+
`"${line}" could not be resolved in ${filePath}\n\n` +
|
|
238
|
+
`The package "${from}" is not installed or cannot be found.\n` +
|
|
239
|
+
`Run "npm install ${from}" to fix this issue.\n\n` +
|
|
240
|
+
`Resolution error: ${error.message}`
|
|
241
|
+
)
|
|
242
|
+
if (throwOnFirstError) {
|
|
243
|
+
throw err
|
|
244
|
+
}
|
|
245
|
+
errors.push(err)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
189
248
|
}
|
|
190
249
|
}
|
|
191
250
|
|
|
@@ -195,19 +254,27 @@ function buildGraphRecursively(filePath, errors, throwOnFirstError, verify, grap
|
|
|
195
254
|
* @param {object} options - Options
|
|
196
255
|
* @param {boolean} [options.buildGraph] - If true, build and return dependency graph. Default: true
|
|
197
256
|
* @param {boolean} [options.verifyGraph] - If true, verify imports/exports. Default: true
|
|
257
|
+
* @param {boolean} [options.verifyNodeModules] - If true, verify node_modules packages can be resolved. Default: false
|
|
198
258
|
* @param {boolean} [options.throwOnFirstError] - If true, throw immediately on first error. Default: false
|
|
199
259
|
* @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.
|
|
200
260
|
*/
|
|
201
261
|
function depGraph(filePath, options = {}) {
|
|
202
|
-
const {
|
|
262
|
+
const {
|
|
263
|
+
buildGraph = true,
|
|
264
|
+
verifyGraph = true,
|
|
265
|
+
verifyNodeModules = false,
|
|
266
|
+
throwOnFirstError = false,
|
|
267
|
+
} = options
|
|
203
268
|
const errors = []
|
|
204
269
|
const graph = buildGraph ? new Map() : null
|
|
205
270
|
|
|
206
|
-
buildGraphRecursively(filePath, errors, throwOnFirstError, verifyGraph, graph)
|
|
271
|
+
buildGraphRecursively(filePath, errors, throwOnFirstError, verifyGraph, verifyNodeModules, graph)
|
|
207
272
|
|
|
208
273
|
if (errors.length > 0) {
|
|
209
|
-
const errorMessage = errors.map((err, idx) => `
|
|
210
|
-
throw new Error(
|
|
274
|
+
const errorMessage = errors.map((err, idx) => `Dep graph error:\n ${err.message}`).join('\n')
|
|
275
|
+
throw new Error(
|
|
276
|
+
`Found ${errors.length} validation error${errors.length === 1 ? '' : 's'}:\n\n${errorMessage}`
|
|
277
|
+
)
|
|
211
278
|
}
|
|
212
279
|
|
|
213
280
|
if (buildGraph) {
|
|
@@ -263,10 +330,11 @@ function resolveDepPaths(filePath, options = {}) {
|
|
|
263
330
|
|
|
264
331
|
if (require.main === module) {
|
|
265
332
|
const entry = path.resolve(__dirname, '../tests/fixtures/cjs-deep-example/index.js')
|
|
266
|
-
const graph = depGraph(entry
|
|
333
|
+
const graph = depGraph(entry, {
|
|
334
|
+
verifyNodeModules: false,
|
|
335
|
+
throwOnFirstError: true
|
|
336
|
+
})
|
|
267
337
|
console.log('graph', graph)
|
|
268
|
-
const depPaths = Array.from(graph.values()).flat()
|
|
269
|
-
console.log('depPaths', depPaths)
|
|
270
338
|
const depPathsProper = resolveDepPaths(entry)
|
|
271
339
|
console.log('depPathsProper', depPathsProper)
|
|
272
340
|
}
|
package/src/get-cjs-exports.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
21
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|
package/src/get-imports.js
CHANGED
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(/^\./)
|