react-doctor 0.8.1-dev.6fcd9c9 → 0.8.1-dev.7818922

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 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]="81bdc95e-12f2-565f-a05c-7b8a60a98f81")}catch(e){}}();
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]="9e32582f-b296-5216-a028-7cc19ed83931")}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";
@@ -37317,10 +37317,6 @@ const listWorkspacePackages = (rootDirectory) => {
37317
37317
  return packages;
37318
37318
  };
37319
37319
  const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
37320
- const MOBX_REACT_PACKAGE_NAME = "mobx-react";
37321
- const MOBX_REACT_LITE_PACKAGE_NAME = "mobx-react-lite";
37322
- const MOBX_STATE_TREE_PACKAGE_NAME = "mobx-state-tree";
37323
- const MOBX_REACT_OBSERVER_PACKAGE_NAME = "mobx-react-observer";
37324
37320
  const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
37325
37321
  const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
37326
37322
  const dependencyDeclaration = getDependencyDeclaration({
@@ -37339,18 +37335,7 @@ const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
37339
37335
  if (nextMajor === null) return false;
37340
37336
  return nextMajor < currentMajor;
37341
37337
  };
37342
- const shouldReplaceSupportedDependencyFact = (currentFact, nextFact, latestSupportedMajor) => {
37343
- if (currentFact.version === null) return true;
37344
- if (nextFact.version === null) return false;
37345
- const currentMajor = getLowestDependencyMajor(currentFact.version);
37346
- const nextMajor = getLowestDependencyMajor(nextFact.version);
37347
- if (currentMajor === null) return false;
37348
- if (nextMajor === null) return true;
37349
- if (currentMajor > latestSupportedMajor) return false;
37350
- if (nextMajor > latestSupportedMajor) return true;
37351
- return nextMajor < currentMajor;
37352
- };
37353
- const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, rootPackageJson) => {
37338
+ const evaluateManifestFacts = (facts, packageJson, directory) => {
37354
37339
  if (facts.expo.version === null) {
37355
37340
  const spec = getDependencySpec(packageJson, "expo");
37356
37341
  if (spec !== null) facts.expo = {
@@ -37372,65 +37357,13 @@ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, roo
37372
37357
  sourceDirectory: directory
37373
37358
  };
37374
37359
  }
37375
- const mobxSpec = getDependencySpec(packageJson, "mobx");
37376
- if (mobxSpec !== null) {
37377
- const nextMobxFact = {
37378
- version: resolveCatalogBackedDependencyVersion({
37379
- rootDirectory: directory,
37380
- rootPackageJson: packageJson,
37381
- packageName: "mobx",
37382
- version: mobxSpec
37383
- }),
37384
- sourceDirectory: directory
37385
- };
37386
- if (shouldReplaceSupportedDependencyFact(facts.mobx, nextMobxFact, 6)) facts.mobx = nextMobxFact;
37387
- }
37388
- facts.hasMobxReact = facts.hasMobxReact || getDependencySpec(packageJson, MOBX_REACT_PACKAGE_NAME) !== null;
37389
- facts.hasMobxReactLite = facts.hasMobxReactLite || getDependencySpec(packageJson, MOBX_REACT_LITE_PACKAGE_NAME) !== null;
37390
- facts.hasMobxStateTree = facts.hasMobxStateTree || getDependencySpec(packageJson, MOBX_STATE_TREE_PACKAGE_NAME) !== null;
37391
- facts.hasMobxReactObserver = facts.hasMobxReactObserver || getDependencySpec(packageJson, MOBX_REACT_OBSERVER_PACKAGE_NAME) !== null;
37392
- const zustandSpec = getDependencySpec(packageJson, "zustand");
37393
- if (zustandSpec !== null) {
37394
- const nextZustandFact = {
37395
- version: resolveCatalogBackedDependencyVersion({
37396
- rootDirectory: directory,
37397
- rootPackageJson: packageJson,
37398
- packageName: "zustand",
37399
- version: zustandSpec
37400
- }),
37401
- sourceDirectory: directory
37402
- };
37403
- if (shouldReplaceSupportedDependencyFact(facts.zustand, nextZustandFact, 5)) facts.zustand = nextZustandFact;
37404
- }
37405
37360
  if (facts.reanimatedVersion === null) {
37406
37361
  const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
37407
37362
  if (spec !== null) facts.reanimatedVersion = spec;
37408
37363
  }
37409
- if (facts.valtioVersion === null) {
37410
- const spec = getDependencySpec(packageJson, "valtio");
37411
- if (spec !== null) facts.valtioVersion = spec;
37412
- }
37413
37364
  facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
37414
37365
  facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
37415
37366
  facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
37416
- const remotionSpec = getDependencySpec(packageJson, "remotion");
37417
- if (remotionSpec !== null) {
37418
- facts.hasRemotionDependency = true;
37419
- const resolvedRemotionVersion = resolveCatalogBackedDependencyVersion({
37420
- rootDirectory,
37421
- rootPackageJson,
37422
- packageName: "remotion",
37423
- version: remotionSpec
37424
- });
37425
- const remotionMajorVersion = resolvedRemotionVersion === null ? null : getLowestDependencyMajor(resolvedRemotionVersion);
37426
- if (remotionMajorVersion === null) {
37427
- facts.hasUnknownRemotionVersion = true;
37428
- facts.remotionVersion = null;
37429
- } else if (!facts.hasUnknownRemotionVersion) {
37430
- const currentRemotionMajorVersion = facts.remotionVersion === null ? null : getLowestDependencyMajor(facts.remotionVersion);
37431
- if (currentRemotionMajorVersion === null || remotionMajorVersion < currentRemotionMajorVersion) facts.remotionVersion = resolvedRemotionVersion;
37432
- }
37433
- }
37434
37367
  };
37435
37368
  const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
37436
37369
  const facts = {
@@ -37450,28 +37383,12 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37450
37383
  version: null,
37451
37384
  sourceDirectory: null
37452
37385
  },
37453
- valtioVersion: null,
37454
- mobx: {
37455
- version: null,
37456
- sourceDirectory: null
37457
- },
37458
- hasMobxReact: false,
37459
- hasMobxReactLite: false,
37460
- hasMobxStateTree: false,
37461
- hasMobxReactObserver: false,
37462
- zustand: {
37463
- version: null,
37464
- sourceDirectory: null
37465
- },
37466
37386
  hasReactNativeAwarePackage: false,
37467
37387
  hasReanimatedAwarePackage: false,
37468
37388
  hasSsrDependency: false,
37469
- hasRemotionDependency: false,
37470
- hasUnknownRemotionVersion: false,
37471
- remotionVersion: null,
37472
37389
  reanimatedVersion: null
37473
37390
  };
37474
- evaluateManifestFacts(facts, rootPackageJson, rootDirectory, rootDirectory, rootPackageJson);
37391
+ evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
37475
37392
  let isReactGroupSettled = !collectReactGroup;
37476
37393
  const visitedDirectories = /* @__PURE__ */ new Set();
37477
37394
  for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
@@ -37480,7 +37397,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37480
37397
  if (visitedDirectories.has(workspaceDirectory)) continue;
37481
37398
  visitedDirectories.add(workspaceDirectory);
37482
37399
  const workspacePackageJson = readPackageJson$1(Path.join(workspaceDirectory, "package.json"));
37483
- evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory, rootDirectory, rootPackageJson);
37400
+ evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
37484
37401
  const info = extractDependencyInfo(workspacePackageJson);
37485
37402
  if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
37486
37403
  if (isReactGroupSettled) continue;
@@ -37701,24 +37618,11 @@ const discoverProjectWithoutPackageJson = (directory) => {
37701
37618
  tailwindVersion: null,
37702
37619
  zodVersion: null,
37703
37620
  zodMajorVersion: null,
37704
- mobxVersion: null,
37705
- mobxMajorVersion: null,
37706
- hasMobxReact: false,
37707
- hasMobxReactLite: false,
37708
- hasMobxStateTree: false,
37709
- hasMobxReactObserver: false,
37710
- zustandVersion: null,
37711
- zustandMajorVersion: null,
37712
37621
  framework: "unknown",
37713
37622
  hasTypeScript: hasOwnTsConfig,
37714
37623
  hasReactCompiler: false,
37715
37624
  hasReactCompilerLintPlugin: false,
37716
37625
  hasTanStackQuery: false,
37717
- valtioVersion: null,
37718
- valtioMajorVersion: null,
37719
- hasRemotion: false,
37720
- remotionVersion: null,
37721
- remotionMajorVersion: null,
37722
37626
  hasSsrDependency: false,
37723
37627
  preactVersion: null,
37724
37628
  preactMajorVersion: null,
@@ -37817,12 +37721,6 @@ const discoverProject = (directory) => {
37817
37721
  packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
37818
37722
  version: workspaceFacts.shopifyFlashList.version
37819
37723
  }) : null;
37820
- const zustandVersion = resolveCatalogBackedDependencyVersion({
37821
- rootDirectory: directory,
37822
- rootPackageJson: packageJson,
37823
- packageName: "zustand",
37824
- version: workspaceFacts.zustand.version
37825
- });
37826
37724
  const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
37827
37725
  const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
37828
37726
  const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
@@ -37831,20 +37729,7 @@ const discoverProject = (directory) => {
37831
37729
  packageName: "next",
37832
37730
  version: workspaceFacts.next.version
37833
37731
  }) : null;
