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.
@@ -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
@@ -711,7 +711,7 @@
711
711
  static stringToUtf8ByteArray(str) {
712
712
  if (globalThis.TextEncoder) {
713
713
  if (!cachedNativeEncoder) cachedNativeEncoder = new TextEncoder();
714
- return Utils.toArray(cachedNativeEncoder.encode(str));
714
+ return cachedNativeEncoder.encode(str);
715
715
  } else {
716
716
  let out = [], p = 0;
717
717
  for (let i = 0; i < str.length; i++) {
@@ -1249,7 +1249,7 @@
1249
1249
  }
1250
1250
  /**
1251
1251
  * Resets the {@code Matcher} and changes the input.
1252
- * @param {MatcherInputBase} input
1252
+ * @param {string|number[]|Uint8Array|MatcherInputBase} input
1253
1253
  * @returns {Matcher} the {@code Matcher} itself, for chained method calls
1254
1254
  */
1255
1255
  resetMatcherInput(input) {
@@ -1405,7 +1405,10 @@
1405
1405
  */
1406
1406
  genMatch(startByte, anchor) {
1407
1407
  const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, 1);
1408
- if (!res[0]) return false;
1408
+ if (!res[0]) {
1409
+ this.hasMatch = false;
1410
+ return false;
1411
+ }
1409
1412
  this.groups = res[1];
1410
1413
  this.hasMatch = true;
1411
1414
  this.hasGroups = this.patternGroupCount === 0;
@@ -1468,43 +1471,47 @@
1468
1471
  let res = "";
1469
1472
  let last = 0;
1470
1473
  const m = replacement.length;
1471
- for (let i = 0; i < m - 1; i++) {
1472
- if (replacement.codePointAt(i) === Codepoint.CODES.get("\\")) {
1474
+ let i = 0;
1475
+ while (i < m) {
1476
+ const cCode = replacement.codePointAt(i);
1477
+ if (cCode === Codepoint.CODES.get("\\")) {
1473
1478
  if (last < i) res += replacement.substring(last, i);
1474
1479
  i++;
1480
+ if (i >= m) throw new RE2JSGroupException("character to be escaped is missing");
1475
1481
  last = i;
1482
+ i++;
1476
1483
  continue;
1477
1484
  }
1478
- if (replacement.codePointAt(i) === Codepoint.CODES.get("$")) {
1479
- let c = replacement.codePointAt(i + 1);
1480
- if (Codepoint.CODES.get("0") <= c && c <= Codepoint.CODES.get("9")) {
1481
- let n = c - Codepoint.CODES.get("0");
1482
- if (last < i) res += replacement.substring(last, i);
1483
- for (i += 2; i < m; i++) {
1484
- c = replacement.codePointAt(i);
1485
- if (c < Codepoint.CODES.get("0") || c > Codepoint.CODES.get("9") || n * 10 + c - Codepoint.CODES.get("0") > this.patternGroupCount) break;
1486
- n = n * 10 + c - Codepoint.CODES.get("0");
1485
+ if (cCode === Codepoint.CODES.get("$")) {
1486
+ if (last < i) res += replacement.substring(last, i);
1487
+ if (i + 1 >= m) throw new RE2JSGroupException("Illegal group reference: group index is missing");
1488
+ const nextCode = replacement.codePointAt(i + 1);
1489
+ if (Codepoint.CODES.get("0") <= nextCode && nextCode <= Codepoint.CODES.get("9")) {
1490
+ let n = nextCode - Codepoint.CODES.get("0");
1491
+ let j = i + 2;
1492
+ for (; j < m; j++) {
1493
+ const digit = replacement.codePointAt(j);
1494
+ if (digit < Codepoint.CODES.get("0") || digit > Codepoint.CODES.get("9") || n * 10 + digit - Codepoint.CODES.get("0") > this.patternGroupCount) break;
1495
+ n = n * 10 + digit - Codepoint.CODES.get("0");
1487
1496
  }
1488
1497
  if (n > this.patternGroupCount) throw new RE2JSGroupException(`n > number of groups: ${n}`);
1489
1498
  const group = this.group(n);
1490
1499
  if (group !== null) res += group;
1500
+ i = j;
1491
1501
  last = i;
1492
- i--;
1493
- continue;
1494
- } else if (c === Codepoint.CODES.get("{")) {
1495
- if (last < i) res += replacement.substring(last, i);
1496
- i++;
1497
- let j = i + 1;
1498
- while (j < replacement.length && replacement.codePointAt(j) !== Codepoint.CODES.get("}") && replacement.codePointAt(j) !== Codepoint.CODES.get(" ")) j++;
1499
- if (j === replacement.length || replacement.codePointAt(j) !== Codepoint.CODES.get("}")) throw new RE2JSGroupException("named capture group is missing trailing '}'");
1500
- const groupName = replacement.substring(i + 1, j);
1502
+ } else if (nextCode === Codepoint.CODES.get("{")) {
1503
+ let j = i + 2;
1504
+ while (j < m && replacement.codePointAt(j) !== Codepoint.CODES.get("}")) j++;
1505
+ if (j >= m) throw new RE2JSGroupException("named capture group is missing trailing '}'");
1506
+ const groupName = replacement.substring(i + 2, j);
1501
1507
  const groupVal = this.group(groupName);
1502
1508
  if (groupVal !== null) res += groupVal;
1503
- last = j + 1;
1504
- i = j;
1505
- continue;
1506
- }
1509
+ i = j + 1;
1510
+ last = i;
1511
+ } else throw new RE2JSGroupException("Illegal group reference");
1512
+ continue;
1507
1513
  }
1514
+ i++;
1508
1515
  }
1509
1516
  if (last < m) res += replacement.substring(last, m);
1510
1517
  return res;
@@ -1815,18 +1822,18 @@
1815
1822
  };
1816
1823
  //#endregion
1817
1824
  //#region src/Machine.js
1818
- var Thread = class {
1819
- constructor() {
1820
- this.inst = null;
1821
- this.cap = null;
1822
- }
1823
- };
1824
1825
  var Queue = class {
1825
1826
  constructor(numInst) {
1826
1827
  this.sparse = new Int32Array(numInst);
1827
1828
  this.densePcs = new Int32Array(numInst);
1828
- this.denseThreads = new Array(numInst);
1829
+ this.denseCaps = null;
1829
1830
  this.size = 0;
1831
+ this.ncap = 0;
1832
+ }
1833
+ init(ncap) {
1834
+ this.ncap = ncap;
1835
+ const needed = this.densePcs.length * ncap;
1836
+ if (!this.denseCaps || this.denseCaps.length < needed) this.denseCaps = new Int32Array(needed);
1830
1837
  }
1831
1838
  contains(pc) {
1832
1839
  const j = this.sparse[pc];
@@ -1838,12 +1845,10 @@
1838
1845
  add(pc) {
1839
1846
  const j = this.size++;
1840
1847
  this.sparse[pc] = j;
1841
- this.denseThreads[j] = null;
1842
1848
  this.densePcs[j] = pc;
1843
1849
  return j;
1844
1850
  }
1845
1851
  clear() {
1846
- for (let i = 0; i < this.size; i++) this.denseThreads[i] = null;
1847
1852
  this.size = 0;
1848
1853
  }
1849
1854
  toString() {
@@ -1857,15 +1862,12 @@
1857
1862
  }
1858
1863
  };
1859
1864
  var Machine = class Machine {
1860
- static THREADS_CHUNK_SIZE = 128;
1861
1865
  static fromRE2(re2) {
1862
1866
  const m = new Machine();
1863
1867
  m.prog = re2.prog;
1864
1868
  m.re2 = re2;
1865
1869
  m.q0 = new Queue(m.prog.numInst());
1866
1870
  m.q1 = new Queue(m.prog.numInst());
1867
- m.pool = [];
1868
- m.poolSize = 0;
1869
1871
  m.matched = false;
1870
1872
  m.matchcap = new Int32Array(m.prog.numCap < 2 ? 2 : m.prog.numCap);
1871
1873
  m.ncap = 0;
@@ -1879,8 +1881,6 @@
1879
1881
  this.re2 = null;
1880
1882
  this.q0 = null;
1881
1883
  this.q1 = null;
1882
- this.pool = [];
1883
- this.poolSize = 0;
1884
1884
  this.matched = false;
1885
1885
  this.matchcap = null;
1886
1886
  this.ncap = 0;
@@ -1888,51 +1888,19 @@
1888
1888
  }
1889
1889
  init(ncap) {
1890
1890
  this.ncap = ncap;
1891
- if (ncap > this.matchcap.length) this.initNewCap(ncap);
1892
- else this.resetCap();
1891
+ if (ncap > this.matchcap.length) this.matchcap = new Int32Array(ncap).fill(-1);
1892
+ else this.matchcap.fill(-1);
1893
+ this.q0.init(ncap);
1894
+ this.q1.init(ncap);
1893
1895
  if (this.prog.numLb > 0) {
1894
1896
  if (!this.lbTable || this.lbTable.length < this.prog.numLb + 1) this.lbTable = new Int32Array(this.prog.numLb + 1);
1895
1897
  this.lbTable.fill(-1);
1896
1898
  }
1897
1899
  }
1898
- resetCap() {
1899
- for (let i = 0; i < this.poolSize; i++) this.pool[i].cap.fill(-1);
1900
- }
1901
- initNewCap(ncap) {
1902
- for (let i = 0; i < this.poolSize; i++) {
1903
- const t = this.pool[i];
1904
- t.cap = new Int32Array(ncap).fill(-1);
1905
- }
1906
- this.matchcap = new Int32Array(ncap).fill(-1);
1907
- }
1908
1900
  submatches() {
1909
1901
  if (this.ncap === 0) return Utils.emptyInts();
1910
1902
  return Utils.toArray(this.matchcap.subarray(0, this.ncap));
1911
1903
  }
1912
- alloc(inst) {
1913
- if (this.poolSize === 0) {
1914
- const capLen = this.matchcap.length;
1915
- for (let i = 0; i < Machine.THREADS_CHUNK_SIZE; i++) {
1916
- const t = new Thread();
1917
- t.cap = new Int32Array(capLen);
1918
- this.pool[this.poolSize++] = t;
1919
- }
1920
- }
1921
- this.poolSize--;
1922
- const t = this.pool[this.poolSize];
1923
- t.inst = inst;
1924
- return t;
1925
- }
1926
- freeQueue(queue, from = 0) {
1927
- for (let i = from; i < queue.size; i++) {
1928
- const t = queue.denseThreads[i];
1929
- if (t !== null) this.pool[this.poolSize++] = t;
1930
- }
1931
- queue.clear();
1932
- }
1933
- freeThread(t) {
1934
- this.pool[this.poolSize++] = t;
1935
- }
1936
1904
  match(input, pos, anchor) {
1937
1905
  const startCond = this.re2.cond;
1938
1906
  if (startCond === Utils.EMPTY_ALL) return false;
@@ -1971,13 +1939,14 @@
1971
1939
  r = input.step(currentPos + width);
1972
1940
  rune1 = r >> 3;
1973
1941
  width1 = r & 7;
1942
+ flag = input.context(currentPos);
1974
1943
  }
1975
1944
  }
1976
- 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);
1945
+ 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);
1977
1946
  if (!this.matched && (currentPos === 0 || anchor === RE2Flags.UNANCHORED)) {
1978
1947
  if (currentPos >= matchStartPos) {
1979
1948
  if (this.ncap > 0) this.matchcap[0] = currentPos;
1980
- this.add(runq, this.prog.start, currentPos, this.matchcap, flag, null);
1949
+ this.add(runq, this.prog.start, currentPos, this.matchcap, 0, flag);
1981
1950
  }
1982
1951
  }
1983
1952
  const nextPos = currentPos + width;
@@ -1997,7 +1966,7 @@
1997
1966
  runq = nextq;
1998
1967
  nextq = tmpq;
1999
1968
  }
2000
- this.freeQueue(nextq);
1969
+ nextq.clear();
2001
1970
  return this.matched;
2002
1971
  }
2003
1972
  matchSet(input, pos, anchor) {
@@ -2025,16 +1994,16 @@
2025
1994
  if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 && currentPos !== 0) break;
2026
1995
  if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && currentPos !== 0) break;
2027
1996
  }
2028
- 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);
1997
+ 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);
2029
1998
  if (currentPos === 0 || anchor === RE2Flags.UNANCHORED) {
2030
- if (currentPos >= matchStartPos) this.add(runq, this.prog.start, currentPos, this.matchcap, flag, null);
1999
+ if (currentPos >= matchStartPos) this.add(runq, this.prog.start, currentPos, this.matchcap, 0, flag);
2031
2000
  }
