1 /*! @author Toru Nagashima <https://github.com/mysticatea> */
4 var ast = /*#__PURE__*/Object.freeze({
8 function isIdStart(cp) {
17 return isLargeIdStart(cp);
19 function isIdContinue(cp) {
34 return isLargeIdStart(cp) || isLargeIdContinue(cp);
36 function isLargeIdStart(cp) {
2684 function isLargeIdContinue(cp) {
4661 const PropertyData = {
4677 "Changes_When_Casefolded",
4679 "Changes_When_Casemapped",
4681 "Changes_When_Lowercased",
4683 "Changes_When_NFKC_Casefolded",
4685 "Changes_When_Titlecased",
4687 "Changes_When_Uppercased",
4690 "Default_Ignorable_Code_Point",
4699 "Emoji_Modifier_Base",
4700 "Emoji_Presentation",
4709 "IDS_Binary_Operator",
4711 "IDS_Trinary_Operator",
4721 "Logical_Order_Exception",
4726 "Noncharacter_Code_Point",
4730 "Pattern_White_Space",
4735 "Regional_Indicator",
4737 "Sentence_Terminal",
4741 "Terminal_Punctuation",
4743 "Unified_Ideograph",
4747 "Variation_Selector",
4756 General_Category: new Set([
4759 "Close_Punctuation",
4761 "Connector_Punctuation",
4775 "Final_Punctuation",
4779 "Initial_Punctuation",
4810 "Other_Punctuation",
4814 "Paragraph_Separator",
4842 "Anatolian_Hieroglyphs",
4872 "Canadian_Aboriginal",
4876 "Caucasian_Albanian",
4900 "Egyptian_Hieroglyphs",
4937 "Inscriptional_Pahlavi",
4939 "Inscriptional_Parthian",
4994 "Meroitic_Hieroglyphs",
5024 "Old_North_Arabian",
5030 "Old_South_Arabian",
5119 PropertyData.gc = PropertyData.General_Category;
5120 PropertyData.sc = PropertyData.Script_Extensions = PropertyData.scx =
5121 PropertyData.Script;
5123 const Backspace = 0x08;
5124 const CharacterTabulation = 0x09;
5125 const LineFeed = 0x0a;
5126 const LineTabulation = 0x0b;
5127 const FormFeed = 0x0c;
5128 const CarriageReturn = 0x0d;
5129 const ExclamationMark = 0x21;
5130 const DollarSign = 0x24;
5131 const LeftParenthesis = 0x28;
5132 const RightParenthesis = 0x29;
5133 const Asterisk = 0x2a;
5134 const PlusSign = 0x2b;
5136 const HyphenMinus = 0x2d;
5137 const FullStop = 0x2e;
5138 const Solidus = 0x2f;
5139 const DigitZero = 0x30;
5140 const DigitOne = 0x31;
5141 const DigitSeven = 0x37;
5142 const DigitNine = 0x39;
5144 const LessThanSign = 0x3c;
5145 const EqualsSign = 0x3d;
5146 const GreaterThanSign = 0x3e;
5147 const QuestionMark = 0x3f;
5148 const LatinCapitalLetterA = 0x41;
5149 const LatinCapitalLetterB = 0x42;
5150 const LatinCapitalLetterD = 0x44;
5151 const LatinCapitalLetterF = 0x46;
5152 const LatinCapitalLetterP = 0x50;
5153 const LatinCapitalLetterS = 0x53;
5154 const LatinCapitalLetterW = 0x57;
5155 const LatinCapitalLetterZ = 0x5a;
5156 const LowLine = 0x5f;
5157 const LatinSmallLetterA = 0x61;
5158 const LatinSmallLetterB = 0x62;
5159 const LatinSmallLetterC = 0x63;
5160 const LatinSmallLetterD = 0x64;
5161 const LatinSmallLetterF = 0x66;
5162 const LatinSmallLetterG = 0x67;
5163 const LatinSmallLetterI = 0x69;
5164 const LatinSmallLetterK = 0x6b;
5165 const LatinSmallLetterM = 0x6d;
5166 const LatinSmallLetterN = 0x6e;
5167 const LatinSmallLetterP = 0x70;
5168 const LatinSmallLetterR = 0x72;
5169 const LatinSmallLetterS = 0x73;
5170 const LatinSmallLetterT = 0x74;
5171 const LatinSmallLetterU = 0x75;
5172 const LatinSmallLetterV = 0x76;
5173 const LatinSmallLetterW = 0x77;
5174 const LatinSmallLetterX = 0x78;
5175 const LatinSmallLetterY = 0x79;
5176 const LatinSmallLetterZ = 0x7a;
5177 const LeftSquareBracket = 0x5b;
5178 const ReverseSolidus = 0x5c;
5179 const RightSquareBracket = 0x5d;
5180 const CircumflexAccent = 0x5e;
5181 const LeftCurlyBracket = 0x7b;
5182 const VerticalLine = 0x7c;
5183 const RightCurlyBracket = 0x7d;
5184 const ZeroWidthNonJoiner = 0x200c;
5185 const ZeroWidthJoiner = 0x200d;
5186 const LineSeparator = 0x2028;
5187 const ParagraphSeparator = 0x2029;
5188 const MinCodePoint = 0x00;
5189 const MaxCodePoint = 0x10ffff;
5190 function isLatinLetter(code) {
5191 return ((code >= LatinCapitalLetterA && code <= LatinCapitalLetterZ) ||
5192 (code >= LatinSmallLetterA && code <= LatinSmallLetterZ));
5194 function isDecimalDigit(code) {
5195 return code >= DigitZero && code <= DigitNine;
5197 function isOctalDigit(code) {
5198 return code >= DigitZero && code <= DigitSeven;
5200 function isHexDigit(code) {
5201 return ((code >= DigitZero && code <= DigitNine) ||
5202 (code >= LatinCapitalLetterA && code <= LatinCapitalLetterF) ||
5203 (code >= LatinSmallLetterA && code <= LatinSmallLetterF));
5205 function isLineTerminator(code) {
5206 return (code === LineFeed ||
5207 code === CarriageReturn ||
5208 code === LineSeparator ||
5209 code === ParagraphSeparator);
5211 function isValidUnicode(code) {
5212 return code >= MinCodePoint && code <= MaxCodePoint;
5214 function digitToInt(code) {
5215 if (code >= LatinSmallLetterA && code <= LatinSmallLetterF) {
5216 return code - LatinSmallLetterA + 10;
5218 if (code >= LatinCapitalLetterA && code <= LatinCapitalLetterF) {
5219 return code - LatinCapitalLetterA + 10;
5221 return code - DigitZero;
5224 const legacyImpl = {
5226 return i < end ? s.charCodeAt(i) : -1;
5232 const unicodeImpl = {
5234 return i < end ? s.codePointAt(i) : -1;
5237 return c > 0xffff ? 2 : 1;
5242 this._impl = legacyImpl;
5260 get currentCodePoint() {
5263 get nextCodePoint() {
5266 get nextCodePoint2() {
5269 get nextCodePoint3() {
5272 reset(source, start, end, uFlag) {
5273 this._impl = uFlag ? unicodeImpl : legacyImpl;
5279 const impl = this._impl;
5281 this._cp1 = impl.at(this._s, this._end, index);
5282 this._w1 = impl.width(this._cp1);
5283 this._cp2 = impl.at(this._s, this._end, index + this._w1);
5284 this._w2 = impl.width(this._cp2);
5285 this._cp3 = impl.at(this._s, this._end, index + this._w1 + this._w2);
5286 this._w3 = impl.width(this._cp3);
5287 this._cp4 = impl.at(this._s, this._end, index + this._w1 + this._w2 + this._w3);
5290 if (this._cp1 !== -1) {
5291 const impl = this._impl;
5292 this._i += this._w1;
5293 this._cp1 = this._cp2;
5294 this._w1 = this._w2;
5295 this._cp2 = this._cp3;
5296 this._w2 = impl.width(this._cp2);
5297 this._cp3 = this._cp4;
5298 this._w3 = impl.width(this._cp3);
5299 this._cp4 = impl.at(this._s, this._end, this._i + this._w1 + this._w2 + this._w3);
5303 if (this._cp1 === cp) {
5310 if (this._cp1 === cp1 && this._cp2 === cp2) {
5317 eat3(cp1, cp2, cp3) {
5318 if (this._cp1 === cp1 && this._cp2 === cp2 && this._cp3 === cp3) {
5328 class RegExpSyntaxError extends SyntaxError {
5329 constructor(source, uFlag, index, message) {
5331 if (source[0] !== "/") {
5332 source = `/${source}/${uFlag ? "u" : ""}`;
5334 source = `: ${source}`;
5336 super(`Invalid regular expression${source}: ${message}`);
5341 function isSyntaxCharacter(cp) {
5342 return (cp === CircumflexAccent ||
5343 cp === DollarSign ||
5344 cp === ReverseSolidus ||
5348 cp === QuestionMark ||
5349 cp === LeftParenthesis ||
5350 cp === RightParenthesis ||
5351 cp === LeftSquareBracket ||
5352 cp === RightSquareBracket ||
5353 cp === LeftCurlyBracket ||
5354 cp === RightCurlyBracket ||
5355 cp === VerticalLine);
5357 function isRegExpIdentifierStart(cp) {
5358 return isIdStart(cp) || cp === DollarSign || cp === LowLine;
5360 function isRegExpIdentifierPart(cp) {
5361 return (isIdContinue(cp) ||
5362 cp === DollarSign ||
5364 cp === ZeroWidthNonJoiner ||
5365 cp === ZeroWidthJoiner);
5367 function isUnicodePropertyNameCharacter(cp) {
5368 return isLatinLetter(cp) || cp === LowLine;
5370 function isUnicodePropertyValueCharacter(cp) {
5371 return isUnicodePropertyNameCharacter(cp) || isDecimalDigit(cp);
5373 function isValidUnicodeProperty(name, value) {
5374 return PropertyData.hasOwnProperty(name) && PropertyData[name].has(value);
5376 function isValidUnicodePropertyName(name) {
5377 return PropertyData.$LONE.has(name);
5379 class RegExpValidator {
5380 constructor(options) {
5381 this._reader = new Reader();
5382 this._uFlag = false;
5383 this._nFlag = false;
5384 this._lastIntValue = 0;
5385 this._lastMinValue = 0;
5386 this._lastMaxValue = 0;
5387 this._lastStrValue = "";
5388 this._lastKeyValue = "";
5389 this._lastValValue = "";
5390 this._lastAssertionIsQuantifiable = false;
5391 this._numCapturingParens = 0;
5392 this._groupNames = new Set();
5393 this._backreferenceNames = new Set();
5394 this._options = options || {};
5396 validateLiteral(source, start = 0, end = source.length) {
5397 this._uFlag = this._nFlag = false;
5398 this.reset(source, start, end);
5399 this.onLiteralEnter(start);
5400 if (this.eat(Solidus) && this.eatRegExpBody() && this.eat(Solidus)) {
5401 const flagStart = this.index;
5402 const uFlag = source.indexOf("u", flagStart) !== -1;
5403 this.validateFlags(source, flagStart, end);
5404 this.validatePattern(source, start + 1, flagStart - 1, uFlag);
5406 else if (start >= end) {
5407 this.raise("Empty");
5410 const c = String.fromCodePoint(this.currentCodePoint);
5411 this.raise(`Unexpected character '${c}'`);
5413 this.onLiteralLeave(start, end);
5415 validateFlags(source, start = 0, end = source.length) {
5416 const existingFlags = new Set();
5418 let ignoreCase = false;
5419 let multiline = false;
5421 let unicode = false;
5423 for (let i = start; i < end; ++i) {
5424 const flag = source.charCodeAt(i);
5425 if (existingFlags.has(flag)) {
5426 this.raise(`Duplicated flag '${source[i]}'`);
5428 existingFlags.add(flag);
5429 if (flag === LatinSmallLetterG) {
5432 else if (flag === LatinSmallLetterI) {
5435 else if (flag === LatinSmallLetterM) {
5438 else if (flag === LatinSmallLetterU && this.ecmaVersion >= 2015) {
5441 else if (flag === LatinSmallLetterY && this.ecmaVersion >= 2015) {
5444 else if (flag === LatinSmallLetterS && this.ecmaVersion >= 2018) {
5448 this.raise(`Invalid flag '${source[i]}'`);
5451 this.onFlags(start, end, global, ignoreCase, multiline, unicode, sticky, dotAll);
5453 validatePattern(source, start = 0, end = source.length, uFlag = false) {
5454 this._uFlag = uFlag && this.ecmaVersion >= 2015;
5455 this._nFlag = uFlag && this.ecmaVersion >= 2018;
5456 this.reset(source, start, end);
5459 this.ecmaVersion >= 2018 &&
5460 this._groupNames.size > 0) {
5467 return Boolean(this._options.strict || this._uFlag);
5470 return this._options.ecmaVersion || 2018;
5472 onLiteralEnter(start) {
5473 if (this._options.onLiteralEnter) {
5474 this._options.onLiteralEnter(start);
5477 onLiteralLeave(start, end) {
5478 if (this._options.onLiteralLeave) {
5479 this._options.onLiteralLeave(start, end);
5482 onFlags(start, end, global, ignoreCase, multiline, unicode, sticky, dotAll) {
5483 if (this._options.onFlags) {
5484 this._options.onFlags(start, end, global, ignoreCase, multiline, unicode, sticky, dotAll);
5487 onPatternEnter(start) {
5488 if (this._options.onPatternEnter) {
5489 this._options.onPatternEnter(start);
5492 onPatternLeave(start, end) {
5493 if (this._options.onPatternLeave) {
5494 this._options.onPatternLeave(start, end);
5497 onDisjunctionEnter(start) {
5498 if (this._options.onDisjunctionEnter) {
5499 this._options.onDisjunctionEnter(start);
5502 onDisjunctionLeave(start, end) {
5503 if (this._options.onDisjunctionLeave) {
5504 this._options.onDisjunctionLeave(start, end);
5507 onAlternativeEnter(start, index) {
5508 if (this._options.onAlternativeEnter) {
5509 this._options.onAlternativeEnter(start, index);
5512 onAlternativeLeave(start, end, index) {
5513 if (this._options.onAlternativeLeave) {
5514 this._options.onAlternativeLeave(start, end, index);
5517 onGroupEnter(start) {
5518 if (this._options.onGroupEnter) {
5519 this._options.onGroupEnter(start);
5522 onGroupLeave(start, end) {
5523 if (this._options.onGroupLeave) {
5524 this._options.onGroupLeave(start, end);
5527 onCapturingGroupEnter(start, name) {
5528 if (this._options.onCapturingGroupEnter) {
5529 this._options.onCapturingGroupEnter(start, name);
5532 onCapturingGroupLeave(start, end, name) {
5533 if (this._options.onCapturingGroupLeave) {
5534 this._options.onCapturingGroupLeave(start, end, name);
5537 onQuantifier(start, end, min, max, greedy) {
5538 if (this._options.onQuantifier) {
5539 this._options.onQuantifier(start, end, min, max, greedy);
5542 onLookaroundAssertionEnter(start, kind, negate) {
5543 if (this._options.onLookaroundAssertionEnter) {
5544 this._options.onLookaroundAssertionEnter(start, kind, negate);
5547 onLookaroundAssertionLeave(start, end, kind, negate) {
5548 if (this._options.onLookaroundAssertionLeave) {
5549 this._options.onLookaroundAssertionLeave(start, end, kind, negate);
5552 onEdgeAssertion(start, end, kind) {
5553 if (this._options.onEdgeAssertion) {
5554 this._options.onEdgeAssertion(start, end, kind);
5557 onWordBoundaryAssertion(start, end, kind, negate) {
5558 if (this._options.onWordBoundaryAssertion) {
5559 this._options.onWordBoundaryAssertion(start, end, kind, negate);
5562 onAnyCharacterSet(start, end, kind) {
5563 if (this._options.onAnyCharacterSet) {
5564 this._options.onAnyCharacterSet(start, end, kind);
5567 onEscapeCharacterSet(start, end, kind, negate) {
5568 if (this._options.onEscapeCharacterSet) {
5569 this._options.onEscapeCharacterSet(start, end, kind, negate);
5572 onUnicodePropertyCharacterSet(start, end, kind, key, value, negate) {
5573 if (this._options.onUnicodePropertyCharacterSet) {
5574 this._options.onUnicodePropertyCharacterSet(start, end, kind, key, value, negate);
5577 onCharacter(start, end, value) {
5578 if (this._options.onCharacter) {
5579 this._options.onCharacter(start, end, value);
5582 onBackreference(start, end, ref) {
5583 if (this._options.onBackreference) {
5584 this._options.onBackreference(start, end, ref);
5587 onCharacterClassEnter(start, negate) {
5588 if (this._options.onCharacterClassEnter) {
5589 this._options.onCharacterClassEnter(start, negate);
5592 onCharacterClassLeave(start, end, negate) {
5593 if (this._options.onCharacterClassLeave) {
5594 this._options.onCharacterClassLeave(start, end, negate);
5597 onCharacterClassRange(start, end, min, max) {
5598 if (this._options.onCharacterClassRange) {
5599 this._options.onCharacterClassRange(start, end, min, max);
5603 return this._reader.source;
5606 return this._reader.index;
5608 get currentCodePoint() {
5609 return this._reader.currentCodePoint;
5611 get nextCodePoint() {
5612 return this._reader.nextCodePoint;
5614 get nextCodePoint2() {
5615 return this._reader.nextCodePoint2;
5617 get nextCodePoint3() {
5618 return this._reader.nextCodePoint3;
5620 reset(source, start, end) {
5621 this._reader.reset(source, start, end, this._uFlag);
5624 this._reader.rewind(index);
5627 this._reader.advance();
5630 return this._reader.eat(cp);
5633 return this._reader.eat2(cp1, cp2);
5635 eat3(cp1, cp2, cp3) {
5636 return this._reader.eat3(cp1, cp2, cp3);
5639 throw new RegExpSyntaxError(this.source, this._uFlag, this.index, message);
5642 const start = this.index;
5643 let inClass = false;
5644 let escaped = false;
5646 const cp = this.currentCodePoint;
5647 if (cp === -1 || isLineTerminator(cp)) {
5648 const kind = inClass ? "character class" : "regular expression";
5649 this.raise(`Unterminated ${kind}`);
5654 else if (cp === ReverseSolidus) {
5657 else if (cp === LeftSquareBracket) {
5660 else if (cp === RightSquareBracket) {
5663 else if ((cp === Solidus && !inClass) ||
5664 (cp === Asterisk && this.index === start)) {
5669 return this.index !== start;
5672 const start = this.index;
5673 this._numCapturingParens = this.countCapturingParens();
5674 this._groupNames.clear();
5675 this._backreferenceNames.clear();
5676 this.onPatternEnter(start);
5678 const cp = this.currentCodePoint;
5679 if (this.currentCodePoint !== -1) {
5680 if (cp === RightParenthesis) {
5681 this.raise("Unmatched ')'");
5683 if (cp === ReverseSolidus) {
5684 this.raise("\\ at end of pattern");
5686 if (cp === RightSquareBracket || cp === RightCurlyBracket) {
5687 this.raise("Lone quantifier brackets");
5689 const c = String.fromCodePoint(cp);
5690 this.raise(`Unexpected character '${c}'`);
5692 for (const name of this._backreferenceNames) {
5693 if (!this._groupNames.has(name)) {
5694 this.raise("Invalid named capture referenced");
5697 this.onPatternLeave(start, this.index);
5699 countCapturingParens() {
5700 const start = this.index;
5701 let inClass = false;
5702 let escaped = false;
5705 while ((cp = this.currentCodePoint) !== -1) {
5709 else if (cp === ReverseSolidus) {
5712 else if (cp === LeftSquareBracket) {
5715 else if (cp === RightSquareBracket) {
5718 else if (cp === LeftParenthesis &&
5720 (this.nextCodePoint !== QuestionMark ||
5721 (this.nextCodePoint2 === LessThanSign &&
5722 this.nextCodePoint3 !== EqualsSign &&
5723 this.nextCodePoint3 !== ExclamationMark))) {
5732 const start = this.index;
5734 this.onDisjunctionEnter(start);
5735 this.alternative(i++);
5736 while (this.eat(VerticalLine)) {
5737 this.alternative(i++);
5739 if (this.eatQuantifier(true)) {
5740 this.raise("Nothing to repeat");
5742 if (this.eat(LeftCurlyBracket)) {
5743 this.raise("Lone quantifier brackets");
5745 this.onDisjunctionLeave(start, this.index);
5748 const start = this.index;
5749 this.onAlternativeEnter(start, i);
5750 while (this.currentCodePoint !== -1 && this.eatTerm()) {
5752 this.onAlternativeLeave(start, this.index, i);
5755 if (this.eatAssertion()) {
5756 if (this._lastAssertionIsQuantifiable) {
5757 this.eatQuantifier();
5761 if (this.strict ? this.eatAtom() : this.eatExtendedAtom()) {
5762 this.eatQuantifier();
5768 const start = this.index;
5769 this._lastAssertionIsQuantifiable = false;
5770 if (this.eat(CircumflexAccent)) {
5771 this.onEdgeAssertion(start, this.index, "start");
5774 if (this.eat(DollarSign)) {
5775 this.onEdgeAssertion(start, this.index, "end");
5778 if (this.eat2(ReverseSolidus, LatinCapitalLetterB)) {
5779 this.onWordBoundaryAssertion(start, this.index, "word", true);
5782 if (this.eat2(ReverseSolidus, LatinSmallLetterB)) {
5783 this.onWordBoundaryAssertion(start, this.index, "word", false);
5786 if (this.eat2(LeftParenthesis, QuestionMark)) {
5787 const lookbehind = this.ecmaVersion >= 2018 && this.eat(LessThanSign);
5789 if (this.eat(EqualsSign) || (negate = this.eat(ExclamationMark))) {
5790 const kind = lookbehind ? "lookbehind" : "lookahead";
5791 this.onLookaroundAssertionEnter(start, kind, negate);
5793 if (!this.eat(RightParenthesis)) {
5794 this.raise("Unterminated group");
5796 this._lastAssertionIsQuantifiable = !lookbehind && !this.strict;
5797 this.onLookaroundAssertionLeave(start, this.index, kind, negate);
5804 eatQuantifier(noError = false) {
5805 const start = this.index;
5809 if (this.eat(Asterisk)) {
5811 max = Number.POSITIVE_INFINITY;
5813 else if (this.eat(PlusSign)) {
5815 max = Number.POSITIVE_INFINITY;
5817 else if (this.eat(QuestionMark)) {
5821 else if (this.eatBracedQuantifier(noError)) {
5822 min = this._lastMinValue;
5823 max = this._lastMaxValue;
5828 greedy = !this.eat(QuestionMark);
5830 this.onQuantifier(start, this.index, min, max, greedy);
5834 eatBracedQuantifier(noError) {
5835 const start = this.index;
5836 if (this.eat(LeftCurlyBracket)) {
5837 this._lastMinValue = 0;
5838 this._lastMaxValue = Number.POSITIVE_INFINITY;
5839 if (this.eatDecimalDigits()) {
5840 this._lastMinValue = this._lastMaxValue = this._lastIntValue;
5841 if (this.eat(Comma)) {
5842 this._lastMaxValue = this.eatDecimalDigits()
5843 ? this._lastIntValue
5844 : Number.POSITIVE_INFINITY;
5846 if (this.eat(RightCurlyBracket)) {
5847 if (!noError && this._lastMaxValue < this._lastMinValue) {
5848 this.raise("numbers out of order in {} quantifier");
5853 if (!noError && this.strict) {
5854 this.raise("Incomplete quantifier");
5861 return (this.eatPatternCharacter() ||
5863 this.eatReverseSolidusAtomEscape() ||
5864 this.eatCharacterClass() ||
5865 this.eatUncapturingGroup() ||
5866 this.eatCapturingGroup());
5869 if (this.eat(FullStop)) {
5870 this.onAnyCharacterSet(this.index - 1, this.index, "any");
5875 eatReverseSolidusAtomEscape() {
5876 const start = this.index;
5877 if (this.eat(ReverseSolidus)) {
5878 if (this.eatAtomEscape()) {
5885 eatUncapturingGroup() {
5886 const start = this.index;
5887 if (this.eat3(LeftParenthesis, QuestionMark, Colon)) {
5888 this.onGroupEnter(start);
5890 if (!this.eat(RightParenthesis)) {
5891 this.raise("Unterminated group");
5893 this.onGroupLeave(start, this.index);
5898 eatCapturingGroup() {
5899 const start = this.index;
5900 if (this.eat(LeftParenthesis)) {
5901 this._lastStrValue = "";
5902 if (this.ecmaVersion >= 2018) {
5903 this.groupSpecifier();
5905 else if (this.currentCodePoint === QuestionMark) {
5906 this.raise("Invalid group");
5908 const name = this._lastStrValue || null;
5909 this.onCapturingGroupEnter(start, name);
5911 if (!this.eat(RightParenthesis)) {
5912 this.raise("Unterminated group");
5914 this.onCapturingGroupLeave(start, this.index, name);
5920 return (this.eatDot() ||
5921 this.eatReverseSolidusAtomEscape() ||
5922 this.eatReverseSolidusFollowedByC() ||
5923 this.eatCharacterClass() ||
5924 this.eatUncapturingGroup() ||
5925 this.eatCapturingGroup() ||
5926 this.eatInvalidBracedQuantifier() ||
5927 this.eatExtendedPatternCharacter());
5929 eatReverseSolidusFollowedByC() {
5930 if (this.currentCodePoint === ReverseSolidus &&
5931 this.nextCodePoint === LatinSmallLetterC) {
5932 this._lastIntValue = this.currentCodePoint;
5934 this.onCharacter(this.index - 1, this.index, ReverseSolidus);
5939 eatInvalidBracedQuantifier() {
5940 if (this.eatBracedQuantifier(true)) {
5941 this.raise("Nothing to repeat");
5945 eatSyntaxCharacter() {
5946 if (isSyntaxCharacter(this.currentCodePoint)) {
5947 this._lastIntValue = this.currentCodePoint;
5953 eatPatternCharacter() {
5954 const start = this.index;
5955 const cp = this.currentCodePoint;
5956 if (cp !== -1 && !isSyntaxCharacter(cp)) {
5958 this.onCharacter(start, this.index, cp);
5963 eatExtendedPatternCharacter() {
5964 const start = this.index;
5965 const cp = this.currentCodePoint;
5967 cp !== CircumflexAccent &&
5968 cp !== DollarSign &&
5969 cp !== ReverseSolidus &&
5973 cp !== QuestionMark &&
5974 cp !== LeftParenthesis &&
5975 cp !== RightParenthesis &&
5976 cp !== LeftSquareBracket &&
5977 cp !== VerticalLine) {
5979 this.onCharacter(start, this.index, cp);
5985 this._lastStrValue = "";
5986 if (this.eat(QuestionMark)) {
5987 if (this.eatGroupName()) {
5988 if (!this._groupNames.has(this._lastStrValue)) {
5989 this._groupNames.add(this._lastStrValue);
5992 this.raise("Duplicate capture group name");
5994 this.raise("Invalid group");
5998 this._lastStrValue = "";
5999 if (this.eat(LessThanSign)) {
6000 if (this.eatRegExpIdentifierName() && this.eat(GreaterThanSign)) {
6003 this.raise("Invalid capture group name");
6007 eatRegExpIdentifierName() {
6008 this._lastStrValue = "";
6009 if (this.eatRegExpIdentifierStart()) {
6010 this._lastStrValue += String.fromCodePoint(this._lastIntValue);
6011 while (this.eatRegExpIdentifierPart()) {
6012 this._lastStrValue += String.fromCodePoint(this._lastIntValue);
6018 eatRegExpIdentifierStart() {
6019 const start = this.index;
6020 let cp = this.currentCodePoint;
6022 if (cp === ReverseSolidus && this.eatRegExpUnicodeEscapeSequence()) {
6023 cp = this._lastIntValue;
6025 if (isRegExpIdentifierStart(cp)) {
6026 this._lastIntValue = cp;
6029 if (this.index !== start) {
6034 eatRegExpIdentifierPart() {
6035 const start = this.index;
6036 let cp = this.currentCodePoint;
6038 if (cp === ReverseSolidus && this.eatRegExpUnicodeEscapeSequence()) {
6039 cp = this._lastIntValue;
6041 if (isRegExpIdentifierPart(cp)) {
6042 this._lastIntValue = cp;
6045 if (this.index !== start) {
6051 if (this.eatBackreference() ||
6052 this.eatCharacterClassEscape() ||
6053 this.eatCharacterEscape() ||
6054 (this._nFlag && this.eatKGroupName())) {
6057 if (this.strict || this._uFlag) {
6058 this.raise("Invalid escape");
6062 eatBackreference() {
6063 const start = this.index;
6064 if (this.eatDecimalEscape()) {
6065 const n = this._lastIntValue;
6066 if (n <= this._numCapturingParens) {
6067 this.onBackreference(start - 1, this.index, n);
6071 this.raise("Invalid escape");
6078 const start = this.index;
6079 if (this.eat(LatinSmallLetterK)) {
6080 if (this.eatGroupName()) {
6081 const groupName = this._lastStrValue;
6082 this._backreferenceNames.add(groupName);
6083 this.onBackreference(start - 1, this.index, groupName);
6086 this.raise("Invalid named reference");
6090 eatCharacterEscape() {
6091 const start = this.index;
6092 if (this.eatControlEscape() ||
6093 this.eatCControlLetter() ||
6095 this.eatHexEscapeSequence() ||
6096 this.eatRegExpUnicodeEscapeSequence() ||
6097 (!this.strict && this.eatLegacyOctalEscapeSequence()) ||
6098 this.eatIdentityEscape()) {
6099 this.onCharacter(start - 1, this.index, this._lastIntValue);
6104 eatCControlLetter() {
6105 const start = this.index;
6106 if (this.eat(LatinSmallLetterC)) {
6107 if (this.eatControlLetter()) {
6115 if (this.currentCodePoint === DigitZero &&
6116 !isDecimalDigit(this.nextCodePoint)) {
6117 this._lastIntValue = 0;
6123 eatControlEscape() {
6124 if (this.eat(LatinSmallLetterT)) {
6125 this._lastIntValue = CharacterTabulation;
6128 if (this.eat(LatinSmallLetterN)) {
6129 this._lastIntValue = LineFeed;
6132 if (this.eat(LatinSmallLetterV)) {
6133 this._lastIntValue = LineTabulation;
6136 if (this.eat(LatinSmallLetterF)) {
6137 this._lastIntValue = FormFeed;
6140 if (this.eat(LatinSmallLetterR)) {
6141 this._lastIntValue = CarriageReturn;
6146 eatControlLetter() {
6147 const cp = this.currentCodePoint;
6148 if (isLatinLetter(cp)) {
6150 this._lastIntValue = cp % 0x20;
6155 eatRegExpUnicodeEscapeSequence() {
6156 const start = this.index;
6157 if (this.eat(LatinSmallLetterU)) {
6158 if (this.eatFixedHexDigits(4)) {
6159 const lead = this._lastIntValue;
6160 if (this._uFlag && lead >= 0xd800 && lead <= 0xdbff) {
6161 const leadSurrogateEnd = this.index;
6162 if (this.eat(ReverseSolidus) &&
6163 this.eat(LatinSmallLetterU) &&
6164 this.eatFixedHexDigits(4)) {
6165 const trail = this._lastIntValue;
6166 if (trail >= 0xdc00 && trail <= 0xdfff) {
6167 this._lastIntValue =
6168 (lead - 0xd800) * 0x400 +
6174 this.rewind(leadSurrogateEnd);
6175 this._lastIntValue = lead;
6180 this.eat(LeftCurlyBracket) &&
6181 this.eatHexDigits() &&
6182 this.eat(RightCurlyBracket) &&
6183 isValidUnicode(this._lastIntValue)) {
6186 if (this.strict || this._uFlag) {
6187 this.raise("Invalid unicode escape");
6193 eatIdentityEscape() {
6195 if (this.eatSyntaxCharacter()) {
6198 if (this.eat(Solidus)) {
6199 this._lastIntValue = Solidus;
6204 if (this.isValidIdentityEscape(this.currentCodePoint)) {
6205 this._lastIntValue = this.currentCodePoint;
6211 isValidIdentityEscape(cp) {
6216 return !isIdContinue(cp);
6218 return (cp !== LatinSmallLetterC &&
6219 (!this._nFlag || cp !== LatinSmallLetterK));
6221 eatDecimalEscape() {
6222 this._lastIntValue = 0;
6223 let cp = this.currentCodePoint;
6224 if (cp >= DigitOne && cp <= DigitNine) {
6226 this._lastIntValue = 10 * this._lastIntValue + (cp - DigitZero);
6228 } while ((cp = this.currentCodePoint) >= DigitZero &&
6234 eatCharacterClassEscape() {
6235 const start = this.index;
6236 if (this.eat(LatinSmallLetterD)) {
6237 this._lastIntValue = -1;
6238 this.onEscapeCharacterSet(start - 1, this.index, "digit", false);
6241 if (this.eat(LatinCapitalLetterD)) {
6242 this._lastIntValue = -1;
6243 this.onEscapeCharacterSet(start - 1, this.index, "digit", true);
6246 if (this.eat(LatinSmallLetterS)) {
6247 this._lastIntValue = -1;
6248 this.onEscapeCharacterSet(start - 1, this.index, "space", false);
6251 if (this.eat(LatinCapitalLetterS)) {
6252 this._lastIntValue = -1;
6253 this.onEscapeCharacterSet(start - 1, this.index, "space", true);
6256 if (this.eat(LatinSmallLetterW)) {
6257 this._lastIntValue = -1;
6258 this.onEscapeCharacterSet(start - 1, this.index, "word", false);
6261 if (this.eat(LatinCapitalLetterW)) {
6262 this._lastIntValue = -1;
6263 this.onEscapeCharacterSet(start - 1, this.index, "word", true);
6268 this.ecmaVersion >= 2018 &&
6269 (this.eat(LatinSmallLetterP) ||
6270 (negate = this.eat(LatinCapitalLetterP)))) {
6271 this._lastIntValue = -1;
6272 if (this.eat(LeftCurlyBracket) &&
6273 this.eatUnicodePropertyValueExpression() &&
6274 this.eat(RightCurlyBracket)) {
6275 this.onUnicodePropertyCharacterSet(start - 1, this.index, "property", this._lastKeyValue, this._lastValValue || null, negate);
6278 this.raise("Invalid property name");
6282 eatUnicodePropertyValueExpression() {
6283 const start = this.index;
6284 if (this.eatUnicodePropertyName() && this.eat(EqualsSign)) {
6285 this._lastKeyValue = this._lastStrValue;
6286 if (this.eatUnicodePropertyValue()) {
6287 this._lastValValue = this._lastStrValue;
6288 if (isValidUnicodeProperty(this._lastKeyValue, this._lastValValue)) {
6291 this.raise("Invalid property name");
6295 if (this.eatLoneUnicodePropertyNameOrValue()) {
6296 const nameOrValue = this._lastStrValue;
6297 if (isValidUnicodeProperty("General_Category", nameOrValue)) {
6298 this._lastKeyValue = "General_Category";
6299 this._lastValValue = nameOrValue;
6302 if (isValidUnicodePropertyName(nameOrValue)) {
6303 this._lastKeyValue = nameOrValue;
6304 this._lastValValue = "";
6307 this.raise("Invalid property name");
6311 eatUnicodePropertyName() {
6312 this._lastStrValue = "";
6313 while (isUnicodePropertyNameCharacter(this.currentCodePoint)) {
6314 this._lastStrValue += String.fromCodePoint(this.currentCodePoint);
6317 return this._lastStrValue !== "";
6319 eatUnicodePropertyValue() {
6320 this._lastStrValue = "";
6321 while (isUnicodePropertyValueCharacter(this.currentCodePoint)) {
6322 this._lastStrValue += String.fromCodePoint(this.currentCodePoint);
6325 return this._lastStrValue !== "";
6327 eatLoneUnicodePropertyNameOrValue() {
6328 return this.eatUnicodePropertyValue();
6330 eatCharacterClass() {
6331 const start = this.index;
6332 if (this.eat(LeftSquareBracket)) {
6333 const negate = this.eat(CircumflexAccent);
6334 this.onCharacterClassEnter(start, negate);
6336 if (!this.eat(RightSquareBracket)) {
6337 this.raise("Unterminated character class");
6339 this.onCharacterClassLeave(start, this.index, negate);
6345 let start = this.index;
6346 while (this.eatClassAtom()) {
6347 const left = this._lastIntValue;
6348 const hyphenStart = this.index;
6349 if (this.eat(HyphenMinus)) {
6350 this.onCharacter(hyphenStart, this.index, HyphenMinus);
6351 if (this.eatClassAtom()) {
6352 const right = this._lastIntValue;
6353 if (left === -1 || right === -1) {
6355 this.raise("Invalid character class");
6358 else if (left > right) {
6359 this.raise("Range out of order in character class");
6362 this.onCharacterClassRange(start, this.index, left, right);
6370 const start = this.index;
6371 if (this.eat(ReverseSolidus)) {
6372 if (this.eatClassEscape()) {
6376 this.raise("Invalid escape");
6380 const cp = this.currentCodePoint;
6381 if (cp !== -1 && cp !== RightSquareBracket) {
6383 this._lastIntValue = cp;
6384 this.onCharacter(start, this.index, cp);
6390 const start = this.index;
6391 if (this.eat(LatinSmallLetterB)) {
6392 this._lastIntValue = Backspace;
6393 this.onCharacter(start - 1, this.index, Backspace);
6396 if (this._uFlag && this.eat(HyphenMinus)) {
6397 this._lastIntValue = HyphenMinus;
6398 this.onCharacter(start - 1, this.index, HyphenMinus);
6401 if (!this._uFlag && this.eat(LatinSmallLetterC)) {
6402 if (this.eatClassControlLetter()) {
6403 this.onCharacter(start - 1, this.index, this._lastIntValue);
6408 return this.eatCharacterClassEscape() || this.eatCharacterEscape();
6410 eatClassControlLetter() {
6411 const cp = this.currentCodePoint;
6412 if (isDecimalDigit(cp) || cp === LowLine) {
6414 this._lastIntValue = cp % 0x20;
6419 eatHexEscapeSequence() {
6420 const start = this.index;
6421 if (this.eat(LatinSmallLetterX)) {
6422 if (this.eatFixedHexDigits(2)) {
6426 this.raise("Invalid escape");
6432 eatDecimalDigits() {
6433 const start = this.index;
6434 this._lastIntValue = 0;
6435 while (isDecimalDigit(this.currentCodePoint)) {
6436 this._lastIntValue =
6437 10 * this._lastIntValue + digitToInt(this.currentCodePoint);
6440 return this.index !== start;
6443 const start = this.index;
6444 this._lastIntValue = 0;
6445 while (isHexDigit(this.currentCodePoint)) {
6446 this._lastIntValue =
6447 16 * this._lastIntValue + digitToInt(this.currentCodePoint);
6450 return this.index !== start;
6452 eatLegacyOctalEscapeSequence() {
6453 if (this.eatOctalDigit()) {
6454 const n1 = this._lastIntValue;
6455 if (this.eatOctalDigit()) {
6456 const n2 = this._lastIntValue;
6457 if (n1 <= 3 && this.eatOctalDigit()) {
6458 this._lastIntValue = n1 * 64 + n2 * 8 + this._lastIntValue;
6461 this._lastIntValue = n1 * 8 + n2;
6465 this._lastIntValue = n1;
6472 const cp = this.currentCodePoint;
6473 if (isOctalDigit(cp)) {
6475 this._lastIntValue = cp - DigitZero;
6478 this._lastIntValue = 0;
6481 eatFixedHexDigits(length) {
6482 const start = this.index;
6483 this._lastIntValue = 0;
6484 for (let i = 0; i < length; ++i) {
6485 const cp = this.currentCodePoint;
6486 if (!isHexDigit(cp)) {
6490 this._lastIntValue = 16 * this._lastIntValue + digitToInt(cp);
6497 const DummyPattern = {};
6498 const DummyFlags = {};
6499 const DummyCapturingGroup = {};
6500 class RegExpParserState {
6501 constructor(options) {
6502 this._node = DummyPattern;
6503 this._flags = DummyFlags;
6504 this._backreferences = [];
6505 this._capturingGroups = [];
6507 this.strict = Boolean(options && options.strict);
6508 this.ecmaVersion = (options && options.ecmaVersion) || 2018;
6511 if (this._node.type !== "Pattern") {
6512 throw new Error("UnknownError");
6517 if (this._flags.type !== "Flags") {
6518 throw new Error("UnknownError");
6522 onFlags(start, end, global, ignoreCase, multiline, unicode, sticky, dotAll) {
6528 raw: this.source.slice(start, end),
6537 onPatternEnter(start) {
6546 this._backreferences.length = 0;
6547 this._capturingGroups.length = 0;
6549 onPatternLeave(start, end) {
6550 this._node.end = end;
6551 this._node.raw = this.source.slice(start, end);
6552 for (const reference of this._backreferences) {
6553 const ref = reference.ref;
6554 const group = typeof ref === "number"
6555 ? this._capturingGroups[ref - 1]
6556 : this._capturingGroups.find(g => g.name === ref);
6557 reference.resolved = group;
6558 group.references.push(reference);
6561 onAlternativeEnter(start) {
6562 const parent = this._node;
6563 if (parent.type !== "Assertion" &&
6564 parent.type !== "CapturingGroup" &&
6565 parent.type !== "Group" &&
6566 parent.type !== "Pattern") {
6567 throw new Error("UnknownError");
6570 type: "Alternative",
6577 parent.alternatives.push(this._node);
6579 onAlternativeLeave(start, end) {
6580 const node = this._node;
6581 if (node.type !== "Alternative") {
6582 throw new Error("UnknownError");
6585 node.raw = this.source.slice(start, end);
6586 this._node = node.parent;
6588 onGroupEnter(start) {
6589 const parent = this._node;
6590 if (parent.type !== "Alternative") {
6591 throw new Error("UnknownError");
6601 parent.elements.push(this._node);
6603 onGroupLeave(start, end) {
6604 const node = this._node;
6605 if (node.type !== "Group" || node.parent.type !== "Alternative") {
6606 throw new Error("UnknownError");
6609 node.raw = this.source.slice(start, end);
6610 this._node = node.parent;
6612 onCapturingGroupEnter(start, name) {
6613 const parent = this._node;
6614 if (parent.type !== "Alternative") {
6615 throw new Error("UnknownError");
6618 type: "CapturingGroup",
6627 parent.elements.push(this._node);
6628 this._capturingGroups.push(this._node);
6630 onCapturingGroupLeave(start, end) {
6631 const node = this._node;
6632 if (node.type !== "CapturingGroup" ||
6633 node.parent.type !== "Alternative") {
6634 throw new Error("UnknownError");
6637 node.raw = this.source.slice(start, end);
6638 this._node = node.parent;
6640 onQuantifier(start, end, min, max, greedy) {
6641 const parent = this._node;
6642 if (parent.type !== "Alternative") {
6643 throw new Error("UnknownError");
6645 const element = parent.elements.pop();
6646 if (element == null ||
6647 element.type === "Quantifier" ||
6648 (element.type === "Assertion" && element.kind !== "lookahead")) {
6649 throw new Error("UnknownError");
6654 start: element.start,
6656 raw: this.source.slice(element.start, end),
6662 parent.elements.push(node);
6663 element.parent = node;
6665 onLookaroundAssertionEnter(start, kind, negate) {
6666 const parent = this._node;
6667 if (parent.type !== "Alternative") {
6668 throw new Error("UnknownError");
6680 parent.elements.push(this._node);
6682 onLookaroundAssertionLeave(start, end) {
6683 const node = this._node;
6684 if (node.type !== "Assertion" || node.parent.type !== "Alternative") {
6685 throw new Error("UnknownError");
6688 node.raw = this.source.slice(start, end);
6689 this._node = node.parent;
6691 onEdgeAssertion(start, end, kind) {
6692 const parent = this._node;
6693 if (parent.type !== "Alternative") {
6694 throw new Error("UnknownError");
6696 parent.elements.push({
6701 raw: this.source.slice(start, end),
6705 onWordBoundaryAssertion(start, end, kind, negate) {
6706 const parent = this._node;
6707 if (parent.type !== "Alternative") {
6708 throw new Error("UnknownError");
6710 parent.elements.push({
6715 raw: this.source.slice(start, end),
6720 onAnyCharacterSet(start, end, kind) {
6721 const parent = this._node;
6722 if (parent.type !== "Alternative") {
6723 throw new Error("UnknownError");
6725 parent.elements.push({
6726 type: "CharacterSet",
6730 raw: this.source.slice(start, end),
6734 onEscapeCharacterSet(start, end, kind, negate) {
6735 const parent = this._node;
6736 if (parent.type !== "Alternative" && parent.type !== "CharacterClass") {
6737 throw new Error("UnknownError");
6739 parent.elements.push({
6740 type: "CharacterSet",
6744 raw: this.source.slice(start, end),
6749 onUnicodePropertyCharacterSet(start, end, kind, key, value, negate) {
6750 const parent = this._node;
6751 if (parent.type !== "Alternative" && parent.type !== "CharacterClass") {
6752 throw new Error("UnknownError");
6754 parent.elements.push({
6755 type: "CharacterSet",
6759 raw: this.source.slice(start, end),
6766 onCharacter(start, end, value) {
6767 const parent = this._node;
6768 if (parent.type !== "Alternative" && parent.type !== "CharacterClass") {
6769 throw new Error("UnknownError");
6771 parent.elements.push({
6776 raw: this.source.slice(start, end),
6780 onBackreference(start, end, ref) {
6781 const parent = this._node;
6782 if (parent.type !== "Alternative") {
6783 throw new Error("UnknownError");
6786 type: "Backreference",
6790 raw: this.source.slice(start, end),
6792 resolved: DummyCapturingGroup,
6794 parent.elements.push(node);
6795 this._backreferences.push(node);
6797 onCharacterClassEnter(start, negate) {
6798 const parent = this._node;
6799 if (parent.type !== "Alternative") {
6800 throw new Error("UnknownError");
6803 type: "CharacterClass",
6811 parent.elements.push(this._node);
6813 onCharacterClassLeave(start, end) {
6814 const node = this._node;
6815 if (node.type !== "CharacterClass" ||
6816 node.parent.type !== "Alternative") {
6817 throw new Error("UnknownError");
6820 node.raw = this.source.slice(start, end);
6821 this._node = node.parent;
6823 onCharacterClassRange(start, end) {
6824 const parent = this._node;
6825 if (parent.type !== "CharacterClass") {
6826 throw new Error("UnknownError");
6828 const elements = parent.elements;
6829 const max = elements.pop();
6830 const hyphen = elements.pop();
6831 const min = elements.pop();
6835 min.type !== "Character" ||
6836 max.type !== "Character" ||
6837 hyphen.type !== "Character" ||
6838 hyphen.value !== HyphenMinus) {
6839 throw new Error("UnknownError");
6842 type: "CharacterClassRange",
6846 raw: this.source.slice(start, end),
6852 elements.push(node);
6855 class RegExpParser {
6856 constructor(options) {
6857 this._state = new RegExpParserState(options);
6858 this._validator = new RegExpValidator(this._state);
6860 parseLiteral(source, start = 0, end = source.length) {
6861 this._state.source = source;
6862 this._validator.validateLiteral(source, start, end);
6863 const pattern = this._state.pattern;
6864 const flags = this._state.flags;
6866 type: "RegExpLiteral",
6874 pattern.parent = literal;
6875 flags.parent = literal;
6878 parseFlags(source, start = 0, end = source.length) {
6879 this._state.source = source;
6880 this._validator.validateFlags(source, start, end);
6881 return this._state.flags;
6883 parsePattern(source, start = 0, end = source.length, uFlag = false) {
6884 this._state.source = source;
6885 this._validator.validatePattern(source, start, end, uFlag);
6886 return this._state.pattern;
6890 class RegExpVisitor {
6891 constructor(handlers) {
6892 this._handlers = handlers;
6895 switch (node.type) {
6897 this.visitAlternative(node);
6900 this.visitAssertion(node);
6902 case "Backreference":
6903 this.visitBackreference(node);
6905 case "CapturingGroup":
6906 this.visitCapturingGroup(node);
6909 this.visitCharacter(node);
6911 case "CharacterClass":
6912 this.visitCharacterClass(node);
6914 case "CharacterClassRange":
6915 this.visitCharacterClassRange(node);
6917 case "CharacterSet":
6918 this.visitCharacterSet(node);
6921 this.visitFlags(node);
6924 this.visitGroup(node);
6927 this.visitPattern(node);
6930 this.visitQuantifier(node);
6932 case "RegExpLiteral":
6933 this.visitRegExpLiteral(node);
6936 throw new Error(`Unknown type: ${node.type}`);
6939 visitAlternative(node) {
6940 if (this._handlers.onAlternativeEnter) {
6941 this._handlers.onAlternativeEnter(node);
6943 node.elements.forEach(this.visit, this);
6944 if (this._handlers.onAlternativeLeave) {
6945 this._handlers.onAlternativeLeave(node);
6948 visitAssertion(node) {
6949 if (this._handlers.onAssertionEnter) {
6950 this._handlers.onAssertionEnter(node);
6952 if (node.kind === "lookahead" || node.kind === "lookbehind") {
6953 node.alternatives.forEach(this.visit, this);
6955 if (this._handlers.onAssertionLeave) {
6956 this._handlers.onAssertionLeave(node);
6959 visitBackreference(node) {
6960 if (this._handlers.onBackreferenceEnter) {
6961 this._handlers.onBackreferenceEnter(node);
6963 if (this._handlers.onBackreferenceLeave) {
6964 this._handlers.onBackreferenceLeave(node);
6967 visitCapturingGroup(node) {
6968 if (this._handlers.onCapturingGroupEnter) {
6969 this._handlers.onCapturingGroupEnter(node);
6971 node.alternatives.forEach(this.visit, this);
6972 if (this._handlers.onCapturingGroupLeave) {
6973 this._handlers.onCapturingGroupLeave(node);
6976 visitCharacter(node) {
6977 if (this._handlers.onCharacterEnter) {
6978 this._handlers.onCharacterEnter(node);
6980 if (this._handlers.onCharacterLeave) {
6981 this._handlers.onCharacterLeave(node);
6984 visitCharacterClass(node) {
6985 if (this._handlers.onCharacterClassEnter) {
6986 this._handlers.onCharacterClassEnter(node);
6988 node.elements.forEach(this.visit, this);
6989 if (this._handlers.onCharacterClassLeave) {
6990 this._handlers.onCharacterClassLeave(node);
6993 visitCharacterClassRange(node) {
6994 if (this._handlers.onCharacterClassRangeEnter) {
6995 this._handlers.onCharacterClassRangeEnter(node);
6997 this.visitCharacter(node.min);
6998 this.visitCharacter(node.max);
6999 if (this._handlers.onCharacterClassRangeLeave) {
7000 this._handlers.onCharacterClassRangeLeave(node);
7003 visitCharacterSet(node) {
7004 if (this._handlers.onCharacterSetEnter) {
7005 this._handlers.onCharacterSetEnter(node);
7007 if (this._handlers.onCharacterSetLeave) {
7008 this._handlers.onCharacterSetLeave(node);
7012 if (this._handlers.onFlagsEnter) {
7013 this._handlers.onFlagsEnter(node);
7015 if (this._handlers.onFlagsLeave) {
7016 this._handlers.onFlagsLeave(node);
7020 if (this._handlers.onGroupEnter) {
7021 this._handlers.onGroupEnter(node);
7023 node.alternatives.forEach(this.visit, this);
7024 if (this._handlers.onGroupLeave) {
7025 this._handlers.onGroupLeave(node);
7028 visitPattern(node) {
7029 if (this._handlers.onPatternEnter) {
7030 this._handlers.onPatternEnter(node);
7032 node.alternatives.forEach(this.visit, this);
7033 if (this._handlers.onPatternLeave) {
7034 this._handlers.onPatternLeave(node);
7037 visitQuantifier(node) {
7038 if (this._handlers.onQuantifierEnter) {
7039 this._handlers.onQuantifierEnter(node);
7041 this.visit(node.element);
7042 if (this._handlers.onQuantifierLeave) {
7043 this._handlers.onQuantifierLeave(node);
7046 visitRegExpLiteral(node) {
7047 if (this._handlers.onRegExpLiteralEnter) {
7048 this._handlers.onRegExpLiteralEnter(node);
7050 this.visitPattern(node.pattern);
7051 this.visitFlags(node.flags);
7052 if (this._handlers.onRegExpLiteralLeave) {
7053 this._handlers.onRegExpLiteralLeave(node);
7058 function parseRegExpLiteral(source, options) {
7059 return new RegExpParser(options).parseLiteral(String(source));
7061 function validateRegExpLiteral(source, options) {
7062 return new RegExpValidator(options).validateLiteral(source);
7064 function visitRegExpAST(node, handlers) {
7065 new RegExpVisitor(handlers).visit(node);
7068 export { ast as AST, RegExpParser, RegExpValidator, parseRegExpLiteral, validateRegExpLiteral, visitRegExpAST };
7069 //# sourceMappingURL=index.mjs.map