feat(core): introduce @AppModule

Main part for #9726
Closes #9730
This commit is contained in:
Tobias Bosch
2016-06-28 09:54:42 -07:00
parent 1608d91728
commit 17e4cfc748
52 changed files with 2085 additions and 851 deletions

View File

@ -11,15 +11,15 @@
* Intended to be used in a build step.
*/
import * as compiler from '@angular/compiler';
import {ViewEncapsulation, lockRunMode} from '@angular/core';
import {AppModuleMetadata, ComponentMetadata, ViewEncapsulation, lockRunMode} from '@angular/core';
import {AngularCompilerOptions} from '@angular/tsc-wrapped';
import * as path from 'path';
import * as ts from 'typescript';
import {CompileMetadataResolver, DirectiveNormalizer, DomElementSchemaRegistry, HtmlParser, Lexer, Parser, StyleCompiler, TemplateParser, TypeScriptEmitter, ViewCompiler} from './compiler_private';
import {AppModuleCompiler, CompileMetadataResolver, DirectiveNormalizer, DomElementSchemaRegistry, HtmlParser, Lexer, Parser, StyleCompiler, TemplateParser, TypeScriptEmitter, ViewCompiler} from './compiler_private';
import {ReflectorHost, ReflectorHostContext} from './reflector_host';
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
import {StaticReflector} from './static_reflector';
import {StaticReflector, StaticSymbol} from './static_reflector';
const GENERATED_FILES = /\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
@ -40,26 +40,9 @@ export class CodeGenerator {
lockRunMode();
}
private generateSource(metadatas: compiler.CompileDirectiveMetadata[]) {
const normalize = (metadata: compiler.CompileDirectiveMetadata) => {
const directiveType = metadata.type.runtime;
const directives = this.resolver.getViewDirectivesMetadata(directiveType);
return Promise.all(directives.map(d => this.compiler.normalizeDirectiveMetadata(d)))
.then(normalizedDirectives => {
const pipes = this.resolver.getViewPipesMetadata(directiveType);
return new compiler.NormalizedComponentWithViewDirectives(
metadata, normalizedDirectives, pipes);
});
};
return Promise.all(metadatas.map(normalize))
.then(
normalizedCompWithDirectives =>
this.compiler.compileTemplates(normalizedCompWithDirectives));
}
private readComponents(absSourcePath: string) {
const result: Promise<compiler.CompileDirectiveMetadata>[] = [];
private readFileMetadata(absSourcePath: string): FileMetadata {
const moduleMetadata = this.staticReflector.getModuleMetadata(absSourcePath);
const result: FileMetadata = {components: [], appModules: [], fileUrl: absSourcePath};
if (!moduleMetadata) {
console.log(`WARNING: no metadata found for ${absSourcePath}`);
return result;
@ -75,13 +58,14 @@ export class CodeGenerator {
continue;
}
const staticType = this.reflectorHost.findDeclaration(absSourcePath, symbol, absSourcePath);
let directive: compiler.CompileDirectiveMetadata;
directive = this.resolver.maybeGetDirectiveMetadata(<any>staticType);
if (!directive || !directive.isComponent) {
continue;
}
result.push(this.compiler.normalizeDirectiveMetadata(directive));
const annotations = this.staticReflector.annotations(staticType);
annotations.forEach((annotation) => {
if (annotation instanceof AppModuleMetadata) {
result.appModules.push(staticType);
} else if (annotation instanceof ComponentMetadata) {
result.components.push(staticType);
}
});
}
return result;
}
@ -102,30 +86,31 @@ export class CodeGenerator {
}
codegen(): Promise<any> {
const generateOneFile = (absSourcePath: string) =>
Promise.all(this.readComponents(absSourcePath))
.then((metadatas: compiler.CompileDirectiveMetadata[]) => {
if (!metadatas || !metadatas.length) {
return;
}
return this.generateSource(metadatas);
})
.then(generatedModules => {
if (generatedModules) {
generatedModules.forEach((generatedModule) => {
const sourceFile = this.program.getSourceFile(absSourcePath);
const emitPath = this.calculateEmitPath(generatedModule.moduleUrl);
this.host.writeFile(
emitPath, PREAMBLE + generatedModule.source, false, () => {}, [sourceFile]);
});
}
})
.catch((e) => { console.error(e.stack); });
var compPromises = this.program.getSourceFiles()
.map(sf => sf.fileName)
.filter(f => !GENERATED_FILES.test(f))
.map(generateOneFile);
return Promise.all(compPromises);
let filePaths =
this.program.getSourceFiles().map(sf => sf.fileName).filter(f => !GENERATED_FILES.test(f));
let fileMetas = filePaths.map((filePath) => this.readFileMetadata(filePath));
let appModules = fileMetas.reduce((appModules, fileMeta) => {
appModules.push(...fileMeta.appModules);
return appModules;
}, <StaticSymbol[]>[]);
let analyzedAppModules = this.compiler.analyzeModules(appModules);
return Promise
.all(fileMetas.map(
(fileMeta) => this.compiler
.compile(
fileMeta.fileUrl, analyzedAppModules, fileMeta.components,
fileMeta.appModules)
.then((generatedModules) => {
generatedModules.forEach((generatedModule) => {
const sourceFile = this.program.getSourceFile(fileMeta.fileUrl);
const emitPath =
this.calculateEmitPath(generatedModule.moduleUrl);
this.host.writeFile(
emitPath, PREAMBLE + generatedModule.source, false, () => {},
[sourceFile]);
});
})))
.catch((e) => { console.error(e.stack); });
}
static create(
@ -158,14 +143,20 @@ export class CodeGenerator {
const tmplParser = new TemplateParser(
parser, new DomElementSchemaRegistry(), htmlParser,
/*console*/ null, []);
const offlineCompiler = new compiler.OfflineCompiler(
normalizer, tmplParser, new StyleCompiler(urlResolver), new ViewCompiler(config),
new TypeScriptEmitter(reflectorHost));
const resolver = new CompileMetadataResolver(
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
new compiler.ViewResolver(staticReflector), config, staticReflector);
const offlineCompiler = new compiler.OfflineCompiler(
resolver, normalizer, tmplParser, new StyleCompiler(urlResolver), new ViewCompiler(config),
new AppModuleCompiler(), new TypeScriptEmitter(reflectorHost));
return new CodeGenerator(
options, program, compilerHost, staticReflector, resolver, offlineCompiler, reflectorHost);
}
}
interface FileMetadata {
fileUrl: string;
components: StaticSymbol[];
appModules: StaticSymbol[];
}

View File

@ -61,5 +61,8 @@ export var StyleCompiler: typeof _c.StyleCompiler = _c.StyleCompiler;
export type ViewCompiler = _c.ViewCompiler;
export var ViewCompiler: typeof _c.ViewCompiler = _c.ViewCompiler;
export type AppModuleCompiler = _c.AppModuleCompiler;
export var AppModuleCompiler: typeof _c.AppModuleCompiler = _c.AppModuleCompiler;
export type TypeScriptEmitter = _c.TypeScriptEmitter;
export var TypeScriptEmitter: typeof _c.TypeScriptEmitter = _c.TypeScriptEmitter;

View File

@ -22,7 +22,7 @@ import * as compiler from '@angular/compiler';
import {ViewEncapsulation, lockRunMode} from '@angular/core';
import {StaticReflector} from './static_reflector';
import {CompileMetadataResolver, HtmlParser, DirectiveNormalizer, Lexer, Parser, TemplateParser, DomElementSchemaRegistry, StyleCompiler, ViewCompiler, TypeScriptEmitter, MessageExtractor, removeDuplicates, ExtractionResult, Message, ParseError, serializeXmb,} from './compiler_private';
import {CompileMetadataResolver, HtmlParser, DirectiveNormalizer, Lexer, Parser, DomElementSchemaRegistry, TypeScriptEmitter, MessageExtractor, removeDuplicates, ExtractionResult, Message, ParseError, serializeXmb,} from './compiler_private';
import {ReflectorHost} from './reflector_host';
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
@ -40,42 +40,27 @@ class Extractor {
constructor(
private _options: tsc.AngularCompilerOptions, private _program: ts.Program,
public host: ts.CompilerHost, private staticReflector: StaticReflector,
private _resolver: CompileMetadataResolver, private _compiler: compiler.OfflineCompiler,
private _resolver: CompileMetadataResolver, private _normalizer: DirectiveNormalizer,
private _reflectorHost: ReflectorHost, private _extractor: MessageExtractor) {
lockRunMode();
}
private _extractCmpMessages(metadatas: compiler.CompileDirectiveMetadata[]):
Promise<ExtractionResult> {
if (!metadatas || !metadatas.length) {
private _extractCmpMessages(components: compiler.CompileDirectiveMetadata[]): ExtractionResult {
if (!components || !components.length) {
return null;
}
const normalize = (metadata: compiler.CompileDirectiveMetadata) => {
const directiveType = metadata.type.runtime;
const directives = this._resolver.getViewDirectivesMetadata(directiveType);
return Promise.all(directives.map(d => this._compiler.normalizeDirectiveMetadata(d)))
.then(normalizedDirectives => {
const pipes = this._resolver.getViewPipesMetadata(directiveType);
return new compiler.NormalizedComponentWithViewDirectives(
metadata, normalizedDirectives, pipes);
});
};
let messages: Message[] = [];
let errors: ParseError[] = [];
components.forEach(metadata => {
let url = _dirPaths.get(metadata);
let result = this._extractor.extract(metadata.template.template, url);
errors = errors.concat(result.errors);
messages = messages.concat(result.messages);
});
return Promise.all(metadatas.map(normalize))
.then((cmps: compiler.NormalizedComponentWithViewDirectives[]) => {
let messages: Message[] = [];
let errors: ParseError[] = [];
cmps.forEach(cmp => {
let url = _dirPaths.get(cmp.component);
let result = this._extractor.extract(cmp.component.template.template, url);
errors = errors.concat(result.errors);
messages = messages.concat(result.messages);
});
// Extraction Result might contain duplicate messages at this point
return new ExtractionResult(messages, errors);
});
// Extraction Result might contain duplicate messages at this point
return new ExtractionResult(messages, errors);
}
private _readComponents(absSourcePath: string): Promise<compiler.CompileDirectiveMetadata>[] {
@ -96,7 +81,7 @@ class Extractor {
directive = this._resolver.maybeGetDirectiveMetadata(<any>staticType);
if (directive && directive.isComponent) {
let promise = this._compiler.normalizeDirectiveMetadata(directive);
let promise = this._normalizer.normalizeDirective(directive).asyncResult;
promise.then(md => _dirPaths.set(md, absSourcePath));
result.push(promise);
}
@ -165,12 +150,6 @@ class Extractor {
});
const normalizer = new DirectiveNormalizer(xhr, urlResolver, htmlParser, config);
const parser = new Parser(new Lexer());
const tmplParser = new TemplateParser(
parser, new DomElementSchemaRegistry(), htmlParser,
/*console*/ null, []);
const offlineCompiler = new compiler.OfflineCompiler(
normalizer, tmplParser, new StyleCompiler(urlResolver), new ViewCompiler(config),
new TypeScriptEmitter(reflectorHost));
const resolver = new CompileMetadataResolver(
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
new compiler.ViewResolver(staticReflector), config, staticReflector);
@ -179,7 +158,7 @@ class Extractor {
const extractor = new MessageExtractor(htmlParser, parser, [], {});
return new Extractor(
options, program, compilerHost, staticReflector, resolver, offlineCompiler, reflectorHost,
options, program, compilerHost, staticReflector, resolver, normalizer, reflectorHost,
extractor);
}
}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AttributeMetadata, ComponentMetadata, ContentChildMetadata, ContentChildrenMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, HostMetadata, InjectMetadata, InjectableMetadata, InputMetadata, OptionalMetadata, OutputMetadata, PipeMetadata, Provider, QueryMetadata, SelfMetadata, SkipSelfMetadata, ViewChildMetadata, ViewChildrenMetadata, ViewQueryMetadata, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
import {AppModuleMetadata, AttributeMetadata, ComponentMetadata, ContentChildMetadata, ContentChildrenMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, HostMetadata, InjectMetadata, InjectableMetadata, InputMetadata, OptionalMetadata, OutputMetadata, PipeMetadata, Provider, QueryMetadata, SelfMetadata, SkipSelfMetadata, ViewChildMetadata, ViewChildrenMetadata, ViewQueryMetadata, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
import {ReflectorReader} from './core_private';
@ -216,6 +216,8 @@ export class StaticReflector implements ReflectorReader {
this.host.findDeclaration(coreDecorators, 'Directive'), DirectiveMetadata);
this.registerDecoratorOrConstructor(
this.host.findDeclaration(coreDecorators, 'Component'), ComponentMetadata);
this.registerDecoratorOrConstructor(
this.host.findDeclaration(coreDecorators, 'AppModule'), AppModuleMetadata);
// Note: Some metadata classes can be used directly with Provider.deps.
this.registerDecoratorOrConstructor(