react-doctor 0.0.19 → 0.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -765,6 +765,46 @@ const createOxlintConfig = ({ pluginPath, framework, hasReactCompiler }) => ({
765
765
  }
766
766
  });
767
767
 
768
+ //#endregion
769
+ //#region src/utils/neutralize-disable-directives.ts
770
+ const findFilesWithDisableDirectives = (rootDirectory) => {
771
+ const result = spawnSync("git", [
772
+ "grep",
773
+ "-l",
774
+ "--untracked",
775
+ "-E",
776
+ "(eslint|oxlint)-disable"
777
+ ], {
778
+ cwd: rootDirectory,
779
+ encoding: "utf-8",
780
+ maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
781
+ });
782
+ if (result.error || result.status === null) return [];
783
+ return result.stdout.split("\n").filter((filePath) => filePath.length > 0 && SOURCE_FILE_PATTERN.test(filePath));
784
+ };
785
+ const neutralizeContent = (content) => content.replaceAll("eslint-disable", "eslint_disable").replaceAll("oxlint-disable", "oxlint_disable");
786
+ const neutralizeDisableDirectives = (rootDirectory) => {
787
+ const filePaths = findFilesWithDisableDirectives(rootDirectory);
788
+ const originalContents = /* @__PURE__ */ new Map();
789
+ for (const relativePath of filePaths) {
790
+ const absolutePath = path.join(rootDirectory, relativePath);
791
+ let originalContent;
792
+ try {
793
+ originalContent = fs.readFileSync(absolutePath, "utf-8");
794
+ } catch {
795
+ continue;
796
+ }
797
+ const neutralizedContent = neutralizeContent(originalContent);
798
+ if (neutralizedContent !== originalContent) {
799
+ originalContents.set(absolutePath, originalContent);
800
+ fs.writeFileSync(absolutePath, neutralizedContent);
801
+ }
802
+ }
803
+ return () => {
804
+ for (const [absolutePath, originalContent] of originalContents) fs.writeFileSync(absolutePath, originalContent);
805
+ };
806
+ };
807
+
768
808
  //#endregion
769
809
  //#region src/utils/run-oxlint.ts
770
810
  const esmRequire = createRequire(import.meta.url);
@@ -832,7 +872,7 @@ const RULE_CATEGORY_MAP = {
832
872
  "react-doctor/async-parallel": "Performance"
833
873
  };
834
874
  const RULE_HELP_MAP = {
835
- "no-derived-state-effect": "Compute during render: `const derived = computeFrom(dep1, dep2)` no useEffect needed",
875
+ "no-derived-state-effect": "For derived state, compute inline: `const x = fn(dep)`. For state resets on prop change, use a key prop: `<Component key={prop} />`",
836
876
  "no-fetch-in-effect": "Use `useQuery()` from @tanstack/react-query, `useSWR()`, or fetch in a Server Component instead",
837
877
  "no-cascading-set-state": "Combine into useReducer: `const [state, dispatch] = useReducer(reducer, initialState)`",
838
878
  "no-effect-event-handler": "Move the conditional logic into onClick, onChange, or onSubmit handlers directly",
@@ -934,6 +974,7 @@ const runOxlint = async (rootDirectory, hasTypeScript, framework, hasReactCompil
934
974
  framework,
935
975
  hasReactCompiler
936
976
  });
977
+ const restoreDisableDirectives = neutralizeDisableDirectives(rootDirectory);
937
978
  try {
938
979
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
939
980
  const args = [
@@ -989,6 +1030,7 @@ const runOxlint = async (rootDirectory, hasTypeScript, framework, hasReactCompil
989
1030
  };
990
1031
  });
991
1032
  } finally {
1033
+ restoreDisableDirectives();
992
1034
  if (fs.existsSync(configPath)) fs.unlinkSync(configPath);
993
1035
  }
994
1036
  };
@@ -1266,7 +1308,10 @@ const scan = async (directory, inputOptions = {}) => {
1266
1308
  return lintDiagnostics;
1267
1309
  } catch (error) {
1268
1310
  lintSpinner?.fail("Lint checks failed (non-fatal, skipping).");
1269
- logger.error(String(error));
1311
+ if (error instanceof Error) {
1312
+ logger.error(error.message);
1313
+ if (error.stack) logger.dim(error.stack);
1314
+ } else logger.error(String(error));
1270
1315
  return [];
1271
1316
  }
1272
1317
  })() : Promise.resolve([]);
@@ -1614,7 +1659,7 @@ const maybePromptSkillInstall = async (shouldSkipPrompts) => {
1614
1659
 
1615
1660
  //#endregion
1616
1661
  //#region src/cli.ts
1617
- const VERSION = "0.0.19";
1662
+ const VERSION = "0.0.20";
1618
1663
  process.on("SIGINT", () => process.exit(0));
1619
1664
  process.on("SIGTERM", () => process.exit(0));
1620
1665
  const resolveDiffMode = async (diffInfo, effectiveDiff, shouldSkipPrompts, isScoreOnly) => {