deslop-js 0.0.16 → 0.0.17-dev.7acf549
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 +181 -20
- package/dist/index.mjs +180 -20
- package/dist/parse-worker.mjs +2248 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -35,6 +35,10 @@ let node_fs_promises = require("node:fs/promises");
|
|
|
35
35
|
let oxc_parser = require("oxc-parser");
|
|
36
36
|
let typescript = require("typescript");
|
|
37
37
|
typescript = __toESM(typescript, 1);
|
|
38
|
+
let node_worker_threads = require("node:worker_threads");
|
|
39
|
+
let node_url = require("node:url");
|
|
40
|
+
let node_os = require("node:os");
|
|
41
|
+
node_os = __toESM(node_os, 1);
|
|
38
42
|
let oxc_resolver = require("oxc-resolver");
|
|
39
43
|
let minimatch = require("minimatch");
|
|
40
44
|
|
|
@@ -6141,6 +6145,148 @@ const discoverToolingEntryPoints = (rootDir, workspacePackages) => {
|
|
|
6141
6145
|
};
|
|
6142
6146
|
};
|
|
6143
6147
|
|
|
6148
|
+
//#endregion
|
|
6149
|
+
//#region src/utils/resolve-available-concurrency.ts
|
|
6150
|
+
const resolveAvailableConcurrency = () => {
|
|
6151
|
+
const available = node_os.default.availableParallelism();
|
|
6152
|
+
if (!Number.isFinite(available) || available < 1) return 1;
|
|
6153
|
+
return Math.max(1, Math.min(Math.floor(available), 16));
|
|
6154
|
+
};
|
|
6155
|
+
|
|
6156
|
+
//#endregion
|
|
6157
|
+
//#region src/collect/parallel-parse.ts
|
|
6158
|
+
const deserializeErrors = (serializedErrors) => serializedErrors.map((errorJson) => new DeslopError({
|
|
6159
|
+
code: errorJson.code,
|
|
6160
|
+
module: errorJson.module,
|
|
6161
|
+
severity: errorJson.severity,
|
|
6162
|
+
message: errorJson.message,
|
|
6163
|
+
path: errorJson.path,
|
|
6164
|
+
detail: errorJson.detail
|
|
6165
|
+
}));
|
|
6166
|
+
const deserializeParsedSource = (serialized) => ({
|
|
6167
|
+
imports: serialized.imports,
|
|
6168
|
+
exports: serialized.exports,
|
|
6169
|
+
memberAccesses: serialized.memberAccesses,
|
|
6170
|
+
wholeObjectUses: serialized.wholeObjectUses,
|
|
6171
|
+
localIdentifierReferences: serialized.localIdentifierReferences,
|
|
6172
|
+
referencedFilenames: serialized.referencedFilenames,
|
|
6173
|
+
redundantTypePatterns: serialized.redundantTypePatterns,
|
|
6174
|
+
identityWrappers: serialized.identityWrappers,
|
|
6175
|
+
typeDefinitionHashes: serialized.typeDefinitionHashes,
|
|
6176
|
+
inlineTypeLiterals: serialized.inlineTypeLiterals,
|
|
6177
|
+
simplifiableFunctions: serialized.simplifiableFunctions,
|
|
6178
|
+
simplifiableExpressions: serialized.simplifiableExpressions,
|
|
6179
|
+
duplicateConstantCandidates: serialized.duplicateConstantCandidates,
|
|
6180
|
+
errors: deserializeErrors(serialized.errors)
|
|
6181
|
+
});
|
|
6182
|
+
const resolveWorkerPath = () => {
|
|
6183
|
+
const currentUrl = require("url").pathToFileURL(__filename).href;
|
|
6184
|
+
if (currentUrl.endsWith(".ts")) return (0, node_url.fileURLToPath)(new URL("./parse-worker.ts", currentUrl));
|
|
6185
|
+
return (0, node_url.fileURLToPath)(new URL("./parse-worker.mjs", currentUrl));
|
|
6186
|
+
};
|
|
6187
|
+
const createWorker = (workerPath) => {
|
|
6188
|
+
return new node_worker_threads.Worker(workerPath, { ...workerPath.endsWith(".ts") ? { execArgv: ["--import", "tsx"] } : {} });
|
|
6189
|
+
};
|
|
6190
|
+
const waitForReady = (worker) => new Promise((resolve, reject) => {
|
|
6191
|
+
const onMessage = (message) => {
|
|
6192
|
+
if (message.type === "ready") {
|
|
6193
|
+
worker.off("message", onMessage);
|
|
6194
|
+
worker.off("error", onError);
|
|
6195
|
+
resolve();
|
|
6196
|
+
}
|
|
6197
|
+
};
|
|
6198
|
+
const onError = (error) => {
|
|
6199
|
+
worker.off("message", onMessage);
|
|
6200
|
+
worker.off("error", onError);
|
|
6201
|
+
reject(error);
|
|
6202
|
+
};
|
|
6203
|
+
worker.on("message", onMessage);
|
|
6204
|
+
worker.on("error", onError);
|
|
6205
|
+
});
|
|
6206
|
+
const parseFilesWithWorkerPool = async (files, workerCount) => {
|
|
6207
|
+
const workerPath = resolveWorkerPath();
|
|
6208
|
+
const results = new Array(files.length);
|
|
6209
|
+
const workers = [];
|
|
6210
|
+
try {
|
|
6211
|
+
for (let workerIndex = 0; workerIndex < workerCount; workerIndex++) workers.push(createWorker(workerPath));
|
|
6212
|
+
await Promise.all(workers.map(waitForReady));
|
|
6213
|
+
} catch {
|
|
6214
|
+
for (const worker of workers) worker.terminate();
|
|
6215
|
+
return files.map((file) => parseSourceFile(file.path));
|
|
6216
|
+
}
|
|
6217
|
+
let nextFileIndex = 0;
|
|
6218
|
+
let completedCount = 0;
|
|
6219
|
+
return new Promise((resolve, reject) => {
|
|
6220
|
+
const dispatchNext = (worker) => {
|
|
6221
|
+
if (nextFileIndex >= files.length) return;
|
|
6222
|
+
const fileIndex = nextFileIndex;
|
|
6223
|
+
nextFileIndex += 1;
|
|
6224
|
+
worker.postMessage({
|
|
6225
|
+
type: "parse",
|
|
6226
|
+
filePath: files[fileIndex].path,
|
|
6227
|
+
fileIndex
|
|
6228
|
+
});
|
|
6229
|
+
};
|
|
6230
|
+
const onWorkerMessage = (worker) => (message) => {
|
|
6231
|
+
if (message.type === "result") {
|
|
6232
|
+
results[message.fileIndex] = deserializeParsedSource(message.parsed);
|
|
6233
|
+
completedCount += 1;
|
|
6234
|
+
if (completedCount === files.length) {
|
|
6235
|
+
cleanup();
|
|
6236
|
+
resolve(results);
|
|
6237
|
+
} else dispatchNext(worker);
|
|
6238
|
+
} else if (message.type === "error") {
|
|
6239
|
+
results[message.fileIndex] = {
|
|
6240
|
+
imports: [],
|
|
6241
|
+
exports: [],
|
|
6242
|
+
memberAccesses: [],
|
|
6243
|
+
wholeObjectUses: [],
|
|
6244
|
+
localIdentifierReferences: [],
|
|
6245
|
+
referencedFilenames: [],
|
|
6246
|
+
redundantTypePatterns: [],
|
|
6247
|
+
identityWrappers: [],
|
|
6248
|
+
typeDefinitionHashes: [],
|
|
6249
|
+
inlineTypeLiterals: [],
|
|
6250
|
+
simplifiableFunctions: [],
|
|
6251
|
+
simplifiableExpressions: [],
|
|
6252
|
+
duplicateConstantCandidates: [],
|
|
6253
|
+
errors: [new ParseError({
|
|
6254
|
+
code: "parse-failed",
|
|
6255
|
+
message: `Worker parse failed: ${message.errorMessage}`,
|
|
6256
|
+
path: message.filePath
|
|
6257
|
+
})]
|
|
6258
|
+
};
|
|
6259
|
+
completedCount += 1;
|
|
6260
|
+
if (completedCount === files.length) {
|
|
6261
|
+
cleanup();
|
|
6262
|
+
resolve(results);
|
|
6263
|
+
} else dispatchNext(worker);
|
|
6264
|
+
}
|
|
6265
|
+
};
|
|
6266
|
+
const cleanup = () => {
|
|
6267
|
+
for (const worker of workers) worker.terminate();
|
|
6268
|
+
};
|
|
6269
|
+
for (const worker of workers) {
|
|
6270
|
+
worker.on("message", onWorkerMessage(worker));
|
|
6271
|
+
worker.on("error", (error) => {
|
|
6272
|
+
cleanup();
|
|
6273
|
+
reject(error);
|
|
6274
|
+
});
|
|
6275
|
+
}
|
|
6276
|
+
for (const worker of workers) dispatchNext(worker);
|
|
6277
|
+
});
|
|
6278
|
+
};
|
|
6279
|
+
const parseFilesInParallel = async (files) => {
|
|
6280
|
+
if (files.length <= 50) return files.map((file) => parseSourceFile(file.path));
|
|
6281
|
+
const concurrency = resolveAvailableConcurrency();
|
|
6282
|
+
if (concurrency <= 1) return files.map((file) => parseSourceFile(file.path));
|
|
6283
|
+
try {
|
|
6284
|
+
return await parseFilesWithWorkerPool(files, concurrency);
|
|
6285
|
+
} catch {
|
|
6286
|
+
return files.map((file) => parseSourceFile(file.path));
|
|
6287
|
+
}
|
|
6288
|
+
};
|
|
6289
|
+
|
|
6144
6290
|
//#endregion
|
|
6145
6291
|
//#region src/utils/is-platform-builtin-or-virtual.ts
|
|
6146
6292
|
const BUILTIN_SUBPATH_NODE_MODULES = new Set([
|
|
@@ -7650,8 +7796,11 @@ const collectPnpmWorkspaceOverrideMappings = (rootDir) => {
|
|
|
7650
7796
|
};
|
|
7651
7797
|
|
|
7652
7798
|
//#endregion
|
|
7653
|
-
//#region src/utils/
|
|
7799
|
+
//#region src/utils/escape-reg-exp.ts
|
|
7654
7800
|
const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7801
|
+
|
|
7802
|
+
//#endregion
|
|
7803
|
+
//#region src/utils/matches-package-import-reference.ts
|
|
7655
7804
|
const matchesPackageImportReference = (content, packageName) => {
|
|
7656
7805
|
const escapedPackageName = escapeRegExp(packageName);
|
|
7657
7806
|
const subpathPattern = `(?:/[^'"]*)?`;
|
|
@@ -7664,6 +7813,13 @@ const matchesPackageImportReference = (content, packageName) => {
|
|
|
7664
7813
|
].some((pattern) => pattern.test(content));
|
|
7665
7814
|
};
|
|
7666
7815
|
|
|
7816
|
+
//#endregion
|
|
7817
|
+
//#region src/utils/matches-package-token-reference.ts
|
|
7818
|
+
const matchesPackageTokenReference = (command, packageName) => {
|
|
7819
|
+
const escapedPackageName = escapeRegExp(packageName);
|
|
7820
|
+
return new RegExp(`(?:^|[\\s='"\`(,;:|&])${escapedPackageName}(?:/[^\\s'"\`]*)?(?=$|[\\s='"\`),;:|&])`).test(command);
|
|
7821
|
+
};
|
|
7822
|
+
|
|
7667
7823
|
//#endregion
|
|
7668
7824
|
//#region src/report/packages.ts
|
|
7669
7825
|
const discoverAllPackageJsonPaths = (rootDir) => {
|
|
@@ -7953,6 +8109,10 @@ const collectScriptReferencedPackages = (packageJsonPath, declaredNames, binToPa
|
|
|
7953
8109
|
if (typeof scriptCommand !== "string") continue;
|
|
7954
8110
|
const commandReferenced = collectCommandReferencedPackages(scriptCommand, declaredNames, binToPackage);
|
|
7955
8111
|
for (const packageName of commandReferenced) referenced.add(packageName);
|
|
8112
|
+
for (const declaredName of declaredNames) {
|
|
8113
|
+
if (referenced.has(declaredName)) continue;
|
|
8114
|
+
if (matchesPackageTokenReference(scriptCommand, declaredName)) referenced.add(declaredName);
|
|
8115
|
+
}
|
|
7956
8116
|
}
|
|
7957
8117
|
} catch {
|
|
7958
8118
|
return referenced;
|
|
@@ -12576,8 +12736,23 @@ const analyze = async (config) => {
|
|
|
12576
12736
|
ignorePatterns: [...config.ignorePatterns, ...allExclusionPatterns]
|
|
12577
12737
|
} : config;
|
|
12578
12738
|
let files;
|
|
12739
|
+
let discoveredEntries;
|
|
12579
12740
|
try {
|
|
12580
|
-
|
|
12741
|
+
const [collectedFiles, resolvedEntries] = await Promise.all([collectSourceFiles(configWithExclusions), resolveEntries(configWithExclusions).catch((entriesError) => {
|
|
12742
|
+
setupErrors.push(new WorkspaceError({
|
|
12743
|
+
code: "workspace-discovery-failed",
|
|
12744
|
+
message: "resolveEntries failed — defaulting to empty entry set",
|
|
12745
|
+
path: config.rootDir,
|
|
12746
|
+
detail: describeUnknownError(entriesError)
|
|
12747
|
+
}));
|
|
12748
|
+
return {
|
|
12749
|
+
productionEntries: [],
|
|
12750
|
+
testEntries: [],
|
|
12751
|
+
alwaysUsedFiles: []
|
|
12752
|
+
};
|
|
12753
|
+
})]);
|
|
12754
|
+
files = collectedFiles;
|
|
12755
|
+
discoveredEntries = resolvedEntries;
|
|
12581
12756
|
} catch (collectError) {
|
|
12582
12757
|
setupErrors.push(new WorkspaceError({
|
|
12583
12758
|
code: "workspace-discovery-failed",
|
|
@@ -12588,22 +12763,6 @@ const analyze = async (config) => {
|
|
|
12588
12763
|
}));
|
|
12589
12764
|
return buildEmptyScanResult(setupErrors, performance.now() - pipelineStartTime);
|
|
12590
12765
|
}
|
|
12591
|
-
let discoveredEntries;
|
|
12592
|
-
try {
|
|
12593
|
-
discoveredEntries = await resolveEntries(configWithExclusions);
|
|
12594
|
-
} catch (entriesError) {
|
|
12595
|
-
setupErrors.push(new WorkspaceError({
|
|
12596
|
-
code: "workspace-discovery-failed",
|
|
12597
|
-
message: "resolveEntries failed — defaulting to empty entry set",
|
|
12598
|
-
path: config.rootDir,
|
|
12599
|
-
detail: describeUnknownError(entriesError)
|
|
12600
|
-
}));
|
|
12601
|
-
discoveredEntries = {
|
|
12602
|
-
productionEntries: [],
|
|
12603
|
-
testEntries: [],
|
|
12604
|
-
alwaysUsedFiles: []
|
|
12605
|
-
};
|
|
12606
|
-
}
|
|
12607
12766
|
const productionEntrySet = new Set(discoveredEntries.productionEntries);
|
|
12608
12767
|
const testEntrySet = new Set(discoveredEntries.testEntries);
|
|
12609
12768
|
const alwaysUsedFileSet = new Set(discoveredEntries.alwaysUsedFiles);
|
|
@@ -12630,9 +12789,11 @@ const analyze = async (config) => {
|
|
|
12630
12789
|
}));
|
|
12631
12790
|
return buildEmptyScanResult(setupErrors, performance.now() - pipelineStartTime);
|
|
12632
12791
|
}
|
|
12792
|
+
const parsedModules = await parseFilesInParallel(files);
|
|
12633
12793
|
const graphInputs = [];
|
|
12634
|
-
for (
|
|
12635
|
-
const
|
|
12794
|
+
for (let fileIndex = 0; fileIndex < files.length; fileIndex++) {
|
|
12795
|
+
const file = files[fileIndex];
|
|
12796
|
+
const parsedModule = parsedModules[fileIndex];
|
|
12636
12797
|
const resolvedImportMap = /* @__PURE__ */ new Map();
|
|
12637
12798
|
const safeResolveImport = (specifier) => {
|
|
12638
12799
|
try {
|
package/dist/index.mjs
CHANGED
|
@@ -4,6 +4,9 @@ import fg from "fast-glob";
|
|
|
4
4
|
import { readFile } from "node:fs/promises";
|
|
5
5
|
import { parseSync } from "oxc-parser";
|
|
6
6
|
import ts from "typescript";
|
|
7
|
+
import { Worker } from "node:worker_threads";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import os from "node:os";
|
|
7
10
|
import { ResolverFactory } from "oxc-resolver";
|
|
8
11
|
import { minimatch } from "minimatch";
|
|
9
12
|
|
|
@@ -6110,6 +6113,148 @@ const discoverToolingEntryPoints = (rootDir, workspacePackages) => {
|
|
|
6110
6113
|
};
|
|
6111
6114
|
};
|
|
6112
6115
|
|
|
6116
|
+
//#endregion
|
|
6117
|
+
//#region src/utils/resolve-available-concurrency.ts
|
|
6118
|
+
const resolveAvailableConcurrency = () => {
|
|
6119
|
+
const available = os.availableParallelism();
|
|
6120
|
+
if (!Number.isFinite(available) || available < 1) return 1;
|
|
6121
|
+
return Math.max(1, Math.min(Math.floor(available), 16));
|
|
6122
|
+
};
|
|
6123
|
+
|
|
6124
|
+
//#endregion
|
|
6125
|
+
//#region src/collect/parallel-parse.ts
|
|
6126
|
+
const deserializeErrors = (serializedErrors) => serializedErrors.map((errorJson) => new DeslopError({
|
|
6127
|
+
code: errorJson.code,
|
|
6128
|
+
module: errorJson.module,
|
|
6129
|
+
severity: errorJson.severity,
|
|
6130
|
+
message: errorJson.message,
|
|
6131
|
+
path: errorJson.path,
|
|
6132
|
+
detail: errorJson.detail
|
|
6133
|
+
}));
|
|
6134
|
+
const deserializeParsedSource = (serialized) => ({
|
|
6135
|
+
imports: serialized.imports,
|
|
6136
|
+
exports: serialized.exports,
|
|
6137
|
+
memberAccesses: serialized.memberAccesses,
|
|
6138
|
+
wholeObjectUses: serialized.wholeObjectUses,
|
|
6139
|
+
localIdentifierReferences: serialized.localIdentifierReferences,
|
|
6140
|
+
referencedFilenames: serialized.referencedFilenames,
|
|
6141
|
+
redundantTypePatterns: serialized.redundantTypePatterns,
|
|
6142
|
+
identityWrappers: serialized.identityWrappers,
|
|
6143
|
+
typeDefinitionHashes: serialized.typeDefinitionHashes,
|
|
6144
|
+
inlineTypeLiterals: serialized.inlineTypeLiterals,
|
|
6145
|
+
simplifiableFunctions: serialized.simplifiableFunctions,
|
|
6146
|
+
simplifiableExpressions: serialized.simplifiableExpressions,
|
|
6147
|
+
duplicateConstantCandidates: serialized.duplicateConstantCandidates,
|
|
6148
|
+
errors: deserializeErrors(serialized.errors)
|
|
6149
|
+
});
|
|
6150
|
+
const resolveWorkerPath = () => {
|
|
6151
|
+
const currentUrl = import.meta.url;
|
|
6152
|
+
if (currentUrl.endsWith(".ts")) return fileURLToPath(new URL("./parse-worker.ts", currentUrl));
|
|
6153
|
+
return fileURLToPath(new URL("./parse-worker.mjs", currentUrl));
|
|
6154
|
+
};
|
|
6155
|
+
const createWorker = (workerPath) => {
|
|
6156
|
+
return new Worker(workerPath, { ...workerPath.endsWith(".ts") ? { execArgv: ["--import", "tsx"] } : {} });
|
|
6157
|
+
};
|
|
6158
|
+
const waitForReady = (worker) => new Promise((resolve, reject) => {
|
|
6159
|
+
const onMessage = (message) => {
|
|
6160
|
+
if (message.type === "ready") {
|
|
6161
|
+
worker.off("message", onMessage);
|
|
6162
|
+
worker.off("error", onError);
|
|
6163
|
+
resolve();
|
|
6164
|
+
}
|
|
6165
|
+
};
|
|
6166
|
+
const onError = (error) => {
|
|
6167
|
+
worker.off("message", onMessage);
|
|
6168
|
+
worker.off("error", onError);
|
|
6169
|
+
reject(error);
|
|
6170
|
+
};
|
|
6171
|
+
worker.on("message", onMessage);
|
|
6172
|
+
worker.on("error", onError);
|
|
6173
|
+
});
|
|
6174
|
+
const parseFilesWithWorkerPool = async (files, workerCount) => {
|
|
6175
|
+
const workerPath = resolveWorkerPath();
|
|
6176
|
+
const results = new Array(files.length);
|
|
6177
|
+
const workers = [];
|
|
6178
|
+
try {
|
|
6179
|
+
for (let workerIndex = 0; workerIndex < workerCount; workerIndex++) workers.push(createWorker(workerPath));
|
|
6180
|
+
await Promise.all(workers.map(waitForReady));
|
|
6181
|
+
} catch {
|
|
6182
|
+
for (const worker of workers) worker.terminate();
|
|
6183
|
+
return files.map((file) => parseSourceFile(file.path));
|
|
6184
|
+
}
|
|
6185
|
+
let nextFileIndex = 0;
|
|
6186
|
+
let completedCount = 0;
|
|
6187
|
+
return new Promise((resolve, reject) => {
|
|
6188
|
+
const dispatchNext = (worker) => {
|
|
6189
|
+
if (nextFileIndex >= files.length) return;
|
|
6190
|
+
const fileIndex = nextFileIndex;
|
|
6191
|
+
nextFileIndex += 1;
|
|
6192
|
+
worker.postMessage({
|
|
6193
|
+
type: "parse",
|
|
6194
|
+
filePath: files[fileIndex].path,
|
|
6195
|
+
fileIndex
|
|
6196
|
+
});
|
|
6197
|
+
};
|
|
6198
|
+
const onWorkerMessage = (worker) => (message) => {
|
|
6199
|
+
if (message.type === "result") {
|
|
6200
|
+
results[message.fileIndex] = deserializeParsedSource(message.parsed);
|
|
6201
|
+
completedCount += 1;
|
|
6202
|
+
if (completedCount === files.length) {
|
|
6203
|
+
cleanup();
|
|
6204
|
+
resolve(results);
|
|
6205
|
+
} else dispatchNext(worker);
|
|
6206
|
+
} else if (message.type === "error") {
|
|
6207
|
+
results[message.fileIndex] = {
|
|
6208
|
+
imports: [],
|
|
6209
|
+
exports: [],
|
|
6210
|
+
memberAccesses: [],
|
|
6211
|
+
wholeObjectUses: [],
|
|
6212
|
+
localIdentifierReferences: [],
|
|
6213
|
+
referencedFilenames: [],
|
|
6214
|
+
redundantTypePatterns: [],
|
|
6215
|
+
identityWrappers: [],
|
|
6216
|
+
typeDefinitionHashes: [],
|
|
6217
|
+
inlineTypeLiterals: [],
|
|
6218
|
+
simplifiableFunctions: [],
|
|
6219
|
+
simplifiableExpressions: [],
|
|
6220
|
+
duplicateConstantCandidates: [],
|
|
6221
|
+
errors: [new ParseError({
|
|
6222
|
+
code: "parse-failed",
|
|
6223
|
+
message: `Worker parse failed: ${message.errorMessage}`,
|
|
6224
|
+
path: message.filePath
|
|
6225
|
+
})]
|
|
6226
|
+
};
|
|
6227
|
+
completedCount += 1;
|
|
6228
|
+
if (completedCount === files.length) {
|
|
6229
|
+
cleanup();
|
|
6230
|
+
resolve(results);
|
|
6231
|
+
} else dispatchNext(worker);
|
|
6232
|
+
}
|
|
6233
|
+
};
|
|
6234
|
+
const cleanup = () => {
|
|
6235
|
+
for (const worker of workers) worker.terminate();
|
|
6236
|
+
};
|
|
6237
|
+
for (const worker of workers) {
|
|
6238
|
+
worker.on("message", onWorkerMessage(worker));
|
|
6239
|
+
worker.on("error", (error) => {
|
|
6240
|
+
cleanup();
|
|
6241
|
+
reject(error);
|
|
6242
|
+
});
|
|
6243
|
+
}
|
|
6244
|
+
for (const worker of workers) dispatchNext(worker);
|
|
6245
|
+
});
|
|
6246
|
+
};
|
|
6247
|
+
const parseFilesInParallel = async (files) => {
|
|
6248
|
+
if (files.length <= 50) return files.map((file) => parseSourceFile(file.path));
|
|
6249
|
+
const concurrency = resolveAvailableConcurrency();
|
|
6250
|
+
if (concurrency <= 1) return files.map((file) => parseSourceFile(file.path));
|
|
6251
|
+
try {
|
|
6252
|
+
return await parseFilesWithWorkerPool(files, concurrency);
|
|
6253
|
+
} catch {
|
|
6254
|
+
return files.map((file) => parseSourceFile(file.path));
|
|
6255
|
+
}
|
|
6256
|
+
};
|
|
6257
|
+
|
|
6113
6258
|
//#endregion
|
|
6114
6259
|
//#region src/utils/is-platform-builtin-or-virtual.ts
|
|
6115
6260
|
const BUILTIN_SUBPATH_NODE_MODULES = new Set([
|
|
@@ -7619,8 +7764,11 @@ const collectPnpmWorkspaceOverrideMappings = (rootDir) => {
|
|
|
7619
7764
|
};
|
|
7620
7765
|
|
|
7621
7766
|
//#endregion
|
|
7622
|
-
//#region src/utils/
|
|
7767
|
+
//#region src/utils/escape-reg-exp.ts
|
|
7623
7768
|
const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7769
|
+
|
|
7770
|
+
//#endregion
|
|
7771
|
+
//#region src/utils/matches-package-import-reference.ts
|
|
7624
7772
|
const matchesPackageImportReference = (content, packageName) => {
|
|
7625
7773
|
const escapedPackageName = escapeRegExp(packageName);
|
|
7626
7774
|
const subpathPattern = `(?:/[^'"]*)?`;
|
|
@@ -7633,6 +7781,13 @@ const matchesPackageImportReference = (content, packageName) => {
|
|
|
7633
7781
|
].some((pattern) => pattern.test(content));
|
|
7634
7782
|
};
|
|
7635
7783
|
|
|
7784
|
+
//#endregion
|
|
7785
|
+
//#region src/utils/matches-package-token-reference.ts
|
|
7786
|
+
const matchesPackageTokenReference = (command, packageName) => {
|
|
7787
|
+
const escapedPackageName = escapeRegExp(packageName);
|
|
7788
|
+
return new RegExp(`(?:^|[\\s='"\`(,;:|&])${escapedPackageName}(?:/[^\\s'"\`]*)?(?=$|[\\s='"\`),;:|&])`).test(command);
|
|
7789
|
+
};
|
|
7790
|
+
|
|
7636
7791
|
//#endregion
|
|
7637
7792
|
//#region src/report/packages.ts
|
|
7638
7793
|
const discoverAllPackageJsonPaths = (rootDir) => {
|
|
@@ -7922,6 +8077,10 @@ const collectScriptReferencedPackages = (packageJsonPath, declaredNames, binToPa
|
|
|
7922
8077
|
if (typeof scriptCommand !== "string") continue;
|
|
7923
8078
|
const commandReferenced = collectCommandReferencedPackages(scriptCommand, declaredNames, binToPackage);
|
|
7924
8079
|
for (const packageName of commandReferenced) referenced.add(packageName);
|
|
8080
|
+
for (const declaredName of declaredNames) {
|
|
8081
|
+
if (referenced.has(declaredName)) continue;
|
|
8082
|
+
if (matchesPackageTokenReference(scriptCommand, declaredName)) referenced.add(declaredName);
|
|
8083
|
+
}
|
|
7925
8084
|
}
|
|
7926
8085
|
} catch {
|
|
7927
8086
|
return referenced;
|
|
@@ -12545,8 +12704,23 @@ const analyze = async (config) => {
|
|
|
12545
12704
|
ignorePatterns: [...config.ignorePatterns, ...allExclusionPatterns]
|
|
12546
12705
|
} : config;
|
|
12547
12706
|
let files;
|
|
12707
|
+
let discoveredEntries;
|
|
12548
12708
|
try {
|
|
12549
|
-
|
|
12709
|
+
const [collectedFiles, resolvedEntries] = await Promise.all([collectSourceFiles(configWithExclusions), resolveEntries(configWithExclusions).catch((entriesError) => {
|
|
12710
|
+
setupErrors.push(new WorkspaceError({
|
|
12711
|
+
code: "workspace-discovery-failed",
|
|
12712
|
+
message: "resolveEntries failed — defaulting to empty entry set",
|
|
12713
|
+
path: config.rootDir,
|
|
12714
|
+
detail: describeUnknownError(entriesError)
|
|
12715
|
+
}));
|
|
12716
|
+
return {
|
|
12717
|
+
productionEntries: [],
|
|
12718
|
+
testEntries: [],
|
|
12719
|
+
alwaysUsedFiles: []
|
|
12720
|
+
};
|
|
12721
|
+
})]);
|
|
12722
|
+
files = collectedFiles;
|
|
12723
|
+
discoveredEntries = resolvedEntries;
|
|
12550
12724
|
} catch (collectError) {
|
|
12551
12725
|
setupErrors.push(new WorkspaceError({
|
|
12552
12726
|
code: "workspace-discovery-failed",
|
|
@@ -12557,22 +12731,6 @@ const analyze = async (config) => {
|
|
|
12557
12731
|
}));
|
|
12558
12732
|
return buildEmptyScanResult(setupErrors, performance.now() - pipelineStartTime);
|
|
12559
12733
|
}
|
|
12560
|
-
let discoveredEntries;
|
|
12561
|
-
try {
|
|
12562
|
-
discoveredEntries = await resolveEntries(configWithExclusions);
|
|
12563
|
-
} catch (entriesError) {
|
|
12564
|
-
setupErrors.push(new WorkspaceError({
|
|
12565
|
-
code: "workspace-discovery-failed",
|
|
12566
|
-
message: "resolveEntries failed — defaulting to empty entry set",
|
|
12567
|
-
path: config.rootDir,
|
|
12568
|
-
detail: describeUnknownError(entriesError)
|
|
12569
|
-
}));
|
|
12570
|
-
discoveredEntries = {
|
|
12571
|
-
productionEntries: [],
|
|
12572
|
-
testEntries: [],
|
|
12573
|
-
alwaysUsedFiles: []
|
|
12574
|
-
};
|
|
12575
|
-
}
|
|
12576
12734
|
const productionEntrySet = new Set(discoveredEntries.productionEntries);
|
|
12577
12735
|
const testEntrySet = new Set(discoveredEntries.testEntries);
|
|
12578
12736
|
const alwaysUsedFileSet = new Set(discoveredEntries.alwaysUsedFiles);
|
|
@@ -12599,9 +12757,11 @@ const analyze = async (config) => {
|
|
|
12599
12757
|
}));
|
|
12600
12758
|
return buildEmptyScanResult(setupErrors, performance.now() - pipelineStartTime);
|
|
12601
12759
|
}
|
|
12760
|
+
const parsedModules = await parseFilesInParallel(files);
|
|
12602
12761
|
const graphInputs = [];
|
|
12603
|
-
for (
|
|
12604
|
-
const
|
|
12762
|
+
for (let fileIndex = 0; fileIndex < files.length; fileIndex++) {
|
|
12763
|
+
const file = files[fileIndex];
|
|
12764
|
+
const parsedModule = parsedModules[fileIndex];
|
|
12605
12765
|
const resolvedImportMap = /* @__PURE__ */ new Map();
|
|
12606
12766
|
const safeResolveImport = (specifier) => {
|
|
12607
12767
|
try {
|