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.
136 lines
5.4 KiB
136 lines
5.4 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 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 = searchValue == undefined ? 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; |
|
if (global) { |
|
var fullUnicode = rx.unicode; |
|
rx.lastIndex = 0; |
|
} |
|
var results = []; |
|
while (true) { |
|
var 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 = []; |
|
// 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); |
|
var 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);
|
|
|