react-doctor 0.5.6-dev.b8170f8 → 0.5.6-dev.ed0258c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ad091b20-c3e2-5c96-93ac-9a910745a035")}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]="a06f0514-b1fa-5452-9c19-0140438862f8")}catch(e){}}();
3
3
  import { createRequire } from "node:module";
4
4
  import * as NodeChildProcess from "node:child_process";
5
5
  import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
@@ -36793,6 +36793,11 @@ const ES_TARGET_YEAR_BY_NAME = {
36793
36793
  esnext: 9999
36794
36794
  };
36795
36795
  /**
36796
+ * tsconfig filenames probed when resolving a project's TypeScript
36797
+ * compiler options — the root config first, then a monorepo base config.
36798
+ */
36799
+ const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
36800
+ /**
36796
36801
  * Project-config files that `StagedFiles.materialize` copies into
36797
36802
  * the temp directory alongside staged sources so oxlint resolves
36798
36803
  * `tsconfig` / `package.json` / lint configs the same way it would
@@ -39941,8 +39946,8 @@ const collectIgnorePatterns = (rootDirectory) => {
39941
39946
  cachedPatternsByRoot.set(rootDirectory, patterns);
39942
39947
  return patterns;
39943
39948
  };
39949
+ const isRecord$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
39944
39950
  const KNIP_JSON_FILENAME = "knip.json";
39945
- const isRecord$1$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
39946
39951
  const readJsonFileSafe = (filePath) => {
39947
39952
  let rawContents;
39948
39953
  try {
@@ -39958,10 +39963,10 @@ const readJsonFileSafe = (filePath) => {
39958
39963
  };
39959
39964
  const readKnipConfig = (rootDirectory) => {
39960
39965
  const knipJson = readJsonFileSafe(path.join(rootDirectory, KNIP_JSON_FILENAME));
39961
- if (isRecord$1$1(knipJson)) return knipJson;
39966
+ if (isRecord$2(knipJson)) return knipJson;
39962
39967
  const packageJson = readJsonFileSafe(path.join(rootDirectory, "package.json"));
39963
- const packageKnipConfig = isRecord$1$1(packageJson) ? packageJson.knip : null;
39964
- return isRecord$1$1(packageKnipConfig) ? packageKnipConfig : null;
39968
+ const packageKnipConfig = isRecord$2(packageJson) ? packageJson.knip : null;
39969
+ return isRecord$2(packageKnipConfig) ? packageKnipConfig : null;
39965
39970
  };
39966
39971
  const normalizePatternList = (value) => {
39967
39972
  if (typeof value === "string" && value.length > 0) return [value];
@@ -39973,10 +39978,10 @@ const prefixWorkspacePatterns = (workspacePattern, patterns) => {
39973
39978
  return patterns.map((pattern) => pattern.startsWith("!") ? `!${normalizedWorkspacePattern}/${pattern.slice(1)}` : `${normalizedWorkspacePattern}/${pattern}`);
39974
39979
  };
39975
39980
  const collectKnipWorkspacePatterns = (workspaces, settingName) => {
39976
- if (!isRecord$1$1(workspaces)) return [];
39981
+ if (!isRecord$2(workspaces)) return [];
39977
39982
  const patterns = [];
39978
39983
  for (const [workspacePattern, workspaceConfig] of Object.entries(workspaces)) {
39979
- if (!isRecord$1$1(workspaceConfig)) continue;
39984
+ if (!isRecord$2(workspaceConfig)) continue;
39980
39985
  patterns.push(...prefixWorkspacePatterns(workspacePattern, normalizePatternList(workspaceConfig[settingName])));
39981
39986
  }
39982
39987
  return patterns;
@@ -40021,8 +40026,6 @@ const toCanonicalPath = (filePath) => {
40021
40026
  };
40022
40027
  const DEAD_CODE_PLUGIN = "deslop";
40023
40028
  const DEAD_CODE_CATEGORY = "Maintainability";
40024
- const TSCONFIG_FILENAMES$1 = ["tsconfig.json", "tsconfig.base.json"];
40025
- const isRecord$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
40026
40029
  const DEAD_CODE_WORKER_SCRIPT = `
40027
40030
  const inputChunks = [];
40028
40031
  process.stdin.on("data", (chunk) => inputChunks.push(chunk));
@@ -40080,7 +40083,7 @@ process.stdin.on("end", () => {
40080
40083
  });
40081
40084
  `;
40082
40085
  const resolveTsConfigPath = (rootDirectory) => {
40083
- for (const filename of TSCONFIG_FILENAMES$1) {
40086
+ for (const filename of TSCONFIG_FILENAMES) {
40084
40087
  const candidate = Path.join(rootDirectory, filename);
40085
40088
  if (NFS.existsSync(candidate)) return candidate;
40086
40089
  }
@@ -41381,7 +41384,6 @@ const resolveOxlintBinary = () => {
41381
41384
  return Path.join(oxlintPackageDirectory, "bin", "oxlint");
41382
41385
  };
41383
41386
  const resolvePluginPath = () => esmRequire.resolve("oxlint-plugin-react-doctor");
41384
- const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
41385
41387
  const resolveTsConfigRelativePath = (rootDirectory) => {
41386
41388
  for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
41387
41389
  return null;
@@ -41753,7 +41755,7 @@ const scopeContainsNonImportBinding = (node, scopeNode, identifierName) => {
41753
41755
  const isIdentifierShadowedByLocalBinding = (identifier, sourceFile) => {
41754
41756
  let currentNode = identifier.parent;
41755
41757
  while (currentNode) {
41756
- if (isScopeNode(currentNode)) {
41758
+ if (isScopeBoundary(currentNode)) {
41757
41759
  if (scopeContainsNonImportBinding(currentNode, currentNode, identifier.text)) return true;
41758
41760
  }
41759
41761
  if (currentNode === sourceFile) return false;
@@ -41844,11 +41846,10 @@ const findResolutionInScope = (scopeNode, identifierName, reactImportBindings, s
41844
41846
  });
41845
41847
  return resolution;
41846
41848
  };
41847
- const isScopeNode = isScopeBoundary;
41848
41849
  const resolveIdentifierBinding = (identifier, reactImportBindings, sourceFile, visitedDeclarations = /* @__PURE__ */ new Set()) => {
41849
41850
  let currentNode = identifier.parent;
41850
41851
  while (currentNode) {
41851
- if (isScopeNode(currentNode)) {
41852
+ if (isScopeBoundary(currentNode)) {
41852
41853
  const resolution = findResolutionInScope(currentNode, identifier.text, reactImportBindings, sourceFile, visitedDeclarations);
41853
41854
  if (resolution) return resolution;
41854
41855
  }
@@ -44040,7 +44041,7 @@ const makeNoopConsole = () => ({
44040
44041
  });
44041
44042
  //#endregion
44042
44043
  //#region src/cli/utils/version.ts
44043
- const VERSION = "0.5.6-dev.b8170f8";
44044
+ const VERSION = "0.5.6-dev.ed0258c";
44044
44045
  //#endregion
44045
44046
  //#region src/cli/utils/json-mode.ts
44046
44047
  let context = null;
@@ -44400,13 +44401,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
44400
44401
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
44401
44402
  * standard `SENTRY_RELEASE` override.
44402
44403
  */
44403
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.5.6-dev.b8170f8`;
44404
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.5.6-dev.ed0258c`;
44404
44405
  /**
44405
44406
  * Deployment environment shown in Sentry's environment filter. Defaults to
44406
44407
  * `production` for tagged releases and `development` for dev/unbuilt versions,
44407
44408
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
44408
44409
  */
44409
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.5.6-dev.b8170f8") ? "development" : "production");
44410
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.5.6-dev.ed0258c") ? "development" : "production");
44410
44411
  /**
44411
44412
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
44412
44413
  * (set to `0` to disable tracing) and falls back to
@@ -49192,6 +49193,78 @@ const resolveCliCategories = (categoryFlag) => {
49192
49193
  return resolvedCategories.length > 0 ? resolvedCategories : void 0;
49193
49194
  };
49194
49195
  //#endregion
49196
+ //#region src/cli/utils/git-hook-shared.ts
49197
+ const HOOK_FILE_NAME = "pre-commit";
49198
+ const HOOK_RELATIVE_PATH = "hooks/pre-commit";
49199
+ const LEGACY_HOOK_RUNNER_RELATIVE_PATH = ".react-doctor/hooks/pre-commit";
49200
+ const HUSKY_HOOKS_PATH = ".husky";
49201
+ const VITE_PLUS_HOOKS_PATH = ".vite-hooks";
49202
+ const LEFTHOOK_CONFIG_FILES = ["lefthook.yml", "lefthook.yaml"];
49203
+ const PRE_COMMIT_CONFIG_FILE = ".pre-commit-config.yaml";
49204
+ const OVERCOMMIT_CONFIG_FILE = ".overcommit.yml";
49205
+ const REACT_DOCTOR_COMMAND = "react-doctor --staged --blocking warning";
49206
+ const NON_BLOCKING_REACT_DOCTOR_COMMAND = [
49207
+ "react_doctor_output=$(mktemp \"${TMPDIR:-/tmp}/react-doctor-hook.XXXXXX\");",
49208
+ `if ${REACT_DOCTOR_COMMAND} > "$react_doctor_output" 2>&1; then`,
49209
+ "rm -f \"$react_doctor_output\";",
49210
+ "else",
49211
+ "rm -f \"$react_doctor_output\";",
49212
+ `printf "%s\\n" "React Doctor found staged regressions." "Run ${REACT_DOCTOR_COMMAND} to inspect." "Want them fixed? Ask your agent to run that command and resolve the findings." >&2;`,
49213
+ "fi"
49214
+ ].join(" ");
49215
+ const PACKAGE_JSON_FILE_NAME = "package.json";
49216
+ const runGit = (projectRoot, args) => {
49217
+ try {
49218
+ return execFileSync("git", [...args], {
49219
+ cwd: projectRoot,
49220
+ encoding: "utf8",
49221
+ stdio: [
49222
+ "ignore",
49223
+ "pipe",
49224
+ "ignore"
49225
+ ]
49226
+ }).trim();
49227
+ } catch {
49228
+ return null;
49229
+ }
49230
+ };
49231
+ const resolveGitPath = (baseDirectory, value) => Path.isAbsolute(value) ? value : Path.resolve(baseDirectory, value);
49232
+ const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
49233
+ const getPackageJsonPath = (projectRoot) => Path.join(projectRoot, PACKAGE_JSON_FILE_NAME);
49234
+ const readPackageJson = (projectRoot) => {
49235
+ try {
49236
+ return JSON.parse(NFS.readFileSync(getPackageJsonPath(projectRoot), "utf8"));
49237
+ } catch {
49238
+ return null;
49239
+ }
49240
+ };
49241
+ const writeJsonFile$1 = (filePath, value) => {
49242
+ NFS.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
49243
+ };
49244
+ const packageHasDependency = (projectRoot, dependencyName) => {
49245
+ const packageJson = readPackageJson(projectRoot);
49246
+ if (!isRecord$1(packageJson)) return false;
49247
+ return [
49248
+ "dependencies",
49249
+ "devDependencies",
49250
+ "optionalDependencies"
49251
+ ].some((fieldName) => {
49252
+ const dependencies = packageJson[fieldName];
49253
+ return isRecord$1(dependencies) && typeof dependencies[dependencyName] === "string";
49254
+ });
49255
+ };
49256
+ const packageHasRecordKey = (projectRoot, key) => {
49257
+ const packageJson = readPackageJson(projectRoot);
49258
+ return isRecord$1(packageJson) && isRecord$1(packageJson[key]);
49259
+ };
49260
+ const packageHasNestedRecordKey = (projectRoot, key, nestedKey) => {
49261
+ const packageJson = readPackageJson(projectRoot);
49262
+ if (!isRecord$1(packageJson)) return false;
49263
+ const value = packageJson[key];
49264
+ return isRecord$1(value) && isRecord$1(value[nestedKey]);
49265
+ };
49266
+ const ensureTrailingNewline = (content) => content.endsWith("\n") ? content : `${content}\n`;
49267
+ //#endregion
49195
49268
  //#region src/cli/utils/scan-result-cache.ts
49196
49269
  const CACHE_DISABLED_VALUES = new Set(["1", "true"]);
49197
49270
  const TOOLCHAIN_PACKAGE_SPECIFIERS = [
@@ -49202,7 +49275,7 @@ const TOOLCHAIN_PACKAGE_SPECIFIERS = [
49202
49275
  "eslint-plugin-react-hooks/package.json"
49203
49276
  ];
49204
49277
  const bundledRequire = createRequire(import.meta.url);
49205
- const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
49278
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
49206
49279
  const normalizeForStableJson = (value) => {
49207
49280
  if (value === null) return null;
49208
49281
  if (value === void 0) return void 0;
@@ -49231,24 +49304,9 @@ const stringifyStableJson = (value) => {
49231
49304
  }
49232
49305
  };
49233
49306
  const hashString = (value) => crypto.createHash("sha1").update(value).digest("hex");
49234
- const runGit$1 = (directory, args) => {
49235
- try {
49236
- return execFileSync("git", [...args], {
49237
- cwd: directory,
49238
- encoding: "utf8",
49239
- stdio: [
49240
- "ignore",
49241
- "pipe",
49242
- "ignore"
49243
- ]
49244
- }).trim();
49245
- } catch {
49246
- return null;
49247
- }
49248
- };
49249
- const readHeadSha = (projectDirectory) => runGit$1(projectDirectory, ["rev-parse", "HEAD"]);
49307
+ const readHeadSha = (projectDirectory) => runGit(projectDirectory, ["rev-parse", "HEAD"]);
49250
49308
  const isWorktreeClean = (projectDirectory) => {
49251
- const status = runGit$1(projectDirectory, [
49309
+ const status = runGit(projectDirectory, [
49252
49310
  "status",
49253
49311
  "--porcelain=v1",
49254
49312
  "--untracked-files=normal"
@@ -49256,7 +49314,7 @@ const isWorktreeClean = (projectDirectory) => {
49256
49314
  return status !== null && status.length === 0;
49257
49315
  };
49258
49316
  const hasHiddenTrackedFileState = (projectDirectory) => {
49259
- const output = runGit$1(projectDirectory, ["ls-files", "-v"]);
49317
+ const output = runGit(projectDirectory, ["ls-files", "-v"]);
49260
49318
  if (output === null) return true;
49261
49319
  return output.split("\n").some((line) => line.length > 0 && line[0] !== "H");
49262
49320
  };
@@ -49269,7 +49327,7 @@ const resolveCacheFilePath = (projectDirectory) => {
49269
49327
  const readPersistedCache = (cacheFilePath) => {
49270
49328
  try {
49271
49329
  const parsed = JSON.parse(fs.readFileSync(cacheFilePath, "utf8"));
49272
- if (!isRecord$1(parsed) || parsed.version !== 1) return {
49330
+ if (!isRecord(parsed) || parsed.version !== 1) return {
49273
49331
  version: 1,
49274
49332
  entries: []
49275
49333
  };
@@ -49279,8 +49337,8 @@ const readPersistedCache = (cacheFilePath) => {
49279
49337
  };
49280
49338
  const entries = [];
49281
49339
  for (const entry of parsed.entries) {
49282
- if (!isRecord$1(entry) || typeof entry.key !== "string" || typeof entry.createdAtMs !== "number") continue;
49283
- if (!isRecord$1(entry.payload) || !Array.isArray(entry.payload.diagnostics)) continue;
49340
+ if (!isRecord(entry) || typeof entry.key !== "string" || typeof entry.createdAtMs !== "number") continue;
49341
+ if (!isRecord(entry.payload) || !Array.isArray(entry.payload.diagnostics)) continue;
49284
49342
  entries.push(entry);
49285
49343
  }
49286
49344
  return {
@@ -50092,78 +50150,6 @@ const detectAvailableAgents = async () => {
50092
50150
  return getSkillAgentTypes().filter((agent) => agent !== "universal" && detected.has(agent));
50093
50151
  };
50094
50152
  //#endregion
50095
- //#region src/cli/utils/git-hook-shared.ts
50096
- const HOOK_FILE_NAME = "pre-commit";
50097
- const HOOK_RELATIVE_PATH = "hooks/pre-commit";
50098
- const LEGACY_HOOK_RUNNER_RELATIVE_PATH = ".react-doctor/hooks/pre-commit";
50099
- const HUSKY_HOOKS_PATH = ".husky";
50100
- const VITE_PLUS_HOOKS_PATH = ".vite-hooks";
50101
- const LEFTHOOK_CONFIG_FILES = ["lefthook.yml", "lefthook.yaml"];
50102
- const PRE_COMMIT_CONFIG_FILE = ".pre-commit-config.yaml";
50103
- const OVERCOMMIT_CONFIG_FILE = ".overcommit.yml";
50104
- const REACT_DOCTOR_COMMAND = "react-doctor --staged --blocking warning";
50105
- const NON_BLOCKING_REACT_DOCTOR_COMMAND = [
50106
- "react_doctor_output=$(mktemp \"${TMPDIR:-/tmp}/react-doctor-hook.XXXXXX\");",
50107
- `if ${REACT_DOCTOR_COMMAND} > "$react_doctor_output" 2>&1; then`,
50108
- "rm -f \"$react_doctor_output\";",
50109
- "else",
50110
- "rm -f \"$react_doctor_output\";",
50111
- `printf "%s\\n" "React Doctor found staged regressions." "Run ${REACT_DOCTOR_COMMAND} to inspect." "Want them fixed? Ask your agent to run that command and resolve the findings." >&2;`,
50112
- "fi"
50113
- ].join(" ");
50114
- const PACKAGE_JSON_FILE_NAME = "package.json";
50115
- const runGit = (projectRoot, args) => {
50116
- try {
50117
- return execFileSync("git", [...args], {
50118
- cwd: projectRoot,
50119
- encoding: "utf8",
50120
- stdio: [
50121
- "ignore",
50122
- "pipe",
50123
- "ignore"
50124
- ]
50125
- }).trim();
50126
- } catch {
50127
- return null;
50128
- }
50129
- };
50130
- const resolveGitPath = (baseDirectory, value) => Path.isAbsolute(value) ? value : Path.resolve(baseDirectory, value);
50131
- const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
50132
- const getPackageJsonPath = (projectRoot) => Path.join(projectRoot, PACKAGE_JSON_FILE_NAME);
50133
- const readPackageJson = (projectRoot) => {
50134
- try {
50135
- return JSON.parse(NFS.readFileSync(getPackageJsonPath(projectRoot), "utf8"));
50136
- } catch {
50137
- return null;
50138
- }
50139
- };
50140
- const writeJsonFile$1 = (filePath, value) => {
50141
- NFS.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
50142
- };
50143
- const packageHasDependency = (projectRoot, dependencyName) => {
50144
- const packageJson = readPackageJson(projectRoot);
50145
- if (!isRecord(packageJson)) return false;
50146
- return [
50147
- "dependencies",
50148
- "devDependencies",
50149
- "optionalDependencies"
50150
- ].some((fieldName) => {
50151
- const dependencies = packageJson[fieldName];
50152
- return isRecord(dependencies) && typeof dependencies[dependencyName] === "string";
50153
- });
50154
- };
50155
- const packageHasRecordKey = (projectRoot, key) => {
50156
- const packageJson = readPackageJson(projectRoot);
50157
- return isRecord(packageJson) && isRecord(packageJson[key]);
50158
- };
50159
- const packageHasNestedRecordKey = (projectRoot, key, nestedKey) => {
50160
- const packageJson = readPackageJson(projectRoot);
50161
- if (!isRecord(packageJson)) return false;
50162
- const value = packageJson[key];
50163
- return isRecord(value) && isRecord(value[nestedKey]);
50164
- };
50165
- const ensureTrailingNewline = (content) => content.endsWith("\n") ? content : `${content}\n`;
50166
- //#endregion
50167
50153
  //#region src/cli/utils/install-doctor-script.ts
50168
50154
  const DOCTOR_SCRIPT_NAME = "doctor";
50169
50155
  const FALLBACK_DOCTOR_SCRIPT_NAME = "react-doctor";
@@ -50189,31 +50175,31 @@ const findNearestPackageDirectory = (startDirectory, stopDirectory) => {
50189
50175
  };
50190
50176
  const hasDoctorScript = (projectRoot) => {
50191
50177
  const packageJson = readPackageJson(findNearestPackageDirectory(projectRoot) ?? projectRoot);
50192
- if (!isRecord(packageJson)) return false;
50178
+ if (!isRecord$1(packageJson)) return false;
50193
50179
  const scripts = packageJson.scripts;
50194
- if (!isRecord(scripts)) return false;
50180
+ if (!isRecord$1(scripts)) return false;
50195
50181
  return isReactDoctorScriptCommand(scripts[DOCTOR_SCRIPT_NAME]) || isReactDoctorScriptCommand(scripts[FALLBACK_DOCTOR_SCRIPT_NAME]);
50196
50182
  };
50197
50183
  const hasDoctorDependency = (packageJson) => DEPENDENCY_FIELD_NAMES.some((fieldName) => {
50198
50184
  const dependencies = packageJson[fieldName];
50199
- return isRecord(dependencies) && Object.hasOwn(dependencies, "react-doctor");
50185
+ return isRecord$1(dependencies) && Object.hasOwn(dependencies, "react-doctor");
50200
50186
  });
50201
50187
  const installDoctorScript = (options) => {
50202
50188
  const packageDirectory = findNearestPackageDirectory(options.projectRoot) ?? options.projectRoot;
50203
50189
  const packageJsonPath = getPackageJsonPath(packageDirectory);
50204
50190
  const packageJson = readPackageJson(packageDirectory);
50205
- if (!isRecord(packageJson)) return {
50191
+ if (!isRecord$1(packageJson)) return {
50206
50192
  packageJsonPath,
50207
50193
  scriptStatus: "skipped",
50208
50194
  scriptReason: "missing-or-invalid-package-json"
50209
50195
  };
50210
50196
  const scripts = packageJson.scripts;
50211
50197
  const scriptTarget = (() => {
50212
- if (scripts !== void 0 && !isRecord(scripts)) return {
50198
+ if (scripts !== void 0 && !isRecord$1(scripts)) return {
50213
50199
  status: "skipped",
50214
50200
  reason: "invalid-scripts"
50215
50201
  };
50216
- const scriptRecord = isRecord(scripts) ? scripts : {};
50202
+ const scriptRecord = isRecord$1(scripts) ? scripts : {};
50217
50203
  if (isReactDoctorScriptCommand(scriptRecord[DOCTOR_SCRIPT_NAME])) return {
50218
50204
  scriptName: DOCTOR_SCRIPT_NAME,
50219
50205
  status: "existing"
@@ -50247,7 +50233,7 @@ const installDoctorScript = (options) => {
50247
50233
  if (scriptStatus === "created") writeJsonFile$1(packageJsonPath, {
50248
50234
  ...packageJson,
50249
50235
  scripts: {
50250
- ...isRecord(scripts) ? scripts : {},
50236
+ ...isRecord$1(scripts) ? scripts : {},
50251
50237
  [scriptTarget.scriptName ?? DOCTOR_SCRIPT_NAME]: DOCTOR_SCRIPT_COMMAND
50252
50238
  }
50253
50239
  });
@@ -51075,13 +51061,13 @@ const installPackageJsonHook = (options, strategy) => {
51075
51061
  const packageJsonPath = getPackageJsonPath(options.projectRoot);
51076
51062
  const didHookExist = NFS.existsSync(packageJsonPath);
51077
51063
  const packageJson = readPackageJson(options.projectRoot);
51078
- const nextPackageJson = isRecord(packageJson) ? { ...packageJson } : {};
51064
+ const nextPackageJson = isRecord$1(packageJson) ? { ...packageJson } : {};
51079
51065
  const parentKeys = strategy.path.slice(0, -1);
51080
51066
  const leafKey = strategy.path[strategy.path.length - 1];
51081
51067
  let parent = nextPackageJson;
51082
51068
  for (const key of parentKeys) {
51083
51069
  const existing = parent[key];
51084
- const cloned = isRecord(existing) ? { ...existing } : {};
51070
+ const cloned = isRecord$1(existing) ? { ...existing } : {};
51085
51071
  parent[key] = cloned;
51086
51072
  parent = cloned;
51087
51073
  }
@@ -51252,7 +51238,7 @@ const isHuskyProject = (projectRoot) => NFS.existsSync(Path.join(projectRoot, ".
51252
51238
  const isVitePlusProject = (projectRoot) => packageHasDependency(projectRoot, "vite-plus");
51253
51239
  const isSimpleGitHooksProject = (projectRoot) => {
51254
51240
  const packageJson = readPackageJson(projectRoot);
51255
- return isRecord(packageJson) && isRecord(packageJson["simple-git-hooks"]) || packageHasDependency(projectRoot, "simple-git-hooks") || NFS.existsSync(Path.join(projectRoot, ".simple-git-hooks.cjs"));
51241
+ return isRecord$1(packageJson) && isRecord$1(packageJson["simple-git-hooks"]) || packageHasDependency(projectRoot, "simple-git-hooks") || NFS.existsSync(Path.join(projectRoot, ".simple-git-hooks.cjs"));
51256
51242
  };
51257
51243
  const getLefthookConfigPath = (projectRoot) => {
51258
51244
  for (const fileName of LEFTHOOK_CONFIG_FILES) {
@@ -51418,7 +51404,7 @@ const detectPackageManager = (projectRoot) => {
51418
51404
  let currentDirectory = Path.resolve(projectRoot);
51419
51405
  while (true) {
51420
51406
  const packageJson = readPackageJson(currentDirectory);
51421
- if (isRecord(packageJson) && typeof packageJson.packageManager === "string") {
51407
+ if (isRecord$1(packageJson) && typeof packageJson.packageManager === "string") {
51422
51408
  const packageManagerName = packageJson.packageManager.split("@")[0];
51423
51409
  if (packageManagerName === "pnpm" || packageManagerName === "yarn" || packageManagerName === "bun" || packageManagerName === "npm") return packageManagerName;
51424
51410
  }
@@ -51494,12 +51480,12 @@ const isSupplyChainTrustError = (error) => {
51494
51480
  const formatInstallCommand = (input) => [input.command, ...input.args].join(" ");
51495
51481
  const installReactDoctorDependency = async (options) => {
51496
51482
  const packageJson = readPackageJson(options.projectRoot);
51497
- if (!isRecord(packageJson)) return {
51483
+ if (!isRecord$1(packageJson)) return {
51498
51484
  dependencyStatus: "skipped",
51499
51485
  dependencyReason: "missing-or-invalid-package-json"
51500
51486
  };
51501
51487
  if (hasDoctorDependency(packageJson)) return { dependencyStatus: "existing" };
51502
- if (packageJson.devDependencies !== void 0 && !isRecord(packageJson.devDependencies)) return {
51488
+ if (packageJson.devDependencies !== void 0 && !isRecord$1(packageJson.devDependencies)) return {
51503
51489
  dependencyStatus: "skipped",
51504
51490
  dependencyReason: "invalid-dev-dependencies"
51505
51491
  };
@@ -54124,4 +54110,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
54124
54110
  export {};
54125
54111
 
54126
54112
  //# sourceMappingURL=cli.js.map
54127
- //# debugId=ad091b20-c3e2-5c96-93ac-9a910745a035
54113
+ //# debugId=a06f0514-b1fa-5452-9c19-0140438862f8
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]="4e83db09-9255-525f-b6fd-405784826e7d")}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]="36898527-7b70-58ed-8b5b-19ca48903764")}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";
@@ -33620,6 +33620,11 @@ const ES_TARGET_YEAR_BY_NAME = {
33620
33620
  esnext: 9999
33621
33621
  };
33622
33622
  /**
33623
+ * tsconfig filenames probed when resolving a project's TypeScript
33624
+ * compiler options — the root config first, then a monorepo base config.
33625
+ */
33626
+ const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
33627
+ /**
33623
33628
  * Project-config files that `StagedFiles.materialize` copies into
33624
33629
  * the temp directory alongside staged sources so oxlint resolves
33625
33630
  * `tsconfig` / `package.json` / lint configs the same way it would
@@ -36705,8 +36710,8 @@ const collectIgnorePatterns = (rootDirectory) => {
36705
36710
  cachedPatternsByRoot.set(rootDirectory, patterns);
36706
36711
  return patterns;
36707
36712
  };
36713
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
36708
36714
  const KNIP_JSON_FILENAME = "knip.json";
36709
- const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
36710
36715
  const readJsonFileSafe = (filePath) => {
36711
36716
  let rawContents;
36712
36717
  try {
@@ -36722,10 +36727,10 @@ const readJsonFileSafe = (filePath) => {
36722
36727
  };
36723
36728
  const readKnipConfig = (rootDirectory) => {
36724
36729
  const knipJson = readJsonFileSafe(path.join(rootDirectory, KNIP_JSON_FILENAME));
36725
- if (isRecord$1(knipJson)) return knipJson;
36730
+ if (isRecord(knipJson)) return knipJson;
36726
36731
  const packageJson = readJsonFileSafe(path.join(rootDirectory, "package.json"));
36727
- const packageKnipConfig = isRecord$1(packageJson) ? packageJson.knip : null;
36728
- return isRecord$1(packageKnipConfig) ? packageKnipConfig : null;
36732
+ const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
36733
+ return isRecord(packageKnipConfig) ? packageKnipConfig : null;
36729
36734
  };
36730
36735
  const normalizePatternList = (value) => {
36731
36736
  if (typeof value === "string" && value.length > 0) return [value];
@@ -36737,10 +36742,10 @@ const prefixWorkspacePatterns = (workspacePattern, patterns) => {
36737
36742
  return patterns.map((pattern) => pattern.startsWith("!") ? `!${normalizedWorkspacePattern}/${pattern.slice(1)}` : `${normalizedWorkspacePattern}/${pattern}`);
36738
36743
  };
36739
36744
  const collectKnipWorkspacePatterns = (workspaces, settingName) => {
36740
- if (!isRecord$1(workspaces)) return [];
36745
+ if (!isRecord(workspaces)) return [];
36741
36746
  const patterns = [];
36742
36747
  for (const [workspacePattern, workspaceConfig] of Object.entries(workspaces)) {
36743
- if (!isRecord$1(workspaceConfig)) continue;
36748
+ if (!isRecord(workspaceConfig)) continue;
36744
36749
  patterns.push(...prefixWorkspacePatterns(workspacePattern, normalizePatternList(workspaceConfig[settingName])));
36745
36750
  }
36746
36751
  return patterns;
@@ -36785,8 +36790,6 @@ const toCanonicalPath = (filePath) => {
36785
36790
  };
36786
36791
  const DEAD_CODE_PLUGIN = "deslop";
36787
36792
  const DEAD_CODE_CATEGORY = "Maintainability";
36788
- const TSCONFIG_FILENAMES$1 = ["tsconfig.json", "tsconfig.base.json"];
36789
- const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
36790
36793
  const DEAD_CODE_WORKER_SCRIPT = `
36791
36794
  const inputChunks = [];
36792
36795
  process.stdin.on("data", (chunk) => inputChunks.push(chunk));
@@ -36844,7 +36847,7 @@ process.stdin.on("end", () => {
36844
36847
  });
36845
36848
  `;
36846
36849
  const resolveTsConfigPath = (rootDirectory) => {
36847
- for (const filename of TSCONFIG_FILENAMES$1) {
36850
+ for (const filename of TSCONFIG_FILENAMES) {
36848
36851
  const candidate = Path.join(rootDirectory, filename);
36849
36852
  if (NFS.existsSync(candidate)) return candidate;
36850
36853
  }
@@ -38145,7 +38148,6 @@ const resolveOxlintBinary = () => {
38145
38148
  return Path.join(oxlintPackageDirectory, "bin", "oxlint");
38146
38149
  };
38147
38150
  const resolvePluginPath = () => esmRequire.resolve("oxlint-plugin-react-doctor");
38148
- const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
38149
38151
  const resolveTsConfigRelativePath = (rootDirectory) => {
38150
38152
  for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
38151
38153
  return null;
@@ -38517,7 +38519,7 @@ const scopeContainsNonImportBinding = (node, scopeNode, identifierName) => {
38517
38519
  const isIdentifierShadowedByLocalBinding = (identifier, sourceFile) => {
38518
38520
  let currentNode = identifier.parent;
38519
38521
  while (currentNode) {
38520
- if (isScopeNode(currentNode)) {
38522
+ if (isScopeBoundary(currentNode)) {
38521
38523
  if (scopeContainsNonImportBinding(currentNode, currentNode, identifier.text)) return true;
38522
38524
  }
38523
38525
  if (currentNode === sourceFile) return false;
@@ -38608,11 +38610,10 @@ const findResolutionInScope = (scopeNode, identifierName, reactImportBindings, s
38608
38610
  });
38609
38611
  return resolution;
38610
38612
  };
38611
- const isScopeNode = isScopeBoundary;
38612
38613
  const resolveIdentifierBinding = (identifier, reactImportBindings, sourceFile, visitedDeclarations = /* @__PURE__ */ new Set()) => {
38613
38614
  let currentNode = identifier.parent;
38614
38615
  while (currentNode) {
38615
- if (isScopeNode(currentNode)) {
38616
+ if (isScopeBoundary(currentNode)) {
38616
38617
  const resolution = findResolutionInScope(currentNode, identifier.text, reactImportBindings, sourceFile, visitedDeclarations);
38617
38618
  if (resolution) return resolution;
38618
38619
  }
@@ -40604,4 +40605,4 @@ const toJsonReport = (result, options) => buildJsonReport({
40604
40605
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
40605
40606
 
40606
40607
  //# sourceMappingURL=index.js.map
40607
- //# debugId=4e83db09-9255-525f-b6fd-405784826e7d
40608
+ //# debugId=36898527-7b70-58ed-8b5b-19ca48903764
package/dist/lsp.js CHANGED
@@ -33657,6 +33657,11 @@ const ES_TARGET_YEAR_BY_NAME = {
33657
33657
  esnext: 9999
33658
33658
  };
33659
33659
  /**
33660
+ * tsconfig filenames probed when resolving a project's TypeScript
33661
+ * compiler options — the root config first, then a monorepo base config.
33662
+ */
33663
+ const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
33664
+ /**
33660
33665
  * Project-config files that `StagedFiles.materialize` copies into
33661
33666
  * the temp directory alongside staged sources so oxlint resolves
33662
33667
  * `tsconfig` / `package.json` / lint configs the same way it would
@@ -36691,8 +36696,8 @@ const collectIgnorePatterns = (rootDirectory) => {
36691
36696
  cachedPatternsByRoot.set(rootDirectory, patterns);
36692
36697
  return patterns;
36693
36698
  };
36699
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
36694
36700
  const KNIP_JSON_FILENAME = "knip.json";
36695
- const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
36696
36701
  const readJsonFileSafe = (filePath) => {
36697
36702
  let rawContents;
36698
36703
  try {
@@ -36708,10 +36713,10 @@ const readJsonFileSafe = (filePath) => {
36708
36713
  };
36709
36714
  const readKnipConfig = (rootDirectory) => {
36710
36715
  const knipJson = readJsonFileSafe(path.join(rootDirectory, KNIP_JSON_FILENAME));
36711
- if (isRecord$1(knipJson)) return knipJson;
36716
+ if (isRecord(knipJson)) return knipJson;
36712
36717
  const packageJson = readJsonFileSafe(path.join(rootDirectory, "package.json"));
36713
- const packageKnipConfig = isRecord$1(packageJson) ? packageJson.knip : null;
36714
- return isRecord$1(packageKnipConfig) ? packageKnipConfig : null;
36718
+ const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
36719
+ return isRecord(packageKnipConfig) ? packageKnipConfig : null;
36715
36720
  };
36716
36721
  const normalizePatternList = (value) => {
36717
36722
  if (typeof value === "string" && value.length > 0) return [value];
@@ -36723,10 +36728,10 @@ const prefixWorkspacePatterns = (workspacePattern, patterns) => {
36723
36728
  return patterns.map((pattern) => pattern.startsWith("!") ? `!${normalizedWorkspacePattern}/${pattern.slice(1)}` : `${normalizedWorkspacePattern}/${pattern}`);
36724
36729
  };
36725
36730
  const collectKnipWorkspacePatterns = (workspaces, settingName) => {
36726
- if (!isRecord$1(workspaces)) return [];
36731
+ if (!isRecord(workspaces)) return [];
36727
36732
  const patterns = [];
36728
36733
  for (const [workspacePattern, workspaceConfig] of Object.entries(workspaces)) {
36729
- if (!isRecord$1(workspaceConfig)) continue;
36734
+ if (!isRecord(workspaceConfig)) continue;
36730
36735
  patterns.push(...prefixWorkspacePatterns(workspacePattern, normalizePatternList(workspaceConfig[settingName])));
36731
36736
  }
36732
36737
  return patterns;
@@ -36771,8 +36776,6 @@ const toCanonicalPath = (filePath) => {
36771
36776
  };
36772
36777
  const DEAD_CODE_PLUGIN = "deslop";
36773
36778
  const DEAD_CODE_CATEGORY = "Maintainability";
36774
- const TSCONFIG_FILENAMES$1 = ["tsconfig.json", "tsconfig.base.json"];
36775
- const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
36776
36779
  const DEAD_CODE_WORKER_SCRIPT = `
36777
36780
  const inputChunks = [];
36778
36781
  process.stdin.on("data", (chunk) => inputChunks.push(chunk));
@@ -36830,7 +36833,7 @@ process.stdin.on("end", () => {
36830
36833
  });
36831
36834
  `;
36832
36835
  const resolveTsConfigPath = (rootDirectory) => {
36833
- for (const filename of TSCONFIG_FILENAMES$1) {
36836
+ for (const filename of TSCONFIG_FILENAMES) {
36834
36837
  const candidate = Path.join(rootDirectory, filename);
36835
36838
  if (NFS.existsSync(candidate)) return candidate;
36836
36839
  }
@@ -38131,7 +38134,6 @@ const resolveOxlintBinary = () => {
38131
38134
  return Path.join(oxlintPackageDirectory, "bin", "oxlint");
38132
38135
  };
38133
38136
  const resolvePluginPath = () => esmRequire.resolve("oxlint-plugin-react-doctor");
38134
- const TSCONFIG_FILENAMES = ["tsconfig.json", "tsconfig.base.json"];
38135
38137
  const resolveTsConfigRelativePath = (rootDirectory) => {
38136
38138
  for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
38137
38139
  return null;
@@ -38503,7 +38505,7 @@ const scopeContainsNonImportBinding = (node, scopeNode, identifierName) => {
38503
38505
  const isIdentifierShadowedByLocalBinding = (identifier, sourceFile) => {
38504
38506
  let currentNode = identifier.parent;
38505
38507
  while (currentNode) {
38506
- if (isScopeNode(currentNode)) {
38508
+ if (isScopeBoundary(currentNode)) {
38507
38509
  if (scopeContainsNonImportBinding(currentNode, currentNode, identifier.text)) return true;
38508
38510
  }
38509
38511
  if (currentNode === sourceFile) return false;
@@ -38594,11 +38596,10 @@ const findResolutionInScope = (scopeNode, identifierName, reactImportBindings, s
38594
38596
  });
38595
38597
  return resolution;
38596
38598
  };
38597
- const isScopeNode = isScopeBoundary;
38598
38599
  const resolveIdentifierBinding = (identifier, reactImportBindings, sourceFile, visitedDeclarations = /* @__PURE__ */ new Set()) => {
38599
38600
  let currentNode = identifier.parent;
38600
38601
  while (currentNode) {
38601
- if (isScopeNode(currentNode)) {
38602
+ if (isScopeBoundary(currentNode)) {
38602
38603
  const resolution = findResolutionInScope(currentNode, identifier.text, reactImportBindings, sourceFile, visitedDeclarations);
38603
38604
  if (resolution) return resolution;
38604
38605
  }
@@ -41002,6 +41003,11 @@ const createProjectGraph = (options) => {
41002
41003
  }
41003
41004
  };
41004
41005
  };
41006
+ const toProjectRelative = (projectDirectory, filePath) => {
41007
+ const relative = Path.relative(projectDirectory, filePath).replace(/\\/g, "/");
41008
+ if (relative.length === 0 || relative.startsWith("../") || Path.isAbsolute(relative)) return null;
41009
+ return relative;
41010
+ };
41005
41011
  const resolveCacheFilePath = (projectDirectory) => {
41006
41012
  const nodeModules = path.join(projectDirectory, "node_modules");
41007
41013
  if (fs.existsSync(nodeModules)) return path.join(nodeModules, ".cache", "react-doctor", "lint-cache.json");
@@ -41062,11 +41068,6 @@ const createLintCache = (input) => {
41062
41068
  };
41063
41069
  const OVERLAY_TEMP_PREFIX = "react-doctor-lsp-";
41064
41070
  const OVERLAY_CONFIG_FILENAMES = [...new Set([...STAGED_FILES_PROJECT_CONFIG_FILENAMES, ...ADOPTABLE_LINT_CONFIG_FILENAMES])];
41065
- const toProjectRelative$1 = (projectDirectory, filePath) => {
41066
- const relative = path.relative(projectDirectory, filePath).replace(/\\/g, "/");
41067
- if (relative.length === 0 || relative.startsWith("../") || path.isAbsolute(relative)) return null;
41068
- return relative;
41069
- };
41070
41071
  /**
41071
41072
  * Writes the live (possibly unsaved) content of the target files into a
41072
41073
  * throwaway temp tree that mirrors the project, alongside the well-known
@@ -41080,7 +41081,7 @@ const materializeOverlay = (input) => {
41080
41081
  const relativePaths = [];
41081
41082
  try {
41082
41083
  for (const filePath of input.files) {
41083
- const relative = toProjectRelative$1(input.projectDirectory, filePath);
41084
+ const relative = toProjectRelative(input.projectDirectory, filePath);
41084
41085
  if (relative === null) continue;
41085
41086
  const content = input.readText(filePath);
41086
41087
  if (content === null) continue;
@@ -41128,11 +41129,6 @@ const materializeOverlay = (input) => {
41128
41129
  throw error;
41129
41130
  }
41130
41131
  };
41131
- const toProjectRelative = (projectDirectory, filePath) => {
41132
- const relative = path.relative(projectDirectory, filePath).replace(/\\/g, "/");
41133
- if (relative.length === 0 || relative.startsWith("../") || path.isAbsolute(relative)) return null;
41134
- return relative;
41135
- };
41136
41132
  /**
41137
41133
  * Resolves a diagnostic's (possibly relative, possibly overlay-temp)
41138
41134
  * file path back to the canonical absolute path inside the real project.
@@ -42389,5 +42385,5 @@ const startLanguageServer = () => {
42389
42385
  };
42390
42386
  //#endregion
42391
42387
  export { startLanguageServer };
42392
- !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]="7deadb2d-94c2-54e2-bd0d-808ee8d4c380")}catch(e){}}();
42393
- //# debugId=7deadb2d-94c2-54e2-bd0d-808ee8d4c380
42388
+ !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]="42683a4c-8da1-5155-bf9c-b9a69b9718e6")}catch(e){}}();
42389
+ //# debugId=42683a4c-8da1-5155-bf9c-b9a69b9718e6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.5.6-dev.b8170f8",
3
+ "version": "0.5.6-dev.ed0258c",
4
4
  "description": "Your agent writes bad React. This catches it",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -64,7 +64,7 @@
64
64
  "vscode-languageserver": "^9.0.1",
65
65
  "vscode-languageserver-textdocument": "^1.0.12",
66
66
  "vscode-uri": "^3.1.0",
67
- "oxlint-plugin-react-doctor": "0.5.6-dev.b8170f8"
67
+ "oxlint-plugin-react-doctor": "0.5.6-dev.ed0258c"
68
68
  },
69
69
  "devDependencies": {
70
70
  "@types/babel__code-frame": "^7.27.0",