react-doctor 0.7.5 → 0.7.6-dev.0a8d30b

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.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]="ab586686-464c-58e6-a96d-70f7b39b1c5d")}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]="80f981d4-ebf0-5bc0-9643-8a68d27626a5")}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;
@@ -33040,7 +33039,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
33040
33039
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
33041
33040
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
33042
33041
  const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
33043
- const CORE_PACKAGE_VERSION = "0.7.5";
33042
+ const CORE_PACKAGE_VERSION = "0.7.6";
33044
33043
  const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
33045
33044
  const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
33046
33045
  const SUPPLY_CHAIN_PLUGIN = "socket";
@@ -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)))));
@@ -39125,7 +39138,7 @@ const normalizeConfigForHash = (config) => {
39125
39138
  if (Array.isArray(clone?.jsPlugins)) clone.jsPlugins = clone.jsPlugins.map((_, index) => `<plugin:${index}>`);
39126
39139
  return clone;
39127
39140
  };
39128
- const computeRulesetHash = (input) => crypto.createHash("sha1").update(JSON.stringify(normalizeConfigForHash(input.config))).update("\0").update([...input.toolchainVersions].join("\0")).update("\0").update([...input.ignorePatterns].join("\n")).update("\0").update(input.tsconfigContent ?? "").digest("hex");
39141
+ const computeRulesetHash = (input) => crypto.createHash("sha1").update(JSON.stringify(normalizeConfigForHash(input.config))).update("\0").update([...input.toolchainVersions].join("\0")).update("\0").update([...input.ignorePatterns].join("\n")).update("\0").update(input.tsconfigContent ?? "").update("\0").update(input.respectInlineDisables ? "respect-inline-disables" : "audit-mode").digest("hex");
39129
39142
  /**
39130
39143
  * Loads a plugin module via the local require resolver and extracts
39131
39144
  * `(name, ruleNames)` from either `module.exports.meta + rules` or
@@ -39161,7 +39174,7 @@ const resolveReactHooksJsPlugin = (hasReactCompiler, customRulesOnly) => {
39161
39174
  } catch {
39162
39175
  return null;
39163
39176
  }
39164
- const { ruleNames } = readPluginShape(pluginSpecifier, (spec) => bundledRequire$1(spec));
39177
+ const { ruleNames } = readPluginShape(pluginSpecifier, (specifier) => bundledRequire$1(specifier));
39165
39178
  return {
39166
39179
  entry: {
39167
39180
  name: "react-hooks-js",
@@ -39569,6 +39582,23 @@ const resolveTsConfigRelativePath = (rootDirectory) => {
39569
39582
  for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
39570
39583
  return null;
39571
39584
  };
39585
+ const DERIVED_STATE_RULE_PRIORITY = new Map([
39586
+ ["no-initialize-state", 0],
39587
+ ["no-adjust-state-on-prop-change", 1],
39588
+ ["no-derived-state", 2],
39589
+ ["no-derived-state-effect", 3]
39590
+ ]);
39591
+ const doDiagnosticSpansOverlap = (first, second) => {
39592
+ if (first.filePath !== second.filePath || first.plugin !== second.plugin) return false;
39593
+ if (first.offset !== void 0 && second.offset !== void 0) {
39594
+ const firstEnd = first.offset + Math.max(first.length ?? 1, 1);
39595
+ const secondEnd = second.offset + Math.max(second.length ?? 1, 1);
39596
+ return first.offset < secondEnd && second.offset < firstEnd;
39597
+ }
39598
+ const firstEndLine = first.endLine ?? first.line;
39599
+ const secondEndLine = second.endLine ?? second.line;
39600
+ return first.line <= secondEndLine && second.line <= firstEndLine;
39601
+ };
39572
39602
  const dedupeDiagnostics = (diagnostics) => {
39573
39603
  const seenKeys = /* @__PURE__ */ new Set();
39574
39604
  const uniqueDiagnostics = [];
