react-doctor 0.7.6-dev.82e10cd → 0.7.6-dev.88ef7fd

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -9654,6 +9654,7 @@ interface DiagnoseOptions {
9654
9654
  /** See `ReactDoctorConfig.deadCode`. Ignored in diff mode. */
9655
9655
  deadCode?: boolean;
9656
9656
  verbose?: boolean;
9657
+ /** Restrict linting to these supported JS/TS source files. */
9657
9658
  includePaths?: string[];
9658
9659
  /**
9659
9660
  * Per-call override for `ReactDoctorConfig.respectInlineDisables`.
@@ -9915,9 +9916,9 @@ interface JsonReportProjectEntry {
9915
9916
  skippedCheckReasons?: Record<string, string>;
9916
9917
  /**
9917
9918
  * Number of source files this scan's linter examined. In diff / changed
9918
- * mode it's the count of changed React-eligible files (`.tsx`/`.jsx` plus
9919
- * framework entry files); in a full scan it's the whole source tree. `0`
9920
- * in a diff scan means the changed files held nothing React Doctor lints —
9919
+ * mode it's the count of changed supported JS/TS source files; in a full
9920
+ * scan it's the whole source tree. `0` in a diff scan means the changed
9921
+ * files held nothing React Doctor lints —
9921
9922
  * the GitHub Action reads that as "nothing to report" (skips the PR comment;
9922
9923
  * the commit status says "skipped"). Optional: absent on reports from
9923
9924
  * constructors that don't track it (e.g. `toJsonReport`).
@@ -10255,7 +10256,7 @@ declare const buildJsonReport: (input: BuildJsonReportInput) => JsonReportV3$1;
10255
10256
  * render diff-base mistakes (`GitBaseBranchInvalid` /
10256
10257
  * `GitBaseBranchMissing`) as clean user errors instead of crashes.
10257
10258
  */
10258
- declare const getDiffInfo: (directory: string, explicitBaseBranch?: string) => Promise<DiffInfo | null>;
10259
+ declare const getDiffInfo: (directory: string, explicitBaseBranch?: string, includeUntracked?: boolean) => Promise<DiffInfo | null>;
10259
10260
  declare const filterSourceFiles: (filePaths: string[]) => string[];
10260
10261
  /**
10261
10262
  * Programmatic façade over `Git.changedLineRanges` (the `lines` scope). Diffs
package/dist/index.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]="7a10d23c-04fd-53e1-a623-a3dc5d6d0830")}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]="2aa6fc3c-96ab-5a4c-8a52-e74d27fb4b5a")}catch(e){}}();
3
3
  import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
4
4
  import { createRequire } from "node:module";
5
5
  import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
@@ -32930,7 +32930,6 @@ const IGNORED_DIRECTORIES = new Set([
32930
32930
  "out",
32931
32931
  "storybook-static"
32932
32932
  ]);
32933
- const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
32934
32933
  const MILLISECONDS_PER_SECOND = 1e3;
32935
32934
  const SCORE_API_URL = "https://www.react.doctor/api/score";
32936
32935
  const FETCH_TIMEOUT_MS = 1e4;
@@ -33143,13 +33142,15 @@ const listSourceFilesViaFilesystem = (rootDirectory) => {
33143
33142
  const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort());
33144
33143
  const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
33145
33144
  const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
33145
+ const UTF8_BOM_CHARACTER = "";
33146
+ const stripUtf8Bom = (content) => content.startsWith(UTF8_BOM_CHARACTER) ? content.slice(1) : content;
33146
33147
  const cachedPackageJsons = /* @__PURE__ */ new Map();
33147
33148
  const clearPackageJsonCache = () => {
33148
33149
  cachedPackageJsons.clear();
33149
33150
  };
33150
33151
  const readPackageJsonUncached = (packageJsonPath) => {
33151
33152
  try {
33152
- return JSON.parse(NFS.readFileSync(packageJsonPath, "utf-8"));
33153
+ return JSON.parse(stripUtf8Bom(NFS.readFileSync(packageJsonPath, "utf-8")));
33153
33154
  } catch (error) {
33154
33155
  if (error instanceof SyntaxError) return {};
33155
33156
  if (isErrnoException(error)) {
@@ -36790,7 +36791,6 @@ const PNPM_WORKSPACE_FILE = "pnpm-workspace.yaml";
36790
36791
  const PNPM_LOCKFILE = "pnpm-lock.yaml";
36791
36792
  const PACKAGE_JSON_FILE = "package.json";
36792
36793
  const PNPM_HARDENING_RULE_KEY = "require-pnpm-hardening";
36793
- const UTF8_BOM_CHAR = "";
36794
36794
  const HARDENING_SETTING_KEYS = new Set([
36795
36795
  "minimumReleaseAge",
36796
36796
  "blockExoticSubdeps",
@@ -36815,12 +36815,11 @@ const stripInlineComment = (rawValue) => {
36815
36815
  return rawValue;
36816
36816
  };
36817
36817
  const unquote = (rawValue) => rawValue.replace(/^["']|["']$/g, "");
36818
- const stripBom = (rawContent) => rawContent.startsWith(UTF8_BOM_CHAR) ? rawContent.slice(1) : rawContent;
36819
36818
  const parseHardeningSettings = (content) => {
36820
36819
  let minimumReleaseAge = null;
36821
36820
  let blockExoticSubdeps = null;
36822
36821
  let trustPolicy = null;
36823
- const lines = stripBom(content).split(/\r?\n/);
36822
+ const lines = stripUtf8Bom(content).split(/\r?\n/);
36824
36823
  for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
36825
36824
  const lineText = lines[lineIndex];
36826
36825
  if (lineText === void 0) continue;
@@ -36854,7 +36853,7 @@ const isPnpmManagedProject = (rootDirectory) => {
36854
36853
  const packageJsonPath = Path.join(rootDirectory, PACKAGE_JSON_FILE);
36855
36854
  if (!isFile(packageJsonPath)) return false;
36856
36855
  try {
36857
- const packageJsonRaw = NFS.readFileSync(packageJsonPath, "utf-8");
36856
+ const packageJsonRaw = stripUtf8Bom(NFS.readFileSync(packageJsonPath, "utf-8"));
36858
36857
  const packageJson = JSON.parse(packageJsonRaw);
36859
36858
  if (packageJson !== null && typeof packageJson === "object" && "packageManager" in packageJson && typeof packageJson.packageManager === "string" && packageJson.packageManager.startsWith("pnpm@")) return true;
36860
36859
  } catch {
@@ -37516,9 +37515,7 @@ const highlighter = {
37516
37515
  gray: import_picocolors.default.gray,
37517
37516
  bold: import_picocolors.default.bold
37518
37517
  };
37519
- const NEXT_ENTRY_FILE_PATTERN = /^(?:\.\/)?(?:src\/)?(?:middleware|proxy)\.(?:tsx?|jsx?|mts|mjs)$/;
37520
- const shouldIncludeExplicitLintPath = (filePath, project) => JSX_FILE_PATTERN.test(filePath) || project?.framework === "nextjs" && NEXT_ENTRY_FILE_PATTERN.test(filePath);
37521
- const computeExplicitLintIncludePaths = (includePaths, project) => includePaths.length > 0 ? includePaths.filter((filePath) => shouldIncludeExplicitLintPath(filePath, project)) : void 0;
37518
+ const computeExplicitLintIncludePaths = (includePaths) => includePaths.length > 0 ? includePaths.filter(isLintableSourceFile) : void 0;
37522
37519
  const LINGUIST_ATTRIBUTE_PATTERN = /^linguist-(?:vendored|generated)(?:=([a-zA-Z0-9]+))?$/i;
37523
37520
  const FALSY_VALUES = new Set([
37524
37521
  "false",
@@ -38360,11 +38357,11 @@ const resolveDeadCodeTimeout = (input) => {
38360
38357
  phaseTimeoutMs: workerTimeoutMs + DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS
38361
38358
  };
38362
38359
  };
38363
- const resolveLintIncludePaths = (rootDirectory, userConfig, project) => {
38360
+ const resolveLintIncludePaths = (rootDirectory, userConfig) => {
38364
38361
  if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) return;
38365
38362
  const ignoredPatterns = compileIgnoredFilePatterns(userConfig);
38366
38363
  return listSourceFiles(rootDirectory).filter((filePath) => {
38367
- if (!shouldIncludeExplicitLintPath(filePath, project)) return false;
38364
+ if (!isLintableSourceFile(filePath)) return false;
38368
38365
  return !isFileIgnoredByPatterns(filePath, rootDirectory, ignoredPatterns);
38369
38366
  });
38370
38367
  };
@@ -38582,6 +38579,7 @@ const parseGithubViewerPermission = (stdout) => {
38582
38579
  return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
38583
38580
  };
38584
38581
  const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
38582
+ const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
38585
38583
  /**
38586
38584
  * `Git` wraps every `git`-via-subprocess call react-doctor makes
38587
38585
  * behind a `Context.Service`. The production layer (`layerNode`)
@@ -38652,6 +38650,14 @@ var Git = class Git extends Service()("react-doctor/Git") {
38652
38650
  args,
38653
38651
  directory
38654
38652
  });
38653
+ const listUntrackedFilePaths = (directory, includePaths = []) => runGit(directory, [
38654
+ "ls-files",
38655
+ "-z",
38656
+ "--others",
38657
+ "--exclude-standard",
38658
+ ...includePaths.length > 0 ? ["--", ...includePaths] : []
38659
+ ]).pipe(map$3((result) => result.status === 0 ? splitNullSeparated(result.stdout) : null));
38660
+ const mergeUntracked = (directory, trackedFilePaths, includeUntracked) => includeUntracked ? listUntrackedFilePaths(directory).pipe(map$3((untracked) => untracked === null ? trackedFilePaths : [...new Set([...trackedFilePaths, ...untracked])])) : succeed$2(trackedFilePaths);
38655
38661
  const currentBranch = (directory) => runGit(directory, [
38656
38662
  "rev-parse",
38657
38663
  "--abbrev-ref",
@@ -38774,7 +38780,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
38774
38780
  githubViewerPermission,
38775
38781
  branchExists,
38776
38782
  mergeBase,
38777
- diffSelection: ({ directory, explicitBaseBranch }) => gen(function* () {
38783
+ diffSelection: ({ directory, explicitBaseBranch, includeUntracked = false }) => gen(function* () {
38778
38784
  if (explicitBaseBranch !== void 0 && explicitBaseBranch.trim().length === 0) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "Diff base branch cannot be empty." }) }));
38779
38785
  if (explicitBaseBranch !== void 0) {
38780
38786
  const range = parseGitDiffRange(explicitBaseBranch);
@@ -38803,7 +38809,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
38803
38809
  "HEAD"
38804
38810
  ]);
38805
38811
  if (uncommitted.status !== 0) return null;
38806
- const files = splitNullSeparated(uncommitted.stdout);
38812
+ const files = yield* mergeUntracked(directory, splitNullSeparated(uncommitted.stdout), includeUntracked);
38807
38813
  if (files.length === 0) return null;
38808
38814
  return {
38809
38815
  currentBranch: resolvedCurrentBranch,
@@ -38833,7 +38839,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
38833
38839
  currentBranch: resolvedCurrentBranch,
38834
38840
  baseBranch,
38835
38841
  diffBaseRef: mergeBaseRef,
38836
- changedFiles: splitNullSeparated(diff.stdout),
38842
+ changedFiles: yield* mergeUntracked(directory, splitNullSeparated(diff.stdout), includeUntracked),
38837
38843
  isCurrentChanges: false
38838
38844
  };
38839
38845
  }).pipe(withSpan("Git.diffSelection")),
@@ -38879,7 +38885,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
38879
38885
  stdout: result.stdout
38880
38886
  };
38881
38887
  }).pipe(withSpan("Git.grep")),
38882
- changedLineRanges: ({ directory, baseRef, cached, files }) => gen(function* () {
38888
+ changedLineRanges: ({ directory, baseRef, cached, files, includeUntracked = false }) => gen(function* () {
38883
38889
  if (files.length === 0) return [];
38884
38890
  if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
38885
38891
  const result = yield* runGit(directory, [
@@ -38893,7 +38899,14 @@ var Git = class Git extends Service()("react-doctor/Git") {
38893
38899
  ...files
38894
38900
  ]);
38895
38901
  if (result.status !== 0) return null;
38896
- return parseChangedLineRanges(result.stdout);
38902
+ const changedLineRanges = parseChangedLineRanges(result.stdout);
38903
+ if (cached || !includeUntracked) return changedLineRanges;
38904
+ const untrackedFilePaths = yield* listUntrackedFilePaths(directory, files);
38905
+ if (untrackedFilePaths === null) return changedLineRanges;
38906
+ return [...changedLineRanges, ...untrackedFilePaths.map((file) => ({
38907
+ file,
38908
+ ranges: [[1, UNTRACKED_FILE_LAST_LINE]]
38909
+ }))];
38897
38910
  }).pipe(catch_$1((error) => error.reason._tag === "GitInvocationFailed" ? succeed$2(null) : fail$4(error)), withSpan("Git.changedLineRanges"))
38898
38911
  });
38899
38912
  })).pipe(provide$2(layer$2.pipe(provide$2(mergeAll$1(layer$1, layer)))));
@@ -39645,6 +39658,12 @@ const mapWithConcurrency = async (items, concurrency, task) => {
39645
39658
  if (errors.length > 0) throw errors[0];
39646
39659
  return results;
39647
39660
  };
39661
+ const lineOfUtf8Offset = (sourceBuffer, utf8Offset) => {
39662
+ let lineNumber = 1;
39663
+ const scanEnd = Math.min(utf8Offset, sourceBuffer.length);
39664
+ for (let byteIndex = 0; byteIndex < scanEnd; byteIndex++) if (sourceBuffer[byteIndex] === 10) lineNumber++;
39665
+ return lineNumber;
39666
+ };
39648
39667
  const REANIMATED_SHARED_VALUE_HINT = "If this is a Reanimated shared value, prefer its React Compiler-compatible `.get()` / `.set()` accessors over `.value` — https://docs.swmansion.com/react-native-reanimated/docs/core/useSharedValue/#react-compiler-support";
39649
39668
  const ACCESSORS_MIN_VERSION = "3.15.0";
39650
39669
  const supportsAccessors = (reanimatedVersion) => {
@@ -40216,13 +40235,6 @@ const findOutermostEnclosingFunctionRange = (sourceFile, targetLine) => {
40216
40235
  visit(sourceFile);
40217
40236
  return foundRange;
40218
40237
  };
40219
- const NEWLINE_BYTE = 10;
40220
- const lineOfUtf8Offset = (sourceBuffer, utf8Offset) => {
40221
- let lineNumber = 1;
40222
- const scanEnd = Math.min(utf8Offset, sourceBuffer.length);
40223
- for (let byteIndex = 0; byteIndex < scanEnd; byteIndex++) if (sourceBuffer[byteIndex] === NEWLINE_BYTE) lineNumber++;
40224
- return lineNumber;
40225
- };
40226
40238
  /**
40227
40239
  * Drops `react-doctor/react-compiler-no-manual-memoization` diagnostics
40228
40240
  * whose enclosing function also carries a `react-hooks-js` (React
@@ -40403,11 +40415,11 @@ const buildRelatedLocations = (labels, filePath) => {
40403
40415
  }
40404
40416
  return related;
40405
40417
  };
40406
- const isOxlintOutput = (value) => {
40407
- if (typeof value !== "object" || value === null) return false;
40408
- const candidate = value;
40409
- return Array.isArray(candidate.diagnostics);
40410
- };
40418
+ const isOxlintSpan = (value) => isRecord(value) && typeof value.offset === "number" && typeof value.length === "number" && typeof value.line === "number" && typeof value.column === "number";
40419
+ const isOxlintLabel = (value) => isRecord(value) && isOxlintSpan(value.span);
40420
+ const isMappableOxlintDiagnostic = (value) => isRecord(value) && typeof value.code === "string" && value.code.length > 0 && typeof value.filename === "string" && value.filename.length > 0 && (value.severity === "warning" || value.severity === "error") && Array.isArray(value.labels) && value.labels.every(isOxlintLabel);
40421
+ const isEngineFailureDiagnostic = (value) => !isRecord(value) || typeof value.filename !== "string" || value.filename.length === 0;
40422
+ const isOxlintOutput = (value) => isRecord(value) && Array.isArray(value.diagnostics);
40411
40423
  /**
40412
40424
  * Parses one oxlint subprocess's stdout into a flat `Diagnostic[]`.
40413
40425
  * Tolerates the leading-notice-line shape oxlint sometimes prints
@@ -40426,23 +40438,59 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
40426
40438
  throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
40427
40439
  }
40428
40440
  if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
40441
+ const engineFailureDiagnostic = parsed.diagnostics.find(isEngineFailureDiagnostic);
40442
+ if (engineFailureDiagnostic !== void 0) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: JSON.stringify(engineFailureDiagnostic).slice(0, 600) }) });
40429
40443
  const minifiedFileCache = /* @__PURE__ */ new Map();
40444
+ const sourceBufferCache = /* @__PURE__ */ new Map();
40445
+ const sourceLinesCache = /* @__PURE__ */ new Map();
40446
+ const resolveAbsolutePath = (filename) => Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
40447
+ const readSourceBuffer = (filename) => {
40448
+ const absolutePath = resolveAbsolutePath(filename);
40449
+ const cached = sourceBufferCache.get(absolutePath);
40450
+ if (cached !== void 0) return cached;
40451
+ let sourceBuffer;
40452
+ try {
40453
+ sourceBuffer = NFS.readFileSync(absolutePath);
40454
+ } catch {
40455
+ sourceBuffer = null;
40456
+ }
40457
+ sourceBufferCache.set(absolutePath, sourceBuffer);
40458
+ return sourceBuffer;
40459
+ };
40460
+ const readSourceLines = (filename) => {
40461
+ const absolutePath = resolveAbsolutePath(filename);
40462
+ const cached = sourceLinesCache.get(absolutePath);
40463
+ if (cached !== void 0) return cached;
40464
+ const sourceBuffer = readSourceBuffer(filename);
40465
+ const sourceLines = sourceBuffer ? sourceBuffer.toString("utf8").split("\n") : null;
40466
+ sourceLinesCache.set(absolutePath, sourceLines);
40467
+ return sourceLines;
40468
+ };
40430
40469
  const isMinifiedDiagnosticFile = (filename) => {
40431
- const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
40470
+ const absolutePath = resolveAbsolutePath(filename);
40432
40471
  const cached = minifiedFileCache.get(absolutePath);
40433
40472
  if (cached !== void 0) return cached;
40434
40473
  const minified = isMinifiedSource(absolutePath);
40435
40474
  minifiedFileCache.set(absolutePath, minified);
40436
40475
  return minified;
40437
40476
  };
40438
- return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => diagnostic.code && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
40477
+ return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => isMappableOxlintDiagnostic(diagnostic) && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
40439
40478
  const { plugin, rule } = parseRuleCode(diagnostic.code);
40440
40479
  const primaryLabel = diagnostic.labels[0];
40441
40480
  const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
40442
40481
  const normalizedFilePath = diagnostic.filename.replaceAll("\\", "/");
40443
40482
  const primarySpan = primaryLabel?.span;
40483
+ const sourceBuffer = primarySpan ? readSourceBuffer(diagnostic.filename) : null;
40444
40484
  const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
40445
40485
  const category = resolveDiagnosticCategory(plugin, rule);
40486
+ const matchByOccurrence = resolveMatchByOccurrence(rule, category);
40487
+ const sourceLines = primarySpan ? readSourceLines(diagnostic.filename) : null;
40488
+ const primaryLineIndex = primarySpan ? primarySpan.line - 1 : -1;
40489
+ const primaryLine = sourceLines?.[primaryLineIndex];
40490
+ const primaryColumnIndex = primarySpan ? primarySpan.column - 1 : -1;
40491
+ const isJsxTagLabel = primaryLine !== void 0 && primaryColumnIndex >= 0 && (primaryLine[primaryColumnIndex] === "<" || primaryLine[primaryColumnIndex - 1] === "<");
40492
+ const jsxOpenerEndLineIndex = sourceLines && isJsxTagLabel ? findJsxOpenerSpan(sourceLines, primaryLineIndex) : null;
40493
+ const primarySpanEndLine = jsxOpenerEndLineIndex !== null ? jsxOpenerEndLineIndex + 1 : primarySpan && sourceBuffer ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset + Math.max(primarySpan.length - 1, 0)) : void 0;
40446
40494
  return {
40447
40495
  filePath: normalizedFilePath,
40448
40496
  plugin,
@@ -40456,10 +40504,11 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
40456
40504
  column: primarySpan?.column ?? 0,
40457
40505
  ...primarySpan ? {
40458
40506
  offset: primarySpan.offset,
40459
- length: primarySpan.length
40507
+ length: primarySpan.length,
40508
+ ...primarySpanEndLine !== void 0 ? { endLine: primarySpanEndLine } : {}
40460
40509
  } : {},
40461
40510
  category,
40462
- ...resolveMatchByOccurrence(rule, category) ? { matchByOccurrence: true } : {},
40511
+ ...matchByOccurrence ? { matchByOccurrence: true } : {},
40463
40512
  ...relatedLocations.length > 0 ? { relatedLocations } : {}
40464
40513
  };
40465
40514
  }), rootDirectory);
@@ -42246,7 +42295,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
42246
42295
  directory: scanDirectory,
42247
42296
  repo
42248
42297
  }).pipe(orElseSucceed(() => null)) : succeed$2(null));
42249
- const lintIncludePaths = (input.skipJsxIncludeFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths], project)) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config, project);
42298
+ const lintIncludePaths = (input.skipExplicitIncludePathFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths])) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config);
42250
42299
  const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
