|
|
/*! * regjsgen 0.5.2 * Copyright 2014-2020 Benjamin Tan <https://ofcr.se/>
* Available under the MIT license <https://github.com/bnjmnt4n/regjsgen/blob/master/LICENSE-MIT.txt>
*/ ;(function() { 'use strict';
// Used to determine if values are of the language type `Object`.
var objectTypes = { 'function': true, 'object': true };
// Used as a reference to the global object.
var root = (objectTypes[typeof window] && window) || this;
// Detect free variable `exports`.
var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
// Detect free variable `module`.
var hasFreeModule = objectTypes[typeof module] && module && !module.nodeType;
// Detect free variable `global` from Node.js or Browserified code and use it as `root`.
var freeGlobal = freeExports && hasFreeModule && typeof global == 'object' && global; if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) { root = freeGlobal; }
// Used to check objects for own properties.
var hasOwnProperty = Object.prototype.hasOwnProperty;
/*--------------------------------------------------------------------------*/
// Generates a string based on the given code point.
// Based on https://mths.be/fromcodepoint by @mathias.
function fromCodePoint() { var codePoint = Number(arguments[0]);
if ( !isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
codePoint < 0 || // not a valid Unicode code point
codePoint > 0x10FFFF || // not a valid Unicode code point
Math.floor(codePoint) != codePoint // not an integer
) { throw RangeError('Invalid code point: ' + codePoint); }
if (codePoint <= 0xFFFF) { // BMP code point
return String.fromCharCode(codePoint); } else { // Astral code point; split in surrogate halves
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
codePoint -= 0x10000; var highSurrogate = (codePoint >> 10) + 0xD800; var lowSurrogate = (codePoint % 0x400) + 0xDC00; return String.fromCharCode(highSurrogate, lowSurrogate); } }
/*--------------------------------------------------------------------------*/
// Ensures that nodes have the correct types.
var assertTypeRegexMap = {}; function assertType(type, expected) { if (expected.indexOf('|') == -1) { if (type == expected) { return; }
throw Error('Invalid node type: ' + type + '; expected type: ' + expected); }
expected = hasOwnProperty.call(assertTypeRegexMap, expected) ? assertTypeRegexMap[expected] : (assertTypeRegexMap[expected] = RegExp('^(?:' + expected + ')$'));
if (expected.test(type)) { return; }
throw Error('Invalid node type: ' + type + '; expected types: ' + expected); }
/*--------------------------------------------------------------------------*/
// Generates a regular expression string based on an AST.
function generate(node) { var type = node.type;
if (hasOwnProperty.call(generators, type)) { return generators[type](node); }
throw Error('Invalid node type: ' + type); }
// Constructs a string by concatentating the output of each term.
function generateSequence(generator, terms) { var i = -1, length = terms.length, result = '', term;
while (++i < length) { term = terms[i];
// Ensure that `\0` null escapes followed by number symbols are not
// treated as backreferences.
if ( i + 1 < length && terms[i].type == 'value' && terms[i].kind == 'null' && terms[i + 1].type == 'value' && terms[i + 1].kind == 'symbol' && terms[i + 1].codePoint >= 48 && terms[i + 1].codePoint <= 57 ) { result += '\\000'; continue; }
result += generator(term); }
return result; }
/*--------------------------------------------------------------------------*/
function generateAlternative(node) { assertType(node.type, 'alternative');
return generateSequence(generateTerm, node.body); }
function generateAnchor(node) { assertType(node.type, 'anchor');
switch (node.kind) { case 'start': return '^'; case 'end': return '$'; case 'boundary': return '\\b'; case 'not-boundary': return '\\B'; default: throw Error('Invalid assertion'); } }
function generateAtom(node) { assertType(node.type, 'anchor|characterClass|characterClassEscape|dot|group|reference|value');
return generate(node); }
function generateCharacterClass(node) { assertType(node.type, 'characterClass');
return '[' + (node.negative ? '^' : '') + generateSequence(generateClassAtom, node.body) + ']'; }
function generateCharacterClassEscape(node) { assertType(node.type, 'characterClassEscape');
return '\\' + node.value; }
function generateCharacterClassRange(node) { assertType(node.type, 'characterClassRange');
var min = node.min, max = node.max;
if (min.type == 'characterClassRange' || max.type == 'characterClassRange') { throw Error('Invalid character class range'); }
return generateClassAtom(min) + '-' + generateClassAtom(max); }
function generateClassAtom(node) { assertType(node.type, 'anchor|characterClassEscape|characterClassRange|dot|value');
return generate(node); }
function generateDisjunction(node) { assertType(node.type, 'disjunction');
var body = node.body, i = -1, length = body.length, result = '';
while (++i < length) { if (i != 0) { result += '|'; } result += generate(body[i]); }
return result; }
function generateDot(node) { assertType(node.type, 'dot');
return '.'; }
function generateGroup(node) { assertType(node.type, 'group');
var result = '';
switch (node.behavior) { case 'normal': if (node.name) { result += '?<' + generateIdentifier(node.name) + '>'; } break; case 'ignore': result += '?:'; break; case 'lookahead': result += '?='; break; case 'negativeLookahead': result += '?!'; break; case 'lookbehind': result += '?<='; break; case 'negativeLookbehind': result += '?<!'; break; default: throw Error('Invalid behaviour: ' + node.behaviour); }
result += generateSequence(generate, node.body);
return '(' + result + ')'; }
function generateIdentifier(node) { assertType(node.type, 'identifier');
return node.value; }
function generateQuantifier(node) { assertType(node.type, 'quantifier');
var quantifier = '', min = node.min, max = node.max;
if (max == null) { if (min == 0) { quantifier = '*'; } else if (min == 1) { quantifier = '+'; } else { quantifier = '{' + min + ',}'; } } else if (min == max) { quantifier = '{' + min + '}'; } else if (min == 0 && max == 1) { quantifier = '?'; } else { quantifier = '{' + min + ',' + max + '}'; }
if (!node.greedy) { quantifier += '?'; }
return generateAtom(node.body[0]) + quantifier; }
function generateReference(node) { assertType(node.type, 'reference');
if (node.matchIndex) { return '\\' + node.matchIndex; } if (node.name) { return '\\k<' + generateIdentifier(node.name) + '>'; }
throw new Error('Unknown reference type'); }
function generateTerm(node) { assertType(node.type, 'anchor|characterClass|characterClassEscape|empty|group|quantifier|reference|unicodePropertyEscape|value|dot');
return generate(node); }
function generateUnicodePropertyEscape(node) { assertType(node.type, 'unicodePropertyEscape');
return '\\' + (node.negative ? 'P' : 'p') + '{' + node.value + '}'; }
function generateValue(node) { assertType(node.type, 'value');
var kind = node.kind, codePoint = node.codePoint;
if (typeof codePoint != 'number') { throw new Error('Invalid code point: ' + codePoint); }
switch (kind) { case 'controlLetter': return '\\c' + fromCodePoint(codePoint + 64); case 'hexadecimalEscape': return '\\x' + ('00' + codePoint.toString(16).toUpperCase()).slice(-2); case 'identifier': return '\\' + fromCodePoint(codePoint); case 'null': return '\\' + codePoint; case 'octal': return '\\' + ('000' + codePoint.toString(8)).slice(-3); case 'singleEscape': switch (codePoint) { case 0x0008: return '\\b'; case 0x0009: return '\\t'; case 0x000A: return '\\n'; case 0x000B: return '\\v'; case 0x000C: return '\\f'; case 0x000D: return '\\r'; case 0x002D: return '\\-'; default: throw Error('Invalid code point: ' + codePoint); } case 'symbol': return fromCodePoint(codePoint); case 'unicodeEscape': return '\\u' + ('0000' + codePoint.toString(16).toUpperCase()).slice(-4); case 'unicodeCodePointEscape': return '\\u{' + codePoint.toString(16).toUpperCase() + '}'; default: throw Error('Unsupported node kind: ' + kind); } }
/*--------------------------------------------------------------------------*/
// Used to generate strings for each node type.
var generators = { 'alternative': generateAlternative, 'anchor': generateAnchor, 'characterClass': generateCharacterClass, 'characterClassEscape': generateCharacterClassEscape, 'characterClassRange': generateCharacterClassRange, 'disjunction': generateDisjunction, 'dot': generateDot, 'group': generateGroup, 'quantifier': generateQuantifier, 'reference': generateReference, 'unicodePropertyEscape': generateUnicodePropertyEscape, 'value': generateValue };
/*--------------------------------------------------------------------------*/
// Export regjsgen.
var regjsgen = { 'generate': generate };
// Some AMD build optimizers, like r.js, check for condition patterns like the following:
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { // Define as an anonymous module so it can be aliased through path mapping.
define(function() { return regjsgen; });
root.regjsgen = regjsgen; } // Check for `exports` after `define` in case a build optimizer adds an `exports` object.
else if (freeExports && hasFreeModule) { // Export for CommonJS support.
freeExports.generate = generate; } else { // Export to the global object.
root.regjsgen = regjsgen; } }.call(this));
|