UNPKG

odatafy-parser

Version:

generate odatafy ast from odata query parameters

131 lines (130 loc) 5.29 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.reverseExprLogic = exports.resolveExpression = exports.reverseEscaped = exports.escapeExpression = exports.hasOnlyMatchingParentheses = exports.escapeStrings = exports.getIdentifier = exports.Prefixes = void 0; // this is by far the most amazing algorithm ever created in 6 hours //God intends that one shall never touch any of this code const crypto_1 = __importDefault(require("crypto")); var Prefixes; (function (Prefixes) { Prefixes["Str_Escape"] = "$"; Prefixes["Func_Escape"] = "%"; Prefixes["Expr_Escape"] = "\u00A7"; Prefixes["Multiexpr_Escape"] = "&"; })(Prefixes = exports.Prefixes || (exports.Prefixes = {})); function getIdentifier(prefix) { return `${prefix}${crypto_1.default.randomBytes(20).toString('hex')}${prefix}`; } exports.getIdentifier = getIdentifier; function escapeStrings(expr) { let escaped = expr; const stringResolve = {}; while (escaped.includes("'")) { const regex = /'.*?'/; const identifier = getIdentifier(Prefixes.Str_Escape); const toEscape = escaped.match(regex); if (toEscape == null) { break; } stringResolve[identifier] = toEscape[0].toString(); escaped = escaped.replace(regex, identifier); } return [escaped, stringResolve]; } exports.escapeStrings = escapeStrings; function hasOnlyMatchingParentheses(expr) { return [...expr.matchAll(/\(/g)].length == [...expr.matchAll(/\)/g)].length; } exports.hasOnlyMatchingParentheses = hasOnlyMatchingParentheses; const expressionResolver = {}; const multiExpressionResolve = {}; function escapeExpression(expr, depth = 0) { let result = ''; const andOrRegex = /( AND | OR )/; const expressionsElements = expr.split(andOrRegex); for (let i = 0; i < expressionsElements.length; i++) { if (expressionsElements[i].match(andOrRegex)) { result += expressionsElements[i]; continue; } if (!(expressionsElements[i].includes('(') || expressionsElements[i].includes(')')) || hasOnlyMatchingParentheses(expressionsElements[i])) { const identifier = getIdentifier(Prefixes.Expr_Escape); result += identifier; expressionResolver[identifier] = expressionsElements[i]; continue; } let subExpr = expressionsElements[i]; let not = false; if (subExpr.startsWith('NOT ')) { subExpr = subExpr.replace('NOT ', ''); not = true; } //cannot be out of bounds while (!hasOnlyMatchingParentheses(subExpr)) { subExpr += expressionsElements[i + 1] + expressionsElements[i + 2]; i += 2; } subExpr = subExpr.trim(); subExpr = subExpr.substring(1, subExpr.length - 1); const identifier = getIdentifier(Prefixes.Multiexpr_Escape); const toEscape = escapeExpression(subExpr, depth + 1); result += identifier; multiExpressionResolve[identifier] = { toEscape: toEscape, depth: depth, not: not }; } return result; } exports.escapeExpression = escapeExpression; function reverseEscaped(expr, resolvers) { const andOrRegex = /( AND | OR )/; const expressionElements = expr.split(andOrRegex).reverse(); expr = expressionElements.join(''); const transformedResolvers = Object.keys(resolvers).map((resolverKey) => { return { toEscape: resolvers[resolverKey].toEscape, depth: resolvers[resolverKey].depth, not: resolvers[resolverKey].not, key: resolverKey }; }); const maxDepth = Math.max(...transformedResolvers.map((o) => o.depth)); for (let i = 0; i <= maxDepth; i++) { const transformedResolversOnDepth = transformedResolvers.filter((transRes) => transRes.depth == i); transformedResolversOnDepth.forEach((tRoD) => { const tRoDElements = tRoD.toEscape.split(andOrRegex).reverse(); tRoD.toEscape = tRoDElements.join(''); expr = expr.replace(tRoD.key, `${tRoD.not ? 'NOT ' : ''}(${tRoD.toEscape})`); }); } return expr; } exports.reverseEscaped = reverseEscaped; function resolveExpression(expr, exprResolver, strResolver) { Object.keys(exprResolver).forEach((key) => { expr = expr.replace(key, exprResolver[key]); }); Object.keys(strResolver).forEach((key) => { expr = expr.replace(key, strResolver[key]); }); return expr; } exports.resolveExpression = resolveExpression; function reverseExprLogic(expr) { const [strResult, stringResolver] = escapeStrings(expr); const exprResult = escapeExpression(strResult); const reverseResult = reverseEscaped(exprResult, multiExpressionResolve); const result = resolveExpression(reverseResult, expressionResolver, stringResolver); return result; } exports.reverseExprLogic = reverseExprLogic; function searchExpressionPreProc(expr) { return reverseExprLogic(expr); } exports.default = searchExpressionPreProc;