@@ -39576,6 +39606,16 @@ const dedupeDiagnostics = (diagnostics) => {
39576
39606
  const key = `${diagnostic.filePath}\u0000${diagnostic.line}\u0000${diagnostic.column}\u0000${diagnostic.plugin}\u0000${diagnostic.rule}\u0000${diagnostic.severity}\u0000${diagnostic.message}`;
39577
39607
  if (seenKeys.has(key)) continue;
39578
39608
  seenKeys.add(key);
39609
+ const priority = DERIVED_STATE_RULE_PRIORITY.get(diagnostic.rule);
39610
+ if (priority !== void 0) {
39611
+ const overlappingDiagnosticIndex = uniqueDiagnostics.findIndex((candidate) => candidate.rule !== diagnostic.rule && candidate.severity === diagnostic.severity && DERIVED_STATE_RULE_PRIORITY.has(candidate.rule) && doDiagnosticSpansOverlap(candidate, diagnostic));
39612
+ if (overlappingDiagnosticIndex >= 0) {
39613
+ const existingDiagnostic = uniqueDiagnostics[overlappingDiagnosticIndex];
39614
+ const existingPriority = existingDiagnostic ? DERIVED_STATE_RULE_PRIORITY.get(existingDiagnostic.rule) : void 0;
39615
+ if (existingPriority !== void 0 && priority < existingPriority) uniqueDiagnostics[overlappingDiagnosticIndex] = diagnostic;
39616
+ continue;
39617
+ }
39618
+ }
39579
39619
  uniqueDiagnostics.push(diagnostic);
39580
39620
  }
39581
39621
  return uniqueDiagnostics;
@@ -39618,6 +39658,12 @@ const mapWithConcurrency = async (items, concurrency, task) => {
39618
39658
  if (errors.length > 0) throw errors[0];
39619
39659
  return results;
39620
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
+ };
39621
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";
39622
39668
  const ACCESSORS_MIN_VERSION = "3.15.0";
