UNPKG

regexp-coder

Version:

A Javascript/Typescript RegExp Coder

472 lines 14.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RegExpCoder = void 0; const regExpSpec_1 = require("./regExpSpec"); const Or = '|'; const Not = '^'; /** * Regular Expression Coder * * @see [Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) */ class RegExpCoder { constructor() { // variables this.variables = new Map(); // the final regular expression this.result = ''; // if enable match whole this.isMatchWhole = false; } /** * Create an instance of RegExpCoder */ static new() { return new RegExpCoder(); } /** * Get the last options if there is * @param exp the expression */ getParamOptions(...exp) { if (!this) { return undefined; } if (!exp) { return undefined; } const lastParam = exp[exp.length - 1]; if (!lastParam) { return undefined; } if (typeof lastParam === 'string' || lastParam instanceof RegExpCoder || lastParam instanceof RegExp) { return undefined; } if (lastParam.expression) { return undefined; } return lastParam; } /** * Apply options to a specific expression * @param exp the expression * @param options the options */ applyOptions(exp, options) { if (!this) { return ''; } let source = exp; // case: set if (options && options.negatedSet) { // case: negatedSet source = `[${Not}${source}]`; } else if (options && options.set) { // case: set source = `[${source}]`; } // qualifier if (options && options.qualifier) { // groupQualifiedItem's defalt value is true, as qualifier operations are in high priority if (options.groupQualifiedItem === undefined || options.groupQualifiedItem) { source = `(${options.notRememberQualifiedItem ? '?:' : ''}${source})`; } source = `${source}${options.qualifier}`; } // case: group if (options && options.group) { if (options.notRemember) { source = `(?:${source})`; } else { const name = options.name || ''; source = `(${name.length > 0 ? `?<${name}>:` : ''}${source})`; } } return source; } /** * Get the source of an expression or a variable * @param exp the expression */ getSource(exp) { if (!exp) { return ''; } // case: string if (typeof exp === 'string') { if (this.variables.has(exp)) { // case: variable return this.variables.get(exp); } return exp; } // case: RegExp if (exp instanceof RegExp) { return exp.source; } // case: RegExpCoder if (exp instanceof RegExpCoder) { return exp.source; } // case: RegExpOptions if (exp.expression) { return this.applyOptions(this.getSource(exp.expression), exp); } // case: RegExpOptions without expression, // return empty, the option will be used by outside return ''; } /** * create an expression * @param exp the expression */ build(...exp) { let source = ''; if (!exp) { return source; } const totalOptions = this.getParamOptions(...exp); exp.forEach((item, index) => { let itemSource = this.getSource(item); if (itemSource) { if (totalOptions && totalOptions.groupItem) { itemSource = `(${itemSource})`; } let or = ''; if (index > 0 && totalOptions && totalOptions.or) { or = Or; } source += `${or}${itemSource}`; } }); return this.applyOptions(source, totalOptions); } /** * Encode a raw string to a regular expression string. * Following special characters will be encoded: `^\.()[]?+*|$` * * For set case, encoded characters: `^\-]` * Rules: * - escape `^` only when it is the first char * - escape `-` only when it is not the first char and not the last char * - escaped `\]` always * @param raw the raw string * @param forSet if for set `[]` operation */ static encodeRegExp(raw, forSet = false) { if (!raw) { return raw; } let ret = ''; for (let index = 0; index < raw.length; index += 1) { const char = raw.charAt(index); if (forSet) { let newChar = RegExpCoder.escapedSetChars.get(char); if (char === '^' && index !== 0) { newChar = undefined; } else if (char === '-' && (index === 0 || index === raw.length - 1)) { newChar = undefined; } ret += newChar || char; } else { const newChar = RegExpCoder.escapedChars.get(char); ret += newChar || char; } } return ret; } /** * `xy` * Define a variable * @param name the variable name * @param exp the variable expression */ define(name, ...exp) { this.variables.set(name, this.build(...exp, this.getParamOptions(...exp))); return this; } /** * `(xy)` * Define a variable for group operation * @param name the variable name * @param exp the variable expression */ defineGroup(name, ...exp) { this.variables.set(name, this.build(...exp, Object.assign({ group: true }, this.getParamOptions(...exp)))); return this; } /** * `x|y` * Define a variable for or operation * @param name the variable name * @param exp the variable expression */ defineOr(name, ...exp) { this.variables.set(name, this.build(...exp, Object.assign({ or: true }, this.getParamOptions(...exp)))); return this; } /** * `[xy]` * Define a variable for set * @param name the variable name * @param exp the variable expression */ defineSet(name, ...exp) { this.variables.set(name, this.build(...exp, Object.assign({ set: true }, this.getParamOptions(...exp)))); return this; } /** * `[^xy]` * Define a variable for negated set * @param name the variable name * @param exp the variable expression */ defineNegatedSet(name, ...exp) { this.variables.set(name, this.build(...exp, Object.assign({ negatedSet: true }, this.getParamOptions(...exp)))); return this; } /** * `x(?=y)` * Define a lookahead variable * @param name the variable name * @param exp the variable expression * @param exp2 the variable expression * @param options the build options */ defineLookahead(name, exp, exp2, options) { this.variables.set(name, this.build(`${this.getSource(exp)}(?=${this.getSource(exp2)})`, options)); return this; } /** * `x(?!y)` * Define a negated lookahead variable * @param name the variable name * @param exp the variable expression * @param exp2 the variable expression * @param options the build options */ defineNegatedLookahead(name, exp, exp2, options) { this.variables.set(name, this.build(`${this.getSource(exp)}(?!${this.getSource(exp2)})`, options)); return this; } /** * `(?<=y)x` * Define a lookbehind variable * @param name the variable name * @param exp the variable expression * @param exp2 the variable expression * @param options the build options */ defineLookbehind(name, exp, exp2, options) { this.variables.set(name, this.build(`(?<=${this.getSource(exp2)})${this.getSource(exp)}`, options)); return this; } /** * `(?<!y)x` * Define a negated lookbehind variable * @param name the variable name * @param exp the variable expression * @param exp2 the variable expression * @param options the build options */ defineNegatedLookbehind(name, exp, exp2, options) { this.variables.set(name, this.build(`(?<!${this.getSource(exp2)})${this.getSource(exp)}`, options)); return this; } /** * Stash the current expression as a variable. * @param name the variable name */ stash(name) { this.variables.set(name, this.result); this.result = ''; return this; } /** * `xy` * Append an expression * @param exp the expression */ join(...exp) { const source = this.build(...exp); this.result += source; return this; } /** * `(xy)` * Append an expression for or operation * @param exp the expression */ group(...exp) { const source = this.build(...exp, Object.assign({ group: true }, this.getParamOptions(...exp))); this.result += source; return this; } /** * `x|y` * Append an expression for or operation * @param exp the expression */ or(...exp) { const source = this.build(...exp, Object.assign({ or: true }, this.getParamOptions(...exp))); this.result += source; return this; } /** * `[xy]` * Append an expression for set * @param exp the expression */ set(...exp) { const source = this.build(...exp, Object.assign({ set: true }, this.getParamOptions(...exp))); this.result += source; return this; } /** * `[^xy]` * Append an expression for negated set * @param exp the expression */ negatedSet(...exp) { const source = this.build(...exp, Object.assign({ negatedSet: true }, this.getParamOptions(...exp))); this.result += source; return this; } /** * `x(?=y)` * Append a lookahead expression * @param exp the variable expression * @param exp2 the variable expression * @param options the build options */ lookahead(exp, exp2, options) { const source = this.build(`${this.getSource(exp)}(?=${this.getSource(exp2)})`, options); this.result += source; return this; } /** * `x(?!y)` * Append a negated lookahead expression * @param exp the variable expression * @param exp2 the variable expression * @param options the build options */ negatedLookahead(exp, exp2, options) { const source = this.build(`${this.getSource(exp)}(?!${this.getSource(exp2)})`, options); this.result += source; return this; } /** * `(?<=y)x` * Append a lookbehind expression * @param exp the variable expression * @param exp2 the variable expression * @param options the build options */ lookbehind(exp, exp2, options) { const source = this.build(`(?<=${this.getSource(exp2)})${this.getSource(exp)}`, options); this.result += source; return this; } /** * `(?<!y)x` * Append a negated lookbehind expression. * @param exp the variable expression * @param exp2 the variable expression * @param options the build options */ negatedLookbehind(exp, exp2, options) { const source = this.build(`(?<!${this.getSource(exp2)})${this.getSource(exp)}`, options); this.result += source; return this; } /** * `(?<name>:`.. * Begin a group * @param name the group name */ beginGroup(name) { this.result += `(${name ? `?<${name}>:` : ''}`; return this; } /** * `)`.. * End a group * @param name the group name */ endGroup(name) { if (name) { this.result += ')'; } this.result += ')'; return this; } /** * Enable match whole */ enableMatchWhole() { this.isMatchWhole = true; return this; } /** * Clear the content * @param keepDefinitions if keep the definitions */ clear(keepDefinitions = false) { this.result = ''; this.isMatchWhole = false; if (!keepDefinitions) { this.variables = new Map(); } return this; } /** * Get the build result * @param flags flags */ toRegExp(flags) { let exp = this.result; if (this.isMatchWhole) { exp = `${regExpSpec_1.RegExpSpec.begin}${exp}${regExpSpec_1.RegExpSpec.end}`; } return new RegExp(exp, flags); } /** * Get source */ get source() { return this.result; } } exports.RegExpCoder = RegExpCoder; /** * Chars that need escaped */ RegExpCoder.escapedChars = new Map([ ['^', '\\^'], ['\\', '\\\\'], ['.', '\\.'], ['(', '\\('], [')', '\\)'], ['[', '\\['], [']', '\\]'], ['?', '\\?'], ['+', '\\+'], ['*', '\\*'], ['|', '\\|'], ['$', '\\$'], ]); /** * Chars that need escaped in a set expression. */ RegExpCoder.escapedSetChars = new Map([ ['^', '\\^'], ['\\', '\\\\'], [']', '\\]'], ['-', '\\-'], ]); //# sourceMappingURL=regExpCoder.js.map