_fix-re-wks.js
3.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
'use strict';
require('./es6.regexp.exec');
var redefine = require('./_redefine');
var hide = require('./_hide');
var fails = require('./_fails');
var defined = require('./_defined');
var wks = require('./_wks');
var regexpExec = require('./_regexp-exec');
var SPECIES = wks('species');
var REPLACE_SUPPORTS_NAMED_GROUPS = !fails(function () {
// #replace needs built-in support for named groups.
// #match works fine because it just return the exec results, even if it has
// a "grops" property.
var re = /./;
re.exec = function () {
var result = [];
result.groups = { a: '7' };
return result;
};
return ''.replace(re, '$<a>') !== '7';
});
var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = (function () {
// Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
var re = /(?:)/;
var originalExec = re.exec;
re.exec = function () { return originalExec.apply(this, arguments); };
var result = 'ab'.split(re);
return result.length === 2 && result[0] === 'a' && result[1] === 'b';
})();
module.exports = function (KEY, length, exec) {
var SYMBOL = wks(KEY);
var DELEGATES_TO_SYMBOL = !fails(function () {
// String methods call symbol-named RegEp methods
var O = {};
O[SYMBOL] = function () { return 7; };
return ''[KEY](O) != 7;
});
var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL ? !fails(function () {
// Symbol-named RegExp methods call .exec
var execCalled = false;
var re = /a/;
re.exec = function () { execCalled = true; return null; };
if (KEY === 'split') {
// RegExp[@@split] doesn't call the regex's exec method, but first creates
// a new one. We need to return the patched regex when creating the new one.
re.constructor = {};
re.constructor[SPECIES] = function () { return re; };
}
re[SYMBOL]('');
return !execCalled;
}) : undefined;
if (
!DELEGATES_TO_SYMBOL ||
!DELEGATES_TO_EXEC ||
(KEY === 'replace' && !REPLACE_SUPPORTS_NAMED_GROUPS) ||
(KEY === 'split' && !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC)
) {
var nativeRegExpMethod = /./[SYMBOL];
var fns = exec(
defined,
SYMBOL,
''[KEY],
function maybeCallNative(nativeMethod, regexp, str, arg2, forceStringMethod) {
if (regexp.exec === regexpExec) {
if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
// The native String method already delegates to @@method (this
// polyfilled function), leasing to infinite recursion.
// We avoid it by directly calling the native @@method method.
return { done: true, value: nativeRegExpMethod.call(regexp, str, arg2) };
}
return { done: true, value: nativeMethod.call(str, regexp, arg2) };
}
return { done: false };
}
);
var strfn = fns[0];
var rxfn = fns[1];
redefine(String.prototype, KEY, strfn);
hide(RegExp.prototype, SYMBOL, length == 2
// 21.2.5.8 RegExp.prototype[@@replace](string, replaceValue)
// 21.2.5.11 RegExp.prototype[@@split](string, limit)
? function (string, arg) { return rxfn.call(string, this, arg); }
// 21.2.5.6 RegExp.prototype[@@match](string)
// 21.2.5.9 RegExp.prototype[@@search](string)
: function (string) { return rxfn.call(string, this); }
);
}
};