deslop-js 0.6.2 → 0.7.0

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/dist/index.cjs CHANGED
@@ -26,6 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  }) : target, mod));
27
27
 
28
28
  //#endregion
29
+ const require_constants = require('./constants-CD9NXHxi.cjs');
29
30
  let node_path = require("node:path");
30
31
  node_path = __toESM(node_path, 1);
31
32
  let node_fs = require("node:fs");
@@ -36,327 +37,20 @@ let oxc_parser = require("oxc-parser");
36
37
  let typescript = require("typescript");
37
38
  typescript = __toESM(typescript, 1);
38
39
  let oxc_resolver = require("oxc-resolver");
39
- let node_worker_threads = require("node:worker_threads");
40
- let node_url = require("node:url");
41
40
  let node_os = require("node:os");
42
41
  node_os = __toESM(node_os, 1);
42
+ let node_worker_threads = require("node:worker_threads");
43
+ let node_url = require("node:url");
43
44
  let minimatch = require("minimatch");
45
+ let node_crypto = require("node:crypto");
46
+ node_crypto = __toESM(node_crypto, 1);
47
+ let node_module = require("node:module");
44
48
  let node_child_process = require("node:child_process");
45
49
 
46
- //#region src/constants.ts
47
- const DEFAULT_EXTENSIONS = [
48
- ".ts",
49
- ".tsx",
50
- ".js",
51
- ".jsx",
52
- ".mts",
53
- ".mjs",
54
- ".cts",
55
- ".cjs",
56
- ".mdx",
57
- ".astro",
58
- ".graphql",
59
- ".gql",
60
- ".css",
61
- ".scss",
62
- ".vue",
63
- ".svelte"
64
- ];
65
- const HIDDEN_DIRECTORY_ALLOWLIST = [
66
- ".storybook",
67
- ".vitepress",
68
- ".well-known",
69
- ".changeset",
70
- ".github",
71
- ".client",
72
- ".server"
73
- ];
74
- const OUTPUT_DIRECTORIES = [
75
- "dist",
76
- "build",
77
- "out",
78
- "esm",
79
- "cjs"
80
- ];
81
- const SOURCE_EXTENSIONS$3 = [
82
- "ts",
83
- "tsx",
84
- "mts",
85
- "cts",
86
- "js",
87
- "jsx",
88
- "mjs",
89
- "cjs"
90
- ];
91
- const DEFAULT_EXCLUSIONS = [
92
- "**/node_modules/**",
93
- "**/.git/**",
94
- "**/coverage/**",
95
- "**/*.min.js",
96
- "**/*.min.mjs",
97
- "**/mockServiceWorker.js"
98
- ];
99
- const SCRIPT_FILE_PATTERN = /(?:^|\s)(?:node|tsx|ts-node|tsc|npx|bun|esr|esno|jiti|babel-node|zx)\s+(?:\S+\s+)*?([\w./@-]+\.(?:ts|tsx|js|jsx|mts|mjs|cts|cjs))(?:\s|$)/;
100
- const SCRIPT_EXTENSIONLESS_FILE_PATTERN = /(?:^|\s)(?:node|tsx|ts-node|bun|esr|esno|jiti|babel-node|zx)\s+(?:\S+\s+)*?((?:[./]|[\w@][\w@-]*\/)[\w./@-]+)(?:\s|$)/;
101
- const SCRIPT_CONFIG_FILE_PATTERN = /--config\s+([\w./@-]+\.(?:ts|tsx|js|jsx|mts|mjs|cts|cjs))/;
102
- const SCRIPT_ENTRY_PATTERNS = [];
103
- const DEFAULT_ENTRY_GLOBS = [
104
- "src/index.{ts,tsx,js,jsx}",
105
- "src/main.{ts,tsx,js,jsx}",
106
- "index.{ts,tsx,js,jsx}",
107
- "main.{ts,tsx,js,jsx}"
108
- ];
109
- const KNOWN_CONFIG_PREFIXES = [
110
- "babel.config.",
111
- "rollup.config.",
112
- "webpack.config.",
113
- "postcss.config.",
114
- "stencil.config.",
115
- "remotion.config.",
116
- "metro.config.",
117
- "tsup.config.",
118
- "tsdown.config.",
119
- "unbuild.config.",
120
- "esbuild.config.",
121
- "swc.config.",
122
- "turbo.",
123
- "jest.config.",
124
- "jest.setup.",
125
- "vitest.config.",
126
- "vitest.ci.config.",
127
- "vitest.setup.",
128
- "vitest.workspace.",
129
- "playwright.config.",
130
- "cypress.config.",
131
- "karma.conf.",
132
- "eslint.config.",
133
- "prettier.config.",
134
- "stylelint.config.",
135
- "lint-staged.config.",
136
- "commitlint.config.",
137
- "next.config.",
138
- "next-sitemap.config.",
139
- "nuxt.config.",
140
- "astro.config.",
141
- "sanity.config.",
142
- "vite.config.",
143
- "tailwind.config.",
144
- "drizzle.config.",
145
- "knexfile.",
146
- "sentry.client.config.",
147
- "sentry.server.config.",
148
- "sentry.edge.config.",
149
- "react-router.config.",
150
- "typedoc.",
151
- "deslop.config.",
152
- "i18next-parser.config.",
153
- "codegen.config.",
154
- "graphql.config.",
155
- "npmpackagejsonlint.config.",
156
- "release-it.",
157
- "release.config.",
158
- "contentlayer.config.",
159
- "rspack.config.",
160
- "rsbuild.config.",
161
- "module-federation.config.",
162
- "vercel.",
163
- "next-env.d.",
164
- "env.d.",
165
- "vite-env.d."
166
- ];
167
- const IMPLICIT_DEPENDENCIES = new Set([
168
- "typescript",
169
- "@types/node",
170
- "@types/react",
171
- "@types/react-dom",
172
- "eslint",
173
- "prettier",
174
- "husky",
175
- "lint-staged",
176
- "tslib",
177
- "@babel/core",
178
- "@babel/runtime",
179
- "babel-core",
180
- "babel-jest",
181
- "babel-loader",
182
- "postcss",
183
- "cross-env",
184
- "sass",
185
- "node-sass",
186
- "less",
187
- "oxlint",
188
- "biome",
189
- "@biomejs/biome",
190
- "patch-package",
191
- "simple-git-hooks",
192
- "lefthook",
193
- "ts-node",
194
- "ts-jest",
195
- "tsx",
196
- "jsdom",
197
- "rimraf",
198
- "concurrently",
199
- "npm-run-all",
200
- "npm-run-all2",
201
- "dotenv-cli",
202
- "webpack",
203
- "rollup",
204
- "terser",
205
- "autoprefixer",
206
- "tailwindcss",
207
- "react-test-renderer",
208
- "esbuild",
209
- "typedoc",
210
- "commitizen",
211
- "cz-conventional-changelog"
212
- ]);
213
- const BUILTIN_MODULES = new Set([
214
- "assert",
215
- "async_hooks",
216
- "buffer",
217
- "child_process",
218
- "cluster",
219
- "console",
220
- "constants",
221
- "crypto",
222
- "dgram",
223
- "diagnostics_channel",
224
- "dns",
225
- "domain",
226
- "events",
227
- "fs",
228
- "http",
229
- "http2",
230
- "https",
231
- "inspector",
232
- "module",
233
- "net",
234
- "os",
235
- "path",
236
- "perf_hooks",
237
- "process",
238
- "punycode",
239
- "querystring",
240
- "readline",
241
- "repl",
242
- "stream",
243
- "string_decoder",
244
- "sys",
245
- "timers",
246
- "tls",
247
- "trace_events",
248
- "tty",
249
- "url",
250
- "util",
251
- "v8",
252
- "vm",
253
- "wasi",
254
- "worker_threads",
255
- "zlib"
256
- ]);
257
- const PLATFORM_SUFFIXES = [
258
- ".web",
259
- ".react-native",
260
- ".native",
261
- ".ios",
262
- ".android",
263
- ".desktop",
264
- ".windows",
265
- ".macos",
266
- ".any",
267
- ".react-server",
268
- ".server",
269
- ".client"
270
- ];
271
- const REACT_NATIVE_PLATFORM_EXTENSIONS = [
272
- ".web.ts",
273
- ".web.tsx",
274
- ".web.js",
275
- ".web.jsx",
276
- ".native.ts",
277
- ".native.tsx",
278
- ".native.js",
279
- ".native.jsx",
280
- ".ios.ts",
281
- ".ios.tsx",
282
- ".ios.js",
283
- ".ios.jsx",
284
- ".android.ts",
285
- ".android.tsx",
286
- ".android.js",
287
- ".android.jsx"
288
- ];
289
- const RESOLVER_EXTENSIONS = [
290
- ...DEFAULT_EXTENSIONS,
291
- ".d.ts",
292
- ".d.mts",
293
- ".d.cts",
294
- ".json",
295
- ".node",
296
- ".css",
297
- ".scss",
298
- ".less",
299
- ".svg",
300
- ".png",
301
- ".jpg",
302
- ".graphql",
303
- ".gql"
304
- ];
305
- const SEMANTIC_MAX_PROGRAM_FILES = 5e3;
306
- const MAX_PARSE_FILE_SIZE_BYTES = 2e6;
307
- const MAX_ANALYSIS_ERRORS = 5e3;
308
- const MAX_ERROR_DETAIL_LENGTH = 1e3;
309
- const BINARY_DETECTION_SAMPLE_BYTES = 2048;
310
- const MINIFIED_DETECTION_MIN_BYTES = 5e3;
311
- /**
312
- * Numeric literals below 1000 are dominated by indices, counters, small
313
- * ranges, ports, percentages, and array sizes that coincide by accident
314
- * (every `MAX_RETRIES = 3` is not a duplicate of every `LIMIT = 3`).
315
- * 1000 admits real shared constants (timeouts in ms, byte sizes, polling
316
- * intervals) without producing the noise floor that smaller magnitudes do.
317
- * NOTE: even at 1000, the rule still produces medium-confidence false
318
- * positives when constants share a value coincidentally with different
319
- * names (e.g. `STEP_DELAY_MS` vs `MINIMUM_TOKENS`); the report explicitly
320
- * downgrades those to `confidence: "medium"`.
321
- */
322
- const MIN_NUMERIC_LITERAL_MAGNITUDE_FOR_DUPLICATE = 1e3;
323
- const DEFAULT_SEMANTIC_DECORATOR_ALLOWLIST = [
324
- "Component",
325
- "Injectable",
326
- "NgModule",
327
- "Pipe",
328
- "Directive",
329
- "Controller",
330
- "Module",
331
- "Resolver",
332
- "Query",
333
- "Mutation",
334
- "Get",
335
- "Post",
336
- "Put",
337
- "Patch",
338
- "Delete",
339
- "Head",
340
- "Options",
341
- "All",
342
- "Sse",
343
- "WebSocketGateway",
344
- "SubscribeMessage"
345
- ];
346
- const DEFAULT_SEMANTIC_TSCONFIG_NAMES = [
347
- "tsconfig.json",
348
- "tsconfig.app.json",
349
- "tsconfig.build.json",
350
- "tsconfig.src.json",
351
- "jsconfig.json"
352
- ];
353
- const GIT_CHECK_IGNORE_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
354
-
355
- //#endregion
356
50
  //#region src/errors.ts
357
51
  const truncateDetail = (text) => {
358
52
  if (text.length <= 1e3) return text;
359
- return `${text.slice(0, MAX_ERROR_DETAIL_LENGTH)}… [truncated ${text.length - MAX_ERROR_DETAIL_LENGTH} chars]`;
53
+ return `${text.slice(0, require_constants.MAX_ERROR_DETAIL_LENGTH)}… [truncated ${text.length - require_constants.MAX_ERROR_DETAIL_LENGTH} chars]`;
360
54
  };