39623
39669
  const supportsAccessors = (reanimatedVersion) => {
@@ -40189,13 +40235,6 @@ const findOutermostEnclosingFunctionRange = (sourceFile, targetLine) => {
40189
40235
  visit(sourceFile);
40190
40236
  return foundRange;
40191
40237
  };
40192
- const NEWLINE_BYTE = 10;
40193
- const lineOfUtf8Offset = (sourceBuffer, utf8Offset) => {
40194
- let lineNumber = 1;
40195
- const scanEnd = Math.min(utf8Offset, sourceBuffer.length);
40196
- for (let byteIndex = 0; byteIndex < scanEnd; byteIndex++) if (sourceBuffer[byteIndex] === NEWLINE_BYTE) lineNumber++;
40197
- return lineNumber;
40198
- };
40199
40238
  /**
40200
40239
  * Drops `react-doctor/react-compiler-no-manual-memoization` diagnostics
40201
40240
  * whose enclosing function also carries a `react-hooks-js` (React
@@ -40400,8 +40439,33 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
40400
40439
  }
40401
40440
  if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
40402
40441
  const minifiedFileCache = /* @__PURE__ */ new Map();
40442
+ const sourceBufferCache = /* @__PURE__ */ new Map();
40443
+ const sourceLinesCache = /* @__PURE__ */ new Map();
40444
+ const resolveAbsolutePath = (filename) => Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
40445
+ const readSourceBuffer = (filename) => {
40446
+ const absolutePath = resolveAbsolutePath(filename);
40447
+ const cached = sourceBufferCache.get(absolutePath);
40448
+ if (cached !== void 0) return cached;
40449
+ let sourceBuffer;
40450
+ try {
40451
+ sourceBuffer = NFS.readFileSync(absolutePath);
40452
+ } catch {
40453
+ sourceBuffer = null;
40454
+ }
40455
+ sourceBufferCache.set(absolutePath, sourceBuffer);
40456
+ return sourceBuffer;
40457
+ };
40458
+ const readSourceLines = (filename) => {
40459
+ const absolutePath = resolveAbsolutePath(filename);
40460
+ const cached = sourceLinesCache.get(absolutePath);
40461
+ if (cached !== void 0) return cached;
40462
+ const sourceBuffer = readSourceBuffer(filename);
40463
+ const sourceLines = sourceBuffer ? sourceBuffer.toString("utf8").split("\n") : null;
40464
+ sourceLinesCache.set(absolutePath, sourceLines);
40465
+ return sourceLines;
40466
+ };
40403
40467
  const isMinifiedDiagnosticFile = (filename) => {
40404
- const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
40468
+ const absolutePath = resolveAbsolutePath(filename);
40405
40469
  const cached = minifiedFileCache.get(absolutePath);
40406
40470
  if (cached !== void 0) return cached;
40407
40471
  const minified = isMinifiedSource(absolutePath);
@@ -40414,8 +40478,17 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
40414
40478
  const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
40415
40479
  const normalizedFilePath = diagnostic.filename.replaceAll("\\", "/");
40416
40480
  const primarySpan = primaryLabel?.span;
40481
+ const sourceBuffer = primarySpan ? readSourceBuffer(diagnostic.filename) : null;
40417
40482
  const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
40418
40483
  const category = resolveDiagnosticCategory(plugin, rule);
40484
+ const matchByOccurrence = resolveMatchByOccurrence(rule, category);
40485
+ const sourceLines = primarySpan ? readSourceLines(diagnostic.filename) : null;
40486
+ const primaryLineIndex = primarySpan ? primarySpan.line - 1 : -1;
40487
+ const primaryLine = sourceLines?.[primaryLineIndex];
40488
+ const primaryColumnIndex = primarySpan ? primarySpan.column - 1 : -1;
40489
+ const isJsxTagLabel = primaryLine !== void 0 && primaryColumnIndex >= 0 && (primaryLine[primaryColumnIndex] === "<" || primaryLine[primaryColumnIndex - 1] === "<");
40490
+ const jsxOpenerEndLineIndex = sourceLines && isJsxTagLabel ? findJsxOpenerSpan(sourceLines, primaryLineIndex) : null;
40491
+ const primarySpanEndLine = jsxOpenerEndLineIndex !== null ? jsxOpenerEndLineIndex + 1 : primarySpan && sourceBuffer ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset + Math.max(primarySpan.length - 1, 0)) : void 0;
40419
40492
  return {
40420
40493
  filePath: normalizedFilePath,
40421
40494
  plugin,
@@ -40429,10 +40502,11 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
40429
40502
  column: primarySpan?.column ?? 0,
40430
40503
  ...primarySpan ? {
40431
40504
  offset: primarySpan.offset,
40432
- length: primarySpan.length
40505
+ length: primarySpan.length,
40506
+ ...primarySpanEndLine !== void 0 ? { endLine: primarySpanEndLine } : {}
40433
40507
  } : {},
40434
40508
  category,
40435
- ...resolveMatchByOccurrence(rule, category) ? { matchByOccurrence: true } : {},
40509
+ ...matchByOccurrence ? { matchByOccurrence: true } : {},
40436
40510
  ...relatedLocations.length > 0 ? { relatedLocations } : {}
40437
40511
  };
40438
40512
  }), rootDirectory);
@@ -40449,6 +40523,11 @@ const buildOxlintChildEnv = (sourceEnv) => {
40449
40523
  if (!isCompileCacheDisabled && !isCompileCacheAlreadySet) childEnv.NODE_COMPILE_CACHE = Path.join(os.tmpdir(), NODE_COMPILE_CACHE_DIR_NAME);
40450
40524
  return childEnv;
40451
40525
  };
40526
+ const buildProfiledNodeArguments = (input) => [
40527
+ ...input.cpuProfileDirectory ? ["--cpu-prof", `--cpu-prof-dir=${input.cpuProfileDirectory}`] : [],
40528
+ ...input.heapProfileDirectory ? ["--heap-prof", `--heap-prof-dir=${input.heapProfileDirectory}`] : [],
40529
+ ...input.argumentsList
40530
+ ];
40452
40531
  const SANITIZED_ENV = buildOxlintChildEnv(process.env);
