react-doctor 0.9.2-dev.b1352a2 → 0.9.2-dev.bf470d5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lsp.js CHANGED
@@ -5,7 +5,7 @@ import * as OS from "node:os";
5
5
  import os from "node:os";
6
6
  import * as Path from "node:path";
7
7
  import path from "node:path";
8
- import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
8
+ 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";
9
9
  import * as Crypto from "node:crypto";
10
10
  import crypto, { createHash } from "node:crypto";
11
11
  import * as NodeChildProcess from "node:child_process";
@@ -17,6 +17,7 @@ import { fileURLToPath } from "node:url";
17
17
  import { parseJSON5 } from "confbox";
18
18
  import { createJiti } from "jiti";
19
19
  import { ANALYZED_MANIFEST_FILENAMES, DEFAULT_EXTENSIONS } from "deslop-js/analyzed-inputs";
20
+ import { convertToTSX } from "@astrojs/compiler/sync";
20
21
  import { gzipSync } from "node:zlib";
21
22
  import { CodeActionKind, CodeActionTriggerKind, DidChangeWatchedFilesNotification, DocumentDiagnosticReportKind, FileChangeType, TextDocumentSyncKind, TextDocuments, createConnection } from "vscode-languageserver/node.js";
22
23
  import { TextDocument } from "vscode-languageserver-textdocument";
@@ -10280,7 +10281,7 @@ const Number$4 = globalThis.Number;
10280
10281
  * @category constructors
10281
10282
  * @since 2.0.0
10282
10283
  */
