react-doctor 0.7.9-dev.2450582 → 0.7.9-dev.2ba83c3

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]="c29245d6-1073-542d-91c7-90d62f3911e2")}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]="5c4df375-a5c4-57d2-9076-4e54cbb8f3bd")}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";
@@ -36252,53 +36252,6 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
36252
36252
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
36253
36253
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
36254
36254
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
36255
- const lastSourceMappingUrl = (fileContent) => {
36256
- const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
36257
- return lastReference ? lastReference[1] : null;
36258
- };
36259
- const mapTargetsSource = (mapContent, input) => {
36260
- const parsedMap = JSON.parse(mapContent);
36261
- if (typeof parsedMap !== "object" || parsedMap === null) return false;
36262
- const { file, sources } = parsedMap;
36263
- if (file !== input.expectedFile) return false;
36264
- if (!Array.isArray(sources) || sources.length !== 1 || typeof sources[0] !== "string") return false;
36265
- return Path.posix.normalize(Path.posix.join(input.mapDirectory, sources[0])) === input.sourcePath;
36266
- };
36267
- const quartetProvesEmit = (stem, sourcePath, readFileText) => {
36268
- try {
36269
- const emitBaseName = Path.posix.basename(stem);
36270
- const mapDirectory = Path.posix.dirname(stem);
36271
- return lastSourceMappingUrl(readFileText(`${stem}.js`)) === `${emitBaseName}.js.map` && lastSourceMappingUrl(readFileText(`${stem}.d.ts`)) === `${emitBaseName}.d.ts.map` && mapTargetsSource(readFileText(`${stem}.js.map`), {
36272
- expectedFile: `${emitBaseName}.js`,
36273
- mapDirectory,
36274
- sourcePath
36275
- }) && mapTargetsSource(readFileText(`${stem}.d.ts.map`), {
36276
- expectedFile: `${emitBaseName}.d.ts`,
36277
- mapDirectory,
36278
- sourcePath
36279
- });
36280
- } catch {
36281
- return false;
36282
- }
36283
- };
36284
- const collectTypeScriptEmitDuplicateJsPaths = (input) => {
36285
- const untracked = new Set(input.untrackedPaths);
36286
- const duplicateJsPaths = /* @__PURE__ */ new Set();
36287
- for (const jsPath of untracked) {
36288
- if (!jsPath.endsWith(".js")) continue;
36289
- const stem = jsPath.slice(0, -3);
36290
- if (![
36291
- jsPath,
36292
- `${stem}.js.map`,
36293
- `${stem}.d.ts`,
36294
- `${stem}.d.ts.map`
36295
- ].every((emitPath) => untracked.has(emitPath) && !input.trackedPaths.has(emitPath))) continue;
36296
- const sourcePath = [`${stem}.ts`, `${stem}.tsx`].find((candidatePath) => input.trackedPaths.has(candidatePath));
36297
- if (!sourcePath) continue;
36298
- if (quartetProvesEmit(stem, sourcePath, input.readFileText)) duplicateJsPaths.add(jsPath);
36299
- }
36300
- return duplicateJsPaths;
36301
- };
36302
36255
  const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
36303
36256
  const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
36304
36257
  const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
@@ -36366,29 +36319,20 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
36366
36319
  }
36367
36320
  return entries;
36368
36321
  };
36369
- const gitLsFiles = (rootDirectory, flags) => {
36322
+ const listSourceFilesViaGit = (rootDirectory) => {
36370
36323
  const result = spawnSync("git", [
36371
36324
  "ls-files",
36372
36325
  "-z",
36373
- ...flags
36326
+ "--cached",
36327
+ "--others",
36328
+ "--exclude-standard"
36374
36329
  ], {
36375
36330
  cwd: rootDirectory,
36376
36331
  encoding: "utf-8",
36377
36332
  maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
36378
36333
  });
36379
36334
  if (result.error || result.status !== 0) return null;
36380
- return result.stdout.split("\0").filter((filePath) => filePath.length > 0);
36381
- };
36382
- const listSourceFilesViaGit = (rootDirectory) => {
36383
- const trackedPaths = gitLsFiles(rootDirectory, ["--cached"]);
36384
- const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
36385
- if (trackedPaths === null || untrackedPaths === null) return null;
36386
- const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
36387
- trackedPaths: new Set(trackedPaths),
36388
- untrackedPaths,
36389
- readFileText: (relativePath) => NFS.readFileSync(Path.resolve(rootDirectory, relativePath), "utf-8")
36390
- });
36391
- return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
36335
+ return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
36392
36336
  };
