re2js 2.7.1 → 2.8.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.
@@ -21,6 +21,12 @@
21
21
  * @author rsc@google.com (Russ Cox)
22
22
  */
23
23
  export class Matcher {
24
+ /**
25
+ * V8 and WebKit have historical hard limits on the number of arguments
26
+ * that can be passed to a function. We cap replacer arguments to prevent
27
+ * Call Stack Overflow (DoS) vulnerabilities on massive ASTs.
28
+ */
29
+ static MAX_REPLACER_ARGS: number;
24
30
  /**
25
31
  * Quotes '\' and '$' in {@code s}, so that the returned string could be used in
26
32
  * {@link #appendReplacement} as a literal replacement of {@code s}.
@@ -210,31 +216,51 @@ export class Matcher {
210
216
  * Returns the input with all matches replaced by {@code replacement}, interpreted as for
211
217
  * {@code appendReplacement}.
212
218
  *
213
- * @param {string} replacement - the replacement string
219
+ * @param {string|Function} replacement - the replacement string or a replacer function
214
220
  * @param {boolean} [javaMode=false] - activate java mode (different behaviour for capture groups and special characters)
215
221
  * @returns {string} the input string with the matches replaced
216
222
  * @throws IndexOutOfBoundsException if replacement refers to an invalid group and javaMode is true
217
223
  */
218
- replaceAll(replacement: string, javaMode?: boolean): string;
224
+ replaceAll(replacement: string | Function, javaMode?: boolean): string;
219
225
  /**
220
226
  * Returns the input with the first match replaced by {@code replacement}, interpreted as for
221
227
  * {@code appendReplacement}.
222
228
  *
223
- * @param {string} replacement - the replacement string
229
+ * @param {string|Function} replacement - the replacement string or a replacer function
224
230
  * @param {boolean} [javaMode=false] - activate java mode (different behaviour for capture groups and special characters)
225
231
  * @returns {string} the input string with the first match replaced
226
232
  * @throws IndexOutOfBoundsException if replacement refers to an invalid group and javaMode is true
227
233
  */
228
- replaceFirst(replacement: string, javaMode?: boolean): string;
234
+ replaceFirst(replacement: string | Function, javaMode?: boolean): string;
229
235
  /**
230
236
  * Helper: replaceAll/replaceFirst hybrid.
231
- * @param {string} replacement - the replacement string
237
+ * @param {string|Function} replacement - the replacement string or a replacer function
232
238
  * @param {boolean} [all=true] - replace all matches
233
239
  * @param {boolean} [javaMode=false] - activate java mode (different behaviour for capture groups and special characters)
234
240
  * @returns {string}
235
241
  * @private
236
242
  */
237
243
  private replace;
244
+ /**
245
+ * Evaluates a replacer function for the current match and appends the result,
246
+ * along with any un-matched preceding text, advancing the append position.
247
+ * @param {Function} replacer - the replacer function
248
+ * @param {boolean} hasNamedGroups - cached flag if pattern has named groups
249
+ * @param {string|Uint8Array|number[]} originalInput - the cached original input reference
250
+ * @returns {string} the evaluated string to append
251
+ * @private
252
+ */
253
+ private appendReplacementFunc;
254
+ /**
255
+ * Builds the argument array for the replacer function matching the standard
256
+ * JS String.prototype.replace(regex, replacer) signature.
257
+ * @param {number} matchStart - the start index of the match
258
+ * @param {boolean} hasNamedGroups - cached flag if pattern has named groups
259
+ * @param {string|Uint8Array|number[]} originalInput - the cached original input reference
260
+ * @returns {Array} array of arguments
261
+ * @private
262
+ */
263
+ private buildReplacerArgs;
238
264
  }
