react-doctor 0.9.4-dev.da0647e → 0.9.5-dev.2b8bc5c

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/index.d.ts CHANGED
@@ -9834,13 +9834,13 @@ interface InspectResult {
9834
9834
  * Number of files the scan reported. Distinct from
9835
9835
  * `project.sourceFileCount` in diff / staged mode (where only changed
9836
9836
  * files are scanned). Optional so non-orchestrator constructors keep
9837
- * working; the multi-project summary falls back to
9837
+ * working; the multi-project report falls back to
9838
9838
  * `project.sourceFileCount` when absent.
9839
9839
  */
9840
9840
  scannedFileCount?: number;
9841
9841
  /**
9842
9842
  * Absolute paths of every file the scan considered. Lets the
9843
- * multi-project summary count UNIQUE files across projects instead of
9843
+ * multi-project report count UNIQUE files across projects instead of
9844
9844
  * summing per-project counts, which double-counts shared files when one
9845
9845
  * workspace package's tree is nested inside another's.
9846
9846
  */
@@ -9854,8 +9854,8 @@ interface InspectResult {
9854
9854
  /**
9855
9855
  * Wall-clock duration of the scan phase, in milliseconds. Distinct
9856
9856
  * from `elapsedMilliseconds` (which spans the full `inspect()` call
9857
- * including score fetch + rendering). Used by the multi-project
9858
- * summary to report combined scan time.
9857
+ * including score fetch + reporting). Used by the multi-project
9858
+ * report to show combined scan time.
9859
9859
  */
9860
9860
  scanElapsedMilliseconds?: number;
9861
9861
  /**
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]="6d2e43de-ae97-5213-b1a7-a9905ce4b1d5")}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]="5415308a-0150-547d-9270-806382225dcf")}catch(e){}}();
3
3
  import { i as __toESM$1, r as __require, t as __commonJSMin$1 } from "./chunk-ChKA3wi6.js";
4
4
  import { createRequire } from "node:module";
5
5
  import { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, REACT_DOCTOR_RULE_REGISTRY, REACT_DOCTOR_SCAN_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor/core";
@@ -17,8 +17,8 @@ import * as NodeUrl from "node:url";
17
17
  import { fileURLToPath } from "node:url";
18
18
  import * as OS from "node:os";
19
19
  import os from "node:os";
20
- import { parseJSON5 } from "confbox";
21
20
  import { createJiti } from "jiti";
21
+ import { parseJSON5 } from "confbox";
22
22
  import { ANALYZED_MANIFEST_FILENAMES, DEFAULT_EXTENSIONS } from "deslop-js/analyzed-inputs";
23
23
  import { convertToTSX } from "@astrojs/compiler/sync";
24
24
  import { gzipSync } from "node:zlib";
@@ -62285,7 +62285,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
62285
62285
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
62286
62286
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
62287
62287
  const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
62288
- const CORE_PACKAGE_VERSION = "0.9.4";
62288
+ const CORE_PACKAGE_VERSION = "0.9.5";
62289
62289
  const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
62290
62290
  const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
62291
62291
  const SUPPLY_CHAIN_PLUGIN = "socket";
@@ -66803,6 +66803,11 @@ var DeadCodeResultCacheEnabled = class extends Reference("react-doctor/DeadCodeR
66803
66803
  if (CACHE_DISABLED_VALUES.has(noDeadCodeCache)) return false;
66804
66804
  return true;
66805
66805
  } }) {};
66806
+ const importDefaultExport = async (jitiInstance, filePath) => {
66807
+ const imported = await jitiInstance.import(filePath);
66808
+ return imported?.default ?? imported;
66809
+ };
66810
+ const readJson5File = (filePath) => parseJSON5(NFS.readFileSync(filePath, "utf-8"));
66806
66811
  const DIAGNOSTIC_SURFACES = [
66807
66812
  "cli",
66808
66813
  "prComment",
@@ -67033,11 +67038,7 @@ const DATA_CONFIG_EXTENSIONS = new Set(["json", "jsonc"]);
67033
67038
  const PACKAGE_JSON_FILENAME = "package.json";
67034
67039
  const PACKAGE_JSON_CONFIG_KEY = "reactDoctor";
67035
67040
  const LEGACY_CONFIG_FILENAME = "react-doctor.config.json";
67036
- const jiti = createJiti(import.meta.url);
67037
- const importDefaultExport = async (jitiInstance, filePath) => {
67038
- const imported = await jitiInstance.import(filePath);
67039
- return imported?.default ?? imported;
67040
- };
67041
+ const jiti$1 = createJiti(import.meta.url);
67041
67042
  const SELF_PACKAGE_IMPORT_SPECIFIER = "react-doctor/api";
67042
67043
  const SELF_PACKAGE_RESOLVE_TARGETS = ["react-doctor/api", "@react-doctor/core"];
67043
67044
  const MODULE_NOT_FOUND_ERROR_CODES = new Set(["MODULE_NOT_FOUND", "ERR_MODULE_NOT_FOUND"]);
@@ -67045,7 +67046,7 @@ let selfAliasJiti;
67045
67046
  const getSelfAliasJiti = () => {
67046
67047
  if (selfAliasJiti !== void 0) return selfAliasJiti;
67047
67048
  for (const resolveTarget of SELF_PACKAGE_RESOLVE_TARGETS) try {
67048
- const aliasTargetPath = fileURLToPath(jiti.esmResolve(resolveTarget));
67049
+ const aliasTargetPath = fileURLToPath(jiti$1.esmResolve(resolveTarget));
67049
67050
  selfAliasJiti = createJiti(import.meta.url, { alias: { [SELF_PACKAGE_IMPORT_SPECIFIER]: aliasTargetPath } });
67050
67051
  return selfAliasJiti;
67051
67052
  } catch {
@@ -67057,7 +67058,7 @@ const getSelfAliasJiti = () => {
67057
67058
  const isSelfPackageResolutionError = (error) => error instanceof Error && "code" in error && typeof error.code === "string" && MODULE_NOT_FOUND_ERROR_CODES.has(error.code) && error.message.includes(SELF_PACKAGE_IMPORT_SPECIFIER);
67058
67059
  const loadModuleConfig = async (filePath) => {
67059
67060
  try {
67060
- return await importDefaultExport(jiti, filePath);
67061
+ return await importDefaultExport(jiti$1, filePath);
67061
67062
  } catch (error) {
67062
67063
  if (!isSelfPackageResolutionError(error)) throw error;
67063
67064
  const aliasJiti = getSelfAliasJiti();
@@ -67069,12 +67070,11 @@ const loadModuleConfig = async (filePath) => {
67069
67070
  }
67070
67071
  }
67071
67072
  };
67072
- const readDataConfig = (filePath) => parseJSON5(NFS.readFileSync(filePath, "utf-8"));
67073
67073
  const readEmbeddedPackageJsonConfig = (directory) => {
67074
67074
  const packageJsonPath = Path.join(directory, PACKAGE_JSON_FILENAME);
67075
67075
  if (!isFile(packageJsonPath)) return null;
67076
67076
  try {
67077
- const packageJson = parseJSON5(NFS.readFileSync(packageJsonPath, "utf-8"));
67077
+ const packageJson = readJson5File(packageJsonPath);
67078
67078
  if (isPlainObject(packageJson)) {
67079
67079
  const embeddedConfig = packageJson[PACKAGE_JSON_CONFIG_KEY];
67080
67080
  if (isPlainObject(embeddedConfig)) return embeddedConfig;
@@ -67099,7 +67099,7 @@ const loadLegacyConfig = (directory) => {
67099
67099
  loaded: null
67100
67100
  };
67101
67101
  try {
67102
- const parsed = readDataConfig(legacyFilePath);
67102
+ const parsed = readJson5File(legacyFilePath);
67103
67103
  if (isPlainObject(parsed)) {
67104
67104
  warn(`${LEGACY_CONFIG_FILENAME} is deprecated — rename it to ${CONFIG_BASENAME}.json (or author a ${CONFIG_BASENAME}.ts). It is still read for now.`);
67105
67105
  return {
@@ -67128,7 +67128,7 @@ const loadConfigFromDirectory = async (directory) => {
67128
67128
  if (!isFile(filePath)) continue;
67129
67129
  const isDataFile = DATA_CONFIG_EXTENSIONS.has(extension);
67130
67130
  try {
67131
- const parsed = isDataFile ? readDataConfig(filePath) : await loadModuleConfig(filePath);
67131
+ const parsed = isDataFile ? readJson5File(filePath) : await loadModuleConfig(filePath);
67132
67132
  if (isPlainObject(parsed)) return {
67133
67133
  status: "found",
67134
67134
  loaded: {
@@ -69330,20 +69330,45 @@ const collectIgnorePatterns = (rootDirectory) => {
69330
69330
  cachedPatternsByRoot.set(rootDirectory, patterns);
69331
69331
  return patterns;
69332
69332
  };
69333
- const failOpenReadJson = (filePath, fallback) => {
69333
+ const KNIP_DATA_CONFIG_FILENAMES = new Set([
69334
+ "knip.json",
69335
+ "knip.jsonc",
69336
+ ".knip.json",
69337
+ ".knip.jsonc"
69338
+ ]);
69339
+ const KNIP_CONFIG_FILENAMES = [
69340
+ ...KNIP_DATA_CONFIG_FILENAMES,
69341
+ "knip.ts",
69342
+ "knip.js",
69343
+ "knip.config.ts",
69344
+ "knip.config.js"
69345
+ ];
69346
+ const jiti = createJiti(import.meta.url, { moduleCache: false });
69347
+ const resolveKnipConfigExport = async (configExport) => {
69348
+ const config = typeof configExport === "function" ? await configExport() : await configExport;
69349
+ return isRecord(config) ? config : null;
69350
+ };
69351
+ const loadKnipConfigFile = async (configFilename, filePath) => {
69334
69352
  try {
69335
- return JSON.parse(NFS.readFileSync(filePath, "utf8"));
69353
+ return await resolveKnipConfigExport(KNIP_DATA_CONFIG_FILENAMES.has(configFilename) ? readJson5File(filePath) : await importDefaultExport(jiti, filePath));
69336
69354
  } catch {
69337
- return fallback;
69355
+ return null;
69338
69356
  }
69339
69357
  };
69340
- const KNIP_JSON_FILENAME = "knip.json";
69341
- const readKnipConfig = (rootDirectory) => {
69342
- const knipJson = failOpenReadJson(path.join(rootDirectory, KNIP_JSON_FILENAME), null);
69343
- if (isRecord(knipJson)) return knipJson;
69344
- const packageJson = failOpenReadJson(path.join(rootDirectory, "package.json"), null);
69345
- const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
69346
- return isRecord(packageKnipConfig) ? packageKnipConfig : null;
69358
+ const loadKnipConfig = async (rootDirectory) => {
69359
+ for (const configFilename of KNIP_CONFIG_FILENAMES) {
69360
+ const filePath = path.join(rootDirectory, configFilename);
69361
+ if (!isFile(filePath)) continue;
69362
+ const config = await loadKnipConfigFile(configFilename, filePath);
69363
+ if (config) return config;
69364
+ }
69365
+ try {
69366
+ const packageJson = readJson5File(path.join(rootDirectory, "package.json"));
69367
+ const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
69368
+ return isRecord(packageKnipConfig) ? packageKnipConfig : null;
69369
+ } catch {
69370
+ return null;
69371
+ }
69347
69372
  };
69348
69373
  const normalizePatternList = (value) => {
69349
69374
  if (typeof value === "string" && value.length > 0) return [value];
@@ -69363,22 +69388,28 @@ const collectKnipWorkspacePatterns = (workspaces, settingName) => {
69363
69388
  }
69364
69389
  return patterns;
69365
69390
  };
69366
- const collectKnipPatterns = (rootDirectory, settingName) => {
69367
- const config = readKnipConfig(rootDirectory);
69391
+ const collectKnipPatterns = (config, settingName) => {
69368
69392
  if (!config) return [];
69369
69393
  return [...normalizePatternList(config[settingName]), ...collectKnipWorkspacePatterns(config.workspaces, settingName)];
69370
69394
  };
69371
- const collectDeadCodeIgnorePatterns = (rootDirectory) => {
69395
+ const collectDeadCodeIgnorePatterns = (rootDirectory, config) => {
69372
69396
  const seen = /* @__PURE__ */ new Set();
69373
69397
  const sources = [
69374
69398
  readIgnoreFile(path.join(rootDirectory, ".gitignore")),
69375
69399
  collectIgnorePatterns(rootDirectory),
69376
- collectKnipPatterns(rootDirectory, "ignore")
69400
+ collectKnipPatterns(config, "ignore")
69377
69401
  ];
69378
69402
  for (const source of sources) for (const pattern of source) seen.add(pattern);
69379
69403
  return [...seen].filter((pattern) => pattern.length > 0);
69380
69404
  };
69381
- const collectDeadCodeEntryPatterns = (rootDirectory) => [...new Set(collectKnipPatterns(rootDirectory, "entry"))].filter((pattern) => pattern.length > 0);
69405
+ const collectDeadCodeEntryPatterns = (config) => [...new Set(collectKnipPatterns(config, "entry"))].filter((pattern) => pattern.length > 0);
69406
+ const collectDeadCodePatterns = async (rootDirectory) => {
69407
+ const config = await loadKnipConfig(rootDirectory);
69408
+ return {
69409
+ entryPatterns: collectDeadCodeEntryPatterns(config),
69410
+ ignorePatterns: collectDeadCodeIgnorePatterns(rootDirectory, config)
69411
+ };
69412
+ };
69382
69413
  const atomicWriteJson = (filePath, value) => {
69383
69414
  try {
69384
69415
  NFS.mkdirSync(Path.dirname(filePath), { recursive: true });
@@ -69389,6 +69420,13 @@ const atomicWriteJson = (filePath, value) => {
69389
69420
  return;
69390
69421
  }
69391
69422
  };
69423
+ const failOpenReadJson = (filePath, fallback) => {
69424
+ try {
69425
+ return JSON.parse(NFS.readFileSync(filePath, "utf8"));
69426
+ } catch {
69427
+ return fallback;
69428
+ }
69429
+ };
69392
69430
  const hashFileContents = (filePath) => {
69393
69431
  try {
69394
69432
  return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
@@ -69397,7 +69435,7 @@ const hashFileContents = (filePath) => {
69397
69435
  }
69398
69436
  };
69399
69437
  const ANALYZED_FILE_EXTENSIONS = new Set(DEFAULT_EXTENSIONS);
69400
- const CORE_SIDE_MANIFEST_NAMES = ["knip.json", "deno.lock"];
69438
+ const CORE_SIDE_MANIFEST_NAMES = [...KNIP_CONFIG_FILENAMES, "deno.lock"];
69401
69439
  const ANALYZED_MANIFEST_NAMES = new Set([...ANALYZED_MANIFEST_FILENAMES, ...CORE_SIDE_MANIFEST_NAMES]);
69402
69440
  const isTsConfigLikeFile = (fileName) => (fileName.startsWith("tsconfig") || fileName.startsWith("jsconfig")) && fileName.endsWith(".json");
69403
69441
  const isFingerprintedFile = (fileName) => ANALYZED_FILE_EXTENSIONS.has(Path.extname(fileName).toLowerCase()) || ANALYZED_MANIFEST_NAMES.has(fileName) || isTsConfigLikeFile(fileName);
@@ -69923,8 +69961,7 @@ const runDeadCodeWorkerWithTimeout = (handle, timeoutMs, abortSignal) => new Pro
69923
69961
  const checkDeadCode = async (options) => {
69924
69962
  const rootDirectory = toCanonicalPath(options.rootDirectory);
69925
69963
  if (!NFS.existsSync(Path.join(rootDirectory, "package.json"))) return [];
69926
- const entryPatterns = collectDeadCodeEntryPatterns(rootDirectory);
69927
- const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
69964
+ const { entryPatterns, ignorePatterns } = await collectDeadCodePatterns(rootDirectory);
69928
69965
  const tsConfigPath = resolveTsConfigPath(rootDirectory);
69929
69966
  const deslopJsModuleSpecifier = options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js");
69930
69967
  const fileStatsSnapshot = options.cacheEnabled ? collectAnalyzedFileStats(rootDirectory) : null;
@@ -75914,4 +75951,4 @@ const toJsonReport = (result, options) => buildJsonReport({
75914
75951
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
75915
75952
 
75916
75953
  //# sourceMappingURL=index.js.map
75917
- //# debugId=6d2e43de-ae97-5213-b1a7-a9905ce4b1d5
75954
+ //# debugId=5415308a-0150-547d-9270-806382225dcf
package/dist/lsp.js CHANGED
@@ -14,8 +14,8 @@ import { ResolverFactory } from "oxc-resolver";
14
14
  import ts from "typescript";
15
15
  import * as NodeUrl from "node:url";
16
16
  import { fileURLToPath } from "node:url";
17
- import { parseJSON5 } from "confbox";
18
17
  import { createJiti } from "jiti";
18
+ import { parseJSON5 } from "confbox";
19
19
  import { ANALYZED_MANIFEST_FILENAMES, DEFAULT_EXTENSIONS } from "deslop-js/analyzed-inputs";
20
20
  import { convertToTSX } from "@astrojs/compiler/sync";
21
21
  import { gzipSync } from "node:zlib";
@@ -62384,7 +62384,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
62384
62384
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
62385
62385
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
62386
62386
  const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
62387
- const CORE_PACKAGE_VERSION = "0.9.4";
62387
+ const CORE_PACKAGE_VERSION = "0.9.5";
62388
62388
  const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
62389
62389
  const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
62390
62390
  const SUPPLY_CHAIN_PLUGIN = "socket";
@@ -66880,6 +66880,11 @@ var DeadCodeResultCacheEnabled = class extends Reference("react-doctor/DeadCodeR
66880
66880
  if (CACHE_DISABLED_VALUES.has(noDeadCodeCache)) return false;
66881
66881
  return true;
66882
66882
  } }) {};
66883
+ const importDefaultExport = async (jitiInstance, filePath) => {
66884
+ const imported = await jitiInstance.import(filePath);
66885
+ return imported?.default ?? imported;
66886
+ };
66887
+ const readJson5File = (filePath) => parseJSON5(NFS.readFileSync(filePath, "utf-8"));
66883
66888
  const DIAGNOSTIC_SURFACES = [
66884
66889
  "cli",
66885
66890
  "prComment",
@@ -67110,11 +67115,7 @@ const DATA_CONFIG_EXTENSIONS = new Set(["json", "jsonc"]);
67110
67115
  const PACKAGE_JSON_FILENAME = "package.json";
67111
67116
  const PACKAGE_JSON_CONFIG_KEY = "reactDoctor";
67112
67117
  const LEGACY_CONFIG_FILENAME = "react-doctor.config.json";
67113
- const jiti = createJiti(import.meta.url);
67114
- const importDefaultExport = async (jitiInstance, filePath) => {
67115
- const imported = await jitiInstance.import(filePath);
67116
- return imported?.default ?? imported;
67117
- };
67118
+ const jiti$1 = createJiti(import.meta.url);
67118
67119
  const SELF_PACKAGE_IMPORT_SPECIFIER = "react-doctor/api";
67119
67120
  const SELF_PACKAGE_RESOLVE_TARGETS = ["react-doctor/api", "@react-doctor/core"];
67120
67121
  const MODULE_NOT_FOUND_ERROR_CODES = new Set(["MODULE_NOT_FOUND", "ERR_MODULE_NOT_FOUND"]);
@@ -67122,7 +67123,7 @@ let selfAliasJiti;
67122
67123
  const getSelfAliasJiti = () => {
67123
67124
  if (selfAliasJiti !== void 0) return selfAliasJiti;
67124
67125
  for (const resolveTarget of SELF_PACKAGE_RESOLVE_TARGETS) try {
67125
- const aliasTargetPath = fileURLToPath(jiti.esmResolve(resolveTarget));
67126
+ const aliasTargetPath = fileURLToPath(jiti$1.esmResolve(resolveTarget));
67126
67127
  selfAliasJiti = createJiti(import.meta.url, { alias: { [SELF_PACKAGE_IMPORT_SPECIFIER]: aliasTargetPath } });
67127
67128
  return selfAliasJiti;
67128
67129
  } catch {
@@ -67134,7 +67135,7 @@ const getSelfAliasJiti = () => {
67134
67135
  const isSelfPackageResolutionError = (error) => error instanceof Error && "code" in error && typeof error.code === "string" && MODULE_NOT_FOUND_ERROR_CODES.has(error.code) && error.message.includes(SELF_PACKAGE_IMPORT_SPECIFIER);
67135
67136
  const loadModuleConfig = async (filePath) => {
67136
67137
  try {
67137
- return await importDefaultExport(jiti, filePath);
67138
+ return await importDefaultExport(jiti$1, filePath);
67138
67139
  } catch (error) {
67139
67140
  if (!isSelfPackageResolutionError(error)) throw error;
67140
67141
  const aliasJiti = getSelfAliasJiti();
@@ -67146,12 +67147,11 @@ const loadModuleConfig = async (filePath) => {
67146
67147
  }
67147
67148
  }
67148
67149
  };
67149
- const readDataConfig = (filePath) => parseJSON5(NFS.readFileSync(filePath, "utf-8"));
67150
67150
  const readEmbeddedPackageJsonConfig = (directory) => {
67151
67151
  const packageJsonPath = Path.join(directory, PACKAGE_JSON_FILENAME);
67152
67152
  if (!isFile(packageJsonPath)) return null;
67153
67153
  try {
67154
- const packageJson = parseJSON5(NFS.readFileSync(packageJsonPath, "utf-8"));
67154
+ const packageJson = readJson5File(packageJsonPath);
67155
67155
  if (isPlainObject(packageJson)) {
67156
67156
  const embeddedConfig = packageJson[PACKAGE_JSON_CONFIG_KEY];
67157
67157
  if (isPlainObject(embeddedConfig)) return embeddedConfig;
@@ -67176,7 +67176,7 @@ const loadLegacyConfig = (directory) => {
67176
67176
  loaded: null
67177
67177
  };
67178
67178
  try {
67179
- const parsed = readDataConfig(legacyFilePath);
67179
+ const parsed = readJson5File(legacyFilePath);
67180
67180
  if (isPlainObject(parsed)) {
67181
67181
  warn(`${LEGACY_CONFIG_FILENAME} is deprecated — rename it to ${CONFIG_BASENAME}.json (or author a ${CONFIG_BASENAME}.ts). It is still read for now.`);
67182
67182
  return {
@@ -67205,7 +67205,7 @@ const loadConfigFromDirectory = async (directory) => {
67205
67205
  if (!isFile(filePath)) continue;
67206
67206
  const isDataFile = DATA_CONFIG_EXTENSIONS.has(extension);
67207
67207
  try {
67208
- const parsed = isDataFile ? readDataConfig(filePath) : await loadModuleConfig(filePath);
67208
+ const parsed = isDataFile ? readJson5File(filePath) : await loadModuleConfig(filePath);
67209
67209
  if (isPlainObject(parsed)) return {
67210
67210
  status: "found",
67211
67211
  loaded: {
@@ -69359,20 +69359,45 @@ const collectIgnorePatterns = (rootDirectory) => {
69359
69359
  cachedPatternsByRoot.set(rootDirectory, patterns);
69360
69360
  return patterns;
69361
69361
  };
69362
- const failOpenReadJson = (filePath, fallback) => {
69362
+ const KNIP_DATA_CONFIG_FILENAMES = new Set([
69363
+ "knip.json",
69364
+ "knip.jsonc",
69365
+ ".knip.json",
69366
+ ".knip.jsonc"
69367
+ ]);
69368
+ const KNIP_CONFIG_FILENAMES = [
69369
+ ...KNIP_DATA_CONFIG_FILENAMES,
69370
+ "knip.ts",
69371
+ "knip.js",
69372
+ "knip.config.ts",
69373
+ "knip.config.js"
69374
+ ];
69375
+ const jiti = createJiti(import.meta.url, { moduleCache: false });
69376
+ const resolveKnipConfigExport = async (configExport) => {
69377
+ const config = typeof configExport === "function" ? await configExport() : await configExport;
69378
+ return isRecord(config) ? config : null;
69379
+ };
69380
+ const loadKnipConfigFile = async (configFilename, filePath) => {
69363
69381
  try {
69364
- return JSON.parse(NFS.readFileSync(filePath, "utf8"));
69382
+ return await resolveKnipConfigExport(KNIP_DATA_CONFIG_FILENAMES.has(configFilename) ? readJson5File(filePath) : await importDefaultExport(jiti, filePath));
69365
69383
  } catch {
69366
- return fallback;
69384
+ return null;
69367
69385
  }
69368
69386
  };
69369
- const KNIP_JSON_FILENAME = "knip.json";
69370
- const readKnipConfig = (rootDirectory) => {
69371
- const knipJson = failOpenReadJson(path.join(rootDirectory, KNIP_JSON_FILENAME), null);
69372
- if (isRecord(knipJson)) return knipJson;
69373
- const packageJson = failOpenReadJson(path.join(rootDirectory, "package.json"), null);
69374
- const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
69375
- return isRecord(packageKnipConfig) ? packageKnipConfig : null;
69387
+ const loadKnipConfig = async (rootDirectory) => {
69388
+ for (const configFilename of KNIP_CONFIG_FILENAMES) {
69389
+ const filePath = path.join(rootDirectory, configFilename);
69390
+ if (!isFile(filePath)) continue;
69391
+ const config = await loadKnipConfigFile(configFilename, filePath);
69392
+ if (config) return config;
69393
+ }
69394
+ try {
69395
+ const packageJson = readJson5File(path.join(rootDirectory, "package.json"));
69396
+ const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
69397
+ return isRecord(packageKnipConfig) ? packageKnipConfig : null;
69398
+ } catch {
69399
+ return null;
69400
+ }
69376
69401
  };
69377
69402
  const normalizePatternList = (value) => {
69378
69403
  if (typeof value === "string" && value.length > 0) return [value];
@@ -69392,22 +69417,28 @@ const collectKnipWorkspacePatterns = (workspaces, settingName) => {
69392
69417
  }
69393
69418
  return patterns;
69394
69419
  };
69395
- const collectKnipPatterns = (rootDirectory, settingName) => {
69396
- const config = readKnipConfig(rootDirectory);
69420
+ const collectKnipPatterns = (config, settingName) => {
69397
69421
  if (!config) return [];
69398
69422
  return [...normalizePatternList(config[settingName]), ...collectKnipWorkspacePatterns(config.workspaces, settingName)];
69399
69423
  };
69400
- const collectDeadCodeIgnorePatterns = (rootDirectory) => {
69424
+ const collectDeadCodeIgnorePatterns = (rootDirectory, config) => {
69401
69425
  const seen = /* @__PURE__ */ new Set();
69402
69426
  const sources = [
69403
69427
  readIgnoreFile(path.join(rootDirectory, ".gitignore")),
69404
69428
  collectIgnorePatterns(rootDirectory),
69405
- collectKnipPatterns(rootDirectory, "ignore")
69429
+ collectKnipPatterns(config, "ignore")
69406
69430
  ];
69407
69431
  for (const source of sources) for (const pattern of source) seen.add(pattern);
69408
69432
  return [...seen].filter((pattern) => pattern.length > 0);
69409
69433
  };
69410
- const collectDeadCodeEntryPatterns = (rootDirectory) => [...new Set(collectKnipPatterns(rootDirectory, "entry"))].filter((pattern) => pattern.length > 0);
69434
+ const collectDeadCodeEntryPatterns = (config) => [...new Set(collectKnipPatterns(config, "entry"))].filter((pattern) => pattern.length > 0);
69435
+ const collectDeadCodePatterns = async (rootDirectory) => {
69436
+ const config = await loadKnipConfig(rootDirectory);
69437
+ return {
69438
+ entryPatterns: collectDeadCodeEntryPatterns(config),
69439
+ ignorePatterns: collectDeadCodeIgnorePatterns(rootDirectory, config)
69440
+ };
69441
+ };
69411
69442
  const atomicWriteJson = (filePath, value) => {
69412
69443
  try {
69413
69444
  NFS.mkdirSync(Path.dirname(filePath), { recursive: true });
@@ -69418,6 +69449,13 @@ const atomicWriteJson = (filePath, value) => {
69418
69449
  return;
69419
69450
  }
69420
69451
  };
69452
+ const failOpenReadJson = (filePath, fallback) => {
69453
+ try {
69454
+ return JSON.parse(NFS.readFileSync(filePath, "utf8"));
69455
+ } catch {
69456
+ return fallback;
69457
+ }
69458
+ };
69421
69459
  const hashFileContents = (filePath) => {
69422
69460
  try {
69423
69461
  return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
@@ -69426,7 +69464,7 @@ const hashFileContents = (filePath) => {
69426
69464
  }
69427
69465
  };
69428
69466
  const ANALYZED_FILE_EXTENSIONS = new Set(DEFAULT_EXTENSIONS);
69429
- const CORE_SIDE_MANIFEST_NAMES = ["knip.json", "deno.lock"];
69467
+ const CORE_SIDE_MANIFEST_NAMES = [...KNIP_CONFIG_FILENAMES, "deno.lock"];
69430
69468
  const ANALYZED_MANIFEST_NAMES = new Set([...ANALYZED_MANIFEST_FILENAMES, ...CORE_SIDE_MANIFEST_NAMES]);
69431
69469
  const isTsConfigLikeFile = (fileName) => (fileName.startsWith("tsconfig") || fileName.startsWith("jsconfig")) && fileName.endsWith(".json");
69432
69470
  const isFingerprintedFile = (fileName) => ANALYZED_FILE_EXTENSIONS.has(Path.extname(fileName).toLowerCase()) || ANALYZED_MANIFEST_NAMES.has(fileName) || isTsConfigLikeFile(fileName);
@@ -69952,8 +69990,7 @@ const runDeadCodeWorkerWithTimeout = (handle, timeoutMs, abortSignal) => new Pro
69952
69990
  const checkDeadCode = async (options) => {
69953
69991
  const rootDirectory = toCanonicalPath(options.rootDirectory);
69954
69992
  if (!NFS.existsSync(Path.join(rootDirectory, "package.json"))) return [];
69955
- const entryPatterns = collectDeadCodeEntryPatterns(rootDirectory);
69956
- const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
69993
+ const { entryPatterns, ignorePatterns } = await collectDeadCodePatterns(rootDirectory);
69957
69994
  const tsConfigPath = resolveTsConfigPath(rootDirectory);
69958
69995
  const deslopJsModuleSpecifier = options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js");
69959
69996
  const fileStatsSnapshot = options.cacheEnabled ? collectAnalyzedFileStats(rootDirectory) : null;
@@ -75564,7 +75601,7 @@ const computeConfigFingerprint = (projectDirectory, version) => {
75564
75601
  /** Display name used in client-facing messages and progress titles. */
75565
75602
  const SERVER_DISPLAY_NAME = "React Doctor";
75566
75603
  /** Server version reported in `serverInfo`; injected at build, `dev` from source. */
75567
- const SERVER_VERSION = "0.9.4";
75604
+ const SERVER_VERSION = "0.9.5";
75568
75605
  /** `Diagnostic.source` shown next to every published diagnostic. */
75569
75606
  const DIAGNOSTIC_SOURCE = "react-doctor";
75570
75607
  /**
@@ -77298,7 +77335,7 @@ const METRIC = {
77298
77335
  tuiFindingNavigated: "tui.finding_navigated",
77299
77336
  tuiIssueStreamShown: "tui.issue_stream_shown",
77300
77337
  tuiProjectPathContextShown: "tui.project_path_context_shown",
77301
- tuiProjectSelectInlineShown: "tui.project_select_inline_shown",
77338
+ tuiProjectSelectShown: "tui.project_select_shown",
77302
77339
  tuiReportActionSelected: "tui.report_action_selected",
77303
77340
  tuiCancelled: "tui.cancelled",
77304
77341
  tuiScanInlineShown: "tui.scan_inline_shown",
@@ -77606,5 +77643,5 @@ const startLanguageServer = () => {
77606
77643
  };
77607
77644
  //#endregion
77608
77645
  export { startLanguageServer };
77609
- !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]="8e8ec622-f2dc-5f52-bfe8-232b07051a7f")}catch(e){}}();
77610
- //# debugId=8e8ec622-f2dc-5f52-bfe8-232b07051a7f
77646
+ !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]="57ccd601-03eb-51e3-a852-2e296333f7ea")}catch(e){}}();
77647
+ //# debugId=57ccd601-03eb-51e3-a852-2e296333f7ea