@internal
(searchValue: RegExp, replacement: string | ReplacementFunction)
| 1335 | |
| 1336 | /** @internal */ |
| 1337 | _replaceRegexp(searchValue: RegExp, replacement: string | ReplacementFunction): this { |
| 1338 | function getReplacement(match: RegExpMatchArray, str: string): string { |
| 1339 | if (typeof replacement === 'string') { |
| 1340 | return expandReplacement( |
| 1341 | replacement, |
| 1342 | match[0], |
| 1343 | match.index, |
| 1344 | str, |
| 1345 | match.slice(1), |
| 1346 | match.groups, |
| 1347 | ) |
| 1348 | } |
| 1349 | else { |
| 1350 | // `String.prototype.replace` only passes the named-capture-groups object |
| 1351 | // when the pattern actually has named groups - passing an `undefined` |
| 1352 | // there unconditionally shifts the last argument a replacer sees |
| 1353 | return match.groups === undefined |
| 1354 | ? replacement(match[0], ...match.slice(1), match.index, str) |
| 1355 | : replacement(match[0], ...match.slice(1), match.index, str, match.groups) |
| 1356 | } |
| 1357 | } |
| 1358 | const replaceMatch = (match: RegExpMatchArray): void => { |
| 1359 | /* v8 ignore next 2 -- `match.index` is always defined for matches from `matchAll` */ |
| 1360 | if (match.index == null) |
| 1361 | return |
| 1362 | |
| 1363 | const replacement = getReplacement(match, this.original) |
| 1364 | if (replacement === match[0]) |
| 1365 | return |
| 1366 | |
| 1367 | if (match[0].length === 0) { |
| 1368 | // a zero-length match spans no characters, so there is no range to |
| 1369 | // overwrite - the replacement is an insertion at the matched position, |
| 1370 | // which is what `String.prototype.replace` does for an empty match |
| 1371 | this.appendRight(match.index, replacement) |
| 1372 | } |
| 1373 | else { |
| 1374 | this.overwrite(match.index, match.index + match[0].length, replacement) |
| 1375 | } |
| 1376 | } |
| 1377 | |
| 1378 | if (searchValue.global) { |
| 1379 | // `String.prototype.replace` starts a global regexp from the beginning of |
| 1380 | // the string, so reset `lastIndex` - a regexp that has already been used |
| 1381 | // would otherwise resume from wherever it stopped and skip earlier matches. |
| 1382 | // `matchAll` also steps over a zero-length match, where `exec` in a loop |
| 1383 | // would keep rematching it at an unmoving `lastIndex` and never terminate. |
| 1384 | searchValue.lastIndex = 0 |
| 1385 | for (const match of this.original.matchAll(searchValue)) { |
| 1386 | replaceMatch(match) |
| 1387 | } |
| 1388 | } |
| 1389 | else { |
| 1390 | const match = this.original.match(searchValue) |
| 1391 | if (match) { |
| 1392 | replaceMatch(match) |
| 1393 | } |
| 1394 | } |
no test coverage detected