@vulcan-sql/core
Version:
Core package of VulcanSQL
184 lines • 8.52 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ParametersChecker = void 0;
const tslib_1 = require("tslib");
const models_1 = require("../../../../models/index");
const lodash_1 = require("lodash");
const nunjucks = require("nunjucks");
const utils_1 = require("../../../utils/index");
const constants_1 = require("./constants");
const inversify_1 = require("inversify");
const types_1 = require("../../../../containers/types");
const extension_utils_1 = require("../../extension-utils");
// Validation filters (VF) which meet the following requirements can be PreCheck Validation Filters (PCVF)
// 1. All arguments should be static. (O) context.params.id | number(max=20) , (X) context.params.id | number(max=var)
// 2. Filters should be applied right after the parameters. (O) context.params.id | number(max=20), (X) context.params.id | upper | number(max=20)
// 3. Filters should not be applied on the children of parameters. (O) context.params.id | number(max=20), (X) context.params.id.account | number(max=20)
let ParametersChecker = class ParametersChecker extends models_1.CompileTimeExtension {
constructor(config, moduleName, validatorLoader) {
super(config, moduleName);
this.metadataName = constants_1.PARAMETER_METADATA_NAME;
this.parameters = new Map();
this.validationFilterNames = new Set();
validatorLoader
.getValidators()
.forEach((validator) => this.validationFilterNames.add((0, extension_utils_1.getValidationFilterName)(validator)));
}
onVisit(node) {
// Clear parameters at the begin
if (node instanceof nunjucks.nodes.Root)
this.parameters.clear();
// Extract parameter from lookupVal node: {{ context.params.xxx }}
if (node instanceof nunjucks.nodes.LookupVal) {
const parameter = this.getParametersOfLookupNode(node);
this.addParameter(parameter);
return;
}
// Visit the children and replace the preCheck validation filters. {{ context.params.xxx | xxx() }}
(0, extension_utils_1.visitChildren)(node, (child, replace) => {
if (!this.isPreCheckValidationFilterNode(child))
return;
const parameter = this.getParametersOfPCVFNode(child);
if (!parameter)
return;
replace(parameter.nodes[0]);
this.addParameter(parameter);
});
}
getMetadata() {
return (0, lodash_1.chain)(Array.from(this.parameters.values()))
.map((parameter) => ({
name: parameter.name,
locations: parameter.nodes.map((node) => ({
lineNo: node.lineno,
columnNo: node.colno,
})),
validators: parameter.validators,
}))
.value();
}
/** Get parameters from PreCheck Validation Filter node */
getParametersOfPCVFNode(node) {
const target = node.args.children[0];
let parameter = null;
if (target instanceof nunjucks.nodes.LookupVal) {
// Get the parameter if our target is a lookup node
parameter = this.getParametersOfLookupNode(target);
}
else if (this.isPreCheckValidationFilterNode(target)) {
// Get its parameter if our target is still a PreCheck node
parameter = this.getParametersOfPCVFNode(target);
}
// Check args
const args = {};
const argsNode = node.args.children[1];
if (argsNode) {
// (max=10, min=0) --> KeywordArgs
if (!(argsNode instanceof nunjucks.nodes.KeywordArgs)) {
throw new utils_1.TemplateError(`The arguments of validation filter ${node.name.value} is invalid`, {
node: argsNode,
});
}
for (const arg of argsNode.children) {
// max=10 --> Pair
if (!(arg instanceof nunjucks.nodes.Pair)) {
throw new utils_1.TemplateError(`The arguments of validation filter ${node.name.value} is invalid`, {
node: arg,
});
}
if (arg.value instanceof nunjucks.nodes.Literal) {
// Static value, set the value. e.g. a=1, a="s", a=true ...
args[arg.key.value] = arg.value.value;
}
else if (arg.value instanceof nunjucks.nodes.Array &&
arg.value.children.every((child) => child instanceof nunjucks.nodes.Literal)) {
// Static array value, set the value. e.g. a=[1,2,3]
args[arg.key.value] = arg.value.children.map((child) => child.value);
}
else {
// Dynamic value, set to null because we know the value only when executing.
args[arg.key.value] = null;
}
}
}
// 1. All arguments should be static. (O) context.params.id | number(max=20) , (X) context.params.id | number(max=var)
if ((0, lodash_1.values)(args).some((value) => value === null))
return null;
// 3. Filters should not be applied on the children of parameters. (O) context.params.id | number(max=20), (X) context.params.id.account | number(max=20)
if (parameter === null || parameter === void 0 ? void 0 : parameter.name.includes('.'))
return null;
parameter === null || parameter === void 0 ? void 0 : parameter.validators.push({
name: (0, extension_utils_1.getValidatorName)(node.name.value),
args,
});
return parameter;
}
/** Return the name and position of parameters if found */
getParametersOfLookupNode(node) {
let name = node.val.value;
let target = node.target;
let depth = 0;
while (target) {
depth++;
if (depth > constants_1.REFERENCE_SEARCH_MAX_DEPTH) {
throw new utils_1.InternalError('Max depth reached');
}
if (target instanceof nunjucks.nodes.LookupVal) {
name = target.val.value + '.' + name;
target = target.target;
}
else if (target instanceof nunjucks.nodes.FunCall) {
target = target.name;
}
else {
name = target.value + '.' + name;
const lookUp = constants_1.LOOK_UP_PARAMETER + '.';
if (name.startsWith(lookUp)) {
return {
name: name.replace(lookUp, ''),
validators: [],
nodes: [node],
};
}
break;
}
}
return null;
}
isValidationFilterNode(node) {
return (node instanceof nunjucks.nodes.Filter &&
node.name instanceof nunjucks.nodes.Symbol &&
this.validationFilterNames.has(node.name.value));
}
isPreCheckValidationFilterNode(node) {
return (this.isValidationFilterNode(node) &&
// 1. All arguments should be static.
node.args.children
.slice(1) // The first argument is the target of the filter
.every((arg) => !(arg instanceof nunjucks.nodes.LookupVal)));
}
addParameter(parameter) {
if (!parameter)
return;
if (!this.parameters.has(parameter.name)) {
this.parameters.set(parameter.name, parameter);
}
else {
const existedParam = this.parameters.get(parameter.name);
// If node is already in our collection, ignore it.
if (existedParam.nodes.includes(parameter.nodes[0]))
return;
existedParam.validators.push(...parameter.validators);
existedParam.nodes.push(...parameter.nodes);
}
}
};
ParametersChecker = tslib_1.__decorate([
(0, models_1.VulcanInternalExtension)(),
tslib_1.__param(0, (0, inversify_1.inject)(types_1.TYPES.ExtensionConfig)),
tslib_1.__param(1, (0, inversify_1.inject)(types_1.TYPES.ExtensionName)),
tslib_1.__param(2, (0, inversify_1.inject)(types_1.TYPES.ValidatorLoader)),
tslib_1.__metadata("design:paramtypes", [Object, String, Object])
], ParametersChecker);
exports.ParametersChecker = ParametersChecker;
//# sourceMappingURL=parametersChecker.js.map