react-doctor 0.9.2-dev.f1a1b16 → 0.9.2-dev.fb5f881
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 -2
- package/dist/cli.js +951 -194
- package/dist/index.d.ts +9 -3
- package/dist/index.js +662 -95
- package/dist/lsp.js +643 -90
- package/dist/{run-scan-app-C9MJnVwv.js → run-scan-app-DHRvqfkX.js} +11 -10
- package/package.json +5 -4
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]="
|
|
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]="3bff4f9b-31f8-5abe-b7a2-a0ab9f6a85b4")}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";
|
|
@@ -8,18 +8,19 @@ import path from "node:path";
|
|
|
8
8
|
import * as NFS from "node:fs";
|
|
9
9
|
import fs, { mkdtempSync, rmSync } from "node:fs";
|
|
10
10
|
import process$1 from "node:process";
|
|
11
|
-
import
|
|
11
|
+
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";
|
|
12
12
|
import * as Crypto from "node:crypto";
|
|
13
13
|
import crypto, { createHash, randomUUID } from "node:crypto";
|
|
14
14
|
import { ResolverFactory } from "oxc-resolver";
|
|
15
15
|
import ts from "typescript";
|
|
16
|
+
import * as NodeUrl from "node:url";
|
|
17
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
16
18
|
import * as OS from "node:os";
|
|
17
19
|
import os, { tmpdir } from "node:os";
|
|
18
20
|
import { parseJSON5 } from "confbox";
|
|
19
|
-
import * as NodeUrl from "node:url";
|
|
20
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
21
21
|
import { createJiti } from "jiti";
|
|
22
22
|
import { ANALYZED_MANIFEST_FILENAMES, DEFAULT_EXTENSIONS } from "deslop-js/analyzed-inputs";
|
|
23
|
+
import { convertToTSX } from "@astrojs/compiler/sync";
|
|
23
24
|
import { gzipSync } from "node:zlib";
|
|
24
25
|
import * as Sentry from "@sentry/node";
|
|
25
26
|
import { performance as performance$1 } from "node:perf_hooks";
|
|
@@ -13342,7 +13343,7 @@ const Number$4 = globalThis.Number;
|
|
|
13342
13343
|
* @category constructors
|
|
13343
13344
|
* @since 2.0.0
|
|
13344
13345
|
*/
|
|
13345
|
-
const parse = (s) => {
|
|
13346
|
+
const parse$1 = (s) => {
|
|
13346
13347
|
if (s === "NaN") return some(NaN);
|
|
13347
13348
|
if (s === "Infinity") return some(Infinity);
|
|
13348
13349
|
if (s === "-Infinity") return some(-Infinity);
|
|
@@ -17405,12 +17406,12 @@ TaggedError("EncodingError");
|
|
|
17405
17406
|
//#endregion
|
|
17406
17407
|
//#region ../../node_modules/.pnpm/effect@4.0.0-beta.70/node_modules/effect/dist/internal/schema/annotations.js
|
|
17407
17408
|
/** @internal */
|
|
17408
|
-
function resolve(ast) {
|
|
17409
|
+
function resolve$1(ast) {
|
|
17409
17410
|
return ast.checks ? ast.checks[ast.checks.length - 1].annotations : ast.annotations;
|
|
17410
17411
|
}
|
|
17411
17412
|
/** @internal */
|
|
17412
17413
|
function resolveAt(key) {
|
|
17413
|
-
return (ast) => resolve(ast)?.[key];
|
|
17414
|
+
return (ast) => resolve$1(ast)?.[key];
|
|
17414
17415
|
}
|
|
17415
17416
|
/** @internal */
|
|
17416
17417
|
const resolveIdentifier = /* @__PURE__ */ resolveAt("identifier");
|
|
@@ -21162,7 +21163,7 @@ function asSync(parser) {
|
|
|
21162
21163
|
}
|
|
21163
21164
|
const recur$1 = /* @__PURE__ */ memoize((ast) => {
|
|
21164
21165
|
let parser;
|
|
21165
|
-
const astOptions = resolve(ast)?.["parseOptions"];
|
|
21166
|
+
const astOptions = resolve$1(ast)?.["parseOptions"];
|
|
21166
21167
|
if (!ast.context && !ast.encoding && !ast.checks) return (ou, options) => {
|
|
21167
21168
|
parser ??= ast.getParser(recur$1);
|
|
21168
21169
|
if (astOptions) options = {
|
|
@@ -60767,7 +60768,7 @@ var UrlParamsError = class extends TaggedError("UrlParamsError") {};
|
|
|
60767
60768
|
* @category converting
|
|
60768
60769
|
* @since 4.0.0
|
|
60769
60770
|
*/
|
|
60770
|
-
const makeUrl = (url, params, hash) => {
|
|
60771
|
+
const makeUrl$1 = (url, params, hash) => {
|
|
60771
60772
|
try {
|
|
60772
60773
|
const urlInstance = new URL(url, baseUrl());
|
|
60773
60774
|
for (let i = 0; i < params.params.length; i++) {
|
|
@@ -61401,7 +61402,7 @@ const Proto$2 = {
|
|
|
61401
61402
|
const make$10 = (f) => makeWith$1((effect) => flatMap$2(effect, (request) => withFiber((fiber) => {
|
|
61402
61403
|
const scopedController = scopedRequests.get(request);
|
|
61403
61404
|
const controller = scopedController ?? new AbortController();
|
|
61404
|
-
const urlResult = makeUrl(request.url, request.urlParams, getOrUndefined(request.hash));
|
|
61405
|
+
const urlResult = makeUrl$1(request.url, request.urlParams, getOrUndefined(request.hash));
|
|
61405
61406
|
if (isFailure(urlResult)) return fail$4(new HttpClientError({ reason: new InvalidUrlError({
|
|
61406
61407
|
request,
|
|
61407
61408
|
cause: urlResult.failure
|
|
@@ -61840,7 +61841,7 @@ const layer$8 = (loggers, options) => effect(CurrentLoggers, withFiber$1(fnUntra
|
|
|
61840
61841
|
* @since 4.0.0
|
|
61841
61842
|
*/
|
|
61842
61843
|
const policy = /* @__PURE__ */ forever$1.pipe(passthrough$2, /* @__PURE__ */ addDelay((error) => {
|
|
61843
|
-
if (isHttpClientError(error) && error.reason._tag === "StatusCodeError" && error.reason.response.status === 429) return succeed$2(seconds(fromUndefinedOr(error.reason.response.headers["retry-after"]).pipe(flatMap$5(parse), getOrElse$1(() => 5))));
|
|
61844
|
+
if (isHttpClientError(error) && error.reason._tag === "StatusCodeError" && error.reason.response.status === 429) return succeed$2(seconds(fromUndefinedOr(error.reason.response.headers["retry-after"]).pipe(flatMap$5(parse$1), getOrElse$1(() => 5))));
|
|
61844
61845
|
return succeed$2(seconds(1));
|
|
61845
61846
|
}));
|
|
61846
61847
|
/**
|
|
@@ -64549,6 +64550,428 @@ const layer$1 = /* @__PURE__ */ succeed$3(Path$1)({
|
|
|
64549
64550
|
toFileUrl
|
|
64550
64551
|
});
|
|
64551
64552
|
//#endregion
|
|
64553
|
+
//#region ../../node_modules/.pnpm/@jridgewell+sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
|
|
64554
|
+
var comma = ",".charCodeAt(0);
|
|
64555
|
+
";".charCodeAt(0);
|
|
64556
|
+
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
64557
|
+
var intToChar = new Uint8Array(64);
|
|
64558
|
+
var charToInt = new Uint8Array(128);
|
|
64559
|
+
for (let i = 0; i < chars.length; i++) {
|
|
64560
|
+
const c = chars.charCodeAt(i);
|
|
64561
|
+
intToChar[i] = c;
|
|
64562
|
+
charToInt[c] = i;
|
|
64563
|
+
}
|
|
64564
|
+
function decodeInteger(reader, relative) {
|
|
64565
|
+
let value = 0;
|
|
64566
|
+
let shift = 0;
|
|
64567
|
+
let integer = 0;
|
|
64568
|
+
do {
|
|
64569
|
+
integer = charToInt[reader.next()];
|
|
64570
|
+
value |= (integer & 31) << shift;
|
|
64571
|
+
shift += 5;
|
|
64572
|
+
} while (integer & 32);
|
|
64573
|
+
const shouldNegate = value & 1;
|
|
64574
|
+
value >>>= 1;
|
|
64575
|
+
if (shouldNegate) value = -2147483648 | -value;
|
|
64576
|
+
return relative + value;
|
|
64577
|
+
}
|
|
64578
|
+
function hasMoreVlq(reader, max) {
|
|
64579
|
+
if (reader.pos >= max) return false;
|
|
64580
|
+
return reader.peek() !== comma;
|
|
64581
|
+
}
|
|
64582
|
+
var StringReader = class {
|
|
64583
|
+
constructor(buffer) {
|
|
64584
|
+
this.pos = 0;
|
|
64585
|
+
this.buffer = buffer;
|
|
64586
|
+
}
|
|
64587
|
+
next() {
|
|
64588
|
+
return this.buffer.charCodeAt(this.pos++);
|
|
64589
|
+
}
|
|
64590
|
+
peek() {
|
|
64591
|
+
return this.buffer.charCodeAt(this.pos);
|
|
64592
|
+
}
|
|
64593
|
+
indexOf(char) {
|
|
64594
|
+
const { buffer, pos } = this;
|
|
64595
|
+
const idx = buffer.indexOf(char, pos);
|
|
64596
|
+
return idx === -1 ? buffer.length : idx;
|
|
64597
|
+
}
|
|
64598
|
+
};
|
|
64599
|
+
function decode(mappings) {
|
|
64600
|
+
const { length } = mappings;
|
|
64601
|
+
const reader = new StringReader(mappings);
|
|
64602
|
+
const decoded = [];
|
|
64603
|
+
let genColumn = 0;
|
|
64604
|
+
let sourcesIndex = 0;
|
|
64605
|
+
let sourceLine = 0;
|
|
64606
|
+
let sourceColumn = 0;
|
|
64607
|
+
let namesIndex = 0;
|
|
64608
|
+
do {
|
|
64609
|
+
const semi = reader.indexOf(";");
|
|
64610
|
+
const line = [];
|
|
64611
|
+
let sorted = true;
|
|
64612
|
+
let lastCol = 0;
|
|
64613
|
+
genColumn = 0;
|
|
64614
|
+
while (reader.pos < semi) {
|
|
64615
|
+
let seg;
|
|
64616
|
+
genColumn = decodeInteger(reader, genColumn);
|
|
64617
|
+
if (genColumn < lastCol) sorted = false;
|
|
64618
|
+
lastCol = genColumn;
|
|
64619
|
+
if (hasMoreVlq(reader, semi)) {
|
|
64620
|
+
sourcesIndex = decodeInteger(reader, sourcesIndex);
|
|
64621
|
+
sourceLine = decodeInteger(reader, sourceLine);
|
|
64622
|
+
sourceColumn = decodeInteger(reader, sourceColumn);
|
|
64623
|
+
if (hasMoreVlq(reader, semi)) {
|
|
64624
|
+
namesIndex = decodeInteger(reader, namesIndex);
|
|
64625
|
+
seg = [
|
|
64626
|
+
genColumn,
|
|
64627
|
+
sourcesIndex,
|
|
64628
|
+
sourceLine,
|
|
64629
|
+
sourceColumn,
|
|
64630
|
+
namesIndex
|
|
64631
|
+
];
|
|
64632
|
+
} else seg = [
|
|
64633
|
+
genColumn,
|
|
64634
|
+
sourcesIndex,
|
|
64635
|
+
sourceLine,
|
|
64636
|
+
sourceColumn
|
|
64637
|
+
];
|
|
64638
|
+
} else seg = [genColumn];
|
|
64639
|
+
line.push(seg);
|
|
64640
|
+
reader.pos++;
|
|
64641
|
+
}
|
|
64642
|
+
if (!sorted) sort(line);
|
|
64643
|
+
decoded.push(line);
|
|
64644
|
+
reader.pos = semi + 1;
|
|
64645
|
+
} while (reader.pos <= length);
|
|
64646
|
+
return decoded;
|
|
64647
|
+
}
|
|
64648
|
+
function sort(line) {
|
|
64649
|
+
line.sort(sortComparator$1);
|
|
64650
|
+
}
|
|
64651
|
+
function sortComparator$1(a, b) {
|
|
64652
|
+
return a[0] - b[0];
|
|
64653
|
+
}
|
|
64654
|
+
//#endregion
|
|
64655
|
+
//#region ../../node_modules/.pnpm/@jridgewell+resolve-uri@3.1.2/node_modules/@jridgewell/resolve-uri/dist/resolve-uri.mjs
|
|
64656
|
+
const schemeRegex = /^[\w+.-]+:\/\//;
|
|
64657
|
+
/**
|
|
64658
|
+
* Matches the parts of a URL:
|
|
64659
|
+
* 1. Scheme, including ":", guaranteed.
|
|
64660
|
+
* 2. User/password, including "@", optional.
|
|
64661
|
+
* 3. Host, guaranteed.
|
|
64662
|
+
* 4. Port, including ":", optional.
|
|
64663
|
+
* 5. Path, including "/", optional.
|
|
64664
|
+
* 6. Query, including "?", optional.
|
|
64665
|
+
* 7. Hash, including "#", optional.
|
|
64666
|
+
*/
|
|
64667
|
+
const urlRegex = /^([\w+.-]+:)\/\/([^@/#?]*@)?([^:/#?]*)(:\d+)?(\/[^#?]*)?(\?[^#]*)?(#.*)?/;
|
|
64668
|
+
/**
|
|
64669
|
+
* File URLs are weird. They dont' need the regular `//` in the scheme, they may or may not start
|
|
64670
|
+
* with a leading `/`, they can have a domain (but only if they don't start with a Windows drive).
|
|
64671
|
+
*
|
|
64672
|
+
* 1. Host, optional.
|
|
64673
|
+
* 2. Path, which may include "/", guaranteed.
|
|
64674
|
+
* 3. Query, including "?", optional.
|
|
64675
|
+
* 4. Hash, including "#", optional.
|
|
64676
|
+
*/
|
|
64677
|
+
const fileRegex = /^file:(?:\/\/((?![a-z]:)[^/#?]*)?)?(\/?[^#?]*)(\?[^#]*)?(#.*)?/i;
|
|
64678
|
+
function isAbsoluteUrl(input) {
|
|
64679
|
+
return schemeRegex.test(input);
|
|
64680
|
+
}
|
|
64681
|
+
function isSchemeRelativeUrl(input) {
|
|
64682
|
+
return input.startsWith("//");
|
|
64683
|
+
}
|
|
64684
|
+
function isAbsolutePath(input) {
|
|
64685
|
+
return input.startsWith("/");
|
|
64686
|
+
}
|
|
64687
|
+
function isFileUrl(input) {
|
|
64688
|
+
return input.startsWith("file:");
|
|
64689
|
+
}
|
|
64690
|
+
function isRelative(input) {
|
|
64691
|
+
return /^[.?#]/.test(input);
|
|
64692
|
+
}
|
|
64693
|
+
function parseAbsoluteUrl(input) {
|
|
64694
|
+
const match = urlRegex.exec(input);
|
|
64695
|
+
return makeUrl(match[1], match[2] || "", match[3], match[4] || "", match[5] || "/", match[6] || "", match[7] || "");
|
|
64696
|
+
}
|
|
64697
|
+
function parseFileUrl(input) {
|
|
64698
|
+
const match = fileRegex.exec(input);
|
|
64699
|
+
const path = match[2];
|
|
64700
|
+
return makeUrl("file:", "", match[1] || "", "", isAbsolutePath(path) ? path : "/" + path, match[3] || "", match[4] || "");
|
|
64701
|
+
}
|
|
64702
|
+
function makeUrl(scheme, user, host, port, path, query, hash) {
|
|
64703
|
+
return {
|
|
64704
|
+
scheme,
|
|
64705
|
+
user,
|
|
64706
|
+
host,
|
|
64707
|
+
port,
|
|
64708
|
+
path,
|
|
64709
|
+
query,
|
|
64710
|
+
hash,
|
|
64711
|
+
type: 7
|
|
64712
|
+
};
|
|
64713
|
+
}
|
|
64714
|
+
function parseUrl(input) {
|
|
64715
|
+
if (isSchemeRelativeUrl(input)) {
|
|
64716
|
+
const url = parseAbsoluteUrl("http:" + input);
|
|
64717
|
+
url.scheme = "";
|
|
64718
|
+
url.type = 6;
|
|
64719
|
+
return url;
|
|
64720
|
+
}
|
|
64721
|
+
if (isAbsolutePath(input)) {
|
|
64722
|
+
const url = parseAbsoluteUrl("http://foo.com" + input);
|
|
64723
|
+
url.scheme = "";
|
|
64724
|
+
url.host = "";
|
|
64725
|
+
url.type = 5;
|
|
64726
|
+
return url;
|
|
64727
|
+
}
|
|
64728
|
+
if (isFileUrl(input)) return parseFileUrl(input);
|
|
64729
|
+
if (isAbsoluteUrl(input)) return parseAbsoluteUrl(input);
|
|
64730
|
+
const url = parseAbsoluteUrl("http://foo.com/" + input);
|
|
64731
|
+
url.scheme = "";
|
|
64732
|
+
url.host = "";
|
|
64733
|
+
url.type = input ? input.startsWith("?") ? 3 : input.startsWith("#") ? 2 : 4 : 1;
|
|
64734
|
+
return url;
|
|
64735
|
+
}
|
|
64736
|
+
function stripPathFilename(path) {
|
|
64737
|
+
if (path.endsWith("/..")) return path;
|
|
64738
|
+
const index = path.lastIndexOf("/");
|
|
64739
|
+
return path.slice(0, index + 1);
|
|
64740
|
+
}
|
|
64741
|
+
function mergePaths(url, base) {
|
|
64742
|
+
normalizePath(base, base.type);
|
|
64743
|
+
if (url.path === "/") url.path = base.path;
|
|
64744
|
+
else url.path = stripPathFilename(base.path) + url.path;
|
|
64745
|
+
}
|
|
64746
|
+
/**
|
|
64747
|
+
* The path can have empty directories "//", unneeded parents "foo/..", or current directory
|
|
64748
|
+
* "foo/.". We need to normalize to a standard representation.
|
|
64749
|
+
*/
|
|
64750
|
+
function normalizePath(url, type) {
|
|
64751
|
+
const rel = type <= 4;
|
|
64752
|
+
const pieces = url.path.split("/");
|
|
64753
|
+
let pointer = 1;
|
|
64754
|
+
let positive = 0;
|
|
64755
|
+
let addTrailingSlash = false;
|
|
64756
|
+
for (let i = 1; i < pieces.length; i++) {
|
|
64757
|
+
const piece = pieces[i];
|
|
64758
|
+
if (!piece) {
|
|
64759
|
+
addTrailingSlash = true;
|
|
64760
|
+
continue;
|
|
64761
|
+
}
|
|
64762
|
+
addTrailingSlash = false;
|
|
64763
|
+
if (piece === ".") continue;
|
|
64764
|
+
if (piece === "..") {
|
|
64765
|
+
if (positive) {
|
|
64766
|
+
addTrailingSlash = true;
|
|
64767
|
+
positive--;
|
|
64768
|
+
pointer--;
|
|
64769
|
+
} else if (rel) pieces[pointer++] = piece;
|
|
64770
|
+
continue;
|
|
64771
|
+
}
|
|
64772
|
+
pieces[pointer++] = piece;
|
|
64773
|
+
positive++;
|
|
64774
|
+
}
|
|
64775
|
+
let path = "";
|
|
64776
|
+
for (let i = 1; i < pointer; i++) path += "/" + pieces[i];
|
|
64777
|
+
if (!path || addTrailingSlash && !path.endsWith("/..")) path += "/";
|
|
64778
|
+
url.path = path;
|
|
64779
|
+
}
|
|
64780
|
+
/**
|
|
64781
|
+
* Attempts to resolve `input` URL/path relative to `base`.
|
|
64782
|
+
*/
|
|
64783
|
+
function resolve(input, base) {
|
|
64784
|
+
if (!input && !base) return "";
|
|
64785
|
+
const url = parseUrl(input);
|
|
64786
|
+
let inputType = url.type;
|
|
64787
|
+
if (base && inputType !== 7) {
|
|
64788
|
+
const baseUrl = parseUrl(base);
|
|
64789
|
+
const baseType = baseUrl.type;
|
|
64790
|
+
switch (inputType) {
|
|
64791
|
+
case 1: url.hash = baseUrl.hash;
|
|
64792
|
+
case 2: url.query = baseUrl.query;
|
|
64793
|
+
case 3:
|
|
64794
|
+
case 4: mergePaths(url, baseUrl);
|
|
64795
|
+
case 5:
|
|
64796
|
+
url.user = baseUrl.user;
|
|
64797
|
+
url.host = baseUrl.host;
|
|
64798
|
+
url.port = baseUrl.port;
|
|
64799
|
+
case 6: url.scheme = baseUrl.scheme;
|
|
64800
|
+
}
|
|
64801
|
+
if (baseType > inputType) inputType = baseType;
|
|
64802
|
+
}
|
|
64803
|
+
normalizePath(url, inputType);
|
|
64804
|
+
const queryHash = url.query + url.hash;
|
|
64805
|
+
switch (inputType) {
|
|
64806
|
+
case 2:
|
|
64807
|
+
case 3: return queryHash;
|
|
64808
|
+
case 4: {
|
|
64809
|
+
const path = url.path.slice(1);
|
|
64810
|
+
if (!path) return queryHash || ".";
|
|
64811
|
+
if (isRelative(base || input) && !isRelative(path)) return "./" + path + queryHash;
|
|
64812
|
+
return path + queryHash;
|
|
64813
|
+
}
|
|
64814
|
+
case 5: return url.path + queryHash;
|
|
64815
|
+
default: return url.scheme + "//" + url.user + url.host + url.port + url.path + queryHash;
|
|
64816
|
+
}
|
|
64817
|
+
}
|
|
64818
|
+
//#endregion
|
|
64819
|
+
//#region ../../node_modules/.pnpm/@jridgewell+trace-mapping@0.3.31/node_modules/@jridgewell/trace-mapping/dist/trace-mapping.mjs
|
|
64820
|
+
function stripFilename(path) {
|
|
64821
|
+
if (!path) return "";
|
|
64822
|
+
const index = path.lastIndexOf("/");
|
|
64823
|
+
return path.slice(0, index + 1);
|
|
64824
|
+
}
|
|
64825
|
+
function resolver(mapUrl, sourceRoot) {
|
|
64826
|
+
const from = stripFilename(mapUrl);
|
|
64827
|
+
const prefix = sourceRoot ? sourceRoot + "/" : "";
|
|
64828
|
+
return (source) => resolve(prefix + (source || ""), from);
|
|
64829
|
+
}
|
|
64830
|
+
var COLUMN = 0;
|
|
64831
|
+
var SOURCES_INDEX = 1;
|
|
64832
|
+
var SOURCE_LINE = 2;
|
|
64833
|
+
var SOURCE_COLUMN = 3;
|
|
64834
|
+
var NAMES_INDEX = 4;
|
|
64835
|
+
function maybeSort(mappings, owned) {
|
|
64836
|
+
const unsortedIndex = nextUnsortedSegmentLine(mappings, 0);
|
|
64837
|
+
if (unsortedIndex === mappings.length) return mappings;
|
|
64838
|
+
if (!owned) mappings = mappings.slice();
|
|
64839
|
+
for (let i = unsortedIndex; i < mappings.length; i = nextUnsortedSegmentLine(mappings, i + 1)) mappings[i] = sortSegments(mappings[i], owned);
|
|
64840
|
+
return mappings;
|
|
64841
|
+
}
|
|
64842
|
+
function nextUnsortedSegmentLine(mappings, start) {
|
|
64843
|
+
for (let i = start; i < mappings.length; i++) if (!isSorted(mappings[i])) return i;
|
|
64844
|
+
return mappings.length;
|
|
64845
|
+
}
|
|
64846
|
+
function isSorted(line) {
|
|
64847
|
+
for (let j = 1; j < line.length; j++) if (line[j][COLUMN] < line[j - 1][COLUMN]) return false;
|
|
64848
|
+
return true;
|
|
64849
|
+
}
|
|
64850
|
+
function sortSegments(line, owned) {
|
|
64851
|
+
if (!owned) line = line.slice();
|
|
64852
|
+
return line.sort(sortComparator);
|
|
64853
|
+
}
|
|
64854
|
+
function sortComparator(a, b) {
|
|
64855
|
+
return a[COLUMN] - b[COLUMN];
|
|
64856
|
+
}
|
|
64857
|
+
var found = false;
|
|
64858
|
+
function binarySearch(haystack, needle, low, high) {
|
|
64859
|
+
while (low <= high) {
|
|
64860
|
+
const mid = low + (high - low >> 1);
|
|
64861
|
+
const cmp = haystack[mid][COLUMN] - needle;
|
|
64862
|
+
if (cmp === 0) {
|
|
64863
|
+
found = true;
|
|
64864
|
+
return mid;
|
|
64865
|
+
}
|
|
64866
|
+
if (cmp < 0) low = mid + 1;
|
|
64867
|
+
else high = mid - 1;
|
|
64868
|
+
}
|
|
64869
|
+
found = false;
|
|
64870
|
+
return low - 1;
|
|
64871
|
+
}
|
|
64872
|
+
function upperBound(haystack, needle, index) {
|
|
64873
|
+
for (let i = index + 1; i < haystack.length; index = i++) if (haystack[i][COLUMN] !== needle) break;
|
|
64874
|
+
return index;
|
|
64875
|
+
}
|
|
64876
|
+
function lowerBound(haystack, needle, index) {
|
|
64877
|
+
for (let i = index - 1; i >= 0; index = i--) if (haystack[i][COLUMN] !== needle) break;
|
|
64878
|
+
return index;
|
|
64879
|
+
}
|
|
64880
|
+
function memoizedState() {
|
|
64881
|
+
return {
|
|
64882
|
+
lastKey: -1,
|
|
64883
|
+
lastNeedle: -1,
|
|
64884
|
+
lastIndex: -1
|
|
64885
|
+
};
|
|
64886
|
+
}
|
|
64887
|
+
function memoizedBinarySearch(haystack, needle, state, key) {
|
|
64888
|
+
const { lastKey, lastNeedle, lastIndex } = state;
|
|
64889
|
+
let low = 0;
|
|
64890
|
+
let high = haystack.length - 1;
|
|
64891
|
+
if (key === lastKey) {
|
|
64892
|
+
if (needle === lastNeedle) {
|
|
64893
|
+
found = lastIndex !== -1 && haystack[lastIndex][COLUMN] === needle;
|
|
64894
|
+
return lastIndex;
|
|
64895
|
+
}
|
|
64896
|
+
if (needle >= lastNeedle) low = lastIndex === -1 ? 0 : lastIndex;
|
|
64897
|
+
else high = lastIndex;
|
|
64898
|
+
}
|
|
64899
|
+
state.lastKey = key;
|
|
64900
|
+
state.lastNeedle = needle;
|
|
64901
|
+
return state.lastIndex = binarySearch(haystack, needle, low, high);
|
|
64902
|
+
}
|
|
64903
|
+
function parse(map) {
|
|
64904
|
+
return typeof map === "string" ? JSON.parse(map) : map;
|
|
64905
|
+
}
|
|
64906
|
+
var LINE_GTR_ZERO = "`line` must be greater than 0 (lines start at line 1)";
|
|
64907
|
+
var COL_GTR_EQ_ZERO = "`column` must be greater than or equal to 0 (columns start at column 0)";
|
|
64908
|
+
var TraceMap = class {
|
|
64909
|
+
constructor(map, mapUrl) {
|
|
64910
|
+
const isString = typeof map === "string";
|
|
64911
|
+
if (!isString && map._decodedMemo) return map;
|
|
64912
|
+
const parsed = parse(map);
|
|
64913
|
+
const { version, file, names, sourceRoot, sources, sourcesContent } = parsed;
|
|
64914
|
+
this.version = version;
|
|
64915
|
+
this.file = file;
|
|
64916
|
+
this.names = names || [];
|
|
64917
|
+
this.sourceRoot = sourceRoot;
|
|
64918
|
+
this.sources = sources;
|
|
64919
|
+
this.sourcesContent = sourcesContent;
|
|
64920
|
+
this.ignoreList = parsed.ignoreList || parsed.x_google_ignoreList || void 0;
|
|
64921
|
+
const resolve = resolver(mapUrl, sourceRoot);
|
|
64922
|
+
this.resolvedSources = sources.map(resolve);
|
|
64923
|
+
const { mappings } = parsed;
|
|
64924
|
+
if (typeof mappings === "string") {
|
|
64925
|
+
this._encoded = mappings;
|
|
64926
|
+
this._decoded = void 0;
|
|
64927
|
+
} else if (Array.isArray(mappings)) {
|
|
64928
|
+
this._encoded = void 0;
|
|
64929
|
+
this._decoded = maybeSort(mappings, isString);
|
|
64930
|
+
} else if (parsed.sections) throw new Error(`TraceMap passed sectioned source map, please use FlattenMap export instead`);
|
|
64931
|
+
else throw new Error(`invalid source map: ${JSON.stringify(parsed)}`);
|
|
64932
|
+
this._decodedMemo = memoizedState();
|
|
64933
|
+
this._bySources = void 0;
|
|
64934
|
+
this._bySourceMemos = void 0;
|
|
64935
|
+
}
|
|
64936
|
+
};
|
|
64937
|
+
function cast(map) {
|
|
64938
|
+
return map;
|
|
64939
|
+
}
|
|
64940
|
+
function decodedMappings(map) {
|
|
64941
|
+
var _a;
|
|
64942
|
+
return (_a = cast(map))._decoded || (_a._decoded = decode(cast(map)._encoded));
|
|
64943
|
+
}
|
|
64944
|
+
function originalPositionFor(map, needle) {
|
|
64945
|
+
let { line, column, bias } = needle;
|
|
64946
|
+
line--;
|
|
64947
|
+
if (line < 0) throw new Error(LINE_GTR_ZERO);
|
|
64948
|
+
if (column < 0) throw new Error(COL_GTR_EQ_ZERO);
|
|
64949
|
+
const decoded = decodedMappings(map);
|
|
64950
|
+
if (line >= decoded.length) return OMapping(null, null, null, null);
|
|
64951
|
+
const segments = decoded[line];
|
|
64952
|
+
const index = traceSegmentInternal(segments, cast(map)._decodedMemo, line, column, bias || 1);
|
|
64953
|
+
if (index === -1) return OMapping(null, null, null, null);
|
|
64954
|
+
const segment = segments[index];
|
|
64955
|
+
if (segment.length === 1) return OMapping(null, null, null, null);
|
|
64956
|
+
const { names, resolvedSources } = map;
|
|
64957
|
+
return OMapping(resolvedSources[segment[SOURCES_INDEX]], segment[SOURCE_LINE] + 1, segment[SOURCE_COLUMN], segment.length === 5 ? names[segment[NAMES_INDEX]] : null);
|
|
64958
|
+
}
|
|
64959
|
+
function OMapping(source, line, column, name) {
|
|
64960
|
+
return {
|
|
64961
|
+
source,
|
|
64962
|
+
line,
|
|
64963
|
+
column,
|
|
64964
|
+
name
|
|
64965
|
+
};
|
|
64966
|
+
}
|
|
64967
|
+
function traceSegmentInternal(segments, memo, line, column, bias) {
|
|
64968
|
+
let index = memoizedBinarySearch(segments, column, memo, line);
|
|
64969
|
+
if (found) index = (bias === -1 ? upperBound : lowerBound)(segments, column, index);
|
|
64970
|
+
else if (bias === -1) index++;
|
|
64971
|
+
if (index === -1 || index === segments.length) return -1;
|
|
64972
|
+
return index;
|
|
64973
|
+
}
|
|
64974
|
+
//#endregion
|
|
64552
64975
|
//#region ../core/dist/index.js
|
|
64553
64976
|
var __create = Object.create;
|
|
64554
64977
|
var __defProp = Object.defineProperty;
|
|
@@ -64618,7 +65041,7 @@ var AmbiguousProjectError = class extends Error {
|
|
|
64618
65041
|
};
|
|
64619
65042
|
const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
|
|
64620
65043
|
const HTML_FILE_PATTERN = /\.html$/i;
|
|
64621
|
-
const SOURCE_FILE_PATTERN = /\.(?:tsx?|jsx?|mts|mjs|[hH][tT][mM][lL])$/;
|
|
65044
|
+
const SOURCE_FILE_PATTERN = /\.(?:astro|tsx?|jsx?|mts|mjs|[hH][tT][mM][lL])$/;
|
|
64622
65045
|
const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
|
|
64623
65046
|
const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
|
|
64624
65047
|
const MINIFIED_SNIFF_BYTES = 65536;
|
|
@@ -65375,6 +65798,7 @@ const FRAMEWORK_PACKAGES = {
|
|
|
65375
65798
|
"@tanstack/react-start": "tanstack-start",
|
|
65376
65799
|
"@remix-run/react": "remix",
|
|
65377
65800
|
gatsby: "gatsby",
|
|
65801
|
+
astro: "astro",
|
|
65378
65802
|
vite: "vite",
|
|
65379
65803
|
"react-scripts": "cra",
|
|
65380
65804
|
expo: "expo",
|
|
@@ -68450,7 +68874,7 @@ const evaluateSuppression = (lines, diagnosticLineIndex, ruleId) => {
|
|
|
68450
68874
|
const getDiagnosticRuleIdentity = (diagnostic) => ({
|
|
68451
68875
|
ruleKey: `${diagnostic.plugin}/${diagnostic.rule}`,
|
|
68452
68876
|
category: diagnostic.category,
|
|
68453
|
-
tags: diagnostic.plugin === "react-doctor" ?
|
|
68877
|
+
tags: diagnostic.plugin === "react-doctor" ? REACT_DOCTOR_RULE_REGISTRY[diagnostic.rule]?.tags ?? [] : []
|
|
68454
68878
|
});
|
|
68455
68879
|
const compileIgnoredFilePatterns = (userConfig) => {
|
|
68456
68880
|
const files = userConfig?.ignore?.files;
|
|
@@ -68586,6 +69010,7 @@ const classifyPackageRole = (filename) => {
|
|
|
68586
69010
|
* Resolves the absolute path to read for a diagnostic's `filePath`,
|
|
68587
69011
|
* accounting for the various shapes oxlint emits:
|
|
68588
69012
|
*
|
|
69013
|
+
* - `file://` URL — decode to an absolute filesystem path.
|
|
68589
69014
|
* - Absolute POSIX (`/abs/path/file.tsx`) — pass through.
|
|
68590
69015
|
* - Absolute Windows (`C:/...` or `C:\...`) — pass through.
|
|
68591
69016
|
* - `./relative` or bare relative — join against `rootDirectory`.
|
|
@@ -68595,6 +69020,7 @@ const classifyPackageRole = (filename) => {
|
|
|
68595
69020
|
* use one canonical resolution path.
|
|
68596
69021
|
*/
|
|
68597
69022
|
const resolveCandidateReadPath = (rootDirectory, filePath) => {
|
|
69023
|
+
if (filePath.startsWith("file://")) return fileURLToPath(filePath);
|
|
68598
69024
|
const normalizedFile = filePath.replace(/\\/g, "/");
|
|
68599
69025
|
if (normalizedFile.startsWith("/") || /^[a-zA-Z]:\//.test(normalizedFile) || /^[a-zA-Z]:\\/.test(filePath)) return filePath;
|
|
68600
69026
|
return `${rootDirectory.replace(/\\/g, "/").replace(/\/$/, "")}/${normalizedFile.replace(/^\.\//, "")}`;
|
|
@@ -68796,7 +69222,7 @@ const buildDiagnosticPipeline = (input) => {
|
|
|
68796
69222
|
};
|
|
68797
69223
|
const shouldAutoSuppress = (diagnostic) => {
|
|
68798
69224
|
if (diagnostic.plugin !== "react-doctor") return false;
|
|
68799
|
-
const rule =
|
|
69225
|
+
const rule = REACT_DOCTOR_RULE_REGISTRY[diagnostic.rule];
|
|
68800
69226
|
if (!rule?.tags?.includes("test-noise")) return false;
|
|
68801
69227
|
if (rule.tags.includes("migration-hint")) return false;
|
|
68802
69228
|
return getFileContext(diagnostic.filePath) !== "production";
|
|
@@ -69228,6 +69654,7 @@ var OxlintConcurrency = class extends Reference("react-doctor/OxlintConcurrency"
|
|
|
69228
69654
|
if (Number.isInteger(parsed) && parsed > 0) return resolveScanConcurrency(parsed);
|
|
69229
69655
|
return resolveAutoScanConcurrency();
|
|
69230
69656
|
} }) {};
|
|
69657
|
+
var OxlintSpawnSlots = class extends Reference("react-doctor/OxlintSpawnSlots", { defaultValue: () => null }) {};
|
|
69231
69658
|
/**
|
|
69232
69659
|
* Three-state control for overlapping the dead-code pass with the lint pass —
|
|
69233
69660
|
* forking dead-code as a child fiber that runs DURING lint instead of strictly
|
|
@@ -71578,8 +72005,8 @@ const getCapabilities = (project) => {
|
|
|
71578
72005
|
const cached = capabilitiesByProject.get(project);
|
|
71579
72006
|
if (cached !== void 0) return cached;
|
|
71580
72007
|
const capabilities = new Set(buildCapabilities(project));
|
|
71581
|
-
const
|
|
71582
|
-
const targetBlankOpenerProtection = detectTargetBlankOpenerProtection(
|
|
72008
|
+
const capabilityRootDirectory = isFile(Path.join(project.rootDirectory, "package.json")) ? project.rootDirectory : findNearestAncestorPackageJson(project.rootDirectory) ?? project.rootDirectory;
|
|
72009
|
+
const targetBlankOpenerProtection = detectTargetBlankOpenerProtection(capabilityRootDirectory, readPackageJson$1(Path.join(capabilityRootDirectory, "package.json")));
|
|
71583
72010
|
if (targetBlankOpenerProtection !== void 0) capabilities.add("target-blank-needs-explicit-protection");
|
|
71584
72011
|
if (targetBlankOpenerProtection === "noreferrer") capabilities.add("target-blank-needs-noreferrer");
|
|
71585
72012
|
capabilitiesByProject.set(project, capabilities);
|
|
@@ -71609,7 +72036,7 @@ const createSecurityScanSession = (rootDirectory, options) => {
|
|
|
71609
72036
|
const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
|
|
71610
72037
|
const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
|
|
71611
72038
|
const includedTags = options.includedTags ?? /* @__PURE__ */ new Set();
|
|
71612
|
-
const enabledScanRules =
|
|
72039
|
+
const enabledScanRules = REACT_DOCTOR_SCAN_RULES.flatMap((entry) => {
|
|
71613
72040
|
const rule = entry.rule;
|
|
71614
72041
|
const scan = rule.scan;
|
|
71615
72042
|
if (typeof scan !== "function") return [];
|
|
@@ -72070,47 +72497,55 @@ const resolveDeadCodeConcurrency = (facts = readSystemFacts()) => {
|
|
|
72070
72497
|
const memoryBoundedWorkers = Math.floor(availableMemoryBytes / DEAD_CODE_WORKER_MEM_BUDGET_BYTES);
|
|
72071
72498
|
return Math.max(1, Math.min(facts.availableCores, memoryBoundedWorkers));
|
|
72072
72499
|
};
|
|
72073
|
-
|
|
72074
|
-
|
|
72075
|
-
const
|
|
72076
|
-
const
|
|
72077
|
-
|
|
72078
|
-
|
|
72500
|
+
const createWorkerSlots = (input) => {
|
|
72501
|
+
let availableSlotCount = input.slotCount;
|
|
72502
|
+
const waiters = [];
|
|
72503
|
+
const releaseSlot = () => {
|
|
72504
|
+
const nextWaiter = waiters.shift();
|
|
72505
|
+
if (nextWaiter === void 0) {
|
|
72506
|
+
availableSlotCount += 1;
|
|
72507
|
+
return;
|
|
72508
|
+
}
|
|
72509
|
+
nextWaiter.abortSignal?.removeEventListener("abort", nextWaiter.onAbort);
|
|
72510
|
+
nextWaiter.resolve();
|
|
72511
|
+
};
|
|
72512
|
+
const acquireSlot = async (abortSignal) => {
|
|
72513
|
+
if (abortSignal?.aborted) throw input.createAbortError();
|
|
72514
|
+
if (availableSlotCount > 0) {
|
|
72515
|
+
availableSlotCount -= 1;
|
|
72516
|
+
return;
|
|
72517
|
+
}
|
|
72518
|
+
await new Promise((resolve, reject) => {
|
|
72519
|
+
const onAbort = () => {
|
|
72520
|
+
const waiterIndex = waiters.indexOf(waiter);
|
|
72521
|
+
if (waiterIndex !== -1) waiters.splice(waiterIndex, 1);
|
|
72522
|
+
reject(input.createAbortError());
|
|
72523
|
+
};
|
|
72524
|
+
const waiter = {
|
|
72525
|
+
resolve,
|
|
72526
|
+
abortSignal,
|
|
72527
|
+
onAbort
|
|
72528
|
+
};
|
|
72529
|
+
waiters.push(waiter);
|
|
72530
|
+
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
72531
|
+
});
|
|
72532
|
+
};
|
|
72533
|
+
return { run: async (task, abortSignal) => {
|
|
72534
|
+
await acquireSlot(abortSignal);
|
|
72535
|
+
try {
|
|
72536
|
+
return await task();
|
|
72537
|
+
} finally {
|
|
72538
|
+
releaseSlot();
|
|
72539
|
+
}
|
|
72540
|
+
} };
|
|
72079
72541
|
};
|
|
72080
|
-
|
|
72081
|
-
* Runs `task` once a dead-code worker slot is free, releasing the slot when the
|
|
72082
|
-
* task settles (success or failure). With a high cap (roomy machine) every
|
|
72083
|
-
* caller proceeds immediately; with a low cap (constrained runner) callers
|
|
72084
|
-
* queue and run as slots free.
|
|
72085
|
-
*
|
|
72086
|
-
* `abortSignal` short-circuits the WAIT: if it's already aborted, or fires while
|
|
72087
|
-
* this caller is queued, the call rejects without acquiring a slot or running
|
|
72088
|
-
* `task` — so a cancelled scan (e.g. lint failed) doesn't sit in the queue and
|
|
72089
|
-
* then spawn a child only to tear it down. A queued caller that aborts removes
|
|
72090
|
-
* its own waiter so a later release never hands a slot to a dead request.
|
|
72091
|
-
*/
|
|
72542
|
+
let deadCodeWorkerSlots = null;
|
|
72092
72543
|
const withDeadCodeWorkerSlot = async (task, abortSignal) => {
|
|
72093
|
-
|
|
72094
|
-
|
|
72095
|
-
|
|
72096
|
-
else await new Promise((resolve, reject) => {
|
|
72097
|
-
const waiter = () => {
|
|
72098
|
-
abortSignal?.removeEventListener("abort", onAbort);
|
|
72099
|
-
resolve();
|
|
72100
|
-
};
|
|
72101
|
-
const onAbort = () => {
|
|
72102
|
-
const queuedIndex = waiters.indexOf(waiter);
|
|
72103
|
-
if (queuedIndex !== -1) waiters.splice(queuedIndex, 1);
|
|
72104
|
-
reject(/* @__PURE__ */ new Error("Dead-code worker aborted."));
|
|
72105
|
-
};
|
|
72106
|
-
waiters.push(waiter);
|
|
72107
|
-
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
72544
|
+
deadCodeWorkerSlots ??= createWorkerSlots({
|
|
72545
|
+
slotCount: resolveDeadCodeConcurrency(),
|
|
72546
|
+
createAbortError: () => /* @__PURE__ */ new Error("Dead-code worker aborted.")
|
|
72108
72547
|
});
|
|
72109
|
-
|
|
72110
|
-
return await task();
|
|
72111
|
-
} finally {
|
|
72112
|
-
releaseSlot();
|
|
72113
|
-
}
|
|
72548
|
+
return deadCodeWorkerSlots.run(task, abortSignal);
|
|
72114
72549
|
};
|
|
72115
72550
|
const projectCacheSubdir = (projectDirectory) => crypto.createHash("sha256").update(projectDirectory).digest("hex").slice(0, 16);
|
|
72116
72551
|
const resolveReactDoctorCacheDir = (projectDirectory) => {
|
|
@@ -72903,7 +73338,10 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
72903
73338
|
if (argvLengthChars > spawnArgsLengthCap) return yield* foldSpawnFailure(`spawn ENAMETOOLONG (${argvLengthChars} argv chars exceed ${spawnArgsLengthCap})`);
|
|
72904
73339
|
const handle = yield* spawner.spawn(make$1(input.command, [...input.args], {
|
|
72905
73340
|
cwd: input.directory,
|
|
72906
|
-
env: input.
|
|
73341
|
+
env: input.command === "git" ? {
|
|
73342
|
+
...input.env,
|
|
73343
|
+
GIT_DIR: void 0
|
|
73344
|
+
} : input.env,
|
|
72907
73345
|
extendEnv: true
|
|
72908
73346
|
}));
|
|
72909
73347
|
const maxStdoutBytes = input.maxStdoutBytes;
|
|
@@ -73176,7 +73614,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
73176
73614
|
"--diff-filter=ACMR",
|
|
73177
73615
|
"--relative"
|
|
73178
73616
|
]).pipe(map$3((result) => {
|
|
73179
|
-
if (result.status !== 0) return
|
|
73617
|
+
if (result.status !== 0) return null;
|
|
73180
73618
|
return splitNullSeparated(result.stdout);
|
|
73181
73619
|
})),
|
|
73182
73620
|
showStagedContent: (directory, relativePath, options) => runCommand({
|
|
@@ -73634,12 +74072,12 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
73634
74072
|
const settingsRootDirectory = resolveSettingsRootDirectory(project.rootDirectory);
|
|
73635
74073
|
const enabledReactDoctorRules = {};
|
|
73636
74074
|
for (const registryEntry of REACT_DOCTOR_RULES) {
|
|
73637
|
-
const rule =
|
|
74075
|
+
const rule = REACT_DOCTOR_RULE_REGISTRY[registryEntry.id];
|
|
73638
74076
|
if (!rule) continue;
|
|
73639
74077
|
if (ruleSelection === "cacheable" && CROSS_FILE_RULE_IDS.has(registryEntry.id)) continue;
|
|
73640
74078
|
if (ruleSelection === "sidecar" && !CROSS_FILE_RULE_IDS.has(registryEntry.id)) continue;
|
|
73641
74079
|
if (ruleSelection === "sidecar" && sidecarRuleIdFilter !== void 0 && !sidecarRuleIdFilter.has(registryEntry.id)) continue;
|
|
73642
|
-
if (rule.
|
|
74080
|
+
if (rule.isScanRule) continue;
|
|
73643
74081
|
if (customRulesOnly && registryEntry.originallyExternal) continue;
|
|
73644
74082
|
if (rule.framework !== "global" && !rule.requires) continue;
|
|
73645
74083
|
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) continue;
|
|
@@ -74264,6 +74702,50 @@ const columnOfUtf8Offset = (sourceBuffer, utf8Offset) => {
|
|
|
74264
74702
|
while (lineStartOffset > 0 && sourceBuffer[lineStartOffset - 1] !== 10) lineStartOffset--;
|
|
74265
74703
|
return sourceBuffer.subarray(lineStartOffset, boundedOffset).toString("utf8").length + 1;
|
|
74266
74704
|
};
|
|
74705
|
+
const utf8OffsetFromSourcePosition = (sourceBuffer, lineNumber, zeroBasedColumn) => {
|
|
74706
|
+
if (lineNumber < 1 || zeroBasedColumn < 0) return null;
|
|
74707
|
+
const sourceLines = sourceBuffer.toString("utf8").split("\n");
|
|
74708
|
+
const sourceLine = sourceLines[lineNumber - 1];
|
|
74709
|
+
if (sourceLine === void 0 || zeroBasedColumn > sourceLine.length) return null;
|
|
74710
|
+
const precedingLines = sourceLines.slice(0, lineNumber - 1).join("\n");
|
|
74711
|
+
return (lineNumber === 1 ? 0 : Buffer.byteLength(precedingLines) + Buffer.byteLength("\n")) + Buffer.byteLength(sourceLine.slice(0, zeroBasedColumn));
|
|
74712
|
+
};
|
|
74713
|
+
const mapPreparedSourceSpan = (span, preparedSourceMap) => {
|
|
74714
|
+
const generatedLine = lineOfUtf8Offset(preparedSourceMap.generatedBuffer, span.offset);
|
|
74715
|
+
const generatedColumn = columnOfUtf8Offset(preparedSourceMap.generatedBuffer, span.offset) - 1;
|
|
74716
|
+
const originalStart = originalPositionFor(preparedSourceMap.traceMap, {
|
|
74717
|
+
line: generatedLine,
|
|
74718
|
+
column: generatedColumn
|
|
74719
|
+
});
|
|
74720
|
+
if (originalStart.source === null || originalStart.line === null || originalStart.column === null) return null;
|
|
74721
|
+
const originalOffset = utf8OffsetFromSourcePosition(preparedSourceMap.sourceBuffer, originalStart.line, originalStart.column);
|
|
74722
|
+
if (originalOffset === null) return null;
|
|
74723
|
+
const generatedSpan = preparedSourceMap.generatedBuffer.subarray(span.offset, span.offset + span.length);
|
|
74724
|
+
return {
|
|
74725
|
+
offset: originalOffset,
|
|
74726
|
+
length: preparedSourceMap.sourceBuffer.subarray(originalOffset, originalOffset + generatedSpan.length).equals(generatedSpan) ? generatedSpan.length : 0,
|
|
74727
|
+
line: originalStart.line,
|
|
74728
|
+
column: originalStart.column + 1
|
|
74729
|
+
};
|
|
74730
|
+
};
|
|
74731
|
+
const mapPreparedSourceLabels = (labels, preparedSourceMap) => {
|
|
74732
|
+
const primaryLabel = labels[0];
|
|
74733
|
+
if (primaryLabel === void 0) return null;
|
|
74734
|
+
const primarySpan = mapPreparedSourceSpan(primaryLabel.span, preparedSourceMap);
|
|
74735
|
+
if (primarySpan === null) return null;
|
|
74736
|
+
const mappedLabels = [{
|
|
74737
|
+
...primaryLabel,
|
|
74738
|
+
span: primarySpan
|
|
74739
|
+
}];
|
|
74740
|
+
for (const relatedLabel of labels.slice(1)) {
|
|
74741
|
+
const relatedSpan = mapPreparedSourceSpan(relatedLabel.span, preparedSourceMap);
|
|
74742
|
+
if (relatedSpan !== null) mappedLabels.push({
|
|
74743
|
+
...relatedLabel,
|
|
74744
|
+
span: relatedSpan
|
|
74745
|
+
});
|
|
74746
|
+
}
|
|
74747
|
+
return mappedLabels;
|
|
74748
|
+
};
|
|
74267
74749
|
const REDACTED_PLACEHOLDER = "<redacted>";
|
|
74268
74750
|
const KEEP_PREFIX = `$1${REDACTED_PLACEHOLDER}`;
|
|
74269
74751
|
const KNOWN_SECRET_RULES = [
|
|
@@ -74906,7 +75388,7 @@ const PLUGIN_CATEGORY_MAP = {
|
|
|
74906
75388
|
};
|
|
74907
75389
|
const lookupOwnString = (record, key) => Object.hasOwn(record, key) ? record[key] : void 0;
|
|
74908
75390
|
const getRuleRecommendation = (ruleName, project) => {
|
|
74909
|
-
const rule =
|
|
75391
|
+
const rule = REACT_DOCTOR_RULE_REGISTRY[ruleName];
|
|
74910
75392
|
if (!rule) return void 0;
|
|
74911
75393
|
if (rule.recommendationFor) {
|
|
74912
75394
|
const capabilities = getCapabilities(project);
|
|
@@ -74915,8 +75397,8 @@ const getRuleRecommendation = (ruleName, project) => {
|
|
|
74915
75397
|
}
|
|
74916
75398
|
return rule.recommendation;
|
|
74917
75399
|
};
|
|
74918
|
-
const getRuleCategory = (ruleName) =>
|
|
74919
|
-
const getRuleTitle = (ruleName) =>
|
|
75400
|
+
const getRuleCategory = (ruleName) => REACT_DOCTOR_RULE_REGISTRY[ruleName]?.category;
|
|
75401
|
+
const getRuleTitle = (ruleName) => REACT_DOCTOR_RULE_REGISTRY[ruleName]?.title;
|
|
74920
75402
|
const resolveDiagnosticTitle = (plugin, rule) => {
|
|
74921
75403
|
if (plugin !== "react-hooks-js") return getRuleTitle(rule);
|
|
74922
75404
|
if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
|
|
@@ -74971,7 +75453,7 @@ const resolveDiagnosticCategory = (plugin, rule) => {
|
|
|
74971
75453
|
if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
|
|
74972
75454
|
return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
|
|
74973
75455
|
};
|
|
74974
|
-
const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(
|
|
75456
|
+
const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(REACT_DOCTOR_RULE_REGISTRY[rule]?.matchByOccurrence);
|
|
74975
75457
|
/**
|
|
74976
75458
|
* Maps oxlint's non-primary labels (`labels[1..]`) into related source
|
|
74977
75459
|
* locations. Editors surface these as a diagnostic's
|
|
@@ -75008,7 +75490,7 @@ const isOxlintOutput = (value) => isRecord$1(value) && Array.isArray(value.diagn
|
|
|
75008
75490
|
* to the first `{`. Raises `OxlintOutputUnparseable` when the
|
|
75009
75491
|
* stdout isn't valid JSON or doesn't carry a `diagnostics` array.
|
|
75010
75492
|
*/
|
|
75011
|
-
const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath) => {
|
|
75493
|
+
const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath, sourceMapByLintPath) => {
|
|
75012
75494
|
if (!stdout) return [];
|
|
75013
75495
|
const jsonStart = stdout.indexOf("{");
|
|
75014
75496
|
const sanitizedStdout = jsonStart > 0 ? stdout.slice(jsonStart) : stdout;
|
|
@@ -75026,6 +75508,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath)
|
|
|
75026
75508
|
const sourceLinesCache = /* @__PURE__ */ new Map();
|
|
75027
75509
|
const resolveAbsolutePath = (filename) => Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
|
|
75028
75510
|
const resolveMappedSourceFilename = (filename) => sourcePathByLintPath?.get(Path.normalize(resolveAbsolutePath(filename)));
|
|
75511
|
+
const resolvePreparedSourceMap = (filename) => sourceMapByLintPath?.get(Path.normalize(resolveAbsolutePath(filename)));
|
|
75029
75512
|
const resolveSourceFilename = (filename) => resolveMappedSourceFilename(filename) ?? filename;
|
|
75030
75513
|
const readSourceBuffer = (filename) => {
|
|
75031
75514
|
const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
|
|
@@ -75057,7 +75540,19 @@ const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath)
|
|
|
75057
75540
|
minifiedFileCache.set(absolutePath, minified);
|
|
75058
75541
|
return minified;
|
|
75059
75542
|
};
|
|
75060
|
-
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.
|
|
75543
|
+
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.flatMap((diagnostic) => {
|
|
75544
|
+
const preparedSourceMap = resolvePreparedSourceMap(diagnostic.filename);
|
|
75545
|
+
if (preparedSourceMap === void 0) return [diagnostic];
|
|
75546
|
+
const { plugin, rule } = parseRuleCode(diagnostic.code);
|
|
75547
|
+
if (plugin !== "react-doctor" || !REACT_DOCTOR_RULE_REGISTRY[rule]?.tags?.includes("design")) return [];
|
|
75548
|
+
const labels = mapPreparedSourceLabels(diagnostic.labels, preparedSourceMap);
|
|
75549
|
+
const sourceFilename = resolveMappedSourceFilename(diagnostic.filename);
|
|
75550
|
+
return labels === null || sourceFilename === void 0 ? [] : [{
|
|
75551
|
+
...diagnostic,
|
|
75552
|
+
filename: sourceFilename,
|
|
75553
|
+
labels
|
|
75554
|
+
}];
|
|
75555
|
+
}).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) => {
|
|
75061
75556
|
const { plugin, rule } = parseRuleCode(diagnostic.code);
|
|
75062
75557
|
const primaryLabel = diagnostic.labels[0];
|
|
75063
75558
|
const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
|
|
@@ -75135,11 +75630,12 @@ const SANITIZED_ENV = buildOxlintChildEnv(process.env);
|
|
|
75135
75630
|
* The first three are splittable (the caller's binary-split retry
|
|
75136
75631
|
* shrinks the batch and re-spawns); the fourth isn't.
|
|
75137
75632
|
*/
|
|
75138
|
-
const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLINT_SPAWN_TIMEOUT_MS, outputMaxBytes = OXLINT_OUTPUT_MAX_BYTES, abortSignal) => new Promise((resolve, reject) => {
|
|
75633
|
+
const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLINT_SPAWN_TIMEOUT_MS, outputMaxBytes = OXLINT_OUTPUT_MAX_BYTES, abortSignal, onSpawn) => new Promise((resolve, reject) => {
|
|
75139
75634
|
if (abortSignal?.aborted) {
|
|
75140
75635
|
reject(new ReactDoctorError({ reason: new OxlintSpawnFailed({ cause: "lint phase aborted" }) }));
|
|
75141
75636
|
return;
|
|
75142
75637
|
}
|
|
75638
|
+
onSpawn?.();
|
|
75143
75639
|
const child = spawn(nodeBinaryPath, buildProfiledNodeArguments({
|
|
75144
75640
|
argumentsList: args,
|
|
75145
75641
|
cpuProfileDirectory: SANITIZED_ENV.REACT_DOCTOR_CPU_PROFILE_DIR,
|
|
@@ -75275,7 +75771,7 @@ const isParallelismRelatedSpawnError = (error) => {
|
|
|
75275
75771
|
* loop with a slimmer config in that case.
|
|
75276
75772
|
*/
|
|
75277
75773
|
const spawnLintBatches = async (input) => {
|
|
75278
|
-
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
|
|
75774
|
+
const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, sourceMapByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
|
|
75279
75775
|
const resolveSourcePath = (filePath) => {
|
|
75280
75776
|
const absoluteFilePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory, filePath);
|
|
75281
75777
|
return sourcePathByLintPath?.get(Path.normalize(absoluteFilePath)) ?? filePath;
|
|
@@ -75299,7 +75795,21 @@ const spawnLintBatches = async (input) => {
|
|
|
75299
75795
|
}
|
|
75300
75796
|
const batchArgs = [...baseArgs, ...batch];
|
|
75301
75797
|
try {
|
|
75302
|
-
|
|
75798
|
+
const spawnBatch = () => {
|
|
75799
|
+
if (isPastDeadline()) {
|
|
75800
|
+
deadlineSkippedFiles.push(...batch);
|
|
75801
|
+
batchState.deadlineSkippedFileCount += batch.length;
|
|
75802
|
+
return Promise.resolve(null);
|
|
75803
|
+
}
|
|
75804
|
+
return spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal, () => {
|
|
75805
|
+
if (batchState.didStart) return;
|
|
75806
|
+
batchState.didStart = true;
|
|
75807
|
+
startedFileCount += batchState.initialFileCount;
|
|
75808
|
+
});
|
|
75809
|
+
};
|
|
75810
|
+
const stdout = input.spawnSlots === void 0 ? await spawnBatch() : await input.spawnSlots.run(spawnBatch, signal);
|
|
75811
|
+
if (stdout === null) return [];
|
|
75812
|
+
return parseOxlintOutput(stdout, project, rootDirectory, sourcePathByLintPath, sourceMapByLintPath);
|
|
75303
75813
|
} catch (error) {
|
|
75304
75814
|
if (!isSplittableReactDoctorError(error)) throw error;
|
|
75305
75815
|
if (isPastDeadline()) {
|
|
@@ -75343,14 +75853,15 @@ const spawnLintBatches = async (input) => {
|
|
|
75343
75853
|
deadlineSkippedFiles.push(...batch);
|
|
75344
75854
|
return [];
|
|
75345
75855
|
}
|
|
75346
|
-
startedFileCount += batch.length;
|
|
75347
75856
|
const batchState = {
|
|
75348
75857
|
deadlineMs: null,
|
|
75349
|
-
deadlineSkippedFileCount: 0
|
|
75858
|
+
deadlineSkippedFileCount: 0,
|
|
75859
|
+
didStart: false,
|
|
75860
|
+
initialFileCount: batch.length
|
|
75350
75861
|
};
|
|
75351
75862
|
const batchDiagnostics = await spawnLintBatch(batch, 0, batchState);
|
|
75352
75863
|
scannedFileCount += batch.length - batchState.deadlineSkippedFileCount;
|
|
75353
|
-
if (passOnFileProgress) {
|
|
75864
|
+
if (passOnFileProgress && batchState.didStart) {
|
|
75354
75865
|
displayedFileCount = Math.min(Math.max(displayedFileCount, scannedFileCount), totalFileCount);
|
|
75355
75866
|
passOnFileProgress(displayedFileCount, totalFileCount);
|
|
75356
75867
|
}
|
|
@@ -75434,8 +75945,8 @@ const validateRuleRegistration = () => {
|
|
|
75434
75945
|
for (const fullKey of ALL_REACT_DOCTOR_RULE_KEYS) {
|
|
75435
75946
|
const ruleName = fullKey.replace(/^react-doctor\//, "");
|
|
75436
75947
|
if (!getRuleCategory(ruleName)) missingCategory.push(fullKey);
|
|
75437
|
-
if (!
|
|
75438
|
-
if (FRAMEWORK_SPECIFIC_RULE_KEYS.has(fullKey) && !
|
|
75948
|
+
if (!REACT_DOCTOR_RULE_REGISTRY[ruleName]?.recommendation) missingHelp.push(fullKey);
|
|
75949
|
+
if (FRAMEWORK_SPECIFIC_RULE_KEYS.has(fullKey) && !REACT_DOCTOR_RULE_REGISTRY[ruleName]?.requires) missingMetadata.push(fullKey);
|
|
75439
75950
|
}
|
|
75440
75951
|
if (missingCategory.length === 0 && missingHelp.length === 0 && missingMetadata.length === 0) return;
|
|
75441
75952
|
const detail = [
|
|
@@ -75738,20 +76249,47 @@ const prepareHtmlScriptSource = (sourceBuffer) => {
|
|
|
75738
76249
|
lintBuffer: maskedBuffer ?? sourceBuffer
|
|
75739
76250
|
};
|
|
75740
76251
|
};
|
|
75741
|
-
const
|
|
76252
|
+
const ASTRO_FILE_PATTERN = /\.astro$/;
|
|
76253
|
+
const prepareLintSources = (rootDirectory, temporaryDirectory, candidateFiles) => {
|
|
75742
76254
|
const lintFiles = [];
|
|
75743
76255
|
const sourcePathByLintPath = /* @__PURE__ */ new Map();
|
|
76256
|
+
const sourceMapByLintPath = /* @__PURE__ */ new Map();
|
|
75744
76257
|
const sizeByLintPath = /* @__PURE__ */ new Map();
|
|
75745
76258
|
const htmlSourcesDirectory = Path.join(temporaryDirectory, "html-sources");
|
|
76259
|
+
const astroSourcesDirectory = Path.join(temporaryDirectory, "astro-sources");
|
|
75746
76260
|
let htmlFileIndex = 0;
|
|
76261
|
+
let astroFileIndex = 0;
|
|
75747
76262
|
let hasThreeModuleImport = false;
|
|
75748
76263
|
for (const candidateFile of candidateFiles) {
|
|
75749
|
-
if (!HTML_FILE_PATTERN.test(candidateFile)) {
|
|
76264
|
+
if (!HTML_FILE_PATTERN.test(candidateFile) && !ASTRO_FILE_PATTERN.test(candidateFile)) {
|
|
75750
76265
|
lintFiles.push(candidateFile);
|
|
75751
76266
|
continue;
|
|
75752
76267
|
}
|
|
75753
76268
|
const absoluteSourcePath = Path.isAbsolute(candidateFile) ? candidateFile : Path.resolve(rootDirectory, candidateFile);
|
|
75754
76269
|
const sourceBuffer = NFS.readFileSync(absoluteSourcePath);
|
|
76270
|
+
if (ASTRO_FILE_PATTERN.test(candidateFile)) {
|
|
76271
|
+
const compilerSourcePath = absoluteSourcePath.replaceAll("\\", "/");
|
|
76272
|
+
const convertedSource = convertToTSX(sourceBuffer.toString("utf8"), {
|
|
76273
|
+
filename: compilerSourcePath,
|
|
76274
|
+
sourcemap: "external",
|
|
76275
|
+
includeScripts: true
|
|
76276
|
+
});
|
|
76277
|
+
if (astroFileIndex === 0) NFS.mkdirSync(astroSourcesDirectory, { recursive: true });
|
|
76278
|
+
const lintPath = Path.join(astroSourcesDirectory, `${astroFileIndex}.tsx`);
|
|
76279
|
+
const generatedBuffer = Buffer.from(convertedSource.code);
|
|
76280
|
+
NFS.writeFileSync(lintPath, generatedBuffer);
|
|
76281
|
+
lintFiles.push(candidateFile);
|
|
76282
|
+
lintFiles.push(lintPath);
|
|
76283
|
+
sourcePathByLintPath.set(Path.resolve(lintPath), candidateFile);
|
|
76284
|
+
sourceMapByLintPath.set(Path.resolve(lintPath), {
|
|
76285
|
+
traceMap: new TraceMap(JSON.stringify(convertedSource.map)),
|
|
76286
|
+
generatedBuffer,
|
|
76287
|
+
sourceBuffer
|
|
76288
|
+
});
|
|
76289
|
+
sizeByLintPath.set(lintPath, sourceBuffer.length);
|
|
76290
|
+
astroFileIndex++;
|
|
76291
|
+
continue;
|
|
76292
|
+
}
|
|
75755
76293
|
const { executableScriptBodies, lintBuffer } = prepareHtmlScriptSource(sourceBuffer);
|
|
75756
76294
|
if (htmlFileIndex === 0) NFS.mkdirSync(htmlSourcesDirectory, { recursive: true });
|
|
75757
76295
|
const lintPath = Path.join(htmlSourcesDirectory, `${htmlFileIndex}.astro`);
|
|
@@ -75765,6 +76303,7 @@ const prepareHtmlLintSources = (rootDirectory, temporaryDirectory, candidateFile
|
|
|
75765
76303
|
return {
|
|
75766
76304
|
lintFiles,
|
|
75767
76305
|
sourcePathByLintPath,
|
|
76306
|
+
sourceMapByLintPath,
|
|
75768
76307
|
sizeByLintPath,
|
|
75769
76308
|
hasThreeModuleImport
|
|
75770
76309
|
};
|
|
@@ -75983,10 +76522,10 @@ const runOxlint = async (options) => {
|
|
|
75983
76522
|
rootDirectory,
|
|
75984
76523
|
candidateFiles
|
|
75985
76524
|
});
|
|
75986
|
-
const
|
|
75987
|
-
const lintFiles =
|
|
75988
|
-
const
|
|
75989
|
-
const lintProject = !project.hasThree &&
|
|
76525
|
+
const preparedLintSources = prepareLintSources(rootDirectory, configDirectory, candidateFiles);
|
|
76526
|
+
const lintFiles = preparedLintSources.lintFiles;
|
|
76527
|
+
const hasPreparedFiles = preparedLintSources.sourcePathByLintPath.size > 0;
|
|
76528
|
+
const lintProject = !project.hasThree && preparedLintSources.hasThreeModuleImport ? {
|
|
75990
76529
|
...project,
|
|
75991
76530
|
hasThree: true
|
|
75992
76531
|
} : project;
|
|
@@ -76008,7 +76547,7 @@ const runOxlint = async (options) => {
|
|
|
76008
76547
|
sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
|
|
76009
76548
|
});
|
|
76010
76549
|
const sizeByFile = sizedScanFiles !== null && lintBatchOrdering === "cost" ? new Map(sizedScanFiles.map((entry) => [entry.path, entry.sizeBytes])) : null;
|
|
76011
|
-
if (sizeByFile !== null) for (const [lintPath, sizeBytes] of
|
|
76550
|
+
if (sizeByFile !== null) for (const [lintPath, sizeBytes] of preparedLintSources.sizeByLintPath) sizeByFile.set(lintPath, sizeBytes);
|
|
76012
76551
|
const buildFileBatches = (passBaseArgs, passFiles) => sizeByFile !== null ? planLintBatches({
|
|
76013
76552
|
baseArgs: passBaseArgs,
|
|
76014
76553
|
files: passFiles,
|
|
@@ -76038,7 +76577,8 @@ const runOxlint = async (options) => {
|
|
|
76038
76577
|
rootDirectory,
|
|
76039
76578
|
nodeBinaryPath,
|
|
76040
76579
|
project: lintProject,
|
|
76041
|
-
sourcePathByLintPath:
|
|
76580
|
+
sourcePathByLintPath: preparedLintSources.sourcePathByLintPath,
|
|
76581
|
+
sourceMapByLintPath: preparedLintSources.sourceMapByLintPath,
|
|
76042
76582
|
onPartialFailure: reportPartialFailure,
|
|
76043
76583
|
onAnalyzedFiles: (filePaths) => {
|
|
76044
76584
|
analyzedFiles = filePaths;
|
|
@@ -76047,6 +76587,7 @@ const runOxlint = async (options) => {
|
|
|
76047
76587
|
spawnTimeoutMs,
|
|
76048
76588
|
outputMaxBytes,
|
|
76049
76589
|
concurrency: options.concurrency,
|
|
76590
|
+
spawnSlots: options.spawnSlots,
|
|
76050
76591
|
signal: options.signal,
|
|
76051
76592
|
deadlineEpochMs: options.deadlineEpochMs
|
|
76052
76593
|
});
|
|
@@ -76073,7 +76614,7 @@ const runOxlint = async (options) => {
|
|
|
76073
76614
|
};
|
|
76074
76615
|
}
|
|
76075
76616
|
};
|
|
76076
|
-
if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0 && !
|
|
76617
|
+
if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0 && !hasPreparedFiles) {
|
|
76077
76618
|
const rulesetHash = computeRulesetHash({
|
|
76078
76619
|
config: buildConfig({
|
|
76079
76620
|
extendsPaths: [],
|
|
@@ -76239,7 +76780,8 @@ const runOxlint = async (options) => {
|
|
|
76239
76780
|
rootDirectory,
|
|
76240
76781
|
nodeBinaryPath,
|
|
76241
76782
|
project: lintProject,
|
|
76242
|
-
sourcePathByLintPath:
|
|
76783
|
+
sourcePathByLintPath: preparedLintSources.sourcePathByLintPath,
|
|
76784
|
+
sourceMapByLintPath: preparedLintSources.sourceMapByLintPath,
|
|
76243
76785
|
onPartialFailure,
|
|
76244
76786
|
onAnalyzedFiles: (filePaths) => {
|
|
76245
76787
|
analyzedFiles = filePaths;
|
|
@@ -76248,6 +76790,7 @@ const runOxlint = async (options) => {
|
|
|
76248
76790
|
spawnTimeoutMs,
|
|
76249
76791
|
outputMaxBytes,
|
|
76250
76792
|
concurrency: options.concurrency,
|
|
76793
|
+
spawnSlots: options.spawnSlots,
|
|
76251
76794
|
signal: options.signal,
|
|
76252
76795
|
deadlineEpochMs: options.deadlineEpochMs
|
|
76253
76796
|
});
|
|
@@ -76342,6 +76885,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
76342
76885
|
const spawnTimeoutMs = yield* OxlintSpawnTimeoutMs;
|
|
76343
76886
|
const outputMaxBytes = yield* OxlintOutputMaxBytes;
|
|
76344
76887
|
const concurrency = yield* OxlintConcurrency;
|
|
76888
|
+
const spawnSlots = yield* OxlintSpawnSlots;
|
|
76345
76889
|
const lintBatchOrdering = yield* LintBatchOrdering;
|
|
76346
76890
|
const perFileLintCacheEnabled = yield* PerFileLintCacheEnabled;
|
|
76347
76891
|
const sidecarLintCacheEnabled = yield* SidecarLintCacheEnabled;
|
|
@@ -76371,6 +76915,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
76371
76915
|
onSidecarStats: input.onSidecarStats,
|
|
76372
76916
|
spawnTimeoutMs,
|
|
76373
76917
|
outputMaxBytes,
|
|
76918
|
+
spawnSlots: spawnSlots ?? void 0,
|
|
76374
76919
|
concurrency,
|
|
76375
76920
|
signal,
|
|
76376
76921
|
lintBatchOrdering,
|
|
@@ -77599,10 +78144,14 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
77599
78144
|
materializedFiles.push(relativePath);
|
|
77600
78145
|
}
|
|
77601
78146
|
yield* sync(() => {
|
|
77602
|
-
for (const configFilename of STAGED_FILES_PROJECT_CONFIG_FILENAMES) {
|
|
77603
|
-
const sourcePath = path.join(input.directory, configFilename);
|
|
77604
|
-
const targetPath = path.
|
|
77605
|
-
if (
|
|
78147
|
+
for (const subdirectory of ["", ...input.configSubdirectories ?? []]) for (const configFilename of STAGED_FILES_PROJECT_CONFIG_FILENAMES) {
|
|
78148
|
+
const sourcePath = path.join(input.directory, subdirectory, configFilename);
|
|
78149
|
+
const targetPath = path.resolve(resolvedTempDirectory, subdirectory, configFilename);
|
|
78150
|
+
if (!isPathInsideDirectory(targetPath, resolvedTempDirectory)) continue;
|
|
78151
|
+
if (fs.existsSync(sourcePath) && !fs.existsSync(targetPath)) {
|
|
78152
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
78153
|
+
fs.cpSync(sourcePath, targetPath);
|
|
78154
|
+
}
|
|
77606
78155
|
}
|
|
77607
78156
|
});
|
|
77608
78157
|
return {
|
|
@@ -77635,15 +78184,17 @@ var StagedFiles = class StagedFiles extends Service()("react-doctor/StagedFiles"
|
|
|
77635
78184
|
static layerNode = effect(StagedFiles, gen(function* () {
|
|
77636
78185
|
const git = yield* Git;
|
|
77637
78186
|
return StagedFiles.of({
|
|
77638
|
-
discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries.filter(isLintableSourceFile)), withSpan("StagedFiles.discoverSourceFiles")),
|
|
77639
|
-
materialize: ({ directory, stagedFiles, tempDirectory }) => materializeSourceTree({
|
|
78187
|
+
discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries === null ? null : entries.filter(isLintableSourceFile)), withSpan("StagedFiles.discoverSourceFiles")),
|
|
78188
|
+
materialize: ({ directory, stagedFiles, tempDirectory, configSubdirectories }) => materializeSourceTree({
|
|
77640
78189
|
directory,
|
|
77641
78190
|
files: stagedFiles,
|
|
77642
78191
|
tempDirectory,
|
|
78192
|
+
configSubdirectories,
|
|
77643
78193
|
readContent: (relativePath) => git.showStagedContent(directory, relativePath, { maxBufferBytes: GIT_SHOW_MAX_BUFFER_BYTES })
|
|
77644
78194
|
}).pipe(map$3((tree) => ({
|
|
77645
78195
|
tempDirectory: tree.tempDirectory,
|
|
77646
78196
|
stagedFiles: tree.materializedFiles,
|
|
78197
|
+
unmaterializedFiles: tree.unmaterializedFiles,
|
|
77647
78198
|
cleanup: tree.cleanup
|
|
77648
78199
|
})), withSpan("StagedFiles.materialize"))
|
|
77649
78200
|
});
|
|
@@ -77658,6 +78209,7 @@ var StagedFiles = class StagedFiles extends Service()("react-doctor/StagedFiles"
|
|
|
77658
78209
|
materialize: ({ tempDirectory }) => succeed$2({
|
|
77659
78210
|
tempDirectory,
|
|
77660
78211
|
stagedFiles: snapshot.materializedFiles ?? snapshot.sourceFiles ?? [],
|
|
78212
|
+
unmaterializedFiles: [],
|
|
77661
78213
|
cleanup: () => {}
|
|
77662
78214
|
})
|
|
77663
78215
|
}));
|
|
@@ -78026,6 +78578,11 @@ const computeConfigFingerprint = (projectDirectory, version) => {
|
|
|
78026
78578
|
}
|
|
78027
78579
|
return crypto.createHash("sha1").update(parts.join("|")).digest("hex");
|
|
78028
78580
|
};
|
|
78581
|
+
const createLintPhaseAbortError = () => new ReactDoctorError({ reason: new OxlintSpawnFailed({ cause: "lint phase aborted" }) });
|
|
78582
|
+
const createOxlintSpawnSlots = (concurrency) => createWorkerSlots({
|
|
78583
|
+
slotCount: resolveScanConcurrency(concurrency),
|
|
78584
|
+
createAbortError: createLintPhaseAbortError
|
|
78585
|
+
});
|
|
78029
78586
|
const AI_TRAINING_ENV_VARS = [
|
|
78030
78587
|
["HF_DATASETS_CACHE", "huggingface"],
|
|
78031
78588
|
["HF_HOME", "huggingface"],
|
|
@@ -78105,7 +78662,7 @@ const groupBy = (items, keyFn) => {
|
|
|
78105
78662
|
* recipe, so advertising "fetch the fix recipe" for them sends agents to
|
|
78106
78663
|
* a 404. Gate the directive on this predicate.
|
|
78107
78664
|
*/
|
|
78108
|
-
const hasPublishedFixRecipe = (diagnostic) => diagnostic.plugin === "react-doctor" && Object.hasOwn(
|
|
78665
|
+
const hasPublishedFixRecipe = (diagnostic) => diagnostic.plugin === "react-doctor" && Object.hasOwn(REACT_DOCTOR_RULE_REGISTRY, diagnostic.rule);
|
|
78109
78666
|
const unionValues = (baseValues, overrideValues) => [...new Set([...baseValues, ...overrideValues])];
|
|
78110
78667
|
const mergeIgnores = (baseIgnore, overrideIgnore) => {
|
|
78111
78668
|
const mergedIgnore = {
|
|
@@ -78367,6 +78924,7 @@ const METRIC = {
|
|
|
78367
78924
|
cliError: "cli.error",
|
|
78368
78925
|
cliEnvironmentError: "cli.env_error",
|
|
78369
78926
|
stagedSnapshotDivergence: "staged.snapshot_divergence",
|
|
78927
|
+
stagedPerProject: "staged.per_project",
|
|
78370
78928
|
projectDetected: "project.detected",
|
|
78371
78929
|
projectPathSelected: "project.path_selected",
|
|
78372
78930
|
projectConfigSelected: "project.config_selected",
|
|
@@ -78452,7 +79010,7 @@ const makeNoopConsole = () => ({
|
|
|
78452
79010
|
});
|
|
78453
79011
|
//#endregion
|
|
78454
79012
|
//#region src/cli/utils/version.ts
|
|
78455
|
-
const VERSION = "0.9.2-dev.
|
|
79013
|
+
const VERSION = "0.9.2-dev.fb5f881";
|
|
78456
79014
|
//#endregion
|
|
78457
79015
|
//#region src/cli/utils/json-mode.ts
|
|
78458
79016
|
let context = null;
|
|
@@ -78810,13 +79368,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
78810
79368
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
78811
79369
|
* standard `SENTRY_RELEASE` override.
|
|
78812
79370
|
*/
|
|
78813
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.2-dev.
|
|
79371
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.2-dev.fb5f881`;
|
|
78814
79372
|
/**
|
|
78815
79373
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
78816
79374
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
78817
79375
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
78818
79376
|
*/
|
|
78819
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.2-dev.
|
|
79377
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.2-dev.fb5f881") ? "development" : "production");
|
|
78820
79378
|
/**
|
|
78821
79379
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
78822
79380
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -90670,7 +91228,8 @@ const buildRuntimeLayers = (input) => {
|
|
|
90670
91228
|
resolvedDirectory: input.directory,
|
|
90671
91229
|
configSourceDirectory: input.configSourceDirectory
|
|
90672
91230
|
}) : Config.layerNode, Files.layerNode, Git.layerNode, linterLayer, LintPartialFailures.layerLive, deadCodeLayer, progressLayer, reporterLayer, scoreLayer, supplyChainLayer);
|
|
90673
|
-
|
|
91231
|
+
const layersWithConcurrency = input.oxlintConcurrency === void 0 ? baseLayers : mergeAll$1(baseLayers, succeed$3(OxlintConcurrency, input.oxlintConcurrency));
|
|
91232
|
+
return input.oxlintSpawnSlots === void 0 ? layersWithConcurrency : mergeAll$1(layersWithConcurrency, succeed$3(OxlintSpawnSlots, input.oxlintSpawnSlots));
|
|
90674
91233
|
};
|
|
90675
91234
|
//#endregion
|
|
90676
91235
|
//#region src/cli/utils/with-sentry-run-span.ts
|
|
@@ -92273,16 +92832,19 @@ const formatClusterLocation = (cluster, resolveSourceRoot, hyperlinks) => {
|
|
|
92273
92832
|
if (!hyperlinks) return `${location}${contextTag}`;
|
|
92274
92833
|
return `${formatHyperlink(location, pathToFileURL(resolveAbsolutePath(lead.filePath, resolveSourceRoot(lead))).href)}${contextTag}`;
|
|
92275
92834
|
};
|
|
92276
|
-
const buildDiagnosticClusterLines = (cluster, resolveSourceRoot, renderCodeFrame, hyperlinks) => {
|
|
92835
|
+
const buildDiagnosticClusterLines = (cluster, resolveSourceRoot, resolveFrameSourceRoot, renderCodeFrame, hyperlinks) => {
|
|
92277
92836
|
const lead = cluster.diagnostics[0];
|
|
92278
92837
|
const isMultiSite = cluster.diagnostics.length > 1;
|
|
92838
|
+
const sourceRoot = resolveSourceRoot(lead);
|
|
92839
|
+
const frameSourceRoot = resolveFrameSourceRoot(lead);
|
|
92840
|
+
const frameFilePath = Path.isAbsolute(lead.filePath) && sourceRoot !== frameSourceRoot ? Path.relative(sourceRoot, lead.filePath) : lead.filePath;
|
|
92279
92841
|
const lines = ["", highlighter.gray(`${TOP_ERROR_DETAIL_INDENT}${formatClusterLocation(cluster, resolveSourceRoot, hyperlinks)}`)];
|
|
92280
92842
|
const codeFrame = renderCodeFrame ? buildCodeFrame({
|
|
92281
|
-
filePath:
|
|
92843
|
+
filePath: frameFilePath,
|
|
92282
92844
|
line: cluster.startLine,
|
|
92283
92845
|
column: isMultiSite ? 0 : lead.column,
|
|
92284
92846
|
endLine: isMultiSite ? cluster.endLine : void 0,
|
|
92285
|
-
rootDirectory:
|
|
92847
|
+
rootDirectory: frameSourceRoot
|
|
92286
92848
|
}) : null;
|
|
92287
92849
|
if (codeFrame) {
|
|
92288
92850
|
const boxInnerWidth = resolveMeasureWidth(8);
|
|
@@ -92295,7 +92857,7 @@ const buildDiagnosticClusterLines = (cluster, resolveSourceRoot, renderCodeFrame
|
|
|
92295
92857
|
}
|
|
92296
92858
|
return lines;
|
|
92297
92859
|
};
|
|
92298
|
-
const buildRuleDetailBlock = (ruleKey, ruleDiagnostics, resolveSourceRoot, renderEverySite, isAgentEnvironment, hyperlinks) => {
|
|
92860
|
+
const buildRuleDetailBlock = (ruleKey, ruleDiagnostics, resolveSourceRoot, resolveFrameSourceRoot, renderEverySite, isAgentEnvironment, hyperlinks) => {
|
|
92299
92861
|
const representative = pickRepresentativeDiagnostic(ruleDiagnostics);
|
|
92300
92862
|
const { severity } = representative;
|
|
92301
92863
|
const trailingBadge = formatTrailingSiteBadge(ruleDiagnostics.length);
|
|
@@ -92317,7 +92879,7 @@ const buildRuleDetailBlock = (ruleKey, ruleDiagnostics, resolveSourceRoot, rende
|
|
|
92317
92879
|
}
|
|
92318
92880
|
const renderCodeFrame = severity === "error";
|
|
92319
92881
|
const sites = renderEverySite ? ruleDiagnostics : [representative];
|
|
92320
|
-
if (!(isCollapsedWarningGroup && representative.help.includes(representative.filePath))) for (const cluster of clusterNearbyDiagnostics(sites)) lines.push(...buildDiagnosticClusterLines(cluster, resolveSourceRoot, renderCodeFrame, hyperlinks));
|
|
92882
|
+
if (!(isCollapsedWarningGroup && representative.help.includes(representative.filePath))) for (const cluster of clusterNearbyDiagnostics(sites)) lines.push(...buildDiagnosticClusterLines(cluster, resolveSourceRoot, resolveFrameSourceRoot, renderCodeFrame, hyperlinks));
|
|
92321
92883
|
return lines;
|
|
92322
92884
|
};
|
|
92323
92885
|
const selectErrorRuleGroups = (diagnostics, rulePriority) => buildSortedRuleGroups(diagnostics.filter((diagnostic) => diagnostic.severity === "error"), rulePriority);
|
|
@@ -92343,7 +92905,7 @@ const buildMigrationScaleAdvisoryLines = (diagnostics) => {
|
|
|
92343
92905
|
return lines;
|
|
92344
92906
|
};
|
|
92345
92907
|
const getTopErrorRuleKeys = (diagnostics, limit, rulePriority) => new Set(selectTopErrorRuleGroups(diagnostics, limit, rulePriority).map(([ruleKey]) => ruleKey));
|
|
92346
|
-
const buildTopErrorsSection = (diagnostics, resolveSourceRoot, hyperlinks, rulePriority) => {
|
|
92908
|
+
const buildTopErrorsSection = (diagnostics, resolveSourceRoot, resolveFrameSourceRoot, hyperlinks, rulePriority) => {
|
|
92347
92909
|
const topRuleGroups = selectErrorRuleGroups(diagnostics, rulePriority).slice(0, 3);
|
|
92348
92910
|
if (topRuleGroups.length === 0) return {
|
|
92349
92911
|
lines: [],
|
|
@@ -92353,7 +92915,7 @@ const buildTopErrorsSection = (diagnostics, resolveSourceRoot, hyperlinks, ruleP
|
|
|
92353
92915
|
const blockOffsets = [];
|
|
92354
92916
|
for (const [ruleKey, ruleDiagnostics] of topRuleGroups) {
|
|
92355
92917
|
blockOffsets.push(lines.length);
|
|
92356
|
-
lines.push(...buildRuleDetailBlock(ruleKey, ruleDiagnostics, resolveSourceRoot, false, false, hyperlinks));
|
|
92918
|
+
lines.push(...buildRuleDetailBlock(ruleKey, ruleDiagnostics, resolveSourceRoot, resolveFrameSourceRoot, false, false, hyperlinks));
|
|
92357
92919
|
lines.push("");
|
|
92358
92920
|
}
|
|
92359
92921
|
return {
|
|
@@ -92391,18 +92953,19 @@ const buildOverviewHeaderLines = (diagnostics) => {
|
|
|
92391
92953
|
* single Effect.forEach over Console.log so failures or fiber
|
|
92392
92954
|
* interruption produce predictable partial output.
|
|
92393
92955
|
*/
|
|
92394
|
-
const printDiagnostics = (diagnostics, isVerbose, sourceRoot, rulePriority, isAgentEnvironment = false, onboarding = {}, hyperlinks = false) => gen(function* () {
|
|
92956
|
+
const printDiagnostics = (diagnostics, isVerbose, sourceRoot, rulePriority, isAgentEnvironment = false, onboarding = {}, hyperlinks = false, frameSourceRoot = sourceRoot) => gen(function* () {
|
|
92395
92957
|
const sectionPause = onboarding.sectionPause ?? void_;
|
|
92396
92958
|
const animateCountUp = onboarding.animateCountUp ?? false;
|
|
92397
92959
|
const resolveSourceRoot = typeof sourceRoot === "function" ? sourceRoot : () => sourceRoot;
|
|
92960
|
+
const resolveFrameSourceRoot = typeof frameSourceRoot === "function" ? frameSourceRoot : () => frameSourceRoot;
|
|
92398
92961
|
let detailLines;
|
|
92399
92962
|
let topErrorBlockOffsets = [];
|
|
92400
92963
|
if (!isVerbose) {
|
|
92401
|
-
const topErrors = buildTopErrorsSection(diagnostics, resolveSourceRoot, hyperlinks, rulePriority);
|
|
92964
|
+
const topErrors = buildTopErrorsSection(diagnostics, resolveSourceRoot, resolveFrameSourceRoot, hyperlinks, rulePriority);
|
|
92402
92965
|
detailLines = topErrors.lines;
|
|
92403
92966
|
topErrorBlockOffsets = topErrors.blockOffsets;
|
|
92404
92967
|
} else detailLines = buildSortedRuleGroups(diagnostics, rulePriority).flatMap(([ruleKey, ruleDiagnostics]) => {
|
|
92405
|
-
return [...buildRuleDetailBlock(ruleKey, ruleDiagnostics, resolveSourceRoot, true, isAgentEnvironment, hyperlinks), ""];
|
|
92968
|
+
return [...buildRuleDetailBlock(ruleKey, ruleDiagnostics, resolveSourceRoot, resolveFrameSourceRoot, true, isAgentEnvironment, hyperlinks), ""];
|
|
92406
92969
|
});
|
|
92407
92970
|
const overflowLine = isVerbose ? void 0 : buildOverflowSummaryLine(diagnostics, rulePriority);
|
|
92408
92971
|
const categoryTallies = buildCategoryDiagnosticGroups(diagnostics, rulePriority).map(buildCategoryTally);
|
|
@@ -93170,7 +93733,7 @@ const buildRunEventConfig = (options, userConfig, hasCustomConfig, resolvedWorke
|
|
|
93170
93733
|
userConfig
|
|
93171
93734
|
};
|
|
93172
93735
|
};
|
|
93173
|
-
const
|
|
93736
|
+
const inspectWithOxlintRuntime = async (directory, inputOptions, oxlintRuntime) => {
|
|
93174
93737
|
const startTime = performance$1.now();
|
|
93175
93738
|
const deadlineEpochMs = inputOptions.deadlineEpochMs ?? (inputOptions.maxDurationMs != null ? Date.now() + inputOptions.maxDurationMs : null);
|
|
93176
93739
|
const isConcurrentScan = inputOptions.concurrentScan === true;
|
|
@@ -93196,7 +93759,7 @@ const inspect = async (directory, inputOptions = {}) => {
|
|
|
93196
93759
|
try {
|
|
93197
93760
|
const result = await withSentryRunSpan(async (rootSentrySpan) => {
|
|
93198
93761
|
try {
|
|
93199
|
-
return await runInspectWithRuntime(scanDirectory, options, userConfig, hasConfigOverride, configSourceDirectory, startTime, deadlineEpochMs, rootSentrySpan);
|
|
93762
|
+
return await runInspectWithRuntime(scanDirectory, options, userConfig, hasConfigOverride, configSourceDirectory, startTime, deadlineEpochMs, rootSentrySpan, oxlintRuntime);
|
|
93200
93763
|
} catch (error) {
|
|
93201
93764
|
recordRunEvent(rootSentrySpan, {
|
|
93202
93765
|
...buildRunEventConfig(options, userConfig, userConfig !== null),
|
|
@@ -93212,6 +93775,15 @@ const inspect = async (directory, inputOptions = {}) => {
|
|
|
93212
93775
|
if (ownsSpinnerSilence) setSpinnerSilent(wasSpinnerSilent);
|
|
93213
93776
|
}
|
|
93214
93777
|
};
|
|
93778
|
+
const createInvocationInspect = (requestedOxlintConcurrency) => {
|
|
93779
|
+
const concurrency = resolveScanConcurrency(requestedOxlintConcurrency ?? runSync(OxlintConcurrency));
|
|
93780
|
+
const oxlintRuntime = {
|
|
93781
|
+
concurrency,
|
|
93782
|
+
spawnSlots: createOxlintSpawnSlots(concurrency)
|
|
93783
|
+
};
|
|
93784
|
+
return (directory, inputOptions = {}) => inspectWithOxlintRuntime(directory, inputOptions, oxlintRuntime);
|
|
93785
|
+
};
|
|
93786
|
+
const inspect = async (directory, inputOptions = {}) => createInvocationInspect(inputOptions.concurrency)(directory, inputOptions);
|
|
93215
93787
|
const countIncompleteLintFiles = (lintPartialFailures) => countDroppedLintFiles(lintPartialFailures) + countDeadlineSkippedFiles(lintPartialFailures);
|
|
93216
93788
|
/**
|
|
93217
93789
|
* Runs a second, lint-only scan over the changed files as they existed at the
|
|
@@ -93265,7 +93837,8 @@ const runBaselineComparison = async (params) => {
|
|
|
93265
93837
|
shouldRunSupplyChain: params.options.supplyChain,
|
|
93266
93838
|
shouldComputeScore: false,
|
|
93267
93839
|
shouldShowProgressSpinners: false,
|
|
93268
|
-
oxlintConcurrency: params.
|
|
93840
|
+
oxlintConcurrency: params.oxlintRuntime.concurrency,
|
|
93841
|
+
oxlintSpawnSlots: params.oxlintRuntime.spawnSlots
|
|
93269
93842
|
});
|
|
93270
93843
|
const baseOutput = await runPromise(restoreLegacyThrow(runInspect({
|
|
93271
93844
|
directory: snapshot.tempDirectory,
|
|
@@ -93310,7 +93883,7 @@ const runBaselineComparison = async (params) => {
|
|
|
93310
93883
|
snapshot.cleanup();
|
|
93311
93884
|
}
|
|
93312
93885
|
};
|
|
93313
|
-
const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOverride, configSourceDirectory, startTime, deadlineEpochMs, rootSentrySpan) => {
|
|
93886
|
+
const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOverride, configSourceDirectory, startTime, deadlineEpochMs, rootSentrySpan, oxlintRuntime) => {
|
|
93314
93887
|
const isDiffMode = options.includePaths.length > 0;
|
|
93315
93888
|
const resolvedNodeBinaryPath = await resolveOxlintNode(options.lint, options.scoreOnly || options.silent);
|
|
93316
93889
|
const lintBindingMissing = options.lint && !resolvedNodeBinaryPath;
|
|
@@ -93360,7 +93933,8 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
93360
93933
|
shouldRunSupplyChain: options.supplyChain,
|
|
93361
93934
|
shouldComputeScore: !options.noScore,
|
|
93362
93935
|
shouldShowProgressSpinners,
|
|
93363
|
-
oxlintConcurrency:
|
|
93936
|
+
oxlintConcurrency: oxlintRuntime.concurrency,
|
|
93937
|
+
oxlintSpawnSlots: oxlintRuntime.spawnSlots,
|
|
93364
93938
|
reporterLayer: options.uiLayers?.reporter,
|
|
93365
93939
|
progressLayer: options.uiLayers?.progress
|
|
93366
93940
|
});
|
|
@@ -93417,7 +93991,8 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
93417
93991
|
baseFiles: options.baseline.baseFiles,
|
|
93418
93992
|
headFiles: options.baseline.headFiles,
|
|
93419
93993
|
headAnalyzedFiles: output.analyzedFiles,
|
|
93420
|
-
deadlineEpochMs
|
|
93994
|
+
deadlineEpochMs,
|
|
93995
|
+
oxlintRuntime
|
|
93421
93996
|
});
|
|
93422
93997
|
if (comparison) {
|
|
93423
93998
|
inspectDiagnostics = comparison.displayDiagnostics;
|
|
@@ -93666,26 +94241,26 @@ const finalizeAndRender = (input) => gen(function* () {
|
|
|
93666
94241
|
//#region src/cli/utils/get-staged-files.ts
|
|
93667
94242
|
const stagedFilesLayer = StagedFiles.layerNode.pipe(provide$2(Git.layerNode));
|
|
93668
94243
|
const getStagedSourceFiles = async (directory) => {
|
|
94244
|
+
let stagedSourceFiles;
|
|
93669
94245
|
try {
|
|
93670
|
-
|
|
94246
|
+
stagedSourceFiles = await runPromise(gen(function* () {
|
|
93671
94247
|
return yield* (yield* StagedFiles).discoverSourceFiles(directory);
|
|
93672
|
-
}).pipe(provide(stagedFilesLayer)))
|
|
94248
|
+
}).pipe(provide(stagedFilesLayer)));
|
|
93673
94249
|
} catch (error) {
|
|
93674
94250
|
cliLogger.warn(`Failed to discover staged files: ${messageFromUnknown(error)}`);
|
|
93675
94251
|
return [];
|
|
93676
94252
|
}
|
|
94253
|
+
if (stagedSourceFiles === null) throw new CliInputError("Could not read the git index to list staged files. Check that git can read the index in this directory.");
|
|
94254
|
+
return [...stagedSourceFiles];
|
|
93677
94255
|
};
|
|
93678
|
-
const materializeStagedFiles = async (
|
|
94256
|
+
const materializeStagedFiles = async (input) => {
|
|
93679
94257
|
const snapshot = await runPromise(gen(function* () {
|
|
93680
|
-
return yield* (yield* StagedFiles).materialize(
|
|
93681
|
-
directory,
|
|
93682
|
-
stagedFiles,
|
|
93683
|
-
tempDirectory
|
|
93684
|
-
});
|
|
94258
|
+
return yield* (yield* StagedFiles).materialize(input);
|
|
93685
94259
|
}).pipe(provide(stagedFilesLayer)));
|
|
93686
94260
|
return {
|
|
93687
94261
|
tempDirectory: snapshot.tempDirectory,
|
|
93688
94262
|
stagedFiles: [...snapshot.stagedFiles],
|
|
94263
|
+
unmaterializedFiles: [...snapshot.unmaterializedFiles],
|
|
93689
94264
|
cleanup: snapshot.cleanup
|
|
93690
94265
|
};
|
|
93691
94266
|
};
|
|
@@ -95559,13 +96134,18 @@ const printMultiProjectSummary = (input) => gen(function* () {
|
|
|
95559
96134
|
const scoreDiagnostics = new Set(filterScansForSurface(completedScans, "score"));
|
|
95560
96135
|
const displayedScoreDiagnostics = displayDiagnostics.filter((diagnostic) => scoreDiagnostics.has(diagnostic));
|
|
95561
96136
|
const projectRootByDiagnostic = /* @__PURE__ */ new WeakMap();
|
|
95562
|
-
|
|
96137
|
+
const frameSourceRootByDiagnostic = /* @__PURE__ */ new WeakMap();
|
|
96138
|
+
for (const scan of completedScans) for (const diagnostic of scan.result.diagnostics) {
|
|
96139
|
+
projectRootByDiagnostic.set(diagnostic, scan.result.project.rootDirectory);
|
|
96140
|
+
frameSourceRootByDiagnostic.set(diagnostic, scan.frameSourceRoot ?? scan.result.project.rootDirectory);
|
|
96141
|
+
}
|
|
95563
96142
|
const resolveDiagnosticSourceRoot = (diagnostic) => projectRootByDiagnostic.get(diagnostic) ?? "";
|
|
96143
|
+
const resolveDiagnosticFrameSourceRoot = (diagnostic) => frameSourceRootByDiagnostic.get(diagnostic) ?? resolveDiagnosticSourceRoot(diagnostic);
|
|
95564
96144
|
const totalScannedFileCount = countUniqueScannedFiles(completedScans.map((scan) => scan.result));
|
|
95565
96145
|
yield* log(`${highlighter.success("✔")} Scanned ${totalScannedFileCount} ${totalScannedFileCount === 1 ? "file" : "files"} in ${formatElapsedTime(totalElapsedMilliseconds)}`);
|
|
95566
96146
|
if (displayDiagnostics.length > 0) {
|
|
95567
96147
|
yield* log("");
|
|
95568
|
-
yield* printDiagnostics(displayDiagnostics, verbose, resolveDiagnosticSourceRoot, buildRulePriorityMap(completedScans.map((scan) => scan.result.score)), isCodingAgentEnvironment(), { animateCountUp: animateRender }, shouldRenderHyperlinks(process.stdout));
|
|
96148
|
+
yield* printDiagnostics(displayDiagnostics, verbose, resolveDiagnosticSourceRoot, buildRulePriorityMap(completedScans.map((scan) => scan.result.score)), isCodingAgentEnvironment(), { animateCountUp: animateRender }, shouldRenderHyperlinks(process.stdout), resolveDiagnosticFrameSourceRoot);
|
|
95569
96149
|
}
|
|
95570
96150
|
const lowestScoredScan = findLowestScoredScan(completedScans);
|
|
95571
96151
|
const aggregateScore = lowestScoredScan?.result.score ?? null;
|
|
@@ -95953,6 +96533,45 @@ const runExplain = async (fileLineArgument, context) => {
|
|
|
95953
96533
|
}
|
|
95954
96534
|
};
|
|
95955
96535
|
//#endregion
|
|
96536
|
+
//#region src/cli/utils/run-project-scan-batch.ts
|
|
96537
|
+
/**
|
|
96538
|
+
* Run one scan per project through the same bounded pool as
|
|
96539
|
+
* `diagnose({ projects })`, with the batch spinner and its progress counter.
|
|
96540
|
+
*
|
|
96541
|
+
* Pool members must not toggle the module-level spinner-silent flag themselves —
|
|
96542
|
+
* overlapping save/restore pairs would race — so the batch owns that toggle once
|
|
96543
|
+
* around the whole run.
|
|
96544
|
+
*
|
|
96545
|
+
* A `scanProject` that returns `null` drops the project from the results: diff
|
|
96546
|
+
* mode skips projects with no changed source.
|
|
96547
|
+
*/
|
|
96548
|
+
const runProjectScanBatch = async (input) => {
|
|
96549
|
+
const startTime = performance$1.now();
|
|
96550
|
+
const projectCount = input.projects.length;
|
|
96551
|
+
const isMultiProject = projectCount > 1;
|
|
96552
|
+
const batchSpinner = isMultiProject && !input.isQuiet ? spinner(`Scanning ${projectCount} projects…`).start() : null;
|
|
96553
|
+
const ownsBatchSpinnerSilence = isMultiProject && input.isSilent;
|
|
96554
|
+
const wasSpinnerSilent = isSpinnerSilent();
|
|
96555
|
+
if (ownsBatchSpinnerSilence) setSpinnerSilent(true);
|
|
96556
|
+
let finishedProjectCount = 0;
|
|
96557
|
+
let scanOutcomes;
|
|
96558
|
+
try {
|
|
96559
|
+
scanOutcomes = await mapWithConcurrency(input.projects, isMultiProject ? 4 : 1, async (project) => {
|
|
96560
|
+
const scanOutcome = await input.scanProject(project);
|
|
96561
|
+
finishedProjectCount += 1;
|
|
96562
|
+
batchSpinner?.update(`Scanning ${projectCount} projects… (${finishedProjectCount}/${projectCount})`);
|
|
96563
|
+
return scanOutcome;
|
|
96564
|
+
});
|
|
96565
|
+
} finally {
|
|
96566
|
+
if (ownsBatchSpinnerSilence) setSpinnerSilent(wasSpinnerSilent);
|
|
96567
|
+
batchSpinner?.stop();
|
|
96568
|
+
}
|
|
96569
|
+
return {
|
|
96570
|
+
completedScans: scanOutcomes.filter((scanOutcome) => scanOutcome !== null),
|
|
96571
|
+
elapsedMilliseconds: performance$1.now() - startTime
|
|
96572
|
+
};
|
|
96573
|
+
};
|
|
96574
|
+
//#endregion
|
|
95956
96575
|
//#region src/cli/utils/project-manifest-changed.ts
|
|
95957
96576
|
const PACKAGE_JSON = "package.json";
|
|
95958
96577
|
/**
|
|
@@ -95969,6 +96588,29 @@ const projectManifestChanged = (rootDirectory, projectDirectory, diffInfo) => {
|
|
|
95969
96588
|
return diffInfo.changedFiles.some((filePath) => toForwardSlashes(filePath) === manifestPath);
|
|
95970
96589
|
};
|
|
95971
96590
|
//#endregion
|
|
96591
|
+
//#region src/cli/utils/select-staged-projects.ts
|
|
96592
|
+
/**
|
|
96593
|
+
* Appended to the reason a `--staged` run could not scan per package. Shared so
|
|
96594
|
+
* both fallback sites word it identically.
|
|
96595
|
+
*/
|
|
96596
|
+
const STAGED_PROJECT_FALLBACK_HINT = "Scanning the staged files at the scan root instead — fix the `projects` entries in your config to scan per package.";
|
|
96597
|
+
/**
|
|
96598
|
+
* Resolve the project directories a `--staged` scan owns. The interactive picker
|
|
96599
|
+
* is always skipped: a commit hook has nobody to answer it.
|
|
96600
|
+
*/
|
|
96601
|
+
const selectStagedProjects = async (input) => {
|
|
96602
|
+
if (input.projectFlag) return selectProjects(input.rootDirectory, input.projectFlag, true, void 0);
|
|
96603
|
+
if (input.configProjects === void 0) return [input.rootDirectory];
|
|
96604
|
+
try {
|
|
96605
|
+
return await selectProjects(input.rootDirectory, void 0, true, input.configProjects);
|
|
96606
|
+
} catch (error) {
|
|
96607
|
+
if (!(error instanceof CliInputError)) throw error;
|
|
96608
|
+
cliLogger.warn(`${error.message} ${STAGED_PROJECT_FALLBACK_HINT}`);
|
|
96609
|
+
cliLogger.break();
|
|
96610
|
+
return [input.rootDirectory];
|
|
96611
|
+
}
|
|
96612
|
+
};
|
|
96613
|
+
//#endregion
|
|
95972
96614
|
//#region src/cli/utils/should-fail-scan-gate.ts
|
|
95973
96615
|
const shouldFailScanGate = (input) => {
|
|
95974
96616
|
if (input.blockingLevel === "none") return false;
|
|
@@ -96183,6 +96825,7 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
|
|
|
96183
96825
|
if (!isQuiet) if (!flags.verbose && canAnimateOnboarding(process.stdout)) await runPromise(playWelcomeScene({ speedMultiplier: !isOnboardingForced() && hasCompletedOnboarding() ? 2 : 1 }));
|
|
96184
96826
|
else runSync(printBrandedHeader);
|
|
96185
96827
|
const scanOptions = resolveCliInspectOptions(flags, userConfig);
|
|
96828
|
+
const inspectProject = createInvocationInspect(scanOptions.concurrency);
|
|
96186
96829
|
const scanDeadlineEpochMs = scanOptions.maxDurationMs !== void 0 ? Date.now() + scanOptions.maxDurationMs : void 0;
|
|
96187
96830
|
const categoryFilters = new Set(scanOptions.categoryFilters ?? []);
|
|
96188
96831
|
const skipPrompts = shouldSkipPrompts({
|
|
@@ -96190,8 +96833,13 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
|
|
|
96190
96833
|
json: flags.json
|
|
96191
96834
|
});
|
|
96192
96835
|
if (flags.staged) {
|
|
96193
|
-
const
|
|
96194
|
-
|
|
96836
|
+
const configProjectsApply = (userConfig?.projects ?? []).some((projectName) => projectName.trim().length > 0) && scanTarget.requestedDirectory === scanTarget.configSourceDirectory;
|
|
96837
|
+
const projectDirectories = await selectStagedProjects({
|
|
96838
|
+
rootDirectory: resolvedDirectory,
|
|
96839
|
+
projectFlag: flags.project,
|
|
96840
|
+
configProjects: configProjectsApply ? userConfig?.projects : void 0
|
|
96841
|
+
});
|
|
96842
|
+
const reportNothingToScan = (input) => {
|
|
96195
96843
|
if (isJsonMode) writeJsonReport(buildJsonReport({
|
|
96196
96844
|
version: VERSION,
|
|
96197
96845
|
directory: resolvedDirectory,
|
|
@@ -96200,71 +96848,197 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
|
|
|
96200
96848
|
scans: [],
|
|
96201
96849
|
totalElapsedMilliseconds: performance$1.now() - startTime
|
|
96202
96850
|
}));
|
|
96203
|
-
else if (!isScoreOnly)
|
|
96851
|
+
else if (!isScoreOnly) if (input.severity === "warn") {
|
|
96852
|
+
cliLogger.warn(input.reason);
|
|
96853
|
+
cliLogger.break();
|
|
96854
|
+
} else cliLogger.dim(input.reason);
|
|
96855
|
+
};
|
|
96856
|
+
const rootStagedFiles = await getStagedSourceFiles(resolvedDirectory);
|
|
96857
|
+
if (rootStagedFiles.length === 0) {
|
|
96858
|
+
reportNothingToScan({ reason: "No staged source files found." });
|
|
96204
96859
|
return;
|
|
96205
96860
|
}
|
|
96206
|
-
|
|
96207
|
-
|
|
96861
|
+
const buildProjectScanContext = async (projectDirectory) => {
|
|
96862
|
+
const projectScanTarget = projectDirectory === resolvedDirectory ? scanTarget : await resolveScanTarget(projectDirectory, { allowAmbiguous: true });
|
|
96863
|
+
const scanDirectory = projectScanTarget.resolvedDirectory;
|
|
96864
|
+
const treeRelativeDirectory = resolveProjectRelativeDirectory(resolvedDirectory, scanDirectory);
|
|
96865
|
+
if (treeRelativeDirectory === null) return null;
|
|
96866
|
+
return {
|
|
96867
|
+
projectDirectory,
|
|
96868
|
+
scanDirectory,
|
|
96869
|
+
treeRelativeDirectory,
|
|
96870
|
+
projectConfig: projectDirectory === resolvedDirectory ? userConfig : mergeReactDoctorConfigs(userConfig, projectScanTarget.userConfig ?? void 0),
|
|
96871
|
+
projectConfigSourceDirectory: projectScanTarget.userConfig?.plugins === void 0 ? scanTarget.configSourceDirectory : projectScanTarget.configSourceDirectory
|
|
96872
|
+
};
|
|
96873
|
+
};
|
|
96874
|
+
const projectScanContexts = [];
|
|
96875
|
+
const seenScanDirectories = /* @__PURE__ */ new Set();
|
|
96876
|
+
for (const projectDirectory of projectDirectories) {
|
|
96877
|
+
const projectScanContext = await buildProjectScanContext(projectDirectory);
|
|
96878
|
+
if (projectScanContext === null) {
|
|
96879
|
+
if (flags.project) throw new CliInputError(`Project "${toRelativePath(projectDirectory, resolvedDirectory)}" is outside ${resolvedDirectory}, so it holds none of the staged files. Run --staged from a directory that contains the project.`);
|
|
96880
|
+
continue;
|
|
96881
|
+
}
|
|
96882
|
+
if (seenScanDirectories.has(projectScanContext.scanDirectory)) continue;
|
|
96883
|
+
seenScanDirectories.add(projectScanContext.scanDirectory);
|
|
96884
|
+
projectScanContexts.push(projectScanContext);
|
|
96885
|
+
}
|
|
96886
|
+
if (projectScanContexts.length === 0) {
|
|
96887
|
+
cliLogger.warn(`No configured project is inside ${resolvedDirectory}. ${STAGED_PROJECT_FALLBACK_HINT}`);
|
|
96208
96888
|
cliLogger.break();
|
|
96889
|
+
const rootScanContext = await buildProjectScanContext(resolvedDirectory);
|
|
96890
|
+
if (rootScanContext !== null) projectScanContexts.push(rootScanContext);
|
|
96209
96891
|
}
|
|
96210
|
-
const
|
|
96211
|
-
const
|
|
96212
|
-
|
|
96213
|
-
|
|
96214
|
-
|
|
96892
|
+
const contextsByLongestPathFirst = [...projectScanContexts].sort((left, right) => right.treeRelativeDirectory.length - left.treeRelativeDirectory.length);
|
|
96893
|
+
const ownedStagedFiles = /* @__PURE__ */ new Map();
|
|
96894
|
+
for (const stagedFile of rootStagedFiles) {
|
|
96895
|
+
const owner = contextsByLongestPathFirst.find((context) => context.treeRelativeDirectory.length === 0 || stagedFile.startsWith(`${context.treeRelativeDirectory}/`));
|
|
96896
|
+
if (owner === void 0) continue;
|
|
96897
|
+
const ownedFiles = ownedStagedFiles.get(owner.scanDirectory);
|
|
96898
|
+
if (ownedFiles === void 0) ownedStagedFiles.set(owner.scanDirectory, [stagedFile]);
|
|
96899
|
+
else ownedFiles.push(stagedFile);
|
|
96900
|
+
}
|
|
96901
|
+
const stagedProjectScans = [];
|
|
96902
|
+
for (const projectScanContext of projectScanContexts) {
|
|
96903
|
+
const projectStagedFiles = ownedStagedFiles.get(projectScanContext.scanDirectory);
|
|
96904
|
+
if (projectStagedFiles === void 0) continue;
|
|
96905
|
+
stagedProjectScans.push({
|
|
96906
|
+
...projectScanContext,
|
|
96907
|
+
stagedFiles: projectStagedFiles
|
|
96215
96908
|
});
|
|
96216
|
-
|
|
96217
|
-
|
|
96909
|
+
}
|
|
96910
|
+
if (stagedProjectScans.length === 0) {
|
|
96911
|
+
reportNothingToScan({ reason: "No staged source files in the selected projects." });
|
|
96912
|
+
return;
|
|
96913
|
+
}
|
|
96914
|
+
const selectedStagedFiles = stagedProjectScans.flatMap((projectScan) => projectScan.stagedFiles);
|
|
96915
|
+
const stagedFileCount = selectedStagedFiles.length;
|
|
96916
|
+
const unselectedStagedFileCount = rootStagedFiles.length - stagedFileCount;
|
|
96917
|
+
if (!isQuiet) {
|
|
96918
|
+
cliLogger.log(`Scanning ${highlighter.info(`${stagedFileCount}`)} staged files...`);
|
|
96919
|
+
if (unselectedStagedFileCount > 0) cliLogger.dim(`${unselectedStagedFileCount} more staged file${unselectedStagedFileCount === 1 ? "" : "s"} outside the selected projects.`);
|
|
96920
|
+
cliLogger.break();
|
|
96921
|
+
}
|
|
96218
96922
|
const stagedWantsLines = resolveScope(flags, userConfig).scope === "lines";
|
|
96219
96923
|
const stagedLineRanges = stagedWantsLines ? await getChangedLineRanges({
|
|
96220
96924
|
directory: resolvedDirectory,
|
|
96221
96925
|
cached: true,
|
|
96222
|
-
files:
|
|
96926
|
+
files: selectedStagedFiles
|
|
96223
96927
|
}) : null;
|
|
96224
96928
|
if (stagedWantsLines && stagedLineRanges === null && !isQuiet) {
|
|
96225
96929
|
cliLogger.warn("Could not determine staged changed lines; reporting all issues in staged files.");
|
|
96226
96930
|
cliLogger.break();
|
|
96227
96931
|
}
|
|
96228
|
-
|
|
96229
|
-
|
|
96932
|
+
if (stagedProjectScans.some((projectScan) => projectScan.treeRelativeDirectory.length > 0)) recordCount(METRIC.stagedPerProject, 1, { projectCount: stagedProjectScans.length });
|
|
96933
|
+
const tempDirectory = NFS.mkdtempSync(Path.join(tmpdir(), STAGED_FILES_TEMP_DIR_PREFIX));
|
|
96934
|
+
const configSubdirectories = /* @__PURE__ */ new Set();
|
|
96935
|
+
for (const projectScan of stagedProjectScans) {
|
|
96936
|
+
configSubdirectories.add(projectScan.treeRelativeDirectory);
|
|
96937
|
+
const projectRelativeDirectory = resolveProjectRelativeDirectory(resolvedDirectory, projectScan.projectDirectory);
|
|
96938
|
+
if (projectRelativeDirectory !== null) configSubdirectories.add(projectRelativeDirectory);
|
|
96939
|
+
}
|
|
96940
|
+
const snapshot = await materializeStagedFiles({
|
|
96941
|
+
directory: resolvedDirectory,
|
|
96942
|
+
stagedFiles: selectedStagedFiles,
|
|
96943
|
+
tempDirectory,
|
|
96944
|
+
configSubdirectories: [...configSubdirectories]
|
|
96945
|
+
}).catch((error) => {
|
|
96946
|
+
NFS.rmSync(tempDirectory, {
|
|
96947
|
+
recursive: true,
|
|
96948
|
+
force: true
|
|
96949
|
+
});
|
|
96950
|
+
throw error;
|
|
96951
|
+
});
|
|
96952
|
+
const materializedStagedFiles = new Set(snapshot.stagedFiles);
|
|
96953
|
+
const stagedProjectRuns = stagedProjectScans.map((projectScan) => ({
|
|
96954
|
+
projectScan,
|
|
96955
|
+
includePaths: resolveProjectSourceFilePaths(resolvedDirectory, projectScan.scanDirectory, projectScan.stagedFiles.filter((stagedFile) => materializedStagedFiles.has(stagedFile)))
|
|
96956
|
+
})).filter((projectRun) => projectRun.includePaths.length > 0);
|
|
96957
|
+
const isMultiProject = stagedProjectRuns.length > 1;
|
|
96958
|
+
if (stagedProjectRuns.length === 0) {
|
|
96959
|
+
snapshot.cleanup();
|
|
96960
|
+
reportNothingToScan({
|
|
96961
|
+
reason: `Could not read any of the ${stagedFileCount} staged file${stagedFileCount === 1 ? "" : "s"} out of the index, so nothing was scanned. An unusually large staged file is the usual cause.`,
|
|
96962
|
+
severity: "warn"
|
|
96963
|
+
});
|
|
96964
|
+
return;
|
|
96965
|
+
}
|
|
96966
|
+
if (snapshot.unmaterializedFiles.length > 0 && !isQuiet) {
|
|
96967
|
+
const stagedFileLabel = `staged file${stagedFileCount === 1 ? "" : "s"}`;
|
|
96968
|
+
cliLogger.warn(`Skipped ${snapshot.unmaterializedFiles.length} of ${stagedFileCount} ${stagedFileLabel}; they could not be snapshotted from the index.`);
|
|
96969
|
+
cliLogger.break();
|
|
96970
|
+
}
|
|
96971
|
+
const scanStagedProject = async (projectRun) => {
|
|
96972
|
+
const { projectScan, includePaths } = projectRun;
|
|
96973
|
+
const projectTempDirectory = Path.join(snapshot.tempDirectory, projectScan.treeRelativeDirectory);
|
|
96974
|
+
const scanResult = await inspectProject(projectTempDirectory, {
|
|
96230
96975
|
...scanOptions,
|
|
96231
96976
|
deadlineEpochMs: scanDeadlineEpochMs,
|
|
96232
|
-
includePaths:
|
|
96233
|
-
configOverride:
|
|
96234
|
-
configSourceDirectory:
|
|
96235
|
-
changedLineRanges: stagedLineRanges
|
|
96977
|
+
includePaths: [...includePaths],
|
|
96978
|
+
configOverride: projectScan.projectConfig,
|
|
96979
|
+
configSourceDirectory: projectScan.projectConfigSourceDirectory ?? void 0,
|
|
96980
|
+
changedLineRanges: stagedLineRanges === null ? void 0 : resolveProjectChangedLineRanges(resolvedDirectory, projectScan.scanDirectory, stagedLineRanges),
|
|
96981
|
+
suppressRendering: isMultiProject,
|
|
96982
|
+
concurrentScan: isMultiProject
|
|
96236
96983
|
});
|
|
96237
96984
|
const remappedDiagnostics = scanResult.diagnostics.map((diagnostic) => ({
|
|
96238
96985
|
...diagnostic,
|
|
96239
|
-
filePath: Path.isAbsolute(diagnostic.filePath) ? diagnostic.filePath.replaceAll(
|
|
96986
|
+
filePath: Path.isAbsolute(diagnostic.filePath) ? diagnostic.filePath.replaceAll(projectTempDirectory, () => projectScan.scanDirectory) : diagnostic.filePath
|
|
96240
96987
|
}));
|
|
96241
|
-
|
|
96242
|
-
|
|
96243
|
-
|
|
96244
|
-
|
|
96245
|
-
|
|
96246
|
-
|
|
96247
|
-
project
|
|
96248
|
-
|
|
96249
|
-
|
|
96250
|
-
|
|
96251
|
-
|
|
96252
|
-
|
|
96253
|
-
|
|
96254
|
-
|
|
96255
|
-
|
|
96256
|
-
|
|
96257
|
-
|
|
96258
|
-
|
|
96259
|
-
|
|
96260
|
-
|
|
96261
|
-
|
|
96262
|
-
|
|
96263
|
-
|
|
96264
|
-
|
|
96988
|
+
return {
|
|
96989
|
+
directory: projectScan.scanDirectory,
|
|
96990
|
+
result: {
|
|
96991
|
+
...scanResult,
|
|
96992
|
+
diagnostics: remappedDiagnostics,
|
|
96993
|
+
project: {
|
|
96994
|
+
...scanResult.project,
|
|
96995
|
+
rootDirectory: projectScan.scanDirectory
|
|
96996
|
+
}
|
|
96997
|
+
},
|
|
96998
|
+
config: projectScan.projectConfig,
|
|
96999
|
+
frameSourceRoot: projectTempDirectory
|
|
97000
|
+
};
|
|
97001
|
+
};
|
|
97002
|
+
const stagedBatch = await runProjectScanBatch({
|
|
97003
|
+
projects: stagedProjectRuns,
|
|
97004
|
+
isQuiet,
|
|
97005
|
+
isSilent: scanOptions.silent === true,
|
|
97006
|
+
scanProject: scanStagedProject
|
|
97007
|
+
}).catch((error) => {
|
|
97008
|
+
snapshot.cleanup();
|
|
97009
|
+
throw error;
|
|
97010
|
+
});
|
|
97011
|
+
const completedScans = stagedBatch.completedScans;
|
|
97012
|
+
try {
|
|
97013
|
+
if (!isQuiet && isMultiProject) {
|
|
97014
|
+
const showShareLink = !isShareOptedOut(completedScans, scanOptions.noScore) && !scanOptions.isCi;
|
|
97015
|
+
await runPromise(printMultiProjectSummary({
|
|
97016
|
+
completedScans,
|
|
97017
|
+
categoryFilters,
|
|
97018
|
+
verbose: Boolean(flags.verbose),
|
|
97019
|
+
outputDirectory: flags.outputDir,
|
|
97020
|
+
isOffline: !showShareLink,
|
|
97021
|
+
projectName: Path.basename(resolvedDirectory),
|
|
97022
|
+
totalElapsedMilliseconds: stagedBatch.elapsedMilliseconds
|
|
97023
|
+
}));
|
|
97024
|
+
}
|
|
97025
|
+
if (flags.outputDir && isMultiProject && isQuiet) await runPromise(printDiagnosticsDump(filterDiagnosticsByCategories(filterScansForSurface(completedScans, scanOptions.outputSurface ?? "cli"), categoryFilters), flags.outputDir, false, "stderr"));
|
|
96265
97026
|
} finally {
|
|
96266
97027
|
snapshot.cleanup();
|
|
96267
97028
|
}
|
|
97029
|
+
finalizeScans({
|
|
97030
|
+
completedScans,
|
|
97031
|
+
mode: "staged",
|
|
97032
|
+
diff: null,
|
|
97033
|
+
baselineIntended: false,
|
|
97034
|
+
isJsonMode,
|
|
97035
|
+
isScoreOnly,
|
|
97036
|
+
flags,
|
|
97037
|
+
categoryFilters,
|
|
97038
|
+
userConfig,
|
|
97039
|
+
resolvedDirectory,
|
|
97040
|
+
startTime
|
|
97041
|
+
});
|
|
96268
97042
|
return;
|
|
96269
97043
|
}
|
|
96270
97044
|
const projectDirectories = await selectProjects(resolvedDirectory, flags.project, skipPrompts, userConfig?.projects);
|
|
@@ -96329,7 +97103,6 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
|
|
|
96329
97103
|
}
|
|
96330
97104
|
cliLogger.break();
|
|
96331
97105
|
}
|
|
96332
|
-
const completedScans = [];
|
|
96333
97106
|
const isMultiProject = projectDirectories.length > 1;
|
|
96334
97107
|
const scanProject = async (projectDirectory) => {
|
|
96335
97108
|
const projectScanTarget = projectDirectory === resolvedDirectory ? scanTarget : await resolveScanTarget(projectDirectory, { allowAmbiguous: true });
|
|
@@ -96357,7 +97130,7 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
|
|
|
96357
97130
|
if (supplyChainManifestChanged) includePaths.push("package.json");
|
|
96358
97131
|
}
|
|
96359
97132
|
if (!isQuiet && !isMultiProject) cliLogger.dim(" ");
|
|
96360
|
-
const scanResult = await
|
|
97133
|
+
const scanResult = await inspectProject(scanDirectory, {
|
|
96361
97134
|
...scanOptions,
|
|
96362
97135
|
deadlineEpochMs: scanDeadlineEpochMs,
|
|
96363
97136
|
includePaths,
|
|
@@ -96380,29 +97153,13 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
|
|
|
96380
97153
|
config: projectConfig
|
|
96381
97154
|
};
|
|
96382
97155
|
};
|
|
96383
|
-
const
|
|
96384
|
-
|
|
96385
|
-
|
|
96386
|
-
|
|
96387
|
-
|
|
96388
|
-
|
|
96389
|
-
|
|
96390
|
-
let scanOutcomes;
|
|
96391
|
-
try {
|
|
96392
|
-
scanOutcomes = await mapWithConcurrency(projectDirectories, isMultiProject ? 4 : 1, async (projectDirectory) => {
|
|
96393
|
-
const scanOutcome = await scanProject(projectDirectory);
|
|
96394
|
-
finishedProjectCount += 1;
|
|
96395
|
-
batchSpinner?.update(`Scanning ${projectCount} projects… (${finishedProjectCount}/${projectCount})`);
|
|
96396
|
-
return scanOutcome;
|
|
96397
|
-
});
|
|
96398
|
-
} finally {
|
|
96399
|
-
if (ownsBatchSpinnerSilence) setSpinnerSilent(wasSpinnerSilent);
|
|
96400
|
-
batchSpinner?.stop();
|
|
96401
|
-
}
|
|
96402
|
-
for (const scanOutcome of scanOutcomes) {
|
|
96403
|
-
if (scanOutcome === null) continue;
|
|
96404
|
-
completedScans.push(scanOutcome);
|
|
96405
|
-
}
|
|
97156
|
+
const projectBatch = await runProjectScanBatch({
|
|
97157
|
+
projects: projectDirectories,
|
|
97158
|
+
isQuiet,
|
|
97159
|
+
isSilent: scanOptions.silent === true,
|
|
97160
|
+
scanProject
|
|
97161
|
+
});
|
|
97162
|
+
const completedScans = projectBatch.completedScans;
|
|
96406
97163
|
if (!isQuiet && isMultiProject && completedScans.length > 0) {
|
|
96407
97164
|
const showShareLink = !isShareOptedOut(completedScans, scanOptions.noScore) && !scanOptions.isCi;
|
|
96408
97165
|
await runPromise(printMultiProjectSummary({
|
|
@@ -96412,7 +97169,7 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
|
|
|
96412
97169
|
outputDirectory: flags.outputDir,
|
|
96413
97170
|
isOffline: !showShareLink,
|
|
96414
97171
|
projectName: Path.basename(resolvedDirectory),
|
|
96415
|
-
totalElapsedMilliseconds:
|
|
97172
|
+
totalElapsedMilliseconds: projectBatch.elapsedMilliseconds
|
|
96416
97173
|
}));
|
|
96417
97174
|
}
|
|
96418
97175
|
const selectedSurfaceDiagnostics = filterDiagnosticsByCategories(filterScansForSurface(completedScans, scanOptions.outputSurface ?? "cli"), categoryFilters);
|
|
@@ -97558,7 +98315,7 @@ ${highlighter.dim("Learn more:")}
|
|
|
97558
98315
|
${highlighter.info(CI_URL)}
|
|
97559
98316
|
`;
|
|
97560
98317
|
const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
|
|
97561
|
-
const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--lint", "enable linting").option("--no-lint", "skip linting").option("--dead-code", "enable dead-code analysis (default)").option("--no-dead-code", "skip dead-code analysis (unused files / exports / dependencies, circular imports)").option("--supply-chain", "enable the dependency supply-chain scan (default)").option("--no-supply-chain", "skip the dependency supply-chain scan (Socket.dev dependency health checks)").option("--verbose", "show every rule and per-file details (default shows top 3 rules)").option("--debug", "force a Sentry trace and print its id at the end (paste it into a bug report)").option("--output-dir <dir>", "directory for the full diagnostics dump (default: a temp folder)").option("--score", "output only the score").option("--json", "output a single structured JSON report (suppresses other output)").option("--json-compact", "with --json, emit compact JSON (no indentation)").option("--json-out <path>", "with --json, write the report to a file instead of stdout").option("-y, --yes", "skip prompts, scan all workspace projects").option("--no-parallel", "lint serially with one worker (default: parallel across CPU cores; set the worker count with REACT_DOCTOR_PARALLEL)").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple); overrides the `projects` config field").option("--scope <value>", "how much supported JS/TS and inline HTML script source to scan/report: full (default), files, changed (only new issues vs base), or lines (issues whose source spans touch changed lines)").option("--base <ref>", "base git ref for files/changed/lines scope (auto-detected when omitted)").option("--include-untracked", "with --scope files/changed/lines, also scan ordinary untracked files (respects .gitignore)").addOption(new Option("--diff [base]", "[deprecated] alias for --scope changed (pass `false` to force a full scan)").hideHelp()).addOption(new Option("--changed-files-from <file>", "scan source files listed in a newline-delimited changed-files file").hideHelp()).option("--no-score", "skip the score API, the share URL, and crash reporting").addOption(new Option("--category <category>", "only show diagnostics in a category (repeatable; e.g. Security)").argParser(collectCategoryOption)).option("--no-telemetry", "alias for --no-score (skip the score API, share URL, and crash reporting)").option("--staged", "scan only staged (git index) files for pre-commit hooks").option("--max-duration <seconds>", "scan time budget for the whole run, shared across workspace projects: past it, remaining lint batches and dead-code are skipped and partial results are reported (skipped files are listed in the JSON report)").option("--blocking <level>", "severity that fails CI: error (default), warning, or none (advisory)").addOption(new Option("--fail-on <level>", "[deprecated] alias for --blocking <level>").hideHelp()).option("--no-respect-inline-disables", "audit mode: neutralize inline lint suppressions before scanning").option("--warnings", "show warning-severity diagnostics (default)").option("--no-warnings", "hide warning-severity diagnostics (errors only)").option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderRootHelpEpilog);
|
|
98318
|
+
const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--lint", "enable linting").option("--no-lint", "skip linting").option("--dead-code", "enable dead-code analysis (default)").option("--no-dead-code", "skip dead-code analysis (unused files / exports / dependencies, circular imports)").option("--supply-chain", "enable the dependency supply-chain scan (default)").option("--no-supply-chain", "skip the dependency supply-chain scan (Socket.dev dependency health checks)").option("--verbose", "show every rule and per-file details (default shows top 3 rules)").option("--debug", "force a Sentry trace and print its id at the end (paste it into a bug report)").option("--output-dir <dir>", "directory for the full diagnostics dump (default: a temp folder)").option("--score", "output only the score").option("--json", "output a single structured JSON report (suppresses other output)").option("--json-compact", "with --json, emit compact JSON (no indentation)").option("--json-out <path>", "with --json, write the report to a file instead of stdout").option("-y, --yes", "skip prompts, scan all workspace projects").option("--no-parallel", "lint serially with one worker (default: parallel across CPU cores; set the worker count with REACT_DOCTOR_PARALLEL)").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple); overrides the `projects` config field").option("--scope <value>", "how much supported JS/TS and inline HTML script source to scan/report: full (default), files, changed (only new issues vs base), or lines (issues whose source spans touch changed lines)").option("--base <ref>", "base git ref for files/changed/lines scope (auto-detected when omitted)").option("--include-untracked", "with --scope files/changed/lines, also scan ordinary untracked files (respects .gitignore)").addOption(new Option("--diff [base]", "[deprecated] alias for --scope changed (pass `false` to force a full scan)").hideHelp()).addOption(new Option("--changed-files-from <file>", "scan source files listed in a newline-delimited changed-files file").hideHelp()).option("--no-score", "skip the score API, the share URL, and crash reporting").addOption(new Option("--category <category>", "only show diagnostics in a category (repeatable; e.g. Security)").argParser(collectCategoryOption)).option("--no-telemetry", "alias for --no-score (skip the score API, share URL, and crash reporting)").option("--staged", "scan only staged (git index) files for pre-commit hooks (honors --project and config `projects`; exits 0 when nothing is staged)").option("--max-duration <seconds>", "scan time budget for the whole run, shared across workspace projects: past it, remaining lint batches and dead-code are skipped and partial results are reported (skipped files are listed in the JSON report)").option("--blocking <level>", "severity that fails CI: error (default), warning, or none (advisory)").addOption(new Option("--fail-on <level>", "[deprecated] alias for --blocking <level>").hideHelp()).option("--no-respect-inline-disables", "audit mode: neutralize inline lint suppressions before scanning").option("--warnings", "show warning-severity diagnostics (default)").option("--no-warnings", "hide warning-severity diagnostics (errors only)").option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderRootHelpEpilog);
|
|
97562
98319
|
program.action(inspectAction);
|
|
97563
98320
|
program.command("design [directory]").description("Run only the focused UI design diagnostics").addHelpText("after", renderDesignHelpEpilog).action((directory, _options, command) => designAction(directory ?? ".", command.optsWithGlobals()));
|
|
97564
98321
|
program.command("why <location>").description("Explain why a rule fired (or why a suppression didn't apply) at a file:line").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple)").option("-c, --cwd <cwd>", "working directory", process.cwd()).option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").action((location, options) => whyAction(location, options));
|
|
@@ -97598,7 +98355,7 @@ program.command("experimental-tui [directory]", { hidden: true }).description("[
|
|
|
97598
98355
|
return;
|
|
97599
98356
|
}
|
|
97600
98357
|
recordCount(METRIC.cliInvoked, 1, { command: "experimental-tui" });
|
|
97601
|
-
const { runScanApp } = await import("./run-scan-app-
|
|
98358
|
+
const { runScanApp } = await import("./run-scan-app-DHRvqfkX.js");
|
|
97602
98359
|
const { shouldFail } = await runScanApp({
|
|
97603
98360
|
directory,
|
|
97604
98361
|
options: {
|
|
@@ -97638,7 +98395,7 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
97638
98395
|
handleError(error, { sentryEventId });
|
|
97639
98396
|
});
|
|
97640
98397
|
//#endregion
|
|
97641
|
-
export { toForwardSlashes as A, getCategoryImpact as B, buildRulePriorityMap as C, resolveBlockingLevel as D, formatLearnMoreLine as E, TUI_REPORT_DETAIL_WIDTH_FRACTION as F, runPromise as G, mapWithConcurrency as H, isCiEnvironment as I, succeed$3 as J, sync as K, DIAGNOSTIC_CATEGORY_BUCKETS as L, isUnicodeSupported as M, METRIC as N, isReactDoctorWorkflowInstalled as O, TUI_REPORT_COMPACT_MAX_ROWS as P, Progress as R, hasLintHardFailure as S, formatFixRecipeLine as T, mergeReactDoctorConfigs as U, highlighter as V, resolveScanTarget as W, canAnimateOnboarding as _, resolveCliInspectOptions as a, buildCodeFrame as b, detectLaunchableAgents as c, launchCliAgent as d, isShareOptedOut as f, doctorFace as g, easeOutCubic as h, selectProjects as i, findNearestPackageDirectory as j, recordCount as k, CLI_AGENT_BINARIES as l, printFooter as m, shouldFailScanGate as n, countUniqueScannedFiles as o,
|
|
98398
|
+
export { toForwardSlashes as A, getCategoryImpact as B, buildRulePriorityMap as C, resolveBlockingLevel as D, formatLearnMoreLine as E, TUI_REPORT_DETAIL_WIDTH_FRACTION as F, runPromise as G, mapWithConcurrency as H, isCiEnvironment as I, succeed$3 as J, sync as K, DIAGNOSTIC_CATEGORY_BUCKETS as L, isUnicodeSupported as M, METRIC as N, isReactDoctorWorkflowInstalled as O, TUI_REPORT_COMPACT_MAX_ROWS as P, Progress as R, hasLintHardFailure as S, formatFixRecipeLine as T, mergeReactDoctorConfigs as U, highlighter as V, resolveScanTarget as W, canAnimateOnboarding as _, resolveCliInspectOptions as a, buildCodeFrame as b, detectLaunchableAgents as c, launchCliAgent as d, isShareOptedOut as f, doctorFace as g, easeOutCubic as h, selectProjects as i, findNearestPackageDirectory as j, recordCount as k, CLI_AGENT_BINARIES as l, printFooter as m, shouldFailScanGate as n, countUniqueScannedFiles as o, createInvocationInspect as p, void_ as q, discoverWorkspacePackages as r, setUpGitHubActions as s, exitGracefully as t, copyToClipboard as u, computeProjectedScore as v, buildSortedRuleGroups as w, buildNoScoreMessage as x, formatElapsedTime as y, Reporter as z };
|
|
97642
98399
|
|
|
97643
98400
|
//# sourceMappingURL=cli.js.map
|
|
97644
|
-
//# debugId=
|
|
98401
|
+
//# debugId=3bff4f9b-31f8-5abe-b7a2-a0ab9f6a85b4
|