36393
36337
  const listSourceFilesViaFilesystem = (rootDirectory) => {
36394
36338
  const filePaths = [];
@@ -39228,10 +39172,8 @@ const isDiagnosticSurface = (value) => typeof value === "string" && DIAGNOSTIC_S
39228
39172
  * to the local CLI so developers see them while editing, but they're
39229
39173
  * removed from the PR comment surface, the score, and the CI gate so
39230
39174
  * they can't bury real React findings or fail a build over a Tailwind
39231
- * shorthand. Diagnostics from test and story files likewise remain in
39232
- * raw output while staying out of the production-health score and CI
39233
- * gate. Override per-surface via `config.surfaces.<surface>` to promote
39234
- * individual rules back in by tag, category, or rule id.
39175
+ * shorthand. Override per-surface via `config.surfaces.<surface>` to
39176
+ * promote individual rules back in by tag, category, or rule id.
39235
39177
  */
39236
39178
  const DEFAULT_SURFACE_EXCLUDED_TAGS = {
39237
39179
  cli: [],
@@ -42062,7 +42004,6 @@ const isDiagnosticOnSurface = (diagnostic, surface, config) => {
42062
42004
  if (resolved.includeRuleKeys.has(ruleKey)) return true;
42063
42005
  if (resolved.includeCategories.has(category)) return true;
42064
42006
  if (intersects(tags, resolved.includeTags)) return true;
42065
- if (diagnostic.fileContext !== void 0 && (surface === "score" || surface === "ciFailure")) return false;
42066
42007
  if (resolved.excludeRuleKeys.has(ruleKey)) return false;
42067
42008
  if (resolved.excludeCategories.has(category)) return false;
42068
42009
  if (intersects(tags, resolved.excludeTags)) return false;
@@ -42487,7 +42428,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
42487
42428
  }
42488
42429
  const diff = yield* runGit(input.directory, [
42489
42430
  "diff",
42490
- "--no-ext-diff",
42491
42431
  "-z",
42492
42432
  "--name-only",
42493
42433
  "--diff-filter=ACMR",
@@ -42534,7 +42474,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
42534
42474
  if (resolvedCurrentBranch !== null && resolvedCurrentBranch === baseBranch) {
42535
42475
  const uncommitted = yield* runGit(directory, [
42536
42476
  "diff",
42537
- "--no-ext-diff",
42538
42477
  "-z",
42539
42478
  "--name-only",
42540
42479
  "--diff-filter=ACMR",
@@ -42561,7 +42500,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
42561
42500
  if (mergeBaseRef === null) return null;
42562
42501
  const diff = yield* runGit(directory, [
42563
42502
  "diff",
42564
- "--no-ext-diff",
42565
42503
  "-z",
42566
42504
  "--name-only",
42567
42505
  "--diff-filter=ACMR",
@@ -42579,7 +42517,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
42579
42517
  }).pipe(withSpan("Git.diffSelection")),
42580
42518
  stagedFilePaths: (directory) => runGit(directory, [
42581
42519
  "diff",
42582
- "--no-ext-diff",
42583
42520
  "--cached",
42584
42521
  "-z",
42585
42522
  "--name-only",
@@ -42625,7 +42562,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
42625
42562
  if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
42626
42563
  const result = yield* runGit(directory, [
42627
42564
  "diff",
42628
- "--no-ext-diff",
42629
42565
  "--unified=0",
42630
42566
  "--diff-filter=ACMR",
42631
42567
  "--relative",
@@ -47223,7 +47159,7 @@ const makeNoopConsole = () => ({
47223
47159
  });
47224
47160
  //#endregion
47225
47161
  //#region src/cli/utils/version.ts
47226
- const VERSION = "0.7.9-dev.2450582";
47162
+ const VERSION = "0.7.9-dev.2ba83c3";
47227
47163
  //#endregion
47228
47164
  //#region src/cli/utils/json-mode.ts
47229
47165
  let context = null;
@@ -47575,13 +47511,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
47575
47511
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
47576
47512
  * standard `SENTRY_RELEASE` override.
47577
47513
  */
47578
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.9-dev.2450582`;
47514
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.9-dev.2ba83c3`;
47579
47515
  /**
47580
47516
  * Deployment environment shown in Sentry's environment filter. Defaults to
47581
47517
  * `production` for tagged releases and `development` for dev/unbuilt versions,
47582
47518
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
47583
47519
  */
47584
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.9-dev.2450582") ? "development" : "production");
47520
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.9-dev.2ba83c3") ? "development" : "production");
47585
47521
  /**
47586
47522
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
47587
47523
  * (set to `0` to disable tracing) and falls back to
@@ -60076,7 +60012,6 @@ const buildOutcomeAttributes = (input) => {
60076
60012
  const summary = summarizeDiagnostics(result.diagnostics);
60077
60013
  const blockingLevel = resolveTelemetryBlocking(input.userConfig);
60078
60014
  const gateDiagnostics = filterDiagnosticsForSurface(result.diagnostics, "ciFailure", input.userConfig);
60079
- const gateDiagnosticSet = new Set(gateDiagnostics);
60080
60015
  const complete = isInspectResultComplete(result);
60081
60016
  const didLintHardFail = hasLintHardFailure(result);
60082
60017
  const failsOnHardFailure = didLintHardFail && blockingLevel !== "none";
@@ -60099,13 +60034,11 @@ const buildOutcomeAttributes = (input) => {
60099
60034
  const largestRuleBucket = buildRuleBlastRadii(result.diagnostics)[0] ?? null;
60100
60035
  let diagnosticsInTestFiles = 0;
60101
60036
  let diagnosticsInStoryFiles = 0;
60102
- let nonProductionGateExcluded = 0;
60103
60037
  const diagnosticSiteCounts = /* @__PURE__ */ new Map();
60104
60038
  const findingsPerFixGroup = /* @__PURE__ */ new Map();
60105
60039
  for (const diagnostic of result.diagnostics) {
60106
60040
  if (diagnostic.fileContext === "test") diagnosticsInTestFiles += 1;
60107
60041
  if (diagnostic.fileContext === "story") diagnosticsInStoryFiles += 1;
60108
- if (diagnostic.fileContext !== void 0 && !gateDiagnosticSet.has(diagnostic)) nonProductionGateExcluded += 1;
60109
60042
  const diagnosticSite = JSON.stringify([
60110
60043
  diagnostic.filePath,
60111
60044
  diagnostic.line,
@@ -60154,7 +60087,6 @@ const buildOutcomeAttributes = (input) => {
60154
60087
  affectedFiles: summary.affectedFileCount,
60155
60088
  inTestFiles: diagnosticsInTestFiles,
60156
60089
  inStoryFiles: diagnosticsInStoryFiles,
60157
- nonProductionGateExcluded,
60158
60090
  distinctRules: countByRule.size,
60159
60091
  topRule,
60160
60092
  sameSiteOccurrences,
@@ -61994,9 +61926,7 @@ const finalizeAndRender = (input) => gen(function* () {
61994
61926
  yield* log(highlighter.gray(` ${demotedDiagnosticCount} demoted from the ${options.outputSurface} surface (e.g. design cleanup) — run \`npx react-doctor@latest .\` locally for the full list.`));
61995
61927
  yield* log("");
61996
61928
  }
61997
- const scoreDiagnostics = filterDiagnosticsForSurface([...diagnostics], "score", userConfig);
61998
- const displayedScoreDiagnostics = filterDiagnosticsForSurface([...printedDiagnostics], "score", userConfig);
61999
- const potentialScore = score ? yield* promise(() => computeProjectedScore(displayedScoreDiagnostics, scoreDiagnostics, score)) : null;
61929
+ const potentialScore = score ? yield* promise(() => computeProjectedScore([...printedDiagnostics], [...surfaceDiagnostics], score)) : null;
62000
61930
  const shouldShowShareLink = !options.noScore && options.share && !options.isCi;
62001
61931
  yield* pause;
62002
61932
  yield* printSummary({
@@ -63897,8 +63827,6 @@ const printMultiProjectSummary = (input) => gen(function* () {
63897
63827
  const categoryFilters = input.categoryFilters ?? /* @__PURE__ */ new Set();
63898
63828
  const animateRender = !verbose && canAnimateOnboarding(process.stdout);
63899
63829
  const displayDiagnostics = filterDiagnosticsByCategories(filterScansForSurface(completedScans, "cli"), categoryFilters);
63900
- const scoreDiagnostics = new Set(filterScansForSurface(completedScans, "score"));
63901
- const displayedScoreDiagnostics = displayDiagnostics.filter((diagnostic) => scoreDiagnostics.has(diagnostic));
63902
63830
  const projectRootByDiagnostic = /* @__PURE__ */ new WeakMap();
63903
63831
  for (const scan of completedScans) for (const diagnostic of scan.result.diagnostics) projectRootByDiagnostic.set(diagnostic, scan.result.project.rootDirectory);
63904
63832
  const resolveDiagnosticSourceRoot = (diagnostic) => projectRootByDiagnostic.get(diagnostic) ?? "";
@@ -63922,7 +63850,7 @@ const printMultiProjectSummary = (input) => gen(function* () {
63922
63850
  diagnostics: displayDiagnostics,
63923
63851
  elapsedMilliseconds: totalElapsedMilliseconds,
63924
63852
  scoreResult: aggregateScore,
63925
- potentialScore: lowestScoredScan ? yield* promise(() => computeProjectedScore(displayedScoreDiagnostics, filterScansForSurface([lowestScoredScan], "score"), lowestScoredScan.result.score)) : null,
63853
+ potentialScore: lowestScoredScan ? yield* promise(() => computeProjectedScore(displayDiagnostics, filterScansForSurface([lowestScoredScan], "cli"), lowestScoredScan.result.score)) : null,
63926
63854
  totalSourceFileCount,
63927
63855
  noScoreMessage: "Score unavailable.",
63928
63856
  verbose,
@@ -65867,4 +65795,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
65867
65795
  export {};
65868
65796
 
65869
65797
  //# sourceMappingURL=cli.js.map
65870
- //# debugId=c29245d6-1073-542d-91c7-90d62f3911e2
65798
+ //# debugId=5c4df375-a5c4-57d2-9076-4e54cbb8f3bd
package/dist/index.d.ts CHANGED
@@ -9056,10 +9056,8 @@ interface ReactDoctorIgnoreConfig {
9056
9056
  *
9057
9057
  * Defaults: design rules (tag `"design"`) are excluded from `prComment`,
9058
9058
  * `score`, and `ciFailure` so style cleanup doesn't dilute meaningful
9059
- * React findings. Diagnostics stamped with `fileContext: "test" | "story"`
9060
- * are excluded from `score` and `ciFailure`. Both remain in `cli`, and an
9061
- * explicit rule, category, or tag include promotes a diagnostic back onto
9062
- * the selected surface.
9059
+ * React findings. They remain in `cli` so locally-running developers
9060
+ * still see the suggestion when they touch the file.
9063
9061
  */
9064
9062
  type DiagnosticSurface = "cli" | "prComment" | "score" | "ciFailure";
9065
9063
  /**
@@ -9340,22 +9338,23 @@ interface ReactDoctorConfig {
9340
9338
  */
9341
9339
  adoptExistingLintConfig?: boolean;
9342
9340
  /**
9343
- * Per-surface include/exclude controls. Each `DiagnosticSurface` resolves
9344
- * rule tags, categories, and identifiers independently. This lets you keep a rule
9345
- * visible locally while hiding it from PR comments, the score, or the CI
9346
- * gate. These controls don't change rule severity or activation.
9341
+ * Per-surface include/exclude controls. Each `DiagnosticSurface` is
9342
+ * resolved independently against rule tags, category, and id so a
9343
+ * single rule can be visible locally yet hidden from PR comments,
9344
+ * neutralized from the score, and excluded from the CI gate — all
9345
+ * without touching the rule's severity or activation.
9347
9346
  *
9348
9347
  * Defaults (applied before user overrides):
9349
9348
  *
9350
9349
  * - `prComment` excludes tag `"design"`
9351
9350
  * - `score` excludes tag `"design"`
9352
9351
  * - `ciFailure` excludes tag `"design"`
9353
- * - `score` and `ciFailure` exclude test/story file contexts unless explicitly included
9354
9352
  *
9355
- * Pass any controls block, including an empty `{}`, to keep the defaults.
9356
- * Your include/exclude entries layer on top. Includes always win over
9357
- * excludes. For example, you can promote one high-signal `design-*` rule
9358
- * back into the score or PR-comment surface.
9353
+ * Pass any controls block (even an empty `{}`) to keep the default
9354
+ * exclusions; the user's include/exclude entries layer on top.
9355
+ * Include entries always win over exclude entries — handy for
9356
+ * promoting a single high-signal `design-*` rule back into the
9357
+ * score or PR-comment surface.
9359
9358
  */
9360
9359
  surfaces?: Partial<Record<DiagnosticSurface, SurfaceControls>>;
9361
9360
  /**
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]="a80081fb-3090-5160-8adf-e2652ffe1212")}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]="526cf949-6544-5cb8-bf6d-3f4d854b6678")}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";
@@ -33050,53 +33050,6 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
33050
33050
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
33051
33051
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
33052
33052
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
33053
- const lastSourceMappingUrl = (fileContent) => {
33054
- const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
33055
- return lastReference ? lastReference[1] : null;
33056
- };
33057
- const mapTargetsSource = (mapContent, input) => {
33058
- const parsedMap = JSON.parse(mapContent);
33059
- if (typeof parsedMap !== "object" || parsedMap === null) return false;
33060
- const { file, sources } = parsedMap;
33061
- if (file !== input.expectedFile) return false;
33062
- if (!Array.isArray(sources) || sources.length !== 1 || typeof sources[0] !== "string") return false;
33063
- return Path.posix.normalize(Path.posix.join(input.mapDirectory, sources[0])) === input.sourcePath;
33064
- };
33065
- const quartetProvesEmit = (stem, sourcePath, readFileText) => {
33066
- try {
33067
- const emitBaseName = Path.posix.basename(stem);
33068
- const mapDirectory = Path.posix.dirname(stem);
33069
- return lastSourceMappingUrl(readFileText(`${stem}.js`)) === `${emitBaseName}.js.map` && lastSourceMappingUrl(readFileText(`${stem}.d.ts`)) === `${emitBaseName}.d.ts.map` && mapTargetsSource(readFileText(`${stem}.js.map`), {
33070
- expectedFile: `${emitBaseName}.js`,
33071
- mapDirectory,
33072
- sourcePath
33073
- }) && mapTargetsSource(readFileText(`${stem}.d.ts.map`), {
33074
- expectedFile: `${emitBaseName}.d.ts`,
33075
- mapDirectory,
33076
- sourcePath
33077
- });
33078
- } catch {
33079
- return false;
33080
- }
33081
- };
33082
- const collectTypeScriptEmitDuplicateJsPaths = (input) => {
33083
- const untracked = new Set(input.untrackedPaths);
33084
- const duplicateJsPaths = /* @__PURE__ */ new Set();
33085
- for (const jsPath of untracked) {
33086
- if (!jsPath.endsWith(".js")) continue;
33087
- const stem = jsPath.slice(0, -3);
33088
- if (![
33089
- jsPath,
33090
- `${stem}.js.map`,
33091
- `${stem}.d.ts`,
33092
- `${stem}.d.ts.map`
33093
- ].every((emitPath) => untracked.has(emitPath) && !input.trackedPaths.has(emitPath))) continue;
33094
- const sourcePath = [`${stem}.ts`, `${stem}.tsx`].find((candidatePath) => input.trackedPaths.has(candidatePath));
33095
- if (!sourcePath) continue;
33096
- if (quartetProvesEmit(stem, sourcePath, input.readFileText)) duplicateJsPaths.add(jsPath);
33097
- }
33098
- return duplicateJsPaths;
33099
- };
33100
33053
  const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
33101
33054
  const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
33102
33055
  const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
@@ -33167,29 +33120,20 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
33167
33120
  }
33168
33121
  return entries;
33169
33122
  };
33170
- const gitLsFiles = (rootDirectory, flags) => {
33123
+ const listSourceFilesViaGit = (rootDirectory) => {
33171
33124
  const result = spawnSync("git", [
33172
33125
  "ls-files",
33173
33126
  "-z",
33174
- ...flags
33127
+ "--cached",
33128
+ "--others",
33129
+ "--exclude-standard"
33175
33130
  ], {
33176
33131
  cwd: rootDirectory,
33177
33132
  encoding: "utf-8",
33178
33133
  maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
33179
33134
  });
33180
33135
  if (result.error || result.status !== 0) return null;
33181
- return result.stdout.split("\0").filter((filePath) => filePath.length > 0);
33182
- };
33183
- const listSourceFilesViaGit = (rootDirectory) => {
33184
- const trackedPaths = gitLsFiles(rootDirectory, ["--cached"]);
33185
- const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
33186
- if (trackedPaths === null || untrackedPaths === null) return null;
33187
- const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
33188
- trackedPaths: new Set(trackedPaths),
33189
- untrackedPaths,
33190
- readFileText: (relativePath) => NFS.readFileSync(Path.resolve(rootDirectory, relativePath), "utf-8")
33191
- });
33192
- return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
33136
+ return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
33193
33137
  };
33194
33138
  const listSourceFilesViaFilesystem = (rootDirectory) => {
33195
33139
  const filePaths = [];
@@ -36028,10 +35972,8 @@ const isDiagnosticSurface = (value) => typeof value === "string" && DIAGNOSTIC_S
36028
35972
  * to the local CLI so developers see them while editing, but they're
36029
35973
  * removed from the PR comment surface, the score, and the CI gate so
36030
35974
  * they can't bury real React findings or fail a build over a Tailwind
36031
- * shorthand. Diagnostics from test and story files likewise remain in
36032
- * raw output while staying out of the production-health score and CI
36033
- * gate. Override per-surface via `config.surfaces.<surface>` to promote
36034
- * individual rules back in by tag, category, or rule id.
35975
+ * shorthand. Override per-surface via `config.surfaces.<surface>` to
35976
+ * promote individual rules back in by tag, category, or rule id.
36035
35977
  */
36036
35978
  const DEFAULT_SURFACE_EXCLUDED_TAGS = {
36037
35979
  cli: [],
@@ -38818,7 +38760,6 @@ const isDiagnosticOnSurface = (diagnostic, surface, config) => {
38818
38760
  if (resolved.includeRuleKeys.has(ruleKey)) return true;
38819
38761
  if (resolved.includeCategories.has(category)) return true;
38820
38762
  if (intersects(tags, resolved.includeTags)) return true;
38821
- if (diagnostic.fileContext !== void 0 && (surface === "score" || surface === "ciFailure")) return false;
38822
38763
  if (resolved.excludeRuleKeys.has(ruleKey)) return false;
38823
38764
  if (resolved.excludeCategories.has(category)) return false;
38824
38765
  if (intersects(tags, resolved.excludeTags)) return false;
@@ -39243,7 +39184,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
39243
39184
  }
39244
39185
  const diff = yield* runGit(input.directory, [
39245
39186
  "diff",
39246
- "--no-ext-diff",
39247
39187
  "-z",
39248
39188
  "--name-only",
39249
39189
  "--diff-filter=ACMR",
@@ -39290,7 +39230,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
39290
39230
  if (resolvedCurrentBranch !== null && resolvedCurrentBranch === baseBranch) {
39291
39231
  const uncommitted = yield* runGit(directory, [
39292
39232
  "diff",
39293
- "--no-ext-diff",
39294
39233
  "-z",
39295
39234
  "--name-only",
39296
39235
  "--diff-filter=ACMR",
@@ -39317,7 +39256,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
39317
39256
  if (mergeBaseRef === null) return null;
39318
39257
  const diff = yield* runGit(directory, [
39319
39258
  "diff",
39320
- "--no-ext-diff",
39321
39259
  "-z",
39322
39260
  "--name-only",
39323
39261
  "--diff-filter=ACMR",
@@ -39335,7 +39273,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
39335
39273
  }).pipe(withSpan("Git.diffSelection")),
39336
39274
  stagedFilePaths: (directory) => runGit(directory, [
39337
39275
  "diff",
39338
- "--no-ext-diff",
39339
39276
  "--cached",
39340
39277
  "-z",
39341
39278
  "--name-only",
@@ -39381,7 +39318,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
39381
39318
  if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
39382
39319
  const result = yield* runGit(directory, [
39383
39320
  "diff",
39384
- "--no-ext-diff",
39385
39321
  "--unified=0",
39386
39322
  "--diff-filter=ACMR",
39387
39323
  "--relative",
@@ -43727,4 +43663,4 @@ const toJsonReport = (result, options) => buildJsonReport({
43727
43663
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
43728
43664
 
43729
43665
  //# sourceMappingURL=index.js.map
43730
- //# debugId=a80081fb-3090-5160-8adf-e2652ffe1212
43666
+ //# debugId=526cf949-6544-5cb8-bf6d-3f4d854b6678
package/dist/lsp.js CHANGED
@@ -33102,53 +33102,6 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
33102
33102
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
33103
33103
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
33104
33104
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
33105
- const lastSourceMappingUrl = (fileContent) => {
33106
- const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
33107
- return lastReference ? lastReference[1] : null;
33108
- };
33109
- const mapTargetsSource = (mapContent, input) => {
33110
- const parsedMap = JSON.parse(mapContent);
33111
- if (typeof parsedMap !== "object" || parsedMap === null) return false;
33112
- const { file, sources } = parsedMap;
33113
- if (file !== input.expectedFile) return false;
33114
- if (!Array.isArray(sources) || sources.length !== 1 || typeof sources[0] !== "string") return false;
33115
- return Path.posix.normalize(Path.posix.join(input.mapDirectory, sources[0])) === input.sourcePath;
33116
- };
33117
- const quartetProvesEmit = (stem, sourcePath, readFileText) => {
33118
- try {
33119
- const emitBaseName = Path.posix.basename(stem);
33120
- const mapDirectory = Path.posix.dirname(stem);
33121
- return lastSourceMappingUrl(readFileText(`${stem}.js`)) === `${emitBaseName}.js.map` && lastSourceMappingUrl(readFileText(`${stem}.d.ts`)) === `${emitBaseName}.d.ts.map` && mapTargetsSource(readFileText(`${stem}.js.map`), {
33122
- expectedFile: `${emitBaseName}.js`,
33123
- mapDirectory,
33124
- sourcePath
33125
- }) && mapTargetsSource(readFileText(`${stem}.d.ts.map`), {
33126
- expectedFile: `${emitBaseName}.d.ts`,
33127
- mapDirectory,
33128
- sourcePath
33129
- });
33130
- } catch {
33131
- return false;
33132
- }
33133
- };
33134
- const collectTypeScriptEmitDuplicateJsPaths = (input) => {
33135
- const untracked = new Set(input.untrackedPaths);
33136
- const duplicateJsPaths = /* @__PURE__ */ new Set();
33137
- for (const jsPath of untracked) {
33138
- if (!jsPath.endsWith(".js")) continue;
33139
- const stem = jsPath.slice(0, -3);
33140
- if (![
33141
- jsPath,
33142
- `${stem}.js.map`,
33143
- `${stem}.d.ts`,
33144
- `${stem}.d.ts.map`
33145
- ].every((emitPath) => untracked.has(emitPath) && !input.trackedPaths.has(emitPath))) continue;
33146
- const sourcePath = [`${stem}.ts`, `${stem}.tsx`].find((candidatePath) => input.trackedPaths.has(candidatePath));
33147
- if (!sourcePath) continue;
33148
- if (quartetProvesEmit(stem, sourcePath, input.readFileText)) duplicateJsPaths.add(jsPath);
33149
- }
33150
- return duplicateJsPaths;
33151
- };
33152
33105
  const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
33153
33106
  const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
33154
33107
  const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
@@ -33219,29 +33172,20 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
33219
33172
  }
33220
33173
  return entries;
33221
33174
  };
33222
- const gitLsFiles = (rootDirectory, flags) => {
33175
+ const listSourceFilesViaGit = (rootDirectory) => {
33223
33176
  const result = spawnSync("git", [
33224
33177
  "ls-files",
33225
33178
  "-z",
33226
- ...flags
33179
+ "--cached",
33180
+ "--others",
33181
+ "--exclude-standard"
33227
33182
  ], {
33228
33183
  cwd: rootDirectory,
33229
33184
  encoding: "utf-8",
33230
33185
  maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
33231
33186
  });
33232
33187
  if (result.error || result.status !== 0) return null;
33233
- return result.stdout.split("\0").filter((filePath) => filePath.length > 0);
33234
- };
33235
- const listSourceFilesViaGit = (rootDirectory) => {
33236
- const trackedPaths = gitLsFiles(rootDirectory, ["--cached"]);
33237
- const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
33238
- if (trackedPaths === null || untrackedPaths === null) return null;
33239
- const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
33240
- trackedPaths: new Set(trackedPaths),
33241
- untrackedPaths,
33242
- readFileText: (relativePath) => NFS.readFileSync(Path.resolve(rootDirectory, relativePath), "utf-8")
33243
- });
33244
- return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
33188
+ return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
33245
33189
  };
33246
33190
  const listSourceFilesViaFilesystem = (rootDirectory) => {
33247
33191
  const filePaths = [];
@@ -36054,10 +35998,8 @@ const isDiagnosticSurface = (value) => typeof value === "string" && DIAGNOSTIC_S
36054
35998
  * to the local CLI so developers see them while editing, but they're
36055
35999
  * removed from the PR comment surface, the score, and the CI gate so
36056
36000
  * they can't bury real React findings or fail a build over a Tailwind
36057
- * shorthand. Diagnostics from test and story files likewise remain in
36058
- * raw output while staying out of the production-health score and CI
36059
- * gate. Override per-surface via `config.surfaces.<surface>` to promote
36060
- * individual rules back in by tag, category, or rule id.
36001
+ * shorthand. Override per-surface via `config.surfaces.<surface>` to
36002
+ * promote individual rules back in by tag, category, or rule id.
36061
36003
  */
36062
36004
  const DEFAULT_SURFACE_EXCLUDED_TAGS = {
36063
36005
  cli: [],
@@ -38796,7 +38738,6 @@ const isDiagnosticOnSurface = (diagnostic, surface, config) => {
38796
38738
  if (resolved.includeRuleKeys.has(ruleKey)) return true;
38797
38739
  if (resolved.includeCategories.has(category)) return true;
38798
38740
  if (intersects(tags, resolved.includeTags)) return true;
38799
- if (diagnostic.fileContext !== void 0 && (surface === "score" || surface === "ciFailure")) return false;
38800
38741
  if (resolved.excludeRuleKeys.has(ruleKey)) return false;
38801
38742
  if (resolved.excludeCategories.has(category)) return false;
38802
38743
  if (intersects(tags, resolved.excludeTags)) return false;
@@ -39221,7 +39162,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
39221
39162
  }
39222
39163
  const diff = yield* runGit(input.directory, [
39223
39164
  "diff",
39224
- "--no-ext-diff",
39225
39165
  "-z",
39226
39166
  "--name-only",
39227
39167
  "--diff-filter=ACMR",
@@ -39268,7 +39208,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
39268
39208
  if (resolvedCurrentBranch !== null && resolvedCurrentBranch === baseBranch) {
39269
39209
  const uncommitted = yield* runGit(directory, [
39270
39210
  "diff",
39271
- "--no-ext-diff",
39272
39211
  "-z",
39273
39212
  "--name-only",
39274
39213
  "--diff-filter=ACMR",
@@ -39295,7 +39234,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
39295
39234
  if (mergeBaseRef === null) return null;
39296
39235
  const diff = yield* runGit(directory, [
39297
39236
  "diff",
39298
- "--no-ext-diff",
39299
39237
  "-z",
39300
39238
  "--name-only",
39301
39239
  "--diff-filter=ACMR",
@@ -39313,7 +39251,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
39313
39251
  }).pipe(withSpan("Git.diffSelection")),
39314
39252
  stagedFilePaths: (directory) => runGit(directory, [
39315
39253
  "diff",
39316
- "--no-ext-diff",
39317
39254
  "--cached",
39318
39255
  "-z",
39319
39256
  "--name-only",
@@ -39359,7 +39296,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
39359
39296
  if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
39360
39297
  const result = yield* runGit(directory, [
39361
39298
  "diff",
39362
- "--no-ext-diff",
39363
39299
  "--unified=0",
39364
39300
  "--diff-filter=ACMR",
39365
39301
  "--relative",
@@ -45347,5 +45283,5 @@ const startLanguageServer = () => {
45347
45283
  };
45348
45284
  //#endregion
45349
45285
  export { startLanguageServer };
45350
- !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]="c9d2ed05-185e-5e8c-bab7-8555349d9999")}catch(e){}}();
45351
- //# debugId=c9d2ed05-185e-5e8c-bab7-8555349d9999
45286
+ !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]="3eb1e331-d4d9-517d-a23d-3170e3d3203f")}catch(e){}}();
45287
+ //# debugId=3eb1e331-d4d9-517d-a23d-3170e3d3203f
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.7.9-dev.2450582",
3
+ "version": "0.7.9-dev.2ba83c3",
4
4
  "description": "Your agent writes bad React. This catches it",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -66,7 +66,7 @@
66
66
  "vscode-uri": "^3.1.0",
67
67
  "yaml": "^2.9.0",
68
68
  "deslop-js": "0.7.9",
69
- "oxlint-plugin-react-doctor": "0.7.9-dev.2450582"
69
+ "oxlint-plugin-react-doctor": "0.7.9-dev.2ba83c3"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/babel__code-frame": "^7.27.0",
@@ -74,8 +74,8 @@
74
74
  "@xterm/headless": "^6.0.0",
75
75
  "commander": "^14.0.3",
76
76
  "ora": "^9.4.0",
77
- "@react-doctor/core": "0.7.9",
78
77
  "@react-doctor/api": "0.7.9",
78
+ "@react-doctor/core": "0.7.9",
79
79
  "@react-doctor/language-server": "0.7.9"
80
80
  },
81
81
  "engines": {