react-doctor 0.9.4-dev.212b8b4 → 0.9.4-dev.881ecfe

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]="7d7e0bde-eb19-58b5-b161-625bcb1b2588")}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]="e74e6a68-20e1-59fe-8db0-62b87e8fe049")}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";
@@ -74115,6 +74115,33 @@ const detectUserLintConfigPaths = (rootDirectory) => {
74115
74115
  return [];
74116
74116
  };
74117
74117
  const DISABLE_DIRECTIVE_PATTERN = /(eslint|oxlint)-disable/;
74118
+ const neutralizedFileLeases = /* @__PURE__ */ new Map();
74119
+ const activeNeutralizationInitializations = /* @__PURE__ */ new Set();
74120
+ const directoriesOverlap = (left, right) => {
74121
+ const isWithin = (parent, candidate) => {
74122
+ const relativePath = Path.relative(parent, candidate);
74123
+ return relativePath.length === 0 || !relativePath.startsWith(`..${Path.sep}`) && relativePath !== ".." && !Path.isAbsolute(relativePath);
74124
+ };
74125
+ return isWithin(left, right) || isWithin(right, left);
74126
+ };
74127
+ const withOverlappingInitializationLock = async (rootDirectory, operation) => {
74128
+ const blockers = [...activeNeutralizationInitializations].filter((initialization) => directoriesOverlap(initialization.rootDirectory, rootDirectory)).map((initialization) => initialization.done);
74129
+ let release;
74130
+ const initialization = {
74131
+ rootDirectory,
74132
+ done: new Promise((resolve) => {
74133
+ release = resolve;
74134
+ })
74135
+ };
74136
+ activeNeutralizationInitializations.add(initialization);
74137
+ await Promise.all(blockers);
74138
+ try {
74139
+ return await operation();
74140
+ } finally {
74141
+ activeNeutralizationInitializations.delete(initialization);
74142
+ release();
74143
+ }
74144
+ };
74118
74145
  const findFilesWithDisableDirectivesViaGit = async (rootDirectory, includePaths) => {
74119
74146
  const program = gen(function* () {
74120
74147
  return yield* (yield* Git).grep({
@@ -74157,34 +74184,84 @@ const findFilesWithDisableDirectivesViaFilesystem = (rootDirectory, includePaths
74157
74184
  };
74158
74185
  const findFilesWithDisableDirectives = async (rootDirectory, includePaths) => await findFilesWithDisableDirectivesViaGit(rootDirectory, includePaths) ?? findFilesWithDisableDirectivesViaFilesystem(rootDirectory, includePaths);
74159
74186
  const neutralizeContent = (content) => content.replaceAll("eslint-disable", "eslint_disable").replaceAll("oxlint-disable", "oxlint_disable");
74160
- const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
74161
- const filePaths = await findFilesWithDisableDirectives(rootDirectory, includePaths);
74162
- const originalContents = /* @__PURE__ */ new Map();
74187
+ const collectNeutralizationCandidatePaths = (rootDirectory, discoveredRelativePaths, includePaths) => {
74188
+ const resolvedRootDirectory = NFS.realpathSync(rootDirectory);
74189
+ const requestedPaths = includePaths && includePaths.length > 0 ? new Set(includePaths.flatMap((includePath) => {
74190
+ try {
74191
+ return [NFS.realpathSync(Path.resolve(resolvedRootDirectory, includePath))];
74192
+ } catch {
74193
+ return [];
74194
+ }
74195
+ })) : null;
74196
+ const candidatePaths = /* @__PURE__ */ new Set();
74197
+ for (const relativePath of discoveredRelativePaths) try {
74198
+ candidatePaths.add(NFS.realpathSync(Path.resolve(resolvedRootDirectory, relativePath)));
74199
+ } catch {
74200
+ continue;
74201
+ }
74202
+ for (const leasedPath of neutralizedFileLeases.keys()) {
74203
+ const relativePath = Path.relative(resolvedRootDirectory, leasedPath);
74204
+ if (!(relativePath.length === 0 || !relativePath.startsWith(`..${Path.sep}`) && relativePath !== ".." && !Path.isAbsolute(relativePath)) || requestedPaths && !requestedPaths.has(leasedPath)) continue;
74205
+ candidatePaths.add(leasedPath);
74206
+ }
74207
+ return candidatePaths;
74208
+ };
74209
+ const neutralizeDisableDirectives = async (rootDirectory, includePaths, options = {}) => {
74210
+ const resolvedRootDirectory = NFS.realpathSync(rootDirectory);
74211
+ const leasedPaths = /* @__PURE__ */ new Set();
74163
74212
  let isRestored = false;
74164
74213
  const restore = () => {
74165
74214
  if (isRestored) return;
74166
74215
  isRestored = true;
74167
- for (const [absolutePath, originalContent] of originalContents) try {
74168
- NFS.writeFileSync(absolutePath, originalContent);
74169
- } catch (error) {
74170
- process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${messageFromUnknown(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
74216
+ for (const absolutePath of leasedPaths) {
74217
+ const lease = neutralizedFileLeases.get(absolutePath);
74218
+ if (!lease) continue;
74219
+ lease.referenceCount -= 1;
74220
+ if (lease.referenceCount > 0) continue;
74221
+ neutralizedFileLeases.delete(absolutePath);
74222
+ try {
74223
+ NFS.writeFileSync(absolutePath, lease.originalContent);
74224
+ } catch (error) {
74225
+ process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${messageFromUnknown(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
74226
+ }
74171
74227
  }
74172
74228
  };
74173
74229
  const onExit = () => restore();
74174
74230
  process.once("exit", onExit);
74175
- for (const relativePath of filePaths) {
74176
- const absolutePath = Path.join(rootDirectory, relativePath);
74231
+ const leaseCandidatePath = (absolutePath) => {
74232
+ if (leasedPaths.has(absolutePath)) return;
74233
+ const existingLease = neutralizedFileLeases.get(absolutePath);
74234
+ if (existingLease) {
74235
+ existingLease.referenceCount += 1;
74236
+ leasedPaths.add(absolutePath);
74237
+ return;
74238
+ }
74177
74239
  let originalContent;
74178
74240
  try {
74179
74241
  originalContent = NFS.readFileSync(absolutePath, "utf-8");
74180
74242
  } catch {
74181
- continue;
74243
+ return;
74182
74244
  }
74183
74245
  const neutralizedContent = neutralizeContent(originalContent);
74184
74246
  if (neutralizedContent !== originalContent) {
74185
- originalContents.set(absolutePath, originalContent);
74186
74247
  NFS.writeFileSync(absolutePath, neutralizedContent);
74248
+ neutralizedFileLeases.set(absolutePath, {
74249
+ originalContent,
74250
+ referenceCount: 1
74251
+ });
74252
+ leasedPaths.add(absolutePath);
74187
74253
  }
74254
+ };
74255
+ try {
74256
+ await withOverlappingInitializationLock(resolvedRootDirectory, async () => {
74257
+ for (const absolutePath of collectNeutralizationCandidatePaths(resolvedRootDirectory, [], includePaths)) if (neutralizedFileLeases.has(absolutePath)) leaseCandidatePath(absolutePath);
74258
+ const discoveredRelativePaths = await (options.findFiles ?? findFilesWithDisableDirectives)(resolvedRootDirectory, includePaths);
74259
+ for (const absolutePath of collectNeutralizationCandidatePaths(resolvedRootDirectory, discoveredRelativePaths, includePaths)) leaseCandidatePath(absolutePath);
74260
+ });
74261
+ } catch (error) {
74262
+ restore();
74263
+ process.removeListener("exit", onExit);
74264
+ throw error;
74188
74265
  }
74189
74266
  return () => {
74190
74267
  restore();
@@ -79419,7 +79496,7 @@ const makeNoopConsole = () => ({
79419
79496
  });
79420
79497
  //#endregion
79421
79498
  //#region src/cli/utils/version.ts
79422
- const VERSION = "0.9.4-dev.212b8b4";
79499
+ const VERSION = "0.9.4-dev.881ecfe";
79423
79500
  //#endregion
79424
79501
  //#region src/cli/utils/json-mode.ts
79425
79502
  let context = null;
@@ -79880,13 +79957,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
79880
79957
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
79881
79958
  * standard `SENTRY_RELEASE` override.
79882
79959
  */
79883
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.4-dev.212b8b4`;
79960
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.4-dev.881ecfe`;
79884
79961
  /**
79885
79962
  * Deployment environment shown in Sentry's environment filter. Defaults to
79886
79963
  * `production` for tagged releases and `development` for dev/unbuilt versions,
79887
79964
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
79888
79965
  */
79889
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.4-dev.212b8b4") ? "development" : "production");
79966
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.4-dev.881ecfe") ? "development" : "production");
79890
79967
  /**
79891
79968
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
79892
79969
  * (set to `0` to disable tracing) and falls back to
@@ -99082,4 +99159,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
99082
99159
  export { TUI_REPORT_DETAIL_WIDTH_FRACTION as $, shouldRecordOnboarding as A, buildSortedRuleGroups as B, createInvocationInspect as C, markOnboardingComplete as D, doctorFace as E, buildEmptyReportMessage as F, recordCount as G, formatLearnMoreLine as H, hasIncompleteScoreAnalysis as I, findNearestPackageDirectory as J, recordDistribution as K, buildNoScoreMessage as L, computeProjectedScore as M, formatElapsedTime as N, canAnimateOnboarding as O, buildCodeFrame as P, TUI_REPORT_COMPACT_MAX_ROWS as Q, hasLintHardFailure as R, deduplicateProjectScans as S, easeOutCubic as T, resolveBlockingLevel as U, formatFixRecipeLine as V, isReactDoctorWorkflowInstalled as W, CI_TRUST_COMPANIES as X, isUnicodeSupported as Y, METRIC as Z, launchCliAgent as _, succeed$3 as _t, selectProjects as a, buildRuleDocsUrl as at, formatSkippedProjectsMessage as b, resolveWorkspaceDeadCodeOwner as c, highlighter as ct, countUniqueScannedFiles as d, remainingDeadlineBudgetMs as dt, isCiEnvironment as et, setUpGitHubActions as f, resolveScanTarget as ft, copyToClipboard as g, void_ as gt, CLI_AGENT_BINARIES as h, sync as ht, discoverWorkspacePackages as i, Reporter as it, filterDiagnosticsByCategories as j, isOnboardingForced as k, resolveCliInspectOptions as l, isPathInsideDirectory as lt, detectLaunchableAgents as m, runPromise as mt, registerActiveTuiRenderer as n, GITHUB_ACTIONS_SETUP_URL as nt, resolveProjectScan as o, getCategoryImpact as ot, openUrl as p, yieldToEventLoop as pt, toForwardSlashes as q, shouldFailScanGate as r, Progress as rt, retryMissingProjectScores as s, hasPublishedFixRecipe as st, exitGracefully as t, DIAGNOSTIC_CATEGORY_BUCKETS as tt, filterScansForSurface as u, mapWithConcurrency as ut, buildHandoffPayload as v, printFooter as w, collectProjectSourceFileCounts as x, isShareOptedOut as y, buildRulePriorityMap as z };
99083
99160
 
99084
99161
  //# sourceMappingURL=cli.js.map
99085
- //# debugId=7d7e0bde-eb19-58b5-b161-625bcb1b2588
99162
+ //# debugId=e74e6a68-20e1-59fe-8db0-62b87e8fe049
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]="8d6e3c06-44f8-589f-8e07-aaa4704b6112")}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]="6d2e43de-ae97-5213-b1a7-a9905ce4b1d5")}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";
@@ -70874,6 +70874,33 @@ const detectUserLintConfigPaths = (rootDirectory) => {
70874
70874
  return [];
70875
70875
  };
70876
70876
  const DISABLE_DIRECTIVE_PATTERN = /(eslint|oxlint)-disable/;
70877
+ const neutralizedFileLeases = /* @__PURE__ */ new Map();
70878
+ const activeNeutralizationInitializations = /* @__PURE__ */ new Set();
70879
+ const directoriesOverlap = (left, right) => {
70880
+ const isWithin = (parent, candidate) => {
70881
+ const relativePath = Path.relative(parent, candidate);
70882
+ return relativePath.length === 0 || !relativePath.startsWith(`..${Path.sep}`) && relativePath !== ".." && !Path.isAbsolute(relativePath);
70883
+ };
70884
+ return isWithin(left, right) || isWithin(right, left);
70885
+ };
70886
+ const withOverlappingInitializationLock = async (rootDirectory, operation) => {
70887
+ const blockers = [...activeNeutralizationInitializations].filter((initialization) => directoriesOverlap(initialization.rootDirectory, rootDirectory)).map((initialization) => initialization.done);
70888
+ let release;
70889
+ const initialization = {
70890
+ rootDirectory,
70891
+ done: new Promise((resolve) => {
70892
+ release = resolve;
70893
+ })
70894
+ };
70895
+ activeNeutralizationInitializations.add(initialization);
70896
+ await Promise.all(blockers);
70897
+ try {
70898
+ return await operation();
70899
+ } finally {
70900
+ activeNeutralizationInitializations.delete(initialization);
70901
+ release();
70902
+ }
70903
+ };
70877
70904
  const findFilesWithDisableDirectivesViaGit = async (rootDirectory, includePaths) => {
70878
70905
  const program = gen(function* () {
70879
70906
  return yield* (yield* Git).grep({
@@ -70916,34 +70943,84 @@ const findFilesWithDisableDirectivesViaFilesystem = (rootDirectory, includePaths
70916
70943
  };
70917
70944
  const findFilesWithDisableDirectives = async (rootDirectory, includePaths) => await findFilesWithDisableDirectivesViaGit(rootDirectory, includePaths) ?? findFilesWithDisableDirectivesViaFilesystem(rootDirectory, includePaths);
70918
70945
  const neutralizeContent = (content) => content.replaceAll("eslint-disable", "eslint_disable").replaceAll("oxlint-disable", "oxlint_disable");
70919
- const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
70920
- const filePaths = await findFilesWithDisableDirectives(rootDirectory, includePaths);
70921
- const originalContents = /* @__PURE__ */ new Map();
70946
+ const collectNeutralizationCandidatePaths = (rootDirectory, discoveredRelativePaths, includePaths) => {
70947
+ const resolvedRootDirectory = NFS.realpathSync(rootDirectory);
70948
+ const requestedPaths = includePaths && includePaths.length > 0 ? new Set(includePaths.flatMap((includePath) => {
70949
+ try {
70950
+ return [NFS.realpathSync(Path.resolve(resolvedRootDirectory, includePath))];
70951
+ } catch {
70952
+ return [];
70953
+ }
70954
+ })) : null;
70955
+ const candidatePaths = /* @__PURE__ */ new Set();
70956
+ for (const relativePath of discoveredRelativePaths) try {
70957
+ candidatePaths.add(NFS.realpathSync(Path.resolve(resolvedRootDirectory, relativePath)));
70958
+ } catch {
70959
+ continue;
70960
+ }
70961
+ for (const leasedPath of neutralizedFileLeases.keys()) {
70962
+ const relativePath = Path.relative(resolvedRootDirectory, leasedPath);
70963
+ if (!(relativePath.length === 0 || !relativePath.startsWith(`..${Path.sep}`) && relativePath !== ".." && !Path.isAbsolute(relativePath)) || requestedPaths && !requestedPaths.has(leasedPath)) continue;
70964
+ candidatePaths.add(leasedPath);
70965
+ }
70966
+ return candidatePaths;
70967
+ };
70968
+ const neutralizeDisableDirectives = async (rootDirectory, includePaths, options = {}) => {
70969
+ const resolvedRootDirectory = NFS.realpathSync(rootDirectory);
70970
+ const leasedPaths = /* @__PURE__ */ new Set();
70922
70971
  let isRestored = false;
70923
70972
  const restore = () => {
70924
70973
  if (isRestored) return;
70925
70974
  isRestored = true;
70926
- for (const [absolutePath, originalContent] of originalContents) try {
70927
- NFS.writeFileSync(absolutePath, originalContent);
70928
- } catch (error) {
70929
- process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${messageFromUnknown(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
70975
+ for (const absolutePath of leasedPaths) {
70976
+ const lease = neutralizedFileLeases.get(absolutePath);
70977
+ if (!lease) continue;
70978
+ lease.referenceCount -= 1;
70979
+ if (lease.referenceCount > 0) continue;
70980
+ neutralizedFileLeases.delete(absolutePath);
70981
+ try {
70982
+ NFS.writeFileSync(absolutePath, lease.originalContent);
70983
+ } catch (error) {
70984
+ process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${messageFromUnknown(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
70985
+ }
70930
70986
  }
70931
70987
  };
70932
70988
  const onExit = () => restore();
70933
70989
  process.once("exit", onExit);
70934
- for (const relativePath of filePaths) {
70935
- const absolutePath = Path.join(rootDirectory, relativePath);
70990
+ const leaseCandidatePath = (absolutePath) => {
70991
+ if (leasedPaths.has(absolutePath)) return;
70992
+ const existingLease = neutralizedFileLeases.get(absolutePath);
70993
+ if (existingLease) {
70994
+ existingLease.referenceCount += 1;
70995
+ leasedPaths.add(absolutePath);
70996
+ return;
70997
+ }
70936
70998
  let originalContent;
70937
70999
  try {
70938
71000
  originalContent = NFS.readFileSync(absolutePath, "utf-8");
70939
71001
  } catch {
70940
- continue;
71002
+ return;
70941
71003
  }
70942
71004
  const neutralizedContent = neutralizeContent(originalContent);
70943
71005
  if (neutralizedContent !== originalContent) {
70944
- originalContents.set(absolutePath, originalContent);
70945
71006
  NFS.writeFileSync(absolutePath, neutralizedContent);
71007
+ neutralizedFileLeases.set(absolutePath, {
71008
+ originalContent,
71009
+ referenceCount: 1
71010
+ });
71011
+ leasedPaths.add(absolutePath);
70946
71012
  }
71013
+ };
71014
+ try {
71015
+ await withOverlappingInitializationLock(resolvedRootDirectory, async () => {
71016
+ for (const absolutePath of collectNeutralizationCandidatePaths(resolvedRootDirectory, [], includePaths)) if (neutralizedFileLeases.has(absolutePath)) leaseCandidatePath(absolutePath);
71017
+ const discoveredRelativePaths = await (options.findFiles ?? findFilesWithDisableDirectives)(resolvedRootDirectory, includePaths);
71018
+ for (const absolutePath of collectNeutralizationCandidatePaths(resolvedRootDirectory, discoveredRelativePaths, includePaths)) leaseCandidatePath(absolutePath);
71019
+ });
71020
+ } catch (error) {
71021
+ restore();
71022
+ process.removeListener("exit", onExit);
71023
+ throw error;
70947
71024
  }
70948
71025
  return () => {
70949
71026
  restore();
@@ -75837,4 +75914,4 @@ const toJsonReport = (result, options) => buildJsonReport({
75837
75914
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
75838
75915
 
75839
75916
  //# sourceMappingURL=index.js.map
75840
- //# debugId=8d6e3c06-44f8-589f-8e07-aaa4704b6112
75917
+ //# debugId=6d2e43de-ae97-5213-b1a7-a9905ce4b1d5
package/dist/lsp.js CHANGED
@@ -70903,6 +70903,33 @@ const detectUserLintConfigPaths = (rootDirectory) => {
70903
70903
  return [];
70904
70904
  };
70905
70905
  const DISABLE_DIRECTIVE_PATTERN = /(eslint|oxlint)-disable/;
70906
+ const neutralizedFileLeases = /* @__PURE__ */ new Map();
70907
+ const activeNeutralizationInitializations = /* @__PURE__ */ new Set();
70908
+ const directoriesOverlap = (left, right) => {
70909
+ const isWithin = (parent, candidate) => {
70910
+ const relativePath = Path.relative(parent, candidate);
70911
+ return relativePath.length === 0 || !relativePath.startsWith(`..${Path.sep}`) && relativePath !== ".." && !Path.isAbsolute(relativePath);
70912
+ };
70913
+ return isWithin(left, right) || isWithin(right, left);
70914
+ };
70915
+ const withOverlappingInitializationLock = async (rootDirectory, operation) => {
70916
+ const blockers = [...activeNeutralizationInitializations].filter((initialization) => directoriesOverlap(initialization.rootDirectory, rootDirectory)).map((initialization) => initialization.done);
70917
+ let release;
70918
+ const initialization = {
70919
+ rootDirectory,
70920
+ done: new Promise((resolve) => {
70921
+ release = resolve;
70922
+ })
70923
+ };
70924
+ activeNeutralizationInitializations.add(initialization);
70925
+ await Promise.all(blockers);
70926
+ try {
70927
+ return await operation();
70928
+ } finally {
70929
+ activeNeutralizationInitializations.delete(initialization);
70930
+ release();
70931
+ }
70932
+ };
70906
70933
  const findFilesWithDisableDirectivesViaGit = async (rootDirectory, includePaths) => {
70907
70934
  const program = gen(function* () {
70908
70935
  return yield* (yield* Git).grep({
@@ -70945,34 +70972,84 @@ const findFilesWithDisableDirectivesViaFilesystem = (rootDirectory, includePaths
70945
70972
  };
70946
70973
  const findFilesWithDisableDirectives = async (rootDirectory, includePaths) => await findFilesWithDisableDirectivesViaGit(rootDirectory, includePaths) ?? findFilesWithDisableDirectivesViaFilesystem(rootDirectory, includePaths);
70947
70974
  const neutralizeContent = (content) => content.replaceAll("eslint-disable", "eslint_disable").replaceAll("oxlint-disable", "oxlint_disable");
70948
- const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
70949
- const filePaths = await findFilesWithDisableDirectives(rootDirectory, includePaths);
70950
- const originalContents = /* @__PURE__ */ new Map();
70975
+ const collectNeutralizationCandidatePaths = (rootDirectory, discoveredRelativePaths, includePaths) => {
70976
+ const resolvedRootDirectory = NFS.realpathSync(rootDirectory);
70977
+ const requestedPaths = includePaths && includePaths.length > 0 ? new Set(includePaths.flatMap((includePath) => {
70978
+ try {
70979
+ return [NFS.realpathSync(Path.resolve(resolvedRootDirectory, includePath))];
70980
+ } catch {
70981
+ return [];
70982
+ }
70983
+ })) : null;
70984
+ const candidatePaths = /* @__PURE__ */ new Set();
70985
+ for (const relativePath of discoveredRelativePaths) try {
70986
+ candidatePaths.add(NFS.realpathSync(Path.resolve(resolvedRootDirectory, relativePath)));
70987
+ } catch {
70988
+ continue;
70989
+ }
70990
+ for (const leasedPath of neutralizedFileLeases.keys()) {
70991
+ const relativePath = Path.relative(resolvedRootDirectory, leasedPath);
70992
+ if (!(relativePath.length === 0 || !relativePath.startsWith(`..${Path.sep}`) && relativePath !== ".." && !Path.isAbsolute(relativePath)) || requestedPaths && !requestedPaths.has(leasedPath)) continue;
70993
+ candidatePaths.add(leasedPath);
70994
+ }
70995
+ return candidatePaths;
70996
+ };
70997
+ const neutralizeDisableDirectives = async (rootDirectory, includePaths, options = {}) => {
70998
+ const resolvedRootDirectory = NFS.realpathSync(rootDirectory);
70999
+ const leasedPaths = /* @__PURE__ */ new Set();
70951
71000
  let isRestored = false;
70952
71001
  const restore = () => {
70953
71002
  if (isRestored) return;
70954
71003
  isRestored = true;
70955
- for (const [absolutePath, originalContent] of originalContents) try {
70956
- NFS.writeFileSync(absolutePath, originalContent);
70957
- } catch (error) {
70958
- process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${messageFromUnknown(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
71004
+ for (const absolutePath of leasedPaths) {
71005
+ const lease = neutralizedFileLeases.get(absolutePath);
71006
+ if (!lease) continue;
71007
+ lease.referenceCount -= 1;
71008
+ if (lease.referenceCount > 0) continue;
71009
+ neutralizedFileLeases.delete(absolutePath);
71010
+ try {
71011
+ NFS.writeFileSync(absolutePath, lease.originalContent);
71012
+ } catch (error) {
71013
+ process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${messageFromUnknown(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
71014
+ }
70959
71015
  }
70960
71016
  };
70961
71017
  const onExit = () => restore();
70962
71018
  process.once("exit", onExit);
70963
- for (const relativePath of filePaths) {
70964
- const absolutePath = Path.join(rootDirectory, relativePath);
71019
+ const leaseCandidatePath = (absolutePath) => {
71020
+ if (leasedPaths.has(absolutePath)) return;
71021
+ const existingLease = neutralizedFileLeases.get(absolutePath);
71022
+ if (existingLease) {
71023
+ existingLease.referenceCount += 1;
71024
+ leasedPaths.add(absolutePath);
71025
+ return;
71026
+ }
70965
71027
  let originalContent;
70966
71028
  try {
70967
71029
  originalContent = NFS.readFileSync(absolutePath, "utf-8");
70968
71030
  } catch {
70969
- continue;
71031
+ return;
70970
71032
  }
70971
71033
  const neutralizedContent = neutralizeContent(originalContent);
70972
71034
  if (neutralizedContent !== originalContent) {
70973
- originalContents.set(absolutePath, originalContent);
70974
71035
  NFS.writeFileSync(absolutePath, neutralizedContent);
71036
+ neutralizedFileLeases.set(absolutePath, {
71037
+ originalContent,
71038
+ referenceCount: 1
71039
+ });
71040
+ leasedPaths.add(absolutePath);
70975
71041
  }
71042
+ };
71043
+ try {
71044
+ await withOverlappingInitializationLock(resolvedRootDirectory, async () => {
71045
+ for (const absolutePath of collectNeutralizationCandidatePaths(resolvedRootDirectory, [], includePaths)) if (neutralizedFileLeases.has(absolutePath)) leaseCandidatePath(absolutePath);
71046
+ const discoveredRelativePaths = await (options.findFiles ?? findFilesWithDisableDirectives)(resolvedRootDirectory, includePaths);
71047
+ for (const absolutePath of collectNeutralizationCandidatePaths(resolvedRootDirectory, discoveredRelativePaths, includePaths)) leaseCandidatePath(absolutePath);
71048
+ });
71049
+ } catch (error) {
71050
+ restore();
71051
+ process.removeListener("exit", onExit);
71052
+ throw error;
70976
71053
  }
70977
71054
  return () => {
70978
71055
  restore();
@@ -77529,5 +77606,5 @@ const startLanguageServer = () => {
77529
77606
  };
77530
77607
  //#endregion
77531
77608
  export { startLanguageServer };
77532
- !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]="2d26cd21-f7f6-5e65-9c29-fabf32208583")}catch(e){}}();
77533
- //# debugId=2d26cd21-f7f6-5e65-9c29-fabf32208583
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.9.4-dev.212b8b4",
3
+ "version": "0.9.4-dev.881ecfe",
4
4
  "description": "Your agent writes bad React. This catches it",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -72,8 +72,8 @@
72
72
  "vscode-languageserver-textdocument": "^1.0.12",
73
73
  "vscode-uri": "^3.1.0",
74
74
  "yaml": "^2.9.0",
75
- "deslop-js": "0.9.4",
76
- "oxlint-plugin-react-doctor": "0.9.4-dev.212b8b4"
75
+ "oxlint-plugin-react-doctor": "0.9.4-dev.881ecfe",
76
+ "deslop-js": "0.9.4"
77
77
  },
78
78
  "devDependencies": {
79
79
  "@types/babel__code-frame": "^7.27.0",