37834
- const valtioVersion = resolveCatalogBackedDependencyVersion({
37835
- rootDirectory: directory,
37836
- rootPackageJson: packageJson,
37837
- packageName: "valtio",
37838
- version: workspaceFacts.valtioVersion
37839
- });
37840
- const mobxVersion = resolveCatalogBackedDependencyVersion({
37841
- rootDirectory: directory,
37842
- rootPackageJson: packageJson,
37843
- packageName: "mobx",
37844
- version: workspaceFacts.mobx.version
37845
- });
37846
37732
  const preactVersion = getPreactVersion(packageJson);
37847
- const remotionVersion = workspaceFacts.remotionVersion;
37848
37733
  const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
37849
37734
  const projectInfo = {
37850
37735
  rootDirectory: directory,
@@ -37854,24 +37739,11 @@ const discoverProject = (directory) => {
37854
37739
  tailwindVersion,
37855
37740
  zodVersion,
37856
37741
  zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
37857
- mobxVersion,
37858
- mobxMajorVersion: mobxVersion === null ? null : getLowestDependencyMajor(mobxVersion),
37859
- hasMobxReact: workspaceFacts.hasMobxReact,
37860
- hasMobxReactLite: workspaceFacts.hasMobxReactLite,
37861
- hasMobxStateTree: workspaceFacts.hasMobxStateTree,
37862
- hasMobxReactObserver: workspaceFacts.hasMobxReactObserver,
37863
- zustandVersion,
37864
- zustandMajorVersion: zustandVersion === null ? null : getLowestDependencyMajor(zustandVersion),
37865
37742
  framework,
37866
37743
  hasTypeScript,
37867
37744
  hasReactCompiler: detectReactCompiler(directory, packageJson),
37868
37745
  hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
37869
37746
  hasTanStackQuery: hasTanStackQuery(packageJson),
37870
- valtioVersion,
37871
- valtioMajorVersion: valtioVersion === null ? null : getLowestDependencyMajor(valtioVersion),
37872
- hasRemotion: workspaceFacts.hasRemotionDependency,
37873
- remotionVersion,
37874
- remotionMajorVersion: remotionVersion === null ? null : getLowestDependencyMajor(remotionVersion),
37875
37747
  hasSsrDependency: workspaceFacts.hasSsrDependency,
37876
37748
  preactVersion,
37877
37749
  preactMajorVersion: parseReactMajor(preactVersion),
@@ -38105,6 +37977,7 @@ const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
38105
37977
  "react/jsx-no-new-function-as-prop": "react-doctor/jsx-no-new-function-as-prop",
38106
37978
  "react/jsx-no-new-object-as-prop": "react-doctor/jsx-no-new-object-as-prop",
38107
37979
  "react/jsx-no-script-url": "react-doctor/jsx-no-script-url",
37980
+ "react/jsx-no-target-blank": "react-doctor/jsx-no-target-blank",
38108
37981
  "react/jsx-no-undef": "react-doctor/jsx-no-undef",
38109
37982
  "react/jsx-no-useless-fragment": "react-doctor/jsx-no-useless-fragment",
38110
37983
  "react/jsx-pascal-case": "react-doctor/jsx-pascal-case",
@@ -40426,25 +40299,9 @@ const BABEL_CONFIG_FILE_NAMES = [
40426
40299
  ".babelrc.json"
40427
40300
  ];
40428
40301
  const LEGACY_PRESET_SPEC = "module:metro-react-native-babel-preset";
40429
- const LEGACY_PRESET_PACKAGE = "metro-react-native-babel-preset";
40430
- const REACT_NATIVE_PACKAGE = "react-native";
40431
- const PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION = "0.73.0";
40432
- const LEGACY_PRESET_REFERENCE = new RegExp(`['"]${LEGACY_PRESET_SPEC}['"]`);
40433
40302
  const MODERN_PRESET_REFERENCE = new RegExp(`['"]module:@react-native/babel-preset['"]`);
40434
40303
  const ENABLE_BABEL_RUNTIME_VERSION = /enableBabelRuntime["']?\s*:\s*['"]/;
40435
- const isReactNativeVersionAtLeastPresetRename = (rootDirectory, packageJson) => {
40436
- const installedReactNativeManifestPath = Path.join(rootDirectory, "node_modules", REACT_NATIVE_PACKAGE, "package.json");
40437
- const reactNativeVersionSpec = (isFile(installedReactNativeManifestPath) ? readPackageJson$1(installedReactNativeManifestPath).version : void 0) ?? getDependencySpec(packageJson, REACT_NATIVE_PACKAGE);
40438
- if (reactNativeVersionSpec === null || reactNativeVersionSpec === void 0) return false;
40439
- const normalizedVersionRange = import_semver.validRange(reactNativeVersionSpec);
40440
- if (normalizedVersionRange === null) return false;
40441
- const minimumVersion = import_semver.minVersion(normalizedVersionRange);
40442
- return minimumVersion !== null && import_semver.gte(minimumVersion, PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION);
40443
- };
40444
- const canResolveLegacyPreset = (rootDirectory, packageJson) => getDependencySpec(packageJson, LEGACY_PRESET_PACKAGE) !== null || isFile(Path.join(rootDirectory, "node_modules", LEGACY_PRESET_PACKAGE, "package.json"));
40445
40304
  const checkReactNativeMetroBabelPreset = (rootDirectory) => {
40446
- const packageJson = readPackageJson$1(Path.join(rootDirectory, "package.json"));
40447
- const shouldReportLegacyPreset = isReactNativeVersionAtLeastPresetRename(rootDirectory, packageJson) && !canResolveLegacyPreset(rootDirectory, packageJson);
40448
40305
  for (const fileName of BABEL_CONFIG_FILE_NAMES) {
40449
40306
  const filePath = Path.join(rootDirectory, fileName);
40450
40307
  if (!isFile(filePath)) continue;
@@ -40454,7 +40311,7 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
40454
40311
  } catch {
40455
40312
  continue;
40456
40313
  }
40457
- if (shouldReportLegacyPreset && LEGACY_PRESET_REFERENCE.test(contents)) return [buildReactNativeDiagnostic({
40314
+ if (contents.includes(LEGACY_PRESET_SPEC)) return [buildReactNativeDiagnostic({
40458
40315
  filePath: fileName,
40459
40316
  rule: "rn-no-metro-babel-preset",
40460
40317
  severity: "error",
@@ -40477,6 +40334,12 @@ const checkReactNativeProject = (rootDirectory, project) => {
40477
40334
  return [...checkReactNativeMetroBabelPreset(rootDirectory), ...checkReactNativeLibraryDependencies(rootDirectory)];
40478
40335
  };
40479
40336
  const RULE_KEY = "no-vulnerable-react-server-components";
40337
+ const DEPENDENCY_SECTIONS = [
40338
+ "dependencies",
40339
+ "devDependencies",
40340
+ "peerDependencies",
40341
+ "optionalDependencies"
40342
+ ];
40480
40343
  const REACT_RSC_ADVISORIES_BY_MINOR = {
40481
40344
  "19.0": {
40482
40345
  rceFixedVersion: "19.0.1",
@@ -40523,13 +40386,20 @@ const enumerateWorkspaceDirectories = (workspaceRoot) => {
40523
40386
  for (const pattern of patterns) for (const directory of resolveWorkspaceDirectories(workspaceRoot, pattern)) directories.add(directory);
40524
40387
  return [...directories];
40525
40388
  };
40389
+ const readDeclaredSpec = (packageJson, packageName) => {
40390
+ for (const section of DEPENDENCY_SECTIONS) {
40391
+ const spec = packageJson[section]?.[packageName];
40392
+ if (typeof spec === "string") return spec;
40393
+ }
40394
+ return null;
40395
+ };
40526
40396
  const resolveVersionInDirectory = (directory, packageName, declaredSpecOverride) => {
40527
40397
  const manifestPath = Path.join(directory, "node_modules", packageName, "package.json");
40528
40398
  if (isFile(manifestPath)) {
40529
40399
  const installedVersion = import_semver.valid(readPackageJson$1(manifestPath).version ?? null);
40530
40400
  if (installedVersion !== null) return installedVersion;
40531
40401
  }
40532
- const candidateSpecs = [getDependencySpec(readPackageJson$1(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
40402
+ const candidateSpecs = [readDeclaredSpec(readPackageJson$1(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
40533
40403
  for (const spec of candidateSpecs) {
40534
40404
  const pinnedVersion = spec === null ? null : import_semver.valid(spec);
40535
40405
  if (pinnedVersion !== null) return pinnedVersion;
@@ -41209,24 +41079,9 @@ const buildCapabilities = (project) => {
41209
41079
  })) capabilities.add("tailwind:3.4");
41210
41080
  if (project.zodVersion !== null) capabilities.add("zod");
41211
41081
  if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
41212
- if (project.mobxVersion !== void 0 && project.mobxVersion !== null || project.hasMobxReact === true || project.hasMobxReactLite === true || project.hasMobxStateTree === true || project.hasMobxReactObserver === true) capabilities.add("mobx");
41213
- if (project.hasMobxReact === true) capabilities.add("mobx-react");
41214
- if (project.hasMobxReactLite === true) capabilities.add("mobx-react-lite");
41215
- if (project.hasMobxReact === true || project.hasMobxReactLite === true) capabilities.add("mobx-react-binding");
41216
- if (project.hasMobxStateTree === true) capabilities.add("mobx-state-tree");
41217
- if (project.hasMobxReactObserver === true) capabilities.add("mobx-react-observer");
41218
- if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addMajorLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
41219
- if (project.zustandVersion !== void 0 && project.zustandVersion !== null) capabilities.add("zustand");
41220
- if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addMajorLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
41221
41082
  if (project.isPreES2023Target) capabilities.add("pre-es2023");
41222
41083
  if (project.hasReactCompiler) capabilities.add("react-compiler");
41223
41084
  if (project.hasTanStackQuery) capabilities.add("tanstack-query");
41224
- if (project.valtioVersion !== null) capabilities.add("valtio");
41225
- addMajorLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
41226
- if (project.hasRemotion) {
41227
- capabilities.add("remotion");
41228
- addMajorLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
41229
- }
41230
41085
  if (project.hasTypeScript) capabilities.add("typescript");
41231
41086
  if (project.preactVersion !== null) capabilities.add("preact");
41232
41087
  addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
@@ -42479,35 +42334,6 @@ const parseGithubViewerPermission = (stdout) => {
42479
42334
  return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
42480
42335
  };
42481
42336
  const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
42482
- const parseBaselineDiffPlan = (value) => {
42483
- const entries = splitNullSeparated(value);
42484
- const baseFiles = /* @__PURE__ */ new Set();
42485
- const headFiles = /* @__PURE__ */ new Set();
42486
- for (let entryIndex = 0; entryIndex < entries.length; entryIndex += 2) {
42487
- const status = entries[entryIndex];
42488
- const filePath = entries[entryIndex + 1];
42489
- if (status === void 0 || filePath === void 0 || status.length !== 1) return null;
42490
- if (status === "A") {
42491
- headFiles.add(filePath);
42492
- continue;
42493
- }
42494
- if (status === "D") {
42495
- baseFiles.add(filePath);
42496
- continue;
42497
- }
42498
- if (status === "M" || status === "T") {
42499
- baseFiles.add(filePath);
42500
- headFiles.add(filePath);
42501
- continue;
42502
- }
42503
- return null;
42504
- }
42505
- return {
42506
- baseFiles: [...baseFiles],
42507
- headFiles: [...headFiles],
42508
- untrackedFiles: []
42509
- };
42510
- };
42511
42337
  const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
42512
42338
  /**
42513
42339
  * `Git` wraps every `git`-via-subprocess call react-doctor makes
@@ -42710,45 +42536,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
42710
42536
  githubViewerPermission,
42711
42537
  branchExists,
42712
42538
  mergeBase,
42713
- baselineDiffPlan: (input) => {
42714
- if (!isSafeGitRevision(input.ref)) return succeed$2(null);
42715
- return gen(function* () {
42716
- const unmerged = yield* runGit(input.directory, [
42717
- "diff",
42718
- "--no-ext-diff",
42719
- "-z",
42720
- "--name-only",
42721
- "--diff-filter=U",
42722
- "--relative"
42723
- ]);
42724
- if (unmerged.status !== 0 || unmerged.stdout.length > 0) return null;
42725
- const result = yield* runGit(input.directory, [
42726
- "diff",
42727
- "--no-ext-diff",
42728
- "--no-textconv",
42729
- "--no-renames",
42730
- "-z",
42731
- "--name-status",
42732
- "--relative",
42733
- input.ref
42734
- ]);
42735
- if (result.status !== 0) return null;
42736
- const plan = parseBaselineDiffPlan(result.stdout);
42737
- if (plan === null) return null;
42738
- const untracked = yield* runGit(input.directory, [
42739
- "ls-files",
42740
- "--others",
42741
- "--exclude-standard",
42742
- "-z"
42743
- ]);
42744
- if (untracked.status !== 0) return null;
42745
- return {
42746
- baseFiles: plan.baseFiles,
42747
- headFiles: plan.headFiles,
42748
- untrackedFiles: splitNullSeparated(untracked.stdout)
42749
- };
42750
- }).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.baselineDiffPlan"));
42751
- },
42752
42539
  diffSelection: ({ directory, explicitBaseBranch, includeUntracked = false }) => gen(function* () {
42753
42540
  if (explicitBaseBranch !== void 0 && explicitBaseBranch.trim().length === 0) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "Diff base branch cannot be empty." }) }));
42754
42541
  if (explicitBaseBranch !== void 0) {
@@ -42898,7 +42685,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
42898
42685
  githubViewerPermission: () => succeed$2(snapshot.githubViewerPermission ?? null),
42899
42686
  branchExists: (_directory, branch) => succeed$2(snapshot.branchExists?.get(branch) ?? false),
42900
42687
  mergeBase: ({ ref }) => succeed$2(snapshot.mergeBase?.get(ref) ?? null),
42901
- baselineDiffPlan: () => succeed$2(snapshot.baselineDiffPlan ?? null),
42902
42688
  diffSelection: () => succeed$2(snapshot.diffSelection ?? null),
42903
42689
  stagedFilePaths: () => succeed$2(snapshot.stagedFiles ?? []),
42904
42690
  showStagedContent: (_directory, relativePath) => succeed$2(snapshot.stagedContent?.get(relativePath) ?? null),
@@ -44236,17 +44022,12 @@ const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown
44236
44022
  const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
44237
44023
  const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
44238
44024
  const REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION = "It's how the library works, not a bug in your code. Memoize values you pass from it into other memoized components, or suppress it with `// react-doctor-disable-next-line react-hooks-js/incompatible-library`.";
44239
- const SET_STATE_IN_EFFECT_ACTION = "Prefer deriving or initializing the value before render. If the effect must read a browser API after mount, treat this as advisory or suppress it with `// react-doctor-disable-next-line react-hooks-js/set-state-in-effect`.";
44240
44025
  const REACT_COMPILER_GENERIC_MESSAGE = `${REACT_COMPILER_IMPACT}. ${REACT_COMPILER_ACTION}`;
44241
44026
  const buildReactCompilerMessage = (reasonSummary, action = REACT_COMPILER_ACTION) => {
44242
44027
  const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
44243
44028
  if (!normalizedSummary) return `${REACT_COMPILER_IMPACT}. ${action}`;
44244
44029
  return `${REACT_COMPILER_IMPACT}: ${normalizedSummary}. ${action}`;
44245
44030
  };
44246
- const buildSetStateInEffectMessage = (reasonSummary) => {
44247
- const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
44248
- return `This synchronous effect update causes an extra render${normalizedSummary ? `: ${normalizedSummary}` : ""}. ${SET_STATE_IN_EFFECT_ACTION}`;
44249
- };
44250
44031
  const PLUGIN_CATEGORY_MAP = {
44251
44032
  react: "Bugs",
44252
44033
  "react-hooks": "Bugs",
@@ -44304,10 +44085,6 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
44304
44085
  message: REACT_ERROR_BOUNDARY_MESSAGE,
44305
44086
  help: reasonDetail || help
44306
44087
  };
44307
- if (rule === "set-state-in-effect") return {
44308
- message: buildSetStateInEffectMessage(reasonSummary.trim()),
44309
- help: reasonDetail || help
44310
- };
44311
44088
  return {
44312
44089
  message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
44313
44090
  help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
@@ -46644,19 +46421,12 @@ const isPathInsideDirectory = (childAbsolutePath, parentAbsolutePath) => {
46644
46421
  */
46645
46422
  const materializeSourceTree = (input) => gen(function* () {
46646
46423
  const materializedFiles = [];
46647
- const unmaterializedFiles = [];
46648
46424
  const resolvedTempDirectory = path.resolve(input.tempDirectory);
46649
46425
  for (const relativePath of input.files) {
46650
46426
  const content = yield* input.readContent(relativePath).pipe(orElseSucceed(() => null));
46651
- if (content === null) {
46652
- unmaterializedFiles.push(relativePath);
46653
- continue;
46654
- }
46427
+ if (content === null) continue;
46655
46428
  const candidateTargetPath = path.resolve(resolvedTempDirectory, relativePath);
46656
- if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory)) {
46657
- unmaterializedFiles.push(relativePath);
46658
- continue;
46659
- }
46429
+ if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory)) continue;
46660
46430
  yield* sync(() => {
46661
46431
  fs.mkdirSync(path.dirname(candidateTargetPath), { recursive: true });
46662
46432
  fs.writeFileSync(candidateTargetPath, content);
@@ -46673,7 +46443,6 @@ const materializeSourceTree = (input) => gen(function* () {
46673
46443
  return {
46674
46444
  tempDirectory: input.tempDirectory,
46675
46445
  materializedFiles,
46676
- unmaterializedFiles,
46677
46446
  cleanup: () => {
46678
46447
  try {
46679
46448
  fs.rmSync(input.tempDirectory, {
@@ -46943,80 +46712,54 @@ const buildSkippedChecks = (input) => {
46943
46712
  skippedCheckReasons
46944
46713
  };
46945
46714
  };
46946
- const fingerprintText = (text) => createHash("sha256").update(text).digest("hex");
46947
- const normalizeEvidence = (evidence) => evidence.replace(/\s+/g, " ").trim();
46948
- const getDiagnosticMatchKeys = (diagnostic, evidence) => {
46715
+ const fingerprintDiagnostic = (diagnostic, lineText) => {
46949
46716
  const ruleKey = `${diagnostic.plugin}/${diagnostic.rule}`;
46950
- const messageFingerprint = fingerprintText(`${diagnostic.title ?? ""}\0${diagnostic.message}`);
46951
- const normalizedEvidence = evidence === null ? "" : normalizeEvidence(evidence);
46952
- const stableEvidenceKey = normalizedEvidence.length > 0 ? `evidence\0${ruleKey}\0${messageFingerprint}\0${fingerprintText(normalizedEvidence)}` : null;
46953
- return {
46954
- stableEvidenceKey,
46955
- sameFileStableEvidenceKey: stableEvidenceKey === null ? null : `${diagnostic.filePath}\0${stableEvidenceKey}`,
46956
- sameFileFallbackKey: diagnostic.matchByOccurrence || normalizedEvidence.length === 0 ? `fallback\0${diagnostic.filePath}\0${ruleKey}\0${messageFingerprint}` : null
46957
- };
46958
- };
46959
- const addDiagnosticIndex = (buckets, key, diagnosticIndex) => {
46960
- if (key === null) return;
46961
- const diagnosticIndexes = buckets.get(key) ?? [];
46962
- diagnosticIndexes.push(diagnosticIndex);
46963
- buckets.set(key, diagnosticIndexes);
46964
- };
46965
- const takeMatchingDiagnosticIndex = (buckets, key, matchedDiagnosticIndexes) => {
46966
- if (key === null) return null;
46967
- for (const diagnosticIndex of buckets.get(key) ?? []) if (!matchedDiagnosticIndexes.has(diagnosticIndex)) return diagnosticIndex;
46968
- return null;
46969
- };
46970
- const readDiagnosticEvidence = (diagnostic, readEvidence, readLine) => readEvidence?.(diagnostic) ?? readLine(diagnostic.filePath, diagnostic.line);
46971
- const buildMatchCandidates = (diagnostics, readEvidence, readLine) => diagnostics.map((diagnostic, diagnosticIndex) => ({
46972
- diagnosticIndex,
46973
- ...getDiagnosticMatchKeys(diagnostic, readDiagnosticEvidence(diagnostic, readEvidence, readLine))
46974
- }));
46975
- /**
46976
- * Diffs a head scan against a base scan using a multiset of construct-level
46977
- * evidence. Stable identities combine plugin/rule, the diagnostic message,
46978
- * and normalized diagnosed source, so unchanged findings can move across
46979
- * files while changed constructs or messages remain new. Cardinality is
46980
- * retained for identical findings. Diagnostics explicitly marked
46981
- * `matchByOccurrence` may fall back to same-file plugin/rule/message matching
46982
- * after same-file strict evidence matching. Cross-file evidence matching runs
46983
- * last so a copy cannot consume a reformatted local occurrence. Unreadable
46984
- * evidence uses the same conservative fallback rather than matching across
46985
- * files without proof.
46717
+ const snippet = lineText === null || diagnostic.matchByOccurrence ? "" : createHash("sha1").update(lineText.trim()).digest("hex");
46718
+ return `${diagnostic.filePath}\u0000${ruleKey}\u0000${snippet}`;
46719
+ };
46720
+ /**
46721
+ * Diffs a head scan against a base scan to isolate the diagnostics a change
46722
+ * introduced (and count the ones it resolved). Matching is a multiset over a
46723
+ * position-independent fingerprint — `(filePath, plugin/rule, hash(flagged
46724
+ * line text))` — so inserting lines above an existing issue doesn't make it
46725
+ * look new, while a genuinely new occurrence (new line text, or one more of
46726
+ * the same) surfaces. Identical repeated findings are matched by count.
46727
+ *
46728
+ * Diagnostics carrying `matchByOccurrence` (resolved at diagnostic creation:
46729
+ * every Accessibility-category finding, plus rules opting in via their
46730
+ * `matchByOccurrence` metadata flag) drop the line-text snippet and match by
46731
+ * `(filePath, plugin/rule)` occurrence count alone. Their identity is the
46732
+ * flagged element, not the line's text, so editing the line (reindentation,
46733
+ * prettier reflow, collapsing a multi-line JSX element) doesn't reclassify a
46734
+ * pre-existing finding as new — while one MORE occurrence of the same rule in
46735
+ * the file still surfaces. Expression-level rules keep the line-text snippet:
46736
+ * there the flagged expression IS the finding, so changed text means new +
46737
+ * fixed.
46738
+ *
46739
+ * v1 limitation: the fingerprint keys on the head-relative `filePath`, and base
46740
+ * content is read at that same path. A file renamed by the change therefore has
46741
+ * no base match, so its pre-existing findings are reported as new. This
46742
+ * over-reports (never hides a real issue) and is rare; rename-aware base
46743
+ * resolution is a follow-up.
46986
46744
  */
46987
46745
  const computeDiagnosticDelta = (input) => {
46988
- const baseCandidates = buildMatchCandidates(input.baseDiagnostics, input.readBaseEvidence, input.readBaseLine);
46989
- const headCandidates = buildMatchCandidates(input.headDiagnostics, input.readHeadEvidence, input.readHeadLine);
46990
- const baseByStableEvidence = /* @__PURE__ */ new Map();
46991
- const baseBySameFileStableEvidence = /* @__PURE__ */ new Map();
46992
- const baseBySameFileFallback = /* @__PURE__ */ new Map();
46993
- for (const candidate of baseCandidates) {
46994
- addDiagnosticIndex(baseByStableEvidence, candidate.stableEvidenceKey, candidate.diagnosticIndex);
46995
- addDiagnosticIndex(baseBySameFileStableEvidence, candidate.sameFileStableEvidenceKey, candidate.diagnosticIndex);
46996
- addDiagnosticIndex(baseBySameFileFallback, candidate.sameFileFallbackKey, candidate.diagnosticIndex);
46997
- }
46998
- const matchedHeadDiagnosticIndexes = /* @__PURE__ */ new Set();
46999
- const matchedBaseDiagnosticIndexes = /* @__PURE__ */ new Set();
47000
- const matchCandidates = (baseBuckets, getKey, onMatch) => {
47001
- for (const candidate of headCandidates) {
47002
- if (matchedHeadDiagnosticIndexes.has(candidate.diagnosticIndex)) continue;
47003
- const baseDiagnosticIndex = takeMatchingDiagnosticIndex(baseBuckets, getKey(candidate), matchedBaseDiagnosticIndexes);
47004
- if (baseDiagnosticIndex === null) continue;
47005
- matchedHeadDiagnosticIndexes.add(candidate.diagnosticIndex);
47006
- matchedBaseDiagnosticIndexes.add(baseDiagnosticIndex);
47007
- onMatch?.(candidate.diagnosticIndex, baseDiagnosticIndex);
47008
- }
47009
- };
47010
- matchCandidates(baseBySameFileStableEvidence, (candidate) => candidate.sameFileStableEvidenceKey);
47011
- matchCandidates(baseBySameFileFallback, (candidate) => candidate.sameFileFallbackKey);
47012
- let crossFileMatchCount = 0;
47013
- matchCandidates(baseByStableEvidence, (candidate) => candidate.stableEvidenceKey, (head, base) => {
47014
- if (input.headDiagnostics[head]?.filePath !== input.baseDiagnostics[base]?.filePath) crossFileMatchCount += 1;
47015
- });
46746
+ const unmatchedBaseByFingerprint = /* @__PURE__ */ new Map();
46747
+ for (const diagnostic of input.baseDiagnostics) {
46748
+ const key = fingerprintDiagnostic(diagnostic, input.readBaseLine(diagnostic.filePath, diagnostic.line));
46749
+ unmatchedBaseByFingerprint.set(key, (unmatchedBaseByFingerprint.get(key) ?? 0) + 1);
46750
+ }
46751
+ const newDiagnostics = [];
46752
+ for (const diagnostic of input.headDiagnostics) {
46753
+ const key = fingerprintDiagnostic(diagnostic, input.readHeadLine(diagnostic.filePath, diagnostic.line));
46754
+ const availableMatches = unmatchedBaseByFingerprint.get(key) ?? 0;
46755
+ if (availableMatches > 0) unmatchedBaseByFingerprint.set(key, availableMatches - 1);
46756
+ else newDiagnostics.push(diagnostic);
46757
+ }
46758
+ let fixedCount = 0;
46759
+ for (const remaining of unmatchedBaseByFingerprint.values()) fixedCount += remaining;
47016
46760
  return {
47017
- newDiagnostics: input.headDiagnostics.filter((_diagnostic, diagnosticIndex) => !matchedHeadDiagnosticIndexes.has(diagnosticIndex)),
47018
- fixedCount: input.baseDiagnostics.length - matchedBaseDiagnosticIndexes.size,
47019
- crossFileMatchCount
46761
+ newDiagnostics,
46762
+ fixedCount
47020
46763
  };
47021
46764
  };
47022
46765
  /**
@@ -47048,12 +46791,6 @@ const getDiffInfo = (directory, explicitBaseBranch, includeUntracked) => runProm
47048
46791
  };
47049
46792
  }).pipe(provide(Git.layerNode)));
47050
46793
  const filterSourceFiles = (filePaths) => filePaths.filter(isLintableSourceFile);
47051
- const getBaselineDiffPlan = (directory, ref) => runPromise(gen(function* () {
47052
- return yield* (yield* Git).baselineDiffPlan({
47053
- directory,
47054
- ref
47055
- });
47056
- }).pipe(provide(Git.layerNode)));
47057
46794
  /**
47058
46795
  * Programmatic façade over `Git.changedLineRanges` (the `lines` scope). Diffs
47059
46796
  * `files` with `--unified=0` against `baseRef` (or the index when `cached`),
@@ -47510,7 +47247,7 @@ const makeNoopConsole = () => ({
47510
47247
  });
47511
47248
  //#endregion
47512
47249
  //#region src/cli/utils/version.ts
47513
- const VERSION = "0.8.1-dev.6fcd9c9";
47250
+ const VERSION = "0.8.1-dev.7818922";
47514
47251
  //#endregion
47515
47252
  //#region src/cli/utils/json-mode.ts
47516
47253
  let context = null;
@@ -47862,13 +47599,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
47862
47599
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
47863
47600
  * standard `SENTRY_RELEASE` override.
47864
47601
  */
47865
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.6fcd9c9`;
47602
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.7818922`;
47866
47603
  /**
47867
47604
  * Deployment environment shown in Sentry's environment filter. Defaults to
47868
47605
  * `production` for tagged releases and `development` for dev/unbuilt versions,
47869
47606
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
47870
47607
  */
47871
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.6fcd9c9") ? "development" : "production");
47608
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.7818922") ? "development" : "production");
47872
47609
  /**
47873
47610
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
47874
47611
  * (set to `0` to disable tracing) and falls back to
@@ -60491,7 +60228,6 @@ const buildOutcomeAttributes = (input) => {
60491
60228
  new: summary.totalDiagnosticCount,
60492
60229
  fixed: result.baselineDelta.fixedCount,
60493
60230
  baseTotal: result.baselineDelta.baseTotalCount,
60494
- crossFileMatches: result.baselineDelta.crossFileMatchCount ?? null,
60495
60231
  degraded: false
60496
60232
  }));
60497
60233
  else if (input.gateExempt) attributes["baseline.degraded"] = true;
@@ -60605,49 +60341,28 @@ const diagnosticIntersectsLineRanges = (diagnostic, lineRanges) => {
60605
60341
  return lineRanges.some(([rangeStartLine, rangeEndLine]) => diagnostic.line <= rangeEndLine && diagnosticEndLine >= rangeStartLine);
60606
60342
  };
60607
60343
  //#endregion
60608
- //#region src/cli/utils/is-materializable-git-source.ts
60609
- const GIT_LFS_POINTER_HEADER = "version https://git-lfs.github.com/spec/v1";
60610
- const isMaterializableGitSource = (content) => !content.includes("\0") && !content.startsWith(GIT_LFS_POINTER_HEADER);
60611
- //#endregion
60612
60344
  //#region src/cli/utils/materialize-baseline-files.ts
60613
60345
  /**
60614
- * Materializes the base side of the `ref` → worktree diff into
60615
- * `tempDirectory`, mirroring the project layout plus head's config files so
60616
- * both sides lint under the same rules. Git rename heuristics are disabled by
60617
- * the diff planner, so an old path is retained as a base deletion while its
60618
- * new path is a head addition. Missing head-only additions are expected;
60619
- * missing paths that the plan says must exist at base make `isComplete` false.
60346
+ * Materializes the `ref` version of `files` into `tempDirectory` (via
60347
+ * `git show <ref>:<path>`), mirroring the project layout + head's config files
60348
+ * so the base lints under the same rules as head. Reuses the shared,
60349
+ * zip-slip-guarded `materializeSourceTree`. Per-file read misses (e.g. a file
60350
+ * the PR added, absent at base) are skipped, which is exactly what we want:
60351
+ * a brand-new file has no base counterpart, so all its findings are "new".
60620
60352
  */
60621
60353
  const materializeBaselineFiles = (input) => runPromise(gen(function* () {
60622
60354
  const git = yield* Git;
60623
- const diffPlan = yield* git.baselineDiffPlan({
60624
- directory: input.directory,
60625
- ref: input.ref
60626
- });
60627
- const baseFiles = input.baseFiles ?? diffPlan?.baseFiles;
60628
- const headFiles = input.headFiles ?? diffPlan?.headFiles;
60629
- const untrackedFiles = diffPlan?.untrackedFiles ?? [];
60630
- if (baseFiles === void 0 || headFiles === void 0) return null;
60631
- const files = [...new Set([...input.files, ...baseFiles])];
60632
- const tree = yield* materializeSourceTree({
60355
+ return yield* materializeSourceTree({
60633
60356
  directory: input.directory,
60634
- files,
60357
+ files: input.files,
60635
60358
  tempDirectory: input.tempDirectory,
60636
60359
  readContent: (relativePath) => git.showRefContent({
60637
60360
  directory: input.directory,
60638
60361
  ref: input.ref,
60639
60362
  relativePath,
60640
60363
  options: { maxBufferBytes: GIT_SHOW_MAX_BUFFER_BYTES }
60641
- }).pipe(map$3((content) => content !== null && isMaterializableGitSource(content) ? content : null))
60364
+ })
60642
60365
  });
60643
- const materializedFiles = new Set(tree.materializedFiles);
60644
- return {
60645
- ...tree,
60646
- baseFiles,
60647
- headFiles,
60648
- isComplete: baseFiles.every((filePath) => materializedFiles.has(filePath)),
60649
- untrackedFiles
60650
- };
60651
60366
  }).pipe(provide(Git.layerNode)));
60652
60367
  /**
60653
60368
  * Resolves the commit a baseline scan should read base content from — the
@@ -60670,8 +60385,8 @@ const resolveMergeBaseRef = async (directory, ref) => {
60670
60385
  //#region src/cli/utils/read-source-line.ts
60671
60386
  /**
60672
60387
  * Builds a cached `(filePath, line) -> source text` reader rooted at
60673
- * `rootDirectory`, used as the fallback when construct-level diagnostic
60674
- * evidence cannot be read. Wraps core's
60388
+ * `rootDirectory`, used to fingerprint a diagnostic by the content of its
60389
+ * flagged line (see `computeDiagnosticDelta`). Wraps core's
60675
60390
  * `createNodeReadFileLinesSync` with per-file memoization + 1-indexed line
60676
60391
  * lookup; unreadable files / out-of-range lines return `null`.
60677
60392
  */
@@ -60686,338 +60401,6 @@ const createSourceLineReader = (rootDirectory) => {
60686
60401
  };
60687
60402
  };
60688
60403
  //#endregion
60689
- //#region src/cli/utils/read-diagnostic-evidence.ts
60690
- const SOURCE_EXTENSIONS = [
60691
- ".ts",
60692
- ".tsx",
60693
- ".js",
60694
- ".jsx",
60695
- ".mts",
60696
- ".cts",
60697
- ".mjs",
60698
- ".cjs"
60699
- ];
60700
- const COMPONENT_WRAPPER_NAMES = new Set(["memo", "forwardRef"]);
60701
- const getScriptKind = (filePath) => {
60702
- const extension = path.extname(filePath).toLowerCase();
60703
- if (extension === ".tsx") return ts.ScriptKind.TSX;
60704
- if (extension === ".jsx") return ts.ScriptKind.JSX;
60705
- if (extension === ".js" || extension === ".mjs" || extension === ".cjs") return ts.ScriptKind.JS;
60706
- return ts.ScriptKind.TS;
60707
- };
60708
- const resolveSafeSourcePath = (rootDirectory, filePath) => {
60709
- try {
60710
- const resolvedRootDirectory = fs.realpathSync(rootDirectory);
60711
- const absolutePath = path.resolve(resolvedRootDirectory, filePath);
60712
- const relativePath = path.relative(resolvedRootDirectory, absolutePath);
60713
- if (relativePath.length === 0 || relativePath === ".." || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath)) return null;
60714
- const stats = fs.lstatSync(absolutePath);
60715
- if (!stats.isFile() || stats.isSymbolicLink()) return null;
60716
- const realPath = fs.realpathSync(absolutePath);
60717
- const realRelativePath = path.relative(resolvedRootDirectory, realPath);
60718
- return realRelativePath !== ".." && !realRelativePath.startsWith(`..${path.sep}`) && !path.isAbsolute(realRelativePath) ? realPath : null;
60719
- } catch {
60720
- return null;
60721
- }
60722
- };
60723
- const readSourceRecord = (rootDirectory, filePath, state) => {
60724
- const normalizedFilePath = filePath.replace(/\\/g, "/");
60725
- if (state.recordByFilePath.has(normalizedFilePath)) return state.recordByFilePath.get(normalizedFilePath) ?? null;
60726
- const absolutePath = resolveSafeSourcePath(rootDirectory, normalizedFilePath);
60727
- if (absolutePath === null) {
60728
- state.recordByFilePath.set(normalizedFilePath, null);
60729
- return null;
60730
- }
60731
- try {
60732
- const sourceText = fs.readFileSync(absolutePath, "utf-8");
60733
- const record = {
60734
- absolutePath,
60735
- filePath: normalizedFilePath,
60736
- sourceFile: ts.createSourceFile(absolutePath, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(absolutePath)),
60737
- sourceText
60738
- };
60739
- state.recordByFilePath.set(normalizedFilePath, record);
60740
- return record;
60741
- } catch {
60742
- state.recordByFilePath.set(normalizedFilePath, null);
60743
- return null;
60744
- }
60745
- };
60746
- const listSourceRecords = (rootDirectory, state) => {
60747
- if (state.sourceRecords !== null) return state.sourceRecords;
60748
- state.sourceRecords = listSourceFiles(rootDirectory).flatMap((filePath) => {
60749
- const record = readSourceRecord(rootDirectory, filePath, state);
60750
- return record === null ? [] : [record];
60751
- });
60752
- return state.sourceRecords;
60753
- };
60754
- const unwrapExpression = (expression) => {
60755
- let currentExpression = expression;
60756
- while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression)) currentExpression = currentExpression.expression;
60757
- return currentExpression;
60758
- };
60759
- const getCalleeName = (expression) => {
60760
- const unwrappedExpression = unwrapExpression(expression);
60761
- if (ts.isIdentifier(unwrappedExpression)) return unwrappedExpression.text;
60762
- if (ts.isPropertyAccessExpression(unwrappedExpression)) return unwrappedExpression.name.text;
60763
- return null;
60764
- };
60765
- const isComponentWrapperCall = (node) => {
60766
- const wrapperName = getCalleeName(node.expression);
60767
- return wrapperName !== null && COMPONENT_WRAPPER_NAMES.has(wrapperName);
60768
- };
60769
- const getFunctionName = (node) => {
60770
- if (ts.isFunctionDeclaration(node) && node.name !== void 0) return node.name.text;
60771
- if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
60772
- let componentExpression = node;
60773
- while (true) {
60774
- const parent = componentExpression.parent;
60775
- if (ts.isParenthesizedExpression(parent) || ts.isAsExpression(parent) || ts.isTypeAssertionExpression(parent) || ts.isNonNullExpression(parent) || ts.isSatisfiesExpression(parent)) {
60776
- componentExpression = parent;
60777
- continue;
60778
- }
60779
- if (ts.isCallExpression(parent) && parent.arguments[0] === componentExpression && isComponentWrapperCall(parent)) {
60780
- componentExpression = parent;
60781
- continue;
60782
- }
60783
- if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) return parent.name.text;
60784
- return node.name?.text ?? null;
60785
- }
60786
- }
60787
- return null;
60788
- };
60789
- const isComponentFunction = (node) => ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node);
60790
- const isDefaultExportedComponent = (record, node, componentName) => {
60791
- if (ts.canHaveModifiers(node) && ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword)) return true;
60792
- return record.sourceFile.statements.some((statement) => ts.isExportAssignment(statement) && ts.isIdentifier(statement.expression) && statement.expression.text === componentName);
60793
- };
60794
- const findEnclosingComponent = (record, diagnostic) => {
60795
- if (!Number.isInteger(diagnostic.line) || diagnostic.line < 1) return null;
60796
- const lineIndex = diagnostic.line - 1;
60797
- const lineStarts = record.sourceFile.getLineStarts();
60798
- const lineStart = lineStarts[lineIndex];
60799
- if (lineStart === void 0) return null;
60800
- const nextLineStart = lineStarts[lineIndex + 1] ?? record.sourceFile.end;
60801
- const lineEnd = Math.max(lineStart, nextLineStart - 1);
60802
- const columnIndex = Number.isInteger(diagnostic.column) ? Math.max(0, diagnostic.column - 1) : 0;
60803
- const diagnosticPosition = Math.min(lineStart + columnIndex, lineEnd);
60804
- let component = null;
60805
- let componentWidth = Number.POSITIVE_INFINITY;
60806
- const visit = (node) => {
60807
- if (diagnosticPosition < node.getStart(record.sourceFile) || diagnosticPosition > node.end) return;
60808
- if (isComponentFunction(node)) {
60809
- const name = getFunctionName(node);
60810
- const width = node.end - node.getStart(record.sourceFile);
60811
- if (name !== null && /^[A-Z]/.test(name) && width < componentWidth) {
60812
- component = {
60813
- isDefaultExport: isDefaultExportedComponent(record, node, name),
60814
- name,
60815
- node,
60816
- record
60817
- };
60818
- componentWidth = width;
60819
- }
60820
- }
60821
- ts.forEachChild(node, visit);
60822
- };
60823
- visit(record.sourceFile);
60824
- return component;
60825
- };
60826
- const moduleSpecifierTargetsComponent = (callerRecord, moduleSpecifier, componentRecord) => {
60827
- if (!moduleSpecifier.startsWith(".")) return false;
60828
- const unresolvedPath = path.resolve(path.dirname(callerRecord.absolutePath), moduleSpecifier);
60829
- const specifiedExtension = path.extname(unresolvedPath).toLowerCase();
60830
- const sourcePathWithoutExtension = SOURCE_EXTENSIONS.includes(specifiedExtension) ? unresolvedPath.slice(0, -specifiedExtension.length) : unresolvedPath;
60831
- return [
60832
- unresolvedPath,
60833
- ...SOURCE_EXTENSIONS.map((extension) => `${sourcePathWithoutExtension}${extension}`),
60834
- ...sourcePathWithoutExtension === unresolvedPath ? SOURCE_EXTENSIONS.map((extension) => path.join(unresolvedPath, `index${extension}`)) : []
60835
- ].includes(componentRecord.absolutePath);
60836
- };
60837
- const getComponentTagNames = (record, component) => {
60838
- if (record.absolutePath === component.record.absolutePath) return new Set([component.name]);
60839
- const tagNames = /* @__PURE__ */ new Set();
60840
- for (const statement of record.sourceFile.statements) {
60841
- if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier) || !moduleSpecifierTargetsComponent(record, statement.moduleSpecifier.text, component.record)) continue;
60842
- const importClause = statement.importClause;
60843
- if (component.isDefaultExport && importClause?.name !== void 0) tagNames.add(importClause.name.text);
60844
- const namedBindings = importClause?.namedBindings;
60845
- if (namedBindings !== void 0 && ts.isNamedImports(namedBindings)) {
60846
- for (const element of namedBindings.elements) if ((element.propertyName?.text ?? element.name.text) === component.name) tagNames.add(element.name.text);
60847
- }
60848
- }
60849
- return tagNames;
60850
- };
60851
- const getTransparentCall = (functionNode) => {
60852
- if (functionNode.body === void 0) return null;
60853
- if (!ts.isBlock(functionNode.body)) {
60854
- const expression = unwrapExpression(functionNode.body);
60855
- return ts.isCallExpression(expression) ? expression : null;
60856
- }
60857
- if (functionNode.body.statements.length !== 1) return null;
60858
- const statement = functionNode.body.statements[0];
60859
- if (statement === void 0) return null;
60860
- const expression = ts.isExpressionStatement(statement) || ts.isReturnStatement(statement) ? statement.expression : void 0;
60861
- if (expression === void 0) return null;
60862
- const unwrappedExpression = unwrapExpression(expression);
60863
- return ts.isCallExpression(unwrappedExpression) ? unwrappedExpression : null;
60864
- };
60865
- const resolveTransparentTarget = (functionNode) => {
60866
- const call = getTransparentCall(functionNode);
60867
- if (call === null) return null;
60868
- const target = unwrapExpression(call.expression);
60869
- if (!ts.isIdentifier(target) || call.arguments.length !== functionNode.parameters.length) return null;
60870
- for (const [parameterIndex, parameter] of functionNode.parameters.entries()) {
60871
- const argument = call.arguments[parameterIndex];
60872
- const unwrappedArgument = argument === void 0 ? null : unwrapExpression(argument);
60873
- if (!ts.isIdentifier(parameter.name) || unwrappedArgument === null || !ts.isIdentifier(unwrappedArgument) || unwrappedArgument.text !== parameter.name.text) return null;
60874
- }
60875
- return target.text;
60876
- };
60877
- const getForwardingFunction = (declaration) => {
60878
- if (ts.isFunctionDeclaration(declaration)) return declaration;
60879
- if (!ts.isVariableDeclaration(declaration) || declaration.initializer === void 0) return null;
60880
- const initializer = unwrapExpression(declaration.initializer);
60881
- if (ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer)) return initializer;
60882
- if (ts.isCallExpression(initializer) && getCalleeName(initializer.expression) === "useCallback") {
60883
- const callback = initializer.arguments[0];
60884
- if (callback !== void 0 && (ts.isArrowFunction(callback) || ts.isFunctionExpression(callback))) return callback;
60885
- }
60886
- return null;
60887
- };
60888
- const getDeclaredBindingName = (node) => {
60889
- 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;
60890
- if (ts.isImportClause(node)) return node.name?.text ?? null;
60891
- if (ts.isImportSpecifier(node) || ts.isNamespaceImport(node)) return node.name.text;
60892
- return null;
60893
- };
60894
- const findBindingScope = (node) => {
60895
- let currentNode = node;
60896
- while (currentNode !== void 0) {
60897
- if (ts.isParameter(currentNode) && ts.isFunctionLike(currentNode.parent)) return currentNode.parent;
60898
- if (ts.isBlock(currentNode) || ts.isModuleBlock(currentNode) || ts.isSourceFile(currentNode)) return currentNode;
60899
- currentNode = currentNode.parent;
60900
- }
60901
- return node.getSourceFile();
60902
- };
60903
- const findBindingDeclaration = (record, binding) => {
60904
- const usagePosition = binding.getStart(record.sourceFile);
60905
- const candidates = [];
60906
- const visit = (node) => {
60907
- if (getDeclaredBindingName(node) === binding.text) {
60908
- const scope = findBindingScope(node);
60909
- const isVisibleScope = usagePosition >= scope.getStart(record.sourceFile) && usagePosition <= scope.end;
60910
- 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;
60911
- if (isVisibleScope && isVisibleDeclaration) candidates.push({
60912
- declaration: node,
60913
- scope
60914
- });
60915
- }
60916
- ts.forEachChild(node, visit);
60917
- };
60918
- visit(record.sourceFile);
60919
- let nearestCandidate = null;
60920
- let nearestScopeWidth = Number.POSITIVE_INFINITY;
60921
- let isNearestScopeAmbiguous = false;
60922
- for (const candidate of candidates) {
60923
- const scopeWidth = candidate.scope.end - candidate.scope.getStart(record.sourceFile);
60924
- if (scopeWidth < nearestScopeWidth) {
60925
- nearestCandidate = candidate;
60926
- nearestScopeWidth = scopeWidth;
60927
- isNearestScopeAmbiguous = false;
60928
- } else if (scopeWidth === nearestScopeWidth) isNearestScopeAmbiguous = true;
60929
- }
60930
- if (isNearestScopeAmbiguous) return null;
60931
- const declaration = nearestCandidate?.declaration;
60932
- return declaration !== void 0 && (ts.isVariableDeclaration(declaration) || ts.isFunctionDeclaration(declaration)) ? declaration : null;
60933
- };
60934
- const resolveHandlerBinding = (record, binding) => {
60935
- const declaration = findBindingDeclaration(record, binding);
60936
- if (declaration === null) return binding.text;
60937
- const forwardingFunction = getForwardingFunction(declaration);
60938
- const target = forwardingFunction === null ? null : resolveTransparentTarget(forwardingFunction);
60939
- return target === null || target === binding.text ? binding.text : target;
60940
- };
60941
- const getJsxTagName = (node) => ts.isIdentifier(node.tagName) ? node.tagName.text : null;
60942
- const getHandlerBinding = (node, propName) => {
60943
- for (const property of node.attributes.properties) {
60944
- if (!ts.isJsxAttribute(property) || property.name.getText() !== propName) continue;
60945
- const initializer = property.initializer;
60946
- if (initializer === void 0 || !ts.isJsxExpression(initializer)) return null;
60947
- if (initializer.expression === void 0) return null;
60948
- const expression = unwrapExpression(initializer.expression);
60949
- return ts.isIdentifier(expression) ? expression : null;
60950
- }
60951
- return null;
60952
- };
60953
- const getForwardedHandlerAliases = (rootDirectory, component, propNames, state) => {
60954
- const cacheKey = `${component.record.filePath}\0${component.name}\0${[...propNames].sort().join("\0")}`;
60955
- const cachedAliases = state.aliasesByComponent.get(cacheKey);
60956
- if (cachedAliases !== void 0) return cachedAliases;
60957
- const bindingsByPropName = /* @__PURE__ */ new Map();
60958
- const unresolvedPropNames = /* @__PURE__ */ new Set();
60959
- let callsiteCount = 0;
60960
- for (const record of listSourceRecords(rootDirectory, state)) {
60961
- const tagNames = getComponentTagNames(record, component);
60962
- if (tagNames.size === 0) continue;
60963
- const visit = (node) => {
60964
- if (record === component.record && node === component.node) return;
60965
- if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
60966
- const tagName = getJsxTagName(node);
60967
- if (tagName !== null && tagNames.has(tagName)) {
60968
- callsiteCount += 1;
60969
- for (const propName of propNames) {
60970
- const binding = getHandlerBinding(node, propName);
60971
- if (binding === null) {
60972
- unresolvedPropNames.add(propName);
60973
- continue;
60974
- }
60975
- const bindings = bindingsByPropName.get(propName) ?? /* @__PURE__ */ new Set();
60976
- bindings.add(resolveHandlerBinding(record, binding));
60977
- bindingsByPropName.set(propName, bindings);
60978
- }
60979
- }
60980
- }
60981
- ts.forEachChild(node, visit);
60982
- };
60983
- visit(record.sourceFile);
60984
- }
60985
- const aliases = /* @__PURE__ */ new Map();
60986
- if (callsiteCount > 0) for (const [propName, bindings] of bindingsByPropName) {
60987
- if (bindings.size !== 1 || unresolvedPropNames.has(propName)) continue;
60988
- const [bindingName] = bindings;
60989
- if (bindingName !== void 0) aliases.set(propName, bindingName);
60990
- }
60991
- state.aliasesByComponent.set(cacheKey, aliases);
60992
- return aliases;
60993
- };
60994
- const normalizeForwardedHandlers = (evidence, aliases) => {
60995
- let normalizedEvidence = evidence;
60996
- for (const [propName, bindingName] of aliases) normalizedEvidence = normalizedEvidence.replace(new RegExp(`\\{\\s*${propName}\\s*\\}`, "g"), `{${bindingName}}`).replace(new RegExp(`=>\\s*${propName}\\s*\\(`, "g"), `=> ${bindingName}(`);
60997
- return normalizedEvidence;
60998
- };
60999
- const createDiagnosticEvidenceReader = (rootDirectory, options = {}) => {
61000
- const state = {
61001
- aliasesByComponent: /* @__PURE__ */ new Map(),
61002
- recordByFilePath: /* @__PURE__ */ new Map(),
61003
- sourceRecords: null
61004
- };
61005
- return (diagnostic) => {
61006
- const record = readSourceRecord(rootDirectory, diagnostic.filePath, state);
61007
- if (record === null || !Number.isInteger(diagnostic.line)) return null;
61008
- const sourceLines = record.sourceText.split(/\r?\n/);
61009
- const startLineIndex = Math.max(0, diagnostic.line - 1);
61010
- const endLineIndex = Math.max(startLineIndex, (diagnostic.endLine ?? diagnostic.line) - 1);
61011
- const evidence = sourceLines.slice(startLineIndex, endLineIndex + 1).join("\n");
61012
- if (!options.resolveForwardedHandlers) return evidence;
61013
- const propNames = new Set(evidence.match(/\bon[A-Z]\w*\b/g) ?? []);
61014
- if (propNames.size === 0) return evidence;
61015
- const component = findEnclosingComponent(record, diagnostic);
61016
- if (component === null) return evidence;
61017
- return normalizeForwardedHandlers(evidence, getForwardedHandlerAliases(rootDirectory, component, propNames, state));
61018
- };
61019
- };
61020
- //#endregion
61021
60404
  //#region src/cli/utils/build-no-score-message.ts
61022
60405
  const ENTERPRISE_CONTACT_HINT = `Want something custom to your company? Contact us at ${ENTERPRISE_CONTACT_URL}.`;
61023
60406
  const buildNoScoreMessage = (isScoreDisabled) => {
@@ -62261,8 +61644,6 @@ const runBaselineComparison = async (params) => {
62261
61644
  directory: params.directory,
62262
61645
  ref: params.baselineRef,
62263
61646
  files: params.options.includePaths,
62264
- baseFiles: params.baseFiles,
62265
- headFiles: params.headFiles,
62266
61647
  tempDirectory
62267
61648
  }).catch((error) => {
62268
61649
  rmSync(tempDirectory, {
@@ -62271,24 +61652,7 @@ const runBaselineComparison = async (params) => {
62271
61652
  });
62272
61653
  throw error;
62273
61654
  });
62274
- if (snapshot === null) {
62275
- rmSync(tempDirectory, {
62276
- recursive: true,
62277
- force: true
62278
- });
62279
- return null;
62280
- }
62281
61655
  try {
62282
- if (!snapshot.isComplete) return null;
62283
- const analyzedHeadFiles = new Set(params.headAnalyzedFiles.map(toForwardSlashes));
62284
- const baseFiles = new Set(snapshot.baseFiles.map(toForwardSlashes));
62285
- const trackedHeadFiles = new Set(snapshot.headFiles.map(toForwardSlashes));
62286
- const expectedHeadFiles = new Set(trackedHeadFiles);
62287
- for (const filePath of params.options.includePaths) {
62288
- const normalizedFilePath = toForwardSlashes(filePath);
62289
- if (!baseFiles.has(normalizedFilePath)) expectedHeadFiles.add(normalizedFilePath);
62290
- }
62291
- if (filterSourceFiles([...expectedHeadFiles]).some((filePath) => !analyzedHeadFiles.has(filePath))) return null;
62292
61656
  const baseLayers = buildRuntimeLayers({
62293
61657
  directory: snapshot.tempDirectory,
62294
61658
  hasConfigOverride: true,
@@ -62304,7 +61668,7 @@ const runBaselineComparison = async (params) => {
62304
61668
  });
62305
61669
  const baseOutput = await runPromise(restoreLegacyThrow(runInspect({
62306
61670
  directory: snapshot.tempDirectory,
62307
- includePaths: snapshot.materializedFiles,
61671
+ includePaths: params.options.includePaths,
62308
61672
  customRulesOnly: params.options.customRulesOnly,
62309
61673
  respectInlineDisables: params.options.respectInlineDisables,
62310
61674
  warnings: params.options.warnings,
@@ -62321,22 +61685,18 @@ const runBaselineComparison = async (params) => {
62321
61685
  deadlineEpochMs: params.deadlineEpochMs ?? void 0
62322
61686
  }, {}).pipe(provide(baseLayers), provideService$2(PerFileLintCacheEnabled, false), provideService$2(SidecarLintCacheEnabled, false), provideService$2(Console, silentConsole))));
62323
61687
  if (baseOutput.didLintFail || countIncompleteLintFiles(baseOutput.lintPartialFailures) > 0) return null;
62324
- const hasUnscannedUntrackedSourceFiles = filterSourceFiles(snapshot.untrackedFiles.map(toForwardSlashes)).some((filePath) => !analyzedHeadFiles.has(filePath));
62325
61688
  const delta = computeDiagnosticDelta({
62326
61689
  headDiagnostics: params.headDiagnostics,
62327
61690
  baseDiagnostics: baseOutput.diagnostics,
62328
61691
  readHeadLine: createSourceLineReader(params.directory),
62329
- readBaseLine: createSourceLineReader(snapshot.tempDirectory),
62330
- readHeadEvidence: createDiagnosticEvidenceReader(params.directory, { resolveForwardedHandlers: true }),
62331
- readBaseEvidence: createDiagnosticEvidenceReader(snapshot.tempDirectory)
61692
+ readBaseLine: createSourceLineReader(snapshot.tempDirectory)
62332
61693
  });
62333
61694
  return {
62334
61695
  displayDiagnostics: delta.newDiagnostics,
62335
61696
  baselineDelta: {
62336
61697
  baseRef: params.baselineRef,
62337
- fixedCount: hasUnscannedUntrackedSourceFiles ? 0 : delta.fixedCount,
62338
- baseTotalCount: baseOutput.diagnostics.length,
62339
- crossFileMatchCount: delta.crossFileMatchCount
61698
+ fixedCount: delta.fixedCount,
61699
+ baseTotalCount: baseOutput.diagnostics.length
62340
61700
  }
62341
61701
  };
62342
61702
  } finally {
@@ -62443,9 +61803,6 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
62443
61803
  headDiagnostics: output.diagnostics,
62444
61804
  resolvedNodeBinaryPath,
62445
61805
  baselineRef: options.baseline.ref,
62446
- baseFiles: options.baseline.baseFiles,
62447
- headFiles: options.baseline.headFiles,
62448
- headAnalyzedFiles: output.analyzedFiles,
62449
61806
  deadlineEpochMs
62450
61807
  });
62451
61808
  if (comparison) {
@@ -64730,25 +64087,20 @@ const resolveProjectRelativeDirectory = (rootDirectory, projectDirectory) => {
64730
64087
  return relativeProjectDirectory;
64731
64088
  };
64732
64089
  //#endregion
64733
- //#region src/cli/utils/resolve-project-source-file-paths.ts
64734
- const resolveProjectSourceFilePaths = (rootDirectory, projectDirectory, filePaths) => {
64090
+ //#region src/cli/utils/resolve-project-diff-include-paths.ts
64091
+ const resolveProjectDiffIncludePaths = (rootDirectory, projectDirectory, diffInfo) => {
64735
64092
  const relativeProjectDirectory = resolveProjectRelativeDirectory(rootDirectory, projectDirectory);
64736
64093
  if (relativeProjectDirectory === null) return [];
64737
- const sourceFilePaths = filterSourceFiles([...filePaths]);
64738
- if (relativeProjectDirectory.length === 0) return sourceFilePaths;
64094
+ const changedSourceFiles = filterSourceFiles(diffInfo.changedFiles);
64095
+ if (relativeProjectDirectory.length === 0) return changedSourceFiles;
64739
64096
  const projectPrefix = `${relativeProjectDirectory}/`;
64740
- return sourceFilePaths.flatMap((filePath) => {
64097
+ return changedSourceFiles.flatMap((filePath) => {
64741
64098
  const normalizedFilePath = toForwardSlashes(filePath);
64742
64099
  if (!normalizedFilePath.startsWith(projectPrefix)) return [];
64743
64100
  const projectRelativePath = normalizedFilePath.slice(projectPrefix.length);
64744
64101
  return projectRelativePath.length > 0 ? [projectRelativePath] : [];
64745
64102
  });
64746
64103
  };
64747
- //#endregion
64748
- //#region src/cli/utils/resolve-project-diff-include-paths.ts
64749
- const resolveProjectDiffIncludePaths = (rootDirectory, projectDirectory, diffInfo) => {
64750
- return resolveProjectSourceFilePaths(rootDirectory, projectDirectory, diffInfo.changedFiles);
64751
- };
64752
64104
  /**
64753
64105
  * Re-keys repo-relative changed line ranges (from `getChangedLineRanges`) to
64754
64106
  * the scanned project, mirroring `resolveProjectDiffIncludePaths`'s boundary
@@ -65287,7 +64639,6 @@ const inspectAction = async (directory, flags) => {
65287
64639
  const isDiffMode = scope !== "full";
65288
64640
  const comparisonBaseRef = isDiffMode && diffInfo && !diffInfo.isCurrentChanges ? diffInfo.baseSha ? await resolveMergeBaseRef(resolvedDirectory, diffInfo.baseSha) : diffInfo.diffBaseRef ?? await resolveMergeBaseRef(resolvedDirectory, diffInfo.baseBranch) : null;
65289
64641
  const baselineRef = scope === "changed" ? comparisonBaseRef : null;
65290
- const baselineDiffPlan = baselineRef === null ? null : await getBaselineDiffPlan(resolvedDirectory, baselineRef);
65291
64642
  const linesBaseRef = diffInfo?.isCurrentChanges ? "HEAD" : comparisonBaseRef;
65292
64643
  const changedLineRanges = scope === "lines" && diffInfo !== null && (diffInfo.isCurrentChanges || linesBaseRef !== null) && diffInfo !== null ? await getChangedLineRanges({
65293
64644
  directory: resolvedDirectory,
@@ -65318,13 +64669,10 @@ const inspectAction = async (directory, flags) => {
65318
64669
  const supplyChainEnabled = flags.supplyChain ?? projectConfig?.supplyChain?.enabled !== false;
65319
64670
  let includePaths;
65320
64671
  let supplyChainManifestChanged = false;
65321
- const projectBaselineBaseFiles = baselineDiffPlan === null ? null : resolveProjectSourceFilePaths(resolvedDirectory, scanDirectory, baselineDiffPlan.baseFiles);
65322
- const projectBaselineHeadFiles = baselineDiffPlan === null ? null : resolveProjectSourceFilePaths(resolvedDirectory, scanDirectory, baselineDiffPlan.headFiles);
65323
64672
  if (isDiffMode) {
65324
64673
  const changedSourceFiles = diffInfo === null ? [] : resolveProjectDiffIncludePaths(resolvedDirectory, scanDirectory, diffInfo);
65325
64674
  supplyChainManifestChanged = supplyChainEnabled && diffInfo !== null && projectManifestChanged(resolvedDirectory, scanDirectory, diffInfo);
65326
- const hasBaselineOnlyFiles = (projectBaselineBaseFiles?.length ?? 0) > 0;
65327
- if (changedSourceFiles.length === 0 && !supplyChainManifestChanged && !hasBaselineOnlyFiles) {
64675
+ if (changedSourceFiles.length === 0 && !supplyChainManifestChanged) {
65328
64676
  if (!isQuiet) {
65329
64677
  cliLogger.dim(`No changed source files in ${scanDirectory}, skipping.`);
65330
64678
  cliLogger.break();
@@ -65332,7 +64680,6 @@ const inspectAction = async (directory, flags) => {
65332
64680
  return null;
65333
64681
  }
65334
64682
  includePaths = [...changedSourceFiles];
65335
- if (includePaths.length === 0 && hasBaselineOnlyFiles) includePaths.push(...projectBaselineBaseFiles ?? []);
65336
64683
  if (supplyChainManifestChanged) includePaths.push("package.json");
65337
64684
  }
65338
64685
  if (!isQuiet && !isMultiProject) cliLogger.dim(" ");
@@ -65344,11 +64691,7 @@ const inspectAction = async (directory, flags) => {
65344
64691
  configSourceDirectory: projectConfigSourceDirectory ?? void 0,
65345
64692
  suppressRendering: isMultiProject,
65346
64693
  concurrentScan: isMultiProject,
65347
- baseline: baselineRef !== null && projectBaselineBaseFiles !== null && projectBaselineHeadFiles !== null ? {
65348
- ref: baselineRef,
65349
- baseFiles: projectBaselineBaseFiles,
65350
- headFiles: projectBaselineHeadFiles
65351
- } : void 0,
64694
+ baseline: baselineRef ? { ref: baselineRef } : void 0,
65352
64695
  changedLineRanges: scope === "lines" && changedLineRanges !== null ? resolveProjectChangedLineRanges(resolvedDirectory, scanDirectory, changedLineRanges) : void 0,
65353
64696
  supplyChainManifestChanged
65354
64697
  });
@@ -66548,4 +65891,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
66548
65891
  export {};
66549
65892
 
66550
65893
  //# sourceMappingURL=cli.js.map
66551
- //# debugId=81bdc95e-12f2-565f-a05c-7b8a60a98f81
65894
+ //# debugId=9e32582f-b296-5216-a028-7cc19ed83931