react-doctor 0.7.9-dev.1a30f2c → 0.7.9-dev.21043e0

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]="23161367-202b-57f9-9fc4-293d3fc10d75")}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]="6f05eada-46fe-5b24-92d8-15fa92a38b00")}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";
@@ -36252,6 +36252,53 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
36252
36252
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
36253
36253
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
36254
36254
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
36255
+ const lastSourceMappingUrl = (fileContent) => {
36256
+ const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
36257
+ return lastReference ? lastReference[1] : null;
36258
+ };
36259
+ const mapTargetsSource = (mapContent, input) => {
36260
+ const parsedMap = JSON.parse(mapContent);
36261
+ if (typeof parsedMap !== "object" || parsedMap === null) return false;
36262
+ const { file, sources } = parsedMap;
36263
+ if (file !== input.expectedFile) return false;
36264
+ if (!Array.isArray(sources) || sources.length !== 1 || typeof sources[0] !== "string") return false;
36265
+ return Path.posix.normalize(Path.posix.join(input.mapDirectory, sources[0])) === input.sourcePath;
36266
+ };
36267
+ const quartetProvesEmit = (stem, sourcePath, readFileText) => {
36268
+ try {
36269
+ const emitBaseName = Path.posix.basename(stem);
36270
+ const mapDirectory = Path.posix.dirname(stem);
36271
+ return lastSourceMappingUrl(readFileText(`${stem}.js`)) === `${emitBaseName}.js.map` && lastSourceMappingUrl(readFileText(`${stem}.d.ts`)) === `${emitBaseName}.d.ts.map` && mapTargetsSource(readFileText(`${stem}.js.map`), {
36272
+ expectedFile: `${emitBaseName}.js`,
36273
+ mapDirectory,
36274
+ sourcePath
36275
+ }) && mapTargetsSource(readFileText(`${stem}.d.ts.map`), {
36276
+ expectedFile: `${emitBaseName}.d.ts`,
36277
+ mapDirectory,
36278
+ sourcePath
36279
+ });
36280
+ } catch {
36281
+ return false;
36282
+ }
36283
+ };
36284
+ const collectTypeScriptEmitDuplicateJsPaths = (input) => {
36285
+ const untracked = new Set(input.untrackedPaths);
36286
+ const duplicateJsPaths = /* @__PURE__ */ new Set();
36287
+ for (const jsPath of untracked) {
36288
+ if (!jsPath.endsWith(".js")) continue;
36289
+ const stem = jsPath.slice(0, -3);
36290
+ if (![
36291
+ jsPath,
36292
+ `${stem}.js.map`,
36293
+ `${stem}.d.ts`,
36294
+ `${stem}.d.ts.map`
36295
+ ].every((emitPath) => untracked.has(emitPath) && !input.trackedPaths.has(emitPath))) continue;
36296
+ const sourcePath = [`${stem}.ts`, `${stem}.tsx`].find((candidatePath) => input.trackedPaths.has(candidatePath));
36297
+ if (!sourcePath) continue;
36298
+ if (quartetProvesEmit(stem, sourcePath, input.readFileText)) duplicateJsPaths.add(jsPath);
36299
+ }
36300
+ return duplicateJsPaths;
36301
+ };
36255
36302
  const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
36256
36303
  const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
36257
36304
  const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
@@ -36319,20 +36366,29 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
36319
36366
  }
36320
36367
  return entries;
36321
36368
  };
36322
- const listSourceFilesViaGit = (rootDirectory) => {
36369
+ const gitLsFiles = (rootDirectory, flags) => {
36323
36370
  const result = spawnSync("git", [
36324
36371
  "ls-files",
36325
36372
  "-z",
36326
- "--cached",
36327
- "--others",
36328
- "--exclude-standard"
36373
+ ...flags
36329
36374
  ], {
36330
36375
  cwd: rootDirectory,
36331
36376
  encoding: "utf-8",
36332
36377
  maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
36333
36378
  });
36334
36379
  if (result.error || result.status !== 0) return null;
36335
- return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
36380
+ return result.stdout.split("\0").filter((filePath) => filePath.length > 0);
36381
+ };
36382
+ const listSourceFilesViaGit = (rootDirectory) => {
36383
+ const trackedPaths = gitLsFiles(rootDirectory, ["--cached"]);
36384
+ const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
36385
+ if (trackedPaths === null || untrackedPaths === null) return null;
36386
+ const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
36387
+ trackedPaths: new Set(trackedPaths),
36388
+ untrackedPaths,
36389
+ readFileText: (relativePath) => NFS.readFileSync(Path.resolve(rootDirectory, relativePath), "utf-8")
36390
+ });
36391
+ return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
36336
36392
  };
