react-doctor 0.9.1-dev.5d2f66d → 0.9.1-dev.8534d86
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/README.md +2 -0
- package/dist/cli.js +334 -45
- package/dist/index.d.ts +2 -2
- package/dist/index.js +329 -41
- package/dist/lsp.js +331 -42
- package/package.json +4 -4
package/dist/lsp.js
CHANGED
|
@@ -61478,7 +61478,8 @@ var AmbiguousProjectError = class extends Error {
|
|
|
61478
61478
|
}
|
|
61479
61479
|
};
|
|
61480
61480
|
const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
|
|
61481
|
-
const
|
|
61481
|
+
const HTML_FILE_PATTERN = /\.html$/i;
|
|
61482
|
+
const SOURCE_FILE_PATTERN = /\.(?:tsx?|jsx?|mts|mjs|[hH][tT][mM][lL])$/;
|
|
61482
61483
|
const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
|
|
61483
61484
|
const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
|
|
61484
61485
|
const MINIFIED_SNIFF_BYTES = 65536;
|
|
@@ -70573,6 +70574,12 @@ const appendReanimatedSharedValueHint = (help, rule, project) => {
|
|
|
70573
70574
|
if (!help) return REANIMATED_SHARED_VALUE_HINT;
|
|
70574
70575
|
return `${help}\n\n${REANIMATED_SHARED_VALUE_HINT}`;
|
|
70575
70576
|
};
|
|
70577
|
+
const columnOfUtf8Offset = (sourceBuffer, utf8Offset) => {
|
|
70578
|
+
const boundedOffset = Math.min(Math.max(utf8Offset, 0), sourceBuffer.length);
|
|
70579
|
+
let lineStartOffset = boundedOffset;
|
|
70580
|
+
while (lineStartOffset > 0 && sourceBuffer[lineStartOffset - 1] !== 10) lineStartOffset--;
|
|
70581
|
+
return sourceBuffer.subarray(lineStartOffset, boundedOffset).toString("utf8").length + 1;
|
|
70582
|
+
};
|
|
70576
70583
|
const REDACTED_PLACEHOLDER = "<redacted>";
|
|
70577
70584
|
const KEEP_PREFIX = `$1${REDACTED_PLACEHOLDER}`;
|
|
70578
70585
|
const KNOWN_SECRET_RULES = [
|
|
@@ -71288,7 +71295,7 @@ const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORI
|
|
|
71288
71295
|
* with empty text still carry a useful jump target, so they're kept
|
|
71289
71296
|
* with a neutral message.
|
|
71290
71297
|
*/
|
|
71291
|
-
const buildRelatedLocations = (labels, filePath) => {
|
|
71298
|
+
const buildRelatedLocations = (labels, filePath, sourceBuffer) => {
|
|
71292
71299
|
if (labels.length <= 1) return [];
|
|
71293
71300
|
const related = [];
|
|
71294
71301
|
for (let labelIndex = 1; labelIndex < labels.length; labelIndex++) {
|
|
@@ -71296,8 +71303,8 @@ const buildRelatedLocations = (labels, filePath) => {
|
|
|
71296
71303
|
if (!label?.span) continue;
|
|
71297
71304
|
related.push({
|
|
71298
71305
|
filePath,
|
|
71299
|
-
line: label.span.line ?? 0,
|
|
71300
|
-
column: label.span.column ?? 0,
|
|
71306
|
+
line: sourceBuffer === null ? label.span.line ?? 0 : lineOfUtf8Offset(sourceBuffer, label.span.offset),
|
|
71307
|
+
column: sourceBuffer === null ? label.span.column ?? 0 : columnOfUtf8Offset(sourceBuffer, label.span.offset),
|
|
71301
71308
|
offset: label.span.offset,
|
|
71302
71309
|
length: label.span.length,
|
|
71303
71310
|
message: label.label ?? ""
|
|
@@ -71317,7 +71324,7 @@ const isOxlintOutput = (value) => isRecord(value) && Array.isArray(value.diagnos
|
|
|
71317
71324
|
* to the first `{`. Raises `OxlintOutputUnparseable` when the
|
|
71318
71325
|
* stdout isn't valid JSON or doesn't carry a `diagnostics` array.
|
|
71319
71326
|
*/
|
|
71320
|
-
const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
71327
|
+
const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath) => {
|
|
71321
71328
|
if (!stdout) return [];
|
|
71322
71329
|
const jsonStart = stdout.indexOf("{");
|
|
71323
71330
|
const sanitizedStdout = jsonStart > 0 ? stdout.slice(jsonStart) : stdout;
|
|
@@ -71334,8 +71341,10 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
71334
71341
|
const sourceBufferCache = /* @__PURE__ */ new Map();
|
|
71335
71342
|
const sourceLinesCache = /* @__PURE__ */ new Map();
|
|
71336
71343
|
const resolveAbsolutePath = (filename) => Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
|
|
71344
|
+
const resolveMappedSourceFilename = (filename) => sourcePathByLintPath?.get(Path.normalize(resolveAbsolutePath(filename)));
|
|
71345
|
+
const resolveSourceFilename = (filename) => resolveMappedSourceFilename(filename) ?? filename;
|
|
71337
71346
|
const readSourceBuffer = (filename) => {
|
|
71338
|
-
const absolutePath = resolveAbsolutePath(filename);
|
|
71347
|
+
const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
|
|
71339
71348
|
const cached = sourceBufferCache.get(absolutePath);
|
|
71340
71349
|
if (cached !== void 0) return cached;
|
|
71341
71350
|
let sourceBuffer;
|
|
@@ -71348,7 +71357,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
71348
71357
|
return sourceBuffer;
|
|
71349
71358
|
};
|
|
71350
71359
|
const readSourceLines = (filename) => {
|
|
71351
|
-
const absolutePath = resolveAbsolutePath(filename);
|
|
71360
|
+
const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
|
|
71352
71361
|
const cached = sourceLinesCache.get(absolutePath);
|
|
71353
71362
|
if (cached !== void 0) return cached;
|
|
71354
71363
|
const sourceBuffer = readSourceBuffer(filename);
|
|
@@ -71357,27 +71366,30 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
71357
71366
|
return sourceLines;
|
|
71358
71367
|
};
|
|
71359
71368
|
const isMinifiedDiagnosticFile = (filename) => {
|
|
71360
|
-
const absolutePath = resolveAbsolutePath(filename);
|
|
71369
|
+
const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
|
|
71361
71370
|
const cached = minifiedFileCache.get(absolutePath);
|
|
71362
71371
|
if (cached !== void 0) return cached;
|
|
71363
71372
|
const minified = isMinifiedSource(absolutePath);
|
|
71364
71373
|
minifiedFileCache.set(absolutePath, minified);
|
|
71365
71374
|
return minified;
|
|
71366
71375
|
};
|
|
71367
|
-
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => isMappableOxlintDiagnostic(diagnostic) && isLintableSourceFile(diagnostic.filename) && !(TYPESCRIPT_DECLARATION_FILE_PATTERN.test(diagnostic.filename) && OXLINT_IGNORED_DECLARATION_DIAGNOSTIC_CODES.has(diagnostic.code)) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
|
|
71376
|
+
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => isMappableOxlintDiagnostic(diagnostic) && isLintableSourceFile(resolveSourceFilename(diagnostic.filename)) && !(TYPESCRIPT_DECLARATION_FILE_PATTERN.test(diagnostic.filename) && OXLINT_IGNORED_DECLARATION_DIAGNOSTIC_CODES.has(diagnostic.code)) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
|
|
71368
71377
|
const { plugin, rule } = parseRuleCode(diagnostic.code);
|
|
71369
71378
|
const primaryLabel = diagnostic.labels[0];
|
|
71370
71379
|
const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
|
|
71371
|
-
const
|
|
71380
|
+
const mappedSourceFilename = resolveMappedSourceFilename(diagnostic.filename);
|
|
71381
|
+
const normalizedFilePath = (mappedSourceFilename ?? diagnostic.filename).replaceAll("\\", "/");
|
|
71372
71382
|
const primarySpan = primaryLabel?.span;
|
|
71373
71383
|
const sourceBuffer = primarySpan ? readSourceBuffer(diagnostic.filename) : null;
|
|
71374
|
-
const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
|
|
71384
|
+
const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath, mappedSourceFilename === void 0 ? null : sourceBuffer);
|
|
71375
71385
|
const category = resolveDiagnosticCategory(plugin, rule);
|
|
71376
71386
|
const matchByOccurrence = resolveMatchByOccurrence(rule, category);
|
|
71377
71387
|
const sourceLines = primarySpan ? readSourceLines(diagnostic.filename) : null;
|
|
71378
|
-
const
|
|
71388
|
+
const primaryLineNumber = primarySpan && mappedSourceFilename !== void 0 && sourceBuffer !== null ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset) : primarySpan?.line ?? 0;
|
|
71389
|
+
const primaryColumnNumber = primarySpan && mappedSourceFilename !== void 0 && sourceBuffer !== null ? columnOfUtf8Offset(sourceBuffer, primarySpan.offset) : primarySpan?.column ?? 0;
|
|
71390
|
+
const primaryLineIndex = primarySpan ? primaryLineNumber - 1 : -1;
|
|
71379
71391
|
const primaryLine = sourceLines?.[primaryLineIndex];
|
|
71380
|
-
const primaryColumnIndex = primarySpan ?
|
|
71392
|
+
const primaryColumnIndex = primarySpan ? primaryColumnNumber - 1 : -1;
|
|
71381
71393
|
const isJsxTagLabel = primaryLine !== void 0 && primaryColumnIndex >= 0 && (primaryLine[primaryColumnIndex] === "<" || primaryLine[primaryColumnIndex - 1] === "<");
|
|
71382
71394
|
const jsxOpenerEndLineIndex = sourceLines && isJsxTagLabel ? findJsxOpenerSpan(sourceLines, primaryLineIndex) : null;
|
|
71383
71395
|
const primarySpanEndLine = jsxOpenerEndLineIndex !== null ? jsxOpenerEndLineIndex + 1 : primarySpan && sourceBuffer ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset + Math.max(primarySpan.length - 1, 0)) : void 0;
|
|
@@ -71390,8 +71402,8 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
71390
71402
|
message: cleaned.message,
|
|
71391
71403
|
help: cleaned.help,
|
|
71392
71404
|
url: diagnostic.url,
|
|
71393
|
-
line:
|
|
71394
|
-
column:
|
|
71405
|
+
line: primaryLineNumber,
|
|
71406
|
+
column: primaryColumnNumber,
|
|
71395
71407
|
...primarySpan ? {
|
|
71396
71408
|
offset: primarySpan.offset,
|
|
71397
71409
|
length: primarySpan.length,
|
|
@@ -71579,7 +71591,11 @@ const isParallelismRelatedSpawnError = (error) => {
|
|
|
71579
71591
|
* loop with a slimmer config in that case.
|
|
71580
71592
|
*/
|
|
71581
71593
|
const spawnLintBatches = async (input) => {
|
|
71582
|
-
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
|
|
71594
|
+
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
|
|
71595
|
+
const resolveSourcePath = (filePath) => {
|
|
71596
|
+
const absoluteFilePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory, filePath);
|
|
71597
|
+
return sourcePathByLintPath?.get(Path.normalize(absoluteFilePath)) ?? filePath;
|
|
71598
|
+
};
|
|
71583
71599
|
const requestedConcurrency = resolveScanConcurrency(input.concurrency ?? 1);
|
|
71584
71600
|
let rescueDeadlineEpochMs;
|
|
71585
71601
|
const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0 || rescueDeadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(rescueDeadlineEpochMs) === 0;
|
|
@@ -71599,7 +71615,7 @@ const spawnLintBatches = async (input) => {
|
|
|
71599
71615
|
}
|
|
71600
71616
|
const batchArgs = [...baseArgs, ...batch];
|
|
71601
71617
|
try {
|
|
71602
|
-
return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory);
|
|
71618
|
+
return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory, sourcePathByLintPath);
|
|
71603
71619
|
} catch (error) {
|
|
71604
71620
|
if (!isSplittableReactDoctorError(error)) throw error;
|
|
71605
71621
|
if (isPastDeadline()) {
|
|
@@ -71705,10 +71721,12 @@ const spawnLintBatches = async (input) => {
|
|
|
71705
71721
|
onPartialFailure(buildMessage(`${skippedFiles.slice(0, 3).join(", ")}${skippedFiles.length > 3 ? `, +${skippedFiles.length - 3} more` : ""}`));
|
|
71706
71722
|
};
|
|
71707
71723
|
const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
|
|
71708
|
-
|
|
71709
|
-
|
|
71724
|
+
const droppedSourceFiles = [...new Set(droppedFiles.map(resolveSourcePath))];
|
|
71725
|
+
const deadlineSkippedSourceFiles = [...new Set(outcome.deadlineSkippedFiles.map(resolveSourcePath))];
|
|
71726
|
+
reportSkippedFiles(droppedSourceFiles, (fileListPreview) => `${droppedSourceFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
|
|
71727
|
+
reportSkippedFiles(deadlineSkippedSourceFiles, (fileListPreview) => `${deadlineSkippedSourceFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
|
|
71710
71728
|
const unavailableFiles = new Set([...droppedFiles, ...outcome.deadlineSkippedFiles]);
|
|
71711
|
-
input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)))].sort());
|
|
71729
|
+
input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)).map(resolveSourcePath))].sort());
|
|
71712
71730
|
return dedupeDiagnostics(diagnostics);
|
|
71713
71731
|
};
|
|
71714
71732
|
let didValidate = false;
|
|
@@ -71807,6 +71825,266 @@ const planLintBatches = ({ baseArgs, files, sizeByFile }) => {
|
|
|
71807
71825
|
}
|
|
71808
71826
|
return batches.filter((batch) => batch.fileIndexes.length > 0).map((batch) => batch.fileIndexes.sort((leftIndex, rightIndex) => leftIndex - rightIndex).map((fileIndex) => files[fileIndex]));
|
|
71809
71827
|
};
|
|
71828
|
+
const THREE_MODULE_IMPORT_PATTERN = /\b(?:from\s*|import\s*(?:\(\s*)?|require\s*\(\s*)["']three(?:\/[^"']*)?["']/;
|
|
71829
|
+
const containsThreeModuleImport = (sourceText) => THREE_MODULE_IMPORT_PATTERN.test(sourceText);
|
|
71830
|
+
const COMMENT_OPEN = "<!--";
|
|
71831
|
+
const COMMENT_CLOSE = "-->";
|
|
71832
|
+
const FRONTMATTER_FENCE = "---";
|
|
71833
|
+
const SCRIPT_TAG_NAME = "script";
|
|
71834
|
+
const SCRIPT_OPEN = `<${SCRIPT_TAG_NAME}`;
|
|
71835
|
+
const SCRIPT_CLOSE = `</${SCRIPT_TAG_NAME}`;
|
|
71836
|
+
const TEMPLATE_TAG_NAME = "template";
|
|
71837
|
+
const TEMPLATE_CLOSE = `</${TEMPLATE_TAG_NAME}`;
|
|
71838
|
+
const JAVASCRIPT_MIME_TYPES = new Set([
|
|
71839
|
+
"application/ecmascript",
|
|
71840
|
+
"application/javascript",
|
|
71841
|
+
"application/x-ecmascript",
|
|
71842
|
+
"application/x-javascript",
|
|
71843
|
+
"text/ecmascript",
|
|
71844
|
+
"text/javascript",
|
|
71845
|
+
"text/javascript1.0",
|
|
71846
|
+
"text/javascript1.1",
|
|
71847
|
+
"text/javascript1.2",
|
|
71848
|
+
"text/javascript1.3",
|
|
71849
|
+
"text/javascript1.4",
|
|
71850
|
+
"text/javascript1.5",
|
|
71851
|
+
"text/jscript",
|
|
71852
|
+
"text/livescript",
|
|
71853
|
+
"text/x-ecmascript",
|
|
71854
|
+
"text/x-javascript"
|
|
71855
|
+
]);
|
|
71856
|
+
const RAW_TEXT_TAG_NAMES = new Set([
|
|
71857
|
+
"iframe",
|
|
71858
|
+
"noembed",
|
|
71859
|
+
"noframes",
|
|
71860
|
+
"noscript",
|
|
71861
|
+
"style",
|
|
71862
|
+
"textarea",
|
|
71863
|
+
"title",
|
|
71864
|
+
"xmp"
|
|
71865
|
+
]);
|
|
71866
|
+
const PLAINTEXT_TAG_NAME = "plaintext";
|
|
71867
|
+
const TAG_OPEN_UTF8_BYTE = "<".charCodeAt(0);
|
|
71868
|
+
const TAG_CLOSE_UTF8_BYTE = ">".charCodeAt(0);
|
|
71869
|
+
const SINGLE_QUOTE_UTF8_BYTE = "'".charCodeAt(0);
|
|
71870
|
+
const DOUBLE_QUOTE_UTF8_BYTE = "\"".charCodeAt(0);
|
|
71871
|
+
const ATTRIBUTE_ASSIGNMENT_UTF8_BYTE = "=".charCodeAt(0);
|
|
71872
|
+
const TAG_SELF_CLOSE_UTF8_BYTE = "/".charCodeAt(0);
|
|
71873
|
+
const TAB_UTF8_BYTE = " ".charCodeAt(0);
|
|
71874
|
+
const FORM_FEED_UTF8_BYTE = "\f".charCodeAt(0);
|
|
71875
|
+
const isHtmlWhitespace = (byte) => byte === TAB_UTF8_BYTE || byte === 10 || byte === FORM_FEED_UTF8_BYTE || byte === 13 || byte === 32;
|
|
71876
|
+
const matchesAsciiCaseInsensitive = (sourceBuffer, startByte, expected) => {
|
|
71877
|
+
if (startByte + expected.length > sourceBuffer.length) return false;
|
|
71878
|
+
for (let expectedIndex = 0; expectedIndex < expected.length; expectedIndex++) {
|
|
71879
|
+
const sourceByte = sourceBuffer[startByte + expectedIndex];
|
|
71880
|
+
if (sourceByte === void 0 || String.fromCharCode(sourceByte).toLowerCase() !== expected[expectedIndex]) return false;
|
|
71881
|
+
}
|
|
71882
|
+
return true;
|
|
71883
|
+
};
|
|
71884
|
+
const isTagBoundary = (byte) => byte === TAG_CLOSE_UTF8_BYTE || byte === TAG_SELF_CLOSE_UTF8_BYTE || isHtmlWhitespace(byte);
|
|
71885
|
+
const isPotentialTagStart = (byte) => {
|
|
71886
|
+
if (byte === void 0) return false;
|
|
71887
|
+
return /[A-Za-z!/?]/.test(String.fromCharCode(byte));
|
|
71888
|
+
};
|
|
71889
|
+
const findLineEnd = (sourceBuffer, lineStartByte) => {
|
|
71890
|
+
let byteIndex = lineStartByte;
|
|
71891
|
+
while (byteIndex < sourceBuffer.length && sourceBuffer[byteIndex] !== 10 && sourceBuffer[byteIndex] !== 13) byteIndex++;
|
|
71892
|
+
return byteIndex;
|
|
71893
|
+
};
|
|
71894
|
+
const findNextLineStart = (sourceBuffer, lineStartByte) => {
|
|
71895
|
+
const lineEndByte = findLineEnd(sourceBuffer, lineStartByte);
|
|
71896
|
+
if (sourceBuffer[lineEndByte] === 13 && sourceBuffer[lineEndByte + 1] === 10) return lineEndByte + 2;
|
|
71897
|
+
return Math.min(lineEndByte + 1, sourceBuffer.length);
|
|
71898
|
+
};
|
|
71899
|
+
const isFrontmatterFenceLine = (sourceBuffer, lineStartByte) => {
|
|
71900
|
+
if (!matchesAsciiCaseInsensitive(sourceBuffer, lineStartByte, FRONTMATTER_FENCE)) return false;
|
|
71901
|
+
const lineEndByte = findLineEnd(sourceBuffer, lineStartByte);
|
|
71902
|
+
for (let byteIndex = lineStartByte + 3; byteIndex < lineEndByte; byteIndex++) if (!isHtmlWhitespace(sourceBuffer[byteIndex])) return false;
|
|
71903
|
+
return true;
|
|
71904
|
+
};
|
|
71905
|
+
const findFrontmatterEnd = (sourceBuffer) => {
|
|
71906
|
+
if (!isFrontmatterFenceLine(sourceBuffer, 0)) return 0;
|
|
71907
|
+
const openingFenceEndByte = findLineEnd(sourceBuffer, 0);
|
|
71908
|
+
let lineStartByte = findNextLineStart(sourceBuffer, 0);
|
|
71909
|
+
while (lineStartByte < sourceBuffer.length) {
|
|
71910
|
+
if (isFrontmatterFenceLine(sourceBuffer, lineStartByte)) return findLineEnd(sourceBuffer, lineStartByte);
|
|
71911
|
+
lineStartByte = findNextLineStart(sourceBuffer, lineStartByte);
|
|
71912
|
+
}
|
|
71913
|
+
return openingFenceEndByte;
|
|
71914
|
+
};
|
|
71915
|
+
const maskByteRange = (maskedBuffer, startByte, endByte) => {
|
|
71916
|
+
for (let byteIndex = startByte; byteIndex < endByte; byteIndex++) {
|
|
71917
|
+
const byte = maskedBuffer[byteIndex];
|
|
71918
|
+
if (byte !== 10 && byte !== 13) maskedBuffer[byteIndex] = 32;
|
|
71919
|
+
}
|
|
71920
|
+
};
|
|
71921
|
+
const readStartTagName = (sourceBuffer, tagStartByte) => {
|
|
71922
|
+
const firstNameByte = sourceBuffer[tagStartByte + 1];
|
|
71923
|
+
if (firstNameByte === void 0 || !/[A-Za-z]/.test(String.fromCharCode(firstNameByte))) return null;
|
|
71924
|
+
let nameEndByte = tagStartByte + 2;
|
|
71925
|
+
while (nameEndByte < sourceBuffer.length && /[A-Za-z0-9:-]/.test(String.fromCharCode(sourceBuffer[nameEndByte] ?? 32))) nameEndByte++;
|
|
71926
|
+
return sourceBuffer.subarray(tagStartByte + 1, nameEndByte).toString("ascii").toLowerCase();
|
|
71927
|
+
};
|
|
71928
|
+
const findTagEnd = (sourceBuffer, startByte) => {
|
|
71929
|
+
let quoteByte = null;
|
|
71930
|
+
for (let byteIndex = startByte; byteIndex < sourceBuffer.length; byteIndex++) {
|
|
71931
|
+
const byte = sourceBuffer[byteIndex];
|
|
71932
|
+
if (quoteByte !== null) {
|
|
71933
|
+
if (byte === quoteByte) quoteByte = null;
|
|
71934
|
+
continue;
|
|
71935
|
+
}
|
|
71936
|
+
if (byte === SINGLE_QUOTE_UTF8_BYTE || byte === DOUBLE_QUOTE_UTF8_BYTE) {
|
|
71937
|
+
quoteByte = byte;
|
|
71938
|
+
continue;
|
|
71939
|
+
}
|
|
71940
|
+
if (byte === TAG_CLOSE_UTF8_BYTE) return byteIndex;
|
|
71941
|
+
}
|
|
71942
|
+
return sourceBuffer.length;
|
|
71943
|
+
};
|
|
71944
|
+
const parseScriptAttributes = (sourceBuffer, attributesStartByte, tagEndByte) => {
|
|
71945
|
+
let byteIndex = attributesStartByte;
|
|
71946
|
+
let hasSource = false;
|
|
71947
|
+
let language = null;
|
|
71948
|
+
let scriptType = null;
|
|
71949
|
+
while (byteIndex < tagEndByte) {
|
|
71950
|
+
while (byteIndex < tagEndByte && (isHtmlWhitespace(sourceBuffer[byteIndex]) || sourceBuffer[byteIndex] === TAG_SELF_CLOSE_UTF8_BYTE)) byteIndex++;
|
|
71951
|
+
const attributeNameStartByte = byteIndex;
|
|
71952
|
+
while (byteIndex < tagEndByte && !isHtmlWhitespace(sourceBuffer[byteIndex]) && sourceBuffer[byteIndex] !== ATTRIBUTE_ASSIGNMENT_UTF8_BYTE && sourceBuffer[byteIndex] !== TAG_SELF_CLOSE_UTF8_BYTE) byteIndex++;
|
|
71953
|
+
const attributeName = sourceBuffer.subarray(attributeNameStartByte, byteIndex).toString("ascii").toLowerCase();
|
|
71954
|
+
while (byteIndex < tagEndByte && isHtmlWhitespace(sourceBuffer[byteIndex])) byteIndex++;
|
|
71955
|
+
let attributeValue = "";
|
|
71956
|
+
if (sourceBuffer[byteIndex] === ATTRIBUTE_ASSIGNMENT_UTF8_BYTE) {
|
|
71957
|
+
byteIndex++;
|
|
71958
|
+
while (byteIndex < tagEndByte && isHtmlWhitespace(sourceBuffer[byteIndex])) byteIndex++;
|
|
71959
|
+
const quoteByte = sourceBuffer[byteIndex];
|
|
71960
|
+
if (quoteByte === SINGLE_QUOTE_UTF8_BYTE || quoteByte === DOUBLE_QUOTE_UTF8_BYTE) {
|
|
71961
|
+
const valueStartByte = byteIndex + 1;
|
|
71962
|
+
byteIndex = valueStartByte;
|
|
71963
|
+
while (byteIndex < tagEndByte && sourceBuffer[byteIndex] !== quoteByte) byteIndex++;
|
|
71964
|
+
attributeValue = sourceBuffer.subarray(valueStartByte, byteIndex).toString("utf8");
|
|
71965
|
+
if (byteIndex < tagEndByte) byteIndex++;
|
|
71966
|
+
} else {
|
|
71967
|
+
const valueStartByte = byteIndex;
|
|
71968
|
+
while (byteIndex < tagEndByte && !isHtmlWhitespace(sourceBuffer[byteIndex]) && sourceBuffer[byteIndex] !== TAG_CLOSE_UTF8_BYTE) byteIndex++;
|
|
71969
|
+
attributeValue = sourceBuffer.subarray(valueStartByte, byteIndex).toString("utf8");
|
|
71970
|
+
}
|
|
71971
|
+
}
|
|
71972
|
+
if (attributeName === "src") hasSource = true;
|
|
71973
|
+
else if (attributeName === "type" && scriptType === null) scriptType = attributeValue;
|
|
71974
|
+
else if (attributeName === "language" && language === null) language = attributeValue;
|
|
71975
|
+
}
|
|
71976
|
+
return {
|
|
71977
|
+
hasSource,
|
|
71978
|
+
language,
|
|
71979
|
+
type: scriptType
|
|
71980
|
+
};
|
|
71981
|
+
};
|
|
71982
|
+
const isExecutableScript = (attributes) => {
|
|
71983
|
+
if (attributes.hasSource) return false;
|
|
71984
|
+
const type = attributes.type?.trim().toLowerCase() ?? "";
|
|
71985
|
+
if (type !== "") {
|
|
71986
|
+
const mimeType = type.split(";")[0]?.trim() ?? "";
|
|
71987
|
+
return mimeType === "module" || JAVASCRIPT_MIME_TYPES.has(mimeType);
|
|
71988
|
+
}
|
|
71989
|
+
const language = attributes.language?.trim().toLowerCase() ?? "";
|
|
71990
|
+
return language === "" || JAVASCRIPT_MIME_TYPES.has(`text/${language}`);
|
|
71991
|
+
};
|
|
71992
|
+
const findElementClose = (sourceBuffer, startByte, tagName) => {
|
|
71993
|
+
const closeTagStart = `</${tagName}`;
|
|
71994
|
+
for (let byteIndex = startByte; byteIndex < sourceBuffer.length; byteIndex++) if (sourceBuffer[byteIndex] === TAG_OPEN_UTF8_BYTE && matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, closeTagStart) && isTagBoundary(sourceBuffer[byteIndex + closeTagStart.length])) return byteIndex;
|
|
71995
|
+
return sourceBuffer.length;
|
|
71996
|
+
};
|
|
71997
|
+
const prepareHtmlScriptSource = (sourceBuffer) => {
|
|
71998
|
+
const frontmatterEndByte = findFrontmatterEnd(sourceBuffer);
|
|
71999
|
+
let maskedBuffer = frontmatterEndByte > 0 ? Buffer.from(sourceBuffer) : null;
|
|
72000
|
+
if (maskedBuffer !== null) maskByteRange(maskedBuffer, 0, frontmatterEndByte);
|
|
72001
|
+
const executableScriptBodies = [];
|
|
72002
|
+
let byteIndex = frontmatterEndByte;
|
|
72003
|
+
let templateDepth = 0;
|
|
72004
|
+
while (byteIndex < sourceBuffer.length) {
|
|
72005
|
+
if (sourceBuffer[byteIndex] !== TAG_OPEN_UTF8_BYTE) {
|
|
72006
|
+
byteIndex++;
|
|
72007
|
+
continue;
|
|
72008
|
+
}
|
|
72009
|
+
if (matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, COMMENT_OPEN)) {
|
|
72010
|
+
const commentEndByte = sourceBuffer.indexOf(COMMENT_CLOSE, byteIndex + 4);
|
|
72011
|
+
byteIndex = commentEndByte === -1 ? sourceBuffer.length : commentEndByte + 3;
|
|
72012
|
+
continue;
|
|
72013
|
+
}
|
|
72014
|
+
if (matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, TEMPLATE_CLOSE) && isTagBoundary(sourceBuffer[byteIndex + TEMPLATE_CLOSE.length])) {
|
|
72015
|
+
const tagEndByte = findTagEnd(sourceBuffer, byteIndex + TEMPLATE_CLOSE.length);
|
|
72016
|
+
if (templateDepth > 0) templateDepth--;
|
|
72017
|
+
byteIndex = Math.min(tagEndByte + 1, sourceBuffer.length);
|
|
72018
|
+
continue;
|
|
72019
|
+
}
|
|
72020
|
+
if (!matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, SCRIPT_OPEN) || !isTagBoundary(sourceBuffer[byteIndex + SCRIPT_OPEN.length])) {
|
|
72021
|
+
if (!isPotentialTagStart(sourceBuffer[byteIndex + 1])) {
|
|
72022
|
+
byteIndex++;
|
|
72023
|
+
continue;
|
|
72024
|
+
}
|
|
72025
|
+
const tagEndByte = findTagEnd(sourceBuffer, byteIndex + 1);
|
|
72026
|
+
const tagName = readStartTagName(sourceBuffer, byteIndex);
|
|
72027
|
+
if (tagName === PLAINTEXT_TAG_NAME) break;
|
|
72028
|
+
if (tagName === TEMPLATE_TAG_NAME) templateDepth++;
|
|
72029
|
+
if (tagName !== null && RAW_TEXT_TAG_NAMES.has(tagName)) {
|
|
72030
|
+
const closeTagStartByte = findElementClose(sourceBuffer, tagEndByte + 1, tagName);
|
|
72031
|
+
if (closeTagStartByte === sourceBuffer.length) break;
|
|
72032
|
+
const closeTagEndByte = findTagEnd(sourceBuffer, closeTagStartByte + tagName.length + 2);
|
|
72033
|
+
byteIndex = Math.min(closeTagEndByte + 1, sourceBuffer.length);
|
|
72034
|
+
continue;
|
|
72035
|
+
}
|
|
72036
|
+
byteIndex = Math.min(tagEndByte + 1, sourceBuffer.length);
|
|
72037
|
+
continue;
|
|
72038
|
+
}
|
|
72039
|
+
const tagEndByte = findTagEnd(sourceBuffer, byteIndex + SCRIPT_OPEN.length);
|
|
72040
|
+
if (tagEndByte === sourceBuffer.length) break;
|
|
72041
|
+
const bodyStartByte = tagEndByte + 1;
|
|
72042
|
+
const bodyEndByte = findElementClose(sourceBuffer, bodyStartByte, SCRIPT_TAG_NAME);
|
|
72043
|
+
const attributes = parseScriptAttributes(sourceBuffer, byteIndex + SCRIPT_OPEN.length, tagEndByte);
|
|
72044
|
+
if (attributes.hasSource || templateDepth > 0) {
|
|
72045
|
+
maskedBuffer ??= Buffer.from(sourceBuffer);
|
|
72046
|
+
maskByteRange(maskedBuffer, bodyStartByte, bodyEndByte);
|
|
72047
|
+
} else if (isExecutableScript(attributes)) executableScriptBodies.push(sourceBuffer.subarray(bodyStartByte, bodyEndByte));
|
|
72048
|
+
if (bodyEndByte === sourceBuffer.length) break;
|
|
72049
|
+
const closeTagEndByte = findTagEnd(sourceBuffer, bodyEndByte + SCRIPT_CLOSE.length);
|
|
72050
|
+
byteIndex = Math.min(closeTagEndByte + 1, sourceBuffer.length);
|
|
72051
|
+
}
|
|
72052
|
+
return {
|
|
72053
|
+
executableScriptBodies,
|
|
72054
|
+
lintBuffer: maskedBuffer ?? sourceBuffer
|
|
72055
|
+
};
|
|
72056
|
+
};
|
|
72057
|
+
const prepareHtmlLintSources = (rootDirectory, temporaryDirectory, candidateFiles) => {
|
|
72058
|
+
const lintFiles = [];
|
|
72059
|
+
const sourcePathByLintPath = /* @__PURE__ */ new Map();
|
|
72060
|
+
const sizeByLintPath = /* @__PURE__ */ new Map();
|
|
72061
|
+
const htmlSourcesDirectory = Path.join(temporaryDirectory, "html-sources");
|
|
72062
|
+
let htmlFileIndex = 0;
|
|
72063
|
+
let hasThreeModuleImport = false;
|
|
72064
|
+
for (const candidateFile of candidateFiles) {
|
|
72065
|
+
if (!HTML_FILE_PATTERN.test(candidateFile)) {
|
|
72066
|
+
lintFiles.push(candidateFile);
|
|
72067
|
+
continue;
|
|
72068
|
+
}
|
|
72069
|
+
const absoluteSourcePath = Path.isAbsolute(candidateFile) ? candidateFile : Path.resolve(rootDirectory, candidateFile);
|
|
72070
|
+
const sourceBuffer = NFS.readFileSync(absoluteSourcePath);
|
|
72071
|
+
const { executableScriptBodies, lintBuffer } = prepareHtmlScriptSource(sourceBuffer);
|
|
72072
|
+
if (htmlFileIndex === 0) NFS.mkdirSync(htmlSourcesDirectory, { recursive: true });
|
|
72073
|
+
const lintPath = Path.join(htmlSourcesDirectory, `${htmlFileIndex}.astro`);
|
|
72074
|
+
NFS.writeFileSync(lintPath, lintBuffer);
|
|
72075
|
+
lintFiles.push(lintPath);
|
|
72076
|
+
sourcePathByLintPath.set(Path.resolve(lintPath), candidateFile);
|
|
72077
|
+
sizeByLintPath.set(lintPath, sourceBuffer.length);
|
|
72078
|
+
hasThreeModuleImport ||= executableScriptBodies.some((scriptBody) => containsThreeModuleImport(scriptBody.toString("utf8")));
|
|
72079
|
+
htmlFileIndex++;
|
|
72080
|
+
}
|
|
72081
|
+
return {
|
|
72082
|
+
lintFiles,
|
|
72083
|
+
sourcePathByLintPath,
|
|
72084
|
+
sizeByLintPath,
|
|
72085
|
+
hasThreeModuleImport
|
|
72086
|
+
};
|
|
72087
|
+
};
|
|
71810
72088
|
/**
|
|
71811
72089
|
* Atomically (re)writes the generated oxlintrc.json. Used twice in
|
|
71812
72090
|
* the runner: once for the primary scan, once for the
|
|
@@ -71980,21 +72258,6 @@ const runOxlint = async (options) => {
|
|
|
71980
72258
|
const pluginPath = resolvePluginPath();
|
|
71981
72259
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
71982
72260
|
const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
71983
|
-
const buildConfig = (overrides) => createOxlintConfig({
|
|
71984
|
-
pluginPath,
|
|
71985
|
-
project,
|
|
71986
|
-
customRulesOnly,
|
|
71987
|
-
extendsPaths: overrides.extendsPaths,
|
|
71988
|
-
ignoredTags,
|
|
71989
|
-
includedTags,
|
|
71990
|
-
includeTagDefaults,
|
|
71991
|
-
serverAuthFunctionNames,
|
|
71992
|
-
severityControls,
|
|
71993
|
-
userPlugins,
|
|
71994
|
-
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
|
|
71995
|
-
ruleSelection: overrides.ruleSelection,
|
|
71996
|
-
sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
|
|
71997
|
-
});
|
|
71998
72261
|
const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
|
|
71999
72262
|
const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
|
|
72000
72263
|
const configPath = Path.join(configDirectory, "oxlintrc.json");
|
|
@@ -72030,7 +72293,30 @@ const runOxlint = async (options) => {
|
|
|
72030
72293
|
await yieldToEventLoop();
|
|
72031
72294
|
const sizedScanFiles = includePaths === void 0 ? listSourceFilesWithSize(rootDirectory) : null;
|
|
72032
72295
|
const candidateFiles = includePaths !== void 0 ? includePaths : (sizedScanFiles ?? []).map((entry) => entry.path);
|
|
72296
|
+
const preparedHtmlSources = prepareHtmlLintSources(rootDirectory, configDirectory, candidateFiles);
|
|
72297
|
+
const lintFiles = preparedHtmlSources.lintFiles;
|
|
72298
|
+
const hasHtmlFiles = preparedHtmlSources.sourcePathByLintPath.size > 0;
|
|
72299
|
+
const lintProject = !project.hasThree && preparedHtmlSources.hasThreeModuleImport ? {
|
|
72300
|
+
...project,
|
|
72301
|
+
hasThree: true
|
|
72302
|
+
} : project;
|
|
72303
|
+
const buildConfig = (overrides) => createOxlintConfig({
|
|
72304
|
+
pluginPath,
|
|
72305
|
+
project: lintProject,
|
|
72306
|
+
customRulesOnly,
|
|
72307
|
+
extendsPaths: overrides.extendsPaths,
|
|
72308
|
+
ignoredTags,
|
|
72309
|
+
includedTags,
|
|
72310
|
+
includeTagDefaults,
|
|
72311
|
+
serverAuthFunctionNames,
|
|
72312
|
+
severityControls,
|
|
72313
|
+
userPlugins,
|
|
72314
|
+
disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
|
|
72315
|
+
ruleSelection: overrides.ruleSelection,
|
|
72316
|
+
sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
|
|
72317
|
+
});
|
|
72033
72318
|
const sizeByFile = sizedScanFiles !== null && lintBatchOrdering === "cost" ? new Map(sizedScanFiles.map((entry) => [entry.path, entry.sizeBytes])) : null;
|
|
72319
|
+
if (sizeByFile !== null) for (const [lintPath, sizeBytes] of preparedHtmlSources.sizeByLintPath) sizeByFile.set(lintPath, sizeBytes);
|
|
72034
72320
|
const buildFileBatches = (passBaseArgs, passFiles) => sizeByFile !== null ? planLintBatches({
|
|
72035
72321
|
baseArgs: passBaseArgs,
|
|
72036
72322
|
files: passFiles,
|
|
@@ -72059,7 +72345,8 @@ const runOxlint = async (options) => {
|
|
|
72059
72345
|
fileBatches: passFileBatches,
|
|
72060
72346
|
rootDirectory,
|
|
72061
72347
|
nodeBinaryPath,
|
|
72062
|
-
project,
|
|
72348
|
+
project: lintProject,
|
|
72349
|
+
sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
|
|
72063
72350
|
onPartialFailure: reportPartialFailure,
|
|
72064
72351
|
onAnalyzedFiles: (filePaths) => {
|
|
72065
72352
|
analyzedFiles = filePaths;
|
|
@@ -72094,7 +72381,7 @@ const runOxlint = async (options) => {
|
|
|
72094
72381
|
};
|
|
72095
72382
|
}
|
|
72096
72383
|
};
|
|
72097
|
-
if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
72384
|
+
if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0 && !hasHtmlFiles) {
|
|
72098
72385
|
const rulesetHash = computeRulesetHash({
|
|
72099
72386
|
config: buildConfig({
|
|
72100
72387
|
extendsPaths: [],
|
|
@@ -72252,14 +72539,15 @@ const runOxlint = async (options) => {
|
|
|
72252
72539
|
]);
|
|
72253
72540
|
}
|
|
72254
72541
|
const baseArgs = makeBaseArgs(configPath);
|
|
72255
|
-
const fileBatches = buildFileBatches(baseArgs,
|
|
72542
|
+
const fileBatches = buildFileBatches(baseArgs, lintFiles);
|
|
72256
72543
|
let analyzedFiles = [];
|
|
72257
72544
|
const runBatches = () => spawnLintBatches({
|
|
72258
72545
|
baseArgs,
|
|
72259
72546
|
fileBatches,
|
|
72260
72547
|
rootDirectory,
|
|
72261
72548
|
nodeBinaryPath,
|
|
72262
|
-
project,
|
|
72549
|
+
project: lintProject,
|
|
72550
|
+
sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
|
|
72263
72551
|
onPartialFailure,
|
|
72264
72552
|
onAnalyzedFiles: (filePaths) => {
|
|
72265
72553
|
analyzedFiles = filePaths;
|
|
@@ -73835,7 +74123,8 @@ const SCANNABLE_EXTENSIONS = [
|
|
|
73835
74123
|
".js",
|
|
73836
74124
|
".jsx",
|
|
73837
74125
|
".mts",
|
|
73838
|
-
".mjs"
|
|
74126
|
+
".mjs",
|
|
74127
|
+
".html"
|
|
73839
74128
|
];
|
|
73840
74129
|
const SILENT_LOGGER = {
|
|
73841
74130
|
info: () => {},
|
|
@@ -75823,5 +76112,5 @@ const startLanguageServer = () => {
|
|
|
75823
76112
|
};
|
|
75824
76113
|
//#endregion
|
|
75825
76114
|
export { startLanguageServer };
|
|
75826
|
-
!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]="
|
|
75827
|
-
//# debugId=
|
|
76115
|
+
!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]="8f4550d9-ab09-5b95-8e16-28b534d81552")}catch(e){}}();
|
|
76116
|
+
//# debugId=8f4550d9-ab09-5b95-8e16-28b534d81552
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-doctor",
|
|
3
|
-
"version": "0.9.1-dev.
|
|
3
|
+
"version": "0.9.1-dev.8534d86",
|
|
4
4
|
"description": "Your agent writes bad React. This catches it",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"vscode-uri": "^3.1.0",
|
|
71
71
|
"yaml": "^2.9.0",
|
|
72
72
|
"deslop-js": "0.9.1",
|
|
73
|
-
"oxlint-plugin-react-doctor": "0.9.1-dev.
|
|
73
|
+
"oxlint-plugin-react-doctor": "0.9.1-dev.8534d86"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"@types/babel__code-frame": "^7.27.0",
|
|
@@ -80,9 +80,9 @@
|
|
|
80
80
|
"commander": "^14.0.3",
|
|
81
81
|
"ink-testing-library": "^4.0.0",
|
|
82
82
|
"ora": "^9.4.0",
|
|
83
|
-
"@react-doctor/api": "0.9.1",
|
|
84
83
|
"@react-doctor/core": "0.9.1",
|
|
85
|
-
"@react-doctor/language-server": "0.9.1"
|
|
84
|
+
"@react-doctor/language-server": "0.9.1",
|
|
85
|
+
"@react-doctor/api": "0.9.1"
|
|
86
86
|
},
|
|
87
87
|
"engines": {
|
|
88
88
|
"node": "^20.19.0 || >=22.13.0"
|