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/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]="a53d2e7d-c9bc-5c54-b965-3a988afa3832")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="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,7 +8,7 @@ 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 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";
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";
@@ -20,6 +20,7 @@ import os, { tmpdir } from "node:os";
20
20
  import { parseJSON5 } from "confbox";
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" ? reactDoctorPlugin.rules[diagnostic.rule]?.tags ?? [] : []
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;
@@ -68798,7 +69222,7 @@ const buildDiagnosticPipeline = (input) => {
68798
69222
  };
68799
69223
  const shouldAutoSuppress = (diagnostic) => {
68800
69224
  if (diagnostic.plugin !== "react-doctor") return false;
68801
- const rule = reactDoctorPlugin.rules[diagnostic.rule];
69225
+ const rule = REACT_DOCTOR_RULE_REGISTRY[diagnostic.rule];
68802
69226
  if (!rule?.tags?.includes("test-noise")) return false;
68803
69227
  if (rule.tags.includes("migration-hint")) return false;
68804
69228
  return getFileContext(diagnostic.filePath) !== "production";
@@ -69230,6 +69654,7 @@ var OxlintConcurrency = class extends Reference("react-doctor/OxlintConcurrency"
69230
69654
  if (Number.isInteger(parsed) && parsed > 0) return resolveScanConcurrency(parsed);
69231
69655
  return resolveAutoScanConcurrency();
69232
69656
  } }) {};
69657
+ var OxlintSpawnSlots = class extends Reference("react-doctor/OxlintSpawnSlots", { defaultValue: () => null }) {};
69233
69658
  /**
69234
69659
  * Three-state control for overlapping the dead-code pass with the lint pass —
69235
69660
  * forking dead-code as a child fiber that runs DURING lint instead of strictly
@@ -71580,8 +72005,8 @@ const getCapabilities = (project) => {
71580
72005
  const cached = capabilitiesByProject.get(project);
71581
72006
  if (cached !== void 0) return cached;
71582
72007
  const capabilities = new Set(buildCapabilities(project));
71583
- const packageJson = readPackageJson$1(Path.join(project.rootDirectory, "package.json"));
71584
- const targetBlankOpenerProtection = detectTargetBlankOpenerProtection(project.rootDirectory, packageJson);
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")));
71585
72010
  if (targetBlankOpenerProtection !== void 0) capabilities.add("target-blank-needs-explicit-protection");
71586
72011
  if (targetBlankOpenerProtection === "noreferrer") capabilities.add("target-blank-needs-noreferrer");
71587
72012
  capabilitiesByProject.set(project, capabilities);
@@ -71611,7 +72036,7 @@ const createSecurityScanSession = (rootDirectory, options) => {
71611
72036
  const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
71612
72037
  const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
71613
72038
  const includedTags = options.includedTags ?? /* @__PURE__ */ new Set();
71614
- const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
72039
+ const enabledScanRules = REACT_DOCTOR_SCAN_RULES.flatMap((entry) => {
71615
72040
  const rule = entry.rule;
71616
72041
  const scan = rule.scan;
71617
72042
  if (typeof scan !== "function") return [];
@@ -72072,47 +72497,55 @@ const resolveDeadCodeConcurrency = (facts = readSystemFacts()) => {
72072
72497
  const memoryBoundedWorkers = Math.floor(availableMemoryBytes / DEAD_CODE_WORKER_MEM_BUDGET_BYTES);
72073
72498
  return Math.max(1, Math.min(facts.availableCores, memoryBoundedWorkers));
72074
72499
  };
72075
- let availableSlots = -1;
72076
- const waiters = [];
72077
- const releaseSlot = () => {
72078
- const nextWaiter = waiters.shift();
72079
- if (nextWaiter !== void 0) nextWaiter();
72080
- else availableSlots += 1;
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
+ } };
72081
72541
  };
