From 79481754c2226f3437b6ad3708512a91bdc6ab40 Mon Sep 17 00:00:00 2001 From: Matt Clough Date: Thu, 9 Jan 2020 13:16:06 -0500 Subject: [PATCH 1/4] checks if RegExp[Symbol.replace] substitutes undefined capture groups --- .../fix-regexp-well-known-symbol-logic.js | 17 +++++++++++++++-- packages/core-js/modules/es.string.replace.js | 5 ++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js b/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js index 05de94193514..ac90829fb375 100644 --- a/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js +++ b/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js @@ -28,6 +28,14 @@ var REPLACE_KEEPS_$0 = (function () { return 'a'.replace(/./, '$0') === '$0'; })(); +// Safari <= 13.0.3(?) substitutes nth capture where n>m with an empty string +var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = (function () { + if (RegExp.prototype['Symbol.replace']) { + return RegExp.prototype['Symbol.replace'].call(/./, 'a', '$0') === ''; + } + return false; +})(); + // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec // Weex JS has frozen built-in prototypes, so use try / catch wrapper var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = !fails(function () { @@ -75,7 +83,9 @@ module.exports = function (KEY, length, exec, sham) { if ( !DELEGATES_TO_SYMBOL || !DELEGATES_TO_EXEC || - (KEY === 'replace' && !(REPLACE_SUPPORTS_NAMED_GROUPS && REPLACE_KEEPS_$0)) || + (KEY === 'replace' && !(REPLACE_SUPPORTS_NAMED_GROUPS && ( + REPLACE_KEEPS_$0 || REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE + ))) || (KEY === 'split' && !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC) ) { var nativeRegExpMethod = /./[SYMBOL]; @@ -90,7 +100,10 @@ module.exports = function (KEY, length, exec, sham) { return { done: true, value: nativeMethod.call(str, regexp, arg2) }; } return { done: false }; - }, { REPLACE_KEEPS_$0: REPLACE_KEEPS_$0 }); + }, { + REPLACE_KEEPS_$0: REPLACE_KEEPS_$0, + REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE: REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE + }); var stringMethod = methods[0]; var regexMethod = methods[1]; diff --git a/packages/core-js/modules/es.string.replace.js b/packages/core-js/modules/es.string.replace.js index 6eeb2abdeea6..c3cf474b82b3 100644 --- a/packages/core-js/modules/es.string.replace.js +++ b/packages/core-js/modules/es.string.replace.js @@ -33,7 +33,10 @@ fixRegExpWellKnownSymbolLogic('replace', 2, function (REPLACE, nativeReplace, ma // `RegExp.prototype[@@replace]` method // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@replace function (regexp, replaceValue) { - if (reason.REPLACE_KEEPS_$0 || (typeof replaceValue === 'string' && replaceValue.indexOf('$0') === -1)) { + if ( + reason.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE && + (reason.REPLACE_KEEPS_$0 || (typeof replaceValue === 'string' && replaceValue.indexOf('$0') === -1)) + ) { var res = maybeCallNative(nativeReplace, regexp, this, replaceValue); if (res.done) return res.value; } From 3bfe93c4de2399abd877db6e6473728d5a4d4489 Mon Sep 17 00:00:00 2001 From: Matt Clough Date: Thu, 9 Jan 2020 14:12:48 -0500 Subject: [PATCH 2/4] use wellKnownSymbol util to get symbol key for replace method --- .../core-js/internals/fix-regexp-well-known-symbol-logic.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js b/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js index ac90829fb375..2ce918a68837 100644 --- a/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js +++ b/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js @@ -30,8 +30,8 @@ var REPLACE_KEEPS_$0 = (function () { // Safari <= 13.0.3(?) substitutes nth capture where n>m with an empty string var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = (function () { - if (RegExp.prototype['Symbol.replace']) { - return RegExp.prototype['Symbol.replace'].call(/./, 'a', '$0') === ''; + if (RegExp.prototype[wellKnownSymbol('replace')]) { + return RegExp.prototype[wellKnownSymbol('replace')].call(/./, 'a', '$0') === ''; } return false; })(); From e0a3d425d76b08dd40ed74766a1791bd5305d7f1 Mon Sep 17 00:00:00 2001 From: Matt Clough Date: Thu, 9 Jan 2020 14:34:13 -0500 Subject: [PATCH 3/4] fixes REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE conditional logic --- packages/core-js/modules/es.string.replace.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core-js/modules/es.string.replace.js b/packages/core-js/modules/es.string.replace.js index c3cf474b82b3..f0e0933ced7f 100644 --- a/packages/core-js/modules/es.string.replace.js +++ b/packages/core-js/modules/es.string.replace.js @@ -34,7 +34,7 @@ fixRegExpWellKnownSymbolLogic('replace', 2, function (REPLACE, nativeReplace, ma // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@replace function (regexp, replaceValue) { if ( - reason.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE && + !reason.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE && (reason.REPLACE_KEEPS_$0 || (typeof replaceValue === 'string' && replaceValue.indexOf('$0') === -1)) ) { var res = maybeCallNative(nativeReplace, regexp, this, replaceValue); From c7429d1c4a34ee787a4375202cbf10f5c6929fa3 Mon Sep 17 00:00:00 2001 From: Matt Clough Date: Thu, 9 Jan 2020 21:17:30 -0500 Subject: [PATCH 4/4] caches Symbol.replace as constant, uses regexp literal, swaps default for guard in fix-regexp-well-known-symbol-logic --- .../internals/fix-regexp-well-known-symbol-logic.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js b/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js index 2ce918a68837..932469f546ad 100644 --- a/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js +++ b/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js @@ -28,10 +28,11 @@ var REPLACE_KEEPS_$0 = (function () { return 'a'.replace(/./, '$0') === '$0'; })(); +var REPLACE = wellKnownSymbol('replace'); // Safari <= 13.0.3(?) substitutes nth capture where n>m with an empty string var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = (function () { - if (RegExp.prototype[wellKnownSymbol('replace')]) { - return RegExp.prototype[wellKnownSymbol('replace')].call(/./, 'a', '$0') === ''; + if (/./[REPLACE]) { + return /./[REPLACE]('a', '$0') === ''; } return false; })(); @@ -83,9 +84,11 @@ module.exports = function (KEY, length, exec, sham) { if ( !DELEGATES_TO_SYMBOL || !DELEGATES_TO_EXEC || - (KEY === 'replace' && !(REPLACE_SUPPORTS_NAMED_GROUPS && ( - REPLACE_KEEPS_$0 || REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE - ))) || + (KEY === 'replace' && !( + REPLACE_SUPPORTS_NAMED_GROUPS && + REPLACE_KEEPS_$0 && + REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE + )) || (KEY === 'split' && !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC) ) { var nativeRegExpMethod = /./[SYMBOL];