239
265
  /**
240
266
  * A compiled representation of an RE2 regular expression
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.d.ts","sourceRoot":"","sources":["index.esm.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.d.ts","sourceRoot":"","sources":["index.esm.js"],"names":[],"mappings":"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"}
@@ -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.7.1
5
+ * @version v2.8.0
6
6
  * @author Oleksii Vasyliev
7
7
  * @homepage https://github.com/le0pard/re2js#readme
8
8
  * @repository github:le0pard/re2js
@@ -1409,6 +1409,13 @@ class RE2JSInternalException extends RE2JSException {
1409
1409
  */
1410
1410
 
1411
1411
  class Matcher {
1412
+ /**
1413
+ * V8 and WebKit have historical hard limits on the number of arguments
1414
+ * that can be passed to a function. We cap replacer arguments to prevent
1415
+ * Call Stack Overflow (DoS) vulnerabilities on massive ASTs.
1416
+ */
1417
+ static MAX_REPLACER_ARGS = 65535;
1418
+
1412
1419
  /**
1413
1420
  * Quotes '\' and '$' in {@code s}, so that the returned string could be used in
1414
1421
  * {@link #appendReplacement} as a literal replacement of {@code s}.
@@ -1705,16 +1712,14 @@ class Matcher {
1705
1712
  * @private
1706
1713
  */
1707
1714
  genMatch(startByte, anchor) {
1708
- const hasLookbehinds = this.patternInput.re2().prog.numLb > 0;
1709
- const ngroup = hasLookbehinds ? 1 + this.patternGroupCount : 1;
1710
- const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, ngroup);
1715
+ const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, 1);
1711
1716
  const ok = res[0];
1712
1717
  if (!ok) {
1713
1718
  return false;
1714
1719
  }
1715
1720
  this.groups = res[1];
1716
1721
  this.hasMatch = true;
1717
- this.hasGroups = hasLookbehinds || this.patternGroupCount === 0;
1722
+ this.hasGroups = this.patternGroupCount === 0;
1718
1723
  this.anchorFlag = anchor;
1719
1724
  return true;
1720
1725
  }
@@ -1967,7 +1972,7 @@ class Matcher {
1967
1972
  * Returns the input with all matches replaced by {@code replacement}, interpreted as for
1968
1973
  * {@code appendReplacement}.
1969
1974
  *
1970
- * @param {string} replacement - the replacement string
1975
+ * @param {string|Function} replacement - the replacement string or a replacer function
1971
1976
  * @param {boolean} [javaMode=false] - activate java mode (different behaviour for capture groups and special characters)
1972
1977
  * @returns {string} the input string with the matches replaced
1973
1978
  * @throws IndexOutOfBoundsException if replacement refers to an invalid group and javaMode is true
@@ -1980,7 +1985,7 @@ class Matcher {
1980
1985
  * Returns the input with the first match replaced by {@code replacement}, interpreted as for
1981
1986
  * {@code appendReplacement}.
1982
1987
  *
1983
- * @param {string} replacement - the replacement string
1988
+ * @param {string|Function} replacement - the replacement string or a replacer function
1984
1989
  * @param {boolean} [javaMode=false] - activate java mode (different behaviour for capture groups and special characters)
1985
1990
  * @returns {string} the input string with the first match replaced
1986
1991
  * @throws IndexOutOfBoundsException if replacement refers to an invalid group and javaMode is true
@@ -1991,7 +1996,7 @@ class Matcher {
1991
1996
 
1992
1997
  /**
1993
1998
  * Helper: replaceAll/replaceFirst hybrid.
1994
- * @param {string} replacement - the replacement string
1999
+ * @param {string|Function} replacement - the replacement string or a replacer function
1995
2000
  * @param {boolean} [all=true] - replace all matches
1996
2001
  * @param {boolean} [javaMode=false] - activate java mode (different behaviour for capture groups and special characters)
1997
2002
  * @returns {string}
@@ -2000,8 +2005,21 @@ class Matcher {
2000
2005
  replace(replacement, all = true, javaMode = false) {
2001
2006
  let res = '';
2002
2007
  this.reset();
2008
+ const isFunc = typeof replacement === 'function';
2009
+
2010
+ // Cache named groups check to avoid GC thrashing on every match
2011
+ const hasNamedGroups = Object.keys(this.namedGroups).length > 0;
2012
+ let originalInput = null;
2013
+ if (isFunc) {
2014
+ // Prevent V8 Call Stack Overflow (DoS vector) on massive capture group counts
2015
+ if (this.groupCount() >= Matcher.MAX_REPLACER_ARGS) {
2016
+ throw new RE2JSGroupException('Too many capture groups to safely invoke replacer function');
2017
+ }
2018
+ // Resolve the original input reference exactly once outside the hot loop
2019
+ originalInput = this.matcherInput.isUTF8Encoding() ? this.matcherInput.asBytes() : this.matcherInput.asCharSequence();
2020
+ }
2003
2021
  while (this.find()) {
2004
- res += this.appendReplacement(replacement, javaMode);
2022
+ res += isFunc ? this.appendReplacementFunc(replacement, hasNamedGroups, originalInput) : this.appendReplacement(replacement, javaMode);
2005
2023
  if (!all) {
2006
2024
  break;
2007
2025
  }
@@ -2009,6 +2027,66 @@ class Matcher {
2009
2027
  res += this.appendTail();
2010
2028
  return res;
2011
2029
  }
2030
+
2031
+ /**
2032
+ * Evaluates a replacer function for the current match and appends the result,
2033
+ * along with any un-matched preceding text, advancing the append position.
2034
+ * @param {Function} replacer - the replacer function
2035
+ * @param {boolean} hasNamedGroups - cached flag if pattern has named groups
2036
+ * @param {string|Uint8Array|number[]} originalInput - the cached original input reference
2037
+ * @returns {string} the evaluated string to append
2038
+ * @private
2039
+ */
2040
+ appendReplacementFunc(replacer, hasNamedGroups, originalInput) {
2041
+ let res = '';
2042
+ const s = this.start();
2043
+ const e = this.end();
2044
+ if (this.appendPos < s) {
2045
+ res += this.substring(this.appendPos, s);
2046
+ }
2047
+ this.appendPos = e;
2048
+ const args = this.buildReplacerArgs(s, hasNamedGroups, originalInput);
2049
+ res += String(replacer(...args));
2050
+ return res;
2051
+ }
2052
+
2053
+ /**
2054
+ * Builds the argument array for the replacer function matching the standard
2055
+ * JS String.prototype.replace(regex, replacer) signature.
2056
+ * @param {number} matchStart - the start index of the match
2057
+ * @param {boolean} hasNamedGroups - cached flag if pattern has named groups
2058
+ * @param {string|Uint8Array|number[]} originalInput - the cached original input reference
2059
+ * @returns {Array} array of arguments
2060
+ * @private
2061
+ */
2062
+ buildReplacerArgs(matchStart, hasNamedGroups, originalInput) {
2063
+ const args = [this.group(0)]; // match
2064
+
2065
+ const numGroups = this.groupCount();
2066
+ // Fast-path capture group extraction
2067
+ for (let i = 1; i <= numGroups; i++) {
2068
+ const start = this.start(i);
2069
+ if (start < 0) {
2070
+ args.push(void 0);
2071
+ } else {
2072
+ args.push(this.substring(start, this.end(i)));
2073
+ }
2074
+ }
2075
+ args.push(matchStart); // offset
2076
+ args.push(originalInput); // original string (cached)
2077
+
2078
+ // Append named groups object if pattern contains them
2079
+ if (hasNamedGroups) {
2080
+ const parsedGroups = this.getNamedGroups();
2081
+ for (const key in parsedGroups) {
2082
+ if (parsedGroups[key] === null) {
2083
+ parsedGroups[key] = void 0;
2084
+ }
2085
+ }
2086
+ args.push(parsedGroups);
2087
+ }
2088
+ return args;
2089
+ }
2012
2090
  }
2013
2091
 
2014
2092
  /**