2032
2001
  const nextPos = currentPos + width;
2033
2002
  flag = input.context(nextPos);
2034
2003
  for (let j = 0; j < runq.size; j++) {
2035
- let t = runq.denseThreads[j];
2036
- if (t === null) continue;
2037
- const i = t.inst;
2004
+ const pc = runq.densePcs[j];
2005
+ const i = this.prog.inst[pc];
2006
+ const capOffset = j * this.ncap;
2038
2007
  let add = false;
2039
2008
  switch (i.op) {
2040
2009
  case Inst.MATCH:
@@ -2051,15 +2020,11 @@
2051
2020
  add = true;
2052
2021
  break;
2053
2022
  case Inst.RUNE_ANY_NOT_NL:
2054
- add = rune !== Codepoint.CODES.get("\n");
2023
+ add = rune !== 10;
2055
2024
  break;
2056
- default: throw new RE2JSInternalException("bad inst");
2057
- }
2058
- if (add) t = this.add(nextq, i.out, nextPos, t.cap, flag, t);
2059
- if (t !== null) {
2060
- this.freeThread(t);
2061
- runq.denseThreads[j] = null;
2025
+ default: continue;
2062
2026
  }
2027
+ if (add) this.add(nextq, i.out, nextPos, runq.denseCaps, capOffset, flag);
2063
2028
  }