36337
36393
  const listSourceFilesViaFilesystem = (rootDirectory) => {
36338
36394
  const filePaths = [];
@@ -45276,6 +45332,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
45276
45332
  });
45277
45333
  }));
45278
45334
  };
45335
+ const HOME_DIRECTORY = os.homedir();
45336
+ const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
45337
+ const scrubSensitivePaths = (text) => {
45338
+ let scrubbed = text;
45339
+ if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
45340
+ for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
45341
+ return scrubbed;
45342
+ };
45279
45343
  const ScoreApiResponseSchema = Struct({
45280
45344
  score: Number$1,
45281
45345
  label: String$1,
@@ -45290,7 +45354,10 @@ const ScoreApiResponseSchema = Struct({
45290
45354
  })))
45291
45355
  });
45292
45356
  const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
45293
- const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => rest);
45357
+ const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
45358
+ ...rest,
45359
+ filePath: redactSensitiveText(scrubSensitivePaths(filePath))
45360
+ }));
45294
45361
  const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
45295
45362
  const describeFailure = (error) => {
45296
45363
  if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
@@ -45303,7 +45370,7 @@ const calculateScore = async (diagnostics, options = {}) => {
45303
45370
  const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
45304
45371
  try {
45305
45372
  const compressedBody = gzipSync(JSON.stringify({
45306
- diagnostics: stripLocalFileFields(diagnostics),
45373
+ diagnostics: sanitizeScoreDiagnostics(diagnostics),
45307
45374
  ...options.metadata?.repo ? { repo: options.metadata.repo } : {},
45308
45375
  ...options.metadata?.sha ? { sha: options.metadata.sha } : {},
45309
45376
  ...options.metadata?.framework ? { framework: options.metadata.framework } : {},
@@ -47148,7 +47215,7 @@ const makeNoopConsole = () => ({
47148
47215
  });
47149
47216
  //#endregion
47150
47217
  //#region src/cli/utils/version.ts
47151
- const VERSION = "0.7.9-dev.1a30f2c";
47218
+ const VERSION = "0.7.9-dev.21043e0";
47152
47219
  //#endregion
47153
47220
  //#region src/cli/utils/json-mode.ts
47154
47221
  let context = null;
@@ -47234,23 +47301,6 @@ const getRunId = () => {
47234
47301
  return cachedRunId;
47235
47302
  };
47236
47303
  //#endregion
47237
- //#region src/cli/utils/scrub-sensitive-text.ts
47238
- const HOME_DIRECTORY = os.homedir();
47239
- const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
47240
- /**
47241
- * Replaces the user's home directory (and generic `/Users|/home|C:\Users\<name>`
47242
- * roots) with `~` so absolute paths can't be tied back to an individual. Keeps
47243
- * the path's relative structure intact, which stays useful for debugging while
47244
- * dropping the personally-identifying prefix. Idempotent — re-running on an
47245
- * already-scrubbed `~/...` path is a no-op.
47246
- */
47247
- const scrubSensitivePaths = (text) => {
47248
- let scrubbed = text;
47249
- if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
47250
- for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
47251
- return scrubbed;
47252
- };
47253
- //#endregion
47254
47304
  //#region src/cli/utils/build-run-context.ts
47255
47305
  const ROOT_SUBCOMMANDS = new Set(["install", "setup"]);
47256
47306
  const detectInvokedVia = () => {
@@ -47517,13 +47567,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
47517
47567
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
47518
47568
  * standard `SENTRY_RELEASE` override.
47519
47569
  */
47520
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.9-dev.1a30f2c`;
47570
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.9-dev.21043e0`;
47521
47571
  /**
47522
47572
  * Deployment environment shown in Sentry's environment filter. Defaults to
47523
47573
  * `production` for tagged releases and `development` for dev/unbuilt versions,
47524
47574
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
47525
47575
  */
47526
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.9-dev.1a30f2c") ? "development" : "production");
47576
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.9-dev.21043e0") ? "development" : "production");
47527
47577
  /**
47528
47578
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
47529
47579
  * (set to `0` to disable tracing) and falls back to
@@ -65801,4 +65851,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
65801
65851
  export {};
65802
65852
 
65803
65853
  //# sourceMappingURL=cli.js.map
65804
- //# debugId=23161367-202b-57f9-9fc4-293d3fc10d75
65854
+ //# debugId=6f05eada-46fe-5b24-92d8-15fa92a38b00
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]="bc3f4cb3-9cb9-5b3f-a968-1596305e5a01")}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]="28287c1c-b7b6-53b8-9e72-7d28d4f3ca45")}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 reactDoctorPlugin, { 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, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
@@ -33050,6 +33050,53 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
33050
33050
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
33051
33051
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
33052
33052
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
33053
+ const lastSourceMappingUrl = (fileContent) => {
33054
+ const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
33055
+ return lastReference ? lastReference[1] : null;
33056
+ };
33057
+ const mapTargetsSource = (mapContent, input) => {
33058
+ const parsedMap = JSON.parse(mapContent);
33059
+ if (typeof parsedMap !== "object" || parsedMap === null) return false;
33060
+ const { file, sources } = parsedMap;
33061
+ if (file !== input.expectedFile) return false;
33062
+ if (!Array.isArray(sources) || sources.length !== 1 || typeof sources[0] !== "string") return false;
33063
+ return Path.posix.normalize(Path.posix.join(input.mapDirectory, sources[0])) === input.sourcePath;
33064
+ };
33065
+ const quartetProvesEmit = (stem, sourcePath, readFileText) => {
33066
+ try {
33067
+ const emitBaseName = Path.posix.basename(stem);
33068
+ const mapDirectory = Path.posix.dirname(stem);
33069
+ return lastSourceMappingUrl(readFileText(`${stem}.js`)) === `${emitBaseName}.js.map` && lastSourceMappingUrl(readFileText(`${stem}.d.ts`)) === `${emitBaseName}.d.ts.map` && mapTargetsSource(readFileText(`${stem}.js.map`), {
33070
+ expectedFile: `${emitBaseName}.js`,
33071
+ mapDirectory,
33072
+ sourcePath
33073
+ }) && mapTargetsSource(readFileText(`${stem}.d.ts.map`), {
33074
+ expectedFile: `${emitBaseName}.d.ts`,
33075
+ mapDirectory,
33076
+ sourcePath
33077
+ });
33078
+ } catch {
33079
+ return false;
33080
+ }
33081
+ };
33082
+ const collectTypeScriptEmitDuplicateJsPaths = (input) => {
33083
+ const untracked = new Set(input.untrackedPaths);
33084
+ const duplicateJsPaths = /* @__PURE__ */ new Set();
33085
+ for (const jsPath of untracked) {
33086
+ if (!jsPath.endsWith(".js")) continue;
33087
+ const stem = jsPath.slice(0, -3);
33088
+ if (![
33089
+ jsPath,
33090
+ `${stem}.js.map`,
33091
+ `${stem}.d.ts`,
33092
+ `${stem}.d.ts.map`
33093
+ ].every((emitPath) => untracked.has(emitPath) && !input.trackedPaths.has(emitPath))) continue;
33094
+ const sourcePath = [`${stem}.ts`, `${stem}.tsx`].find((candidatePath) => input.trackedPaths.has(candidatePath));
33095
+ if (!sourcePath) continue;
33096
+ if (quartetProvesEmit(stem, sourcePath, input.readFileText)) duplicateJsPaths.add(jsPath);
33097
+ }
33098
+ return duplicateJsPaths;
33099
+ };
33053
33100
  const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
33054
33101
  const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
33055
33102
  const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
@@ -33120,20 +33167,29 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
33120
33167
  }
33121
33168
  return entries;
33122
33169
  };
33123
- const listSourceFilesViaGit = (rootDirectory) => {
33170
+ const gitLsFiles = (rootDirectory, flags) => {
33124
33171
  const result = spawnSync("git", [
33125
33172
  "ls-files",
33126
33173
  "-z",
33127
- "--cached",
33128
- "--others",
33129
- "--exclude-standard"
33174
+ ...flags
33130
33175
  ], {
33131
33176
  cwd: rootDirectory,
33132
33177
  encoding: "utf-8",
33133
33178
  maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
33134
33179
  });
33135
33180
  if (result.error || result.status !== 0) return null;
33136
- return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
33181
+ return result.stdout.split("\0").filter((filePath) => filePath.length > 0);
33182
+ };
33183
+ const listSourceFilesViaGit = (rootDirectory) => {
33184
+ const trackedPaths = gitLsFiles(rootDirectory, ["--cached"]);
33185
+ const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
33186
+ if (trackedPaths === null || untrackedPaths === null) return null;
33187
+ const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
33188
+ trackedPaths: new Set(trackedPaths),
33189
+ untrackedPaths,
33190
+ readFileText: (relativePath) => NFS.readFileSync(Path.resolve(rootDirectory, relativePath), "utf-8")
33191
+ });
33192
+ return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
33137
33193
  };
33138
33194
  const listSourceFilesViaFilesystem = (rootDirectory) => {
33139
33195
  const filePaths = [];
@@ -42032,6 +42088,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
42032
42088
  });
42033
42089
  }));
