react-doctor 0.9.3-dev.ba04952 → 0.9.3-dev.c825c59

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.
Files changed (4) hide show
  1. package/dist/cli.js +228 -304
  2. package/dist/index.js +177 -227
  3. package/dist/lsp.js +181 -204
  4. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
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]="4b6a1dd7-2795-5a24-b1f2-8de4e74574e3")}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]="4a84ec53-f412-5723-a5c5-f6814e010cac")}catch(e){}}();
3
3
  import { i as __toESM$1, r as __require, t as __commonJSMin$1 } from "./chunk-ChKA3wi6.js";
4
4
  import { createRequire } from "node:module";
5
5
  import { 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, REACT_DOCTOR_RULE_REGISTRY, REACT_DOCTOR_SCAN_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor/core";
6
6
  import * as Crypto from "node:crypto";
7
7
  import crypto, { createHash } from "node:crypto";
8
- import * as NFS from "node:fs";
9
- import fs from "node:fs";
10
8
  import * as Path from "node:path";
11
9
  import path from "node:path";
10
+ import * as NFS from "node:fs";
11
+ import fs from "node:fs";
12
12
  import * as NodeChildProcess from "node:child_process";
13
13
  import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
14
14
  import { ResolverFactory } from "oxc-resolver";
@@ -64205,13 +64205,7 @@ const hasReactDependency = (packageJson) => {
64205
64205
  };
64206
64206
  return Object.keys(allDependencies).some((packageName) => REACT_DEPENDENCY_NAMES.has(packageName));
64207
64207
  };
