feat(animations): report errors when invalid CSS properties are detected (#18718)

Closes #18701

PR Close #18718
This commit is contained in:
Matias Niemelä
2017-08-15 16:11:11 -07:00
committed by Miško Hevery
parent ec56760c9b
commit 409688fe17
16 changed files with 88 additions and 52 deletions

View File

@ -20,7 +20,7 @@ export class Animation {
private _animationAst: Ast;
constructor(private _driver: AnimationDriver, input: AnimationMetadata|AnimationMetadata[]) {
const errors: any[] = [];
const ast = buildAnimationAst(input, errors);
const ast = buildAnimationAst(_driver, input, errors);
if (errors.length) {
const errorMessage = `animation validation failed:\n${errors.join("\n")}`;
throw new Error(errorMessage);

View File

@ -7,6 +7,7 @@
*/
import {AUTO_STYLE, AnimateTimings, AnimationAnimateChildMetadata, AnimationAnimateMetadata, AnimationAnimateRefMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationQueryMetadata, AnimationQueryOptions, AnimationReferenceMetadata, AnimationSequenceMetadata, AnimationStaggerMetadata, AnimationStateMetadata, AnimationStyleMetadata, AnimationTransitionMetadata, AnimationTriggerMetadata, style, ɵStyleData} from '@angular/animations';
import {AnimationDriver} from '../render/animation_driver';
import {getOrSetAsInMap} from '../render/shared';
import {ENTER_SELECTOR, LEAVE_SELECTOR, NG_ANIMATING_SELECTOR, NG_TRIGGER_SELECTOR, SUBSTITUTION_EXPR_START, copyObj, extractStyleParams, iteratorToArray, normalizeAnimationEntry, resolveTiming, validateStyleParams} from '../util';
@ -54,8 +55,9 @@ const SELF_TOKEN_REGEX = new RegExp(`\s*${SELF_TOKEN}\s*,?`, 'g');
* Otherwise an error will be thrown.
*/
export function buildAnimationAst(
metadata: AnimationMetadata | AnimationMetadata[], errors: any[]): Ast {
return new AnimationAstBuilderVisitor().build(metadata, errors);
driver: AnimationDriver, metadata: AnimationMetadata | AnimationMetadata[],
errors: any[]): Ast {
return new AnimationAstBuilderVisitor(driver).build(metadata, errors);
}
const LEAVE_TOKEN = ':leave';
@ -65,6 +67,8 @@ const ENTER_TOKEN_REGEX = new RegExp(ENTER_TOKEN, 'g');
const ROOT_SELECTOR = '';
export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
constructor(private _driver: AnimationDriver) {}
build(metadata: AnimationMetadata|AnimationMetadata[], errors: any[]): Ast {
const context = new AnimationAstBuilderContext(errors);
this._resetContextStyleTimingState(context);
@ -273,6 +277,12 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
if (typeof tuple == 'string') return;
Object.keys(tuple).forEach(prop => {
if (!this._driver.validateStyleProperty(prop)) {
context.errors.push(
`The provided animation property "${prop}" is not a supported CSS property for animations`);
return;
}
const collectedStyles = context.collectedStyles[context.currentQuerySelector !];
const collectedEntry = collectedStyles[prop];
let updateCollectedStyle = true;

View File

@ -447,7 +447,7 @@ export class AnimationTimelineContext {
private _driver: AnimationDriver, public element: any,
public subInstructions: ElementInstructionMap, public errors: any[],
public timelines: TimelineBuilder[], initialTimeline?: TimelineBuilder) {
this.currentTimeline = initialTimeline || new TimelineBuilder(element, 0);
this.currentTimeline = initialTimeline || new TimelineBuilder(this._driver, element, 0);
timelines.push(this.currentTimeline);
}
@ -530,7 +530,7 @@ export class AnimationTimelineContext {
easing: ''
};
const builder = new SubTimelineBuilder(
instruction.element, instruction.keyframes, instruction.preStyleProps,
this._driver, instruction.element, instruction.keyframes, instruction.preStyleProps,
instruction.postStyleProps, updatedTimings, instruction.stretchStartingKeyframe);
this.timelines.push(builder);
return updatedTimings;
@ -582,7 +582,7 @@ export class TimelineBuilder {
private _currentEmptyStepKeyframe: ɵStyleData|null = null;
constructor(
public element: any, public startTime: number,
private _driver: AnimationDriver, public element: any, public startTime: number,
private _elementTimelineStylesLookup?: Map<any, ɵStyleData>) {
if (!this._elementTimelineStylesLookup) {
this._elementTimelineStylesLookup = new Map<any, ɵStyleData>();
@ -632,7 +632,7 @@ export class TimelineBuilder {
fork(element: any, currentTime?: number): TimelineBuilder {
this.applyStylesToKeyframe();
return new TimelineBuilder(
element, currentTime || this.currentTime, this._elementTimelineStylesLookup);
this._driver, element, currentTime || this.currentTime, this._elementTimelineStylesLookup);
}
private _loadKeyframe() {
@ -796,10 +796,10 @@ class SubTimelineBuilder extends TimelineBuilder {
public timings: AnimateTimings;
constructor(
public element: any, public keyframes: ɵStyleData[], public preStyleProps: string[],
public postStyleProps: string[], timings: AnimateTimings,
driver: AnimationDriver, public element: any, public keyframes: ɵStyleData[],
public preStyleProps: string[], public postStyleProps: string[], timings: AnimateTimings,
private _stretchStartingKeyframe: boolean = false) {
super(element, timings.delay);
super(driver, element, timings.delay);
this.timings = {duration: timings.duration, delay: timings.delay, easing: timings.easing};
}