2064
2029
  runq.clear();
2065
2030
  if (width === 0) break;
@@ -2075,28 +2040,25 @@
2075
2040
  runq = nextq;
2076
2041
  nextq = tmpq;
2077
2042
  }
2078
- this.freeQueue(nextq);
2043
+ nextq.clear();
2079
2044
  return Array.from(matches).sort((a, b) => a - b);
2080
2045
  }
2081
2046
  step(runq, nextq, pos, nextPos, c, nextCond, anchor, atEnd) {
2082
2047
  const longest = this.re2.longest;
2083
2048
  for (let j = 0; j < runq.size; j++) {
2084
- let t = runq.denseThreads[j];
2085
- if (t === null) continue;
2086
- if (longest && this.matched && this.ncap > 0 && this.matchcap[0] < t.cap[0]) {
2087
- this.freeThread(t);
2088
- continue;
2089
- }
2090
- const i = t.inst;
2049
+ const pc = runq.densePcs[j];
2050
+ const capOffset = j * this.ncap;
2051
+ if (longest && this.matched && this.ncap > 0 && this.matchcap[0] < runq.denseCaps[capOffset]) continue;
2052
+ const i = this.prog.inst[pc];
2091
2053
  let add = false;
2092
2054
  switch (i.op) {
2093
2055
  case Inst.MATCH:
2094
2056
  if (anchor === RE2Flags.ANCHOR_BOTH && !atEnd) break;
2095
2057
  if (this.ncap > 0 && (!longest || !this.matched || this.matchcap[1] < pos)) {
2096
- t.cap[1] = pos;
2097
- this.matchcap.set(t.cap.subarray(0, this.ncap));
2058
+ runq.denseCaps[capOffset + 1] = pos;
2059
+ for (let k = 0; k < this.ncap; k++) this.matchcap[k] = runq.denseCaps[capOffset + k];
2098
2060
  }
2099
- if (!longest) this.freeQueue(runq, j + 1);
2061
+ if (!longest) runq.size = 0;
2100
2062
  this.matched = true;
2101
2063
  break;
2102
2064
  case Inst.RUNE:
@@ -2109,29 +2071,25 @@
2109
2071
  add = true;
2110
2072
  break;
2111
2073
  case Inst.RUNE_ANY_NOT_NL:
2112
- add = c !== Codepoint.CODES.get("\n");
2074
+ add = c !== 10;
2113
2075
  break;
2114
- default: throw new RE2JSInternalException("bad inst");
2115
- }
2116
- if (add) t = this.add(nextq, i.out, nextPos, t.cap, nextCond, t);
2117
- if (t !== null) {
2118
- this.freeThread(t);
2119
- runq.denseThreads[j] = null;
2076
+ default: continue;
2120
2077
  }
2078
+ if (add) this.add(nextq, i.out, nextPos, runq.denseCaps, capOffset, nextCond);
2121
2079
  }
2122
2080
  runq.clear();
2123
2081
  }