42034
42090
  };
42091
+ const HOME_DIRECTORY = os.homedir();
42092
+ const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
42093
+ const scrubSensitivePaths = (text) => {
42094
+ let scrubbed = text;
42095
+ if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
42096
+ for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
42097
+ return scrubbed;
42098
+ };
42035
42099
  const ScoreApiResponseSchema = Struct({
42036
42100
  score: Number$1,
42037
42101
  label: String$1,
@@ -42046,7 +42110,10 @@ const ScoreApiResponseSchema = Struct({
42046
42110
  })))
42047
42111
  });
42048
42112
  const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
42049
- const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => rest);
42113
+ const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
42114
+ ...rest,
42115
+ filePath: redactSensitiveText(scrubSensitivePaths(filePath))
42116
+ }));
42050
42117
  const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
42051
42118
  const describeFailure = (error) => {
42052
42119
  if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
@@ -42059,7 +42126,7 @@ const calculateScore = async (diagnostics, options = {}) => {
42059
42126
  const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
42060
42127
  try {
42061
42128
  const compressedBody = gzipSync(JSON.stringify({
42062
- diagnostics: stripLocalFileFields(diagnostics),
42129
+ diagnostics: sanitizeScoreDiagnostics(diagnostics),
42063
42130
  ...options.metadata?.repo ? { repo: options.metadata.repo } : {},
42064
42131
  ...options.metadata?.sha ? { sha: options.metadata.sha } : {},
42065
42132
  ...options.metadata?.framework ? { framework: options.metadata.framework } : {},
@@ -43652,4 +43719,4 @@ const toJsonReport = (result, options) => buildJsonReport({
43652
43719
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
43653
43720
 
43654
43721
  //# sourceMappingURL=index.js.map
43655
- //# debugId=bc3f4cb3-9cb9-5b3f-a968-1596305e5a01
43722
+ //# debugId=28287c1c-b7b6-53b8-9e72-7d28d4f3ca45
package/dist/lsp.js CHANGED
@@ -33102,6 +33102,53 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
33102
33102
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
33103
33103
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
33104
33104
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
33105
+ const lastSourceMappingUrl = (fileContent) => {
33106
+ const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
33107
+ return lastReference ? lastReference[1] : null;
33108
+ };
33109
+ const mapTargetsSource = (mapContent, input) => {
33110
+ const parsedMap = JSON.parse(mapContent);
33111
+ if (typeof parsedMap !== "object" || parsedMap === null) return false;
33112
+ const { file, sources } = parsedMap;
33113
+ if (file !== input.expectedFile) return false;
33114
+ if (!Array.isArray(sources) || sources.length !== 1 || typeof sources[0] !== "string") return false;
33115
+ return Path.posix.normalize(Path.posix.join(input.mapDirectory, sources[0])) === input.sourcePath;
33116
+ };
33117
+ const quartetProvesEmit = (stem, sourcePath, readFileText) => {
33118
+ try {
33119
+ const emitBaseName = Path.posix.basename(stem);
33120
+ const mapDirectory = Path.posix.dirname(stem);
33121
+ return lastSourceMappingUrl(readFileText(`${stem}.js`)) === `${emitBaseName}.js.map` && lastSourceMappingUrl(readFileText(`${stem}.d.ts`)) === `${emitBaseName}.d.ts.map` && mapTargetsSource(readFileText(`${stem}.js.map`), {
33122
+ expectedFile: `${emitBaseName}.js`,
33123
+ mapDirectory,
33124
+ sourcePath
33125
+ }) && mapTargetsSource(readFileText(`${stem}.d.ts.map`), {
33126
+ expectedFile: `${emitBaseName}.d.ts`,
33127
+ mapDirectory,
33128
+ sourcePath
33129
+ });
33130
+ } catch {
33131
+ return false;
33132
+ }
33133
+ };
33134
+ const collectTypeScriptEmitDuplicateJsPaths = (input) => {
33135
+ const untracked = new Set(input.untrackedPaths);
33136
+ const duplicateJsPaths = /* @__PURE__ */ new Set();
33137
+ for (const jsPath of untracked) {
33138
+ if (!jsPath.endsWith(".js")) continue;
33139
+ const stem = jsPath.slice(0, -3);
33140
+ if (![
33141
+ jsPath,
33142
+ `${stem}.js.map`,
33143
+ `${stem}.d.ts`,
33144
+ `${stem}.d.ts.map`
33145
+ ].every((emitPath) => untracked.has(emitPath) && !input.trackedPaths.has(emitPath))) continue;
33146
+ const sourcePath = [`${stem}.ts`, `${stem}.tsx`].find((candidatePath) => input.trackedPaths.has(candidatePath));
33147
+ if (!sourcePath) continue;
33148
+ if (quartetProvesEmit(stem, sourcePath, input.readFileText)) duplicateJsPaths.add(jsPath);
33149
+ }
33150
+ return duplicateJsPaths;
33151
+ };
33105
33152
  const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
33106
33153
  const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
33107
33154
  const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
@@ -33172,20 +33219,29 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
33172
33219
  }
33173
33220
  return entries;
33174
33221
  };
33175
- const listSourceFilesViaGit = (rootDirectory) => {
33222
+ const gitLsFiles = (rootDirectory, flags) => {
33176
33223
  const result = spawnSync("git", [
33177
33224
  "ls-files",
33178
33225
  "-z",
33179
- "--cached",
33180
- "--others",
33181
- "--exclude-standard"
33226
+ ...flags
33182
33227
  ], {
33183
33228
  cwd: rootDirectory,
33184
33229
  encoding: "utf-8",
33185
33230
  maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
33186
33231
  });
33187
33232
  if (result.error || result.status !== 0) return null;
33188
- return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
33233
+ return result.stdout.split("\0").filter((filePath) => filePath.length > 0);
33234
+ };
33235
+ const listSourceFilesViaGit = (rootDirectory) => {
33236
+ const trackedPaths = gitLsFiles(rootDirectory, ["--cached"]);
33237
+ const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
33238
+ if (trackedPaths === null || untrackedPaths === null) return null;
33239
+ const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
33240
+ trackedPaths: new Set(trackedPaths),
33241
+ untrackedPaths,
33242
+ readFileText: (relativePath) => NFS.readFileSync(Path.resolve(rootDirectory, relativePath), "utf-8")
33243
+ });
33244
+ return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
33189
33245
  };
33190
33246
  const listSourceFilesViaFilesystem = (rootDirectory) => {
33191
33247
  const filePaths = [];
@@ -42010,6 +42066,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
42010
42066
  });
42011
42067
  }));
42012
42068
  };
