react-doctor 0.5.8-dev.8232e96 → 0.5.8-dev.88a5c3c

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 +272 -333
  2. package/dist/index.js +223 -251
  3. package/dist/lsp.js +246 -274
  4. package/package.json +4 -4
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]="62cf4740-7938-5db0-8b80-dc81b60af36a")}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]="7cfd5199-4216-5c6e-8cf5-c9623c317a1e")}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 * as NFS from "node:fs";
@@ -32789,31 +32789,12 @@ const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
32789
32789
  const MINIFIED_SNIFF_BYTES = 65536;
32790
32790
  const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
32791
32791
  const IGNORED_DIRECTORIES = new Set([
32792
- ".angular",
32793
- ".astro",
32794
- ".cache",
32795
- ".contentlayer",
32796
- ".direnv",
32797
- ".docusaurus",
32798
- ".expo",
32799
- ".firebase",
32800
32792
  ".git",
32801
- ".gradle",
32802
- ".hg",
32803
32793
  ".next",
32804
32794
  ".nuxt",
32805
- ".nx",
32806
32795
  ".output",
32807
- ".parcel-cache",
32808
- ".serverless",
32809
32796
  ".svelte-kit",
32810
- ".svn",
32811
- ".terraform",
32812
32797
  ".turbo",
32813
- ".venv",
32814
- ".vercel",
32815
- ".wrangler",
32816
- ".yarn",
32817
32798
  "build",
32818
32799
  "coverage",
32819
32800
  "dist",
@@ -32821,119 +32802,6 @@ const IGNORED_DIRECTORIES = new Set([
32821
32802
  "out",
32822
32803
  "storybook-static"
32823
32804
  ]);
32824
- const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
32825
- const MILLISECONDS_PER_SECOND = 1e3;
32826
- const SCORE_API_URL = "https://www.react.doctor/api/score";
32827
- const FETCH_TIMEOUT_MS = 1e4;
32828
- const GITHUB_VIEWER_PERMISSION_TIMEOUT_MS = 2e3;
32829
- const SPAWN_ARGS_MAX_LENGTH_CHARS = 24e3;
32830
- const SPAWN_ARGS_MAX_LENGTH_CHARS_POSIX = 15e5;
32831
- const SPAWN_ARGS_MAX_LENGTH_CHARS_DARWIN = 8e5;
32832
- const NODE_VERSION_PROBE_TIMEOUT_MS = 5e3;
32833
- const PER_WORKER_MEM_BUDGET_BYTES = 1024 * 1024 * 1024;
32834
- const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
32835
- const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
32836
- const GIT_SHOW_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
32837
- const ES_TARGET_YEAR_BY_NAME = {
32838
- es3: 1999,
32839
- es5: 2009,
32840
- es6: 2015,
32841
- es2015: 2015,
32842
- es2016: 2016,
32843
- es2017: 2017,
32844
- es2018: 2018,
32845
- es2019: 2019,
32846
- es2020: 2020,
32847
- es2021: 2021,
32848
- es2022: 2022,
32849
- es2023: 2023,
32850
- es2024: 2024,
32851
- es2025: 2025,
32852
- esnext: 9999
32853
- };
32854
- /**
32855
- * tsconfig filenames probed when resolving a project's TypeScript
32856
- * compiler options — the root config first, then a monorepo base config.
32857
- */
32858
- const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
32859
- /**
32860
- * Project-config files that `StagedFiles.materialize` copies into
32861
- * the temp directory alongside staged sources so oxlint resolves
32862
- * `tsconfig` / `package.json` / lint configs the same way it would
32863
- * in the working tree. Hoisted out of the staged-files helper so
32864
- * the constant lives next to the rest of the IO budget knobs.
32865
- */
32866
- const STAGED_FILES_PROJECT_CONFIG_FILENAMES = [
32867
- "tsconfig.json",
32868
- "tsconfig.base.json",
32869
- "package.json",
32870
- "doctor.config.ts",
32871
- "doctor.config.mts",
32872
- "doctor.config.cts",
32873
- "doctor.config.js",
32874
- "doctor.config.mjs",
32875
- "doctor.config.cjs",
32876
- "doctor.config.json",
32877
- "doctor.config.jsonc",
32878
- "oxlint.json",
32879
- ".oxlintrc.json"
32880
- ];
32881
- const OXLINT_OUTPUT_MAX_BYTES = 50 * 1024 * 1024;
32882
- const OXLINT_SPAWN_TIMEOUT_MS = 6e4;
32883
- const NODE_COMPILE_CACHE_DIR_NAME = "node-compile-cache";
32884
- const DEAD_CODE_WORKER_TIMEOUT_MS = 12e4;
32885
- const OXLINT_SPLIT_TOTAL_BUDGET_MS = 18e4;
32886
- const DEAD_CODE_PHASE_TIMEOUT_MS = 15e4;
32887
- const LINT_PHASE_TIMEOUT_MS = 3e5;
32888
- const SCAN_TOTAL_DEADLINE_MS = 9e5;
32889
- const DEAD_CODE_WORKER_MAX_OLD_SPACE_MB = 8192;
32890
- const DEAD_CODE_WORKER_MEM_BUDGET_BYTES = 2 * 1024 * 1024 * 1024;
32891
- const DEAD_CODE_TIMEOUT_CEILING_MS = 6e5;
32892
- const DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS = 3e4;
32893
- const DEAD_CODE_OVERLAP_PARSE_SHARE = .4;
32894
- const RECOMMENDED_PNPM_MINIMUM_RELEASE_AGE_MINUTES = 10080;
32895
- const REACT_SERVER_DOM_PACKAGES = [
32896
- "react-server-dom-webpack",
32897
- "react-server-dom-parcel",
32898
- "react-server-dom-turbopack"
32899
- ];
32900
- const REACT_BLOG_RSC_ADVISORY_URL = "https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components";
32901
- const VERCEL_NEXTJS_SECURITY_RELEASE_URL = "https://vercel.com/changelog/next-js-may-2026-security-release";
32902
- const DIAGNOSTIC_CATEGORY_BUCKETS = [
32903
- "Security",
32904
- "Bugs",
32905
- "Performance",
32906
- "Accessibility",
32907
- "Maintainability"
32908
- ];
32909
- const APP_ONLY_RULE_KEYS = new Set([
32910
- "react-hooks-js/static-components",
32911
- "react-doctor/no-render-prop-children",
32912
- "react-doctor/prefer-explicit-variants"
32913
- ]);
32914
- const COMPILER_CLEANUP_BUCKET = "compiler-cleanup";
32915
- const COMPILER_CLEANUP_RULE_KEYS = new Set(["react-doctor/react-compiler-no-manual-memoization"]);
32916
- const ROOT_CAUSE_GROUPABLE_RULE_KEYS = new Set([
32917
- "react-doctor/no-derived-state",
32918
- "react-doctor/no-derived-state-effect",
32919
- "react-doctor/no-derived-useState",
32920
- "react-doctor/no-adjust-state-on-prop-change",
32921
- "react-doctor/no-reset-all-state-on-prop-change"
32922
- ]);
32923
- const MAX_GLOB_PATTERN_LENGTH_CHARS = 1024;
32924
- const CONFIG_CACHE_TTL_MS = 300 * 1e3;
32925
- const SOCKET_FREE_PURL_API_BASE = "https://firewall-api.socket.dev/purl";
32926
- const SOCKET_PACKAGE_PAGE_BASE = "https://socket.dev/npm/package";
32927
- const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
32928
- const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
32929
- const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
32930
- const SUPPLY_CHAIN_PLUGIN = "socket";
32931
- const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
32932
- const SUPPLY_CHAIN_CATEGORY = "Security";
32933
- const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
32934
- const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
32935
- const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
32936
- const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => IGNORED_DIRECTORIES.has(segment));
32937
32805
  const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath);
