@eslint-community/regexpp 4.11.2 → 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.mjs
CHANGED
|
@@ -548,6 +548,17 @@ const CLASS_SET_RESERVED_PUNCTUATOR = new Set([
|
|
|
548
548
|
GRAVE_ACCENT,
|
|
549
549
|
TILDE,
|
|
550
550
|
]);
|
|
551
|
+
const FLAG_PROP_TO_CODEPOINT = {
|
|
552
|
+
global: LATIN_SMALL_LETTER_G,
|
|
553
|
+
ignoreCase: LATIN_SMALL_LETTER_I,
|
|
554
|
+
multiline: LATIN_SMALL_LETTER_M,
|
|
555
|
+
unicode: LATIN_SMALL_LETTER_U,
|
|
556
|
+
sticky: LATIN_SMALL_LETTER_Y,
|
|
557
|
+
dotAll: LATIN_SMALL_LETTER_S,
|
|
558
|
+
hasIndices: LATIN_SMALL_LETTER_D,
|
|
559
|
+
unicodeSets: LATIN_SMALL_LETTER_V,
|
|
560
|
+
};
|
|
561
|
+
const FLAG_CODEPOINT_TO_PROP = Object.fromEntries(Object.entries(FLAG_PROP_TO_CODEPOINT).map(([k, v]) => [v, k]));
|
|
551
562
|
function isSyntaxCharacter(cp) {
|
|
552
563
|
return SYNTAX_CHARACTER.has(cp);
|
|
553
564
|
}
|
|
@@ -575,6 +586,11 @@ function isUnicodePropertyNameCharacter(cp) {
|
|
|
575
586
|
function isUnicodePropertyValueCharacter(cp) {
|
|
576
587
|
return isUnicodePropertyNameCharacter(cp) || isDecimalDigit(cp);
|
|
577
588
|
}
|
|
589
|
+
function isRegularExpressionModifier(ch) {
|
|
590
|
+
return (ch === LATIN_SMALL_LETTER_I ||
|
|
591
|
+
ch === LATIN_SMALL_LETTER_M ||
|
|
592
|
+
ch === LATIN_SMALL_LETTER_S);
|
|
593
|
+
}
|
|
578
594
|
class RegExpValidator {
|
|
579
595
|
constructor(options) {
|
|
580
596
|
this._reader = new Reader();
|
|
@@ -645,64 +661,8 @@ class RegExpValidator {
|
|
|
645
661
|
}
|
|
646
662
|
}
|
|
647
663
|
validateFlagsInternal(source, start, end) {
|
|
648
|
-
const
|
|
649
|
-
|
|
650
|
-
let ignoreCase = false;
|
|
651
|
-
let multiline = false;
|
|
652
|
-
let sticky = false;
|
|
653
|
-
let unicode = false;
|
|
654
|
-
let dotAll = false;
|
|
655
|
-
let hasIndices = false;
|
|
656
|
-
let unicodeSets = false;
|
|
657
|
-
for (let i = start; i < end; ++i) {
|
|
658
|
-
const flag = source.charCodeAt(i);
|
|
659
|
-
if (existingFlags.has(flag)) {
|
|
660
|
-
this.raise(`Duplicated flag '${source[i]}'`, { index: start });
|
|
661
|
-
}
|
|
662
|
-
existingFlags.add(flag);
|
|
663
|
-
if (flag === LATIN_SMALL_LETTER_G) {
|
|
664
|
-
global = true;
|
|
665
|
-
}
|
|
666
|
-
else if (flag === LATIN_SMALL_LETTER_I) {
|
|
667
|
-
ignoreCase = true;
|
|
668
|
-
}
|
|
669
|
-
else if (flag === LATIN_SMALL_LETTER_M) {
|
|
670
|
-
multiline = true;
|
|
671
|
-
}
|
|
672
|
-
else if (flag === LATIN_SMALL_LETTER_U &&
|
|
673
|
-
this.ecmaVersion >= 2015) {
|
|
674
|
-
unicode = true;
|
|
675
|
-
}
|
|
676
|
-
else if (flag === LATIN_SMALL_LETTER_Y &&
|
|
677
|
-
this.ecmaVersion >= 2015) {
|
|
678
|
-
sticky = true;
|
|
679
|
-
}
|
|
680
|
-
else if (flag === LATIN_SMALL_LETTER_S &&
|
|
681
|
-
this.ecmaVersion >= 2018) {
|
|
682
|
-
dotAll = true;
|
|
683
|
-
}
|
|
684
|
-
else if (flag === LATIN_SMALL_LETTER_D &&
|
|
685
|
-
this.ecmaVersion >= 2022) {
|
|
686
|
-
hasIndices = true;
|
|
687
|
-
}
|
|
688
|
-
else if (flag === LATIN_SMALL_LETTER_V &&
|
|
689
|
-
this.ecmaVersion >= 2024) {
|
|
690
|
-
unicodeSets = true;
|
|
691
|
-
}
|
|
692
|
-
else {
|
|
693
|
-
this.raise(`Invalid flag '${source[i]}'`, { index: start });
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
this.onRegExpFlags(start, end, {
|
|
697
|
-
global,
|
|
698
|
-
ignoreCase,
|
|
699
|
-
multiline,
|
|
700
|
-
unicode,
|
|
701
|
-
sticky,
|
|
702
|
-
dotAll,
|
|
703
|
-
hasIndices,
|
|
704
|
-
unicodeSets,
|
|
705
|
-
});
|
|
664
|
+
const flags = this.parseFlags(source, start, end);
|
|
665
|
+
this.onRegExpFlags(start, end, flags);
|
|
706
666
|
}
|
|
707
667
|
_parseFlagsOptionToMode(uFlagOrFlags, sourceEnd) {
|
|
708
668
|
let unicode = false;
|
|
@@ -797,6 +757,26 @@ class RegExpValidator {
|
|
|
797
757
|
this._options.onGroupLeave(start, end);
|
|
798
758
|
}
|
|
799
759
|
}
|
|
760
|
+
onModifiersEnter(start) {
|
|
761
|
+
if (this._options.onModifiersEnter) {
|
|
762
|
+
this._options.onModifiersEnter(start);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
onModifiersLeave(start, end) {
|
|
766
|
+
if (this._options.onModifiersLeave) {
|
|
767
|
+
this._options.onModifiersLeave(start, end);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
onAddModifiers(start, end, flags) {
|
|
771
|
+
if (this._options.onAddModifiers) {
|
|
772
|
+
this._options.onAddModifiers(start, end, flags);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
onRemoveModifiers(start, end, flags) {
|
|
776
|
+
if (this._options.onRemoveModifiers) {
|
|
777
|
+
this._options.onRemoveModifiers(start, end, flags);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
800
780
|
onCapturingGroupEnter(start, name) {
|
|
801
781
|
if (this._options.onCapturingGroupEnter) {
|
|
802
782
|
this._options.onCapturingGroupEnter(start, name);
|
|
@@ -1169,8 +1149,8 @@ class RegExpValidator {
|
|
|
1169
1149
|
this.consumeDot() ||
|
|
1170
1150
|
this.consumeReverseSolidusAtomEscape() ||
|
|
1171
1151
|
Boolean(this.consumeCharacterClass()) ||
|
|
1172
|
-
this.
|
|
1173
|
-
this.
|
|
1152
|
+
this.consumeCapturingGroup() ||
|
|
1153
|
+
this.consumeUncapturingGroup());
|
|
1174
1154
|
}
|
|
1175
1155
|
consumeDot() {
|
|
1176
1156
|
if (this.eat(FULL_STOP)) {
|
|
@@ -1191,8 +1171,15 @@ class RegExpValidator {
|
|
|
1191
1171
|
}
|
|
1192
1172
|
consumeUncapturingGroup() {
|
|
1193
1173
|
const start = this.index;
|
|
1194
|
-
if (this.
|
|
1174
|
+
if (this.eat2(LEFT_PARENTHESIS, QUESTION_MARK)) {
|
|
1195
1175
|
this.onGroupEnter(start);
|
|
1176
|
+
if (this.ecmaVersion >= 2025) {
|
|
1177
|
+
this.consumeModifiers();
|
|
1178
|
+
}
|
|
1179
|
+
if (!this.eat(COLON)) {
|
|
1180
|
+
this.rewind(start + 1);
|
|
1181
|
+
this.raise("Invalid group");
|
|
1182
|
+
}
|
|
1196
1183
|
this.consumeDisjunction();
|
|
1197
1184
|
if (!this.eat(RIGHT_PARENTHESIS)) {
|
|
1198
1185
|
this.raise("Unterminated group");
|
|
@@ -1202,6 +1189,35 @@ class RegExpValidator {
|
|
|
1202
1189
|
}
|
|
1203
1190
|
return false;
|
|
1204
1191
|
}
|
|
1192
|
+
consumeModifiers() {
|
|
1193
|
+
const start = this.index;
|
|
1194
|
+
const hasAddModifiers = this.eatModifiers();
|
|
1195
|
+
const addModifiersEnd = this.index;
|
|
1196
|
+
const hasHyphen = this.eat(HYPHEN_MINUS);
|
|
1197
|
+
if (!hasAddModifiers && !hasHyphen) {
|
|
1198
|
+
return false;
|
|
1199
|
+
}
|
|
1200
|
+
this.onModifiersEnter(start);
|
|
1201
|
+
const addModifiers = this.parseModifiers(start, addModifiersEnd);
|
|
1202
|
+
this.onAddModifiers(start, addModifiersEnd, addModifiers);
|
|
1203
|
+
if (hasHyphen) {
|
|
1204
|
+
const modifiersStart = this.index;
|
|
1205
|
+
if (!this.eatModifiers() &&
|
|
1206
|
+
!hasAddModifiers &&
|
|
1207
|
+
this.currentCodePoint === COLON) {
|
|
1208
|
+
this.raise("Invalid empty flags");
|
|
1209
|
+
}
|
|
1210
|
+
const modifiers = this.parseModifiers(modifiersStart, this.index);
|
|
1211
|
+
for (const [flagName] of Object.entries(modifiers).filter(([, enable]) => enable)) {
|
|
1212
|
+
if (addModifiers[flagName]) {
|
|
1213
|
+
this.raise(`Duplicated flag '${String.fromCodePoint(FLAG_PROP_TO_CODEPOINT[flagName])}'`);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
this.onRemoveModifiers(modifiersStart, this.index, modifiers);
|
|
1217
|
+
}
|
|
1218
|
+
this.onModifiersLeave(start, this.index);
|
|
1219
|
+
return true;
|
|
1220
|
+
}
|
|
1205
1221
|
consumeCapturingGroup() {
|
|
1206
1222
|
const start = this.index;
|
|
1207
1223
|
if (this.eat(LEFT_PARENTHESIS)) {
|
|
@@ -1210,9 +1226,14 @@ class RegExpValidator {
|
|
|
1210
1226
|
if (this.consumeGroupSpecifier()) {
|
|
1211
1227
|
name = this._lastStrValue;
|
|
1212
1228
|
}
|
|
1229
|
+
else if (this.currentCodePoint === QUESTION_MARK) {
|
|
1230
|
+
this.rewind(start);
|
|
1231
|
+
return false;
|
|
1232
|
+
}
|
|
1213
1233
|
}
|
|
1214
1234
|
else if (this.currentCodePoint === QUESTION_MARK) {
|
|
1215
|
-
this.
|
|
1235
|
+
this.rewind(start);
|
|
1236
|
+
return false;
|
|
1216
1237
|
}
|
|
1217
1238
|
this.onCapturingGroupEnter(start, name);
|
|
1218
1239
|
this.consumeDisjunction();
|
|
@@ -1229,8 +1250,8 @@ class RegExpValidator {
|
|
|
1229
1250
|
this.consumeReverseSolidusAtomEscape() ||
|
|
1230
1251
|
this.consumeReverseSolidusFollowedByC() ||
|
|
1231
1252
|
Boolean(this.consumeCharacterClass()) ||
|
|
1232
|
-
this.consumeUncapturingGroup() ||
|
|
1233
1253
|
this.consumeCapturingGroup() ||
|
|
1254
|
+
this.consumeUncapturingGroup() ||
|
|
1234
1255
|
this.consumeInvalidBracedQuantifier() ||
|
|
1235
1256
|
this.consumeExtendedPatternCharacter());
|
|
1236
1257
|
}
|
|
@@ -1283,6 +1304,7 @@ class RegExpValidator {
|
|
|
1283
1304
|
return false;
|
|
1284
1305
|
}
|
|
1285
1306
|
consumeGroupSpecifier() {
|
|
1307
|
+
const start = this.index;
|
|
1286
1308
|
if (this.eat(QUESTION_MARK)) {
|
|
1287
1309
|
if (this.eatGroupName()) {
|
|
1288
1310
|
if (!this._groupSpecifiers.hasInScope(this._lastStrValue)) {
|
|
@@ -1291,7 +1313,7 @@ class RegExpValidator {
|
|
|
1291
1313
|
}
|
|
1292
1314
|
this.raise("Duplicate capture group name");
|
|
1293
1315
|
}
|
|
1294
|
-
this.
|
|
1316
|
+
this.rewind(start);
|
|
1295
1317
|
}
|
|
1296
1318
|
return false;
|
|
1297
1319
|
}
|
|
@@ -2039,6 +2061,63 @@ class RegExpValidator {
|
|
|
2039
2061
|
}
|
|
2040
2062
|
return true;
|
|
2041
2063
|
}
|
|
2064
|
+
eatModifiers() {
|
|
2065
|
+
let ate = false;
|
|
2066
|
+
while (isRegularExpressionModifier(this.currentCodePoint)) {
|
|
2067
|
+
this.advance();
|
|
2068
|
+
ate = true;
|
|
2069
|
+
}
|
|
2070
|
+
return ate;
|
|
2071
|
+
}
|
|
2072
|
+
parseModifiers(start, end) {
|
|
2073
|
+
const { ignoreCase, multiline, dotAll } = this.parseFlags(this._reader.source, start, end);
|
|
2074
|
+
return { ignoreCase, multiline, dotAll };
|
|
2075
|
+
}
|
|
2076
|
+
parseFlags(source, start, end) {
|
|
2077
|
+
const flags = {
|
|
2078
|
+
global: false,
|
|
2079
|
+
ignoreCase: false,
|
|
2080
|
+
multiline: false,
|
|
2081
|
+
unicode: false,
|
|
2082
|
+
sticky: false,
|
|
2083
|
+
dotAll: false,
|
|
2084
|
+
hasIndices: false,
|
|
2085
|
+
unicodeSets: false,
|
|
2086
|
+
};
|
|
2087
|
+
const validFlags = new Set();
|
|
2088
|
+
validFlags.add(LATIN_SMALL_LETTER_G);
|
|
2089
|
+
validFlags.add(LATIN_SMALL_LETTER_I);
|
|
2090
|
+
validFlags.add(LATIN_SMALL_LETTER_M);
|
|
2091
|
+
if (this.ecmaVersion >= 2015) {
|
|
2092
|
+
validFlags.add(LATIN_SMALL_LETTER_U);
|
|
2093
|
+
validFlags.add(LATIN_SMALL_LETTER_Y);
|
|
2094
|
+
if (this.ecmaVersion >= 2018) {
|
|
2095
|
+
validFlags.add(LATIN_SMALL_LETTER_S);
|
|
2096
|
+
if (this.ecmaVersion >= 2021) {
|
|
2097
|
+
validFlags.add(LATIN_SMALL_LETTER_D);
|
|
2098
|
+
if (this.ecmaVersion >= 2024) {
|
|
2099
|
+
validFlags.add(LATIN_SMALL_LETTER_V);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
for (let i = start; i < end; ++i) {
|
|
2105
|
+
const flag = source.charCodeAt(i);
|
|
2106
|
+
if (validFlags.has(flag)) {
|
|
2107
|
+
const prop = FLAG_CODEPOINT_TO_PROP[flag];
|
|
2108
|
+
if (flags[prop]) {
|
|
2109
|
+
this.raise(`Duplicated flag '${source[i]}'`, {
|
|
2110
|
+
index: start,
|
|
2111
|
+
});
|
|
2112
|
+
}
|
|
2113
|
+
flags[prop] = true;
|
|
2114
|
+
}
|
|
2115
|
+
else {
|
|
2116
|
+
this.raise(`Invalid flag '${source[i]}'`, { index: start });
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
return flags;
|
|
2120
|
+
}
|
|
2042
2121
|
}
|
|
2043
2122
|
|
|
2044
2123
|
const DUMMY_PATTERN = {};
|
|
@@ -2158,14 +2237,16 @@ class RegExpParserState {
|
|
|
2158
2237
|
if (parent.type !== "Alternative") {
|
|
2159
2238
|
throw new Error("UnknownError");
|
|
2160
2239
|
}
|
|
2161
|
-
|
|
2240
|
+
const group = {
|
|
2162
2241
|
type: "Group",
|
|
2163
2242
|
parent,
|
|
2164
2243
|
start,
|
|
2165
2244
|
end: start,
|
|
2166
2245
|
raw: "",
|
|
2246
|
+
modifiers: null,
|
|
2167
2247
|
alternatives: [],
|
|
2168
2248
|
};
|
|
2249
|
+
this._node = group;
|
|
2169
2250
|
parent.elements.push(this._node);
|
|
2170
2251
|
}
|
|
2171
2252
|
onGroupLeave(start, end) {
|
|
@@ -2177,6 +2258,63 @@ class RegExpParserState {
|
|
|
2177
2258
|
node.raw = this.source.slice(start, end);
|
|
2178
2259
|
this._node = node.parent;
|
|
2179
2260
|
}
|
|
2261
|
+
onModifiersEnter(start) {
|
|
2262
|
+
const parent = this._node;
|
|
2263
|
+
if (parent.type !== "Group") {
|
|
2264
|
+
throw new Error("UnknownError");
|
|
2265
|
+
}
|
|
2266
|
+
this._node = {
|
|
2267
|
+
type: "Modifiers",
|
|
2268
|
+
parent,
|
|
2269
|
+
start,
|
|
2270
|
+
end: start,
|
|
2271
|
+
raw: "",
|
|
2272
|
+
add: null,
|
|
2273
|
+
remove: null,
|
|
2274
|
+
};
|
|
2275
|
+
parent.modifiers = this._node;
|
|
2276
|
+
}
|
|
2277
|
+
onModifiersLeave(start, end) {
|
|
2278
|
+
const node = this._node;
|
|
2279
|
+
if (node.type !== "Modifiers" || node.parent.type !== "Group") {
|
|
2280
|
+
throw new Error("UnknownError");
|
|
2281
|
+
}
|
|
2282
|
+
node.end = end;
|
|
2283
|
+
node.raw = this.source.slice(start, end);
|
|
2284
|
+
this._node = node.parent;
|
|
2285
|
+
}
|
|
2286
|
+
onAddModifiers(start, end, { ignoreCase, multiline, dotAll, }) {
|
|
2287
|
+
const parent = this._node;
|
|
2288
|
+
if (parent.type !== "Modifiers") {
|
|
2289
|
+
throw new Error("UnknownError");
|
|
2290
|
+
}
|
|
2291
|
+
parent.add = {
|
|
2292
|
+
type: "ModifierFlags",
|
|
2293
|
+
parent,
|
|
2294
|
+
start,
|
|
2295
|
+
end,
|
|
2296
|
+
raw: this.source.slice(start, end),
|
|
2297
|
+
ignoreCase,
|
|
2298
|
+
multiline,
|
|
2299
|
+
dotAll,
|
|
2300
|
+
};
|
|
2301
|
+
}
|
|
2302
|
+
onRemoveModifiers(start, end, { ignoreCase, multiline, dotAll, }) {
|
|
2303
|
+
const parent = this._node;
|
|
2304
|
+
if (parent.type !== "Modifiers") {
|
|
2305
|
+
throw new Error("UnknownError");
|
|
2306
|
+
}
|
|
2307
|
+
parent.remove = {
|
|
2308
|
+
type: "ModifierFlags",
|
|
2309
|
+
parent,
|
|
2310
|
+
start,
|
|
2311
|
+
end,
|
|
2312
|
+
raw: this.source.slice(start, end),
|
|
2313
|
+
ignoreCase,
|
|
2314
|
+
multiline,
|
|
2315
|
+
dotAll,
|
|
2316
|
+
};
|
|
2317
|
+
}
|
|
2180
2318
|
onCapturingGroupEnter(start, name) {
|
|
2181
2319
|
const parent = this._node;
|
|
2182
2320
|
if (parent.type !== "Alternative") {
|
|
@@ -2662,6 +2800,12 @@ class RegExpVisitor {
|
|
|
2662
2800
|
case "Group":
|
|
2663
2801
|
this.visitGroup(node);
|
|
2664
2802
|
break;
|
|
2803
|
+
case "Modifiers":
|
|
2804
|
+
this.visitModifiers(node);
|
|
2805
|
+
break;
|
|
2806
|
+
case "ModifierFlags":
|
|
2807
|
+
this.visitModifierFlags(node);
|
|
2808
|
+
break;
|
|
2665
2809
|
case "Pattern":
|
|
2666
2810
|
this.visitPattern(node);
|
|
2667
2811
|
break;
|
|
@@ -2800,11 +2944,36 @@ class RegExpVisitor {
|
|
|
2800
2944
|
if (this._handlers.onGroupEnter) {
|
|
2801
2945
|
this._handlers.onGroupEnter(node);
|
|
2802
2946
|
}
|
|
2947
|
+
if (node.modifiers) {
|
|
2948
|
+
this.visit(node.modifiers);
|
|
2949
|
+
}
|
|
2803
2950
|
node.alternatives.forEach(this.visit, this);
|
|
2804
2951
|
if (this._handlers.onGroupLeave) {
|
|
2805
2952
|
this._handlers.onGroupLeave(node);
|
|
2806
2953
|
}
|
|
2807
2954
|
}
|
|
2955
|
+
visitModifiers(node) {
|
|
2956
|
+
if (this._handlers.onModifiersEnter) {
|
|
2957
|
+
this._handlers.onModifiersEnter(node);
|
|
2958
|
+
}
|
|
2959
|
+
if (node.add) {
|
|
2960
|
+
this.visit(node.add);
|
|
2961
|
+
}
|
|
2962
|
+
if (node.remove) {
|
|
2963
|
+
this.visit(node.remove);
|
|
2964
|
+
}
|
|
2965
|
+
if (this._handlers.onModifiersLeave) {
|
|
2966
|
+
this._handlers.onModifiersLeave(node);
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
visitModifierFlags(node) {
|
|
2970
|
+
if (this._handlers.onModifierFlagsEnter) {
|
|
2971
|
+
this._handlers.onModifierFlagsEnter(node);
|
|
2972
|
+
}
|
|
2973
|
+
if (this._handlers.onModifierFlagsLeave) {
|
|
2974
|
+
this._handlers.onModifierFlagsLeave(node);
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2808
2977
|
visitPattern(node) {
|
|
2809
2978
|
if (this._handlers.onPatternEnter) {
|
|
2810
2979
|
this._handlers.onPatternEnter(node);
|