@eslint-community/regexpp 4.10.1 → 4.11.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 CHANGED
@@ -430,10 +430,21 @@ declare module "@eslint-community/regexpp/ast" {
430
430
  * The backreference.
431
431
  * E.g. `\1`, `\k<name>`
432
432
  */
433
- export interface Backreference extends NodeBase {
433
+ export type Backreference = AmbiguousBackreference | UnambiguousBackreference;
434
+ interface BaseBackreference extends NodeBase {
434
435
  type: "Backreference";
435
436
  parent: Alternative | Quantifier;
436
437
  ref: number | string;
438
+ ambiguous: boolean;
439
+ resolved: CapturingGroup | CapturingGroup[];
440
+ }
441
+ export interface AmbiguousBackreference extends BaseBackreference {
442
+ ref: string;
443
+ ambiguous: true;
444
+ resolved: CapturingGroup[];
445
+ }
446
+ export interface UnambiguousBackreference extends BaseBackreference {
447
+ ambiguous: false;
437
448
  resolved: CapturingGroup;
438
449
  }
439
450
  /**
@@ -471,7 +482,7 @@ declare module "@eslint-community/regexpp/parser" {
471
482
  */
472
483
  strict?: boolean;
473
484
  /**
474
- * ECMAScript version. Default is `2024`.
485
+ * ECMAScript version. Default is `2025`.
475
486
  * - `2015` added `u` and `y` flags.
476
487
  * - `2018` added `s` flag, Named Capturing Group, Lookbehind Assertion,
477
488
  * and Unicode Property Escape.
@@ -479,6 +490,7 @@ declare module "@eslint-community/regexpp/parser" {
479
490
  * - `2022` added `d` flag.
480
491
  * - `2023` added more valid Unicode Property Escapes.
481
492
  * - `2024` added `v` flag.
493
+ * - `2025` added duplicate named capturing groups.
482
494
  */
483
495
  ecmaVersion?: EcmaVersion;
484
496
  }
@@ -559,7 +571,7 @@ declare module "@eslint-community/regexpp/validator" {
559
571
  */
560
572
  strict?: boolean;
561
573
  /**
562
- * ECMAScript version. Default is `2024`.
574
+ * ECMAScript version. Default is `2025`.
563
575
  * - `2015` added `u` and `y` flags.
564
576
  * - `2018` added `s` flag, Named Capturing Group, Lookbehind Assertion,
565
577
  * and Unicode Property Escape.
@@ -567,6 +579,7 @@ declare module "@eslint-community/regexpp/validator" {
567
579
  * - `2022` added `d` flag.
568
580
  * - `2023` added more valid Unicode Property Escapes.
569
581
  * - `2024` added `v` flag.
582
+ * - `2025` added duplicate named capturing groups.
570
583
  */
571
584
  ecmaVersion?: EcmaVersion;
572
585
  /**
@@ -1060,6 +1073,7 @@ declare module "@eslint-community/regexpp/ecma-versions" {
1060
1073
  | 2021
1061
1074
  | 2022
1062
1075
  | 2023
1063
- | 2024;
1064
- export const latestEcmaVersion = 2024;
1076
+ | 2024
1077
+ | 2025;
1078
+ export const latestEcmaVersion = 2025;
1065
1079
  }
package/index.js CHANGED
@@ -6,7 +6,7 @@ var ast = /*#__PURE__*/Object.freeze({
6
6
  __proto__: null
7
7
  });
8
8
 
9
- const latestEcmaVersion = 2024;
9
+ const latestEcmaVersion = 2025;
10
10
 
11
11
  let largeIdStartRanges = undefined;
12
12
  let largeIdContinueRanges = undefined;
@@ -264,6 +264,103 @@ function combineSurrogatePair(lead, trail) {
264
264
  return (lead - 0xd800) * 0x400 + (trail - 0xdc00) + 0x10000;
265
265
  }
266
266
 
267
+ class GroupSpecifiersAsES2018 {
268
+ constructor() {
269
+ this.groupName = new Set();
270
+ }
271
+ clear() {
272
+ this.groupName.clear();
273
+ }
274
+ isEmpty() {
275
+ return !this.groupName.size;
276
+ }
277
+ hasInPattern(name) {
278
+ return this.groupName.has(name);
279
+ }
280
+ hasInScope(name) {
281
+ return this.hasInPattern(name);
282
+ }
283
+ addToScope(name) {
284
+ this.groupName.add(name);
285
+ }
286
+ enterDisjunction() {
287
+ }
288
+ enterAlternative() {
289
+ }
290
+ leaveDisjunction() {
291
+ }
292
+ }
293
+ class BranchID {
294
+ constructor(parent, base) {
295
+ this.parent = parent;
296
+ this.base = base !== null && base !== void 0 ? base : this;
297
+ }
298
+ separatedFrom(other) {
299
+ var _a, _b;
300
+ if (this.base === other.base && this !== other) {
301
+ return true;
302
+ }
303
+ if (other.parent && this.separatedFrom(other.parent)) {
304
+ return true;
305
+ }
306
+ return (_b = (_a = this.parent) === null || _a === void 0 ? void 0 : _a.separatedFrom(other)) !== null && _b !== void 0 ? _b : false;
307
+ }
308
+ child() {
309
+ return new BranchID(this, null);
310
+ }
311
+ sibling() {
312
+ return new BranchID(this.parent, this.base);
313
+ }
314
+ }
315
+ class GroupSpecifiersAsES2025 {
316
+ constructor() {
317
+ this.branchID = new BranchID(null, null);
318
+ this.groupNames = new Map();
319
+ }
320
+ clear() {
321
+ this.branchID = new BranchID(null, null);
322
+ this.groupNames.clear();
323
+ }
324
+ isEmpty() {
325
+ return !this.groupNames.size;
326
+ }
327
+ enterDisjunction() {
328
+ this.branchID = this.branchID.child();
329
+ }
330
+ enterAlternative(index) {
331
+ if (index === 0) {
332
+ return;
333
+ }
334
+ this.branchID = this.branchID.sibling();
335
+ }
336
+ leaveDisjunction() {
337
+ this.branchID = this.branchID.parent;
338
+ }
339
+ hasInPattern(name) {
340
+ return this.groupNames.has(name);
341
+ }
342
+ hasInScope(name) {
343
+ const branches = this.groupNames.get(name);
344
+ if (!branches) {
345
+ return false;
346
+ }
347
+ for (const branch of branches) {
348
+ if (!branch.separatedFrom(this.branchID)) {
349
+ return true;
350
+ }
351
+ }
352
+ return false;
353
+ }
354
+ addToScope(name) {
355
+ const branches = this.groupNames.get(name);
356
+ if (branches) {
357
+ branches.push(this.branchID);
358
+ return;
359
+ }
360
+ this.groupNames.set(name, [this.branchID]);
361
+ }
362
+ }
363
+
267
364
  const legacyImpl = {
268
365
  at(s, end, i) {
269
366
  return i < end ? s.charCodeAt(i) : -1;
@@ -496,10 +593,13 @@ class RegExpValidator {
496
593
  this._lastStrValue = "";
497
594
  this._lastAssertionIsQuantifiable = false;
498
595
  this._numCapturingParens = 0;
499
- this._groupNames = new Set();
500
596
  this._backreferenceNames = new Set();
501
597
  this._srcCtx = null;
502
598
  this._options = options !== null && options !== void 0 ? options : {};
599
+ this._groupSpecifiers =
600
+ this.ecmaVersion >= 2025
601
+ ? new GroupSpecifiersAsES2025()
602
+ : new GroupSpecifiersAsES2018();
503
603
  }
504
604
  validateLiteral(source, start = 0, end = source.length) {
505
605
  this._srcCtx = { source, start, end, kind: "literal" };
@@ -542,7 +642,7 @@ class RegExpValidator {
542
642
  this.consumePattern();
543
643
  if (!this._nFlag &&
544
644
  this.ecmaVersion >= 2018 &&
545
- this._groupNames.size > 0) {
645
+ !this._groupSpecifiers.isEmpty()) {
546
646
  this._nFlag = true;
547
647
  this.rewind(start);
548
648
  this.consumePattern();
@@ -879,7 +979,7 @@ class RegExpValidator {
879
979
  consumePattern() {
880
980
  const start = this.index;
881
981
  this._numCapturingParens = this.countCapturingParens();
882
- this._groupNames.clear();
982
+ this._groupSpecifiers.clear();
883
983
  this._backreferenceNames.clear();
884
984
  this.onPatternEnter(start);
885
985
  this.consumeDisjunction();
@@ -898,7 +998,7 @@ class RegExpValidator {
898
998
  this.raise(`Unexpected character '${c}'`);
899
999
  }
900
1000
  for (const name of this._backreferenceNames) {
901
- if (!this._groupNames.has(name)) {
1001
+ if (!this._groupSpecifiers.hasInPattern(name)) {
902
1002
  this.raise("Invalid named capture referenced");
903
1003
  }
904
1004
  }
@@ -939,6 +1039,7 @@ class RegExpValidator {
939
1039
  consumeDisjunction() {
940
1040
  const start = this.index;
941
1041
  let i = 0;
1042
+ this._groupSpecifiers.enterDisjunction();
942
1043
  this.onDisjunctionEnter(start);
943
1044
  do {
944
1045
  this.consumeAlternative(i++);
@@ -950,9 +1051,11 @@ class RegExpValidator {
950
1051
  this.raise("Lone quantifier brackets");
951
1052
  }
952
1053
  this.onDisjunctionLeave(start, this.index);
1054
+ this._groupSpecifiers.leaveDisjunction();
953
1055
  }
954
1056
  consumeAlternative(i) {
955
1057
  const start = this.index;
1058
+ this._groupSpecifiers.enterAlternative(i);
956
1059
  this.onAlternativeEnter(start, i);
957
1060
  while (this.currentCodePoint !== -1 && this.consumeTerm()) {
958
1061
  }
@@ -1186,8 +1289,8 @@ class RegExpValidator {
1186
1289
  consumeGroupSpecifier() {
1187
1290
  if (this.eat(QUESTION_MARK)) {
1188
1291
  if (this.eatGroupName()) {
1189
- if (!this._groupNames.has(this._lastStrValue)) {
1190
- this._groupNames.add(this._lastStrValue);
1292
+ if (!this._groupSpecifiers.hasInScope(this._lastStrValue)) {
1293
+ this._groupSpecifiers.addToScope(this._lastStrValue);
1191
1294
  return true;
1192
1295
  }
1193
1296
  this.raise("Duplicate capture group name");
@@ -2010,11 +2113,21 @@ class RegExpParserState {
2010
2113
  this._node.raw = this.source.slice(start, end);
2011
2114
  for (const reference of this._backreferences) {
2012
2115
  const ref = reference.ref;
2013
- const group = typeof ref === "number"
2014
- ? this._capturingGroups[ref - 1]
2015
- : this._capturingGroups.find((g) => g.name === ref);
2016
- reference.resolved = group;
2017
- group.references.push(reference);
2116
+ const groups = typeof ref === "number"
2117
+ ? [this._capturingGroups[ref - 1]]
2118
+ : this._capturingGroups.filter((g) => g.name === ref);
2119
+ if (groups.length === 1) {
2120
+ const group = groups[0];
2121
+ reference.ambiguous = false;
2122
+ reference.resolved = group;
2123
+ }
2124
+ else {
2125
+ reference.ambiguous = true;
2126
+ reference.resolved = groups;
2127
+ }
2128
+ for (const group of groups) {
2129
+ group.references.push(reference);
2130
+ }
2018
2131
  }
2019
2132
  }
2020
2133
  onAlternativeEnter(start) {
@@ -2260,6 +2373,7 @@ class RegExpParserState {
2260
2373
  end,
2261
2374
  raw: this.source.slice(start, end),
2262
2375
  ref,
2376
+ ambiguous: false,
2263
2377
  resolved: DUMMY_CAPTURING_GROUP,
2264
2378
  };
2265
2379
  parent.elements.push(node);