build: reformat repo to new clang@1.4.0 (#36613)

PR Close #36613
This commit is contained in:
Joey Perrott
2020-04-13 16:40:21 -07:00
committed by atscott
parent 5e80e7e216
commit 698b0288be
1160 changed files with 31667 additions and 24000 deletions

View File

@ -22,7 +22,7 @@ export class Animation {
const errors: any[] = [];
const ast = buildAnimationAst(_driver, input, errors);
if (errors.length) {
const errorMessage = `animation validation failed:\n${errors.join("\n")}`;
const errorMessage = `animation validation failed:\n${errors.join('\n')}`;
throw new Error(errorMessage);
}
this._animationAst = ast;
@ -42,7 +42,7 @@ export class Animation {
this._driver, element, this._animationAst, ENTER_CLASSNAME, LEAVE_CLASSNAME, start, dest,
options, subInstructions, errors);
if (errors.length) {
const errorMessage = `animation building failed:\n${errors.join("\n")}`;
const errorMessage = `animation building failed:\n${errors.join('\n')}`;
throw new Error(errorMessage);
}
return result;

View File

@ -74,7 +74,9 @@ export interface StyleAst extends Ast<AnimationMetadataType.Style> {
isEmptyStep?: boolean;
}
export interface KeyframesAst extends Ast<AnimationMetadataType.Keyframes> { styles: StyleAst[]; }
export interface KeyframesAst extends Ast<AnimationMetadataType.Keyframes> {
styles: StyleAst[];
}
export interface ReferenceAst extends Ast<AnimationMetadataType.Reference> {
animation: Ast<AnimationMetadataType>;

View File

@ -5,11 +5,11 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
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 {AnimateTimings, AnimationAnimateChildMetadata, AnimationAnimateMetadata, AnimationAnimateRefMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationQueryMetadata, AnimationQueryOptions, AnimationReferenceMetadata, AnimationSequenceMetadata, AnimationStaggerMetadata, AnimationStateMetadata, AnimationStyleMetadata, AnimationTransitionMetadata, AnimationTriggerMetadata, AUTO_STYLE, 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, visitDslNode} from '../util';
import {copyObj, ENTER_SELECTOR, extractStyleParams, iteratorToArray, LEAVE_SELECTOR, NG_ANIMATING_SELECTOR, NG_TRIGGER_SELECTOR, normalizeAnimationEntry, resolveTiming, SUBSTITUTION_EXPR_START, validateStyleParams, visitDslNode} from '../util';
import {AnimateAst, AnimateChildAst, AnimateRefAst, Ast, DynamicTimingAst, GroupAst, KeyframesAst, QueryAst, ReferenceAst, SequenceAst, StaggerAst, StateAst, StyleAst, TimingAst, TransitionAst, TriggerAst} from './animation_ast';
import {AnimationDslVisitor} from './animation_dsl_visitor';
@ -55,7 +55,7 @@ const SELF_TOKEN_REGEX = new RegExp(`\s*${SELF_TOKEN}\s*,?`, 'g');
* Otherwise an error will be thrown.
*/
export function buildAnimationAst(
driver: AnimationDriver, metadata: AnimationMetadata | AnimationMetadata[],
driver: AnimationDriver, metadata: AnimationMetadata|AnimationMetadata[],
errors: any[]): Ast<AnimationMetadataType> {
return new AnimationAstBuilderVisitor(driver).build(metadata, errors);
}
@ -114,7 +114,11 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
return {
type: AnimationMetadataType.Trigger,
name: metadata.name, states, transitions, queryCount, depCount,
name: metadata.name,
states,
transitions,
queryCount,
depCount,
options: null
};
}
@ -139,8 +143,10 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
});
if (missingSubs.size) {
const missingSubsArr = iteratorToArray(missingSubs.values());
context.errors.push(
`state("${metadata.name}", ...) must define default values for all the following style substitutions: ${missingSubsArr.join(', ')}`);
context.errors.push(`state("${
metadata
.name}", ...) must define default values for all the following style substitutions: ${
missingSubsArr.join(', ')}`);
}
}
@ -210,7 +216,7 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
let isEmpty = false;
if (!styleMetadata) {
isEmpty = true;
const newStyleData: {[prop: string]: string | number} = {};
const newStyleData: {[prop: string]: string|number} = {};
if (timingAst.easing) {
newStyleData['easing'] = timingAst.easing;
}
@ -239,9 +245,9 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
private _makeStyleAst(metadata: AnimationStyleMetadata, context: AnimationAstBuilderContext):
StyleAst {
const styles: (ɵStyleData | string)[] = [];
const styles: (ɵStyleData|string)[] = [];
if (Array.isArray(metadata.styles)) {
(metadata.styles as(ɵStyleData | string)[]).forEach(styleTuple => {
(metadata.styles as (ɵStyleData | string)[]).forEach(styleTuple => {
if (typeof styleTuple == 'string') {
if (styleTuple == AUTO_STYLE) {
styles.push(styleTuple);
@ -282,7 +288,8 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
type: AnimationMetadataType.Style,
styles,
easing: collectedEasing,
offset: metadata.offset, containsDynamicStyles,
offset: metadata.offset,
containsDynamicStyles,
options: null
};
}
@ -300,19 +307,22 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
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`);
context.errors.push(`The provided animation property "${
prop}" is not a supported CSS property for animations`);
return;
}
const collectedStyles = context.collectedStyles[context.currentQuerySelector !];
const collectedStyles = context.collectedStyles[context.currentQuerySelector!];
const collectedEntry = collectedStyles[prop];
let updateCollectedStyle = true;
if (collectedEntry) {
if (startTime != endTime && startTime >= collectedEntry.startTime &&
endTime <= collectedEntry.endTime) {
context.errors.push(
`The CSS property "${prop}" that exists between the times of "${collectedEntry.startTime}ms" and "${collectedEntry.endTime}ms" is also being animated in a parallel animation between the times of "${startTime}ms" and "${endTime}ms"`);
context.errors.push(`The CSS property "${prop}" that exists between the times of "${
collectedEntry.startTime}ms" and "${
collectedEntry
.endTime}ms" is also being animated in a parallel animation between the times of "${
startTime}ms" and "${endTime}ms"`);
updateCollectedStyle = false;
}
@ -383,7 +393,7 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
const limit = length - 1;
const currentTime = context.currentTime;
const currentAnimateTimings = context.currentAnimateTimings !;
const currentAnimateTimings = context.currentAnimateTimings!;
const animateDuration = currentAnimateTimings.duration;
keyframes.forEach((kf, i) => {
const offset = generatedOffset > 0 ? (i == limit ? 1 : (generatedOffset * i)) : offsets[i];
@ -427,7 +437,7 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
}
visitQuery(metadata: AnimationQueryMetadata, context: AnimationAstBuilderContext): QueryAst {
const parentSelector = context.currentQuerySelector !;
const parentSelector = context.currentQuerySelector!;
const options = (metadata.options || {}) as AnimationQueryOptions;
context.queryCount++;
@ -445,7 +455,9 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
type: AnimationMetadataType.Query,
selector,
limit: options.limit || 0,
optional: !!options.optional, includeSelf, animation,
optional: !!options.optional,
includeSelf,
animation,
originalSelector: metadata.selector,
options: normalizeAnimationOptions(metadata.options)
};
@ -462,7 +474,8 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
return {
type: AnimationMetadataType.Stagger,
animation: visitDslNode(this, normalizeAnimationEntry(metadata.animation), context), timings,
animation: visitDslNode(this, normalizeAnimationEntry(metadata.animation), context),
timings,
options: null
};
}
@ -483,7 +496,7 @@ function normalizeSelector(selector: string): [string, boolean] {
}
function normalizeParams(obj: {[key: string]: any} | any): {[key: string]: any}|null {
function normalizeParams(obj: {[key: string]: any}|any): {[key: string]: any}|null {
return obj ? copyObj(obj) : null;
}
@ -504,7 +517,7 @@ export class AnimationAstBuilderContext {
constructor(public errors: any[]) {}
}
function consumeOffset(styles: ɵStyleData | string | (ɵStyleData | string)[]): number|null {
function consumeOffset(styles: ɵStyleData|string|(ɵStyleData | string)[]): number|null {
if (typeof styles == 'string') return null;
let offset: number|null = null;
@ -529,7 +542,7 @@ function isObject(value: any): boolean {
return !Array.isArray(value) && typeof value == 'object';
}
function constructTimingAst(value: string | number | AnimateTimings, errors: any[]) {
function constructTimingAst(value: string|number|AnimateTimings, errors: any[]) {
let timings: AnimateTimings|null = null;
if (value.hasOwnProperty('duration')) {
timings = value as AnimateTimings;
@ -551,11 +564,11 @@ function constructTimingAst(value: string | number | AnimateTimings, errors: any
return makeTimingAst(timings.duration, timings.delay, timings.easing);
}
function normalizeAnimationOptions(options: AnimationOptions | null): AnimationOptions {
function normalizeAnimationOptions(options: AnimationOptions|null): AnimationOptions {
if (options) {
options = copyObj(options);
if (options['params']) {
options['params'] = normalizeParams(options['params']) !;
options['params'] = normalizeParams(options['params'])!;
}
} else {
options = {};
@ -563,6 +576,6 @@ function normalizeAnimationOptions(options: AnimationOptions | null): AnimationO
return options;
}
function makeTimingAst(duration: number, delay: number, easing: string | null): TimingAst {
function makeTimingAst(duration: number, delay: number, easing: string|null): TimingAst {
return {duration, delay, easing};
}

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {AUTO_STYLE, AnimateChildOptions, AnimateTimings, AnimationMetadataType, AnimationOptions, AnimationQueryOptions, ɵPRE_STYLE as PRE_STYLE, ɵStyleData} from '@angular/animations';
import {AnimateChildOptions, AnimateTimings, AnimationMetadataType, AnimationOptions, AnimationQueryOptions, AUTO_STYLE, ɵPRE_STYLE as PRE_STYLE, ɵStyleData} from '@angular/animations';
import {AnimationDriver} from '../render/animation_driver';
import {copyObj, copyStyles, interpolateParams, iteratorToArray, resolveTiming, resolveTimingValue, visitDslNode} from '../util';
@ -301,7 +301,7 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
visitStyle(ast: StyleAst, context: AnimationTimelineContext) {
const timeline = context.currentTimeline;
const timings = context.currentAnimateTimings !;
const timings = context.currentAnimateTimings!;
// this is a special case for when a style() call
// directly follows an animate() call (but not inside of an animate() call)
@ -320,8 +320,8 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
}
visitKeyframes(ast: KeyframesAst, context: AnimationTimelineContext) {
const currentAnimateTimings = context.currentAnimateTimings !;
const startTime = (context.currentTimeline !).duration;
const currentAnimateTimings = context.currentAnimateTimings!;
const startTime = (context.currentTimeline!).duration;
const duration = currentAnimateTimings.duration;
const innerContext = context.createSubContext();
const innerTimeline = innerContext.currentTimeline;
@ -351,8 +351,9 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
const options = (ast.options || {}) as AnimationQueryOptions;
const delay = options.delay ? resolveTimingValue(options.delay) : 0;
if (delay && (context.previousNode.type === AnimationMetadataType.Style ||
(startTime == 0 && context.currentTimeline.getCurrentStyleProperties().length))) {
if (delay &&
(context.previousNode.type === AnimationMetadataType.Style ||
(startTime == 0 && context.currentTimeline.getCurrentStyleProperties().length))) {
context.currentTimeline.snapshotCurrentStyles();
context.previousNode = DEFAULT_NOOP_PREVIOUS_NODE;
}
@ -365,7 +366,6 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
context.currentQueryTotal = elms.length;
let sameElementTimeline: TimelineBuilder|null = null;
elms.forEach((element, i) => {
context.currentQueryIndex = i;
const innerContext = context.createSubContext(ast.options, element);
if (delay) {
@ -400,7 +400,7 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
}
visitStagger(ast: StaggerAst, context: AnimationTimelineContext) {
const parentContext = context.parentContext !;
const parentContext = context.parentContext!;
const tl = context.currentTimeline;
const timings = ast.timings;
const duration = Math.abs(timings.duration);
@ -460,7 +460,9 @@ export class AnimationTimelineContext {
timelines.push(this.currentTimeline);
}
get params() { return this.options.params; }
get params() {
return this.options.params;
}
updateOptions(options: AnimationOptions|null, skipIfExists?: boolean) {
if (!options) return;
@ -479,7 +481,7 @@ export class AnimationTimelineContext {
const newParams = newOptions.params;
if (newParams) {
let paramsToUpdate: {[name: string]: any} = optionsToUpdate.params !;
let paramsToUpdate: {[name: string]: any} = optionsToUpdate.params!;
if (!paramsToUpdate) {
paramsToUpdate = this.options.params = {};
}
@ -498,7 +500,9 @@ export class AnimationTimelineContext {
const oldParams = this.options.params;
if (oldParams) {
const params: {[name: string]: any} = options['params'] = {};
Object.keys(oldParams).forEach(name => { params[name] = oldParams[name]; });
Object.keys(oldParams).forEach(name => {
params[name] = oldParams[name];
});
}
}
return options;
@ -576,8 +580,8 @@ export class AnimationTimelineContext {
}
if (!optional && results.length == 0) {
errors.push(
`\`query("${originalSelector}")\` returned zero elements. (Use \`query("${originalSelector}", { optional: true })\` if you wish to allow this.)`);
errors.push(`\`query("${originalSelector}")\` returned zero elements. (Use \`query("${
originalSelector}", { optional: true })\` if you wish to allow this.)`);
}
return results;
}
@ -587,7 +591,7 @@ export class AnimationTimelineContext {
export class TimelineBuilder {
public duration: number = 0;
// TODO(issue/24571): remove '!'.
public easing !: string | null;
public easing!: string|null;
private _previousKeyframe: ɵStyleData = {};
private _currentKeyframe: ɵStyleData = {};
private _keyframes = new Map<number, ɵStyleData>();
@ -606,7 +610,7 @@ export class TimelineBuilder {
}
this._localTimelineStyles = Object.create(this._backFill, {});
this._globalTimelineStyles = this._elementTimelineStylesLookup.get(element) !;
this._globalTimelineStyles = this._elementTimelineStylesLookup.get(element)!;
if (!this._globalTimelineStyles) {
this._globalTimelineStyles = this._localTimelineStyles;
this._elementTimelineStylesLookup.set(element, this._localTimelineStyles);
@ -625,9 +629,13 @@ export class TimelineBuilder {
}
}
getCurrentStyleProperties(): string[] { return Object.keys(this._currentKeyframe); }
getCurrentStyleProperties(): string[] {
return Object.keys(this._currentKeyframe);
}
get currentTime() { return this.startTime + this.duration; }
get currentTime() {
return this.startTime + this.duration;
}
delayNextStep(delay: number) {
// in the event that a style() step is placed right before a stagger()
@ -656,7 +664,7 @@ export class TimelineBuilder {
if (this._currentKeyframe) {
this._previousKeyframe = this._currentKeyframe;
}
this._currentKeyframe = this._keyframes.get(this.duration) !;
this._currentKeyframe = this._keyframes.get(this.duration)!;
if (!this._currentKeyframe) {
this._currentKeyframe = Object.create(this._backFill, {});
this._keyframes.set(this.duration, this._currentKeyframe);
@ -680,7 +688,9 @@ export class TimelineBuilder {
this._styleSummary[prop] = {time: this.currentTime, value};
}
allowOnlyTimelineStyles() { return this._currentEmptyStepKeyframe !== this._currentKeyframe; }
allowOnlyTimelineStyles() {
return this._currentEmptyStepKeyframe !== this._currentKeyframe;
}
applyEmptyStep(easing: string|null) {
if (easing) {
@ -748,7 +758,9 @@ export class TimelineBuilder {
});
}
getFinalKeyframe() { return this._keyframes.get(this.duration); }
getFinalKeyframe() {
return this._keyframes.get(this.duration);
}
get properties() {
const properties: string[] = [];
@ -820,7 +832,9 @@ class SubTimelineBuilder extends TimelineBuilder {
this.timings = {duration: timings.duration, delay: timings.delay, easing: timings.easing};
}
containsAnimation(): boolean { return this.keyframes.length > 1; }
containsAnimation(): boolean {
return this.keyframes.length > 1;
}
buildKeyframes(): AnimationTimelineInstruction {
let keyframes = this.keyframes;
@ -883,13 +897,15 @@ function roundOffset(offset: number, decimalPoints = 3): number {
return Math.round(offset * mult) / mult;
}
function flattenStyles(input: (ɵStyleData | string)[], allStyles: ɵStyleData) {
function flattenStyles(input: (ɵStyleData|string)[], allStyles: ɵStyleData) {
const styles: ɵStyleData = {};
let allProperties: string[];
input.forEach(token => {
if (token === '*') {
allProperties = allProperties || Object.keys(allStyles);
allProperties.forEach(prop => { styles[prop] = AUTO_STYLE; });
allProperties.forEach(prop => {
styles[prop] = AUTO_STYLE;
});
} else {
copyStyles(token as ɵStyleData, false, styles);
}

View File

@ -23,7 +23,7 @@ export interface AnimationTimelineInstruction extends AnimationEngineInstruction
export function createTimelineInstruction(
element: any, keyframes: ɵStyleData[], preStyleProps: string[], postStyleProps: string[],
duration: number, delay: number, easing: string | null = null,
duration: number, delay: number, easing: string|null = null,
subTimeline: boolean = false): AnimationTimelineInstruction {
return {
type: AnimationTransitionInstructionType.TimelineAnimation,
@ -33,6 +33,8 @@ export function createTimelineInstruction(
postStyleProps,
duration,
delay,
totalTime: duration + delay, easing, subTimeline
totalTime: duration + delay,
easing,
subTimeline
};
}

View File

@ -10,7 +10,7 @@ export declare type TransitionMatcherFn =
(fromState: any, toState: any, element: any, params: {[key: string]: any}) => boolean;
export function parseTransitionExpr(
transitionValue: string | TransitionMatcherFn, errors: string[]): TransitionMatcherFn[] {
transitionValue: string|TransitionMatcherFn, errors: string[]): TransitionMatcherFn[] {
const expressions: TransitionMatcherFn[] = [];
if (typeof transitionValue == 'string') {
transitionValue.split(/\s*,\s*/).forEach(

View File

@ -55,13 +55,16 @@ export class AnimationTransitionFactory {
const animationOptions = {params: {...transitionAnimationParams, ...nextAnimationParams}};
const timelines = skipAstBuild ? [] : buildAnimationTimelines(
driver, element, this.ast.animation, enterClassName,
leaveClassName, currentStateStyles, nextStateStyles,
animationOptions, subInstructions, errors);
const timelines = skipAstBuild ?
[] :
buildAnimationTimelines(
driver, element, this.ast.animation, enterClassName, leaveClassName, currentStateStyles,
nextStateStyles, animationOptions, subInstructions, errors);
let totalTime = 0;
timelines.forEach(tl => { totalTime = Math.max(tl.duration + tl.delay, totalTime); });
timelines.forEach(tl => {
totalTime = Math.max(tl.duration + tl.delay, totalTime);
});
if (errors.length) {
return createTransitionInstruction(

View File

@ -22,8 +22,8 @@ export function buildTrigger(name: string, ast: TriggerAst): AnimationTrigger {
}
/**
* @publicApi
*/
* @publicApi
*/
export class AnimationTrigger {
public transitionFactories: AnimationTransitionFactory[] = [];
public fallbackTransition: AnimationTransitionFactory;
@ -45,7 +45,9 @@ export class AnimationTrigger {
this.fallbackTransition = createFallbackTransition(name, this.states);
}
get containsQueries() { return this.ast.queryCount > 0; }
get containsQueries() {
return this.ast.queryCount > 0;
}
matchTransition(currentState: any, nextState: any, element: any, params: {[key: string]: any}):
AnimationTransitionFactory|null {

View File

@ -28,7 +28,11 @@ export class ElementInstructionMap {
existingInstructions.push(...instructions);
}
has(element: any): boolean { return this._map.has(element); }
has(element: any): boolean {
return this._map.has(element);
}
clear() { this._map.clear(); }
clear() {
this._map.clear();
}
}

View File

@ -20,7 +20,9 @@ export abstract class AnimationStyleNormalizer {
* @publicApi
*/
export class NoopAnimationStyleNormalizer {
normalizePropertyName(propertyName: string, errors: string[]): string { return propertyName; }
normalizePropertyName(propertyName: string, errors: string[]): string {
return propertyName;
}
normalizeStyleValue(
userProvidedProperty: string, normalizedProperty: string, value: string|number,

View File

@ -13,6 +13,6 @@ export {AnimationEngine as ɵAnimationEngine} from './render/animation_engine_ne
export {CssKeyframesDriver as ɵCssKeyframesDriver} from './render/css_keyframes/css_keyframes_driver';
export {CssKeyframesPlayer as ɵCssKeyframesPlayer} from './render/css_keyframes/css_keyframes_player';
export {containsElement as ɵcontainsElement, invokeQuery as ɵinvokeQuery, matchesElement as ɵmatchesElement, validateStyleProperty as ɵvalidateStyleProperty} from './render/shared';
export {WebAnimationsDriver as ɵWebAnimationsDriver, supportsWebAnimations as ɵsupportsWebAnimations} from './render/web_animations/web_animations_driver';
export {supportsWebAnimations as ɵsupportsWebAnimations, WebAnimationsDriver as ɵWebAnimationsDriver} from './render/web_animations/web_animations_driver';
export {WebAnimationsPlayer as ɵWebAnimationsPlayer} from './render/web_animations/web_animations_player';
export {allowPreviousPlayerStylesMerge as ɵallowPreviousPlayerStylesMerge} from './util';

View File

@ -15,13 +15,17 @@ import {containsElement, invokeQuery, matchesElement, validateStyleProperty} fro
*/
@Injectable()
export class NoopAnimationDriver implements AnimationDriver {
validateStyleProperty(prop: string): boolean { return validateStyleProperty(prop); }
validateStyleProperty(prop: string): boolean {
return validateStyleProperty(prop);
}
matchesElement(element: any, selector: string): boolean {
return matchesElement(element, selector);
}
containsElement(elm1: any, elm2: any): boolean { return containsElement(elm1, elm2); }
containsElement(elm1: any, elm2: any): boolean {
return containsElement(elm1, elm2);
}
query(element: any, selector: string, multi: boolean): any[] {
return invokeQuery(element, selector, multi);
@ -32,7 +36,7 @@ export class NoopAnimationDriver implements AnimationDriver {
}
animate(
element: any, keyframes: {[key: string]: string | number}[], duration: number, delay: number,
element: any, keyframes: {[key: string]: string|number}[], duration: number, delay: number,
easing: string, previousPlayers: any[] = [],
scrubberAccessRequested?: boolean): AnimationPlayer {
return new NoopAnimationPlayer(duration, delay);
@ -56,6 +60,6 @@ export abstract class AnimationDriver {
abstract computeStyle(element: any, prop: string, defaultValue?: string): string;
abstract animate(
element: any, keyframes: {[key: string]: string | number}[], duration: number, delay: number,
element: any, keyframes: {[key: string]: string|number}[], duration: number, delay: number,
easing?: string|null, previousPlayers?: any[], scrubberAccessRequested?: boolean): any;
}

View File

@ -5,6 +5,11 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export const enum AnimationTransitionInstructionType {TransitionAnimation, TimelineAnimation}
export const enum AnimationTransitionInstructionType {
TransitionAnimation,
TimelineAnimation
}
export interface AnimationEngineInstruction { type: AnimationTransitionInstructionType; }
export interface AnimationEngineInstruction {
type: AnimationTransitionInstructionType;
}

View File

@ -45,8 +45,8 @@ export class AnimationEngine {
const ast =
buildAnimationAst(this._driver, metadata as AnimationMetadata, errors) as TriggerAst;
if (errors.length) {
throw new Error(
`The animation trigger "${name}" has failed to build due to the following errors:\n - ${errors.join("\n - ")}`);
throw new Error(`The animation trigger "${
name}" has failed to build due to the following errors:\n - ${errors.join('\n - ')}`);
}
trigger = buildTrigger(name, ast);
this._triggerCache[cacheKey] = trigger;
@ -95,12 +95,16 @@ export class AnimationEngine {
return this._transitionEngine.listen(namespaceId, element, eventName, eventPhase, callback);
}
flush(microtaskId: number = -1): void { this._transitionEngine.flush(microtaskId); }
flush(microtaskId: number = -1): void {
this._transitionEngine.flush(microtaskId);
}
get players(): AnimationPlayer[] {
return (this._transitionEngine.players as AnimationPlayer[])
.concat(this._timelineEngine.players as AnimationPlayer[]);
}
whenRenderingDone(): Promise<any> { return this._transitionEngine.whenRenderingDone(); }
whenRenderingDone(): Promise<any> {
return this._transitionEngine.whenRenderingDone();
}
}

View File

@ -23,13 +23,17 @@ export class CssKeyframesDriver implements AnimationDriver {
private readonly _head: any = document.querySelector('head');
private _warningIssued = false;
validateStyleProperty(prop: string): boolean { return validateStyleProperty(prop); }
validateStyleProperty(prop: string): boolean {
return validateStyleProperty(prop);
}
matchesElement(element: any, selector: string): boolean {
return matchesElement(element, selector);
}
containsElement(elm1: any, elm2: any): boolean { return containsElement(elm1, elm2); }
containsElement(elm1: any, elm2: any): boolean {
return containsElement(elm1, elm2);
}
query(element: any, selector: string, multi: boolean): any[] {
return invokeQuery(element, selector, multi);
@ -104,7 +108,7 @@ export class CssKeyframesDriver implements AnimationDriver {
const animationName = `${KEYFRAMES_NAME_PREFIX}${this._count++}`;
const kfElm = this.buildKeyframeElement(element, animationName, keyframes);
document.querySelector('head') !.appendChild(kfElm);
document.querySelector('head')!.appendChild(kfElm);
const specialStyles = packageNonAnimatableStyles(element, keyframes);
const player = new CssKeyframesPlayer(
@ -124,8 +128,8 @@ export class CssKeyframesDriver implements AnimationDriver {
}
}
function flattenKeyframesIntoStyles(
keyframes: null | {[key: string]: any} | {[key: string]: any}[]): {[key: string]: any} {
function flattenKeyframesIntoStyles(keyframes: null|{[key: string]: any}|
{[key: string]: any}[]): {[key: string]: any} {
let flatKeyframes: {[key: string]: any} = {};
if (keyframes) {
const kfs = Array.isArray(keyframes) ? keyframes : [keyframes];

View File

@ -14,7 +14,12 @@ import {ElementAnimationStyleHandler} from './element_animation_style_handler';
const DEFAULT_FILL_MODE = 'forwards';
const DEFAULT_EASING = 'linear';
export const enum AnimatorControlState {INITIALIZED = 1, STARTED = 2, FINISHED = 3, DESTROYED = 4}
export const enum AnimatorControlState {
INITIALIZED = 1,
STARTED = 2,
FINISHED = 3,
DESTROYED = 4
}
export class CssKeyframesPlayer implements AnimationPlayer {
private _onDoneFns: Function[] = [];
@ -23,10 +28,10 @@ export class CssKeyframesPlayer implements AnimationPlayer {
private _started = false;
// TODO(issue/24571): remove '!'.
private _styler !: ElementAnimationStyleHandler;
private _styler!: ElementAnimationStyleHandler;
// TODO(issue/24571): remove '!'.
public parentPlayer !: AnimationPlayer;
public parentPlayer!: AnimationPlayer;
public readonly totalTime: number;
public readonly easing: string;
public currentSnapshot: {[key: string]: string} = {};
@ -34,7 +39,7 @@ export class CssKeyframesPlayer implements AnimationPlayer {
private _state: AnimatorControlState = 0;
constructor(
public readonly element: any, public readonly keyframes: {[key: string]: string | number}[],
public readonly element: any, public readonly keyframes: {[key: string]: string|number}[],
public readonly animationName: string, private readonly _duration: number,
private readonly _delay: number, easing: string,
private readonly _finalStyles: {[key: string]: any},
@ -44,11 +49,17 @@ export class CssKeyframesPlayer implements AnimationPlayer {
this._buildStyler();
}
onStart(fn: () => void): void { this._onStartFns.push(fn); }
onStart(fn: () => void): void {
this._onStartFns.push(fn);
}
onDone(fn: () => void): void { this._onDoneFns.push(fn); }
onDone(fn: () => void): void {
this._onDoneFns.push(fn);
}
onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); }
onDestroy(fn: () => void): void {
this._onDestroyFns.push(fn);
}
destroy() {
this.init();
@ -86,11 +97,17 @@ export class CssKeyframesPlayer implements AnimationPlayer {
this._flushDoneFns();
}
setPosition(value: number) { this._styler.setPosition(value); }
setPosition(value: number) {
this._styler.setPosition(value);
}
getPosition(): number { return this._styler.getPosition(); }
getPosition(): number {
return this._styler.getPosition();
}
hasStarted(): boolean { return this._state >= AnimatorControlState.STARTED; }
hasStarted(): boolean {
return this._state >= AnimatorControlState.STARTED;
}
init(): void {
if (this._state >= AnimatorControlState.INITIALIZED) return;
this._state = AnimatorControlState.INITIALIZED;

View File

@ -22,7 +22,7 @@ export class DirectStylePlayer extends NoopAnimationPlayer {
if (this.__initialized || !this._startingStyles) return;
this.__initialized = true;
Object.keys(this._styles).forEach(prop => {
this._startingStyles ![prop] = this.element.style[prop];
this._startingStyles![prop] = this.element.style[prop];
});
super.init();
}
@ -38,7 +38,7 @@ export class DirectStylePlayer extends NoopAnimationPlayer {
destroy() {
if (!this._startingStyles) return;
Object.keys(this._startingStyles).forEach(prop => {
const value = this._startingStyles ![prop];
const value = this._startingStyles![prop];
if (value) {
this.element.style.setProperty(prop, value);
} else {

View File

@ -28,14 +28,19 @@ export class ElementAnimationStyleHandler {
apply() {
applyKeyframeAnimation(
this._element,
`${this._duration}ms ${this._easing} ${this._delay}ms 1 normal ${this._fillMode} ${this._name}`);
`${this._duration}ms ${this._easing} ${this._delay}ms 1 normal ${this._fillMode} ${
this._name}`);
addRemoveAnimationEvent(this._element, this._eventFn, false);
this._startTime = Date.now();
}
pause() { playPauseAnimation(this._element, this._name, 'paused'); }
pause() {
playPauseAnimation(this._element, this._name, 'paused');
}
resume() { playPauseAnimation(this._element, this._name, 'running'); }
resume() {
playPauseAnimation(this._element, this._name, 'running');
}
setPosition(position: number) {
const index = findIndexForAnimation(this._element, this._name);
@ -43,7 +48,9 @@ export class ElementAnimationStyleHandler {
setAnimationStyle(this._element, 'Delay', `-${this._position}ms`, index);
}
getPosition() { return this._position; }
getPosition() {
return this._position;
}
private _handleCallback(event: any) {
const timestamp = event._ngTestManualTimestamp || Date.now();
@ -70,7 +77,7 @@ export class ElementAnimationStyleHandler {
}
}
function playPauseAnimation(element: any, name: string, status: 'running' | 'paused') {
function playPauseAnimation(element: any, name: string, status: 'running'|'paused') {
const index = findIndexForAnimation(element, name);
setAnimationStyle(element, 'PlayState', status, index);
}

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {AUTO_STYLE, AnimationEvent, AnimationPlayer, NoopAnimationPlayer, ɵAnimationGroupPlayer, ɵPRE_STYLE as PRE_STYLE, ɵStyleData} from '@angular/animations';
import {AnimationEvent, AnimationPlayer, AUTO_STYLE, NoopAnimationPlayer, ɵAnimationGroupPlayer, ɵPRE_STYLE as PRE_STYLE, ɵStyleData} from '@angular/animations';
import {AnimationStyleNormalizer} from '../../src/dsl/style_normalization/animation_style_normalizer';
import {AnimationDriver} from '../../src/render/animation_driver';
@ -89,7 +89,7 @@ export function normalizeKeyframes(
}
export function listenOnPlayer(
player: AnimationPlayer, eventName: string, event: AnimationEvent | undefined,
player: AnimationPlayer, eventName: string, event: AnimationEvent|undefined,
callback: (event: any) => any) {
switch (eventName) {
case 'start':
@ -125,7 +125,7 @@ export function makeAnimationEvent(
}
export function getOrSetAsInMap(
map: Map<any, any>| {[key: string]: any}, key: any, defaultValue: any) {
map: Map<any, any>|{[key: string]: any}, key: any, defaultValue: any) {
let value: any;
if (map instanceof Map) {
value = map.get(key);
@ -161,7 +161,9 @@ let _query: (element: any, selector: string, multi: boolean) => any[] =
const _isNode = isNode();
if (_isNode || typeof Element !== 'undefined') {
// this is well supported in all browsers
_contains = (elm1: any, elm2: any) => { return elm1.contains(elm2) as boolean; };
_contains = (elm1: any, elm2: any) => {
return elm1.contains(elm2) as boolean;
};
_matches = (() => {
if (_isNode || Element.prototype.matches) {
@ -203,15 +205,15 @@ let _IS_WEBKIT = false;
export function validateStyleProperty(prop: string): boolean {
if (!_CACHED_BODY) {
_CACHED_BODY = getBodyNode() || {};
_IS_WEBKIT = _CACHED_BODY !.style ? ('WebkitAppearance' in _CACHED_BODY !.style) : false;
_IS_WEBKIT = _CACHED_BODY!.style ? ('WebkitAppearance' in _CACHED_BODY!.style) : false;
}
let result = true;
if (_CACHED_BODY !.style && !containsVendorPrefix(prop)) {
result = prop in _CACHED_BODY !.style;
if (_CACHED_BODY!.style && !containsVendorPrefix(prop)) {
result = prop in _CACHED_BODY!.style;
if (!result && _IS_WEBKIT) {
const camelProp = 'Webkit' + prop.charAt(0).toUpperCase() + prop.substr(1);
result = camelProp in _CACHED_BODY !.style;
result = camelProp in _CACHED_BODY!.style;
}
}

View File

@ -19,7 +19,7 @@ import {eraseStyles, setStyles} from '../util';
* @returns an instance of `SpecialCasedStyles` if any special styles are detected otherwise `null`
*/
export function packageNonAnimatableStyles(
element: any, styles: {[key: string]: any} | {[key: string]: any}[]): SpecialCasedStyles|null {
element: any, styles: {[key: string]: any}|{[key: string]: any}[]): SpecialCasedStyles|null {
let startStyles: {[key: string]: any}|null = null;
let endStyles: {[key: string]: any}|null = null;
if (Array.isArray(styles) && styles.length) {
@ -47,7 +47,7 @@ export class SpecialCasedStyles {
static initialStylesByElement = new WeakMap<any, {[key: string]: any}>();
private _state = SpecialCasedStylesState.Pending;
private _initialStyles !: {[key: string]: any};
private _initialStyles!: {[key: string]: any};
constructor(
private _element: any, private _startStyles: {[key: string]: any}|null,

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {AUTO_STYLE, AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationPlayer, ɵStyleData} from '@angular/animations';
import {AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationPlayer, AUTO_STYLE, ɵStyleData} from '@angular/animations';
import {Ast} from '../dsl/animation_ast';
import {buildAnimationAst} from '../dsl/animation_ast_builder';
@ -34,7 +34,7 @@ export class TimelineAnimationEngine {
const ast = buildAnimationAst(this._driver, metadata, errors);
if (errors.length) {
throw new Error(
`Unable to build the animation due to the following errors: ${errors.join("\n")}`);
`Unable to build the animation due to the following errors: ${errors.join('\n')}`);
} else {
this._animations[id] = ast;
}
@ -71,12 +71,13 @@ export class TimelineAnimationEngine {
if (errors.length) {
throw new Error(
`Unable to create the animation due to the following errors: ${errors.join("\n")}`);
`Unable to create the animation due to the following errors: ${errors.join('\n')}`);
}
autoStylesMap.forEach((styles, element) => {
Object.keys(styles).forEach(
prop => { styles[prop] = this._driver.computeStyle(element, prop, AUTO_STYLE); });
Object.keys(styles).forEach(prop => {
styles[prop] = this._driver.computeStyle(element, prop, AUTO_STYLE);
});
});
const players = instructions.map(i => {

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {AUTO_STYLE, AnimationOptions, AnimationPlayer, NoopAnimationPlayer, ɵAnimationGroupPlayer as AnimationGroupPlayer, ɵPRE_STYLE as PRE_STYLE, ɵStyleData} from '@angular/animations';
import {AnimationOptions, AnimationPlayer, AUTO_STYLE, NoopAnimationPlayer, ɵAnimationGroupPlayer as AnimationGroupPlayer, ɵPRE_STYLE as PRE_STYLE, ɵStyleData} from '@angular/animations';
import {AnimationTimelineInstruction} from '../dsl/animation_timeline_instruction';
import {AnimationTransitionFactory} from '../dsl/animation_transition_factory';
@ -13,7 +13,7 @@ import {AnimationTransitionInstruction} from '../dsl/animation_transition_instru
import {AnimationTrigger} from '../dsl/animation_trigger';
import {ElementInstructionMap} from '../dsl/element_instruction_map';
import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_style_normalizer';
import {ENTER_CLASSNAME, LEAVE_CLASSNAME, NG_ANIMATING_CLASSNAME, NG_ANIMATING_SELECTOR, NG_TRIGGER_CLASSNAME, NG_TRIGGER_SELECTOR, copyObj, eraseStyles, iteratorToArray, setStyles} from '../util';
import {copyObj, ENTER_CLASSNAME, eraseStyles, iteratorToArray, LEAVE_CLASSNAME, NG_ANIMATING_CLASSNAME, NG_ANIMATING_SELECTOR, NG_TRIGGER_CLASSNAME, NG_TRIGGER_SELECTOR, setStyles} from '../util';
import {AnimationDriver} from './animation_driver';
import {getOrSetAsInMap, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer} from './shared';
@ -71,7 +71,9 @@ export class StateValue {
public value: string;
public options: AnimationOptions;
get params(): {[key: string]: any} { return this.options.params as{[key: string]: any}; }
get params(): {[key: string]: any} {
return this.options.params as {[key: string]: any};
}
constructor(input: any, public namespaceId: string = '') {
const isObj = input && input.hasOwnProperty('value');
@ -92,7 +94,7 @@ export class StateValue {
absorbOptions(options: AnimationOptions) {
const newParams = options.params;
if (newParams) {
const oldParams = this.options.params !;
const oldParams = this.options.params!;
Object.keys(newParams).forEach(prop => {
if (oldParams[prop] == null) {
oldParams[prop] = newParams[prop];
@ -263,7 +265,9 @@ export class AnimationTransitionNamespace {
if (!isFallbackTransition) {
addClass(element, QUEUED_CLASSNAME);
player.onStart(() => { removeClass(element, QUEUED_CLASSNAME); });
player.onStart(() => {
removeClass(element, QUEUED_CLASSNAME);
});
}
player.onDone(() => {
@ -290,11 +294,14 @@ export class AnimationTransitionNamespace {
deregister(name: string) {
delete this._triggers[name];
this._engine.statesByElement.forEach((stateMap, element) => { delete stateMap[name]; });
this._engine.statesByElement.forEach((stateMap, element) => {
delete stateMap[name];
});
this._elementListeners.forEach((listeners, element) => {
this._elementListeners.set(
element, listeners.filter(entry => { return entry.name != name; }));
this._elementListeners.set(element, listeners.filter(entry => {
return entry.name != name;
}));
});
}
@ -372,7 +379,7 @@ export class AnimationTransitionNamespace {
const trigger = this._triggers[triggerName];
const transition = trigger.fallbackTransition;
const elementStates = this._engine.statesByElement.get(element) !;
const elementStates = this._engine.statesByElement.get(element)!;
const fromState = elementStates[triggerName] || DEFAULT_STATE_VALUE;
const toState = new StateValue(VOID_VALUE);
const player = new TransitionAnimationPlayer(this.id, triggerName, element);
@ -448,7 +455,9 @@ export class AnimationTransitionNamespace {
}
}
insertNode(element: any, parent: any): void { addClass(element, this._hostClassName); }
insertNode(element: any, parent: any): void {
addClass(element, this._hostClassName);
}
drainQueuedTransitions(microtaskId: number): QueueInstruction[] {
const instructions: QueueInstruction[] = [];
@ -538,7 +547,9 @@ export class TransitionAnimationEngine {
public onRemovalComplete = (element: any, context: any) => {};
/** @internal */
_onRemovalComplete(element: any, context: any) { this.onRemovalComplete(element, context); }
_onRemovalComplete(element: any, context: any) {
this.onRemovalComplete(element, context);
}
constructor(
public bodyNode: any, public driver: AnimationDriver,
@ -631,7 +642,9 @@ export class TransitionAnimationEngine {
this.afterFlushAnimationsDone(() => ns.destroy(context));
}
private _fetchNamespace(id: string) { return this._namespaceLookup[id]; }
private _fetchNamespace(id: string) {
return this._namespaceLookup[id];
}
fetchNamespacesByElement(element: any): Set<AnimationTransitionNamespace> {
// normally there should only be one namespace per element, however
@ -704,7 +717,9 @@ export class TransitionAnimationEngine {
}
}
collectEnterElement(element: any) { this.collectedEnterElements.push(element); }
collectEnterElement(element: any) {
this.collectedEnterElements.push(element);
}
markElementAsDisabled(element: any, value: boolean) {
if (value) {
@ -740,11 +755,8 @@ export class TransitionAnimationEngine {
markElementAsRemoved(namespaceId: string, element: any, hasAnimation?: boolean, context?: any) {
this.collectedLeaveElements.push(element);
element[REMOVAL_FLAG] = {
namespaceId,
setForRemoval: context, hasAnimation,
removedBeforeQueried: false
};
element[REMOVAL_FLAG] =
{namespaceId, setForRemoval: context, hasAnimation, removedBeforeQueried: false};
}
listen(
@ -876,7 +888,9 @@ export class TransitionAnimationEngine {
this._whenQuietFns = [];
if (players.length) {
optimizeGroupPlayer(players).onDone(() => { quietFns.forEach(fn => fn()); });
optimizeGroupPlayer(players).onDone(() => {
quietFns.forEach(fn => fn());
});
} else {
quietFns.forEach(fn => fn());
}
@ -950,16 +964,18 @@ export class TransitionAnimationEngine {
cleanupFns.push(() => {
enterNodeMap.forEach((nodes, root) => {
const className = enterNodeMapIds.get(root) !;
const className = enterNodeMapIds.get(root)!;
nodes.forEach(node => removeClass(node, className));
});
leaveNodeMap.forEach((nodes, root) => {
const className = leaveNodeMapIds.get(root) !;
const className = leaveNodeMapIds.get(root)!;
nodes.forEach(node => removeClass(node, className));
});
allLeaveNodes.forEach(element => { this.processLeaveNode(element); });
allLeaveNodes.forEach(element => {
this.processLeaveNode(element);
});
});
const allPlayers: TransitionAnimationPlayer[] = [];
@ -981,10 +997,10 @@ export class TransitionAnimationEngine {
}
const nodeIsOrphaned = !bodyNode || !this.driver.containsElement(bodyNode, element);
const leaveClassName = leaveNodeMapIds.get(element) !;
const enterClassName = enterNodeMapIds.get(element) !;
const leaveClassName = leaveNodeMapIds.get(element)!;
const enterClassName = enterNodeMapIds.get(element)!;
const instruction = this._buildInstruction(
entry, subTimelines, enterClassName, leaveClassName, nodeIsOrphaned) !;
entry, subTimelines, enterClassName, leaveClassName, nodeIsOrphaned)!;
if (instruction.errors && instruction.errors.length) {
erroneousTransitions.push(instruction);
return;
@ -1029,7 +1045,7 @@ export class TransitionAnimationEngine {
instruction.preStyleProps.forEach((stringMap, element) => {
const props = Object.keys(stringMap);
if (props.length) {
let setVal: Set<string> = allPreStyleElements.get(element) !;
let setVal: Set<string> = allPreStyleElements.get(element)!;
if (!setVal) {
allPreStyleElements.set(element, setVal = new Set<string>());
}
@ -1039,7 +1055,7 @@ export class TransitionAnimationEngine {
instruction.postStyleProps.forEach((stringMap, element) => {
const props = Object.keys(stringMap);
let setVal: Set<string> = allPostStyleElements.get(element) !;
let setVal: Set<string> = allPostStyleElements.get(element)!;
if (!setVal) {
allPostStyleElements.set(element, setVal = new Set<string>());
}
@ -1052,7 +1068,7 @@ export class TransitionAnimationEngine {
const errors: string[] = [];
erroneousTransitions.forEach(instruction => {
errors.push(`@${instruction.triggerName} has failed due to:\n`);
instruction.errors !.forEach(error => errors.push(`- ${error}\n`));
instruction.errors!.forEach(error => errors.push(`- ${error}\n`));
});
allPlayers.forEach(player => player.destroy());
@ -1116,7 +1132,7 @@ export class TransitionAnimationEngine {
replaceNodes.forEach(node => {
const post = postStylesMap.get(node);
const pre = preStylesMap.get(node);
postStylesMap.set(node, { ...post, ...pre } as any);
postStylesMap.set(node, {...post, ...pre} as any);
});
const rootPlayers: TransitionAnimationPlayer[] = [];
@ -1274,9 +1290,13 @@ export class TransitionAnimationEngine {
return this._fetchNamespace(namespaceId).elementContainsData(element) || containsData;
}
afterFlush(callback: () => any) { this._flushFns.push(callback); }
afterFlush(callback: () => any) {
this._flushFns.push(callback);
}
afterFlushAnimationsDone(callback: () => any) { this._whenQuietFns.push(callback); }
afterFlushAnimationsDone(callback: () => any) {
this._whenQuietFns.push(callback);
}
private _getPreviousPlayers(
element: string, isQueriedElement: boolean, namespaceId?: string, triggerName?: string,
@ -1413,8 +1433,9 @@ export class TransitionAnimationEngine {
// this basically makes all of the callbacks for sub element animations
// be dependent on the upper players for when they finish
allSubElements.forEach(
element => { getOrSetAsInMap(skippedPlayersMap, element, []).push(player); });
allSubElements.forEach(element => {
getOrSetAsInMap(skippedPlayersMap, element, []).push(player);
});
return player;
}
@ -1441,7 +1462,7 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
private _queuedCallbacks: {[name: string]: (() => any)[]} = {};
public readonly destroyed = false;
// TODO(issue/24571): remove '!'.
public parentPlayer !: AnimationPlayer;
public parentPlayer!: AnimationPlayer;
public markedForDestroy: boolean = false;
public disabled = false;
@ -1462,17 +1483,21 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
this._queuedCallbacks = {};
this._containsRealPlayer = true;
this.overrideTotalTime(player.totalTime);
(this as{queued: boolean}).queued = false;
(this as {queued: boolean}).queued = false;
}
getRealPlayer() { return this._player; }
getRealPlayer() {
return this._player;
}
overrideTotalTime(totalTime: number) { (this as any).totalTime = totalTime; }
overrideTotalTime(totalTime: number) {
(this as any).totalTime = totalTime;
}
syncPlayerEvents(player: AnimationPlayer) {
const p = this._player as any;
if (p.triggerCallback) {
player.onStart(() => p.triggerCallback !('start'));
player.onStart(() => p.triggerCallback!('start'));
}
player.onDone(() => this.finish());
player.onDestroy(() => this.destroy());
@ -1503,24 +1528,38 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
this._player.onDestroy(fn);
}
init(): void { this._player.init(); }
init(): void {
this._player.init();
}
hasStarted(): boolean { return this.queued ? false : this._player.hasStarted(); }
hasStarted(): boolean {
return this.queued ? false : this._player.hasStarted();
}
play(): void { !this.queued && this._player.play(); }
play(): void {
!this.queued && this._player.play();
}
pause(): void { !this.queued && this._player.pause(); }
pause(): void {
!this.queued && this._player.pause();
}
restart(): void { !this.queued && this._player.restart(); }
restart(): void {
!this.queued && this._player.restart();
}
finish(): void { this._player.finish(); }
finish(): void {
this._player.finish();
}
destroy(): void {
(this as{destroyed: boolean}).destroyed = true;
(this as {destroyed: boolean}).destroyed = true;
this._player.destroy();
}
reset(): void { !this.queued && this._player.reset(); }
reset(): void {
!this.queued && this._player.reset();
}
setPosition(p: any): void {
if (!this.queued) {
@ -1528,7 +1567,9 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
}
}
getPosition(): number { return this.queued ? 0 : this._player.getPosition(); }
getPosition(): number {
return this.queued ? 0 : this._player.getPosition();
}
/** @internal */
triggerCallback(phaseName: string): void {
@ -1539,7 +1580,7 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
}
}
function deleteOrUnsetInMap(map: Map<any, any[]>| {[key: string]: any}, key: any, value: any) {
function deleteOrUnsetInMap(map: Map<any, any[]>|{[key: string]: any}, key: any, value: any) {
let currentValues: any[]|null|undefined;
if (map instanceof Map) {
currentValues = map.get(key);
@ -1661,7 +1702,7 @@ function buildRootMap(roots: any[], nodes: any[]): Map<any, any[]> {
nodes.forEach(node => {
const root = getRoot(node);
if (root !== NULL_NODE) {
rootMap.get(root) !.push(node);
rootMap.get(root)!.push(node);
}
});
@ -1742,7 +1783,7 @@ function replacePostStylesAsPre(
let preEntry = allPreStyleElements.get(element);
if (preEntry) {
postEntry.forEach(data => preEntry !.add(data));
postEntry.forEach(data => preEntry!.add(data));
} else {
allPreStyleElements.set(element, postEntry);
}

View File

@ -19,13 +19,17 @@ export class WebAnimationsDriver implements AnimationDriver {
private _isNativeImpl = /\{\s*\[native\s+code\]\s*\}/.test(getElementAnimateFn().toString());
private _cssKeyframesDriver = new CssKeyframesDriver();
validateStyleProperty(prop: string): boolean { return validateStyleProperty(prop); }
validateStyleProperty(prop: string): boolean {
return validateStyleProperty(prop);
}
matchesElement(element: any, selector: string): boolean {
return matchesElement(element, selector);
}
containsElement(elm1: any, elm2: any): boolean { return containsElement(elm1, elm2); }
containsElement(elm1: any, elm2: any): boolean {
return containsElement(elm1, elm2);
}
query(element: any, selector: string, multi: boolean): any[] {
return invokeQuery(element, selector, multi);
@ -35,7 +39,9 @@ export class WebAnimationsDriver implements AnimationDriver {
return (window.getComputedStyle(element) as any)[prop] as string;
}
overrideWebAnimationsSupport(supported: boolean) { this._isNativeImpl = supported; }
overrideWebAnimationsSupport(supported: boolean) {
this._isNativeImpl = supported;
}
animate(
element: any, keyframes: ɵStyleData[], duration: number, delay: number, easing: string,
@ -47,7 +53,7 @@ export class WebAnimationsDriver implements AnimationDriver {
}
const fill = delay == 0 ? 'both' : 'forwards';
const playerOptions: {[key: string]: string | number} = {duration, delay, fill};
const playerOptions: {[key: string]: string|number} = {duration, delay, fill};
// we check for this to avoid having a null|undefined value be present
// for the easing (which results in an error for certain browsers #9752)
if (easing) {

View File

@ -23,18 +23,18 @@ export class WebAnimationsPlayer implements AnimationPlayer {
private _started = false;
private _destroyed = false;
// TODO(issue/24571): remove '!'.
private _finalKeyframe !: {[key: string]: string | number};
private _finalKeyframe!: {[key: string]: string|number};
// TODO(issue/24571): remove '!'.
public readonly domPlayer !: DOMAnimation;
public readonly domPlayer!: DOMAnimation;
public time = 0;
public parentPlayer: AnimationPlayer|null = null;
public currentSnapshot: {[styleName: string]: string | number} = {};
public currentSnapshot: {[styleName: string]: string|number} = {};
constructor(
public element: any, public keyframes: {[key: string]: string | number}[],
public options: {[key: string]: string | number},
public element: any, public keyframes: {[key: string]: string|number}[],
public options: {[key: string]: string|number},
private _specialStyles?: SpecialCasedStyles|null) {
this._duration = <number>options['duration'];
this._delay = <number>options['delay'] || 0;
@ -59,7 +59,7 @@ export class WebAnimationsPlayer implements AnimationPlayer {
this._initialized = true;
const keyframes = this.keyframes;
(this as{domPlayer: DOMAnimation}).domPlayer =
(this as {domPlayer: DOMAnimation}).domPlayer =
this._triggerWebAnimation(this.element, keyframes, this.options);
this._finalKeyframe = keyframes.length ? keyframes[keyframes.length - 1] : {};
this.domPlayer.addEventListener('finish', () => this._onFinish());
@ -81,11 +81,17 @@ export class WebAnimationsPlayer implements AnimationPlayer {
return element['animate'](keyframes, options) as DOMAnimation;
}
onStart(fn: () => void): void { this._onStartFns.push(fn); }
onStart(fn: () => void): void {
this._onStartFns.push(fn);
}
onDone(fn: () => void): void { this._onDoneFns.push(fn); }
onDone(fn: () => void): void {
this._onDoneFns.push(fn);
}
onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); }
onDestroy(fn: () => void): void {
this._onDestroyFns.push(fn);
}
play(): void {
this._buildPlayer();
@ -132,7 +138,9 @@ export class WebAnimationsPlayer implements AnimationPlayer {
this.play();
}
hasStarted(): boolean { return this._started; }
hasStarted(): boolean {
return this._started;
}
destroy(): void {
if (!this._destroyed) {
@ -147,14 +155,20 @@ export class WebAnimationsPlayer implements AnimationPlayer {
}
}
setPosition(p: number): void { this.domPlayer.currentTime = p * this.time; }
setPosition(p: number): void {
this.domPlayer.currentTime = p * this.time;
}
getPosition(): number { return this.domPlayer.currentTime / this.time; }
getPosition(): number {
return this.domPlayer.currentTime / this.time;
}
get totalTime(): number { return this._delay + this._duration; }
get totalTime(): number {
return this._delay + this._duration;
}
beforeDestroy() {
const styles: {[key: string]: string | number} = {};
const styles: {[key: string]: string|number} = {};
if (this.hasStarted()) {
Object.keys(this._finalKeyframe).forEach(prop => {
if (prop != 'offset') {

View File

@ -23,7 +23,7 @@ export const NG_TRIGGER_SELECTOR = '.ng-trigger';
export const NG_ANIMATING_CLASSNAME = 'ng-animating';
export const NG_ANIMATING_SELECTOR = '.ng-animating';
export function resolveTimingValue(value: string | number) {
export function resolveTimingValue(value: string|number) {
if (typeof value == 'number') return value;
const matches = value.match(/^(-?[\.\d]+)(m?s)/);
@ -42,14 +42,14 @@ function _convertTimeValueToMS(value: number, unit: string): number {
}
export function resolveTiming(
timings: string | number | AnimateTimings, errors: any[], allowNegativeValues?: boolean) {
timings: string|number|AnimateTimings, errors: any[], allowNegativeValues?: boolean) {
return timings.hasOwnProperty('duration') ?
<AnimateTimings>timings :
parseTimeExpression(<string|number>timings, errors, allowNegativeValues);
}
function parseTimeExpression(
exp: string | number, errors: string[], allowNegativeValues?: boolean): AnimateTimings {
exp: string|number, errors: string[], allowNegativeValues?: boolean): AnimateTimings {
const regex = /^(-?[\.\d]+)(m?s)(?:\s+(-?[\.\d]+)(m?s))?(?:\s+([-a-z]+(?:\(.+?\))?))?$/i;
let duration: number;
let delay: number = 0;
@ -97,11 +97,13 @@ function parseTimeExpression(
export function copyObj(
obj: {[key: string]: any}, destination: {[key: string]: any} = {}): {[key: string]: any} {
Object.keys(obj).forEach(prop => { destination[prop] = obj[prop]; });
Object.keys(obj).forEach(prop => {
destination[prop] = obj[prop];
});
return destination;
}
export function normalizeStyles(styles: ɵStyleData | ɵStyleData[]): ɵStyleData {
export function normalizeStyles(styles: ɵStyleData|ɵStyleData[]): ɵStyleData {
const normalizedStyles: ɵStyleData = {};
if (Array.isArray(styles)) {
styles.forEach(data => copyStyles(data, false, normalizedStyles));
@ -186,8 +188,8 @@ export function eraseStyles(element: any, styles: ɵStyleData) {
}
}
export function normalizeAnimationEntry(steps: AnimationMetadata | AnimationMetadata[]):
AnimationMetadata {
export function normalizeAnimationEntry(steps: AnimationMetadata|
AnimationMetadata[]): AnimationMetadata {
if (Array.isArray(steps)) {
if (steps.length == 1) return steps[0];
return sequence(steps);
@ -196,7 +198,7 @@ export function normalizeAnimationEntry(steps: AnimationMetadata | AnimationMeta
}
export function validateStyleParams(
value: string | number, options: AnimationOptions, errors: any[]) {
value: string|number, options: AnimationOptions, errors: any[]) {
const params = options.params || {};
const matches = extractStyleParams(value);
if (matches.length) {
@ -211,7 +213,7 @@ export function validateStyleParams(
const PARAM_REGEX =
new RegExp(`${SUBSTITUTION_EXPR_START}\\s*(.+?)\\s*${SUBSTITUTION_EXPR_END}`, 'g');
export function extractStyleParams(value: string | number): string[] {
export function extractStyleParams(value: string|number): string[] {
let params: string[] = [];
if (typeof value === 'string') {
let match: any;
@ -224,7 +226,7 @@ export function extractStyleParams(value: string | number): string[] {
}
export function interpolateParams(
value: string | number, params: {[name: string]: any}, errors: any[]): string|number {
value: string|number, params: {[name: string]: any}, errors: any[]): string|number {
const original = value.toString();
const str = original.replace(PARAM_REGEX, (_, varName) => {
let localVal = params[varName];
@ -297,7 +299,9 @@ export function balancePreviousStylesIntoKeyframes(
// tslint:disable-next-line
for (var i = 1; i < keyframes.length; i++) {
let kf = keyframes[i];
missingStyleProps.forEach(function(prop) { kf[prop] = computeStyle(element, prop); });
missingStyleProps.forEach(function(prop) {
kf[prop] = computeStyle(element, prop);
});
}
}
}

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {AUTO_STYLE, AnimationMetadata, AnimationMetadataType, AnimationOptions, animate, animation, group, keyframes, query, sequence, state, style, transition, trigger, useAnimation, ɵStyleData} from '@angular/animations';
import {animate, animation, AnimationMetadata, AnimationMetadataType, AnimationOptions, AUTO_STYLE, group, keyframes, query, sequence, state, style, transition, trigger, useAnimation, ɵStyleData} from '@angular/animations';
import {Animation} from '../../src/dsl/animation';
import {buildAnimationAst} from '../../src/dsl/animation_ast_builder';
@ -35,7 +35,9 @@ function createDiv() {
rootElement.appendChild(subElement2);
});
afterEach(() => { document.body.removeChild(rootElement); });
afterEach(() => {
document.body.removeChild(rootElement);
});
describe('validation', () => {
it('should throw an error if one or more but not all keyframes() styles contain offsets',
@ -45,7 +47,9 @@ function createDiv() {
style({opacity: 1, offset: 1}),
]));
expect(() => { validateAndThrowAnimationSequence(steps); })
expect(() => {
validateAndThrowAnimationSequence(steps);
})
.toThrowError(
/Not all style\(\) steps within the declared keyframes\(\) contain offsets/);
});
@ -96,7 +100,9 @@ function createDiv() {
]))
]);
expect(() => { validateAndThrowAnimationSequence(steps); })
expect(() => {
validateAndThrowAnimationSequence(steps);
})
.toThrowError(
/The CSS property "opacity" that exists between the times of "0ms" and "2000ms" is also being animated in a parallel animation between the times of "0ms" and "1500ms"/);
});
@ -191,7 +197,9 @@ function createDiv() {
})),
];
expect(() => { validateAndThrowAnimationSequence(steps); })
expect(() => {
validateAndThrowAnimationSequence(steps);
})
.toThrowError(
/state\("final", ...\) must define default values for all the following style substitutions: one, two, three/);
@ -203,7 +211,9 @@ function createDiv() {
}),
{params: {redColor: 'maroon'}})];
expect(() => { validateAndThrowAnimationSequence(steps2); })
expect(() => {
validateAndThrowAnimationSequence(steps2);
})
.toThrowError(
/state\("panfinal", ...\) must define default values for all the following style substitutions: greyColor/);
});
@ -211,7 +221,9 @@ function createDiv() {
it('should throw an error if an invalid CSS property is used in the animation', () => {
const steps = [animate(1000, style({abc: '500px'}))];
expect(() => { validateAndThrowAnimationSequence(steps); })
expect(() => {
validateAndThrowAnimationSequence(steps);
})
.toThrowError(
/The provided animation property "abc" is not a supported CSS property for animations/);
});
@ -388,7 +400,7 @@ function createDiv() {
let players = invokeAnimationSequence(rootElement, steps);
expect(players.length).toEqual(1);
let p1 = players.pop() !;
let p1 = players.pop()!;
expect(p1.duration).toEqual(1500);
expect(p1.keyframes).toEqual([
{width: '*', offset: 0},
@ -405,7 +417,7 @@ function createDiv() {
players = invokeAnimationSequence(rootElement, steps);
expect(players.length).toEqual(1);
p1 = players.pop() !;
p1 = players.pop()!;
expect(p1.duration).toEqual(1000);
expect(p1.keyframes).toEqual([
{width: '100px', offset: 0},
@ -876,7 +888,9 @@ function createDiv() {
const steps =
[query('somethingFake', [style({opacity: 0}), animate(1000, style({opacity: 1}))])];
expect(() => { invokeAnimationSequence(rootElement, steps); })
expect(() => {
invokeAnimationSequence(rootElement, steps);
})
.toThrowError(
/`query\("somethingFake"\)` returned zero elements\. \(Use `query\("somethingFake", \{ optional: true \}\)` if you wish to allow this\.\)/);
});
@ -887,13 +901,17 @@ function createDiv() {
'somethingFake', [style({opacity: 0}), animate(1000, style({opacity: 1}))],
{optional: true})];
expect(() => { invokeAnimationSequence(rootElement, steps); }).not.toThrow();
expect(() => {
invokeAnimationSequence(rootElement, steps);
}).not.toThrow();
const steps2 = [query(
'fakeSomethings', [style({opacity: 0}), animate(1000, style({opacity: 1}))],
{optional: true})];
expect(() => { invokeAnimationSequence(rootElement, steps2); }).not.toThrow();
expect(() => {
invokeAnimationSequence(rootElement, steps2);
}).not.toThrow();
});
it('should delay the query operation if a delay option is provided', () => {
@ -1025,8 +1043,7 @@ function createDiv() {
const players = invokeAnimationSequence(rootElement, steps, {}, fromStyles, toStyles);
expect(players[0].keyframes).toEqual([
{background: 'blue', offset: 0, easing: 'ease-out'},
{background: 'red', offset: 1}
{background: 'blue', offset: 0, easing: 'ease-out'}, {background: 'red', offset: 1}
]);
});
});
@ -1042,7 +1059,7 @@ function humanizeOffsets(keyframes: ɵStyleData[], digits: number = 3): ɵStyleD
}
function invokeAnimationSequence(
element: any, steps: AnimationMetadata | AnimationMetadata[], locals: {[key: string]: any} = {},
element: any, steps: AnimationMetadata|AnimationMetadata[], locals: {[key: string]: any} = {},
startingStyles: ɵStyleData[] = [], destinationStyles: ɵStyleData[] = [],
subInstructions?: ElementInstructionMap): AnimationTimelineInstruction[] {
const driver = new MockAnimationDriver();
@ -1050,7 +1067,7 @@ function invokeAnimationSequence(
.buildTimelines(element, startingStyles, destinationStyles, locals, subInstructions);
}
function validateAndThrowAnimationSequence(steps: AnimationMetadata | AnimationMetadata[]) {
function validateAndThrowAnimationSequence(steps: AnimationMetadata|AnimationMetadata[]) {
const driver = new MockAnimationDriver();
const errors: any[] = [];
const ast = buildAnimationAst(driver, steps, errors);

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AnimationOptions, animate, state, style, transition} from '@angular/animations';
import {animate, AnimationOptions, state, style, transition} from '@angular/animations';
import {AnimationTransitionInstruction} from '@angular/animations/browser/src/dsl/animation_transition_instruction';
import {AnimationTrigger} from '@angular/animations/browser/src/dsl/animation_trigger';
@ -25,7 +25,9 @@ import {makeTrigger} from '../shared';
document.body.appendChild(element);
});
afterEach(() => { document.body.removeChild(element); });
afterEach(() => {
document.body.removeChild(element);
});
describe('trigger validation', () => {
it('should group errors together for an animation trigger', () => {
@ -36,8 +38,9 @@ import {makeTrigger} from '../shared';
it('should throw an error when a transition within a trigger contains an invalid expression',
() => {
expect(
() => { makeTrigger('name', [transition('somethingThatIsWrong', animate(3333))]); })
expect(() => {
makeTrigger('name', [transition('somethingThatIsWrong', animate(3333))]);
})
.toThrowError(
/- The provided transition expression "somethingThatIsWrong" is not supported/);
});
@ -78,7 +81,7 @@ import {makeTrigger} from '../shared';
const result = makeTrigger(
'name', [transition('a => b', animate(1234)), transition('b => c', animate(5678))]);
const trans = buildTransition(result, element, 'b', 'c') !;
const trans = buildTransition(result, element, 'b', 'c')!;
expect(trans.timelines.length).toEqual(1);
const timeline = trans.timelines[0];
expect(timeline.duration).toEqual(5678);
@ -90,13 +93,13 @@ import {makeTrigger} from '../shared';
transition('* => *', animate(9999))
]);
let trans = buildTransition(result, element, 'b', 'c') !;
let trans = buildTransition(result, element, 'b', 'c')!;
expect(trans.timelines[0].duration).toEqual(5678);
trans = buildTransition(result, element, 'a', 'b') !;
trans = buildTransition(result, element, 'a', 'b')!;
expect(trans.timelines[0].duration).toEqual(1234);
trans = buildTransition(result, element, 'c', 'c') !;
trans = buildTransition(result, element, 'c', 'c')!;
expect(trans.timelines[0].duration).toEqual(9999);
});
@ -110,23 +113,23 @@ import {makeTrigger} from '../shared';
it('should support bi-directional transition expressions', () => {
const result = makeTrigger('name', [transition('a <=> b', animate(2222))]);
const t1 = buildTransition(result, element, 'a', 'b') !;
const t1 = buildTransition(result, element, 'a', 'b')!;
expect(t1.timelines[0].duration).toEqual(2222);
const t2 = buildTransition(result, element, 'b', 'a') !;
const t2 = buildTransition(result, element, 'b', 'a')!;
expect(t2.timelines[0].duration).toEqual(2222);
});
it('should support multiple transition statements in one string', () => {
const result = makeTrigger('name', [transition('a => b, b => a, c => *', animate(1234))]);
const t1 = buildTransition(result, element, 'a', 'b') !;
const t1 = buildTransition(result, element, 'a', 'b')!;
expect(t1.timelines[0].duration).toEqual(1234);
const t2 = buildTransition(result, element, 'b', 'a') !;
const t2 = buildTransition(result, element, 'b', 'a')!;
expect(t2.timelines[0].duration).toEqual(1234);
const t3 = buildTransition(result, element, 'c', 'a') !;
const t3 = buildTransition(result, element, 'c', 'a')!;
expect(t3.timelines[0].duration).toEqual(1234);
});
@ -138,7 +141,7 @@ import {makeTrigger} from '../shared';
'a => b', [style({height: '{{ a }}'}), animate(1000, style({height: '{{ b }}'}))],
buildParams({a: '100px', b: '200px'}))]);
const trans = buildTransition(result, element, 'a', 'b') !;
const trans = buildTransition(result, element, 'a', 'b')!;
const keyframes = trans.timelines[0].keyframes;
expect(keyframes).toEqual([{height: '100px', offset: 0}, {height: '200px', offset: 1}]);
});
@ -153,7 +156,7 @@ import {makeTrigger} from '../shared';
buildParams({a: '100px', b: '200px'}))]);
const trans =
buildTransition(result, element, 'a', 'b', {}, buildParams({a: '300px'})) !;
buildTransition(result, element, 'a', 'b', {}, buildParams({a: '300px'}))!;
const keyframes = trans.timelines[0].keyframes;
expect(keyframes).toEqual(
@ -167,7 +170,7 @@ import {makeTrigger} from '../shared';
transition('true <=> false', animate(1234))
]);
const trans = buildTransition(result, element, false, true) !;
const trans = buildTransition(result, element, false, true)!;
expect(trans.timelines[0].duration).toEqual(1234);
});
@ -177,7 +180,7 @@ import {makeTrigger} from '../shared';
transition('1 <=> 0', animate(4567))
]);
const trans = buildTransition(result, element, false, true) !;
const trans = buildTransition(result, element, false, true)!;
expect(trans.timelines[0].duration).toEqual(4567);
});
@ -188,7 +191,7 @@ import {makeTrigger} from '../shared';
transition('1 <=> 0', animate(4567))
]);
const trans = buildTransition(result, element, false, true) !;
const trans = buildTransition(result, element, false, true)!;
expect(trans.timelines[0].keyframes).toEqual([
{offset: 0, color: 'red'}, {offset: 1, color: 'green'}
]);
@ -201,7 +204,7 @@ import {makeTrigger} from '../shared';
transition('true <=> false', animate(4567))
]);
const trans = buildTransition(result, element, false, true) !;
const trans = buildTransition(result, element, false, true)!;
expect(trans.timelines[0].keyframes).toEqual([
{offset: 0, color: 'orange'}, {offset: 1, color: 'blue'}
]);
@ -214,7 +217,7 @@ import {makeTrigger} from '../shared';
]);
expect(() => {
const trans = buildTransition(result, element, false, true) !;
const trans = buildTransition(result, element, false, true)!;
}).not.toThrow();
});
@ -222,14 +225,14 @@ import {makeTrigger} from '../shared';
it('should alias the :enter transition as void => *', () => {
const result = makeTrigger('name', [transition(':enter', animate(3333))]);
const trans = buildTransition(result, element, 'void', 'something') !;
const trans = buildTransition(result, element, 'void', 'something')!;
expect(trans.timelines[0].duration).toEqual(3333);
});
it('should alias the :leave transition as * => void', () => {
const result = makeTrigger('name', [transition(':leave', animate(3333))]);
const trans = buildTransition(result, element, 'something', 'void') !;
const trans = buildTransition(result, element, 'something', 'void')!;
expect(trans.timelines[0].duration).toEqual(3333);
});
});
@ -242,12 +245,12 @@ function buildTransition(
fromOptions?: AnimationOptions, toOptions?: AnimationOptions): AnimationTransitionInstruction|
null {
const params = toOptions && toOptions.params || {};
const trans = trigger.matchTransition(fromState, toState, element, params) !;
const trans = trigger.matchTransition(fromState, toState, element, params)!;
if (trans) {
const driver = new MockAnimationDriver();
return trans.build(
driver, element, fromState, toState, ENTER_CLASSNAME, LEAVE_CLASSNAME, fromOptions,
toOptions) !;
toOptions)!;
}
return null;
}

View File

@ -16,13 +16,13 @@ import {WebAnimationsStyleNormalizer} from '../../../src/dsl/style_normalization
expect(normalizer.normalizePropertyName('width', [])).toEqual('width');
expect(normalizer.normalizePropertyName('border-width', [])).toEqual('borderWidth');
expect(normalizer.normalizePropertyName('borderHeight', [])).toEqual('borderHeight');
expect(normalizer.normalizePropertyName('-webkit-animation', [
])).toEqual('WebkitAnimation');
expect(normalizer.normalizePropertyName('-webkit-animation', []))
.toEqual('WebkitAnimation');
});
});
describe('normalizeStyleValue', () => {
function normalize(prop: string, val: string | number): string {
function normalize(prop: string, val: string|number): string {
const errors: string[] = [];
const result = normalizer.normalizeStyleValue(prop, prop, val, errors);
if (errors.length) {

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {TestBed, fakeAsync, flushMicrotasks} from '@angular/core/testing';
import {fakeAsync, flushMicrotasks, TestBed} from '@angular/core/testing';
import {CssKeyframesDriver} from '../../../src/render/css_keyframes/css_keyframes_driver';
import {CssKeyframesPlayer} from '../../../src/render/css_keyframes/css_keyframes_player';
@ -16,7 +16,7 @@ import {assertElementExistsInDom, createElement, findKeyframeDefinition, forceRe
const CSS_KEYFRAME_RULE_TYPE = 7;
describe('CssKeyframesDriver tests', () => {
if (isNode || typeof(window as any)['AnimationEvent'] == 'undefined') return;
if (isNode || typeof (window as any)['AnimationEvent'] == 'undefined') return;
describe('building keyframes', () => {
it('should build CSS keyframe style object containing the keyframe styles', () => {
@ -28,7 +28,7 @@ describe('CssKeyframesDriver tests', () => {
{opacity: 1, width: '200px', offset: 1},
]);
const head = document.querySelector('head') !;
const head = document.querySelector('head')!;
head.appendChild(kfElm);
forceReflow();
@ -67,7 +67,7 @@ describe('CssKeyframesDriver tests', () => {
{width: '200px', offset: 1},
]);
const head = document.querySelector('head') !;
const head = document.querySelector('head')!;
head.appendChild(kfElm);
forceReflow();
@ -261,7 +261,7 @@ describe('CssKeyframesDriver tests', () => {
player.play();
player.finish();
player.beforeDestroy !();
player.beforeDestroy!();
expect(player.currentSnapshot).toEqual({
width: '999px',
height: '999px',

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {TestBed, fakeAsync, flushMicrotasks} from '@angular/core/testing';
import {fakeAsync, flushMicrotasks, TestBed} from '@angular/core/testing';
import {DirectStylePlayer} from '../../../src/render/css_keyframes/direct_style_player';

View File

@ -13,7 +13,7 @@ import {assertStyle, createElement, makeAnimationEvent, supportsAnimationEventCr
const EMPTY_FN = () => {};
{
describe('ElementAnimationStyleHandler', () => {
if (isNode || typeof(window as any)['AnimationEvent'] == 'undefined') return;
if (isNode || typeof (window as any)['AnimationEvent'] == 'undefined') return;
it('should add and remove an animation on to an element\'s styling', () => {
const element = createElement();

View File

@ -10,7 +10,7 @@ export function forceReflow() {
}
export function makeAnimationEvent(
startOrEnd: 'start' | 'end', animationName: string, elapsedTime: number, timestamp?: number) {
startOrEnd: 'start'|'end', animationName: string, elapsedTime: number, timestamp?: number) {
const e = new AnimationEvent('animation' + startOrEnd, {animationName, elapsedTime});
if (timestamp) {
(e as any)._ngTestManualTimestamp = timestamp;

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {AnimationMetadata, animate, style} from '@angular/animations';
import {animate, AnimationMetadata, style} from '@angular/animations';
import {AnimationStyleNormalizer, NoopAnimationStyleNormalizer} from '../../src/dsl/style_normalization/animation_style_normalizer';
import {AnimationDriver} from '../../src/render/animation_driver';
@ -14,98 +14,101 @@ import {TimelineAnimationEngine} from '../../src/render/timeline_animation_engin
import {MockAnimationDriver, MockAnimationPlayer} from '../../testing/src/mock_animation_driver';
(function() {
const defaultDriver = new MockAnimationDriver();
const defaultDriver = new MockAnimationDriver();
function makeEngine(body: any, driver?: AnimationDriver, normalizer?: AnimationStyleNormalizer) {
return new TimelineAnimationEngine(
body, driver || defaultDriver, normalizer || new NoopAnimationStyleNormalizer());
}
function makeEngine(body: any, driver?: AnimationDriver, normalizer?: AnimationStyleNormalizer) {
return new TimelineAnimationEngine(
body, driver || defaultDriver, normalizer || new NoopAnimationStyleNormalizer());
}
// these tests are only mean't to be run within the DOM
if (isNode) return;
// these tests are only mean't to be run within the DOM
if (isNode) return;
describe('TimelineAnimationEngine', () => {
let element: any;
describe('TimelineAnimationEngine', () => {
let element: any;
beforeEach(() => {
MockAnimationDriver.log = [];
element = document.createElement('div');
document.body.appendChild(element);
});
afterEach(() => document.body.removeChild(element));
it('should animate a timeline', () => {
const engine = makeEngine(getBodyNode());
const steps = [style({height: 100}), animate(1000, style({height: 0}))];
expect(MockAnimationDriver.log.length).toEqual(0);
invokeAnimation(engine, element, steps);
expect(MockAnimationDriver.log.length).toEqual(1);
});
it('should not destroy timeline-based animations after they have finished', () => {
const engine = makeEngine(getBodyNode());
const log: string[] = [];
function capture(value: string) {
return () => { log.push(value); };
}
const steps = [style({height: 0}), animate(1000, style({height: 500}))];
const player = invokeAnimation(engine, element, steps);
player.onDone(capture('done'));
player.onDestroy(capture('destroy'));
expect(log).toEqual([]);
player.finish();
expect(log).toEqual(['done']);
player.destroy();
expect(log).toEqual(['done', 'destroy']);
});
it('should normalize the style values that are animateTransitioned within an a timeline animation',
() => {
const engine =
makeEngine(getBodyNode(), defaultDriver, new SuffixNormalizer('-normalized'));
const steps = [
style({width: '333px'}),
animate(1000, style({width: '999px'})),
];
const player = invokeAnimation(engine, element, steps) as MockAnimationPlayer;
expect(player.keyframes).toEqual([
{'width-normalized': '333px-normalized', offset: 0},
{'width-normalized': '999px-normalized', offset: 1}
]);
});
it('should normalize `*` values', () => {
const driver = new SuperMockDriver();
const engine = makeEngine(getBodyNode(), driver);
const steps = [
style({width: '*'}),
animate(1000, style({width: '999px'})),
];
const player = invokeAnimation(engine, element, steps) as MockAnimationPlayer;
expect(player.keyframes).toEqual([{width: '*star*', offset: 0}, {width: '999px', offset: 1}]);
});
beforeEach(() => {
MockAnimationDriver.log = [];
element = document.createElement('div');
document.body.appendChild(element);
});
afterEach(() => document.body.removeChild(element));
it('should animate a timeline', () => {
const engine = makeEngine(getBodyNode());
const steps = [style({height: 100}), animate(1000, style({height: 0}))];
expect(MockAnimationDriver.log.length).toEqual(0);
invokeAnimation(engine, element, steps);
expect(MockAnimationDriver.log.length).toEqual(1);
});
it('should not destroy timeline-based animations after they have finished', () => {
const engine = makeEngine(getBodyNode());
const log: string[] = [];
function capture(value: string) {
return () => {
log.push(value);
};
}
const steps = [style({height: 0}), animate(1000, style({height: 500}))];
const player = invokeAnimation(engine, element, steps);
player.onDone(capture('done'));
player.onDestroy(capture('destroy'));
expect(log).toEqual([]);
player.finish();
expect(log).toEqual(['done']);
player.destroy();
expect(log).toEqual(['done', 'destroy']);
});
it('should normalize the style values that are animateTransitioned within an a timeline animation',
() => {
const engine = makeEngine(getBodyNode(), defaultDriver, new SuffixNormalizer('-normalized'));
const steps = [
style({width: '333px'}),
animate(1000, style({width: '999px'})),
];
const player = invokeAnimation(engine, element, steps) as MockAnimationPlayer;
expect(player.keyframes).toEqual([
{'width-normalized': '333px-normalized', offset: 0},
{'width-normalized': '999px-normalized', offset: 1}
]);
});
it('should normalize `*` values', () => {
const driver = new SuperMockDriver();
const engine = makeEngine(getBodyNode(), driver);
const steps = [
style({width: '*'}),
animate(1000, style({width: '999px'})),
];
const player = invokeAnimation(engine, element, steps) as MockAnimationPlayer;
expect(player.keyframes).toEqual([{width: '*star*', offset: 0}, {width: '999px', offset: 1}]);
});
});
})();
function invokeAnimation(
engine: TimelineAnimationEngine, element: any, steps: AnimationMetadata | AnimationMetadata[],
engine: TimelineAnimationEngine, element: any, steps: AnimationMetadata|AnimationMetadata[],
id: string = 'id') {
engine.register(id, steps);
return engine.create(id, element);
}
class SuffixNormalizer extends AnimationStyleNormalizer {
constructor(private _suffix: string) { super(); }
constructor(private _suffix: string) {
super();
}
normalizePropertyName(propertyName: string, errors: string[]): string {
return propertyName + this._suffix;
@ -119,5 +122,7 @@ class SuffixNormalizer extends AnimationStyleNormalizer {
}
class SuperMockDriver extends MockAnimationDriver {
computeStyle(element: any, prop: string, defaultValue?: string): string { return '*star*'; }
computeStyle(element: any, prop: string, defaultValue?: string): string {
return '*star*';
}
}

View File

@ -13,7 +13,9 @@ import {WebAnimationsPlayer} from '../../../src/render/web_animations/web_animat
let innerPlayer: MockDomAnimation|null = null;
beforeEach(() => {
element = {};
element['animate'] = () => { return innerPlayer = new MockDomAnimation(); };
element['animate'] = () => {
return innerPlayer = new MockDomAnimation();
};
});
describe('WebAnimationsPlayer tests', () => {
@ -26,7 +28,7 @@ import {WebAnimationsPlayer} from '../../../src/render/web_animations/web_animat
const player = new WebAnimationsPlayer(element, keyframes, {duration: 1000});
player.init();
const p = innerPlayer !;
const p = innerPlayer!;
expect(p.log).toEqual(['pause']);
player.play();
@ -42,7 +44,7 @@ import {WebAnimationsPlayer} from '../../../src/render/web_animations/web_animat
const player = new WebAnimationsPlayer(element, keyframes, {duration: 1000});
player.play();
const p = innerPlayer !;
const p = innerPlayer!;
expect(p.log).toEqual(['play']);
});
@ -70,10 +72,18 @@ import {WebAnimationsPlayer} from '../../../src/render/web_animations/web_animat
class MockDomAnimation implements DOMAnimation {
log: string[] = [];
cancel(): void { this.log.push('cancel'); }
play(): void { this.log.push('play'); }
pause(): void { this.log.push('pause'); }
finish(): void { this.log.push('finish'); }
cancel(): void {
this.log.push('cancel');
}
play(): void {
this.log.push('play');
}
pause(): void {
this.log.push('pause');
}
finish(): void {
this.log.push('finish');
}
onfinish: Function = () => {};
position: number = 0;
currentTime: number = 0;

View File

@ -21,8 +21,8 @@ export function makeTrigger(
const triggerAst = buildAnimationAst(driver, triggerData, errors) as TriggerAst;
if (!skipErrors && errors.length) {
const LINE_START = '\n - ';
throw new Error(
`Animation parsing for the ${name} trigger have failed:${LINE_START}${errors.join(LINE_START)}`);
throw new Error(`Animation parsing for the ${name} trigger have failed:${LINE_START}${
errors.join(LINE_START)}`);
}
return buildTrigger(name, triggerAst);
}

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {AUTO_STYLE, AnimationPlayer, NoopAnimationPlayer, ɵStyleData} from '@angular/animations';
import {AnimationPlayer, AUTO_STYLE, NoopAnimationPlayer, ɵStyleData} from '@angular/animations';
import {AnimationDriver, ɵallowPreviousPlayerStylesMerge as allowPreviousPlayerStylesMerge, ɵcontainsElement as containsElement, ɵinvokeQuery as invokeQuery, ɵmatchesElement as matchesElement, ɵvalidateStyleProperty as validateStyleProperty} from '@angular/animations/browser';
@ -15,13 +15,17 @@ import {AnimationDriver, ɵallowPreviousPlayerStylesMerge as allowPreviousPlayer
export class MockAnimationDriver implements AnimationDriver {
static log: AnimationPlayer[] = [];
validateStyleProperty(prop: string): boolean { return validateStyleProperty(prop); }
validateStyleProperty(prop: string): boolean {
return validateStyleProperty(prop);
}
matchesElement(element: any, selector: string): boolean {
return matchesElement(element, selector);
}
containsElement(elm1: any, elm2: any): boolean { return containsElement(elm1, elm2); }
containsElement(elm1: any, elm2: any): boolean {
return containsElement(elm1, elm2);
}
query(element: any, selector: string, multi: boolean): any[] {
return invokeQuery(element, selector, multi);
@ -32,7 +36,7 @@ export class MockAnimationDriver implements AnimationDriver {
}
animate(
element: any, keyframes: {[key: string]: string | number}[], duration: number, delay: number,
element: any, keyframes: {[key: string]: string|number}[], duration: number, delay: number,
easing: string, previousPlayers: any[] = []): MockAnimationPlayer {
const player =
new MockAnimationPlayer(element, keyframes, duration, delay, easing, previousPlayers);
@ -47,12 +51,12 @@ export class MockAnimationDriver implements AnimationDriver {
export class MockAnimationPlayer extends NoopAnimationPlayer {
private __finished = false;
private __started = false;
public previousStyles: {[key: string]: string | number} = {};
public previousStyles: {[key: string]: string|number} = {};
private _onInitFns: (() => any)[] = [];
public currentSnapshot: ɵStyleData = {};
constructor(
public element: any, public keyframes: {[key: string]: string | number}[],
public element: any, public keyframes: {[key: string]: string|number}[],
public duration: number, public delay: number, public easing: string,
public previousPlayers: any[]) {
super(duration, delay);
@ -68,7 +72,9 @@ export class MockAnimationPlayer extends NoopAnimationPlayer {
}
/* @internal */
onInit(fn: () => any) { this._onInitFns.push(fn); }
onInit(fn: () => any) {
this._onInitFns.push(fn);
}
/* @internal */
init() {
@ -95,7 +101,9 @@ export class MockAnimationPlayer extends NoopAnimationPlayer {
this.__started = true;
}
hasStarted() { return this.__started; }
hasStarted() {
return this.__started;
}
beforeDestroy() {
const captures: ɵStyleData = {};

View File

@ -9,7 +9,9 @@
/**
* Represents a set of CSS styles for use in an animation style.
*/
export interface ɵStyleData { [key: string]: string|number; }
export interface ɵStyleData {
[key: string]: string|number;
}
/**
* Represents animation-step timing parameters for an animation step.
@ -67,10 +69,10 @@ export declare interface AnimationOptions {
*/
delay?: number|string;
/**
* A set of developer-defined parameters that modify styling and timing
* when an animation action starts. An array of key-value pairs, where the provided value
* is used as a default.
*/
* A set of developer-defined parameters that modify styling and timing
* when an animation action starts. An array of key-value pairs, where the provided value
* is used as a default.
*/
params?: {[name: string]: any};
}
@ -81,7 +83,9 @@ export declare interface AnimationOptions {
*
* @publicApi
*/
export declare interface AnimateChildOptions extends AnimationOptions { duration?: number|string; }
export declare interface AnimateChildOptions extends AnimationOptions {
duration?: number|string;
}
/**
* @description Constants for the categories of parameters that can be defined for animations.
@ -171,7 +175,9 @@ export const AUTO_STYLE = '*';
*
* @publicApi
*/
export interface AnimationMetadata { type: AnimationMetadataType; }
export interface AnimationMetadata {
type: AnimationMetadataType;
}
/**
* Contains an animation trigger. Instantiated and returned by the
@ -181,8 +187,8 @@ export interface AnimationMetadata { type: AnimationMetadataType; }
*/
export interface AnimationTriggerMetadata extends AnimationMetadata {
/**
* The trigger name, used to associate it with an element. Unique within the component.
*/
* The trigger name, used to associate it with an element. Unique within the component.
*/
name: string;
/**
* An animation definition object, containing an array of state and transition declarations.
@ -654,8 +660,9 @@ export function trigger(name: string, definitions: AnimationMetadata[]): Animati
* @publicApi
*/
export function animate(
timings: string | number, styles: AnimationStyleMetadata | AnimationKeyframesSequenceMetadata |
null = null): AnimationAnimateMetadata {
timings: string|number,
styles: AnimationStyleMetadata|AnimationKeyframesSequenceMetadata|null =
null): AnimationAnimateMetadata {
return {type: AnimationMetadataType.Animate, styles, timings};
}
@ -693,7 +700,7 @@ export function animate(
* @publicApi
*/
export function group(
steps: AnimationMetadata[], options: AnimationOptions | null = null): AnimationGroupMetadata {
steps: AnimationMetadata[], options: AnimationOptions|null = null): AnimationGroupMetadata {
return {type: AnimationMetadataType.Group, steps, options};
}
@ -721,7 +728,8 @@ export function group(
* @usageNotes
* When you pass an array of steps to a
* `transition()` call, the steps run sequentially by default.
* Compare this to the `{@link animations/group group()}` call, which runs animation steps in parallel.
* Compare this to the `{@link animations/group group()}` call, which runs animation steps in
*parallel.
*
* When a sequence is used within a `{@link animations/group group()}` or a `transition()` call,
* execution continues to the next instruction only after each of the inner animation
@ -729,8 +737,8 @@ export function group(
*
* @publicApi
**/
export function sequence(steps: AnimationMetadata[], options: AnimationOptions | null = null):
AnimationSequenceMetadata {
export function sequence(
steps: AnimationMetadata[], options: AnimationOptions|null = null): AnimationSequenceMetadata {
return {type: AnimationMetadataType.Sequence, steps, options};
}
@ -773,9 +781,8 @@ export function sequence(steps: AnimationMetadata[], options: AnimationOptions |
*
* @publicApi
**/
export function style(
tokens: '*' | {[key: string]: string | number} |
Array<'*'|{[key: string]: string | number}>): AnimationStyleMetadata {
export function style(tokens: '*'|{[key: string]: string | number}|
Array<'*'|{[key: string]: string | number}>): AnimationStyleMetadata {
return {type: AnimationMetadataType.Style, styles: tokens, offset: null};
}
@ -1032,10 +1039,10 @@ export function keyframes(steps: AnimationStyleMetadata[]): AnimationKeyframesSe
* @publicApi
**/
export function transition(
stateChangeExpr: string | ((fromState: string, toState: string, element?: any,
params?: {[key: string]: any}) => boolean),
steps: AnimationMetadata | AnimationMetadata[],
options: AnimationOptions | null = null): AnimationTransitionMetadata {
stateChangeExpr: string|
((fromState: string, toState: string, element?: any, params?: {[key: string]: any}) => boolean),
steps: AnimationMetadata|AnimationMetadata[],
options: AnimationOptions|null = null): AnimationTransitionMetadata {
return {type: AnimationMetadataType.Transition, expr: stateChangeExpr, animation: steps, options};
}
@ -1085,8 +1092,8 @@ export function transition(
* @publicApi
*/
export function animation(
steps: AnimationMetadata | AnimationMetadata[],
options: AnimationOptions | null = null): AnimationReferenceMetadata {
steps: AnimationMetadata|AnimationMetadata[],
options: AnimationOptions|null = null): AnimationReferenceMetadata {
return {type: AnimationMetadataType.Reference, animation: steps, options};
}
@ -1109,7 +1116,7 @@ export function animation(
*
* @publicApi
*/
export function animateChild(options: AnimateChildOptions | null = null):
export function animateChild(options: AnimateChildOptions|null = null):
AnimationAnimateChildMetadata {
return {type: AnimationMetadataType.AnimateChild, options};
}
@ -1126,7 +1133,7 @@ export function animateChild(options: AnimateChildOptions | null = null):
*/
export function useAnimation(
animation: AnimationReferenceMetadata,
options: AnimationOptions | null = null): AnimationAnimateRefMetadata {
options: AnimationOptions|null = null): AnimationAnimateRefMetadata {
return {type: AnimationMetadataType.AnimateRef, animation, options};
}
@ -1179,7 +1186,7 @@ export function useAnimation(
* ### Usage Example
*
* The following example queries for inner elements and animates them
* individually using `animate()`.
* individually using `animate()`.
*
* ```typescript
* @Component({
@ -1218,8 +1225,8 @@ export function useAnimation(
* @publicApi
*/
export function query(
selector: string, animation: AnimationMetadata | AnimationMetadata[],
options: AnimationQueryOptions | null = null): AnimationQueryMetadata {
selector: string, animation: AnimationMetadata|AnimationMetadata[],
options: AnimationQueryOptions|null = null): AnimationQueryMetadata {
return {type: AnimationMetadataType.Query, selector, animation, options};
}
@ -1303,8 +1310,7 @@ export function query(
*
* @publicApi
*/
export function stagger(
timings: string | number,
animation: AnimationMetadata | AnimationMetadata[]): AnimationStaggerMetadata {
export function stagger(timings: string|number, animation: AnimationMetadata|AnimationMetadata[]):
AnimationStaggerMetadata {
return {type: AnimationMetadataType.Stagger, timings, animation};
}

View File

@ -13,7 +13,7 @@
*/
export {AnimationBuilder, AnimationFactory} from './animation_builder';
export {AnimationEvent} from './animation_event';
export {AUTO_STYLE, AnimateChildOptions, AnimateTimings, AnimationAnimateChildMetadata, AnimationAnimateMetadata, AnimationAnimateRefMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationQueryMetadata, AnimationQueryOptions, AnimationReferenceMetadata, AnimationSequenceMetadata, AnimationStaggerMetadata, AnimationStateMetadata, AnimationStyleMetadata, AnimationTransitionMetadata, AnimationTriggerMetadata, animate, animateChild, animation, group, keyframes, query, sequence, stagger, state, style, transition, trigger, useAnimation, ɵStyleData} from './animation_metadata';
export {animate, animateChild, AnimateChildOptions, AnimateTimings, animation, AnimationAnimateChildMetadata, AnimationAnimateMetadata, AnimationAnimateRefMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationQueryMetadata, AnimationQueryOptions, AnimationReferenceMetadata, AnimationSequenceMetadata, AnimationStaggerMetadata, AnimationStateMetadata, AnimationStyleMetadata, AnimationTransitionMetadata, AnimationTriggerMetadata, AUTO_STYLE, group, keyframes, query, sequence, stagger, state, style, transition, trigger, useAnimation, ɵStyleData} from './animation_metadata';
export {AnimationPlayer, NoopAnimationPlayer} from './players/animation_player';
export * from './private_export';

View File

@ -69,9 +69,13 @@ export class AnimationGroupPlayer implements AnimationPlayer {
}
}
init(): void { this.players.forEach(player => player.init()); }
init(): void {
this.players.forEach(player => player.init());
}
onStart(fn: () => void): void { this._onStartFns.push(fn); }
onStart(fn: () => void): void {
this._onStartFns.push(fn);
}
private _onStart() {
if (!this.hasStarted()) {
@ -81,11 +85,17 @@ export class AnimationGroupPlayer implements AnimationPlayer {
}
}
onDone(fn: () => void): void { this._onDoneFns.push(fn); }
onDone(fn: () => void): void {
this._onDoneFns.push(fn);
}
onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); }
onDestroy(fn: () => void): void {
this._onDestroyFns.push(fn);
}
hasStarted() { return this._started; }
hasStarted() {
return this._started;
}
play() {
if (!this.parentPlayer) {
@ -95,16 +105,22 @@ export class AnimationGroupPlayer implements AnimationPlayer {
this.players.forEach(player => player.play());
}
pause(): void { this.players.forEach(player => player.pause()); }
pause(): void {
this.players.forEach(player => player.pause());
}
restart(): void { this.players.forEach(player => player.restart()); }
restart(): void {
this.players.forEach(player => player.restart());
}
finish(): void {
this._onFinish();
this.players.forEach(player => player.finish());
}
destroy(): void { this._onDestroy(); }
destroy(): void {
this._onDestroy();
}
private _onDestroy() {
if (!this._destroyed) {

View File

@ -94,11 +94,13 @@ export interface AnimationPlayer {
* Provides a callback to invoke before the animation is destroyed.
*/
beforeDestroy?: () => any;
/** @internal
/**
* @internal
* Internal
*/
triggerCallback?: (phaseName: string) => void;
/** @internal
/**
* @internal
* Internal
*/
disabled?: boolean;
@ -124,7 +126,9 @@ export class NoopAnimationPlayer implements AnimationPlayer {
private _finished = false;
public parentPlayer: AnimationPlayer|null = null;
public readonly totalTime: number;
constructor(duration: number = 0, delay: number = 0) { this.totalTime = duration + delay; }
constructor(duration: number = 0, delay: number = 0) {
this.totalTime = duration + delay;
}
private _onFinish() {
if (!this._finished) {
this._finished = true;
@ -132,10 +136,18 @@ export class NoopAnimationPlayer implements AnimationPlayer {
this._onDoneFns = [];
}
}
onStart(fn: () => void): void { this._onStartFns.push(fn); }
onDone(fn: () => void): void { this._onDoneFns.push(fn); }
onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); }
hasStarted(): boolean { return this._started; }
onStart(fn: () => void): void {
this._onStartFns.push(fn);
}
onDone(fn: () => void): void {
this._onDoneFns.push(fn);
}
onDestroy(fn: () => void): void {
this._onDestroyFns.push(fn);
}
hasStarted(): boolean {
return this._started;
}
init(): void {}
play(): void {
if (!this.hasStarted()) {
@ -146,7 +158,9 @@ export class NoopAnimationPlayer implements AnimationPlayer {
}
/** @internal */
triggerMicrotask() { scheduleMicroTask(() => this._onFinish()); }
triggerMicrotask() {
scheduleMicroTask(() => this._onFinish());
}
private _onStart() {
this._onStartFns.forEach(fn => fn());
@ -155,7 +169,9 @@ export class NoopAnimationPlayer implements AnimationPlayer {
pause(): void {}
restart(): void {}
finish(): void { this._onFinish(); }
finish(): void {
this._onFinish();
}
destroy(): void {
if (!this._destroyed) {
this._destroyed = true;
@ -169,7 +185,9 @@ export class NoopAnimationPlayer implements AnimationPlayer {
}
reset(): void {}
setPosition(position: number): void {}
getPosition(): number { return 0; }
getPosition(): number {
return 0;
}
/** @internal */
triggerCallback(phaseName: string): void {

View File

@ -69,7 +69,9 @@ import {scheduleMicroTask} from '../src/util';
const log: string[] = [];
const player = new NoopAnimationPlayer();
player.onStart(() => { scheduleMicroTask(() => log.push('started')); });
player.onStart(() => {
scheduleMicroTask(() => log.push('started'));
});
player.onDone(() => log.push('done'));
expect(log).toEqual([]);

View File

@ -38,7 +38,7 @@ export function runMain(
// API extractor doesn't always support the version of TypeScript used in the repo
// example: at the moment it is not compatable with 3.2
// to use the internal TypeScript we shall not create a program but rather pass a parsed tsConfig.
const parsedTsConfig = parsedConfig !.config as any;
const parsedTsConfig = parsedConfig!.config as any;
const compilerOptions = parsedTsConfig.compilerOptions;
for (const [key, values] of Object.entries<string[]>(compilerOptions.paths)) {
if (key === '*') {
@ -113,8 +113,8 @@ api-extractor: running with
const dtsBundleOuts = dtsBundleOut.split(',');
if (entryPoints.length !== entryPoints.length) {
throw new Error(
`Entry points count (${entryPoints.length}) does not match Bundle out count (${dtsBundleOuts.length})`);
throw new Error(`Entry points count (${entryPoints.length}) does not match Bundle out count (${
dtsBundleOuts.length})`);
}
for (let i = 0; i < entryPoints.length; i++) {

View File

@ -9,12 +9,12 @@
/// <reference types='node'/>
import {spawn} from 'child_process';
import {copyFileSync, existsSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync} from 'fs';
import {copyFileSync, existsSync, readdirSync, readFileSync, statSync, unlinkSync, writeFileSync} from 'fs';
import {platform} from 'os';
import {dirname, join, normalize} from 'path';
export type Executable = 'bazel' | 'ibazel';
export type Command = 'build' | 'test' | 'run' | 'coverage' | 'query';
export type Executable = 'bazel'|'ibazel';
export type Command = 'build'|'test'|'run'|'coverage'|'query';
/**
* Spawn the Bazel process. Trap SINGINT to make sure Bazel process is killed.

View File

@ -13,27 +13,29 @@ import {JsonObject} from '@angular-devkit/core';
import {checkInstallation, copyBazelFiles, deleteBazelFiles, getTemplateDir, runBazel} from './bazel';
import {Schema} from './schema';
async function _bazelBuilder(options: JsonObject & Schema, context: BuilderContext, ):
Promise<BuilderOutput> {
const {logger, workspaceRoot} = context;
const {bazelCommand, leaveBazelFilesOnDisk, targetLabel, watch} = options;
const executable = watch ? 'ibazel' : 'bazel';
const binary = checkInstallation(executable, workspaceRoot);
const templateDir = getTemplateDir(workspaceRoot);
const bazelFiles = copyBazelFiles(workspaceRoot, templateDir);
async function _bazelBuilder(
options: JsonObject&Schema,
context: BuilderContext,
): Promise<BuilderOutput> {
const {logger, workspaceRoot} = context;
const {bazelCommand, leaveBazelFilesOnDisk, targetLabel, watch} = options;
const executable = watch ? 'ibazel' : 'bazel';
const binary = checkInstallation(executable, workspaceRoot);
const templateDir = getTemplateDir(workspaceRoot);
const bazelFiles = copyBazelFiles(workspaceRoot, templateDir);
try {
const flags: string[] = [];
await runBazel(workspaceRoot, binary, bazelCommand, targetLabel, flags);
return {success: true};
} catch (err) {
logger.error(err.message);
return {success: false};
} finally {
if (!leaveBazelFilesOnDisk) {
deleteBazelFiles(bazelFiles); // this will never throw
}
}
try {
const flags: string[] = [];
await runBazel(workspaceRoot, binary, bazelCommand, targetLabel, flags);
return {success: true};
} catch (err) {
logger.error(err.message);
return {success: false};
} finally {
if (!leaveBazelFilesOnDisk) {
deleteBazelFiles(bazelFiles); // this will never throw
}
}
}
export default createBuilder(_bazelBuilder);

View File

@ -22,7 +22,9 @@ function main(args: string[]): number {
const paramFilePath = args[0];
// Bazel params may be surrounded with quotes
function unquoteParameter(s: string) { return s.replace(/^'(.*)'$/, '$1'); }
function unquoteParameter(s: string) {
return s.replace(/^'(.*)'$/, '$1');
}
// Parameters are specified in the file one per line.
const params = fs.readFileSync(paramFilePath, 'utf-8').split('\n').map(unquoteParameter);
@ -109,7 +111,7 @@ function main(args: string[]): number {
* @param inputPath Path to the file in the input tree.
* @param fileContent Content of the file.
*/
function writeFileFromInputPath(inputPath: string, fileContent: string | Buffer) {
function writeFileFromInputPath(inputPath: string, fileContent: string|Buffer) {
// We want the relative path from the given file to its ancestor "root" directory.
// This root depends on whether the file lives in the source tree (srcDir) as a basic file
// input to ng_package, the bin output tree (binDir) as the output of another rule, or
@ -164,9 +166,15 @@ function main(args: string[]): number {
esm2015.forEach(file => writeEsmFile(file, '', 'esm2015'));
esm5.forEach(file => writeEsmFile(file, '.esm5', 'esm5'));
bundles.forEach(bundle => { copyFile(bundle, out, 'bundles'); });
fesm2015.forEach(file => { copyFile(file, out, 'fesm2015'); });
fesm5.forEach(file => { copyFile(file, out, 'fesm5'); });
bundles.forEach(bundle => {
copyFile(bundle, out, 'bundles');
});
fesm2015.forEach(file => {
copyFile(file, out, 'fesm2015');
});
fesm5.forEach(file => {
copyFile(file, out, 'fesm5');
});
// Copy all type definitions into the package. This is necessary so that developers can use
// the package with type definitions.
@ -419,14 +427,16 @@ export * from '${srcDirRelative(inputPath, typingsFile.replace(/\.d\.tsx?$/, '')
* Normalizes the specified path by replacing backslash separators with Posix
* forward slash separators.
*/
function normalizeSeparators(path: string): string { return path.replace(/\\/g, '/'); }
function normalizeSeparators(path: string): string {
return path.replace(/\\/g, '/');
}
/**
* Rewires metadata to point to the flattened dts file.
*
* @param metadataPath the metadata file path
* @param typingsPath the typings bundle entrypoint
*/
* Rewires metadata to point to the flattened dts file.
*
* @param metadataPath the metadata file path
* @param typingsPath the typings bundle entrypoint
*/
function rewireMetadata(metadataPath: string, typingsPath: string): string {
const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf-8'));
@ -470,7 +480,7 @@ export function newArray<T>(size: number, value: T): T[];
export function newArray<T>(size: number, value?: T): T[] {
const list: T[] = [];
for (let i = 0; i < size; i++) {
list.push(value !);
list.push(value!);
}
return list;
}

View File

@ -7,7 +7,7 @@
*/
import * as ng from '@angular/compiler-cli';
import {BazelOptions, CachedFileLoader, CompilerHost, FileCache, FileLoader, UncachedFileLoader, constructManifest, debug, parseTsconfig, resolveNormalizedPath, runAsWorker, runWorkerLoop} from '@bazel/typescript';
import {BazelOptions, CachedFileLoader, CompilerHost, constructManifest, debug, FileCache, FileLoader, parseTsconfig, resolveNormalizedPath, runAsWorker, runWorkerLoop, UncachedFileLoader} from '@bazel/typescript';
import * as fs from 'fs';
import * as path from 'path';
import * as tsickle from 'tsickle';
@ -123,7 +123,12 @@ export function runOneBuild(args: string[], inputs?: {[path: string]: string}):
const {diagnostics} = compile({
allDepsCompiledWithBazel: ALL_DEPS_COMPILED_WITH_BAZEL,
useManifestPathsAsModuleName: _useManifestPathsAsModuleName,
expectedOuts: expectedOut, compilerOpts, tsHost, bazelOpts, files, inputs,
expectedOuts: expectedOut,
compilerOpts,
tsHost,
bazelOpts,
files,
inputs,
});
if (diagnostics.length) {
console.error(ng.formatDiagnostics(diagnostics));
@ -142,16 +147,24 @@ export function relativeToRootDirs(filePath: string, rootDirs: string[]): string
return filePath;
}
export function compile({allDepsCompiledWithBazel = true, useManifestPathsAsModuleName,
compilerOpts, tsHost, bazelOpts, files, inputs, expectedOuts,
gatherDiagnostics, bazelHost}: {
export function compile({
allDepsCompiledWithBazel = true,
useManifestPathsAsModuleName,
compilerOpts,
tsHost,
bazelOpts,
files,
inputs,
expectedOuts,
gatherDiagnostics,
bazelHost
}: {
allDepsCompiledWithBazel?: boolean,
useManifestPathsAsModuleName?: boolean,
compilerOpts: ng.CompilerOptions,
tsHost: ts.CompilerHost, inputs?: {[path: string]: string},
bazelOpts: BazelOptions,
files: string[],
expectedOuts: string[],
useManifestPathsAsModuleName?: boolean, compilerOpts: ng.CompilerOptions, tsHost: ts.CompilerHost,
inputs?: {[path: string]: string},
bazelOpts: BazelOptions,
files: string[],
expectedOuts: string[],
gatherDiagnostics?: (program: ng.Program) => ng.Diagnostics,
bazelHost?: CompilerHost,
}): {diagnostics: ng.Diagnostics, program: ng.Program} {
@ -362,7 +375,7 @@ export function compile({allDepsCompiledWithBazel = true, useManifestPathsAsModu
if ((compilerOpts.module === ts.ModuleKind.UMD || compilerOpts.module === ts.ModuleKind.AMD) &&
ngHost.amdModuleName) {
return ngHost.amdModuleName({ fileName: importedFilePath } as ts.SourceFile);
return ngHost.amdModuleName({fileName: importedFilePath} as ts.SourceFile);
}
// If no AMD module name has been set for the source file by the `@bazel/typescript` compiler
@ -434,8 +447,10 @@ export function compile({allDepsCompiledWithBazel = true, useManifestPathsAsModu
const {diagnostics, emitResult, program} = ng.performCompilation({
rootNames: files,
options: compilerOpts,
host: ngHost, emitCallback,
mergeEmitResultsCallback: tsickle.mergeEmitResults, gatherDiagnostics
host: ngHost,
emitCallback,
mergeEmitResultsCallback: tsickle.mergeEmitResults,
gatherDiagnostics
});
const tsickleEmitResult = emitResult as tsickle.EmitResult;
let externs = '/** @externs */\n';
@ -512,9 +527,9 @@ function convertToForwardSlashPath(filePath: string): string {
function gatherDiagnosticsForInputsOnly(
options: ng.CompilerOptions, bazelOpts: BazelOptions,
ngProgram: ng.Program): (ng.Diagnostic | ts.Diagnostic)[] {
ngProgram: ng.Program): (ng.Diagnostic|ts.Diagnostic)[] {
const tsProgram = ngProgram.getTsProgram();
const diagnostics: (ng.Diagnostic | ts.Diagnostic)[] = [];
const diagnostics: (ng.Diagnostic|ts.Diagnostic)[] = [];
// These checks mirror ts.getPreEmitDiagnostics, with the important
// exception of avoiding b/30708240, which is that if you call
// program.getDeclarationDiagnostics() it somehow corrupts the emit.

View File

@ -10,7 +10,6 @@ import {HostTree} from '@angular-devkit/schematics';
import {SchematicTestRunner, UnitTestTree} from '@angular-devkit/schematics/testing';
describe('ng-add schematic', () => {
const defaultOptions = {name: 'demo'};
let host: UnitTestTree;
let schematicRunner: SchematicTestRunner;
@ -61,7 +60,7 @@ describe('ng-add schematic', () => {
new SchematicTestRunner('@angular/bazel', require.resolve('../collection.json'));
});
it('throws if package.json is not found', async() => {
it('throws if package.json is not found', async () => {
expect(host.files).toContain('/package.json');
host.delete('/package.json');
@ -76,7 +75,7 @@ describe('ng-add schematic', () => {
expect(message).toBe('Could not read package.json.');
});
it('throws if angular.json is not found', async() => {
it('throws if angular.json is not found', async () => {
expect(host.files).toContain('/angular.json');
host.delete('/angular.json');
@ -91,7 +90,7 @@ describe('ng-add schematic', () => {
expect(message).toBe('Could not find angular.json');
});
it('should add @angular/bazel to package.json dependencies', async() => {
it('should add @angular/bazel to package.json dependencies', async () => {
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
const {files} = host;
expect(files).toContain('/package.json');
@ -106,7 +105,7 @@ describe('ng-add schematic', () => {
expect(Object.keys(json.devDependencies)).toContain(bazel);
});
it('should add @bazel/* dev dependencies', async() => {
it('should add @bazel/* dev dependencies', async () => {
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
const content = host.readContent('/package.json');
const json = JSON.parse(content);
@ -118,7 +117,7 @@ describe('ng-add schematic', () => {
expect(devDeps).toContain('@bazel/typescript');
});
it('should replace an existing dev dependency', async() => {
it('should replace an existing dev dependency', async () => {
expect(host.files).toContain('/package.json');
const packageJson = JSON.parse(host.readContent('/package.json'));
packageJson.devDependencies['@angular/bazel'] = '4.2.42';
@ -126,12 +125,12 @@ describe('ng-add schematic', () => {
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
const content = host.readContent('/package.json');
// It is possible that a dep gets added twice if the package already exists.
expect(content.match(/@angular\/bazel/g) !.length).toEqual(1);
expect(content.match(/@angular\/bazel/g)!.length).toEqual(1);
const json = JSON.parse(content);
expect(json.devDependencies['@angular/bazel']).toBe('1.2.3');
});
it('should remove an existing dependency', async() => {
it('should remove an existing dependency', async () => {
expect(host.files).toContain('/package.json');
const packageJson = JSON.parse(host.readContent('/package.json'));
packageJson.dependencies['@angular/bazel'] = '4.2.42';
@ -144,7 +143,7 @@ describe('ng-add schematic', () => {
expect(json.devDependencies['@angular/bazel']).toBe('1.2.3');
});
it('should remove unneeded dependencies', async() => {
it('should remove unneeded dependencies', async () => {
const packageJson = JSON.parse(host.readContent('/package.json'));
packageJson.devDependencies['@angular-devkit/build-angular'] = '1.2.3';
host.overwrite('/package.json', JSON.stringify(packageJson));
@ -154,7 +153,7 @@ describe('ng-add schematic', () => {
expect(json.devDependencies['angular-devkit/build-angular']).toBeUndefined();
});
it('should append to scripts.postinstall if it already exists', async() => {
it('should append to scripts.postinstall if it already exists', async () => {
const packageJson = JSON.parse(host.readContent('/package.json'));
packageJson['scripts'] = {
postinstall: 'angular rocks',
@ -167,7 +166,7 @@ describe('ng-add schematic', () => {
.toBe('angular rocks; ngcc --properties es2015 browser module main');
});
it('should update ngcc in scripts.postinstall if it already exists', async() => {
it('should update ngcc in scripts.postinstall if it already exists', async () => {
const packageJson = JSON.parse(host.readContent('/package.json'));
packageJson['scripts'] = {
postinstall:
@ -180,14 +179,14 @@ describe('ng-add schematic', () => {
expect(json.scripts['postinstall']).toBe('ngcc --properties es2015 browser module main');
});
it('should not create Bazel workspace file', async() => {
it('should not create Bazel workspace file', async () => {
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
const {files} = host;
expect(files).not.toContain('/WORKSPACE');
expect(files).not.toContain('/BUILD.bazel');
});
it('should produce main.dev.ts and main.prod.ts for AOT', async() => {
it('should produce main.dev.ts and main.prod.ts for AOT', async () => {
host.create('/src/main.ts', 'generated by CLI');
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
const {files} = host;
@ -199,7 +198,7 @@ describe('ng-add schematic', () => {
expect(files).toContain('/src/main.ts');
});
it('should not overwrite index.html with script tags', async() => {
it('should not overwrite index.html with script tags', async () => {
host.create('/src/index.html', '<html>Hello World</html>');
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
const {files} = host;
@ -209,14 +208,14 @@ describe('ng-add schematic', () => {
expect(content).not.toMatch('<script src="/bundle.min.js"></script>');
});
it('should generate main.dev.ts and main.prod.ts', async() => {
it('should generate main.dev.ts and main.prod.ts', async () => {
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
const {files} = host;
expect(files).toContain('/src/main.dev.ts');
expect(files).toContain('/src/main.prod.ts');
});
it('should overwrite .gitignore for bazel-out directory', async() => {
it('should overwrite .gitignore for bazel-out directory', async () => {
host.create('.gitignore', '\n# compiled output\n');
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
const {files} = host;
@ -225,7 +224,7 @@ describe('ng-add schematic', () => {
expect(content).toMatch('\n# compiled output\n/bazel-out\n');
});
it('should create a backup for original angular.json', async() => {
it('should create a backup for original angular.json', async () => {
expect(host.files).toContain('/angular.json');
const original = host.readContent('/angular.json');
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
@ -235,7 +234,7 @@ describe('ng-add schematic', () => {
expect(content).toMatch(original);
});
it('should update angular.json to use Bazel builder', async() => {
it('should update angular.json to use Bazel builder', async () => {
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
const {files} = host;
expect(files).toContain('/angular.json');
@ -256,7 +255,7 @@ describe('ng-add schematic', () => {
expect(lint.builder).toBe('@angular-devkit/build-angular:tslint');
});
it('should get defaultProject if name is not provided', async() => {
it('should get defaultProject if name is not provided', async () => {
const options = {};
host = await schematicRunner.runSchematicAsync('ng-add', options, host).toPromise();
const content = host.readContent('/angular.json');
@ -281,7 +280,7 @@ describe('ng-add schematic', () => {
['~7.0.1', false],
];
for (const [version, upgrade] of cases) {
it(`should ${upgrade ? '' : 'not '}upgrade v${version}')`, async() => {
it(`should ${upgrade ? '' : 'not '}upgrade v${version}')`, async () => {
host.overwrite('package.json', JSON.stringify({
name: 'demo',
dependencies: {
@ -305,7 +304,7 @@ describe('ng-add schematic', () => {
}
});
it('should add a postinstall step to package.json', async() => {
it('should add a postinstall step to package.json', async () => {
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
expect(host.files).toContain('/package.json');
const content = host.readContent('/package.json');
@ -313,7 +312,7 @@ describe('ng-add schematic', () => {
expect(json.scripts.postinstall).toBe('ngcc --properties es2015 browser module main');
});
it('should work when run on a minimal project (without test and e2e targets)', async() => {
it('should work when run on a minimal project (without test and e2e targets)', async () => {
host.overwrite('angular.json', JSON.stringify({
projects: {
'demo': {
@ -338,5 +337,4 @@ describe('ng-add schematic', () => {
expect(error).toBeNull();
});
});

View File

@ -8,8 +8,9 @@
* @fileoverview Schematics for ng-new project that builds with Bazel.
*/
import {Rule, Tree, chain, externalSchematic, schematic} from '@angular-devkit/schematics';
import {chain, externalSchematic, Rule, schematic, Tree} from '@angular-devkit/schematics';
import {validateProjectName} from '@schematics/angular/utility/validation';
import {Schema} from './schema';
export default function(options: Schema): Rule {

View File

@ -9,14 +9,16 @@
import {SchematicTestRunner} from '@angular-devkit/schematics/testing';
describe('ng-new schematic', () => {
const schematicRunner =
new SchematicTestRunner('@angular/bazel', require.resolve('../collection.json'), );
const schematicRunner = new SchematicTestRunner(
'@angular/bazel',
require.resolve('../collection.json'),
);
const defaultOptions = {
name: 'demo',
version: '7.0.0',
};
it('should call external @schematics/angular', async() => {
it('should call external @schematics/angular', async () => {
const options = {...defaultOptions};
const host = await schematicRunner.runSchematicAsync('ng-new', options).toPromise();
const {files} = host;
@ -25,7 +27,7 @@ describe('ng-new schematic', () => {
expect(files).toContain('/demo/package.json');
});
it('should call ng-add to generate additional files needed by Bazel', async() => {
it('should call ng-add to generate additional files needed by Bazel', async () => {
const options = {...defaultOptions};
const host = await schematicRunner.runSchematicAsync('ng-new', options).toPromise();
const {files} = host;

View File

@ -86,8 +86,8 @@ export interface Schema {
viewEncapsulation?: ViewEncapsulation;
}
/**
* Initial git repository commit information.
*/
* Initial git repository commit information.
*/
export declare type CommitUnion = boolean | CommitObject;
export interface CommitObject {
email: string;
@ -95,16 +95,16 @@ export interface CommitObject {
name: string;
}
/**
* The file extension or preprocessor to use for style files.
*/
* The file extension or preprocessor to use for style files.
*/
export declare enum Style {
Css = 'css',
Sass = 'sass',
Scss = 'scss',
}
/**
* The view encapsulation strategy to use in the initial project.
*/
* The view encapsulation strategy to use in the initial project.
*/
export declare enum ViewEncapsulation {
Emulated = 'Emulated',
Native = 'Native',

View File

@ -42,7 +42,7 @@ export function removeKeyValueInAstObject(
let length = end - start;
const match = content.slice(end).match(/^[,\s]+/);
if (match) {
length += match.pop() !.length;
length += match.pop()!.length;
}
recorder.remove(start, length);
if (i === node.properties.length - 1) { // last property
@ -60,6 +60,6 @@ export function removeKeyValueInAstObject(
/**
* Returns true if the specified 'node' is a JsonAstObject, false otherwise.
*/
export function isJsonAstObject(node: JsonAstNode | null): node is JsonAstObject {
export function isJsonAstObject(node: JsonAstNode|null): node is JsonAstObject {
return !!node && node.kind === 'object';
}

View File

@ -12,9 +12,10 @@ import {UnitTestTree} from '@angular-devkit/schematics/testing';
import {isJsonAstObject, removeKeyValueInAstObject, replacePropertyInAstObject} from './json-utils';
describe('JsonUtils', () => {
let tree: UnitTestTree;
beforeEach(() => { tree = new UnitTestTree(new HostTree()); });
beforeEach(() => {
tree = new UnitTestTree(new HostTree());
});
describe('replacePropertyInAstObject', () => {
it('should replace property', () => {

View File

@ -30,8 +30,9 @@ describe('@angular/common ng_package', () => {
});
// regression test for https://github.com/angular/angular/issues/23217
// Note, we don't have an e2e test that covers this
it('doesn\'t pass require in a way that breaks webpack static analysis',
() => { expect(shx.cat('locales/fr.js')).not.toContain('factory(require, exports)'); });
it('doesn\'t pass require in a way that breaks webpack static analysis', () => {
expect(shx.cat('locales/fr.js')).not.toContain('factory(require, exports)');
});
});
it('should have right bundle files', () => {
@ -59,8 +60,9 @@ describe('@angular/common ng_package', () => {
]);
});
it('should reference core using global symbol in umd',
() => { expect(shx.cat('bundles/common.umd.js')).toContain('global.ng.core'); });
it('should reference core using global symbol in umd', () => {
expect(shx.cat('bundles/common.umd.js')).toContain('global.ng.core');
});
it('should have right fesm files', () => {
const expected = [

View File

@ -41,8 +41,9 @@ describe('@angular/core ng_package', () => {
describe('package.json', () => {
const packageJson = 'package.json';
it('should have a package.json file',
() => { expect(shx.grep('"name":', packageJson)).toContain(`@angular/core`); });
it('should have a package.json file', () => {
expect(shx.grep('"name":', packageJson)).toContain(`@angular/core`);
});
it('should contain correct version number with the PLACEHOLDER string replaced', () => {
expect(shx.grep('"version":', packageJson)).toMatch(/\d+\.\d+\.\d+(?!-PLACEHOLDER)/);
@ -66,16 +67,20 @@ describe('@angular/core ng_package', () => {
describe('typescript support', () => {
if (ivyEnabled) {
it('should have an index d.ts file',
() => { expect(shx.cat('core.d.ts')).toContain(`export *`); });
it('should have an index d.ts file', () => {
expect(shx.cat('core.d.ts')).toContain(`export *`);
});
it('should not have amd module names',
() => { expect(shx.cat('public_api.d.ts')).not.toContain('<amd-module name'); });
it('should not have amd module names', () => {
expect(shx.cat('public_api.d.ts')).not.toContain('<amd-module name');
});
} else {
it('should have an index d.ts file',
() => { expect(shx.cat('core.d.ts')).toContain('export declare'); });
it('should have an r3_symbols d.ts file',
() => { expect(shx.cat('src/r3_symbols.d.ts')).toContain('export declare'); });
it('should have an index d.ts file', () => {
expect(shx.cat('core.d.ts')).toContain('export declare');
});
it('should have an r3_symbols d.ts file', () => {
expect(shx.cat('src/r3_symbols.d.ts')).toContain('export declare');
});
}
});
@ -87,15 +92,18 @@ describe('@angular/core ng_package', () => {
obsoleteInIvy('metadata files are no longer needed or produced in Ivy')
.describe('angular metadata', () => {
it('should have metadata.json files',
() => { expect(shx.cat('core.metadata.json')).toContain(`"__symbolic":"module"`); });
it('should not have self-references in metadata.json',
() => { expect(shx.cat('core.metadata.json')).not.toContain(`"from":"./core"`); });
it('should have metadata.json files', () => {
expect(shx.cat('core.metadata.json')).toContain(`"__symbolic":"module"`);
});
it('should not have self-references in metadata.json', () => {
expect(shx.cat('core.metadata.json')).not.toContain(`"from":"./core"`);
});
});
describe('fesm2015', () => {
it('should have a fesm15 file in the /fesm2015 directory',
() => { expect(shx.cat('fesm2015/core.js')).toContain(`export {`); });
it('should have a fesm15 file in the /fesm2015 directory', () => {
expect(shx.cat('fesm2015/core.js')).toContain(`export {`);
});
it('should have a source map', () => {
expect(shx.cat('fesm2015/core.js.map'))
@ -114,8 +122,9 @@ describe('@angular/core ng_package', () => {
});
describe('fesm5', () => {
it('should have a fesm5 file in the /fesm5 directory',
() => { expect(shx.cat('fesm5/core.js')).toContain(`export {`); });
it('should have a fesm5 file in the /fesm5 directory', () => {
expect(shx.cat('fesm5/core.js')).toContain(`export {`);
});
it('should have a source map', () => {
expect(shx.cat('fesm5/core.js.map')).toContain(`{"version":3,"file":"core.js","sources":`);
@ -131,12 +140,14 @@ describe('@angular/core ng_package', () => {
expect(shx.cat('fesm5/core.js')).toContain('.ɵprov = ');
});
} else {
it('should have decorators',
() => { expect(shx.cat('fesm5/core.js')).toContain('__decorate'); });
it('should have decorators', () => {
expect(shx.cat('fesm5/core.js')).toContain('__decorate');
});
// See: https://github.com/angular/angular/pull/32069
it('should retain access to const',
() => { expect(shx.cat('fesm5/core.js')).toContain('!ivyEnabled'); });
it('should retain access to const', () => {
expect(shx.cat('fesm5/core.js')).toContain('!ivyEnabled');
});
}
it('should load tslib from external bundle', () => {
@ -145,8 +156,9 @@ describe('@angular/core ng_package', () => {
});
obsoleteInIvy('we no longer need to export private symbols')
.it('should have been built from the generated bundle index',
() => { expect(shx.cat('fesm5/core.js')).toMatch('export {.*makeParamDecorator'); });
.it('should have been built from the generated bundle index', () => {
expect(shx.cat('fesm5/core.js')).toMatch('export {.*makeParamDecorator');
});
});
describe('esm2015', () => {
@ -160,25 +172,31 @@ describe('@angular/core ng_package', () => {
});
describe('esm5', () => {
it('should not contain any *.ngfactory.js files',
() => { expect(shx.find('esm5').filter(f => f.endsWith('.ngfactory.js'))).toEqual([]); });
it('should not contain any *.ngfactory.js files', () => {
expect(shx.find('esm5').filter(f => f.endsWith('.ngfactory.js'))).toEqual([]);
});
it('should not contain any *.ngsummary.js files',
() => { expect(shx.find('esm5').filter(f => f.endsWith('.ngsummary.js'))).toEqual([]); });
it('should not contain any *.ngsummary.js files', () => {
expect(shx.find('esm5').filter(f => f.endsWith('.ngsummary.js'))).toEqual([]);
});
});
describe('umd', () => {
it('should have a umd file in the /bundles directory',
() => { expect(shx.ls('bundles/core.umd.js').length).toBe(1, 'File not found'); });
it('should have a umd file in the /bundles directory', () => {
expect(shx.ls('bundles/core.umd.js').length).toBe(1, 'File not found');
});
it('should have a source map next to the umd file',
() => { expect(shx.ls('bundles/core.umd.js.map').length).toBe(1, 'File not found'); });
it('should have a source map next to the umd file', () => {
expect(shx.ls('bundles/core.umd.js.map').length).toBe(1, 'File not found');
});
it('should have a minified umd file in the /bundles directory',
() => { expect(shx.ls('bundles/core.umd.min.js').length).toBe(1, 'File not found'); });
it('should have a minified umd file in the /bundles directory', () => {
expect(shx.ls('bundles/core.umd.min.js').length).toBe(1, 'File not found');
});
it('should have a source map next to the minified umd file',
() => { expect(shx.ls('bundles/core.umd.min.js.map').length).toBe(1, 'File not found'); });
it('should have a source map next to the minified umd file', () => {
expect(shx.ls('bundles/core.umd.min.js.map').length).toBe(1, 'File not found');
});
it('should have the version info in the header', () => {
expect(shx.cat('bundles/core.umd.js'))
@ -189,22 +207,25 @@ describe('@angular/core ng_package', () => {
expect(shx.cat('bundles/core.umd.js')).toContain('function __extends');
expect(shx.cat('bundles/core.umd.js')).not.toContain('undefined.__extends');
});
it('should have an AMD name',
() => { expect(shx.cat('bundles/core.umd.js')).toContain('define(\'@angular/core\''); });
it('should define ng global symbols',
() => { expect(shx.cat('bundles/core.umd.js')).toContain('global.ng.core = {}'); });
it('should have an AMD name', () => {
expect(shx.cat('bundles/core.umd.js')).toContain('define(\'@angular/core\'');
});
it('should define ng global symbols', () => {
expect(shx.cat('bundles/core.umd.js')).toContain('global.ng.core = {}');
});
});
});
describe('secondary entry-point', () => {
describe('package.json', () => {
const packageJson = p `testing/package.json`;
const packageJson = p`testing/package.json`;
it('should have a package.json file',
() => { expect(shx.grep('"name":', packageJson)).toContain(`@angular/core/testing`); });
it('should have a package.json file', () => {
expect(shx.grep('"name":', packageJson)).toContain(`@angular/core/testing`);
});
it('should have its module resolution mappings defined in the nested package.json', () => {
const packageJson = p `testing/package.json`;
const packageJson = p`testing/package.json`;
expect(shx.grep('"main":', packageJson)).toContain(`../bundles/core-testing.umd.js`);
expect(shx.grep('"module":', packageJson)).toContain(`../fesm5/testing.js`);
expect(shx.grep('"es2015":', packageJson)).toContain(`../fesm2015/testing.js`);
@ -216,13 +237,15 @@ describe('@angular/core ng_package', () => {
describe('typings', () => {
if (ivyEnabled) {
const typingsFile = p `testing/index.d.ts`;
it('should have a typings file',
() => { expect(shx.cat(typingsFile)).toContain(`export * from './public_api';`); });
const typingsFile = p`testing/index.d.ts`;
it('should have a typings file', () => {
expect(shx.cat(typingsFile)).toContain(`export * from './public_api';`);
});
} else {
const typingsFile = p `testing/testing.d.ts`;
it('should have a typings file',
() => { expect(shx.cat(typingsFile)).toContain('export declare'); });
const typingsFile = p`testing/testing.d.ts`;
it('should have a typings file', () => {
expect(shx.cat(typingsFile)).toContain('export declare');
});
}
obsoleteInIvy(
@ -242,8 +265,9 @@ describe('@angular/core ng_package', () => {
});
describe('fesm2015', () => {
it('should have a fesm15 file in the /fesm2015 directory',
() => { expect(shx.cat('fesm2015/testing.js')).toContain(`export {`); });
it('should have a fesm15 file in the /fesm2015 directory', () => {
expect(shx.cat('fesm2015/testing.js')).toContain(`export {`);
});
it('should have a source map', () => {
expect(shx.cat('fesm2015/testing.js.map'))
@ -257,8 +281,9 @@ describe('@angular/core ng_package', () => {
});
describe('fesm5', () => {
it('should have a fesm5 file in the /fesm5 directory',
() => { expect(shx.cat('fesm5/testing.js')).toContain(`export {`); });
it('should have a fesm5 file in the /fesm5 directory', () => {
expect(shx.cat('fesm5/testing.js')).toContain(`export {`);
});
it('should have a source map', () => {
expect(shx.cat('fesm5/testing.js.map'))
@ -267,8 +292,9 @@ describe('@angular/core ng_package', () => {
});
describe('umd', () => {
it('should have a umd file in the /bundles directory',
() => { expect(shx.ls('bundles/core-testing.umd.js').length).toBe(1, 'File not found'); });
it('should have a umd file in the /bundles directory', () => {
expect(shx.ls('bundles/core-testing.umd.js').length).toBe(1, 'File not found');
});
it('should have a source map next to the umd file', () => {
expect(shx.ls('bundles/core-testing.umd.js.map').length).toBe(1, 'File not found');

View File

@ -11,7 +11,6 @@ import {existsSync, readFileSync} from 'fs';
import {dirname, join} from 'path';
describe('flat_module ng_module', () => {
let packageOutput: string;
let flatModuleOutFile: string;
@ -21,11 +20,11 @@ describe('flat_module ng_module', () => {
flatModuleOutFile = join(packageOutput, 'flat_module.js');
});
it('should have a flat module out file',
() => { expect(existsSync(flatModuleOutFile)).toBe(true); });
it('should have a flat module out file', () => {
expect(existsSync(flatModuleOutFile)).toBe(true);
});
describe('flat module out file', () => {
obsoleteInIvy('Ngtsc computes the AMD module name differently than NGC')
.it('should have a proper AMD module name', () => {
expect(readFileSync(flatModuleOutFile, 'utf8'))

View File

@ -11,7 +11,6 @@ import * as path from 'path';
import {setup} from './test_support';
describe('ngc_wrapped', () => {
it('should work', () => {
const {read, write, runOneBuild, writeConfig, shouldExist, basePath, typesRoots} = setup();

View File

@ -19,7 +19,9 @@ export interface TestSupport {
angularCorePath: string;
typesRoots: string;
writeConfig({
srcTargetPath, depPaths, pathMapping,
srcTargetPath,
depPaths,
pathMapping,
}: {
srcTargetPath: string,
depPaths?: string[],
@ -33,13 +35,13 @@ export interface TestSupport {
runOneBuild(): boolean;
}
export function setup(
{
bazelBin = 'bazel-bin', tsconfig = 'tsconfig.json',
}: {
bazelBin?: string,
tsconfig?: string,
} = {}): TestSupport {
export function setup({
bazelBin = 'bazel-bin',
tsconfig = 'tsconfig.json',
}: {
bazelBin?: string,
tsconfig?: string,
} = {}): TestSupport {
const runfilesPath = process.env['TEST_SRCDIR'];
const basePath = makeTempDir(runfilesPath);
@ -93,12 +95,17 @@ export function setup(
}
function writeFiles(...mockDirs: {[fileName: string]: string}[]) {
mockDirs.forEach(
(dir) => { Object.keys(dir).forEach((fileName) => { write(fileName, dir[fileName]); }); });
mockDirs.forEach((dir) => {
Object.keys(dir).forEach((fileName) => {
write(fileName, dir[fileName]);
});
});
}
function writeConfig({
srcTargetPath, depPaths = [], pathMapping = [],
srcTargetPath,
depPaths = [],
pathMapping = [],
}: {
srcTargetPath: string,
depPaths?: string[],
@ -133,7 +140,8 @@ export function setup(
defaultTsConfig: emptyTsConfig.config,
rootDir: basePath,
target: target,
outDir: bazelBinPath, compilationTargetSrc,
outDir: bazelBinPath,
compilationTargetSrc,
files: files,
pathMapping: pathMappingObj,
});
@ -153,7 +161,9 @@ export function setup(
}
}
function runOneBuildImpl(): boolean { return runOneBuild(['@' + tsConfigJsonPath]); }
function runOneBuildImpl(): boolean {
return runOneBuild(['@' + tsConfigJsonPath]);
}
}
function makeTempDir(baseDir: string): string {

View File

@ -24,7 +24,7 @@ export {JsonFileReporter} from './src/reporter/json_file_reporter';
export {MultiReporter} from './src/reporter/multi_reporter';
export {Runner} from './src/runner';
export {SampleDescription} from './src/sample_description';
export {SampleState, Sampler} from './src/sampler';
export {Sampler, SampleState} from './src/sampler';
export {Validator} from './src/validator';
export {RegressionSlopeValidator} from './src/validator/regression_slope_validator';
export {SizeValidator} from './src/validator/size_validator';

View File

@ -14,18 +14,24 @@ export abstract class Metric {
/**
* Starts measuring
*/
beginMeasure(): Promise<any> { throw new Error('NYI'); }
beginMeasure(): Promise<any> {
throw new Error('NYI');
}
/**
* Ends measuring and reports the data
* since the begin call.
* @param restart: Whether to restart right after this.
*/
endMeasure(restart: boolean): Promise<{[key: string]: any}> { throw new Error('NYI'); }
endMeasure(restart: boolean): Promise<{[key: string]: any}> {
throw new Error('NYI');
}
/**
* Describes the metrics provided by this metric implementation.
* (e.g. units, ...)
*/
describe(): {[key: string]: string} { throw new Error('NYI'); }
describe(): {[key: string]: string} {
throw new Error('NYI');
}
}

View File

@ -26,7 +26,9 @@ export class MultiMetric extends Metric {
];
}
constructor(private _metrics: Metric[]) { super(); }
constructor(private _metrics: Metric[]) {
super();
}
/**
* Starts measuring
@ -56,7 +58,11 @@ export class MultiMetric extends Metric {
function mergeStringMaps(maps: {[key: string]: string}[]): {[key: string]: string} {
const result: {[key: string]: string} = {};
maps.forEach(map => { Object.keys(map).forEach(prop => { result[prop] = map[prop]; }); });
maps.forEach(map => {
Object.keys(map).forEach(prop => {
result[prop] = map[prop];
});
});
return result;
}

View File

@ -23,11 +23,12 @@ export class PerflogMetric extends Metric {
static PROVIDERS = [
{
provide: PerflogMetric,
deps: [
WebDriverExtension, PerflogMetric.SET_TIMEOUT, Options.MICRO_METRICS, Options.FORCE_GC,
Options.CAPTURE_FRAMES, Options.RECEIVED_DATA, Options.REQUEST_COUNT,
PerflogMetric.IGNORE_NAVIGATION
]
deps:
[
WebDriverExtension, PerflogMetric.SET_TIMEOUT, Options.MICRO_METRICS, Options.FORCE_GC,
Options.CAPTURE_FRAMES, Options.RECEIVED_DATA, Options.REQUEST_COUNT,
PerflogMetric.IGNORE_NAVIGATION
]
},
{
provide: PerflogMetric.SET_TIMEOUT,
@ -169,7 +170,9 @@ export class PerflogMetric extends Metric {
return result;
}
let resolve: (result: any) => void;
const promise = new Promise<{[key: string]: number}>(res => { resolve = res; });
const promise = new Promise<{[key: string]: number}>(res => {
resolve = res;
});
this._setTimeout(() => resolve(this._readUntilEndMark(markName, loopCount + 1)), 100);
return promise;
});
@ -188,7 +191,7 @@ export class PerflogMetric extends Metric {
}
startEvent['ph'] = 'B';
endEvent['ph'] = 'E';
endEvent['ts'] = startEvent['ts'] ! + startEvent['dur'] !;
endEvent['ts'] = startEvent['ts']! + startEvent['dur']!;
this._remainingEvents.push(startEvent);
this._remainingEvents.push(endEvent);
} else {
@ -198,7 +201,7 @@ export class PerflogMetric extends Metric {
if (needSort) {
// Need to sort because of the ph==='X' events
this._remainingEvents.sort((a, b) => {
const diff = a['ts'] ! - b['ts'] !;
const diff = a['ts']! - b['ts']!;
return diff > 0 ? 1 : diff < 0 ? -1 : 0;
});
}
@ -230,8 +233,8 @@ export class PerflogMetric extends Metric {
result['requestCount'] = 0;
}
let markStartEvent: PerfLogEvent = null !;
let markEndEvent: PerfLogEvent = null !;
let markStartEvent: PerfLogEvent = null!;
let markEndEvent: PerfLogEvent = null!;
events.forEach((event) => {
const ph = event['ph'];
const name = event['name'];
@ -267,7 +270,7 @@ export class PerflogMetric extends Metric {
let inMeasureRange = false;
events.forEach((event) => {
const ph = event['ph'];
let name = event['name'] !;
let name = event['name']!;
let microIterations = 1;
const microIterationsMatch = name.match(_MICRO_ITERATIONS_REGEX);
if (microIterationsMatch) {
@ -286,7 +289,7 @@ export class PerflogMetric extends Metric {
if (this._requestCount && name === 'sendRequest') {
result['requestCount'] += 1;
} else if (this._receivedData && name === 'receivedData' && ph === 'I') {
result['receivedData'] += event['args'] !['encodedDataLength'] !;
result['receivedData'] += event['args']!['encodedDataLength']!;
}
if (ph === 'B' && name === _MARK_NAME_FRAME_CAPTURE) {
if (frameCaptureStartEvent) {
@ -305,7 +308,7 @@ export class PerflogMetric extends Metric {
}
if (ph === 'I' && frameCaptureStartEvent && !frameCaptureEndEvent && name === 'frame') {
frameTimestamps.push(event['ts'] !);
frameTimestamps.push(event['ts']!);
if (frameTimestamps.length >= 2) {
frameTimes.push(
frameTimestamps[frameTimestamps.length - 1] -
@ -324,14 +327,14 @@ export class PerflogMetric extends Metric {
intervalStartCount[name]--;
if (intervalStartCount[name] === 0) {
const startEvent = intervalStarts[name];
const duration = (event['ts'] ! - startEvent['ts'] !);
intervalStarts[name] = null !;
const duration = (event['ts']! - startEvent['ts']!);
intervalStarts[name] = null!;
if (name === 'gc') {
result['gcTime'] += duration;
const amount =
(startEvent['args'] !['usedHeapSize'] ! - event['args'] !['usedHeapSize'] !) / 1000;
(startEvent['args']!['usedHeapSize']! - event['args']!['usedHeapSize']!) / 1000;
result['gcAmount'] += amount;
const majorGc = event['args'] !['majorGc'];
const majorGc = event['args']!['majorGc'];
if (majorGc && majorGc) {
result['majorGcTime'] += duration;
}
@ -374,7 +377,9 @@ export class PerflogMetric extends Metric {
frameTimes.filter(t => t < _FRAME_TIME_SMOOTH_THRESHOLD).length / frameTimes.length;
}
private _markName(index: number) { return `${_MARK_NAME_PREFIX}${index}`; }
private _markName(index: number) {
return `${_MARK_NAME_PREFIX}${index}`;
}
}
const _MICRO_ITERATIONS_REGEX = /(.+)\*(\d+)$/;

View File

@ -26,7 +26,9 @@ export class UserMetric extends Metric {
/**
* Starts measuring
*/
beginMeasure(): Promise<any> { return Promise.resolve(true); }
beginMeasure(): Promise<any> {
return Promise.resolve(true);
}
/**
* Ends measuring.
@ -34,8 +36,7 @@ export class UserMetric extends Metric {
endMeasure(restart: boolean): Promise<{[key: string]: any}> {
let resolve: (result: any) => void;
let reject: (error: any) => void;
const promise = new Promise < { [key: string]: any; }
> ((res, rej) => {
const promise = new Promise<{[key: string]: any;}>((res, rej) => {
resolve = res;
reject = rej;
});
@ -67,5 +68,7 @@ export class UserMetric extends Metric {
* Describes the metrics provided by this metric implementation.
* (e.g. units, ...)
*/
describe(): {[key: string]: any} { return this._userMetrics; }
describe(): {[key: string]: any} {
return this._userMetrics;
}
}

View File

@ -12,7 +12,9 @@ import {MeasureValues} from './measure_values';
* A reporter reports measure values and the valid sample.
*/
export abstract class Reporter {
reportMeasureValues(values: MeasureValues): Promise<any> { throw new Error('NYI'); }
reportMeasureValues(values: MeasureValues): Promise<any> {
throw new Error('NYI');
}
reportSample(completeSample: MeasureValues[], validSample: MeasureValues[]): Promise<any> {
throw new Error('NYI');

View File

@ -28,10 +28,11 @@ export class ConsoleReporter extends Reporter {
},
{provide: ConsoleReporter.COLUMN_WIDTH, useValue: 18}, {
provide: ConsoleReporter.PRINT,
useValue: function(v: any) {
// tslint:disable-next-line:no-console
console.log(v);
}
useValue:
function(v: any) {
// tslint:disable-next-line:no-console
console.log(v);
}
}
];
@ -58,7 +59,9 @@ export class ConsoleReporter extends Reporter {
this._print(`BENCHMARK ${sampleDescription.id}`);
this._print('Description:');
const props = sortedProps(sampleDescription.description);
props.forEach((prop) => { this._print(`- ${prop}: ${sampleDescription.description[prop]}`); });
props.forEach((prop) => {
this._print(`- ${prop}: ${sampleDescription.description[prop]}`);
});
this._print('Metrics:');
this._metricNames.forEach((metricName) => {
this._print(`- ${metricName}: ${sampleDescription.metrics[metricName]}`);

View File

@ -37,7 +37,9 @@ export class JsonFileReporter extends Reporter {
super();
}
reportMeasureValues(measureValues: MeasureValues): Promise<any> { return Promise.resolve(null); }
reportMeasureValues(measureValues: MeasureValues): Promise<any> {
return Promise.resolve(null);
}
reportSample(completeSample: MeasureValues[], validSample: MeasureValues[]): Promise<any> {
const stats: {[key: string]: string} = {};

View File

@ -27,7 +27,9 @@ export class MultiReporter extends Reporter {
];
}
constructor(private _reporters: Reporter[]) { super(); }
constructor(private _reporters: Reporter[]) {
super();
}
reportMeasureValues(values: MeasureValues): Promise<any[]> {
return Promise.all(this._reporters.map(reporter => reporter.reportMeasureValues(values)));

View File

@ -17,7 +17,7 @@ import {Reporter} from './reporter';
import {ConsoleReporter} from './reporter/console_reporter';
import {MultiReporter} from './reporter/multi_reporter';
import {SampleDescription} from './sample_description';
import {SampleState, Sampler} from './sampler';
import {Sampler, SampleState} from './sampler';
import {Validator} from './validator';
import {RegressionSlopeValidator} from './validator/regression_slope_validator';
import {SizeValidator} from './validator/size_validator';

View File

@ -29,10 +29,11 @@ export class SampleDescription {
userDesc
],
metric.describe()),
deps: [
Metric, Options.SAMPLE_ID, Options.FORCE_GC, Options.USER_AGENT, Validator,
Options.DEFAULT_DESCRIPTION, Options.SAMPLE_DESCRIPTION
]
deps:
[
Metric, Options.SAMPLE_ID, Options.FORCE_GC, Options.USER_AGENT, Validator,
Options.DEFAULT_DESCRIPTION, Options.SAMPLE_DESCRIPTION
]
}];
description: {[key: string]: any};
@ -41,9 +42,13 @@ export class SampleDescription {
public metrics: {[key: string]: any}) {
this.description = {};
descriptions.forEach(description => {
Object.keys(description).forEach(prop => { this.description[prop] = description[prop]; });
Object.keys(description).forEach(prop => {
this.description[prop] = description[prop];
});
});
}
toJson() { return {'id': this.id, 'description': this.description, 'metrics': this.metrics}; }
toJson() {
return {'id': this.id, 'description': this.description, 'metrics': this.metrics};
}
}

View File

@ -28,9 +28,11 @@ import {WebDriverAdapter} from './web_driver_adapter';
export class Sampler {
static PROVIDERS = <StaticProvider[]>[{
provide: Sampler,
deps: [
WebDriverAdapter, Metric, Reporter, Validator, Options.PREPARE, Options.EXECUTE, Options.NOW
]
deps:
[
WebDriverAdapter, Metric, Reporter, Validator, Options.PREPARE, Options.EXECUTE,
Options.NOW
]
}];
constructor(
private _driver: WebDriverAdapter, private _metric: Metric, private _reporter: Reporter,

View File

@ -17,11 +17,15 @@ export abstract class Validator {
/**
* Calculates a valid sample out of the complete sample
*/
validate(completeSample: MeasureValues[]): MeasureValues[]|null { throw new Error('NYI'); }
validate(completeSample: MeasureValues[]): MeasureValues[]|null {
throw new Error('NYI');
}
/**
* Returns a Map that describes the properties of the validator
* (e.g. sample size, ...)
*/
describe(): {[key: string]: any} { throw new Error('NYI'); }
describe(): {[key: string]: any} {
throw new Error('NYI');
}
}

View File

@ -22,9 +22,13 @@ export class SizeValidator extends Validator {
{provide: SizeValidator.SAMPLE_SIZE, useValue: 10}
];
constructor(@Inject(SizeValidator.SAMPLE_SIZE) private _sampleSize: number) { super(); }
constructor(@Inject(SizeValidator.SAMPLE_SIZE) private _sampleSize: number) {
super();
}
describe(): {[key: string]: any} { return {'sampleSize': this._sampleSize}; }
describe(): {[key: string]: any} {
return {'sampleSize': this._sampleSize};
}
validate(completeSample: MeasureValues[]): MeasureValues[]|null {
if (completeSample.length >= this._sampleSize) {

View File

@ -14,9 +14,19 @@
* Needs one implementation for every supported WebDriver client.
*/
export abstract class WebDriverAdapter {
waitFor(callback: Function): Promise<any> { throw new Error('NYI'); }
executeScript(script: string): Promise<any> { throw new Error('NYI'); }
executeAsyncScript(script: string): Promise<any> { throw new Error('NYI'); }
capabilities(): Promise<{[key: string]: any}> { throw new Error('NYI'); }
logs(type: string): Promise<any[]> { throw new Error('NYI'); }
waitFor(callback: Function): Promise<any> {
throw new Error('NYI');
}
executeScript(script: string): Promise<any> {
throw new Error('NYI');
}
executeAsyncScript(script: string): Promise<any> {
throw new Error('NYI');
}
capabilities(): Promise<{[key: string]: any}> {
throw new Error('NYI');
}
logs(type: string): Promise<any[]> {
throw new Error('NYI');
}
}

View File

@ -12,7 +12,7 @@ import {Options} from './common_options';
export type PerfLogEvent = {
[key: string]: any
} & {
}&{
ph?: 'X' | 'B' | 'E' | 'I',
ts?: number,
dur?: number,
@ -43,7 +43,7 @@ export abstract class WebDriverExtension {
{
provide: WebDriverExtension,
useFactory: (children: WebDriverExtension[], capabilities: {[key: string]: any}) => {
let delegate: WebDriverExtension = undefined !;
let delegate: WebDriverExtension = undefined!;
children.forEach(extension => {
if (extension.supports(capabilities)) {
delegate = extension;
@ -60,11 +60,17 @@ export abstract class WebDriverExtension {
return res;
}
gc(): Promise<any> { throw new Error('NYI'); }
gc(): Promise<any> {
throw new Error('NYI');
}
timeBegin(name: string): Promise<any> { throw new Error('NYI'); }
timeBegin(name: string): Promise<any> {
throw new Error('NYI');
}
timeEnd(name: string, restartName: string|null): Promise<any> { throw new Error('NYI'); }
timeEnd(name: string, restartName: string|null): Promise<any> {
throw new Error('NYI');
}
/**
* Format:
@ -78,11 +84,17 @@ export abstract class WebDriverExtension {
* Based on [Chrome Trace Event
*Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit)
**/
readPerfLog(): Promise<PerfLogEvent[]> { throw new Error('NYI'); }
readPerfLog(): Promise<PerfLogEvent[]> {
throw new Error('NYI');
}
perfLogFeatures(): PerfLogFeatures { throw new Error('NYI'); }
perfLogFeatures(): PerfLogFeatures {
throw new Error('NYI');
}
supports(capabilities: {[key: string]: any}): boolean { return true; }
supports(capabilities: {[key: string]: any}): boolean {
return true;
}
}
export class PerfLogFeatures {

View File

@ -54,7 +54,9 @@ export class ChromeDriverExtension extends WebDriverExtension {
return parseInt(v, 10);
}
gc() { return this.driver.executeScript('window.gc()'); }
gc() {
return this.driver.executeScript('window.gc()');
}
async timeBegin(name: string): Promise<any> {
if (this._firstRun) {
@ -108,7 +110,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
chromeEvents.forEach((event) => {
const categories = this._parseCategories(event['cat']);
const normalizedEvent = this._convertEvent(event, categories);
if (normalizedEvent != null) normalizedEvents !.push(normalizedEvent);
if (normalizedEvent != null) normalizedEvents!.push(normalizedEvent);
});
return normalizedEvents;
}
@ -184,7 +186,9 @@ export class ChromeDriverExtension extends WebDriverExtension {
return null; // nothing useful in this event
}
private _parseCategories(categories: string): string[] { return categories.split(','); }
private _parseCategories(categories: string): string[] {
return categories.split(',');
}
private _isEvent(
eventCategories: string[], eventName: string, expectedCategories: string[],

View File

@ -22,7 +22,9 @@ export class FirefoxDriverExtension extends WebDriverExtension {
this._profilerStarted = false;
}
gc() { return this._driver.executeScript('window.forceGC()'); }
gc() {
return this._driver.executeScript('window.forceGC()');
}
timeBegin(name: string): Promise<any> {
if (!this._profilerStarted) {
@ -44,7 +46,9 @@ export class FirefoxDriverExtension extends WebDriverExtension {
return this._driver.executeAsyncScript('var cb = arguments[0]; window.getProfile(cb);');
}
perfLogFeatures(): PerfLogFeatures { return new PerfLogFeatures({render: true, gc: true}); }
perfLogFeatures(): PerfLogFeatures {
return new PerfLogFeatures({render: true, gc: true});
}
supports(capabilities: {[key: string]: any}): boolean {
return capabilities['browserName'].toLowerCase() === 'firefox';

View File

@ -15,9 +15,13 @@ import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_e
export class IOsDriverExtension extends WebDriverExtension {
static PROVIDERS = [{provide: IOsDriverExtension, deps: [WebDriverAdapter]}];
constructor(private _driver: WebDriverAdapter) { super(); }
constructor(private _driver: WebDriverAdapter) {
super();
}
gc(): Promise<any> { throw new Error('Force GC is not supported on iOS'); }
gc(): Promise<any> {
throw new Error('Force GC is not supported on iOS');
}
timeBegin(name: string): Promise<any> {
return this._driver.executeScript(`console.time('${name}');`);
@ -62,16 +66,16 @@ export class IOsDriverExtension extends WebDriverExtension {
const endTime = record['endTime'];
if (type === 'FunctionCall' && (data == null || data['scriptName'] !== 'InjectedScript')) {
events !.push(createStartEvent('script', startTime));
events!.push(createStartEvent('script', startTime));
endEvent = createEndEvent('script', endTime);
} else if (type === 'Time') {
events !.push(createMarkStartEvent(data['message'], startTime));
events!.push(createMarkStartEvent(data['message'], startTime));
} else if (type === 'TimeEnd') {
events !.push(createMarkEndEvent(data['message'], startTime));
events!.push(createMarkEndEvent(data['message'], startTime));
} else if (
type === 'RecalculateStyles' || type === 'Layout' || type === 'UpdateLayerTree' ||
type === 'Paint' || type === 'Rasterize' || type === 'CompositeLayers') {
events !.push(createStartEvent('render', startTime));
events!.push(createStartEvent('render', startTime));
endEvent = createEndEvent('render', endTime);
}
// Note: ios used to support GCEvent up until iOS 6 :-(
@ -79,21 +83,22 @@ export class IOsDriverExtension extends WebDriverExtension {
this._convertPerfRecordsToEvents(record['children'], events);
}
if (endEvent != null) {
events !.push(endEvent);
events!.push(endEvent);
}
});
return events;
}
perfLogFeatures(): PerfLogFeatures { return new PerfLogFeatures({render: true}); }
perfLogFeatures(): PerfLogFeatures {
return new PerfLogFeatures({render: true});
}
supports(capabilities: {[key: string]: any}): boolean {
return capabilities['browserName'].toLowerCase() === 'safari';
}
}
function createEvent(
ph: 'X' | 'B' | 'E' | 'B' | 'E', name: string, time: number, args: any = null) {
function createEvent(ph: 'X'|'B'|'E'|'B'|'E', name: string, time: number, args: any = null) {
const result: PerfLogEvent = {
'cat': 'timeline',
'name': name,

View File

@ -21,11 +21,17 @@ export class SeleniumWebDriverAdapter extends WebDriverAdapter {
deps: []
}];
constructor(private _driver: any) { super(); }
constructor(private _driver: any) {
super();
}
waitFor(callback: () => any): Promise<any> { return this._driver.call(callback); }
waitFor(callback: () => any): Promise<any> {
return this._driver.call(callback);
}
executeScript(script: string): Promise<any> { return this._driver.executeScript(script); }
executeScript(script: string): Promise<any> {
return this._driver.executeScript(script);
}
executeAsyncScript(script: string): Promise<any> {
return this._driver.executeAsyncScript(script);
@ -58,7 +64,9 @@ class Command {
private parameters_: {[key: string]: any} = {};
constructor(private name_: string) {}
getName() { return this.name_; }
getName() {
return this.name_;
}
setParameter(name: string, value: any) {
this.parameters_[name] = value;
@ -70,7 +78,11 @@ class Command {
return this;
}
getParameter(key: string) { return this.parameters_[key]; }
getParameter(key: string) {
return this.parameters_[key];
}
getParameters() { return this.parameters_; }
getParameters() {
return this.parameters_;
}
}

View File

@ -11,50 +11,52 @@ import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/te
import {Injector, Metric, MultiMetric} from '../../index';
(function() {
function createMetric(ids: any[]) {
const m = Injector
.create([
ids.map(id => ({provide: id, useValue: new MockMetric(id)})),
MultiMetric.provideWith(ids)
])
.get<MultiMetric>(MultiMetric);
return Promise.resolve(m);
}
function createMetric(ids: any[]) {
const m = Injector
.create([
ids.map(id => ({provide: id, useValue: new MockMetric(id)})),
MultiMetric.provideWith(ids)
])
.get<MultiMetric>(MultiMetric);
return Promise.resolve(m);
}
describe('multi metric', () => {
it('should merge descriptions', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createMetric(['m1', 'm2']).then((m) => {
expect(m.describe()).toEqual({'m1': 'describe', 'm2': 'describe'});
async.done();
});
}));
describe('multi metric', () => {
it('should merge descriptions', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createMetric(['m1', 'm2']).then((m) => {
expect(m.describe()).toEqual({'m1': 'describe', 'm2': 'describe'});
async.done();
});
}));
it('should merge all beginMeasure calls',
it('should merge all beginMeasure calls',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createMetric(['m1', 'm2']).then((m) => m.beginMeasure()).then((values) => {
expect(values).toEqual(['m1_beginMeasure', 'm2_beginMeasure']);
async.done();
});
}));
[false, true].forEach((restartFlag) => {
it(`should merge all endMeasure calls for restart=${restartFlag}`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createMetric(['m1', 'm2']).then((m) => m.beginMeasure()).then((values) => {
expect(values).toEqual(['m1_beginMeasure', 'm2_beginMeasure']);
createMetric(['m1', 'm2']).then((m) => m.endMeasure(restartFlag)).then((values) => {
expect(values).toEqual({'m1': {'restart': restartFlag}, 'm2': {'restart': restartFlag}});
async.done();
});
}));
[false, true].forEach((restartFlag) => {
it(`should merge all endMeasure calls for restart=${restartFlag}`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createMetric(['m1', 'm2']).then((m) => m.endMeasure(restartFlag)).then((values) => {
expect(values).toEqual(
{'m1': {'restart': restartFlag}, 'm2': {'restart': restartFlag}});
async.done();
});
}));
});
});
});
})();
class MockMetric extends Metric {
constructor(private _id: string) { super(); }
constructor(private _id: string) {
super();
}
beginMeasure(): Promise<string> { return Promise.resolve(`${this._id}_beginMeasure`); }
beginMeasure(): Promise<string> {
return Promise.resolve(`${this._id}_beginMeasure`);
}
endMeasure(restart: boolean): Promise<{[key: string]: any}> {
const result: {[key: string]: any} = {};

File diff suppressed because it is too large Load Diff

View File

@ -12,55 +12,55 @@ import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/te
import {Options, PerfLogEvent, PerfLogFeatures, UserMetric, WebDriverAdapter} from '../../index';
(function() {
let wdAdapter: MockDriverAdapter;
let wdAdapter: MockDriverAdapter;
function createMetric(
perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
{userMetrics}: {userMetrics?: {[key: string]: string}} = {}): UserMetric {
if (!perfLogFeatures) {
perfLogFeatures =
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
}
if (!userMetrics) {
userMetrics = {};
}
wdAdapter = new MockDriverAdapter();
const providers: StaticProvider[] = [
Options.DEFAULT_PROVIDERS, UserMetric.PROVIDERS,
{provide: Options.USER_METRICS, useValue: userMetrics},
{provide: WebDriverAdapter, useValue: wdAdapter}
];
return Injector.create(providers).get(UserMetric);
function createMetric(
perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
{userMetrics}: {userMetrics?: {[key: string]: string}} = {}): UserMetric {
if (!perfLogFeatures) {
perfLogFeatures =
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
}
if (!userMetrics) {
userMetrics = {};
}
wdAdapter = new MockDriverAdapter();
const providers: StaticProvider[] = [
Options.DEFAULT_PROVIDERS, UserMetric.PROVIDERS,
{provide: Options.USER_METRICS, useValue: userMetrics},
{provide: WebDriverAdapter, useValue: wdAdapter}
];
return Injector.create(providers).get(UserMetric);
}
describe('user metric', () => {
it('should describe itself based on userMetrics', () => {
expect(createMetric([[]], new PerfLogFeatures(), {
userMetrics: {'loadTime': 'time to load'}
}).describe())
.toEqual({'loadTime': 'time to load'});
});
describe('endMeasure', () => {
it('should stop measuring when all properties have numeric values',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const metric = createMetric(
[[]], new PerfLogFeatures(),
{userMetrics: {'loadTime': 'time to load', 'content': 'time to see content'}});
metric.beginMeasure().then(() => metric.endMeasure(true)).then(values => {
expect(values['loadTime']).toBe(25);
expect(values['content']).toBe(250);
async.done();
});
wdAdapter.data['loadTime'] = 25;
// Wait before setting 2nd property.
setTimeout(() => { wdAdapter.data['content'] = 250; }, 50);
}), 600);
});
describe('user metric', () => {
it('should describe itself based on userMetrics', () => {
expect(createMetric([[]], new PerfLogFeatures(), {
userMetrics: {'loadTime': 'time to load'}
}).describe())
.toEqual({'loadTime': 'time to load'});
});
describe('endMeasure', () => {
it('should stop measuring when all properties have numeric values',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const metric = createMetric(
[[]], new PerfLogFeatures(),
{userMetrics: {'loadTime': 'time to load', 'content': 'time to see content'}});
metric.beginMeasure().then(() => metric.endMeasure(true)).then(values => {
expect(values['loadTime']).toBe(25);
expect(values['content']).toBe(250);
async.done();
});
wdAdapter.data['loadTime'] = 25;
// Wait before setting 2nd property.
setTimeout(() => {
wdAdapter.data['content'] = 250;
}, 50);
}), 600);
});
});
})();
class MockDriverAdapter extends WebDriverAdapter {

View File

@ -18,10 +18,10 @@ import {ConsoleReporter, Injector, MeasureValues, SampleDescription} from '../..
function createReporter(
{columnWidth = null, sampleId = null, descriptions = null, metrics = null}: {
columnWidth?: number | null,
sampleId?: string | null,
descriptions?: {[key: string]: any}[] | null,
metrics?: {[key: string]: any} | null
columnWidth?: number|null,
sampleId?: string|null,
descriptions?: {[key: string]: any}[]|null,
metrics?: {[key: string]: any}|null
}) {
log = [];
if (!descriptions) {
@ -33,7 +33,7 @@ import {ConsoleReporter, Injector, MeasureValues, SampleDescription} from '../..
const providers: StaticProvider[] = [
ConsoleReporter.PROVIDERS, {
provide: SampleDescription,
useValue: new SampleDescription(sampleId, descriptions, metrics !)
useValue: new SampleDescription(sampleId, descriptions, metrics!)
},
{provide: ConsoleReporter.PRINT, useValue: (line: string) => log.push(line)}
];
@ -84,7 +84,6 @@ import {ConsoleReporter, Injector, MeasureValues, SampleDescription} from '../..
reporter.reportSample([], [mv(0, 0, {'a': 3, 'b': 0}), mv(1, 1, {'a': 5, 'b': 0})]);
expect(log).toEqual(['======== | ========', '4.00+-25% | 0.00']);
});
});
}

View File

@ -62,16 +62,12 @@ import {Injector, JsonFileReporter, MeasureValues, Options, SampleDescription} f
{'timeStamp': '1970-01-01T00:00:00.000Z', 'runIndex': 0, 'values': {'a': 3, 'b': 6}}
],
'validSample': [
{'timeStamp': '1970-01-01T00:00:00.000Z', 'runIndex': 0, 'values': {'a': 3, 'b': 6}}, {
'timeStamp': '1970-01-01T00:00:00.001Z',
'runIndex': 1,
'values': {'a': 5, 'b': 9}
}
{'timeStamp': '1970-01-01T00:00:00.000Z', 'runIndex': 0, 'values': {'a': 3, 'b': 6}},
{'timeStamp': '1970-01-01T00:00:00.001Z', 'runIndex': 1, 'values': {'a': 5, 'b': 9}}
]
});
async.done();
}));
});
}

View File

@ -11,50 +11,48 @@ import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/te
import {Injector, MeasureValues, MultiReporter, Reporter} from '../../index';
(function() {
function createReporters(ids: any[]) {
const r = Injector
.create([
ids.map(id => ({provide: id, useValue: new MockReporter(id)})),
MultiReporter.provideWith(ids)
])
.get<MultiReporter>(MultiReporter);
return Promise.resolve(r);
}
function createReporters(ids: any[]) {
const r = Injector
.create([
ids.map(id => ({provide: id, useValue: new MockReporter(id)})),
MultiReporter.provideWith(ids)
])
.get<MultiReporter>(MultiReporter);
return Promise.resolve(r);
}
describe('multi reporter', () => {
describe('multi reporter', () => {
it('should reportMeasureValues to all',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const mv = new MeasureValues(0, new Date(), {});
createReporters(['m1', 'm2']).then((r) => r.reportMeasureValues(mv)).then((values) => {
expect(values).toEqual([{'id': 'm1', 'values': mv}, {'id': 'm2', 'values': mv}]);
async.done();
});
}));
it('should reportMeasureValues to all',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const mv = new MeasureValues(0, new Date(), {});
createReporters(['m1', 'm2']).then((r) => r.reportMeasureValues(mv)).then((values) => {
it('should reportSample to call', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const completeSample =
[new MeasureValues(0, new Date(), {}), new MeasureValues(1, new Date(), {})];
const validSample = [completeSample[1]];
expect(values).toEqual([{'id': 'm1', 'values': mv}, {'id': 'm2', 'values': mv}]);
async.done();
});
}));
it('should reportSample to call', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const completeSample =
[new MeasureValues(0, new Date(), {}), new MeasureValues(1, new Date(), {})];
const validSample = [completeSample[1]];
createReporters(['m1', 'm2'])
.then((r) => r.reportSample(completeSample, validSample))
.then((values) => {
expect(values).toEqual([
{'id': 'm1', 'completeSample': completeSample, 'validSample': validSample},
{'id': 'm2', 'completeSample': completeSample, 'validSample': validSample}
]);
async.done();
});
}));
});
createReporters(['m1', 'm2'])
.then((r) => r.reportSample(completeSample, validSample))
.then((values) => {
expect(values).toEqual([
{'id': 'm1', 'completeSample': completeSample, 'validSample': validSample},
{'id': 'm2', 'completeSample': completeSample, 'validSample': validSample}
]);
async.done();
});
}));
});
})();
class MockReporter extends Reporter {
constructor(private _id: string) { super(); }
constructor(private _id: string) {
super();
}
reportMeasureValues(values: MeasureValues): Promise<{[key: string]: any}> {
return Promise.resolve({'id': this._id, 'values': values});

View File

@ -8,7 +8,7 @@
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/src/testing_internal';
import {Injector, Metric, Options, Runner, SampleDescription, SampleState, Sampler, Validator, WebDriverAdapter} from '../index';
import {Injector, Metric, Options, Runner, SampleDescription, Sampler, SampleState, Validator, WebDriverAdapter} from '../index';
{
describe('runner', () => {
@ -68,7 +68,6 @@ import {Injector, Metric, Options, Runner, SampleDescription, SampleState, Sampl
.sample({id: 'someId'})
.then((_) => injector.get(SampleDescription))
.then((desc) => {
expect(desc.metrics).toEqual({'m1': 'some metric'});
async.done();
});
@ -109,32 +108,45 @@ import {Injector, Metric, Options, Runner, SampleDescription, SampleState, Sampl
})
.then((_) => injector.get(SampleDescription))
.then((desc) => {
expect(desc.description['a']).toBe(2);
async.done();
});
}));
});
}
class MockWebDriverAdapter extends WebDriverAdapter {
executeScript(script: string): Promise<string> { return Promise.resolve('someUserAgent'); }
capabilities(): Promise<Map<string, any>> { return null !; }
executeScript(script: string): Promise<string> {
return Promise.resolve('someUserAgent');
}
capabilities(): Promise<Map<string, any>> {
return null!;
}
}
class MockValidator extends Validator {
constructor() { super(); }
describe() { return {'v': 11}; }
constructor() {
super();
}
describe() {
return {'v': 11};
}
}
class MockMetric extends Metric {
constructor() { super(); }
describe() { return {'m1': 'some metric'}; }
constructor() {
super();
}
describe() {
return {'m1': 'some metric'};
}
}
class MockSampler extends Sampler {
constructor() { super(null !, null !, null !, null !, null !, null !, null !); }
sample(): Promise<SampleState> { return Promise.resolve(new SampleState([], [])); }
constructor() {
super(null!, null!, null!, null!, null!, null!, null!);
}
sample(): Promise<SampleState> {
return Promise.resolve(new SampleState([], []));
}
}

View File

@ -67,7 +67,6 @@ import {Injector, MeasureValues, Metric, Options, Reporter, Sampler, Validator,
expect(log).toEqual([0, 1, 2, 3]);
async.done();
});
}));
it('should call prepare, beginMeasure, execute, endMeasure for every iteration',
@ -77,8 +76,12 @@ import {Injector, MeasureValues, Metric, Options, Reporter, Sampler, Validator,
createSampler({
metric: createCountingMetric(log),
validator: createCountingValidator(2),
prepare: () => { log.push(`p${workCount++}`); },
execute: () => { log.push(`w${workCount++}`); }
prepare: () => {
log.push(`p${workCount++}`);
},
execute: () => {
log.push(`w${workCount++}`);
}
});
sampler.sample().then((_) => {
expect(log).toEqual([
@ -102,7 +105,9 @@ import {Injector, MeasureValues, Metric, Options, Reporter, Sampler, Validator,
createSampler({
metric: createCountingMetric(log),
validator: createCountingValidator(2),
execute: () => { log.push(`w${workCount++}`); },
execute: () => {
log.push(`w${workCount++}`);
},
prepare: null
});
sampler.sample().then((_) => {
@ -130,7 +135,9 @@ import {Injector, MeasureValues, Metric, Options, Reporter, Sampler, Validator,
scriptTime = 0;
return result;
}),
prepare: () => { scriptTime = 1 * iterationCount; },
prepare: () => {
scriptTime = 1 * iterationCount;
},
execute: () => {
scriptTime = 10 * iterationCount;
iterationCount++;
@ -147,7 +154,7 @@ import {Injector, MeasureValues, Metric, Options, Reporter, Sampler, Validator,
it('should call the validator for every execution and store the valid sample',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const log: any[] = [];
const validSample = [mv(null !, null !, {})];
const validSample = [mv(null!, null!, {})];
createSampler({
metric: createCountingMetric(),
@ -174,7 +181,7 @@ import {Injector, MeasureValues, Metric, Options, Reporter, Sampler, Validator,
it('should report the metric values',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const log: any[] = [];
const validSample = [mv(null !, null !, {})];
const validSample = [mv(null!, null!, {})];
createSampler({
validator: createCountingValidator(2, validSample),
metric: createCountingMetric(),
@ -198,7 +205,6 @@ import {Injector, MeasureValues, Metric, Options, Reporter, Sampler, Validator,
async.done();
});
}));
});
}
@ -223,7 +229,9 @@ function createCountingMetric(log: any[] = []) {
}
class MockDriverAdapter extends WebDriverAdapter {
constructor(private _log: any[] = [], private _waitFor: Function|null = null) { super(); }
constructor(private _log: any[] = [], private _waitFor: Function|null = null) {
super();
}
waitFor(callback: Function): Promise<any> {
if (this._waitFor != null) {
return this._waitFor(callback);
@ -235,7 +243,9 @@ class MockDriverAdapter extends WebDriverAdapter {
class MockValidator extends Validator {
constructor(private _log: any[] = [], private _validate: Function|null = null) { super(); }
constructor(private _log: any[] = [], private _validate: Function|null = null) {
super();
}
validate(completeSample: MeasureValues[]): MeasureValues[] {
const stableSample = this._validate != null ? this._validate(completeSample) : completeSample;
this._log.push(['validate', completeSample, stableSample]);
@ -244,7 +254,9 @@ class MockValidator extends Validator {
}
class MockMetric extends Metric {
constructor(private _log: any[] = [], private _endMeasure: Function|null = null) { super(); }
constructor(private _log: any[] = [], private _endMeasure: Function|null = null) {
super();
}
beginMeasure() {
this._log.push(['beginMeasure']);
return Promise.resolve(null);
@ -257,7 +269,9 @@ class MockMetric extends Metric {
}
class MockReporter extends Reporter {
constructor(private _log: any[] = []) { super(); }
constructor(private _log: any[] = []) {
super();
}
reportMeasureValues(values: MeasureValues): Promise<any> {
this._log.push(['reportMeasureValues', values]);
return Promise.resolve(null);

View File

@ -11,7 +11,6 @@ import {Statistic} from '../src/statistic';
{
describe('statistic', () => {
it('should calculate the mean', () => {
expect(Statistic.calculateMean([])).toBeNaN();
expect(Statistic.calculateMean([1, 2, 3])).toBe(2.0);
@ -34,6 +33,5 @@ import {Statistic} from '../src/statistic';
expect(Statistic.calculateRegressionSlope([1], 1, [2], 2)).toBeNaN();
expect(Statistic.calculateRegressionSlope([1, 2], 1.5, [2, 4], 3)).toBe(2.0);
});
});
}

View File

@ -20,13 +20,21 @@ export class TraceEventFactory {
return res;
}
markStart(name: string, time: number) { return this.create('B', name, time); }
markStart(name: string, time: number) {
return this.create('B', name, time);
}
markEnd(name: string, time: number) { return this.create('E', name, time); }
markEnd(name: string, time: number) {
return this.create('E', name, time);
}
start(name: string, time: number, args: any = null) { return this.create('B', name, time, args); }
start(name: string, time: number, args: any = null) {
return this.create('B', name, time, args);
}
end(name: string, time: number, args: any = null) { return this.create('E', name, time, args); }
end(name: string, time: number, args: any = null) {
return this.create('E', name, time, args);
}
instant(name: string, time: number, args: any = null) {
return this.create('I', name, time, args);

View File

@ -53,7 +53,6 @@ import {Injector, MeasureValues, RegressionSlopeValidator} from '../../index';
expect(validator.validate(sample.slice(0, 2))).toEqual(sample.slice(0, 2));
expect(validator.validate(sample)).toEqual(sample.slice(1, 3));
});
});
}

View File

@ -39,7 +39,6 @@ import {Injector, MeasureValues, SizeValidator} from '../../index';
expect(validator.validate(sample.slice(0, 2))).toEqual(sample.slice(0, 2));
expect(validator.validate(sample)).toEqual(sample.slice(1, 3));
});
});
}

View File

@ -11,44 +11,45 @@ import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/te
import {Injector, Options, WebDriverExtension} from '../index';
(function() {
function createExtension(ids: any[], caps: any) {
return new Promise<any>((res, rej) => {
try {
res(Injector
.create([
ids.map((id) => ({provide: id, useValue: new MockExtension(id)})),
{provide: Options.CAPABILITIES, useValue: caps},
WebDriverExtension.provideFirstSupported(ids)
])
.get(WebDriverExtension));
} catch (e) {
rej(e);
}
});
}
describe('WebDriverExtension.provideFirstSupported', () => {
it('should provide the extension that matches the capabilities',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(['m1', 'm2', 'm3'], {'browser': 'm2'}).then((m) => {
expect(m.id).toEqual('m2');
async.done();
});
}));
it('should throw if there is no match',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(['m1'], {'browser': 'm2'}).catch((err) => {
expect(err != null).toBe(true);
async.done();
});
}));
function createExtension(ids: any[], caps: any) {
return new Promise<any>((res, rej) => {
try {
res(Injector
.create([
ids.map((id) => ({provide: id, useValue: new MockExtension(id)})),
{provide: Options.CAPABILITIES, useValue: caps},
WebDriverExtension.provideFirstSupported(ids)
])
.get(WebDriverExtension));
} catch (e) {
rej(e);
}
});
}
describe('WebDriverExtension.provideFirstSupported', () => {
it('should provide the extension that matches the capabilities',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(['m1', 'm2', 'm3'], {'browser': 'm2'}).then((m) => {
expect(m.id).toEqual('m2');
async.done();
});
}));
it('should throw if there is no match',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(['m1'], {'browser': 'm2'}).catch((err) => {
expect(err != null).toBe(true);
async.done();
});
}));
});
})();
class MockExtension extends WebDriverExtension {
constructor(public id: string) { super(); }
constructor(public id: string) {
super();
}
supports(capabilities: {[key: string]: any}): boolean {
return capabilities['browser'] === this.id;

View File

@ -32,7 +32,7 @@ import {TraceEventFactory} from '../trace_event_factory';
const normEvents = new TraceEventFactory('timeline', 'pid0');
function createExtension(
perfRecords: any[] | null = null, userAgent: string | null = null,
perfRecords: any[]|null = null, userAgent: string|null = null,
messageMethod = 'Tracing.dataCollected'): WebDriverExtension {
if (!perfRecords) {
perfRecords = [];
@ -97,9 +97,9 @@ import {TraceEventFactory} from '../trace_event_factory';
it('should mark the timeline via performance.mark() with start and end of a test',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeEnd('name1', 'name2').then((_) => {
expect(log).toEqual([[
'executeScript', `performance.mark('name1-bpend');performance.mark('name2-bpstart');`
]]);
expect(log).toEqual([
['executeScript', `performance.mark('name1-bpend');performance.mark('name2-bpstart');`]
]);
async.done();
});
}));
@ -173,7 +173,8 @@ import {TraceEventFactory} from '../trace_event_factory';
[
chromeTimelineV8Events.start('MajorGC', 1000, {'usedHeapSizeBefore': 1000}),
chromeTimelineV8Events.end('MajorGC', 2000, {'usedHeapSizeAfter': 0}),
], )
],
)
.readPerfLog()
.then((events) => {
expect(events.length).toEqual(2);
@ -192,7 +193,8 @@ import {TraceEventFactory} from '../trace_event_factory';
[
chrome45TimelineEvents.start(recordType, 1234),
chrome45TimelineEvents.end(recordType, 2345)
], )
],
)
.readPerfLog()
.then((events) => {
expect(events).toEqual([
@ -210,7 +212,8 @@ import {TraceEventFactory} from '../trace_event_factory';
[
chromeBlinkTimelineEvents.start('UpdateLayoutTree', 1234),
chromeBlinkTimelineEvents.end('UpdateLayoutTree', 2345)
], )
],
)
.readPerfLog()
.then((events) => {
expect(events).toEqual([
@ -254,8 +257,10 @@ import {TraceEventFactory} from '../trace_event_factory';
}));
it('should report receivedData', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chrome45TimelineEvents.instant(
'ResourceReceivedData', 1234, {'data': {'encodedDataLength': 987}})], )
createExtension(
[chrome45TimelineEvents.instant(
'ResourceReceivedData', 1234, {'data': {'encodedDataLength': 987}})],
)
.readPerfLog()
.then((events) => {
expect(events).toEqual(
@ -265,9 +270,11 @@ import {TraceEventFactory} from '../trace_event_factory';
}));
it('should report sendRequest', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chrome45TimelineEvents.instant(
'ResourceSendRequest', 1234,
{'data': {'url': 'http://here', 'requestMethod': 'GET'}})], )
createExtension(
[chrome45TimelineEvents.instant(
'ResourceSendRequest', 1234,
{'data': {'url': 'http://here', 'requestMethod': 'GET'}})],
)
.readPerfLog()
.then((events) => {
expect(events).toEqual([normEvents.instant(
@ -277,7 +284,6 @@ import {TraceEventFactory} from '../trace_event_factory';
}));
describe('readPerfLog (common)', () => {
it('should execute a dummy script before reading them',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
// TODO(tbosch): This seems to be a bug in ChromeDriver:
@ -296,7 +302,8 @@ import {TraceEventFactory} from '../trace_event_factory';
[
chromeTimelineEvents.start(recordType, 1234),
chromeTimelineEvents.end(recordType, 2345)
], )
],
)
.readPerfLog()
.then((events) => {
expect(events).toEqual([
@ -337,7 +344,6 @@ import {TraceEventFactory} from '../trace_event_factory';
it('should throw when ImplThreadRenderingStats contains more than one frame',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([benchmarkEvents.instant(
'BenchmarkInstrumentation::ImplThreadRenderingStats', 1100,
{'data': {'frame_count': 2}})])
@ -349,7 +355,6 @@ import {TraceEventFactory} from '../trace_event_factory';
async.done();
});
}));
});
it('should report begin timestamps',
@ -374,7 +379,6 @@ import {TraceEventFactory} from '../trace_event_factory';
it('should throw an error on buffer overflow',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[
chromeTimelineEvents.start('FunctionCall', 1234),
@ -394,9 +398,7 @@ import {TraceEventFactory} from '../trace_event_factory';
expect(createExtension().supports({'browserName': 'Chrome'})).toBe(true);
});
});
});
}
@ -419,7 +421,7 @@ class MockDriverAdapter extends WebDriverAdapter {
{'message': {'method': this._messageMethod, 'params': event}}, null, 2)
})));
} else {
return null !;
return null!;
}
}
}

View File

@ -8,7 +8,7 @@
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/src/testing_internal';
import {IOsDriverExtension, Injector, WebDriverAdapter, WebDriverExtension} from '../../index';
import {Injector, IOsDriverExtension, WebDriverAdapter, WebDriverExtension} from '../../index';
import {TraceEventFactory} from '../trace_event_factory';
{
@ -18,7 +18,7 @@ import {TraceEventFactory} from '../trace_event_factory';
const normEvents = new TraceEventFactory('timeline', 'pid0');
function createExtension(perfRecords: any[] | null = null): WebDriverExtension {
function createExtension(perfRecords: any[]|null = null): WebDriverExtension {
if (!perfRecords) {
perfRecords = [];
}
@ -63,7 +63,6 @@ import {TraceEventFactory} from '../trace_event_factory';
}));
describe('readPerfLog', () => {
it('should execute a dummy script before reading them',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
// TODO(tbosch): This seems to be a bug in ChromeDriver:
@ -140,9 +139,7 @@ import {TraceEventFactory} from '../trace_event_factory';
expect(createExtension().supports({'browserName': 'Safari'})).toBe(true);
});
});
});
}
@ -155,7 +152,7 @@ function timeEndRecord(name: string, time: number) {
}
function durationRecord(
type: string, startTime: number, endTime: number, children: any[] | null = null) {
type: string, startTime: number, endTime: number, children: any[]|null = null) {
if (!children) {
children = [];
}
@ -172,7 +169,9 @@ function internalScriptRecord(startTime: number, endTime: number) {
}
class MockDriverAdapter extends WebDriverAdapter {
constructor(private _log: any[], private _perfRecords: any[]) { super(); }
constructor(private _log: any[], private _perfRecords: any[]) {
super();
}
executeScript(script: string) {
this._log.push(['executeScript', script]);
@ -190,7 +189,7 @@ class MockDriverAdapter extends WebDriverAdapter {
};
}));
} else {
return null !;
return null!;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,7 @@ export class HttpHeaders {
* Internal map of lowercase header names to values.
*/
// TODO(issue/24571): remove '!'.
private headers !: Map<string, string[]>;
private headers!: Map<string, string[]>;
/**
@ -36,7 +36,7 @@ export class HttpHeaders {
/**
* Complete the lazy initialization of this object (needed before reading).
*/
private lazyInit !: HttpHeaders | Function | null;
private lazyInit!: HttpHeaders|Function|null;
/**
* Queued updates to be materialized the next initialization.
@ -59,7 +59,7 @@ export class HttpHeaders {
const value = line.slice(index + 1).trim();
this.maybeSetNormalizedName(name, key);
if (this.headers.has(key)) {
this.headers.get(key) !.push(value);
this.headers.get(key)!.push(value);
} else {
this.headers.set(key, [value]);
}
@ -169,7 +169,7 @@ export class HttpHeaders {
*
* @returns A clone of the HTTP headers object with the given value deleted.
*/
delete (name: string, value?: string|string[]): HttpHeaders {
delete(name: string, value?: string|string[]): HttpHeaders {
return this.clone({name, value, op: 'd'});
}
@ -197,8 +197,8 @@ export class HttpHeaders {
private copyFrom(other: HttpHeaders) {
other.init();
Array.from(other.headers.keys()).forEach(key => {
this.headers.set(key, other.headers.get(key) !);
this.normalizedNames.set(key, other.normalizedNames.get(key) !);
this.headers.set(key, other.headers.get(key)!);
this.normalizedNames.set(key, other.normalizedNames.get(key)!);
});
}
@ -215,7 +215,7 @@ export class HttpHeaders {
switch (update.op) {
case 'a':
case 's':
let value = update.value !;
let value = update.value!;
if (typeof value === 'string') {
value = [value];
}
@ -255,6 +255,6 @@ export class HttpHeaders {
forEach(fn: (name: string, values: string[]) => void) {
this.init();
Array.from(this.normalizedNames.keys())
.forEach(key => fn(this.normalizedNames.get(key) !, this.headers.get(key) !));
.forEach(key => fn(this.normalizedNames.get(key)!, this.headers.get(key)!));
}
}

View File

@ -38,8 +38,8 @@ import {HttpEvent} from './response';
* To use the same instance of `HttpInterceptors` for the entire app, import the `HttpClientModule`
* only in your `AppModule`, and add the interceptors to the root application injector .
* If you import `HttpClientModule` multiple times across different modules (for example, in lazy
* loading modules), each import creates a new copy of the `HttpClientModule`, which overwrites the interceptors
* provided in the root module.
* loading modules), each import creates a new copy of the `HttpClientModule`, which overwrites the
* interceptors provided in the root module.
*
*/
export interface HttpInterceptor {

View File

@ -36,7 +36,9 @@ export const JSONP_ERR_WRONG_RESPONSE_TYPE = 'JSONP requests must use Json respo
*
*
*/
export abstract class JsonpCallbackContext { [key: string]: (data: any) => void; }
export abstract class JsonpCallbackContext {
[key: string]: (data: any) => void;
}
/**
* Processes an `HttpRequest` with the JSONP method,
@ -53,7 +55,9 @@ export class JsonpClientBackend implements HttpBackend {
/**
* Get the name of the next callback method, by incrementing the global `nextRequestId`.
*/
private nextCallback(): string { return `ng_jsonp_callback_${nextRequestId++}`; }
private nextCallback(): string {
return `ng_jsonp_callback_${nextRequestId++}`;
}
/**
* Processes a JSONP request and returns an event stream of the results.
@ -157,7 +161,8 @@ export class JsonpClientBackend implements HttpBackend {
observer.next(new HttpResponse({
body,
status: 200,
statusText: 'OK', url,
statusText: 'OK',
url,
}));
// Complete the stream, the response is over.
@ -178,7 +183,8 @@ export class JsonpClientBackend implements HttpBackend {
observer.error(new HttpErrorResponse({
error,
status: 0,
statusText: 'JSONP Error', url,
statusText: 'JSONP Error',
url,
}));
};

View File

@ -52,7 +52,7 @@ export class HttpInterceptingHandler implements HttpHandler {
*
*/
export function interceptingHandler(
backend: HttpBackend, interceptors: HttpInterceptor[] | null = []): HttpHandler {
backend: HttpBackend, interceptors: HttpInterceptor[]|null = []): HttpHandler {
if (!interceptors) {
return backend;
}

View File

@ -37,28 +37,36 @@ export class HttpUrlEncodingCodec implements HttpParameterCodec {
* @param key The key name.
* @returns The encoded key name.
*/
encodeKey(key: string): string { return standardEncoding(key); }
encodeKey(key: string): string {
return standardEncoding(key);
}
/**
* Encodes the value of a URL parameter or query-string.
* @param value The value.
* @returns The encoded value.
*/
encodeValue(value: string): string { return standardEncoding(value); }
encodeValue(value: string): string {
return standardEncoding(value);
}
/**
* Decodes an encoded URL parameter or query-string key.
* @param key The encoded key name.
* @returns The decoded key name.
*/
decodeKey(key: string): string { return decodeURIComponent(key); }
decodeKey(key: string): string {
return decodeURIComponent(key);
}
/**
* Decodes an encoded URL parameter or query-string value.
* @param value The encoded value.
* @returns The decoded value.
*/
decodeValue(value: string) { return decodeURIComponent(value); }
decodeValue(value: string) {
return decodeURIComponent(value);
}
}
@ -97,7 +105,8 @@ interface Update {
op: 'a'|'d'|'s';
}
/** Options used to construct an `HttpParams` instance.
/**
* Options used to construct an `HttpParams` instance.
*
* @publicApi
*/
@ -109,7 +118,7 @@ export interface HttpParamsOptions {
fromString?: string;
/** Object map of the HTTP parameters. Mutually exclusive with `fromString`. */
fromObject?: {[param: string]: string | ReadonlyArray<string>};
fromObject?: {[param: string]: string|ReadonlyArray<string>};
/** Encoding codec used to parse and serialize the parameters. */
encoder?: HttpParameterCodec;
@ -140,7 +149,7 @@ export class HttpParams {
this.map = new Map<string, string[]>();
Object.keys(options.fromObject).forEach(key => {
const value = (options.fromObject as any)[key];
this.map !.set(key, Array.isArray(value) ? value : [value]);
this.map!.set(key, Array.isArray(value) ? value : [value]);
});
} else {
this.map = null;
@ -155,7 +164,7 @@ export class HttpParams {
*/
has(param: string): boolean {
this.init();
return this.map !.has(param);
return this.map!.has(param);
}
/**
@ -166,7 +175,7 @@ export class HttpParams {
*/
get(param: string): string|null {
this.init();
const res = this.map !.get(param);
const res = this.map!.get(param);
return !!res ? res[0] : null;
}
@ -178,7 +187,7 @@ export class HttpParams {
*/
getAll(param: string): string[]|null {
this.init();
return this.map !.get(param) || null;
return this.map!.get(param) || null;
}
/**
@ -187,7 +196,7 @@ export class HttpParams {
*/
keys(): string[] {
this.init();
return Array.from(this.map !.keys());
return Array.from(this.map!.keys());
}
/**
@ -196,7 +205,9 @@ export class HttpParams {
* @param value The new value to add.
* @return A new body with the appended value.
*/
append(param: string, value: string): HttpParams { return this.clone({param, value, op: 'a'}); }
append(param: string, value: string): HttpParams {
return this.clone({param, value, op: 'a'});
}
/**
* Replaces the value for a parameter.
@ -204,7 +215,9 @@ export class HttpParams {
* @param value The new value.
* @return A new body with the new value.
*/
set(param: string, value: string): HttpParams { return this.clone({param, value, op: 's'}); }
set(param: string, value: string): HttpParams {
return this.clone({param, value, op: 's'});
}
/**
* Removes a given value or all values from a parameter.
@ -213,7 +226,9 @@ export class HttpParams {
* @return A new body with the given value removed, or with all values
* removed if no value is specified.
*/
delete (param: string, value?: string): HttpParams { return this.clone({param, value, op: 'd'}); }
delete(param: string, value?: string): HttpParams {
return this.clone({param, value, op: 'd'});
}
/**
* Serializes the body to an encoded string, where key-value pairs (separated by `=`) are
@ -227,7 +242,7 @@ export class HttpParams {
// `a: ['1']` produces `'a=1'`
// `b: []` produces `''`
// `c: ['1', '2']` produces `'c=1&c=2'`
return this.map !.get(key) !.map(value => eKey + '=' + this.encoder.encodeValue(value))
return this.map!.get(key)!.map(value => eKey + '=' + this.encoder.encodeValue(value))
.join('&');
})
// filter out empty values because `b: []` produces `''`
@ -237,7 +252,7 @@ export class HttpParams {
}
private clone(update: Update): HttpParams {
const clone = new HttpParams({ encoder: this.encoder } as HttpParamsOptions);
const clone = new HttpParams({encoder: this.encoder} as HttpParamsOptions);
clone.cloneFrom = this.cloneFrom || this;
clone.updates = (this.updates || []).concat([update]);
return clone;
@ -249,29 +264,29 @@ export class HttpParams {
}
if (this.cloneFrom !== null) {
this.cloneFrom.init();
this.cloneFrom.keys().forEach(key => this.map !.set(key, this.cloneFrom !.map !.get(key) !));
this.updates !.forEach(update => {
this.cloneFrom.keys().forEach(key => this.map!.set(key, this.cloneFrom!.map!.get(key)!));
this.updates!.forEach(update => {
switch (update.op) {
case 'a':
case 's':
const base = (update.op === 'a' ? this.map !.get(update.param) : undefined) || [];
base.push(update.value !);
this.map !.set(update.param, base);
const base = (update.op === 'a' ? this.map!.get(update.param) : undefined) || [];
base.push(update.value!);
this.map!.set(update.param, base);
break;
case 'd':
if (update.value !== undefined) {
let base = this.map !.get(update.param) || [];
let base = this.map!.get(update.param) || [];
const idx = base.indexOf(update.value);
if (idx !== -1) {
base.splice(idx, 1);
}
if (base.length > 0) {
this.map !.set(update.param, base);
this.map!.set(update.param, base);
} else {
this.map !.delete(update.param);
this.map!.delete(update.param);
}
} else {
this.map !.delete(update.param);
this.map!.delete(update.param);
break;
}
}

View File

@ -89,7 +89,7 @@ export class HttpRequest<T> {
* Outgoing headers for this request.
*/
// TODO(issue/24571): remove '!'.
readonly headers !: HttpHeaders;
readonly headers!: HttpHeaders;
/**
* Whether this request should be made in a way that exposes progress events.
@ -121,7 +121,7 @@ export class HttpRequest<T> {
* Outgoing URL parameters.
*/
// TODO(issue/24571): remove '!'.
readonly params !: HttpParams;
readonly params!: HttpParams;
/**
* The outgoing URL with all URL parameters set.
@ -312,7 +312,7 @@ export class HttpRequest<T> {
body?: T|null,
method?: string,
url?: string,
setHeaders?: {[name: string]: string | string[]},
setHeaders?: {[name: string]: string|string[]},
setParams?: {[param: string]: string},
}): HttpRequest<T>;
clone<V>(update: {
@ -324,7 +324,7 @@ export class HttpRequest<T> {
body?: V|null,
method?: string,
url?: string,
setHeaders?: {[name: string]: string | string[]},
setHeaders?: {[name: string]: string|string[]},
setParams?: {[param: string]: string},
}): HttpRequest<V>;
clone(update: {
@ -336,7 +336,7 @@ export class HttpRequest<T> {
body?: any|null,
method?: string,
url?: string,
setHeaders?: {[name: string]: string | string[]},
setHeaders?: {[name: string]: string|string[]},
setParams?: {[param: string]: string};
} = {}): HttpRequest<any> {
// For method, url, and responseType, take the current value unless
@ -368,20 +368,23 @@ export class HttpRequest<T> {
// Set every requested header.
headers =
Object.keys(update.setHeaders)
.reduce((headers, name) => headers.set(name, update.setHeaders ![name]), headers);
.reduce((headers, name) => headers.set(name, update.setHeaders![name]), headers);
}
// Check whether the caller has asked to set params.
if (update.setParams) {
// Set every requested param.
params = Object.keys(update.setParams)
.reduce((params, param) => params.set(param, update.setParams ![param]), params);
.reduce((params, param) => params.set(param, update.setParams![param]), params);
}
// Finally, construct the new HttpRequest using the pieces from above.
return new HttpRequest(
method, url, body, {
params, headers, reportProgress, responseType, withCredentials,
});
return new HttpRequest(method, url, body, {
params,
headers,
reportProgress,
responseType,
withCredentials,
});
}
}

Some files were not shown because too many files have changed in this diff Show More