react-doctor 0.5.8-dev.ea00b1b → 0.5.8-dev.f69f216
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/LICENSE +14 -1
- package/dist/cli.js +372 -107
- package/dist/index.d.ts +2 -2
- package/dist/index.js +194 -32
- package/dist/lsp.js +134 -33
- package/package.json +8 -7
package/dist/lsp.js
CHANGED
|
@@ -6021,7 +6021,7 @@ const composePassthrough = /* @__PURE__ */ dual(2, (left, right) => (input) => {
|
|
|
6021
6021
|
* @since 2.0.0
|
|
6022
6022
|
*/
|
|
6023
6023
|
const Scheduler = /* @__PURE__ */ Reference("effect/Scheduler", { defaultValue: () => new MixedScheduler() });
|
|
6024
|
-
const setImmediate = "setImmediate" in globalThis ? (f) => {
|
|
6024
|
+
const setImmediate$1 = "setImmediate" in globalThis ? (f) => {
|
|
6025
6025
|
const timer = globalThis.setImmediate(f);
|
|
6026
6026
|
return () => globalThis.clearImmediate(timer);
|
|
6027
6027
|
} : (f) => {
|
|
@@ -6065,7 +6065,7 @@ var PriorityBuckets = class {
|
|
|
6065
6065
|
var MixedScheduler = class {
|
|
6066
6066
|
executionMode;
|
|
6067
6067
|
setImmediate;
|
|
6068
|
-
constructor(executionMode = "async", setImmediateFn = setImmediate) {
|
|
6068
|
+
constructor(executionMode = "async", setImmediateFn = setImmediate$1) {
|
|
6069
6069
|
this.executionMode = executionMode;
|
|
6070
6070
|
this.setImmediate = setImmediateFn;
|
|
6071
6071
|
}
|
|
@@ -6090,7 +6090,7 @@ var MixedSchedulerDispatcher = class {
|
|
|
6090
6090
|
tasks = /* @__PURE__ */ new PriorityBuckets();
|
|
6091
6091
|
running = void 0;
|
|
6092
6092
|
setImmediate;
|
|
6093
|
-
constructor(setImmediateFn = setImmediate) {
|
|
6093
|
+
constructor(setImmediateFn = setImmediate$1) {
|
|
6094
6094
|
this.setImmediate = setImmediateFn;
|
|
6095
6095
|
}
|
|
6096
6096
|
/**
|
|
@@ -33811,6 +33811,7 @@ const DEAD_CODE_PHASE_TIMEOUT_MS = 15e4;
|
|
|
33811
33811
|
const LINT_PHASE_TIMEOUT_MS = 3e5;
|
|
33812
33812
|
const SCAN_TOTAL_DEADLINE_MS = 9e5;
|
|
33813
33813
|
const DEAD_CODE_WORKER_MAX_OLD_SPACE_MB = 8192;
|
|
33814
|
+
const DEAD_CODE_WORKER_MEM_BUDGET_BYTES = 2 * 1024 * 1024 * 1024;
|
|
33814
33815
|
const DEAD_CODE_TIMEOUT_CEILING_MS = 6e5;
|
|
33815
33816
|
const DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS = 3e4;
|
|
33816
33817
|
const DEAD_CODE_OVERLAP_PARSE_SHARE = .4;
|
|
@@ -35402,7 +35403,7 @@ const resolveScanConcurrency = (requested) => {
|
|
|
35402
35403
|
if (!Number.isFinite(requested) || requested < 1) return 1;
|
|
35403
35404
|
return Math.min(Math.floor(requested), 32);
|
|
35404
35405
|
};
|
|
35405
|
-
const readSystemFacts = () => ({
|
|
35406
|
+
const readSystemFacts$1 = () => ({
|
|
35406
35407
|
availableCores: os.availableParallelism(),
|
|
35407
35408
|
totalMemoryBytes: os.totalmem(),
|
|
35408
35409
|
cgroupMemoryLimitBytes: readCgroupMemoryLimitBytes()
|
|
@@ -35423,7 +35424,7 @@ const readSystemFacts = () => ({
|
|
|
35423
35424
|
* `facts` is injectable so tests exercise core-bound, memory-bound, cgroup-
|
|
35424
35425
|
* limited, and ceiling cases without mocking `os` or the filesystem.
|
|
35425
35426
|
*/
|
|
35426
|
-
const resolveAutoScanConcurrency = (facts = readSystemFacts()) => {
|
|
35427
|
+
const resolveAutoScanConcurrency = (facts = readSystemFacts$1()) => {
|
|
35427
35428
|
const availableMemoryBytes = Math.min(facts.totalMemoryBytes, facts.cgroupMemoryLimitBytes ?? Number.POSITIVE_INFINITY);
|
|
35428
35429
|
const memoryBoundedWorkers = Math.floor(availableMemoryBytes / PER_WORKER_MEM_BUDGET_BYTES);
|
|
35429
35430
|
return resolveScanConcurrency(Math.min(facts.availableCores, memoryBoundedWorkers));
|
|
@@ -36908,7 +36909,10 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledBy)
|
|
|
36908
36909
|
}
|
|
36909
36910
|
return true;
|
|
36910
36911
|
};
|
|
36911
|
-
const
|
|
36912
|
+
const yieldToEventLoop = () => new Promise((resolve) => {
|
|
36913
|
+
setImmediate(resolve);
|
|
36914
|
+
});
|
|
36915
|
+
const createSecurityScanSession = (rootDirectory, options) => {
|
|
36912
36916
|
const capabilities = options.project ? buildCapabilities(options.project) : /* @__PURE__ */ new Set();
|
|
36913
36917
|
const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
|
|
36914
36918
|
const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
|
|
@@ -36923,7 +36927,7 @@ const checkSecurityScan = (rootDirectory, options = {}) => {
|
|
|
36923
36927
|
committedFilesOnly: rule.committedFilesOnly === true
|
|
36924
36928
|
}];
|
|
36925
36929
|
});
|
|
36926
|
-
if (enabledScanRules.length === 0) return
|
|
36930
|
+
if (enabledScanRules.length === 0) return null;
|
|
36927
36931
|
const diagnostics = [];
|
|
36928
36932
|
const seen = /* @__PURE__ */ new Set();
|
|
36929
36933
|
const gitIgnoredCache = /* @__PURE__ */ new Map();
|
|
@@ -36935,15 +36939,34 @@ const checkSecurityScan = (rootDirectory, options = {}) => {
|
|
|
36935
36939
|
}
|
|
36936
36940
|
return status === true;
|
|
36937
36941
|
};
|
|
36938
|
-
|
|
36939
|
-
|
|
36940
|
-
|
|
36941
|
-
|
|
36942
|
-
|
|
36943
|
-
|
|
36944
|
-
|
|
36942
|
+
const scanFile = (file) => {
|
|
36943
|
+
for (const { entry, scan, committedFilesOnly } of enabledScanRules) for (const finding of scan(file)) {
|
|
36944
|
+
if (committedFilesOnly && isFileGitIgnored(file)) continue;
|
|
36945
|
+
const diagnostic = buildSecurityScanDiagnostic(finding, entry, file.relativePath);
|
|
36946
|
+
const key = `${diagnostic.rule}:${diagnostic.filePath}:${diagnostic.line}:${diagnostic.column}:${diagnostic.message}`;
|
|
36947
|
+
if (seen.has(key)) continue;
|
|
36948
|
+
seen.add(key);
|
|
36949
|
+
diagnostics.push(diagnostic);
|
|
36950
|
+
}
|
|
36951
|
+
};
|
|
36952
|
+
return {
|
|
36953
|
+
scanFile,
|
|
36954
|
+
diagnostics
|
|
36955
|
+
};
|
|
36956
|
+
};
|
|
36957
|
+
const checkSecurityScanCooperative = async (rootDirectory, options = {}) => {
|
|
36958
|
+
const session = createSecurityScanSession(rootDirectory, options);
|
|
36959
|
+
if (session === null) return [];
|
|
36960
|
+
let filesSinceYield = 0;
|
|
36961
|
+
for (const file of collectSecurityScanFiles(rootDirectory)) {
|
|
36962
|
+
session.scanFile(file);
|
|
36963
|
+
filesSinceYield += 1;
|
|
36964
|
+
if (filesSinceYield >= 16) {
|
|
36965
|
+
filesSinceYield = 0;
|
|
36966
|
+
await yieldToEventLoop();
|
|
36967
|
+
}
|
|
36945
36968
|
}
|
|
36946
|
-
return diagnostics;
|
|
36969
|
+
return session.diagnostics;
|
|
36947
36970
|
};
|
|
36948
36971
|
var import_picocolors = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
36949
36972
|
let p = process || {}, argv = p.argv || [], env = p.env || {};
|
|
@@ -37160,6 +37183,74 @@ const collectDeadCodeIgnorePatterns = (rootDirectory) => {
|
|
|
37160
37183
|
return [...seen].filter((pattern) => pattern.length > 0);
|
|
37161
37184
|
};
|
|
37162
37185
|
const collectDeadCodeEntryPatterns = (rootDirectory) => [...new Set(collectKnipPatterns(rootDirectory, "entry"))].filter((pattern) => pattern.length > 0);
|
|
37186
|
+
const readSystemFacts = () => ({
|
|
37187
|
+
availableCores: os.availableParallelism(),
|
|
37188
|
+
totalMemoryBytes: os.totalmem(),
|
|
37189
|
+
cgroupMemoryLimitBytes: readCgroupMemoryLimitBytes()
|
|
37190
|
+
});
|
|
37191
|
+
/**
|
|
37192
|
+
* How many real deslop dead-code child processes may run at once, across the
|
|
37193
|
+
* concurrent per-project `runInspect` fibers of one CLI run. The cap is the
|
|
37194
|
+
* smaller of the core count and the number of `DEAD_CODE_WORKER_MEM_BUDGET_BYTES`
|
|
37195
|
+
* workers that fit in available memory, floored at 1.
|
|
37196
|
+
*
|
|
37197
|
+
* On a roomy dev box / CI runner this resolves high enough that every
|
|
37198
|
+
* concurrently-scanned project still spawns its own worker (no serialization vs
|
|
37199
|
+
* the prior uncapped behavior); on a memory-constrained runner it collapses
|
|
37200
|
+
* toward 1, so the `withDeadCodeWorkerSlot` semaphore serializes the spawns
|
|
37201
|
+
* instead of oversubscribing memory with N simultaneous children — the global
|
|
37202
|
+
* cap the per-project spawn path lacked.
|
|
37203
|
+
*
|
|
37204
|
+
* Mirrors `resolveAutoScanConcurrency` (lint), but budgets memory per the
|
|
37205
|
+
* heavier dead-code worker. `facts` is injectable for tests.
|
|
37206
|
+
*/
|
|
37207
|
+
const resolveDeadCodeConcurrency = (facts = readSystemFacts()) => {
|
|
37208
|
+
const availableMemoryBytes = Math.min(facts.totalMemoryBytes, facts.cgroupMemoryLimitBytes ?? Number.POSITIVE_INFINITY);
|
|
37209
|
+
const memoryBoundedWorkers = Math.floor(availableMemoryBytes / DEAD_CODE_WORKER_MEM_BUDGET_BYTES);
|
|
37210
|
+
return Math.max(1, Math.min(facts.availableCores, memoryBoundedWorkers));
|
|
37211
|
+
};
|
|
37212
|
+
let availableSlots = -1;
|
|
37213
|
+
const waiters = [];
|
|
37214
|
+
const releaseSlot = () => {
|
|
37215
|
+
const nextWaiter = waiters.shift();
|
|
37216
|
+
if (nextWaiter !== void 0) nextWaiter();
|
|
37217
|
+
else availableSlots += 1;
|
|
37218
|
+
};
|
|
37219
|
+
/**
|
|
37220
|
+
* Runs `task` once a dead-code worker slot is free, releasing the slot when the
|
|
37221
|
+
* task settles (success or failure). With a high cap (roomy machine) every
|
|
37222
|
+
* caller proceeds immediately; with a low cap (constrained runner) callers
|
|
37223
|
+
* queue and run as slots free.
|
|
37224
|
+
*
|
|
37225
|
+
* `abortSignal` short-circuits the WAIT: if it's already aborted, or fires while
|
|
37226
|
+
* this caller is queued, the call rejects without acquiring a slot or running
|
|
37227
|
+
* `task` — so a cancelled scan (e.g. lint failed) doesn't sit in the queue and
|
|
37228
|
+
* then spawn a child only to tear it down. A queued caller that aborts removes
|
|
37229
|
+
* its own waiter so a later release never hands a slot to a dead request.
|
|
37230
|
+
*/
|
|
37231
|
+
const withDeadCodeWorkerSlot = async (task, abortSignal) => {
|
|
37232
|
+
if (abortSignal?.aborted) throw new Error("Dead-code worker aborted.");
|
|
37233
|
+
if (availableSlots < 0) availableSlots = resolveDeadCodeConcurrency();
|
|
37234
|
+
if (availableSlots > 0) availableSlots -= 1;
|
|
37235
|
+
else await new Promise((resolve, reject) => {
|
|
37236
|
+
const waiter = () => {
|
|
37237
|
+
abortSignal?.removeEventListener("abort", onAbort);
|
|
37238
|
+
resolve();
|
|
37239
|
+
};
|
|
37240
|
+
const onAbort = () => {
|
|
37241
|
+
const queuedIndex = waiters.indexOf(waiter);
|
|
37242
|
+
if (queuedIndex !== -1) waiters.splice(queuedIndex, 1);
|
|
37243
|
+
reject(/* @__PURE__ */ new Error("Dead-code worker aborted."));
|
|
37244
|
+
};
|
|
37245
|
+
waiters.push(waiter);
|
|
37246
|
+
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
37247
|
+
});
|
|
37248
|
+
try {
|
|
37249
|
+
return await task();
|
|
37250
|
+
} finally {
|
|
37251
|
+
releaseSlot();
|
|
37252
|
+
}
|
|
37253
|
+
};
|
|
37163
37254
|
/**
|
|
37164
37255
|
* Resolves a path to its canonical, symlink-free form, falling back to
|
|
37165
37256
|
* the input when it cannot be realpath'd (broken symlink, permission
|
|
@@ -37450,14 +37541,17 @@ const checkDeadCode = async (options) => {
|
|
|
37450
37541
|
if (!NFS.existsSync(Path.join(rootDirectory, "package.json"))) return [];
|
|
37451
37542
|
const entryPatterns = collectDeadCodeEntryPatterns(rootDirectory);
|
|
37452
37543
|
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
|
|
37453
|
-
const
|
|
37454
|
-
|
|
37455
|
-
|
|
37456
|
-
|
|
37457
|
-
|
|
37458
|
-
|
|
37459
|
-
|
|
37460
|
-
|
|
37544
|
+
const spawnAndRun = () => {
|
|
37545
|
+
return runDeadCodeWorkerWithTimeout((options.createWorker ?? createDeadCodeWorker)({
|
|
37546
|
+
rootDirectory,
|
|
37547
|
+
entryPatterns,
|
|
37548
|
+
tsConfigPath: resolveTsConfigPath(rootDirectory),
|
|
37549
|
+
ignorePatterns,
|
|
37550
|
+
deslopJsModuleSpecifier: options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js"),
|
|
37551
|
+
parseConcurrency: options.parseConcurrency
|
|
37552
|
+
}), options.workerTimeoutMs ?? 12e4, options.abortSignal);
|
|
37553
|
+
};
|
|
37554
|
+
const result = parseDeadCodeWorkerResult(options.createWorker === void 0 ? await withDeadCodeWorkerSlot(spawnAndRun, options.abortSignal) : await spawnAndRun());
|
|
37461
37555
|
const toRelative = (filePath) => toRelativeFilePath(rootDirectory, filePath);
|
|
37462
37556
|
const diagnostics = [];
|
|
37463
37557
|
for (const unusedFile of result.unusedFiles) diagnostics.push({
|
|
@@ -40621,7 +40715,10 @@ const formatLintFailText = (reasonTag, nodeVersion) => {
|
|
|
40621
40715
|
* diagnostics).
|
|
40622
40716
|
* 2. beforeLint hook (e.g. CLI renders the project-detection block)
|
|
40623
40717
|
* 3. environment checks (reduced-motion + pnpm hardening +
|
|
40624
|
-
* expo/react-native
|
|
40718
|
+
* expo/react-native), collected synchronously. The heavier
|
|
40719
|
+
* content-regex security scan is forked instead (like supply-chain
|
|
40720
|
+
* below) and joined before the concat, so its CPU overlaps lint
|
|
40721
|
+
* rather than blocking the event loop before it.
|
|
40625
40722
|
* 4. The supply-chain check (Socket.dev) is forked onto a background
|
|
40626
40723
|
* fiber so its ~100% network-bound time overlaps the ~100%
|
|
40627
40724
|
* CPU/subprocess-bound lint pass below, collapsing two serial
|
|
@@ -40641,7 +40738,7 @@ const formatLintFailText = (reasonTag, nodeVersion) => {
|
|
|
40641
40738
|
* order, so terminal output is identical either way; supply-chain
|
|
40642
40739
|
* rides alongside without a spinner.
|
|
40643
40740
|
* 6. Join the supply-chain fiber, then assemble the diagnostics in a
|
|
40644
|
-
* FIXED order (env, supply-chain, lint, dead-code) so the output is
|
|
40741
|
+
* FIXED order (env, security-scan, supply-chain, lint, dead-code) so the output is
|
|
40645
40742
|
* byte-identical regardless of which fiber settled first. The
|
|
40646
40743
|
* viewer-permission fiber is joined later, during score-metadata
|
|
40647
40744
|
* assembly (it feeds score metadata, not diagnostics). The per-element
|
|
@@ -40702,12 +40799,12 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
40702
40799
|
...checkPnpmHardening(scanDirectory),
|
|
40703
40800
|
...checkReactServerComponentsAdvisory(scanDirectory, project),
|
|
40704
40801
|
...checkExpoProject(scanDirectory, project),
|
|
40705
|
-
...checkReactNativeProject(scanDirectory, project)
|
|
40706
|
-
...checkSecurityScan(scanDirectory, {
|
|
40707
|
-
project,
|
|
40708
|
-
ignoredTags: input.ignoredTags
|
|
40709
|
-
})
|
|
40802
|
+
...checkReactNativeProject(scanDirectory, project)
|
|
40710
40803
|
])));
|
|
40804
|
+
const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(promise(() => checkSecurityScanCooperative(scanDirectory, {
|
|
40805
|
+
project,
|
|
40806
|
+
ignoredTags: input.ignoredTags
|
|
40807
|
+
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)))))).pipe(withSpan("SecurityScan.run")));
|
|
40711
40808
|
const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
|
|
40712
40809
|
const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
|
|
40713
40810
|
const supplyChainFiber = yield* forkChild(shouldRunSupplyChain ? runCollect(applyPerElementPipeline(supplyChainService.run({
|
|
@@ -40843,9 +40940,11 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
40843
40940
|
else yield* scanProgress.succeed(`Scanned ${scannedFilesLabel} in ${scanElapsedSeconds}s${workerCountSuffix}`);
|
|
40844
40941
|
const supplyChainResult = yield* join(supplyChainFiber);
|
|
40845
40942
|
const supplyChainCollected = supplyChainResult.diagnostics;
|
|
40943
|
+
const securityScanCollected = yield* join(securityScanFiber);
|
|
40846
40944
|
yield* reporterService.finalize;
|
|
40847
40945
|
const finalDiagnostics = sortDiagnosticsStable(assignFixGroups([
|
|
40848
40946
|
...envCollected,
|
|
40947
|
+
...securityScanCollected,
|
|
40849
40948
|
...supplyChainCollected,
|
|
40850
40949
|
...lintCollected,
|
|
40851
40950
|
...deadCodeCollected
|
|
@@ -42947,7 +43046,9 @@ const METRIC = {
|
|
|
42947
43046
|
lspSessionStarted: "lsp.session.started",
|
|
42948
43047
|
lspScanCompleted: "lsp.scan.completed",
|
|
42949
43048
|
lspScanDuration: "lsp.scan.duration",
|
|
42950
|
-
lspScanDiagnostics: "lsp.scan.diagnostics"
|
|
43049
|
+
lspScanDiagnostics: "lsp.scan.diagnostics",
|
|
43050
|
+
aiTrainingWarningShown: "ai.training.warning_shown",
|
|
43051
|
+
jsonOutUsed: "json.out_used"
|
|
42951
43052
|
};
|
|
42952
43053
|
//#endregion
|
|
42953
43054
|
//#region src/cli/utils/to-category-key.ts
|
|
@@ -43264,5 +43365,5 @@ const startLanguageServer = () => {
|
|
|
43264
43365
|
};
|
|
43265
43366
|
//#endregion
|
|
43266
43367
|
export { startLanguageServer };
|
|
43267
|
-
!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]="
|
|
43268
|
-
//# debugId=
|
|
43368
|
+
!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]="c5b6c740-461d-5f65-a993-9e6d35ad9113")}catch(e){}}();
|
|
43369
|
+
//# debugId=c5b6c740-461d-5f65-a993-9e6d35ad9113
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-doctor",
|
|
3
|
-
"version": "0.5.8-dev.
|
|
3
|
+
"version": "0.5.8-dev.f69f216",
|
|
4
4
|
"description": "Your agent writes bad React. This catches it",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"bugs": {
|
|
21
21
|
"url": "https://github.com/millionco/react-doctor/issues"
|
|
22
22
|
},
|
|
23
|
-
"license": "
|
|
23
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
24
24
|
"author": "Million Software, Inc",
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"bin/**",
|
|
35
35
|
"dist/**/*.js",
|
|
36
36
|
"dist/**/*.d.ts",
|
|
37
|
-
"dist/skills/**"
|
|
37
|
+
"dist/skills/**",
|
|
38
|
+
"LICENSE"
|
|
38
39
|
],
|
|
39
40
|
"type": "module",
|
|
40
41
|
"sideEffects": false,
|
|
@@ -59,12 +60,12 @@
|
|
|
59
60
|
"magicast": "^0.5.3",
|
|
60
61
|
"oxlint": ">=1.66.0 <1.67.0",
|
|
61
62
|
"prompts": "^2.4.2",
|
|
62
|
-
"typescript": ">=5.0.4 <
|
|
63
|
+
"typescript": ">=5.0.4 <6",
|
|
63
64
|
"vscode-languageserver": "^9.0.1",
|
|
64
65
|
"vscode-languageserver-textdocument": "^1.0.12",
|
|
65
66
|
"vscode-uri": "^3.1.0",
|
|
66
67
|
"deslop-js": "0.5.8",
|
|
67
|
-
"oxlint-plugin-react-doctor": "0.5.8-dev.
|
|
68
|
+
"oxlint-plugin-react-doctor": "0.5.8-dev.f69f216"
|
|
68
69
|
},
|
|
69
70
|
"devDependencies": {
|
|
70
71
|
"@types/babel__code-frame": "^7.27.0",
|
|
@@ -73,8 +74,8 @@
|
|
|
73
74
|
"commander": "^14.0.3",
|
|
74
75
|
"ora": "^9.4.0",
|
|
75
76
|
"@react-doctor/api": "0.5.8",
|
|
76
|
-
"@react-doctor/
|
|
77
|
-
"@react-doctor/
|
|
77
|
+
"@react-doctor/core": "0.5.8",
|
|
78
|
+
"@react-doctor/language-server": "0.5.8"
|
|
78
79
|
},
|
|
79
80
|
"engines": {
|
|
80
81
|
"node": "^20.19.0 || >=22.13.0"
|