nextpay-querystring
Version:
Thư viện QueryString của NextPay - Chuyển đổi QueryString thành điều kiện select cho MongoDB và MySQL với kiểm soát bảo mật
156 lines • 6.42 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable @typescript-eslint/no-use-before-define */
/* eslint-disable no-continue */
/* eslint-disable operator-linebreak */
/* eslint-disable implicit-arrow-linebreak */
const clauses_1 = require("./clauses");
const tokens_1 = require("../models/tokens");
const generics_1 = require("../utils/generics");
const exceptions_1 = require("../utils/exceptions");
const filters_1 = require("./filters");
// token-types order:
// OR: 8
// AND: 7
// ===: 6
// IN, NIN, RANGE: 5
// == != < <= > >=: 4
// NOT: 2
const FULLMATCH_FILTER_LEVEL = 6;
const ARRAY_FILTER_LEVEL = 5;
const COMPARE_FILTER_LEVEL = 4;
const NOT_CLAUSE_LEVEL = 2;
const precedenceRules = [
[tokens_1.TokenType.OR, 8],
[tokens_1.TokenType.AND, 7],
[tokens_1.TokenType.TRIPLE_EQUALS, 6],
[tokens_1.TokenType.IN, 5],
[tokens_1.TokenType.NIN, 5],
[tokens_1.TokenType.RANGE, 5],
[tokens_1.TokenType.DOUBLE_EQUALS, 4],
[tokens_1.TokenType.BANG_EQUAL, 4],
[tokens_1.TokenType.LESS, 4],
[tokens_1.TokenType.LESS_EQUAL, 4],
[tokens_1.TokenType.GREATER, 4],
[tokens_1.TokenType.GREATER_EQUAL, 4],
[tokens_1.TokenType.PREFIX_LIKE, 4],
[tokens_1.TokenType.MIDDLE_LIKE, 4],
[tokens_1.TokenType.SUFFIX_LIKE, 4],
[tokens_1.TokenType.NOT, 2],
];
const parseFuncPath = 'step2.Step2Converter.convert: ';
const getRightParentAt = (0, generics_1.matchingElemPosition)({ type: tokens_1.TokenType.LEFT_PAREN, lexeme: '(' }, { type: tokens_1.TokenType.RIGHT_PAREN, lexeme: ')' })((x, y) => x.type === y.type && x.lexeme === y.lexeme);
const getRightBracketAt = (0, generics_1.findFirst)({
type: tokens_1.TokenType.RIGHT_BRACKET,
lexeme: ']',
})((x, y) => x.type === y.type && x.lexeme === y.lexeme);
const and = (tokens, leftId, rightId) => {
let lastIndex = leftId - 1;
const nodes = [];
for (let i = leftId; i < rightId; i += 1) {
if (tokens[i]?.type === tokens_1.TokenType.LEFT_PAREN) {
i = getRightParentAt(tokens, i, rightId, []);
}
if (tokens[i]?.type !== tokens_1.TokenType.AND)
continue;
nodes.push(buildAST(tokens, lastIndex + 1, i));
lastIndex = i;
}
nodes.push(buildAST(tokens, lastIndex + 1, rightId));
return new clauses_1.AndClause(nodes);
};
const or = (tokens, leftId, rightId) => {
let lastIndex = leftId - 1;
const nodes = [];
for (let i = leftId; i < rightId; i += 1) {
if (tokens[i]?.type === tokens_1.TokenType.LEFT_PAREN) {
i = getRightParentAt(tokens, i, rightId, []);
}
if (tokens[i]?.type !== tokens_1.TokenType.OR)
continue;
nodes.push(buildAST(tokens, lastIndex + 1, i));
lastIndex = i;
}
nodes.push(buildAST(tokens, lastIndex + 1, rightId));
return new clauses_1.OrClause(nodes);
};
const not = (tokens, leftId, rightId) => {
const notSubGroup = tokens[leftId + 1]?.type !== tokens_1.TokenType.LEFT_PAREN &&
getRightParentAt(tokens, leftId + 1, rightId, []) !== rightId - 1;
if (tokens[leftId]?.type !== tokens_1.TokenType.NOT || notSubGroup) {
throw (0, exceptions_1.notCorrectPiecesException)(parseFuncPath, leftId, rightId)(NOT_CLAUSE_LEVEL);
}
return new clauses_1.NotClause(buildAST(tokens, leftId + 2, rightId - 1));
};
const fullmatchOpr = (tokens, leftId, rightId) => {
const op = tokens[rightId - 2];
const str = tokens[rightId - 1];
const notArray = tokens[leftId]?.type !== tokens_1.TokenType.LEFT_BRACKET ||
getRightBracketAt(tokens, leftId, rightId, []) !== rightId - 3;
if (op?.type !== tokens_1.TokenType.TRIPLE_EQUALS ||
str?.type !== tokens_1.TokenType.STRING ||
notArray) {
throw (0, exceptions_1.notCorrectPiecesException)(parseFuncPath, leftId, rightId)(FULLMATCH_FILTER_LEVEL);
}
return new filters_1.FmFilter(tokens.slice(leftId + 1, rightId - 3), str);
};
const compareFilter = (tokens, leftId, rightId) => {
if (rightId - leftId !== 3 || tokens[leftId]?.type !== tokens_1.TokenType.VARIABLE) {
throw (0, exceptions_1.notCorrectPiecesException)(parseFuncPath, leftId, rightId)(COMPARE_FILTER_LEVEL);
}
return (0, filters_1.compareFilterFactory)(tokens[leftId + 1])(tokens[leftId], tokens[rightId - 1]);
};
const arrayFilter = (tokens, leftId, rightId) => {
const notArray = tokens[leftId + 2]?.type !== tokens_1.TokenType.LEFT_BRACKET ||
getRightBracketAt(tokens, leftId, rightId, []) !== rightId - 1;
if (tokens[leftId]?.type !== tokens_1.TokenType.VARIABLE || notArray) {
throw (0, exceptions_1.notCorrectPiecesException)(parseFuncPath, leftId, rightId)(ARRAY_FILTER_LEVEL);
}
const values = tokens.slice(leftId + 3, rightId - 1);
return (0, filters_1.arrayFilterFactory)(tokens[leftId + 1])(tokens[leftId], values);
};
const precedenceOf = (type) => {
const rule = precedenceRules.find(e => e[0] === type);
if (!rule) {
return -1;
}
return rule[1];
};
const buildAST = (tokens, leftId, rightId) => {
if (leftId >= rightId) {
throw (0, exceptions_1.outOfRangeException)(parseFuncPath, leftId, rightId);
}
const coveredByBracket = tokens[leftId]?.type === tokens_1.TokenType.LEFT_PAREN &&
getRightParentAt(tokens, leftId, rightId, []) === rightId - 1;
if (coveredByBracket) {
return buildAST(tokens, leftId + 1, rightId - 1);
}
let maxPrecedence = 0;
for (let i = leftId; i < rightId; i += 1) {
if (tokens[i]?.type === tokens_1.TokenType.LEFT_PAREN) {
i = getRightParentAt(tokens, i, rightId, []);
}
else {
maxPrecedence = Math.max(maxPrecedence, precedenceOf(tokens[i]?.type));
}
}
switch (maxPrecedence) {
case 8:
return or(tokens, leftId, rightId);
case 7:
return and(tokens, leftId, rightId);
case 6:
return fullmatchOpr(tokens, leftId, rightId);
case 5:
return arrayFilter(tokens, leftId, rightId);
case 4:
return compareFilter(tokens, leftId, rightId);
case 2:
return not(tokens, leftId, rightId);
default:
throw new Error('not existed');
}
};
const parse = (tokens) => buildAST(tokens, 0, tokens.length);
exports.default = parse;
//# sourceMappingURL=parser.js.map
;