UNPKG

32.2 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright Google Inc. All Rights Reserved.
4 *
5 * Use of this source code is governed by an MIT-style license that can be
6 * found in the LICENSE file at https://angular.io/license
7 */
8"use strict";
9var __extends = (this && this.__extends) || function (d, b) {
10 for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
11 function __() { this.constructor = d; }
12 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
13};
14var core_1 = require('@angular/core');
15var SUPPORTED_SCHEMA_VERSION = 1;
16/**
17 * A token representing the a reference to a static type.
18 *
19 * This token is unique for a filePath and name and can be used as a hash table key.
20 */
21var StaticSymbol = (function () {
22 function StaticSymbol(filePath, name, members) {
23 this.filePath = filePath;
24 this.name = name;
25 this.members = members;
26 }
27 return StaticSymbol;
28}());
29exports.StaticSymbol = StaticSymbol;
30/**
31 * A static reflector implements enough of the Reflector API that is necessary to compile
32 * templates statically.
33 */
34var StaticReflector = (function () {
35 function StaticReflector(host) {
36 this.host = host;
37 this.annotationCache = new Map();
38 this.propertyCache = new Map();
39 this.parameterCache = new Map();
40 this.metadataCache = new Map();
41 this.conversionMap = new Map();
42 this.initializeConversionMap();
43 }
44 StaticReflector.prototype.importUri = function (typeOrFunc) {
45 var staticSymbol = this.host.findDeclaration(typeOrFunc.filePath, typeOrFunc.name, '');
46 return staticSymbol ? staticSymbol.filePath : null;
47 };
48 StaticReflector.prototype.resolveIdentifier = function (name, moduleUrl, runtime) {
49 return this.host.findDeclaration(moduleUrl, name, '');
50 };
51 StaticReflector.prototype.resolveEnum = function (enumIdentifier, name) {
52 var staticSymbol = enumIdentifier;
53 return this.host.getStaticSymbol(staticSymbol.filePath, staticSymbol.name, [name]);
54 };
55 StaticReflector.prototype.annotations = function (type) {
56 var annotations = this.annotationCache.get(type);
57 if (!annotations) {
58 var classMetadata = this.getTypeMetadata(type);
59 if (classMetadata['decorators']) {
60 annotations = this.simplify(type, classMetadata['decorators']);
61 }
62 else {
63 annotations = [];
64 }
65 this.annotationCache.set(type, annotations.filter(function (ann) { return !!ann; }));
66 }
67 return annotations;
68 };
69 StaticReflector.prototype.propMetadata = function (type) {
70 var _this = this;
71 var propMetadata = this.propertyCache.get(type);
72 if (!propMetadata) {
73 var classMetadata = this.getTypeMetadata(type);
74 var members = classMetadata ? classMetadata['members'] : {};
75 propMetadata = mapStringMap(members, function (propData, propName) {
76 var prop = propData
77 .find(function (a) { return a['__symbolic'] == 'property' || a['__symbolic'] == 'method'; });
78 if (prop && prop['decorators']) {
79 return _this.simplify(type, prop['decorators']);
80 }
81 else {
82 return [];
83 }
84 });
85 this.propertyCache.set(type, propMetadata);
86 }
87 return propMetadata;
88 };
89 StaticReflector.prototype.parameters = function (type) {
90 if (!(type instanceof StaticSymbol)) {
91 throw new Error("parameters received " + JSON.stringify(type) + " which is not a StaticSymbol");
92 }
93 try {
94 var parameters_1 = this.parameterCache.get(type);
95 if (!parameters_1) {
96 var classMetadata = this.getTypeMetadata(type);
97 var members = classMetadata ? classMetadata['members'] : null;
98 var ctorData = members ? members['__ctor__'] : null;
99 if (ctorData) {
100 var ctor = ctorData.find(function (a) { return a['__symbolic'] == 'constructor'; });
101 var parameterTypes = this.simplify(type, ctor['parameters'] || []);
102 var parameterDecorators_1 = this.simplify(type, ctor['parameterDecorators'] || []);
103 parameters_1 = [];
104 parameterTypes.forEach(function (paramType, index) {
105 var nestedResult = [];
106 if (paramType) {
107 nestedResult.push(paramType);
108 }
109 var decorators = parameterDecorators_1 ? parameterDecorators_1[index] : null;
110 if (decorators) {
111 nestedResult.push.apply(nestedResult, decorators);
112 }
113 parameters_1.push(nestedResult);
114 });
115 }
116 if (!parameters_1) {
117 parameters_1 = [];
118 }
119 this.parameterCache.set(type, parameters_1);
120 }
121 return parameters_1;
122 }
123 catch (e) {
124 console.error("Failed on type " + JSON.stringify(type) + " with error " + e);
125 throw e;
126 }
127 };
128 StaticReflector.prototype.hasLifecycleHook = function (type, lcProperty) {
129 if (!(type instanceof StaticSymbol)) {
130 throw new Error("hasLifecycleHook received " + JSON.stringify(type) + " which is not a StaticSymbol");
131 }
132 var classMetadata = this.getTypeMetadata(type);
133 var members = classMetadata ? classMetadata['members'] : null;
134 var member = members && members.hasOwnProperty(lcProperty) ? members[lcProperty] : null;
135 return member ? member.some(function (a) { return a['__symbolic'] == 'method'; }) : false;
136 };
137 StaticReflector.prototype.registerDecoratorOrConstructor = function (type, ctor) {
138 this.conversionMap.set(type, function (context, args) { return new (ctor.bind.apply(ctor, [void 0].concat(args)))(); });
139 };
140 StaticReflector.prototype.registerFunction = function (type, fn) {
141 this.conversionMap.set(type, function (context, args) { return fn.apply(undefined, args); });
142 };
143 StaticReflector.prototype.initializeConversionMap = function () {
144 var _a = this.host.angularImportLocations(), coreDecorators = _a.coreDecorators, diDecorators = _a.diDecorators, diMetadata = _a.diMetadata, diOpaqueToken = _a.diOpaqueToken, animationMetadata = _a.animationMetadata, provider = _a.provider;
145 this.opaqueToken = this.host.findDeclaration(diOpaqueToken, 'OpaqueToken');
146 this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Host'), core_1.Host);
147 this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Injectable'), core_1.Injectable);
148 this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Self'), core_1.Self);
149 this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'SkipSelf'), core_1.SkipSelf);
150 this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Inject'), core_1.Inject);
151 this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Optional'), core_1.Optional);
152 this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Attribute'), core_1.Attribute);
153 this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ContentChild'), core_1.ContentChild);
154 this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ContentChildren'), core_1.ContentChildren);
155 this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ViewChild'), core_1.ViewChild);
156 this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ViewChildren'), core_1.ViewChildren);
157 this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Input'), core_1.Input);
158 this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Output'), core_1.Output);
159 this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Pipe'), core_1.Pipe);
160 this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'HostBinding'), core_1.HostBinding);
161 this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'HostListener'), core_1.HostListener);
162 this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Directive'), core_1.Directive);
163 this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Component'), core_1.Component);
164 this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'NgModule'), core_1.NgModule);
165 // Note: Some metadata classes can be used directly with Provider.deps.
166 this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'Host'), core_1.Host);
167 this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'Self'), core_1.Self);
168 this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'SkipSelf'), core_1.SkipSelf);
169 this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'Optional'), core_1.Optional);
170 this.registerFunction(this.host.findDeclaration(animationMetadata, 'trigger'), core_1.trigger);
171 this.registerFunction(this.host.findDeclaration(animationMetadata, 'state'), core_1.state);
172 this.registerFunction(this.host.findDeclaration(animationMetadata, 'transition'), core_1.transition);
173 this.registerFunction(this.host.findDeclaration(animationMetadata, 'style'), core_1.style);
174 this.registerFunction(this.host.findDeclaration(animationMetadata, 'animate'), core_1.animate);
175 this.registerFunction(this.host.findDeclaration(animationMetadata, 'keyframes'), core_1.keyframes);
176 this.registerFunction(this.host.findDeclaration(animationMetadata, 'sequence'), core_1.sequence);
177 this.registerFunction(this.host.findDeclaration(animationMetadata, 'group'), core_1.group);
178 };
179 /** @internal */
180 StaticReflector.prototype.simplify = function (context, value) {
181 var _this = this;
182 var scope = BindingScope.empty;
183 var calling = new Map();
184 function simplifyInContext(context, value, depth) {
185 function resolveReference(context, expression) {
186 var staticSymbol;
187 if (expression['module']) {
188 staticSymbol = _this.host.findDeclaration(expression['module'], expression['name'], context.filePath);
189 }
190 else {
191 staticSymbol = _this.host.getStaticSymbol(context.filePath, expression['name']);
192 }
193 return staticSymbol;
194 }
195 function resolveReferenceValue(staticSymbol) {
196 var moduleMetadata = _this.getModuleMetadata(staticSymbol.filePath);
197 var declarationValue = moduleMetadata ? moduleMetadata['metadata'][staticSymbol.name] : null;
198 return declarationValue;
199 }
200 function isOpaqueToken(context, value) {
201 if (value && value.__symbolic === 'new' && value.expression) {
202 var target = value.expression;
203 if (target.__symbolic == 'reference') {
204 return sameSymbol(resolveReference(context, target), _this.opaqueToken);
205 }
206 }
207 return false;
208 }
209 function simplifyCall(expression) {
210 var callContext = undefined;
211 if (expression['__symbolic'] == 'call') {
212 var target = expression['expression'];
213 var functionSymbol = void 0;
214 var targetFunction = void 0;
215 if (target) {
216 switch (target.__symbolic) {
217 case 'reference':
218 // Find the function to call.
219 callContext = { name: target.name };
220 functionSymbol = resolveReference(context, target);
221 targetFunction = resolveReferenceValue(functionSymbol);
222 break;
223 case 'select':
224 // Find the static method to call
225 if (target.expression.__symbolic == 'reference') {
226 functionSymbol = resolveReference(context, target.expression);
227 var classData = resolveReferenceValue(functionSymbol);
228 if (classData && classData.statics) {
229 targetFunction = classData.statics[target.member];
230 }
231 }
232 break;
233 }
234 }
235 if (targetFunction && targetFunction['__symbolic'] == 'function') {
236 if (calling.get(functionSymbol)) {
237 throw new Error('Recursion not supported');
238 }
239 calling.set(functionSymbol, true);
240 try {
241 var value_1 = targetFunction['value'];
242 if (value_1 && (depth != 0 || value_1.__symbolic != 'error')) {
243 // Determine the arguments
244 var args = (expression['arguments'] || []).map(function (arg) { return simplify(arg); });
245 var parameters = targetFunction['parameters'];
246 var defaults = targetFunction.defaults;
247 if (defaults && defaults.length > args.length) {
248 args.push.apply(args, defaults.slice(args.length).map(function (value) { return simplify(value); }));
249 }
250 var functionScope = BindingScope.build();
251 for (var i = 0; i < parameters.length; i++) {
252 functionScope.define(parameters[i], args[i]);
253 }
254 var oldScope = scope;
255 var result_1;
256 try {
257 scope = functionScope.done();
258 result_1 = simplifyInContext(functionSymbol, value_1, depth + 1);
259 }
260 finally {
261 scope = oldScope;
262 }
263 return result_1;
264 }
265 }
266 finally {
267 calling.delete(functionSymbol);
268 }
269 }
270 }
271 if (depth === 0) {
272 // If depth is 0 we are evaluating the top level expression that is describing element
273 // decorator. In this case, it is a decorator we don't understand, such as a custom
274 // non-angular decorator, and we should just ignore it.
275 return { __symbolic: 'ignore' };
276 }
277 return simplify({ __symbolic: 'error', message: 'Function call not supported', context: callContext });
278 }
279 function simplify(expression) {
280 if (isPrimitive(expression)) {
281 return expression;
282 }
283 if (expression instanceof Array) {
284 var result_2 = [];
285 for (var _i = 0, _a = expression; _i < _a.length; _i++) {
286 var item = _a[_i];
287 // Check for a spread expression
288 if (item && item.__symbolic === 'spread') {
289 var spreadArray = simplify(item.expression);
290 if (Array.isArray(spreadArray)) {
291 for (var _b = 0, spreadArray_1 = spreadArray; _b < spreadArray_1.length; _b++) {
292 var spreadItem = spreadArray_1[_b];
293 result_2.push(spreadItem);
294 }
295 continue;
296 }
297 }
298 var value_2 = simplify(item);
299 if (shouldIgnore(value_2)) {
300 continue;
301 }
302 result_2.push(value_2);
303 }
304 return result_2;
305 }
306 if (expression instanceof StaticSymbol) {
307 return expression;
308 }
309 if (expression) {
310 if (expression['__symbolic']) {
311 var staticSymbol = void 0;
312 switch (expression['__symbolic']) {
313 case 'binop':
314 var left = simplify(expression['left']);
315 if (shouldIgnore(left))
316 return left;
317 var right = simplify(expression['right']);
318 if (shouldIgnore(right))
319 return right;
320 switch (expression['operator']) {
321 case '&&':
322 return left && right;
323 case '||':
324 return left || right;
325 case '|':
326 return left | right;
327 case '^':
328 return left ^ right;
329 case '&':
330 return left & right;
331 case '==':
332 return left == right;
333 case '!=':
334 return left != right;
335 case '===':
336 return left === right;
337 case '!==':
338 return left !== right;
339 case '<':
340 return left < right;
341 case '>':
342 return left > right;
343 case '<=':
344 return left <= right;
345 case '>=':
346 return left >= right;
347 case '<<':
348 return left << right;
349 case '>>':
350 return left >> right;
351 case '+':
352 return left + right;
353 case '-':
354 return left - right;
355 case '*':
356 return left * right;
357 case '/':
358 return left / right;
359 case '%':
360 return left % right;
361 }
362 return null;
363 case 'if':
364 var condition = simplify(expression['condition']);
365 return condition ? simplify(expression['thenExpression']) :
366 simplify(expression['elseExpression']);
367 case 'pre':
368 var operand = simplify(expression['operand']);
369 if (shouldIgnore(operand))
370 return operand;
371 switch (expression['operator']) {
372 case '+':
373 return operand;
374 case '-':
375 return -operand;
376 case '!':
377 return !operand;
378 case '~':
379 return ~operand;
380 }
381 return null;
382 case 'index':
383 var indexTarget = simplify(expression['expression']);
384 var index = simplify(expression['index']);
385 if (indexTarget && isPrimitive(index))
386 return indexTarget[index];
387 return null;
388 case 'select':
389 var selectTarget = simplify(expression['expression']);
390 if (selectTarget instanceof StaticSymbol) {
391 // Access to a static instance variable
392 var declarationValue_1 = resolveReferenceValue(selectTarget);
393 if (declarationValue_1 && declarationValue_1.statics) {
394 selectTarget = declarationValue_1.statics;
395 }
396 else {
397 var member_1 = expression['member'];
398 var members = selectTarget.members ?
399 selectTarget.members.concat(member_1) :
400 [member_1];
401 return _this.host.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
402 }
403 }
404 var member = simplify(expression['member']);
405 if (selectTarget && isPrimitive(member))
406 return simplify(selectTarget[member]);
407 return null;
408 case 'reference':
409 if (!expression.module) {
410 var name_1 = expression['name'];
411 var localValue = scope.resolve(name_1);
412 if (localValue != BindingScope.missing) {
413 return localValue;
414 }
415 }
416 staticSymbol = resolveReference(context, expression);
417 var result_3 = staticSymbol;
418 var declarationValue = resolveReferenceValue(result_3);
419 if (declarationValue) {
420 if (isOpaqueToken(staticSymbol, declarationValue)) {
421 // If the referenced symbol is initalized by a new OpaqueToken we can keep the
422 // reference to the symbol.
423 return staticSymbol;
424 }
425 result_3 = simplifyInContext(staticSymbol, declarationValue, depth + 1);
426 }
427 return result_3;
428 case 'class':
429 return context;
430 case 'function':
431 return context;
432 case 'new':
433 case 'call':
434 // Determine if the function is a built-in conversion
435 var target = expression['expression'];
436 if (target['module']) {
437 staticSymbol = _this.host.findDeclaration(target['module'], target['name'], context.filePath);
438 }
439 else {
440 staticSymbol = _this.host.getStaticSymbol(context.filePath, target['name']);
441 }
442 var converter = _this.conversionMap.get(staticSymbol);
443 if (converter) {
444 var args = expression['arguments'];
445 if (!args) {
446 args = [];
447 }
448 return converter(context, args.map(function (arg) { return simplifyInContext(context, arg, depth + 1); }));
449 }
450 // Determine if the function is one we can simplify.
451 return simplifyCall(expression);
452 case 'error':
453 var message = produceErrorMessage(expression);
454 if (expression['line']) {
455 message =
456 message + " (position " + (expression['line'] + 1) + ":" + (expression['character'] + 1) + " in the original .ts file)";
457 throw positionalError(message, context.filePath, expression['line'], expression['character']);
458 }
459 throw new Error(message);
460 }
461 return null;
462 }
463 return mapStringMap(expression, function (value, name) { return simplify(value); });
464 }
465 return null;
466 }
467 try {
468 return simplify(value);
469 }
470 catch (e) {
471 var message = e.message + ", resolving symbol " + context.name + " in " + context.filePath;
472 if (e.fileName) {
473 throw positionalError(message, e.fileName, e.line, e.column);
474 }
475 throw new Error(message);
476 }
477 }
478 var result = simplifyInContext(context, value, 0);
479 if (shouldIgnore(result)) {
480 return undefined;
481 }
482 return result;
483 };
484 /**
485 * @param module an absolute path to a module file.
486 */
487 StaticReflector.prototype.getModuleMetadata = function (module) {
488 var moduleMetadata = this.metadataCache.get(module);
489 if (!moduleMetadata) {
490 moduleMetadata = this.host.getMetadataFor(module);
491 if (Array.isArray(moduleMetadata)) {
492 moduleMetadata = moduleMetadata.find(function (md) { return md['version'] === SUPPORTED_SCHEMA_VERSION; }) ||
493 moduleMetadata[0];
494 }
495 if (!moduleMetadata) {
496 moduleMetadata =
497 { __symbolic: 'module', version: SUPPORTED_SCHEMA_VERSION, module: module, metadata: {} };
498 }
499 if (moduleMetadata['version'] != SUPPORTED_SCHEMA_VERSION) {
500 throw new Error("Metadata version mismatch for module " + module + ", found version " + moduleMetadata['version'] + ", expected " + SUPPORTED_SCHEMA_VERSION);
501 }
502 this.metadataCache.set(module, moduleMetadata);
503 }
504 return moduleMetadata;
505 };
506 StaticReflector.prototype.getTypeMetadata = function (type) {
507 var moduleMetadata = this.getModuleMetadata(type.filePath);
508 return moduleMetadata['metadata'][type.name] || { __symbolic: 'class' };
509 };
510 return StaticReflector;
511}());
512exports.StaticReflector = StaticReflector;
513function expandedMessage(error) {
514 switch (error.message) {
515 case 'Reference to non-exported class':
516 if (error.context && error.context.className) {
517 return "Reference to a non-exported class " + error.context.className + ". Consider exporting the class";
518 }
519 break;
520 case 'Variable not initialized':
521 return 'Only initialized variables and constants can be referenced because the value of this variable is needed by the template compiler';
522 case 'Destructuring not supported':
523 return 'Referencing an exported destructured variable or constant is not supported by the template compiler. Consider simplifying this to avoid destructuring';
524 case 'Could not resolve type':
525 if (error.context && error.context.typeName) {
526 return "Could not resolve type " + error.context.typeName;
527 }
528 break;
529 case 'Function call not supported':
530 var prefix = error.context && error.context.name ? "Calling function '" + error.context.name + "', f" : 'F';
531 return prefix +
532 'unction calls are not supported. Consider replacing the function or lambda with a reference to an exported function';
533 case 'Reference to a local symbol':
534 if (error.context && error.context.name) {
535 return "Reference to a local (non-exported) symbol '" + error.context.name + "'. Consider exporting the symbol";
536 }
537 }
538 return error.message;
539}
540function produceErrorMessage(error) {
541 return "Error encountered resolving symbol values statically. " + expandedMessage(error);
542}
543function mapStringMap(input, transform) {
544 if (!input)
545 return {};
546 var result = {};
547 Object.keys(input).forEach(function (key) {
548 var value = transform(input[key], key);
549 if (!shouldIgnore(value)) {
550 result[key] = value;
551 }
552 });
553 return result;
554}
555function isPrimitive(o) {
556 return o === null || (typeof o !== 'function' && typeof o !== 'object');
557}
558var BindingScope = (function () {
559 function BindingScope() {
560 }
561 BindingScope.build = function () {
562 var current = new Map();
563 return {
564 define: function (name, value) {
565 current.set(name, value);
566 return this;
567 },
568 done: function () {
569 return current.size > 0 ? new PopulatedScope(current) : BindingScope.empty;
570 }
571 };
572 };
573 BindingScope.missing = {};
574 BindingScope.empty = { resolve: function (name) { return BindingScope.missing; } };
575 return BindingScope;
576}());
577var PopulatedScope = (function (_super) {
578 __extends(PopulatedScope, _super);
579 function PopulatedScope(bindings) {
580 _super.call(this);
581 this.bindings = bindings;
582 }
583 PopulatedScope.prototype.resolve = function (name) {
584 return this.bindings.has(name) ? this.bindings.get(name) : BindingScope.missing;
585 };
586 return PopulatedScope;
587}(BindingScope));
588function sameSymbol(a, b) {
589 return a === b || (a.name == b.name && a.filePath == b.filePath);
590}
591function shouldIgnore(value) {
592 return value && value.__symbolic == 'ignore';
593}
594function positionalError(message, fileName, line, column) {
595 var result = new Error(message);
596 result.fileName = fileName;
597 result.line = line;
598 result.column = column;
599 return result;
600}
601//# sourceMappingURL=static_reflector.js.map
\No newline at end of file