Skip to content

Commit

Permalink
Fix emulation groups with transfer given emulation groups that adjust…
Browse files Browse the repository at this point in the history
… capture indices
  • Loading branch information
slevithan committed Dec 26, 2024
1 parent 7d971b0 commit 5577cc1
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 15 deletions.
62 changes: 52 additions & 10 deletions spec/regex-tag.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,25 +167,67 @@ describe('regex', () => {

it('should adjust for emulation groups with transfer', () => {
const transferTo1 = `$1${emulationGroupMarker}`;
expect(regex({subclass: true, disable: {n: true}})({raw: [`^(a)(${transferTo1}b)$`]}).exec('ab')[1]).toBe('b');
expect(regex({subclass: true, disable: {n: true}})({raw: [`^(?<a>a)(${transferTo1}b)$`]}).exec('ab').groups.a).toBe('b');
expect(regex({subclass: true, disable: {n: true}})({raw: [`^(?<a>a)(${transferTo1}b)(${transferTo1}c)$`]}).exec('abc').groups.a).toBe('c');
expect(regex({subclass: true, disable: {n: true}})({raw: [
`^(a)(${transferTo1}b)$`
]}).exec('ab')[1]).toBe('b');
expect(regex({subclass: true, disable: {n: true}})({raw: [
`^(?<a>a)(${transferTo1}b)$`
]}).exec('ab').groups.a).toBe('b');
expect(regex({subclass: true, disable: {n: true}})({raw: [
`^(?<a>a)(${transferTo1}b)(${transferTo1}c)$`
]}).exec('abc').groups.a).toBe('c');
// ## Documenting behavior without transfer
expect(regex({subclass: true, disable: {n: true}})({raw: [`^(a)(${emulationGroupMarker}b)$`]}).exec('ab')[1]).toBe('a');
expect(regex({subclass: true, disable: {n: true}})({raw: [`^(?<a>a)(${emulationGroupMarker}b)$`]}).exec('ab').groups.a).toBe('a');
expect(regex({subclass: true, disable: {n: true}})({raw: [
`^(a)(${emulationGroupMarker}b)$`
]}).exec('ab')[1]).toBe('a');
expect(regex({subclass: true, disable: {n: true}})({raw: [
`^(?<a>a)(${emulationGroupMarker}b)$`
]}).exec('ab').groups.a).toBe('a');
});

it('should adjust indices with flag d for emulation groups with transfer', () => {
if (!envSupportsFlagD) {
pending('requires support for flag d (Node.js 16)');
}
const transferTo1 = `$1${emulationGroupMarker}`;
expect(regex({flags: 'd', subclass: true, disable: {n: true}})({raw: [`^(a)(${transferTo1}b)$`]}).exec('ab').indices[1]).toEqual([1, 2]);
expect(regex({flags: 'd', subclass: true, disable: {n: true}})({raw: [`^(?<a>a)(${transferTo1}b)$`]}).exec('ab').indices.groups.a).toEqual([1, 2]);
expect(regex({flags: 'd', subclass: true, disable: {n: true}})({raw: [`^(?<a>a)(${transferTo1}b)(${transferTo1}c)$`]}).exec('abc').indices.groups.a).toEqual([2, 3]);
expect(regex({flags: 'd', subclass: true, disable: {n: true}})({raw: [
`^(a)(${transferTo1}b)$`
]}).exec('ab').indices[1]).toEqual([1, 2]);
expect(regex({flags: 'd', subclass: true, disable: {n: true}})({raw: [
`^(?<a>a)(${transferTo1}b)$`
]}).exec('ab').indices.groups.a).toEqual([1, 2]);
expect(regex({flags: 'd', subclass: true, disable: {n: true}})({raw: [
`^(?<a>a)(${transferTo1}b)(${transferTo1}c)$`
]}).exec('abc').indices.groups.a).toEqual([2, 3]);
// ## Documenting behavior without transfer
expect(regex({flags: 'd', subclass: true, disable: {n: true}})({raw: [`^(a)(${emulationGroupMarker}b)$`]}).exec('ab').indices[1]).toEqual([0, 1]);
expect(regex({flags: 'd', subclass: true, disable: {n: true}})({raw: [`^(?<a>a)(${emulationGroupMarker}b)$`]}).exec('ab').indices.groups.a).toEqual([0, 1]);
expect(regex({flags: 'd', subclass: true, disable: {n: true}})({raw: [
`^(a)(${emulationGroupMarker}b)$`
]}).exec('ab').indices[1]).toEqual([0, 1]);
expect(regex({flags: 'd', subclass: true, disable: {n: true}})({raw: [
`^(?<a>a)(${emulationGroupMarker}b)$`
]}).exec('ab').indices.groups.a).toEqual([0, 1]);
});

it('should adjust for emulation groups with transfer given emulation groups that adjust capture indices', () => {
if (!envSupportsFlagD) {
pending('requires support for flag d (Node.js 16)');
}
const egm = emulationGroupMarker;
const transferTo1 = `$1${egm}`;
const transferTo2 = `$2${egm}`;
const match = regex({flags: 'd', subclass: true, disable: {n: true}})({raw: [
`^(${egm}(${egm}.))(?<a>(${transferTo2}.))(${transferTo1}(${transferTo2}.))(?<b>.)$`
]}).exec('abcd');
expect(match[1]).toBe('c');
expect(match[2]).toBe('d');
expect(match).toHaveSize(3);
expect(match.indices[1]).toEqual([2, 3]);
expect(match.indices[2]).toEqual([3, 4]);
expect(match.indices).toHaveSize(3);
expect(match.groups.a).toBe('c');
expect(match.groups.b).toBe('d');
expect(match.indices.groups.a).toEqual([2, 3]);
expect(match.indices.groups.b).toEqual([3, 4]);
});
});
});
Expand Down
10 changes: 5 additions & 5 deletions src/subclass.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,22 +111,22 @@ function unmarkEmulationGroups(expression) {
const marker = emulationGroupMarker.replace(/\$/g, '\\$');
const _captureMap = [{exclude: false}];
const _namesByIndex = {0: ''};
let captureNum = 0;
let realCaptureNum = 0;
expression = replaceUnescaped(
expression,
String.raw`\((?:(?!\?)|\?<(?![=!])(?<name>[^>]+)>)(?<mark>(?:\$(?<transfer>[1-9]\d*))?${marker})?`,
({0: m, groups: {name, mark, transfer}}) => {
captureNum++;
if (name) {
_namesByIndex[captureNum] = name;
}
if (mark) {
_captureMap.push({
exclude: true,
transfer: transfer && +transfer,
});
return m.slice(0, -mark.length);
}
realCaptureNum++;
if (name) {
_namesByIndex[realCaptureNum] = name;
}
_captureMap.push({
exclude: false,
});
Expand Down

0 comments on commit 5577cc1

Please sign in to comment.