feat(compiler): generate proper reexports in `.ngfactory.ts` files to not need transitive deps for compiling `.ngfactory.ts` files. (#13524)
Note: This checks the constructors of `@Injectable` classes more strictly. E.g this will fail now as the constructor argument has no `@Inject` nor is the type of the argument a DI token. ``` @Injectable() class MyService { constructor(dep: string) {} } ``` Last part of #12787 Closes #12787
This commit is contained in:
parent
697690349f
commit
9c697030e6
|
@ -10,7 +10,7 @@ import {SchemaMetadata} from '@angular/core';
|
||||||
|
|
||||||
import {AnimationCompiler} from '../animation/animation_compiler';
|
import {AnimationCompiler} from '../animation/animation_compiler';
|
||||||
import {AnimationParser} from '../animation/animation_parser';
|
import {AnimationParser} from '../animation/animation_parser';
|
||||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, CompileProviderMetadata, CompileTypeSummary, createHostComponentMeta, identifierModuleUrl, identifierName} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, CompileProviderMetadata, CompileTypeSummary, componentFactoryName, createHostComponentMeta, identifierModuleUrl, identifierName} from '../compile_metadata';
|
||||||
import {DirectiveNormalizer} from '../directive_normalizer';
|
import {DirectiveNormalizer} from '../directive_normalizer';
|
||||||
import {DirectiveWrapperCompileResult, DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
|
import {DirectiveWrapperCompileResult, DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
|
||||||
import {ListWrapper} from '../facade/collection';
|
import {ListWrapper} from '../facade/collection';
|
||||||
|
@ -22,13 +22,14 @@ import * as o from '../output/output_ast';
|
||||||
import {CompiledStylesheet, StyleCompiler} from '../style_compiler';
|
import {CompiledStylesheet, StyleCompiler} from '../style_compiler';
|
||||||
import {SummaryResolver} from '../summary_resolver';
|
import {SummaryResolver} from '../summary_resolver';
|
||||||
import {TemplateParser} from '../template_parser/template_parser';
|
import {TemplateParser} from '../template_parser/template_parser';
|
||||||
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewClassDependency, ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler';
|
import {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency, ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler';
|
||||||
|
|
||||||
import {AotCompilerHost} from './compiler_host';
|
import {AotCompilerHost} from './compiler_host';
|
||||||
import {GeneratedFile} from './generated_file';
|
import {GeneratedFile} from './generated_file';
|
||||||
import {StaticSymbol} from './static_symbol';
|
import {StaticSymbol} from './static_symbol';
|
||||||
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
|
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
|
||||||
import {serializeSummaries, summaryFileName} from './summary_serializer';
|
import {serializeSummaries} from './summary_serializer';
|
||||||
|
import {ngfactoryFilePath, splitTypescriptSuffix, summaryFileName} from './util';
|
||||||
|
|
||||||
export class AotCompiler {
|
export class AotCompiler {
|
||||||
private _animationCompiler = new AnimationCompiler();
|
private _animationCompiler = new AnimationCompiler();
|
||||||
|
@ -65,12 +66,13 @@ export class AotCompiler {
|
||||||
srcFileUrl: string, ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>,
|
srcFileUrl: string, ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>,
|
||||||
directives: StaticSymbol[], pipes: StaticSymbol[], ngModules: StaticSymbol[],
|
directives: StaticSymbol[], pipes: StaticSymbol[], ngModules: StaticSymbol[],
|
||||||
injectables: StaticSymbol[]): GeneratedFile[] {
|
injectables: StaticSymbol[]): GeneratedFile[] {
|
||||||
const fileSuffix = _splitTypescriptSuffix(srcFileUrl)[1];
|
const fileSuffix = splitTypescriptSuffix(srcFileUrl)[1];
|
||||||
const statements: o.Statement[] = [];
|
const statements: o.Statement[] = [];
|
||||||
const exportedVars: string[] = [];
|
const exportedVars: string[] = [];
|
||||||
const generatedFiles: GeneratedFile[] = [];
|
const generatedFiles: GeneratedFile[] = [];
|
||||||
|
|
||||||
generatedFiles.push(this._createSummary(srcFileUrl, directives, pipes, ngModules, injectables));
|
generatedFiles.push(this._createSummary(
|
||||||
|
srcFileUrl, directives, pipes, ngModules, injectables, statements, exportedVars));
|
||||||
|
|
||||||
// compile all ng modules
|
// compile all ng modules
|
||||||
exportedVars.push(
|
exportedVars.push(
|
||||||
|
@ -109,7 +111,7 @@ export class AotCompiler {
|
||||||
});
|
});
|
||||||
if (statements.length > 0) {
|
if (statements.length > 0) {
|
||||||
const srcModule = this._codegenSourceModule(
|
const srcModule = this._codegenSourceModule(
|
||||||
srcFileUrl, _ngfactoryModuleUrl(srcFileUrl), statements, exportedVars);
|
srcFileUrl, ngfactoryFilePath(srcFileUrl), statements, exportedVars);
|
||||||
generatedFiles.unshift(srcModule);
|
generatedFiles.unshift(srcModule);
|
||||||
}
|
}
|
||||||
return generatedFiles;
|
return generatedFiles;
|
||||||
|
@ -117,7 +119,8 @@ export class AotCompiler {
|
||||||
|
|
||||||
private _createSummary(
|
private _createSummary(
|
||||||
srcFileUrl: string, directives: StaticSymbol[], pipes: StaticSymbol[],
|
srcFileUrl: string, directives: StaticSymbol[], pipes: StaticSymbol[],
|
||||||
ngModules: StaticSymbol[], injectables: StaticSymbol[]): GeneratedFile {
|
ngModules: StaticSymbol[], injectables: StaticSymbol[], targetStatements: o.Statement[],
|
||||||
|
targetExportedVars: string[]): GeneratedFile {
|
||||||
const symbolSummaries = this._symbolResolver.getSymbolsOf(srcFileUrl)
|
const symbolSummaries = this._symbolResolver.getSymbolsOf(srcFileUrl)
|
||||||
.map(symbol => this._symbolResolver.resolveSymbol(symbol));
|
.map(symbol => this._symbolResolver.resolveSymbol(symbol));
|
||||||
const typeSummaries = [
|
const typeSummaries = [
|
||||||
|
@ -126,8 +129,13 @@ export class AotCompiler {
|
||||||
...pipes.map(ref => this._metadataResolver.getPipeSummary(ref)),
|
...pipes.map(ref => this._metadataResolver.getPipeSummary(ref)),
|
||||||
...injectables.map(ref => this._metadataResolver.getInjectableSummary(ref))
|
...injectables.map(ref => this._metadataResolver.getInjectableSummary(ref))
|
||||||
];
|
];
|
||||||
const json = serializeSummaries(
|
const {json, exportAs} = serializeSummaries(
|
||||||
this._host, this._summaryResolver, this._symbolResolver, symbolSummaries, typeSummaries);
|
this._summaryResolver, this._symbolResolver, symbolSummaries, typeSummaries);
|
||||||
|
exportAs.forEach((entry) => {
|
||||||
|
targetStatements.push(
|
||||||
|
o.variable(entry.exportAs).set(o.importExpr({reference: entry.symbol})).toDeclStmt());
|
||||||
|
targetExportedVars.push(entry.exportAs);
|
||||||
|
});
|
||||||
return new GeneratedFile(srcFileUrl, summaryFileName(srcFileUrl), json);
|
return new GeneratedFile(srcFileUrl, summaryFileName(srcFileUrl), json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,12 +158,6 @@ export class AotCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
const appCompileResult = this._ngModuleCompiler.compile(ngModule, providers);
|
const appCompileResult = this._ngModuleCompiler.compile(ngModule, providers);
|
||||||
|
|
||||||
appCompileResult.dependencies.forEach((dep) => {
|
|
||||||
dep.placeholder.reference = this._symbolResolver.getStaticSymbol(
|
|
||||||
_ngfactoryModuleUrl(identifierModuleUrl(dep.comp)), _componentFactoryName(dep.comp));
|
|
||||||
});
|
|
||||||
|
|
||||||
targetStatements.push(...appCompileResult.statements);
|
targetStatements.push(...appCompileResult.statements);
|
||||||
return appCompileResult.ngModuleFactoryVar;
|
return appCompileResult.ngModuleFactoryVar;
|
||||||
}
|
}
|
||||||
|
@ -172,13 +174,12 @@ export class AotCompiler {
|
||||||
private _compileComponentFactory(
|
private _compileComponentFactory(
|
||||||
compMeta: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata, fileSuffix: string,
|
compMeta: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata, fileSuffix: string,
|
||||||
targetStatements: o.Statement[]): string {
|
targetStatements: o.Statement[]): string {
|
||||||
|
const hostType = this._metadataResolver.getHostComponentType(compMeta.type.reference);
|
||||||
const hostMeta = createHostComponentMeta(
|
const hostMeta = createHostComponentMeta(
|
||||||
this._symbolResolver.getStaticSymbol(
|
hostType, compMeta, this._metadataResolver.getHostComponentViewClass(hostType));
|
||||||
identifierModuleUrl(compMeta.type), `${identifierName(compMeta.type)}_Host`),
|
|
||||||
compMeta);
|
|
||||||
const hostViewFactoryVar = this._compileComponent(
|
const hostViewFactoryVar = this._compileComponent(
|
||||||
hostMeta, ngModule, [compMeta.type], null, fileSuffix, targetStatements);
|
hostMeta, ngModule, [compMeta.type], null, fileSuffix, targetStatements);
|
||||||
const compFactoryVar = _componentFactoryName(compMeta.type);
|
const compFactoryVar = componentFactoryName(compMeta.type.reference);
|
||||||
targetStatements.push(
|
targetStatements.push(
|
||||||
o.variable(compFactoryVar)
|
o.variable(compFactoryVar)
|
||||||
.set(o.importExpr(
|
.set(o.importExpr(
|
||||||
|
@ -219,7 +220,7 @@ export class AotCompiler {
|
||||||
..._resolveStyleStatements(this._symbolResolver, componentStyles, fileSuffix));
|
..._resolveStyleStatements(this._symbolResolver, componentStyles, fileSuffix));
|
||||||
}
|
}
|
||||||
compiledAnimations.forEach(entry => targetStatements.push(...entry.statements));
|
compiledAnimations.forEach(entry => targetStatements.push(...entry.statements));
|
||||||
targetStatements.push(..._resolveViewStatements(this._symbolResolver, viewResult));
|
targetStatements.push(...viewResult.statements);
|
||||||
return viewResult.viewClassVar;
|
return viewResult.viewClassVar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,27 +242,6 @@ export class AotCompiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _resolveViewStatements(
|
|
||||||
reflector: StaticSymbolResolver, compileResult: ViewCompileResult): o.Statement[] {
|
|
||||||
compileResult.dependencies.forEach((dep) => {
|
|
||||||
if (dep instanceof ViewClassDependency) {
|
|
||||||
const vfd = <ViewClassDependency>dep;
|
|
||||||
vfd.placeholder.reference =
|
|
||||||
reflector.getStaticSymbol(_ngfactoryModuleUrl(identifierModuleUrl(vfd.comp)), dep.name);
|
|
||||||
} else if (dep instanceof ComponentFactoryDependency) {
|
|
||||||
const cfd = <ComponentFactoryDependency>dep;
|
|
||||||
cfd.placeholder.reference = reflector.getStaticSymbol(
|
|
||||||
_ngfactoryModuleUrl(identifierModuleUrl(cfd.comp)), _componentFactoryName(cfd.comp));
|
|
||||||
} else if (dep instanceof DirectiveWrapperDependency) {
|
|
||||||
const dwd = <DirectiveWrapperDependency>dep;
|
|
||||||
dwd.placeholder.reference =
|
|
||||||
reflector.getStaticSymbol(_ngfactoryModuleUrl(identifierModuleUrl(dwd.dir)), dwd.name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return compileResult.statements;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function _resolveStyleStatements(
|
function _resolveStyleStatements(
|
||||||
reflector: StaticSymbolResolver, compileResult: CompiledStylesheet,
|
reflector: StaticSymbolResolver, compileResult: CompiledStylesheet,
|
||||||
fileSuffix: string): o.Statement[] {
|
fileSuffix: string): o.Statement[] {
|
||||||
|
@ -272,15 +252,6 @@ function _resolveStyleStatements(
|
||||||
return compileResult.statements;
|
return compileResult.statements;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _ngfactoryModuleUrl(dirUrl: string): string {
|
|
||||||
const urlWithSuffix = _splitTypescriptSuffix(dirUrl);
|
|
||||||
return `${urlWithSuffix[0]}.ngfactory${urlWithSuffix[1]}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _componentFactoryName(comp: CompileIdentifierMetadata): string {
|
|
||||||
return `${identifierName(comp)}NgFactory`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _stylesModuleUrl(stylesheetUrl: string, shim: boolean, suffix: string): string {
|
function _stylesModuleUrl(stylesheetUrl: string, shim: boolean, suffix: string): string {
|
||||||
return `${stylesheetUrl}${shim ? '.shim' : ''}.ngstyle${suffix}`;
|
return `${stylesheetUrl}${shim ? '.shim' : ''}.ngstyle${suffix}`;
|
||||||
}
|
}
|
||||||
|
@ -292,20 +263,6 @@ function _assertComponent(meta: CompileDirectiveMetadata) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _splitTypescriptSuffix(path: string): string[] {
|
|
||||||
if (path.endsWith('.d.ts')) {
|
|
||||||
return [path.slice(0, -5), '.ts'];
|
|
||||||
}
|
|
||||||
|
|
||||||
const lastDot = path.lastIndexOf('.');
|
|
||||||
|
|
||||||
if (lastDot !== -1) {
|
|
||||||
return [path.substring(0, lastDot), path.substring(lastDot)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [path, ''];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NgAnalyzedModules {
|
export interface NgAnalyzedModules {
|
||||||
ngModules: CompileNgModuleMetadata[];
|
ngModules: CompileNgModuleMetadata[];
|
||||||
ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>;
|
ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>;
|
||||||
|
|
|
@ -34,11 +34,12 @@ import {AotCompilerHost} from './compiler_host';
|
||||||
import {AotCompilerOptions} from './compiler_options';
|
import {AotCompilerOptions} from './compiler_options';
|
||||||
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
|
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
|
||||||
import {StaticReflector} from './static_reflector';
|
import {StaticReflector} from './static_reflector';
|
||||||
import {StaticSymbolCache} from './static_symbol';
|
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
||||||
import {StaticSymbolResolver} from './static_symbol_resolver';
|
import {StaticSymbolResolver} from './static_symbol_resolver';
|
||||||
import {AotSummaryResolver} from './summary_resolver';
|
import {AotSummaryResolver} from './summary_resolver';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new AotCompiler based on options and a host.
|
* Creates a new AotCompiler based on options and a host.
|
||||||
*/
|
*/
|
||||||
|
@ -69,13 +70,19 @@ export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCom
|
||||||
const resolver = new CompileMetadataResolver(
|
const resolver = new CompileMetadataResolver(
|
||||||
new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector),
|
new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector),
|
||||||
new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer,
|
new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer,
|
||||||
staticReflector);
|
symbolCache, staticReflector);
|
||||||
// TODO(vicb): do not pass options.i18nFormat here
|
// TODO(vicb): do not pass options.i18nFormat here
|
||||||
|
const importResolver = {
|
||||||
|
getImportAs: (symbol: StaticSymbol) => symbolResolver.getImportAs(symbol),
|
||||||
|
fileNameToModuleName: (fileName: string, containingFilePath: string) =>
|
||||||
|
compilerHost.fileNameToModuleName(fileName, containingFilePath)
|
||||||
|
};
|
||||||
const compiler = new AotCompiler(
|
const compiler = new AotCompiler(
|
||||||
compilerHost, resolver, tmplParser, new StyleCompiler(urlResolver),
|
compilerHost, resolver, tmplParser, new StyleCompiler(urlResolver),
|
||||||
new ViewCompiler(config, elementSchemaRegistry),
|
new ViewCompiler(config, elementSchemaRegistry),
|
||||||
new DirectiveWrapperCompiler(config, expressionParser, elementSchemaRegistry, console),
|
new DirectiveWrapperCompiler(config, expressionParser, elementSchemaRegistry, console),
|
||||||
new NgModuleCompiler(), new TypeScriptEmitter(compilerHost), summaryResolver, options.locale,
|
new NgModuleCompiler(), new TypeScriptEmitter(importResolver), summaryResolver,
|
||||||
options.i18nFormat, new AnimationParser(elementSchemaRegistry), symbolResolver);
|
options.locale, options.i18nFormat, new AnimationParser(elementSchemaRegistry),
|
||||||
|
symbolResolver);
|
||||||
return {compiler, reflector: staticReflector};
|
return {compiler, reflector: staticReflector};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,24 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ImportResolver} from '../output/path_util';
|
|
||||||
|
|
||||||
import {StaticSymbol} from './static_symbol';
|
import {StaticSymbol} from './static_symbol';
|
||||||
import {StaticSymbolResolverHost} from './static_symbol_resolver';
|
import {StaticSymbolResolverHost} from './static_symbol_resolver';
|
||||||
import {AotSummaryResolverHost} from './summary_resolver';
|
import {AotSummaryResolverHost} from './summary_resolver';
|
||||||
import {AotSummarySerializerHost} from './summary_serializer';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The host of the AotCompiler disconnects the implementation from TypeScript / other language
|
* The host of the AotCompiler disconnects the implementation from TypeScript / other language
|
||||||
* services and from underlying file systems.
|
* services and from underlying file systems.
|
||||||
*/
|
*/
|
||||||
export interface AotCompilerHost extends StaticSymbolResolverHost, ImportResolver,
|
export interface AotCompilerHost extends StaticSymbolResolverHost, AotSummaryResolverHost {
|
||||||
AotSummaryResolverHost, AotSummarySerializerHost {
|
/**
|
||||||
|
* 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`.
|
||||||
|
*
|
||||||
|
* See ImportResolver.
|
||||||
|
*/
|
||||||
|
fileNameToModuleName(importedFilePath: string, containingFilePath: string): string
|
||||||
|
/*|null*/;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a resource (e.g. html / css)
|
* Loads a resource (e.g. html / css)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -83,8 +83,11 @@ export class StaticReflector implements ReflectorReader {
|
||||||
annotations = [];
|
annotations = [];
|
||||||
const classMetadata = this.getTypeMetadata(type);
|
const classMetadata = this.getTypeMetadata(type);
|
||||||
if (classMetadata['extends']) {
|
if (classMetadata['extends']) {
|
||||||
const parentAnnotations = this.annotations(this.simplify(type, classMetadata['extends']));
|
const parentType = this.simplify(type, classMetadata['extends']);
|
||||||
annotations.push(...parentAnnotations);
|
if (parentType instanceof StaticSymbol) {
|
||||||
|
const parentAnnotations = this.annotations(parentType);
|
||||||
|
annotations.push(...parentAnnotations);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (classMetadata['decorators']) {
|
if (classMetadata['decorators']) {
|
||||||
const ownAnnotations: any[] = this.simplify(type, classMetadata['decorators']);
|
const ownAnnotations: any[] = this.simplify(type, classMetadata['decorators']);
|
||||||
|
@ -101,10 +104,13 @@ export class StaticReflector implements ReflectorReader {
|
||||||
const classMetadata = this.getTypeMetadata(type);
|
const classMetadata = this.getTypeMetadata(type);
|
||||||
propMetadata = {};
|
propMetadata = {};
|
||||||
if (classMetadata['extends']) {
|
if (classMetadata['extends']) {
|
||||||
const parentPropMetadata = this.propMetadata(this.simplify(type, classMetadata['extends']));
|
const parentType = this.simplify(type, classMetadata['extends']);
|
||||||
Object.keys(parentPropMetadata).forEach((parentProp) => {
|
if (parentType instanceof StaticSymbol) {
|
||||||
propMetadata[parentProp] = parentPropMetadata[parentProp];
|
const parentPropMetadata = this.propMetadata(parentType);
|
||||||
});
|
Object.keys(parentPropMetadata).forEach((parentProp) => {
|
||||||
|
propMetadata[parentProp] = parentPropMetadata[parentProp];
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const members = classMetadata['members'] || {};
|
const members = classMetadata['members'] || {};
|
||||||
|
@ -156,7 +162,10 @@ export class StaticReflector implements ReflectorReader {
|
||||||
parameters.push(nestedResult);
|
parameters.push(nestedResult);
|
||||||
});
|
});
|
||||||
} else if (classMetadata['extends']) {
|
} else if (classMetadata['extends']) {
|
||||||
parameters = this.parameters(this.simplify(type, classMetadata['extends']));
|
const parentType = this.simplify(type, classMetadata['extends']);
|
||||||
|
if (parentType instanceof StaticSymbol) {
|
||||||
|
parameters = this.parameters(parentType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!parameters) {
|
if (!parameters) {
|
||||||
parameters = [];
|
parameters = [];
|
||||||
|
@ -176,10 +185,13 @@ export class StaticReflector implements ReflectorReader {
|
||||||
const classMetadata = this.getTypeMetadata(type);
|
const classMetadata = this.getTypeMetadata(type);
|
||||||
methodNames = {};
|
methodNames = {};
|
||||||
if (classMetadata['extends']) {
|
if (classMetadata['extends']) {
|
||||||
const parentMethodNames = this._methodNames(this.simplify(type, classMetadata['extends']));
|
const parentType = this.simplify(type, classMetadata['extends']);
|
||||||
Object.keys(parentMethodNames).forEach((parentProp) => {
|
if (parentType instanceof StaticSymbol) {
|
||||||
methodNames[parentProp] = parentMethodNames[parentProp];
|
const parentMethodNames = this._methodNames(parentType);
|
||||||
});
|
Object.keys(parentMethodNames).forEach((parentProp) => {
|
||||||
|
methodNames[parentProp] = parentMethodNames[parentProp];
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const members = classMetadata['members'] || {};
|
const members = classMetadata['members'] || {};
|
||||||
|
|
|
@ -12,7 +12,14 @@
|
||||||
* This token is unique for a filePath and name and can be used as a hash table key.
|
* This token is unique for a filePath and name and can be used as a hash table key.
|
||||||
*/
|
*/
|
||||||
export class StaticSymbol {
|
export class StaticSymbol {
|
||||||
constructor(public filePath: string, public name: string, public members?: string[]) {}
|
constructor(public filePath: string, public name: string, public members: string[]) {}
|
||||||
|
|
||||||
|
assertNoMembers() {
|
||||||
|
if (this.members.length) {
|
||||||
|
throw new Error(
|
||||||
|
`Illegal state: symbol without members expected, but got ${JSON.stringify(this)}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -45,11 +45,18 @@ const SUPPORTED_SCHEMA_VERSION = 3;
|
||||||
/**
|
/**
|
||||||
* This class is responsible for loading metadata per symbol,
|
* This class is responsible for loading metadata per symbol,
|
||||||
* and normalizing references between symbols.
|
* and normalizing references between symbols.
|
||||||
|
*
|
||||||
|
* Internally, it only uses symbols without members,
|
||||||
|
* and deduces the values for symbols with members based
|
||||||
|
* on these symbols.
|
||||||
*/
|
*/
|
||||||
export class StaticSymbolResolver {
|
export class StaticSymbolResolver {
|
||||||
private metadataCache = new Map<string, {[key: string]: any}>();
|
private metadataCache = new Map<string, {[key: string]: any}>();
|
||||||
|
// Note: this will only contain StaticSymbols without members!
|
||||||
private resolvedSymbols = new Map<StaticSymbol, ResolvedStaticSymbol>();
|
private resolvedSymbols = new Map<StaticSymbol, ResolvedStaticSymbol>();
|
||||||
private resolvedFilePaths = new Set<string>();
|
private resolvedFilePaths = new Set<string>();
|
||||||
|
// Note: this will only contain StaticSymbols without members!
|
||||||
|
private importAs = new Map<StaticSymbol, StaticSymbol>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private host: StaticSymbolResolverHost, private staticSymbolCache: StaticSymbolCache,
|
private host: StaticSymbolResolverHost, private staticSymbolCache: StaticSymbolCache,
|
||||||
|
@ -60,13 +67,33 @@ export class StaticSymbolResolver {
|
||||||
if (staticSymbol.members.length > 0) {
|
if (staticSymbol.members.length > 0) {
|
||||||
return this._resolveSymbolMembers(staticSymbol);
|
return this._resolveSymbolMembers(staticSymbol);
|
||||||
}
|
}
|
||||||
let result = this._resolveSymbolFromSummary(staticSymbol);
|
let result = this.resolvedSymbols.get(staticSymbol);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = this._resolveSymbolFromSummary(staticSymbol);
|
||||||
|
if (result) {
|
||||||
|
return 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
getImportAs(staticSymbol: StaticSymbol): StaticSymbol {
|
||||||
|
if (staticSymbol.members.length) {
|
||||||
|
const baseSymbol = this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name);
|
||||||
|
const baseImportAs = this.getImportAs(baseSymbol);
|
||||||
|
return baseImportAs ?
|
||||||
|
this.getStaticSymbol(baseImportAs.filePath, baseImportAs.name, staticSymbol.members) :
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
let result = this.summaryResolver.getImportAs(staticSymbol);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
// Note: Some users use libraries that were not compiled with ngc, i.e. they don't
|
result = this.importAs.get(staticSymbol);
|
||||||
// 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;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -135,10 +162,13 @@ export class StaticSymbolResolver {
|
||||||
const metadata = this.getModuleMetadata(filePath);
|
const metadata = this.getModuleMetadata(filePath);
|
||||||
if (metadata['metadata']) {
|
if (metadata['metadata']) {
|
||||||
// handle direct declarations of the symbol
|
// handle direct declarations of the symbol
|
||||||
Object.keys(metadata['metadata']).forEach((symbolName) => {
|
const topLevelSymbolNames =
|
||||||
const symbolMeta = metadata['metadata'][symbolName];
|
new Set<string>(Object.keys(metadata['metadata']).map(unescapeIdentifier));
|
||||||
resolvedSymbols.push(
|
Object.keys(metadata['metadata']).forEach((metadataKey) => {
|
||||||
this.createResolvedSymbol(this.getStaticSymbol(filePath, symbolName), symbolMeta));
|
const symbolMeta = metadata['metadata'][metadataKey];
|
||||||
|
resolvedSymbols.push(this.createResolvedSymbol(
|
||||||
|
this.getStaticSymbol(filePath, unescapeIdentifier(metadataKey)), topLevelSymbolNames,
|
||||||
|
symbolMeta));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,15 +184,16 @@ export class StaticSymbolResolver {
|
||||||
} else {
|
} else {
|
||||||
symbolName = exportSymbol.as;
|
symbolName = exportSymbol.as;
|
||||||
}
|
}
|
||||||
|
symbolName = unescapeIdentifier(symbolName);
|
||||||
let symName = symbolName;
|
let symName = symbolName;
|
||||||
if (typeof exportSymbol !== 'string') {
|
if (typeof exportSymbol !== 'string') {
|
||||||
symName = exportSymbol.name;
|
symName = unescapeIdentifier(exportSymbol.name);
|
||||||
}
|
}
|
||||||
const resolvedModule = this.resolveModule(moduleExport.from, filePath);
|
const resolvedModule = this.resolveModule(moduleExport.from, filePath);
|
||||||
if (resolvedModule) {
|
if (resolvedModule) {
|
||||||
const targetSymbol = this.getStaticSymbol(resolvedModule, symName);
|
const targetSymbol = this.getStaticSymbol(resolvedModule, symName);
|
||||||
const sourceSymbol = this.getStaticSymbol(filePath, symbolName);
|
const sourceSymbol = this.getStaticSymbol(filePath, symbolName);
|
||||||
resolvedSymbols.push(new ResolvedStaticSymbol(sourceSymbol, targetSymbol));
|
resolvedSymbols.push(this.createExport(sourceSymbol, targetSymbol));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -172,7 +203,7 @@ export class StaticSymbolResolver {
|
||||||
const nestedExports = this.getSymbolsOf(resolvedModule);
|
const nestedExports = this.getSymbolsOf(resolvedModule);
|
||||||
nestedExports.forEach((targetSymbol) => {
|
nestedExports.forEach((targetSymbol) => {
|
||||||
const sourceSymbol = this.getStaticSymbol(filePath, targetSymbol.name);
|
const sourceSymbol = this.getStaticSymbol(filePath, targetSymbol.name);
|
||||||
resolvedSymbols.push(new ResolvedStaticSymbol(sourceSymbol, targetSymbol));
|
resolvedSymbols.push(this.createExport(sourceSymbol, targetSymbol));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,7 +213,9 @@ export class StaticSymbolResolver {
|
||||||
(resolvedSymbol) => this.resolvedSymbols.set(resolvedSymbol.symbol, resolvedSymbol));
|
(resolvedSymbol) => this.resolvedSymbols.set(resolvedSymbol.symbol, resolvedSymbol));
|
||||||
}
|
}
|
||||||
|
|
||||||
private createResolvedSymbol(sourceSymbol: StaticSymbol, metadata: any): ResolvedStaticSymbol {
|
private createResolvedSymbol(
|
||||||
|
sourceSymbol: StaticSymbol, topLevelSymbolNames: Set<string>,
|
||||||
|
metadata: any): ResolvedStaticSymbol {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
class ReferenceTransformer extends ValueTransformer {
|
class ReferenceTransformer extends ValueTransformer {
|
||||||
|
@ -196,7 +229,7 @@ export class StaticSymbolResolver {
|
||||||
return result;
|
return result;
|
||||||
} else if (symbolic === 'reference') {
|
} else if (symbolic === 'reference') {
|
||||||
const module = map['module'];
|
const module = map['module'];
|
||||||
const name = map['name'];
|
const name = map['name'] ? unescapeIdentifier(map['name']) : map['name'];
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -209,28 +242,43 @@ export class StaticSymbolResolver {
|
||||||
message: `Could not resolve ${module} relative to ${sourceSymbol.filePath}.`
|
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);
|
return self.getStaticSymbol(filePath, name);
|
||||||
} else {
|
} else if (functionParams.indexOf(name) >= 0) {
|
||||||
// reference to a function parameter
|
// reference to a function parameter
|
||||||
return {__symbolic: 'reference', name: name};
|
return {__symbolic: 'reference', name: name};
|
||||||
|
} else {
|
||||||
|
if (topLevelSymbolNames.has(name)) {
|
||||||
|
return self.getStaticSymbol(sourceSymbol.filePath, name);
|
||||||
|
}
|
||||||
|
// ambient value
|
||||||
|
null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return super.visitStringMap(map, functionParams);
|
return super.visitStringMap(map, functionParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const transformedMeta = visitValue(metadata, new ReferenceTransformer(), []);
|
const transformedMeta = visitValue(metadata, new ReferenceTransformer(), []);
|
||||||
|
if (transformedMeta instanceof StaticSymbol) {
|
||||||
|
return this.createExport(sourceSymbol, transformedMeta);
|
||||||
|
}
|
||||||
return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
|
return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private createExport(sourceSymbol: StaticSymbol, targetSymbol: StaticSymbol):
|
||||||
|
ResolvedStaticSymbol {
|
||||||
|
sourceSymbol.assertNoMembers();
|
||||||
|
targetSymbol.assertNoMembers();
|
||||||
|
if (this.summaryResolver.isLibraryFile(sourceSymbol.filePath)) {
|
||||||
|
// This case is for an ng library importing symbols from a plain ts library
|
||||||
|
// transitively.
|
||||||
|
// Note: We rely on the fact that we discover symbols in the direction
|
||||||
|
// from source files to library files
|
||||||
|
this.importAs.set(targetSymbol, this.getImportAs(sourceSymbol) || sourceSymbol);
|
||||||
|
}
|
||||||
|
return new ResolvedStaticSymbol(sourceSymbol, targetSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
private reportError(error: Error, context: StaticSymbol, path?: string) {
|
private reportError(error: Error, context: StaticSymbol, path?: string) {
|
||||||
if (this.errorRecorder) {
|
if (this.errorRecorder) {
|
||||||
this.errorRecorder(error, (context && context.filePath) || path);
|
this.errorRecorder(error, (context && context.filePath) || path);
|
||||||
|
@ -287,3 +335,11 @@ export class StaticSymbolResolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UNDERSCORE_CHAR_CODE = 95;
|
||||||
|
|
||||||
|
// Remove extra underscore from escaped identifier.
|
||||||
|
// See https://github.com/Microsoft/TypeScript/blob/master/src/compiler/utilities.ts
|
||||||
|
export function unescapeIdentifier(identifier: string): string {
|
||||||
|
return identifier.startsWith('___') ? identifier.substr(1) : identifier;
|
||||||
|
}
|
|
@ -10,9 +10,8 @@ import {Summary, SummaryResolver} from '../summary_resolver';
|
||||||
|
|
||||||
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
||||||
import {ResolvedStaticSymbol} from './static_symbol_resolver';
|
import {ResolvedStaticSymbol} from './static_symbol_resolver';
|
||||||
import {deserializeSummaries, summaryFileName} from './summary_serializer';
|
import {deserializeSummaries} from './summary_serializer';
|
||||||
|
import {ngfactoryFilePath, stripNgFactory, summaryFileName} from './util';
|
||||||
const STRIP_SRC_FILE_SUFFIXES = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
|
||||||
|
|
||||||
export interface AotSummaryResolverHost {
|
export interface AotSummaryResolverHost {
|
||||||
/**
|
/**
|
||||||
|
@ -24,23 +23,34 @@ export interface AotSummaryResolverHost {
|
||||||
* Returns whether a file is a source file or not.
|
* Returns whether a file is a source file or not.
|
||||||
*/
|
*/
|
||||||
isSourceFile(sourceFilePath: string): boolean;
|
isSourceFile(sourceFilePath: string): boolean;
|
||||||
|
/**
|
||||||
|
* Returns the output file path of a source file.
|
||||||
|
* E.g.
|
||||||
|
* `some_file.ts` -> `some_file.d.ts`
|
||||||
|
*/
|
||||||
|
getOutputFileName(sourceFilePath: string): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AotSummaryResolver implements SummaryResolver<StaticSymbol> {
|
export class AotSummaryResolver implements SummaryResolver<StaticSymbol> {
|
||||||
|
// Note: this will only contain StaticSymbols without members!
|
||||||
private summaryCache = new Map<StaticSymbol, Summary<StaticSymbol>>();
|
private summaryCache = new Map<StaticSymbol, Summary<StaticSymbol>>();
|
||||||
private loadedFilePaths = new Set<string>();
|
private loadedFilePaths = new Set<string>();
|
||||||
|
// Note: this will only contain StaticSymbols without members!
|
||||||
|
private importAs = new Map<StaticSymbol, StaticSymbol>();
|
||||||
|
|
||||||
constructor(private host: AotSummaryResolverHost, private staticSymbolCache: StaticSymbolCache) {}
|
constructor(private host: AotSummaryResolverHost, private staticSymbolCache: StaticSymbolCache) {}
|
||||||
|
|
||||||
private _assertNoMembers(symbol: StaticSymbol) {
|
isLibraryFile(filePath: string): boolean {
|
||||||
if (symbol.members.length) {
|
// Note: We need to strip the .ngfactory. file path,
|
||||||
throw new Error(
|
// so this method also works for generated files
|
||||||
`Internal state: StaticSymbols in summaries can't have members! ${JSON.stringify(symbol)}`);
|
// (for which host.isSourceFile will always return false).
|
||||||
}
|
return !this.host.isSourceFile(stripNgFactory(filePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLibraryFileName(filePath: string) { return this.host.getOutputFileName(filePath); }
|
||||||
|
|
||||||
resolveSummary(staticSymbol: StaticSymbol): Summary<StaticSymbol> {
|
resolveSummary(staticSymbol: StaticSymbol): Summary<StaticSymbol> {
|
||||||
this._assertNoMembers(staticSymbol);
|
staticSymbol.assertNoMembers();
|
||||||
let summary = this.summaryCache.get(staticSymbol);
|
let summary = this.summaryCache.get(staticSymbol);
|
||||||
if (!summary) {
|
if (!summary) {
|
||||||
this._loadSummaryFile(staticSymbol.filePath);
|
this._loadSummaryFile(staticSymbol.filePath);
|
||||||
|
@ -54,12 +64,17 @@ export class AotSummaryResolver implements SummaryResolver<StaticSymbol> {
|
||||||
return Array.from(this.summaryCache.keys()).filter((symbol) => symbol.filePath === filePath);
|
return Array.from(this.summaryCache.keys()).filter((symbol) => symbol.filePath === filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getImportAs(staticSymbol: StaticSymbol): StaticSymbol {
|
||||||
|
staticSymbol.assertNoMembers();
|
||||||
|
return this.importAs.get(staticSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
private _loadSummaryFile(filePath: string) {
|
private _loadSummaryFile(filePath: string) {
|
||||||
if (this.loadedFilePaths.has(filePath)) {
|
if (this.loadedFilePaths.has(filePath)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.loadedFilePaths.add(filePath);
|
this.loadedFilePaths.add(filePath);
|
||||||
if (!this.host.isSourceFile(filePath)) {
|
if (this.isLibraryFile(filePath)) {
|
||||||
const summaryFilePath = summaryFileName(filePath);
|
const summaryFilePath = summaryFileName(filePath);
|
||||||
let json: string;
|
let json: string;
|
||||||
try {
|
try {
|
||||||
|
@ -69,8 +84,13 @@ export class AotSummaryResolver implements SummaryResolver<StaticSymbol> {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
if (json) {
|
if (json) {
|
||||||
const readSummaries = deserializeSummaries(this.staticSymbolCache, json);
|
const {summaries, importAs} = deserializeSummaries(this.staticSymbolCache, json);
|
||||||
readSummaries.forEach((summary) => { this.summaryCache.set(summary.symbol, summary); });
|
summaries.forEach((summary) => this.summaryCache.set(summary.symbol, summary));
|
||||||
|
importAs.forEach((importAs) => {
|
||||||
|
this.importAs.set(
|
||||||
|
importAs.symbol,
|
||||||
|
this.staticSymbolCache.get(ngfactoryFilePath(filePath), importAs.importAs));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,25 +15,11 @@ import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolv
|
||||||
|
|
||||||
const STRIP_SRC_FILE_SUFFIXES = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
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(
|
export function serializeSummaries(
|
||||||
host: AotSummarySerializerHost, summaryResolver: SummaryResolver<StaticSymbol>,
|
summaryResolver: SummaryResolver<StaticSymbol>, symbolResolver: StaticSymbolResolver,
|
||||||
symbolResolver: StaticSymbolResolver,
|
symbols: ResolvedStaticSymbol[], types: CompileTypeSummary[]):
|
||||||
|
{json: string, exportAs: {symbol: StaticSymbol, exportAs: string}[]} {
|
||||||
symbols: ResolvedStaticSymbol[], types: CompileTypeSummary[]): string {
|
const serializer = new Serializer(symbolResolver, summaryResolver);
|
||||||
const serializer = new Serializer(host);
|
|
||||||
|
|
||||||
// for symbols, we use everything except for the class metadata itself
|
// for symbols, we use everything except for the class metadata itself
|
||||||
// (we keep the statics though), as the class metadata is contained in the
|
// (we keep the statics though), as the class metadata is contained in the
|
||||||
|
@ -46,7 +32,7 @@ export function serializeSummaries(
|
||||||
// we execute the loop!
|
// we execute the loop!
|
||||||
for (let processedIndex = 0; processedIndex < serializer.symbols.length; processedIndex++) {
|
for (let processedIndex = 0; processedIndex < serializer.symbols.length; processedIndex++) {
|
||||||
const symbol = serializer.symbols[processedIndex];
|
const symbol = serializer.symbols[processedIndex];
|
||||||
if (!host.isSourceFile(symbol.filePath)) {
|
if (summaryResolver.isLibraryFile(symbol.filePath)) {
|
||||||
let summary = summaryResolver.resolveSummary(symbol);
|
let summary = summaryResolver.resolveSummary(symbol);
|
||||||
if (!summary) {
|
if (!summary) {
|
||||||
// some symbols might originate from a plain typescript library
|
// some symbols might originate from a plain typescript library
|
||||||
|
@ -74,8 +60,11 @@ export function serializeSummaries(
|
||||||
const ngModuleSummary = <CompileNgModuleSummary>typeSummary;
|
const ngModuleSummary = <CompileNgModuleSummary>typeSummary;
|
||||||
ngModuleSummary.exportedDirectives.concat(ngModuleSummary.exportedPipes).forEach((id) => {
|
ngModuleSummary.exportedDirectives.concat(ngModuleSummary.exportedPipes).forEach((id) => {
|
||||||
const symbol: StaticSymbol = id.reference;
|
const symbol: StaticSymbol = id.reference;
|
||||||
if (!host.isSourceFile(symbol.filePath)) {
|
if (summaryResolver.isLibraryFile(symbol.filePath)) {
|
||||||
serializer.addOrMergeSummary(summaryResolver.resolveSummary(symbol));
|
const summary = summaryResolver.resolveSummary(symbol);
|
||||||
|
if (summary) {
|
||||||
|
serializer.addOrMergeSummary(summary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -83,18 +72,14 @@ export function serializeSummaries(
|
||||||
return serializer.serialize();
|
return serializer.serialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deserializeSummaries(
|
export function deserializeSummaries(symbolCache: StaticSymbolCache, json: string):
|
||||||
symbolCache: StaticSymbolCache, json: string): Summary<StaticSymbol>[] {
|
{summaries: Summary<StaticSymbol>[], importAs: {symbol: StaticSymbol, importAs: string}[]} {
|
||||||
const deserializer = new Deserializer(symbolCache);
|
const deserializer = new Deserializer(symbolCache);
|
||||||
return deserializer.deserialize(json);
|
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 {
|
class Serializer extends ValueTransformer {
|
||||||
|
// Note: This only contains symbols without members.
|
||||||
symbols: StaticSymbol[] = [];
|
symbols: StaticSymbol[] = [];
|
||||||
private indexBySymbol = new Map<StaticSymbol, number>();
|
private indexBySymbol = new Map<StaticSymbol, number>();
|
||||||
// This now contains a `__symbol: number` in the place of
|
// This now contains a `__symbol: number` in the place of
|
||||||
|
@ -102,7 +87,11 @@ class Serializer extends ValueTransformer {
|
||||||
private processedSummaryBySymbol = new Map<StaticSymbol, any>();
|
private processedSummaryBySymbol = new Map<StaticSymbol, any>();
|
||||||
private processedSummaries: any[] = [];
|
private processedSummaries: any[] = [];
|
||||||
|
|
||||||
constructor(private host: AotSummarySerializerHost) { super(); }
|
constructor(
|
||||||
|
private symbolResolver: StaticSymbolResolver,
|
||||||
|
private summaryResolver: SummaryResolver<StaticSymbol>) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
addOrMergeSummary(summary: Summary<StaticSymbol>) {
|
addOrMergeSummary(summary: Summary<StaticSymbol>) {
|
||||||
let symbolMeta = summary.metadata;
|
let symbolMeta = summary.metadata;
|
||||||
|
@ -129,34 +118,44 @@ class Serializer extends ValueTransformer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(): string {
|
serialize(): {json: string, exportAs: {symbol: StaticSymbol, exportAs: string}[]} {
|
||||||
return JSON.stringify({
|
const exportAs: {symbol: StaticSymbol, exportAs: string}[] = [];
|
||||||
|
const json = JSON.stringify({
|
||||||
summaries: this.processedSummaries,
|
summaries: this.processedSummaries,
|
||||||
symbols: this.symbols.map((symbol, index) => {
|
symbols: this.symbols.map((symbol, index) => {
|
||||||
|
symbol.assertNoMembers();
|
||||||
|
let importAs: string;
|
||||||
|
if (this.summaryResolver.isLibraryFile(symbol.filePath)) {
|
||||||
|
importAs = `${symbol.name}_${index}`;
|
||||||
|
exportAs.push({symbol, exportAs: importAs});
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
__symbol: index,
|
__symbol: index,
|
||||||
name: symbol.name,
|
name: symbol.name,
|
||||||
// We convert the source filenames tinto output filenames,
|
// We convert the source filenames tinto output filenames,
|
||||||
// as the generated summary file will be used when teh current
|
// as the generated summary file will be used when teh current
|
||||||
// compilation unit is used as a library
|
// compilation unit is used as a library
|
||||||
filePath: this.host.getOutputFileName(symbol.filePath)
|
filePath: this.summaryResolver.getLibraryFileName(symbol.filePath),
|
||||||
|
importAs: importAs
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
return {json, exportAs};
|
||||||
}
|
}
|
||||||
|
|
||||||
private processValue(value: any): any { return visitValue(value, this, null); }
|
private processValue(value: any): any { return visitValue(value, this, null); }
|
||||||
|
|
||||||
visitOther(value: any, context: any): any {
|
visitOther(value: any, context: any): any {
|
||||||
if (value instanceof StaticSymbol) {
|
if (value instanceof StaticSymbol) {
|
||||||
let index = this.indexBySymbol.get(value);
|
const baseSymbol = this.symbolResolver.getStaticSymbol(value.filePath, value.name);
|
||||||
|
let index = this.indexBySymbol.get(baseSymbol);
|
||||||
// Note: == by purpose to compare with undefined!
|
// Note: == by purpose to compare with undefined!
|
||||||
if (index == null) {
|
if (index == null) {
|
||||||
index = this.indexBySymbol.size;
|
index = this.indexBySymbol.size;
|
||||||
this.indexBySymbol.set(value, index);
|
this.indexBySymbol.set(baseSymbol, index);
|
||||||
this.symbols.push(value);
|
this.symbols.push(baseSymbol);
|
||||||
}
|
}
|
||||||
return {__symbol: index};
|
return {__symbol: index, members: value.members};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,16 +165,28 @@ class Deserializer extends ValueTransformer {
|
||||||
|
|
||||||
constructor(private symbolCache: StaticSymbolCache) { super(); }
|
constructor(private symbolCache: StaticSymbolCache) { super(); }
|
||||||
|
|
||||||
deserialize(json: string): Summary<StaticSymbol>[] {
|
deserialize(json: string):
|
||||||
|
{summaries: Summary<StaticSymbol>[], importAs: {symbol: StaticSymbol, importAs: string}[]} {
|
||||||
const data: {summaries: any[], symbols: any[]} = JSON.parse(json);
|
const data: {summaries: any[], symbols: any[]} = JSON.parse(json);
|
||||||
this.symbols = data.symbols.map(
|
const importAs: {symbol: StaticSymbol, importAs: string}[] = [];
|
||||||
serializedSymbol => this.symbolCache.get(serializedSymbol.filePath, serializedSymbol.name));
|
this.symbols = [];
|
||||||
return visitValue(data.summaries, this, null);
|
data.symbols.forEach((serializedSymbol) => {
|
||||||
|
const symbol = this.symbolCache.get(serializedSymbol.filePath, serializedSymbol.name);
|
||||||
|
this.symbols.push(symbol);
|
||||||
|
if (serializedSymbol.importAs) {
|
||||||
|
importAs.push({symbol: symbol, importAs: serializedSymbol.importAs});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const summaries = visitValue(data.summaries, this, null);
|
||||||
|
return {summaries, importAs};
|
||||||
}
|
}
|
||||||
|
|
||||||
visitStringMap(map: {[key: string]: any}, context: any): any {
|
visitStringMap(map: {[key: string]: any}, context: any): any {
|
||||||
if ('__symbol' in map) {
|
if ('__symbol' in map) {
|
||||||
return this.symbols[map['__symbol']];
|
const baseSymbol = this.symbols[map['__symbol']];
|
||||||
|
const members = map['members'];
|
||||||
|
return members.length ? this.symbolCache.get(baseSymbol.filePath, baseSymbol.name, members) :
|
||||||
|
baseSymbol;
|
||||||
} else {
|
} else {
|
||||||
return super.visitStringMap(map, context);
|
return super.visitStringMap(map, context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
const STRIP_SRC_FILE_SUFFIXES = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
||||||
|
|
||||||
|
export function ngfactoryFilePath(filePath: string): string {
|
||||||
|
const urlWithSuffix = splitTypescriptSuffix(filePath);
|
||||||
|
return `${urlWithSuffix[0]}.ngfactory${urlWithSuffix[1]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stripNgFactory(filePath: string): string {
|
||||||
|
return filePath.replace(/\.ngfactory\./, '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function splitTypescriptSuffix(path: string): string[] {
|
||||||
|
if (path.endsWith('.d.ts')) {
|
||||||
|
return [path.slice(0, -5), '.ts'];
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastDot = path.lastIndexOf('.');
|
||||||
|
|
||||||
|
if (lastDot !== -1) {
|
||||||
|
return [path.substring(0, lastDot), path.substring(lastDot)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [path, ''];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function summaryFileName(fileName: string): string {
|
||||||
|
const fileNameWithoutSuffix = fileName.replace(STRIP_SRC_FILE_SUFFIXES, '');
|
||||||
|
return `${fileNameWithoutSuffix}.ngsummary.json`;
|
||||||
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ChangeDetectionStrategy, SchemaMetadata, Type, ViewEncapsulation} from '@angular/core';
|
import {ChangeDetectionStrategy, ComponentFactory, SchemaMetadata, Type, ViewEncapsulation} from '@angular/core';
|
||||||
|
|
||||||
import {StaticSymbol} from './aot/static_symbol';
|
import {StaticSymbol} from './aot/static_symbol';
|
||||||
import {ListWrapper} from './facade/collection';
|
import {ListWrapper} from './facade/collection';
|
||||||
|
@ -112,6 +112,24 @@ export function identifierModuleUrl(compileIdentifier: CompileIdentifierMetadata
|
||||||
return reflector.importUri(ref);
|
return reflector.importUri(ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function viewClassName(compType: any, embeddedTemplateIndex: number): string {
|
||||||
|
return `View_${identifierName({reference: compType})}_${embeddedTemplateIndex}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hostViewClassName(compType: any): string {
|
||||||
|
return `HostView_${identifierName({reference: compType})}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dirWrapperClassName(dirType: any) {
|
||||||
|
return `Wrapper_${identifierName({reference: dirType})}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function componentFactoryName(compType: any): string {
|
||||||
|
return `${identifierName({reference: compType})}NgFactory`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProxyClass { setDelegate(delegate: any): void; }
|
||||||
|
|
||||||
export interface CompileIdentifierMetadata { reference: any; }
|
export interface CompileIdentifierMetadata { reference: any; }
|
||||||
|
|
||||||
export enum CompileSummaryKind {
|
export enum CompileSummaryKind {
|
||||||
|
@ -241,7 +259,7 @@ export class CompileTemplateMetadata {
|
||||||
externalStylesheets?: CompileStylesheetMetadata[],
|
externalStylesheets?: CompileStylesheetMetadata[],
|
||||||
ngContentSelectors?: string[],
|
ngContentSelectors?: string[],
|
||||||
animations?: CompileAnimationEntryMetadata[],
|
animations?: CompileAnimationEntryMetadata[],
|
||||||
interpolation?: [string, string]
|
interpolation?: [string, string],
|
||||||
} = {}) {
|
} = {}) {
|
||||||
this.encapsulation = encapsulation;
|
this.encapsulation = encapsulation;
|
||||||
this.template = template;
|
this.template = template;
|
||||||
|
@ -261,11 +279,16 @@ export class CompileTemplateMetadata {
|
||||||
return {
|
return {
|
||||||
animations: this.animations.map(anim => anim.name),
|
animations: this.animations.map(anim => anim.name),
|
||||||
ngContentSelectors: this.ngContentSelectors,
|
ngContentSelectors: this.ngContentSelectors,
|
||||||
encapsulation: this.encapsulation
|
encapsulation: this.encapsulation,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CompileEntryComponentMetadata {
|
||||||
|
componentType: any;
|
||||||
|
componentFactory: StaticSymbol|ComponentFactory<any>;
|
||||||
|
}
|
||||||
|
|
||||||
// Note: This should only use interfaces as nested data types
|
// Note: This should only use interfaces as nested data types
|
||||||
// as we need to be able to serialize this from/to JSON!
|
// as we need to be able to serialize this from/to JSON!
|
||||||
export interface CompileDirectiveSummary extends CompileTypeSummary {
|
export interface CompileDirectiveSummary extends CompileTypeSummary {
|
||||||
|
@ -281,9 +304,12 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
|
||||||
providers: CompileProviderMetadata[];
|
providers: CompileProviderMetadata[];
|
||||||
viewProviders: CompileProviderMetadata[];
|
viewProviders: CompileProviderMetadata[];
|
||||||
queries: CompileQueryMetadata[];
|
queries: CompileQueryMetadata[];
|
||||||
entryComponents: CompileIdentifierMetadata[];
|
entryComponents: CompileEntryComponentMetadata[];
|
||||||
changeDetection: ChangeDetectionStrategy;
|
changeDetection: ChangeDetectionStrategy;
|
||||||
template: CompileTemplateSummary;
|
template: CompileTemplateSummary;
|
||||||
|
wrapperType: StaticSymbol|ProxyClass;
|
||||||
|
componentViewType: StaticSymbol|ProxyClass;
|
||||||
|
componentFactory: StaticSymbol|ComponentFactory<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -292,7 +318,8 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
|
||||||
export class CompileDirectiveMetadata {
|
export class CompileDirectiveMetadata {
|
||||||
static create(
|
static create(
|
||||||
{isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host,
|
{isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host,
|
||||||
providers, viewProviders, queries, viewQueries, entryComponents, template}: {
|
providers, viewProviders, queries, viewQueries, entryComponents, template, wrapperType,
|
||||||
|
componentViewType, componentFactory}: {
|
||||||
isHost?: boolean,
|
isHost?: boolean,
|
||||||
type?: CompileTypeMetadata,
|
type?: CompileTypeMetadata,
|
||||||
isComponent?: boolean,
|
isComponent?: boolean,
|
||||||
|
@ -306,8 +333,11 @@ export class CompileDirectiveMetadata {
|
||||||
viewProviders?: CompileProviderMetadata[],
|
viewProviders?: CompileProviderMetadata[],
|
||||||
queries?: CompileQueryMetadata[],
|
queries?: CompileQueryMetadata[],
|
||||||
viewQueries?: CompileQueryMetadata[],
|
viewQueries?: CompileQueryMetadata[],
|
||||||
entryComponents?: CompileIdentifierMetadata[],
|
entryComponents?: CompileEntryComponentMetadata[],
|
||||||
template?: CompileTemplateMetadata
|
template?: CompileTemplateMetadata,
|
||||||
|
wrapperType?: StaticSymbol|ProxyClass,
|
||||||
|
componentViewType?: StaticSymbol|ProxyClass,
|
||||||
|
componentFactory?: StaticSymbol|ComponentFactory<any>,
|
||||||
} = {}): CompileDirectiveMetadata {
|
} = {}): CompileDirectiveMetadata {
|
||||||
const hostListeners: {[key: string]: string} = {};
|
const hostListeners: {[key: string]: string} = {};
|
||||||
const hostProperties: {[key: string]: string} = {};
|
const hostProperties: {[key: string]: string} = {};
|
||||||
|
@ -359,6 +389,9 @@ export class CompileDirectiveMetadata {
|
||||||
viewQueries,
|
viewQueries,
|
||||||
entryComponents,
|
entryComponents,
|
||||||
template,
|
template,
|
||||||
|
wrapperType,
|
||||||
|
componentViewType,
|
||||||
|
componentFactory,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
isHost: boolean;
|
isHost: boolean;
|
||||||
|
@ -376,32 +409,39 @@ export class CompileDirectiveMetadata {
|
||||||
viewProviders: CompileProviderMetadata[];
|
viewProviders: CompileProviderMetadata[];
|
||||||
queries: CompileQueryMetadata[];
|
queries: CompileQueryMetadata[];
|
||||||
viewQueries: CompileQueryMetadata[];
|
viewQueries: CompileQueryMetadata[];
|
||||||
entryComponents: CompileIdentifierMetadata[];
|
entryComponents: CompileEntryComponentMetadata[];
|
||||||
|
|
||||||
template: CompileTemplateMetadata;
|
template: CompileTemplateMetadata;
|
||||||
|
|
||||||
constructor(
|
wrapperType: StaticSymbol|ProxyClass;
|
||||||
{isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs,
|
componentViewType: StaticSymbol|ProxyClass;
|
||||||
hostListeners, hostProperties, hostAttributes, providers, viewProviders, queries,
|
componentFactory: StaticSymbol|ComponentFactory<any>;
|
||||||
viewQueries, entryComponents, template}: {
|
|
||||||
isHost?: boolean,
|
constructor({isHost, type, isComponent, selector, exportAs,
|
||||||
type?: CompileTypeMetadata,
|
changeDetection, inputs, outputs, hostListeners, hostProperties,
|
||||||
isComponent?: boolean,
|
hostAttributes, providers, viewProviders, queries, viewQueries,
|
||||||
selector?: string,
|
entryComponents, template, wrapperType, componentViewType, componentFactory}: {
|
||||||
exportAs?: string,
|
isHost?: boolean,
|
||||||
changeDetection?: ChangeDetectionStrategy,
|
type?: CompileTypeMetadata,
|
||||||
inputs?: {[key: string]: string},
|
isComponent?: boolean,
|
||||||
outputs?: {[key: string]: string},
|
selector?: string,
|
||||||
hostListeners?: {[key: string]: string},
|
exportAs?: string,
|
||||||
hostProperties?: {[key: string]: string},
|
changeDetection?: ChangeDetectionStrategy,
|
||||||
hostAttributes?: {[key: string]: string},
|
inputs?: {[key: string]: string},
|
||||||
providers?: CompileProviderMetadata[],
|
outputs?: {[key: string]: string},
|
||||||
viewProviders?: CompileProviderMetadata[],
|
hostListeners?: {[key: string]: string},
|
||||||
queries?: CompileQueryMetadata[],
|
hostProperties?: {[key: string]: string},
|
||||||
viewQueries?: CompileQueryMetadata[],
|
hostAttributes?: {[key: string]: string},
|
||||||
entryComponents?: CompileIdentifierMetadata[],
|
providers?: CompileProviderMetadata[],
|
||||||
template?: CompileTemplateMetadata,
|
viewProviders?: CompileProviderMetadata[],
|
||||||
} = {}) {
|
queries?: CompileQueryMetadata[],
|
||||||
|
viewQueries?: CompileQueryMetadata[],
|
||||||
|
entryComponents?: CompileEntryComponentMetadata[],
|
||||||
|
template?: CompileTemplateMetadata,
|
||||||
|
wrapperType?: StaticSymbol|ProxyClass,
|
||||||
|
componentViewType?: StaticSymbol|ProxyClass,
|
||||||
|
componentFactory?: StaticSymbol|ComponentFactory<any>,
|
||||||
|
} = {}) {
|
||||||
this.isHost = !!isHost;
|
this.isHost = !!isHost;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.isComponent = isComponent;
|
this.isComponent = isComponent;
|
||||||
|
@ -418,8 +458,11 @@ export class CompileDirectiveMetadata {
|
||||||
this.queries = _normalizeArray(queries);
|
this.queries = _normalizeArray(queries);
|
||||||
this.viewQueries = _normalizeArray(viewQueries);
|
this.viewQueries = _normalizeArray(viewQueries);
|
||||||
this.entryComponents = _normalizeArray(entryComponents);
|
this.entryComponents = _normalizeArray(entryComponents);
|
||||||
|
|
||||||
this.template = template;
|
this.template = template;
|
||||||
|
|
||||||
|
this.wrapperType = wrapperType;
|
||||||
|
this.componentViewType = componentViewType;
|
||||||
|
this.componentFactory = componentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
toSummary(): CompileDirectiveSummary {
|
toSummary(): CompileDirectiveSummary {
|
||||||
|
@ -439,7 +482,10 @@ export class CompileDirectiveMetadata {
|
||||||
queries: this.queries,
|
queries: this.queries,
|
||||||
entryComponents: this.entryComponents,
|
entryComponents: this.entryComponents,
|
||||||
changeDetection: this.changeDetection,
|
changeDetection: this.changeDetection,
|
||||||
template: this.template && this.template.toSummary()
|
template: this.template && this.template.toSummary(),
|
||||||
|
wrapperType: this.wrapperType,
|
||||||
|
componentViewType: this.componentViewType,
|
||||||
|
componentFactory: this.componentFactory
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -448,11 +494,12 @@ export class CompileDirectiveMetadata {
|
||||||
* Construct {@link CompileDirectiveMetadata} from {@link ComponentTypeMetadata} and a selector.
|
* Construct {@link CompileDirectiveMetadata} from {@link ComponentTypeMetadata} and a selector.
|
||||||
*/
|
*/
|
||||||
export function createHostComponentMeta(
|
export function createHostComponentMeta(
|
||||||
typeReference: any, compMeta: CompileDirectiveMetadata): CompileDirectiveMetadata {
|
hostTypeReference: any, compMeta: CompileDirectiveMetadata,
|
||||||
|
hostViewType: StaticSymbol | ProxyClass): CompileDirectiveMetadata {
|
||||||
const template = CssSelector.parse(compMeta.selector)[0].getMatchingElementTemplate();
|
const template = CssSelector.parse(compMeta.selector)[0].getMatchingElementTemplate();
|
||||||
return CompileDirectiveMetadata.create({
|
return CompileDirectiveMetadata.create({
|
||||||
isHost: true,
|
isHost: true,
|
||||||
type: {reference: typeReference, diDeps: [], lifecycleHooks: []},
|
type: {reference: hostTypeReference, diDeps: [], lifecycleHooks: []},
|
||||||
template: new CompileTemplateMetadata({
|
template: new CompileTemplateMetadata({
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
template: template,
|
template: template,
|
||||||
|
@ -471,7 +518,8 @@ export function createHostComponentMeta(
|
||||||
providers: [],
|
providers: [],
|
||||||
viewProviders: [],
|
viewProviders: [],
|
||||||
queries: [],
|
queries: [],
|
||||||
viewQueries: []
|
viewQueries: [],
|
||||||
|
componentViewType: hostViewType
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,7 +565,7 @@ export interface CompileNgModuleSummary extends CompileTypeSummary {
|
||||||
exportedPipes: CompileIdentifierMetadata[];
|
exportedPipes: CompileIdentifierMetadata[];
|
||||||
|
|
||||||
// Note: This is transitive.
|
// Note: This is transitive.
|
||||||
entryComponents: CompileIdentifierMetadata[];
|
entryComponents: CompileEntryComponentMetadata[];
|
||||||
// Note: This is transitive.
|
// Note: This is transitive.
|
||||||
providers: {provider: CompileProviderMetadata, module: CompileIdentifierMetadata}[];
|
providers: {provider: CompileProviderMetadata, module: CompileIdentifierMetadata}[];
|
||||||
// Note: This is transitive.
|
// Note: This is transitive.
|
||||||
|
@ -534,7 +582,7 @@ export class CompileNgModuleMetadata {
|
||||||
declaredPipes: CompileIdentifierMetadata[];
|
declaredPipes: CompileIdentifierMetadata[];
|
||||||
|
|
||||||
exportedPipes: CompileIdentifierMetadata[];
|
exportedPipes: CompileIdentifierMetadata[];
|
||||||
entryComponents: CompileIdentifierMetadata[];
|
entryComponents: CompileEntryComponentMetadata[];
|
||||||
bootstrapComponents: CompileIdentifierMetadata[];
|
bootstrapComponents: CompileIdentifierMetadata[];
|
||||||
providers: CompileProviderMetadata[];
|
providers: CompileProviderMetadata[];
|
||||||
|
|
||||||
|
@ -555,7 +603,7 @@ export class CompileNgModuleMetadata {
|
||||||
exportedDirectives?: CompileIdentifierMetadata[],
|
exportedDirectives?: CompileIdentifierMetadata[],
|
||||||
declaredPipes?: CompileIdentifierMetadata[],
|
declaredPipes?: CompileIdentifierMetadata[],
|
||||||
exportedPipes?: CompileIdentifierMetadata[],
|
exportedPipes?: CompileIdentifierMetadata[],
|
||||||
entryComponents?: CompileIdentifierMetadata[],
|
entryComponents?: CompileEntryComponentMetadata[],
|
||||||
bootstrapComponents?: CompileIdentifierMetadata[],
|
bootstrapComponents?: CompileIdentifierMetadata[],
|
||||||
importedModules?: CompileNgModuleSummary[],
|
importedModules?: CompileNgModuleSummary[],
|
||||||
exportedModules?: CompileNgModuleSummary[],
|
exportedModules?: CompileNgModuleSummary[],
|
||||||
|
@ -603,7 +651,7 @@ export class TransitiveCompileNgModuleMetadata {
|
||||||
modulesSet = new Set<any>();
|
modulesSet = new Set<any>();
|
||||||
modules: CompileTypeMetadata[] = [];
|
modules: CompileTypeMetadata[] = [];
|
||||||
entryComponentsSet = new Set<any>();
|
entryComponentsSet = new Set<any>();
|
||||||
entryComponents: CompileIdentifierMetadata[] = [];
|
entryComponents: CompileEntryComponentMetadata[] = [];
|
||||||
|
|
||||||
providers: {provider: CompileProviderMetadata, module: CompileIdentifierMetadata}[] = [];
|
providers: {provider: CompileProviderMetadata, module: CompileIdentifierMetadata}[] = [];
|
||||||
|
|
||||||
|
@ -641,10 +689,10 @@ export class TransitiveCompileNgModuleMetadata {
|
||||||
this.modules.push(id);
|
this.modules.push(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addEntryComponent(id: CompileIdentifierMetadata) {
|
addEntryComponent(ec: CompileEntryComponentMetadata) {
|
||||||
if (!this.entryComponentsSet.has(id.reference)) {
|
if (!this.entryComponentsSet.has(ec.componentType)) {
|
||||||
this.entryComponentsSet.add(id.reference);
|
this.entryComponentsSet.add(ec.componentType);
|
||||||
this.entryComponents.push(id);
|
this.entryComponents.push(ec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, identifierModuleUrl, identifierName} from './compile_metadata';
|
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, dirWrapperClassName, identifierModuleUrl, identifierName} from './compile_metadata';
|
||||||
import {createCheckBindingField, createCheckBindingStmt} from './compiler_util/binding_util';
|
import {createCheckBindingField, createCheckBindingStmt} from './compiler_util/binding_util';
|
||||||
import {EventHandlerVars, convertActionBinding, convertPropertyBinding} from './compiler_util/expression_converter';
|
import {EventHandlerVars, convertActionBinding, convertPropertyBinding} from './compiler_util/expression_converter';
|
||||||
import {triggerAnimation, writeToRenderer} from './compiler_util/render_util';
|
import {triggerAnimation, writeToRenderer} from './compiler_util/render_util';
|
||||||
|
@ -52,10 +52,6 @@ const RESET_CHANGES_STMT = o.THIS_EXPR.prop(CHANGES_FIELD_NAME).set(o.literalMap
|
||||||
*/
|
*/
|
||||||
@CompilerInjectable()
|
@CompilerInjectable()
|
||||||
export class DirectiveWrapperCompiler {
|
export class DirectiveWrapperCompiler {
|
||||||
static dirWrapperClassName(id: CompileIdentifierMetadata) {
|
|
||||||
return `Wrapper_${identifierName(id)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private compilerConfig: CompilerConfig, private _exprParser: Parser,
|
private compilerConfig: CompilerConfig, private _exprParser: Parser,
|
||||||
private _schemaRegistry: ElementSchemaRegistry, private _console: Console) {}
|
private _schemaRegistry: ElementSchemaRegistry, private _console: Console) {}
|
||||||
|
@ -149,7 +145,7 @@ class DirectiveWrapperBuilder implements ClassBuilder {
|
||||||
.toStmt());
|
.toStmt());
|
||||||
|
|
||||||
return createClassStmt({
|
return createClassStmt({
|
||||||
name: DirectiveWrapperCompiler.dirWrapperClassName(this.dirMeta.type),
|
name: dirWrapperClassName(this.dirMeta.type.reference),
|
||||||
ctorParams: dirDepParamNames.map((paramName) => new o.FnParam(paramName, o.DYNAMIC_TYPE)),
|
ctorParams: dirDepParamNames.map((paramName) => new o.FnParam(paramName, o.DYNAMIC_TYPE)),
|
||||||
builders: [{fields, ctorStmts, methods}, this]
|
builders: [{fields, ctorStmts, methods}, this]
|
||||||
});
|
});
|
||||||
|
|
|
@ -109,7 +109,7 @@ export class Extractor {
|
||||||
const resolver = new CompileMetadataResolver(
|
const resolver = new CompileMetadataResolver(
|
||||||
new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector),
|
new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector),
|
||||||
new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer,
|
new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer,
|
||||||
staticReflector);
|
symbolCache, staticReflector);
|
||||||
|
|
||||||
// TODO(vicb): implicit tags & attributes
|
// TODO(vicb): implicit tags & attributes
|
||||||
const messageBundle = new MessageBundle(htmlParser, [], {});
|
const messageBundle = new MessageBundle(htmlParser, [], {});
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {Compiler, ComponentFactory, Injector, ModuleWithComponentFactories, NgMo
|
||||||
|
|
||||||
import {AnimationCompiler} from '../animation/animation_compiler';
|
import {AnimationCompiler} from '../animation/animation_compiler';
|
||||||
import {AnimationParser} from '../animation/animation_parser';
|
import {AnimationParser} from '../animation/animation_parser';
|
||||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, ProviderMeta, createHostComponentMeta, identifierName} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, ProviderMeta, ProxyClass, createHostComponentMeta, identifierName} from '../compile_metadata';
|
||||||
import {CompilerConfig} from '../config';
|
import {CompilerConfig} from '../config';
|
||||||
import {DirectiveNormalizer} from '../directive_normalizer';
|
import {DirectiveNormalizer} from '../directive_normalizer';
|
||||||
import {DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
|
import {DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
|
||||||
|
@ -21,10 +21,11 @@ import {NgModuleCompiler} from '../ng_module_compiler';
|
||||||
import * as ir from '../output/output_ast';
|
import * as ir from '../output/output_ast';
|
||||||
import {interpretStatements} from '../output/output_interpreter';
|
import {interpretStatements} from '../output/output_interpreter';
|
||||||
import {jitStatements} from '../output/output_jit';
|
import {jitStatements} from '../output/output_jit';
|
||||||
|
import {view_utils} from '../private_import_core';
|
||||||
import {CompiledStylesheet, StyleCompiler} from '../style_compiler';
|
import {CompiledStylesheet, StyleCompiler} from '../style_compiler';
|
||||||
import {TemplateParser} from '../template_parser/template_parser';
|
import {TemplateParser} from '../template_parser/template_parser';
|
||||||
import {SyncAsyncResult} from '../util';
|
import {SyncAsyncResult} from '../util';
|
||||||
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewClassDependency, ViewCompiler} from '../view_compiler/view_compiler';
|
import {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency, ViewCompiler} from '../view_compiler/view_compiler';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -130,10 +131,6 @@ export class JitCompiler implements Compiler {
|
||||||
const extraProviders = [this._metadataResolver.getProviderMetadata(new ProviderMeta(
|
const extraProviders = [this._metadataResolver.getProviderMetadata(new ProviderMeta(
|
||||||
Compiler, {useFactory: () => new ModuleBoundCompiler(this, moduleMeta.type.reference)}))];
|
Compiler, {useFactory: () => new ModuleBoundCompiler(this, moduleMeta.type.reference)}))];
|
||||||
const compileResult = this._ngModuleCompiler.compile(moduleMeta, extraProviders);
|
const compileResult = this._ngModuleCompiler.compile(moduleMeta, extraProviders);
|
||||||
compileResult.dependencies.forEach((dep) => {
|
|
||||||
dep.placeholder.reference =
|
|
||||||
this._assertComponentKnown(dep.comp.reference, true).proxyComponentFactory;
|
|
||||||
});
|
|
||||||
if (!this._compilerConfig.useJit) {
|
if (!this._compilerConfig.useJit) {
|
||||||
ngModuleFactory =
|
ngModuleFactory =
|
||||||
interpretStatements(compileResult.statements, compileResult.ngModuleFactoryVar);
|
interpretStatements(compileResult.statements, compileResult.ngModuleFactoryVar);
|
||||||
|
@ -168,7 +165,7 @@ export class JitCompiler implements Compiler {
|
||||||
const template =
|
const template =
|
||||||
this._createCompiledHostTemplate(dirMeta.type.reference, localModuleMeta);
|
this._createCompiledHostTemplate(dirMeta.type.reference, localModuleMeta);
|
||||||
templates.add(template);
|
templates.add(template);
|
||||||
allComponentFactories.push(template.proxyComponentFactory);
|
allComponentFactories.push(<ComponentFactory<any>>dirMeta.componentFactory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -180,15 +177,16 @@ export class JitCompiler implements Compiler {
|
||||||
const dirMeta = this._metadataResolver.getDirectiveMetadata(dirIdentifier.reference);
|
const dirMeta = this._metadataResolver.getDirectiveMetadata(dirIdentifier.reference);
|
||||||
if (dirMeta.isComponent) {
|
if (dirMeta.isComponent) {
|
||||||
dirMeta.entryComponents.forEach((entryComponentType) => {
|
dirMeta.entryComponents.forEach((entryComponentType) => {
|
||||||
const moduleMeta = moduleByDirective.get(entryComponentType.reference);
|
const moduleMeta = moduleByDirective.get(entryComponentType.componentType);
|
||||||
templates.add(
|
templates.add(
|
||||||
this._createCompiledHostTemplate(entryComponentType.reference, moduleMeta));
|
this._createCompiledHostTemplate(entryComponentType.componentType, moduleMeta));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
localModuleMeta.entryComponents.forEach((entryComponentType) => {
|
localModuleMeta.entryComponents.forEach((entryComponentType) => {
|
||||||
const moduleMeta = moduleByDirective.get(entryComponentType.reference);
|
const moduleMeta = moduleByDirective.get(entryComponentType.componentType);
|
||||||
templates.add(this._createCompiledHostTemplate(entryComponentType.reference, moduleMeta));
|
templates.add(
|
||||||
|
this._createCompiledHostTemplate(entryComponentType.componentType, moduleMeta));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
templates.forEach((template) => this._compileTemplate(template));
|
templates.forEach((template) => this._compileTemplate(template));
|
||||||
|
@ -222,12 +220,12 @@ export class JitCompiler implements Compiler {
|
||||||
const compMeta = this._metadataResolver.getDirectiveMetadata(compType);
|
const compMeta = this._metadataResolver.getDirectiveMetadata(compType);
|
||||||
assertComponent(compMeta);
|
assertComponent(compMeta);
|
||||||
|
|
||||||
const HostClass = function HostClass() {};
|
const componentFactory = <ComponentFactory<any>>compMeta.componentFactory;
|
||||||
(<any>HostClass).overriddenName = `${identifierName(compMeta.type)}_Host`;
|
const hostClass = this._metadataResolver.getHostComponentType(compType);
|
||||||
|
const hostMeta = createHostComponentMeta(
|
||||||
const hostMeta = createHostComponentMeta(HostClass, compMeta);
|
hostClass, compMeta, <any>view_utils.getComponentFactoryViewClass(componentFactory));
|
||||||
compiledTemplate = new CompiledTemplate(
|
compiledTemplate =
|
||||||
true, compMeta.selector, compMeta.type, hostMeta, ngModule, [compMeta.type]);
|
new CompiledTemplate(true, compMeta.type, hostMeta, ngModule, [compMeta.type]);
|
||||||
this._compiledHostTemplateCache.set(compType, compiledTemplate);
|
this._compiledHostTemplateCache.set(compType, compiledTemplate);
|
||||||
}
|
}
|
||||||
return compiledTemplate;
|
return compiledTemplate;
|
||||||
|
@ -239,8 +237,7 @@ export class JitCompiler implements Compiler {
|
||||||
if (!compiledTemplate) {
|
if (!compiledTemplate) {
|
||||||
assertComponent(compMeta);
|
assertComponent(compMeta);
|
||||||
compiledTemplate = new CompiledTemplate(
|
compiledTemplate = new CompiledTemplate(
|
||||||
false, compMeta.selector, compMeta.type, compMeta, ngModule,
|
false, compMeta.type, compMeta, ngModule, ngModule.transitiveModule.directives);
|
||||||
ngModule.transitiveModule.directives);
|
|
||||||
this._compiledTemplateCache.set(compMeta.type.reference, compiledTemplate);
|
this._compiledTemplateCache.set(compMeta.type.reference, compiledTemplate);
|
||||||
}
|
}
|
||||||
return compiledTemplate;
|
return compiledTemplate;
|
||||||
|
@ -277,6 +274,7 @@ export class JitCompiler implements Compiler {
|
||||||
`/${identifierName(moduleMeta.type)}/${identifierName(dirMeta.type)}/wrapper.ngfactory.js`,
|
`/${identifierName(moduleMeta.type)}/${identifierName(dirMeta.type)}/wrapper.ngfactory.js`,
|
||||||
statements, compileResult.dirWrapperClassVar);
|
statements, compileResult.dirWrapperClassVar);
|
||||||
}
|
}
|
||||||
|
(<ProxyClass>dirMeta.wrapperType).setDelegate(directiveWrapperClass);
|
||||||
this._compiledDirectiveWrapperCache.set(dirMeta.type.reference, directiveWrapperClass);
|
this._compiledDirectiveWrapperCache.set(dirMeta.type.reference, directiveWrapperClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,21 +302,6 @@ export class JitCompiler implements Compiler {
|
||||||
const compileResult = this._viewCompiler.compileComponent(
|
const compileResult = this._viewCompiler.compileComponent(
|
||||||
compMeta, parsedTemplate, ir.variable(stylesCompileResult.componentStylesheet.stylesVar),
|
compMeta, parsedTemplate, ir.variable(stylesCompileResult.componentStylesheet.stylesVar),
|
||||||
pipes, compiledAnimations);
|
pipes, compiledAnimations);
|
||||||
compileResult.dependencies.forEach((dep) => {
|
|
||||||
let depTemplate: CompiledTemplate;
|
|
||||||
if (dep instanceof ViewClassDependency) {
|
|
||||||
const vfd = <ViewClassDependency>dep;
|
|
||||||
depTemplate = this._assertComponentKnown(vfd.comp.reference, false);
|
|
||||||
vfd.placeholder.reference = depTemplate.proxyViewClass;
|
|
||||||
} else if (dep instanceof ComponentFactoryDependency) {
|
|
||||||
const cfd = <ComponentFactoryDependency>dep;
|
|
||||||
depTemplate = this._assertComponentKnown(cfd.comp.reference, true);
|
|
||||||
cfd.placeholder.reference = depTemplate.proxyComponentFactory;
|
|
||||||
} else if (dep instanceof DirectiveWrapperDependency) {
|
|
||||||
const dwd = <DirectiveWrapperDependency>dep;
|
|
||||||
dwd.placeholder.reference = this._assertDirectiveWrapper(dwd.dir.reference);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const statements = stylesCompileResult.componentStylesheet.statements
|
const statements = stylesCompileResult.componentStylesheet.statements
|
||||||
.concat(...compiledAnimations.map(ca => ca.statements))
|
.concat(...compiledAnimations.map(ca => ca.statements))
|
||||||
.concat(compileResult.statements);
|
.concat(compileResult.statements);
|
||||||
|
@ -358,30 +341,18 @@ export class JitCompiler implements Compiler {
|
||||||
|
|
||||||
class CompiledTemplate {
|
class CompiledTemplate {
|
||||||
private _viewClass: Function = null;
|
private _viewClass: Function = null;
|
||||||
proxyViewClass: Type<any>;
|
|
||||||
proxyComponentFactory: ComponentFactory<any>;
|
|
||||||
isCompiled = false;
|
isCompiled = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public isHost: boolean, selector: string, public compType: CompileIdentifierMetadata,
|
public isHost: boolean, public compType: CompileIdentifierMetadata,
|
||||||
public compMeta: CompileDirectiveMetadata, public ngModule: CompileNgModuleMetadata,
|
public compMeta: CompileDirectiveMetadata, public ngModule: CompileNgModuleMetadata,
|
||||||
public directives: CompileIdentifierMetadata[]) {
|
public directives: CompileIdentifierMetadata[]) {
|
||||||
const self = this;
|
const self = this;
|
||||||
this.proxyViewClass = <any>function() {
|
|
||||||
if (!self._viewClass) {
|
|
||||||
throw new Error(
|
|
||||||
`Illegal state: CompiledTemplate for ${stringify(self.compType)} is not compiled yet!`);
|
|
||||||
}
|
|
||||||
return self._viewClass.apply(this, arguments);
|
|
||||||
};
|
|
||||||
this.proxyComponentFactory = isHost ?
|
|
||||||
new ComponentFactory<any>(selector, this.proxyViewClass, compType.reference) :
|
|
||||||
null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
compiled(viewClass: Function) {
|
compiled(viewClass: Function) {
|
||||||
this._viewClass = viewClass;
|
this._viewClass = viewClass;
|
||||||
this.proxyViewClass.prototype = viewClass.prototype;
|
(<ProxyClass>this.compMeta.componentViewType).setDelegate(viewClass);
|
||||||
this.isCompiled = true;
|
this.isCompiled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,10 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, Attribute, ChangeDetectionStrategy, Component, Directive, Host, Inject, Injectable, ModuleWithProviders, OpaqueToken, Optional, Provider, Query, SchemaMetadata, Self, SkipSelf, Type, resolveForwardRef} from '@angular/core';
|
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, Attribute, ChangeDetectionStrategy, Component, ComponentFactory, Directive, Host, Inject, Injectable, ModuleWithProviders, OpaqueToken, Optional, Provider, Query, SchemaMetadata, Self, SkipSelf, Type, resolveForwardRef} from '@angular/core';
|
||||||
|
|
||||||
import {StaticSymbol} from './aot/static_symbol';
|
import {StaticSymbol, StaticSymbolCache} from './aot/static_symbol';
|
||||||
|
import {ngfactoryFilePath} from './aot/util';
|
||||||
import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
|
import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
|
||||||
import * as cpl from './compile_metadata';
|
import * as cpl from './compile_metadata';
|
||||||
import {DirectiveNormalizer} from './directive_normalizer';
|
import {DirectiveNormalizer} from './directive_normalizer';
|
||||||
|
@ -38,6 +39,8 @@ export const ERROR_COLLECTOR_TOKEN = new OpaqueToken('ErrorCollector');
|
||||||
// to wait correctly.
|
// to wait correctly.
|
||||||
@CompilerInjectable()
|
@CompilerInjectable()
|
||||||
export class CompileMetadataResolver {
|
export class CompileMetadataResolver {
|
||||||
|
private _nonNormalizedDirectiveCache =
|
||||||
|
new Map<Type<any>, {annotation: Directive, metadata: cpl.CompileDirectiveMetadata}>();
|
||||||
private _directiveCache = new Map<Type<any>, cpl.CompileDirectiveMetadata>();
|
private _directiveCache = new Map<Type<any>, cpl.CompileDirectiveMetadata>();
|
||||||
private _summaryCache = new Map<Type<any>, cpl.CompileTypeSummary>();
|
private _summaryCache = new Map<Type<any>, cpl.CompileTypeSummary>();
|
||||||
private _pipeCache = new Map<Type<any>, cpl.CompilePipeMetadata>();
|
private _pipeCache = new Map<Type<any>, cpl.CompilePipeMetadata>();
|
||||||
|
@ -49,12 +52,14 @@ export class CompileMetadataResolver {
|
||||||
private _pipeResolver: PipeResolver, private _summaryResolver: SummaryResolver<any>,
|
private _pipeResolver: PipeResolver, private _summaryResolver: SummaryResolver<any>,
|
||||||
private _schemaRegistry: ElementSchemaRegistry,
|
private _schemaRegistry: ElementSchemaRegistry,
|
||||||
private _directiveNormalizer: DirectiveNormalizer,
|
private _directiveNormalizer: DirectiveNormalizer,
|
||||||
|
@Optional() private _staticSymbolCache: StaticSymbolCache,
|
||||||
private _reflector: ReflectorReader = reflector,
|
private _reflector: ReflectorReader = reflector,
|
||||||
@Optional() @Inject(ERROR_COLLECTOR_TOKEN) private _errorCollector?: ErrorCollector) {}
|
@Optional() @Inject(ERROR_COLLECTOR_TOKEN) private _errorCollector?: ErrorCollector) {}
|
||||||
|
|
||||||
clearCacheFor(type: Type<any>) {
|
clearCacheFor(type: Type<any>) {
|
||||||
const dirMeta = this._directiveCache.get(type);
|
const dirMeta = this._directiveCache.get(type);
|
||||||
this._directiveCache.delete(type);
|
this._directiveCache.delete(type);
|
||||||
|
this._nonNormalizedDirectiveCache.delete(type);
|
||||||
this._summaryCache.delete(type);
|
this._summaryCache.delete(type);
|
||||||
this._pipeCache.delete(type);
|
this._pipeCache.delete(type);
|
||||||
this._ngModuleOfTypes.delete(type);
|
this._ngModuleOfTypes.delete(type);
|
||||||
|
@ -67,6 +72,7 @@ export class CompileMetadataResolver {
|
||||||
|
|
||||||
clearCache() {
|
clearCache() {
|
||||||
this._directiveCache.clear();
|
this._directiveCache.clear();
|
||||||
|
this._nonNormalizedDirectiveCache.clear();
|
||||||
this._summaryCache.clear();
|
this._summaryCache.clear();
|
||||||
this._pipeCache.clear();
|
this._pipeCache.clear();
|
||||||
this._ngModuleCache.clear();
|
this._ngModuleCache.clear();
|
||||||
|
@ -74,6 +80,66 @@ export class CompileMetadataResolver {
|
||||||
this._directiveNormalizer.clearCache();
|
this._directiveNormalizer.clearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _createProxyClass(baseType: any, name: string): cpl.ProxyClass {
|
||||||
|
let delegate: any = null;
|
||||||
|
const proxyClass: cpl.ProxyClass = <any>function() {
|
||||||
|
if (!delegate) {
|
||||||
|
throw new Error(
|
||||||
|
`Illegal state: Class ${name} for type ${stringify(baseType)} is not compiled yet!`);
|
||||||
|
}
|
||||||
|
return delegate.apply(this, arguments);
|
||||||
|
};
|
||||||
|
proxyClass.setDelegate = (d) => {
|
||||||
|
delegate = d;
|
||||||
|
(<any>proxyClass).prototype = d.prototype;
|
||||||
|
};
|
||||||
|
// Make stringify work correctly
|
||||||
|
(<any>proxyClass).overriddenName = name;
|
||||||
|
return proxyClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getGeneratedClass(dirType: any, name: string): StaticSymbol|cpl.ProxyClass {
|
||||||
|
if (dirType instanceof StaticSymbol) {
|
||||||
|
return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), name);
|
||||||
|
} else {
|
||||||
|
return this._createProxyClass(dirType, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getDirectiveWrapperClass(dirType: any): StaticSymbol|cpl.ProxyClass {
|
||||||
|
return this.getGeneratedClass(dirType, cpl.dirWrapperClassName(dirType));
|
||||||
|
}
|
||||||
|
|
||||||
|
private getComponentViewClass(dirType: any): StaticSymbol|cpl.ProxyClass {
|
||||||
|
return this.getGeneratedClass(dirType, cpl.viewClassName(dirType, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
getHostComponentViewClass(dirType: any): StaticSymbol|cpl.ProxyClass {
|
||||||
|
return this.getGeneratedClass(dirType, cpl.hostViewClassName(dirType));
|
||||||
|
}
|
||||||
|
|
||||||
|
getHostComponentType(dirType: any): StaticSymbol|Type<any> {
|
||||||
|
const name = `${cpl.identifierName({reference: dirType})}_Host`;
|
||||||
|
if (dirType instanceof StaticSymbol) {
|
||||||
|
return this._staticSymbolCache.get(dirType.filePath, name);
|
||||||
|
} else {
|
||||||
|
const HostClass = <any>function HostClass() {};
|
||||||
|
HostClass.overriddenName = name;
|
||||||
|
|
||||||
|
return HostClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getComponentFactory(selector: string, dirType: any): StaticSymbol|ComponentFactory<any> {
|
||||||
|
if (dirType instanceof StaticSymbol) {
|
||||||
|
return this._staticSymbolCache.get(
|
||||||
|
ngfactoryFilePath(dirType.filePath), cpl.componentFactoryName(dirType));
|
||||||
|
} else {
|
||||||
|
const hostView = this.getHostComponentViewClass(dirType);
|
||||||
|
return new ComponentFactory(selector, <any>hostView, dirType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getAnimationEntryMetadata(entry: AnimationEntryMetadata): cpl.CompileAnimationEntryMetadata {
|
getAnimationEntryMetadata(entry: AnimationEntryMetadata): cpl.CompileAnimationEntryMetadata {
|
||||||
const defs = entry.definitions.map(def => this._getAnimationStateMetadata(def));
|
const defs = entry.definitions.map(def => this._getAnimationStateMetadata(def));
|
||||||
return new cpl.CompileAnimationEntryMetadata(entry.name, defs);
|
return new cpl.CompileAnimationEntryMetadata(entry.name, defs);
|
||||||
|
@ -162,6 +228,9 @@ export class CompileMetadataResolver {
|
||||||
queries: metadata.queries,
|
queries: metadata.queries,
|
||||||
viewQueries: metadata.viewQueries,
|
viewQueries: metadata.viewQueries,
|
||||||
entryComponents: metadata.entryComponents,
|
entryComponents: metadata.entryComponents,
|
||||||
|
wrapperType: metadata.wrapperType,
|
||||||
|
componentViewType: metadata.componentViewType,
|
||||||
|
componentFactory: metadata.componentFactory,
|
||||||
template: templateMetadata
|
template: templateMetadata
|
||||||
});
|
});
|
||||||
this._directiveCache.set(directiveType, normalizedDirMeta);
|
this._directiveCache.set(directiveType, normalizedDirMeta);
|
||||||
|
@ -201,7 +270,14 @@ export class CompileMetadataResolver {
|
||||||
getNonNormalizedDirectiveMetadata(directiveType: any):
|
getNonNormalizedDirectiveMetadata(directiveType: any):
|
||||||
{annotation: Directive, metadata: cpl.CompileDirectiveMetadata} {
|
{annotation: Directive, metadata: cpl.CompileDirectiveMetadata} {
|
||||||
directiveType = resolveForwardRef(directiveType);
|
directiveType = resolveForwardRef(directiveType);
|
||||||
const dirMeta = this._directiveResolver.resolve(directiveType);
|
if (!directiveType) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let cacheEntry = this._nonNormalizedDirectiveCache.get(directiveType);
|
||||||
|
if (cacheEntry) {
|
||||||
|
return cacheEntry;
|
||||||
|
}
|
||||||
|
const dirMeta = this._directiveResolver.resolve(directiveType, false);
|
||||||
if (!dirMeta) {
|
if (!dirMeta) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -230,7 +306,7 @@ export class CompileMetadataResolver {
|
||||||
|
|
||||||
let changeDetectionStrategy: ChangeDetectionStrategy = null;
|
let changeDetectionStrategy: ChangeDetectionStrategy = null;
|
||||||
let viewProviders: cpl.CompileProviderMetadata[] = [];
|
let viewProviders: cpl.CompileProviderMetadata[] = [];
|
||||||
let entryComponentMetadata: cpl.CompileIdentifierMetadata[] = [];
|
let entryComponentMetadata: cpl.CompileEntryComponentMetadata[] = [];
|
||||||
let selector = dirMeta.selector;
|
let selector = dirMeta.selector;
|
||||||
|
|
||||||
if (dirMeta instanceof Component) {
|
if (dirMeta instanceof Component) {
|
||||||
|
@ -243,7 +319,7 @@ export class CompileMetadataResolver {
|
||||||
}
|
}
|
||||||
if (dirMeta.entryComponents) {
|
if (dirMeta.entryComponents) {
|
||||||
entryComponentMetadata = flattenAndDedupeArray(dirMeta.entryComponents)
|
entryComponentMetadata = flattenAndDedupeArray(dirMeta.entryComponents)
|
||||||
.map((type) => this._getIdentifierMetadata(type))
|
.map((type) => this._getEntryComponentMetadata(type))
|
||||||
.concat(entryComponentMetadata);
|
.concat(entryComponentMetadata);
|
||||||
}
|
}
|
||||||
if (!selector) {
|
if (!selector) {
|
||||||
|
@ -287,9 +363,17 @@ export class CompileMetadataResolver {
|
||||||
viewProviders: viewProviders,
|
viewProviders: viewProviders,
|
||||||
queries: queries,
|
queries: queries,
|
||||||
viewQueries: viewQueries,
|
viewQueries: viewQueries,
|
||||||
entryComponents: entryComponentMetadata
|
entryComponents: entryComponentMetadata,
|
||||||
|
wrapperType: this.getDirectiveWrapperClass(directiveType),
|
||||||
|
componentViewType: nonNormalizedTemplateMetadata ? this.getComponentViewClass(directiveType) :
|
||||||
|
undefined,
|
||||||
|
componentFactory: nonNormalizedTemplateMetadata ?
|
||||||
|
this.getComponentFactory(selector, directiveType) :
|
||||||
|
undefined
|
||||||
});
|
});
|
||||||
return {metadata, annotation: dirMeta};
|
cacheEntry = {metadata, annotation: dirMeta};
|
||||||
|
this._nonNormalizedDirectiveCache.set(directiveType, cacheEntry);
|
||||||
|
return cacheEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -371,7 +455,7 @@ export class CompileMetadataResolver {
|
||||||
const importedModules: cpl.CompileNgModuleSummary[] = [];
|
const importedModules: cpl.CompileNgModuleSummary[] = [];
|
||||||
const exportedModules: cpl.CompileNgModuleSummary[] = [];
|
const exportedModules: cpl.CompileNgModuleSummary[] = [];
|
||||||
const providers: cpl.CompileProviderMetadata[] = [];
|
const providers: cpl.CompileProviderMetadata[] = [];
|
||||||
const entryComponents: cpl.CompileIdentifierMetadata[] = [];
|
const entryComponents: cpl.CompileEntryComponentMetadata[] = [];
|
||||||
const bootstrapComponents: cpl.CompileIdentifierMetadata[] = [];
|
const bootstrapComponents: cpl.CompileIdentifierMetadata[] = [];
|
||||||
const schemas: SchemaMetadata[] = [];
|
const schemas: SchemaMetadata[] = [];
|
||||||
|
|
||||||
|
@ -488,7 +572,7 @@ export class CompileMetadataResolver {
|
||||||
|
|
||||||
if (meta.entryComponents) {
|
if (meta.entryComponents) {
|
||||||
entryComponents.push(...flattenAndDedupeArray(meta.entryComponents)
|
entryComponents.push(...flattenAndDedupeArray(meta.entryComponents)
|
||||||
.map(type => this._getIdentifierMetadata(type)));
|
.map(type => this._getEntryComponentMetadata(type)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta.bootstrap) {
|
if (meta.bootstrap) {
|
||||||
|
@ -504,7 +588,8 @@ export class CompileMetadataResolver {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
entryComponents.push(...bootstrapComponents);
|
entryComponents.push(
|
||||||
|
...bootstrapComponents.map(type => this._getEntryComponentMetadata(type.reference)));
|
||||||
|
|
||||||
if (meta.schemas) {
|
if (meta.schemas) {
|
||||||
schemas.push(...flattenAndDedupeArray(meta.schemas));
|
schemas.push(...flattenAndDedupeArray(meta.schemas));
|
||||||
|
@ -769,7 +854,7 @@ export class CompileMetadataResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getProvidersMetadata(
|
private _getProvidersMetadata(
|
||||||
providers: Provider[], targetEntryComponents: cpl.CompileIdentifierMetadata[],
|
providers: Provider[], targetEntryComponents: cpl.CompileEntryComponentMetadata[],
|
||||||
debugInfo?: string, compileProviders: cpl.CompileProviderMetadata[] = [],
|
debugInfo?: string, compileProviders: cpl.CompileProviderMetadata[] = [],
|
||||||
type?: any): cpl.CompileProviderMetadata[] {
|
type?: any): cpl.CompileProviderMetadata[] {
|
||||||
providers.forEach((provider: any, providerIdx: number) => {
|
providers.forEach((provider: any, providerIdx: number) => {
|
||||||
|
@ -813,8 +898,8 @@ export class CompileMetadataResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getEntryComponentsFromProvider(provider: cpl.ProviderMeta, type?: any):
|
private _getEntryComponentsFromProvider(provider: cpl.ProviderMeta, type?: any):
|
||||||
cpl.CompileIdentifierMetadata[] {
|
cpl.CompileEntryComponentMetadata[] {
|
||||||
const components: cpl.CompileIdentifierMetadata[] = [];
|
const components: cpl.CompileEntryComponentMetadata[] = [];
|
||||||
const collectedIdentifiers: cpl.CompileIdentifierMetadata[] = [];
|
const collectedIdentifiers: cpl.CompileIdentifierMetadata[] = [];
|
||||||
|
|
||||||
if (provider.useFactory || provider.useExisting || provider.useClass) {
|
if (provider.useFactory || provider.useExisting || provider.useClass) {
|
||||||
|
@ -832,14 +917,27 @@ export class CompileMetadataResolver {
|
||||||
|
|
||||||
extractIdentifiers(provider.useValue, collectedIdentifiers);
|
extractIdentifiers(provider.useValue, collectedIdentifiers);
|
||||||
collectedIdentifiers.forEach((identifier) => {
|
collectedIdentifiers.forEach((identifier) => {
|
||||||
if (this._directiveResolver.isDirective(identifier.reference) ||
|
const entry = this._getEntryComponentMetadata(identifier.reference);
|
||||||
this._loadSummary(identifier.reference, cpl.CompileSummaryKind.Directive)) {
|
if (entry) {
|
||||||
components.push(identifier);
|
components.push(entry);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return components;
|
return components;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _getEntryComponentMetadata(dirType: any): cpl.CompileEntryComponentMetadata {
|
||||||
|
const dirMeta = this.getNonNormalizedDirectiveMetadata(dirType);
|
||||||
|
if (dirMeta) {
|
||||||
|
return {componentType: dirType, componentFactory: dirMeta.metadata.componentFactory};
|
||||||
|
} else {
|
||||||
|
const dirSummary =
|
||||||
|
<cpl.CompileDirectiveSummary>this._loadSummary(dirType, cpl.CompileSummaryKind.Directive);
|
||||||
|
if (dirSummary) {
|
||||||
|
return {componentType: dirType, componentFactory: dirSummary.componentFactory};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getProviderMetadata(provider: cpl.ProviderMeta): cpl.CompileProviderMetadata {
|
getProviderMetadata(provider: cpl.ProviderMeta): cpl.CompileProviderMetadata {
|
||||||
let compileDeps: cpl.CompileDiDependencyMetadata[];
|
let compileDeps: cpl.CompileDiDependencyMetadata[];
|
||||||
let compileTypeMetadata: cpl.CompileTypeMetadata = null;
|
let compileTypeMetadata: cpl.CompileTypeMetadata = null;
|
||||||
|
|
|
@ -19,9 +19,12 @@ import {LifecycleHooks} from './private_import_core';
|
||||||
import {NgModuleProviderAnalyzer} from './provider_analyzer';
|
import {NgModuleProviderAnalyzer} from './provider_analyzer';
|
||||||
import {ProviderAst} from './template_parser/template_ast';
|
import {ProviderAst} from './template_parser/template_ast';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is currently not read, but will probably be used in the future.
|
||||||
|
* We keep it as we already pass it through all the rigth places...
|
||||||
|
*/
|
||||||
export class ComponentFactoryDependency {
|
export class ComponentFactoryDependency {
|
||||||
constructor(
|
constructor(public compType: any) {}
|
||||||
public comp: CompileIdentifierMetadata, public placeholder: CompileIdentifierMetadata) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NgModuleCompileResult {
|
export class NgModuleCompileResult {
|
||||||
|
@ -46,13 +49,12 @@ export class NgModuleCompiler {
|
||||||
const bootstrapComponentFactories: CompileIdentifierMetadata[] = [];
|
const bootstrapComponentFactories: CompileIdentifierMetadata[] = [];
|
||||||
const entryComponentFactories =
|
const entryComponentFactories =
|
||||||
ngModuleMeta.transitiveModule.entryComponents.map((entryComponent) => {
|
ngModuleMeta.transitiveModule.entryComponents.map((entryComponent) => {
|
||||||
const id: CompileIdentifierMetadata = {reference: null};
|
|
||||||
if (ngModuleMeta.bootstrapComponents.some(
|
if (ngModuleMeta.bootstrapComponents.some(
|
||||||
(id) => id.reference === entryComponent.reference)) {
|
(id) => id.reference === entryComponent.componentType)) {
|
||||||
bootstrapComponentFactories.push(id);
|
bootstrapComponentFactories.push({reference: entryComponent.componentFactory});
|
||||||
}
|
}
|
||||||
deps.push(new ComponentFactoryDependency(entryComponent, id));
|
deps.push(new ComponentFactoryDependency(entryComponent.componentType));
|
||||||
return id;
|
return {reference: entryComponent.componentFactory};
|
||||||
});
|
});
|
||||||
const builder = new _InjectorBuilder(
|
const builder = new _InjectorBuilder(
|
||||||
ngModuleMeta, entryComponentFactories, bootstrapComponentFactories, sourceSpan);
|
ngModuleMeta, entryComponentFactories, bootstrapComponentFactories, sourceSpan);
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import {identifierModuleUrl, identifierName} from '../compile_metadata';
|
import {StaticSymbol} from '../aot/static_symbol';
|
||||||
|
import {CompileIdentifierMetadata} from '../compile_metadata';
|
||||||
import {isBlank, isPresent} from '../facade/lang';
|
import {isBlank, isPresent} from '../facade/lang';
|
||||||
|
|
||||||
import {EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
|
import {EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
|
||||||
|
@ -16,17 +17,17 @@ import * as o from './output_ast';
|
||||||
import {ImportResolver} from './path_util';
|
import {ImportResolver} from './path_util';
|
||||||
|
|
||||||
export class JavaScriptEmitter implements OutputEmitter {
|
export class JavaScriptEmitter implements OutputEmitter {
|
||||||
constructor(private _importGenerator: ImportResolver) {}
|
constructor(private _importResolver: ImportResolver) {}
|
||||||
emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string {
|
emitStatements(genFilePath: string, stmts: o.Statement[], exportedVars: string[]): string {
|
||||||
const converter = new JsEmitterVisitor(moduleUrl);
|
const converter = new JsEmitterVisitor(genFilePath, this._importResolver);
|
||||||
const ctx = EmitterVisitorContext.createRoot(exportedVars);
|
const ctx = EmitterVisitorContext.createRoot(exportedVars);
|
||||||
converter.visitAllStatements(stmts, ctx);
|
converter.visitAllStatements(stmts, ctx);
|
||||||
const srcParts: string[] = [];
|
const srcParts: string[] = [];
|
||||||
converter.importsWithPrefixes.forEach((prefix, importedModuleUrl) => {
|
converter.importsWithPrefixes.forEach((prefix, importedFilePath) => {
|
||||||
// Note: can't write the real word for import as it screws up system.js auto detection...
|
// Note: can't write the real word for import as it screws up system.js auto detection...
|
||||||
srcParts.push(
|
srcParts.push(
|
||||||
`var ${prefix} = req` +
|
`var ${prefix} = req` +
|
||||||
`uire('${this._importGenerator.fileNameToModuleName(importedModuleUrl, moduleUrl)}');`);
|
`uire('${this._importResolver.fileNameToModuleName(importedFilePath, genFilePath)}');`);
|
||||||
});
|
});
|
||||||
srcParts.push(ctx.toSource());
|
srcParts.push(ctx.toSource());
|
||||||
return srcParts.join('\n');
|
return srcParts.join('\n');
|
||||||
|
@ -36,20 +37,23 @@ export class JavaScriptEmitter implements OutputEmitter {
|
||||||
class JsEmitterVisitor extends AbstractJsEmitterVisitor {
|
class JsEmitterVisitor extends AbstractJsEmitterVisitor {
|
||||||
importsWithPrefixes = new Map<string, string>();
|
importsWithPrefixes = new Map<string, string>();
|
||||||
|
|
||||||
constructor(private _moduleUrl: string) { super(); }
|
constructor(private _genFilePath: string, private _importResolver: ImportResolver) { super(); }
|
||||||
|
|
||||||
|
private _resolveStaticSymbol(value: CompileIdentifierMetadata): StaticSymbol {
|
||||||
|
const reference = value.reference;
|
||||||
|
if (!(reference instanceof StaticSymbol)) {
|
||||||
|
throw new Error(`Internal error: unknown identifier ${JSON.stringify(value)}`);
|
||||||
|
}
|
||||||
|
return this._importResolver.getImportAs(reference) || reference;
|
||||||
|
}
|
||||||
|
|
||||||
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
|
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
|
||||||
const name = identifierName(ast.value);
|
const {name, filePath} = this._resolveStaticSymbol(ast.value);
|
||||||
const moduleUrl = identifierModuleUrl(ast.value);
|
if (filePath != this._genFilePath) {
|
||||||
if (isBlank(name)) {
|
let prefix = this.importsWithPrefixes.get(filePath);
|
||||||
console.error('>>>', ast.value);
|
|
||||||
throw new Error(`Internal error: unknown identifier ${ast.value}`);
|
|
||||||
}
|
|
||||||
if (isPresent(moduleUrl) && moduleUrl != this._moduleUrl) {
|
|
||||||
let prefix = this.importsWithPrefixes.get(moduleUrl);
|
|
||||||
if (isBlank(prefix)) {
|
if (isBlank(prefix)) {
|
||||||
prefix = `import${this.importsWithPrefixes.size}`;
|
prefix = `import${this.importsWithPrefixes.size}`;
|
||||||
this.importsWithPrefixes.set(moduleUrl, prefix);
|
this.importsWithPrefixes.set(filePath, prefix);
|
||||||
}
|
}
|
||||||
ctx.print(`${prefix}.`);
|
ctx.print(`${prefix}.`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {StaticSymbol} from '../aot/static_symbol';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface that defines how import statements should be generated.
|
* Interface that defines how import statements should be generated.
|
||||||
*/
|
*/
|
||||||
|
@ -16,4 +18,10 @@ export abstract class ImportResolver {
|
||||||
*/
|
*/
|
||||||
abstract fileNameToModuleName(importedFilePath: string, containingFilePath: string): string
|
abstract fileNameToModuleName(importedFilePath: string, containingFilePath: string): string
|
||||||
/*|null*/;
|
/*|null*/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given StaticSymbol into another StaticSymbol that should be used
|
||||||
|
* to generate the import from.
|
||||||
|
*/
|
||||||
|
abstract getImportAs(symbol: StaticSymbol): StaticSymbol /*|null*/;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,18 +7,22 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import {CompileIdentifierMetadata, identifierModuleUrl, identifierName} from '../compile_metadata';
|
import {StaticSymbol} from '../aot/static_symbol';
|
||||||
|
import {CompileIdentifierMetadata} from '../compile_metadata';
|
||||||
import {isBlank, isPresent} from '../facade/lang';
|
import {isBlank, isPresent} from '../facade/lang';
|
||||||
|
|
||||||
import {AbstractEmitterVisitor, CATCH_ERROR_VAR, CATCH_STACK_VAR, EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
|
import {AbstractEmitterVisitor, CATCH_ERROR_VAR, CATCH_STACK_VAR, EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
|
||||||
import * as o from './output_ast';
|
import * as o from './output_ast';
|
||||||
import {ImportResolver} from './path_util';
|
import {ImportResolver} from './path_util';
|
||||||
|
|
||||||
const _debugModuleUrl = '/debug/lib';
|
const _debugFilePath = '/debug/lib';
|
||||||
|
|
||||||
export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.Type | any[]):
|
export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.Type | any[]):
|
||||||
string {
|
string {
|
||||||
const converter = new _TsEmitterVisitor(_debugModuleUrl);
|
const converter = new _TsEmitterVisitor(_debugFilePath, {
|
||||||
|
fileNameToModuleName(filePath: string, containingFilePath: string) { return filePath; },
|
||||||
|
getImportAs(symbol: StaticSymbol) { return null; }
|
||||||
|
});
|
||||||
const ctx = EmitterVisitorContext.createRoot([]);
|
const ctx = EmitterVisitorContext.createRoot([]);
|
||||||
const asts: any[] = Array.isArray(ast) ? ast : [ast];
|
const asts: any[] = Array.isArray(ast) ? ast : [ast];
|
||||||
|
|
||||||
|
@ -37,17 +41,23 @@ export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.T
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TypeScriptEmitter implements OutputEmitter {
|
export class TypeScriptEmitter implements OutputEmitter {
|
||||||
constructor(private _importGenerator: ImportResolver) {}
|
constructor(private _importResolver: ImportResolver) {}
|
||||||
emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string {
|
emitStatements(genFilePath: string, stmts: o.Statement[], exportedVars: string[]): string {
|
||||||
const converter = new _TsEmitterVisitor(moduleUrl);
|
const converter = new _TsEmitterVisitor(genFilePath, this._importResolver);
|
||||||
const ctx = EmitterVisitorContext.createRoot(exportedVars);
|
const ctx = EmitterVisitorContext.createRoot(exportedVars);
|
||||||
converter.visitAllStatements(stmts, ctx);
|
converter.visitAllStatements(stmts, ctx);
|
||||||
const srcParts: string[] = [];
|
const srcParts: string[] = [];
|
||||||
converter.importsWithPrefixes.forEach((prefix, importedModuleUrl) => {
|
converter.reexports.forEach((reexports, exportedFilePath) => {
|
||||||
|
const reexportsCode =
|
||||||
|
reexports.map(reexport => `${reexport.name} as ${reexport.as}`).join(',');
|
||||||
|
srcParts.push(
|
||||||
|
`export {${reexportsCode}} from '${this._importResolver.fileNameToModuleName(exportedFilePath, genFilePath)}';`);
|
||||||
|
});
|
||||||
|
converter.importsWithPrefixes.forEach((prefix, importedFilePath) => {
|
||||||
// Note: can't write the real word for import as it screws up system.js auto detection...
|
// Note: can't write the real word for import as it screws up system.js auto detection...
|
||||||
srcParts.push(
|
srcParts.push(
|
||||||
`imp` +
|
`imp` +
|
||||||
`ort * as ${prefix} from '${this._importGenerator.fileNameToModuleName(importedModuleUrl, moduleUrl)}';`);
|
`ort * as ${prefix} from '${this._importResolver.fileNameToModuleName(importedFilePath, genFilePath)}';`);
|
||||||
});
|
});
|
||||||
srcParts.push(ctx.toSource());
|
srcParts.push(ctx.toSource());
|
||||||
return srcParts.join('\n');
|
return srcParts.join('\n');
|
||||||
|
@ -55,9 +65,12 @@ export class TypeScriptEmitter implements OutputEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor {
|
class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor {
|
||||||
constructor(private _moduleUrl: string) { super(false); }
|
constructor(private _genFilePath: string, private _importResolver: ImportResolver) {
|
||||||
|
super(false);
|
||||||
|
}
|
||||||
|
|
||||||
importsWithPrefixes = new Map<string, string>();
|
importsWithPrefixes = new Map<string, string>();
|
||||||
|
reexports = new Map<string, {name: string, as: string}[]>();
|
||||||
|
|
||||||
visitType(t: o.Type, ctx: EmitterVisitorContext, defaultType: string = 'any') {
|
visitType(t: o.Type, ctx: EmitterVisitorContext, defaultType: string = 'any') {
|
||||||
if (isPresent(t)) {
|
if (isPresent(t)) {
|
||||||
|
@ -98,6 +111,19 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||||
}
|
}
|
||||||
|
|
||||||
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
|
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
|
||||||
|
if (ctx.isExportedVar(stmt.name) && stmt.value instanceof o.ExternalExpr && !stmt.type) {
|
||||||
|
// check for a reexport
|
||||||
|
const {name, filePath, members} = this._resolveStaticSymbol(stmt.value.value);
|
||||||
|
if (members.length === 0 && filePath !== this._genFilePath) {
|
||||||
|
let reexports = this.reexports.get(filePath);
|
||||||
|
if (!reexports) {
|
||||||
|
reexports = [];
|
||||||
|
this.reexports.set(filePath, reexports);
|
||||||
|
}
|
||||||
|
reexports.push({name, as: stmt.name});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (ctx.isExportedVar(stmt.name)) {
|
if (ctx.isExportedVar(stmt.name)) {
|
||||||
ctx.print(`export `);
|
ctx.print(`export `);
|
||||||
}
|
}
|
||||||
|
@ -320,25 +346,29 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||||
}, params, ctx, ',');
|
}, params, ctx, ',');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _resolveStaticSymbol(value: CompileIdentifierMetadata): StaticSymbol {
|
||||||
|
const reference = value.reference;
|
||||||
|
if (!(reference instanceof StaticSymbol)) {
|
||||||
|
throw new Error(`Internal error: unknown identifier ${JSON.stringify(value)}`);
|
||||||
|
}
|
||||||
|
return this._importResolver.getImportAs(reference) || reference;
|
||||||
|
}
|
||||||
|
|
||||||
private _visitIdentifier(
|
private _visitIdentifier(
|
||||||
value: CompileIdentifierMetadata, typeParams: o.Type[], ctx: EmitterVisitorContext): void {
|
value: CompileIdentifierMetadata, typeParams: o.Type[], ctx: EmitterVisitorContext): void {
|
||||||
const name = identifierName(value);
|
const {name, filePath, members} = this._resolveStaticSymbol(value);
|
||||||
const moduleUrl = identifierModuleUrl(value);
|
if (filePath != this._genFilePath) {
|
||||||
if (isBlank(name)) {
|
let prefix = this.importsWithPrefixes.get(filePath);
|
||||||
throw new Error(`Internal error: unknown identifier ${value}`);
|
|
||||||
}
|
|
||||||
if (isPresent(moduleUrl) && moduleUrl != this._moduleUrl) {
|
|
||||||
let prefix = this.importsWithPrefixes.get(moduleUrl);
|
|
||||||
if (isBlank(prefix)) {
|
if (isBlank(prefix)) {
|
||||||
prefix = `import${this.importsWithPrefixes.size}`;
|
prefix = `import${this.importsWithPrefixes.size}`;
|
||||||
this.importsWithPrefixes.set(moduleUrl, prefix);
|
this.importsWithPrefixes.set(filePath, prefix);
|
||||||
}
|
}
|
||||||
ctx.print(`${prefix}.`);
|
ctx.print(`${prefix}.`);
|
||||||
}
|
}
|
||||||
if (value.reference && value.reference.members && value.reference.members.length) {
|
if (members.length) {
|
||||||
ctx.print(value.reference.name);
|
ctx.print(name);
|
||||||
ctx.print('.');
|
ctx.print('.');
|
||||||
ctx.print(value.reference.members.join('.'));
|
ctx.print(members.join('.'));
|
||||||
} else {
|
} else {
|
||||||
ctx.print(name);
|
ctx.print(name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,9 @@ export interface Summary<T> {
|
||||||
|
|
||||||
@CompilerInjectable()
|
@CompilerInjectable()
|
||||||
export class SummaryResolver<T> {
|
export class SummaryResolver<T> {
|
||||||
|
isLibraryFile(fileName: string): boolean { return false; };
|
||||||
|
getLibraryFileName(fileName: string): string { return null; }
|
||||||
resolveSummary(reference: T): Summary<T> { return null; };
|
resolveSummary(reference: T): Summary<T> { return null; };
|
||||||
getSymbolsOf(filePath: string): T[] { return []; }
|
getSymbolsOf(filePath: string): T[] { return []; }
|
||||||
|
getImportAs(reference: T): T { return reference; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,12 +97,11 @@ export class CompileElement extends CompileNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _createComponentFactoryResolver() {
|
private _createComponentFactoryResolver() {
|
||||||
const entryComponents =
|
const entryComponents = this.component.entryComponents.map((entryComponent) => {
|
||||||
this.component.entryComponents.map((entryComponent: CompileIdentifierMetadata) => {
|
this.view.targetDependencies.push(
|
||||||
const id: CompileIdentifierMetadata = {reference: null};
|
new ComponentFactoryDependency(entryComponent.componentType));
|
||||||
this.view.targetDependencies.push(new ComponentFactoryDependency(entryComponent, id));
|
return {reference: entryComponent.componentFactory};
|
||||||
return id;
|
});
|
||||||
});
|
|
||||||
if (!entryComponents || entryComponents.length === 0) {
|
if (!entryComponents || entryComponents.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -179,11 +178,11 @@ export class CompileElement extends CompileNode {
|
||||||
const depsExpr =
|
const depsExpr =
|
||||||
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep));
|
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep));
|
||||||
if (isDirectiveWrapper) {
|
if (isDirectiveWrapper) {
|
||||||
const directiveWrapperIdentifier: CompileIdentifierMetadata = {reference: null};
|
const dirMeta =
|
||||||
this.view.targetDependencies.push(new DirectiveWrapperDependency(
|
this._directives.find(dir => dir.type.reference === provider.useClass.reference);
|
||||||
provider.useClass, DirectiveWrapperCompiler.dirWrapperClassName(provider.useClass),
|
this.view.targetDependencies.push(
|
||||||
directiveWrapperIdentifier));
|
new DirectiveWrapperDependency(dirMeta.type.reference));
|
||||||
return DirectiveWrapperExpressions.create(directiveWrapperIdentifier, depsExpr);
|
return DirectiveWrapperExpressions.create({reference: dirMeta.wrapperType}, depsExpr);
|
||||||
} else {
|
} else {
|
||||||
return o.importExpr(provider.useClass)
|
return o.importExpr(provider.useClass)
|
||||||
.instantiate(depsExpr, o.importType(provider.useClass));
|
.instantiate(depsExpr, o.importType(provider.useClass));
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AnimationEntryCompileResult} from '../animation/animation_compiler';
|
import {AnimationEntryCompileResult} from '../animation/animation_compiler';
|
||||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeSummary, tokenName} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeSummary, tokenName, viewClassName} from '../compile_metadata';
|
||||||
import {EventHandlerVars, NameResolver} from '../compiler_util/expression_converter';
|
import {EventHandlerVars, NameResolver} from '../compiler_util/expression_converter';
|
||||||
import {createPureProxy} from '../compiler_util/identifier_util';
|
import {createPureProxy} from '../compiler_util/identifier_util';
|
||||||
import {CompilerConfig} from '../config';
|
import {CompilerConfig} from '../config';
|
||||||
|
@ -20,8 +20,8 @@ import {CompileElement, CompileNode} from './compile_element';
|
||||||
import {CompileMethod} from './compile_method';
|
import {CompileMethod} from './compile_method';
|
||||||
import {CompilePipe} from './compile_pipe';
|
import {CompilePipe} from './compile_pipe';
|
||||||
import {CompileQuery, addQueryToTokenMap, createQueryList} from './compile_query';
|
import {CompileQuery, addQueryToTokenMap, createQueryList} from './compile_query';
|
||||||
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewClassDependency} from './deps';
|
import {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency} from './deps';
|
||||||
import {getPropertyInView, getViewClassName} from './util';
|
import {getPropertyInView} from './util';
|
||||||
|
|
||||||
export enum CompileViewRootNodeType {
|
export enum CompileViewRootNodeType {
|
||||||
Node,
|
Node,
|
||||||
|
@ -87,7 +87,7 @@ export class CompileView implements NameResolver {
|
||||||
public animations: AnimationEntryCompileResult[], public viewIndex: number,
|
public animations: AnimationEntryCompileResult[], public viewIndex: number,
|
||||||
public declarationElement: CompileElement, public templateVariableBindings: string[][],
|
public declarationElement: CompileElement, public templateVariableBindings: string[][],
|
||||||
public targetDependencies:
|
public targetDependencies:
|
||||||
Array<ViewClassDependency|ComponentFactoryDependency|DirectiveWrapperDependency>) {
|
Array<ComponentViewDependency|ComponentFactoryDependency|DirectiveWrapperDependency>) {
|
||||||
this.createMethod = new CompileMethod(this);
|
this.createMethod = new CompileMethod(this);
|
||||||
this.animationBindingsMethod = new CompileMethod(this);
|
this.animationBindingsMethod = new CompileMethod(this);
|
||||||
this.injectorGetMethod = new CompileMethod(this);
|
this.injectorGetMethod = new CompileMethod(this);
|
||||||
|
@ -103,7 +103,7 @@ export class CompileView implements NameResolver {
|
||||||
this.detachMethod = new CompileMethod(this);
|
this.detachMethod = new CompileMethod(this);
|
||||||
|
|
||||||
this.viewType = getViewType(component, viewIndex);
|
this.viewType = getViewType(component, viewIndex);
|
||||||
this.className = getViewClassName(component, viewIndex);
|
this.className = viewClassName(component.type.reference, viewIndex);
|
||||||
this.classType = o.expressionType(o.variable(this.className));
|
this.classType = o.expressionType(o.variable(this.className));
|
||||||
this.classExpr = o.variable(this.className);
|
this.classExpr = o.variable(this.className);
|
||||||
if (this.viewType === ViewType.COMPONENT || this.viewType === ViewType.HOST) {
|
if (this.viewType === ViewType.COMPONENT || this.viewType === ViewType.HOST) {
|
||||||
|
|
|
@ -8,19 +8,26 @@
|
||||||
|
|
||||||
import {CompileIdentifierMetadata} from '../compile_metadata';
|
import {CompileIdentifierMetadata} from '../compile_metadata';
|
||||||
|
|
||||||
export class ViewClassDependency {
|
/**
|
||||||
constructor(
|
* This is currently not read, but will probably be used in the future.
|
||||||
public comp: CompileIdentifierMetadata, public name: string,
|
* We keep it as we already pass it through all the rigth places...
|
||||||
public placeholder: CompileIdentifierMetadata) {}
|
*/
|
||||||
|
export class ComponentViewDependency {
|
||||||
|
constructor(public compType: any) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is currently not read, but will probably be used in the future.
|
||||||
|
* We keep it as we already pass it through all the rigth places...
|
||||||
|
*/
|
||||||
export class ComponentFactoryDependency {
|
export class ComponentFactoryDependency {
|
||||||
constructor(
|
constructor(public compType: any) {}
|
||||||
public comp: CompileIdentifierMetadata, public placeholder: CompileIdentifierMetadata) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is currently not read, but will probably be used in the future.
|
||||||
|
* We keep it as we already pass it through all the rigth places...
|
||||||
|
*/
|
||||||
export class DirectiveWrapperDependency {
|
export class DirectiveWrapperDependency {
|
||||||
constructor(
|
constructor(public dirType: any) {}
|
||||||
public dir: CompileIdentifierMetadata, public name: string,
|
|
||||||
public placeholder: CompileIdentifierMetadata) {}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,12 +71,6 @@ export function injectFromViewParentInjector(
|
||||||
return viewExpr.callMethod('injectorGet', args);
|
return viewExpr.callMethod('injectorGet', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getViewClassName(
|
|
||||||
component: CompileDirectiveSummary | CompileDirectiveMetadata,
|
|
||||||
embeddedTemplateIndex: number): string {
|
|
||||||
return `View_${identifierName(component.type)}${embeddedTemplateIndex}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getHandleEventMethodName(elementIndex: number): string {
|
export function getHandleEventMethodName(elementIndex: number): string {
|
||||||
return `handleEvent_${elementIndex}`;
|
return `handleEvent_${elementIndex}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import {ViewEncapsulation} from '@angular/core';
|
import {ViewEncapsulation} from '@angular/core';
|
||||||
|
|
||||||
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileTokenMetadata, identifierModuleUrl, identifierName} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileTokenMetadata, identifierModuleUrl, identifierName, viewClassName} from '../compile_metadata';
|
||||||
import {createSharedBindingVariablesIfNeeded} from '../compiler_util/expression_converter';
|
import {createSharedBindingVariablesIfNeeded} from '../compiler_util/expression_converter';
|
||||||
import {createDiTokenExpression, createInlineArray} from '../compiler_util/identifier_util';
|
import {createDiTokenExpression, createInlineArray} from '../compiler_util/identifier_util';
|
||||||
import {isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
|
@ -22,8 +22,7 @@ import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventA
|
||||||
import {CompileElement, CompileNode} from './compile_element';
|
import {CompileElement, CompileNode} from './compile_element';
|
||||||
import {CompileView, CompileViewRootNode, CompileViewRootNodeType} from './compile_view';
|
import {CompileView, CompileViewRootNode, CompileViewRootNodeType} from './compile_view';
|
||||||
import {ChangeDetectorStatusEnum, DetectChangesVars, InjectMethodVars, ViewConstructorVars, ViewEncapsulationEnum, ViewProperties, ViewTypeEnum} from './constants';
|
import {ChangeDetectorStatusEnum, DetectChangesVars, InjectMethodVars, ViewConstructorVars, ViewEncapsulationEnum, ViewProperties, ViewTypeEnum} from './constants';
|
||||||
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewClassDependency} from './deps';
|
import {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency} from './deps';
|
||||||
import {getViewClassName} from './util';
|
|
||||||
|
|
||||||
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
|
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
|
||||||
const CLASS_ATTR = 'class';
|
const CLASS_ATTR = 'class';
|
||||||
|
@ -36,7 +35,8 @@ const rootSelectorVar = o.variable('rootSelector');
|
||||||
export function buildView(
|
export function buildView(
|
||||||
view: CompileView, template: TemplateAst[],
|
view: CompileView, template: TemplateAst[],
|
||||||
targetDependencies:
|
targetDependencies:
|
||||||
Array<ViewClassDependency|ComponentFactoryDependency|DirectiveWrapperDependency>): number {
|
Array<ComponentViewDependency|ComponentFactoryDependency|DirectiveWrapperDependency>):
|
||||||
|
number {
|
||||||
const builderVisitor = new ViewBuilderVisitor(view, targetDependencies);
|
const builderVisitor = new ViewBuilderVisitor(view, targetDependencies);
|
||||||
const parentEl =
|
const parentEl =
|
||||||
view.declarationElement.isNull() ? view.declarationElement : view.declarationElement.parent;
|
view.declarationElement.isNull() ? view.declarationElement : view.declarationElement.parent;
|
||||||
|
@ -63,7 +63,7 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||||
constructor(
|
constructor(
|
||||||
public view: CompileView,
|
public view: CompileView,
|
||||||
public targetDependencies:
|
public targetDependencies:
|
||||||
Array<ViewClassDependency|ComponentFactoryDependency|DirectiveWrapperDependency>) {}
|
Array<ComponentViewDependency|ComponentFactoryDependency|DirectiveWrapperDependency>) {}
|
||||||
|
|
||||||
private _isRootNode(parent: CompileElement): boolean { return parent.view !== this.view; }
|
private _isRootNode(parent: CompileElement): boolean { return parent.view !== this.view; }
|
||||||
|
|
||||||
|
@ -214,9 +214,7 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||||
this.view.nodes.push(compileElement);
|
this.view.nodes.push(compileElement);
|
||||||
let compViewExpr: o.ReadPropExpr = null;
|
let compViewExpr: o.ReadPropExpr = null;
|
||||||
if (isPresent(component)) {
|
if (isPresent(component)) {
|
||||||
const nestedComponentIdentifier: CompileIdentifierMetadata = {reference: null};
|
this.targetDependencies.push(new ComponentViewDependency(component.type.reference));
|
||||||
this.targetDependencies.push(new ViewClassDependency(
|
|
||||||
component.type, getViewClassName(component, 0), nestedComponentIdentifier));
|
|
||||||
|
|
||||||
compViewExpr = o.THIS_EXPR.prop(`compView_${nodeIndex}`); // fix highlighting: `
|
compViewExpr = o.THIS_EXPR.prop(`compView_${nodeIndex}`); // fix highlighting: `
|
||||||
this.view.fields.push(new o.ClassField(
|
this.view.fields.push(new o.ClassField(
|
||||||
|
@ -226,7 +224,7 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||||
compileElement.setComponentView(compViewExpr);
|
compileElement.setComponentView(compViewExpr);
|
||||||
this.view.createMethod.addStmt(
|
this.view.createMethod.addStmt(
|
||||||
compViewExpr
|
compViewExpr
|
||||||
.set(o.importExpr(nestedComponentIdentifier).instantiate([
|
.set(o.importExpr({reference: component.componentViewType}).instantiate([
|
||||||
ViewProperties.viewUtils, o.THIS_EXPR, o.literal(nodeIndex), renderNode
|
ViewProperties.viewUtils, o.THIS_EXPR, o.literal(nodeIndex), renderNode
|
||||||
]))
|
]))
|
||||||
.toStmt());
|
.toStmt());
|
||||||
|
|
|
@ -16,17 +16,17 @@ import {TemplateAst} from '../template_parser/template_ast';
|
||||||
|
|
||||||
import {CompileElement} from './compile_element';
|
import {CompileElement} from './compile_element';
|
||||||
import {CompileView} from './compile_view';
|
import {CompileView} from './compile_view';
|
||||||
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewClassDependency} from './deps';
|
import {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency} from './deps';
|
||||||
import {bindView} from './view_binder';
|
import {bindView} from './view_binder';
|
||||||
import {buildView, finishView} from './view_builder';
|
import {buildView, finishView} from './view_builder';
|
||||||
|
|
||||||
export {ComponentFactoryDependency, DirectiveWrapperDependency, ViewClassDependency} from './deps';
|
export {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency} from './deps';
|
||||||
|
|
||||||
export class ViewCompileResult {
|
export class ViewCompileResult {
|
||||||
constructor(
|
constructor(
|
||||||
public statements: o.Statement[], public viewClassVar: string,
|
public statements: o.Statement[], public viewClassVar: string,
|
||||||
public dependencies:
|
public dependencies:
|
||||||
Array<ViewClassDependency|ComponentFactoryDependency|DirectiveWrapperDependency>) {}
|
Array<ComponentViewDependency|ComponentFactoryDependency|DirectiveWrapperDependency>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@CompilerInjectable()
|
@CompilerInjectable()
|
||||||
|
@ -38,7 +38,7 @@ export class ViewCompiler {
|
||||||
pipes: CompilePipeSummary[],
|
pipes: CompilePipeSummary[],
|
||||||
compiledAnimations: AnimationEntryCompileResult[]): ViewCompileResult {
|
compiledAnimations: AnimationEntryCompileResult[]): ViewCompileResult {
|
||||||
const dependencies:
|
const dependencies:
|
||||||
Array<ViewClassDependency|ComponentFactoryDependency|DirectiveWrapperDependency> = [];
|
Array<ComponentViewDependency|ComponentFactoryDependency|DirectiveWrapperDependency> = [];
|
||||||
const view = new CompileView(
|
const view = new CompileView(
|
||||||
component, this._genConfig, pipes, styles, compiledAnimations, 0,
|
component, this._genConfig, pipes, styles, compiledAnimations, 0,
|
||||||
CompileElement.createNull(), [], dependencies);
|
CompileElement.createNull(), [], dependencies);
|
||||||
|
|
|
@ -487,6 +487,8 @@ describe('StaticReflector', () => {
|
||||||
export class Child extends Parent {}
|
export class Child extends Parent {}
|
||||||
|
|
||||||
export class ChildNoDecorators extends Parent {}
|
export class ChildNoDecorators extends Parent {}
|
||||||
|
|
||||||
|
export class ChildInvalidParent extends a.InvalidParent {}
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -500,6 +502,10 @@ describe('StaticReflector', () => {
|
||||||
expect(
|
expect(
|
||||||
reflector.annotations(reflector.getStaticSymbol('/tmp/src/main.ts', 'ChildNoDecorators')))
|
reflector.annotations(reflector.getStaticSymbol('/tmp/src/main.ts', 'ChildNoDecorators')))
|
||||||
.toEqual([new ClassDecorator('parent')]);
|
.toEqual([new ClassDecorator('parent')]);
|
||||||
|
|
||||||
|
expect(reflector.annotations(
|
||||||
|
reflector.getStaticSymbol('/tmp/src/main.ts', 'ChildInvalidParent')))
|
||||||
|
.toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should inherit parameters', () => {
|
it('should inherit parameters', () => {
|
||||||
|
@ -520,6 +526,8 @@ describe('StaticReflector', () => {
|
||||||
export class ChildWithCtor extends Parent {
|
export class ChildWithCtor extends Parent {
|
||||||
constructor(@ParamDecorator('c') c: C) {}
|
constructor(@ParamDecorator('c') c: C) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ChildInvalidParent extends a.InvalidParent {}
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -537,6 +545,10 @@ describe('StaticReflector', () => {
|
||||||
|
|
||||||
expect(reflector.parameters(reflector.getStaticSymbol('/tmp/src/main.ts', 'ChildWithCtor')))
|
expect(reflector.parameters(reflector.getStaticSymbol('/tmp/src/main.ts', 'ChildWithCtor')))
|
||||||
.toEqual([[reflector.getStaticSymbol('/tmp/src/main.ts', 'C'), new ParamDecorator('c')]]);
|
.toEqual([[reflector.getStaticSymbol('/tmp/src/main.ts', 'C'), new ParamDecorator('c')]]);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
reflector.parameters(reflector.getStaticSymbol('/tmp/src/main.ts', 'ChildInvalidParent')))
|
||||||
|
.toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should inherit property metadata', () => {
|
it('should inherit property metadata', () => {
|
||||||
|
@ -561,6 +573,8 @@ describe('StaticReflector', () => {
|
||||||
@PropDecorator('c')
|
@PropDecorator('c')
|
||||||
c: C;
|
c: C;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ChildInvalidParent extends a.InvalidParent {}
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -577,6 +591,10 @@ describe('StaticReflector', () => {
|
||||||
'b': [new PropDecorator('b1'), new PropDecorator('b2')],
|
'b': [new PropDecorator('b1'), new PropDecorator('b2')],
|
||||||
'c': [new PropDecorator('c')]
|
'c': [new PropDecorator('c')]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(reflector.propMetadata(
|
||||||
|
reflector.getStaticSymbol('/tmp/src/main.ts', 'ChildInvalidParent')))
|
||||||
|
.toEqual({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should inherit lifecycle hooks', () => {
|
it('should inherit lifecycle hooks', () => {
|
||||||
|
@ -591,6 +609,8 @@ describe('StaticReflector', () => {
|
||||||
hook2() {}
|
hook2() {}
|
||||||
hook3() {}
|
hook3() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ChildInvalidParent extends a.InvalidParent {}
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -606,6 +626,10 @@ describe('StaticReflector', () => {
|
||||||
expect(hooks(reflector.getStaticSymbol('/tmp/src/main.ts', 'Child'), [
|
expect(hooks(reflector.getStaticSymbol('/tmp/src/main.ts', 'Child'), [
|
||||||
'hook1', 'hook2', 'hook3'
|
'hook1', 'hook2', 'hook3'
|
||||||
])).toEqual([true, true, true]);
|
])).toEqual([true, true, true]);
|
||||||
|
|
||||||
|
expect(hooks(reflector.getStaticSymbol('/tmp/src/main.ts', 'ChildInvalidParent'), [
|
||||||
|
'hook1', 'hook2', 'hook3'
|
||||||
|
])).toEqual([false, false, false]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import * as ts from 'typescript';
|
||||||
const TS_EXT = /(^.|(?!\.d)..)\.ts$/;
|
const TS_EXT = /(^.|(?!\.d)..)\.ts$/;
|
||||||
|
|
||||||
describe('StaticSymbolResolver', () => {
|
describe('StaticSymbolResolver', () => {
|
||||||
const noContext = new StaticSymbol('', '');
|
const noContext = new StaticSymbol('', '', []);
|
||||||
let host: StaticSymbolResolverHost;
|
let host: StaticSymbolResolverHost;
|
||||||
let symbolResolver: StaticSymbolResolver;
|
let symbolResolver: StaticSymbolResolver;
|
||||||
let symbolCache: StaticSymbolCache;
|
let symbolCache: StaticSymbolCache;
|
||||||
|
@ -24,10 +24,11 @@ describe('StaticSymbolResolver', () => {
|
||||||
beforeEach(() => { symbolCache = new StaticSymbolCache(); });
|
beforeEach(() => { symbolCache = new StaticSymbolCache(); });
|
||||||
|
|
||||||
function init(
|
function init(
|
||||||
testData: {[key: string]: any} = DEFAULT_TEST_DATA, summaries: Summary<StaticSymbol>[] = []) {
|
testData: {[key: string]: any} = DEFAULT_TEST_DATA, summaries: Summary<StaticSymbol>[] = [],
|
||||||
|
summaryImportAs: {symbol: StaticSymbol, importAs: StaticSymbol}[] = []) {
|
||||||
host = new MockStaticSymbolResolverHost(testData);
|
host = new MockStaticSymbolResolverHost(testData);
|
||||||
symbolResolver =
|
symbolResolver = new StaticSymbolResolver(
|
||||||
new StaticSymbolResolver(host, symbolCache, new MockSummaryResolver(summaries));
|
host, symbolCache, new MockSummaryResolver(summaries, summaryImportAs));
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => init());
|
beforeEach(() => init());
|
||||||
|
@ -137,6 +138,73 @@ describe('StaticSymbolResolver', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('importAs', () => {
|
||||||
|
|
||||||
|
it('should calculate importAs relationship for non source files without summaries', () => {
|
||||||
|
init(
|
||||||
|
{
|
||||||
|
'/test.d.ts': [{
|
||||||
|
'__symbolic': 'module',
|
||||||
|
'version': 3,
|
||||||
|
'metadata': {
|
||||||
|
'a': {'__symbolic': 'reference', 'name': 'b', 'module': './test2'},
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
'/test2.d.ts': [{
|
||||||
|
'__symbolic': 'module',
|
||||||
|
'version': 3,
|
||||||
|
'metadata': {
|
||||||
|
'b': {'__symbolic': 'reference', 'name': 'c', 'module': './test3'},
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
[]);
|
||||||
|
symbolResolver.getSymbolsOf('/test.d.ts');
|
||||||
|
symbolResolver.getSymbolsOf('/test2.d.ts');
|
||||||
|
|
||||||
|
expect(symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'b')))
|
||||||
|
.toBe(symbolCache.get('/test.d.ts', 'a'));
|
||||||
|
expect(symbolResolver.getImportAs(symbolCache.get('/test3.d.ts', 'c')))
|
||||||
|
.toBe(symbolCache.get('/test.d.ts', 'a'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should calculate importAs relationship for non source files with summaries', () => {
|
||||||
|
init(
|
||||||
|
{
|
||||||
|
'/test.ts': `
|
||||||
|
export {a} from './test2';
|
||||||
|
`
|
||||||
|
},
|
||||||
|
[], [{
|
||||||
|
symbol: symbolCache.get('/test2.d.ts', 'a'),
|
||||||
|
importAs: symbolCache.get('/test3.d.ts', 'b')
|
||||||
|
}]);
|
||||||
|
symbolResolver.getSymbolsOf('/test.ts');
|
||||||
|
|
||||||
|
expect(symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'a')))
|
||||||
|
.toBe(symbolCache.get('/test3.d.ts', 'b'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should calculate importAs for symbols with members based on importAs for symbols without',
|
||||||
|
() => {
|
||||||
|
init(
|
||||||
|
{
|
||||||
|
'/test.ts': `
|
||||||
|
export {a} from './test2';
|
||||||
|
`
|
||||||
|
},
|
||||||
|
[], [{
|
||||||
|
symbol: symbolCache.get('/test2.d.ts', 'a'),
|
||||||
|
importAs: symbolCache.get('/test3.d.ts', 'b')
|
||||||
|
}]);
|
||||||
|
symbolResolver.getSymbolsOf('/test.ts');
|
||||||
|
|
||||||
|
expect(symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'a', ['someMember'])))
|
||||||
|
.toBe(symbolCache.get('/test3.d.ts', 'b', ['someMember']));
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
it('should replace references by StaticSymbols', () => {
|
it('should replace references by StaticSymbols', () => {
|
||||||
init({
|
init({
|
||||||
'/test.ts': `
|
'/test.ts': `
|
||||||
|
@ -180,6 +248,42 @@ describe('StaticSymbolResolver', () => {
|
||||||
.toBeFalsy();
|
.toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should fill references to ambient symbols with undefined', () => {
|
||||||
|
init({
|
||||||
|
'/test.ts': `
|
||||||
|
export var y = 1;
|
||||||
|
export var z = [window, z];
|
||||||
|
`
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'z')).metadata).toEqual([
|
||||||
|
undefined, symbolCache.get('/test.ts', 'z')
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow to use symbols with __', () => {
|
||||||
|
init({
|
||||||
|
'/test.ts': `
|
||||||
|
export {__a__ as __b__} from './test2';
|
||||||
|
import {__c__} from './test2';
|
||||||
|
|
||||||
|
export var __x__ = 1;
|
||||||
|
export var __y__ = __c__;
|
||||||
|
`
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', '__x__')).metadata).toBe(1);
|
||||||
|
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', '__y__')).metadata)
|
||||||
|
.toBe(symbolCache.get('/test2.d.ts', '__c__'));
|
||||||
|
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', '__b__')).metadata)
|
||||||
|
.toBe(symbolCache.get('/test2.d.ts', '__a__'));
|
||||||
|
|
||||||
|
expect(symbolResolver.getSymbolsOf('/test.ts')).toEqual([
|
||||||
|
symbolCache.get('/test.ts', '__x__'), symbolCache.get('/test.ts', '__y__'),
|
||||||
|
symbolCache.get('/test.ts', '__b__')
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('should be able to trace a named export', () => {
|
it('should be able to trace a named export', () => {
|
||||||
const symbol = symbolResolver
|
const symbol = symbolResolver
|
||||||
.resolveSymbol(symbolResolver.getSymbolByModule(
|
.resolveSymbol(symbolResolver.getSymbolByModule(
|
||||||
|
@ -240,7 +344,10 @@ describe('StaticSymbolResolver', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
export class MockSummaryResolver implements SummaryResolver<StaticSymbol> {
|
export class MockSummaryResolver implements SummaryResolver<StaticSymbol> {
|
||||||
constructor(private summaries: Summary<StaticSymbol>[] = []) {}
|
constructor(private summaries: Summary<StaticSymbol>[] = [], private importAs: {
|
||||||
|
symbol: StaticSymbol,
|
||||||
|
importAs: StaticSymbol
|
||||||
|
}[] = []) {}
|
||||||
|
|
||||||
resolveSummary(reference: StaticSymbol): Summary<StaticSymbol> {
|
resolveSummary(reference: StaticSymbol): Summary<StaticSymbol> {
|
||||||
return this.summaries.find(summary => summary.symbol === reference);
|
return this.summaries.find(summary => summary.symbol === reference);
|
||||||
|
@ -249,6 +356,13 @@ export class MockSummaryResolver implements SummaryResolver<StaticSymbol> {
|
||||||
return this.summaries.filter(summary => summary.symbol.filePath === filePath)
|
return this.summaries.filter(summary => summary.symbol.filePath === filePath)
|
||||||
.map(summary => summary.symbol);
|
.map(summary => summary.symbol);
|
||||||
}
|
}
|
||||||
|
getImportAs(symbol: StaticSymbol): StaticSymbol {
|
||||||
|
const entry = this.importAs.find(entry => entry.symbol === symbol);
|
||||||
|
return entry ? entry.importAs : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
isLibraryFile(filePath: string): boolean { return filePath.endsWith('.d.ts'); }
|
||||||
|
getLibraryFileName(filePath: string): string { return filePath.replace(/(\.d)?\.ts$/, '.d.ts'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MockStaticSymbolResolverHost implements StaticSymbolResolverHost {
|
export class MockStaticSymbolResolverHost implements StaticSymbolResolverHost {
|
||||||
|
|
|
@ -7,12 +7,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AotSummaryResolver, AotSummaryResolverHost, CompileSummaryKind, CompileTypeSummary, ResolvedStaticSymbol, StaticSymbol, StaticSymbolCache, StaticSymbolResolver} from '@angular/compiler';
|
import {AotSummaryResolver, AotSummaryResolverHost, CompileSummaryKind, CompileTypeSummary, ResolvedStaticSymbol, StaticSymbol, StaticSymbolCache, StaticSymbolResolver} from '@angular/compiler';
|
||||||
import {AotSummarySerializerHost, deserializeSummaries, serializeSummaries} from '@angular/compiler/src/aot/summary_serializer';
|
import {deserializeSummaries, serializeSummaries} from '@angular/compiler/src/aot/summary_serializer';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
import {MockStaticSymbolResolverHost, MockSummaryResolver} from './static_symbol_resolver_spec';
|
import {MockStaticSymbolResolverHost, MockSummaryResolver} from './static_symbol_resolver_spec';
|
||||||
|
|
||||||
const EXT = /\.ts$|.d.ts$/;
|
const EXT = /(\.d)?\.ts$/;
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('AotSummaryResolver', () => {
|
describe('AotSummaryResolver', () => {
|
||||||
|
@ -32,8 +32,7 @@ export function main() {
|
||||||
const mockSummaryResolver = new MockSummaryResolver([]);
|
const mockSummaryResolver = new MockSummaryResolver([]);
|
||||||
const symbolResolver = new StaticSymbolResolver(
|
const symbolResolver = new StaticSymbolResolver(
|
||||||
new MockStaticSymbolResolverHost({}), symbolCache, mockSummaryResolver);
|
new MockStaticSymbolResolverHost({}), symbolCache, mockSummaryResolver);
|
||||||
return serializeSummaries(
|
return serializeSummaries(mockSummaryResolver, symbolResolver, symbols, types).json;
|
||||||
new MockAotSummarySerializerHost(), mockSummaryResolver, symbolResolver, symbols, types);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should load serialized summary files', () => {
|
it('should load serialized summary files', () => {
|
||||||
|
@ -56,17 +55,48 @@ export function main() {
|
||||||
expect(summaryResolver.resolveSummary(asymbol)).toBe(summaryResolver.resolveSummary(asymbol));
|
expect(summaryResolver.resolveSummary(asymbol)).toBe(summaryResolver.resolveSummary(asymbol));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return all sumbols in a summary', () => {
|
it('should return all symbols in a summary', () => {
|
||||||
const asymbol = symbolCache.get('/a.d.ts', 'a');
|
const asymbol = symbolCache.get('/a.d.ts', 'a');
|
||||||
init({'/a.ngsummary.json': serialize([{symbol: asymbol, metadata: 1}], [])});
|
init({'/a.ngsummary.json': serialize([{symbol: asymbol, metadata: 1}], [])});
|
||||||
expect(summaryResolver.getSymbolsOf('/a.d.ts')).toEqual([asymbol]);
|
expect(summaryResolver.getSymbolsOf('/a.d.ts')).toEqual([asymbol]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fill importAs for deep symbols', () => {
|
||||||
|
const libSymbol = symbolCache.get('/lib.d.ts', 'Lib');
|
||||||
|
const srcSymbol = symbolCache.get('/src.ts', 'Src');
|
||||||
|
init({
|
||||||
|
'/src.ngsummary.json':
|
||||||
|
serialize([{symbol: srcSymbol, metadata: 1}, {symbol: libSymbol, metadata: 2}], [])
|
||||||
|
});
|
||||||
|
summaryResolver.getSymbolsOf('/src.d.ts');
|
||||||
|
|
||||||
|
expect(summaryResolver.getImportAs(symbolCache.get('/src.d.ts', 'Src'))).toBeFalsy();
|
||||||
|
expect(summaryResolver.getImportAs(libSymbol))
|
||||||
|
.toBe(symbolCache.get('/src.ngfactory.ts', 'Lib_1'));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isLibraryFile', () => {
|
||||||
|
it('should use host.isSourceFile to calculate the result', () => {
|
||||||
|
init();
|
||||||
|
expect(summaryResolver.isLibraryFile('someFile.ts')).toBe(false);
|
||||||
|
expect(summaryResolver.isLibraryFile('someFile.d.ts')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should calculate the result for generated files based on the result for non generated files',
|
||||||
|
() => {
|
||||||
|
init();
|
||||||
|
spyOn(host, 'isSourceFile').and.callThrough();
|
||||||
|
expect(summaryResolver.isLibraryFile('someFile.ngfactory.ts')).toBe(false);
|
||||||
|
expect(host.isSourceFile).toHaveBeenCalledWith('someFile.ts');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class MockAotSummarySerializerHost implements AotSummarySerializerHost {
|
export class MockAotSummaryResolverHost implements AotSummaryResolverHost {
|
||||||
|
constructor(private summaries: {[fileName: string]: string}) {}
|
||||||
|
|
||||||
fileNameToModuleName(fileName: string): string {
|
fileNameToModuleName(fileName: string): string {
|
||||||
return './' + path.basename(fileName).replace(EXT, '');
|
return './' + path.basename(fileName).replace(EXT, '');
|
||||||
}
|
}
|
||||||
|
@ -76,11 +106,6 @@ export class MockAotSummarySerializerHost implements AotSummarySerializerHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
isSourceFile(filePath: string) { return !filePath.endsWith('.d.ts'); }
|
isSourceFile(filePath: string) { return !filePath.endsWith('.d.ts'); }
|
||||||
}
|
|
||||||
|
|
||||||
export class MockAotSummaryResolverHost extends MockAotSummarySerializerHost implements
|
|
||||||
AotSummaryResolverHost {
|
|
||||||
constructor(private summaries: {[fileName: string]: string}) { super(); }
|
|
||||||
|
|
||||||
loadSummary(filePath: string): string { return this.summaries[filePath]; }
|
loadSummary(filePath: string): string { return this.summaries[filePath]; }
|
||||||
}
|
}
|
|
@ -7,7 +7,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AotSummaryResolver, AotSummaryResolverHost, CompileSummaryKind, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, StaticSymbolResolverHost} from '@angular/compiler';
|
import {AotSummaryResolver, AotSummaryResolverHost, CompileSummaryKind, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, StaticSymbolResolverHost} from '@angular/compiler';
|
||||||
import {AotSummarySerializerHost, deserializeSummaries, serializeSummaries, summaryFileName} from '@angular/compiler/src/aot/summary_serializer';
|
import {deserializeSummaries, serializeSummaries} from '@angular/compiler/src/aot/summary_serializer';
|
||||||
|
import {summaryFileName} from '@angular/compiler/src/aot/util';
|
||||||
|
|
||||||
import {MockStaticSymbolResolverHost} from './static_symbol_resolver_spec';
|
import {MockStaticSymbolResolverHost} from './static_symbol_resolver_spec';
|
||||||
import {MockAotSummaryResolverHost} from './summary_resolver_spec';
|
import {MockAotSummaryResolverHost} from './summary_resolver_spec';
|
||||||
|
@ -42,7 +43,7 @@ export function main() {
|
||||||
it('should serialize various data correctly', () => {
|
it('should serialize various data correctly', () => {
|
||||||
init();
|
init();
|
||||||
const serializedData = serializeSummaries(
|
const serializedData = serializeSummaries(
|
||||||
host, summaryResolver, symbolResolver,
|
summaryResolver, symbolResolver,
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
symbol: symbolCache.get('/tmp/some_values.ts', 'Values'),
|
symbol: symbolCache.get('/tmp/some_values.ts', 'Values'),
|
||||||
|
@ -50,7 +51,9 @@ export function main() {
|
||||||
aNumber: 1,
|
aNumber: 1,
|
||||||
aString: 'hello',
|
aString: 'hello',
|
||||||
anArray: [1, 2],
|
anArray: [1, 2],
|
||||||
aStaticSymbol: symbolCache.get('/tmp/some_symbol.ts', 'someName')
|
aStaticSymbol: symbolCache.get('/tmp/some_symbol.ts', 'someName'),
|
||||||
|
aStaticSymbolWithMembers:
|
||||||
|
symbolCache.get('/tmp/some_symbol.ts', 'someName', ['someMember']),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -66,11 +69,11 @@ export function main() {
|
||||||
summaryKind: CompileSummaryKind.Injectable,
|
summaryKind: CompileSummaryKind.Injectable,
|
||||||
type: {
|
type: {
|
||||||
reference: symbolCache.get('/tmp/some_service.ts', 'SomeService'),
|
reference: symbolCache.get('/tmp/some_service.ts', 'SomeService'),
|
||||||
},
|
}
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
|
||||||
const summaries = deserializeSummaries(symbolCache, serializedData);
|
const summaries = deserializeSummaries(symbolCache, serializedData.json).summaries;
|
||||||
expect(summaries.length).toBe(2);
|
expect(summaries.length).toBe(2);
|
||||||
|
|
||||||
// Note: change from .ts to .d.ts is expected
|
// Note: change from .ts to .d.ts is expected
|
||||||
|
@ -79,7 +82,9 @@ export function main() {
|
||||||
aNumber: 1,
|
aNumber: 1,
|
||||||
aString: 'hello',
|
aString: 'hello',
|
||||||
anArray: [1, 2],
|
anArray: [1, 2],
|
||||||
aStaticSymbol: symbolCache.get('/tmp/some_symbol.d.ts', 'someName')
|
aStaticSymbol: symbolCache.get('/tmp/some_symbol.d.ts', 'someName'),
|
||||||
|
aStaticSymbolWithMembers:
|
||||||
|
symbolCache.get('/tmp/some_symbol.d.ts', 'someName', ['someMember'])
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(summaries[1].symbol).toBe(symbolCache.get('/tmp/some_service.d.ts', 'SomeService'));
|
expect(summaries[1].symbol).toBe(symbolCache.get('/tmp/some_service.d.ts', 'SomeService'));
|
||||||
|
@ -91,8 +96,8 @@ export function main() {
|
||||||
|
|
||||||
it('should automatically add exported directives / pipes of NgModules that are not source files',
|
it('should automatically add exported directives / pipes of NgModules that are not source files',
|
||||||
() => {
|
() => {
|
||||||
init({});
|
init();
|
||||||
const externalSerialized = serializeSummaries(host, summaryResolver, symbolResolver, [], [
|
const externalSerialized = serializeSummaries(summaryResolver, symbolResolver, [], [
|
||||||
<any>{
|
<any>{
|
||||||
summaryKind: CompileSummaryKind.Pipe,
|
summaryKind: CompileSummaryKind.Pipe,
|
||||||
type: {
|
type: {
|
||||||
|
@ -107,11 +112,11 @@ export function main() {
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
init({
|
init({
|
||||||
'/tmp/external.ngsummary.json': externalSerialized,
|
'/tmp/external.ngsummary.json': externalSerialized.json,
|
||||||
});
|
});
|
||||||
|
|
||||||
const serialized = serializeSummaries(
|
const serialized = serializeSummaries(
|
||||||
host, summaryResolver, symbolResolver, [], [<any>{
|
summaryResolver, symbolResolver, [], [<any>{
|
||||||
summaryKind: CompileSummaryKind.NgModule,
|
summaryKind: CompileSummaryKind.NgModule,
|
||||||
type: {reference: symbolCache.get('/tmp/some_module.ts', 'SomeModule')},
|
type: {reference: symbolCache.get('/tmp/some_module.ts', 'SomeModule')},
|
||||||
exportedPipes: [
|
exportedPipes: [
|
||||||
|
@ -124,7 +129,7 @@ export function main() {
|
||||||
]
|
]
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
const summaries = deserializeSummaries(symbolCache, serialized);
|
const summaries = deserializeSummaries(symbolCache, serialized.json).summaries;
|
||||||
expect(summaries.length).toBe(3);
|
expect(summaries.length).toBe(3);
|
||||||
expect(summaries[0].symbol).toBe(symbolCache.get('/tmp/some_module.d.ts', 'SomeModule'));
|
expect(summaries[0].symbol).toBe(symbolCache.get('/tmp/some_module.d.ts', 'SomeModule'));
|
||||||
expect(summaries[1].symbol).toBe(symbolCache.get('/tmp/external.d.ts', 'SomeExternalDir'));
|
expect(summaries[1].symbol).toBe(symbolCache.get('/tmp/external.d.ts', 'SomeExternalDir'));
|
||||||
|
@ -134,8 +139,9 @@ export function main() {
|
||||||
|
|
||||||
it('should automatically add the metadata of referenced symbols that are not in the soure files',
|
it('should automatically add the metadata of referenced symbols that are not in the soure files',
|
||||||
() => {
|
() => {
|
||||||
|
init();
|
||||||
const externalSerialized = serializeSummaries(
|
const externalSerialized = serializeSummaries(
|
||||||
host, summaryResolver, symbolResolver,
|
summaryResolver, symbolResolver,
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
symbol: symbolCache.get('/tmp/external.ts', 'PROVIDERS'),
|
symbol: symbolCache.get('/tmp/external.ts', 'PROVIDERS'),
|
||||||
|
@ -154,7 +160,7 @@ export function main() {
|
||||||
}]);
|
}]);
|
||||||
init(
|
init(
|
||||||
{
|
{
|
||||||
'/tmp/external.ngsummary.json': externalSerialized,
|
'/tmp/external.ngsummary.json': externalSerialized.json,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'/tmp/local.ts': `
|
'/tmp/local.ts': `
|
||||||
|
@ -164,7 +170,7 @@ export function main() {
|
||||||
{__symbolic: 'module', version: 3, metadata: {'external': 'b'}}
|
{__symbolic: 'module', version: 3, metadata: {'external': 'b'}}
|
||||||
});
|
});
|
||||||
const serialized = serializeSummaries(
|
const serialized = serializeSummaries(
|
||||||
host, summaryResolver, symbolResolver, [{
|
summaryResolver, symbolResolver, [{
|
||||||
symbol: symbolCache.get('/tmp/test.ts', 'main'),
|
symbol: symbolCache.get('/tmp/test.ts', 'main'),
|
||||||
metadata: {
|
metadata: {
|
||||||
local: symbolCache.get('/tmp/local.ts', 'local'),
|
local: symbolCache.get('/tmp/local.ts', 'local'),
|
||||||
|
@ -174,7 +180,7 @@ export function main() {
|
||||||
}],
|
}],
|
||||||
[]);
|
[]);
|
||||||
|
|
||||||
const summaries = deserializeSummaries(symbolCache, serialized);
|
const summaries = deserializeSummaries(symbolCache, serialized.json).summaries;
|
||||||
// Note: local should not show up!
|
// Note: local should not show up!
|
||||||
expect(summaries.length).toBe(4);
|
expect(summaries.length).toBe(4);
|
||||||
expect(summaries[0].symbol).toBe(symbolCache.get('/tmp/test.d.ts', 'main'));
|
expect(summaries[0].symbol).toBe(symbolCache.get('/tmp/test.d.ts', 'main'));
|
||||||
|
@ -195,5 +201,28 @@ export function main() {
|
||||||
expect(summaries[3].type.type.reference)
|
expect(summaries[3].type.type.reference)
|
||||||
.toBe(symbolCache.get('/tmp/external_svc.d.ts', 'SomeService'));
|
.toBe(symbolCache.get('/tmp/external_svc.d.ts', 'SomeService'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create "importAs" names for non source symbols', () => {
|
||||||
|
init();
|
||||||
|
const serialized = serializeSummaries(
|
||||||
|
summaryResolver, symbolResolver, [{
|
||||||
|
symbol: symbolCache.get('/tmp/test.ts', 'main'),
|
||||||
|
metadata: [
|
||||||
|
symbolCache.get('/tmp/external.d.ts', 'lib'),
|
||||||
|
symbolCache.get('/tmp/external.d.ts', 'lib', ['someMember']),
|
||||||
|
]
|
||||||
|
}],
|
||||||
|
[]);
|
||||||
|
// Note: no entry for the symbol with members!
|
||||||
|
expect(serialized.exportAs).toEqual([
|
||||||
|
{symbol: symbolCache.get('/tmp/external.d.ts', 'lib'), exportAs: 'lib_1'}
|
||||||
|
]);
|
||||||
|
|
||||||
|
const deserialized = deserializeSummaries(symbolCache, serialized.json);
|
||||||
|
// Note: no entry for the symbol with members!
|
||||||
|
expect(deserialized.importAs).toEqual([
|
||||||
|
{symbol: symbolCache.get('/tmp/external.d.ts', 'lib'), importAs: 'lib_1'}
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol';
|
||||||
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
|
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
|
||||||
import {JavaScriptEmitter} from '@angular/compiler/src/output/js_emitter';
|
import {JavaScriptEmitter} from '@angular/compiler/src/output/js_emitter';
|
||||||
import * as o from '@angular/compiler/src/output/output_ast';
|
import * as o from '@angular/compiler/src/output/output_ast';
|
||||||
|
@ -15,16 +16,17 @@ const someModuleUrl = 'somePackage/somePath';
|
||||||
const anotherModuleUrl = 'somePackage/someOtherPath';
|
const anotherModuleUrl = 'somePackage/someOtherPath';
|
||||||
|
|
||||||
const sameModuleIdentifier: CompileIdentifierMetadata = {
|
const sameModuleIdentifier: CompileIdentifierMetadata = {
|
||||||
reference: {name: 'someLocalId', filePath: someModuleUrl}
|
reference: new StaticSymbol(someModuleUrl, 'someLocalId', [])
|
||||||
};
|
};
|
||||||
const externalModuleIdentifier: CompileIdentifierMetadata = {
|
const externalModuleIdentifier: CompileIdentifierMetadata = {
|
||||||
reference: {name: 'someExternalId', filePath: anotherModuleUrl}
|
reference: new StaticSymbol(anotherModuleUrl, 'someExternalId', [])
|
||||||
};
|
};
|
||||||
|
|
||||||
class SimpleJsImportGenerator implements ImportResolver {
|
class SimpleJsImportGenerator implements ImportResolver {
|
||||||
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
|
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
|
||||||
return importedUrlStr;
|
return importedUrlStr;
|
||||||
}
|
}
|
||||||
|
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
|
@ -33,11 +35,13 @@ export function main() {
|
||||||
// - declaring fields
|
// - declaring fields
|
||||||
|
|
||||||
describe('JavaScriptEmitter', () => {
|
describe('JavaScriptEmitter', () => {
|
||||||
|
let importResolver: ImportResolver;
|
||||||
let emitter: JavaScriptEmitter;
|
let emitter: JavaScriptEmitter;
|
||||||
let someVar: o.ReadVarExpr;
|
let someVar: o.ReadVarExpr;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
emitter = new JavaScriptEmitter(new SimpleJsImportGenerator());
|
importResolver = new SimpleJsImportGenerator();
|
||||||
|
emitter = new JavaScriptEmitter(importResolver);
|
||||||
someVar = o.variable('someVar');
|
someVar = o.variable('someVar');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -124,6 +128,16 @@ export function main() {
|
||||||
].join('\n'));
|
].join('\n'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support `importAs` for external identifiers', () => {
|
||||||
|
spyOn(importResolver, 'getImportAs')
|
||||||
|
.and.returnValue(new StaticSymbol('somePackage/importAsModule', 'importAsName', []));
|
||||||
|
expect(emitStmt(o.importExpr(externalModuleIdentifier).toStmt())).toEqual([
|
||||||
|
`var import0 = re` +
|
||||||
|
`quire('somePackage/importAsModule');`,
|
||||||
|
`import0.importAsName;`
|
||||||
|
].join('\n'));
|
||||||
|
});
|
||||||
|
|
||||||
it('should support operators', () => {
|
it('should support operators', () => {
|
||||||
const lhs = o.variable('lhs');
|
const lhs = o.variable('lhs');
|
||||||
const rhs = o.variable('rhs');
|
const rhs = o.variable('rhs');
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol';
|
||||||
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
|
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
|
||||||
import {assetUrl, createIdentifier} from '@angular/compiler/src/identifiers';
|
import {assetUrl, createIdentifier} from '@angular/compiler/src/identifiers';
|
||||||
import * as o from '@angular/compiler/src/output/output_ast';
|
import * as o from '@angular/compiler/src/output/output_ast';
|
||||||
|
@ -262,4 +263,5 @@ export class SimpleJsImportGenerator implements ImportResolver {
|
||||||
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
|
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
|
||||||
return importedUrlStr;
|
return importedUrlStr;
|
||||||
}
|
}
|
||||||
|
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,4 +74,5 @@ class StubReflectorHost implements StaticSymbolResolverHost {
|
||||||
|
|
||||||
class StubImportResolver extends ImportResolver {
|
class StubImportResolver extends ImportResolver {
|
||||||
fileNameToModuleName(importedFilePath: string, containingFilePath: string): string { return ''; }
|
fileNameToModuleName(importedFilePath: string, containingFilePath: string): string { return ''; }
|
||||||
|
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol';
|
||||||
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
|
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
|
||||||
import * as o from '@angular/compiler/src/output/output_ast';
|
import * as o from '@angular/compiler/src/output/output_ast';
|
||||||
import {ImportResolver} from '@angular/compiler/src/output/path_util';
|
import {ImportResolver} from '@angular/compiler/src/output/path_util';
|
||||||
|
@ -15,38 +16,42 @@ const someModuleUrl = 'somePackage/somePath';
|
||||||
const anotherModuleUrl = 'somePackage/someOtherPath';
|
const anotherModuleUrl = 'somePackage/someOtherPath';
|
||||||
|
|
||||||
const sameModuleIdentifier: CompileIdentifierMetadata = {
|
const sameModuleIdentifier: CompileIdentifierMetadata = {
|
||||||
reference: {name: 'someLocalId', filePath: someModuleUrl}
|
reference: new StaticSymbol(someModuleUrl, 'someLocalId', [])
|
||||||
};
|
};
|
||||||
|
|
||||||
const externalModuleIdentifier: CompileIdentifierMetadata = {
|
const externalModuleIdentifier: CompileIdentifierMetadata = {
|
||||||
reference: {name: 'someExternalId', filePath: anotherModuleUrl}
|
reference: new StaticSymbol(anotherModuleUrl, 'someExternalId', [])
|
||||||
};
|
};
|
||||||
|
|
||||||
class SimpleJsImportGenerator implements ImportResolver {
|
class SimpleJsImportGenerator implements ImportResolver {
|
||||||
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
|
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
|
||||||
return importedUrlStr;
|
return importedUrlStr;
|
||||||
}
|
}
|
||||||
|
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
// Note supported features of our OutputAsti n TS:
|
// Not supported features of our OutputAst in TS:
|
||||||
// - real `const` like in Dart
|
// - real `const` like in Dart
|
||||||
// - final fields
|
// - final fields
|
||||||
|
|
||||||
describe('TypeScriptEmitter', () => {
|
describe('TypeScriptEmitter', () => {
|
||||||
|
let importResolver: ImportResolver;
|
||||||
let emitter: TypeScriptEmitter;
|
let emitter: TypeScriptEmitter;
|
||||||
let someVar: o.ReadVarExpr;
|
let someVar: o.ReadVarExpr;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
emitter = new TypeScriptEmitter(new SimpleJsImportGenerator());
|
importResolver = new SimpleJsImportGenerator();
|
||||||
|
emitter = new TypeScriptEmitter(importResolver);
|
||||||
someVar = o.variable('someVar');
|
someVar = o.variable('someVar');
|
||||||
});
|
});
|
||||||
|
|
||||||
function emitStmt(stmt: o.Statement, exportedVars: string[] = null): string {
|
function emitStmt(stmt: o.Statement | o.Statement[], exportedVars: string[] = null): string {
|
||||||
if (!exportedVars) {
|
if (!exportedVars) {
|
||||||
exportedVars = [];
|
exportedVars = [];
|
||||||
}
|
}
|
||||||
return emitter.emitStatements(someModuleUrl, [stmt], exportedVars);
|
const stmts = Array.isArray(stmt) ? stmt : [stmt];
|
||||||
|
return emitter.emitStatements(someModuleUrl, stmts, exportedVars);
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should declare variables', () => {
|
it('should declare variables', () => {
|
||||||
|
@ -59,6 +64,79 @@ export function main() {
|
||||||
.toEqual(`var someVar:number = 1;`);
|
.toEqual(`var someVar:number = 1;`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('declare variables with ExternExpressions as values', () => {
|
||||||
|
it('should create no reexport if the identifier is in the same module', () => {
|
||||||
|
// identifier is in the same module -> no reexport
|
||||||
|
expect(emitStmt(someVar.set(o.importExpr(sameModuleIdentifier)).toDeclStmt(), ['someVar']))
|
||||||
|
.toEqual('export var someVar:any = someLocalId;');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create no reexport if the variable is not exported', () => {
|
||||||
|
expect(emitStmt(someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt())).toEqual([
|
||||||
|
`import * as import0 from 'somePackage/someOtherPath';`,
|
||||||
|
`var someVar:any = import0.someExternalId;`
|
||||||
|
].join('\n'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create no reexport if the variable is typed', () => {
|
||||||
|
expect(emitStmt(
|
||||||
|
someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(o.DYNAMIC_TYPE),
|
||||||
|
['someVar']))
|
||||||
|
.toEqual([
|
||||||
|
`import * as import0 from 'somePackage/someOtherPath';`,
|
||||||
|
`export var someVar:any = import0.someExternalId;`
|
||||||
|
].join('\n'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create no reexport if the identifier has members', () => {
|
||||||
|
const externalModuleIdentifierWithMembers: CompileIdentifierMetadata = {
|
||||||
|
reference: new StaticSymbol(anotherModuleUrl, 'someExternalId', ['a'])
|
||||||
|
};
|
||||||
|
expect(emitStmt(
|
||||||
|
someVar.set(o.importExpr(externalModuleIdentifierWithMembers)).toDeclStmt(),
|
||||||
|
['someVar']))
|
||||||
|
.toEqual([
|
||||||
|
`import * as import0 from 'somePackage/someOtherPath';`,
|
||||||
|
`export var someVar:any = import0.someExternalId.a;`
|
||||||
|
].join('\n'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a reexport', () => {
|
||||||
|
expect(
|
||||||
|
emitStmt(someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(), ['someVar']))
|
||||||
|
.toEqual([
|
||||||
|
`export {someExternalId as someVar} from 'somePackage/someOtherPath';`, ``
|
||||||
|
].join('\n'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create multiple reexports from the same file', () => {
|
||||||
|
const someVar2 = o.variable('someVar2');
|
||||||
|
const externalModuleIdentifier2: CompileIdentifierMetadata = {
|
||||||
|
reference: new StaticSymbol(anotherModuleUrl, 'someExternalId2', [])
|
||||||
|
};
|
||||||
|
expect(emitStmt(
|
||||||
|
[
|
||||||
|
someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(),
|
||||||
|
someVar2.set(o.importExpr(externalModuleIdentifier2)).toDeclStmt()
|
||||||
|
],
|
||||||
|
['someVar', 'someVar2']))
|
||||||
|
.toEqual([
|
||||||
|
`export {someExternalId as someVar,someExternalId2 as someVar2} from 'somePackage/someOtherPath';`,
|
||||||
|
``
|
||||||
|
].join('\n'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use `importAs` for reexports', () => {
|
||||||
|
spyOn(importResolver, 'getImportAs')
|
||||||
|
.and.returnValue(new StaticSymbol('somePackage/importAsModule', 'importAsName', []));
|
||||||
|
expect(
|
||||||
|
emitStmt(someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(), ['someVar']))
|
||||||
|
.toEqual([
|
||||||
|
`export {importAsName as someVar} from 'somePackage/importAsModule';`, ``
|
||||||
|
].join('\n'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should read and write variables', () => {
|
it('should read and write variables', () => {
|
||||||
expect(emitStmt(someVar.toStmt())).toEqual(`someVar;`);
|
expect(emitStmt(someVar.toStmt())).toEqual(`someVar;`);
|
||||||
expect(emitStmt(someVar.set(o.literal(1)).toStmt())).toEqual(`someVar = 1;`);
|
expect(emitStmt(someVar.set(o.literal(1)).toStmt())).toEqual(`someVar = 1;`);
|
||||||
|
@ -134,6 +212,14 @@ export function main() {
|
||||||
].join('\n'));
|
].join('\n'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support `importAs` for external identifiers', () => {
|
||||||
|
spyOn(importResolver, 'getImportAs')
|
||||||
|
.and.returnValue(new StaticSymbol('somePackage/importAsModule', 'importAsName', []));
|
||||||
|
expect(emitStmt(o.importExpr(externalModuleIdentifier).toStmt())).toEqual([
|
||||||
|
`import * as import0 from 'somePackage/importAsModule';`, `import0.importAsName;`
|
||||||
|
].join('\n'));
|
||||||
|
});
|
||||||
|
|
||||||
it('should support operators', () => {
|
it('should support operators', () => {
|
||||||
const lhs = o.variable('lhs');
|
const lhs = o.variable('lhs');
|
||||||
const rhs = o.variable('rhs');
|
const rhs = o.variable('rhs');
|
||||||
|
@ -332,6 +418,16 @@ export function main() {
|
||||||
].join('\n'));
|
].join('\n'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support `importAs` for external types', () => {
|
||||||
|
spyOn(importResolver, 'getImportAs')
|
||||||
|
.and.returnValue(new StaticSymbol('somePackage/importAsModule', 'importAsName', []));
|
||||||
|
const writeVarExpr = o.variable('a').set(o.NULL_EXPR);
|
||||||
|
expect(emitStmt(writeVarExpr.toDeclStmt(o.importType(externalModuleIdentifier)))).toEqual([
|
||||||
|
`import * as import0 from 'somePackage/importAsModule';`,
|
||||||
|
`var a:import0.importAsName = (null as any);`
|
||||||
|
].join('\n'));
|
||||||
|
});
|
||||||
|
|
||||||
it('should support expression types', () => {
|
it('should support expression types', () => {
|
||||||
expect(emitStmt(o.variable('a')
|
expect(emitStmt(o.variable('a')
|
||||||
.set(o.NULL_EXPR)
|
.set(o.NULL_EXPR)
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Injectable} from './metadata';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a token that can be used in a DI Provider.
|
* Creates a token that can be used in a DI Provider.
|
||||||
*
|
*
|
||||||
|
@ -30,7 +28,6 @@ import {Injectable} from './metadata';
|
||||||
* error messages.
|
* error messages.
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
@Injectable() // so that metadata is gathered for this class
|
|
||||||
export class OpaqueToken {
|
export class OpaqueToken {
|
||||||
constructor(private _desc: string) {}
|
constructor(private _desc: string) {}
|
||||||
|
|
||||||
|
|
|
@ -95,9 +95,12 @@ const EMPTY_CONTEXT = new Object();
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export class ComponentFactory<C> {
|
export class ComponentFactory<C> {
|
||||||
|
/** @internal */
|
||||||
|
_viewClass: Type<AppView<any>>;
|
||||||
constructor(
|
constructor(
|
||||||
public selector: string, private _viewClass: Type<AppView<any>>,
|
public selector: string, _viewClass: Type<AppView<any>>, private _componentType: Type<any>) {
|
||||||
private _componentType: Type<any>) {}
|
this._viewClass = _viewClass;
|
||||||
|
}
|
||||||
|
|
||||||
get componentType(): Type<any> { return this._componentType; }
|
get componentType(): Type<any> { return this._componentType; }
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,11 @@ import {isPresent, looseIdentical} from '../facade/lang';
|
||||||
import {ViewEncapsulation} from '../metadata/view';
|
import {ViewEncapsulation} from '../metadata/view';
|
||||||
import {RenderComponentType, RenderDebugInfo, Renderer, RootRenderer} from '../render/api';
|
import {RenderComponentType, RenderDebugInfo, Renderer, RootRenderer} from '../render/api';
|
||||||
import {Sanitizer} from '../security';
|
import {Sanitizer} from '../security';
|
||||||
|
import {Type} from '../type';
|
||||||
import {VERSION} from '../version';
|
import {VERSION} from '../version';
|
||||||
import {NgZone} from '../zone/ng_zone';
|
import {NgZone} from '../zone/ng_zone';
|
||||||
|
|
||||||
|
import {ComponentFactory} from './component_factory';
|
||||||
import {ExpressionChangedAfterItHasBeenCheckedError} from './errors';
|
import {ExpressionChangedAfterItHasBeenCheckedError} from './errors';
|
||||||
import {AppView} from './view';
|
import {AppView} from './view';
|
||||||
|
|
||||||
|
@ -652,3 +654,10 @@ export class InlineArrayDynamic<T> implements InlineArray<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EMPTY_INLINE_ARRAY: InlineArray<any> = new InlineArray0();
|
export const EMPTY_INLINE_ARRAY: InlineArray<any> = new InlineArray0();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a private API only used by the compiler to read the view class.
|
||||||
|
*/
|
||||||
|
export function getComponentFactoryViewClass(componentFactory: ComponentFactory<any>): Type<any> {
|
||||||
|
return componentFactory._viewClass;
|
||||||
|
}
|
||||||
|
|
|
@ -122,7 +122,7 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
||||||
|
|
||||||
result = this._resolver = new CompileMetadataResolver(
|
result = this._resolver = new CompileMetadataResolver(
|
||||||
moduleResolver, directiveResolver, pipeResolver, new SummaryResolver(),
|
moduleResolver, directiveResolver, pipeResolver, new SummaryResolver(),
|
||||||
elementSchemaRegistry, directiveNormalizer, this.reflector,
|
elementSchemaRegistry, directiveNormalizer, this._staticSymbolCache, this.reflector,
|
||||||
(error, type) => this.collectError(error, type && type.filePath));
|
(error, type) => this.collectError(error, type && type.filePath));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -397,7 +397,8 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
||||||
const summaryResolver = new AotSummaryResolver(
|
const summaryResolver = new AotSummaryResolver(
|
||||||
{
|
{
|
||||||
loadSummary(filePath: string) { return null; },
|
loadSummary(filePath: string) { return null; },
|
||||||
isSourceFile(sourceFilePath: string) { return true; }
|
isSourceFile(sourceFilePath: string) { return true; },
|
||||||
|
getOutputFileName(sourceFilePath: string) { return null; }
|
||||||
},
|
},
|
||||||
this._staticSymbolCache);
|
this._staticSymbolCache);
|
||||||
result = this._staticSymbolResolver = new StaticSymbolResolver(
|
result = this._staticSymbolResolver = new StaticSymbolResolver(
|
||||||
|
|
Loading…
Reference in New Issue