re2js 2.8.4 → 2.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -228,6 +228,37 @@ matchString.group() // 'e'
228
228
  matchString.find(7) // false
229
229
  ```
230
230
 
231
+ ### Executing a Search (`exec`)
232
+
233
+ If you want a native, 1:1 drop-in replacement for JavaScript's `RegExp.prototype.exec()`, you can use the `.exec()` method.
234
+
235
+ Instead of dealing with a stateful `Matcher` object, `exec()` performs a single search and returns a standard `RegExpExecArray`-shaped result, or `null` if no match is found. It includes the `.index`, `.input`, and `.groups` properties, and accurately maps unmatched optional capture groups to `undefined` (just like native JavaScript).
236
+
237
+ ```js
238
+ import { RE2JS } from 're2js'
239
+
240
+ const re = RE2JS.compile('(?P<first>\\w+) (?:(?P<middle>\\w+) )?(?P<last>\\w+)');
241
+ const result = re.exec('John Doe');
242
+
243
+ if (result !== null) {
244
+ console.log(result[0]); // "John Doe" (Full match)
245
+ console.log(result[1]); // "John" (Group 1)
246
+ console.log(result[2]); // undefined (Group 2 didn't match)
247
+ console.log(result[3]); // "Doe" (Group 3)
248
+
249
+ console.log(result.index); // 0
250
+ console.log(result.input); // "John Doe"
251
+
252
+ // Named groups dictionary
253
+ console.log(result.groups.first); // "John"
254
+ console.log(result.groups.middle); // undefined
255
+ console.log(result.groups.last); // "Doe"
256
+ }
257
+
258
+ ```
259
+
260
+ ***Performance Note:** If you are running `exec()` inside a `while` loop to manually extract multiple matches globally, it is highly recommended to use `.matchAll()` instead, as it is cleaner, strictly stateless, and avoids infinite loop pitfalls.*
261
+
231
262
  ### Iterating Over Matches (`matchAll`)
232
263
 
233
264
  For a more modern, JavaScript-native developer experience, RE2JS provides a `.matchAll()` method. This returns an ES6 `IterableIterator`, allowing you to safely and cleanly iterate over matches using `for...of` loops or the array spread operator `[...]`.
package/build/index.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
  * re2js
3
3
  * RE2JS is the JavaScript port of RE2, a regular expression engine that provides linear time matching
4
4
  *
5
- * @version v2.8.4
5
+ * @version v2.8.6
6
6
  * @author Oleksii Vasyliev
7
7
  * @homepage https://github.com/le0pard/re2js#readme
8
8
  * @repository github:le0pard/re2js
@@ -708,7 +708,7 @@ var Utils = class Utils {
708
708
  static stringToUtf8ByteArray(str) {
709
709
  if (globalThis.TextEncoder) {
710
710
  if (!cachedNativeEncoder) cachedNativeEncoder = new TextEncoder();
711
- return Utils.toArray(cachedNativeEncoder.encode(str));
711
+ return cachedNativeEncoder.encode(str);
712
712
  } else {
713
713
  let out = [], p = 0;
714
714
  for (let i = 0; i < str.length; i++) {
@@ -1246,7 +1246,7 @@ var Matcher = class Matcher {
1246
1246
  }
1247
1247
  /**
1248
1248
  * Resets the {@code Matcher} and changes the input.
1249
- * @param {MatcherInputBase} input
1249
+ * @param {string|number[]|Uint8Array|MatcherInputBase} input
1250
1250
  * @returns {Matcher} the {@code Matcher} itself, for chained method calls
1251
1251
  */
1252
1252
  resetMatcherInput(input) {
@@ -1402,7 +1402,10 @@ var Matcher = class Matcher {
1402
1402
  */
1403
1403
  genMatch(startByte, anchor) {
1404
1404
  const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, 1);
1405
- if (!res[0]) return false;
1405
+ if (!res[0]) {
1406
+ this.hasMatch = false;
1407
+ return false;
1408
+ }
1406
1409
  this.groups = res[1];
1407
1410
  this.hasMatch = true;
1408
1411
  this.hasGroups = this.patternGroupCount === 0;
@@ -1465,43 +1468,47 @@ var Matcher = class Matcher {
1465
1468
  let res = "";
1466
1469
  let last = 0;
1467
1470
  const m = replacement.length;
1468
- for (let i = 0; i < m - 1; i++) {
1469
- if (replacement.codePointAt(i) === Codepoint.CODES.get("\\")) {
1471
+ let i = 0;
1472
+ while (i < m) {
1473
+ const cCode = replacement.codePointAt(i);
1474
+ if (cCode === Codepoint.CODES.get("\\")) {
1470
1475
  if (last < i) res += replacement.substring(last, i);
1471
1476
  i++;
1477
+ if (i >= m) throw new RE2JSGroupException("character to be escaped is missing");
1472
1478
  last = i;
1479
+ i++;
1473
1480
  continue;
1474
1481
  }
1475
- if (replacement.codePointAt(i) === Codepoint.CODES.get("$")) {
1476
- let c = replacement.codePointAt(i + 1);
1477
- if (Codepoint.CODES.get("0") <= c && c <= Codepoint.CODES.get("9")) {
1478
- let n = c - Codepoint.CODES.get("0");
1479
- if (last < i) res += replacement.substring(last, i);
1480
- for (i += 2; i < m; i++) {
1481
- c = replacement.codePointAt(i);
1482
- if (c < Codepoint.CODES.get("0") || c > Codepoint.CODES.get("9") || n * 10 + c - Codepoint.CODES.get("0") > this.patternGroupCount) break;
1483
- n = n * 10 + c - Codepoint.CODES.get("0");
1482
+ if (cCode === Codepoint.CODES.get("$")) {
1483
+ if (last < i) res += replacement.substring(last, i);
1484
+ if (i + 1 >= m) throw new RE2JSGroupException("Illegal group reference: group index is missing");
1485
+ const nextCode = replacement.codePointAt(i + 1);
1486
+ if (Codepoint.CODES.get("0") <= nextCode && nextCode <= Codepoint.CODES.get("9")) {
1487
+ let n = nextCode - Codepoint.CODES.get("0");
1488
+ let j = i + 2;
1489
+ for (; j < m; j++) {
1490
+ const digit = replacement.codePointAt(j);
1491
+ if (digit < Codepoint.CODES.get("0") || digit > Codepoint.CODES.get("9") || n * 10 + digit - Codepoint.CODES.get("0") > this.patternGroupCount) break;
1492
+ n = n * 10 + digit - Codepoint.CODES.get("0");
1484
1493
  }
1485
1494
  if (n > this.patternGroupCount) throw new RE2JSGroupException(`n > number of groups: ${n}`);
1486
1495
  const group = this.group(n);
1487
1496
  if (group !== null) res += group;
1497
+ i = j;
1488
1498
  last = i;
1489
- i--;
1490
- continue;
1491
- } else if (c === Codepoint.CODES.get("{")) {
1492
- if (last < i) res += replacement.substring(last, i);
1493
- i++;
1494
- let j = i + 1;
1495
- while (j < replacement.length && replacement.codePointAt(j) !== Codepoint.CODES.get("}") && replacement.codePointAt(j) !== Codepoint.CODES.get(" ")) j++;
1496
- if (j === replacement.length || replacement.codePointAt(j) !== Codepoint.CODES.get("}")) throw new RE2JSGroupException("named capture group is missing trailing '}'");
1497
- const groupName = replacement.substring(i + 1, j);
1499
+ } else if (nextCode === Codepoint.CODES.get("{")) {
1500
+ let j = i + 2;
1501
+ while (j < m && replacement.codePointAt(j) !== Codepoint.CODES.get("}")) j++;
1502
+ if (j >= m) throw new RE2JSGroupException("named capture group is missing trailing '}'");
1503
+ const groupName = replacement.substring(i + 2, j);
1498
1504
  const groupVal = this.group(groupName);
1499
1505
  if (groupVal !== null) res += groupVal;
1500
- last = j + 1;
1501
- i = j;
1502
- continue;
1503
- }
1506
+ i = j + 1;
1507
+ last = i;
1508
+ } else throw new RE2JSGroupException("Illegal group reference");
1509
+ continue;
1504
1510
  }
1511
+ i++;
1505
1512
  }
1506
1513
  if (last < m) res += replacement.substring(last, m);
1507
1514
  return res;
@@ -1812,18 +1819,18 @@ var Inst = class Inst {
1812
1819
  };
1813
1820
  //#endregion
1814
1821
  //#region src/Machine.js
1815
- var Thread = class {
1816
- constructor() {
1817
- this.inst = null;
1818
- this.cap = null;
1819
- }
1820
- };
1821
1822
  var Queue = class {
1822
1823
  constructor(numInst) {
1823
1824
  this.sparse = new Int32Array(numInst);
1824
1825
  this.densePcs = new Int32Array(numInst);
1825
- this.denseThreads = new Array(numInst);
1826
+ this.denseCaps = null;
1826
1827
  this.size = 0;
1828
+ this.ncap = 0;
1829
+ }
1830
+ init(ncap) {
1831
+ this.ncap = ncap;
1832
+ const needed = this.densePcs.length * ncap;
1833
+ if (!this.denseCaps || this.denseCaps.length < needed) this.denseCaps = new Int32Array(needed);
1827
1834
  }
1828
1835
  contains(pc) {
1829
1836
  const j = this.sparse[pc];
@@ -1835,12 +1842,10 @@ var Queue = class {
1835
1842
  add(pc) {
1836
1843
  const j = this.size++;
1837
1844
  this.sparse[pc] = j;
1838
- this.denseThreads[j] = null;
1839
1845
  this.densePcs[j] = pc;
1840
1846
  return j;
1841
1847
  }
1842
1848
  clear() {
1843
- for (let i = 0; i < this.size; i++) this.denseThreads[i] = null;
1844
1849
  this.size = 0;
1845
1850
  }
1846
1851
  toString() {
@@ -1854,15 +1859,12 @@ var Queue = class {
1854
1859
  }
1855
1860
  };
1856
1861
  var Machine = class Machine {
1857
- static THREADS_CHUNK_SIZE = 128;
1858
1862
  static fromRE2(re2) {
1859
1863
  const m = new Machine();
1860
1864
  m.prog = re2.prog;
1861
1865
  m.re2 = re2;
1862
1866
  m.q0 = new Queue(m.prog.numInst());
1863
1867
  m.q1 = new Queue(m.prog.numInst());
1864
- m.pool = [];
1865
- m.poolSize = 0;
1866
1868
  m.matched = false;
1867
1869
  m.matchcap = new Int32Array(m.prog.numCap < 2 ? 2 : m.prog.numCap);
1868
1870
  m.ncap = 0;
@@ -1876,8 +1878,6 @@ var Machine = class Machine {
1876
1878
  this.re2 = null;
1877
1879
  this.q0 = null;
1878
1880
  this.q1 = null;
1879
- this.pool = [];
1880
- this.poolSize = 0;
1881
1881
  this.matched = false;
1882
1882
  this.matchcap = null;
1883
1883
  this.ncap = 0;
@@ -1885,51 +1885,19 @@ var Machine = class Machine {
1885
1885
  }
1886
1886
  init(ncap) {
1887
1887
  this.ncap = ncap;
1888
- if (ncap > this.matchcap.length) this.initNewCap(ncap);
1889
- else this.resetCap();
1888
+ if (ncap > this.matchcap.length) this.matchcap = new Int32Array(ncap).fill(-1);
1889
+ else this.matchcap.fill(-1);
1890
+ this.q0.init(ncap);
1891
+ this.q1.init(ncap);
1890
1892
  if (this.prog.numLb > 0) {
1891
1893
  if (!this.lbTable || this.lbTable.length < this.prog.numLb + 1) this.lbTable = new Int32Array(this.prog.numLb + 1);
1892
1894
  this.lbTable.fill(-1);
1893
1895
  }
1894
1896
  }
1895
- resetCap() {
1896
- for (let i = 0; i < this.poolSize; i++) this.pool[i].cap.fill(-1);
1897
- }
1898
- initNewCap(ncap) {
1899
- for (let i = 0; i < this.poolSize; i++) {
1900
- const t = this.pool[i];
1901
- t.cap = new Int32Array(ncap).fill(-1);
1902
- }
1903
- this.matchcap = new Int32Array(ncap).fill(-1);
1904
- }
1905
1897
  submatches() {
1906
1898
  if (this.ncap === 0) return Utils.emptyInts();
1907
1899
  return Utils.toArray(this.matchcap.subarray(0, this.ncap));
1908
1900
  }
1909
- alloc(inst) {
1910
- if (this.poolSize === 0) {
1911
- const capLen = this.matchcap.length;
1912
- for (let i = 0; i < Machine.THREADS_CHUNK_SIZE; i++) {
1913
- const t = new Thread();
1914
- t.cap = new Int32Array(capLen);
1915
- this.pool[this.poolSize++] = t;
1916
- }
1917
- }
1918
- this.poolSize--;
1919
- const t = this.pool[this.poolSize];
1920
- t.inst = inst;
1921
- return t;
1922
- }
1923
- freeQueue(queue, from = 0) {
1924
- for (let i = from; i < queue.size; i++) {
1925
- const t = queue.denseThreads[i];
1926
- if (t !== null) this.pool[this.poolSize++] = t;
1927
- }
1928
- queue.clear();
1929
- }
1930
- freeThread(t) {
1931
- this.pool[this.poolSize++] = t;
1932
- }
1933
1901
  match(input, pos, anchor) {
1934
1902
  const startCond = this.re2.cond;
1935
1903
  if (startCond === Utils.EMPTY_ALL) return false;
@@ -1968,13 +1936,14 @@ var Machine = class Machine {
1968
1936
  r = input.step(currentPos + width);
1969
1937
  rune1 = r >> 3;
1970
1938
  width1 = r & 7;
1939
+ flag = input.context(currentPos);
1971
1940
  }
1972
1941
  }
1973
- 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, flag, null);
1942
+ 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);
1974
1943
  if (!this.matched && (currentPos === 0 || anchor === RE2Flags.UNANCHORED)) {
1975
1944
  if (currentPos >= matchStartPos) {
1976
1945
  if (this.ncap > 0) this.matchcap[0] = currentPos;
1977
- this.add(runq, this.prog.start, currentPos, this.matchcap, flag, null);
1946
+ this.add(runq, this.prog.start, currentPos, this.matchcap, 0, flag);
1978
1947
  }
1979
1948
  }
1980
1949
  const nextPos = currentPos + width;
@@ -1994,7 +1963,7 @@ var Machine = class Machine {
1994
1963
  runq = nextq;
1995
1964
  nextq = tmpq;
1996
1965
  }
1997
- this.freeQueue(nextq);
1966
+ nextq.clear();
1998
1967
  return this.matched;
1999
1968
  }
2000
1969
  matchSet(input, pos, anchor) {
@@ -2022,16 +1991,16 @@ var Machine = class Machine {
2022
1991
  if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 && currentPos !== 0) break;
2023
1992
  if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && currentPos !== 0) break;
2024
1993
  }
2025
- 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, flag, null);
1994
+ 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);
2026
1995
  if (currentPos === 0 || anchor === RE2Flags.UNANCHORED) {
2027
- if (currentPos >= matchStartPos) this.add(runq, this.prog.start, currentPos, this.matchcap, flag, null);
1996
+ if (currentPos >= matchStartPos) this.add(runq, this.prog.start, currentPos, this.matchcap, 0, flag);
2028
1997
  }
2029
1998
  const nextPos = currentPos + width;
2030
1999
  flag = input.context(nextPos);
2031
2000
  for (let j = 0; j < runq.size; j++) {
2032
- let t = runq.denseThreads[j];
2033
- if (t === null) continue;
2034
- const i = t.inst;
2001
+ const pc = runq.densePcs[j];
2002
+ const i = this.prog.inst[pc];
2003
+ const capOffset = j * this.ncap;
2035
2004
  let add = false;
2036
2005
  switch (i.op) {
2037
2006
  case Inst.MATCH:
@@ -2048,15 +2017,11 @@ var Machine = class Machine {
2048
2017
  add = true;
2049
2018
  break;
2050
2019
  case Inst.RUNE_ANY_NOT_NL:
2051
- add = rune !== Codepoint.CODES.get("\n");
2020
+ add = rune !== 10;
2052
2021
  break;
2053
- default: throw new RE2JSInternalException("bad inst");
2054
- }
2055
- if (add) t = this.add(nextq, i.out, nextPos, t.cap, flag, t);
2056
- if (t !== null) {
2057
- this.freeThread(t);
2058
- runq.denseThreads[j] = null;
2022
+ default: continue;
2059
2023
  }
2024
+ if (add) this.add(nextq, i.out, nextPos, runq.denseCaps, capOffset, flag);
2060
2025
  }
2061
2026
  runq.clear();
2062
2027
  if (width === 0) break;
@@ -2072,28 +2037,25 @@ var Machine = class Machine {
2072
2037
  runq = nextq;
2073
2038
  nextq = tmpq;
2074
2039
  }
2075
- this.freeQueue(nextq);
2040
+ nextq.clear();
2076
2041
  return Array.from(matches).sort((a, b) => a - b);
2077
2042
  }
2078
2043
  step(runq, nextq, pos, nextPos, c, nextCond, anchor, atEnd) {
2079
2044
  const longest = this.re2.longest;
2080
2045
  for (let j = 0; j < runq.size; j++) {
2081
- let t = runq.denseThreads[j];
2082
- if (t === null) continue;
2083
- if (longest && this.matched && this.ncap > 0 && this.matchcap[0] < t.cap[0]) {
2084
- this.freeThread(t);
2085
- continue;
2086
- }
2087
- const i = t.inst;
2046
+ const pc = runq.densePcs[j];
2047
+ const capOffset = j * this.ncap;
2048
+ if (longest && this.matched && this.ncap > 0 && this.matchcap[0] < runq.denseCaps[capOffset]) continue;
2049
+ const i = this.prog.inst[pc];
2088
2050
  let add = false;
2089
2051
  switch (i.op) {
2090
2052
  case Inst.MATCH:
2091
2053
  if (anchor === RE2Flags.ANCHOR_BOTH && !atEnd) break;
2092
2054
  if (this.ncap > 0 && (!longest || !this.matched || this.matchcap[1] < pos)) {
2093
- t.cap[1] = pos;
2094
- this.matchcap.set(t.cap.subarray(0, this.ncap));
2055
+ runq.denseCaps[capOffset + 1] = pos;
2056
+ for (let k = 0; k < this.ncap; k++) this.matchcap[k] = runq.denseCaps[capOffset + k];
2095
2057
  }
2096
- if (!longest) this.freeQueue(runq, j + 1);
2058
+ if (!longest) runq.size = 0;
2097
2059
  this.matched = true;
2098
2060
  break;
2099
2061
  case Inst.RUNE:
@@ -2106,29 +2068,25 @@ var Machine = class Machine {
2106
2068
  add = true;
2107
2069
  break;
2108
2070
  case Inst.RUNE_ANY_NOT_NL:
2109
- add = c !== Codepoint.CODES.get("\n");
2071
+ add = c !== 10;
2110
2072
  break;
2111
- default: throw new RE2JSInternalException("bad inst");
2112
- }
2113
- if (add) t = this.add(nextq, i.out, nextPos, t.cap, nextCond, t);
2114
- if (t !== null) {
2115
- this.freeThread(t);
2116
- runq.denseThreads[j] = null;
2073
+ default: continue;
2117
2074
  }
2075
+ if (add) this.add(nextq, i.out, nextPos, runq.denseCaps, capOffset, nextCond);
2118
2076
  }
2119
2077
  runq.clear();
2120
2078
  }
2121
- add(q, pc, pos, cap, cond, t) {
2079
+ add(q, pc, pos, capArray, capOffset, cond) {
2122
2080
  while (true) {
2123
- if (pc === 0) return t;
2124
- if (q.contains(pc)) return t;
2081
+ if (pc === 0) return;
2082
+ if (q.contains(pc)) return;
2125
2083
  const d = q.add(pc);
2126
2084
  const inst = this.prog.inst[pc];
2127
2085
  switch (inst.op) {
2128
- case Inst.FAIL: return t;
2086
+ case Inst.FAIL: return;
2129
2087
  case Inst.ALT:
2130
2088
  case Inst.ALT_MATCH:
2131
- t = this.add(q, inst.out, pos, cap, cond, t);
2089
+ this.add(q, inst.out, pos, capArray, capOffset, cond);
2132
2090
  pc = inst.arg;
2133
2091
  continue;
2134
2092
  case Inst.EMPTY_WIDTH:
@@ -2136,16 +2094,16 @@ var Machine = class Machine {
2136
2094
  pc = inst.out;
2137
2095
  continue;
2138
2096
  }
2139
- return t;
2097
+ return;
2140
2098
  case Inst.NOP:
2141
2099
  pc = inst.out;
2142
2100
  continue;
2143
2101
  case Inst.CAPTURE: if (inst.arg < this.ncap) {
2144
- const opos = cap[inst.arg];
2145
- cap[inst.arg] = pos;
2146
- this.add(q, inst.out, pos, cap, cond, null);
2147
- cap[inst.arg] = opos;
2148
- return t;
2102
+ const opos = capArray[capOffset + inst.arg];
2103
+ capArray[capOffset + inst.arg] = pos;
2104
+ this.add(q, inst.out, pos, capArray, capOffset, cond);
2105
+ capArray[capOffset + inst.arg] = opos;
2106
+ return;
2149
2107
  } else {
2150
2108
  pc = inst.out;
2151
2109
  continue;
@@ -2164,19 +2122,18 @@ var Machine = class Machine {
2164
2122
  pc = inst.out;
2165
2123
  continue;
2166
2124
  }
2167
- return t;
2125
+ return;
2168
2126
  case Inst.MATCH:
2169
2127
  case Inst.RUNE:
2170
2128
  case Inst.RUNE1:
2171
2129
  case Inst.RUNE_ANY:
2172
2130
  case Inst.RUNE_ANY_NOT_NL:
2173
- if (t === null) t = this.alloc(inst);
2174
- else t.inst = inst;
2175
- if (this.ncap > 0 && t.cap !== cap) for (let c = 0; c < this.ncap; c++) t.cap[c] = cap[c];
2176
- q.denseThreads[d] = t;
2177
- t = null;
2178
- return t;
2179
- default: throw new Error("unhandled");
2131
+ if (this.ncap > 0) {
2132
+ const destOffset = d * this.ncap;
2133
+ for (let c = 0; c < this.ncap; c++) q.denseCaps[destOffset + c] = capArray[capOffset + c];
2134
+ }
2135
+ return;
2136
+ default: throw new RE2JSInternalException("unhandled");
2180
2137
  }
2181
2138
  }
2182
2139
  }
@@ -2773,7 +2730,9 @@ const makeOnePass = (p) => {
2773
2730
  m[pc] = true;
2774
2731
  inst.op = Inst.ALT_MATCH;
2775
2732
  }
2776
- const mergeRes = mergeRuneSets(onePassRunes[inst.out] || [], onePassRunes[inst.arg] || [], inst.out, inst.arg);
2733
+ const leftRunes = onePassRunes[inst.out] || [];
2734
+ const rightRunes = onePassRunes[inst.arg] || [];
2735
+ const mergeRes = mergeRuneSets(leftRunes, rightRunes, inst.out, inst.arg);
2777
2736
  if (!mergeRes) return false;
2778
2737
  onePassRunes[pc] = mergeRes.merged;
2779
2738
  inst.next = new Uint32Array(mergeRes.next);
@@ -5365,24 +5324,6 @@ var Parser = class Parser {
5365
5324
  };
5366
5325
  //#endregion
5367
5326
  //#region src/RE2.js
5368
- var AtomicReference = class {
5369
- constructor(initialValue) {
5370
- this.value = initialValue;
5371
- }
5372
- get() {
5373
- return this.value;
5374
- }
5375
- set(newValue) {
5376
- this.value = newValue;
5377
- }
5378
- compareAndSet(expect, update) {
5379
- if (this.value === expect) {
5380
- this.value = update;
5381
- return true;
5382
- }
5383
- return false;
5384
- }
5385
- };
5386
5327
  /**
5387
5328
  * An RE2 class instance is a compiled representation of an RE2 regular expression, independent of
5388
5329
  * the public Java-like Pattern/Matcher API.
@@ -5471,7 +5412,7 @@ var RE2 = class RE2 {
5471
5412
  this.prefixUTF8 = null;
5472
5413
  this.prefixComplete = false;
5473
5414
  this.prefixRune = 0;
5474
- this.pooled = new AtomicReference();
5415
+ this.machinePool = [];
5475
5416
  this.dfa = new DFA(this.prog);
5476
5417
  this.onepass = OnePass.compile(this.prog);
5477
5418
  this.prefilter = null;
@@ -5535,42 +5476,23 @@ var RE2 = class RE2 {
5535
5476
  return this.prog.numInst();
5536
5477
  }
5537
5478
  get() {
5538
- let head;
5539
- do
5540
- head = this.pooled.get();
5541
- while (head && !this.pooled.compareAndSet(head, head.next));
5542
- return head;
5479
+ return this.machinePool.length > 0 ? this.machinePool.pop() : null;
5543
5480
  }
5544
5481
  reset() {
5545
- this.pooled.set(null);
5546
- }
5547
- put(m, isNew) {
5548
- let head = this.pooled.get();
5549
- do {
5550
- head = this.pooled.get();
5551
- if (!isNew && head) {
5552
- m = Machine.fromMachine(m);
5553
- isNew = true;
5554
- }
5555
- if (m.next !== head) m.next = head;
5556
- } while (!this.pooled.compareAndSet(head, m));
5482
+ this.machinePool.length = 0;
5483
+ }
5484
+ put(m) {
5485
+ this.machinePool.push(m);
5557
5486
  }
5558
5487
  toString() {
5559
5488
  return this.expr;
5560
5489
  }
5561
5490
  doExecuteNFA(input, pos, anchor, ncap) {
5562
5491
  let m = this.get();
5563
- let isNew = false;
5564
- if (!m) {
5565
- m = Machine.fromRE2(this);
5566
- isNew = true;
5567
- } else if (m.next !== null) {
5568
- m = Machine.fromMachine(m);
5569
- isNew = true;
5570
- }
5492
+ if (!m) m = Machine.fromRE2(this);
5571
5493
  m.init(ncap);
5572
5494
  const cap = m.match(input, pos, anchor) ? m.submatches() : null;
5573
- this.put(m, isNew);
5495
+ this.put(m);
5574
5496
  return cap;
5575
5497
  }
5576
5498
  match(s) {
@@ -6366,6 +6288,33 @@ var RE2JS = class RE2JS {
6366
6288
  return this.re2Input.executeEngine(machineInput, 0, RE2Flags.ANCHOR_BOTH, 0) !== null;
6367
6289
  }
6368
6290
  /**
6291
+ * Executes a search for a match in a specified string.
6292
+ * Returns a result array, or null if no match is found.
6293
+ * The returned array perfectly mirrors standard JavaScript `RegExpExecArray`,
6294
+ * including `.index`, `.input`, and `.groups` properties.
6295
+ *
6296
+ * @param {string|number[]|Uint8Array} input the input string or byte array
6297
+ * @returns {Array|null} the match array with index, input, and groups properties, or null
6298
+ */
6299
+ exec(input) {
6300
+ const m = this.matcher(input);
6301
+ if (!m.find()) return null;
6302
+ const result = [m.group(0)];
6303
+ for (let i = 1; i <= m.groupCount(); i++) {
6304
+ const val = m.group(i);
6305
+ result.push(val === null ? void 0 : val);
6306
+ }
6307
+ result.index = m.start(0);
6308
+ result.input = input;
6309
+ const namedGroups = this.namedGroups();
6310
+ if (Object.keys(namedGroups).length > 0) {
6311
+ const parsedGroups = m.getNamedGroups();
6312
+ for (const key in parsedGroups) if (parsedGroups[key] === null) parsedGroups[key] = void 0;
6313
+ result.groups = parsedGroups;
6314
+ } else result.groups = void 0;
6315
+ return result;
6316
+ }
6317
+ /**
6369
6318
  * Splits input around instances of the regular expression. It returns an array giving the strings
6370
6319
  * that occur before, between, and after instances of the regular expression.
6371
6320
  *
@@ -6409,7 +6358,7 @@ var RE2JS = class RE2JS {
6409
6358
  }
6410
6359
  result.push(m.substring(last, m.inputLength()));
6411
6360
  }
6412
- if (limit !== 0 || result.length === 0) result.push(m.substring(last, m.inputLength()));
6361
+ if (limit !== 0 || result.length === 0 && !(last === m.inputLength() && last > 0)) result.push(m.substring(last, m.inputLength()));
6413
6362
  return result;
6414
6363
  }
6415
6364
  /**
@@ -6417,7 +6366,7 @@ var RE2JS = class RE2JS {
6417
6366
  * including capturing groups.
6418
6367
  *
6419
6368
  * @param {string|number[]|Uint8Array} input the input string or byte array
6420
- * @returns {IterableIterator<Array>}
6369
+ * @returns {IterableIterator<RegExpMatchArray>}
6421
6370
  */
6422
6371
  *matchAll(input) {
6423
6372
  const m = this.matcher(input);
package/build/index.d.cts CHANGED
@@ -221,10 +221,10 @@ export class Matcher {
221
221
  anchorFlag: number;
222
222
  /**
223
223
  * Resets the {@code Matcher} and changes the input.
224
- * @param {MatcherInputBase} input
224
+ * @param {string|number[]|Uint8Array|MatcherInputBase} input
225
225
  * @returns {Matcher} the {@code Matcher} itself, for chained method calls
226
226
  */
227
- resetMatcherInput(input: MatcherInputBase): Matcher;
227
+ resetMatcherInput(input: string | number[] | Uint8Array | MatcherInputBase): Matcher;
228
228
  matcherInput: MatcherInputBase;
229
229
  /**
230
230
  * Returns the start of the named group of the most recent match, or -1 if the group was not
@@ -503,7 +503,7 @@ declare class RE2 {
503
503
  prefixUTF8: any;
504
504
  prefixComplete: boolean;
505
505
  prefixRune: number;
506
- pooled: AtomicReference;
506
+ machinePool: any[];
507
507
  dfa: DFA;
508
508
  onepass: {
509
509
  start: any;
@@ -523,7 +523,7 @@ declare class RE2 {
523
523
  numberOfInstructions(): any;
524
524
  get(): any;
525
525
  reset(): void;
526
- put(m: any, isNew: any): void;
526
+ put(m: any): void;
527
527
  toString(): any;
528
528
  doExecuteNFA(input: any, pos: any, anchor: any, ncap: any): any;
529
529
  match(s: any): boolean;
@@ -699,13 +699,6 @@ declare class RE2 {
699
699
  */
700
700
  findAllSubmatchIndex(s: any, n: any): any[];
701
701
  }
702
- declare class AtomicReference {
703
- constructor(initialValue: any);
704
- value: any;
705
- get(): any;
706
- set(newValue: any): void;
707
- compareAndSet(expect: any, update: any): boolean;
708
- }
709
702
  /**
710
703
  * Creates an RE2JS regex directly from a template literal.
711
704
  * @overload
@@ -873,6 +866,16 @@ export class RE2JS {
873
866
  * @returns {boolean} `true` if the exact input string fully matches the pattern, `false` otherwise.
874
867
  */
875
868
  testExact(input: string | number[] | Uint8Array): boolean;
869
+ /**
870
+ * Executes a search for a match in a specified string.
871
+ * Returns a result array, or null if no match is found.
872
+ * The returned array perfectly mirrors standard JavaScript `RegExpExecArray`,
873
+ * including `.index`, `.input`, and `.groups` properties.
874
+ *
875
+ * @param {string|number[]|Uint8Array} input the input string or byte array
876
+ * @returns {Array|null} the match array with index, input, and groups properties, or null
877
+ */
878
+ exec(input: string | number[] | Uint8Array): any[] | null;
876
879
  /**
877
880
  * Splits input around instances of the regular expression. It returns an array giving the strings
878
881
  * that occur before, between, and after instances of the regular expression.
@@ -892,9 +895,9 @@ export class RE2JS {
892
895
  * including capturing groups.
893
896
  *
894
897
  * @param {string|number[]|Uint8Array} input the input string or byte array
895
- * @returns {IterableIterator<Array>}
898
+ * @returns {IterableIterator<RegExpMatchArray>}
896
899
  */
897
- matchAll(input: string | number[] | Uint8Array): IterableIterator<any[]>;
900
+ matchAll(input: string | number[] | Uint8Array): IterableIterator<RegExpMatchArray>;
898
901
  /**
899
902
  *
900
903
  * @returns {string}