react-doctor 0.9.1 → 0.9.2-dev.1098b9c

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]="b226693e-22a9-5a5c-8c9f-2679545b582a")}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]="bb982094-8280-5afe-b061-eb103665c55c")}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";
@@ -11,14 +11,16 @@ import process$1 from "node:process";
11
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";
12
12
  import * as Crypto from "node:crypto";
13
13
  import crypto, { createHash, randomUUID } from "node:crypto";
14
+ import { ResolverFactory } from "oxc-resolver";
14
15
  import ts from "typescript";
16
+ import * as NodeUrl from "node:url";
17
+ import { fileURLToPath, pathToFileURL } from "node:url";
15
18
  import * as OS from "node:os";
16
19
  import os, { tmpdir } from "node:os";
17
20
  import { parseJSON5 } from "confbox";
18
- import * as NodeUrl from "node:url";
19
- import { fileURLToPath, pathToFileURL } from "node:url";
20
21
  import { createJiti } from "jiti";
21
22
  import { ANALYZED_MANIFEST_FILENAMES, DEFAULT_EXTENSIONS } from "deslop-js/analyzed-inputs";
23
+ import { convertToTSX } from "@astrojs/compiler/sync";
22
24
  import { gzipSync } from "node:zlib";
23
25
  import * as Sentry from "@sentry/node";
24
26
  import { performance as performance$1 } from "node:perf_hooks";
@@ -13341,7 +13343,7 @@ const Number$4 = globalThis.Number;
13341
13343
  * @category constructors
13342
13344
  * @since 2.0.0
13343
13345
  */