72082
- /**
72083
- * Runs `task` once a dead-code worker slot is free, releasing the slot when the
72084
- * task settles (success or failure). With a high cap (roomy machine) every
72085
- * caller proceeds immediately; with a low cap (constrained runner) callers
72086
- * queue and run as slots free.
72087
- *
72088
- * `abortSignal` short-circuits the WAIT: if it's already aborted, or fires while
72089
- * this caller is queued, the call rejects without acquiring a slot or running
72090
- * `task` — so a cancelled scan (e.g. lint failed) doesn't sit in the queue and
72091
- * then spawn a child only to tear it down. A queued caller that aborts removes
72092
- * its own waiter so a later release never hands a slot to a dead request.
72093
- */
72542
+ let deadCodeWorkerSlots = null;
72094
72543
  const withDeadCodeWorkerSlot = async (task, abortSignal) => {
72095
- if (abortSignal?.aborted) throw new Error("Dead-code worker aborted.");
72096
- if (availableSlots < 0) availableSlots = resolveDeadCodeConcurrency();
72097
- if (availableSlots > 0) availableSlots -= 1;
72098
- else await new Promise((resolve, reject) => {
72099
- const waiter = () => {
72100
- abortSignal?.removeEventListener("abort", onAbort);
72101
- resolve();
72102
- };
72103
- const onAbort = () => {
72104
- const queuedIndex = waiters.indexOf(waiter);
72105
- if (queuedIndex !== -1) waiters.splice(queuedIndex, 1);
72106
- reject(/* @__PURE__ */ new Error("Dead-code worker aborted."));
72107
- };
72108
- waiters.push(waiter);
72109
- abortSignal?.addEventListener("abort", onAbort, { once: true });
72544
+ deadCodeWorkerSlots ??= createWorkerSlots({
72545
+ slotCount: resolveDeadCodeConcurrency(),
72546
+ createAbortError: () => /* @__PURE__ */ new Error("Dead-code worker aborted.")
72110
72547
  });
72111
- try {
72112
- return await task();
72113
- } finally {
72114
- releaseSlot();
72115
- }
72548
+ return deadCodeWorkerSlots.run(task, abortSignal);
72116
72549
  };
72117
72550
  const projectCacheSubdir = (projectDirectory) => crypto.createHash("sha256").update(projectDirectory).digest("hex").slice(0, 16);
72118
72551
  const resolveReactDoctorCacheDir = (projectDirectory) => {
@@ -72905,7 +73338,10 @@ var Git = class Git extends Service()("react-doctor/Git") {
72905
73338
  if (argvLengthChars > spawnArgsLengthCap) return yield* foldSpawnFailure(`spawn ENAMETOOLONG (${argvLengthChars} argv chars exceed ${spawnArgsLengthCap})`);
72906
73339
  const handle = yield* spawner.spawn(make$1(input.command, [...input.args], {
72907
73340
  cwd: input.directory,
72908
- env: input.env,
73341
+ env: input.command === "git" ? {
73342
+ ...input.env,
73343
+ GIT_DIR: void 0
73344
+ } : input.env,
72909
73345
  extendEnv: true
72910
73346
  }));
72911
73347
  const maxStdoutBytes = input.maxStdoutBytes;
@@ -73178,7 +73614,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
73178
73614
  "--diff-filter=ACMR",
73179
73615
  "--relative"
73180
73616
  ]).pipe(map$3((result) => {
73181
- if (result.status !== 0) return [];
73617
+ if (result.status !== 0) return null;
73182
73618
  return splitNullSeparated(result.stdout);
73183
73619
  })),
73184
73620
  showStagedContent: (directory, relativePath, options) => runCommand({
@@ -73636,12 +74072,12 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
73636
74072
  const settingsRootDirectory = resolveSettingsRootDirectory(project.rootDirectory);
73637
74073
  const enabledReactDoctorRules = {};
73638
74074
  for (const registryEntry of REACT_DOCTOR_RULES) {
73639
- const rule = reactDoctorPlugin.rules[registryEntry.id];
74075
+ const rule = REACT_DOCTOR_RULE_REGISTRY[registryEntry.id];
73640
74076
  if (!rule) continue;
73641
74077
  if (ruleSelection === "cacheable" && CROSS_FILE_RULE_IDS.has(registryEntry.id)) continue;
73642
74078
  if (ruleSelection === "sidecar" && !CROSS_FILE_RULE_IDS.has(registryEntry.id)) continue;
73643
74079
  if (ruleSelection === "sidecar" && sidecarRuleIdFilter !== void 0 && !sidecarRuleIdFilter.has(registryEntry.id)) continue;
73644
- if (rule.scan !== void 0) continue;
74080
+ if (rule.isScanRule) continue;
73645
74081
  if (customRulesOnly && registryEntry.originallyExternal) continue;
73646
74082
  if (rule.framework !== "global" && !rule.requires) continue;
73647
74083
  if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) continue;
@@ -74266,6 +74702,50 @@ const columnOfUtf8Offset = (sourceBuffer, utf8Offset) => {
74266
74702
  while (lineStartOffset > 0 && sourceBuffer[lineStartOffset - 1] !== 10) lineStartOffset--;
74267
74703
  return sourceBuffer.subarray(lineStartOffset, boundedOffset).toString("utf8").length + 1;
74268
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
+ };
74269
74749
  const REDACTED_PLACEHOLDER = "<redacted>";
74270
74750
  const KEEP_PREFIX = `$1${REDACTED_PLACEHOLDER}`;
74271
74751
  const KNOWN_SECRET_RULES = [
@@ -74908,7 +75388,7 @@ const PLUGIN_CATEGORY_MAP = {
74908
75388
  };
74909
75389
  const lookupOwnString = (record, key) => Object.hasOwn(record, key) ? record[key] : void 0;
74910
75390
  const getRuleRecommendation = (ruleName, project) => {
74911
- const rule = reactDoctorPlugin.rules[ruleName];
75391
+ const rule = REACT_DOCTOR_RULE_REGISTRY[ruleName];
74912
75392
  if (!rule) return void 0;
74913
75393
  if (rule.recommendationFor) {
74914
75394
  const capabilities = getCapabilities(project);
@@ -74917,8 +75397,8 @@ const getRuleRecommendation = (ruleName, project) => {
74917
75397
  }
74918
75398
  return rule.recommendation;
74919
75399
  };
74920
- const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.category;
74921
- const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
75400
+ const getRuleCategory = (ruleName) => REACT_DOCTOR_RULE_REGISTRY[ruleName]?.category;
75401
+ const getRuleTitle = (ruleName) => REACT_DOCTOR_RULE_REGISTRY[ruleName]?.title;
74922
75402
  const resolveDiagnosticTitle = (plugin, rule) => {
74923
75403
  if (plugin !== "react-hooks-js") return getRuleTitle(rule);
74924
75404
  if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
@@ -74973,7 +75453,7 @@ const resolveDiagnosticCategory = (plugin, rule) => {
74973
75453
  if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
74974
75454
  return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
74975
75455
  };
74976
- const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
75456
+ const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(REACT_DOCTOR_RULE_REGISTRY[rule]?.matchByOccurrence);
74977
75457
  /**
74978
75458
  * Maps oxlint's non-primary labels (`labels[1..]`) into related source
74979
75459
  * locations. Editors surface these as a diagnostic's
@@ -75010,7 +75490,7 @@ const isOxlintOutput = (value) => isRecord$1(value) && Array.isArray(value.diagn
75010
75490
  * to the first `{`. Raises `OxlintOutputUnparseable` when the
75011
75491
  * stdout isn't valid JSON or doesn't carry a `diagnostics` array.
75012
75492
  */
75013
- const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath) => {
75493
+ const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath, sourceMapByLintPath) => {
75014
75494
  if (!stdout) return [];
75015
75495
  const jsonStart = stdout.indexOf("{");
75016
75496
  const sanitizedStdout = jsonStart > 0 ? stdout.slice(jsonStart) : stdout;
@@ -75028,6 +75508,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath)
75028
75508
  const sourceLinesCache = /* @__PURE__ */ new Map();
75029
75509
  const resolveAbsolutePath = (filename) => Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
75030
75510
  const resolveMappedSourceFilename = (filename) => sourcePathByLintPath?.get(Path.normalize(resolveAbsolutePath(filename)));
75511
+ const resolvePreparedSourceMap = (filename) => sourceMapByLintPath?.get(Path.normalize(resolveAbsolutePath(filename)));
75031
75512
  const resolveSourceFilename = (filename) => resolveMappedSourceFilename(filename) ?? filename;
75032
75513
  const readSourceBuffer = (filename) => {
75033
75514
  const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
@@ -75059,7 +75540,19 @@ const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath)
75059
75540
  minifiedFileCache.set(absolutePath, minified);
75060
75541
  return minified;
75061
75542
  };
75062
- 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) => {
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) => {
75063
75556
  const { plugin, rule } = parseRuleCode(diagnostic.code);
75064
75557
  const primaryLabel = diagnostic.labels[0];
75065
75558
  const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
@@ -75137,11 +75630,12 @@ const SANITIZED_ENV = buildOxlintChildEnv(process.env);
75137
75630
  * The first three are splittable (the caller's binary-split retry
75138
75631
  * shrinks the batch and re-spawns); the fourth isn't.
75139
75632
  */
75140
- 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) => {
75141
75634
  if (abortSignal?.aborted) {
75142
75635
  reject(new ReactDoctorError({ reason: new OxlintSpawnFailed({ cause: "lint phase aborted" }) }));
75143
75636
  return;
75144
75637
  }
75638
+ onSpawn?.();
75145
75639
  const child = spawn(nodeBinaryPath, buildProfiledNodeArguments({
75146
75640
  argumentsList: args,
75147
75641
  cpuProfileDirectory: SANITIZED_ENV.REACT_DOCTOR_CPU_PROFILE_DIR,
@@ -75277,7 +75771,7 @@ const isParallelismRelatedSpawnError = (error) => {
75277
75771
  * loop with a slimmer config in that case.
75278
75772
  */
75279
75773
  const spawnLintBatches = async (input) => {
75280
- 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;
75281
75775
  const resolveSourcePath = (filePath) => {
75282
75776
  const absoluteFilePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory, filePath);
75283
75777
  return sourcePathByLintPath?.get(Path.normalize(absoluteFilePath)) ?? filePath;
@@ -75301,7 +75795,21 @@ const spawnLintBatches = async (input) => {
75301
75795
  }
75302
75796
  const batchArgs = [...baseArgs, ...batch];
75303
75797
  try {
75304
- return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory, sourcePathByLintPath);
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);
75305
75813
  } catch (error) {
75306
75814
  if (!isSplittableReactDoctorError(error)) throw error;
75307
75815
  if (isPastDeadline()) {
@@ -75345,14 +75853,15 @@ const spawnLintBatches = async (input) => {
75345
75853
  deadlineSkippedFiles.push(...batch);
75346
75854
  return [];
75347
75855
  }
75348
- startedFileCount += batch.length;
75349
75856
  const batchState = {
75350
75857
  deadlineMs: null,
75351
- deadlineSkippedFileCount: 0
75858
+ deadlineSkippedFileCount: 0,
75859
+ didStart: false,
75860
+ initialFileCount: batch.length
75352
75861
  };
75353
75862
  const batchDiagnostics = await spawnLintBatch(batch, 0, batchState);
75354
75863
  scannedFileCount += batch.length - batchState.deadlineSkippedFileCount;
75355
- if (passOnFileProgress) {
75864
+ if (passOnFileProgress && batchState.didStart) {
75356
75865
  displayedFileCount = Math.min(Math.max(displayedFileCount, scannedFileCount), totalFileCount);
75357
75866
  passOnFileProgress(displayedFileCount, totalFileCount);
75358
75867
  }
@@ -75436,8 +75945,8 @@ const validateRuleRegistration = () => {
75436
75945
  for (const fullKey of ALL_REACT_DOCTOR_RULE_KEYS) {
75437
75946
  const ruleName = fullKey.replace(/^react-doctor\//, "");
75438
75947
  if (!getRuleCategory(ruleName)) missingCategory.push(fullKey);
75439
- if (!reactDoctorPlugin.rules[ruleName]?.recommendation) missingHelp.push(fullKey);
75440
- if (FRAMEWORK_SPECIFIC_RULE_KEYS.has(fullKey) && !reactDoctorPlugin.rules[ruleName]?.requires) missingMetadata.push(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);
75441
75950
  }
75442
75951
  if (missingCategory.length === 0 && missingHelp.length === 0 && missingMetadata.length === 0) return;
75443
75952
  const detail = [
@@ -75740,20 +76249,47 @@ const prepareHtmlScriptSource = (sourceBuffer) => {
75740
76249
  lintBuffer: maskedBuffer ?? sourceBuffer
75741
76250
  };
75742
76251
  };
75743
- const prepareHtmlLintSources = (rootDirectory, temporaryDirectory, candidateFiles) => {
76252
+ const ASTRO_FILE_PATTERN = /\.astro$/;
76253
+ const prepareLintSources = (rootDirectory, temporaryDirectory, candidateFiles) => {
75744
76254
  const lintFiles = [];
75745
76255
  const sourcePathByLintPath = /* @__PURE__ */ new Map();
76256
+ const sourceMapByLintPath = /* @__PURE__ */ new Map();
75746
76257
  const sizeByLintPath = /* @__PURE__ */ new Map();
75747
76258
  const htmlSourcesDirectory = Path.join(temporaryDirectory, "html-sources");
76259
+ const astroSourcesDirectory = Path.join(temporaryDirectory, "astro-sources");
75748
76260
  let htmlFileIndex = 0;
76261
+ let astroFileIndex = 0;
75749
76262
  let hasThreeModuleImport = false;
75750
76263
  for (const candidateFile of candidateFiles) {
75751
- if (!HTML_FILE_PATTERN.test(candidateFile)) {
76264
+ if (!HTML_FILE_PATTERN.test(candidateFile) && !ASTRO_FILE_PATTERN.test(candidateFile)) {
75752
76265
  lintFiles.push(candidateFile);
75753
76266
  continue;
75754
76267
  }
75755
76268
  const absoluteSourcePath = Path.isAbsolute(candidateFile) ? candidateFile : Path.resolve(rootDirectory, candidateFile);
75756
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
+ }
75757
76293
  const { executableScriptBodies, lintBuffer } = prepareHtmlScriptSource(sourceBuffer);
75758
76294
  if (htmlFileIndex === 0) NFS.mkdirSync(htmlSourcesDirectory, { recursive: true });
75759
76295
  const lintPath = Path.join(htmlSourcesDirectory, `${htmlFileIndex}.astro`);
@@ -75767,6 +76303,7 @@ const prepareHtmlLintSources = (rootDirectory, temporaryDirectory, candidateFile
75767
76303
  return {
75768
76304
  lintFiles,
75769
76305
  sourcePathByLintPath,
76306
+ sourceMapByLintPath,
75770
76307
  sizeByLintPath,
75771
76308
  hasThreeModuleImport
75772
76309
  };
@@ -75985,10 +76522,10 @@ const runOxlint = async (options) => {
75985
76522
  rootDirectory,
75986
76523
  candidateFiles
75987
76524
  });
75988
- const preparedHtmlSources = prepareHtmlLintSources(rootDirectory, configDirectory, candidateFiles);
75989
- const lintFiles = preparedHtmlSources.lintFiles;
75990
- const hasHtmlFiles = preparedHtmlSources.sourcePathByLintPath.size > 0;
75991
- const lintProject = !project.hasThree && preparedHtmlSources.hasThreeModuleImport ? {
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 ? {
75992
76529
  ...project,
75993
76530
  hasThree: true
75994
76531
  } : project;
@@ -76010,7 +76547,7 @@ const runOxlint = async (options) => {
76010
76547
  sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
76011
76548
  });
76012
76549
  const sizeByFile = sizedScanFiles !== null && lintBatchOrdering === "cost" ? new Map(sizedScanFiles.map((entry) => [entry.path, entry.sizeBytes])) : null;
76013
- if (sizeByFile !== null) for (const [lintPath, sizeBytes] of preparedHtmlSources.sizeByLintPath) sizeByFile.set(lintPath, sizeBytes);
76550
+ if (sizeByFile !== null) for (const [lintPath, sizeBytes] of preparedLintSources.sizeByLintPath) sizeByFile.set(lintPath, sizeBytes);
76014
76551
  const buildFileBatches = (passBaseArgs, passFiles) => sizeByFile !== null ? planLintBatches({
76015
76552
  baseArgs: passBaseArgs,
76016
76553
  files: passFiles,
@@ -76040,7 +76577,8 @@ const runOxlint = async (options) => {
76040
76577
  rootDirectory,
76041
76578
  nodeBinaryPath,
76042
76579
  project: lintProject,
76043
- sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
76580
+ sourcePathByLintPath: preparedLintSources.sourcePathByLintPath,
76581
+ sourceMapByLintPath: preparedLintSources.sourceMapByLintPath,
76044
76582
  onPartialFailure: reportPartialFailure,
76045
76583
  onAnalyzedFiles: (filePaths) => {
76046
76584
  analyzedFiles = filePaths;
@@ -76049,6 +76587,7 @@ const runOxlint = async (options) => {
76049
76587
  spawnTimeoutMs,
76050
76588
  outputMaxBytes,
76051
76589
  concurrency: options.concurrency,
76590
+ spawnSlots: options.spawnSlots,
76052
76591
  signal: options.signal,
76053
76592
  deadlineEpochMs: options.deadlineEpochMs
76054
76593
  });
@@ -76075,7 +76614,7 @@ const runOxlint = async (options) => {
76075
76614
  };
76076
76615
  }
76077
76616
  };
76078
- if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0 && !hasHtmlFiles) {
76617
+ if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0 && !hasPreparedFiles) {
76079
76618
  const rulesetHash = computeRulesetHash({
76080
76619
  config: buildConfig({
76081
76620
  extendsPaths: [],
@@ -76241,7 +76780,8 @@ const runOxlint = async (options) => {
76241
76780
  rootDirectory,
76242
76781
  nodeBinaryPath,
76243
76782
  project: lintProject,
76244
- sourcePathByLintPath: preparedHtmlSources.sourcePathByLintPath,
76783
+ sourcePathByLintPath: preparedLintSources.sourcePathByLintPath,
76784
+ sourceMapByLintPath: preparedLintSources.sourceMapByLintPath,
76245
76785
  onPartialFailure,
76246
76786
  onAnalyzedFiles: (filePaths) => {
76247
76787
  analyzedFiles = filePaths;
@@ -76250,6 +76790,7 @@ const runOxlint = async (options) => {
76250
76790
  spawnTimeoutMs,
76251
76791
  outputMaxBytes,
76252
76792
  concurrency: options.concurrency,
76793
+ spawnSlots: options.spawnSlots,
76253
76794
  signal: options.signal,
76254
76795
  deadlineEpochMs: options.deadlineEpochMs
76255
76796
  });
@@ -76344,6 +76885,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
76344
76885
  const spawnTimeoutMs = yield* OxlintSpawnTimeoutMs;
76345
76886
  const outputMaxBytes = yield* OxlintOutputMaxBytes;
76346
76887
  const concurrency = yield* OxlintConcurrency;
76888
+ const spawnSlots = yield* OxlintSpawnSlots;
76347
76889
  const lintBatchOrdering = yield* LintBatchOrdering;
76348
76890
  const perFileLintCacheEnabled = yield* PerFileLintCacheEnabled;
76349
76891
  const sidecarLintCacheEnabled = yield* SidecarLintCacheEnabled;
@@ -76373,6 +76915,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
76373
76915
  onSidecarStats: input.onSidecarStats,
76374
76916
  spawnTimeoutMs,
76375
76917
  outputMaxBytes,
76918
+ spawnSlots: spawnSlots ?? void 0,
76376
76919
  concurrency,
76377
76920
  signal,
76378
76921
  lintBatchOrdering,
@@ -77601,10 +78144,14 @@ const materializeSourceTree = (input) => gen(function* () {
77601
78144
  materializedFiles.push(relativePath);
77602
78145
  }
77603
78146
  yield* sync(() => {
77604
- for (const configFilename of STAGED_FILES_PROJECT_CONFIG_FILENAMES) {
77605
- const sourcePath = path.join(input.directory, configFilename);
77606
- const targetPath = path.join(resolvedTempDirectory, configFilename);
77607
- if (fs.existsSync(sourcePath) && !fs.existsSync(targetPath)) fs.cpSync(sourcePath, targetPath);
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
+ }
77608
78155
  }
77609
78156
  });
77610
78157
  return {
@@ -77637,15 +78184,17 @@ var StagedFiles = class StagedFiles extends Service()("react-doctor/StagedFiles"
77637
78184
  static layerNode = effect(StagedFiles, gen(function* () {
77638
78185
  const git = yield* Git;
77639
78186
  return StagedFiles.of({
77640
- discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries.filter(isLintableSourceFile)), withSpan("StagedFiles.discoverSourceFiles")),
77641
- 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({
77642
78189
  directory,
77643
78190
  files: stagedFiles,
77644
78191
  tempDirectory,
78192
+ configSubdirectories,
77645
78193
  readContent: (relativePath) => git.showStagedContent(directory, relativePath, { maxBufferBytes: GIT_SHOW_MAX_BUFFER_BYTES })
77646
78194
  }).pipe(map$3((tree) => ({
77647
78195
  tempDirectory: tree.tempDirectory,
77648
78196
  stagedFiles: tree.materializedFiles,
78197
+ unmaterializedFiles: tree.unmaterializedFiles,
77649
78198
  cleanup: tree.cleanup
77650
78199
  })), withSpan("StagedFiles.materialize"))
77651
78200
  });
@@ -77660,6 +78209,7 @@ var StagedFiles = class StagedFiles extends Service()("react-doctor/StagedFiles"
77660
78209
  materialize: ({ tempDirectory }) => succeed$2({
77661
78210
  tempDirectory,
77662
78211
  stagedFiles: snapshot.materializedFiles ?? snapshot.sourceFiles ?? [],
78212
+ unmaterializedFiles: [],
77663
78213
  cleanup: () => {}
77664
78214
  })
77665
78215
  }));
@@ -78028,6 +78578,11 @@ const computeConfigFingerprint = (projectDirectory, version) => {
78028
78578
  }
78029
78579
  return crypto.createHash("sha1").update(parts.join("|")).digest("hex");
78030
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
+ });
78031
78586
  const AI_TRAINING_ENV_VARS = [
78032
78587
  ["HF_DATASETS_CACHE", "huggingface"],
78033
78588
  ["HF_HOME", "huggingface"],
@@ -78107,7 +78662,7 @@ const groupBy = (items, keyFn) => {
78107
78662
  * recipe, so advertising "fetch the fix recipe" for them sends agents to
78108
78663
  * a 404. Gate the directive on this predicate.
78109
78664
  */
78110
- const hasPublishedFixRecipe = (diagnostic) => diagnostic.plugin === "react-doctor" && Object.hasOwn(reactDoctorPlugin.rules, diagnostic.rule);
78665
+ const hasPublishedFixRecipe = (diagnostic) => diagnostic.plugin === "react-doctor" && Object.hasOwn(REACT_DOCTOR_RULE_REGISTRY, diagnostic.rule);
78111
78666
  const unionValues = (baseValues, overrideValues) => [...new Set([...baseValues, ...overrideValues])];
78112
78667
  const mergeIgnores = (baseIgnore, overrideIgnore) => {
78113
78668
  const mergedIgnore = {
@@ -78369,6 +78924,7 @@ const METRIC = {
78369
78924
  cliError: "cli.error",
78370
78925
  cliEnvironmentError: "cli.env_error",
78371
78926
  stagedSnapshotDivergence: "staged.snapshot_divergence",
78927
+ stagedPerProject: "staged.per_project",
78372
78928
  projectDetected: "project.detected",
78373
78929
  projectPathSelected: "project.path_selected",
78374
78930
  projectConfigSelected: "project.config_selected",
@@ -78454,7 +79010,7 @@ const makeNoopConsole = () => ({
78454
79010
  });
78455
79011
  //#endregion
78456
79012
  //#region src/cli/utils/version.ts
78457
- const VERSION = "0.9.2-dev.b1352a2";
79013
+ const VERSION = "0.9.2-dev.bf470d5";
78458
79014
  //#endregion
78459
79015
  //#region src/cli/utils/json-mode.ts
78460
79016
  let context = null;
@@ -78812,13 +79368,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
78812
79368
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
78813
79369
  * standard `SENTRY_RELEASE` override.
78814
79370
  */
78815
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.2-dev.b1352a2`;
79371
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.2-dev.bf470d5`;
78816
79372
  /**
78817
79373
  * Deployment environment shown in Sentry's environment filter. Defaults to
78818
79374
  * `production` for tagged releases and `development` for dev/unbuilt versions,
78819
79375
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
78820
79376
  */
78821
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.2-dev.b1352a2") ? "development" : "production");
79377
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.2-dev.bf470d5") ? "development" : "production");
78822
79378
  /**
78823
79379
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
78824
79380
  * (set to `0` to disable tracing) and falls back to
@@ -90672,7 +91228,8 @@ const buildRuntimeLayers = (input) => {
90672
91228
  resolvedDirectory: input.directory,
90673
91229
  configSourceDirectory: input.configSourceDirectory
90674
91230
  }) : Config.layerNode, Files.layerNode, Git.layerNode, linterLayer, LintPartialFailures.layerLive, deadCodeLayer, progressLayer, reporterLayer, scoreLayer, supplyChainLayer);
90675
- return input.oxlintConcurrency === void 0 ? baseLayers : mergeAll$1(baseLayers, succeed$3(OxlintConcurrency, input.oxlintConcurrency));
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));
90676
91233
  };
90677
91234
  //#endregion
90678
91235
  //#region src/cli/utils/with-sentry-run-span.ts
@@ -92275,16 +92832,19 @@ const formatClusterLocation = (cluster, resolveSourceRoot, hyperlinks) => {
92275
92832
  if (!hyperlinks) return `${location}${contextTag}`;
92276
92833
  return `${formatHyperlink(location, pathToFileURL(resolveAbsolutePath(lead.filePath, resolveSourceRoot(lead))).href)}${contextTag}`;
92277
92834
  };
92278
- const buildDiagnosticClusterLines = (cluster, resolveSourceRoot, renderCodeFrame, hyperlinks) => {
92835
+ const buildDiagnosticClusterLines = (cluster, resolveSourceRoot, resolveFrameSourceRoot, renderCodeFrame, hyperlinks) => {
92279
92836
  const lead = cluster.diagnostics[0];
92280
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;
92281
92841
  const lines = ["", highlighter.gray(`${TOP_ERROR_DETAIL_INDENT}${formatClusterLocation(cluster, resolveSourceRoot, hyperlinks)}`)];
92282
92842
  const codeFrame = renderCodeFrame ? buildCodeFrame({
92283
- filePath: lead.filePath,
92843
+ filePath: frameFilePath,
92284
92844
  line: cluster.startLine,
92285
92845
  column: isMultiSite ? 0 : lead.column,
92286
92846
  endLine: isMultiSite ? cluster.endLine : void 0,
92287
- rootDirectory: resolveSourceRoot(lead)
92847
+ rootDirectory: frameSourceRoot
92288
92848
  }) : null;
92289
92849
  if (codeFrame) {
92290
92850
  const boxInnerWidth = resolveMeasureWidth(8);
@@ -92297,7 +92857,7 @@ const buildDiagnosticClusterLines = (cluster, resolveSourceRoot, renderCodeFrame
92297
92857
  }
92298
92858
  return lines;
92299
92859
  };
92300
- const buildRuleDetailBlock = (ruleKey, ruleDiagnostics, resolveSourceRoot, renderEverySite, isAgentEnvironment, hyperlinks) => {
92860
+ const buildRuleDetailBlock = (ruleKey, ruleDiagnostics, resolveSourceRoot, resolveFrameSourceRoot, renderEverySite, isAgentEnvironment, hyperlinks) => {
92301
92861
  const representative = pickRepresentativeDiagnostic(ruleDiagnostics);
92302
92862
  const { severity } = representative;
92303
92863
  const trailingBadge = formatTrailingSiteBadge(ruleDiagnostics.length);
@@ -92319,7 +92879,7 @@ const buildRuleDetailBlock = (ruleKey, ruleDiagnostics, resolveSourceRoot, rende
92319
92879
  }
92320
92880
  const renderCodeFrame = severity === "error";
92321
92881
  const sites = renderEverySite ? ruleDiagnostics : [representative];
92322
- 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));
92323
92883
  return lines;
92324
92884
  };
92325
92885
  const selectErrorRuleGroups = (diagnostics, rulePriority) => buildSortedRuleGroups(diagnostics.filter((diagnostic) => diagnostic.severity === "error"), rulePriority);
@@ -92345,7 +92905,7 @@ const buildMigrationScaleAdvisoryLines = (diagnostics) => {
92345
92905
  return lines;
92346
92906
  };
92347
92907
  const getTopErrorRuleKeys = (diagnostics, limit, rulePriority) => new Set(selectTopErrorRuleGroups(diagnostics, limit, rulePriority).map(([ruleKey]) => ruleKey));
92348
- const buildTopErrorsSection = (diagnostics, resolveSourceRoot, hyperlinks, rulePriority) => {
92908
+ const buildTopErrorsSection = (diagnostics, resolveSourceRoot, resolveFrameSourceRoot, hyperlinks, rulePriority) => {
92349
92909
  const topRuleGroups = selectErrorRuleGroups(diagnostics, rulePriority).slice(0, 3);
92350
92910
  if (topRuleGroups.length === 0) return {
92351
92911
  lines: [],
@@ -92355,7 +92915,7 @@ const buildTopErrorsSection = (diagnostics, resolveSourceRoot, hyperlinks, ruleP
92355
92915
  const blockOffsets = [];
92356
92916
  for (const [ruleKey, ruleDiagnostics] of topRuleGroups) {
92357
92917
  blockOffsets.push(lines.length);
92358
- lines.push(...buildRuleDetailBlock(ruleKey, ruleDiagnostics, resolveSourceRoot, false, false, hyperlinks));
92918
+ lines.push(...buildRuleDetailBlock(ruleKey, ruleDiagnostics, resolveSourceRoot, resolveFrameSourceRoot, false, false, hyperlinks));
92359
92919
  lines.push("");
92360
92920
  }
92361
92921
  return {
@@ -92393,18 +92953,19 @@ const buildOverviewHeaderLines = (diagnostics) => {
92393
92953
  * single Effect.forEach over Console.log so failures or fiber
92394
92954
  * interruption produce predictable partial output.
92395
92955
  */
92396
- 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* () {
92397
92957
  const sectionPause = onboarding.sectionPause ?? void_;
92398
92958
  const animateCountUp = onboarding.animateCountUp ?? false;
92399
92959
  const resolveSourceRoot = typeof sourceRoot === "function" ? sourceRoot : () => sourceRoot;
92960
+ const resolveFrameSourceRoot = typeof frameSourceRoot === "function" ? frameSourceRoot : () => frameSourceRoot;
92400
92961
  let detailLines;
92401
92962
  let topErrorBlockOffsets = [];
92402
92963
  if (!isVerbose) {
92403
- const topErrors = buildTopErrorsSection(diagnostics, resolveSourceRoot, hyperlinks, rulePriority);
92964
+ const topErrors = buildTopErrorsSection(diagnostics, resolveSourceRoot, resolveFrameSourceRoot, hyperlinks, rulePriority);
92404
92965
  detailLines = topErrors.lines;
92405
92966
  topErrorBlockOffsets = topErrors.blockOffsets;
92406
92967
  } else detailLines = buildSortedRuleGroups(diagnostics, rulePriority).flatMap(([ruleKey, ruleDiagnostics]) => {
92407
- return [...buildRuleDetailBlock(ruleKey, ruleDiagnostics, resolveSourceRoot, true, isAgentEnvironment, hyperlinks), ""];
92968
+ return [...buildRuleDetailBlock(ruleKey, ruleDiagnostics, resolveSourceRoot, resolveFrameSourceRoot, true, isAgentEnvironment, hyperlinks), ""];
92408
92969
  });
92409
92970
  const overflowLine = isVerbose ? void 0 : buildOverflowSummaryLine(diagnostics, rulePriority);
92410
92971
  const categoryTallies = buildCategoryDiagnosticGroups(diagnostics, rulePriority).map(buildCategoryTally);
@@ -93172,7 +93733,7 @@ const buildRunEventConfig = (options, userConfig, hasCustomConfig, resolvedWorke
93172
93733
  userConfig
93173
93734
  };
93174
93735
  };
93175
- const inspect = async (directory, inputOptions = {}) => {
93736
+ const inspectWithOxlintRuntime = async (directory, inputOptions, oxlintRuntime) => {
93176
93737
  const startTime = performance$1.now();
93177
93738
  const deadlineEpochMs = inputOptions.deadlineEpochMs ?? (inputOptions.maxDurationMs != null ? Date.now() + inputOptions.maxDurationMs : null);
93178
93739
  const isConcurrentScan = inputOptions.concurrentScan === true;
@@ -93198,7 +93759,7 @@ const inspect = async (directory, inputOptions = {}) => {
93198
93759
  try {
93199
93760
  const result = await withSentryRunSpan(async (rootSentrySpan) => {
93200
93761
  try {
93201
- return await runInspectWithRuntime(scanDirectory, options, userConfig, hasConfigOverride, configSourceDirectory, startTime, deadlineEpochMs, rootSentrySpan);
93762
+ return await runInspectWithRuntime(scanDirectory, options, userConfig, hasConfigOverride, configSourceDirectory, startTime, deadlineEpochMs, rootSentrySpan, oxlintRuntime);
93202
93763
  } catch (error) {
93203
93764
  recordRunEvent(rootSentrySpan, {
93204
93765
  ...buildRunEventConfig(options, userConfig, userConfig !== null),
@@ -93214,6 +93775,15 @@ const inspect = async (directory, inputOptions = {}) => {
93214
93775
  if (ownsSpinnerSilence) setSpinnerSilent(wasSpinnerSilent);
93215
93776
  }
93216
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);
93217
93787
  const countIncompleteLintFiles = (lintPartialFailures) => countDroppedLintFiles(lintPartialFailures) + countDeadlineSkippedFiles(lintPartialFailures);
93218
93788
  /**
93219
93789
  * Runs a second, lint-only scan over the changed files as they existed at the
@@ -93267,7 +93837,8 @@ const runBaselineComparison = async (params) => {
93267
93837
  shouldRunSupplyChain: params.options.supplyChain,
93268
93838
  shouldComputeScore: false,
93269
93839
  shouldShowProgressSpinners: false,
93270
- oxlintConcurrency: params.options.concurrency
93840
+ oxlintConcurrency: params.oxlintRuntime.concurrency,
93841
+ oxlintSpawnSlots: params.oxlintRuntime.spawnSlots
93271
93842
  });
93272
93843
  const baseOutput = await runPromise(restoreLegacyThrow(runInspect({
93273
93844
  directory: snapshot.tempDirectory,
@@ -93312,7 +93883,7 @@ const runBaselineComparison = async (params) => {
93312
93883
  snapshot.cleanup();
93313
93884
  }
93314
93885
  };
93315
- const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOverride, configSourceDirectory, startTime, deadlineEpochMs, rootSentrySpan) => {
93886
+ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOverride, configSourceDirectory, startTime, deadlineEpochMs, rootSentrySpan, oxlintRuntime) => {
93316
93887
  const isDiffMode = options.includePaths.length > 0;
93317
93888
  const resolvedNodeBinaryPath = await resolveOxlintNode(options.lint, options.scoreOnly || options.silent);
93318
93889
  const lintBindingMissing = options.lint && !resolvedNodeBinaryPath;
@@ -93362,7 +93933,8 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
93362
93933
  shouldRunSupplyChain: options.supplyChain,
93363
93934
  shouldComputeScore: !options.noScore,
93364
93935
  shouldShowProgressSpinners,
93365
- oxlintConcurrency: options.concurrency,
93936
+ oxlintConcurrency: oxlintRuntime.concurrency,
93937
+ oxlintSpawnSlots: oxlintRuntime.spawnSlots,
93366
93938
  reporterLayer: options.uiLayers?.reporter,
93367
93939
  progressLayer: options.uiLayers?.progress
93368
93940
  });
@@ -93419,7 +93991,8 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
93419
93991
  baseFiles: options.baseline.baseFiles,
93420
93992
  headFiles: options.baseline.headFiles,
93421
93993
  headAnalyzedFiles: output.analyzedFiles,
93422
- deadlineEpochMs
93994
+ deadlineEpochMs,
93995
+ oxlintRuntime
93423
93996
  });
93424
93997
  if (comparison) {
93425
93998
  inspectDiagnostics = comparison.displayDiagnostics;
@@ -93668,26 +94241,26 @@ const finalizeAndRender = (input) => gen(function* () {
93668
94241
  //#region src/cli/utils/get-staged-files.ts
93669
94242
  const stagedFilesLayer = StagedFiles.layerNode.pipe(provide$2(Git.layerNode));
93670
94243
  const getStagedSourceFiles = async (directory) => {
94244
+ let stagedSourceFiles;
93671
94245
  try {
93672
- return [...await runPromise(gen(function* () {
94246
+ stagedSourceFiles = await runPromise(gen(function* () {
93673
94247
  return yield* (yield* StagedFiles).discoverSourceFiles(directory);
93674
- }).pipe(provide(stagedFilesLayer)))];
94248
+ }).pipe(provide(stagedFilesLayer)));
93675
94249
  } catch (error) {
93676
94250
  cliLogger.warn(`Failed to discover staged files: ${messageFromUnknown(error)}`);
93677
94251
  return [];
93678
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];
93679
94255
  };
93680
- const materializeStagedFiles = async (directory, stagedFiles, tempDirectory) => {
94256
+ const materializeStagedFiles = async (input) => {
93681
94257
  const snapshot = await runPromise(gen(function* () {
93682
- return yield* (yield* StagedFiles).materialize({
93683
- directory,
93684
- stagedFiles,
93685
- tempDirectory
93686
- });
94258
+ return yield* (yield* StagedFiles).materialize(input);
93687
94259
  }).pipe(provide(stagedFilesLayer)));
93688
94260
  return {
93689
94261
  tempDirectory: snapshot.tempDirectory,
93690
94262
  stagedFiles: [...snapshot.stagedFiles],
94263
+ unmaterializedFiles: [...snapshot.unmaterializedFiles],
93691
94264
  cleanup: snapshot.cleanup
93692
94265
  };
93693
94266
  };
@@ -95561,13 +96134,18 @@ const printMultiProjectSummary = (input) => gen(function* () {
95561
96134
  const scoreDiagnostics = new Set(filterScansForSurface(completedScans, "score"));
95562
96135
  const displayedScoreDiagnostics = displayDiagnostics.filter((diagnostic) => scoreDiagnostics.has(diagnostic));
95563
96136
  const projectRootByDiagnostic = /* @__PURE__ */ new WeakMap();
95564
- for (const scan of completedScans) for (const diagnostic of scan.result.diagnostics) projectRootByDiagnostic.set(diagnostic, scan.result.project.rootDirectory);
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
+ }
95565
96142
  const resolveDiagnosticSourceRoot = (diagnostic) => projectRootByDiagnostic.get(diagnostic) ?? "";
96143
+ const resolveDiagnosticFrameSourceRoot = (diagnostic) => frameSourceRootByDiagnostic.get(diagnostic) ?? resolveDiagnosticSourceRoot(diagnostic);
95566
96144
  const totalScannedFileCount = countUniqueScannedFiles(completedScans.map((scan) => scan.result));
95567
96145
  yield* log(`${highlighter.success("✔")} Scanned ${totalScannedFileCount} ${totalScannedFileCount === 1 ? "file" : "files"} in ${formatElapsedTime(totalElapsedMilliseconds)}`);
95568
96146
  if (displayDiagnostics.length > 0) {
95569
96147
  yield* log("");
95570
- 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);
95571
96149
  }
95572
96150
  const lowestScoredScan = findLowestScoredScan(completedScans);
95573
96151
  const aggregateScore = lowestScoredScan?.result.score ?? null;
@@ -95955,6 +96533,45 @@ const runExplain = async (fileLineArgument, context) => {
95955
96533
  }
95956
96534
  };
95957
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
95958
96575
  //#region src/cli/utils/project-manifest-changed.ts
95959
96576
  const PACKAGE_JSON = "package.json";
95960
96577
  /**
@@ -95971,6 +96588,29 @@ const projectManifestChanged = (rootDirectory, projectDirectory, diffInfo) => {
95971
96588
  return diffInfo.changedFiles.some((filePath) => toForwardSlashes(filePath) === manifestPath);
95972
96589
  };
95973
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
95974
96614
  //#region src/cli/utils/should-fail-scan-gate.ts
95975
96615
  const shouldFailScanGate = (input) => {
95976
96616
  if (input.blockingLevel === "none") return false;
@@ -96185,6 +96825,7 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
96185
96825
  if (!isQuiet) if (!flags.verbose && canAnimateOnboarding(process.stdout)) await runPromise(playWelcomeScene({ speedMultiplier: !isOnboardingForced() && hasCompletedOnboarding() ? 2 : 1 }));
96186
96826
  else runSync(printBrandedHeader);
96187
96827
  const scanOptions = resolveCliInspectOptions(flags, userConfig);
96828
+ const inspectProject = createInvocationInspect(scanOptions.concurrency);
96188
96829
  const scanDeadlineEpochMs = scanOptions.maxDurationMs !== void 0 ? Date.now() + scanOptions.maxDurationMs : void 0;
96189
96830
  const categoryFilters = new Set(scanOptions.categoryFilters ?? []);
96190
96831
  const skipPrompts = shouldSkipPrompts({
@@ -96192,8 +96833,13 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
96192
96833
  json: flags.json
96193
96834
  });
96194
96835
  if (flags.staged) {
96195
- const stagedFiles = await getStagedSourceFiles(resolvedDirectory);
96196
- if (stagedFiles.length === 0) {
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) => {
96197
96843
  if (isJsonMode) writeJsonReport(buildJsonReport({
96198
96844
  version: VERSION,
96199
96845
  directory: resolvedDirectory,
@@ -96202,71 +96848,197 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
96202
96848
  scans: [],
96203
96849
  totalElapsedMilliseconds: performance$1.now() - startTime
96204
96850
  }));
96205
- else if (!isScoreOnly) cliLogger.dim("No staged source files found.");
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." });
96206
96859
  return;
96207
96860
  }
96208
- if (!isQuiet) {
96209
- cliLogger.log(`Scanning ${highlighter.info(`${stagedFiles.length}`)} staged files...`);
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}`);
96210
96888
  cliLogger.break();
96889
+ const rootScanContext = await buildProjectScanContext(resolvedDirectory);
96890
+ if (rootScanContext !== null) projectScanContexts.push(rootScanContext);
96211
96891
  }
96212
- const tempDirectory = NFS.mkdtempSync(Path.join(tmpdir(), STAGED_FILES_TEMP_DIR_PREFIX));
96213
- const snapshot = await materializeStagedFiles(resolvedDirectory, stagedFiles, tempDirectory).catch((error) => {
96214
- NFS.rmSync(tempDirectory, {
96215
- recursive: true,
96216
- force: true
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
96217
96908
  });
96218
- throw error;
96219
- });
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
+ }
96220
96922
  const stagedWantsLines = resolveScope(flags, userConfig).scope === "lines";
96221
96923
  const stagedLineRanges = stagedWantsLines ? await getChangedLineRanges({
96222
96924
  directory: resolvedDirectory,
96223
96925
  cached: true,
96224
- files: snapshot.stagedFiles
96926
+ files: selectedStagedFiles
96225
96927
  }) : null;
96226
96928
  if (stagedWantsLines && stagedLineRanges === null && !isQuiet) {
96227
96929
  cliLogger.warn("Could not determine staged changed lines; reporting all issues in staged files.");
96228
96930
  cliLogger.break();
96229
96931
  }
96230
- try {
96231
- const scanResult = await inspect(snapshot.tempDirectory, {
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, {
96232
96975
  ...scanOptions,
96233
96976
  deadlineEpochMs: scanDeadlineEpochMs,
96234
- includePaths: snapshot.stagedFiles,
96235
- configOverride: userConfig,
96236
- configSourceDirectory: scanTarget.configSourceDirectory ?? void 0,
96237
- changedLineRanges: stagedLineRanges ?? void 0
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
96238
96983
  });
96239
96984
  const remappedDiagnostics = scanResult.diagnostics.map((diagnostic) => ({
96240
96985
  ...diagnostic,
96241
- filePath: Path.isAbsolute(diagnostic.filePath) ? diagnostic.filePath.replaceAll(snapshot.tempDirectory, () => resolvedDirectory) : diagnostic.filePath
96986
+ filePath: Path.isAbsolute(diagnostic.filePath) ? diagnostic.filePath.replaceAll(projectTempDirectory, () => projectScan.scanDirectory) : diagnostic.filePath
96242
96987
  }));
96243
- finalizeScans({
96244
- completedScans: [{
96245
- directory: resolvedDirectory,
96246
- result: {
96247
- ...scanResult,
96248
- diagnostics: remappedDiagnostics,
96249
- project: {
96250
- ...scanResult.project,
96251
- rootDirectory: resolvedDirectory
96252
- }
96253
- },
96254
- config: userConfig
96255
- }],
96256
- mode: "staged",
96257
- diff: null,
96258
- baselineIntended: false,
96259
- isJsonMode,
96260
- isScoreOnly,
96261
- flags,
96262
- categoryFilters,
96263
- userConfig,
96264
- resolvedDirectory,
96265
- startTime
96266
- });
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"));
96267
97026
  } finally {
96268
97027
  snapshot.cleanup();
96269
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
+ });
96270
97042
  return;
96271
97043
  }
96272
97044
  const projectDirectories = await selectProjects(resolvedDirectory, flags.project, skipPrompts, userConfig?.projects);
@@ -96331,7 +97103,6 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
96331
97103
  }
96332
97104
  cliLogger.break();
96333
97105
  }
96334
- const completedScans = [];
96335
97106
  const isMultiProject = projectDirectories.length > 1;
96336
97107
  const scanProject = async (projectDirectory) => {
96337
97108
  const projectScanTarget = projectDirectory === resolvedDirectory ? scanTarget : await resolveScanTarget(projectDirectory, { allowAmbiguous: true });
@@ -96359,7 +97130,7 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
96359
97130
  if (supplyChainManifestChanged) includePaths.push("package.json");
96360
97131
  }
96361
97132
  if (!isQuiet && !isMultiProject) cliLogger.dim(" ");
96362
- const scanResult = await inspect(scanDirectory, {
97133
+ const scanResult = await inspectProject(scanDirectory, {
96363
97134
  ...scanOptions,
96364
97135
  deadlineEpochMs: scanDeadlineEpochMs,
96365
97136
  includePaths,
@@ -96382,29 +97153,13 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
96382
97153
  config: projectConfig
96383
97154
  };
96384
97155
  };
96385
- const scanLoopStartTime = performance$1.now();
96386
- const projectCount = projectDirectories.length;
96387
- const batchSpinner = isMultiProject && !isQuiet ? spinner(`Scanning ${projectCount} projects…`).start() : null;
96388
- const ownsBatchSpinnerSilence = isMultiProject && scanOptions.silent === true;
96389
- const wasSpinnerSilent = isSpinnerSilent();
96390
- if (ownsBatchSpinnerSilence) setSpinnerSilent(true);
96391
- let finishedProjectCount = 0;
96392
- let scanOutcomes;
96393
- try {
96394
- scanOutcomes = await mapWithConcurrency(projectDirectories, isMultiProject ? 4 : 1, async (projectDirectory) => {
96395
- const scanOutcome = await scanProject(projectDirectory);
96396
- finishedProjectCount += 1;
96397
- batchSpinner?.update(`Scanning ${projectCount} projects… (${finishedProjectCount}/${projectCount})`);
96398
- return scanOutcome;
96399
- });
96400
- } finally {
96401
- if (ownsBatchSpinnerSilence) setSpinnerSilent(wasSpinnerSilent);
96402
- batchSpinner?.stop();
96403
- }
96404
- for (const scanOutcome of scanOutcomes) {
96405
- if (scanOutcome === null) continue;
96406
- completedScans.push(scanOutcome);
96407
- }
97156
+ const projectBatch = await runProjectScanBatch({
97157
+ projects: projectDirectories,
97158
+ isQuiet,
97159
+ isSilent: scanOptions.silent === true,
97160
+ scanProject
97161
+ });
97162
+ const completedScans = projectBatch.completedScans;
96408
97163
  if (!isQuiet && isMultiProject && completedScans.length > 0) {
96409
97164
  const showShareLink = !isShareOptedOut(completedScans, scanOptions.noScore) && !scanOptions.isCi;
96410
97165
  await runPromise(printMultiProjectSummary({
@@ -96414,7 +97169,7 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
96414
97169
  outputDirectory: flags.outputDir,
96415
97170
  isOffline: !showShareLink,
96416
97171
  projectName: Path.basename(resolvedDirectory),
96417
- totalElapsedMilliseconds: performance$1.now() - scanLoopStartTime
97172
+ totalElapsedMilliseconds: projectBatch.elapsedMilliseconds
96418
97173
  }));
96419
97174
  }
96420
97175
  const selectedSurfaceDiagnostics = filterDiagnosticsByCategories(filterScansForSurface(completedScans, scanOptions.outputSurface ?? "cli"), categoryFilters);
@@ -97560,7 +98315,7 @@ ${highlighter.dim("Learn more:")}
97560
98315
  ${highlighter.info(CI_URL)}
97561
98316
  `;
97562
98317
  const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
97563
- 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);
97564
98319
  program.action(inspectAction);
97565
98320
  program.command("design [directory]").description("Run only the focused UI design diagnostics").addHelpText("after", renderDesignHelpEpilog).action((directory, _options, command) => designAction(directory ?? ".", command.optsWithGlobals()));
97566
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));
@@ -97600,7 +98355,7 @@ program.command("experimental-tui [directory]", { hidden: true }).description("[
97600
98355
  return;
97601
98356
  }
97602
98357
  recordCount(METRIC.cliInvoked, 1, { command: "experimental-tui" });
97603
- const { runScanApp } = await import("./run-scan-app-C9MJnVwv.js");
98358
+ const { runScanApp } = await import("./run-scan-app-DHRvqfkX.js");
97604
98359
  const { shouldFail } = await runScanApp({
97605
98360
  directory,
97606
98361
  options: {
@@ -97640,7 +98395,7 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
97640
98395
  handleError(error, { sentryEventId });
97641
98396
  });
97642
98397
  //#endregion
97643
- 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, inspect 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 };
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 };
97644
98399
 
97645
98400
  //# sourceMappingURL=cli.js.map
97646
- //# debugId=a53d2e7d-c9bc-5c54-b965-3a988afa3832
98401
+ //# debugId=3bff4f9b-31f8-5abe-b7a2-a0ab9f6a85b4