UNPKG

32.2 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright Google Inc. All Rights Reserved.
5 *
6 * Use of this source code is governed by an MIT-style license that can be
7 * found in the LICENSE file at https://angular.io/license
8 */
9Object.defineProperty(exports, "__esModule", { value: true });
10var ts = require("typescript");
11var schema_1 = require("./schema");
12// In TypeScript 2.1 the spread element kind was renamed.
13var spreadElementSyntaxKind = ts.SyntaxKind.SpreadElement || ts.SyntaxKind.SpreadElementExpression;
14function 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}
25function 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 * ts.forEachChild stops iterating children when the callback return a truthy value.
35 * This method inverts this to implement an `every` style iterator. It will return
36 * true if every call to `cb` returns `true`.
37 */
38function everyNodeChild(node, cb) {
39 return !ts.forEachChild(node, function (node) { return !cb(node); });
40}
41function isPrimitive(value) {
42 return Object(value) !== value;
43}
44exports.isPrimitive = isPrimitive;
45function isDefined(obj) {
46 return obj !== undefined;
47}
48function getSourceFileOfNode(node) {
49 while (node && node.kind != ts.SyntaxKind.SourceFile) {
50 node = node.parent;
51 }
52 return node;
53}
54/* @internal */
55function 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}
72exports.errorSymbol = errorSymbol;
73/**
74 * Produce a symbolic representation of an expression folding values into their final value when
75 * possible.
76 */
77var 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 * Returns true if the expression represented by `node` can be folded into a literal expression.
98 *
99 * For example, a literal is always foldable. This means that literal expressions such as `1.2`
100 * `"Some value"` `true` `false` are foldable.
101 *
102 * - An object literal is foldable if all the properties in the literal are foldable.
103 * - An array literal is foldable if all the elements are foldable.
104 * - A call is foldable if it is a call to a Array.prototype.concat or a call to CONST_EXPR.
105 * - A property access is foldable if the object is foldable.
106 * - A array index is foldable if index expression is foldable and the array is foldable.
107 * - Binary operator expressions are foldable if the left and right expressions are foldable and
108 * it is one of '+', '-', '*', '/', '%', '||', and '&&'.
109 * - An identifier is foldable if a value can be found for its symbol in the evaluator symbol
110 * table.
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 // We can fold a <array>.concat(<v>).
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 // It needs to be an array.
138 var arrayValue = this.evaluateNode(arrayNode);
139 if (arrayValue && Array.isArray(arrayValue)) {
140 return true;
141 }
142 }
143 }
144 // We can fold a call to CONST_EXPR
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 * Produce a JSON serialiable object representing `node`. The foldable values in the expression
200 * tree are folded. For example, a node representing `1 + 2` is folded into `3`.
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 // Encode as a global reference. StaticReflector will check the reference.
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, /* preferReference */ true) :
241 resolveName(propertyName, /* preferReference */ true);
242 if (isFoldableError(propertyValue)) {
243 error = propertyValue;
244 return true; // Stop the forEachChild.
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, /* preferReference */ true);
261 // Check for error
262 if (isFoldableError(value)) {
263 error = value;
264 return true; // Stop the forEachChild.
265 }
266 // Handle spread expressions
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 // Always fold a CONST_EXPR even if the argument is not foldable.
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 // A select into a module reference and be converted into a reference to the symbol
349 // in the module
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 // Record a type reference to a declared type as a select.
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 // TODO: Remove typecast when upgraded to 2.0 as it will be corretly inferred.
410 // Some versions of 1.9 do not infer this correctly.
411 typeReference.arguments = args_2;
412 }
413 return recordEntry(typeReference, node);
414 case ts.SyntaxKind.UnionType:
415 var unionType = node;
416 // Remove null and undefined from the list of unions.
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 // The remmaining reference must be the same. If two have type arguments consider them
422 // different even if the type arguments are the same.
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}());
622exports.Evaluator = Evaluator;
623function isPropertyAssignment(node) {
624 return node.kind == ts.SyntaxKind.PropertyAssignment;
625}
626var empty = [];
627function arrayOrEmpty(v) {
628 return v || empty;
629}
630//# sourceMappingURL=evaluator.js.map
\No newline at end of file