40453
40532
  /**
40454
40533
  * Spawn one oxlint subprocess with hard ceilings on wall time and
@@ -40473,7 +40552,11 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
40473
40552
  reject(new ReactDoctorError({ reason: new OxlintSpawnFailed({ cause: "lint phase aborted" }) }));
40474
40553
  return;
40475
40554
  }
40476
- const child = spawn(nodeBinaryPath, args, {
40555
+ const child = spawn(nodeBinaryPath, buildProfiledNodeArguments({
40556
+ argumentsList: args,
40557
+ cpuProfileDirectory: SANITIZED_ENV.REACT_DOCTOR_CPU_PROFILE_DIR,
40558
+ heapProfileDirectory: SANITIZED_ENV.REACT_DOCTOR_HEAP_PROFILE_DIR
40559
+ }), {
40477
40560
  cwd: rootDirectory,
40478
40561
  env: SANITIZED_ENV,
40479
40562
  stdio: [
@@ -41117,7 +41200,7 @@ const runOxlint = async (options) => {
41117
41200
  };
41118
41201
  }
41119
41202
  };
41120
- if (perFileLintCacheEnabled && respectInlineDisables && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
41203
+ if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
41121
41204
  const rulesetHash = computeRulesetHash({
41122
41205
  config: buildConfig({
41123
41206
  extendsPaths: [],
@@ -41125,7 +41208,8 @@ const runOxlint = async (options) => {
41125
41208
  }),
41126
41209
  toolchainVersions: resolveOxlintToolchainVersions(nodeBinaryPath),
41127
41210
  ignorePatterns: combinedPatterns,
41128
- tsconfigContent
41211
+ tsconfigContent,
41212
+ respectInlineDisables
41129
41213
  });
41130
41214
  const cache = createFileLintCache(resolveReactDoctorCacheDir(rootDirectory), rulesetHash);
41131
41215
  const cacheKeyByFile = /* @__PURE__ */ new Map();
@@ -41168,7 +41252,8 @@ const runOxlint = async (options) => {
41168
41252
  }),
41169
41253
  toolchainVersions: resolveOxlintToolchainVersions(nodeBinaryPath),
41170
41254
  ignorePatterns: combinedPatterns,
41171
- tsconfigContent
41255
+ tsconfigContent,
41256
+ respectInlineDisables
41172
41257
  })) : null;
41173
41258
  const probeAnswers = createSidecarProbeAnswerResolver({
41174
41259
  rootDirectory,
@@ -42208,7 +42293,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
42208
42293
  directory: scanDirectory,
42209
42294
  repo
42210
42295
  }).pipe(orElseSucceed(() => null)) : succeed$2(null));
42211
- const lintIncludePaths = (input.skipJsxIncludeFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths], project)) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config, project);
42296
+ const lintIncludePaths = (input.skipExplicitIncludePathFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths])) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config);
42212
42297
  const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
42213
42298
  const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
42214
42299
  const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
@@ -42879,10 +42964,11 @@ const buildSkippedChecks = (input) => {
42879
42964
  * render diff-base mistakes (`GitBaseBranchInvalid` /
42880
42965
  * `GitBaseBranchMissing`) as clean user errors instead of crashes.
42881
42966
  */
42882
- const getDiffInfo = (directory, explicitBaseBranch) => runPromise(gen(function* () {
42967
+ const getDiffInfo = (directory, explicitBaseBranch, includeUntracked) => runPromise(gen(function* () {
42883
42968
  const selection = yield* (yield* Git).diffSelection({
42884
42969
  directory,
42885
- explicitBaseBranch
42970
+ explicitBaseBranch,
42971
+ includeUntracked
42886
42972
  });
42887
42973
  if (selection === null) return null;
42888
42974
  return {
@@ -43172,4 +43258,4 @@ const toJsonReport = (result, options) => buildJsonReport({
43172
43258
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
43173
43259
 
43174
43260
  //# sourceMappingURL=index.js.map
43175
- //# debugId=ab586686-464c-58e6-a96d-70f7b39b1c5d
43261
+ //# debugId=80f981d4-ebf0-5bc0-9643-8a68d27626a5