361
55
  const describeUnknownError = (caughtValue) => {
362
56
  let rawText;
@@ -1716,7 +1410,7 @@ const stripByteOrderMark = (sourceText) => {
1716
1410
  return sourceText;
1717
1411
  };
1718
1412
  const looksLikeBinaryContent = (sourceText) => {
1719
- const sampleLength = Math.min(sourceText.length, BINARY_DETECTION_SAMPLE_BYTES);
1413
+ const sampleLength = Math.min(sourceText.length, require_constants.BINARY_DETECTION_SAMPLE_BYTES);
1720
1414
  let nullByteCount = 0;
1721
1415
  for (let scanIndex = 0; scanIndex < sampleLength; scanIndex++) {
1722
1416
  if (sourceText.charCodeAt(scanIndex) === 0) nullByteCount++;
@@ -1745,7 +1439,7 @@ const safeReadSourceFile = (filePath, errors) => {
1745
1439
  if (stats.size > 2e6) {
1746
1440
  errors.push(new FileReadError({
1747
1441
  code: "file-too-large",
1748
- message: `file size ${stats.size}B exceeds MAX_PARSE_FILE_SIZE_BYTES (${MAX_PARSE_FILE_SIZE_BYTES})`,
1442
+ message: `file size ${stats.size}B exceeds MAX_PARSE_FILE_SIZE_BYTES (${require_constants.MAX_PARSE_FILE_SIZE_BYTES})`,
1749
1443
  path: filePath
1750
1444
  }));
1751
1445
  return;
@@ -2644,13 +2338,7 @@ const resolveWorkspaces = (rootDir) => {
2644
2338
  };
2645
2339
  };
2646
2340
  const IMPLICIT_SUB_PROJECT_SEARCH_DEPTH = 3;
2647
- const STANDALONE_PROJECT_LOCKFILES = [
2648
- "package-lock.json",
2649
- "yarn.lock",
2650
- "pnpm-lock.yaml",
2651
- "bun.lockb"
2652
- ];
2653
- const isStandaloneProject = (directory) => STANDALONE_PROJECT_LOCKFILES.some((lockfile) => (0, node_fs.existsSync)((0, node_path.join)(directory, lockfile)));
2341
+ const isStandaloneProject = (directory) => require_constants.STANDALONE_PROJECT_LOCKFILES.some((lockfile) => (0, node_fs.existsSync)((0, node_path.join)(directory, lockfile)));
2654
2342
  const discoverImplicitSubProjects = (rootDir, alreadyDiscoveredDirectories) => {
2655
2343
  const knownDirectories = new Set(alreadyDiscoveredDirectories);
2656
2344
  const hasDeclaredWorkspaces = alreadyDiscoveredDirectories.length > 0;
@@ -3211,7 +2899,7 @@ const NESTED_EXPO_CONFIG_FILE_GLOBS = [
3211
2899
  "**/app.json"
3212
2900
  ];
3213
2901
  const EXPO_REACT_NATIVE_DEPENDENCIES = new Set(["expo", "react-native"]);
3214
- const EXPO_PLUGIN_RESOLVABLE_EXTENSIONS = SOURCE_EXTENSIONS$3.map((sourceExtension) => `.${sourceExtension}`);
2902
+ const EXPO_PLUGIN_RESOLVABLE_EXTENSIONS = require_constants.SOURCE_EXTENSIONS.map((sourceExtension) => `.${sourceExtension}`);
3215
2903
  const isRecord = (value) => typeof value === "object" && value !== null;
3216
2904
  const isExpoOrReactNativeWorkspace = (dependencies) => [...EXPO_REACT_NATIVE_DEPENDENCIES].some((dependencyName) => dependencyName in dependencies);
3217
2905
  const isLocalExpoPluginPath = (value) => (value.startsWith("./") || value.startsWith("../")) && !value.includes("*") && !value.includes("?");
@@ -3476,21 +3164,6 @@ const resolveWithIndexPrefix = (stemPath, directory) => {
3476
3164
 
3477
3165
  //#endregion
3478
3166
  //#region src/utils/find-monorepo-root.ts
3479
- const MONOREPO_ROOT_MARKERS = [
3480
- "pnpm-workspace.yaml",
3481
- "pnpm-workspace.yml",
3482
- "lerna.json",
3483
- "nx.json",
3484
- "turbo.json",
3485
- "rush.json"
3486
- ];
3487
- const LOCKFILE_MARKERS = [
3488
- "pnpm-lock.yaml",
3489
- "yarn.lock",
3490
- "package-lock.json",
3491
- "bun.lockb",
3492
- "bun.lock"
3493
- ];
3494
3167
  const MAX_MONOREPO_WALK_DEPTH = 5;
3495
3168
  const findMonorepoRoot = (rootDir) => {
3496
3169
  let currentDirectory = (0, node_path.resolve)(rootDir);
@@ -3501,16 +3174,16 @@ const findMonorepoRoot = (rootDir) => {
3501
3174
  currentDirectory = parentDirectory;
3502
3175
  walkedDepth++;
3503
3176
  if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, ".git"))) {
3504
- for (const marker of MONOREPO_ROOT_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, marker))) return currentDirectory;
3177
+ for (const marker of require_constants.MONOREPO_ROOT_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, marker))) return currentDirectory;
3505
3178
  const packageJsonPath = (0, node_path.join)(currentDirectory, "package.json");
3506
3179
  if ((0, node_fs.existsSync)(packageJsonPath)) try {
3507
3180
  const content = (0, node_fs.readFileSync)(packageJsonPath, "utf-8");
3508
3181
  if (JSON.parse(content).workspaces) return currentDirectory;
3509
3182
  } catch {}
3510
- for (const lockfile of LOCKFILE_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, lockfile))) return currentDirectory;
3183
+ for (const lockfile of require_constants.LOCKFILE_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, lockfile))) return currentDirectory;
3511
3184
  return;
3512
3185
  }
3513
- for (const marker of MONOREPO_ROOT_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, marker))) return currentDirectory;
3186
+ for (const marker of require_constants.MONOREPO_ROOT_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, marker))) return currentDirectory;
3514
3187
  const packageJsonPath = (0, node_path.join)(currentDirectory, "package.json");
3515
3188
  if ((0, node_fs.existsSync)(packageJsonPath)) try {
3516
3189
  const content = (0, node_fs.readFileSync)(packageJsonPath, "utf-8");
@@ -3518,7 +3191,7 @@ const findMonorepoRoot = (rootDir) => {
3518
3191
  } catch {
3519
3192
  continue;
3520
3193
  }
3521
- for (const lockfile of LOCKFILE_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, lockfile))) return currentDirectory;
3194
+ for (const lockfile of require_constants.LOCKFILE_MARKERS) if ((0, node_fs.existsSync)((0, node_path.join)(currentDirectory, lockfile))) return currentDirectory;
3522
3195
  }
3523
3196
  };
3524
3197
 
@@ -3742,9 +3415,9 @@ const isPlatformBuiltinOrVirtualSpecifier = (specifier) => {
3742
3415
  if (specifier === "std" || specifier.startsWith("std/")) return true;
3743
3416
  const stripped = specifier.startsWith("node:") ? specifier.slice(5) : specifier;
3744
3417
  const slashIndex = stripped.indexOf("/");
3745
- if (slashIndex === -1) return BUILTIN_MODULES.has(stripped);
3418
+ if (slashIndex === -1) return require_constants.BUILTIN_MODULES.has(stripped);
3746
3419
  const baseName = stripped.slice(0, slashIndex);
3747
- if (!BUILTIN_MODULES.has(baseName)) return false;
3420
+ if (!require_constants.BUILTIN_MODULES.has(baseName)) return false;
3748
3421
  return BUILTIN_SUBPATH_NODE_MODULES.has(baseName);
3749
3422
  };
3750
3423
 
@@ -3798,7 +3471,7 @@ const existsAsFile = (filePath) => {
3798
3471
  };
