| 'use strict'; |
| var fixRegExpWellKnownSymbolLogic = require('../internals/fix-regexp-well-known-symbol-logic'); |
| var anObject = require('../internals/an-object'); |
| var toObject = require('../internals/to-object'); |
| var toLength = require('../internals/to-length'); |
| var toInteger = require('../internals/to-integer'); |
| var requireObjectCoercible = require('../internals/require-object-coercible'); |
| var advanceStringIndex = require('../internals/advance-string-index'); |
| var regExpExec = require('../internals/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 |
| fixRegExpWellKnownSymbolLogic('replace', 2, function (REPLACE, nativeReplace, maybeCallNative) { |
| return [ |
| // `String.prototype.replace` method |
| // https://tc39.github.io/ecma262/#sec-string.prototype.replace |
| function replace(searchValue, replaceValue) { |
| var O = requireObjectCoercible(this); |
| var replacer = searchValue == undefined ? undefined : searchValue[REPLACE]; |
| return replacer !== undefined |
| ? replacer.call(searchValue, O, replaceValue) |
| : nativeReplace.call(String(O), searchValue, replaceValue); |
| }, |
| // `RegExp.prototype[@@replace]` method |
| // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@replace |
| function (regexp, replaceValue) { |
| var res = maybeCallNative(nativeReplace, 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 nativeReplace.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; |
| }); |
| } |
| }); |