@eslint-community/regexpp 4.11.1 → 4.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +87 -3
- package/index.js +234 -65
- package/index.js.map +1 -1
- package/index.mjs +234 -65
- package/index.mjs.map +1 -1
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -51,6 +51,7 @@ declare module "@eslint-community/regexpp/ast" {
|
|
|
51
51
|
| ExpressionCharacterClass
|
|
52
52
|
| Group
|
|
53
53
|
| LookaroundAssertion
|
|
54
|
+
| Modifiers
|
|
54
55
|
| Pattern
|
|
55
56
|
| Quantifier
|
|
56
57
|
| RegExpLiteral
|
|
@@ -63,7 +64,8 @@ declare module "@eslint-community/regexpp/ast" {
|
|
|
63
64
|
| BoundaryAssertion
|
|
64
65
|
| Character
|
|
65
66
|
| CharacterSet
|
|
66
|
-
| Flags
|
|
67
|
+
| Flags
|
|
68
|
+
| ModifierFlags;
|
|
67
69
|
/**
|
|
68
70
|
* The type which includes all atom nodes.
|
|
69
71
|
*/
|
|
@@ -147,6 +149,7 @@ declare module "@eslint-community/regexpp/ast" {
|
|
|
147
149
|
export interface Group extends NodeBase {
|
|
148
150
|
type: "Group";
|
|
149
151
|
parent: Alternative | Quantifier;
|
|
152
|
+
modifiers: Modifiers | null;
|
|
150
153
|
alternatives: Alternative[];
|
|
151
154
|
}
|
|
152
155
|
/**
|
|
@@ -447,6 +450,34 @@ declare module "@eslint-community/regexpp/ast" {
|
|
|
447
450
|
ambiguous: false;
|
|
448
451
|
resolved: CapturingGroup;
|
|
449
452
|
}
|
|
453
|
+
/**
|
|
454
|
+
* The modifiers.
|
|
455
|
+
*/
|
|
456
|
+
export interface Modifiers extends NodeBase {
|
|
457
|
+
type: "Modifiers";
|
|
458
|
+
parent: Group;
|
|
459
|
+
/**
|
|
460
|
+
* The add modifier flags.
|
|
461
|
+
*/
|
|
462
|
+
add: ModifierFlags;
|
|
463
|
+
/**
|
|
464
|
+
* The remove modifier flags.
|
|
465
|
+
*
|
|
466
|
+
* `null` means no remove modifier flags. e.g. `(?ims:x)`
|
|
467
|
+
* The reason for `null` is that there is no position where the remove modifier flags appears. Must be behind the minus mark.
|
|
468
|
+
*/
|
|
469
|
+
remove: ModifierFlags | null;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* The modifier flags.
|
|
473
|
+
*/
|
|
474
|
+
export interface ModifierFlags extends NodeBase {
|
|
475
|
+
type: "ModifierFlags";
|
|
476
|
+
parent: Modifiers;
|
|
477
|
+
dotAll: boolean;
|
|
478
|
+
ignoreCase: boolean;
|
|
479
|
+
multiline: boolean;
|
|
480
|
+
}
|
|
450
481
|
/**
|
|
451
482
|
* The flags.
|
|
452
483
|
*/
|
|
@@ -490,7 +521,7 @@ declare module "@eslint-community/regexpp/parser" {
|
|
|
490
521
|
* - `2022` added `d` flag.
|
|
491
522
|
* - `2023` added more valid Unicode Property Escapes.
|
|
492
523
|
* - `2024` added `v` flag.
|
|
493
|
-
* - `2025` added duplicate named capturing groups.
|
|
524
|
+
* - `2025` added duplicate named capturing groups, modifiers.
|
|
494
525
|
*/
|
|
495
526
|
ecmaVersion?: EcmaVersion;
|
|
496
527
|
}
|
|
@@ -579,7 +610,7 @@ declare module "@eslint-community/regexpp/validator" {
|
|
|
579
610
|
* - `2022` added `d` flag.
|
|
580
611
|
* - `2023` added more valid Unicode Property Escapes.
|
|
581
612
|
* - `2024` added `v` flag.
|
|
582
|
-
* - `2025` added duplicate named capturing groups.
|
|
613
|
+
* - `2025` added duplicate named capturing groups, modifiers.
|
|
583
614
|
*/
|
|
584
615
|
ecmaVersion?: EcmaVersion;
|
|
585
616
|
/**
|
|
@@ -691,6 +722,53 @@ declare module "@eslint-community/regexpp/validator" {
|
|
|
691
722
|
* @param end The next 0-based index of the last character.
|
|
692
723
|
*/
|
|
693
724
|
onGroupLeave?: (start: number, end: number) => void;
|
|
725
|
+
/**
|
|
726
|
+
* A function that is called when the validator entered a modifiers.
|
|
727
|
+
* @param start The 0-based index of the first character.
|
|
728
|
+
*/
|
|
729
|
+
onModifiersEnter?: (start: number) => void;
|
|
730
|
+
/**
|
|
731
|
+
* A function that is called when the validator left a modifiers.
|
|
732
|
+
* @param start The 0-based index of the first character.
|
|
733
|
+
* @param end The next 0-based index of the last character.
|
|
734
|
+
*/
|
|
735
|
+
onModifiersLeave?: (start: number, end: number) => void;
|
|
736
|
+
/**
|
|
737
|
+
* A function that is called when the validator found an add modifiers.
|
|
738
|
+
* @param start The 0-based index of the first character.
|
|
739
|
+
* @param end The next 0-based index of the last character.
|
|
740
|
+
* @param flags flags.
|
|
741
|
+
* @param flags.ignoreCase `i` flag.
|
|
742
|
+
* @param flags.multiline `m` flag.
|
|
743
|
+
* @param flags.dotAll `s` flag.
|
|
744
|
+
*/
|
|
745
|
+
onAddModifiers?: (
|
|
746
|
+
start: number,
|
|
747
|
+
end: number,
|
|
748
|
+
flags: {
|
|
749
|
+
ignoreCase: boolean;
|
|
750
|
+
multiline: boolean;
|
|
751
|
+
dotAll: boolean;
|
|
752
|
+
}
|
|
753
|
+
) => void;
|
|
754
|
+
/**
|
|
755
|
+
* A function that is called when the validator found a remove modifiers.
|
|
756
|
+
* @param start The 0-based index of the first character.
|
|
757
|
+
* @param end The next 0-based index of the last character.
|
|
758
|
+
* @param flags flags.
|
|
759
|
+
* @param flags.ignoreCase `i` flag.
|
|
760
|
+
* @param flags.multiline `m` flag.
|
|
761
|
+
* @param flags.dotAll `s` flag.
|
|
762
|
+
*/
|
|
763
|
+
onRemoveModifiers?: (
|
|
764
|
+
start: number,
|
|
765
|
+
end: number,
|
|
766
|
+
flags: {
|
|
767
|
+
ignoreCase: boolean;
|
|
768
|
+
multiline: boolean;
|
|
769
|
+
dotAll: boolean;
|
|
770
|
+
}
|
|
771
|
+
) => void;
|
|
694
772
|
/**
|
|
695
773
|
* A function that is called when the validator entered a capturing group.
|
|
696
774
|
* @param start The 0-based index of the first character.
|
|
@@ -977,6 +1055,8 @@ declare module "@eslint-community/regexpp/visitor" {
|
|
|
977
1055
|
ExpressionCharacterClass,
|
|
978
1056
|
Flags,
|
|
979
1057
|
Group,
|
|
1058
|
+
ModifierFlags,
|
|
1059
|
+
Modifiers,
|
|
980
1060
|
Node,
|
|
981
1061
|
Pattern,
|
|
982
1062
|
Quantifier,
|
|
@@ -1032,6 +1112,10 @@ declare module "@eslint-community/regexpp/visitor" {
|
|
|
1032
1112
|
onFlagsLeave?: (node: Flags) => void;
|
|
1033
1113
|
onGroupEnter?: (node: Group) => void;
|
|
1034
1114
|
onGroupLeave?: (node: Group) => void;
|
|
1115
|
+
onModifierFlagsEnter?: (node: ModifierFlags) => void;
|
|
1116
|
+
onModifierFlagsLeave?: (node: ModifierFlags) => void;
|
|
1117
|
+
onModifiersEnter?: (node: Modifiers) => void;
|
|
1118
|
+
onModifiersLeave?: (node: Modifiers) => void;
|
|
1035
1119
|
onPatternEnter?: (node: Pattern) => void;
|
|
1036
1120
|
onPatternLeave?: (node: Pattern) => void;
|
|
1037
1121
|
onQuantifierEnter?: (node: Quantifier) => void;
|
package/index.js
CHANGED
|
@@ -552,6 +552,17 @@ const CLASS_SET_RESERVED_PUNCTUATOR = new Set([
|
|
|
552
552
|
GRAVE_ACCENT,
|
|
553
553
|
TILDE,
|
|
554
554
|
]);
|
|
555
|
+
const FLAG_PROP_TO_CODEPOINT = {
|
|
556
|
+
global: LATIN_SMALL_LETTER_G,
|
|
557
|
+
ignoreCase: LATIN_SMALL_LETTER_I,
|
|
558
|
+
multiline: LATIN_SMALL_LETTER_M,
|
|
559
|
+
unicode: LATIN_SMALL_LETTER_U,
|
|
560
|
+
sticky: LATIN_SMALL_LETTER_Y,
|
|
561
|
+
dotAll: LATIN_SMALL_LETTER_S,
|
|
562
|
+
hasIndices: LATIN_SMALL_LETTER_D,
|
|
563
|
+
unicodeSets: LATIN_SMALL_LETTER_V,
|
|
564
|
+
};
|
|
565
|
+
const FLAG_CODEPOINT_TO_PROP = Object.fromEntries(Object.entries(FLAG_PROP_TO_CODEPOINT).map(([k, v]) => [v, k]));
|
|
555
566
|
function isSyntaxCharacter(cp) {
|
|
556
567
|
return SYNTAX_CHARACTER.has(cp);
|
|
557
568
|
}
|
|
@@ -579,6 +590,11 @@ function isUnicodePropertyNameCharacter(cp) {
|
|
|
579
590
|
function isUnicodePropertyValueCharacter(cp) {
|
|
580
591
|
return isUnicodePropertyNameCharacter(cp) || isDecimalDigit(cp);
|
|
581
592
|
}
|
|
593
|
+
function isRegularExpressionModifier(ch) {
|
|
594
|
+
return (ch === LATIN_SMALL_LETTER_I ||
|
|
595
|
+
ch === LATIN_SMALL_LETTER_M ||
|
|
596
|
+
ch === LATIN_SMALL_LETTER_S);
|
|
597
|
+
}
|
|
582
598
|
class RegExpValidator {
|
|
583
599
|
constructor(options) {
|
|
584
600
|
this._reader = new Reader();
|
|
@@ -649,64 +665,8 @@ class RegExpValidator {
|
|
|
649
665
|
}
|
|
650
666
|
}
|
|
651
667
|
validateFlagsInternal(source, start, end) {
|
|
652
|
-
const
|
|
653
|
-
|
|
654
|
-
let ignoreCase = false;
|
|
655
|
-
let multiline = false;
|
|
656
|
-
let sticky = false;
|
|
657
|
-
let unicode = false;
|
|
658
|
-
let dotAll = false;
|
|
659
|
-
let hasIndices = false;
|
|
660
|
-
let unicodeSets = false;
|
|
661
|
-
for (let i = start; i < end; ++i) {
|
|
662
|
-
const flag = source.charCodeAt(i);
|
|
663
|
-
if (existingFlags.has(flag)) {
|
|
664
|
-
this.raise(`Duplicated flag '${source[i]}'`, { index: start });
|
|
665
|
-
}
|
|
666
|
-
existingFlags.add(flag);
|
|
667
|
-
if (flag === LATIN_SMALL_LETTER_G) {
|
|
668
|
-
global = true;
|
|
669
|
-
}
|
|
670
|
-
else if (flag === LATIN_SMALL_LETTER_I) {
|
|
671
|
-
ignoreCase = true;
|
|
672
|
-
}
|
|
673
|
-
else if (flag === LATIN_SMALL_LETTER_M) {
|
|
674
|
-
multiline = true;
|
|
675
|
-
}
|
|
676
|
-
else if (flag === LATIN_SMALL_LETTER_U &&
|
|
677
|
-
this.ecmaVersion >= 2015) {
|
|
678
|
-
unicode = true;
|
|
679
|
-
}
|
|
680
|
-
else if (flag === LATIN_SMALL_LETTER_Y &&
|
|
681
|
-
this.ecmaVersion >= 2015) {
|
|
682
|
-
sticky = true;
|
|
683
|
-
}
|
|
684
|
-
else if (flag === LATIN_SMALL_LETTER_S &&
|
|
685
|
-
this.ecmaVersion >= 2018) {
|
|
686
|
-
dotAll = true;
|
|
687
|
-
}
|
|
688
|
-
else if (flag === LATIN_SMALL_LETTER_D &&
|
|
689
|
-
this.ecmaVersion >= 2022) {
|
|
690
|
-
hasIndices = true;
|
|
691
|
-
}
|
|
692
|
-
else if (flag === LATIN_SMALL_LETTER_V &&
|
|
693
|
-
this.ecmaVersion >= 2024) {
|
|
694
|
-
unicodeSets = true;
|
|
695
|
-
}
|
|
696
|
-
else {
|
|
697
|
-
this.raise(`Invalid flag '${source[i]}'`, { index: start });
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
this.onRegExpFlags(start, end, {
|
|
701
|
-
global,
|
|
702
|
-
ignoreCase,
|
|
703
|
-
multiline,
|
|
704
|
-
unicode,
|
|
705
|
-
sticky,
|
|
706
|
-
dotAll,
|
|
707
|
-
hasIndices,
|
|
708
|
-
unicodeSets,
|
|
709
|
-
});
|
|
668
|
+
const flags = this.parseFlags(source, start, end);
|
|
669
|
+
this.onRegExpFlags(start, end, flags);
|
|
710
670
|
}
|
|
711
671
|
_parseFlagsOptionToMode(uFlagOrFlags, sourceEnd) {
|
|
712
672
|
let unicode = false;
|
|
@@ -801,6 +761,26 @@ class RegExpValidator {
|
|
|
801
761
|
this._options.onGroupLeave(start, end);
|
|
802
762
|
}
|
|
803
763
|
}
|
|
764
|
+
onModifiersEnter(start) {
|
|
765
|
+
if (this._options.onModifiersEnter) {
|
|
766
|
+
this._options.onModifiersEnter(start);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
onModifiersLeave(start, end) {
|
|
770
|
+
if (this._options.onModifiersLeave) {
|
|
771
|
+
this._options.onModifiersLeave(start, end);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
onAddModifiers(start, end, flags) {
|
|
775
|
+
if (this._options.onAddModifiers) {
|
|
776
|
+
this._options.onAddModifiers(start, end, flags);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
onRemoveModifiers(start, end, flags) {
|
|
780
|
+
if (this._options.onRemoveModifiers) {
|
|
781
|
+
this._options.onRemoveModifiers(start, end, flags);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
804
784
|
onCapturingGroupEnter(start, name) {
|
|
805
785
|
if (this._options.onCapturingGroupEnter) {
|
|
806
786
|
this._options.onCapturingGroupEnter(start, name);
|
|
@@ -1173,8 +1153,8 @@ class RegExpValidator {
|
|
|
1173
1153
|
this.consumeDot() ||
|
|
1174
1154
|
this.consumeReverseSolidusAtomEscape() ||
|
|
1175
1155
|
Boolean(this.consumeCharacterClass()) ||
|
|
1176
|
-
this.
|
|
1177
|
-
this.
|
|
1156
|
+
this.consumeCapturingGroup() ||
|
|
1157
|
+
this.consumeUncapturingGroup());
|
|
1178
1158
|
}
|
|
1179
1159
|
consumeDot() {
|
|
1180
1160
|
if (this.eat(FULL_STOP)) {
|
|
@@ -1195,8 +1175,15 @@ class RegExpValidator {
|
|
|
1195
1175
|
}
|
|
1196
1176
|
consumeUncapturingGroup() {
|
|
1197
1177
|
const start = this.index;
|
|
1198
|
-
if (this.
|
|
1178
|
+
if (this.eat2(LEFT_PARENTHESIS, QUESTION_MARK)) {
|
|
1199
1179
|
this.onGroupEnter(start);
|
|
1180
|
+
if (this.ecmaVersion >= 2025) {
|
|
1181
|
+
this.consumeModifiers();
|
|
1182
|
+
}
|
|
1183
|
+
if (!this.eat(COLON)) {
|
|
1184
|
+
this.rewind(start + 1);
|
|
1185
|
+
this.raise("Invalid group");
|
|
1186
|
+
}
|
|
1200
1187
|
this.consumeDisjunction();
|
|
1201
1188
|
if (!this.eat(RIGHT_PARENTHESIS)) {
|
|
1202
1189
|
this.raise("Unterminated group");
|
|
@@ -1206,6 +1193,35 @@ class RegExpValidator {
|
|
|
1206
1193
|
}
|
|
1207
1194
|
return false;
|
|
1208
1195
|
}
|
|
1196
|
+
consumeModifiers() {
|
|
1197
|
+
const start = this.index;
|
|
1198
|
+
const hasAddModifiers = this.eatModifiers();
|
|
1199
|
+
const addModifiersEnd = this.index;
|
|
1200
|
+
const hasHyphen = this.eat(HYPHEN_MINUS);
|
|
1201
|
+
if (!hasAddModifiers && !hasHyphen) {
|
|
1202
|
+
return false;
|
|
1203
|
+
}
|
|
1204
|
+
this.onModifiersEnter(start);
|
|
1205
|
+
const addModifiers = this.parseModifiers(start, addModifiersEnd);
|
|
1206
|
+
this.onAddModifiers(start, addModifiersEnd, addModifiers);
|
|
1207
|
+
if (hasHyphen) {
|
|
1208
|
+
const modifiersStart = this.index;
|
|
1209
|
+
if (!this.eatModifiers() &&
|
|
1210
|
+
!hasAddModifiers &&
|
|
1211
|
+
this.currentCodePoint === COLON) {
|
|
1212
|
+
this.raise("Invalid empty flags");
|
|
1213
|
+
}
|
|
1214
|
+
const modifiers = this.parseModifiers(modifiersStart, this.index);
|
|
1215
|
+
for (const [flagName] of Object.entries(modifiers).filter(([, enable]) => enable)) {
|
|
1216
|
+
if (addModifiers[flagName]) {
|
|
1217
|
+
this.raise(`Duplicated flag '${String.fromCodePoint(FLAG_PROP_TO_CODEPOINT[flagName])}'`);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
this.onRemoveModifiers(modifiersStart, this.index, modifiers);
|
|
1221
|
+
}
|
|
1222
|
+
this.onModifiersLeave(start, this.index);
|
|
1223
|
+
return true;
|
|
1224
|
+
}
|
|
1209
1225
|
consumeCapturingGroup() {
|
|
1210
1226
|
const start = this.index;
|
|
1211
1227
|
if (this.eat(LEFT_PARENTHESIS)) {
|
|
@@ -1214,9 +1230,14 @@ class RegExpValidator {
|
|
|
1214
1230
|
if (this.consumeGroupSpecifier()) {
|
|
1215
1231
|
name = this._lastStrValue;
|
|
1216
1232
|
}
|
|
1233
|
+
else if (this.currentCodePoint === QUESTION_MARK) {
|
|
1234
|
+
this.rewind(start);
|
|
1235
|
+
return false;
|
|
1236
|
+
}
|
|
1217
1237
|
}
|
|
1218
1238
|
else if (this.currentCodePoint === QUESTION_MARK) {
|
|
1219
|
-
this.
|
|
1239
|
+
this.rewind(start);
|
|
1240
|
+
return false;
|
|
1220
1241
|
}
|
|
1221
1242
|
this.onCapturingGroupEnter(start, name);
|
|
1222
1243
|
this.consumeDisjunction();
|
|
@@ -1233,8 +1254,8 @@ class RegExpValidator {
|
|
|
1233
1254
|
this.consumeReverseSolidusAtomEscape() ||
|
|
1234
1255
|
this.consumeReverseSolidusFollowedByC() ||
|
|
1235
1256
|
Boolean(this.consumeCharacterClass()) ||
|
|
1236
|
-
this.consumeUncapturingGroup() ||
|
|
1237
1257
|
this.consumeCapturingGroup() ||
|
|
1258
|
+
this.consumeUncapturingGroup() ||
|
|
1238
1259
|
this.consumeInvalidBracedQuantifier() ||
|
|
1239
1260
|
this.consumeExtendedPatternCharacter());
|
|
1240
1261
|
}
|
|
@@ -1287,6 +1308,7 @@ class RegExpValidator {
|
|
|
1287
1308
|
return false;
|
|
1288
1309
|
}
|
|
1289
1310
|
consumeGroupSpecifier() {
|
|
1311
|
+
const start = this.index;
|
|
1290
1312
|
if (this.eat(QUESTION_MARK)) {
|
|
1291
1313
|
if (this.eatGroupName()) {
|
|
1292
1314
|
if (!this._groupSpecifiers.hasInScope(this._lastStrValue)) {
|
|
@@ -1295,7 +1317,7 @@ class RegExpValidator {
|
|
|
1295
1317
|
}
|
|
1296
1318
|
this.raise("Duplicate capture group name");
|
|
1297
1319
|
}
|
|
1298
|
-
this.
|
|
1320
|
+
this.rewind(start);
|
|
1299
1321
|
}
|
|
1300
1322
|
return false;
|
|
1301
1323
|
}
|
|
@@ -2043,6 +2065,63 @@ class RegExpValidator {
|
|
|
2043
2065
|
}
|
|
2044
2066
|
return true;
|
|
2045
2067
|
}
|
|
2068
|
+
eatModifiers() {
|
|
2069
|
+
let ate = false;
|
|
2070
|
+
while (isRegularExpressionModifier(this.currentCodePoint)) {
|
|
2071
|
+
this.advance();
|
|
2072
|
+
ate = true;
|
|
2073
|
+
}
|
|
2074
|
+
return ate;
|
|
2075
|
+
}
|
|
2076
|
+
parseModifiers(start, end) {
|
|
2077
|
+
const { ignoreCase, multiline, dotAll } = this.parseFlags(this._reader.source, start, end);
|
|
2078
|
+
return { ignoreCase, multiline, dotAll };
|
|
2079
|
+
}
|
|
2080
|
+
parseFlags(source, start, end) {
|
|
2081
|
+
const flags = {
|
|
2082
|
+
global: false,
|
|
2083
|
+
ignoreCase: false,
|
|
2084
|
+
multiline: false,
|
|
2085
|
+
unicode: false,
|
|
2086
|
+
sticky: false,
|
|
2087
|
+
dotAll: false,
|
|
2088
|
+
hasIndices: false,
|
|
2089
|
+
unicodeSets: false,
|
|
2090
|
+
};
|
|
2091
|
+
const validFlags = new Set();
|
|
2092
|
+
validFlags.add(LATIN_SMALL_LETTER_G);
|
|
2093
|
+
validFlags.add(LATIN_SMALL_LETTER_I);
|
|
2094
|
+
validFlags.add(LATIN_SMALL_LETTER_M);
|
|
2095
|
+
if (this.ecmaVersion >= 2015) {
|
|
2096
|
+
validFlags.add(LATIN_SMALL_LETTER_U);
|
|
2097
|
+
validFlags.add(LATIN_SMALL_LETTER_Y);
|
|
2098
|
+
if (this.ecmaVersion >= 2018) {
|
|
2099
|
+
validFlags.add(LATIN_SMALL_LETTER_S);
|
|
2100
|
+
if (this.ecmaVersion >= 2021) {
|
|
2101
|
+
validFlags.add(LATIN_SMALL_LETTER_D);
|
|
2102
|
+
if (this.ecmaVersion >= 2024) {
|
|
2103
|
+
validFlags.add(LATIN_SMALL_LETTER_V);
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
for (let i = start; i < end; ++i) {
|
|
2109
|
+
const flag = source.charCodeAt(i);
|
|
2110
|
+
if (validFlags.has(flag)) {
|
|
2111
|
+
const prop = FLAG_CODEPOINT_TO_PROP[flag];
|
|
2112
|
+
if (flags[prop]) {
|
|
2113
|
+
this.raise(`Duplicated flag '${source[i]}'`, {
|
|
2114
|
+
index: start,
|
|
2115
|
+
});
|
|
2116
|
+
}
|
|
2117
|
+
flags[prop] = true;
|
|
2118
|
+
}
|
|
2119
|
+
else {
|
|
2120
|
+
this.raise(`Invalid flag '${source[i]}'`, { index: start });
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
return flags;
|
|
2124
|
+
}
|
|
2046
2125
|
}
|
|
2047
2126
|
|
|
2048
2127
|
const DUMMY_PATTERN = {};
|
|
@@ -2162,14 +2241,16 @@ class RegExpParserState {
|
|
|
2162
2241
|
if (parent.type !== "Alternative") {
|
|
2163
2242
|
throw new Error("UnknownError");
|
|
2164
2243
|
}
|
|
2165
|
-
|
|
2244
|
+
const group = {
|
|
2166
2245
|
type: "Group",
|
|
2167
2246
|
parent,
|
|
2168
2247
|
start,
|
|
2169
2248
|
end: start,
|
|
2170
2249
|
raw: "",
|
|
2250
|
+
modifiers: null,
|
|
2171
2251
|
alternatives: [],
|
|
2172
2252
|
};
|
|
2253
|
+
this._node = group;
|
|
2173
2254
|
parent.elements.push(this._node);
|
|
2174
2255
|
}
|
|
2175
2256
|
onGroupLeave(start, end) {
|
|
@@ -2181,6 +2262,63 @@ class RegExpParserState {
|
|
|
2181
2262
|
node.raw = this.source.slice(start, end);
|
|
2182
2263
|
this._node = node.parent;
|
|
2183
2264
|
}
|
|
2265
|
+
onModifiersEnter(start) {
|
|
2266
|
+
const parent = this._node;
|
|
2267
|
+
if (parent.type !== "Group") {
|
|
2268
|
+
throw new Error("UnknownError");
|
|
2269
|
+
}
|
|
2270
|
+
this._node = {
|
|
2271
|
+
type: "Modifiers",
|
|
2272
|
+
parent,
|
|
2273
|
+
start,
|
|
2274
|
+
end: start,
|
|
2275
|
+
raw: "",
|
|
2276
|
+
add: null,
|
|
2277
|
+
remove: null,
|
|
2278
|
+
};
|
|
2279
|
+
parent.modifiers = this._node;
|
|
2280
|
+
}
|
|
2281
|
+
onModifiersLeave(start, end) {
|
|
2282
|
+
const node = this._node;
|
|
2283
|
+
if (node.type !== "Modifiers" || node.parent.type !== "Group") {
|
|
2284
|
+
throw new Error("UnknownError");
|
|
2285
|
+
}
|
|
2286
|
+
node.end = end;
|
|
2287
|
+
node.raw = this.source.slice(start, end);
|
|
2288
|
+
this._node = node.parent;
|
|
2289
|
+
}
|
|
2290
|
+
onAddModifiers(start, end, { ignoreCase, multiline, dotAll, }) {
|
|
2291
|
+
const parent = this._node;
|
|
2292
|
+
if (parent.type !== "Modifiers") {
|
|
2293
|
+
throw new Error("UnknownError");
|
|
2294
|
+
}
|
|
2295
|
+
parent.add = {
|
|
2296
|
+
type: "ModifierFlags",
|
|
2297
|
+
parent,
|
|
2298
|
+
start,
|
|
2299
|
+
end,
|
|
2300
|
+
raw: this.source.slice(start, end),
|
|
2301
|
+
ignoreCase,
|
|
2302
|
+
multiline,
|
|
2303
|
+
dotAll,
|
|
2304
|
+
};
|
|
2305
|
+
}
|
|
2306
|
+
onRemoveModifiers(start, end, { ignoreCase, multiline, dotAll, }) {
|
|
2307
|
+
const parent = this._node;
|
|
2308
|
+
if (parent.type !== "Modifiers") {
|
|
2309
|
+
throw new Error("UnknownError");
|
|
2310
|
+
}
|
|
2311
|
+
parent.remove = {
|
|
2312
|
+
type: "ModifierFlags",
|
|
2313
|
+
parent,
|
|
2314
|
+
start,
|
|
2315
|
+
end,
|
|
2316
|
+
raw: this.source.slice(start, end),
|
|
2317
|
+
ignoreCase,
|
|
2318
|
+
multiline,
|
|
2319
|
+
dotAll,
|
|
2320
|
+
};
|
|
2321
|
+
}
|
|
2184
2322
|
onCapturingGroupEnter(start, name) {
|
|
2185
2323
|
const parent = this._node;
|
|
2186
2324
|
if (parent.type !== "Alternative") {
|
|
@@ -2666,6 +2804,12 @@ class RegExpVisitor {
|
|
|
2666
2804
|
case "Group":
|
|
2667
2805
|
this.visitGroup(node);
|
|
2668
2806
|
break;
|
|
2807
|
+
case "Modifiers":
|
|
2808
|
+
this.visitModifiers(node);
|
|
2809
|
+
break;
|
|
2810
|
+
case "ModifierFlags":
|
|
2811
|
+
this.visitModifierFlags(node);
|
|
2812
|
+
break;
|
|
2669
2813
|
case "Pattern":
|
|
2670
2814
|
this.visitPattern(node);
|
|
2671
2815
|
break;
|
|
@@ -2804,11 +2948,36 @@ class RegExpVisitor {
|
|
|
2804
2948
|
if (this._handlers.onGroupEnter) {
|
|
2805
2949
|
this._handlers.onGroupEnter(node);
|
|
2806
2950
|
}
|
|
2951
|
+
if (node.modifiers) {
|
|
2952
|
+
this.visit(node.modifiers);
|
|
2953
|
+
}
|
|
2807
2954
|
node.alternatives.forEach(this.visit, this);
|
|
2808
2955
|
if (this._handlers.onGroupLeave) {
|
|
2809
2956
|
this._handlers.onGroupLeave(node);
|
|
2810
2957
|
}
|
|
2811
2958
|
}
|
|
2959
|
+
visitModifiers(node) {
|
|
2960
|
+
if (this._handlers.onModifiersEnter) {
|
|
2961
|
+
this._handlers.onModifiersEnter(node);
|
|
2962
|
+
}
|
|
2963
|
+
if (node.add) {
|
|
2964
|
+
this.visit(node.add);
|
|
2965
|
+
}
|
|
2966
|
+
if (node.remove) {
|
|
2967
|
+
this.visit(node.remove);
|
|
2968
|
+
}
|
|
2969
|
+
if (this._handlers.onModifiersLeave) {
|
|
2970
|
+
this._handlers.onModifiersLeave(node);
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
visitModifierFlags(node) {
|
|
2974
|
+
if (this._handlers.onModifierFlagsEnter) {
|
|
2975
|
+
this._handlers.onModifierFlagsEnter(node);
|
|
2976
|
+
}
|
|
2977
|
+
if (this._handlers.onModifierFlagsLeave) {
|
|
2978
|
+
this._handlers.onModifierFlagsLeave(node);
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2812
2981
|
visitPattern(node) {
|
|
2813
2982
|
if (this._handlers.onPatternEnter) {
|
|
2814
2983
|
this._handlers.onPatternEnter(node);
|