Skip to content

Commit 2df85e3

Browse files
committed
Don't copy existing transfer markers for emulation groups in recursed subpattern
1 parent ea6fb10 commit 2df85e3

File tree

1 file changed

+13
-8
lines changed

1 file changed

+13
-8
lines changed

src/index.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const recursiveToken = r`\(\?R=(?<rDepth>[^\)]+)\)|${gRToken}`;
77
const namedCapturingDelim = r`\(\?<(?![=!])(?<captureName>[^>]+)>`;
88
const token = new RegExp(r`${namedCapturingDelim}|${recursiveToken}|\(\?|\\?.`, 'gsu');
99
const overlappingRecursionMsg = 'Cannot use multiple overlapping recursions';
10+
// Support emulation groups with transfer marker prefix
11+
const emulationGroupMarkerRe = new RegExp(r`(?:\$[1-9]\d*)?${emulationGroupMarker.replace(/\$/g, r`\$`)}`, 'y');
1012

1113
/**
1214
@param {string} expression
@@ -101,6 +103,7 @@ export function recursion(expression, data) {
101103
hasRecursed = true;
102104
} else if (captureName) {
103105
numCaptures++;
106+
// NOTE: Not currently handling *named* emulation groups that already exist in the pattern
104107
groupContentsStartPos.set(String(numCaptures), token.lastIndex);
105108
groupContentsStartPos.set(captureName, token.lastIndex);
106109
openGroups.push({
@@ -185,16 +188,20 @@ function repeatWithDepth(expression, reps, namesInRecursed, direction, useEmulat
185188
const captureNum = depthNum(i);
186189
result += replaceUnescaped(
187190
expression,
188-
r`${namedCapturingDelim}|\\k<(?<backref>[^>]+)>${useEmulationGroups ? r`|\((?!\?)` : ''}`,
189-
({0: m, index, groups: {captureName, backref}}) => {
191+
// NOTE: Not currently handling *named* emulation groups that already exist in the pattern
192+
r`${namedCapturingDelim}|\\k<(?<backref>[^>]+)>${
193+
useEmulationGroups ? r`|(?<unnamed>\()(?!\?)(?:${emulationGroupMarkerRe.source})?` : ''
194+
}`,
195+
({0: m, index, groups: {captureName, backref, unnamed}}) => {
190196
if (backref && namesInRecursed && !namesInRecursed.has(backref)) {
191197
// Don't alter backrefs to groups outside the recursed subpattern
192198
return m;
193199
}
194-
// `(` only matched if `useEmulationGroups`
195-
if (m === '(') {
196-
// Add an emulation group marker if there isn't one already
197-
return `(${emulationGroupMarkerLength(expression, index + 1) ? '' : emulationGroupMarker}`;
200+
// Only matches unnamed capture delim if `useEmulationGroups`
201+
if (unnamed) {
202+
// Add an emulation group marker, possibly replacing an existing marker (removes any
203+
// transfer prefix)
204+
return `(${emulationGroupMarker}`;
198205
}
199206
const suffix = `_$${captureNum}`;
200207
return captureName ?
@@ -207,8 +214,6 @@ function repeatWithDepth(expression, reps, namesInRecursed, direction, useEmulat
207214
return result;
208215
}
209216

210-
const emulationGroupMarkerRe = new RegExp(r`(?:\$[1-9]\d*)?${emulationGroupMarker.replace(/\$/g, r`\$`)}`, 'y');
211-
212217
function emulationGroupMarkerLength(expression, index) {
213218
emulationGroupMarkerRe.lastIndex = index;
214219
const match = emulationGroupMarkerRe.exec(expression);

0 commit comments

Comments
 (0)