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/lsp.js CHANGED
@@ -32825,31 +32825,12 @@ const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
32825
32825
  const MINIFIED_SNIFF_BYTES = 65536;
32826
32826
  const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
32827
32827
  const IGNORED_DIRECTORIES = new Set([
32828
- ".angular",
32829
- ".astro",
32830
- ".cache",
32831
- ".contentlayer",
32832
- ".direnv",
32833
- ".docusaurus",
32834
- ".expo",
32835
- ".firebase",
32836
32828
  ".git",
32837
- ".gradle",
32838
- ".hg",
32839
32829
  ".next",
32840
32830
  ".nuxt",
32841
- ".nx",
32842
32831
  ".output",
32843
- ".parcel-cache",
32844
- ".serverless",
32845
32832
  ".svelte-kit",
32846
- ".svn",
32847
- ".terraform",
32848
32833
  ".turbo",
32849
- ".venv",
32850
- ".vercel",
32851
- ".wrangler",
32852
- ".yarn",
32853
32834
  "build",
32854
32835
  "coverage",
32855
32836
  "dist",
@@ -32857,142 +32838,6 @@ const IGNORED_DIRECTORIES = new Set([
32857
32838
  "out",
32858
32839
  "storybook-static"
32859
32840
  ]);
32860
- const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
32861
- const MILLISECONDS_PER_SECOND = 1e3;
32862
- const SCORE_API_URL = "https://www.react.doctor/api/score";
32863
- const FETCH_TIMEOUT_MS = 1e4;
32864
- const GITHUB_VIEWER_PERMISSION_TIMEOUT_MS = 2e3;
32865
- const SPAWN_ARGS_MAX_LENGTH_CHARS = 24e3;
32866
- const SPAWN_ARGS_MAX_LENGTH_CHARS_POSIX = 15e5;
32867
- const SPAWN_ARGS_MAX_LENGTH_CHARS_DARWIN = 8e5;
32868
- const NODE_VERSION_PROBE_TIMEOUT_MS = 5e3;
32869
- const PER_WORKER_MEM_BUDGET_BYTES = 1024 * 1024 * 1024;
32870
- const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
32871
- const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
32872
- const GIT_SHOW_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
32873
- const ES_TARGET_YEAR_BY_NAME = {
32874
- es3: 1999,
32875
- es5: 2009,
32876
- es6: 2015,
32877
- es2015: 2015,
32878
- es2016: 2016,
32879
- es2017: 2017,
32880
- es2018: 2018,
32881
- es2019: 2019,
32882
- es2020: 2020,
32883
- es2021: 2021,
32884
- es2022: 2022,
32885
- es2023: 2023,
32886
- es2024: 2024,
32887
- es2025: 2025,
32888
- esnext: 9999
32889
- };
32890
- /**
32891
- * tsconfig filenames probed when resolving a project's TypeScript
32892
- * compiler options — the root config first, then a monorepo base config.
32893
- */
32894
- const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
32895
- /**
32896
- * Project-config files that `StagedFiles.materialize` copies into
32897
- * the temp directory alongside staged sources so oxlint resolves
32898
- * `tsconfig` / `package.json` / lint configs the same way it would
32899
- * in the working tree. Hoisted out of the staged-files helper so
32900
- * the constant lives next to the rest of the IO budget knobs.
32901
- */
32902
- const STAGED_FILES_PROJECT_CONFIG_FILENAMES = [
32903
- "tsconfig.json",
32904
- "tsconfig.base.json",
32905
- "package.json",
32906
- "doctor.config.ts",
32907
- "doctor.config.mts",
32908
- "doctor.config.cts",
32909
- "doctor.config.js",
32910
- "doctor.config.mjs",
32911
- "doctor.config.cjs",
32912
- "doctor.config.json",
32913
- "doctor.config.jsonc",
32914
- "oxlint.json",
32915
- ".oxlintrc.json"
32916
- ];
32917
- const CONFIG_FINGERPRINT_FILENAMES = [
32918
- "doctor.config.ts",
32919
- "doctor.config.mts",
32920
- "doctor.config.cts",
32921
- "doctor.config.js",
32922
- "doctor.config.mjs",
32923
- "doctor.config.cjs",
32924
- "doctor.config.json",
32925
- "doctor.config.jsonc",
32926
- "react-doctor.config.json",
32927
- "package.json",
32928
- "pnpm-workspace.yaml",
32929
- "tsconfig.json",
32930
- "tsconfig.base.json",
32931
- ".oxlintrc.json",
32932
- ".eslintrc.json",
32933
- "pnpm-lock.yaml",
32934
- "package-lock.json",
32935
- "yarn.lock",
32936
- "bun.lock",
32937
- "bun.lockb",
32938
- ".gitignore"
32939
- ];
32940
- const OXLINT_OUTPUT_MAX_BYTES = 50 * 1024 * 1024;
32941
- const OXLINT_SPAWN_TIMEOUT_MS = 6e4;
32942
- const NODE_COMPILE_CACHE_DIR_NAME = "node-compile-cache";
32943
- const DEAD_CODE_WORKER_TIMEOUT_MS = 12e4;
32944
- const OXLINT_SPLIT_TOTAL_BUDGET_MS = 18e4;
32945
- const DEAD_CODE_PHASE_TIMEOUT_MS = 15e4;
32946
- const LINT_PHASE_TIMEOUT_MS = 3e5;
32947
- const SCAN_TOTAL_DEADLINE_MS = 9e5;
32948
- const DEAD_CODE_WORKER_MAX_OLD_SPACE_MB = 8192;
32949
- const DEAD_CODE_WORKER_MEM_BUDGET_BYTES = 2 * 1024 * 1024 * 1024;
32950
- const DEAD_CODE_TIMEOUT_CEILING_MS = 6e5;
32951
- const DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS = 3e4;
32952
- const DEAD_CODE_OVERLAP_PARSE_SHARE = .4;
32953
- const RECOMMENDED_PNPM_MINIMUM_RELEASE_AGE_MINUTES = 10080;
32954
- const REACT_SERVER_DOM_PACKAGES = [
32955
- "react-server-dom-webpack",
32956
- "react-server-dom-parcel",
32957
- "react-server-dom-turbopack"
32958
- ];
32959
- const REACT_BLOG_RSC_ADVISORY_URL = "https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components";
32960
- const VERCEL_NEXTJS_SECURITY_RELEASE_URL = "https://vercel.com/changelog/next-js-may-2026-security-release";
32961
- const DIAGNOSTIC_CATEGORY_BUCKETS = [
32962
- "Security",
32963
- "Bugs",
32964
- "Performance",
32965
- "Accessibility",
32966
- "Maintainability"
32967
- ];
32968
- const APP_ONLY_RULE_KEYS = new Set([
32969
- "react-hooks-js/static-components",
32970
- "react-doctor/no-render-prop-children",
32971
- "react-doctor/prefer-explicit-variants"
32972
- ]);
32973
- const COMPILER_CLEANUP_BUCKET = "compiler-cleanup";
32974
- const COMPILER_CLEANUP_RULE_KEYS = new Set(["react-doctor/react-compiler-no-manual-memoization"]);
32975
- const ROOT_CAUSE_GROUPABLE_RULE_KEYS = new Set([
32976
- "react-doctor/no-derived-state",
32977
- "react-doctor/no-derived-state-effect",
32978
- "react-doctor/no-derived-useState",
32979
- "react-doctor/no-adjust-state-on-prop-change",
32980
- "react-doctor/no-reset-all-state-on-prop-change"
32981
- ]);
32982
- const MAX_GLOB_PATTERN_LENGTH_CHARS = 1024;
32983
- const CONFIG_CACHE_TTL_MS = 300 * 1e3;
32984
- const SOCKET_FREE_PURL_API_BASE = "https://firewall-api.socket.dev/purl";
32985
- const SOCKET_PACKAGE_PAGE_BASE = "https://socket.dev/npm/package";
32986
- const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
32987
- const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
32988
- const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
32989
- const SUPPLY_CHAIN_PLUGIN = "socket";
32990
- const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
32991
- const SUPPLY_CHAIN_CATEGORY = "Security";
32992
- const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
32993
- const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
32994
- const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
32995
- const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => IGNORED_DIRECTORIES.has(segment));
32996
32841
  const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath);
