Skip to content

Commit

Permalink
refactor(compiler): various cleanups
Browse files Browse the repository at this point in the history
- use `$implicit` variable value correctly
- handle `ng-non-bindable` correctly
- add some more assertions to `TemplateCompiler`
- make `CompiledTemplate` const
- fix default value for `@Directive.moduleId`
- add new compiler to application bindings

BREAKING CHANGE:
- `Compiler.compileInHost` and all methods of `DynamicComponentLoader` don’t take `Binding` any more, only `Type`s. This is in preparation for the new compiler which does not support this.

Part of #3605

Closes #4346
  • Loading branch information
tbosch committed Sep 24, 2015
1 parent bffa2cb commit 7470ad1
Show file tree
Hide file tree
Showing 29 changed files with 494 additions and 286 deletions.
7 changes: 4 additions & 3 deletions modules/angular2/src/compiler/command_compiler.ts
Expand Up @@ -35,7 +35,8 @@ import {escapeSingleQuoteString} from './util';
import {Injectable} from 'angular2/src/core/di';

export var TEMPLATE_COMMANDS_MODULE_REF = moduleRef('angular2/src/core/compiler/template_commands');
const IMPLICIT_VAR = '%implicit';

const IMPLICIT_TEMPLATE_VAR = '\$implicit';

