refactor(compiler): cleanup and preparation for integration
- Rename `DirectiveMetadata` into `CompileDirectiveMetadata`, merge with `NormalizedDirectiveMetadata` and remove `ChangeDetectionMetadata` - Store change detector factories not as array but directly at the `CompiledTemplate` or the embedded template to make instantiation easier later on - Already analyze variable values and map them to `Directive.exportAs` - Keep the directive sort order as specified in the `@View()` annotation - Allow to clear the runtime cache in `StyleCompiler` and `TemplateCompiler` - Ignore `script` elements to match the semantics of the current compiler - Make all components dynamically loadable and remove the previously introduced property `@Component#dynamicLoadable` for now until we find a better option to configure this - Don’t allow to specify bindings in `@View#directives` and `@View#pipes` as this was never supported by the transformer (see below for the breaking change) BREAKING CHANGE: - don't support DI bindings in `@View#directives` and `@View@pipes` any more in preparation of integrating the new compiler. Use `@Directive#bindings` to reexport directives under a different token instead. Part of #3605 Closes #4314
This commit is contained in:
@ -1,8 +1,7 @@
|
||||
import {
|
||||
TypeMetadata,
|
||||
TemplateMetadata,
|
||||
NormalizedDirectiveMetadata,
|
||||
NormalizedTemplateMetadata
|
||||
CompileTypeMetadata,
|
||||
CompileDirectiveMetadata,
|
||||
CompileTemplateMetadata
|
||||
} from './directive_metadata';
|
||||
import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
|
||||
import {Promise, PromiseWrapper} from 'angular2/src/core/facade/async';
|
||||
@ -11,6 +10,7 @@ import {XHR} from 'angular2/src/core/render/xhr';
|
||||
import {UrlResolver} from 'angular2/src/core/services/url_resolver';
|
||||
import {resolveStyleUrls} from './style_url_resolver';
|
||||
import {Injectable} from 'angular2/src/core/di';
|
||||
import {ViewEncapsulation} from 'angular2/src/core/render/api';
|
||||
|
||||
import {
|
||||
HtmlAstVisitor,
|
||||
@ -22,21 +22,15 @@ import {
|
||||
} from './html_ast';
|
||||
import {HtmlParser} from './html_parser';
|
||||
|
||||
const NG_CONTENT_SELECT_ATTR = 'select';
|
||||
const NG_CONTENT_ELEMENT = 'ng-content';
|
||||
const LINK_ELEMENT = 'link';
|
||||
const LINK_STYLE_REL_ATTR = 'rel';
|
||||
const LINK_STYLE_HREF_ATTR = 'href';
|
||||
const LINK_STYLE_REL_VALUE = 'stylesheet';
|
||||
const STYLE_ELEMENT = 'style';
|
||||
import {preparseElement, PreparsedElement, PreparsedElementType} from './template_preparser';
|
||||
|
||||
@Injectable()
|
||||
export class TemplateNormalizer {
|
||||
constructor(private _xhr: XHR, private _urlResolver: UrlResolver,
|
||||
private _domParser: HtmlParser) {}
|
||||
|
||||
normalizeTemplate(directiveType: TypeMetadata,
|
||||
template: TemplateMetadata): Promise<NormalizedTemplateMetadata> {
|
||||
normalizeTemplate(directiveType: CompileTypeMetadata,
|
||||
template: CompileTemplateMetadata): Promise<CompileTemplateMetadata> {
|
||||
if (isPresent(template.template)) {
|
||||
return PromiseWrapper.resolve(this.normalizeLoadedTemplate(
|
||||
directiveType, template, template.template, directiveType.moduleId));
|
||||
@ -48,11 +42,11 @@ export class TemplateNormalizer {
|
||||
}
|
||||
}
|
||||
|
||||
normalizeLoadedTemplate(directiveType: TypeMetadata, templateMeta: TemplateMetadata,
|
||||
template: string, templateAbsUrl: string): NormalizedTemplateMetadata {
|
||||
normalizeLoadedTemplate(directiveType: CompileTypeMetadata, templateMeta: CompileTemplateMetadata,
|
||||
template: string, templateAbsUrl: string): CompileTemplateMetadata {
|
||||
var domNodes = this._domParser.parse(template, directiveType.name);
|
||||
var visitor = new TemplatePreparseVisitor();
|
||||
var remainingNodes = htmlVisitAll(visitor, domNodes);
|
||||
htmlVisitAll(visitor, domNodes);
|
||||
var allStyles = templateMeta.styles.concat(visitor.styles);
|
||||
|
||||
var allStyleAbsUrls =
|
||||
@ -65,11 +59,17 @@ export class TemplateNormalizer {
|
||||
styleWithImports.styleUrls.forEach(styleUrl => allStyleAbsUrls.push(styleUrl));
|
||||
return styleWithImports.style;
|
||||
});
|
||||
return new NormalizedTemplateMetadata({
|
||||
encapsulation: templateMeta.encapsulation,
|
||||
template: this._domParser.unparse(remainingNodes),
|
||||
var encapsulation = templateMeta.encapsulation;
|
||||
if (encapsulation === ViewEncapsulation.Emulated && allResolvedStyles.length === 0 &&
|
||||
allStyleAbsUrls.length === 0) {
|
||||
encapsulation = ViewEncapsulation.None;
|
||||
}
|
||||
return new CompileTemplateMetadata({
|
||||
encapsulation: encapsulation,
|
||||
template: template,
|
||||
templateUrl: templateAbsUrl,
|
||||
styles: allResolvedStyles,
|
||||
styleAbsUrls: allStyleAbsUrls,
|
||||
styleUrls: allStyleAbsUrls,
|
||||
ngContentSelectors: visitor.ngContentSelectors
|
||||
});
|
||||
}
|
||||
@ -80,50 +80,30 @@ class TemplatePreparseVisitor implements HtmlAstVisitor {
|
||||
styles: string[] = [];
|
||||
styleUrls: string[] = [];
|
||||
|
||||
visitElement(ast: HtmlElementAst, context: any): HtmlElementAst {
|
||||
var selectAttr = null;
|
||||
var hrefAttr = null;
|
||||
var relAttr = null;
|
||||
ast.attrs.forEach(attr => {
|
||||
if (attr.name == NG_CONTENT_SELECT_ATTR) {
|
||||
selectAttr = attr.value;
|
||||
} else if (attr.name == LINK_STYLE_HREF_ATTR) {
|
||||
hrefAttr = attr.value;
|
||||
} else if (attr.name == LINK_STYLE_REL_ATTR) {
|
||||
relAttr = attr.value;
|
||||
}
|
||||
});
|
||||
var nodeName = ast.name;
|
||||
var keepElement = true;
|
||||
if (nodeName == NG_CONTENT_ELEMENT) {
|
||||
this.ngContentSelectors.push(normalizeNgContentSelect(selectAttr));
|
||||
} else if (nodeName == STYLE_ELEMENT) {
|
||||
keepElement = false;
|
||||
var textContent = '';
|
||||
ast.children.forEach(child => {
|
||||
if (child instanceof HtmlTextAst) {
|
||||
textContent += (<HtmlTextAst>child).value;
|
||||
}
|
||||
});
|
||||
this.styles.push(textContent);
|
||||
} else if (nodeName == LINK_ELEMENT && relAttr == LINK_STYLE_REL_VALUE) {
|
||||
keepElement = false;
|
||||
this.styleUrls.push(hrefAttr);
|
||||
visitElement(ast: HtmlElementAst, context: any): any {
|
||||
var preparsedElement = preparseElement(ast);
|
||||
switch (preparsedElement.type) {
|
||||
case PreparsedElementType.NG_CONTENT:
|
||||
this.ngContentSelectors.push(preparsedElement.selectAttr);
|
||||
break;
|
||||
case PreparsedElementType.STYLE:
|
||||
var textContent = '';
|
||||
ast.children.forEach(child => {
|
||||
if (child instanceof HtmlTextAst) {
|
||||
textContent += (<HtmlTextAst>child).value;
|
||||
}
|
||||
});
|
||||
this.styles.push(textContent);
|
||||
break;
|
||||
case PreparsedElementType.STYLESHEET:
|
||||
this.styleUrls.push(preparsedElement.hrefAttr);
|
||||
break;
|
||||
}
|
||||
if (keepElement) {
|
||||
return new HtmlElementAst(ast.name, ast.attrs, htmlVisitAll(this, ast.children),
|
||||
ast.sourceInfo);
|
||||
} else {
|
||||
return null;
|
||||
if (preparsedElement.type !== PreparsedElementType.NON_BINDABLE) {
|
||||
htmlVisitAll(this, ast.children);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitAttr(ast: HtmlAttrAst, context: any): HtmlAttrAst { return ast; }
|
||||
visitText(ast: HtmlTextAst, context: any): HtmlTextAst { return ast; }
|
||||
visitAttr(ast: HtmlAttrAst, context: any): any { return null; }
|
||||
visitText(ast: HtmlTextAst, context: any): any { return null; }
|
||||
}
|
||||
|
||||
function normalizeNgContentSelect(selectAttr: string): string {
|
||||
if (isBlank(selectAttr) || selectAttr.length === 0) {
|
||||
return '*';
|
||||
}
|
||||
return selectAttr;
|
||||
}
|
Reference in New Issue
Block a user