* Expands the `$` substitution patterns that `String.prototype.replace` accepts * in a string replacement. * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_a_parameter * * `captures` holds the capture groups in order, so `ca
( replacement: string, matched: string, position: number, str: string, captures: (string | undefined)[], namedCaptures: Record<string, string | undefined> | undefined, )
| 59 | * value, where there are no groups of either kind. |
| 60 | */ |
| 61 | function expandReplacement( |
| 62 | replacement: string, |
| 63 | matched: string, |
| 64 | position: number, |
| 65 | str: string, |
| 66 | captures: (string | undefined)[], |
| 67 | namedCaptures: Record<string, string | undefined> | undefined, |
| 68 | ): string { |
| 69 | if (!replacement.includes('$')) |
| 70 | return replacement |
| 71 | |
| 72 | let result = '' |
| 73 | let index = 0 |
| 74 | |
| 75 | while (index < replacement.length) { |
| 76 | const dollar = replacement.indexOf('$', index) |
| 77 | if (dollar === -1) { |
| 78 | result += replacement.slice(index) |
| 79 | break |
| 80 | } |
| 81 | |
| 82 | result += replacement.slice(index, dollar) |
| 83 | |
| 84 | const char = replacement[dollar + 1] |
| 85 | // a `$` that introduces nothing recognisable stands for itself, so consume |
| 86 | // only the `$` and reconsider what follows as text |
| 87 | let expansion = '$' |
| 88 | let consumed = 1 |
| 89 | |
| 90 | if (char === '$') { |
| 91 | consumed = 2 |
| 92 | } |
| 93 | else if (char === '&') { |
| 94 | expansion = matched |
| 95 | consumed = 2 |
| 96 | } |
| 97 | else if (char === '`') { |
| 98 | expansion = str.slice(0, position) |
| 99 | consumed = 2 |
| 100 | } |
| 101 | else if (char === '\'') { |
| 102 | expansion = str.slice(position + matched.length) |
| 103 | consumed = 2 |
| 104 | } |
| 105 | else if (char === '<' && namedCaptures !== undefined) { |
| 106 | const close = replacement.indexOf('>', dollar + 2) |
| 107 | if (close !== -1) { |
| 108 | // an unknown group name expands to nothing rather than staying literal |
| 109 | expansion = namedCaptures[replacement.slice(dollar + 2, close)] ?? '' |
| 110 | consumed = close + 1 - dollar |
| 111 | } |
| 112 | } |
| 113 | else if (char >= '0' && char <= '9') { |
| 114 | const second = replacement[dollar + 2] |
| 115 | const double = second >= '0' && second <= '9' ? Number(char + second) : Number.NaN |
| 116 | const single = Number(char) |
| 117 | |
| 118 | // `$nn` only wins over `$n` when it names a group that exists, so `$12` |
no test coverage detected