refactor(compiler): store metadata of top level symbols also in summaries (#13289)
This allows a build using summaries to not need .metadata.json files at all any more. Part of #12787
This commit is contained in:

committed by
Chuck Jazdzewski

parent
dbb364e23a
commit
1f0f429f2a
@ -6,11 +6,10 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injectable} from '@angular/core';
|
||||
|
||||
import {CompileAnimationAnimateMetadata, CompileAnimationEntryMetadata, CompileAnimationGroupMetadata, CompileAnimationKeyframesSequenceMetadata, CompileAnimationMetadata, CompileAnimationSequenceMetadata, CompileAnimationStateDeclarationMetadata, CompileAnimationStateTransitionMetadata, CompileAnimationStyleMetadata, CompileAnimationWithStepsMetadata, CompileDirectiveMetadata, identifierName} from '../compile_metadata';
|
||||
import {StringMapWrapper} from '../facade/collection';
|
||||
import {isBlank, isPresent} from '../facade/lang';
|
||||
import {CompilerInjectable} from '../injectable';
|
||||
import {ParseError} from '../parse_util';
|
||||
import {ANY_STATE, FILL_STYLE_FLAG} from '../private_import_core';
|
||||
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
|
||||
@ -35,7 +34,7 @@ export class AnimationEntryParseResult {
|
||||
constructor(public ast: AnimationEntryAst, public errors: AnimationParseError[]) {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class AnimationParser {
|
||||
constructor(private _schema: ElementSchemaRegistry) {}
|
||||
|
||||
|
@ -20,34 +20,34 @@ import {NgModuleCompiler} from '../ng_module_compiler';
|
||||
import {OutputEmitter} from '../output/abstract_emitter';
|
||||
import * as o from '../output/output_ast';
|
||||
import {CompiledStylesheet, StyleCompiler} from '../style_compiler';
|
||||
import {SummaryResolver} from '../summary_resolver';
|
||||
import {TemplateParser} from '../template_parser/template_parser';
|
||||
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewClassDependency, ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler';
|
||||
|
||||
import {AotCompilerOptions} from './compiler_options';
|
||||
import {AotCompilerHost} from './compiler_host';
|
||||
import {GeneratedFile} from './generated_file';
|
||||
import {StaticReflector} from './static_reflector';
|
||||
import {StaticSymbol} from './static_symbol';
|
||||
import {AotSummaryResolver} from './summary_resolver';
|
||||
import {filterFileByPatterns} from './utils';
|
||||
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
|
||||
import {serializeSummaries, summaryFileName} from './summary_serializer';
|
||||
|
||||
export class AotCompiler {
|
||||
private _animationCompiler = new AnimationCompiler();
|
||||
|
||||
constructor(
|
||||
private _metadataResolver: CompileMetadataResolver, private _templateParser: TemplateParser,
|
||||
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
|
||||
private _dirWrapperCompiler: DirectiveWrapperCompiler,
|
||||
private _host: AotCompilerHost, private _metadataResolver: CompileMetadataResolver,
|
||||
private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler,
|
||||
private _viewCompiler: ViewCompiler, private _dirWrapperCompiler: DirectiveWrapperCompiler,
|
||||
private _ngModuleCompiler: NgModuleCompiler, private _outputEmitter: OutputEmitter,
|
||||
private _summaryResolver: AotSummaryResolver, private _localeId: string,
|
||||
private _summaryResolver: SummaryResolver<StaticSymbol>, private _localeId: string,
|
||||
private _translationFormat: string, private _animationParser: AnimationParser,
|
||||
private _staticReflector: StaticReflector, private _options: AotCompilerOptions) {}
|
||||
private _symbolResolver: StaticSymbolResolver) {}
|
||||
|
||||
clearCache() { this._metadataResolver.clearCache(); }
|
||||
|
||||
compileAll(rootFiles: string[]): Promise<GeneratedFile[]> {
|
||||
const programSymbols = extractProgramSymbols(this._staticReflector, rootFiles, this._options);
|
||||
const programSymbols = extractProgramSymbols(this._symbolResolver, rootFiles, this._host);
|
||||
const {ngModuleByPipeOrDirective, files, ngModules} =
|
||||
analyzeAndValidateNgModules(programSymbols, this._options, this._metadataResolver);
|
||||
analyzeAndValidateNgModules(programSymbols, this._host, this._metadataResolver);
|
||||
return Promise
|
||||
.all(ngModules.map(
|
||||
ngModule => this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(
|
||||
@ -56,27 +56,21 @@ export class AotCompiler {
|
||||
const sourceModules = files.map(
|
||||
file => this._compileSrcFile(
|
||||
file.srcUrl, ngModuleByPipeOrDirective, file.directives, file.pipes,
|
||||
file.ngModules));
|
||||
file.ngModules, file.injectables));
|
||||
return ListWrapper.flatten(sourceModules);
|
||||
});
|
||||
}
|
||||
|
||||
private _compileSrcFile(
|
||||
srcFileUrl: string, ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>,
|
||||
directives: StaticSymbol[], pipes: StaticSymbol[],
|
||||
ngModules: StaticSymbol[]): GeneratedFile[] {
|
||||
directives: StaticSymbol[], pipes: StaticSymbol[], ngModules: StaticSymbol[],
|
||||
injectables: StaticSymbol[]): GeneratedFile[] {
|
||||
const fileSuffix = _splitTypescriptSuffix(srcFileUrl)[1];
|
||||
const statements: o.Statement[] = [];
|
||||
const exportedVars: string[] = [];
|
||||
const generatedFiles: GeneratedFile[] = [];
|
||||
|
||||
// write summary files
|
||||
const summaries: CompileTypeSummary[] = [
|
||||
...ngModules.map(ref => this._metadataResolver.getNgModuleSummary(ref)),
|
||||
...directives.map(ref => this._metadataResolver.getDirectiveSummary(ref)),
|
||||
...pipes.map(ref => this._metadataResolver.getPipeSummary(ref))
|
||||
];
|
||||
generatedFiles.push(this._summaryResolver.serializeSummaries(srcFileUrl, summaries));
|
||||
generatedFiles.push(this._createSummary(srcFileUrl, directives, pipes, ngModules, injectables));
|
||||
|
||||
// compile all ng modules
|
||||
exportedVars.push(
|
||||
@ -121,6 +115,22 @@ export class AotCompiler {
|
||||
return generatedFiles;
|
||||
}
|
||||
|
||||
private _createSummary(
|
||||
srcFileUrl: string, directives: StaticSymbol[], pipes: StaticSymbol[],
|
||||
ngModules: StaticSymbol[], injectables: StaticSymbol[]): GeneratedFile {
|
||||
const symbolSummaries = this._symbolResolver.getSymbolsOf(srcFileUrl)
|
||||
.map(symbol => this._symbolResolver.resolveSymbol(symbol));
|
||||
const typeSummaries = [
|
||||
...ngModules.map(ref => this._metadataResolver.getNgModuleSummary(ref)),
|
||||
...directives.map(ref => this._metadataResolver.getDirectiveSummary(ref)),
|
||||
...pipes.map(ref => this._metadataResolver.getPipeSummary(ref)),
|
||||
...injectables.map(ref => this._metadataResolver.getInjectableSummary(ref))
|
||||
];
|
||||
const json = serializeSummaries(
|
||||
this._host, this._summaryResolver, this._symbolResolver, symbolSummaries, typeSummaries);
|
||||
return new GeneratedFile(srcFileUrl, summaryFileName(srcFileUrl), json);
|
||||
}
|
||||
|
||||
private _compileModule(ngModuleType: StaticSymbol, targetStatements: o.Statement[]): string {
|
||||
const ngModule = this._metadataResolver.getNgModuleMetadata(ngModuleType);
|
||||
const providers: CompileProviderMetadata[] = [];
|
||||
@ -142,7 +152,7 @@ export class AotCompiler {
|
||||
const appCompileResult = this._ngModuleCompiler.compile(ngModule, providers);
|
||||
|
||||
appCompileResult.dependencies.forEach((dep) => {
|
||||
dep.placeholder.reference = this._staticReflector.getStaticSymbol(
|
||||
dep.placeholder.reference = this._symbolResolver.getStaticSymbol(
|
||||
_ngfactoryModuleUrl(identifierModuleUrl(dep.comp)), _componentFactoryName(dep.comp));
|
||||
});
|
||||
|
||||
@ -163,7 +173,7 @@ export class AotCompiler {
|
||||
compMeta: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata, fileSuffix: string,
|
||||
targetStatements: o.Statement[]): string {
|
||||
const hostMeta = createHostComponentMeta(
|
||||
this._staticReflector.getStaticSymbol(
|
||||
this._symbolResolver.getStaticSymbol(
|
||||
identifierModuleUrl(compMeta.type), `${identifierName(compMeta.type)}_Host`),
|
||||
compMeta);
|
||||
const hostViewFactoryVar = this._compileComponent(
|
||||
@ -206,16 +216,16 @@ export class AotCompiler {
|
||||
compMeta, parsedTemplate, stylesExpr, pipes, compiledAnimations);
|
||||
if (componentStyles) {
|
||||
targetStatements.push(
|
||||
..._resolveStyleStatements(this._staticReflector, componentStyles, fileSuffix));
|
||||
..._resolveStyleStatements(this._symbolResolver, componentStyles, fileSuffix));
|
||||
}
|
||||
compiledAnimations.forEach(entry => targetStatements.push(...entry.statements));
|
||||
targetStatements.push(..._resolveViewStatements(this._staticReflector, viewResult));
|
||||
targetStatements.push(..._resolveViewStatements(this._symbolResolver, viewResult));
|
||||
return viewResult.viewClassVar;
|
||||
}
|
||||
|
||||
private _codgenStyles(
|
||||
fileUrl: string, stylesCompileResult: CompiledStylesheet, fileSuffix: string): GeneratedFile {
|
||||
_resolveStyleStatements(this._staticReflector, stylesCompileResult, fileSuffix);
|
||||
_resolveStyleStatements(this._symbolResolver, stylesCompileResult, fileSuffix);
|
||||
return this._codegenSourceModule(
|
||||
fileUrl, _stylesModuleUrl(
|
||||
stylesCompileResult.meta.moduleUrl, stylesCompileResult.isShimmed, fileSuffix),
|
||||
@ -232,7 +242,7 @@ export class AotCompiler {
|
||||
}
|
||||
|
||||
function _resolveViewStatements(
|
||||
reflector: StaticReflector, compileResult: ViewCompileResult): o.Statement[] {
|
||||
reflector: StaticSymbolResolver, compileResult: ViewCompileResult): o.Statement[] {
|
||||
compileResult.dependencies.forEach((dep) => {
|
||||
if (dep instanceof ViewClassDependency) {
|
||||
const vfd = <ViewClassDependency>dep;
|
||||
@ -253,7 +263,7 @@ function _resolveViewStatements(
|
||||
|
||||
|
||||
function _resolveStyleStatements(
|
||||
reflector: StaticReflector, compileResult: CompiledStylesheet,
|
||||
reflector: StaticSymbolResolver, compileResult: CompiledStylesheet,
|
||||
fileSuffix: string): o.Statement[] {
|
||||
compileResult.dependencies.forEach((dep) => {
|
||||
dep.valuePlaceholder.reference = reflector.getStaticSymbol(
|
||||
@ -303,26 +313,27 @@ export interface NgAnalyzedModules {
|
||||
srcUrl: string,
|
||||
directives: StaticSymbol[],
|
||||
pipes: StaticSymbol[],
|
||||
ngModules: StaticSymbol[]
|
||||
ngModules: StaticSymbol[],
|
||||
injectables: StaticSymbol[]
|
||||
}>;
|
||||
symbolsMissingModule?: StaticSymbol[];
|
||||
}
|
||||
|
||||
export interface NgAnalyzeModulesHost { isSourceFile(filePath: string): boolean; }
|
||||
|
||||
// Returns all the source files and a mapping from modules to directives
|
||||
export function analyzeNgModules(
|
||||
programStaticSymbols: StaticSymbol[],
|
||||
options: {includeFilePattern?: RegExp, excludeFilePattern?: RegExp},
|
||||
programStaticSymbols: StaticSymbol[], host: NgAnalyzeModulesHost,
|
||||
metadataResolver: CompileMetadataResolver): NgAnalyzedModules {
|
||||
const {ngModules, symbolsMissingModule} =
|
||||
_createNgModules(programStaticSymbols, options, metadataResolver);
|
||||
return _analyzeNgModules(ngModules, symbolsMissingModule);
|
||||
_createNgModules(programStaticSymbols, host, metadataResolver);
|
||||
return _analyzeNgModules(programStaticSymbols, ngModules, symbolsMissingModule, metadataResolver);
|
||||
}
|
||||
|
||||
export function analyzeAndValidateNgModules(
|
||||
programStaticSymbols: StaticSymbol[],
|
||||
options: {includeFilePattern?: RegExp, excludeFilePattern?: RegExp},
|
||||
programStaticSymbols: StaticSymbol[], host: NgAnalyzeModulesHost,
|
||||
metadataResolver: CompileMetadataResolver): NgAnalyzedModules {
|
||||
const result = analyzeNgModules(programStaticSymbols, options, metadataResolver);
|
||||
const result = analyzeNgModules(programStaticSymbols, host, metadataResolver);
|
||||
if (result.symbolsMissingModule && result.symbolsMissingModule.length) {
|
||||
const messages = result.symbolsMissingModule.map(
|
||||
s => `Cannot determine the module for class ${s.name} in ${s.filePath}!`);
|
||||
@ -332,16 +343,27 @@ export function analyzeAndValidateNgModules(
|
||||
}
|
||||
|
||||
function _analyzeNgModules(
|
||||
ngModuleMetas: CompileNgModuleMetadata[],
|
||||
symbolsMissingModule: StaticSymbol[]): NgAnalyzedModules {
|
||||
programSymbols: StaticSymbol[], ngModuleMetas: CompileNgModuleMetadata[],
|
||||
symbolsMissingModule: StaticSymbol[],
|
||||
metadataResolver: CompileMetadataResolver): NgAnalyzedModules {
|
||||
const moduleMetasByRef = new Map<any, CompileNgModuleMetadata>();
|
||||
ngModuleMetas.forEach((ngModule) => moduleMetasByRef.set(ngModule.type.reference, ngModule));
|
||||
const ngModuleByPipeOrDirective = new Map<StaticSymbol, CompileNgModuleMetadata>();
|
||||
const ngModulesByFile = new Map<string, StaticSymbol[]>();
|
||||
const ngDirectivesByFile = new Map<string, StaticSymbol[]>();
|
||||
const ngPipesByFile = new Map<string, StaticSymbol[]>();
|
||||
const ngInjectablesByFile = new Map<string, StaticSymbol[]>();
|
||||
const filePaths = new Set<string>();
|
||||
|
||||
// Make sure we produce an analyzed file for each input file
|
||||
programSymbols.forEach((symbol) => {
|
||||
const filePath = symbol.filePath;
|
||||
filePaths.add(filePath);
|
||||
if (metadataResolver.isInjectable(symbol)) {
|
||||
ngInjectablesByFile.set(filePath, (ngInjectablesByFile.get(filePath) || []).concat(symbol));
|
||||
}
|
||||
});
|
||||
|
||||
// Looping over all modules to construct:
|
||||
// - a map from file to modules `ngModulesByFile`,
|
||||
// - a map from file to directives `ngDirectivesByFile`,
|
||||
@ -369,17 +391,20 @@ function _analyzeNgModules(
|
||||
});
|
||||
});
|
||||
|
||||
const files:
|
||||
{srcUrl: string,
|
||||
directives: StaticSymbol[],
|
||||
pipes: StaticSymbol[],
|
||||
ngModules: StaticSymbol[]}[] = [];
|
||||
const files: {
|
||||
srcUrl: string,
|
||||
directives: StaticSymbol[],
|
||||
pipes: StaticSymbol[],
|
||||
ngModules: StaticSymbol[],
|
||||
injectables: StaticSymbol[]
|
||||
}[] = [];
|
||||
|
||||
filePaths.forEach((srcUrl) => {
|
||||
const directives = ngDirectivesByFile.get(srcUrl) || [];
|
||||
const pipes = ngPipesByFile.get(srcUrl) || [];
|
||||
const ngModules = ngModulesByFile.get(srcUrl) || [];
|
||||
files.push({srcUrl, directives, pipes, ngModules});
|
||||
const injectables = ngInjectablesByFile.get(srcUrl) || [];
|
||||
files.push({srcUrl, directives, pipes, ngModules, injectables});
|
||||
});
|
||||
|
||||
return {
|
||||
@ -392,29 +417,20 @@ function _analyzeNgModules(
|
||||
}
|
||||
|
||||
export function extractProgramSymbols(
|
||||
staticReflector: StaticReflector, files: string[],
|
||||
options: {includeFilePattern?: RegExp, excludeFilePattern?: RegExp} = {}): StaticSymbol[] {
|
||||
staticSymbolResolver: StaticSymbolResolver, files: string[],
|
||||
host: NgAnalyzeModulesHost): StaticSymbol[] {
|
||||
const staticSymbols: StaticSymbol[] = [];
|
||||
files.filter(fileName => filterFileByPatterns(fileName, options)).forEach(sourceFile => {
|
||||
const moduleMetadata = staticReflector.getModuleMetadata(sourceFile);
|
||||
if (!moduleMetadata) {
|
||||
console.error(`WARNING: no metadata found for ${sourceFile}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const metadata = moduleMetadata['metadata'];
|
||||
|
||||
if (!metadata) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const symbol of Object.keys(metadata)) {
|
||||
if (metadata[symbol] && metadata[symbol].__symbolic == 'error') {
|
||||
// Ignore symbols that are only included to record error information.
|
||||
continue;
|
||||
files.filter(fileName => host.isSourceFile(fileName)).forEach(sourceFile => {
|
||||
staticSymbolResolver.getSymbolsOf(sourceFile).forEach((symbol) => {
|
||||
const resolvedSymbol = staticSymbolResolver.resolveSymbol(symbol);
|
||||
const symbolMeta = resolvedSymbol.metadata;
|
||||
if (symbolMeta) {
|
||||
if (symbolMeta.__symbolic != 'error') {
|
||||
// Ignore symbols that are only included to record error information.
|
||||
staticSymbols.push(resolvedSymbol.symbol);
|
||||
}
|
||||
}
|
||||
staticSymbols.push(staticReflector.getStaticSymbol(sourceFile, symbol));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return staticSymbols;
|
||||
@ -424,8 +440,7 @@ export function extractProgramSymbols(
|
||||
// that all directives / pipes that are present in the program
|
||||
// are also declared by a module.
|
||||
function _createNgModules(
|
||||
programStaticSymbols: StaticSymbol[],
|
||||
options: {includeFilePattern?: RegExp, excludeFilePattern?: RegExp},
|
||||
programStaticSymbols: StaticSymbol[], host: NgAnalyzeModulesHost,
|
||||
metadataResolver: CompileMetadataResolver):
|
||||
{ngModules: CompileNgModuleMetadata[], symbolsMissingModule: StaticSymbol[]} {
|
||||
const ngModules = new Map<any, CompileNgModuleMetadata>();
|
||||
@ -433,7 +448,7 @@ function _createNgModules(
|
||||
const ngModulePipesAndDirective = new Set<StaticSymbol>();
|
||||
|
||||
const addNgModule = (staticSymbol: any) => {
|
||||
if (ngModules.has(staticSymbol) || !filterFileByPatterns(staticSymbol.filePath, options)) {
|
||||
if (ngModules.has(staticSymbol) || !host.isSourceFile(staticSymbol.filePath)) {
|
||||
return false;
|
||||
}
|
||||
const ngModule = metadataResolver.getNgModuleMetadata(staticSymbol, false);
|
||||
|
@ -34,8 +34,11 @@ import {AotCompilerHost} from './compiler_host';
|
||||
import {AotCompilerOptions} from './compiler_options';
|
||||
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
|
||||
import {StaticReflector} from './static_reflector';
|
||||
import {StaticSymbolCache} from './static_symbol';
|
||||
import {StaticSymbolResolver} from './static_symbol_resolver';
|
||||
import {AotSummaryResolver} from './summary_resolver';
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new AotCompiler based on options and a host.
|
||||
*/
|
||||
@ -44,7 +47,10 @@ export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCom
|
||||
let translations: string = options.translations || '';
|
||||
|
||||
const urlResolver = createOfflineCompileUrlResolver();
|
||||
const staticReflector = new StaticReflector(compilerHost);
|
||||
const symbolCache = new StaticSymbolCache();
|
||||
const summaryResolver = new AotSummaryResolver(compilerHost, symbolCache);
|
||||
const symbolResolver = new StaticSymbolResolver(compilerHost, symbolCache, summaryResolver);
|
||||
const staticReflector = new StaticReflector(symbolResolver);
|
||||
StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
||||
const htmlParser = new I18NHtmlParser(new HtmlParser(), translations, options.i18nFormat);
|
||||
const config = new CompilerConfig({
|
||||
@ -60,17 +66,16 @@ export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCom
|
||||
const console = new Console();
|
||||
const tmplParser =
|
||||
new TemplateParser(expressionParser, elementSchemaRegistry, htmlParser, console, []);
|
||||
const summaryResolver = new AotSummaryResolver(compilerHost, staticReflector, options);
|
||||
const resolver = new CompileMetadataResolver(
|
||||
new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector),
|
||||
new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer,
|
||||
staticReflector);
|
||||
// TODO(vicb): do not pass options.i18nFormat here
|
||||
const compiler = new AotCompiler(
|
||||
resolver, tmplParser, new StyleCompiler(urlResolver),
|
||||
compilerHost, resolver, tmplParser, new StyleCompiler(urlResolver),
|
||||
new ViewCompiler(config, elementSchemaRegistry),
|
||||
new DirectiveWrapperCompiler(config, expressionParser, elementSchemaRegistry, console),
|
||||
new NgModuleCompiler(), new TypeScriptEmitter(compilerHost), summaryResolver, options.locale,
|
||||
options.i18nFormat, new AnimationParser(elementSchemaRegistry), staticReflector, options);
|
||||
options.i18nFormat, new AnimationParser(elementSchemaRegistry), symbolResolver);
|
||||
return {compiler, reflector: staticReflector};
|
||||
}
|
||||
|
@ -8,16 +8,17 @@
|
||||
|
||||
import {ImportResolver} from '../output/path_util';
|
||||
|
||||
import {StaticReflectorHost} from './static_reflector';
|
||||
import {StaticSymbol} from './static_symbol';
|
||||
import {StaticSymbolResolverHost} from './static_symbol_resolver';
|
||||
import {AotSummaryResolverHost} from './summary_resolver';
|
||||
import {AotSummarySerializerHost} from './summary_serializer';
|
||||
|
||||
/**
|
||||
* The host of the AotCompiler disconnects the implementation from TypeScript / other language
|
||||
* services and from underlying file systems.
|
||||
*/
|
||||
export interface AotCompilerHost extends StaticReflectorHost, ImportResolver,
|
||||
AotSummaryResolverHost {
|
||||
export interface AotCompilerHost extends StaticSymbolResolverHost, ImportResolver,
|
||||
AotSummaryResolverHost, AotSummarySerializerHost {
|
||||
/**
|
||||
* Loads a resource (e.g. html / css)
|
||||
*/
|
||||
|
@ -11,6 +11,4 @@ export interface AotCompilerOptions {
|
||||
locale?: string;
|
||||
i18nFormat?: string;
|
||||
translations?: string;
|
||||
includeFilePattern?: RegExp;
|
||||
excludeFilePattern?: RegExp;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
import {GetterFn, MethodFn, ReflectionCapabilities, SetterFn, reflector} from '../private_import_core';
|
||||
import {StaticReflector} from './static_reflector';
|
||||
import {StaticSymbol} from './static_symbol';
|
||||
|
||||
export class StaticAndDynamicReflectionCapabilities {
|
||||
static install(staticDelegate: StaticReflector) {
|
||||
@ -42,7 +43,7 @@ export class StaticAndDynamicReflectionCapabilities {
|
||||
method(name: string): MethodFn { return this.dynamicDelegate.method(name); }
|
||||
importUri(type: any): string { return this.staticDelegate.importUri(type); }
|
||||
resolveIdentifier(name: string, moduleUrl: string, runtime: any) {
|
||||
return this.staticDelegate.resolveIdentifier(name, moduleUrl, runtime);
|
||||
return this.staticDelegate.resolveIdentifier(name, moduleUrl);
|
||||
}
|
||||
resolveEnum(enumIdentifier: any, name: string): any {
|
||||
if (isStaticType(enumIdentifier)) {
|
||||
|
@ -7,10 +7,12 @@
|
||||
*/
|
||||
|
||||
import {Attribute, Component, ContentChild, ContentChildren, Directive, Host, HostBinding, HostListener, Inject, Injectable, Input, NgModule, Optional, Output, Pipe, Self, SkipSelf, ViewChild, ViewChildren, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
|
||||
import {ReflectorReader} from '../private_import_core';
|
||||
import {StaticSymbol} from './static_symbol';
|
||||
|
||||
const SUPPORTED_SCHEMA_VERSION = 3;
|
||||
import {ReflectorReader} from '../private_import_core';
|
||||
|
||||
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
||||
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
|
||||
|
||||
const ANGULAR_IMPORT_LOCATIONS = {
|
||||
coreDecorators: '@angular/core/src/metadata',
|
||||
diDecorators: '@angular/core/src/di/metadata',
|
||||
@ -22,66 +24,20 @@ const ANGULAR_IMPORT_LOCATIONS = {
|
||||
|
||||
const HIDDEN_KEY = /^\$.*\$$/;
|
||||
|
||||
/**
|
||||
* The host of the StaticReflector disconnects the implementation from TypeScript / other language
|
||||
* services and from underlying file systems.
|
||||
*/
|
||||
export interface StaticReflectorHost {
|
||||
/**
|
||||
* Return a ModuleMetadata for the given module.
|
||||
* Angular 2 CLI will produce this metadata for a module whenever a .d.ts files is
|
||||
* produced and the module has exported variables or classes with decorators. Module metadata can
|
||||
* also be produced directly from TypeScript sources by using MetadataCollector in tools/metadata.
|
||||
*
|
||||
* @param modulePath is a string identifier for a module as an absolute path.
|
||||
* @returns the metadata for the given module.
|
||||
*/
|
||||
getMetadataFor(modulePath: string): {[key: string]: any}[];
|
||||
|
||||
/**
|
||||
* Converts a module name that is used in an `import` to a file path.
|
||||
* I.e.
|
||||
* `path/to/containingFile.ts` containing `import {...} from 'module-name'`.
|
||||
*/
|
||||
moduleNameToFileName(moduleName: string, containingFile: string): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A cache of static symbol used by the StaticReflector to return the same symbol for the
|
||||
* same symbol values.
|
||||
*/
|
||||
export class StaticSymbolCache {
|
||||
private cache = new Map<string, StaticSymbol>();
|
||||
|
||||
get(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
||||
const memberSuffix = members ? `.${ members.join('.')}` : '';
|
||||
const key = `"${declarationFile}".${name}${memberSuffix}`;
|
||||
let result = this.cache.get(key);
|
||||
if (!result) {
|
||||
result = new StaticSymbol(declarationFile, name, members);
|
||||
this.cache.set(key, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A static reflector implements enough of the Reflector API that is necessary to compile
|
||||
* templates statically.
|
||||
*/
|
||||
export class StaticReflector implements ReflectorReader {
|
||||
private declarationCache = new Map<string, StaticSymbol>();
|
||||
private annotationCache = new Map<StaticSymbol, any[]>();
|
||||
private propertyCache = new Map<StaticSymbol, {[key: string]: any[]}>();
|
||||
private parameterCache = new Map<StaticSymbol, any[]>();
|
||||
private methodCache = new Map<StaticSymbol, {[key: string]: boolean}>();
|
||||
private metadataCache = new Map<string, {[key: string]: any}>();
|
||||
private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
|
||||
private opaqueToken: StaticSymbol;
|
||||
|
||||
constructor(
|
||||
private host: StaticReflectorHost,
|
||||
private staticSymbolCache: StaticSymbolCache = new StaticSymbolCache(),
|
||||
private symbolResolver: StaticSymbolResolver,
|
||||
knownMetadataClasses: {name: string, filePath: string, ctor: any}[] = [],
|
||||
knownMetadataFunctions: {name: string, filePath: string, fn: any}[] = [],
|
||||
private errorRecorder?: (error: any, fileName: string) => void) {
|
||||
@ -94,12 +50,26 @@ export class StaticReflector implements ReflectorReader {
|
||||
}
|
||||
|
||||
importUri(typeOrFunc: StaticSymbol): string {
|
||||
const staticSymbol = this.findDeclaration(typeOrFunc.filePath, typeOrFunc.name, '');
|
||||
const staticSymbol = this.findSymbolDeclaration(typeOrFunc);
|
||||
return staticSymbol ? staticSymbol.filePath : null;
|
||||
}
|
||||
|
||||
resolveIdentifier(name: string, moduleUrl: string, runtime: any): any {
|
||||
return this.findDeclaration(moduleUrl, name, '');
|
||||
resolveIdentifier(name: string, moduleUrl: string): StaticSymbol {
|
||||
return this.findDeclaration(moduleUrl, name);
|
||||
}
|
||||
|
||||
findDeclaration(moduleUrl: string, name: string, containingFile?: string): StaticSymbol {
|
||||
return this.findSymbolDeclaration(
|
||||
this.symbolResolver.getSymbolByModule(moduleUrl, name, containingFile));
|
||||
}
|
||||
|
||||
findSymbolDeclaration(symbol: StaticSymbol): StaticSymbol {
|
||||
const resolvedSymbol = this.symbolResolver.resolveSymbol(symbol);
|
||||
if (resolvedSymbol && resolvedSymbol.metadata instanceof StaticSymbol) {
|
||||
return this.findSymbolDeclaration(resolvedSymbol.metadata);
|
||||
} else {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
|
||||
resolveEnum(enumIdentifier: any, name: string): any {
|
||||
@ -128,7 +98,7 @@ export class StaticReflector implements ReflectorReader {
|
||||
public propMetadata(type: StaticSymbol): {[key: string]: any[]} {
|
||||
let propMetadata = this.propertyCache.get(type);
|
||||
if (!propMetadata) {
|
||||
const classMetadata = this.getTypeMetadata(type) || {};
|
||||
const classMetadata = this.getTypeMetadata(type);
|
||||
propMetadata = {};
|
||||
if (classMetadata['extends']) {
|
||||
const parentPropMetadata = this.propMetadata(this.simplify(type, classMetadata['extends']));
|
||||
@ -203,7 +173,7 @@ export class StaticReflector implements ReflectorReader {
|
||||
private _methodNames(type: any): {[key: string]: boolean} {
|
||||
let methodNames = this.methodCache.get(type);
|
||||
if (!methodNames) {
|
||||
const classMetadata = this.getTypeMetadata(type) || {};
|
||||
const classMetadata = this.getTypeMetadata(type);
|
||||
methodNames = {};
|
||||
if (classMetadata['extends']) {
|
||||
const parentMethodNames = this._methodNames(this.simplify(type, classMetadata['extends']));
|
||||
@ -306,7 +276,7 @@ export class StaticReflector implements ReflectorReader {
|
||||
* @param name the name of the type.
|
||||
*/
|
||||
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
||||
return this.staticSymbolCache.get(declarationFile, name, members);
|
||||
return this.symbolResolver.getStaticSymbol(declarationFile, name, members);
|
||||
}
|
||||
|
||||
private reportError(error: Error, context: StaticSymbol, path?: string) {
|
||||
@ -317,96 +287,6 @@ export class StaticReflector implements ReflectorReader {
|
||||
}
|
||||
}
|
||||
|
||||
private resolveExportedSymbol(filePath: string, symbolName: string): StaticSymbol {
|
||||
const resolveModule = (moduleName: string): string => {
|
||||
const resolvedModulePath = this.host.moduleNameToFileName(moduleName, filePath);
|
||||
if (!resolvedModulePath) {
|
||||
this.reportError(
|
||||
new Error(`Could not resolve module '${moduleName}' relative to file ${filePath}`),
|
||||
null, filePath);
|
||||
}
|
||||
return resolvedModulePath;
|
||||
};
|
||||
const cacheKey = `${filePath}|${symbolName}`;
|
||||
let staticSymbol = this.declarationCache.get(cacheKey);
|
||||
if (staticSymbol) {
|
||||
return staticSymbol;
|
||||
}
|
||||
const metadata = this.getModuleMetadata(filePath);
|
||||
if (metadata) {
|
||||
// If we have metadata for the symbol, this is the original exporting location.
|
||||
if (metadata['metadata'][symbolName]) {
|
||||
staticSymbol = this.getStaticSymbol(filePath, symbolName);
|
||||
}
|
||||
|
||||
// If no, try to find the symbol in one of the re-export location
|
||||
if (!staticSymbol && metadata['exports']) {
|
||||
// Try and find the symbol in the list of explicitly re-exported symbols.
|
||||
for (const moduleExport of metadata['exports']) {
|
||||
if (moduleExport.export) {
|
||||
const exportSymbol = moduleExport.export.find((symbol: any) => {
|
||||
if (typeof symbol === 'string') {
|
||||
return symbol == symbolName;
|
||||
} else {
|
||||
return symbol.as == symbolName;
|
||||
}
|
||||
});
|
||||
if (exportSymbol) {
|
||||
let symName = symbolName;
|
||||
if (typeof exportSymbol !== 'string') {
|
||||
symName = exportSymbol.name;
|
||||
}
|
||||
const resolvedModule = resolveModule(moduleExport.from);
|
||||
if (resolvedModule) {
|
||||
staticSymbol =
|
||||
this.resolveExportedSymbol(resolveModule(moduleExport.from), symName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!staticSymbol) {
|
||||
// Try to find the symbol via export * directives.
|
||||
for (const moduleExport of metadata['exports']) {
|
||||
if (!moduleExport.export) {
|
||||
const resolvedModule = resolveModule(moduleExport.from);
|
||||
if (resolvedModule) {
|
||||
const candidateSymbol = this.resolveExportedSymbol(resolvedModule, symbolName);
|
||||
if (candidateSymbol) {
|
||||
staticSymbol = candidateSymbol;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.declarationCache.set(cacheKey, staticSymbol);
|
||||
return staticSymbol;
|
||||
}
|
||||
|
||||
findDeclaration(module: string, symbolName: string, containingFile?: string): StaticSymbol {
|
||||
try {
|
||||
const filePath = this.host.moduleNameToFileName(module, containingFile);
|
||||
let symbol: StaticSymbol;
|
||||
if (!filePath) {
|
||||
// If the file cannot be found the module is probably referencing a declared module
|
||||
// for which there is no disambiguating file and we also don't need to track
|
||||
// re-exports. Just use the module name.
|
||||
symbol = this.getStaticSymbol(module, symbolName);
|
||||
} else {
|
||||
symbol = this.resolveExportedSymbol(filePath, symbolName) ||
|
||||
this.getStaticSymbol(filePath, symbolName);
|
||||
}
|
||||
return symbol;
|
||||
} catch (e) {
|
||||
console.error(`can't resolve module ${module} from ${containingFile}`);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public simplify(context: StaticSymbol, value: any): any {
|
||||
const self = this;
|
||||
@ -414,93 +294,41 @@ export class StaticReflector implements ReflectorReader {
|
||||
const calling = new Map<StaticSymbol, boolean>();
|
||||
|
||||
function simplifyInContext(context: StaticSymbol, value: any, depth: number): any {
|
||||
function resolveReference(context: StaticSymbol, expression: any): StaticSymbol {
|
||||
let staticSymbol: StaticSymbol;
|
||||
if (expression['module']) {
|
||||
staticSymbol =
|
||||
self.findDeclaration(expression['module'], expression['name'], context.filePath);
|
||||
} else {
|
||||
staticSymbol = self.getStaticSymbol(context.filePath, expression['name']);
|
||||
}
|
||||
return staticSymbol;
|
||||
}
|
||||
|
||||
function resolveReferenceValue(staticSymbol: StaticSymbol): any {
|
||||
const moduleMetadata = self.getModuleMetadata(staticSymbol.filePath);
|
||||
const declarationValue =
|
||||
moduleMetadata ? moduleMetadata['metadata'][staticSymbol.name] : null;
|
||||
return declarationValue;
|
||||
const resolvedSymbol = self.symbolResolver.resolveSymbol(staticSymbol);
|
||||
return resolvedSymbol ? resolvedSymbol.metadata : null;
|
||||
}
|
||||
|
||||
function isOpaqueToken(context: StaticSymbol, value: any): boolean {
|
||||
if (value && value.__symbolic === 'new' && value.expression) {
|
||||
const target = value.expression;
|
||||
if (target.__symbolic == 'reference') {
|
||||
return sameSymbol(resolveReference(context, target), self.opaqueToken);
|
||||
function simplifyCall(functionSymbol: StaticSymbol, targetFunction: any, args: any[]) {
|
||||
if (targetFunction && targetFunction['__symbolic'] == 'function') {
|
||||
if (calling.get(functionSymbol)) {
|
||||
throw new Error('Recursion not supported');
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function simplifyCall(expression: any) {
|
||||
let callContext: {[name: string]: string}|undefined = undefined;
|
||||
if (expression['__symbolic'] == 'call') {
|
||||
const target = expression['expression'];
|
||||
let functionSymbol: StaticSymbol;
|
||||
let targetFunction: any;
|
||||
if (target) {
|
||||
switch (target.__symbolic) {
|
||||
case 'reference':
|
||||
// Find the function to call.
|
||||
callContext = {name: target.name};
|
||||
functionSymbol = resolveReference(context, target);
|
||||
targetFunction = resolveReferenceValue(functionSymbol);
|
||||
break;
|
||||
case 'select':
|
||||
// Find the static method to call
|
||||
if (target.expression.__symbolic == 'reference') {
|
||||
functionSymbol = resolveReference(context, target.expression);
|
||||
const classData = resolveReferenceValue(functionSymbol);
|
||||
if (classData && classData.statics) {
|
||||
targetFunction = classData.statics[target.member];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (targetFunction && targetFunction['__symbolic'] == 'function') {
|
||||
if (calling.get(functionSymbol)) {
|
||||
throw new Error('Recursion not supported');
|
||||
}
|
||||
calling.set(functionSymbol, true);
|
||||
try {
|
||||
const value = targetFunction['value'];
|
||||
if (value && (depth != 0 || value.__symbolic != 'error')) {
|
||||
// Determine the arguments
|
||||
const args: any[] =
|
||||
(expression['arguments'] || []).map((arg: any) => simplify(arg));
|
||||
const parameters: string[] = targetFunction['parameters'];
|
||||
const defaults: any[] = targetFunction.defaults;
|
||||
if (defaults && defaults.length > args.length) {
|
||||
args.push(...defaults.slice(args.length).map((value: any) => simplify(value)));
|
||||
}
|
||||
const functionScope = BindingScope.build();
|
||||
for (let i = 0; i < parameters.length; i++) {
|
||||
functionScope.define(parameters[i], args[i]);
|
||||
}
|
||||
const oldScope = scope;
|
||||
let result: any;
|
||||
try {
|
||||
scope = functionScope.done();
|
||||
result = simplifyInContext(functionSymbol, value, depth + 1);
|
||||
} finally {
|
||||
scope = oldScope;
|
||||
}
|
||||
return result;
|
||||
calling.set(functionSymbol, true);
|
||||
try {
|
||||
const value = targetFunction['value'];
|
||||
if (value && (depth != 0 || value.__symbolic != 'error')) {
|
||||
const parameters: string[] = targetFunction['parameters'];
|
||||
const defaults: any[] = targetFunction.defaults;
|
||||
if (defaults && defaults.length > args.length) {
|
||||
args.push(...defaults.slice(args.length).map((value: any) => simplify(value)));
|
||||
}
|
||||
} finally {
|
||||
calling.delete(functionSymbol);
|
||||
const functionScope = BindingScope.build();
|
||||
for (let i = 0; i < parameters.length; i++) {
|
||||
functionScope.define(parameters[i], args[i]);
|
||||
}
|
||||
const oldScope = scope;
|
||||
let result: any;
|
||||
try {
|
||||
scope = functionScope.done();
|
||||
result = simplifyInContext(functionSymbol, value, depth + 1);
|
||||
} finally {
|
||||
scope = oldScope;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} finally {
|
||||
calling.delete(functionSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
@ -511,7 +339,7 @@ export class StaticReflector implements ReflectorReader {
|
||||
return {__symbolic: 'ignore'};
|
||||
}
|
||||
return simplify(
|
||||
{__symbolic: 'error', message: 'Function call not supported', context: callContext});
|
||||
{__symbolic: 'error', message: 'Function call not supported', context: functionSymbol});
|
||||
}
|
||||
|
||||
function simplify(expression: any): any {
|
||||
@ -540,7 +368,18 @@ export class StaticReflector implements ReflectorReader {
|
||||
return result;
|
||||
}
|
||||
if (expression instanceof StaticSymbol) {
|
||||
return expression;
|
||||
// Stop simplification at builtin symbols
|
||||
if (expression === self.opaqueToken || self.conversionMap.has(expression)) {
|
||||
return expression;
|
||||
} else {
|
||||
const staticSymbol = expression;
|
||||
const declarationValue = resolveReferenceValue(staticSymbol);
|
||||
if (declarationValue) {
|
||||
return simplifyInContext(staticSymbol, declarationValue, depth + 1);
|
||||
} else {
|
||||
return staticSymbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (expression) {
|
||||
if (expression['__symbolic']) {
|
||||
@ -618,50 +457,33 @@ export class StaticReflector implements ReflectorReader {
|
||||
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) {
|
||||
// Access to a static instance variable
|
||||
const member: string = expression['member'];
|
||||
const members = selectTarget.members ?
|
||||
(selectTarget.members as string[]).concat(member) :
|
||||
[member];
|
||||
const declarationValue = resolveReferenceValue(selectTarget);
|
||||
const members = selectTarget.members.concat(member);
|
||||
selectContext =
|
||||
self.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
|
||||
if (declarationValue && declarationValue.statics) {
|
||||
selectTarget = declarationValue.statics;
|
||||
const declarationValue = resolveReferenceValue(selectContext);
|
||||
if (declarationValue) {
|
||||
return simplifyInContext(selectContext, declarationValue, depth + 1);
|
||||
} else {
|
||||
return selectContext;
|
||||
}
|
||||
}
|
||||
const member = simplifyInContext(selectContext, expression['member'], depth + 1);
|
||||
if (selectTarget && isPrimitive(member))
|
||||
return simplifyInContext(selectContext, selectTarget[member], depth + 1);
|
||||
return null;
|
||||
case 'reference':
|
||||
if (!expression['name']) {
|
||||
return context;
|
||||
// Note: This only has to deal with variable references,
|
||||
// as symbol references have been converted into StaticSymbols already
|
||||
// in the StaticSymbolResolver!
|
||||
const name: string = expression['name'];
|
||||
const localValue = scope.resolve(name);
|
||||
if (localValue != BindingScope.missing) {
|
||||
return localValue;
|
||||
}
|
||||
if (!expression.module) {
|
||||
const name: string = expression['name'];
|
||||
const localValue = scope.resolve(name);
|
||||
if (localValue != BindingScope.missing) {
|
||||
return localValue;
|
||||
}
|
||||
}
|
||||
staticSymbol = resolveReference(context, expression);
|
||||
let result: any = staticSymbol;
|
||||
let declarationValue = resolveReferenceValue(result);
|
||||
if (declarationValue) {
|
||||
if (isOpaqueToken(staticSymbol, declarationValue)) {
|
||||
// If the referenced symbol is initalized by a new OpaqueToken we can keep the
|
||||
// reference to the symbol.
|
||||
return staticSymbol;
|
||||
}
|
||||
result = simplifyInContext(staticSymbol, declarationValue, depth + 1);
|
||||
}
|
||||
return result;
|
||||
break;
|
||||
case 'class':
|
||||
return context;
|
||||
case 'function':
|
||||
@ -669,26 +491,26 @@ export class StaticReflector implements ReflectorReader {
|
||||
case 'new':
|
||||
case 'call':
|
||||
// Determine if the function is a built-in conversion
|
||||
let target = expression['expression'];
|
||||
if (target['module']) {
|
||||
staticSymbol =
|
||||
self.findDeclaration(target['module'], target['name'], context.filePath);
|
||||
} else {
|
||||
staticSymbol = self.getStaticSymbol(context.filePath, target['name']);
|
||||
}
|
||||
let converter = self.conversionMap.get(staticSymbol);
|
||||
if (converter) {
|
||||
let args: any[] = expression['arguments'];
|
||||
if (!args) {
|
||||
args = [];
|
||||
staticSymbol = simplifyInContext(context, expression['expression'], depth + 1);
|
||||
if (staticSymbol instanceof StaticSymbol) {
|
||||
if (staticSymbol === self.opaqueToken) {
|
||||
// if somebody calls new OpaqueToken, don't create an OpaqueToken,
|
||||
// but rather return the symbol to which the OpaqueToken is assigned to.
|
||||
return context;
|
||||
}
|
||||
const argExpressions: any[] = expression['arguments'] || [];
|
||||
const args =
|
||||
argExpressions.map(arg => simplifyInContext(context, arg, depth + 1));
|
||||
let converter = self.conversionMap.get(staticSymbol);
|
||||
if (converter) {
|
||||
return converter(context, args);
|
||||
} else {
|
||||
// Determine if the function is one we can simplify.
|
||||
const targetFunction = resolveReferenceValue(staticSymbol);
|
||||
return simplifyCall(staticSymbol, targetFunction, args);
|
||||
}
|
||||
return converter(
|
||||
context, args.map(arg => simplifyInContext(context, arg, depth + 1)));
|
||||
}
|
||||
|
||||
// Determine if the function is one we can simplify.
|
||||
return simplifyCall(expression);
|
||||
|
||||
break;
|
||||
case 'error':
|
||||
let message = produceErrorMessage(expression);
|
||||
if (expression['line']) {
|
||||
@ -709,7 +531,9 @@ export class StaticReflector implements ReflectorReader {
|
||||
try {
|
||||
return simplify(value);
|
||||
} catch (e) {
|
||||
const message = `${e.message}, resolving symbol ${context.name} in ${context.filePath}`;
|
||||
const members = context.members.length ? `.${context.members.join('.')}` : '';
|
||||
const message =
|
||||
`${e.message}, resolving symbol ${context.name}${members} in ${context.filePath}`;
|
||||
if (e.fileName) {
|
||||
throw positionalError(message, e.fileName, e.line, e.column);
|
||||
}
|
||||
@ -733,40 +557,10 @@ export class StaticReflector implements ReflectorReader {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param module an absolute path to a module file.
|
||||
*/
|
||||
public getModuleMetadata(module: string): {[key: string]: any} {
|
||||
let moduleMetadata = this.metadataCache.get(module);
|
||||
if (!moduleMetadata) {
|
||||
const moduleMetadatas = this.host.getMetadataFor(module);
|
||||
if (moduleMetadatas) {
|
||||
let maxVersion = -1;
|
||||
moduleMetadatas.forEach((md) => {
|
||||
if (md['version'] > maxVersion) {
|
||||
maxVersion = md['version'];
|
||||
moduleMetadata = md;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!moduleMetadata) {
|
||||
moduleMetadata =
|
||||
{__symbolic: 'module', version: SUPPORTED_SCHEMA_VERSION, module: module, metadata: {}};
|
||||
}
|
||||
if (moduleMetadata['version'] != SUPPORTED_SCHEMA_VERSION) {
|
||||
const errorMessage = moduleMetadata['version'] == 2 ?
|
||||
`Unsupported metadata version ${moduleMetadata['version']} for module ${module}. This module should be compiled with a newer version of ngc` :
|
||||
`Metadata version mismatch for module ${module}, found version ${moduleMetadata['version']}, expected ${SUPPORTED_SCHEMA_VERSION}`;
|
||||
this.reportError(new Error(errorMessage), null);
|
||||
}
|
||||
this.metadataCache.set(module, moduleMetadata);
|
||||
}
|
||||
return moduleMetadata;
|
||||
}
|
||||
|
||||
private getTypeMetadata(type: StaticSymbol): {[key: string]: any} {
|
||||
const moduleMetadata = this.getModuleMetadata(type.filePath);
|
||||
return moduleMetadata['metadata'][type.name] || {__symbolic: 'class'};
|
||||
const resolvedSymbol = this.symbolResolver.resolveSymbol(type);
|
||||
return resolvedSymbol && resolvedSymbol.metadata ? resolvedSymbol.metadata :
|
||||
{__symbolic: 'class'};
|
||||
}
|
||||
}
|
||||
|
||||
@ -858,7 +652,7 @@ class PopulatedScope extends BindingScope {
|
||||
}
|
||||
|
||||
function sameSymbol(a: StaticSymbol, b: StaticSymbol): boolean {
|
||||
return a === b || (a.name == b.name && a.filePath == b.filePath);
|
||||
return a === b;
|
||||
}
|
||||
|
||||
function shouldIgnore(value: any): boolean {
|
||||
|
@ -14,3 +14,23 @@
|
||||
export class StaticSymbol {
|
||||
constructor(public filePath: string, public name: string, public members?: string[]) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* A cache of static symbol used by the StaticReflector to return the same symbol for the
|
||||
* same symbol values.
|
||||
*/
|
||||
export class StaticSymbolCache {
|
||||
private cache = new Map<string, StaticSymbol>();
|
||||
|
||||
get(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
||||
members = members || [];
|
||||
const memberSuffix = members.length ? `.${ members.join('.')}` : '';
|
||||
const key = `"${declarationFile}".${name}${memberSuffix}`;
|
||||
let result = this.cache.get(key);
|
||||
if (!result) {
|
||||
result = new StaticSymbol(declarationFile, name, members);
|
||||
this.cache.set(key, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
289
modules/@angular/compiler/src/aot/static_symbol_resolver.ts
Normal file
289
modules/@angular/compiler/src/aot/static_symbol_resolver.ts
Normal file
@ -0,0 +1,289 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. 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 {SummaryResolver} from '../summary_resolver';
|
||||
import {ValueTransformer, visitValue} from '../util';
|
||||
|
||||
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
||||
|
||||
export class ResolvedStaticSymbol {
|
||||
constructor(public symbol: StaticSymbol, public metadata: any) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* The host of the SymbolResolverHost disconnects the implementation from TypeScript / other
|
||||
* language
|
||||
* services and from underlying file systems.
|
||||
*/
|
||||
export interface StaticSymbolResolverHost {
|
||||
/**
|
||||
* Return a ModuleMetadata for the given module.
|
||||
* Angular 2 CLI will produce this metadata for a module whenever a .d.ts files is
|
||||
* produced and the module has exported variables or classes with decorators. Module metadata can
|
||||
* also be produced directly from TypeScript sources by using MetadataCollector in tools/metadata.
|
||||
*
|
||||
* @param modulePath is a string identifier for a module as an absolute path.
|
||||
* @returns the metadata for the given module.
|
||||
*/
|
||||
getMetadataFor(modulePath: string): {[key: string]: any}[];
|
||||
|
||||
/**
|
||||
* Converts a module name that is used in an `import` to a file path.
|
||||
* I.e.
|
||||
* `path/to/containingFile.ts` containing `import {...} from 'module-name'`.
|
||||
*/
|
||||
moduleNameToFileName(moduleName: string, containingFile: string): string /*|null*/;
|
||||
}
|
||||
|
||||
const SUPPORTED_SCHEMA_VERSION = 3;
|
||||
|
||||
/**
|
||||
* This class is responsible for loading metadata per symbol,
|
||||
* and normalizing references between symbols.
|
||||
*/
|
||||
export class StaticSymbolResolver {
|
||||
private metadataCache = new Map<string, {[key: string]: any}>();
|
||||
private resolvedSymbols = new Map<StaticSymbol, ResolvedStaticSymbol>();
|
||||
private resolvedFilePaths = new Set<string>();
|
||||
|
||||
constructor(
|
||||
private host: StaticSymbolResolverHost, private staticSymbolCache: StaticSymbolCache,
|
||||
private summaryResolver: SummaryResolver<StaticSymbol>,
|
||||
private errorRecorder?: (error: any, fileName: string) => void) {}
|
||||
|
||||
resolveSymbol(staticSymbol: StaticSymbol): ResolvedStaticSymbol {
|
||||
if (staticSymbol.members.length > 0) {
|
||||
return this._resolveSymbolMembers(staticSymbol);
|
||||
}
|
||||
let result = this._resolveSymbolFromSummary(staticSymbol);
|
||||
if (!result) {
|
||||
// Note: Some users use libraries that were not compiled with ngc, i.e. they don't
|
||||
// have summaries, only .d.ts files. So we always need to check both, the summary
|
||||
// and metadata.
|
||||
this._createSymbolsOf(staticSymbol.filePath);
|
||||
result = this.resolvedSymbols.get(staticSymbol);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private _resolveSymbolMembers(staticSymbol: StaticSymbol): ResolvedStaticSymbol {
|
||||
const members = staticSymbol.members;
|
||||
const baseResolvedSymbol =
|
||||
this.resolveSymbol(this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name));
|
||||
if (!baseResolvedSymbol) {
|
||||
return null;
|
||||
}
|
||||
const baseMetadata = baseResolvedSymbol.metadata;
|
||||
if (baseMetadata instanceof StaticSymbol) {
|
||||
return new ResolvedStaticSymbol(
|
||||
staticSymbol, this.getStaticSymbol(baseMetadata.filePath, baseMetadata.name, members));
|
||||
} else if (baseMetadata && baseMetadata.__symbolic === 'class') {
|
||||
if (baseMetadata.statics && members.length === 1) {
|
||||
return new ResolvedStaticSymbol(staticSymbol, baseMetadata.statics[members[0]]);
|
||||
}
|
||||
} else {
|
||||
let value = baseMetadata;
|
||||
for (var i = 0; i < members.length && value; i++) {
|
||||
value = value[members[i]];
|
||||
}
|
||||
return new ResolvedStaticSymbol(staticSymbol, value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private _resolveSymbolFromSummary(staticSymbol: StaticSymbol): ResolvedStaticSymbol {
|
||||
const summary = this.summaryResolver.resolveSummary(staticSymbol);
|
||||
return summary ? new ResolvedStaticSymbol(staticSymbol, summary.metadata) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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: string, name: string, members?: string[]): StaticSymbol {
|
||||
return this.staticSymbolCache.get(declarationFile, name, members);
|
||||
}
|
||||
|
||||
getSymbolsOf(filePath: string): StaticSymbol[] {
|
||||
// Note: Some users use libraries that were not compiled with ngc, i.e. they don't
|
||||
// have summaries, only .d.ts files. So we always need to check both, the summary
|
||||
// and metadata.
|
||||
let symbols = new Set<StaticSymbol>(this.summaryResolver.getSymbolsOf(filePath));
|
||||
this._createSymbolsOf(filePath);
|
||||
this.resolvedSymbols.forEach((resolvedSymbol) => {
|
||||
if (resolvedSymbol.symbol.filePath === filePath) {
|
||||
symbols.add(resolvedSymbol.symbol);
|
||||
}
|
||||
});
|
||||
return Array.from(symbols);
|
||||
}
|
||||
|
||||
private _createSymbolsOf(filePath: string) {
|
||||
if (this.resolvedFilePaths.has(filePath)) {
|
||||
return;
|
||||
}
|
||||
this.resolvedFilePaths.add(filePath);
|
||||
const resolvedSymbols: ResolvedStaticSymbol[] = [];
|
||||
const metadata = this.getModuleMetadata(filePath);
|
||||
if (metadata['metadata']) {
|
||||
// handle direct declarations of the symbol
|
||||
Object.keys(metadata['metadata']).forEach((symbolName) => {
|
||||
const symbolMeta = metadata['metadata'][symbolName];
|
||||
resolvedSymbols.push(
|
||||
this.createResolvedSymbol(this.getStaticSymbol(filePath, symbolName), symbolMeta));
|
||||
});
|
||||
}
|
||||
|
||||
// handle the symbols in one of the re-export location
|
||||
if (metadata['exports']) {
|
||||
for (const moduleExport of metadata['exports']) {
|
||||
// handle the symbols in the list of explicitly re-exported symbols.
|
||||
if (moduleExport.export) {
|
||||
moduleExport.export.forEach((exportSymbol: any) => {
|
||||
let symbolName: string;
|
||||
if (typeof exportSymbol === 'string') {
|
||||
symbolName = exportSymbol;
|
||||
} else {
|
||||
symbolName = exportSymbol.as;
|
||||
}
|
||||
let symName = symbolName;
|
||||
if (typeof exportSymbol !== 'string') {
|
||||
symName = exportSymbol.name;
|
||||
}
|
||||
const resolvedModule = this.resolveModule(moduleExport.from, filePath);
|
||||
if (resolvedModule) {
|
||||
const targetSymbol = this.getStaticSymbol(resolvedModule, symName);
|
||||
const sourceSymbol = this.getStaticSymbol(filePath, symbolName);
|
||||
resolvedSymbols.push(new ResolvedStaticSymbol(sourceSymbol, targetSymbol));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// handle the symbols via export * directives.
|
||||
const resolvedModule = this.resolveModule(moduleExport.from, filePath);
|
||||
if (resolvedModule) {
|
||||
const nestedExports = this.getSymbolsOf(resolvedModule);
|
||||
nestedExports.forEach((targetSymbol) => {
|
||||
const sourceSymbol = this.getStaticSymbol(filePath, targetSymbol.name);
|
||||
resolvedSymbols.push(new ResolvedStaticSymbol(sourceSymbol, targetSymbol));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
resolvedSymbols.forEach(
|
||||
(resolvedSymbol) => this.resolvedSymbols.set(resolvedSymbol.symbol, resolvedSymbol));
|
||||
}
|
||||
|
||||
private createResolvedSymbol(sourceSymbol: StaticSymbol, metadata: any): ResolvedStaticSymbol {
|
||||
const self = this;
|
||||
|
||||
class ReferenceTransformer extends ValueTransformer {
|
||||
visitStringMap(map: {[key: string]: any}, functionParams: string[]): any {
|
||||
const symbolic = map['__symbolic'];
|
||||
if (symbolic === 'function') {
|
||||
const oldLen = functionParams.length;
|
||||
functionParams.push(...(map['parameters'] || []));
|
||||
const result = super.visitStringMap(map, functionParams);
|
||||
functionParams.length = oldLen;
|
||||
return result;
|
||||
} else if (symbolic === 'reference') {
|
||||
const module = map['module'];
|
||||
const name = map['name'];
|
||||
if (!name) {
|
||||
return null;
|
||||
}
|
||||
let filePath: string;
|
||||
if (module) {
|
||||
filePath = self.resolveModule(module, sourceSymbol.filePath);
|
||||
if (!filePath) {
|
||||
return {
|
||||
__symbolic: 'error',
|
||||
message: `Could not resolve ${module} relative to ${sourceSymbol.filePath}.`
|
||||
};
|
||||
}
|
||||
} else {
|
||||
const isFunctionParam = functionParams.indexOf(name) >= 0;
|
||||
if (!isFunctionParam) {
|
||||
filePath = sourceSymbol.filePath;
|
||||
}
|
||||
}
|
||||
if (filePath) {
|
||||
return self.getStaticSymbol(filePath, name);
|
||||
} else {
|
||||
// reference to a function parameter
|
||||
return {__symbolic: 'reference', name: name};
|
||||
}
|
||||
} else {
|
||||
return super.visitStringMap(map, functionParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const transformedMeta = visitValue(metadata, new ReferenceTransformer(), []);
|
||||
return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
|
||||
}
|
||||
|
||||
private reportError(error: Error, context: StaticSymbol, path?: string) {
|
||||
if (this.errorRecorder) {
|
||||
this.errorRecorder(error, (context && context.filePath) || path);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param module an absolute path to a module file.
|
||||
*/
|
||||
private getModuleMetadata(module: string): {[key: string]: any} {
|
||||
let moduleMetadata = this.metadataCache.get(module);
|
||||
if (!moduleMetadata) {
|
||||
const moduleMetadatas = this.host.getMetadataFor(module);
|
||||
if (moduleMetadatas) {
|
||||
let maxVersion = -1;
|
||||
moduleMetadatas.forEach((md) => {
|
||||
if (md['version'] > maxVersion) {
|
||||
maxVersion = md['version'];
|
||||
moduleMetadata = md;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!moduleMetadata) {
|
||||
moduleMetadata =
|
||||
{__symbolic: 'module', version: SUPPORTED_SCHEMA_VERSION, module: module, metadata: {}};
|
||||
}
|
||||
if (moduleMetadata['version'] != SUPPORTED_SCHEMA_VERSION) {
|
||||
const errorMessage = moduleMetadata['version'] == 2 ?
|
||||
`Unsupported metadata version ${moduleMetadata['version']} for module ${module}. This module should be compiled with a newer version of ngc` :
|
||||
`Metadata version mismatch for module ${module}, found version ${moduleMetadata['version']}, expected ${SUPPORTED_SCHEMA_VERSION}`;
|
||||
this.reportError(new Error(errorMessage), null);
|
||||
}
|
||||
this.metadataCache.set(module, moduleMetadata);
|
||||
}
|
||||
return moduleMetadata;
|
||||
}
|
||||
|
||||
getSymbolByModule(module: string, symbolName: string, containingFile?: string): StaticSymbol {
|
||||
const filePath = this.resolveModule(module, containingFile);
|
||||
if (!filePath) {
|
||||
throw new Error(`Could not resolve module ${module} relative to ${containingFile}`);
|
||||
}
|
||||
return this.getStaticSymbol(filePath, symbolName);
|
||||
}
|
||||
|
||||
private resolveModule(module: string, containingFile: string): string {
|
||||
try {
|
||||
return this.host.moduleNameToFileName(module, containingFile);
|
||||
} catch (e) {
|
||||
console.error(`Could not resolve module '${module}' relative to file ${containingFile}`);
|
||||
this.reportError(new e, null, containingFile);
|
||||
}
|
||||
}
|
||||
}
|
@ -5,13 +5,12 @@
|
||||
* 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 {CompileDirectiveSummary, CompileIdentifierMetadata, CompileNgModuleSummary, CompilePipeSummary, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary, identifierModuleUrl, identifierName} from '../compile_metadata';
|
||||
import {SummaryResolver} from '../summary_resolver';
|
||||
import {CompileSummaryKind, CompileTypeSummary} from '../compile_metadata';
|
||||
import {Summary, SummaryResolver} from '../summary_resolver';
|
||||
|
||||
import {GeneratedFile} from './generated_file';
|
||||
import {StaticReflector} from './static_reflector';
|
||||
import {StaticSymbol} from './static_symbol';
|
||||
import {filterFileByPatterns} from './utils';
|
||||
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
||||
import {ResolvedStaticSymbol} from './static_symbol_resolver';
|
||||
import {deserializeSummaries, summaryFileName} from './summary_serializer';
|
||||
|
||||
const STRIP_SRC_FILE_SUFFIXES = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
||||
|
||||
@ -19,106 +18,60 @@ export interface AotSummaryResolverHost {
|
||||
/**
|
||||
* Loads an NgModule/Directive/Pipe summary file
|
||||
*/
|
||||
loadSummary(filePath: string): string;
|
||||
loadSummary(filePath: string): string /*|null*/;
|
||||
|
||||
/**
|
||||
* Returns the output file path of a source file.
|
||||
* E.g.
|
||||
* `some_file.ts` -> `some_file.d.ts`
|
||||
* Returns whether a file is a source file or not.
|
||||
*/
|
||||
getOutputFileName(sourceFilePath: string): string;
|
||||
isSourceFile(sourceFilePath: string): boolean;
|
||||
}
|
||||
|
||||
export interface AotSummaryResolverOptions {
|
||||
includeFilePattern?: RegExp;
|
||||
excludeFilePattern?: RegExp;
|
||||
}
|
||||
export class AotSummaryResolver implements SummaryResolver<StaticSymbol> {
|
||||
private summaryCache = new Map<StaticSymbol, Summary<StaticSymbol>>();
|
||||
private loadedFilePaths = new Set<string>();
|
||||
|
||||
export class AotSummaryResolver implements SummaryResolver {
|
||||
private summaryCache: {[cacheKey: string]: CompileTypeSummary} = {};
|
||||
constructor(private host: AotSummaryResolverHost, private staticSymbolCache: StaticSymbolCache) {}
|
||||
|
||||
constructor(
|
||||
private host: AotSummaryResolverHost, private staticReflector: StaticReflector,
|
||||
private options: AotSummaryResolverOptions) {}
|
||||
|
||||
serializeSummaries(srcFileUrl: string, summaries: CompileTypeSummary[]): GeneratedFile {
|
||||
const jsonReplacer = (key: string, value: any) => {
|
||||
if (value instanceof StaticSymbol) {
|
||||
// We convert the source filenames into output filenames,
|
||||
// as the generated summary file will be used when the current
|
||||
// compilation unit is used as a library
|
||||
return {
|
||||
'__symbolic__': 'symbol',
|
||||
'name': value.name,
|
||||
'path': this.host.getOutputFileName(value.filePath),
|
||||
'members': value.members
|
||||
};
|
||||
}
|
||||
return value;
|
||||
};
|
||||
const allSummaries = summaries.slice();
|
||||
summaries.forEach((summary) => {
|
||||
if (summary.summaryKind === CompileSummaryKind.NgModule) {
|
||||
const moduleMeta = <CompileNgModuleSummary>summary;
|
||||
moduleMeta.exportedDirectives.concat(moduleMeta.exportedPipes).forEach((id) => {
|
||||
if (!filterFileByPatterns(id.reference.filePath, this.options)) {
|
||||
allSummaries.push(this.resolveSummary(id.reference));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return new GeneratedFile(
|
||||
srcFileUrl, summaryFileName(srcFileUrl), JSON.stringify(allSummaries, jsonReplacer));
|
||||
private _assertNoMembers(symbol: StaticSymbol) {
|
||||
if (symbol.members.length) {
|
||||
throw new Error(
|
||||
`Internal state: StaticSymbols in summaries can't have members! ${JSON.stringify(symbol)}`);
|
||||
}
|
||||
}
|
||||
|
||||
private _cacheKey(symbol: StaticSymbol) { return `${symbol.filePath}|${symbol.name}`; }
|
||||
resolveSummary(staticSymbol: StaticSymbol): Summary<StaticSymbol> {
|
||||
this._assertNoMembers(staticSymbol);
|
||||
let summary = this.summaryCache.get(staticSymbol);
|
||||
if (!summary) {
|
||||
this._loadSummaryFile(staticSymbol.filePath);
|
||||
summary = this.summaryCache.get(staticSymbol);
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
|
||||
resolveSummary(staticSymbol: StaticSymbol): any {
|
||||
const filePath = staticSymbol.filePath;
|
||||
const name = staticSymbol.name;
|
||||
const cacheKey = this._cacheKey(staticSymbol);
|
||||
if (!filterFileByPatterns(filePath, this.options)) {
|
||||
let summary = this.summaryCache[cacheKey];
|
||||
getSymbolsOf(filePath: string): StaticSymbol[] {
|
||||
this._loadSummaryFile(filePath);
|
||||
return Array.from(this.summaryCache.keys()).filter((symbol) => symbol.filePath === filePath);
|
||||
}
|
||||
|
||||
private _loadSummaryFile(filePath: string) {
|
||||
if (this.loadedFilePaths.has(filePath)) {
|
||||
return;
|
||||
}
|
||||
this.loadedFilePaths.add(filePath);
|
||||
if (!this.host.isSourceFile(filePath)) {
|
||||
const summaryFilePath = summaryFileName(filePath);
|
||||
if (!summary) {
|
||||
try {
|
||||
const jsonReviver = (key: string, value: any) => {
|
||||
if (value && value['__symbolic__'] === 'symbol') {
|
||||
// Note: We can't use staticReflector.findDeclaration here:
|
||||
// Summary files can contain symbols of transitive compilation units
|
||||
// (via the providers), and findDeclaration needs .metadata.json / .d.ts files,
|
||||
// but we don't want to depend on these for transitive dependencies.
|
||||
return this.staticReflector.getStaticSymbol(
|
||||
value['path'], value['name'], value['members']);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
const readSummaries: CompileTypeSummary[] =
|
||||
JSON.parse(this.host.loadSummary(summaryFilePath), jsonReviver);
|
||||
readSummaries.forEach((summary) => {
|
||||
const filePath = summary.type.reference.filePath;
|
||||
this.summaryCache[this._cacheKey(summary.type.reference)] = summary;
|
||||
});
|
||||
summary = this.summaryCache[cacheKey];
|
||||
} catch (e) {
|
||||
console.error(`Error loading summary file ${summaryFilePath}`);
|
||||
throw e;
|
||||
}
|
||||
let json: string;
|
||||
try {
|
||||
json = this.host.loadSummary(summaryFilePath);
|
||||
} catch (e) {
|
||||
console.error(`Error loading summary file ${summaryFilePath}`);
|
||||
throw e;
|
||||
}
|
||||
if (!summary) {
|
||||
throw new Error(
|
||||
`Could not find the symbol ${name} in the summary file ${summaryFilePath}!`);
|
||||
if (json) {
|
||||
const readSummaries = deserializeSummaries(this.staticSymbolCache, json);
|
||||
readSummaries.forEach((summary) => { this.summaryCache.set(summary.symbol, summary); });
|
||||
}
|
||||
return summary;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function summaryFileName(fileName: string): string {
|
||||
const fileNameWithoutSuffix = fileName.replace(STRIP_SRC_FILE_SUFFIXES, '');
|
||||
return `${fileNameWithoutSuffix}.ngsummary.json`;
|
||||
}
|
||||
|
183
modules/@angular/compiler/src/aot/summary_serializer.ts
Normal file
183
modules/@angular/compiler/src/aot/summary_serializer.ts
Normal file
@ -0,0 +1,183 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. 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 {CompileDirectiveSummary, CompileIdentifierMetadata, CompileNgModuleSummary, CompilePipeSummary, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary, identifierModuleUrl, identifierName} from '../compile_metadata';
|
||||
import {Summary, SummaryResolver} from '../summary_resolver';
|
||||
import {ValueTransformer, visitValue} from '../util';
|
||||
|
||||
import {GeneratedFile} from './generated_file';
|
||||
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
||||
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
|
||||
|
||||
const STRIP_SRC_FILE_SUFFIXES = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
||||
|
||||
export interface AotSummarySerializerHost {
|
||||
/**
|
||||
* Returns the output file path of a source file.
|
||||
* E.g.
|
||||
* `some_file.ts` -> `some_file.d.ts`
|
||||
*/
|
||||
getOutputFileName(sourceFilePath: string): string;
|
||||
/**
|
||||
* Returns whether a file is a source file or not.
|
||||
*/
|
||||
isSourceFile(sourceFilePath: string): boolean;
|
||||
}
|
||||
|
||||
export function serializeSummaries(
|
||||
host: AotSummarySerializerHost, summaryResolver: SummaryResolver<StaticSymbol>,
|
||||
symbolResolver: StaticSymbolResolver,
|
||||
|
||||
symbols: ResolvedStaticSymbol[], types: CompileTypeSummary[]): string {
|
||||
const serializer = new Serializer(host);
|
||||
|
||||
// for symbols, we use everything except for the class metadata itself
|
||||
// (we keep the statics though), as the class metadata is contained in the
|
||||
// CompileTypeSummary.
|
||||
symbols.forEach(
|
||||
(resolvedSymbol) => serializer.addOrMergeSummary(
|
||||
{symbol: resolvedSymbol.symbol, metadata: resolvedSymbol.metadata}));
|
||||
// Add summaries that are referenced by the given symbols (transitively)
|
||||
// Note: the serializer.symbols array might be growing while
|
||||
// we execute the loop!
|
||||
for (let processedIndex = 0; processedIndex < serializer.symbols.length; processedIndex++) {
|
||||
const symbol = serializer.symbols[processedIndex];
|
||||
if (!host.isSourceFile(symbol.filePath)) {
|
||||
let summary = summaryResolver.resolveSummary(symbol);
|
||||
if (!summary) {
|
||||
// some symbols might originate from a plain typescript library
|
||||
// that just exported .d.ts and .metadata.json files, i.e. where no summary
|
||||
// files were created.
|
||||
const resolvedSymbol = symbolResolver.resolveSymbol(symbol);
|
||||
if (resolvedSymbol) {
|
||||
summary = {symbol: resolvedSymbol.symbol, metadata: resolvedSymbol.metadata};
|
||||
}
|
||||
}
|
||||
if (summary) {
|
||||
serializer.addOrMergeSummary(summary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add type summaries.
|
||||
// Note: We don't add the summaries of all referenced symbols as for the ResolvedSymbols,
|
||||
// as the type summaries already contain the transitive data that they require
|
||||
// (in a minimal way).
|
||||
types.forEach((typeSummary) => {
|
||||
serializer.addOrMergeSummary(
|
||||
{symbol: typeSummary.type.reference, metadata: {__symbolic: 'class'}, type: typeSummary});
|
||||
if (typeSummary.summaryKind === CompileSummaryKind.NgModule) {
|
||||
const ngModuleSummary = <CompileNgModuleSummary>typeSummary;
|
||||
ngModuleSummary.exportedDirectives.concat(ngModuleSummary.exportedPipes).forEach((id) => {
|
||||
const symbol: StaticSymbol = id.reference;
|
||||
if (!host.isSourceFile(symbol.filePath)) {
|
||||
serializer.addOrMergeSummary(summaryResolver.resolveSummary(symbol));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return serializer.serialize();
|
||||
}
|
||||
|
||||
export function deserializeSummaries(
|
||||
symbolCache: StaticSymbolCache, json: string): Summary<StaticSymbol>[] {
|
||||
const deserializer = new Deserializer(symbolCache);
|
||||
return deserializer.deserialize(json);
|
||||
}
|
||||
|
||||
export function summaryFileName(fileName: string): string {
|
||||
const fileNameWithoutSuffix = fileName.replace(STRIP_SRC_FILE_SUFFIXES, '');
|
||||
return `${fileNameWithoutSuffix}.ngsummary.json`;
|
||||
}
|
||||
|
||||
class Serializer extends ValueTransformer {
|
||||
symbols: StaticSymbol[] = [];
|
||||
private indexBySymbol = new Map<StaticSymbol, number>();
|
||||
// This now contains a `__symbol: number` in the place of
|
||||
// StaticSymbols, but otherwise has the same shape as the original objects.
|
||||
private processedSummaryBySymbol = new Map<StaticSymbol, any>();
|
||||
private processedSummaries: any[] = [];
|
||||
|
||||
constructor(private host: AotSummarySerializerHost) { super(); }
|
||||
|
||||
addOrMergeSummary(summary: Summary<StaticSymbol>) {
|
||||
let symbolMeta = summary.metadata;
|
||||
if (symbolMeta && symbolMeta.__symbolic === 'class') {
|
||||
// For classes, we only keep their statics, but not the metadata
|
||||
// of the class itself as that has been captured already via other summaries
|
||||
// (e.g. DirectiveSummary, ...).
|
||||
symbolMeta = {__symbolic: 'class', statics: symbolMeta.statics};
|
||||
}
|
||||
|
||||
let processedSummary = this.processedSummaryBySymbol.get(summary.symbol);
|
||||
if (!processedSummary) {
|
||||
processedSummary = this.processValue({symbol: summary.symbol});
|
||||
this.processedSummaries.push(processedSummary);
|
||||
this.processedSummaryBySymbol.set(summary.symbol, processedSummary);
|
||||
}
|
||||
// Note: == by purpose to compare with undefined!
|
||||
if (processedSummary.metadata == null && symbolMeta != null) {
|
||||
processedSummary.metadata = this.processValue(symbolMeta);
|
||||
}
|
||||
// Note: == by purpose to compare with undefined!
|
||||
if (processedSummary.type == null && summary.type != null) {
|
||||
processedSummary.type = this.processValue(summary.type);
|
||||
}
|
||||
}
|
||||
|
||||
serialize(): string {
|
||||
return JSON.stringify({
|
||||
summaries: this.processedSummaries,
|
||||
symbols: this.symbols.map((symbol, index) => {
|
||||
return {
|
||||
__symbol: index,
|
||||
name: symbol.name,
|
||||
// We convert the source filenames tinto output filenames,
|
||||
// as the generated summary file will be used when teh current
|
||||
// compilation unit is used as a library
|
||||
filePath: this.host.getOutputFileName(symbol.filePath)
|
||||
};
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
private processValue(value: any): any { return visitValue(value, this, null); }
|
||||
|
||||
visitOther(value: any, context: any): any {
|
||||
if (value instanceof StaticSymbol) {
|
||||
let index = this.indexBySymbol.get(value);
|
||||
// Note: == by purpose to compare with undefined!
|
||||
if (index == null) {
|
||||
index = this.indexBySymbol.size;
|
||||
this.indexBySymbol.set(value, index);
|
||||
this.symbols.push(value);
|
||||
}
|
||||
return {__symbol: index};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Deserializer extends ValueTransformer {
|
||||
private symbols: StaticSymbol[];
|
||||
|
||||
constructor(private symbolCache: StaticSymbolCache) { super(); }
|
||||
|
||||
deserialize(json: string): Summary<StaticSymbol>[] {
|
||||
const data: {summaries: any[], symbols: any[]} = JSON.parse(json);
|
||||
this.symbols = data.symbols.map(
|
||||
serializedSymbol => this.symbolCache.get(serializedSymbol.filePath, serializedSymbol.name));
|
||||
return visitValue(data.summaries, this, null);
|
||||
}
|
||||
|
||||
visitStringMap(map: {[key: string]: any}, context: any): any {
|
||||
if ('__symbol' in map) {
|
||||
return this.symbols[map['__symbol']];
|
||||
} else {
|
||||
return super.visitStringMap(map, context);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. 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
|
||||
*/
|
||||
|
||||
export function filterFileByPatterns(
|
||||
fileName: string, options: {includeFilePattern?: RegExp, excludeFilePattern?: RegExp} = {}) {
|
||||
let match = true;
|
||||
if (options.includeFilePattern) {
|
||||
match = match && !!options.includeFilePattern.exec(fileName);
|
||||
}
|
||||
if (options.excludeFilePattern) {
|
||||
match = match && !options.excludeFilePattern.exec(fileName);
|
||||
}
|
||||
return match;
|
||||
}
|
@ -115,10 +115,10 @@ export function identifierModuleUrl(compileIdentifier: CompileIdentifierMetadata
|
||||
export interface CompileIdentifierMetadata { reference: any; }
|
||||
|
||||
export enum CompileSummaryKind {
|
||||
Template,
|
||||
Pipe,
|
||||
Directive,
|
||||
NgModule
|
||||
NgModule,
|
||||
Injectable
|
||||
}
|
||||
|
||||
/**
|
||||
@ -126,9 +126,10 @@ export enum CompileSummaryKind {
|
||||
* in other modules / components. However, this data is not enough to compile
|
||||
* the directive / module itself.
|
||||
*/
|
||||
export interface CompileSummary { summaryKind: CompileSummaryKind; }
|
||||
|
||||
export interface CompileTypeSummary extends CompileSummary { type: CompileTypeMetadata; }
|
||||
export interface CompileTypeSummary {
|
||||
summaryKind: CompileSummaryKind
|
||||
type: CompileTypeMetadata;
|
||||
}
|
||||
|
||||
export interface CompileDiDependencyMetadata {
|
||||
isAttribute?: boolean;
|
||||
@ -210,7 +211,7 @@ export class CompileStylesheetMetadata {
|
||||
/**
|
||||
* Summary Metadata regarding compilation of a template.
|
||||
*/
|
||||
export interface CompileTemplateSummary extends CompileSummary {
|
||||
export interface CompileTemplateSummary {
|
||||
animations: string[];
|
||||
ngContentSelectors: string[];
|
||||
encapsulation: ViewEncapsulation;
|
||||
@ -258,7 +259,6 @@ export class CompileTemplateMetadata {
|
||||
|
||||
toSummary(): CompileTemplateSummary {
|
||||
return {
|
||||
summaryKind: CompileSummaryKind.Template,
|
||||
animations: this.animations.map(anim => anim.name),
|
||||
ngContentSelectors: this.ngContentSelectors,
|
||||
encapsulation: this.encapsulation
|
||||
|
@ -6,11 +6,12 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, Injectable, ViewEncapsulation} from '@angular/core';
|
||||
import {Component, ViewEncapsulation} from '@angular/core';
|
||||
|
||||
import {CompileAnimationEntryMetadata, CompileDirectiveMetadata, CompileStylesheetMetadata, CompileTemplateMetadata, CompileTypeMetadata} from './compile_metadata';
|
||||
import {CompilerConfig} from './config';
|
||||
import {isBlank, isPresent, stringify} from './facade/lang';
|
||||
import {CompilerInjectable} from './injectable';
|
||||
import * as html from './ml_parser/ast';
|
||||
import {HtmlParser} from './ml_parser/html_parser';
|
||||
import {InterpolationConfig} from './ml_parser/interpolation_config';
|
||||
@ -32,7 +33,7 @@ export interface PrenormalizedTemplateMetadata {
|
||||
animations?: CompileAnimationEntryMetadata[];
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class DirectiveNormalizer {
|
||||
private _resourceLoaderCache = new Map<string, Promise<string>>();
|
||||
|
||||
|
@ -6,14 +6,16 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, Directive, HostBinding, HostListener, Injectable, Input, Output, Query, Type, resolveForwardRef} from '@angular/core';
|
||||
import {Component, Directive, HostBinding, HostListener, Input, Output, Query, Type, resolveForwardRef} from '@angular/core';
|
||||
|
||||
import {ListWrapper, StringMapWrapper} from './facade/collection';
|
||||
import {stringify} from './facade/lang';
|
||||
import {CompilerInjectable} from './injectable';
|
||||
import {ReflectorReader, reflector} from './private_import_core';
|
||||
import {splitAtColon} from './util';
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Resolve a `Type` for {@link Directive}.
|
||||
*
|
||||
@ -21,7 +23,7 @@ import {splitAtColon} from './util';
|
||||
*
|
||||
* See {@link Compiler}
|
||||
*/
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class DirectiveResolver {
|
||||
constructor(private _reflector: ReflectorReader = reflector) {}
|
||||
|
||||
|
@ -6,8 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injectable} from '@angular/core';
|
||||
|
||||
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, identifierModuleUrl, identifierName} from './compile_metadata';
|
||||
import {createCheckBindingField, createCheckBindingStmt} from './compiler_util/binding_util';
|
||||
import {EventHandlerVars, convertActionBinding, convertPropertyBinding} from './compiler_util/expression_converter';
|
||||
@ -15,6 +13,7 @@ import {triggerAnimation, writeToRenderer} from './compiler_util/render_util';
|
||||
import {CompilerConfig} from './config';
|
||||
import {Parser} from './expression_parser/parser';
|
||||
import {Identifiers, createIdentifier} from './identifiers';
|
||||
import {CompilerInjectable} from './injectable';
|
||||
import {DEFAULT_INTERPOLATION_CONFIG} from './ml_parser/interpolation_config';
|
||||
import {ClassBuilder, createClassStmt} from './output/class_builder';
|
||||
import * as o from './output/output_ast';
|
||||
@ -51,7 +50,7 @@ const RESET_CHANGES_STMT = o.THIS_EXPR.prop(CHANGES_FIELD_NAME).set(o.literalMap
|
||||
*
|
||||
* So far, only `@Input` and the lifecycle hooks have been implemented.
|
||||
*/
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class DirectiveWrapperCompiler {
|
||||
static dirWrapperClassName(id: CompileIdentifierMetadata) {
|
||||
return `Wrapper_${identifierName(id)}`;
|
||||
|
@ -6,9 +6,9 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injectable} from '@angular/core';
|
||||
import * as chars from '../chars';
|
||||
import {NumberWrapper, isPresent} from '../facade/lang';
|
||||
import {CompilerInjectable} from '../injectable';
|
||||
|
||||
export enum TokenType {
|
||||
Character,
|
||||
@ -22,7 +22,7 @@ export enum TokenType {
|
||||
|
||||
const KEYWORDS = ['var', 'let', 'null', 'undefined', 'true', 'false', 'if', 'else', 'this'];
|
||||
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class Lexer {
|
||||
tokenize(text: string): Token[] {
|
||||
const scanner = new _Scanner(text);
|
||||
|
@ -6,10 +6,9 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injectable} from '@angular/core';
|
||||
|
||||
import * as chars from '../chars';
|
||||
import {escapeRegExp, isBlank, isPresent} from '../facade/lang';
|
||||
import {CompilerInjectable} from '../injectable';
|
||||
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../ml_parser/interpolation_config';
|
||||
|
||||
import {AST, ASTWithSource, AstVisitor, Binary, BindingPipe, Chain, Conditional, EmptyExpr, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, ParseSpan, ParserError, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead, TemplateBinding} from './ast';
|
||||
@ -31,7 +30,7 @@ function _createInterpolateRegExp(config: InterpolationConfig): RegExp {
|
||||
return new RegExp(pattern, 'g');
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class Parser {
|
||||
private errors: ParserError[] = [];
|
||||
|
||||
|
@ -14,7 +14,9 @@ import {ViewEncapsulation} from '@angular/core';
|
||||
|
||||
import {analyzeAndValidateNgModules, extractProgramSymbols} from '../aot/compiler';
|
||||
import {StaticAndDynamicReflectionCapabilities} from '../aot/static_reflection_capabilities';
|
||||
import {StaticReflector, StaticReflectorHost} from '../aot/static_reflector';
|
||||
import {StaticReflector} from '../aot/static_reflector';
|
||||
import {StaticSymbolCache} from '../aot/static_symbol';
|
||||
import {StaticSymbolResolver, StaticSymbolResolverHost} from '../aot/static_symbol_resolver';
|
||||
import {AotSummaryResolver, AotSummaryResolverHost} from '../aot/summary_resolver';
|
||||
import {CompileDirectiveMetadata} from '../compile_metadata';
|
||||
import {CompilerConfig} from '../config';
|
||||
@ -33,16 +35,11 @@ import {createOfflineCompileUrlResolver} from '../url_resolver';
|
||||
import {I18NHtmlParser} from './i18n_html_parser';
|
||||
import {MessageBundle} from './message_bundle';
|
||||
|
||||
export interface ExtractorOptions {
|
||||
includeFilePattern?: RegExp;
|
||||
excludeFilePattern?: RegExp;
|
||||
}
|
||||
|
||||
/**
|
||||
* The host of the Extractor disconnects the implementation from TypeScript / other language
|
||||
* services and from underlying file systems.
|
||||
*/
|
||||
export interface ExtractorHost extends StaticReflectorHost, AotSummaryResolverHost {
|
||||
export interface ExtractorHost extends StaticSymbolResolverHost, AotSummaryResolverHost {
|
||||
/**
|
||||
* Loads a resource (e.g. html / css)
|
||||
*/
|
||||
@ -51,14 +48,13 @@ export interface ExtractorHost extends StaticReflectorHost, AotSummaryResolverHo
|
||||
|
||||
export class Extractor {
|
||||
constructor(
|
||||
private options: ExtractorOptions, public host: ExtractorHost,
|
||||
private staticReflector: StaticReflector, private messageBundle: MessageBundle,
|
||||
private metadataResolver: CompileMetadataResolver) {}
|
||||
public host: ExtractorHost, private staticSymbolResolver: StaticSymbolResolver,
|
||||
private messageBundle: MessageBundle, private metadataResolver: CompileMetadataResolver) {}
|
||||
|
||||
extract(rootFiles: string[]): Promise<MessageBundle> {
|
||||
const programSymbols = extractProgramSymbols(this.staticReflector, rootFiles, this.options);
|
||||
const programSymbols = extractProgramSymbols(this.staticSymbolResolver, rootFiles, this.host);
|
||||
const {ngModuleByPipeOrDirective, files, ngModules} =
|
||||
analyzeAndValidateNgModules(programSymbols, this.options, this.metadataResolver);
|
||||
analyzeAndValidateNgModules(programSymbols, this.host, this.metadataResolver);
|
||||
return Promise
|
||||
.all(ngModules.map(
|
||||
ngModule => this.metadataResolver.loadNgModuleDirectiveAndPipeMetadata(
|
||||
@ -91,12 +87,14 @@ export class Extractor {
|
||||
});
|
||||
}
|
||||
|
||||
static create(host: ExtractorHost, options: ExtractorOptions):
|
||||
{extractor: Extractor, staticReflector: StaticReflector} {
|
||||
static create(host: ExtractorHost): {extractor: Extractor, staticReflector: StaticReflector} {
|
||||
const htmlParser = new I18NHtmlParser(new HtmlParser());
|
||||
|
||||
const urlResolver = createOfflineCompileUrlResolver();
|
||||
const staticReflector = new StaticReflector(host);
|
||||
const symbolCache = new StaticSymbolCache();
|
||||
const summaryResolver = new AotSummaryResolver(host, symbolCache);
|
||||
const staticSymbolResolver = new StaticSymbolResolver(host, symbolCache, summaryResolver);
|
||||
const staticReflector = new StaticReflector(staticSymbolResolver);
|
||||
StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
||||
|
||||
const config = new CompilerConfig({
|
||||
@ -111,13 +109,13 @@ export class Extractor {
|
||||
const elementSchemaRegistry = new DomElementSchemaRegistry();
|
||||
const resolver = new CompileMetadataResolver(
|
||||
new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector),
|
||||
new PipeResolver(staticReflector), new AotSummaryResolver(host, staticReflector, options),
|
||||
elementSchemaRegistry, normalizer, staticReflector);
|
||||
new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer,
|
||||
staticReflector);
|
||||
|
||||
// TODO(vicb): implicit tags & attributes
|
||||
const messageBundle = new MessageBundle(htmlParser, [], {});
|
||||
|
||||
const extractor = new Extractor(options, host, staticReflector, messageBundle, resolver);
|
||||
const extractor = new Extractor(host, staticSymbolResolver, messageBundle, resolver);
|
||||
return {extractor, staticReflector};
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
export {Extractor, ExtractorHost, ExtractorOptions} from './extractor';
|
||||
export {Extractor, ExtractorHost} from './extractor';
|
||||
export {I18NHtmlParser} from './i18n_html_parser';
|
||||
export {MessageBundle} from './message_bundle';
|
||||
export {Serializer} from './serializers/serializer';
|
||||
|
16
modules/@angular/compiler/src/injectable.ts
Normal file
16
modules/@angular/compiler/src/injectable.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* A replacement for @Injectable to be used in the compiler, so that
|
||||
* we don't try to evaluate the metadata in the compiler during AoT.
|
||||
* This decorator is enough to make the compiler work with the ReflectiveInjector though.
|
||||
*/
|
||||
export function CompilerInjectable(): (data: any) => any {
|
||||
return (x) => x;
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Compiler, ComponentFactory, Injectable, Injector, ModuleWithComponentFactories, NgModuleFactory, SchemaMetadata, Type} from '@angular/core';
|
||||
import {Compiler, ComponentFactory, Injector, ModuleWithComponentFactories, NgModuleFactory, SchemaMetadata, Type} from '@angular/core';
|
||||
|
||||
import {AnimationCompiler} from '../animation/animation_compiler';
|
||||
import {AnimationParser} from '../animation/animation_parser';
|
||||
@ -15,6 +15,7 @@ import {CompilerConfig} from '../config';
|
||||
import {DirectiveNormalizer} from '../directive_normalizer';
|
||||
import {DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
|
||||
import {stringify} from '../facade/lang';
|
||||
import {CompilerInjectable} from '../injectable';
|
||||
import {CompileMetadataResolver} from '../metadata_resolver';
|
||||
import {NgModuleCompiler} from '../ng_module_compiler';
|
||||
import * as ir from '../output/output_ast';
|
||||
@ -36,7 +37,7 @@ import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewClassDepende
|
||||
* from a trusted source. Attacker-controlled data introduced by a template could expose your
|
||||
* application to XSS risks. For more detail, see the [Security Guide](http://g.co/ng/security).
|
||||
*/
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class JitCompiler implements Compiler {
|
||||
private _compiledTemplateCache = new Map<Type<any>, CompiledTemplate>();
|
||||
private _compiledHostTemplateCache = new Map<Type<any>, CompiledTemplate>();
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {COMPILER_OPTIONS, Compiler, CompilerFactory, CompilerOptions, Inject, Injectable, Optional, PLATFORM_INITIALIZER, PlatformRef, Provider, ReflectiveInjector, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, ViewEncapsulation, createPlatformFactory, isDevMode, platformCore} from '@angular/core';
|
||||
import {COMPILER_OPTIONS, Compiler, CompilerFactory, CompilerOptions, Inject, Optional, PLATFORM_INITIALIZER, PlatformRef, Provider, ReflectiveInjector, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, ViewEncapsulation, createPlatformFactory, isDevMode, platformCore} from '@angular/core';
|
||||
|
||||
import {AnimationParser} from '../animation/animation_parser';
|
||||
import {CompilerConfig} from '../config';
|
||||
@ -16,6 +16,7 @@ import {DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
|
||||
import {Lexer} from '../expression_parser/lexer';
|
||||
import {Parser} from '../expression_parser/parser';
|
||||
import * as i18n from '../i18n/index';
|
||||
import {CompilerInjectable} from '../injectable';
|
||||
import {CompileMetadataResolver} from '../metadata_resolver';
|
||||
import {HtmlParser} from '../ml_parser/html_parser';
|
||||
import {NgModuleCompiler} from '../ng_module_compiler';
|
||||
@ -83,7 +84,7 @@ export const COMPILER_PROVIDERS: Array<any|Type<any>|{[k: string]: any}|any[]> =
|
||||
];
|
||||
|
||||
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class JitCompilerFactory implements CompilerFactory {
|
||||
private _defaultOptions: CompilerOptions[];
|
||||
constructor(@Inject(COMPILER_OPTIONS) defaultOptions: CompilerOptions[]) {
|
||||
|
@ -16,6 +16,7 @@ import {DirectiveResolver} from './directive_resolver';
|
||||
import {ListWrapper, StringMapWrapper} from './facade/collection';
|
||||
import {isBlank, isPresent, stringify} from './facade/lang';
|
||||
import {Identifiers, createIdentifierToken, resolveIdentifier} from './identifiers';
|
||||
import {CompilerInjectable} from './injectable';
|
||||
import {hasLifecycleHook} from './lifecycle_reflector';
|
||||
import {NgModuleResolver} from './ng_module_resolver';
|
||||
import {PipeResolver} from './pipe_resolver';
|
||||
@ -35,7 +36,7 @@ export const ERROR_COLLECTOR_TOKEN = new OpaqueToken('ErrorCollector');
|
||||
// But we want to report errors even when the async work is
|
||||
// not required to check that the user would have been able
|
||||
// to wait correctly.
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class CompileMetadataResolver {
|
||||
private _directiveCache = new Map<Type<any>, cpl.CompileDirectiveMetadata>();
|
||||
private _summaryCache = new Map<Type<any>, cpl.CompileTypeSummary>();
|
||||
@ -45,7 +46,7 @@ export class CompileMetadataResolver {
|
||||
|
||||
constructor(
|
||||
private _ngModuleResolver: NgModuleResolver, private _directiveResolver: DirectiveResolver,
|
||||
private _pipeResolver: PipeResolver, private _summaryResolver: SummaryResolver,
|
||||
private _pipeResolver: PipeResolver, private _summaryResolver: SummaryResolver<any>,
|
||||
private _schemaRegistry: ElementSchemaRegistry,
|
||||
private _directiveNormalizer: DirectiveNormalizer,
|
||||
private _reflector: ReflectorReader = reflector,
|
||||
@ -128,12 +129,13 @@ export class CompileMetadataResolver {
|
||||
}
|
||||
|
||||
private _loadSummary(type: any, kind: cpl.CompileSummaryKind): cpl.CompileTypeSummary {
|
||||
let summary = this._summaryCache.get(type);
|
||||
if (!summary) {
|
||||
summary = this._summaryResolver.resolveSummary(type);
|
||||
this._summaryCache.set(type, summary);
|
||||
let typeSummary = this._summaryCache.get(type);
|
||||
if (!typeSummary) {
|
||||
const summary = this._summaryResolver.resolveSummary(type);
|
||||
typeSummary = summary ? summary.type : null;
|
||||
this._summaryCache.set(type, typeSummary);
|
||||
}
|
||||
return summary && summary.summaryKind === kind ? summary : null;
|
||||
return typeSummary && typeSummary.summaryKind === kind ? typeSummary : null;
|
||||
}
|
||||
|
||||
private _loadDirectiveMetadata(directiveType: any, isSync: boolean): Promise<any> {
|
||||
@ -237,7 +239,7 @@ export class CompileMetadataResolver {
|
||||
if (dirMeta.viewProviders) {
|
||||
viewProviders = this._getProvidersMetadata(
|
||||
dirMeta.viewProviders, entryComponentMetadata,
|
||||
`viewProviders for "${stringify(directiveType)}"`, [], directiveType);
|
||||
`viewProviders for "${stringifyType(directiveType)}"`, [], directiveType);
|
||||
}
|
||||
if (dirMeta.entryComponents) {
|
||||
entryComponentMetadata = flattenAndDedupeArray(dirMeta.entryComponents)
|
||||
@ -251,7 +253,7 @@ export class CompileMetadataResolver {
|
||||
// Directive
|
||||
if (!selector) {
|
||||
this._reportError(
|
||||
new Error(`Directive ${stringify(directiveType)} has no selector, please add it!`),
|
||||
new Error(`Directive ${stringifyType(directiveType)} has no selector, please add it!`),
|
||||
directiveType);
|
||||
selector = 'error';
|
||||
}
|
||||
@ -260,8 +262,8 @@ export class CompileMetadataResolver {
|
||||
let providers: cpl.CompileProviderMetadata[] = [];
|
||||
if (isPresent(dirMeta.providers)) {
|
||||
providers = this._getProvidersMetadata(
|
||||
dirMeta.providers, entryComponentMetadata, `providers for "${stringify(directiveType)}"`,
|
||||
[], directiveType);
|
||||
dirMeta.providers, entryComponentMetadata,
|
||||
`providers for "${stringifyType(directiveType)}"`, [], directiveType);
|
||||
}
|
||||
let queries: cpl.CompileQueryMetadata[] = [];
|
||||
let viewQueries: cpl.CompileQueryMetadata[] = [];
|
||||
@ -298,7 +300,7 @@ export class CompileMetadataResolver {
|
||||
if (!dirMeta) {
|
||||
this._reportError(
|
||||
new Error(
|
||||
`Illegal state: getDirectiveMetadata can only be called after loadNgModuleMetadata for a module that declares it. Directive ${stringify(directiveType)}.`),
|
||||
`Illegal state: getDirectiveMetadata can only be called after loadNgModuleMetadata for a module that declares it. Directive ${stringifyType(directiveType)}.`),
|
||||
directiveType);
|
||||
}
|
||||
return dirMeta;
|
||||
@ -310,7 +312,7 @@ export class CompileMetadataResolver {
|
||||
if (!dirSummary) {
|
||||
this._reportError(
|
||||
new Error(
|
||||
`Illegal state: Could not load the summary for directive ${stringify(dirType)}.`),
|
||||
`Illegal state: Could not load the summary for directive ${stringifyType(dirType)}.`),
|
||||
dirType);
|
||||
}
|
||||
return dirSummary;
|
||||
@ -383,7 +385,8 @@ export class CompileMetadataResolver {
|
||||
if (moduleWithProviders.providers) {
|
||||
providers.push(...this._getProvidersMetadata(
|
||||
moduleWithProviders.providers, entryComponents,
|
||||
`provider for the NgModule '${stringify(importedModuleType)}'`, [], importedType));
|
||||
`provider for the NgModule '${stringifyType(importedModuleType)}'`, [],
|
||||
importedType));
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,7 +395,7 @@ export class CompileMetadataResolver {
|
||||
if (!importedModuleSummary) {
|
||||
this._reportError(
|
||||
new Error(
|
||||
`Unexpected ${this._getTypeDescriptor(importedType)} '${stringify(importedType)}' imported by the module '${stringify(moduleType)}'`),
|
||||
`Unexpected ${this._getTypeDescriptor(importedType)} '${stringifyType(importedType)}' imported by the module '${stringifyType(moduleType)}'`),
|
||||
moduleType);
|
||||
return;
|
||||
}
|
||||
@ -400,7 +403,7 @@ export class CompileMetadataResolver {
|
||||
} else {
|
||||
this._reportError(
|
||||
new Error(
|
||||
`Unexpected value '${stringify(importedType)}' imported by the module '${stringify(moduleType)}'`),
|
||||
`Unexpected value '${stringifyType(importedType)}' imported by the module '${stringifyType(moduleType)}'`),
|
||||
moduleType);
|
||||
return;
|
||||
}
|
||||
@ -412,7 +415,7 @@ export class CompileMetadataResolver {
|
||||
if (!isValidType(exportedType)) {
|
||||
this._reportError(
|
||||
new Error(
|
||||
`Unexpected value '${stringify(exportedType)}' exported by the module '${stringify(moduleType)}'`),
|
||||
`Unexpected value '${stringifyType(exportedType)}' exported by the module '${stringifyType(moduleType)}'`),
|
||||
moduleType);
|
||||
return;
|
||||
}
|
||||
@ -433,7 +436,7 @@ export class CompileMetadataResolver {
|
||||
if (!isValidType(declaredType)) {
|
||||
this._reportError(
|
||||
new Error(
|
||||
`Unexpected value '${stringify(declaredType)}' declared by the module '${stringify(moduleType)}'`),
|
||||
`Unexpected value '${stringifyType(declaredType)}' declared by the module '${stringifyType(moduleType)}'`),
|
||||
moduleType);
|
||||
return;
|
||||
}
|
||||
@ -450,7 +453,7 @@ export class CompileMetadataResolver {
|
||||
} else {
|
||||
this._reportError(
|
||||
new Error(
|
||||
`Unexpected ${this._getTypeDescriptor(declaredType)} '${stringify(declaredType)}' declared by the module '${stringify(moduleType)}'`),
|
||||
`Unexpected ${this._getTypeDescriptor(declaredType)} '${stringifyType(declaredType)}' declared by the module '${stringifyType(moduleType)}'`),
|
||||
moduleType);
|
||||
return;
|
||||
}
|
||||
@ -469,7 +472,7 @@ export class CompileMetadataResolver {
|
||||
} else {
|
||||
this._reportError(
|
||||
new Error(
|
||||
`Can't export ${this._getTypeDescriptor(exportedId.reference)} ${stringify(exportedId.reference)} from ${stringify(moduleType)} as it was neither declared nor imported!`),
|
||||
`Can't export ${this._getTypeDescriptor(exportedId.reference)} ${stringifyType(exportedId.reference)} from ${stringifyType(moduleType)} as it was neither declared nor imported!`),
|
||||
moduleType);
|
||||
}
|
||||
});
|
||||
@ -478,13 +481,13 @@ export class CompileMetadataResolver {
|
||||
// so that they overwrite any other provider we already added.
|
||||
if (meta.providers) {
|
||||
providers.push(...this._getProvidersMetadata(
|
||||
meta.providers, entryComponents, `provider for the NgModule '${stringify(moduleType)}'`,
|
||||
[], moduleType));
|
||||
meta.providers, entryComponents,
|
||||
`provider for the NgModule '${stringifyType(moduleType)}'`, [], moduleType));
|
||||
}
|
||||
|
||||
if (meta.entryComponents) {
|
||||
entryComponents.push(
|
||||
...flattenAndDedupeArray(meta.entryComponents).map(type => this._getTypeMetadata(type)));
|
||||
entryComponents.push(...flattenAndDedupeArray(meta.entryComponents)
|
||||
.map(type => this._getIdentifierMetadata(type)));
|
||||
}
|
||||
|
||||
if (meta.bootstrap) {
|
||||
@ -492,11 +495,11 @@ export class CompileMetadataResolver {
|
||||
if (!isValidType(type)) {
|
||||
this._reportError(
|
||||
new Error(
|
||||
`Unexpected value '${stringify(type)}' used in the bootstrap property of module '${stringify(moduleType)}'`),
|
||||
`Unexpected value '${stringifyType(type)}' used in the bootstrap property of module '${stringifyType(moduleType)}'`),
|
||||
moduleType);
|
||||
return;
|
||||
}
|
||||
bootstrapComponents.push(this._getTypeMetadata(type));
|
||||
bootstrapComponents.push(this._getIdentifierMetadata(type));
|
||||
});
|
||||
}
|
||||
|
||||
@ -555,9 +558,9 @@ export class CompileMetadataResolver {
|
||||
if (oldModule && oldModule !== moduleType) {
|
||||
this._reportError(
|
||||
new Error(
|
||||
`Type ${stringify(type)} is part of the declarations of 2 modules: ${stringify(oldModule)} and ${stringify(moduleType)}! ` +
|
||||
`Please consider moving ${stringify(type)} to a higher module that imports ${stringify(oldModule)} and ${stringify(moduleType)}. ` +
|
||||
`You can also create a new NgModule that exports and includes ${stringify(type)} then import that NgModule in ${stringify(oldModule)} and ${stringify(moduleType)}.`),
|
||||
`Type ${stringifyType(type)} is part of the declarations of 2 modules: ${stringifyType(oldModule)} and ${stringifyType(moduleType)}! ` +
|
||||
`Please consider moving ${stringifyType(type)} to a higher module that imports ${stringifyType(oldModule)} and ${stringifyType(moduleType)}. ` +
|
||||
`You can also create a new NgModule that exports and includes ${stringifyType(type)} then import that NgModule in ${stringifyType(oldModule)} and ${stringifyType(moduleType)}.`),
|
||||
moduleType);
|
||||
}
|
||||
this._ngModuleOfTypes.set(type, moduleType);
|
||||
@ -606,6 +609,26 @@ export class CompileMetadataResolver {
|
||||
return {reference: type};
|
||||
}
|
||||
|
||||
isInjectable(type: any): boolean {
|
||||
const annotations = this._reflector.annotations(type);
|
||||
// Note: We need an exact check here as @Component / @Directive / ... inherit
|
||||
// from @CompilerInjectable!
|
||||
return annotations.some(ann => ann.constructor === Injectable);
|
||||
}
|
||||
|
||||
getInjectableSummary(type: any): cpl.CompileTypeSummary {
|
||||
return {summaryKind: cpl.CompileSummaryKind.Injectable, type: this._getTypeMetadata(type)};
|
||||
}
|
||||
|
||||
private _getInjectableMetadata(type: Type<any>, dependencies: any[] = null):
|
||||
cpl.CompileTypeMetadata {
|
||||
const typeSummary = this._loadSummary(type, cpl.CompileSummaryKind.Injectable);
|
||||
if (typeSummary) {
|
||||
return typeSummary.type;
|
||||
}
|
||||
return this._getTypeMetadata(type, dependencies);
|
||||
}
|
||||
|
||||
private _getTypeMetadata(type: Type<any>, dependencies: any[] = null): cpl.CompileTypeMetadata {
|
||||
const identifier = this._getIdentifierMetadata(type);
|
||||
return {
|
||||
@ -631,7 +654,7 @@ export class CompileMetadataResolver {
|
||||
if (!pipeMeta) {
|
||||
this._reportError(
|
||||
new Error(
|
||||
`Illegal state: getPipeMetadata can only be called after loadNgModuleMetadata for a module that declares it. Pipe ${stringify(pipeType)}.`),
|
||||
`Illegal state: getPipeMetadata can only be called after loadNgModuleMetadata for a module that declares it. Pipe ${stringifyType(pipeType)}.`),
|
||||
pipeType);
|
||||
}
|
||||
return pipeMeta;
|
||||
@ -642,7 +665,8 @@ export class CompileMetadataResolver {
|
||||
<cpl.CompilePipeSummary>this._loadSummary(pipeType, cpl.CompileSummaryKind.Pipe);
|
||||
if (!pipeSummary) {
|
||||
this._reportError(
|
||||
new Error(`Illegal state: Could not load the summary for pipe ${stringify(pipeType)}.`),
|
||||
new Error(
|
||||
`Illegal state: Could not load the summary for pipe ${stringifyType(pipeType)}.`),
|
||||
pipeType);
|
||||
}
|
||||
return pipeSummary;
|
||||
@ -722,9 +746,10 @@ export class CompileMetadataResolver {
|
||||
|
||||
if (hasUnknownDeps) {
|
||||
const depsTokens =
|
||||
dependenciesMetadata.map((dep) => dep ? stringify(dep.token) : '?').join(', ');
|
||||
dependenciesMetadata.map((dep) => dep ? stringifyType(dep.token) : '?').join(', ');
|
||||
this._reportError(
|
||||
new Error(`Can't resolve all parameters for ${stringify(typeOrFunc)}: (${depsTokens}).`),
|
||||
new Error(
|
||||
`Can't resolve all parameters for ${stringifyType(typeOrFunc)}: (${depsTokens}).`),
|
||||
typeOrFunc);
|
||||
}
|
||||
|
||||
@ -761,9 +786,9 @@ export class CompileMetadataResolver {
|
||||
(<string[]>providers.reduce(
|
||||
(soFar: string[], seenProvider: any, seenProviderIdx: number) => {
|
||||
if (seenProviderIdx < providerIdx) {
|
||||
soFar.push(`${stringify(seenProvider)}`);
|
||||
soFar.push(`${stringifyType(seenProvider)}`);
|
||||
} else if (seenProviderIdx == providerIdx) {
|
||||
soFar.push(`?${stringify(seenProvider)}?`);
|
||||
soFar.push(`?${stringifyType(seenProvider)}?`);
|
||||
} else if (seenProviderIdx == providerIdx + 1) {
|
||||
soFar.push('...');
|
||||
}
|
||||
@ -805,7 +830,8 @@ export class CompileMetadataResolver {
|
||||
|
||||
extractIdentifiers(provider.useValue, collectedIdentifiers);
|
||||
collectedIdentifiers.forEach((identifier) => {
|
||||
if (this._directiveResolver.isDirective(identifier.reference)) {
|
||||
if (this._directiveResolver.isDirective(identifier.reference) ||
|
||||
this._loadSummary(identifier.reference, cpl.CompileSummaryKind.Directive)) {
|
||||
components.push(identifier);
|
||||
}
|
||||
});
|
||||
@ -819,7 +845,7 @@ export class CompileMetadataResolver {
|
||||
let token: cpl.CompileTokenMetadata = this._getTokenMetadata(provider.token);
|
||||
|
||||
if (provider.useClass) {
|
||||
compileTypeMetadata = this._getTypeMetadata(provider.useClass, provider.dependencies);
|
||||
compileTypeMetadata = this._getInjectableMetadata(provider.useClass, provider.dependencies);
|
||||
compileDeps = compileTypeMetadata.diDeps;
|
||||
if (provider.token === provider.useClass) {
|
||||
// use the compileTypeMetadata as it contains information about lifecycleHooks...
|
||||
@ -868,7 +894,7 @@ export class CompileMetadataResolver {
|
||||
if (!q.selector) {
|
||||
this._reportError(
|
||||
new Error(
|
||||
`Can't construct a query for the property "${propertyName}" of "${stringify(typeOrFunc)}" since the query selector wasn't defined.`),
|
||||
`Can't construct a query for the property "${propertyName}" of "${stringifyType(typeOrFunc)}" since the query selector wasn't defined.`),
|
||||
typeOrFunc);
|
||||
}
|
||||
selectors = [this._getTokenMetadata(q.selector)];
|
||||
@ -936,7 +962,7 @@ export function componentModuleUrl(
|
||||
return scheme ? moduleId : `package:${moduleId}${MODULE_SUFFIX}`;
|
||||
} else if (moduleId !== null && moduleId !== void 0) {
|
||||
throw new Error(
|
||||
`moduleId should be a string in "${stringify(type)}". See https://goo.gl/wIDDiL for more information.\n` +
|
||||
`moduleId should be a string in "${stringifyType(type)}". See https://goo.gl/wIDDiL for more information.\n` +
|
||||
`If you're using Webpack you should inline the template and the styles, see https://goo.gl/X2J8zc.`);
|
||||
}
|
||||
|
||||
@ -952,3 +978,11 @@ class _CompileValueConverter extends ValueTransformer {
|
||||
targetIdentifiers.push({reference: value});
|
||||
}
|
||||
}
|
||||
|
||||
function stringifyType(type: any): string {
|
||||
if (type instanceof StaticSymbol) {
|
||||
return `${type.name} in ${type.filePath}`;
|
||||
} else {
|
||||
return stringify(type);
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injectable} from '@angular/core';
|
||||
import {CompilerInjectable} from '../injectable';
|
||||
|
||||
import {getHtmlTagDefinition} from './html_tags';
|
||||
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from './interpolation_config';
|
||||
@ -14,7 +14,7 @@ import {ParseTreeResult, Parser} from './parser';
|
||||
|
||||
export {ParseTreeResult, TreeError} from './parser';
|
||||
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class HtmlParser extends Parser {
|
||||
constructor() { super(getHtmlTagDefinition); }
|
||||
|
||||
|
@ -6,12 +6,11 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injectable} from '@angular/core';
|
||||
|
||||
import {CompileDiDependencyMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileProviderMetadata, CompileTokenMetadata, identifierModuleUrl, identifierName, tokenName, tokenReference} from './compile_metadata';
|
||||
import {createDiTokenExpression} from './compiler_util/identifier_util';
|
||||
import {isPresent} from './facade/lang';
|
||||
import {Identifiers, createIdentifier, createIdentifierToken, resolveIdentifier} from './identifiers';
|
||||
import {CompilerInjectable} from './injectable';
|
||||
import {ClassBuilder, createClassStmt} from './output/class_builder';
|
||||
import * as o from './output/output_ast';
|
||||
import {convertValueToOutputAst} from './output/value_util';
|
||||
@ -31,7 +30,7 @@ export class NgModuleCompileResult {
|
||||
public dependencies: ComponentFactoryDependency[]) {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class NgModuleCompiler {
|
||||
compile(ngModuleMeta: CompileNgModuleMetadata, extraProviders: CompileProviderMetadata[]):
|
||||
NgModuleCompileResult {
|
||||
|
@ -6,10 +6,11 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injectable, NgModule, Type} from '@angular/core';
|
||||
import {NgModule, Type} from '@angular/core';
|
||||
|
||||
import {ListWrapper} from './facade/collection';
|
||||
import {isPresent, stringify} from './facade/lang';
|
||||
import {CompilerInjectable} from './injectable';
|
||||
import {ReflectorReader, reflector} from './private_import_core';
|
||||
|
||||
function _isNgModuleMetadata(obj: any): obj is NgModule {
|
||||
@ -19,7 +20,7 @@ function _isNgModuleMetadata(obj: any): obj is NgModule {
|
||||
/**
|
||||
* Resolves types to {@link NgModule}.
|
||||
*/
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class NgModuleResolver {
|
||||
constructor(private _reflector: ReflectorReader = reflector) {}
|
||||
|
||||
|
@ -14,5 +14,6 @@ export abstract class ImportResolver {
|
||||
* Converts a file path to a module name that can be used as an `import.
|
||||
* I.e. `path/to/importedFile.ts` should be imported by `path/to/containingFile.ts`.
|
||||
*/
|
||||
abstract fileNameToModuleName(importedFilePath: string, containingFilePath: string): string;
|
||||
abstract fileNameToModuleName(importedFilePath: string, containingFilePath: string): string
|
||||
/*|null*/;
|
||||
}
|
||||
|
@ -335,7 +335,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||
}
|
||||
ctx.print(`${prefix}.`);
|
||||
}
|
||||
if (value.reference && value.reference.members) {
|
||||
if (value.reference && value.reference.members && value.reference.members.length) {
|
||||
ctx.print(value.reference.name);
|
||||
ctx.print('.');
|
||||
ctx.print(value.reference.members.join('.'));
|
||||
|
@ -6,10 +6,11 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injectable, Pipe, Type, resolveForwardRef} from '@angular/core';
|
||||
import {Pipe, Type, resolveForwardRef} from '@angular/core';
|
||||
|
||||
import {ListWrapper} from './facade/collection';
|
||||
import {isPresent, stringify} from './facade/lang';
|
||||
import {CompilerInjectable} from './injectable';
|
||||
import {ReflectorReader, reflector} from './private_import_core';
|
||||
|
||||
function _isPipeMetadata(type: any): boolean {
|
||||
@ -23,7 +24,7 @@ function _isPipeMetadata(type: any): boolean {
|
||||
*
|
||||
* See {@link Compiler}
|
||||
*/
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class PipeResolver {
|
||||
constructor(private _reflector: ReflectorReader = reflector) {}
|
||||
|
||||
|
@ -6,7 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AUTO_STYLE, CUSTOM_ELEMENTS_SCHEMA, Injectable, NO_ERRORS_SCHEMA, SchemaMetadata, SecurityContext} from '@angular/core';
|
||||
import {AUTO_STYLE, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SchemaMetadata, SecurityContext} from '@angular/core';
|
||||
import {CompilerInjectable} from '../injectable';
|
||||
|
||||
import {dashCaseToCamelCase} from '../util';
|
||||
|
||||
@ -238,7 +239,7 @@ const _ATTR_TO_PROP: {[name: string]: string} = {
|
||||
'tabindex': 'tabIndex',
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class DomElementSchemaRegistry extends ElementSchemaRegistry {
|
||||
private _schema: {[element: string]: {[property: string]: string}} = {};
|
||||
|
||||
|
@ -6,9 +6,10 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injectable, ViewEncapsulation} from '@angular/core';
|
||||
import {ViewEncapsulation} from '@angular/core';
|
||||
|
||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileStylesheetMetadata, identifierModuleUrl, identifierName} from './compile_metadata';
|
||||
import {CompilerInjectable} from './injectable';
|
||||
import * as o from './output/output_ast';
|
||||
import {ShadowCss} from './shadow_css';
|
||||
import {UrlResolver} from './url_resolver';
|
||||
@ -36,7 +37,7 @@ export class CompiledStylesheet {
|
||||
public meta: CompileStylesheetMetadata) {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class StyleCompiler {
|
||||
private _shadowCss: ShadowCss = new ShadowCss();
|
||||
|
||||
|
@ -5,10 +5,17 @@
|
||||
* 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 {Injectable} from '@angular/core';
|
||||
import {CompileTypeSummary} from './compile_metadata';
|
||||
import {CompilerInjectable} from './injectable';
|
||||
|
||||
@Injectable()
|
||||
export class SummaryResolver {
|
||||
resolveSummary(reference: any): CompileTypeSummary { return null; }
|
||||
export interface Summary<T> {
|
||||
symbol: T;
|
||||
metadata: any;
|
||||
type?: CompileTypeSummary;
|
||||
}
|
||||
|
||||
@CompilerInjectable()
|
||||
export class SummaryResolver<T> {
|
||||
resolveSummary(reference: T): Summary<T> { return null; };
|
||||
getSymbolsOf(filePath: string): T[] { return []; }
|
||||
}
|
||||
|
@ -6,13 +6,13 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Inject, Injectable, OpaqueToken, Optional, SchemaMetadata} from '@angular/core';
|
||||
|
||||
import {Inject, OpaqueToken, Optional, SchemaMetadata} from '@angular/core';
|
||||
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeSummary, CompileTemplateSummary, CompileTokenMetadata, CompileTypeMetadata, identifierName} from '../compile_metadata';
|
||||
import {Parser} from '../expression_parser/parser';
|
||||
import {isPresent} from '../facade/lang';
|
||||
import {I18NHtmlParser} from '../i18n/i18n_html_parser';
|
||||
import {Identifiers, createIdentifierToken, identifierToken} from '../identifiers';
|
||||
import {CompilerInjectable} from '../injectable';
|
||||
import * as html from '../ml_parser/ast';
|
||||
import {ParseTreeResult} from '../ml_parser/html_parser';
|
||||
import {expandNodes} from '../ml_parser/icu_ast_expander';
|
||||
@ -79,7 +79,7 @@ export class TemplateParseResult {
|
||||
constructor(public templateAst?: TemplateAst[], public errors?: ParseError[]) {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class TemplateParser {
|
||||
constructor(
|
||||
private _exprParser: Parser, private _schemaRegistry: ElementSchemaRegistry,
|
||||
|
@ -6,9 +6,11 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Inject, Injectable, PACKAGE_ROOT_URL} from '@angular/core';
|
||||
import {Inject, PACKAGE_ROOT_URL} from '@angular/core';
|
||||
|
||||
import {isBlank, isPresent} from './facade/lang';
|
||||
import {CompilerInjectable} from './injectable';
|
||||
|
||||
|
||||
/**
|
||||
* Create a {@link UrlResolver} with no package prefix.
|
||||
@ -45,7 +47,7 @@ export var DEFAULT_PACKAGE_URL_PROVIDER = {
|
||||
* Attacker-controlled data introduced by a template could expose your
|
||||
* application to XSS risks. For more detail, see the [Security Guide](http://g.co/ng/security).
|
||||
*/
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class UrlResolver {
|
||||
constructor(@Inject(PACKAGE_ROOT_URL) private _packagePrefix: string = null) {}
|
||||
|
||||
|
@ -6,11 +6,10 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injectable} from '@angular/core';
|
||||
|
||||
import {AnimationEntryCompileResult} from '../animation/animation_compiler';
|
||||
import {CompileDirectiveMetadata, CompilePipeSummary} from '../compile_metadata';
|
||||
import {CompilerConfig} from '../config';
|
||||
import {CompilerInjectable} from '../injectable';
|
||||
import * as o from '../output/output_ast';
|
||||
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
|
||||
import {TemplateAst} from '../template_parser/template_ast';
|
||||
@ -30,7 +29,7 @@ export class ViewCompileResult {
|
||||
Array<ViewClassDependency|ComponentFactoryDependency|DirectiveWrapperDependency>) {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@CompilerInjectable()
|
||||
export class ViewCompiler {
|
||||
constructor(private _genConfig: CompilerConfig, private _schemaRegistry: ElementSchemaRegistry) {}
|
||||
|
||||
|
Reference in New Issue
Block a user