@internal
(searchValue: RegExp, replacement: string | ReplacementFunction)
| 1359 | |
| 1360 | /** @internal */ |
| 1361 | _replaceRegexp(searchValue: RegExp, replacement: string | ReplacementFunction): this { |
| 1362 | function getReplacement(match: RegExpMatchArray, str: string): string { |
| 1363 | if (typeof replacement === 'string') { |
| 1364 | return expandReplacement( |
| 1365 | replacement, |
| 1366 | match[0], |
| 1367 | match.index, |
| 1368 | str, |
| 1369 | match.slice(1), |
| 1370 | match.groups, |
| 1371 | ) |
| 1372 | } |
| 1373 | else { |
| 1374 | // `String.prototype.replace` only passes the named-capture-groups object |
| 1375 | // when the pattern actually has named groups - passing an `undefined` |
| 1376 | // there unconditionally shifts the last argument a replacer sees |
| 1377 | return match.groups === undefined |
| 1378 | ? replacement(match[0], ...match.slice(1), match.index, str) |
| 1379 | : replacement(match[0], ...match.slice(1), match.index, str, match.groups) |
| 1380 | } |
| 1381 | } |
| 1382 | const replaceMatch = (match: RegExpMatchArray): void => { |
| 1383 | /* v8 ignore next 2 -- `match.index` is always defined for matches from `matchAll` */ |
| 1384 | if (match.index == null) |
| 1385 | return |
| 1386 | |
| 1387 | const replacement = getReplacement(match, this.original) |
| 1388 | if (replacement === match[0]) |
| 1389 | return |
| 1390 | |
| 1391 | if (match[0].length === 0) { |
| 1392 | // a zero-length match spans no characters, so there is no range to |
| 1393 | // overwrite - the replacement is an insertion at the matched position, |
| 1394 | // which is what `String.prototype.replace` does for an empty match |
| 1395 | this.appendRight(match.index, replacement) |
| 1396 | } |
| 1397 | else { |
| 1398 | this.overwrite(match.index, match.index + match[0].length, replacement) |
| 1399 | } |
| 1400 | } |
| 1401 | |
| 1402 | if (searchValue.global) { |
| 1403 | // `String.prototype.replace` starts a global regexp from the beginning of |
| 1404 | // the string, so reset `lastIndex` - a regexp that has already been used |
| 1405 | // would otherwise resume from wherever it stopped and skip earlier matches. |
| 1406 | // `matchAll` also steps over a zero-length match, where `exec` in a loop |
| 1407 | // would keep rematching it at an unmoving `lastIndex` and never terminate. |
| 1408 | searchValue.lastIndex = 0 |
| 1409 | for (const match of this.original.matchAll(searchValue)) { |
| 1410 | replaceMatch(match) |
| 1411 | } |
| 1412 | } |
| 1413 | else { |
| 1414 | const match = this.original.match(searchValue) |
| 1415 | if (match) { |
| 1416 | replaceMatch(match) |
| 1417 | } |
| 1418 | } |
no test coverage detected