@wxml/parser
Version:
A fast and tolerant wxml parser
1,551 lines (1,415 loc) • 539 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.wxmlParser = {}));
})(this, (function (exports) { 'use strict';
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var api$1 = {};
var version = {};
Object.defineProperty(version, "__esModule", { value: true });
version.VERSION = void 0;
// needs a separate module as this is required inside chevrotain productive code
// and also in the entry point for webpack(api.ts).
// A separate file avoids cyclic dependencies and webpack errors.
version.VERSION = "9.0.2";
var parser = {};
var api = {};
/*
Utils using lodash style API. (not necessarily 100% compliant) for functional and other utils.
These utils should replace usage of lodash in the production code base. not because they are any better...
but for the purpose of being a dependency free library.
The hotspots in the code are already written in imperative style for performance reasons.
so writing several dozen utils which may be slower than the original lodash, does not matter as much
considering they will not be invoked in hotspots...
*/
var __spreadArray = (commonjsGlobal && commonjsGlobal.__spreadArray) || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};
Object.defineProperty(api, "__esModule", { value: true });
api.toFastProperties = api.timer = api.peek = api.isES2015MapSupported = api.PRINT_WARNING = api.PRINT_ERROR = api.packArray = api.IDENTITY = api.NOOP = api.merge = api.groupBy = api.defaults = api.assignNoOverwrite = api.assign = api.zipObject = api.sortBy = api.indexOf = api.some = api.difference = api.every = api.isObject = api.isRegExp = api.isArray = api.partial = api.uniq = api.compact = api.reduce = api.findAll = api.find = api.cloneObj = api.cloneArr = api.contains = api.has = api.pick = api.reject = api.filter = api.dropRight = api.drop = api.isFunction = api.isUndefined = api.isString = api.forEach = api.last = api.first = api.flatten = api.map = api.mapValues = api.values = api.keys = api.isEmpty = void 0;
api.upperFirst = void 0;
function isEmpty(arr) {
return arr && arr.length === 0;
}
api.isEmpty = isEmpty;
function keys$2(obj) {
if (obj === undefined || obj === null) {
return [];
}
return Object.keys(obj);
}
api.keys = keys$2;
function values(obj) {
var vals = [];
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
vals.push(obj[keys[i]]);
}
return vals;
}
api.values = values;
function mapValues(obj, callback) {
var result = [];
var objKeys = keys$2(obj);
for (var idx = 0; idx < objKeys.length; idx++) {
var currKey = objKeys[idx];
result.push(callback.call(null, obj[currKey], currKey));
}
return result;
}
api.mapValues = mapValues;
function map$1(arr, callback) {
var result = [];
for (var idx = 0; idx < arr.length; idx++) {
result.push(callback.call(null, arr[idx], idx));
}
return result;
}
api.map = map$1;
function flatten$1(arr) {
var result = [];
for (var idx = 0; idx < arr.length; idx++) {
var currItem = arr[idx];
if (Array.isArray(currItem)) {
result = result.concat(flatten$1(currItem));
}
else {
result.push(currItem);
}
}
return result;
}
api.flatten = flatten$1;
function first$2(arr) {
return isEmpty(arr) ? undefined : arr[0];
}
api.first = first$2;
function last(arr) {
var len = arr && arr.length;
return len ? arr[len - 1] : undefined;
}
api.last = last;
function forEach(collection, iteratorCallback) {
/* istanbul ignore else */
if (Array.isArray(collection)) {
for (var i = 0; i < collection.length; i++) {
iteratorCallback.call(null, collection[i], i);
}
}
else if (isObject$1(collection)) {
var colKeys = keys$2(collection);
for (var i = 0; i < colKeys.length; i++) {
var key = colKeys[i];
var value = collection[key];
iteratorCallback.call(null, value, key);
}
}
else {
throw Error("non exhaustive match");
}
}
api.forEach = forEach;
function isString(item) {
return typeof item === "string";
}
api.isString = isString;
function isUndefined(item) {
return item === undefined;
}
api.isUndefined = isUndefined;
function isFunction$1(item) {
return item instanceof Function;
}
api.isFunction = isFunction$1;
function drop(arr, howMuch) {
if (howMuch === void 0) { howMuch = 1; }
return arr.slice(howMuch, arr.length);
}
api.drop = drop;
function dropRight(arr, howMuch) {
if (howMuch === void 0) { howMuch = 1; }
return arr.slice(0, arr.length - howMuch);
}
api.dropRight = dropRight;
function filter(arr, predicate) {
var result = [];
if (Array.isArray(arr)) {
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
if (predicate.call(null, item)) {
result.push(item);
}
}
}
return result;
}
api.filter = filter;
function reject(arr, predicate) {
return filter(arr, function (item) { return !predicate(item); });
}
api.reject = reject;
function pick$2(obj, predicate) {
var keys = Object.keys(obj);
var result = {};
for (var i = 0; i < keys.length; i++) {
var currKey = keys[i];
var currItem = obj[currKey];
if (predicate(currItem)) {
result[currKey] = currItem;
}
}
return result;
}
api.pick = pick$2;
function has(obj, prop) {
if (isObject$1(obj)) {
return obj.hasOwnProperty(prop);
}
return false;
}
api.has = has;
function contains(arr, item) {
return find(arr, function (currItem) { return currItem === item; }) !== undefined ? true : false;
}
api.contains = contains;
/**
* shallow clone
*/
function cloneArr(arr) {
var newArr = [];
for (var i = 0; i < arr.length; i++) {
newArr.push(arr[i]);
}
return newArr;
}
api.cloneArr = cloneArr;
/**
* shallow clone
*/
function cloneObj(obj) {
var clonedObj = {};
for (var key in obj) {
/* istanbul ignore else */
if (Object.prototype.hasOwnProperty.call(obj, key)) {
clonedObj[key] = obj[key];
}
}
return clonedObj;
}
api.cloneObj = cloneObj;
function find(arr, predicate) {
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
if (predicate.call(null, item)) {
return item;
}
}
return undefined;
}
api.find = find;
function findAll(arr, predicate) {
var found = [];
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
if (predicate.call(null, item)) {
found.push(item);
}
}
return found;
}
api.findAll = findAll;
function reduce(arrOrObj, iterator, initial) {
var isArr = Array.isArray(arrOrObj);
var vals = isArr ? arrOrObj : values(arrOrObj);
var objKeys = isArr ? [] : keys$2(arrOrObj);
var accumulator = initial;
for (var i = 0; i < vals.length; i++) {
accumulator = iterator.call(null, accumulator, vals[i], isArr ? i : objKeys[i]);
}
return accumulator;
}
api.reduce = reduce;
function compact(arr) {
return reject(arr, function (item) { return item === null || item === undefined; });
}
api.compact = compact;
function uniq(arr, identity) {
if (identity === void 0) { identity = function (item) { return item; }; }
var identities = [];
return reduce(arr, function (result, currItem) {
var currIdentity = identity(currItem);
if (contains(identities, currIdentity)) {
return result;
}
else {
identities.push(currIdentity);
return result.concat(currItem);
}
}, []);
}
api.uniq = uniq;
function partial(func) {
var restArgs = [];
for (var _i = 1; _i < arguments.length; _i++) {
restArgs[_i - 1] = arguments[_i];
}
var firstArg = [null];
var allArgs = firstArg.concat(restArgs);
return Function.bind.apply(func, allArgs);
}
api.partial = partial;
function isArray$2(obj) {
return Array.isArray(obj);
}
api.isArray = isArray$2;
function isRegExp(obj) {
return obj instanceof RegExp;
}
api.isRegExp = isRegExp;
function isObject$1(obj) {
return obj instanceof Object;
}
api.isObject = isObject$1;
function every(arr, predicate) {
for (var i = 0; i < arr.length; i++) {
if (!predicate(arr[i], i)) {
return false;
}
}
return true;
}
api.every = every;
function difference(arr, values) {
return reject(arr, function (item) { return contains(values, item); });
}
api.difference = difference;
function some(arr, predicate) {
for (var i = 0; i < arr.length; i++) {
if (predicate(arr[i])) {
return true;
}
}
return false;
}
api.some = some;
function indexOf(arr, value) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] === value) {
return i;
}
}
return -1;
}
api.indexOf = indexOf;
function sortBy$2(arr, orderFunc) {
var result = cloneArr(arr);
result.sort(function (a, b) { return orderFunc(a) - orderFunc(b); });
return result;
}
api.sortBy = sortBy$2;
function zipObject(keys, values) {
if (keys.length !== values.length) {
throw Error("can't zipObject with different number of keys and values!");
}
var result = {};
for (var i = 0; i < keys.length; i++) {
result[keys[i]] = values[i];
}
return result;
}
api.zipObject = zipObject;
/**
* mutates! (and returns) target
*/
function assign(target) {
var sources = [];
for (var _i = 1; _i < arguments.length; _i++) {
sources[_i - 1] = arguments[_i];
}
for (var i = 0; i < sources.length; i++) {
var curSource = sources[i];
var currSourceKeys = keys$2(curSource);
for (var j = 0; j < currSourceKeys.length; j++) {
var currKey = currSourceKeys[j];
target[currKey] = curSource[currKey];
}
}
return target;
}
api.assign = assign;
/**
* mutates! (and returns) target
*/
function assignNoOverwrite(target) {
var sources = [];
for (var _i = 1; _i < arguments.length; _i++) {
sources[_i - 1] = arguments[_i];
}
for (var i = 0; i < sources.length; i++) {
var curSource = sources[i];
var currSourceKeys = keys$2(curSource);
for (var j = 0; j < currSourceKeys.length; j++) {
var currKey = currSourceKeys[j];
if (!has(target, currKey)) {
target[currKey] = curSource[currKey];
}
}
}
return target;
}
api.assignNoOverwrite = assignNoOverwrite;
function defaults() {
var sources = [];
for (var _i = 0; _i < arguments.length; _i++) {
sources[_i] = arguments[_i];
}
return assignNoOverwrite.apply(void 0, __spreadArray([{}], sources));
}
api.defaults = defaults;
function groupBy(arr, groupKeyFunc) {
var result = {};
forEach(arr, function (item) {
var currGroupKey = groupKeyFunc(item);
var currGroupArr = result[currGroupKey];
if (currGroupArr) {
currGroupArr.push(item);
}
else {
result[currGroupKey] = [item];
}
});
return result;
}
api.groupBy = groupBy;
/**
* Merge obj2 into obj1.
* Will overwrite existing properties with the same name
*/
function merge(obj1, obj2) {
var result = cloneObj(obj1);
var keys2 = keys$2(obj2);
for (var i = 0; i < keys2.length; i++) {
var key = keys2[i];
var value = obj2[key];
result[key] = value;
}
return result;
}
api.merge = merge;
function NOOP() { }
api.NOOP = NOOP;
function IDENTITY(item) {
return item;
}
api.IDENTITY = IDENTITY;
/**
* Will return a new packed array with same values.
*/
function packArray(holeyArr) {
var result = [];
for (var i = 0; i < holeyArr.length; i++) {
var orgValue = holeyArr[i];
result.push(orgValue !== undefined ? orgValue : undefined);
}
return result;
}
api.packArray = packArray;
function PRINT_ERROR(msg) {
/* istanbul ignore else - can't override global.console in node.js */
if (console && console.error) {
console.error("Error: " + msg);
}
}
api.PRINT_ERROR = PRINT_ERROR;
function PRINT_WARNING(msg) {
/* istanbul ignore else - can't override global.console in node.js*/
if (console && console.warn) {
// TODO: modify docs accordingly
console.warn("Warning: " + msg);
}
}
api.PRINT_WARNING = PRINT_WARNING;
function isES2015MapSupported() {
return typeof Map === "function";
}
api.isES2015MapSupported = isES2015MapSupported;
function peek(arr) {
return arr[arr.length - 1];
}
api.peek = peek;
/* istanbul ignore next - for performance tracing*/
function timer(func) {
var start = new Date().getTime();
var val = func();
var end = new Date().getTime();
var total = end - start;
return { time: total, value: val };
}
api.timer = timer;
// based on: https://github.com/petkaantonov/bluebird/blob/b97c0d2d487e8c5076e8bd897e0dcd4622d31846/src/util.js#L201-L216
function toFastProperties(toBecomeFast) {
function FakeConstructor() { }
// If our object is used as a constructor it would receive
FakeConstructor.prototype = toBecomeFast;
var fakeInstance = new FakeConstructor();
function fakeAccess() {
return typeof fakeInstance.bar;
}
// help V8 understand this is a "real" prototype by actually using
// the fake instance.
fakeAccess();
fakeAccess();
return toBecomeFast;
}
api.toFastProperties = toFastProperties;
function upperFirst(str) {
if (!str) {
return str;
}
var firstChar = getCharacterFromCodePointAt(str, 0);
return firstChar.toUpperCase() + str.substring(firstChar.length);
}
api.upperFirst = upperFirst;
var surrogatePairPattern = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;
function getCharacterFromCodePointAt(str, idx) {
var surrogatePairCandidate = str.substring(idx, idx + 1);
return surrogatePairPattern.test(surrogatePairCandidate)
? surrogatePairCandidate
: str[idx];
}
var follow = {};
var rest = {};
var gast_public = {};
var tokens_public = {};
var lexer_public = {};
var lexer = {};
var regexpToAst = {exports: {}};
(function (module) {
(function(root, factory) {
// istanbul ignore next
if (module.exports) {
module.exports = factory();
} else {
// istanbul ignore next
root.regexpToAst = factory();
}
})(
typeof self !== "undefined"
? // istanbul ignore next
self
: commonjsGlobal,
function() {
// references
// https://hackernoon.com/the-madness-of-parsing-real-world-javascript-regexps-d9ee336df983
// https://www.ecma-international.org/ecma-262/8.0/index.html#prod-Pattern
function RegExpParser() {}
RegExpParser.prototype.saveState = function() {
return {
idx: this.idx,
input: this.input,
groupIdx: this.groupIdx
}
};
RegExpParser.prototype.restoreState = function(newState) {
this.idx = newState.idx;
this.input = newState.input;
this.groupIdx = newState.groupIdx;
};
RegExpParser.prototype.pattern = function(input) {
// parser state
this.idx = 0;
this.input = input;
this.groupIdx = 0;
this.consumeChar("/");
var value = this.disjunction();
this.consumeChar("/");
var flags = {
type: "Flags",
loc: { begin: this.idx, end: input.length },
global: false,
ignoreCase: false,
multiLine: false,
unicode: false,
sticky: false
};
while (this.isRegExpFlag()) {
switch (this.popChar()) {
case "g":
addFlag(flags, "global");
break
case "i":
addFlag(flags, "ignoreCase");
break
case "m":
addFlag(flags, "multiLine");
break
case "u":
addFlag(flags, "unicode");
break
case "y":
addFlag(flags, "sticky");
break
}
}
if (this.idx !== this.input.length) {
throw Error(
"Redundant input: " + this.input.substring(this.idx)
)
}
return {
type: "Pattern",
flags: flags,
value: value,
loc: this.loc(0)
}
};
RegExpParser.prototype.disjunction = function() {
var alts = [];
var begin = this.idx;
alts.push(this.alternative());
while (this.peekChar() === "|") {
this.consumeChar("|");
alts.push(this.alternative());
}
return { type: "Disjunction", value: alts, loc: this.loc(begin) }
};
RegExpParser.prototype.alternative = function() {
var terms = [];
var begin = this.idx;
while (this.isTerm()) {
terms.push(this.term());
}
return { type: "Alternative", value: terms, loc: this.loc(begin) }
};
RegExpParser.prototype.term = function() {
if (this.isAssertion()) {
return this.assertion()
} else {
return this.atom()
}
};
RegExpParser.prototype.assertion = function() {
var begin = this.idx;
switch (this.popChar()) {
case "^":
return {
type: "StartAnchor",
loc: this.loc(begin)
}
case "$":
return { type: "EndAnchor", loc: this.loc(begin) }
// '\b' or '\B'
case "\\":
switch (this.popChar()) {
case "b":
return {
type: "WordBoundary",
loc: this.loc(begin)
}
case "B":
return {
type: "NonWordBoundary",
loc: this.loc(begin)
}
}
// istanbul ignore next
throw Error("Invalid Assertion Escape")
// '(?=' or '(?!'
case "(":
this.consumeChar("?");
var type;
switch (this.popChar()) {
case "=":
type = "Lookahead";
break
case "!":
type = "NegativeLookahead";
break
}
ASSERT_EXISTS(type);
var disjunction = this.disjunction();
this.consumeChar(")");
return {
type: type,
value: disjunction,
loc: this.loc(begin)
}
}
// istanbul ignore next
ASSERT_NEVER_REACH_HERE();
};
RegExpParser.prototype.quantifier = function(isBacktracking) {
var range;
var begin = this.idx;
switch (this.popChar()) {
case "*":
range = {
atLeast: 0,
atMost: Infinity
};
break
case "+":
range = {
atLeast: 1,
atMost: Infinity
};
break
case "?":
range = {
atLeast: 0,
atMost: 1
};
break
case "{":
var atLeast = this.integerIncludingZero();
switch (this.popChar()) {
case "}":
range = {
atLeast: atLeast,
atMost: atLeast
};
break
case ",":
var atMost;
if (this.isDigit()) {
atMost = this.integerIncludingZero();
range = {
atLeast: atLeast,
atMost: atMost
};
} else {
range = {
atLeast: atLeast,
atMost: Infinity
};
}
this.consumeChar("}");
break
}
// throwing exceptions from "ASSERT_EXISTS" during backtracking
// causes severe performance degradations
if (isBacktracking === true && range === undefined) {
return undefined
}
ASSERT_EXISTS(range);
break
}
// throwing exceptions from "ASSERT_EXISTS" during backtracking
// causes severe performance degradations
if (isBacktracking === true && range === undefined) {
return undefined
}
ASSERT_EXISTS(range);
if (this.peekChar(0) === "?") {
this.consumeChar("?");
range.greedy = false;
} else {
range.greedy = true;
}
range.type = "Quantifier";
range.loc = this.loc(begin);
return range
};
RegExpParser.prototype.atom = function() {
var atom;
var begin = this.idx;
switch (this.peekChar()) {
case ".":
atom = this.dotAll();
break
case "\\":
atom = this.atomEscape();
break
case "[":
atom = this.characterClass();
break
case "(":
atom = this.group();
break
}
if (atom === undefined && this.isPatternCharacter()) {
atom = this.patternCharacter();
}
ASSERT_EXISTS(atom);
atom.loc = this.loc(begin);
if (this.isQuantifier()) {
atom.quantifier = this.quantifier();
}
return atom
};
RegExpParser.prototype.dotAll = function() {
this.consumeChar(".");
return {
type: "Set",
complement: true,
value: [cc("\n"), cc("\r"), cc("\u2028"), cc("\u2029")]
}
};
RegExpParser.prototype.atomEscape = function() {
this.consumeChar("\\");
switch (this.peekChar()) {
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
return this.decimalEscapeAtom()
case "d":
case "D":
case "s":
case "S":
case "w":
case "W":
return this.characterClassEscape()
case "f":
case "n":
case "r":
case "t":
case "v":
return this.controlEscapeAtom()
case "c":
return this.controlLetterEscapeAtom()
case "0":
return this.nulCharacterAtom()
case "x":
return this.hexEscapeSequenceAtom()
case "u":
return this.regExpUnicodeEscapeSequenceAtom()
default:
return this.identityEscapeAtom()
}
};
RegExpParser.prototype.decimalEscapeAtom = function() {
var value = this.positiveInteger();
return { type: "GroupBackReference", value: value }
};
RegExpParser.prototype.characterClassEscape = function() {
var set;
var complement = false;
switch (this.popChar()) {
case "d":
set = digitsCharCodes;
break
case "D":
set = digitsCharCodes;
complement = true;
break
case "s":
set = whitespaceCodes;
break
case "S":
set = whitespaceCodes;
complement = true;
break
case "w":
set = wordCharCodes;
break
case "W":
set = wordCharCodes;
complement = true;
break
}
ASSERT_EXISTS(set);
return { type: "Set", value: set, complement: complement }
};
RegExpParser.prototype.controlEscapeAtom = function() {
var escapeCode;
switch (this.popChar()) {
case "f":
escapeCode = cc("\f");
break
case "n":
escapeCode = cc("\n");
break
case "r":
escapeCode = cc("\r");
break
case "t":
escapeCode = cc("\t");
break
case "v":
escapeCode = cc("\v");
break
}
ASSERT_EXISTS(escapeCode);
return { type: "Character", value: escapeCode }
};
RegExpParser.prototype.controlLetterEscapeAtom = function() {
this.consumeChar("c");
var letter = this.popChar();
if (/[a-zA-Z]/.test(letter) === false) {
throw Error("Invalid ")
}
var letterCode = letter.toUpperCase().charCodeAt(0) - 64;
return { type: "Character", value: letterCode }
};
RegExpParser.prototype.nulCharacterAtom = function() {
// TODO implement '[lookahead ∉ DecimalDigit]'
// TODO: for the deprecated octal escape sequence
this.consumeChar("0");
return { type: "Character", value: cc("\0") }
};
RegExpParser.prototype.hexEscapeSequenceAtom = function() {
this.consumeChar("x");
return this.parseHexDigits(2)
};
RegExpParser.prototype.regExpUnicodeEscapeSequenceAtom = function() {
this.consumeChar("u");
return this.parseHexDigits(4)
};
RegExpParser.prototype.identityEscapeAtom = function() {
// TODO: implement "SourceCharacter but not UnicodeIDContinue"
// // http://unicode.org/reports/tr31/#Specific_Character_Adjustments
var escapedChar = this.popChar();
return { type: "Character", value: cc(escapedChar) }
};
RegExpParser.prototype.classPatternCharacterAtom = function() {
switch (this.peekChar()) {
// istanbul ignore next
case "\n":
// istanbul ignore next
case "\r":
// istanbul ignore next
case "\u2028":
// istanbul ignore next
case "\u2029":
// istanbul ignore next
case "\\":
// istanbul ignore next
case "]":
throw Error("TBD")
default:
var nextChar = this.popChar();
return { type: "Character", value: cc(nextChar) }
}
};
RegExpParser.prototype.characterClass = function() {
var set = [];
var complement = false;
this.consumeChar("[");
if (this.peekChar(0) === "^") {
this.consumeChar("^");
complement = true;
}
while (this.isClassAtom()) {
var from = this.classAtom();
var isFromSingleChar = from.type === "Character";
if (isFromSingleChar && this.isRangeDash()) {
this.consumeChar("-");
var to = this.classAtom();
var isToSingleChar = to.type === "Character";
// a range can only be used when both sides are single characters
if (isToSingleChar) {
if (to.value < from.value) {
throw Error("Range out of order in character class")
}
set.push({ from: from.value, to: to.value });
} else {
// literal dash
insertToSet(from.value, set);
set.push(cc("-"));
insertToSet(to.value, set);
}
} else {
insertToSet(from.value, set);
}
}
this.consumeChar("]");
return { type: "Set", complement: complement, value: set }
};
RegExpParser.prototype.classAtom = function() {
switch (this.peekChar()) {
// istanbul ignore next
case "]":
// istanbul ignore next
case "\n":
// istanbul ignore next
case "\r":
// istanbul ignore next
case "\u2028":
// istanbul ignore next
case "\u2029":
throw Error("TBD")
case "\\":
return this.classEscape()
default:
return this.classPatternCharacterAtom()
}
};
RegExpParser.prototype.classEscape = function() {
this.consumeChar("\\");
switch (this.peekChar()) {
// Matches a backspace.
// (Not to be confused with \b word boundary outside characterClass)
case "b":
this.consumeChar("b");
return { type: "Character", value: cc("\u0008") }
case "d":
case "D":
case "s":
case "S":
case "w":
case "W":
return this.characterClassEscape()
case "f":
case "n":
case "r":
case "t":
case "v":
return this.controlEscapeAtom()
case "c":
return this.controlLetterEscapeAtom()
case "0":
return this.nulCharacterAtom()
case "x":
return this.hexEscapeSequenceAtom()
case "u":
return this.regExpUnicodeEscapeSequenceAtom()
default:
return this.identityEscapeAtom()
}
};
RegExpParser.prototype.group = function() {
var capturing = true;
this.consumeChar("(");
switch (this.peekChar(0)) {
case "?":
this.consumeChar("?");
this.consumeChar(":");
capturing = false;
break
default:
this.groupIdx++;
break
}
var value = this.disjunction();
this.consumeChar(")");
var groupAst = {
type: "Group",
capturing: capturing,
value: value
};
if (capturing) {
groupAst.idx = this.groupIdx;
}
return groupAst
};
RegExpParser.prototype.positiveInteger = function() {
var number = this.popChar();
// istanbul ignore next - can't ever get here due to previous lookahead checks
// still implementing this error checking in case this ever changes.
if (decimalPatternNoZero.test(number) === false) {
throw Error("Expecting a positive integer")
}
while (decimalPattern.test(this.peekChar(0))) {
number += this.popChar();
}
return parseInt(number, 10)
};
RegExpParser.prototype.integerIncludingZero = function() {
var number = this.popChar();
if (decimalPattern.test(number) === false) {
throw Error("Expecting an integer")
}
while (decimalPattern.test(this.peekChar(0))) {
number += this.popChar();
}
return parseInt(number, 10)
};
RegExpParser.prototype.patternCharacter = function() {
var nextChar = this.popChar();
switch (nextChar) {
// istanbul ignore next
case "\n":
// istanbul ignore next
case "\r":
// istanbul ignore next
case "\u2028":
// istanbul ignore next
case "\u2029":
// istanbul ignore next
case "^":
// istanbul ignore next
case "$":
// istanbul ignore next
case "\\":
// istanbul ignore next
case ".":
// istanbul ignore next
case "*":
// istanbul ignore next
case "+":
// istanbul ignore next
case "?":
// istanbul ignore next
case "(":
// istanbul ignore next
case ")":
// istanbul ignore next
case "[":
// istanbul ignore next
case "|":
// istanbul ignore next
throw Error("TBD")
default:
return { type: "Character", value: cc(nextChar) }
}
};
RegExpParser.prototype.isRegExpFlag = function() {
switch (this.peekChar(0)) {
case "g":
case "i":
case "m":
case "u":
case "y":
return true
default:
return false
}
};
RegExpParser.prototype.isRangeDash = function() {
return this.peekChar() === "-" && this.isClassAtom(1)
};
RegExpParser.prototype.isDigit = function() {
return decimalPattern.test(this.peekChar(0))
};
RegExpParser.prototype.isClassAtom = function(howMuch) {
if (howMuch === undefined) {
howMuch = 0;
}
switch (this.peekChar(howMuch)) {
case "]":
case "\n":
case "\r":
case "\u2028":
case "\u2029":
return false
default:
return true
}
};
RegExpParser.prototype.isTerm = function() {
return this.isAtom() || this.isAssertion()
};
RegExpParser.prototype.isAtom = function() {
if (this.isPatternCharacter()) {
return true
}
switch (this.peekChar(0)) {
case ".":
case "\\": // atomEscape
case "[": // characterClass
// TODO: isAtom must be called before isAssertion - disambiguate
case "(": // group
return true
default:
return false
}
};
RegExpParser.prototype.isAssertion = function() {
switch (this.peekChar(0)) {
case "^":
case "$":
return true
// '\b' or '\B'
case "\\":
switch (this.peekChar(1)) {
case "b":
case "B":
return true
default:
return false
}
// '(?=' or '(?!'
case "(":
return (
this.peekChar(1) === "?" &&
(this.peekChar(2) === "=" || this.peekChar(2) === "!")
)
default:
return false
}
};
RegExpParser.prototype.isQuantifier = function() {
var prevState = this.saveState();
try {
return this.quantifier(true) !== undefined
} catch (e) {
return false
} finally {
this.restoreState(prevState);
}
};
RegExpParser.prototype.isPatternCharacter = function() {
switch (this.peekChar()) {
case "^":
case "$":
case "\\":
case ".":
case "*":
case "+":
case "?":
case "(":
case ")":
case "[":
case "|":
case "/":
case "\n":
case "\r":
case "\u2028":
case "\u2029":
return false
default:
return true
}
};
RegExpParser.prototype.parseHexDigits = function(howMany) {
var hexString = "";
for (var i = 0; i < howMany; i++) {
var hexChar = this.popChar();
if (hexDigitPattern.test(hexChar) === false) {
throw Error("Expecting a HexDecimal digits")
}
hexString += hexChar;
}
var charCode = parseInt(hexString, 16);
return { type: "Character", value: charCode }
};
RegExpParser.prototype.peekChar = function(howMuch) {
if (howMuch === undefined) {
howMuch = 0;
}
return this.input[this.idx + howMuch]
};
RegExpParser.prototype.popChar = function() {
var nextChar = this.peekChar(0);
this.consumeChar();
return nextChar
};
RegExpParser.prototype.consumeChar = function(char) {
if (char !== undefined && this.input[this.idx] !== char) {
throw Error(
"Expected: '" +
char +
"' but found: '" +
this.input[this.idx] +
"' at offset: " +
this.idx
)
}
if (this.idx >= this.input.length) {
throw Error("Unexpected end of input")
}
this.idx++;
};
RegExpParser.prototype.loc = function(begin) {
return { begin: begin, end: this.idx }
};
// consts and utilities
var hexDigitPattern = /[0-9a-fA-F]/;
var decimalPattern = /[0-9]/;
var decimalPatternNoZero = /[1-9]/;
function cc(char) {
return char.charCodeAt(0)
}
function insertToSet(item, set) {
if (item.length !== undefined) {
item.forEach(function(subItem) {
set.push(subItem);
});
} else {
set.push(item);
}
}
function addFlag(flagObj, flagKey) {
if (flagObj[flagKey] === true) {
throw "duplicate flag " + flagKey
}
flagObj[flagKey] = true;
}
function ASSERT_EXISTS(obj) {
// istanbul ignore next
if (obj === undefined) {
throw Error("Internal Error - Should never get here!")
}
}
// istanbul ignore next
function ASSERT_NEVER_REACH_HERE() {
throw Error("Internal Error - Should never get here!")
}
var i;
var digitsCharCodes = [];
for (i = cc("0"); i <= cc("9"); i++) {
digitsCharCodes.push(i);
}
var wordCharCodes = [cc("_")].concat(digitsCharCodes);
for (i = cc("a"); i <= cc("z"); i++) {
wordCharCodes.push(i);
}
for (i = cc("A"); i <= cc("Z"); i++) {
wordCharCodes.push(i);
}
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#character-classes
var whitespaceCodes = [
cc(" "),
cc("\f"),
cc("\n"),
cc("\r"),
cc("\t"),
cc("\v"),
cc("\t"),
cc("\u00a0"),
cc("\u1680"),
cc("\u2000"),
cc("\u2001"),
cc("\u2002"),
cc("\u2003"),
cc("\u2004"),
cc("\u2005"),
cc("\u2006"),
cc("\u2007"),
cc("\u2008"),
cc("\u2009"),
cc("\u200a"),
cc("\u2028"),
cc("\u2029"),
cc("\u202f"),
cc("\u205f"),
cc("\u3000"),
cc("\ufeff")
];
function BaseRegExpVisitor() {}
BaseRegExpVisitor.prototype.visitChildren = function(node) {
for (var key in node) {
var child = node[key];
/* istanbul ignore else */
if (node.hasOwnProperty(key)) {
if (child.type !== undefined) {
this.visit(child);
} else if (Array.isArray(child)) {
child.forEach(function(subChild) {
this.visit(subChild);
}, this);
}
}
}
};
BaseRegExpVisitor.prototype.visit = function(node) {
switch (node.type) {
case "Pattern":
this.visitPattern(node);
break
case "Flags":
this.visitFlags(node);
break
case "Disjunction":
this.visitDisjunction(node);
break
case "Alternative":
this.visitAlternative(node);
break
case "StartAnchor":
this.visitStartAnchor(node);
break
case "EndAnchor":
this.visitEndAnchor(node);
break
case "WordBoundary":
this.visitWordBoundary(node);
break
case "NonWordBoundary":
this.visitNonWordBoundary(node);
break
case "Lookahead":
this.visitLookahead(node);
break
case "NegativeLookahead":
this.visitNegativeLookahead(node);
break
case "Character":
this.visitCharacter(node);
break
case "Set":
this.visitSet(node);
break
case "Group":
this.visitGroup(node);
break
case "GroupBackReference":
this.visitGroupBackReference(node);
break
case "Quantifier":
this.visitQuantifier(node);
break
}
this.visitChildren(node);
};
BaseRegExpVisitor.prototype.visitPattern = function(node) {};
BaseRegExpVisitor.prototype.visitFlags = function(node) {};
BaseRegExpVisitor.prototype.visitDisjunction = function(node) {};
BaseRegExpVisitor.prototype.visitAlternative = function(node) {};
// Assertion
BaseRegExpVisitor.prototype.visitStartAnchor = function(node) {};
BaseRegExpVisitor.prototype.visitEndAnchor = function(node) {};
BaseRegExpVisitor.prototype.visitWordBoundary = function(node) {};
BaseRegExpVisitor.prototype.visitNonWordBoundary = function(node) {};
BaseRegExpVisitor.prototype.visitLookahead = function(node) {};
BaseRegExpVisitor.prototype.visitNegativeLookahead = function(node) {};
// atoms
BaseRegExpVisitor.prototype.visitCharacter = function(node) {};
BaseRegExpVisitor.prototype.visitSet = function(node) {};
BaseRegExpVisitor.prototype.visitGroup = function(node) {};
BaseRegExpVisitor.prototype.visitGroupBackReference = function(node) {};
BaseRegExpVisitor.prototype.visitQuantifier = function(node) {};
return {
RegExpParser: RegExpParser,
BaseRegExpVisitor: BaseRegExpVisitor,
VERSION: "0.5.0"
}
}
);
}(regexpToAst));
var reg_exp = {};
var reg_exp_parser = {};
Object.defineProperty(reg_exp_parser, "__esModule", { value: true });
reg_exp_parser.clearRegExpParserCache = reg_exp_parser.getRegExpAst = void 0;
var regexp_to_ast_1 = regexpToAst.exports;
var regExpAstCache = {};
var regExpParser = new regexp_to_ast_1.RegExpParser();
function getRegExpAst(regExp) {
var regExpStr = regExp.toString();
if (regExpAstCache.hasOwnProperty(regExpStr)) {
return regExpAstCache[regExpStr];
}
else {
var regExpAst = regExpParser.pattern(regExpStr);
regExpAstCache[regExpStr] = regExpAst;
return regExpAst;
}
}
reg_exp_parser.getRegExpAst = getRegExpAst;
function clearRegExpParserCache() {
regExpAstCache = {};
}
reg_exp_parser.clearRegExpParserCache = clearRegExpParserCache;
(function (exports) {
var __extends = (commonjsGlobal && commonjsGlobal.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);