react-doctor 0.8.0 → 0.8.1-dev.1839566
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/cli.js +602 -75
- package/dist/index.d.ts +92 -94
- package/dist/index.js +107 -6
- package/dist/lsp.js +108 -7
- package/dist/skills/react-doctor/references/explain.md +1 -0
- package/package.json +6 -6
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c24708ed-97a3-59cc-81f7-4cf277ab29f2")}catch(e){}}();
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import * as NodeChildProcess from "node:child_process";
|
|
5
5
|
import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
|
|
@@ -36242,7 +36242,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
36242
36242
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
36243
36243
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
36244
36244
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
36245
|
-
const CORE_PACKAGE_VERSION = "0.8.
|
|
36245
|
+
const CORE_PACKAGE_VERSION = "0.8.1";
|
|
36246
36246
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
36247
36247
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
36248
36248
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -38359,6 +38359,9 @@ const SCRIPT_EXTENSION_FRAGMENT = "[cm]?[jt]sx?";
|
|
|
38359
38359
|
const STORY_FILE_SUFFIX_PATTERN = new RegExp(`\\.(?:stories|story)\\.(?:${SCRIPT_EXTENSION_FRAGMENT})$`);
|
|
38360
38360
|
const TEST_FILE_SUFFIX_PATTERN = new RegExp(`\\.(?:test|spec|fixture|fixtures)\\.(?:${SCRIPT_EXTENSION_FRAGMENT})$`);
|
|
38361
38361
|
const TEST_FILE_DIRECTORY_PATTERN = /(?:^|\/)(?:__tests__|__test__|tests|test|__mocks__|cypress|e2e|playwright)\//;
|
|
38362
|
+
const AMBIGUOUS_TEST_ROUTE_DIRECTORY_PATTERN = /(?:^|\/)(?:tests|test)\//;
|
|
38363
|
+
const NEXT_APP_ROUTE_FILE_SUFFIX_PATTERN = /\/(?:default|error|forbidden|global-error|layout|loading|not-found|page|route|template|unauthorized)\.[cm]?[jt]sx?$/;
|
|
38364
|
+
const SCRIPT_FILE_SUFFIX_PATTERN = /\.[cm]?[jt]sx?$/;
|
|
38362
38365
|
const FIXTURE_PROJECT_PATTERN = /\/(?:fixtures|__fixtures__)\//;
|
|
38363
38366
|
const SOURCE_ROOT_PATTERN = /\/(?:src|app|lib|components|pages|features|modules|packages|apps|frontend|client)\//g;
|
|
38364
38367
|
const stripAboveSourceRoot = (relativePath) => {
|
|
@@ -38369,6 +38372,14 @@ const stripAboveSourceRoot = (relativePath) => {
|
|
|
38369
38372
|
if (lastIdx >= 0) return relativePath.slice(lastIdx);
|
|
38370
38373
|
return relativePath.slice(fixtureMatch.index + fixtureMatch[0].length - 1);
|
|
38371
38374
|
};
|
|
38375
|
+
const isFrameworkRouteBeforeAmbiguousTestDirectory = (relativePath) => {
|
|
38376
|
+
const testDirectoryMatch = AMBIGUOUS_TEST_ROUTE_DIRECTORY_PATTERN.exec(relativePath);
|
|
38377
|
+
if (testDirectoryMatch === null) return false;
|
|
38378
|
+
let nearestRouteRoot;
|
|
38379
|
+
for (const pathSegment of relativePath.slice(0, testDirectoryMatch.index).split("/")) if (pathSegment === "app" || pathSegment === "pages") nearestRouteRoot = pathSegment;
|
|
38380
|
+
if (nearestRouteRoot === void 0) return false;
|
|
38381
|
+
return nearestRouteRoot === "pages" ? SCRIPT_FILE_SUFFIX_PATTERN.test(relativePath) : NEXT_APP_ROUTE_FILE_SUFFIX_PATTERN.test(relativePath);
|
|
38382
|
+
};
|
|
38372
38383
|
/**
|
|
38373
38384
|
* Classifies where a file sits relative to shipped code. A finding in a
|
|
38374
38385
|
* `.stories.tsx` or `.spec.ts` file never runs in front of users, so
|
|
@@ -38385,6 +38396,7 @@ const classifyFileContext = (relativePath) => {
|
|
|
38385
38396
|
if (STORY_FILE_SUFFIX_PATTERN.test(forwardSlashed)) return "story";
|
|
38386
38397
|
if (TEST_FILE_SUFFIX_PATTERN.test(forwardSlashed)) return "test";
|
|
38387
38398
|
const scoped = stripAboveSourceRoot(forwardSlashed);
|
|
38399
|
+
if (isFrameworkRouteBeforeAmbiguousTestDirectory(scoped)) return "production";
|
|
38388
38400
|
return TEST_FILE_DIRECTORY_PATTERN.test(scoped) ? "test" : "production";
|
|
38389
38401
|
};
|
|
38390
38402
|
/**
|
|
@@ -39244,6 +39256,7 @@ const VALID_RULE_SEVERITIES = [
|
|
|
39244
39256
|
"warn",
|
|
39245
39257
|
"off"
|
|
39246
39258
|
];
|
|
39259
|
+
const VALID_INCLUDED_FILE_CONTEXTS = ["test", "story"];
|
|
39247
39260
|
const KNOWN_CATEGORY_LABEL = DIAGNOSTIC_CATEGORY_BUCKETS.join(", ");
|
|
39248
39261
|
const isDiagnosticCategoryBucket = (value) => DIAGNOSTIC_CATEGORY_BUCKETS.includes(value);
|
|
39249
39262
|
const filterKnownCategories = (fieldName, categories) => categories.filter((category) => {
|
|
@@ -39278,6 +39291,7 @@ const SURFACE_CONTROL_FIELD_NAMES = [
|
|
|
39278
39291
|
"includeRules",
|
|
39279
39292
|
"excludeRules"
|
|
39280
39293
|
];
|
|
39294
|
+
const isIncludedFileContext = (value) => VALID_INCLUDED_FILE_CONTEXTS.some((fileContext) => fileContext === value);
|
|
39281
39295
|
const SEVERITY_FIELD_NAMES = ["rules", "categories"];
|
|
39282
39296
|
const isPlainObject$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
39283
39297
|
const formatType = (value) => typeof value === "string" ? `"${value}"` : typeof value;
|
|
@@ -39312,6 +39326,15 @@ const validateSurfaceControls = (surface, rawControls) => {
|
|
|
39312
39326
|
return;
|
|
39313
39327
|
}
|
|
39314
39328
|
const validatedSurfaceControls = {};
|
|
39329
|
+
if (rawControls.includeFileContexts !== void 0) {
|
|
39330
|
+
const qualifiedName = `surfaces.${surface}.includeFileContexts`;
|
|
39331
|
+
const result = validateStringArrayField(qualifiedName, rawControls.includeFileContexts);
|
|
39332
|
+
if (result !== void 0) validatedSurfaceControls.includeFileContexts = result.filter((fileContext) => {
|
|
39333
|
+
if (isIncludedFileContext(fileContext)) return true;
|
|
39334
|
+
warnConfigIssue(`config field "${qualifiedName}" lists "${fileContext}", which is not a non-production file context (expected one of: ${VALID_INCLUDED_FILE_CONTEXTS.join(", ")}); ignoring the entry.`);
|
|
39335
|
+
return false;
|
|
39336
|
+
});
|
|
39337
|
+
}
|
|
39315
39338
|
for (const fieldName of SURFACE_CONTROL_FIELD_NAMES) {
|
|
39316
39339
|
if (rawControls[fieldName] === void 0) continue;
|
|
39317
39340
|
const qualifiedName = `surfaces.${surface}.${fieldName}`;
|
|
@@ -42047,6 +42070,7 @@ const buildResolvedControls = (surface, userControls) => {
|
|
|
42047
42070
|
for (const tag of includeTags) excludeTags.delete(tag);
|
|
42048
42071
|
for (const tag of toStringSet(userControls?.excludeTags)) excludeTags.add(tag);
|
|
42049
42072
|
return {
|
|
42073
|
+
includeFileContexts: toStringSet(userControls?.includeFileContexts),
|
|
42050
42074
|
includeTags,
|
|
42051
42075
|
excludeTags,
|
|
42052
42076
|
includeCategories: toStringSet(userControls?.includeCategories),
|
|
@@ -42062,7 +42086,7 @@ const isDiagnosticOnSurface = (diagnostic, surface, config) => {
|
|
|
42062
42086
|
if (resolved.includeRuleKeys.has(ruleKey)) return true;
|
|
42063
42087
|
if (resolved.includeCategories.has(category)) return true;
|
|
42064
42088
|
if (intersects(tags, resolved.includeTags)) return true;
|
|
42065
|
-
if (diagnostic.fileContext !== void 0 && (surface === "score" || surface === "ciFailure")) return false;
|
|
42089
|
+
if (diagnostic.fileContext !== void 0 && (surface === "score" || surface === "ciFailure") && !resolved.includeFileContexts.has(diagnostic.fileContext)) return false;
|
|
42066
42090
|
if (resolved.excludeRuleKeys.has(ruleKey)) return false;
|
|
42067
42091
|
if (resolved.excludeCategories.has(category)) return false;
|
|
42068
42092
|
if (intersects(tags, resolved.excludeTags)) return false;
|
|
@@ -42310,6 +42334,35 @@ const parseGithubViewerPermission = (stdout) => {
|
|
|
42310
42334
|
return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
|
|
42311
42335
|
};
|
|
42312
42336
|
const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
|
|
42337
|
+
const parseBaselineDiffPlan = (value) => {
|
|
42338
|
+
const entries = splitNullSeparated(value);
|
|
42339
|
+
const baseFiles = /* @__PURE__ */ new Set();
|
|
42340
|
+
const headFiles = /* @__PURE__ */ new Set();
|
|
42341
|
+
for (let entryIndex = 0; entryIndex < entries.length; entryIndex += 2) {
|
|
42342
|
+
const status = entries[entryIndex];
|
|
42343
|
+
const filePath = entries[entryIndex + 1];
|
|
42344
|
+
if (status === void 0 || filePath === void 0 || status.length !== 1) return null;
|
|
42345
|
+
if (status === "A") {
|
|
42346
|
+
headFiles.add(filePath);
|
|
42347
|
+
continue;
|
|
42348
|
+
}
|
|
42349
|
+
if (status === "D") {
|
|
42350
|
+
baseFiles.add(filePath);
|
|
42351
|
+
continue;
|
|
42352
|
+
}
|
|
42353
|
+
if (status === "M" || status === "T") {
|
|
42354
|
+
baseFiles.add(filePath);
|
|
42355
|
+
headFiles.add(filePath);
|
|
42356
|
+
continue;
|
|
42357
|
+
}
|
|
42358
|
+
return null;
|
|
42359
|
+
}
|
|
42360
|
+
return {
|
|
42361
|
+
baseFiles: [...baseFiles],
|
|
42362
|
+
headFiles: [...headFiles],
|
|
42363
|
+
untrackedFiles: []
|
|
42364
|
+
};
|
|
42365
|
+
};
|
|
42313
42366
|
const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
|
|
42314
42367
|
/**
|
|
42315
42368
|
* `Git` wraps every `git`-via-subprocess call react-doctor makes
|
|
@@ -42512,6 +42565,45 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
42512
42565
|
githubViewerPermission,
|
|
42513
42566
|
branchExists,
|
|
42514
42567
|
mergeBase,
|
|
42568
|
+
baselineDiffPlan: (input) => {
|
|
42569
|
+
if (!isSafeGitRevision(input.ref)) return succeed$2(null);
|
|
42570
|
+
return gen(function* () {
|
|
42571
|
+
const unmerged = yield* runGit(input.directory, [
|
|
42572
|
+
"diff",
|
|
42573
|
+
"--no-ext-diff",
|
|
42574
|
+
"-z",
|
|
42575
|
+
"--name-only",
|
|
42576
|
+
"--diff-filter=U",
|
|
42577
|
+
"--relative"
|
|
42578
|
+
]);
|
|
42579
|
+
if (unmerged.status !== 0 || unmerged.stdout.length > 0) return null;
|
|
42580
|
+
const result = yield* runGit(input.directory, [
|
|
42581
|
+
"diff",
|
|
42582
|
+
"--no-ext-diff",
|
|
42583
|
+
"--no-textconv",
|
|
42584
|
+
"--no-renames",
|
|
42585
|
+
"-z",
|
|
42586
|
+
"--name-status",
|
|
42587
|
+
"--relative",
|
|
42588
|
+
input.ref
|
|
42589
|
+
]);
|
|
42590
|
+
if (result.status !== 0) return null;
|
|
42591
|
+
const plan = parseBaselineDiffPlan(result.stdout);
|
|
42592
|
+
if (plan === null) return null;
|
|
42593
|
+
const untracked = yield* runGit(input.directory, [
|
|
42594
|
+
"ls-files",
|
|
42595
|
+
"--others",
|
|
42596
|
+
"--exclude-standard",
|
|
42597
|
+
"-z"
|
|
42598
|
+
]);
|
|
42599
|
+
if (untracked.status !== 0) return null;
|
|
42600
|
+
return {
|
|
42601
|
+
baseFiles: plan.baseFiles,
|
|
42602
|
+
headFiles: plan.headFiles,
|
|
42603
|
+
untrackedFiles: splitNullSeparated(untracked.stdout)
|
|
42604
|
+
};
|
|
42605
|
+
}).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.baselineDiffPlan"));
|
|
42606
|
+
},
|
|
42515
42607
|
diffSelection: ({ directory, explicitBaseBranch, includeUntracked = false }) => gen(function* () {
|
|
42516
42608
|
if (explicitBaseBranch !== void 0 && explicitBaseBranch.trim().length === 0) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "Diff base branch cannot be empty." }) }));
|
|
42517
42609
|
if (explicitBaseBranch !== void 0) {
|
|
@@ -42661,6 +42753,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
42661
42753
|
githubViewerPermission: () => succeed$2(snapshot.githubViewerPermission ?? null),
|
|
42662
42754
|
branchExists: (_directory, branch) => succeed$2(snapshot.branchExists?.get(branch) ?? false),
|
|
42663
42755
|
mergeBase: ({ ref }) => succeed$2(snapshot.mergeBase?.get(ref) ?? null),
|
|
42756
|
+
baselineDiffPlan: () => succeed$2(snapshot.baselineDiffPlan ?? null),
|
|
42664
42757
|
diffSelection: () => succeed$2(snapshot.diffSelection ?? null),
|
|
42665
42758
|
stagedFilePaths: () => succeed$2(snapshot.stagedFiles ?? []),
|
|
42666
42759
|
showStagedContent: (_directory, relativePath) => succeed$2(snapshot.stagedContent?.get(relativePath) ?? null),
|
|
@@ -46397,12 +46490,19 @@ const isPathInsideDirectory = (childAbsolutePath, parentAbsolutePath) => {
|
|
|
46397
46490
|
*/
|
|
46398
46491
|
const materializeSourceTree = (input) => gen(function* () {
|
|
46399
46492
|
const materializedFiles = [];
|
|
46493
|
+
const unmaterializedFiles = [];
|
|
46400
46494
|
const resolvedTempDirectory = path.resolve(input.tempDirectory);
|
|
46401
46495
|
for (const relativePath of input.files) {
|
|
46402
46496
|
const content = yield* input.readContent(relativePath).pipe(orElseSucceed(() => null));
|
|
46403
|
-
if (content === null)
|
|
46497
|
+
if (content === null) {
|
|
46498
|
+
unmaterializedFiles.push(relativePath);
|
|
46499
|
+
continue;
|
|
46500
|
+
}
|
|
46404
46501
|
const candidateTargetPath = path.resolve(resolvedTempDirectory, relativePath);
|
|
46405
|
-
if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory))
|
|
46502
|
+
if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory)) {
|
|
46503
|
+
unmaterializedFiles.push(relativePath);
|
|
46504
|
+
continue;
|
|
46505
|
+
}
|
|
46406
46506
|
yield* sync(() => {
|
|
46407
46507
|
fs.mkdirSync(path.dirname(candidateTargetPath), { recursive: true });
|
|
46408
46508
|
fs.writeFileSync(candidateTargetPath, content);
|
|
@@ -46419,6 +46519,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
46419
46519
|
return {
|
|
46420
46520
|
tempDirectory: input.tempDirectory,
|
|
46421
46521
|
materializedFiles,
|
|
46522
|
+
unmaterializedFiles,
|
|
46422
46523
|
cleanup: () => {
|
|
46423
46524
|
try {
|
|
46424
46525
|
fs.rmSync(input.tempDirectory, {
|
|
@@ -46688,54 +46789,80 @@ const buildSkippedChecks = (input) => {
|
|
|
46688
46789
|
skippedCheckReasons
|
|
46689
46790
|
};
|
|
46690
46791
|
};
|
|
46691
|
-
const
|
|
46792
|
+
const fingerprintText = (text) => createHash("sha256").update(text).digest("hex");
|
|
46793
|
+
const normalizeEvidence = (evidence) => evidence.replace(/\s+/g, " ").trim();
|
|
46794
|
+
const getDiagnosticMatchKeys = (diagnostic, evidence) => {
|
|
46692
46795
|
const ruleKey = `${diagnostic.plugin}/${diagnostic.rule}`;
|
|
46693
|
-
const
|
|
46694
|
-
|
|
46695
|
-
};
|
|
46696
|
-
|
|
46697
|
-
|
|
46698
|
-
|
|
46699
|
-
|
|
46700
|
-
|
|
46701
|
-
|
|
46702
|
-
|
|
46703
|
-
|
|
46704
|
-
|
|
46705
|
-
|
|
46706
|
-
|
|
46707
|
-
|
|
46708
|
-
|
|
46709
|
-
|
|
46710
|
-
|
|
46711
|
-
|
|
46712
|
-
|
|
46713
|
-
|
|
46714
|
-
|
|
46715
|
-
|
|
46716
|
-
|
|
46717
|
-
|
|
46718
|
-
|
|
46719
|
-
*
|
|
46796
|
+
const messageFingerprint = fingerprintText(`${diagnostic.title ?? ""}\0${diagnostic.message}`);
|
|
46797
|
+
const normalizedEvidence = evidence === null ? "" : normalizeEvidence(evidence);
|
|
46798
|
+
const stableEvidenceKey = normalizedEvidence.length > 0 ? `evidence\0${ruleKey}\0${messageFingerprint}\0${fingerprintText(normalizedEvidence)}` : null;
|
|
46799
|
+
return {
|
|
46800
|
+
stableEvidenceKey,
|
|
46801
|
+
sameFileStableEvidenceKey: stableEvidenceKey === null ? null : `${diagnostic.filePath}\0${stableEvidenceKey}`,
|
|
46802
|
+
sameFileFallbackKey: diagnostic.matchByOccurrence || normalizedEvidence.length === 0 ? `fallback\0${diagnostic.filePath}\0${ruleKey}\0${messageFingerprint}` : null
|
|
46803
|
+
};
|
|
46804
|
+
};
|
|
46805
|
+
const addDiagnosticIndex = (buckets, key, diagnosticIndex) => {
|
|
46806
|
+
if (key === null) return;
|
|
46807
|
+
const diagnosticIndexes = buckets.get(key) ?? [];
|
|
46808
|
+
diagnosticIndexes.push(diagnosticIndex);
|
|
46809
|
+
buckets.set(key, diagnosticIndexes);
|
|
46810
|
+
};
|
|
46811
|
+
const takeMatchingDiagnosticIndex = (buckets, key, matchedDiagnosticIndexes) => {
|
|
46812
|
+
if (key === null) return null;
|
|
46813
|
+
for (const diagnosticIndex of buckets.get(key) ?? []) if (!matchedDiagnosticIndexes.has(diagnosticIndex)) return diagnosticIndex;
|
|
46814
|
+
return null;
|
|
46815
|
+
};
|
|
46816
|
+
const readDiagnosticEvidence = (diagnostic, readEvidence, readLine) => readEvidence?.(diagnostic) ?? readLine(diagnostic.filePath, diagnostic.line);
|
|
46817
|
+
const buildMatchCandidates = (diagnostics, readEvidence, readLine) => diagnostics.map((diagnostic, diagnosticIndex) => ({
|
|
46818
|
+
diagnosticIndex,
|
|
46819
|
+
...getDiagnosticMatchKeys(diagnostic, readDiagnosticEvidence(diagnostic, readEvidence, readLine))
|
|
46820
|
+
}));
|
|
46821
|
+
/**
|
|
46822
|
+
* Diffs a head scan against a base scan using a multiset of construct-level
|
|
46823
|
+
* evidence. Stable identities combine plugin/rule, the diagnostic message,
|
|
46824
|
+
* and normalized diagnosed source, so unchanged findings can move across
|
|
46825
|
+
* files while changed constructs or messages remain new. Cardinality is
|
|
46826
|
+
* retained for identical findings. Diagnostics explicitly marked
|
|
46827
|
+
* `matchByOccurrence` may fall back to same-file plugin/rule/message matching
|
|
46828
|
+
* after same-file strict evidence matching. Cross-file evidence matching runs
|
|
46829
|
+
* last so a copy cannot consume a reformatted local occurrence. Unreadable
|
|
46830
|
+
* evidence uses the same conservative fallback rather than matching across
|
|
46831
|
+
* files without proof.
|
|
46720
46832
|
*/
|
|
46721
46833
|
const computeDiagnosticDelta = (input) => {
|
|
46722
|
-
const
|
|
46723
|
-
|
|
46724
|
-
|
|
46725
|
-
|
|
46726
|
-
|
|
46727
|
-
const
|
|
46728
|
-
|
|
46729
|
-
|
|
46730
|
-
|
|
46731
|
-
|
|
46732
|
-
|
|
46733
|
-
|
|
46734
|
-
|
|
46735
|
-
|
|
46834
|
+
const baseCandidates = buildMatchCandidates(input.baseDiagnostics, input.readBaseEvidence, input.readBaseLine);
|
|
46835
|
+
const headCandidates = buildMatchCandidates(input.headDiagnostics, input.readHeadEvidence, input.readHeadLine);
|
|
46836
|
+
const baseByStableEvidence = /* @__PURE__ */ new Map();
|
|
46837
|
+
const baseBySameFileStableEvidence = /* @__PURE__ */ new Map();
|
|
46838
|
+
const baseBySameFileFallback = /* @__PURE__ */ new Map();
|
|
46839
|
+
for (const candidate of baseCandidates) {
|
|
46840
|
+
addDiagnosticIndex(baseByStableEvidence, candidate.stableEvidenceKey, candidate.diagnosticIndex);
|
|
46841
|
+
addDiagnosticIndex(baseBySameFileStableEvidence, candidate.sameFileStableEvidenceKey, candidate.diagnosticIndex);
|
|
46842
|
+
addDiagnosticIndex(baseBySameFileFallback, candidate.sameFileFallbackKey, candidate.diagnosticIndex);
|
|
46843
|
+
}
|
|
46844
|
+
const matchedHeadDiagnosticIndexes = /* @__PURE__ */ new Set();
|
|
46845
|
+
const matchedBaseDiagnosticIndexes = /* @__PURE__ */ new Set();
|
|
46846
|
+
const matchCandidates = (baseBuckets, getKey, onMatch) => {
|
|
46847
|
+
for (const candidate of headCandidates) {
|
|
46848
|
+
if (matchedHeadDiagnosticIndexes.has(candidate.diagnosticIndex)) continue;
|
|
46849
|
+
const baseDiagnosticIndex = takeMatchingDiagnosticIndex(baseBuckets, getKey(candidate), matchedBaseDiagnosticIndexes);
|
|
46850
|
+
if (baseDiagnosticIndex === null) continue;
|
|
46851
|
+
matchedHeadDiagnosticIndexes.add(candidate.diagnosticIndex);
|
|
46852
|
+
matchedBaseDiagnosticIndexes.add(baseDiagnosticIndex);
|
|
46853
|
+
onMatch?.(candidate.diagnosticIndex, baseDiagnosticIndex);
|
|
46854
|
+
}
|
|
46855
|
+
};
|
|
46856
|
+
matchCandidates(baseBySameFileStableEvidence, (candidate) => candidate.sameFileStableEvidenceKey);
|
|
46857
|
+
matchCandidates(baseBySameFileFallback, (candidate) => candidate.sameFileFallbackKey);
|
|
46858
|
+
let crossFileMatchCount = 0;
|
|
46859
|
+
matchCandidates(baseByStableEvidence, (candidate) => candidate.stableEvidenceKey, (head, base) => {
|
|
46860
|
+
if (input.headDiagnostics[head]?.filePath !== input.baseDiagnostics[base]?.filePath) crossFileMatchCount += 1;
|
|
46861
|
+
});
|
|
46736
46862
|
return {
|
|
46737
|
-
newDiagnostics,
|
|
46738
|
-
fixedCount
|
|
46863
|
+
newDiagnostics: input.headDiagnostics.filter((_diagnostic, diagnosticIndex) => !matchedHeadDiagnosticIndexes.has(diagnosticIndex)),
|
|
46864
|
+
fixedCount: input.baseDiagnostics.length - matchedBaseDiagnosticIndexes.size,
|
|
46865
|
+
crossFileMatchCount
|
|
46739
46866
|
};
|
|
46740
46867
|
};
|
|
46741
46868
|
/**
|
|
@@ -46767,6 +46894,12 @@ const getDiffInfo = (directory, explicitBaseBranch, includeUntracked) => runProm
|
|
|
46767
46894
|
};
|
|
46768
46895
|
}).pipe(provide(Git.layerNode)));
|
|
46769
46896
|
const filterSourceFiles = (filePaths) => filePaths.filter(isLintableSourceFile);
|
|
46897
|
+
const getBaselineDiffPlan = (directory, ref) => runPromise(gen(function* () {
|
|
46898
|
+
return yield* (yield* Git).baselineDiffPlan({
|
|
46899
|
+
directory,
|
|
46900
|
+
ref
|
|
46901
|
+
});
|
|
46902
|
+
}).pipe(provide(Git.layerNode)));
|
|
46770
46903
|
/**
|
|
46771
46904
|
* Programmatic façade over `Git.changedLineRanges` (the `lines` scope). Diffs
|
|
46772
46905
|
* `files` with `--unified=0` against `baseRef` (or the index when `cached`),
|
|
@@ -47223,7 +47356,7 @@ const makeNoopConsole = () => ({
|
|
|
47223
47356
|
});
|
|
47224
47357
|
//#endregion
|
|
47225
47358
|
//#region src/cli/utils/version.ts
|
|
47226
|
-
const VERSION = "0.8.
|
|
47359
|
+
const VERSION = "0.8.1-dev.1839566";
|
|
47227
47360
|
//#endregion
|
|
47228
47361
|
//#region src/cli/utils/json-mode.ts
|
|
47229
47362
|
let context = null;
|
|
@@ -47575,13 +47708,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
47575
47708
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
47576
47709
|
* standard `SENTRY_RELEASE` override.
|
|
47577
47710
|
*/
|
|
47578
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.
|
|
47711
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.1839566`;
|
|
47579
47712
|
/**
|
|
47580
47713
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
47581
47714
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
47582
47715
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
47583
47716
|
*/
|
|
47584
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.
|
|
47717
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.1839566") ? "development" : "production");
|
|
47585
47718
|
/**
|
|
47586
47719
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
47587
47720
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -60204,6 +60337,7 @@ const buildOutcomeAttributes = (input) => {
|
|
|
60204
60337
|
new: summary.totalDiagnosticCount,
|
|
60205
60338
|
fixed: result.baselineDelta.fixedCount,
|
|
60206
60339
|
baseTotal: result.baselineDelta.baseTotalCount,
|
|
60340
|
+
crossFileMatches: result.baselineDelta.crossFileMatchCount ?? null,
|
|
60207
60341
|
degraded: false
|
|
60208
60342
|
}));
|
|
60209
60343
|
else if (input.gateExempt) attributes["baseline.degraded"] = true;
|
|
@@ -60317,28 +60451,49 @@ const diagnosticIntersectsLineRanges = (diagnostic, lineRanges) => {
|
|
|
60317
60451
|
return lineRanges.some(([rangeStartLine, rangeEndLine]) => diagnostic.line <= rangeEndLine && diagnosticEndLine >= rangeStartLine);
|
|
60318
60452
|
};
|
|
60319
60453
|
//#endregion
|
|
60454
|
+
//#region src/cli/utils/is-materializable-git-source.ts
|
|
60455
|
+
const GIT_LFS_POINTER_HEADER = "version https://git-lfs.github.com/spec/v1";
|
|
60456
|
+
const isMaterializableGitSource = (content) => !content.includes("\0") && !content.startsWith(GIT_LFS_POINTER_HEADER);
|
|
60457
|
+
//#endregion
|
|
60320
60458
|
//#region src/cli/utils/materialize-baseline-files.ts
|
|
60321
60459
|
/**
|
|
60322
|
-
* Materializes the
|
|
60323
|
-
* `
|
|
60324
|
-
*
|
|
60325
|
-
*
|
|
60326
|
-
*
|
|
60327
|
-
*
|
|
60460
|
+
* Materializes the base side of the `ref` → worktree diff into
|
|
60461
|
+
* `tempDirectory`, mirroring the project layout plus head's config files so
|
|
60462
|
+
* both sides lint under the same rules. Git rename heuristics are disabled by
|
|
60463
|
+
* the diff planner, so an old path is retained as a base deletion while its
|
|
60464
|
+
* new path is a head addition. Missing head-only additions are expected;
|
|
60465
|
+
* missing paths that the plan says must exist at base make `isComplete` false.
|
|
60328
60466
|
*/
|
|
60329
60467
|
const materializeBaselineFiles = (input) => runPromise(gen(function* () {
|
|
60330
60468
|
const git = yield* Git;
|
|
60331
|
-
|
|
60469
|
+
const diffPlan = yield* git.baselineDiffPlan({
|
|
60332
60470
|
directory: input.directory,
|
|
60333
|
-
|
|
60471
|
+
ref: input.ref
|
|
60472
|
+
});
|
|
60473
|
+
const baseFiles = input.baseFiles ?? diffPlan?.baseFiles;
|
|
60474
|
+
const headFiles = input.headFiles ?? diffPlan?.headFiles;
|
|
60475
|
+
const untrackedFiles = diffPlan?.untrackedFiles ?? [];
|
|
60476
|
+
if (baseFiles === void 0 || headFiles === void 0) return null;
|
|
60477
|
+
const files = [...new Set([...input.files, ...baseFiles])];
|
|
60478
|
+
const tree = yield* materializeSourceTree({
|
|
60479
|
+
directory: input.directory,
|
|
60480
|
+
files,
|
|
60334
60481
|
tempDirectory: input.tempDirectory,
|
|
60335
60482
|
readContent: (relativePath) => git.showRefContent({
|
|
60336
60483
|
directory: input.directory,
|
|
60337
60484
|
ref: input.ref,
|
|
60338
60485
|
relativePath,
|
|
60339
60486
|
options: { maxBufferBytes: GIT_SHOW_MAX_BUFFER_BYTES }
|
|
60340
|
-
})
|
|
60487
|
+
}).pipe(map$3((content) => content !== null && isMaterializableGitSource(content) ? content : null))
|
|
60341
60488
|
});
|
|
60489
|
+
const materializedFiles = new Set(tree.materializedFiles);
|
|
60490
|
+
return {
|
|
60491
|
+
...tree,
|
|
60492
|
+
baseFiles,
|
|
60493
|
+
headFiles,
|
|
60494
|
+
isComplete: baseFiles.every((filePath) => materializedFiles.has(filePath)),
|
|
60495
|
+
untrackedFiles
|
|
60496
|
+
};
|
|
60342
60497
|
}).pipe(provide(Git.layerNode)));
|
|
60343
60498
|
/**
|
|
60344
60499
|
* Resolves the commit a baseline scan should read base content from — the
|
|
@@ -60361,8 +60516,8 @@ const resolveMergeBaseRef = async (directory, ref) => {
|
|
|
60361
60516
|
//#region src/cli/utils/read-source-line.ts
|
|
60362
60517
|
/**
|
|
60363
60518
|
* Builds a cached `(filePath, line) -> source text` reader rooted at
|
|
60364
|
-
* `rootDirectory`, used
|
|
60365
|
-
*
|
|
60519
|
+
* `rootDirectory`, used as the fallback when construct-level diagnostic
|
|
60520
|
+
* evidence cannot be read. Wraps core's
|
|
60366
60521
|
* `createNodeReadFileLinesSync` with per-file memoization + 1-indexed line
|
|
60367
60522
|
* lookup; unreadable files / out-of-range lines return `null`.
|
|
60368
60523
|
*/
|
|
@@ -60377,6 +60532,338 @@ const createSourceLineReader = (rootDirectory) => {
|
|
|
60377
60532
|
};
|
|
60378
60533
|
};
|
|
60379
60534
|
//#endregion
|
|
60535
|
+
//#region src/cli/utils/read-diagnostic-evidence.ts
|
|
60536
|
+
const SOURCE_EXTENSIONS = [
|
|
60537
|
+
".ts",
|
|
60538
|
+
".tsx",
|
|
60539
|
+
".js",
|
|
60540
|
+
".jsx",
|
|
60541
|
+
".mts",
|
|
60542
|
+
".cts",
|
|
60543
|
+
".mjs",
|
|
60544
|
+
".cjs"
|
|
60545
|
+
];
|
|
60546
|
+
const COMPONENT_WRAPPER_NAMES = new Set(["memo", "forwardRef"]);
|
|
60547
|
+
const getScriptKind = (filePath) => {
|
|
60548
|
+
const extension = path.extname(filePath).toLowerCase();
|
|
60549
|
+
if (extension === ".tsx") return ts.ScriptKind.TSX;
|
|
60550
|
+
if (extension === ".jsx") return ts.ScriptKind.JSX;
|
|
60551
|
+
if (extension === ".js" || extension === ".mjs" || extension === ".cjs") return ts.ScriptKind.JS;
|
|
60552
|
+
return ts.ScriptKind.TS;
|
|
60553
|
+
};
|
|
60554
|
+
const resolveSafeSourcePath = (rootDirectory, filePath) => {
|
|
60555
|
+
try {
|
|
60556
|
+
const resolvedRootDirectory = fs.realpathSync(rootDirectory);
|
|
60557
|
+
const absolutePath = path.resolve(resolvedRootDirectory, filePath);
|
|
60558
|
+
const relativePath = path.relative(resolvedRootDirectory, absolutePath);
|
|
60559
|
+
if (relativePath.length === 0 || relativePath === ".." || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath)) return null;
|
|
60560
|
+
const stats = fs.lstatSync(absolutePath);
|
|
60561
|
+
if (!stats.isFile() || stats.isSymbolicLink()) return null;
|
|
60562
|
+
const realPath = fs.realpathSync(absolutePath);
|
|
60563
|
+
const realRelativePath = path.relative(resolvedRootDirectory, realPath);
|
|
60564
|
+
return realRelativePath !== ".." && !realRelativePath.startsWith(`..${path.sep}`) && !path.isAbsolute(realRelativePath) ? realPath : null;
|
|
60565
|
+
} catch {
|
|
60566
|
+
return null;
|
|
60567
|
+
}
|
|
60568
|
+
};
|
|
60569
|
+
const readSourceRecord = (rootDirectory, filePath, state) => {
|
|
60570
|
+
const normalizedFilePath = filePath.replace(/\\/g, "/");
|
|
60571
|
+
if (state.recordByFilePath.has(normalizedFilePath)) return state.recordByFilePath.get(normalizedFilePath) ?? null;
|
|
60572
|
+
const absolutePath = resolveSafeSourcePath(rootDirectory, normalizedFilePath);
|
|
60573
|
+
if (absolutePath === null) {
|
|
60574
|
+
state.recordByFilePath.set(normalizedFilePath, null);
|
|
60575
|
+
return null;
|
|
60576
|
+
}
|
|
60577
|
+
try {
|
|
60578
|
+
const sourceText = fs.readFileSync(absolutePath, "utf-8");
|
|
60579
|
+
const record = {
|
|
60580
|
+
absolutePath,
|
|
60581
|
+
filePath: normalizedFilePath,
|
|
60582
|
+
sourceFile: ts.createSourceFile(absolutePath, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(absolutePath)),
|
|
60583
|
+
sourceText
|
|
60584
|
+
};
|
|
60585
|
+
state.recordByFilePath.set(normalizedFilePath, record);
|
|
60586
|
+
return record;
|
|
60587
|
+
} catch {
|
|
60588
|
+
state.recordByFilePath.set(normalizedFilePath, null);
|
|
60589
|
+
return null;
|
|
60590
|
+
}
|
|
60591
|
+
};
|
|
60592
|
+
const listSourceRecords = (rootDirectory, state) => {
|
|
60593
|
+
if (state.sourceRecords !== null) return state.sourceRecords;
|
|
60594
|
+
state.sourceRecords = listSourceFiles(rootDirectory).flatMap((filePath) => {
|
|
60595
|
+
const record = readSourceRecord(rootDirectory, filePath, state);
|
|
60596
|
+
return record === null ? [] : [record];
|
|
60597
|
+
});
|
|
60598
|
+
return state.sourceRecords;
|
|
60599
|
+
};
|
|
60600
|
+
const unwrapExpression = (expression) => {
|
|
60601
|
+
let currentExpression = expression;
|
|
60602
|
+
while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression)) currentExpression = currentExpression.expression;
|
|
60603
|
+
return currentExpression;
|
|
60604
|
+
};
|
|
60605
|
+
const getCalleeName = (expression) => {
|
|
60606
|
+
const unwrappedExpression = unwrapExpression(expression);
|
|
60607
|
+
if (ts.isIdentifier(unwrappedExpression)) return unwrappedExpression.text;
|
|
60608
|
+
if (ts.isPropertyAccessExpression(unwrappedExpression)) return unwrappedExpression.name.text;
|
|
60609
|
+
return null;
|
|
60610
|
+
};
|
|
60611
|
+
const isComponentWrapperCall = (node) => {
|
|
60612
|
+
const wrapperName = getCalleeName(node.expression);
|
|
60613
|
+
return wrapperName !== null && COMPONENT_WRAPPER_NAMES.has(wrapperName);
|
|
60614
|
+
};
|
|
60615
|
+
const getFunctionName = (node) => {
|
|
60616
|
+
if (ts.isFunctionDeclaration(node) && node.name !== void 0) return node.name.text;
|
|
60617
|
+
if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
|
|
60618
|
+
let componentExpression = node;
|
|
60619
|
+
while (true) {
|
|
60620
|
+
const parent = componentExpression.parent;
|
|
60621
|
+
if (ts.isParenthesizedExpression(parent) || ts.isAsExpression(parent) || ts.isTypeAssertionExpression(parent) || ts.isNonNullExpression(parent) || ts.isSatisfiesExpression(parent)) {
|
|
60622
|
+
componentExpression = parent;
|
|
60623
|
+
continue;
|
|
60624
|
+
}
|
|
60625
|
+
if (ts.isCallExpression(parent) && parent.arguments[0] === componentExpression && isComponentWrapperCall(parent)) {
|
|
60626
|
+
componentExpression = parent;
|
|
60627
|
+
continue;
|
|
60628
|
+
}
|
|
60629
|
+
if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) return parent.name.text;
|
|
60630
|
+
return node.name?.text ?? null;
|
|
60631
|
+
}
|
|
60632
|
+
}
|
|
60633
|
+
return null;
|
|
60634
|
+
};
|
|
60635
|
+
const isComponentFunction = (node) => ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node);
|
|
60636
|
+
const isDefaultExportedComponent = (record, node, componentName) => {
|
|
60637
|
+
if (ts.canHaveModifiers(node) && ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword)) return true;
|
|
60638
|
+
return record.sourceFile.statements.some((statement) => ts.isExportAssignment(statement) && ts.isIdentifier(statement.expression) && statement.expression.text === componentName);
|
|
60639
|
+
};
|
|
60640
|
+
const findEnclosingComponent = (record, diagnostic) => {
|
|
60641
|
+
if (!Number.isInteger(diagnostic.line) || diagnostic.line < 1) return null;
|
|
60642
|
+
const lineIndex = diagnostic.line - 1;
|
|
60643
|
+
const lineStarts = record.sourceFile.getLineStarts();
|
|
60644
|
+
const lineStart = lineStarts[lineIndex];
|
|
60645
|
+
if (lineStart === void 0) return null;
|
|
60646
|
+
const nextLineStart = lineStarts[lineIndex + 1] ?? record.sourceFile.end;
|
|
60647
|
+
const lineEnd = Math.max(lineStart, nextLineStart - 1);
|
|
60648
|
+
const columnIndex = Number.isInteger(diagnostic.column) ? Math.max(0, diagnostic.column - 1) : 0;
|
|
60649
|
+
const diagnosticPosition = Math.min(lineStart + columnIndex, lineEnd);
|
|
60650
|
+
let component = null;
|
|
60651
|
+
let componentWidth = Number.POSITIVE_INFINITY;
|
|
60652
|
+
const visit = (node) => {
|
|
60653
|
+
if (diagnosticPosition < node.getStart(record.sourceFile) || diagnosticPosition > node.end) return;
|
|
60654
|
+
if (isComponentFunction(node)) {
|
|
60655
|
+
const name = getFunctionName(node);
|
|
60656
|
+
const width = node.end - node.getStart(record.sourceFile);
|
|
60657
|
+
if (name !== null && /^[A-Z]/.test(name) && width < componentWidth) {
|
|
60658
|
+
component = {
|
|
60659
|
+
isDefaultExport: isDefaultExportedComponent(record, node, name),
|
|
60660
|
+
name,
|
|
60661
|
+
node,
|
|
60662
|
+
record
|
|
60663
|
+
};
|
|
60664
|
+
componentWidth = width;
|
|
60665
|
+
}
|
|
60666
|
+
}
|
|
60667
|
+
ts.forEachChild(node, visit);
|
|
60668
|
+
};
|
|
60669
|
+
visit(record.sourceFile);
|
|
60670
|
+
return component;
|
|
60671
|
+
};
|
|
60672
|
+
const moduleSpecifierTargetsComponent = (callerRecord, moduleSpecifier, componentRecord) => {
|
|
60673
|
+
if (!moduleSpecifier.startsWith(".")) return false;
|
|
60674
|
+
const unresolvedPath = path.resolve(path.dirname(callerRecord.absolutePath), moduleSpecifier);
|
|
60675
|
+
const specifiedExtension = path.extname(unresolvedPath).toLowerCase();
|
|
60676
|
+
const sourcePathWithoutExtension = SOURCE_EXTENSIONS.includes(specifiedExtension) ? unresolvedPath.slice(0, -specifiedExtension.length) : unresolvedPath;
|
|
60677
|
+
return [
|
|
60678
|
+
unresolvedPath,
|
|
60679
|
+
...SOURCE_EXTENSIONS.map((extension) => `${sourcePathWithoutExtension}${extension}`),
|
|
60680
|
+
...sourcePathWithoutExtension === unresolvedPath ? SOURCE_EXTENSIONS.map((extension) => path.join(unresolvedPath, `index${extension}`)) : []
|
|
60681
|
+
].includes(componentRecord.absolutePath);
|
|
60682
|
+
};
|
|
60683
|
+
const getComponentTagNames = (record, component) => {
|
|
60684
|
+
if (record.absolutePath === component.record.absolutePath) return new Set([component.name]);
|
|
60685
|
+
const tagNames = /* @__PURE__ */ new Set();
|
|
60686
|
+
for (const statement of record.sourceFile.statements) {
|
|
60687
|
+
if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier) || !moduleSpecifierTargetsComponent(record, statement.moduleSpecifier.text, component.record)) continue;
|
|
60688
|
+
const importClause = statement.importClause;
|
|
60689
|
+
if (component.isDefaultExport && importClause?.name !== void 0) tagNames.add(importClause.name.text);
|
|
60690
|
+
const namedBindings = importClause?.namedBindings;
|
|
60691
|
+
if (namedBindings !== void 0 && ts.isNamedImports(namedBindings)) {
|
|
60692
|
+
for (const element of namedBindings.elements) if ((element.propertyName?.text ?? element.name.text) === component.name) tagNames.add(element.name.text);
|
|
60693
|
+
}
|
|
60694
|
+
}
|
|
60695
|
+
return tagNames;
|
|
60696
|
+
};
|
|
60697
|
+
const getTransparentCall = (functionNode) => {
|
|
60698
|
+
if (functionNode.body === void 0) return null;
|
|
60699
|
+
if (!ts.isBlock(functionNode.body)) {
|
|
60700
|
+
const expression = unwrapExpression(functionNode.body);
|
|
60701
|
+
return ts.isCallExpression(expression) ? expression : null;
|
|
60702
|
+
}
|
|
60703
|
+
if (functionNode.body.statements.length !== 1) return null;
|
|
60704
|
+
const statement = functionNode.body.statements[0];
|
|
60705
|
+
if (statement === void 0) return null;
|
|
60706
|
+
const expression = ts.isExpressionStatement(statement) || ts.isReturnStatement(statement) ? statement.expression : void 0;
|
|
60707
|
+
if (expression === void 0) return null;
|
|
60708
|
+
const unwrappedExpression = unwrapExpression(expression);
|
|
60709
|
+
return ts.isCallExpression(unwrappedExpression) ? unwrappedExpression : null;
|
|
60710
|
+
};
|
|
60711
|
+
const resolveTransparentTarget = (functionNode) => {
|
|
60712
|
+
const call = getTransparentCall(functionNode);
|
|
60713
|
+
if (call === null) return null;
|
|
60714
|
+
const target = unwrapExpression(call.expression);
|
|
60715
|
+
if (!ts.isIdentifier(target) || call.arguments.length !== functionNode.parameters.length) return null;
|
|
60716
|
+
for (const [parameterIndex, parameter] of functionNode.parameters.entries()) {
|
|
60717
|
+
const argument = call.arguments[parameterIndex];
|
|
60718
|
+
const unwrappedArgument = argument === void 0 ? null : unwrapExpression(argument);
|
|
60719
|
+
if (!ts.isIdentifier(parameter.name) || unwrappedArgument === null || !ts.isIdentifier(unwrappedArgument) || unwrappedArgument.text !== parameter.name.text) return null;
|
|
60720
|
+
}
|
|
60721
|
+
return target.text;
|
|
60722
|
+
};
|
|
60723
|
+
const getForwardingFunction = (declaration) => {
|
|
60724
|
+
if (ts.isFunctionDeclaration(declaration)) return declaration;
|
|
60725
|
+
if (!ts.isVariableDeclaration(declaration) || declaration.initializer === void 0) return null;
|
|
60726
|
+
const initializer = unwrapExpression(declaration.initializer);
|
|
60727
|
+
if (ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer)) return initializer;
|
|
60728
|
+
if (ts.isCallExpression(initializer) && getCalleeName(initializer.expression) === "useCallback") {
|
|
60729
|
+
const callback = initializer.arguments[0];
|
|
60730
|
+
if (callback !== void 0 && (ts.isArrowFunction(callback) || ts.isFunctionExpression(callback))) return callback;
|
|
60731
|
+
}
|
|
60732
|
+
return null;
|
|
60733
|
+
};
|
|
60734
|
+
const getDeclaredBindingName = (node) => {
|
|
60735
|
+
if ((ts.isVariableDeclaration(node) || ts.isParameter(node) || ts.isBindingElement(node) || ts.isFunctionDeclaration(node)) && node.name !== void 0 && ts.isIdentifier(node.name)) return node.name.text;
|
|
60736
|
+
if (ts.isImportClause(node)) return node.name?.text ?? null;
|
|
60737
|
+
if (ts.isImportSpecifier(node) || ts.isNamespaceImport(node)) return node.name.text;
|
|
60738
|
+
return null;
|
|
60739
|
+
};
|
|
60740
|
+
const findBindingScope = (node) => {
|
|
60741
|
+
let currentNode = node;
|
|
60742
|
+
while (currentNode !== void 0) {
|
|
60743
|
+
if (ts.isParameter(currentNode) && ts.isFunctionLike(currentNode.parent)) return currentNode.parent;
|
|
60744
|
+
if (ts.isBlock(currentNode) || ts.isModuleBlock(currentNode) || ts.isSourceFile(currentNode)) return currentNode;
|
|
60745
|
+
currentNode = currentNode.parent;
|
|
60746
|
+
}
|
|
60747
|
+
return node.getSourceFile();
|
|
60748
|
+
};
|
|
60749
|
+
const findBindingDeclaration = (record, binding) => {
|
|
60750
|
+
const usagePosition = binding.getStart(record.sourceFile);
|
|
60751
|
+
const candidates = [];
|
|
60752
|
+
const visit = (node) => {
|
|
60753
|
+
if (getDeclaredBindingName(node) === binding.text) {
|
|
60754
|
+
const scope = findBindingScope(node);
|
|
60755
|
+
const isVisibleScope = usagePosition >= scope.getStart(record.sourceFile) && usagePosition <= scope.end;
|
|
60756
|
+
const isVisibleDeclaration = ts.isFunctionDeclaration(node) || ts.isParameter(node) || ts.isBindingElement(node) || ts.isImportClause(node) || ts.isImportSpecifier(node) || ts.isNamespaceImport(node) || node.getStart(record.sourceFile) < usagePosition;
|
|
60757
|
+
if (isVisibleScope && isVisibleDeclaration) candidates.push({
|
|
60758
|
+
declaration: node,
|
|
60759
|
+
scope
|
|
60760
|
+
});
|
|
60761
|
+
}
|
|
60762
|
+
ts.forEachChild(node, visit);
|
|
60763
|
+
};
|
|
60764
|
+
visit(record.sourceFile);
|
|
60765
|
+
let nearestCandidate = null;
|
|
60766
|
+
let nearestScopeWidth = Number.POSITIVE_INFINITY;
|
|
60767
|
+
let isNearestScopeAmbiguous = false;
|
|
60768
|
+
for (const candidate of candidates) {
|
|
60769
|
+
const scopeWidth = candidate.scope.end - candidate.scope.getStart(record.sourceFile);
|
|
60770
|
+
if (scopeWidth < nearestScopeWidth) {
|
|
60771
|
+
nearestCandidate = candidate;
|
|
60772
|
+
nearestScopeWidth = scopeWidth;
|
|
60773
|
+
isNearestScopeAmbiguous = false;
|
|
60774
|
+
} else if (scopeWidth === nearestScopeWidth) isNearestScopeAmbiguous = true;
|
|
60775
|
+
}
|
|
60776
|
+
if (isNearestScopeAmbiguous) return null;
|
|
60777
|
+
const declaration = nearestCandidate?.declaration;
|
|
60778
|
+
return declaration !== void 0 && (ts.isVariableDeclaration(declaration) || ts.isFunctionDeclaration(declaration)) ? declaration : null;
|
|
60779
|
+
};
|
|
60780
|
+
const resolveHandlerBinding = (record, binding) => {
|
|
60781
|
+
const declaration = findBindingDeclaration(record, binding);
|
|
60782
|
+
if (declaration === null) return binding.text;
|
|
60783
|
+
const forwardingFunction = getForwardingFunction(declaration);
|
|
60784
|
+
const target = forwardingFunction === null ? null : resolveTransparentTarget(forwardingFunction);
|
|
60785
|
+
return target === null || target === binding.text ? binding.text : target;
|
|
60786
|
+
};
|
|
60787
|
+
const getJsxTagName = (node) => ts.isIdentifier(node.tagName) ? node.tagName.text : null;
|
|
60788
|
+
const getHandlerBinding = (node, propName) => {
|
|
60789
|
+
for (const property of node.attributes.properties) {
|
|
60790
|
+
if (!ts.isJsxAttribute(property) || property.name.getText() !== propName) continue;
|
|
60791
|
+
const initializer = property.initializer;
|
|
60792
|
+
if (initializer === void 0 || !ts.isJsxExpression(initializer)) return null;
|
|
60793
|
+
if (initializer.expression === void 0) return null;
|
|
60794
|
+
const expression = unwrapExpression(initializer.expression);
|
|
60795
|
+
return ts.isIdentifier(expression) ? expression : null;
|
|
60796
|
+
}
|
|
60797
|
+
return null;
|
|
60798
|
+
};
|
|
60799
|
+
const getForwardedHandlerAliases = (rootDirectory, component, propNames, state) => {
|
|
60800
|
+
const cacheKey = `${component.record.filePath}\0${component.name}\0${[...propNames].sort().join("\0")}`;
|
|
60801
|
+
const cachedAliases = state.aliasesByComponent.get(cacheKey);
|
|
60802
|
+
if (cachedAliases !== void 0) return cachedAliases;
|
|
60803
|
+
const bindingsByPropName = /* @__PURE__ */ new Map();
|
|
60804
|
+
const unresolvedPropNames = /* @__PURE__ */ new Set();
|
|
60805
|
+
let callsiteCount = 0;
|
|
60806
|
+
for (const record of listSourceRecords(rootDirectory, state)) {
|
|
60807
|
+
const tagNames = getComponentTagNames(record, component);
|
|
60808
|
+
if (tagNames.size === 0) continue;
|
|
60809
|
+
const visit = (node) => {
|
|
60810
|
+
if (record === component.record && node === component.node) return;
|
|
60811
|
+
if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
|
|
60812
|
+
const tagName = getJsxTagName(node);
|
|
60813
|
+
if (tagName !== null && tagNames.has(tagName)) {
|
|
60814
|
+
callsiteCount += 1;
|
|
60815
|
+
for (const propName of propNames) {
|
|
60816
|
+
const binding = getHandlerBinding(node, propName);
|
|
60817
|
+
if (binding === null) {
|
|
60818
|
+
unresolvedPropNames.add(propName);
|
|
60819
|
+
continue;
|
|
60820
|
+
}
|
|
60821
|
+
const bindings = bindingsByPropName.get(propName) ?? /* @__PURE__ */ new Set();
|
|
60822
|
+
bindings.add(resolveHandlerBinding(record, binding));
|
|
60823
|
+
bindingsByPropName.set(propName, bindings);
|
|
60824
|
+
}
|
|
60825
|
+
}
|
|
60826
|
+
}
|
|
60827
|
+
ts.forEachChild(node, visit);
|
|
60828
|
+
};
|
|
60829
|
+
visit(record.sourceFile);
|
|
60830
|
+
}
|
|
60831
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
60832
|
+
if (callsiteCount > 0) for (const [propName, bindings] of bindingsByPropName) {
|
|
60833
|
+
if (bindings.size !== 1 || unresolvedPropNames.has(propName)) continue;
|
|
60834
|
+
const [bindingName] = bindings;
|
|
60835
|
+
if (bindingName !== void 0) aliases.set(propName, bindingName);
|
|
60836
|
+
}
|
|
60837
|
+
state.aliasesByComponent.set(cacheKey, aliases);
|
|
60838
|
+
return aliases;
|
|
60839
|
+
};
|
|
60840
|
+
const normalizeForwardedHandlers = (evidence, aliases) => {
|
|
60841
|
+
let normalizedEvidence = evidence;
|
|
60842
|
+
for (const [propName, bindingName] of aliases) normalizedEvidence = normalizedEvidence.replace(new RegExp(`\\{\\s*${propName}\\s*\\}`, "g"), `{${bindingName}}`).replace(new RegExp(`=>\\s*${propName}\\s*\\(`, "g"), `=> ${bindingName}(`);
|
|
60843
|
+
return normalizedEvidence;
|
|
60844
|
+
};
|
|
60845
|
+
const createDiagnosticEvidenceReader = (rootDirectory, options = {}) => {
|
|
60846
|
+
const state = {
|
|
60847
|
+
aliasesByComponent: /* @__PURE__ */ new Map(),
|
|
60848
|
+
recordByFilePath: /* @__PURE__ */ new Map(),
|
|
60849
|
+
sourceRecords: null
|
|
60850
|
+
};
|
|
60851
|
+
return (diagnostic) => {
|
|
60852
|
+
const record = readSourceRecord(rootDirectory, diagnostic.filePath, state);
|
|
60853
|
+
if (record === null || !Number.isInteger(diagnostic.line)) return null;
|
|
60854
|
+
const sourceLines = record.sourceText.split(/\r?\n/);
|
|
60855
|
+
const startLineIndex = Math.max(0, diagnostic.line - 1);
|
|
60856
|
+
const endLineIndex = Math.max(startLineIndex, (diagnostic.endLine ?? diagnostic.line) - 1);
|
|
60857
|
+
const evidence = sourceLines.slice(startLineIndex, endLineIndex + 1).join("\n");
|
|
60858
|
+
if (!options.resolveForwardedHandlers) return evidence;
|
|
60859
|
+
const propNames = new Set(evidence.match(/\bon[A-Z]\w*\b/g) ?? []);
|
|
60860
|
+
if (propNames.size === 0) return evidence;
|
|
60861
|
+
const component = findEnclosingComponent(record, diagnostic);
|
|
60862
|
+
if (component === null) return evidence;
|
|
60863
|
+
return normalizeForwardedHandlers(evidence, getForwardedHandlerAliases(rootDirectory, component, propNames, state));
|
|
60864
|
+
};
|
|
60865
|
+
};
|
|
60866
|
+
//#endregion
|
|
60380
60867
|
//#region src/cli/utils/build-no-score-message.ts
|
|
60381
60868
|
const ENTERPRISE_CONTACT_HINT = `Want something custom to your company? Contact us at ${ENTERPRISE_CONTACT_URL}.`;
|
|
60382
60869
|
const buildNoScoreMessage = (isScoreDisabled) => {
|
|
@@ -61620,6 +62107,8 @@ const runBaselineComparison = async (params) => {
|
|
|
61620
62107
|
directory: params.directory,
|
|
61621
62108
|
ref: params.baselineRef,
|
|
61622
62109
|
files: params.options.includePaths,
|
|
62110
|
+
baseFiles: params.baseFiles,
|
|
62111
|
+
headFiles: params.headFiles,
|
|
61623
62112
|
tempDirectory
|
|
61624
62113
|
}).catch((error) => {
|
|
61625
62114
|
rmSync(tempDirectory, {
|
|
@@ -61628,7 +62117,24 @@ const runBaselineComparison = async (params) => {
|
|
|
61628
62117
|
});
|
|
61629
62118
|
throw error;
|
|
61630
62119
|
});
|
|
62120
|
+
if (snapshot === null) {
|
|
62121
|
+
rmSync(tempDirectory, {
|
|
62122
|
+
recursive: true,
|
|
62123
|
+
force: true
|
|
62124
|
+
});
|
|
62125
|
+
return null;
|
|
62126
|
+
}
|
|
61631
62127
|
try {
|
|
62128
|
+
if (!snapshot.isComplete) return null;
|
|
62129
|
+
const analyzedHeadFiles = new Set(params.headAnalyzedFiles.map(toForwardSlashes));
|
|
62130
|
+
const baseFiles = new Set(snapshot.baseFiles.map(toForwardSlashes));
|
|
62131
|
+
const trackedHeadFiles = new Set(snapshot.headFiles.map(toForwardSlashes));
|
|
62132
|
+
const expectedHeadFiles = new Set(trackedHeadFiles);
|
|
62133
|
+
for (const filePath of params.options.includePaths) {
|
|
62134
|
+
const normalizedFilePath = toForwardSlashes(filePath);
|
|
62135
|
+
if (!baseFiles.has(normalizedFilePath)) expectedHeadFiles.add(normalizedFilePath);
|
|
62136
|
+
}
|
|
62137
|
+
if (filterSourceFiles([...expectedHeadFiles]).some((filePath) => !analyzedHeadFiles.has(filePath))) return null;
|
|
61632
62138
|
const baseLayers = buildRuntimeLayers({
|
|
61633
62139
|
directory: snapshot.tempDirectory,
|
|
61634
62140
|
hasConfigOverride: true,
|
|
@@ -61644,7 +62150,7 @@ const runBaselineComparison = async (params) => {
|
|
|
61644
62150
|
});
|
|
61645
62151
|
const baseOutput = await runPromise(restoreLegacyThrow(runInspect({
|
|
61646
62152
|
directory: snapshot.tempDirectory,
|
|
61647
|
-
includePaths:
|
|
62153
|
+
includePaths: snapshot.materializedFiles,
|
|
61648
62154
|
customRulesOnly: params.options.customRulesOnly,
|
|
61649
62155
|
respectInlineDisables: params.options.respectInlineDisables,
|
|
61650
62156
|
warnings: params.options.warnings,
|
|
@@ -61661,18 +62167,22 @@ const runBaselineComparison = async (params) => {
|
|
|
61661
62167
|
deadlineEpochMs: params.deadlineEpochMs ?? void 0
|
|
61662
62168
|
}, {}).pipe(provide(baseLayers), provideService$2(PerFileLintCacheEnabled, false), provideService$2(SidecarLintCacheEnabled, false), provideService$2(Console, silentConsole))));
|
|
61663
62169
|
if (baseOutput.didLintFail || countIncompleteLintFiles(baseOutput.lintPartialFailures) > 0) return null;
|
|
62170
|
+
const hasUnscannedUntrackedSourceFiles = filterSourceFiles(snapshot.untrackedFiles.map(toForwardSlashes)).some((filePath) => !analyzedHeadFiles.has(filePath));
|
|
61664
62171
|
const delta = computeDiagnosticDelta({
|
|
61665
62172
|
headDiagnostics: params.headDiagnostics,
|
|
61666
62173
|
baseDiagnostics: baseOutput.diagnostics,
|
|
61667
62174
|
readHeadLine: createSourceLineReader(params.directory),
|
|
61668
|
-
readBaseLine: createSourceLineReader(snapshot.tempDirectory)
|
|
62175
|
+
readBaseLine: createSourceLineReader(snapshot.tempDirectory),
|
|
62176
|
+
readHeadEvidence: createDiagnosticEvidenceReader(params.directory, { resolveForwardedHandlers: true }),
|
|
62177
|
+
readBaseEvidence: createDiagnosticEvidenceReader(snapshot.tempDirectory)
|
|
61669
62178
|
});
|
|
61670
62179
|
return {
|
|
61671
62180
|
displayDiagnostics: delta.newDiagnostics,
|
|
61672
62181
|
baselineDelta: {
|
|
61673
62182
|
baseRef: params.baselineRef,
|
|
61674
|
-
fixedCount: delta.fixedCount,
|
|
61675
|
-
baseTotalCount: baseOutput.diagnostics.length
|
|
62183
|
+
fixedCount: hasUnscannedUntrackedSourceFiles ? 0 : delta.fixedCount,
|
|
62184
|
+
baseTotalCount: baseOutput.diagnostics.length,
|
|
62185
|
+
crossFileMatchCount: delta.crossFileMatchCount
|
|
61676
62186
|
}
|
|
61677
62187
|
};
|
|
61678
62188
|
} finally {
|
|
@@ -61779,6 +62289,9 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
61779
62289
|
headDiagnostics: output.diagnostics,
|
|
61780
62290
|
resolvedNodeBinaryPath,
|
|
61781
62291
|
baselineRef: options.baseline.ref,
|
|
62292
|
+
baseFiles: options.baseline.baseFiles,
|
|
62293
|
+
headFiles: options.baseline.headFiles,
|
|
62294
|
+
headAnalyzedFiles: output.analyzedFiles,
|
|
61782
62295
|
deadlineEpochMs
|
|
61783
62296
|
});
|
|
61784
62297
|
if (comparison) {
|
|
@@ -64063,20 +64576,25 @@ const resolveProjectRelativeDirectory = (rootDirectory, projectDirectory) => {
|
|
|
64063
64576
|
return relativeProjectDirectory;
|
|
64064
64577
|
};
|
|
64065
64578
|
//#endregion
|
|
64066
|
-
//#region src/cli/utils/resolve-project-
|
|
64067
|
-
const
|
|
64579
|
+
//#region src/cli/utils/resolve-project-source-file-paths.ts
|
|
64580
|
+
const resolveProjectSourceFilePaths = (rootDirectory, projectDirectory, filePaths) => {
|
|
64068
64581
|
const relativeProjectDirectory = resolveProjectRelativeDirectory(rootDirectory, projectDirectory);
|
|
64069
64582
|
if (relativeProjectDirectory === null) return [];
|
|
64070
|
-
const
|
|
64071
|
-
if (relativeProjectDirectory.length === 0) return
|
|
64583
|
+
const sourceFilePaths = filterSourceFiles([...filePaths]);
|
|
64584
|
+
if (relativeProjectDirectory.length === 0) return sourceFilePaths;
|
|
64072
64585
|
const projectPrefix = `${relativeProjectDirectory}/`;
|
|
64073
|
-
return
|
|
64586
|
+
return sourceFilePaths.flatMap((filePath) => {
|
|
64074
64587
|
const normalizedFilePath = toForwardSlashes(filePath);
|
|
64075
64588
|
if (!normalizedFilePath.startsWith(projectPrefix)) return [];
|
|
64076
64589
|
const projectRelativePath = normalizedFilePath.slice(projectPrefix.length);
|
|
64077
64590
|
return projectRelativePath.length > 0 ? [projectRelativePath] : [];
|
|
64078
64591
|
});
|
|
64079
64592
|
};
|
|
64593
|
+
//#endregion
|
|
64594
|
+
//#region src/cli/utils/resolve-project-diff-include-paths.ts
|
|
64595
|
+
const resolveProjectDiffIncludePaths = (rootDirectory, projectDirectory, diffInfo) => {
|
|
64596
|
+
return resolveProjectSourceFilePaths(rootDirectory, projectDirectory, diffInfo.changedFiles);
|
|
64597
|
+
};
|
|
64080
64598
|
/**
|
|
64081
64599
|
* Re-keys repo-relative changed line ranges (from `getChangedLineRanges`) to
|
|
64082
64600
|
* the scanned project, mirroring `resolveProjectDiffIncludePaths`'s boundary
|
|
@@ -64615,6 +65133,7 @@ const inspectAction = async (directory, flags) => {
|
|
|
64615
65133
|
const isDiffMode = scope !== "full";
|
|
64616
65134
|
const comparisonBaseRef = isDiffMode && diffInfo && !diffInfo.isCurrentChanges ? diffInfo.baseSha ? await resolveMergeBaseRef(resolvedDirectory, diffInfo.baseSha) : diffInfo.diffBaseRef ?? await resolveMergeBaseRef(resolvedDirectory, diffInfo.baseBranch) : null;
|
|
64617
65135
|
const baselineRef = scope === "changed" ? comparisonBaseRef : null;
|
|
65136
|
+
const baselineDiffPlan = baselineRef === null ? null : await getBaselineDiffPlan(resolvedDirectory, baselineRef);
|
|
64618
65137
|
const linesBaseRef = diffInfo?.isCurrentChanges ? "HEAD" : comparisonBaseRef;
|
|
64619
65138
|
const changedLineRanges = scope === "lines" && diffInfo !== null && (diffInfo.isCurrentChanges || linesBaseRef !== null) && diffInfo !== null ? await getChangedLineRanges({
|
|
64620
65139
|
directory: resolvedDirectory,
|
|
@@ -64645,10 +65164,13 @@ const inspectAction = async (directory, flags) => {
|
|
|
64645
65164
|
const supplyChainEnabled = flags.supplyChain ?? projectConfig?.supplyChain?.enabled !== false;
|
|
64646
65165
|
let includePaths;
|
|
64647
65166
|
let supplyChainManifestChanged = false;
|
|
65167
|
+
const projectBaselineBaseFiles = baselineDiffPlan === null ? null : resolveProjectSourceFilePaths(resolvedDirectory, scanDirectory, baselineDiffPlan.baseFiles);
|
|
65168
|
+
const projectBaselineHeadFiles = baselineDiffPlan === null ? null : resolveProjectSourceFilePaths(resolvedDirectory, scanDirectory, baselineDiffPlan.headFiles);
|
|
64648
65169
|
if (isDiffMode) {
|
|
64649
65170
|
const changedSourceFiles = diffInfo === null ? [] : resolveProjectDiffIncludePaths(resolvedDirectory, scanDirectory, diffInfo);
|
|
64650
65171
|
supplyChainManifestChanged = supplyChainEnabled && diffInfo !== null && projectManifestChanged(resolvedDirectory, scanDirectory, diffInfo);
|
|
64651
|
-
|
|
65172
|
+
const hasBaselineOnlyFiles = (projectBaselineBaseFiles?.length ?? 0) > 0;
|
|
65173
|
+
if (changedSourceFiles.length === 0 && !supplyChainManifestChanged && !hasBaselineOnlyFiles) {
|
|
64652
65174
|
if (!isQuiet) {
|
|
64653
65175
|
cliLogger.dim(`No changed source files in ${scanDirectory}, skipping.`);
|
|
64654
65176
|
cliLogger.break();
|
|
@@ -64656,6 +65178,7 @@ const inspectAction = async (directory, flags) => {
|
|
|
64656
65178
|
return null;
|
|
64657
65179
|
}
|
|
64658
65180
|
includePaths = [...changedSourceFiles];
|
|
65181
|
+
if (includePaths.length === 0 && hasBaselineOnlyFiles) includePaths.push(...projectBaselineBaseFiles ?? []);
|
|
64659
65182
|
if (supplyChainManifestChanged) includePaths.push("package.json");
|
|
64660
65183
|
}
|
|
64661
65184
|
if (!isQuiet && !isMultiProject) cliLogger.dim(" ");
|
|
@@ -64667,7 +65190,11 @@ const inspectAction = async (directory, flags) => {
|
|
|
64667
65190
|
configSourceDirectory: projectConfigSourceDirectory ?? void 0,
|
|
64668
65191
|
suppressRendering: isMultiProject,
|
|
64669
65192
|
concurrentScan: isMultiProject,
|
|
64670
|
-
baseline: baselineRef
|
|
65193
|
+
baseline: baselineRef !== null && projectBaselineBaseFiles !== null && projectBaselineHeadFiles !== null ? {
|
|
65194
|
+
ref: baselineRef,
|
|
65195
|
+
baseFiles: projectBaselineBaseFiles,
|
|
65196
|
+
headFiles: projectBaselineHeadFiles
|
|
65197
|
+
} : void 0,
|
|
64671
65198
|
changedLineRanges: scope === "lines" && changedLineRanges !== null ? resolveProjectChangedLineRanges(resolvedDirectory, scanDirectory, changedLineRanges) : void 0,
|
|
64672
65199
|
supplyChainManifestChanged
|
|
64673
65200
|
});
|
|
@@ -65867,4 +66394,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
65867
66394
|
export {};
|
|
65868
66395
|
|
|
65869
66396
|
//# sourceMappingURL=cli.js.map
|
|
65870
|
-
//# debugId=
|
|
66397
|
+
//# debugId=c24708ed-97a3-59cc-81f7-4cf277ab29f2
|