42251
42300
  const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
42252
42301
  const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
@@ -42917,10 +42966,11 @@ const buildSkippedChecks = (input) => {
42917
42966
  * render diff-base mistakes (`GitBaseBranchInvalid` /
42918
42967
  * `GitBaseBranchMissing`) as clean user errors instead of crashes.
42919
42968
  */
42920
- const getDiffInfo = (directory, explicitBaseBranch) => runPromise(gen(function* () {
42969
+ const getDiffInfo = (directory, explicitBaseBranch, includeUntracked) => runPromise(gen(function* () {
42921
42970
  const selection = yield* (yield* Git).diffSelection({
42922
42971
  directory,
42923
- explicitBaseBranch
42972
+ explicitBaseBranch,
42973
+ includeUntracked
42924
42974
  });
42925
42975
  if (selection === null) return null;
42926
42976
  return {
@@ -43210,4 +43260,4 @@ const toJsonReport = (result, options) => buildJsonReport({
43210
43260
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
43211
43261
 
43212
43262
  //# sourceMappingURL=index.js.map
43213
- //# debugId=7a10d23c-04fd-53e1-a623-a3dc5d6d0830
43263
+ //# debugId=2aa6fc3c-96ab-5a4c-8a52-e74d27fb4b5a
package/dist/lsp.js CHANGED
@@ -32959,7 +32959,6 @@ const IGNORED_DIRECTORIES = new Set([
32959
32959
  "out",
32960
32960
  "storybook-static"
32961
32961
  ]);
32962
- const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
32963
32962
  const MILLISECONDS_PER_SECOND = 1e3;
32964
32963
  const SCORE_API_URL = "https://www.react.doctor/api/score";
32965
32964
  const FETCH_TIMEOUT_MS = 1e4;
@@ -33195,13 +33194,15 @@ const listSourceFilesViaFilesystem = (rootDirectory) => {
33195
33194
  const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort());
33196
33195
  const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
33197
33196
  const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
33197
+ const UTF8_BOM_CHARACTER = "";
33198
+ const stripUtf8Bom = (content) => content.startsWith(UTF8_BOM_CHARACTER) ? content.slice(1) : content;
33198
33199
  const cachedPackageJsons = /* @__PURE__ */ new Map();
33199
33200
  const clearPackageJsonCache = () => {
33200
33201
  cachedPackageJsons.clear();
33201
33202
  };
33202
33203
  const readPackageJsonUncached = (packageJsonPath) => {
33203
33204
  try {
33204
- return JSON.parse(NFS.readFileSync(packageJsonPath, "utf-8"));
33205
+ return JSON.parse(stripUtf8Bom(NFS.readFileSync(packageJsonPath, "utf-8")));
33205
33206
  } catch (error) {
33206
33207
  if (error instanceof SyntaxError) return {};
33207
33208
  if (isErrnoException(error)) {
@@ -36768,7 +36769,6 @@ const PNPM_WORKSPACE_FILE = "pnpm-workspace.yaml";
36768
36769
  const PNPM_LOCKFILE = "pnpm-lock.yaml";
36769
36770
  const PACKAGE_JSON_FILE = "package.json";
36770
36771
  const PNPM_HARDENING_RULE_KEY = "require-pnpm-hardening";
36771
- const UTF8_BOM_CHAR = "";
36772
36772
  const HARDENING_SETTING_KEYS = new Set([
36773
36773
  "minimumReleaseAge",
36774
36774
  "blockExoticSubdeps",
@@ -36793,12 +36793,11 @@ const stripInlineComment = (rawValue) => {
36793
36793
  return rawValue;
36794
36794
  };
36795
36795
  const unquote = (rawValue) => rawValue.replace(/^["']|["']$/g, "");
36796
- const stripBom = (rawContent) => rawContent.startsWith(UTF8_BOM_CHAR) ? rawContent.slice(1) : rawContent;
36797
36796
  const parseHardeningSettings = (content) => {
36798
36797
  let minimumReleaseAge = null;
36799
36798
  let blockExoticSubdeps = null;
36800
36799
  let trustPolicy = null;
36801
- const lines = stripBom(content).split(/\r?\n/);
36800
+ const lines = stripUtf8Bom(content).split(/\r?\n/);
36802
36801
  for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
36803
36802
  const lineText = lines[lineIndex];
36804
36803
  if (lineText === void 0) continue;
@@ -36832,7 +36831,7 @@ const isPnpmManagedProject = (rootDirectory) => {
36832
36831
  const packageJsonPath = Path.join(rootDirectory, PACKAGE_JSON_FILE);
36833
36832
  if (!isFile(packageJsonPath)) return false;
36834
36833
  try {
36835
- const packageJsonRaw = NFS.readFileSync(packageJsonPath, "utf-8");
36834
+ const packageJsonRaw = stripUtf8Bom(NFS.readFileSync(packageJsonPath, "utf-8"));
36836
36835
  const packageJson = JSON.parse(packageJsonRaw);
36837
36836
  if (packageJson !== null && typeof packageJson === "object" && "packageManager" in packageJson && typeof packageJson.packageManager === "string" && packageJson.packageManager.startsWith("pnpm@")) return true;
36838
36837
  } catch {
@@ -37494,9 +37493,7 @@ const highlighter = {
37494
37493
  gray: import_picocolors.default.gray,
37495
37494
  bold: import_picocolors.default.bold
37496
37495
  };
37497
- const NEXT_ENTRY_FILE_PATTERN = /^(?:\.\/)?(?:src\/)?(?:middleware|proxy)\.(?:tsx?|jsx?|mts|mjs)$/;
37498
- const shouldIncludeExplicitLintPath = (filePath, project) => JSX_FILE_PATTERN.test(filePath) || project?.framework === "nextjs" && NEXT_ENTRY_FILE_PATTERN.test(filePath);
37499
- const computeExplicitLintIncludePaths = (includePaths, project) => includePaths.length > 0 ? includePaths.filter((filePath) => shouldIncludeExplicitLintPath(filePath, project)) : void 0;
37496
+ const computeExplicitLintIncludePaths = (includePaths) => includePaths.length > 0 ? includePaths.filter(isLintableSourceFile) : void 0;
37500
37497
  const LINGUIST_ATTRIBUTE_PATTERN = /^linguist-(?:vendored|generated)(?:=([a-zA-Z0-9]+))?$/i;
37501
37498
  const FALSY_VALUES = new Set([
37502
37499
  "false",
@@ -38338,11 +38335,11 @@ const resolveDeadCodeTimeout = (input) => {
38338
38335
  phaseTimeoutMs: workerTimeoutMs + DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS
38339
38336
  };
38340
38337
  };
38341
- const resolveLintIncludePaths = (rootDirectory, userConfig, project) => {
38338
+ const resolveLintIncludePaths = (rootDirectory, userConfig) => {
38342
38339
  if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) return;
38343
38340
  const ignoredPatterns = compileIgnoredFilePatterns(userConfig);
38344
38341
  return listSourceFiles(rootDirectory).filter((filePath) => {
38345
- if (!shouldIncludeExplicitLintPath(filePath, project)) return false;
38342
+ if (!isLintableSourceFile(filePath)) return false;
38346
38343
  return !isFileIgnoredByPatterns(filePath, rootDirectory, ignoredPatterns);
38347
38344
  });
38348
38345
  };
@@ -38560,6 +38557,7 @@ const parseGithubViewerPermission = (stdout) => {
38560
38557
  return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
38561
38558
  };
38562
38559
  const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
38560
+ const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
38563
38561
  /**
38564
38562
  * `Git` wraps every `git`-via-subprocess call react-doctor makes
38565
38563
  * behind a `Context.Service`. The production layer (`layerNode`)
@@ -38630,6 +38628,14 @@ var Git = class Git extends Service()("react-doctor/Git") {
38630
38628
  args,
38631
38629
  directory
38632
38630
  });
38631
+ const listUntrackedFilePaths = (directory, includePaths = []) => runGit(directory, [
38632
+ "ls-files",
38633
+ "-z",
38634
+ "--others",
38635
+ "--exclude-standard",
38636
+ ...includePaths.length > 0 ? ["--", ...includePaths] : []
38637
+ ]).pipe(map$3((result) => result.status === 0 ? splitNullSeparated(result.stdout) : null));
38638
+ const mergeUntracked = (directory, trackedFilePaths, includeUntracked) => includeUntracked ? listUntrackedFilePaths(directory).pipe(map$3((untracked) => untracked === null ? trackedFilePaths : [...new Set([...trackedFilePaths, ...untracked])])) : succeed$2(trackedFilePaths);
38633
38639
  const currentBranch = (directory) => runGit(directory, [
38634
38640
  "rev-parse",
38635
38641
  "--abbrev-ref",
@@ -38752,7 +38758,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
38752
38758
  githubViewerPermission,
38753
38759
  branchExists,
38754
38760
  mergeBase,
38755
- diffSelection: ({ directory, explicitBaseBranch }) => gen(function* () {
38761
+ diffSelection: ({ directory, explicitBaseBranch, includeUntracked = false }) => gen(function* () {
38756
38762
  if (explicitBaseBranch !== void 0 && explicitBaseBranch.trim().length === 0) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "Diff base branch cannot be empty." }) }));
38757
38763
  if (explicitBaseBranch !== void 0) {
38758
38764
  const range = parseGitDiffRange(explicitBaseBranch);
@@ -38781,7 +38787,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
38781
38787
  "HEAD"
38782
38788
  ]);
38783
38789
  if (uncommitted.status !== 0) return null;
38784
- const files = splitNullSeparated(uncommitted.stdout);
38790
+ const files = yield* mergeUntracked(directory, splitNullSeparated(uncommitted.stdout), includeUntracked);
38785
38791
  if (files.length === 0) return null;
38786
38792
  return {
38787
38793
  currentBranch: resolvedCurrentBranch,
@@ -38811,7 +38817,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
38811
38817
  currentBranch: resolvedCurrentBranch,
38812
38818
  baseBranch,
38813
38819
  diffBaseRef: mergeBaseRef,
38814
- changedFiles: splitNullSeparated(diff.stdout),
38820
+ changedFiles: yield* mergeUntracked(directory, splitNullSeparated(diff.stdout), includeUntracked),
38815
38821
  isCurrentChanges: false
38816
38822
  };
38817
38823
  }).pipe(withSpan("Git.diffSelection")),
@@ -38857,7 +38863,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
38857
38863
  stdout: result.stdout
38858
38864
  };
38859
38865
  }).pipe(withSpan("Git.grep")),
38860
- changedLineRanges: ({ directory, baseRef, cached, files }) => gen(function* () {
38866
+ changedLineRanges: ({ directory, baseRef, cached, files, includeUntracked = false }) => gen(function* () {
38861
38867
  if (files.length === 0) return [];
38862
38868
  if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
38863
38869
  const result = yield* runGit(directory, [
@@ -38871,7 +38877,14 @@ var Git = class Git extends Service()("react-doctor/Git") {
38871
38877
  ...files
38872
38878
  ]);
38873
38879
  if (result.status !== 0) return null;
38874
- return parseChangedLineRanges(result.stdout);
38880
+ const changedLineRanges = parseChangedLineRanges(result.stdout);
38881
+ if (cached || !includeUntracked) return changedLineRanges;
38882
+ const untrackedFilePaths = yield* listUntrackedFilePaths(directory, files);
38883
+ if (untrackedFilePaths === null) return changedLineRanges;
38884
+ return [...changedLineRanges, ...untrackedFilePaths.map((file) => ({
38885
+ file,
38886
+ ranges: [[1, UNTRACKED_FILE_LAST_LINE]]
38887
+ }))];
38875
38888
  }).pipe(catch_$1((error) => error.reason._tag === "GitInvocationFailed" ? succeed$2(null) : fail$4(error)), withSpan("Git.changedLineRanges"))
38876
38889
  });
38877
38890
  })).pipe(provide$2(layer$2.pipe(provide$2(mergeAll$1(layer$1, layer)))));
@@ -39623,6 +39636,12 @@ const mapWithConcurrency = async (items, concurrency, task) => {
39623
39636
  if (errors.length > 0) throw errors[0];
39624
39637
  return results;
39625
39638
  };
39639
+ const lineOfUtf8Offset = (sourceBuffer, utf8Offset) => {
39640
+ let lineNumber = 1;
39641
+ const scanEnd = Math.min(utf8Offset, sourceBuffer.length);
39642
+ for (let byteIndex = 0; byteIndex < scanEnd; byteIndex++) if (sourceBuffer[byteIndex] === 10) lineNumber++;
39643
+ return lineNumber;
39644
+ };
39626
39645
  const REANIMATED_SHARED_VALUE_HINT = "If this is a Reanimated shared value, prefer its React Compiler-compatible `.get()` / `.set()` accessors over `.value` — https://docs.swmansion.com/react-native-reanimated/docs/core/useSharedValue/#react-compiler-support";
39627
39646
  const ACCESSORS_MIN_VERSION = "3.15.0";
39628
39647
  const supportsAccessors = (reanimatedVersion) => {
@@ -40194,13 +40213,6 @@ const findOutermostEnclosingFunctionRange = (sourceFile, targetLine) => {
40194
40213
  visit(sourceFile);
40195
40214
  return foundRange;
40196
40215
  };
40197
- const NEWLINE_BYTE = 10;
40198
- const lineOfUtf8Offset = (sourceBuffer, utf8Offset) => {
40199
- let lineNumber = 1;
40200
- const scanEnd = Math.min(utf8Offset, sourceBuffer.length);
40201
- for (let byteIndex = 0; byteIndex < scanEnd; byteIndex++) if (sourceBuffer[byteIndex] === NEWLINE_BYTE) lineNumber++;
40202
- return lineNumber;
40203
- };
40204
40216
  /**
40205
40217
  * Drops `react-doctor/react-compiler-no-manual-memoization` diagnostics
40206
40218
  * whose enclosing function also carries a `react-hooks-js` (React
@@ -40381,11 +40393,11 @@ const buildRelatedLocations = (labels, filePath) => {
40381
40393
  }
40382
40394
  return related;
40383
40395
  };
40384
- const isOxlintOutput = (value) => {
40385
- if (typeof value !== "object" || value === null) return false;
40386
- const candidate = value;
40387
- return Array.isArray(candidate.diagnostics);
40388
- };
40396
+ const isOxlintSpan = (value) => isRecord(value) && typeof value.offset === "number" && typeof value.length === "number" && typeof value.line === "number" && typeof value.column === "number";
40397
+ const isOxlintLabel = (value) => isRecord(value) && isOxlintSpan(value.span);
40398
+ const isMappableOxlintDiagnostic = (value) => isRecord(value) && typeof value.code === "string" && value.code.length > 0 && typeof value.filename === "string" && value.filename.length > 0 && (value.severity === "warning" || value.severity === "error") && Array.isArray(value.labels) && value.labels.every(isOxlintLabel);
40399
+ const isEngineFailureDiagnostic = (value) => !isRecord(value) || typeof value.filename !== "string" || value.filename.length === 0;
40400
+ const isOxlintOutput = (value) => isRecord(value) && Array.isArray(value.diagnostics);
40389
40401
  /**
40390
40402
  * Parses one oxlint subprocess's stdout into a flat `Diagnostic[]`.
40391
40403
  * Tolerates the leading-notice-line shape oxlint sometimes prints
@@ -40404,23 +40416,59 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
40404
40416
  throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
40405
40417
  }
40406
40418
  if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
40419
+ const engineFailureDiagnostic = parsed.diagnostics.find(isEngineFailureDiagnostic);
40420
+ if (engineFailureDiagnostic !== void 0) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: JSON.stringify(engineFailureDiagnostic).slice(0, 600) }) });
40407
40421
  const minifiedFileCache = /* @__PURE__ */ new Map();
40422
+ const sourceBufferCache = /* @__PURE__ */ new Map();
40423
+ const sourceLinesCache = /* @__PURE__ */ new Map();
40424
+ const resolveAbsolutePath = (filename) => Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
40425
+ const readSourceBuffer = (filename) => {
40426
+ const absolutePath = resolveAbsolutePath(filename);
40427
+ const cached = sourceBufferCache.get(absolutePath);
40428
+ if (cached !== void 0) return cached;
40429
+ let sourceBuffer;
40430
+ try {
40431
+ sourceBuffer = NFS.readFileSync(absolutePath);
40432
+ } catch {
40433
+ sourceBuffer = null;
40434
+ }
40435
+ sourceBufferCache.set(absolutePath, sourceBuffer);
40436
+ return sourceBuffer;
40437
+ };
40438
+ const readSourceLines = (filename) => {
40439
+ const absolutePath = resolveAbsolutePath(filename);
40440
+ const cached = sourceLinesCache.get(absolutePath);
40441
+ if (cached !== void 0) return cached;
40442
+ const sourceBuffer = readSourceBuffer(filename);
40443
+ const sourceLines = sourceBuffer ? sourceBuffer.toString("utf8").split("\n") : null;
40444
+ sourceLinesCache.set(absolutePath, sourceLines);
40445
+ return sourceLines;
40446
+ };
40408
40447
  const isMinifiedDiagnosticFile = (filename) => {
40409
- const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
40448
+ const absolutePath = resolveAbsolutePath(filename);
40410
40449
  const cached = minifiedFileCache.get(absolutePath);
40411
40450
  if (cached !== void 0) return cached;
40412
40451
  const minified = isMinifiedSource(absolutePath);
40413
40452
  minifiedFileCache.set(absolutePath, minified);
40414
40453
  return minified;
40415
40454
  };
40416
- return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => diagnostic.code && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
40455
+ return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => isMappableOxlintDiagnostic(diagnostic) && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
40417
40456
  const { plugin, rule } = parseRuleCode(diagnostic.code);
40418
40457
  const primaryLabel = diagnostic.labels[0];
40419
40458
  const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
40420
40459
  const normalizedFilePath = diagnostic.filename.replaceAll("\\", "/");
40421
40460
  const primarySpan = primaryLabel?.span;
40461
+ const sourceBuffer = primarySpan ? readSourceBuffer(diagnostic.filename) : null;
40422
40462
  const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
40423
40463
  const category = resolveDiagnosticCategory(plugin, rule);
40464
+ const matchByOccurrence = resolveMatchByOccurrence(rule, category);
40465
+ const sourceLines = primarySpan ? readSourceLines(diagnostic.filename) : null;
40466
+ const primaryLineIndex = primarySpan ? primarySpan.line - 1 : -1;
40467
+ const primaryLine = sourceLines?.[primaryLineIndex];
40468
+ const primaryColumnIndex = primarySpan ? primarySpan.column - 1 : -1;
40469
+ const isJsxTagLabel = primaryLine !== void 0 && primaryColumnIndex >= 0 && (primaryLine[primaryColumnIndex] === "<" || primaryLine[primaryColumnIndex - 1] === "<");
40470
+ const jsxOpenerEndLineIndex = sourceLines && isJsxTagLabel ? findJsxOpenerSpan(sourceLines, primaryLineIndex) : null;
40471
+ const primarySpanEndLine = jsxOpenerEndLineIndex !== null ? jsxOpenerEndLineIndex + 1 : primarySpan && sourceBuffer ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset + Math.max(primarySpan.length - 1, 0)) : void 0;
40424
40472
  return {
40425
40473
  filePath: normalizedFilePath,
40426
40474
  plugin,
@@ -40434,10 +40482,11 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
40434
40482
  column: primarySpan?.column ?? 0,
40435
40483
  ...primarySpan ? {
40436
40484
  offset: primarySpan.offset,
40437
- length: primarySpan.length
40485
+ length: primarySpan.length,
40486
+ ...primarySpanEndLine !== void 0 ? { endLine: primarySpanEndLine } : {}
40438
40487
  } : {},
40439
40488
  category,
40440
- ...resolveMatchByOccurrence(rule, category) ? { matchByOccurrence: true } : {},
40489
+ ...matchByOccurrence ? { matchByOccurrence: true } : {},
40441
40490
  ...relatedLocations.length > 0 ? { relatedLocations } : {}
40442
40491
  };
40443
40492
  }), rootDirectory);
@@ -42224,7 +42273,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
42224
42273
  directory: scanDirectory,
42225
42274
  repo
42226
42275
  }).pipe(orElseSucceed(() => null)) : succeed$2(null));
42227
- const lintIncludePaths = (input.skipJsxIncludeFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths], project)) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config, project);
42276
+ const lintIncludePaths = (input.skipExplicitIncludePathFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths])) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config);
42228
42277
  const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
42229
42278
  const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
42230
42279
  const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
@@ -42719,7 +42768,7 @@ const runEditorScan = async (input) => {
42719
42768
  warnings,
42720
42769
  isCi: false,
42721
42770
  resolveLocalGithubViewerPermission: false,
42722
- skipJsxIncludeFilter: true
42771
+ skipExplicitIncludePathFilter: true
42723
42772
  }).pipe(withSpan("runEditorScan", { attributes: {
42724
42773
  "editor.lint": lint,
42725
42774
  "editor.runDeadCode": runDeadCode
@@ -44493,6 +44542,7 @@ const METRIC = {
44493
44542
  cliInvoked: "cli.invoked",
44494
44543
  cliError: "cli.error",
44495
44544
  cliEnvironmentError: "cli.env_error",
44545
+ stagedSnapshotDivergence: "staged.snapshot_divergence",
44496
44546
  projectDetected: "project.detected",
44497
44547
  projectPathSelected: "project.path_selected",
44498
44548
  projectConfigSelected: "project.config_selected",
@@ -44847,5 +44897,5 @@ const startLanguageServer = () => {
44847
44897
  };
44848
44898
  //#endregion
44849
44899
  export { startLanguageServer };
44850
- !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]="56ea0b36-0904-532b-96d1-b4d9c867fe13")}catch(e){}}();
44851
- //# debugId=56ea0b36-0904-532b-96d1-b4d9c867fe13
44900
+ !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]="8ed74459-2a69-556c-bb95-8cdebdb094cd")}catch(e){}}();
44901
+ //# debugId=8ed74459-2a69-556c-bb95-8cdebdb094cd