3799
3472
  const trySourceFallback = (resolvedPath) => {
3800
3473
  const segments = resolvedPath.split(node_path.sep);
3801
- const isOutputDirectory = (segment) => OUTPUT_DIRECTORIES.some((outputDirectory) => segment === outputDirectory || segment.startsWith(`${outputDirectory}-`));
3474
+ const isOutputDirectory = (segment) => require_constants.OUTPUT_DIRECTORIES.some((outputDirectory) => segment === outputDirectory || segment.startsWith(`${outputDirectory}-`));
3802
3475
  let lastOutputPosition = -1;
3803
3476
  for (let index = segments.length - 1; index >= 0; index--) if (isOutputDirectory(segments[index])) {
3804
3477
  lastOutputPosition = index;
@@ -3812,18 +3485,18 @@ const trySourceFallback = (resolvedPath) => {
3812
3485
  if (!suffix) return void 0;
3813
3486
  const fileExtension = (0, node_path.extname)((0, node_path.basename)(suffix));
3814
3487
  const stemmedSuffix = fileExtension ? suffix.slice(0, suffix.length - fileExtension.length) : suffix;
3815
- for (const sourceExtension of SOURCE_EXTENSIONS$3) {
3488
+ for (const sourceExtension of require_constants.SOURCE_EXTENSIONS) {
3816
3489
  const sourceCandidate = (0, node_path.join)(prefix, "src", `${stemmedSuffix}.${sourceExtension}`);
3817
3490
  if (existsAsFile(sourceCandidate)) return sourceCandidate;
3818
3491
  }
3819
3492
  };
3820
3493
  const resolvePathWithExtensionFallback = (candidatePath) => {
3821
3494
  if (existsAsFile(candidatePath)) return candidatePath;
3822
- for (const extension of RESOLVER_EXTENSIONS) {
3495
+ for (const extension of require_constants.RESOLVER_EXTENSIONS) {
3823
3496
  const withExtension = candidatePath + extension;
3824
3497
  if (existsAsFile(withExtension)) return withExtension;
3825
3498
  }
3826
- for (const extension of RESOLVER_EXTENSIONS) {
3499
+ for (const extension of require_constants.RESOLVER_EXTENSIONS) {
3827
3500
  const indexCandidate = (0, node_path.join)(candidatePath, `index${extension}`);
3828
3501
  if (existsAsFile(indexCandidate)) return indexCandidate;
3829
3502
  }
@@ -3831,13 +3504,13 @@ const resolvePathWithExtensionFallback = (candidatePath) => {
3831
3504
  };
3832
3505
  const resolveAliasTarget = (target) => {
3833
3506
  if (existsAsFile(target)) return target;
3834
- for (const extension of RESOLVER_EXTENSIONS) if (cachedExistsSync(target + extension)) return target + extension;
3507
+ for (const extension of require_constants.RESOLVER_EXTENSIONS) if (cachedExistsSync(target + extension)) return target + extension;
3835
3508
  const sourceTarget = target.replace(/\.[cm]?js$/, "");
3836
3509
  if (sourceTarget !== target) {
3837
- for (const extension of RESOLVER_EXTENSIONS) if (cachedExistsSync(sourceTarget + extension)) return sourceTarget + extension;
3510
+ for (const extension of require_constants.RESOLVER_EXTENSIONS) if (cachedExistsSync(sourceTarget + extension)) return sourceTarget + extension;
3838
3511
  }
3839
3512
  const indexCandidate = (0, node_path.join)(target, "index");
3840
- for (const extension of RESOLVER_EXTENSIONS) if (cachedExistsSync(indexCandidate + extension)) return indexCandidate + extension;
3513
+ for (const extension of require_constants.RESOLVER_EXTENSIONS) if (cachedExistsSync(indexCandidate + extension)) return indexCandidate + extension;
3841
3514
  };
3842
3515
  const pathMappingSpecificity = (mapping) => mapping.isWildcard ? mapping.prefix.length + mapping.suffix.length : Number.MAX_SAFE_INTEGER;
3843
3516
  const compilePathMappings = (entries) => {
@@ -3880,7 +3553,7 @@ const COMMON_RESOLVER_OPTIONS = {
3880
3553
  "node",
3881
3554
  "default"
3882
3555
  ],
3883
- extensions: RESOLVER_EXTENSIONS,
3556
+ extensions: require_constants.RESOLVER_EXTENSIONS,
3884
3557
  mainFields: [
3885
3558
  "module",
3886
3559
  "main",
@@ -4176,7 +3849,7 @@ const resolveWorkspaceSubpath = (workspaceDirectory, subpath) => {
4176
3849
  if (subpath && !resolvedEntryPath) {
4177
3850
  const subpathCandidates = [(0, node_path.resolve)(workspaceDirectory, subpath), (0, node_path.resolve)(workspaceDirectory, "src", subpath)];
4178
3851
  for (const directSubpath of subpathCandidates) {
4179
- for (const candidateExtension of RESOLVER_EXTENSIONS) {
3852
+ for (const candidateExtension of require_constants.RESOLVER_EXTENSIONS) {
4180
3853
  const candidate = directSubpath + candidateExtension;
4181
3854
  if (cachedExistsSync(candidate)) {
4182
3855
  resolvedEntryPath = candidate;
@@ -4184,7 +3857,7 @@ const resolveWorkspaceSubpath = (workspaceDirectory, subpath) => {
4184
3857
  }
4185
3858
  }
4186
3859
  if (resolvedEntryPath) break;
4187
- for (const candidateExtension of RESOLVER_EXTENSIONS) {
3860
+ for (const candidateExtension of require_constants.RESOLVER_EXTENSIONS) {
4188
3861
  const indexCandidate = (0, node_path.join)(directSubpath, `index${candidateExtension}`);
4189
3862
  if (cachedExistsSync(indexCandidate)) {
4190
3863
  resolvedEntryPath = indexCandidate;
@@ -4214,7 +3887,7 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
4214
3887
  const resolverCache = /* @__PURE__ */ new Map();
4215
3888
  const resolveResultCache = /* @__PURE__ */ new Map();
4216
3889
  const failedTsconfigPaths = /* @__PURE__ */ new Set();
4217
- const resolverExtensions = options.hasReactNative ? [...REACT_NATIVE_PLATFORM_EXTENSIONS, ...RESOLVER_EXTENSIONS] : RESOLVER_EXTENSIONS;
3890
+ const resolverExtensions = options.hasReactNative ? [...require_constants.REACT_NATIVE_PLATFORM_EXTENSIONS, ...require_constants.RESOLVER_EXTENSIONS] : require_constants.RESOLVER_EXTENSIONS;
4218
3891
  const resolverOptions = {
4219
3892
  ...COMMON_RESOLVER_OPTIONS,
4220
3893
  extensions: resolverExtensions
@@ -4603,7 +4276,7 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
4603
4276
  const baseUrlDirectory = getBaseUrlDirectory(tsconfigFile);
4604
4277
  if (baseUrlDirectory) {
4605
4278
  const baseUrlCandidate = (0, node_path.resolve)(baseUrlDirectory, cleanedSpecifier);
4606
- for (const candidateExtension of RESOLVER_EXTENSIONS) {
4279
+ for (const candidateExtension of require_constants.RESOLVER_EXTENSIONS) {
4607
4280
  const fullCandidate = baseUrlCandidate + candidateExtension;
4608
4281
  if (cachedExistsSync(fullCandidate)) {
4609
4282
  const resolvedResult = {
@@ -4616,7 +4289,7 @@ const createResolver = (config, workspacePackages = [], options = {}) => {
4616
4289
  }
4617
4290
  }
4618
4291
  const indexCandidate = (0, node_path.join)(baseUrlCandidate, "index");
4619
- for (const candidateExtension of RESOLVER_EXTENSIONS) {
4292
+ for (const candidateExtension of require_constants.RESOLVER_EXTENSIONS) {
4620
4293
  const fullCandidate = indexCandidate + candidateExtension;
4621
4294
  if (cachedExistsSync(fullCandidate)) {
4622
4295
  const resolvedResult = {
@@ -4792,9 +4465,9 @@ const extractSiblingWorkspaceImportEntries = (absoluteRoot) => {
4792
4465
  //#endregion
4793
4466
  //#region src/collect/entries.ts
4794
4467
  const collectSourceFiles = async (config) => {
4795
- const extensions = config.includeExtensions.length > 0 ? config.includeExtensions : DEFAULT_EXTENSIONS;
4468
+ const extensions = config.includeExtensions.length > 0 ? config.includeExtensions : require_constants.DEFAULT_EXTENSIONS;
4796
4469
  const extensionGlob = extensions.length === 1 ? `**/*${extensions[0]}` : `**/*{${extensions.join(",")}}`;
4797
- const ignorePatterns = [...DEFAULT_EXCLUSIONS, ...config.ignorePatterns].map(toPosixPath);
4470
+ const ignorePatterns = [...require_constants.DEFAULT_EXCLUSIONS, ...config.ignorePatterns].map(toPosixPath);
4798
4471
  const absoluteRoot = (0, node_path.resolve)(config.rootDir);
4799
4472
  const mainFiles = await (0, fast_glob.default)(extensionGlob, {
4800
4473
  cwd: absoluteRoot,
@@ -4803,7 +4476,7 @@ const collectSourceFiles = async (config) => {
4803
4476
  dot: false,
4804
4477
  onlyFiles: true
4805
4478
  });
4806
- const allowedHiddenGlobs = HIDDEN_DIRECTORY_ALLOWLIST.flatMap((directory) => [`${directory}/**/*{${extensions.join(",")}}`, `**/${directory}/**/*{${extensions.join(",")}}`]);
4479
+ const allowedHiddenGlobs = require_constants.HIDDEN_DIRECTORY_ALLOWLIST.flatMap((directory) => [`${directory}/**/*{${extensions.join(",")}}`, `**/${directory}/**/*{${extensions.join(",")}}`]);
4807
4480
  const hiddenFiles = allowedHiddenGlobs.length > 0 ? await (0, fast_glob.default)(allowedHiddenGlobs, {
4808
4481
  cwd: absoluteRoot,
4809
4482
  absolute: true,
@@ -5374,7 +5047,7 @@ const extractScriptEntries = (directory) => {
5374
5047
  const scripts = JSON.parse(content).scripts;
5375
5048
  if (scripts && typeof scripts === "object") for (const scriptCommand of Object.values(scripts)) {
5376
5049
  if (typeof scriptCommand !== "string") continue;
5377
- const match = scriptCommand.match(SCRIPT_FILE_PATTERN);
5050
+ const match = scriptCommand.match(require_constants.SCRIPT_FILE_PATTERN);
5378
5051
  if (match?.[1]) {
5379
5052
  const scriptFilePath = (0, node_path.resolve)(directory, match[1]);
5380
5053
  if ((0, node_fs.existsSync)(scriptFilePath)) entries.push(scriptFilePath);
@@ -5383,14 +5056,14 @@ const extractScriptEntries = (directory) => {
5383
5056
  if (sourcePath) entries.push(sourcePath);
5384
5057
  }
5385
5058
  } else {
5386
- const extensionlessMatch = scriptCommand.match(SCRIPT_EXTENSIONLESS_FILE_PATTERN);
5059
+ const extensionlessMatch = scriptCommand.match(require_constants.SCRIPT_EXTENSIONLESS_FILE_PATTERN);
5387
5060
  if (extensionlessMatch?.[1]) {
5388
5061
  const extensionlessPath = extensionlessMatch[1];
5389
5062
  const resolved = resolveExtensionlessScriptPath((0, node_path.resolve)(directory, extensionlessPath));
5390
5063
  if (resolved) entries.push(resolved);
5391
5064
  }
5392
5065
  }
5393
- const configMatch = scriptCommand.match(SCRIPT_CONFIG_FILE_PATTERN);
5066
+ const configMatch = scriptCommand.match(require_constants.SCRIPT_CONFIG_FILE_PATTERN);
5394
5067
  if (configMatch?.[1]) {
5395
5068
  const configFilePath = (0, node_path.resolve)(directory, configMatch[1]);
5396
5069
  if ((0, node_fs.existsSync)(configFilePath)) entries.push(configFilePath);
@@ -5402,7 +5075,7 @@ const extractScriptEntries = (directory) => {
5402
5075
  entries.push(...extractScriptFileArguments(scriptCommand, directory));
5403
5076
  }
5404
5077
  } catch {}
5405
- const scriptDirectoryFiles = fast_glob.default.sync(SCRIPT_ENTRY_PATTERNS, {
5078
+ const scriptDirectoryFiles = fast_glob.default.sync(require_constants.SCRIPT_ENTRY_PATTERNS, {
5406
5079
  cwd: directory,
5407
5080
  absolute: true,
5408
5081
  onlyFiles: true,
@@ -5458,12 +5131,12 @@ const extractCiWorkflowEntries = (rootDir) => {
5458
5131
  for (const workflowFile of workflowFiles) try {
5459
5132
  const runCommands = extractCiRunCommands((0, node_fs.readFileSync)(workflowFile, "utf-8"));
5460
5133
  for (const command of runCommands) {
5461
- const scriptMatch = command.match(SCRIPT_FILE_PATTERN);
5134
+ const scriptMatch = command.match(require_constants.SCRIPT_FILE_PATTERN);
5462
5135
  if (scriptMatch?.[1]) {
5463
5136
  const scriptFilePath = (0, node_path.resolve)(rootDir, scriptMatch[1]);
5464
5137
  if ((0, node_fs.existsSync)(scriptFilePath)) entries.push(scriptFilePath);
5465
5138
  }
5466
- const configMatch = command.match(SCRIPT_CONFIG_FILE_PATTERN);
5139
+ const configMatch = command.match(require_constants.SCRIPT_CONFIG_FILE_PATTERN);
5467
5140
  if (configMatch?.[1]) {
5468
5141
  const configFilePath = (0, node_path.resolve)(rootDir, configMatch[1]);
5469
5142
  if ((0, node_fs.existsSync)(configFilePath)) entries.push(configFilePath);
@@ -6109,7 +5782,7 @@ const extractTestSetupFiles = (directory) => {
6109
5782
  } catch {}
6110
5783
  return entries;
6111
5784
  };
6112
- const IMPORTABLE_EXTENSION_SET = new Set(SOURCE_EXTENSIONS$3.map((extension) => `.${extension}`));
5785
+ const IMPORTABLE_EXTENSION_SET = new Set(require_constants.SOURCE_EXTENSIONS.map((extension) => `.${extension}`));
6113
5786
  const isImportableSourceFile = (filePath) => IMPORTABLE_EXTENSION_SET.has(filePath.slice(filePath.lastIndexOf(".")));
6114
5787
  const expandWildcardExportPattern = (pattern, rootDir) => {
6115
5788
  const normalized = pattern.startsWith("./") ? pattern.slice(2) : pattern;
@@ -7256,6 +6929,18 @@ const resolveAvailableConcurrency = () => {
7256
6929
  return clampParseConcurrency(available);
7257
6930
  };
7258
6931
 
6932
+ //#endregion
6933
+ //#region src/collect/launch-worker.ts
6934
+ /**
6935
+ * Launches a worker module that sits next to `fromModuleUrl`: the TypeScript
6936
+ * source (via tsx) when the caller itself runs from source — tests and direct
6937
+ * `tsx` execution — and the built `.mjs` sibling when running from dist.
6938
+ */
6939
+ const launchSiblingWorker = (fromModuleUrl, workerBaseName) => {
6940
+ const isTypeScriptSource = fromModuleUrl.endsWith(".ts");
6941
+ return new node_worker_threads.Worker((0, node_url.fileURLToPath)(new URL(isTypeScriptSource ? `./${workerBaseName}.ts` : `./${workerBaseName}.mjs`, fromModuleUrl)), { ...isTypeScriptSource ? { execArgv: ["--import", "tsx"] } : {} });
6942
+ };
6943
+
7259
6944
  //#endregion
7260
6945
  //#region src/collect/parallel-parse.ts
7261
6946
  const deserializeErrors = (serializedErrors) => serializedErrors.map((errorJson) => new DeslopError({
@@ -7282,14 +6967,6 @@ const deserializeParsedSource = (serialized) => ({
7282
6967
  duplicateConstantCandidates: serialized.duplicateConstantCandidates,
7283
6968
  errors: deserializeErrors(serialized.errors)
7284
6969
  });
7285
- const resolveWorkerPath = () => {
7286
- const currentUrl = require("url").pathToFileURL(__filename).href;
7287
- if (currentUrl.endsWith(".ts")) return (0, node_url.fileURLToPath)(new URL("./parse-worker.ts", currentUrl));
7288
- return (0, node_url.fileURLToPath)(new URL("./parse-worker.mjs", currentUrl));
7289
- };
7290
- const createWorker = (workerPath) => {
7291
- return new node_worker_threads.Worker(workerPath, { ...workerPath.endsWith(".ts") ? { execArgv: ["--import", "tsx"] } : {} });
7292
- };
7293
6970
  const waitForReady = (worker) => new Promise((resolve, reject) => {
7294
6971
  const onMessage = (message) => {
7295
6972
  if (message.type === "ready") {
@@ -7307,11 +6984,10 @@ const waitForReady = (worker) => new Promise((resolve, reject) => {
7307
6984
  worker.on("error", onError);
7308
6985
  });
7309
6986
  const parseFilesWithWorkerPool = async (files, workerCount) => {
7310
- const workerPath = resolveWorkerPath();
7311
6987
  const results = new Array(files.length);
7312
6988
  const workers = [];
7313
6989
  try {
7314
- for (let workerIndex = 0; workerIndex < workerCount; workerIndex++) workers.push(createWorker(workerPath));
6990
+ for (let workerIndex = 0; workerIndex < workerCount; workerIndex++) workers.push(launchSiblingWorker(require("url").pathToFileURL(__filename).href, "parse-worker"));
7315
6991
  await Promise.all(workers.map(waitForReady));
7316
6992
  } catch {
7317
6993
  for (const worker of workers) worker.terminate();
@@ -7397,7 +7073,7 @@ const isConfigFile = (filePath) => {
7397
7073
  if (fileName.startsWith(".") && !fileName.startsWith("..")) {
7398
7074
  if (fileName.toLowerCase().includes("rc.")) return true;
7399
7075
  }
7400
- return KNOWN_CONFIG_PREFIXES.some((prefix) => fileName.startsWith(prefix));
7076
+ return require_constants.KNOWN_CONFIG_PREFIXES.some((prefix) => fileName.startsWith(prefix));
7401
7077
  };
7402
7078
 
7403
7079
  //#endregion
@@ -7524,7 +7200,7 @@ const PLATFORM_DIRECTORY_NAMES = new Set([
7524
7200
  "macos"
7525
7201
  ]);
7526
7202
  const stripPlatformSuffix = (filePath) => {
7527
- for (const suffix of PLATFORM_SUFFIXES) {
7203
+ for (const suffix of require_constants.PLATFORM_SUFFIXES) {
7528
7204
  const extensionIndex = filePath.lastIndexOf(".");
7529
7205
  if (extensionIndex === -1) continue;
7530
7206
  const withoutExtension = filePath.slice(0, extensionIndex);
@@ -7831,10 +7507,16 @@ const detectDeadExports = (graph, config) => {
7831
7507
  const buildUsageMap = (graph) => {
7832
7508
  const usedExportKeys = /* @__PURE__ */ new Set();
7833
7509
  const sourceToTargetMap = buildSourceToTargetsMap(graph);
7510
+ const reExportEdgesBySource = /* @__PURE__ */ new Map();
7511
+ for (const edge of graph.edges) {
7512
+ if (!edge.isReExportEdge) continue;
7513
+ const existingEdges = reExportEdgesBySource.get(edge.source);
7514
+ if (existingEdges) existingEdges.push(edge);
7515
+ else reExportEdgesBySource.set(edge.source, [edge]);
7516
+ }
7834
7517
  for (const module of graph.modules) {
7835
7518
  if (!module.isEntryPoint) continue;
7836
- for (const edge of graph.edges) {
7837
- if (edge.source !== module.fileId.index || !edge.isReExportEdge) continue;
7519
+ for (const edge of reExportEdgesBySource.get(module.fileId.index) ?? []) {
7838
7520
  const targetModule = graph.modules[edge.target];
7839
7521
  if (!targetModule) continue;
7840
7522
  if (edge.reExportedNames.includes("*")) markAllExportsUsedRecursive(targetModule, graph, sourceToTargetMap, usedExportKeys, /* @__PURE__ */ new Set());
@@ -8081,12 +7763,29 @@ const matchesPackageTokenReference = (command, packageName) => {
8081
7763
 
8082
7764
  //#endregion
8083
7765
  //#region src/report/packages.ts
8084
- const discoverAllPackageJsonPaths = (rootDir) => {
7766
+ const globPackageFiles = (cwd, patterns, options, summaryCache) => summaryCache?.matchWalkedFiles({
7767
+ cwd,
7768
+ patterns,
7769
+ ...options
7770
+ }) ?? fast_glob.default.sync([...patterns], {
7771
+ cwd,
7772
+ absolute: true,
7773
+ onlyFiles: true,
7774
+ ignore: [...options.ignore],
7775
+ deep: options.deep,
7776
+ ...options.dot === void 0 ? {} : { dot: options.dot }
7777
+ });
7778
+ const containsPackageName = (content, packageName) => content.includes(packageName);
7779
+ const matchPackageNamesInFile = (filePath, kind, names, matcher, summaryCache) => {
7780
+ if (summaryCache !== void 0) return summaryCache.matchPackageNames(filePath, kind, names, matcher);
7781
+ const content = (0, node_fs.readFileSync)(filePath, "utf-8");
7782
+ const matchedNames = [];
7783
+ for (const packageName of names) if (matcher(content, packageName)) matchedNames.push(packageName);
7784
+ return matchedNames;
7785
+ };
7786
+ const discoverAllPackageJsonPaths = (rootDir, summaryCache) => {
8085
7787
  const paths = [(0, node_path.join)(rootDir, "package.json")];
8086
- const workspacePackageJsons = fast_glob.default.sync("**/package.json", {
8087
- cwd: rootDir,
8088
- absolute: true,
8089
- onlyFiles: true,
7788
+ const workspacePackageJsons = globPackageFiles(rootDir, ["**/package.json"], {
8090
7789
  ignore: [
8091
7790
  "**/node_modules/**",
8092
7791
  "**/dist/**",
@@ -8094,11 +7793,11 @@ const discoverAllPackageJsonPaths = (rootDir) => {
8094
7793
  "**/.git/**"
8095
7794
  ],
8096
7795
  deep: 5
8097
- });
7796
+ }, summaryCache);
8098
7797
  for (const workspacePath of workspacePackageJsons) if (workspacePath !== paths[0] && !paths.includes(workspacePath)) paths.push(workspacePath);
8099
7798
  return paths;
8100
7799
  };
8101
- const detectStalePackages = (graph, config) => {
7800
+ const detectStalePackages = (graph, config, summaryCache) => {
8102
7801
  const packageJsonPath = (0, node_path.resolve)(config.rootDir, "package.json");
8103
7802
  let packageJson;
8104
7803
  try {
@@ -8116,7 +7815,7 @@ const detectStalePackages = (graph, config) => {
8116
7815
  const usedPackageNames = collectUsedPackages(graph);
8117
7816
  const monorepoRoot = findMonorepoRoot(config.rootDir);
8118
7817
  const nodeModulesSearchRoots = monorepoRoot && monorepoRoot !== config.rootDir ? [config.rootDir, monorepoRoot] : [config.rootDir];
8119
- const allPackageJsonPaths = discoverAllPackageJsonPaths(config.rootDir);
7818
+ const allPackageJsonPaths = discoverAllPackageJsonPaths(config.rootDir, summaryCache);
8120
7819
  if (monorepoRoot) {
8121
7820
  const monorepoPackageJson = (0, node_path.join)(monorepoRoot, "package.json");
8122
7821
  if (!allPackageJsonPaths.includes(monorepoPackageJson) && (0, node_fs.existsSync)(monorepoPackageJson)) allPackageJsonPaths.push(monorepoPackageJson);
@@ -8129,13 +7828,13 @@ const detectStalePackages = (graph, config) => {
8129
7828
  const packageJsonConfigReferenced = collectPackageJsonConfigReferences(workspacePackageJsonPath, declaredNames);
8130
7829
  for (const packageName of packageJsonConfigReferenced) usedPackageNames.add(packageName);
8131
7830
  }
8132
- const nxProjectReferenced = collectNxProjectJsonReferences(config.rootDir, declaredNames, binToPackage);
7831
+ const nxProjectReferenced = collectNxProjectJsonReferences(config.rootDir, declaredNames, binToPackage, summaryCache);
8133
7832
  for (const packageName of nxProjectReferenced) usedPackageNames.add(packageName);
8134
7833
  const configSearchRoots = monorepoRoot && monorepoRoot !== config.rootDir ? [config.rootDir, monorepoRoot] : [config.rootDir];
8135
7834
  for (const configSearchRoot of configSearchRoots) {
8136
- const configReferenced = collectConfigReferencedPackages(configSearchRoot, graph, declaredNames);
7835
+ const configReferenced = collectConfigReferencedPackages(configSearchRoot, graph, declaredNames, summaryCache);
8137
7836
  for (const packageName of configReferenced) usedPackageNames.add(packageName);
8138
- const tsconfigReferenced = collectTsconfigReferencedPackages(configSearchRoot);
7837
+ const tsconfigReferenced = collectTsconfigReferencedPackages(configSearchRoot, summaryCache);
8139
7838
  for (const packageName of tsconfigReferenced) usedPackageNames.add(packageName);
8140
7839
  const { packageNames: expoPluginPackageNames } = extractExpoConfigPluginEntries(configSearchRoot, {
8141
7840
  ...dependencies,
@@ -8187,7 +7886,7 @@ const detectStalePackages = (graph, config) => {
8187
7886
  candidateUnused.add(dependencyName);
8188
7887
  }
8189
7888
  if (candidateUnused.size > 0) {
8190
- const sourceFileRescued = scanSourceFilesForPackageImports(config.rootDir, candidateUnused);
7889
+ const sourceFileRescued = scanSourceFilesForPackageImports(config.rootDir, candidateUnused, summaryCache);
8191
7890
  for (const packageName of sourceFileRescued) {
8192
7891
  usedPackageNames.add(packageName);
8193
7892
  candidateUnused.delete(packageName);
@@ -8355,35 +8054,26 @@ const CONFIG_FILE_GLOBS = [
8355
8054
  ".dumirc.js",
8356
8055
  "dumi.config.{ts,js}"
8357
8056
  ];
8358
- const collectConfigReferencedPackages = (rootDir, graph, declaredNames) => {
8057
+ const collectConfigReferencedPackages = (rootDir, graph, declaredNames, summaryCache) => {
8359
8058
  const referenced = /* @__PURE__ */ new Set();
8360
- for (const module of graph.modules) {
8361
- if (!module.isConfigFile) continue;
8059
+ const addMatchesFromFile = (filePath, kind, matcher) => {
8362
8060
  try {
8363
- const content = (0, node_fs.readFileSync)(module.fileId.path, "utf-8");
8364
- for (const packageName of declaredNames) if (content.includes(packageName)) referenced.add(packageName);
8061
+ for (const packageName of matchPackageNamesInFile(filePath, kind, declaredNames, matcher, summaryCache)) referenced.add(packageName);
8365
8062
  } catch {
8366
- continue;
8063
+ return;
8367
8064
  }
8065
+ };
8066
+ for (const module of graph.modules) {
8067
+ if (!module.isConfigFile) continue;
8068
+ addMatchesFromFile(module.fileId.path, "substring", containsPackageName);
8368
8069
  }
8369
- const configFiles = fast_glob.default.sync(CONFIG_FILE_GLOBS, {
8370
- cwd: rootDir,
8371
- absolute: true,
8372
- onlyFiles: true,
8070
+ const configFiles = globPackageFiles(rootDir, CONFIG_FILE_GLOBS, {
8373
8071
  ignore: ["**/node_modules/**"],
8374
8072
  dot: true,
8375
8073
  deep: 3
8376
- });
8377
- for (const configPath of configFiles) try {
8378
- const content = (0, node_fs.readFileSync)(configPath, "utf-8");
8379
- for (const packageName of declaredNames) if (content.includes(packageName)) referenced.add(packageName);
8380
- } catch {
8381
- continue;
8382
- }
8383
- const documentationFiles = fast_glob.default.sync(["**/*.{mdx,md}"], {
8384
- cwd: rootDir,
8385
- absolute: true,
8386
- onlyFiles: true,
8074
+ }, summaryCache);
8075
+ for (const configPath of configFiles) addMatchesFromFile(configPath, "substring", containsPackageName);
8076
+ const documentationFiles = globPackageFiles(rootDir, ["**/*.{mdx,md}"], {
8387
8077
  ignore: [
8388
8078
  "**/node_modules/**",
8389
8079
  "**/dist/**",
@@ -8391,13 +8081,8 @@ const collectConfigReferencedPackages = (rootDir, graph, declaredNames) => {
8391
8081
  "**/CHANGELOG.md"
8392
8082
  ],
8393
8083
  deep: 6
8394
- });
8395
- for (const documentationPath of documentationFiles) try {
8396
- const content = (0, node_fs.readFileSync)(documentationPath, "utf-8");
8397
- for (const packageName of declaredNames) if (matchesPackageImportReference(content, packageName)) referenced.add(packageName);
8398
- } catch {
8399
- continue;
8400
- }
8084
+ }, summaryCache);
8085
+ for (const documentationPath of documentationFiles) addMatchesFromFile(documentationPath, "importReference", matchesPackageImportReference);
8401
8086
  return referenced;
8402
8087
  };
8403
8088
  const PACKAGE_JSON_CONFIG_SECTIONS = [
@@ -8468,19 +8153,16 @@ const collectPackageJsonConfigReferences = (packageJsonPath, declaredNames) => {
8468
8153
  }
8469
8154
  return referenced;
8470
8155
  };
8471
- const collectNxProjectJsonReferences = (rootDir, declaredNames, binToPackage) => {
8156
+ const collectNxProjectJsonReferences = (rootDir, declaredNames, binToPackage, summaryCache) => {
8472
8157
  const referenced = /* @__PURE__ */ new Set();
8473
- const projectJsonPaths = fast_glob.default.sync(["project.json", "**/project.json"], {
8474
- cwd: rootDir,
8475
- absolute: true,
8476
- onlyFiles: true,
8158
+ const projectJsonPaths = globPackageFiles(rootDir, ["project.json", "**/project.json"], {
8477
8159
  ignore: [
8478
8160
  "**/node_modules/**",
8479
8161
  "**/dist/**",
8480
8162
  "**/build/**"
8481
8163
  ],
8482
8164
  deep: 5
8483
- });
8165
+ }, summaryCache);
8484
8166
  for (const projectJsonPath of projectJsonPaths) try {
8485
8167
  const content = (0, node_fs.readFileSync)(projectJsonPath, "utf-8");
8486
8168
  const projectJson = JSON.parse(content);
@@ -8508,16 +8190,13 @@ const TSCONFIG_GLOBS = [
8508
8190
  "**/tsconfig.json",
8509
8191
  "**/tsconfig.*.json"
8510
8192
  ];
8511
- const collectTsconfigReferencedPackages = (rootDir) => {
8193
+ const collectTsconfigReferencedPackages = (rootDir, summaryCache) => {
8512
8194
  const referenced = /* @__PURE__ */ new Set();
8513
- const tsconfigFiles = fast_glob.default.sync(TSCONFIG_GLOBS, {
8514
- cwd: rootDir,
8515
- absolute: true,
8516
- onlyFiles: true,
8195
+ const tsconfigFiles = globPackageFiles(rootDir, TSCONFIG_GLOBS, {
8517
8196
  ignore: ["**/node_modules/**"],
8518
8197
  dot: false,
8519
8198
  deep: 4
8520
- });
8199
+ }, summaryCache);
8521
8200
  for (const tsconfigPath of tsconfigFiles) try {
8522
8201
  const cleaned = (0, node_fs.readFileSync)(tsconfigPath, "utf-8").replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
8523
8202
  const parsed = JSON.parse(cleaned);
@@ -8563,16 +8242,22 @@ const SOURCE_FILE_IGNORES = [
8563
8242
  "**/*.min.js",
8564
8243
  "**/*.d.ts"
8565
8244
  ];
8566
- const scanSourceFilesForPackageImports = (rootDir, candidatePackages) => {
8245
+ const scanSourceFilesForPackageImports = (rootDir, candidatePackages, summaryCache) => {
8567
8246
  const found = /* @__PURE__ */ new Set();
8568
8247
  if (candidatePackages.size === 0) return found;
8569
- const sourceFiles = fast_glob.default.sync(SOURCE_FILE_GLOBS, {
8570
- cwd: rootDir,
8571
- absolute: true,
8572
- onlyFiles: true,
8248
+ const sourceFiles = globPackageFiles(rootDir, SOURCE_FILE_GLOBS, {
8573
8249
  ignore: SOURCE_FILE_IGNORES,
8574
8250
  deep: 15
8575
- });
8251
+ }, summaryCache);
8252
+ if (summaryCache !== void 0) {
8253
+ for (const filePath of sourceFiles) try {
8254
+ for (const packageName of summaryCache.matchPackageNames(filePath, "importReference", candidatePackages, matchesPackageImportReference)) found.add(packageName);
8255
+ } catch {
8256
+ continue;
8257
+ }
8258
+ for (const packageName of found) candidatePackages.delete(packageName);
8259
+ return found;
8260
+ }
8576
8261
  for (const filePath of sourceFiles) {
8577
8262
  if (candidatePackages.size === 0) break;
8578
8263
  try {
@@ -8641,7 +8326,7 @@ const ALWAYS_USED_PREFIXES = [
8641
8326
  ];
8642
8327
  const ALWAYS_USED_SUFFIXES = ["-loader"];
8643
8328
  const isAlwaysConsideredUsed = (dependencyName) => {
8644
- if (IMPLICIT_DEPENDENCIES.has(dependencyName)) return true;
8329
+ if (require_constants.IMPLICIT_DEPENDENCIES.has(dependencyName)) return true;
8645
8330
  if (ALWAYS_USED_PREFIXES.some((prefix) => dependencyName.startsWith(prefix))) return true;
8646
8331
  if (ALWAYS_USED_SUFFIXES.some((suffix) => dependencyName.endsWith(suffix))) return true;
8647
8332
  return false;
@@ -8809,13 +8494,13 @@ const isPlatformSpecificModulePath = (modulePath) => {
8809
8494
  const extensionIndex = modulePath.lastIndexOf(".");
8810
8495
  if (extensionIndex === -1) return false;
8811
8496
  const withoutExtension = modulePath.slice(0, extensionIndex);
8812
- return PLATFORM_SUFFIXES.some((suffix) => withoutExtension.endsWith(suffix));
8497
+ return require_constants.PLATFORM_SUFFIXES.some((suffix) => withoutExtension.endsWith(suffix));
8813
8498
  };
8814
8499
  const platformStrippedBasePath = (modulePath) => {
8815
8500
  const extensionIndex = modulePath.lastIndexOf(".");
8816
8501
  if (extensionIndex === -1) return modulePath;
8817
8502
  const withoutExtension = modulePath.slice(0, extensionIndex);
8818
- for (const suffix of PLATFORM_SUFFIXES) if (withoutExtension.endsWith(suffix)) return withoutExtension.slice(0, -suffix.length) + modulePath.slice(extensionIndex);
8503
+ for (const suffix of require_constants.PLATFORM_SUFFIXES) if (withoutExtension.endsWith(suffix)) return withoutExtension.slice(0, -suffix.length) + modulePath.slice(extensionIndex);
8819
8504
  return modulePath;
8820
8505
  };
8821
8506
  const buildPlatformSiblingGroupSizes = (graph) => {
@@ -9855,7 +9540,7 @@ const tokenizeAst = (program) => {
9855
9540
  //#endregion
9856
9541
  //#region src/duplicate-blocks/index.ts
9857
9542
  const isBinaryFile = (sourceText) => {
9858
- const sampleEnd = Math.min(sourceText.length, BINARY_DETECTION_SAMPLE_BYTES);
9543
+ const sampleEnd = Math.min(sourceText.length, require_constants.BINARY_DETECTION_SAMPLE_BYTES);
9859
9544
  let nullByteCount = 0;
9860
9545
  for (let charIndex = 0; charIndex < sampleEnd; charIndex++) if (sourceText.charCodeAt(charIndex) === 0) {
9861
9546
  nullByteCount++;
@@ -11587,7 +11272,7 @@ const findNearestTsconfig = (rootDir, explicitPath) => {
11587
11272
  if ((0, node_fs.existsSync)(absoluteExplicit)) return absoluteExplicit;
11588
11273
  return;
11589
11274
  }
11590
- for (const candidateName of DEFAULT_SEMANTIC_TSCONFIG_NAMES) {
11275
+ for (const candidateName of require_constants.DEFAULT_SEMANTIC_TSCONFIG_NAMES) {
11591
11276
  const candidatePath = (0, node_path.resolve)(rootDir, candidateName);
11592
11277
  if ((0, node_fs.existsSync)(candidatePath)) return candidatePath;
11593
11278
  }
@@ -11640,7 +11325,7 @@ const createSemanticContext = (rootDir, tsconfigPath) => {
11640
11325
  }
11641
11326
  if (parsedCommandLine.fileNames.length > 5e3) return {
11642
11327
  ok: false,
11643
- failure: failureFor("too-many-files", `Project has ${parsedCommandLine.fileNames.length} files, exceeds SEMANTIC_MAX_PROGRAM_FILES=${SEMANTIC_MAX_PROGRAM_FILES}`, { rootDir: resolvedTsconfigPath })
11328
+ failure: failureFor("too-many-files", `Project has ${parsedCommandLine.fileNames.length} files, exceeds SEMANTIC_MAX_PROGRAM_FILES=${require_constants.SEMANTIC_MAX_PROGRAM_FILES}`, { rootDir: resolvedTsconfigPath })
11644
11329
  };
11645
11330
  try {
11646
11331
  const program = typescript.default.createProgram({
@@ -12542,7 +12227,7 @@ const safeReportDetector = (detectorName, detector, fallback, errorSink) => runS
12542
12227
  module: "report",
12543
12228
  contextDescription: "while building findings"
12544
12229
  });
12545
- const generateReport = (graph, config) => {
12230
+ const generateReport = (graph, config, summaryCache) => {
12546
12231
  const analysisStartTime = performance.now();
12547
12232
  const errorSink = [];
12548
12233
  for (const module of graph.modules) {
@@ -12554,7 +12239,7 @@ const generateReport = (graph, config) => {
12554
12239
  }
12555
12240
  const unusedFiles = safeReportDetector("detectOrphanFiles", () => detectOrphanFiles(graph), [], errorSink);
12556
12241
  const unusedExports = safeReportDetector("detectDeadExports", () => detectDeadExports(graph, config), [], errorSink);
12557
- const unusedDependencies = safeReportDetector("detectStalePackages", () => detectStalePackages(graph, config), [], errorSink);
12242
+ const unusedDependencies = safeReportDetector("detectStalePackages", () => detectStalePackages(graph, config, summaryCache), [], errorSink);
12558
12243
  const circularDependencies = safeReportDetector("detectCycles", () => detectCycles(graph), [], errorSink);
12559
12244
  const syntacticRedundantAliases = config.reportRedundancy ? [...safeReportDetector("detectRedundantAliases", () => detectRedundantAliases(graph), [], errorSink), ...safeReportDetector("detectUselessAliasedReExports", () => detectUselessAliasedReExports(graph), [], errorSink)] : [];
12560
12245
  const duplicateExports = config.reportRedundancy ? safeReportDetector("detectDuplicateExports", () => detectDuplicateExports(graph), [], errorSink) : [];
@@ -12648,6 +12333,478 @@ const generateReport = (graph, config) => {
12648
12333
  };
12649
12334
  };
12650
12335
 
12336
+ //#endregion
12337
+ //#region src/collect/entries-in-worker.ts
12338
+ /**
12339
+ * Runs `resolveEntries` on a dedicated worker thread so its ~90%-synchronous
12340
+ * fs work overlaps the main-thread analysis phases — the incremental-cache
12341
+ * warm path has no long parse `await` left to hide it behind. Entry content
12342
+ * reads stay live (fresh every run) exactly as inline. Worker infrastructure
12343
+ * failures fall back to the inline call (same result, just serialized); an
12344
+ * error thrown by `resolveEntries` itself rejects with the same message an
12345
+ * inline throw would, so the caller's fallback-to-empty-entries handling is
12346
+ * unchanged.
12347
+ */
12348
+ const resolveEntriesInWorker = async (config) => {
12349
+ let worker;
12350
+ try {
12351
+ worker = launchSiblingWorker(require("url").pathToFileURL(__filename).href, "entries-worker");
12352
+ } catch {
12353
+ return resolveEntries(config);
12354
+ }
12355
+ try {
12356
+ const outcome = await new Promise((resolveOutcome) => {
12357
+ worker.on("message", (message) => {
12358
+ if (message.type === "ready") worker.postMessage({
12359
+ type: "resolve-entries",
12360
+ config
12361
+ });
12362
+ else if (message.type === "result") resolveOutcome({
12363
+ kind: "result",
12364
+ entries: message.entries
12365
+ });
12366
+ else if (message.type === "error") resolveOutcome({
12367
+ kind: "analysis-error",
12368
+ errorMessage: message.errorMessage
12369
+ });
12370
+ });
12371
+ worker.on("error", () => resolveOutcome({ kind: "infra-failure" }));
12372
+ worker.on("exit", () => resolveOutcome({ kind: "infra-failure" }));
12373
+ });
12374
+ if (outcome.kind === "result") return outcome.entries;
12375
+ if (outcome.kind === "analysis-error") throw new Error(outcome.errorMessage);
12376
+ return resolveEntries(config);
12377
+ } finally {
12378
+ worker.terminate();
12379
+ }
12380
+ };
12381
+
12382
+ //#endregion
12383
+ //#region src/summary-cache.ts
12384
+ const WALK_SKIP_DIRECTORY_NAMES = new Set(["node_modules", ".git"]);
12385
+ const MANIFEST_LIKE_FILENAMES = new Set(require_constants.ANALYZED_MANIFEST_FILENAMES);
12386
+ const isManifestLikeFileName = (fileName) => MANIFEST_LIKE_FILENAMES.has(fileName) || (fileName.startsWith("tsconfig") || fileName.startsWith("jsconfig")) && fileName.endsWith(".json");
12387
+ const isResolverConfigFileName = (fileName) => fileName.includes("webpack") || fileName.startsWith("vite.config.") || fileName.startsWith("vitest.config.") || fileName.startsWith("babel.config.") || fileName.startsWith(".babelrc") || fileName.startsWith("jest.config.");
12388
+ const sha1Hex = (text) => node_crypto.default.createHash("sha1").update(text).digest("hex");
12389
+ const sha1OfFileBytes = (filePath) => {
12390
+ try {
12391
+ return node_crypto.default.createHash("sha1").update((0, node_fs.readFileSync)(filePath)).digest("hex");
12392
+ } catch {
12393
+ return null;
12394
+ }
12395
+ };
12396
+ const fileNameOfPosixPath = (posixPath) => posixPath.slice(posixPath.lastIndexOf("/") + 1);
12397
+ const deslopRequire = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
12398
+ const resolveOwnPackageVersion = () => {
12399
+ try {
12400
+ const packageJson = deslopRequire("deslop-js/package.json");
12401
+ return typeof packageJson?.version === "string" ? packageJson.version : "unknown";
12402
+ } catch {
12403
+ return "unknown";
12404
+ }
12405
+ };
12406
+ const walkTreeStats = (rootDirectory) => {
12407
+ const collected = /* @__PURE__ */ new Map();
12408
+ const followedLinkTargets = /* @__PURE__ */ new Set();
12409
+ const walk = (directory) => {
12410
+ let entries;
12411
+ try {
12412
+ entries = (0, node_fs.readdirSync)(directory, { withFileTypes: true });
12413
+ } catch {
12414
+ return;
12415
+ }
12416
+ for (const entry of entries) {
12417
+ const entryPath = `${directory}/${entry.name}`;
12418
+ if (entry.isDirectory()) {
12419
+ if (!WALK_SKIP_DIRECTORY_NAMES.has(entry.name)) walk(entryPath);
12420
+ continue;
12421
+ }
12422
+ if (entry.isSymbolicLink()) {
12423
+ if (WALK_SKIP_DIRECTORY_NAMES.has(entry.name)) continue;
12424
+ try {
12425
+ const linkStat = (0, node_fs.statSync)(entryPath);
12426
+ if (linkStat.isDirectory()) {
12427
+ const linkTarget = (0, node_fs.realpathSync)(entryPath);
12428
+ if (!followedLinkTargets.has(linkTarget)) {
12429
+ followedLinkTargets.add(linkTarget);
12430
+ walk(entryPath);
12431
+ }
12432
+ } else if (linkStat.isFile()) collected.set(entryPath, {
12433
+ m: linkStat.mtimeMs,
12434
+ s: linkStat.size
12435
+ });
12436
+ } catch {
12437
+ continue;
12438
+ }
12439
+ continue;
12440
+ }
12441
+ if (!entry.isFile()) continue;
12442
+ try {
12443
+ const fileStat = (0, node_fs.statSync)(entryPath);
12444
+ collected.set(entryPath, {
12445
+ m: fileStat.mtimeMs,
12446
+ s: fileStat.size
12447
+ });
12448
+ } catch {
12449
+ continue;
12450
+ }
12451
+ }
12452
+ };
12453
+ walk(toPosixPath((0, node_path.resolve)(rootDirectory)));
12454
+ return collected;
12455
+ };
12456
+ const compileGlobAlternation = (patterns, matchDotNames) => {
12457
+ const regexSources = [];
12458
+ for (const pattern of patterns) {
12459
+ const compiled = new minimatch.Minimatch(pattern, { dot: matchDotNames }).makeRe();
12460
+ if (compiled === false) return null;
12461
+ regexSources.push(compiled.source);
12462
+ }
12463
+ return regexSources.length === 0 ? null : new RegExp(regexSources.join("|"));
12464
+ };
12465
+ const countPathSegments = (relativePath) => {
12466
+ let segmentCount = 1;
12467
+ for (let charIndex = 0; charIndex < relativePath.length; charIndex++) if (relativePath.charCodeAt(charIndex) === 47) segmentCount++;
12468
+ return segmentCount;
12469
+ };
12470
+ const contentFingerprintOf = (filePath, fileStat) => `${filePath}:${fileStat.s}:${sha1OfFileBytes(filePath) ?? `stat-${fileStat.m}`}`;
12471
+ const computeCollectHash = (walkedStats) => {
12472
+ const fingerprintLines = [];
12473
+ for (const [filePath, fileStat] of walkedStats) fingerprintLines.push(isManifestLikeFileName(fileNameOfPosixPath(filePath)) ? contentFingerprintOf(filePath, fileStat) : filePath);
12474
+ fingerprintLines.sort();
12475
+ return sha1Hex(fingerprintLines.join("\n"));
12476
+ };
12477
+ const computeResolutionHash = (collectHash, walkedStats) => {
12478
+ const fingerprintLines = [];
12479
+ for (const [filePath, fileStat] of walkedStats) if (isResolverConfigFileName(fileNameOfPosixPath(filePath))) fingerprintLines.push(contentFingerprintOf(filePath, fileStat));
12480
+ fingerprintLines.sort();
12481
+ return sha1Hex(`${collectHash}\n${fingerprintLines.join("\n")}`);
12482
+ };
12483
+ const computeScopeHash = (config) => sha1Hex(JSON.stringify({
12484
+ deslopVersion: resolveOwnPackageVersion(),
12485
+ rootDir: toPosixPath((0, node_path.resolve)(config.rootDir)),
12486
+ entryPatterns: config.entryPatterns,
12487
+ ignorePatterns: config.ignorePatterns,
12488
+ includeExtensions: config.includeExtensions,
12489
+ reportTypes: config.reportTypes,
12490
+ includeEntryExports: config.includeEntryExports,
12491
+ reportRedundancy: config.reportRedundancy,
12492
+ tsConfigPath: config.tsConfigPath ?? null,
12493
+ paths: config.paths ?? null
12494
+ }));
12495
+ const isRecordValue = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
12496
+ const isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
12497
+ const isOptionalArray = (value) => value === void 0 || Array.isArray(value);
12498
+ const emptyStore = (scopeHash) => ({
12499
+ version: 2,
12500
+ scopeHash,
12501
+ fileList: null,
12502
+ resolutions: null,
12503
+ summaries: {},
12504
+ packageFacts: {}
12505
+ });
12506
+ const readPersistedStore = (cachePath, scopeHash) => {
12507
+ try {
12508
+ const parsed = JSON.parse((0, node_fs.readFileSync)(cachePath, "utf-8"));
12509
+ if (isRecordValue(parsed) && parsed.version === 2 && parsed.scopeHash === scopeHash && isRecordValue(parsed.summaries) && isRecordValue(parsed.packageFacts)) {
12510
+ const persisted = parsed;
12511
+ return {
12512
+ version: 2,
12513
+ scopeHash,
12514
+ fileList: isRecordValue(persisted.fileList) ? persisted.fileList : null,
12515
+ resolutions: isRecordValue(persisted.resolutions) && typeof persisted.resolutions.hash === "string" && isRecordValue(persisted.resolutions.entries) ? persisted.resolutions : null,
12516
+ summaries: persisted.summaries,
12517
+ packageFacts: persisted.packageFacts
12518
+ };
12519
+ }
12520
+ } catch {}
12521
+ return emptyStore(scopeHash);
12522
+ };
12523
+ const intersectLocalReferencesWithOwnExports = (parsed) => {
12524
+ if (parsed.localIdentifierReferences.length === 0) return [];
12525
+ const ownExportNames = new Set(parsed.exports.map((exportInfo) => exportInfo.name));
12526
+ return parsed.localIdentifierReferences.filter((identifierName) => ownExportNames.has(identifierName));
12527
+ };
12528
+ const toPersistedArray = (values) => values.length > 0 ? values : void 0;
12529
+ const serializeParsedSource = (parsed, shouldPersistDryPatternFields) => ({
12530
+ imports: toPersistedArray(parsed.imports),
12531
+ exports: toPersistedArray(parsed.exports),
12532
+ memberAccesses: toPersistedArray(parsed.memberAccesses),
12533
+ wholeObjectUses: toPersistedArray(parsed.wholeObjectUses),
12534
+ localIdentifierReferences: toPersistedArray(intersectLocalReferencesWithOwnExports(parsed)),
12535
+ referencedFilenames: toPersistedArray(parsed.referencedFilenames),
12536
+ ...shouldPersistDryPatternFields ? {
12537
+ redundantTypePatterns: toPersistedArray(parsed.redundantTypePatterns),
12538
+ identityWrappers: toPersistedArray(parsed.identityWrappers),
12539
+ typeDefinitionHashes: toPersistedArray(parsed.typeDefinitionHashes),
12540
+ inlineTypeLiterals: toPersistedArray(parsed.inlineTypeLiterals),
12541
+ simplifiableFunctions: toPersistedArray(parsed.simplifiableFunctions),
12542
+ simplifiableExpressions: toPersistedArray(parsed.simplifiableExpressions),
12543
+ duplicateConstantCandidates: toPersistedArray(parsed.duplicateConstantCandidates)
12544
+ } : {},
12545
+ errors: toPersistedArray(parsed.errors.map((deslopError) => deslopError.toJSON()))
12546
+ });
12547
+ const isPersistedErrorJson = (value) => isRecordValue(value) && typeof value.code === "string" && typeof value.module === "string" && typeof value.message === "string";
12548
+ const PERSISTED_SOURCE_ARRAY_FIELDS = [
12549
+ "imports",
12550
+ "exports",
12551
+ "memberAccesses",
12552
+ "wholeObjectUses",
12553
+ "localIdentifierReferences",
12554
+ "referencedFilenames",
12555
+ "redundantTypePatterns",
12556
+ "identityWrappers",
12557
+ "typeDefinitionHashes",
12558
+ "inlineTypeLiterals",
12559
+ "simplifiableFunctions",
12560
+ "simplifiableExpressions",
12561
+ "duplicateConstantCandidates",
12562
+ "errors"
12563
+ ];
12564
+ const reviveParsedSource = (persisted) => {
12565
+ if (!isRecordValue(persisted)) return null;
12566
+ for (const fieldName of PERSISTED_SOURCE_ARRAY_FIELDS) if (!isOptionalArray(persisted[fieldName])) return null;
12567
+ const source = persisted;
12568
+ const persistedErrors = source.errors ?? [];
12569
+ if (!persistedErrors.every(isPersistedErrorJson)) return null;
12570
+ return {
12571
+ imports: source.imports ?? [],
12572
+ exports: source.exports ?? [],
12573
+ memberAccesses: source.memberAccesses ?? [],
12574
+ wholeObjectUses: source.wholeObjectUses ?? [],
12575
+ localIdentifierReferences: source.localIdentifierReferences ?? [],
12576
+ referencedFilenames: source.referencedFilenames ?? [],
12577
+ redundantTypePatterns: source.redundantTypePatterns ?? [],
12578
+ identityWrappers: source.identityWrappers ?? [],
12579
+ typeDefinitionHashes: source.typeDefinitionHashes ?? [],
12580
+ inlineTypeLiterals: source.inlineTypeLiterals ?? [],
12581
+ simplifiableFunctions: source.simplifiableFunctions ?? [],
12582
+ simplifiableExpressions: source.simplifiableExpressions ?? [],
12583
+ duplicateConstantCandidates: source.duplicateConstantCandidates ?? [],
12584
+ errors: persistedErrors.map((errorJson) => new DeslopError({
12585
+ code: errorJson.code,
12586
+ module: errorJson.module,
12587
+ severity: errorJson.severity,
12588
+ message: errorJson.message,
12589
+ path: errorJson.path,
12590
+ detail: errorJson.detail
12591
+ }))
12592
+ };
12593
+ };
12594
+ const atomicWriteFile = (filePath, contents) => {
12595
+ try {
12596
+ (0, node_fs.mkdirSync)((0, node_path.dirname)(filePath), { recursive: true });
12597
+ const temporaryPath = `${filePath}.${process.pid}.tmp`;
12598
+ (0, node_fs.writeFileSync)(temporaryPath, contents);
12599
+ (0, node_fs.renameSync)(temporaryPath, filePath);
12600
+ } catch {}
12601
+ };
12602
+ const createSummaryCache = (cachePath, config) => {
12603
+ const scopeHash = computeScopeHash(config);
12604
+ const store = readPersistedStore(cachePath, scopeHash);
12605
+ const walkRoot = toPosixPath((0, node_path.resolve)(config.rootDir));
12606
+ const walkedStats = walkTreeStats(config.rootDir);
12607
+ const collectHash = computeCollectHash(walkedStats);
12608
+ const resolutionHash = computeResolutionHash(collectHash, walkedStats);
12609
+ const shouldPersistDryPatternFields = config.reportRedundancy;
12610
+ if (store.resolutions === null || store.resolutions.hash !== resolutionHash) store.resolutions = {
12611
+ hash: resolutionHash,
12612
+ entries: {}
12613
+ };
12614
+ const resolutionEntries = store.resolutions.entries;
12615
+ let isDirty = false;
12616
+ const activeSummaryPaths = /* @__PURE__ */ new Set();
12617
+ const activeResolutionKeys = /* @__PURE__ */ new Set();
12618
+ const activeFactPaths = /* @__PURE__ */ new Set();
12619
+ const sortedNameSetMemo = /* @__PURE__ */ new WeakMap();
12620
+ const statOfLive = (filePath) => {
12621
+ try {
12622
+ const fileStat = (0, node_fs.statSync)(filePath);
12623
+ return {
12624
+ m: fileStat.mtimeMs,
12625
+ s: fileStat.size
12626
+ };
12627
+ } catch {
12628
+ return null;
12629
+ }
12630
+ };
12631
+ const statOf = (filePath) => walkedStats.get(filePath) ?? statOfLive(filePath);
12632
+ return {
12633
+ lookupFileList: () => {
12634
+ const cachedFileList = store.fileList;
12635
+ if (cachedFileList === null || cachedFileList.hash !== collectHash || !isStringArray(cachedFileList.files)) return null;
12636
+ return cachedFileList.files.map((filePath, fileIndex) => ({
12637
+ index: fileIndex,
12638
+ path: filePath
12639
+ }));
12640
+ },
12641
+ storeFileList: (files) => {
12642
+ store.fileList = {
12643
+ hash: collectHash,
12644
+ files: files.map((file) => file.path)
12645
+ };
12646
+ isDirty = true;
12647
+ },
12648
+ lookupSummary: (filePath) => {
12649
+ const cachedSummary = store.summaries[filePath];
12650
+ if (!isRecordValue(cachedSummary)) return null;
12651
+ const fileStat = statOf(filePath);
12652
+ if (!fileStat) return null;
12653
+ if (fileStat.m !== cachedSummary.m || fileStat.s !== cachedSummary.s) {
12654
+ if (fileStat.s !== cachedSummary.s || typeof cachedSummary.h !== "string") return null;
12655
+ const contentHash = sha1OfFileBytes(filePath);
12656
+ if (contentHash === null || contentHash !== cachedSummary.h) return null;
12657
+ cachedSummary.m = fileStat.m;
12658
+ cachedSummary.s = fileStat.s;
12659
+ isDirty = true;
12660
+ }
12661
+ const revived = reviveParsedSource(cachedSummary.p);
12662
+ if (revived === null) return null;
12663
+ activeSummaryPaths.add(filePath);
12664
+ return revived;
12665
+ },
12666
+ storeSummary: (filePath, parsed) => {
12667
+ const walkStat = statOf(filePath);
12668
+ if (!walkStat) return;
12669
+ const contentHash = sha1OfFileBytes(filePath);
12670
+ if (contentHash === null) return;
12671
+ const liveStat = statOfLive(filePath);
12672
+ if (liveStat === null || liveStat.m !== walkStat.m || liveStat.s !== walkStat.s) return;
12673
+ store.summaries[filePath] = {
12674
+ m: walkStat.m,
12675
+ s: walkStat.s,
12676
+ h: contentHash,
12677
+ p: serializeParsedSource(parsed, shouldPersistDryPatternFields)
12678
+ };
12679
+ activeSummaryPaths.add(filePath);
12680
+ isDirty = true;
12681
+ },
12682
+ lookupResolution: (specifier, fromFile) => {
12683
+ const resolutionKey = `${(0, node_path.dirname)(fromFile)}::${specifier}`;
12684
+ const cachedResolution = resolutionEntries[resolutionKey];
12685
+ if (!isRecordValue(cachedResolution) || typeof cachedResolution.e !== "boolean") return null;
12686
+ activeResolutionKeys.add(resolutionKey);
12687
+ return {
12688
+ resolvedPath: typeof cachedResolution.p === "string" ? cachedResolution.p : void 0,
12689
+ isExternal: cachedResolution.e,
12690
+ packageName: typeof cachedResolution.n === "string" ? cachedResolution.n : void 0
12691
+ };
12692
+ },
12693
+ storeResolution: (specifier, fromFile, resolved) => {
12694
+ const resolutionKey = `${(0, node_path.dirname)(fromFile)}::${specifier}`;
12695
+ resolutionEntries[resolutionKey] = {
12696
+ p: resolved.resolvedPath ?? null,
12697
+ e: resolved.isExternal,
12698
+ n: resolved.packageName ?? null
12699
+ };
12700
+ activeResolutionKeys.add(resolutionKey);
12701
+ isDirty = true;
12702
+ },
12703
+ matchPackageNames: (filePath, kind, names, matcher) => {
12704
+ let nameSet = sortedNameSetMemo.get(names);
12705
+ if (nameSet === void 0) {
12706
+ const sortedNames = [...names].sort();
12707
+ nameSet = {
12708
+ sortedNames,
12709
+ hash: sha1Hex(sortedNames.join("\n"))
12710
+ };
12711
+ sortedNameSetMemo.set(names, nameSet);
12712
+ }
12713
+ activeFactPaths.add(filePath);
12714
+ const fileStat = statOf(filePath);
12715
+ const existingEntry = isRecordValue(store.packageFacts[filePath]) ? store.packageFacts[filePath] : null;
12716
+ let validEntry = fileStat !== null && existingEntry !== null && existingEntry.m === fileStat.m && existingEntry.s === fileStat.s ? existingEntry : null;
12717
+ const existingMatch = validEntry?.[kind];
12718
+ if (isRecordValue(existingMatch) && existingMatch.h === nameSet.hash && isStringArray(existingMatch.matched)) return existingMatch.matched;
12719
+ const content = (0, node_fs.readFileSync)(filePath, "utf-8");
12720
+ const contentHash = sha1Hex(content);
12721
+ if (validEntry === null && fileStat !== null && existingEntry?.h === contentHash) {
12722
+ existingEntry.m = fileStat.m;
12723
+ existingEntry.s = fileStat.s;
12724
+ isDirty = true;
12725
+ validEntry = existingEntry;
12726
+ const repairedMatch = validEntry[kind];
12727
+ if (isRecordValue(repairedMatch) && repairedMatch.h === nameSet.hash && isStringArray(repairedMatch.matched)) return repairedMatch.matched;
12728
+ }
12729
+ const matchedNames = nameSet.sortedNames.filter((packageName) => matcher(content, packageName));
12730
+ if (fileStat !== null) {
12731
+ const factEntry = validEntry ?? {
12732
+ m: fileStat.m,
12733
+ s: fileStat.s,
12734
+ h: contentHash
12735
+ };
12736
+ factEntry[kind] = {
12737
+ h: nameSet.hash,
12738
+ matched: matchedNames
12739
+ };
12740
+ store.packageFacts[filePath] = factEntry;
12741
+ isDirty = true;
12742
+ }
12743
+ return matchedNames;
12744
+ },
12745
+ matchWalkedFiles: (query) => {
12746
+ if (toPosixPath((0, node_path.resolve)(query.cwd)) !== walkRoot) return null;
12747
+ const positiveMatcher = compileGlobAlternation(query.patterns, query.dot === true);
12748
+ if (positiveMatcher === null) return null;
12749
+ const ignoreMatcher = query.ignore.length > 0 ? compileGlobAlternation(query.ignore, true) : null;
12750
+ if (query.ignore.length > 0 && ignoreMatcher === null) return null;
12751
+ const rootPrefixLength = walkRoot.length + 1;
12752
+ const matchedPaths = [];
12753
+ for (const filePath of walkedStats.keys()) {
12754
+ const relativePath = filePath.slice(rootPrefixLength);
12755
+ if (countPathSegments(relativePath) > query.deep) continue;
12756
+ if (ignoreMatcher !== null && ignoreMatcher.test(relativePath)) continue;
12757
+ if (positiveMatcher.test(relativePath)) matchedPaths.push(filePath);
12758
+ }
12759
+ return matchedPaths.sort();
12760
+ },
12761
+ save: () => {
12762
+ if (!isDirty) return;
12763
+ const compactedSummaries = {};
12764
+ for (const filePath of activeSummaryPaths) {
12765
+ const summaryEntry = store.summaries[filePath];
12766
+ if (summaryEntry !== void 0) compactedSummaries[filePath] = summaryEntry;
12767
+ }
12768
+ const compactedFacts = {};
12769
+ for (const filePath of activeFactPaths) {
12770
+ const factEntry = store.packageFacts[filePath];
12771
+ if (factEntry !== void 0) compactedFacts[filePath] = factEntry;
12772
+ }
12773
+ const compactedResolutions = {};
12774
+ for (const resolutionKey of activeResolutionKeys) {
12775
+ const resolutionEntry = resolutionEntries[resolutionKey];
12776
+ if (resolutionEntry !== void 0) compactedResolutions[resolutionKey] = resolutionEntry;
12777
+ }
12778
+ const serialized = JSON.stringify({
12779
+ version: 2,
12780
+ scopeHash,
12781
+ fileList: store.fileList,
12782
+ resolutions: {
12783
+ hash: resolutionHash,
12784
+ entries: compactedResolutions
12785
+ },
12786
+ summaries: compactedSummaries,
12787
+ packageFacts: compactedFacts
12788
+ });
12789
+ if (serialized.length > 268435456) return;
12790
+ atomicWriteFile(cachePath, serialized);
12791
+ }
12792
+ };
12793
+ };
12794
+ /**
12795
+ * Loads the incremental cache configured at `config.incrementalCachePath`.
12796
+ * Returns `null` (analysis runs exactly as without a cache) when the path is
12797
+ * unset or anything about initialization fails.
12798
+ */
12799
+ const loadSummaryCache = (config) => {
12800
+ if (!config.incrementalCachePath) return null;
12801
+ try {
12802
+ return createSummaryCache(config.incrementalCachePath, config);
12803
+ } catch {
12804
+ return null;
12805
+ }
12806
+ };
12807
+
12651
12808
  //#endregion
12652
12809
  //#region src/utils/collect-git-ignored-paths.ts
12653
12810
  /**
@@ -12686,7 +12843,7 @@ const collectGitIgnoredPaths = (rootDirectory, candidatePaths) => {
12686
12843
  cwd: rootDirectory,
12687
12844
  input: candidatePaths.join("\0"),
12688
12845
  encoding: "utf-8",
12689
- maxBuffer: GIT_CHECK_IGNORE_MAX_BUFFER_BYTES
12846
+ maxBuffer: require_constants.GIT_CHECK_IGNORE_MAX_BUFFER_BYTES
12690
12847
  });
12691
12848
  if (result.error) {
12692
12849
  const gitBinaryMissing = "code" in result.error && result.error.code === "ENOENT";
@@ -12802,7 +12959,7 @@ const fillSemanticConfig = (semanticOverrides) => {
12802
12959
  reportRedundantVariableAliases: overrides.reportRedundantVariableAliases ?? true,
12803
12960
  reportMisclassifiedDependencies: overrides.reportMisclassifiedDependencies ?? true,
12804
12961
  reportRoundTripAliases: overrides.reportRoundTripAliases ?? true,
12805
- decoratorAllowlist: overrides.decoratorAllowlist ?? DEFAULT_SEMANTIC_DECORATOR_ALLOWLIST
12962
+ decoratorAllowlist: overrides.decoratorAllowlist ?? require_constants.DEFAULT_SEMANTIC_DECORATOR_ALLOWLIST
12806
12963
  };
12807
12964
  };
12808
12965
  const fillDuplicateBlocksConfig = (duplicateBlocksOverrides) => {
@@ -12837,11 +12994,12 @@ const fillComplexityConfig = (complexityOverrides) => {
12837
12994
  };
12838
12995
  const defineConfig = (options) => ({
12839
12996
  rootDir: (0, node_path.resolve)(options.rootDir),
12840
- entryPatterns: options.entryPatterns ?? DEFAULT_ENTRY_GLOBS,
12997
+ entryPatterns: options.entryPatterns ?? require_constants.DEFAULT_ENTRY_GLOBS,
12841
12998
  ignorePatterns: options.ignorePatterns ?? [],
12842
- includeExtensions: options.includeExtensions ?? DEFAULT_EXTENSIONS,
12999
+ includeExtensions: options.includeExtensions ?? require_constants.DEFAULT_EXTENSIONS,
12843
13000
  tsConfigPath: options.tsConfigPath,
12844
13001
  paths: options.paths,
13002
+ incrementalCachePath: options.incrementalCachePath,
12845
13003
  reportTypes: options.reportTypes ?? false,
12846
13004
  includeEntryExports: options.includeEntryExports ?? false,
12847
13005
  reportRedundancy: options.reportRedundancy ?? true,
@@ -12952,7 +13110,7 @@ const analyze = async (config) => {
12952
13110
  }));
12953
13111
  }
12954
13112
  const absoluteRoot = (0, node_path.resolve)(config.rootDir);
12955
- const outputDirectoryExclusions = OUTPUT_DIRECTORIES.flatMap((outputDirectory) => [`${absoluteRoot}/${outputDirectory}/**`, `${absoluteRoot}/**/${outputDirectory}/**`]);
13113
+ const outputDirectoryExclusions = require_constants.OUTPUT_DIRECTORIES.flatMap((outputDirectory) => [`${absoluteRoot}/${outputDirectory}/**`, `${absoluteRoot}/**/${outputDirectory}/**`]);
12956
13114
  const allExclusionPatterns = [
12957
13115
  ...workspaceDiscovery.excludedDirectories.map((directory) => `${directory}/**`),
12958
13116
  ...frameworkIgnorePatterns,
@@ -12962,24 +13120,26 @@ const analyze = async (config) => {
12962
13120
  ...config,
12963
13121
  ignorePatterns: [...config.ignorePatterns, ...allExclusionPatterns]
12964
13122
  } : config;
13123
+ const entriesPromise = (configWithExclusions.incrementalCachePath ? resolveEntriesInWorker(configWithExclusions) : resolveEntries(configWithExclusions)).catch((entriesError) => {
13124
+ setupErrors.push(new WorkspaceError({
13125
+ code: "workspace-discovery-failed",
13126
+ message: "resolveEntries failed — defaulting to empty entry set",
13127
+ path: config.rootDir,
13128
+ detail: describeUnknownError(entriesError)
13129
+ }));
13130
+ return {
13131
+ productionEntries: [],
13132
+ testEntries: [],
13133
+ alwaysUsedFiles: []
13134
+ };
13135
+ });
13136
+ const summaryCache = loadSummaryCache(configWithExclusions);
12965
13137
  let files;
12966
- let discoveredEntries;
12967
- try {
12968
- const [collectedFiles, resolvedEntries] = await Promise.all([collectSourceFiles(configWithExclusions), resolveEntries(configWithExclusions).catch((entriesError) => {
12969
- setupErrors.push(new WorkspaceError({
12970
- code: "workspace-discovery-failed",
12971
- message: "resolveEntries failed — defaulting to empty entry set",
12972
- path: config.rootDir,
12973
- detail: describeUnknownError(entriesError)
12974
- }));
12975
- return {
12976
- productionEntries: [],
12977
- testEntries: [],
12978
- alwaysUsedFiles: []
12979
- };
12980
- })]);
12981
- files = collectedFiles;
12982
- discoveredEntries = resolvedEntries;
13138
+ const cachedFileList = summaryCache?.lookupFileList() ?? null;
13139
+ if (cachedFileList !== null) files = cachedFileList;
13140
+ else try {
13141
+ files = await collectSourceFiles(configWithExclusions);
13142
+ summaryCache?.storeFileList(files);
12983
13143
  } catch (collectError) {
12984
13144
  setupErrors.push(new WorkspaceError({
12985
13145
  code: "workspace-discovery-failed",
@@ -12990,9 +13150,6 @@ const analyze = async (config) => {
12990
13150
  }));
12991
13151
  return buildEmptyScanResult(setupErrors, performance.now() - pipelineStartTime);
12992
13152
  }
12993
- const productionEntrySet = new Set(discoveredEntries.productionEntries);
12994
- const testEntrySet = new Set(discoveredEntries.testEntries);
12995
- const alwaysUsedFileSet = new Set(discoveredEntries.alwaysUsedFiles);
12996
13153
  const gitIgnoreResult = collectGitIgnoredPaths((0, node_path.resolve)(config.rootDir), files.map((file) => file.path));
12997
13154
  const gitIgnoredFileSet = gitIgnoreResult.ignoredPaths;
12998
13155
  if (gitIgnoreResult.gitUnavailable) setupErrors.push(new WorkspaceError({
@@ -13024,7 +13181,41 @@ const analyze = async (config) => {
13024
13181
  }));
13025
13182
  return buildEmptyScanResult(setupErrors, performance.now() - pipelineStartTime);
13026
13183
  }
13027
- const parsedModules = await parseFilesInParallel(files);
13184
+ const resolveModuleThroughCache = (specifier, fromFile) => {
13185
+ if (summaryCache === null) return moduleResolver.resolveModule(specifier, fromFile);
13186
+ const cachedResolution = summaryCache.lookupResolution(specifier, fromFile);
13187
+ if (cachedResolution !== null) return cachedResolution;
13188
+ const resolved = moduleResolver.resolveModule(specifier, fromFile);
13189
+ summaryCache.storeResolution(specifier, fromFile, resolved);
13190
+ return resolved;
13191
+ };
13192
+ let parsedModules;
13193
+ let summaryMissCount = 0;
13194
+ if (summaryCache === null) parsedModules = await parseFilesInParallel(files);
13195
+ else {
13196
+ parsedModules = new Array(files.length);
13197
+ const missedFiles = [];
13198
+ const missedPositions = [];
13199
+ for (let fileIndex = 0; fileIndex < files.length; fileIndex++) {
13200
+ const cachedSummary = summaryCache.lookupSummary(files[fileIndex].path);
13201
+ if (cachedSummary !== null) {
13202
+ parsedModules[fileIndex] = cachedSummary;
13203
+ continue;
13204
+ }
13205
+ missedFiles.push(files[fileIndex]);
13206
+ missedPositions.push(fileIndex);
13207
+ }
13208
+ summaryMissCount = missedFiles.length;
13209
+ const parsedMissedModules = await parseFilesInParallel(missedFiles);
13210
+ for (let missIndex = 0; missIndex < missedFiles.length; missIndex++) {
13211
+ parsedModules[missedPositions[missIndex]] = parsedMissedModules[missIndex];
13212
+ summaryCache.storeSummary(missedFiles[missIndex].path, parsedMissedModules[missIndex]);
13213
+ }
13214
+ }
13215
+ const discoveredEntries = await entriesPromise;
13216
+ const productionEntrySet = new Set(discoveredEntries.productionEntries);
13217
+ const testEntrySet = new Set(discoveredEntries.testEntries);
13218
+ const alwaysUsedFileSet = new Set(discoveredEntries.alwaysUsedFiles);
13028
13219
  const graphInputs = [];
13029
13220
  for (let fileIndex = 0; fileIndex < files.length; fileIndex++) {
13030
13221
  const file = files[fileIndex];
@@ -13032,7 +13223,7 @@ const analyze = async (config) => {
13032
13223
  const resolvedImportMap = /* @__PURE__ */ new Map();
13033
13224
  const safeResolveImport = (specifier) => {
13034
13225
  try {
13035
- return moduleResolver.resolveModule(specifier, file.path);
13226
+ return resolveModuleThroughCache(specifier, file.path);
13036
13227
  } catch (resolveError) {
13037
13228
  setupErrors.push(new ResolverError({
13038
13229
  severity: "warning",
@@ -13112,7 +13303,7 @@ const analyze = async (config) => {
13112
13303
  for (const importInfo of parsedStyleModule.imports) {
13113
13304
  let resolvedImport;
13114
13305
  try {
13115
- resolvedImport = moduleResolver.resolveModule(importInfo.specifier, styleFilePath);
13306
+ resolvedImport = resolveModuleThroughCache(importInfo.specifier, styleFilePath);
13116
13307
  } catch (styleResolveError) {
13117
13308
  setupErrors.push(new ResolverError({
13118
13309
  severity: "warning",
@@ -13176,7 +13367,7 @@ const analyze = async (config) => {
13176
13367
  }
13177
13368
  let analysisResult;
13178
13369
  try {
13179
- analysisResult = generateReport(moduleGraph, config);
13370
+ analysisResult = generateReport(moduleGraph, config, summaryCache ?? void 0);
13180
13371
  } catch (reportError) {
13181
13372
  setupErrors.push(new DetectorError({
13182
13373
  module: "report",
@@ -13186,6 +13377,11 @@ const analyze = async (config) => {
13186
13377
  }));
13187
13378
  return buildEmptyScanResult(setupErrors, performance.now() - pipelineStartTime);
13188
13379
  }
13380
+ summaryCache?.save();
13381
+ if (summaryCache !== null) analysisResult.incrementalCacheStats = {
13382
+ summaryHits: files.length - summaryMissCount,
13383
+ summaryMisses: summaryMissCount
13384
+ };
13189
13385
  if (setupErrors.length > 0) analysisResult.analysisErrors = [...setupErrors, ...analysisResult.analysisErrors];
13190
13386
  analysisResult.analysisTimeMs = performance.now() - pipelineStartTime;
13191
13387
  return analysisResult;