@davidwells/extract-deps 0.1.2 → 0.1.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@davidwells/extract-deps",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Get imports and requires from a codebase without AST",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -1,4 +1,5 @@
1
1
  // via https://github.com/unjs/mlly/blob/6bf5ad4d784e314319f872a8df41d64edd4e5505/src/syntax.ts#L7
2
+ const { stripComments } = require('./utils')
2
3
 
3
4
  const ESM_RE =
4
5
  /([\s;]|^)(import\b[\s\w*,{}]*from|import\b\s*["'*{]|export\b\s*(?:[*{]|default|class|type|interface|enum|function|const|var|let|async function)|import\.meta\b)/m;
@@ -6,8 +7,6 @@ const ESM_RE =
6
7
  const CJS_RE =
7
8
  /([\s;]|^)(module\.exports\b|exports\.\w|require\s*\(|global\.\w)/m;
8
9
 
9
- const COMMENT_RE = /\/\*.+?\*\/|\/\/.*(?:\r?\n|$)/g;
10
-
11
10
  const BUILTIN_EXTENSIONS = new Set([".mjs", ".cjs", ".node", ".wasm"]);
12
11
 
13
12
  /**
@@ -25,8 +24,8 @@ const BUILTIN_EXTENSIONS = new Set([".mjs", ".cjs", ".node", ".wasm"]);
25
24
  */
26
25
  function hasESMSyntax(code, opts = {}) {
27
26
  // Always strip comments to avoid false positives from commented syntax
28
- code = code.replace(COMMENT_RE, "");
29
- return ESM_RE.test(code);
27
+ code = stripComments(code)
28
+ return ESM_RE.test(code)
30
29
  }
31
30
 
32
31
  /**
@@ -38,8 +37,8 @@ function hasESMSyntax(code, opts = {}) {
38
37
  */
39
38
  function hasCJSSyntax(code, opts = {}) {
40
39
  // Always strip comments to avoid false positives from commented syntax
41
- code = code.replace(COMMENT_RE, "");
42
- return CJS_RE.test(code);
40
+ code = stripComments(code)
41
+ return CJS_RE.test(code)
43
42
  }
44
43
 
45
44
  /**
@@ -51,16 +50,16 @@ function hasCJSSyntax(code, opts = {}) {
51
50
  */
52
51
  function detectSyntax(code, opts = {}) {
53
52
  // Always strip comments to avoid false positives from commented syntax
54
- code = code.replace(COMMENT_RE, "");
53
+ code = stripComments(code)
55
54
  // We strip comments once hence not passing opts down to hasESMSyntax and hasCJSSyntax
56
- const hasESM = hasESMSyntax(code, {});
57
- const hasCJS = hasCJSSyntax(code, {});
55
+ const hasESM = hasESMSyntax(code, {})
56
+ const hasCJS = hasCJSSyntax(code, {})
58
57
 
59
58
  return {
60
59
  hasESM,
61
60
  hasCJS,
62
61
  isMixed: hasESM && hasCJS,
63
- };
62
+ }
64
63
  }
65
64
 
66
65
  module.exports = {
@@ -1,4 +1,4 @@
1
- const { getNames, extractExportName } = require('./utils')
1
+ const { getNames, extractExportName, stripComments } = require('./utils')
2
2
 
3
3
  // https://regex101.com/r/example/1
4
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
@@ -15,7 +15,9 @@ const EXPORT_TYPE_REGEX = /export\s+(?:type|interface)\s+([\w$]+)/gm
15
15
  // https://regex101.com/r/example/7
16
16
  const EXPORT_ASSERTION_REGEX = /export\s+(?:["'\s]*([\w*{}\n\r\t, ]+)from\s*)?["'\s](.*[@\w_-]+)["'\s]+(assert|with)\s*\{([^}]+)\};?$/gm
17
17
 
18
- function getExports(code, options = {}) {
18
+ function getExports(code = '', options = {}) {
19
+ // Strip comments to avoid false positives
20
+ code = stripComments(code)
19
21
  const defaultExports = getDefaultExports(code)
20
22
  const namedExports = getNamedExports(code)
21
23
  const namedDeclarationExports = getNamedDeclarationExports(code)
@@ -1,4 +1,4 @@
1
- const { isBuiltIn, isRelativeImport, isRelativeImportWithQuotes, getNames } = require('./utils')
1
+ const { isBuiltIn, isRelativeImport, isRelativeImportWithQuotes, getNames, stripComments } = 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
@@ -9,7 +9,9 @@ const DYNAMIC_IMPORT_REGEX = /(?:(const|var|let)\s+([\w*{}\n\r\t,:= ]+)\s*=\s*)?
9
9
  // https://regex101.com/r/example/1
10
10
  const ASSERTION_IMPORT_REGEX = /(?:^|\n)\s*import\s+(?:["'\s]*([\w*{}\n\r\t, ]+)from\s*)?["'\s](.*[@\w_-]+)["'\s]+(assert|with)\s*\{([^}]+)\};?$/gm
11
11
 
12
- function getImports(code, options = {}) {
12
+ function getImports(code = '', options = {}) {
13
+ // Strip comments to avoid false positives
14
+ code = stripComments(code)
13
15
  const staticImports = getStaticImports(code)
14
16
  const dynamicImports = getDynamicImports(code)
15
17
  if (options.includeAssertionImports) {
package/src/utils.js CHANGED
@@ -1,6 +1,26 @@
1
1
  const { inspectParameters, getParametersNames } = require('./vendor/inspect-parameters-declaration')
2
2
  const builtinModules = require('module').builtinModules
3
3
 
4
+ const COMMENT_RE = /\/\*[\s\S]*?\*\/|\/\/.*(?:\r?\n|$)/g
5
+ const PROTOCOL_PLACEHOLDER = '__PROTO_SLASH__'
6
+
7
+ /**
8
+ * Strip comments from code, preserving :// in URLs
9
+ * @param {string} code
10
+ * @returns {string}
11
+ */
12
+ function stripComments(code) {
13
+ const hasProtocol = code.indexOf('://') > -1
14
+ if (hasProtocol) {
15
+ code = code.replace(/:\/\//g, PROTOCOL_PLACEHOLDER)
16
+ }
17
+ code = code.replace(COMMENT_RE, '')
18
+ if (hasProtocol) {
19
+ code = code.replace(/__PROTO_SLASH__/g, '://')
20
+ }
21
+ return code
22
+ }
23
+
4
24
  /**
5
25
  * Check if a module specifier is a Node.js built-in
6
26
  * @param {string} moduleName - The module specifier (e.g., 'fs', 'node:fs/promises')
@@ -211,6 +231,7 @@ function extractExportName(exportValue) {
211
231
  }
212
232
 
213
233
  module.exports = {
234
+ stripComments,
214
235
  isBuiltIn,
215
236
  isRelativeImport,
216
237
  isRelativeImportWithQuotes,
@@ -532,4 +532,35 @@ export {
532
532
  assert.equal(foundExports[0].exportAlias, 'myHandler', 'exportAlias should be "myHandler" without trailing comma')
533
533
  })
534
534
 
535
+ test('should ignore commented-out exports', () => {
536
+ const code = `
537
+ // export const foo = 'foo'
538
+ /* export default bar */
539
+ /*
540
+ export const multiLine = 'test'
541
+ */
542
+ export const realExport = 'real'
543
+ `
544
+
545
+ const foundExports = getExports(code)
546
+
547
+ assert.equal(foundExports.length, 1, 'Should only find 1 real export')
548
+ assert.equal(foundExports[0].exportName, 'realExport', 'Should find realExport')
549
+ })
550
+
551
+ test('should preserve URLs with :// in strings', () => {
552
+ const code = `
553
+ export const url = 'http://example.com/path'
554
+ export const https = 'https://secure.com'
555
+ export const real = 'value' // this comment should be stripped
556
+ `
557
+
558
+ const foundExports = getExports(code)
559
+
560
+ assert.equal(foundExports.length, 3, 'Should find 3 exports')
561
+ assert.equal(foundExports[0].exportName, 'url', 'Should find url export')
562
+ assert.equal(foundExports[1].exportName, 'https', 'Should find https export')
563
+ assert.equal(foundExports[2].exportName, 'real', 'Should find real export')
564
+ })
565
+
535
566
  test.run()
@@ -412,4 +412,31 @@ import styles from './styles.css' with { type: 'css' }
412
412
  assert.is(hasWithImport, true, 'Should have with import')
413
413
  })
414
414
 
415
+ test('should ignore commented-out imports', () => {
416
+ const code = `
417
+ // import foo from 'foo'
418
+ /* import bar from 'bar' */
419
+ /*
420
+ import multiLine from 'multi'
421
+ */
422
+ import realImport from 'real'
423
+ `
424
+
425
+ const importsFound = getImports(code)
426
+
427
+ assert.equal(importsFound.length, 1, 'Should only find 1 real import')
428
+ assert.equal(importsFound[0].from, 'real', 'Should find real import')
429
+ })
430
+
431
+ test('should preserve URLs with :// in strings', () => {
432
+ const code = `
433
+ import foo from 'foo' // http://example.com
434
+ `
435
+
436
+ const importsFound = getImports(code)
437
+
438
+ assert.equal(importsFound.length, 1, 'Should find 1 import')
439
+ assert.equal(importsFound[0].from, 'foo', 'Should find foo import')
440
+ })
441
+
415
442
  test.run()