2124
- add(q, pc, pos, cap, cond, t) {
2082
+ add(q, pc, pos, capArray, capOffset, cond) {
2125
2083
  while (true) {
2126
- if (pc === 0) return t;
2127
- if (q.contains(pc)) return t;
2084
+ if (pc === 0) return;
2085
+ if (q.contains(pc)) return;
2128
2086
  const d = q.add(pc);
2129
2087
  const inst = this.prog.inst[pc];
2130
2088
  switch (inst.op) {
2131
- case Inst.FAIL: return t;
2089
+ case Inst.FAIL: return;
2132
2090
  case Inst.ALT:
2133
2091
  case Inst.ALT_MATCH:
2134
- t = this.add(q, inst.out, pos, cap, cond, t);
2092
+ this.add(q, inst.out, pos, capArray, capOffset, cond);
2135
2093
  pc = inst.arg;
2136
2094
  continue;
2137
2095
  case Inst.EMPTY_WIDTH:
@@ -2139,16 +2097,16 @@
2139
2097
  pc = inst.out;
2140
2098
  continue;
2141
2099
  }
2142
- return t;
2100
+ return;
2143
2101
  case Inst.NOP:
2144
2102
  pc = inst.out;
2145
2103
  continue;
2146
2104
  case Inst.CAPTURE: if (inst.arg < this.ncap) {
2147
- const opos = cap[inst.arg];
2148
- cap[inst.arg] = pos;
2149
- this.add(q, inst.out, pos, cap, cond, null);
2150
- cap[inst.arg] = opos;
2151
- return t;
2105
+ const opos = capArray[capOffset + inst.arg];
2106
+ capArray[capOffset + inst.arg] = pos;
2107
+ this.add(q, inst.out, pos, capArray, capOffset, cond);
2108
+ capArray[capOffset + inst.arg] = opos;
2109
+ return;
2152
2110
  } else {
2153
2111
  pc = inst.out;
2154
2112
  continue;
@@ -2167,19 +2125,18 @@
2167
2125
  pc = inst.out;
2168
2126
  continue;
2169
2127
  }
2170
- return t;
2128
+ return;
2171
2129
  case Inst.MATCH:
2172
2130
  case Inst.RUNE:
2173
2131
  case Inst.RUNE1:
2174
2132
  case Inst.RUNE_ANY:
2175
2133
  case Inst.RUNE_ANY_NOT_NL:
2176
- if (t === null) t = this.alloc(inst);
2177
- else t.inst = inst;
2178
- if (this.ncap > 0 && t.cap !== cap) for (let c = 0; c < this.ncap; c++) t.cap[c] = cap[c];
2179
- q.denseThreads[d] = t;
2180
- t = null;
2181
- return t;
2182
- default: throw new Error("unhandled");
2134
+ if (this.ncap > 0) {
2135
+ const destOffset = d * this.ncap;
2136
+ for (let c = 0; c < this.ncap; c++) q.denseCaps[destOffset + c] = capArray[capOffset + c];
2137
+ }
2138
+ return;
2139
+ default: throw new RE2JSInternalException("unhandled");
2183
2140
  }
2184
2141
  }
2185
2142
  }
