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.
118 lines
4.5 KiB
118 lines
4.5 KiB
'use strict'; |
|
|
|
var anObject = require('./_an-object'); |
|
var toObject = require('./_to-object'); |
|
var toLength = require('./_to-length'); |
|
var toInteger = require('./_to-integer'); |
|
var advanceStringIndex = require('./_advance-string-index'); |
|
var regExpExec = require('./_regexp-exec-abstract'); |
|
var max = Math.max; |
|
var min = Math.min; |
|
var floor = Math.floor; |
|
var SUBSTITUTION_SYMBOLS = /\$([$&`']|\d\d?|<[^>]*>)/g; |
|
var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&`']|\d\d?)/g; |
|
|
|
var maybeToString = function (it) { |
|
return it === undefined ? it : String(it); |
|
}; |
|
|
|
// @@replace logic |
|
require('./_fix-re-wks')('replace', 2, function (defined, REPLACE, $replace, maybeCallNative) { |
|
return [ |
|
// `String.prototype.replace` method |
|
// https://tc39.github.io/ecma262/#sec-string.prototype.replace |
|
function replace(searchValue, replaceValue) { |
|
var O = defined(this); |
|
var fn = searchValue == undefined ? undefined : searchValue[REPLACE]; |
|
return fn !== undefined |
|
? fn.call(searchValue, O, replaceValue) |
|
: $replace.call(String(O), searchValue, replaceValue); |
|
}, |
|
// `RegExp.prototype[@@replace]` method |
|
// https://tc39.github.io/ecma262/#sec-regexp.prototype-@@replace |
|
function (regexp, replaceValue) { |
|
var res = maybeCallNative($replace, regexp, this, replaceValue); |
|
if (res.done) return res.value; |
|
|
|
var rx = anObject(regexp); |
|
var S = String(this); |
|
var functionalReplace = typeof replaceValue === 'function'; |
|
if (!functionalReplace) replaceValue = String(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; |
|
results.push(result); |
|
if (!global) break; |
|
var matchStr = String(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 = String(result[0]); |
|
var position = max(min(toInteger(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++) captures.push(maybeToString(result[j])); |
|
var namedCaptures = result.groups; |
|
if (functionalReplace) { |
|
var replacerArgs = [matched].concat(captures, position, S); |
|
if (namedCaptures !== undefined) replacerArgs.push(namedCaptures); |
|
var replacement = String(replaceValue.apply(undefined, replacerArgs)); |
|
} else { |
|
replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue); |
|
} |
|
if (position >= nextSourcePosition) { |
|
accumulatedResult += S.slice(nextSourcePosition, position) + replacement; |
|
nextSourcePosition = position + matched.length; |
|
} |
|
} |
|
return accumulatedResult + S.slice(nextSourcePosition); |
|
} |
|
]; |
|
|
|
// https://tc39.github.io/ecma262/#sec-getsubstitution |
|
function getSubstitution(matched, str, position, captures, namedCaptures, replacement) { |
|
var tailPos = position + matched.length; |
|
var m = captures.length; |
|
var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED; |
|
if (namedCaptures !== undefined) { |
|
namedCaptures = toObject(namedCaptures); |
|
symbols = SUBSTITUTION_SYMBOLS; |
|
} |
|
return $replace.call(replacement, symbols, function (match, ch) { |
|
var capture; |
|
switch (ch.charAt(0)) { |
|
case '$': return '$'; |
|
case '&': return matched; |
|
case '`': return str.slice(0, position); |
|
case "'": return str.slice(tailPos); |
|
case '<': |
|
capture = namedCaptures[ch.slice(1, -1)]; |
|
break; |
|
default: // \d\d? |
|
var n = +ch; |
|
if (n === 0) return match; |
|
if (n > m) { |
|
var f = floor(n / 10); |
|
if (f === 0) return match; |
|
if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1); |
|
return match; |
|
} |
|
capture = captures[n - 1]; |
|
} |
|
return capture === undefined ? '' : capture; |
|
}); |
|
} |
|
});
|
|
|