@internal
(searchValue: RegExp, replacement: string | ReplacementFunction)
| 1204 | |
| 1205 | /** @internal */ |
| 1206 | _replaceRegexp(searchValue: RegExp, replacement: string | ReplacementFunction): this { |
| 1207 | function getReplacement(match: RegExpMatchArray, str: string): string { |
| 1208 | if (typeof replacement === 'string') { |
| 1209 | return replacement.replace(/\$(\$|&|\d+)/g, (_: string, i: string) => { |
| 1210 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_a_parameter |
| 1211 | if (i === '$') |
| 1212 | return '$' |
| 1213 | if (i === '&') |
| 1214 | return match[0] |
| 1215 | const num = +i |
| 1216 | if (num < match.length) |
| 1217 | return match[+i] |
| 1218 | return `$${i}` |
| 1219 | }) |
| 1220 | } |
| 1221 | else { |
| 1222 | return replacement(match[0], ...match.slice(1), match.index, str, match.groups) |
| 1223 | } |
| 1224 | } |
| 1225 | const replaceMatch = (match: RegExpMatchArray): void => { |
| 1226 | if (match.index == null) |
| 1227 | return |
| 1228 | |
| 1229 | const replacement = getReplacement(match, this.original) |
| 1230 | if (replacement === match[0]) |
| 1231 | return |
| 1232 | |
| 1233 | if (match[0].length === 0) { |
| 1234 | // a zero-length match spans no characters, so there is no range to |
| 1235 | // overwrite - the replacement is an insertion at the matched position, |
| 1236 | // which is what `String.prototype.replace` does for an empty match |
| 1237 | this.appendRight(match.index, replacement) |
| 1238 | } |
| 1239 | else { |
| 1240 | this.overwrite(match.index, match.index + match[0].length, replacement) |
| 1241 | } |
| 1242 | } |
| 1243 | |
| 1244 | if (searchValue.global) { |
| 1245 | // `String.prototype.replace` starts a global regexp from the beginning of |
| 1246 | // the string, so reset `lastIndex` - a regexp that has already been used |
| 1247 | // would otherwise resume from wherever it stopped and skip earlier matches. |
| 1248 | // `matchAll` also steps over a zero-length match, where `exec` in a loop |
| 1249 | // would keep rematching it at an unmoving `lastIndex` and never terminate. |
| 1250 | searchValue.lastIndex = 0 |
| 1251 | for (const match of this.original.matchAll(searchValue)) { |
| 1252 | replaceMatch(match) |
| 1253 | } |
| 1254 | } |
| 1255 | else { |
| 1256 | const match = this.original.match(searchValue) |
| 1257 | if (match) { |
| 1258 | replaceMatch(match) |
| 1259 | } |
| 1260 | } |
| 1261 | return this |
| 1262 | } |
| 1263 |
no test coverage detected