deslop-js 0.0.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.
- package/LICENSE +21 -0
- package/dist/cli.cjs +141 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +142 -0
- package/dist/index.cjs +4953 -0
- package/dist/index.d.cts +44 -0
- package/dist/index.d.mts +44 -0
- package/dist/index.mjs +4922 -0
- package/dist/src-BIp8ek0h.mjs +4922 -0
- package/dist/src-BuniDJsj.cjs +4970 -0
- package/dist/src-OVMbJnkL.mjs +4924 -0
- package/dist/src-wbNpmldQ.cjs +4968 -0
- package/package.json +64 -0
|
@@ -0,0 +1,4922 @@
|
|
|
1
|
+
import path, { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
|
|
2
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import fg from "fast-glob";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { parseSync } from "oxc-parser";
|
|
6
|
+
import { ResolverFactory } from "oxc-resolver";
|
|
7
|
+
import { minimatch } from "minimatch";
|
|
8
|
+
|
|
9
|
+
//#region src/constants.ts
|
|
10
|
+
const DEFAULT_EXTENSIONS = [
|
|
11
|
+
".ts",
|
|
12
|
+
".tsx",
|
|
13
|
+
".js",
|
|
14
|
+
".jsx",
|
|
15
|
+
".mts",
|
|
16
|
+
".mjs",
|
|
17
|
+
".cts",
|
|
18
|
+
".cjs",
|
|
19
|
+
".mdx",
|
|
20
|
+
".astro",
|
|
21
|
+
".graphql",
|
|
22
|
+
".gql",
|
|
23
|
+
".css",
|
|
24
|
+
".scss",
|
|
25
|
+
".vue",
|
|
26
|
+
".svelte"
|
|
27
|
+
];
|
|
28
|
+
const HIDDEN_DIRECTORY_ALLOWLIST = [
|
|
29
|
+
".storybook",
|
|
30
|
+
".vitepress",
|
|
31
|
+
".well-known",
|
|
32
|
+
".changeset",
|
|
33
|
+
".github",
|
|
34
|
+
".client",
|
|
35
|
+
".server"
|
|
36
|
+
];
|
|
37
|
+
const OUTPUT_DIRECTORIES = [
|
|
38
|
+
"dist",
|
|
39
|
+
"build",
|
|
40
|
+
"out",
|
|
41
|
+
"esm",
|
|
42
|
+
"cjs"
|
|
43
|
+
];
|
|
44
|
+
const SOURCE_EXTENSIONS$3 = [
|
|
45
|
+
"ts",
|
|
46
|
+
"tsx",
|
|
47
|
+
"mts",
|
|
48
|
+
"cts",
|
|
49
|
+
"js",
|
|
50
|
+
"jsx",
|
|
51
|
+
"mjs",
|
|
52
|
+
"cjs"
|
|
53
|
+
];
|
|
54
|
+
const DEFAULT_IGNORE_PATTERNS = [
|
|
55
|
+
"**/node_modules/**",
|
|
56
|
+
"**/.git/**",
|
|
57
|
+
"**/coverage/**",
|
|
58
|
+
"**/*.min.js",
|
|
59
|
+
"**/*.min.mjs",
|
|
60
|
+
"**/mockServiceWorker.js"
|
|
61
|
+
];
|
|
62
|
+
const SCRIPT_FILE_PATTERN = /(?:^|\s)(?:node|tsx|ts-node|tsc|npx|bun|esr|esno|jiti|babel-node|zx)\s+(?:(?:-[\w-]+(?:[=\s][\w./@=-]+)?\s+)|(?:[\w/-]+\s+))*([\w./@-]+\.(?:ts|tsx|js|jsx|mts|mjs|cts|cjs))(?:\s|$)/;
|
|
63
|
+
const SCRIPT_EXTENSIONLESS_FILE_PATTERN = /(?:^|\s)(?:node|tsx|ts-node|bun|esr|esno|jiti|babel-node|zx)\s+(?:(?:-[\w-]+(?:[=\s][\w./@=-]+)?\s+))*((?:[./]|[\w@][\w@-]*\/)[\w./@-]+)(?:\s|$)/;
|
|
64
|
+
const SCRIPT_CONFIG_FILE_PATTERN = /--config\s+([\w./@-]+\.(?:ts|tsx|js|jsx|mts|mjs|cts|cjs))/;
|
|
65
|
+
const SCRIPT_ENTRY_PATTERNS = [];
|
|
66
|
+
const DEFAULT_ENTRY_PATTERNS = [
|
|
67
|
+
"src/index.{ts,tsx,js,jsx}",
|
|
68
|
+
"src/main.{ts,tsx,js,jsx}",
|
|
69
|
+
"index.{ts,tsx,js,jsx}",
|
|
70
|
+
"main.{ts,tsx,js,jsx}"
|
|
71
|
+
];
|
|
72
|
+
const CONFIG_FILE_PREFIXES = [
|
|
73
|
+
"babel.config.",
|
|
74
|
+
"rollup.config.",
|
|
75
|
+
"webpack.config.",
|
|
76
|
+
"postcss.config.",
|
|
77
|
+
"stencil.config.",
|
|
78
|
+
"remotion.config.",
|
|
79
|
+
"metro.config.",
|
|
80
|
+
"tsup.config.",
|
|
81
|
+
"tsdown.config.",
|
|
82
|
+
"unbuild.config.",
|
|
83
|
+
"esbuild.config.",
|
|
84
|
+
"swc.config.",
|
|
85
|
+
"turbo.",
|
|
86
|
+
"jest.config.",
|
|
87
|
+
"jest.setup.",
|
|
88
|
+
"vitest.config.",
|
|
89
|
+
"vitest.ci.config.",
|
|
90
|
+
"vitest.setup.",
|
|
91
|
+
"vitest.workspace.",
|
|
92
|
+
"playwright.config.",
|
|
93
|
+
"cypress.config.",
|
|
94
|
+
"karma.conf.",
|
|
95
|
+
"eslint.config.",
|
|
96
|
+
"prettier.config.",
|
|
97
|
+
"stylelint.config.",
|
|
98
|
+
"lint-staged.config.",
|
|
99
|
+
"commitlint.config.",
|
|
100
|
+
"next.config.",
|
|
101
|
+
"next-sitemap.config.",
|
|
102
|
+
"nuxt.config.",
|
|
103
|
+
"astro.config.",
|
|
104
|
+
"sanity.config.",
|
|
105
|
+
"vite.config.",
|
|
106
|
+
"tailwind.config.",
|
|
107
|
+
"drizzle.config.",
|
|
108
|
+
"knexfile.",
|
|
109
|
+
"sentry.client.config.",
|
|
110
|
+
"sentry.server.config.",
|
|
111
|
+
"sentry.edge.config.",
|
|
112
|
+
"react-router.config.",
|
|
113
|
+
"typedoc.",
|
|
114
|
+
"deslop.config.",
|
|
115
|
+
"i18next-parser.config.",
|
|
116
|
+
"codegen.config.",
|
|
117
|
+
"graphql.config.",
|
|
118
|
+
"npmpackagejsonlint.config.",
|
|
119
|
+
"release-it.",
|
|
120
|
+
"release.config.",
|
|
121
|
+
"contentlayer.config.",
|
|
122
|
+
"rspack.config.",
|
|
123
|
+
"rsbuild.config.",
|
|
124
|
+
"module-federation.config.",
|
|
125
|
+
"next-env.d.",
|
|
126
|
+
"env.d.",
|
|
127
|
+
"vite-env.d."
|
|
128
|
+
];
|
|
129
|
+
const ALWAYS_USED_PACKAGES = new Set([
|
|
130
|
+
"typescript",
|
|
131
|
+
"@types/node",
|
|
132
|
+
"@types/react",
|
|
133
|
+
"@types/react-dom",
|
|
134
|
+
"eslint",
|
|
135
|
+
"prettier",
|
|
136
|
+
"husky",
|
|
137
|
+
"lint-staged",
|
|
138
|
+
"tslib"
|
|
139
|
+
]);
|
|
140
|
+
const BUILTIN_MODULES = new Set([
|
|
141
|
+
"assert",
|
|
142
|
+
"async_hooks",
|
|
143
|
+
"buffer",
|
|
144
|
+
"child_process",
|
|
145
|
+
"cluster",
|
|
146
|
+
"console",
|
|
147
|
+
"constants",
|
|
148
|
+
"crypto",
|
|
149
|
+
"dgram",
|
|
150
|
+
"diagnostics_channel",
|
|
151
|
+
"dns",
|
|
152
|
+
"domain",
|
|
153
|
+
"events",
|
|
154
|
+
"fs",
|
|
155
|
+
"http",
|
|
156
|
+
"http2",
|
|
157
|
+
"https",
|
|
158
|
+
"inspector",
|
|
159
|
+
"module",
|
|
160
|
+
"net",
|
|
161
|
+
"os",
|
|
162
|
+
"path",
|
|
163
|
+
"perf_hooks",
|
|
164
|
+
"process",
|
|
165
|
+
"punycode",
|
|
166
|
+
"querystring",
|
|
167
|
+
"readline",
|
|
168
|
+
"repl",
|
|
169
|
+
"stream",
|
|
170
|
+
"string_decoder",
|
|
171
|
+
"sys",
|
|
172
|
+
"timers",
|
|
173
|
+
"tls",
|
|
174
|
+
"trace_events",
|
|
175
|
+
"tty",
|
|
176
|
+
"url",
|
|
177
|
+
"util",
|
|
178
|
+
"v8",
|
|
179
|
+
"vm",
|
|
180
|
+
"wasi",
|
|
181
|
+
"worker_threads",
|
|
182
|
+
"zlib"
|
|
183
|
+
]);
|
|
184
|
+
const PLATFORM_SUFFIXES = [
|
|
185
|
+
".web",
|
|
186
|
+
".native",
|
|
187
|
+
".ios",
|
|
188
|
+
".android",
|
|
189
|
+
".desktop",
|
|
190
|
+
".windows",
|
|
191
|
+
".macos",
|
|
192
|
+
".any"
|
|
193
|
+
];
|
|
194
|
+
const REACT_NATIVE_PLATFORM_EXTENSIONS = [
|
|
195
|
+
".web.ts",
|
|
196
|
+
".web.tsx",
|
|
197
|
+
".web.js",
|
|
198
|
+
".web.jsx",
|
|
199
|
+
".native.ts",
|
|
200
|
+
".native.tsx",
|
|
201
|
+
".native.js",
|
|
202
|
+
".native.jsx",
|
|
203
|
+
".ios.ts",
|
|
204
|
+
".ios.tsx",
|
|
205
|
+
".ios.js",
|
|
206
|
+
".ios.jsx",
|
|
207
|
+
".android.ts",
|
|
208
|
+
".android.tsx",
|
|
209
|
+
".android.js",
|
|
210
|
+
".android.jsx"
|
|
211
|
+
];
|
|
212
|
+
const RESOLVER_EXTENSIONS = [
|
|
213
|
+
...DEFAULT_EXTENSIONS,
|
|
214
|
+
".d.ts",
|
|
215
|
+
".d.mts",
|
|
216
|
+
".d.cts",
|
|
217
|
+
".json",
|
|
218
|
+
".node",
|
|
219
|
+
".css",
|
|
220
|
+
".scss",
|
|
221
|
+
".less",
|
|
222
|
+
".svg",
|
|
223
|
+
".png",
|
|
224
|
+
".jpg",
|
|
225
|
+
".graphql",
|
|
226
|
+
".gql"
|
|
227
|
+
];
|
|
228
|
+
|
|
229
|
+
//#endregion
|
|
230
|
+
//#region src/utils/line-column.ts
|
|
231
|
+
const getLineFromOffset = (source, offset) => {
|
|
232
|
+
let line = 1;
|
|
233
|
+
for (let charIndex = 0; charIndex < offset && charIndex < source.length; charIndex++) if (source[charIndex] === "\n") line++;
|
|
234
|
+
return line;
|
|
235
|
+
};
|
|
236
|
+
const getColumnFromOffset = (source, offset) => {
|
|
237
|
+
let column = 0;
|
|
238
|
+
for (let charIndex = offset - 1; charIndex >= 0; charIndex--) {
|
|
239
|
+
if (source[charIndex] === "\n") break;
|
|
240
|
+
column++;
|
|
241
|
+
}
|
|
242
|
+
return column;
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
//#endregion
|
|
246
|
+
//#region src/scanner/parse.ts
|
|
247
|
+
const extractMdxImportsExports = (sourceText) => {
|
|
248
|
+
const statements = [];
|
|
249
|
+
let isInMultiline = false;
|
|
250
|
+
let braceDepth = 0;
|
|
251
|
+
for (const line of sourceText.split("\n")) {
|
|
252
|
+
const trimmedLine = line.trim();
|
|
253
|
+
if (isInMultiline) {
|
|
254
|
+
statements.push(line);
|
|
255
|
+
for (const character of trimmedLine) {
|
|
256
|
+
if (character === "{") braceDepth++;
|
|
257
|
+
if (character === "}") braceDepth--;
|
|
258
|
+
}
|
|
259
|
+
const hasFromClause = trimmedLine.includes(" from ") || trimmedLine.includes(" from'") || trimmedLine.includes(" from\"");
|
|
260
|
+
if (braceDepth <= 0 || trimmedLine.endsWith(";") || hasFromClause) {
|
|
261
|
+
isInMultiline = false;
|
|
262
|
+
braceDepth = 0;
|
|
263
|
+
}
|
|
264
|
+
} else if (trimmedLine.startsWith("import ") || trimmedLine.startsWith("import{") || trimmedLine.startsWith("export ") || trimmedLine.startsWith("export{")) {
|
|
265
|
+
statements.push(line);
|
|
266
|
+
for (const character of trimmedLine) {
|
|
267
|
+
if (character === "{") braceDepth++;
|
|
268
|
+
if (character === "}") braceDepth--;
|
|
269
|
+
}
|
|
270
|
+
if (braceDepth > 0 && !trimmedLine.includes(" from ")) isInMultiline = true;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return statements.join("\n");
|
|
274
|
+
};
|
|
275
|
+
const ASTRO_FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---/;
|
|
276
|
+
const extractAstroFrontmatter = (sourceText) => {
|
|
277
|
+
const frontmatterMatch = sourceText.match(ASTRO_FRONTMATTER_PATTERN);
|
|
278
|
+
if (!frontmatterMatch) return "";
|
|
279
|
+
return frontmatterMatch[1];
|
|
280
|
+
};
|
|
281
|
+
const VUE_SCRIPT_PATTERN = /<script[^>]*(?:lang=["'](?:ts|tsx)["'][^>]*)?>([\s\S]*?)<\/script>/gi;
|
|
282
|
+
const extractVueScriptContent = (sourceText) => {
|
|
283
|
+
const scriptBlocks = [];
|
|
284
|
+
let scriptMatch;
|
|
285
|
+
VUE_SCRIPT_PATTERN.lastIndex = 0;
|
|
286
|
+
while ((scriptMatch = VUE_SCRIPT_PATTERN.exec(sourceText)) !== null) if (scriptMatch[1]) scriptBlocks.push(scriptMatch[1]);
|
|
287
|
+
return scriptBlocks.join("\n");
|
|
288
|
+
};
|
|
289
|
+
const SVELTE_SCRIPT_PATTERN = /<script[^>]*>([\s\S]*?)<\/script>/gi;
|
|
290
|
+
const extractSvelteScriptContent = (sourceText) => {
|
|
291
|
+
const scriptBlocks = [];
|
|
292
|
+
let scriptMatch;
|
|
293
|
+
SVELTE_SCRIPT_PATTERN.lastIndex = 0;
|
|
294
|
+
while ((scriptMatch = SVELTE_SCRIPT_PATTERN.exec(sourceText)) !== null) if (scriptMatch[1]) scriptBlocks.push(scriptMatch[1]);
|
|
295
|
+
return scriptBlocks.join("\n");
|
|
296
|
+
};
|
|
297
|
+
const getModuleExportNameValue = (exportName) => {
|
|
298
|
+
if (exportName.type === "Identifier") return exportName.name;
|
|
299
|
+
if (exportName.type === "Literal") return exportName.value;
|
|
300
|
+
return "default";
|
|
301
|
+
};
|
|
302
|
+
const CSS_EXTENSIONS = [
|
|
303
|
+
".css",
|
|
304
|
+
".scss",
|
|
305
|
+
".less",
|
|
306
|
+
".sass"
|
|
307
|
+
];
|
|
308
|
+
const CSS_IMPORT_PATTERN = /@import\s+(?:url\()?['"]([^'"]+)['"]\)?/g;
|
|
309
|
+
const SCSS_USE_FORWARD_PATTERN = /@(?:use|forward)\s+['"]([^'"]+)['"]/g;
|
|
310
|
+
const parseCssImports = (filePath) => {
|
|
311
|
+
const sourceText = readFileSync(filePath, "utf-8");
|
|
312
|
+
const imports = [];
|
|
313
|
+
const patterns = [CSS_IMPORT_PATTERN, SCSS_USE_FORWARD_PATTERN];
|
|
314
|
+
for (const pattern of patterns) {
|
|
315
|
+
let match;
|
|
316
|
+
pattern.lastIndex = 0;
|
|
317
|
+
while ((match = pattern.exec(sourceText)) !== null) {
|
|
318
|
+
const specifier = match[1];
|
|
319
|
+
if (specifier && !specifier.startsWith("http")) imports.push({
|
|
320
|
+
specifier,
|
|
321
|
+
importedNames: [],
|
|
322
|
+
isTypeOnly: false,
|
|
323
|
+
isDynamic: false,
|
|
324
|
+
isSideEffect: true,
|
|
325
|
+
line: sourceText.substring(0, match.index).split("\n").length,
|
|
326
|
+
column: 0
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return {
|
|
331
|
+
imports,
|
|
332
|
+
exports: [],
|
|
333
|
+
memberAccesses: [],
|
|
334
|
+
wholeObjectUses: []
|
|
335
|
+
};
|
|
336
|
+
};
|
|
337
|
+
const NON_JS_EXTENSIONS = [".graphql", ".gql"];
|
|
338
|
+
const parseModule = (filePath) => {
|
|
339
|
+
if (CSS_EXTENSIONS.some((ext) => filePath.endsWith(ext))) return parseCssImports(filePath);
|
|
340
|
+
if (NON_JS_EXTENSIONS.some((ext) => filePath.endsWith(ext))) return {
|
|
341
|
+
imports: [],
|
|
342
|
+
exports: [],
|
|
343
|
+
memberAccesses: [],
|
|
344
|
+
wholeObjectUses: []
|
|
345
|
+
};
|
|
346
|
+
const sourceText = readFileSync(filePath, "utf-8");
|
|
347
|
+
const imports = [];
|
|
348
|
+
const exports = [];
|
|
349
|
+
const isMdx = filePath.endsWith(".mdx");
|
|
350
|
+
const isAstro = filePath.endsWith(".astro");
|
|
351
|
+
const isVue = filePath.endsWith(".vue");
|
|
352
|
+
const isSvelte = filePath.endsWith(".svelte");
|
|
353
|
+
const textToParse = isMdx ? extractMdxImportsExports(sourceText) : isAstro ? extractAstroFrontmatter(sourceText) : isVue ? extractVueScriptContent(sourceText) : isSvelte ? extractSvelteScriptContent(sourceText) : sourceText;
|
|
354
|
+
const parseFileName = isMdx || isAstro || isVue || isSvelte ? filePath.replace(/\.(mdx|astro|vue|svelte)$/, ".tsx") : filePath;
|
|
355
|
+
let result = parseSync(parseFileName, textToParse);
|
|
356
|
+
const isPlainJsFile = parseFileName.endsWith(".js") || parseFileName.endsWith(".mjs") || parseFileName.endsWith(".cjs");
|
|
357
|
+
if (result.errors.length > 0 && isPlainJsFile && result.errors.some((parseError) => {
|
|
358
|
+
const errorMessage = String(parseError.message ?? "");
|
|
359
|
+
return errorMessage.includes("JSX") || errorMessage.includes("Unexpected token");
|
|
360
|
+
})) result = parseSync(parseFileName.replace(/\.(m?js|cjs)$/, ".jsx"), textToParse);
|
|
361
|
+
if (result.errors.length > 0) return {
|
|
362
|
+
imports,
|
|
363
|
+
exports,
|
|
364
|
+
memberAccesses: [],
|
|
365
|
+
wholeObjectUses: []
|
|
366
|
+
};
|
|
367
|
+
const program = result.program;
|
|
368
|
+
if (!program?.body) return {
|
|
369
|
+
imports,
|
|
370
|
+
exports,
|
|
371
|
+
memberAccesses: [],
|
|
372
|
+
wholeObjectUses: []
|
|
373
|
+
};
|
|
374
|
+
for (const node of program.body) switch (node.type) {
|
|
375
|
+
case "ImportDeclaration":
|
|
376
|
+
extractImportDeclaration(node, sourceText, imports);
|
|
377
|
+
break;
|
|
378
|
+
case "ExportNamedDeclaration":
|
|
379
|
+
extractNamedExportDeclaration(node, sourceText, exports);
|
|
380
|
+
break;
|
|
381
|
+
case "ExportDefaultDeclaration":
|
|
382
|
+
extractDefaultExportDeclaration(node, sourceText, exports);
|
|
383
|
+
break;
|
|
384
|
+
case "ExportAllDeclaration":
|
|
385
|
+
extractExportAllDeclaration(node, sourceText, exports);
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
collectDynamicImports(program.body, sourceText, imports);
|
|
389
|
+
const namespaceLocalNames = collectNamespaceLocalNames(imports);
|
|
390
|
+
const memberAccesses = [];
|
|
391
|
+
const wholeObjectUses = [];
|
|
392
|
+
if (namespaceLocalNames.size > 0) collectMemberAccesses(program.body, namespaceLocalNames, memberAccesses, wholeObjectUses);
|
|
393
|
+
return {
|
|
394
|
+
imports,
|
|
395
|
+
exports,
|
|
396
|
+
memberAccesses,
|
|
397
|
+
wholeObjectUses
|
|
398
|
+
};
|
|
399
|
+
};
|
|
400
|
+
const WHOLE_OBJECT_FUNCTION_NAMES = new Set([
|
|
401
|
+
"keys",
|
|
402
|
+
"values",
|
|
403
|
+
"entries",
|
|
404
|
+
"assign",
|
|
405
|
+
"freeze",
|
|
406
|
+
"getOwnPropertyNames",
|
|
407
|
+
"getOwnPropertyDescriptors"
|
|
408
|
+
]);
|
|
409
|
+
const collectNamespaceLocalNames = (imports) => {
|
|
410
|
+
const namespaceNames = /* @__PURE__ */ new Set();
|
|
411
|
+
for (const importInfo of imports) for (const importedName of importInfo.importedNames) if (importedName.isNamespace && importedName.alias) namespaceNames.add(importedName.alias);
|
|
412
|
+
return namespaceNames;
|
|
413
|
+
};
|
|
414
|
+
const collectMemberAccesses = (bodyNodes, namespaceLocalNames, memberAccesses, wholeObjectUses) => {
|
|
415
|
+
const walkForMemberAccesses = (node) => {
|
|
416
|
+
if (node.type === "MemberExpression" && !node.computed) {
|
|
417
|
+
const memberExpression = node;
|
|
418
|
+
if (memberExpression.object.type === "Identifier" && namespaceLocalNames.has(memberExpression.object.name)) {
|
|
419
|
+
const objectName = memberExpression.object.name;
|
|
420
|
+
const memberName = memberExpression.property.name;
|
|
421
|
+
if (memberName) memberAccesses.push({
|
|
422
|
+
objectName,
|
|
423
|
+
memberName
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
if (node.type === "MemberExpression" && Boolean(node.computed)) {
|
|
428
|
+
const computedExpression = node;
|
|
429
|
+
if (computedExpression.object.type === "Identifier" && namespaceLocalNames.has(computedExpression.object.name)) {
|
|
430
|
+
const objectName = computedExpression.object.name;
|
|
431
|
+
const expressionNode = node.expression;
|
|
432
|
+
if (expressionNode?.type === "Literal") {
|
|
433
|
+
const literalValue = expressionNode.value;
|
|
434
|
+
if (typeof literalValue === "string") memberAccesses.push({
|
|
435
|
+
objectName,
|
|
436
|
+
memberName: literalValue
|
|
437
|
+
});
|
|
438
|
+
else wholeObjectUses.push(objectName);
|
|
439
|
+
} else wholeObjectUses.push(objectName);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
if (node.type === "SpreadElement") {
|
|
443
|
+
const spreadArgument = node.argument;
|
|
444
|
+
if (spreadArgument?.type === "Identifier" && namespaceLocalNames.has(spreadArgument.name)) wholeObjectUses.push(spreadArgument.name);
|
|
445
|
+
}
|
|
446
|
+
if (node.type === "ForInStatement") {
|
|
447
|
+
const forInRight = node.right;
|
|
448
|
+
if (forInRight?.type === "Identifier" && namespaceLocalNames.has(forInRight.name)) wholeObjectUses.push(forInRight.name);
|
|
449
|
+
}
|
|
450
|
+
if (node.type === "CallExpression") {
|
|
451
|
+
const callExpression = node;
|
|
452
|
+
if (callExpression.callee.type === "MemberExpression" && !callExpression.callee.computed) {
|
|
453
|
+
const calleeMember = callExpression.callee;
|
|
454
|
+
if (calleeMember.object.type === "Identifier" && calleeMember.object.name === "Object" && WHOLE_OBJECT_FUNCTION_NAMES.has(calleeMember.property.name)) {
|
|
455
|
+
const firstArgument = callExpression.arguments[0];
|
|
456
|
+
if (firstArgument && firstArgument.type !== "SpreadElement" && firstArgument.type === "Identifier" && namespaceLocalNames.has(firstArgument.name)) wholeObjectUses.push(firstArgument.name);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
for (const value of Object.values(node)) if (Array.isArray(value)) {
|
|
461
|
+
for (const element of value) if (isWalkableNode(element)) walkForMemberAccesses(element);
|
|
462
|
+
} else if (isWalkableNode(value)) walkForMemberAccesses(value);
|
|
463
|
+
};
|
|
464
|
+
for (const topLevelNode of bodyNodes) if (isWalkableNode(topLevelNode)) walkForMemberAccesses(topLevelNode);
|
|
465
|
+
};
|
|
466
|
+
const extractImportDeclaration = (node, sourceText, imports) => {
|
|
467
|
+
const specifier = node.source.value;
|
|
468
|
+
if (!specifier) return;
|
|
469
|
+
const isTypeOnly = node.importKind === "type";
|
|
470
|
+
const importedNames = [];
|
|
471
|
+
for (const specifierNode of node.specifiers) switch (specifierNode.type) {
|
|
472
|
+
case "ImportDefaultSpecifier":
|
|
473
|
+
importedNames.push({
|
|
474
|
+
name: "default",
|
|
475
|
+
alias: specifierNode.local.name,
|
|
476
|
+
isNamespace: false,
|
|
477
|
+
isDefault: true,
|
|
478
|
+
isTypeOnly
|
|
479
|
+
});
|
|
480
|
+
break;
|
|
481
|
+
case "ImportNamespaceSpecifier":
|
|
482
|
+
importedNames.push({
|
|
483
|
+
name: "*",
|
|
484
|
+
alias: specifierNode.local.name,
|
|
485
|
+
isNamespace: true,
|
|
486
|
+
isDefault: false,
|
|
487
|
+
isTypeOnly
|
|
488
|
+
});
|
|
489
|
+
break;
|
|
490
|
+
case "ImportSpecifier": {
|
|
491
|
+
const importedName = getModuleExportNameValue(specifierNode.imported);
|
|
492
|
+
const localName = specifierNode.local.name;
|
|
493
|
+
importedNames.push({
|
|
494
|
+
name: importedName,
|
|
495
|
+
alias: localName !== importedName ? localName : void 0,
|
|
496
|
+
isNamespace: false,
|
|
497
|
+
isDefault: importedName === "default",
|
|
498
|
+
isTypeOnly: isTypeOnly || specifierNode.importKind === "type"
|
|
499
|
+
});
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
const isSideEffectImport = importedNames.length === 0;
|
|
504
|
+
if (isSideEffectImport) importedNames.push({
|
|
505
|
+
name: "*",
|
|
506
|
+
alias: void 0,
|
|
507
|
+
isNamespace: false,
|
|
508
|
+
isDefault: false,
|
|
509
|
+
isTypeOnly: false
|
|
510
|
+
});
|
|
511
|
+
imports.push({
|
|
512
|
+
specifier,
|
|
513
|
+
importedNames,
|
|
514
|
+
isTypeOnly,
|
|
515
|
+
isDynamic: false,
|
|
516
|
+
isSideEffect: isSideEffectImport,
|
|
517
|
+
line: getLineFromOffset(sourceText, node.start),
|
|
518
|
+
column: getColumnFromOffset(sourceText, node.start)
|
|
519
|
+
});
|
|
520
|
+
};
|
|
521
|
+
const extractNamedExportDeclaration = (node, sourceText, exports) => {
|
|
522
|
+
const isTypeOnly = node.exportKind === "type";
|
|
523
|
+
const reExportSource = node.source?.value ?? void 0;
|
|
524
|
+
if (node.declaration) extractDeclarationNames(node.declaration, isTypeOnly, sourceText, exports, node.start);
|
|
525
|
+
for (const specifierNode of node.specifiers) {
|
|
526
|
+
const exportedName = getModuleExportNameValue(specifierNode.exported);
|
|
527
|
+
const localName = getModuleExportNameValue(specifierNode.local);
|
|
528
|
+
exports.push({
|
|
529
|
+
name: exportedName,
|
|
530
|
+
isDefault: exportedName === "default",
|
|
531
|
+
isTypeOnly: isTypeOnly || specifierNode.exportKind === "type",
|
|
532
|
+
isReExport: reExportSource !== void 0,
|
|
533
|
+
isSynthetic: false,
|
|
534
|
+
reExportSource,
|
|
535
|
+
reExportOriginalName: reExportSource !== void 0 ? localName : void 0,
|
|
536
|
+
isNamespaceReExport: false,
|
|
537
|
+
line: getLineFromOffset(sourceText, specifierNode.start ?? node.start),
|
|
538
|
+
column: getColumnFromOffset(sourceText, specifierNode.start ?? node.start)
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
const extractDefaultExportDeclaration = (node, sourceText, exports) => {
|
|
543
|
+
exports.push({
|
|
544
|
+
name: "default",
|
|
545
|
+
isDefault: true,
|
|
546
|
+
isTypeOnly: false,
|
|
547
|
+
isReExport: false,
|
|
548
|
+
isSynthetic: false,
|
|
549
|
+
reExportSource: void 0,
|
|
550
|
+
reExportOriginalName: void 0,
|
|
551
|
+
isNamespaceReExport: false,
|
|
552
|
+
line: getLineFromOffset(sourceText, node.start),
|
|
553
|
+
column: getColumnFromOffset(sourceText, node.start)
|
|
554
|
+
});
|
|
555
|
+
};
|
|
556
|
+
const extractExportAllDeclaration = (node, sourceText, exports) => {
|
|
557
|
+
const reExportSource = node.source.value;
|
|
558
|
+
if (!reExportSource) return;
|
|
559
|
+
const exportedName = node.exported ? getModuleExportNameValue(node.exported) : void 0;
|
|
560
|
+
exports.push({
|
|
561
|
+
name: exportedName ?? "*",
|
|
562
|
+
isDefault: false,
|
|
563
|
+
isTypeOnly: node.exportKind === "type",
|
|
564
|
+
isReExport: true,
|
|
565
|
+
isSynthetic: false,
|
|
566
|
+
reExportSource,
|
|
567
|
+
reExportOriginalName: "*",
|
|
568
|
+
isNamespaceReExport: !exportedName,
|
|
569
|
+
line: getLineFromOffset(sourceText, node.start),
|
|
570
|
+
column: getColumnFromOffset(sourceText, node.start)
|
|
571
|
+
});
|
|
572
|
+
};
|
|
573
|
+
const extractDeclarationNames = (declaration, isTypeOnly, sourceText, exports, fallbackStart) => {
|
|
574
|
+
const declarationType = declaration.type;
|
|
575
|
+
if (declarationType === "FunctionDeclaration" || declarationType === "ClassDeclaration" || declarationType === "TSEnumDeclaration") {
|
|
576
|
+
const declarationName = declaration.id?.name;
|
|
577
|
+
if (declarationName) exports.push({
|
|
578
|
+
name: declarationName,
|
|
579
|
+
isDefault: false,
|
|
580
|
+
isTypeOnly,
|
|
581
|
+
isReExport: false,
|
|
582
|
+
isSynthetic: false,
|
|
583
|
+
reExportSource: void 0,
|
|
584
|
+
reExportOriginalName: void 0,
|
|
585
|
+
isNamespaceReExport: false,
|
|
586
|
+
line: getLineFromOffset(sourceText, declaration.start ?? fallbackStart),
|
|
587
|
+
column: getColumnFromOffset(sourceText, declaration.start ?? fallbackStart)
|
|
588
|
+
});
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
if (declarationType === "TSTypeAliasDeclaration" || declarationType === "TSInterfaceDeclaration") {
|
|
592
|
+
const declarationName = declaration.id.name;
|
|
593
|
+
if (declarationName) exports.push({
|
|
594
|
+
name: declarationName,
|
|
595
|
+
isDefault: false,
|
|
596
|
+
isTypeOnly: true,
|
|
597
|
+
isReExport: false,
|
|
598
|
+
isSynthetic: false,
|
|
599
|
+
reExportSource: void 0,
|
|
600
|
+
reExportOriginalName: void 0,
|
|
601
|
+
isNamespaceReExport: false,
|
|
602
|
+
line: getLineFromOffset(sourceText, declaration.start ?? fallbackStart),
|
|
603
|
+
column: getColumnFromOffset(sourceText, declaration.start ?? fallbackStart)
|
|
604
|
+
});
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
if (declarationType === "VariableDeclaration") {
|
|
608
|
+
const variableDeclaration = declaration;
|
|
609
|
+
for (const declarator of variableDeclaration.declarations) {
|
|
610
|
+
const bindingNames = extractBindingPatternNames(declarator.id);
|
|
611
|
+
for (const bindingName of bindingNames) exports.push({
|
|
612
|
+
name: bindingName,
|
|
613
|
+
isDefault: false,
|
|
614
|
+
isTypeOnly,
|
|
615
|
+
isReExport: false,
|
|
616
|
+
isSynthetic: false,
|
|
617
|
+
reExportSource: void 0,
|
|
618
|
+
reExportOriginalName: void 0,
|
|
619
|
+
isNamespaceReExport: false,
|
|
620
|
+
line: getLineFromOffset(sourceText, declarator.start ?? fallbackStart),
|
|
621
|
+
column: getColumnFromOffset(sourceText, declarator.start ?? fallbackStart)
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
const extractBindingPatternNames = (pattern) => {
|
|
627
|
+
if (!pattern) return [];
|
|
628
|
+
if (pattern.type === "Identifier") return pattern.name ? [pattern.name] : [];
|
|
629
|
+
if (pattern.type === "ObjectPattern") {
|
|
630
|
+
const names = [];
|
|
631
|
+
for (const property of pattern.properties) if (property.type === "RestElement") names.push(...extractBindingPatternNames(property.argument));
|
|
632
|
+
else names.push(...extractBindingPatternNames(property.value));
|
|
633
|
+
return names;
|
|
634
|
+
}
|
|
635
|
+
if (pattern.type === "ArrayPattern") {
|
|
636
|
+
const names = [];
|
|
637
|
+
for (const element of pattern.elements) {
|
|
638
|
+
if (!element) continue;
|
|
639
|
+
if (element.type === "RestElement") names.push(...extractBindingPatternNames(element.argument));
|
|
640
|
+
else names.push(...extractBindingPatternNames(element));
|
|
641
|
+
}
|
|
642
|
+
return names;
|
|
643
|
+
}
|
|
644
|
+
if (pattern.type === "AssignmentPattern") return extractBindingPatternNames(pattern.left);
|
|
645
|
+
return [];
|
|
646
|
+
};
|
|
647
|
+
const createNamespaceImportedName = () => ({
|
|
648
|
+
name: "*",
|
|
649
|
+
alias: void 0,
|
|
650
|
+
isNamespace: true,
|
|
651
|
+
isDefault: false,
|
|
652
|
+
isTypeOnly: false
|
|
653
|
+
});
|
|
654
|
+
const isWalkableNode = (value) => Boolean(value) && typeof value === "object" && typeof value.type === "string";
|
|
655
|
+
const extractStringLiteralFromArgument = (callArguments) => {
|
|
656
|
+
const firstArgument = callArguments[0];
|
|
657
|
+
if (!firstArgument) return void 0;
|
|
658
|
+
if (firstArgument.type === "SpreadElement") return void 0;
|
|
659
|
+
if (firstArgument.type !== "Literal") return void 0;
|
|
660
|
+
const literalValue = firstArgument.value;
|
|
661
|
+
return typeof literalValue === "string" ? literalValue : void 0;
|
|
662
|
+
};
|
|
663
|
+
const extractGlobPatterns = (callArguments) => {
|
|
664
|
+
const firstArgument = callArguments[0];
|
|
665
|
+
if (!firstArgument || firstArgument.type === "SpreadElement") return [];
|
|
666
|
+
if (firstArgument.type === "Literal") {
|
|
667
|
+
const literalValue = firstArgument.value;
|
|
668
|
+
if (typeof literalValue === "string" && (literalValue.startsWith("./") || literalValue.startsWith("../"))) return [literalValue];
|
|
669
|
+
return [];
|
|
670
|
+
}
|
|
671
|
+
if (firstArgument.type === "ArrayExpression") return firstArgument.elements.filter((element) => element.type === "Literal" && typeof element.value === "string" && (element.value.startsWith("./") || element.value.startsWith("../"))).map((element) => element.value);
|
|
672
|
+
return [];
|
|
673
|
+
};
|
|
674
|
+
const extractRegexGlobSuffix = (callArguments) => {
|
|
675
|
+
const thirdArgument = callArguments[2];
|
|
676
|
+
if (!thirdArgument || thirdArgument.type === "SpreadElement") return void 0;
|
|
677
|
+
if (thirdArgument.type !== "Literal") return void 0;
|
|
678
|
+
const regExpValue = thirdArgument.regex;
|
|
679
|
+
if (!regExpValue) return void 0;
|
|
680
|
+
const extensionMatch = regExpValue.pattern.match(/^\\\.([\w|]+)\$$/);
|
|
681
|
+
if (extensionMatch) {
|
|
682
|
+
const extensions = extensionMatch[1].split("|");
|
|
683
|
+
if (extensions.length === 1) return `*.${extensions[0]}`;
|
|
684
|
+
return `*.{${extensions.join(",")}}`;
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
const hasMockFactoryArgument = (callExpression) => {
|
|
688
|
+
const secondArgument = callExpression.arguments[1];
|
|
689
|
+
if (!secondArgument) return false;
|
|
690
|
+
if (secondArgument.type === "SpreadElement") return false;
|
|
691
|
+
return secondArgument.type === "ArrowFunctionExpression" || secondArgument.type === "FunctionExpression";
|
|
692
|
+
};
|
|
693
|
+
const synthesizeAutoMockSibling = (mockSource) => {
|
|
694
|
+
if (!mockSource || mockSource.includes("://") || mockSource.startsWith("data:") || mockSource.split("/").some((segment) => segment === "__mocks__")) return;
|
|
695
|
+
const lastSlashIndex = mockSource.lastIndexOf("/");
|
|
696
|
+
if (lastSlashIndex === -1) return void 0;
|
|
697
|
+
const directory = mockSource.slice(0, lastSlashIndex);
|
|
698
|
+
const fileName = mockSource.slice(lastSlashIndex + 1);
|
|
699
|
+
if (!fileName) return void 0;
|
|
700
|
+
return `${directory}/__mocks__/${fileName}`;
|
|
701
|
+
};
|
|
702
|
+
const collectDynamicImports = (bodyNodes, sourceText, imports) => {
|
|
703
|
+
const walkNode = (node) => {
|
|
704
|
+
if (node.type === "ImportExpression") {
|
|
705
|
+
const importExpression = node;
|
|
706
|
+
const sourceExpression = importExpression.source;
|
|
707
|
+
if (sourceExpression.type === "Literal") {
|
|
708
|
+
const specifierValue = sourceExpression.value;
|
|
709
|
+
if (specifierValue) imports.push({
|
|
710
|
+
specifier: specifierValue,
|
|
711
|
+
importedNames: [createNamespaceImportedName()],
|
|
712
|
+
isTypeOnly: false,
|
|
713
|
+
isDynamic: true,
|
|
714
|
+
isSideEffect: false,
|
|
715
|
+
line: getLineFromOffset(sourceText, importExpression.start),
|
|
716
|
+
column: getColumnFromOffset(sourceText, importExpression.start)
|
|
717
|
+
});
|
|
718
|
+
} else if (sourceExpression.type === "TemplateLiteral") {
|
|
719
|
+
const templateLiteral = sourceExpression;
|
|
720
|
+
if (templateLiteral.quasis.length >= 2) {
|
|
721
|
+
const globPattern = templateLiteral.quasis.map((quasi) => quasi.value.cooked).join("*");
|
|
722
|
+
if (globPattern.startsWith("./") || globPattern.startsWith("../")) imports.push({
|
|
723
|
+
specifier: globPattern,
|
|
724
|
+
importedNames: [createNamespaceImportedName()],
|
|
725
|
+
isTypeOnly: false,
|
|
726
|
+
isDynamic: true,
|
|
727
|
+
isSideEffect: false,
|
|
728
|
+
isGlob: true,
|
|
729
|
+
line: getLineFromOffset(sourceText, importExpression.start),
|
|
730
|
+
column: getColumnFromOffset(sourceText, importExpression.start)
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
if (node.type === "CallExpression") {
|
|
737
|
+
const callExpression = node;
|
|
738
|
+
if (callExpression.callee.type === "Identifier" && callExpression.callee.name === "require") {
|
|
739
|
+
const requireSpecifier = extractStringLiteralFromArgument(callExpression.arguments);
|
|
740
|
+
if (requireSpecifier) imports.push({
|
|
741
|
+
specifier: requireSpecifier,
|
|
742
|
+
importedNames: [createNamespaceImportedName()],
|
|
743
|
+
isTypeOnly: false,
|
|
744
|
+
isDynamic: true,
|
|
745
|
+
isSideEffect: false,
|
|
746
|
+
line: getLineFromOffset(sourceText, callExpression.start),
|
|
747
|
+
column: getColumnFromOffset(sourceText, callExpression.start)
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
if (callExpression.callee.type === "MemberExpression" && !callExpression.callee.computed) {
|
|
751
|
+
const memberExpression = callExpression.callee;
|
|
752
|
+
if (memberExpression.object.type === "Identifier" && memberExpression.object.name === "require" && memberExpression.property.name === "resolve") {
|
|
753
|
+
const resolveSpecifier = extractStringLiteralFromArgument(callExpression.arguments);
|
|
754
|
+
if (resolveSpecifier) imports.push({
|
|
755
|
+
specifier: resolveSpecifier,
|
|
756
|
+
importedNames: [createNamespaceImportedName()],
|
|
757
|
+
isTypeOnly: false,
|
|
758
|
+
isDynamic: true,
|
|
759
|
+
isSideEffect: false,
|
|
760
|
+
line: getLineFromOffset(sourceText, callExpression.start),
|
|
761
|
+
column: getColumnFromOffset(sourceText, callExpression.start)
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
if (memberExpression.object.type === "Identifier" && (memberExpression.object.name === "vi" || memberExpression.object.name === "jest") && memberExpression.property.name === "mock") {
|
|
765
|
+
const mockSpecifier = extractStringLiteralFromArgument(callExpression.arguments);
|
|
766
|
+
if (mockSpecifier) {
|
|
767
|
+
imports.push({
|
|
768
|
+
specifier: mockSpecifier,
|
|
769
|
+
importedNames: [createNamespaceImportedName()],
|
|
770
|
+
isTypeOnly: false,
|
|
771
|
+
isDynamic: true,
|
|
772
|
+
isSideEffect: true,
|
|
773
|
+
line: getLineFromOffset(sourceText, callExpression.start),
|
|
774
|
+
column: getColumnFromOffset(sourceText, callExpression.start)
|
|
775
|
+
});
|
|
776
|
+
const hasFactoryArgument = hasMockFactoryArgument(callExpression);
|
|
777
|
+
const autoMockSibling = synthesizeAutoMockSibling(mockSpecifier);
|
|
778
|
+
if (!hasFactoryArgument && autoMockSibling) imports.push({
|
|
779
|
+
specifier: autoMockSibling,
|
|
780
|
+
importedNames: [createNamespaceImportedName()],
|
|
781
|
+
isTypeOnly: false,
|
|
782
|
+
isDynamic: true,
|
|
783
|
+
isSideEffect: true,
|
|
784
|
+
line: getLineFromOffset(sourceText, callExpression.start),
|
|
785
|
+
column: getColumnFromOffset(sourceText, callExpression.start)
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
if (memberExpression.object.type === "MetaProperty" && memberExpression.property.name === "glob") {
|
|
790
|
+
const globPatterns = extractGlobPatterns(callExpression.arguments);
|
|
791
|
+
for (const globPattern of globPatterns) imports.push({
|
|
792
|
+
specifier: globPattern,
|
|
793
|
+
importedNames: [createNamespaceImportedName()],
|
|
794
|
+
isTypeOnly: false,
|
|
795
|
+
isDynamic: true,
|
|
796
|
+
isSideEffect: false,
|
|
797
|
+
isGlob: true,
|
|
798
|
+
line: getLineFromOffset(sourceText, callExpression.start),
|
|
799
|
+
column: getColumnFromOffset(sourceText, callExpression.start)
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
if (memberExpression.object.type === "Identifier" && memberExpression.object.name === "require" && memberExpression.property.name === "context") {
|
|
803
|
+
const directoryArgument = extractStringLiteralFromArgument(callExpression.arguments);
|
|
804
|
+
if (directoryArgument && (directoryArgument.startsWith("./") || directoryArgument.startsWith("../"))) {
|
|
805
|
+
const hasRegexArgument = callExpression.arguments.length >= 3 && callExpression.arguments[2].type !== "SpreadElement";
|
|
806
|
+
const regexSuffix = extractRegexGlobSuffix(callExpression.arguments);
|
|
807
|
+
if (!hasRegexArgument || Boolean(regexSuffix)) {
|
|
808
|
+
const contextGlobPrefix = callExpression.arguments[1]?.type === "Literal" && callExpression.arguments[1].value === true ? `${directoryArgument}/**/` : `${directoryArgument}/`;
|
|
809
|
+
const contextGlobPattern = regexSuffix ? `${contextGlobPrefix}${regexSuffix}` : `${contextGlobPrefix}*`;
|
|
810
|
+
imports.push({
|
|
811
|
+
specifier: contextGlobPattern,
|
|
812
|
+
importedNames: [createNamespaceImportedName()],
|
|
813
|
+
isTypeOnly: false,
|
|
814
|
+
isDynamic: true,
|
|
815
|
+
isSideEffect: false,
|
|
816
|
+
isGlob: true,
|
|
817
|
+
line: getLineFromOffset(sourceText, callExpression.start),
|
|
818
|
+
column: getColumnFromOffset(sourceText, callExpression.start)
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
if (node.type === "NewExpression") {
|
|
826
|
+
const newExpression = node;
|
|
827
|
+
if (newExpression.callee.type === "Identifier" && newExpression.callee.name === "URL" && newExpression.arguments.length >= 2) {
|
|
828
|
+
const secondArgument = newExpression.arguments[1];
|
|
829
|
+
if (secondArgument.type === "MemberExpression" && secondArgument.object.type === "MetaProperty" && secondArgument.property.name === "url") {
|
|
830
|
+
const urlSpecifier = extractStringLiteralFromArgument(newExpression.arguments);
|
|
831
|
+
if (urlSpecifier) imports.push({
|
|
832
|
+
specifier: urlSpecifier,
|
|
833
|
+
importedNames: [createNamespaceImportedName()],
|
|
834
|
+
isTypeOnly: false,
|
|
835
|
+
isDynamic: true,
|
|
836
|
+
isSideEffect: true,
|
|
837
|
+
line: getLineFromOffset(sourceText, newExpression.start),
|
|
838
|
+
column: getColumnFromOffset(sourceText, newExpression.start)
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
if (node.type === "Decorator") {
|
|
844
|
+
const expression = node.expression;
|
|
845
|
+
if (expression?.type === "CallExpression") {
|
|
846
|
+
const callNode = expression;
|
|
847
|
+
const callee = callNode.callee;
|
|
848
|
+
if (callee.type === "Identifier" && callee.name === "Component") {
|
|
849
|
+
const objectArgument = callNode.arguments[0];
|
|
850
|
+
if (objectArgument?.type === "ObjectExpression") {
|
|
851
|
+
const objectProperties = objectArgument.properties;
|
|
852
|
+
for (const property of objectProperties) {
|
|
853
|
+
if (property.type !== "ObjectProperty" && property.type !== "Property") continue;
|
|
854
|
+
const propertyKey = property.key;
|
|
855
|
+
const propertyName = propertyKey?.name ?? propertyKey?.value;
|
|
856
|
+
const propertyValue = property.value;
|
|
857
|
+
if (propertyName === "templateUrl" && propertyValue?.type === "Literal") {
|
|
858
|
+
const templatePath = propertyValue.value;
|
|
859
|
+
if (templatePath) imports.push({
|
|
860
|
+
specifier: templatePath.startsWith(".") ? templatePath : `./${templatePath}`,
|
|
861
|
+
importedNames: [],
|
|
862
|
+
isTypeOnly: false,
|
|
863
|
+
isDynamic: false,
|
|
864
|
+
isSideEffect: true,
|
|
865
|
+
line: getLineFromOffset(sourceText, property.start),
|
|
866
|
+
column: getColumnFromOffset(sourceText, property.start)
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
if ((propertyName === "styleUrl" || propertyName === "styleUrls") && propertyValue) {
|
|
870
|
+
const styleUrlValues = [];
|
|
871
|
+
if (propertyValue.type === "Literal") {
|
|
872
|
+
const singleValue = propertyValue.value;
|
|
873
|
+
if (singleValue) styleUrlValues.push(singleValue);
|
|
874
|
+
} else if (propertyValue.type === "ArrayExpression") {
|
|
875
|
+
const arrayElements = propertyValue.elements;
|
|
876
|
+
for (const element of arrayElements) if (element?.type === "Literal") {
|
|
877
|
+
const elementValue = element.value;
|
|
878
|
+
if (elementValue) styleUrlValues.push(elementValue);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
for (const styleUrl of styleUrlValues) imports.push({
|
|
882
|
+
specifier: styleUrl.startsWith(".") ? styleUrl : `./${styleUrl}`,
|
|
883
|
+
importedNames: [],
|
|
884
|
+
isTypeOnly: false,
|
|
885
|
+
isDynamic: false,
|
|
886
|
+
isSideEffect: true,
|
|
887
|
+
line: getLineFromOffset(sourceText, property.start),
|
|
888
|
+
column: getColumnFromOffset(sourceText, property.start)
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
for (const value of Object.values(node)) if (Array.isArray(value)) {
|
|
897
|
+
for (const element of value) if (isWalkableNode(element)) walkNode(element);
|
|
898
|
+
} else if (isWalkableNode(value)) walkNode(value);
|
|
899
|
+
};
|
|
900
|
+
for (const topLevelNode of bodyNodes) if (isWalkableNode(topLevelNode)) walkNode(topLevelNode);
|
|
901
|
+
};
|
|
902
|
+
const ROUTE_CALL_FILE_ARG_INDEX = {
|
|
903
|
+
route: 1,
|
|
904
|
+
layout: 0,
|
|
905
|
+
index: 0
|
|
906
|
+
};
|
|
907
|
+
const extractStringFromExpression = (expression) => {
|
|
908
|
+
if (expression.type === "Literal") {
|
|
909
|
+
const literalValue = expression.value;
|
|
910
|
+
return typeof literalValue === "string" ? literalValue : void 0;
|
|
911
|
+
}
|
|
912
|
+
if (expression.type === "TemplateLiteral") {
|
|
913
|
+
const templateLiteral = expression;
|
|
914
|
+
if (templateLiteral.expressions.length === 0 && templateLiteral.quasis.length === 1) return templateLiteral.quasis[0]?.value.cooked;
|
|
915
|
+
}
|
|
916
|
+
};
|
|
917
|
+
const extractReactRouterRouteModuleEntries = (routesFilePath) => {
|
|
918
|
+
const result = parseSync(routesFilePath, readFileSync(routesFilePath, "utf-8"));
|
|
919
|
+
if (result.errors.length > 0 || !result.program?.body) return [];
|
|
920
|
+
const modulePaths = [];
|
|
921
|
+
const walkForRouteCalls = (node) => {
|
|
922
|
+
if (node.type === "CallExpression") {
|
|
923
|
+
const callExpression = node;
|
|
924
|
+
const callee = callExpression.callee;
|
|
925
|
+
if (callee.type === "Identifier") {
|
|
926
|
+
const fileArgumentIndex = ROUTE_CALL_FILE_ARG_INDEX[callee.name];
|
|
927
|
+
if (fileArgumentIndex !== void 0) {
|
|
928
|
+
const fileArgument = callExpression.arguments[fileArgumentIndex];
|
|
929
|
+
if (fileArgument && fileArgument.type !== "SpreadElement") {
|
|
930
|
+
const filePath = extractStringFromExpression(fileArgument);
|
|
931
|
+
if (filePath) modulePaths.push(filePath);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
for (const value of Object.values(node)) if (Array.isArray(value)) {
|
|
937
|
+
for (const element of value) if (isWalkableNode(element)) walkForRouteCalls(element);
|
|
938
|
+
} else if (isWalkableNode(value)) walkForRouteCalls(value);
|
|
939
|
+
};
|
|
940
|
+
for (const topLevelNode of result.program.body) if (isWalkableNode(topLevelNode)) walkForRouteCalls(topLevelNode);
|
|
941
|
+
return modulePaths;
|
|
942
|
+
};
|
|
943
|
+
|
|
944
|
+
//#endregion
|
|
945
|
+
//#region src/scanner/workspaces.ts
|
|
946
|
+
const discoverWorkspacePackagesWithExclusions = (rootDir) => {
|
|
947
|
+
const rootPatterns = collectWorkspacePatterns(rootDir);
|
|
948
|
+
const hasRootLevelWorkspacePatterns = rootPatterns.length > 0;
|
|
949
|
+
let expandedDirectories = hasRootLevelWorkspacePatterns ? expandWorkspaceGlobs(rootPatterns, rootDir) : [];
|
|
950
|
+
const implicitSubProjects = discoverImplicitSubProjects(rootDir, expandedDirectories);
|
|
951
|
+
if (expandedDirectories.length === 0 && implicitSubProjects.length > 0) for (const subProjectDirectory of implicitSubProjects) {
|
|
952
|
+
const subPatterns = collectWorkspacePatterns(subProjectDirectory);
|
|
953
|
+
if (subPatterns.length > 0) {
|
|
954
|
+
const subExpanded = expandWorkspaceGlobs(subPatterns, subProjectDirectory);
|
|
955
|
+
expandedDirectories.push(subProjectDirectory, ...subExpanded);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
const declaredDirectorySet = new Set(expandedDirectories);
|
|
959
|
+
const excludedDirectories = [];
|
|
960
|
+
const filteredImplicitSubProjects = implicitSubProjects;
|
|
961
|
+
const allDirectories = [...new Set([...expandedDirectories, ...filteredImplicitSubProjects])];
|
|
962
|
+
const workspacePackages = [];
|
|
963
|
+
for (const directory of allDirectories) {
|
|
964
|
+
const packageJsonPath = join(directory, "package.json");
|
|
965
|
+
if (!existsSync(packageJsonPath)) continue;
|
|
966
|
+
try {
|
|
967
|
+
const packageContent = readFileSync(packageJsonPath, "utf-8");
|
|
968
|
+
const packageJson = JSON.parse(packageContent);
|
|
969
|
+
const packageName = packageJson.name || relative(rootDir, directory);
|
|
970
|
+
const entryFiles = extractWorkspaceEntries(packageJson, directory);
|
|
971
|
+
const depthFromRoot = relative(rootDir, directory).split("/").filter(Boolean).length;
|
|
972
|
+
workspacePackages.push({
|
|
973
|
+
name: packageName,
|
|
974
|
+
directory,
|
|
975
|
+
entryFiles,
|
|
976
|
+
isDeclaredWorkspace: declaredDirectorySet.has(directory),
|
|
977
|
+
depthFromRoot
|
|
978
|
+
});
|
|
979
|
+
} catch {}
|
|
980
|
+
}
|
|
981
|
+
return {
|
|
982
|
+
packages: workspacePackages,
|
|
983
|
+
excludedDirectories,
|
|
984
|
+
hasRootLevelWorkspacePatterns
|
|
985
|
+
};
|
|
986
|
+
};
|
|
987
|
+
const IMPLICIT_SUB_PROJECT_SEARCH_DEPTH = 3;
|
|
988
|
+
const STANDALONE_PROJECT_LOCKFILES = [
|
|
989
|
+
"package-lock.json",
|
|
990
|
+
"yarn.lock",
|
|
991
|
+
"pnpm-lock.yaml",
|
|
992
|
+
"bun.lockb"
|
|
993
|
+
];
|
|
994
|
+
const isStandaloneProject = (directory) => STANDALONE_PROJECT_LOCKFILES.some((lockfile) => existsSync(join(directory, lockfile)));
|
|
995
|
+
const discoverImplicitSubProjects = (rootDir, alreadyDiscoveredDirectories) => {
|
|
996
|
+
const knownDirectories = new Set(alreadyDiscoveredDirectories);
|
|
997
|
+
const hasDeclaredWorkspaces = alreadyDiscoveredDirectories.length > 0;
|
|
998
|
+
const subProjectDirectories = [];
|
|
999
|
+
const subPackageJsonPaths = fg.sync("**/package.json", {
|
|
1000
|
+
cwd: rootDir,
|
|
1001
|
+
absolute: true,
|
|
1002
|
+
onlyFiles: true,
|
|
1003
|
+
ignore: [
|
|
1004
|
+
"**/node_modules/**",
|
|
1005
|
+
"**/dist/**",
|
|
1006
|
+
"**/build/**",
|
|
1007
|
+
"**/.git/**"
|
|
1008
|
+
],
|
|
1009
|
+
deep: IMPLICIT_SUB_PROJECT_SEARCH_DEPTH + 1
|
|
1010
|
+
});
|
|
1011
|
+
for (const packageJsonPath of subPackageJsonPaths) {
|
|
1012
|
+
const directory = packageJsonPath.replace(/\/package\.json$/, "");
|
|
1013
|
+
if (directory === rootDir) continue;
|
|
1014
|
+
if (knownDirectories.has(directory)) continue;
|
|
1015
|
+
if (hasDeclaredWorkspaces && isStandaloneProject(directory)) continue;
|
|
1016
|
+
subProjectDirectories.push(directory);
|
|
1017
|
+
}
|
|
1018
|
+
return subProjectDirectories;
|
|
1019
|
+
};
|
|
1020
|
+
const collectWorkspacePatterns = (rootDir) => {
|
|
1021
|
+
const patterns = [];
|
|
1022
|
+
const packageJsonPath = join(rootDir, "package.json");
|
|
1023
|
+
if (existsSync(packageJsonPath)) try {
|
|
1024
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
1025
|
+
const packageJson = JSON.parse(content);
|
|
1026
|
+
if (Array.isArray(packageJson.workspaces)) patterns.push(...packageJson.workspaces);
|
|
1027
|
+
else if (packageJson.workspaces?.packages) patterns.push(...packageJson.workspaces.packages);
|
|
1028
|
+
} catch {}
|
|
1029
|
+
const pnpmWorkspacePath = join(rootDir, "pnpm-workspace.yaml");
|
|
1030
|
+
if (existsSync(pnpmWorkspacePath)) try {
|
|
1031
|
+
const packageLines = extractPnpmWorkspacePackages(readFileSync(pnpmWorkspacePath, "utf-8"));
|
|
1032
|
+
patterns.push(...packageLines);
|
|
1033
|
+
} catch {}
|
|
1034
|
+
return patterns;
|
|
1035
|
+
};
|
|
1036
|
+
const extractPnpmWorkspacePackages = (yamlContent) => {
|
|
1037
|
+
const packages = [];
|
|
1038
|
+
let inPackagesSection = false;
|
|
1039
|
+
for (const line of yamlContent.split("\n")) {
|
|
1040
|
+
const trimmedLine = line.trim();
|
|
1041
|
+
if (trimmedLine === "packages:") {
|
|
1042
|
+
inPackagesSection = true;
|
|
1043
|
+
continue;
|
|
1044
|
+
}
|
|
1045
|
+
if (inPackagesSection) {
|
|
1046
|
+
if (trimmedLine.startsWith("- ")) {
|
|
1047
|
+
const pattern = trimmedLine.slice(2).trim().replace(/^["']|["']$/g, "");
|
|
1048
|
+
if (pattern && !pattern.startsWith("!")) packages.push(pattern);
|
|
1049
|
+
} else if (trimmedLine && !trimmedLine.startsWith("#")) break;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
return packages;
|
|
1053
|
+
};
|
|
1054
|
+
const expandWorkspaceGlobs = (patterns, rootDir) => {
|
|
1055
|
+
const directories = [];
|
|
1056
|
+
for (const pattern of patterns) if (pattern.includes("*")) {
|
|
1057
|
+
const globPattern = pattern.endsWith("/") ? `${pattern}package.json` : `${pattern}/package.json`;
|
|
1058
|
+
try {
|
|
1059
|
+
const matchedFiles = fg.sync(globPattern, {
|
|
1060
|
+
cwd: rootDir,
|
|
1061
|
+
absolute: true,
|
|
1062
|
+
onlyFiles: true
|
|
1063
|
+
});
|
|
1064
|
+
for (const matchedPath of matchedFiles) directories.push(matchedPath.replace(/\/package\.json$/, ""));
|
|
1065
|
+
} catch {}
|
|
1066
|
+
} else {
|
|
1067
|
+
const absoluteDirectory = resolve(rootDir, pattern);
|
|
1068
|
+
if (existsSync(join(absoluteDirectory, "package.json"))) directories.push(absoluteDirectory);
|
|
1069
|
+
}
|
|
1070
|
+
return [...new Set(directories)];
|
|
1071
|
+
};
|
|
1072
|
+
const SOURCE_EXTENSIONS$2 = [
|
|
1073
|
+
".ts",
|
|
1074
|
+
".tsx",
|
|
1075
|
+
".js",
|
|
1076
|
+
".jsx",
|
|
1077
|
+
".mts",
|
|
1078
|
+
".mjs",
|
|
1079
|
+
".cts",
|
|
1080
|
+
".cjs"
|
|
1081
|
+
];
|
|
1082
|
+
const OUTPUT_DIR_PREFIXES$1 = [
|
|
1083
|
+
"dist/",
|
|
1084
|
+
"build/",
|
|
1085
|
+
"lib/",
|
|
1086
|
+
"lib-dist/",
|
|
1087
|
+
"esm/",
|
|
1088
|
+
"cjs/",
|
|
1089
|
+
"out/",
|
|
1090
|
+
"./dist/",
|
|
1091
|
+
"./lib-dist/"
|
|
1092
|
+
];
|
|
1093
|
+
const SOURCE_INDEX_FALLBACK_STEMS$1 = [
|
|
1094
|
+
"src/index",
|
|
1095
|
+
"src/main",
|
|
1096
|
+
"index",
|
|
1097
|
+
"main"
|
|
1098
|
+
];
|
|
1099
|
+
const resolveSourcePath$1 = (distPath, directory) => {
|
|
1100
|
+
const relativeToDist = relative(directory, distPath);
|
|
1101
|
+
if (OUTPUT_DIR_PREFIXES$1.some((prefix) => relativeToDist.startsWith(prefix))) {
|
|
1102
|
+
const sourceVariants = OUTPUT_DIR_PREFIXES$1.map((prefix) => relativeToDist.replace(new RegExp(`^${prefix.replace(".", "\\.")}`), "src/")).filter((variant) => variant !== relativeToDist);
|
|
1103
|
+
for (const variant of sourceVariants) {
|
|
1104
|
+
const withoutExtension = variant.replace(/\.[^.]+$/, "");
|
|
1105
|
+
for (const sourceExtension of SOURCE_EXTENSIONS$2) {
|
|
1106
|
+
const sourceCandidate = resolve(directory, withoutExtension + sourceExtension);
|
|
1107
|
+
if (existsSync(sourceCandidate)) return [sourceCandidate];
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
for (const stem of SOURCE_INDEX_FALLBACK_STEMS$1) for (const sourceExtension of SOURCE_EXTENSIONS$2) {
|
|
1111
|
+
const fallbackCandidate = resolve(directory, stem + sourceExtension);
|
|
1112
|
+
if (existsSync(fallbackCandidate)) return [fallbackCandidate];
|
|
1113
|
+
}
|
|
1114
|
+
return [];
|
|
1115
|
+
}
|
|
1116
|
+
const resolvedDistPath = resolve(directory, relativeToDist);
|
|
1117
|
+
const candidates = [];
|
|
1118
|
+
const withoutJsExtension = relativeToDist.replace(/\.[cm]?js$/, "");
|
|
1119
|
+
if (withoutJsExtension !== relativeToDist) {
|
|
1120
|
+
for (const sourceExtension of SOURCE_EXTENSIONS$2) {
|
|
1121
|
+
const directSourceCandidate = resolve(directory, withoutJsExtension + sourceExtension);
|
|
1122
|
+
if (existsSync(directSourceCandidate)) candidates.push(directSourceCandidate);
|
|
1123
|
+
}
|
|
1124
|
+
const indexCandidate = resolve(directory, withoutJsExtension, "index.ts");
|
|
1125
|
+
if (existsSync(indexCandidate) && !candidates.includes(indexCandidate)) candidates.push(indexCandidate);
|
|
1126
|
+
}
|
|
1127
|
+
const withoutTsExtension = relativeToDist.replace(/\.ts$/, "");
|
|
1128
|
+
if (withoutTsExtension !== relativeToDist && !existsSync(resolvedDistPath)) {
|
|
1129
|
+
const tsxCandidate = resolve(directory, withoutTsExtension + ".tsx");
|
|
1130
|
+
if (existsSync(tsxCandidate) && !candidates.includes(tsxCandidate)) candidates.push(tsxCandidate);
|
|
1131
|
+
}
|
|
1132
|
+
if (candidates.length === 0 && existsSync(resolvedDistPath)) candidates.push(resolvedDistPath);
|
|
1133
|
+
return candidates;
|
|
1134
|
+
};
|
|
1135
|
+
const extractWorkspaceEntries = (packageJson, directory) => {
|
|
1136
|
+
const entries = [];
|
|
1137
|
+
const addWithSourceResolution = (filePath) => {
|
|
1138
|
+
const resolved = resolve(directory, filePath);
|
|
1139
|
+
const sourceVariants = resolveSourcePath$1(resolved, directory);
|
|
1140
|
+
if (sourceVariants.length > 0) entries.push(...sourceVariants);
|
|
1141
|
+
else entries.push(resolved);
|
|
1142
|
+
};
|
|
1143
|
+
for (const field of [
|
|
1144
|
+
"main",
|
|
1145
|
+
"module",
|
|
1146
|
+
"browser",
|
|
1147
|
+
"types",
|
|
1148
|
+
"typings",
|
|
1149
|
+
"source"
|
|
1150
|
+
]) {
|
|
1151
|
+
const fieldValue = packageJson[field];
|
|
1152
|
+
if (typeof fieldValue === "string") addWithSourceResolution(fieldValue);
|
|
1153
|
+
}
|
|
1154
|
+
if (packageJson.exports) {
|
|
1155
|
+
const exportPaths = [];
|
|
1156
|
+
collectExportPaths$1(packageJson.exports, directory, exportPaths);
|
|
1157
|
+
for (const exportPath of exportPaths) {
|
|
1158
|
+
const sourceVariants = resolveSourcePath$1(exportPath, directory);
|
|
1159
|
+
if (sourceVariants.length > 0) entries.push(...sourceVariants);
|
|
1160
|
+
else entries.push(exportPath);
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
if (packageJson.bin) {
|
|
1164
|
+
if (typeof packageJson.bin === "string") addWithSourceResolution(packageJson.bin);
|
|
1165
|
+
else if (typeof packageJson.bin === "object" && packageJson.bin !== null) {
|
|
1166
|
+
for (const binPath of Object.values(packageJson.bin)) if (typeof binPath === "string") addWithSourceResolution(binPath);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
return [...new Set(entries)];
|
|
1170
|
+
};
|
|
1171
|
+
const collectExportPaths$1 = (exportValue, rootDir, entries) => {
|
|
1172
|
+
if (typeof exportValue === "string") {
|
|
1173
|
+
if (exportValue.startsWith(".")) if (exportValue.includes("*")) {
|
|
1174
|
+
const globPattern = exportValue.replace(/^\.\/?/, "");
|
|
1175
|
+
try {
|
|
1176
|
+
const expandedFiles = fg.sync(globPattern, {
|
|
1177
|
+
cwd: rootDir,
|
|
1178
|
+
absolute: true,
|
|
1179
|
+
onlyFiles: true,
|
|
1180
|
+
ignore: ["**/node_modules/**"]
|
|
1181
|
+
});
|
|
1182
|
+
entries.push(...expandedFiles);
|
|
1183
|
+
} catch {}
|
|
1184
|
+
} else entries.push(resolve(rootDir, exportValue));
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
if (typeof exportValue !== "object" || exportValue === null) return;
|
|
1188
|
+
for (const nestedValue of Object.values(exportValue)) collectExportPaths$1(nestedValue, rootDir, entries);
|
|
1189
|
+
};
|
|
1190
|
+
const NEXTJS_APP_ROUTER_CONVENTIONS = [
|
|
1191
|
+
"page",
|
|
1192
|
+
"layout",
|
|
1193
|
+
"loading",
|
|
1194
|
+
"error",
|
|
1195
|
+
"not-found",
|
|
1196
|
+
"template",
|
|
1197
|
+
"default",
|
|
1198
|
+
"route",
|
|
1199
|
+
"global-error",
|
|
1200
|
+
"forbidden",
|
|
1201
|
+
"unauthorized",
|
|
1202
|
+
"middleware",
|
|
1203
|
+
"instrumentation",
|
|
1204
|
+
"manifest",
|
|
1205
|
+
"robots",
|
|
1206
|
+
"sitemap",
|
|
1207
|
+
"opengraph-image",
|
|
1208
|
+
"twitter-image",
|
|
1209
|
+
"icon",
|
|
1210
|
+
"apple-icon",
|
|
1211
|
+
"actions"
|
|
1212
|
+
];
|
|
1213
|
+
const FRAMEWORK_FILE_GLOB = "**/*.{ts,tsx,js,jsx,mjs,cjs}";
|
|
1214
|
+
const FRAMEWORK_FILE_GLOB_WITH_MDX = "**/*.{ts,tsx,js,jsx,mdx,md,mjs,cjs}";
|
|
1215
|
+
const NEXTJS_ENABLERS = ["next"];
|
|
1216
|
+
const REACT_ROUTER_ENABLERS = ["@react-router/dev"];
|
|
1217
|
+
const REMIX_ENABLERS = [
|
|
1218
|
+
"@remix-run/node",
|
|
1219
|
+
"@remix-run/react",
|
|
1220
|
+
"@remix-run/cloudflare",
|
|
1221
|
+
"@remix-run/cloudflare-pages",
|
|
1222
|
+
"@remix-run/deno"
|
|
1223
|
+
];
|
|
1224
|
+
const NUXT_ENABLERS = ["nuxt"];
|
|
1225
|
+
const SVELTEKIT_ENABLERS = ["@sveltejs/kit"];
|
|
1226
|
+
const ASTRO_ENABLERS = ["astro"];
|
|
1227
|
+
const GATSBY_ENABLERS = ["gatsby"];
|
|
1228
|
+
const readDependencies = (directory) => {
|
|
1229
|
+
const packageJsonPath = join(directory, "package.json");
|
|
1230
|
+
if (!existsSync(packageJsonPath)) return {};
|
|
1231
|
+
try {
|
|
1232
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
1233
|
+
const packageJson = JSON.parse(content);
|
|
1234
|
+
return {
|
|
1235
|
+
...packageJson.dependencies,
|
|
1236
|
+
...packageJson.devDependencies,
|
|
1237
|
+
...packageJson.optionalDependencies
|
|
1238
|
+
};
|
|
1239
|
+
} catch {
|
|
1240
|
+
return {};
|
|
1241
|
+
}
|
|
1242
|
+
};
|
|
1243
|
+
const hasAnyEnabler = (dependencies, enablers) => enablers.some((enabler) => enabler in dependencies);
|
|
1244
|
+
const extractReactRouterAppDirectory = (directory) => {
|
|
1245
|
+
for (const configFile of [
|
|
1246
|
+
"react-router.config.ts",
|
|
1247
|
+
"react-router.config.js",
|
|
1248
|
+
"react-router.config.mjs",
|
|
1249
|
+
"react-router.config.cjs"
|
|
1250
|
+
]) {
|
|
1251
|
+
const configPath = join(directory, configFile);
|
|
1252
|
+
if (!existsSync(configPath)) continue;
|
|
1253
|
+
try {
|
|
1254
|
+
const appDirectoryMatch = readFileSync(configPath, "utf-8").match(/appDirectory\s*:\s*['"`]([^'"`]+)['"`]/);
|
|
1255
|
+
if (appDirectoryMatch) return appDirectoryMatch[1].replace(/^\.\//, "");
|
|
1256
|
+
} catch {}
|
|
1257
|
+
}
|
|
1258
|
+
return "app";
|
|
1259
|
+
};
|
|
1260
|
+
const ROUTE_FILE_EXTENSIONS = [
|
|
1261
|
+
".ts",
|
|
1262
|
+
".tsx",
|
|
1263
|
+
".js",
|
|
1264
|
+
".jsx"
|
|
1265
|
+
];
|
|
1266
|
+
const resolveRouteModulePath = (modulePath, routesFileDirectory) => {
|
|
1267
|
+
const normalizedPath = modulePath.startsWith("./") ? modulePath.slice(2) : modulePath;
|
|
1268
|
+
if (ROUTE_FILE_EXTENSIONS.some((extension) => normalizedPath.endsWith(extension))) {
|
|
1269
|
+
const absolutePath = resolve(routesFileDirectory, normalizedPath);
|
|
1270
|
+
if (existsSync(absolutePath)) return absolutePath;
|
|
1271
|
+
return;
|
|
1272
|
+
}
|
|
1273
|
+
for (const extension of ROUTE_FILE_EXTENSIONS) {
|
|
1274
|
+
const absolutePath = resolve(routesFileDirectory, normalizedPath + extension);
|
|
1275
|
+
if (existsSync(absolutePath)) return absolutePath;
|
|
1276
|
+
}
|
|
1277
|
+
for (const extension of ROUTE_FILE_EXTENSIONS) {
|
|
1278
|
+
const absolutePath = resolve(routesFileDirectory, normalizedPath, `index${extension}`);
|
|
1279
|
+
if (existsSync(absolutePath)) return absolutePath;
|
|
1280
|
+
}
|
|
1281
|
+
};
|
|
1282
|
+
const extractRouteModuleEntriesFromRoutesFiles = (rootDir, appDirectory) => {
|
|
1283
|
+
const routesFileCandidates = fg.sync([
|
|
1284
|
+
`${appDirectory}/routes.{ts,js,mts,mjs}`,
|
|
1285
|
+
`${appDirectory}/routes/**/*.{ts,js,mts,mjs}`,
|
|
1286
|
+
`src/routes.{ts,js,mts,mjs}`
|
|
1287
|
+
], {
|
|
1288
|
+
cwd: rootDir,
|
|
1289
|
+
absolute: true,
|
|
1290
|
+
onlyFiles: true,
|
|
1291
|
+
ignore: ["**/node_modules/**"]
|
|
1292
|
+
});
|
|
1293
|
+
const resolvedEntries = [];
|
|
1294
|
+
for (const routesFilePath of routesFileCandidates) {
|
|
1295
|
+
const routesFileDirectory = dirname(routesFilePath);
|
|
1296
|
+
const modulePaths = extractReactRouterRouteModuleEntries(routesFilePath);
|
|
1297
|
+
for (const modulePath of modulePaths) {
|
|
1298
|
+
const resolvedPath = resolveRouteModulePath(modulePath, routesFileDirectory);
|
|
1299
|
+
if (resolvedPath) resolvedEntries.push(resolvedPath);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
return resolvedEntries;
|
|
1303
|
+
};
|
|
1304
|
+
const discoverFrameworkEntryPoints = (rootDir) => {
|
|
1305
|
+
const entryPoints = [];
|
|
1306
|
+
const dependencies = readDependencies(rootDir);
|
|
1307
|
+
const isNextjs = hasAnyEnabler(dependencies, NEXTJS_ENABLERS);
|
|
1308
|
+
const isReactRouter = hasAnyEnabler(dependencies, REACT_ROUTER_ENABLERS);
|
|
1309
|
+
const isRemix = hasAnyEnabler(dependencies, REMIX_ENABLERS);
|
|
1310
|
+
const isNuxt = hasAnyEnabler(dependencies, NUXT_ENABLERS);
|
|
1311
|
+
const isSvelteKit = hasAnyEnabler(dependencies, SVELTEKIT_ENABLERS);
|
|
1312
|
+
const isAstro = hasAnyEnabler(dependencies, ASTRO_ENABLERS);
|
|
1313
|
+
const isGatsby = hasAnyEnabler(dependencies, GATSBY_ENABLERS);
|
|
1314
|
+
if (isNextjs) {
|
|
1315
|
+
const appRouterConventionGlob = NEXTJS_APP_ROUTER_CONVENTIONS.map((convention) => `**/${convention}.{ts,tsx,js,jsx,mdx}`).join(",");
|
|
1316
|
+
const appDirs = [join(rootDir, "app"), join(rootDir, "src", "app")];
|
|
1317
|
+
for (const appDir of appDirs) if (existsSync(appDir) && statSync(appDir).isDirectory()) entryPoints.push(...fg.sync(`{${appRouterConventionGlob}}`, {
|
|
1318
|
+
cwd: appDir,
|
|
1319
|
+
absolute: true,
|
|
1320
|
+
onlyFiles: true,
|
|
1321
|
+
ignore: ["**/node_modules/**"]
|
|
1322
|
+
}));
|
|
1323
|
+
const pagesDirs = [join(rootDir, "pages"), join(rootDir, "src", "pages")];
|
|
1324
|
+
for (const pagesDir of pagesDirs) if (existsSync(pagesDir) && statSync(pagesDir).isDirectory()) entryPoints.push(...fg.sync(FRAMEWORK_FILE_GLOB, {
|
|
1325
|
+
cwd: pagesDir,
|
|
1326
|
+
absolute: true,
|
|
1327
|
+
onlyFiles: true,
|
|
1328
|
+
ignore: ["**/node_modules/**"]
|
|
1329
|
+
}));
|
|
1330
|
+
entryPoints.push(...fg.sync([
|
|
1331
|
+
"middleware.{ts,js}",
|
|
1332
|
+
"src/middleware.{ts,js}",
|
|
1333
|
+
"instrumentation.{ts,js}",
|
|
1334
|
+
"instrumentation-client.{ts,js}",
|
|
1335
|
+
"src/instrumentation.{ts,js}",
|
|
1336
|
+
"src/instrumentation-client.{ts,js}",
|
|
1337
|
+
"mdx-components.{ts,tsx,js,jsx}",
|
|
1338
|
+
"src/mdx-components.{ts,tsx,js,jsx}"
|
|
1339
|
+
], {
|
|
1340
|
+
cwd: rootDir,
|
|
1341
|
+
absolute: true,
|
|
1342
|
+
onlyFiles: true,
|
|
1343
|
+
ignore: ["**/node_modules/**"]
|
|
1344
|
+
}));
|
|
1345
|
+
}
|
|
1346
|
+
if (isReactRouter || isRemix) {
|
|
1347
|
+
const reactRouterAppDirectory = extractReactRouterAppDirectory(rootDir);
|
|
1348
|
+
entryPoints.push(...fg.sync([
|
|
1349
|
+
`${reactRouterAppDirectory}/routes/**/*.{ts,tsx,js,jsx}`,
|
|
1350
|
+
`${reactRouterAppDirectory}/root.{ts,tsx,js,jsx}`,
|
|
1351
|
+
`${reactRouterAppDirectory}/entry.client.{ts,tsx,js,jsx}`,
|
|
1352
|
+
`${reactRouterAppDirectory}/entry.server.{ts,tsx,js,jsx}`,
|
|
1353
|
+
`${reactRouterAppDirectory}/routes.{ts,js,mts,mjs}`
|
|
1354
|
+
], {
|
|
1355
|
+
cwd: rootDir,
|
|
1356
|
+
absolute: true,
|
|
1357
|
+
onlyFiles: true,
|
|
1358
|
+
ignore: ["**/node_modules/**"]
|
|
1359
|
+
}));
|
|
1360
|
+
const routeModuleEntries = extractRouteModuleEntriesFromRoutesFiles(rootDir, reactRouterAppDirectory);
|
|
1361
|
+
entryPoints.push(...routeModuleEntries);
|
|
1362
|
+
}
|
|
1363
|
+
if (isNuxt) for (const nuxtDir of [
|
|
1364
|
+
"pages",
|
|
1365
|
+
"layouts",
|
|
1366
|
+
"middleware",
|
|
1367
|
+
"server",
|
|
1368
|
+
"composables",
|
|
1369
|
+
"plugins"
|
|
1370
|
+
]) {
|
|
1371
|
+
const dirPath = join(rootDir, nuxtDir);
|
|
1372
|
+
if (existsSync(dirPath) && statSync(dirPath).isDirectory()) entryPoints.push(...fg.sync("**/*.{ts,tsx,js,jsx,vue}", {
|
|
1373
|
+
cwd: dirPath,
|
|
1374
|
+
absolute: true,
|
|
1375
|
+
onlyFiles: true,
|
|
1376
|
+
ignore: ["**/node_modules/**"]
|
|
1377
|
+
}));
|
|
1378
|
+
}
|
|
1379
|
+
if (isSvelteKit) {
|
|
1380
|
+
const svelteDirs = [
|
|
1381
|
+
join(rootDir, "src", "routes"),
|
|
1382
|
+
join(rootDir, "src", "lib"),
|
|
1383
|
+
join(rootDir, "src", "params")
|
|
1384
|
+
];
|
|
1385
|
+
for (const svelteDir of svelteDirs) if (existsSync(svelteDir) && statSync(svelteDir).isDirectory()) entryPoints.push(...fg.sync("**/*.{ts,tsx,js,jsx,svelte}", {
|
|
1386
|
+
cwd: svelteDir,
|
|
1387
|
+
absolute: true,
|
|
1388
|
+
onlyFiles: true,
|
|
1389
|
+
ignore: ["**/node_modules/**"]
|
|
1390
|
+
}));
|
|
1391
|
+
}
|
|
1392
|
+
if (isAstro) {
|
|
1393
|
+
const astroDirs = [
|
|
1394
|
+
join(rootDir, "src", "pages"),
|
|
1395
|
+
join(rootDir, "src", "layouts"),
|
|
1396
|
+
join(rootDir, "src", "content")
|
|
1397
|
+
];
|
|
1398
|
+
for (const astroDir of astroDirs) if (existsSync(astroDir) && statSync(astroDir).isDirectory()) entryPoints.push(...fg.sync(FRAMEWORK_FILE_GLOB_WITH_MDX, {
|
|
1399
|
+
cwd: astroDir,
|
|
1400
|
+
absolute: true,
|
|
1401
|
+
onlyFiles: true,
|
|
1402
|
+
ignore: ["**/node_modules/**"]
|
|
1403
|
+
}));
|
|
1404
|
+
}
|
|
1405
|
+
if (isGatsby) {
|
|
1406
|
+
const gatsbyDirs = [join(rootDir, "src", "pages"), join(rootDir, "src", "templates")];
|
|
1407
|
+
for (const gatsbyDir of gatsbyDirs) if (existsSync(gatsbyDir) && statSync(gatsbyDir).isDirectory()) entryPoints.push(...fg.sync(FRAMEWORK_FILE_GLOB, {
|
|
1408
|
+
cwd: gatsbyDir,
|
|
1409
|
+
absolute: true,
|
|
1410
|
+
onlyFiles: true,
|
|
1411
|
+
ignore: ["**/node_modules/**"]
|
|
1412
|
+
}));
|
|
1413
|
+
}
|
|
1414
|
+
entryPoints.push(...fg.sync([
|
|
1415
|
+
"**/*.stories.{ts,tsx,js,jsx,mts,mjs}",
|
|
1416
|
+
"**/*.story.{ts,tsx,js,jsx,mts,mjs}",
|
|
1417
|
+
".storybook/**/*.{ts,tsx,js,jsx,mts,mjs}"
|
|
1418
|
+
], {
|
|
1419
|
+
cwd: rootDir,
|
|
1420
|
+
absolute: true,
|
|
1421
|
+
onlyFiles: true,
|
|
1422
|
+
ignore: ["**/node_modules/**"],
|
|
1423
|
+
dot: true
|
|
1424
|
+
}));
|
|
1425
|
+
entryPoints.push(...fg.sync([
|
|
1426
|
+
"env.{ts,js,mjs}",
|
|
1427
|
+
"src/env.{ts,js,mjs}",
|
|
1428
|
+
"src/routeTree.gen.{ts,tsx}",
|
|
1429
|
+
"src/router.{ts,tsx}"
|
|
1430
|
+
], {
|
|
1431
|
+
cwd: rootDir,
|
|
1432
|
+
absolute: true,
|
|
1433
|
+
onlyFiles: true,
|
|
1434
|
+
ignore: ["**/node_modules/**"],
|
|
1435
|
+
dot: true
|
|
1436
|
+
}));
|
|
1437
|
+
for (const entryDir of ["e2e", "cypress"]) {
|
|
1438
|
+
const dirPath = join(rootDir, entryDir);
|
|
1439
|
+
if (existsSync(dirPath) && statSync(dirPath).isDirectory()) entryPoints.push(...fg.sync(FRAMEWORK_FILE_GLOB, {
|
|
1440
|
+
cwd: dirPath,
|
|
1441
|
+
absolute: true,
|
|
1442
|
+
onlyFiles: true,
|
|
1443
|
+
dot: entryDir.startsWith(".")
|
|
1444
|
+
}));
|
|
1445
|
+
}
|
|
1446
|
+
entryPoints.push(...discoverElectronEntryPoints(rootDir));
|
|
1447
|
+
entryPoints.push(...discoverMobileEntryPoints(rootDir));
|
|
1448
|
+
return [...new Set(entryPoints)];
|
|
1449
|
+
};
|
|
1450
|
+
const ELECTRON_ENABLERS = [
|
|
1451
|
+
"electron",
|
|
1452
|
+
"electron-builder",
|
|
1453
|
+
"@electron-forge/cli",
|
|
1454
|
+
"electron-vite"
|
|
1455
|
+
];
|
|
1456
|
+
const ELECTRON_ENTRY_PATTERNS = [
|
|
1457
|
+
"src/main/**/*.{ts,js}",
|
|
1458
|
+
"src/preload/**/*.{ts,js}",
|
|
1459
|
+
"electron/main.{ts,js}",
|
|
1460
|
+
"electron.vite.config.{ts,js,mjs}",
|
|
1461
|
+
"forge.config.{ts,js,cjs}",
|
|
1462
|
+
"electron-builder.{yml,yaml,json,json5,toml}"
|
|
1463
|
+
];
|
|
1464
|
+
const discoverElectronEntryPoints = (rootDir) => {
|
|
1465
|
+
const packageJsonPath = join(rootDir, "package.json");
|
|
1466
|
+
if (!existsSync(packageJsonPath)) return [];
|
|
1467
|
+
try {
|
|
1468
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
1469
|
+
const packageJson = JSON.parse(content);
|
|
1470
|
+
const allDependencies = {
|
|
1471
|
+
...packageJson.dependencies,
|
|
1472
|
+
...packageJson.devDependencies,
|
|
1473
|
+
...packageJson.optionalDependencies
|
|
1474
|
+
};
|
|
1475
|
+
if (!ELECTRON_ENABLERS.some((enabler) => enabler in allDependencies)) return [];
|
|
1476
|
+
return fg.sync(ELECTRON_ENTRY_PATTERNS, {
|
|
1477
|
+
cwd: rootDir,
|
|
1478
|
+
absolute: true,
|
|
1479
|
+
onlyFiles: true,
|
|
1480
|
+
ignore: ["**/node_modules/**"]
|
|
1481
|
+
});
|
|
1482
|
+
} catch {
|
|
1483
|
+
return [];
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
const EXPO_ENABLERS = ["expo"];
|
|
1487
|
+
const EXPO_ROUTER_ENABLERS = ["expo-router"];
|
|
1488
|
+
const EXPO_ENTRY_PATTERNS = [
|
|
1489
|
+
"App.{ts,tsx,js,jsx}",
|
|
1490
|
+
"src/App.{ts,tsx,js,jsx}",
|
|
1491
|
+
"app.config.{ts,js,mjs,cjs}",
|
|
1492
|
+
"metro.config.{ts,js,mjs,cjs}",
|
|
1493
|
+
"babel.config.{ts,js,mjs,cjs}"
|
|
1494
|
+
];
|
|
1495
|
+
const EXPO_ROUTER_ENTRY_PATTERNS = [
|
|
1496
|
+
"app/**/*.{ts,tsx,js,jsx}",
|
|
1497
|
+
"app.config.{ts,js,mjs,cjs}",
|
|
1498
|
+
"metro.config.{ts,js,mjs,cjs}",
|
|
1499
|
+
"babel.config.{ts,js,mjs,cjs}"
|
|
1500
|
+
];
|
|
1501
|
+
const REACT_NATIVE_ENABLERS$1 = ["react-native"];
|
|
1502
|
+
const REACT_NATIVE_ENTRY_PATTERNS = [
|
|
1503
|
+
"index.{ts,tsx,js,jsx}",
|
|
1504
|
+
"index.android.{ts,tsx,js,jsx}",
|
|
1505
|
+
"index.ios.{ts,tsx,js,jsx}",
|
|
1506
|
+
"index.native.{ts,tsx,js,jsx}",
|
|
1507
|
+
"App.{ts,tsx,js,jsx}",
|
|
1508
|
+
"src/App.{ts,tsx,js,jsx}",
|
|
1509
|
+
"metro.config.{ts,js}",
|
|
1510
|
+
"react-native.config.{ts,js}"
|
|
1511
|
+
];
|
|
1512
|
+
const discoverMobileEntryPoints = (directory) => {
|
|
1513
|
+
const packageJsonPath = join(directory, "package.json");
|
|
1514
|
+
if (!existsSync(packageJsonPath)) return [];
|
|
1515
|
+
try {
|
|
1516
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
1517
|
+
const packageJson = JSON.parse(content);
|
|
1518
|
+
const allDependencies = {
|
|
1519
|
+
...packageJson.dependencies,
|
|
1520
|
+
...packageJson.devDependencies,
|
|
1521
|
+
...packageJson.optionalDependencies
|
|
1522
|
+
};
|
|
1523
|
+
const detectedPatterns = [];
|
|
1524
|
+
if (EXPO_ROUTER_ENABLERS.some((enabler) => enabler in allDependencies)) detectedPatterns.push(...EXPO_ROUTER_ENTRY_PATTERNS);
|
|
1525
|
+
else if (EXPO_ENABLERS.some((enabler) => enabler in allDependencies)) detectedPatterns.push(...EXPO_ENTRY_PATTERNS);
|
|
1526
|
+
if (REACT_NATIVE_ENABLERS$1.some((enabler) => enabler in allDependencies)) detectedPatterns.push(...REACT_NATIVE_ENTRY_PATTERNS);
|
|
1527
|
+
if (detectedPatterns.length === 0) return [];
|
|
1528
|
+
return fg.sync(detectedPatterns, {
|
|
1529
|
+
cwd: directory,
|
|
1530
|
+
absolute: true,
|
|
1531
|
+
onlyFiles: true,
|
|
1532
|
+
ignore: ["**/node_modules/**"]
|
|
1533
|
+
});
|
|
1534
|
+
} catch {
|
|
1535
|
+
return [];
|
|
1536
|
+
}
|
|
1537
|
+
};
|
|
1538
|
+
|
|
1539
|
+
//#endregion
|
|
1540
|
+
//#region src/resolver/source-path.ts
|
|
1541
|
+
const SOURCE_EXTENSIONS$1 = [
|
|
1542
|
+
".ts",
|
|
1543
|
+
".tsx",
|
|
1544
|
+
".js",
|
|
1545
|
+
".jsx",
|
|
1546
|
+
".mts",
|
|
1547
|
+
".mjs"
|
|
1548
|
+
];
|
|
1549
|
+
const OUTPUT_DIR_PREFIXES = [
|
|
1550
|
+
"dist/esm/",
|
|
1551
|
+
"dist/cjs/",
|
|
1552
|
+
"dist/es/",
|
|
1553
|
+
"dist/lib/",
|
|
1554
|
+
"dist/",
|
|
1555
|
+
"build/",
|
|
1556
|
+
"lib/",
|
|
1557
|
+
"lib-dist/",
|
|
1558
|
+
"esm/",
|
|
1559
|
+
"cjs/",
|
|
1560
|
+
"out/"
|
|
1561
|
+
];
|
|
1562
|
+
const DIST_WILDCARD_PATTERN = /^dist-[^/]+\//;
|
|
1563
|
+
const SOURCE_INDEX_FALLBACK_STEMS = ["src/index", "src/main"];
|
|
1564
|
+
const matchesOutputDirectory = (relativePath) => OUTPUT_DIR_PREFIXES.some((prefix) => relativePath.startsWith(prefix)) || DIST_WILDCARD_PATTERN.test(relativePath);
|
|
1565
|
+
const resolveSourcePath = (distPath, directory) => {
|
|
1566
|
+
if (existsSync(distPath)) return distPath;
|
|
1567
|
+
const relativeToDist = relative(directory, distPath);
|
|
1568
|
+
const sourceReplacements = ["src/"];
|
|
1569
|
+
const allPrefixes = [...OUTPUT_DIR_PREFIXES];
|
|
1570
|
+
const wildcardMatch = DIST_WILDCARD_PATTERN.exec(relativeToDist);
|
|
1571
|
+
if (wildcardMatch) allPrefixes.push(wildcardMatch[0]);
|
|
1572
|
+
const sourceVariants = allPrefixes.flatMap((prefix) => sourceReplacements.map((replacement) => relativeToDist.replace(new RegExp(`^${prefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`), replacement))).filter((variant) => variant !== relativeToDist);
|
|
1573
|
+
for (const variant of sourceVariants) {
|
|
1574
|
+
const withoutExtension = variant.replace(/\.[^.]+$/, "");
|
|
1575
|
+
for (const sourceExtension of SOURCE_EXTENSIONS$1) {
|
|
1576
|
+
const sourceCandidate = resolve(directory, withoutExtension + sourceExtension);
|
|
1577
|
+
if (existsSync(sourceCandidate)) return sourceCandidate;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
if (matchesOutputDirectory(relativeToDist)) for (const stem of SOURCE_INDEX_FALLBACK_STEMS) for (const sourceExtension of SOURCE_EXTENSIONS$1) {
|
|
1581
|
+
const fallbackCandidate = resolve(directory, stem + sourceExtension);
|
|
1582
|
+
if (existsSync(fallbackCandidate)) return fallbackCandidate;
|
|
1583
|
+
}
|
|
1584
|
+
const withoutExtension = relativeToDist.replace(/\.[cm]?js$/, "");
|
|
1585
|
+
if (withoutExtension !== relativeToDist) {
|
|
1586
|
+
for (const sourceExtension of SOURCE_EXTENSIONS$1) {
|
|
1587
|
+
const directSourceCandidate = resolve(directory, withoutExtension + sourceExtension);
|
|
1588
|
+
if (existsSync(directSourceCandidate)) return directSourceCandidate;
|
|
1589
|
+
}
|
|
1590
|
+
const indexCandidate = resolve(directory, withoutExtension, "index.ts");
|
|
1591
|
+
if (existsSync(indexCandidate)) return indexCandidate;
|
|
1592
|
+
}
|
|
1593
|
+
};
|
|
1594
|
+
|
|
1595
|
+
//#endregion
|
|
1596
|
+
//#region src/scanner/discover.ts
|
|
1597
|
+
const discoverFiles = async (config) => {
|
|
1598
|
+
const extensions = config.includeExtensions.length > 0 ? config.includeExtensions : DEFAULT_EXTENSIONS;
|
|
1599
|
+
const extensionGlob = extensions.length === 1 ? `**/*${extensions[0]}` : `**/*{${extensions.join(",")}}`;
|
|
1600
|
+
const ignorePatterns = [...DEFAULT_IGNORE_PATTERNS, ...config.ignorePatterns];
|
|
1601
|
+
const absoluteRoot = resolve(config.rootDir);
|
|
1602
|
+
const mainFiles = await fg(extensionGlob, {
|
|
1603
|
+
cwd: absoluteRoot,
|
|
1604
|
+
absolute: true,
|
|
1605
|
+
ignore: ignorePatterns,
|
|
1606
|
+
dot: false,
|
|
1607
|
+
onlyFiles: true
|
|
1608
|
+
});
|
|
1609
|
+
const allowedHiddenGlobs = HIDDEN_DIRECTORY_ALLOWLIST.flatMap((directory) => [`${directory}/**/*{${extensions.join(",")}}`, `**/${directory}/**/*{${extensions.join(",")}}`]);
|
|
1610
|
+
const hiddenFiles = allowedHiddenGlobs.length > 0 ? await fg(allowedHiddenGlobs, {
|
|
1611
|
+
cwd: absoluteRoot,
|
|
1612
|
+
absolute: true,
|
|
1613
|
+
ignore: ignorePatterns,
|
|
1614
|
+
dot: true,
|
|
1615
|
+
onlyFiles: true
|
|
1616
|
+
}) : [];
|
|
1617
|
+
return [...mainFiles, ...hiddenFiles].sort().map((filePath, fileIndex) => ({
|
|
1618
|
+
index: fileIndex,
|
|
1619
|
+
path: filePath
|
|
1620
|
+
}));
|
|
1621
|
+
};
|
|
1622
|
+
const discoverFrameworkIgnorePatterns = (rootDir) => {
|
|
1623
|
+
const absoluteRoot = resolve(rootDir);
|
|
1624
|
+
const directoriesToCheck = [absoluteRoot, ...discoverWorkspacePackagesWithExclusions(absoluteRoot).packages.map((workspacePackage) => workspacePackage.directory)];
|
|
1625
|
+
const ignorePatterns = [];
|
|
1626
|
+
for (const directory of directoriesToCheck) {
|
|
1627
|
+
const packageJsonPath = join(directory, "package.json");
|
|
1628
|
+
if (!existsSync(packageJsonPath)) continue;
|
|
1629
|
+
let allDependencies = {};
|
|
1630
|
+
try {
|
|
1631
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
1632
|
+
const packageJson = JSON.parse(content);
|
|
1633
|
+
allDependencies = {
|
|
1634
|
+
...packageJson.dependencies,
|
|
1635
|
+
...packageJson.devDependencies,
|
|
1636
|
+
...packageJson.optionalDependencies
|
|
1637
|
+
};
|
|
1638
|
+
} catch {
|
|
1639
|
+
continue;
|
|
1640
|
+
}
|
|
1641
|
+
for (const plugin of TOOLING_PLUGIN_DEFINITIONS) if (plugin.contentIgnorePatterns && isToolingPluginEnabled(plugin, allDependencies)) for (const pattern of plugin.contentIgnorePatterns) {
|
|
1642
|
+
const absolutePattern = join(directory, pattern);
|
|
1643
|
+
ignorePatterns.push(absolutePattern);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
return ignorePatterns;
|
|
1647
|
+
};
|
|
1648
|
+
const discoverEntryPoints = async (config) => {
|
|
1649
|
+
const absoluteRoot = resolve(config.rootDir);
|
|
1650
|
+
const entryFiles = config.entryPatterns.length > 0 ? await fg(config.entryPatterns, {
|
|
1651
|
+
cwd: absoluteRoot,
|
|
1652
|
+
absolute: true,
|
|
1653
|
+
onlyFiles: true
|
|
1654
|
+
}) : [];
|
|
1655
|
+
const packageJsonEntries = await extractPackageJsonEntries(resolve(absoluteRoot, "package.json"));
|
|
1656
|
+
const workspaceDiscovery = discoverWorkspacePackagesWithExclusions(absoluteRoot);
|
|
1657
|
+
const workspacePackages = workspaceDiscovery.packages;
|
|
1658
|
+
const isEntryEligible = (workspacePackage) => {
|
|
1659
|
+
if (workspaceDiscovery.hasRootLevelWorkspacePatterns) return true;
|
|
1660
|
+
return workspacePackage.depthFromRoot <= 2;
|
|
1661
|
+
};
|
|
1662
|
+
const hasDeclaredWorkspaces = workspacePackages.some((workspacePackage) => workspacePackage.isDeclaredWorkspace);
|
|
1663
|
+
const workspaceEntries = [];
|
|
1664
|
+
for (const workspacePackage of workspacePackages) {
|
|
1665
|
+
const isEligible = isEntryEligible(workspacePackage);
|
|
1666
|
+
if (workspaceDiscovery.hasRootLevelWorkspacePatterns && hasDeclaredWorkspaces ? workspacePackage.isDeclaredWorkspace && isEligible : isEligible) {
|
|
1667
|
+
const workspaceFrameworkEntries = discoverFrameworkEntryPoints(workspacePackage.directory);
|
|
1668
|
+
workspaceEntries.push(...workspaceFrameworkEntries);
|
|
1669
|
+
}
|
|
1670
|
+
if (isEligible && (workspacePackage.isDeclaredWorkspace || !workspaceDiscovery.hasRootLevelWorkspacePatterns)) {
|
|
1671
|
+
const workspacePackageJsonEntries = await extractPackageJsonEntries(resolve(workspacePackage.directory, "package.json"));
|
|
1672
|
+
if (workspacePackageJsonEntries.some((entryPath) => existsSync(entryPath))) workspaceEntries.push(...workspacePackageJsonEntries);
|
|
1673
|
+
else {
|
|
1674
|
+
const defaultFallback = findDefaultIndexEntry(workspacePackage.directory);
|
|
1675
|
+
if (defaultFallback) workspaceEntries.push(defaultFallback);
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
const frameworkEntries = discoverFrameworkEntryPoints(absoluteRoot);
|
|
1680
|
+
const entryEligiblePackages = workspacePackages.filter(isEntryEligible);
|
|
1681
|
+
const scriptEntries = extractScriptEntries(absoluteRoot);
|
|
1682
|
+
for (const workspacePackage of entryEligiblePackages) scriptEntries.push(...extractScriptEntries(workspacePackage.directory));
|
|
1683
|
+
const webpackEntries = extractWebpackEntryPoints(absoluteRoot);
|
|
1684
|
+
for (const workspacePackage of entryEligiblePackages) webpackEntries.push(...extractWebpackEntryPoints(workspacePackage.directory));
|
|
1685
|
+
const viteEntries = extractViteEntryPoints(absoluteRoot);
|
|
1686
|
+
for (const workspacePackage of entryEligiblePackages) viteEntries.push(...extractViteEntryPoints(workspacePackage.directory));
|
|
1687
|
+
const bundlerConfigEntries = extractBundlerConfigEntryPoints(absoluteRoot);
|
|
1688
|
+
for (const workspacePackage of entryEligiblePackages) bundlerConfigEntries.push(...extractBundlerConfigEntryPoints(workspacePackage.directory));
|
|
1689
|
+
const htmlScriptEntries = extractHtmlScriptEntries(absoluteRoot);
|
|
1690
|
+
for (const workspacePackage of entryEligiblePackages) htmlScriptEntries.push(...extractHtmlScriptEntries(workspacePackage.directory));
|
|
1691
|
+
const allDiscoveredEntries = [
|
|
1692
|
+
...scriptEntries,
|
|
1693
|
+
...webpackEntries,
|
|
1694
|
+
...viteEntries,
|
|
1695
|
+
...bundlerConfigEntries
|
|
1696
|
+
];
|
|
1697
|
+
for (const entryPath of allDiscoveredEntries) if (entryPath.endsWith(".html") && existsSync(entryPath)) htmlScriptEntries.push(...extractScriptTagsFromHtmlFile(entryPath));
|
|
1698
|
+
const angularEntries = extractAngularEntryPoints(absoluteRoot);
|
|
1699
|
+
for (const workspacePackage of entryEligiblePackages) angularEntries.push(...extractAngularEntryPoints(workspacePackage.directory));
|
|
1700
|
+
const testSetupEntries = extractTestSetupFiles(absoluteRoot);
|
|
1701
|
+
for (const workspacePackage of entryEligiblePackages) testSetupEntries.push(...extractTestSetupFiles(workspacePackage.directory));
|
|
1702
|
+
const pluginFileEntries = extractNextConfigPluginFiles(absoluteRoot);
|
|
1703
|
+
for (const workspacePackage of entryEligiblePackages) pluginFileEntries.push(...extractNextConfigPluginFiles(workspacePackage.directory));
|
|
1704
|
+
const testRunnerDiscovery = discoverTestRunnerEntryPoints(absoluteRoot, entryEligiblePackages);
|
|
1705
|
+
const toolingDiscovery = discoverToolingEntryPoints(absoluteRoot, entryEligiblePackages);
|
|
1706
|
+
const ciEntries = extractCiWorkflowEntries(absoluteRoot);
|
|
1707
|
+
const testEntries = [...new Set([...testRunnerDiscovery.entryFiles, ...testSetupEntries])];
|
|
1708
|
+
const testEntryPathSet = new Set(testEntries);
|
|
1709
|
+
return {
|
|
1710
|
+
productionEntries: [...new Set([
|
|
1711
|
+
...entryFiles,
|
|
1712
|
+
...packageJsonEntries,
|
|
1713
|
+
...workspaceEntries,
|
|
1714
|
+
...frameworkEntries,
|
|
1715
|
+
...scriptEntries,
|
|
1716
|
+
...webpackEntries,
|
|
1717
|
+
...viteEntries,
|
|
1718
|
+
...bundlerConfigEntries,
|
|
1719
|
+
...htmlScriptEntries,
|
|
1720
|
+
...angularEntries,
|
|
1721
|
+
...pluginFileEntries,
|
|
1722
|
+
...toolingDiscovery.entryFiles,
|
|
1723
|
+
...ciEntries
|
|
1724
|
+
])].filter((entryPath) => !testEntryPathSet.has(entryPath)),
|
|
1725
|
+
testEntries,
|
|
1726
|
+
alwaysUsedFiles: [...new Set([...toolingDiscovery.alwaysUsedFiles, ...testRunnerDiscovery.alwaysUsedFiles])]
|
|
1727
|
+
};
|
|
1728
|
+
};
|
|
1729
|
+
const DEFAULT_INDEX_PATTERNS = [
|
|
1730
|
+
"src/index.ts",
|
|
1731
|
+
"src/index.tsx",
|
|
1732
|
+
"src/index.js",
|
|
1733
|
+
"src/index.jsx",
|
|
1734
|
+
"src/main.ts",
|
|
1735
|
+
"src/main.tsx",
|
|
1736
|
+
"src/main.js",
|
|
1737
|
+
"src/main.jsx",
|
|
1738
|
+
"index.ts",
|
|
1739
|
+
"index.tsx",
|
|
1740
|
+
"index.js",
|
|
1741
|
+
"index.jsx",
|
|
1742
|
+
"main.ts",
|
|
1743
|
+
"main.tsx",
|
|
1744
|
+
"main.js",
|
|
1745
|
+
"main.jsx"
|
|
1746
|
+
];
|
|
1747
|
+
const findDefaultIndexEntry = (directory) => {
|
|
1748
|
+
for (const pattern of DEFAULT_INDEX_PATTERNS) {
|
|
1749
|
+
const candidatePath = resolve(directory, pattern);
|
|
1750
|
+
if (existsSync(candidatePath)) return candidatePath;
|
|
1751
|
+
}
|
|
1752
|
+
};
|
|
1753
|
+
const SOURCE_EXTENSIONS = [
|
|
1754
|
+
".ts",
|
|
1755
|
+
".tsx",
|
|
1756
|
+
".mts",
|
|
1757
|
+
".cts"
|
|
1758
|
+
];
|
|
1759
|
+
const COMMON_SOURCE_DIRECTORIES = [
|
|
1760
|
+
"src",
|
|
1761
|
+
"lib",
|
|
1762
|
+
"main",
|
|
1763
|
+
"app",
|
|
1764
|
+
"source"
|
|
1765
|
+
];
|
|
1766
|
+
const BUILD_OUTPUT_DIRECTORY_PATTERN = /^(?:\.\/)?(?:dist(?:-[a-z]+)?|build|out|esm|cjs)\/(?:(?:esm|cjs|es|lib|commonjs|module)\/)?/;
|
|
1767
|
+
const findSourceFile = (baseDir, relativePath) => {
|
|
1768
|
+
const pathWithoutExtension = join(baseDir, relativePath).replace(/\.[cm]?js(x?)$/, "");
|
|
1769
|
+
for (const sourceExtension of SOURCE_EXTENSIONS) {
|
|
1770
|
+
const candidatePath = pathWithoutExtension + sourceExtension;
|
|
1771
|
+
if (existsSync(candidatePath)) return candidatePath;
|
|
1772
|
+
}
|
|
1773
|
+
const indexCandidate = join(pathWithoutExtension, "index.ts");
|
|
1774
|
+
if (existsSync(indexCandidate)) return indexCandidate;
|
|
1775
|
+
};
|
|
1776
|
+
const findSourceFileStrict = (baseDir, relativePath) => {
|
|
1777
|
+
const pathWithoutExtension = join(baseDir, relativePath).replace(/\.[cm]?js(x?)$/, "");
|
|
1778
|
+
for (const sourceExtension of SOURCE_EXTENSIONS) {
|
|
1779
|
+
const candidatePath = pathWithoutExtension + sourceExtension;
|
|
1780
|
+
if (existsSync(candidatePath)) return candidatePath;
|
|
1781
|
+
}
|
|
1782
|
+
const exactPath = join(baseDir, relativePath);
|
|
1783
|
+
if (existsSync(exactPath)) return exactPath;
|
|
1784
|
+
};
|
|
1785
|
+
const resolveBuiltPathToSource = (builtAbsolutePath, rootDir) => {
|
|
1786
|
+
if (existsSync(builtAbsolutePath)) return void 0;
|
|
1787
|
+
try {
|
|
1788
|
+
const tsconfigPath = join(rootDir, "tsconfig.json");
|
|
1789
|
+
if (!existsSync(tsconfigPath)) return void 0;
|
|
1790
|
+
const tsconfigContent = readFileSync(tsconfigPath, "utf-8").replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
1791
|
+
const tsconfig = JSON.parse(tsconfigContent);
|
|
1792
|
+
const outDir = tsconfig?.compilerOptions?.outDir;
|
|
1793
|
+
if (!outDir) return void 0;
|
|
1794
|
+
const absoluteOutDir = resolve(rootDir, outDir);
|
|
1795
|
+
const relativeToBuild = builtAbsolutePath.startsWith(absoluteOutDir) ? builtAbsolutePath.slice(absoluteOutDir.length) : void 0;
|
|
1796
|
+
if (!relativeToBuild) return void 0;
|
|
1797
|
+
const rootDirOption = tsconfig?.compilerOptions?.rootDir;
|
|
1798
|
+
const sourceRoot = rootDirOption ? resolve(rootDir, rootDirOption) : rootDir;
|
|
1799
|
+
const sourceFileMatch = findSourceFile(sourceRoot, relativeToBuild);
|
|
1800
|
+
if (sourceFileMatch) return sourceFileMatch;
|
|
1801
|
+
const directCandidate = join(sourceRoot, relativeToBuild);
|
|
1802
|
+
if (existsSync(directCandidate)) return directCandidate;
|
|
1803
|
+
if (!rootDirOption) for (const sourceDir of COMMON_SOURCE_DIRECTORIES) {
|
|
1804
|
+
const candidate = findSourceFile(resolve(rootDir, sourceDir), relativeToBuild);
|
|
1805
|
+
if (candidate) return candidate;
|
|
1806
|
+
}
|
|
1807
|
+
} catch {}
|
|
1808
|
+
};
|
|
1809
|
+
const resolveEntryPathViaHeuristic = (entryPath, rootDir) => {
|
|
1810
|
+
if (!BUILD_OUTPUT_DIRECTORY_PATTERN.test(entryPath)) return void 0;
|
|
1811
|
+
const buildDirMatch = entryPath.match(BUILD_OUTPUT_DIRECTORY_PATTERN);
|
|
1812
|
+
if (!buildDirMatch) return void 0;
|
|
1813
|
+
const relativeToBuildDir = entryPath.slice(buildDirMatch[0].length);
|
|
1814
|
+
for (const sourceDir of COMMON_SOURCE_DIRECTORIES) {
|
|
1815
|
+
const sourceBaseDir = resolve(rootDir, sourceDir);
|
|
1816
|
+
if (!existsSync(sourceBaseDir)) continue;
|
|
1817
|
+
const sourceFileMatch = findSourceFileStrict(sourceBaseDir, relativeToBuildDir);
|
|
1818
|
+
if (sourceFileMatch) return sourceFileMatch;
|
|
1819
|
+
}
|
|
1820
|
+
};
|
|
1821
|
+
const resolveEntryPath = (entryPath, rootDir) => {
|
|
1822
|
+
const absolutePath = resolve(rootDir, entryPath);
|
|
1823
|
+
const normalizedEntry = entryPath.replace(/^\.\//, "");
|
|
1824
|
+
if (BUILD_OUTPUT_DIRECTORY_PATTERN.test(normalizedEntry)) {
|
|
1825
|
+
const sourcePath = resolveBuiltPathToSource(absolutePath, rootDir);
|
|
1826
|
+
if (sourcePath) return sourcePath;
|
|
1827
|
+
const heuristicMatch = resolveEntryPathViaHeuristic(normalizedEntry, rootDir);
|
|
1828
|
+
if (heuristicMatch) return heuristicMatch;
|
|
1829
|
+
}
|
|
1830
|
+
if (existsSync(absolutePath)) return absolutePath;
|
|
1831
|
+
const sourcePath = resolveBuiltPathToSource(absolutePath, rootDir);
|
|
1832
|
+
if (sourcePath) return sourcePath;
|
|
1833
|
+
const directSourceMatch = findSourceFile(rootDir, normalizedEntry);
|
|
1834
|
+
if (directSourceMatch) return directSourceMatch;
|
|
1835
|
+
const heuristicMatch = resolveEntryPathViaHeuristic(normalizedEntry, rootDir);
|
|
1836
|
+
if (heuristicMatch) return heuristicMatch;
|
|
1837
|
+
return absolutePath;
|
|
1838
|
+
};
|
|
1839
|
+
const extractPackageJsonEntries = async (packageJsonPath) => {
|
|
1840
|
+
const entries = [];
|
|
1841
|
+
try {
|
|
1842
|
+
const content = await readFile(packageJsonPath, "utf-8");
|
|
1843
|
+
const packageJson = JSON.parse(content);
|
|
1844
|
+
const rootDir = packageJsonPath.replace(/\/package\.json$/, "");
|
|
1845
|
+
for (const field of [
|
|
1846
|
+
"main",
|
|
1847
|
+
"module",
|
|
1848
|
+
"browser",
|
|
1849
|
+
"types",
|
|
1850
|
+
"typings"
|
|
1851
|
+
]) if (typeof packageJson[field] === "string") entries.push(resolveEntryPath(packageJson[field], rootDir));
|
|
1852
|
+
if (packageJson.exports) {
|
|
1853
|
+
const exportEntries = [];
|
|
1854
|
+
collectExportPaths(packageJson.exports, rootDir, exportEntries);
|
|
1855
|
+
for (const exportEntry of exportEntries) if (existsSync(exportEntry)) entries.push(exportEntry);
|
|
1856
|
+
else {
|
|
1857
|
+
const sourcePath = resolveSourcePath(exportEntry, rootDir);
|
|
1858
|
+
if (sourcePath) entries.push(sourcePath);
|
|
1859
|
+
else if (exportEntry.endsWith(".ts")) {
|
|
1860
|
+
const tsxFallback = exportEntry.replace(/\.ts$/, ".tsx");
|
|
1861
|
+
if (existsSync(tsxFallback)) entries.push(tsxFallback);
|
|
1862
|
+
else entries.push(exportEntry);
|
|
1863
|
+
} else entries.push(resolveEntryPath(exportEntry, rootDir));
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
if (packageJson.bin) {
|
|
1867
|
+
if (typeof packageJson.bin === "string") entries.push(resolveEntryPath(packageJson.bin, rootDir));
|
|
1868
|
+
else if (typeof packageJson.bin === "object") {
|
|
1869
|
+
for (const binPath of Object.values(packageJson.bin)) if (typeof binPath === "string") entries.push(resolveEntryPath(binPath, rootDir));
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
} catch {}
|
|
1873
|
+
return entries;
|
|
1874
|
+
};
|
|
1875
|
+
const SHELL_OPERATORS_PATTERN = /\s*(?:&&|\|\||[;&|])\s*/;
|
|
1876
|
+
const SCRIPT_MULTIPLEXERS = new Set([
|
|
1877
|
+
"concurrently",
|
|
1878
|
+
"run-s",
|
|
1879
|
+
"run-p",
|
|
1880
|
+
"npm-run-all",
|
|
1881
|
+
"npm-run-all2",
|
|
1882
|
+
"wireit",
|
|
1883
|
+
"turbo",
|
|
1884
|
+
"lerna",
|
|
1885
|
+
"ultra"
|
|
1886
|
+
]);
|
|
1887
|
+
const CONFIG_LIKE_FLAGS = new Set([
|
|
1888
|
+
"--config",
|
|
1889
|
+
"-c",
|
|
1890
|
+
"--format",
|
|
1891
|
+
"--formatter",
|
|
1892
|
+
"--tsconfig",
|
|
1893
|
+
"--project",
|
|
1894
|
+
"-p",
|
|
1895
|
+
"--setup",
|
|
1896
|
+
"--global-setup"
|
|
1897
|
+
]);
|
|
1898
|
+
const ENV_WRAPPER_BINARIES = new Set([
|
|
1899
|
+
"cross-env",
|
|
1900
|
+
"dotenv",
|
|
1901
|
+
"dotenv-flow",
|
|
1902
|
+
"env-cmd"
|
|
1903
|
+
]);
|
|
1904
|
+
const NON_ENTRY_BINARIES = new Set([
|
|
1905
|
+
"prettier",
|
|
1906
|
+
"eslint",
|
|
1907
|
+
"tslint",
|
|
1908
|
+
"stylelint",
|
|
1909
|
+
"biome",
|
|
1910
|
+
"oxlint",
|
|
1911
|
+
"oxfmt",
|
|
1912
|
+
"tsc",
|
|
1913
|
+
"tsup",
|
|
1914
|
+
"tsdown",
|
|
1915
|
+
"rollup",
|
|
1916
|
+
"webpack",
|
|
1917
|
+
"rimraf",
|
|
1918
|
+
"del-cli",
|
|
1919
|
+
"shx",
|
|
1920
|
+
"cpy-cli",
|
|
1921
|
+
"cpx",
|
|
1922
|
+
"echo",
|
|
1923
|
+
"cat",
|
|
1924
|
+
"mkdir",
|
|
1925
|
+
"rm",
|
|
1926
|
+
"cp",
|
|
1927
|
+
"mv",
|
|
1928
|
+
"ls",
|
|
1929
|
+
"pwd",
|
|
1930
|
+
"test",
|
|
1931
|
+
"husky",
|
|
1932
|
+
"lint-staged",
|
|
1933
|
+
"commitlint",
|
|
1934
|
+
"changeset",
|
|
1935
|
+
"changesets",
|
|
1936
|
+
"typedoc",
|
|
1937
|
+
"api-extractor",
|
|
1938
|
+
"madge",
|
|
1939
|
+
"depcheck",
|
|
1940
|
+
"deslop",
|
|
1941
|
+
"sort-package-json",
|
|
1942
|
+
"pnpm",
|
|
1943
|
+
"npm",
|
|
1944
|
+
"yarn",
|
|
1945
|
+
"ni",
|
|
1946
|
+
"nr",
|
|
1947
|
+
"nun",
|
|
1948
|
+
"next",
|
|
1949
|
+
"nuxt",
|
|
1950
|
+
"astro",
|
|
1951
|
+
"vite",
|
|
1952
|
+
"svelte-kit",
|
|
1953
|
+
"prisma",
|
|
1954
|
+
"drizzle-kit",
|
|
1955
|
+
"formatjs",
|
|
1956
|
+
"i18next",
|
|
1957
|
+
"i18next-parser",
|
|
1958
|
+
"lingui",
|
|
1959
|
+
"storybook",
|
|
1960
|
+
"chromatic",
|
|
1961
|
+
"msw",
|
|
1962
|
+
"patch-package",
|
|
1963
|
+
"syncpack",
|
|
1964
|
+
"manypkg",
|
|
1965
|
+
"jest",
|
|
1966
|
+
"vitest",
|
|
1967
|
+
"mocha",
|
|
1968
|
+
"ava",
|
|
1969
|
+
"tap",
|
|
1970
|
+
"c8",
|
|
1971
|
+
"nyc",
|
|
1972
|
+
"playwright",
|
|
1973
|
+
"cypress",
|
|
1974
|
+
"puppeteer",
|
|
1975
|
+
"webdriver",
|
|
1976
|
+
"sequelize",
|
|
1977
|
+
"typeorm",
|
|
1978
|
+
"mikro-orm",
|
|
1979
|
+
"wait-on",
|
|
1980
|
+
"start-server-and-test",
|
|
1981
|
+
"remark",
|
|
1982
|
+
"markdownlint",
|
|
1983
|
+
"markdownlint-cli2",
|
|
1984
|
+
"textlint",
|
|
1985
|
+
"alex",
|
|
1986
|
+
"cspell",
|
|
1987
|
+
"ncu",
|
|
1988
|
+
"npm-check-updates",
|
|
1989
|
+
"size-limit",
|
|
1990
|
+
"bundlewatch",
|
|
1991
|
+
"dbdocs",
|
|
1992
|
+
"lobe-i18n",
|
|
1993
|
+
"lobe-seo"
|
|
1994
|
+
]);
|
|
1995
|
+
const looksLikeFilePath = (token) => {
|
|
1996
|
+
if (token.startsWith("-") || token.includes("${{") || token.includes("://")) return false;
|
|
1997
|
+
if (token.includes("}}") && !token.includes("{{")) return false;
|
|
1998
|
+
if (/\.(?:[cm]?[jt]sx?|css|scss|json|yaml|yml|toml|html|mjs|cjs|mts|cts|graphql|gql|mdx|astro|vue|svelte)$/.test(token)) return true;
|
|
1999
|
+
if (/\.\{[^}]+\}$/.test(token)) return true;
|
|
2000
|
+
if (token.startsWith("./") || token.startsWith("../")) return true;
|
|
2001
|
+
return token.includes("/") && !token.startsWith("@");
|
|
2002
|
+
};
|
|
2003
|
+
const isGlobPattern = (token) => {
|
|
2004
|
+
return token.includes("*") || token.includes("{") || token.includes("?");
|
|
2005
|
+
};
|
|
2006
|
+
const extractScriptFileArguments = (scriptCommand, directory) => {
|
|
2007
|
+
const entries = [];
|
|
2008
|
+
const segments = scriptCommand.split(SHELL_OPERATORS_PATTERN);
|
|
2009
|
+
for (const segment of segments) {
|
|
2010
|
+
const trimmedSegment = segment.trim();
|
|
2011
|
+
if (!trimmedSegment) continue;
|
|
2012
|
+
const tokens = trimmedSegment.split(/\s+/);
|
|
2013
|
+
if (tokens.length === 0) continue;
|
|
2014
|
+
let startIndex = 0;
|
|
2015
|
+
const firstBinary = tokens[0].replace(/^.*\//, "");
|
|
2016
|
+
if (ENV_WRAPPER_BINARIES.has(firstBinary)) {
|
|
2017
|
+
startIndex = 1;
|
|
2018
|
+
while (startIndex < tokens.length && /^[A-Z_][A-Z0-9_]*=/.test(tokens[startIndex])) startIndex++;
|
|
2019
|
+
if (startIndex >= tokens.length) continue;
|
|
2020
|
+
}
|
|
2021
|
+
const binaryName = tokens[startIndex].replace(/^.*\//, "");
|
|
2022
|
+
if (SCRIPT_MULTIPLEXERS.has(binaryName)) continue;
|
|
2023
|
+
const effectiveBinaryName = binaryName === "npx" || binaryName === "pnpx" || binaryName === "bunx" ? tokens[startIndex + 1]?.replace(/^.*\//, "") ?? "" : binaryName;
|
|
2024
|
+
const isNonEntryBinary = NON_ENTRY_BINARIES.has(binaryName) || effectiveBinaryName !== "" && NON_ENTRY_BINARIES.has(effectiveBinaryName);
|
|
2025
|
+
for (let tokenIndex = startIndex + 1; tokenIndex < tokens.length; tokenIndex++) {
|
|
2026
|
+
const token = tokens[tokenIndex].replace(/^['"]|['"]$/g, "");
|
|
2027
|
+
if (CONFIG_LIKE_FLAGS.has(token)) {
|
|
2028
|
+
if (tokenIndex + 1 < tokens.length && !tokens[tokenIndex + 1].startsWith("-")) {
|
|
2029
|
+
const configPath = tokens[tokenIndex + 1].replace(/^['"]|['"]$/g, "");
|
|
2030
|
+
if (looksLikeFilePath(configPath)) {
|
|
2031
|
+
const absoluteConfigPath = resolve(directory, configPath);
|
|
2032
|
+
if (existsSync(absoluteConfigPath)) entries.push(absoluteConfigPath);
|
|
2033
|
+
}
|
|
2034
|
+
tokenIndex++;
|
|
2035
|
+
}
|
|
2036
|
+
continue;
|
|
2037
|
+
}
|
|
2038
|
+
const equalsIndex = token.indexOf("=");
|
|
2039
|
+
if (equalsIndex > 0 && CONFIG_LIKE_FLAGS.has(token.slice(0, equalsIndex))) {
|
|
2040
|
+
const configValue = token.slice(equalsIndex + 1);
|
|
2041
|
+
if (configValue && looksLikeFilePath(configValue)) {
|
|
2042
|
+
const absoluteConfigPath = resolve(directory, configValue);
|
|
2043
|
+
if (existsSync(absoluteConfigPath)) entries.push(absoluteConfigPath);
|
|
2044
|
+
}
|
|
2045
|
+
continue;
|
|
2046
|
+
}
|
|
2047
|
+
if (token.startsWith("-")) continue;
|
|
2048
|
+
if (isNonEntryBinary) continue;
|
|
2049
|
+
if (!looksLikeFilePath(token)) continue;
|
|
2050
|
+
if (isGlobPattern(token)) {
|
|
2051
|
+
const expandedFiles = fg.sync(token, {
|
|
2052
|
+
cwd: directory,
|
|
2053
|
+
absolute: true,
|
|
2054
|
+
onlyFiles: true,
|
|
2055
|
+
ignore: ["**/node_modules/**"]
|
|
2056
|
+
});
|
|
2057
|
+
entries.push(...expandedFiles);
|
|
2058
|
+
} else {
|
|
2059
|
+
const absoluteFilePath = resolve(directory, token);
|
|
2060
|
+
if (existsSync(absoluteFilePath)) entries.push(absoluteFilePath);
|
|
2061
|
+
else {
|
|
2062
|
+
const sourcePath = resolveSourcePath(absoluteFilePath, directory);
|
|
2063
|
+
if (sourcePath) entries.push(sourcePath);
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
return entries;
|
|
2069
|
+
};
|
|
2070
|
+
const EXTENSIONLESS_SCRIPT_EXTENSIONS = [
|
|
2071
|
+
".ts",
|
|
2072
|
+
".tsx",
|
|
2073
|
+
".js",
|
|
2074
|
+
".jsx",
|
|
2075
|
+
".mts",
|
|
2076
|
+
".mjs",
|
|
2077
|
+
".cjs"
|
|
2078
|
+
];
|
|
2079
|
+
const resolveExtensionlessScriptPath = (basePath) => {
|
|
2080
|
+
for (const extension of EXTENSIONLESS_SCRIPT_EXTENSIONS) {
|
|
2081
|
+
const candidate = basePath + extension;
|
|
2082
|
+
if (existsSync(candidate)) return candidate;
|
|
2083
|
+
}
|
|
2084
|
+
const indexCandidate = resolve(basePath, "index.ts");
|
|
2085
|
+
if (existsSync(indexCandidate)) return indexCandidate;
|
|
2086
|
+
};
|
|
2087
|
+
const extractScriptEntries = (directory) => {
|
|
2088
|
+
const packageJsonPath = resolve(directory, "package.json");
|
|
2089
|
+
if (!existsSync(packageJsonPath)) return [];
|
|
2090
|
+
const entries = [];
|
|
2091
|
+
try {
|
|
2092
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
2093
|
+
const scripts = JSON.parse(content).scripts;
|
|
2094
|
+
if (scripts && typeof scripts === "object") for (const scriptCommand of Object.values(scripts)) {
|
|
2095
|
+
if (typeof scriptCommand !== "string") continue;
|
|
2096
|
+
const match = scriptCommand.match(SCRIPT_FILE_PATTERN);
|
|
2097
|
+
if (match?.[1]) {
|
|
2098
|
+
const scriptFilePath = resolve(directory, match[1]);
|
|
2099
|
+
if (existsSync(scriptFilePath)) entries.push(scriptFilePath);
|
|
2100
|
+
else {
|
|
2101
|
+
const sourcePath = resolveSourcePath(scriptFilePath, directory);
|
|
2102
|
+
if (sourcePath) entries.push(sourcePath);
|
|
2103
|
+
}
|
|
2104
|
+
} else {
|
|
2105
|
+
const extensionlessMatch = scriptCommand.match(SCRIPT_EXTENSIONLESS_FILE_PATTERN);
|
|
2106
|
+
if (extensionlessMatch?.[1]) {
|
|
2107
|
+
const extensionlessPath = extensionlessMatch[1];
|
|
2108
|
+
const resolved = resolveExtensionlessScriptPath(resolve(directory, extensionlessPath));
|
|
2109
|
+
if (resolved) entries.push(resolved);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
const configMatch = scriptCommand.match(SCRIPT_CONFIG_FILE_PATTERN);
|
|
2113
|
+
if (configMatch?.[1]) {
|
|
2114
|
+
const configFilePath = resolve(directory, configMatch[1]);
|
|
2115
|
+
if (existsSync(configFilePath)) entries.push(configFilePath);
|
|
2116
|
+
else {
|
|
2117
|
+
const sourcePath = resolveSourcePath(configFilePath, directory);
|
|
2118
|
+
if (sourcePath) entries.push(sourcePath);
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
entries.push(...extractScriptFileArguments(scriptCommand, directory));
|
|
2122
|
+
}
|
|
2123
|
+
} catch {}
|
|
2124
|
+
const scriptDirectoryFiles = fg.sync(SCRIPT_ENTRY_PATTERNS, {
|
|
2125
|
+
cwd: directory,
|
|
2126
|
+
absolute: true,
|
|
2127
|
+
onlyFiles: true,
|
|
2128
|
+
ignore: ["**/node_modules/**"]
|
|
2129
|
+
});
|
|
2130
|
+
entries.push(...scriptDirectoryFiles);
|
|
2131
|
+
return entries;
|
|
2132
|
+
};
|
|
2133
|
+
const isYamlMapping = (line) => {
|
|
2134
|
+
const firstWord = line.split(/\s/)[0];
|
|
2135
|
+
if (!firstWord) return false;
|
|
2136
|
+
return firstWord.endsWith(":") && !firstWord.startsWith("http") && !firstWord.startsWith("ftp");
|
|
2137
|
+
};
|
|
2138
|
+
const extractCiRunCommands = (content) => {
|
|
2139
|
+
const commands = [];
|
|
2140
|
+
let inMultilineRun = false;
|
|
2141
|
+
let multilineIndent = 0;
|
|
2142
|
+
for (const line of content.split("\n")) {
|
|
2143
|
+
const trimmedLine = line.trim();
|
|
2144
|
+
if (trimmedLine === "" || trimmedLine.startsWith("#")) continue;
|
|
2145
|
+
if (inMultilineRun) {
|
|
2146
|
+
if (line.length - line.trimStart().length > multilineIndent && trimmedLine !== "") {
|
|
2147
|
+
commands.push(trimmedLine);
|
|
2148
|
+
continue;
|
|
2149
|
+
}
|
|
2150
|
+
inMultilineRun = false;
|
|
2151
|
+
}
|
|
2152
|
+
const runMatch = trimmedLine.match(/^(?:-\s+)?run:\s*(.*)$/);
|
|
2153
|
+
if (runMatch) {
|
|
2154
|
+
const runValue = runMatch[1].trim();
|
|
2155
|
+
if (runValue === "|" || runValue === "|-" || runValue === "|+") {
|
|
2156
|
+
inMultilineRun = true;
|
|
2157
|
+
multilineIndent = line.length - line.trimStart().length;
|
|
2158
|
+
} else if (runValue !== "") commands.push(runValue);
|
|
2159
|
+
continue;
|
|
2160
|
+
}
|
|
2161
|
+
if (trimmedLine.startsWith("- ")) {
|
|
2162
|
+
const listItem = trimmedLine.slice(2).trim();
|
|
2163
|
+
if (listItem !== "" && !listItem.startsWith("{") && !listItem.startsWith("[") && !isYamlMapping(listItem)) commands.push(listItem);
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
return commands;
|
|
2167
|
+
};
|
|
2168
|
+
const extractCiWorkflowEntries = (rootDir) => {
|
|
2169
|
+
const entries = [];
|
|
2170
|
+
const workflowsDir = join(rootDir, ".github", "workflows");
|
|
2171
|
+
if (!existsSync(workflowsDir)) return entries;
|
|
2172
|
+
const workflowFiles = fg.sync("*.{yml,yaml}", {
|
|
2173
|
+
cwd: workflowsDir,
|
|
2174
|
+
absolute: true,
|
|
2175
|
+
onlyFiles: true
|
|
2176
|
+
});
|
|
2177
|
+
for (const workflowFile of workflowFiles) try {
|
|
2178
|
+
const runCommands = extractCiRunCommands(readFileSync(workflowFile, "utf-8"));
|
|
2179
|
+
for (const command of runCommands) {
|
|
2180
|
+
const scriptMatch = command.match(SCRIPT_FILE_PATTERN);
|
|
2181
|
+
if (scriptMatch?.[1]) {
|
|
2182
|
+
const scriptFilePath = resolve(rootDir, scriptMatch[1]);
|
|
2183
|
+
if (existsSync(scriptFilePath)) entries.push(scriptFilePath);
|
|
2184
|
+
}
|
|
2185
|
+
const configMatch = command.match(SCRIPT_CONFIG_FILE_PATTERN);
|
|
2186
|
+
if (configMatch?.[1]) {
|
|
2187
|
+
const configFilePath = resolve(rootDir, configMatch[1]);
|
|
2188
|
+
if (existsSync(configFilePath)) entries.push(configFilePath);
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
} catch {}
|
|
2192
|
+
return entries;
|
|
2193
|
+
};
|
|
2194
|
+
const VITE_INPUT_BLOCK_PATTERN = /input\s*:\s*(?:\{[^}]*\}|\[[^\]]*\]|['"][^'"]+['"])/gs;
|
|
2195
|
+
const BUNDLER_ENTRY_FILE_PATTERN = /['"]([^'"]+\.(?:js|ts|tsx|jsx|mjs|mts|less|scss|css|sass|html))['"]/g;
|
|
2196
|
+
const extractViteEntryPoints = (directory) => {
|
|
2197
|
+
const entries = [];
|
|
2198
|
+
const viteConfigPaths = fg.sync("vite.config.{js,ts,mjs,mts}", {
|
|
2199
|
+
cwd: directory,
|
|
2200
|
+
absolute: true,
|
|
2201
|
+
onlyFiles: true
|
|
2202
|
+
});
|
|
2203
|
+
for (const configPath of viteConfigPaths) try {
|
|
2204
|
+
const content = readFileSync(configPath, "utf-8");
|
|
2205
|
+
let inputMatch;
|
|
2206
|
+
VITE_INPUT_BLOCK_PATTERN.lastIndex = 0;
|
|
2207
|
+
while ((inputMatch = VITE_INPUT_BLOCK_PATTERN.exec(content)) !== null) {
|
|
2208
|
+
const inputBlock = inputMatch[0];
|
|
2209
|
+
let valueMatch;
|
|
2210
|
+
BUNDLER_ENTRY_FILE_PATTERN.lastIndex = 0;
|
|
2211
|
+
while ((valueMatch = BUNDLER_ENTRY_FILE_PATTERN.exec(inputBlock)) !== null) {
|
|
2212
|
+
const entryPath = valueMatch[1];
|
|
2213
|
+
if (entryPath.startsWith("./") || entryPath.startsWith("../") || !entryPath.startsWith("/")) {
|
|
2214
|
+
const absoluteEntryPath = resolve(directory, entryPath);
|
|
2215
|
+
if (existsSync(absoluteEntryPath)) entries.push(absoluteEntryPath);
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
} catch {}
|
|
2220
|
+
return entries;
|
|
2221
|
+
};
|
|
2222
|
+
const BUNDLER_CONFIG_ENTRY_BLOCK_PATTERN = /entry\s*:\s*\[([^\]]*)\]/gs;
|
|
2223
|
+
const BUNDLER_CONFIG_ENTRY_STRING_PATTERN = /['"]([^'"]+)['"]/g;
|
|
2224
|
+
const extractBundlerConfigEntryPoints = (directory) => {
|
|
2225
|
+
const entries = [];
|
|
2226
|
+
const configPaths = fg.sync(["tsdown.config.{ts,js,cjs,mjs}", "tsup.config.{ts,js,cjs,mjs}"], {
|
|
2227
|
+
cwd: directory,
|
|
2228
|
+
absolute: true,
|
|
2229
|
+
onlyFiles: true
|
|
2230
|
+
});
|
|
2231
|
+
for (const configPath of configPaths) try {
|
|
2232
|
+
const content = readFileSync(configPath, "utf-8");
|
|
2233
|
+
let blockMatch;
|
|
2234
|
+
BUNDLER_CONFIG_ENTRY_BLOCK_PATTERN.lastIndex = 0;
|
|
2235
|
+
while ((blockMatch = BUNDLER_CONFIG_ENTRY_BLOCK_PATTERN.exec(content)) !== null) {
|
|
2236
|
+
const arrayContent = blockMatch[1];
|
|
2237
|
+
let stringMatch;
|
|
2238
|
+
BUNDLER_CONFIG_ENTRY_STRING_PATTERN.lastIndex = 0;
|
|
2239
|
+
while ((stringMatch = BUNDLER_CONFIG_ENTRY_STRING_PATTERN.exec(arrayContent)) !== null) {
|
|
2240
|
+
const entryPath = stringMatch[1];
|
|
2241
|
+
const resolvedPath = resolveEntryWithExtensions(resolve(directory, entryPath));
|
|
2242
|
+
if (resolvedPath) entries.push(resolvedPath);
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
} catch {}
|
|
2246
|
+
return entries;
|
|
2247
|
+
};
|
|
2248
|
+
const WEBPACK_ENTRY_BLOCK_PATTERN = /entry\s*:\s*(?:\{[^}]*\}|\[[^\]]*\]|['"][^'"]+['"]|path\.(?:join|resolve)\([^)]*\))/gs;
|
|
2249
|
+
const WEBPACK_ENTRY_FILE_PATTERN = /['"]([^'"]+)['"]/g;
|
|
2250
|
+
const WEBPACK_PATH_JOIN_PATTERN = /path\.(?:join|resolve)\(\s*__dirname\s*,\s*((?:['"][^'"]*['"]\s*,?\s*)+)\)/g;
|
|
2251
|
+
const REQUIRE_RESOLVE_PATTERN = /require\.resolve\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
2252
|
+
const RESOLVABLE_EXTENSIONS = [
|
|
2253
|
+
".ts",
|
|
2254
|
+
".tsx",
|
|
2255
|
+
".js",
|
|
2256
|
+
".jsx",
|
|
2257
|
+
".mjs",
|
|
2258
|
+
".mts"
|
|
2259
|
+
];
|
|
2260
|
+
const resolveEntryWithExtensions = (basePath) => {
|
|
2261
|
+
if (existsSync(basePath)) return basePath;
|
|
2262
|
+
for (const extension of RESOLVABLE_EXTENSIONS) {
|
|
2263
|
+
const withExtension = basePath + extension;
|
|
2264
|
+
if (existsSync(withExtension)) return withExtension;
|
|
2265
|
+
}
|
|
2266
|
+
const indexCandidates = RESOLVABLE_EXTENSIONS.map((extension) => resolve(basePath, `index${extension}`));
|
|
2267
|
+
for (const candidate of indexCandidates) if (existsSync(candidate)) return candidate;
|
|
2268
|
+
};
|
|
2269
|
+
const extractWebpackEntryPoints = (directory) => {
|
|
2270
|
+
const entries = [];
|
|
2271
|
+
const webpackConfigPaths = fg.sync([
|
|
2272
|
+
"webpack.config.{js,ts,mjs,cjs}",
|
|
2273
|
+
"**/webpack*.config.{js,ts,mjs,cjs}",
|
|
2274
|
+
"**/webpack.config*.{js,ts,mjs,cjs}",
|
|
2275
|
+
"**/webpack*.config*.babel.{js,ts}"
|
|
2276
|
+
], {
|
|
2277
|
+
cwd: directory,
|
|
2278
|
+
absolute: true,
|
|
2279
|
+
onlyFiles: true,
|
|
2280
|
+
ignore: ["**/node_modules/**"],
|
|
2281
|
+
deep: 3
|
|
2282
|
+
});
|
|
2283
|
+
for (const configPath of webpackConfigPaths) try {
|
|
2284
|
+
const content = readFileSync(configPath, "utf-8");
|
|
2285
|
+
const configDirectory = dirname(configPath);
|
|
2286
|
+
let pathJoinMatch;
|
|
2287
|
+
WEBPACK_PATH_JOIN_PATTERN.lastIndex = 0;
|
|
2288
|
+
while ((pathJoinMatch = WEBPACK_PATH_JOIN_PATTERN.exec(content)) !== null) {
|
|
2289
|
+
const segments = [...pathJoinMatch[1].matchAll(/['"]([^'"]*)['"]/g)].map((match) => match[1]);
|
|
2290
|
+
if (segments.length > 0) {
|
|
2291
|
+
const resolvedEntry = resolveEntryWithExtensions(resolve(configDirectory, ...segments));
|
|
2292
|
+
if (resolvedEntry) entries.push(resolvedEntry);
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
let requireResolveMatch;
|
|
2296
|
+
REQUIRE_RESOLVE_PATTERN.lastIndex = 0;
|
|
2297
|
+
while ((requireResolveMatch = REQUIRE_RESOLVE_PATTERN.exec(content)) !== null) {
|
|
2298
|
+
const requirePath = requireResolveMatch[1];
|
|
2299
|
+
if (requirePath.startsWith("./") || requirePath.startsWith("../")) {
|
|
2300
|
+
const resolvedEntry = resolveEntryWithExtensions(resolve(configDirectory, requirePath));
|
|
2301
|
+
if (resolvedEntry) entries.push(resolvedEntry);
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
let entryMatch;
|
|
2305
|
+
WEBPACK_ENTRY_BLOCK_PATTERN.lastIndex = 0;
|
|
2306
|
+
while ((entryMatch = WEBPACK_ENTRY_BLOCK_PATTERN.exec(content)) !== null) {
|
|
2307
|
+
const entryBlock = entryMatch[0];
|
|
2308
|
+
if (entryBlock.includes("path.join") || entryBlock.includes("path.resolve")) continue;
|
|
2309
|
+
let valueMatch;
|
|
2310
|
+
WEBPACK_ENTRY_FILE_PATTERN.lastIndex = 0;
|
|
2311
|
+
while ((valueMatch = WEBPACK_ENTRY_FILE_PATTERN.exec(entryBlock)) !== null) {
|
|
2312
|
+
const entryPath = valueMatch[1];
|
|
2313
|
+
if (entryPath.startsWith("./") || entryPath.startsWith("../") || !entryPath.startsWith("/")) {
|
|
2314
|
+
const resolvedEntry = resolveEntryWithExtensions(resolve(directory, entryPath));
|
|
2315
|
+
if (resolvedEntry) entries.push(resolvedEntry);
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
} catch {}
|
|
2320
|
+
return entries;
|
|
2321
|
+
};
|
|
2322
|
+
const HTML_SCRIPT_SRC_PATTERN = /<script[^>]+src=["']([^"']+\.(?:ts|tsx|js|jsx|mts|mjs))["'][^>]*>/gi;
|
|
2323
|
+
const extractHtmlScriptEntries = (directory) => {
|
|
2324
|
+
const entries = [];
|
|
2325
|
+
const htmlFiles = fg.sync(["index.html", "*.html"], {
|
|
2326
|
+
cwd: directory,
|
|
2327
|
+
absolute: true,
|
|
2328
|
+
onlyFiles: true,
|
|
2329
|
+
ignore: [
|
|
2330
|
+
"**/node_modules/**",
|
|
2331
|
+
"**/dist/**",
|
|
2332
|
+
"**/build/**"
|
|
2333
|
+
],
|
|
2334
|
+
deep: 1
|
|
2335
|
+
});
|
|
2336
|
+
for (const htmlPath of htmlFiles) try {
|
|
2337
|
+
const content = readFileSync(htmlPath, "utf-8");
|
|
2338
|
+
let scriptMatch;
|
|
2339
|
+
HTML_SCRIPT_SRC_PATTERN.lastIndex = 0;
|
|
2340
|
+
while ((scriptMatch = HTML_SCRIPT_SRC_PATTERN.exec(content)) !== null) {
|
|
2341
|
+
const scriptSrc = scriptMatch[1].replace(/^\//, "");
|
|
2342
|
+
const absoluteScriptPath = resolve(htmlPath.replace(/\/[^/]+$/, ""), scriptSrc);
|
|
2343
|
+
if (existsSync(absoluteScriptPath)) entries.push(absoluteScriptPath);
|
|
2344
|
+
}
|
|
2345
|
+
} catch {}
|
|
2346
|
+
return entries;
|
|
2347
|
+
};
|
|
2348
|
+
const extractScriptTagsFromHtmlFile = (htmlFilePath) => {
|
|
2349
|
+
const entries = [];
|
|
2350
|
+
try {
|
|
2351
|
+
const content = readFileSync(htmlFilePath, "utf-8");
|
|
2352
|
+
let scriptMatch;
|
|
2353
|
+
HTML_SCRIPT_SRC_PATTERN.lastIndex = 0;
|
|
2354
|
+
while ((scriptMatch = HTML_SCRIPT_SRC_PATTERN.exec(content)) !== null) {
|
|
2355
|
+
const scriptSrc = scriptMatch[1].replace(/^\//, "");
|
|
2356
|
+
const absoluteScriptPath = resolve(dirname(htmlFilePath), scriptSrc);
|
|
2357
|
+
if (existsSync(absoluteScriptPath)) entries.push(absoluteScriptPath);
|
|
2358
|
+
}
|
|
2359
|
+
} catch {}
|
|
2360
|
+
return entries;
|
|
2361
|
+
};
|
|
2362
|
+
const ANGULAR_ENTRY_KEYS = [
|
|
2363
|
+
"main",
|
|
2364
|
+
"polyfills",
|
|
2365
|
+
"styles"
|
|
2366
|
+
];
|
|
2367
|
+
const extractAngularEntryPoints = (directory) => {
|
|
2368
|
+
const entries = [];
|
|
2369
|
+
const angularJsonPaths = fg.sync(["angular.json", ".angular-cli.json"], {
|
|
2370
|
+
cwd: directory,
|
|
2371
|
+
absolute: true,
|
|
2372
|
+
onlyFiles: true
|
|
2373
|
+
});
|
|
2374
|
+
for (const angularJsonPath of angularJsonPaths) try {
|
|
2375
|
+
const content = readFileSync(angularJsonPath, "utf-8");
|
|
2376
|
+
const projects = JSON.parse(content).projects ?? {};
|
|
2377
|
+
const angularDir = angularJsonPath.replace(/\/[^/]+$/, "");
|
|
2378
|
+
for (const projectConfig of Object.values(projects)) {
|
|
2379
|
+
const projectRecord = projectConfig;
|
|
2380
|
+
const architect = projectRecord.architect;
|
|
2381
|
+
if (architect) for (const targetConfig of Object.values(architect)) {
|
|
2382
|
+
const options = targetConfig.options;
|
|
2383
|
+
if (!options) continue;
|
|
2384
|
+
for (const entryKey of ANGULAR_ENTRY_KEYS) {
|
|
2385
|
+
const entryValue = options[entryKey];
|
|
2386
|
+
if (typeof entryValue === "string") {
|
|
2387
|
+
const absolutePath = resolve(angularDir, entryValue);
|
|
2388
|
+
if (existsSync(absolutePath)) entries.push(absolutePath);
|
|
2389
|
+
}
|
|
2390
|
+
if (Array.isArray(entryValue)) {
|
|
2391
|
+
for (const entryItem of entryValue) if (typeof entryItem === "string") {
|
|
2392
|
+
const absolutePath = resolve(angularDir, entryItem);
|
|
2393
|
+
if (existsSync(absolutePath)) entries.push(absolutePath);
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
const projectDir = resolve(angularDir, typeof projectRecord.root === "string" ? projectRecord.root : "");
|
|
2399
|
+
const ngPackagePaths = fg.sync(["ng-package.json", "**/ng-package.json"], {
|
|
2400
|
+
cwd: projectDir,
|
|
2401
|
+
absolute: true,
|
|
2402
|
+
onlyFiles: true,
|
|
2403
|
+
deep: 2,
|
|
2404
|
+
ignore: ["**/node_modules/**"]
|
|
2405
|
+
});
|
|
2406
|
+
for (const ngPackagePath of ngPackagePaths) try {
|
|
2407
|
+
const ngContent = readFileSync(ngPackagePath, "utf-8");
|
|
2408
|
+
const ngPackage = JSON.parse(ngContent);
|
|
2409
|
+
const ngDir = ngPackagePath.replace(/\/[^/]+$/, "");
|
|
2410
|
+
const libEntry = ngPackage?.lib?.entryFile;
|
|
2411
|
+
if (typeof libEntry === "string") {
|
|
2412
|
+
const absoluteEntry = resolve(ngDir, libEntry);
|
|
2413
|
+
if (existsSync(absoluteEntry)) entries.push(absoluteEntry);
|
|
2414
|
+
}
|
|
2415
|
+
} catch {}
|
|
2416
|
+
}
|
|
2417
|
+
} catch {}
|
|
2418
|
+
return entries;
|
|
2419
|
+
};
|
|
2420
|
+
const PLUGIN_FILE_ARGUMENT_PATTERN = /(?:createNextIntlPlugin|createMDX|withContentlayer|withPlaiceholder)\s*\(\s*['"]([^'"]+)['"]/g;
|
|
2421
|
+
const NEXT_INTL_IMPORT_PATTERN = /createNextIntlPlugin/;
|
|
2422
|
+
const NEXT_INTL_DEFAULT_PATHS = [
|
|
2423
|
+
"src/i18n/request.ts",
|
|
2424
|
+
"src/i18n/request.tsx",
|
|
2425
|
+
"src/i18n/request.js",
|
|
2426
|
+
"i18n/request.ts",
|
|
2427
|
+
"i18n/request.tsx",
|
|
2428
|
+
"i18n/request.js",
|
|
2429
|
+
"i18n.ts",
|
|
2430
|
+
"i18n.tsx"
|
|
2431
|
+
];
|
|
2432
|
+
const extractNextConfigPluginFiles = (directory) => {
|
|
2433
|
+
const entries = [];
|
|
2434
|
+
const nextConfigPaths = fg.sync(["next.config.{ts,js,mjs,mts}"], {
|
|
2435
|
+
cwd: directory,
|
|
2436
|
+
absolute: true,
|
|
2437
|
+
onlyFiles: true,
|
|
2438
|
+
ignore: ["**/node_modules/**"]
|
|
2439
|
+
});
|
|
2440
|
+
for (const configPath of nextConfigPaths) try {
|
|
2441
|
+
const content = readFileSync(configPath, "utf-8");
|
|
2442
|
+
const configDirectory = configPath.replace(/\/[^/]+$/, "");
|
|
2443
|
+
let pluginMatch;
|
|
2444
|
+
PLUGIN_FILE_ARGUMENT_PATTERN.lastIndex = 0;
|
|
2445
|
+
let didMatchNextIntlWithPath = false;
|
|
2446
|
+
while ((pluginMatch = PLUGIN_FILE_ARGUMENT_PATTERN.exec(content)) !== null) {
|
|
2447
|
+
const filePath = pluginMatch[1];
|
|
2448
|
+
const absolutePath = resolve(configDirectory, filePath);
|
|
2449
|
+
if (existsSync(absolutePath)) entries.push(absolutePath);
|
|
2450
|
+
if (pluginMatch[0].includes("createNextIntlPlugin")) didMatchNextIntlWithPath = true;
|
|
2451
|
+
}
|
|
2452
|
+
if (!didMatchNextIntlWithPath && NEXT_INTL_IMPORT_PATTERN.test(content)) for (const defaultPath of NEXT_INTL_DEFAULT_PATHS) {
|
|
2453
|
+
const absolutePath = resolve(configDirectory, defaultPath);
|
|
2454
|
+
if (existsSync(absolutePath)) {
|
|
2455
|
+
entries.push(absolutePath);
|
|
2456
|
+
break;
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
} catch {}
|
|
2460
|
+
return entries;
|
|
2461
|
+
};
|
|
2462
|
+
const VITEST_INCLUDE_ITEM_PATTERN = /['"]([^'"]+)['"]/g;
|
|
2463
|
+
const COVERAGE_BLOCK_PATTERN = /coverage\s*:\s*\{/g;
|
|
2464
|
+
const TEST_MATCH_ARRAY_PATTERN = /testMatch\s*:\s*\[([^\]]*)\]/;
|
|
2465
|
+
const STRING_LITERAL_PATTERN = /['"]([^'"]+)['"]/g;
|
|
2466
|
+
const extractJestTestMatchPatterns = (directory) => {
|
|
2467
|
+
const configPaths = fg.sync(["jest.config.{ts,js,mjs,cjs}"], {
|
|
2468
|
+
cwd: directory,
|
|
2469
|
+
absolute: true,
|
|
2470
|
+
onlyFiles: true,
|
|
2471
|
+
ignore: ["**/node_modules/**"]
|
|
2472
|
+
});
|
|
2473
|
+
if (configPaths.length === 0) {
|
|
2474
|
+
try {
|
|
2475
|
+
const packageContent = readFileSync(join(directory, "package.json"), "utf-8");
|
|
2476
|
+
const packageJson = JSON.parse(packageContent);
|
|
2477
|
+
if (packageJson.jest?.testMatch) return convertJestTestMatchToGlobs(packageJson.jest.testMatch);
|
|
2478
|
+
} catch {}
|
|
2479
|
+
return [];
|
|
2480
|
+
}
|
|
2481
|
+
for (const configPath of configPaths) try {
|
|
2482
|
+
const content = readFileSync(configPath, "utf-8");
|
|
2483
|
+
const testMatchMatch = TEST_MATCH_ARRAY_PATTERN.exec(content);
|
|
2484
|
+
if (!testMatchMatch) continue;
|
|
2485
|
+
const arrayContent = testMatchMatch[1];
|
|
2486
|
+
const patterns = [];
|
|
2487
|
+
STRING_LITERAL_PATTERN.lastIndex = 0;
|
|
2488
|
+
let itemMatch;
|
|
2489
|
+
while ((itemMatch = STRING_LITERAL_PATTERN.exec(arrayContent)) !== null) patterns.push(itemMatch[1]);
|
|
2490
|
+
if (patterns.length > 0) return convertJestTestMatchToGlobs(patterns);
|
|
2491
|
+
} catch {}
|
|
2492
|
+
return [];
|
|
2493
|
+
};
|
|
2494
|
+
const convertJestTestMatchToGlobs = (patterns) => {
|
|
2495
|
+
return patterns.map((pattern) => {
|
|
2496
|
+
let converted = pattern.replace(/<rootDir>\/?/g, "");
|
|
2497
|
+
converted = converted.replace(/\?\(\*\.\)/g, "*.");
|
|
2498
|
+
converted = converted.replace(/\?\(([^)]+)\)/g, (_, group) => {
|
|
2499
|
+
return `{${[...group.includes("|") ? group.split("|") : [group], ""].join(",")}}`;
|
|
2500
|
+
});
|
|
2501
|
+
converted = converted.replace(/\+\(([^)]+)\)/g, (_, group) => {
|
|
2502
|
+
return group.includes("|") ? `{${group.replace(/\|/g, ",")}}` : group;
|
|
2503
|
+
});
|
|
2504
|
+
converted = converted.replace(/\(([^)]+)\)/g, (_, group) => {
|
|
2505
|
+
return group.includes("|") ? `{${group.replace(/\|/g, ",")}}` : group;
|
|
2506
|
+
});
|
|
2507
|
+
return converted;
|
|
2508
|
+
});
|
|
2509
|
+
};
|
|
2510
|
+
const extractVitestIncludePatterns = (directory) => {
|
|
2511
|
+
const configPaths = fg.sync(["vitest.config.{ts,js,mts,mjs}", "vitest.web.config.{ts,js,mts,mjs}"], {
|
|
2512
|
+
cwd: directory,
|
|
2513
|
+
absolute: true,
|
|
2514
|
+
onlyFiles: true,
|
|
2515
|
+
ignore: ["**/node_modules/**"]
|
|
2516
|
+
});
|
|
2517
|
+
const patterns = [];
|
|
2518
|
+
for (const configPath of configPaths) try {
|
|
2519
|
+
const content = readFileSync(configPath, "utf-8");
|
|
2520
|
+
const coverageBlockRanges = findNestedBlockRanges(content, COVERAGE_BLOCK_PATTERN);
|
|
2521
|
+
const includePattern = /include\s*:\s*\[([^\]]*)\]/g;
|
|
2522
|
+
includePattern.lastIndex = 0;
|
|
2523
|
+
let includeMatch;
|
|
2524
|
+
while ((includeMatch = includePattern.exec(content)) !== null) {
|
|
2525
|
+
const matchStart = includeMatch.index;
|
|
2526
|
+
if (coverageBlockRanges.some(([blockStart, blockEnd]) => matchStart > blockStart && matchStart < blockEnd)) continue;
|
|
2527
|
+
const arrayContent = includeMatch[1];
|
|
2528
|
+
VITEST_INCLUDE_ITEM_PATTERN.lastIndex = 0;
|
|
2529
|
+
let itemMatch;
|
|
2530
|
+
while ((itemMatch = VITEST_INCLUDE_ITEM_PATTERN.exec(arrayContent)) !== null) patterns.push(itemMatch[1]);
|
|
2531
|
+
}
|
|
2532
|
+
} catch {}
|
|
2533
|
+
return patterns;
|
|
2534
|
+
};
|
|
2535
|
+
const findNestedBlockRanges = (content, blockStartPattern) => {
|
|
2536
|
+
const ranges = [];
|
|
2537
|
+
blockStartPattern.lastIndex = 0;
|
|
2538
|
+
let blockMatch;
|
|
2539
|
+
while ((blockMatch = blockStartPattern.exec(content)) !== null) {
|
|
2540
|
+
const openBraceIndex = content.indexOf("{", blockMatch.index);
|
|
2541
|
+
if (openBraceIndex === -1) continue;
|
|
2542
|
+
let braceDepth = 1;
|
|
2543
|
+
let position = openBraceIndex + 1;
|
|
2544
|
+
while (position < content.length && braceDepth > 0) {
|
|
2545
|
+
if (content[position] === "{") braceDepth++;
|
|
2546
|
+
if (content[position] === "}") braceDepth--;
|
|
2547
|
+
position++;
|
|
2548
|
+
}
|
|
2549
|
+
ranges.push([blockMatch.index, position]);
|
|
2550
|
+
}
|
|
2551
|
+
return ranges;
|
|
2552
|
+
};
|
|
2553
|
+
const SETUP_FILES_PATTERN = /(?:setupFiles|setupFilesAfterEnv|globalSetup|globalTeardown)\s*:\s*(?:\[([^\]]*)\]|['"]([^'"]+)['"])/gs;
|
|
2554
|
+
const SETUP_FILE_PATH_PATTERN = /['"]([^'"]+)['"]/g;
|
|
2555
|
+
const extractTestSetupFiles = (directory) => {
|
|
2556
|
+
const entries = [];
|
|
2557
|
+
const configPaths = fg.sync([
|
|
2558
|
+
"vitest.config.{ts,js,mts,mjs}",
|
|
2559
|
+
"vitest.web.config.{ts,js,mts,mjs}",
|
|
2560
|
+
"vite.config.{ts,js,mts,mjs}",
|
|
2561
|
+
"jest.config.{ts,js,mjs,cjs}",
|
|
2562
|
+
"**/vitest.config.{ts,js,mts,mjs}"
|
|
2563
|
+
], {
|
|
2564
|
+
cwd: directory,
|
|
2565
|
+
absolute: true,
|
|
2566
|
+
onlyFiles: true,
|
|
2567
|
+
ignore: ["**/node_modules/**"],
|
|
2568
|
+
deep: 3
|
|
2569
|
+
});
|
|
2570
|
+
for (const configPath of configPaths) try {
|
|
2571
|
+
const content = readFileSync(configPath, "utf-8");
|
|
2572
|
+
const configDirectory = configPath.replace(/\/[^/]+$/, "");
|
|
2573
|
+
let setupMatch;
|
|
2574
|
+
SETUP_FILES_PATTERN.lastIndex = 0;
|
|
2575
|
+
while ((setupMatch = SETUP_FILES_PATTERN.exec(content)) !== null) {
|
|
2576
|
+
const arrayContent = setupMatch[1];
|
|
2577
|
+
const singleValue = setupMatch[2];
|
|
2578
|
+
if (singleValue) {
|
|
2579
|
+
const absolutePath = resolve(configDirectory, singleValue);
|
|
2580
|
+
if (existsSync(absolutePath)) entries.push(absolutePath);
|
|
2581
|
+
}
|
|
2582
|
+
if (arrayContent) {
|
|
2583
|
+
let pathMatch;
|
|
2584
|
+
SETUP_FILE_PATH_PATTERN.lastIndex = 0;
|
|
2585
|
+
while ((pathMatch = SETUP_FILE_PATH_PATTERN.exec(arrayContent)) !== null) {
|
|
2586
|
+
const absolutePath = resolve(configDirectory, pathMatch[1]);
|
|
2587
|
+
if (existsSync(absolutePath)) entries.push(absolutePath);
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
} catch {}
|
|
2592
|
+
return entries;
|
|
2593
|
+
};
|
|
2594
|
+
const IMPORTABLE_EXTENSION_SET = new Set(SOURCE_EXTENSIONS$3.map((extension) => `.${extension}`));
|
|
2595
|
+
const isImportableSourceFile = (filePath) => IMPORTABLE_EXTENSION_SET.has(filePath.slice(filePath.lastIndexOf(".")));
|
|
2596
|
+
const expandWildcardExportPattern = (pattern, rootDir) => {
|
|
2597
|
+
const normalized = pattern.startsWith("./") ? pattern.slice(2) : pattern;
|
|
2598
|
+
return fg.sync(normalized, {
|
|
2599
|
+
cwd: rootDir,
|
|
2600
|
+
absolute: true,
|
|
2601
|
+
onlyFiles: true,
|
|
2602
|
+
ignore: ["**/node_modules/**"]
|
|
2603
|
+
}).filter(isImportableSourceFile);
|
|
2604
|
+
};
|
|
2605
|
+
const collectExportPaths = (exportValue, rootDir, entries) => {
|
|
2606
|
+
if (typeof exportValue === "string") {
|
|
2607
|
+
if (exportValue.includes("*")) {
|
|
2608
|
+
const expandedFiles = expandWildcardExportPattern(exportValue, rootDir);
|
|
2609
|
+
entries.push(...expandedFiles);
|
|
2610
|
+
return;
|
|
2611
|
+
}
|
|
2612
|
+
entries.push(resolveEntryPath(exportValue, rootDir));
|
|
2613
|
+
return;
|
|
2614
|
+
}
|
|
2615
|
+
if (typeof exportValue !== "object" || exportValue === null) return;
|
|
2616
|
+
for (const [, nestedValue] of Object.entries(exportValue)) collectExportPaths(nestedValue, rootDir, entries);
|
|
2617
|
+
};
|
|
2618
|
+
const TEST_RUNNER_DEFINITIONS = [
|
|
2619
|
+
{
|
|
2620
|
+
enablers: [
|
|
2621
|
+
"vitest",
|
|
2622
|
+
"@vitest/runner",
|
|
2623
|
+
"vite-plus"
|
|
2624
|
+
],
|
|
2625
|
+
configFileActivators: [
|
|
2626
|
+
"vitest.config.ts",
|
|
2627
|
+
"vitest.config.js",
|
|
2628
|
+
"vitest.config.mts",
|
|
2629
|
+
"vitest.config.mjs"
|
|
2630
|
+
],
|
|
2631
|
+
entryPatterns: [
|
|
2632
|
+
"**/*.test.{ts,tsx,js,jsx}",
|
|
2633
|
+
"**/*.spec.{ts,tsx,js,jsx}",
|
|
2634
|
+
"**/__tests__/**/*.{ts,tsx,js,jsx}",
|
|
2635
|
+
"**/*.bench.{ts,tsx,js,jsx}"
|
|
2636
|
+
],
|
|
2637
|
+
fixturePatterns: ["**/__fixtures__/**/*.{ts,tsx,js,jsx,json}", "**/fixtures/**/*.{ts,tsx,js,jsx,json}"],
|
|
2638
|
+
alwaysUsed: [
|
|
2639
|
+
"vitest.config.{ts,js,mts,mjs}",
|
|
2640
|
+
"vitest.setup.{ts,js}",
|
|
2641
|
+
"vitest.workspace.{ts,js}",
|
|
2642
|
+
"**/src/setupTests.{ts,tsx,js,jsx}",
|
|
2643
|
+
"**/src/test-setup.{ts,tsx,js,jsx}"
|
|
2644
|
+
]
|
|
2645
|
+
},
|
|
2646
|
+
{
|
|
2647
|
+
enablers: [
|
|
2648
|
+
"jest",
|
|
2649
|
+
"@jest/core",
|
|
2650
|
+
"ts-jest"
|
|
2651
|
+
],
|
|
2652
|
+
configFileActivators: [
|
|
2653
|
+
"jest.config.ts",
|
|
2654
|
+
"jest.config.js",
|
|
2655
|
+
"jest.config.mjs",
|
|
2656
|
+
"jest.config.cjs"
|
|
2657
|
+
],
|
|
2658
|
+
entryPatterns: [
|
|
2659
|
+
"**/*.test.{ts,tsx,js,jsx}",
|
|
2660
|
+
"**/*.spec.{ts,tsx,js,jsx}",
|
|
2661
|
+
"**/__tests__/**/*.{ts,tsx,js,jsx}",
|
|
2662
|
+
"**/__mocks__/**/*.{ts,tsx,js,jsx,mjs,cjs}"
|
|
2663
|
+
],
|
|
2664
|
+
fixturePatterns: ["**/__fixtures__/**/*.{ts,tsx,js,jsx,json}", "**/fixtures/**/*.{ts,tsx,js,jsx,json}"],
|
|
2665
|
+
alwaysUsed: ["jest.config.{ts,js,mjs,cjs}", "jest.setup.{ts,js,tsx,jsx}"]
|
|
2666
|
+
},
|
|
2667
|
+
{
|
|
2668
|
+
enablers: ["@playwright/test", "playwright"],
|
|
2669
|
+
configFileActivators: ["playwright.config.ts", "playwright.config.js"],
|
|
2670
|
+
entryPatterns: [
|
|
2671
|
+
"**/*.spec.{ts,tsx,js,jsx}",
|
|
2672
|
+
"**/*.test.{ts,tsx,js,jsx}",
|
|
2673
|
+
"tests/**/*.{ts,tsx,js,jsx}",
|
|
2674
|
+
"e2e/**/*.{ts,tsx,js,jsx}"
|
|
2675
|
+
],
|
|
2676
|
+
fixturePatterns: ["**/fixtures/**/*.{ts,tsx,js,jsx,json}"],
|
|
2677
|
+
alwaysUsed: ["playwright.config.{ts,js}"]
|
|
2678
|
+
},
|
|
2679
|
+
{
|
|
2680
|
+
enablers: ["mocha"],
|
|
2681
|
+
configFileActivators: [
|
|
2682
|
+
".mocharc.js",
|
|
2683
|
+
".mocharc.yaml",
|
|
2684
|
+
".mocharc.yml",
|
|
2685
|
+
".mocharc.json"
|
|
2686
|
+
],
|
|
2687
|
+
entryPatterns: [
|
|
2688
|
+
"test/**/*.{ts,tsx,js,jsx}",
|
|
2689
|
+
"tests/**/*.{ts,tsx,js,jsx}",
|
|
2690
|
+
"spec/**/*.{ts,tsx,js,jsx}",
|
|
2691
|
+
"**/*.test.{ts,tsx,js,jsx}",
|
|
2692
|
+
"**/*.spec.{ts,tsx,js,jsx}"
|
|
2693
|
+
],
|
|
2694
|
+
fixturePatterns: [],
|
|
2695
|
+
alwaysUsed: [".mocharc.*"]
|
|
2696
|
+
},
|
|
2697
|
+
{
|
|
2698
|
+
enablers: ["ava", "@ava/typescript"],
|
|
2699
|
+
configFileActivators: [
|
|
2700
|
+
"ava.config.js",
|
|
2701
|
+
"ava.config.cjs",
|
|
2702
|
+
"ava.config.mjs"
|
|
2703
|
+
],
|
|
2704
|
+
entryPatterns: [
|
|
2705
|
+
"test/**/*.{ts,tsx,js,jsx}",
|
|
2706
|
+
"tests/**/*.{ts,tsx,js,jsx}",
|
|
2707
|
+
"**/*.test.{ts,tsx,js,jsx}",
|
|
2708
|
+
"**/*.spec.{ts,tsx,js,jsx}"
|
|
2709
|
+
],
|
|
2710
|
+
fixturePatterns: [],
|
|
2711
|
+
alwaysUsed: ["ava.config.{js,cjs,mjs}"]
|
|
2712
|
+
},
|
|
2713
|
+
{
|
|
2714
|
+
enablers: ["cypress"],
|
|
2715
|
+
configFileActivators: ["cypress.config.ts", "cypress.config.js"],
|
|
2716
|
+
entryPatterns: [
|
|
2717
|
+
"**/*.cy.{ts,tsx,js,jsx}",
|
|
2718
|
+
"cypress/**/*.{ts,tsx,js,jsx}",
|
|
2719
|
+
"cypress/support/**/*.{ts,js}"
|
|
2720
|
+
],
|
|
2721
|
+
fixturePatterns: ["**/fixtures/**/*.{ts,tsx,js,jsx,json}"],
|
|
2722
|
+
alwaysUsed: ["cypress.config.{ts,js}", "cypress.config.*.{ts,js}"]
|
|
2723
|
+
}
|
|
2724
|
+
];
|
|
2725
|
+
const TOOLING_PLUGIN_DEFINITIONS = [
|
|
2726
|
+
{
|
|
2727
|
+
enablers: ["storybook"],
|
|
2728
|
+
enablerPrefixes: ["@storybook/"],
|
|
2729
|
+
entryPatterns: ["**/*.stories.{ts,tsx,js,jsx,mdx}", ".storybook/**/*.{ts,tsx,js,jsx}"],
|
|
2730
|
+
alwaysUsed: [
|
|
2731
|
+
".storybook/main.{ts,js,mjs,cjs}",
|
|
2732
|
+
".storybook/preview.{ts,tsx,js,jsx}",
|
|
2733
|
+
".storybook/manager.{ts,tsx,js,jsx}"
|
|
2734
|
+
]
|
|
2735
|
+
},
|
|
2736
|
+
{
|
|
2737
|
+
enablers: ["msw"],
|
|
2738
|
+
enablerPrefixes: [],
|
|
2739
|
+
entryPatterns: [
|
|
2740
|
+
"mocks/**/*.{ts,tsx,js,jsx}",
|
|
2741
|
+
"src/mocks/**/*.{ts,tsx,js,jsx}",
|
|
2742
|
+
"**/mocks/**/*.{ts,tsx,js,jsx}"
|
|
2743
|
+
],
|
|
2744
|
+
alwaysUsed: []
|
|
2745
|
+
},
|
|
2746
|
+
{
|
|
2747
|
+
enablers: ["typeorm"],
|
|
2748
|
+
enablerPrefixes: [],
|
|
2749
|
+
entryPatterns: [
|
|
2750
|
+
"migrations/**/*.{ts,js}",
|
|
2751
|
+
"src/migrations/**/*.{ts,js}",
|
|
2752
|
+
"src/migration/**/*.{ts,js}",
|
|
2753
|
+
"migration/**/*.{ts,js}",
|
|
2754
|
+
"src/entity/**/*.{ts,js}"
|
|
2755
|
+
],
|
|
2756
|
+
alwaysUsed: ["ormconfig.{ts,js,json}"]
|
|
2757
|
+
},
|
|
2758
|
+
{
|
|
2759
|
+
enablers: ["knex"],
|
|
2760
|
+
enablerPrefixes: [],
|
|
2761
|
+
entryPatterns: ["migrations/**/*.{ts,js}", "seeds/**/*.{ts,js}"],
|
|
2762
|
+
alwaysUsed: ["knexfile.{ts,js}"]
|
|
2763
|
+
},
|
|
2764
|
+
{
|
|
2765
|
+
enablers: ["drizzle-orm"],
|
|
2766
|
+
enablerPrefixes: [],
|
|
2767
|
+
entryPatterns: ["drizzle/**/*.{ts,js}"],
|
|
2768
|
+
alwaysUsed: ["drizzle.config.{ts,js,mjs}"]
|
|
2769
|
+
},
|
|
2770
|
+
{
|
|
2771
|
+
enablers: ["kysely"],
|
|
2772
|
+
enablerPrefixes: [],
|
|
2773
|
+
entryPatterns: ["migrations/**/*.{ts,js}", "src/migrations/**/*.{ts,js}"],
|
|
2774
|
+
alwaysUsed: []
|
|
2775
|
+
},
|
|
2776
|
+
{
|
|
2777
|
+
enablers: ["prisma", "@prisma/client"],
|
|
2778
|
+
enablerPrefixes: [],
|
|
2779
|
+
entryPatterns: ["prisma/**/*.{ts,js}", "prisma/seed.{ts,js}"],
|
|
2780
|
+
alwaysUsed: [
|
|
2781
|
+
"prisma/schema.prisma",
|
|
2782
|
+
"schema.prisma",
|
|
2783
|
+
"prisma/schema/*.prisma",
|
|
2784
|
+
"prisma.config.{ts,mts,cts,js,mjs,cjs}",
|
|
2785
|
+
".config/prisma.{ts,mts,cts,js,mjs,cjs}"
|
|
2786
|
+
]
|
|
2787
|
+
},
|
|
2788
|
+
{
|
|
2789
|
+
enablers: ["@nestjs/core"],
|
|
2790
|
+
enablerPrefixes: ["@nestjs/"],
|
|
2791
|
+
entryPatterns: [
|
|
2792
|
+
"src/main.ts",
|
|
2793
|
+
"src/**/*.module.ts",
|
|
2794
|
+
"src/**/*.controller.ts",
|
|
2795
|
+
"src/**/*.service.ts",
|
|
2796
|
+
"src/**/*.guard.ts",
|
|
2797
|
+
"src/**/*.interceptor.ts",
|
|
2798
|
+
"src/**/*.pipe.ts",
|
|
2799
|
+
"src/**/*.filter.ts",
|
|
2800
|
+
"src/**/*.middleware.ts",
|
|
2801
|
+
"src/**/*.decorator.ts",
|
|
2802
|
+
"src/**/*.gateway.ts",
|
|
2803
|
+
"src/**/*.resolver.ts"
|
|
2804
|
+
],
|
|
2805
|
+
alwaysUsed: ["nest-cli.json"]
|
|
2806
|
+
},
|
|
2807
|
+
{
|
|
2808
|
+
enablers: ["wrangler"],
|
|
2809
|
+
enablerPrefixes: ["@cloudflare/"],
|
|
2810
|
+
entryPatterns: [
|
|
2811
|
+
"src/index.{ts,js}",
|
|
2812
|
+
"src/worker.{ts,js}",
|
|
2813
|
+
"functions/**/*.{ts,js}"
|
|
2814
|
+
],
|
|
2815
|
+
alwaysUsed: []
|
|
2816
|
+
},
|
|
2817
|
+
{
|
|
2818
|
+
enablers: ["gatsby"],
|
|
2819
|
+
enablerPrefixes: ["gatsby-"],
|
|
2820
|
+
entryPatterns: [
|
|
2821
|
+
"src/pages/**/*.{ts,tsx,js,jsx}",
|
|
2822
|
+
"src/templates/**/*.{ts,tsx,js,jsx}",
|
|
2823
|
+
"src/api/**/*.{ts,js}"
|
|
2824
|
+
],
|
|
2825
|
+
alwaysUsed: [
|
|
2826
|
+
"gatsby-config.{ts,js,mjs}",
|
|
2827
|
+
"gatsby-node.{ts,js,mjs}",
|
|
2828
|
+
"gatsby-browser.{ts,tsx,js,jsx}",
|
|
2829
|
+
"gatsby-ssr.{ts,tsx,js,jsx}"
|
|
2830
|
+
]
|
|
2831
|
+
},
|
|
2832
|
+
{
|
|
2833
|
+
enablers: ["@angular/core"],
|
|
2834
|
+
enablerPrefixes: ["@angular/"],
|
|
2835
|
+
entryPatterns: [
|
|
2836
|
+
"src/main.ts",
|
|
2837
|
+
"src/app/**/*.ts",
|
|
2838
|
+
"src/environments/**/*.ts",
|
|
2839
|
+
"src/polyfills.ts",
|
|
2840
|
+
"src/test.ts"
|
|
2841
|
+
],
|
|
2842
|
+
alwaysUsed: ["angular.json", "**/karma.conf.js"]
|
|
2843
|
+
},
|
|
2844
|
+
{
|
|
2845
|
+
enablers: ["react-scripts", "react-app-rewired"],
|
|
2846
|
+
enablerPrefixes: [],
|
|
2847
|
+
entryPatterns: ["src/index.{ts,tsx,js,jsx}"],
|
|
2848
|
+
alwaysUsed: [
|
|
2849
|
+
"src/setupTests.{ts,tsx,js,jsx}",
|
|
2850
|
+
"src/reportWebVitals.{ts,tsx,js,jsx}",
|
|
2851
|
+
"src/react-app-env.d.ts"
|
|
2852
|
+
]
|
|
2853
|
+
},
|
|
2854
|
+
{
|
|
2855
|
+
enablers: [
|
|
2856
|
+
"@remix-run/node",
|
|
2857
|
+
"@remix-run/react",
|
|
2858
|
+
"@remix-run/cloudflare",
|
|
2859
|
+
"@react-router/node",
|
|
2860
|
+
"@react-router/serve",
|
|
2861
|
+
"@react-router/dev"
|
|
2862
|
+
],
|
|
2863
|
+
enablerPrefixes: ["@remix-run/", "@react-router/"],
|
|
2864
|
+
entryPatterns: [
|
|
2865
|
+
"app/routes/**/*.{ts,tsx,js,jsx}",
|
|
2866
|
+
"app/root.{ts,tsx,js,jsx}",
|
|
2867
|
+
"app/entry.client.{ts,tsx,js,jsx}",
|
|
2868
|
+
"app/entry.server.{ts,tsx,js,jsx}",
|
|
2869
|
+
"app/routes.{ts,js,mts,mjs}",
|
|
2870
|
+
"src/routes.{ts,js,mts,mjs}"
|
|
2871
|
+
],
|
|
2872
|
+
alwaysUsed: ["react-router.config.{ts,js,mjs}", "remix.config.{ts,js,mjs}"]
|
|
2873
|
+
},
|
|
2874
|
+
{
|
|
2875
|
+
enablers: ["@docusaurus/core"],
|
|
2876
|
+
enablerPrefixes: ["@docusaurus/"],
|
|
2877
|
+
entryPatterns: [
|
|
2878
|
+
"**/*.{md,mdx}",
|
|
2879
|
+
"src/pages/**/*.{ts,tsx,js,jsx}",
|
|
2880
|
+
"src/theme/**/*.{ts,tsx,js,jsx}",
|
|
2881
|
+
"src/theme/**/index.{ts,tsx,js,jsx}",
|
|
2882
|
+
"plugins/**/*.{ts,js,mjs}"
|
|
2883
|
+
],
|
|
2884
|
+
alwaysUsed: [
|
|
2885
|
+
"docusaurus.config.{ts,js,mjs}",
|
|
2886
|
+
"sidebars.{ts,js,mjs,cjs}",
|
|
2887
|
+
"sidebar*.{ts,js,mjs,cjs}",
|
|
2888
|
+
"*-sidebar.{ts,js,mjs,cjs}",
|
|
2889
|
+
"*-sidebars.{ts,js,mjs,cjs}",
|
|
2890
|
+
"*Sidebar*.{ts,js,mjs,cjs}",
|
|
2891
|
+
"*sidebar*.{ts,js,mjs,cjs}"
|
|
2892
|
+
],
|
|
2893
|
+
contentIgnorePatterns: ["versioned_sidebars/**"]
|
|
2894
|
+
},
|
|
2895
|
+
{
|
|
2896
|
+
enablers: ["eslint", "@eslint/js"],
|
|
2897
|
+
enablerPrefixes: [],
|
|
2898
|
+
entryPatterns: [],
|
|
2899
|
+
alwaysUsed: ["eslint.config.{js,mjs,cjs,ts,mts,cts}", ".eslintrc.{js,cjs,mjs,json,yaml,yml}"]
|
|
2900
|
+
},
|
|
2901
|
+
{
|
|
2902
|
+
enablers: ["prettier"],
|
|
2903
|
+
enablerPrefixes: [],
|
|
2904
|
+
entryPatterns: [],
|
|
2905
|
+
alwaysUsed: [".prettierrc.{js,cjs,mjs,json,yaml,yml}", "prettier.config.{js,mjs,cjs,ts}"]
|
|
2906
|
+
},
|
|
2907
|
+
{
|
|
2908
|
+
enablers: ["tailwindcss", "@tailwindcss/postcss"],
|
|
2909
|
+
enablerPrefixes: [],
|
|
2910
|
+
entryPatterns: [],
|
|
2911
|
+
alwaysUsed: ["tailwind.config.{ts,js,cjs,mjs}"]
|
|
2912
|
+
},
|
|
2913
|
+
{
|
|
2914
|
+
enablers: ["postcss"],
|
|
2915
|
+
enablerPrefixes: [],
|
|
2916
|
+
entryPatterns: [],
|
|
2917
|
+
alwaysUsed: ["postcss.config.{ts,js,cjs,mjs}"]
|
|
2918
|
+
},
|
|
2919
|
+
{
|
|
2920
|
+
enablers: ["typescript"],
|
|
2921
|
+
enablerPrefixes: [],
|
|
2922
|
+
entryPatterns: [],
|
|
2923
|
+
alwaysUsed: ["tsconfig.json", "tsconfig.*.json"]
|
|
2924
|
+
},
|
|
2925
|
+
{
|
|
2926
|
+
enablers: ["lint-staged"],
|
|
2927
|
+
enablerPrefixes: [],
|
|
2928
|
+
entryPatterns: [],
|
|
2929
|
+
alwaysUsed: [".lintstagedrc.{js,cjs,mjs,json}", "lint-staged.config.{js,mjs,cjs}"]
|
|
2930
|
+
},
|
|
2931
|
+
{
|
|
2932
|
+
enablers: ["husky"],
|
|
2933
|
+
enablerPrefixes: [],
|
|
2934
|
+
entryPatterns: [],
|
|
2935
|
+
alwaysUsed: [".husky/**/*"]
|
|
2936
|
+
},
|
|
2937
|
+
{
|
|
2938
|
+
enablers: ["@biomejs/biome"],
|
|
2939
|
+
enablerPrefixes: [],
|
|
2940
|
+
entryPatterns: [],
|
|
2941
|
+
alwaysUsed: ["biome.json", "biome.jsonc"]
|
|
2942
|
+
},
|
|
2943
|
+
{
|
|
2944
|
+
enablers: ["@commitlint/cli"],
|
|
2945
|
+
enablerPrefixes: [],
|
|
2946
|
+
entryPatterns: [],
|
|
2947
|
+
alwaysUsed: ["commitlint.config.{js,cjs,mjs,ts}", ".commitlintrc.{js,cjs,mjs,json,yaml,yml}"]
|
|
2948
|
+
},
|
|
2949
|
+
{
|
|
2950
|
+
enablers: ["semantic-release"],
|
|
2951
|
+
enablerPrefixes: [],
|
|
2952
|
+
entryPatterns: [],
|
|
2953
|
+
alwaysUsed: [".releaserc.{js,cjs,mjs,json,yaml,yml}", "release.config.{js,cjs,mjs,ts}"]
|
|
2954
|
+
},
|
|
2955
|
+
{
|
|
2956
|
+
enablers: ["@changesets/cli"],
|
|
2957
|
+
enablerPrefixes: [],
|
|
2958
|
+
entryPatterns: [],
|
|
2959
|
+
alwaysUsed: [".changeset/**/*"]
|
|
2960
|
+
},
|
|
2961
|
+
{
|
|
2962
|
+
enablers: ["next"],
|
|
2963
|
+
enablerPrefixes: [],
|
|
2964
|
+
entryPatterns: [
|
|
2965
|
+
"app/**/page.{ts,tsx,js,jsx}",
|
|
2966
|
+
"app/**/layout.{ts,tsx,js,jsx}",
|
|
2967
|
+
"app/**/loading.{ts,tsx,js,jsx}",
|
|
2968
|
+
"app/**/error.{ts,tsx,js,jsx}",
|
|
2969
|
+
"app/**/not-found.{ts,tsx,js,jsx}",
|
|
2970
|
+
"app/**/template.{ts,tsx,js,jsx}",
|
|
2971
|
+
"app/**/default.{ts,tsx,js,jsx}",
|
|
2972
|
+
"app/**/route.{ts,tsx,js,jsx}",
|
|
2973
|
+
"app/**/global-error.{ts,tsx,js,jsx}",
|
|
2974
|
+
"app/**/forbidden.{ts,tsx,js,jsx}",
|
|
2975
|
+
"app/**/unauthorized.{ts,tsx,js,jsx}",
|
|
2976
|
+
"app/global-not-found.{ts,tsx,js,jsx}",
|
|
2977
|
+
"app/**/opengraph-image.{ts,tsx,js,jsx}",
|
|
2978
|
+
"app/**/twitter-image.{ts,tsx,js,jsx}",
|
|
2979
|
+
"app/**/icon.{ts,tsx,js,jsx}",
|
|
2980
|
+
"app/**/apple-icon.{ts,tsx,js,jsx}",
|
|
2981
|
+
"app/**/manifest.{ts,tsx,js,jsx}",
|
|
2982
|
+
"app/**/sitemap.{ts,tsx,js,jsx}",
|
|
2983
|
+
"app/**/robots.{ts,tsx,js,jsx}",
|
|
2984
|
+
"pages/**/*.{ts,tsx,js,jsx}",
|
|
2985
|
+
"src/app/**/page.{ts,tsx,js,jsx}",
|
|
2986
|
+
"src/app/**/layout.{ts,tsx,js,jsx}",
|
|
2987
|
+
"src/app/**/loading.{ts,tsx,js,jsx}",
|
|
2988
|
+
"src/app/**/error.{ts,tsx,js,jsx}",
|
|
2989
|
+
"src/app/**/not-found.{ts,tsx,js,jsx}",
|
|
2990
|
+
"src/app/**/template.{ts,tsx,js,jsx}",
|
|
2991
|
+
"src/app/**/default.{ts,tsx,js,jsx}",
|
|
2992
|
+
"src/app/**/route.{ts,tsx,js,jsx}",
|
|
2993
|
+
"src/app/**/global-error.{ts,tsx,js,jsx}",
|
|
2994
|
+
"src/app/**/forbidden.{ts,tsx,js,jsx}",
|
|
2995
|
+
"src/app/**/unauthorized.{ts,tsx,js,jsx}",
|
|
2996
|
+
"src/app/global-not-found.{ts,tsx,js,jsx}",
|
|
2997
|
+
"src/app/**/opengraph-image.{ts,tsx,js,jsx}",
|
|
2998
|
+
"src/app/**/twitter-image.{ts,tsx,js,jsx}",
|
|
2999
|
+
"src/app/**/icon.{ts,tsx,js,jsx}",
|
|
3000
|
+
"src/app/**/apple-icon.{ts,tsx,js,jsx}",
|
|
3001
|
+
"src/app/**/manifest.{ts,tsx,js,jsx}",
|
|
3002
|
+
"src/app/**/sitemap.{ts,tsx,js,jsx}",
|
|
3003
|
+
"src/app/**/robots.{ts,tsx,js,jsx}",
|
|
3004
|
+
"src/pages/**/*.{ts,tsx,js,jsx}",
|
|
3005
|
+
"middleware.{ts,js}",
|
|
3006
|
+
"src/middleware.{ts,js}",
|
|
3007
|
+
"proxy.{ts,js}",
|
|
3008
|
+
"src/proxy.{ts,js}",
|
|
3009
|
+
"instrumentation.{ts,js}",
|
|
3010
|
+
"instrumentation-client.{ts,js}",
|
|
3011
|
+
"src/instrumentation.{ts,js}",
|
|
3012
|
+
"src/instrumentation-client.{ts,js}"
|
|
3013
|
+
],
|
|
3014
|
+
alwaysUsed: [
|
|
3015
|
+
"next.config.{ts,js,mjs,mts}",
|
|
3016
|
+
"next-env.d.ts",
|
|
3017
|
+
"mdx-components.{ts,tsx,js,jsx}",
|
|
3018
|
+
"src/mdx-components.{ts,tsx,js,jsx}",
|
|
3019
|
+
"src/i18n/request.{ts,js}",
|
|
3020
|
+
"src/i18n/routing.{ts,js}",
|
|
3021
|
+
"i18n/request.{ts,js}",
|
|
3022
|
+
"i18n/routing.{ts,js}"
|
|
3023
|
+
]
|
|
3024
|
+
},
|
|
3025
|
+
{
|
|
3026
|
+
enablers: [
|
|
3027
|
+
"@tanstack/react-router",
|
|
3028
|
+
"@tanstack/react-start",
|
|
3029
|
+
"@tanstack/start",
|
|
3030
|
+
"@tanstack/solid-router",
|
|
3031
|
+
"@tanstack/solid-start"
|
|
3032
|
+
],
|
|
3033
|
+
enablerPrefixes: ["@tanstack/router"],
|
|
3034
|
+
entryPatterns: [
|
|
3035
|
+
"src/routes/**/*.{ts,tsx,js,jsx}",
|
|
3036
|
+
"app/routes/**/*.{ts,tsx,js,jsx}",
|
|
3037
|
+
"src/server.{ts,tsx,js,jsx}",
|
|
3038
|
+
"src/client.{ts,tsx,js,jsx}",
|
|
3039
|
+
"src/router.{ts,tsx,js,jsx}",
|
|
3040
|
+
"src/routeTree.gen.{ts,js}"
|
|
3041
|
+
],
|
|
3042
|
+
alwaysUsed: ["tsr.config.json", "app.config.{ts,js}"]
|
|
3043
|
+
},
|
|
3044
|
+
{
|
|
3045
|
+
enablers: ["vite", "rolldown-vite"],
|
|
3046
|
+
enablerPrefixes: ["@vitejs/"],
|
|
3047
|
+
entryPatterns: [
|
|
3048
|
+
"src/main.{ts,tsx,js,jsx}",
|
|
3049
|
+
"src/index.{ts,tsx,js,jsx}",
|
|
3050
|
+
"index.html"
|
|
3051
|
+
],
|
|
3052
|
+
alwaysUsed: ["vite.config.{ts,js,mts,mjs}"]
|
|
3053
|
+
},
|
|
3054
|
+
{
|
|
3055
|
+
enablers: ["vue", "@vue/cli-service"],
|
|
3056
|
+
enablerPrefixes: ["@vue/"],
|
|
3057
|
+
entryPatterns: ["src/main.{ts,js}", "src/App.vue"],
|
|
3058
|
+
alwaysUsed: ["vue.config.{ts,js,mjs,cjs}"]
|
|
3059
|
+
},
|
|
3060
|
+
{
|
|
3061
|
+
enablers: ["nuxt", "nuxt3"],
|
|
3062
|
+
enablerPrefixes: ["@nuxt/"],
|
|
3063
|
+
entryPatterns: [
|
|
3064
|
+
"pages/**/*.vue",
|
|
3065
|
+
"layouts/**/*.vue",
|
|
3066
|
+
"components/**/*.vue",
|
|
3067
|
+
"composables/**/*.{ts,js}",
|
|
3068
|
+
"plugins/**/*.{ts,js}",
|
|
3069
|
+
"middleware/**/*.{ts,js}",
|
|
3070
|
+
"server/**/*.{ts,js}",
|
|
3071
|
+
"app.vue"
|
|
3072
|
+
],
|
|
3073
|
+
alwaysUsed: ["nuxt.config.{ts,js,mjs}"]
|
|
3074
|
+
},
|
|
3075
|
+
{
|
|
3076
|
+
enablers: ["svelte", "@sveltejs/kit"],
|
|
3077
|
+
enablerPrefixes: ["@sveltejs/"],
|
|
3078
|
+
entryPatterns: [
|
|
3079
|
+
"src/routes/**/*.svelte",
|
|
3080
|
+
"src/lib/**/*.svelte",
|
|
3081
|
+
"src/routes/**/+page.{ts,js,svelte}",
|
|
3082
|
+
"src/routes/**/+layout.{ts,js,svelte}",
|
|
3083
|
+
"src/routes/**/+server.{ts,js}"
|
|
3084
|
+
],
|
|
3085
|
+
alwaysUsed: ["svelte.config.{ts,js,mjs}"]
|
|
3086
|
+
},
|
|
3087
|
+
{
|
|
3088
|
+
enablers: ["webpack", "webpack-cli"],
|
|
3089
|
+
enablerPrefixes: [],
|
|
3090
|
+
entryPatterns: [],
|
|
3091
|
+
alwaysUsed: ["webpack.config.{ts,js,mjs,cjs}", "webpack.*.config.{ts,js,mjs,cjs}"]
|
|
3092
|
+
},
|
|
3093
|
+
{
|
|
3094
|
+
enablers: ["rollup"],
|
|
3095
|
+
enablerPrefixes: [],
|
|
3096
|
+
entryPatterns: [],
|
|
3097
|
+
alwaysUsed: ["rollup.config.{ts,js,mjs,cjs}", "rollup.*.config.{ts,js,mjs,cjs}"]
|
|
3098
|
+
},
|
|
3099
|
+
{
|
|
3100
|
+
enablers: ["@rspack/core", "@rspack/cli"],
|
|
3101
|
+
enablerPrefixes: ["@rspack/"],
|
|
3102
|
+
entryPatterns: ["src/index.{ts,tsx,js,jsx}"],
|
|
3103
|
+
alwaysUsed: ["rspack.config.{ts,js,mjs,cjs}", "rspack.*.config.{ts,js,mjs,cjs}"]
|
|
3104
|
+
},
|
|
3105
|
+
{
|
|
3106
|
+
enablers: ["@rsbuild/core"],
|
|
3107
|
+
enablerPrefixes: ["@rsbuild/"],
|
|
3108
|
+
entryPatterns: ["src/index.{ts,tsx,js,jsx}"],
|
|
3109
|
+
alwaysUsed: ["rsbuild.config.{ts,js,mjs,cjs}"]
|
|
3110
|
+
},
|
|
3111
|
+
{
|
|
3112
|
+
enablers: ["tsup"],
|
|
3113
|
+
enablerPrefixes: [],
|
|
3114
|
+
entryPatterns: [],
|
|
3115
|
+
alwaysUsed: ["tsup.config.{ts,js,cjs,mjs}"]
|
|
3116
|
+
},
|
|
3117
|
+
{
|
|
3118
|
+
enablers: ["tsdown"],
|
|
3119
|
+
enablerPrefixes: [],
|
|
3120
|
+
entryPatterns: [],
|
|
3121
|
+
alwaysUsed: ["tsdown.config.{ts,js,cjs,mjs}"]
|
|
3122
|
+
},
|
|
3123
|
+
{
|
|
3124
|
+
enablers: ["@trigger.dev/sdk"],
|
|
3125
|
+
enablerPrefixes: ["@trigger.dev/"],
|
|
3126
|
+
entryPatterns: [],
|
|
3127
|
+
alwaysUsed: ["trigger.config.{ts,js,mjs,mts}"]
|
|
3128
|
+
},
|
|
3129
|
+
{
|
|
3130
|
+
enablers: ["@swc/core"],
|
|
3131
|
+
enablerPrefixes: [],
|
|
3132
|
+
entryPatterns: [],
|
|
3133
|
+
alwaysUsed: [".swcrc"]
|
|
3134
|
+
},
|
|
3135
|
+
{
|
|
3136
|
+
enablers: ["@babel/core"],
|
|
3137
|
+
enablerPrefixes: [],
|
|
3138
|
+
entryPatterns: [],
|
|
3139
|
+
alwaysUsed: ["babel.config.{js,cjs,mjs,json}", ".babelrc.{js,cjs,mjs,json}"]
|
|
3140
|
+
},
|
|
3141
|
+
{
|
|
3142
|
+
enablers: ["sanity", "@sanity/cli"],
|
|
3143
|
+
enablerPrefixes: ["@sanity/"],
|
|
3144
|
+
entryPatterns: [],
|
|
3145
|
+
alwaysUsed: ["sanity.config.{ts,js}", "sanity.cli.{ts,js}"]
|
|
3146
|
+
},
|
|
3147
|
+
{
|
|
3148
|
+
enablers: ["astro"],
|
|
3149
|
+
enablerPrefixes: ["@astrojs/"],
|
|
3150
|
+
entryPatterns: [
|
|
3151
|
+
"src/pages/**/*.{astro,ts,tsx,js,jsx,mts,mjs,cts,cjs,md,mdx}",
|
|
3152
|
+
"src/content/**/*.{ts,js,mts,mjs,cts,cjs,md,mdx}",
|
|
3153
|
+
"src/layouts/**/*.astro",
|
|
3154
|
+
"src/middleware.{js,ts,mjs,mts,cjs,cts}",
|
|
3155
|
+
"src/middleware/index.{js,ts,mjs,mts,cjs,cts}",
|
|
3156
|
+
"src/actions/index.{js,ts,mjs,mts,cjs,cts}"
|
|
3157
|
+
],
|
|
3158
|
+
alwaysUsed: [
|
|
3159
|
+
"astro.config.{ts,js,mjs,cjs}",
|
|
3160
|
+
"src/content/config.{js,ts,mjs,mts,cjs,cts}",
|
|
3161
|
+
"src/content.config.{js,ts,mjs,mts,cjs,cts}"
|
|
3162
|
+
]
|
|
3163
|
+
},
|
|
3164
|
+
{
|
|
3165
|
+
enablers: [
|
|
3166
|
+
"i18next",
|
|
3167
|
+
"react-i18next",
|
|
3168
|
+
"vue-i18n",
|
|
3169
|
+
"next-i18next"
|
|
3170
|
+
],
|
|
3171
|
+
enablerPrefixes: [],
|
|
3172
|
+
entryPatterns: [
|
|
3173
|
+
"src/i18n.{ts,js,mjs}",
|
|
3174
|
+
"src/i18n/index.{ts,js}",
|
|
3175
|
+
"i18n.{ts,js,mjs}",
|
|
3176
|
+
"i18n/index.{ts,js}"
|
|
3177
|
+
],
|
|
3178
|
+
alwaysUsed: [
|
|
3179
|
+
"src/i18n.{ts,js,mjs}",
|
|
3180
|
+
"src/i18n/index.{ts,js}",
|
|
3181
|
+
"i18n.{ts,js,mjs}",
|
|
3182
|
+
"i18n/index.{ts,js}",
|
|
3183
|
+
"i18next.config.{js,ts,mjs}",
|
|
3184
|
+
"next-i18next.config.{js,mjs}",
|
|
3185
|
+
"locales/**/*.json",
|
|
3186
|
+
"public/locales/**/*.json",
|
|
3187
|
+
"src/locales/**/*.json"
|
|
3188
|
+
]
|
|
3189
|
+
},
|
|
3190
|
+
{
|
|
3191
|
+
enablers: ["turbo"],
|
|
3192
|
+
enablerPrefixes: [],
|
|
3193
|
+
entryPatterns: [],
|
|
3194
|
+
alwaysUsed: ["turbo.json", "turbo/generators/config.{ts,js}"]
|
|
3195
|
+
},
|
|
3196
|
+
{
|
|
3197
|
+
enablers: [
|
|
3198
|
+
"@sentry/nextjs",
|
|
3199
|
+
"@sentry/react",
|
|
3200
|
+
"@sentry/node",
|
|
3201
|
+
"@sentry/browser"
|
|
3202
|
+
],
|
|
3203
|
+
enablerPrefixes: ["@sentry/"],
|
|
3204
|
+
entryPatterns: [],
|
|
3205
|
+
alwaysUsed: [
|
|
3206
|
+
"sentry.client.config.{ts,js,mjs}",
|
|
3207
|
+
"sentry.server.config.{ts,js,mjs}",
|
|
3208
|
+
"sentry.edge.config.{ts,js,mjs}"
|
|
3209
|
+
]
|
|
3210
|
+
},
|
|
3211
|
+
{
|
|
3212
|
+
enablers: ["nodemon"],
|
|
3213
|
+
enablerPrefixes: [],
|
|
3214
|
+
entryPatterns: [],
|
|
3215
|
+
alwaysUsed: [
|
|
3216
|
+
"nodemon.json",
|
|
3217
|
+
".nodemonrc",
|
|
3218
|
+
".nodemonrc.{json,yml,yaml}"
|
|
3219
|
+
]
|
|
3220
|
+
},
|
|
3221
|
+
{
|
|
3222
|
+
enablers: ["nx"],
|
|
3223
|
+
enablerPrefixes: ["@nx/"],
|
|
3224
|
+
entryPatterns: [],
|
|
3225
|
+
alwaysUsed: ["nx.json", "**/project.json"]
|
|
3226
|
+
},
|
|
3227
|
+
{
|
|
3228
|
+
enablers: ["react-native"],
|
|
3229
|
+
enablerPrefixes: ["@react-native/", "@react-native-community/"],
|
|
3230
|
+
entryPatterns: [
|
|
3231
|
+
"index.{ts,tsx,js,jsx}",
|
|
3232
|
+
"App.{ts,tsx,js,jsx}",
|
|
3233
|
+
"src/App.{ts,tsx,js,jsx}"
|
|
3234
|
+
],
|
|
3235
|
+
alwaysUsed: [
|
|
3236
|
+
"metro.config.{ts,js}",
|
|
3237
|
+
"react-native.config.{ts,js}",
|
|
3238
|
+
"app.json"
|
|
3239
|
+
]
|
|
3240
|
+
},
|
|
3241
|
+
{
|
|
3242
|
+
enablers: ["expo"],
|
|
3243
|
+
enablerPrefixes: ["@expo/"],
|
|
3244
|
+
entryPatterns: [
|
|
3245
|
+
"App.{ts,tsx,js,jsx}",
|
|
3246
|
+
"app/_layout.{ts,tsx,js,jsx}",
|
|
3247
|
+
"app/index.{ts,tsx,js,jsx}"
|
|
3248
|
+
],
|
|
3249
|
+
alwaysUsed: ["app.json", "app.config.{ts,js}"]
|
|
3250
|
+
},
|
|
3251
|
+
{
|
|
3252
|
+
enablers: ["wrangler"],
|
|
3253
|
+
enablerPrefixes: ["@cloudflare/"],
|
|
3254
|
+
entryPatterns: [
|
|
3255
|
+
"src/index.{ts,js}",
|
|
3256
|
+
"src/worker.{ts,js}",
|
|
3257
|
+
"functions/**/*.{ts,js}"
|
|
3258
|
+
],
|
|
3259
|
+
alwaysUsed: [
|
|
3260
|
+
"wrangler.toml",
|
|
3261
|
+
"wrangler.json",
|
|
3262
|
+
"wrangler.jsonc"
|
|
3263
|
+
]
|
|
3264
|
+
},
|
|
3265
|
+
{
|
|
3266
|
+
enablers: [
|
|
3267
|
+
"electron",
|
|
3268
|
+
"electron-builder",
|
|
3269
|
+
"@electron-forge/cli",
|
|
3270
|
+
"electron-vite",
|
|
3271
|
+
"electron-webpack"
|
|
3272
|
+
],
|
|
3273
|
+
enablerPrefixes: ["@electron-forge/", "@electron/"],
|
|
3274
|
+
entryPatterns: [
|
|
3275
|
+
"src/main/**/*.{ts,tsx,js,jsx}",
|
|
3276
|
+
"src/preload/**/*.{ts,tsx,js,jsx}",
|
|
3277
|
+
"electron/main.{ts,js}"
|
|
3278
|
+
],
|
|
3279
|
+
alwaysUsed: [
|
|
3280
|
+
"electron-builder.{yml,yaml,json,json5,toml}",
|
|
3281
|
+
"forge.config.{ts,js,cjs}",
|
|
3282
|
+
"electron.vite.config.{ts,js,mjs}"
|
|
3283
|
+
]
|
|
3284
|
+
},
|
|
3285
|
+
{
|
|
3286
|
+
enablers: ["lefthook"],
|
|
3287
|
+
enablerPrefixes: [],
|
|
3288
|
+
entryPatterns: [],
|
|
3289
|
+
alwaysUsed: [
|
|
3290
|
+
"lefthook.yml",
|
|
3291
|
+
"lefthook.yaml",
|
|
3292
|
+
".lefthook.yml"
|
|
3293
|
+
]
|
|
3294
|
+
},
|
|
3295
|
+
{
|
|
3296
|
+
enablers: ["syncpack"],
|
|
3297
|
+
enablerPrefixes: [],
|
|
3298
|
+
entryPatterns: [],
|
|
3299
|
+
alwaysUsed: [
|
|
3300
|
+
".syncpackrc",
|
|
3301
|
+
".syncpackrc.{json,yaml,yml}",
|
|
3302
|
+
"syncpack.config.{js,mjs,cjs}"
|
|
3303
|
+
]
|
|
3304
|
+
},
|
|
3305
|
+
{
|
|
3306
|
+
enablers: ["@capacitor/core", "@capacitor/cli"],
|
|
3307
|
+
enablerPrefixes: ["@capacitor/"],
|
|
3308
|
+
entryPatterns: [],
|
|
3309
|
+
alwaysUsed: ["capacitor.config.{ts,js,json}"]
|
|
3310
|
+
}
|
|
3311
|
+
];
|
|
3312
|
+
const detectNodeTestRunner = (directory) => {
|
|
3313
|
+
try {
|
|
3314
|
+
const packageJsonPath = join(directory, "package.json");
|
|
3315
|
+
if (!existsSync(packageJsonPath)) return false;
|
|
3316
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
3317
|
+
const scripts = JSON.parse(content).scripts ?? {};
|
|
3318
|
+
return Object.values(scripts).some((scriptValue) => typeof scriptValue === "string" && /\bnode\b.*\s--test\b/.test(scriptValue));
|
|
3319
|
+
} catch {
|
|
3320
|
+
return false;
|
|
3321
|
+
}
|
|
3322
|
+
};
|
|
3323
|
+
const detectBunTestRunner = (directory) => {
|
|
3324
|
+
try {
|
|
3325
|
+
const packageJsonPath = join(directory, "package.json");
|
|
3326
|
+
if (!existsSync(packageJsonPath)) return false;
|
|
3327
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
3328
|
+
const scripts = JSON.parse(content).scripts ?? {};
|
|
3329
|
+
return Object.values(scripts).some((scriptValue) => typeof scriptValue === "string" && /\bbun\s+test\b/.test(scriptValue));
|
|
3330
|
+
} catch {
|
|
3331
|
+
return false;
|
|
3332
|
+
}
|
|
3333
|
+
};
|
|
3334
|
+
const discoverTestRunnerEntryPoints = (rootDir, workspacePackages) => {
|
|
3335
|
+
const allEntries = [];
|
|
3336
|
+
const allAlwaysUsed = [];
|
|
3337
|
+
const directoriesToCheck = [rootDir, ...workspacePackages.map((workspacePackage) => workspacePackage.directory)];
|
|
3338
|
+
for (const directory of directoriesToCheck) {
|
|
3339
|
+
const packageJsonPath = join(directory, "package.json");
|
|
3340
|
+
if (!existsSync(packageJsonPath)) continue;
|
|
3341
|
+
let allDependencies = {};
|
|
3342
|
+
try {
|
|
3343
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
3344
|
+
const packageJson = JSON.parse(content);
|
|
3345
|
+
allDependencies = {
|
|
3346
|
+
...packageJson.dependencies,
|
|
3347
|
+
...packageJson.devDependencies,
|
|
3348
|
+
...packageJson.optionalDependencies
|
|
3349
|
+
};
|
|
3350
|
+
} catch {
|
|
3351
|
+
continue;
|
|
3352
|
+
}
|
|
3353
|
+
const activatedPatterns = [];
|
|
3354
|
+
const activatedFixturePatterns = [];
|
|
3355
|
+
const activatedAlwaysUsed = [];
|
|
3356
|
+
const isRunnerEnabled = (runner, dependencies, checkDirectory) => {
|
|
3357
|
+
if (runner.enablers.some((enabler) => {
|
|
3358
|
+
return enabler in dependencies;
|
|
3359
|
+
})) return true;
|
|
3360
|
+
return runner.configFileActivators.some((configFile) => existsSync(join(checkDirectory, configFile)));
|
|
3361
|
+
};
|
|
3362
|
+
for (const runner of TEST_RUNNER_DEFINITIONS) if (isRunnerEnabled(runner, allDependencies, directory)) {
|
|
3363
|
+
const isVitestRunner = runner.enablers.includes("vitest");
|
|
3364
|
+
const isJestRunner = runner.enablers.includes("jest");
|
|
3365
|
+
let customPatterns = [];
|
|
3366
|
+
if (isVitestRunner) customPatterns = extractVitestIncludePatterns(directory);
|
|
3367
|
+
else if (isJestRunner) customPatterns = extractJestTestMatchPatterns(directory);
|
|
3368
|
+
if (customPatterns.length > 0) activatedPatterns.push(...customPatterns);
|
|
3369
|
+
else activatedPatterns.push(...runner.entryPatterns);
|
|
3370
|
+
activatedFixturePatterns.push(...runner.fixturePatterns);
|
|
3371
|
+
activatedAlwaysUsed.push(...runner.alwaysUsed);
|
|
3372
|
+
}
|
|
3373
|
+
if (activatedPatterns.length === 0 && directory !== rootDir) {
|
|
3374
|
+
const rootPackageJsonPath = join(rootDir, "package.json");
|
|
3375
|
+
if (existsSync(rootPackageJsonPath)) try {
|
|
3376
|
+
const rootContent = readFileSync(rootPackageJsonPath, "utf-8");
|
|
3377
|
+
const rootPackageJson = JSON.parse(rootContent);
|
|
3378
|
+
const rootDeps = {
|
|
3379
|
+
...rootPackageJson.dependencies,
|
|
3380
|
+
...rootPackageJson.devDependencies,
|
|
3381
|
+
...rootPackageJson.optionalDependencies
|
|
3382
|
+
};
|
|
3383
|
+
for (const runner of TEST_RUNNER_DEFINITIONS) if (isRunnerEnabled(runner, rootDeps, rootDir)) {
|
|
3384
|
+
activatedPatterns.push(...runner.entryPatterns);
|
|
3385
|
+
activatedFixturePatterns.push(...runner.fixturePatterns);
|
|
3386
|
+
activatedAlwaysUsed.push(...runner.alwaysUsed);
|
|
3387
|
+
}
|
|
3388
|
+
} catch {}
|
|
3389
|
+
}
|
|
3390
|
+
if (detectNodeTestRunner(directory) || detectNodeTestRunner(rootDir)) activatedPatterns.push("**/*.test.{ts,tsx,js,jsx,mts,mjs,cts,cjs}", "**/*.spec.{ts,tsx,js,jsx,mts,mjs,cts,cjs}", "**/__tests__/**/*.{ts,tsx,js,jsx,mts,mjs,cts,cjs}");
|
|
3391
|
+
if (detectBunTestRunner(directory) || detectBunTestRunner(rootDir)) activatedPatterns.push("**/*.test.{ts,tsx,js,jsx,mts,mjs}", "**/*.spec.{ts,tsx,js,jsx,mts,mjs}", "**/*_test.{ts,tsx,js,jsx,mts,mjs}", "**/*_spec.{ts,tsx,js,jsx,mts,mjs}", "**/__tests__/**/*.{ts,tsx,js,jsx,mts,mjs}");
|
|
3392
|
+
if (activatedPatterns.length === 0) continue;
|
|
3393
|
+
const uniquePatterns = [...new Set(activatedPatterns)];
|
|
3394
|
+
const testFiles = fg.sync(uniquePatterns, {
|
|
3395
|
+
cwd: directory,
|
|
3396
|
+
absolute: true,
|
|
3397
|
+
onlyFiles: true,
|
|
3398
|
+
ignore: ["**/node_modules/**", "**/*.gen.{ts,tsx,js,jsx}"]
|
|
3399
|
+
});
|
|
3400
|
+
allEntries.push(...testFiles);
|
|
3401
|
+
const uniqueFixturePatterns = [...new Set(activatedFixturePatterns)];
|
|
3402
|
+
if (uniqueFixturePatterns.length > 0) {
|
|
3403
|
+
const fixtureFiles = fg.sync(uniqueFixturePatterns, {
|
|
3404
|
+
cwd: directory,
|
|
3405
|
+
absolute: true,
|
|
3406
|
+
onlyFiles: true,
|
|
3407
|
+
ignore: ["**/node_modules/**"]
|
|
3408
|
+
});
|
|
3409
|
+
allEntries.push(...fixtureFiles);
|
|
3410
|
+
}
|
|
3411
|
+
const uniqueAlwaysUsed = [...new Set(activatedAlwaysUsed)];
|
|
3412
|
+
if (uniqueAlwaysUsed.length > 0) {
|
|
3413
|
+
const alwaysUsedFiles = fg.sync(uniqueAlwaysUsed, {
|
|
3414
|
+
cwd: directory,
|
|
3415
|
+
absolute: true,
|
|
3416
|
+
onlyFiles: true,
|
|
3417
|
+
ignore: ["**/node_modules/**"],
|
|
3418
|
+
dot: true
|
|
3419
|
+
});
|
|
3420
|
+
allAlwaysUsed.push(...alwaysUsedFiles);
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3423
|
+
return {
|
|
3424
|
+
entryFiles: allEntries,
|
|
3425
|
+
alwaysUsedFiles: allAlwaysUsed
|
|
3426
|
+
};
|
|
3427
|
+
};
|
|
3428
|
+
const isToolingPluginEnabled = (plugin, dependencies) => {
|
|
3429
|
+
if (plugin.enablers.some((enabler) => enabler in dependencies)) return true;
|
|
3430
|
+
if (plugin.enablerPrefixes.length > 0) {
|
|
3431
|
+
const depNames = Object.keys(dependencies);
|
|
3432
|
+
return plugin.enablerPrefixes.some((prefix) => depNames.some((depName) => depName.startsWith(prefix)));
|
|
3433
|
+
}
|
|
3434
|
+
return false;
|
|
3435
|
+
};
|
|
3436
|
+
const discoverToolingEntryPoints = (rootDir, workspacePackages) => {
|
|
3437
|
+
const allEntries = [];
|
|
3438
|
+
const allAlwaysUsed = [];
|
|
3439
|
+
const directoriesToCheck = [rootDir, ...workspacePackages.map((workspacePackage) => workspacePackage.directory)];
|
|
3440
|
+
let rootDependencies = {};
|
|
3441
|
+
const rootPackageJsonPath = join(rootDir, "package.json");
|
|
3442
|
+
if (existsSync(rootPackageJsonPath)) try {
|
|
3443
|
+
const rootContent = readFileSync(rootPackageJsonPath, "utf-8");
|
|
3444
|
+
const rootPackageJson = JSON.parse(rootContent);
|
|
3445
|
+
rootDependencies = {
|
|
3446
|
+
...rootPackageJson.dependencies,
|
|
3447
|
+
...rootPackageJson.devDependencies,
|
|
3448
|
+
...rootPackageJson.optionalDependencies
|
|
3449
|
+
};
|
|
3450
|
+
} catch {}
|
|
3451
|
+
for (const directory of directoriesToCheck) {
|
|
3452
|
+
const packageJsonPath = join(directory, "package.json");
|
|
3453
|
+
if (!existsSync(packageJsonPath)) continue;
|
|
3454
|
+
let workspaceDependencies = {};
|
|
3455
|
+
try {
|
|
3456
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
3457
|
+
const packageJson = JSON.parse(content);
|
|
3458
|
+
workspaceDependencies = {
|
|
3459
|
+
...packageJson.dependencies,
|
|
3460
|
+
...packageJson.devDependencies,
|
|
3461
|
+
...packageJson.optionalDependencies
|
|
3462
|
+
};
|
|
3463
|
+
} catch {
|
|
3464
|
+
continue;
|
|
3465
|
+
}
|
|
3466
|
+
const mergedDependencies = directory === rootDir ? rootDependencies : workspaceDependencies;
|
|
3467
|
+
const activatedPatterns = [];
|
|
3468
|
+
const activatedAlwaysUsed = [];
|
|
3469
|
+
for (const plugin of TOOLING_PLUGIN_DEFINITIONS) if (isToolingPluginEnabled(plugin, mergedDependencies)) {
|
|
3470
|
+
activatedPatterns.push(...plugin.entryPatterns);
|
|
3471
|
+
activatedAlwaysUsed.push(...plugin.alwaysUsed);
|
|
3472
|
+
}
|
|
3473
|
+
if (activatedPatterns.length === 0 && activatedAlwaysUsed.length === 0) continue;
|
|
3474
|
+
const uniquePatterns = [...new Set(activatedPatterns)];
|
|
3475
|
+
const toolingFiles = fg.sync(uniquePatterns, {
|
|
3476
|
+
cwd: directory,
|
|
3477
|
+
absolute: true,
|
|
3478
|
+
onlyFiles: true,
|
|
3479
|
+
ignore: ["**/node_modules/**"],
|
|
3480
|
+
dot: true
|
|
3481
|
+
});
|
|
3482
|
+
allEntries.push(...toolingFiles);
|
|
3483
|
+
const uniqueAlwaysUsed = [...new Set(activatedAlwaysUsed)];
|
|
3484
|
+
if (uniqueAlwaysUsed.length > 0) {
|
|
3485
|
+
const alwaysUsedFiles = fg.sync(uniqueAlwaysUsed, {
|
|
3486
|
+
cwd: directory,
|
|
3487
|
+
absolute: true,
|
|
3488
|
+
onlyFiles: true,
|
|
3489
|
+
ignore: ["**/node_modules/**"],
|
|
3490
|
+
dot: true
|
|
3491
|
+
});
|
|
3492
|
+
allAlwaysUsed.push(...alwaysUsedFiles);
|
|
3493
|
+
}
|
|
3494
|
+
}
|
|
3495
|
+
const rootActivatedGlobalPatterns = [];
|
|
3496
|
+
for (const plugin of TOOLING_PLUGIN_DEFINITIONS) if (isToolingPluginEnabled(plugin, rootDependencies)) {
|
|
3497
|
+
for (const pattern of plugin.alwaysUsed) if (!pattern.startsWith("**/")) rootActivatedGlobalPatterns.push(`**/${pattern}`);
|
|
3498
|
+
}
|
|
3499
|
+
if (rootActivatedGlobalPatterns.length > 0) {
|
|
3500
|
+
const globalAlwaysUsedFiles = fg.sync([...new Set(rootActivatedGlobalPatterns)], {
|
|
3501
|
+
cwd: rootDir,
|
|
3502
|
+
absolute: true,
|
|
3503
|
+
onlyFiles: true,
|
|
3504
|
+
ignore: ["**/node_modules/**"],
|
|
3505
|
+
dot: true
|
|
3506
|
+
});
|
|
3507
|
+
allAlwaysUsed.push(...globalAlwaysUsedFiles);
|
|
3508
|
+
}
|
|
3509
|
+
return {
|
|
3510
|
+
entryFiles: allEntries,
|
|
3511
|
+
alwaysUsedFiles: allAlwaysUsed
|
|
3512
|
+
};
|
|
3513
|
+
};
|
|
3514
|
+
|
|
3515
|
+
//#endregion
|
|
3516
|
+
//#region src/resolver/resolve.ts
|
|
3517
|
+
const fileExistsCache = /* @__PURE__ */ new Map();
|
|
3518
|
+
const pathExistsCache = /* @__PURE__ */ new Map();
|
|
3519
|
+
const fileContentCache = /* @__PURE__ */ new Map();
|
|
3520
|
+
const cachedReadFileSync = (filePath) => {
|
|
3521
|
+
const cached = fileContentCache.get(filePath);
|
|
3522
|
+
if (cached !== void 0) return cached;
|
|
3523
|
+
const content = readFileSync(filePath, "utf-8");
|
|
3524
|
+
fileContentCache.set(filePath, content);
|
|
3525
|
+
return content;
|
|
3526
|
+
};
|
|
3527
|
+
const cachedExistsSync = (targetPath) => {
|
|
3528
|
+
const cached = pathExistsCache.get(targetPath);
|
|
3529
|
+
if (cached !== void 0) return cached;
|
|
3530
|
+
const result = existsSync(targetPath);
|
|
3531
|
+
pathExistsCache.set(targetPath, result);
|
|
3532
|
+
return result;
|
|
3533
|
+
};
|
|
3534
|
+
const existsAsFile = (filePath) => {
|
|
3535
|
+
const cached = fileExistsCache.get(filePath);
|
|
3536
|
+
if (cached !== void 0) return cached;
|
|
3537
|
+
try {
|
|
3538
|
+
const result = cachedExistsSync(filePath) && statSync(filePath).isFile();
|
|
3539
|
+
fileExistsCache.set(filePath, result);
|
|
3540
|
+
return result;
|
|
3541
|
+
} catch {
|
|
3542
|
+
fileExistsCache.set(filePath, false);
|
|
3543
|
+
return false;
|
|
3544
|
+
}
|
|
3545
|
+
};
|
|
3546
|
+
const trySourceFallback = (resolvedPath) => {
|
|
3547
|
+
const segments = resolvedPath.split(sep);
|
|
3548
|
+
const isOutputDirectory = (segment) => OUTPUT_DIRECTORIES.some((outputDirectory) => segment === outputDirectory || segment.startsWith(`${outputDirectory}-`));
|
|
3549
|
+
let lastOutputPosition = -1;
|
|
3550
|
+
for (let index = segments.length - 1; index >= 0; index--) if (isOutputDirectory(segments[index])) {
|
|
3551
|
+
lastOutputPosition = index;
|
|
3552
|
+
break;
|
|
3553
|
+
}
|
|
3554
|
+
if (lastOutputPosition === -1) return void 0;
|
|
3555
|
+
let firstOutputPosition = lastOutputPosition;
|
|
3556
|
+
while (firstOutputPosition > 0 && isOutputDirectory(segments[firstOutputPosition - 1])) firstOutputPosition--;
|
|
3557
|
+
const prefix = segments.slice(0, firstOutputPosition).join(sep);
|
|
3558
|
+
const suffix = segments.slice(lastOutputPosition + 1).join(sep);
|
|
3559
|
+
if (!suffix) return void 0;
|
|
3560
|
+
const fileExtension = extname(basename(suffix));
|
|
3561
|
+
const stemmedSuffix = fileExtension ? suffix.slice(0, suffix.length - fileExtension.length) : suffix;
|
|
3562
|
+
for (const sourceExtension of SOURCE_EXTENSIONS$3) {
|
|
3563
|
+
const sourceCandidate = join(prefix, "src", `${stemmedSuffix}.${sourceExtension}`);
|
|
3564
|
+
if (existsAsFile(sourceCandidate)) return sourceCandidate;
|
|
3565
|
+
}
|
|
3566
|
+
};
|
|
3567
|
+
const resolvePathWithExtensionFallback = (candidatePath) => {
|
|
3568
|
+
if (existsAsFile(candidatePath)) return candidatePath;
|
|
3569
|
+
for (const extension of RESOLVER_EXTENSIONS) {
|
|
3570
|
+
const withExtension = candidatePath + extension;
|
|
3571
|
+
if (existsAsFile(withExtension)) return withExtension;
|
|
3572
|
+
}
|
|
3573
|
+
for (const extension of RESOLVER_EXTENSIONS) {
|
|
3574
|
+
const indexCandidate = join(candidatePath, `index${extension}`);
|
|
3575
|
+
if (existsAsFile(indexCandidate)) return indexCandidate;
|
|
3576
|
+
}
|
|
3577
|
+
return candidatePath;
|
|
3578
|
+
};
|
|
3579
|
+
const COMMON_RESOLVER_OPTIONS = {
|
|
3580
|
+
conditionNames: [
|
|
3581
|
+
"import",
|
|
3582
|
+
"require",
|
|
3583
|
+
"node",
|
|
3584
|
+
"default"
|
|
3585
|
+
],
|
|
3586
|
+
extensions: RESOLVER_EXTENSIONS,
|
|
3587
|
+
mainFields: [
|
|
3588
|
+
"module",
|
|
3589
|
+
"main",
|
|
3590
|
+
"browser"
|
|
3591
|
+
],
|
|
3592
|
+
extensionAlias: {
|
|
3593
|
+
".js": [
|
|
3594
|
+
".ts",
|
|
3595
|
+
".tsx",
|
|
3596
|
+
".js",
|
|
3597
|
+
".jsx"
|
|
3598
|
+
],
|
|
3599
|
+
".jsx": [".tsx", ".jsx"],
|
|
3600
|
+
".mjs": [".mts", ".mjs"],
|
|
3601
|
+
".cjs": [".cts", ".cjs"]
|
|
3602
|
+
}
|
|
3603
|
+
};
|
|
3604
|
+
const TSCONFIG_FILENAMES = [
|
|
3605
|
+
"tsconfig.json",
|
|
3606
|
+
"tsconfig.web.json",
|
|
3607
|
+
"tsconfig.app.json",
|
|
3608
|
+
"tsconfig.base.json"
|
|
3609
|
+
];
|
|
3610
|
+
const findNearestTsconfig = (fromDir, rootDir) => {
|
|
3611
|
+
let currentDirectory = fromDir;
|
|
3612
|
+
const normalizedRoot = resolve(rootDir);
|
|
3613
|
+
while (currentDirectory.length >= normalizedRoot.length) {
|
|
3614
|
+
for (const tsconfigFilename of TSCONFIG_FILENAMES) {
|
|
3615
|
+
const tsconfigCandidate = join(currentDirectory, tsconfigFilename);
|
|
3616
|
+
if (cachedExistsSync(tsconfigCandidate)) return tsconfigCandidate;
|
|
3617
|
+
}
|
|
3618
|
+
const parentDirectory = dirname(currentDirectory);
|
|
3619
|
+
if (parentDirectory === currentDirectory) break;
|
|
3620
|
+
currentDirectory = parentDirectory;
|
|
3621
|
+
}
|
|
3622
|
+
};
|
|
3623
|
+
const STYLE_FILE_EXTENSIONS = [
|
|
3624
|
+
".css",
|
|
3625
|
+
".scss",
|
|
3626
|
+
".less",
|
|
3627
|
+
".sass"
|
|
3628
|
+
];
|
|
3629
|
+
const SCSS_PARTIAL_EXTENSIONS = [
|
|
3630
|
+
".scss",
|
|
3631
|
+
".sass",
|
|
3632
|
+
".css"
|
|
3633
|
+
];
|
|
3634
|
+
const resolveScssPartial = (specifier, fromDirectory) => {
|
|
3635
|
+
const basePath = resolve(fromDirectory, specifier);
|
|
3636
|
+
const baseDirectory = dirname(basePath);
|
|
3637
|
+
const baseFileName = basePath.split("/").pop() ?? "";
|
|
3638
|
+
const candidates = [];
|
|
3639
|
+
for (const extension of SCSS_PARTIAL_EXTENSIONS) if (!basePath.endsWith(extension)) {
|
|
3640
|
+
candidates.push(`${basePath}${extension}`);
|
|
3641
|
+
candidates.push(join(baseDirectory, `_${baseFileName}${extension}`));
|
|
3642
|
+
} else {
|
|
3643
|
+
candidates.push(basePath);
|
|
3644
|
+
candidates.push(join(baseDirectory, `_${baseFileName}`));
|
|
3645
|
+
}
|
|
3646
|
+
candidates.push(join(basePath, `index.scss`));
|
|
3647
|
+
candidates.push(join(basePath, `_index.scss`));
|
|
3648
|
+
candidates.push(join(basePath, `index.sass`));
|
|
3649
|
+
candidates.push(join(basePath, `_index.sass`));
|
|
3650
|
+
for (const candidate of candidates) if (cachedExistsSync(candidate)) return candidate;
|
|
3651
|
+
};
|
|
3652
|
+
const createModuleResolver = (config, workspacePackages = [], options = {}) => {
|
|
3653
|
+
const resolverCache = /* @__PURE__ */ new Map();
|
|
3654
|
+
const resolveResultCache = /* @__PURE__ */ new Map();
|
|
3655
|
+
const failedTsconfigPaths = /* @__PURE__ */ new Set();
|
|
3656
|
+
const resolverExtensions = options.hasReactNative ? [...REACT_NATIVE_PLATFORM_EXTENSIONS, ...RESOLVER_EXTENSIONS] : RESOLVER_EXTENSIONS;
|
|
3657
|
+
const resolverOptions = {
|
|
3658
|
+
...COMMON_RESOLVER_OPTIONS,
|
|
3659
|
+
extensions: resolverExtensions
|
|
3660
|
+
};
|
|
3661
|
+
const getOrCreateResolver = (tsconfigPath) => {
|
|
3662
|
+
const effectivePath = tsconfigPath && !failedTsconfigPaths.has(tsconfigPath) ? tsconfigPath : void 0;
|
|
3663
|
+
const cacheKey = effectivePath ?? "__no_tsconfig__";
|
|
3664
|
+
const existingResolver = resolverCache.get(cacheKey);
|
|
3665
|
+
if (existingResolver) return existingResolver;
|
|
3666
|
+
try {
|
|
3667
|
+
const newResolver = new ResolverFactory({
|
|
3668
|
+
...resolverOptions,
|
|
3669
|
+
tsconfig: effectivePath ? {
|
|
3670
|
+
configFile: effectivePath,
|
|
3671
|
+
references: "auto"
|
|
3672
|
+
} : void 0
|
|
3673
|
+
});
|
|
3674
|
+
resolverCache.set(cacheKey, newResolver);
|
|
3675
|
+
return newResolver;
|
|
3676
|
+
} catch {
|
|
3677
|
+
if (effectivePath) {
|
|
3678
|
+
failedTsconfigPaths.add(effectivePath);
|
|
3679
|
+
return getOrCreateResolver(void 0);
|
|
3680
|
+
}
|
|
3681
|
+
const fallbackResolver = new ResolverFactory(COMMON_RESOLVER_OPTIONS);
|
|
3682
|
+
resolverCache.set(cacheKey, fallbackResolver);
|
|
3683
|
+
return fallbackResolver;
|
|
3684
|
+
}
|
|
3685
|
+
};
|
|
3686
|
+
const workspaceNameToDirectory = /* @__PURE__ */ new Map();
|
|
3687
|
+
for (const workspacePackage of workspacePackages) workspaceNameToDirectory.set(workspacePackage.name, workspacePackage.directory);
|
|
3688
|
+
let rootTsconfigPath;
|
|
3689
|
+
if (config.tsConfigPath) rootTsconfigPath = resolve(config.rootDir, config.tsConfigPath);
|
|
3690
|
+
else for (const candidate of [
|
|
3691
|
+
"tsconfig.json",
|
|
3692
|
+
"tsconfig.web.json",
|
|
3693
|
+
"tsconfig.app.json",
|
|
3694
|
+
"tsconfig.base.json"
|
|
3695
|
+
]) {
|
|
3696
|
+
const candidatePath = resolve(config.rootDir, candidate);
|
|
3697
|
+
if (cachedExistsSync(candidatePath)) {
|
|
3698
|
+
rootTsconfigPath = candidatePath;
|
|
3699
|
+
break;
|
|
3700
|
+
}
|
|
3701
|
+
}
|
|
3702
|
+
const tsconfigPathCache = /* @__PURE__ */ new Map();
|
|
3703
|
+
const tsconfigPathAliasCache = /* @__PURE__ */ new Map();
|
|
3704
|
+
const findTsconfigForFile = (filePath) => {
|
|
3705
|
+
const fileDir = dirname(filePath);
|
|
3706
|
+
const cached = tsconfigPathCache.get(fileDir);
|
|
3707
|
+
if (cached !== void 0) return cached;
|
|
3708
|
+
const tsconfigResult = findNearestTsconfig(fileDir, config.rootDir) ?? rootTsconfigPath;
|
|
3709
|
+
tsconfigPathCache.set(fileDir, tsconfigResult);
|
|
3710
|
+
return tsconfigResult;
|
|
3711
|
+
};
|
|
3712
|
+
const tsconfigBaseUrlCache = /* @__PURE__ */ new Map();
|
|
3713
|
+
const getBaseUrlDirectory = (tsconfigFile) => {
|
|
3714
|
+
const cached = tsconfigBaseUrlCache.get(tsconfigFile);
|
|
3715
|
+
if (cached !== void 0) return cached;
|
|
3716
|
+
try {
|
|
3717
|
+
const cleanedContent = stripJsonComments(cachedReadFileSync(tsconfigFile));
|
|
3718
|
+
const baseUrl = JSON.parse(cleanedContent).compilerOptions?.baseUrl;
|
|
3719
|
+
if (baseUrl) {
|
|
3720
|
+
const absoluteBaseUrl = resolve(dirname(tsconfigFile), baseUrl);
|
|
3721
|
+
tsconfigBaseUrlCache.set(tsconfigFile, absoluteBaseUrl);
|
|
3722
|
+
return absoluteBaseUrl;
|
|
3723
|
+
}
|
|
3724
|
+
} catch {}
|
|
3725
|
+
tsconfigBaseUrlCache.set(tsconfigFile, void 0);
|
|
3726
|
+
};
|
|
3727
|
+
const hasNextJsDependency = (() => {
|
|
3728
|
+
try {
|
|
3729
|
+
const rootPackageJson = JSON.parse(cachedReadFileSync(resolve(config.rootDir, "package.json")));
|
|
3730
|
+
return "next" in {
|
|
3731
|
+
...rootPackageJson.dependencies,
|
|
3732
|
+
...rootPackageJson.devDependencies
|
|
3733
|
+
};
|
|
3734
|
+
} catch {
|
|
3735
|
+
return false;
|
|
3736
|
+
}
|
|
3737
|
+
})();
|
|
3738
|
+
const getPathAliases = (tsconfigFile) => {
|
|
3739
|
+
const cached = tsconfigPathAliasCache.get(tsconfigFile);
|
|
3740
|
+
if (cached) return cached;
|
|
3741
|
+
const aliasMap = /* @__PURE__ */ new Map();
|
|
3742
|
+
const tsconfigDir = dirname(tsconfigFile);
|
|
3743
|
+
try {
|
|
3744
|
+
const tsconfigContent = cachedReadFileSync(tsconfigFile).trim();
|
|
3745
|
+
if (tsconfigContent.length > 0) {
|
|
3746
|
+
const cleanedContent = stripJsonComments(tsconfigContent);
|
|
3747
|
+
const tsconfigJson = JSON.parse(cleanedContent);
|
|
3748
|
+
const paths = tsconfigJson.compilerOptions?.paths;
|
|
3749
|
+
const baseUrl = tsconfigJson.compilerOptions?.baseUrl ?? ".";
|
|
3750
|
+
if (paths && typeof paths === "object") {
|
|
3751
|
+
for (const [pattern, targets] of Object.entries(paths)) if (Array.isArray(targets)) aliasMap.set(pattern, targets.map((target) => resolve(tsconfigDir, baseUrl, target)));
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
} catch {}
|
|
3755
|
+
if (aliasMap.size === 0 && hasNextJsDependency) if (cachedExistsSync(resolve(tsconfigDir, "src"))) aliasMap.set("@/*", [resolve(tsconfigDir, "src/*")]);
|
|
3756
|
+
else aliasMap.set("@/*", [resolve(tsconfigDir, "*")]);
|
|
3757
|
+
tsconfigPathAliasCache.set(tsconfigFile, aliasMap);
|
|
3758
|
+
return aliasMap;
|
|
3759
|
+
};
|
|
3760
|
+
const tryResolveViaPathAlias = (specifier, fromFile) => {
|
|
3761
|
+
const tsconfigFile = findTsconfigForFile(fromFile);
|
|
3762
|
+
if (!tsconfigFile) return void 0;
|
|
3763
|
+
const aliases = getPathAliases(tsconfigFile);
|
|
3764
|
+
for (const [pattern, targetPatterns] of aliases) {
|
|
3765
|
+
const wildcardIndex = pattern.indexOf("*");
|
|
3766
|
+
if (wildcardIndex === -1) {
|
|
3767
|
+
if (specifier === pattern) for (const targetPattern of targetPatterns) {
|
|
3768
|
+
const candidate = targetPattern.replace("*", "");
|
|
3769
|
+
if (existsAsFile(candidate)) return candidate;
|
|
3770
|
+
for (const ext of RESOLVER_EXTENSIONS) if (cachedExistsSync(candidate + ext)) return candidate + ext;
|
|
3771
|
+
const indexCandidate = join(candidate, "index");
|
|
3772
|
+
for (const ext of RESOLVER_EXTENSIONS) if (cachedExistsSync(indexCandidate + ext)) return indexCandidate + ext;
|
|
3773
|
+
}
|
|
3774
|
+
continue;
|
|
3775
|
+
}
|
|
3776
|
+
const prefix = pattern.slice(0, wildcardIndex);
|
|
3777
|
+
const suffix = pattern.slice(wildcardIndex + 1);
|
|
3778
|
+
if (!specifier.startsWith(prefix) || !specifier.endsWith(suffix)) continue;
|
|
3779
|
+
const matchedWildcard = specifier.slice(prefix.length, specifier.length - suffix.length);
|
|
3780
|
+
for (const targetPattern of targetPatterns) {
|
|
3781
|
+
const resolvedTarget = targetPattern.replace("*", matchedWildcard);
|
|
3782
|
+
if (existsAsFile(resolvedTarget)) return resolvedTarget;
|
|
3783
|
+
for (const ext of RESOLVER_EXTENSIONS) if (cachedExistsSync(resolvedTarget + ext)) return resolvedTarget + ext;
|
|
3784
|
+
const strippedTarget = resolvedTarget.replace(/\.[cm]?js$/, "");
|
|
3785
|
+
if (strippedTarget !== resolvedTarget) {
|
|
3786
|
+
for (const ext of RESOLVER_EXTENSIONS) if (cachedExistsSync(strippedTarget + ext)) return strippedTarget + ext;
|
|
3787
|
+
}
|
|
3788
|
+
const indexCandidate = join(resolvedTarget, "index");
|
|
3789
|
+
for (const ext of RESOLVER_EXTENSIONS) if (cachedExistsSync(indexCandidate + ext)) return indexCandidate + ext;
|
|
3790
|
+
}
|
|
3791
|
+
}
|
|
3792
|
+
};
|
|
3793
|
+
const resolveModule = (specifier, fromFile) => {
|
|
3794
|
+
const queryIndex = specifier.indexOf("?");
|
|
3795
|
+
const cleanedSpecifier = queryIndex !== -1 ? specifier.slice(0, queryIndex) : specifier;
|
|
3796
|
+
const fromDir = dirname(fromFile);
|
|
3797
|
+
const cacheKey = `${fromDir}::${cleanedSpecifier}`;
|
|
3798
|
+
const cached = resolveResultCache.get(cacheKey);
|
|
3799
|
+
if (cached) return cached;
|
|
3800
|
+
if (isBuiltinModule(cleanedSpecifier)) {
|
|
3801
|
+
const resolvedResult = {
|
|
3802
|
+
resolvedPath: void 0,
|
|
3803
|
+
isExternal: true,
|
|
3804
|
+
packageName: cleanedSpecifier.startsWith("node:") ? cleanedSpecifier.slice(5) : cleanedSpecifier
|
|
3805
|
+
};
|
|
3806
|
+
resolveResultCache.set(cacheKey, resolvedResult);
|
|
3807
|
+
return resolvedResult;
|
|
3808
|
+
}
|
|
3809
|
+
if (STYLE_FILE_EXTENSIONS.some((extension) => fromFile.endsWith(extension)) && isBareSpecifier(cleanedSpecifier)) {
|
|
3810
|
+
const scssResolved = resolveScssPartial(cleanedSpecifier, fromDir);
|
|
3811
|
+
if (scssResolved) {
|
|
3812
|
+
const resolvedResult = {
|
|
3813
|
+
resolvedPath: scssResolved,
|
|
3814
|
+
isExternal: false,
|
|
3815
|
+
packageName: void 0
|
|
3816
|
+
};
|
|
3817
|
+
resolveResultCache.set(cacheKey, resolvedResult);
|
|
3818
|
+
return resolvedResult;
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
if (isBareSpecifier(cleanedSpecifier) && workspaceNameToDirectory.size > 0) {
|
|
3822
|
+
const packageName = extractPackageNameFromSpecifier(cleanedSpecifier);
|
|
3823
|
+
const workspaceDirectory = workspaceNameToDirectory.get(packageName);
|
|
3824
|
+
if (workspaceDirectory) {
|
|
3825
|
+
const subpath = cleanedSpecifier.slice(packageName.length + 1);
|
|
3826
|
+
const workspacePackageJsonPath = join(workspaceDirectory, "package.json");
|
|
3827
|
+
try {
|
|
3828
|
+
const workspacePackageContent = cachedReadFileSync(workspacePackageJsonPath);
|
|
3829
|
+
const workspacePackageJson = JSON.parse(workspacePackageContent);
|
|
3830
|
+
let resolvedEntryPath;
|
|
3831
|
+
if (subpath && workspacePackageJson.exports) {
|
|
3832
|
+
const exportKey = `./${subpath}`;
|
|
3833
|
+
const exportValue = workspacePackageJson.exports[exportKey];
|
|
3834
|
+
if (typeof exportValue === "string") {
|
|
3835
|
+
const candidatePath = resolvePathWithExtensionFallback(resolve(workspaceDirectory, exportValue));
|
|
3836
|
+
resolvedEntryPath = existsAsFile(candidatePath) ? candidatePath : trySourceFallback(candidatePath);
|
|
3837
|
+
} else if (typeof exportValue === "object" && exportValue !== null) {
|
|
3838
|
+
const conditionValue = exportValue.import ?? exportValue.require ?? exportValue.default ?? exportValue.types;
|
|
3839
|
+
if (typeof conditionValue === "string") {
|
|
3840
|
+
const candidatePath = resolvePathWithExtensionFallback(resolve(workspaceDirectory, conditionValue));
|
|
3841
|
+
resolvedEntryPath = existsAsFile(candidatePath) ? candidatePath : trySourceFallback(candidatePath);
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
3844
|
+
if (!resolvedEntryPath) for (const [wildcardPattern, wildcardTarget] of Object.entries(workspacePackageJson.exports)) {
|
|
3845
|
+
if (typeof wildcardPattern !== "string" || !wildcardPattern.includes("*")) continue;
|
|
3846
|
+
const wildcardTargetRecord = typeof wildcardTarget === "object" && wildcardTarget !== null ? wildcardTarget : void 0;
|
|
3847
|
+
const wildcardTargetValue = typeof wildcardTarget === "string" ? wildcardTarget : wildcardTargetRecord ? String(wildcardTargetRecord["import"] ?? wildcardTargetRecord["require"] ?? wildcardTargetRecord["default"] ?? wildcardTargetRecord["types"] ?? "") : void 0;
|
|
3848
|
+
if (typeof wildcardTargetValue !== "string") continue;
|
|
3849
|
+
const wildcardPrefix = wildcardPattern.slice(0, wildcardPattern.indexOf("*"));
|
|
3850
|
+
const wildcardSuffix = wildcardPattern.slice(wildcardPattern.indexOf("*") + 1);
|
|
3851
|
+
if (exportKey.startsWith(wildcardPrefix) && exportKey.endsWith(wildcardSuffix)) {
|
|
3852
|
+
const matchedSegment = exportKey.slice(wildcardPrefix.length, exportKey.length - wildcardSuffix.length || void 0);
|
|
3853
|
+
const candidatePath = resolvePathWithExtensionFallback(resolve(workspaceDirectory, wildcardTargetValue.replace("*", matchedSegment)));
|
|
3854
|
+
resolvedEntryPath = existsAsFile(candidatePath) ? candidatePath : trySourceFallback(candidatePath);
|
|
3855
|
+
break;
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
}
|
|
3859
|
+
if (subpath && !resolvedEntryPath) {
|
|
3860
|
+
const subpathCandidates = [resolve(workspaceDirectory, subpath), resolve(workspaceDirectory, "src", subpath)];
|
|
3861
|
+
for (const directSubpath of subpathCandidates) {
|
|
3862
|
+
for (const candidateExtension of RESOLVER_EXTENSIONS) {
|
|
3863
|
+
const candidate = directSubpath + candidateExtension;
|
|
3864
|
+
if (cachedExistsSync(candidate)) {
|
|
3865
|
+
resolvedEntryPath = candidate;
|
|
3866
|
+
break;
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
if (resolvedEntryPath) break;
|
|
3870
|
+
for (const candidateExtension of RESOLVER_EXTENSIONS) {
|
|
3871
|
+
const indexCandidate = join(directSubpath, `index${candidateExtension}`);
|
|
3872
|
+
if (cachedExistsSync(indexCandidate)) {
|
|
3873
|
+
resolvedEntryPath = indexCandidate;
|
|
3874
|
+
break;
|
|
3875
|
+
}
|
|
3876
|
+
}
|
|
3877
|
+
if (resolvedEntryPath) break;
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3880
|
+
if (!subpath) {
|
|
3881
|
+
const mainField = workspacePackageJson.main ?? workspacePackageJson.module;
|
|
3882
|
+
if (typeof mainField === "string") resolvedEntryPath = resolve(workspaceDirectory, mainField);
|
|
3883
|
+
if (!resolvedEntryPath && workspacePackageJson.exports?.["."]) {
|
|
3884
|
+
const dotExport = workspacePackageJson.exports["."];
|
|
3885
|
+
if (typeof dotExport === "string") resolvedEntryPath = resolve(workspaceDirectory, dotExport);
|
|
3886
|
+
else if (typeof dotExport === "object" && dotExport !== null) {
|
|
3887
|
+
const conditionValue = dotExport.import ?? dotExport.require ?? dotExport.default ?? dotExport.types;
|
|
3888
|
+
if (typeof conditionValue === "string") resolvedEntryPath = resolve(workspaceDirectory, conditionValue);
|
|
3889
|
+
}
|
|
3890
|
+
}
|
|
3891
|
+
}
|
|
3892
|
+
if (resolvedEntryPath) {
|
|
3893
|
+
const finalPath = resolveSourcePath(resolvedEntryPath, workspaceDirectory) ?? resolvedEntryPath;
|
|
3894
|
+
if (cachedExistsSync(finalPath)) {
|
|
3895
|
+
const resolvedResult = {
|
|
3896
|
+
resolvedPath: finalPath,
|
|
3897
|
+
isExternal: false,
|
|
3898
|
+
packageName: void 0
|
|
3899
|
+
};
|
|
3900
|
+
resolveResultCache.set(cacheKey, resolvedResult);
|
|
3901
|
+
return resolvedResult;
|
|
3902
|
+
}
|
|
3903
|
+
const sourceFallbackPath = trySourceFallback(resolvedEntryPath);
|
|
3904
|
+
if (sourceFallbackPath) {
|
|
3905
|
+
const resolvedResult = {
|
|
3906
|
+
resolvedPath: sourceFallbackPath,
|
|
3907
|
+
isExternal: false,
|
|
3908
|
+
packageName: void 0
|
|
3909
|
+
};
|
|
3910
|
+
resolveResultCache.set(cacheKey, resolvedResult);
|
|
3911
|
+
return resolvedResult;
|
|
3912
|
+
}
|
|
3913
|
+
}
|
|
3914
|
+
} catch {}
|
|
3915
|
+
}
|
|
3916
|
+
}
|
|
3917
|
+
const tsconfigForFile = findTsconfigForFile(fromFile);
|
|
3918
|
+
const resolver = getOrCreateResolver(tsconfigForFile);
|
|
3919
|
+
const tryResolve = (activeResolver) => {
|
|
3920
|
+
try {
|
|
3921
|
+
const resolverResult = activeResolver.sync(fromDir, cleanedSpecifier);
|
|
3922
|
+
if (resolverResult.path) {
|
|
3923
|
+
const isInsideNodeModules = resolverResult.path.includes("/node_modules/");
|
|
3924
|
+
return {
|
|
3925
|
+
resolvedPath: isInsideNodeModules ? void 0 : resolverResult.path,
|
|
3926
|
+
isExternal: isInsideNodeModules,
|
|
3927
|
+
packageName: isInsideNodeModules ? extractPackageNameFromSpecifier(cleanedSpecifier) : void 0
|
|
3928
|
+
};
|
|
3929
|
+
}
|
|
3930
|
+
} catch {
|
|
3931
|
+
return;
|
|
3932
|
+
}
|
|
3933
|
+
};
|
|
3934
|
+
const resolversToAttempt = [
|
|
3935
|
+
resolver,
|
|
3936
|
+
...tsconfigForFile !== rootTsconfigPath && rootTsconfigPath ? [getOrCreateResolver(rootTsconfigPath)] : [],
|
|
3937
|
+
...tsconfigForFile ? [getOrCreateResolver(void 0)] : []
|
|
3938
|
+
];
|
|
3939
|
+
for (const activeResolver of resolversToAttempt) {
|
|
3940
|
+
const resolvedResult = tryResolve(activeResolver);
|
|
3941
|
+
if (resolvedResult) {
|
|
3942
|
+
resolveResultCache.set(cacheKey, resolvedResult);
|
|
3943
|
+
return resolvedResult;
|
|
3944
|
+
}
|
|
3945
|
+
}
|
|
3946
|
+
const pathAliasResolved = tryResolveViaPathAlias(cleanedSpecifier, fromFile);
|
|
3947
|
+
if (pathAliasResolved) {
|
|
3948
|
+
const resolvedResult = {
|
|
3949
|
+
resolvedPath: pathAliasResolved,
|
|
3950
|
+
isExternal: false,
|
|
3951
|
+
packageName: void 0
|
|
3952
|
+
};
|
|
3953
|
+
resolveResultCache.set(cacheKey, resolvedResult);
|
|
3954
|
+
return resolvedResult;
|
|
3955
|
+
}
|
|
3956
|
+
if (isBareSpecifier(cleanedSpecifier)) {
|
|
3957
|
+
const tsconfigFile = findTsconfigForFile(fromFile);
|
|
3958
|
+
if (tsconfigFile) {
|
|
3959
|
+
const baseUrlDirectory = getBaseUrlDirectory(tsconfigFile);
|
|
3960
|
+
if (baseUrlDirectory) {
|
|
3961
|
+
const baseUrlCandidate = resolve(baseUrlDirectory, cleanedSpecifier);
|
|
3962
|
+
for (const candidateExtension of RESOLVER_EXTENSIONS) {
|
|
3963
|
+
const fullCandidate = baseUrlCandidate + candidateExtension;
|
|
3964
|
+
if (cachedExistsSync(fullCandidate)) {
|
|
3965
|
+
const resolvedResult = {
|
|
3966
|
+
resolvedPath: fullCandidate,
|
|
3967
|
+
isExternal: false,
|
|
3968
|
+
packageName: void 0
|
|
3969
|
+
};
|
|
3970
|
+
resolveResultCache.set(cacheKey, resolvedResult);
|
|
3971
|
+
return resolvedResult;
|
|
3972
|
+
}
|
|
3973
|
+
}
|
|
3974
|
+
const indexCandidate = join(baseUrlCandidate, "index");
|
|
3975
|
+
for (const candidateExtension of RESOLVER_EXTENSIONS) {
|
|
3976
|
+
const fullCandidate = indexCandidate + candidateExtension;
|
|
3977
|
+
if (cachedExistsSync(fullCandidate)) {
|
|
3978
|
+
const resolvedResult = {
|
|
3979
|
+
resolvedPath: fullCandidate,
|
|
3980
|
+
isExternal: false,
|
|
3981
|
+
packageName: void 0
|
|
3982
|
+
};
|
|
3983
|
+
resolveResultCache.set(cacheKey, resolvedResult);
|
|
3984
|
+
return resolvedResult;
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3987
|
+
}
|
|
3988
|
+
}
|
|
3989
|
+
const resolvedResult = {
|
|
3990
|
+
resolvedPath: void 0,
|
|
3991
|
+
isExternal: true,
|
|
3992
|
+
packageName: extractPackageNameFromSpecifier(cleanedSpecifier)
|
|
3993
|
+
};
|
|
3994
|
+
resolveResultCache.set(cacheKey, resolvedResult);
|
|
3995
|
+
return resolvedResult;
|
|
3996
|
+
}
|
|
3997
|
+
const unresolvedResult = {
|
|
3998
|
+
resolvedPath: void 0,
|
|
3999
|
+
isExternal: false,
|
|
4000
|
+
packageName: void 0
|
|
4001
|
+
};
|
|
4002
|
+
resolveResultCache.set(cacheKey, unresolvedResult);
|
|
4003
|
+
return unresolvedResult;
|
|
4004
|
+
};
|
|
4005
|
+
return { resolveModule };
|
|
4006
|
+
};
|
|
4007
|
+
const stripJsonComments = (content) => {
|
|
4008
|
+
let result = "";
|
|
4009
|
+
let insideString = false;
|
|
4010
|
+
let index = 0;
|
|
4011
|
+
while (index < content.length) {
|
|
4012
|
+
if (insideString) {
|
|
4013
|
+
if (content[index] === "\\" && index + 1 < content.length) {
|
|
4014
|
+
result += content[index] + content[index + 1];
|
|
4015
|
+
index += 2;
|
|
4016
|
+
continue;
|
|
4017
|
+
}
|
|
4018
|
+
if (content[index] === "\"") insideString = false;
|
|
4019
|
+
result += content[index];
|
|
4020
|
+
index++;
|
|
4021
|
+
continue;
|
|
4022
|
+
}
|
|
4023
|
+
if (content[index] === "\"") {
|
|
4024
|
+
insideString = true;
|
|
4025
|
+
result += content[index];
|
|
4026
|
+
index++;
|
|
4027
|
+
continue;
|
|
4028
|
+
}
|
|
4029
|
+
if (content[index] === "/" && index + 1 < content.length) {
|
|
4030
|
+
if (content[index + 1] === "/") {
|
|
4031
|
+
while (index < content.length && content[index] !== "\n") index++;
|
|
4032
|
+
continue;
|
|
4033
|
+
}
|
|
4034
|
+
if (content[index + 1] === "*") {
|
|
4035
|
+
index += 2;
|
|
4036
|
+
while (index + 1 < content.length && !(content[index] === "*" && content[index + 1] === "/")) index++;
|
|
4037
|
+
index += 2;
|
|
4038
|
+
continue;
|
|
4039
|
+
}
|
|
4040
|
+
}
|
|
4041
|
+
result += content[index];
|
|
4042
|
+
index++;
|
|
4043
|
+
}
|
|
4044
|
+
return result.replace(/,(\s*[}\]])/g, "$1");
|
|
4045
|
+
};
|
|
4046
|
+
const BUILTIN_SUBPATH_MODULES = new Set([
|
|
4047
|
+
"fs",
|
|
4048
|
+
"dns",
|
|
4049
|
+
"stream",
|
|
4050
|
+
"readline",
|
|
4051
|
+
"timers",
|
|
4052
|
+
"util"
|
|
4053
|
+
]);
|
|
4054
|
+
const isBuiltinModule = (specifier) => {
|
|
4055
|
+
if (specifier.startsWith("node:")) return true;
|
|
4056
|
+
const baseName = specifier.split("/")[0];
|
|
4057
|
+
if (!BUILTIN_MODULES.has(baseName)) return false;
|
|
4058
|
+
if (!specifier.includes("/")) return true;
|
|
4059
|
+
return BUILTIN_SUBPATH_MODULES.has(baseName);
|
|
4060
|
+
};
|
|
4061
|
+
const isBareSpecifier = (specifier) => !specifier.startsWith(".") && !specifier.startsWith("/");
|
|
4062
|
+
const extractPackageNameFromSpecifier = (specifier) => {
|
|
4063
|
+
if (specifier.startsWith("node:")) return specifier.slice(5).split("/")[0];
|
|
4064
|
+
if (specifier.startsWith("@")) {
|
|
4065
|
+
const parts = specifier.split("/");
|
|
4066
|
+
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : specifier;
|
|
4067
|
+
}
|
|
4068
|
+
return specifier.split("/")[0];
|
|
4069
|
+
};
|
|
4070
|
+
|
|
4071
|
+
//#endregion
|
|
4072
|
+
//#region src/utils/is-config-file.ts
|
|
4073
|
+
const isConfigFile = (filePath) => {
|
|
4074
|
+
const fileName = filePath.split("/").pop() ?? "";
|
|
4075
|
+
if (fileName.startsWith(".") && !fileName.startsWith("..")) {
|
|
4076
|
+
if (fileName.toLowerCase().includes("rc.")) return true;
|
|
4077
|
+
}
|
|
4078
|
+
return CONFIG_FILE_PREFIXES.some((prefix) => fileName.startsWith(prefix));
|
|
4079
|
+
};
|
|
4080
|
+
|
|
4081
|
+
//#endregion
|
|
4082
|
+
//#region src/graph/build.ts
|
|
4083
|
+
const buildModuleGraph = (inputs) => {
|
|
4084
|
+
const fileIdMap = /* @__PURE__ */ new Map();
|
|
4085
|
+
for (const input of inputs) fileIdMap.set(input.fileId.path, input.fileId.index);
|
|
4086
|
+
const modules = inputs.map((input) => ({
|
|
4087
|
+
fileId: input.fileId,
|
|
4088
|
+
imports: input.parsed.imports,
|
|
4089
|
+
exports: input.parsed.exports,
|
|
4090
|
+
memberAccesses: input.parsed.memberAccesses,
|
|
4091
|
+
wholeObjectUses: input.parsed.wholeObjectUses,
|
|
4092
|
+
isEntryPoint: input.isEntryPoint,
|
|
4093
|
+
isTestEntry: input.isTestEntry,
|
|
4094
|
+
isReachable: false,
|
|
4095
|
+
isDeclarationFile: input.fileId.path.endsWith(".d.ts") || input.fileId.path.endsWith(".d.mts") || input.fileId.path.endsWith(".d.cts"),
|
|
4096
|
+
isConfigFile: isConfigFile(input.fileId.path)
|
|
4097
|
+
}));
|
|
4098
|
+
const edges = [];
|
|
4099
|
+
const reverseEdges = /* @__PURE__ */ new Map();
|
|
4100
|
+
const addEdge = (sourceIndex, targetIndex, symbols, isReExportEdge = false, reExportedNames = [], reExportMappings = []) => {
|
|
4101
|
+
edges.push({
|
|
4102
|
+
source: sourceIndex,
|
|
4103
|
+
target: targetIndex,
|
|
4104
|
+
importedSymbols: symbols,
|
|
4105
|
+
isReExportEdge,
|
|
4106
|
+
reExportedNames,
|
|
4107
|
+
reExportMappings
|
|
4108
|
+
});
|
|
4109
|
+
const existingReverseEdges = reverseEdges.get(targetIndex);
|
|
4110
|
+
if (existingReverseEdges) {
|
|
4111
|
+
if (!existingReverseEdges.includes(sourceIndex)) existingReverseEdges.push(sourceIndex);
|
|
4112
|
+
} else reverseEdges.set(targetIndex, [sourceIndex]);
|
|
4113
|
+
};
|
|
4114
|
+
for (const input of inputs) {
|
|
4115
|
+
const sourceIndex = input.fileId.index;
|
|
4116
|
+
for (const importInfo of input.parsed.imports) {
|
|
4117
|
+
if (importInfo.isGlob) {
|
|
4118
|
+
const sourceDir = path.dirname(input.fileId.path);
|
|
4119
|
+
const globPattern = importInfo.specifier;
|
|
4120
|
+
for (const [filePath] of fileIdMap) {
|
|
4121
|
+
const relativePath = path.relative(sourceDir, filePath);
|
|
4122
|
+
if (minimatch(relativePath.startsWith(".") ? relativePath : `./${relativePath}`, globPattern)) {
|
|
4123
|
+
const targetIndex = fileIdMap.get(filePath);
|
|
4124
|
+
if (targetIndex !== void 0) addEdge(sourceIndex, targetIndex, []);
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
continue;
|
|
4128
|
+
}
|
|
4129
|
+
const resolved = input.resolvedImports.get(importInfo.specifier);
|
|
4130
|
+
if (!resolved?.resolvedPath) continue;
|
|
4131
|
+
const targetIndex = fileIdMap.get(resolved.resolvedPath);
|
|
4132
|
+
if (targetIndex === void 0) continue;
|
|
4133
|
+
addEdge(sourceIndex, targetIndex, importInfo.importedNames.map((importedName) => ({
|
|
4134
|
+
importedName: importedName.name,
|
|
4135
|
+
localName: importedName.alias ?? importedName.name,
|
|
4136
|
+
isTypeOnly: importedName.isTypeOnly,
|
|
4137
|
+
isNamespace: importedName.isNamespace,
|
|
4138
|
+
isDefault: importedName.isDefault
|
|
4139
|
+
})));
|
|
4140
|
+
}
|
|
4141
|
+
const reExportsByTarget = /* @__PURE__ */ new Map();
|
|
4142
|
+
for (const exportInfo of input.parsed.exports) {
|
|
4143
|
+
if (!exportInfo.isReExport || !exportInfo.reExportSource) continue;
|
|
4144
|
+
const resolved = input.resolvedImports.get(exportInfo.reExportSource);
|
|
4145
|
+
if (!resolved?.resolvedPath) continue;
|
|
4146
|
+
const targetIndex = fileIdMap.get(resolved.resolvedPath);
|
|
4147
|
+
if (targetIndex === void 0) continue;
|
|
4148
|
+
const exportedName = exportInfo.isNamespaceReExport ? "*" : exportInfo.name;
|
|
4149
|
+
const originalName = exportInfo.isNamespaceReExport ? "*" : exportInfo.reExportOriginalName ?? exportInfo.name;
|
|
4150
|
+
const existing = reExportsByTarget.get(targetIndex);
|
|
4151
|
+
if (existing) {
|
|
4152
|
+
existing.names.push(exportedName);
|
|
4153
|
+
existing.mappings.push({
|
|
4154
|
+
exportedName,
|
|
4155
|
+
originalName
|
|
4156
|
+
});
|
|
4157
|
+
} else reExportsByTarget.set(targetIndex, {
|
|
4158
|
+
names: [exportedName],
|
|
4159
|
+
mappings: [{
|
|
4160
|
+
exportedName,
|
|
4161
|
+
originalName
|
|
4162
|
+
}]
|
|
4163
|
+
});
|
|
4164
|
+
}
|
|
4165
|
+
for (const [targetIndex, { names: reExportedNames, mappings: reExportMappings }] of reExportsByTarget) addEdge(sourceIndex, targetIndex, [], true, reExportedNames, reExportMappings);
|
|
4166
|
+
}
|
|
4167
|
+
return {
|
|
4168
|
+
modules,
|
|
4169
|
+
edges,
|
|
4170
|
+
reverseEdges,
|
|
4171
|
+
fileIdMap
|
|
4172
|
+
};
|
|
4173
|
+
};
|
|
4174
|
+
|
|
4175
|
+
//#endregion
|
|
4176
|
+
//#region src/graph/reachability.ts
|
|
4177
|
+
const PLATFORM_DIRECTORY_NAMES = new Set([
|
|
4178
|
+
"web",
|
|
4179
|
+
"native",
|
|
4180
|
+
"ios",
|
|
4181
|
+
"android",
|
|
4182
|
+
"desktop",
|
|
4183
|
+
"windows",
|
|
4184
|
+
"macos"
|
|
4185
|
+
]);
|
|
4186
|
+
const stripPlatformSuffix = (filePath) => {
|
|
4187
|
+
for (const suffix of PLATFORM_SUFFIXES) {
|
|
4188
|
+
const extensionIndex = filePath.lastIndexOf(".");
|
|
4189
|
+
if (extensionIndex === -1) continue;
|
|
4190
|
+
const withoutExtension = filePath.slice(0, extensionIndex);
|
|
4191
|
+
if (withoutExtension.endsWith(suffix)) return withoutExtension.slice(0, -suffix.length) + filePath.slice(extensionIndex);
|
|
4192
|
+
}
|
|
4193
|
+
};
|
|
4194
|
+
const stripPlatformDirectory = (filePath) => {
|
|
4195
|
+
const segments = filePath.split("/");
|
|
4196
|
+
for (let segmentIndex = segments.length - 2; segmentIndex >= 0; segmentIndex--) if (PLATFORM_DIRECTORY_NAMES.has(segments[segmentIndex])) return [...segments.slice(0, segmentIndex), ...segments.slice(segmentIndex + 1)].join("/");
|
|
4197
|
+
};
|
|
4198
|
+
const markReachable = (graph) => {
|
|
4199
|
+
const totalModules = graph.modules.length;
|
|
4200
|
+
const visited = new Uint8Array(totalModules);
|
|
4201
|
+
const consumedExportsPerModule = /* @__PURE__ */ new Map();
|
|
4202
|
+
const queue = [];
|
|
4203
|
+
const outgoingEdgesMap = /* @__PURE__ */ new Map();
|
|
4204
|
+
for (const edge of graph.edges) {
|
|
4205
|
+
const existing = outgoingEdgesMap.get(edge.source);
|
|
4206
|
+
if (existing) existing.push(edge);
|
|
4207
|
+
else outgoingEdgesMap.set(edge.source, [edge]);
|
|
4208
|
+
}
|
|
4209
|
+
for (const module of graph.modules) if (module.isEntryPoint) {
|
|
4210
|
+
const moduleIndex = module.fileId.index;
|
|
4211
|
+
if (moduleIndex < totalModules) {
|
|
4212
|
+
visited[moduleIndex] = 1;
|
|
4213
|
+
queue.push({
|
|
4214
|
+
moduleIndex,
|
|
4215
|
+
demandedSymbols: "all"
|
|
4216
|
+
});
|
|
4217
|
+
}
|
|
4218
|
+
}
|
|
4219
|
+
const markConsumedExports = (targetModuleIndex, symbols) => {
|
|
4220
|
+
if (symbols === "all") {
|
|
4221
|
+
consumedExportsPerModule.set(targetModuleIndex, new Set(["*"]));
|
|
4222
|
+
return;
|
|
4223
|
+
}
|
|
4224
|
+
const existing = consumedExportsPerModule.get(targetModuleIndex);
|
|
4225
|
+
if (existing && existing.has("*")) return;
|
|
4226
|
+
if (existing) for (const symbol of symbols) existing.add(symbol);
|
|
4227
|
+
else consumedExportsPerModule.set(targetModuleIndex, new Set(symbols));
|
|
4228
|
+
};
|
|
4229
|
+
let headPointer = 0;
|
|
4230
|
+
while (headPointer < queue.length) {
|
|
4231
|
+
const { moduleIndex: currentIndex } = queue[headPointer++];
|
|
4232
|
+
const outgoingEdges = outgoingEdgesMap.get(currentIndex);
|
|
4233
|
+
if (!outgoingEdges) continue;
|
|
4234
|
+
for (const edge of outgoingEdges) {
|
|
4235
|
+
const targetIndex = edge.target;
|
|
4236
|
+
if (targetIndex >= totalModules) continue;
|
|
4237
|
+
if (edge.isReExportEdge) {
|
|
4238
|
+
if (!visited[targetIndex]) {
|
|
4239
|
+
visited[targetIndex] = 1;
|
|
4240
|
+
markConsumedExports(targetIndex, "all");
|
|
4241
|
+
queue.push({
|
|
4242
|
+
moduleIndex: targetIndex,
|
|
4243
|
+
demandedSymbols: "all"
|
|
4244
|
+
});
|
|
4245
|
+
}
|
|
4246
|
+
} else {
|
|
4247
|
+
const importSymbolNames = /* @__PURE__ */ new Set();
|
|
4248
|
+
let isNamespaceOrSideEffect = edge.importedSymbols.length === 0;
|
|
4249
|
+
for (const symbol of edge.importedSymbols) {
|
|
4250
|
+
if (symbol.isNamespace) {
|
|
4251
|
+
isNamespaceOrSideEffect = true;
|
|
4252
|
+
break;
|
|
4253
|
+
}
|
|
4254
|
+
importSymbolNames.add(symbol.importedName);
|
|
4255
|
+
if (symbol.isDefault) importSymbolNames.add("default");
|
|
4256
|
+
}
|
|
4257
|
+
const symbolDemand = isNamespaceOrSideEffect ? "all" : importSymbolNames;
|
|
4258
|
+
if (!visited[targetIndex]) {
|
|
4259
|
+
visited[targetIndex] = 1;
|
|
4260
|
+
markConsumedExports(targetIndex, symbolDemand);
|
|
4261
|
+
queue.push({
|
|
4262
|
+
moduleIndex: targetIndex,
|
|
4263
|
+
demandedSymbols: symbolDemand
|
|
4264
|
+
});
|
|
4265
|
+
} else {
|
|
4266
|
+
const existingConsumed = consumedExportsPerModule.get(targetIndex);
|
|
4267
|
+
if (symbolDemand !== "all" && existingConsumed && !existingConsumed.has("*")) {
|
|
4268
|
+
let hasNewSymbols = false;
|
|
4269
|
+
for (const symbol of symbolDemand) if (!existingConsumed.has(symbol)) {
|
|
4270
|
+
hasNewSymbols = true;
|
|
4271
|
+
break;
|
|
4272
|
+
}
|
|
4273
|
+
if (hasNewSymbols) {
|
|
4274
|
+
markConsumedExports(targetIndex, symbolDemand);
|
|
4275
|
+
queue.push({
|
|
4276
|
+
moduleIndex: targetIndex,
|
|
4277
|
+
demandedSymbols: symbolDemand
|
|
4278
|
+
});
|
|
4279
|
+
}
|
|
4280
|
+
} else if (symbolDemand === "all" && (!existingConsumed || !existingConsumed.has("*"))) {
|
|
4281
|
+
markConsumedExports(targetIndex, "all");
|
|
4282
|
+
queue.push({
|
|
4283
|
+
moduleIndex: targetIndex,
|
|
4284
|
+
demandedSymbols: "all"
|
|
4285
|
+
});
|
|
4286
|
+
}
|
|
4287
|
+
}
|
|
4288
|
+
}
|
|
4289
|
+
}
|
|
4290
|
+
}
|
|
4291
|
+
const platformSiblingGroups = /* @__PURE__ */ new Map();
|
|
4292
|
+
const addToSiblingGroup = (groupKey, moduleIndex) => {
|
|
4293
|
+
const existingSiblings = platformSiblingGroups.get(groupKey);
|
|
4294
|
+
if (existingSiblings) existingSiblings.push(moduleIndex);
|
|
4295
|
+
else platformSiblingGroups.set(groupKey, [moduleIndex]);
|
|
4296
|
+
};
|
|
4297
|
+
for (let moduleIndex = 0; moduleIndex < totalModules; moduleIndex++) {
|
|
4298
|
+
const modulePath = graph.modules[moduleIndex].fileId.path;
|
|
4299
|
+
const basePathFromSuffix = stripPlatformSuffix(modulePath);
|
|
4300
|
+
if (basePathFromSuffix) addToSiblingGroup(basePathFromSuffix, moduleIndex);
|
|
4301
|
+
const basePathFromDirectory = stripPlatformDirectory(modulePath);
|
|
4302
|
+
if (basePathFromDirectory) addToSiblingGroup("dir:" + basePathFromDirectory, moduleIndex);
|
|
4303
|
+
}
|
|
4304
|
+
for (let moduleIndex = 0; moduleIndex < totalModules; moduleIndex++) {
|
|
4305
|
+
const modulePath = graph.modules[moduleIndex].fileId.path;
|
|
4306
|
+
if (platformSiblingGroups.has(modulePath)) platformSiblingGroups.get(modulePath).push(moduleIndex);
|
|
4307
|
+
}
|
|
4308
|
+
const platformQueue = [];
|
|
4309
|
+
for (const siblingIndices of platformSiblingGroups.values()) if (siblingIndices.some((index) => Boolean(visited[index]))) {
|
|
4310
|
+
for (const siblingIndex of siblingIndices) if (!visited[siblingIndex]) {
|
|
4311
|
+
visited[siblingIndex] = 1;
|
|
4312
|
+
platformQueue.push({
|
|
4313
|
+
moduleIndex: siblingIndex,
|
|
4314
|
+
demandedSymbols: "all"
|
|
4315
|
+
});
|
|
4316
|
+
}
|
|
4317
|
+
}
|
|
4318
|
+
let platformHeadPointer = 0;
|
|
4319
|
+
while (platformHeadPointer < platformQueue.length) {
|
|
4320
|
+
const { moduleIndex: currentIndex } = platformQueue[platformHeadPointer++];
|
|
4321
|
+
const outgoingEdges = outgoingEdgesMap.get(currentIndex);
|
|
4322
|
+
if (!outgoingEdges) continue;
|
|
4323
|
+
for (const edge of outgoingEdges) if (edge.target < totalModules && !visited[edge.target]) {
|
|
4324
|
+
visited[edge.target] = 1;
|
|
4325
|
+
platformQueue.push({
|
|
4326
|
+
moduleIndex: edge.target,
|
|
4327
|
+
demandedSymbols: "all"
|
|
4328
|
+
});
|
|
4329
|
+
}
|
|
4330
|
+
}
|
|
4331
|
+
for (let moduleIndex = 0; moduleIndex < totalModules; moduleIndex++) graph.modules[moduleIndex].isReachable = Boolean(visited[moduleIndex]);
|
|
4332
|
+
};
|
|
4333
|
+
|
|
4334
|
+
//#endregion
|
|
4335
|
+
//#region src/graph/re-exports.ts
|
|
4336
|
+
const propagateReExports = (graph) => {
|
|
4337
|
+
const sourceToTargets = buildSourceTargetMap(graph);
|
|
4338
|
+
const maxIterations = graph.modules.length * 2 + 1;
|
|
4339
|
+
let didChange = true;
|
|
4340
|
+
let iterationCount = 0;
|
|
4341
|
+
while (didChange && iterationCount < maxIterations) {
|
|
4342
|
+
didChange = false;
|
|
4343
|
+
iterationCount++;
|
|
4344
|
+
for (const module of graph.modules) {
|
|
4345
|
+
const originalExportCount = module.exports.length;
|
|
4346
|
+
for (let exportIndex = 0; exportIndex < originalExportCount; exportIndex++) {
|
|
4347
|
+
const exportInfo = module.exports[exportIndex];
|
|
4348
|
+
if (!exportInfo.isReExport || !exportInfo.reExportSource) continue;
|
|
4349
|
+
if (!exportInfo.isNamespaceReExport) continue;
|
|
4350
|
+
const targetIndices = sourceToTargets.get(module.fileId.index);
|
|
4351
|
+
if (!targetIndices) continue;
|
|
4352
|
+
for (const targetIndex of targetIndices) {
|
|
4353
|
+
const targetModule = graph.modules[targetIndex];
|
|
4354
|
+
if (!targetModule) continue;
|
|
4355
|
+
for (const targetExport of targetModule.exports) {
|
|
4356
|
+
if (targetExport.name === "*" && targetExport.isNamespaceReExport) continue;
|
|
4357
|
+
if (!module.exports.some((existingExport) => existingExport.name === targetExport.name && !existingExport.isNamespaceReExport)) {
|
|
4358
|
+
module.exports.push({
|
|
4359
|
+
name: targetExport.name,
|
|
4360
|
+
isDefault: targetExport.isDefault,
|
|
4361
|
+
isTypeOnly: targetExport.isTypeOnly || exportInfo.isTypeOnly,
|
|
4362
|
+
isReExport: true,
|
|
4363
|
+
isSynthetic: true,
|
|
4364
|
+
reExportSource: exportInfo.reExportSource,
|
|
4365
|
+
reExportOriginalName: targetExport.name,
|
|
4366
|
+
isNamespaceReExport: false,
|
|
4367
|
+
line: exportInfo.line,
|
|
4368
|
+
column: exportInfo.column
|
|
4369
|
+
});
|
|
4370
|
+
didChange = true;
|
|
4371
|
+
}
|
|
4372
|
+
}
|
|
4373
|
+
}
|
|
4374
|
+
}
|
|
4375
|
+
}
|
|
4376
|
+
}
|
|
4377
|
+
};
|
|
4378
|
+
const buildSourceTargetMap = (graph) => {
|
|
4379
|
+
const sourceTargets = /* @__PURE__ */ new Map();
|
|
4380
|
+
for (const edge of graph.edges) {
|
|
4381
|
+
const existing = sourceTargets.get(edge.source);
|
|
4382
|
+
if (existing) {
|
|
4383
|
+
if (!existing.includes(edge.target)) existing.push(edge.target);
|
|
4384
|
+
} else sourceTargets.set(edge.source, [edge.target]);
|
|
4385
|
+
}
|
|
4386
|
+
return sourceTargets;
|
|
4387
|
+
};
|
|
4388
|
+
|
|
4389
|
+
//#endregion
|
|
4390
|
+
//#region src/analyzer/unused-files.ts
|
|
4391
|
+
const isHtmlFile = (filePath) => {
|
|
4392
|
+
return filePath.endsWith(".html");
|
|
4393
|
+
};
|
|
4394
|
+
const findUnusedFiles = (graph) => {
|
|
4395
|
+
const unusedFiles = [];
|
|
4396
|
+
for (const module of graph.modules) {
|
|
4397
|
+
if (module.isReachable) continue;
|
|
4398
|
+
if (module.isEntryPoint) continue;
|
|
4399
|
+
if (module.isDeclarationFile) continue;
|
|
4400
|
+
if (module.isConfigFile) continue;
|
|
4401
|
+
if (isHtmlFile(module.fileId.path)) continue;
|
|
4402
|
+
if (isBarrelWithReachableSources(module, graph)) continue;
|
|
4403
|
+
if (hasReachableDirectImporter(module.fileId.index, graph)) continue;
|
|
4404
|
+
unusedFiles.push({ path: module.fileId.path });
|
|
4405
|
+
}
|
|
4406
|
+
return unusedFiles;
|
|
4407
|
+
};
|
|
4408
|
+
const isBarrelWithReachableSources = (module, graph) => {
|
|
4409
|
+
if (module.exports.length === 0) return false;
|
|
4410
|
+
if (!module.exports.every((exportInfo) => exportInfo.isNamespaceReExport || exportInfo.isSynthetic)) return false;
|
|
4411
|
+
for (const edge of graph.edges) if (edge.source === module.fileId.index) {
|
|
4412
|
+
if (graph.modules[edge.target]?.isReachable) return true;
|
|
4413
|
+
}
|
|
4414
|
+
return false;
|
|
4415
|
+
};
|
|
4416
|
+
const hasReachableDirectImporter = (targetModuleIndex, graph) => {
|
|
4417
|
+
for (const edge of graph.edges) {
|
|
4418
|
+
if (edge.target !== targetModuleIndex) continue;
|
|
4419
|
+
if (edge.isReExportEdge) continue;
|
|
4420
|
+
if (graph.modules[edge.source]?.isReachable) return true;
|
|
4421
|
+
}
|
|
4422
|
+
return false;
|
|
4423
|
+
};
|
|
4424
|
+
|
|
4425
|
+
//#endregion
|
|
4426
|
+
//#region src/analyzer/unused-exports.ts
|
|
4427
|
+
const findUnusedExports = (graph, config) => {
|
|
4428
|
+
const usageMap = buildUsageMap(graph);
|
|
4429
|
+
const unusedExports = [];
|
|
4430
|
+
for (const module of graph.modules) {
|
|
4431
|
+
if (!module.isReachable) continue;
|
|
4432
|
+
if (module.isDeclarationFile) continue;
|
|
4433
|
+
if (module.isEntryPoint && !config.includeEntryExports) continue;
|
|
4434
|
+
for (const exportInfo of module.exports) {
|
|
4435
|
+
if (exportInfo.name === "*" && exportInfo.isNamespaceReExport) continue;
|
|
4436
|
+
if (exportInfo.isReExport && exportInfo.reExportOriginalName) continue;
|
|
4437
|
+
if (!config.reportTypes && exportInfo.isTypeOnly) continue;
|
|
4438
|
+
const usageKey = `${module.fileId.path}::${exportInfo.name}`;
|
|
4439
|
+
if (!usageMap.has(usageKey)) unusedExports.push({
|
|
4440
|
+
path: module.fileId.path,
|
|
4441
|
+
name: exportInfo.name,
|
|
4442
|
+
line: exportInfo.line,
|
|
4443
|
+
column: exportInfo.column,
|
|
4444
|
+
isTypeOnly: exportInfo.isTypeOnly
|
|
4445
|
+
});
|
|
4446
|
+
}
|
|
4447
|
+
}
|
|
4448
|
+
return unusedExports;
|
|
4449
|
+
};
|
|
4450
|
+
const buildUsageMap = (graph) => {
|
|
4451
|
+
const usedExportKeys = /* @__PURE__ */ new Set();
|
|
4452
|
+
const sourceToTargetMap = buildSourceToTargetsMap(graph);
|
|
4453
|
+
for (const edge of graph.edges) {
|
|
4454
|
+
const targetModule = graph.modules[edge.target];
|
|
4455
|
+
if (!targetModule) continue;
|
|
4456
|
+
const sourceModule = graph.modules[edge.source];
|
|
4457
|
+
for (const symbol of edge.importedSymbols) if (symbol.isNamespace) handleNamespaceImport(sourceModule, targetModule, symbol.localName, graph, sourceToTargetMap, usedExportKeys);
|
|
4458
|
+
else {
|
|
4459
|
+
const importName = symbol.isDefault ? "default" : symbol.importedName;
|
|
4460
|
+
markExportUsedRecursive(targetModule.fileId.path, importName, graph, sourceToTargetMap, usedExportKeys, /* @__PURE__ */ new Set());
|
|
4461
|
+
}
|
|
4462
|
+
}
|
|
4463
|
+
return usedExportKeys;
|
|
4464
|
+
};
|
|
4465
|
+
const handleNamespaceImport = (sourceModule, targetModule, namespaceLocalName, graph, sourceToTargets, usedKeys) => {
|
|
4466
|
+
if (!sourceModule) {
|
|
4467
|
+
markAllExportsUsedRecursive(targetModule, graph, sourceToTargets, usedKeys, /* @__PURE__ */ new Set());
|
|
4468
|
+
return;
|
|
4469
|
+
}
|
|
4470
|
+
if (sourceModule.wholeObjectUses.includes(namespaceLocalName)) {
|
|
4471
|
+
markAllExportsUsedRecursive(targetModule, graph, sourceToTargets, usedKeys, /* @__PURE__ */ new Set());
|
|
4472
|
+
return;
|
|
4473
|
+
}
|
|
4474
|
+
const accessedMemberNames = extractAccessedMemberNames(sourceModule.memberAccesses, namespaceLocalName);
|
|
4475
|
+
const isNamespaceReExported = sourceModule.exports.some((exportInfo) => exportInfo.reExportOriginalName === namespaceLocalName || !exportInfo.isReExport && exportInfo.name === namespaceLocalName);
|
|
4476
|
+
if (accessedMemberNames.length === 0 && !isNamespaceReExported) {
|
|
4477
|
+
markAllExportsUsedRecursive(targetModule, graph, sourceToTargets, usedKeys, /* @__PURE__ */ new Set());
|
|
4478
|
+
return;
|
|
4479
|
+
}
|
|
4480
|
+
if (isNamespaceReExported && !sourceModule.isEntryPoint) {
|
|
4481
|
+
markAllExportsUsedRecursive(targetModule, graph, sourceToTargets, usedKeys, /* @__PURE__ */ new Set());
|
|
4482
|
+
return;
|
|
4483
|
+
}
|
|
4484
|
+
for (const memberName of accessedMemberNames) markExportUsedRecursive(targetModule.fileId.path, memberName, graph, sourceToTargets, usedKeys, /* @__PURE__ */ new Set());
|
|
4485
|
+
};
|
|
4486
|
+
const extractAccessedMemberNames = (memberAccesses, objectName) => {
|
|
4487
|
+
const memberNames = [];
|
|
4488
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
4489
|
+
for (const access of memberAccesses) if (access.objectName === objectName && !seenNames.has(access.memberName)) {
|
|
4490
|
+
seenNames.add(access.memberName);
|
|
4491
|
+
memberNames.push(access.memberName);
|
|
4492
|
+
}
|
|
4493
|
+
return memberNames;
|
|
4494
|
+
};
|
|
4495
|
+
const buildSourceToTargetsMap = (graph) => {
|
|
4496
|
+
const sourceToTargets = /* @__PURE__ */ new Map();
|
|
4497
|
+
for (const edge of graph.edges) {
|
|
4498
|
+
const existing = sourceToTargets.get(edge.source);
|
|
4499
|
+
if (existing) {
|
|
4500
|
+
if (!existing.includes(edge.target)) existing.push(edge.target);
|
|
4501
|
+
} else sourceToTargets.set(edge.source, [edge.target]);
|
|
4502
|
+
}
|
|
4503
|
+
return sourceToTargets;
|
|
4504
|
+
};
|
|
4505
|
+
const markAllExportsUsedRecursive = (module, graph, sourceToTargets, usedKeys, visited) => {
|
|
4506
|
+
const visitKey = `all::${module.fileId.path}`;
|
|
4507
|
+
if (visited.has(visitKey)) return;
|
|
4508
|
+
visited.add(visitKey);
|
|
4509
|
+
for (const exportInfo of module.exports) {
|
|
4510
|
+
if (exportInfo.name === "*" && exportInfo.isNamespaceReExport) continue;
|
|
4511
|
+
const usageKey = `${module.fileId.path}::${exportInfo.name}`;
|
|
4512
|
+
usedKeys.add(usageKey);
|
|
4513
|
+
if (exportInfo.isReExport && exportInfo.reExportSource) followReExportChain(module.fileId.index, exportInfo, graph, sourceToTargets, usedKeys, visited);
|
|
4514
|
+
}
|
|
4515
|
+
};
|
|
4516
|
+
const markExportUsedRecursive = (filePath, exportName, graph, sourceToTargets, usedKeys, visited) => {
|
|
4517
|
+
const visitKey = `${filePath}::${exportName}`;
|
|
4518
|
+
if (visited.has(visitKey)) return;
|
|
4519
|
+
visited.add(visitKey);
|
|
4520
|
+
usedKeys.add(visitKey);
|
|
4521
|
+
const moduleIndex = graph.fileIdMap.get(filePath);
|
|
4522
|
+
if (moduleIndex === void 0) return;
|
|
4523
|
+
const module = graph.modules[moduleIndex];
|
|
4524
|
+
if (!module) return;
|
|
4525
|
+
for (const exportInfo of module.exports) {
|
|
4526
|
+
if (exportInfo.name !== exportName) continue;
|
|
4527
|
+
if (exportInfo.isReExport && exportInfo.reExportSource) followReExportChain(moduleIndex, exportInfo, graph, sourceToTargets, usedKeys, visited);
|
|
4528
|
+
}
|
|
4529
|
+
};
|
|
4530
|
+
const followReExportChain = (reExporterModuleIndex, exportInfo, graph, sourceToTargets, usedKeys, visited) => {
|
|
4531
|
+
const targetIndices = sourceToTargets.get(reExporterModuleIndex);
|
|
4532
|
+
if (!targetIndices) return;
|
|
4533
|
+
const originalName = exportInfo.reExportOriginalName ?? exportInfo.name;
|
|
4534
|
+
for (const targetIndex of targetIndices) {
|
|
4535
|
+
const targetModule = graph.modules[targetIndex];
|
|
4536
|
+
if (!targetModule) continue;
|
|
4537
|
+
if (originalName === "*" || exportInfo.isNamespaceReExport) markExportUsedRecursive(targetModule.fileId.path, exportInfo.name, graph, sourceToTargets, usedKeys, visited);
|
|
4538
|
+
else if (targetModule.exports.some((targetExport) => targetExport.name === originalName || targetExport.isNamespaceReExport && targetExport.name === "*")) markExportUsedRecursive(targetModule.fileId.path, originalName, graph, sourceToTargets, usedKeys, visited);
|
|
4539
|
+
}
|
|
4540
|
+
};
|
|
4541
|
+
|
|
4542
|
+
//#endregion
|
|
4543
|
+
//#region src/utils/package-name.ts
|
|
4544
|
+
const extractPackageName = (specifier) => {
|
|
4545
|
+
if (specifier.startsWith(".") || specifier.startsWith("/")) return void 0;
|
|
4546
|
+
if (specifier.startsWith("node:")) return void 0;
|
|
4547
|
+
if (specifier.startsWith("@")) {
|
|
4548
|
+
const parts = specifier.split("/");
|
|
4549
|
+
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : void 0;
|
|
4550
|
+
}
|
|
4551
|
+
return specifier.split("/")[0];
|
|
4552
|
+
};
|
|
4553
|
+
|
|
4554
|
+
//#endregion
|
|
4555
|
+
//#region src/analyzer/unused-dependencies.ts
|
|
4556
|
+
const findUnusedDependencies = (graph, config) => {
|
|
4557
|
+
const packageJsonPath = resolve(config.rootDir, "package.json");
|
|
4558
|
+
let packageJson;
|
|
4559
|
+
try {
|
|
4560
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
4561
|
+
packageJson = JSON.parse(content);
|
|
4562
|
+
} catch {
|
|
4563
|
+
return [];
|
|
4564
|
+
}
|
|
4565
|
+
const dependencies = packageJson.dependencies ?? {};
|
|
4566
|
+
const devDependencies = packageJson.devDependencies ?? {};
|
|
4567
|
+
const declaredDependencies = /* @__PURE__ */ new Map();
|
|
4568
|
+
for (const dependencyName of Object.keys(dependencies)) declaredDependencies.set(dependencyName, false);
|
|
4569
|
+
for (const dependencyName of Object.keys(devDependencies)) declaredDependencies.set(dependencyName, true);
|
|
4570
|
+
const usedPackageNames = collectUsedPackages(graph);
|
|
4571
|
+
const unusedDependencies = [];
|
|
4572
|
+
for (const [dependencyName, isDevDependency] of declaredDependencies) {
|
|
4573
|
+
if (isAlwaysConsideredUsed(dependencyName)) continue;
|
|
4574
|
+
if (!usedPackageNames.has(dependencyName)) unusedDependencies.push({
|
|
4575
|
+
name: dependencyName,
|
|
4576
|
+
isDevDependency
|
|
4577
|
+
});
|
|
4578
|
+
}
|
|
4579
|
+
return unusedDependencies;
|
|
4580
|
+
};
|
|
4581
|
+
const collectUsedPackages = (graph) => {
|
|
4582
|
+
const usedPackages = /* @__PURE__ */ new Set();
|
|
4583
|
+
for (const module of graph.modules) for (const importInfo of module.imports) {
|
|
4584
|
+
const packageName = extractPackageName(importInfo.specifier);
|
|
4585
|
+
if (packageName) usedPackages.add(packageName);
|
|
4586
|
+
}
|
|
4587
|
+
return usedPackages;
|
|
4588
|
+
};
|
|
4589
|
+
const isAlwaysConsideredUsed = (dependencyName) => {
|
|
4590
|
+
if (ALWAYS_USED_PACKAGES.has(dependencyName)) return true;
|
|
4591
|
+
if (dependencyName.startsWith("@types/")) return true;
|
|
4592
|
+
if (dependencyName.startsWith("eslint-config-")) return true;
|
|
4593
|
+
if (dependencyName.startsWith("eslint-plugin-")) return true;
|
|
4594
|
+
if (dependencyName.startsWith("prettier-plugin-")) return true;
|
|
4595
|
+
return false;
|
|
4596
|
+
};
|
|
4597
|
+
|
|
4598
|
+
//#endregion
|
|
4599
|
+
//#region src/analyzer/circular-deps.ts
|
|
4600
|
+
const UNDEFINED_INDEX = -1;
|
|
4601
|
+
const buildAdjacencyList = (graph) => {
|
|
4602
|
+
const targetSets = Array.from({ length: graph.modules.length }, () => /* @__PURE__ */ new Set());
|
|
4603
|
+
for (const edge of graph.edges) {
|
|
4604
|
+
if (edge.importedSymbols.every((symbol) => symbol.isTypeOnly)) continue;
|
|
4605
|
+
if (edge.target < graph.modules.length) targetSets[edge.source].add(edge.target);
|
|
4606
|
+
}
|
|
4607
|
+
return targetSets.map((targets) => [...targets]);
|
|
4608
|
+
};
|
|
4609
|
+
const findStronglyConnectedComponents = (adjacencyList) => {
|
|
4610
|
+
const nodeCount = adjacencyList.length;
|
|
4611
|
+
if (nodeCount === 0) return [];
|
|
4612
|
+
const state = {
|
|
4613
|
+
indexCounter: 0,
|
|
4614
|
+
indices: Array(nodeCount).fill(UNDEFINED_INDEX),
|
|
4615
|
+
lowlinks: Array(nodeCount).fill(0),
|
|
4616
|
+
onStack: Array(nodeCount).fill(false),
|
|
4617
|
+
stack: []
|
|
4618
|
+
};
|
|
4619
|
+
const components = [];
|
|
4620
|
+
const dfsStack = [];
|
|
4621
|
+
for (let startNode = 0; startNode < nodeCount; startNode++) {
|
|
4622
|
+
if (state.indices[startNode] !== UNDEFINED_INDEX) continue;
|
|
4623
|
+
state.indices[startNode] = state.indexCounter;
|
|
4624
|
+
state.lowlinks[startNode] = state.indexCounter;
|
|
4625
|
+
state.indexCounter++;
|
|
4626
|
+
state.onStack[startNode] = true;
|
|
4627
|
+
state.stack.push(startNode);
|
|
4628
|
+
dfsStack.push({
|
|
4629
|
+
node: startNode,
|
|
4630
|
+
successorPosition: 0
|
|
4631
|
+
});
|
|
4632
|
+
while (dfsStack.length > 0) {
|
|
4633
|
+
const frame = dfsStack[dfsStack.length - 1];
|
|
4634
|
+
const successors = adjacencyList[frame.node];
|
|
4635
|
+
if (frame.successorPosition < successors.length) {
|
|
4636
|
+
const successor = successors[frame.successorPosition];
|
|
4637
|
+
frame.successorPosition++;
|
|
4638
|
+
if (state.indices[successor] === UNDEFINED_INDEX) {
|
|
4639
|
+
state.indices[successor] = state.indexCounter;
|
|
4640
|
+
state.lowlinks[successor] = state.indexCounter;
|
|
4641
|
+
state.indexCounter++;
|
|
4642
|
+
state.onStack[successor] = true;
|
|
4643
|
+
state.stack.push(successor);
|
|
4644
|
+
dfsStack.push({
|
|
4645
|
+
node: successor,
|
|
4646
|
+
successorPosition: 0
|
|
4647
|
+
});
|
|
4648
|
+
} else if (state.onStack[successor]) state.lowlinks[frame.node] = Math.min(state.lowlinks[frame.node], state.indices[successor]);
|
|
4649
|
+
} else {
|
|
4650
|
+
const currentNode = frame.node;
|
|
4651
|
+
const currentLowlink = state.lowlinks[currentNode];
|
|
4652
|
+
const currentIndex = state.indices[currentNode];
|
|
4653
|
+
dfsStack.pop();
|
|
4654
|
+
if (dfsStack.length > 0) {
|
|
4655
|
+
const parentFrame = dfsStack[dfsStack.length - 1];
|
|
4656
|
+
state.lowlinks[parentFrame.node] = Math.min(state.lowlinks[parentFrame.node], currentLowlink);
|
|
4657
|
+
}
|
|
4658
|
+
if (currentLowlink === currentIndex) {
|
|
4659
|
+
const component = [];
|
|
4660
|
+
let poppedNode;
|
|
4661
|
+
do {
|
|
4662
|
+
poppedNode = state.stack.pop();
|
|
4663
|
+
state.onStack[poppedNode] = false;
|
|
4664
|
+
component.push(poppedNode);
|
|
4665
|
+
} while (poppedNode !== currentNode);
|
|
4666
|
+
if (component.length >= 2) components.push(component);
|
|
4667
|
+
}
|
|
4668
|
+
}
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4671
|
+
return components;
|
|
4672
|
+
};
|
|
4673
|
+
const canonicalizeCycle = (cycle, graph) => {
|
|
4674
|
+
if (cycle.length === 0) return [];
|
|
4675
|
+
let minPosition = 0;
|
|
4676
|
+
let minPath = graph.modules[cycle[0]].fileId.path;
|
|
4677
|
+
for (let position = 1; position < cycle.length; position++) {
|
|
4678
|
+
const currentPath = graph.modules[cycle[position]].fileId.path;
|
|
4679
|
+
if (currentPath < minPath) {
|
|
4680
|
+
minPath = currentPath;
|
|
4681
|
+
minPosition = position;
|
|
4682
|
+
}
|
|
4683
|
+
}
|
|
4684
|
+
return [...cycle.slice(minPosition), ...cycle.slice(0, minPosition)];
|
|
4685
|
+
};
|
|
4686
|
+
const enumerateElementaryCycles = (componentNodes, adjacencyList, graph) => {
|
|
4687
|
+
if (componentNodes.length === 2) {
|
|
4688
|
+
const [nodeA, nodeB] = componentNodes;
|
|
4689
|
+
return [graph.modules[nodeA].fileId.path <= graph.modules[nodeB].fileId.path ? [nodeA, nodeB] : [nodeB, nodeA]];
|
|
4690
|
+
}
|
|
4691
|
+
const componentSet = new Set(componentNodes);
|
|
4692
|
+
const cycles = [];
|
|
4693
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
4694
|
+
for (const startNode of componentNodes) {
|
|
4695
|
+
if (cycles.length >= 20) break;
|
|
4696
|
+
const visitedInThisSearch = /* @__PURE__ */ new Set();
|
|
4697
|
+
visitedInThisSearch.add(startNode);
|
|
4698
|
+
const pathStack = [startNode];
|
|
4699
|
+
const successorPositionStack = [0];
|
|
4700
|
+
while (pathStack.length > 0 && cycles.length < 20) {
|
|
4701
|
+
const currentNode = pathStack[pathStack.length - 1];
|
|
4702
|
+
const currentSuccessorPosition = successorPositionStack[successorPositionStack.length - 1];
|
|
4703
|
+
const successors = adjacencyList[currentNode].filter((successor) => componentSet.has(successor));
|
|
4704
|
+
if (currentSuccessorPosition < successors.length) {
|
|
4705
|
+
successorPositionStack[successorPositionStack.length - 1]++;
|
|
4706
|
+
const successor = successors[currentSuccessorPosition];
|
|
4707
|
+
if (successor === startNode) {
|
|
4708
|
+
const canonical = canonicalizeCycle([...pathStack], graph);
|
|
4709
|
+
const key = canonical.join(",");
|
|
4710
|
+
if (!seenKeys.has(key)) {
|
|
4711
|
+
seenKeys.add(key);
|
|
4712
|
+
cycles.push(canonical);
|
|
4713
|
+
}
|
|
4714
|
+
} else if (!visitedInThisSearch.has(successor)) {
|
|
4715
|
+
visitedInThisSearch.add(successor);
|
|
4716
|
+
pathStack.push(successor);
|
|
4717
|
+
successorPositionStack.push(0);
|
|
4718
|
+
}
|
|
4719
|
+
} else {
|
|
4720
|
+
visitedInThisSearch.delete(pathStack.pop());
|
|
4721
|
+
successorPositionStack.pop();
|
|
4722
|
+
}
|
|
4723
|
+
}
|
|
4724
|
+
}
|
|
4725
|
+
return cycles;
|
|
4726
|
+
};
|
|
4727
|
+
const findCircularDependencies = (graph) => {
|
|
4728
|
+
const adjacencyList = buildAdjacencyList(graph);
|
|
4729
|
+
const components = findStronglyConnectedComponents(adjacencyList);
|
|
4730
|
+
const allCycles = [];
|
|
4731
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
4732
|
+
const sortedComponents = [...components].sort((componentA, componentB) => componentA.length - componentB.length);
|
|
4733
|
+
for (const component of sortedComponents) {
|
|
4734
|
+
if (allCycles.length >= 200) break;
|
|
4735
|
+
if (component.length > 50) continue;
|
|
4736
|
+
const elementaryCycles = enumerateElementaryCycles(component, adjacencyList, graph);
|
|
4737
|
+
for (const cycle of elementaryCycles) {
|
|
4738
|
+
const key = cycle.join(",");
|
|
4739
|
+
if (!seenKeys.has(key)) {
|
|
4740
|
+
seenKeys.add(key);
|
|
4741
|
+
allCycles.push(cycle);
|
|
4742
|
+
}
|
|
4743
|
+
if (allCycles.length >= 200) break;
|
|
4744
|
+
}
|
|
4745
|
+
}
|
|
4746
|
+
allCycles.sort((cycleA, cycleB) => {
|
|
4747
|
+
const lengthDiff = cycleA.length - cycleB.length;
|
|
4748
|
+
if (lengthDiff !== 0) return lengthDiff;
|
|
4749
|
+
return graph.modules[cycleA[0]].fileId.path.localeCompare(graph.modules[cycleB[0]].fileId.path);
|
|
4750
|
+
});
|
|
4751
|
+
return allCycles.map((cycle) => ({ files: cycle.map((nodeIndex) => graph.modules[nodeIndex].fileId.path) }));
|
|
4752
|
+
};
|
|
4753
|
+
|
|
4754
|
+
//#endregion
|
|
4755
|
+
//#region src/analyzer/analyze.ts
|
|
4756
|
+
const analyzeGraph = (graph, config) => {
|
|
4757
|
+
const analysisStartTime = performance.now();
|
|
4758
|
+
const unusedFiles = findUnusedFiles(graph);
|
|
4759
|
+
const unusedExports = findUnusedExports(graph, config);
|
|
4760
|
+
const unusedDependencies = findUnusedDependencies(graph, config);
|
|
4761
|
+
const circularDependencies = findCircularDependencies(graph);
|
|
4762
|
+
const totalExports = graph.modules.reduce((exportCount, module) => exportCount + module.exports.filter((exportInfo) => !(exportInfo.name === "*" && exportInfo.isNamespaceReExport)).length, 0);
|
|
4763
|
+
return {
|
|
4764
|
+
unusedFiles,
|
|
4765
|
+
unusedExports,
|
|
4766
|
+
unusedDependencies,
|
|
4767
|
+
circularDependencies,
|
|
4768
|
+
totalFiles: graph.modules.length,
|
|
4769
|
+
totalExports,
|
|
4770
|
+
analysisTimeMs: performance.now() - analysisStartTime
|
|
4771
|
+
};
|
|
4772
|
+
};
|
|
4773
|
+
|
|
4774
|
+
//#endregion
|
|
4775
|
+
//#region src/index.ts
|
|
4776
|
+
const STYLE_EXTENSIONS = [".css", ".scss"];
|
|
4777
|
+
const REACT_NATIVE_ENABLERS = ["react-native", "expo"];
|
|
4778
|
+
const detectReactNative = (rootDir, workspacePackages) => {
|
|
4779
|
+
const directoriesToCheck = [rootDir, ...workspacePackages.map((workspacePackage) => workspacePackage.directory)];
|
|
4780
|
+
for (const directory of directoriesToCheck) {
|
|
4781
|
+
const packageJsonPath = resolve(directory, "package.json");
|
|
4782
|
+
if (!existsSync(packageJsonPath)) continue;
|
|
4783
|
+
try {
|
|
4784
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
4785
|
+
const packageJson = JSON.parse(content);
|
|
4786
|
+
const allDependencies = {
|
|
4787
|
+
...packageJson.dependencies,
|
|
4788
|
+
...packageJson.devDependencies,
|
|
4789
|
+
...packageJson.optionalDependencies
|
|
4790
|
+
};
|
|
4791
|
+
if (REACT_NATIVE_ENABLERS.some((enabler) => enabler in allDependencies)) return true;
|
|
4792
|
+
} catch {
|
|
4793
|
+
continue;
|
|
4794
|
+
}
|
|
4795
|
+
}
|
|
4796
|
+
return false;
|
|
4797
|
+
};
|
|
4798
|
+
const createConfig = (options) => ({
|
|
4799
|
+
rootDir: resolve(options.rootDir),
|
|
4800
|
+
entryPatterns: options.entryPatterns ?? DEFAULT_ENTRY_PATTERNS,
|
|
4801
|
+
ignorePatterns: options.ignorePatterns ?? [],
|
|
4802
|
+
includeExtensions: options.includeExtensions ?? DEFAULT_EXTENSIONS,
|
|
4803
|
+
tsConfigPath: options.tsConfigPath ?? void 0,
|
|
4804
|
+
reportTypes: options.reportTypes ?? false,
|
|
4805
|
+
includeEntryExports: options.includeEntryExports ?? false
|
|
4806
|
+
});
|
|
4807
|
+
const analyze = async (config) => {
|
|
4808
|
+
const pipelineStartTime = performance.now();
|
|
4809
|
+
const workspaceDiscovery = discoverWorkspacePackagesWithExclusions(resolve(config.rootDir));
|
|
4810
|
+
const workspacePackages = workspaceDiscovery.packages;
|
|
4811
|
+
const frameworkIgnorePatterns = discoverFrameworkIgnorePatterns(config.rootDir);
|
|
4812
|
+
const absoluteRoot = resolve(config.rootDir);
|
|
4813
|
+
const outputDirectoryExclusions = OUTPUT_DIRECTORIES.flatMap((outputDirectory) => {
|
|
4814
|
+
const exclusions = [`${absoluteRoot}/${outputDirectory}/**`];
|
|
4815
|
+
for (const workspacePackage of workspacePackages) exclusions.push(`${workspacePackage.directory}/${outputDirectory}/**`);
|
|
4816
|
+
return exclusions;
|
|
4817
|
+
});
|
|
4818
|
+
const allExclusionPatterns = [
|
|
4819
|
+
...workspaceDiscovery.excludedDirectories.map((directory) => `${directory}/**`),
|
|
4820
|
+
...frameworkIgnorePatterns,
|
|
4821
|
+
...outputDirectoryExclusions
|
|
4822
|
+
];
|
|
4823
|
+
const configWithExclusions = allExclusionPatterns.length > 0 ? {
|
|
4824
|
+
...config,
|
|
4825
|
+
ignorePatterns: [...config.ignorePatterns, ...allExclusionPatterns]
|
|
4826
|
+
} : config;
|
|
4827
|
+
const files = await discoverFiles(configWithExclusions);
|
|
4828
|
+
const discoveredEntries = await discoverEntryPoints(configWithExclusions);
|
|
4829
|
+
const productionEntrySet = new Set(discoveredEntries.productionEntries);
|
|
4830
|
+
const testEntrySet = new Set(discoveredEntries.testEntries);
|
|
4831
|
+
const alwaysUsedFileSet = new Set(discoveredEntries.alwaysUsedFiles);
|
|
4832
|
+
const hasReactNative = detectReactNative(config.rootDir, workspacePackages);
|
|
4833
|
+
const moduleResolver = createModuleResolver(config, workspacePackages.map((workspacePackage) => ({
|
|
4834
|
+
name: workspacePackage.name,
|
|
4835
|
+
directory: workspacePackage.directory
|
|
4836
|
+
})), { hasReactNative });
|
|
4837
|
+
const graphInputs = [];
|
|
4838
|
+
for (const file of files) {
|
|
4839
|
+
const parsedModule = parseModule(file.path);
|
|
4840
|
+
const resolvedImportMap = /* @__PURE__ */ new Map();
|
|
4841
|
+
for (const importInfo of parsedModule.imports) {
|
|
4842
|
+
if (importInfo.isGlob) {
|
|
4843
|
+
const fileDir = dirname(file.path);
|
|
4844
|
+
const expandedFiles = fg.sync(importInfo.specifier, {
|
|
4845
|
+
cwd: fileDir,
|
|
4846
|
+
absolute: true,
|
|
4847
|
+
onlyFiles: true,
|
|
4848
|
+
ignore: ["**/node_modules/**"]
|
|
4849
|
+
});
|
|
4850
|
+
for (const expandedFile of expandedFiles) resolvedImportMap.set(expandedFile, {
|
|
4851
|
+
resolvedPath: expandedFile,
|
|
4852
|
+
isExternal: false,
|
|
4853
|
+
packageName: void 0
|
|
4854
|
+
});
|
|
4855
|
+
resolvedImportMap.set(importInfo.specifier, {
|
|
4856
|
+
resolvedPath: void 0,
|
|
4857
|
+
isExternal: false,
|
|
4858
|
+
packageName: void 0
|
|
4859
|
+
});
|
|
4860
|
+
continue;
|
|
4861
|
+
}
|
|
4862
|
+
const resolvedImport = moduleResolver.resolveModule(importInfo.specifier, file.path);
|
|
4863
|
+
resolvedImportMap.set(importInfo.specifier, resolvedImport);
|
|
4864
|
+
}
|
|
4865
|
+
for (const exportInfo of parsedModule.exports) if (exportInfo.isReExport && exportInfo.reExportSource) {
|
|
4866
|
+
if (!resolvedImportMap.has(exportInfo.reExportSource)) {
|
|
4867
|
+
const resolvedImport = moduleResolver.resolveModule(exportInfo.reExportSource, file.path);
|
|
4868
|
+
resolvedImportMap.set(exportInfo.reExportSource, resolvedImport);
|
|
4869
|
+
}
|
|
4870
|
+
}
|
|
4871
|
+
const isAlwaysUsed = alwaysUsedFileSet.has(file.path);
|
|
4872
|
+
graphInputs.push({
|
|
4873
|
+
fileId: file,
|
|
4874
|
+
parsed: parsedModule,
|
|
4875
|
+
resolvedImports: resolvedImportMap,
|
|
4876
|
+
isEntryPoint: isAlwaysUsed || productionEntrySet.has(file.path) || testEntrySet.has(file.path),
|
|
4877
|
+
isTestEntry: testEntrySet.has(file.path)
|
|
4878
|
+
});
|
|
4879
|
+
}
|
|
4880
|
+
const discoveredFilePaths = new Set(files.map((file) => file.path));
|
|
4881
|
+
const styleFilesToAdd = /* @__PURE__ */ new Set();
|
|
4882
|
+
for (const input of graphInputs) for (const [, resolvedImport] of input.resolvedImports) {
|
|
4883
|
+
if (!resolvedImport.resolvedPath || resolvedImport.isExternal) continue;
|
|
4884
|
+
if (discoveredFilePaths.has(resolvedImport.resolvedPath)) continue;
|
|
4885
|
+
if (STYLE_EXTENSIONS.some((ext) => resolvedImport.resolvedPath.endsWith(ext)) && existsSync(resolvedImport.resolvedPath)) styleFilesToAdd.add(resolvedImport.resolvedPath);
|
|
4886
|
+
}
|
|
4887
|
+
const sortedStyleFiles = [...styleFilesToAdd].sort();
|
|
4888
|
+
let nextFileIndex = files.length;
|
|
4889
|
+
for (const styleFilePath of sortedStyleFiles) {
|
|
4890
|
+
const styleFileId = {
|
|
4891
|
+
index: nextFileIndex,
|
|
4892
|
+
path: styleFilePath
|
|
4893
|
+
};
|
|
4894
|
+
const parsedStyleModule = parseModule(styleFilePath);
|
|
4895
|
+
const resolvedStyleImportMap = /* @__PURE__ */ new Map();
|
|
4896
|
+
for (const importInfo of parsedStyleModule.imports) {
|
|
4897
|
+
const resolvedImport = moduleResolver.resolveModule(importInfo.specifier, styleFilePath);
|
|
4898
|
+
resolvedStyleImportMap.set(importInfo.specifier, resolvedImport);
|
|
4899
|
+
if (resolvedImport.resolvedPath && !discoveredFilePaths.has(resolvedImport.resolvedPath)) {
|
|
4900
|
+
if (STYLE_EXTENSIONS.some((ext) => resolvedImport.resolvedPath.endsWith(ext)) && existsSync(resolvedImport.resolvedPath)) styleFilesToAdd.add(resolvedImport.resolvedPath);
|
|
4901
|
+
}
|
|
4902
|
+
}
|
|
4903
|
+
graphInputs.push({
|
|
4904
|
+
fileId: styleFileId,
|
|
4905
|
+
parsed: parsedStyleModule,
|
|
4906
|
+
resolvedImports: resolvedStyleImportMap,
|
|
4907
|
+
isEntryPoint: false,
|
|
4908
|
+
isTestEntry: false
|
|
4909
|
+
});
|
|
4910
|
+
discoveredFilePaths.add(styleFilePath);
|
|
4911
|
+
nextFileIndex++;
|
|
4912
|
+
}
|
|
4913
|
+
const moduleGraph = buildModuleGraph(graphInputs);
|
|
4914
|
+
propagateReExports(moduleGraph);
|
|
4915
|
+
markReachable(moduleGraph);
|
|
4916
|
+
const analysisResult = analyzeGraph(moduleGraph, config);
|
|
4917
|
+
analysisResult.analysisTimeMs = performance.now() - pipelineStartTime;
|
|
4918
|
+
return analysisResult;
|
|
4919
|
+
};
|
|
4920
|
+
|
|
4921
|
+
//#endregion
|
|
4922
|
+
export { createConfig as n, analyze as t };
|