32997
32842
  const isMinifiedSource = (absolutePath) => {
32998
32843
  let fileDescriptor;
@@ -33049,38 +32894,23 @@ const readDirectoryEntries = (directoryPath) => {
33049
32894
  throw error;
33050
32895
  }
33051
32896
  };
33052
- function* walkSourceTreeFiles(rootDirectory) {
32897
+ const countSourceFilesViaFilesystem = (rootDirectory) => {
32898
+ let count = 0;
33053
32899
  const stack = [rootDirectory];
33054
32900
  while (stack.length > 0) {
33055
32901
  const currentDirectory = stack.pop();
33056
- if (currentDirectory === void 0) continue;
33057
- for (const entry of readDirectoryEntries(currentDirectory)) {
33058
- const absolutePath = Path.join(currentDirectory, entry.name);
32902
+ const entries = readDirectoryEntries(currentDirectory);
32903
+ for (const entry of entries) {
33059
32904
  if (entry.isDirectory()) {
33060
- if (!IGNORED_DIRECTORIES.has(entry.name)) stack.push(absolutePath);
32905
+ if (!entry.name.startsWith(".") && !IGNORED_DIRECTORIES.has(entry.name)) stack.push(Path.join(currentDirectory, entry.name));
33061
32906
  continue;
33062
32907
  }
33063
- if (entry.isFile()) yield {
33064
- absolutePath,
33065
- name: entry.name
33066
- };
32908
+ if (entry.isFile() && isLintableSourceFile(entry.name) && !isLargeMinifiedFile(Path.join(currentDirectory, entry.name))) count++;
33067
32909
  }
33068
32910
  }
33069
- }
33070
- const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
33071
- const entries = [];
33072
- for (const relativePath of relativePaths) {
33073
- const absolutePath = Path.resolve(rootDirectory, relativePath);
33074
- const sizeBytes = statSourceFileSize(absolutePath);
33075
- if (isLargeMinifiedFile(absolutePath, sizeBytes)) continue;
33076
- entries.push({
33077
- path: relativePath,
33078
- sizeBytes: sizeBytes ?? 0
33079
- });
33080
- }
33081
- return entries;
32911
+ return count;
33082
32912
  };
33083
- const listSourceFilesViaGit = (rootDirectory) => {
32913
+ const countSourceFilesViaGit = (rootDirectory) => {
33084
32914
  const result = spawnSync("git", [
33085
32915
  "ls-files",
33086
32916
  "-z",
@@ -33093,16 +32923,9 @@ const listSourceFilesViaGit = (rootDirectory) => {
33093
32923
  maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
33094
32924
  });
33095
32925
  if (result.error || result.status !== 0) return null;
33096
- return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
32926
+ return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !isLargeMinifiedFile(Path.resolve(rootDirectory, filePath))).length;
33097
32927
  };
33098
- const listSourceFilesViaFilesystem = (rootDirectory) => {
33099
- const filePaths = [];
33100
- for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) if (isLintableSourceFile(name)) filePaths.push(Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/"));
33101
- return filePaths;
33102
- };
33103
- const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort());
33104
- const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
33105
- const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
32928
+ const countSourceFiles = (rootDirectory) => countSourceFilesViaGit(rootDirectory) ?? countSourceFilesViaFilesystem(rootDirectory);
33106
32929
  const cachedPackageJsons = /* @__PURE__ */ new Map();
33107
32930
  const clearPackageJsonCache = () => {
33108
32931
  cachedPackageJsons.clear();
@@ -33911,6 +33734,141 @@ const resolveEffectiveReactMajor = (reactVersion, packageJson) => {
33911
33734
  if (peerFloor === null) return hasUpperBoundOnlyPeerRange(peerReactRange) ? null : installedReactMajor;
33912
33735
  return installedReactMajor !== null ? Math.min(installedReactMajor, peerFloor) : peerFloor;
33913
33736
  };
33737
+ const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
33738
+ const MILLISECONDS_PER_SECOND = 1e3;
33739
+ const SCORE_API_URL = "https://www.react.doctor/api/score";
33740
+ const FETCH_TIMEOUT_MS = 1e4;
33741
+ const GITHUB_VIEWER_PERMISSION_TIMEOUT_MS = 2e3;
33742
+ const SPAWN_ARGS_MAX_LENGTH_CHARS = 24e3;
33743
+ const SPAWN_ARGS_MAX_LENGTH_CHARS_POSIX = 15e5;
33744
+ const SPAWN_ARGS_MAX_LENGTH_CHARS_DARWIN = 8e5;
33745
+ const NODE_VERSION_PROBE_TIMEOUT_MS = 5e3;
33746
+ const PER_WORKER_MEM_BUDGET_BYTES = 1024 * 1024 * 1024;
33747
+ const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
33748
+ const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
33749
+ const GIT_SHOW_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
33750
+ const ES_TARGET_YEAR_BY_NAME = {
33751
+ es3: 1999,
33752
+ es5: 2009,
33753
+ es6: 2015,
33754
+ es2015: 2015,
33755
+ es2016: 2016,
33756
+ es2017: 2017,
33757
+ es2018: 2018,
33758
+ es2019: 2019,
33759
+ es2020: 2020,
33760
+ es2021: 2021,
33761
+ es2022: 2022,
33762
+ es2023: 2023,
33763
+ es2024: 2024,
33764
+ es2025: 2025,
33765
+ esnext: 9999
33766
+ };
33767
+ /**
33768
+ * tsconfig filenames probed when resolving a project's TypeScript
33769
+ * compiler options — the root config first, then a monorepo base config.
33770
+ */
33771
+ const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
33772
+ /**
33773
+ * Project-config files that `StagedFiles.materialize` copies into
33774
+ * the temp directory alongside staged sources so oxlint resolves
33775
+ * `tsconfig` / `package.json` / lint configs the same way it would
33776
+ * in the working tree. Hoisted out of the staged-files helper so
33777
+ * the constant lives next to the rest of the IO budget knobs.
33778
+ */
33779
+ const STAGED_FILES_PROJECT_CONFIG_FILENAMES = [
33780
+ "tsconfig.json",
33781
+ "tsconfig.base.json",
33782
+ "package.json",
33783
+ "doctor.config.ts",
33784
+ "doctor.config.mts",
33785
+ "doctor.config.cts",
33786
+ "doctor.config.js",
33787
+ "doctor.config.mjs",
33788
+ "doctor.config.cjs",
33789
+ "doctor.config.json",
33790
+ "doctor.config.jsonc",
33791
+ "oxlint.json",
33792
+ ".oxlintrc.json"
33793
+ ];
33794
+ const CONFIG_FINGERPRINT_FILENAMES = [
33795
+ "doctor.config.ts",
33796
+ "doctor.config.mts",
33797
+ "doctor.config.cts",
33798
+ "doctor.config.js",
33799
+ "doctor.config.mjs",
33800
+ "doctor.config.cjs",
33801
+ "doctor.config.json",
33802
+ "doctor.config.jsonc",
33803
+ "react-doctor.config.json",
33804
+ "package.json",
33805
+ "pnpm-workspace.yaml",
33806
+ "tsconfig.json",
33807
+ "tsconfig.base.json",
33808
+ ".oxlintrc.json",
33809
+ ".eslintrc.json",
33810
+ "pnpm-lock.yaml",
33811
+ "package-lock.json",
33812
+ "yarn.lock",
33813
+ "bun.lock",
33814
+ "bun.lockb",
33815
+ ".gitignore"
33816
+ ];
33817
+ const OXLINT_OUTPUT_MAX_BYTES = 50 * 1024 * 1024;
33818
+ const OXLINT_SPAWN_TIMEOUT_MS = 6e4;
33819
+ const NODE_COMPILE_CACHE_DIR_NAME = "node-compile-cache";
33820
+ const DEAD_CODE_WORKER_TIMEOUT_MS = 12e4;
33821
+ const OXLINT_SPLIT_TOTAL_BUDGET_MS = 18e4;
33822
+ const DEAD_CODE_PHASE_TIMEOUT_MS = 15e4;
33823
+ const LINT_PHASE_TIMEOUT_MS = 3e5;
33824
+ const SCAN_TOTAL_DEADLINE_MS = 9e5;
33825
+ const DEAD_CODE_WORKER_MAX_OLD_SPACE_MB = 8192;
33826
+ const DEAD_CODE_WORKER_MEM_BUDGET_BYTES = 2 * 1024 * 1024 * 1024;
33827
+ const DEAD_CODE_TIMEOUT_CEILING_MS = 6e5;
33828
+ const DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS = 3e4;
33829
+ const DEAD_CODE_OVERLAP_PARSE_SHARE = .4;
33830
+ const RECOMMENDED_PNPM_MINIMUM_RELEASE_AGE_MINUTES = 10080;
33831
+ const REACT_SERVER_DOM_PACKAGES = [
33832
+ "react-server-dom-webpack",
33833
+ "react-server-dom-parcel",
33834
+ "react-server-dom-turbopack"
33835
+ ];
33836
+ const REACT_BLOG_RSC_ADVISORY_URL = "https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components";
33837
+ const VERCEL_NEXTJS_SECURITY_RELEASE_URL = "https://vercel.com/changelog/next-js-may-2026-security-release";
33838
+ const DIAGNOSTIC_CATEGORY_BUCKETS = [
33839
+ "Security",
33840
+ "Bugs",
33841
+ "Performance",
33842
+ "Accessibility",
33843
+ "Maintainability"
33844
+ ];
33845
+ const APP_ONLY_RULE_KEYS = new Set([
33846
+ "react-hooks-js/static-components",
33847
+ "react-doctor/no-render-prop-children",
33848
+ "react-doctor/prefer-explicit-variants"
33849
+ ]);
33850
+ const COMPILER_CLEANUP_BUCKET = "compiler-cleanup";
33851
+ const COMPILER_CLEANUP_RULE_KEYS = new Set(["react-doctor/react-compiler-no-manual-memoization"]);
33852
+ const ROOT_CAUSE_GROUPABLE_RULE_KEYS = new Set([
33853
+ "react-doctor/no-derived-state",
33854
+ "react-doctor/no-derived-state-effect",
33855
+ "react-doctor/no-derived-useState",
33856
+ "react-doctor/no-adjust-state-on-prop-change",
33857
+ "react-doctor/no-reset-all-state-on-prop-change"
33858
+ ]);
33859
+ const MAX_GLOB_PATTERN_LENGTH_CHARS = 1024;
33860
+ const CONFIG_CACHE_TTL_MS = 300 * 1e3;
33861
+ const SOCKET_FREE_PURL_API_BASE = "https://firewall-api.socket.dev/purl";
33862
+ const SOCKET_PACKAGE_PAGE_BASE = "https://socket.dev/npm/package";
33863
+ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
33864
+ const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
33865
+ const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
33866
+ const SUPPLY_CHAIN_PLUGIN = "socket";
33867
+ const SUPPLY_CHAIN_RULE = "low-supply-chain-score";
33868
+ const SUPPLY_CHAIN_CATEGORY = "Security";
33869
+ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
33870
+ const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
33871
+ const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
33914
33872
  const TSCONFIG_FILENAME = "tsconfig.json";
33915
33873
  const isRelativeExtendsValue = (extendsValue) => extendsValue.startsWith("./") || extendsValue.startsWith("../") || Path.isAbsolute(extendsValue);
33916
33874
  const ensureJsonExtension = (filePath) => Path.extname(filePath) === "" ? `${filePath}.json` : filePath;
@@ -36784,17 +36742,14 @@ const checkReactServerComponentsAdvisory = (scanDirectory, project) => {
36784
36742
  return diagnostics;
36785
36743
  };
36786
36744
  const REDUCED_MOTION_GREP_PATTERN = "prefers-reduced-motion|useReducedMotion|MotionConfig|reducedMotion";
36787
- const REDUCED_MOTION_PATTERN = new RegExp(REDUCED_MOTION_GREP_PATTERN);
36788
- const REDUCED_MOTION_FILE_EXTENSIONS = new Set([
36789
- ".ts",
36790
- ".tsx",
36791
- ".js",
36792
- ".jsx",
36793
- ".css",
36794
- ".scss"
36795
- ]);
36796
- const REDUCED_MOTION_FILE_GLOBS = [...REDUCED_MOTION_FILE_EXTENSIONS].map((extension) => `*${extension}`);
36797
- const GIT_GREP_NO_MATCH_STATUS = 1;
36745
+ const REDUCED_MOTION_FILE_GLOBS = [
36746
+ "*.ts",
36747
+ "*.tsx",
36748
+ "*.js",
36749
+ "*.jsx",
36750
+ "*.css",
36751
+ "*.scss"
36752
+ ];
36798
36753
  const MISSING_REDUCED_MOTION_DIAGNOSTIC = {
36799
36754
  filePath: "package.json",
36800
36755
  plugin: "react-doctor",
@@ -36806,19 +36761,6 @@ const MISSING_REDUCED_MOTION_DIAGNOSTIC = {
36806
36761
  column: 0,
36807
36762
  category: "Accessibility"
36808
36763
  };
36809
- const hasReducedMotionHandlingViaFilesystem = (rootDirectory) => {
36810
- for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
36811
- if (!REDUCED_MOTION_FILE_EXTENSIONS.has(Path.extname(name))) continue;
36812
- let content;
36813
- try {
36814
- content = NFS.readFileSync(absolutePath, "utf-8");
36815
- } catch {
36816
- continue;
36817
- }
36818
- if (REDUCED_MOTION_PATTERN.test(content)) return true;
36819
- }
36820
- return false;
36821
- };
36822
36764
  const checkReducedMotion = (rootDirectory) => {
36823
36765
  const packageJsonPath = Path.join(rootDirectory, "package.json");
36824
36766
  if (!isFile(packageJsonPath)) return [];
@@ -36837,21 +36779,22 @@ const checkReducedMotion = (rootDirectory) => {
36837
36779
  const result = spawnSync("git", [
36838
36780
  "grep",
36839
36781
  "--untracked",
36840
- "-lE",
36782
+ "-ql",
36783
+ "-E",
36841
36784
  REDUCED_MOTION_GREP_PATTERN,
36842
36785
  "--",
36843
36786
  ...REDUCED_MOTION_FILE_GLOBS
36844
36787
  ], {
36845
36788
  cwd: rootDirectory,
36846
- encoding: "utf-8",
36847
36789
  stdio: [
36848
36790
  "ignore",
36849
36791
  "pipe",
36850
36792
  "pipe"
36851
36793
  ]
36852
36794
  });
36853
- if (!(!result.error && (result.status === 0 || result.status === GIT_GREP_NO_MATCH_STATUS))) return hasReducedMotionHandlingViaFilesystem(rootDirectory) ? [] : [MISSING_REDUCED_MOTION_DIAGNOSTIC];
36854
- return result.status === 0 && result.stdout.split("\n").some((filePath) => filePath.length > 0 && !hasIgnoredPathSegment(filePath)) ? [] : [MISSING_REDUCED_MOTION_DIAGNOSTIC];
36795
+ if (result.error) return [MISSING_REDUCED_MOTION_DIAGNOSTIC];
36796
+ if (result.status === 0) return [];
36797
+ return [MISSING_REDUCED_MOTION_DIAGNOSTIC];
36855
36798
  };
36856
36799
  const buildSecurityScanDiagnostic = (finding, entry, relativePath) => ({
36857
36800
  filePath: relativePath,
@@ -37747,7 +37690,6 @@ const isDiagnosticOnSurface = (diagnostic, surface, config) => {
37747
37690
  return true;
37748
37691
  };
37749
37692
  const filterDiagnosticsForSurface = (diagnostics, surface, config) => diagnostics.filter((diagnostic) => isDiagnosticOnSurface(diagnostic, surface, config));
37750
- const remainingDeadlineBudgetMs = (deadlineEpochMs) => Math.max(deadlineEpochMs - Date.now(), 0);
37751
37693
  /**
37752
37694
  * Budget for the dead-code phase, scaled to the work. deslop's graph build is
37753
37695
  * CPU-bound and roughly linear in file count, so a fixed 120s cap is too tight
@@ -37766,6 +37708,53 @@ const resolveDeadCodeTimeout = (input) => {
37766
37708
  phaseTimeoutMs: workerTimeoutMs + DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS
37767
37709
  };
37768
37710
  };
37711
+ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
37712
+ const entries = [];
37713
+ for (const relativePath of relativePaths) {
37714
+ const absolutePath = Path.resolve(rootDirectory, relativePath);
37715
+ const sizeBytes = statSourceFileSize(absolutePath);
37716
+ if (isLargeMinifiedFile(absolutePath, sizeBytes)) continue;
37717
+ entries.push({
37718
+ path: relativePath,
37719
+ sizeBytes: sizeBytes ?? 0
37720
+ });
37721
+ }
37722
+ return entries;
37723
+ };
37724
+ const listSourceFilesViaGit = (rootDirectory) => {
37725
+ const result = spawnSync("git", [
37726
+ "ls-files",
37727
+ "-z",
37728
+ "--cached",
37729
+ "--others",
37730
+ "--exclude-standard"
37731
+ ], {
37732
+ cwd: rootDirectory,
37733
+ encoding: "utf-8",
37734
+ maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
37735
+ });
37736
+ if (result.error || result.status !== 0) return null;
37737
+ return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath));
37738
+ };
37739
+ const listSourceFilesViaFilesystem = (rootDirectory) => {
37740
+ const filePaths = [];
37741
+ const stack = [rootDirectory];
37742
+ while (stack.length > 0) {
37743
+ const currentDirectory = stack.pop();
37744
+ const entries = readDirectoryEntries(currentDirectory);
37745
+ for (const entry of entries) {
37746
+ const absolutePath = Path.join(currentDirectory, entry.name);
37747
+ if (entry.isDirectory()) {
37748
+ if (!entry.name.startsWith(".") && !IGNORED_DIRECTORIES.has(entry.name)) stack.push(absolutePath);
37749
+ continue;
37750
+ }
37751
+ if (entry.isFile() && isLintableSourceFile(entry.name)) filePaths.push(Path.relative(rootDirectory, absolutePath).replace(/\\/g, "/"));
37752
+ }
37753
+ }
37754
+ return filePaths;
37755
+ };
37756
+ const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory));
37757
+ const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
37769
37758
  const resolveLintIncludePaths = (rootDirectory, userConfig, project) => {
37770
37759
  if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) return;
37771
37760
  const ignoredPatterns = compileIgnoredFilePatterns(userConfig);
@@ -38462,12 +38451,12 @@ const findFilesWithDisableDirectivesViaGit = async (rootDirectory, includePaths)
38462
38451
  return null;
38463
38452
  }
38464
38453
  if (grepResult === null) return null;
38465
- return grepResult.stdout.split("\n").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
38454
+ return grepResult.stdout.split("\n").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath));
38466
38455
  };
38467
38456
  const findFilesWithDisableDirectivesViaFilesystem = (rootDirectory, includePaths) => {
38468
38457
  const matches = [];
38469
38458
  const checkFile = (relativePath) => {
38470
- if (!isLintableSourceFile(relativePath) || hasIgnoredPathSegment(relativePath)) return;
38459
+ if (!isLintableSourceFile(relativePath)) return;
38471
38460
  const absolutePath = Path.join(rootDirectory, relativePath);
38472
38461
  let content;
38473
38462
  try {
@@ -38481,7 +38470,22 @@ const findFilesWithDisableDirectivesViaFilesystem = (rootDirectory, includePaths
38481
38470
  for (const candidate of includePaths) checkFile(candidate);
38482
38471
  return matches;
38483
38472
  }
38484
- for (const { absolutePath } of walkSourceTreeFiles(rootDirectory)) checkFile(Path.relative(rootDirectory, absolutePath));
38473
+ const stack = [rootDirectory];
38474
+ while (stack.length > 0) {
38475
+ const current = stack.pop();
38476
+ if (current === void 0) continue;
38477
+ const entries = readDirectoryEntries(current);
38478
+ for (const entry of entries) {
38479
+ if (entry.isDirectory()) {
38480
+ if (entry.name.startsWith(".") || IGNORED_DIRECTORIES.has(entry.name)) continue;
38481
+ stack.push(Path.join(current, entry.name));
38482
+ continue;
38483
+ }
38484
+ if (!entry.isFile()) continue;
38485
+ const absolute = Path.join(current, entry.name);
38486
+ checkFile(Path.relative(rootDirectory, absolute));
38487
+ }
38488
+ }
38485
38489
  return matches;
38486
38490
  };
38487
38491
  const findFilesWithDisableDirectives = async (rootDirectory, includePaths) => await findFilesWithDisableDirectivesViaGit(rootDirectory, includePaths) ?? findFilesWithDisableDirectivesViaFilesystem(rootDirectory, includePaths);
@@ -39685,33 +39689,21 @@ const isParallelismRelatedSpawnError = (error) => {
39685
39689
  * loop with a slimmer config in that case.
39686
39690
  */
39687
39691
  const spawnLintBatches = async (input) => {
39688
- const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
39692
+ const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal } = input;
39689
39693
  const requestedConcurrency = resolveScanConcurrency(input.concurrency ?? 1);
39690
39694
  const totalFileCount = fileBatches.reduce((sum, batch) => sum + batch.length, 0);
39691
39695
  const runBatchPass = async (concurrency) => {
39692
39696
  const allDiagnostics = [];
39693
39697
  const droppedFiles = [];
39694
- const deadlineSkippedFiles = [];
39695
- const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0;
39696
39698
  let firstDropReason = null;
39697
- const spawnLintBatch = async (batch, depth, batchState) => {
39698
- if (isPastDeadline()) {
39699
- deadlineSkippedFiles.push(...batch);
39700
- batchState.deadlineSkippedFileCount += batch.length;
39701
- return [];
39702
- }
39699
+ const spawnLintBatch = async (batch, depth, splitBudget) => {
39703
39700
  const batchArgs = [...baseArgs, ...batch];
39704
39701
  try {
39705
39702
  return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory);
39706
39703
  } catch (error) {
39707
39704
  if (!isSplittableReactDoctorError(error)) throw error;
39708
- if (isPastDeadline()) {
39709
- deadlineSkippedFiles.push(...batch);
39710
- batchState.deadlineSkippedFileCount += batch.length;
39711
- return [];
39712
- }
39713
- batchState.deadlineMs ??= Date.now() + splitTotalBudgetMs;
39714
- const isBudgetElapsed = Date.now() >= batchState.deadlineMs;
39705
+ splitBudget.deadlineMs ??= Date.now() + splitTotalBudgetMs;
39706
+ const isBudgetElapsed = Date.now() >= splitBudget.deadlineMs;
39715
39707
  const isDepthCapReached = depth >= splitMaxDepth;
39716
39708
  if (batch.length <= 1 || isBudgetElapsed || isDepthCapReached) {
39717
39709
  droppedFiles.push(...batch);
@@ -39724,7 +39716,7 @@ const spawnLintBatches = async (input) => {
39724
39716
  return [];
39725
39717
  }
39726
39718
  const splitIndex = Math.ceil(batch.length / 2);
39727
- return [...await spawnLintBatch(batch.slice(0, splitIndex), depth + 1, batchState), ...await spawnLintBatch(batch.slice(splitIndex), depth + 1, batchState)];
39719
+ return [...await spawnLintBatch(batch.slice(0, splitIndex), depth + 1, splitBudget), ...await spawnLintBatch(batch.slice(splitIndex), depth + 1, splitBudget)];
39728
39720
  }
39729
39721
  };
39730
39722
  let startedFileCount = 0;
@@ -39740,17 +39732,9 @@ const spawnLintBatches = async (input) => {
39740
39732
  progressTimer?.unref?.();
39741
39733
  try {
39742
39734
  const batchResults = await mapWithConcurrency(fileBatches, concurrency, async (batch) => {
39743
- if (isPastDeadline()) {
39744
- deadlineSkippedFiles.push(...batch);
39745
- return [];
39746
- }
39747
39735
  startedFileCount += batch.length;
39748
- const batchState = {
39749
- deadlineMs: null,
39750
- deadlineSkippedFileCount: 0
39751
- };
39752
- const batchDiagnostics = await spawnLintBatch(batch, 0, batchState);
39753
- scannedFileCount += batch.length - batchState.deadlineSkippedFileCount;
39736
+ const batchDiagnostics = await spawnLintBatch(batch, 0, { deadlineMs: null });
39737
+ scannedFileCount += batch.length;
39754
39738
  if (onFileProgress) {
39755
39739
  displayedFileCount = Math.min(Math.max(displayedFileCount, scannedFileCount), totalFileCount);
39756
39740
  onFileProgress(displayedFileCount, totalFileCount);
@@ -39761,13 +39745,12 @@ const spawnLintBatches = async (input) => {
39761
39745
  } finally {
39762
39746
  if (progressTimer !== null) clearInterval(progressTimer);
39763
39747
  }
39764
- const reportSkippedFiles = (skippedFiles, buildMessage) => {
39765
- if (skippedFiles.length === 0 || !onPartialFailure) return;
39766
- onPartialFailure(buildMessage(`${skippedFiles.slice(0, 3).join(", ")}${skippedFiles.length > 3 ? `, +${skippedFiles.length - 3} more` : ""}`));
39767
- };
39768
- const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
39769
- reportSkippedFiles(droppedFiles, (fileListPreview) => `${droppedFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
39770
- reportSkippedFiles(deadlineSkippedFiles, (fileListPreview) => `${deadlineSkippedFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
39748
+ if (droppedFiles.length > 0 && onPartialFailure) {
39749
+ const previewFiles = droppedFiles.slice(0, 3).join(", ");
39750
+ const remainderHint = droppedFiles.length > 3 ? `, +${droppedFiles.length - 3} more` : "";
39751
+ const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
39752
+ onPartialFailure(`${droppedFiles.length} file(s) failed to lint and were skipped (${previewFiles}${remainderHint})${reasonHint}`);
39753
+ }
39771
39754
  return allDiagnostics;
39772
39755
  };
39773
39756
  let diagnostics;
@@ -39971,8 +39954,7 @@ const runOxlint = async (options) => {
39971
39954
  spawnTimeoutMs,
39972
39955
  outputMaxBytes,
39973
39956
  concurrency: options.concurrency,
39974
- signal: options.signal,
39975
- deadlineEpochMs: options.deadlineEpochMs
39957
+ signal: options.signal
39976
39958
  });
39977
39959
  writeOxlintConfig(passConfigPath, buildConfigForPass({}));
39978
39960
  try {
@@ -40071,8 +40053,7 @@ const runOxlint = async (options) => {
40071
40053
  spawnTimeoutMs,
40072
40054
  outputMaxBytes,
40073
40055
  concurrency: options.concurrency,
40074
- signal: options.signal,
40075
- deadlineEpochMs: options.deadlineEpochMs
40056
+ signal: options.signal
40076
40057
  });
40077
40058
  writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
40078
40059
  try {
@@ -40176,8 +40157,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
40176
40157
  outputMaxBytes,
40177
40158
  concurrency,
40178
40159
  signal,
40179
- lintBatchOrdering,
40180
- deadlineEpochMs: input.deadlineEpochMs
40160
+ lintBatchOrdering
40181
40161
  }),
40182
40162
  catch: ensureReactDoctorError
40183
40163
  });
@@ -40937,7 +40917,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
40937
40917
  const deadCodePhaseTimeoutMs = yield* DeadCodePhaseTimeoutMs;
40938
40918
  const resolveDeadCodePhaseTimeoutMs = (scaledPhaseTimeoutMs) => deadCodePhaseTimeoutMs === 15e4 ? scaledPhaseTimeoutMs : deadCodePhaseTimeoutMs;
40939
40919
  const workerCountSuffix = scanConcurrency > 1 ? ` ${highlighter.dim(`[~${scanConcurrency} workers]`)}` : "";
40940
- const capToDeadline = (phaseTimeoutMs) => input.deadlineEpochMs === void 0 ? phaseTimeoutMs : Math.min(phaseTimeoutMs, remainingDeadlineBudgetMs(input.deadlineEpochMs));
40941
40920
  const shouldRunDeadCode = input.runDeadCode && !isDiffMode && (showWarnings || deadCodeMaySurfaceWhenWarningsHidden(resolvedConfig.config));
40942
40921
  const deadCodeOverlapMode = yield* DeadCodeOverlap;
40943
40922
  const shouldOverlapDeadCode = shouldRunDeadCode && deadCodeOverlapMode === "on";
@@ -40967,7 +40946,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
40967
40946
  });
40968
40947
  const deadCodeFiber = shouldOverlapDeadCode ? yield* forkChild(buildCollectDeadCode({
40969
40948
  workerTimeoutMs: overlapDeadCodeTimeout.workerTimeoutMs,
40970
- phaseTimeoutMs: capToDeadline(resolveDeadCodePhaseTimeoutMs(overlapDeadCodeTimeout.phaseTimeoutMs))
40949
+ phaseTimeoutMs: resolveDeadCodePhaseTimeoutMs(overlapDeadCodeTimeout.phaseTimeoutMs)
40971
40950
  })) : null;
40972
40951
  const scanProgress = yield* progressService.start("Scanning...");
40973
40952
  const scanStartTime = Date.now();
@@ -40992,8 +40971,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
40992
40971
  onCacheStats: (cacheHitFileCount, totalConsideredFileCount) => {
40993
40972
  lintCacheHitFileCount = cacheHitFileCount;
40994
40973
  lintCacheTotalFileCount = totalConsideredFileCount;
40995
- },
40996
- deadlineEpochMs: input.deadlineEpochMs
40974
+ }
40997
40975
  }).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
40998
40976
  yield* set(lintFailure, {
40999
40977
  didFail: true,
@@ -41020,13 +40998,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41020
40998
  let deadCodeCollected = [];
41021
40999
  if (lintFailureState.didFail) {
41022
41000
  if (deadCodeFiber !== null) yield* interrupt(deadCodeFiber);
41023
- } else if (shouldRunDeadCode) if (input.deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(input.deadlineEpochMs) === 0) {
41024
- if (deadCodeFiber !== null) yield* interrupt(deadCodeFiber);
41025
- yield* set(deadCodeFailure, {
41026
- didFail: true,
41027
- reason: "Dead-code analysis skipped — max scan duration reached."
41028
- });
41029
- } else {
41001
+ } else if (shouldRunDeadCode) {
41030
41002
  yield* scanProgress.update(`Scanned ${scannedFilesLabel}, analyzing dead code...`);
41031
41003
  const sequentialDeadCodeTimeout = resolveDeadCodeTimeout({
41032
41004
  sourceFileCount: totalFileCount,
@@ -41035,7 +41007,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41035
41007
  });
41036
41008
  deadCodeCollected = deadCodeFiber !== null ? yield* join(deadCodeFiber) : yield* buildCollectDeadCode({
41037
41009
  workerTimeoutMs: sequentialDeadCodeTimeout.workerTimeoutMs,
41038
- phaseTimeoutMs: capToDeadline(resolveDeadCodePhaseTimeoutMs(sequentialDeadCodeTimeout.phaseTimeoutMs))
41010
+ phaseTimeoutMs: resolveDeadCodePhaseTimeoutMs(sequentialDeadCodeTimeout.phaseTimeoutMs)
41039
41011
  });
41040
41012
  }
41041
41013
  const deadCodeFailureState = lintFailureState.didFail ? {
@@ -41073,7 +41045,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41073
41045
  };
41074
41046
  const scoreSurface = input.scoreSurface ?? "score";
41075
41047
  const scoreDiagnostics = filterDiagnosticsForSurface([...finalDiagnostics], scoreSurface, resolvedConfig.config);
41076
- const score = lintFailureState.didFail || deadCodeFailureState.didFail ? null : yield* scoreService.compute({
41048
+ const score = lintFailureState.didFail ? null : yield* scoreService.compute({
41077
41049
  diagnostics: scoreDiagnostics,
41078
41050
  isCi: input.isCi,
41079
41051
  metadata: scoreMetadata
@@ -43482,5 +43454,5 @@ const startLanguageServer = () => {
43482
43454
  };
43483
43455
  //#endregion
43484
43456
  export { startLanguageServer };
43485
- !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]="6811672b-baa6-5b7c-b676-5121c592d4a0")}catch(e){}}();
43486
- //# debugId=6811672b-baa6-5b7c-b676-5121c592d4a0
43457
+ !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]="f7d16df6-f4da-5a95-ab64-acd6d3a0f5ca")}catch(e){}}();
43458
+ //# debugId=f7d16df6-f4da-5a95-ab64-acd6d3a0f5ca