1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const tslib_1 = require("tslib");
|
4 | const babel = require("@babel/standalone");
|
5 | const t = require("@babel/types");
|
6 | const data_engine_utils_1 = require("@narwhal/data-engine-utils");
|
7 | const inversify_1 = require("inversify");
|
8 | let PredicateParser = class PredicateParser {
|
9 | constructor() {
|
10 | this.cache = {};
|
11 | this.async_field_names = {};
|
12 | }
|
13 | convertPredicate(predicate, scope) {
|
14 | return this._cached_convertPredicate(predicate, scope);
|
15 | }
|
16 | _cached_convertPredicate(predicate, scope) {
|
17 | const key = JSON.stringify({ predicate });
|
18 | if (this.cache[key] === undefined) {
|
19 | this.cache[key] = this._convertPredicate(predicate, scope);
|
20 | }
|
21 | return this.cache[key];
|
22 | }
|
23 | _convertPredicate(predicate, scope = {}) {
|
24 |
|
25 | const transformed = babel.transform(predicate, { ast: true, babelrc: false, presets: [], plugins: [] });
|
26 | const statements = transformed.ast.program.body;
|
27 | let actual_program;
|
28 | if (statements.length > 1) {
|
29 | actual_program = t.blockStatement(transformed.ast.program.body);
|
30 | }
|
31 | else {
|
32 | actual_program = statements[0];
|
33 | }
|
34 |
|
35 | if (!actual_program) {
|
36 |
|
37 | actual_program = t.expressionStatement(t.stringLiteral(predicate));
|
38 | }
|
39 | const new_statements = [];
|
40 | let isFunction = t.isFunction(actual_program);
|
41 | let isAsync = false;
|
42 | if (t.isFunctionDeclaration(actual_program)) {
|
43 | actual_program = t.expressionStatement(t.arrowFunctionExpression(actual_program.params, actual_program.body));
|
44 | isFunction = true;
|
45 | }
|
46 | if (t.isExpressionStatement(actual_program)) {
|
47 | if (t.isFunction(actual_program.expression)) {
|
48 | const funcExpression = actual_program.expression;
|
49 | isFunction = true;
|
50 | new_statements.push(t.returnStatement(funcExpression));
|
51 | }
|
52 | else {
|
53 | isFunction = false;
|
54 |
|
55 | const return_statement = t.returnStatement(t.isStringLiteral(actual_program.expression) &&
|
56 | (actual_program.expression.value.startsWith("'") || actual_program.expression.value.startsWith('"'))
|
57 | ? t.stringLiteral(actual_program.expression.value.slice(1, -1))
|
58 | : actual_program.expression);
|
59 | new_statements.push(return_statement);
|
60 | }
|
61 | }
|
62 | else if (statements.find(statement => t.isExpressionStatement(statement))) {
|
63 | const exprStatement = (statements.find(statement => t.isExpressionStatement(statement)));
|
64 | isFunction = t.isFunction(exprStatement.expression);
|
65 | if (exprStatement.expression.async) {
|
66 | isAsync = true;
|
67 | }
|
68 | const wrapped = [
|
69 | ...statements.filter(statement => !t.isExpressionStatement(statement)),
|
70 | t.returnStatement(exprStatement.expression),
|
71 | ];
|
72 | new_statements.push(...wrapped);
|
73 | }
|
74 | else {
|
75 | new_statements.push(...statements);
|
76 | }
|
77 | if (!isAsync) {
|
78 | if (predicate.startsWith("async")) {
|
79 | isAsync = true;
|
80 | }
|
81 | }
|
82 | const errorAgg = this.errorAggregator;
|
83 | const compiled = babel.transformFromAst(t.file(t.program(new_statements, [], "script"), [], []), undefined, { babelrc: false, presets: [], plugins: ["proposal-optional-chaining"] });
|
84 |
|
85 | const order = Object.keys(scope);
|
86 |
|
87 | let func;
|
88 | try {
|
89 | func = new Function(...order, compiled.code);
|
90 | }
|
91 | catch (e) {
|
92 |
|
93 | const err = new Error(`Error while parsing predicate: ${predicate}\n converted to: ${compiled.code}\n Eval error: ${e}`);
|
94 | errorAgg.handleError(e, { predicate, code: compiled.code, err });
|
95 | throw err;
|
96 | }
|
97 | let evald = function (...args) {
|
98 | try {
|
99 | let evalResult = func.apply(this, order.map(key => scope[key]));
|
100 | if (isFunction) {
|
101 | evalResult = evalResult.apply(this, arguments);
|
102 | }
|
103 | return evalResult;
|
104 | }
|
105 | catch (e) {
|
106 | const err = new Error(`Error when executing predicate. Predicate contents: ${predicate}. Error: \n${e}`);
|
107 | err.stack = e.stack;
|
108 | err.name = e.name;
|
109 | errorAgg.handleError(e, { predicate, code: compiled.code, err });
|
110 | throw err;
|
111 | }
|
112 | };
|
113 | if (isAsync) {
|
114 | const old_evald = evald;
|
115 | evald = function (...args) {
|
116 | return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
117 | let done = false;
|
118 | const keepAlive = () => setTimeout(() => { if (!done) {
|
119 | keepAlive();
|
120 | } }, 10);
|
121 | keepAlive();
|
122 | try {
|
123 | return yield old_evald.apply(this, args);
|
124 | }
|
125 | finally {
|
126 | done = true;
|
127 | }
|
128 | });
|
129 | };
|
130 | }
|
131 | evald.isAsync = isAsync;
|
132 | return evald;
|
133 | }
|
134 | };
|
135 | tslib_1.__decorate([
|
136 | inversify_1.inject(data_engine_utils_1.UTIL_TYPES.TelemetryErrorAggregator),
|
137 | tslib_1.__metadata("design:type", data_engine_utils_1.TelemetryErrorReporterAggregator)
|
138 | ], PredicateParser.prototype, "errorAggregator", void 0);
|
139 | PredicateParser = tslib_1.__decorate([
|
140 | inversify_1.injectable()
|
141 | ], PredicateParser);
|
142 | exports.PredicateParser = PredicateParser;
|
143 |
|
\ | No newline at end of file |