@Injectable()
export class CommandCompiler {
Expand Down Expand Up @@ -207,7 +208,7 @@ class CommandBuilderVisitor<R> implements TemplateAstVisitor {
var variableNameAndValues = [];
ast.vars.forEach((varAst) => {
variableNameAndValues.push(varAst.name);
variableNameAndValues.push(varAst.value);
variableNameAndValues.push(varAst.value.length > 0 ? varAst.value : IMPLICIT_TEMPLATE_VAR);
});
var directives = [];
ListWrapper.forEachWithIndex(ast.directives, (directiveAst: DirectiveAst, index: number) => {
Expand All @@ -227,7 +228,7 @@ class CommandBuilderVisitor<R> implements TemplateAstVisitor {
if (isBlank(component)) {
ast.exportAsVars.forEach((varAst) => {
variableNameAndValues.push(varAst.name);
variableNameAndValues.push(IMPLICIT_VAR);
variableNameAndValues.push(null);
});
}
var directives = [];
Expand Down
28 changes: 28 additions & 0 deletions modules/angular2/src/compiler/compiler.ts
Expand Up @@ -5,3 +5,31 @@ export {
CompileTemplateMetadata
} from './directive_metadata';
export {SourceModule, SourceWithImports} from './source_module';

import {assertionsEnabled, Type} from 'angular2/src/core/facade/lang';
import {bind, Binding} from 'angular2/src/core/di';
import {TemplateParser} from 'angular2/src/compiler/template_parser';
import {HtmlParser} from 'angular2/src/compiler/html_parser';
import {TemplateNormalizer} from 'angular2/src/compiler/template_normalizer';
import {RuntimeMetadataResolver} from 'angular2/src/compiler/runtime_metadata';
import {ChangeDetectionCompiler} from 'angular2/src/compiler/change_detector_compiler';
import {StyleCompiler} from 'angular2/src/compiler/style_compiler';
import {CommandCompiler} from 'angular2/src/compiler/command_compiler';
import {TemplateCompiler} from 'angular2/src/compiler/template_compiler';
import {ChangeDetectorGenConfig} from 'angular2/src/core/change_detection/change_detection';

export function compilerBindings(): Array<Type | Binding | any[]> {
return [
HtmlParser,
TemplateParser,
TemplateNormalizer,
RuntimeMetadataResolver,
StyleCompiler,
CommandCompiler,
ChangeDetectionCompiler,
bind(ChangeDetectorGenConfig)
.toValue(
new ChangeDetectorGenConfig(assertionsEnabled(), assertionsEnabled(), false, true)),
TemplateCompiler,
];
}
17 changes: 1 addition & 16 deletions modules/angular2/src/compiler/html_parser.ts
Expand Up @@ -57,12 +57,7 @@ function parseElement(element: Element, indexInParent: number, parentSourceInfo:
var sourceInfo = `${parentSourceInfo} > ${nodeName}:nth-child(${indexInParent})`;
var attrs = parseAttrs(element, sourceInfo);

var childNodes;
if (ignoreChildren(attrs)) {
childNodes = [];
} else {
childNodes = parseChildNodes(element, sourceInfo);
}
var childNodes = parseChildNodes(element, sourceInfo);
return new HtmlElementAst(nodeName, attrs, childNodes, sourceInfo);
}

Expand Down Expand Up @@ -100,16 +95,6 @@ function parseChildNodes(element: Element, parentSourceInfo: string): HtmlAst[]
return result;
}

function ignoreChildren(attrs: HtmlAttrAst[]): boolean {
for (var i = 0; i < attrs.length; i++) {
var a = attrs[i];
if (a.name == NG_NON_BINDABLE) {
return true;
}
}
return false;
}

class UnparseVisitor implements HtmlAstVisitor {
visitElement(ast: HtmlElementAst, parts: string[]): any {
parts.push(`<${ast.name}`);
Expand Down
25 changes: 13 additions & 12 deletions modules/angular2/src/compiler/style_compiler.ts
@@ -1,4 +1,4 @@
import {CompileTypeMetadata, CompileDirectiveMetadata} from './directive_metadata';
import {CompileTypeMetadata, CompileTemplateMetadata} from './directive_metadata';
import {SourceModule, SourceExpression, moduleRef} from './source_module';
import {ViewEncapsulation} from 'angular2/src/core/render/api';
import {XHR} from 'angular2/src/core/render/xhr';
Expand Down Expand Up @@ -29,27 +29,28 @@ export class StyleCompiler {

constructor(private _xhr: XHR, private _urlResolver: UrlResolver) {}

compileComponentRuntime(component: CompileDirectiveMetadata): Promise<string[]> {
var styles = component.template.styles;
var styleAbsUrls = component.template.styleUrls;
compileComponentRuntime(type: CompileTypeMetadata,
template: CompileTemplateMetadata): Promise<string[]> {
var styles = template.styles;
var styleAbsUrls = template.styleUrls;
return this._loadStyles(styles, styleAbsUrls,
component.template.encapsulation === ViewEncapsulation.Emulated)
.then(styles => styles.map(style => StringWrapper.replaceAll(style, COMPONENT_REGEX,
`${component.type.id}`)));
template.encapsulation === ViewEncapsulation.Emulated)
.then(styles => styles.map(
style => StringWrapper.replaceAll(style, COMPONENT_REGEX, `${type.id}`)));
}

compileComponentCodeGen(component: CompileDirectiveMetadata): SourceExpression {
var shim = component.template.encapsulation === ViewEncapsulation.Emulated;
compileComponentCodeGen(type: CompileTypeMetadata,
template: CompileTemplateMetadata): SourceExpression {
var shim = template.encapsulation === ViewEncapsulation.Emulated;
var suffix;
if (shim) {
var componentId = `${ component.type.id}`;
var componentId = `${ type.id}`;
suffix =
codeGenMapArray(['style'], `style${codeGenReplaceAll(COMPONENT_VARIABLE, componentId)}`);
} else {
suffix = '';
}
return this._styleCodeGen(component.template.styles, component.template.styleUrls, shim,
suffix);
return this._styleCodeGen(template.styles, template.styleUrls, shim, suffix);
}

compileStylesheetCodeGen(moduleId: string, cssText: string): SourceModule[] {
Expand Down
66 changes: 35 additions & 31 deletions modules/angular2/src/compiler/template_compiler.ts
@@ -1,4 +1,5 @@
import {Type, Json, isBlank, stringify} from 'angular2/src/core/facade/lang';
import {BaseException} from 'angular2/src/core/facade/exceptions';
import {ListWrapper, SetWrapper} from 'angular2/src/core/facade/collection';
import {PromiseWrapper, Promise} from 'angular2/src/core/facade/async';
import {CompiledTemplate, TemplateCmd} from 'angular2/src/core/compiler/template_commands';
Expand Down Expand Up @@ -58,18 +59,12 @@ export class TemplateCompiler {
}));
}

serializeDirectiveMetadata(metadata: CompileDirectiveMetadata): string {
return Json.stringify(metadata.toJson());
}

deserializeDirectiveMetadata(data: string): CompileDirectiveMetadata {
return CompileDirectiveMetadata.fromJson(Json.parse(data));
}

compileHostComponentRuntime(type: Type): Promise<CompiledTemplate> {
var compMeta: CompileDirectiveMetadata = this._runtimeMetadataResolver.getMetadata(type);
assertComponent(compMeta);
var hostMeta: CompileDirectiveMetadata =
createHostComponentMeta(compMeta.type, compMeta.selector);

this._compileComponentRuntime(hostMeta, [compMeta], new Set());
return this._compiledTemplateDone.get(hostMeta.type.id);
}
Expand All @@ -93,28 +88,30 @@ export class TemplateCompiler {
new CompiledTemplate(compMeta.type.id, () => [changeDetectorFactory, commands, styles]);
this._compiledTemplateCache.set(compMeta.type.id, compiledTemplate);
compilingComponentIds.add(compMeta.type.id);
done = PromiseWrapper.all([<any>this._styleCompiler.compileComponentRuntime(compMeta)].concat(
viewDirectives.map(
dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
.then((stylesAndNormalizedViewDirMetas: any[]) => {
var childPromises = [];
var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1);
var parsedTemplate = this._templateParser.parse(
compMeta.template.template, normalizedViewDirMetas, compMeta.type.name);

var changeDetectorFactories = this._cdCompiler.compileComponentRuntime(
compMeta.type, compMeta.changeDetection, parsedTemplate);
changeDetectorFactory = changeDetectorFactories[0];
styles = stylesAndNormalizedViewDirMetas[0];
commands = this._compileCommandsRuntime(compMeta, parsedTemplate,
changeDetectorFactories,
compilingComponentIds, childPromises);
return PromiseWrapper.all(childPromises);
})
.then((_) => {
SetWrapper.delete(compilingComponentIds, compMeta.type.id);
return compiledTemplate;
});
done =
PromiseWrapper
.all([
<any>this._styleCompiler.compileComponentRuntime(compMeta.type, compMeta.template)
].concat(viewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
.then((stylesAndNormalizedViewDirMetas: any[]) => {
var childPromises = [];
var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1);
var parsedTemplate = this._templateParser.parse(
compMeta.template.template, normalizedViewDirMetas, compMeta.type.name);

var changeDetectorFactories = this._cdCompiler.compileComponentRuntime(
compMeta.type, compMeta.changeDetection, parsedTemplate);
changeDetectorFactory = changeDetectorFactories[0];
styles = stylesAndNormalizedViewDirMetas[0];
commands =
this._compileCommandsRuntime(compMeta, parsedTemplate, changeDetectorFactories,
compilingComponentIds, childPromises);
return PromiseWrapper.all(childPromises);
})
.then((_) => {
SetWrapper.delete(compilingComponentIds, compMeta.type.id);
return compiledTemplate;
});
this._compiledTemplateDone.set(compMeta.type.id, done);
}
return compiledTemplate;
Expand Down Expand Up @@ -148,6 +145,7 @@ export class TemplateCompiler {
var componentMetas: CompileDirectiveMetadata[] = [];
components.forEach(componentWithDirs => {
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
assertComponent(compMeta);
componentMetas.push(compMeta);
this._processTemplateCodeGen(compMeta,
<CompileDirectiveMetadata[]>componentWithDirs.directives,
Expand All @@ -174,7 +172,7 @@ export class TemplateCompiler {
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata,
directives: CompileDirectiveMetadata[],
targetDeclarations: string[], targetTemplateArguments: any[][]) {
var styleExpr = this._styleCompiler.compileComponentCodeGen(compMeta);
var styleExpr = this._styleCompiler.compileComponentCodeGen(compMeta.type, compMeta.template);
var parsedTemplate =
this._templateParser.parse(compMeta.template.template, directives, compMeta.type.name);
var changeDetectorsExprs = this._cdCompiler.compileComponentCodeGen(
Expand All @@ -197,6 +195,12 @@ export class NormalizedComponentWithViewDirectives {
public directives: CompileDirectiveMetadata[]) {}
}

function assertComponent(meta: CompileDirectiveMetadata) {
if (!meta.isComponent) {
throw new BaseException(`Could not compile '${meta.type.name}' because it is not a component.`);
}
}

function templateVariableName(type: CompileTypeMetadata): string {
return `${type.name}Template`;
}
Expand Down
18 changes: 14 additions & 4 deletions modules/angular2/src/compiler/template_normalizer.ts
Expand Up @@ -4,6 +4,7 @@ import {
CompileTemplateMetadata
} from './directive_metadata';
import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
import {BaseException} from 'angular2/src/core/facade/exceptions';
import {Promise, PromiseWrapper} from 'angular2/src/core/facade/async';

import {XHR} from 'angular2/src/core/render/xhr';
Expand Down Expand Up @@ -34,11 +35,13 @@ export class TemplateNormalizer {
if (isPresent(template.template)) {
return PromiseWrapper.resolve(this.normalizeLoadedTemplate(
directiveType, template, template.template, directiveType.moduleId));
} else {
} else if (isPresent(template.templateUrl)) {
var sourceAbsUrl = this._urlResolver.resolve(directiveType.moduleId, template.templateUrl);
return this._xhr.get(sourceAbsUrl)
.then(templateContent => this.normalizeLoadedTemplate(directiveType, template,
templateContent, sourceAbsUrl));
} else {
throw new BaseException(`No template specified for component ${directiveType.name}`);
}
}

Expand Down Expand Up @@ -79,12 +82,15 @@ class TemplatePreparseVisitor implements HtmlAstVisitor {
ngContentSelectors: string[] = [];
styles: string[] = [];
styleUrls: string[] = [];
ngNonBindableStackCount: number = 0;

visitElement(ast: HtmlElementAst, context: any): any {
var preparsedElement = preparseElement(ast);
switch (preparsedElement.type) {
case PreparsedElementType.NG_CONTENT:
this.ngContentSelectors.push(preparsedElement.selectAttr);
if (this.ngNonBindableStackCount === 0) {
this.ngContentSelectors.push(preparsedElement.selectAttr);
}
break;
case PreparsedElementType.STYLE:
var textContent = '';
Expand All @@ -99,8 +105,12 @@ class TemplatePreparseVisitor implements HtmlAstVisitor {
this.styleUrls.push(preparsedElement.hrefAttr);
break;
}
if (preparsedElement.type !== PreparsedElementType.NON_BINDABLE) {
htmlVisitAll(this, ast.children);
if (preparsedElement.nonBindable) {
this.ngNonBindableStackCount++;
}
htmlVisitAll(this, ast.children);
if (preparsedElement.nonBindable) {
this.ngNonBindableStackCount--;
}
return null;
}
Expand Down

0 comments on commit 7470ad1

Please sign in to comment.