10283
- const parse = (s) => {
10284
+ const parse$1 = (s) => {
10284
10285
  if (s === "NaN") return some(NaN);
10285
10286
  if (s === "Infinity") return some(Infinity);
10286
10287
  if (s === "-Infinity") return some(-Infinity);
@@ -14334,12 +14335,12 @@ TaggedError("EncodingError");
14334
14335
  //#endregion
14335
14336
  //#region ../../node_modules/.pnpm/effect@4.0.0-beta.70/node_modules/effect/dist/internal/schema/annotations.js
14336
14337
  /** @internal */
14337
- function resolve(ast) {
14338
+ function resolve$1(ast) {
14338
14339
  return ast.checks ? ast.checks[ast.checks.length - 1].annotations : ast.annotations;
14339
14340
  }
14340
14341
  /** @internal */
14341
14342
  function resolveAt(key) {
14342
- return (ast) => resolve(ast)?.[key];
14343
+ return (ast) => resolve$1(ast)?.[key];
14343
14344
  }
14344
14345
  /** @internal */
14345
14346
  const resolveIdentifier = /* @__PURE__ */ resolveAt("identifier");
@@ -18091,7 +18092,7 @@ function asSync(parser) {
18091
18092
  }
18092
18093
  const recur$1 = /* @__PURE__ */ memoize((ast) => {
18093
18094
  let parser;
18094
- const astOptions = resolve(ast)?.["parseOptions"];
18095
+ const astOptions = resolve$1(ast)?.["parseOptions"];
18095
18096
  if (!ast.context && !ast.encoding && !ast.checks) return (ou, options) => {
18096
18097
  parser ??= ast.getParser(recur$1);
18097
18098
  if (astOptions) options = {
@@ -57696,7 +57697,7 @@ var UrlParamsError = class extends TaggedError("UrlParamsError") {};
57696
57697
  * @category converting
57697
57698
  * @since 4.0.0
57698
57699
  */
57699
- const makeUrl = (url, params, hash) => {
57700
+ const makeUrl$1 = (url, params, hash) => {
57700
57701
  try {
57701
57702
  const urlInstance = new URL(url, baseUrl());
57702
57703
  for (let i = 0; i < params.params.length; i++) {
@@ -58330,7 +58331,7 @@ const Proto$2 = {
58330
58331
  const make$10 = (f) => makeWith$1((effect) => flatMap$2(effect, (request) => withFiber((fiber) => {
58331
58332
  const scopedController = scopedRequests.get(request);
58332
58333
  const controller = scopedController ?? new AbortController();
58333
- const urlResult = makeUrl(request.url, request.urlParams, getOrUndefined(request.hash));
58334
+ const urlResult = makeUrl$1(request.url, request.urlParams, getOrUndefined(request.hash));
58334
58335
  if (isFailure(urlResult)) return fail$4(new HttpClientError({ reason: new InvalidUrlError({
58335
58336
  request,
58336
58337
  cause: urlResult.failure
@@ -58769,7 +58770,7 @@ const layer$7 = (loggers, options) => effect(CurrentLoggers, withFiber$1(fnUntra
58769
58770
  * @since 4.0.0
58770
58771
  */
58771
58772
  const policy = /* @__PURE__ */ forever$1.pipe(passthrough$2, /* @__PURE__ */ addDelay((error) => {
58772
- 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))));
58773
+ 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))));
58773
58774
  return succeed$2(seconds(1));
58774
58775
  }));
58775
58776
  /**
@@ -61411,6 +61412,428 @@ const layer = /* @__PURE__ */ succeed$3(Path$1)({
61411
61412
  toFileUrl
61412
61413
  });
61413
61414
  //#endregion
61415
+ //#region ../../node_modules/.pnpm/@jridgewell+sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
61416
+ var comma = ",".charCodeAt(0);
61417
+ ";".charCodeAt(0);
61418
+ var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
61419
+ var intToChar = new Uint8Array(64);
61420
+ var charToInt = new Uint8Array(128);
61421
+ for (let i = 0; i < chars.length; i++) {
61422
+ const c = chars.charCodeAt(i);
61423
+ intToChar[i] = c;
61424
+ charToInt[c] = i;
61425
+ }
61426
+ function decodeInteger(reader, relative) {
61427
+ let value = 0;
61428
+ let shift = 0;
61429
+ let integer = 0;
61430
+ do {
61431
+ integer = charToInt[reader.next()];
61432
+ value |= (integer & 31) << shift;
61433
+ shift += 5;
61434
+ } while (integer & 32);
61435
+ const shouldNegate = value & 1;
61436
+ value >>>= 1;
61437
+ if (shouldNegate) value = -2147483648 | -value;
61438
+ return relative + value;
61439
+ }
61440
+ function hasMoreVlq(reader, max) {
61441
+ if (reader.pos >= max) return false;
61442
+ return reader.peek() !== comma;
61443
+ }
61444
+ var StringReader = class {
61445
+ constructor(buffer) {
61446
+ this.pos = 0;
61447
+ this.buffer = buffer;
61448
+ }
61449
+ next() {
61450
+ return this.buffer.charCodeAt(this.pos++);
61451
+ }
61452
+ peek() {
61453
+ return this.buffer.charCodeAt(this.pos);
61454
+ }
61455
+ indexOf(char) {
61456
+ const { buffer, pos } = this;
61457
+ const idx = buffer.indexOf(char, pos);
61458
+ return idx === -1 ? buffer.length : idx;
61459
+ }
61460
+ };
61461
+ function decode(mappings) {
61462
+ const { length } = mappings;
61463
+ const reader = new StringReader(mappings);
61464
+ const decoded = [];
61465
+ let genColumn = 0;
61466
+ let sourcesIndex = 0;
61467
+ let sourceLine = 0;
61468
+ let sourceColumn = 0;
61469
+ let namesIndex = 0;
61470
+ do {
61471
+ const semi = reader.indexOf(";");
61472
+ const line = [];
61473
+ let sorted = true;
61474
+ let lastCol = 0;
61475
+ genColumn = 0;
61476
+ while (reader.pos < semi) {
61477
+ let seg;
61478
+ genColumn = decodeInteger(reader, genColumn);
61479
+ if (genColumn < lastCol) sorted = false;
61480
+ lastCol = genColumn;
61481
+ if (hasMoreVlq(reader, semi)) {
61482
+ sourcesIndex = decodeInteger(reader, sourcesIndex);
61483
+ sourceLine = decodeInteger(reader, sourceLine);
61484
+ sourceColumn = decodeInteger(reader, sourceColumn);
61485
+ if (hasMoreVlq(reader, semi)) {
61486
+ namesIndex = decodeInteger(reader, namesIndex);
61487
+ seg = [
61488
+ genColumn,
61489
+ sourcesIndex,
61490
+ sourceLine,
61491
+ sourceColumn,
61492
+ namesIndex
61493
+ ];
61494
+ } else seg = [
61495
+ genColumn,
61496
+ sourcesIndex,
61497
+ sourceLine,
61498
+ sourceColumn
61499
+ ];
61500
+ } else seg = [genColumn];
61501
+ line.push(seg);
61502
+ reader.pos++;
61503
+ }
61504
+ if (!sorted) sort(line);
61505
+ decoded.push(line);
61506
+ reader.pos = semi + 1;
61507
+ } while (reader.pos <= length);
61508
+ return decoded;
61509
+ }
61510
+ function sort(line) {
61511
+ line.sort(sortComparator$1);
61512
+ }
61513
+ function sortComparator$1(a, b) {
61514
+ return a[0] - b[0];
61515
+ }
61516
+ //#endregion
61517
+ //#region ../../node_modules/.pnpm/@jridgewell+resolve-uri@3.1.2/node_modules/@jridgewell/resolve-uri/dist/resolve-uri.mjs
61518
+ const schemeRegex = /^[\w+.-]+:\/\//;
61519
+ /**
61520
+ * Matches the parts of a URL:
61521
+ * 1. Scheme, including ":", guaranteed.
61522
+ * 2. User/password, including "@", optional.
61523
+ * 3. Host, guaranteed.
61524
+ * 4. Port, including ":", optional.
61525
+ * 5. Path, including "/", optional.
61526
+ * 6. Query, including "?", optional.
61527
+ * 7. Hash, including "#", optional.
61528
+ */
61529
+ const urlRegex = /^([\w+.-]+:)\/\/([^@/#?]*@)?([^:/#?]*)(:\d+)?(\/[^#?]*)?(\?[^#]*)?(#.*)?/;
61530
+ /**
61531
+ * File URLs are weird. They dont' need the regular `//` in the scheme, they may or may not start
61532
+ * with a leading `/`, they can have a domain (but only if they don't start with a Windows drive).
61533
+ *
61534
+ * 1. Host, optional.
61535
+ * 2. Path, which may include "/", guaranteed.
61536
+ * 3. Query, including "?", optional.
61537
+ * 4. Hash, including "#", optional.
61538
+ */
61539
+ const fileRegex = /^file:(?:\/\/((?![a-z]:)[^/#?]*)?)?(\/?[^#?]*)(\?[^#]*)?(#.*)?/i;
61540
+ function isAbsoluteUrl(input) {
61541
+ return schemeRegex.test(input);
61542
+ }
61543
+ function isSchemeRelativeUrl(input) {
61544
+ return input.startsWith("//");
61545
+ }
61546
+ function isAbsolutePath(input) {
61547
+ return input.startsWith("/");
61548
+ }
61549
+ function isFileUrl(input) {
61550
+ return input.startsWith("file:");
61551
+ }
61552
+ function isRelative(input) {
61553
+ return /^[.?#]/.test(input);
61554
+ }
61555
+ function parseAbsoluteUrl(input) {
61556
+ const match = urlRegex.exec(input);
61557
+ return makeUrl(match[1], match[2] || "", match[3], match[4] || "", match[5] || "/", match[6] || "", match[7] || "");
61558
+ }
61559
+ function parseFileUrl(input) {
61560
+ const match = fileRegex.exec(input);
61561
+ const path = match[2];
61562
+ return makeUrl("file:", "", match[1] || "", "", isAbsolutePath(path) ? path : "/" + path, match[3] || "", match[4] || "");
61563
+ }
61564
+ function makeUrl(scheme, user, host, port, path, query, hash) {
61565
+ return {
61566
+ scheme,
61567
+ user,
61568
+ host,
61569
+ port,
61570
+ path,
61571
+ query,
61572
+ hash,
61573
+ type: 7
61574
+ };
61575
+ }
61576
+ function parseUrl(input) {
61577
+ if (isSchemeRelativeUrl(input)) {
61578
+ const url = parseAbsoluteUrl("http:" + input);
61579
+ url.scheme = "";
61580
+ url.type = 6;
61581
+ return url;
61582
+ }
61583
+ if (isAbsolutePath(input)) {
61584
+ const url = parseAbsoluteUrl("http://foo.com" + input);
61585
+ url.scheme = "";
61586
+ url.host = "";
61587
+ url.type = 5;
61588
+ return url;
61589
+ }
61590
+ if (isFileUrl(input)) return parseFileUrl(input);
61591
+ if (isAbsoluteUrl(input)) return parseAbsoluteUrl(input);
61592
+ const url = parseAbsoluteUrl("http://foo.com/" + input);
61593
+ url.scheme = "";
61594
+ url.host = "";
61595
+ url.type = input ? input.startsWith("?") ? 3 : input.startsWith("#") ? 2 : 4 : 1;
61596
+ return url;
61597
+ }
61598
+ function stripPathFilename(path) {
61599
+ if (path.endsWith("/..")) return path;
61600
+ const index = path.lastIndexOf("/");
61601
+ return path.slice(0, index + 1);
61602
+ }
61603
+ function mergePaths(url, base) {
61604
+ normalizePath(base, base.type);
61605
+ if (url.path === "/") url.path = base.path;
61606
+ else url.path = stripPathFilename(base.path) + url.path;
61607
+ }
61608
+ /**
61609
+ * The path can have empty directories "//", unneeded parents "foo/..", or current directory
61610
+ * "foo/.". We need to normalize to a standard representation.
61611
+ */
61612
+ function normalizePath(url, type) {
61613
+ const rel = type <= 4;
61614
+ const pieces = url.path.split("/");
61615
+ let pointer = 1;
61616
+ let positive = 0;
61617
+ let addTrailingSlash = false;
61618
+ for (let i = 1; i < pieces.length; i++) {
61619
+ const piece = pieces[i];
61620
+ if (!piece) {
61621
+ addTrailingSlash = true;
61622
+ continue;
61623
+ }
61624
+ addTrailingSlash = false;
61625
+ if (piece === ".") continue;
61626
+ if (piece === "..") {
61627
+ if (positive) {
61628
+ addTrailingSlash = true;
61629
+ positive--;
61630
+ pointer--;
61631
+ } else if (rel) pieces[pointer++] = piece;
61632
+ continue;
61633
+ }
61634
+ pieces[pointer++] = piece;
61635
+ positive++;
61636
+ }
61637
+ let path = "";
61638
+ for (let i = 1; i < pointer; i++) path += "/" + pieces[i];
61639
+ if (!path || addTrailingSlash && !path.endsWith("/..")) path += "/";
61640
+ url.path = path;
61641
+ }
61642
+ /**
61643
+ * Attempts to resolve `input` URL/path relative to `base`.
61644
+ */
61645
+ function resolve(input, base) {
61646
+ if (!input && !base) return "";
61647
+ const url = parseUrl(input);
61648
+ let inputType = url.type;
61649
+ if (base && inputType !== 7) {
61650
+ const baseUrl = parseUrl(base);
61651
+ const baseType = baseUrl.type;
61652
+ switch (inputType) {
61653
+ case 1: url.hash = baseUrl.hash;
61654
+ case 2: url.query = baseUrl.query;
61655
+ case 3:
61656
+ case 4: mergePaths(url, baseUrl);
61657
+ case 5:
61658
+ url.user = baseUrl.user;
61659
+ url.host = baseUrl.host;
61660
+ url.port = baseUrl.port;
61661
+ case 6: url.scheme = baseUrl.scheme;
61662
+ }
61663
+ if (baseType > inputType) inputType = baseType;
61664
+ }
61665
+ normalizePath(url, inputType);
61666
+ const queryHash = url.query + url.hash;
61667
+ switch (inputType) {
61668
+ case 2:
61669
+ case 3: return queryHash;
61670
+ case 4: {
61671
+ const path = url.path.slice(1);
61672
+ if (!path) return queryHash || ".";
61673
+ if (isRelative(base || input) && !isRelative(path)) return "./" + path + queryHash;
61674
+ return path + queryHash;
61675
+ }
61676
+ case 5: return url.path + queryHash;
61677
+ default: return url.scheme + "//" + url.user + url.host + url.port + url.path + queryHash;
61678
+ }
61679
+ }
61680
+ //#endregion
61681
+ //#region ../../node_modules/.pnpm/@jridgewell+trace-mapping@0.3.31/node_modules/@jridgewell/trace-mapping/dist/trace-mapping.mjs
61682
+ function stripFilename(path) {
61683
+ if (!path) return "";
61684
+ const index = path.lastIndexOf("/");
61685
+ return path.slice(0, index + 1);
61686
+ }
61687
+ function resolver(mapUrl, sourceRoot) {
61688
+ const from = stripFilename(mapUrl);
61689
+ const prefix = sourceRoot ? sourceRoot + "/" : "";
61690
+ return (source) => resolve(prefix + (source || ""), from);
61691
+ }
61692
+ var COLUMN = 0;
61693
+ var SOURCES_INDEX = 1;
61694
+ var SOURCE_LINE = 2;
61695
+ var SOURCE_COLUMN = 3;
61696
+ var NAMES_INDEX = 4;
61697
+ function maybeSort(mappings, owned) {
61698
+ const unsortedIndex = nextUnsortedSegmentLine(mappings, 0);
61699
+ if (unsortedIndex === mappings.length) return mappings;
61700
+ if (!owned) mappings = mappings.slice();
61701
+ for (let i = unsortedIndex; i < mappings.length; i = nextUnsortedSegmentLine(mappings, i + 1)) mappings[i] = sortSegments(mappings[i], owned);
61702
+ return mappings;
61703
+ }
61704
+ function nextUnsortedSegmentLine(mappings, start) {
61705
+ for (let i = start; i < mappings.length; i++) if (!isSorted(mappings[i])) return i;
61706
+ return mappings.length;
61707
+ }
61708
+ function isSorted(line) {
61709
+ for (let j = 1; j < line.length; j++) if (line[j][COLUMN] < line[j - 1][COLUMN]) return false;
61710
+ return true;
61711
+ }
61712
+ function sortSegments(line, owned) {
61713
+ if (!owned) line = line.slice();
61714
+ return line.sort(sortComparator);
61715
+ }
61716
+ function sortComparator(a, b) {
61717
+ return a[COLUMN] - b[COLUMN];
61718
+ }
61719
+ var found = false;
61720
+ function binarySearch(haystack, needle, low, high) {
61721
+ while (low <= high) {
61722
+ const mid = low + (high - low >> 1);
61723
+ const cmp = haystack[mid][COLUMN] - needle;
61724
+ if (cmp === 0) {
61725
+ found = true;
61726
+ return mid;
61727
+ }
61728
+ if (cmp < 0) low = mid + 1;
61729
+ else high = mid - 1;
61730
+ }
61731
+ found = false;
61732
+ return low - 1;
61733
+ }
61734
+ function upperBound(haystack, needle, index) {
61735
+ for (let i = index + 1; i < haystack.length; index = i++) if (haystack[i][COLUMN] !== needle) break;
61736
+ return index;
61737
+ }
61738
+ function lowerBound(haystack, needle, index) {
61739
+ for (let i = index - 1; i >= 0; index = i--) if (haystack[i][COLUMN] !== needle) break;
61740
+ return index;
61741
+ }
61742
+ function memoizedState() {
61743
+ return {
61744
+ lastKey: -1,
61745
+ lastNeedle: -1,
61746
+ lastIndex: -1
61747
+ };
61748
+ }
61749
+ function memoizedBinarySearch(haystack, needle, state, key) {
61750
+ const { lastKey, lastNeedle, lastIndex } = state;
61751
+ let low = 0;
61752
+ let high = haystack.length - 1;
61753
+ if (key === lastKey) {
61754
+ if (needle === lastNeedle) {
61755
+ found = lastIndex !== -1 && haystack[lastIndex][COLUMN] === needle;
61756
+ return lastIndex;
61757
+ }
61758
+ if (needle >= lastNeedle) low = lastIndex === -1 ? 0 : lastIndex;
61759
+ else high = lastIndex;
61760
+ }
61761
+ state.lastKey = key;
61762
+ state.lastNeedle = needle;
61763
+ return state.lastIndex = binarySearch(haystack, needle, low, high);
61764
+ }
61765
+ function parse(map) {
61766
+ return typeof map === "string" ? JSON.parse(map) : map;
61767
+ }
61768
+ var LINE_GTR_ZERO = "`line` must be greater than 0 (lines start at line 1)";
61769
+ var COL_GTR_EQ_ZERO = "`column` must be greater than or equal to 0 (columns start at column 0)";
61770
+ var TraceMap = class {
61771
+ constructor(map, mapUrl) {
61772
+ const isString = typeof map === "string";
61773
+ if (!isString && map._decodedMemo) return map;
61774
+ const parsed = parse(map);
61775
+ const { version, file, names, sourceRoot, sources, sourcesContent } = parsed;
61776
+ this.version = version;
61777
+ this.file = file;
61778
+ this.names = names || [];
61779
+ this.sourceRoot = sourceRoot;
61780
+ this.sources = sources;
61781
+ this.sourcesContent = sourcesContent;
61782
+ this.ignoreList = parsed.ignoreList || parsed.x_google_ignoreList || void 0;
61783
+ const resolve = resolver(mapUrl, sourceRoot);
61784
+ this.resolvedSources = sources.map(resolve);
61785
+ const { mappings } = parsed;
61786
+ if (typeof mappings === "string") {
61787
+ this._encoded = mappings;
61788
+ this._decoded = void 0;
61789
+ } else if (Array.isArray(mappings)) {
61790
+ this._encoded = void 0;
61791
+ this._decoded = maybeSort(mappings, isString);
61792
+ } else if (parsed.sections) throw new Error(`TraceMap passed sectioned source map, please use FlattenMap export instead`);
61793
+ else throw new Error(`invalid source map: ${JSON.stringify(parsed)}`);
61794
+ this._decodedMemo = memoizedState();
61795
+ this._bySources = void 0;
61796
+ this._bySourceMemos = void 0;
61797
+ }
61798
+ };
61799
+ function cast(map) {
61800
+ return map;
61801
+ }
61802
+ function decodedMappings(map) {
61803
+ var _a;
61804
+ return (_a = cast(map))._decoded || (_a._decoded = decode(cast(map)._encoded));
61805
+ }
61806
+ function originalPositionFor(map, needle) {
61807
+ let { line, column, bias } = needle;
61808
+ line--;
61809
+ if (line < 0) throw new Error(LINE_GTR_ZERO);
61810
+ if (column < 0) throw new Error(COL_GTR_EQ_ZERO);
61811
+ const decoded = decodedMappings(map);
61812
+ if (line >= decoded.length) return OMapping(null, null, null, null);
61813
+ const segments = decoded[line];
61814
+ const index = traceSegmentInternal(segments, cast(map)._decodedMemo, line, column, bias || 1);
61815
+ if (index === -1) return OMapping(null, null, null, null);
61816
+ const segment = segments[index];
61817
+ if (segment.length === 1) return OMapping(null, null, null, null);
61818
+ const { names, resolvedSources } = map;
61819
+ return OMapping(resolvedSources[segment[SOURCES_INDEX]], segment[SOURCE_LINE] + 1, segment[SOURCE_COLUMN], segment.length === 5 ? names[segment[NAMES_INDEX]] : null);
61820
+ }
61821
+ function OMapping(source, line, column, name) {
61822
+ return {
61823
+ source,
61824
+ line,
61825
+ column,
61826
+ name
61827
+ };
61828
+ }
61829
+ function traceSegmentInternal(segments, memo, line, column, bias) {
61830
+ let index = memoizedBinarySearch(segments, column, memo, line);
61831
+ if (found) index = (bias === -1 ? upperBound : lowerBound)(segments, column, index);
61832
+ else if (bias === -1) index++;
61833
+ if (index === -1 || index === segments.length) return -1;
61834
+ return index;
61835
+ }
61836
+ //#endregion
61414
61837
  //#region ../core/dist/index.js
61415
61838
  var __create = Object.create;
61416
61839
  var __defProp = Object.defineProperty;
@@ -61480,7 +61903,7 @@ var AmbiguousProjectError = class extends Error {
61480
61903
  };
61481
61904
  const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
61482
61905
  const HTML_FILE_PATTERN = /\.html$/i;
61483
- const SOURCE_FILE_PATTERN = /\.(?:tsx?|jsx?|mts|mjs|[hH][tT][mM][lL])$/;
61906
+ const SOURCE_FILE_PATTERN = /\.(?:astro|tsx?|jsx?|mts|mjs|[hH][tT][mM][lL])$/;
61484
61907
  const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
61485
61908
  const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
61486
61909
  const MINIFIED_SNIFF_BYTES = 65536;
@@ -62231,6 +62654,7 @@ const FRAMEWORK_PACKAGES = {
62231
62654
  "@tanstack/react-start": "tanstack-start",
62232
62655
  "@remix-run/react": "remix",
62233
62656
  gatsby: "gatsby",
62657
+ astro: "astro",
62234
62658
  vite: "vite",
62235
62659
  "react-scripts": "cra",
62236
62660
  expo: "expo",
@@ -65302,7 +65726,7 @@ const evaluateSuppression = (lines, diagnosticLineIndex, ruleId) => {
65302
65726
  const getDiagnosticRuleIdentity = (diagnostic) => ({
65303
65727
  ruleKey: `${diagnostic.plugin}/${diagnostic.rule}`,
65304
65728
  category: diagnostic.category,
65305
- tags: diagnostic.plugin === "react-doctor" ? reactDoctorPlugin.rules[diagnostic.rule]?.tags ?? [] : []
65729
+ tags: diagnostic.plugin === "react-doctor" ? REACT_DOCTOR_RULE_REGISTRY[diagnostic.rule]?.tags ?? [] : []
65306
65730
  });
65307
65731
  const compileIgnoredFilePatterns = (userConfig) => {
65308
65732
  const files = userConfig?.ignore?.files;
@@ -65650,7 +66074,7 @@ const buildDiagnosticPipeline = (input) => {
65650
66074
  };
65651
66075
  const shouldAutoSuppress = (diagnostic) => {
65652
66076
  if (diagnostic.plugin !== "react-doctor") return false;
65653
- const rule = reactDoctorPlugin.rules[diagnostic.rule];
66077
+ const rule = REACT_DOCTOR_RULE_REGISTRY[diagnostic.rule];
65654
66078
  if (!rule?.tags?.includes("test-noise")) return false;
65655
66079
  if (rule.tags.includes("migration-hint")) return false;
65656
66080
  return getFileContext(diagnostic.filePath) !== "production";
@@ -66060,6 +66484,7 @@ var OxlintConcurrency = class extends Reference("react-doctor/OxlintConcurrency"
66060
66484
  if (Number.isInteger(parsed) && parsed > 0) return resolveScanConcurrency(parsed);
66061
66485
  return resolveAutoScanConcurrency();
66062
66486
  } }) {};
66487
+ var OxlintSpawnSlots = class extends Reference("react-doctor/OxlintSpawnSlots", { defaultValue: () => null }) {};
66063
66488
  /**
66064
66489
  * Three-state control for overlapping the dead-code pass with the lint pass —
66065
66490
  * forking dead-code as a child fiber that runs DURING lint instead of strictly
@@ -68334,8 +68759,8 @@ const getCapabilities = (project) => {
68334
68759
  const cached = capabilitiesByProject.get(project);
68335
68760
  if (cached !== void 0) return cached;
68336
68761
  const capabilities = new Set(buildCapabilities(project));
68337
- const packageJson = readPackageJson(Path.join(project.rootDirectory, "package.json"));
68338
- const targetBlankOpenerProtection = detectTargetBlankOpenerProtection(project.rootDirectory, packageJson);
68762
+ const capabilityRootDirectory = isFile(Path.join(project.rootDirectory, "package.json")) ? project.rootDirectory : findNearestAncestorPackageJson(project.rootDirectory) ?? project.rootDirectory;
68763
+ const targetBlankOpenerProtection = detectTargetBlankOpenerProtection(capabilityRootDirectory, readPackageJson(Path.join(capabilityRootDirectory, "package.json")));
68339
68764
  if (targetBlankOpenerProtection !== void 0) capabilities.add("target-blank-needs-explicit-protection");
68340
68765
  if (targetBlankOpenerProtection === "noreferrer") capabilities.add("target-blank-needs-noreferrer");
68341
68766
  capabilitiesByProject.set(project, capabilities);
@@ -68365,7 +68790,7 @@ const createSecurityScanSession = (rootDirectory, options) => {
68365
68790
  const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
68366
68791
  const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
68367
68792
  const includedTags = options.includedTags ?? /* @__PURE__ */ new Set();
68368
- const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
68793
+ const enabledScanRules = REACT_DOCTOR_SCAN_RULES.flatMap((entry) => {
68369
68794
  const rule = entry.rule;
68370
68795
  const scan = rule.scan;
68371
68796
  if (typeof scan !== "function") return [];
@@ -68810,47 +69235,55 @@ const resolveDeadCodeConcurrency = (facts = readSystemFacts()) => {
68810
69235
  const memoryBoundedWorkers = Math.floor(availableMemoryBytes / DEAD_CODE_WORKER_MEM_BUDGET_BYTES);
68811
69236
  return Math.max(1, Math.min(facts.availableCores, memoryBoundedWorkers));
68812
69237
  };
68813
- let availableSlots = -1;
68814
- const waiters = [];
68815
- const releaseSlot = () => {
68816
- const nextWaiter = waiters.shift();
68817
- if (nextWaiter !== void 0) nextWaiter();
68818
- else availableSlots += 1;
69238
+ const createWorkerSlots = (input) => {
69239
+ let availableSlotCount = input.slotCount;
69240
+ const waiters = [];
69241
+ const releaseSlot = () => {
69242
+ const nextWaiter = waiters.shift();
69243
+ if (nextWaiter === void 0) {
69244
+ availableSlotCount += 1;
69245
+ return;
69246
+ }
69247
+ nextWaiter.abortSignal?.removeEventListener("abort", nextWaiter.onAbort);
69248
+ nextWaiter.resolve();
69249
+ };
69250
+ const acquireSlot = async (abortSignal) => {
69251
+ if (abortSignal?.aborted) throw input.createAbortError();
69252
+ if (availableSlotCount > 0) {
69253
+ availableSlotCount -= 1;
69254
+ return;
69255
+ }
69256
+ await new Promise((resolve, reject) => {
69257
+ const onAbort = () => {
69258
+ const waiterIndex = waiters.indexOf(waiter);
69259
+ if (waiterIndex !== -1) waiters.splice(waiterIndex, 1);
69260
+ reject(input.createAbortError());
69261
+ };
69262
+ const waiter = {
69263
+ resolve,
69264
+ abortSignal,
69265
+ onAbort
69266
+ };
69267
+ waiters.push(waiter);
69268
+ abortSignal?.addEventListener("abort", onAbort, { once: true });
69269
+ });
69270
+ };
69271
+ return { run: async (task, abortSignal) => {
69272
+ await acquireSlot(abortSignal);
69273
+ try {
69274
+ return await task();
69275
+ } finally {
69276
+ releaseSlot();
69277
+ }
69278
+ } };
68819
69279
  };
68820
- /**
68821
- * Runs `task` once a dead-code worker slot is free, releasing the slot when the
68822
- * task settles (success or failure). With a high cap (roomy machine) every
68823
- * caller proceeds immediately; with a low cap (constrained runner) callers
68824
- * queue and run as slots free.
68825
- *
68826
- * `abortSignal` short-circuits the WAIT: if it's already aborted, or fires while
68827
- * this caller is queued, the call rejects without acquiring a slot or running
68828
- * `task` — so a cancelled scan (e.g. lint failed) doesn't sit in the queue and
68829
- * then spawn a child only to tear it down. A queued caller that aborts removes
68830
- * its own waiter so a later release never hands a slot to a dead request.
68831
- */
69280
+ let deadCodeWorkerSlots = null;
68832
69281
  const withDeadCodeWorkerSlot = async (task, abortSignal) => {
68833
- if (abortSignal?.aborted) throw new Error("Dead-code worker aborted.");
68834
- if (availableSlots < 0) availableSlots = resolveDeadCodeConcurrency();
68835
- if (availableSlots > 0) availableSlots -= 1;
68836
- else await new Promise((resolve, reject) => {
68837
- const waiter = () => {
68838
- abortSignal?.removeEventListener("abort", onAbort);
68839
- resolve();
68840
- };
68841
- const onAbort = () => {
68842
- const queuedIndex = waiters.indexOf(waiter);
68843
- if (queuedIndex !== -1) waiters.splice(queuedIndex, 1);
68844
- reject(/* @__PURE__ */ new Error("Dead-code worker aborted."));
68845
- };
68846
- waiters.push(waiter);
68847
- abortSignal?.addEventListener("abort", onAbort, { once: true });
69282
+ deadCodeWorkerSlots ??= createWorkerSlots({
69283
+ slotCount: resolveDeadCodeConcurrency(),
69284
+ createAbortError: () => /* @__PURE__ */ new Error("Dead-code worker aborted.")
68848
69285
  });
68849
- try {
68850
- return await task();
68851
- } finally {
68852
- releaseSlot();
68853
- }
69286
+ return deadCodeWorkerSlots.run(task, abortSignal);
68854
69287
  };
68855
69288
  const projectCacheSubdir = (projectDirectory) => crypto.createHash("sha256").update(projectDirectory).digest("hex").slice(0, 16);
68856
69289
  const resolveReactDoctorCacheDir = (projectDirectory) => {
@@ -69643,7 +70076,10 @@ var Git = class Git extends Service()("react-doctor/Git") {
69643
70076
  if (argvLengthChars > spawnArgsLengthCap) return yield* foldSpawnFailure(`spawn ENAMETOOLONG (${argvLengthChars} argv chars exceed ${spawnArgsLengthCap})`);
69644
70077
  const handle = yield* spawner.spawn(make$1(input.command, [...input.args], {
69645
70078
  cwd: input.directory,
69646
- env: input.env,
70079
+ env: input.command === "git" ? {
70080
+ ...input.env,
70081
+ GIT_DIR: void 0
70082
+ } : input.env,
69647
70083
  extendEnv: true
69648
70084
  }));
69649
70085
  const maxStdoutBytes = input.maxStdoutBytes;
@@ -69916,7 +70352,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
69916
70352
  "--diff-filter=ACMR",
69917
70353
  "--relative"
69918
70354
  ]).pipe(map$3((result) => {
69919
- if (result.status !== 0) return [];
70355
+ if (result.status !== 0) return null;
69920
70356
  return splitNullSeparated(result.stdout);
69921
70357
  })),
69922
70358
  showStagedContent: (directory, relativePath, options) => runCommand({
@@ -70374,12 +70810,12 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
70374
70810
  const settingsRootDirectory = resolveSettingsRootDirectory(project.rootDirectory);
70375
70811
  const enabledReactDoctorRules = {};
70376
70812
  for (const registryEntry of REACT_DOCTOR_RULES) {
70377
- const rule = reactDoctorPlugin.rules[registryEntry.id];
70813
+ const rule = REACT_DOCTOR_RULE_REGISTRY[registryEntry.id];
70378
70814
  if (!rule) continue;
70379
70815
  if (ruleSelection === "cacheable" && CROSS_FILE_RULE_IDS.has(registryEntry.id)) continue;
70380
70816
  if (ruleSelection === "sidecar" && !CROSS_FILE_RULE_IDS.has(registryEntry.id)) continue;
70381
70817
  if (ruleSelection === "sidecar" && sidecarRuleIdFilter !== void 0 && !sidecarRuleIdFilter.has(registryEntry.id)) continue;
70382
- if (rule.scan !== void 0) continue;
70818
+ if (rule.isScanRule) continue;
70383
70819
  if (customRulesOnly && registryEntry.originallyExternal) continue;
70384
70820
  if (rule.framework !== "global" && !rule.requires) continue;
70385
70821
  if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) continue;
@@ -71004,6 +71440,50 @@ const columnOfUtf8Offset = (sourceBuffer, utf8Offset) => {
71004
71440
  while (lineStartOffset > 0 && sourceBuffer[lineStartOffset - 1] !== 10) lineStartOffset--;
71005
71441
  return sourceBuffer.subarray(lineStartOffset, boundedOffset).toString("utf8").length + 1;
71006
71442
  };
71443
+ const utf8OffsetFromSourcePosition = (sourceBuffer, lineNumber, zeroBasedColumn) => {
71444
+ if (lineNumber < 1 || zeroBasedColumn < 0) return null;
71445
+ const sourceLines = sourceBuffer.toString("utf8").split("\n");
71446
+ const sourceLine = sourceLines[lineNumber - 1];
71447
+ if (sourceLine === void 0 || zeroBasedColumn > sourceLine.length) return null;
71448
+ const precedingLines = sourceLines.slice(0, lineNumber - 1).join("\n");
71449
+ return (lineNumber === 1 ? 0 : Buffer.byteLength(precedingLines) + Buffer.byteLength("\n")) + Buffer.byteLength(sourceLine.slice(0, zeroBasedColumn));
71450
+ };
71451
+ const mapPreparedSourceSpan = (span, preparedSourceMap) => {
71452
+ const generatedLine = lineOfUtf8Offset(preparedSourceMap.generatedBuffer, span.offset);
71453
+ const generatedColumn = columnOfUtf8Offset(preparedSourceMap.generatedBuffer, span.offset) - 1;
71454
+ const originalStart = originalPositionFor(preparedSourceMap.traceMap, {
71455
+ line: generatedLine,
71456
+ column: generatedColumn
71457
+ });
71458
+ if (originalStart.source === null || originalStart.line === null || originalStart.column === null) return null;
71459
+ const originalOffset = utf8OffsetFromSourcePosition(preparedSourceMap.sourceBuffer, originalStart.line, originalStart.column);
71460
+ if (originalOffset === null) return null;
71461
+ const generatedSpan = preparedSourceMap.generatedBuffer.subarray(span.offset, span.offset + span.length);
71462
+ return {
71463
+ offset: originalOffset,
71464
+ length: preparedSourceMap.sourceBuffer.subarray(originalOffset, originalOffset + generatedSpan.length).equals(generatedSpan) ? generatedSpan.length : 0,
71465
+ line: originalStart.line,
71466
+ column: originalStart.column + 1
71467
+ };
71468
+ };
71469
+ const mapPreparedSourceLabels = (labels, preparedSourceMap) => {
71470
+ const primaryLabel = labels[0];
71471
+ if (primaryLabel === void 0) return null;
71472
+ const primarySpan = mapPreparedSourceSpan(primaryLabel.span, preparedSourceMap);
71473
+ if (primarySpan === null) return null;
71474
+ const mappedLabels = [{
71475
+ ...primaryLabel,
71476
+ span: primarySpan
71477
+ }];
71478
+ for (const relatedLabel of labels.slice(1)) {
71479
+ const relatedSpan = mapPreparedSourceSpan(relatedLabel.span, preparedSourceMap);
71480
+ if (relatedSpan !== null) mappedLabels.push({
71481
+ ...relatedLabel,
71482
+ span: relatedSpan
71483
+ });
71484
+ }
71485
+ return mappedLabels;
71486
+ };
71007
71487
  const REDACTED_PLACEHOLDER = "<redacted>";
71008
71488
  const KEEP_PREFIX = `$1${REDACTED_PLACEHOLDER}`;
71009
71489
  const KNOWN_SECRET_RULES = [
@@ -71646,7 +72126,7 @@ const PLUGIN_CATEGORY_MAP = {
71646
72126
  };
71647
72127
  const lookupOwnString = (record, key) => Object.hasOwn(record, key) ? record[key] : void 0;
71648
72128
  const getRuleRecommendation = (ruleName, project) => {
71649
- const rule = reactDoctorPlugin.rules[ruleName];
72129
+ const rule = REACT_DOCTOR_RULE_REGISTRY[ruleName];
71650
72130
  if (!rule) return void 0;
71651
72131
  if (rule.recommendationFor) {
71652
72132
  const capabilities = getCapabilities(project);
@@ -71655,8 +72135,8 @@ const getRuleRecommendation = (ruleName, project) => {
71655
72135
  }
71656
72136
  return rule.recommendation;
71657
72137
  };
71658
- const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.category;
71659
- const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
72138
+ const getRuleCategory = (ruleName) => REACT_DOCTOR_RULE_REGISTRY[ruleName]?.category;
72139
+ const getRuleTitle = (ruleName) => REACT_DOCTOR_RULE_REGISTRY[ruleName]?.title;
71660
72140
  const resolveDiagnosticTitle = (plugin, rule) => {
71661
72141
  if (plugin !== "react-hooks-js") return getRuleTitle(rule);
71662
72142
  if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
@@ -71711,7 +72191,7 @@ const resolveDiagnosticCategory = (plugin, rule) => {
71711
72191
  if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
71712
72192
  return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
71713
72193
  };
71714
- const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
72194
+ const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(REACT_DOCTOR_RULE_REGISTRY[rule]?.matchByOccurrence);
71715
72195
  /**
71716
72196
  * Maps oxlint's non-primary labels (`labels[1..]`) into related source
71717
72197
  * locations. Editors surface these as a diagnostic's
@@ -71748,7 +72228,7 @@ const isOxlintOutput = (value) => isRecord(value) && Array.isArray(value.diagnos
71748
72228
  * to the first `{`. Raises `OxlintOutputUnparseable` when the
71749
72229
  * stdout isn't valid JSON or doesn't carry a `diagnostics` array.
71750
72230
  */
71751
- const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath) => {
72231
+ const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath, sourceMapByLintPath) => {
71752
72232
  if (!stdout) return [];
71753
72233
  const jsonStart = stdout.indexOf("{");
71754
72234
  const sanitizedStdout = jsonStart > 0 ? stdout.slice(jsonStart) : stdout;
@@ -71766,6 +72246,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath)
71766
72246
  const sourceLinesCache = /* @__PURE__ */ new Map();
71767
72247
  const resolveAbsolutePath = (filename) => Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
71768
72248
  const resolveMappedSourceFilename = (filename) => sourcePathByLintPath?.get(Path.normalize(resolveAbsolutePath(filename)));
72249
+ const resolvePreparedSourceMap = (filename) => sourceMapByLintPath?.get(Path.normalize(resolveAbsolutePath(filename)));
71769
72250
  const resolveSourceFilename = (filename) => resolveMappedSourceFilename(filename) ?? filename;
71770
72251
  const readSourceBuffer = (filename) => {
71771
72252
  const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
@@ -71797,7 +72278,19 @@ const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath)
71797
72278
  minifiedFileCache.set(absolutePath, minified);
71798
72279
  return minified;
71799
72280
  };
71800
- return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => isMappableOxlintDiagnostic(diagnostic) && isLintableSourceFile(resolveSourceFilename(diagnostic.filename)) && !(TYPESCRIPT_DECLARATION_FILE_PATTERN.test(diagnostic.filename) && OXLINT_IGNORED_DECLARATION_DIAGNOSTIC_CODES.has(diagnostic.code)) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
72281
+ return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.flatMap((diagnostic) => {
72282
+ const preparedSourceMap = resolvePreparedSourceMap(diagnostic.filename);
72283
+ if (preparedSourceMap === void 0) return [diagnostic];
72284
+ const { plugin, rule } = parseRuleCode(diagnostic.code);
72285
+ if (plugin !== "react-doctor" || !REACT_DOCTOR_RULE_REGISTRY[rule]?.tags?.includes("design")) return [];
72286
+ const labels = mapPreparedSourceLabels(diagnostic.labels, preparedSourceMap);
72287
+ const sourceFilename = resolveMappedSourceFilename(diagnostic.filename);
72288
+ return labels === null || sourceFilename === void 0 ? [] : [{
72289
+ ...diagnostic,
72290
+ filename: sourceFilename,
72291
+ labels
72292
+ }];
72293
+ }).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) => {
71801
72294
  const { plugin, rule } = parseRuleCode(diagnostic.code);
71802
72295
  const primaryLabel = diagnostic.labels[0];
71803
72296
  const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
@@ -71875,11 +72368,12 @@ const SANITIZED_ENV = buildOxlintChildEnv(process.env);
71875
72368
  * The first three are splittable (the caller's binary-split retry
71876
72369
  * shrinks the batch and re-spawns); the fourth isn't.
71877
72370
  */
71878
- const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLINT_SPAWN_TIMEOUT_MS, outputMaxBytes = OXLINT_OUTPUT_MAX_BYTES, abortSignal) => new Promise((resolve, reject) => {
72371
+ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLINT_SPAWN_TIMEOUT_MS, outputMaxBytes = OXLINT_OUTPUT_MAX_BYTES, abortSignal, onSpawn) => new Promise((resolve, reject) => {
71879
72372
  if (abortSignal?.aborted) {
71880
72373
  reject(new ReactDoctorError({ reason: new OxlintSpawnFailed({ cause: "lint phase aborted" }) }));
71881
72374
  return;
71882
72375
  }
72376
+ onSpawn?.();
71883
72377
  const child = spawn(nodeBinaryPath, buildProfiledNodeArguments({
71884
72378
  argumentsList: args,
71885
72379
  cpuProfileDirectory: SANITIZED_ENV.REACT_DOCTOR_CPU_PROFILE_DIR,
@@ -72015,7 +72509,7 @@ const isParallelismRelatedSpawnError = (error) => {
72015
72509
  * loop with a slimmer config in that case.
72016
72510
  */
72017
72511
  const spawnLintBatches = async (input) => {
72018
- const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
72512
+ const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, sourceMapByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
72019
72513
  const resolveSourcePath = (filePath) => {
72020
72514
  const absoluteFilePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory, filePath);
72021
72515
  return sourcePathByLintPath?.get(Path.normalize(absoluteFilePath)) ?? filePath;
@@ -72039,7 +72533,21 @@ const spawnLintBatches = async (input) => {
72039
72533
  }
72040
72534
  const batchArgs = [...baseArgs, ...batch];
72041
72535
  try {
72042
- return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory, sourcePathByLintPath);
72536
+ const spawnBatch = () => {
72537
+ if (isPastDeadline()) {
72538
+ deadlineSkippedFiles.push(...batch);
72539
+ batchState.deadlineSkippedFileCount += batch.length;
72540
+ return Promise.resolve(null);
72541
+ }
72542
+ return spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal, () => {
72543
+ if (batchState.didStart) return;
72544
+ batchState.didStart = true;
72545
+ startedFileCount += batchState.initialFileCount;
72546
+ });
72547
+ };
72548
+ const stdout = input.spawnSlots === void 0 ? await spawnBatch() : await input.spawnSlots.run(spawnBatch, signal);
72549
+ if (stdout === null) return [];
72550
+ return parseOxlintOutput(stdout, project, rootDirectory, sourcePathByLintPath, sourceMapByLintPath);
72043
72551
  } catch (error) {
72044
72552
  if (!isSplittableReactDoctorError(error)) throw error;
72045
72553
  if (isPastDeadline()) {
@@ -72083,14 +72591,15 @@ const spawnLintBatches = async (input) => {
72083
72591
  deadlineSkippedFiles.push(...batch);
72084
72592
  return [];
72085
72593
  }
72086
- startedFileCount += batch.length;
72087
72594
  const batchState = {
72088
72595
  deadlineMs: null,
72089
- deadlineSkippedFileCount: 0
72596
+ deadlineSkippedFileCount: 0,
72597
+ didStart: false,
72598
+ initialFileCount: batch.length
72090
72599
  };
72091
72600
  const batchDiagnostics = await spawnLintBatch(batch, 0, batchState);
72092
72601
  scannedFileCount += batch.length - batchState.deadlineSkippedFileCount;
72093
- if (passOnFileProgress) {
72602
+ if (passOnFileProgress && batchState.didStart) {
72094
72603
  displayedFileCount = Math.min(Math.max(displayedFileCount, scannedFileCount), totalFileCount);
72095
72604
  passOnFileProgress(displayedFileCount, totalFileCount);
72096
72605
  }
@@ -72174,8 +72683,8 @@ const validateRuleRegistration = () => {
72174
72683
  for (const fullKey of ALL_REACT_DOCTOR_RULE_KEYS) {
72175
72684
  const ruleName = fullKey.replace(/^react-doctor\//, "");
72176
72685
  if (!getRuleCategory(ruleName)) missingCategory.push(fullKey);
72177
- if (!reactDoctorPlugin.rules[ruleName]?.recommendation) missingHelp.push(fullKey);
72178
- if (FRAMEWORK_SPECIFIC_RULE_KEYS.has(fullKey) && !reactDoctorPlugin.rules[ruleName]?.requires) missingMetadata.push(fullKey);
72686
+ if (!REACT_DOCTOR_RULE_REGISTRY[ruleName]?.recommendation) missingHelp.push(fullKey);
72687
+ if (FRAMEWORK_SPECIFIC_RULE_KEYS.has(fullKey) && !REACT_DOCTOR_RULE_REGISTRY[ruleName]?.requires) missingMetadata.push(fullKey);
72179
72688
  }
72180
72689
  if (missingCategory.length === 0 && missingHelp.length === 0 && missingMetadata.length === 0) return;
72181
72690
  const detail = [
@@ -72478,20 +72987,47 @@ const prepareHtmlScriptSource = (sourceBuffer) => {
72478
72987
  lintBuffer: maskedBuffer ?? sourceBuffer
72479
72988
  };
72480
72989
  };
72481
- const prepareHtmlLintSources = (rootDirectory, temporaryDirectory, candidateFiles) => {
72990
+ const ASTRO_FILE_PATTERN = /\.astro$/;
72991
+ const prepareLintSources = (rootDirectory, temporaryDirectory, candidateFiles) => {
72482
72992
  const lintFiles = [];
72483
72993
  const sourcePathByLintPath = /* @__PURE__ */ new Map();
72994
+ const sourceMapByLintPath = /* @__PURE__ */ new Map();
72484
72995
  const sizeByLintPath = /* @__PURE__ */ new Map();
72485
72996
  const htmlSourcesDirectory = Path.join(temporaryDirectory, "html-sources");
72997
+ const astroSourcesDirectory = Path.join(temporaryDirectory, "astro-sources");
72486
72998
  let htmlFileIndex = 0;
72999
+ let astroFileIndex = 0;
72487
73000
  let hasThreeModuleImport = false;
72488
73001
  for (const candidateFile of candidateFiles) {
72489
- if (!HTML_FILE_PATTERN.test(candidateFile)) {
73002
+ if (!HTML_FILE_PATTERN.test(candidateFile) && !ASTRO_FILE_PATTERN.test(candidateFile)) {
72490
73003
  lintFiles.push(candidateFile);
72491
73004
  continue;
72492
73005
  }
72493
73006
  const absoluteSourcePath = Path.isAbsolute(candidateFile) ? candidateFile : Path.resolve(rootDirectory, candidateFile);
72494
73007
  const sourceBuffer = NFS.readFileSync(absoluteSourcePath);
73008
+ if (ASTRO_FILE_PATTERN.test(candidateFile)) {
73009
+ const compilerSourcePath = absoluteSourcePath.replaceAll("\\", "/");
73010
+ const convertedSource = convertToTSX(sourceBuffer.toString("utf8"), {
73011
+ filename: compilerSourcePath,
73012
+ sourcemap: "external",
73013
+ includeScripts: true
73014
+ });
73015
+ if (astroFileIndex === 0) NFS.mkdirSync(astroSourcesDirectory, { recursive: true });
73016
+ const lintPath = Path.join(astroSourcesDirectory, `${astroFileIndex}.tsx`);
73017
+ const generatedBuffer = Buffer.from(convertedSource.code);
73018
+ NFS.writeFileSync(lintPath, generatedBuffer);
73019
+ lintFiles.push(candidateFile);
73020
+ lintFiles.push(lintPath);
73021
+ sourcePathByLintPath.set(Path.resolve(lintPath), candidateFile);
73022
+ sourceMapByLintPath.set(Path.resolve(lintPath), {
73023
+ traceMap: new TraceMap(JSON.stringify(convertedSource.map)),
73024
+ generatedBuffer,
73025
+ sourceBuffer
73026
+ });
73027
+ sizeByLintPath.set(lintPath, sourceBuffer.length);
73028
+ astroFileIndex++;
73029
+ continue;
73030
+ }
72495
73031
  const { executableScriptBodies, lintBuffer } = prepareHtmlScriptSource(sourceBuffer);
72496
73032
  if (htmlFileIndex === 0) NFS.mkdirSync(htmlSourcesDirectory, { recursive: true });
72497
73033
  const lintPath = Path.join(htmlSourcesDirectory, `${htmlFileIndex}.astro`);
@@ -72505,6 +73041,7 @@ const prepareHtmlLintSources = (rootDirectory, temporaryDirectory, candidateFile
72505
73041
  return {
72506
73042
  lintFiles,
72507
73043
  sourcePathByLintPath,
73044
+ sourceMapByLintPath,
72508
73045
  sizeByLintPath,
72509
73046
  hasThreeModuleImport
72510
73047
  };
@@ -72723,10 +73260,10 @@ const runOxlint = async (options) => {
72723
73260
  rootDirectory,
72724
73261
  candidateFiles
72725
73262
  });
72726
- const preparedHtmlSources = prepareHtmlLintSources(rootDirectory, configDirectory, candidateFiles);
72727
- const lintFiles = preparedHtmlSources.lintFiles;
72728
- const hasHtmlFiles = preparedHtmlSources.sourcePathByLintPath.size > 0;
72729
- const lintProject = !project.hasThree && preparedHtmlSources.hasThreeModuleImport ? {
73263
+ const preparedLintSources = prepareLintSources(rootDirectory, configDirectory, candidateFiles);
73264
+ const lintFiles = preparedLintSources.lintFiles;
73265
+ const hasPreparedFiles = preparedLintSources.sourcePathByLintPath.size > 0;
73266
+ const lintProject = !project.hasThree && preparedLintSources.hasThreeModuleImport ? {
72730
73267
  ...project,
72731
73268
  hasThree: true
72732
73269
  } : project;
@@ -72748,7 +73285,7 @@ const runOxlint = async (options) => {
72748
73285
  sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
72749
73286
  });
72750
73287
  const sizeByFile = sizedScanFiles !== null && lintBatchOrdering === "cost" ? new Map(sizedScanFiles.map((entry) => [entry.path, entry.sizeBytes])) : null;
72751
- if (sizeByFile !== null) for (const [lintPath, sizeBytes] of preparedHtmlSources.sizeByLintPath) sizeByFile.set(lintPath, sizeBytes);
73288
+ if (sizeByFile !== null) for (const [lintPath, sizeBytes] of preparedLintSources.sizeByLintPath) sizeByFile.set(lintPath, sizeBytes);
72752
73289
  const buildFileBatches = (passBaseArgs, passFiles) => sizeByFile !== null ? planLintBatches({
72753
73290
  baseArgs: passBaseArgs,
72754
73291
  files: passFiles,
@@ -72778,7 +73315,8 @@ const runOxlint = async (options) => {
72778
73315
  rootDirectory,
72779
73316
  nodeBinaryPath,
72780
73317
  project: lintProject,
72781
- sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
73318
+ sourcePathByLintPath: preparedLintSources.sourcePathByLintPath,
73319
+ sourceMapByLintPath: preparedLintSources.sourceMapByLintPath,
72782
73320
  onPartialFailure: reportPartialFailure,
72783
73321
  onAnalyzedFiles: (filePaths) => {
72784
73322
  analyzedFiles = filePaths;
@@ -72787,6 +73325,7 @@ const runOxlint = async (options) => {
72787
73325
  spawnTimeoutMs,
72788
73326
  outputMaxBytes,
72789
73327
  concurrency: options.concurrency,
73328
+ spawnSlots: options.spawnSlots,
72790
73329
  signal: options.signal,
72791
73330
  deadlineEpochMs: options.deadlineEpochMs
72792
73331
  });
@@ -72813,7 +73352,7 @@ const runOxlint = async (options) => {
72813
73352
  };
72814
73353
  }
72815
73354
  };
72816
- if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0 && !hasHtmlFiles) {
73355
+ if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0 && !hasPreparedFiles) {
72817
73356
  const rulesetHash = computeRulesetHash({
72818
73357
  config: buildConfig({
72819
73358
  extendsPaths: [],
@@ -72979,7 +73518,8 @@ const runOxlint = async (options) => {
72979
73518
  rootDirectory,
72980
73519
  nodeBinaryPath,
72981
73520
  project: lintProject,
72982
- sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
73521
+ sourcePathByLintPath: preparedLintSources.sourcePathByLintPath,
73522
+ sourceMapByLintPath: preparedLintSources.sourceMapByLintPath,
72983
73523
  onPartialFailure,
72984
73524
  onAnalyzedFiles: (filePaths) => {
72985
73525
  analyzedFiles = filePaths;
@@ -72988,6 +73528,7 @@ const runOxlint = async (options) => {
72988
73528
  spawnTimeoutMs,
72989
73529
  outputMaxBytes,
72990
73530
  concurrency: options.concurrency,
73531
+ spawnSlots: options.spawnSlots,
72991
73532
  signal: options.signal,
72992
73533
  deadlineEpochMs: options.deadlineEpochMs
72993
73534
  });
@@ -73082,6 +73623,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
73082
73623
  const spawnTimeoutMs = yield* OxlintSpawnTimeoutMs;
73083
73624
  const outputMaxBytes = yield* OxlintOutputMaxBytes;
73084
73625
  const concurrency = yield* OxlintConcurrency;
73626
+ const spawnSlots = yield* OxlintSpawnSlots;
73085
73627
  const lintBatchOrdering = yield* LintBatchOrdering;
73086
73628
  const perFileLintCacheEnabled = yield* PerFileLintCacheEnabled;
73087
73629
  const sidecarLintCacheEnabled = yield* SidecarLintCacheEnabled;
@@ -73111,6 +73653,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
73111
73653
  onSidecarStats: input.onSidecarStats,
73112
73654
  spawnTimeoutMs,
73113
73655
  outputMaxBytes,
73656
+ spawnSlots: spawnSlots ?? void 0,
73114
73657
  concurrency,
73115
73658
  signal,
73116
73659
  lintBatchOrdering,
@@ -74328,10 +74871,14 @@ const materializeSourceTree = (input) => gen(function* () {
74328
74871
  materializedFiles.push(relativePath);
74329
74872
  }
74330
74873
  yield* sync(() => {
74331
- for (const configFilename of STAGED_FILES_PROJECT_CONFIG_FILENAMES) {
74332
- const sourcePath = path.join(input.directory, configFilename);
74333
- const targetPath = path.join(resolvedTempDirectory, configFilename);
74334
- if (fs.existsSync(sourcePath) && !fs.existsSync(targetPath)) fs.cpSync(sourcePath, targetPath);
74874
+ for (const subdirectory of ["", ...input.configSubdirectories ?? []]) for (const configFilename of STAGED_FILES_PROJECT_CONFIG_FILENAMES) {
74875
+ const sourcePath = path.join(input.directory, subdirectory, configFilename);
74876
+ const targetPath = path.resolve(resolvedTempDirectory, subdirectory, configFilename);
74877
+ if (!isPathInsideDirectory(targetPath, resolvedTempDirectory)) continue;
74878
+ if (fs.existsSync(sourcePath) && !fs.existsSync(targetPath)) {
74879
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
74880
+ fs.cpSync(sourcePath, targetPath);
74881
+ }
74335
74882
  }
74336
74883
  });
74337
74884
  return {
@@ -74352,15 +74899,17 @@ const materializeSourceTree = (input) => gen(function* () {
74352
74899
  static layerNode = effect(StagedFiles, gen(function* () {
74353
74900
  const git = yield* Git;
74354
74901
  return StagedFiles.of({
74355
- discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries.filter(isLintableSourceFile)), withSpan("StagedFiles.discoverSourceFiles")),
74356
- materialize: ({ directory, stagedFiles, tempDirectory }) => materializeSourceTree({
74902
+ discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries === null ? null : entries.filter(isLintableSourceFile)), withSpan("StagedFiles.discoverSourceFiles")),
74903
+ materialize: ({ directory, stagedFiles, tempDirectory, configSubdirectories }) => materializeSourceTree({
74357
74904
  directory,
74358
74905
  files: stagedFiles,
74359
74906
  tempDirectory,
74907
+ configSubdirectories,
74360
74908
  readContent: (relativePath) => git.showStagedContent(directory, relativePath, { maxBufferBytes: GIT_SHOW_MAX_BUFFER_BYTES })
74361
74909
  }).pipe(map$3((tree) => ({
74362
74910
  tempDirectory: tree.tempDirectory,
74363
74911
  stagedFiles: tree.materializedFiles,
74912
+ unmaterializedFiles: tree.unmaterializedFiles,
74364
74913
  cleanup: tree.cleanup
74365
74914
  })), withSpan("StagedFiles.materialize"))
74366
74915
  });
@@ -74375,6 +74924,7 @@ const materializeSourceTree = (input) => gen(function* () {
74375
74924
  materialize: ({ tempDirectory }) => succeed$2({
74376
74925
  tempDirectory,
74377
74926
  stagedFiles: snapshot.materializedFiles ?? snapshot.sourceFiles ?? [],
74927
+ unmaterializedFiles: [],
74378
74928
  cleanup: () => {}
74379
74929
  })
74380
74930
  }));
@@ -74474,7 +75024,7 @@ const runEditorScan = async (input) => {
74474
75024
  * other `clear*` helpers.
74475
75025
  */
74476
75026
  const clearAutoSuppressionCaches = () => {};
74477
- const lookupOwnRule = (rule) => Object.hasOwn(reactDoctorPlugin.rules, rule) ? reactDoctorPlugin.rules[rule] : void 0;
75027
+ const lookupOwnRule = (rule) => Object.hasOwn(REACT_DOCTOR_RULE_REGISTRY, rule) ? REACT_DOCTOR_RULE_REGISTRY[rule] : void 0;
74478
75028
  /**
74479
75029
  * Returns presentation metadata for `<plugin>/<rule>`, or `null` when the
74480
75030
  * rule is not part of the bundled react-doctor plugin (e.g. an adopted
@@ -76207,6 +76757,7 @@ const METRIC = {
76207
76757
  cliError: "cli.error",
76208
76758
  cliEnvironmentError: "cli.env_error",
76209
76759
  stagedSnapshotDivergence: "staged.snapshot_divergence",
76760
+ stagedPerProject: "staged.per_project",
76210
76761
  projectDetected: "project.detected",
76211
76762
  projectPathSelected: "project.path_selected",
76212
76763
  projectConfigSelected: "project.config_selected",
@@ -76549,5 +77100,5 @@ const startLanguageServer = () => {
76549
77100
  };
76550
77101
  //#endregion
76551
77102
  export { startLanguageServer };
76552
- !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]="d58404fe-4e69-5868-81c2-97b15676ab73")}catch(e){}}();
76553
- //# debugId=d58404fe-4e69-5868-81c2-97b15676ab73
77103
+ !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]="ec49e114-f0f3-593d-b3c1-8b1a04d065a6")}catch(e){}}();
77104
+ //# debugId=ec49e114-f0f3-593d-b3c1-8b1a04d065a6