@davidwells/extract-deps 0.1.9 → 0.1.12
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 +1 -1
- package/src/dep-graph.js +1 -1
- package/src/get-cjs-exports.js +6 -8
- package/src/get-exports.js +7 -7
- package/src/get-imports.js +5 -6
- package/src/get-requires.js +46 -5
- package/src/index.js +29 -0
- package/src/utils.js +224 -32
- package/tests/dep-graph.test.js +27 -0
- package/tests/fixtures/ts-regex-export-fixture/index.ts +8 -0
- package/tests/fixtures/ts-regex-export-fixture/message-builder.ts +23 -0
- package/tests/get-exports.test.js +62 -2
- package/tests/index.test.js +11 -0
- package/tests/parser-edge-cases.test.js +101 -0
- package/tests/utils.test.js +8 -0
- package/types/dep-graph.d.ts +45 -0
- package/types/dep-graph.d.ts.map +1 -0
- package/types/detect-syntax.d.ts +39 -0
- package/types/detect-syntax.d.ts.map +1 -0
- package/types/get-cjs-exports.d.ts +45 -0
- package/types/get-cjs-exports.d.ts.map +1 -0
- package/types/get-exports.d.ts +54 -0
- package/types/get-exports.d.ts.map +1 -0
- package/types/get-imports.d.ts +59 -0
- package/types/get-imports.d.ts.map +1 -0
- package/types/get-requires.d.ts +37 -0
- package/types/get-requires.d.ts.map +1 -0
- package/types/index.d.ts +25 -0
- package/types/index.d.ts.map +1 -0
- package/types/utils.d.ts +76 -0
- package/types/utils.d.ts.map +1 -0
- package/types/vendor/inspect-parameters-declaration.d.ts +4 -0
- package/types/vendor/inspect-parameters-declaration.d.ts.map +1 -0
- package/types/verify-package-entries.d.ts +30 -0
- package/types/verify-package-entries.d.ts.map +1 -0
package/package.json
CHANGED
package/src/dep-graph.js
CHANGED
|
@@ -3,7 +3,7 @@ const path = require('path')
|
|
|
3
3
|
const fs = require('fs')
|
|
4
4
|
const { pathToFileURL, fileURLToPath } = require('url')
|
|
5
5
|
const { resolve: resolveImport } = require('@dual-bundle/import-meta-resolve')
|
|
6
|
-
const { extractDeps } = require('./index')
|
|
6
|
+
const { extractDepsShared: extractDeps } = require('./index')
|
|
7
7
|
const { isBuiltIn } = require('./utils')
|
|
8
8
|
|
|
9
9
|
function fsExistsSync(path) {
|
package/src/get-cjs-exports.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Extracts CommonJS module.exports and exports patterns from JavaScript code
|
|
2
2
|
|
|
3
|
-
const { getNames, extractExportName,
|
|
3
|
+
const { getNames, extractExportName, stripCommentsAndStrings } = require('./utils')
|
|
4
4
|
|
|
5
5
|
// Matches: module.exports = ... or exports = module.exports = ...
|
|
6
6
|
// https://regex101.com/r/example/cjs-1
|
|
@@ -35,13 +35,11 @@ function stripComments(code) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
function getCjsExports(code) {
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
// Strip comments to prevent false positives from commented code
|
|
44
|
-
const sanitizedCode = stripComments(code)
|
|
38
|
+
// Single tokenizer-based pass that blanks comments and code-bearing
|
|
39
|
+
// strings/templates together. Length is preserved so the position-based
|
|
40
|
+
// logic below (which slices into the original `code` for full export
|
|
41
|
+
// values) keeps working off the same indices.
|
|
42
|
+
const sanitizedCode = stripCommentsAndStrings(code)
|
|
45
43
|
|
|
46
44
|
const assignmentExports = getModuleExportsAssignment(code, sanitizedCode)
|
|
47
45
|
const modulePropertyExports = getModuleExportsProperty(code, sanitizedCode)
|
package/src/get-exports.js
CHANGED
|
@@ -3,7 +3,7 @@ const { getNames, extractExportName, stripComments, stripStringContents } = requ
|
|
|
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
|
|
5
5
|
// https://regex101.com/r/example/2
|
|
6
|
-
const EXPORT_NAMED_REGEX = /export\s+(?:const|let|var|function|class|async\s+function)\s+([\w$]+)/gm
|
|
6
|
+
const EXPORT_NAMED_REGEX = /export\s+(?:const\s+enum|enum|const|let|var|function|class|async\s+function)\s+([\w$]+)/gm
|
|
7
7
|
// https://regex101.com/r/example/3
|
|
8
8
|
const EXPORT_NAMED_DECLARATION_REGEX = /export\s*{([^}]+)}/gm
|
|
9
9
|
// https://regex101.com/r/example/4
|
|
@@ -16,12 +16,12 @@ const EXPORT_TYPE_REGEX = /export\s+(?:type|interface)\s+([\w$]+)/gm
|
|
|
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
18
|
function getExports(code = '', options = {}) {
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
// Strip comments to avoid false positives
|
|
19
|
+
// Comments first, then strings — order matters. Running stripStringContents
|
|
20
|
+
// alone would mis-pair an apostrophe inside a JSDoc comment (`Netlify's …`)
|
|
21
|
+
// with a later quote and shift subsequent backtick pairing, which could
|
|
22
|
+
// swallow real `export` declarations a few lines later.
|
|
24
23
|
code = stripComments(code)
|
|
24
|
+
code = stripStringContents(code)
|
|
25
25
|
const defaultExports = getDefaultExports(code)
|
|
26
26
|
const namedExports = getNamedExports(code)
|
|
27
27
|
const namedDeclarationExports = getNamedDeclarationExports(code)
|
|
@@ -303,4 +303,4 @@ module.exports = {
|
|
|
303
303
|
getNamespaceExports,
|
|
304
304
|
getTypeExports,
|
|
305
305
|
getAssertionExports
|
|
306
|
-
}
|
|
306
|
+
}
|
package/src/get-imports.js
CHANGED
|
@@ -37,13 +37,12 @@ const DYNAMIC_IMPORT_REGEX = /(?:(const|var|let)\s+([\w*{}\n\r\t,:= $]+)\s*=\s*)
|
|
|
37
37
|
const ASSERTION_IMPORT_REGEX = /(?:^|\n)\s*import\s+(?:["'\s]*([\w*{}\n\r\t, $]+)from\s*)?["'\s]+([^"'`\n;\s]+)\s*["']\s+(assert|with)\s*\{([^}]+)\}/gm
|
|
38
38
|
|
|
39
39
|
function getImports(code = '', options = {}) {
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
code = stripStringContents(code)
|
|
45
|
-
// Strip comments to avoid false positives
|
|
40
|
+
// Strip comments FIRST so apostrophes/backticks inside JSDoc text get
|
|
41
|
+
// removed before `stripStringContents` looks for string literals.
|
|
42
|
+
// (Running the two in the opposite order let comment chars masquerade as
|
|
43
|
+
// string openers and swallow real `import`/`export` lines further down.)
|
|
46
44
|
code = stripComments(code)
|
|
45
|
+
code = stripStringContents(code)
|
|
47
46
|
const staticImports = getStaticImports(code)
|
|
48
47
|
const dynamicImports = getDynamicImports(code)
|
|
49
48
|
if (options.includeAssertionImports) {
|
package/src/get-requires.js
CHANGED
|
@@ -38,11 +38,51 @@ function getDynamicRequires(code) {
|
|
|
38
38
|
return results
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
// Sticky copy of REQUIRE_REGEX: matches only at an exact start position.
|
|
42
|
+
const REQUIRE_REGEX_AT = new RegExp(REQUIRE_REGEX.source, 'my')
|
|
43
|
+
// Every char REQUIRE_REGEX can consume before its literal `require(`.
|
|
44
|
+
const REQUIRE_PREFIX_CHAR = /[\w\s*{}:=,$]/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Same result as `REQUIRE_REGEX.exec` with `lastIndex = from`, but only
|
|
48
|
+
* attempts start positions that can reach a `require(` literal. Scanning
|
|
49
|
+
* every position is quadratic on long lines because of the leading
|
|
50
|
+
* `(?!.*await\s+import)` lookahead.
|
|
51
|
+
*
|
|
52
|
+
* A match starting at `s` must contain `require(` at some `p >= s` with
|
|
53
|
+
* every char in [s, p) matching REQUIRE_PREFIX_CHAR. `(` is not in that set,
|
|
54
|
+
* so the match uses the first `require(` at or after `s`. For each
|
|
55
|
+
* `require(` at `p`, the only viable starts are therefore [q, p], where q
|
|
56
|
+
* walks back from p over prefix chars. Trying those in ascending order finds
|
|
57
|
+
* the same leftmost match.
|
|
58
|
+
* @param {string} text
|
|
59
|
+
* @param {number} from
|
|
60
|
+
*/
|
|
61
|
+
function execRequireFrom(text, from) {
|
|
62
|
+
let searchFrom = from
|
|
63
|
+
let tried = from
|
|
64
|
+
while (true) {
|
|
65
|
+
const requireIndex = text.indexOf('require(', searchFrom)
|
|
66
|
+
if (requireIndex === -1) return null
|
|
67
|
+
let start = requireIndex
|
|
68
|
+
while (start > tried && REQUIRE_PREFIX_CHAR.test(text[start - 1])) start--
|
|
69
|
+
for (; start <= requireIndex; start++) {
|
|
70
|
+
REQUIRE_REGEX_AT.lastIndex = start
|
|
71
|
+
const match = REQUIRE_REGEX_AT.exec(text)
|
|
72
|
+
if (match) return match
|
|
73
|
+
}
|
|
74
|
+
tried = requireIndex + 1
|
|
75
|
+
searchFrom = requireIndex + 1
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
41
79
|
// https://regex101.com/r/sR1TIP/1
|
|
42
80
|
function getStaticRequires(targetText = '') {
|
|
43
81
|
let requireStatements = []
|
|
44
82
|
var result;
|
|
45
|
-
|
|
83
|
+
let searchStart = 0
|
|
84
|
+
while((result = execRequireFrom(targetText, searchStart)) !== null) {
|
|
85
|
+
searchStart = result.index + result[0].length
|
|
46
86
|
const [ line, varType, names, from ] = result
|
|
47
87
|
// console.log('getStaticRequires result', result)
|
|
48
88
|
const importLocation = from
|
|
@@ -65,11 +105,12 @@ function getStaticRequires(targetText = '') {
|
|
|
65
105
|
}
|
|
66
106
|
|
|
67
107
|
function getRequires(code) {
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
|
|
108
|
+
// Strip comments first, then strings — order matters. `stripComments`
|
|
109
|
+
// alone would mis-eat `//` inside strings; running it first instead means
|
|
110
|
+
// comment chars (incl. apostrophes/backticks inside JSDoc) disappear
|
|
111
|
+
// before `stripStringContents` looks for real string literals.
|
|
72
112
|
code = stripComments(code)
|
|
113
|
+
code = stripStringContents(code)
|
|
73
114
|
const staticRequires = getStaticRequires(code)
|
|
74
115
|
const dynamicRequires = getDynamicRequires(code)
|
|
75
116
|
return staticRequires.concat(dynamicRequires).sort((a, b) => a.index - b.index)
|
package/src/index.js
CHANGED
|
@@ -16,7 +16,35 @@ const {
|
|
|
16
16
|
// https://github.com/ganeshkbhat/get-imports/blob/main/index.js
|
|
17
17
|
// Alt get imports https://github.com/beenotung/fix-esm-import-path/blob/master/fix-esm-import-path.js#L186
|
|
18
18
|
|
|
19
|
+
// Parse results keyed by source text. Extraction is a pure function of the
|
|
20
|
+
// code, and dep-graph walks re-visit the same shared modules once per entry
|
|
21
|
+
// point, so repeat parses dominate runtime without this. Bounded FIFO so a
|
|
22
|
+
// long-lived process scanning many files doesn't grow without limit.
|
|
23
|
+
const PARSE_CACHE_MAX = 2000
|
|
24
|
+
const parseCache = new Map()
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Cached extraction. Returns a shared object — callers must treat it as
|
|
28
|
+
* read-only. Use `extractDeps` for a private copy.
|
|
29
|
+
* @param {string} code
|
|
30
|
+
*/
|
|
31
|
+
function extractDepsShared(code) {
|
|
32
|
+
let result = parseCache.get(code)
|
|
33
|
+
if (result === undefined) {
|
|
34
|
+
result = parseDeps(code)
|
|
35
|
+
if (parseCache.size >= PARSE_CACHE_MAX) {
|
|
36
|
+
parseCache.delete(parseCache.keys().next().value)
|
|
37
|
+
}
|
|
38
|
+
parseCache.set(code, result)
|
|
39
|
+
}
|
|
40
|
+
return result
|
|
41
|
+
}
|
|
42
|
+
|
|
19
43
|
function extractDeps(code, filePath = '') {
|
|
44
|
+
return structuredClone(extractDepsShared(code))
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function parseDeps(code) {
|
|
20
48
|
const imports = getImports(code)
|
|
21
49
|
//console.log('imports', imports)
|
|
22
50
|
const requires = getRequires(code)
|
|
@@ -94,6 +122,7 @@ const { execSync, spawnSync } = require('child_process')
|
|
|
94
122
|
|
|
95
123
|
module.exports = {
|
|
96
124
|
extractDeps,
|
|
125
|
+
extractDepsShared,
|
|
97
126
|
/* syntax detection */
|
|
98
127
|
hasESMSyntax,
|
|
99
128
|
hasCJSSyntax,
|
package/src/utils.js
CHANGED
|
@@ -1,22 +1,6 @@
|
|
|
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
|
-
// Single-quoted and double-quoted strings can't contain unescaped newlines
|
|
8
|
-
// (per JS spec — they'd need `\n` escapes or `\<NL>` line continuations). The
|
|
9
|
-
// `[^"\\\n]` / `[^'\\\n]` char classes enforce that, so an unbalanced quote
|
|
10
|
-
// followed by a newline doesn't sweep up the next several lines as "string".
|
|
11
|
-
// Template literals (`` `...` ``) DO span newlines, so their inner class only
|
|
12
|
-
// excludes backtick and backslash. Escape sequences (`\.`) are allowed in all
|
|
13
|
-
// three so escaped quotes don't prematurely end the match.
|
|
14
|
-
// Note: this treats `${...}` interpolations as part of the string body — code
|
|
15
|
-
// inside `${...}` (rare, but possible: `${import('./x.js')}`) gets blanked too.
|
|
16
|
-
// Acceptable for the change-detection use case; a full tokenizer would be
|
|
17
|
-
// needed to preserve interpolations.
|
|
18
|
-
const STRING_LITERAL_RE = /"(?:[^"\\\n]|\\[\s\S])*"|'(?:[^'\\\n]|\\[\s\S])*'|`(?:[^`\\]|\\[\s\S])*`/g
|
|
19
|
-
|
|
20
4
|
// Strings whose bodies contain these tokens are treated as embedded code
|
|
21
5
|
// samples (template strings, generator helpers, fenced docs) and get blanked.
|
|
22
6
|
// Plain module specifiers like `'lodash'` or `'./foo.js'` don't contain any
|
|
@@ -38,8 +22,9 @@ const EMBEDDED_CODE_RE = /\b(?:import|export|require|module\.exports)\b/
|
|
|
38
22
|
* Without this pass, regex-based extractors falsely match `import`, `export`,
|
|
39
23
|
* and `require` keywords that appear inside code samples embedded in strings.
|
|
40
24
|
*
|
|
41
|
-
* Run
|
|
42
|
-
*
|
|
25
|
+
* Run after `stripComments` in the import/require/export extractors. The
|
|
26
|
+
* comment scanner already skips strings and regex literals, so this pass can
|
|
27
|
+
* focus on embedded-code strings without risking `//` in URLs or regexes.
|
|
43
28
|
*
|
|
44
29
|
* Caveat: `${...}` interpolations inside template literals are treated as
|
|
45
30
|
* part of the body, so a runtime `${import('./x.js')}` inside a template
|
|
@@ -50,34 +35,240 @@ const EMBEDDED_CODE_RE = /\b(?:import|export|require|module\.exports)\b/
|
|
|
50
35
|
* @returns {string}
|
|
51
36
|
*/
|
|
52
37
|
function stripStringContents(code) {
|
|
53
|
-
|
|
38
|
+
let output = ''
|
|
39
|
+
let i = 0
|
|
40
|
+
|
|
41
|
+
while (i < code.length) {
|
|
42
|
+
const char = code[i]
|
|
43
|
+
|
|
44
|
+
if (char === '/' && isRegexLiteralStart(code, i)) {
|
|
45
|
+
const end = readRegexLiteral(code, i)
|
|
46
|
+
output += code.slice(i, end)
|
|
47
|
+
i = end
|
|
48
|
+
continue
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (char !== '"' && char !== "'" && char !== '`') {
|
|
52
|
+
output += char
|
|
53
|
+
i++
|
|
54
|
+
continue
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const end = readQuoted(code, i, char)
|
|
58
|
+
const match = code.slice(i, end)
|
|
59
|
+
if (match.length < 2 || match[match.length - 1] !== char) {
|
|
60
|
+
output += char
|
|
61
|
+
i++
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
64
|
+
|
|
54
65
|
const body = match.slice(1, -1)
|
|
55
66
|
if (!EMBEDDED_CODE_RE.test(body)) {
|
|
56
67
|
// Plain string — leave it alone so module specifiers stay extractable.
|
|
57
|
-
|
|
68
|
+
output += match
|
|
69
|
+
i = end
|
|
70
|
+
continue
|
|
58
71
|
}
|
|
59
72
|
const opener = match[0]
|
|
60
73
|
const closer = match[match.length - 1]
|
|
61
74
|
const middle = body.replace(/[^\n]/g, ' ')
|
|
62
|
-
|
|
63
|
-
|
|
75
|
+
output += opener + middle + closer
|
|
76
|
+
i = end
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return output
|
|
64
80
|
}
|
|
65
81
|
|
|
66
82
|
/**
|
|
67
|
-
*
|
|
83
|
+
* Blank comment bodies and code-bearing string/template bodies together.
|
|
84
|
+
* Solves two bugs that occurred when the string-strip and comment-strip ran
|
|
85
|
+
* as naive regex passes:
|
|
86
|
+
*
|
|
87
|
+
* - Apostrophes inside JSDoc comments (e.g. `* Netlify's \`...`) were
|
|
88
|
+
* mis-paired with later quotes, which shifted subsequent backtick
|
|
89
|
+
* pairing and could swallow real `export` declarations a few lines
|
|
90
|
+
* later in the same file.
|
|
91
|
+
* - `//` and `/* *\/` sequences inside string bodies were mis-stripped
|
|
92
|
+
* as comments.
|
|
93
|
+
* - `//` inside regex literals such as `/^https?:\/\//i` was mis-stripped
|
|
94
|
+
* as a line comment.
|
|
95
|
+
*
|
|
96
|
+
* Length is preserved (each consumed char replaced by a space or newline
|
|
97
|
+
* kept verbatim) so downstream character indices stay valid.
|
|
98
|
+
*
|
|
99
|
+
* Strings whose bodies don't reference `import` / `export` / `require` /
|
|
100
|
+
* `module.exports` pass through unchanged, so module specifiers like
|
|
101
|
+
* `'lodash'` or `'./foo.js'` stay readable by the downstream regexes.
|
|
102
|
+
*
|
|
103
|
+
* Caveat: `${...}` interpolations inside template literals are part of the
|
|
104
|
+
* body, so `${import('./x.js')}` inside a template gets blanked. Rare in
|
|
105
|
+
* practice; a full parser would be needed otherwise.
|
|
106
|
+
*
|
|
68
107
|
* @param {string} code
|
|
69
108
|
* @returns {string}
|
|
70
109
|
*/
|
|
71
|
-
function
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
110
|
+
function stripCommentsAndStrings(code) {
|
|
111
|
+
return stripStringContents(stripCommentsImpl(code, { preserveLength: true }))
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const REGEX_PREFIX_KEYWORDS = new Set([
|
|
115
|
+
'case',
|
|
116
|
+
'delete',
|
|
117
|
+
'do',
|
|
118
|
+
'else',
|
|
119
|
+
'in',
|
|
120
|
+
'instanceof',
|
|
121
|
+
'of',
|
|
122
|
+
'return',
|
|
123
|
+
'throw',
|
|
124
|
+
'typeof',
|
|
125
|
+
'void',
|
|
126
|
+
'yield',
|
|
127
|
+
'await',
|
|
128
|
+
])
|
|
129
|
+
|
|
130
|
+
function isRegexLiteralStart(code, slashIndex) {
|
|
131
|
+
let i = slashIndex - 1
|
|
132
|
+
while (i >= 0 && /\s/.test(code[i])) i--
|
|
133
|
+
if (i < 0) return true
|
|
134
|
+
|
|
135
|
+
const previousChar = code[i]
|
|
136
|
+
if ('([{=,:;!&|?+-*~^<>'.includes(previousChar)) return true
|
|
137
|
+
|
|
138
|
+
// Same result as `code.slice(0, i + 1).match(/([A-Za-z_$][\w$]*)$/)[1]`
|
|
139
|
+
// without copying and re-scanning the whole prefix on every `/` (quadratic
|
|
140
|
+
// on large files): the leftmost match starts at the first non-digit of the
|
|
141
|
+
// trailing run of [\w$] chars.
|
|
142
|
+
let start = i
|
|
143
|
+
while (start >= 0 && isIdentifierChar(code.charCodeAt(start))) start--
|
|
144
|
+
start++
|
|
145
|
+
while (start <= i && isDigit(code.charCodeAt(start))) start++
|
|
146
|
+
if (start > i) return false
|
|
147
|
+
return REGEX_PREFIX_KEYWORDS.has(code.slice(start, i + 1))
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function isDigit(charCode) {
|
|
151
|
+
return charCode >= 48 && charCode <= 57
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// [\w$] — ASCII letters, digits, underscore, dollar
|
|
155
|
+
function isIdentifierChar(charCode) {
|
|
156
|
+
return (
|
|
157
|
+
(charCode >= 97 && charCode <= 122) ||
|
|
158
|
+
(charCode >= 65 && charCode <= 90) ||
|
|
159
|
+
isDigit(charCode) ||
|
|
160
|
+
charCode === 95 ||
|
|
161
|
+
charCode === 36
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function readQuoted(code, start, quote) {
|
|
166
|
+
let i = start + 1
|
|
167
|
+
while (i < code.length) {
|
|
168
|
+
if (code[i] === '\\') {
|
|
169
|
+
i += 2
|
|
170
|
+
continue
|
|
171
|
+
}
|
|
172
|
+
if (code[i] === quote) return i + 1
|
|
173
|
+
if (quote !== '`' && (code[i] === '\n' || code[i] === '\r')) return i
|
|
174
|
+
i++
|
|
75
175
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
176
|
+
return i
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function readRegexLiteral(code, start) {
|
|
180
|
+
let i = start + 1
|
|
181
|
+
let inCharacterClass = false
|
|
182
|
+
|
|
183
|
+
while (i < code.length) {
|
|
184
|
+
const char = code[i]
|
|
185
|
+
if (char === '\\') {
|
|
186
|
+
i += 2
|
|
187
|
+
continue
|
|
188
|
+
}
|
|
189
|
+
if (char === '[') {
|
|
190
|
+
inCharacterClass = true
|
|
191
|
+
i++
|
|
192
|
+
continue
|
|
193
|
+
}
|
|
194
|
+
if (char === ']') {
|
|
195
|
+
inCharacterClass = false
|
|
196
|
+
i++
|
|
197
|
+
continue
|
|
198
|
+
}
|
|
199
|
+
if (char === '/' && !inCharacterClass) {
|
|
200
|
+
i++
|
|
201
|
+
while (i < code.length && /[a-z]/i.test(code[i])) i++
|
|
202
|
+
return i
|
|
203
|
+
}
|
|
204
|
+
if (char === '\n' || char === '\r') return i
|
|
205
|
+
i++
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return i
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function appendSkippedComment(output, commentText, preserveLength) {
|
|
212
|
+
if (!preserveLength) {
|
|
213
|
+
return output + commentText.replace(/[^\n\r]/g, '')
|
|
214
|
+
}
|
|
215
|
+
return output + commentText.replace(/[^\n\r]/g, ' ')
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function stripCommentsImpl(code, { preserveLength = false } = {}) {
|
|
219
|
+
let output = ''
|
|
220
|
+
let i = 0
|
|
221
|
+
|
|
222
|
+
while (i < code.length) {
|
|
223
|
+
const char = code[i]
|
|
224
|
+
const next = code[i + 1]
|
|
225
|
+
|
|
226
|
+
if (char === '"' || char === "'" || char === '`') {
|
|
227
|
+
const end = readQuoted(code, i, char)
|
|
228
|
+
output += code.slice(i, end)
|
|
229
|
+
i = end
|
|
230
|
+
continue
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (char === '/' && next === '/') {
|
|
234
|
+
let end = i + 2
|
|
235
|
+
while (end < code.length && code[end] !== '\n' && code[end] !== '\r') end++
|
|
236
|
+
output = appendSkippedComment(output, code.slice(i, end), preserveLength)
|
|
237
|
+
i = end
|
|
238
|
+
continue
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (char === '/' && next === '*') {
|
|
242
|
+
let end = code.indexOf('*/', i + 2)
|
|
243
|
+
end = end === -1 ? code.length : end + 2
|
|
244
|
+
output = appendSkippedComment(output, code.slice(i, end), preserveLength)
|
|
245
|
+
i = end
|
|
246
|
+
continue
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (char === '/' && isRegexLiteralStart(code, i)) {
|
|
250
|
+
const end = readRegexLiteral(code, i)
|
|
251
|
+
output += code.slice(i, end)
|
|
252
|
+
i = end
|
|
253
|
+
continue
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
output += char
|
|
257
|
+
i++
|
|
79
258
|
}
|
|
80
|
-
|
|
259
|
+
|
|
260
|
+
return output
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Strip comments from code while skipping strings, templates, and regex
|
|
265
|
+
* literals. Regex literals can legally contain `//`, for example `/https?:\/\//`,
|
|
266
|
+
* and must not be treated as line comments.
|
|
267
|
+
* @param {string} code
|
|
268
|
+
* @returns {string}
|
|
269
|
+
*/
|
|
270
|
+
function stripComments(code) {
|
|
271
|
+
return stripCommentsImpl(code)
|
|
81
272
|
}
|
|
82
273
|
|
|
83
274
|
/**
|
|
@@ -292,9 +483,10 @@ function extractExportName(exportValue) {
|
|
|
292
483
|
module.exports = {
|
|
293
484
|
stripComments,
|
|
294
485
|
stripStringContents,
|
|
486
|
+
stripCommentsAndStrings,
|
|
295
487
|
isBuiltIn,
|
|
296
488
|
isRelativeImport,
|
|
297
489
|
isRelativeImportWithQuotes,
|
|
298
490
|
getNames,
|
|
299
491
|
extractExportName
|
|
300
|
-
}
|
|
492
|
+
}
|
package/tests/dep-graph.test.js
CHANGED
|
@@ -654,6 +654,7 @@ test('dynamic import should still build the dep edge', () => {
|
|
|
654
654
|
|
|
655
655
|
// TypeScript patterns fixture — exercises all fixed false positive patterns
|
|
656
656
|
const TS_PATTERNS_FIXTURE = path.resolve(__dirname, './fixtures/ts-patterns-fixture/index.ts')
|
|
657
|
+
const TS_REGEX_EXPORT_FIXTURE = path.resolve(__dirname, './fixtures/ts-regex-export-fixture/index.ts')
|
|
657
658
|
|
|
658
659
|
test('TS patterns: import type, inline type, import * as, $-prefixed names should all pass', () => {
|
|
659
660
|
// This fixture contains:
|
|
@@ -700,4 +701,30 @@ test('TS patterns: resolveDepPaths with returnErrors should have zero errors', (
|
|
|
700
701
|
assert.is(result.errors.length, 0, 'Should have zero verification errors')
|
|
701
702
|
})
|
|
702
703
|
|
|
704
|
+
test('TS regex exports: verifies named imports from .js specifier resolved to .ts file', () => {
|
|
705
|
+
assert.not.throws(() => {
|
|
706
|
+
depGraph(TS_REGEX_EXPORT_FIXTURE, { verifyGraph: true })
|
|
707
|
+
}, 'Regex literals in the target module should not hide later exports')
|
|
708
|
+
})
|
|
709
|
+
|
|
710
|
+
test('TS regex exports: should build dependency edge to resolved .ts module', () => {
|
|
711
|
+
const graph = depGraph(TS_REGEX_EXPORT_FIXTURE, { verifyGraph: true })
|
|
712
|
+
|
|
713
|
+
const indexPath = Array.from(graph.keys()).find(key => key.includes('ts-regex-export-fixture/index.ts'))
|
|
714
|
+
assert.ok(indexPath, 'Should have index.ts in graph')
|
|
715
|
+
|
|
716
|
+
const deps = graph.get(indexPath)
|
|
717
|
+
assert.ok(deps.some(d => d.includes('ts-regex-export-fixture/message-builder.ts')), 'Should depend on message-builder.ts')
|
|
718
|
+
})
|
|
719
|
+
|
|
720
|
+
test('TS regex exports: resolveDepPaths with returnErrors should have zero errors', () => {
|
|
721
|
+
const result = resolveDepPaths(TS_REGEX_EXPORT_FIXTURE, { returnErrors: true })
|
|
722
|
+
|
|
723
|
+
assert.ok(Array.isArray(result.errors), 'Should have errors array')
|
|
724
|
+
if (result.errors.length > 0) {
|
|
725
|
+
console.log('Unexpected errors:', result.errors.map(e => e.message))
|
|
726
|
+
}
|
|
727
|
+
assert.is(result.errors.length, 0, 'Should have zero verification errors')
|
|
728
|
+
})
|
|
729
|
+
|
|
703
730
|
test.run()
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export enum DeliveryStatus {
|
|
2
|
+
Ready = 'ready',
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function escapeHtmlAttribute(value: string): string {
|
|
6
|
+
return value.replace(/`/g, '`')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function sanitizeEmailHtml(html: string): string {
|
|
10
|
+
return html.replace(/<!--[\s\S]*?-->/g, '').replace(/<(script|style)\b[\s\S]*?<\/\1>/gi, '').replace(
|
|
11
|
+
/<\/?([a-z][a-z0-9]*)\b([^>]*)>/gi,
|
|
12
|
+
(tag, rawName: string, rawAttributes: string) => {
|
|
13
|
+
const hrefMatch = rawAttributes.match(/\shref\s*=\s*("([^"]*)"|'([^']*)'|([^\s>]+))/i)
|
|
14
|
+
const href = hrefMatch?.[2] ?? hrefMatch?.[3] ?? hrefMatch?.[4] ?? ''
|
|
15
|
+
if (!/^https?:\/\//i.test(href)) return '<a>'
|
|
16
|
+
return `<a href="${escapeHtmlAttribute(href)}">`
|
|
17
|
+
},
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function buildRawMessage({ htmlBody, status }: { htmlBody: string; status: DeliveryStatus }): string {
|
|
22
|
+
return `${status}:${htmlBody}`
|
|
23
|
+
}
|
|
@@ -78,11 +78,13 @@ export var thirdVariable = 'value'
|
|
|
78
78
|
export function myFunction() {}
|
|
79
79
|
export class MyClass {}
|
|
80
80
|
export async function asyncFunction() {}
|
|
81
|
+
export enum MyEnum {}
|
|
82
|
+
export const enum MyConstEnum {}
|
|
81
83
|
`
|
|
82
84
|
|
|
83
85
|
const foundExports = getNamedExports(code)
|
|
84
86
|
|
|
85
|
-
assert.ok(foundExports.length ===
|
|
87
|
+
assert.ok(foundExports.length === 8, 'Should find 8 named exports')
|
|
86
88
|
|
|
87
89
|
const exportNames = foundExports.map(exp => exp.exportName)
|
|
88
90
|
assert.ok(exportNames.includes('myVariable'), 'Should find const export')
|
|
@@ -91,6 +93,8 @@ export async function asyncFunction() {}
|
|
|
91
93
|
assert.ok(exportNames.includes('myFunction'), 'Should find function export')
|
|
92
94
|
assert.ok(exportNames.includes('MyClass'), 'Should find class export')
|
|
93
95
|
assert.ok(exportNames.includes('asyncFunction'), 'Should find async function export')
|
|
96
|
+
assert.ok(exportNames.includes('MyEnum'), 'Should find enum export')
|
|
97
|
+
assert.ok(exportNames.includes('MyConstEnum'), 'Should find const enum export')
|
|
94
98
|
|
|
95
99
|
foundExports.forEach(exp => {
|
|
96
100
|
assert.equal(exp.exportType, 'named')
|
|
@@ -563,6 +567,41 @@ export const real = 'value' // this comment should be stripped
|
|
|
563
567
|
assert.equal(foundExports[2].exportName, 'real', 'Should find real export')
|
|
564
568
|
})
|
|
565
569
|
|
|
570
|
+
test('apostrophe inside JSDoc with surrounding backticks does not swallow later exports', () => {
|
|
571
|
+
// Regression: when `stripStringContents` ran BEFORE `stripComments`, an
|
|
572
|
+
// apostrophe inside a JSDoc block (e.g. `Netlify's \`promptType: 'foo'\``)
|
|
573
|
+
// was treated as the opener of a single-quoted string and consumed text up
|
|
574
|
+
// to the next `'`, shifting every subsequent backtick pair by one. The
|
|
575
|
+
// newly mis-paired template literal then spanned multiple lines, including
|
|
576
|
+
// the real `export async function` declaration that followed the JSDoc,
|
|
577
|
+
// and the embedded-code heuristic blanked it. The fix runs `stripComments`
|
|
578
|
+
// first so JSDoc-internal punctuation is gone before string matching.
|
|
579
|
+
//
|
|
580
|
+
// This fixture replicates the structural shape of the AWS SDK adapter file
|
|
581
|
+
// that originally surfaced the bug: a JSDoc block containing both an
|
|
582
|
+
// apostrophe and multiple backticks, followed by an `export async function`,
|
|
583
|
+
// followed by ANOTHER JSDoc with backticks.
|
|
584
|
+
const code = `
|
|
585
|
+
/**
|
|
586
|
+
* Stuff with \`code-one\`. Netlify's \`promptType: 'foo'\`. End \`Error\` on
|
|
587
|
+
* non-2xx upstream responses or malformed bodies.
|
|
588
|
+
*/
|
|
589
|
+
export async function generateThing(request) {
|
|
590
|
+
return request
|
|
591
|
+
}
|
|
592
|
+
/** Test seam: override the global \`fetch\` for unit tests. */
|
|
593
|
+
export const helper = 1
|
|
594
|
+
`
|
|
595
|
+
|
|
596
|
+
const found = getExports(code)
|
|
597
|
+
const names = found.map(e => e.exportName).sort()
|
|
598
|
+
assert.equal(
|
|
599
|
+
names,
|
|
600
|
+
['generateThing', 'helper'],
|
|
601
|
+
'Both exports must survive past the JSDoc apostrophe+backtick combo'
|
|
602
|
+
)
|
|
603
|
+
})
|
|
604
|
+
|
|
566
605
|
test('ignores ESM exports embedded in template literals and strings', () => {
|
|
567
606
|
const code = `
|
|
568
607
|
export const real = 'real'
|
|
@@ -580,4 +619,25 @@ const dq = "export { foo } from 'fake'"
|
|
|
580
619
|
assert.equal(names, ['real'], 'Only the real export should be detected')
|
|
581
620
|
})
|
|
582
621
|
|
|
583
|
-
test
|
|
622
|
+
test('finds exports after regex literals that contain //', () => {
|
|
623
|
+
const code = `
|
|
624
|
+
export function sanitizeEmailHtml(html: string): string {
|
|
625
|
+
return html.replace(/<!--[\\s\\S]*?-->/g, '')
|
|
626
|
+
.replace(/<(script|style)\\b[\\s\\S]*?<\\/\\1>/gi, '')
|
|
627
|
+
.replace(/<\\/?([a-z][a-z0-9]*)\\b([^>]*)>/gi, (tag, rawName: string) => {
|
|
628
|
+
if (!/^https?:\\/\\//i.test(tag)) return '<a>'
|
|
629
|
+
return '<a>'
|
|
630
|
+
})
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
export function buildRawMessage(input: { htmlBody: string }): string {
|
|
634
|
+
return input.htmlBody
|
|
635
|
+
}
|
|
636
|
+
`
|
|
637
|
+
|
|
638
|
+
const found = getExports(code)
|
|
639
|
+
const names = found.map(e => e.exportName).sort()
|
|
640
|
+
assert.equal(names, ['buildRawMessage', 'sanitizeEmailHtml'])
|
|
641
|
+
})
|
|
642
|
+
|
|
643
|
+
test.run()
|
package/tests/index.test.js
CHANGED
|
@@ -199,4 +199,15 @@ test('should handle packages with no dependencies gracefully', async () => {
|
|
|
199
199
|
}
|
|
200
200
|
})
|
|
201
201
|
|
|
202
|
+
test('extractDeps - repeat calls on same code return equal, independent results', () => {
|
|
203
|
+
const code = `const path = require('path')\nimport foo from './foo'\nexport const bar = 1\n`
|
|
204
|
+
const first = extractDeps(code)
|
|
205
|
+
first.requires[0].from = 'mutated'
|
|
206
|
+
first.imports.length = 0
|
|
207
|
+
const second = extractDeps(code)
|
|
208
|
+
assert.is(second.requires[0].from, 'path')
|
|
209
|
+
assert.is(second.imports.length, 1)
|
|
210
|
+
assert.equal(extractDeps(code), second)
|
|
211
|
+
})
|
|
212
|
+
|
|
202
213
|
test.run()
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
const { test } = require('uvu')
|
|
2
|
+
const assert = require('uvu/assert')
|
|
3
|
+
const { detectSyntax, extractDeps } = require('../src')
|
|
4
|
+
|
|
5
|
+
function exportNames(code) {
|
|
6
|
+
return extractDeps(code).exports.map(exp => exp.exportName).filter(Boolean).sort()
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function cjsExportNames(code) {
|
|
10
|
+
return extractDeps(code).moduleExports.map(exp => exp.exportName).filter(Boolean).sort()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
test('regex literals with // do not hide later ESM exports', () => {
|
|
14
|
+
const code = `
|
|
15
|
+
const protocol = /^https?:\\/\\//i
|
|
16
|
+
const slashy = /\\/\\*not-a-comment\\*\\//
|
|
17
|
+
export function sanitizeEmailHtml(html: string): string {
|
|
18
|
+
return html
|
|
19
|
+
}
|
|
20
|
+
export function buildRawMessage(): string {
|
|
21
|
+
return ''
|
|
22
|
+
}
|
|
23
|
+
`
|
|
24
|
+
|
|
25
|
+
assert.equal(exportNames(code), ['buildRawMessage', 'sanitizeEmailHtml'])
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('regex literals with // do not hide later imports, requires, or CJS exports', () => {
|
|
29
|
+
const code = `
|
|
30
|
+
const protocol = /^https?:\\/\\//i
|
|
31
|
+
const commentText = /\\/\\/ not really a comment/
|
|
32
|
+
import real from './real.js'
|
|
33
|
+
const actual = require('./actual.js')
|
|
34
|
+
module.exports.afterRegex = { real, actual }
|
|
35
|
+
`
|
|
36
|
+
|
|
37
|
+
const deps = extractDeps(code)
|
|
38
|
+
assert.equal(deps.imports.map(dep => dep.from), ['./real.js'])
|
|
39
|
+
assert.equal(deps.requires.map(dep => dep.from), ['./actual.js'])
|
|
40
|
+
assert.equal(cjsExportNames(code), ['afterRegex'])
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('regex literals with backticks do not start fake template literals', () => {
|
|
44
|
+
const code = `
|
|
45
|
+
function escapeHtmlAttribute(value: string): string {
|
|
46
|
+
return value.replace(/\\\`/g, '`')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const afterBacktickRegex = true
|
|
50
|
+
`
|
|
51
|
+
|
|
52
|
+
assert.equal(exportNames(code), ['afterBacktickRegex'])
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('regex literals containing parser keywords are not imports/requires/exports', () => {
|
|
56
|
+
const code = `
|
|
57
|
+
const importPattern = /import\\s+fake\\s+from/
|
|
58
|
+
const exportPattern = /export\\s+const\\s+fake/
|
|
59
|
+
const requirePattern = /require\\(['"]fake['"]\\)/
|
|
60
|
+
const cjsPattern = /module\\.exports\\.fake/
|
|
61
|
+
|
|
62
|
+
import real from './real.js'
|
|
63
|
+
const actual = require('./actual.js')
|
|
64
|
+
export const realExport = true
|
|
65
|
+
module.exports.cjsExport = actual
|
|
66
|
+
`
|
|
67
|
+
|
|
68
|
+
const deps = extractDeps(code)
|
|
69
|
+
assert.equal(deps.imports.map(dep => dep.from), ['./real.js'])
|
|
70
|
+
assert.equal(deps.requires.map(dep => dep.from), ['./actual.js'])
|
|
71
|
+
assert.equal(exportNames(code), ['realExport'])
|
|
72
|
+
assert.equal(cjsExportNames(code), ['cjsExport'])
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
test('detectSyntax ignores parser keywords inside regex literals', () => {
|
|
76
|
+
const result = detectSyntax(`
|
|
77
|
+
const importPattern = /import\\s+fake\\s+from/
|
|
78
|
+
const exportPattern = /export\\s+const\\s+fake/
|
|
79
|
+
const requirePattern = /require\\(['"]fake['"]\\)/
|
|
80
|
+
const cjsPattern = /module\\.exports\\.fake/
|
|
81
|
+
`)
|
|
82
|
+
|
|
83
|
+
assert.equal(result, { hasESM: false, hasCJS: false, isMixed: false })
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test('TypeScript enum exports are named exports', () => {
|
|
87
|
+
const code = `
|
|
88
|
+
export enum DeliveryStatus {
|
|
89
|
+
Pending = 'pending',
|
|
90
|
+
Sent = 'sent',
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const enum InlineStatus {
|
|
94
|
+
Ready = 'ready',
|
|
95
|
+
}
|
|
96
|
+
`
|
|
97
|
+
|
|
98
|
+
assert.equal(exportNames(code), ['DeliveryStatus', 'InlineStatus'])
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
test.run()
|
package/tests/utils.test.js
CHANGED
|
@@ -142,4 +142,12 @@ test('stripStringContents — neutralizes // inside code-bearing strings so stri
|
|
|
142
142
|
assert.ok(after.includes('"\nconst y = 1'), 'closing quote and following code survive')
|
|
143
143
|
})
|
|
144
144
|
|
|
145
|
+
test('stripComments — preserves regex literals that contain //', () => {
|
|
146
|
+
const input = `if (!/^https?:\\/\\//i.test(href)) return '<a>'\nexport function afterRegex() {}`
|
|
147
|
+
const output = stripComments(input)
|
|
148
|
+
|
|
149
|
+
assert.ok(output.includes('/^https?:\\/\\//i.test(href)'), 'regex literal survives')
|
|
150
|
+
assert.ok(output.includes('export function afterRegex() {}'), 'following export survives')
|
|
151
|
+
})
|
|
152
|
+
|
|
145
153
|
test.run()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build dependency graph for a file and its dependencies
|
|
3
|
+
* @param {string} filePath - File to analyze
|
|
4
|
+
* @param {object} options - Options
|
|
5
|
+
* @param {boolean} [options.buildGraph] - If true, build and return dependency graph. Default: true
|
|
6
|
+
* @param {boolean} [options.verifyGraph] - If true, verify imports/exports. Default: true
|
|
7
|
+
* @param {boolean} [options.verifyNodeModules] - If true, verify node_modules packages can be resolved. Default: false
|
|
8
|
+
* @param {boolean} [options.includeNodeModules] - If true, include node_modules package names in the graph. Default: false
|
|
9
|
+
* @param {boolean} [options.throwOnFirstError] - If true, throw immediately on first error. Default: 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.
|
|
12
|
+
*/
|
|
13
|
+
export function depGraph(filePath: string, options?: {
|
|
14
|
+
buildGraph?: boolean;
|
|
15
|
+
verifyGraph?: boolean;
|
|
16
|
+
verifyNodeModules?: boolean;
|
|
17
|
+
includeNodeModules?: boolean;
|
|
18
|
+
throwOnFirstError?: boolean;
|
|
19
|
+
returnErrors?: boolean;
|
|
20
|
+
}): Map<string, string[]> | {
|
|
21
|
+
graph: Map<any, any>;
|
|
22
|
+
errors: Error[];
|
|
23
|
+
} | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Get all dependency file paths in build order (dependencies first), deduplicated
|
|
26
|
+
* @param {string} filePath - Entry file path
|
|
27
|
+
* @param {object} options - Options to pass to depGraph
|
|
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[], builtIns: string[], errors?: Error[] }} - Object with files in topological order, npm packages, and Node.js built-ins
|
|
33
|
+
*/
|
|
34
|
+
export function resolveDepPaths(filePath: string, options?: {
|
|
35
|
+
verifyGraph?: boolean;
|
|
36
|
+
verifyNodeModules?: boolean;
|
|
37
|
+
throwOnFirstError?: boolean;
|
|
38
|
+
returnErrors?: boolean;
|
|
39
|
+
}): {
|
|
40
|
+
files: string[];
|
|
41
|
+
nodeModules: string[];
|
|
42
|
+
builtIns: string[];
|
|
43
|
+
errors?: Error[];
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=dep-graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dep-graph.d.ts","sourceRoot":"","sources":["../src/dep-graph.js"],"names":[],"mappings":"AAmUA;;;;;;;;;;;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,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAA;CAAE,CAkF5F"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for detecting syntax within a code string.
|
|
3
|
+
*/
|
|
4
|
+
export type DetectSyntaxOptions = {
|
|
5
|
+
/**
|
|
6
|
+
* - Indicates whether comments should be stripped from the code before syntax checking.
|
|
7
|
+
*/
|
|
8
|
+
stripComments?: boolean;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Options for detecting syntax within a code string.
|
|
12
|
+
* @typedef {Object} DetectSyntaxOptions
|
|
13
|
+
* @property {boolean} [stripComments=false] - Indicates whether comments should be stripped from the code before syntax checking.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Determines if a given code string contains ECMAScript module syntax.
|
|
17
|
+
*
|
|
18
|
+
* @param {string} code - The source code to analyze.
|
|
19
|
+
* @param {DetectSyntaxOptions} opts - See {@link DetectSyntaxOptions}.
|
|
20
|
+
* @returns {boolean} `true` if the code contains ESM syntax, otherwise `false`.
|
|
21
|
+
*/
|
|
22
|
+
export function hasESMSyntax(code: string, opts?: DetectSyntaxOptions): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Determines if a given string of code contains CommonJS syntax.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} code - The source code to analyze.
|
|
27
|
+
* @param {DetectSyntaxOptions} opts - See {@link DetectSyntaxOptions}.
|
|
28
|
+
* @returns {boolean} `true` if the code contains CommonJS syntax, `false` otherwise.
|
|
29
|
+
*/
|
|
30
|
+
export function hasCJSSyntax(code: string, opts?: DetectSyntaxOptions): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Analyzes the supplied code to determine if it contains ECMAScript module syntax, CommonJS syntax, or both.
|
|
33
|
+
*
|
|
34
|
+
* @param {string} code - The source code to analyze.
|
|
35
|
+
* @param {DetectSyntaxOptions} opts - See {@link DetectSyntaxOptions}.
|
|
36
|
+
* @returns {Object} An object indicating the presence of ESM syntax (`hasESM`), CJS syntax (`hasCJS`) and whether both syntaxes are present (`isMixed`).
|
|
37
|
+
*/
|
|
38
|
+
export function detectSyntax(code: string, opts?: DetectSyntaxOptions): any;
|
|
39
|
+
//# sourceMappingURL=detect-syntax.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-syntax.d.ts","sourceRoot":"","sources":["../src/detect-syntax.js"],"names":[],"mappings":";;;;;;;oBAcc,OAAO;;AAHrB;;;;GAIG;AAEH;;;;;;GAMG;AACH,mCAJW,MAAM,SACN,mBAAmB,GACjB,OAAO,CAMnB;AAED;;;;;;GAMG;AACH,mCAJW,MAAM,SACN,mBAAmB,GACjB,OAAO,CAMnB;AAED;;;;;;GAMG;AACH,mCAJW,MAAM,SACN,mBAAmB,OAe7B"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export function getCjsExports(code: any): any[];
|
|
2
|
+
export function getModuleExportsAssignment(originalText?: string, sanitizedText?: string): {
|
|
3
|
+
line: string;
|
|
4
|
+
exportType: string;
|
|
5
|
+
exportName: string;
|
|
6
|
+
exportDefinitionName: any;
|
|
7
|
+
exportValue: string;
|
|
8
|
+
index: number;
|
|
9
|
+
isExport: boolean;
|
|
10
|
+
}[];
|
|
11
|
+
export function getModuleExportsProperty(originalText?: string, sanitizedText?: string): {
|
|
12
|
+
line: string;
|
|
13
|
+
exportType: string;
|
|
14
|
+
exportName: string;
|
|
15
|
+
exportValue: string;
|
|
16
|
+
index: number;
|
|
17
|
+
isExport: boolean;
|
|
18
|
+
}[];
|
|
19
|
+
export function getExportsProperty(originalText?: string, sanitizedText?: string): {
|
|
20
|
+
line: string;
|
|
21
|
+
exportType: string;
|
|
22
|
+
exportName: string;
|
|
23
|
+
exportValue: string;
|
|
24
|
+
index: number;
|
|
25
|
+
isExport: boolean;
|
|
26
|
+
}[];
|
|
27
|
+
export function getObjectAssignExports(originalText?: string, sanitizedText?: string): {
|
|
28
|
+
line: string;
|
|
29
|
+
exportType: string;
|
|
30
|
+
exportName: string;
|
|
31
|
+
exportValue: string;
|
|
32
|
+
index: number;
|
|
33
|
+
isExport: boolean;
|
|
34
|
+
}[];
|
|
35
|
+
export function getDefinePropertyExports(originalText?: string, sanitizedText?: string): {
|
|
36
|
+
line: string;
|
|
37
|
+
exportType: string;
|
|
38
|
+
exportName: string;
|
|
39
|
+
exportValue: string;
|
|
40
|
+
exportDefinitionName: string;
|
|
41
|
+
index: number;
|
|
42
|
+
isExport: boolean;
|
|
43
|
+
isDefineProperty: boolean;
|
|
44
|
+
}[];
|
|
45
|
+
//# sourceMappingURL=get-cjs-exports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-cjs-exports.d.ts","sourceRoot":"","sources":["../src/get-cjs-exports.js"],"names":[],"mappings":"AAoCA,gDAgDC;AA+BD;;;;;;;;IAqGC;AAED;;;;;;;IAqBC;AAED;;;;;;;IAqBC;AAED;;;;;;;IAiDC;AAED;;;;;;;;;IAwEC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export function getExports(code?: string, options?: {}): any[];
|
|
2
|
+
export function getDefaultExports(targetText?: string): {
|
|
3
|
+
line: string;
|
|
4
|
+
exportType: string;
|
|
5
|
+
exportName: string;
|
|
6
|
+
exportDefinitionName: any;
|
|
7
|
+
exportValue: string;
|
|
8
|
+
index: number;
|
|
9
|
+
isExport: boolean;
|
|
10
|
+
}[];
|
|
11
|
+
export function getNamedExports(targetText?: string): {
|
|
12
|
+
line: string;
|
|
13
|
+
exportType: string;
|
|
14
|
+
exportName: string;
|
|
15
|
+
index: number;
|
|
16
|
+
isExport: boolean;
|
|
17
|
+
}[];
|
|
18
|
+
export function getNamedDeclarationExports(targetText?: string): any[];
|
|
19
|
+
export function getAllExports(targetText?: string): {
|
|
20
|
+
line: string;
|
|
21
|
+
exportType: string;
|
|
22
|
+
from: string;
|
|
23
|
+
index: number;
|
|
24
|
+
isExport: boolean;
|
|
25
|
+
}[];
|
|
26
|
+
export function getNamespaceExports(targetText?: string): {
|
|
27
|
+
line: string;
|
|
28
|
+
exportType: string;
|
|
29
|
+
namespace: string;
|
|
30
|
+
from: string;
|
|
31
|
+
index: number;
|
|
32
|
+
isExport: boolean;
|
|
33
|
+
}[];
|
|
34
|
+
export function getTypeExports(targetText?: string): {
|
|
35
|
+
line: string;
|
|
36
|
+
exportType: string;
|
|
37
|
+
exportName: string;
|
|
38
|
+
index: number;
|
|
39
|
+
isExport: boolean;
|
|
40
|
+
}[];
|
|
41
|
+
export function getAssertionExports(targetText?: string): {
|
|
42
|
+
line: string;
|
|
43
|
+
exportType: string;
|
|
44
|
+
exportName: string;
|
|
45
|
+
definitions: any;
|
|
46
|
+
keys: any;
|
|
47
|
+
from: string;
|
|
48
|
+
assertion: string;
|
|
49
|
+
assertionType: string;
|
|
50
|
+
index: number;
|
|
51
|
+
isExport: boolean;
|
|
52
|
+
isAssertion: boolean;
|
|
53
|
+
}[];
|
|
54
|
+
//# sourceMappingURL=get-exports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-exports.d.ts","sourceRoot":"","sources":["../src/get-exports.js"],"names":[],"mappings":"AAiBA,+DAqCC;AAED;;;;;;;;IAqDC;AAED;;;;;;IAeC;AAED,uEAuBC;AAED;;;;;;IAeC;AAED;;;;;;;IAgBC;AAED;;;;;;IAeC;AAED;;;;;;;;;;;;IA0BC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export function getImports(code?: string, options?: {}): {
|
|
2
|
+
line: string;
|
|
3
|
+
varType: string;
|
|
4
|
+
varName: string;
|
|
5
|
+
definitions: any;
|
|
6
|
+
from: string;
|
|
7
|
+
index: number;
|
|
8
|
+
isImport: boolean;
|
|
9
|
+
isRelative: boolean;
|
|
10
|
+
isBuiltIn: boolean;
|
|
11
|
+
}[];
|
|
12
|
+
export function getStaticImports(targetText?: string): {
|
|
13
|
+
line: string;
|
|
14
|
+
varType: string;
|
|
15
|
+
varName: string;
|
|
16
|
+
definitions: any;
|
|
17
|
+
from: string;
|
|
18
|
+
index: number;
|
|
19
|
+
isImport: boolean;
|
|
20
|
+
isRelative: boolean;
|
|
21
|
+
isBuiltIn: boolean;
|
|
22
|
+
}[];
|
|
23
|
+
export function getTypeImports(targetText?: string): {
|
|
24
|
+
importStatement: string;
|
|
25
|
+
importPath: string;
|
|
26
|
+
importName: string;
|
|
27
|
+
index: number;
|
|
28
|
+
isImport: boolean;
|
|
29
|
+
isTypeImport: boolean;
|
|
30
|
+
isRelative: boolean;
|
|
31
|
+
isBuiltIn: boolean;
|
|
32
|
+
}[];
|
|
33
|
+
export function getDynamicImports(targetText?: string): {
|
|
34
|
+
line: string;
|
|
35
|
+
varType: string;
|
|
36
|
+
varName: string;
|
|
37
|
+
definitions: any;
|
|
38
|
+
from: string;
|
|
39
|
+
index: number;
|
|
40
|
+
isImport: boolean;
|
|
41
|
+
isRelative: boolean;
|
|
42
|
+
isBuiltIn: boolean;
|
|
43
|
+
isDynamic: boolean;
|
|
44
|
+
}[];
|
|
45
|
+
export function getAssertionImports(targetText?: string): {
|
|
46
|
+
line: string;
|
|
47
|
+
varType: string;
|
|
48
|
+
varName: string;
|
|
49
|
+
definitions: any;
|
|
50
|
+
from: string;
|
|
51
|
+
assertion: string;
|
|
52
|
+
assertionType: string;
|
|
53
|
+
index: number;
|
|
54
|
+
isImport: boolean;
|
|
55
|
+
isRelative: boolean;
|
|
56
|
+
isBuiltIn: boolean;
|
|
57
|
+
isAssertion: boolean;
|
|
58
|
+
}[];
|
|
59
|
+
//# sourceMappingURL=get-imports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-imports.d.ts","sourceRoot":"","sources":["../src/get-imports.js"],"names":[],"mappings":"AAsCA;;;;;;;;;;IAcC;AAGD;;;;;;;;;;IAsCC;AAED;;;;;;;;;IAkBC;AAED;;;;;;;;;;;IAuBC;AAED;;;;;;;;;;;;;IA0BC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export function getRequires(code: any): {
|
|
2
|
+
line: string;
|
|
3
|
+
varType: string;
|
|
4
|
+
varName: string;
|
|
5
|
+
definitions: any;
|
|
6
|
+
from: string;
|
|
7
|
+
index: number;
|
|
8
|
+
isRequire: boolean;
|
|
9
|
+
isRelative: boolean;
|
|
10
|
+
isBuiltIn: boolean;
|
|
11
|
+
isDynamic: boolean;
|
|
12
|
+
}[];
|
|
13
|
+
export function getStaticRequires(targetText?: string): {
|
|
14
|
+
line: string;
|
|
15
|
+
varType: string;
|
|
16
|
+
varName: string;
|
|
17
|
+
definitions: any;
|
|
18
|
+
from: string;
|
|
19
|
+
index: number;
|
|
20
|
+
isRequire: boolean;
|
|
21
|
+
isRelative: boolean;
|
|
22
|
+
isBuiltIn: boolean;
|
|
23
|
+
isDynamic: boolean;
|
|
24
|
+
}[];
|
|
25
|
+
export function getDynamicRequires(code: any): {
|
|
26
|
+
line: string;
|
|
27
|
+
varType: string;
|
|
28
|
+
varName: string;
|
|
29
|
+
definitions: any;
|
|
30
|
+
from: string;
|
|
31
|
+
index: number;
|
|
32
|
+
isRequire: boolean;
|
|
33
|
+
isRelative: boolean;
|
|
34
|
+
isBuiltIn: boolean;
|
|
35
|
+
isDynamic: boolean;
|
|
36
|
+
}[];
|
|
37
|
+
//# sourceMappingURL=get-requires.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-requires.d.ts","sourceRoot":"","sources":["../src/get-requires.js"],"names":[],"mappings":"AA0GA;;;;;;;;;;;IAUC;AArCD;;;;;;;;;;;IAyBC;AA/FD;;;;;;;;;;;IA6BC"}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function extractDeps(code: any, filePath?: string): any;
|
|
2
|
+
/**
|
|
3
|
+
* Cached extraction. Returns a shared object — callers must treat it as
|
|
4
|
+
* read-only. Use `extractDeps` for a private copy.
|
|
5
|
+
* @param {string} code
|
|
6
|
+
*/
|
|
7
|
+
export function extractDepsShared(code: string): any;
|
|
8
|
+
import { hasESMSyntax } from "./detect-syntax";
|
|
9
|
+
import { hasCJSSyntax } from "./detect-syntax";
|
|
10
|
+
import { detectSyntax } from "./detect-syntax";
|
|
11
|
+
import { getRequires } from "./get-requires";
|
|
12
|
+
import { getDynamicRequires } from "./get-requires";
|
|
13
|
+
import { getStaticRequires } from "./get-requires";
|
|
14
|
+
import { getImports } from "./get-imports";
|
|
15
|
+
import { getStaticImports } from "./get-imports";
|
|
16
|
+
import { getDynamicImports } from "./get-imports";
|
|
17
|
+
import { getExports } from "./get-exports";
|
|
18
|
+
import { getDefaultExports } from "./get-exports";
|
|
19
|
+
import { getNamedExports } from "./get-exports";
|
|
20
|
+
import { getNamedDeclarationExports } from "./get-exports";
|
|
21
|
+
import { getAllExports } from "./get-exports";
|
|
22
|
+
import { getNamespaceExports } from "./get-exports";
|
|
23
|
+
import { getTypeExports } from "./get-exports";
|
|
24
|
+
export { hasESMSyntax, hasCJSSyntax, detectSyntax, getRequires, getDynamicRequires, getStaticRequires, getImports, getStaticImports, getDynamicImports, getExports, getDefaultExports, getNamedExports, getNamedDeclarationExports, getAllExports, getNamespaceExports, getTypeExports };
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AA0CA,+DAEC;AAnBD;;;;GAIG;AACH,wCAFW,MAAM,OAYhB"}
|
package/types/utils.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip comments from code while skipping strings, templates, and regex
|
|
3
|
+
* literals. Regex literals can legally contain `//`, for example `/https?:\/\//`,
|
|
4
|
+
* and must not be treated as line comments.
|
|
5
|
+
* @param {string} code
|
|
6
|
+
* @returns {string}
|
|
7
|
+
*/
|
|
8
|
+
export function stripComments(code: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Blank the contents of every string/template literal in `code` that looks
|
|
11
|
+
* like it contains embedded code (its body mentions `import`, `export`,
|
|
12
|
+
* `require`, or `module.exports`). The opening and closing quote chars are
|
|
13
|
+
* preserved, as are newlines. Total length is preserved so character indices
|
|
14
|
+
* remain stable.
|
|
15
|
+
*
|
|
16
|
+
* Strings whose bodies don't reference those keywords — including ordinary
|
|
17
|
+
* module specifiers like `'lodash'`, paths like `'./foo.js'`, URLs, and
|
|
18
|
+
* arbitrary user text — pass through untouched, so the static-import/require
|
|
19
|
+
* regexes can still read their content.
|
|
20
|
+
*
|
|
21
|
+
* Without this pass, regex-based extractors falsely match `import`, `export`,
|
|
22
|
+
* and `require` keywords that appear inside code samples embedded in strings.
|
|
23
|
+
*
|
|
24
|
+
* Run after `stripComments` in the import/require/export extractors. The
|
|
25
|
+
* comment scanner already skips strings and regex literals, so this pass can
|
|
26
|
+
* focus on embedded-code strings without risking `//` in URLs or regexes.
|
|
27
|
+
*
|
|
28
|
+
* Caveat: `${...}` interpolations inside template literals are treated as
|
|
29
|
+
* part of the body, so a runtime `${import('./x.js')}` inside a template
|
|
30
|
+
* would be blanked. Very rare in practice; a proper tokenizer would be
|
|
31
|
+
* needed to do better.
|
|
32
|
+
*
|
|
33
|
+
* @param {string} code
|
|
34
|
+
* @returns {string}
|
|
35
|
+
*/
|
|
36
|
+
export function stripStringContents(code: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Blank comment bodies and code-bearing string/template bodies together.
|
|
39
|
+
* Solves two bugs that occurred when the string-strip and comment-strip ran
|
|
40
|
+
* as naive regex passes:
|
|
41
|
+
*
|
|
42
|
+
* - Apostrophes inside JSDoc comments (e.g. `* Netlify's \`...`) were
|
|
43
|
+
* mis-paired with later quotes, which shifted subsequent backtick
|
|
44
|
+
* pairing and could swallow real `export` declarations a few lines
|
|
45
|
+
* later in the same file.
|
|
46
|
+
* - `//` and `/* *\/` sequences inside string bodies were mis-stripped
|
|
47
|
+
* as comments.
|
|
48
|
+
* - `//` inside regex literals such as `/^https?:\/\//i` was mis-stripped
|
|
49
|
+
* as a line comment.
|
|
50
|
+
*
|
|
51
|
+
* Length is preserved (each consumed char replaced by a space or newline
|
|
52
|
+
* kept verbatim) so downstream character indices stay valid.
|
|
53
|
+
*
|
|
54
|
+
* Strings whose bodies don't reference `import` / `export` / `require` /
|
|
55
|
+
* `module.exports` pass through unchanged, so module specifiers like
|
|
56
|
+
* `'lodash'` or `'./foo.js'` stay readable by the downstream regexes.
|
|
57
|
+
*
|
|
58
|
+
* Caveat: `${...}` interpolations inside template literals are part of the
|
|
59
|
+
* body, so `${import('./x.js')}` inside a template gets blanked. Rare in
|
|
60
|
+
* practice; a full parser would be needed otherwise.
|
|
61
|
+
*
|
|
62
|
+
* @param {string} code
|
|
63
|
+
* @returns {string}
|
|
64
|
+
*/
|
|
65
|
+
export function stripCommentsAndStrings(code: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* Check if a module specifier is a Node.js built-in
|
|
68
|
+
* @param {string} moduleName - The module specifier (e.g., 'fs', 'node:fs/promises')
|
|
69
|
+
* @returns {boolean}
|
|
70
|
+
*/
|
|
71
|
+
export function isBuiltIn(moduleName: string): boolean;
|
|
72
|
+
export function isRelativeImport(importLocation: any): boolean;
|
|
73
|
+
export function isRelativeImportWithQuotes(importLocation: any): boolean;
|
|
74
|
+
export function getNames(names: any, aliasKey?: string): any;
|
|
75
|
+
export function extractExportName(exportValue: any): any;
|
|
76
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.js"],"names":[],"mappings":"AAsQA;;;;;;GAMG;AACH,oCAHW,MAAM,GACJ,MAAM,CAIlB;AAtQD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,0CAHW,MAAM,GACJ,MAAM,CA6ClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,8CAHW,MAAM,GACJ,MAAM,CAIlB;AAkKD;;;;GAIG;AACH,sCAHW,MAAM,GACJ,OAAO,CAUnB;AAED,+DAEC;AAED,yEAKC;AAgFD,6DA+DC;AAGD,yDAqCC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect-parameters-declaration.d.ts","sourceRoot":"","sources":["../../src/vendor/inspect-parameters-declaration.js"],"names":[],"mappings":"AA0QA,oDAaC;AAtBD,qDAGC;AAED,gFAEC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract all entry points from package.json
|
|
3
|
+
* @param {string} packageJsonPath - Path to package.json
|
|
4
|
+
* @returns {Array<{field: string, path: string, resolvedPath: string}>} - Array of entry point objects
|
|
5
|
+
*/
|
|
6
|
+
export function getPackageEntryPoints(packageJsonPath: string): Array<{
|
|
7
|
+
field: string;
|
|
8
|
+
path: string;
|
|
9
|
+
resolvedPath: string;
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* Verify all package.json entry points and collect dependencies
|
|
13
|
+
* @param {string} packagePath - Path to package.json
|
|
14
|
+
* @param {object} options - Options
|
|
15
|
+
* @param {boolean} [options.collectDeps] - If true, collect dependency paths for each entry point. Default: true
|
|
16
|
+
* @param {boolean} [options.verifyGraph] - If true, verify imports/exports. Default: true
|
|
17
|
+
* @param {boolean} [options.throwIfErrors] - If true, throw an error if there are any errors. Default: false
|
|
18
|
+
* @returns {{entryPoints: Array, sourceFiles: Set, errors: Array}} - Verification results
|
|
19
|
+
*/
|
|
20
|
+
export function verifyPackageEntries(packagePath: string, options?: {
|
|
21
|
+
collectDeps?: boolean;
|
|
22
|
+
verifyGraph?: boolean;
|
|
23
|
+
throwIfErrors?: boolean;
|
|
24
|
+
}): {
|
|
25
|
+
entryPoints: any[];
|
|
26
|
+
sourceFiles: Set<any>;
|
|
27
|
+
errors: any[];
|
|
28
|
+
};
|
|
29
|
+
export function collectEntryPoints(packageJson: any, packageDir: any): any[];
|
|
30
|
+
//# sourceMappingURL=verify-package-entries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-package-entries.d.ts","sourceRoot":"","sources":["../src/verify-package-entries.js"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,uDAHW,MAAM,GACJ,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAC,CAAC,CAOtE;AAmGD;;;;;;;;GAQG;AACH,kDAPW,MAAM,YAEd;IAA0B,WAAW,GAA7B,OAAO;IACW,WAAW,GAA7B,OAAO;IACW,aAAa,GAA/B,OAAO;CACf,GAAU;IAAC,WAAW,QAAQ;IAAC,WAAW,WAAM;IAAC,MAAM,QAAO;CAAC,CAoEjE;AA5KD,6EA8DC"}
|