'use strict'; const regexpTree = require('regexp-tree'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; } const regexpTree__default = /*#__PURE__*/_interopDefaultCompat(regexpTree); function build(node) { if (node === null) return ""; switch (node.type) { case "CharacterClass": { const exprs = combineContinuousSimpleChars(node.expressions); if (exprs.length === 1) { const first = exprs[0]; if (typeof first === "string") { return node.negative ? `charNotIn(${first})` : `charIn(${first})`; } else if (first.type === "Char" && first.kind === "meta" && node.negative) { if (first.value === "\\t") return `not.tab`; if (first.value === "\\n") return `not.linefeed`; if (first.value === "\\r") return `not.carriageReturn`; } else { const range = normalizeClassRange(first); if (range === "A-Z") return node.negative ? `not.letter.uppercase` : `letter.uppercase`; else if (range === "a-z") return node.negative ? `not.letter.lowercase` : `letter.lowercase`; } } else if (exprs.length === 2) { if (typeof exprs[0] !== "string" && typeof exprs[1] !== "string") { const range1 = normalizeClassRange(exprs[0]); const range2 = normalizeClassRange(exprs[1]); if (range1 === "A-Z" && range2 === "a-z" || range1 === "a-z" && range2 === "A-Z") return node.negative ? `not.letter` : `letter`; } } throw new Error("Unsupported for Complex charactor class"); } case "Disjunction": return chain(build(node.left), `or(${build(node.right)})`); case "Assertion": switch (node.kind) { case "\\b": return "wordBoundary"; case "\\B": return "not.wordBoundary"; case "^": return chain("", "at.lineStart()"); case "$": return chain("", "at.lineEnd()"); case "Lookbehind": return chain("", `${node.negative ? "notAfter" : "after"}(${build(node.assertion)})`); case "Lookahead": return chain("", `${node.negative ? "notBefore" : "before"}(${build(node.assertion)})`); /* v8 ignore next 2 */ default: throw new TypeError(`Unknown Assertion kind: ${node.kind}`); } case "Char": if (node.kind === "meta") { switch (node.value) { case ".": return "char"; case "\\w": return "wordChar"; case "\\d": return "digit"; case "\\s": return "whitespace"; case "\\t": return "tab"; case "\\n": return "linefeed"; case "\\r": return "carriageReturn"; case "\\W": return "not.wordChar"; case "\\D": return "not.digit"; case "\\S": return "not.whitespace"; case "\f": case "\v": default: throw new Error(`Unsupported Meta Char: ${node.value}`); } } else { const char = getChar(node); if (char === null) throw new Error(`Unknown Char: ${node.value}`); return `'${char}'`; } case "Repetition": { const quantifier = node.quantifier; const expr = build(node.expression); const lazy = !quantifier.greedy; if (lazy) throw new Error("Unsupported for lazy quantifier"); switch (quantifier.kind) { case "+": return `oneOrMore(${expr})`; case "?": return `maybe(${expr})`; case "*": return chain(expr, "times.any()"); case "Range": if (quantifier.from === quantifier.to) return chain(expr, `times(${quantifier.from})`); else if (!quantifier.to) return chain(expr, `times.atLeast(${quantifier.from})`); else if (quantifier.from === 0) return chain(expr, `times.atMost(${quantifier.to})`); return chain(expr, `times.between(${quantifier.from}, ${quantifier.to})`); /* v8 ignore next 2 */ default: return ""; } } case "Alternative": { const alts = combineContinuousSimpleChars(node.expressions); const exprs = []; for (let i = 0; i < alts.length; i++) { const alt = alts[i]; if (typeof alt === "string") { exprs.push(alt); continue; } if (alt.type === "Assertion") { switch (alt.kind) { case "^": { const next = alts[++i]; if (next === void 0) throw new Error(`Unexpected assertion: ${JSON.stringify(alt)}`); exprs.push(chain(next, "at.lineStart()")); continue; } case "$": { const prev = exprs.pop(); if (prev === void 0) throw new Error(`Unexpected assertion: ${JSON.stringify(alt)}`); exprs.push(chain(prev, "at.lineEnd()")); continue; } case "Lookbehind": { const next = alts[++i]; if (next === void 0) throw new Error(`Unexpected assertion: ${JSON.stringify(alt)}`); const helper = alt.negative ? "notAfter" : "after"; exprs.push(chain(next, `${helper}(${build(alt.assertion)})`)); continue; } case "Lookahead": { const prev = exprs.pop(); if (prev === void 0) throw new Error(`Unexpected assertion: ${JSON.stringify(alt)}`); const helper = alt.negative ? "notBefore" : "before"; exprs.push(chain(prev, `${helper}(${build(alt.assertion)})`)); continue; } } } if (alt.type === "Backreference") { if (alt.kind !== "name") throw new Error(`Unsupport for number reference`); const ref = chain(`exactly(${exprs.join(", ")})`, `and.referenceTo('${alt.reference}')`); exprs.length = 0; exprs.push(ref); continue; } exprs.push(build(alt)); } return exprs.join(", "); } case "Group": if (node.capturing) return chain(build(node.expression), node.name ? `as('${node.name}')` : "grouped()"); else return chain(build(node.expression)); /* v8 ignore next 2 */ case "Backreference": return chain("", `and.referenceTo('${node.reference}')`); } } function normalizeClassRange(node) { if (node.type === "ClassRange") return `${node.from.value}-${node.to.value}`; } function combineContinuousSimpleChars(expressions) { let simpleChars = ""; const exprs = expressions.reduce( (acc, expr) => { const char = expr.type === "Char" ? getChar(expr) : null; if (char !== null) { simpleChars += char; } else { if (simpleChars) { acc.push(`'${simpleChars}'`); simpleChars = ""; } acc.push(expr); } return acc; }, [] ); if (simpleChars) exprs.push(`'${simpleChars}'`); return exprs; } function getChar(char) { function escapeSimpleChar(char2) { return char2 === "'" ? "\\'" : char2; } switch (char.kind) { case "simple": return escapeSimpleChar(char.value); case "oct": case "decimal": case "hex": case "unicode": if ("symbol" in char) return escapeSimpleChar(char.symbol); } return null; } function chain(expr, helper) { let _expr = ""; if (typeof expr === "string") { if (expr === "") _expr = "exactly('')"; else _expr = expr.startsWith("'") && expr.endsWith("'") ? `exactly(${expr})` : expr; } else { _expr = build(expr); } return helper ? `${_expr}.${helper}` : _expr; } function buildFlags(flags) { if (!flags) return ""; const readableFlags = flags.split("").map((flag) => { return { d: "withIndices", i: "caseInsensitive", g: "global", m: "multiline", s: "dotAll", u: "unicode", y: "sticky" }[flag] || `'${flag}'`; }); return `[${readableFlags.join(", ")}]`; } function convert(regex, { argsOnly = false } = {}) { const ast = regexpTree__default.parse(regex); if (ast.type !== "RegExp") throw new TypeError(`Unexpected RegExp AST: ${ast.type}`); const flags = buildFlags(ast.flags); const args = build(ast.body) + (flags ? `, ${flags}` : ""); return argsOnly ? args : `createRegExp(${args})`; } exports.convert = convert;