@davidwells/extract-deps 0.1.0 → 0.1.2

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.
@@ -8,7 +8,8 @@
8
8
  "Bash(tar:*)",
9
9
  "Bash(npm install)",
10
10
  "Bash(npm test)",
11
- "Bash(npm test:*)"
11
+ "Bash(npm test:*)",
12
+ "Bash(npm run types:*)"
12
13
  ],
13
14
  "deny": [],
14
15
  "ask": []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@davidwells/extract-deps",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Get imports and requires from a codebase without AST",
5
5
  "main": "src/index.js",
6
6
  "exports": {
package/src/dep-graph.js CHANGED
@@ -4,6 +4,7 @@ const fs = require('fs')
4
4
  const { pathToFileURL, fileURLToPath } = require('url')
5
5
  const { resolve: resolveImport } = require('@dual-bundle/import-meta-resolve')
6
6
  const { extractDeps } = require('./index')
7
+ const { isBuiltIn } = require('./utils')
7
8
 
8
9
  function fsExistsSync(path) {
9
10
  try {
@@ -229,13 +230,18 @@ function buildGraphRecursively(
229
230
  }
230
231
  }
231
232
 
232
- // Verify node_modules dependencies if enabled
233
+ // Verify node_modules dependencies if enabled (skip built-ins)
233
234
  if (verifyNodeModules && nodeModuleDeps.length > 0) {
234
235
  const parentURL = pathToFileURL(filePath).href
235
236
 
236
237
  for (const dep of nodeModuleDeps) {
237
238
  const { from, line } = dep
238
239
 
240
+ // Skip verification for built-in modules
241
+ if (dep.isBuiltIn) {
242
+ continue
243
+ }
244
+
239
245
  try {
240
246
  // Try to resolve the module using Node's resolution algorithm
241
247
  const resolved = resolveImport(from, parentURL)
@@ -266,7 +272,8 @@ function buildGraphRecursively(
266
272
  * @param {boolean} [options.verifyNodeModules] - If true, verify node_modules packages can be resolved. Default: false
267
273
  * @param {boolean} [options.includeNodeModules] - If true, include node_modules package names in the graph. Default: false
268
274
  * @param {boolean} [options.throwOnFirstError] - If true, throw immediately on first error. Default: false
269
- * @returns {Map<string, string[]>|undefined} - Dependency graph where keys are file paths and values are arrays of dependency paths (or package names if includeNodeModules). Returns undefined if buildGraph is false.
275
+ * @param {boolean} [options.returnErrors] - If true, return { graph, errors } instead of throwing. Default: false
276
+ * @returns {Map<string, string[]>|{graph: Map, errors: Error[]}|undefined} - Dependency graph, or { graph, errors } if returnErrors is true. Returns undefined if buildGraph is false.
270
277
  */
271
278
  function depGraph(filePath, options = {}) {
272
279
  const {
@@ -275,12 +282,17 @@ function depGraph(filePath, options = {}) {
275
282
  verifyNodeModules = false,
276
283
  includeNodeModules = false,
277
284
  throwOnFirstError = false,
285
+ returnErrors = false,
278
286
  } = options
279
287
  const errors = []
280
288
  const graph = buildGraph ? new Map() : null
281
289
 
282
290
  buildGraphRecursively(filePath, errors, throwOnFirstError, verifyGraph, verifyNodeModules, includeNodeModules, graph)
283
291
 
292
+ if (returnErrors) {
293
+ return { graph, errors }
294
+ }
295
+
284
296
  if (errors.length > 0) {
285
297
  const errorMessage = errors.map((err, idx) => `Dep graph error:\n ${err.message}`).join('\n')
286
298
  throw new Error(
@@ -298,17 +310,43 @@ function depGraph(filePath, options = {}) {
298
310
  * Get all dependency file paths in build order (dependencies first), deduplicated
299
311
  * @param {string} filePath - Entry file path
300
312
  * @param {object} options - Options to pass to depGraph
301
- * @returns {{ files: string[], nodeModules: string[] }} - Object with files in topological order and unique node_modules
313
+ * @param {boolean} [options.verifyGraph] - If true, verify imports/exports. Default: true
314
+ * @param {boolean} [options.verifyNodeModules] - If true, verify node_modules packages can be resolved. Default: false
315
+ * @param {boolean} [options.throwOnFirstError] - If true, throw immediately on first error. Default: false
316
+ * @param {boolean} [options.returnErrors] - If true, include errors array in result instead of throwing
317
+ * @returns {{ files: string[], nodeModules: string[], builtIns: string[], errors?: Error[] }} - Object with files in topological order, npm packages, and Node.js built-ins
302
318
  */
303
319
  function resolveDepPaths(filePath, options = {}) {
304
- const graph = depGraph(filePath, { ...options, includeNodeModules: true })
320
+ const { returnErrors = false, ...restOptions } = options
321
+
322
+ /** @type {Map<string, string[]>} */
323
+ let graph
324
+ /** @type {Error[]} */
325
+ let errors = []
305
326
 
306
- // Collect node_modules (non-path strings in dependency arrays)
327
+ if (returnErrors) {
328
+ const result = /** @type {{ graph: Map<string, string[]>, errors: Error[] }} */ (
329
+ depGraph(filePath, { ...restOptions, includeNodeModules: true, returnErrors: true })
330
+ )
331
+ graph = result.graph
332
+ errors = result.errors
333
+ } else {
334
+ graph = /** @type {Map<string, string[]>} */ (
335
+ depGraph(filePath, { ...restOptions, includeNodeModules: true })
336
+ )
337
+ }
338
+
339
+ // Collect node_modules and built-ins (non-path strings in dependency arrays)
307
340
  const nodeModulesSet = new Set()
341
+ const builtInsSet = new Set()
308
342
  for (const deps of graph.values()) {
309
343
  for (const dep of deps) {
310
344
  if (!dep.startsWith('/')) {
311
- nodeModulesSet.add(dep)
345
+ if (isBuiltIn(dep)) {
346
+ builtInsSet.add(dep)
347
+ } else {
348
+ nodeModulesSet.add(dep)
349
+ }
312
350
  }
313
351
  }
314
352
  }
@@ -347,10 +385,17 @@ function resolveDepPaths(filePath, options = {}) {
347
385
  }
348
386
  }
349
387
 
350
- return {
388
+ const result = {
351
389
  files: buildOrder,
352
- nodeModules: Array.from(nodeModulesSet)
390
+ nodeModules: Array.from(nodeModulesSet),
391
+ builtIns: Array.from(builtInsSet)
392
+ }
393
+
394
+ if (returnErrors) {
395
+ result.errors = errors
353
396
  }
397
+
398
+ return result
354
399
  }
355
400
 
356
401
 
@@ -1,4 +1,4 @@
1
- const { isRelativeImport, isRelativeImportWithQuotes, getNames } = require('./utils')
1
+ const { isBuiltIn, isRelativeImport, isRelativeImportWithQuotes, getNames } = require('./utils')
2
2
 
3
3
  // https://regex101.com/r/cfEmlm/1
4
4
  const IMPORT_REGEX = /import(?:["'\s]*([\w*{}\n\r\t, ]+)from\s*)?["'\s](.*[@\w_-]+)["'\s]+;?$/gm
@@ -26,7 +26,7 @@ function getStaticImports(targetText = '') {
26
26
  while((result = IMPORT_REGEX.exec(targetText)) !== null) {
27
27
  const [ line, names, from ] = result
28
28
  const namesValues = (names || '').trim()
29
- importStatements.push({
29
+ importStatements.push({
30
30
  line,
31
31
  varType: 'const',
32
32
  varName: namesValues,
@@ -34,7 +34,8 @@ function getStaticImports(targetText = '') {
34
34
  from,
35
35
  index: result.index,
36
36
  isImport: true,
37
- isRelative: isRelativeImport(from)
37
+ isRelative: isRelativeImport(from),
38
+ isBuiltIn: isBuiltIn(from)
38
39
  })
39
40
  }
40
41
  return importStatements
@@ -53,7 +54,8 @@ function getTypeImports(targetText = '') {
53
54
  index: result.index,
54
55
  isImport: true,
55
56
  isTypeImport: true,
56
- isRelative: isRelativeImport(importPath)
57
+ isRelative: isRelativeImport(importPath),
58
+ isBuiltIn: isBuiltIn(importPath)
57
59
  })
58
60
  }
59
61
  return importStatements
@@ -75,6 +77,7 @@ function getDynamicImports(targetText = '') {
75
77
  index: result.index,
76
78
  isImport: true,
77
79
  isRelative: isRelativeImport(from) || isRelativeImportWithQuotes(from),
80
+ isBuiltIn: isBuiltIn(from.trim()),
78
81
  isDynamic: true
79
82
  })
80
83
  }
@@ -101,6 +104,7 @@ function getAssertionImports(targetText = '') {
101
104
  index: result.index,
102
105
  isImport: true,
103
106
  isRelative: isRelativeImport(from),
107
+ isBuiltIn: isBuiltIn(from),
104
108
  isAssertion: true
105
109
  })
106
110
  }
@@ -1,4 +1,4 @@
1
- const { isRelativeImport, getNames } = require('./utils')
1
+ const { isBuiltIn, isRelativeImport, getNames } = require('./utils')
2
2
 
3
3
  // Updated regex to exclude ES6 dynamic imports
4
4
  const REQUIRE_REGEX = /(?!.*await\s+import)(const|var|let)(?:["'\s]*([\w*{}:=\n\r\t,:= ]+)\s*=\s*require\(\s*)?["'\s](.*[@\w_-]+)["'\s]+\);?$|(?!.*await\s+import)require\(["'\s](.*[@\w_-]+)["'\s]\)/gm
@@ -28,6 +28,7 @@ function getDynamicRequires(code) {
28
28
  index: match.index,
29
29
  isRequire: true,
30
30
  isRelative: false,
31
+ isBuiltIn: isBuiltIn(from.trim()),
31
32
  isDynamic: true
32
33
  })
33
34
  }
@@ -53,6 +54,7 @@ function getStaticRequires(targetText = '') {
53
54
  index: result.index,
54
55
  isRequire: true,
55
56
  isRelative: isRelativeImport(importLocation),
57
+ isBuiltIn: isBuiltIn(importLocation),
56
58
  isDynamic: false
57
59
  })
58
60
  }
package/src/utils.js CHANGED
@@ -1,4 +1,20 @@
1
1
  const { inspectParameters, getParametersNames } = require('./vendor/inspect-parameters-declaration')
2
+ const builtinModules = require('module').builtinModules
3
+
4
+ /**
5
+ * Check if a module specifier is a Node.js built-in
6
+ * @param {string} moduleName - The module specifier (e.g., 'fs', 'node:fs/promises')
7
+ * @returns {boolean}
8
+ */
9
+ function isBuiltIn(moduleName) {
10
+ // Handle node: prefix (always a built-in)
11
+ if (moduleName.startsWith('node:')) {
12
+ return true
13
+ }
14
+ // Handle subpaths like 'fs/promises' - check the base name
15
+ const baseName = moduleName.split('/')[0]
16
+ return builtinModules.includes(baseName)
17
+ }
2
18
 
3
19
  function isRelativeImport(importLocation) {
4
20
  return !!importLocation.match(/^\./)
@@ -195,6 +211,7 @@ function extractExportName(exportValue) {
195
211
  }
196
212
 
197
213
  module.exports = {
214
+ isBuiltIn,
198
215
  isRelativeImport,
199
216
  isRelativeImportWithQuotes,
200
217
  getNames,
@@ -0,0 +1,134 @@
1
+ // Test handling of Node.js built-in modules
2
+ const { test } = require('uvu')
3
+ const assert = require('uvu/assert')
4
+ const path = require('path')
5
+ const { isBuiltIn } = require('../src/utils')
6
+ const { getStaticImports } = require('../src/get-imports')
7
+ const { getStaticRequires } = require('../src/get-requires')
8
+ const { resolveDepPaths } = require('../src/dep-graph')
9
+
10
+ const BUILTINS_FIXTURE_PATH = path.resolve(__dirname, './fixtures/builtins-example/index.js')
11
+
12
+ // isBuiltIn utility tests
13
+ test('isBuiltIn should detect node: prefix', () => {
14
+ assert.is(isBuiltIn('node:fs'), true)
15
+ assert.is(isBuiltIn('node:path'), true)
16
+ assert.is(isBuiltIn('node:stream'), true)
17
+ })
18
+
19
+ test('isBuiltIn should detect node: prefix with subpaths', () => {
20
+ assert.is(isBuiltIn('node:fs/promises'), true)
21
+ assert.is(isBuiltIn('node:stream/promises'), true)
22
+ assert.is(isBuiltIn('node:timers/promises'), true)
23
+ })
24
+
25
+ test('isBuiltIn should detect legacy bare built-ins', () => {
26
+ assert.is(isBuiltIn('fs'), true)
27
+ assert.is(isBuiltIn('path'), true)
28
+ assert.is(isBuiltIn('stream'), true)
29
+ assert.is(isBuiltIn('http'), true)
30
+ assert.is(isBuiltIn('crypto'), true)
31
+ })
32
+
33
+ test('isBuiltIn should detect legacy bare built-ins with subpaths', () => {
34
+ assert.is(isBuiltIn('fs/promises'), true)
35
+ assert.is(isBuiltIn('stream/promises'), true)
36
+ assert.is(isBuiltIn('timers/promises'), true)
37
+ })
38
+
39
+ test('isBuiltIn should return false for npm packages', () => {
40
+ assert.is(isBuiltIn('lodash'), false)
41
+ assert.is(isBuiltIn('express'), false)
42
+ assert.is(isBuiltIn('@org/package'), false)
43
+ assert.is(isBuiltIn('uvu/assert'), false)
44
+ })
45
+
46
+ test('isBuiltIn should return false for relative imports', () => {
47
+ assert.is(isBuiltIn('./foo'), false)
48
+ assert.is(isBuiltIn('../bar'), false)
49
+ assert.is(isBuiltIn('./node/fake'), false)
50
+ })
51
+
52
+ // getStaticImports with isBuiltIn flag
53
+ test('getStaticImports should mark built-ins with isBuiltIn flag', () => {
54
+ const code = `
55
+ import fs from 'fs'
56
+ import { readFile } from 'node:fs/promises'
57
+ import path from 'path'
58
+ import lodash from 'lodash'
59
+ import { foo } from './local'
60
+ `
61
+
62
+ const imports = getStaticImports(code)
63
+
64
+ const fsImport = imports.find(i => i.from === 'fs')
65
+ const nodeFsImport = imports.find(i => i.from === 'node:fs/promises')
66
+ const pathImport = imports.find(i => i.from === 'path')
67
+ const lodashImport = imports.find(i => i.from === 'lodash')
68
+ const localImport = imports.find(i => i.from === './local')
69
+
70
+ assert.is(fsImport.isBuiltIn, true, 'fs should be built-in')
71
+ assert.is(nodeFsImport.isBuiltIn, true, 'node:fs/promises should be built-in')
72
+ assert.is(pathImport.isBuiltIn, true, 'path should be built-in')
73
+ assert.is(lodashImport.isBuiltIn, false, 'lodash should not be built-in')
74
+ assert.is(localImport.isBuiltIn, false, './local should not be built-in')
75
+ })
76
+
77
+ // getStaticRequires with isBuiltIn flag
78
+ test('getStaticRequires should mark built-ins with isBuiltIn flag', () => {
79
+ const code = `
80
+ const fs = require('fs')
81
+ const { readFile } = require('node:fs/promises')
82
+ const path = require('path')
83
+ const lodash = require('lodash')
84
+ const local = require('./local')
85
+ `
86
+
87
+ const requires = getStaticRequires(code)
88
+
89
+ const fsReq = requires.find(r => r.from === 'fs')
90
+ const nodeFsReq = requires.find(r => r.from === 'node:fs/promises')
91
+ const pathReq = requires.find(r => r.from === 'path')
92
+ const lodashReq = requires.find(r => r.from === 'lodash')
93
+ const localReq = requires.find(r => r.from === './local')
94
+
95
+ assert.is(fsReq.isBuiltIn, true, 'fs should be built-in')
96
+ assert.is(nodeFsReq.isBuiltIn, true, 'node:fs/promises should be built-in')
97
+ assert.is(pathReq.isBuiltIn, true, 'path should be built-in')
98
+ assert.is(lodashReq.isBuiltIn, false, 'lodash should not be built-in')
99
+ assert.is(localReq.isBuiltIn, false, './local should not be built-in')
100
+ })
101
+
102
+ // resolveDepPaths tests for builtIns
103
+ test('resolveDepPaths should return separate builtIns array', () => {
104
+ const result = resolveDepPaths(BUILTINS_FIXTURE_PATH)
105
+
106
+ assert.ok(Array.isArray(result.builtIns), 'should have builtIns array')
107
+ assert.ok(Array.isArray(result.nodeModules), 'should have nodeModules array')
108
+ assert.ok(Array.isArray(result.files), 'should have files array')
109
+ })
110
+
111
+ test('resolveDepPaths should separate built-ins from nodeModules', () => {
112
+ const { builtIns, nodeModules } = resolveDepPaths(BUILTINS_FIXTURE_PATH)
113
+
114
+ // Built-ins should include fs, node:fs/promises, path, node:stream, node:crypto
115
+ assert.ok(builtIns.includes('fs'), 'builtIns should include fs')
116
+ assert.ok(builtIns.includes('node:fs/promises'), 'builtIns should include node:fs/promises')
117
+ assert.ok(builtIns.includes('path'), 'builtIns should include path')
118
+ assert.ok(builtIns.includes('node:stream'), 'builtIns should include node:stream')
119
+ assert.ok(builtIns.includes('node:crypto'), 'builtIns should include node:crypto')
120
+
121
+ // nodeModules should include lodash but not built-ins
122
+ assert.ok(nodeModules.includes('lodash'), 'nodeModules should include lodash')
123
+ assert.ok(!nodeModules.includes('fs'), 'nodeModules should NOT include fs')
124
+ assert.ok(!nodeModules.includes('node:fs/promises'), 'nodeModules should NOT include node:fs/promises')
125
+ })
126
+
127
+ test('resolveDepPaths builtIns should not duplicate entries', () => {
128
+ const { builtIns } = resolveDepPaths(BUILTINS_FIXTURE_PATH)
129
+
130
+ const uniqueBuiltIns = [...new Set(builtIns)]
131
+ assert.is(builtIns.length, uniqueBuiltIns.length, 'builtIns should be deduplicated')
132
+ })
133
+
134
+ test.run()
@@ -438,4 +438,87 @@ test('includeNodeModules works independently of verifyNodeModules', () => {
438
438
  assert.ok(indexDeps.includes('lodash'), 'Should include lodash without verification')
439
439
  })
440
440
 
441
+ // returnErrors tests
442
+ test('returnErrors: true should return { graph, errors } instead of throwing', () => {
443
+ const fs = require('fs')
444
+ const testFile = path.resolve(__dirname, 'fixtures/test-return-errors.js')
445
+
446
+ fs.writeFileSync(testFile, `
447
+ const missing = require('missing-package-xyz')
448
+ module.exports = { missing }
449
+ `)
450
+
451
+ try {
452
+ const result = depGraph(testFile, { verifyNodeModules: true, returnErrors: true })
453
+
454
+ assert.ok(result.graph instanceof Map, 'Should return graph in result')
455
+ assert.ok(Array.isArray(result.errors), 'Should return errors array')
456
+ assert.ok(result.errors.length > 0, 'Should have errors for missing package')
457
+ assert.ok(result.errors[0].message.includes('missing-package-xyz'), 'Error should mention package')
458
+ } finally {
459
+ fs.unlinkSync(testFile)
460
+ }
461
+ })
462
+
463
+ test('returnErrors: true with no errors returns empty errors array', () => {
464
+ const result = depGraph(CJS_FIXTURE_PATH, { returnErrors: true })
465
+
466
+ assert.ok(result.graph instanceof Map, 'Should return graph')
467
+ assert.ok(Array.isArray(result.errors), 'Should return errors array')
468
+ assert.is(result.errors.length, 0, 'Should have no errors')
469
+ })
470
+
471
+ test('returnErrors: true collects all errors without throwing', () => {
472
+ const fs = require('fs')
473
+ const testFile = path.resolve(__dirname, 'fixtures/test-return-multi-errors.js')
474
+
475
+ fs.writeFileSync(testFile, `
476
+ const missing1 = require('missing-pkg-1-xyz')
477
+ const missing2 = require('missing-pkg-2-xyz')
478
+ module.exports = { missing1, missing2 }
479
+ `)
480
+
481
+ try {
482
+ const result = depGraph(testFile, { verifyNodeModules: true, returnErrors: true })
483
+
484
+ assert.is(result.errors.length, 2, 'Should collect both errors')
485
+ assert.ok(result.errors.some(e => e.message.includes('missing-pkg-1-xyz')), 'Should have first error')
486
+ assert.ok(result.errors.some(e => e.message.includes('missing-pkg-2-xyz')), 'Should have second error')
487
+ } finally {
488
+ fs.unlinkSync(testFile)
489
+ }
490
+ })
491
+
492
+ // resolveDepPaths with returnErrors
493
+ test('resolveDepPaths with returnErrors: true returns { files, nodeModules, errors }', () => {
494
+ const fs = require('fs')
495
+ const testFile = path.resolve(__dirname, 'fixtures/test-resolve-return-errors.js')
496
+
497
+ fs.writeFileSync(testFile, `
498
+ const missing = require('missing-resolve-pkg-xyz')
499
+ module.exports = { missing }
500
+ `)
501
+
502
+ try {
503
+ const result = resolveDepPaths(testFile, { verifyNodeModules: true, returnErrors: true })
504
+
505
+ assert.ok(Array.isArray(result.files), 'Should have files array')
506
+ assert.ok(Array.isArray(result.nodeModules), 'Should have nodeModules array')
507
+ assert.ok(Array.isArray(result.errors), 'Should have errors array')
508
+ assert.ok(result.errors.length > 0, 'Should have errors')
509
+ assert.ok(result.errors[0].message.includes('missing-resolve-pkg-xyz'), 'Error should mention package')
510
+ } finally {
511
+ fs.unlinkSync(testFile)
512
+ }
513
+ })
514
+
515
+ test('resolveDepPaths with returnErrors: true and no errors', () => {
516
+ const result = resolveDepPaths(CJS_FIXTURE_PATH, { returnErrors: true })
517
+
518
+ assert.ok(Array.isArray(result.files), 'Should have files')
519
+ assert.ok(Array.isArray(result.nodeModules), 'Should have nodeModules')
520
+ assert.ok(Array.isArray(result.errors), 'Should have errors array')
521
+ assert.is(result.errors.length, 0, 'Should have no errors')
522
+ })
523
+
441
524
  test.run()
@@ -0,0 +1,8 @@
1
+ // Local helper using built-ins
2
+ const { createHash } = require('node:crypto')
3
+
4
+ function helper() {
5
+ return createHash('sha256')
6
+ }
7
+
8
+ module.exports = { helper }
@@ -0,0 +1,16 @@
1
+ // Fixture using Node.js built-ins and npm packages
2
+ const fs = require('fs')
3
+ const { readFile } = require('node:fs/promises')
4
+ const path = require('path')
5
+ const { Transform } = require('node:stream')
6
+ const lodash = require('lodash')
7
+ const { helper } = require('./helper')
8
+
9
+ module.exports = {
10
+ fs,
11
+ readFile,
12
+ path,
13
+ Transform,
14
+ lodash,
15
+ helper
16
+ }
@@ -50,7 +50,8 @@ test('getStaticImports', async () => {
50
50
  },
51
51
  from: 'url',
52
52
  isImport: true,
53
- isRelative: false
53
+ isRelative: false,
54
+ isBuiltIn: true
54
55
  },
55
56
  {
56
57
  line: "import foo from 'fs'",
@@ -59,7 +60,8 @@ test('getStaticImports', async () => {
59
60
  definitions: { declaration: 'foo', name: 'foo' },
60
61
  from: 'fs',
61
62
  isImport: true,
62
- isRelative: false
63
+ isRelative: false,
64
+ isBuiltIn: true
63
65
  },
64
66
  {
65
67
  line: "import * as Fs from 'fs'",
@@ -68,7 +70,8 @@ test('getStaticImports', async () => {
68
70
  definitions: { declaration: '* as Fs', name: '*', alias: 'Fs' },
69
71
  from: 'fs',
70
72
  isImport: true,
71
- isRelative: false
73
+ isRelative: false,
74
+ isBuiltIn: true
72
75
  },
73
76
  {
74
77
  line: "import assert from 'uvu/assert'",
@@ -77,7 +80,8 @@ test('getStaticImports', async () => {
77
80
  definitions: { declaration: 'assert', name: 'assert' },
78
81
  from: 'uvu/assert',
79
82
  isImport: true,
80
- isRelative: false
83
+ isRelative: false,
84
+ isBuiltIn: false
81
85
  }
82
86
  ])
83
87
  })
@@ -105,7 +109,8 @@ test('get jsDoc Imports', async () => {
105
109
  importName: 'hdhdhdhdhddh',
106
110
  isImport: true,
107
111
  isTypeImport: true,
108
- isRelative: true
112
+ isRelative: true,
113
+ isBuiltIn: false
109
114
  },
110
115
  {
111
116
  importStatement: 'import("lodash").omit',
@@ -113,7 +118,8 @@ test('get jsDoc Imports', async () => {
113
118
  importName: 'omit',
114
119
  isImport: true,
115
120
  isTypeImport: true,
116
- isRelative: false
121
+ isRelative: false,
122
+ isBuiltIn: false
117
123
  },
118
124
  {
119
125
  importStatement: 'import("uvu/assert")',
@@ -121,7 +127,8 @@ test('get jsDoc Imports', async () => {
121
127
  importName: '',
122
128
  isImport: true,
123
129
  isTypeImport: true,
124
- isRelative: false
130
+ isRelative: false,
131
+ isBuiltIn: false
125
132
  }
126
133
  ])
127
134
  })
@@ -166,6 +173,7 @@ test('getDynamicImports', async () => {
166
173
  from: "'./module.js'",
167
174
  isImport: true,
168
175
  isRelative: true,
176
+ isBuiltIn: false,
169
177
  isDynamic: true
170
178
  },
171
179
  {
@@ -176,6 +184,7 @@ test('getDynamicImports', async () => {
176
184
  from: 'moduleName',
177
185
  isImport: true,
178
186
  isRelative: false,
187
+ isBuiltIn: false,
179
188
  isDynamic: true
180
189
  },
181
190
  {
@@ -186,6 +195,7 @@ test('getDynamicImports', async () => {
186
195
  from: '`./src/${folder}/Button.js`',
187
196
  isImport: true,
188
197
  isRelative: false,
198
+ isBuiltIn: false,
189
199
  isDynamic: true
190
200
  },
191
201
  {
@@ -196,6 +206,7 @@ test('getDynamicImports', async () => {
196
206
  from: 'modulePath',
197
207
  isImport: true,
198
208
  isRelative: false,
209
+ isBuiltIn: false,
199
210
  isDynamic: true
200
211
  },
201
212
  {
@@ -218,6 +229,7 @@ test('getDynamicImports', async () => {
218
229
  from: "'./Component.js'",
219
230
  isImport: true,
220
231
  isRelative: true,
232
+ isBuiltIn: false,
221
233
  isDynamic: true
222
234
  },
223
235
  {
@@ -228,6 +240,7 @@ test('getDynamicImports', async () => {
228
240
  from: 'getModulePath()',
229
241
  isImport: true,
230
242
  isRelative: false,
243
+ isBuiltIn: false,
231
244
  isDynamic: true
232
245
  }
233
246
  ])
@@ -324,6 +337,7 @@ import styles from './styles.css' with { type: 'css' }
324
337
  assertionType: 'assert',
325
338
  isImport: true,
326
339
  isRelative: true,
340
+ isBuiltIn: false,
327
341
  isAssertion: true
328
342
  },
329
343
  {
@@ -336,6 +350,7 @@ import styles from './styles.css' with { type: 'css' }
336
350
  assertionType: 'assert',
337
351
  isImport: true,
338
352
  isRelative: true,
353
+ isBuiltIn: false,
339
354
  isAssertion: true
340
355
  },
341
356
  {
@@ -348,6 +363,7 @@ import styles from './styles.css' with { type: 'css' }
348
363
  assertionType: 'with',
349
364
  isImport: true,
350
365
  isRelative: true,
366
+ isBuiltIn: false,
351
367
  isAssertion: true
352
368
  },
353
369
  {
@@ -360,6 +376,7 @@ import styles from './styles.css' with { type: 'css' }
360
376
  assertionType: 'with',
361
377
  isImport: true,
362
378
  isRelative: true,
379
+ isBuiltIn: false,
363
380
  isAssertion: true
364
381
  }
365
382
  ])
@@ -33,6 +33,7 @@ test('getRequires', async () => {
33
33
  from: 'uvu',
34
34
  isRequire: true,
35
35
  isRelative: false,
36
+ isBuiltIn: false,
36
37
  isDynamic: false
37
38
  },
38
39
  {
@@ -43,6 +44,7 @@ test('getRequires', async () => {
43
44
  from: 'uvu/assert',
44
45
  isRequire: true,
45
46
  isRelative: false,
47
+ isBuiltIn: false,
46
48
  isDynamic: false
47
49
  },
48
50
  {
@@ -58,6 +60,7 @@ test('getRequires', async () => {
58
60
  from: './get-imports',
59
61
  isRequire: true,
60
62
  isRelative: true,
63
+ isBuiltIn: false,
61
64
  isDynamic: false
62
65
  }
63
66
  ])
@@ -96,6 +99,7 @@ test('getRequires 2', async () => {
96
99
  from: 'uvu',
97
100
  isRequire: true,
98
101
  isRelative: false,
102
+ isBuiltIn: false,
99
103
  isDynamic: false
100
104
  },
101
105
  {
@@ -106,6 +110,7 @@ test('getRequires 2', async () => {
106
110
  from: 'uvu/assert',
107
111
  isRequire: true,
108
112
  isRelative: false,
113
+ isBuiltIn: false,
109
114
  isDynamic: false
110
115
  },
111
116
  {
@@ -121,6 +126,7 @@ test('getRequires 2', async () => {
121
126
  from: './get-imports',
122
127
  isRequire: true,
123
128
  isRelative: true,
129
+ isBuiltIn: false,
124
130
  isDynamic: false
125
131
  }
126
132
  ])
@@ -151,6 +157,7 @@ test('getRequires with dynamic requires', async () => {
151
157
  from: 'moduleName',
152
158
  isRequire: true,
153
159
  isRelative: false,
160
+ isBuiltIn: false,
154
161
  isDynamic: true
155
162
  },
156
163
  {
@@ -161,6 +168,7 @@ test('getRequires with dynamic requires', async () => {
161
168
  from: "path.join(__dirname, 'utils')",
162
169
  isRequire: true,
163
170
  isRelative: false,
171
+ isBuiltIn: false,
164
172
  isDynamic: true
165
173
  },
166
174
  {
@@ -171,6 +179,7 @@ test('getRequires with dynamic requires', async () => {
171
179
  from: '`./${folder}/file`',
172
180
  isRequire: true,
173
181
  isRelative: false,
182
+ isBuiltIn: false,
174
183
  isDynamic: true
175
184
  },
176
185
  {
@@ -193,6 +202,7 @@ test('getRequires with dynamic requires', async () => {
193
202
  from: 'moduleTwo',
194
203
  isRequire: true,
195
204
  isRelative: false,
205
+ isBuiltIn: false,
196
206
  isDynamic: true
197
207
  }
198
208
  ])
@@ -7,7 +7,8 @@
7
7
  * @param {boolean} [options.verifyNodeModules] - If true, verify node_modules packages can be resolved. Default: false
8
8
  * @param {boolean} [options.includeNodeModules] - If true, include node_modules package names in the graph. Default: false
9
9
  * @param {boolean} [options.throwOnFirstError] - If true, throw immediately on first error. Default: false
10
- * @returns {Map<string, string[]>|undefined} - Dependency graph where keys are file paths and values are arrays of dependency paths (or package names if includeNodeModules). Returns undefined if buildGraph is false.
10
+ * @param {boolean} [options.returnErrors] - If true, return { graph, errors } instead of throwing. Default: false
11
+ * @returns {Map<string, string[]>|{graph: Map, errors: Error[]}|undefined} - Dependency graph, or { graph, errors } if returnErrors is true. Returns undefined if buildGraph is false.
11
12
  */
12
13
  export function depGraph(filePath: string, options?: {
13
14
  buildGraph?: boolean;
@@ -15,15 +16,29 @@ export function depGraph(filePath: string, options?: {
15
16
  verifyNodeModules?: boolean;
16
17
  includeNodeModules?: boolean;
17
18
  throwOnFirstError?: boolean;
18
- }): Map<string, string[]> | undefined;
19
+ returnErrors?: boolean;
20
+ }): Map<string, string[]> | {
21
+ graph: Map<any, any>;
22
+ errors: Error[];
23
+ } | undefined;
19
24
  /**
20
25
  * Get all dependency file paths in build order (dependencies first), deduplicated
21
26
  * @param {string} filePath - Entry file path
22
27
  * @param {object} options - Options to pass to depGraph
23
- * @returns {{ files: string[], nodeModules: string[] }} - Object with files in topological order and unique node_modules
28
+ * @param {boolean} [options.verifyGraph] - If true, verify imports/exports. Default: true
29
+ * @param {boolean} [options.verifyNodeModules] - If true, verify node_modules packages can be resolved. Default: false
30
+ * @param {boolean} [options.throwOnFirstError] - If true, throw immediately on first error. Default: false
31
+ * @param {boolean} [options.returnErrors] - If true, include errors array in result instead of throwing
32
+ * @returns {{ files: string[], nodeModules: string[], errors?: Error[] }} - Object with files in topological order and unique node_modules
24
33
  */
25
- export function resolveDepPaths(filePath: string, options?: object): {
34
+ export function resolveDepPaths(filePath: string, options?: {
35
+ verifyGraph?: boolean;
36
+ verifyNodeModules?: boolean;
37
+ throwOnFirstError?: boolean;
38
+ returnErrors?: boolean;
39
+ }): {
26
40
  files: string[];
27
41
  nodeModules: string[];
42
+ errors?: Error[];
28
43
  };
29
44
  //# sourceMappingURL=dep-graph.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dep-graph.d.ts","sourceRoot":"","sources":["../src/dep-graph.js"],"names":[],"mappings":"AAmQA;;;;;;;;;;GAUG;AACH,mCATW,MAAM,YAEd;IAA0B,UAAU,GAA5B,OAAO;IACW,WAAW,GAA7B,OAAO;IACW,iBAAiB,GAAnC,OAAO;IACW,kBAAkB,GAApC,OAAO;IACW,iBAAiB,GAAnC,OAAO;CACf,GAAU,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAC,SAAS,CAyB3C;AAGD;;;;;GAKG;AACH,0CAJW,MAAM,YACN,MAAM,GACJ;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAA;CAAE,CAqDtD"}
1
+ {"version":3,"file":"dep-graph.d.ts","sourceRoot":"","sources":["../src/dep-graph.js"],"names":[],"mappings":"AAmQA;;;;;;;;;;;GAWG;AACH,mCAVW,MAAM,YAEd;IAA0B,UAAU,GAA5B,OAAO;IACW,WAAW,GAA7B,OAAO;IACW,iBAAiB,GAAnC,OAAO;IACW,kBAAkB,GAApC,OAAO;IACW,iBAAiB,GAAnC,OAAO;IACW,YAAY,GAA9B,OAAO;CACf,GAAU,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAC;IAAC,KAAK,gBAAM;IAAC,MAAM,EAAE,KAAK,EAAE,CAAA;CAAC,GAAC,SAAS,CA8BzE;AAGD;;;;;;;;;GASG;AACH,0CARW,MAAM,YAEd;IAA0B,WAAW,GAA7B,OAAO;IACW,iBAAiB,GAAnC,OAAO;IACW,iBAAiB,GAAnC,OAAO;IACW,YAAY,GAA9B,OAAO;CACf,GAAU;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAA;CAAE,CA4ExE"}