@eslint-community/regexpp 4.6.1 → 4.7.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
@@ -88,8 +88,8 @@ declare module "@eslint-community/regexpp/ast" {
88
88
  export type ClassRangesCharacterClassElement =
89
89
  | Character
90
90
  | CharacterClassRange
91
- | EscapeCharacterSet
92
- | UnicodePropertyCharacterSet;
91
+ | CharacterUnicodePropertyCharacterSet
92
+ | EscapeCharacterSet;
93
93
  export type UnicodeSetsCharacterClassElement =
94
94
  | Character
95
95
  | CharacterClassRange
@@ -215,12 +215,23 @@ declare module "@eslint-community/regexpp/ast" {
215
215
  negate: boolean;
216
216
  elements: CharacterClassElement[];
217
217
  }
218
+ /**
219
+ * The character class used in legacy (neither `u` nor `v` flag) and Unicode mode (`u` flag).
220
+ *
221
+ * This character class is guaranteed to **not** contain strings.
222
+ *
223
+ * In Unicode sets mode (`v` flag), {@link UnicodeSetsCharacterClass} is used.
224
+ */
218
225
  export interface ClassRangesCharacterClass extends BaseCharacterClass {
219
226
  parent: Alternative | Quantifier;
220
227
  unicodeSets: false;
221
228
  elements: ClassRangesCharacterClassElement[];
222
229
  }
223
- /** UnicodeSetsCharacterClass is the CharacterClass when in Unicode sets mode. So it may contain strings. */
230
+ /**
231
+ * The character class used in Unicode sets mode (`v` flag).
232
+ *
233
+ * This character class may contain strings.
234
+ */
224
235
  export interface UnicodeSetsCharacterClass extends BaseCharacterClass {
225
236
  parent:
226
237
  | Alternative
@@ -522,6 +533,12 @@ declare module "@eslint-community/regexpp/parser" {
522
533
 
523
534
  declare module "@eslint-community/regexpp/validator" {
524
535
  import type { EcmaVersion } from "@eslint-community/regexpp/ecma-versions";
536
+ export type RegExpValidatorSourceContext = {
537
+ readonly source: string;
538
+ readonly start: number;
539
+ readonly end: number;
540
+ readonly kind: "flags" | "literal" | "pattern";
541
+ };
525
542
  export namespace RegExpValidator {
526
543
  /**
527
544
  * The options for RegExpValidator construction.
package/index.js CHANGED
@@ -360,12 +360,18 @@ class Reader {
360
360
  }
361
361
 
362
362
  class RegExpSyntaxError extends SyntaxError {
363
- constructor(source, flags, index, message) {
364
- if (source) {
365
- if (!source.startsWith("/")) {
366
- source = `/${source}/${flags.unicode ? "u" : ""}${flags.unicodeSets ? "v" : ""}`;
363
+ constructor(srcCtx, flags, index, message) {
364
+ let source = "";
365
+ if (srcCtx.kind === "literal") {
366
+ const literal = srcCtx.source.slice(srcCtx.start, srcCtx.end);
367
+ if (literal) {
368
+ source = `: ${literal}`;
367
369
  }
368
- source = `: ${source}`;
370
+ }
371
+ else if (srcCtx.kind === "pattern") {
372
+ const pattern = srcCtx.source.slice(srcCtx.start, srcCtx.end);
373
+ const flagsText = `${flags.unicode ? "u" : ""}${flags.unicodeSets ? "v" : ""}`;
374
+ source = `: /${pattern}/${flagsText}`;
369
375
  }
370
376
  super(`Invalid regular expression${source}: ${message}`);
371
377
  this.index = index;
@@ -493,9 +499,11 @@ class RegExpValidator {
493
499
  this._numCapturingParens = 0;
494
500
  this._groupNames = new Set();
495
501
  this._backreferenceNames = new Set();
502
+ this._srcCtx = null;
496
503
  this._options = options !== null && options !== void 0 ? options : {};
497
504
  }
498
505
  validateLiteral(source, start = 0, end = source.length) {
506
+ this._srcCtx = { source, start, end, kind: "literal" };
499
507
  this._unicodeSetsMode = this._unicodeMode = this._nFlag = false;
500
508
  this.reset(source, start, end);
501
509
  this.onLiteralEnter(start);
@@ -503,8 +511,8 @@ class RegExpValidator {
503
511
  const flagStart = this.index;
504
512
  const unicode = source.includes("u", flagStart);
505
513
  const unicodeSets = source.includes("v", flagStart);
506
- this.validateFlags(source, flagStart, end);
507
- this.validatePattern(source, start + 1, flagStart - 1, {
514
+ this.validateFlagsInternal(source, flagStart, end);
515
+ this.validatePatternInternal(source, start + 1, flagStart - 1, {
508
516
  unicode,
509
517
  unicodeSets,
510
518
  });
@@ -519,6 +527,29 @@ class RegExpValidator {
519
527
  this.onLiteralLeave(start, end);
520
528
  }
521
529
  validateFlags(source, start = 0, end = source.length) {
530
+ this._srcCtx = { source, start, end, kind: "flags" };
531
+ this.validateFlagsInternal(source, start, end);
532
+ }
533
+ validatePattern(source, start = 0, end = source.length, uFlagOrFlags = undefined) {
534
+ this._srcCtx = { source, start, end, kind: "pattern" };
535
+ this.validatePatternInternal(source, start, end, uFlagOrFlags);
536
+ }
537
+ validatePatternInternal(source, start = 0, end = source.length, uFlagOrFlags = undefined) {
538
+ const mode = this._parseFlagsOptionToMode(uFlagOrFlags, end);
539
+ this._unicodeMode = mode.unicodeMode;
540
+ this._nFlag = mode.nFlag;
541
+ this._unicodeSetsMode = mode.unicodeSetsMode;
542
+ this.reset(source, start, end);
543
+ this.consumePattern();
544
+ if (!this._nFlag &&
545
+ this.ecmaVersion >= 2018 &&
546
+ this._groupNames.size > 0) {
547
+ this._nFlag = true;
548
+ this.rewind(start);
549
+ this.consumePattern();
550
+ }
551
+ }
552
+ validateFlagsInternal(source, start, end) {
522
553
  const existingFlags = new Set();
523
554
  let global = false;
524
555
  let ignoreCase = false;
@@ -531,7 +562,7 @@ class RegExpValidator {
531
562
  for (let i = start; i < end; ++i) {
532
563
  const flag = source.charCodeAt(i);
533
564
  if (existingFlags.has(flag)) {
534
- this.raise(`Duplicated flag '${source[i]}'`);
565
+ this.raise(`Duplicated flag '${source[i]}'`, { index: start });
535
566
  }
536
567
  existingFlags.add(flag);
537
568
  if (flag === LATIN_SMALL_LETTER_G) {
@@ -564,7 +595,7 @@ class RegExpValidator {
564
595
  unicodeSets = true;
565
596
  }
566
597
  else {
567
- this.raise(`Invalid flag '${source[i]}'`);
598
+ this.raise(`Invalid flag '${source[i]}'`, { index: start });
568
599
  }
569
600
  }
570
601
  this.onRegExpFlags(start, end, {
@@ -578,22 +609,7 @@ class RegExpValidator {
578
609
  unicodeSets,
579
610
  });
580
611
  }
581
- validatePattern(source, start = 0, end = source.length, uFlagOrFlags = undefined) {
582
- const mode = this._parseFlagsOptionToMode(uFlagOrFlags, source, end);
583
- this._unicodeMode = mode.unicodeMode;
584
- this._nFlag = mode.nFlag;
585
- this._unicodeSetsMode = mode.unicodeSetsMode;
586
- this.reset(source, start, end);
587
- this.consumePattern();
588
- if (!this._nFlag &&
589
- this.ecmaVersion >= 2018 &&
590
- this._groupNames.size > 0) {
591
- this._nFlag = true;
592
- this.rewind(start);
593
- this.consumePattern();
594
- }
595
- }
596
- _parseFlagsOptionToMode(uFlagOrFlags, source, sourceEnd) {
612
+ _parseFlagsOptionToMode(uFlagOrFlags, sourceEnd) {
597
613
  let unicode = false;
598
614
  let unicodeSets = false;
599
615
  if (uFlagOrFlags && this.ecmaVersion >= 2015) {
@@ -608,7 +624,11 @@ class RegExpValidator {
608
624
  }
609
625
  }
610
626
  if (unicode && unicodeSets) {
611
- throw new RegExpSyntaxError(source, { unicode, unicodeSets }, sourceEnd + 1, "Invalid regular expression flags");
627
+ this.raise("Invalid regular expression flags", {
628
+ index: sourceEnd + 1,
629
+ unicode,
630
+ unicodeSets,
631
+ });
612
632
  }
613
633
  const unicodeMode = unicode || unicodeSets;
614
634
  const nFlag = (unicode && this.ecmaVersion >= 2018) ||
@@ -787,9 +807,6 @@ class RegExpValidator {
787
807
  this._options.onStringAlternativeLeave(start, end, index);
788
808
  }
789
809
  }
790
- get source() {
791
- return this._reader.source;
792
- }
793
810
  get index() {
794
811
  return this._reader.index;
795
812
  }
@@ -823,11 +840,12 @@ class RegExpValidator {
823
840
  eat3(cp1, cp2, cp3) {
824
841
  return this._reader.eat3(cp1, cp2, cp3);
825
842
  }
826
- raise(message) {
827
- throw new RegExpSyntaxError(this.source, {
828
- unicode: this._unicodeMode && !this._unicodeSetsMode,
829
- unicodeSets: this._unicodeSetsMode,
830
- }, this.index, message);
843
+ raise(message, context) {
844
+ var _a, _b, _c;
845
+ throw new RegExpSyntaxError(this._srcCtx, {
846
+ unicode: (_a = context === null || context === void 0 ? void 0 : context.unicode) !== null && _a !== void 0 ? _a : (this._unicodeMode && !this._unicodeSetsMode),
847
+ unicodeSets: (_b = context === null || context === void 0 ? void 0 : context.unicodeSets) !== null && _b !== void 0 ? _b : this._unicodeSetsMode,
848
+ }, (_c = context === null || context === void 0 ? void 0 : context.index) !== null && _c !== void 0 ? _c : this.index, message);
831
849
  }
832
850
  eatRegExpBody() {
833
851
  const start = this.index;
@@ -2208,7 +2226,15 @@ class RegExpParserState {
2208
2226
  const node = strings
2209
2227
  ? Object.assign(Object.assign({}, base), { value: null, negate: false, strings: true }) : Object.assign(Object.assign({}, base), { value,
2210
2228
  negate, strings: false });
2211
- parent.elements.push(node);
2229
+ if (node.strings) {
2230
+ if (parent.type === "CharacterClass" && !parent.unicodeSets) {
2231
+ throw new Error("UnknownError");
2232
+ }
2233
+ parent.elements.push(node);
2234
+ }
2235
+ else {
2236
+ parent.elements.push(node);
2237
+ }
2212
2238
  }
2213
2239
  onCharacter(start, end, value) {
2214
2240
  const parent = this._node;