64208
- const getPreactVersion = (packageJson) => {
64209
- return {
64210
- ...packageJson.peerDependencies,
64211
- ...packageJson.dependencies,
64212
- ...packageJson.devDependencies
64213
- }.preact ?? null;
64214
- };
64208
+ const getPreactVersion = (packageJson) => getDependencySpec(packageJson, "preact");
64215
64209
  const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, sourceDirectory = rootDirectory, sourcePackageJson = rootPackageJson, version }) => {
64216
64210
  if (version === null || !isCatalogReference(version)) return version;
64217
64211
  const catalogName = extractCatalogName(version);
@@ -65077,7 +65071,7 @@ const clearProjectCache = () => {
65077
65071
  */
65078
65072
  const discoverProjectWithoutPackageJson = (directory, options) => {
65079
65073
  const sourceFileCount = options.sourceFileCount ?? countSourceFiles(directory);
65080
- const hasOwnTsConfig = NFS.existsSync(Path.join(directory, "tsconfig.json"));
65074
+ const hasOwnTsConfig = isFile(Path.join(directory, "tsconfig.json"));
65081
65075
  const enclosingProjectRoot = findNearestAncestorPackageJson(directory);
65082
65076
  const enclosingProject = enclosingProjectRoot !== null ? discoverProject(enclosingProjectRoot) : null;
65083
65077
  if (enclosingProject !== null) return {
@@ -65213,7 +65207,7 @@ const discoverProject = (directory, options = {}) => {
65213
65207
  const tailwindVersion = tailwindcss.version;
65214
65208
  const zodVersion = zod.version;
65215
65209
  const projectName = packageJson.name ?? Path.basename(directory);
65216
- const hasTypeScript = NFS.existsSync(Path.join(directory, "tsconfig.json"));
65210
+ const hasTypeScript = isFile(Path.join(directory, "tsconfig.json"));
65217
65211
  const sourceFileCount = options.sourceFileCount ?? countSourceFiles(directory);
65218
65212
  const hasReactNativeWorkspace = framework === "expo" || framework === "react-native" || workspaceFacts.hasReactNativeAwarePackage;
65219
65213
  const expoVersion = hasReactNativeWorkspace ? resolveCatalogBackedDependencyVersion({
@@ -65343,134 +65337,6 @@ const discoverProject = (directory, options = {}) => {
65343
65337
  * single source file has nothing to analyze.
65344
65338
  */
65345
65339
  const isAnalyzableProject = (project) => project.reactVersion !== null || project.preactVersion !== null || project.sourceFileCount > 0;
65346
- const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
65347
- var InvalidGlobPatternError = class extends Error {
65348
- pattern;
65349
- reason;
65350
- constructor(pattern, reason) {
65351
- super(`Invalid glob pattern ${JSON.stringify(pattern)}: ${reason}`);
65352
- this.name = "InvalidGlobPatternError";
65353
- this.pattern = pattern;
65354
- this.reason = reason;
65355
- }
65356
- };
65357
- const assertGlobPattern = (condition, pattern, reason) => {
65358
- if (!condition) throw new InvalidGlobPatternError(pattern, reason);
65359
- };
65360
- const countGlobWildcards = (pattern) => (pattern.match(/[*?]/g) ?? []).length;
65361
- const normalizeGlobPattern = (pattern) => pattern.replace(/\\/g, "/").replace(/^\//, "");
65362
- const PICOMATCH_OPTIONS = {
65363
- dot: true,
65364
- strictSlashes: false,
65365
- windows: false
65366
- };
65367
- const compileGlobPattern = (rawPattern) => {
65368
- assertGlobPattern(typeof rawPattern === "string" && rawPattern.length > 0, String(rawPattern), "pattern must be a non-empty string.");
65369
- assertGlobPattern(rawPattern.length <= MAX_GLOB_PATTERN_LENGTH_CHARS, rawPattern, `pattern length ${rawPattern.length} exceeds the maximum of ${MAX_GLOB_PATTERN_LENGTH_CHARS} characters.`);
65370
- const wildcardCount = countGlobWildcards(rawPattern);
65371
- assertGlobPattern(wildcardCount <= 24, rawPattern, `pattern uses ${wildcardCount} wildcards (\`*\` / \`?\`), exceeding the maximum of 24. This guards against catastrophic backtracking from pathological patterns; split the pattern into multiple smaller entries.`);
65372
- try {
65373
- return import_picomatch.default.makeRe(normalizeGlobPattern(rawPattern), PICOMATCH_OPTIONS);
65374
- } catch (caughtError) {
65375
- throw new InvalidGlobPatternError(rawPattern, messageFromUnknown(caughtError));
65376
- }
65377
- };
65378
- const compileGlobPatternsLenient = (patterns, onInvalid) => {
65379
- const compiled = [];
65380
- for (const pattern of patterns) try {
65381
- compiled.push(compileGlobPattern(pattern));
65382
- } catch (caughtError) {
65383
- if (!(caughtError instanceof InvalidGlobPatternError)) throw caughtError;
65384
- onInvalid(caughtError);
65385
- }
65386
- return compiled;
65387
- };
65388
- const toRelativePath = (filePath, rootDirectory) => {
65389
- const normalizedFilePath = filePath.replace(/\\/g, "/");
65390
- const normalizedRoot = rootDirectory.replace(/\\/g, "/").replace(/\/$/, "") + "/";
65391
- if (normalizedFilePath.startsWith(normalizedRoot)) return normalizedFilePath.slice(normalizedRoot.length);
65392
- return normalizedFilePath.replace(/^\.\//, "");
65393
- };
65394
- const warnConfigIssue = (message) => {
65395
- process.stderr.write(`[react-doctor] ${message}\n`);
65396
- };
65397
- const isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
65398
- const collectStringList = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
65399
- const validateOverrideEntry = (entry, index) => {
65400
- if (!isPlainObject(entry)) {
65401
- warnConfigIssue(`ignore.overrides[${index}] must be an object with { files, rules }; ignoring this entry.`);
65402
- return null;
65403
- }
65404
- if (!isStringArray(entry.files)) {
65405
- warnConfigIssue(`ignore.overrides[${index}].files must be an array of strings; ignoring this entry.`);
65406
- return null;
65407
- }
65408
- if (entry.rules !== void 0 && !isStringArray(entry.rules)) {
65409
- warnConfigIssue(`ignore.overrides[${index}].rules must be an array of "plugin/rule" strings or omitted; treating as missing (override would suppress every rule for the matched files).`);
65410
- return { files: entry.files };
65411
- }
65412
- return entry.rules === void 0 ? { files: entry.files } : {
65413
- files: entry.files,
65414
- rules: entry.rules
65415
- };
65416
- };
65417
- const compileIgnoreOverrides = (userConfig) => {
65418
- const overrides = userConfig?.ignore?.overrides;
65419
- if (overrides === void 0) return [];
65420
- if (!Array.isArray(overrides)) {
65421
- warnConfigIssue(`ignore.overrides must be an array of { files, rules } entries; ignoring.`);
65422
- return [];
65423
- }
65424
- return overrides.flatMap((entry, index) => {
65425
- const validated = validateOverrideEntry(entry, index);
65426
- if (!validated) return [];
65427
- const filePatterns = compileGlobPatternsLenient(collectStringList(validated.files), (error) => warnConfigIssue(`ignore.overrides[${index}]: ${error.message}`));
65428
- if (filePatterns.length === 0) return [];
65429
- return [{
65430
- filePatterns,
65431
- ruleIds: new Set(collectStringList(validated.rules))
65432
- }];
65433
- });
65434
- };
65435
- const isDiagnosticIgnoredByOverrides = (diagnostic, rootDirectory, overrides) => {
65436
- if (overrides.length === 0) return false;
65437
- const relativeFilePath = toRelativePath(diagnostic.filePath, rootDirectory);
65438
- const ruleIdentifier = `${diagnostic.plugin}/${diagnostic.rule}`;
65439
- return overrides.some((override) => override.filePatterns.some((pattern) => pattern.test(relativeFilePath)) && (override.ruleIds.size === 0 || override.ruleIds.has(ruleIdentifier)));
65440
- };
65441
- const SEVERITY_FOR_OVERRIDE = {
65442
- error: "error",
65443
- warn: "warning"
65444
- };
65445
- const restampSeverity = (diagnostic, override) => {
65446
- const targetSeverity = SEVERITY_FOR_OVERRIDE[override];
65447
- if (diagnostic.severity === targetSeverity) return diagnostic;
65448
- return {
65449
- ...diagnostic,
65450
- severity: targetSeverity
65451
- };
65452
- };
65453
- /**
65454
- * Assembles the internal `RuleSeverityControls` shape from a user
65455
- * config's top-level `rules` and `categories` fields — the
65456
- * ESLint / oxlint-shaped severity surface.
65457
- *
65458
- * Returns `undefined` when neither field is present so the common
65459
- * path (no severity config at all) stays allocation-free for
65460
- * downstream consumers.
65461
- */
65462
- const buildRuleSeverityControls = (config) => {
65463
- if (!config) return void 0;
65464
- if (config.rules === void 0 && config.categories === void 0 && config.buckets === void 0) return;
65465
- return {
65466
- ...config.rules !== void 0 ? { rules: config.rules } : {},
65467
- ...config.categories !== void 0 ? { categories: config.categories } : {},
65468
- ...config.buckets !== void 0 ? { buckets: config.buckets } : {}
65469
- };
65470
- };
65471
- const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
65472
- const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
65473
- const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
65474
65340
  const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
65475
65341
  "effect/no-adjust-state-on-prop-change": "react-doctor/no-adjust-state-on-prop-change",
65476
65342
  "effect/no-chain-state-updates": "react-doctor/no-chain-state-updates",
@@ -65609,6 +65475,139 @@ const getEquivalentRuleKeys = (ruleKey) => {
65609
65475
  const nativeRuleKey = canonicalizeRuleKey(ruleKey);
65610
65476
  return [nativeRuleKey, ...getLegacyRuleKeysForNative(nativeRuleKey)];
65611
65477
  };
65478
+ const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
65479
+ var InvalidGlobPatternError = class extends Error {
65480
+ pattern;
65481
+ reason;
65482
+ constructor(pattern, reason) {
65483
+ super(`Invalid glob pattern ${JSON.stringify(pattern)}: ${reason}`);
65484
+ this.name = "InvalidGlobPatternError";
65485
+ this.pattern = pattern;
65486
+ this.reason = reason;
65487
+ }
65488
+ };
65489
+ const assertGlobPattern = (condition, pattern, reason) => {
65490
+ if (!condition) throw new InvalidGlobPatternError(pattern, reason);
65491
+ };
65492
+ const countGlobWildcards = (pattern) => (pattern.match(/[*?]/g) ?? []).length;
65493
+ const normalizeGlobPattern = (pattern) => pattern.replace(/\\/g, "/").replace(/^\//, "");
65494
+ const PICOMATCH_OPTIONS = {
65495
+ dot: true,
65496
+ strictSlashes: false,
65497
+ windows: false
65498
+ };
65499
+ const compileGlobPattern = (rawPattern) => {
65500
+ assertGlobPattern(typeof rawPattern === "string" && rawPattern.length > 0, String(rawPattern), "pattern must be a non-empty string.");
65501
+ assertGlobPattern(rawPattern.length <= MAX_GLOB_PATTERN_LENGTH_CHARS, rawPattern, `pattern length ${rawPattern.length} exceeds the maximum of ${MAX_GLOB_PATTERN_LENGTH_CHARS} characters.`);
65502
+ const wildcardCount = countGlobWildcards(rawPattern);
65503
+ assertGlobPattern(wildcardCount <= 24, rawPattern, `pattern uses ${wildcardCount} wildcards (\`*\` / \`?\`), exceeding the maximum of 24. This guards against catastrophic backtracking from pathological patterns; split the pattern into multiple smaller entries.`);
65504
+ try {
65505
+ return import_picomatch.default.makeRe(normalizeGlobPattern(rawPattern), PICOMATCH_OPTIONS);
65506
+ } catch (caughtError) {
65507
+ throw new InvalidGlobPatternError(rawPattern, messageFromUnknown(caughtError));
65508
+ }
65509
+ };
65510
+ const compileGlobPatternsLenient = (patterns, onInvalid) => {
65511
+ const compiled = [];
65512
+ for (const pattern of patterns) try {
65513
+ compiled.push(compileGlobPattern(pattern));
65514
+ } catch (caughtError) {
65515
+ if (!(caughtError instanceof InvalidGlobPatternError)) throw caughtError;
65516
+ onInvalid(caughtError);
65517
+ }
65518
+ return compiled;
65519
+ };
65520
+ const toRelativePath = (filePath, rootDirectory) => {
65521
+ const normalizedFilePath = filePath.replace(/\\/g, "/");
65522
+ const normalizedRoot = rootDirectory.replace(/\\/g, "/").replace(/\/$/, "") + "/";
65523
+ if (normalizedFilePath.startsWith(normalizedRoot)) return normalizedFilePath.slice(normalizedRoot.length);
65524
+ return normalizedFilePath.replace(/^\.\//, "");
65525
+ };
65526
+ const warnConfigIssue = (message) => {
65527
+ process.stderr.write(`[react-doctor] ${message}\n`);
65528
+ };
65529
+ const isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
65530
+ const collectStringList = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
65531
+ const hasMatchingRuleOverride = (ruleIds, ruleIdentifier) => {
65532
+ if (ruleIds.size === 0) return true;
65533
+ for (const ruleId of ruleIds) if (isSameRuleKey(ruleId, ruleIdentifier)) return true;
65534
+ return false;
65535
+ };
65536
+ const validateOverrideEntry = (entry, index) => {
65537
+ if (!isPlainObject(entry)) {
65538
+ warnConfigIssue(`ignore.overrides[${index}] must be an object with { files, rules }; ignoring this entry.`);
65539
+ return null;
65540
+ }
65541
+ if (!isStringArray(entry.files)) {
65542
+ warnConfigIssue(`ignore.overrides[${index}].files must be an array of strings; ignoring this entry.`);
65543
+ return null;
65544
+ }
65545
+ if (entry.rules !== void 0 && !isStringArray(entry.rules)) {
65546
+ warnConfigIssue(`ignore.overrides[${index}].rules must be an array of "plugin/rule" strings or omitted; treating as missing (override would suppress every rule for the matched files).`);
65547
+ return { files: entry.files };
65548
+ }
65549
+ return entry.rules === void 0 ? { files: entry.files } : {
65550
+ files: entry.files,
65551
+ rules: entry.rules
65552
+ };
65553
+ };
65554
+ const compileIgnoreOverrides = (userConfig) => {
65555
+ const overrides = userConfig?.ignore?.overrides;
65556
+ if (overrides === void 0) return [];
65557
+ if (!Array.isArray(overrides)) {
65558
+ warnConfigIssue(`ignore.overrides must be an array of { files, rules } entries; ignoring.`);
65559
+ return [];
65560
+ }
65561
+ return overrides.flatMap((entry, index) => {
65562
+ const validated = validateOverrideEntry(entry, index);
65563
+ if (!validated) return [];
65564
+ const filePatterns = compileGlobPatternsLenient(collectStringList(validated.files), (error) => warnConfigIssue(`ignore.overrides[${index}]: ${error.message}`));
65565
+ if (filePatterns.length === 0) return [];
65566
+ return [{
65567
+ filePatterns,
65568
+ ruleIds: new Set(collectStringList(validated.rules))
65569
+ }];
65570
+ });
65571
+ };
65572
+ const isDiagnosticIgnoredByOverrides = (diagnostic, rootDirectory, overrides) => {
65573
+ if (overrides.length === 0) return false;
65574
+ const relativeFilePath = toRelativePath(diagnostic.filePath, rootDirectory);
65575
+ const ruleIdentifier = `${diagnostic.plugin}/${diagnostic.rule}`;
65576
+ return overrides.some((override) => override.filePatterns.some((pattern) => pattern.test(relativeFilePath)) && hasMatchingRuleOverride(override.ruleIds, ruleIdentifier));
65577
+ };
65578
+ const SEVERITY_FOR_OVERRIDE = {
65579
+ error: "error",
65580
+ warn: "warning"
65581
+ };
65582
+ const restampSeverity = (diagnostic, override) => {
65583
+ const targetSeverity = SEVERITY_FOR_OVERRIDE[override];
65584
+ if (diagnostic.severity === targetSeverity) return diagnostic;
65585
+ return {
65586
+ ...diagnostic,
65587
+ severity: targetSeverity
65588
+ };
65589
+ };
65590
+ /**
65591
+ * Assembles the internal `RuleSeverityControls` shape from a user
65592
+ * config's top-level `rules` and `categories` fields — the
65593
+ * ESLint / oxlint-shaped severity surface.
65594
+ *
65595
+ * Returns `undefined` when neither field is present so the common
65596
+ * path (no severity config at all) stays allocation-free for
65597
+ * downstream consumers.
65598
+ */
65599
+ const buildRuleSeverityControls = (config) => {
65600
+ if (!config) return void 0;
65601
+ if (config.rules === void 0 && config.categories === void 0 && config.buckets === void 0) return;
65602
+ return {
65603
+ ...config.rules !== void 0 ? { rules: config.rules } : {},
65604
+ ...config.categories !== void 0 ? { categories: config.categories } : {},
65605
+ ...config.buckets !== void 0 ? { buckets: config.buckets } : {}
65606
+ };
65607
+ };
65608
+ const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
65609
+ const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
65610
+ const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
65612
65611
  const stripDescriptionTail = (ruleList) => {
65613
65612
  const descriptionMatch = ruleList.match(/(?:^|\s)--\s/);
65614
65613
  if (!descriptionMatch || descriptionMatch.index === void 0) return ruleList;
@@ -66259,12 +66258,8 @@ const buildDiagnosticPipeline = (input) => {
66259
66258
  if (rule.tags.includes("migration-hint")) return false;
66260
66259
  return getFileContext(diagnostic.filePath) !== "production";
66261
66260
  };
66262
- const isRuleIgnored = (ruleIdentifier) => {
66263
- for (const ignored of ignoredRules) if (isSameRuleKey(ignored, ruleIdentifier)) return true;
66264
- return false;
66265
- };
66266
- const isAppOnlyRule = (ruleIdentifier) => {
66267
- for (const appOnlyRuleKey of APP_ONLY_RULE_KEYS) if (isSameRuleKey(appOnlyRuleKey, ruleIdentifier)) return true;
66261
+ const matchesRuleKey = (ruleIdentifier, candidates) => {
66262
+ for (const candidate of candidates) if (isSameRuleKey(candidate, ruleIdentifier)) return true;
66268
66263
  return false;
66269
66264
  };
66270
66265
  const isRnRawTextSuppressedByConfig = (diagnostic) => {
@@ -66306,12 +66301,13 @@ const buildDiagnosticPipeline = (input) => {
66306
66301
  if (explicitSeverityOverride === "off") return suppress(current, "config");
66307
66302
  if (explicitSeverityOverride !== void 0) current = restampSeverity(current, explicitSeverityOverride);
66308
66303
  }
66304
+ const ruleIdentifier = `${current.plugin}/${current.rule}`;
66309
66305
  if (explicitRuleOverride === void 0) {
66310
- if (isAppOnlyRule(`${current.plugin}/${current.rule}`) && isLibraryFile(current.filePath)) return null;
66306
+ if (matchesRuleKey(ruleIdentifier, APP_ONLY_RULE_KEYS) && isLibraryFile(current.filePath)) return null;
66311
66307
  }
66312
66308
  if (!showWarnings && current.severity === "warning" && explicitSeverityOverride !== "warn") return null;
66313
66309
  if (userConfig) {
66314
- if (isRuleIgnored(`${current.plugin}/${current.rule}`)) return suppress(current, "config");
66310
+ if (matchesRuleKey(ruleIdentifier, ignoredRules)) return suppress(current, "config");
66315
66311
  if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
66316
66312
  if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return suppress(current, "override");
66317
66313
  if (isRnRawTextSuppressedByConfig(current)) return null;
@@ -66320,7 +66316,6 @@ const buildDiagnosticPipeline = (input) => {
66320
66316
  if (respectInlineDisables && current.line > 0) {
66321
66317
  const lines = getFileLines(current.filePath);
66322
66318
  if (lines) {
66323
- const ruleIdentifier = `${current.plugin}/${current.rule}`;
66324
66319
  const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
66325
66320
  if (evaluation.isSuppressed) return suppress(current, evaluation.isForeignDirective ? "foreign-inline" : "inline");
66326
66321
  if (evaluation.nearMissHint) current = {
@@ -66816,6 +66811,7 @@ const DEFAULT_SURFACE_EXCLUDED_TAGS = {
66816
66811
  score: ["design"],
66817
66812
  ciFailure: ["design"]
66818
66813
  };
66814
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
66819
66815
  const VALID_RULE_SEVERITIES = [
66820
66816
  "error",
66821
66817
  "warn",
@@ -66858,7 +66854,6 @@ const SURFACE_CONTROL_FIELD_NAMES = [
66858
66854
  ];
66859
66855
  const isIncludedFileContext = (value) => VALID_INCLUDED_FILE_CONTEXTS.some((fileContext) => fileContext === value);
66860
66856
  const SEVERITY_FIELD_NAMES = ["rules", "categories"];
66861
- const isPlainObject$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
66862
66857
  const formatType = (value) => typeof value === "string" ? `"${value}"` : typeof value;
66863
66858
  const isRuleSeverity = (value) => typeof value === "string" && VALID_RULE_SEVERITIES.includes(value);
66864
66859
  const coerceMaybeBooleanString = (fieldName, value) => {
@@ -66886,7 +66881,7 @@ const validateStringArrayField = (fieldName, value) => {
66886
66881
  });
66887
66882
  };
66888
66883
  const validateSurfaceControls = (surface, rawControls) => {
66889
- if (!isPlainObject$1(rawControls)) {
66884
+ if (!isRecord(rawControls)) {
66890
66885
  warnConfigIssue(`config field "surfaces.${surface}" must be an object (got ${typeof rawControls}); ignoring this surface.`);
66891
66886
  return;
66892
66887
  }
@@ -66910,7 +66905,7 @@ const validateSurfaceControls = (surface, rawControls) => {
66910
66905
  return validatedSurfaceControls;
66911
66906
  };
66912
66907
  const validateSurfacesField = (rawSurfaces) => {
66913
- if (!isPlainObject$1(rawSurfaces)) {
66908
+ if (!isRecord(rawSurfaces)) {
66914
66909
  warnConfigIssue(`config field "surfaces" must be an object (got ${typeof rawSurfaces}); ignoring this field.`);
66915
66910
  return;
66916
66911
  }
@@ -66926,7 +66921,7 @@ const validateSurfacesField = (rawSurfaces) => {
66926
66921
  return validated;
66927
66922
  };
66928
66923
  const validateSeverityMap = (fieldName, rawMap, keysAreCategories = false) => {
66929
- if (!isPlainObject$1(rawMap)) {
66924
+ if (!isRecord(rawMap)) {
66930
66925
  warnConfigIssue(`config field "${fieldName}" must be an object (got ${typeof rawMap}); ignoring this field.`);
66931
66926
  return;
66932
66927
  }
@@ -69280,25 +69275,18 @@ const collectIgnorePatterns = (rootDirectory) => {
69280
69275
  cachedPatternsByRoot.set(rootDirectory, patterns);
69281
69276
  return patterns;
69282
69277
  };
69283
- const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
69284
- const KNIP_JSON_FILENAME = "knip.json";
69285
- const readJsonFileSafe = (filePath) => {
69286
- let rawContents;
69287
- try {
69288
- rawContents = fs.readFileSync(filePath, "utf-8");
69289
- } catch {
69290
- return null;
69291
- }
69278
+ const failOpenReadJson = (filePath, fallback) => {
69292
69279
  try {
69293
- return JSON.parse(rawContents);
69280
+ return JSON.parse(NFS.readFileSync(filePath, "utf8"));
69294
69281
  } catch {
69295
- return null;
69282
+ return fallback;
69296
69283
  }
69297
69284
  };
69285
+ const KNIP_JSON_FILENAME = "knip.json";
69298
69286
  const readKnipConfig = (rootDirectory) => {
69299
- const knipJson = readJsonFileSafe(path.join(rootDirectory, KNIP_JSON_FILENAME));
69287
+ const knipJson = failOpenReadJson(path.join(rootDirectory, KNIP_JSON_FILENAME), null);
69300
69288
  if (isRecord(knipJson)) return knipJson;
69301
- const packageJson = readJsonFileSafe(path.join(rootDirectory, "package.json"));
69289
+ const packageJson = failOpenReadJson(path.join(rootDirectory, "package.json"), null);
69302
69290
  const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
69303
69291
  return isRecord(packageKnipConfig) ? packageKnipConfig : null;
69304
69292
  };
@@ -69346,13 +69334,6 @@ const atomicWriteJson = (filePath, value) => {
69346
69334
  return;
69347
69335
  }
69348
69336
  };
69349
- const failOpenReadJson = (filePath, fallback) => {
69350
- try {
69351
- return JSON.parse(NFS.readFileSync(filePath, "utf8"));
69352
- } catch {
69353
- return fallback;
69354
- }
69355
- };
69356
69337
  const hashFileContents = (filePath) => {
69357
69338
  try {
69358
69339
  return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
@@ -71394,11 +71375,17 @@ const collectUnpluginAutoImportGlobalScopes = ({ rootDirectory, candidateFiles }
71394
71375
  return scopes.some((scope) => scope.names.length > 0) ? scopes : [];
71395
71376
  };
71396
71377
  const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
71378
+ const decodeDiagnostic = (raw) => {
71379
+ const diagnostic = validateDiagnostic$1(raw);
71380
+ return {
71381
+ ...diagnostic,
71382
+ relatedLocations: diagnostic.relatedLocations?.map((location) => ({ ...location }))
71383
+ };
71384
+ };
71397
71385
  const decodeFileDiagnostics = (raw) => {
71398
71386
  if (!Array.isArray(raw)) return null;
71399
71387
  try {
71400
- for (const entry of raw) validateDiagnostic$1(entry);
71401
- return raw;
71388
+ return raw.map((entry) => decodeDiagnostic(entry));
71402
71389
  } catch {
71403
71390
  return null;
71404
71391
  }
@@ -74693,10 +74680,6 @@ const NO_HOOKS = {
74693
74680
  beforeLint: () => void_,
74694
74681
  afterLint: () => void_
74695
74682
  };
74696
- const filterMapNullable = (transform) => fromPredicateOption((value) => {
74697
- const result = transform(value);
74698
- return result === null ? none() : some(result);
74699
- });
74700
74683
  const fileReader = (filesService, rootDirectory) => (filePath) => {
74701
74684
  const lines = runSync(filesService.readLines({
74702
74685
  filePath,
@@ -74720,7 +74703,7 @@ const formatLintFailText = (reasonTag, nodeVersion) => {
74720
74703
  * The GitHub viewer-permission lookup is forked onto a background
74721
74704
  * fiber here and joined late (it feeds score metadata, not
74722
74705
  * diagnostics).
74723
- * 2. beforeLint hook (e.g. CLI renders the project-detection block)
74706
+ * 2. beforeLint hook (e.g. CLI records project telemetry)
74724
74707
  * 3. environment checks (reduced-motion + pnpm hardening +
74725
74708
  * expo/react-native), collected synchronously. The heavier
74726
74709
  * content-regex security scan is forked instead (like supply-chain
@@ -74733,13 +74716,11 @@ const formatLintFailText = (reasonTag, nodeVersion) => {
74733
74716
  * `SupplyChainOverlapTimeoutMs` (measured from fork) so a hung
74734
74717
  * socket can't drag out its join; on timeout it fails open to no
74735
74718
  * diagnostics — the same outcome class as a Socket outage.
74736
- * 5. Linter.run runs; DeadCode.run runs concurrently (forked child
74737
- * fiber) ONLY when the memory gate has headroom to run the 8 GB
74738
- * dead-code child alongside the oxlint workers — or when overlap is
74739
- * forced via REACT_DOCTOR_DEAD_CODE_OVERLAP. Otherwise dead-code
74740
- * runs sequentially after lint, exactly as it did pre-overlap. The
74741
- * fiber is joined (or interrupted, SIGKILLing its worker, on lint
74742
- * failure) before diagnostics are concatenated. The afterLint hook
74719
+ * 5. Linter.run runs; DeadCode.run forks only when
74720
+ * REACT_DOCTOR_DEAD_CODE_OVERLAP=on. The default "auto" and explicit
74721
+ * "off" paths stay sequential. The fiber is joined (or interrupted,
74722
+ * SIGKILLing its worker, on lint failure) before diagnostics are
74723
+ * concatenated. The afterLint hook
74743
74724
  * fires between lint and dead-code. Progress spinner labels AND the
74744
74725
  * final diagnostic / score order stay independent of execution
74745
74726
  * order, so terminal output is identical either way; supply-chain
@@ -74815,7 +74796,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
74815
74796
  const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? includedPrecomputedSourceFiles ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
74816
74797
  const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
74817
74798
  const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
74818
- yield* beforeLint(project, lintIncludePaths ?? void 0);
74799
+ yield* beforeLint(project);
74819
74800
  const isDiffMode = input.includePaths.length > 0;
74820
74801
  const showWarnings = input.warnings ?? resolvedConfig.config?.warnings ?? true;
74821
74802
  const transform = buildDiagnosticPipeline({
@@ -74825,7 +74806,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
74825
74806
  respectInlineDisables: input.respectInlineDisables,
74826
74807
  showWarnings
74827
74808
  });
74828
- const filterPerElementPipeline = (rawStream) => rawStream.pipe(filterMap(filterMapNullable(transform.apply)));
74809
+ const filterPerElementPipeline = (rawStream) => rawStream.pipe(filterMap(fromPredicateOption((diagnostic) => {
74810
+ const filteredDiagnostic = transform.apply(diagnostic);
74811
+ return filteredDiagnostic === null ? none() : some(filteredDiagnostic);
74812
+ })));
74829
74813
  const applyPerElementPipeline = (rawStream) => filterPerElementPipeline(rawStream).pipe(tap((diagnostic) => reporterService.emit(diagnostic)));
74830
74814
  const envCollected = yield* runCollect(applyPerElementPipeline(fromIterable$1(isDiffMode ? [] : [
74831
74815
  ...checkReducedMotion(scanDirectory),
@@ -75538,14 +75522,6 @@ const getDiffInfo = (directory, explicitBaseBranch, includeUntracked) => runProm
75538
75522
  };
75539
75523
  }).pipe(provide(Git.layerNode)));
75540
75524
  const filterSourceFiles = (filePaths) => filePaths.filter(isLintableSourceFile);
75541
- /**
75542
- * Back-compat alias: the streaming pipeline holds its caches in
75543
- * per-pipeline closures that are garbage-collected when the pipeline
75544
- * goes out of scope, so there is nothing to clear at module scope. The
75545
- * public CLI's `clearCaches()` still calls this for symmetry with the
75546
- * other `clear*` helpers.
75547
- */
75548
- const clearAutoSuppressionCaches = () => {};
75549
75525
  const createLintPhaseAbortError = () => new ReactDoctorError({ reason: new OxlintSpawnFailed({ cause: "lint phase aborted" }) });
75550
75526
  const createOxlintSpawnSlots = (concurrency) => createWorkerSlots({
75551
75527
  slotCount: resolveScanConcurrency(concurrency),
@@ -75558,59 +75534,34 @@ const createOxlintSpawnSlots = (concurrency) => createWorkerSlots({
75558
75534
  * untouched so the loader sees the same plain object either way.
75559
75535
  */
75560
75536
  const defineConfig = (config) => config;
75561
- const AI_TRAINING_ENV_VARS = [
75562
- ["HF_DATASETS_CACHE", "huggingface"],
75563
- ["HF_HOME", "huggingface"],
75564
- ["HUGGINGFACE_HUB_CACHE", "huggingface"],
75565
- ["SPACE_ID", "huggingface-spaces"],
75566
- ["CUDA_VISIBLE_DEVICES", "cuda"],
75567
- ["NVIDIA_VISIBLE_DEVICES", "nvidia"],
75568
- ["ROCR_VISIBLE_DEVICES", "rocm"],
75569
- ["TPU_NAME", "google-tpu"],
75537
+ const AI_TRAINING_BY_ENVIRONMENT_VARIABLE = [
75570
75538
  ["WANDB_RUN_ID", "wandb"],
75571
75539
  ["WANDB_SWEEP_ID", "wandb"],
75572
75540
  ["MLFLOW_RUN_ID", "mlflow"],
75573
- ["MLFLOW_TRACKING_URI", "mlflow"],
75574
75541
  ["COMET_EXPERIMENT_KEY", "comet"],
75575
75542
  ["NEPTUNE_RUN_ID", "neptune"],
75576
75543
  ["CLEARML_TASK_ID", "clearml"],
75577
75544
  ["DVC_STAGE", "dvc"],
75578
75545
  ["RAY_WORKER_PROCESS", "ray"],
75579
- ["RAY_ADDRESS", "ray"],
75580
- ["MUJOCO_GL", "mujoco"],
75581
- ["MUJOCO_PATH", "mujoco"],
75582
- ["GYM_DISABLE_ENV_CHECKER", "gymnasium"],
75583
75546
  ["SM_TRAINING_ENV", "sagemaker"],
75584
75547
  ["TRAINING_JOB_ARN", "sagemaker"],
75585
- ["SAGEMAKER_BASE_DIR", "sagemaker"],
75586
75548
  ["AZUREML_RUN_ID", "azure-ml"],
75587
- ["AZURE_ML_MODEL_DIR", "azure-ml"],
75588
- ["CLOUD_ML_PROJECT_ID", "vertex-ai"],
75589
- ["VERTEX_AI_LOG_LEVEL", "vertex-ai"],
75590
- ["DET_MASTER", "determined-ai"],
75591
- ["LIGHTNING_USER_ID", "lightning-ai"],
75592
75549
  ["FLYTE_INTERNAL_EXECUTION_ID", "flyte"],
75593
- ["ARGO_WORKFLOW_NAME", "argo-workflows"],
75594
75550
  ["KFP_POD_NAME", "kubeflow-pipelines"],
75595
75551
  ["KAGGLE_KERNEL_RUN_TYPE", "kaggle"],
75596
75552
  ["COLAB_BACKEND_VERSION", "google-colab"],
75597
- ["DATABRICKS_RUNTIME_VERSION", "databricks"],
75598
75553
  ["DAYTONA_WS_ID", "daytona"],
75599
- ["DAYTONA_WS_NAME", "daytona"],
75600
75554
  ["E2B_SANDBOX_ID", "e2b"],
75601
75555
  ["MODAL_FUNCTION_ID", "modal"],
75602
75556
  ["MODAL_TASK_ID", "modal"],
75603
75557
  ["RUNPOD_POD_ID", "runpod"],
75604
- ["REPLICATE_USERNAME", "replicate"],
75605
75558
  ["VAST_CONTAINERLABEL", "vast-ai"],
75606
- ["HARBOR_URL", "harbor"],
75607
- ["HARBOR_HOSTNAME", "harbor"],
75608
75559
  ["SWE_BENCH_TASK", "swe-bench"],
75609
75560
  ["SWEBENCH_TASK", "swe-bench"],
75610
75561
  ["SWE_AGENT_MODEL", "swe-agent"]
75611
75562
  ];
75612
- const detectAiTrainingEnvironment = () => {
75613
- for (const [envVar, label] of AI_TRAINING_ENV_VARS) if (process.env[envVar]) return label;
75563
+ const detectAiTrainingEnvironment = (environment = process.env) => {
75564
+ for (const [environmentVariable, label] of AI_TRAINING_BY_ENVIRONMENT_VARIABLE) if (environment[environmentVariable]?.trim()) return label;
75614
75565
  return null;
75615
75566
  };
75616
75567
  const unionValues = (baseValues, overrideValues) => [...new Set([...baseValues, ...overrideValues])];
@@ -75804,7 +75755,6 @@ const clearCaches = () => {
75804
75755
  clearPackageJsonCache();
75805
75756
  clearIgnorePatternsCache();
75806
75757
  clearPackageRoleCache();
75807
- clearAutoSuppressionCaches();
75808
75758
  clearMinifiedFileCache();
75809
75759
  };
75810
75760
  const toJsonReport = (result, options) => buildJsonReport({
@@ -75831,4 +75781,4 @@ const toJsonReport = (result, options) => buildJsonReport({
75831
75781
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
75832
75782
 
75833
75783
  //# sourceMappingURL=index.js.map
75834
- //# debugId=4b6a1dd7-2795-5a24-b1f2-8de4e74574e3
75784
+ //# debugId=4a84ec53-f412-5723-a5c5-f6814e010cac