@angular/compiler
Version:
Angular - the compiler library
933 lines • 150 kB
JavaScript
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { CompileSummaryKind } from '../compile_metadata';
import { createAttribute, createComponent, createContentChild, createContentChildren, createDirective, createHost, createHostBinding, createHostListener, createInject, createInjectable, createInput, createNgModule, createOptional, createOutput, createPipe, createSelf, createSkipSelf, createViewChild, createViewChildren } from '../core';
import { syntaxError } from '../parse_util';
import { formattedError } from './formatted_error';
import { StaticSymbol } from './static_symbol';
const ANGULAR_CORE = '@angular/core';
const ANGULAR_ROUTER = '@angular/router';
const HIDDEN_KEY = /^\$.*\$$/;
const IGNORE = {
__symbolic: 'ignore'
};
const USE_VALUE = 'useValue';
const PROVIDE = 'provide';
const REFERENCE_SET = new Set([USE_VALUE, 'useFactory', 'data', 'id', 'loadChildren']);
const TYPEGUARD_POSTFIX = 'TypeGuard';
const USE_IF = 'UseIf';
function shouldIgnore(value) {
return value && value.__symbolic == 'ignore';
}
/**
* A static reflector implements enough of the Reflector API that is necessary to compile
* templates statically.
*/
export class StaticReflector {
constructor(summaryResolver, symbolResolver, knownMetadataClasses = [], knownMetadataFunctions = [], errorRecorder) {
this.summaryResolver = summaryResolver;
this.symbolResolver = symbolResolver;
this.errorRecorder = errorRecorder;
this.annotationCache = new Map();
this.shallowAnnotationCache = new Map();
this.propertyCache = new Map();
this.parameterCache = new Map();
this.methodCache = new Map();
this.staticCache = new Map();
this.conversionMap = new Map();
this.resolvedExternalReferences = new Map();
this.annotationForParentClassWithSummaryKind = new Map();
this.initializeConversionMap();
knownMetadataClasses.forEach((kc) => this._registerDecoratorOrConstructor(this.getStaticSymbol(kc.filePath, kc.name), kc.ctor));
knownMetadataFunctions.forEach((kf) => this._registerFunction(this.getStaticSymbol(kf.filePath, kf.name), kf.fn));
this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.Directive, [createDirective, createComponent]);
this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.Pipe, [createPipe]);
this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.NgModule, [createNgModule]);
this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.Injectable, [createInjectable, createPipe, createDirective, createComponent, createNgModule]);
}
componentModuleUrl(typeOrFunc) {
const staticSymbol = this.findSymbolDeclaration(typeOrFunc);
return this.symbolResolver.getResourcePath(staticSymbol);
}
/**
* Invalidate the specified `symbols` on program change.
* @param symbols
*/
invalidateSymbols(symbols) {
for (const symbol of symbols) {
this.annotationCache.delete(symbol);
this.shallowAnnotationCache.delete(symbol);
this.propertyCache.delete(symbol);
this.parameterCache.delete(symbol);
this.methodCache.delete(symbol);
this.staticCache.delete(symbol);
this.conversionMap.delete(symbol);
}
}
resolveExternalReference(ref, containingFile) {
let key = undefined;
if (!containingFile) {
key = `${ref.moduleName}:${ref.name}`;
const declarationSymbol = this.resolvedExternalReferences.get(key);
if (declarationSymbol)
return declarationSymbol;
}
const refSymbol = this.symbolResolver.getSymbolByModule(ref.moduleName, ref.name, containingFile);
const declarationSymbol = this.findSymbolDeclaration(refSymbol);
if (!containingFile) {
this.symbolResolver.recordModuleNameForFileName(refSymbol.filePath, ref.moduleName);
this.symbolResolver.recordImportAs(declarationSymbol, refSymbol);
}
if (key) {
this.resolvedExternalReferences.set(key, declarationSymbol);
}
return declarationSymbol;
}
findDeclaration(moduleUrl, name, containingFile) {
return this.findSymbolDeclaration(this.symbolResolver.getSymbolByModule(moduleUrl, name, containingFile));
}
tryFindDeclaration(moduleUrl, name, containingFile) {
return this.symbolResolver.ignoreErrorsFor(() => this.findDeclaration(moduleUrl, name, containingFile));
}
findSymbolDeclaration(symbol) {
const resolvedSymbol = this.symbolResolver.resolveSymbol(symbol);
if (resolvedSymbol) {
let resolvedMetadata = resolvedSymbol.metadata;
if (resolvedMetadata && resolvedMetadata.__symbolic === 'resolved') {
resolvedMetadata = resolvedMetadata.symbol;
}
if (resolvedMetadata instanceof StaticSymbol) {
return this.findSymbolDeclaration(resolvedSymbol.metadata);
}
}
return symbol;
}
tryAnnotations(type) {
const originalRecorder = this.errorRecorder;
this.errorRecorder = (error, fileName) => { };
try {
return this.annotations(type);
}
finally {
this.errorRecorder = originalRecorder;
}
}
annotations(type) {
return this._annotations(type, (type, decorators) => this.simplify(type, decorators), this.annotationCache);
}
shallowAnnotations(type) {
return this._annotations(type, (type, decorators) => this.simplify(type, decorators, true), this.shallowAnnotationCache);
}
_annotations(type, simplify, annotationCache) {
let annotations = annotationCache.get(type);
if (!annotations) {
annotations = [];
const classMetadata = this.getTypeMetadata(type);
const parentType = this.findParentType(type, classMetadata);
if (parentType) {
const parentAnnotations = this.annotations(parentType);
annotations.push(...parentAnnotations);
}
let ownAnnotations = [];
if (classMetadata['decorators']) {
ownAnnotations = simplify(type, classMetadata['decorators']);
if (ownAnnotations) {
annotations.push(...ownAnnotations);
}
}
if (parentType && !this.summaryResolver.isLibraryFile(type.filePath) &&
this.summaryResolver.isLibraryFile(parentType.filePath)) {
const summary = this.summaryResolver.resolveSummary(parentType);
if (summary && summary.type) {
const requiredAnnotationTypes = this.annotationForParentClassWithSummaryKind.get(summary.type.summaryKind);
const typeHasRequiredAnnotation = requiredAnnotationTypes.some((requiredType) => ownAnnotations.some(ann => requiredType.isTypeOf(ann)));
if (!typeHasRequiredAnnotation) {
this.reportError(formatMetadataError(metadataError(`Class ${type.name} in ${type.filePath} extends from a ${CompileSummaryKind[summary.type.summaryKind]} in another compilation unit without duplicating the decorator`,
/* summary */ undefined, `Please add a ${requiredAnnotationTypes.map((type) => type.ngMetadataName)
.join(' or ')} decorator to the class`), type), type);
}
}
}
annotationCache.set(type, annotations.filter(ann => !!ann));
}
return annotations;
}
propMetadata(type) {
let propMetadata = this.propertyCache.get(type);
if (!propMetadata) {
const classMetadata = this.getTypeMetadata(type);
propMetadata = {};
const parentType = this.findParentType(type, classMetadata);
if (parentType) {
const parentPropMetadata = this.propMetadata(parentType);
Object.keys(parentPropMetadata).forEach((parentProp) => {
propMetadata[parentProp] = parentPropMetadata[parentProp];
});
}
const members = classMetadata['members'] || {};
Object.keys(members).forEach((propName) => {
const propData = members[propName];
const prop = propData
.find(a => a['__symbolic'] == 'property' || a['__symbolic'] == 'method');
const decorators = [];
// hasOwnProperty() is used here to make sure we do not look up methods
// on `Object.prototype`.
if (propMetadata?.hasOwnProperty(propName)) {
decorators.push(...propMetadata[propName]);
}
propMetadata[propName] = decorators;
if (prop && prop['decorators']) {
decorators.push(...this.simplify(type, prop['decorators']));
}
});
this.propertyCache.set(type, propMetadata);
}
return propMetadata;
}
parameters(type) {
if (!(type instanceof StaticSymbol)) {
this.reportError(new Error(`parameters received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
return [];
}
try {
let parameters = this.parameterCache.get(type);
if (!parameters) {
const classMetadata = this.getTypeMetadata(type);
const parentType = this.findParentType(type, classMetadata);
const members = classMetadata ? classMetadata['members'] : null;
const ctorData = members ? members['__ctor__'] : null;
if (ctorData) {
const ctor = ctorData.find(a => a['__symbolic'] == 'constructor');
const rawParameterTypes = ctor['parameters'] || [];
const parameterDecorators = this.simplify(type, ctor['parameterDecorators'] || []);
parameters = [];
rawParameterTypes.forEach((rawParamType, index) => {
const nestedResult = [];
const paramType = this.trySimplify(type, rawParamType);
if (paramType)
nestedResult.push(paramType);
const decorators = parameterDecorators ? parameterDecorators[index] : null;
if (decorators) {
nestedResult.push(...decorators);
}
parameters.push(nestedResult);
});
}
else if (parentType) {
parameters = this.parameters(parentType);
}
if (!parameters) {
parameters = [];
}
this.parameterCache.set(type, parameters);
}
return parameters;
}
catch (e) {
console.error(`Failed on type ${JSON.stringify(type)} with error ${e}`);
throw e;
}
}
_methodNames(type) {
let methodNames = this.methodCache.get(type);
if (!methodNames) {
const classMetadata = this.getTypeMetadata(type);
methodNames = {};
const parentType = this.findParentType(type, classMetadata);
if (parentType) {
const parentMethodNames = this._methodNames(parentType);
Object.keys(parentMethodNames).forEach((parentProp) => {
methodNames[parentProp] = parentMethodNames[parentProp];
});
}
const members = classMetadata['members'] || {};
Object.keys(members).forEach((propName) => {
const propData = members[propName];
const isMethod = propData.some(a => a['__symbolic'] == 'method');
methodNames[propName] = methodNames[propName] || isMethod;
});
this.methodCache.set(type, methodNames);
}
return methodNames;
}
_staticMembers(type) {
let staticMembers = this.staticCache.get(type);
if (!staticMembers) {
const classMetadata = this.getTypeMetadata(type);
const staticMemberData = classMetadata['statics'] || {};
staticMembers = Object.keys(staticMemberData);
this.staticCache.set(type, staticMembers);
}
return staticMembers;
}
findParentType(type, classMetadata) {
const parentType = this.trySimplify(type, classMetadata['extends']);
if (parentType instanceof StaticSymbol) {
return parentType;
}
}
hasLifecycleHook(type, lcProperty) {
if (!(type instanceof StaticSymbol)) {
this.reportError(new Error(`hasLifecycleHook received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
}
try {
return !!this._methodNames(type)[lcProperty];
}
catch (e) {
console.error(`Failed on type ${JSON.stringify(type)} with error ${e}`);
throw e;
}
}
guards(type) {
if (!(type instanceof StaticSymbol)) {
this.reportError(new Error(`guards received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
return {};
}
const staticMembers = this._staticMembers(type);
const result = {};
for (let name of staticMembers) {
if (name.endsWith(TYPEGUARD_POSTFIX)) {
let property = name.substr(0, name.length - TYPEGUARD_POSTFIX.length);
let value;
if (property.endsWith(USE_IF)) {
property = name.substr(0, property.length - USE_IF.length);
value = USE_IF;
}
else {
value = this.getStaticSymbol(type.filePath, type.name, [name]);
}
result[property] = value;
}
}
return result;
}
_registerDecoratorOrConstructor(type, ctor) {
this.conversionMap.set(type, (context, args) => new ctor(...args));
}
_registerFunction(type, fn) {
this.conversionMap.set(type, (context, args) => fn.apply(undefined, args));
}
initializeConversionMap() {
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Injectable'), createInjectable);
this.injectionToken = this.findDeclaration(ANGULAR_CORE, 'InjectionToken');
this.opaqueToken = this.findDeclaration(ANGULAR_CORE, 'OpaqueToken');
this.ROUTES = this.tryFindDeclaration(ANGULAR_ROUTER, 'ROUTES');
this.ANALYZE_FOR_ENTRY_COMPONENTS =
this.findDeclaration(ANGULAR_CORE, 'ANALYZE_FOR_ENTRY_COMPONENTS');
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), createHost);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), createSelf);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), createSkipSelf);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Inject'), createInject);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Optional'), createOptional);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Attribute'), createAttribute);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ContentChild'), createContentChild);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ContentChildren'), createContentChildren);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ViewChild'), createViewChild);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ViewChildren'), createViewChildren);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Input'), createInput);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Output'), createOutput);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Pipe'), createPipe);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'HostBinding'), createHostBinding);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'HostListener'), createHostListener);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Directive'), createDirective);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Component'), createComponent);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'NgModule'), createNgModule);
// Note: Some metadata classes can be used directly with Provider.deps.
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), createHost);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), createSelf);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), createSkipSelf);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Optional'), createOptional);
}
/**
* getStaticSymbol produces a Type whose metadata is known but whose implementation is not loaded.
* All types passed to the StaticResolver should be pseudo-types returned by this method.
*
* @param declarationFile the absolute path of the file where the symbol is declared
* @param name the name of the type.
*/
getStaticSymbol(declarationFile, name, members) {
return this.symbolResolver.getStaticSymbol(declarationFile, name, members);
}
/**
* Simplify but discard any errors
*/
trySimplify(context, value) {
const originalRecorder = this.errorRecorder;
this.errorRecorder = (error, fileName) => { };
const result = this.simplify(context, value);
this.errorRecorder = originalRecorder;
return result;
}
/** @internal */
simplify(context, value, lazy = false) {
const self = this;
let scope = BindingScope.empty;
const calling = new Map();
const rootContext = context;
function simplifyInContext(context, value, depth, references) {
function resolveReferenceValue(staticSymbol) {
const resolvedSymbol = self.symbolResolver.resolveSymbol(staticSymbol);
return resolvedSymbol ? resolvedSymbol.metadata : null;
}
function simplifyEagerly(value) {
return simplifyInContext(context, value, depth, 0);
}
function simplifyLazily(value) {
return simplifyInContext(context, value, depth, references + 1);
}
function simplifyNested(nestedContext, value) {
if (nestedContext === context) {
// If the context hasn't changed let the exception propagate unmodified.
return simplifyInContext(nestedContext, value, depth + 1, references);
}
try {
return simplifyInContext(nestedContext, value, depth + 1, references);
}
catch (e) {
if (isMetadataError(e)) {
// Propagate the message text up but add a message to the chain that explains how we got
// here.
// e.chain implies e.symbol
const summaryMsg = e.chain ? 'references \'' + e.symbol.name + '\'' : errorSummary(e);
const summary = `'${nestedContext.name}' ${summaryMsg}`;
const chain = { message: summary, position: e.position, next: e.chain };
// TODO(chuckj): retrieve the position information indirectly from the collectors node
// map if the metadata is from a .ts file.
self.error({
message: e.message,
advise: e.advise,
context: e.context,
chain,
symbol: nestedContext
}, context);
}
else {
// It is probably an internal error.
throw e;
}
}
}
function simplifyCall(functionSymbol, targetFunction, args, targetExpression) {
if (targetFunction && targetFunction['__symbolic'] == 'function') {
if (calling.get(functionSymbol)) {
self.error({
message: 'Recursion is not supported',
summary: `called '${functionSymbol.name}' recursively`,
value: targetFunction
}, functionSymbol);
}
try {
const value = targetFunction['value'];
if (value && (depth != 0 || value.__symbolic != 'error')) {
const parameters = targetFunction['parameters'];
const defaults = targetFunction.defaults;
args = args.map(arg => simplifyNested(context, arg))
.map(arg => shouldIgnore(arg) ? undefined : arg);
if (defaults && defaults.length > args.length) {
args.push(...defaults.slice(args.length).map((value) => simplify(value)));
}
calling.set(functionSymbol, true);
const functionScope = BindingScope.build();
for (let i = 0; i < parameters.length; i++) {
functionScope.define(parameters[i], args[i]);
}
const oldScope = scope;
let result;
try {
scope = functionScope.done();
result = simplifyNested(functionSymbol, value);
}
finally {
scope = oldScope;
}
return result;
}
}
finally {
calling.delete(functionSymbol);
}
}
if (depth === 0) {
// If depth is 0 we are evaluating the top level expression that is describing element
// decorator. In this case, it is a decorator we don't understand, such as a custom
// non-angular decorator, and we should just ignore it.
return IGNORE;
}
let position = undefined;
if (targetExpression && targetExpression.__symbolic == 'resolved') {
const line = targetExpression.line;
const character = targetExpression.character;
const fileName = targetExpression.fileName;
if (fileName != null && line != null && character != null) {
position = { fileName, line, column: character };
}
}
self.error({
message: FUNCTION_CALL_NOT_SUPPORTED,
context: functionSymbol,
value: targetFunction,
position
}, context);
}
function simplify(expression) {
if (isPrimitive(expression)) {
return expression;
}
if (Array.isArray(expression)) {
const result = [];
for (const item of expression) {
// Check for a spread expression
if (item && item.__symbolic === 'spread') {
// We call with references as 0 because we require the actual value and cannot
// tolerate a reference here.
const spreadArray = simplifyEagerly(item.expression);
if (Array.isArray(spreadArray)) {
for (const spreadItem of spreadArray) {
result.push(spreadItem);
}
continue;
}
}
const value = simplify(item);
if (shouldIgnore(value)) {
continue;
}
result.push(value);
}
return result;
}
if (expression instanceof StaticSymbol) {
// Stop simplification at builtin symbols or if we are in a reference context and
// the symbol doesn't have members.
if (expression === self.injectionToken || self.conversionMap.has(expression) ||
(references > 0 && !expression.members.length)) {
return expression;
}
else {
const staticSymbol = expression;
const declarationValue = resolveReferenceValue(staticSymbol);
if (declarationValue != null) {
return simplifyNested(staticSymbol, declarationValue);
}
else {
return staticSymbol;
}
}
}
if (expression) {
if (expression['__symbolic']) {
let staticSymbol;
switch (expression['__symbolic']) {
case 'binop':
let left = simplify(expression['left']);
if (shouldIgnore(left))
return left;
let right = simplify(expression['right']);
if (shouldIgnore(right))
return right;
switch (expression['operator']) {
case '&&':
return left && right;
case '||':
return left || right;
case '|':
return left | right;
case '^':
return left ^ right;
case '&':
return left & right;
case '==':
return left == right;
case '!=':
return left != right;
case '===':
return left === right;
case '!==':
return left !== right;
case '<':
return left < right;
case '>':
return left > right;
case '<=':
return left <= right;
case '>=':
return left >= right;
case '<<':
return left << right;
case '>>':
return left >> right;
case '+':
return left + right;
case '-':
return left - right;
case '*':
return left * right;
case '/':
return left / right;
case '%':
return left % right;
case '??':
return left ?? right;
}
return null;
case 'if':
let condition = simplify(expression['condition']);
return condition ? simplify(expression['thenExpression']) :
simplify(expression['elseExpression']);
case 'pre':
let operand = simplify(expression['operand']);
if (shouldIgnore(operand))
return operand;
switch (expression['operator']) {
case '+':
return operand;
case '-':
return -operand;
case '!':
return !operand;
case '~':
return ~operand;
}
return null;
case 'index':
let indexTarget = simplifyEagerly(expression['expression']);
let index = simplifyEagerly(expression['index']);
if (indexTarget && isPrimitive(index))
return indexTarget[index];
return null;
case 'select':
const member = expression['member'];
let selectContext = context;
let selectTarget = simplify(expression['expression']);
if (selectTarget instanceof StaticSymbol) {
const members = selectTarget.members.concat(member);
selectContext =
self.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
const declarationValue = resolveReferenceValue(selectContext);
if (declarationValue != null) {
return simplifyNested(selectContext, declarationValue);
}
else {
return selectContext;
}
}
if (selectTarget && isPrimitive(member))
return simplifyNested(selectContext, selectTarget[member]);
return null;
case 'reference':
// Note: This only has to deal with variable references, as symbol references have
// been converted into 'resolved'
// in the StaticSymbolResolver.
const name = expression['name'];
const localValue = scope.resolve(name);
if (localValue != BindingScope.missing) {
return localValue;
}
break;
case 'resolved':
try {
return simplify(expression.symbol);
}
catch (e) {
// If an error is reported evaluating the symbol record the position of the
// reference in the error so it can
// be reported in the error message generated from the exception.
if (isMetadataError(e) && expression.fileName != null &&
expression.line != null && expression.character != null) {
e.position = {
fileName: expression.fileName,
line: expression.line,
column: expression.character
};
}
throw e;
}
case 'class':
return context;
case 'function':
return context;
case 'new':
case 'call':
// Determine if the function is a built-in conversion
staticSymbol = simplifyInContext(context, expression['expression'], depth + 1, /* references */ 0);
if (staticSymbol instanceof StaticSymbol) {
if (staticSymbol === self.injectionToken || staticSymbol === self.opaqueToken) {
// if somebody calls new InjectionToken, don't create an InjectionToken,
// but rather return the symbol to which the InjectionToken is assigned to.
// OpaqueToken is supported too as it is required by the language service to
// support v4 and prior versions of Angular.
return context;
}
const argExpressions = expression['arguments'] || [];
let converter = self.conversionMap.get(staticSymbol);
if (converter) {
const args = argExpressions.map(arg => simplifyNested(context, arg))
.map(arg => shouldIgnore(arg) ? undefined : arg);
return converter(context, args);
}
else {
// Determine if the function is one we can simplify.
const targetFunction = resolveReferenceValue(staticSymbol);
return simplifyCall(staticSymbol, targetFunction, argExpressions, expression['expression']);
}
}
return IGNORE;
case 'error':
let message = expression.message;
if (expression['line'] != null) {
self.error({
message,
context: expression.context,
value: expression,
position: {
fileName: expression['fileName'],
line: expression['line'],
column: expression['character']
}
}, context);
}
else {
self.error({ message, context: expression.context }, context);
}
return IGNORE;
case 'ignore':
return expression;
}
return null;
}
return mapStringMap(expression, (value, name) => {
if (REFERENCE_SET.has(name)) {
if (name === USE_VALUE && PROVIDE in expression) {
// If this is a provider expression, check for special tokens that need the value
// during analysis.
const provide = simplify(expression.provide);
if (provide === self.ROUTES || provide == self.ANALYZE_FOR_ENTRY_COMPONENTS) {
return simplify(value);
}
}
return simplifyLazily(value);
}
return simplify(value);
});
}
return IGNORE;
}
return simplify(value);
}
let result;
try {
result = simplifyInContext(context, value, 0, lazy ? 1 : 0);
}
catch (e) {
if (this.errorRecorder) {
this.reportError(e, context);
}
else {
throw formatMetadataError(e, context);
}
}
if (shouldIgnore(result)) {
return undefined;
}
return result;
}
getTypeMetadata(type) {
const resolvedSymbol = this.symbolResolver.resolveSymbol(type);
return resolvedSymbol && resolvedSymbol.metadata ? resolvedSymbol.metadata :
{ __symbolic: 'class' };
}
reportError(error, context, path) {
if (this.errorRecorder) {
this.errorRecorder(formatMetadataError(error, context), (context && context.filePath) || path);
}
else {
throw error;
}
}
error({ message, summary, advise, position, context, value, symbol, chain }, reportingContext) {
this.reportError(metadataError(message, summary, advise, position, symbol, context, chain), reportingContext);
}
}
const METADATA_ERROR = 'ngMetadataError';
function metadataError(message, summary, advise, position, symbol, context, chain) {
const error = syntaxError(message);
error[METADATA_ERROR] = true;
if (advise)
error.advise = advise;
if (position)
error.position = position;
if (summary)
error.summary = summary;
if (context)
error.context = context;
if (chain)
error.chain = chain;
if (symbol)
error.symbol = symbol;
return error;
}
function isMetadataError(error) {
return !!error[METADATA_ERROR];
}
const REFERENCE_TO_NONEXPORTED_CLASS = 'Reference to non-exported class';
const VARIABLE_NOT_INITIALIZED = 'Variable not initialized';
const DESTRUCTURE_NOT_SUPPORTED = 'Destructuring not supported';
const COULD_NOT_RESOLVE_TYPE = 'Could not resolve type';
const FUNCTION_CALL_NOT_SUPPORTED = 'Function call not supported';
const REFERENCE_TO_LOCAL_SYMBOL = 'Reference to a local symbol';
const LAMBDA_NOT_SUPPORTED = 'Lambda not supported';
function expandedMessage(message, context) {
switch (message) {
case REFERENCE_TO_NONEXPORTED_CLASS:
if (context && context.className) {
return `References to a non-exported class are not supported in decorators but ${context.className} was referenced.`;
}
break;
case VARIABLE_NOT_INITIALIZED:
return 'Only initialized variables and constants can be referenced in decorators because the value of this variable is needed by the template compiler';
case DESTRUCTURE_NOT_SUPPORTED:
return 'Referencing an exported destructured variable or constant is not supported in decorators and this value is needed by the template compiler';
case COULD_NOT_RESOLVE_TYPE:
if (context && context.typeName) {
return `Could not resolve type ${context.typeName}`;
}
break;
case FUNCTION_CALL_NOT_SUPPORTED:
if (context && context.name) {
return `Function calls are not supported in decorators but '${context.name}' was called`;
}
return 'Function calls are not supported in decorators';
case REFERENCE_TO_LOCAL_SYMBOL:
if (context && context.name) {
return `Reference to a local (non-exported) symbols are not supported in decorators but '${context.name}' was referenced`;
}
break;
case LAMBDA_NOT_SUPPORTED:
return `Function expressions are not supported in decorators`;
}
return message;
}
function messageAdvise(message, context) {
switch (message) {
case REFERENCE_TO_NONEXPORTED_CLASS:
if (context && context.className) {
return `Consider exporting '${context.className}'`;
}
break;
case DESTRUCTURE_NOT_SUPPORTED:
return 'Consider simplifying to avoid destructuring';
case REFERENCE_TO_LOCAL_SYMBOL:
if (context && context.name) {
return `Consider exporting '${context.name}'`;
}
break;
case LAMBDA_NOT_SUPPORTED:
return `Consider changing the function expression into an exported function`;
}
return undefined;
}
function errorSummary(error) {
if (error.summary) {
return error.summary;
}
switch (error.message) {
case REFERENCE_TO_NONEXPORTED_CLASS:
if (error.context && error.context.className) {
return `references non-exported class ${error.context.className}`;
}
break;
case VARIABLE_NOT_INITIALIZED:
return 'is not initialized';
case DESTRUCTURE_NOT_SUPPORTED:
return 'is a destructured variable';
case COULD_NOT_RESOLVE_TYPE:
return 'could not be resolved';
case FUNCTION_CALL_NOT_SUPPORTED:
if (error.context && error.context.name) {
return `calls '${error.context.name}'`;
}
return `calls a function`;
case REFERENCE_TO_LOCAL_SYMBOL:
if (error.context && error.context.name) {
return `references local variable ${error.context.name}`;
}
return `references a local variable`;
}
return 'contains the error';
}
function mapStringMap(input, transform) {
if (!input)
return {};
const result = {};
Object.keys(input).forEach((key) => {
const value = transform(input[key], key);
if (!shouldIgnore(value)) {
if (HIDDEN_KEY.test(key)) {
Object.defineProperty(result, key, { enumerable: false, configurable: true, value: value });
}
else {
result[key] = value;
}
}
});
return result;
}
function isPrimitive(o) {
return o === null || (typeof o !== 'function' && typeof o !== 'object');
}
class BindingScope {
static build() {
const current = new Map();
return {
define: function (name, value) {
current.set(name, value);
return this;
},
done: function () {
return current.size > 0 ? new PopulatedScope(current) : BindingScope.empty;
}
};
}
}
BindingScope.missing = {};
BindingScope.empty = { resolve: name => BindingScope.missing };
class PopulatedScope extends BindingScope {
constructor(bindings) {
super();
this.bindings = bindings;
}
resolve(name) {
return this.bindings.has(name) ? this.bindings.get(name) : BindingScope.missing;
}
}
function formatMetadataMessageChain(chain, advise) {
const expanded = expandedMessage(chain.message, chain.context);
const nesting = chain.symbol ? ` in '${chain.symbol.name}'` : '';
const message = `${expanded}${nesting}`;
const position = chain.position;
const next = chain.next ?
formatMetadataMessageChain(chain.next, advise) :
advise ? { message: advise } : undefined;
return { message, position, next: next ? [next] : undefined };
}
function formatMetadataError(e, context) {
if (isMetadataError(e)) {
// Produce a formatted version of the and leaving enough information in the original error
// to recover the formatting information to eventually produce a diagnostic error message.
const position = e.position;
const chain = {
message: `Error during template compile of '${context.name}'`,
position: position,
next: { message: e.message, next: e.chain, context: e.context, symbol: e.symbol }
};
const advise = e.advise || messageAdvise(e.message, e.context);
return formattedError(formatMetadataMessageChain(chain, advise));
}
return e;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGljX3JlZmxlY3Rvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2NvbXBpbGVyL3NyYy9hb3Qvc3RhdGljX3JlZmxlY3Rvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEVBQUMsa0JBQWtCLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUV2RCxPQUFPLEVBQUMsZUFBZSxFQUFFLGVBQWUsRUFBRSxrQkFBa0IsRUFBRSxxQkFBcUIsRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLGlCQUFpQixFQUFFLGtCQUFrQixFQUFFLFlBQVksRUFBRSxnQkFBZ0IsRUFBRSxXQUFXLEVBQUUsY0FBYyxFQUFFLGNBQWMsRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxjQUFjLEVBQUUsZUFBZSxFQUFFLGtCQUFrQixFQUFrQixNQUFNLFNBQVMsQ0FBQztBQUVqVyxPQUFPLEVBQUMsV0FBVyxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBRzFDLE9BQU8sRUFBQyxjQUFjLEVBQXdCLE1BQU0sbUJBQW1CLENBQUM7QUFDeEUsT0FBTyxFQUFDLFlBQVksRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBRzdDLE1BQU0sWUFBWSxHQUFHLGVBQWUsQ0FBQztBQUNyQyxNQUFNLGNBQWMsR0FBRyxpQkFBaUIsQ0FBQztBQUV6QyxNQUFNLFVBQVUsR0FBRyxVQUFVLENBQUM7QUFFOUIsTUFBTSxNQUFNLEdBQUc7SUFDYixVQUFVLEVBQUUsUUFBUTtDQUNyQixDQUFDO0FBRUYsTUFBTSxTQUFTLEdBQUcsVUFBVSxDQUFDO0FBQzdCLE1BQU0sT0FBTyxHQUFHLFNBQVMsQ0FBQztBQUMxQixNQUFNLGFBQWEsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLFNBQVMsRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxjQUFjLENBQUMsQ0FBQyxDQUFDO0FBQ3ZGLE1BQU0saUJBQWlCLEdBQUcsV0FBVyxDQUFDO0FBQ3RDLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQztBQUV2QixTQUFTLFlBQVksQ0FBQyxLQUFVO0lBQzlCLE9BQU8sS0FBSyxJQUFJLEtBQUssQ0FBQyxVQUFVLElBQUksUUFBUSxDQUFDO0FBQy9DLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLE9BQU8sZUFBZTtJQW9CMUIsWUFDWSxlQUE4QyxFQUM5QyxjQUFvQyxFQUM1Qyx1QkFBc0UsRUFBRSxFQUN4RSx5QkFBc0UsRUFBRSxFQUNoRSxhQUF1RDtRQUp2RCxvQkFBZSxHQUFmLGVBQWUsQ0FBK0I7UUFDOUMsbUJBQWMsR0FBZCxjQUFjLENBQXNCO1FBR3BDLGtCQUFhLEdBQWIsYUFBYSxDQUEwQztRQXhCM0Qsb0JBQWUsR0FBRyxJQUFJLEdBQUcsRUFBdUIsQ0FBQztRQUNqRCwyQkFBc0IsR0FBRyxJQUFJLEdBQUcsRUFBdUIsQ0FBQztRQUN4RCxrQkFBYSxHQUFHLElBQUksR0FBRyxFQUF3QyxDQUFDO1FBQ2hFLG1CQUFjLEdBQUcsSUFBSSxHQUFHLEVBQXVCLENBQUM7UUFDaEQsZ0JBQVcsR0FBRyxJQUFJLEdBQUcsRUFBMEMsQ0FBQztRQUNoRSxnQkFBVyxHQUFHLElBQUksR0FBRyxFQUEwQixDQUFDO1FBQ2hELGtCQUFhLEdBQUcsSUFBSSxHQUFHLEVBQTZELENBQUM7UUFDckYsK0JBQTBCLEdBQUcsSUFBSSxHQUFHLEVBQXdCLENBQUM7UUFTN0QsNENBQXVDLEdBQzNDLElBQUksR0FBRyxFQUE4QyxDQUFDO1FBUXhELElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1FBQy9CLG9CQUFvQixDQUFDLE9BQU8sQ0FDeEIsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQywrQkFBK0IsQ0FDeEMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUM5RCxzQkFBc0IsQ0FBQyxPQUFPLENBQzFCLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUN2RixJQUFJLENBQUMsdUNBQXVDLENBQUMsR0FBRyxDQUM1QyxrQkFBa0IsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxlQUFlLEVBQUUsZUFBZSxDQUFDLENBQUMsQ0FBQztRQUN0RSxJQUFJLENBQUMsdUNBQXVDLENBQUMsR0FBRyxDQUFDLGtCQUFrQixDQUFDLElBQUksRUFBRSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7UUFDeEYsSUFBSSxDQUFDLHVDQUF1QyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDO1FBQ2hHLElBQUksQ0FBQyx1Q0FBdUMsQ0FBQyxHQUFHLENBQzVDLGtCQUFrQixDQUFDLFVBQVUsRUFDN0IsQ0FBQyxnQkFBZ0IsRUFBRSxVQUFVLEVBQUUsZUFBZSxFQUFFLGVBQWUsRUFBRSxjQUFjLENBQUMsQ0FBQyxDQUFDO0lBQ3hGLENBQUM7SUFFRCxrQkFBa0IsQ0FBQyxVQUF3QjtRQUN6QyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDNUQsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFDLGVBQWUsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUMzRCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsaUJBQWlCLENBQUMsT0FBdUI7UUFDdkMsS0FBSyxNQUFNLE1BQU0sSUFBSSxPQUFPLEVBQUU7WUFDNUIsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQