UNPKG

6.22 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const tslib_1 = require("tslib");
4const babel = require("@babel/standalone");
5const t = require("@babel/types");
6const data_engine_utils_1 = require("@narwhal/data-engine-utils");
7const inversify_1 = require("inversify");
8let 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 // Run the input predicate string through babel to get an abstract syntax tree.
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 // Get the root of the ast, which happens to be a "file" object.
35 if (!actual_program) {
36 // We probably got a string literal parsed as a directive instead of an expression. Fix that...
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 // wrap literal statements in ()=>{return blabla}
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 // tslint:disable-next-line:ban-types
87 let func;
88 try {
89 func = new Function(...order, compiled.code);
90 }
91 catch (e) {
92 // Sentry.captureException(e, {extra: {predicate, code: compiled.code}});
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};
135tslib_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);
139PredicateParser = tslib_1.__decorate([
140 inversify_1.injectable()
141], PredicateParser);
142exports.PredicateParser = PredicateParser;
143//# sourceMappingURL=predicate_parser.js.map
\No newline at end of file