42069
+ const HOME_DIRECTORY = os.homedir();
42070
+ const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
42071
+ const scrubSensitivePaths = (text) => {
42072
+ let scrubbed = text;
42073
+ if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
42074
+ for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
42075
+ return scrubbed;
42076
+ };
42013
42077
  const ScoreApiResponseSchema = Struct({
42014
42078
  score: Number$1,
42015
42079
  label: String$1,
@@ -42024,7 +42088,10 @@ const ScoreApiResponseSchema = Struct({
42024
42088
  })))
42025
42089
  });
42026
42090
  const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
42027
- const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => rest);
42091
+ const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
42092
+ ...rest,
42093
+ filePath: redactSensitiveText(scrubSensitivePaths(filePath))
42094
+ }));
42028
42095
  const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
42029
42096
  const describeFailure = (error) => {
42030
42097
  if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
@@ -42037,7 +42104,7 @@ const calculateScore = async (diagnostics, options = {}) => {
42037
42104
  const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
42038
42105
  try {
42039
42106
  const compressedBody = gzipSync(JSON.stringify({
42040
- diagnostics: stripLocalFileFields(diagnostics),
42107
+ diagnostics: sanitizeScoreDiagnostics(diagnostics),
42041
42108
  ...options.metadata?.repo ? { repo: options.metadata.repo } : {},
42042
42109
  ...options.metadata?.sha ? { sha: options.metadata.sha } : {},
42043
42110
  ...options.metadata?.framework ? { framework: options.metadata.framework } : {},
@@ -44984,23 +45051,6 @@ const METRIC = {
44984
45051
  */
44985
45052
  const toCategoryKey = (category) => category.toLowerCase().replace(/[^a-z0-9]+/g, "_");
44986
45053
  //#endregion
44987
- //#region src/cli/utils/scrub-sensitive-text.ts
44988
- const HOME_DIRECTORY = os.homedir();
44989
- const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
44990
- /**
44991
- * Replaces the user's home directory (and generic `/Users|/home|C:\Users\<name>`
44992
- * roots) with `~` so absolute paths can't be tied back to an individual. Keeps
44993
- * the path's relative structure intact, which stays useful for debugging while
44994
- * dropping the personally-identifying prefix. Idempotent — re-running on an
44995
- * already-scrubbed `~/...` path is a no-op.
44996
- */
44997
- const scrubSensitivePaths = (text) => {
44998
- let scrubbed = text;
44999
- if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
45000
- for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
45001
- return scrubbed;
45002
- };
45003
- //#endregion
45004
45054
  //#region src/cli/utils/anonymize-text.ts
45005
45055
  /**
45006
45056
  * Free-text fields can carry both a home-directory path (the OS username) and a
@@ -45289,5 +45339,5 @@ const startLanguageServer = () => {
45289
45339
  };
45290
45340
  //#endregion
45291
45341
  export { startLanguageServer };
45292
- !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]="3af67fb4-a992-5939-906b-39e662d71deb")}catch(e){}}();
45293
- //# debugId=3af67fb4-a992-5939-906b-39e662d71deb
45342
+ !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]="6c89dec9-5fbe-5a2e-b1fe-6b3954e0e85b")}catch(e){}}();
45343
+ //# debugId=6c89dec9-5fbe-5a2e-b1fe-6b3954e0e85b
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.7.9-dev.1a30f2c",
3
+ "version": "0.7.9-dev.21043e0",
4
4
  "description": "Your agent writes bad React. This catches it",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -66,7 +66,7 @@
66
66
  "vscode-uri": "^3.1.0",
67
67
  "yaml": "^2.9.0",
68
68
  "deslop-js": "0.7.9",
69
- "oxlint-plugin-react-doctor": "0.7.9-dev.1a30f2c"
69
+ "oxlint-plugin-react-doctor": "0.7.9-dev.21043e0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/babel__code-frame": "^7.27.0",
@@ -74,9 +74,9 @@
74
74
  "@xterm/headless": "^6.0.0",
75
75
  "commander": "^14.0.3",
76
76
  "ora": "^9.4.0",
77
- "@react-doctor/api": "0.7.9",
78
77
  "@react-doctor/core": "0.7.9",
79
- "@react-doctor/language-server": "0.7.9"
78
+ "@react-doctor/language-server": "0.7.9",
79
+ "@react-doctor/api": "0.7.9"
80
80
  },
81
81
  "engines": {
82
82
  "node": "^20.19.0 || >=22.13.0"