32938
32806
  const isMinifiedSource = (absolutePath) => {
32939
32807
  let fileDescriptor;
@@ -32990,38 +32858,23 @@ const readDirectoryEntries = (directoryPath) => {
32990
32858
  throw error;
32991
32859
  }
32992
32860
  };
32993
- function* walkSourceTreeFiles(rootDirectory) {
32861
+ const countSourceFilesViaFilesystem = (rootDirectory) => {
32862
+ let count = 0;
32994
32863
  const stack = [rootDirectory];
32995
32864
  while (stack.length > 0) {
32996
32865
  const currentDirectory = stack.pop();
32997
- if (currentDirectory === void 0) continue;
32998
- for (const entry of readDirectoryEntries(currentDirectory)) {
32999
- const absolutePath = Path.join(currentDirectory, entry.name);
32866
+ const entries = readDirectoryEntries(currentDirectory);
32867
+ for (const entry of entries) {
33000
32868
  if (entry.isDirectory()) {
33001
- if (!IGNORED_DIRECTORIES.has(entry.name)) stack.push(absolutePath);
32869
+ if (!entry.name.startsWith(".") && !IGNORED_DIRECTORIES.has(entry.name)) stack.push(Path.join(currentDirectory, entry.name));
33002
32870
  continue;
33003
32871
  }
33004
- if (entry.isFile()) yield {
33005
- absolutePath,
33006
- name: entry.name
33007
- };
32872
+ if (entry.isFile() && isLintableSourceFile(entry.name) && !isLargeMinifiedFile(Path.join(currentDirectory, entry.name))) count++;
33008
32873
  }
33009
32874
  }
33010
- }
33011
- const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
33012
- const entries = [];
33013
- for (const relativePath of relativePaths) {
33014
- const absolutePath = Path.resolve(rootDirectory, relativePath);
33015
- const sizeBytes = statSourceFileSize(absolutePath);
33016
- if (isLargeMinifiedFile(absolutePath, sizeBytes)) continue;
33017
- entries.push({
33018
- path: relativePath,
33019
- sizeBytes: sizeBytes ?? 0
33020
- });
33021
- }
33022
- return entries;
32875
+ return count;
33023
32876
  };
33024
- const listSourceFilesViaGit = (rootDirectory) => {
32877
+ const countSourceFilesViaGit = (rootDirectory) => {
33025
32878
  const result = spawnSync("git", [
33026
32879
  "ls-files",
33027
32880
  "-z",
@@ -33034,16 +32887,9 @@ const listSourceFilesViaGit = (rootDirectory) => {
33034
32887
  maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
33035
32888
  });
33036
32889
  if (result.error || result.status !== 0) return null;
33037
- return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
32890
+ return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !isLargeMinifiedFile(Path.resolve(rootDirectory, filePath))).length;
33038
32891
  };
33039
- const listSourceFilesViaFilesystem = (rootDirectory) => {
33040
- const filePaths = [];
33041
- for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) if (isLintableSourceFile(name)) filePaths.push(Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/"));
33042
- return filePaths;
33043
- };
33044
- const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort());
33045
- const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
33046
- const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
32892
+ const countSourceFiles = (rootDirectory) => countSourceFilesViaGit(rootDirectory) ?? countSourceFilesViaFilesystem(rootDirectory);
33047
32893
  const cachedPackageJsons = /* @__PURE__ */ new Map();
33048
32894
  const clearPackageJsonCache = () => {
33049
32895
  cachedPackageJsons.clear();
@@ -33852,6 +33698,118 @@ const resolveEffectiveReactMajor = (reactVersion, packageJson) => {
33852
33698
  if (peerFloor === null) return hasUpperBoundOnlyPeerRange(peerReactRange) ? null : installedReactMajor;
33853
33699
  return installedReactMajor !== null ? Math.min(installedReactMajor, peerFloor) : peerFloor;
33854
33700
  };
33701
+ const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
33702
+ const MILLISECONDS_PER_SECOND = 1e3;
33703
+ const SCORE_API_URL = "https://www.react.doctor/api/score";
33704
+ const FETCH_TIMEOUT_MS = 1e4;
33705
+ const GITHUB_VIEWER_PERMISSION_TIMEOUT_MS = 2e3;
33706
+ const SPAWN_ARGS_MAX_LENGTH_CHARS = 24e3;
33707
+ const SPAWN_ARGS_MAX_LENGTH_CHARS_POSIX = 15e5;
33708
+ const SPAWN_ARGS_MAX_LENGTH_CHARS_DARWIN = 8e5;
33709
+ const NODE_VERSION_PROBE_TIMEOUT_MS = 5e3;
33710
+ const PER_WORKER_MEM_BUDGET_BYTES = 1024 * 1024 * 1024;
33711
+ const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
33712
+ const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
33713
+ const GIT_SHOW_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
33714
+ const ES_TARGET_YEAR_BY_NAME = {
33715
+ es3: 1999,
33716
+ es5: 2009,
33717
+ es6: 2015,
33718
+ es2015: 2015,
33719
+ es2016: 2016,
33720
+ es2017: 2017,
33721
+ es2018: 2018,
33722
+ es2019: 2019,
33723
+ es2020: 2020,
33724
+ es2021: 2021,
33725
+ es2022: 2022,
33726
+ es2023: 2023,
33727
+ es2024: 2024,
33728
+ es2025: 2025,
33729
+ esnext: 9999
33730
+ };
33731
+ /**
33732
+ * tsconfig filenames probed when resolving a project's TypeScript
33733
+ * compiler options — the root config first, then a monorepo base config.
33734
+ */
33735
+ const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
33736
+ /**
33737
+ * Project-config files that `StagedFiles.materialize` copies into
33738
+ * the temp directory alongside staged sources so oxlint resolves
33739
+ * `tsconfig` / `package.json` / lint configs the same way it would
33740
+ * in the working tree. Hoisted out of the staged-files helper so
33741
+ * the constant lives next to the rest of the IO budget knobs.
33742
+ */
33743
+ const STAGED_FILES_PROJECT_CONFIG_FILENAMES = [
33744
+ "tsconfig.json",
33745
+ "tsconfig.base.json",
33746
+ "package.json",
33747
+ "doctor.config.ts",
33748
+ "doctor.config.mts",
33749
+ "doctor.config.cts",
33750
+ "doctor.config.js",
33751
+ "doctor.config.mjs",
33752
+ "doctor.config.cjs",
33753
+ "doctor.config.json",
33754
+ "doctor.config.jsonc",
33755
+ "oxlint.json",
33756
+ ".oxlintrc.json"
33757
+ ];
33758
+ const OXLINT_OUTPUT_MAX_BYTES = 50 * 1024 * 1024;
33759
+ const OXLINT_SPAWN_TIMEOUT_MS = 6e4;
33760
+ const NODE_COMPILE_CACHE_DIR_NAME = "node-compile-cache";
33761
+ const DEAD_CODE_WORKER_TIMEOUT_MS = 12e4;
33762
+ const OXLINT_SPLIT_TOTAL_BUDGET_MS = 18e4;
33763
+ const DEAD_CODE_PHASE_TIMEOUT_MS = 15e4;
33764
+ const LINT_PHASE_TIMEOUT_MS = 3e5;
33765
+ const SCAN_TOTAL_DEADLINE_MS = 9e5;
33766
+ const DEAD_CODE_WORKER_MAX_OLD_SPACE_MB = 8192;
33767
+ const DEAD_CODE_WORKER_MEM_BUDGET_BYTES = 2 * 1024 * 1024 * 1024;
33768
+ const DEAD_CODE_TIMEOUT_CEILING_MS = 6e5;
33769
+ const DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS = 3e4;
33770
+ const DEAD_CODE_OVERLAP_PARSE_SHARE = .4;
33771
+ const RECOMMENDED_PNPM_MINIMUM_RELEASE_AGE_MINUTES = 10080;
33772
+ const REACT_SERVER_DOM_PACKAGES = [
33773
+ "react-server-dom-webpack",
33774
+ "react-server-dom-parcel",
33775
+ "react-server-dom-turbopack"
33776
+ ];
33777
+ const REACT_BLOG_RSC_ADVISORY_URL = "https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components";
33778
+ const VERCEL_NEXTJS_SECURITY_RELEASE_URL = "https://vercel.com/changelog/next-js-may-2026-security-release";
33779
+ const DIAGNOSTIC_CATEGORY_BUCKETS = [
33780
+ "Security",
33781
+ "Bugs",
33782
+ "Performance",
33783
+ "Accessibility",
33784
+ "Maintainability"
33785
+ ];
33786
+ const APP_ONLY_RULE_KEYS = new Set([
33787
+ "react-hooks-js/static-components",
33788
+ "react-doctor/no-render-prop-children",
33789
+ "react-doctor/prefer-explicit-variants"
33790
+ ]);
33791
+ const COMPILER_CLEANUP_BUCKET = "compiler-cleanup";
33792
+ const COMPILER_CLEANUP_RULE_KEYS = new Set(["react-doctor/react-compiler-no-manual-memoization"]);
33793
+ const ROOT_CAUSE_GROUPABLE_RULE_KEYS = new Set([
33794
+ "react-doctor/no-derived-state",
33795
+ "react-doctor/no-derived-state-effect",
33796
+ "react-doctor/no-derived-useState",
33797
+ "react-doctor/no-adjust-state-on-prop-change",
33798
+ "react-doctor/no-reset-all-state-on-prop-change"
33799
+ ]);
33800
+ const MAX_GLOB_PATTERN_LENGTH_CHARS = 1024;
33801
+ const CONFIG_CACHE_TTL_MS = 300 * 1e3;
33802
+ const SOCKET_FREE_PURL_API_BASE = "https://firewall-api.socket.dev/purl";
33803
+ const SOCKET_PACKAGE_PAGE_BASE = "https://socket.dev/npm/package";
33804
+ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
33805
+ const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
33806
+ const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
33807
+ const SUPPLY_CHAIN_PLUGIN = "socket";
33808
+ const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
33809
+ const SUPPLY_CHAIN_CATEGORY = "Security";
33810
+ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
33811
+ const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
33812
+ const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
33855
33813
  const TSCONFIG_FILENAME = "tsconfig.json";
33856
33814
  const isRelativeExtendsValue = (extendsValue) => extendsValue.startsWith("./") || extendsValue.startsWith("../") || Path.isAbsolute(extendsValue);
33857
33815
  const ensureJsonExtension = (filePath) => Path.extname(filePath) === "" ? `${filePath}.json` : filePath;
@@ -36799,17 +36757,14 @@ const checkReactServerComponentsAdvisory = (scanDirectory, project) => {
36799
36757
  return diagnostics;
36800
36758
  };
36801
36759
  const REDUCED_MOTION_GREP_PATTERN = "prefers-reduced-motion|useReducedMotion|MotionConfig|reducedMotion";
36802
- const REDUCED_MOTION_PATTERN = new RegExp(REDUCED_MOTION_GREP_PATTERN);
36803
- const REDUCED_MOTION_FILE_EXTENSIONS = new Set([
36804
- ".ts",
36805
- ".tsx",
36806
- ".js",
36807
- ".jsx",
36808
- ".css",
36809
- ".scss"
36810
- ]);
36811
- const REDUCED_MOTION_FILE_GLOBS = [...REDUCED_MOTION_FILE_EXTENSIONS].map((extension) => `*${extension}`);
36812
- const GIT_GREP_NO_MATCH_STATUS = 1;
36760
+ const REDUCED_MOTION_FILE_GLOBS = [
36761
+ "*.ts",
36762
+ "*.tsx",
36763
+ "*.js",
36764
+ "*.jsx",
36765
+ "*.css",
36766
+ "*.scss"
36767
+ ];
36813
36768
  const MISSING_REDUCED_MOTION_DIAGNOSTIC = {
36814
36769
  filePath: "package.json",
36815
36770
  plugin: "react-doctor",
@@ -36821,19 +36776,6 @@ const MISSING_REDUCED_MOTION_DIAGNOSTIC = {
36821
36776
  column: 0,
36822
36777
  category: "Accessibility"
36823
36778
  };
36824
- const hasReducedMotionHandlingViaFilesystem = (rootDirectory) => {
36825
- for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
36826
- if (!REDUCED_MOTION_FILE_EXTENSIONS.has(Path.extname(name))) continue;
36827
- let content;
36828
- try {
36829
- content = NFS.readFileSync(absolutePath, "utf-8");
36830
- } catch {
36831
- continue;
36832
- }
36833
- if (REDUCED_MOTION_PATTERN.test(content)) return true;
36834
- }
36835
- return false;
36836
- };
36837
36779
  const checkReducedMotion = (rootDirectory) => {
36838
36780
  const packageJsonPath = Path.join(rootDirectory, "package.json");
36839
36781
  if (!isFile(packageJsonPath)) return [];
@@ -36852,21 +36794,22 @@ const checkReducedMotion = (rootDirectory) => {
36852
36794
  const result = spawnSync("git", [
36853
36795
  "grep",
36854
36796
  "--untracked",
36855
- "-lE",
36797
+ "-ql",
36798
+ "-E",
36856
36799
  REDUCED_MOTION_GREP_PATTERN,
36857
36800
  "--",
36858
36801
  ...REDUCED_MOTION_FILE_GLOBS
36859
36802
  ], {
36860
36803
  cwd: rootDirectory,
36861
- encoding: "utf-8",
36862
36804
  stdio: [
36863
36805
  "ignore",
36864
36806
  "pipe",
36865
36807
  "pipe"
36866
36808
  ]
36867
36809
  });
36868
- if (!(!result.error && (result.status === 0 || result.status === GIT_GREP_NO_MATCH_STATUS))) return hasReducedMotionHandlingViaFilesystem(rootDirectory) ? [] : [MISSING_REDUCED_MOTION_DIAGNOSTIC];
36869
- return result.status === 0 && result.stdout.split("\n").some((filePath) => filePath.length > 0 && !hasIgnoredPathSegment(filePath)) ? [] : [MISSING_REDUCED_MOTION_DIAGNOSTIC];
36810
+ if (result.error) return [MISSING_REDUCED_MOTION_DIAGNOSTIC];
36811
+ if (result.status === 0) return [];
36812
+ return [MISSING_REDUCED_MOTION_DIAGNOSTIC];
36870
36813
  };
36871
36814
  const buildSecurityScanDiagnostic = (finding, entry, relativePath) => ({
36872
36815
  filePath: relativePath,
@@ -37762,7 +37705,6 @@ const isDiagnosticOnSurface = (diagnostic, surface, config) => {
37762
37705
  return true;
37763
37706
  };
37764
37707
  const filterDiagnosticsForSurface = (diagnostics, surface, config) => diagnostics.filter((diagnostic) => isDiagnosticOnSurface(diagnostic, surface, config));
37765
- const remainingDeadlineBudgetMs = (deadlineEpochMs) => Math.max(deadlineEpochMs - Date.now(), 0);
37766
37708
  /**
37767
37709
  * Budget for the dead-code phase, scaled to the work. deslop's graph build is
37768
37710
  * CPU-bound and roughly linear in file count, so a fixed 120s cap is too tight
@@ -37781,6 +37723,53 @@ const resolveDeadCodeTimeout = (input) => {
37781
37723
  phaseTimeoutMs: workerTimeoutMs + DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS
37782
37724
  };
37783
37725
  };
37726
+ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
37727
+ const entries = [];
37728
+ for (const relativePath of relativePaths) {
37729
+ const absolutePath = Path.resolve(rootDirectory, relativePath);
37730
+ const sizeBytes = statSourceFileSize(absolutePath);
37731
+ if (isLargeMinifiedFile(absolutePath, sizeBytes)) continue;
37732
+ entries.push({
37733
+ path: relativePath,
37734
+ sizeBytes: sizeBytes ?? 0
37735
+ });
37736
+ }
37737
+ return entries;
37738
+ };
37739
+ const listSourceFilesViaGit = (rootDirectory) => {
37740
+ const result = spawnSync("git", [
37741
+ "ls-files",
37742
+ "-z",
37743
+ "--cached",
37744
+ "--others",
37745
+ "--exclude-standard"
37746
+ ], {
37747
+ cwd: rootDirectory,
37748
+ encoding: "utf-8",
37749
+ maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
37750
+ });
37751
+ if (result.error || result.status !== 0) return null;
37752
+ return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath));
37753
+ };
37754
+ const listSourceFilesViaFilesystem = (rootDirectory) => {
37755
+ const filePaths = [];
37756
+ const stack = [rootDirectory];
37757
+ while (stack.length > 0) {
37758
+ const currentDirectory = stack.pop();
37759
+ const entries = readDirectoryEntries(currentDirectory);
37760
+ for (const entry of entries) {
37761
+ const absolutePath = Path.join(currentDirectory, entry.name);
37762
+ if (entry.isDirectory()) {
37763
+ if (!entry.name.startsWith(".") && !IGNORED_DIRECTORIES.has(entry.name)) stack.push(absolutePath);
37764
+ continue;
37765
+ }
37766
+ if (entry.isFile() && isLintableSourceFile(entry.name)) filePaths.push(Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/"));
37767
+ }
37768
+ }
37769
+ return filePaths;
37770
+ };
37771
+ const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory));
37772
+ const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
37784
37773
  const resolveLintIncludePaths = (rootDirectory, userConfig, project) => {
37785
37774
  if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) return;
37786
37775
  const ignoredPatterns = compileIgnoredFilePatterns(userConfig);
@@ -38477,12 +38466,12 @@ const findFilesWithDisableDirectivesViaGit = async (rootDirectory, includePaths)
38477
38466
  return null;
38478
38467
  }
38479
38468
  if (grepResult === null) return null;
38480
- return grepResult.stdout.split("\n").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
38469
+ return grepResult.stdout.split("\n").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath));
38481
38470
  };
38482
38471
  const findFilesWithDisableDirectivesViaFilesystem = (rootDirectory, includePaths) => {
38483
38472
  const matches = [];
38484
38473
  const checkFile = (relativePath) => {
38485
- if (!isLintableSourceFile(relativePath) || hasIgnoredPathSegment(relativePath)) return;
38474
+ if (!isLintableSourceFile(relativePath)) return;
38486
38475
  const absolutePath = Path.join(rootDirectory, relativePath);
38487
38476
  let content;
38488
38477
  try {
@@ -38496,7 +38485,22 @@ const findFilesWithDisableDirectivesViaFilesystem = (rootDirectory, includePaths
38496
38485
  for (const candidate of includePaths) checkFile(candidate);
38497
38486
  return matches;
38498
38487
  }
38499
- for (const { absolutePath } of walkSourceTreeFiles(rootDirectory)) checkFile(Path.relative(rootDirectory, absolutePath));
38488
+ const stack = [rootDirectory];
38489
+ while (stack.length > 0) {
38490
+ const current = stack.pop();
38491
+ if (current === void 0) continue;
38492
+ const entries = readDirectoryEntries(current);
38493
+ for (const entry of entries) {
38494
+ if (entry.isDirectory()) {
38495
+ if (entry.name.startsWith(".") || IGNORED_DIRECTORIES.has(entry.name)) continue;
38496
+ stack.push(Path.join(current, entry.name));
38497
+ continue;
38498
+ }
38499
+ if (!entry.isFile()) continue;
38500
+ const absolute = Path.join(current, entry.name);
38501
+ checkFile(Path.relative(rootDirectory, absolute));
38502
+ }
38503
+ }
38500
38504
  return matches;
38501
38505
  };
38502
38506
  const findFilesWithDisableDirectives = async (rootDirectory, includePaths) => await findFilesWithDisableDirectivesViaGit(rootDirectory, includePaths) ?? findFilesWithDisableDirectivesViaFilesystem(rootDirectory, includePaths);
@@ -39700,33 +39704,21 @@ const isParallelismRelatedSpawnError = (error) => {
39700
39704
  * loop with a slimmer config in that case.
39701
39705
  */
39702
39706
  const spawnLintBatches = async (input) => {
39703
- const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
39707
+ const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal } = input;
39704
39708
  const requestedConcurrency = resolveScanConcurrency(input.concurrency ?? 1);
39705
39709
  const totalFileCount = fileBatches.reduce((sum, batch) => sum + batch.length, 0);
39706
39710
  const runBatchPass = async (concurrency) => {
39707
39711
  const allDiagnostics = [];
39708
39712
  const droppedFiles = [];
39709
- const deadlineSkippedFiles = [];
39710
- const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0;
39711
39713
  let firstDropReason = null;
39712
- const spawnLintBatch = async (batch, depth, batchState) => {
39713
- if (isPastDeadline()) {
39714
- deadlineSkippedFiles.push(...batch);
39715
- batchState.deadlineSkippedFileCount += batch.length;
39716
- return [];
39717
- }
39714
+ const spawnLintBatch = async (batch, depth, splitBudget) => {
39718
39715
  const batchArgs = [...baseArgs, ...batch];
39719
39716
  try {
39720
39717
  return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory);
39721
39718
  } catch (error) {
39722
39719
  if (!isSplittableReactDoctorError(error)) throw error;
39723
- if (isPastDeadline()) {
39724
- deadlineSkippedFiles.push(...batch);
39725
- batchState.deadlineSkippedFileCount += batch.length;
39726
- return [];
39727
- }
39728
- batchState.deadlineMs ??= Date.now() + splitTotalBudgetMs;
39729
- const isBudgetElapsed = Date.now() >= batchState.deadlineMs;
39720
+ splitBudget.deadlineMs ??= Date.now() + splitTotalBudgetMs;
39721
+ const isBudgetElapsed = Date.now() >= splitBudget.deadlineMs;
39730
39722
  const isDepthCapReached = depth >= splitMaxDepth;
39731
39723
  if (batch.length <= 1 || isBudgetElapsed || isDepthCapReached) {
39732
39724
  droppedFiles.push(...batch);
@@ -39739,7 +39731,7 @@ const spawnLintBatches = async (input) => {
39739
39731
  return [];
39740
39732
  }
39741
39733
  const splitIndex = Math.ceil(batch.length / 2);
39742
- return [...await spawnLintBatch(batch.slice(0, splitIndex), depth + 1, batchState), ...await spawnLintBatch(batch.slice(splitIndex), depth + 1, batchState)];
39734
+ return [...await spawnLintBatch(batch.slice(0, splitIndex), depth + 1, splitBudget), ...await spawnLintBatch(batch.slice(splitIndex), depth + 1, splitBudget)];
39743
39735
  }
39744
39736
  };
39745
39737
  let startedFileCount = 0;
@@ -39755,17 +39747,9 @@ const spawnLintBatches = async (input) => {
39755
39747
  progressTimer?.unref?.();
39756
39748
  try {
39757
39749
  const batchResults = await mapWithConcurrency(fileBatches, concurrency, async (batch) => {
39758
- if (isPastDeadline()) {
39759
- deadlineSkippedFiles.push(...batch);
39760
- return [];
39761
- }
39762
39750
  startedFileCount += batch.length;
39763
- const batchState = {
39764
- deadlineMs: null,
39765
- deadlineSkippedFileCount: 0
39766
- };
39767
- const batchDiagnostics = await spawnLintBatch(batch, 0, batchState);
39768
- scannedFileCount += batch.length - batchState.deadlineSkippedFileCount;
39751
+ const batchDiagnostics = await spawnLintBatch(batch, 0, { deadlineMs: null });
39752
+ scannedFileCount += batch.length;
39769
39753
  if (onFileProgress) {
39770
39754
  displayedFileCount = Math.min(Math.max(displayedFileCount, scannedFileCount), totalFileCount);
39771
39755
  onFileProgress(displayedFileCount, totalFileCount);
@@ -39776,13 +39760,12 @@ const spawnLintBatches = async (input) => {
39776
39760
  } finally {
39777
39761
  if (progressTimer !== null) clearInterval(progressTimer);
39778
39762
  }
39779
- const reportSkippedFiles = (skippedFiles, buildMessage) => {
39780
- if (skippedFiles.length === 0 || !onPartialFailure) return;
39781
- onPartialFailure(buildMessage(`${skippedFiles.slice(0, 3).join(", ")}${skippedFiles.length > 3 ? `, +${skippedFiles.length - 3} more` : ""}`));
39782
- };
39783
- const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
39784
- reportSkippedFiles(droppedFiles, (fileListPreview) => `${droppedFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
39785
- reportSkippedFiles(deadlineSkippedFiles, (fileListPreview) => `${deadlineSkippedFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
39763
+ if (droppedFiles.length > 0 && onPartialFailure) {
39764
+ const previewFiles = droppedFiles.slice(0, 3).join(", ");
39765
+ const remainderHint = droppedFiles.length > 3 ? `, +${droppedFiles.length - 3} more` : "";
39766
+ const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
39767
+ onPartialFailure(`${droppedFiles.length} file(s) failed to lint and were skipped (${previewFiles}${remainderHint})${reasonHint}`);
39768
+ }
39786
39769
  return allDiagnostics;
39787
39770
  };
39788
39771
  let diagnostics;
@@ -39986,8 +39969,7 @@ const runOxlint = async (options) => {
39986
39969
  spawnTimeoutMs,
39987
39970
  outputMaxBytes,
39988
39971
  concurrency: options.concurrency,
39989
- signal: options.signal,
39990
- deadlineEpochMs: options.deadlineEpochMs
39972
+ signal: options.signal
39991
39973
  });
39992
39974
  writeOxlintConfig(passConfigPath, buildConfigForPass({}));
39993
39975
  try {
@@ -40086,8 +40068,7 @@ const runOxlint = async (options) => {
40086
40068
  spawnTimeoutMs,
40087
40069
  outputMaxBytes,
40088
40070
  concurrency: options.concurrency,
40089
- signal: options.signal,
40090
- deadlineEpochMs: options.deadlineEpochMs
40071
+ signal: options.signal
40091
40072
  });
40092
40073
  writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
40093
40074
  try {
@@ -40191,8 +40172,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
40191
40172
  outputMaxBytes,
40192
40173
  concurrency,
40193
40174
  signal,
40194
- lintBatchOrdering,
40195
- deadlineEpochMs: input.deadlineEpochMs
40175
+ lintBatchOrdering
40196
40176
  }),
40197
40177
  catch: ensureReactDoctorError
40198
40178
  });
@@ -40952,7 +40932,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
40952
40932
  const deadCodePhaseTimeoutMs = yield* DeadCodePhaseTimeoutMs;
40953
40933
  const resolveDeadCodePhaseTimeoutMs = (scaledPhaseTimeoutMs) => deadCodePhaseTimeoutMs === 15e4 ? scaledPhaseTimeoutMs : deadCodePhaseTimeoutMs;
40954
40934
  const workerCountSuffix = scanConcurrency > 1 ? ` ${highlighter.dim(`[~${scanConcurrency} workers]`)}` : "";
40955
- const capToDeadline = (phaseTimeoutMs) => input.deadlineEpochMs === void 0 ? phaseTimeoutMs : Math.min(phaseTimeoutMs, remainingDeadlineBudgetMs(input.deadlineEpochMs));
40956
40935
  const shouldRunDeadCode = input.runDeadCode && !isDiffMode && (showWarnings || deadCodeMaySurfaceWhenWarningsHidden(resolvedConfig.config));
40957
40936
  const deadCodeOverlapMode = yield* DeadCodeOverlap;
40958
40937
  const shouldOverlapDeadCode = shouldRunDeadCode && deadCodeOverlapMode === "on";
@@ -40982,7 +40961,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
40982
40961
  });
40983
40962
  const deadCodeFiber = shouldOverlapDeadCode ? yield* forkChild(buildCollectDeadCode({
40984
40963
  workerTimeoutMs: overlapDeadCodeTimeout.workerTimeoutMs,
40985
- phaseTimeoutMs: capToDeadline(resolveDeadCodePhaseTimeoutMs(overlapDeadCodeTimeout.phaseTimeoutMs))
40964
+ phaseTimeoutMs: resolveDeadCodePhaseTimeoutMs(overlapDeadCodeTimeout.phaseTimeoutMs)
40986
40965
  })) : null;
40987
40966
  const scanProgress = yield* progressService.start("Scanning...");
40988
40967
  const scanStartTime = Date.now();
@@ -41007,8 +40986,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41007
40986
  onCacheStats: (cacheHitFileCount, totalConsideredFileCount) => {
41008
40987
  lintCacheHitFileCount = cacheHitFileCount;
41009
40988
  lintCacheTotalFileCount = totalConsideredFileCount;
41010
- },
41011
- deadlineEpochMs: input.deadlineEpochMs
40989
+ }
41012
40990
  }).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
41013
40991
  yield* set(lintFailure, {
41014
40992
  didFail: true,
@@ -41035,13 +41013,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41035
41013
  let deadCodeCollected = [];
41036
41014
  if (lintFailureState.didFail) {
41037
41015
  if (deadCodeFiber !== null) yield* interrupt(deadCodeFiber);
41038
- } else if (shouldRunDeadCode) if (input.deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(input.deadlineEpochMs) === 0) {
41039
- if (deadCodeFiber !== null) yield* interrupt(deadCodeFiber);
41040
- yield* set(deadCodeFailure, {
41041
- didFail: true,
41042
- reason: "Dead-code analysis skipped — max scan duration reached."
41043
- });
41044
- } else {
41016
+ } else if (shouldRunDeadCode) {
41045
41017
  yield* scanProgress.update(`Scanned ${scannedFilesLabel}, analyzing dead code...`);
41046
41018
  const sequentialDeadCodeTimeout = resolveDeadCodeTimeout({
41047
41019
  sourceFileCount: totalFileCount,
@@ -41050,7 +41022,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41050
41022
  });
41051
41023
  deadCodeCollected = deadCodeFiber !== null ? yield* join(deadCodeFiber) : yield* buildCollectDeadCode({
41052
41024
  workerTimeoutMs: sequentialDeadCodeTimeout.workerTimeoutMs,
41053
- phaseTimeoutMs: capToDeadline(resolveDeadCodePhaseTimeoutMs(sequentialDeadCodeTimeout.phaseTimeoutMs))
41025
+ phaseTimeoutMs: resolveDeadCodePhaseTimeoutMs(sequentialDeadCodeTimeout.phaseTimeoutMs)
41054
41026
  });
41055
41027
  }
41056
41028
  const deadCodeFailureState = lintFailureState.didFail ? {
@@ -41088,7 +41060,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41088
41060
  };
41089
41061
  const scoreSurface = input.scoreSurface ?? "score";
41090
41062
  const scoreDiagnostics = filterDiagnosticsForSurface([...finalDiagnostics], scoreSurface, resolvedConfig.config);
41091
- const score = lintFailureState.didFail || deadCodeFailureState.didFail ? null : yield* scoreService.compute({
41063
+ const score = lintFailureState.didFail ? null : yield* scoreService.compute({
41092
41064
  diagnostics: scoreDiagnostics,
41093
41065
  isCi: input.isCi,
41094
41066
  metadata: scoreMetadata
@@ -41758,4 +41730,4 @@ const toJsonReport = (result, options) => buildJsonReport({
41758
41730
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
41759
41731
 
41760
41732
  //# sourceMappingURL=index.js.map
41761
- //# debugId=62cf4740-7938-5db0-8b80-dc81b60af36a
41733
+ //# debugId=7cfd5199-4216-5c6e-8cf5-c9623c317a1e