@@ -2776,7 +2733,9 @@
2776
2733
  m[pc] = true;
2777
2734
  inst.op = Inst.ALT_MATCH;
2778
2735
  }
2779
- const mergeRes = mergeRuneSets(onePassRunes[inst.out] || [], onePassRunes[inst.arg] || [], inst.out, inst.arg);
2736
+ const leftRunes = onePassRunes[inst.out] || [];
2737
+ const rightRunes = onePassRunes[inst.arg] || [];
2738
+ const mergeRes = mergeRuneSets(leftRunes, rightRunes, inst.out, inst.arg);
2780
2739
  if (!mergeRes) return false;
2781
2740
  onePassRunes[pc] = mergeRes.merged;
2782
2741
  inst.next = new Uint32Array(mergeRes.next);
@@ -5368,24 +5327,6 @@
5368
5327
  };
5369
5328
  //#endregion
5370
5329
  //#region src/RE2.js
5371
- var AtomicReference = class {
5372
- constructor(initialValue) {
5373
- this.value = initialValue;
5374
- }
5375
- get() {
5376
- return this.value;
5377
- }
5378
- set(newValue) {
5379
- this.value = newValue;
5380
- }
5381
- compareAndSet(expect, update) {
5382
- if (this.value === expect) {
5383
- this.value = update;
5384
- return true;
5385
- }
5386
- return false;
5387
- }
5388
- };
5389
5330
  /**
5390
5331
  * An RE2 class instance is a compiled representation of an RE2 regular expression, independent of
5391
5332
  * the public Java-like Pattern/Matcher API.
@@ -5474,7 +5415,7 @@
5474
5415
  this.prefixUTF8 = null;
5475
5416
  this.prefixComplete = false;
5476
5417
  this.prefixRune = 0;
5477
- this.pooled = new AtomicReference();
5418
+ this.machinePool = [];
5478
5419
  this.dfa = new DFA(this.prog);
5479
5420
  this.onepass = OnePass.compile(this.prog);
5480
5421
  this.prefilter = null;
@@ -5538,42 +5479,23 @@
5538
5479
  return this.prog.numInst();
5539
5480
  }
5540
5481
  get() {
5541
- let head;
5542
- do
5543
- head = this.pooled.get();
5544
- while (head && !this.pooled.compareAndSet(head, head.next));
5545
- return head;
5482
+ return this.machinePool.length > 0 ? this.machinePool.pop() : null;
5546
5483
  }
5547
5484
  reset() {
5548
- this.pooled.set(null);
5549
- }
5550
- put(m, isNew) {
5551
- let head = this.pooled.get();
5552
- do {
5553
- head = this.pooled.get();
5554
- if (!isNew && head) {
5555
- m = Machine.fromMachine(m);
5556
- isNew = true;
5557
- }
5558
- if (m.next !== head) m.next = head;
5559
- } while (!this.pooled.compareAndSet(head, m));
5485
+ this.machinePool.length = 0;
5486
+ }
5487
+ put(m) {
5488
+ this.machinePool.push(m);
5560
5489
  }
5561
5490
  toString() {
5562
5491
  return this.expr;
5563
5492
  }
5564
5493
  doExecuteNFA(input, pos, anchor, ncap) {
5565
5494
  let m = this.get();
5566
- let isNew = false;
5567
- if (!m) {
5568
- m = Machine.fromRE2(this);
5569
- isNew = true;
5570
- } else if (m.next !== null) {
5571
- m = Machine.fromMachine(m);
5572
- isNew = true;
5573
- }
5495
+ if (!m) m = Machine.fromRE2(this);
5574
5496
  m.init(ncap);
5575
5497
  const cap = m.match(input, pos, anchor) ? m.submatches() : null;
5576
- this.put(m, isNew);
5498
+ this.put(m);
5577
5499
  return cap;
5578
5500
  }
5579
5501
  match(s) {
@@ -6369,6 +6291,33 @@
6369
6291
  return this.re2Input.executeEngine(machineInput, 0, RE2Flags.ANCHOR_BOTH, 0) !== null;
6370
6292
  }
6371
6293
  /**
6294
+ * Executes a search for a match in a specified string.
6295
+ * Returns a result array, or null if no match is found.
6296
+ * The returned array perfectly mirrors standard JavaScript `RegExpExecArray`,
6297
+ * including `.index`, `.input`, and `.groups` properties.
6298
+ *
6299
+ * @param {string|number[]|Uint8Array} input the input string or byte array
6300
+ * @returns {Array|null} the match array with index, input, and groups properties, or null
6301
+ */
6302
+ exec(input) {
6303
+ const m = this.matcher(input);
6304
+ if (!m.find()) return null;
6305
+ const result = [m.group(0)];
6306
+ for (let i = 1; i <= m.groupCount(); i++) {
6307
+ const val = m.group(i);
6308
+ result.push(val === null ? void 0 : val);
6309
+ }
6310
+ result.index = m.start(0);
6311
+ result.input = input;
6312
+ const namedGroups = this.namedGroups();
6313
+ if (Object.keys(namedGroups).length > 0) {
6314
+ const parsedGroups = m.getNamedGroups();
6315
+ for (const key in parsedGroups) if (parsedGroups[key] === null) parsedGroups[key] = void 0;
6316
+ result.groups = parsedGroups;
6317
+ } else result.groups = void 0;
6318
+ return result;
6319
+ }
6320
+ /**
6372
6321
  * Splits input around instances of the regular expression. It returns an array giving the strings
6373
6322
  * that occur before, between, and after instances of the regular expression.
6374
6323
  *
@@ -6412,7 +6361,7 @@
6412
6361
  }
6413
6362
  result.push(m.substring(last, m.inputLength()));
6414
6363
  }
6415
- if (limit !== 0 || result.length === 0) result.push(m.substring(last, m.inputLength()));
6364
+ if (limit !== 0 || result.length === 0 && !(last === m.inputLength() && last > 0)) result.push(m.substring(last, m.inputLength()));
6416
6365
  return result;
6417
6366
  }
6418
6367
  /**
@@ -6420,7 +6369,7 @@
6420
6369
  * including capturing groups.
6421
6370
  *
6422
6371
  * @param {string|number[]|Uint8Array} input the input string or byte array
6423
- * @returns {IterableIterator<Array>}
6372
+ * @returns {IterableIterator<RegExpMatchArray>}
6424
6373
  */
6425
6374
  *matchAll(input) {
6426
6375
  const m = this.matcher(input);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "re2js",
3
- "version": "2.8.4",
3
+ "version": "2.8.6",
4
4
  "description": "RE2JS is the JavaScript port of RE2, a regular expression engine that provides linear time matching",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -69,8 +69,8 @@
69
69
  "globals": "^17.7.0",
70
70
  "lodash": "^4.18.1",
71
71
  "playwright": "^1.61.1",
72
- "prettier": "^3.8.4",
73
- "rolldown": "^1.1.3",
72
+ "prettier": "^3.9.4",
73
+ "rolldown": "^1.1.4",
74
74
  "typescript": "^6.0.3",
75
75
  "unicode-property-value-aliases": "^3.9.0",
76
76
  "vitest": "^4.1.9"