1
1
import type { EcmaVersion } from "./ecma-versions"
2
2
import { latestEcmaVersion } from "./ecma-versions"
3
+ import type { GroupSpecifiers } from "./group-specifiers"
4
+ import {
5
+ GroupSpecifiersAsES2018 ,
6
+ GroupSpecifiersAsES2025 ,
7
+ } from "./group-specifiers"
3
8
import { Reader } from "./reader"
4
9
import { newRegExpSyntaxError } from "./regexp-syntax-error"
5
10
import {
@@ -231,14 +236,15 @@ export namespace RegExpValidator {
231
236
strict ?: boolean
232
237
233
238
/**
234
- * ECMAScript version. Default is `2024 `.
239
+ * ECMAScript version. Default is `2025 `.
235
240
* - `2015` added `u` and `y` flags.
236
241
* - `2018` added `s` flag, Named Capturing Group, Lookbehind Assertion,
237
242
* and Unicode Property Escape.
238
243
* - `2019`, `2020`, and `2021` added more valid Unicode Property Escapes.
239
244
* - `2022` added `d` flag.
240
245
* - `2023` added more valid Unicode Property Escapes.
241
246
* - `2024` added `v` flag.
247
+ * - `2025` added duplicate named capturing groups.
242
248
*/
243
249
ecmaVersion ?: EcmaVersion
244
250
@@ -631,7 +637,7 @@ export class RegExpValidator {
631
637
632
638
private _numCapturingParens = 0
633
639
634
- private _groupNames = new Set < string > ( )
640
+ private _groupSpecifiers : GroupSpecifiers
635
641
636
642
private _backreferenceNames = new Set < string > ( )
637
643
@@ -643,6 +649,10 @@ export class RegExpValidator {
643
649
*/
644
650
public constructor ( options ?: RegExpValidator . Options ) {
645
651
this . _options = options ?? { }
652
+ this . _groupSpecifiers =
653
+ this . ecmaVersion >= 2025
654
+ ? new GroupSpecifiersAsES2025 ( )
655
+ : new GroupSpecifiersAsES2018 ( )
646
656
}
647
657
648
658
/**
@@ -763,7 +773,7 @@ export class RegExpValidator {
763
773
if (
764
774
! this . _nFlag &&
765
775
this . ecmaVersion >= 2018 &&
766
- this . _groupNames . size > 0
776
+ ! this . _groupSpecifiers . isEmpty ( )
767
777
) {
768
778
this . _nFlag = true
769
779
this . rewind ( start )
@@ -1301,7 +1311,7 @@ export class RegExpValidator {
1301
1311
private consumePattern ( ) : void {
1302
1312
const start = this . index
1303
1313
this . _numCapturingParens = this . countCapturingParens ( )
1304
- this . _groupNames . clear ( )
1314
+ this . _groupSpecifiers . clear ( )
1305
1315
this . _backreferenceNames . clear ( )
1306
1316
1307
1317
this . onPatternEnter ( start )
@@ -1322,7 +1332,7 @@ export class RegExpValidator {
1322
1332
this . raise ( `Unexpected character '${ c } '` )
1323
1333
}
1324
1334
for ( const name of this . _backreferenceNames ) {
1325
- if ( ! this . _groupNames . has ( name ) ) {
1335
+ if ( ! this . _groupSpecifiers . hasInPattern ( name ) ) {
1326
1336
this . raise ( "Invalid named capture referenced" )
1327
1337
}
1328
1338
}
@@ -1380,7 +1390,9 @@ export class RegExpValidator {
1380
1390
1381
1391
this . onDisjunctionEnter ( start )
1382
1392
do {
1393
+ this . _groupSpecifiers . enterAlternative ( )
1383
1394
this . consumeAlternative ( i ++ )
1395
+ this . _groupSpecifiers . leaveAlternative ( )
1384
1396
} while ( this . eat ( VERTICAL_LINE ) )
1385
1397
1386
1398
if ( this . consumeQuantifier ( true ) ) {
@@ -1846,8 +1858,8 @@ export class RegExpValidator {
1846
1858
private consumeGroupSpecifier ( ) : boolean {
1847
1859
if ( this . eat ( QUESTION_MARK ) ) {
1848
1860
if ( this . eatGroupName ( ) ) {
1849
- if ( ! this . _groupNames . has ( this . _lastStrValue ) ) {
1850
- this . _groupNames . add ( this . _lastStrValue )
1861
+ if ( ! this . _groupSpecifiers . hasInScope ( this . _lastStrValue ) ) {
1862
+ this . _groupSpecifiers . addToScope ( this . _lastStrValue )
1851
1863
return true
1852
1864
}
1853
1865
this . raise ( "Duplicate capture group name" )
0 commit comments