refactor(compiler): Drop support for the deprecated `<template>`. Use `<ng-template>` instead (#22783)
BREAKING CHANGE: The `<template>` tag was deprecated in Angular v4 to avoid collisions (i.e. when using Web Components). This commit removes support for `<template>`. `<ng-template>` should be used instead. BEFORE: <!-- html template --> <template>some template content</template> # tsconfig.json { # ... "angularCompilerOptions": { # ... # This option is no more supported and will have no effect "enableLegacyTemplate": [true|false] } } AFTER: <!-- html template --> <ng-template>some template content</ng-template> PR Close #22783
This commit is contained in:
parent
4e6ac185e5
commit
0ebd577db4
|
@ -215,13 +215,6 @@ value | description
|
||||||
|
|
||||||
This tells the compiler to print extra information while compiling templates.
|
This tells the compiler to print extra information while compiling templates.
|
||||||
|
|
||||||
### *enableLegacyTemplate*
|
|
||||||
|
|
||||||
The use of `<template>` element was deprecated starting in Angular 4.0 in favor of using
|
|
||||||
`<ng-template>` to avoid colliding with the DOM's element of the same name. Setting this option to
|
|
||||||
`true` enables the use of the deprecated `<template>` element . This option
|
|
||||||
is `false` by default. This option might be required by some third-party Angular libraries.
|
|
||||||
|
|
||||||
### *disableExpressionLowering*
|
### *disableExpressionLowering*
|
||||||
|
|
||||||
The Angular template compiler transforms code that is used, or could be used, in an annotation
|
The Angular template compiler transforms code that is used, or could be used, in an annotation
|
||||||
|
|
|
@ -25,9 +25,9 @@ import {ScrollAreaComponent} from './scroll_area';
|
||||||
<div style="display: flex">
|
<div style="display: flex">
|
||||||
<scroll-area id="testArea"></scroll-area>
|
<scroll-area id="testArea"></scroll-area>
|
||||||
</div>
|
</div>
|
||||||
<div template="ngIf scrollAreas.length > 0">
|
<div *ngIf="scrollAreas.length > 0">
|
||||||
<p>Following tables are only here to add weight to the UI:</p>
|
<p>Following tables are only here to add weight to the UI:</p>
|
||||||
<scroll-area template="ngFor let scrollArea of scrollAreas"></scroll-area>
|
<scroll-area *ngFor="let scrollArea of scrollAreas"></scroll-area>
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
|
@ -62,7 +62,7 @@ export class Stage {
|
||||||
directives: [NgFor],
|
directives: [NgFor],
|
||||||
template: `
|
template: `
|
||||||
<div [style.width.px]="cellWidth">
|
<div [style.width.px]="cellWidth">
|
||||||
<button template="ngFor let stage of stages"
|
<button *ngFor="let stage of stages"
|
||||||
[disabled]="stage.isDisabled"
|
[disabled]="stage.isDisabled"
|
||||||
[style.background-color]="stage.backgroundColor"
|
[style.background-color]="stage.backgroundColor"
|
||||||
on-click="setStage(stage)">
|
on-click="setStage(stage)">
|
||||||
|
|
|
@ -25,7 +25,7 @@ import {ScrollItemComponent} from './scroll_item';
|
||||||
<div id="padding"></div>
|
<div id="padding"></div>
|
||||||
<div id="inner">
|
<div id="inner">
|
||||||
<scroll-item
|
<scroll-item
|
||||||
template="ngFor let item of visibleItems"
|
*ngFor="let item of visibleItems"
|
||||||
[offering]="item">
|
[offering]="item">
|
||||||
</scroll-item>
|
</scroll-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -50,7 +50,6 @@ export interface CompilerOptions extends ts.CompilerOptions {
|
||||||
annotateForClosureCompiler?: boolean;
|
annotateForClosureCompiler?: boolean;
|
||||||
annotationsAs?: 'decorators'|'static fields';
|
annotationsAs?: 'decorators'|'static fields';
|
||||||
trace?: boolean;
|
trace?: boolean;
|
||||||
enableLegacyTemplate?: boolean;
|
|
||||||
disableExpressionLowering?: boolean;
|
disableExpressionLowering?: boolean;
|
||||||
i18nOutLocale?: string;
|
i18nOutLocale?: string;
|
||||||
i18nOutFormat?: string;
|
i18nOutFormat?: string;
|
||||||
|
|
|
@ -125,9 +125,6 @@ export interface CompilerOptions extends ts.CompilerOptions {
|
||||||
// Print extra information while running the compiler
|
// Print extra information while running the compiler
|
||||||
trace?: boolean;
|
trace?: boolean;
|
||||||
|
|
||||||
// Whether to enable support for <template> and the template attribute (false by default)
|
|
||||||
enableLegacyTemplate?: boolean;
|
|
||||||
|
|
||||||
// Whether to enable lowering expressions lambdas and expressions in a reference value
|
// Whether to enable lowering expressions lambdas and expressions in a reference value
|
||||||
// position.
|
// position.
|
||||||
disableExpressionLowering?: boolean;
|
disableExpressionLowering?: boolean;
|
||||||
|
|
|
@ -828,7 +828,6 @@ function getAotCompilerOptions(options: CompilerOptions): AotCompilerOptions {
|
||||||
return {
|
return {
|
||||||
locale: options.i18nInLocale,
|
locale: options.i18nInLocale,
|
||||||
i18nFormat: options.i18nInFormat || options.i18nOutFormat, translations, missingTranslation,
|
i18nFormat: options.i18nInFormat || options.i18nOutFormat, translations, missingTranslation,
|
||||||
enableLegacyTemplate: options.enableLegacyTemplate,
|
|
||||||
enableSummariesForJit: options.enableSummariesForJit,
|
enableSummariesForJit: options.enableSummariesForJit,
|
||||||
preserveWhitespaces: options.preserveWhitespaces,
|
preserveWhitespaces: options.preserveWhitespaces,
|
||||||
fullTemplateTypeCheck: options.fullTemplateTypeCheck,
|
fullTemplateTypeCheck: options.fullTemplateTypeCheck,
|
||||||
|
|
|
@ -536,7 +536,6 @@ The recommended options for producing a ivy application are
|
||||||
| `"renderer2BackPatching"` | `true` | implied |
|
| `"renderer2BackPatching"` | `true` | implied |
|
||||||
| `"generateCodeForLibraries"` | `true` | default |
|
| `"generateCodeForLibraries"` | `true` | default |
|
||||||
| `"annotationsAs"` | `remove` | implied |
|
| `"annotationsAs"` | `remove` | implied |
|
||||||
| `"enableLegacyTemplate"` | `false` | default |
|
|
||||||
| `"preserveWhitespaces"` | `false` | default |
|
| `"preserveWhitespaces"` | `false` | default |
|
||||||
| `"skipMetadataEmit"` | `true` | default |
|
| `"skipMetadataEmit"` | `true` | default |
|
||||||
| `"strictMetadataEmit"` | `false` | implied |
|
| `"strictMetadataEmit"` | `false` | implied |
|
||||||
|
@ -574,7 +573,6 @@ The recommended options for producing a ivy library are:
|
||||||
| `"renderer2BackPatching"` | `false` | default |
|
| `"renderer2BackPatching"` | `false` | default |
|
||||||
| `"generateCodeForLibraries"` | `false` | |
|
| `"generateCodeForLibraries"` | `false` | |
|
||||||
| `"annotationsAs"` | `remove` | implied |
|
| `"annotationsAs"` | `remove` | implied |
|
||||||
| `"enableLegacyTemplate"` | `false` | default |
|
|
||||||
| `"preserveWhitespaces"` | `false` | default |
|
| `"preserveWhitespaces"` | `false` | default |
|
||||||
| `"skipMetadataEmit"` | `false` | |
|
| `"skipMetadataEmit"` | `false` | |
|
||||||
| `"strictMetadataEmit"` | `true ` | |
|
| `"strictMetadataEmit"` | `true ` | |
|
||||||
|
@ -598,25 +596,21 @@ depending on the target:
|
||||||
| | `"renderer2BackPatching"` | `true` | enforced |
|
| | `"renderer2BackPatching"` | `true` | enforced |
|
||||||
| | `"generateCodeForLibraries"` | `true` | |
|
| | `"generateCodeForLibraries"` | `true` | |
|
||||||
| | `"annotationsAs"` | `remove` | |
|
| | `"annotationsAs"` | `remove` | |
|
||||||
| | `"enableLegacyTemplate"` | `false` | |
|
|
||||||
| | `"preserveWhitespaces"` | `false` | |
|
| | `"preserveWhitespaces"` | `false` | |
|
||||||
| | `"skipMetadataEmit"` | `false` | |
|
| | `"skipMetadataEmit"` | `false` | |
|
||||||
| | `"strictMetadataEmit"` | `true` | |
|
| | `"strictMetadataEmit"` | `true` | |
|
||||||
| | `"skipTemplateCodegen"` | `false` | |
|
| | `"skipTemplateCodegen"` | `false` | |
|
||||||
| | `"fullTemplateTypeCheck"` | `true` | |
|
| | `"fullTemplateTypeCheck"` | `true` | |
|
||||||
| | `"enableLegacyTemplate"` | `false` | |
|
|
||||||
| | | | |
|
| | | | |
|
||||||
| `"library"` | `"generateRenderer2Factories"` | `false` | enforced |
|
| `"library"` | `"generateRenderer2Factories"` | `false` | enforced |
|
||||||
| | `"renderer2BackPatching"` | `false` | enforced |
|
| | `"renderer2BackPatching"` | `false` | enforced |
|
||||||
| | `"generateCodeForLibraries"` | `false` | enforced |
|
| | `"generateCodeForLibraries"` | `false` | enforced |
|
||||||
| | `"annotationsAs"` | `decorators` | |
|
| | `"annotationsAs"` | `decorators` | |
|
||||||
| | `"enableLegacyTemplate"` | `false` | |
|
|
||||||
| | `"preserveWhitespaces"` | `false` | |
|
| | `"preserveWhitespaces"` | `false` | |
|
||||||
| | `"skipMetadataEmit"` | `false` | enforced |
|
| | `"skipMetadataEmit"` | `false` | enforced |
|
||||||
| | `"strictMetadataEmit"` | `true` | |
|
| | `"strictMetadataEmit"` | `true` | |
|
||||||
| | `"skipTemplateCodegen"` | `false` | enforced |
|
| | `"skipTemplateCodegen"` | `false` | enforced |
|
||||||
| | `"fullTemplateTypeCheck"` | `true` | |
|
| | `"fullTemplateTypeCheck"` | `true` | |
|
||||||
| | `"enableLegacyTemplate"` | `false` | |
|
|
||||||
| | | | |
|
| | | | |
|
||||||
| `"package"` | `"flatModuleOutFile"` | | required |
|
| `"package"` | `"flatModuleOutFile"` | | required |
|
||||||
| | `"flatModuleId"` | | required |
|
| | `"flatModuleId"` | | required |
|
||||||
|
@ -625,13 +619,11 @@ depending on the target:
|
||||||
| | `"renderer2BackPatching"` | `false` | enforced |
|
| | `"renderer2BackPatching"` | `false` | enforced |
|
||||||
| | `"generateCodeForLibraries"` | `false` | enforced |
|
| | `"generateCodeForLibraries"` | `false` | enforced |
|
||||||
| | `"annotationsAs"` | `remove` | |
|
| | `"annotationsAs"` | `remove` | |
|
||||||
| | `"enableLegacyTemplate"` | `false` | |
|
|
||||||
| | `"preserveWhitespaces"` | `false` | |
|
| | `"preserveWhitespaces"` | `false` | |
|
||||||
| | `"skipMetadataEmit"` | `false` | enforced |
|
| | `"skipMetadataEmit"` | `false` | enforced |
|
||||||
| | `"strictMetadataEmit"` | `true` | |
|
| | `"strictMetadataEmit"` | `true` | |
|
||||||
| | `"skipTemplateCodegen"` | `false` | enforced |
|
| | `"skipTemplateCodegen"` | `false` | enforced |
|
||||||
| | `"fullTemplateTypeCheck"` | `true` | |
|
| | `"fullTemplateTypeCheck"` | `true` | |
|
||||||
| | `"enableLegacyTemplate"` | `false` | |
|
|
||||||
|
|
||||||
Options that are marked "enforced" are reported as an error if they are
|
Options that are marked "enforced" are reported as an error if they are
|
||||||
explicitly set to a value different from what is specified here. The options
|
explicitly set to a value different from what is specified here. The options
|
||||||
|
|
|
@ -70,7 +70,6 @@ export function createAotCompiler(
|
||||||
const config = new CompilerConfig({
|
const config = new CompilerConfig({
|
||||||
defaultEncapsulation: ViewEncapsulation.Emulated,
|
defaultEncapsulation: ViewEncapsulation.Emulated,
|
||||||
useJit: false,
|
useJit: false,
|
||||||
enableLegacyTemplate: options.enableLegacyTemplate === true,
|
|
||||||
missingTranslation: options.missingTranslation,
|
missingTranslation: options.missingTranslation,
|
||||||
preserveWhitespaces: options.preserveWhitespaces,
|
preserveWhitespaces: options.preserveWhitespaces,
|
||||||
strictInjectionParameters: options.strictInjectionParameters,
|
strictInjectionParameters: options.strictInjectionParameters,
|
||||||
|
|
|
@ -13,7 +13,6 @@ export interface AotCompilerOptions {
|
||||||
i18nFormat?: string;
|
i18nFormat?: string;
|
||||||
translations?: string;
|
translations?: string;
|
||||||
missingTranslation?: MissingTranslationStrategy;
|
missingTranslation?: MissingTranslationStrategy;
|
||||||
enableLegacyTemplate?: boolean;
|
|
||||||
enableSummariesForJit?: boolean;
|
enableSummariesForJit?: boolean;
|
||||||
preserveWhitespaces?: boolean;
|
preserveWhitespaces?: boolean;
|
||||||
fullTemplateTypeCheck?: boolean;
|
fullTemplateTypeCheck?: boolean;
|
||||||
|
|
|
@ -14,9 +14,6 @@ import {noUndefined} from './util';
|
||||||
|
|
||||||
export class CompilerConfig {
|
export class CompilerConfig {
|
||||||
public defaultEncapsulation: ViewEncapsulation|null;
|
public defaultEncapsulation: ViewEncapsulation|null;
|
||||||
// Whether to support the `<template>` tag and the `template` attribute to define angular
|
|
||||||
// templates. They have been deprecated in 4.x, `<ng-template>` should be used instead.
|
|
||||||
public enableLegacyTemplate: boolean;
|
|
||||||
public useJit: boolean;
|
public useJit: boolean;
|
||||||
public jitDevMode: boolean;
|
public jitDevMode: boolean;
|
||||||
public missingTranslation: MissingTranslationStrategy|null;
|
public missingTranslation: MissingTranslationStrategy|null;
|
||||||
|
@ -25,13 +22,11 @@ export class CompilerConfig {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
{defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, jitDevMode = false,
|
{defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, jitDevMode = false,
|
||||||
missingTranslation = null, enableLegacyTemplate, preserveWhitespaces,
|
missingTranslation = null, preserveWhitespaces, strictInjectionParameters}: {
|
||||||
strictInjectionParameters}: {
|
|
||||||
defaultEncapsulation?: ViewEncapsulation,
|
defaultEncapsulation?: ViewEncapsulation,
|
||||||
useJit?: boolean,
|
useJit?: boolean,
|
||||||
jitDevMode?: boolean,
|
jitDevMode?: boolean,
|
||||||
missingTranslation?: MissingTranslationStrategy,
|
missingTranslation?: MissingTranslationStrategy,
|
||||||
enableLegacyTemplate?: boolean,
|
|
||||||
preserveWhitespaces?: boolean,
|
preserveWhitespaces?: boolean,
|
||||||
strictInjectionParameters?: boolean,
|
strictInjectionParameters?: boolean,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
|
@ -39,7 +34,6 @@ export class CompilerConfig {
|
||||||
this.useJit = !!useJit;
|
this.useJit = !!useJit;
|
||||||
this.jitDevMode = !!jitDevMode;
|
this.jitDevMode = !!jitDevMode;
|
||||||
this.missingTranslation = missingTranslation;
|
this.missingTranslation = missingTranslation;
|
||||||
this.enableLegacyTemplate = enableLegacyTemplate === true;
|
|
||||||
this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces));
|
this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces));
|
||||||
this.strictInjectionParameters = strictInjectionParameters === true;
|
this.strictInjectionParameters = strictInjectionParameters === true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,6 @@ export function mergeNsAndName(prefix: string, localName: string): string {
|
||||||
// This list is not exhaustive to keep the compiler footprint low.
|
// This list is not exhaustive to keep the compiler footprint low.
|
||||||
// The `{` / `ƫ` syntax should be used when the named character reference does not
|
// The `{` / `ƫ` syntax should be used when the named character reference does not
|
||||||
// exist.
|
// exist.
|
||||||
|
|
||||||
export const NAMED_ENTITIES: {[k: string]: string} = {
|
export const NAMED_ENTITIES: {[k: string]: string} = {
|
||||||
'Aacute': '\u00C1',
|
'Aacute': '\u00C1',
|
||||||
'aacute': '\u00E1',
|
'aacute': '\u00E1',
|
||||||
|
|
|
@ -55,20 +55,11 @@ const IDENT_PROPERTY_IDX = 9;
|
||||||
// Group 10 = identifier inside ()
|
// Group 10 = identifier inside ()
|
||||||
const IDENT_EVENT_IDX = 10;
|
const IDENT_EVENT_IDX = 10;
|
||||||
|
|
||||||
// deprecated in 4.x
|
|
||||||
const TEMPLATE_ELEMENT = 'template';
|
|
||||||
// deprecated in 4.x
|
|
||||||
const TEMPLATE_ATTR = 'template';
|
|
||||||
const TEMPLATE_ATTR_PREFIX = '*';
|
const TEMPLATE_ATTR_PREFIX = '*';
|
||||||
const CLASS_ATTR = 'class';
|
const CLASS_ATTR = 'class';
|
||||||
|
|
||||||
const TEXT_CSS_SELECTOR = CssSelector.parse('*')[0];
|
const TEXT_CSS_SELECTOR = CssSelector.parse('*')[0];
|
||||||
|
|
||||||
const TEMPLATE_ELEMENT_DEPRECATION_WARNING =
|
|
||||||
'The <template> element is deprecated. Use <ng-template> instead';
|
|
||||||
const TEMPLATE_ATTR_DEPRECATION_WARNING =
|
|
||||||
'The template attribute is deprecated. Use an ng-template element instead.';
|
|
||||||
|
|
||||||
let warningCounts: {[warning: string]: number} = {};
|
let warningCounts: {[warning: string]: number} = {};
|
||||||
|
|
||||||
function warnOnlyOnce(warnings: string[]): (warning: ParseError) => boolean {
|
function warnOnlyOnce(warnings: string[]): (warning: ParseError) => boolean {
|
||||||
|
@ -109,10 +100,7 @@ export class TemplateParser {
|
||||||
preserveWhitespaces: boolean): {template: TemplateAst[], pipes: CompilePipeSummary[]} {
|
preserveWhitespaces: boolean): {template: TemplateAst[], pipes: CompilePipeSummary[]} {
|
||||||
const result = this.tryParse(
|
const result = this.tryParse(
|
||||||
component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces);
|
component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces);
|
||||||
const warnings =
|
const warnings = result.errors !.filter(error => error.level === ParseErrorLevel.WARNING);
|
||||||
result.errors !.filter(error => error.level === ParseErrorLevel.WARNING)
|
|
||||||
.filter(warnOnlyOnce(
|
|
||||||
[TEMPLATE_ATTR_DEPRECATION_WARNING, TEMPLATE_ELEMENT_DEPRECATION_WARNING]));
|
|
||||||
|
|
||||||
const errors = result.errors !.filter(error => error.level === ParseErrorLevel.ERROR);
|
const errors = result.errors !.filter(error => error.level === ParseErrorLevel.ERROR);
|
||||||
|
|
||||||
|
@ -295,9 +283,7 @@ class TemplateParseVisitor implements html.Visitor {
|
||||||
|
|
||||||
let hasInlineTemplates = false;
|
let hasInlineTemplates = false;
|
||||||
const attrs: AttrAst[] = [];
|
const attrs: AttrAst[] = [];
|
||||||
const isTemplateElement = isTemplate(
|
const isTemplateElement = isNgTemplate(element.name);
|
||||||
element, this.config.enableLegacyTemplate,
|
|
||||||
(m: string, span: ParseSourceSpan) => this._reportError(m, span, ParseErrorLevel.WARNING));
|
|
||||||
|
|
||||||
element.attrs.forEach(attr => {
|
element.attrs.forEach(attr => {
|
||||||
const hasBinding = this._parseAttr(
|
const hasBinding = this._parseAttr(
|
||||||
|
@ -306,13 +292,9 @@ class TemplateParseVisitor implements html.Visitor {
|
||||||
|
|
||||||
let templateBindingsSource: string|undefined;
|
let templateBindingsSource: string|undefined;
|
||||||
let prefixToken: string|undefined;
|
let prefixToken: string|undefined;
|
||||||
let normalizedName = this._normalizeAttributeName(attr.name);
|
const normalizedName = this._normalizeAttributeName(attr.name);
|
||||||
|
|
||||||
if (this.config.enableLegacyTemplate && normalizedName == TEMPLATE_ATTR) {
|
if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX)) {
|
||||||
this._reportError(
|
|
||||||
TEMPLATE_ATTR_DEPRECATION_WARNING, attr.sourceSpan, ParseErrorLevel.WARNING);
|
|
||||||
templateBindingsSource = attr.value;
|
|
||||||
} else if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX)) {
|
|
||||||
templateBindingsSource = attr.value;
|
templateBindingsSource = attr.value;
|
||||||
prefixToken = normalizedName.substring(TEMPLATE_ATTR_PREFIX.length) + ':';
|
prefixToken = normalizedName.substring(TEMPLATE_ATTR_PREFIX.length) + ':';
|
||||||
}
|
}
|
||||||
|
@ -321,7 +303,7 @@ class TemplateParseVisitor implements html.Visitor {
|
||||||
if (hasTemplateBinding) {
|
if (hasTemplateBinding) {
|
||||||
if (hasInlineTemplates) {
|
if (hasInlineTemplates) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
`Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with *`,
|
`Can't have multiple template bindings on one element. Use only one attribute prefixed with *`,
|
||||||
attr.sourceSpan);
|
attr.sourceSpan);
|
||||||
}
|
}
|
||||||
hasInlineTemplates = true;
|
hasInlineTemplates = true;
|
||||||
|
@ -400,7 +382,7 @@ class TemplateParseVisitor implements html.Visitor {
|
||||||
|
|
||||||
if (hasInlineTemplates) {
|
if (hasInlineTemplates) {
|
||||||
const templateQueryStartIndex = this.contentQueryStartId;
|
const templateQueryStartIndex = this.contentQueryStartId;
|
||||||
const templateSelector = createElementCssSelector(TEMPLATE_ELEMENT, templateMatchableAttrs);
|
const templateSelector = createElementCssSelector('ng-template', templateMatchableAttrs);
|
||||||
const {directives: templateDirectiveMetas} =
|
const {directives: templateDirectiveMetas} =
|
||||||
this._parseDirectives(this.selectorMatcher, templateSelector);
|
this._parseDirectives(this.selectorMatcher, templateSelector);
|
||||||
const templateBoundDirectivePropNames = new Set<string>();
|
const templateBoundDirectivePropNames = new Set<string>();
|
||||||
|
@ -909,19 +891,3 @@ function isEmptyExpression(ast: AST): boolean {
|
||||||
}
|
}
|
||||||
return ast instanceof EmptyExpr;
|
return ast instanceof EmptyExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// `template` is deprecated in 4.x
|
|
||||||
function isTemplate(
|
|
||||||
el: html.Element, enableLegacyTemplate: boolean,
|
|
||||||
reportDeprecation: (m: string, span: ParseSourceSpan) => void): boolean {
|
|
||||||
if (isNgTemplate(el.name)) return true;
|
|
||||||
const tagNoNs = splitNsName(el.name)[1];
|
|
||||||
// `<template>` is HTML and case insensitive
|
|
||||||
if (tagNoNs.toLowerCase() === TEMPLATE_ELEMENT) {
|
|
||||||
if (enableLegacyTemplate && tagNoNs.toLowerCase() === TEMPLATE_ELEMENT) {
|
|
||||||
reportDeprecation(TEMPLATE_ELEMENT_DEPRECATION_WARNING, el.sourceSpan !);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
|
@ -32,10 +32,6 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse text nodes inside <ng-template> elements', () => {
|
it('should parse text nodes inside <ng-template> elements', () => {
|
||||||
// deprecated in 4.0
|
|
||||||
expect(humanizeDom(parser.parse('<template>a</template>', 'TestComp'))).toEqual([
|
|
||||||
[html.Element, 'template', 0], [html.Text, 'a', 1]
|
|
||||||
]);
|
|
||||||
expect(humanizeDom(parser.parse('<ng-template>a</ng-template>', 'TestComp'))).toEqual([
|
expect(humanizeDom(parser.parse('<ng-template>a</ng-template>', 'TestComp'))).toEqual([
|
||||||
[html.Element, 'ng-template', 0], [html.Text, 'a', 1]
|
[html.Element, 'ng-template', 0], [html.Text, 'a', 1]
|
||||||
]);
|
]);
|
||||||
|
@ -62,8 +58,6 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse elements inside <ng-template> elements', () => {
|
it('should parse elements inside <ng-template> elements', () => {
|
||||||
expect(humanizeDom(parser.parse('<template><span></span></template>', 'TestComp')))
|
|
||||||
.toEqual([[html.Element, 'template', 0], [html.Element, 'span', 1]]);
|
|
||||||
expect(humanizeDom(parser.parse('<ng-template><span></span></ng-template>', 'TestComp')))
|
expect(humanizeDom(parser.parse('<ng-template><span></span></ng-template>', 'TestComp')))
|
||||||
.toEqual([[html.Element, 'ng-template', 0], [html.Element, 'span', 1]]);
|
.toEqual([[html.Element, 'ng-template', 0], [html.Element, 'span', 1]]);
|
||||||
});
|
});
|
||||||
|
@ -175,10 +169,6 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not add the requiredParent when the parent is a <ng-template>', () => {
|
it('should not add the requiredParent when the parent is a <ng-template>', () => {
|
||||||
expect(humanizeDom(parser.parse('<template><tr></tr></template>', 'TestComp'))).toEqual([
|
|
||||||
[html.Element, 'template', 0],
|
|
||||||
[html.Element, 'tr', 1],
|
|
||||||
]);
|
|
||||||
expect(humanizeDom(parser.parse('<ng-template><tr></tr></ng-template>', 'TestComp')))
|
expect(humanizeDom(parser.parse('<ng-template><tr></tr></ng-template>', 'TestComp')))
|
||||||
.toEqual([
|
.toEqual([
|
||||||
[html.Element, 'ng-template', 0],
|
[html.Element, 'ng-template', 0],
|
||||||
|
@ -282,10 +272,6 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse attributes on <ng-template> elements', () => {
|
it('should parse attributes on <ng-template> elements', () => {
|
||||||
expect(humanizeDom(parser.parse('<template k="v"></template>', 'TestComp'))).toEqual([
|
|
||||||
[html.Element, 'template', 0],
|
|
||||||
[html.Attribute, 'k', 'v'],
|
|
||||||
]);
|
|
||||||
expect(humanizeDom(parser.parse('<ng-template k="v"></ng-template>', 'TestComp')))
|
expect(humanizeDom(parser.parse('<ng-template k="v"></ng-template>', 'TestComp')))
|
||||||
.toEqual([
|
.toEqual([
|
||||||
[html.Element, 'ng-template', 0],
|
[html.Element, 'ng-template', 0],
|
||||||
|
|
|
@ -158,7 +158,6 @@ function doCompile(
|
||||||
const config = new CompilerConfig({
|
const config = new CompilerConfig({
|
||||||
defaultEncapsulation: ViewEncapsulation.Emulated,
|
defaultEncapsulation: ViewEncapsulation.Emulated,
|
||||||
useJit: false,
|
useJit: false,
|
||||||
enableLegacyTemplate: options.enableLegacyTemplate === true,
|
|
||||||
missingTranslation: options.missingTranslation,
|
missingTranslation: options.missingTranslation,
|
||||||
preserveWhitespaces: options.preserveWhitespaces,
|
preserveWhitespaces: options.preserveWhitespaces,
|
||||||
strictInjectionParameters: options.strictInjectionParameters,
|
strictInjectionParameters: options.strictInjectionParameters,
|
||||||
|
|
|
@ -336,7 +336,6 @@ class ArrayConsole implements Console {
|
||||||
TestBed.configureCompiler({
|
TestBed.configureCompiler({
|
||||||
providers: [
|
providers: [
|
||||||
{provide: Console, useValue: console},
|
{provide: Console, useValue: console},
|
||||||
{provide: CompilerConfig, useValue: new CompilerConfig({enableLegacyTemplate: true})}
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -812,6 +811,35 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support * directives', () => {
|
||||||
|
expect(humanizeTplAst(parse('<div *ngIf>', [ngIf]))).toEqual([
|
||||||
|
[EmbeddedTemplateAst],
|
||||||
|
[DirectiveAst, ngIf],
|
||||||
|
[BoundDirectivePropertyAst, 'ngIf', 'null'],
|
||||||
|
[ElementAst, 'div'],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support <ng-template>', () => {
|
||||||
|
expect(humanizeTplAst(parse('<ng-template>', []))).toEqual([
|
||||||
|
[EmbeddedTemplateAst],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should treat <template> as a regular tag', () => {
|
||||||
|
expect(humanizeTplAst(parse('<template>', []))).toEqual([
|
||||||
|
[ElementAst, 'template'],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not special case the template attribute', () => {
|
||||||
|
expect(humanizeTplAst(parse('<p template="ngFor">', []))).toEqual([
|
||||||
|
[ElementAst, 'p'],
|
||||||
|
[AttrAst, 'template', 'ngFor'],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('events', () => {
|
describe('events', () => {
|
||||||
|
@ -852,17 +880,11 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
||||||
() => {
|
() => {
|
||||||
const dirA =
|
const dirA =
|
||||||
compileDirectiveMetadataCreate({
|
compileDirectiveMetadataCreate({
|
||||||
selector: 'template,ng-template',
|
selector: 'ng-template',
|
||||||
outputs: ['e'],
|
outputs: ['e'],
|
||||||
type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}})
|
type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}})
|
||||||
}).toSummary();
|
}).toSummary();
|
||||||
|
|
||||||
expect(humanizeTplAst(parse('<template (e)="f"></template>', [dirA]))).toEqual([
|
|
||||||
[EmbeddedTemplateAst],
|
|
||||||
[BoundEventAst, 'e', null, 'f'],
|
|
||||||
[DirectiveAst, dirA],
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(humanizeTplAst(parse('<ng-template (e)="f"></ng-template>', [dirA]))).toEqual([
|
expect(humanizeTplAst(parse('<ng-template (e)="f"></ng-template>', [dirA]))).toEqual([
|
||||||
[EmbeddedTemplateAst],
|
[EmbeddedTemplateAst],
|
||||||
[BoundEventAst, 'e', null, 'f'],
|
[BoundEventAst, 'e', null, 'f'],
|
||||||
|
@ -952,7 +974,7 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
||||||
it('should locate directives in inline templates', () => {
|
it('should locate directives in inline templates', () => {
|
||||||
const dirTemplate =
|
const dirTemplate =
|
||||||
compileDirectiveMetadataCreate({
|
compileDirectiveMetadataCreate({
|
||||||
selector: 'template',
|
selector: 'ng-template',
|
||||||
type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'onTemplate'}})
|
type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'onTemplate'}})
|
||||||
}).toSummary();
|
}).toSummary();
|
||||||
expect(humanizeTplAst(parse('<div *ngIf="cond">', [ngIf, dirTemplate]))).toEqual([
|
expect(humanizeTplAst(parse('<div *ngIf="cond">', [ngIf, dirTemplate]))).toEqual([
|
||||||
|
@ -1460,8 +1482,6 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
||||||
|
|
||||||
it('should not throw error when there is same reference name in different templates',
|
it('should not throw error when there is same reference name in different templates',
|
||||||
() => {
|
() => {
|
||||||
expect(() => parse('<div #a><template #a><span>OK</span></template></div>', []))
|
|
||||||
.not.toThrowError();
|
|
||||||
expect(() => parse('<div #a><ng-template #a><span>OK</span></ng-template></div>', []))
|
expect(() => parse('<div #a><ng-template #a><span>OK</span></ng-template></div>', []))
|
||||||
.not.toThrowError();
|
.not.toThrowError();
|
||||||
});
|
});
|
||||||
|
@ -1500,20 +1520,12 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
||||||
beforeEach(() => { reflector = new JitReflector(); });
|
beforeEach(() => { reflector = new JitReflector(); });
|
||||||
|
|
||||||
it('should create embedded templates for <ng-template> elements', () => {
|
it('should create embedded templates for <ng-template> elements', () => {
|
||||||
expect(humanizeTplAst(parse('<template></template>', [
|
|
||||||
]))).toEqual([[EmbeddedTemplateAst]]);
|
|
||||||
expect(humanizeTplAst(parse('<TEMPLATE></TEMPLATE>', [
|
|
||||||
]))).toEqual([[EmbeddedTemplateAst]]);
|
|
||||||
expect(humanizeTplAst(parse('<ng-template></ng-template>', [
|
expect(humanizeTplAst(parse('<ng-template></ng-template>', [
|
||||||
]))).toEqual([[EmbeddedTemplateAst]]);
|
]))).toEqual([[EmbeddedTemplateAst]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create embedded templates for <ng-template> elements regardless the namespace',
|
it('should create embedded templates for <ng-template> elements regardless the namespace',
|
||||||
() => {
|
() => {
|
||||||
expect(humanizeTplAst(parse('<svg><template></template></svg>', []))).toEqual([
|
|
||||||
[ElementAst, ':svg:svg'],
|
|
||||||
[EmbeddedTemplateAst],
|
|
||||||
]);
|
|
||||||
expect(humanizeTplAst(parse('<svg><ng-template></ng-template></svg>', []))).toEqual([
|
expect(humanizeTplAst(parse('<svg><ng-template></ng-template></svg>', []))).toEqual([
|
||||||
[ElementAst, ':svg:svg'],
|
[ElementAst, ':svg:svg'],
|
||||||
[EmbeddedTemplateAst],
|
[EmbeddedTemplateAst],
|
||||||
|
@ -1521,12 +1533,6 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support references via #...', () => {
|
it('should support references via #...', () => {
|
||||||
expect(humanizeTplAst(parse('<template #a>', []))).toEqual([
|
|
||||||
[EmbeddedTemplateAst],
|
|
||||||
[
|
|
||||||
ReferenceAst, 'a', createTokenForExternalReference(reflector, Identifiers.TemplateRef)
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
expect(humanizeTplAst(parse('<ng-template #a>', []))).toEqual([
|
expect(humanizeTplAst(parse('<ng-template #a>', []))).toEqual([
|
||||||
[EmbeddedTemplateAst],
|
[EmbeddedTemplateAst],
|
||||||
[
|
[
|
||||||
|
@ -1536,12 +1542,6 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support references via ref-...', () => {
|
it('should support references via ref-...', () => {
|
||||||
expect(humanizeTplAst(parse('<template ref-a>', []))).toEqual([
|
|
||||||
[EmbeddedTemplateAst],
|
|
||||||
[
|
|
||||||
ReferenceAst, 'a', createTokenForExternalReference(reflector, Identifiers.TemplateRef)
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
expect(humanizeTplAst(parse('<ng-template ref-a>', []))).toEqual([
|
expect(humanizeTplAst(parse('<ng-template ref-a>', []))).toEqual([
|
||||||
[EmbeddedTemplateAst],
|
[EmbeddedTemplateAst],
|
||||||
[
|
[
|
||||||
|
@ -1551,10 +1551,6 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse variables via let-...', () => {
|
it('should parse variables via let-...', () => {
|
||||||
expect(humanizeTplAst(parse('<template let-a="b">', []))).toEqual([
|
|
||||||
[EmbeddedTemplateAst],
|
|
||||||
[VariableAst, 'a', 'b'],
|
|
||||||
]);
|
|
||||||
expect(humanizeTplAst(parse('<ng-template let-a="b">', []))).toEqual([
|
expect(humanizeTplAst(parse('<ng-template let-a="b">', []))).toEqual([
|
||||||
[EmbeddedTemplateAst],
|
[EmbeddedTemplateAst],
|
||||||
[VariableAst, 'a', 'b'],
|
[VariableAst, 'a', 'b'],
|
||||||
|
@ -1567,10 +1563,6 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
||||||
selector: '[a]',
|
selector: '[a]',
|
||||||
type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}})
|
type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}})
|
||||||
}).toSummary();
|
}).toSummary();
|
||||||
expect(humanizeTplAst(parse('<template let-a="b"></template>', [dirA]))).toEqual([
|
|
||||||
[EmbeddedTemplateAst],
|
|
||||||
[VariableAst, 'a', 'b'],
|
|
||||||
]);
|
|
||||||
expect(humanizeTplAst(parse('<ng-template let-a="b"></ng-template>', [dirA]))).toEqual([
|
expect(humanizeTplAst(parse('<ng-template let-a="b"></ng-template>', [dirA]))).toEqual([
|
||||||
[EmbeddedTemplateAst],
|
[EmbeddedTemplateAst],
|
||||||
[VariableAst, 'a', 'b'],
|
[VariableAst, 'a', 'b'],
|
||||||
|
@ -1580,30 +1572,6 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('inline templates', () => {
|
describe('inline templates', () => {
|
||||||
it('should wrap the element into an EmbeddedTemplateAST', () => {
|
|
||||||
expect(humanizeTplAst(parse('<div template>', []))).toEqual([
|
|
||||||
[EmbeddedTemplateAst],
|
|
||||||
[ElementAst, 'div'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should wrap the element with data-template attribute into an EmbeddedTemplateAST ',
|
|
||||||
() => {
|
|
||||||
expect(humanizeTplAst(parse('<div data-template>', []))).toEqual([
|
|
||||||
[EmbeddedTemplateAst],
|
|
||||||
[ElementAst, 'div'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should parse bound properties', () => {
|
|
||||||
expect(humanizeTplAst(parse('<div template="ngIf test">', [ngIf]))).toEqual([
|
|
||||||
[EmbeddedTemplateAst],
|
|
||||||
[DirectiveAst, ngIf],
|
|
||||||
[BoundDirectivePropertyAst, 'ngIf', 'test'],
|
|
||||||
[ElementAst, 'div'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should report an error on variables declared with #', () => {
|
it('should report an error on variables declared with #', () => {
|
||||||
expect(() => humanizeTplAst(parse('<div *ngIf="#a=b">', [])))
|
expect(() => humanizeTplAst(parse('<div *ngIf="#a=b">', [])))
|
||||||
.toThrowError(/Parser Error: Unexpected token # at column 1/);
|
.toThrowError(/Parser Error: Unexpected token # at column 1/);
|
||||||
|
@ -1646,7 +1614,7 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
||||||
selector: '[b]',
|
selector: '[b]',
|
||||||
type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirB'}})
|
type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirB'}})
|
||||||
}).toSummary();
|
}).toSummary();
|
||||||
expect(humanizeTplAst(parse('<div template="a b" b>', [dirA, dirB]))).toEqual([
|
expect(humanizeTplAst(parse('<div *a="b" b>', [dirA, dirB]))).toEqual([
|
||||||
[EmbeddedTemplateAst], [DirectiveAst, dirA], [BoundDirectivePropertyAst, 'a', 'b'],
|
[EmbeddedTemplateAst], [DirectiveAst, dirA], [BoundDirectivePropertyAst, 'a', 'b'],
|
||||||
[ElementAst, 'div'], [AttrAst, 'b', ''], [DirectiveAst, dirB]
|
[ElementAst, 'div'], [AttrAst, 'b', ''], [DirectiveAst, dirB]
|
||||||
]);
|
]);
|
||||||
|
@ -1658,8 +1626,12 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
||||||
selector: '[a]',
|
selector: '[a]',
|
||||||
type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}})
|
type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}})
|
||||||
}).toSummary();
|
}).toSummary();
|
||||||
expect(humanizeTplAst(parse('<div template="let a=b">', [dirA]))).toEqual([
|
expect(
|
||||||
[EmbeddedTemplateAst], [VariableAst, 'a', 'b'], [ElementAst, 'div']
|
humanizeTplAst(parse('<ng-template let-a="b"><div></div></ng-template>', [dirA])))
|
||||||
|
.toEqual([
|
||||||
|
[EmbeddedTemplateAst],
|
||||||
|
[VariableAst, 'a', 'b'],
|
||||||
|
[ElementAst, 'div'],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1760,13 +1732,11 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
||||||
|
|
||||||
describe('embedded templates', () => {
|
describe('embedded templates', () => {
|
||||||
it('should project embedded templates with wildcard selector', () => {
|
it('should project embedded templates with wildcard selector', () => {
|
||||||
expect(humanizeContentProjection(parse(
|
expect(humanizeContentProjection(
|
||||||
'<div><template></template><ng-template></ng-template></div>',
|
parse('<div><ng-template></ng-template></div>', [createComp('div', ['*'])])))
|
||||||
[createComp('div', ['*'])])))
|
|
||||||
.toEqual([
|
.toEqual([
|
||||||
['div', null],
|
['div', null],
|
||||||
['template', 0],
|
['template', 0],
|
||||||
['template', 0],
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1848,14 +1818,12 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should override <ng-template>', () => {
|
it('should override <ng-template>', () => {
|
||||||
expect(
|
expect(humanizeContentProjection(parse(
|
||||||
humanizeContentProjection(parse(
|
'<div><ng-template ngProjectAs="b"></ng-template></div>',
|
||||||
'<div><template ngProjectAs="b"></template><ng-template ngProjectAs="b"></ng-template></div>',
|
|
||||||
[createComp('div', ['template', 'b'])])))
|
[createComp('div', ['template', 'b'])])))
|
||||||
.toEqual([
|
.toEqual([
|
||||||
['div', null],
|
['div', null],
|
||||||
['template', 1],
|
['template', 1],
|
||||||
['template', 1],
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1894,26 +1862,14 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
||||||
`<ng-content> element cannot have content. ("[ERROR ->]<ng-content>content</ng-content>"): TestComp@0:0`);
|
`<ng-content> element cannot have content. ("[ERROR ->]<ng-content>content</ng-content>"): TestComp@0:0`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should treat *attr on a template element as valid', () => {
|
it('should treat *attr on a template element as valid',
|
||||||
expect(() => parse('<template *ngIf>', [])).not.toThrowError();
|
() => { expect(() => parse('<ng-template *ngIf>', [])).not.toThrowError(); });
|
||||||
expect(() => parse('<ng-template *ngIf>', [])).not.toThrowError();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should treat template attribute on a template element as valid', () => {
|
|
||||||
expect(() => parse('<template template="ngIf">', [])).not.toThrowError();
|
|
||||||
expect(() => parse('<ng-template template="ngIf">', [])).not.toThrowError();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should report when multiple *attrs are used on the same element', () => {
|
it('should report when multiple *attrs are used on the same element', () => {
|
||||||
expect(() => parse('<div *ngIf *ngFor>', [])).toThrowError(`Template parse errors:
|
expect(() => parse('<div *ngIf *ngFor>', [])).toThrowError(`Template parse errors:
|
||||||
Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with * ("<div *ngIf [ERROR ->]*ngFor>"): TestComp@0:11`);
|
Can't have multiple template bindings on one element. Use only one attribute prefixed with * ("<div *ngIf [ERROR ->]*ngFor>"): TestComp@0:11`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should report when mix of template and *attrs are used on the same element', () => {
|
|
||||||
expect(() => parse('<span template="ngIf" *ngFor>', []))
|
|
||||||
.toThrowError(`Template parse errors:
|
|
||||||
Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with * ("<span template="ngIf" [ERROR ->]*ngFor>"): TestComp@0:22`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should report invalid property names', () => {
|
it('should report invalid property names', () => {
|
||||||
expect(() => parse('<div [invalidProp]></div>', [])).toThrowError(`Template parse errors:
|
expect(() => parse('<div [invalidProp]></div>', [])).toThrowError(`Template parse errors:
|
||||||
|
@ -1977,12 +1933,6 @@ Parser Error: Unexpected token 'b' at column 3 in [a b] in TestComp@0:5 ("<div [
|
||||||
template: compileTemplateMetadata({ngContentSelectors: []})
|
template: compileTemplateMetadata({ngContentSelectors: []})
|
||||||
}).toSummary();
|
}).toSummary();
|
||||||
|
|
||||||
expect(() => parse('<template [a]="b" (e)="f"></template>', [dirA]))
|
|
||||||
.toThrowError(`Template parse errors:
|
|
||||||
Event binding e not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "@NgModule.declarations". ("<template [a]="b" [ERROR ->](e)="f"></template>"): TestComp@0:18
|
|
||||||
Components on an embedded template: DirA ("[ERROR ->]<template [a]="b" (e)="f"></template>"): TestComp@0:0
|
|
||||||
Property binding a not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "@NgModule.declarations". ("[ERROR ->]<template [a]="b" (e)="f"></template>"): TestComp@0:0`);
|
|
||||||
|
|
||||||
expect(() => parse('<ng-template [a]="b" (e)="f"></ng-template>', [dirA]))
|
expect(() => parse('<ng-template [a]="b" (e)="f"></ng-template>', [dirA]))
|
||||||
.toThrowError(`Template parse errors:
|
.toThrowError(`Template parse errors:
|
||||||
Event binding e not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "@NgModule.declarations". ("<ng-template [a]="b" [ERROR ->](e)="f"></ng-template>"): TestComp@0:21
|
Event binding e not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "@NgModule.declarations". ("<ng-template [a]="b" [ERROR ->](e)="f"></ng-template>"): TestComp@0:21
|
||||||
|
@ -2093,8 +2043,6 @@ Property binding a not used by any directive on an embedded template. Make sure
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support embedded template', () => {
|
it('should support embedded template', () => {
|
||||||
expect(humanizeTplAstSourceSpans(parse('<template></template>', [
|
|
||||||
]))).toEqual([[EmbeddedTemplateAst, '<template>']]);
|
|
||||||
expect(humanizeTplAstSourceSpans(parse('<ng-template></ng-template>', [
|
expect(humanizeTplAstSourceSpans(parse('<ng-template></ng-template>', [
|
||||||
]))).toEqual([[EmbeddedTemplateAst, '<ng-template>']]);
|
]))).toEqual([[EmbeddedTemplateAst, '<ng-template>']]);
|
||||||
});
|
});
|
||||||
|
@ -2112,10 +2060,6 @@ Property binding a not used by any directive on an embedded template. Make sure
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support variables', () => {
|
it('should support variables', () => {
|
||||||
expect(humanizeTplAstSourceSpans(parse('<template let-a="b"></template>', []))).toEqual([
|
|
||||||
[EmbeddedTemplateAst, '<template let-a="b">'],
|
|
||||||
[VariableAst, 'a', 'b', 'let-a="b"'],
|
|
||||||
]);
|
|
||||||
expect(humanizeTplAstSourceSpans(parse('<ng-template let-a="b"></ng-template>', [])))
|
expect(humanizeTplAstSourceSpans(parse('<ng-template let-a="b"></ng-template>', [])))
|
||||||
.toEqual([
|
.toEqual([
|
||||||
[EmbeddedTemplateAst, '<ng-template let-a="b">'],
|
[EmbeddedTemplateAst, '<ng-template let-a="b">'],
|
||||||
|
@ -2342,47 +2286,6 @@ The pipe 'test' could not be found ("{{[ERROR ->]a | test}}"): TestComp@0:2`);
|
||||||
...humanizedExpandedForm, ...humanizedExpandedForm
|
...humanizedExpandedForm, ...humanizedExpandedForm
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Template Parser - `<template>` support disabled by default', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
TestBed.configureCompiler({
|
|
||||||
providers: [
|
|
||||||
{provide: Console, useValue: console},
|
|
||||||
{provide: CompilerConfig, useValue: new CompilerConfig()}
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
commonBeforeEach();
|
|
||||||
|
|
||||||
it('should support * directives', () => {
|
|
||||||
expect(humanizeTplAst(parse('<div *ngIf>', [ngIf]))).toEqual([
|
|
||||||
[EmbeddedTemplateAst],
|
|
||||||
[DirectiveAst, ngIf],
|
|
||||||
[BoundDirectivePropertyAst, 'ngIf', 'null'],
|
|
||||||
[ElementAst, 'div'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should support <ng-template>', () => {
|
|
||||||
expect(humanizeTplAst(parse('<ng-template>', []))).toEqual([
|
|
||||||
[EmbeddedTemplateAst],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should treat <template> as a regular tag', () => {
|
|
||||||
expect(humanizeTplAst(parse('<template>', []))).toEqual([
|
|
||||||
[ElementAst, 'template'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not special case the template attribute', () => {
|
|
||||||
expect(humanizeTplAst(parse('<p template="ngFor">', []))).toEqual([
|
|
||||||
[ElementAst, 'p'],
|
|
||||||
[AttrAst, 'template', 'ngFor'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -90,9 +90,6 @@ export type CompilerOptions = {
|
||||||
defaultEncapsulation?: ViewEncapsulation,
|
defaultEncapsulation?: ViewEncapsulation,
|
||||||
providers?: StaticProvider[],
|
providers?: StaticProvider[],
|
||||||
missingTranslation?: MissingTranslationStrategy,
|
missingTranslation?: MissingTranslationStrategy,
|
||||||
// Whether to support the `<template>` tag and the `template` attribute to define angular
|
|
||||||
// templates. They have been deprecated in 4.x, `<ng-template>` should be used instead.
|
|
||||||
enableLegacyTemplate?: boolean,
|
|
||||||
preserveWhitespaces?: boolean,
|
preserveWhitespaces?: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -38,14 +38,7 @@ const ANCHOR_ELEMENT = new InjectionToken('AnchorElement');
|
||||||
function declareTests({useJit}: {useJit: boolean}) {
|
function declareTests({useJit}: {useJit: boolean}) {
|
||||||
describe('integration tests', function() {
|
describe('integration tests', function() {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => { TestBed.configureCompiler({useJit}); });
|
||||||
TestBed.configureCompiler({
|
|
||||||
useJit,
|
|
||||||
providers: [
|
|
||||||
{provide: CompilerConfig, useValue: new CompilerConfig({enableLegacyTemplate: true})}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('react to record changes', function() {
|
describe('react to record changes', function() {
|
||||||
it('should consume text node changes', () => {
|
it('should consume text node changes', () => {
|
||||||
|
@ -420,22 +413,6 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||||
expect(getDOM().isCommentNode(childNodesOfWrapper[0])).toBe(true);
|
expect(getDOM().isCommentNode(childNodesOfWrapper[0])).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support template directives via `template` attribute.', () => {
|
|
||||||
TestBed.configureTestingModule({declarations: [MyComp, SomeViewport]});
|
|
||||||
const template =
|
|
||||||
'<span template="some-viewport: let greeting=someTmpl">{{greeting}}</span>';
|
|
||||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
|
||||||
const fixture = TestBed.createComponent(MyComp);
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
const childNodesOfWrapper = getDOM().childNodes(fixture.nativeElement);
|
|
||||||
// 1 template + 2 copies.
|
|
||||||
expect(childNodesOfWrapper.length).toBe(3);
|
|
||||||
expect(childNodesOfWrapper[1]).toHaveText('hello');
|
|
||||||
expect(childNodesOfWrapper[2]).toHaveText('again');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow to transplant TemplateRefs into other ViewContainers', () => {
|
it('should allow to transplant TemplateRefs into other ViewContainers', () => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
|
|
@ -162,7 +162,6 @@ export class JitCompilerFactory implements CompilerFactory {
|
||||||
useJit: true,
|
useJit: true,
|
||||||
defaultEncapsulation: ViewEncapsulation.Emulated,
|
defaultEncapsulation: ViewEncapsulation.Emulated,
|
||||||
missingTranslation: MissingTranslationStrategy.Warning,
|
missingTranslation: MissingTranslationStrategy.Warning,
|
||||||
enableLegacyTemplate: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this._defaultOptions = [compilerOptions, ...defaultOptions];
|
this._defaultOptions = [compilerOptions, ...defaultOptions];
|
||||||
|
@ -182,7 +181,6 @@ export class JitCompilerFactory implements CompilerFactory {
|
||||||
// from the app providers
|
// from the app providers
|
||||||
defaultEncapsulation: opts.defaultEncapsulation,
|
defaultEncapsulation: opts.defaultEncapsulation,
|
||||||
missingTranslation: opts.missingTranslation,
|
missingTranslation: opts.missingTranslation,
|
||||||
enableLegacyTemplate: opts.enableLegacyTemplate,
|
|
||||||
preserveWhitespaces: opts.preserveWhitespaces,
|
preserveWhitespaces: opts.preserveWhitespaces,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -200,7 +198,6 @@ function _mergeOptions(optionsArr: CompilerOptions[]): CompilerOptions {
|
||||||
defaultEncapsulation: _lastDefined(optionsArr.map(options => options.defaultEncapsulation)),
|
defaultEncapsulation: _lastDefined(optionsArr.map(options => options.defaultEncapsulation)),
|
||||||
providers: _mergeArrays(optionsArr.map(options => options.providers !)),
|
providers: _mergeArrays(optionsArr.map(options => options.providers !)),
|
||||||
missingTranslation: _lastDefined(optionsArr.map(options => options.missingTranslation)),
|
missingTranslation: _lastDefined(optionsArr.map(options => options.missingTranslation)),
|
||||||
enableLegacyTemplate: _lastDefined(optionsArr.map(options => options.enableLegacyTemplate)),
|
|
||||||
preserveWhitespaces: _lastDefined(optionsArr.map(options => options.preserveWhitespaces)),
|
preserveWhitespaces: _lastDefined(optionsArr.map(options => options.preserveWhitespaces)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,6 @@ export declare type CompilerOptions = {
|
||||||
defaultEncapsulation?: ViewEncapsulation;
|
defaultEncapsulation?: ViewEncapsulation;
|
||||||
providers?: StaticProvider[];
|
providers?: StaticProvider[];
|
||||||
missingTranslation?: MissingTranslationStrategy;
|
missingTranslation?: MissingTranslationStrategy;
|
||||||
enableLegacyTemplate?: boolean;
|
|
||||||
preserveWhitespaces?: boolean;
|
preserveWhitespaces?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue