1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | Object.defineProperty(exports, "__esModule", { value: true });
|
10 | var ts = require("typescript");
|
11 | var schema_1 = require("./schema");
|
12 |
|
13 | var spreadElementSyntaxKind = ts.SyntaxKind.SpreadElement || ts.SyntaxKind.SpreadElementExpression;
|
14 | function isMethodCallOf(callExpression, memberName) {
|
15 | var expression = callExpression.expression;
|
16 | if (expression.kind === ts.SyntaxKind.PropertyAccessExpression) {
|
17 | var propertyAccessExpression = expression;
|
18 | var name_1 = propertyAccessExpression.name;
|
19 | if (name_1.kind == ts.SyntaxKind.Identifier) {
|
20 | return name_1.text === memberName;
|
21 | }
|
22 | }
|
23 | return false;
|
24 | }
|
25 | function isCallOf(callExpression, ident) {
|
26 | var expression = callExpression.expression;
|
27 | if (expression.kind === ts.SyntaxKind.Identifier) {
|
28 | var identifier = expression;
|
29 | return identifier.text === ident;
|
30 | }
|
31 | return false;
|
32 | }
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 | function everyNodeChild(node, cb) {
|
39 | return !ts.forEachChild(node, function (node) { return !cb(node); });
|
40 | }
|
41 | function isPrimitive(value) {
|
42 | return Object(value) !== value;
|
43 | }
|
44 | exports.isPrimitive = isPrimitive;
|
45 | function isDefined(obj) {
|
46 | return obj !== undefined;
|
47 | }
|
48 | function getSourceFileOfNode(node) {
|
49 | while (node && node.kind != ts.SyntaxKind.SourceFile) {
|
50 | node = node.parent;
|
51 | }
|
52 | return node;
|
53 | }
|
54 |
|
55 | function errorSymbol(message, node, context, sourceFile) {
|
56 | var result;
|
57 | if (node) {
|
58 | sourceFile = sourceFile || getSourceFileOfNode(node);
|
59 | if (sourceFile) {
|
60 | var _a = ts.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)), line = _a.line, character = _a.character;
|
61 | result = { __symbolic: 'error', message: message, line: line, character: character };
|
62 | }
|
63 | }
|
64 | if (!result) {
|
65 | result = { __symbolic: 'error', message: message };
|
66 | }
|
67 | if (context) {
|
68 | result.context = context;
|
69 | }
|
70 | return result;
|
71 | }
|
72 | exports.errorSymbol = errorSymbol;
|
73 |
|
74 |
|
75 |
|
76 |
|
77 | var Evaluator = (function () {
|
78 | function Evaluator(symbols, nodeMap, options) {
|
79 | if (options === void 0) { options = {}; }
|
80 | this.symbols = symbols;
|
81 | this.nodeMap = nodeMap;
|
82 | this.options = options;
|
83 | }
|
84 | Evaluator.prototype.nameOf = function (node) {
|
85 | if (node.kind == ts.SyntaxKind.Identifier) {
|
86 | return node.text;
|
87 | }
|
88 | var result = this.evaluateNode(node);
|
89 | if (schema_1.isMetadataError(result) || typeof result === 'string') {
|
90 | return result;
|
91 | }
|
92 | else {
|
93 | return errorSymbol('Name expected', node, { received: node.getText() });
|
94 | }
|
95 | };
|
96 | |
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 | Evaluator.prototype.isFoldable = function (node) {
|
113 | return this.isFoldableWorker(node, new Map());
|
114 | };
|
115 | Evaluator.prototype.isFoldableWorker = function (node, folding) {
|
116 | var _this = this;
|
117 | if (node) {
|
118 | switch (node.kind) {
|
119 | case ts.SyntaxKind.ObjectLiteralExpression:
|
120 | return everyNodeChild(node, function (child) {
|
121 | if (child.kind === ts.SyntaxKind.PropertyAssignment) {
|
122 | var propertyAssignment = child;
|
123 | return _this.isFoldableWorker(propertyAssignment.initializer, folding);
|
124 | }
|
125 | return false;
|
126 | });
|
127 | case ts.SyntaxKind.ArrayLiteralExpression:
|
128 | return everyNodeChild(node, function (child) { return _this.isFoldableWorker(child, folding); });
|
129 | case ts.SyntaxKind.CallExpression:
|
130 | var callExpression = node;
|
131 |
|
132 | if (isMethodCallOf(callExpression, 'concat') &&
|
133 | arrayOrEmpty(callExpression.arguments).length === 1) {
|
134 | var arrayNode = callExpression.expression.expression;
|
135 | if (this.isFoldableWorker(arrayNode, folding) &&
|
136 | this.isFoldableWorker(callExpression.arguments[0], folding)) {
|
137 |
|
138 | var arrayValue = this.evaluateNode(arrayNode);
|
139 | if (arrayValue && Array.isArray(arrayValue)) {
|
140 | return true;
|
141 | }
|
142 | }
|
143 | }
|
144 |
|
145 | if (isCallOf(callExpression, 'CONST_EXPR') &&
|
146 | arrayOrEmpty(callExpression.arguments).length === 1)
|
147 | return this.isFoldableWorker(callExpression.arguments[0], folding);
|
148 | return false;
|
149 | case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
|
150 | case ts.SyntaxKind.StringLiteral:
|
151 | case ts.SyntaxKind.NumericLiteral:
|
152 | case ts.SyntaxKind.NullKeyword:
|
153 | case ts.SyntaxKind.TrueKeyword:
|
154 | case ts.SyntaxKind.FalseKeyword:
|
155 | case ts.SyntaxKind.TemplateHead:
|
156 | case ts.SyntaxKind.TemplateMiddle:
|
157 | case ts.SyntaxKind.TemplateTail:
|
158 | return true;
|
159 | case ts.SyntaxKind.ParenthesizedExpression:
|
160 | var parenthesizedExpression = node;
|
161 | return this.isFoldableWorker(parenthesizedExpression.expression, folding);
|
162 | case ts.SyntaxKind.BinaryExpression:
|
163 | var binaryExpression = node;
|
164 | switch (binaryExpression.operatorToken.kind) {
|
165 | case ts.SyntaxKind.PlusToken:
|
166 | case ts.SyntaxKind.MinusToken:
|
167 | case ts.SyntaxKind.AsteriskToken:
|
168 | case ts.SyntaxKind.SlashToken:
|
169 | case ts.SyntaxKind.PercentToken:
|
170 | case ts.SyntaxKind.AmpersandAmpersandToken:
|
171 | case ts.SyntaxKind.BarBarToken:
|
172 | return this.isFoldableWorker(binaryExpression.left, folding) &&
|
173 | this.isFoldableWorker(binaryExpression.right, folding);
|
174 | default:
|
175 | return false;
|
176 | }
|
177 | case ts.SyntaxKind.PropertyAccessExpression:
|
178 | var propertyAccessExpression = node;
|
179 | return this.isFoldableWorker(propertyAccessExpression.expression, folding);
|
180 | case ts.SyntaxKind.ElementAccessExpression:
|
181 | var elementAccessExpression = node;
|
182 | return this.isFoldableWorker(elementAccessExpression.expression, folding) &&
|
183 | this.isFoldableWorker(elementAccessExpression.argumentExpression, folding);
|
184 | case ts.SyntaxKind.Identifier:
|
185 | var identifier = node;
|
186 | var reference = this.symbols.resolve(identifier.text);
|
187 | if (reference !== undefined && isPrimitive(reference)) {
|
188 | return true;
|
189 | }
|
190 | break;
|
191 | case ts.SyntaxKind.TemplateExpression:
|
192 | var templateExpression = node;
|
193 | return templateExpression.templateSpans.every(function (span) { return _this.isFoldableWorker(span.expression, folding); });
|
194 | }
|
195 | }
|
196 | return false;
|
197 | };
|
198 | |
199 |
|
200 |
|
201 |
|
202 | Evaluator.prototype.evaluateNode = function (node, preferReference) {
|
203 | var _this = this;
|
204 | var t = this;
|
205 | var error;
|
206 | function recordEntry(entry, node) {
|
207 | t.nodeMap.set(entry, node);
|
208 | return entry;
|
209 | }
|
210 | function isFoldableError(value) {
|
211 | return !t.options.verboseInvalidExpression && schema_1.isMetadataError(value);
|
212 | }
|
213 | var resolveName = function (name, preferReference) {
|
214 | var reference = _this.symbols.resolve(name, preferReference);
|
215 | if (reference === undefined) {
|
216 |
|
217 | return recordEntry({ __symbolic: 'reference', name: name }, node);
|
218 | }
|
219 | return reference;
|
220 | };
|
221 | switch (node.kind) {
|
222 | case ts.SyntaxKind.ObjectLiteralExpression:
|
223 | var obj_1 = {};
|
224 | var quoted_1 = [];
|
225 | ts.forEachChild(node, function (child) {
|
226 | switch (child.kind) {
|
227 | case ts.SyntaxKind.ShorthandPropertyAssignment:
|
228 | case ts.SyntaxKind.PropertyAssignment:
|
229 | var assignment = child;
|
230 | if (assignment.name.kind == ts.SyntaxKind.StringLiteral) {
|
231 | var name_2 = assignment.name.text;
|
232 | quoted_1.push(name_2);
|
233 | }
|
234 | var propertyName = _this.nameOf(assignment.name);
|
235 | if (isFoldableError(propertyName)) {
|
236 | error = propertyName;
|
237 | return true;
|
238 | }
|
239 | var propertyValue = isPropertyAssignment(assignment) ?
|
240 | _this.evaluateNode(assignment.initializer, true) :
|
241 | resolveName(propertyName, true);
|
242 | if (isFoldableError(propertyValue)) {
|
243 | error = propertyValue;
|
244 | return true;
|
245 | }
|
246 | else {
|
247 | obj_1[propertyName] = propertyValue;
|
248 | }
|
249 | }
|
250 | });
|
251 | if (error)
|
252 | return error;
|
253 | if (this.options.quotedNames && quoted_1.length) {
|
254 | obj_1['$quoted$'] = quoted_1;
|
255 | }
|
256 | return obj_1;
|
257 | case ts.SyntaxKind.ArrayLiteralExpression:
|
258 | var arr_1 = [];
|
259 | ts.forEachChild(node, function (child) {
|
260 | var value = _this.evaluateNode(child, true);
|
261 |
|
262 | if (isFoldableError(value)) {
|
263 | error = value;
|
264 | return true;
|
265 | }
|
266 |
|
267 | if (schema_1.isMetadataSymbolicSpreadExpression(value)) {
|
268 | if (Array.isArray(value.expression)) {
|
269 | for (var _i = 0, _a = value.expression; _i < _a.length; _i++) {
|
270 | var spreadValue = _a[_i];
|
271 | arr_1.push(spreadValue);
|
272 | }
|
273 | return;
|
274 | }
|
275 | }
|
276 | arr_1.push(value);
|
277 | });
|
278 | if (error)
|
279 | return error;
|
280 | return arr_1;
|
281 | case spreadElementSyntaxKind:
|
282 | var spreadExpression = this.evaluateNode(node.expression);
|
283 | return recordEntry({ __symbolic: 'spread', expression: spreadExpression }, node);
|
284 | case ts.SyntaxKind.CallExpression:
|
285 | var callExpression = node;
|
286 | if (isCallOf(callExpression, 'forwardRef') &&
|
287 | arrayOrEmpty(callExpression.arguments).length === 1) {
|
288 | var firstArgument = callExpression.arguments[0];
|
289 | if (firstArgument.kind == ts.SyntaxKind.ArrowFunction) {
|
290 | var arrowFunction = firstArgument;
|
291 | return recordEntry(this.evaluateNode(arrowFunction.body), node);
|
292 | }
|
293 | }
|
294 | var args_1 = arrayOrEmpty(callExpression.arguments).map(function (arg) { return _this.evaluateNode(arg); });
|
295 | if (!this.options.verboseInvalidExpression && args_1.some(schema_1.isMetadataError)) {
|
296 | return args_1.find(schema_1.isMetadataError);
|
297 | }
|
298 | if (this.isFoldable(callExpression)) {
|
299 | if (isMethodCallOf(callExpression, 'concat')) {
|
300 | var arrayValue = this.evaluateNode(callExpression.expression.expression);
|
301 | if (isFoldableError(arrayValue))
|
302 | return arrayValue;
|
303 | return arrayValue.concat(args_1[0]);
|
304 | }
|
305 | }
|
306 |
|
307 | if (isCallOf(callExpression, 'CONST_EXPR') &&
|
308 | arrayOrEmpty(callExpression.arguments).length === 1) {
|
309 | return recordEntry(args_1[0], node);
|
310 | }
|
311 | var expression = this.evaluateNode(callExpression.expression);
|
312 | if (isFoldableError(expression)) {
|
313 | return recordEntry(expression, node);
|
314 | }
|
315 | var result = { __symbolic: 'call', expression: expression };
|
316 | if (args_1 && args_1.length) {
|
317 | result.arguments = args_1;
|
318 | }
|
319 | return recordEntry(result, node);
|
320 | case ts.SyntaxKind.NewExpression:
|
321 | var newExpression = node;
|
322 | var newArgs = arrayOrEmpty(newExpression.arguments).map(function (arg) { return _this.evaluateNode(arg); });
|
323 | if (!this.options.verboseInvalidExpression && newArgs.some(schema_1.isMetadataError)) {
|
324 | return recordEntry(newArgs.find(schema_1.isMetadataError), node);
|
325 | }
|
326 | var newTarget = this.evaluateNode(newExpression.expression);
|
327 | if (schema_1.isMetadataError(newTarget)) {
|
328 | return recordEntry(newTarget, node);
|
329 | }
|
330 | var call = { __symbolic: 'new', expression: newTarget };
|
331 | if (newArgs.length) {
|
332 | call.arguments = newArgs;
|
333 | }
|
334 | return recordEntry(call, node);
|
335 | case ts.SyntaxKind.PropertyAccessExpression: {
|
336 | var propertyAccessExpression = node;
|
337 | var expression_1 = this.evaluateNode(propertyAccessExpression.expression);
|
338 | if (isFoldableError(expression_1)) {
|
339 | return recordEntry(expression_1, node);
|
340 | }
|
341 | var member = this.nameOf(propertyAccessExpression.name);
|
342 | if (isFoldableError(member)) {
|
343 | return recordEntry(member, node);
|
344 | }
|
345 | if (expression_1 && this.isFoldable(propertyAccessExpression.expression))
|
346 | return expression_1[member];
|
347 | if (schema_1.isMetadataModuleReferenceExpression(expression_1)) {
|
348 |
|
349 |
|
350 | return recordEntry({ __symbolic: 'reference', module: expression_1.module, name: member }, node);
|
351 | }
|
352 | return recordEntry({ __symbolic: 'select', expression: expression_1, member: member }, node);
|
353 | }
|
354 | case ts.SyntaxKind.ElementAccessExpression: {
|
355 | var elementAccessExpression = node;
|
356 | var expression_2 = this.evaluateNode(elementAccessExpression.expression);
|
357 | if (isFoldableError(expression_2)) {
|
358 | return recordEntry(expression_2, node);
|
359 | }
|
360 | if (!elementAccessExpression.argumentExpression) {
|
361 | return recordEntry(errorSymbol('Expression form not supported', node), node);
|
362 | }
|
363 | var index = this.evaluateNode(elementAccessExpression.argumentExpression);
|
364 | if (isFoldableError(expression_2)) {
|
365 | return recordEntry(expression_2, node);
|
366 | }
|
367 | if (this.isFoldable(elementAccessExpression.expression) &&
|
368 | this.isFoldable(elementAccessExpression.argumentExpression))
|
369 | return expression_2[index];
|
370 | return recordEntry({ __symbolic: 'index', expression: expression_2, index: index }, node);
|
371 | }
|
372 | case ts.SyntaxKind.Identifier:
|
373 | var identifier = node;
|
374 | var name_3 = identifier.text;
|
375 | return resolveName(name_3, preferReference);
|
376 | case ts.SyntaxKind.TypeReference:
|
377 | var typeReferenceNode = node;
|
378 | var typeNameNode_1 = typeReferenceNode.typeName;
|
379 | var getReference = function (node) {
|
380 | if (typeNameNode_1.kind === ts.SyntaxKind.QualifiedName) {
|
381 | var qualifiedName = node;
|
382 | var left_1 = _this.evaluateNode(qualifiedName.left);
|
383 | if (schema_1.isMetadataModuleReferenceExpression(left_1)) {
|
384 | return recordEntry({
|
385 | __symbolic: 'reference',
|
386 | module: left_1.module,
|
387 | name: qualifiedName.right.text
|
388 | }, node);
|
389 | }
|
390 |
|
391 | return { __symbolic: 'select', expression: left_1, member: qualifiedName.right.text };
|
392 | }
|
393 | else {
|
394 | var identifier_1 = typeNameNode_1;
|
395 | var symbol = _this.symbols.resolve(identifier_1.text);
|
396 | if (isFoldableError(symbol) || schema_1.isMetadataSymbolicReferenceExpression(symbol)) {
|
397 | return recordEntry(symbol, node);
|
398 | }
|
399 | return recordEntry(errorSymbol('Could not resolve type', node, { typeName: identifier_1.text }), node);
|
400 | }
|
401 | };
|
402 | var typeReference = getReference(typeNameNode_1);
|
403 | if (isFoldableError(typeReference)) {
|
404 | return recordEntry(typeReference, node);
|
405 | }
|
406 | if (!schema_1.isMetadataModuleReferenceExpression(typeReference) &&
|
407 | typeReferenceNode.typeArguments && typeReferenceNode.typeArguments.length) {
|
408 | var args_2 = typeReferenceNode.typeArguments.map(function (element) { return _this.evaluateNode(element); });
|
409 |
|
410 |
|
411 | typeReference.arguments = args_2;
|
412 | }
|
413 | return recordEntry(typeReference, node);
|
414 | case ts.SyntaxKind.UnionType:
|
415 | var unionType = node;
|
416 |
|
417 | var references = unionType.types
|
418 | .filter(function (n) { return n.kind != ts.SyntaxKind.NullKeyword &&
|
419 | n.kind != ts.SyntaxKind.UndefinedKeyword; })
|
420 | .map(function (n) { return _this.evaluateNode(n); });
|
421 |
|
422 |
|
423 | var candidate = null;
|
424 | for (var i = 0; i < references.length; i++) {
|
425 | var reference = references[i];
|
426 | if (schema_1.isMetadataSymbolicReferenceExpression(reference)) {
|
427 | if (candidate) {
|
428 | if (reference.name == candidate.name &&
|
429 | reference.module == candidate.module && !reference.arguments) {
|
430 | candidate = reference;
|
431 | }
|
432 | }
|
433 | else {
|
434 | candidate = reference;
|
435 | }
|
436 | }
|
437 | else {
|
438 | return reference;
|
439 | }
|
440 | }
|
441 | if (candidate)
|
442 | return candidate;
|
443 | break;
|
444 | case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
|
445 | case ts.SyntaxKind.StringLiteral:
|
446 | case ts.SyntaxKind.TemplateHead:
|
447 | case ts.SyntaxKind.TemplateTail:
|
448 | case ts.SyntaxKind.TemplateMiddle:
|
449 | return node.text;
|
450 | case ts.SyntaxKind.NumericLiteral:
|
451 | return parseFloat(node.text);
|
452 | case ts.SyntaxKind.AnyKeyword:
|
453 | return recordEntry({ __symbolic: 'reference', name: 'any' }, node);
|
454 | case ts.SyntaxKind.StringKeyword:
|
455 | return recordEntry({ __symbolic: 'reference', name: 'string' }, node);
|
456 | case ts.SyntaxKind.NumberKeyword:
|
457 | return recordEntry({ __symbolic: 'reference', name: 'number' }, node);
|
458 | case ts.SyntaxKind.BooleanKeyword:
|
459 | return recordEntry({ __symbolic: 'reference', name: 'boolean' }, node);
|
460 | case ts.SyntaxKind.ArrayType:
|
461 | var arrayTypeNode = node;
|
462 | return recordEntry({
|
463 | __symbolic: 'reference',
|
464 | name: 'Array',
|
465 | arguments: [this.evaluateNode(arrayTypeNode.elementType)]
|
466 | }, node);
|
467 | case ts.SyntaxKind.NullKeyword:
|
468 | return null;
|
469 | case ts.SyntaxKind.TrueKeyword:
|
470 | return true;
|
471 | case ts.SyntaxKind.FalseKeyword:
|
472 | return false;
|
473 | case ts.SyntaxKind.ParenthesizedExpression:
|
474 | var parenthesizedExpression = node;
|
475 | return this.evaluateNode(parenthesizedExpression.expression);
|
476 | case ts.SyntaxKind.TypeAssertionExpression:
|
477 | var typeAssertion = node;
|
478 | return this.evaluateNode(typeAssertion.expression);
|
479 | case ts.SyntaxKind.PrefixUnaryExpression:
|
480 | var prefixUnaryExpression = node;
|
481 | var operand = this.evaluateNode(prefixUnaryExpression.operand);
|
482 | if (isDefined(operand) && isPrimitive(operand)) {
|
483 | switch (prefixUnaryExpression.operator) {
|
484 | case ts.SyntaxKind.PlusToken:
|
485 | return +operand;
|
486 | case ts.SyntaxKind.MinusToken:
|
487 | return -operand;
|
488 | case ts.SyntaxKind.TildeToken:
|
489 | return ~operand;
|
490 | case ts.SyntaxKind.ExclamationToken:
|
491 | return !operand;
|
492 | }
|
493 | }
|
494 | var operatorText = void 0;
|
495 | switch (prefixUnaryExpression.operator) {
|
496 | case ts.SyntaxKind.PlusToken:
|
497 | operatorText = '+';
|
498 | break;
|
499 | case ts.SyntaxKind.MinusToken:
|
500 | operatorText = '-';
|
501 | break;
|
502 | case ts.SyntaxKind.TildeToken:
|
503 | operatorText = '~';
|
504 | break;
|
505 | case ts.SyntaxKind.ExclamationToken:
|
506 | operatorText = '!';
|
507 | break;
|
508 | default:
|
509 | return undefined;
|
510 | }
|
511 | return recordEntry({ __symbolic: 'pre', operator: operatorText, operand: operand }, node);
|
512 | case ts.SyntaxKind.BinaryExpression:
|
513 | var binaryExpression = node;
|
514 | var left = this.evaluateNode(binaryExpression.left);
|
515 | var right = this.evaluateNode(binaryExpression.right);
|
516 | if (isDefined(left) && isDefined(right)) {
|
517 | if (isPrimitive(left) && isPrimitive(right))
|
518 | switch (binaryExpression.operatorToken.kind) {
|
519 | case ts.SyntaxKind.BarBarToken:
|
520 | return left || right;
|
521 | case ts.SyntaxKind.AmpersandAmpersandToken:
|
522 | return left && right;
|
523 | case ts.SyntaxKind.AmpersandToken:
|
524 | return left & right;
|
525 | case ts.SyntaxKind.BarToken:
|
526 | return left | right;
|
527 | case ts.SyntaxKind.CaretToken:
|
528 | return left ^ right;
|
529 | case ts.SyntaxKind.EqualsEqualsToken:
|
530 | return left == right;
|
531 | case ts.SyntaxKind.ExclamationEqualsToken:
|
532 | return left != right;
|
533 | case ts.SyntaxKind.EqualsEqualsEqualsToken:
|
534 | return left === right;
|
535 | case ts.SyntaxKind.ExclamationEqualsEqualsToken:
|
536 | return left !== right;
|
537 | case ts.SyntaxKind.LessThanToken:
|
538 | return left < right;
|
539 | case ts.SyntaxKind.GreaterThanToken:
|
540 | return left > right;
|
541 | case ts.SyntaxKind.LessThanEqualsToken:
|
542 | return left <= right;
|
543 | case ts.SyntaxKind.GreaterThanEqualsToken:
|
544 | return left >= right;
|
545 | case ts.SyntaxKind.LessThanLessThanToken:
|
546 | return left << right;
|
547 | case ts.SyntaxKind.GreaterThanGreaterThanToken:
|
548 | return left >> right;
|
549 | case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
|
550 | return left >>> right;
|
551 | case ts.SyntaxKind.PlusToken:
|
552 | return left + right;
|
553 | case ts.SyntaxKind.MinusToken:
|
554 | return left - right;
|
555 | case ts.SyntaxKind.AsteriskToken:
|
556 | return left * right;
|
557 | case ts.SyntaxKind.SlashToken:
|
558 | return left / right;
|
559 | case ts.SyntaxKind.PercentToken:
|
560 | return left % right;
|
561 | }
|
562 | return recordEntry({
|
563 | __symbolic: 'binop',
|
564 | operator: binaryExpression.operatorToken.getText(),
|
565 | left: left,
|
566 | right: right
|
567 | }, node);
|
568 | }
|
569 | break;
|
570 | case ts.SyntaxKind.ConditionalExpression:
|
571 | var conditionalExpression = node;
|
572 | var condition = this.evaluateNode(conditionalExpression.condition);
|
573 | var thenExpression = this.evaluateNode(conditionalExpression.whenTrue);
|
574 | var elseExpression = this.evaluateNode(conditionalExpression.whenFalse);
|
575 | if (isPrimitive(condition)) {
|
576 | return condition ? thenExpression : elseExpression;
|
577 | }
|
578 | return recordEntry({ __symbolic: 'if', condition: condition, thenExpression: thenExpression, elseExpression: elseExpression }, node);
|
579 | case ts.SyntaxKind.FunctionExpression:
|
580 | case ts.SyntaxKind.ArrowFunction:
|
581 | return recordEntry(errorSymbol('Function call not supported', node), node);
|
582 | case ts.SyntaxKind.TaggedTemplateExpression:
|
583 | return recordEntry(errorSymbol('Tagged template expressions are not supported in metadata', node), node);
|
584 | case ts.SyntaxKind.TemplateExpression:
|
585 | var templateExpression = node;
|
586 | if (this.isFoldable(node)) {
|
587 | return templateExpression.templateSpans.reduce(function (previous, current) { return previous + _this.evaluateNode(current.expression) +
|
588 | _this.evaluateNode(current.literal); }, this.evaluateNode(templateExpression.head));
|
589 | }
|
590 | else {
|
591 | return templateExpression.templateSpans.reduce(function (previous, current) {
|
592 | var expr = _this.evaluateNode(current.expression);
|
593 | var literal = _this.evaluateNode(current.literal);
|
594 | if (isFoldableError(expr))
|
595 | return expr;
|
596 | if (isFoldableError(literal))
|
597 | return literal;
|
598 | if (typeof previous === 'string' && typeof expr === 'string' &&
|
599 | typeof literal === 'string') {
|
600 | return previous + expr + literal;
|
601 | }
|
602 | var result = expr;
|
603 | if (previous !== '') {
|
604 | result = { __symbolic: 'binop', operator: '+', left: previous, right: expr };
|
605 | }
|
606 | if (literal != '') {
|
607 | result = { __symbolic: 'binop', operator: '+', left: result, right: literal };
|
608 | }
|
609 | return result;
|
610 | }, this.evaluateNode(templateExpression.head));
|
611 | }
|
612 | case ts.SyntaxKind.AsExpression:
|
613 | var asExpression = node;
|
614 | return this.evaluateNode(asExpression.expression);
|
615 | case ts.SyntaxKind.ClassExpression:
|
616 | return { __symbolic: 'class' };
|
617 | }
|
618 | return recordEntry(errorSymbol('Expression form not supported', node), node);
|
619 | };
|
620 | return Evaluator;
|
621 | }());
|
622 | exports.Evaluator = Evaluator;
|
623 | function isPropertyAssignment(node) {
|
624 | return node.kind == ts.SyntaxKind.PropertyAssignment;
|
625 | }
|
626 | var empty = [];
|
627 | function arrayOrEmpty(v) {
|
628 | return v || empty;
|
629 | }
|
630 |
|
\ | No newline at end of file |