1'use strict'; 2 3var anObject = require('./_an-object'); 4var toObject = require('./_to-object'); 5var toLength = require('./_to-length'); 6var toInteger = require('./_to-integer'); 7var advanceStringIndex = require('./_advance-string-index'); 8var regExpExec = require('./_regexp-exec-abstract'); 9var max = Math.max; 10var min = Math.min; 11var floor = Math.floor; 12var SUBSTITUTION_SYMBOLS = /\$([$&`']|\d\d?|<[^>]*>)/g; 13var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&`']|\d\d?)/g; 14 15var maybeToString = function (it) { 16 return it === undefined ? it : String(it); 17}; 18 19// @@replace logic 20require('./_fix-re-wks')('replace', 2, function (defined, REPLACE, $replace, maybeCallNative) { 21 return [ 22 // `String.prototype.replace` method 23 // https://tc39.github.io/ecma262/#sec-string.prototype.replace 24 function replace(searchValue, replaceValue) { 25 var O = defined(this); 26 var fn = searchValue == undefined ? undefined : searchValue[REPLACE]; 27 return fn !== undefined 28 ? fn.call(searchValue, O, replaceValue) 29 : $replace.call(String(O), searchValue, replaceValue); 30 }, 31 // `RegExp.prototype[@@replace]` method 32 // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@replace 33 function (regexp, replaceValue) { 34 var res = maybeCallNative($replace, regexp, this, replaceValue); 35 if (res.done) return res.value; 36 37 var rx = anObject(regexp); 38 var S = String(this); 39 var functionalReplace = typeof replaceValue === 'function'; 40 if (!functionalReplace) replaceValue = String(replaceValue); 41 var global = rx.global; 42 if (global) { 43 var fullUnicode = rx.unicode; 44 rx.lastIndex = 0; 45 } 46 var results = []; 47 while (true) { 48 var result = regExpExec(rx, S); 49 if (result === null) break; 50 results.push(result); 51 if (!global) break; 52 var matchStr = String(result[0]); 53 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode); 54 } 55 var accumulatedResult = ''; 56 var nextSourcePosition = 0; 57 for (var i = 0; i < results.length; i++) { 58 result = results[i]; 59 var matched = String(result[0]); 60 var position = max(min(toInteger(result.index), S.length), 0); 61 var captures = []; 62 // NOTE: This is equivalent to 63 // captures = result.slice(1).map(maybeToString) 64 // but for some reason `nativeSlice.call(result, 1, result.length)` (called in 65 // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and 66 // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it. 67 for (var j = 1; j < result.length; j++) captures.push(maybeToString(result[j])); 68 var namedCaptures = result.groups; 69 if (functionalReplace) { 70 var replacerArgs = [matched].concat(captures, position, S); 71 if (namedCaptures !== undefined) replacerArgs.push(namedCaptures); 72 var replacement = String(replaceValue.apply(undefined, replacerArgs)); 73 } else { 74 replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue); 75 } 76 if (position >= nextSourcePosition) { 77 accumulatedResult += S.slice(nextSourcePosition, position) + replacement; 78 nextSourcePosition = position + matched.length; 79 } 80 } 81 return accumulatedResult + S.slice(nextSourcePosition); 82 } 83 ]; 84 85 // https://tc39.github.io/ecma262/#sec-getsubstitution 86 function getSubstitution(matched, str, position, captures, namedCaptures, replacement) { 87 var tailPos = position + matched.length; 88 var m = captures.length; 89 var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED; 90 if (namedCaptures !== undefined) { 91 namedCaptures = toObject(namedCaptures); 92 symbols = SUBSTITUTION_SYMBOLS; 93 } 94 return $replace.call(replacement, symbols, function (match, ch) { 95 var capture; 96 switch (ch.charAt(0)) { 97 case '$': return '$'; 98 case '&': return matched; 99 case '`': return str.slice(0, position); 100 case "'": return str.slice(tailPos); 101 case '<': 102 capture = namedCaptures[ch.slice(1, -1)]; 103 break; 104 default: // \d\d? 105 var n = +ch; 106 if (n === 0) return match; 107 if (n > m) { 108 var f = floor(n / 10); 109 if (f === 0) return match; 110 if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1); 111 return match; 112 } 113 capture = captures[n - 1]; 114 } 115 return capture === undefined ? '' : capture; 116 }); 117 } 118}); 119