13344
- const parse = (s) => {
13346
+ const parse$1 = (s) => {
13345
13347
  if (s === "NaN") return some(NaN);
13346
13348
  if (s === "Infinity") return some(Infinity);
13347
13349
  if (s === "-Infinity") return some(-Infinity);
@@ -17404,12 +17406,12 @@ TaggedError("EncodingError");
17404
17406
  //#endregion
17405
17407
  //#region ../../node_modules/.pnpm/effect@4.0.0-beta.70/node_modules/effect/dist/internal/schema/annotations.js
17406
17408
  /** @internal */
17407
- function resolve(ast) {
17409
+ function resolve$1(ast) {
17408
17410
  return ast.checks ? ast.checks[ast.checks.length - 1].annotations : ast.annotations;
17409
17411
  }
17410
17412
  /** @internal */
17411
17413
  function resolveAt(key) {
17412
- return (ast) => resolve(ast)?.[key];
17414
+ return (ast) => resolve$1(ast)?.[key];
17413
17415
  }
17414
17416
  /** @internal */
17415
17417
  const resolveIdentifier = /* @__PURE__ */ resolveAt("identifier");
@@ -21161,7 +21163,7 @@ function asSync(parser) {
21161
21163
  }
21162
21164
  const recur$1 = /* @__PURE__ */ memoize((ast) => {
21163
21165
  let parser;
21164
- const astOptions = resolve(ast)?.["parseOptions"];
21166
+ const astOptions = resolve$1(ast)?.["parseOptions"];
21165
21167
  if (!ast.context && !ast.encoding && !ast.checks) return (ou, options) => {
21166
21168
  parser ??= ast.getParser(recur$1);
21167
21169
  if (astOptions) options = {
@@ -60766,7 +60768,7 @@ var UrlParamsError = class extends TaggedError("UrlParamsError") {};
60766
60768
  * @category converting
60767
60769
  * @since 4.0.0
60768
60770
  */
60769
- const makeUrl = (url, params, hash) => {
60771
+ const makeUrl$1 = (url, params, hash) => {
60770
60772
  try {
60771
60773
  const urlInstance = new URL(url, baseUrl());
60772
60774
  for (let i = 0; i < params.params.length; i++) {
@@ -61400,7 +61402,7 @@ const Proto$2 = {
61400
61402
  const make$10 = (f) => makeWith$1((effect) => flatMap$2(effect, (request) => withFiber((fiber) => {
61401
61403
  const scopedController = scopedRequests.get(request);
61402
61404
  const controller = scopedController ?? new AbortController();
61403
- const urlResult = makeUrl(request.url, request.urlParams, getOrUndefined(request.hash));
61405
+ const urlResult = makeUrl$1(request.url, request.urlParams, getOrUndefined(request.hash));
61404
61406
  if (isFailure(urlResult)) return fail$4(new HttpClientError({ reason: new InvalidUrlError({
61405
61407
  request,
61406
61408
  cause: urlResult.failure
@@ -61839,7 +61841,7 @@ const layer$8 = (loggers, options) => effect(CurrentLoggers, withFiber$1(fnUntra
61839
61841
  * @since 4.0.0
61840
61842
  */
61841
61843
  const policy = /* @__PURE__ */ forever$1.pipe(passthrough$2, /* @__PURE__ */ addDelay((error) => {
61842
- 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))));
61843
61845
  return succeed$2(seconds(1));
61844
61846
  }));
61845
61847
  /**
@@ -64548,6 +64550,428 @@ const layer$1 = /* @__PURE__ */ succeed$3(Path$1)({
64548
64550
  toFileUrl
64549
64551
  });
64550
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
64551
64975
  //#region ../core/dist/index.js
64552
64976
  var __create = Object.create;
64553
64977
  var __defProp = Object.defineProperty;
@@ -64616,7 +65040,8 @@ var AmbiguousProjectError = class extends Error {
64616
65040
  }
64617
65041
  };
64618
65042
  const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
64619
- const SOURCE_FILE_PATTERN = /\.(tsx?|jsx?|mts|mjs)$/;
65043
+ const HTML_FILE_PATTERN = /\.html$/i;
65044
+ const SOURCE_FILE_PATTERN = /\.(?:astro|tsx?|jsx?|mts|mjs|[hH][tT][mM][lL])$/;
64620
65045
  const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
64621
65046
  const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
64622
65047
  const MINIFIED_SNIFF_BYTES = 65536;
@@ -64994,7 +65419,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
64994
65419
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
64995
65420
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
64996
65421
  const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
64997
- const CORE_PACKAGE_VERSION = "0.9.1";
65422
+ const CORE_PACKAGE_VERSION = "0.9.2";
64998
65423
  const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
64999
65424
  const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
65000
65425
  const SUPPLY_CHAIN_PLUGIN = "socket";
@@ -65238,8 +65663,13 @@ const findMonorepoRoot = (startDirectory) => {
65238
65663
  * byte-equivalent copy.
65239
65664
  */
65240
65665
  const isProjectBoundary = (directory) => NFS.existsSync(Path.join(directory, ".git")) || isMonorepoRoot(directory);
65666
+ const unwrapTypescriptExpression = (expression) => {
65667
+ let currentExpression = expression;
65668
+ while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
65669
+ return currentExpression;
65670
+ };
65241
65671
  const TSCONFIG_FILENAME = "tsconfig.json";
65242
- const isRelativeExtendsValue = (extendsValue) => extendsValue.startsWith("./") || extendsValue.startsWith("../") || Path.isAbsolute(extendsValue);
65672
+ const isLocalModuleSpecifier = (moduleSpecifier) => moduleSpecifier === "." || moduleSpecifier === ".." || moduleSpecifier.startsWith("./") || moduleSpecifier.startsWith("../") || Path.isAbsolute(moduleSpecifier);
65243
65673
  const ensureJsonExtension = (filePath) => Path.extname(filePath) === "" ? `${filePath}.json` : filePath;
65244
65674
  const resolvePackageExtendsPath = (extendsValue, fromConfigDirectory) => {
65245
65675
  const requireFromConfig = createRequire(Path.join(fromConfigDirectory, "tsconfig.json"));
@@ -65256,7 +65686,12 @@ const resolvePackageExtendsPath = (extendsValue, fromConfigDirectory) => {
65256
65686
  return null;
65257
65687
  };
65258
65688
  const resolveExtendsPath = (extendsValue, fromConfigDirectory) => {
65259
- if (isRelativeExtendsValue(extendsValue)) return ensureJsonExtension(Path.resolve(fromConfigDirectory, extendsValue));
65689
+ if (isLocalModuleSpecifier(extendsValue)) {
65690
+ const resolvedPath = Path.resolve(fromConfigDirectory, extendsValue);
65691
+ if (isFile(resolvedPath)) return resolvedPath;
65692
+ const directoryConfigPath = Path.join(resolvedPath, TSCONFIG_FILENAME);
65693
+ return isFile(directoryConfigPath) ? directoryConfigPath : ensureJsonExtension(resolvedPath);
65694
+ }
65260
65695
  return resolvePackageExtendsPath(extendsValue, fromConfigDirectory);
65261
65696
  };
65262
65697
  const normalizeCompilerOptions = (compilerOptions) => {
@@ -65363,6 +65798,7 @@ const FRAMEWORK_PACKAGES = {
65363
65798
  "@tanstack/react-start": "tanstack-start",
65364
65799
  "@remix-run/react": "remix",
65365
65800
  gatsby: "gatsby",
65801
+ astro: "astro",
65366
65802
  vite: "vite",
65367
65803
  "react-scripts": "cra",
65368
65804
  expo: "expo",
@@ -65450,6 +65886,15 @@ const REACT_COMPILER_CONFIG_SOURCE_EXTENSIONS = [
65450
65886
  ".cts",
65451
65887
  ".json"
65452
65888
  ];
65889
+ const REACT_COMPILER_CONFIG_RESOLVER = new ResolverFactory({
65890
+ conditionNames: [
65891
+ "import",
65892
+ "require",
65893
+ "node",
65894
+ "default"
65895
+ ],
65896
+ extensions: REACT_COMPILER_CONFIG_SOURCE_EXTENSIONS
65897
+ });
65453
65898
  const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
65454
65899
  const hasCompilerPackage = (packageJson, compilerPackages) => {
65455
65900
  const allDependencies = {
@@ -65473,6 +65918,18 @@ const hasCompilerPackageInAncestors = (directory, compilerPackages) => {
65473
65918
  return false;
65474
65919
  };
65475
65920
  const resolveImportedConfigFile = (fromFilePath, moduleSpecifier) => {
65921
+ if (!isLocalModuleSpecifier(moduleSpecifier)) {
65922
+ try {
65923
+ const resolvedPath = REACT_COMPILER_CONFIG_RESOLVER.resolveFileSync(fromFilePath, moduleSpecifier).path;
65924
+ if (resolvedPath && isFile(resolvedPath)) return resolvedPath;
65925
+ } catch {}
65926
+ try {
65927
+ const resolvedPath = createRequire(fromFilePath).resolve(moduleSpecifier);
65928
+ return isFile(resolvedPath) ? resolvedPath : null;
65929
+ } catch {
65930
+ return null;
65931
+ }
65932
+ }
65476
65933
  const unresolvedPath = Path.resolve(Path.dirname(fromFilePath), moduleSpecifier);
65477
65934
  const extension = Path.extname(unresolvedPath);
65478
65935
  return (extension ? [unresolvedPath, ...REACT_COMPILER_CONFIG_SOURCE_EXTENSIONS.map((sourceExtension) => `${unresolvedPath.slice(0, -extension.length)}${sourceExtension}`)] : [
@@ -65482,10 +65939,10 @@ const resolveImportedConfigFile = (fromFilePath, moduleSpecifier) => {
65482
65939
  ]).find(isFile) ?? null;
65483
65940
  };
65484
65941
  const parseConfigSourceFile = (filePath, content) => filePath.endsWith(".json") || Path.basename(filePath) === ".babelrc" ? ts.parseJsonText(filePath, content) : ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
65485
- const getStaticPropertyName$1 = (propertyName) => ts.isIdentifier(propertyName) || ts.isStringLiteralLike(propertyName) ? propertyName.text : ts.isComputedPropertyName(propertyName) && ts.isStringLiteralLike(propertyName.expression) ? propertyName.expression.text : null;
65942
+ const getStaticPropertyName$2 = (propertyName) => ts.isIdentifier(propertyName) || ts.isStringLiteralLike(propertyName) ? propertyName.text : ts.isComputedPropertyName(propertyName) && ts.isStringLiteralLike(propertyName.expression) ? propertyName.expression.text : null;
65486
65943
  const isCommonJsConfigExportAssignment = (node, sourceFile) => ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && (node.left.getText(sourceFile) === "module.exports" || node.left.getText(sourceFile) === "exports.default");
65487
65944
  const hasExportModifier = (node) => ts.canHaveModifiers(node) && Boolean(ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword));
65488
- const getRequireModuleSpecifier = (expression) => {
65945
+ const getRequireModuleSpecifier$1 = (expression) => {
65489
65946
  if (!ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression) || expression.expression.text !== "require" || expression.arguments.length !== 1) return null;
65490
65947
  const moduleSpecifier = expression.arguments[0];
65491
65948
  return moduleSpecifier && ts.isStringLiteralLike(moduleSpecifier) ? moduleSpecifier.text : null;
@@ -65498,7 +65955,7 @@ const hasTopLevelValueBinding = (sourceFile, bindingName) => sourceFile.statemen
65498
65955
  const namedBindings = importClause?.namedBindings;
65499
65956
  return namedBindings ? ts.isNamespaceImport(namedBindings) ? namedBindings.name.text === bindingName : namedBindings.elements.some((element) => element.name.text === bindingName) : false;
65500
65957
  }
65501
- if (ts.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) => ts.isIdentifier(declaration.name) && declaration.name.text === bindingName);
65958
+ if (ts.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) => bindingNameContainsIdentifier(declaration.name, bindingName));
65502
65959
  return (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name?.text === bindingName;
65503
65960
  });
65504
65961
  const getImportBinding = (sourceFile, bindingName) => {
@@ -65529,24 +65986,24 @@ const getImportBinding = (sourceFile, bindingName) => {
65529
65986
  for (const declaration of statement.declarationList.declarations) {
65530
65987
  if (!declaration.initializer) continue;
65531
65988
  if (ts.isIdentifier(declaration.name) && declaration.name.text === bindingName) {
65532
- const directModuleSpecifier = getRequireModuleSpecifier(declaration.initializer);
65989
+ const directModuleSpecifier = getRequireModuleSpecifier$1(declaration.initializer);
65533
65990
  if (directModuleSpecifier) return {
65534
65991
  moduleSpecifier: directModuleSpecifier,
65535
65992
  exportName: "default",
65536
65993
  isNamespace: true
65537
65994
  };
65538
- if (ts.isPropertyAccessExpression(declaration.initializer) && getRequireModuleSpecifier(declaration.initializer.expression) !== null) return {
65539
- moduleSpecifier: getRequireModuleSpecifier(declaration.initializer.expression) ?? "",
65995
+ if (ts.isPropertyAccessExpression(declaration.initializer) && getRequireModuleSpecifier$1(declaration.initializer.expression) !== null) return {
65996
+ moduleSpecifier: getRequireModuleSpecifier$1(declaration.initializer.expression) ?? "",
65540
65997
  exportName: declaration.initializer.name.text,
65541
65998
  isNamespace: false
65542
65999
  };
65543
66000
  }
65544
66001
  if (!ts.isObjectBindingPattern(declaration.name)) continue;
65545
66002
  const bindingElement = declaration.name.elements.find((element) => ts.isIdentifier(element.name) && element.name.text === bindingName);
65546
- const moduleSpecifier = getRequireModuleSpecifier(declaration.initializer);
66003
+ const moduleSpecifier = getRequireModuleSpecifier$1(declaration.initializer);
65547
66004
  if (bindingElement && moduleSpecifier) return {
65548
66005
  moduleSpecifier,
65549
- exportName: bindingElement.propertyName ? getStaticPropertyName$1(bindingElement.propertyName) ?? bindingElement.propertyName.getText(sourceFile) : bindingElement.name.getText(sourceFile),
66006
+ exportName: bindingElement.propertyName ? getStaticPropertyName$2(bindingElement.propertyName) ?? bindingElement.propertyName.getText(sourceFile) : bindingElement.name.getText(sourceFile),
65550
66007
  isNamespace: false
65551
66008
  };
65552
66009
  }
@@ -65563,10 +66020,16 @@ const getTopLevelBinding = (sourceFile, bindingName) => {
65563
66020
  }
65564
66021
  return null;
65565
66022
  };
65566
- const getFunctionLocalBindings = (functionNode, argumentsList) => {
66023
+ const getFunctionLocalBindings = (functionNode, argumentsList, argumentAnalysis, functionAnalysis) => {
65567
66024
  const localBindings = /* @__PURE__ */ new Map();
65568
66025
  functionNode.parameters.forEach((parameter, parameterIndex) => {
65569
- if (ts.isIdentifier(parameter.name)) localBindings.set(parameter.name.text, argumentsList[parameterIndex] ?? parameter.initializer ?? null);
66026
+ if (ts.isIdentifier(parameter.name)) {
66027
+ const argument = argumentsList[parameterIndex];
66028
+ localBindings.set(parameter.name.text, {
66029
+ expression: argument ?? parameter.initializer ?? null,
66030
+ analysis: argument ? argumentAnalysis : functionAnalysis
66031
+ });
66032
+ }
65570
66033
  });
65571
66034
  return localBindings;
65572
66035
  };
@@ -65599,6 +66062,48 @@ const getScopedConfigBinding = (identifier) => {
65599
66062
  };
65600
66063
  };
65601
66064
  const isCompilerTransformModule = (moduleSpecifier, exportName) => moduleSpecifier === "babel-plugin-react-compiler" && exportName === "default" || moduleSpecifier === "@vitejs/plugin-react" && exportName === "reactCompilerPreset";
66065
+ const NODE_MODULE_SPECIFIERS = new Set(["module", "node:module"]);
66066
+ const isConstantVariableInitializer = (node) => ts.isExpression(node) && ts.isVariableDeclaration(node.parent) && ts.isVariableDeclarationList(node.parent.parent) && Boolean(node.parent.parent.flags & ts.NodeFlags.Const);
66067
+ const isNodeCreateRequireCall = (node, analysis) => {
66068
+ if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isTypeAssertionExpression(node) || ts.isSatisfiesExpression(node) || ts.isNonNullExpression(node) || ts.isAwaitExpression(node)) return isNodeCreateRequireCall(node.expression, analysis);
66069
+ if (!ts.isCallExpression(node)) return false;
66070
+ const target = node.expression;
66071
+ if (ts.isIdentifier(target)) {
66072
+ if (analysis.localBindings.has(target.text) || getScopedConfigBinding(target).wasFound) return false;
66073
+ const importBinding = getImportBinding(analysis.sourceFile, target.text);
66074
+ return Boolean(importBinding && NODE_MODULE_SPECIFIERS.has(importBinding.moduleSpecifier) && importBinding.exportName === "createRequire");
66075
+ }
66076
+ if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return false;
66077
+ if ((ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null) !== "createRequire") return false;
66078
+ const createRequireReceiver = target.expression;
66079
+ if (ts.isCallExpression(createRequireReceiver)) {
66080
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(createRequireReceiver);
66081
+ if (requiredModuleSpecifier === null || !NODE_MODULE_SPECIFIERS.has(requiredModuleSpecifier) || !ts.isIdentifier(createRequireReceiver.expression)) return false;
66082
+ const requireIdentifier = createRequireReceiver.expression;
66083
+ return !analysis.localBindings.has(requireIdentifier.text) && !getScopedConfigBinding(requireIdentifier).wasFound && !hasTopLevelValueBinding(analysis.sourceFile, requireIdentifier.text);
66084
+ }
66085
+ if (!ts.isIdentifier(createRequireReceiver)) return false;
66086
+ if (analysis.localBindings.has(createRequireReceiver.text) || getScopedConfigBinding(createRequireReceiver).wasFound) return false;
66087
+ const importBinding = getImportBinding(analysis.sourceFile, createRequireReceiver.text);
66088
+ return Boolean(importBinding?.isNamespace && NODE_MODULE_SPECIFIERS.has(importBinding.moduleSpecifier));
66089
+ };
66090
+ const getNodeRequireResolveModuleSpecifier = (callExpression, analysis) => {
66091
+ const [moduleSpecifierNode] = callExpression.arguments;
66092
+ if (!moduleSpecifierNode || !ts.isStringLiteralLike(moduleSpecifierNode)) return null;
66093
+ const target = callExpression.expression;
66094
+ if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return null;
66095
+ if ((ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null) !== "resolve") return null;
66096
+ if (isNodeCreateRequireCall(target.expression, analysis)) return moduleSpecifierNode.text;
66097
+ if (!ts.isIdentifier(target.expression)) return null;
66098
+ const resolverIdentifier = target.expression;
66099
+ if (analysis.localBindings.has(resolverIdentifier.text)) return null;
66100
+ const scopedBinding = getScopedConfigBinding(resolverIdentifier);
66101
+ const topLevelBinding = scopedBinding.wasFound ? null : getTopLevelBinding(analysis.sourceFile, resolverIdentifier.text);
66102
+ const resolverInitializer = scopedBinding.wasFound ? scopedBinding.initializer : topLevelBinding;
66103
+ if (resolverInitializer === null && !scopedBinding.wasFound && resolverIdentifier.text === "require" && !hasTopLevelValueBinding(analysis.sourceFile, resolverIdentifier.text) && getImportBinding(analysis.sourceFile, resolverIdentifier.text) === null) return moduleSpecifierNode.text;
66104
+ if (!resolverInitializer || !isConstantVariableInitializer(resolverInitializer) || !isNodeCreateRequireCall(resolverInitializer, analysis)) return null;
66105
+ return moduleSpecifierNode.text;
66106
+ };
65602
66107
  const getAssignedPropertyInitializer = (identifier, propertyName) => {
65603
66108
  let bindingScope = null;
65604
66109
  let currentNode = identifier;
@@ -65641,9 +66146,11 @@ const getAssignedPropertyInitializer = (identifier, propertyName) => {
65641
66146
  initializer: assignedInitializer
65642
66147
  };
65643
66148
  };
65644
- const getStaticConfigValueState = (expression, analysis) => {
65645
- let unwrappedExpression = expression;
65646
- while (ts.isParenthesizedExpression(unwrappedExpression) || ts.isAsExpression(unwrappedExpression) || ts.isTypeAssertionExpression(unwrappedExpression) || ts.isSatisfiesExpression(unwrappedExpression) || ts.isNonNullExpression(unwrappedExpression)) unwrappedExpression = unwrappedExpression.expression;
66149
+ const getStaticConfigValueState = (expression, analysis, visitedExpressions = /* @__PURE__ */ new Set()) => {
66150
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
66151
+ if (visitedExpressions.has(unwrappedExpression)) return null;
66152
+ const nextVisitedExpressions = new Set(visitedExpressions);
66153
+ nextVisitedExpressions.add(unwrappedExpression);
65647
66154
  if (unwrappedExpression.kind === ts.SyntaxKind.NullKeyword || ts.isIdentifier(unwrappedExpression) && unwrappedExpression.text === "undefined") return {
65648
66155
  isNullish: true,
65649
66156
  isTruthy: false
@@ -65658,32 +66165,32 @@ const getStaticConfigValueState = (expression, analysis) => {
65658
66165
  };
65659
66166
  if (ts.isIdentifier(unwrappedExpression)) {
65660
66167
  if (analysis.localBindings.has(unwrappedExpression.text)) {
65661
- const localInitializer = analysis.localBindings.get(unwrappedExpression.text);
65662
- return localInitializer ? getStaticConfigValueState(localInitializer, analysis) : null;
66168
+ const localReference = analysis.localBindings.get(unwrappedExpression.text);
66169
+ return localReference?.expression ? getStaticConfigValueState(localReference.expression, localReference.analysis, nextVisitedExpressions) : null;
65663
66170
  }
65664
66171
  const topLevelBinding = getTopLevelBinding(analysis.sourceFile, unwrappedExpression.text);
65665
- return topLevelBinding && ts.isExpression(topLevelBinding) ? getStaticConfigValueState(topLevelBinding, analysis) : null;
66172
+ return topLevelBinding && ts.isExpression(topLevelBinding) ? getStaticConfigValueState(topLevelBinding, analysis, nextVisitedExpressions) : null;
65666
66173
  }
65667
66174
  if (ts.isConditionalExpression(unwrappedExpression)) {
65668
- const conditionState = getStaticConfigValueState(unwrappedExpression.condition, analysis);
65669
- if (conditionState !== null) return getStaticConfigValueState(conditionState.isTruthy ? unwrappedExpression.whenTrue : unwrappedExpression.whenFalse, analysis);
65670
- const whenTrueState = getStaticConfigValueState(unwrappedExpression.whenTrue, analysis);
65671
- const whenFalseState = getStaticConfigValueState(unwrappedExpression.whenFalse, analysis);
66175
+ const conditionState = getStaticConfigValueState(unwrappedExpression.condition, analysis, nextVisitedExpressions);
66176
+ if (conditionState !== null) return getStaticConfigValueState(conditionState.isTruthy ? unwrappedExpression.whenTrue : unwrappedExpression.whenFalse, analysis, nextVisitedExpressions);
66177
+ const whenTrueState = getStaticConfigValueState(unwrappedExpression.whenTrue, analysis, nextVisitedExpressions);
66178
+ const whenFalseState = getStaticConfigValueState(unwrappedExpression.whenFalse, analysis, nextVisitedExpressions);
65672
66179
  return whenTrueState !== null && whenFalseState !== null && whenTrueState.isNullish === whenFalseState.isNullish && whenTrueState.isTruthy === whenFalseState.isTruthy ? whenTrueState : null;
65673
66180
  }
65674
66181
  if (ts.isBinaryExpression(unwrappedExpression)) {
65675
- const leftState = getStaticConfigValueState(unwrappedExpression.left, analysis);
66182
+ const leftState = getStaticConfigValueState(unwrappedExpression.left, analysis, nextVisitedExpressions);
65676
66183
  if (unwrappedExpression.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) {
65677
66184
  if (leftState === null) return null;
65678
- return leftState.isTruthy ? getStaticConfigValueState(unwrappedExpression.right, analysis) : leftState;
66185
+ return leftState.isTruthy ? getStaticConfigValueState(unwrappedExpression.right, analysis, nextVisitedExpressions) : leftState;
65679
66186
  }
65680
66187
  if (unwrappedExpression.operatorToken.kind === ts.SyntaxKind.BarBarToken) {
65681
66188
  if (leftState === null) return null;
65682
- return leftState.isTruthy ? leftState : getStaticConfigValueState(unwrappedExpression.right, analysis);
66189
+ return leftState.isTruthy ? leftState : getStaticConfigValueState(unwrappedExpression.right, analysis, nextVisitedExpressions);
65683
66190
  }
65684
66191
  if (unwrappedExpression.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
65685
66192
  if (leftState === null) return null;
65686
- return leftState.isNullish ? getStaticConfigValueState(unwrappedExpression.right, analysis) : leftState;
66193
+ return leftState.isNullish ? getStaticConfigValueState(unwrappedExpression.right, analysis, nextVisitedExpressions) : leftState;
65687
66194
  }
65688
66195
  }
65689
66196
  return null;
@@ -65692,25 +66199,27 @@ const isStaticallyDisabledConfigExpression = (expression, analysis) => getStatic
65692
66199
  const isStaticallyTruthyConfigExpression = (expression, analysis) => getStaticConfigValueState(expression, analysis)?.isTruthy === true;
65693
66200
  const isStaticallyNullishConfigExpression = (expression, analysis) => getStaticConfigValueState(expression, analysis)?.isNullish === true;
65694
66201
  const isStaticallyNonNullishConfigExpression = (expression, analysis) => getStaticConfigValueState(expression, analysis)?.isNullish === false;
65695
- const getReactCompilerFlagState = (expression, analysis) => {
65696
- let unwrappedExpression = expression;
65697
- while (ts.isParenthesizedExpression(unwrappedExpression) || ts.isAsExpression(unwrappedExpression) || ts.isTypeAssertionExpression(unwrappedExpression) || ts.isSatisfiesExpression(unwrappedExpression) || ts.isNonNullExpression(unwrappedExpression)) unwrappedExpression = unwrappedExpression.expression;
66202
+ const getReactCompilerFlagState = (expression, analysis, visitedExpressions = /* @__PURE__ */ new Set()) => {
66203
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
66204
+ if (visitedExpressions.has(unwrappedExpression)) return null;
66205
+ const nextVisitedExpressions = new Set(visitedExpressions);
66206
+ nextVisitedExpressions.add(unwrappedExpression);
65698
66207
  if (ts.isIdentifier(unwrappedExpression)) {
65699
66208
  const assignedBinding = getAssignedPropertyInitializer(unwrappedExpression, "reactCompiler");
65700
66209
  if (assignedBinding.wasFound && assignedBinding.initializer) return { isEnabled: !isStaticallyDisabledConfigExpression(assignedBinding.initializer, analysis) };
65701
66210
  if (analysis.localBindings.has(unwrappedExpression.text)) {
65702
- const localInitializer = analysis.localBindings.get(unwrappedExpression.text);
65703
- return localInitializer ? getReactCompilerFlagState(localInitializer, analysis) : null;
66211
+ const localReference = analysis.localBindings.get(unwrappedExpression.text);
66212
+ return localReference?.expression ? getReactCompilerFlagState(localReference.expression, localReference.analysis, nextVisitedExpressions) : null;
65704
66213
  }
65705
66214
  const topLevelBinding = getTopLevelBinding(analysis.sourceFile, unwrappedExpression.text);
65706
- return topLevelBinding && ts.isExpression(topLevelBinding) ? getReactCompilerFlagState(topLevelBinding, analysis) : null;
66215
+ return topLevelBinding && ts.isExpression(topLevelBinding) ? getReactCompilerFlagState(topLevelBinding, analysis, nextVisitedExpressions) : null;
65707
66216
  }
65708
66217
  if (!ts.isObjectLiteralExpression(unwrappedExpression)) return null;
65709
66218
  for (const property of [...unwrappedExpression.properties].reverse()) {
65710
- if (ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === "reactCompiler") return { isEnabled: !isStaticallyDisabledConfigExpression(property.initializer, analysis) };
66219
+ if (ts.isPropertyAssignment(property) && getStaticPropertyName$2(property.name) === "reactCompiler") return { isEnabled: !isStaticallyDisabledConfigExpression(property.initializer, analysis) };
65711
66220
  if (ts.isShorthandPropertyAssignment(property) && property.name.text === "reactCompiler") return { isEnabled: !isStaticallyDisabledConfigExpression(property.name, analysis) };
65712
66221
  if (ts.isSpreadAssignment(property)) {
65713
- const spreadState = getReactCompilerFlagState(property.expression, analysis);
66222
+ const spreadState = getReactCompilerFlagState(property.expression, analysis, nextVisitedExpressions);
65714
66223
  if (spreadState) return spreadState;
65715
66224
  }
65716
66225
  }
@@ -65723,8 +66232,8 @@ const getSelectedObjectProperty = (expression, propertyName, analysis, visitedEx
65723
66232
  visitedExpressions.add(resolvedExpression);
65724
66233
  if (ts.isIdentifier(resolvedExpression)) {
65725
66234
  if (analysis.localBindings.has(resolvedExpression.text)) {
65726
- const localInitializer = analysis.localBindings.get(resolvedExpression.text);
65727
- return localInitializer ? getSelectedObjectProperty(localInitializer, propertyName, analysis, visitedExpressions) : null;
66235
+ const localReference = analysis.localBindings.get(resolvedExpression.text);
66236
+ return localReference?.expression ? getSelectedObjectProperty(localReference.expression, propertyName, localReference.analysis, visitedExpressions) : null;
65728
66237
  }
65729
66238
  const scopedBinding = getScopedConfigBinding(resolvedExpression);
65730
66239
  if (scopedBinding.wasFound) return scopedBinding.initializer ? getSelectedObjectProperty(scopedBinding.initializer, propertyName, analysis, visitedExpressions) : null;
@@ -65733,9 +66242,18 @@ const getSelectedObjectProperty = (expression, propertyName, analysis, visitedEx
65733
66242
  }
65734
66243
  if (!ts.isObjectLiteralExpression(resolvedExpression)) return null;
65735
66244
  for (const property of [...resolvedExpression.properties].reverse()) {
65736
- if (ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === propertyName) return property.initializer;
65737
- if (ts.isMethodDeclaration(property) && getStaticPropertyName$1(property.name) === propertyName) return property;
65738
- if (ts.isShorthandPropertyAssignment(property) && property.name.text === propertyName) return property.name;
66245
+ if (ts.isPropertyAssignment(property) && getStaticPropertyName$2(property.name) === propertyName) return {
66246
+ node: property.initializer,
66247
+ analysis
66248
+ };
66249
+ if (ts.isMethodDeclaration(property) && getStaticPropertyName$2(property.name) === propertyName) return {
66250
+ node: property,
66251
+ analysis
66252
+ };
66253
+ if (ts.isShorthandPropertyAssignment(property) && property.name.text === propertyName) return {
66254
+ node: property.name,
66255
+ analysis
66256
+ };
65739
66257
  if (ts.isSpreadAssignment(property)) {
65740
66258
  const spreadProperty = getSelectedObjectProperty(property.expression, propertyName, analysis, visitedExpressions);
65741
66259
  if (spreadProperty) return spreadProperty;
@@ -65748,8 +66266,8 @@ const configExpressionMayDefineProperty = (expression, propertyName, analysis) =
65748
66266
  while (ts.isParenthesizedExpression(resolvedExpression) || ts.isAsExpression(resolvedExpression) || ts.isTypeAssertionExpression(resolvedExpression) || ts.isSatisfiesExpression(resolvedExpression) || ts.isNonNullExpression(resolvedExpression)) resolvedExpression = resolvedExpression.expression;
65749
66267
  if (ts.isIdentifier(resolvedExpression)) {
65750
66268
  if (analysis.localBindings.has(resolvedExpression.text)) {
65751
- const localInitializer = analysis.localBindings.get(resolvedExpression.text);
65752
- return localInitializer ? configExpressionMayDefineProperty(localInitializer, propertyName, analysis) : true;
66269
+ const localReference = analysis.localBindings.get(resolvedExpression.text);
66270
+ return localReference?.expression ? configExpressionMayDefineProperty(localReference.expression, propertyName, localReference.analysis) : true;
65753
66271
  }
65754
66272
  const scopedBinding = getScopedConfigBinding(resolvedExpression);
65755
66273
  if (scopedBinding.wasFound) return scopedBinding.initializer ? configExpressionMayDefineProperty(scopedBinding.initializer, propertyName, analysis) : true;
@@ -65765,7 +66283,7 @@ const configExpressionMayDefineProperty = (expression, propertyName, analysis) =
65765
66283
  return resolvedExpression.properties.some((property) => {
65766
66284
  if (ts.isSpreadAssignment(property)) return configExpressionMayDefineProperty(property.expression, propertyName, analysis);
65767
66285
  if (ts.isPropertyAssignment(property) || ts.isShorthandPropertyAssignment(property) || ts.isMethodDeclaration(property) || ts.isGetAccessorDeclaration(property) || ts.isSetAccessorDeclaration(property)) {
65768
- const staticPropertyName = getStaticPropertyName$1(property.name);
66286
+ const staticPropertyName = getStaticPropertyName$2(property.name);
65769
66287
  return staticPropertyName === null || staticPropertyName === propertyName;
65770
66288
  }
65771
66289
  return false;
@@ -65784,7 +66302,7 @@ const getExportedConfigNodes = (sourceFile, exportName) => {
65784
66302
  continue;
65785
66303
  }
65786
66304
  if (ts.isExpressionStatement(statement) && isCommonJsConfigExportAssignment(statement.expression, sourceFile) && exportName !== "default" && ts.isObjectLiteralExpression(statement.expression.right)) for (const property of [...statement.expression.right.properties].reverse()) {
65787
- if (ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === exportName) {
66305
+ if (ts.isPropertyAssignment(property) && getStaticPropertyName$2(property.name) === exportName) {
65788
66306
  exportedNodes.push(property.initializer);
65789
66307
  break;
65790
66308
  }
@@ -65833,15 +66351,15 @@ const getReExportedConfigModules = (sourceFile, exportName) => {
65833
66351
  }
65834
66352
  return bindings;
65835
66353
  };
65836
- const analyzeConfigModuleExport = (filePath, exportName, allowCompilerTransform, importDepth, visitedModules, argumentsList = []) => {
66354
+ const analyzeConfigModuleExport = (filePath, exportName, allowCompilerTransform, importDepth, visitedModules, argumentsList = [], argumentAnalysis) => {
65837
66355
  if (!isFile(filePath) || importDepth > 4) return false;
65838
66356
  const moduleVisitKey = `${filePath}:${exportName}:${allowCompilerTransform}`;
65839
66357
  if (visitedModules.has(moduleVisitKey)) return false;
65840
66358
  const nextVisitedModules = new Set(visitedModules);
65841
66359
  nextVisitedModules.add(moduleVisitKey);
65842
- return analyzeConfigSourceFileExport(parseConfigSourceFile(filePath, NFS.readFileSync(filePath, "utf-8")), filePath, exportName, allowCompilerTransform, importDepth, nextVisitedModules, argumentsList);
66360
+ return analyzeConfigSourceFileExport(parseConfigSourceFile(filePath, NFS.readFileSync(filePath, "utf-8")), filePath, exportName, allowCompilerTransform, importDepth, nextVisitedModules, argumentsList, argumentAnalysis);
65843
66361
  };
65844
- const analyzeConfigSourceFileExport = (sourceFile, filePath, exportName, allowCompilerTransform, importDepth, visitedModules, argumentsList = []) => {
66362
+ const analyzeConfigSourceFileExport = (sourceFile, filePath, exportName, allowCompilerTransform, importDepth, visitedModules, argumentsList = [], argumentAnalysis) => {
65845
66363
  const analysis = {
65846
66364
  filePath,
65847
66365
  sourceFile,
@@ -65851,14 +66369,27 @@ const analyzeConfigSourceFileExport = (sourceFile, filePath, exportName, allowCo
65851
66369
  localBindings: /* @__PURE__ */ new Map(),
65852
66370
  activeFunctions: /* @__PURE__ */ new Set()
65853
66371
  };
66372
+ const resolvedArgumentAnalysis = argumentAnalysis ?? analysis;
65854
66373
  const exportedConfigNodes = getExportedConfigNodes(sourceFile, exportName);
65855
- return exportedConfigNodes.some((node) => ts.isArrowFunction(node) || ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node) ? analyzeConfigFunction(node, analysis, allowCompilerTransform, argumentsList) : analyzeConfigNode(node, analysis, allowCompilerTransform)) || getReExportedConfigModules(sourceFile, exportName).some((binding) => {
66374
+ return exportedConfigNodes.some((node) => {
66375
+ if (ts.isArrowFunction(node) || ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) return analyzeConfigFunction(node, analysis, allowCompilerTransform, argumentsList, resolvedArgumentAnalysis);
66376
+ if (argumentsList.length > 0 && ts.isIdentifier(node)) {
66377
+ const topLevelBinding = getTopLevelBinding(sourceFile, node.text);
66378
+ if (topLevelBinding && ts.isFunctionLike(topLevelBinding)) return analyzeConfigFunction(topLevelBinding, analysis, allowCompilerTransform, argumentsList, resolvedArgumentAnalysis);
66379
+ const importBinding = getImportBinding(sourceFile, node.text);
66380
+ if (importBinding) {
66381
+ const importedFilePath = resolveImportedConfigFile(filePath, importBinding.moduleSpecifier);
66382
+ return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, importBinding.exportName, allowCompilerTransform, importDepth + 1, visitedModules, argumentsList, resolvedArgumentAnalysis));
66383
+ }
66384
+ }
66385
+ return analyzeConfigNode(node, analysis, allowCompilerTransform);
66386
+ }) || getReExportedConfigModules(sourceFile, exportName).some((binding) => {
65856
66387
  if (exportedConfigNodes.length > 0 && binding.isNamespace) return false;
65857
66388
  const importedFilePath = resolveImportedConfigFile(filePath, binding.moduleSpecifier);
65858
- return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, binding.exportName, allowCompilerTransform, importDepth + 1, visitedModules, argumentsList));
66389
+ return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, binding.exportName, allowCompilerTransform, importDepth + 1, visitedModules, argumentsList, resolvedArgumentAnalysis));
65859
66390
  });
65860
66391
  };
65861
- const analyzeConfigFunction = (functionNode, analysis, allowCompilerTransform, argumentsList = []) => {
66392
+ const analyzeConfigFunction = (functionNode, analysis, allowCompilerTransform, argumentsList = [], argumentAnalysis = analysis) => {
65862
66393
  if (!functionNode.body) return false;
65863
66394
  if (analysis.activeFunctions.has(functionNode.pos)) return false;
65864
66395
  const activeFunctions = new Set(analysis.activeFunctions);
@@ -65866,7 +66397,7 @@ const analyzeConfigFunction = (functionNode, analysis, allowCompilerTransform, a
65866
66397
  const functionAnalysis = {
65867
66398
  ...analysis,
65868
66399
  visitedNodes: /* @__PURE__ */ new Set(),
65869
- localBindings: getFunctionLocalBindings(functionNode, argumentsList),
66400
+ localBindings: getFunctionLocalBindings(functionNode, argumentsList, argumentAnalysis, analysis),
65870
66401
  activeFunctions
65871
66402
  };
65872
66403
  if (!ts.isBlock(functionNode.body)) return analyzeConfigNode(functionNode.body, functionAnalysis, allowCompilerTransform);
@@ -65882,6 +66413,11 @@ const analyzeConfigFunction = (functionNode, analysis, allowCompilerTransform, a
65882
66413
  visitReturns(functionNode.body);
65883
66414
  return hasCompiler;
65884
66415
  };
66416
+ const analyzeImportedConfig = ({ analysis, moduleSpecifier, exportName, allowCompilerTransform, argumentsList }) => {
66417
+ const importedFilePath = resolveImportedConfigFile(analysis.filePath, moduleSpecifier);
66418
+ if (!importedFilePath) return null;
66419
+ return analyzeConfigModuleExport(importedFilePath, exportName, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules, argumentsList, analysis);
66420
+ };
65885
66421
  const analyzeConfigIdentifier = (identifier, analysis, allowCompilerTransform, isCompilerTransformCollection, excludedPropertyNames) => {
65886
66422
  const assignedReactCompiler = getAssignedPropertyInitializer(identifier, "reactCompiler");
65887
66423
  if (assignedReactCompiler.initializer && !isStaticallyDisabledConfigExpression(assignedReactCompiler.initializer, analysis)) return true;
@@ -65894,42 +66430,74 @@ const analyzeConfigIdentifier = (identifier, analysis, allowCompilerTransform, i
65894
66430
  if (assignedPlugins.wasFound) overriddenPropertyNames.add("plugins");
65895
66431
  if (assignedPresets.wasFound) overriddenPropertyNames.add("presets");
65896
66432
  if (analysis.localBindings.has(identifier.text)) {
65897
- const localInitializer = analysis.localBindings.get(identifier.text);
65898
- return Boolean(localInitializer && analyzeConfigNode(localInitializer, analysis, allowCompilerTransform, isCompilerTransformCollection, overriddenPropertyNames));
66433
+ const localReference = analysis.localBindings.get(identifier.text);
66434
+ return Boolean(localReference?.expression && analyzeConfigNode(localReference.expression, localReference.analysis, allowCompilerTransform, isCompilerTransformCollection, overriddenPropertyNames));
65899
66435
  }
65900
66436
  const scopedBinding = getScopedConfigBinding(identifier);
65901
66437
  if (scopedBinding.wasFound) return Boolean(scopedBinding.initializer && analyzeConfigNode(scopedBinding.initializer, analysis, allowCompilerTransform, isCompilerTransformCollection, overriddenPropertyNames));
65902
66438
  const importBinding = getImportBinding(analysis.sourceFile, identifier.text);
65903
66439
  if (importBinding) {
65904
66440
  if (allowCompilerTransform && isCompilerTransformModule(importBinding.moduleSpecifier, importBinding.exportName)) return true;
65905
- if (!importBinding.moduleSpecifier.startsWith(".")) return false;
65906
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, importBinding.moduleSpecifier);
65907
- return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, importBinding.exportName, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules));
66441
+ return Boolean(analyzeImportedConfig({
66442
+ analysis,
66443
+ moduleSpecifier: importBinding.moduleSpecifier,
66444
+ exportName: importBinding.exportName,
66445
+ allowCompilerTransform
66446
+ }));
65908
66447
  }
65909
66448
  const topLevelBinding = getTopLevelBinding(analysis.sourceFile, identifier.text);
65910
66449
  return Boolean(topLevelBinding && analyzeConfigNode(topLevelBinding, analysis, allowCompilerTransform, isCompilerTransformCollection, overriddenPropertyNames));
65911
66450
  };
65912
66451
  const analyzeConfigCallTarget = (callExpression, analysis, allowCompilerTransform) => {
65913
66452
  const target = callExpression.expression;
66453
+ const callableRequiredModuleSpecifier = getRequireModuleSpecifier$1(target);
66454
+ if (callableRequiredModuleSpecifier !== null) {
66455
+ if (ts.isCallExpression(target) && ts.isIdentifier(target.expression) && (analysis.localBindings.has(target.expression.text) || getScopedConfigBinding(target.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
66456
+ if (allowCompilerTransform && isCompilerTransformModule(callableRequiredModuleSpecifier, "default")) return true;
66457
+ const hasCompilerTransform = analyzeImportedConfig({
66458
+ analysis,
66459
+ moduleSpecifier: callableRequiredModuleSpecifier,
66460
+ exportName: "default",
66461
+ allowCompilerTransform,
66462
+ argumentsList: callExpression.arguments
66463
+ });
66464
+ if (isLocalModuleSpecifier(callableRequiredModuleSpecifier) || hasCompilerTransform !== null) return Boolean(hasCompilerTransform);
66465
+ return null;
66466
+ }
65914
66467
  if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return null;
65915
66468
  const propertyName = ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null;
65916
66469
  if (propertyName === null) return null;
65917
- const requiredModuleSpecifier = getRequireModuleSpecifier(target.expression);
66470
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(target.expression);
65918
66471
  if (requiredModuleSpecifier !== null) {
65919
- if (ts.isCallExpression(target.expression) && ts.isIdentifier(target.expression.expression) && (getScopedConfigBinding(target.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
65920
- if (!requiredModuleSpecifier.startsWith(".")) return null;
65921
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, requiredModuleSpecifier);
65922
- return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, propertyName, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules, callExpression.arguments));
66472
+ if (ts.isCallExpression(target.expression) && ts.isIdentifier(target.expression.expression) && (analysis.localBindings.has(target.expression.expression.text) || getScopedConfigBinding(target.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
66473
+ if (allowCompilerTransform && isCompilerTransformModule(requiredModuleSpecifier, propertyName)) return true;
66474
+ const hasCompilerTransform = analyzeImportedConfig({
66475
+ analysis,
66476
+ moduleSpecifier: requiredModuleSpecifier,
66477
+ exportName: propertyName,
66478
+ allowCompilerTransform,
66479
+ argumentsList: callExpression.arguments
66480
+ });
66481
+ if (isLocalModuleSpecifier(requiredModuleSpecifier) || hasCompilerTransform !== null) return Boolean(hasCompilerTransform);
66482
+ return null;
65923
66483
  }
65924
66484
  if (!ts.isIdentifier(target.expression)) return null;
65925
- const importBinding = getImportBinding(analysis.sourceFile, target.expression.text);
65926
- if (importBinding?.isNamespace && importBinding.moduleSpecifier.startsWith(".")) {
65927
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, importBinding.moduleSpecifier);
65928
- return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, propertyName, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules, callExpression.arguments));
66485
+ const importBinding = analysis.localBindings.has(target.expression.text) || getScopedConfigBinding(target.expression).wasFound ? null : getImportBinding(analysis.sourceFile, target.expression.text);
66486
+ if (importBinding?.isNamespace) {
66487
+ if (allowCompilerTransform && isCompilerTransformModule(importBinding.moduleSpecifier, propertyName)) return true;
66488
+ const hasCompilerTransform = analyzeImportedConfig({
66489
+ analysis,
66490
+ moduleSpecifier: importBinding.moduleSpecifier,
66491
+ exportName: propertyName,
66492
+ allowCompilerTransform,
66493
+ argumentsList: callExpression.arguments
66494
+ });
66495
+ if (isLocalModuleSpecifier(importBinding.moduleSpecifier) || hasCompilerTransform !== null) return Boolean(hasCompilerTransform);
66496
+ return null;
65929
66497
  }
65930
66498
  const selectedProperty = getSelectedObjectProperty(target.expression, propertyName, analysis);
65931
66499
  if (selectedProperty === null) return null;
65932
- return ts.isFunctionLike(selectedProperty) ? analyzeConfigFunction(selectedProperty, analysis, allowCompilerTransform, callExpression.arguments) : analyzeConfigNode(selectedProperty, analysis, allowCompilerTransform);
66500
+ return ts.isFunctionLike(selectedProperty.node) ? analyzeConfigFunction(selectedProperty.node, selectedProperty.analysis, allowCompilerTransform, callExpression.arguments, analysis) : analyzeConfigNode(selectedProperty.node, selectedProperty.analysis, allowCompilerTransform);
65933
66501
  };
65934
66502
  const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTransformCollection = false, excludedPropertyNames) => {
65935
66503
  const excludedPropertiesVisitKey = excludedPropertyNames ? [...excludedPropertyNames].sort().join(",") : "";
@@ -65943,25 +66511,29 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
65943
66511
  const reactCompilerFlagState = excludedPropertyNames?.has("reactCompiler") ? null : getReactCompilerFlagState(node, analysis);
65944
66512
  if (reactCompilerFlagState?.isEnabled) return true;
65945
66513
  for (const [propertyIndex, property] of node.properties.entries()) if (ts.isPropertyAssignment(property)) {
65946
- const propertyName = getStaticPropertyName$1(property.name);
66514
+ const propertyName = getStaticPropertyName$2(property.name);
65947
66515
  if (propertyName && excludedPropertyNames?.has(propertyName)) continue;
65948
66516
  if (propertyName === "reactCompiler") continue;
65949
- if ((propertyName === "plugins" || propertyName === "presets") && node.properties.slice(propertyIndex + 1).some((laterProperty) => ts.isSpreadAssignment(laterProperty) && configExpressionMayDefineProperty(laterProperty.expression, propertyName, analysis) || (ts.isPropertyAssignment(laterProperty) || ts.isShorthandPropertyAssignment(laterProperty)) && getStaticPropertyName$1(laterProperty.name) === propertyName)) continue;
66517
+ if ((propertyName === "plugins" || propertyName === "presets") && node.properties.slice(propertyIndex + 1).some((laterProperty) => ts.isSpreadAssignment(laterProperty) && configExpressionMayDefineProperty(laterProperty.expression, propertyName, analysis) || (ts.isPropertyAssignment(laterProperty) || ts.isShorthandPropertyAssignment(laterProperty)) && getStaticPropertyName$2(laterProperty.name) === propertyName)) continue;
65950
66518
  const propertyAllowsCompilerTransform = propertyName === "plugins" || propertyName === "presets";
65951
- if (propertyName === "extends" && ts.isStringLiteralLike(property.initializer) && property.initializer.text.startsWith(".")) {
65952
- const extendedFilePath = resolveImportedConfigFile(analysis.filePath, property.initializer.text);
65953
- if (extendedFilePath && analyzeConfigModuleExport(extendedFilePath, "default", false, analysis.importDepth + 1, analysis.visitedModules)) return true;
66519
+ if (propertyName === "extends" && ts.isStringLiteralLike(property.initializer)) {
66520
+ if (analyzeImportedConfig({
66521
+ analysis,
66522
+ moduleSpecifier: property.initializer.text,
66523
+ exportName: "default",
66524
+ allowCompilerTransform: false
66525
+ })) return true;
65954
66526
  }
65955
66527
  if (analyzeConfigNode(property.initializer, analysis, propertyAllowsCompilerTransform, propertyAllowsCompilerTransform)) return true;
65956
66528
  } else if (ts.isShorthandPropertyAssignment(property)) {
65957
66529
  if (excludedPropertyNames?.has(property.name.text)) continue;
65958
66530
  if (property.name.text === "reactCompiler") continue;
65959
- if ((property.name.text === "plugins" || property.name.text === "presets") && node.properties.slice(propertyIndex + 1).some((laterProperty) => ts.isSpreadAssignment(laterProperty) && configExpressionMayDefineProperty(laterProperty.expression, property.name.text, analysis) || (ts.isPropertyAssignment(laterProperty) || ts.isShorthandPropertyAssignment(laterProperty)) && getStaticPropertyName$1(laterProperty.name) === property.name.text)) continue;
66531
+ if ((property.name.text === "plugins" || property.name.text === "presets") && node.properties.slice(propertyIndex + 1).some((laterProperty) => ts.isSpreadAssignment(laterProperty) && configExpressionMayDefineProperty(laterProperty.expression, property.name.text, analysis) || (ts.isPropertyAssignment(laterProperty) || ts.isShorthandPropertyAssignment(laterProperty)) && getStaticPropertyName$2(laterProperty.name) === property.name.text)) continue;
65960
66532
  const propertyAllowsCompilerTransform = property.name.text === "plugins" || property.name.text === "presets";
65961
66533
  if (analyzeConfigNode(property.name, analysis, propertyAllowsCompilerTransform, propertyAllowsCompilerTransform)) return true;
65962
66534
  } else if (ts.isSpreadAssignment(property)) {
65963
66535
  if (reactCompilerFlagState && getReactCompilerFlagState(property.expression, analysis) !== null) continue;
65964
- if (node.properties.slice(propertyIndex + 1).some((laterProperty) => (ts.isPropertyAssignment(laterProperty) || ts.isShorthandPropertyAssignment(laterProperty)) && (getStaticPropertyName$1(laterProperty.name) === "plugins" || getStaticPropertyName$1(laterProperty.name) === "presets"))) continue;
66536
+ if (node.properties.slice(propertyIndex + 1).some((laterProperty) => (ts.isPropertyAssignment(laterProperty) || ts.isShorthandPropertyAssignment(laterProperty)) && (getStaticPropertyName$2(laterProperty.name) === "plugins" || getStaticPropertyName$2(laterProperty.name) === "presets"))) continue;
65965
66537
  if (analyzeConfigNode(property.expression, analysis, allowCompilerTransform, false, excludedPropertyNames)) return true;
65966
66538
  }
65967
66539
  return false;
@@ -65974,23 +66546,36 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
65974
66546
  });
65975
66547
  }
65976
66548
  if (ts.isCallExpression(node)) {
66549
+ const resolvedModuleSpecifier = getNodeRequireResolveModuleSpecifier(node, analysis);
66550
+ if (resolvedModuleSpecifier !== null) return allowCompilerTransform && isCompilerTransformModule(resolvedModuleSpecifier, "default");
65977
66551
  const callTargetResult = analyzeConfigCallTarget(node, analysis, allowCompilerTransform);
65978
66552
  if (callTargetResult !== null) return callTargetResult;
65979
- const directModuleSpecifier = getRequireModuleSpecifier(node);
66553
+ const directModuleSpecifier = getRequireModuleSpecifier$1(node);
65980
66554
  const isRequireShadowed = analysis.localBindings.has("require") || ts.isIdentifier(node.expression) && getScopedConfigBinding(node.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require");
65981
66555
  if (directModuleSpecifier && isRequireShadowed) return analyzeConfigNode(node.expression, analysis, allowCompilerTransform);
65982
66556
  if (directModuleSpecifier && !isRequireShadowed) {
65983
66557
  if (allowCompilerTransform && isCompilerTransformModule(directModuleSpecifier, "default")) return true;
65984
- if (directModuleSpecifier.startsWith(".")) {
65985
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, directModuleSpecifier);
65986
- if (importedFilePath && analyzeConfigModuleExport(importedFilePath, "default", allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules)) return true;
65987
- }
66558
+ if (analyzeImportedConfig({
66559
+ analysis,
66560
+ moduleSpecifier: directModuleSpecifier,
66561
+ exportName: "default",
66562
+ allowCompilerTransform
66563
+ })) return true;
65988
66564
  }
65989
66565
  if (ts.isIdentifier(node.expression)) {
65990
- const importBinding = getImportBinding(analysis.sourceFile, node.expression.text);
65991
- if (importBinding?.moduleSpecifier.startsWith(".")) {
65992
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, importBinding.moduleSpecifier);
65993
- return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, importBinding.exportName, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules, node.arguments));
66566
+ if (!analysis.localBindings.has(node.expression.text) && !getScopedConfigBinding(node.expression).wasFound) {
66567
+ const importBinding = getImportBinding(analysis.sourceFile, node.expression.text);
66568
+ if (importBinding) {
66569
+ if (allowCompilerTransform && isCompilerTransformModule(importBinding.moduleSpecifier, importBinding.exportName)) return true;
66570
+ const hasCompilerTransform = analyzeImportedConfig({
66571
+ analysis,
66572
+ moduleSpecifier: importBinding.moduleSpecifier,
66573
+ exportName: importBinding.exportName,
66574
+ allowCompilerTransform,
66575
+ argumentsList: node.arguments
66576
+ });
66577
+ if (isLocalModuleSpecifier(importBinding.moduleSpecifier) || hasCompilerTransform !== null) return Boolean(hasCompilerTransform);
66578
+ }
65994
66579
  }
65995
66580
  const topLevelBinding = getTopLevelBinding(analysis.sourceFile, node.expression.text);
65996
66581
  if (topLevelBinding && ts.isFunctionLike(topLevelBinding) && analyzeConfigFunction(topLevelBinding, analysis, allowCompilerTransform, node.arguments)) return true;
@@ -65998,47 +66583,57 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
65998
66583
  return analyzeConfigNode(node.expression, analysis, allowCompilerTransform) || node.arguments.some((argument) => analyzeConfigNode(argument, analysis, false));
65999
66584
  }
66000
66585
  if (ts.isPropertyAccessExpression(node)) {
66001
- const requiredModuleSpecifier = getRequireModuleSpecifier(node.expression);
66586
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(node.expression);
66002
66587
  if (requiredModuleSpecifier) {
66003
- if (ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression) && (getScopedConfigBinding(node.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
66004
- if (requiredModuleSpecifier.startsWith(".")) {
66005
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, requiredModuleSpecifier);
66006
- return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, node.name.text, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules));
66007
- }
66588
+ if (ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression) && (analysis.localBindings.has(node.expression.expression.text) || getScopedConfigBinding(node.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
66589
+ if (analyzeImportedConfig({
66590
+ analysis,
66591
+ moduleSpecifier: requiredModuleSpecifier,
66592
+ exportName: node.name.text,
66593
+ allowCompilerTransform
66594
+ })) return true;
66008
66595
  return allowCompilerTransform && isCompilerTransformModule(requiredModuleSpecifier, node.name.text);
66009
66596
  }
66010
66597
  if (ts.isIdentifier(node.expression)) {
66011
- if (analysis.localBindings.has(node.expression.text)) {
66012
- const localInitializer = analysis.localBindings.get(node.expression.text);
66013
- return Boolean(localInitializer && analyzeConfigNode(localInitializer, analysis, allowCompilerTransform));
66598
+ if (analysis.localBindings.has(node.expression.text) || getScopedConfigBinding(node.expression).wasFound) {
66599
+ const selectedProperty = getSelectedObjectProperty(node.expression, node.name.text, analysis);
66600
+ return Boolean(selectedProperty && analyzeConfigNode(selectedProperty.node, selectedProperty.analysis, allowCompilerTransform));
66014
66601
  }
66015
66602
  const importBinding = getImportBinding(analysis.sourceFile, node.expression.text);
66016
66603
  if (importBinding?.isNamespace) {
66017
66604
  if (allowCompilerTransform && isCompilerTransformModule(importBinding.moduleSpecifier, node.name.text)) return true;
66018
- if (importBinding.moduleSpecifier.startsWith(".")) {
66019
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, importBinding.moduleSpecifier);
66020
- if (importedFilePath && analyzeConfigModuleExport(importedFilePath, node.name.text, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules)) return true;
66021
- }
66605
+ if (analyzeImportedConfig({
66606
+ analysis,
66607
+ moduleSpecifier: importBinding.moduleSpecifier,
66608
+ exportName: node.name.text,
66609
+ allowCompilerTransform
66610
+ })) return true;
66022
66611
  return false;
66023
66612
  }
66024
66613
  const selectedProperty = getSelectedObjectProperty(node.expression, node.name.text, analysis);
66025
- if (selectedProperty) return analyzeConfigNode(selectedProperty, analysis, allowCompilerTransform);
66614
+ if (selectedProperty) return analyzeConfigNode(selectedProperty.node, selectedProperty.analysis, allowCompilerTransform);
66026
66615
  return false;
66027
66616
  }
66028
66617
  return analyzeConfigNode(node.expression, analysis, allowCompilerTransform);
66029
66618
  }
66030
66619
  if (ts.isElementAccessExpression(node) && node.argumentExpression && ts.isStringLiteralLike(node.argumentExpression)) {
66031
66620
  if (ts.isIdentifier(node.expression)) {
66621
+ if (analysis.localBindings.has(node.expression.text) || getScopedConfigBinding(node.expression).wasFound) {
66622
+ const selectedProperty = getSelectedObjectProperty(node.expression, node.argumentExpression.text, analysis);
66623
+ return Boolean(selectedProperty && analyzeConfigNode(selectedProperty.node, selectedProperty.analysis, allowCompilerTransform));
66624
+ }
66032
66625
  const importBinding = getImportBinding(analysis.sourceFile, node.expression.text);
66033
66626
  if (importBinding?.isNamespace) {
66034
66627
  if (allowCompilerTransform && isCompilerTransformModule(importBinding.moduleSpecifier, node.argumentExpression.text)) return true;
66035
- if (importBinding.moduleSpecifier.startsWith(".")) {
66036
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, importBinding.moduleSpecifier);
66037
- return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, node.argumentExpression.text, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules));
66038
- }
66628
+ return Boolean(analyzeImportedConfig({
66629
+ analysis,
66630
+ moduleSpecifier: importBinding.moduleSpecifier,
66631
+ exportName: node.argumentExpression.text,
66632
+ allowCompilerTransform
66633
+ }));
66039
66634
  }
66040
66635
  const selectedProperty = getSelectedObjectProperty(node.expression, node.argumentExpression.text, analysis);
66041
- if (selectedProperty) return analyzeConfigNode(selectedProperty, analysis, allowCompilerTransform);
66636
+ if (selectedProperty) return analyzeConfigNode(selectedProperty.node, selectedProperty.analysis, allowCompilerTransform);
66042
66637
  return false;
66043
66638
  }
66044
66639
  return analyzeConfigNode(node.expression, analysis, allowCompilerTransform);
@@ -66073,14 +66668,19 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
66073
66668
  };
66074
66669
  const hasCompilerInConfigFile = (filePath) => analyzeConfigModuleExport(filePath, "default", false, 0, /* @__PURE__ */ new Set());
66075
66670
  const hasCompilerInConfigFiles = (directory, filenames) => filenames.some((filename) => hasCompilerInConfigFile(Path.join(directory, filename)));
66076
- const hasCompilerInPackageJsonConfig = (packageJson) => isPlainObject(packageJson.babel) && analyzeConfigSourceFileExport(ts.parseJsonText("package.json", JSON.stringify(packageJson.babel)), "package.json#babel", "default", false, 0, /* @__PURE__ */ new Set());
66077
- const hasCompilerConfiguration = (directory, packageJson) => hasCompilerInPackageJsonConfig(packageJson) || hasCompilerInConfigFiles(directory, REACT_COMPILER_CONFIG_FILENAMES);
66671
+ const hasCompilerInPackageJsonConfig = (directory, packageJson) => {
66672
+ if (!isPlainObject(packageJson.babel)) return false;
66673
+ const packageJsonPath = Path.join(directory, "package.json");
66674
+ return analyzeConfigSourceFileExport(ts.parseJsonText(packageJsonPath, JSON.stringify(packageJson.babel)), packageJsonPath, "default", false, 0, /* @__PURE__ */ new Set());
66675
+ };
66676
+ const hasCompilerConfiguration = (directory, packageJson) => hasCompilerInPackageJsonConfig(directory, packageJson) || hasCompilerInConfigFiles(directory, REACT_COMPILER_CONFIG_FILENAMES);
66078
66677
  const hasCompilerConfigurationInAncestors = (directory) => {
66079
66678
  if (isProjectBoundary(directory)) return false;
66080
66679
  let ancestorDirectory = Path.dirname(directory);
66081
66680
  while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
66082
66681
  const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
66083
- if (hasCompilerInPackageJsonConfig(isFile(ancestorPackagePath) ? readPackageJson$1(ancestorPackagePath) : {}) || hasCompilerInConfigFiles(ancestorDirectory, BABEL_CONFIG_FILENAMES)) return true;
66682
+ const ancestorPackageJson = isFile(ancestorPackagePath) ? readPackageJson$1(ancestorPackagePath) : {};
66683
+ if (hasCompilerInPackageJsonConfig(ancestorDirectory, ancestorPackageJson) || hasCompilerInConfigFiles(ancestorDirectory, BABEL_CONFIG_FILENAMES)) return true;
66084
66684
  if (isProjectBoundary(ancestorDirectory)) return false;
66085
66685
  ancestorDirectory = Path.dirname(ancestorDirectory);
66086
66686
  }
@@ -68410,6 +69010,7 @@ const classifyPackageRole = (filename) => {
68410
69010
  * Resolves the absolute path to read for a diagnostic's `filePath`,
68411
69011
  * accounting for the various shapes oxlint emits:
68412
69012
  *
69013
+ * - `file://` URL — decode to an absolute filesystem path.
68413
69014
  * - Absolute POSIX (`/abs/path/file.tsx`) — pass through.
68414
69015
  * - Absolute Windows (`C:/...` or `C:\...`) — pass through.
68415
69016
  * - `./relative` or bare relative — join against `rootDirectory`.
@@ -68419,6 +69020,7 @@ const classifyPackageRole = (filename) => {
68419
69020
  * use one canonical resolution path.
68420
69021
  */
68421
69022
  const resolveCandidateReadPath = (rootDirectory, filePath) => {
69023
+ if (filePath.startsWith("file://")) return fileURLToPath(filePath);
68422
69024
  const normalizedFile = filePath.replace(/\\/g, "/");
68423
69025
  if (normalizedFile.startsWith("/") || /^[a-zA-Z]:\//.test(normalizedFile) || /^[a-zA-Z]:\\/.test(filePath)) return filePath;
68424
69026
  return `${rootDirectory.replace(/\\/g, "/").replace(/\/$/, "")}/${normalizedFile.replace(/^\.\//, "")}`;
@@ -69335,7 +69937,7 @@ const warn = (message) => {
69335
69937
  runSync(warn$1(message));
69336
69938
  };
69337
69939
  const CONFIG_BASENAME = "doctor.config";
69338
- const CONFIG_EXTENSIONS = [
69940
+ const CONFIG_EXTENSIONS$1 = [
69339
69941
  "ts",
69340
69942
  "mts",
69341
69943
  "cts",
@@ -69439,7 +70041,7 @@ const loadLegacyConfig = (directory) => {
69439
70041
  };
69440
70042
  const loadConfigFromDirectory = async (directory) => {
69441
70043
  let sawBrokenConfigFile = false;
69442
- for (const extension of CONFIG_EXTENSIONS) {
70044
+ for (const extension of CONFIG_EXTENSIONS$1) {
69443
70045
  const filePath = Path.join(directory, `${CONFIG_BASENAME}.${extension}`);
69444
70046
  if (!isFile(filePath)) continue;
69445
70047
  const isDataFile = DATA_CONFIG_EXTENSIONS.has(extension);
@@ -69498,7 +70100,7 @@ const loadConfigWithSource = (rootDirectory) => {
69498
70100
  return loadPromise;
69499
70101
  };
69500
70102
  const directoryHasCurrentConfig = (directory) => {
69501
- for (const extension of CONFIG_EXTENSIONS) if (isFile(Path.join(directory, `${CONFIG_BASENAME}.${extension}`))) return true;
70103
+ for (const extension of CONFIG_EXTENSIONS$1) if (isFile(Path.join(directory, `${CONFIG_BASENAME}.${extension}`))) return true;
69502
70104
  return readEmbeddedPackageJsonConfig(directory) !== null;
69503
70105
  };
69504
70106
  /**
@@ -70202,6 +70804,316 @@ const buildReactNativeDiagnostic = (input) => ({
70202
70804
  column: input.column ?? 0,
70203
70805
  category: input.category ?? "Correctness"
70204
70806
  });
70807
+ const ANDROID_APP_BUILD_FILE_NAMES = ["build.gradle", "build.gradle.kts"];
70808
+ const BUILD_TYPES_BLOCK_PATTERN = /\bbuildTypes\s*\{/g;
70809
+ const RELEASE_STRING_MARKER = "__RD_RELEASE__";
70810
+ const RELEASE_BLOCK_PATTERNS = [/\brelease\s*\{/g, /\b(?:getByName|named)\s*\(\s*(?:["']release["']|__RD_RELEASE__)\s*\)\s*\{/g];
70811
+ const MINIFY_ASSIGNMENT_PATTERN = /\b(?:isMinifyEnabled|minifyEnabled)\b\s*(?:\(\s*|=\s*|\s+)([^;}\r\n]+)/g;
70812
+ const SHRINK_RESOURCES_ASSIGNMENT_PATTERN = /\b(?:isShrinkResources|shrinkResources)\b\s*(?:\(\s*|=\s*|\s+)([^;}\r\n]+)/g;
70813
+ const stripGradleComments = (contents) => {
70814
+ let result = "";
70815
+ let index = 0;
70816
+ let quote = null;
70817
+ while (index < contents.length) {
70818
+ const character = contents[index];
70819
+ const nextCharacter = contents[index + 1];
70820
+ if (quote !== null) {
70821
+ result += character;
70822
+ if (character === "\\") {
70823
+ result += nextCharacter ?? "";
70824
+ index += 2;
70825
+ continue;
70826
+ }
70827
+ if (character === quote) quote = null;
70828
+ index += 1;
70829
+ continue;
70830
+ }
70831
+ if (character === "\"" || character === "'") {
70832
+ quote = character;
70833
+ result += character;
70834
+ index += 1;
70835
+ continue;
70836
+ }
70837
+ if (character === "/" && nextCharacter === "/") {
70838
+ while (index < contents.length && contents[index] !== "\n") {
70839
+ result += " ";
70840
+ index += 1;
70841
+ }
70842
+ continue;
70843
+ }
70844
+ if (character === "/" && nextCharacter === "*") {
70845
+ result += " ";
70846
+ index += 2;
70847
+ while (index < contents.length && !(contents[index] === "*" && contents[index + 1] === "/")) {
70848
+ result += contents[index] === "\n" ? "\n" : " ";
70849
+ index += 1;
70850
+ }
70851
+ if (index < contents.length) {
70852
+ result += " ";
70853
+ index += 2;
70854
+ }
70855
+ continue;
70856
+ }
70857
+ result += character;
70858
+ index += 1;
70859
+ }
70860
+ return result;
70861
+ };
70862
+ const maskGradleStrings = (contents) => {
70863
+ let result = "";
70864
+ let index = 0;
70865
+ let quote = null;
70866
+ while (index < contents.length) {
70867
+ const character = contents[index];
70868
+ if (quote === null) {
70869
+ if (character === "\"" || character === "'") {
70870
+ quote = character;
70871
+ result += " ";
70872
+ } else result += character;
70873
+ index += 1;
70874
+ continue;
70875
+ }
70876
+ if (character === "\\") {
70877
+ result += " ";
70878
+ index += 2;
70879
+ continue;
70880
+ }
70881
+ if (character === quote) quote = null;
70882
+ result += character === "\n" ? "\n" : " ";
70883
+ index += 1;
70884
+ }
70885
+ return result;
70886
+ };
70887
+ const findBlockContents = (contents, pattern) => {
70888
+ const blocks = [];
70889
+ pattern.lastIndex = 0;
70890
+ let match = pattern.exec(contents);
70891
+ while (match !== null) {
70892
+ const openingBraceIndex = pattern.lastIndex - 1;
70893
+ let depth = 1;
70894
+ let index = openingBraceIndex + 1;
70895
+ let quote = null;
70896
+ while (index < contents.length && depth > 0) {
70897
+ const character = contents[index];
70898
+ if (quote !== null) {
70899
+ if (character === "\\") {
70900
+ index += 2;
70901
+ continue;
70902
+ }
70903
+ if (character === quote) quote = null;
70904
+ } else if (character === "\"" || character === "'") quote = character;
70905
+ else if (character === "{") depth += 1;
70906
+ else if (character === "}") depth -= 1;
70907
+ index += 1;
70908
+ }
70909
+ if (depth === 0) blocks.push(contents.slice(openingBraceIndex + 1, index - 1));
70910
+ match = pattern.exec(contents);
70911
+ }
70912
+ return blocks;
70913
+ };
70914
+ const getFinalStaticBoolean = (contents, pattern) => {
70915
+ pattern.lastIndex = 0;
70916
+ let finalValue = null;
70917
+ let match = pattern.exec(contents);
70918
+ while (match !== null) {
70919
+ const staticValue = match[1]?.trim().replace(/\)$/, "").trim();
70920
+ if (staticValue === "true") finalValue = true;
70921
+ else if (staticValue === "false") finalValue = false;
70922
+ else finalValue = null;
70923
+ match = pattern.exec(contents);
70924
+ }
70925
+ return finalValue;
70926
+ };
70927
+ const getReleaseBlocks = (contents) => findBlockContents(contents, BUILD_TYPES_BLOCK_PATTERN).flatMap((buildTypesBlock) => RELEASE_BLOCK_PATTERNS.flatMap((pattern) => findBlockContents(buildTypesBlock, pattern)));
70928
+ const readAndroidReleaseShrinking = (rootDirectory) => {
70929
+ for (const buildFileName of ANDROID_APP_BUILD_FILE_NAMES) {
70930
+ const filePath = Path.posix.join("android", "app", buildFileName);
70931
+ const absoluteFilePath = Path.join(rootDirectory, filePath);
70932
+ if (!isFile(absoluteFilePath)) continue;
70933
+ let contents;
70934
+ try {
70935
+ contents = stripGradleComments(NFS.readFileSync(absoluteFilePath, "utf-8"));
70936
+ } catch {
70937
+ return null;
70938
+ }
70939
+ const releaseBlocks = getReleaseBlocks(maskGradleStrings(contents.replace(/(["'])release\1/g, RELEASE_STRING_MARKER)));
70940
+ const [releaseBlock] = releaseBlocks;
70941
+ if (releaseBlock === void 0 || releaseBlocks.length !== 1) return null;
70942
+ const hasDisabledMinification = getFinalStaticBoolean(releaseBlock, MINIFY_ASSIGNMENT_PATTERN) === false;
70943
+ const hasDisabledResourceShrinking = getFinalStaticBoolean(releaseBlock, SHRINK_RESOURCES_ASSIGNMENT_PATTERN) === false;
70944
+ if (!hasDisabledMinification && !hasDisabledResourceShrinking) return null;
70945
+ return {
70946
+ filePath,
70947
+ hasDisabledMinification,
70948
+ hasDisabledResourceShrinking
70949
+ };
70950
+ }
70951
+ return null;
70952
+ };
70953
+ const checkReactNativeAndroidReleaseShrinking = (rootDirectory) => {
70954
+ const releaseShrinking = readAndroidReleaseShrinking(rootDirectory);
70955
+ if (releaseShrinking === null) return [];
70956
+ const disabledFeatures = [releaseShrinking.hasDisabledMinification ? "code minification" : null, releaseShrinking.hasDisabledResourceShrinking ? "resource shrinking" : null].filter((feature) => feature !== null);
70957
+ return [buildReactNativeDiagnostic({
70958
+ filePath: releaseShrinking.filePath,
70959
+ rule: "rn-android-release-shrinking-disabled",
70960
+ category: "Performance",
70961
+ message: `The Android release build explicitly disables ${disabledFeatures.join(" and ")}, leaving unreachable code or resources in the shipped app.`,
70962
+ help: "Enable release code minification and resource shrinking, then test the optimized build and add keep rules for libraries that require them."
70963
+ })];
70964
+ };
70965
+ const getTypescriptScriptKind = (fileName) => {
70966
+ if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
70967
+ if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
70968
+ if (fileName.endsWith(".ts")) return ts.ScriptKind.TS;
70969
+ return ts.ScriptKind.JS;
70970
+ };
70971
+ const BABEL_CONFIG_FILE_NAMES$1 = [
70972
+ "babel.config.js",
70973
+ "babel.config.cjs",
70974
+ "babel.config.mjs",
70975
+ "babel.config.ts",
70976
+ "babel.config.cts",
70977
+ "babel.config.json",
70978
+ ".babelrc",
70979
+ ".babelrc.js",
70980
+ ".babelrc.cjs",
70981
+ ".babelrc.mjs",
70982
+ ".babelrc.cts",
70983
+ ".babelrc.json"
70984
+ ];
70985
+ const readUnknownPluginNames = (value) => {
70986
+ if (!Array.isArray(value)) return null;
70987
+ const pluginNames = [];
70988
+ for (const entry of value) {
70989
+ if (typeof entry === "string") {
70990
+ pluginNames.push(entry);
70991
+ continue;
70992
+ }
70993
+ if (Array.isArray(entry) && typeof entry[0] === "string") {
70994
+ pluginNames.push(entry[0]);
70995
+ continue;
70996
+ }
70997
+ return null;
70998
+ }
70999
+ return pluginNames;
71000
+ };
71001
+ const getStaticPropertyName$1 = (propertyName) => {
71002
+ if (ts.isIdentifier(propertyName) || ts.isStringLiteralLike(propertyName)) return propertyName.text;
71003
+ return null;
71004
+ };
71005
+ const getStaticPluginName = (expression) => {
71006
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
71007
+ if (ts.isStringLiteralLike(unwrappedExpression)) return unwrappedExpression.text;
71008
+ if (!ts.isArrayLiteralExpression(unwrappedExpression)) return null;
71009
+ const pluginExpression = unwrappedExpression.elements[0];
71010
+ return pluginExpression && ts.isStringLiteralLike(pluginExpression) ? pluginExpression.text : null;
71011
+ };
71012
+ const getPluginNamesFromObject = (objectExpression) => {
71013
+ if (objectExpression.properties.some((property) => ts.isSpreadAssignment(property))) return null;
71014
+ const pluginProperties = objectExpression.properties.filter((property) => ts.isPropertyAssignment(property) && getStaticPropertyName$1(property.name) === "plugins");
71015
+ if (pluginProperties.length !== 1) return pluginProperties.length === 0 ? [] : null;
71016
+ const pluginListExpression = unwrapTypescriptExpression(pluginProperties[0].initializer);
71017
+ if (!ts.isArrayLiteralExpression(pluginListExpression)) return null;
71018
+ const pluginNames = [];
71019
+ for (const element of pluginListExpression.elements) {
71020
+ if (ts.isSpreadElement(element)) return null;
71021
+ const pluginName = getStaticPluginName(element);
71022
+ if (pluginName === null) return null;
71023
+ pluginNames.push(pluginName);
71024
+ }
71025
+ return pluginNames;
71026
+ };
71027
+ const isModuleExports = (expression) => ts.isPropertyAccessExpression(expression) && ts.isIdentifier(expression.expression) && expression.expression.text === "module" && expression.name.text === "exports" || ts.isElementAccessExpression(expression) && ts.isIdentifier(expression.expression) && expression.expression.text === "module" && expression.argumentExpression !== void 0 && ts.isStringLiteralLike(expression.argumentExpression) && expression.argumentExpression.text === "exports";
71028
+ const getDirectExportedObject = (sourceFile) => {
71029
+ const exportedExpressions = [];
71030
+ for (const statement of sourceFile.statements) {
71031
+ if (ts.isExportAssignment(statement)) {
71032
+ exportedExpressions.push(statement.expression);
71033
+ continue;
71034
+ }
71035
+ if (ts.isExpressionStatement(statement) && ts.isBinaryExpression(statement.expression) && statement.expression.operatorToken.kind === ts.SyntaxKind.EqualsToken && isModuleExports(statement.expression.left)) exportedExpressions.push(statement.expression.right);
71036
+ }
71037
+ if (exportedExpressions.length !== 1) return null;
71038
+ const exportedExpression = unwrapTypescriptExpression(exportedExpressions[0]);
71039
+ return ts.isObjectLiteralExpression(exportedExpression) ? exportedExpression : null;
71040
+ };
71041
+ const parseConfigPluginNames = (filePath, contents) => {
71042
+ try {
71043
+ const parsedJson = JSON.parse(contents);
71044
+ return isPlainObject(parsedJson) ? readUnknownPluginNames(parsedJson.plugins) : null;
71045
+ } catch {
71046
+ if (ts.transpileModule(contents, {
71047
+ fileName: filePath,
71048
+ reportDiagnostics: true,
71049
+ compilerOptions: { allowJs: true }
71050
+ }).diagnostics?.some((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error)) return null;
71051
+ const exportedObject = getDirectExportedObject(ts.createSourceFile(filePath, contents, ts.ScriptTarget.Latest, true, getTypescriptScriptKind(filePath)));
71052
+ return exportedObject === null ? null : getPluginNamesFromObject(exportedObject);
71053
+ }
71054
+ };
71055
+ const readStaticBabelPluginNames = (rootDirectory) => {
71056
+ for (const fileName of BABEL_CONFIG_FILE_NAMES$1) {
71057
+ const absoluteFilePath = Path.join(rootDirectory, fileName);
71058
+ if (!isFile(absoluteFilePath)) continue;
71059
+ try {
71060
+ return {
71061
+ filePath: fileName,
71062
+ pluginNames: parseConfigPluginNames(fileName, NFS.readFileSync(absoluteFilePath, "utf-8"))
71063
+ };
71064
+ } catch {
71065
+ return {
71066
+ filePath: fileName,
71067
+ pluginNames: null
71068
+ };
71069
+ }
71070
+ }
71071
+ const packageJson = readPackageJson$1(Path.join(rootDirectory, "package.json"));
71072
+ if (!isPlainObject(packageJson.babel)) return null;
71073
+ return {
71074
+ filePath: "package.json",
71075
+ pluginNames: readUnknownPluginNames(packageJson.babel.plugins)
71076
+ };
71077
+ };
71078
+ const REACT_COMPILER_PLUGIN_NAMES = new Set(["babel-plugin-react-compiler", "react-compiler"]);
71079
+ const REANIMATED_PLUGIN_NAME = "react-native-reanimated/plugin";
71080
+ const WORKLETS_PLUGIN_NAME = "react-native-worklets/plugin";
71081
+ const checkReactCompilerPluginOrder = (filePath, pluginNames) => {
71082
+ if (pluginNames.findIndex((pluginName) => REACT_COMPILER_PLUGIN_NAMES.has(pluginName)) <= 0) return [];
71083
+ return [buildReactNativeDiagnostic({
71084
+ filePath,
71085
+ rule: "rn-react-compiler-plugin-first",
71086
+ category: "Performance",
71087
+ message: "The React Compiler Babel plugin is not first, so an earlier transform can change component or hook code before the compiler analyzes it.",
71088
+ help: "Move `babel-plugin-react-compiler` to the first entry in the Babel `plugins` array."
71089
+ })];
71090
+ };
71091
+ const checkReanimatedPluginOrder = (project, filePath, pluginNames) => {
71092
+ const reanimatedMajorVersion = project.reanimatedVersion === null || project.reanimatedVersion === void 0 ? null : getLowestDependencyMajor(project.reanimatedVersion);
71093
+ if (reanimatedMajorVersion === null || reanimatedMajorVersion < 4) return [];
71094
+ const diagnostics = [];
71095
+ if (pluginNames.includes(REANIMATED_PLUGIN_NAME)) diagnostics.push(buildReactNativeDiagnostic({
71096
+ filePath,
71097
+ rule: "rn-reanimated-worklets-plugin-last",
71098
+ category: "Performance",
71099
+ message: "This Reanimated 4 project still uses `react-native-reanimated/plugin`, which was renamed to the Worklets Babel plugin.",
71100
+ help: "Replace it with `react-native-worklets/plugin` and keep that plugin last in the Babel `plugins` array."
71101
+ }));
71102
+ const workletsPluginIndex = pluginNames.lastIndexOf(WORKLETS_PLUGIN_NAME);
71103
+ if (workletsPluginIndex !== -1 && workletsPluginIndex !== pluginNames.length - 1) diagnostics.push(buildReactNativeDiagnostic({
71104
+ filePath,
71105
+ rule: "rn-reanimated-worklets-plugin-last",
71106
+ category: "Performance",
71107
+ message: "`react-native-worklets/plugin` is not last in the Babel `plugins` array, so later transforms can prevent worklets from being compiled correctly.",
71108
+ help: "Move `react-native-worklets/plugin` to the final entry in the Babel `plugins` array."
71109
+ }));
71110
+ return diagnostics;
71111
+ };
71112
+ const checkReactNativeBabelPluginOrder = (rootDirectory, project) => {
71113
+ const babelPlugins = readStaticBabelPluginNames(rootDirectory);
71114
+ if (babelPlugins === null || babelPlugins.pluginNames === null) return [];
71115
+ return [...checkReactCompilerPluginOrder(babelPlugins.filePath, babelPlugins.pluginNames), ...checkReanimatedPluginOrder(project, babelPlugins.filePath, babelPlugins.pluginNames)];
71116
+ };
70205
71117
  const BUILDER_BOB_PACKAGE = "react-native-builder-bob";
70206
71118
  const isBuilderBobLibrary = (packageJson) => {
70207
71119
  const bobConfig = packageJson[BUILDER_BOB_PACKAGE];
@@ -70278,7 +71190,12 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
70278
71190
  const isReactNativeProject = (project) => project.framework === "react-native" || project.framework === "expo" || project.hasReactNativeWorkspace || project.expoVersion !== null;
70279
71191
  const checkReactNativeProject = (rootDirectory, project) => {
70280
71192
  if (!isReactNativeProject(project)) return [];
70281
- return [...checkReactNativeMetroBabelPreset(rootDirectory), ...checkReactNativeLibraryDependencies(rootDirectory)];
71193
+ return [
71194
+ ...checkReactNativeMetroBabelPreset(rootDirectory),
71195
+ ...checkReactNativeBabelPluginOrder(rootDirectory, project),
71196
+ ...checkReactNativeAndroidReleaseShrinking(rootDirectory),
71197
+ ...checkReactNativeLibraryDependencies(rootDirectory)
71198
+ ];
70282
71199
  };
70283
71200
  const RULE_KEY = "no-vulnerable-react-server-components";
70284
71201
  const REACT_RSC_ADVISORIES_BY_MINOR = {
@@ -70429,17 +71346,6 @@ const checkReactServerComponentsAdvisory = (scanDirectory, project) => {
70429
71346
  }
70430
71347
  return diagnostics;
70431
71348
  };
70432
- const getTypescriptScriptKind = (fileName) => {
70433
- if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
70434
- if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
70435
- if (fileName.endsWith(".ts")) return ts.ScriptKind.TS;
70436
- return ts.ScriptKind.JS;
70437
- };
70438
- const unwrapTypescriptExpression = (expression) => {
70439
- let currentExpression = expression;
70440
- while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
70441
- return currentExpression;
70442
- };
70443
71349
  const EMPTY_MOTION_EXPRESSION_EVIDENCE = {
70444
71350
  isAnimationFunction: false,
70445
71351
  isMotionComponent: false,
@@ -70995,7 +71901,11 @@ const buildCapabilities = (project) => {
70995
71901
  capabilities.add(project.framework);
70996
71902
  if (project.reactVersion !== null || project.preactVersion !== null) capabilities.add("react");
70997
71903
  if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
70998
- if (project.expoVersion !== null) capabilities.add("expo");
71904
+ if (project.expoVersion !== null) {
71905
+ capabilities.add("expo");
71906
+ const expoSdkMajorVersion = getLowestDependencyMajor(project.expoVersion);
71907
+ if (expoSdkMajorVersion !== null && expoSdkMajorVersion >= 54) capabilities.add("expo:54");
71908
+ }
70999
71909
  if ((project.framework === "nextjs" || project.framework === "tanstack-start" || project.framework === "remix") && !project.isStaticExport) capabilities.add("server-actions");
71000
71910
  if (SSR_FRAMEWORKS.has(project.framework) || project.hasSsrDependency) capabilities.add("ssr");
71001
71911
  if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
@@ -71059,6 +71969,11 @@ const buildCapabilities = (project) => {
71059
71969
  if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addVersionCapabilityLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
71060
71970
  if (project.isPreES2023Target) capabilities.add("pre-es2023");
71061
71971
  if (project.hasReactCompiler) capabilities.add("react-compiler");
71972
+ if (project.reanimatedVersion !== void 0 && project.reanimatedVersion !== null) {
71973
+ capabilities.add("reanimated");
71974
+ const reanimatedMajorVersion = getLowestDependencyMajor(project.reanimatedVersion);
71975
+ if (reanimatedMajorVersion !== null && reanimatedMajorVersion >= 4) capabilities.add("reanimated:4");
71976
+ }
71062
71977
  if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
71063
71978
  if (project.styledComponentsVersion) {
71064
71979
  capabilities.add("styled-components");
@@ -72414,7 +73329,10 @@ var Git = class Git extends Service()("react-doctor/Git") {
72414
73329
  if (argvLengthChars > spawnArgsLengthCap) return yield* foldSpawnFailure(`spawn ENAMETOOLONG (${argvLengthChars} argv chars exceed ${spawnArgsLengthCap})`);
72415
73330
  const handle = yield* spawner.spawn(make$1(input.command, [...input.args], {
72416
73331
  cwd: input.directory,
72417
- env: input.env,
73332
+ env: input.command === "git" ? {
73333
+ ...input.env,
73334
+ GIT_DIR: void 0
73335
+ } : input.env,
72418
73336
  extendEnv: true
72419
73337
  }));
72420
73338
  const maxStdoutBytes = input.maxStdoutBytes;
@@ -72687,7 +73605,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
72687
73605
  "--diff-filter=ACMR",
72688
73606
  "--relative"
72689
73607
  ]).pipe(map$3((result) => {
72690
- if (result.status !== 0) return [];
73608
+ if (result.status !== 0) return null;
72691
73609
  return splitNullSeparated(result.stdout);
72692
73610
  })),
72693
73611
  showStagedContent: (directory, relativePath, options) => runCommand({
@@ -72972,7 +73890,11 @@ const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
72972
73890
  const ROOT_DIRECTORY_PLACEHOLDER = "<root>";
72973
73891
  const normalizeConfigForHash = (config) => {
72974
73892
  const clone = JSON.parse(JSON.stringify(config));
72975
- if (clone?.settings?.["react-doctor"]) clone.settings["react-doctor"].rootDirectory = ROOT_DIRECTORY_PLACEHOLDER;
73893
+ if (clone?.settings?.["react-doctor"]) {
73894
+ const reactDoctorSettings = clone.settings["react-doctor"];
73895
+ reactDoctorSettings.rootDirectory = ROOT_DIRECTORY_PLACEHOLDER;
73896
+ if (Array.isArray(reactDoctorSettings.unpluginAutoImportRootDirectories)) reactDoctorSettings.unpluginAutoImportRootDirectories = [ROOT_DIRECTORY_PLACEHOLDER];
73897
+ }
72976
73898
  if (Array.isArray(clone?.jsPlugins)) clone.jsPlugins = clone.jsPlugins.map((_, index) => `<plugin:${index}>`);
72977
73899
  return clone;
72978
73900
  };
@@ -73131,13 +74053,14 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
73131
74053
  }
73132
74054
  return enabled;
73133
74055
  };
73134
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
74056
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, runtimeGlobals, unpluginAutoImportGlobalScopes, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
73135
74057
  const hasIncludedTags = includedTags.size > 0;
73136
74058
  const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
73137
74059
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
73138
74060
  const jsPlugins = [];
73139
74061
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
73140
74062
  const capabilities = getCapabilities(project);
74063
+ const settingsRootDirectory = resolveSettingsRootDirectory(project.rootDirectory);
73141
74064
  const enabledReactDoctorRules = {};
73142
74065
  for (const registryEntry of REACT_DOCTOR_RULES) {
73143
74066
  const rule = reactDoctorPlugin.rules[registryEntry.id];
@@ -73183,8 +74106,16 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
73183
74106
  jsPlugins: [...jsPlugins, pluginPath],
73184
74107
  settings: { "react-doctor": {
73185
74108
  framework: project.framework,
73186
- rootDirectory: resolveSettingsRootDirectory(project.rootDirectory),
74109
+ rootDirectory: settingsRootDirectory,
73187
74110
  capabilities: [...capabilities].sort(),
74111
+ ...runtimeGlobals && runtimeGlobals.length > 0 ? { runtimeGlobals: [...runtimeGlobals] } : {},
74112
+ ...unpluginAutoImportGlobalScopes && unpluginAutoImportGlobalScopes.length > 0 ? {
74113
+ unpluginAutoImportRootDirectories: [...new Set([settingsRootDirectory, project.rootDirectory])],
74114
+ unpluginAutoImportGlobalScopes: unpluginAutoImportGlobalScopes.map((scope) => ({
74115
+ directory: scope.directory,
74116
+ names: [...scope.names]
74117
+ }))
74118
+ } : {},
73188
74119
  ...project.shopifyFlashListMajorVersion !== null ? { shopifyFlashListMajorVersion: project.shopifyFlashListMajorVersion } : {},
73189
74120
  ...serverAuthFunctionNames && serverAuthFunctionNames.length > 0 ? { serverAuthFunctionNames: [...serverAuthFunctionNames] } : {}
73190
74121
  } },
@@ -73195,6 +74126,245 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
73195
74126
  }
73196
74127
  };
73197
74128
  };
74129
+ const AUTO_IMPORT_ADAPTER_PATTERN = /^unplugin-auto-import\/(?:astro|esbuild|rollup|rolldown|rspack|vite|webpack)$/;
74130
+ const CONFIG_BASENAMES = [
74131
+ "astro.config",
74132
+ "esbuild.config",
74133
+ "rollup.config",
74134
+ "rolldown.config",
74135
+ "rspack.config",
74136
+ "vite.config",
74137
+ "webpack.config"
74138
+ ];
74139
+ const CONFIG_EXTENSIONS = [
74140
+ ".cjs",
74141
+ ".cts",
74142
+ ".js",
74143
+ ".mjs",
74144
+ ".mts",
74145
+ ".ts"
74146
+ ];
74147
+ const CONFIG_FILENAMES = new Set(CONFIG_BASENAMES.flatMap((basename) => CONFIG_EXTENSIONS.map((extension) => `${basename}${extension}`)));
74148
+ const DEFAULT_ESLINT_GLOBALS_PATH = ".eslintrc-auto-import.json";
74149
+ const SUPPORTED_GLOBAL_VALUES = new Set([
74150
+ true,
74151
+ false,
74152
+ "readable",
74153
+ "readonly",
74154
+ "writable",
74155
+ "writeable"
74156
+ ]);
74157
+ const getStaticProperty = (objectExpression, propertyName) => objectExpression.properties.find((property) => {
74158
+ if (ts.isSpreadAssignment(property)) return false;
74159
+ const name = ts.isComputedPropertyName(property.name) ? unwrapTypescriptExpression(property.name.expression) : property.name;
74160
+ return (ts.isIdentifier(name) || ts.isStringLiteralLike(name)) && name.text === propertyName;
74161
+ }) ?? null;
74162
+ const hasNonLiteralComputedProperty = (objectExpression) => objectExpression.properties.some((property) => !ts.isSpreadAssignment(property) && ts.isComputedPropertyName(property.name) && !ts.isStringLiteralLike(unwrapTypescriptExpression(property.name.expression)));
74163
+ const getStaticPropertyAssignment = (objectExpression, propertyName) => {
74164
+ const property = getStaticProperty(objectExpression, propertyName);
74165
+ return property && ts.isPropertyAssignment(property) ? property : null;
74166
+ };
74167
+ const getRequireModuleSpecifier = (expression) => {
74168
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
74169
+ if (ts.isPropertyAccessExpression(unwrappedExpression) && unwrappedExpression.name.text === "default") return getRequireModuleSpecifier(unwrappedExpression.expression);
74170
+ if (!ts.isCallExpression(unwrappedExpression) || !ts.isIdentifier(unwrappedExpression.expression) || unwrappedExpression.expression.text !== "require" || unwrappedExpression.arguments.length !== 1) return null;
74171
+ const moduleSpecifier = unwrappedExpression.arguments[0];
74172
+ return moduleSpecifier && ts.isStringLiteralLike(moduleSpecifier) ? moduleSpecifier.text : null;
74173
+ };
74174
+ const getRequiredPropertyModuleSpecifier = (expression, propertyName) => {
74175
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
74176
+ return ts.isPropertyAccessExpression(unwrappedExpression) && unwrappedExpression.name.text === propertyName ? getRequireModuleSpecifier(unwrappedExpression.expression) : null;
74177
+ };
74178
+ const isCommonJsExportAssignment = (node, sourceFile) => ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && (node.left.getText(sourceFile) === "module.exports" || node.left.getText(sourceFile) === "exports.default");
74179
+ const isTopLevelExpression = (node) => {
74180
+ let ancestor = node.parent;
74181
+ while (ancestor && !ts.isSourceFile(ancestor)) {
74182
+ if (ts.isExpressionStatement(ancestor)) return ts.isSourceFile(ancestor.parent);
74183
+ if (!ts.isParenthesizedExpression(ancestor) && !ts.isAsExpression(ancestor) && !ts.isSatisfiesExpression(ancestor) && !ts.isNonNullExpression(ancestor) && !ts.isTypeAssertionExpression(ancestor) && !ts.isAwaitExpression(ancestor)) return false;
74184
+ ancestor = ancestor.parent;
74185
+ }
74186
+ return false;
74187
+ };
74188
+ const isInsideActiveConfigProperty = (node, propertyName, sourceFile, esbuildBindings, esbuildNamespaceBindings) => {
74189
+ let ancestor = node.parent;
74190
+ let didFindConfigProperty = false;
74191
+ while (ancestor && !ts.isSourceFile(ancestor)) {
74192
+ if (!didFindConfigProperty && !ts.isArrayLiteralExpression(ancestor) && !ts.isParenthesizedExpression(ancestor) && !ts.isAsExpression(ancestor) && !ts.isSatisfiesExpression(ancestor) && !ts.isNonNullExpression(ancestor) && !ts.isTypeAssertionExpression(ancestor) && !ts.isPropertyAssignment(ancestor)) return false;
74193
+ if (ts.isPropertyAssignment(ancestor)) {
74194
+ const isConfigProperty = (ts.isIdentifier(ancestor.name) || ts.isStringLiteralLike(ancestor.name)) && ancestor.name.text === propertyName;
74195
+ if (didFindConfigProperty || !isConfigProperty) return false;
74196
+ if (!ts.isObjectLiteralExpression(ancestor.parent) || ancestor.parent.properties.some(ts.isSpreadAssignment)) return false;
74197
+ didFindConfigProperty = true;
74198
+ ancestor = ancestor.parent;
74199
+ continue;
74200
+ }
74201
+ if (didFindConfigProperty) {
74202
+ if (ts.isExportAssignment(ancestor)) return true;
74203
+ if (isCommonJsExportAssignment(ancestor, sourceFile)) return isTopLevelExpression(ancestor);
74204
+ if (propertyName === "plugins" && ts.isCallExpression(ancestor) && (ts.isIdentifier(ancestor.expression) ? esbuildBindings.has(ancestor.expression.text) : ts.isPropertyAccessExpression(ancestor.expression) && ancestor.expression.name.text === "build" && (ts.isIdentifier(ancestor.expression.expression) && esbuildNamespaceBindings.has(ancestor.expression.expression.text) || getRequireModuleSpecifier(ancestor.expression.expression) === "esbuild"))) return isTopLevelExpression(ancestor);
74205
+ if (!(ts.isObjectLiteralExpression(ancestor) || ts.isParenthesizedExpression(ancestor) || ts.isAsExpression(ancestor) || ts.isSatisfiesExpression(ancestor) || ts.isNonNullExpression(ancestor) || ts.isTypeAssertionExpression(ancestor) || ts.isCallExpression(ancestor) && ts.isIdentifier(ancestor.expression) && ancestor.expression.text === "defineConfig")) return false;
74206
+ }
74207
+ ancestor = ancestor.parent;
74208
+ }
74209
+ return false;
74210
+ };
74211
+ const getGlobalsPathFromActiveAutoImportCall = (callExpression, packageDirectory) => {
74212
+ const optionsExpression = callExpression.arguments[0];
74213
+ if (!optionsExpression) return null;
74214
+ const unwrappedOptions = unwrapTypescriptExpression(optionsExpression);
74215
+ if (!ts.isObjectLiteralExpression(unwrappedOptions)) return null;
74216
+ if (unwrappedOptions.properties.some(ts.isSpreadAssignment) || hasNonLiteralComputedProperty(unwrappedOptions)) return null;
74217
+ if (getStaticProperty(unwrappedOptions, "include") || getStaticProperty(unwrappedOptions, "exclude")) return null;
74218
+ const eslintrcProperty = getStaticPropertyAssignment(unwrappedOptions, "eslintrc");
74219
+ if (!eslintrcProperty) return null;
74220
+ const eslintrcExpression = unwrapTypescriptExpression(eslintrcProperty.initializer);
74221
+ if (!ts.isObjectLiteralExpression(eslintrcExpression)) return null;
74222
+ if (eslintrcExpression.properties.some(ts.isSpreadAssignment) || hasNonLiteralComputedProperty(eslintrcExpression)) return null;
74223
+ const enabledProperty = getStaticPropertyAssignment(eslintrcExpression, "enabled");
74224
+ if (!enabledProperty || unwrapTypescriptExpression(enabledProperty.initializer).kind !== ts.SyntaxKind.TrueKeyword) return null;
74225
+ const filepathProperty = getStaticProperty(eslintrcExpression, "filepath");
74226
+ if (!filepathProperty) return Path.join(packageDirectory, DEFAULT_ESLINT_GLOBALS_PATH);
74227
+ if (!ts.isPropertyAssignment(filepathProperty)) return null;
74228
+ const filepathExpression = unwrapTypescriptExpression(filepathProperty.initializer);
74229
+ return ts.isStringLiteralLike(filepathExpression) ? Path.resolve(packageDirectory, filepathExpression.text) : null;
74230
+ };
74231
+ const collectGlobalsPathsFromConfig = (configPath, packageDirectory) => {
74232
+ let sourceText;
74233
+ try {
74234
+ sourceText = NFS.readFileSync(configPath, "utf8");
74235
+ } catch {
74236
+ return {
74237
+ didFindActiveAutoImport: false,
74238
+ globalsPaths: []
74239
+ };
74240
+ }
74241
+ const sourceFile = ts.createSourceFile(configPath, sourceText, ts.ScriptTarget.Latest, true);
74242
+ const autoImportBindings = /* @__PURE__ */ new Map();
74243
+ const esbuildBindings = /* @__PURE__ */ new Set();
74244
+ const esbuildNamespaceBindings = /* @__PURE__ */ new Set();
74245
+ for (const statement of sourceFile.statements) {
74246
+ if (ts.isImportDeclaration(statement) && ts.isStringLiteralLike(statement.moduleSpecifier)) {
74247
+ const moduleSpecifier = statement.moduleSpecifier.text;
74248
+ if (AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) {
74249
+ const defaultBinding = statement.importClause?.name;
74250
+ if (defaultBinding) autoImportBindings.set(defaultBinding.text, moduleSpecifier);
74251
+ }
74252
+ if (moduleSpecifier === "esbuild") {
74253
+ const defaultBinding = statement.importClause?.name;
74254
+ if (defaultBinding) esbuildNamespaceBindings.add(defaultBinding.text);
74255
+ const namedBindings = statement.importClause?.namedBindings;
74256
+ if (namedBindings && ts.isNamedImports(namedBindings)) {
74257
+ for (const importSpecifier of namedBindings.elements) if ((importSpecifier.propertyName ?? importSpecifier.name).text === "build") esbuildBindings.add(importSpecifier.name.text);
74258
+ }
74259
+ if (namedBindings && ts.isNamespaceImport(namedBindings)) esbuildNamespaceBindings.add(namedBindings.name.text);
74260
+ }
74261
+ }
74262
+ if (!ts.isVariableStatement(statement)) continue;
74263
+ for (const declaration of statement.declarationList.declarations) {
74264
+ if (!declaration.initializer) continue;
74265
+ const declarationName = ts.isIdentifier(declaration.name) ? declaration.name.text : null;
74266
+ const moduleSpecifier = getRequireModuleSpecifier(declaration.initializer);
74267
+ if (declarationName && moduleSpecifier && AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) autoImportBindings.set(declarationName, moduleSpecifier);
74268
+ if (moduleSpecifier === "esbuild") {
74269
+ if (declarationName) esbuildNamespaceBindings.add(declarationName);
74270
+ if (ts.isObjectBindingPattern(declaration.name)) for (const bindingElement of declaration.name.elements) {
74271
+ const importedName = bindingElement.propertyName ?? bindingElement.name;
74272
+ if (ts.isIdentifier(importedName) && importedName.text === "build" && ts.isIdentifier(bindingElement.name)) esbuildBindings.add(bindingElement.name.text);
74273
+ }
74274
+ }
74275
+ if (declarationName && getRequiredPropertyModuleSpecifier(declaration.initializer, "build") === "esbuild") esbuildBindings.add(declarationName);
74276
+ }
74277
+ }
74278
+ const globalsPaths = /* @__PURE__ */ new Set();
74279
+ let didFindActiveAutoImport = false;
74280
+ let didFindUnsafeActiveAutoImport = false;
74281
+ const visit = (node) => {
74282
+ if (ts.isCallExpression(node)) {
74283
+ const moduleSpecifier = ts.isIdentifier(node.expression) ? autoImportBindings.get(node.expression.text) : getRequireModuleSpecifier(node.expression);
74284
+ if (moduleSpecifier && AUTO_IMPORT_ADAPTER_PATTERN.test(moduleSpecifier)) {
74285
+ if (isInsideActiveConfigProperty(node, moduleSpecifier.endsWith("/astro") ? "integrations" : "plugins", sourceFile, esbuildBindings, esbuildNamespaceBindings)) {
74286
+ didFindActiveAutoImport = true;
74287
+ const globalsPath = getGlobalsPathFromActiveAutoImportCall(node, packageDirectory);
74288
+ if (globalsPath) globalsPaths.add(globalsPath);
74289
+ else didFindUnsafeActiveAutoImport = true;
74290
+ }
74291
+ }
74292
+ }
74293
+ ts.forEachChild(node, visit);
74294
+ };
74295
+ visit(sourceFile);
74296
+ return {
74297
+ didFindActiveAutoImport,
74298
+ globalsPaths: didFindUnsafeActiveAutoImport ? [] : [...globalsPaths]
74299
+ };
74300
+ };
74301
+ const collectGeneratedGlobalNames = (globalsPath, rootDirectory) => {
74302
+ const relativePath = Path.relative(rootDirectory, globalsPath);
74303
+ if (relativePath.startsWith("..") || Path.isAbsolute(relativePath)) return [];
74304
+ const parsed = failOpenReadJson(globalsPath, null);
74305
+ if (!isPlainObject(parsed) || !isPlainObject(parsed.globals)) return [];
74306
+ return Object.entries(parsed.globals).filter((entry) => entry[0].length > 0 && (typeof entry[1] === "boolean" || typeof entry[1] === "string") && SUPPORTED_GLOBAL_VALUES.has(entry[1])).map(([name]) => name).sort();
74307
+ };
74308
+ const findOwningPackageDirectory = (absoluteFilePath, rootDirectory, cache) => {
74309
+ let currentDirectory = Path.dirname(absoluteFilePath);
74310
+ const visitedDirectories = [];
74311
+ while (true) {
74312
+ const cachedDirectory = cache.get(currentDirectory);
74313
+ if (cachedDirectory !== void 0) {
74314
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, cachedDirectory);
74315
+ return cachedDirectory;
74316
+ }
74317
+ const relativeDirectory = Path.relative(rootDirectory, currentDirectory);
74318
+ if (relativeDirectory.startsWith("..") || Path.isAbsolute(relativeDirectory)) {
74319
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, null);
74320
+ return null;
74321
+ }
74322
+ visitedDirectories.push(currentDirectory);
74323
+ if (NFS.existsSync(Path.join(currentDirectory, "package.json"))) {
74324
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, currentDirectory);
74325
+ return currentDirectory;
74326
+ }
74327
+ if (currentDirectory === rootDirectory) {
74328
+ for (const visitedDirectory of visitedDirectories) cache.set(visitedDirectory, null);
74329
+ return null;
74330
+ }
74331
+ currentDirectory = Path.dirname(currentDirectory);
74332
+ }
74333
+ };
74334
+ const collectPackageGlobalNames = (packageDirectory, rootDirectory) => {
74335
+ let directoryEntries;
74336
+ try {
74337
+ directoryEntries = NFS.readdirSync(packageDirectory, { withFileTypes: true });
74338
+ } catch {
74339
+ return [];
74340
+ }
74341
+ const configuredGlobalsPaths = [];
74342
+ for (const entry of directoryEntries) {
74343
+ if (!entry.isFile() && !entry.isSymbolicLink() || !CONFIG_FILENAMES.has(entry.name)) continue;
74344
+ const configGlobalsPaths = collectGlobalsPathsFromConfig(Path.join(packageDirectory, entry.name), packageDirectory);
74345
+ if (configGlobalsPaths.didFindActiveAutoImport) configuredGlobalsPaths.push(configGlobalsPaths.globalsPaths.toSorted());
74346
+ }
74347
+ if (configuredGlobalsPaths.length === 0) return [];
74348
+ const globalsPaths = configuredGlobalsPaths[0];
74349
+ if (configuredGlobalsPaths.some((candidatePaths) => candidatePaths.length !== globalsPaths.length || candidatePaths.some((candidatePath, index) => candidatePath !== globalsPaths[index]))) return [];
74350
+ const names = /* @__PURE__ */ new Set();
74351
+ for (const globalsPath of globalsPaths) for (const name of collectGeneratedGlobalNames(globalsPath, rootDirectory)) names.add(name);
74352
+ return [...names].sort();
74353
+ };
74354
+ const collectUnpluginAutoImportGlobalScopes = ({ rootDirectory, candidateFiles }) => {
74355
+ const absoluteRootDirectory = Path.resolve(rootDirectory);
74356
+ const packageDirectoryCache = /* @__PURE__ */ new Map();
74357
+ const packageDirectories = /* @__PURE__ */ new Set();
74358
+ for (const candidateFile of candidateFiles) {
74359
+ const packageDirectory = findOwningPackageDirectory(Path.resolve(absoluteRootDirectory, candidateFile), absoluteRootDirectory, packageDirectoryCache);
74360
+ if (packageDirectory) packageDirectories.add(packageDirectory);
74361
+ }
74362
+ const scopes = [...packageDirectories].map((packageDirectory) => ({
74363
+ directory: Path.relative(absoluteRootDirectory, packageDirectory).replaceAll("\\", "/"),
74364
+ names: collectPackageGlobalNames(packageDirectory, absoluteRootDirectory)
74365
+ })).sort((firstScope, secondScope) => firstScope.directory.localeCompare(secondScope.directory));
74366
+ return scopes.some((scope) => scope.names.length > 0) ? scopes : [];
74367
+ };
73198
74368
  const validateDiagnostic$1 = decodeUnknownSync(Diagnostic);
73199
74369
  const decodeFileDiagnostics = (raw) => {
73200
74370
  if (!Array.isArray(raw)) return null;
@@ -73517,6 +74687,56 @@ const appendReanimatedSharedValueHint = (help, rule, project) => {
73517
74687
  if (!help) return REANIMATED_SHARED_VALUE_HINT;
73518
74688
  return `${help}\n\n${REANIMATED_SHARED_VALUE_HINT}`;
73519
74689
  };
74690
+ const columnOfUtf8Offset = (sourceBuffer, utf8Offset) => {
74691
+ const boundedOffset = Math.min(Math.max(utf8Offset, 0), sourceBuffer.length);
74692
+ let lineStartOffset = boundedOffset;
74693
+ while (lineStartOffset > 0 && sourceBuffer[lineStartOffset - 1] !== 10) lineStartOffset--;
74694
+ return sourceBuffer.subarray(lineStartOffset, boundedOffset).toString("utf8").length + 1;
74695
+ };
74696
+ const utf8OffsetFromSourcePosition = (sourceBuffer, lineNumber, zeroBasedColumn) => {
74697
+ if (lineNumber < 1 || zeroBasedColumn < 0) return null;
74698
+ const sourceLines = sourceBuffer.toString("utf8").split("\n");
74699
+ const sourceLine = sourceLines[lineNumber - 1];
74700
+ if (sourceLine === void 0 || zeroBasedColumn > sourceLine.length) return null;
74701
+ const precedingLines = sourceLines.slice(0, lineNumber - 1).join("\n");
74702
+ return (lineNumber === 1 ? 0 : Buffer.byteLength(precedingLines) + Buffer.byteLength("\n")) + Buffer.byteLength(sourceLine.slice(0, zeroBasedColumn));
74703
+ };
74704
+ const mapPreparedSourceSpan = (span, preparedSourceMap) => {
74705
+ const generatedLine = lineOfUtf8Offset(preparedSourceMap.generatedBuffer, span.offset);
74706
+ const generatedColumn = columnOfUtf8Offset(preparedSourceMap.generatedBuffer, span.offset) - 1;
74707
+ const originalStart = originalPositionFor(preparedSourceMap.traceMap, {
74708
+ line: generatedLine,
74709
+ column: generatedColumn
74710
+ });
74711
+ if (originalStart.source === null || originalStart.line === null || originalStart.column === null) return null;
74712
+ const originalOffset = utf8OffsetFromSourcePosition(preparedSourceMap.sourceBuffer, originalStart.line, originalStart.column);
74713
+ if (originalOffset === null) return null;
74714
+ const generatedSpan = preparedSourceMap.generatedBuffer.subarray(span.offset, span.offset + span.length);
74715
+ return {
74716
+ offset: originalOffset,
74717
+ length: preparedSourceMap.sourceBuffer.subarray(originalOffset, originalOffset + generatedSpan.length).equals(generatedSpan) ? generatedSpan.length : 0,
74718
+ line: originalStart.line,
74719
+ column: originalStart.column + 1
74720
+ };
74721
+ };
74722
+ const mapPreparedSourceLabels = (labels, preparedSourceMap) => {
74723
+ const primaryLabel = labels[0];
74724
+ if (primaryLabel === void 0) return null;
74725
+ const primarySpan = mapPreparedSourceSpan(primaryLabel.span, preparedSourceMap);
74726
+ if (primarySpan === null) return null;
74727
+ const mappedLabels = [{
74728
+ ...primaryLabel,
74729
+ span: primarySpan
74730
+ }];
74731
+ for (const relatedLabel of labels.slice(1)) {
74732
+ const relatedSpan = mapPreparedSourceSpan(relatedLabel.span, preparedSourceMap);
74733
+ if (relatedSpan !== null) mappedLabels.push({
74734
+ ...relatedLabel,
74735
+ span: relatedSpan
74736
+ });
74737
+ }
74738
+ return mappedLabels;
74739
+ };
73520
74740
  const REDACTED_PLACEHOLDER = "<redacted>";
73521
74741
  const KEEP_PREFIX = `$1${REDACTED_PLACEHOLDER}`;
73522
74742
  const KNOWN_SECRET_RULES = [
@@ -74232,7 +75452,7 @@ const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORI
74232
75452
  * with empty text still carry a useful jump target, so they're kept
74233
75453
  * with a neutral message.
74234
75454
  */
74235
- const buildRelatedLocations = (labels, filePath) => {
75455
+ const buildRelatedLocations = (labels, filePath, sourceBuffer) => {
74236
75456
  if (labels.length <= 1) return [];
74237
75457
  const related = [];
74238
75458
  for (let labelIndex = 1; labelIndex < labels.length; labelIndex++) {
@@ -74240,8 +75460,8 @@ const buildRelatedLocations = (labels, filePath) => {
74240
75460
  if (!label?.span) continue;
74241
75461
  related.push({
74242
75462
  filePath,
74243
- line: label.span.line ?? 0,
74244
- column: label.span.column ?? 0,
75463
+ line: sourceBuffer === null ? label.span.line ?? 0 : lineOfUtf8Offset(sourceBuffer, label.span.offset),
75464
+ column: sourceBuffer === null ? label.span.column ?? 0 : columnOfUtf8Offset(sourceBuffer, label.span.offset),
74245
75465
  offset: label.span.offset,
74246
75466
  length: label.span.length,
74247
75467
  message: label.label ?? ""
@@ -74261,7 +75481,7 @@ const isOxlintOutput = (value) => isRecord$1(value) && Array.isArray(value.diagn
74261
75481
  * to the first `{`. Raises `OxlintOutputUnparseable` when the
74262
75482
  * stdout isn't valid JSON or doesn't carry a `diagnostics` array.
74263
75483
  */
74264
- const parseOxlintOutput = (stdout, project, rootDirectory) => {
75484
+ const parseOxlintOutput = (stdout, project, rootDirectory, sourcePathByLintPath, sourceMapByLintPath) => {
74265
75485
  if (!stdout) return [];
74266
75486
  const jsonStart = stdout.indexOf("{");
74267
75487
  const sanitizedStdout = jsonStart > 0 ? stdout.slice(jsonStart) : stdout;
@@ -74278,8 +75498,11 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
74278
75498
  const sourceBufferCache = /* @__PURE__ */ new Map();
74279
75499
  const sourceLinesCache = /* @__PURE__ */ new Map();
74280
75500
  const resolveAbsolutePath = (filename) => Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
75501
+ const resolveMappedSourceFilename = (filename) => sourcePathByLintPath?.get(Path.normalize(resolveAbsolutePath(filename)));
75502
+ const resolvePreparedSourceMap = (filename) => sourceMapByLintPath?.get(Path.normalize(resolveAbsolutePath(filename)));
75503
+ const resolveSourceFilename = (filename) => resolveMappedSourceFilename(filename) ?? filename;
74281
75504
  const readSourceBuffer = (filename) => {
74282
- const absolutePath = resolveAbsolutePath(filename);
75505
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
74283
75506
  const cached = sourceBufferCache.get(absolutePath);
74284
75507
  if (cached !== void 0) return cached;
74285
75508
  let sourceBuffer;
@@ -74292,7 +75515,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
74292
75515
  return sourceBuffer;
74293
75516
  };
74294
75517
  const readSourceLines = (filename) => {
74295
- const absolutePath = resolveAbsolutePath(filename);
75518
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
74296
75519
  const cached = sourceLinesCache.get(absolutePath);
74297
75520
  if (cached !== void 0) return cached;
74298
75521
  const sourceBuffer = readSourceBuffer(filename);
@@ -74301,27 +75524,42 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
74301
75524
  return sourceLines;
74302
75525
  };
74303
75526
  const isMinifiedDiagnosticFile = (filename) => {
74304
- const absolutePath = resolveAbsolutePath(filename);
75527
+ const absolutePath = resolveAbsolutePath(resolveSourceFilename(filename));
74305
75528
  const cached = minifiedFileCache.get(absolutePath);
74306
75529
  if (cached !== void 0) return cached;
74307
75530
  const minified = isMinifiedSource(absolutePath);
74308
75531
  minifiedFileCache.set(absolutePath, minified);
74309
75532
  return minified;
74310
75533
  };
74311
- return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => isMappableOxlintDiagnostic(diagnostic) && isLintableSourceFile(diagnostic.filename) && !(TYPESCRIPT_DECLARATION_FILE_PATTERN.test(diagnostic.filename) && OXLINT_IGNORED_DECLARATION_DIAGNOSTIC_CODES.has(diagnostic.code)) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
75534
+ return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.flatMap((diagnostic) => {
75535
+ const preparedSourceMap = resolvePreparedSourceMap(diagnostic.filename);
75536
+ if (preparedSourceMap === void 0) return [diagnostic];
75537
+ const { plugin, rule } = parseRuleCode(diagnostic.code);
75538
+ if (plugin !== "react-doctor" || !reactDoctorPlugin.rules[rule]?.tags?.includes("design")) return [];
75539
+ const labels = mapPreparedSourceLabels(diagnostic.labels, preparedSourceMap);
75540
+ const sourceFilename = resolveMappedSourceFilename(diagnostic.filename);
75541
+ return labels === null || sourceFilename === void 0 ? [] : [{
75542
+ ...diagnostic,
75543
+ filename: sourceFilename,
75544
+ labels
75545
+ }];
75546
+ }).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) => {
74312
75547
  const { plugin, rule } = parseRuleCode(diagnostic.code);
74313
75548
  const primaryLabel = diagnostic.labels[0];
74314
75549
  const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
74315
- const normalizedFilePath = diagnostic.filename.replaceAll("\\", "/");
75550
+ const mappedSourceFilename = resolveMappedSourceFilename(diagnostic.filename);
75551
+ const normalizedFilePath = (mappedSourceFilename ?? diagnostic.filename).replaceAll("\\", "/");
74316
75552
  const primarySpan = primaryLabel?.span;
74317
75553
  const sourceBuffer = primarySpan ? readSourceBuffer(diagnostic.filename) : null;
74318
- const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
75554
+ const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath, mappedSourceFilename === void 0 ? null : sourceBuffer);
74319
75555
  const category = resolveDiagnosticCategory(plugin, rule);
74320
75556
  const matchByOccurrence = resolveMatchByOccurrence(rule, category);
74321
75557
  const sourceLines = primarySpan ? readSourceLines(diagnostic.filename) : null;
74322
- const primaryLineIndex = primarySpan ? primarySpan.line - 1 : -1;
75558
+ const primaryLineNumber = primarySpan && mappedSourceFilename !== void 0 && sourceBuffer !== null ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset) : primarySpan?.line ?? 0;
75559
+ const primaryColumnNumber = primarySpan && mappedSourceFilename !== void 0 && sourceBuffer !== null ? columnOfUtf8Offset(sourceBuffer, primarySpan.offset) : primarySpan?.column ?? 0;
75560
+ const primaryLineIndex = primarySpan ? primaryLineNumber - 1 : -1;
74323
75561
  const primaryLine = sourceLines?.[primaryLineIndex];
74324
- const primaryColumnIndex = primarySpan ? primarySpan.column - 1 : -1;
75562
+ const primaryColumnIndex = primarySpan ? primaryColumnNumber - 1 : -1;
74325
75563
  const isJsxTagLabel = primaryLine !== void 0 && primaryColumnIndex >= 0 && (primaryLine[primaryColumnIndex] === "<" || primaryLine[primaryColumnIndex - 1] === "<");
74326
75564
  const jsxOpenerEndLineIndex = sourceLines && isJsxTagLabel ? findJsxOpenerSpan(sourceLines, primaryLineIndex) : null;
74327
75565
  const primarySpanEndLine = jsxOpenerEndLineIndex !== null ? jsxOpenerEndLineIndex + 1 : primarySpan && sourceBuffer ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset + Math.max(primarySpan.length - 1, 0)) : void 0;
@@ -74334,8 +75572,8 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
74334
75572
  message: cleaned.message,
74335
75573
  help: cleaned.help,
74336
75574
  url: diagnostic.url,
74337
- line: primarySpan?.line ?? 0,
74338
- column: primarySpan?.column ?? 0,
75575
+ line: primaryLineNumber,
75576
+ column: primaryColumnNumber,
74339
75577
  ...primarySpan ? {
74340
75578
  offset: primarySpan.offset,
74341
75579
  length: primarySpan.length,
@@ -74523,7 +75761,11 @@ const isParallelismRelatedSpawnError = (error) => {
74523
75761
  * loop with a slimmer config in that case.
74524
75762
  */
74525
75763
  const spawnLintBatches = async (input) => {
74526
- const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
75764
+ const { baseArgs, fileBatches, rootDirectory, nodeBinaryPath, project, sourcePathByLintPath, sourceMapByLintPath, onPartialFailure, onFileProgress, spawnTimeoutMs, outputMaxBytes, splitTotalBudgetMs = OXLINT_SPLIT_TOTAL_BUDGET_MS, splitMaxDepth = 8, signal, deadlineEpochMs } = input;
75765
+ const resolveSourcePath = (filePath) => {
75766
+ const absoluteFilePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory, filePath);
75767
+ return sourcePathByLintPath?.get(Path.normalize(absoluteFilePath)) ?? filePath;
75768
+ };
74527
75769
  const requestedConcurrency = resolveScanConcurrency(input.concurrency ?? 1);
74528
75770
  let rescueDeadlineEpochMs;
74529
75771
  const isPastDeadline = () => deadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(deadlineEpochMs) === 0 || rescueDeadlineEpochMs !== void 0 && remainingDeadlineBudgetMs(rescueDeadlineEpochMs) === 0;
@@ -74543,7 +75785,7 @@ const spawnLintBatches = async (input) => {
74543
75785
  }
74544
75786
  const batchArgs = [...baseArgs, ...batch];
74545
75787
  try {
74546
- return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory);
75788
+ return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory, sourcePathByLintPath, sourceMapByLintPath);
74547
75789
  } catch (error) {
74548
75790
  if (!isSplittableReactDoctorError(error)) throw error;
74549
75791
  if (isPastDeadline()) {
@@ -74649,10 +75891,12 @@ const spawnLintBatches = async (input) => {
74649
75891
  onPartialFailure(buildMessage(`${skippedFiles.slice(0, 3).join(", ")}${skippedFiles.length > 3 ? `, +${skippedFiles.length - 3} more` : ""}`));
74650
75892
  };
74651
75893
  const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
74652
- reportSkippedFiles(droppedFiles, (fileListPreview) => `${droppedFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
74653
- reportSkippedFiles(outcome.deadlineSkippedFiles, (fileListPreview) => `${outcome.deadlineSkippedFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
75894
+ const droppedSourceFiles = [...new Set(droppedFiles.map(resolveSourcePath))];
75895
+ const deadlineSkippedSourceFiles = [...new Set(outcome.deadlineSkippedFiles.map(resolveSourcePath))];
75896
+ reportSkippedFiles(droppedSourceFiles, (fileListPreview) => `${droppedSourceFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
75897
+ reportSkippedFiles(deadlineSkippedSourceFiles, (fileListPreview) => `${deadlineSkippedSourceFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
74654
75898
  const unavailableFiles = new Set([...droppedFiles, ...outcome.deadlineSkippedFiles]);
74655
- input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)))].sort());
75899
+ input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)).map(resolveSourcePath))].sort());
74656
75900
  return dedupeDiagnostics(diagnostics);
74657
75901
  };
74658
75902
  let didValidate = false;
@@ -74751,6 +75995,294 @@ const planLintBatches = ({ baseArgs, files, sizeByFile }) => {
74751
75995
  }
74752
75996
  return batches.filter((batch) => batch.fileIndexes.length > 0).map((batch) => batch.fileIndexes.sort((leftIndex, rightIndex) => leftIndex - rightIndex).map((fileIndex) => files[fileIndex]));
74753
75997
  };
75998
+ const THREE_MODULE_IMPORT_PATTERN = /\b(?:from\s*|import\s*(?:\(\s*)?|require\s*\(\s*)["']three(?:\/[^"']*)?["']/;
75999
+ const containsThreeModuleImport = (sourceText) => THREE_MODULE_IMPORT_PATTERN.test(sourceText);
76000
+ const COMMENT_OPEN = "<!--";
76001
+ const COMMENT_CLOSE = "-->";
76002
+ const FRONTMATTER_FENCE = "---";
76003
+ const SCRIPT_TAG_NAME = "script";
76004
+ const SCRIPT_OPEN = `<${SCRIPT_TAG_NAME}`;
76005
+ const SCRIPT_CLOSE = `</${SCRIPT_TAG_NAME}`;
76006
+ const TEMPLATE_TAG_NAME = "template";
76007
+ const TEMPLATE_CLOSE = `</${TEMPLATE_TAG_NAME}`;
76008
+ const JAVASCRIPT_MIME_TYPES = new Set([
76009
+ "application/ecmascript",
76010
+ "application/javascript",
76011
+ "application/x-ecmascript",
76012
+ "application/x-javascript",
76013
+ "text/ecmascript",
76014
+ "text/javascript",
76015
+ "text/javascript1.0",
76016
+ "text/javascript1.1",
76017
+ "text/javascript1.2",
76018
+ "text/javascript1.3",
76019
+ "text/javascript1.4",
76020
+ "text/javascript1.5",
76021
+ "text/jscript",
76022
+ "text/livescript",
76023
+ "text/x-ecmascript",
76024
+ "text/x-javascript"
76025
+ ]);
76026
+ const RAW_TEXT_TAG_NAMES = new Set([
76027
+ "iframe",
76028
+ "noembed",
76029
+ "noframes",
76030
+ "noscript",
76031
+ "style",
76032
+ "textarea",
76033
+ "title",
76034
+ "xmp"
76035
+ ]);
76036
+ const PLAINTEXT_TAG_NAME = "plaintext";
76037
+ const TAG_OPEN_UTF8_BYTE = "<".charCodeAt(0);
76038
+ const TAG_CLOSE_UTF8_BYTE = ">".charCodeAt(0);
76039
+ const SINGLE_QUOTE_UTF8_BYTE = "'".charCodeAt(0);
76040
+ const DOUBLE_QUOTE_UTF8_BYTE = "\"".charCodeAt(0);
76041
+ const ATTRIBUTE_ASSIGNMENT_UTF8_BYTE = "=".charCodeAt(0);
76042
+ const TAG_SELF_CLOSE_UTF8_BYTE = "/".charCodeAt(0);
76043
+ const TAB_UTF8_BYTE = " ".charCodeAt(0);
76044
+ const FORM_FEED_UTF8_BYTE = "\f".charCodeAt(0);
76045
+ const isHtmlWhitespace = (byte) => byte === TAB_UTF8_BYTE || byte === 10 || byte === FORM_FEED_UTF8_BYTE || byte === 13 || byte === 32;
76046
+ const matchesAsciiCaseInsensitive = (sourceBuffer, startByte, expected) => {
76047
+ if (startByte + expected.length > sourceBuffer.length) return false;
76048
+ for (let expectedIndex = 0; expectedIndex < expected.length; expectedIndex++) {
76049
+ const sourceByte = sourceBuffer[startByte + expectedIndex];
76050
+ if (sourceByte === void 0 || String.fromCharCode(sourceByte).toLowerCase() !== expected[expectedIndex]) return false;
76051
+ }
76052
+ return true;
76053
+ };
76054
+ const isTagBoundary = (byte) => byte === TAG_CLOSE_UTF8_BYTE || byte === TAG_SELF_CLOSE_UTF8_BYTE || isHtmlWhitespace(byte);
76055
+ const isPotentialTagStart = (byte) => {
76056
+ if (byte === void 0) return false;
76057
+ return /[A-Za-z!/?]/.test(String.fromCharCode(byte));
76058
+ };
76059
+ const findLineEnd = (sourceBuffer, lineStartByte) => {
76060
+ let byteIndex = lineStartByte;
76061
+ while (byteIndex < sourceBuffer.length && sourceBuffer[byteIndex] !== 10 && sourceBuffer[byteIndex] !== 13) byteIndex++;
76062
+ return byteIndex;
76063
+ };
76064
+ const findNextLineStart = (sourceBuffer, lineStartByte) => {
76065
+ const lineEndByte = findLineEnd(sourceBuffer, lineStartByte);
76066
+ if (sourceBuffer[lineEndByte] === 13 && sourceBuffer[lineEndByte + 1] === 10) return lineEndByte + 2;
76067
+ return Math.min(lineEndByte + 1, sourceBuffer.length);
76068
+ };
76069
+ const isFrontmatterFenceLine = (sourceBuffer, lineStartByte) => {
76070
+ if (!matchesAsciiCaseInsensitive(sourceBuffer, lineStartByte, FRONTMATTER_FENCE)) return false;
76071
+ const lineEndByte = findLineEnd(sourceBuffer, lineStartByte);
76072
+ for (let byteIndex = lineStartByte + 3; byteIndex < lineEndByte; byteIndex++) if (!isHtmlWhitespace(sourceBuffer[byteIndex])) return false;
76073
+ return true;
76074
+ };
76075
+ const findFrontmatterEnd = (sourceBuffer) => {
76076
+ if (!isFrontmatterFenceLine(sourceBuffer, 0)) return 0;
76077
+ const openingFenceEndByte = findLineEnd(sourceBuffer, 0);
76078
+ let lineStartByte = findNextLineStart(sourceBuffer, 0);
76079
+ while (lineStartByte < sourceBuffer.length) {
76080
+ if (isFrontmatterFenceLine(sourceBuffer, lineStartByte)) return findLineEnd(sourceBuffer, lineStartByte);
76081
+ lineStartByte = findNextLineStart(sourceBuffer, lineStartByte);
76082
+ }
76083
+ return openingFenceEndByte;
76084
+ };
76085
+ const maskByteRange = (maskedBuffer, startByte, endByte) => {
76086
+ for (let byteIndex = startByte; byteIndex < endByte; byteIndex++) {
76087
+ const byte = maskedBuffer[byteIndex];
76088
+ if (byte !== 10 && byte !== 13) maskedBuffer[byteIndex] = 32;
76089
+ }
76090
+ };
76091
+ const readStartTagName = (sourceBuffer, tagStartByte) => {
76092
+ const firstNameByte = sourceBuffer[tagStartByte + 1];
76093
+ if (firstNameByte === void 0 || !/[A-Za-z]/.test(String.fromCharCode(firstNameByte))) return null;
76094
+ let nameEndByte = tagStartByte + 2;
76095
+ while (nameEndByte < sourceBuffer.length && /[A-Za-z0-9:-]/.test(String.fromCharCode(sourceBuffer[nameEndByte] ?? 32))) nameEndByte++;
76096
+ return sourceBuffer.subarray(tagStartByte + 1, nameEndByte).toString("ascii").toLowerCase();
76097
+ };
76098
+ const findTagEnd = (sourceBuffer, startByte) => {
76099
+ let quoteByte = null;
76100
+ for (let byteIndex = startByte; byteIndex < sourceBuffer.length; byteIndex++) {
76101
+ const byte = sourceBuffer[byteIndex];
76102
+ if (quoteByte !== null) {
76103
+ if (byte === quoteByte) quoteByte = null;
76104
+ continue;
76105
+ }
76106
+ if (byte === SINGLE_QUOTE_UTF8_BYTE || byte === DOUBLE_QUOTE_UTF8_BYTE) {
76107
+ quoteByte = byte;
76108
+ continue;
76109
+ }
76110
+ if (byte === TAG_CLOSE_UTF8_BYTE) return byteIndex;
76111
+ }
76112
+ return sourceBuffer.length;
76113
+ };
76114
+ const parseScriptAttributes = (sourceBuffer, attributesStartByte, tagEndByte) => {
76115
+ let byteIndex = attributesStartByte;
76116
+ let hasSource = false;
76117
+ let language = null;
76118
+ let scriptType = null;
76119
+ while (byteIndex < tagEndByte) {
76120
+ while (byteIndex < tagEndByte && (isHtmlWhitespace(sourceBuffer[byteIndex]) || sourceBuffer[byteIndex] === TAG_SELF_CLOSE_UTF8_BYTE)) byteIndex++;
76121
+ const attributeNameStartByte = byteIndex;
76122
+ while (byteIndex < tagEndByte && !isHtmlWhitespace(sourceBuffer[byteIndex]) && sourceBuffer[byteIndex] !== ATTRIBUTE_ASSIGNMENT_UTF8_BYTE && sourceBuffer[byteIndex] !== TAG_SELF_CLOSE_UTF8_BYTE) byteIndex++;
76123
+ const attributeName = sourceBuffer.subarray(attributeNameStartByte, byteIndex).toString("ascii").toLowerCase();
76124
+ while (byteIndex < tagEndByte && isHtmlWhitespace(sourceBuffer[byteIndex])) byteIndex++;
76125
+ let attributeValue = "";
76126
+ if (sourceBuffer[byteIndex] === ATTRIBUTE_ASSIGNMENT_UTF8_BYTE) {
76127
+ byteIndex++;
76128
+ while (byteIndex < tagEndByte && isHtmlWhitespace(sourceBuffer[byteIndex])) byteIndex++;
76129
+ const quoteByte = sourceBuffer[byteIndex];
76130
+ if (quoteByte === SINGLE_QUOTE_UTF8_BYTE || quoteByte === DOUBLE_QUOTE_UTF8_BYTE) {
76131
+ const valueStartByte = byteIndex + 1;
76132
+ byteIndex = valueStartByte;
76133
+ while (byteIndex < tagEndByte && sourceBuffer[byteIndex] !== quoteByte) byteIndex++;
76134
+ attributeValue = sourceBuffer.subarray(valueStartByte, byteIndex).toString("utf8");
76135
+ if (byteIndex < tagEndByte) byteIndex++;
76136
+ } else {
76137
+ const valueStartByte = byteIndex;
76138
+ while (byteIndex < tagEndByte && !isHtmlWhitespace(sourceBuffer[byteIndex]) && sourceBuffer[byteIndex] !== TAG_CLOSE_UTF8_BYTE) byteIndex++;
76139
+ attributeValue = sourceBuffer.subarray(valueStartByte, byteIndex).toString("utf8");
76140
+ }
76141
+ }
76142
+ if (attributeName === "src") hasSource = true;
76143
+ else if (attributeName === "type" && scriptType === null) scriptType = attributeValue;
76144
+ else if (attributeName === "language" && language === null) language = attributeValue;
76145
+ }
76146
+ return {
76147
+ hasSource,
76148
+ language,
76149
+ type: scriptType
76150
+ };
76151
+ };
76152
+ const isExecutableScript = (attributes) => {
76153
+ if (attributes.hasSource) return false;
76154
+ const type = attributes.type?.trim().toLowerCase() ?? "";
76155
+ if (type !== "") {
76156
+ const mimeType = type.split(";")[0]?.trim() ?? "";
76157
+ return mimeType === "module" || JAVASCRIPT_MIME_TYPES.has(mimeType);
76158
+ }
76159
+ const language = attributes.language?.trim().toLowerCase() ?? "";
76160
+ return language === "" || JAVASCRIPT_MIME_TYPES.has(`text/${language}`);
76161
+ };
76162
+ const findElementClose = (sourceBuffer, startByte, tagName) => {
76163
+ const closeTagStart = `</${tagName}`;
76164
+ for (let byteIndex = startByte; byteIndex < sourceBuffer.length; byteIndex++) if (sourceBuffer[byteIndex] === TAG_OPEN_UTF8_BYTE && matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, closeTagStart) && isTagBoundary(sourceBuffer[byteIndex + closeTagStart.length])) return byteIndex;
76165
+ return sourceBuffer.length;
76166
+ };
76167
+ const prepareHtmlScriptSource = (sourceBuffer) => {
76168
+ const frontmatterEndByte = findFrontmatterEnd(sourceBuffer);
76169
+ let maskedBuffer = frontmatterEndByte > 0 ? Buffer.from(sourceBuffer) : null;
76170
+ if (maskedBuffer !== null) maskByteRange(maskedBuffer, 0, frontmatterEndByte);
76171
+ const executableScriptBodies = [];
76172
+ let byteIndex = frontmatterEndByte;
76173
+ let templateDepth = 0;
76174
+ while (byteIndex < sourceBuffer.length) {
76175
+ if (sourceBuffer[byteIndex] !== TAG_OPEN_UTF8_BYTE) {
76176
+ byteIndex++;
76177
+ continue;
76178
+ }
76179
+ if (matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, COMMENT_OPEN)) {
76180
+ const commentEndByte = sourceBuffer.indexOf(COMMENT_CLOSE, byteIndex + 4);
76181
+ byteIndex = commentEndByte === -1 ? sourceBuffer.length : commentEndByte + 3;
76182
+ continue;
76183
+ }
76184
+ if (matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, TEMPLATE_CLOSE) && isTagBoundary(sourceBuffer[byteIndex + TEMPLATE_CLOSE.length])) {
76185
+ const tagEndByte = findTagEnd(sourceBuffer, byteIndex + TEMPLATE_CLOSE.length);
76186
+ if (templateDepth > 0) templateDepth--;
76187
+ byteIndex = Math.min(tagEndByte + 1, sourceBuffer.length);
76188
+ continue;
76189
+ }
76190
+ if (!matchesAsciiCaseInsensitive(sourceBuffer, byteIndex, SCRIPT_OPEN) || !isTagBoundary(sourceBuffer[byteIndex + SCRIPT_OPEN.length])) {
76191
+ if (!isPotentialTagStart(sourceBuffer[byteIndex + 1])) {
76192
+ byteIndex++;
76193
+ continue;
76194
+ }
76195
+ const tagEndByte = findTagEnd(sourceBuffer, byteIndex + 1);
76196
+ const tagName = readStartTagName(sourceBuffer, byteIndex);
76197
+ if (tagName === PLAINTEXT_TAG_NAME) break;
76198
+ if (tagName === TEMPLATE_TAG_NAME) templateDepth++;
76199
+ if (tagName !== null && RAW_TEXT_TAG_NAMES.has(tagName)) {
76200
+ const closeTagStartByte = findElementClose(sourceBuffer, tagEndByte + 1, tagName);
76201
+ if (closeTagStartByte === sourceBuffer.length) break;
76202
+ const closeTagEndByte = findTagEnd(sourceBuffer, closeTagStartByte + tagName.length + 2);
76203
+ byteIndex = Math.min(closeTagEndByte + 1, sourceBuffer.length);
76204
+ continue;
76205
+ }
76206
+ byteIndex = Math.min(tagEndByte + 1, sourceBuffer.length);
76207
+ continue;
76208
+ }
76209
+ const tagEndByte = findTagEnd(sourceBuffer, byteIndex + SCRIPT_OPEN.length);
76210
+ if (tagEndByte === sourceBuffer.length) break;
76211
+ const bodyStartByte = tagEndByte + 1;
76212
+ const bodyEndByte = findElementClose(sourceBuffer, bodyStartByte, SCRIPT_TAG_NAME);
76213
+ const attributes = parseScriptAttributes(sourceBuffer, byteIndex + SCRIPT_OPEN.length, tagEndByte);
76214
+ if (attributes.hasSource || templateDepth > 0) {
76215
+ maskedBuffer ??= Buffer.from(sourceBuffer);
76216
+ maskByteRange(maskedBuffer, bodyStartByte, bodyEndByte);
76217
+ } else if (isExecutableScript(attributes)) executableScriptBodies.push(sourceBuffer.subarray(bodyStartByte, bodyEndByte));
76218
+ if (bodyEndByte === sourceBuffer.length) break;
76219
+ const closeTagEndByte = findTagEnd(sourceBuffer, bodyEndByte + SCRIPT_CLOSE.length);
76220
+ byteIndex = Math.min(closeTagEndByte + 1, sourceBuffer.length);
76221
+ }
76222
+ return {
76223
+ executableScriptBodies,
76224
+ lintBuffer: maskedBuffer ?? sourceBuffer
76225
+ };
76226
+ };
76227
+ const ASTRO_FILE_PATTERN = /\.astro$/;
76228
+ const prepareLintSources = (rootDirectory, temporaryDirectory, candidateFiles) => {
76229
+ const lintFiles = [];
76230
+ const sourcePathByLintPath = /* @__PURE__ */ new Map();
76231
+ const sourceMapByLintPath = /* @__PURE__ */ new Map();
76232
+ const sizeByLintPath = /* @__PURE__ */ new Map();
76233
+ const htmlSourcesDirectory = Path.join(temporaryDirectory, "html-sources");
76234
+ const astroSourcesDirectory = Path.join(temporaryDirectory, "astro-sources");
76235
+ let htmlFileIndex = 0;
76236
+ let astroFileIndex = 0;
76237
+ let hasThreeModuleImport = false;
76238
+ for (const candidateFile of candidateFiles) {
76239
+ if (!HTML_FILE_PATTERN.test(candidateFile) && !ASTRO_FILE_PATTERN.test(candidateFile)) {
76240
+ lintFiles.push(candidateFile);
76241
+ continue;
76242
+ }
76243
+ const absoluteSourcePath = Path.isAbsolute(candidateFile) ? candidateFile : Path.resolve(rootDirectory, candidateFile);
76244
+ const sourceBuffer = NFS.readFileSync(absoluteSourcePath);
76245
+ if (ASTRO_FILE_PATTERN.test(candidateFile)) {
76246
+ const compilerSourcePath = absoluteSourcePath.replaceAll("\\", "/");
76247
+ const convertedSource = convertToTSX(sourceBuffer.toString("utf8"), {
76248
+ filename: compilerSourcePath,
76249
+ sourcemap: "external",
76250
+ includeScripts: true
76251
+ });
76252
+ if (astroFileIndex === 0) NFS.mkdirSync(astroSourcesDirectory, { recursive: true });
76253
+ const lintPath = Path.join(astroSourcesDirectory, `${astroFileIndex}.tsx`);
76254
+ const generatedBuffer = Buffer.from(convertedSource.code);
76255
+ NFS.writeFileSync(lintPath, generatedBuffer);
76256
+ lintFiles.push(candidateFile);
76257
+ lintFiles.push(lintPath);
76258
+ sourcePathByLintPath.set(Path.resolve(lintPath), candidateFile);
76259
+ sourceMapByLintPath.set(Path.resolve(lintPath), {
76260
+ traceMap: new TraceMap(JSON.stringify(convertedSource.map)),
76261
+ generatedBuffer,
76262
+ sourceBuffer
76263
+ });
76264
+ sizeByLintPath.set(lintPath, sourceBuffer.length);
76265
+ astroFileIndex++;
76266
+ continue;
76267
+ }
76268
+ const { executableScriptBodies, lintBuffer } = prepareHtmlScriptSource(sourceBuffer);
76269
+ if (htmlFileIndex === 0) NFS.mkdirSync(htmlSourcesDirectory, { recursive: true });
76270
+ const lintPath = Path.join(htmlSourcesDirectory, `${htmlFileIndex}.astro`);
76271
+ NFS.writeFileSync(lintPath, lintBuffer);
76272
+ lintFiles.push(lintPath);
76273
+ sourcePathByLintPath.set(Path.resolve(lintPath), candidateFile);
76274
+ sizeByLintPath.set(lintPath, sourceBuffer.length);
76275
+ hasThreeModuleImport ||= executableScriptBodies.some((scriptBody) => containsThreeModuleImport(scriptBody.toString("utf8")));
76276
+ htmlFileIndex++;
76277
+ }
76278
+ return {
76279
+ lintFiles,
76280
+ sourcePathByLintPath,
76281
+ sourceMapByLintPath,
76282
+ sizeByLintPath,
76283
+ hasThreeModuleImport
76284
+ };
76285
+ };
74754
76286
  /**
74755
76287
  * Atomically (re)writes the generated oxlintrc.json. Used twice in
74756
76288
  * the runner: once for the primary scan, once for the
@@ -74911,6 +76443,8 @@ const reactHooksJsPluginDropNote = (error) => {
74911
76443
  const runOxlint = async (options) => {
74912
76444
  const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, userConfig, configSourceDirectory = rootDirectory, onPartialFailure, onFileCoverage, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
74913
76445
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
76446
+ const runtimeGlobals = Array.isArray(userConfig?.runtimeGlobals) ? userConfig.runtimeGlobals.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
76447
+ let unpluginAutoImportGlobalScopes = [];
74914
76448
  const severityControls = buildRuleSeverityControls(userConfig);
74915
76449
  validateRuleRegistration();
74916
76450
  resetManifestCaches();
@@ -74924,21 +76458,6 @@ const runOxlint = async (options) => {
74924
76458
  const pluginPath = resolvePluginPath();
74925
76459
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
74926
76460
  const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
74927
- const buildConfig = (overrides) => createOxlintConfig({
74928
- pluginPath,
74929
- project,
74930
- customRulesOnly,
74931
- extendsPaths: overrides.extendsPaths,
74932
- ignoredTags,
74933
- includedTags,
74934
- includeTagDefaults,
74935
- serverAuthFunctionNames,
74936
- severityControls,
74937
- userPlugins,
74938
- disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
74939
- ruleSelection: overrides.ruleSelection,
74940
- sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
74941
- });
74942
76461
  const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
74943
76462
  const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
74944
76463
  const configPath = Path.join(configDirectory, "oxlintrc.json");
@@ -74974,7 +76493,36 @@ const runOxlint = async (options) => {
74974
76493
  await yieldToEventLoop();
74975
76494
  const sizedScanFiles = includePaths === void 0 ? listSourceFilesWithSize(rootDirectory) : null;
74976
76495
  const candidateFiles = includePaths !== void 0 ? includePaths : (sizedScanFiles ?? []).map((entry) => entry.path);
76496
+ unpluginAutoImportGlobalScopes = collectUnpluginAutoImportGlobalScopes({
76497
+ rootDirectory,
76498
+ candidateFiles
76499
+ });
76500
+ const preparedLintSources = prepareLintSources(rootDirectory, configDirectory, candidateFiles);
76501
+ const lintFiles = preparedLintSources.lintFiles;
76502
+ const hasPreparedFiles = preparedLintSources.sourcePathByLintPath.size > 0;
76503
+ const lintProject = !project.hasThree && preparedLintSources.hasThreeModuleImport ? {
76504
+ ...project,
76505
+ hasThree: true
76506
+ } : project;
76507
+ const buildConfig = (overrides) => createOxlintConfig({
76508
+ pluginPath,
76509
+ project: lintProject,
76510
+ customRulesOnly,
76511
+ extendsPaths: overrides.extendsPaths,
76512
+ ignoredTags,
76513
+ includedTags,
76514
+ includeTagDefaults,
76515
+ runtimeGlobals,
76516
+ unpluginAutoImportGlobalScopes,
76517
+ serverAuthFunctionNames,
76518
+ severityControls,
76519
+ userPlugins,
76520
+ disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin,
76521
+ ruleSelection: overrides.ruleSelection,
76522
+ sidecarRuleIdFilter: overrides.sidecarRuleIdFilter
76523
+ });
74977
76524
  const sizeByFile = sizedScanFiles !== null && lintBatchOrdering === "cost" ? new Map(sizedScanFiles.map((entry) => [entry.path, entry.sizeBytes])) : null;
76525
+ if (sizeByFile !== null) for (const [lintPath, sizeBytes] of preparedLintSources.sizeByLintPath) sizeByFile.set(lintPath, sizeBytes);
74978
76526
  const buildFileBatches = (passBaseArgs, passFiles) => sizeByFile !== null ? planLintBatches({
74979
76527
  baseArgs: passBaseArgs,
74980
76528
  files: passFiles,
@@ -75003,7 +76551,9 @@ const runOxlint = async (options) => {
75003
76551
  fileBatches: passFileBatches,
75004
76552
  rootDirectory,
75005
76553
  nodeBinaryPath,
75006
- project,
76554
+ project: lintProject,
76555
+ sourcePathByLintPath: preparedLintSources.sourcePathByLintPath,
76556
+ sourceMapByLintPath: preparedLintSources.sourceMapByLintPath,
75007
76557
  onPartialFailure: reportPartialFailure,
75008
76558
  onAnalyzedFiles: (filePaths) => {
75009
76559
  analyzedFiles = filePaths;
@@ -75038,7 +76588,7 @@ const runOxlint = async (options) => {
75038
76588
  };
75039
76589
  }
75040
76590
  };
75041
- if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
76591
+ if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0 && !hasPreparedFiles) {
75042
76592
  const rulesetHash = computeRulesetHash({
75043
76593
  config: buildConfig({
75044
76594
  extendsPaths: [],
@@ -75196,14 +76746,16 @@ const runOxlint = async (options) => {
75196
76746
  ]);
75197
76747
  }
75198
76748
  const baseArgs = makeBaseArgs(configPath);
75199
- const fileBatches = buildFileBatches(baseArgs, candidateFiles);
76749
+ const fileBatches = buildFileBatches(baseArgs, lintFiles);
75200
76750
  let analyzedFiles = [];
75201
76751
  const runBatches = () => spawnLintBatches({
75202
76752
  baseArgs,
75203
76753
  fileBatches,
75204
76754
  rootDirectory,
75205
76755
  nodeBinaryPath,
75206
- project,
76756
+ project: lintProject,
76757
+ sourcePathByLintPath: preparedLintSources.sourcePathByLintPath,
76758
+ sourceMapByLintPath: preparedLintSources.sourceMapByLintPath,
75207
76759
  onPartialFailure,
75208
76760
  onAnalyzedFiles: (filePaths) => {
75209
76761
  analyzedFiles = filePaths;
@@ -76563,10 +78115,14 @@ const materializeSourceTree = (input) => gen(function* () {
76563
78115
  materializedFiles.push(relativePath);
76564
78116
  }
76565
78117
  yield* sync(() => {
76566
- for (const configFilename of STAGED_FILES_PROJECT_CONFIG_FILENAMES) {
76567
- const sourcePath = path.join(input.directory, configFilename);
76568
- const targetPath = path.join(resolvedTempDirectory, configFilename);
76569
- if (fs.existsSync(sourcePath) && !fs.existsSync(targetPath)) fs.cpSync(sourcePath, targetPath);
78118
+ for (const subdirectory of ["", ...input.configSubdirectories ?? []]) for (const configFilename of STAGED_FILES_PROJECT_CONFIG_FILENAMES) {
78119
+ const sourcePath = path.join(input.directory, subdirectory, configFilename);
78120
+ const targetPath = path.resolve(resolvedTempDirectory, subdirectory, configFilename);
78121
+ if (!isPathInsideDirectory(targetPath, resolvedTempDirectory)) continue;
78122
+ if (fs.existsSync(sourcePath) && !fs.existsSync(targetPath)) {
78123
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
78124
+ fs.cpSync(sourcePath, targetPath);
78125
+ }
76570
78126
  }
76571
78127
  });
76572
78128
  return {
@@ -76599,15 +78155,17 @@ var StagedFiles = class StagedFiles extends Service()("react-doctor/StagedFiles"
76599
78155
  static layerNode = effect(StagedFiles, gen(function* () {
76600
78156
  const git = yield* Git;
76601
78157
  return StagedFiles.of({
76602
- discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries.filter(isLintableSourceFile)), withSpan("StagedFiles.discoverSourceFiles")),
76603
- materialize: ({ directory, stagedFiles, tempDirectory }) => materializeSourceTree({
78158
+ discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries === null ? null : entries.filter(isLintableSourceFile)), withSpan("StagedFiles.discoverSourceFiles")),
78159
+ materialize: ({ directory, stagedFiles, tempDirectory, configSubdirectories }) => materializeSourceTree({
76604
78160
  directory,
76605
78161
  files: stagedFiles,
76606
78162
  tempDirectory,
78163
+ configSubdirectories,
76607
78164
  readContent: (relativePath) => git.showStagedContent(directory, relativePath, { maxBufferBytes: GIT_SHOW_MAX_BUFFER_BYTES })
76608
78165
  }).pipe(map$3((tree) => ({
76609
78166
  tempDirectory: tree.tempDirectory,
76610
78167
  stagedFiles: tree.materializedFiles,
78168
+ unmaterializedFiles: tree.unmaterializedFiles,
76611
78169
  cleanup: tree.cleanup
76612
78170
  })), withSpan("StagedFiles.materialize"))
76613
78171
  });
@@ -76622,6 +78180,7 @@ var StagedFiles = class StagedFiles extends Service()("react-doctor/StagedFiles"
76622
78180
  materialize: ({ tempDirectory }) => succeed$2({
76623
78181
  tempDirectory,
76624
78182
  stagedFiles: snapshot.materializedFiles ?? snapshot.sourceFiles ?? [],
78183
+ unmaterializedFiles: [],
76625
78184
  cleanup: () => {}
76626
78185
  })
76627
78186
  }));
@@ -77318,6 +78877,7 @@ const BASELINE_FILES_TEMP_DIR_PREFIX = "react-doctor-baseline-";
77318
78877
  const SCAN_RESULT_CACHE_FILENAME = "scan-cache.json";
77319
78878
  const RUN_GIT_MAX_BUFFER_BYTES = 64 * 1024 * 1024;
77320
78879
  const GH_DEFAULT_BRANCH_PROBE_TIMEOUT_MS = 5e3;
78880
+ const TUI_REPORT_COMPACT_MAX_ROWS = 29;
77321
78881
  const TUI_REPORT_DETAIL_WIDTH_FRACTION = .6;
77322
78882
  const CI_TRUST_COMPANIES = "PayPal, Rippling, and Alibaba";
77323
78883
  const WELCOME_EXPLANATION_HOLD_MS = 1e3;
@@ -77330,11 +78890,13 @@ const METRIC = {
77330
78890
  cliError: "cli.error",
77331
78891
  cliEnvironmentError: "cli.env_error",
77332
78892
  stagedSnapshotDivergence: "staged.snapshot_divergence",
78893
+ stagedPerProject: "staged.per_project",
77333
78894
  projectDetected: "project.detected",
77334
78895
  projectPathSelected: "project.path_selected",
77335
78896
  projectConfigSelected: "project.config_selected",
77336
78897
  scanCompleted: "scan.completed",
77337
78898
  scanDuration: "scan.duration",
78899
+ scanFeedbackDelay: "scan.feedback_delay",
77338
78900
  scanPhaseDuration: "scan.phase_duration",
77339
78901
  scanFiles: "scan.files",
77340
78902
  scanScore: "scan.score",
@@ -77366,6 +78928,10 @@ const METRIC = {
77366
78928
  lspScanCompleted: "lsp.scan.completed",
77367
78929
  lspScanDuration: "lsp.scan.duration",
77368
78930
  lspScanDiagnostics: "lsp.scan.diagnostics",
78931
+ tuiActionMenuOpened: "tui.action_menu_opened",
78932
+ tuiCompactReportShown: "tui.compact_report_shown",
78933
+ tuiFindingNavigated: "tui.finding_navigated",
78934
+ tuiStackedReportCapped: "tui.stacked_report_capped",
77369
78935
  aiTrainingWarningShown: "ai.training.warning_shown",
77370
78936
  jsonOutUsed: "json.out_used"
77371
78937
  };
@@ -77410,7 +78976,7 @@ const makeNoopConsole = () => ({
77410
78976
  });
77411
78977
  //#endregion
77412
78978
  //#region src/cli/utils/version.ts
77413
- const VERSION = "0.9.1";
78979
+ const VERSION = "0.9.2-dev.1098b9c";
77414
78980
  //#endregion
77415
78981
  //#region src/cli/utils/json-mode.ts
77416
78982
  let context = null;
@@ -77768,13 +79334,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
77768
79334
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
77769
79335
  * standard `SENTRY_RELEASE` override.
77770
79336
  */
77771
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.1`;
79337
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.2-dev.1098b9c`;
77772
79338
  /**
77773
79339
  * Deployment environment shown in Sentry's environment filter. Defaults to
77774
79340
  * `production` for tagged releases and `development` for dev/unbuilt versions,
77775
79341
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
77776
79342
  */
77777
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.1") ? "development" : "production");
79343
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.2-dev.1098b9c") ? "development" : "production");
77778
79344
  /**
77779
79345
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
77780
79346
  * (set to `0` to disable tracing) and falls back to
@@ -90439,6 +92005,7 @@ const buildScanAttributes = (input) => {
90439
92005
  rulesDisabled: ruleKeys.filter((key) => ruleOverrides[key] === "off").length,
90440
92006
  fileCount: input.result?.scannedFileCount ?? null,
90441
92007
  nonJsxFileCount: input.result?.analyzedFiles?.filter((filePath) => !JSX_FILE_PATTERN.test(filePath)).length ?? null,
92008
+ htmlFileCount: input.result?.analyzedFiles?.filter((filePath) => HTML_FILE_PATTERN.test(filePath)).length ?? null,
90442
92009
  multilineDiagnosticCount: input.result?.diagnostics.filter((diagnostic) => (diagnostic.endLine ?? diagnostic.line) > diagnostic.line).length ?? null
90443
92010
  });
90444
92011
  };
@@ -91230,16 +92797,19 @@ const formatClusterLocation = (cluster, resolveSourceRoot, hyperlinks) => {
91230
92797
  if (!hyperlinks) return `${location}${contextTag}`;
91231
92798
  return `${formatHyperlink(location, pathToFileURL(resolveAbsolutePath(lead.filePath, resolveSourceRoot(lead))).href)}${contextTag}`;
91232
92799
  };
91233
- const buildDiagnosticClusterLines = (cluster, resolveSourceRoot, renderCodeFrame, hyperlinks) => {
92800
+ const buildDiagnosticClusterLines = (cluster, resolveSourceRoot, resolveFrameSourceRoot, renderCodeFrame, hyperlinks) => {
91234
92801
  const lead = cluster.diagnostics[0];
91235
92802
  const isMultiSite = cluster.diagnostics.length > 1;
92803
+ const sourceRoot = resolveSourceRoot(lead);
92804
+ const frameSourceRoot = resolveFrameSourceRoot(lead);
92805
+ const frameFilePath = Path.isAbsolute(lead.filePath) && sourceRoot !== frameSourceRoot ? Path.relative(sourceRoot, lead.filePath) : lead.filePath;
91236
92806
  const lines = ["", highlighter.gray(`${TOP_ERROR_DETAIL_INDENT}${formatClusterLocation(cluster, resolveSourceRoot, hyperlinks)}`)];
91237
92807
  const codeFrame = renderCodeFrame ? buildCodeFrame({
91238
- filePath: lead.filePath,
92808
+ filePath: frameFilePath,
91239
92809
  line: cluster.startLine,
91240
92810
  column: isMultiSite ? 0 : lead.column,
91241
92811
  endLine: isMultiSite ? cluster.endLine : void 0,
91242
- rootDirectory: resolveSourceRoot(lead)
92812
+ rootDirectory: frameSourceRoot
91243
92813
  }) : null;
91244
92814
  if (codeFrame) {
91245
92815
  const boxInnerWidth = resolveMeasureWidth(8);
@@ -91252,7 +92822,7 @@ const buildDiagnosticClusterLines = (cluster, resolveSourceRoot, renderCodeFrame
91252
92822
  }
91253
92823
  return lines;
91254
92824
  };
91255
- const buildRuleDetailBlock = (ruleKey, ruleDiagnostics, resolveSourceRoot, renderEverySite, isAgentEnvironment, hyperlinks) => {
92825
+ const buildRuleDetailBlock = (ruleKey, ruleDiagnostics, resolveSourceRoot, resolveFrameSourceRoot, renderEverySite, isAgentEnvironment, hyperlinks) => {
91256
92826
  const representative = pickRepresentativeDiagnostic(ruleDiagnostics);
91257
92827
  const { severity } = representative;
91258
92828
  const trailingBadge = formatTrailingSiteBadge(ruleDiagnostics.length);
@@ -91274,7 +92844,7 @@ const buildRuleDetailBlock = (ruleKey, ruleDiagnostics, resolveSourceRoot, rende
91274
92844
  }
91275
92845
  const renderCodeFrame = severity === "error";
91276
92846
  const sites = renderEverySite ? ruleDiagnostics : [representative];
91277
- if (!(isCollapsedWarningGroup && representative.help.includes(representative.filePath))) for (const cluster of clusterNearbyDiagnostics(sites)) lines.push(...buildDiagnosticClusterLines(cluster, resolveSourceRoot, renderCodeFrame, hyperlinks));
92847
+ if (!(isCollapsedWarningGroup && representative.help.includes(representative.filePath))) for (const cluster of clusterNearbyDiagnostics(sites)) lines.push(...buildDiagnosticClusterLines(cluster, resolveSourceRoot, resolveFrameSourceRoot, renderCodeFrame, hyperlinks));
91278
92848
  return lines;
91279
92849
  };
91280
92850
  const selectErrorRuleGroups = (diagnostics, rulePriority) => buildSortedRuleGroups(diagnostics.filter((diagnostic) => diagnostic.severity === "error"), rulePriority);
@@ -91300,7 +92870,7 @@ const buildMigrationScaleAdvisoryLines = (diagnostics) => {
91300
92870
  return lines;
91301
92871
  };
91302
92872
  const getTopErrorRuleKeys = (diagnostics, limit, rulePriority) => new Set(selectTopErrorRuleGroups(diagnostics, limit, rulePriority).map(([ruleKey]) => ruleKey));
91303
- const buildTopErrorsSection = (diagnostics, resolveSourceRoot, hyperlinks, rulePriority) => {
92873
+ const buildTopErrorsSection = (diagnostics, resolveSourceRoot, resolveFrameSourceRoot, hyperlinks, rulePriority) => {
91304
92874
  const topRuleGroups = selectErrorRuleGroups(diagnostics, rulePriority).slice(0, 3);
91305
92875
  if (topRuleGroups.length === 0) return {
91306
92876
  lines: [],
@@ -91310,7 +92880,7 @@ const buildTopErrorsSection = (diagnostics, resolveSourceRoot, hyperlinks, ruleP
91310
92880
  const blockOffsets = [];
91311
92881
  for (const [ruleKey, ruleDiagnostics] of topRuleGroups) {
91312
92882
  blockOffsets.push(lines.length);
91313
- lines.push(...buildRuleDetailBlock(ruleKey, ruleDiagnostics, resolveSourceRoot, false, false, hyperlinks));
92883
+ lines.push(...buildRuleDetailBlock(ruleKey, ruleDiagnostics, resolveSourceRoot, resolveFrameSourceRoot, false, false, hyperlinks));
91314
92884
  lines.push("");
91315
92885
  }
91316
92886
  return {
@@ -91348,18 +92918,19 @@ const buildOverviewHeaderLines = (diagnostics) => {
91348
92918
  * single Effect.forEach over Console.log so failures or fiber
91349
92919
  * interruption produce predictable partial output.
91350
92920
  */
91351
- const printDiagnostics = (diagnostics, isVerbose, sourceRoot, rulePriority, isAgentEnvironment = false, onboarding = {}, hyperlinks = false) => gen(function* () {
92921
+ const printDiagnostics = (diagnostics, isVerbose, sourceRoot, rulePriority, isAgentEnvironment = false, onboarding = {}, hyperlinks = false, frameSourceRoot = sourceRoot) => gen(function* () {
91352
92922
  const sectionPause = onboarding.sectionPause ?? void_;
91353
92923
  const animateCountUp = onboarding.animateCountUp ?? false;
91354
92924
  const resolveSourceRoot = typeof sourceRoot === "function" ? sourceRoot : () => sourceRoot;
92925
+ const resolveFrameSourceRoot = typeof frameSourceRoot === "function" ? frameSourceRoot : () => frameSourceRoot;
91355
92926
  let detailLines;
91356
92927
  let topErrorBlockOffsets = [];
91357
92928
  if (!isVerbose) {
91358
- const topErrors = buildTopErrorsSection(diagnostics, resolveSourceRoot, hyperlinks, rulePriority);
92929
+ const topErrors = buildTopErrorsSection(diagnostics, resolveSourceRoot, resolveFrameSourceRoot, hyperlinks, rulePriority);
91359
92930
  detailLines = topErrors.lines;
91360
92931
  topErrorBlockOffsets = topErrors.blockOffsets;
91361
92932
  } else detailLines = buildSortedRuleGroups(diagnostics, rulePriority).flatMap(([ruleKey, ruleDiagnostics]) => {
91362
- return [...buildRuleDetailBlock(ruleKey, ruleDiagnostics, resolveSourceRoot, true, isAgentEnvironment, hyperlinks), ""];
92933
+ return [...buildRuleDetailBlock(ruleKey, ruleDiagnostics, resolveSourceRoot, resolveFrameSourceRoot, true, isAgentEnvironment, hyperlinks), ""];
91363
92934
  });
91364
92935
  const overflowLine = isVerbose ? void 0 : buildOverflowSummaryLine(diagnostics, rulePriority);
91365
92936
  const categoryTallies = buildCategoryDiagnosticGroups(diagnostics, rulePriority).map(buildCategoryTally);
@@ -92623,26 +94194,26 @@ const finalizeAndRender = (input) => gen(function* () {
92623
94194
  //#region src/cli/utils/get-staged-files.ts
92624
94195
  const stagedFilesLayer = StagedFiles.layerNode.pipe(provide$2(Git.layerNode));
92625
94196
  const getStagedSourceFiles = async (directory) => {
94197
+ let stagedSourceFiles;
92626
94198
  try {
92627
- return [...await runPromise(gen(function* () {
94199
+ stagedSourceFiles = await runPromise(gen(function* () {
92628
94200
  return yield* (yield* StagedFiles).discoverSourceFiles(directory);
92629
- }).pipe(provide(stagedFilesLayer)))];
94201
+ }).pipe(provide(stagedFilesLayer)));
92630
94202
  } catch (error) {
92631
94203
  cliLogger.warn(`Failed to discover staged files: ${messageFromUnknown(error)}`);
92632
94204
  return [];
92633
94205
  }
94206
+ 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.");
94207
+ return [...stagedSourceFiles];
92634
94208
  };
92635
- const materializeStagedFiles = async (directory, stagedFiles, tempDirectory) => {
94209
+ const materializeStagedFiles = async (input) => {
92636
94210
  const snapshot = await runPromise(gen(function* () {
92637
- return yield* (yield* StagedFiles).materialize({
92638
- directory,
92639
- stagedFiles,
92640
- tempDirectory
92641
- });
94211
+ return yield* (yield* StagedFiles).materialize(input);
92642
94212
  }).pipe(provide(stagedFilesLayer)));
92643
94213
  return {
92644
94214
  tempDirectory: snapshot.tempDirectory,
92645
94215
  stagedFiles: [...snapshot.stagedFiles],
94216
+ unmaterializedFiles: [...snapshot.unmaterializedFiles],
92646
94217
  cleanup: snapshot.cleanup
92647
94218
  };
92648
94219
  };
@@ -94516,13 +96087,18 @@ const printMultiProjectSummary = (input) => gen(function* () {
94516
96087
  const scoreDiagnostics = new Set(filterScansForSurface(completedScans, "score"));
94517
96088
  const displayedScoreDiagnostics = displayDiagnostics.filter((diagnostic) => scoreDiagnostics.has(diagnostic));
94518
96089
  const projectRootByDiagnostic = /* @__PURE__ */ new WeakMap();
94519
- for (const scan of completedScans) for (const diagnostic of scan.result.diagnostics) projectRootByDiagnostic.set(diagnostic, scan.result.project.rootDirectory);
96090
+ const frameSourceRootByDiagnostic = /* @__PURE__ */ new WeakMap();
96091
+ for (const scan of completedScans) for (const diagnostic of scan.result.diagnostics) {
96092
+ projectRootByDiagnostic.set(diagnostic, scan.result.project.rootDirectory);
96093
+ frameSourceRootByDiagnostic.set(diagnostic, scan.frameSourceRoot ?? scan.result.project.rootDirectory);
96094
+ }
94520
96095
  const resolveDiagnosticSourceRoot = (diagnostic) => projectRootByDiagnostic.get(diagnostic) ?? "";
96096
+ const resolveDiagnosticFrameSourceRoot = (diagnostic) => frameSourceRootByDiagnostic.get(diagnostic) ?? resolveDiagnosticSourceRoot(diagnostic);
94521
96097
  const totalScannedFileCount = countUniqueScannedFiles(completedScans.map((scan) => scan.result));
94522
96098
  yield* log(`${highlighter.success("✔")} Scanned ${totalScannedFileCount} ${totalScannedFileCount === 1 ? "file" : "files"} in ${formatElapsedTime(totalElapsedMilliseconds)}`);
94523
96099
  if (displayDiagnostics.length > 0) {
94524
96100
  yield* log("");
94525
- yield* printDiagnostics(displayDiagnostics, verbose, resolveDiagnosticSourceRoot, buildRulePriorityMap(completedScans.map((scan) => scan.result.score)), isCodingAgentEnvironment(), { animateCountUp: animateRender }, shouldRenderHyperlinks(process.stdout));
96101
+ yield* printDiagnostics(displayDiagnostics, verbose, resolveDiagnosticSourceRoot, buildRulePriorityMap(completedScans.map((scan) => scan.result.score)), isCodingAgentEnvironment(), { animateCountUp: animateRender }, shouldRenderHyperlinks(process.stdout), resolveDiagnosticFrameSourceRoot);
94526
96102
  }
94527
96103
  const lowestScoredScan = findLowestScoredScan(completedScans);
94528
96104
  const aggregateScore = lowestScoredScan?.result.score ?? null;
@@ -94910,6 +96486,45 @@ const runExplain = async (fileLineArgument, context) => {
94910
96486
  }
94911
96487
  };
94912
96488
  //#endregion
96489
+ //#region src/cli/utils/run-project-scan-batch.ts
96490
+ /**
96491
+ * Run one scan per project through the same bounded pool as
96492
+ * `diagnose({ projects })`, with the batch spinner and its progress counter.
96493
+ *
96494
+ * Pool members must not toggle the module-level spinner-silent flag themselves —
96495
+ * overlapping save/restore pairs would race — so the batch owns that toggle once
96496
+ * around the whole run.
96497
+ *
96498
+ * A `scanProject` that returns `null` drops the project from the results: diff
96499
+ * mode skips projects with no changed source.
96500
+ */
96501
+ const runProjectScanBatch = async (input) => {
96502
+ const startTime = performance$1.now();
96503
+ const projectCount = input.projects.length;
96504
+ const isMultiProject = projectCount > 1;
96505
+ const batchSpinner = isMultiProject && !input.isQuiet ? spinner(`Scanning ${projectCount} projects…`).start() : null;
96506
+ const ownsBatchSpinnerSilence = isMultiProject && input.isSilent;
96507
+ const wasSpinnerSilent = isSpinnerSilent();
96508
+ if (ownsBatchSpinnerSilence) setSpinnerSilent(true);
96509
+ let finishedProjectCount = 0;
96510
+ let scanOutcomes;
96511
+ try {
96512
+ scanOutcomes = await mapWithConcurrency(input.projects, isMultiProject ? 4 : 1, async (project) => {
96513
+ const scanOutcome = await input.scanProject(project);
96514
+ finishedProjectCount += 1;
96515
+ batchSpinner?.update(`Scanning ${projectCount} projects… (${finishedProjectCount}/${projectCount})`);
96516
+ return scanOutcome;
96517
+ });
96518
+ } finally {
96519
+ if (ownsBatchSpinnerSilence) setSpinnerSilent(wasSpinnerSilent);
96520
+ batchSpinner?.stop();
96521
+ }
96522
+ return {
96523
+ completedScans: scanOutcomes.filter((scanOutcome) => scanOutcome !== null),
96524
+ elapsedMilliseconds: performance$1.now() - startTime
96525
+ };
96526
+ };
96527
+ //#endregion
94913
96528
  //#region src/cli/utils/project-manifest-changed.ts
94914
96529
  const PACKAGE_JSON = "package.json";
94915
96530
  /**
@@ -94926,6 +96541,29 @@ const projectManifestChanged = (rootDirectory, projectDirectory, diffInfo) => {
94926
96541
  return diffInfo.changedFiles.some((filePath) => toForwardSlashes(filePath) === manifestPath);
94927
96542
  };
94928
96543
  //#endregion
96544
+ //#region src/cli/utils/select-staged-projects.ts
96545
+ /**
96546
+ * Appended to the reason a `--staged` run could not scan per package. Shared so
96547
+ * both fallback sites word it identically.
96548
+ */
96549
+ 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.";
96550
+ /**
96551
+ * Resolve the project directories a `--staged` scan owns. The interactive picker
96552
+ * is always skipped: a commit hook has nobody to answer it.
96553
+ */
96554
+ const selectStagedProjects = async (input) => {
96555
+ if (input.projectFlag) return selectProjects(input.rootDirectory, input.projectFlag, true, void 0);
96556
+ if (input.configProjects === void 0) return [input.rootDirectory];
96557
+ try {
96558
+ return await selectProjects(input.rootDirectory, void 0, true, input.configProjects);
96559
+ } catch (error) {
96560
+ if (!(error instanceof CliInputError)) throw error;
96561
+ cliLogger.warn(`${error.message} ${STAGED_PROJECT_FALLBACK_HINT}`);
96562
+ cliLogger.break();
96563
+ return [input.rootDirectory];
96564
+ }
96565
+ };
96566
+ //#endregion
94929
96567
  //#region src/cli/utils/should-fail-scan-gate.ts
94930
96568
  const shouldFailScanGate = (input) => {
94931
96569
  if (input.blockingLevel === "none") return false;
@@ -95091,6 +96729,7 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
95091
96729
  const isQuiet = isScoreOnly || isJsonMode;
95092
96730
  const requestedDirectory = Path.resolve(directory);
95093
96731
  const startTime = performance$1.now();
96732
+ let scanStartupSpinner = null;
95094
96733
  if (isJsonMode) {
95095
96734
  enableJsonMode({
95096
96735
  compact: Boolean(flags.jsonCompact),
@@ -95146,8 +96785,13 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
95146
96785
  json: flags.json
95147
96786
  });
95148
96787
  if (flags.staged) {
95149
- const stagedFiles = await getStagedSourceFiles(resolvedDirectory);
95150
- if (stagedFiles.length === 0) {
96788
+ const configProjectsApply = (userConfig?.projects ?? []).some((projectName) => projectName.trim().length > 0) && scanTarget.requestedDirectory === scanTarget.configSourceDirectory;
96789
+ const projectDirectories = await selectStagedProjects({
96790
+ rootDirectory: resolvedDirectory,
96791
+ projectFlag: flags.project,
96792
+ configProjects: configProjectsApply ? userConfig?.projects : void 0
96793
+ });
96794
+ const reportNothingToScan = (input) => {
95151
96795
  if (isJsonMode) writeJsonReport(buildJsonReport({
95152
96796
  version: VERSION,
95153
96797
  directory: resolvedDirectory,
@@ -95156,75 +96800,214 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
95156
96800
  scans: [],
95157
96801
  totalElapsedMilliseconds: performance$1.now() - startTime
95158
96802
  }));
95159
- else if (!isScoreOnly) cliLogger.dim("No staged source files found.");
96803
+ else if (!isScoreOnly) if (input.severity === "warn") {
96804
+ cliLogger.warn(input.reason);
96805
+ cliLogger.break();
96806
+ } else cliLogger.dim(input.reason);
96807
+ };
96808
+ const rootStagedFiles = await getStagedSourceFiles(resolvedDirectory);
96809
+ if (rootStagedFiles.length === 0) {
96810
+ reportNothingToScan({ reason: "No staged source files found." });
95160
96811
  return;
95161
96812
  }
95162
- if (!isQuiet) {
95163
- cliLogger.log(`Scanning ${highlighter.info(`${stagedFiles.length}`)} staged files...`);
96813
+ const buildProjectScanContext = async (projectDirectory) => {
96814
+ const projectScanTarget = projectDirectory === resolvedDirectory ? scanTarget : await resolveScanTarget(projectDirectory, { allowAmbiguous: true });
96815
+ const scanDirectory = projectScanTarget.resolvedDirectory;
96816
+ const treeRelativeDirectory = resolveProjectRelativeDirectory(resolvedDirectory, scanDirectory);
96817
+ if (treeRelativeDirectory === null) return null;
96818
+ return {
96819
+ projectDirectory,
96820
+ scanDirectory,
96821
+ treeRelativeDirectory,
96822
+ projectConfig: projectDirectory === resolvedDirectory ? userConfig : mergeReactDoctorConfigs(userConfig, projectScanTarget.userConfig ?? void 0),
96823
+ projectConfigSourceDirectory: projectScanTarget.userConfig?.plugins === void 0 ? scanTarget.configSourceDirectory : projectScanTarget.configSourceDirectory
96824
+ };
96825
+ };
96826
+ const projectScanContexts = [];
96827
+ const seenScanDirectories = /* @__PURE__ */ new Set();
96828
+ for (const projectDirectory of projectDirectories) {
96829
+ const projectScanContext = await buildProjectScanContext(projectDirectory);
96830
+ if (projectScanContext === null) {
96831
+ 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.`);
96832
+ continue;
96833
+ }
96834
+ if (seenScanDirectories.has(projectScanContext.scanDirectory)) continue;
96835
+ seenScanDirectories.add(projectScanContext.scanDirectory);
96836
+ projectScanContexts.push(projectScanContext);
96837
+ }
96838
+ if (projectScanContexts.length === 0) {
96839
+ cliLogger.warn(`No configured project is inside ${resolvedDirectory}. ${STAGED_PROJECT_FALLBACK_HINT}`);
95164
96840
  cliLogger.break();
96841
+ const rootScanContext = await buildProjectScanContext(resolvedDirectory);
96842
+ if (rootScanContext !== null) projectScanContexts.push(rootScanContext);
95165
96843
  }
95166
- const tempDirectory = NFS.mkdtempSync(Path.join(tmpdir(), STAGED_FILES_TEMP_DIR_PREFIX));
95167
- const snapshot = await materializeStagedFiles(resolvedDirectory, stagedFiles, tempDirectory).catch((error) => {
95168
- NFS.rmSync(tempDirectory, {
95169
- recursive: true,
95170
- force: true
96844
+ const contextsByLongestPathFirst = [...projectScanContexts].sort((left, right) => right.treeRelativeDirectory.length - left.treeRelativeDirectory.length);
96845
+ const ownedStagedFiles = /* @__PURE__ */ new Map();
96846
+ for (const stagedFile of rootStagedFiles) {
96847
+ const owner = contextsByLongestPathFirst.find((context) => context.treeRelativeDirectory.length === 0 || stagedFile.startsWith(`${context.treeRelativeDirectory}/`));
96848
+ if (owner === void 0) continue;
96849
+ const ownedFiles = ownedStagedFiles.get(owner.scanDirectory);
96850
+ if (ownedFiles === void 0) ownedStagedFiles.set(owner.scanDirectory, [stagedFile]);
96851
+ else ownedFiles.push(stagedFile);
96852
+ }
96853
+ const stagedProjectScans = [];
96854
+ for (const projectScanContext of projectScanContexts) {
96855
+ const projectStagedFiles = ownedStagedFiles.get(projectScanContext.scanDirectory);
96856
+ if (projectStagedFiles === void 0) continue;
96857
+ stagedProjectScans.push({
96858
+ ...projectScanContext,
96859
+ stagedFiles: projectStagedFiles
95171
96860
  });
95172
- throw error;
95173
- });
96861
+ }
96862
+ if (stagedProjectScans.length === 0) {
96863
+ reportNothingToScan({ reason: "No staged source files in the selected projects." });
96864
+ return;
96865
+ }
96866
+ const selectedStagedFiles = stagedProjectScans.flatMap((projectScan) => projectScan.stagedFiles);
96867
+ const stagedFileCount = selectedStagedFiles.length;
96868
+ const unselectedStagedFileCount = rootStagedFiles.length - stagedFileCount;
96869
+ if (!isQuiet) {
96870
+ cliLogger.log(`Scanning ${highlighter.info(`${stagedFileCount}`)} staged files...`);
96871
+ if (unselectedStagedFileCount > 0) cliLogger.dim(`${unselectedStagedFileCount} more staged file${unselectedStagedFileCount === 1 ? "" : "s"} outside the selected projects.`);
96872
+ cliLogger.break();
96873
+ }
95174
96874
  const stagedWantsLines = resolveScope(flags, userConfig).scope === "lines";
95175
96875
  const stagedLineRanges = stagedWantsLines ? await getChangedLineRanges({
95176
96876
  directory: resolvedDirectory,
95177
96877
  cached: true,
95178
- files: snapshot.stagedFiles
96878
+ files: selectedStagedFiles
95179
96879
  }) : null;
95180
96880
  if (stagedWantsLines && stagedLineRanges === null && !isQuiet) {
95181
96881
  cliLogger.warn("Could not determine staged changed lines; reporting all issues in staged files.");
95182
96882
  cliLogger.break();
95183
96883
  }
95184
- try {
95185
- const scanResult = await inspect(snapshot.tempDirectory, {
96884
+ if (stagedProjectScans.some((projectScan) => projectScan.treeRelativeDirectory.length > 0)) recordCount(METRIC.stagedPerProject, 1, { projectCount: stagedProjectScans.length });
96885
+ const tempDirectory = NFS.mkdtempSync(Path.join(tmpdir(), STAGED_FILES_TEMP_DIR_PREFIX));
96886
+ const configSubdirectories = /* @__PURE__ */ new Set();
96887
+ for (const projectScan of stagedProjectScans) {
96888
+ configSubdirectories.add(projectScan.treeRelativeDirectory);
96889
+ const projectRelativeDirectory = resolveProjectRelativeDirectory(resolvedDirectory, projectScan.projectDirectory);
96890
+ if (projectRelativeDirectory !== null) configSubdirectories.add(projectRelativeDirectory);
96891
+ }
96892
+ const snapshot = await materializeStagedFiles({
96893
+ directory: resolvedDirectory,
96894
+ stagedFiles: selectedStagedFiles,
96895
+ tempDirectory,
96896
+ configSubdirectories: [...configSubdirectories]
96897
+ }).catch((error) => {
96898
+ NFS.rmSync(tempDirectory, {
96899
+ recursive: true,
96900
+ force: true
96901
+ });
96902
+ throw error;
96903
+ });
96904
+ const materializedStagedFiles = new Set(snapshot.stagedFiles);
96905
+ const stagedProjectRuns = stagedProjectScans.map((projectScan) => ({
96906
+ projectScan,
96907
+ includePaths: resolveProjectSourceFilePaths(resolvedDirectory, projectScan.scanDirectory, projectScan.stagedFiles.filter((stagedFile) => materializedStagedFiles.has(stagedFile)))
96908
+ })).filter((projectRun) => projectRun.includePaths.length > 0);
96909
+ const isMultiProject = stagedProjectRuns.length > 1;
96910
+ if (stagedProjectRuns.length === 0) {
96911
+ snapshot.cleanup();
96912
+ reportNothingToScan({
96913
+ 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.`,
96914
+ severity: "warn"
96915
+ });
96916
+ return;
96917
+ }
96918
+ if (snapshot.unmaterializedFiles.length > 0 && !isQuiet) {
96919
+ const stagedFileLabel = `staged file${stagedFileCount === 1 ? "" : "s"}`;
96920
+ cliLogger.warn(`Skipped ${snapshot.unmaterializedFiles.length} of ${stagedFileCount} ${stagedFileLabel}; they could not be snapshotted from the index.`);
96921
+ cliLogger.break();
96922
+ }
96923
+ const scanStagedProject = async (projectRun) => {
96924
+ const { projectScan, includePaths } = projectRun;
96925
+ const projectTempDirectory = Path.join(snapshot.tempDirectory, projectScan.treeRelativeDirectory);
96926
+ const scanResult = await inspect(projectTempDirectory, {
95186
96927
  ...scanOptions,
95187
96928
  deadlineEpochMs: scanDeadlineEpochMs,
95188
- includePaths: snapshot.stagedFiles,
95189
- configOverride: userConfig,
95190
- configSourceDirectory: scanTarget.configSourceDirectory ?? void 0,
95191
- changedLineRanges: stagedLineRanges ?? void 0
96929
+ includePaths: [...includePaths],
96930
+ configOverride: projectScan.projectConfig,
96931
+ configSourceDirectory: projectScan.projectConfigSourceDirectory ?? void 0,
96932
+ changedLineRanges: stagedLineRanges === null ? void 0 : resolveProjectChangedLineRanges(resolvedDirectory, projectScan.scanDirectory, stagedLineRanges),
96933
+ suppressRendering: isMultiProject,
96934
+ concurrentScan: isMultiProject
95192
96935
  });
95193
96936
  const remappedDiagnostics = scanResult.diagnostics.map((diagnostic) => ({
95194
96937
  ...diagnostic,
95195
- filePath: Path.isAbsolute(diagnostic.filePath) ? diagnostic.filePath.replaceAll(snapshot.tempDirectory, () => resolvedDirectory) : diagnostic.filePath
96938
+ filePath: Path.isAbsolute(diagnostic.filePath) ? diagnostic.filePath.replaceAll(projectTempDirectory, () => projectScan.scanDirectory) : diagnostic.filePath
95196
96939
  }));
95197
- finalizeScans({
95198
- completedScans: [{
95199
- directory: resolvedDirectory,
95200
- result: {
95201
- ...scanResult,
95202
- diagnostics: remappedDiagnostics,
95203
- project: {
95204
- ...scanResult.project,
95205
- rootDirectory: resolvedDirectory
95206
- }
95207
- },
95208
- config: userConfig
95209
- }],
95210
- mode: "staged",
95211
- diff: null,
95212
- baselineIntended: false,
95213
- isJsonMode,
95214
- isScoreOnly,
95215
- flags,
95216
- categoryFilters,
95217
- userConfig,
95218
- resolvedDirectory,
95219
- startTime
95220
- });
96940
+ return {
96941
+ directory: projectScan.scanDirectory,
96942
+ result: {
96943
+ ...scanResult,
96944
+ diagnostics: remappedDiagnostics,
96945
+ project: {
96946
+ ...scanResult.project,
96947
+ rootDirectory: projectScan.scanDirectory
96948
+ }
96949
+ },
96950
+ config: projectScan.projectConfig,
96951
+ frameSourceRoot: projectTempDirectory
96952
+ };
96953
+ };
96954
+ const stagedBatch = await runProjectScanBatch({
96955
+ projects: stagedProjectRuns,
96956
+ isQuiet,
96957
+ isSilent: scanOptions.silent === true,
96958
+ scanProject: scanStagedProject
96959
+ }).catch((error) => {
96960
+ snapshot.cleanup();
96961
+ throw error;
96962
+ });
96963
+ const completedScans = stagedBatch.completedScans;
96964
+ try {
96965
+ if (!isQuiet && isMultiProject) {
96966
+ const showShareLink = !isShareOptedOut(completedScans, scanOptions.noScore) && !scanOptions.isCi;
96967
+ await runPromise(printMultiProjectSummary({
96968
+ completedScans,
96969
+ categoryFilters,
96970
+ verbose: Boolean(flags.verbose),
96971
+ outputDirectory: flags.outputDir,
96972
+ isOffline: !showShareLink,
96973
+ projectName: Path.basename(resolvedDirectory),
96974
+ totalElapsedMilliseconds: stagedBatch.elapsedMilliseconds
96975
+ }));
96976
+ }
96977
+ if (flags.outputDir && isMultiProject && isQuiet) await runPromise(printDiagnosticsDump(filterDiagnosticsByCategories(filterScansForSurface(completedScans, scanOptions.outputSurface ?? "cli"), categoryFilters), flags.outputDir, false, "stderr"));
95221
96978
  } finally {
95222
96979
  snapshot.cleanup();
95223
96980
  }
96981
+ finalizeScans({
96982
+ completedScans,
96983
+ mode: "staged",
96984
+ diff: null,
96985
+ baselineIntended: false,
96986
+ isJsonMode,
96987
+ isScoreOnly,
96988
+ flags,
96989
+ categoryFilters,
96990
+ userConfig,
96991
+ resolvedDirectory,
96992
+ startTime
96993
+ });
95224
96994
  return;
95225
96995
  }
95226
96996
  const projectDirectories = await selectProjects(resolvedDirectory, flags.project, skipPrompts, userConfig?.projects);
95227
- const changedFilesDiffInfo = flags.changedFilesFrom ? buildChangedFilesDiffInfo(readChangedFilesFrom(Path.resolve(flags.changedFilesFrom))) : null;
96997
+ const projectSelectionCompletedTime = performance$1.now();
96998
+ let changedFilesDiffInfo = flags.changedFilesFrom ? buildChangedFilesDiffInfo(readChangedFilesFrom(Path.resolve(flags.changedFilesFrom))) : null;
96999
+ if (changedFilesDiffInfo !== null && scanTarget.didRedirectViaRootDir) {
97000
+ const relativeProjectDirectory = resolveProjectRelativeDirectory(requestedDirectory, resolvedDirectory);
97001
+ if (relativeProjectDirectory) {
97002
+ const projectPrefix = `${relativeProjectDirectory}/`;
97003
+ changedFilesDiffInfo = {
97004
+ ...changedFilesDiffInfo,
97005
+ changedFiles: changedFilesDiffInfo.changedFiles.flatMap((filePath) => {
97006
+ return filePath.startsWith(projectPrefix) ? [filePath.slice(projectPrefix.length)] : [];
97007
+ })
97008
+ };
97009
+ }
97010
+ }
95228
97011
  const requestedScope = resolveScope(flags, userConfig);
95229
97012
  const includeUntracked = flags.includeUntracked ?? false;
95230
97013
  const scopeRequest = requestedScope.scope === void 0 && changedFilesDiffInfo !== null ? {
@@ -95232,15 +97015,20 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
95232
97015
  scope: "changed"
95233
97016
  } : requestedScope;
95234
97017
  validateIncludeUntrackedScope(includeUntracked, scopeRequest.scope);
97018
+ scanStartupSpinner = !isQuiet ? spinner("Scanning...").start() : null;
97019
+ if (scanStartupSpinner !== null) recordDistribution(METRIC.scanFeedbackDelay, performance$1.now() - projectSelectionCompletedTime, { unit: "millisecond" });
95235
97020
  const wantsDiffMode = scopeRequest.scope !== void 0 && scopeRequest.scope !== "full";
95236
97021
  const shouldDetectDiff = changedFilesDiffInfo === null && (wantsDiffMode || scopeRequest.scope === void 0 && !skipPrompts && !isQuiet);
95237
97022
  const diffInfo = changedFilesDiffInfo ?? (shouldDetectDiff ? await getDiffInfo(resolvedDirectory, scopeRequest.base, includeUntracked) : null);
97023
+ scanStartupSpinner?.stop();
97024
+ scanStartupSpinner = null;
95238
97025
  const scope = await finalizeScope({
95239
97026
  requested: scopeRequest,
95240
97027
  diffInfo,
95241
97028
  skipPrompts,
95242
97029
  isQuiet
95243
97030
  });
97031
+ scanStartupSpinner = !isQuiet ? spinner("Scanning...").start() : null;
95244
97032
  const isDiffMode = scope !== "full";
95245
97033
  const comparisonBaseRef = isDiffMode && diffInfo && !diffInfo.isCurrentChanges ? diffInfo.baseSha ? await resolveMergeBaseRef(resolvedDirectory, diffInfo.baseSha) : diffInfo.diffBaseRef ?? await resolveMergeBaseRef(resolvedDirectory, diffInfo.baseBranch) : null;
95246
97034
  const baselineRef = scope === "changed" ? comparisonBaseRef : null;
@@ -95252,6 +97040,8 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
95252
97040
  files: [...diffInfo.changedFiles],
95253
97041
  includeUntracked
95254
97042
  }) : null;
97043
+ scanStartupSpinner?.stop();
97044
+ scanStartupSpinner = null;
95255
97045
  if (scope === "lines" && changedLineRanges === null && !isQuiet) {
95256
97046
  cliLogger.warn("Could not determine changed lines (no base ref or git diff failed); reporting all issues in changed files.");
95257
97047
  cliLogger.break();
@@ -95265,7 +97055,6 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
95265
97055
  }
95266
97056
  cliLogger.break();
95267
97057
  }
95268
- const completedScans = [];
95269
97058
  const isMultiProject = projectDirectories.length > 1;
95270
97059
  const scanProject = async (projectDirectory) => {
95271
97060
  const projectScanTarget = projectDirectory === resolvedDirectory ? scanTarget : await resolveScanTarget(projectDirectory, { allowAmbiguous: true });
@@ -95316,29 +97105,13 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
95316
97105
  config: projectConfig
95317
97106
  };
95318
97107
  };
95319
- const scanLoopStartTime = performance$1.now();
95320
- const projectCount = projectDirectories.length;
95321
- const batchSpinner = isMultiProject && !isQuiet ? spinner(`Scanning ${projectCount} projects…`).start() : null;
95322
- const ownsBatchSpinnerSilence = isMultiProject && scanOptions.silent === true;
95323
- const wasSpinnerSilent = isSpinnerSilent();
95324
- if (ownsBatchSpinnerSilence) setSpinnerSilent(true);
95325
- let finishedProjectCount = 0;
95326
- let scanOutcomes;
95327
- try {
95328
- scanOutcomes = await mapWithConcurrency(projectDirectories, isMultiProject ? 4 : 1, async (projectDirectory) => {
95329
- const scanOutcome = await scanProject(projectDirectory);
95330
- finishedProjectCount += 1;
95331
- batchSpinner?.update(`Scanning ${projectCount} projects… (${finishedProjectCount}/${projectCount})`);
95332
- return scanOutcome;
95333
- });
95334
- } finally {
95335
- if (ownsBatchSpinnerSilence) setSpinnerSilent(wasSpinnerSilent);
95336
- batchSpinner?.stop();
95337
- }
95338
- for (const scanOutcome of scanOutcomes) {
95339
- if (scanOutcome === null) continue;
95340
- completedScans.push(scanOutcome);
95341
- }
97108
+ const projectBatch = await runProjectScanBatch({
97109
+ projects: projectDirectories,
97110
+ isQuiet,
97111
+ isSilent: scanOptions.silent === true,
97112
+ scanProject
97113
+ });
97114
+ const completedScans = projectBatch.completedScans;
95342
97115
  if (!isQuiet && isMultiProject && completedScans.length > 0) {
95343
97116
  const showShareLink = !isShareOptedOut(completedScans, scanOptions.noScore) && !scanOptions.isCi;
95344
97117
  await runPromise(printMultiProjectSummary({
@@ -95348,7 +97121,7 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
95348
97121
  outputDirectory: flags.outputDir,
95349
97122
  isOffline: !showShareLink,
95350
97123
  projectName: Path.basename(resolvedDirectory),
95351
- totalElapsedMilliseconds: performance$1.now() - scanLoopStartTime
97124
+ totalElapsedMilliseconds: projectBatch.elapsedMilliseconds
95352
97125
  }));
95353
97126
  }
95354
97127
  const selectedSurfaceDiagnostics = filterDiagnosticsByCategories(filterScansForSurface(completedScans, scanOptions.outputSurface ?? "cli"), categoryFilters);
@@ -95395,6 +97168,7 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
95395
97168
  }
95396
97169
  }
95397
97170
  } catch (error) {
97171
+ scanStartupSpinner?.stop();
95398
97172
  const isUserError = isExpectedUserError(error);
95399
97173
  const sentryEventId = isUserError ? void 0 : await reportErrorToSentry(error);
95400
97174
  if (isDebugFlagEnabled()) await flushSentry();
@@ -96329,6 +98103,7 @@ const COMMAND_FLAG_SPECS = new Map([
96329
98103
  "--no-color",
96330
98104
  "--no-dead-code",
96331
98105
  "--no-score",
98106
+ "--no-supply-chain",
96332
98107
  "--yes"
96333
98108
  ]),
96334
98109
  longOptionsWithRequiredValues: new Set(["--blocking", "--project"]),
@@ -96492,7 +98267,7 @@ ${highlighter.dim("Learn more:")}
96492
98267
  ${highlighter.info(CI_URL)}
96493
98268
  `;
96494
98269
  const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
96495
- 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 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);
98270
+ 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);
96496
98271
  program.action(inspectAction);
96497
98272
  program.command("design [directory]").description("Run only the focused UI design diagnostics").addHelpText("after", renderDesignHelpEpilog).action((directory, _options, command) => designAction(directory ?? ".", command.optsWithGlobals()));
96498
98273
  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));
@@ -96514,15 +98289,17 @@ rules.command("category <category> <severity>").description("Set the severity fo
96514
98289
  rules.command("ignore-tag <tag>").description("Skip a whole rule family by tag before linting (e.g. design)").option("-c, --cwd <cwd>", "working directory", process.cwd()).action((tag, _options, command) => rulesIgnoreTagAction(tag, command.optsWithGlobals()));
96515
98290
  rules.command("unignore-tag <tag>").description("Stop ignoring a tag previously skipped via ignore-tag").option("-c, --cwd <cwd>", "working directory", process.cwd()).action((tag, _options, command) => rulesUnignoreTagAction(tag, command.optsWithGlobals()));
96516
98291
  program.command("experimental-lsp", { hidden: false }).description("[experimental] run the React Doctor language server over stdio (for editors)").allowUnknownOption().action(() => {});
96517
- program.command("experimental-tui [directory]", { hidden: true }).description("[experimental] interactive, scrollable scan report").option("--blocking <level>", "severity that fails CI: error (default), warning, or none (advisory)").option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").option("--no-dead-code", "skip dead-code analysis").option("--no-score", "skip the score API, the share URL, and crash reporting").option("-p, --project <names>", "scan specific workspace projects (comma-separated, or *)").option("-y, --yes", "skip the project prompt and scan every discovered project").action(async (directory = ".", _localOptions, command) => {
98292
+ program.command("experimental-tui [directory]", { hidden: true }).description("[experimental] interactive, scrollable scan report").option("--blocking <level>", "severity that fails CI: error (default), warning, or none (advisory)").option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").option("--no-dead-code", "skip dead-code analysis").option("--no-supply-chain", "skip the dependency supply-chain scan").option("--no-score", "skip the score API, the share URL, and crash reporting").option("-p, --project <names>", "scan specific workspace projects (comma-separated, or *)").option("-y, --yes", "skip the project prompt and scan every discovered project").action(async (directory = ".", _localOptions, command) => {
96518
98293
  const options = command.optsWithGlobals();
96519
98294
  const deadCode = options.deadCode === false ? false : void 0;
96520
98295
  const noScore = options.score === false ? true : void 0;
98296
+ const supplyChain = options.supplyChain === false ? false : void 0;
96521
98297
  const nodeMajorVersion = Number(process.versions.node.split(".")[0]);
96522
98298
  if (process.stdout.isTTY !== true || process.stdin.isTTY !== true || isNonInteractiveEnvironment() || nodeMajorVersion < 22) {
96523
98299
  await inspectAction(directory, {
96524
98300
  deadCode,
96525
98301
  score: options.score === false ? false : void 0,
98302
+ supplyChain,
96526
98303
  project: options.project,
96527
98304
  yes: options.yes,
96528
98305
  blocking: options.blocking
@@ -96530,12 +98307,13 @@ program.command("experimental-tui [directory]", { hidden: true }).description("[
96530
98307
  return;
96531
98308
  }
96532
98309
  recordCount(METRIC.cliInvoked, 1, { command: "experimental-tui" });
96533
- const { runScanApp } = await import("./run-scan-app-DZ5jGWFf.js");
98310
+ const { runScanApp } = await import("./run-scan-app-C9MJnVwv.js");
96534
98311
  const { shouldFail } = await runScanApp({
96535
98312
  directory,
96536
98313
  options: {
96537
98314
  deadCode,
96538
- noScore
98315
+ noScore,
98316
+ supplyChain
96539
98317
  },
96540
98318
  projectFlag: options.project,
96541
98319
  skipPrompts: options.yes ?? false,
@@ -96569,7 +98347,7 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
96569
98347
  handleError(error, { sentryEventId });
96570
98348
  });
96571
98349
  //#endregion
96572
- export { toForwardSlashes as A, highlighter as B, buildRulePriorityMap as C, resolveBlockingLevel as D, formatLearnMoreLine as E, isCiEnvironment as F, sync as G, mergeReactDoctorConfigs as H, DIAGNOSTIC_CATEGORY_BUCKETS as I, void_ as K, Progress as L, isUnicodeSupported as M, METRIC as N, isReactDoctorWorkflowInstalled as O, TUI_REPORT_DETAIL_WIDTH_FRACTION as P, Reporter as R, hasLintHardFailure as S, formatFixRecipeLine as T, resolveScanTarget as U, mapWithConcurrency as V, runPromise 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, succeed$3 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, getCategoryImpact as z };
98350
+ 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 };
96573
98351
 
96574
98352
  //# sourceMappingURL=cli.js.map
96575
- //# debugId=b226693e-22a9-5a5c-8c9f-2679545b582a
98353
+ //# debugId=bb982094-8280-5afe-b061-eb103665c55c