refactor(animations): ensure animation input/outputs are managed within the template parser (#11782)

Closes #11782
Closes #11601
Related #11707
This commit is contained in:
Matias Niemelä
2016-09-23 16:37:04 -04:00
committed by Rado Kirov
parent 45ad13560b
commit f1b6c6efa1
23 changed files with 325 additions and 399 deletions

View File

@ -10,7 +10,8 @@ import {AnimationMetadata, animate, group, sequence, style, transition, trigger}
import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
import {StringMapWrapper} from '../../../platform-browser-dynamic/src/facade/collection';
import {AnimationCompiler, CompiledAnimationTriggerResult} from '../../src/animation/animation_compiler';
import {AnimationCompiler, AnimationEntryCompileResult} from '../../src/animation/animation_compiler';
import {AnimationParser} from '../../src/animation/animation_parser';
import {CompileAnimationEntryMetadata, CompileDirectiveMetadata, CompileTemplateMetadata, CompileTypeMetadata} from '../../src/compile_metadata';
import {CompileMetadataResolver} from '../../src/metadata_resolver';
@ -20,12 +21,13 @@ export function main() {
beforeEach(
inject([CompileMetadataResolver], (res: CompileMetadataResolver) => { resolver = res; }));
var compiler = new AnimationCompiler();
const parser = new AnimationParser();
const compiler = new AnimationCompiler();
var compileAnimations =
(component: CompileDirectiveMetadata): CompiledAnimationTriggerResult => {
var result = compiler.compileComponent(component, []);
return result.triggers[0];
(component: CompileDirectiveMetadata): AnimationEntryCompileResult[] => {
const parsedAnimations = parser.parseComponent(component);
return compiler.compile(component.type.name, parsedAnimations);
};
var compileTriggers = (input: any[]) => {
@ -66,14 +68,5 @@ export function main() {
expect(capturedErrorMessage)
.toMatch(/Animation states via styles must be prefixed with a ":"/);
});
it('should throw an error when two or more animation triggers contain the same name', () => {
var t1Data: any[] = [];
var t2Data: any[] = [];
expect(() => {
compileTriggers([['myTrigger', t1Data], ['myTrigger', t2Data]]);
}).toThrowError(/The animation trigger "myTrigger" has already been registered on "myCmp"/);
});
});
}

View File

