You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
142 lines
5.5 KiB
142 lines
5.5 KiB
'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);
|
|
|