123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- 'use strict';
- var apply = require('../internals/function-apply');
- var call = require('../internals/function-call');
- var uncurryThis = require('../internals/function-uncurry-this');
- var fixRegExpWellKnownSymbolLogic = require('../internals/fix-regexp-well-known-symbol-logic');
- var fails = require('../internals/fails');
- var anObject = require('../internals/an-object');
- var isCallable = require('../internals/is-callable');
- var isNullOrUndefined = require('../internals/is-null-or-undefined');
- var toIntegerOrInfinity = require('../internals/to-integer-or-infinity');
- var toLength = require('../internals/to-length');
- var toString = require('../internals/to-string');
- var requireObjectCoercible = require('../internals/require-object-coercible');
- var advanceStringIndex = require('../internals/advance-string-index');
- var getMethod = require('../internals/get-method');
- var getSubstitution = require('../internals/get-substitution');
- var regExpExec = require('../internals/regexp-exec-abstract');
- var wellKnownSymbol = require('../internals/well-known-symbol');
-
- var REPLACE = wellKnownSymbol('replace');
- var max = Math.max;
- var min = Math.min;
- var concat = uncurryThis([].concat);
- var push = uncurryThis([].push);
- var stringIndexOf = uncurryThis(''.indexOf);
- var stringSlice = uncurryThis(''.slice);
-
- var maybeToString = function (it) {
- return it === undefined ? it : String(it);
- };
-
- // IE <= 11 replaces $0 with the whole match, as if it was $&
- // https://stackoverflow.com/questions/6024666/getting-ie-to-replace-a-regex-with-the-literal-string-0
- var REPLACE_KEEPS_$0 = (function () {
- // eslint-disable-next-line regexp/prefer-escape-replacement-dollar-char -- required for testing
- 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 (/./[REPLACE]) {
- return /./[REPLACE]('a', '$0') === '';
- }
- return false;
- })();
-
- var REPLACE_SUPPORTS_NAMED_GROUPS = !fails(function () {
- var re = /./;
- re.exec = function () {
- var result = [];
- result.groups = { a: '7' };
- return result;
- };
- // eslint-disable-next-line regexp/no-useless-dollar-replacements -- false positive
- return ''.replace(re, '$<a>') !== '7';
- });
-
- // @@replace logic
- fixRegExpWellKnownSymbolLogic('replace', function (_, nativeReplace, maybeCallNative) {
- var UNSAFE_SUBSTITUTE = REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE ? '$' : '$0';
-
- return [
- // `String.prototype.replace` method
- // https://tc39.es/ecma262/#sec-string.prototype.replace
- function replace(searchValue, replaceValue) {
- var O = requireObjectCoercible(this);
- var replacer = isNullOrUndefined(searchValue) ? undefined : getMethod(searchValue, REPLACE);
- return replacer
- ? call(replacer, searchValue, O, replaceValue)
- : call(nativeReplace, toString(O), searchValue, replaceValue);
- },
- // `RegExp.prototype[@@replace]` method
- // https://tc39.es/ecma262/#sec-regexp.prototype-@@replace
- function (string, replaceValue) {
- var rx = anObject(this);
- var S = toString(string);
-
- if (
- typeof replaceValue == 'string' &&
- stringIndexOf(replaceValue, UNSAFE_SUBSTITUTE) === -1 &&
- stringIndexOf(replaceValue, '$<') === -1
- ) {
- var res = maybeCallNative(nativeReplace, rx, S, replaceValue);
- if (res.done) return res.value;
- }
-
- var functionalReplace = isCallable(replaceValue);
- if (!functionalReplace) replaceValue = toString(replaceValue);
-
- var global = rx.global;
- var fullUnicode;
- if (global) {
- fullUnicode = rx.unicode;
- rx.lastIndex = 0;
- }
-
- var results = [];
- var result;
- while (true) {
- result = regExpExec(rx, S);
- if (result === null) break;
-
- push(results, result);
- if (!global) break;
-
- var matchStr = toString(result[0]);
- if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
- }
-
- var accumulatedResult = '';
- var nextSourcePosition = 0;
- for (var i = 0; i < results.length; i++) {
- result = results[i];
-
- var matched = toString(result[0]);
- var position = max(min(toIntegerOrInfinity(result.index), S.length), 0);
- var captures = [];
- var replacement;
- // NOTE: This is equivalent to
- // captures = result.slice(1).map(maybeToString)
- // but for some reason `nativeSlice.call(result, 1, result.length)` (called in
- // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and
- // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.
- for (var j = 1; j < result.length; j++) push(captures, maybeToString(result[j]));
- var namedCaptures = result.groups;
- if (functionalReplace) {
- var replacerArgs = concat([matched], captures, position, S);
- if (namedCaptures !== undefined) push(replacerArgs, namedCaptures);
- replacement = toString(apply(replaceValue, undefined, replacerArgs));
- } else {
- replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);
- }
- if (position >= nextSourcePosition) {
- accumulatedResult += stringSlice(S, nextSourcePosition, position) + replacement;
- nextSourcePosition = position + matched.length;
- }
- }
-
- return accumulatedResult + stringSlice(S, nextSourcePosition);
- }
- ];
- }, !REPLACE_SUPPORTS_NAMED_GROUPS || !REPLACE_KEEPS_$0 || REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE);
|