auto-mode 3.0.0 → 3.1.0

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.
@@ -1,15 +1,13 @@
1
- import { t as findEditFields } from "./find-edit-fields-CzkhPA4j.js";
2
- import { basename, relative, sep } from "node:path";
3
1
  import { Buffer } from "node:buffer";
4
- //#region node_modules/.bun/re2js@2.8.6/node_modules/re2js/build/index.js
2
+ //#region node_modules/.bun/re2js@2.8.8/node_modules/re2js/build/index.js
5
3
  /*!
6
4
  * re2js
7
5
  * RE2JS is the JavaScript port of RE2, a regular expression engine that provides linear time matching
8
6
  *
9
- * @version v2.8.6
7
+ * @version v2.8.8
10
8
  * @author Oleksii Vasyliev
11
9
  * @homepage https://github.com/le0pard/re2js#readme
12
- * @repository github:le0pard/re2js
10
+ * @repository [object Object]
13
11
  * @license MIT
14
12
  */
15
13
  var RE2Flags = class RE2Flags {
@@ -492,6 +490,10 @@ var UnicodeTables = class {
492
490
  */
493
491
  var Unicode = class Unicode {
494
492
  static MAX_RUNE = 1114111;
493
+ static RUNE_ERROR = 65533;
494
+ static isUnsearchable(r) {
495
+ return r === Unicode.RUNE_ERROR || r >= Unicode.MIN_HIGH_SURROGATE && r <= Unicode.MAX_LOW_SURROGATE;
496
+ }
495
497
  static MAX_ASCII = 127;
496
498
  static MAX_LATIN1 = 255;
497
499
  static MAX_BMP = 65535;
@@ -544,9 +546,11 @@ var Unicode = class Unicode {
544
546
  }
545
547
  static simpleFold(r) {
546
548
  if (UnicodeTables.CASE_ORBIT.has(r)) return UnicodeTables.CASE_ORBIT.get(r);
547
- const l = Codepoint.toLowerCase(r);
548
- if (l !== r) return l;
549
- return Codepoint.toUpperCase(r);
549
+ if (r <= Unicode.MAX_ASCII) {
550
+ const l = Codepoint.toLowerCase(r);
551
+ return l !== r ? l : Codepoint.toUpperCase(r);
552
+ }
553
+ return r;
550
554
  }
551
555
  static equalsIgnoreCase(r1, r2) {
552
556
  if (r1 === r2) return true;
@@ -592,7 +596,7 @@ var Utils = class Utils {
592
596
  return [];
593
597
  }
594
598
  static isByteArray(input) {
595
- return Array.isArray(input) || input instanceof Uint8Array;
599
+ return Array.isArray(input) || Object.prototype.toString.call(input) === "[object Uint8Array]";
596
600
  }
597
601
  static isalnum(c) {
598
602
  return Codepoint.CODES.get("0") <= c && c <= Codepoint.CODES.get("9") || Codepoint.CODES.get("a") <= c && c <= Codepoint.CODES.get("z") || Codepoint.CODES.get("A") <= c && c <= Codepoint.CODES.get("Z");
@@ -651,7 +655,7 @@ var Utils = class Utils {
651
655
  runes.push(cp);
652
656
  i += cp > Unicode.MAX_BMP ? 2 : 1;
653
657
  }
654
- return runes;
658
+ return new Int32Array(runes);
655
659
  }
656
660
  static runeToString(r) {
657
661
  return String.fromCodePoint(r);
@@ -774,7 +778,7 @@ var MatcherInputBase = class MatcherInputBase {
774
778
  asCharSequence() {
775
779
  throw Error("not implemented");
776
780
  }
777
- /** @returns {Uint8Array|number[]} */
781
+ /** @returns {Uint8Array|number[]|null} */
778
782
  asBytes() {
779
783
  throw Error("not implemented");
780
784
  }
@@ -903,7 +907,8 @@ var MachineInputBase = class {
903
907
  return 0;
904
908
  }
905
909
  };
906
- var MachineUTF8Input = class extends MachineInputBase {
910
+ var MachineUTF8Input = class MachineUTF8Input extends MachineInputBase {
911
+ static RUNE_ERROR_STEP = Unicode.RUNE_ERROR << 3 | 1;
907
912
  constructor(bytes, start = 0, end = bytes.length) {
908
913
  super();
909
914
  this.bytes = bytes;
@@ -917,33 +922,46 @@ var MachineUTF8Input = class extends MachineInputBase {
917
922
  return idx !== -1 && idx <= this.end - target.length;
918
923
  }
919
924
  hasAnyString(prefilter, pos) {
920
- if (!prefilter.ac8) return false;
921
- return prefilter.ac8.searchUTF8(this.bytes, this.start + pos, this.end);
925
+ return prefilter.automaton8().searchUTF8(this.bytes, this.start + pos, this.end);
922
926
  }
923
927
  step(pos) {
924
928
  pos += this.start;
925
929
  if (pos >= this.end) return MachineInputBase.EOF();
926
930
  const c = this.bytes[pos] & 255;
927
931
  if (c < 128) return c << 3 | 1;
928
- else if (c >= 194 && c <= 223 && pos + 1 < this.end) {
929
- const c1 = this.bytes[pos + 1] & 255;
930
- if ((c1 & 192) !== 128) return c << 3 | 1;
931
- return ((c & 31) << 6 | c1 & 63) << 3 | 2;
932
- } else if (c >= 224 && c <= 239 && pos + 2 < this.end) {
933
- const c1 = this.bytes[pos + 1] & 255;
934
- if ((c1 & 192) !== 128) return c << 3 | 1;
932
+ let size;
933
+ let rune;
934
+ let lo = 128;
935
+ let hi = 191;
936
+ if (c >= 194 && c <= 223) {
937
+ size = 2;
938
+ rune = c & 31;
939
+ } else if (c >= 224 && c <= 239) {
940
+ size = 3;
941
+ rune = c & 15;
942
+ if (c === 224) lo = 160;
943
+ else if (c === 237) hi = 159;
944
+ } else if (c >= 240 && c <= 244) {
945
+ size = 4;
946
+ rune = c & 7;
947
+ if (c === 240) lo = 144;
948
+ else if (c === 244) hi = 143;
949
+ } else return MachineUTF8Input.RUNE_ERROR_STEP;
950
+ if (pos + size > this.end) return MachineUTF8Input.RUNE_ERROR_STEP;
951
+ const c1 = this.bytes[pos + 1] & 255;
952
+ if (c1 < lo || c1 > hi) return MachineUTF8Input.RUNE_ERROR_STEP;
953
+ rune = rune << 6 | c1 & 63;
954
+ if (size > 2) {
935
955
  const c2 = this.bytes[pos + 2] & 255;
936
- if ((c2 & 192) !== 128) return c << 3 | 1;
937
- return ((c & 15) << 12 | (c1 & 63) << 6 | c2 & 63) << 3 | 3;
938
- } else if (c >= 240 && c <= 244 && pos + 3 < this.end) {
939
- const c1 = this.bytes[pos + 1] & 255;
940
- if ((c1 & 192) !== 128) return c << 3 | 1;
941
- const c2 = this.bytes[pos + 2] & 255;
942
- if ((c2 & 192) !== 128) return c << 3 | 1;
943
- const c3 = this.bytes[pos + 3] & 255;
944
- if ((c3 & 192) !== 128) return c << 3 | 1;
945
- return ((c & 7) << 18 | (c1 & 63) << 12 | (c2 & 63) << 6 | c3 & 63) << 3 | 4;
946
- } else return c << 3 | 1;
956
+ if ((c2 & 192) !== 128) return MachineUTF8Input.RUNE_ERROR_STEP;
957
+ rune = rune << 6 | c2 & 63;
958
+ if (size > 3) {
959
+ const c3 = this.bytes[pos + 3] & 255;
960
+ if ((c3 & 192) !== 128) return MachineUTF8Input.RUNE_ERROR_STEP;
961
+ rune = rune << 6 | c3 & 63;
962
+ }
963
+ }
964
+ return rune << 3 | size;
947
965
  }
948
966
  index(re2, pos) {
949
967
  pos += this.start;
@@ -961,7 +979,8 @@ var MachineUTF8Input = class extends MachineInputBase {
961
979
  if (lim < this.start) lim = this.start;
962
980
  while (start >= lim && (this.bytes[start] & 192) === 128) start--;
963
981
  if (start < this.start) start = this.start;
964
- r1 = this.step(start - this.start) >> 3;
982
+ const r = this.step(start - this.start);
983
+ r1 = start + (r & 7) === pos ? r >> 3 : Unicode.RUNE_ERROR;
965
984
  }
966
985
  }
967
986
  const r2 = pos < this.end ? this.step(pos - this.start) >> 3 : -1;
@@ -1008,8 +1027,7 @@ var MachineUTF16Input = class extends MachineInputBase {
1008
1027
  return idx !== -1 && idx <= this.end - prefilter.str.length;
1009
1028
  }
1010
1029
  hasAnyString(prefilter, pos) {
1011
- if (!prefilter.ac16) return false;
1012
- return prefilter.ac16.searchUTF16(this.charSequence, this.start + pos, this.end);
1030
+ return prefilter.automaton16().searchUTF16(this.charSequence, this.start + pos, this.end);
1013
1031
  }
1014
1032
  step(pos) {
1015
1033
  pos += this.start;
@@ -1198,6 +1216,8 @@ var Matcher = class Matcher {
1198
1216
  this.namedGroups = re2.namedGroups;
1199
1217
  /** @type {number} */
1200
1218
  this.numberOfInstructions = re2.numberOfInstructions();
1219
+ /** @type {import('./Machine.js').LookbehindState|null} */
1220
+ this.lookbehindState = null;
1201
1221
  if (input instanceof MatcherInputBase) this.resetMatcherInput(input);
1202
1222
  else if (Utils.isByteArray(input)) this.resetMatcherInput(MatcherInput.utf8(input));
1203
1223
  else this.resetMatcherInput(MatcherInput.utf16(input));
@@ -1231,9 +1251,13 @@ var Matcher = class Matcher {
1231
1251
  */
1232
1252
  resetMatcherInput(input) {
1233
1253
  if (input === null) throw new Error("input is null");
1234
- if (!(input instanceof MatcherInputBase)) if (Utils.isByteArray(input)) input = MatcherInput.utf8(input);
1235
- else input = MatcherInput.utf16(input);
1254
+ if (!(input instanceof MatcherInputBase)) {
1255
+ if (Utils.isByteArray(input)) input = MatcherInput.utf8(input);
1256
+ else input = MatcherInput.utf16(input);
1257
+ }
1236
1258
  this.matcherInput = input;
1259
+ if (this.lookbehindState !== null) this.lookbehindState.reset();
1260
+ else this.lookbehindState = this.patternInput.re2().createLookbehindState();
1237
1261
  this.reset();
1238
1262
  return this;
1239
1263
  }
@@ -1321,11 +1345,11 @@ var Matcher = class Matcher {
1321
1345
  * @private
1322
1346
  */
1323
1347
  loadGroup(group) {
1324
- if (group < 0 || group > this.patternGroupCount) throw new RE2JSGroupException(`Group index out of bounds: ${group}`);
1348
+ if (!Number.isInteger(group) || group < 0 || group > this.patternGroupCount) throw new RE2JSGroupException(`Group index out of bounds: ${group}`);
1325
1349
  if (!this.hasMatch) throw new RE2JSGroupException("perhaps no match attempted");
1326
1350
  if (group === 0 || this.hasGroups) return;
1327
1351
  const end = this.matcherInputLength;
1328
- const res = this.patternInput.re2().matchMachineInput(this.matcherInput, this.groups[0], end, this.anchorFlag, 1 + this.patternGroupCount);
1352
+ const res = this.patternInput.re2().matchMachineInput(this.matcherInput, this.groups[0], end, this.anchorFlag, 1 + this.patternGroupCount, this.lookbehindState);
1329
1353
  if (!res[0]) throw new RE2JSGroupException("inconsistency in matching group data");
1330
1354
  this.groups = res[1];
1331
1355
  this.hasGroups = true;
@@ -1358,7 +1382,7 @@ var Matcher = class Matcher {
1358
1382
  */
1359
1383
  find(start = null) {
1360
1384
  if (start !== null) {
1361
- if (start < 0 || start > this.matcherInputLength) throw new RE2JSGroupException(`start index out of bounds: ${start}`);
1385
+ if (!Number.isInteger(start) || start < 0 || start > this.matcherInputLength) throw new RE2JSGroupException(`start index out of bounds: ${start}`);
1362
1386
  this.reset();
1363
1387
  return this.genMatch(start, 0);
1364
1388
  }
@@ -1381,7 +1405,7 @@ var Matcher = class Matcher {
1381
1405
  * @private
1382
1406
  */
1383
1407
  genMatch(startByte, anchor) {
1384
- const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, 1);
1408
+ const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, 1, this.lookbehindState);
1385
1409
  if (!res[0]) {
1386
1410
  this.hasMatch = false;
1387
1411
  return false;
@@ -1708,7 +1732,8 @@ var Inst = class Inst {
1708
1732
  this.op = op;
1709
1733
  this.out = 0;
1710
1734
  this.arg = 0;
1711
- this.runes = [];
1735
+ /** @type {Int32Array} */
1736
+ this.runes = /* @__PURE__ */ new Int32Array(0);
1712
1737
  /** @type {Uint32Array | number[] | null} */
1713
1738
  this.next = null;
1714
1739
  }
@@ -1795,19 +1820,27 @@ var Inst = class Inst {
1795
1820
  }
1796
1821
  }
1797
1822
  };
1798
- var Queue = class {
1823
+ var Queue = class Queue {
1799
1824
  constructor(numInst) {
1800
1825
  this.sparse = new Int32Array(numInst);
1801
1826
  this.densePcs = new Int32Array(numInst);
1802
1827
  this.denseCaps = null;
1803
1828
  this.size = 0;
1804
1829
  this.ncap = 0;
1830
+ this.mainThreads = 0;
1805
1831
  }
1832
+ static INITIAL_THREADS = 32;
1806
1833
  init(ncap) {
1807
1834
  this.ncap = ncap;
1808
- const needed = this.densePcs.length * ncap;
1835
+ const needed = Math.min(this.densePcs.length, Queue.INITIAL_THREADS) * ncap;
1809
1836
  if (!this.denseCaps || this.denseCaps.length < needed) this.denseCaps = new Int32Array(needed);
1810
1837
  }
1838
+ growCaps(needed) {
1839
+ const limit = this.densePcs.length * this.ncap;
1840
+ const grown = new Int32Array(Math.min(limit, Math.max(needed, 2 * this.denseCaps.length)));
1841
+ grown.set(this.denseCaps);
1842
+ this.denseCaps = grown;
1843
+ }
1811
1844
  contains(pc) {
1812
1845
  const j = this.sparse[pc];
1813
1846
  return j < this.size && this.densePcs[j] === pc;
@@ -1823,6 +1856,7 @@ var Queue = class {
1823
1856
  }
1824
1857
  clear() {
1825
1858
  this.size = 0;
1859
+ this.mainThreads = 0;
1826
1860
  }
1827
1861
  toString() {
1828
1862
  let out = "{";
@@ -1834,6 +1868,18 @@ var Queue = class {
1834
1868
  return out;
1835
1869
  }
1836
1870
  };
1871
+ var LookbehindState = class {
1872
+ constructor(prog) {
1873
+ this.pos = -1;
1874
+ this.pcs = new Int32Array(prog.numInst());
1875
+ this.size = 0;
1876
+ this.lbTable = new Int32Array(prog.numLb + 1);
1877
+ }
1878
+ reset() {
1879
+ this.pos = -1;
1880
+ this.size = 0;
1881
+ }
1882
+ };
1837
1883
  var Machine = class Machine {
1838
1884
  static fromRE2(re2) {
1839
1885
  const m = new Machine();
@@ -1841,19 +1887,18 @@ var Machine = class Machine {
1841
1887
  m.re2 = re2;
1842
1888
  m.q0 = new Queue(m.prog.numInst());
1843
1889
  m.q1 = new Queue(m.prog.numInst());
1890
+ m.addStack = new Int32Array(2 * (m.prog.numInst() + 1));
1844
1891
  m.matched = false;
1845
1892
  m.matchcap = new Int32Array(m.prog.numCap < 2 ? 2 : m.prog.numCap);
1846
1893
  m.ncap = 0;
1847
1894
  return m;
1848
1895
  }
1849
- static fromMachine(machine) {
1850
- return Machine.fromRE2(machine.re2);
1851
- }
1852
1896
  constructor() {
1853
1897
  this.prog = null;
1854
1898
  this.re2 = null;
1855
1899
  this.q0 = null;
1856
1900
  this.q1 = null;
1901
+ this.addStack = null;
1857
1902
  this.matched = false;
1858
1903
  this.matchcap = null;
1859
1904
  this.ncap = 0;
@@ -1874,14 +1919,23 @@ var Machine = class Machine {
1874
1919
  if (this.ncap === 0) return Utils.emptyInts();
1875
1920
  return Utils.toArray(this.matchcap.subarray(0, this.ncap));
1876
1921
  }
1877
- match(input, pos, anchor) {
1922
+ match(input, pos, anchor, lbState = null) {
1878
1923
  const startCond = this.re2.cond;
1879
1924
  if (startCond === Utils.EMPTY_ALL) return false;
1880
1925
  if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) return false;
1881
1926
  this.matched = false;
1882
1927
  this.matchcap.fill(-1);
1883
- let currentPos = this.prog.numLb > 0 ? 0 : pos;
1884
- let matchStartPos = pos;
1928
+ const hasLookbehinds = this.prog.numLb > 0;
1929
+ const matchStartPos = pos;
1930
+ let currentPos = pos;
1931
+ let resumeLookbehinds = false;
1932
+ if (hasLookbehinds) {
1933
+ if (lbState !== null && lbState.pos >= 0 && lbState.pos <= pos) {
1934
+ currentPos = lbState.pos;
1935
+ resumeLookbehinds = true;
1936
+ } else currentPos = 0;
1937
+ }
1938
+ let saveLookbehinds = hasLookbehinds && lbState !== null;
1885
1939
  let runq = this.q0;
1886
1940
  let nextq = this.q1;
1887
1941
  let r = input.step(currentPos);
@@ -1897,12 +1951,16 @@ var Machine = class Machine {
1897
1951
  let flag;
1898
1952
  if (currentPos === 0) flag = Utils.emptyOpContext(-1, rune);
1899
1953
  else flag = input.context(currentPos);
1954
+ if (hasLookbehinds) {
1955
+ if (resumeLookbehinds) this.restoreLookbehinds(lbState, runq, flag);
1956
+ else this.spawnLookbehinds(runq, currentPos, flag);
1957
+ }
1900
1958
  while (true) {
1901
- if (runq.isEmpty()) {
1959
+ if (runq.mainThreads === 0) {
1902
1960
  if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 && currentPos !== 0) break;
1903
1961
  if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && currentPos !== 0) break;
1904
1962
  if (this.matched) break;
1905
- if (this.prog.numLb === 0 && !(this.re2.prefix.length === 0) && rune1 !== this.re2.prefixRune && input.canCheckPrefix()) {
1963
+ if (this.prog.numLb === 0 && runq.isEmpty() && !(this.re2.prefix.length === 0) && rune1 !== this.re2.prefixRune && input.canCheckPrefix()) {
1906
1964
  const advance = input.index(this.re2, currentPos);
1907
1965
  if (advance < 0) break;
1908
1966
  currentPos += advance;
@@ -1915,9 +1973,12 @@ var Machine = class Machine {
1915
1973
  flag = input.context(currentPos);
1916
1974
  }
1917
1975
  }
1918
- if (currentPos === 0 && this.prog.numLb > 0) for (let i = 0; i < this.prog.lbStarts.length; i++) this.add(runq, this.prog.lbStarts[i], currentPos, this.matchcap, 0, flag);
1919
- if (!this.matched && (currentPos === 0 || anchor === RE2Flags.UNANCHORED)) {
1920
- if (currentPos >= matchStartPos) {
1976
+ if (currentPos >= matchStartPos) {
1977
+ if (saveLookbehinds) {
1978
+ this.saveLookbehinds(lbState, runq, currentPos);
1979
+ saveLookbehinds = false;
1980
+ }
1981
+ if (!this.matched && (currentPos === 0 || anchor === RE2Flags.UNANCHORED)) {
1921
1982
  if (this.ncap > 0) this.matchcap[0] = currentPos;
1922
1983
  this.add(runq, this.prog.start, currentPos, this.matchcap, 0, flag);
1923
1984
  }
@@ -1939,6 +2000,7 @@ var Machine = class Machine {
1939
2000
  runq = nextq;
1940
2001
  nextq = tmpq;
1941
2002
  }
2003
+ runq.clear();
1942
2004
  nextq.clear();
1943
2005
  return this.matched;
1944
2006
  }
@@ -1962,12 +2024,12 @@ var Machine = class Machine {
1962
2024
  }
1963
2025
  let flag = currentPos === 0 ? Utils.emptyOpContext(-1, rune) : input.context(currentPos);
1964
2026
  const matches = /* @__PURE__ */ new Set();
2027
+ if (this.prog.numLb > 0) this.spawnLookbehinds(runq, currentPos, flag);
1965
2028
  while (true) {
1966
- if (runq.isEmpty()) {
2029
+ if (runq.mainThreads === 0) {
1967
2030
  if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 && currentPos !== 0) break;
1968
2031
  if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && currentPos !== 0) break;
1969
2032
  }
1970
- if (currentPos === 0 && this.prog.numLb > 0) for (let i = 0; i < this.prog.lbStarts.length; i++) this.add(runq, this.prog.lbStarts[i], currentPos, this.matchcap, 0, flag);
1971
2033
  if (currentPos === 0 || anchor === RE2Flags.UNANCHORED) {
1972
2034
  if (currentPos >= matchStartPos) this.add(runq, this.prog.start, currentPos, this.matchcap, 0, flag);
1973
2035
  }
@@ -2052,74 +2114,100 @@ var Machine = class Machine {
2052
2114
  }
2053
2115
  runq.clear();
2054
2116
  }
2117
+ spawnLookbehinds(q, pos, flag) {
2118
+ for (let i = 0; i < this.prog.lbStarts.length; i++) this.add(q, this.prog.lbStarts[i], pos, this.matchcap, 0, flag);
2119
+ }
2120
+ restoreLookbehinds(lbState, q, flag) {
2121
+ this.lbTable.set(lbState.lbTable);
2122
+ for (let j = 0; j < lbState.size; j++) this.add(q, lbState.pcs[j], lbState.pos, this.matchcap, 0, flag);
2123
+ }
2124
+ saveLookbehinds(lbState, q, pos) {
2125
+ let size = 0;
2126
+ for (let j = 0; j < q.size; j++) {
2127
+ const pc = q.densePcs[j];
2128
+ if (this.prog.lbInst[pc] === 1 && Inst.isRuneOp(this.prog.inst[pc].op)) lbState.pcs[size++] = pc;
2129
+ }
2130
+ lbState.size = size;
2131
+ lbState.pos = pos;
2132
+ lbState.lbTable.set(this.lbTable);
2133
+ }
2055
2134
  add(q, pc, pos, capArray, capOffset, cond) {
2056
- while (true) {
2057
- if (pc === 0) return;
2058
- if (q.contains(pc)) return;
2059
- const d = q.add(pc);
2060
- const inst = this.prog.inst[pc];
2061
- switch (inst.op) {
2062
- case Inst.FAIL: return;
2063
- case Inst.ALT:
2064
- case Inst.ALT_MATCH:
2065
- this.add(q, inst.out, pos, capArray, capOffset, cond);
2066
- pc = inst.arg;
2067
- continue;
2068
- case Inst.EMPTY_WIDTH:
2069
- if ((inst.arg & ~cond) === 0) {
2135
+ const stk = this.addStack;
2136
+ let nstk = 0;
2137
+ for (;;) {
2138
+ while (pc !== 0 && !q.contains(pc)) {
2139
+ const d = q.add(pc);
2140
+ const inst = this.prog.inst[pc];
2141
+ switch (inst.op) {
2142
+ case Inst.FAIL:
2143
+ pc = 0;
2144
+ break;
2145
+ case Inst.ALT:
2146
+ case Inst.ALT_MATCH:
2147
+ stk[nstk++] = inst.arg;
2148
+ stk[nstk++] = 0;
2070
2149
  pc = inst.out;
2071
- continue;
2072
- }
2073
- return;
2074
- case Inst.NOP:
2075
- pc = inst.out;
2076
- continue;
2077
- case Inst.CAPTURE: if (inst.arg < this.ncap) {
2078
- const opos = capArray[capOffset + inst.arg];
2079
- capArray[capOffset + inst.arg] = pos;
2080
- this.add(q, inst.out, pos, capArray, capOffset, cond);
2081
- capArray[capOffset + inst.arg] = opos;
2082
- return;
2083
- } else {
2084
- pc = inst.out;
2085
- continue;
2086
- }
2087
- case Inst.LB_WRITE:
2088
- this.lbTable[Math.abs(inst.arg)] = pos;
2089
- pc = inst.out;
2090
- continue;
2091
- case Inst.LB_CHECK:
2092
- if (inst.arg > 0) {
2093
- if (this.lbTable[inst.arg] === pos) {
2094
- pc = inst.out;
2095
- continue;
2150
+ break;
2151
+ case Inst.EMPTY_WIDTH:
2152
+ pc = (inst.arg & ~cond) === 0 ? inst.out : 0;
2153
+ break;
2154
+ case Inst.NOP:
2155
+ pc = inst.out;
2156
+ break;
2157
+ case Inst.CAPTURE:
2158
+ if (inst.arg < this.ncap) {
2159
+ stk[nstk++] = -inst.arg - 1;
2160
+ stk[nstk++] = capArray[capOffset + inst.arg];
2161
+ capArray[capOffset + inst.arg] = pos;
2096
2162
  }
2097
- } else if (this.lbTable[-inst.arg] !== pos) {
2098
2163
  pc = inst.out;
2099
- continue;
2100
- }
2101
- return;
2102
- case Inst.MATCH:
2103
- case Inst.RUNE:
2104
- case Inst.RUNE1:
2105
- case Inst.RUNE_ANY:
2106
- case Inst.RUNE_ANY_NOT_NL:
2107
- if (this.ncap > 0) {
2108
- const destOffset = d * this.ncap;
2109
- for (let c = 0; c < this.ncap; c++) q.denseCaps[destOffset + c] = capArray[capOffset + c];
2110
- }
2111
- return;
2112
- default: throw new RE2JSInternalException("unhandled");
2164
+ break;
2165
+ case Inst.LB_WRITE:
2166
+ this.lbTable[Math.abs(inst.arg)] = pos;
2167
+ pc = inst.out;
2168
+ break;
2169
+ case Inst.LB_CHECK:
2170
+ if (inst.arg > 0) pc = this.lbTable[inst.arg] === pos ? inst.out : 0;
2171
+ else pc = this.lbTable[-inst.arg] !== pos ? inst.out : 0;
2172
+ break;
2173
+ case Inst.MATCH:
2174
+ case Inst.RUNE:
2175
+ case Inst.RUNE1:
2176
+ case Inst.RUNE_ANY:
2177
+ case Inst.RUNE_ANY_NOT_NL:
2178
+ if (this.prog.lbInst[pc] === 0) q.mainThreads++;
2179
+ if (this.ncap > 0) {
2180
+ const destOffset = d * this.ncap;
2181
+ if (destOffset + this.ncap > q.denseCaps.length) q.growCaps(destOffset + this.ncap);
2182
+ for (let c = 0; c < this.ncap; c++) q.denseCaps[destOffset + c] = capArray[capOffset + c];
2183
+ }
2184
+ pc = 0;
2185
+ break;
2186
+ default: throw new RE2JSInternalException("unhandled");
2187
+ }
2113
2188
  }
2189
+ if (nstk === 0) return;
2190
+ nstk -= 2;
2191
+ const entry = stk[nstk];
2192
+ if (entry < 0) {
2193
+ capArray[capOffset - entry - 1] = stk[nstk + 1];
2194
+ pc = 0;
2195
+ } else pc = entry;
2114
2196
  }
2115
2197
  }
2116
2198
  };
2117
- const hashPCs = (pcs) => {
2199
+ const hashState = (pcs, flag, ids) => {
2118
2200
  let h = -2128831035;
2119
2201
  for (let i = 0; i < pcs.length; i++) {
2120
2202
  h ^= pcs[i];
2121
2203
  h = Math.imul(h, 16777619);
2122
2204
  }
2205
+ h ^= flag;
2206
+ h = Math.imul(h, 16777619);
2207
+ for (let i = 0; i < ids.length; i++) {
2208
+ h ^= ids[i];
2209
+ h = Math.imul(h, 16777619);
2210
+ }
2123
2211
  return h;
2124
2212
  };
2125
2213
  const arraysEqual = (a, b) => {
@@ -2127,46 +2215,105 @@ const arraysEqual = (a, b) => {
2127
2215
  for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
2128
2216
  return true;
2129
2217
  };
2218
+ const NO_IDS = [];
2219
+ const END_TEXT = -1;
2130
2220
  var DFAState = class {
2131
- constructor(nfaStates, isMatch, matchIDs = []) {
2221
+ constructor(nfaStates, flag, matchIDs) {
2132
2222
  this.nfaStates = nfaStates;
2133
- this.isMatch = isMatch;
2223
+ this.flag = flag;
2224
+ this.isMatch = (flag & DFA.FLAG_MATCH) !== 0;
2134
2225
  this.matchIDs = matchIDs;
2135
- this.nextLatin1 = new Array(Unicode.MAX_LATIN1 + 1).fill(null);
2136
- this.nextLatin1Anchored = new Array(Unicode.MAX_LATIN1 + 1).fill(null);
2137
- this.transKeys = [];
2138
- this.transVals = [];
2139
- this.lastSeen = 0;
2226
+ this.next = null;
2227
+ this.nextAnchored = null;
2140
2228
  }
2141
2229
  };
2142
2230
  var DFA = class DFA {
2143
- static MAX_CACHE_CLEARS = 5;
2144
- static STATE_MEMORY_ESTIMATE = 838;
2231
+ static FLAG_EMPTY_MASK = 255;
2232
+ static FLAG_MATCH = 256;
2233
+ static FLAG_LAST_WORD = 512;
2234
+ static FLAG_NEED_SHIFT = 16;
2235
+ static STATE_OVERHEAD = 160;
2236
+ static TABLE_OVERHEAD = 16;
2237
+ static PROGRESS_PER_STATE = 10;
2145
2238
  constructor(prog, maxMem = 8388608) {
2146
2239
  this.prog = prog;
2240
+ this.maxMem = maxMem;
2147
2241
  this.stateCache = /* @__PURE__ */ new Map();
2148
2242
  this.stateCount = 0;
2149
- this.startState = null;
2150
- this.stateLimit = Math.max(1, Math.floor(maxMem / DFA.STATE_MEMORY_ESTIMATE));
2151
- this.cacheClears = 0;
2243
+ this.startStates = /* @__PURE__ */ new Map();
2152
2244
  this.failed = false;
2153
- this.clock = 0;
2245
+ for (let pc = 0; pc < prog.numInst(); pc++) {
2246
+ const op = prog.getInst(pc).op;
2247
+ if (op === Inst.LB_WRITE || op === Inst.LB_CHECK) {
2248
+ this.failed = true;
2249
+ break;
2250
+ }
2251
+ }
2252
+ this.computeRuneClasses();
2253
+ this.stateBudget = maxMem;
2254
+ this.memBudget = maxMem;
2255
+ }
2256
+ computeRuneClasses() {
2257
+ const bounds = /* @__PURE__ */ new Set();
2258
+ const addRange = (lo, hi) => {
2259
+ bounds.add(lo);
2260
+ bounds.add(hi + 1);
2261
+ };
2262
+ for (let pc = 0; pc < this.prog.numInst(); pc++) {
2263
+ const inst = this.prog.getInst(pc);
2264
+ switch (inst.op) {
2265
+ case Inst.RUNE:
2266
+ case Inst.RUNE1:
2267
+ if (inst.runes.length === 1) {
2268
+ addRange(inst.runes[0], inst.runes[0]);
2269
+ if ((inst.arg & RE2Flags.FOLD_CASE) !== 0) for (let f = Unicode.simpleFold(inst.runes[0]); f !== inst.runes[0]; f = Unicode.simpleFold(f)) addRange(f, f);
2270
+ } else for (let j = 0; j < inst.runes.length; j += 2) addRange(inst.runes[j], inst.runes[j + 1]);
2271
+ break;
2272
+ case Inst.RUNE_ANY_NOT_NL:
2273
+ addRange(10, 10);
2274
+ break;
2275
+ case Inst.EMPTY_WIDTH:
2276
+ if ((inst.arg & (Utils.EMPTY_BEGIN_LINE | Utils.EMPTY_END_LINE)) !== 0) addRange(10, 10);
2277
+ if ((inst.arg & (Utils.EMPTY_WORD_BOUNDARY | Utils.EMPTY_NO_WORD_BOUNDARY)) !== 0) {
2278
+ addRange(48, 57);
2279
+ addRange(65, 90);
2280
+ addRange(95, 95);
2281
+ addRange(97, 122);
2282
+ }
2283
+ }
2284
+ }
2285
+ bounds.delete(0);
2286
+ this.classBounds = Int32Array.from(bounds).sort();
2287
+ this.numClasses = this.classBounds.length + 1;
2288
+ const latin1Class = new Int32Array(Unicode.MAX_LATIN1 + 1);
2289
+ for (let r = 0; r <= Unicode.MAX_LATIN1; r++) latin1Class[r] = this.searchClass(r);
2290
+ this.latin1Class = latin1Class;
2291
+ }
2292
+ runeClass(r) {
2293
+ if (r <= Unicode.MAX_LATIN1) return this.latin1Class[r];
2294
+ return this.searchClass(r);
2295
+ }
2296
+ searchClass(r) {
2297
+ const bounds = this.classBounds;
2298
+ let lo = 0;
2299
+ let hi = bounds.length;
2300
+ while (lo < hi) {
2301
+ const mid = lo + hi >> 1;
2302
+ if (bounds[mid] <= r) lo = mid + 1;
2303
+ else hi = mid;
2304
+ }
2305
+ return lo;
2154
2306
  }
2155
- computeClosure(pcs) {
2307
+ closure(pcs, flag) {
2156
2308
  const closure = /* @__PURE__ */ new Set();
2157
- const stack = [...pcs];
2158
- let isMatch = false;
2159
- const matchIDs = [];
2309
+ const stack = Array.from(pcs);
2310
+ let needflags = 0;
2160
2311
  while (stack.length > 0) {
2161
2312
  const pc = stack.pop();
2162
- if (closure.has(pc)) continue;
2313
+ if (pc === 0 || closure.has(pc)) continue;
2163
2314
  closure.add(pc);
2164
2315
  const inst = this.prog.getInst(pc);
2165
2316
  switch (inst.op) {
2166
- case Inst.MATCH:
2167
- isMatch = true;
2168
- if (!matchIDs.includes(inst.arg)) matchIDs.push(inst.arg);
2169
- break;
2170
2317
  case Inst.ALT:
2171
2318
  case Inst.ALT_MATCH:
2172
2319
  stack.push(inst.out);
@@ -2177,176 +2324,183 @@ var DFA = class DFA {
2177
2324
  stack.push(inst.out);
2178
2325
  break;
2179
2326
  case Inst.EMPTY_WIDTH:
2180
- case Inst.LB_WRITE:
2181
- case Inst.LB_CHECK: return null;
2327
+ needflags |= inst.arg;
2328
+ if ((inst.arg & ~flag) === 0) stack.push(inst.out);
2182
2329
  }
2183
2330
  }
2184
- const sortedPCs = Int32Array.from(closure).sort();
2185
- matchIDs.sort((a, b) => a - b);
2186
2331
  return {
2187
- pcs: sortedPCs,
2188
- isMatch,
2189
- matchIDs
2332
+ pcs: Int32Array.from(closure).sort(),
2333
+ needflags
2190
2334
  };
2191
2335
  }
2192
- getState(pcs) {
2193
- const closureResult = this.computeClosure(pcs);
2194
- if (!closureResult) return null;
2195
- const sortedPCs = closureResult.pcs;
2196
- const hash = hashPCs(sortedPCs);
2336
+ getState(pcs, flag, ids) {
2337
+ const hash = hashState(pcs, flag, ids);
2197
2338
  let bucket = this.stateCache.get(hash);
2198
2339
  if (bucket) for (let i = 0; i < bucket.length; i++) {
2199
2340
  const state = bucket[i];
2200
- if (arraysEqual(state.nfaStates, sortedPCs)) {
2201
- state.lastSeen = ++this.clock;
2202
- return state;
2203
- }
2341
+ if (state.flag === flag && arraysEqual(state.nfaStates, pcs) && arraysEqual(state.matchIDs, ids)) return state;
2204
2342
  }
2205
- else {
2343
+ const cost = DFA.STATE_OVERHEAD + 4 * pcs.length + 8 * ids.length;
2344
+ if (this.memBudget < cost) return null;
2345
+ this.memBudget -= cost;
2346
+ if (!bucket) {
2206
2347
  bucket = [];
2207
2348
  this.stateCache.set(hash, bucket);
2208
2349
  }
2209
- if (this.failed) return null;
2210
- if (this.stateCount >= this.stateLimit) {
2211
- this.cacheClears++;
2212
- if (this.cacheClears >= DFA.MAX_CACHE_CLEARS) {
2213
- this.failed = true;
2214
- this.stateCache.clear();
2215
- this.stateCount = 0;
2216
- this.startState = null;
2217
- return null;
2218
- }
2219
- this.evictCache();
2220
- bucket = this.stateCache.get(hash);
2221
- if (!bucket) {
2222
- bucket = [];
2223
- this.stateCache.set(hash, bucket);
2224
- }
2225
- }
2226
- const state = new DFAState(sortedPCs, closureResult.isMatch, closureResult.matchIDs);
2227
- state.lastSeen = ++this.clock;
2350
+ const state = new DFAState(pcs, flag, ids);
2228
2351
  bucket.push(state);
2229
2352
  this.stateCount++;
2230
2353
  return state;
2231
2354
  }
2232
- evictCache() {
2233
- const allStates = [];
2234
- for (const bucket of this.stateCache.values()) for (let i = 0; i < bucket.length; i++) allStates.push(bucket[i]);
2235
- allStates.sort((a, b) => a.lastSeen - b.lastSeen);
2236
- const keepCount = Math.max(1, Math.floor(this.stateLimit / 2));
2237
- const startIndex = allStates.length - keepCount;
2238
- const survivorsArray = allStates.slice(startIndex);
2239
- const survivors = new Set(survivorsArray);
2355
+ makeState(pcs, flag, ids) {
2356
+ const closure = this.closure(pcs, flag & DFA.FLAG_EMPTY_MASK);
2357
+ let stateFlag = flag;
2358
+ if (closure.needflags === 0) stateFlag &= DFA.FLAG_MATCH;
2359
+ stateFlag |= closure.needflags << DFA.FLAG_NEED_SHIFT;
2360
+ return this.getState(closure.pcs, stateFlag, ids);
2361
+ }
2362
+ allocTable(state, anchor) {
2363
+ const size = this.numClasses + 1;
2364
+ const cost = DFA.TABLE_OVERHEAD + 8 * size;
2365
+ if (this.memBudget < cost) return null;
2366
+ this.memBudget -= cost;
2367
+ const table = new Array(size).fill(null);
2368
+ if (anchor === RE2Flags.UNANCHORED) state.next = table;
2369
+ else state.nextAnchored = table;
2370
+ return table;
2371
+ }
2372
+ clearCache() {
2240
2373
  this.stateCache.clear();
2241
2374
  this.stateCount = 0;
2242
- for (let i = 0; i < survivorsArray.length; i++) {
2243
- const state = survivorsArray[i];
2244
- state.nextLatin1.fill(null);
2245
- state.nextLatin1Anchored.fill(null);
2246
- state.transKeys.length = 0;
2247
- state.transVals.length = 0;
2248
- const hash = hashPCs(state.nfaStates);
2249
- let bucket = this.stateCache.get(hash);
2250
- if (!bucket) {
2251
- bucket = [];
2252
- this.stateCache.set(hash, bucket);
2253
- }
2254
- bucket.push(state);
2255
- this.stateCount++;
2256
- }
2257
- if (this.startState && !survivors.has(this.startState)) this.startState = null;
2258
- }
2259
- step(state, charCode, anchor) {
2260
- if (charCode <= Unicode.MAX_LATIN1) if (anchor === RE2Flags.UNANCHORED) {
2261
- const next = state.nextLatin1[charCode];
2262
- if (next !== null) return next;
2375
+ this.startStates.clear();
2376
+ this.memBudget = this.stateBudget;
2377
+ }
2378
+ resetCache(current) {
2379
+ this.clearCache();
2380
+ return this.getState(current.nfaStates, current.flag, current.matchIDs);
2381
+ }
2382
+ step(state, cls, rune, anchor) {
2383
+ let table = anchor === RE2Flags.UNANCHORED ? state.next : state.nextAnchored;
2384
+ if (table !== null) {
2385
+ const cached = table[cls];
2386
+ if (cached !== null) return cached;
2263
2387
  } else {
2264
- const next = state.nextLatin1Anchored[charCode];
2265
- if (next !== null) return next;
2388
+ table = this.allocTable(state, anchor);
2389
+ if (table === null) return null;
2266
2390
  }
2267
- else {
2268
- const key = charCode + (anchor === RE2Flags.UNANCHORED ? 0 : Unicode.MAX_RUNE + 1);
2269
- const keys = state.transKeys;
2270
- const len = keys.length;
2271
- for (let i = 0; i < len; i++) if (keys[i] === key) return state.transVals[i];
2391
+ const needflag = state.flag >>> DFA.FLAG_NEED_SHIFT;
2392
+ const oldbeforeflag = state.flag & DFA.FLAG_EMPTY_MASK;
2393
+ let beforeflag = oldbeforeflag;
2394
+ let afterflag = 0;
2395
+ if (rune === 10) {
2396
+ beforeflag |= Utils.EMPTY_END_LINE;
2397
+ afterflag |= Utils.EMPTY_BEGIN_LINE;
2272
2398
  }
2399
+ if (rune === END_TEXT) beforeflag |= Utils.EMPTY_END_LINE | Utils.EMPTY_END_TEXT;
2400
+ const islastword = (state.flag & DFA.FLAG_LAST_WORD) !== 0;
2401
+ const isword = rune !== END_TEXT && Utils.isWordRune(rune);
2402
+ beforeflag |= isword === islastword ? Utils.EMPTY_NO_WORD_BOUNDARY : Utils.EMPTY_WORD_BOUNDARY;
2403
+ let pcs = state.nfaStates;
2404
+ if ((beforeflag & ~oldbeforeflag & needflag) !== 0) pcs = this.closure(pcs, beforeflag).pcs;
2273
2405
  const nextPCs = [];
2274
- for (let i = 0; i < state.nfaStates.length; i++) {
2275
- const pc = state.nfaStates[i];
2276
- const inst = this.prog.getInst(pc);
2277
- if (Inst.isRuneOp(inst.op) && inst.matchRune(charCode)) nextPCs.push(inst.out);
2278
- }
2279
- if (anchor === RE2Flags.UNANCHORED) nextPCs.push(this.prog.start);
2280
- const nextState = this.getState(nextPCs);
2281
- if (charCode <= Unicode.MAX_LATIN1) if (anchor === RE2Flags.UNANCHORED) state.nextLatin1[charCode] = nextState;
2282
- else state.nextLatin1Anchored[charCode] = nextState;
2283
- else {
2284
- const key = charCode + (anchor === RE2Flags.UNANCHORED ? 0 : Unicode.MAX_RUNE + 1);
2285
- state.transKeys.push(key);
2286
- state.transVals.push(nextState);
2406
+ let ismatch = false;
2407
+ let ids = NO_IDS;
2408
+ for (let i = 0; i < pcs.length; i++) {
2409
+ const inst = this.prog.getInst(pcs[i]);
2410
+ if (inst.op === Inst.MATCH) {
2411
+ if (!ismatch) {
2412
+ ismatch = true;
2413
+ ids = [];
2414
+ }
2415
+ ids.push(inst.arg);
2416
+ } else if (rune !== END_TEXT && Inst.isRuneOp(inst.op) && inst.matchRune(rune)) nextPCs.push(inst.out);
2287
2417
  }
2418
+ if (ids.length > 1) ids.sort((a, b) => a - b);
2419
+ if (anchor === RE2Flags.UNANCHORED && rune !== END_TEXT) nextPCs.push(this.prog.start);
2420
+ let flag = afterflag;
2421
+ if (ismatch) flag |= DFA.FLAG_MATCH;
2422
+ if (isword) flag |= DFA.FLAG_LAST_WORD;
2423
+ const nextState = this.makeState(nextPCs, flag, ids);
2424
+ if (nextState === null) return null;
2425
+ table[cls] = nextState;
2288
2426
  return nextState;
2289
2427
  }
2290
- match(input, pos, anchor) {
2291
- if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) return false;
2292
- if (!this.startState) {
2293
- this.startState = this.getState([this.prog.start]);
2294
- if (!this.startState) return null;
2428
+ start(input, pos) {
2429
+ const context = input.context(pos);
2430
+ let flags;
2431
+ if ((context & Utils.EMPTY_BEGIN_TEXT) !== 0) flags = Utils.EMPTY_BEGIN_TEXT | Utils.EMPTY_BEGIN_LINE;
2432
+ else if ((context & Utils.EMPTY_BEGIN_LINE) !== 0) flags = Utils.EMPTY_BEGIN_LINE;
2433
+ else {
2434
+ const r = input.step(pos);
2435
+ const nextIsWord = r >= 0 && Utils.isWordRune(r >> 3);
2436
+ flags = (context & Utils.EMPTY_WORD_BOUNDARY) !== 0 !== nextIsWord ? DFA.FLAG_LAST_WORD : 0;
2295
2437
  }
2296
- let endPos = input.endPos();
2297
- let currentState = this.startState;
2298
- if (currentState.isMatch) if (anchor === RE2Flags.ANCHOR_BOTH) {
2299
- if (pos === endPos) return true;
2300
- } else return true;
2438
+ let state = this.startStates.get(flags);
2439
+ if (state === void 0) {
2440
+ state = this.makeState([this.prog.start], flags, NO_IDS);
2441
+ if (state === null) {
2442
+ this.clearCache();
2443
+ state = this.makeState([this.prog.start], flags, NO_IDS);
2444
+ if (state === null) return null;
2445
+ }
2446
+ this.startStates.set(flags, state);
2447
+ }
2448
+ return state;
2449
+ }
2450
+ stepOrReset(state, cls, rune, anchor, pos, search) {
2451
+ let next = this.step(state, cls, rune, anchor);
2452
+ if (next !== null) return next;
2453
+ if (search.resetPos >= 0 && pos - search.resetPos < DFA.PROGRESS_PER_STATE * this.stateCount) return null;
2454
+ search.resetPos = pos;
2455
+ const restored = this.resetCache(state);
2456
+ if (restored === null) return null;
2457
+ next = this.step(restored, cls, rune, anchor);
2458
+ return next;
2459
+ }
2460
+ run(input, pos, anchor, state, onMatch) {
2461
+ const endPos = input.endPos();
2462
+ const latin1Class = this.latin1Class;
2463
+ const unanchored = anchor === RE2Flags.UNANCHORED;
2464
+ const search = { resetPos: -1 };
2301
2465
  let i = pos;
2302
2466
  while (i < endPos) {
2303
2467
  const r = input.step(i);
2304
2468
  const rune = r >> 3;
2305
2469
  const width = r & 7;
2306
2470
  if (width === 0) break;
2307
- currentState = anchor === RE2Flags.UNANCHORED && rune <= Unicode.MAX_LATIN1 && currentState.nextLatin1[rune] || this.step(currentState, rune, anchor);
2308
- if (currentState === null) return null;
2309
- currentState.lastSeen = ++this.clock;
2310
- if (currentState.isMatch) if (anchor === RE2Flags.ANCHOR_BOTH) {
2311
- if (i + width === endPos) return true;
2312
- } else return true;
2313
- if (currentState.nfaStates.length === 0) {
2314
- if (anchor !== RE2Flags.UNANCHORED) return false;
2471
+ const cls = rune <= Unicode.MAX_LATIN1 ? latin1Class[rune] : this.runeClass(rune);
2472
+ let next = unanchored && state.next !== null ? state.next[cls] : null;
2473
+ if (next === null) {
2474
+ next = this.stepOrReset(state, cls, rune, anchor, i, search);
2475
+ if (next === null) return null;
2315
2476
  }
2477
+ state = next;
2478
+ if (state.isMatch && onMatch(state, false)) return true;
2479
+ if (!unanchored && state.nfaStates.length === 0) return false;
2316
2480
  i += width;
2317
2481
  }
2318
- return false;
2482
+ state = this.stepOrReset(state, this.numClasses, END_TEXT, anchor, i, search);
2483
+ if (state === null) return null;
2484
+ return state.isMatch && onMatch(state, true);
2485
+ }
2486
+ match(input, pos, anchor) {
2487
+ if (this.failed) return null;
2488
+ if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) return false;
2489
+ const startState = this.start(input, pos);
2490
+ if (startState === null) return null;
2491
+ return this.run(input, pos, anchor, startState, (state, atEnd) => anchor !== RE2Flags.ANCHOR_BOTH || atEnd);
2319
2492
  }
2320
2493
  matchSet(input, pos, anchor) {
2494
+ if (this.failed) return null;
2321
2495
  if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) return [];
2322
- if (!this.startState) {
2323
- this.startState = this.getState([this.prog.start]);
2324
- if (!this.startState) return null;
2325
- }
2326
- let endPos = input.endPos();
2327
- let currentState = this.startState;
2496
+ const startState = this.start(input, pos);
2497
+ if (startState === null) return null;
2328
2498
  const matches = /* @__PURE__ */ new Set();
2329
- const checkMatch = (state, currentPos) => {
2330
- if (state.isMatch) if (anchor === RE2Flags.ANCHOR_BOTH) {
2331
- if (currentPos === endPos) state.matchIDs.forEach((id) => matches.add(id));
2332
- } else state.matchIDs.forEach((id) => matches.add(id));
2499
+ const collect = (state, atEnd) => {
2500
+ if (anchor !== RE2Flags.ANCHOR_BOTH || atEnd) for (let k = 0; k < state.matchIDs.length; k++) matches.add(state.matchIDs[k]);
2501
+ return false;
2333
2502
  };
2334
- checkMatch(currentState, pos);
2335
- let i = pos;
2336
- while (i < endPos) {
2337
- const r = input.step(i);
2338
- const rune = r >> 3;
2339
- const width = r & 7;
2340
- if (width === 0) break;
2341
- currentState = anchor === RE2Flags.UNANCHORED && rune <= Unicode.MAX_LATIN1 && currentState.nextLatin1[rune] || this.step(currentState, rune, anchor);
2342
- if (currentState === null) return null;
2343
- currentState.lastSeen = ++this.clock;
2344
- i += width;
2345
- checkMatch(currentState, i);
2346
- if (currentState.nfaStates.length === 0) {
2347
- if (anchor !== RE2Flags.UNANCHORED) break;
2348
- }
2349
- }
2503
+ if (this.run(input, pos, anchor, startState, collect) === null) return null;
2350
2504
  return Array.from(matches).sort((a, b) => a - b);
2351
2505
  }
2352
2506
  };
@@ -2634,7 +2788,7 @@ var OnePassProg = class {
2634
2788
  const inst = new Inst(orig.op);
2635
2789
  inst.out = orig.out;
2636
2790
  inst.arg = orig.arg;
2637
- inst.runes = orig.runes ? orig.runes.slice() : [];
2791
+ inst.runes = orig.runes ? new Int32Array(orig.runes) : /* @__PURE__ */ new Int32Array(0);
2638
2792
  inst.next = null;
2639
2793
  this.inst[i] = inst;
2640
2794
  }
@@ -2704,7 +2858,7 @@ const makeOnePass = (p) => {
2704
2858
  const rightRunes = onePassRunes[inst.arg] || [];
2705
2859
  const mergeRes = mergeRuneSets(leftRunes, rightRunes, inst.out, inst.arg);
2706
2860
  if (!mergeRes) return false;
2707
- onePassRunes[pc] = mergeRes.merged;
2861
+ onePassRunes[pc] = new Int32Array(mergeRes.merged);
2708
2862
  inst.next = new Uint32Array(mergeRes.next);
2709
2863
  break;
2710
2864
  }
@@ -2713,7 +2867,7 @@ const makeOnePass = (p) => {
2713
2867
  case Inst.NOP:
2714
2868
  ok = check(inst.out);
2715
2869
  m[pc] = m[inst.out];
2716
- onePassRunes[pc] = onePassRunes[inst.out] ? onePassRunes[inst.out].slice() : [];
2870
+ onePassRunes[pc] = onePassRunes[inst.out] ? new Int32Array(onePassRunes[inst.out]) : /* @__PURE__ */ new Int32Array(0);
2717
2871
  inst.next = new Uint32Array(Math.floor(onePassRunes[pc].length / 2) + 1).fill(inst.out);
2718
2872
  break;
2719
2873
  case Inst.MATCH:
@@ -2725,7 +2879,7 @@ const makeOnePass = (p) => {
2725
2879
  if (inst.next && inst.next.length > 0) break;
2726
2880
  instQueue.insert(inst.out);
2727
2881
  if (!inst.runes || inst.runes.length === 0) {
2728
- onePassRunes[pc] = [];
2882
+ onePassRunes[pc] = /* @__PURE__ */ new Int32Array(0);
2729
2883
  inst.next = new Uint32Array([inst.out]);
2730
2884
  break;
2731
2885
  }
@@ -2736,7 +2890,7 @@ const makeOnePass = (p) => {
2736
2890
  for (let r1 = Unicode.simpleFold(r0); r1 !== r0; r1 = Unicode.simpleFold(r1)) runes.push(r1, r1);
2737
2891
  runes.sort((a, b) => a - b);
2738
2892
  } else for (let j = 0; j < inst.runes.length; j++) runes.push(inst.runes[j]);
2739
- onePassRunes[pc] = runes;
2893
+ onePassRunes[pc] = new Int32Array(runes);
2740
2894
  inst.next = new Uint32Array(Math.floor(runes.length / 2) + 1).fill(inst.out);
2741
2895
  inst.op = Inst.RUNE;
2742
2896
  break;
@@ -2752,7 +2906,7 @@ const makeOnePass = (p) => {
2752
2906
  for (let r1 = Unicode.simpleFold(r0); r1 !== r0; r1 = Unicode.simpleFold(r1)) runes.push(r1, r1);
2753
2907
  runes.sort((a, b) => a - b);
2754
2908
  } else runes.push(inst.runes[0], inst.runes[0]);
2755
- onePassRunes[pc] = runes;
2909
+ onePassRunes[pc] = new Int32Array(runes);
2756
2910
  inst.next = new Uint32Array(Math.floor(runes.length / 2) + 1).fill(inst.out);
2757
2911
  inst.op = Inst.RUNE;
2758
2912
  break;
@@ -2761,19 +2915,19 @@ const makeOnePass = (p) => {
2761
2915
  m[pc] = false;
2762
2916
  if (inst.next && inst.next.length > 0) break;
2763
2917
  instQueue.insert(inst.out);
2764
- onePassRunes[pc] = [0, Unicode.MAX_RUNE];
2918
+ onePassRunes[pc] = new Int32Array([0, Unicode.MAX_RUNE]);
2765
2919
  inst.next = new Uint32Array([inst.out]);
2766
2920
  break;
2767
2921
  case Inst.RUNE_ANY_NOT_NL:
2768
2922
  m[pc] = false;
2769
2923
  if (inst.next && inst.next.length > 0) break;
2770
2924
  instQueue.insert(inst.out);
2771
- onePassRunes[pc] = [
2925
+ onePassRunes[pc] = new Int32Array([
2772
2926
  0,
2773
2927
  9,
2774
2928
  11,
2775
2929
  Unicode.MAX_RUNE
2776
- ];
2930
+ ]);
2777
2931
  inst.next = new Uint32Array(Math.floor(onePassRunes[pc].length / 2) + 1).fill(inst.out);
2778
2932
  }
2779
2933
  return ok;
@@ -2806,7 +2960,7 @@ const cleanupOnePass = (p, original) => {
2806
2960
  case Inst.RUNE_ANY_NOT_NL:
2807
2961
  p.inst[ix].next = null;
2808
2962
  p.inst[ix].op = instOriginal.op;
2809
- p.inst[ix].runes = instOriginal.runes ? instOriginal.runes.slice() : [];
2963
+ p.inst[ix].runes = instOriginal.runes ? new Int32Array(instOriginal.runes) : /* @__PURE__ */ new Int32Array(0);
2810
2964
  }
2811
2965
  }
2812
2966
  };
@@ -2984,7 +3138,7 @@ var Regexp = class Regexp {
2984
3138
  this.op = op;
2985
3139
  this.flags = 0;
2986
3140
  this.subs = Regexp.emptySubs();
2987
- this.runes = [];
3141
+ this.runes = /* @__PURE__ */ new Int32Array(0);
2988
3142
  this.min = 0;
2989
3143
  this.max = 0;
2990
3144
  this.cap = 0;
@@ -2995,7 +3149,7 @@ var Regexp = class Regexp {
2995
3149
  reinit() {
2996
3150
  this.flags = 0;
2997
3151
  this.subs = Regexp.emptySubs();
2998
- this.runes = [];
3152
+ this.runes = /* @__PURE__ */ new Int32Array(0);
2999
3153
  this.cap = 0;
3000
3154
  this.min = 0;
3001
3155
  this.max = 0;
@@ -3153,6 +3307,7 @@ var Regexp = class Regexp {
3153
3307
  break;
3154
3308
  case Regexp.Op.LITERAL:
3155
3309
  case Regexp.Op.CHAR_CLASS:
3310
+ if ((this.flags & RE2Flags.FOLD_CASE) !== (that.flags & RE2Flags.FOLD_CASE)) return false;
3156
3311
  if (this.runes === null && that.runes === null) break;
3157
3312
  if (this.runes === null || that.runes === null) return false;
3158
3313
  if (this.runes.length !== that.runes.length) return false;
@@ -3180,61 +3335,149 @@ var Regexp = class Regexp {
3180
3335
  return true;
3181
3336
  }
3182
3337
  };
3338
+ /**
3339
+ * Walks a Regexp tree without recursion, visiting nodes in the same order a recursive walk
3340
+ * would (RE2: re2/walker-inl.h, "Helper class for traversing Regexps without recursion").
3341
+ *
3342
+ * The handler sees a node without subexpressions once, through `leaf(re)`, which returns its
3343
+ * result. Any other node is seen up to three times:
3344
+ * - `enter(re)` before its children. It returns the state kept for `re` while its children are
3345
+ * visited; a state whose `result` is already set skips the children.
3346
+ * - `child(re, state, result, i)` after child `i` produced `result`. Setting `state.result`
3347
+ * stops visiting the remaining children.
3348
+ * - `leave(re, state)` after the last child; it returns the result for `re`.
3349
+ *
3350
+ * Counted repetitions expand into one nesting level per copy, so the simplified tree can be
3351
+ * thousands of levels deep; recursion over it would overflow the JS stack, which has no fixed
3352
+ * relation to the parser's nesting limit. This walk keeps its frames on the heap instead.
3353
+ */
3354
+ var RegexpWalker = class {
3355
+ static walk(root, handler) {
3356
+ const stack = [];
3357
+ let re = root;
3358
+ let result;
3359
+ for (;;) {
3360
+ if (re.subs.length === 0) result = handler.leaf(re);
3361
+ else {
3362
+ const state = handler.enter(re);
3363
+ if (state.result === void 0) {
3364
+ stack.push({
3365
+ re,
3366
+ state,
3367
+ i: 0
3368
+ });
3369
+ re = re.subs[0];
3370
+ continue;
3371
+ }
3372
+ result = state.result;
3373
+ }
3374
+ for (;;) {
3375
+ if (stack.length === 0) return result;
3376
+ const frame = stack[stack.length - 1];
3377
+ handler.child(frame.re, frame.state, result, frame.i);
3378
+ frame.i++;
3379
+ if (frame.state.result === void 0 && frame.i < frame.re.subs.length) {
3380
+ re = frame.re.subs[frame.i];
3381
+ break;
3382
+ }
3383
+ stack.pop();
3384
+ result = frame.state.result !== void 0 ? frame.state.result : handler.leave(frame.re, frame.state);
3385
+ }
3386
+ }
3387
+ }
3388
+ };
3183
3389
  var AhoCorasick = class {
3184
- constructor(wordArrays) {
3185
- this.next = [Object.create(null)];
3186
- this.fail = [0];
3187
- this.match = [false];
3188
- for (const word of wordArrays) {
3390
+ constructor(words, alphabetSize) {
3391
+ const edges = /* @__PURE__ */ new Map();
3392
+ const parent = [0];
3393
+ const unit = [0];
3394
+ const depth = [0];
3395
+ const terminal = [0];
3396
+ for (const word of words) {
3189
3397
  let node = 0;
3190
3398
  for (let i = 0; i < word.length; i++) {
3191
- const val = word[i];
3192
- if (!(val in this.next[node])) {
3193
- this.next.push(Object.create(null));
3194
- this.fail.push(0);
3195
- this.match.push(false);
3196
- this.next[node][val] = this.next.length - 1;
3399
+ const key = node * alphabetSize + word[i];
3400
+ let child = edges.get(key);
3401
+ if (child === void 0) {
3402
+ child = parent.length;
3403
+ edges.set(key, child);
3404
+ parent.push(node);
3405
+ unit.push(word[i]);
3406
+ depth.push(depth[node] + 1);
3407
+ terminal.push(0);
3197
3408
  }
3198
- node = this.next[node][val];
3409
+ node = child;
3199
3410
  }
3200
- this.match[node] = true;
3411
+ terminal[node] = 1;
3201
3412
  }
3202
- const queue = [];
3203
- for (const val in this.next[0]) if (Object.prototype.hasOwnProperty.call(this.next[0], val)) {
3204
- const child = this.next[0][val];
3205
- this.fail[child] = 0;
3206
- queue.push(child);
3207
- }
3208
- while (queue.length > 0) {
3209
- const curr = queue.shift();
3210
- for (const val in this.next[curr]) if (Object.prototype.hasOwnProperty.call(this.next[curr], val)) {
3211
- const child = this.next[curr][val];
3212
- let failNode = this.fail[curr];
3213
- while (failNode !== 0 && !(val in this.next[failNode])) failNode = this.fail[failNode];
3214
- if (val in this.next[failNode]) this.fail[child] = this.next[failNode][val];
3215
- else this.fail[child] = 0;
3216
- this.match[child] = this.match[child] || this.match[this.fail[child]];
3217
- queue.push(child);
3413
+ const numNodes = parent.length;
3414
+ const children = new Int32Array(numNodes - 1);
3415
+ for (let c = 1; c < numNodes; c++) children[c - 1] = c;
3416
+ children.sort((a, b) => parent[a] - parent[b] || unit[a] - unit[b]);
3417
+ const childStart = new Int32Array(numNodes + 1);
3418
+ for (let c = 1; c < numNodes; c++) childStart[parent[c] + 1]++;
3419
+ for (let n = 0; n < numNodes; n++) childStart[n + 1] += childStart[n];
3420
+ const childUnit = new Int32Array(numNodes - 1);
3421
+ for (let k = 0; k < children.length; k++) childUnit[k] = unit[children[k]];
3422
+ this.childStart = childStart;
3423
+ this.childUnit = childUnit;
3424
+ this.childNode = children;
3425
+ const byDepth = new Int32Array(numNodes);
3426
+ for (let n = 0; n < numNodes; n++) byDepth[n] = n;
3427
+ byDepth.sort((a, b) => depth[a] - depth[b]);
3428
+ const fail = new Int32Array(numNodes);
3429
+ const match = Uint8Array.from(terminal);
3430
+ for (let k = 1; k < numNodes; k++) {
3431
+ const c = byDepth[k];
3432
+ const p = parent[c];
3433
+ if (p !== 0) {
3434
+ let f = fail[p];
3435
+ let next = this.next(f, unit[c]);
3436
+ while (next < 0 && f !== 0) {
3437
+ f = fail[f];
3438
+ next = this.next(f, unit[c]);
3439
+ }
3440
+ fail[c] = next >= 0 ? next : 0;
3218
3441
  }
3442
+ match[c] |= match[fail[c]];
3443
+ }
3444
+ this.fail = fail;
3445
+ this.match = match;
3446
+ }
3447
+ next(node, u) {
3448
+ let lo = this.childStart[node];
3449
+ let hi = this.childStart[node + 1];
3450
+ const units = this.childUnit;
3451
+ while (lo < hi) {
3452
+ const mid = lo + hi >> 1;
3453
+ const m = units[mid];
3454
+ if (m === u) return this.childNode[mid];
3455
+ if (m < u) lo = mid + 1;
3456
+ else hi = mid;
3457
+ }
3458
+ return -1;
3459
+ }
3460
+ advance(node, u) {
3461
+ for (;;) {
3462
+ const next = this.next(node, u);
3463
+ if (next >= 0) return next;
3464
+ if (node === 0) return 0;
3465
+ node = this.fail[node];
3219
3466
  }
3220
3467
  }
3221
3468
  searchUTF16(charSeq, start, end) {
3222
3469
  let node = 0;
3223
3470
  for (let i = start; i < end; i++) {
3224
- const val = charSeq.charCodeAt(i);
3225
- while (node !== 0 && !(val in this.next[node])) node = this.fail[node];
3226
- if (val in this.next[node]) node = this.next[node][val];
3227
- if (this.match[node]) return true;
3471
+ node = this.advance(node, charSeq.charCodeAt(i));
3472
+ if (this.match[node] === 1) return true;
3228
3473
  }
3229
3474
  return false;
3230
3475
  }
3231
3476
  searchUTF8(bytes, start, end) {
3232
3477
  let node = 0;
3233
3478
  for (let i = start; i < end; i++) {
3234
- const val = bytes[i];
3235
- while (node !== 0 && !(val in this.next[node])) node = this.fail[node];
3236
- if (val in this.next[node]) node = this.next[node][val];
3237
- if (this.match[node]) return true;
3479
+ node = this.advance(node, bytes[i]);
3480
+ if (this.match[node] === 1) return true;
3238
3481
  }
3239
3482
  return false;
3240
3483
  }
@@ -3246,14 +3489,33 @@ var Prefilter = class Prefilter {
3246
3489
  AND: 2,
3247
3490
  OR: 3
3248
3491
  };
3492
+ static MAX_SCANS = 32;
3493
+ static MAX_AC_UNITS = 1 << 18;
3249
3494
  constructor(type) {
3250
3495
  this.type = type;
3251
3496
  this.subs = [];
3252
3497
  this.str = "";
3253
3498
  this.bytes = null;
3499
+ this.cost = type === Prefilter.Type.EXACT ? 1 : 0;
3500
+ this.allExact = false;
3254
3501
  this.ac16 = null;
3255
3502
  this.ac8 = null;
3256
3503
  }
3504
+ automaton16() {
3505
+ if (this.ac16 === null) {
3506
+ const words = this.subs.map((s) => {
3507
+ const arr = new Array(s.str.length);
3508
+ for (let i = 0; i < s.str.length; i++) arr[i] = s.str.charCodeAt(i);
3509
+ return arr;
3510
+ });
3511
+ this.ac16 = new AhoCorasick(words, 65536);
3512
+ }
3513
+ return this.ac16;
3514
+ }
3515
+ automaton8() {
3516
+ if (this.ac8 === null) this.ac8 = new AhoCorasick(this.subs.map((s) => s.bytes), 256);
3517
+ return this.ac8;
3518
+ }
3257
3519
  eval(input, pos) {
3258
3520
  switch (this.type) {
3259
3521
  case Prefilter.Type.NONE: return true;
@@ -3262,7 +3524,7 @@ var Prefilter = class Prefilter {
3262
3524
  for (let i = 0; i < this.subs.length; i++) if (!this.subs[i].eval(input, pos)) return false;
3263
3525
  return true;
3264
3526
  case Prefilter.Type.OR:
3265
- if (this.ac16 && this.ac8) return input.hasAnyString(this, pos);
3527
+ if (this.allExact) return input.hasAnyString(this, pos);
3266
3528
  for (let i = 0; i < this.subs.length; i++) if (this.subs[i].eval(input, pos)) return true;
3267
3529
  return false;
3268
3530
  default: return true;
@@ -3271,100 +3533,115 @@ var Prefilter = class Prefilter {
3271
3533
  };
3272
3534
  var PrefilterTree = class PrefilterTree {
3273
3535
  static build(re) {
3274
- const pf = PrefilterTree.fromRegexp(re);
3275
- return PrefilterTree.simplify(pf);
3276
- }
3277
- static fromRegexp(re) {
3278
3536
  if (!re) return new Prefilter(Prefilter.Type.NONE);
3537
+ return RegexpWalker.walk(re, PrefilterTree.WALKER);
3538
+ }
3539
+ static WALKER = {
3540
+ leaf: (re) => PrefilterTree.leaf(re),
3541
+ enter: (re) => PrefilterTree.enter(re),
3542
+ child: (re, state, result) => PrefilterTree.child(re, state, result),
3543
+ leave: (re, state) => PrefilterTree.leave(re, state)
3544
+ };
3545
+ static leaf(re) {
3546
+ if (re.op !== Regexp.Op.LITERAL) return new Prefilter(Prefilter.Type.NONE);
3547
+ if (re.runes.length === 0 || (re.flags & RE2Flags.FOLD_CASE) !== 0) return new Prefilter(Prefilter.Type.NONE);
3548
+ let str = "";
3549
+ for (let i = 0; i < re.runes.length; i++) {
3550
+ if (Unicode.isUnsearchable(re.runes[i])) return new Prefilter(Prefilter.Type.NONE);
3551
+ str += String.fromCodePoint(re.runes[i]);
3552
+ }
3553
+ const pf = new Prefilter(Prefilter.Type.EXACT);
3554
+ pf.str = str;
3555
+ pf.bytes = Utils.stringToUtf8ByteArray(pf.str);
3556
+ return pf;
3557
+ }
3558
+ static enter(re) {
3279
3559
  switch (re.op) {
3280
- case Regexp.Op.PLB:
3281
- case Regexp.Op.NLB:
3282
- case Regexp.Op.NO_MATCH:
3283
- case Regexp.Op.EMPTY_MATCH:
3284
- case Regexp.Op.BEGIN_LINE:
3285
- case Regexp.Op.END_LINE:
3286
- case Regexp.Op.BEGIN_TEXT:
3287
- case Regexp.Op.END_TEXT:
3288
- case Regexp.Op.WORD_BOUNDARY:
3289
- case Regexp.Op.NO_WORD_BOUNDARY:
3290
- case Regexp.Op.CHAR_CLASS:
3291
- case Regexp.Op.ANY_CHAR_NOT_NL:
3292
- case Regexp.Op.ANY_CHAR: return new Prefilter(Prefilter.Type.NONE);
3293
- case Regexp.Op.LITERAL: {
3294
- if (re.runes.length === 0 || (re.flags & RE2Flags.FOLD_CASE) !== 0) return new Prefilter(Prefilter.Type.NONE);
3295
- const pf = new Prefilter(Prefilter.Type.EXACT);
3296
- let str = "";
3297
- for (let i = 0; i < re.runes.length; i++) str += String.fromCodePoint(re.runes[i]);
3298
- pf.str = str;
3299
- pf.bytes = Utils.stringToUtf8ByteArray(pf.str);
3300
- return pf;
3301
- }
3302
3560
  case Regexp.Op.CAPTURE:
3303
- case Regexp.Op.PLUS: return PrefilterTree.fromRegexp(re.subs[0]);
3561
+ case Regexp.Op.PLUS: return { sub: null };
3304
3562
  case Regexp.Op.REPEAT:
3305
- if (re.min >= 1) return PrefilterTree.fromRegexp(re.subs[0]);
3306
- return new Prefilter(Prefilter.Type.NONE);
3307
- case Regexp.Op.CONCAT: {
3308
- const pf = new Prefilter(Prefilter.Type.AND);
3309
- for (const sub of re.subs) pf.subs.push(PrefilterTree.fromRegexp(sub));
3310
- return pf;
3563
+ if (re.min >= 1) return { sub: null };
3564
+ return { result: new Prefilter(Prefilter.Type.NONE) };
3565
+ case Regexp.Op.CONCAT: return {
3566
+ pf: new Prefilter(Prefilter.Type.AND),
3567
+ subs: []
3568
+ };
3569
+ case Regexp.Op.ALTERNATE: return {
3570
+ pf: new Prefilter(Prefilter.Type.OR),
3571
+ subs: []
3572
+ };
3573
+ default: return { result: new Prefilter(Prefilter.Type.NONE) };
3574
+ }
3575
+ }
3576
+ static child(re, state, s) {
3577
+ if (state.subs === void 0) {
3578
+ state.sub = s;
3579
+ return;
3580
+ }
3581
+ if (state.pf.type === Prefilter.Type.AND) {
3582
+ if (s.type === Prefilter.Type.NONE) return;
3583
+ if (s.type === Prefilter.Type.AND) {
3584
+ for (let j = 0; j < s.subs.length; j++) state.subs.push(s.subs[j]);
3585
+ return;
3311
3586
  }
3312
- case Regexp.Op.ALTERNATE: {
3313
- const pf = new Prefilter(Prefilter.Type.OR);
3314
- for (const sub of re.subs) pf.subs.push(PrefilterTree.fromRegexp(sub));
3315
- return pf;
3587
+ state.subs.push(s);
3588
+ return;
3589
+ }
3590
+ if (s.type === Prefilter.Type.NONE) {
3591
+ state.result = new Prefilter(Prefilter.Type.NONE);
3592
+ return;
3593
+ }
3594
+ if (s.type === Prefilter.Type.OR) {
3595
+ for (let j = 0; j < s.subs.length; j++) state.subs.push(s.subs[j]);
3596
+ return;
3597
+ }
3598
+ state.subs.push(s);
3599
+ }
3600
+ static leave(re, state) {
3601
+ if (state.subs === void 0) return state.sub;
3602
+ const pf = state.pf;
3603
+ const seen = /* @__PURE__ */ new Set();
3604
+ const subs = [];
3605
+ for (const sub of state.subs) {
3606
+ if (sub.type === Prefilter.Type.EXACT) {
3607
+ if (seen.has(sub.str)) continue;
3608
+ seen.add(sub.str);
3316
3609
  }
3317
- default: return new Prefilter(Prefilter.Type.NONE);
3610
+ subs.push(sub);
3318
3611
  }
3319
- }
3320
- static simplify(pf) {
3321
- if (pf.type === Prefilter.Type.EXACT || pf.type === Prefilter.Type.NONE) return pf;
3322
3612
  if (pf.type === Prefilter.Type.AND) {
3323
- const newSubs = [];
3324
- for (const sub of pf.subs) {
3325
- const s = PrefilterTree.simplify(sub);
3326
- if (s.type !== Prefilter.Type.NONE) if (s.type === Prefilter.Type.AND) for (let j = 0; j < s.subs.length; j++) newSubs.push(s.subs[j]);
3327
- else newSubs.push(s);
3613
+ const kept = [];
3614
+ let cost = 0;
3615
+ for (const sub of subs) {
3616
+ if (cost + sub.cost > Prefilter.MAX_SCANS) continue;
3617
+ kept.push(sub);
3618
+ cost += sub.cost;
3328
3619
  }
3329
- if (newSubs.length === 0) return new Prefilter(Prefilter.Type.NONE);
3330
- if (newSubs.length === 1) return newSubs[0];
3331
- pf.subs = newSubs;
3620
+ if (kept.length === 0) return new Prefilter(Prefilter.Type.NONE);
3621
+ if (kept.length === 1) return kept[0];
3622
+ pf.subs = kept;
3623
+ pf.cost = cost;
3332
3624
  return pf;
3333
3625
  }
3334
- if (pf.type === Prefilter.Type.OR) {
3335
- const newSubs = [];
3336
- for (const sub of pf.subs) {
3337
- const s = PrefilterTree.simplify(sub);
3338
- if (s.type === Prefilter.Type.NONE) return new Prefilter(Prefilter.Type.NONE);
3339
- if (s.type === Prefilter.Type.OR) for (let j = 0; j < s.subs.length; j++) newSubs.push(s.subs[j]);
3340
- else newSubs.push(s);
3341
- }
3342
- if (newSubs.length === 0) return new Prefilter(Prefilter.Type.NONE);
3343
- if (newSubs.length === 1) return newSubs[0];
3344
- const seen = /* @__PURE__ */ new Set();
3345
- const uniqueSubs = [];
3346
- for (const sub of newSubs) if (sub.type === Prefilter.Type.EXACT) {
3347
- if (!seen.has(sub.str)) {
3348
- seen.add(sub.str);
3349
- uniqueSubs.push(sub);
3350
- }
3351
- } else uniqueSubs.push(sub);
3352
- pf.subs = uniqueSubs;
3353
- let allExact = true;
3354
- for (const sub of uniqueSubs) if (sub.type !== Prefilter.Type.EXACT) {
3355
- allExact = false;
3356
- break;
3357
- }
3358
- if (allExact && uniqueSubs.length > 1) {
3359
- pf.ac16 = new AhoCorasick(uniqueSubs.map((s) => {
3360
- const arr = [];
3361
- for (let i = 0; i < s.str.length; i++) arr.push(s.str.charCodeAt(i));
3362
- return arr;
3363
- }));
3364
- pf.ac8 = new AhoCorasick(uniqueSubs.map((s) => s.bytes));
3365
- }
3626
+ if (subs.length === 0) return new Prefilter(Prefilter.Type.NONE);
3627
+ if (subs.length === 1) return subs[0];
3628
+ pf.subs = subs;
3629
+ let allExact = true;
3630
+ let cost = 0;
3631
+ let units = 0;
3632
+ for (const sub of subs) {
3633
+ if (sub.type !== Prefilter.Type.EXACT) allExact = false;
3634
+ else units += sub.bytes.length;
3635
+ cost += sub.cost;
3636
+ }
3637
+ if (allExact) {
3638
+ if (units > Prefilter.MAX_AC_UNITS) return new Prefilter(Prefilter.Type.NONE);
3639
+ pf.allExact = true;
3640
+ pf.cost = 1;
3366
3641
  return pf;
3367
3642
  }
3643
+ if (cost > Prefilter.MAX_SCANS) return new Prefilter(Prefilter.Type.NONE);
3644
+ pf.cost = cost;
3368
3645
  return pf;
3369
3646
  }
3370
3647
  };
@@ -3398,6 +3675,7 @@ var Prog = class {
3398
3675
  this.numCap = 2;
3399
3676
  this.lbStarts = [];
3400
3677
  this.numLb = 0;
3678
+ this.lbInst = null;
3401
3679
  }
3402
3680
  getInst(pc) {
3403
3681
  return this.inst[pc];
@@ -3408,6 +3686,26 @@ var Prog = class {
3408
3686
  addInst(op) {
3409
3687
  this.inst.push(new Inst(op));
3410
3688
  }
3689
+ markLookbehindInsts() {
3690
+ const lbInst = new Uint8Array(this.inst.length);
3691
+ const pending = this.lbStarts.slice();
3692
+ while (pending.length > 0) {
3693
+ const pc = pending.pop();
3694
+ if (pc === 0 || lbInst[pc] === 1) continue;
3695
+ lbInst[pc] = 1;
3696
+ const i = this.inst[pc];
3697
+ switch (i.op) {
3698
+ case Inst.ALT:
3699
+ case Inst.ALT_MATCH:
3700
+ pending.push(i.out, i.arg);
3701
+ break;
3702
+ case Inst.MATCH:
3703
+ case Inst.FAIL: break;
3704
+ default: pending.push(i.out);
3705
+ }
3706
+ }
3707
+ this.lbInst = lbInst;
3708
+ }
3411
3709
  skipNop(pc) {
3412
3710
  let i = this.inst[pc];
3413
3711
  while (i.op === Inst.NOP || i.op === Inst.CAPTURE) {
@@ -3420,7 +3718,7 @@ var Prog = class {
3420
3718
  let prefix = "";
3421
3719
  let i = this.skipNop(this.start);
3422
3720
  if (!Inst.isRuneOp(i.op) || i.runes.length !== 1) return [i.op === Inst.MATCH, prefix];
3423
- while (Inst.isRuneOp(i.op) && i.runes.length === 1 && (i.arg & RE2Flags.FOLD_CASE) === 0) {
3721
+ while (Inst.isRuneOp(i.op) && i.runes.length === 1 && (i.arg & RE2Flags.FOLD_CASE) === 0 && !Unicode.isUnsearchable(i.runes[0])) {
3424
3722
  prefix += String.fromCodePoint(i.runes[0]);
3425
3723
  i = this.skipNop(i.out);
3426
3724
  }
@@ -3482,6 +3780,13 @@ var Prog = class {
3482
3780
  return out;
3483
3781
  }
3484
3782
  };
3783
+ const ANY_RUNE_NOT_NL = new Int32Array([
3784
+ 0,
3785
+ Codepoint.CODES.get("\n") - 1,
3786
+ Codepoint.CODES.get("\n") + 1,
3787
+ Unicode.MAX_RUNE
3788
+ ]);
3789
+ const ANY_RUNE = new Int32Array([0, Unicode.MAX_RUNE]);
3485
3790
  /**
3486
3791
  * A fragment of a compiled regular expression program.
3487
3792
  *
@@ -3501,28 +3806,19 @@ var Frag = class {
3501
3806
  * The only entry point is {@link #compileRegexp}.
3502
3807
  */
3503
3808
  var Compiler = class Compiler {
3504
- static ANY_RUNE_NOT_NL() {
3505
- return [
3506
- 0,
3507
- Codepoint.CODES.get("\n") - 1,
3508
- Codepoint.CODES.get("\n") + 1,
3509
- Unicode.MAX_RUNE
3510
- ];
3511
- }
3512
- static ANY_RUNE() {
3513
- return [0, Unicode.MAX_RUNE];
3514
- }
3515
3809
  static compileRegexp(re) {
3516
3810
  const c = new Compiler();
3517
3811
  const f = c.compile(re);
3518
3812
  c.prog.patch(f.out, c.newInst(Inst.MATCH).i);
3519
3813
  c.prog.start = f.i;
3814
+ c.prog.markLookbehindInsts();
3520
3815
  return c.prog;
3521
3816
  }
3522
3817
  static compileSet(regexps) {
3523
3818
  const c = new Compiler();
3524
3819
  if (regexps.length === 0) {
3525
3820
  c.prog.start = c.newInst(Inst.FAIL).i;
3821
+ c.prog.markLookbehindInsts();
3526
3822
  return c.prog;
3527
3823
  }
3528
3824
  let starts = [];
@@ -3542,11 +3838,19 @@ var Compiler = class Compiler {
3542
3838
  start = f.i;
3543
3839
  }
3544
3840
  c.prog.start = start;
3841
+ c.prog.markLookbehindInsts();
3545
3842
  return c.prog;
3546
3843
  }
3547
3844
  constructor() {
3548
3845
  this.prog = new Prog();
3549
3846
  this.newInst(Inst.FAIL);
3847
+ this.runeCache = /* @__PURE__ */ new Map();
3848
+ this.walker = {
3849
+ leaf: (re) => this.leaf(re),
3850
+ enter: (re) => this.enter(re),
3851
+ child: (re, state, result) => this.child(re, state, result),
3852
+ leave: (re, state) => this.leave(re, state)
3853
+ };
3550
3854
  }
3551
3855
  newInst(op) {
3552
3856
  this.prog.addInst(op);
@@ -3639,7 +3943,7 @@ var Compiler = class Compiler {
3639
3943
  lookBehind(a, lb) {
3640
3944
  const id = this.newInst(Inst.LB_WRITE);
3641
3945
  this.prog.getInst(id.i).arg = lb;
3642
- const any = this.rune(Compiler.ANY_RUNE(), 0);
3946
+ const any = this.rune(ANY_RUNE, 0);
3643
3947
  const dotStar = this.star(any, true);
3644
3948
  const lbAutomaton = this.cat(dotStar, a);
3645
3949
  this.prog.patch(lbAutomaton.out, id.i);
@@ -3651,56 +3955,74 @@ var Compiler = class Compiler {
3651
3955
  return checkId;
3652
3956
  }
3653
3957
  compile(re) {
3958
+ return RegexpWalker.walk(re, this.walker);
3959
+ }
3960
+ leaf(re) {
3654
3961
  switch (re.op) {
3655
3962
  case Regexp.Op.NO_MATCH: return this.fail();
3656
3963
  case Regexp.Op.EMPTY_MATCH: return this.nop();
3657
- case Regexp.Op.LITERAL: if (re.runes.length === 0) return this.nop();
3658
- else {
3964
+ case Regexp.Op.LITERAL: {
3965
+ if (re.runes.length === 0) return this.nop();
3659
3966
  let f = null;
3660
3967
  for (let r of re.runes) {
3661
- const f1 = this.rune([r], re.flags);
3968
+ let singleRune = this.runeCache.get(r);
3969
+ if (singleRune === void 0) {
3970
+ singleRune = new Int32Array([r]);
3971
+ this.runeCache.set(r, singleRune);
3972
+ }
3973
+ const f1 = this.rune(singleRune, re.flags);
3662
3974
  f = f === null ? f1 : this.cat(f, f1);
3663
3975
  }
3664
3976
  return f;
3665
3977
  }
3666
3978
  case Regexp.Op.CHAR_CLASS: return this.rune(re.runes, re.flags);
3667
- case Regexp.Op.ANY_CHAR_NOT_NL: return this.rune(Compiler.ANY_RUNE_NOT_NL(), 0);
3668
- case Regexp.Op.ANY_CHAR: return this.rune(Compiler.ANY_RUNE(), 0);
3979
+ case Regexp.Op.ANY_CHAR_NOT_NL: return this.rune(ANY_RUNE_NOT_NL, 0);
3980
+ case Regexp.Op.ANY_CHAR: return this.rune(ANY_RUNE, 0);
3669
3981
  case Regexp.Op.BEGIN_LINE: return this.empty(Utils.EMPTY_BEGIN_LINE);
3670
3982
  case Regexp.Op.END_LINE: return this.empty(Utils.EMPTY_END_LINE);
3671
3983
  case Regexp.Op.BEGIN_TEXT: return this.empty(Utils.EMPTY_BEGIN_TEXT);
3672
3984
  case Regexp.Op.END_TEXT: return this.empty(Utils.EMPTY_END_TEXT);
3673
3985
  case Regexp.Op.WORD_BOUNDARY: return this.empty(Utils.EMPTY_WORD_BOUNDARY);
3674
3986
  case Regexp.Op.NO_WORD_BOUNDARY: return this.empty(Utils.EMPTY_NO_WORD_BOUNDARY);
3987
+ case Regexp.Op.CONCAT:
3988
+ case Regexp.Op.ALTERNATE: return this.nop();
3989
+ default: throw new RE2JSCompileException("regexp: unhandled case in compile");
3990
+ }
3991
+ }
3992
+ enter(re) {
3993
+ switch (re.op) {
3675
3994
  case Regexp.Op.PLB:
3676
- case Regexp.Op.NLB: return this.lookBehind(this.compile(re.subs[0]), re.lb);
3995
+ case Regexp.Op.NLB:
3996
+ case Regexp.Op.STAR:
3997
+ case Regexp.Op.PLUS:
3998
+ case Regexp.Op.QUEST: return { sub: null };
3999
+ case Regexp.Op.CAPTURE: return {
4000
+ bra: this.cap(re.cap << 1),
4001
+ sub: null
4002
+ };
4003
+ case Regexp.Op.CONCAT:
4004
+ case Regexp.Op.ALTERNATE: return { f: null };
4005
+ default: throw new RE2JSCompileException("regexp: unhandled case in compile");
4006
+ }
4007
+ }
4008
+ child(re, state, f1) {
4009
+ if (re.op === Regexp.Op.CONCAT) state.f = state.f === null ? f1 : this.cat(state.f, f1);
4010
+ else if (re.op === Regexp.Op.ALTERNATE) state.f = state.f === null ? f1 : this.alt(state.f, f1);
4011
+ else state.sub = f1;
4012
+ }
4013
+ leave(re, state) {
4014
+ switch (re.op) {
4015
+ case Regexp.Op.PLB:
4016
+ case Regexp.Op.NLB: return this.lookBehind(state.sub, re.lb);
3677
4017
  case Regexp.Op.CAPTURE: {
3678
- const bra = this.cap(re.cap << 1);
3679
- const sub = this.compile(re.subs[0]);
3680
4018
  const ket = this.cap(re.cap << 1 | 1);
3681
- return this.cat(this.cat(bra, sub), ket);
3682
- }
3683
- case Regexp.Op.STAR: return this.star(this.compile(re.subs[0]), (re.flags & RE2Flags.NON_GREEDY) !== 0);
3684
- case Regexp.Op.PLUS: return this.plus(this.compile(re.subs[0]), (re.flags & RE2Flags.NON_GREEDY) !== 0);
3685
- case Regexp.Op.QUEST: return this.quest(this.compile(re.subs[0]), (re.flags & RE2Flags.NON_GREEDY) !== 0);
3686
- case Regexp.Op.CONCAT: if (re.subs.length === 0) return this.nop();
3687
- else {
3688
- let f = null;
3689
- for (let sub of re.subs) {
3690
- const f1 = this.compile(sub);
3691
- f = f === null ? f1 : this.cat(f, f1);
3692
- }
3693
- return f;
3694
- }
3695
- case Regexp.Op.ALTERNATE: if (re.subs.length === 0) return this.nop();
3696
- else {
3697
- let f = null;
3698
- for (let sub of re.subs) {
3699
- const f1 = this.compile(sub);
3700
- f = f === null ? f1 : this.alt(f, f1);
3701
- }
3702
- return f;
4019
+ return this.cat(this.cat(state.bra, state.sub), ket);
3703
4020
  }
4021
+ case Regexp.Op.STAR: return this.star(state.sub, (re.flags & RE2Flags.NON_GREEDY) !== 0);
4022
+ case Regexp.Op.PLUS: return this.plus(state.sub, (re.flags & RE2Flags.NON_GREEDY) !== 0);
4023
+ case Regexp.Op.QUEST: return this.quest(state.sub, (re.flags & RE2Flags.NON_GREEDY) !== 0);
4024
+ case Regexp.Op.CONCAT:
4025
+ case Regexp.Op.ALTERNATE: return state.f;
3704
4026
  default: throw new RE2JSCompileException("regexp: unhandled case in compile");
3705
4027
  }
3706
4028
  }
@@ -3708,111 +4030,149 @@ var Compiler = class Compiler {
3708
4030
  var Simplify = class Simplify {
3709
4031
  static simplify(re) {
3710
4032
  if (re === null) return null;
4033
+ return RegexpWalker.walk(re, Simplify.WALKER);
4034
+ }
4035
+ static WALKER = {
4036
+ leaf: (re) => Simplify.leaf(re),
4037
+ enter: (re) => Simplify.enter(re),
4038
+ child: (re, state, result, i) => Simplify.child(re, state, result, i),
4039
+ leave: (re, state) => Simplify.leave(re, state)
4040
+ };
4041
+ static leaf(re) {
4042
+ if (re.op === Regexp.Op.CHAR_CLASS) {
4043
+ if (re.runes === null) return re;
4044
+ if (re.runes.length === 0) return new Regexp(Regexp.Op.NO_MATCH);
4045
+ if (re.runes.length === 2 && re.runes[0] === 0 && re.runes[1] === Unicode.MAX_RUNE) return new Regexp(Regexp.Op.ANY_CHAR);
4046
+ if (re.runes.length === 4 && re.runes[0] === 0 && re.runes[1] === Codepoint.CODES.get("\n") - 1 && re.runes[2] === Codepoint.CODES.get("\n") + 1 && re.runes[3] === Unicode.MAX_RUNE) return new Regexp(Regexp.Op.ANY_CHAR_NOT_NL);
4047
+ }
4048
+ return re;
4049
+ }
4050
+ static enter(re) {
4051
+ switch (re.op) {
4052
+ case Regexp.Op.PLB:
4053
+ case Regexp.Op.NLB:
4054
+ case Regexp.Op.CAPTURE:
4055
+ case Regexp.Op.STAR:
4056
+ case Regexp.Op.PLUS:
4057
+ case Regexp.Op.QUEST: return { sub: null };
4058
+ case Regexp.Op.CONCAT:
4059
+ case Regexp.Op.ALTERNATE: return {
4060
+ subs: [],
4061
+ changed: false
4062
+ };
4063
+ case Regexp.Op.REPEAT:
4064
+ if (re.min === 0 && re.max === 0) return { result: new Regexp(Regexp.Op.EMPTY_MATCH) };
4065
+ return { sub: null };
4066
+ default: return { result: re };
4067
+ }
4068
+ }
4069
+ static child(re, state, nsub, i) {
4070
+ if (state.subs === void 0) {
4071
+ state.sub = nsub;
4072
+ return;
4073
+ }
4074
+ if (nsub !== re.subs[i]) state.changed = true;
4075
+ if (re.op === Regexp.Op.CONCAT) {
4076
+ if (nsub.op === Regexp.Op.NO_MATCH) {
4077
+ state.result = new Regexp(Regexp.Op.NO_MATCH);
4078
+ return;
4079
+ }
4080
+ if (nsub.op === Regexp.Op.EMPTY_MATCH) {
4081
+ state.changed = true;
4082
+ return;
4083
+ }
4084
+ if (nsub.op === Regexp.Op.CONCAT) {
4085
+ state.changed = true;
4086
+ for (let j = 0; j < nsub.subs.length; j++) state.subs.push(nsub.subs[j]);
4087
+ return;
4088
+ }
4089
+ } else {
4090
+ if (nsub.op === Regexp.Op.NO_MATCH) {
4091
+ state.changed = true;
4092
+ return;
4093
+ }
4094
+ if (nsub.op === Regexp.Op.ALTERNATE) {
4095
+ state.changed = true;
4096
+ for (let j = 0; j < nsub.subs.length; j++) state.subs.push(nsub.subs[j]);
4097
+ return;
4098
+ }
4099
+ }
4100
+ state.subs.push(nsub);
4101
+ }
4102
+ static leave(re, state) {
3711
4103
  switch (re.op) {
3712
4104
  case Regexp.Op.PLB:
3713
4105
  case Regexp.Op.NLB:
3714
4106
  case Regexp.Op.CAPTURE: {
3715
- const sub = Simplify.simplify(re.subs[0]);
4107
+ const sub = state.sub;
3716
4108
  if (sub !== re.subs[0]) {
3717
4109
  const nre = Regexp.fromRegexp(re);
3718
- nre.runes = [];
4110
+ nre.runes = /* @__PURE__ */ new Int32Array(0);
3719
4111
  nre.subs = [sub];
3720
4112
  return nre;
3721
4113
  }
3722
4114
  return re;
3723
4115
  }
3724
4116
  case Regexp.Op.CONCAT:
3725
- case Regexp.Op.ALTERNATE: {
3726
- const newSubs = [];
3727
- let changed = false;
3728
- for (let i = 0; i < re.subs.length; i++) {
3729
- const sub = re.subs[i];
3730
- const nsub = Simplify.simplify(sub);
3731
- if (nsub !== sub) changed = true;
3732
- if (re.op === Regexp.Op.CONCAT) {
3733
- if (nsub.op === Regexp.Op.NO_MATCH) return new Regexp(Regexp.Op.NO_MATCH);
3734
- if (nsub.op === Regexp.Op.EMPTY_MATCH) {
3735
- changed = true;
3736
- continue;
3737
- }
3738
- if (nsub.op === Regexp.Op.CONCAT) {
3739
- changed = true;
3740
- for (let j = 0; j < nsub.subs.length; j++) newSubs.push(nsub.subs[j]);
3741
- continue;
3742
- }
3743
- } else if (re.op === Regexp.Op.ALTERNATE) {
3744
- if (nsub.op === Regexp.Op.NO_MATCH) {
3745
- changed = true;
3746
- continue;
3747
- }
3748
- if (nsub.op === Regexp.Op.ALTERNATE) {
3749
- changed = true;
3750
- for (let j = 0; j < nsub.subs.length; j++) newSubs.push(nsub.subs[j]);
3751
- continue;
3752
- }
3753
- }
3754
- newSubs.push(nsub);
3755
- }
3756
- if (changed) {
4117
+ case Regexp.Op.ALTERNATE:
4118
+ if (state.changed) {
4119
+ const newSubs = state.subs;
3757
4120
  if (newSubs.length === 0) return new Regexp(re.op === Regexp.Op.CONCAT ? Regexp.Op.EMPTY_MATCH : Regexp.Op.NO_MATCH);
3758
4121
  if (newSubs.length === 1) return newSubs[0];
3759
4122
  const nre = Regexp.fromRegexp(re);
3760
- nre.runes = [];
4123
+ nre.runes = /* @__PURE__ */ new Int32Array(0);
3761
4124
  nre.subs = newSubs;
3762
4125
  return nre;
3763
4126
  }
3764
4127
  return re;
3765
- }
3766
- case Regexp.Op.CHAR_CLASS:
3767
- if (re.runes === null) return re;
3768
- if (re.runes.length === 0) return new Regexp(Regexp.Op.NO_MATCH);
3769
- if (re.runes.length === 2 && re.runes[0] === 0 && re.runes[1] === Unicode.MAX_RUNE) return new Regexp(Regexp.Op.ANY_CHAR);
3770
- if (re.runes.length === 4 && re.runes[0] === 0 && re.runes[1] === Codepoint.CODES.get("\n") - 1 && re.runes[2] === Codepoint.CODES.get("\n") + 1 && re.runes[3] === Unicode.MAX_RUNE) return new Regexp(Regexp.Op.ANY_CHAR_NOT_NL);
3771
- return re;
3772
4128
  case Regexp.Op.STAR:
3773
4129
  case Regexp.Op.PLUS:
3774
- case Regexp.Op.QUEST: {
3775
- const sub = Simplify.simplify(re.subs[0]);
3776
- return Simplify.simplify1(re.op, re.flags, sub, re);
3777
- }
3778
- case Regexp.Op.REPEAT: {
3779
- if (re.min === 0 && re.max === 0) return new Regexp(Regexp.Op.EMPTY_MATCH);
3780
- const sub = Simplify.simplify(re.subs[0]);
3781
- if (re.max === -1) {
3782
- if (re.min === 0) return Simplify.simplify1(Regexp.Op.STAR, re.flags, sub, null);
3783
- if (re.min === 1) return Simplify.simplify1(Regexp.Op.PLUS, re.flags, sub, null);
3784
- const nre = new Regexp(Regexp.Op.CONCAT);
3785
- const subs = [];
3786
- for (let i = 0; i < re.min - 1; i++) subs.push(sub);
3787
- subs.push(Simplify.simplify1(Regexp.Op.PLUS, re.flags, sub, null));
3788
- nre.subs = subs.slice(0);
3789
- return Simplify.simplify(nre);
3790
- }
3791
- if (re.min === 1 && re.max === 1) return sub;
3792
- let prefixSubs = null;
3793
- if (re.min > 0) {
3794
- prefixSubs = [];
3795
- for (let i = 0; i < re.min; i++) prefixSubs.push(sub);
3796
- }
3797
- if (re.max > re.min) {
3798
- let suffix = Simplify.simplify1(Regexp.Op.QUEST, re.flags, sub, null);
3799
- for (let i = re.min + 1; i < re.max; i++) {
3800
- const nre2 = new Regexp(Regexp.Op.CONCAT);
3801
- nre2.subs = [sub, suffix];
3802
- suffix = Simplify.simplify1(Regexp.Op.QUEST, re.flags, nre2, null);
3803
- }
3804
- if (prefixSubs === null) return suffix;
3805
- prefixSubs.push(suffix);
3806
- }
3807
- if (prefixSubs !== null) {
3808
- const prefix = new Regexp(Regexp.Op.CONCAT);
3809
- prefix.subs = prefixSubs.slice(0);
3810
- return Simplify.simplify(prefix);
3811
- }
3812
- return new Regexp(Regexp.Op.NO_MATCH);
4130
+ case Regexp.Op.QUEST: return Simplify.simplify1(re.op, re.flags, state.sub, re);
4131
+ case Regexp.Op.REPEAT: return Simplify.simplifyRepeat(re, state.sub);
4132
+ default: return re;
4133
+ }
4134
+ }
4135
+ static simplifyRepeat(re, sub) {
4136
+ if (re.max === -1) {
4137
+ if (re.min === 0) return Simplify.simplify1(Regexp.Op.STAR, re.flags, sub, null);
4138
+ if (re.min === 1) return Simplify.simplify1(Regexp.Op.PLUS, re.flags, sub, null);
4139
+ const subs = [];
4140
+ for (let i = 0; i < re.min - 1; i++) subs.push(sub);
4141
+ subs.push(Simplify.simplify1(Regexp.Op.PLUS, re.flags, sub, null));
4142
+ return Simplify.concat(subs);
4143
+ }
4144
+ if (re.min === 1 && re.max === 1) return sub;
4145
+ let prefixSubs = null;
4146
+ if (re.min > 0) {
4147
+ prefixSubs = [];
4148
+ for (let i = 0; i < re.min; i++) prefixSubs.push(sub);
4149
+ }
4150
+ if (re.max > re.min) {
4151
+ let suffix = Simplify.simplify1(Regexp.Op.QUEST, re.flags, sub, null);
4152
+ for (let i = re.min + 1; i < re.max; i++) suffix = Simplify.simplify1(Regexp.Op.QUEST, re.flags, Simplify.concat([sub, suffix]), null);
4153
+ if (prefixSubs === null) return suffix;
4154
+ prefixSubs.push(suffix);
4155
+ }
4156
+ if (prefixSubs !== null) return Simplify.concat(prefixSubs);
4157
+ return new Regexp(Regexp.Op.NO_MATCH);
4158
+ }
4159
+ static concat(subs) {
4160
+ const newSubs = [];
4161
+ for (let i = 0; i < subs.length; i++) {
4162
+ const sub = subs[i];
4163
+ if (sub.op === Regexp.Op.NO_MATCH) return new Regexp(Regexp.Op.NO_MATCH);
4164
+ if (sub.op === Regexp.Op.EMPTY_MATCH) continue;
4165
+ if (sub.op === Regexp.Op.CONCAT) {
4166
+ for (let j = 0; j < sub.subs.length; j++) newSubs.push(sub.subs[j]);
4167
+ continue;
3813
4168
  }
4169
+ newSubs.push(sub);
3814
4170
  }
3815
- return re;
4171
+ if (newSubs.length === 0) return new Regexp(Regexp.Op.EMPTY_MATCH);
4172
+ if (newSubs.length === 1) return newSubs[0];
4173
+ const nre = new Regexp(Regexp.Op.CONCAT);
4174
+ nre.subs = newSubs;
4175
+ return nre;
3816
4176
  }
3817
4177
  static simplify1(op, flags, sub, re) {
3818
4178
  if (sub.op === Regexp.Op.EMPTY_MATCH) return sub;
@@ -3976,46 +4336,35 @@ var CharClass = class CharClass {
3976
4336
  result += "]";
3977
4337
  return result;
3978
4338
  }
3979
- static cmp(array, i, pivotFrom, pivotTo) {
3980
- const cmp = array[i] - pivotFrom;
3981
- return cmp !== 0 ? cmp : pivotTo - array[i + 1];
3982
- }
3983
- static qsortIntPair(array, left, right) {
3984
- const pivotIndex = ((left + right) / 2 | 0) & -2;
3985
- const pivotFrom = array[pivotIndex];
3986
- const pivotTo = array[pivotIndex + 1];
3987
- let i = left;
3988
- let j = right;
3989
- while (i <= j) {
3990
- while (i < right && CharClass.cmp(array, i, pivotFrom, pivotTo) < 0) i += 2;
3991
- while (j > left && CharClass.cmp(array, j, pivotFrom, pivotTo) > 0) j -= 2;
3992
- if (i <= j) {
3993
- if (i !== j) {
3994
- let temp = array[i];
3995
- array[i] = array[j];
3996
- array[j] = temp;
3997
- temp = array[i + 1];
3998
- array[i + 1] = array[j + 1];
3999
- array[j + 1] = temp;
4000
- }
4001
- i += 2;
4002
- j -= 2;
4003
- }
4339
+ static sortRanges(array, len) {
4340
+ const n = len >> 1;
4341
+ const order = new Array(n);
4342
+ for (let i = 0; i < n; i++) order[i] = i;
4343
+ order.sort((a, b) => array[2 * a] - array[2 * b] || array[2 * b + 1] - array[2 * a + 1]);
4344
+ const sorted = array.slice(0, len);
4345
+ for (let i = 0; i < n; i++) {
4346
+ array[2 * i] = sorted[2 * order[i]];
4347
+ array[2 * i + 1] = sorted[2 * order[i] + 1];
4004
4348
  }
4005
- if (left < j) CharClass.qsortIntPair(array, left, j);
4006
- if (i < right) CharClass.qsortIntPair(array, i, right);
4007
4349
  }
4008
4350
  constructor(r = Utils.emptyInts()) {
4009
4351
  this.r = r;
4010
4352
  this.len = r.length;
4011
4353
  }
4012
4354
  toArray() {
4013
- if (this.len === this.r.length) return this.r;
4014
- else return this.r.slice(0, this.len);
4355
+ if (this.r instanceof Int32Array) return this.len === this.r.length ? this.r : this.r.subarray(0, this.len);
4356
+ return new Int32Array(this.len === this.r.length ? this.r : this.r.slice(0, this.len));
4357
+ }
4358
+ toGrowableArray() {
4359
+ if (Array.isArray(this.r)) {
4360
+ this.r.length = this.len;
4361
+ return this.r;
4362
+ }
4363
+ return Array.from(this.r.subarray(0, this.len));
4015
4364
  }
4016
4365
  cleanClass() {
4017
4366
  if (this.len < 4) return this;
4018
- CharClass.qsortIntPair(this.r, 0, this.len - 2);
4367
+ CharClass.sortRanges(this.r, this.len);
4019
4368
  let w = 2;
4020
4369
  for (let i = 2; i < this.len; i += 2) {
4021
4370
  const lo = this.r[i];
@@ -4217,7 +4566,7 @@ var Parser = class Parser {
4217
4566
  static ERR_LARGE = "expression too large";
4218
4567
  static ERR_INVALID_CAPTURE_IN_LOOKBEHIND = "invalid capture in lookbehind";
4219
4568
  static MAX_HEIGHT = 1e3;
4220
- static MAX_SIZE = 3355443;
4569
+ static MAX_SIZE = 1398101;
4221
4570
  static MAX_RUNES = 33554432;
4222
4571
  static ANY_TABLE = new UnicodeRangeTable(new Uint32Array([
4223
4572
  0,
@@ -4359,14 +4708,17 @@ var Parser = class Parser {
4359
4708
  case Regexp.Op.ANY_CHAR_NOT_NL:
4360
4709
  if (Parser.matchRune(src, Codepoint.CODES.get("\n"))) dst.op = Regexp.Op.ANY_CHAR;
4361
4710
  break;
4362
- case Regexp.Op.CHAR_CLASS:
4363
- if (src.op === Regexp.Op.LITERAL) dst.runes = new CharClass(dst.runes).appendLiteral(src.runes[0], src.flags).toArray();
4364
- else dst.runes = new CharClass(dst.runes).appendClass(src.runes).toArray();
4711
+ case Regexp.Op.CHAR_CLASS: {
4712
+ const cc = new CharClass(Array.isArray(dst.runes) ? dst.runes : Array.from(dst.runes));
4713
+ if (src.op === Regexp.Op.LITERAL) cc.appendLiteral(src.runes[0], src.flags);
4714
+ else cc.appendClass(src.runes);
4715
+ dst.runes = cc.toGrowableArray();
4365
4716
  break;
4717
+ }
4366
4718
  case Regexp.Op.LITERAL:
4367
4719
  if (src.runes[0] === dst.runes[0] && src.flags === dst.flags) break;
4368
4720
  dst.op = Regexp.Op.CHAR_CLASS;
4369
- dst.runes = new CharClass().appendLiteral(dst.runes[0], dst.flags).appendLiteral(src.runes[0], src.flags).toArray();
4721
+ dst.runes = new CharClass().appendLiteral(dst.runes[0], dst.flags).appendLiteral(src.runes[0], src.flags).toGrowableArray();
4370
4722
  }
4371
4723
  }
4372
4724
  static parseEscape(t) {
@@ -4432,10 +4784,6 @@ var Parser = class Parser {
4432
4784
  if (t.lookingAt("\\")) return Parser.parseEscape(t);
4433
4785
  return t.pop();
4434
4786
  }
4435
- static concatRunes(x, y) {
4436
- for (let i = 0; i < y.length; i++) x.push(y[i]);
4437
- return x;
4438
- }
4439
4787
  static hasCapture(re) {
4440
4788
  if (re === null) return false;
4441
4789
  if (re.op === Regexp.Op.CAPTURE) return true;
@@ -4566,9 +4914,7 @@ var Parser = class Parser {
4566
4914
  const n = this.stack.length;
4567
4915
  let i = n;
4568
4916
  while (i > 0 && !Regexp.isPseudoOp(this.stack[i - 1].op)) i--;
4569
- const r = this.stack.slice(i, n);
4570
- this.stack = this.stack.slice(0, i);
4571
- return r;
4917
+ return this.stack.splice(i, n - i);
4572
4918
  }
4573
4919
  push(re) {
4574
4920
  this.numRunes += re.runes.length;
@@ -4593,7 +4939,8 @@ var Parser = class Parser {
4593
4939
  const re1 = this.stack[n - 1];
4594
4940
  const re2 = this.stack[n - 2];
4595
4941
  if (re1.op !== Regexp.Op.LITERAL || re2.op !== Regexp.Op.LITERAL || (re1.flags & RE2Flags.FOLD_CASE) !== (re2.flags & RE2Flags.FOLD_CASE)) return false;
4596
- re2.runes = Parser.concatRunes(re2.runes, re1.runes);
4942
+ if (!Array.isArray(re2.runes)) re2.runes = Array.from(re2.runes);
4943
+ for (let i = 0; i < re1.runes.length; i++) re2.runes.push(re1.runes[i]);
4597
4944
  if (r >= 0) {
4598
4945
  re1.runes = [r];
4599
4946
  re1.flags = flags;
@@ -4665,12 +5012,12 @@ var Parser = class Parser {
4665
5012
  }
4666
5013
  cleanAlt(re) {
4667
5014
  if (re.op === Regexp.Op.CHAR_CLASS) {
4668
- re.runes = new CharClass(re.runes).cleanClass().toArray();
5015
+ re.runes = new CharClass(Array.from(re.runes)).cleanClass().toArray();
4669
5016
  if (re.runes.length === 2 && re.runes[0] === 0 && re.runes[1] === Unicode.MAX_RUNE) {
4670
- re.runes = [];
5017
+ re.runes = /* @__PURE__ */ new Int32Array(0);
4671
5018
  re.op = Regexp.Op.ANY_CHAR;
4672
5019
  } else if (re.runes.length === 4 && re.runes[0] === 0 && re.runes[1] === Codepoint.CODES.get("\n") - 1 && re.runes[2] === Codepoint.CODES.get("\n") + 1 && re.runes[3] === Unicode.MAX_RUNE) {
4673
- re.runes = [];
5020
+ re.runes = /* @__PURE__ */ new Int32Array(0);
4674
5021
  re.op = Regexp.Op.ANY_CHAR_NOT_NL;
4675
5022
  }
4676
5023
  }
@@ -4935,13 +5282,14 @@ var Parser = class Parser {
4935
5282
  break;
4936
5283
  }
4937
5284
  case Codepoint.CODES.get("{"): {
4938
- repeatPos = t.pos();
5285
+ const before = t.pos();
4939
5286
  const minMax = Parser.parseRepeat(t);
4940
5287
  if (minMax < 0) {
4941
- t.rewindTo(repeatPos);
5288
+ t.rewindTo(before);
4942
5289
  this.literal(t.pop());
4943
5290
  break;
4944
5291
  }
5292
+ repeatPos = before;
4945
5293
  min = minMax >> 16;
4946
5294
  max = (minMax & Unicode.MAX_BMP) << 16 >> 16;
4947
5295
  this.repeat(Regexp.Op.REPEAT, min, max, repeatPos, t, lastRepeatPos);
@@ -5202,7 +5550,7 @@ var Parser = class Parser {
5202
5550
  if ((this.flags & RE2Flags.FOLD_CASE) === 0 || fold === null) cc.appendTableWithSign(tab, sign);
5203
5551
  else {
5204
5552
  const tmp = new CharClass().appendTable(tab).appendTable(fold).cleanClass().toArray();
5205
- cc.appendClassWithSign(tmp, sign);
5553
+ cc.appendClassWithSign(Array.from(tmp), sign);
5206
5554
  }
5207
5555
  return true;
5208
5556
  }
@@ -5313,6 +5661,7 @@ var RE2 = class RE2 {
5313
5661
  static compileImpl(expr, mode, longest) {
5314
5662
  let re = Parser.parse(expr, mode);
5315
5663
  const maxCap = re.maxCap();
5664
+ const namedGroups = re.namedGroups;
5316
5665
  re = Simplify.simplify(re);
5317
5666
  const prefilter = PrefilterTree.build(re);
5318
5667
  const prog = Compiler.compileRegexp(re);
@@ -5323,7 +5672,7 @@ var RE2 = class RE2 {
5323
5672
  re2.prefix = prefixStr;
5324
5673
  re2.prefixUTF8 = Utils.stringToUtf8ByteArray(re2.prefix);
5325
5674
  if (re2.prefix.length > 0) re2.prefixRune = re2.prefix.codePointAt(0);
5326
- re2.namedGroups = re.namedGroups;
5675
+ re2.namedGroups = namedGroups;
5327
5676
  return re2;
5328
5677
  }
5329
5678
  /**
@@ -5378,7 +5727,10 @@ var RE2 = class RE2 {
5378
5727
  }
5379
5728
  return [];
5380
5729
  }
5381
- executeEngine(input, pos, anchor, ncap) {
5730
+ createLookbehindState() {
5731
+ return this.prog.numLb > 0 ? new LookbehindState(this.prog) : null;
5732
+ }
5733
+ executeEngine(input, pos, anchor, ncap, lbState = null) {
5382
5734
  if (this.prefixComplete && (ncap === 0 || this.numSubexp === 0)) return this.matchPrefixComplete(input, pos, anchor, ncap);
5383
5735
  if (this.prefilter !== null && anchor === RE2Flags.UNANCHORED) {
5384
5736
  if (!this.prefilter.eval(input, pos)) return null;
@@ -5386,14 +5738,14 @@ var RE2 = class RE2 {
5386
5738
  if (this.onepass !== null) return OnePass.execute(this, input, pos, anchor, ncap);
5387
5739
  if (ncap > 0) {
5388
5740
  if (this.prog.numLb === 0 && input.endPos() <= Backtracker.maxBitStateLen(this.prog)) return Backtracker.execute(this, input, pos, anchor, ncap);
5389
- return this.doExecuteNFA(input, pos, anchor, ncap);
5741
+ return this.doExecuteNFA(input, pos, anchor, ncap, lbState);
5390
5742
  }
5391
5743
  if (this.prog.numLb === 0) {
5392
5744
  const dfaResult = this.dfa.match(input, pos, anchor);
5393
5745
  if (dfaResult !== null) return dfaResult ? [] : null;
5394
5746
  if (input.endPos() <= Backtracker.maxBitStateLen(this.prog)) return Backtracker.execute(this, input, pos, anchor, ncap);
5395
5747
  }
5396
- return this.doExecuteNFA(input, pos, anchor, ncap);
5748
+ return this.doExecuteNFA(input, pos, anchor, ncap, lbState);
5397
5749
  }
5398
5750
  /**
5399
5751
  * Returns the number of parenthesized subexpressions in this regular expression.
@@ -5419,11 +5771,11 @@ var RE2 = class RE2 {
5419
5771
  toString() {
5420
5772
  return this.expr;
5421
5773
  }
5422
- doExecuteNFA(input, pos, anchor, ncap) {
5774
+ doExecuteNFA(input, pos, anchor, ncap, lbState = null) {
5423
5775
  let m = this.get();
5424
5776
  if (!m) m = Machine.fromRE2(this);
5425
5777
  m.init(ncap);
5426
- const cap = m.match(input, pos, anchor) ? m.submatches() : null;
5778
+ const cap = m.match(input, pos, anchor, lbState) ? m.submatches() : null;
5427
5779
  this.put(m);
5428
5780
  return cap;
5429
5781
  }
@@ -5442,17 +5794,21 @@ var RE2 = class RE2 {
5442
5794
  * @param anchor the anchoring flag (UNANCHORED, ANCHOR_START, ANCHOR_BOTH)
5443
5795
  * @param group the array to fill with submatch positions
5444
5796
  * @param ngroup the number of array pairs to fill in
5797
+ * @param lbState optional state carried between successive matches over the same input (see
5798
+ * createLookbehindState); omit it to evaluate lookbehinds from the beginning of the input
5445
5799
  * @returns true if a match was found
5446
5800
  */
5447
- matchWithGroup(input, start, end, anchor, ngroup) {
5448
- if (!(input instanceof MatcherInputBase)) if (Utils.isByteArray(input)) input = MatcherInput.utf8(input);
5449
- else input = MatcherInput.utf16(input);
5450
- return this.matchMachineInput(input, start, end, anchor, ngroup);
5801
+ matchWithGroup(input, start, end, anchor, ngroup, lbState = null) {
5802
+ if (!(input instanceof MatcherInputBase)) {
5803
+ if (Utils.isByteArray(input)) input = MatcherInput.utf8(input);
5804
+ else input = MatcherInput.utf16(input);
5805
+ }
5806
+ return this.matchMachineInput(input, start, end, anchor, ngroup, lbState);
5451
5807
  }
5452
- matchMachineInput(input, start, end, anchor, ngroup) {
5808
+ matchMachineInput(input, start, end, anchor, ngroup, lbState = null) {
5453
5809
  if (start > end) return [false, null];
5454
5810
  const machineInput = input.isUTF16Encoding() ? MachineInput.fromUTF16(input.asCharSequence(), 0, end) : MachineInput.fromUTF8(input.asBytes(), 0, end);
5455
- const groupMatch = this.executeEngine(machineInput, start, anchor, 2 * ngroup);
5811
+ const groupMatch = this.executeEngine(machineInput, start, anchor, 2 * ngroup, lbState);
5456
5812
  if (groupMatch === null) return [false, null];
5457
5813
  return [true, groupMatch];
5458
5814
  }
@@ -5489,9 +5845,10 @@ var RE2 = class RE2 {
5489
5845
  let searchPos = 0;
5490
5846
  let out = "";
5491
5847
  const input = MachineInput.fromUTF16(src);
5848
+ const lbState = this.createLookbehindState();
5492
5849
  let numReplaces = 0;
5493
5850
  while (searchPos <= src.length) {
5494
- const a = this.executeEngine(input, searchPos, RE2Flags.UNANCHORED, 2);
5851
+ const a = this.executeEngine(input, searchPos, RE2Flags.UNANCHORED, 2, lbState);
5495
5852
  if (a === null || a.length === 0) break;
5496
5853
  out += src.substring(lastMatchEnd, a[0]);
5497
5854
  if (a[1] > lastMatchEnd || a[0] === 0) {
@@ -5525,8 +5882,9 @@ var RE2 = class RE2 {
5525
5882
  let pos = 0;
5526
5883
  let i = 0;
5527
5884
  let prevMatchEnd = -1;
5885
+ const lbState = this.createLookbehindState();
5528
5886
  while (i < n && pos <= end) {
5529
- const matches = this.executeEngine(input, pos, RE2Flags.UNANCHORED, this.prog.numCap);
5887
+ const matches = this.executeEngine(input, pos, RE2Flags.UNANCHORED, this.prog.numCap, lbState);
5530
5888
  if (matches === null || matches.length === 0) break;
5531
5889
  let accept = true;
5532
5890
  if (matches[1] === pos) {
@@ -5794,7 +6152,9 @@ var RE2 = class RE2 {
5794
6152
  */
5795
6153
  compile() {
5796
6154
  if (this.prog) return;
5797
- this.prog = Compiler.compileSet(this.regexps);
6155
+ const prog = Compiler.compileSet(this.regexps);
6156
+ if (prog.numInst() > Parser.MAX_SIZE) throw new RE2JSCompileException(`${Parser.ERR_LARGE}: the set compiles to ${prog.numInst()} instructions, more than ${Parser.MAX_SIZE}`);
6157
+ this.prog = prog;
5798
6158
  this.dfa = new DFA(this.prog, this.maxMem);
5799
6159
  this.dummyRe2 = {
5800
6160
  prog: this.prog,
@@ -17720,137 +18080,4 @@ function countEntropy(text) {
17720
18080
  return entropy;
17721
18081
  }
17722
18082
  //#endregion
17723
- //#region src/bypass/classify-edit.ts
17724
- const MAX_SCANNED_BYTES = 262144;
17725
- function classifyEdit(action, scope) {
17726
- const fields = findEditFields(action.toolName);
17727
- if (fields === null) return {
17728
- kind: "jev",
17729
- reason: "not a file-tool edit"
17730
- };
17731
- const worktree = findWorktree(action.target, scope.worktrees);
17732
- if (worktree === null) return {
17733
- kind: "jev",
17734
- reason: "target outside every in-scope worktree"
17735
- };
17736
- const path = relative(worktree, action.target).split(sep).join("/");
17737
- if (path.startsWith(".worktrees/")) return {
17738
- kind: "jev",
17739
- reason: "target in a nested worktree outside the scope"
17740
- };
17741
- if (action.checkout !== null && action.checkout !== worktree) return {
17742
- kind: "jev",
17743
- reason: "target in a checkout outside the scope"
17744
- };
17745
- const exclusion = [action.target, action.requested].some((each) => scope.protectedDirs.some((directory) => isWithin(each, directory))) ? "auto-mode configuration or state" : findExclusion(path) ?? findExclusion(toWorktreePath(action.requested, scope.worktrees));
17746
- if (exclusion !== null) return {
17747
- kind: "jev",
17748
- reason: `target is ${exclusion}`
17749
- };
17750
- const text = buildScanText(action, fields.content);
17751
- if (typeof text !== "string") return {
17752
- kind: "jev",
17753
- reason: text.reason
17754
- };
17755
- if (Buffer.byteLength(text, "utf8") > MAX_SCANNED_BYTES) return {
17756
- kind: "jev",
17757
- reason: "content larger than the secret scan reads"
17758
- };
17759
- const secret = findSecret({
17760
- text,
17761
- path
17762
- });
17763
- return secret === null ? {
17764
- kind: "bypass",
17765
- target: action.target
17766
- } : {
17767
- kind: "jev",
17768
- reason: `secret scan matched ${secret.rule}`
17769
- };
17770
- }
17771
- function findWorktree(target, worktrees) {
17772
- return worktrees.filter((worktree) => isWithin(target, worktree)).toSorted((left, right) => right.length - left.length)[0] ?? null;
17773
- }
17774
- function isWithin(path, directory) {
17775
- const offset = relative(directory, path);
17776
- return offset !== "" && !offset.startsWith("..") && !offset.startsWith(sep);
17777
- }
17778
- const EXCLUDED_PATHS = [
17779
- [".git", "git metadata"],
17780
- [".claude", "agent configuration"],
17781
- [".codex", "agent configuration"],
17782
- [".muse", "agent configuration"],
17783
- [".husky", "a hook file"],
17784
- [".githooks", "a hook file"],
17785
- [".vscode/tasks.json", "a hook file"],
17786
- [".github/workflows", "a CI workflow"],
17787
- [".circleci", "a CI workflow"],
17788
- [".ssh", "a credential file"],
17789
- [".aws", "a credential file"],
17790
- [".kube", "a credential file"],
17791
- [".docker", "a credential file"],
17792
- [".gnupg", "a credential file"]
17793
- ];
17794
- const EXCLUDED_NAMES = [
17795
- [/^(?:agents|claude)(?:\.[\w-]+)?\.md$/iu, "agent configuration"],
17796
- [/^\.mcp\.json$/iu, "agent configuration"],
17797
- [/^settings(?:\.[\w-]+)?\.json$/iu, "a settings file"],
17798
- [/^(?:hooks\.json|\.?lefthook(?:-local)?\.ya?ml|\.pre-commit-config\.ya?ml)$/iu, "a hook file"],
17799
- [/^(?:package\.json|\.?bunfig\.toml|\.gitattributes)$/iu, "a hook file"],
17800
- [/^\.gitlab-ci\.ya?ml$/iu, "a CI workflow"],
17801
- [/^\.env(?:\..*)?$|^\.envrc$/iu, "an env file"],
17802
- [/^(?:\.netrc|\.npmrc|\.pypirc|\.git-credentials|\.dockercfg|kubeconfig)$/iu, "a credential file"],
17803
- [/^credentials(?:\.\w+)?$|^secrets?\.(?:json|ya?ml|toml|env)$/iu, "a credential file"],
17804
- [/^id_(?:rsa|dsa|ecdsa|ed25519)|\.(?:pem|key|p12|pfx|jks|keystore|tfvars)$/iu, "a credential file"]
17805
- ];
17806
- function findExclusion(path) {
17807
- const lower = path.toLowerCase();
17808
- const excludedPath = EXCLUDED_PATHS.find(([prefix]) => lower === prefix || lower.endsWith(`/${prefix}`) || lower.startsWith(`${prefix}/`) || lower.includes(`/${prefix}/`));
17809
- if (excludedPath !== void 0) return excludedPath[1];
17810
- const name = basename(path);
17811
- return EXCLUDED_NAMES.find(([pattern]) => pattern.test(name))?.[1] ?? null;
17812
- }
17813
- function toWorktreePath(path, worktrees) {
17814
- const worktree = findWorktree(path, worktrees);
17815
- return worktree === null ? path : relative(worktree, path).split(sep).join("/");
17816
- }
17817
- function buildScanText(action, field) {
17818
- const content = action.toolInput[field] ?? "";
17819
- if (typeof content !== "string") return { reason: "edit content is not text" };
17820
- if (action.toolName !== "Edit") return content;
17821
- const old = action.toolInput["old_string"];
17822
- if (typeof old !== "string" || old === "" || action.current === null) return { reason: "the edit cannot be read in the context of its file" };
17823
- const parts = action.current.split(old);
17824
- if (parts.length === 1) return { reason: "the edit text is not in the file" };
17825
- const replaced = action.toolInput["replace_all"] === true ? parts.length - 1 : 1;
17826
- const spans = [];
17827
- let produced = parts[0] ?? "";
17828
- for (let index = 1; index < parts.length; index += 1) {
17829
- const isReplaced = index <= replaced;
17830
- if (isReplaced) spans.push({
17831
- start: produced.length,
17832
- end: produced.length + content.length
17833
- });
17834
- produced += `${isReplaced ? content : old}${parts[index] ?? ""}`;
17835
- }
17836
- return collectContext(produced, spans);
17837
- }
17838
- const CONTEXT_LINES = 12;
17839
- function collectContext(text, spans) {
17840
- const lines = text.split("\n");
17841
- const starts = [];
17842
- let offset = 0;
17843
- for (const line of lines) {
17844
- starts.push(offset);
17845
- offset += line.length + 1;
17846
- }
17847
- const keep = /* @__PURE__ */ new Set();
17848
- for (const span of spans) {
17849
- const first = starts.findLastIndex((start) => start <= span.start);
17850
- const last = starts.findLastIndex((start) => start <= span.end);
17851
- for (let line = first - CONTEXT_LINES; line <= last + CONTEXT_LINES; line += 1) keep.add(line);
17852
- }
17853
- return lines.filter((_, index) => keep.has(index)).join("\n");
17854
- }
17855
- //#endregion
17856
- export { classifyEdit };
18083
+ export { findSecret as t };