@ -11,7 +11,8 @@ import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe
import {expect} from '@angular/platform-browser/testing/matchers';
import {AnimationAst, AnimationEntryAst, AnimationGroupAst, AnimationKeyframeAst, AnimationSequenceAst, AnimationStateTransitionAst, AnimationStepAst, AnimationStylesAst} from '../../src/animation/animation_ast';
import {parseAnimationEntry} from '../../src/animation/animation_parser';
import {AnimationParser} from '../../src/animation/animation_parser';
import {CompileDirectiveMetadata, CompileTemplateMetadata, CompileTypeMetadata} from '../../src/compile_metadata';
import {StringMapWrapper} from '../../src/facade/collection';
import {CompileMetadataResolver} from '../../src/metadata_resolver';
import {FILL_STYLE_FLAG, flattenStyles} from '../private_import_core';
@ -46,9 +47,10 @@ export function main() {
inject([CompileMetadataResolver], (res: CompileMetadataResolver) => { resolver = res; }));
var parseAnimation = (data: AnimationMetadata[]) => {
var entry = trigger('myAnimation', [transition('state1 => state2', sequence(data))]);
var compiledAnimationEntry = resolver.getAnimationEntryMetadata(entry);
return parseAnimationEntry(compiledAnimationEntry);
const entry = trigger('myAnimation', [transition('state1 => state2', sequence(data))]);
const compiledAnimationEntry = resolver.getAnimationEntryMetadata(entry);
const parser = new AnimationParser();
return parser.parseEntry(compiledAnimationEntry);
};
var getAnimationAstFromEntryAst =

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompilePipeMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata} from '@angular/compiler/src/compile_metadata';
import {CompileAnimationEntryMetadata, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompilePipeMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata} from '@angular/compiler/src/compile_metadata';
import {DomElementSchemaRegistry} from '@angular/compiler/src/schema/dom_element_schema_registry';
import {ElementSchemaRegistry} from '@angular/compiler/src/schema/element_schema_registry';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAstType, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '@angular/compiler/src/template_parser/template_ast';
@ -16,7 +16,6 @@ import {SchemaMetadata, SecurityContext, Type} from '@angular/core';
import {Console} from '@angular/core/src/console';
import {TestBed} from '@angular/core/testing';
import {afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Identifiers, identifierToken, resolveIdentifierToken} from '../../src/identifiers';
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../src/ml_parser/interpolation_config';
import {MockSchemaRegistry} from '../../testing/index';
@ -32,9 +31,9 @@ const MOCK_SCHEMA_REGISTRY = [{
export function main() {
var ngIf: CompileDirectiveMetadata;
var parse:
(template: string, directives: CompileDirectiveMetadata[], pipes?: CompilePipeMetadata[]) =>
TemplateAst[];
var parse: (
template: string, directives: CompileDirectiveMetadata[], pipes?: CompilePipeMetadata[],
schemas?: SchemaMetadata[]) => TemplateAst[];
var console: ArrayConsole;
function commonBeforeEach() {
@ -43,14 +42,18 @@ export function main() {
TestBed.configureCompiler({providers: [{provide: Console, useValue: console}]});
});
beforeEach(inject([TemplateParser], (parser: TemplateParser) => {
var someAnimation = new CompileAnimationEntryMetadata('someAnimation', []);
var someTemplate = new CompileTemplateMetadata({animations: [someAnimation]});
var component = CompileDirectiveMetadata.create({
selector: 'root',
template: someTemplate,
type: new CompileTypeMetadata(
{moduleUrl: someModuleUrl, name: 'Root', reference: {} as Type<any>}),
isComponent: true
});
ngIf = CompileDirectiveMetadata.create({
selector: '[ngIf]',
template: someTemplate,
type: new CompileTypeMetadata(
{moduleUrl: someModuleUrl, name: 'NgIf', reference: {} as Type<any>}),
inputs: ['ngIf']
@ -302,27 +305,31 @@ Can't bind to 'invalidProp' since it isn't a known property of 'my-component'.
]);
});
it('should parse bound properties via bind-animate- and not report them as animation properties',
it('should parse bound properties via bind-animate- and not report them as attributes',
() => {
expect(humanizeTplAst(parse('<div bind-animate-something="value2">', []))).toEqual([
[ElementAst, 'div'],
[
BoundElementPropertyAst, PropertyBindingType.Animation, 'something', 'value2', null
]
]);
expect(humanizeTplAst(parse('<div bind-animate-someAnimation="value2">', [], [], [])))
.toEqual([
[ElementAst, 'div'],
[
BoundElementPropertyAst, PropertyBindingType.Animation, 'someAnimation',
'value2', null
]
]);
});
it('should throw an error when parsing detects non-bound properties via @ that contain a value',
() => {
expect(() => { parse('<div @something="value2">', []); })
expect(() => { parse('<div @someAnimation="value2">', [], [], []); })
.toThrowError(
/Assigning animation triggers via @prop="exp" attributes with an expression is invalid. Use property bindings \(e.g. \[@prop\]="exp"\) or use an attribute without a value \(e.g. @prop\) instead. \("<div \[ERROR ->\]@something="value2">"\): TestComp@0:5/);
/Assigning animation triggers via @prop="exp" attributes with an expression is invalid. Use property bindings \(e.g. \[@prop\]="exp"\) or use an attribute without a value \(e.g. @prop\) instead. \("<div \[ERROR ->\]@someAnimation="value2">"\): TestComp@0:5/);
});
it('should not issue a warning when host attributes contain a valid property-bound animation trigger',
() => {
const animationEntries = [new CompileAnimationEntryMetadata('prop', [])];
var dirA = CompileDirectiveMetadata.create({
selector: 'div',
template: new CompileTemplateMetadata({animations: animationEntries}),
type: new CompileTypeMetadata(
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
host: {'[@prop]': 'expr'}
@ -360,14 +367,17 @@ Can't bind to 'invalidProp' since it isn't a known property of 'my-component'.
it('should not issue a warning when an animation property is bound without an expression',
() => {
humanizeTplAst(parse('<div @something>', []));
humanizeTplAst(parse('<div @someAnimation>', [], [], []));
expect(console.warnings.length).toEqual(0);
});
it('should parse bound properties via [@] and not report them as attributes', () => {
expect(humanizeTplAst(parse('<div [@something]="value2">', []))).toEqual([
expect(humanizeTplAst(parse('<div [@someAnimation]="value2">', [], [], []))).toEqual([
[ElementAst, 'div'],
[BoundElementPropertyAst, PropertyBindingType.Animation, 'something', 'value2', null]
[
BoundElementPropertyAst, PropertyBindingType.Animation, 'someAnimation', 'value2',
null
]
]);
});
});