Skip to content
This repository was archived by the owner on Apr 14, 2021. It is now read-only.

Commit b5d5bf7

Browse files
author
Mike Lewis
committed
Allow disable of RegExp cache/restore
The implementation of cache/restore of RegExp properties has the potential to cause a number of issues. A perfect solution is not possible because it's not possible to determine the regex that was used to turn the cached input into the cached match and group matches. The current solution simply takes the lastMatch and escapes it, wrapping any match groups in parens. One problem with this approach is that when the match is very long, it will overrun the maximum length of a RegEx in JavaScript. In this commit, we add the capability to disable restore of RegExp properties entirely, via `IntlPolyfill.__disableRegExpRestore`.
1 parent f8c5616 commit b5d5bf7

File tree

5 files changed

+59
-1
lines changed

5 files changed

+59
-1
lines changed

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,14 @@ is automatically added to the runtime and does not need to be provided.
185185
Contents of the `locale-data` directory are a modified form of the Unicode CLDR
186186
data found at http://www.unicode.org/cldr/.
187187

188+
## RegExp cache / restore
189+
`Intl.js` attempts to cache and restore static RegExp properties before executing any
190+
regular expressions in order to comply with ECMA-402. This process is imperfect,
191+
and some situations are not supported. For example, you may experience errors when
192+
attempting to use `Intl.js` methods immediately after executing a regular expression
193+
against a very long input. This behavior is not strictly necessary, and is only
194+
required if the app depends on RegExp static properties not changing (which is highly
195+
unlikely). To disable this functionality, invoke `Intl.__disableRegExpRestore()`.
188196

189197
## Contribute
190198

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
"build:dist": "npm run build:dist:dev && npm run build:dist:prod",
7373
"build": "npm run build:data && npm run build:lib && npm run build:dist",
7474
"lint": "eslint .",
75-
"test": "cd tests && node polyfilling.js && node sanity.js && node noderunner.js && node saucelabs.js",
75+
"test": "cd tests && node polyfilling.js && node sanity.js && node noderunner.js && node saucelabs.js && node disableregexprestore.js",
7676
"pretest": "npm run lint",
7777
"preversion": "npm run clean && npm run build && npm run test",
7878
"prepublish": "npm run clean && npm run build"

src/core.js

+6
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,10 @@ function addLocaleData (data, tag) {
9393
setDefaultLocale(tag);
9494
}
9595

96+
defineProperty(Intl, '__disableRegExpRestore', {
97+
value: function () {
98+
internals.disableRegExpRestore = true;
99+
}
100+
});
101+
96102
export default Intl;

src/util.js

+4
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ List.prototype = objCreate(null);
132132
* Constructs a regular expression to restore tainted RegExp properties
133133
*/
134134
export function createRegExpRestore () {
135+
if (internals.disableRegExpRestore) {
136+
return { exp: /a/, input: 'a' };
137+
}
138+
135139
let esc = /[.?*+^$[\]\\(){}|-]/g,
136140
lm = RegExp.lastMatch || '',
137141
ml = RegExp.multiline ? 'm' : '',

tests/disableregexprestore.js

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
var IntlPolyfill = require('../');
2+
3+
function assertEqual(value, expected, message) {
4+
console.log(message);
5+
if (value !== expected) {
6+
console.error(' > ERROR: expected value ' + expected + ' but the actual value is ' + value);
7+
process.exit(1);
8+
} else {
9+
console.log(' > PASSED');
10+
}
11+
}
12+
13+
function assertNotEqual(value, expected, message) {
14+
console.log(message);
15+
if (value === expected) {
16+
console.error(' > ERROR: expected value ' + expected + ' but the actual value is ' + value);
17+
process.exit(1);
18+
} else {
19+
console.log(' > PASSED');
20+
}
21+
}
22+
23+
/foo/.exec('a foo test');
24+
new IntlPolyfill.NumberFormat('en-US', {
25+
style: 'currency',
26+
currency: 'GBP',
27+
minimumFractionDigits: 2,
28+
});
29+
assertEqual(RegExp.input, 'a foo test', 'Normally, RegExp.input should be cached and restored');
30+
assertEqual(RegExp.lastMatch, 'foo', 'Normally, RegExp.lastMatch should be cached and restored');
31+
32+
IntlPolyfill.__disableRegExpRestore();
33+
/foo/.exec('a foo test');
34+
new IntlPolyfill.NumberFormat('en-US', {
35+
style: 'currency',
36+
currency: 'GBP',
37+
minimumFractionDigits: 2,
38+
});
39+
assertNotEqual(RegExp.input, 'a foo test', 'After invoking __disableRegExpRestore, RegExp.input should not be cached and restored');
40+
assertNotEqual(RegExp.lastMatch, 'foo', 'After invoking __disableRegExpRestore, RegExp.lastMatch should not be cached and restored');

0 commit comments

Comments
 (0)