perf: delete pre-view-engine core, compiler, platform-browser, etc code (#14788)

After the introduction of the view engine, we can drop a lot of code that is not used any more.

This should reduce the size of the app bundles because a lot of this code was not being properly tree-shaken by today's tools even though it was dead code.
This commit is contained in:
Tobias Bosch 2017-02-27 23:08:19 -08:00 committed by Igor Minar
parent e58cb7ba08
commit 126fda2613
151 changed files with 1283 additions and 14864 deletions

View File

@ -1,109 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {StaticSymbol} from '../aot/static_symbol';
export abstract class AnimationAst {
public startTime: number = 0;
public playTime: number = 0;
abstract visit(visitor: AnimationAstVisitor, context: any): any;
}
export abstract class AnimationStateAst extends AnimationAst {
abstract visit(visitor: AnimationAstVisitor, context: any): any;
}
export interface AnimationAstVisitor {
visitAnimationEntry(ast: AnimationEntryAst, context: any): any;
visitAnimationStateDeclaration(ast: AnimationStateDeclarationAst, context: any): any;
visitAnimationStateTransition(ast: AnimationStateTransitionAst, context: any): any;
visitAnimationStep(ast: AnimationStepAst, context: any): any;
visitAnimationSequence(ast: AnimationSequenceAst, context: any): any;
visitAnimationGroup(ast: AnimationGroupAst, context: any): any;
visitAnimationKeyframe(ast: AnimationKeyframeAst, context: any): any;
visitAnimationStyles(ast: AnimationStylesAst, context: any): any;
}
export class AnimationEntryAst extends AnimationAst {
constructor(
public name: string, public stateDeclarations: AnimationStateDeclarationAst[],
public stateTransitions: AnimationStateTransitionAst[]) {
super();
}
visit(visitor: AnimationAstVisitor, context: any): any {
return visitor.visitAnimationEntry(this, context);
}
}
export class AnimationStateDeclarationAst extends AnimationStateAst {
constructor(public stateName: string, public styles: AnimationStylesAst) { super(); }
visit(visitor: AnimationAstVisitor, context: any): any {
return visitor.visitAnimationStateDeclaration(this, context);
}
}
export class AnimationStateTransitionExpression {
constructor(public fromState: string, public toState: string) {}
}
export class AnimationStateTransitionFnExpression extends AnimationStateTransitionExpression {
constructor(public fn: Function|StaticSymbol) { super(null, null); }
}
export class AnimationStateTransitionAst extends AnimationStateAst {
constructor(
public stateChanges: AnimationStateTransitionExpression[],
public animation: AnimationWithStepsAst) {
super();
}
visit(visitor: AnimationAstVisitor, context: any): any {
return visitor.visitAnimationStateTransition(this, context);
}
}
export class AnimationStepAst extends AnimationAst {
constructor(
public startingStyles: AnimationStylesAst, public keyframes: AnimationKeyframeAst[],
public duration: number, public delay: number, public easing: string) {
super();
}
visit(visitor: AnimationAstVisitor, context: any): any {
return visitor.visitAnimationStep(this, context);
}
}
export class AnimationStylesAst extends AnimationAst {
constructor(public styles: Array<{[key: string]: string | number}>) { super(); }
visit(visitor: AnimationAstVisitor, context: any): any {
return visitor.visitAnimationStyles(this, context);
}
}
export class AnimationKeyframeAst extends AnimationAst {
constructor(public offset: number, public styles: AnimationStylesAst) { super(); }
visit(visitor: AnimationAstVisitor, context: any): any {
return visitor.visitAnimationKeyframe(this, context);
}
}
export abstract class AnimationWithStepsAst extends AnimationAst {
constructor(public steps: AnimationAst[]) { super(); }
}
export class AnimationGroupAst extends AnimationWithStepsAst {
constructor(steps: AnimationAst[]) { super(steps); }
visit(visitor: AnimationAstVisitor, context: any): any {
return visitor.visitAnimationGroup(this, context);
}
}
export class AnimationSequenceAst extends AnimationWithStepsAst {
constructor(steps: AnimationAst[]) { super(steps); }
visit(visitor: AnimationAstVisitor, context: any): any {
return visitor.visitAnimationSequence(this, context);
}
}

View File

@ -1,391 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {ɵANY_STATE, ɵDEFAULT_STATE, ɵEMPTY_STATE} from '@angular/core';
import {isPresent} from '../facade/lang';
import {Identifiers, createIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {AnimationAst, AnimationAstVisitor, AnimationEntryAst, AnimationGroupAst, AnimationKeyframeAst, AnimationSequenceAst, AnimationStateDeclarationAst, AnimationStateTransitionAst, AnimationStateTransitionFnExpression, AnimationStepAst, AnimationStylesAst} from './animation_ast';
export class AnimationEntryCompileResult {
constructor(public name: string, public statements: o.Statement[], public fnExp: o.Expression) {}
}
export class AnimationCompiler {
compile(factoryNamePrefix: string, parsedAnimations: AnimationEntryAst[]):
AnimationEntryCompileResult[] {
return parsedAnimations.map(entry => {
const factoryName = `${factoryNamePrefix}_${entry.name}`;
const visitor = new _AnimationBuilder(entry.name, factoryName);
return visitor.build(entry);
});
}
}
const _ANIMATION_FACTORY_ELEMENT_VAR = o.variable('element');
const _ANIMATION_DEFAULT_STATE_VAR = o.variable('defaultStateStyles');
const _ANIMATION_FACTORY_VIEW_VAR = o.variable('view');
const _ANIMATION_FACTORY_VIEW_CONTEXT = _ANIMATION_FACTORY_VIEW_VAR.prop('animationContext');
const _ANIMATION_FACTORY_RENDERER_VAR = _ANIMATION_FACTORY_VIEW_VAR.prop('renderer');
const _ANIMATION_CURRENT_STATE_VAR = o.variable('currentState');
const _ANIMATION_NEXT_STATE_VAR = o.variable('nextState');
const _ANIMATION_PLAYER_VAR = o.variable('player');
const _ANIMATION_TIME_VAR = o.variable('totalTime');
const _ANIMATION_START_STATE_STYLES_VAR = o.variable('startStateStyles');
const _ANIMATION_END_STATE_STYLES_VAR = o.variable('endStateStyles');
const _ANIMATION_COLLECTED_STYLES = o.variable('collectedStyles');
const _PREVIOUS_ANIMATION_PLAYERS = o.variable('previousPlayers');
const _EMPTY_MAP = o.literalMap([]);
const _EMPTY_ARRAY = o.literalArr([]);
class _AnimationBuilder implements AnimationAstVisitor {
private _fnVarName: string;
private _statesMapVarName: string;
private _statesMapVar: any;
constructor(public animationName: string, factoryName: string) {
this._fnVarName = factoryName + '_factory';
this._statesMapVarName = factoryName + '_states';
this._statesMapVar = o.variable(this._statesMapVarName);
}
visitAnimationStyles(ast: AnimationStylesAst, context: _AnimationBuilderContext): o.Expression {
const stylesArr: any[] = [];
if (context.isExpectingFirstStyleStep) {
stylesArr.push(_ANIMATION_START_STATE_STYLES_VAR);
context.isExpectingFirstStyleStep = false;
}
ast.styles.forEach(entry => {
const entries =
Object.keys(entry).map((key): [string, o.Expression] => [key, o.literal(entry[key])]);
stylesArr.push(o.literalMap(entries, null, true));
});
return o.importExpr(createIdentifier(Identifiers.AnimationStyles)).instantiate([
o.importExpr(createIdentifier(Identifiers.collectAndResolveStyles)).callFn([
_ANIMATION_COLLECTED_STYLES, o.literalArr(stylesArr)
])
]);
}
visitAnimationKeyframe(ast: AnimationKeyframeAst, context: _AnimationBuilderContext):
o.Expression {
return o.importExpr(createIdentifier(Identifiers.AnimationKeyframe)).instantiate([
o.literal(ast.offset), ast.styles.visit(this, context)
]);
}
visitAnimationStep(ast: AnimationStepAst, context: _AnimationBuilderContext): o.Expression {
if (context.endStateAnimateStep === ast) {
return this._visitEndStateAnimation(ast, context);
}
const startingStylesExpr = ast.startingStyles.visit(this, context);
const keyframeExpressions =
ast.keyframes.map(keyframeEntry => keyframeEntry.visit(this, context));
return this._callAnimateMethod(
ast, startingStylesExpr, o.literalArr(keyframeExpressions), context);
}
/** @internal */
_visitEndStateAnimation(ast: AnimationStepAst, context: _AnimationBuilderContext): o.Expression {
const startingStylesExpr = ast.startingStyles.visit(this, context);
const keyframeExpressions = ast.keyframes.map(keyframe => keyframe.visit(this, context));
const keyframesExpr =
o.importExpr(createIdentifier(Identifiers.balanceAnimationKeyframes)).callFn([
_ANIMATION_COLLECTED_STYLES, _ANIMATION_END_STATE_STYLES_VAR,
o.literalArr(keyframeExpressions)
]);
return this._callAnimateMethod(ast, startingStylesExpr, keyframesExpr, context);
}
/** @internal */
_callAnimateMethod(
ast: AnimationStepAst, startingStylesExpr: any, keyframesExpr: any,
context: _AnimationBuilderContext) {
let previousStylesValue: o.Expression = _EMPTY_ARRAY;
if (context.isExpectingFirstAnimateStep) {
previousStylesValue = _PREVIOUS_ANIMATION_PLAYERS;
context.isExpectingFirstAnimateStep = false;
}
context.totalTransitionTime += ast.duration + ast.delay;
return _ANIMATION_FACTORY_RENDERER_VAR.callMethod('animate', [
_ANIMATION_FACTORY_ELEMENT_VAR, startingStylesExpr, keyframesExpr, o.literal(ast.duration),
o.literal(ast.delay), o.literal(ast.easing), previousStylesValue
]);
}
visitAnimationSequence(ast: AnimationSequenceAst, context: _AnimationBuilderContext):
o.Expression {
const playerExprs = ast.steps.map(step => step.visit(this, context));
return o.importExpr(createIdentifier(Identifiers.AnimationSequencePlayer)).instantiate([
o.literalArr(playerExprs)
]);
}
visitAnimationGroup(ast: AnimationGroupAst, context: _AnimationBuilderContext): o.Expression {
const playerExprs = ast.steps.map(step => step.visit(this, context));
return o.importExpr(createIdentifier(Identifiers.AnimationGroupPlayer)).instantiate([
o.literalArr(playerExprs)
]);
}
visitAnimationStateDeclaration(
ast: AnimationStateDeclarationAst, context: _AnimationBuilderContext): void {
const flatStyles: {[key: string]: string | number} = {};
_getStylesArray(ast).forEach(
entry => { Object.keys(entry).forEach(key => { flatStyles[key] = entry[key]; }); });
context.stateMap.registerState(ast.stateName, flatStyles);
}
visitAnimationStateTransition(
ast: AnimationStateTransitionAst, context: _AnimationBuilderContext): any {
const steps = ast.animation.steps;
const lastStep = steps[steps.length - 1];
if (_isEndStateAnimateStep(lastStep)) {
context.endStateAnimateStep = <AnimationStepAst>lastStep;
}
context.totalTransitionTime = 0;
context.isExpectingFirstStyleStep = true;
context.isExpectingFirstAnimateStep = true;
const stateChangePreconditions: o.Expression[] = [];
ast.stateChanges.forEach(stateChange => {
if (stateChange instanceof AnimationStateTransitionFnExpression) {
stateChangePreconditions.push(o.importExpr({reference: stateChange.fn}).callFn([
_ANIMATION_CURRENT_STATE_VAR, _ANIMATION_NEXT_STATE_VAR
]));
} else {
stateChangePreconditions.push(
_compareToAnimationStateExpr(_ANIMATION_CURRENT_STATE_VAR, stateChange.fromState)
.and(_compareToAnimationStateExpr(_ANIMATION_NEXT_STATE_VAR, stateChange.toState)));
if (stateChange.fromState != ɵANY_STATE) {
context.stateMap.registerState(stateChange.fromState);
}
if (stateChange.toState != ɵANY_STATE) {
context.stateMap.registerState(stateChange.toState);
}
}
});
const animationPlayerExpr = ast.animation.visit(this, context);
const reducedStateChangesPrecondition = stateChangePreconditions.reduce((a, b) => a.or(b));
const precondition =
_ANIMATION_PLAYER_VAR.equals(o.NULL_EXPR).and(reducedStateChangesPrecondition);
const animationStmt = _ANIMATION_PLAYER_VAR.set(animationPlayerExpr).toStmt();
const totalTimeStmt = _ANIMATION_TIME_VAR.set(o.literal(context.totalTransitionTime)).toStmt();
return new o.IfStmt(precondition, [animationStmt, totalTimeStmt]);
}
visitAnimationEntry(ast: AnimationEntryAst, context: _AnimationBuilderContext): any {
// visit each of the declarations first to build the context state map
ast.stateDeclarations.forEach(def => def.visit(this, context));
// this should always be defined even if the user overrides it
context.stateMap.registerState(ɵDEFAULT_STATE, {});
const statements: o.Statement[] = [];
statements.push(_PREVIOUS_ANIMATION_PLAYERS
.set(_ANIMATION_FACTORY_VIEW_CONTEXT.callMethod(
'getAnimationPlayers',
[
_ANIMATION_FACTORY_ELEMENT_VAR,
_ANIMATION_NEXT_STATE_VAR.equals(o.literal(ɵEMPTY_STATE))
.conditional(o.NULL_EXPR, o.literal(this.animationName))
]))
.toDeclStmt());
statements.push(_ANIMATION_COLLECTED_STYLES.set(_EMPTY_MAP).toDeclStmt());
statements.push(_ANIMATION_PLAYER_VAR.set(o.NULL_EXPR).toDeclStmt());
statements.push(_ANIMATION_TIME_VAR.set(o.literal(0)).toDeclStmt());
statements.push(
_ANIMATION_DEFAULT_STATE_VAR.set(this._statesMapVar.key(o.literal(ɵDEFAULT_STATE)))
.toDeclStmt());
statements.push(
_ANIMATION_START_STATE_STYLES_VAR.set(this._statesMapVar.key(_ANIMATION_CURRENT_STATE_VAR))
.toDeclStmt());
statements.push(new o.IfStmt(
_ANIMATION_START_STATE_STYLES_VAR.equals(o.NULL_EXPR),
[_ANIMATION_START_STATE_STYLES_VAR.set(_ANIMATION_DEFAULT_STATE_VAR).toStmt()]));
statements.push(
_ANIMATION_END_STATE_STYLES_VAR.set(this._statesMapVar.key(_ANIMATION_NEXT_STATE_VAR))
.toDeclStmt());
statements.push(new o.IfStmt(
_ANIMATION_END_STATE_STYLES_VAR.equals(o.NULL_EXPR),
[_ANIMATION_END_STATE_STYLES_VAR.set(_ANIMATION_DEFAULT_STATE_VAR).toStmt()]));
const RENDER_STYLES_FN = o.importExpr(createIdentifier(Identifiers.renderStyles));
ast.stateTransitions.forEach(transAst => statements.push(transAst.visit(this, context)));
// this check ensures that the animation factory always returns a player
// so that the onDone callback can be used for tracking
statements.push(new o.IfStmt(
_ANIMATION_PLAYER_VAR.equals(o.NULL_EXPR),
[_ANIMATION_PLAYER_VAR
.set(o.importExpr(createIdentifier(Identifiers.NoOpAnimationPlayer)).instantiate([]))
.toStmt()]));
// once complete we want to apply the styles on the element
// since the destination state's values should persist once
// the animation sequence has completed.
statements.push(
_ANIMATION_PLAYER_VAR
.callMethod(
'onDone',
[o
.fn([],
[
_ANIMATION_PLAYER_VAR.callMethod('destroy', []).toStmt(),
RENDER_STYLES_FN
.callFn([
_ANIMATION_FACTORY_ELEMENT_VAR, _ANIMATION_FACTORY_RENDERER_VAR,
o.importExpr(
createIdentifier(Identifiers.prepareFinalAnimationStyles))
.callFn(
[
_ANIMATION_START_STATE_STYLES_VAR,
_ANIMATION_END_STATE_STYLES_VAR
])
])
.toStmt()
])])
.toStmt());
statements.push(o.importExpr(createIdentifier(Identifiers.AnimationSequencePlayer))
.instantiate([_PREVIOUS_ANIMATION_PLAYERS])
.callMethod('destroy', [])
.toStmt());
// before we start any animation we want to clear out the starting
// styles from the element's style property (since they were placed
// there at the end of the last animation
statements.push(RENDER_STYLES_FN
.callFn([
_ANIMATION_FACTORY_ELEMENT_VAR, _ANIMATION_FACTORY_RENDERER_VAR,
o.importExpr(createIdentifier(Identifiers.clearStyles))
.callFn([_ANIMATION_START_STATE_STYLES_VAR])
])
.toStmt());
statements.push(_ANIMATION_FACTORY_VIEW_CONTEXT
.callMethod(
'queueAnimation',
[
_ANIMATION_FACTORY_ELEMENT_VAR, o.literal(this.animationName),
_ANIMATION_PLAYER_VAR
])
.toStmt());
statements.push(new o.ReturnStatement(
o.importExpr(createIdentifier(Identifiers.AnimationTransition)).instantiate([
_ANIMATION_PLAYER_VAR, _ANIMATION_FACTORY_ELEMENT_VAR, o.literal(this.animationName),
_ANIMATION_CURRENT_STATE_VAR, _ANIMATION_NEXT_STATE_VAR, _ANIMATION_TIME_VAR
])));
return o.fn(
[
new o.FnParam(
_ANIMATION_FACTORY_VIEW_VAR.name,
o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
new o.FnParam(_ANIMATION_FACTORY_ELEMENT_VAR.name, o.DYNAMIC_TYPE),
new o.FnParam(_ANIMATION_CURRENT_STATE_VAR.name, o.DYNAMIC_TYPE),
new o.FnParam(_ANIMATION_NEXT_STATE_VAR.name, o.DYNAMIC_TYPE)
],
statements, o.importType(createIdentifier(Identifiers.AnimationTransition)));
}
build(ast: AnimationAst): AnimationEntryCompileResult {
const context = new _AnimationBuilderContext();
const fnStatement = ast.visit(this, context).toDeclStmt(this._fnVarName);
const fnVariable = o.variable(this._fnVarName);
const lookupMap: any[] = [];
Object.keys(context.stateMap.states).forEach(stateName => {
const value = context.stateMap.states[stateName];
let variableValue = _EMPTY_MAP;
if (isPresent(value)) {
const styleMap: any[] = [];
Object.keys(value).forEach(key => { styleMap.push([key, o.literal(value[key])]); });
variableValue = o.literalMap(styleMap, null, true);
}
lookupMap.push([stateName, variableValue]);
});
const compiledStatesMapStmt =
this._statesMapVar.set(o.literalMap(lookupMap, null, true)).toDeclStmt();
const statements: o.Statement[] = [compiledStatesMapStmt, fnStatement];
return new AnimationEntryCompileResult(this.animationName, statements, fnVariable);
}
}
class _AnimationBuilderContext {
stateMap = new _AnimationBuilderStateMap();
endStateAnimateStep: AnimationStepAst = null;
isExpectingFirstStyleStep = false;
isExpectingFirstAnimateStep = false;
totalTransitionTime = 0;
}
class _AnimationBuilderStateMap {
private _states: {[key: string]: {[prop: string]: string | number}} = {};
get states() { return this._states; }
registerState(name: string, value: {[prop: string]: string | number} = null): void {
const existingEntry = this._states[name];
if (!existingEntry) {
this._states[name] = value;
}
}
}
function _compareToAnimationStateExpr(value: o.Expression, animationState: string): o.Expression {
const emptyStateLiteral = o.literal(ɵEMPTY_STATE);
switch (animationState) {
case ɵEMPTY_STATE:
return value.equals(emptyStateLiteral);
case ɵANY_STATE:
return o.literal(true);
default:
return value.equals(o.literal(animationState));
}
}
function _isEndStateAnimateStep(step: AnimationAst): boolean {
// the final animation step is characterized by having only TWO
// keyframe values and it must have zero styles for both keyframes
if (step instanceof AnimationStepAst && step.duration > 0 && step.keyframes.length == 2) {
const styles1 = _getStylesArray(step.keyframes[0])[0];
const styles2 = _getStylesArray(step.keyframes[1])[0];
return Object.keys(styles1).length === 0 && Object.keys(styles2).length === 0;
}
return false;
}
function _getStylesArray(obj: any): {[key: string]: any}[] {
return obj.styles.styles;
}

View File

@ -1,605 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {ɵANY_STATE, ɵFILL_STYLE_FLAG} from '@angular/core';
import {StaticSymbol} from '../aot/static_symbol';
import {CompileAnimationAnimateMetadata, CompileAnimationEntryMetadata, CompileAnimationGroupMetadata, CompileAnimationKeyframesSequenceMetadata, CompileAnimationMetadata, CompileAnimationSequenceMetadata, CompileAnimationStateDeclarationMetadata, CompileAnimationStateTransitionMetadata, CompileAnimationStyleMetadata, CompileAnimationWithStepsMetadata, CompileDirectiveMetadata, identifierName} from '../compile_metadata';
import {StringMapWrapper} from '../facade/collection';
import {isBlank, isPresent} from '../facade/lang';
import {CompilerInjectable} from '../injectable';
import {ParseError} from '../parse_util';
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
import {AnimationAst, AnimationEntryAst, AnimationGroupAst, AnimationKeyframeAst, AnimationSequenceAst, AnimationStateDeclarationAst, AnimationStateTransitionAst, AnimationStateTransitionExpression, AnimationStateTransitionFnExpression, AnimationStepAst, AnimationStylesAst, AnimationWithStepsAst} from './animation_ast';
import {StylesCollection} from './styles_collection';
const _INITIAL_KEYFRAME = 0;
const _TERMINAL_KEYFRAME = 1;
const _ONE_SECOND = 1000;
declare type Styles = {
[key: string]: string | number
};
export class AnimationParseError extends ParseError {
constructor(message: string) { super(null, message); }
toString(): string { return `${this.msg}`; }
}
export class AnimationEntryParseResult {
constructor(public ast: AnimationEntryAst, public errors: AnimationParseError[]) {}
}
@CompilerInjectable()
export class AnimationParser {
constructor(private _schema: ElementSchemaRegistry) {}
parseComponent(component: CompileDirectiveMetadata): AnimationEntryAst[] {
const errors: string[] = [];
const componentName = identifierName(component.type);
const animationTriggerNames = new Set<string>();
const asts = component.template.animations.map(entry => {
const result = this.parseEntry(entry);
const ast = result.ast;
const triggerName = ast.name;
if (animationTriggerNames.has(triggerName)) {
result.errors.push(new AnimationParseError(
`The animation trigger "${triggerName}" has already been registered for the ${componentName} component`));
} else {
animationTriggerNames.add(triggerName);
}
if (result.errors.length > 0) {
let errorMessage =
`- Unable to parse the animation sequence for "${triggerName}" on the ${componentName} component due to the following errors:`;
result.errors.forEach(
(error: AnimationParseError) => { errorMessage += '\n-- ' + error.msg; });
errors.push(errorMessage);
}
return ast;
});
if (errors.length > 0) {
const errorString = errors.join('\n');
throw new Error(`Animation parse errors:\n${errorString}`);
}
return asts;
}
parseEntry(entry: CompileAnimationEntryMetadata): AnimationEntryParseResult {
const errors: AnimationParseError[] = [];
const stateStyles: {[key: string]: AnimationStylesAst} = {};
const transitions: CompileAnimationStateTransitionMetadata[] = [];
const stateDeclarationAsts: AnimationStateDeclarationAst[] = [];
entry.definitions.forEach(def => {
if (def instanceof CompileAnimationStateDeclarationMetadata) {
_parseAnimationDeclarationStates(def, this._schema, errors).forEach(ast => {
stateDeclarationAsts.push(ast);
stateStyles[ast.stateName] = ast.styles;
});
} else {
transitions.push(<CompileAnimationStateTransitionMetadata>def);
}
});
const stateTransitionAsts = transitions.map(
transDef => _parseAnimationStateTransition(transDef, stateStyles, this._schema, errors));
const ast = new AnimationEntryAst(entry.name, stateDeclarationAsts, stateTransitionAsts);
return new AnimationEntryParseResult(ast, errors);
}
}
function _parseAnimationDeclarationStates(
stateMetadata: CompileAnimationStateDeclarationMetadata, schema: ElementSchemaRegistry,
errors: AnimationParseError[]): AnimationStateDeclarationAst[] {
const normalizedStyles = _normalizeStyleMetadata(stateMetadata.styles, {}, schema, errors, false);
const defStyles = new AnimationStylesAst(normalizedStyles);
const states = stateMetadata.stateNameExpr.split(/\s*,\s*/);
return states.map(state => new AnimationStateDeclarationAst(state, defStyles));
}
function _parseAnimationStateTransition(
transitionStateMetadata: CompileAnimationStateTransitionMetadata,
stateStyles: {[key: string]: AnimationStylesAst}, schema: ElementSchemaRegistry,
errors: AnimationParseError[]): AnimationStateTransitionAst {
const styles = new StylesCollection();
const transitionExprs: AnimationStateTransitionExpression[] = [];
const stateChangeExpr = transitionStateMetadata.stateChangeExpr;
const transitionStates: Array<Function|StaticSymbol|string> = typeof stateChangeExpr == 'string' ?
(<string>stateChangeExpr).split(/\s*,\s*/) :
[<Function|StaticSymbol>stateChangeExpr];
transitionStates.forEach(
expr => transitionExprs.push(..._parseAnimationTransitionExpr(expr, errors)));
const entry = _normalizeAnimationEntry(transitionStateMetadata.steps);
const animation = _normalizeStyleSteps(entry, stateStyles, schema, errors);
const animationAst = _parseTransitionAnimation(animation, 0, styles, stateStyles, errors);
if (errors.length == 0) {
_fillAnimationAstStartingKeyframes(animationAst, styles, errors);
}
const stepsAst: AnimationWithStepsAst = (animationAst instanceof AnimationWithStepsAst) ?
animationAst :
new AnimationSequenceAst([animationAst]);
return new AnimationStateTransitionAst(transitionExprs, stepsAst);
}
function _parseAnimationAlias(alias: string, errors: AnimationParseError[]): string {
switch (alias) {
case ':enter':
return 'void => *';
case ':leave':
return '* => void';
default:
errors.push(
new AnimationParseError(`the transition alias value "${alias}" is not supported`));
return '* => *';
}
}
function _parseAnimationTransitionExpr(
transitionValue: string | Function | StaticSymbol,
errors: AnimationParseError[]): AnimationStateTransitionExpression[] {
const expressions: AnimationStateTransitionExpression[] = [];
if (typeof transitionValue == 'string') {
let eventStr = <string>transitionValue;
if (eventStr[0] == ':') {
eventStr = _parseAnimationAlias(eventStr, errors);
}
const match = eventStr.match(/^(\*|[-\w]+)\s*(<?[=-]>)\s*(\*|[-\w]+)$/);
if (!isPresent(match) || match.length < 4) {
errors.push(new AnimationParseError(`the provided ${eventStr} is not of a supported format`));
return expressions;
}
const fromState = match[1];
const separator = match[2];
const toState = match[3];
expressions.push(new AnimationStateTransitionExpression(fromState, toState));
const isFullAnyStateExpr = fromState == ɵANY_STATE && toState == ɵANY_STATE;
if (separator[0] == '<' && !isFullAnyStateExpr) {
expressions.push(new AnimationStateTransitionExpression(toState, fromState));
}
} else {
expressions.push(
new AnimationStateTransitionFnExpression(<Function|StaticSymbol>transitionValue));
}
return expressions;
}
function _normalizeAnimationEntry(entry: CompileAnimationMetadata | CompileAnimationMetadata[]):
CompileAnimationMetadata {
return Array.isArray(entry) ? new CompileAnimationSequenceMetadata(entry) : entry;
}
function _normalizeStyleMetadata(
entry: CompileAnimationStyleMetadata, stateStyles: {[key: string]: AnimationStylesAst},
schema: ElementSchemaRegistry, errors: AnimationParseError[],
permitStateReferences: boolean): {[key: string]: string | number}[] {
const offset = entry.offset;
if (offset > 1 || offset < 0) {
errors.push(new AnimationParseError(`Offset values for animations must be between 0 and 1`));
}
const normalizedStyles: {[key: string]: string | number}[] = [];
entry.styles.forEach(styleEntry => {
if (typeof styleEntry === 'string') {
if (permitStateReferences) {
normalizedStyles.push(..._resolveStylesFromState(<string>styleEntry, stateStyles, errors));
} else {
errors.push(new AnimationParseError(
`State based animations cannot contain references to other states`));
}
} else {
const stylesObj = <Styles>styleEntry;
const normalizedStylesObj: Styles = {};
Object.keys(stylesObj).forEach(propName => {
const normalizedProp = schema.normalizeAnimationStyleProperty(propName);
const normalizedOutput =
schema.normalizeAnimationStyleValue(normalizedProp, propName, stylesObj[propName]);
const normalizationError = normalizedOutput['error'];
if (normalizationError) {
errors.push(new AnimationParseError(normalizationError));
}
normalizedStylesObj[normalizedProp] = normalizedOutput['value'];
});
normalizedStyles.push(normalizedStylesObj);
}
});
return normalizedStyles;
}
function _normalizeStyleSteps(
entry: CompileAnimationMetadata, stateStyles: {[key: string]: AnimationStylesAst},
schema: ElementSchemaRegistry, errors: AnimationParseError[]): CompileAnimationMetadata {
const steps = _normalizeStyleStepEntry(entry, stateStyles, schema, errors);
return (entry instanceof CompileAnimationGroupMetadata) ?
new CompileAnimationGroupMetadata(steps) :
new CompileAnimationSequenceMetadata(steps);
}
function _mergeAnimationStyles(
stylesList: any[], newItem: {[key: string]: string | number} | string) {
if (typeof newItem === 'object' && newItem !== null && stylesList.length > 0) {
const lastIndex = stylesList.length - 1;
const lastItem = stylesList[lastIndex];
if (typeof lastItem === 'object' && lastItem !== null) {
stylesList[lastIndex] = StringMapWrapper.merge(
<{[key: string]: string | number}>lastItem, <{[key: string]: string | number}>newItem);
return;
}
}
stylesList.push(newItem);
}
function _normalizeStyleStepEntry(
entry: CompileAnimationMetadata, stateStyles: {[key: string]: AnimationStylesAst},
schema: ElementSchemaRegistry, errors: AnimationParseError[]): CompileAnimationMetadata[] {
let steps: CompileAnimationMetadata[];
if (entry instanceof CompileAnimationWithStepsMetadata) {
steps = entry.steps;
} else {
return [entry];
}
const newSteps: CompileAnimationMetadata[] = [];
let combinedStyles: Styles[];
steps.forEach(step => {
if (step instanceof CompileAnimationStyleMetadata) {
// this occurs when a style step is followed by a previous style step
// or when the first style step is run. We want to concatenate all subsequent
// style steps together into a single style step such that we have the correct
// starting keyframe data to pass into the animation player.
if (!isPresent(combinedStyles)) {
combinedStyles = [];
}
_normalizeStyleMetadata(
<CompileAnimationStyleMetadata>step, stateStyles, schema, errors, true)
.forEach(entry => { _mergeAnimationStyles(combinedStyles, entry); });
} else {
// it is important that we create a metadata entry of the combined styles
// before we go on an process the animate, sequence or group metadata steps.
// This will ensure that the AST will have the previous styles painted on
// screen before any further animations that use the styles take place.
if (isPresent(combinedStyles)) {
newSteps.push(new CompileAnimationStyleMetadata(0, combinedStyles));
combinedStyles = null;
}
if (step instanceof CompileAnimationAnimateMetadata) {
// we do not recurse into CompileAnimationAnimateMetadata since
// those style steps are not going to be squashed
const animateStyleValue = (<CompileAnimationAnimateMetadata>step).styles;
if (animateStyleValue instanceof CompileAnimationStyleMetadata) {
animateStyleValue.styles =
_normalizeStyleMetadata(animateStyleValue, stateStyles, schema, errors, true);
} else if (animateStyleValue instanceof CompileAnimationKeyframesSequenceMetadata) {
animateStyleValue.steps.forEach(step => {
step.styles = _normalizeStyleMetadata(step, stateStyles, schema, errors, true);
});
}
} else if (step instanceof CompileAnimationWithStepsMetadata) {
const innerSteps = _normalizeStyleStepEntry(step, stateStyles, schema, errors);
step = step instanceof CompileAnimationGroupMetadata ?
new CompileAnimationGroupMetadata(innerSteps) :
new CompileAnimationSequenceMetadata(innerSteps);
}
newSteps.push(step);
}
});
// this happens when only styles were animated within the sequence
if (isPresent(combinedStyles)) {
newSteps.push(new CompileAnimationStyleMetadata(0, combinedStyles));
}
return newSteps;
}
function _resolveStylesFromState(
stateName: string, stateStyles: {[key: string]: AnimationStylesAst},
errors: AnimationParseError[]) {
const styles: Styles[] = [];
if (stateName[0] != ':') {
errors.push(new AnimationParseError(`Animation states via styles must be prefixed with a ":"`));
} else {
const normalizedStateName = stateName.substring(1);
const value = stateStyles[normalizedStateName];
if (!isPresent(value)) {
errors.push(new AnimationParseError(
`Unable to apply styles due to missing a state: "${normalizedStateName}"`));
} else {
value.styles.forEach(stylesEntry => {
if (typeof stylesEntry === 'object' && stylesEntry !== null) {
styles.push(stylesEntry as Styles);
}
});
}
}
return styles;
}
class _AnimationTimings {
constructor(public duration: number, public delay: number, public easing: string) {}
}
function _parseAnimationKeyframes(
keyframeSequence: CompileAnimationKeyframesSequenceMetadata, currentTime: number,
collectedStyles: StylesCollection, stateStyles: {[key: string]: AnimationStylesAst},
errors: AnimationParseError[]): AnimationKeyframeAst[] {
const totalEntries = keyframeSequence.steps.length;
let totalOffsets = 0;
keyframeSequence.steps.forEach(step => totalOffsets += (isPresent(step.offset) ? 1 : 0));
if (totalOffsets > 0 && totalOffsets < totalEntries) {
errors.push(new AnimationParseError(
`Not all style() entries contain an offset for the provided keyframe()`));
totalOffsets = totalEntries;
}
let limit = totalEntries - 1;
const margin = totalOffsets == 0 ? (1 / limit) : 0;
const rawKeyframes: any[] /** TODO #9100 */ = [];
let index = 0;
let doSortKeyframes = false;
let lastOffset = 0;
keyframeSequence.steps.forEach(styleMetadata => {
let offset = styleMetadata.offset;
const keyframeStyles: Styles = {};
styleMetadata.styles.forEach(entry => {
Object.keys(entry).forEach(prop => {
if (prop != 'offset') {
keyframeStyles[prop] = (entry as Styles)[prop];
}
});
});
if (isPresent(offset)) {
doSortKeyframes = doSortKeyframes || (offset < lastOffset);
} else {
offset = index == limit ? _TERMINAL_KEYFRAME : (margin * index);
}
rawKeyframes.push([offset, keyframeStyles]);
lastOffset = offset;
index++;
});
if (doSortKeyframes) {
rawKeyframes.sort((a, b) => a[0] <= b[0] ? -1 : 1);
}
let firstKeyframe = rawKeyframes[0];
if (firstKeyframe[0] != _INITIAL_KEYFRAME) {
rawKeyframes.splice(0, 0, firstKeyframe = [_INITIAL_KEYFRAME, {}]);
}
const firstKeyframeStyles = firstKeyframe[1];
limit = rawKeyframes.length - 1;
let lastKeyframe = rawKeyframes[limit];
if (lastKeyframe[0] != _TERMINAL_KEYFRAME) {
rawKeyframes.push(lastKeyframe = [_TERMINAL_KEYFRAME, {}]);
limit++;
}
const lastKeyframeStyles = lastKeyframe[1];
for (let i = 1; i <= limit; i++) {
const entry = rawKeyframes[i];
const styles = entry[1];
Object.keys(styles).forEach(prop => {
if (!isPresent(firstKeyframeStyles[prop])) {
firstKeyframeStyles[prop] = ɵFILL_STYLE_FLAG;
}
});
}
for (let i = limit - 1; i >= 0; i--) {
const entry = rawKeyframes[i];
const styles = entry[1];
Object.keys(styles).forEach(prop => {
if (!isPresent(lastKeyframeStyles[prop])) {
lastKeyframeStyles[prop] = styles[prop];
}
});
}
return rawKeyframes.map(
entry => new AnimationKeyframeAst(entry[0], new AnimationStylesAst([entry[1]])));
}
function _parseTransitionAnimation(
entry: CompileAnimationMetadata, currentTime: number, collectedStyles: StylesCollection,
stateStyles: {[key: string]: AnimationStylesAst}, errors: AnimationParseError[]): AnimationAst {
let ast: any /** TODO #9100 */;
let playTime = 0;
const startingTime = currentTime;
if (entry instanceof CompileAnimationWithStepsMetadata) {
let maxDuration = 0;
const steps: any[] /** TODO #9100 */ = [];
const isGroup = entry instanceof CompileAnimationGroupMetadata;
let previousStyles: any /** TODO #9100 */;
entry.steps.forEach(entry => {
// these will get picked up by the next step...
const time = isGroup ? startingTime : currentTime;
if (entry instanceof CompileAnimationStyleMetadata) {
entry.styles.forEach(stylesEntry => {
// by this point we know that we only have stringmap values
const map = stylesEntry as Styles;
Object.keys(map).forEach(
prop => { collectedStyles.insertAtTime(prop, time, map[prop]); });
});
previousStyles = entry.styles;
return;
}
const innerAst = _parseTransitionAnimation(entry, time, collectedStyles, stateStyles, errors);
if (isPresent(previousStyles)) {
if (entry instanceof CompileAnimationWithStepsMetadata) {
const startingStyles = new AnimationStylesAst(previousStyles);
steps.push(new AnimationStepAst(startingStyles, [], 0, 0, ''));
} else {
const innerStep = <AnimationStepAst>innerAst;
innerStep.startingStyles.styles.push(...previousStyles);
}
previousStyles = null;
}
const astDuration = innerAst.playTime;
currentTime += astDuration;
playTime += astDuration;
maxDuration = Math.max(astDuration, maxDuration);
steps.push(innerAst);
});
if (isPresent(previousStyles)) {
const startingStyles = new AnimationStylesAst(previousStyles);
steps.push(new AnimationStepAst(startingStyles, [], 0, 0, ''));
}
if (isGroup) {
ast = new AnimationGroupAst(steps);
playTime = maxDuration;
currentTime = startingTime + playTime;
} else {
ast = new AnimationSequenceAst(steps);
}
} else if (entry instanceof CompileAnimationAnimateMetadata) {
const timings = _parseTimeExpression(entry.timings, errors);
const styles = entry.styles;
let keyframes: any /** TODO #9100 */;
if (styles instanceof CompileAnimationKeyframesSequenceMetadata) {
keyframes =
_parseAnimationKeyframes(styles, currentTime, collectedStyles, stateStyles, errors);
} else {
const styleData = <CompileAnimationStyleMetadata>styles;
const offset = _TERMINAL_KEYFRAME;
const styleAst = new AnimationStylesAst(styleData.styles as Styles[]);
const keyframe = new AnimationKeyframeAst(offset, styleAst);
keyframes = [keyframe];
}
ast = new AnimationStepAst(
new AnimationStylesAst([]), keyframes, timings.duration, timings.delay, timings.easing);
playTime = timings.duration + timings.delay;
currentTime += playTime;
keyframes.forEach(
(keyframe: any /** TODO #9100 */) => keyframe.styles.styles.forEach(
(entry: any /** TODO #9100 */) => Object.keys(entry).forEach(
prop => { collectedStyles.insertAtTime(prop, currentTime, entry[prop]); })));
} else {
// if the code reaches this stage then an error
// has already been populated within the _normalizeStyleSteps()
// operation...
ast = new AnimationStepAst(null, [], 0, 0, '');
}
ast.playTime = playTime;
ast.startTime = startingTime;
return ast;
}
function _fillAnimationAstStartingKeyframes(
ast: AnimationAst, collectedStyles: StylesCollection, errors: AnimationParseError[]): void {
// steps that only contain style will not be filled
if ((ast instanceof AnimationStepAst) && ast.keyframes.length > 0) {
const keyframes = ast.keyframes;
if (keyframes.length == 1) {
const endKeyframe = keyframes[0];
const startKeyframe = _createStartKeyframeFromEndKeyframe(
endKeyframe, ast.startTime, ast.playTime, collectedStyles, errors);
ast.keyframes = [startKeyframe, endKeyframe];
}
} else if (ast instanceof AnimationWithStepsAst) {
ast.steps.forEach(entry => _fillAnimationAstStartingKeyframes(entry, collectedStyles, errors));
}
}
function _parseTimeExpression(
exp: string | number, errors: AnimationParseError[]): _AnimationTimings {
const regex = /^([\.\d]+)(m?s)(?:\s+([\.\d]+)(m?s))?(?:\s+([-a-z]+(?:\(.+?\))?))?/i;
let duration: number;
let delay: number = 0;
let easing: string = null;
if (typeof exp === 'string') {
const matches = exp.match(regex);
if (matches === null) {
errors.push(new AnimationParseError(`The provided timing value "${exp}" is invalid.`));
return new _AnimationTimings(0, 0, null);
}
let durationMatch = parseFloat(matches[1]);
const durationUnit = matches[2];
if (durationUnit == 's') {
durationMatch *= _ONE_SECOND;
}
duration = Math.floor(durationMatch);
const delayMatch = matches[3];
const delayUnit = matches[4];
if (isPresent(delayMatch)) {
let delayVal: number = parseFloat(delayMatch);
if (isPresent(delayUnit) && delayUnit == 's') {
delayVal *= _ONE_SECOND;
}
delay = Math.floor(delayVal);
}
const easingVal = matches[5];
if (!isBlank(easingVal)) {
easing = easingVal;
}
} else {
duration = <number>exp;
}
return new _AnimationTimings(duration, delay, easing);
}
function _createStartKeyframeFromEndKeyframe(
endKeyframe: AnimationKeyframeAst, startTime: number, duration: number,
collectedStyles: StylesCollection, errors: AnimationParseError[]): AnimationKeyframeAst {
const values: Styles = {};
const endTime = startTime + duration;
endKeyframe.styles.styles.forEach((styleData: Styles) => {
Object.keys(styleData).forEach(prop => {
const val = styleData[prop];
if (prop == 'offset') return;
const resultIndex = collectedStyles.indexOfAtOrBeforeTime(prop, startTime);
let resultEntry: any /** TODO #9100 */, nextEntry: any /** TODO #9100 */,
value: any /** TODO #9100 */;
if (isPresent(resultIndex)) {
resultEntry = collectedStyles.getByIndex(prop, resultIndex);
value = resultEntry.value;
nextEntry = collectedStyles.getByIndex(prop, resultIndex + 1);
} else {
// this is a flag that the runtime code uses to pass
// in a value either from the state declaration styles
// or using the AUTO_STYLE value (e.g. getComputedStyle)
value = ɵFILL_STYLE_FLAG;
}
if (isPresent(nextEntry) && !nextEntry.matches(endTime, val)) {
errors.push(new AnimationParseError(
`The animated CSS property "${prop}" unexpectedly changes between steps "${resultEntry.time}ms" and "${endTime}ms" at "${nextEntry.time}ms"`));
}
values[prop] = value;
});
});
return new AnimationKeyframeAst(_INITIAL_KEYFRAME, new AnimationStylesAst([values]));
}

View File

@ -1,59 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {isPresent} from '../facade/lang';
export class StylesCollectionEntry {
constructor(public time: number, public value: string|number) {}
matches(time: number, value: string|number): boolean {
return time == this.time && value == this.value;
}
}
export class StylesCollection {
styles: {[key: string]: StylesCollectionEntry[]} = {};
insertAtTime(property: string, time: number, value: string|number) {
const tuple = new StylesCollectionEntry(time, value);
let entries = this.styles[property];
if (!isPresent(entries)) {
entries = this.styles[property] = [];
}
// insert this at the right stop in the array
// this way we can keep it sorted
let insertionIndex = 0;
for (let i = entries.length - 1; i >= 0; i--) {
if (entries[i].time <= time) {
insertionIndex = i + 1;
break;
}
}
entries.splice(insertionIndex, 0, tuple);
}
getByIndex(property: string, index: number): StylesCollectionEntry {
const items = this.styles[property];
if (isPresent(items)) {
return index >= items.length ? null : items[index];
}
return null;
}
indexOfAtOrBeforeTime(property: string, time: number): number {
const entries = this.styles[property];
if (isPresent(entries)) {
for (let i = entries.length - 1; i >= 0; i--) {
if (entries[i].time <= time) return i;
}
}
return null;
}
}

View File

@ -6,11 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AnimationCompiler} from '../animation/animation_compiler';
import {AnimationParser} from '../animation/animation_parser';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileProviderMetadata, componentFactoryName, createHostComponentMeta, identifierName} from '../compile_metadata';
import {CompilerConfig} from '../config';
import {DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
import {ListWrapper} from '../facade/collection';
import {Identifiers, createIdentifier, createIdentifierToken} from '../identifiers';
import {CompileMetadataResolver} from '../metadata_resolver';
@ -31,17 +28,13 @@ import {serializeSummaries} from './summary_serializer';
import {ngfactoryFilePath, splitTypescriptSuffix, summaryFileName} from './util';
export class AotCompiler {
private _animationCompiler = new AnimationCompiler();
constructor(
private _config: CompilerConfig, private _host: AotCompilerHost,
private _metadataResolver: CompileMetadataResolver, private _templateParser: TemplateParser,
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
private _dirWrapperCompiler: DirectiveWrapperCompiler,
private _ngModuleCompiler: NgModuleCompiler, private _outputEmitter: OutputEmitter,
private _summaryResolver: SummaryResolver<StaticSymbol>, private _localeId: string,
private _translationFormat: string, private _animationParser: AnimationParser,
private _symbolResolver: StaticSymbolResolver) {}
private _translationFormat: string, private _symbolResolver: StaticSymbolResolver) {}
clearCache() { this._metadataResolver.clearCache(); }
@ -78,12 +71,6 @@ export class AotCompiler {
exportedVars.push(
...ngModules.map((ngModuleType) => this._compileModule(ngModuleType, statements)));
// compile directive wrappers
if (!this._config.useViewEngine) {
exportedVars.push(...directives.map(
(directiveType) => this._compileDirectiveWrapper(directiveType, statements)));
}
// compile components
directives.forEach((dirType) => {
const compMeta = this._metadataResolver.getDirectiveMetadata(<any>dirType);
@ -165,15 +152,6 @@ export class AotCompiler {
return appCompileResult.ngModuleFactoryVar;
}
private _compileDirectiveWrapper(directiveType: StaticSymbol, targetStatements: o.Statement[]):
string {
const dirMeta = this._metadataResolver.getDirectiveMetadata(directiveType);
const dirCompileResult = this._dirWrapperCompiler.compile(dirMeta);
targetStatements.push(...dirCompileResult.statements);
return dirCompileResult.dirWrapperClassVar;
}
private _compileComponentFactory(
compMeta: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata, fileSuffix: string,
targetStatements: o.Statement[]): string {
@ -185,35 +163,18 @@ export class AotCompiler {
hostMeta, ngModule, [compMeta.type], null, fileSuffix, targetStatements)
.viewClassVar;
const compFactoryVar = componentFactoryName(compMeta.type.reference);
if (this._config.useViewEngine) {
targetStatements.push(
o.variable(compFactoryVar)
.set(o.importExpr(createIdentifier(Identifiers.createComponentFactory)).callFn([
o.literal(compMeta.selector),
o.importExpr(compMeta.type),
o.variable(hostViewFactoryVar),
]))
.toDeclStmt(
o.importType(
createIdentifier(Identifiers.ComponentFactory), [o.importType(compMeta.type)],
[o.TypeModifier.Const]),
[o.StmtModifier.Final]));
} else {
targetStatements.push(
o.variable(compFactoryVar)
.set(o.importExpr(createIdentifier(Identifiers.ComponentFactory), [o.importType(
compMeta.type)])
.instantiate(
[
o.literal(compMeta.selector),
o.variable(hostViewFactoryVar),
o.importExpr(compMeta.type),
],
o.importType(
createIdentifier(Identifiers.ComponentFactory),
[o.importType(compMeta.type)], [o.TypeModifier.Const])))
.toDeclStmt(null, [o.StmtModifier.Final]));
}
targetStatements.push(
o.variable(compFactoryVar)
.set(o.importExpr(createIdentifier(Identifiers.createComponentFactory)).callFn([
o.literal(compMeta.selector),
o.importExpr(compMeta.type),
o.variable(hostViewFactoryVar),
]))
.toDeclStmt(
o.importType(
createIdentifier(Identifiers.ComponentFactory), [o.importType(compMeta.type)],
[o.TypeModifier.Const]),
[o.StmtModifier.Final]));
return compFactoryVar;
}
@ -232,7 +193,7 @@ export class AotCompiler {
identifierName(compMeta.type));
const stylesExpr = componentStyles ? o.variable(componentStyles.stylesVar) : o.literalArr([]);
const viewResult =
this._viewCompiler.compileComponent(compMeta, parsedTemplate, stylesExpr, usedPipes, null);
this._viewCompiler.compileComponent(compMeta, parsedTemplate, stylesExpr, usedPipes);
if (componentStyles) {
targetStatements.push(
..._resolveStyleStatements(this._symbolResolver, componentStyles, fileSuffix));

View File

@ -7,11 +7,9 @@
*/
import {MissingTranslationStrategy, ViewEncapsulation, ɵConsole as Console} from '@angular/core';
import {AnimationParser} from '../animation/animation_parser';
import {CompilerConfig} from '../config';
import {DirectiveNormalizer} from '../directive_normalizer';
import {DirectiveResolver} from '../directive_resolver';
import {DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
import {Lexer} from '../expression_parser/lexer';
import {Parser} from '../expression_parser/parser';
import {I18NHtmlParser} from '../i18n/i18n_html_parser';
@ -26,7 +24,6 @@ import {StyleCompiler} from '../style_compiler';
import {TemplateParser} from '../template_parser/template_parser';
import {createOfflineCompileUrlResolver} from '../url_resolver';
import {ViewCompiler} from '../view_compiler/view_compiler';
import {ViewCompilerNext} from '../view_compiler_next/view_compiler';
import {AotCompiler} from './compiler';
import {AotCompilerHost} from './compiler_host';
@ -61,7 +58,6 @@ export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCom
defaultEncapsulation: ViewEncapsulation.Emulated,
logBindingUpdate: false,
useJit: false,
useViewEngine: options.useViewEngine,
enableLegacyTemplate: options.enableLegacyTemplate !== false,
});
const normalizer = new DirectiveNormalizer(
@ -81,13 +77,10 @@ export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCom
compilerHost.fileNameToModuleName(fileName, containingFilePath),
getTypeArity: (symbol: StaticSymbol) => symbolResolver.getTypeArity(symbol)
};
const viewCompiler = config.useViewEngine ? new ViewCompilerNext(config, elementSchemaRegistry) :
new ViewCompiler(config, elementSchemaRegistry);
const viewCompiler = new ViewCompiler(config, elementSchemaRegistry);
const compiler = new AotCompiler(
config, compilerHost, resolver, tmplParser, new StyleCompiler(urlResolver), viewCompiler,
new DirectiveWrapperCompiler(config, expressionParser, elementSchemaRegistry, console),
new NgModuleCompiler(), new TypeScriptEmitter(importResolver), summaryResolver,
options.locale, options.i18nFormat, new AnimationParser(elementSchemaRegistry),
symbolResolver);
options.locale, options.i18nFormat, symbolResolver);
return {compiler, reflector: staticReflector};
}

View File

@ -11,6 +11,5 @@ export interface AotCompilerOptions {
locale?: string;
i18nFormat?: string;
translations?: string;
useViewEngine?: boolean;
enableLegacyTemplate?: boolean;
}

View File

@ -313,7 +313,6 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
entryComponents: CompileEntryComponentMetadata[];
changeDetection: ChangeDetectionStrategy;
template: CompileTemplateSummary;
wrapperType: StaticSymbol|ProxyClass;
componentViewType: StaticSymbol|ProxyClass;
rendererType: StaticSymbol|RendererTypeV2;
componentFactory: StaticSymbol|ComponentFactory<any>;
@ -325,8 +324,8 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
export class CompileDirectiveMetadata {
static create(
{isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host,
providers, viewProviders, queries, viewQueries, entryComponents, template, wrapperType,
componentViewType, rendererType, componentFactory}: {
providers, viewProviders, queries, viewQueries, entryComponents, template, componentViewType,
rendererType, componentFactory}: {
isHost?: boolean,
type?: CompileTypeMetadata,
isComponent?: boolean,
@ -342,7 +341,6 @@ export class CompileDirectiveMetadata {
viewQueries?: CompileQueryMetadata[],
entryComponents?: CompileEntryComponentMetadata[],
template?: CompileTemplateMetadata,
wrapperType?: StaticSymbol|ProxyClass,
componentViewType?: StaticSymbol|ProxyClass,
rendererType?: StaticSymbol|RendererTypeV2,
componentFactory?: StaticSymbol|ComponentFactory<any>,
@ -397,7 +395,6 @@ export class CompileDirectiveMetadata {
viewQueries,
entryComponents,
template,
wrapperType,
componentViewType,
rendererType,
componentFactory,
@ -422,16 +419,14 @@ export class CompileDirectiveMetadata {
template: CompileTemplateMetadata;
wrapperType: StaticSymbol|ProxyClass;
componentViewType: StaticSymbol|ProxyClass;
rendererType: StaticSymbol|RendererTypeV2;
componentFactory: StaticSymbol|ComponentFactory<any>;
constructor({isHost, type, isComponent, selector, exportAs,
changeDetection, inputs, outputs, hostListeners, hostProperties,
hostAttributes, providers, viewProviders, queries, viewQueries,
entryComponents, template, wrapperType, componentViewType, rendererType,
componentFactory}: {
constructor({isHost, type, isComponent, selector, exportAs,
changeDetection, inputs, outputs, hostListeners, hostProperties,
hostAttributes, providers, viewProviders, queries, viewQueries,
entryComponents, template, componentViewType, rendererType, componentFactory}: {
isHost?: boolean,
type?: CompileTypeMetadata,
isComponent?: boolean,
@ -449,7 +444,6 @@ export class CompileDirectiveMetadata {
viewQueries?: CompileQueryMetadata[],
entryComponents?: CompileEntryComponentMetadata[],
template?: CompileTemplateMetadata,
wrapperType?: StaticSymbol|ProxyClass,
componentViewType?: StaticSymbol|ProxyClass,
rendererType?: StaticSymbol|RendererTypeV2,
componentFactory?: StaticSymbol|ComponentFactory<any>,
@ -472,7 +466,6 @@ export class CompileDirectiveMetadata {
this.entryComponents = _normalizeArray(entryComponents);
this.template = template;
this.wrapperType = wrapperType;
this.componentViewType = componentViewType;
this.rendererType = rendererType;
this.componentFactory = componentFactory;
@ -497,7 +490,6 @@ export class CompileDirectiveMetadata {
entryComponents: this.entryComponents,
changeDetection: this.changeDetection,
template: this.template && this.template.toSummary(),
wrapperType: this.wrapperType,
componentViewType: this.componentViewType,
rendererType: this.rendererType,
componentFactory: this.componentFactory

View File

@ -24,7 +24,7 @@
export {VERSION} from './version';
export * from './template_parser/template_ast';
export {TEMPLATE_TRANSFORMS} from './template_parser/template_parser';
export {CompilerConfig, RenderTypes} from './config';
export {CompilerConfig} from './config';
export * from './compile_metadata';
export * from './aot/compiler_factory';
export * from './aot/compiler';
@ -57,7 +57,6 @@ export * from './ml_parser/html_tags';
export * from './ml_parser/interpolation_config';
export * from './ml_parser/tags';
export {NgModuleCompiler} from './ng_module_compiler';
export {DirectiveWrapperCompiler} from './directive_wrapper_compiler';
export * from './output/path_util';
export * from './output/ts_emitter';
export * from './parse_util';
@ -66,6 +65,5 @@ export * from './selector';
export * from './style_compiler';
export * from './template_parser/template_parser';
export {ViewCompiler} from './view_compiler/view_compiler';
export {AnimationParser} from './animation/animation_parser';
export {isSyntaxError, syntaxError} from './util';
// This file only reexports content of the `src` folder. Keep it that way.

View File

@ -1,31 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {ClassBuilder} from '../output/class_builder';
import * as o from '../output/output_ast';
export class CheckBindingField {
constructor(public expression: o.ReadPropExpr, public bindingId: string) {}
}
export function createCheckBindingField(builder: ClassBuilder): CheckBindingField {
const bindingId = `${builder.fields.length}`;
const fieldExpr = createBindFieldExpr(bindingId);
// private is fine here as no child view will reference the cached value...
builder.fields.push(new o.ClassField(fieldExpr.name, null, [o.StmtModifier.Private]));
builder.ctorStmts.push(o.THIS_EXPR.prop(fieldExpr.name).set(o.literal(undefined)).toStmt());
return new CheckBindingField(fieldExpr, bindingId);
}
function createBindFieldExpr(bindingId: string): o.ReadPropExpr {
return o.THIS_EXPR.prop(`_expr_${bindingId}`);
}
export function isFirstViewCheck(view: o.Expression): o.Expression {
return o.not(view.prop('numberOfChecks'));
}

View File

@ -10,13 +10,8 @@
import * as cdAst from '../expression_parser/ast';
import {isBlank} from '../facade/lang';
import {Identifiers, createIdentifier} from '../identifiers';
import {ClassBuilder} from '../output/class_builder';
import * as o from '../output/output_ast';
import {createPureProxy} from './identifier_util';
const VAL_UNWRAPPER_VAR = o.variable(`valUnwrapper`);
export class EventHandlerVars { static event = o.variable('$event'); }
export interface LocalResolver { getLocal(name: string): o.Expression; }
@ -116,73 +111,6 @@ export function convertPropertyBinding(
return new ConvertPropertyBindingResult(stmts, currValExpr);
}
export class LegacyConvertPropertyBindingResult implements ConvertPropertyBindingResult {
constructor(
public stmts: o.Statement[], public currValExpr: o.Expression,
public forceUpdate: o.Expression) {}
}
export interface LegacyNameResolver {
callPipe(name: string, input: o.Expression, args: o.Expression[]): o.Expression;
getLocal(name: string): o.Expression;
}
/**
* Converts the given expression AST into an executable output AST, assuming the expression is
* used in a property binding.
*/
export function legacyConvertPropertyBinding(
builder: ClassBuilder, nameResolver: LegacyNameResolver, implicitReceiver: o.Expression,
expression: cdAst.AST, bindingId: string): LegacyConvertPropertyBindingResult {
if (!nameResolver) {
nameResolver = new LegacyDefaultNameResolver();
}
let needsValueUnwrapper = false;
const expressionWithoutBuiltins = convertBuiltins(
{
createLiteralArrayConverter: (argCount: number) => {
return (args: o.Expression[]) => legacyCreateCachedLiteralArray(builder, args);
},
createLiteralMapConverter: (keys: string[]) => {
return (args: o.Expression[]) => legacyCreateCachedLiteralMap(
builder, <[string, o.Expression][]>keys.map((key, i) => [key, args[i]]));
},
createPipeConverter: (name: string) => {
needsValueUnwrapper = true;
return (args: o.Expression[]) => VAL_UNWRAPPER_VAR.callMethod(
'unwrap', [nameResolver.callPipe(name, args[0], args.slice(1))]);
}
},
expression);
const {stmts, currValExpr} =
convertPropertyBinding(nameResolver, implicitReceiver, expressionWithoutBuiltins, bindingId);
let forceUpdate: o.Expression = null;
if (needsValueUnwrapper) {
const initValueUnwrapperStmt = VAL_UNWRAPPER_VAR.callMethod('reset', []).toStmt();
stmts.unshift(initValueUnwrapperStmt);
forceUpdate = VAL_UNWRAPPER_VAR.prop('hasWrappedValue');
}
return new LegacyConvertPropertyBindingResult(stmts, currValExpr, forceUpdate);
}
/**
* Creates variables that are shared by multiple calls to `convertActionBinding` /
* `convertPropertyBinding`
*/
export function legacyCreateSharedBindingVariablesIfNeeded(stmts: o.Statement[]): o.Statement[] {
const unwrapperStmts: o.Statement[] = [];
const readVars = o.findReadVarNames(stmts);
if (readVars.has(VAL_UNWRAPPER_VAR.name)) {
unwrapperStmts.push(
VAL_UNWRAPPER_VAR
.set(o.importExpr(createIdentifier(Identifiers.ValueUnwrapper)).instantiate([]))
.toDeclStmt(null, [o.StmtModifier.Final]));
}
return unwrapperStmts;
}
function convertBuiltins(converterFactory: BuiltinConverterFactory, ast: cdAst.AST): cdAst.AST {
const visitor = new _BuiltinAstConverter(converterFactory);
return ast.visit(visitor);
@ -649,50 +577,6 @@ function flattenStatements(arg: any, output: o.Statement[]) {
}
}
function legacyCreateCachedLiteralArray(
builder: ClassBuilder, values: o.Expression[]): o.Expression {
if (values.length === 0) {
return o.importExpr(createIdentifier(Identifiers.EMPTY_ARRAY));
}
const proxyExpr = o.THIS_EXPR.prop(`_arr_${builder.fields.length}`);
const proxyParams: o.FnParam[] = [];
const proxyReturnEntries: o.Expression[] = [];
for (let i = 0; i < values.length; i++) {
const paramName = `p${i}`;
proxyParams.push(new o.FnParam(paramName));
proxyReturnEntries.push(o.variable(paramName));
}
createPureProxy(
o.fn(
proxyParams, [new o.ReturnStatement(o.literalArr(proxyReturnEntries))],
new o.ArrayType(o.DYNAMIC_TYPE)),
values.length, proxyExpr, builder);
return proxyExpr.callFn(values);
}
function legacyCreateCachedLiteralMap(
builder: ClassBuilder, entries: [string, o.Expression][]): o.Expression {
if (entries.length === 0) {
return o.importExpr(createIdentifier(Identifiers.EMPTY_MAP));
}
const proxyExpr = o.THIS_EXPR.prop(`_map_${builder.fields.length}`);
const proxyParams: o.FnParam[] = [];
const proxyReturnEntries: [string, o.Expression][] = [];
const values: o.Expression[] = [];
for (let i = 0; i < entries.length; i++) {
const paramName = `p${i}`;
proxyParams.push(new o.FnParam(paramName));
proxyReturnEntries.push([entries[i][0], o.variable(paramName)]);
values.push(<o.Expression>entries[i][1]);
}
createPureProxy(
o.fn(
proxyParams, [new o.ReturnStatement(o.literalMap(proxyReturnEntries))],
new o.MapType(o.DYNAMIC_TYPE)),
entries.length, proxyExpr, builder);
return proxyExpr.callFn(values);
}
class DefaultLocalResolver implements LocalResolver {
getLocal(name: string): o.Expression {
if (name === EventHandlerVars.event.name) {
@ -702,16 +586,6 @@ class DefaultLocalResolver implements LocalResolver {
}
}
class LegacyDefaultNameResolver implements LegacyNameResolver {
callPipe(name: string, input: o.Expression, args: o.Expression[]): o.Expression { return null; }
getLocal(name: string): o.Expression {
if (name === EventHandlerVars.event.name) {
return EventHandlerVars.event;
}
return null;
}
}
function createCurrValueExpr(bindingId: string): o.ReadVarExpr {
return o.variable(`currVal_${bindingId}`); // fix syntax highlighting: `
}

View File

@ -1,57 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {CompileTokenMetadata} from '../compile_metadata';
import {isPresent} from '../facade/lang';
import {IdentifierSpec, Identifiers, createEnumIdentifier, createIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
export function createDiTokenExpression(token: CompileTokenMetadata): o.Expression {
if (isPresent(token.value)) {
return o.literal(token.value);
} else {
return o.importExpr(token.identifier);
}
}
export function createInlineArray(values: o.Expression[]): o.Expression {
if (values.length === 0) {
return o.importExpr(createIdentifier(Identifiers.EMPTY_INLINE_ARRAY));
}
const log2 = Math.log(values.length) / Math.log(2);
const index = Math.ceil(log2);
const identifierSpec = index < Identifiers.inlineArrays.length ? Identifiers.inlineArrays[index] :
Identifiers.InlineArrayDynamic;
const identifier = createIdentifier(identifierSpec);
return o.importExpr(identifier).instantiate([
<o.Expression>o.literal(values.length)
].concat(values));
}
export function createPureProxy(
fn: o.Expression, argCount: number, pureProxyProp: o.ReadPropExpr,
builder: {fields: o.ClassField[], ctorStmts: {push: (stmt: o.Statement) => void}}) {
builder.fields.push(new o.ClassField(pureProxyProp.name, null));
const pureProxyId =
argCount < Identifiers.pureProxies.length ? Identifiers.pureProxies[argCount] : null;
if (!pureProxyId) {
throw new Error(`Unsupported number of argument for pure functions: ${argCount}`);
}
builder.ctorStmts.push(o.THIS_EXPR.prop(pureProxyProp.name)
.set(o.importExpr(createIdentifier(pureProxyId)).callFn([fn]))
.toStmt());
}
export function createEnumExpression(enumType: IdentifierSpec, enumValue: any): o.Expression {
const enumName =
Object.keys(enumType.runtime).find((propName) => enumType.runtime[propName] === enumValue);
if (!enumName) {
throw new Error(`Unknown enum value ${enumValue} in ${enumType.name}`);
}
return o.importExpr(createEnumIdentifier(enumType, enumName));
}

View File

@ -1,153 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {SecurityContext, ɵEMPTY_STATE as EMPTY_ANIMATION_STATE} from '@angular/core';
import {Identifiers, createIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {BoundElementPropertyAst, BoundEventAst, PropertyBindingType} from '../template_parser/template_ast';
import {isFirstViewCheck} from './binding_util';
import {LegacyConvertPropertyBindingResult} from './expression_converter';
import {createEnumExpression} from './identifier_util';
export function createCheckRenderBindingStmt(
view: o.Expression, renderElement: o.Expression, boundProp: BoundElementPropertyAst,
oldValue: o.ReadPropExpr, evalResult: LegacyConvertPropertyBindingResult,
securityContextExpression?: o.Expression): o.Statement[] {
const checkStmts: o.Statement[] = [...evalResult.stmts];
const securityContext = calcSecurityContext(boundProp, securityContextExpression);
switch (boundProp.type) {
case PropertyBindingType.Property:
checkStmts.push(o.importExpr(createIdentifier(Identifiers.checkRenderProperty))
.callFn([
view, renderElement, o.literal(boundProp.name), oldValue,
oldValue.set(evalResult.currValExpr),
evalResult.forceUpdate || o.literal(false), securityContext
])
.toStmt());
break;
case PropertyBindingType.Attribute:
checkStmts.push(o.importExpr(createIdentifier(Identifiers.checkRenderAttribute))
.callFn([
view, renderElement, o.literal(boundProp.name), oldValue,
oldValue.set(evalResult.currValExpr),
evalResult.forceUpdate || o.literal(false), securityContext
])
.toStmt());
break;
case PropertyBindingType.Class:
checkStmts.push(
o.importExpr(createIdentifier(Identifiers.checkRenderClass))
.callFn([
view, renderElement, o.literal(boundProp.name), oldValue,
oldValue.set(evalResult.currValExpr), evalResult.forceUpdate || o.literal(false)
])
.toStmt());
break;
case PropertyBindingType.Style:
checkStmts.push(
o.importExpr(createIdentifier(Identifiers.checkRenderStyle))
.callFn([
view, renderElement, o.literal(boundProp.name), o.literal(boundProp.unit), oldValue,
oldValue.set(evalResult.currValExpr), evalResult.forceUpdate || o.literal(false),
securityContext
])
.toStmt());
break;
case PropertyBindingType.Animation:
throw new Error('Illegal state: Should not come here!');
}
return checkStmts;
}
function calcSecurityContext(
boundProp: BoundElementPropertyAst, securityContextExpression?: o.Expression): o.Expression {
if (boundProp.securityContext === SecurityContext.NONE) {
return o.NULL_EXPR; // No sanitization needed.
}
if (!boundProp.needsRuntimeSecurityContext) {
securityContextExpression =
createEnumExpression(Identifiers.SecurityContext, boundProp.securityContext);
}
if (!securityContextExpression) {
throw new Error(`internal error, no SecurityContext given ${boundProp.name}`);
}
return securityContextExpression;
}
export function createCheckAnimationBindingStmts(
view: o.Expression, componentView: o.Expression, boundProp: BoundElementPropertyAst,
boundOutputs: BoundEventAst[], eventListener: o.Expression, renderElement: o.Expression,
oldValue: o.ReadPropExpr, evalResult: LegacyConvertPropertyBindingResult) {
const detachStmts: o.Statement[] = [];
const updateStmts: o.Statement[] = [];
const animationName = boundProp.name;
const animationFnExpr =
componentView.prop('componentType').prop('animations').key(o.literal(animationName));
// it's important to normalize the void value as `void` explicitly
// so that the styles data can be obtained from the stringmap
const emptyStateValue = o.literal(EMPTY_ANIMATION_STATE);
const animationTransitionVar = o.variable('animationTransition_' + animationName);
updateStmts.push(
animationTransitionVar
.set(animationFnExpr.callFn([
view, renderElement, isFirstViewCheck(view).conditional(emptyStateValue, oldValue),
evalResult.currValExpr
]))
.toDeclStmt());
updateStmts.push(oldValue.set(evalResult.currValExpr).toStmt());
detachStmts.push(animationTransitionVar
.set(animationFnExpr.callFn(
[view, renderElement, evalResult.currValExpr, emptyStateValue]))
.toDeclStmt());
const registerStmts: o.Statement[] = [];
const animationStartMethodExists = boundOutputs.find(
event => event.isAnimation && event.name == animationName && event.phase == 'start');
if (animationStartMethodExists) {
registerStmts.push(
animationTransitionVar
.callMethod(
'onStart',
[eventListener.callMethod(
o.BuiltinMethod.Bind,
[view, o.literal(BoundEventAst.calcFullName(animationName, null, 'start'))])])
.toStmt());
}
const animationDoneMethodExists = boundOutputs.find(
event => event.isAnimation && event.name == animationName && event.phase == 'done');
if (animationDoneMethodExists) {
registerStmts.push(
animationTransitionVar
.callMethod(
'onDone',
[eventListener.callMethod(
o.BuiltinMethod.Bind,
[view, o.literal(BoundEventAst.calcFullName(animationName, null, 'done'))])])
.toStmt());
}
updateStmts.push(...registerStmts);
detachStmts.push(...registerStmts);
const checkUpdateStmts: o.Statement[] = [
...evalResult.stmts,
new o.IfStmt(
o.importExpr(createIdentifier(Identifiers.checkBinding)).callFn([
view, oldValue, evalResult.currValExpr, evalResult.forceUpdate || o.literal(false)
]),
updateStmts)
];
const checkDetachStmts: o.Statement[] = [...evalResult.stmts, ...detachStmts];
return {checkUpdateStmts, checkDetachStmts};
}

View File

@ -12,47 +12,32 @@ import {CompileIdentifierMetadata} from './compile_metadata';
import {Identifiers, createIdentifier} from './identifiers';
/**
* Temporal switch for the compiler to use the new view engine,
* until it is fully integrated.
*
* Only works in Jit for now.
*/
export const USE_VIEW_ENGINE = new InjectionToken<boolean>('UseViewEngine');
export class CompilerConfig {
public renderTypes: RenderTypes;
public defaultEncapsulation: ViewEncapsulation;
// Whether to support the `<template>` tag and the `template` attribute to define angular
// templates. They have been deprecated in 4.x, `<ng-template>` should be used instead.
public enableLegacyTemplate: boolean;
public useJit: boolean;
public useViewEngine: boolean;
public missingTranslation: MissingTranslationStrategy;
private _genDebugInfo: boolean;
private _logBindingUpdate: boolean;
constructor(
{renderTypes = new DefaultRenderTypes(), defaultEncapsulation = ViewEncapsulation.Emulated,
genDebugInfo, logBindingUpdate, useJit = true, missingTranslation, useViewEngine,
enableLegacyTemplate}: {
renderTypes?: RenderTypes,
{defaultEncapsulation = ViewEncapsulation.Emulated, genDebugInfo, logBindingUpdate,
useJit = true, missingTranslation, enableLegacyTemplate}: {
defaultEncapsulation?: ViewEncapsulation,
genDebugInfo?: boolean,
logBindingUpdate?: boolean,
useJit?: boolean,
missingTranslation?: MissingTranslationStrategy,
useViewEngine?: boolean,
enableLegacyTemplate?: boolean,
} = {}) {
this.renderTypes = renderTypes;
this.defaultEncapsulation = defaultEncapsulation;
this._genDebugInfo = genDebugInfo;
this._logBindingUpdate = logBindingUpdate;
this.useJit = useJit;
this.missingTranslation = missingTranslation;
this.useViewEngine = true;
this.enableLegacyTemplate = enableLegacyTemplate !== false;
}
@ -63,26 +48,3 @@ export class CompilerConfig {
return this._logBindingUpdate === void 0 ? isDevMode() : this._logBindingUpdate;
}
}
/**
* Types used for the renderer.
* Can be replaced to specialize the generated output to a specific renderer
* to help tree shaking.
*/
export abstract class RenderTypes {
abstract get renderer(): CompileIdentifierMetadata;
abstract get renderText(): CompileIdentifierMetadata;
abstract get renderElement(): CompileIdentifierMetadata;
abstract get renderComment(): CompileIdentifierMetadata;
abstract get renderNode(): CompileIdentifierMetadata;
abstract get renderEvent(): CompileIdentifierMetadata;
}
export class DefaultRenderTypes implements RenderTypes {
get renderer() { return createIdentifier(Identifiers.Renderer); };
renderText: any = null;
renderElement: any = null;
renderComment: any = null;
renderNode: any = null;
renderEvent: any = null;
}

View File

@ -1,461 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {ɵConsole as Console, ɵLifecycleHooks as LifecycleHooks} from '@angular/core';
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, dirWrapperClassName, identifierModuleUrl, identifierName} from './compile_metadata';
import {createCheckBindingField, isFirstViewCheck} from './compiler_util/binding_util';
import {EventHandlerVars, convertActionBinding, legacyConvertPropertyBinding} from './compiler_util/expression_converter';
import {createCheckAnimationBindingStmts, createCheckRenderBindingStmt} from './compiler_util/render_util';
import {CompilerConfig} from './config';
import {Parser} from './expression_parser/parser';
import {Identifiers, createIdentifier} from './identifiers';
import {CompilerInjectable} from './injectable';
import {DEFAULT_INTERPOLATION_CONFIG} from './ml_parser/interpolation_config';
import {ClassBuilder, createClassStmt} from './output/class_builder';
import * as o from './output/output_ast';
import {ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan} from './parse_util';
import {ElementSchemaRegistry} from './schema/element_schema_registry';
import {BindingParser} from './template_parser/binding_parser';
import {BoundElementPropertyAst, BoundEventAst} from './template_parser/template_ast';
export class DirectiveWrapperCompileResult {
constructor(public statements: o.Statement[], public dirWrapperClassVar: string) {}
}
const CONTEXT_FIELD_NAME = 'context';
const CHANGES_FIELD_NAME = '_changes';
const CHANGED_FIELD_NAME = '_changed';
const EVENT_HANDLER_FIELD_NAME = '_eventHandler';
const CHANGE_VAR = o.variable('change');
const CURR_VALUE_VAR = o.variable('currValue');
const FORCE_UPDATE_VAR = o.variable('forceUpdate');
const VIEW_VAR = o.variable('view');
const COMPONENT_VIEW_VAR = o.variable('componentView');
const RENDER_EL_VAR = o.variable('el');
const EVENT_NAME_VAR = o.variable('eventName');
const RESET_CHANGES_STMT = o.THIS_EXPR.prop(CHANGES_FIELD_NAME).set(o.literalMap([])).toStmt();
/**
* We generate directive wrappers to prevent code bloat when a directive is used.
* A directive wrapper encapsulates
* the dirty checking for `@Input`, the handling of `@HostListener` / `@HostBinding`
* and calling the lifecyclehooks `ngOnInit`, `ngOnChanges`, `ngDoCheck`.
*
* So far, only `@Input` and the lifecycle hooks have been implemented.
*/
@CompilerInjectable()
export class DirectiveWrapperCompiler {
constructor(
private compilerConfig: CompilerConfig, private _exprParser: Parser,
private _schemaRegistry: ElementSchemaRegistry, private _console: Console) {}
compile(dirMeta: CompileDirectiveMetadata): DirectiveWrapperCompileResult {
const hostParseResult = parseHostBindings(dirMeta, this._exprParser, this._schemaRegistry);
reportParseErrors(hostParseResult.errors, this._console);
const builder = new DirectiveWrapperBuilder(this.compilerConfig, dirMeta);
Object.keys(dirMeta.inputs).forEach((inputFieldName) => {
addCheckInputMethod(inputFieldName, builder);
});
addNgDoCheckMethod(builder);
addCheckHostMethod(hostParseResult.hostProps, hostParseResult.hostListeners, builder);
addHandleEventMethod(hostParseResult.hostListeners, builder);
addSubscribeMethod(dirMeta, builder);
const classStmt = builder.build();
return new DirectiveWrapperCompileResult([classStmt], classStmt.name);
}
}
class DirectiveWrapperBuilder implements ClassBuilder {
fields: o.ClassField[] = [];
getters: o.ClassGetter[] = [];
methods: o.ClassMethod[] = [];
ctorStmts: o.Statement[] = [];
detachStmts: o.Statement[] = [];
destroyStmts: o.Statement[] = [];
genChanges: boolean;
ngOnChanges: boolean;
ngOnInit: boolean;
ngDoCheck: boolean;
ngOnDestroy: boolean;
constructor(public compilerConfig: CompilerConfig, public dirMeta: CompileDirectiveMetadata) {
const dirLifecycleHooks = dirMeta.type.lifecycleHooks;
this.genChanges = dirLifecycleHooks.indexOf(LifecycleHooks.OnChanges) !== -1 ||
this.compilerConfig.logBindingUpdate;
this.ngOnChanges = dirLifecycleHooks.indexOf(LifecycleHooks.OnChanges) !== -1;
this.ngOnInit = dirLifecycleHooks.indexOf(LifecycleHooks.OnInit) !== -1;
this.ngDoCheck = dirLifecycleHooks.indexOf(LifecycleHooks.DoCheck) !== -1;
this.ngOnDestroy = dirLifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1;
if (this.ngOnDestroy) {
this.destroyStmts.push(
o.THIS_EXPR.prop(CONTEXT_FIELD_NAME).callMethod('ngOnDestroy', []).toStmt());
}
}
build(): o.ClassStmt {
const dirDepParamNames: string[] = [];
for (let i = 0; i < this.dirMeta.type.diDeps.length; i++) {
dirDepParamNames.push(`p${i}`);
}
const methods = [
new o.ClassMethod(
'ngOnDetach',
[
new o.FnParam(
VIEW_VAR.name,
o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
new o.FnParam(
COMPONENT_VIEW_VAR.name,
o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
new o.FnParam(RENDER_EL_VAR.name, o.DYNAMIC_TYPE),
],
this.detachStmts),
new o.ClassMethod('ngOnDestroy', [], this.destroyStmts),
];
const fields: o.ClassField[] = [
new o.ClassField(EVENT_HANDLER_FIELD_NAME, o.FUNCTION_TYPE, [o.StmtModifier.Private]),
new o.ClassField(CONTEXT_FIELD_NAME, o.importType(this.dirMeta.type)),
new o.ClassField(CHANGED_FIELD_NAME, o.BOOL_TYPE, [o.StmtModifier.Private]),
];
const ctorStmts: o.Statement[] = [
o.THIS_EXPR.prop(CHANGED_FIELD_NAME).set(o.literal(false)).toStmt(),
];
if (this.genChanges) {
fields.push(new o.ClassField(
CHANGES_FIELD_NAME, new o.MapType(o.DYNAMIC_TYPE), [o.StmtModifier.Private]));
ctorStmts.push(RESET_CHANGES_STMT);
}
ctorStmts.push(
o.THIS_EXPR.prop(CONTEXT_FIELD_NAME)
.set(o.importExpr(this.dirMeta.type)
.instantiate(dirDepParamNames.map((paramName) => o.variable(paramName))))
.toStmt());
return createClassStmt({
name: dirWrapperClassName(this.dirMeta.type.reference),
ctorParams: dirDepParamNames.map((paramName) => new o.FnParam(paramName, o.DYNAMIC_TYPE)),
builders: [{fields, ctorStmts, methods}, this]
});
}
}
function addNgDoCheckMethod(builder: DirectiveWrapperBuilder) {
const changedVar = o.variable('changed');
const stmts: o.Statement[] = [
changedVar.set(o.THIS_EXPR.prop(CHANGED_FIELD_NAME)).toDeclStmt(),
o.THIS_EXPR.prop(CHANGED_FIELD_NAME).set(o.literal(false)).toStmt(),
];
const lifecycleStmts: o.Statement[] = [];
if (builder.genChanges) {
const onChangesStmts: o.Statement[] = [];
if (builder.ngOnChanges) {
onChangesStmts.push(o.THIS_EXPR.prop(CONTEXT_FIELD_NAME)
.callMethod('ngOnChanges', [o.THIS_EXPR.prop(CHANGES_FIELD_NAME)])
.toStmt());
}
if (builder.compilerConfig.logBindingUpdate) {
onChangesStmts.push(
o.importExpr(createIdentifier(Identifiers.setBindingDebugInfoForChanges))
.callFn(
[VIEW_VAR.prop('renderer'), RENDER_EL_VAR, o.THIS_EXPR.prop(CHANGES_FIELD_NAME)])
.toStmt());
}
onChangesStmts.push(RESET_CHANGES_STMT);
lifecycleStmts.push(new o.IfStmt(changedVar, onChangesStmts));
}
if (builder.ngOnInit) {
lifecycleStmts.push(new o.IfStmt(
isFirstViewCheck(VIEW_VAR),
[o.THIS_EXPR.prop(CONTEXT_FIELD_NAME).callMethod('ngOnInit', []).toStmt()]));
}
if (builder.ngDoCheck) {
lifecycleStmts.push(o.THIS_EXPR.prop(CONTEXT_FIELD_NAME).callMethod('ngDoCheck', []).toStmt());
}
if (lifecycleStmts.length > 0) {
stmts.push(new o.IfStmt(o.not(VIEW_VAR.prop('throwOnChange')), lifecycleStmts));
}
stmts.push(new o.ReturnStatement(changedVar));
builder.methods.push(new o.ClassMethod(
'ngDoCheck',
[
new o.FnParam(
VIEW_VAR.name, o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
new o.FnParam(RENDER_EL_VAR.name, o.DYNAMIC_TYPE),
],
stmts, o.BOOL_TYPE));
}
function addCheckInputMethod(input: string, builder: DirectiveWrapperBuilder) {
const field = createCheckBindingField(builder);
const onChangeStatements: o.Statement[] = [
o.THIS_EXPR.prop(CHANGED_FIELD_NAME).set(o.literal(true)).toStmt(),
o.THIS_EXPR.prop(CONTEXT_FIELD_NAME).prop(input).set(CURR_VALUE_VAR).toStmt(),
field.expression.set(CURR_VALUE_VAR).toStmt()
];
let methodBody: o.Statement[];
if (builder.genChanges) {
onChangeStatements.push(
o.THIS_EXPR.prop(CHANGES_FIELD_NAME).key(o.literal(input)).set(CHANGE_VAR).toStmt());
methodBody = [
CHANGE_VAR
.set(o.importExpr(createIdentifier(Identifiers.checkBindingChange)).callFn([
VIEW_VAR, field.expression, CURR_VALUE_VAR, FORCE_UPDATE_VAR
]))
.toDeclStmt(),
new o.IfStmt(CHANGE_VAR, onChangeStatements)
];
} else {
methodBody = [new o.IfStmt(
o.importExpr(createIdentifier(Identifiers.checkBinding)).callFn([
VIEW_VAR, field.expression, CURR_VALUE_VAR, FORCE_UPDATE_VAR
]),
onChangeStatements)];
}
builder.methods.push(new o.ClassMethod(
`check_${input}`,
[
new o.FnParam(
VIEW_VAR.name, o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
new o.FnParam(CURR_VALUE_VAR.name, o.DYNAMIC_TYPE),
new o.FnParam(FORCE_UPDATE_VAR.name, o.BOOL_TYPE)
],
methodBody));
}
function addCheckHostMethod(
hostProps: BoundElementPropertyAst[], hostEvents: BoundEventAst[],
builder: DirectiveWrapperBuilder) {
const stmts: o.Statement[] = [];
const methodParams: o.FnParam[] = [
new o.FnParam(
VIEW_VAR.name, o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
new o.FnParam(
COMPONENT_VIEW_VAR.name,
o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
new o.FnParam(RENDER_EL_VAR.name, o.DYNAMIC_TYPE),
];
hostProps.forEach((hostProp, hostPropIdx) => {
const field = createCheckBindingField(builder);
const evalResult = legacyConvertPropertyBinding(
builder, null, o.THIS_EXPR.prop(CONTEXT_FIELD_NAME), hostProp.value, field.bindingId);
if (!evalResult) {
return;
}
let securityContextExpr: o.ReadVarExpr;
if (hostProp.needsRuntimeSecurityContext) {
securityContextExpr = o.variable(`secCtx_${methodParams.length}`);
methodParams.push(new o.FnParam(
securityContextExpr.name, o.importType(createIdentifier(Identifiers.SecurityContext))));
}
if (hostProp.isAnimation) {
const {checkUpdateStmts, checkDetachStmts} = createCheckAnimationBindingStmts(
VIEW_VAR, COMPONENT_VIEW_VAR, hostProp, hostEvents,
o.THIS_EXPR.prop(EVENT_HANDLER_FIELD_NAME)
.or(o.importExpr(createIdentifier(Identifiers.noop))),
RENDER_EL_VAR, field.expression, evalResult);
builder.detachStmts.push(...checkDetachStmts);
stmts.push(...checkUpdateStmts);
} else {
stmts.push(...createCheckRenderBindingStmt(
VIEW_VAR, RENDER_EL_VAR, hostProp, field.expression, evalResult, securityContextExpr));
}
});
builder.methods.push(new o.ClassMethod('checkHost', methodParams, stmts));
}
function addHandleEventMethod(hostListeners: BoundEventAst[], builder: DirectiveWrapperBuilder) {
const resultVar = o.variable(`result`);
const actionStmts: o.Statement[] = [resultVar.set(o.literal(true)).toDeclStmt(o.BOOL_TYPE)];
hostListeners.forEach((hostListener, eventIdx) => {
const evalResult = convertActionBinding(
null, o.THIS_EXPR.prop(CONTEXT_FIELD_NAME), hostListener.handler, `sub_${eventIdx}`);
const trueStmts = evalResult.stmts;
if (evalResult.allowDefault) {
trueStmts.push(resultVar.set(evalResult.allowDefault.and(resultVar)).toStmt());
}
// TODO(tbosch): convert this into a `switch` once our OutputAst supports it.
actionStmts.push(
new o.IfStmt(EVENT_NAME_VAR.equals(o.literal(hostListener.fullName)), trueStmts));
});
actionStmts.push(new o.ReturnStatement(resultVar));
builder.methods.push(new o.ClassMethod(
'handleEvent',
[
new o.FnParam(EVENT_NAME_VAR.name, o.STRING_TYPE),
new o.FnParam(EventHandlerVars.event.name, o.DYNAMIC_TYPE)
],
actionStmts, o.BOOL_TYPE));
}
function addSubscribeMethod(dirMeta: CompileDirectiveMetadata, builder: DirectiveWrapperBuilder) {
const methodParams: o.FnParam[] = [
new o.FnParam(
VIEW_VAR.name, o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
new o.FnParam(EVENT_HANDLER_FIELD_NAME, o.DYNAMIC_TYPE)
];
const stmts: o.Statement[] = [
o.THIS_EXPR.prop(EVENT_HANDLER_FIELD_NAME).set(o.variable(EVENT_HANDLER_FIELD_NAME)).toStmt()
];
Object.keys(dirMeta.outputs).forEach((emitterPropName, emitterIdx) => {
const eventName = dirMeta.outputs[emitterPropName];
const paramName = `emit${emitterIdx}`;
methodParams.push(new o.FnParam(paramName, o.BOOL_TYPE));
const subscriptionFieldName = `subscription${emitterIdx}`;
builder.fields.push(new o.ClassField(subscriptionFieldName, o.DYNAMIC_TYPE));
stmts.push(new o.IfStmt(o.variable(paramName), [
o.THIS_EXPR.prop(subscriptionFieldName)
.set(o.THIS_EXPR.prop(CONTEXT_FIELD_NAME)
.prop(emitterPropName)
.callMethod(
o.BuiltinMethod.SubscribeObservable,
[o.variable(EVENT_HANDLER_FIELD_NAME)
.callMethod(o.BuiltinMethod.Bind, [VIEW_VAR, o.literal(eventName)])]))
.toStmt()
]));
builder.destroyStmts.push(
o.THIS_EXPR.prop(subscriptionFieldName)
.and(o.THIS_EXPR.prop(subscriptionFieldName).callMethod('unsubscribe', []))
.toStmt());
});
builder.methods.push(new o.ClassMethod('subscribe', methodParams, stmts));
}
class ParseResult {
constructor(
public hostProps: BoundElementPropertyAst[], public hostListeners: BoundEventAst[],
public errors: ParseError[]) {}
}
function parseHostBindings(
dirMeta: CompileDirectiveMetadata, exprParser: Parser,
schemaRegistry: ElementSchemaRegistry): ParseResult {
const errors: ParseError[] = [];
const parser =
new BindingParser(exprParser, DEFAULT_INTERPOLATION_CONFIG, schemaRegistry, [], errors);
const moduleUrl = identifierModuleUrl(dirMeta.type);
const sourceFileName = moduleUrl ?
`in Directive ${identifierName(dirMeta.type)} in ${moduleUrl}` :
`in Directive ${identifierName(dirMeta.type)}`;
const sourceFile = new ParseSourceFile('', sourceFileName);
const sourceSpan = new ParseSourceSpan(
new ParseLocation(sourceFile, null, null, null),
new ParseLocation(sourceFile, null, null, null));
const parsedHostProps =
parser.createDirectiveHostPropertyAsts(dirMeta.toSummary(), dirMeta.selector, sourceSpan);
const parsedHostListeners = parser.createDirectiveHostEventAsts(dirMeta.toSummary(), sourceSpan);
return new ParseResult(parsedHostProps, parsedHostListeners, errors);
}
function reportParseErrors(parseErrors: ParseError[], console: Console) {
const warnings = parseErrors.filter(error => error.level === ParseErrorLevel.WARNING);
const errors = parseErrors.filter(error => error.level === ParseErrorLevel.FATAL);
if (warnings.length > 0) {
this._console.warn(`Directive parse warnings:\n${warnings.join('\n')}`);
}
if (errors.length > 0) {
throw new Error(`Directive parse errors:\n${errors.join('\n')}`);
}
}
export class DirectiveWrapperExpressions {
static create(dir: CompileIdentifierMetadata, depsExpr: o.Expression[]): o.Expression {
return o.importExpr(dir).instantiate(depsExpr, o.importType(dir));
}
static context(dirWrapper: o.Expression): o.ReadPropExpr {
return dirWrapper.prop(CONTEXT_FIELD_NAME);
}
static ngDoCheck(dirWrapper: o.Expression, view: o.Expression, renderElement: o.Expression, ):
o.Expression {
return dirWrapper.callMethod('ngDoCheck', [view, renderElement]);
}
static checkHost(
hostProps: BoundElementPropertyAst[], dirWrapper: o.Expression, view: o.Expression,
componentView: o.Expression, renderElement: o.Expression,
runtimeSecurityContexts: o.Expression[]): o.Statement[] {
if (hostProps.length) {
return [dirWrapper
.callMethod(
'checkHost',
[view, componentView, renderElement].concat(runtimeSecurityContexts))
.toStmt()];
} else {
return [];
}
}
static ngOnDetach(
hostProps: BoundElementPropertyAst[], dirWrapper: o.Expression, view: o.Expression,
componentView: o.Expression, renderEl: o.Expression): o.Statement[] {
if (hostProps.some(prop => prop.isAnimation)) {
return [dirWrapper
.callMethod(
'ngOnDetach',
[
view,
componentView,
renderEl,
])
.toStmt()];
} else {
return [];
}
}
static ngOnDestroy(dir: CompileDirectiveSummary, dirWrapper: o.Expression): o.Statement[] {
if (dir.type.lifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1 ||
Object.keys(dir.outputs).length > 0) {
return [dirWrapper.callMethod('ngOnDestroy', []).toStmt()];
} else {
return [];
}
}
static subscribe(
dirMeta: CompileDirectiveSummary, hostProps: BoundElementPropertyAst[], usedEvents: string[],
dirWrapper: o.Expression, view: o.Expression, eventListener: o.Expression): o.Statement[] {
let needsSubscribe = false;
const eventFlags: o.Expression[] = [];
Object.keys(dirMeta.outputs).forEach((propName) => {
const eventName = dirMeta.outputs[propName];
const eventUsed = usedEvents.indexOf(eventName) > -1;
needsSubscribe = needsSubscribe || eventUsed;
eventFlags.push(o.literal(eventUsed));
});
hostProps.forEach((hostProp) => {
if (hostProp.isAnimation && usedEvents.length > 0) {
needsSubscribe = true;
}
});
if (needsSubscribe) {
return [
dirWrapper.callMethod('subscribe', [view, eventListener].concat(eventFlags)).toStmt()
];
} else {
return [];
}
}
static handleEvent(
hostEvents: BoundEventAst[], dirWrapper: o.Expression, eventName: o.Expression,
event: o.Expression): o.Expression {
return dirWrapper.callMethod('handleEvent', [eventName, event]);
}
}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ComponentRef, ElementRef, Injector, LOCALE_ID, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TRANSLATIONS_FORMAT, TemplateRef, ViewContainerRef, ViewEncapsulation, ɵAnimationGroupPlayer, ɵAnimationKeyframe, ɵAnimationSequencePlayer, ɵAnimationStyles, ɵAnimationTransition, ɵAppView, ɵChangeDetectorStatus, ɵCodegenComponentFactoryResolver, ɵComponentRef_, ɵDebugAppView, ɵDebugContext, ɵEMPTY_ARRAY, ɵEMPTY_INLINE_ARRAY, ɵEMPTY_MAP, ɵInlineArray16, ɵInlineArray2, ɵInlineArray4, ɵInlineArray8, ɵInlineArrayDynamic, ɵNgModuleInjector, ɵNoOpAnimationPlayer, ɵStaticNodeDebugInfo, ɵTemplateRef_, ɵValueUnwrapper, ɵViewContainer, ɵViewType, ɵViewUtils, ɵand, ɵbalanceAnimationKeyframes, ɵcastByValue, ɵccf, ɵcheckBinding, ɵcheckBindingChange, ɵcheckRenderAttribute, ɵcheckRenderClass, ɵcheckRenderProperty, ɵcheckRenderStyle, ɵcheckRenderText, ɵclearStyles, ɵcollectAndResolveStyles, ɵcreateRenderComponentType, ɵcreateRenderElement, ɵcrt, ɵdevModeEqual, ɵdid, ɵeld, ɵinlineInterpolate, ɵinterpolate, ɵncd, ɵnoop, ɵnov, ɵpad, ɵpid, ɵpod, ɵppd, ɵprd, ɵprepareFinalAnimationStyles, ɵpureProxy1, ɵpureProxy10, ɵpureProxy2, ɵpureProxy3, ɵpureProxy4, ɵpureProxy5, ɵpureProxy6, ɵpureProxy7, ɵpureProxy8, ɵpureProxy9, ɵqud, ɵreflector, ɵregisterModuleFactory, ɵrenderStyles, ɵselectOrCreateRenderHostElement, ɵsetBindingDebugInfo, ɵsetBindingDebugInfoForChanges, ɵsubscribeToRenderElement, ɵted, ɵunv, ɵvid} from '@angular/core';
import {ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ComponentRef, ElementRef, Injector, LOCALE_ID, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TRANSLATIONS_FORMAT, TemplateRef, ViewContainerRef, ViewEncapsulation, ɵChangeDetectorStatus, ɵCodegenComponentFactoryResolver, ɵEMPTY_ARRAY, ɵEMPTY_MAP, ɵNgModuleInjector, ɵValueUnwrapper, ɵand, ɵccf, ɵcrt, ɵdevModeEqual, ɵdid, ɵeld, ɵinlineInterpolate, ɵinterpolate, ɵncd, ɵnov, ɵpad, ɵpid, ɵpod, ɵppd, ɵprd, ɵqud, ɵreflector, ɵregisterModuleFactory, ɵted, ɵunv, ɵvid} from '@angular/core';
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
@ -25,23 +25,13 @@ export class Identifiers {
moduleUrl: CORE,
runtime: ANALYZE_FOR_ENTRY_COMPONENTS
};
static ViewUtils: IdentifierSpec = {name: 'ɵViewUtils', moduleUrl: CORE, runtime: ɵViewUtils};
static AppView: IdentifierSpec = {name: 'ɵAppView', moduleUrl: CORE, runtime: ɵAppView};
static DebugAppView:
IdentifierSpec = {name: 'ɵDebugAppView', moduleUrl: CORE, runtime: ɵDebugAppView};
static ViewContainer:
IdentifierSpec = {name: 'ɵViewContainer', moduleUrl: CORE, runtime: ɵViewContainer};
static ElementRef: IdentifierSpec = {name: 'ElementRef', moduleUrl: CORE, runtime: ElementRef};
static ViewContainerRef:
IdentifierSpec = {name: 'ViewContainerRef', moduleUrl: CORE, runtime: ViewContainerRef};
static ChangeDetectorRef:
IdentifierSpec = {name: 'ChangeDetectorRef', moduleUrl: CORE, runtime: ChangeDetectorRef};
static RenderComponentType:
IdentifierSpec = {name: 'RenderComponentType', moduleUrl: CORE, runtime: RenderComponentType};
static QueryList: IdentifierSpec = {name: 'QueryList', moduleUrl: CORE, runtime: QueryList};
static TemplateRef: IdentifierSpec = {name: 'TemplateRef', moduleUrl: CORE, runtime: TemplateRef};
static TemplateRef_:
IdentifierSpec = {name: 'ɵTemplateRef_', moduleUrl: CORE, runtime: ɵTemplateRef_};
static CodegenComponentFactoryResolver: IdentifierSpec = {
name: 'ɵCodegenComponentFactoryResolver',
moduleUrl: CORE,
@ -54,11 +44,6 @@ export class Identifiers {
};
static ComponentFactory:
IdentifierSpec = {name: 'ComponentFactory', moduleUrl: CORE, runtime: ComponentFactory};
static ComponentRef_: IdentifierSpec = {
name: 'ɵComponentRef_',
moduleUrl: CORE,
runtime: ɵComponentRef_,
};
static ComponentRef:
IdentifierSpec = {name: 'ComponentRef', moduleUrl: CORE, runtime: ComponentRef};
static NgModuleFactory:
@ -73,176 +58,31 @@ export class Identifiers {
moduleUrl: CORE,
runtime: ɵregisterModuleFactory,
};
static ValueUnwrapper:
IdentifierSpec = {name: 'ɵValueUnwrapper', moduleUrl: CORE, runtime: ɵValueUnwrapper};
static Injector: IdentifierSpec = {name: 'Injector', moduleUrl: CORE, runtime: Injector};
static ViewEncapsulation:
IdentifierSpec = {name: 'ViewEncapsulation', moduleUrl: CORE, runtime: ViewEncapsulation};
static ViewType: IdentifierSpec = {name: 'ɵViewType', moduleUrl: CORE, runtime: ɵViewType};
static ChangeDetectionStrategy: IdentifierSpec = {
name: 'ChangeDetectionStrategy',
moduleUrl: CORE,
runtime: ChangeDetectionStrategy
};
static StaticNodeDebugInfo: IdentifierSpec = {
name: 'ɵStaticNodeDebugInfo',
moduleUrl: CORE,
runtime: ɵStaticNodeDebugInfo
};
static DebugContext:
IdentifierSpec = {name: 'ɵDebugContext', moduleUrl: CORE, runtime: ɵDebugContext};
static Renderer: IdentifierSpec = {name: 'Renderer', moduleUrl: CORE, runtime: Renderer};
static SimpleChange:
IdentifierSpec = {name: 'SimpleChange', moduleUrl: CORE, runtime: SimpleChange};
static ChangeDetectorStatus: IdentifierSpec = {
name: 'ɵChangeDetectorStatus',
moduleUrl: CORE,
runtime: ɵChangeDetectorStatus
};
static checkBinding:
IdentifierSpec = {name: 'ɵcheckBinding', moduleUrl: CORE, runtime: ɵcheckBinding};
static checkBindingChange:
IdentifierSpec = {name: 'ɵcheckBindingChange', moduleUrl: CORE, runtime: ɵcheckBindingChange};
static checkRenderText:
IdentifierSpec = {name: 'ɵcheckRenderText', moduleUrl: CORE, runtime: ɵcheckRenderText};
static checkRenderProperty: IdentifierSpec = {
name: 'ɵcheckRenderProperty',
moduleUrl: CORE,
runtime: ɵcheckRenderProperty
};
static checkRenderAttribute: IdentifierSpec = {
name: 'ɵcheckRenderAttribute',
moduleUrl: CORE,
runtime: ɵcheckRenderAttribute
};
static checkRenderClass:
IdentifierSpec = {name: 'ɵcheckRenderClass', moduleUrl: CORE, runtime: ɵcheckRenderClass};
static checkRenderStyle:
IdentifierSpec = {name: 'ɵcheckRenderStyle', moduleUrl: CORE, runtime: ɵcheckRenderStyle};
static devModeEqual:
IdentifierSpec = {name: 'ɵdevModeEqual', moduleUrl: CORE, runtime: ɵdevModeEqual};
static inlineInterpolate:
IdentifierSpec = {name: 'ɵinlineInterpolate', moduleUrl: CORE, runtime: ɵinlineInterpolate};
static interpolate:
IdentifierSpec = {name: 'ɵinterpolate', moduleUrl: CORE, runtime: ɵinterpolate};
static castByValue:
IdentifierSpec = {name: 'ɵcastByValue', moduleUrl: CORE, runtime: ɵcastByValue};
static EMPTY_ARRAY:
IdentifierSpec = {name: 'ɵEMPTY_ARRAY', moduleUrl: CORE, runtime: ɵEMPTY_ARRAY};
static EMPTY_MAP: IdentifierSpec = {name: 'ɵEMPTY_MAP', moduleUrl: CORE, runtime: ɵEMPTY_MAP};
static createRenderElement: IdentifierSpec = {
name: 'ɵcreateRenderElement',
moduleUrl: CORE,
runtime: ɵcreateRenderElement
};
static selectOrCreateRenderHostElement: IdentifierSpec = {
name: 'ɵselectOrCreateRenderHostElement',
moduleUrl: CORE,
runtime: ɵselectOrCreateRenderHostElement
};
static pureProxies: IdentifierSpec[] = [
null,
{name: 'ɵpureProxy1', moduleUrl: CORE, runtime: ɵpureProxy1},
{name: 'ɵpureProxy2', moduleUrl: CORE, runtime: ɵpureProxy2},
{name: 'ɵpureProxy3', moduleUrl: CORE, runtime: ɵpureProxy3},
{name: 'ɵpureProxy4', moduleUrl: CORE, runtime: ɵpureProxy4},
{name: 'ɵpureProxy5', moduleUrl: CORE, runtime: ɵpureProxy5},
{name: 'ɵpureProxy6', moduleUrl: CORE, runtime: ɵpureProxy6},
{name: 'ɵpureProxy7', moduleUrl: CORE, runtime: ɵpureProxy7},
{name: 'ɵpureProxy8', moduleUrl: CORE, runtime: ɵpureProxy8},
{name: 'ɵpureProxy9', moduleUrl: CORE, runtime: ɵpureProxy9},
{name: 'ɵpureProxy10', moduleUrl: CORE, runtime: ɵpureProxy10},
];
static SecurityContext: IdentifierSpec = {
name: 'SecurityContext',
moduleUrl: CORE,
runtime: SecurityContext,
};
static AnimationKeyframe:
IdentifierSpec = {name: 'ɵAnimationKeyframe', moduleUrl: CORE, runtime: ɵAnimationKeyframe};
static AnimationStyles:
IdentifierSpec = {name: 'ɵAnimationStyles', moduleUrl: CORE, runtime: ɵAnimationStyles};
static NoOpAnimationPlayer: IdentifierSpec = {
name: 'ɵNoOpAnimationPlayer',
moduleUrl: CORE,
runtime: ɵNoOpAnimationPlayer
};
static AnimationGroupPlayer: IdentifierSpec = {
name: 'ɵAnimationGroupPlayer',
moduleUrl: CORE,
runtime: ɵAnimationGroupPlayer
};
static AnimationSequencePlayer: IdentifierSpec = {
name: 'ɵAnimationSequencePlayer',
moduleUrl: CORE,
runtime: ɵAnimationSequencePlayer
};
static prepareFinalAnimationStyles: IdentifierSpec = {
name: 'ɵprepareFinalAnimationStyles',
moduleUrl: CORE,
runtime: ɵprepareFinalAnimationStyles
};
static balanceAnimationKeyframes: IdentifierSpec = {
name: 'ɵbalanceAnimationKeyframes',
moduleUrl: CORE,
runtime: ɵbalanceAnimationKeyframes
};
static clearStyles:
IdentifierSpec = {name: 'ɵclearStyles', moduleUrl: CORE, runtime: ɵclearStyles};
static renderStyles:
IdentifierSpec = {name: 'ɵrenderStyles', moduleUrl: CORE, runtime: ɵrenderStyles};
static collectAndResolveStyles: IdentifierSpec = {
name: 'ɵcollectAndResolveStyles',
moduleUrl: CORE,
runtime: ɵcollectAndResolveStyles
};
static LOCALE_ID: IdentifierSpec = {name: 'LOCALE_ID', moduleUrl: CORE, runtime: LOCALE_ID};
static TRANSLATIONS_FORMAT:
IdentifierSpec = {name: 'TRANSLATIONS_FORMAT', moduleUrl: CORE, runtime: TRANSLATIONS_FORMAT};
static setBindingDebugInfo: IdentifierSpec = {
name: 'ɵsetBindingDebugInfo',
moduleUrl: CORE,
runtime: ɵsetBindingDebugInfo
};
static setBindingDebugInfoForChanges: IdentifierSpec = {
name: 'ɵsetBindingDebugInfoForChanges',
moduleUrl: CORE,
runtime: ɵsetBindingDebugInfoForChanges
};
static AnimationTransition: IdentifierSpec = {
name: 'ɵAnimationTransition',
moduleUrl: CORE,
runtime: ɵAnimationTransition
};
// This is just the interface!
static InlineArray:
IdentifierSpec = {name: 'InlineArray', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: null};
static inlineArrays: IdentifierSpec[] = [
{name: 'ɵInlineArray2', moduleUrl: CORE, runtime: ɵInlineArray2},
{name: 'ɵInlineArray2', moduleUrl: CORE, runtime: ɵInlineArray2},
{name: 'ɵInlineArray4', moduleUrl: CORE, runtime: ɵInlineArray4},
{name: 'ɵInlineArray8', moduleUrl: CORE, runtime: ɵInlineArray8},
{name: 'ɵInlineArray16', moduleUrl: CORE, runtime: ɵInlineArray16},
];
static EMPTY_INLINE_ARRAY:
IdentifierSpec = {name: 'ɵEMPTY_INLINE_ARRAY', moduleUrl: CORE, runtime: ɵEMPTY_INLINE_ARRAY};
static InlineArrayDynamic:
IdentifierSpec = {name: 'ɵInlineArrayDynamic', moduleUrl: CORE, runtime: ɵInlineArrayDynamic};
static subscribeToRenderElement: IdentifierSpec = {
name: 'ɵsubscribeToRenderElement',
moduleUrl: CORE,
runtime: ɵsubscribeToRenderElement
};
static createRenderComponentType: IdentifierSpec = {
name: 'ɵcreateRenderComponentType',
moduleUrl: CORE,
runtime: ɵcreateRenderComponentType
};
static noop: IdentifierSpec = {name: 'ɵnoop', moduleUrl: CORE, runtime: ɵnoop};
static inlineInterpolate:
IdentifierSpec = {name: 'ɵinlineInterpolate', moduleUrl: CORE, runtime: ɵinlineInterpolate};
static interpolate:
IdentifierSpec = {name: 'ɵinterpolate', moduleUrl: CORE, runtime: ɵinterpolate};
static EMPTY_ARRAY:
IdentifierSpec = {name: 'ɵEMPTY_ARRAY', moduleUrl: CORE, runtime: ɵEMPTY_ARRAY};
static EMPTY_MAP: IdentifierSpec = {name: 'ɵEMPTY_MAP', moduleUrl: CORE, runtime: ɵEMPTY_MAP};
static Renderer: IdentifierSpec = {name: 'Renderer', moduleUrl: CORE, runtime: Renderer};
static viewDef: IdentifierSpec = {name: 'ɵvid', moduleUrl: CORE, runtime: ɵvid};
static elementDef: IdentifierSpec = {name: 'ɵeld', moduleUrl: CORE, runtime: ɵeld};
static anchorDef: IdentifierSpec = {name: 'ɵand', moduleUrl: CORE, runtime: ɵand};

View File

@ -6,13 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Compiler, ComponentFactory, Inject, Injector, ModuleWithComponentFactories, NgModuleFactory, Type, ɵgetComponentFactoryViewClass as getComponentFactoryViewClass} from '@angular/core';
import {Compiler, ComponentFactory, Inject, Injector, ModuleWithComponentFactories, NgModuleFactory, Type, ɵgetComponentViewDefinitionFactory as getComponentViewDefinitionFactory} from '@angular/core';
import {AnimationCompiler, AnimationEntryCompileResult} from '../animation/animation_compiler';
import {AnimationParser} from '../animation/animation_parser';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, ProviderMeta, ProxyClass, createHostComponentMeta, identifierName} from '../compile_metadata';
import {CompilerConfig} from '../config';
import {DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
import {stringify} from '../facade/lang';
import {CompilerInjectable} from '../injectable';
import {CompileMetadataResolver} from '../metadata_resolver';
@ -42,14 +39,12 @@ export class JitCompiler implements Compiler {
private _compiledHostTemplateCache = new Map<Type<any>, CompiledTemplate>();
private _compiledDirectiveWrapperCache = new Map<Type<any>, Type<any>>();
private _compiledNgModuleCache = new Map<Type<any>, NgModuleFactory<any>>();
private _animationCompiler = new AnimationCompiler();
constructor(
private _injector: Injector, private _metadataResolver: CompileMetadataResolver,
private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler,
private _viewCompiler: ViewCompiler, private _ngModuleCompiler: NgModuleCompiler,
private _directiveWrapperCompiler: DirectiveWrapperCompiler,
private _compilerConfig: CompilerConfig, private _animationParser: AnimationParser) {}
private _compilerConfig: CompilerConfig) {}
get injector(): Injector { return this._injector; }
@ -156,7 +151,6 @@ export class JitCompiler implements Compiler {
localModuleMeta.declaredDirectives.forEach((dirIdentifier) => {
moduleByDirective.set(dirIdentifier.reference, localModuleMeta);
const dirMeta = this._metadataResolver.getDirectiveMetadata(dirIdentifier.reference);
this._compileDirectiveWrapper(dirMeta, localModuleMeta);
if (dirMeta.isComponent) {
templates.add(this._createCompiledTemplate(dirMeta, localModuleMeta));
if (allComponentFactories) {
@ -221,7 +215,7 @@ export class JitCompiler implements Compiler {
const componentFactory = <ComponentFactory<any>>compMeta.componentFactory;
const hostClass = this._metadataResolver.getHostComponentType(compType);
const hostMeta = createHostComponentMeta(
hostClass, compMeta, <any>getComponentFactoryViewClass(componentFactory));
hostClass, compMeta, <any>getComponentViewDefinitionFactory(componentFactory));
compiledTemplate =
new CompiledTemplate(true, compMeta.type, hostMeta, ngModule, [compMeta.type]);
this._compiledHostTemplateCache.set(compType, compiledTemplate);
@ -241,26 +235,6 @@ export class JitCompiler implements Compiler {
return compiledTemplate;
}
private _compileDirectiveWrapper(
dirMeta: CompileDirectiveMetadata, moduleMeta: CompileNgModuleMetadata): void {
if (this._compilerConfig.useViewEngine) {
return;
}
const compileResult = this._directiveWrapperCompiler.compile(dirMeta);
const statements = compileResult.statements;
let directiveWrapperClass: any;
if (!this._compilerConfig.useJit) {
directiveWrapperClass =
interpretStatements(statements, [compileResult.dirWrapperClassVar])[0];
} else {
directiveWrapperClass = jitStatements(
`/${identifierName(moduleMeta.type)}/${identifierName(dirMeta.type)}/wrapper.ngfactory.js`,
statements, [compileResult.dirWrapperClassVar])[0];
}
(<ProxyClass>dirMeta.wrapperType).setDelegate(directiveWrapperClass);
this._compiledDirectiveWrapperCache.set(dirMeta.type.reference, directiveWrapperClass);
}
private _compileTemplate(template: CompiledTemplate) {
if (template.isCompiled) {
return;
@ -272,8 +246,6 @@ export class JitCompiler implements Compiler {
(r) => { externalStylesheetsByModuleUrl.set(r.meta.moduleUrl, r); });
this._resolveStylesCompileResult(
stylesCompileResult.componentStylesheet, externalStylesheetsByModuleUrl);
const parsedAnimations =
this._compilerConfig.useViewEngine ? [] : this._animationParser.parseComponent(compMeta);
const directives =
template.directives.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference));
const pipes = template.ngModule.transitiveModule.pipes.map(
@ -281,15 +253,11 @@ export class JitCompiler implements Compiler {
const {template: parsedTemplate, pipes: usedPipes} = this._templateParser.parse(
compMeta, compMeta.template.template, directives, pipes, template.ngModule.schemas,
identifierName(compMeta.type));
const compiledAnimations = this._compilerConfig.useViewEngine ?
[] :
this._animationCompiler.compile(identifierName(compMeta.type), parsedAnimations);
const compileResult = this._viewCompiler.compileComponent(
compMeta, parsedTemplate, ir.variable(stylesCompileResult.componentStylesheet.stylesVar),
usedPipes, compiledAnimations);
const statements = stylesCompileResult.componentStylesheet.statements
.concat(...compiledAnimations.map(ca => ca.statements))
.concat(compileResult.statements);
usedPipes);
const statements =
stylesCompileResult.componentStylesheet.statements.concat(compileResult.statements);
let viewClass: any;
let rendererType: any;
if (!this._compilerConfig.useJit) {

View File

@ -7,11 +7,9 @@
*/
import {COMPILER_OPTIONS, Compiler, CompilerFactory, CompilerOptions, Inject, InjectionToken, MissingTranslationStrategy, Optional, PLATFORM_INITIALIZER, PlatformRef, Provider, ReflectiveInjector, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, ViewEncapsulation, createPlatformFactory, isDevMode, platformCore, ɵConsole as Console, ɵReflectionCapabilities as ReflectionCapabilities, ɵReflector as Reflector, ɵReflectorReader as ReflectorReader, ɵreflector as reflector} from '@angular/core';
import {AnimationParser} from '../animation/animation_parser';
import {CompilerConfig, USE_VIEW_ENGINE} from '../config';
import {CompilerConfig} from '../config';
import {DirectiveNormalizer} from '../directive_normalizer';
import {DirectiveResolver} from '../directive_resolver';
import {DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
import {Lexer} from '../expression_parser/lexer';
import {Parser} from '../expression_parser/parser';
import * as i18n from '../i18n/index';
@ -29,7 +27,6 @@ import {SummaryResolver} from '../summary_resolver';
import {TemplateParser} from '../template_parser/template_parser';
import {DEFAULT_PACKAGE_URL_PROVIDER, UrlResolver} from '../url_resolver';
import {ViewCompiler} from '../view_compiler/view_compiler';
import {ViewCompilerNext} from '../view_compiler_next/view_compiler';
import {JitCompiler} from './compiler';
@ -41,10 +38,6 @@ const _NO_RESOURCE_LOADER: ResourceLoader = {
const baseHtmlParser = new InjectionToken('HtmlParser');
function viewCompilerFactory(cc: CompilerConfig, sr: ElementSchemaRegistry) {
return cc.useViewEngine ? new ViewCompilerNext(cc, sr) : new ViewCompiler(cc, sr);
}
/**
* A set of providers that provide `JitCompiler` and its dependencies to use for
* template compilation.
@ -84,14 +77,8 @@ export const COMPILER_PROVIDERS: Array<any|Type<any>|{[k: string]: any}|any[]> =
CompileMetadataResolver,
DEFAULT_PACKAGE_URL_PROVIDER,
StyleCompiler,
{provide: USE_VIEW_ENGINE, useValue: false},
{
provide: ViewCompiler,
useFactory: viewCompilerFactory,
deps: [CompilerConfig, ElementSchemaRegistry]
},
ViewCompiler,
NgModuleCompiler,
DirectiveWrapperCompiler,
{provide: CompilerConfig, useValue: new CompilerConfig()},
JitCompiler,
{provide: Compiler, useExisting: JitCompiler},
@ -101,7 +88,6 @@ export const COMPILER_PROVIDERS: Array<any|Type<any>|{[k: string]: any}|any[]> =
DirectiveResolver,
PipeResolver,
NgModuleResolver,
AnimationParser,
];
@CompilerInjectable()
@ -123,7 +109,7 @@ export class JitCompilerFactory implements CompilerFactory {
const injector = ReflectiveInjector.resolveAndCreate([
COMPILER_PROVIDERS, {
provide: CompilerConfig,
useFactory: (useViewEngine: boolean) => {
useFactory: () => {
return new CompilerConfig({
// let explicit values from the compiler options overwrite options
// from the app providers. E.g. important for the testing platform.
@ -135,11 +121,11 @@ export class JitCompilerFactory implements CompilerFactory {
// from the app providers
defaultEncapsulation: opts.defaultEncapsulation,
logBindingUpdate: opts.useDebug,
missingTranslation: opts.missingTranslation, useViewEngine,
missingTranslation: opts.missingTranslation,
enableLegacyTemplate: opts.enableLegacyTemplate,
});
},
deps: [USE_VIEW_ENGINE]
deps: []
},
opts.providers
]);

View File

@ -106,13 +106,6 @@ export class CompileMetadataResolver {
}
}
private getDirectiveWrapperClass(dirType: any): StaticSymbol|cpl.ProxyClass {
if (!this._config.useViewEngine) {
return this.getGeneratedClass(dirType, cpl.dirWrapperClassName(dirType));
}
return null;
}
private getComponentViewClass(dirType: any): StaticSymbol|cpl.ProxyClass {
return this.getGeneratedClass(dirType, cpl.viewClassName(dirType, 0));
}
@ -150,11 +143,7 @@ export class CompileMetadataResolver {
ngfactoryFilePath(dirType.filePath), cpl.componentFactoryName(dirType));
} else {
const hostView = this.getHostComponentViewClass(dirType);
if (this._config.useViewEngine) {
return createComponentFactory(selector, dirType, <any>hostView);
} else {
return new ComponentFactory(selector, <any>hostView, dirType);
}
return createComponentFactory(selector, dirType, <any>hostView);
}
}
@ -192,7 +181,6 @@ export class CompileMetadataResolver {
queries: metadata.queries,
viewQueries: metadata.viewQueries,
entryComponents: metadata.entryComponents,
wrapperType: metadata.wrapperType,
componentViewType: metadata.componentViewType,
rendererType: metadata.rendererType,
componentFactory: metadata.componentFactory,
@ -327,7 +315,6 @@ export class CompileMetadataResolver {
queries: queries,
viewQueries: viewQueries,
entryComponents: entryComponentMetadata,
wrapperType: this.getDirectiveWrapperClass(directiveType),
componentViewType: nonNormalizedTemplateMetadata ? this.getComponentViewClass(directiveType) :
undefined,
rendererType: nonNormalizedTemplateMetadata ? this.getRendererType(directiveType) : undefined,

View File

@ -9,7 +9,6 @@
import {ɵLifecycleHooks} from '@angular/core';
import {CompileDiDependencyMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileProviderMetadata, CompileTokenMetadata, identifierModuleUrl, identifierName, tokenName, tokenReference} from './compile_metadata';
import {createDiTokenExpression} from './compiler_util/identifier_util';
import {isPresent} from './facade/lang';
import {Identifiers, createIdentifier, resolveIdentifier} from './identifiers';
import {CompilerInjectable} from './injectable';
@ -239,6 +238,14 @@ class _InjectorBuilder implements ClassBuilder {
}
}
function createDiTokenExpression(token: CompileTokenMetadata): o.Expression {
if (isPresent(token.value)) {
return o.literal(token.value);
} else {
return o.importExpr(token.identifier);
}
}
class InjectorProps {
static parent = o.THIS_EXPR.prop('parent');
}

View File

@ -242,8 +242,8 @@ export class BindingParser {
BoundElementPropertyAst {
if (boundProp.isAnimation) {
return new BoundElementPropertyAst(
boundProp.name, PropertyBindingType.Animation, SecurityContext.NONE, false,
boundProp.expression, null, boundProp.sourceSpan);
boundProp.name, PropertyBindingType.Animation, SecurityContext.NONE, boundProp.expression,
null, boundProp.sourceSpan);
}
let unit: string = null;
@ -290,8 +290,8 @@ export class BindingParser {
}
return new BoundElementPropertyAst(
boundPropertyName, bindingType, securityContexts.length === 1 ? securityContexts[0] : null,
securityContexts.length > 1, boundProp.expression, unit, boundProp.sourceSpan);
boundPropertyName, bindingType, securityContexts[0], boundProp.expression, unit,
boundProp.sourceSpan);
}
parseEvent(

View File

@ -62,8 +62,8 @@ export class AttrAst implements TemplateAst {
export class BoundElementPropertyAst implements TemplateAst {
constructor(
public name: string, public type: PropertyBindingType,
public securityContext: SecurityContext, public needsRuntimeSecurityContext: boolean,
public value: AST, public unit: string, public sourceSpan: ParseSourceSpan) {}
public securityContext: SecurityContext, public value: AST, public unit: string,
public sourceSpan: ParseSourceSpan) {}
visit(visitor: TemplateAstVisitor, context: any): any {
return visitor.visitElementProperty(this, context);
}

View File

@ -372,16 +372,6 @@ class TemplateParseVisitor implements html.Visitor {
providerContext.transformedDirectiveAsts, providerContext.transformProviders,
providerContext.transformedHasViewContainer, providerContext.queryMatches, children,
hasInlineTemplates ? null : ngContentIndex, element.sourceSpan, element.endSourceSpan);
this._findComponentDirectives(directiveAsts)
.forEach(
componentDirectiveAst => this._validateElementAnimationInputOutputs(
componentDirectiveAst.hostProperties, componentDirectiveAst.hostEvents,
componentDirectiveAst.directive.template));
const componentTemplate = providerContext.viewContext.component.template;
this._validateElementAnimationInputOutputs(
elementProps, events, componentTemplate.toSummary());
}
if (hasInlineTemplates) {
@ -412,34 +402,6 @@ class TemplateParseVisitor implements html.Visitor {
return parsedElement;
}
private _validateElementAnimationInputOutputs(
inputs: BoundElementPropertyAst[], outputs: BoundEventAst[],
template: CompileTemplateSummary) {
if (this.config.useViewEngine) return;
const triggerLookup = new Set<string>();
template.animations.forEach(entry => { triggerLookup.add(entry); });
const animationInputs = inputs.filter(input => input.isAnimation);
animationInputs.forEach(input => {
const name = input.name;
if (!triggerLookup.has(name)) {
this._reportError(`Couldn't find an animation entry for "${name}"`, input.sourceSpan);
}
});
outputs.forEach(output => {
if (output.isAnimation) {
const found = animationInputs.find(input => input.name == output.name);
if (!found) {
this._reportError(
`Unable to listen on (@${output.name}.${output.phase}) because the animation trigger [@${output.name}] isn't being used on the same element`,
output.sourceSpan);
}
}
});
}
private _parseAttr(
isTemplateElement: boolean, attr: html.Attribute, targetMatchableAttrs: string[][],
targetProps: BoundProperty[], targetEvents: BoundEventAst[],
@ -578,8 +540,8 @@ class TemplateParseVisitor implements html.Visitor {
component = directive;
}
const directiveProperties: BoundDirectivePropertyAst[] = [];
let hostProperties = this._bindingParser.createDirectiveHostPropertyAsts(
directive, this.config.useViewEngine ? elementName : directive.selector, sourceSpan);
let hostProperties =
this._bindingParser.createDirectiveHostPropertyAsts(directive, elementName, sourceSpan);
// Note: We need to check the host properties here as well,
// as we don't know the element name in the DirectiveWrapperCompiler yet.
hostProperties = this._checkPropertiesInSchema(elementName, hostProperties);

View File

@ -1,402 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {CompileDiDependencyMetadata, CompileDirectiveSummary, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata, tokenName, tokenReference} from '../compile_metadata';
import {createDiTokenExpression} from '../compiler_util/identifier_util';
import {DirectiveWrapperExpressions} from '../directive_wrapper_compiler';
import {isPresent} from '../facade/lang';
import {Identifiers, createIdentifier, createIdentifierToken, identifierToken, resolveIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {convertValueToOutputAst} from '../output/value_util';
import {ProviderAst, ProviderAstType, ReferenceAst, TemplateAst} from '../template_parser/template_ast';
import {CompileMethod} from './compile_method';
import {CompileQuery, addQueryToTokenMap, createQueryList} from './compile_query';
import {CompileView, CompileViewRootNode} from './compile_view';
import {InjectMethodVars} from './constants';
import {ComponentFactoryDependency, DirectiveWrapperDependency} from './deps';
import {getPropertyInView, injectFromViewParentInjector} from './util';
export class CompileNode {
constructor(
public parent: CompileElement, public view: CompileView, public nodeIndex: number,
public renderNode: o.Expression, public sourceAst: TemplateAst) {}
isNull(): boolean { return !this.renderNode; }
isRootElement(): boolean { return this.view != this.parent.view; }
}
export class CompileElement extends CompileNode {
static createNull(): CompileElement {
return new CompileElement(null, null, null, null, null, null, [], [], false, false, []);
}
public compViewExpr: o.Expression = null;
public viewContainer: o.ReadPropExpr;
public elementRef: o.Expression;
public instances = new Map<any, o.Expression>();
public directiveWrapperInstance = new Map<any, o.Expression>();
private _resolvedProviders: Map<any, ProviderAst>;
private _queryCount = 0;
private _queries = new Map<any, CompileQuery[]>();
public contentNodesByNgContentIndex: Array<CompileViewRootNode>[] = null;
public embeddedView: CompileView;
public referenceTokens: {[key: string]: CompileTokenMetadata};
constructor(
parent: CompileElement, view: CompileView, nodeIndex: number, renderNode: o.Expression,
sourceAst: TemplateAst, public component: CompileDirectiveSummary,
private _directives: CompileDirectiveSummary[],
private _resolvedProvidersArray: ProviderAst[], public hasViewContainer: boolean,
public hasEmbeddedView: boolean, references: ReferenceAst[]) {
super(parent, view, nodeIndex, renderNode, sourceAst);
this.referenceTokens = {};
references.forEach(ref => this.referenceTokens[ref.name] = ref.value);
this.elementRef =
o.importExpr(createIdentifier(Identifiers.ElementRef)).instantiate([this.renderNode]);
this.instances.set(resolveIdentifier(Identifiers.ElementRef), this.elementRef);
this.instances.set(
resolveIdentifier(Identifiers.Injector),
o.THIS_EXPR.callMethod('injector', [o.literal(this.nodeIndex)]));
this.instances.set(resolveIdentifier(Identifiers.Renderer), o.THIS_EXPR.prop('renderer'));
if (this.hasViewContainer || this.hasEmbeddedView) {
this._createViewContainer();
}
if (this.component) {
this._createComponentFactoryResolver();
}
}
private _createViewContainer() {
const fieldName = `_vc_${this.nodeIndex}`;
const parentNodeIndex = this.isRootElement() ? null : this.parent.nodeIndex;
// private is fine here as no child view will reference a ViewContainer
this.view.fields.push(new o.ClassField(
fieldName, o.importType(createIdentifier(Identifiers.ViewContainer)),
[o.StmtModifier.Private]));
const statement =
o.THIS_EXPR.prop(fieldName)
.set(o.importExpr(createIdentifier(Identifiers.ViewContainer)).instantiate([
o.literal(this.nodeIndex), o.literal(parentNodeIndex), o.THIS_EXPR, this.renderNode
]))
.toStmt();
this.view.createMethod.addStmt(statement);
this.viewContainer = o.THIS_EXPR.prop(fieldName);
this.instances.set(resolveIdentifier(Identifiers.ViewContainer), this.viewContainer);
this.view.viewContainers.push(this.viewContainer);
}
private _createComponentFactoryResolver() {
const entryComponents = this.component.entryComponents.map((entryComponent) => {
this.view.targetDependencies.push(
new ComponentFactoryDependency(entryComponent.componentType));
return {reference: entryComponent.componentFactory};
});
if (!entryComponents || entryComponents.length === 0) {
return;
}
const createComponentFactoryResolverExpr =
o.importExpr(createIdentifier(Identifiers.CodegenComponentFactoryResolver)).instantiate([
o.literalArr(entryComponents.map((entryComponent) => o.importExpr(entryComponent))),
injectFromViewParentInjector(
this.view, createIdentifierToken(Identifiers.ComponentFactoryResolver), false)
]);
const provider: CompileProviderMetadata = {
token: createIdentifierToken(Identifiers.ComponentFactoryResolver),
useValue: createComponentFactoryResolverExpr
};
// Add ComponentFactoryResolver as first provider as it does not have deps on other providers
// ProviderAstType.PrivateService as only the component and its view can see it,
// but nobody else
this._resolvedProvidersArray.unshift(new ProviderAst(
provider.token, false, true, [provider], ProviderAstType.PrivateService, [],
this.sourceAst.sourceSpan));
}
setComponentView(compViewExpr: o.Expression) {
this.compViewExpr = compViewExpr;
this.contentNodesByNgContentIndex =
new Array(this.component.template.ngContentSelectors.length);
for (let i = 0; i < this.contentNodesByNgContentIndex.length; i++) {
this.contentNodesByNgContentIndex[i] = [];
}
}
setEmbeddedView(embeddedView: CompileView) {
this.embeddedView = embeddedView;
if (isPresent(embeddedView)) {
const createTemplateRefExpr =
o.importExpr(createIdentifier(Identifiers.TemplateRef_)).instantiate([
o.THIS_EXPR, o.literal(this.nodeIndex), this.renderNode
]);
const provider: CompileProviderMetadata = {
token: createIdentifierToken(Identifiers.TemplateRef),
useValue: createTemplateRefExpr
};
// Add TemplateRef as first provider as it does not have deps on other providers
this._resolvedProvidersArray.unshift(new ProviderAst(
provider.token, false, true, [provider], ProviderAstType.Builtin, [],
this.sourceAst.sourceSpan));
}
}
beforeChildren(): void {
if (this.hasViewContainer) {
this.instances.set(
resolveIdentifier(Identifiers.ViewContainerRef), this.viewContainer.prop('vcRef'));
}
this._resolvedProviders = new Map<any, ProviderAst>();
this._resolvedProvidersArray.forEach(
provider => this._resolvedProviders.set(tokenReference(provider.token), provider));
// create all the provider instances, some in the view constructor,
// some as getters. We rely on the fact that they are already sorted topologically.
Array.from(this._resolvedProviders.values()).forEach((resolvedProvider) => {
const isDirectiveWrapper = resolvedProvider.providerType === ProviderAstType.Component ||
resolvedProvider.providerType === ProviderAstType.Directive;
const providerValueExpressions = resolvedProvider.providers.map((provider) => {
if (provider.useExisting) {
return this._getDependency(resolvedProvider.providerType, {token: provider.useExisting});
} else if (provider.useFactory) {
const deps = provider.deps || provider.useFactory.diDeps;
const depsExpr =
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep));
return o.importExpr(provider.useFactory).callFn(depsExpr);
} else if (provider.useClass) {
const deps = provider.deps || provider.useClass.diDeps;
const depsExpr =
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep));
if (isDirectiveWrapper) {
const dirMeta =
this._directives.find(dir => dir.type.reference === provider.useClass.reference);
this.view.targetDependencies.push(
new DirectiveWrapperDependency(dirMeta.type.reference));
return DirectiveWrapperExpressions.create({reference: dirMeta.wrapperType}, depsExpr);
} else {
return o.importExpr(provider.useClass)
.instantiate(depsExpr, o.importType(provider.useClass));
}
} else {
return convertValueToOutputAst(provider.useValue);
}
});
const propName =
`_${tokenName(resolvedProvider.token)}_${this.nodeIndex}_${this.instances.size}`;
const instance = createProviderProperty(
propName, providerValueExpressions, resolvedProvider.multiProvider,
resolvedProvider.eager, this);
if (isDirectiveWrapper) {
this.directiveWrapperInstance.set(tokenReference(resolvedProvider.token), instance);
this.instances.set(
tokenReference(resolvedProvider.token), DirectiveWrapperExpressions.context(instance));
} else {
this.instances.set(tokenReference(resolvedProvider.token), instance);
}
});
for (let i = 0; i < this._directives.length; i++) {
const directive = this._directives[i];
const directiveInstance = this.instances.get(tokenReference(identifierToken(directive.type)));
directive.queries.forEach((queryMeta) => { this._addQuery(queryMeta, directiveInstance); });
}
Object.keys(this.referenceTokens).forEach(varName => {
const token = this.referenceTokens[varName];
let varValue: o.Expression;
if (token) {
varValue = this.instances.get(tokenReference(token));
} else {
varValue = this.renderNode;
}
this.view.locals.set(varName, varValue);
});
}
afterChildren(childNodeCount: number) {
Array.from(this._resolvedProviders.values()).forEach((resolvedProvider) => {
// Note: afterChildren is called after recursing into children.
// This is good so that an injector match in an element that is closer to a requesting element
// matches first.
const providerExpr = this.instances.get(tokenReference(resolvedProvider.token));
// Note: view providers are only visible on the injector of that element.
// This is not fully correct as the rules during codegen don't allow a directive
// to get hold of a view provdier on the same element. We still do this semantic
// as it simplifies our model to having only one runtime injector per element.
const providerChildNodeCount =
resolvedProvider.providerType === ProviderAstType.PrivateService ? 0 : childNodeCount;
this.view.injectorGetMethod.addStmt(createInjectInternalCondition(
this.nodeIndex, providerChildNodeCount, resolvedProvider, providerExpr));
});
}
finish() {
Array.from(this._queries.values())
.forEach(
queries => queries.forEach(
q => q.generateStatements(
this.view.createMethod, this.view.updateContentQueriesMethod)));
}
addContentNode(ngContentIndex: number, nodeExpr: CompileViewRootNode) {
this.contentNodesByNgContentIndex[ngContentIndex].push(nodeExpr);
}
getComponent(): o.Expression {
return isPresent(this.component) ?
this.instances.get(tokenReference(identifierToken(this.component.type))) :
null;
}
getProviderTokens(): CompileTokenMetadata[] {
return Array.from(this._resolvedProviders.values()).map(provider => provider.token);
}
getQueriesFor(token: CompileTokenMetadata): CompileQuery[] {
const result: CompileQuery[] = [];
let currentEl: CompileElement = this;
let distance = 0;
let queries: CompileQuery[];
while (!currentEl.isNull()) {
queries = currentEl._queries.get(tokenReference(token));
if (isPresent(queries)) {
result.push(...queries.filter((query) => query.meta.descendants || distance <= 1));
}
if (currentEl._directives.length > 0) {
distance++;
}
currentEl = currentEl.parent;
}
queries = this.view.componentView.viewQueries.get(tokenReference(token));
if (isPresent(queries)) {
result.push(...queries);
}
return result;
}
private _addQuery(queryMeta: CompileQueryMetadata, directiveInstance: o.Expression):
CompileQuery {
const propName =
`_query_${tokenName(queryMeta.selectors[0])}_${this.nodeIndex}_${this._queryCount++}`;
const queryList = createQueryList(propName, this.view);
const query = new CompileQuery(queryMeta, queryList, directiveInstance, this.view);
addQueryToTokenMap(this._queries, query);
return query;
}
private _getLocalDependency(
requestingProviderType: ProviderAstType, dep: CompileDiDependencyMetadata): o.Expression {
let result: o.Expression = null;
if (isPresent(dep.token)) {
// access builtins with special visibility
if (!result) {
if (tokenReference(dep.token) === resolveIdentifier(Identifiers.ChangeDetectorRef)) {
if (requestingProviderType === ProviderAstType.Component) {
return this.compViewExpr.prop('ref');
} else {
return getPropertyInView(o.THIS_EXPR.prop('ref'), this.view, this.view.componentView);
}
}
}
// access regular providers on the element
if (!result) {
const resolvedProvider = this._resolvedProviders.get(tokenReference(dep.token));
// don't allow directives / public services to access private services.
// only components and private services can access private services.
if (resolvedProvider && (requestingProviderType === ProviderAstType.Directive ||
requestingProviderType === ProviderAstType.PublicService) &&
resolvedProvider.providerType === ProviderAstType.PrivateService) {
return null;
}
result = this.instances.get(tokenReference(dep.token));
}
}
return result;
}
private _getDependency(requestingProviderType: ProviderAstType, dep: CompileDiDependencyMetadata):
o.Expression {
let currElement: CompileElement = this;
let result: o.Expression = null;
if (dep.isValue) {
result = o.literal(dep.value);
}
if (!result && !dep.isSkipSelf) {
result = this._getLocalDependency(requestingProviderType, dep);
}
// check parent elements
while (!result && !currElement.parent.isNull()) {
currElement = currElement.parent;
result = currElement._getLocalDependency(ProviderAstType.PublicService, {token: dep.token});
}
if (!result) {
result = injectFromViewParentInjector(this.view, dep.token, dep.isOptional);
}
if (!result) {
result = o.NULL_EXPR;
}
return getPropertyInView(result, this.view, currElement.view);
}
}
function createInjectInternalCondition(
nodeIndex: number, childNodeCount: number, provider: ProviderAst,
providerExpr: o.Expression): o.Statement {
let indexCondition: o.Expression;
if (childNodeCount > 0) {
indexCondition = o.literal(nodeIndex)
.lowerEquals(InjectMethodVars.requestNodeIndex)
.and(InjectMethodVars.requestNodeIndex.lowerEquals(
o.literal(nodeIndex + childNodeCount)));
} else {
indexCondition = o.literal(nodeIndex).identical(InjectMethodVars.requestNodeIndex);
}
return new o.IfStmt(
InjectMethodVars.token.identical(createDiTokenExpression(provider.token)).and(indexCondition),
[new o.ReturnStatement(providerExpr)]);
}
function createProviderProperty(
propName: string, providerValueExpressions: o.Expression[], isMulti: boolean, isEager: boolean,
compileElement: CompileElement): o.Expression {
const view = compileElement.view;
let resolvedProviderValueExpr: o.Expression;
let type: o.Type;
if (isMulti) {
resolvedProviderValueExpr = o.literalArr(providerValueExpressions);
type = new o.ArrayType(o.DYNAMIC_TYPE);
} else {
resolvedProviderValueExpr = providerValueExpressions[0];
type = providerValueExpressions[0].type;
}
if (!type) {
type = o.DYNAMIC_TYPE;
}
if (isEager) {
view.fields.push(new o.ClassField(propName, type));
view.createMethod.addStmt(o.THIS_EXPR.prop(propName).set(resolvedProviderValueExpr).toStmt());
} else {
const internalField = `_${propName}`;
view.fields.push(new o.ClassField(internalField, type));
const getter = new CompileMethod(view);
getter.resetDebugInfo(compileElement.nodeIndex, compileElement.sourceAst);
// Note: Equals is important for JS so that it also checks the undefined case!
getter.addStmt(new o.IfStmt(
o.THIS_EXPR.prop(internalField).isBlank(),
[o.THIS_EXPR.prop(internalField).set(resolvedProviderValueExpr).toStmt()]));
getter.addStmt(new o.ReturnStatement(o.THIS_EXPR.prop(internalField)));
view.getters.push(new o.ClassGetter(propName, getter.finish(), type));
}
return o.THIS_EXPR.prop(propName);
}

View File

@ -1,81 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 * as o from '../output/output_ast';
import {TemplateAst} from '../template_parser/template_ast';
import {CompileView} from './compile_view';
class _DebugState {
constructor(public nodeIndex: number, public sourceAst: TemplateAst) {}
}
const NULL_DEBUG_STATE = new _DebugState(null, null);
export class CompileMethod {
private _newState: _DebugState = NULL_DEBUG_STATE;
private _currState: _DebugState = NULL_DEBUG_STATE;
private _debugEnabled: boolean;
private _bodyStatements: o.Statement[] = [];
constructor(private _view: CompileView) {
this._debugEnabled = this._view.genConfig.genDebugInfo;
}
private _updateDebugContextIfNeeded() {
if (this._newState.nodeIndex !== this._currState.nodeIndex ||
this._newState.sourceAst !== this._currState.sourceAst) {
const expr = this._updateDebugContext(this._newState);
if (expr) {
this._bodyStatements.push(expr.toStmt());
}
}
}
private _updateDebugContext(newState: _DebugState): o.Expression {
this._currState = this._newState = newState;
if (this._debugEnabled) {
const sourceLocation = newState.sourceAst ? newState.sourceAst.sourceSpan.start : null;
return o.THIS_EXPR.callMethod('debug', [
o.literal(newState.nodeIndex),
sourceLocation ? o.literal(sourceLocation.line) : o.NULL_EXPR,
sourceLocation ? o.literal(sourceLocation.col) : o.NULL_EXPR
]);
} else {
return null;
}
}
resetDebugInfoExpr(nodeIndex: number, templateAst: TemplateAst): o.Expression {
const res = this._updateDebugContext(new _DebugState(nodeIndex, templateAst));
return res || o.NULL_EXPR;
}
resetDebugInfo(nodeIndex: number, templateAst: TemplateAst) {
this._newState = new _DebugState(nodeIndex, templateAst);
}
push(...stmts: o.Statement[]) { this.addStmts(stmts); }
addStmt(stmt: o.Statement) {
this._updateDebugContextIfNeeded();
this._bodyStatements.push(stmt);
}
addStmts(stmts: o.Statement[]) {
this._updateDebugContextIfNeeded();
this._bodyStatements.push(...stmts);
}
finish(): o.Statement[] { return this._bodyStatements; }
isEmpty(): boolean { return this._bodyStatements.length === 0; }
}

View File

@ -1,94 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {CompilePipeSummary, tokenReference} from '../compile_metadata';
import {createPureProxy} from '../compiler_util/identifier_util';
import {Identifiers, createIdentifier, resolveIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {CompileView} from './compile_view';
import {getPropertyInView, injectFromViewParentInjector} from './util';
export class CompilePipe {
static call(view: CompileView, name: string, args: o.Expression[]): o.Expression {
const compView = view.componentView;
const meta = _findPipeMeta(compView, name);
let pipe: CompilePipe;
if (meta.pure) {
// pure pipes live on the component view
pipe = compView.purePipes.get(name);
if (!pipe) {
pipe = new CompilePipe(compView, meta);
compView.purePipes.set(name, pipe);
compView.pipes.push(pipe);
}
} else {
// Non pure pipes live on the view that called it
pipe = new CompilePipe(view, meta);
view.pipes.push(pipe);
}
return pipe._call(view, args);
}
instance: o.ReadPropExpr;
private _purePipeProxyCount = 0;
constructor(public view: CompileView, public meta: CompilePipeSummary) {
this.instance = o.THIS_EXPR.prop(`_pipe_${meta.name}_${view.pipeCount++}`);
const deps = this.meta.type.diDeps.map((diDep) => {
if (tokenReference(diDep.token) === resolveIdentifier(Identifiers.ChangeDetectorRef)) {
return getPropertyInView(o.THIS_EXPR.prop('ref'), this.view, this.view.componentView);
}
return injectFromViewParentInjector(view, diDep.token, false);
});
this.view.fields.push(new o.ClassField(this.instance.name, o.importType(this.meta.type)));
this.view.createMethod.resetDebugInfo(null, null);
this.view.createMethod.addStmt(o.THIS_EXPR.prop(this.instance.name)
.set(o.importExpr(this.meta.type).instantiate(deps))
.toStmt());
}
get pure(): boolean { return this.meta.pure; }
private _call(callingView: CompileView, args: o.Expression[]): o.Expression {
if (this.meta.pure) {
// PurePipeProxies live on the view that called them.
const purePipeProxyInstance =
o.THIS_EXPR.prop(`${this.instance.name}_${this._purePipeProxyCount++}`);
const pipeInstanceSeenFromPureProxy =
getPropertyInView(this.instance, callingView, this.view);
createPureProxy(
pipeInstanceSeenFromPureProxy.prop('transform')
.callMethod(o.BuiltinMethod.Bind, [pipeInstanceSeenFromPureProxy]),
args.length, purePipeProxyInstance,
{fields: callingView.fields, ctorStmts: callingView.createMethod});
return o.importExpr(createIdentifier(Identifiers.castByValue))
.callFn([purePipeProxyInstance, pipeInstanceSeenFromPureProxy.prop('transform')])
.callFn(args);
} else {
return getPropertyInView(this.instance, callingView, this.view).callMethod('transform', args);
}
}
}
function _findPipeMeta(view: CompileView, name: string): CompilePipeSummary {
let pipeMeta: CompilePipeSummary = null;
for (let i = view.pipeMetas.length - 1; i >= 0; i--) {
const localPipeMeta = view.pipeMetas[i];
if (localPipeMeta.name == name) {
pipeMeta = localPipeMeta;
break;
}
}
if (!pipeMeta) {
throw new Error(
`Illegal state: Could not find pipe ${name} although the parser should have detected this error!`);
}
return pipeMeta;
}

View File

@ -1,133 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {CompileQueryMetadata, tokenReference} from '../compile_metadata';
import {ListWrapper} from '../facade/collection';
import {Identifiers, createIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {CompileElement} from './compile_element';
import {CompileMethod} from './compile_method';
import {CompileView} from './compile_view';
import {getPropertyInView} from './util';
class ViewQueryValues {
constructor(public view: CompileView, public values: Array<o.Expression|ViewQueryValues>) {}
}
export class CompileQuery {
private _values: ViewQueryValues;
constructor(
public meta: CompileQueryMetadata, public queryList: o.Expression,
public ownerDirectiveExpression: o.Expression, public view: CompileView) {
this._values = new ViewQueryValues(view, []);
}
addValue(value: o.Expression, view: CompileView) {
let currentView = view;
const elPath: CompileElement[] = [];
while (currentView && currentView !== this.view) {
const parentEl = currentView.declarationElement;
elPath.unshift(parentEl);
currentView = parentEl.view;
}
const queryListForDirtyExpr = getPropertyInView(this.queryList, view, this.view);
let viewValues = this._values;
elPath.forEach((el) => {
const last =
viewValues.values.length > 0 ? viewValues.values[viewValues.values.length - 1] : null;
if (last instanceof ViewQueryValues && last.view === el.embeddedView) {
viewValues = last;
} else {
const newViewValues = new ViewQueryValues(el.embeddedView, []);
viewValues.values.push(newViewValues);
viewValues = newViewValues;
}
});
viewValues.values.push(value);
if (elPath.length > 0) {
view.dirtyParentQueriesMethod.addStmt(
queryListForDirtyExpr.callMethod('setDirty', []).toStmt());
}
}
private _isStatic(): boolean {
return !this._values.values.some(value => value instanceof ViewQueryValues);
}
generateStatements(targetStaticMethod: CompileMethod, targetDynamicMethod: CompileMethod) {
const values = createQueryValues(this._values);
const updateStmts = [this.queryList.callMethod('reset', [o.literalArr(values)]).toStmt()];
if (this.ownerDirectiveExpression) {
const valueExpr = this.meta.first ? this.queryList.prop('first') : this.queryList;
updateStmts.push(
this.ownerDirectiveExpression.prop(this.meta.propertyName).set(valueExpr).toStmt());
}
if (!this.meta.first) {
updateStmts.push(this.queryList.callMethod('notifyOnChanges', []).toStmt());
}
if (this.meta.first && this._isStatic()) {
// for queries that don't change and the user asked for a single element,
// set it immediately. That is e.g. needed for querying for ViewContainerRefs, ...
// we don't do this for QueryLists for now as this would break the timing when
// we call QueryList listeners...
targetStaticMethod.addStmts(updateStmts);
} else {
targetDynamicMethod.addStmt(new o.IfStmt(this.queryList.prop('dirty'), updateStmts));
}
}
}
function createQueryValues(viewValues: ViewQueryValues): o.Expression[] {
return ListWrapper.flatten(viewValues.values.map((entry) => {
if (entry instanceof ViewQueryValues) {
return mapNestedViews(
entry.view.declarationElement.viewContainer, entry.view, createQueryValues(entry));
} else {
return <o.Expression>entry;
}
}));
}
function mapNestedViews(
viewContainer: o.Expression, view: CompileView, expressions: o.Expression[]): o.Expression {
const adjustedExpressions: o.Expression[] = expressions.map(
(expr) => o.replaceVarInExpression(o.THIS_EXPR.name, o.variable('nestedView'), expr));
return viewContainer.callMethod('mapNestedViews', [
o.variable(view.className),
o.fn(
[new o.FnParam('nestedView', view.classType)],
[new o.ReturnStatement(o.literalArr(adjustedExpressions))], o.DYNAMIC_TYPE)
]);
}
export function createQueryList(propertyName: string, compileView: CompileView): o.Expression {
compileView.fields.push(new o.ClassField(
propertyName, o.importType(createIdentifier(Identifiers.QueryList), [o.DYNAMIC_TYPE])));
const expr = o.THIS_EXPR.prop(propertyName);
compileView.createMethod.addStmt(
o.THIS_EXPR.prop(propertyName)
.set(o.importExpr(createIdentifier(Identifiers.QueryList), [o.DYNAMIC_TYPE]).instantiate([
]))
.toStmt());
return expr;
}
export function addQueryToTokenMap(map: Map<any, CompileQuery[]>, query: CompileQuery) {
query.meta.selectors.forEach((selector) => {
let entry = map.get(tokenReference(selector));
if (!entry) {
entry = [];
map.set(tokenReference(selector), entry);
}
entry.push(query);
});
}

View File

@ -1,176 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {ɵViewType as ViewType} from '@angular/core';
import {AnimationEntryCompileResult} from '../animation/animation_compiler';
import {CompileDirectiveMetadata, CompilePipeSummary, rendererTypeName, tokenName, viewClassName} from '../compile_metadata';
import {EventHandlerVars, LegacyNameResolver} from '../compiler_util/expression_converter';
import {CompilerConfig} from '../config';
import {isPresent} from '../facade/lang';
import * as o from '../output/output_ast';
import {CompileElement, CompileNode} from './compile_element';
import {CompileMethod} from './compile_method';
import {CompilePipe} from './compile_pipe';
import {CompileQuery, addQueryToTokenMap, createQueryList} from './compile_query';
import {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency} from './deps';
import {getPropertyInView} from './util';
export enum CompileViewRootNodeType {
Node,
ViewContainer,
NgContent
}
export class CompileViewRootNode {
constructor(
public type: CompileViewRootNodeType, public expr: o.Expression,
public ngContentIndex?: number) {}
}
export class CompileView implements LegacyNameResolver {
public viewType: ViewType;
public viewQueries: Map<any, CompileQuery[]>;
public viewChildren: o.Expression[] = [];
public nodes: CompileNode[] = [];
public rootNodes: CompileViewRootNode[] = [];
public lastRenderNode: o.Expression = o.NULL_EXPR;
public viewContainers: o.Expression[] = [];
public createMethod: CompileMethod;
public animationBindingsMethod: CompileMethod;
public injectorGetMethod: CompileMethod;
public updateContentQueriesMethod: CompileMethod;
public dirtyParentQueriesMethod: CompileMethod;
public updateViewQueriesMethod: CompileMethod;
public detectChangesInInputsMethod: CompileMethod;
public detectChangesRenderPropertiesMethod: CompileMethod;
public afterContentLifecycleCallbacksMethod: CompileMethod;
public afterViewLifecycleCallbacksMethod: CompileMethod;
public destroyMethod: CompileMethod;
public detachMethod: CompileMethod;
public methods: o.ClassMethod[] = [];
public ctorStmts: o.Statement[] = [];
public fields: o.ClassField[] = [];
public getters: o.ClassGetter[] = [];
public disposables: o.Expression[] = [];
public componentView: CompileView;
public purePipes = new Map<string, CompilePipe>();
public pipes: CompilePipe[] = [];
public locals = new Map<string, o.Expression>();
public className: string;
public rendererTypeName: string;
public classType: o.Type;
public classExpr: o.ReadVarExpr;
public literalArrayCount = 0;
public literalMapCount = 0;
public pipeCount = 0;
public componentContext: o.Expression;
constructor(
public component: CompileDirectiveMetadata, public genConfig: CompilerConfig,
public pipeMetas: CompilePipeSummary[], public styles: o.Expression,
public animations: AnimationEntryCompileResult[], public viewIndex: number,
public declarationElement: CompileElement, public templateVariableBindings: string[][],
public targetDependencies:
Array<ComponentViewDependency|ComponentFactoryDependency|DirectiveWrapperDependency>) {
this.createMethod = new CompileMethod(this);
this.animationBindingsMethod = new CompileMethod(this);
this.injectorGetMethod = new CompileMethod(this);
this.updateContentQueriesMethod = new CompileMethod(this);
this.dirtyParentQueriesMethod = new CompileMethod(this);
this.updateViewQueriesMethod = new CompileMethod(this);
this.detectChangesInInputsMethod = new CompileMethod(this);
this.detectChangesRenderPropertiesMethod = new CompileMethod(this);
this.afterContentLifecycleCallbacksMethod = new CompileMethod(this);
this.afterViewLifecycleCallbacksMethod = new CompileMethod(this);
this.destroyMethod = new CompileMethod(this);
this.detachMethod = new CompileMethod(this);
this.viewType = getViewType(component, viewIndex);
this.className = viewClassName(component.type.reference, viewIndex);
this.rendererTypeName = rendererTypeName(component.type.reference);
this.classType = o.expressionType(o.variable(this.className));
this.classExpr = o.variable(this.className);
if (this.viewType === ViewType.COMPONENT || this.viewType === ViewType.HOST) {
this.componentView = this;
} else {
this.componentView = this.declarationElement.view.componentView;
}
this.componentContext =
getPropertyInView(o.THIS_EXPR.prop('context'), this, this.componentView);
const viewQueries = new Map<any, CompileQuery[]>();
if (this.viewType === ViewType.COMPONENT) {
const directiveInstance = o.THIS_EXPR.prop('context');
this.component.viewQueries.forEach((queryMeta, queryIndex) => {
const propName = `_viewQuery_${tokenName(queryMeta.selectors[0])}_${queryIndex}`;
const queryList = createQueryList(propName, this);
const query = new CompileQuery(queryMeta, queryList, directiveInstance, this);
addQueryToTokenMap(viewQueries, query);
});
}
this.viewQueries = viewQueries;
templateVariableBindings.forEach(
(entry) => { this.locals.set(entry[1], o.THIS_EXPR.prop('context').prop(entry[0])); });
if (!this.declarationElement.isNull()) {
this.declarationElement.setEmbeddedView(this);
}
}
callPipe(name: string, input: o.Expression, args: o.Expression[]): o.Expression {
return CompilePipe.call(this, name, [input].concat(args));
}
getLocal(name: string): o.Expression {
if (name == EventHandlerVars.event.name) {
return EventHandlerVars.event;
}
let currView: CompileView = this;
let result = currView.locals.get(name);
while (!result && isPresent(currView.declarationElement.view)) {
currView = currView.declarationElement.view;
result = currView.locals.get(name);
}
if (isPresent(result)) {
return getPropertyInView(result, this, currView);
} else {
return null;
}
}
finish() {
Array.from(this.viewQueries.values())
.forEach(
queries => queries.forEach(
q => q.generateStatements(this.createMethod, this.updateViewQueriesMethod)));
}
}
function getViewType(component: CompileDirectiveMetadata, embeddedTemplateIndex: number): ViewType {
if (embeddedTemplateIndex > 0) {
return ViewType.EMBEDDED;
}
if (component.isHost) {
return ViewType.HOST;
}
return ViewType.COMPONENT;
}

View File

@ -1,49 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {ChangeDetectionStrategy, ViewEncapsulation, ɵViewType as ViewType} from '@angular/core';
import {createEnumExpression} from '../compiler_util/identifier_util';
import {Identifiers} from '../identifiers';
import * as o from '../output/output_ast';
export class ViewTypeEnum {
static fromValue(value: ViewType): o.Expression {
return createEnumExpression(Identifiers.ViewType, value);
}
}
export class ViewEncapsulationEnum {
static fromValue(value: ViewEncapsulation): o.Expression {
return createEnumExpression(Identifiers.ViewEncapsulation, value);
}
}
export class ChangeDetectorStatusEnum {
static fromValue(value: ChangeDetectorStatusEnum): o.Expression {
return createEnumExpression(Identifiers.ChangeDetectorStatus, value);
}
}
export class ViewConstructorVars {
static viewUtils = o.variable('viewUtils');
static parentView = o.variable('parentView');
static parentIndex = o.variable('parentIndex');
static parentElement = o.variable('parentElement');
}
export class ViewProperties {
static renderer = o.THIS_EXPR.prop('renderer');
static viewUtils = o.THIS_EXPR.prop('viewUtils');
static throwOnChange = o.THIS_EXPR.prop('throwOnChange');
}
export class InjectMethodVars {
static token = o.variable('token');
static requestNodeIndex = o.variable('requestNodeIndex');
static notFoundResult = o.variable('notFoundResult');
}

View File

@ -1,31 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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
*/
/**
* This is currently not read, but will probably be used in the future.
* We keep it as we already pass it through all the right places...
*/
export class ComponentViewDependency {
constructor(public compType: any) {}
}
/**
* This is currently not read, but will probably be used in the future.
* We keep it as we already pass it through all the right places...
*/
export class ComponentFactoryDependency {
constructor(public compType: any) {}
}
/**
* This is currently not read, but will probably be used in the future.
* We keep it as we already pass it through all the right places...
*/
export class DirectiveWrapperDependency {
constructor(public dirType: any) {}
}

View File

@ -1,135 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {EventHandlerVars, convertActionBinding} from '../compiler_util/expression_converter';
import {createInlineArray} from '../compiler_util/identifier_util';
import {DirectiveWrapperExpressions} from '../directive_wrapper_compiler';
import {Identifiers, createIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {BoundEventAst, DirectiveAst} from '../template_parser/template_ast';
import {CompileElement} from './compile_element';
import {CompileMethod} from './compile_method';
import {getHandleEventMethodName} from './util';
export function bindOutputs(
boundEvents: BoundEventAst[], directives: DirectiveAst[], compileElement: CompileElement,
bindToRenderer: boolean): boolean {
const usedEvents = collectEvents(boundEvents, directives);
if (!usedEvents.size) {
return false;
}
if (bindToRenderer) {
subscribeToRenderEvents(usedEvents, compileElement);
}
subscribeToDirectiveEvents(usedEvents, directives, compileElement);
generateHandleEventMethod(boundEvents, directives, compileElement);
return true;
}
function collectEvents(
boundEvents: BoundEventAst[], directives: DirectiveAst[]): Map<string, EventSummary> {
const usedEvents = new Map<string, EventSummary>();
boundEvents.forEach((event) => { usedEvents.set(event.fullName, event); });
directives.forEach((dirAst) => {
dirAst.hostEvents.forEach((event) => { usedEvents.set(event.fullName, event); });
});
return usedEvents;
}
function subscribeToRenderEvents(
usedEvents: Map<string, EventSummary>, compileElement: CompileElement) {
const eventAndTargetExprs: o.Expression[] = [];
usedEvents.forEach((event) => {
if (!event.phase) {
eventAndTargetExprs.push(o.literal(event.name), o.literal(event.target));
}
});
if (eventAndTargetExprs.length) {
const disposableVar = o.variable(`disposable_${compileElement.view.disposables.length}`);
compileElement.view.disposables.push(disposableVar);
compileElement.view.createMethod.addStmt(
disposableVar
.set(o.importExpr(createIdentifier(Identifiers.subscribeToRenderElement)).callFn([
o.THIS_EXPR, compileElement.renderNode, createInlineArray(eventAndTargetExprs),
handleEventExpr(compileElement)
]))
.toDeclStmt(o.FUNCTION_TYPE, [o.StmtModifier.Private]));
}
}
function subscribeToDirectiveEvents(
usedEvents: Map<string, EventSummary>, directives: DirectiveAst[],
compileElement: CompileElement) {
const usedEventNames = Array.from(usedEvents.keys());
directives.forEach((dirAst) => {
const dirWrapper = compileElement.directiveWrapperInstance.get(dirAst.directive.type.reference);
compileElement.view.createMethod.addStmts(DirectiveWrapperExpressions.subscribe(
dirAst.directive, dirAst.hostProperties, usedEventNames, dirWrapper, o.THIS_EXPR,
handleEventExpr(compileElement)));
});
}
function generateHandleEventMethod(
boundEvents: BoundEventAst[], directives: DirectiveAst[], compileElement: CompileElement) {
const hasComponentHostListener =
directives.some((dirAst) => dirAst.hostEvents.some((event) => dirAst.directive.isComponent));
const markPathToRootStart = hasComponentHostListener ? compileElement.compViewExpr : o.THIS_EXPR;
const handleEventStmts = new CompileMethod(compileElement.view);
handleEventStmts.resetDebugInfo(compileElement.nodeIndex, compileElement.sourceAst);
handleEventStmts.push(markPathToRootStart.callMethod('markPathToRootAsCheckOnce', []).toStmt());
const eventNameVar = o.variable('eventName');
const resultVar = o.variable('result');
handleEventStmts.push(resultVar.set(o.literal(true)).toDeclStmt(o.BOOL_TYPE));
directives.forEach((dirAst, dirIdx) => {
const dirWrapper = compileElement.directiveWrapperInstance.get(dirAst.directive.type.reference);
if (dirAst.hostEvents.length > 0) {
handleEventStmts.push(
resultVar
.set(DirectiveWrapperExpressions
.handleEvent(
dirAst.hostEvents, dirWrapper, eventNameVar, EventHandlerVars.event)
.and(resultVar))
.toStmt());
}
});
boundEvents.forEach((renderEvent, renderEventIdx) => {
const evalResult = convertActionBinding(
compileElement.view, compileElement.view.componentContext, renderEvent.handler,
`sub_${renderEventIdx}`);
const trueStmts = evalResult.stmts;
if (evalResult.allowDefault) {
trueStmts.push(resultVar.set(evalResult.allowDefault.and(resultVar)).toStmt());
}
// TODO(tbosch): convert this into a `switch` once our OutputAst supports it.
handleEventStmts.push(
new o.IfStmt(eventNameVar.equals(o.literal(renderEvent.fullName)), trueStmts));
});
handleEventStmts.push(new o.ReturnStatement(resultVar));
compileElement.view.methods.push(new o.ClassMethod(
getHandleEventMethodName(compileElement.nodeIndex),
[
new o.FnParam(eventNameVar.name, o.STRING_TYPE),
new o.FnParam(EventHandlerVars.event.name, o.DYNAMIC_TYPE)
],
handleEventStmts.finish(), o.BOOL_TYPE));
}
function handleEventExpr(compileElement: CompileElement) {
const handleEventMethodName = getHandleEventMethodName(compileElement.nodeIndex);
return o.THIS_EXPR.callMethod('eventHandler', [o.THIS_EXPR.prop(handleEventMethodName)]);
}
type EventSummary = {
name: string,
target: string,
phase: string
};

View File

@ -1,85 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {ɵLifecycleHooks as LifecycleHooks} from '@angular/core';
import {CompileDirectiveSummary, CompilePipeSummary} from '../compile_metadata';
import {isFirstViewCheck} from '../compiler_util/binding_util';
import {DirectiveWrapperExpressions} from '../directive_wrapper_compiler';
import * as o from '../output/output_ast';
import {DirectiveAst, ProviderAst, ProviderAstType} from '../template_parser/template_ast';
import {CompileElement} from './compile_element';
import {CompileView} from './compile_view';
export function bindDirectiveAfterContentLifecycleCallbacks(
directiveMeta: CompileDirectiveSummary, directiveInstance: o.Expression,
compileElement: CompileElement) {
const view = compileElement.view;
const lifecycleHooks = directiveMeta.type.lifecycleHooks;
const afterContentLifecycleCallbacksMethod = view.afterContentLifecycleCallbacksMethod;
afterContentLifecycleCallbacksMethod.resetDebugInfo(
compileElement.nodeIndex, compileElement.sourceAst);
if (lifecycleHooks.indexOf(LifecycleHooks.AfterContentInit) !== -1) {
afterContentLifecycleCallbacksMethod.addStmt(new o.IfStmt(
isFirstViewCheck(o.THIS_EXPR),
[directiveInstance.callMethod('ngAfterContentInit', []).toStmt()]));
}
if (lifecycleHooks.indexOf(LifecycleHooks.AfterContentChecked) !== -1) {
afterContentLifecycleCallbacksMethod.addStmt(
directiveInstance.callMethod('ngAfterContentChecked', []).toStmt());
}
}
export function bindDirectiveAfterViewLifecycleCallbacks(
directiveMeta: CompileDirectiveSummary, directiveInstance: o.Expression,
compileElement: CompileElement) {
const view = compileElement.view;
const lifecycleHooks = directiveMeta.type.lifecycleHooks;
const afterViewLifecycleCallbacksMethod = view.afterViewLifecycleCallbacksMethod;
afterViewLifecycleCallbacksMethod.resetDebugInfo(
compileElement.nodeIndex, compileElement.sourceAst);
if (lifecycleHooks.indexOf(LifecycleHooks.AfterViewInit) !== -1) {
afterViewLifecycleCallbacksMethod.addStmt(new o.IfStmt(
isFirstViewCheck(o.THIS_EXPR),
[directiveInstance.callMethod('ngAfterViewInit', []).toStmt()]));
}
if (lifecycleHooks.indexOf(LifecycleHooks.AfterViewChecked) !== -1) {
afterViewLifecycleCallbacksMethod.addStmt(
directiveInstance.callMethod('ngAfterViewChecked', []).toStmt());
}
}
export function bindDirectiveWrapperLifecycleCallbacks(
dir: DirectiveAst, directiveWrapperIntance: o.Expression, compileElement: CompileElement) {
compileElement.view.destroyMethod.addStmts(
DirectiveWrapperExpressions.ngOnDestroy(dir.directive, directiveWrapperIntance));
compileElement.view.detachMethod.addStmts(DirectiveWrapperExpressions.ngOnDetach(
dir.hostProperties, directiveWrapperIntance, o.THIS_EXPR,
compileElement.compViewExpr || o.THIS_EXPR, compileElement.renderNode));
}
export function bindInjectableDestroyLifecycleCallbacks(
provider: ProviderAst, providerInstance: o.Expression, compileElement: CompileElement) {
const onDestroyMethod = compileElement.view.destroyMethod;
onDestroyMethod.resetDebugInfo(compileElement.nodeIndex, compileElement.sourceAst);
if (provider.providerType !== ProviderAstType.Directive &&
provider.providerType !== ProviderAstType.Component &&
provider.lifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1) {
onDestroyMethod.addStmt(providerInstance.callMethod('ngOnDestroy', []).toStmt());
}
}
export function bindPipeDestroyLifecycleCallbacks(
pipeMeta: CompilePipeSummary, pipeInstance: o.Expression, view: CompileView) {
const onDestroyMethod = view.destroyMethod;
if (pipeMeta.type.lifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1) {
onDestroyMethod.addStmt(pipeInstance.callMethod('ngOnDestroy', []).toStmt());
}
}

View File

@ -1,146 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {SecurityContext, ɵisDefaultChangeDetectionStrategy as isDefaultChangeDetectionStrategy} from '@angular/core';
import {createCheckBindingField} from '../compiler_util/binding_util';
import {legacyConvertPropertyBinding} from '../compiler_util/expression_converter';
import {createEnumExpression} from '../compiler_util/identifier_util';
import {createCheckAnimationBindingStmts, createCheckRenderBindingStmt} from '../compiler_util/render_util';
import {DirectiveWrapperExpressions} from '../directive_wrapper_compiler';
import {Identifiers, createIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
import {BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, PropertyBindingType} from '../template_parser/template_ast';
import {CompileElement, CompileNode} from './compile_element';
import {CompileView} from './compile_view';
import {getHandleEventMethodName} from './util';
export function bindRenderText(
boundText: BoundTextAst, compileNode: CompileNode, view: CompileView): void {
const valueField = createCheckBindingField(view);
const evalResult = legacyConvertPropertyBinding(
view, view, view.componentContext, boundText.value, valueField.bindingId);
if (!evalResult) {
return null;
}
view.detectChangesRenderPropertiesMethod.resetDebugInfo(compileNode.nodeIndex, boundText);
view.detectChangesRenderPropertiesMethod.addStmts(evalResult.stmts);
view.detectChangesRenderPropertiesMethod.addStmt(
o.importExpr(createIdentifier(Identifiers.checkRenderText))
.callFn([
o.THIS_EXPR, compileNode.renderNode, valueField.expression,
valueField.expression.set(evalResult.currValExpr),
evalResult.forceUpdate || o.literal(false)
])
.toStmt());
}
export function bindRenderInputs(
boundProps: BoundElementPropertyAst[], boundOutputs: BoundEventAst[], hasEvents: boolean,
compileElement: CompileElement) {
const view = compileElement.view;
const renderNode = compileElement.renderNode;
boundProps.forEach((boundProp) => {
const bindingField = createCheckBindingField(view);
view.detectChangesRenderPropertiesMethod.resetDebugInfo(compileElement.nodeIndex, boundProp);
const evalResult = legacyConvertPropertyBinding(
view, view, compileElement.view.componentContext, boundProp.value, bindingField.bindingId);
if (!evalResult) {
return;
}
let compileMethod = view.detectChangesRenderPropertiesMethod;
switch (boundProp.type) {
case PropertyBindingType.Property:
case PropertyBindingType.Attribute:
case PropertyBindingType.Class:
case PropertyBindingType.Style:
compileMethod.addStmts(createCheckRenderBindingStmt(
o.THIS_EXPR, renderNode, boundProp, bindingField.expression, evalResult));
break;
case PropertyBindingType.Animation:
compileMethod = view.animationBindingsMethod;
const {checkUpdateStmts, checkDetachStmts} = createCheckAnimationBindingStmts(
o.THIS_EXPR, o.THIS_EXPR, boundProp, boundOutputs,
(hasEvents ? o.THIS_EXPR.prop(getHandleEventMethodName(compileElement.nodeIndex)) :
o.importExpr(createIdentifier(Identifiers.noop)))
.callMethod(o.BuiltinMethod.Bind, [o.THIS_EXPR]),
compileElement.renderNode, bindingField.expression, evalResult);
view.detachMethod.addStmts(checkDetachStmts);
compileMethod.addStmts(checkUpdateStmts);
break;
}
});
}
export function bindDirectiveHostProps(
directiveAst: DirectiveAst, directiveWrapperInstance: o.Expression,
compileElement: CompileElement, elementName: string,
schemaRegistry: ElementSchemaRegistry): void {
// We need to provide the SecurityContext for properties that could need sanitization.
const runtimeSecurityCtxExprs =
directiveAst.hostProperties.filter(boundProp => boundProp.needsRuntimeSecurityContext)
.map((boundProp) => {
let ctx: SecurityContext;
switch (boundProp.type) {
case PropertyBindingType.Property:
ctx = schemaRegistry.securityContext(elementName, boundProp.name, false);
break;
case PropertyBindingType.Attribute:
ctx = schemaRegistry.securityContext(elementName, boundProp.name, true);
break;
default:
throw new Error(
`Illegal state: Only property / attribute bindings can have an unknown security context! Binding ${boundProp.name}`);
}
return createEnumExpression(Identifiers.SecurityContext, ctx);
});
compileElement.view.detectChangesRenderPropertiesMethod.addStmts(
DirectiveWrapperExpressions.checkHost(
directiveAst.hostProperties, directiveWrapperInstance, o.THIS_EXPR,
compileElement.compViewExpr || o.THIS_EXPR, compileElement.renderNode,
runtimeSecurityCtxExprs));
}
export function bindDirectiveInputs(
directiveAst: DirectiveAst, directiveWrapperInstance: o.Expression, dirIndex: number,
compileElement: CompileElement) {
const view = compileElement.view;
const detectChangesInInputsMethod = view.detectChangesInInputsMethod;
detectChangesInInputsMethod.resetDebugInfo(compileElement.nodeIndex, compileElement.sourceAst);
directiveAst.inputs.forEach((input, inputIdx) => {
// Note: We can't use `fields.length` here, as we are not adding a field!
const bindingId = `${compileElement.nodeIndex}_${dirIndex}_${inputIdx}`;
detectChangesInInputsMethod.resetDebugInfo(compileElement.nodeIndex, input);
const evalResult =
legacyConvertPropertyBinding(view, view, view.componentContext, input.value, bindingId);
if (!evalResult) {
return;
}
detectChangesInInputsMethod.addStmts(evalResult.stmts);
detectChangesInInputsMethod.addStmt(
directiveWrapperInstance
.callMethod(
`check_${input.directiveName}`,
[o.THIS_EXPR, evalResult.currValExpr, evalResult.forceUpdate || o.literal(false)])
.toStmt());
});
const isOnPushComp = directiveAst.directive.isComponent &&
!isDefaultChangeDetectionStrategy(directiveAst.directive.changeDetection);
const directiveDetectChangesExpr = DirectiveWrapperExpressions.ngDoCheck(
directiveWrapperInstance, o.THIS_EXPR, compileElement.renderNode);
const directiveDetectChangesStmt = isOnPushComp ?
new o.IfStmt(
directiveDetectChangesExpr,
[compileElement.compViewExpr.callMethod('markAsCheckOnce', []).toStmt()]) :
directiveDetectChangesExpr.toStmt();
detectChangesInInputsMethod.addStmt(directiveDetectChangesStmt);
}

View File

@ -1,57 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {CompileTokenMetadata, tokenReference} from '../compile_metadata';
import * as o from '../output/output_ast';
import {CompileElement} from './compile_element';
import {CompileQuery} from './compile_query';
// Note: We can't do this when we create the CompileElements already,
// as we create embedded views before the <ng-template> elements themselves.
export function bindQueryValues(ce: CompileElement) {
const queriesWithReads: _QueryWithRead[] = [];
ce.getProviderTokens().forEach((token) => {
const queriesForProvider = ce.getQueriesFor(token);
queriesWithReads.push(...queriesForProvider.map(query => new _QueryWithRead(query, token)));
});
Object.keys(ce.referenceTokens).forEach(varName => {
const varToken = {value: varName};
queriesWithReads.push(
...ce.getQueriesFor(varToken).map(query => new _QueryWithRead(query, varToken)));
});
queriesWithReads.forEach((queryWithRead) => {
let value: o.Expression;
if (queryWithRead.read.identifier) {
// query for an identifier
value = ce.instances.get(tokenReference(queryWithRead.read));
} else {
// query for a reference
const token = ce.referenceTokens[queryWithRead.read.value];
if (token) {
value = ce.instances.get(tokenReference(token));
} else {
value = ce.elementRef;
}
}
if (value) {
queryWithRead.query.addValue(value, ce.view);
}
});
}
class _QueryWithRead {
public read: CompileTokenMetadata;
constructor(public query: CompileQuery, match: CompileTokenMetadata) {
this.read = query.meta.read || match;
}
}

View File

@ -1,75 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {ɵViewType as ViewType} from '@angular/core';
import {CompileTokenMetadata} from '../compile_metadata';
import {createDiTokenExpression} from '../compiler_util/identifier_util';
import * as o from '../output/output_ast';
import {CompileView} from './compile_view';
export function getPropertyInView(
property: o.Expression, callingView: CompileView, definedView: CompileView): o.Expression {
if (callingView === definedView) {
return property;
} else {
let viewProp: o.Expression = o.THIS_EXPR;
let currView: CompileView = callingView;
while (currView !== definedView && currView.declarationElement.view) {
currView = currView.declarationElement.view;
viewProp = viewProp.prop('parentView');
}
if (currView !== definedView) {
throw new Error(
`Internal error: Could not calculate a property in a parent view: ${property}`);
}
return property.visitExpression(new _ReplaceViewTransformer(viewProp, definedView), null);
}
}
class _ReplaceViewTransformer extends o.ExpressionTransformer {
constructor(private _viewExpr: o.Expression, private _view: CompileView) { super(); }
private _isThis(expr: o.Expression): boolean {
return expr instanceof o.ReadVarExpr && expr.builtin === o.BuiltinVar.This;
}
visitReadVarExpr(ast: o.ReadVarExpr, context: any): any {
return this._isThis(ast) ? this._viewExpr : ast;
}
visitReadPropExpr(ast: o.ReadPropExpr, context: any): any {
if (this._isThis(ast.receiver)) {
// Note: Don't cast for members of the AppView base class...
if (this._view.fields.some((field) => field.name == ast.name) ||
this._view.getters.some((field) => field.name == ast.name)) {
return this._viewExpr.cast(this._view.classType).prop(ast.name);
}
}
return super.visitReadPropExpr(ast, context);
}
}
export function injectFromViewParentInjector(
view: CompileView, token: CompileTokenMetadata, optional: boolean): o.Expression {
let viewExpr: o.Expression;
if (view.viewType === ViewType.HOST) {
viewExpr = o.THIS_EXPR;
} else {
viewExpr = o.THIS_EXPR.prop('parentView');
}
const args = [createDiTokenExpression(token), o.THIS_EXPR.prop('parentIndex')];
if (optional) {
args.push(o.NULL_EXPR);
}
return viewExpr.callMethod('injectorGet', args);
}
export function getHandleEventMethodName(elementIndex: number): string {
return `handleEvent_${elementIndex}`;
}

View File

@ -1,113 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {tokenReference} from '../compile_metadata';
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
import {CompileElement} from './compile_element';
import {CompileView} from './compile_view';
import {bindOutputs} from './event_binder';
import {bindDirectiveAfterContentLifecycleCallbacks, bindDirectiveAfterViewLifecycleCallbacks, bindDirectiveWrapperLifecycleCallbacks, bindInjectableDestroyLifecycleCallbacks, bindPipeDestroyLifecycleCallbacks} from './lifecycle_binder';
import {bindDirectiveHostProps, bindDirectiveInputs, bindRenderInputs, bindRenderText} from './property_binder';
import {bindQueryValues} from './query_binder';
export function bindView(
view: CompileView, parsedTemplate: TemplateAst[], schemaRegistry: ElementSchemaRegistry): void {
const visitor = new ViewBinderVisitor(view, schemaRegistry);
templateVisitAll(visitor, parsedTemplate);
view.pipes.forEach(
(pipe) => { bindPipeDestroyLifecycleCallbacks(pipe.meta, pipe.instance, pipe.view); });
}
class ViewBinderVisitor implements TemplateAstVisitor {
private _nodeIndex: number = 0;
constructor(public view: CompileView, private _schemaRegistry: ElementSchemaRegistry) {}
visitBoundText(ast: BoundTextAst, parent: CompileElement): any {
const node = this.view.nodes[this._nodeIndex++];
bindRenderText(ast, node, this.view);
return null;
}
visitText(ast: TextAst, parent: CompileElement): any {
this._nodeIndex++;
return null;
}
visitNgContent(ast: NgContentAst, parent: CompileElement): any { return null; }
visitElement(ast: ElementAst, parent: CompileElement): any {
const compileElement = <CompileElement>this.view.nodes[this._nodeIndex++];
bindQueryValues(compileElement);
const hasEvents = bindOutputs(ast.outputs, ast.directives, compileElement, true);
bindRenderInputs(ast.inputs, ast.outputs, hasEvents, compileElement);
ast.directives.forEach((directiveAst, dirIndex) => {
const directiveWrapperInstance =
compileElement.directiveWrapperInstance.get(directiveAst.directive.type.reference);
bindDirectiveInputs(directiveAst, directiveWrapperInstance, dirIndex, compileElement);
bindDirectiveHostProps(
directiveAst, directiveWrapperInstance, compileElement, ast.name, this._schemaRegistry);
});
templateVisitAll(this, ast.children, compileElement);
// afterContent and afterView lifecycles need to be called bottom up
// so that children are notified before parents
ast.directives.forEach((directiveAst) => {
const directiveInstance = compileElement.instances.get(directiveAst.directive.type.reference);
const directiveWrapperInstance =
compileElement.directiveWrapperInstance.get(directiveAst.directive.type.reference);
bindDirectiveAfterContentLifecycleCallbacks(
directiveAst.directive, directiveInstance, compileElement);
bindDirectiveAfterViewLifecycleCallbacks(
directiveAst.directive, directiveInstance, compileElement);
bindDirectiveWrapperLifecycleCallbacks(
directiveAst, directiveWrapperInstance, compileElement);
});
ast.providers.forEach((providerAst) => {
const providerInstance = compileElement.instances.get(tokenReference(providerAst.token));
bindInjectableDestroyLifecycleCallbacks(providerAst, providerInstance, compileElement);
});
return null;
}
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, parent: CompileElement): any {
const compileElement = <CompileElement>this.view.nodes[this._nodeIndex++];
bindQueryValues(compileElement);
bindOutputs(ast.outputs, ast.directives, compileElement, false);
ast.directives.forEach((directiveAst, dirIndex) => {
const directiveInstance = compileElement.instances.get(directiveAst.directive.type.reference);
const directiveWrapperInstance =
compileElement.directiveWrapperInstance.get(directiveAst.directive.type.reference);
bindDirectiveInputs(directiveAst, directiveWrapperInstance, dirIndex, compileElement);
bindDirectiveAfterContentLifecycleCallbacks(
directiveAst.directive, directiveInstance, compileElement);
bindDirectiveAfterViewLifecycleCallbacks(
directiveAst.directive, directiveInstance, compileElement);
bindDirectiveWrapperLifecycleCallbacks(
directiveAst, directiveWrapperInstance, compileElement);
});
ast.providers.forEach((providerAst) => {
const providerInstance = compileElement.instances.get(tokenReference(providerAst.token));
bindInjectableDestroyLifecycleCallbacks(providerAst, providerInstance, compileElement);
});
bindView(compileElement.embeddedView, ast.children, this._schemaRegistry);
return null;
}
visitAttr(ast: AttrAst, ctx: any): any { return null; }
visitDirective(ast: DirectiveAst, ctx: any): any { return null; }
visitEvent(ast: BoundEventAst, eventTargetAndNames: Map<string, BoundEventAst>): any {
return null;
}
visitReference(ast: ReferenceAst, ctx: any): any { return null; }
visitVariable(ast: VariableAst, ctx: any): any { return null; }
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
}

View File

@ -1,697 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {ViewEncapsulation, ɵChangeDetectorStatus as ChangeDetectorStatus, ɵViewType as ViewType, ɵisDefaultChangeDetectionStrategy as isDefaultChangeDetectionStrategy} from '@angular/core';
import {CompileDirectiveSummary, identifierModuleUrl, identifierName} from '../compile_metadata';
import {legacyCreateSharedBindingVariablesIfNeeded} from '../compiler_util/expression_converter';
import {createDiTokenExpression, createInlineArray} from '../compiler_util/identifier_util';
import {isPresent} from '../facade/lang';
import {Identifiers, createIdentifier, identifierToken} from '../identifiers';
import {createClassStmt} from '../output/class_builder';
import * as o from '../output/output_ast';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
import {CompileElement, CompileNode} from './compile_element';
import {CompileView, CompileViewRootNode, CompileViewRootNodeType} from './compile_view';
import {ChangeDetectorStatusEnum, InjectMethodVars, ViewConstructorVars, ViewEncapsulationEnum, ViewProperties, ViewTypeEnum} from './constants';
import {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency} from './deps';
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
const CLASS_ATTR = 'class';
const STYLE_ATTR = 'style';
const NG_CONTAINER_TAG = 'ng-container';
const parentRenderNodeVar = o.variable('parentRenderNode');
const rootSelectorVar = o.variable('rootSelector');
export function buildView(
view: CompileView, template: TemplateAst[],
targetDependencies:
Array<ComponentViewDependency|ComponentFactoryDependency|DirectiveWrapperDependency>):
number {
const builderVisitor = new ViewBuilderVisitor(view, targetDependencies);
const parentEl =
view.declarationElement.isNull() ? view.declarationElement : view.declarationElement.parent;
templateVisitAll(builderVisitor, template, parentEl);
if (view.viewType === ViewType.EMBEDDED || view.viewType === ViewType.HOST) {
view.lastRenderNode = builderVisitor.getOrCreateLastRenderNode();
}
return builderVisitor.nestedViewCount;
}
export function finishView(view: CompileView, targetStatements: o.Statement[]) {
view.nodes.forEach((node) => {
if (node instanceof CompileElement) {
node.finish();
if (node.hasEmbeddedView) {
finishView(node.embeddedView, targetStatements);
}
}
});
view.finish();
createViewTopLevelStmts(view, targetStatements);
}
class ViewBuilderVisitor implements TemplateAstVisitor {
nestedViewCount: number = 0;
constructor(
public view: CompileView,
public targetDependencies:
Array<ComponentViewDependency|ComponentFactoryDependency|DirectiveWrapperDependency>) {}
private _isRootNode(parent: CompileElement): boolean { return parent.view !== this.view; }
private _addRootNodeAndProject(node: CompileNode) {
const projectedNode = _getOuterContainerOrSelf(node);
const parent = projectedNode.parent;
const ngContentIndex = (<any>projectedNode.sourceAst).ngContentIndex;
const viewContainer =
(node instanceof CompileElement && node.hasViewContainer) ? node.viewContainer : null;
if (this._isRootNode(parent)) {
if (this.view.viewType !== ViewType.COMPONENT) {
this.view.rootNodes.push(new CompileViewRootNode(
viewContainer ? CompileViewRootNodeType.ViewContainer : CompileViewRootNodeType.Node,
viewContainer || node.renderNode));
}
} else if (isPresent(parent.component) && isPresent(ngContentIndex)) {
parent.addContentNode(
ngContentIndex,
new CompileViewRootNode(
viewContainer ? CompileViewRootNodeType.ViewContainer : CompileViewRootNodeType.Node,
viewContainer || node.renderNode));
}
}
private _getParentRenderNode(parent: CompileElement): o.Expression {
parent = _getOuterContainerParentOrSelf(parent);
if (this._isRootNode(parent)) {
if (this.view.viewType === ViewType.COMPONENT) {
return parentRenderNodeVar;
} else {
// root node of an embedded/host view
return o.NULL_EXPR;
}
} else {
return isPresent(parent.component) &&
parent.component.template.encapsulation !== ViewEncapsulation.Native ?
o.NULL_EXPR :
parent.renderNode;
}
}
getOrCreateLastRenderNode(): o.Expression {
const view = this.view;
if (view.rootNodes.length === 0 ||
view.rootNodes[view.rootNodes.length - 1].type !== CompileViewRootNodeType.Node) {
const fieldName = `_el_${view.nodes.length}`;
view.fields.push(
new o.ClassField(fieldName, o.importType(view.genConfig.renderTypes.renderElement)));
view.createMethod.addStmt(o.THIS_EXPR.prop(fieldName)
.set(ViewProperties.renderer.callMethod(
'createTemplateAnchor', [o.NULL_EXPR, o.NULL_EXPR]))
.toStmt());
view.rootNodes.push(
new CompileViewRootNode(CompileViewRootNodeType.Node, o.THIS_EXPR.prop(fieldName)));
}
return view.rootNodes[view.rootNodes.length - 1].expr;
}
visitBoundText(ast: BoundTextAst, parent: CompileElement): any {
return this._visitText(ast, '', parent);
}
visitText(ast: TextAst, parent: CompileElement): any {
return this._visitText(ast, ast.value, parent);
}
private _visitText(ast: TemplateAst, value: string, parent: CompileElement): o.Expression {
const fieldName = `_text_${this.view.nodes.length}`;
this.view.fields.push(
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderText)));
const renderNode = o.THIS_EXPR.prop(fieldName);
const compileNode = new CompileNode(parent, this.view, this.view.nodes.length, renderNode, ast);
const createRenderNode =
o.THIS_EXPR.prop(fieldName)
.set(ViewProperties.renderer.callMethod(
'createText',
[
this._getParentRenderNode(parent), o.literal(value),
this.view.createMethod.resetDebugInfoExpr(this.view.nodes.length, ast)
]))
.toStmt();
this.view.nodes.push(compileNode);
this.view.createMethod.addStmt(createRenderNode);
this._addRootNodeAndProject(compileNode);
return renderNode;
}
visitNgContent(ast: NgContentAst, parent: CompileElement): any {
// the projected nodes originate from a different view, so we don't
// have debug information for them...
this.view.createMethod.resetDebugInfo(null, ast);
const parentRenderNode = this._getParentRenderNode(parent);
if (parentRenderNode !== o.NULL_EXPR) {
this.view.createMethod.addStmt(
o.THIS_EXPR.callMethod('projectNodes', [parentRenderNode, o.literal(ast.index)])
.toStmt());
} else if (this._isRootNode(parent)) {
if (this.view.viewType !== ViewType.COMPONENT) {
// store root nodes only for embedded/host views
this.view.rootNodes.push(
new CompileViewRootNode(CompileViewRootNodeType.NgContent, null, ast.index));
}
} else {
if (isPresent(parent.component) && isPresent(ast.ngContentIndex)) {
parent.addContentNode(
ast.ngContentIndex,
new CompileViewRootNode(CompileViewRootNodeType.NgContent, null, ast.index));
}
}
return null;
}
visitElement(ast: ElementAst, parent: CompileElement): any {
const nodeIndex = this.view.nodes.length;
let createRenderNodeExpr: o.Expression;
const debugContextExpr = this.view.createMethod.resetDebugInfoExpr(nodeIndex, ast);
const directives = ast.directives.map(directiveAst => directiveAst.directive);
const component = directives.find(directive => directive.isComponent);
if (ast.name === NG_CONTAINER_TAG) {
createRenderNodeExpr = ViewProperties.renderer.callMethod(
'createTemplateAnchor', [this._getParentRenderNode(parent), debugContextExpr]);
} else {
const htmlAttrs = _readHtmlAttrs(ast.attrs);
const attrNameAndValues = createInlineArray(
_mergeHtmlAndDirectiveAttrs(htmlAttrs, directives).map(v => o.literal(v)));
if (nodeIndex === 0 && this.view.viewType === ViewType.HOST) {
createRenderNodeExpr =
o.importExpr(createIdentifier(Identifiers.selectOrCreateRenderHostElement)).callFn([
ViewProperties.renderer, o.literal(ast.name), attrNameAndValues, rootSelectorVar,
debugContextExpr
]);
} else {
createRenderNodeExpr =
o.importExpr(createIdentifier(Identifiers.createRenderElement)).callFn([
ViewProperties.renderer, this._getParentRenderNode(parent), o.literal(ast.name),
attrNameAndValues, debugContextExpr
]);
}
}
const fieldName = `_el_${nodeIndex}`;
this.view.fields.push(
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderElement)));
this.view.createMethod.addStmt(o.THIS_EXPR.prop(fieldName).set(createRenderNodeExpr).toStmt());
const renderNode = o.THIS_EXPR.prop(fieldName);
const compileElement = new CompileElement(
parent, this.view, nodeIndex, renderNode, ast, component, directives, ast.providers,
ast.hasViewContainer, false, ast.references);
this.view.nodes.push(compileElement);
let compViewExpr: o.ReadPropExpr = null;
if (isPresent(component)) {
this.targetDependencies.push(new ComponentViewDependency(component.type.reference));
compViewExpr = o.THIS_EXPR.prop(`compView_${nodeIndex}`); // fix highlighting: `
this.view.fields.push(new o.ClassField(
compViewExpr.name,
o.importType(createIdentifier(Identifiers.AppView), [o.importType(component.type)])));
this.view.viewChildren.push(compViewExpr);
compileElement.setComponentView(compViewExpr);
this.view.createMethod.addStmt(
compViewExpr
.set(o.importExpr({reference: component.componentViewType}).instantiate([
ViewProperties.viewUtils, o.THIS_EXPR, o.literal(nodeIndex), renderNode
]))
.toStmt());
}
compileElement.beforeChildren();
this._addRootNodeAndProject(compileElement);
templateVisitAll(this, ast.children, compileElement);
compileElement.afterChildren(this.view.nodes.length - nodeIndex - 1);
if (isPresent(compViewExpr)) {
this.view.createMethod.addStmt(
compViewExpr.callMethod('create', [compileElement.getComponent()]).toStmt());
}
return null;
}
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, parent: CompileElement): any {
const nodeIndex = this.view.nodes.length;
const fieldName = `_anchor_${nodeIndex}`;
this.view.fields.push(
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderComment)));
this.view.createMethod.addStmt(
o.THIS_EXPR.prop(fieldName)
.set(ViewProperties.renderer.callMethod(
'createTemplateAnchor',
[
this._getParentRenderNode(parent),
this.view.createMethod.resetDebugInfoExpr(nodeIndex, ast)
]))
.toStmt());
const renderNode = o.THIS_EXPR.prop(fieldName);
const templateVariableBindings = ast.variables.map(
varAst => [varAst.value.length > 0 ? varAst.value : IMPLICIT_TEMPLATE_VAR, varAst.name]);
const directives = ast.directives.map(directiveAst => directiveAst.directive);
const compileElement = new CompileElement(
parent, this.view, nodeIndex, renderNode, ast, null, directives, ast.providers,
ast.hasViewContainer, true, ast.references);
this.view.nodes.push(compileElement);
this.nestedViewCount++;
const embeddedView = new CompileView(
this.view.component, this.view.genConfig, this.view.pipeMetas, o.NULL_EXPR,
this.view.animations, this.view.viewIndex + this.nestedViewCount, compileElement,
templateVariableBindings, this.targetDependencies);
this.nestedViewCount += buildView(embeddedView, ast.children, this.targetDependencies);
compileElement.beforeChildren();
this._addRootNodeAndProject(compileElement);
compileElement.afterChildren(0);
return null;
}
visitAttr(ast: AttrAst, ctx: any): any { return null; }
visitDirective(ast: DirectiveAst, ctx: any): any { return null; }
visitEvent(ast: BoundEventAst, eventTargetAndNames: Map<string, BoundEventAst>): any {
return null;
}
visitReference(ast: ReferenceAst, ctx: any): any { return null; }
visitVariable(ast: VariableAst, ctx: any): any { return null; }
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
}
/**
* Walks up the nodes while the direct parent is a container.
*
* Returns the outer container or the node itself when it is not a direct child of a container.
*
* @internal
*/
function _getOuterContainerOrSelf(node: CompileNode): CompileNode {
const view = node.view;
while (_isNgContainer(node.parent, view)) {
node = node.parent;
}
return node;
}
/**
* Walks up the nodes while they are container and returns the first parent which is not.
*
* Returns the parent of the outer container or the node itself when it is not a container.
*
* @internal
*/
function _getOuterContainerParentOrSelf(el: CompileElement): CompileElement {
const view = el.view;
while (_isNgContainer(el, view)) {
el = el.parent;
}
return el;
}
function _isNgContainer(node: CompileNode, view: CompileView): boolean {
return !node.isNull() && (<ElementAst>node.sourceAst).name === NG_CONTAINER_TAG &&
node.view === view;
}
function _mergeHtmlAndDirectiveAttrs(
declaredHtmlAttrs: {[key: string]: string}, directives: CompileDirectiveSummary[]): string[] {
const mapResult: {[key: string]: string} = {};
Object.keys(declaredHtmlAttrs).forEach(key => { mapResult[key] = declaredHtmlAttrs[key]; });
directives.forEach(directiveMeta => {
Object.keys(directiveMeta.hostAttributes).forEach(name => {
const value = directiveMeta.hostAttributes[name];
const prevValue = mapResult[name];
mapResult[name] = isPresent(prevValue) ? mergeAttributeValue(name, prevValue, value) : value;
});
});
const arrResult: string[] = [];
// Note: We need to sort to get a defined output order
// for tests and for caching generated artifacts...
Object.keys(mapResult).sort().forEach(
(attrName) => { arrResult.push(attrName, mapResult[attrName]); });
return arrResult;
}
function _readHtmlAttrs(attrs: AttrAst[]): {[key: string]: string} {
const htmlAttrs: {[key: string]: string} = {};
attrs.forEach((ast) => { htmlAttrs[ast.name] = ast.value; });
return htmlAttrs;
}
function mergeAttributeValue(attrName: string, attrValue1: string, attrValue2: string): string {
if (attrName == CLASS_ATTR || attrName == STYLE_ATTR) {
return `${attrValue1} ${attrValue2}`;
} else {
return attrValue2;
}
}
function createViewTopLevelStmts(view: CompileView, targetStatements: o.Statement[]) {
let nodeDebugInfosVar: o.Expression = o.NULL_EXPR;
if (view.genConfig.genDebugInfo) {
nodeDebugInfosVar = o.variable(
`nodeDebugInfos_${identifierName(view.component.type)}${view.viewIndex}`); // fix
// highlighting:
// `
targetStatements.push(
(<o.ReadVarExpr>nodeDebugInfosVar)
.set(o.literalArr(
view.nodes.map(createStaticNodeDebugInfo),
new o.ArrayType(
o.importType(createIdentifier(Identifiers.StaticNodeDebugInfo)),
[o.TypeModifier.Const])))
.toDeclStmt(null, [o.StmtModifier.Final]));
}
const renderCompTypeVar: o.ReadVarExpr =
o.variable(view.rendererTypeName); // fix highlighting: `
if (view.viewIndex === 0) {
let templateUrlInfo: string;
if (view.component.template.templateUrl == identifierModuleUrl(view.component.type)) {
templateUrlInfo =
`${identifierModuleUrl(view.component.type)} class ${identifierName(view.component.type)} - inline template`;
} else {
templateUrlInfo = view.component.template.templateUrl;
}
targetStatements.push(
renderCompTypeVar
.set(o.importExpr(createIdentifier(Identifiers.createRenderComponentType)).callFn([
view.genConfig.genDebugInfo ? o.literal(templateUrlInfo) : o.literal(''),
o.literal(view.component.template.ngContentSelectors.length),
ViewEncapsulationEnum.fromValue(view.component.template.encapsulation),
view.styles,
o.literalMap(
view.animations.map((entry): [string, o.Expression] => [entry.name, entry.fnExp]),
null, true),
]))
.toDeclStmt(o.importType(createIdentifier(Identifiers.RenderComponentType))));
}
const viewClass = createViewClass(view, renderCompTypeVar, nodeDebugInfosVar);
targetStatements.push(viewClass);
}
function createStaticNodeDebugInfo(node: CompileNode): o.Expression {
const compileElement = node instanceof CompileElement ? node : null;
let providerTokens: o.Expression[] = [];
let componentToken: o.Expression = o.NULL_EXPR;
const varTokenEntries: any[] = [];
if (isPresent(compileElement)) {
providerTokens =
compileElement.getProviderTokens().map((token) => createDiTokenExpression(token));
if (isPresent(compileElement.component)) {
componentToken = createDiTokenExpression(identifierToken(compileElement.component.type));
}
Object.keys(compileElement.referenceTokens).forEach(varName => {
const token = compileElement.referenceTokens[varName];
varTokenEntries.push(
[varName, isPresent(token) ? createDiTokenExpression(token) : o.NULL_EXPR]);
});
}
return o.importExpr(createIdentifier(Identifiers.StaticNodeDebugInfo))
.instantiate(
[
o.literalArr(providerTokens, new o.ArrayType(o.DYNAMIC_TYPE, [o.TypeModifier.Const])),
componentToken,
o.literalMap(varTokenEntries, new o.MapType(o.DYNAMIC_TYPE, [o.TypeModifier.Const]))
],
o.importType(
createIdentifier(Identifiers.StaticNodeDebugInfo), null, [o.TypeModifier.Const]));
}
function createViewClass(
view: CompileView, renderCompTypeVar: o.ReadVarExpr,
nodeDebugInfosVar: o.Expression): o.ClassStmt {
const viewConstructorArgs = [
new o.FnParam(
ViewConstructorVars.viewUtils.name, o.importType(createIdentifier(Identifiers.ViewUtils))),
new o.FnParam(
ViewConstructorVars.parentView.name,
o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
new o.FnParam(ViewConstructorVars.parentIndex.name, o.NUMBER_TYPE),
new o.FnParam(ViewConstructorVars.parentElement.name, o.DYNAMIC_TYPE)
];
const superConstructorArgs = [
o.variable(view.className), renderCompTypeVar, ViewTypeEnum.fromValue(view.viewType),
ViewConstructorVars.viewUtils, ViewConstructorVars.parentView, ViewConstructorVars.parentIndex,
ViewConstructorVars.parentElement,
ChangeDetectorStatusEnum.fromValue(getChangeDetectionMode(view))
];
if (view.genConfig.genDebugInfo) {
superConstructorArgs.push(nodeDebugInfosVar);
}
if (view.viewType === ViewType.EMBEDDED) {
viewConstructorArgs.push(new o.FnParam(
'declaredViewContainer', o.importType(createIdentifier(Identifiers.ViewContainer))));
superConstructorArgs.push(o.variable('declaredViewContainer'));
}
const viewMethods = [
new o.ClassMethod(
'createInternal', [new o.FnParam(rootSelectorVar.name, o.STRING_TYPE)],
generateCreateMethod(view),
o.importType(createIdentifier(Identifiers.ComponentRef), [o.DYNAMIC_TYPE])),
new o.ClassMethod(
'injectorGetInternal',
[
new o.FnParam(InjectMethodVars.token.name, o.DYNAMIC_TYPE),
// Note: Can't use o.INT_TYPE here as the method in AppView uses number
new o.FnParam(InjectMethodVars.requestNodeIndex.name, o.NUMBER_TYPE),
new o.FnParam(InjectMethodVars.notFoundResult.name, o.DYNAMIC_TYPE)
],
addReturnValuefNotEmpty(view.injectorGetMethod.finish(), InjectMethodVars.notFoundResult),
o.DYNAMIC_TYPE),
new o.ClassMethod('detectChangesInternal', [], generateDetectChangesMethod(view)),
new o.ClassMethod('dirtyParentQueriesInternal', [], view.dirtyParentQueriesMethod.finish()),
new o.ClassMethod('destroyInternal', [], generateDestroyMethod(view)),
new o.ClassMethod('detachInternal', [], view.detachMethod.finish()),
generateVisitRootNodesMethod(view), generateVisitProjectableNodesMethod(view),
generateCreateEmbeddedViewsMethod(view)
].filter((method) => method.body.length > 0);
const superClass = view.genConfig.genDebugInfo ? Identifiers.DebugAppView : Identifiers.AppView;
const viewClass = createClassStmt({
name: view.className,
parent: o.importExpr(createIdentifier(superClass), [getContextType(view)]),
parentArgs: superConstructorArgs,
ctorParams: viewConstructorArgs,
builders: [{methods: viewMethods}, view]
});
return viewClass;
}
function generateDestroyMethod(view: CompileView): o.Statement[] {
const stmts: o.Statement[] = [];
view.viewContainers.forEach((viewContainer) => {
stmts.push(viewContainer.callMethod('destroyNestedViews', []).toStmt());
});
view.viewChildren.forEach(
(viewChild) => { stmts.push(viewChild.callMethod('destroy', []).toStmt()); });
stmts.push(...view.destroyMethod.finish());
return stmts;
}
function generateCreateMethod(view: CompileView): o.Statement[] {
let parentRenderNodeExpr: o.Expression = o.NULL_EXPR;
let parentRenderNodeStmts: any[] = [];
if (view.viewType === ViewType.COMPONENT) {
parentRenderNodeExpr =
ViewProperties.renderer.callMethod('createViewRoot', [o.THIS_EXPR.prop('parentElement')]);
parentRenderNodeStmts =
[parentRenderNodeVar.set(parentRenderNodeExpr)
.toDeclStmt(
o.importType(view.genConfig.renderTypes.renderNode), [o.StmtModifier.Final])];
}
let resultExpr: o.Expression;
if (view.viewType === ViewType.HOST) {
const hostEl = <CompileElement>view.nodes[0];
resultExpr =
o.importExpr(createIdentifier(Identifiers.ComponentRef_), [o.DYNAMIC_TYPE]).instantiate([
o.literal(hostEl.nodeIndex), o.THIS_EXPR, hostEl.renderNode, hostEl.getComponent()
]);
} else {
resultExpr = o.NULL_EXPR;
}
const allNodesExpr: o.Expression =
ViewProperties.renderer.cast(o.DYNAMIC_TYPE)
.prop('directRenderer')
.conditional(o.NULL_EXPR, o.literalArr(view.nodes.map(node => node.renderNode)));
return parentRenderNodeStmts.concat(view.createMethod.finish(), [
o.THIS_EXPR
.callMethod(
'init',
[
view.lastRenderNode,
allNodesExpr,
view.disposables.length ? o.literalArr(view.disposables) : o.NULL_EXPR,
])
.toStmt(),
new o.ReturnStatement(resultExpr)
]);
}
function generateDetectChangesMethod(view: CompileView): o.Statement[] {
const stmts: any[] = [];
if (view.animationBindingsMethod.isEmpty() && view.detectChangesInInputsMethod.isEmpty() &&
view.updateContentQueriesMethod.isEmpty() &&
view.afterContentLifecycleCallbacksMethod.isEmpty() &&
view.detectChangesRenderPropertiesMethod.isEmpty() &&
view.updateViewQueriesMethod.isEmpty() && view.afterViewLifecycleCallbacksMethod.isEmpty() &&
view.viewContainers.length === 0 && view.viewChildren.length === 0) {
return stmts;
}
stmts.push(...view.animationBindingsMethod.finish());
stmts.push(...view.detectChangesInInputsMethod.finish());
view.viewContainers.forEach((viewContainer) => {
stmts.push(
viewContainer.callMethod('detectChangesInNestedViews', [ViewProperties.throwOnChange])
.toStmt());
});
const afterContentStmts = view.updateContentQueriesMethod.finish().concat(
view.afterContentLifecycleCallbacksMethod.finish());
if (afterContentStmts.length > 0) {
stmts.push(new o.IfStmt(o.not(ViewProperties.throwOnChange), afterContentStmts));
}
stmts.push(...view.detectChangesRenderPropertiesMethod.finish());
view.viewChildren.forEach((viewChild) => {
stmts.push(
viewChild.callMethod('internalDetectChanges', [ViewProperties.throwOnChange]).toStmt());
});
const afterViewStmts =
view.updateViewQueriesMethod.finish().concat(view.afterViewLifecycleCallbacksMethod.finish());
if (afterViewStmts.length > 0) {
stmts.push(new o.IfStmt(o.not(ViewProperties.throwOnChange), afterViewStmts));
}
const varStmts = legacyCreateSharedBindingVariablesIfNeeded(stmts);
return varStmts.concat(stmts);
}
function addReturnValuefNotEmpty(statements: o.Statement[], value: o.Expression): o.Statement[] {
if (statements.length > 0) {
return statements.concat([new o.ReturnStatement(value)]);
} else {
return statements;
}
}
function getContextType(view: CompileView): o.Type {
if (view.viewType === ViewType.COMPONENT) {
return o.importType(view.component.type);
}
return o.DYNAMIC_TYPE;
}
function getChangeDetectionMode(view: CompileView): ChangeDetectorStatus {
let mode: ChangeDetectorStatus;
if (view.viewType === ViewType.COMPONENT) {
mode = isDefaultChangeDetectionStrategy(view.component.changeDetection) ?
ChangeDetectorStatus.CheckAlways :
ChangeDetectorStatus.CheckOnce;
} else {
mode = ChangeDetectorStatus.CheckAlways;
}
return mode;
}
function generateVisitRootNodesMethod(view: CompileView): o.ClassMethod {
const cbVar = o.variable('cb');
const ctxVar = o.variable('ctx');
const stmts: o.Statement[] = generateVisitNodesStmts(view.rootNodes, cbVar, ctxVar);
return new o.ClassMethod(
'visitRootNodesInternal',
[new o.FnParam(cbVar.name, o.DYNAMIC_TYPE), new o.FnParam(ctxVar.name, o.DYNAMIC_TYPE)],
stmts);
}
function generateVisitProjectableNodesMethod(view: CompileView): o.ClassMethod {
const nodeIndexVar = o.variable('nodeIndex');
const ngContentIndexVar = o.variable('ngContentIndex');
const cbVar = o.variable('cb');
const ctxVar = o.variable('ctx');
const stmts: o.Statement[] = [];
view.nodes.forEach((node) => {
if (node instanceof CompileElement && node.component) {
node.contentNodesByNgContentIndex.forEach((projectedNodes, ngContentIndex) => {
stmts.push(new o.IfStmt(
nodeIndexVar.equals(o.literal(node.nodeIndex))
.and(ngContentIndexVar.equals(o.literal(ngContentIndex))),
generateVisitNodesStmts(projectedNodes, cbVar, ctxVar)));
});
}
});
return new o.ClassMethod(
'visitProjectableNodesInternal',
[
new o.FnParam(nodeIndexVar.name, o.NUMBER_TYPE),
new o.FnParam(ngContentIndexVar.name, o.NUMBER_TYPE),
new o.FnParam(cbVar.name, o.DYNAMIC_TYPE), new o.FnParam(ctxVar.name, o.DYNAMIC_TYPE)
],
stmts);
}
function generateVisitNodesStmts(
nodes: CompileViewRootNode[], cb: o.Expression, ctx: o.Expression): o.Statement[] {
const stmts: o.Statement[] = [];
nodes.forEach((node) => {
switch (node.type) {
case CompileViewRootNodeType.Node:
stmts.push(cb.callFn([node.expr, ctx]).toStmt());
break;
case CompileViewRootNodeType.ViewContainer:
stmts.push(cb.callFn([node.expr.prop('nativeElement'), ctx]).toStmt());
stmts.push(node.expr.callMethod('visitNestedViewRootNodes', [cb, ctx]).toStmt());
break;
case CompileViewRootNodeType.NgContent:
stmts.push(
o.THIS_EXPR.callMethod('visitProjectedNodes', [o.literal(node.ngContentIndex), cb, ctx])
.toStmt());
break;
}
});
return stmts;
}
function generateCreateEmbeddedViewsMethod(view: CompileView): o.ClassMethod {
const nodeIndexVar = o.variable('nodeIndex');
const stmts: o.Statement[] = [];
view.nodes.forEach((node) => {
if (node instanceof CompileElement) {
if (node.embeddedView) {
stmts.push(new o.IfStmt(
nodeIndexVar.equals(o.literal(node.nodeIndex)),
[new o.ReturnStatement(node.embeddedView.classExpr.instantiate([
ViewProperties.viewUtils, o.THIS_EXPR, o.literal(node.nodeIndex), node.renderNode,
node.viewContainer
]))]));
}
}
});
if (stmts.length > 0) {
stmts.push(new o.ReturnStatement(o.NULL_EXPR));
}
return new o.ClassMethod(
'createEmbeddedViewInternal', [new o.FnParam(nodeIndexVar.name, o.NUMBER_TYPE)], stmts,
o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE]));
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
# Compiler Integration for new View Engine
This folder contains the code to integrate the compiler with the new view engine.
Note: This is work in progress, and once complete will replace the regular view_compiler folder.

View File

@ -23,7 +23,6 @@ const minCoreIndex = `
export * from './src/di/metadata';
export * from './src/di/injector';
export * from './src/di/injection_token';
export * from './src/animation/metadata';
export * from './src/linker';
export * from './src/render';
export * from './src/codegen_private_exports';
@ -115,19 +114,6 @@ describe('compiler (bundled Angular)', () => {
expect(generatedFiles.find(f => /app\.module\.ngfactory\.ts/.test(f.genFileUrl)))
.toBeDefined();
})));
it('should compile with view engine',
async(() => compile(host, aotHost, expectNoDiagnostics, undefined, {
useViewEngine: true
}).then(generatedFiles => {
const genCompFile =
generatedFiles.find(f => /app\.component\.ngfactory\.ts/.test(f.genFileUrl));
expect(genCompFile).toBeDefined();
expect(genCompFile.source).toContain('ViewDefinition');
expect(genCompFile.source).not.toContain('AppView');
expect(generatedFiles.find(f => /app\.module\.ngfactory\.ts/.test(f.genFileUrl)))
.toBeDefined();
})));
});
});

View File

@ -1,63 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {createInlineArray} from '../../src/compiler_util/identifier_util';
import {Identifiers, createIdentifier} from '../../src/identifiers';
import * as o from '../../src/output/output_ast';
export function main() {
describe('createInlineArray', () => {
function check(argCount: number, expectedIdentifier: any) {
const args = createArgs(argCount);
expect(createInlineArray(args))
.toEqual(o.importExpr(createIdentifier(expectedIdentifier)).instantiate([
<o.Expression>o.literal(argCount)
].concat(args)));
}
function createArgs(count: number): o.Expression[] {
const result: o.Expression[] = [];
for (let i = 0; i < count; i++) {
result.push(o.NULL_EXPR);
}
return result;
}
it('should work for arrays of length 0', () => {
expect(createInlineArray([
])).toEqual(o.importExpr(createIdentifier(Identifiers.EMPTY_INLINE_ARRAY)));
});
it('should work for arrays of length 1 - 2', () => {
check(1, Identifiers.inlineArrays[0]);
check(2, Identifiers.inlineArrays[1]);
});
it('should work for arrays of length 3 - 4', () => {
for (let i = 3; i <= 4; i++) {
check(i, Identifiers.inlineArrays[2]);
}
});
it('should work for arrays of length 5 - 8', () => {
for (let i = 5; i <= 8; i++) {
check(i, Identifiers.inlineArrays[3]);
}
});
it('should work for arrays of length 9 - 16', () => {
for (let i = 9; i <= 16; i++) {
check(i, Identifiers.inlineArrays[4]);
}
});
it('should work for arrays of length > 16',
() => { check(17, Identifiers.InlineArrayDynamic); });
});
}

View File

@ -135,7 +135,7 @@ export function main() {
new class extends NullVisitor{
visitElementProperty(ast: BoundElementPropertyAst, context: any): any{return ast;}
},
new BoundElementPropertyAst('foo', null, null, false, null, 'bar', null));
new BoundElementPropertyAst('foo', null, null, null, 'bar', null));
});
it('should visit AttrAst', () => {
@ -182,7 +182,7 @@ export function main() {
new ElementAst('foo', [], [], [], [], [], [], false, [], [], 0, null, null),
new ReferenceAst('foo', null, null), new VariableAst('foo', 'bar', null),
new BoundEventAst('foo', 'bar', 'goo', null, null),
new BoundElementPropertyAst('foo', null, null, false, null, 'bar', null),
new BoundElementPropertyAst('foo', null, null, null, 'bar', null),
new AttrAst('foo', 'bar', null), new BoundTextAst(null, 0, null),
new TextAst('foo', 0, null), new DirectiveAst(null, [], [], [], 0, null),
new BoundDirectivePropertyAst('foo', 'bar', null, null)

View File

@ -1,65 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {CompileIdentifierMetadata} from '../../src/compile_metadata';
import * as o from '../../src/output/output_ast';
import {CompileView} from '../../src/view_compiler/compile_view';
import {getPropertyInView} from '../../src/view_compiler/util';
export function main() {
describe('getPropertyInView', () => {
it('should return the expression if it is the same view', () => {
const expr = o.THIS_EXPR.prop('someProp');
const callingView = createCompileView({className: 'view'});
expect(getPropertyInView(expr, callingView, callingView)).toBe(expr);
});
it('should access an unknown property in a parent view', () => {
const expr = o.THIS_EXPR.prop('someProp');
const definedView = createCompileView({className: 'parentView'});
const callingView = createCompileView({className: 'childView', parent: definedView});
expect(getPropertyInView(expr, callingView, definedView))
.toEqual(o.THIS_EXPR.prop('parentView').prop('someProp'));
});
it('should access a known property in a parent view with cast', () => {
const expr = o.THIS_EXPR.prop('someProp');
const definedView = createCompileView({className: 'parentView', fields: ['someProp']});
const callingView = createCompileView({className: 'childView', parent: definedView});
expect(getPropertyInView(expr, callingView, definedView))
.toEqual(o.THIS_EXPR.prop('parentView').cast(definedView.classType).prop('someProp'));
});
it('should access a known property in a parent view with cast also for property chain expressions',
() => {
const expr = o.THIS_EXPR.prop('someProp').prop('context');
const definedView = createCompileView({className: 'parentView', fields: ['someProp']});
const callingView = createCompileView({className: 'childView', parent: definedView});
expect(getPropertyInView(expr, callingView, definedView))
.toEqual(o.THIS_EXPR.prop('parentView')
.cast(definedView.classType)
.prop('someProp')
.prop('context'));
});
});
}
function createCompileView(config: {className: string, parent?: CompileView, fields?: string[]}):
CompileView {
const declarationElement: any = config.parent ? {view: config.parent} : {view: null};
const fields: o.ClassField[] = [];
if (config.fields) {
config.fields.forEach((fieldName) => { fields.push(new o.ClassField(fieldName)); });
}
return <any>{
classType: o.importType({reference: null}),
fields: fields,
getters: [],
declarationElement: declarationElement
};
}

View File

@ -1,12 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 FILL_STYLE_FLAG = 'true'; // TODO (matsko): change to boolean
export const ANY_STATE = '*';
export const DEFAULT_STATE = '*';
export const EMPTY_STATE = 'void';

View File

@ -1,110 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {isPresent, scheduleMicroTask} from '../facade/lang';
import {AnimationPlayer} from './animation_player';
export class AnimationGroupPlayer implements AnimationPlayer {
private _onDoneFns: Function[] = [];
private _onStartFns: Function[] = [];
private _finished = false;
private _started = false;
private _destroyed = false;
private _onDestroyFns: Function[] = [];
public parentPlayer: AnimationPlayer = null;
constructor(private _players: AnimationPlayer[]) {
let count = 0;
const total = this._players.length;
if (total == 0) {
scheduleMicroTask(() => this._onFinish());
} else {
this._players.forEach(player => {
player.parentPlayer = this;
player.onDone(() => {
if (++count >= total) {
this._onFinish();
}
});
});
}
}
private _onFinish() {
if (!this._finished) {
this._finished = true;
this._onDoneFns.forEach(fn => fn());
this._onDoneFns = [];
}
}
init(): void { this._players.forEach(player => player.init()); }
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() { return this._started; }
play() {
if (!isPresent(this.parentPlayer)) {
this.init();
}
if (!this.hasStarted()) {
this._onStartFns.forEach(fn => fn());
this._onStartFns = [];
this._started = true;
}
this._players.forEach(player => player.play());
}
pause(): void { this._players.forEach(player => player.pause()); }
restart(): void { this._players.forEach(player => player.restart()); }
finish(): void {
this._onFinish();
this._players.forEach(player => player.finish());
}
destroy(): void {
if (!this._destroyed) {
this._onFinish();
this._players.forEach(player => player.destroy());
this._destroyed = true;
this._onDestroyFns.forEach(fn => fn());
this._onDestroyFns = [];
}
}
reset(): void {
this._players.forEach(player => player.reset());
this._destroyed = false;
this._finished = false;
this._started = false;
}
setPosition(p: number): void {
this._players.forEach(player => { player.setPosition(p); });
}
getPosition(): number {
let min = 0;
this._players.forEach(player => {
const p = player.getPosition();
min = Math.min(p, min);
});
return min;
}
get players(): AnimationPlayer[] { return this._players; }
}

View File

@ -1,23 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {AnimationStyles} from './animation_styles';
/**
* `AnimationKeyframe` consists of a series of styles (contained within {@link AnimationStyles
* `AnimationStyles`})
* and an offset value indicating when those styles are applied within the `duration/delay/easing`
* timings.
* `AnimationKeyframe` is mostly an internal class which is designed to be used alongside {@link
* Renderer#animate-anchor `Renderer.animate`}.
*
* @experimental Animation support is experimental
*/
export class AnimationKeyframe {
constructor(public offset: number, public styles: AnimationStyles) {}
}

View File

@ -1,75 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {scheduleMicroTask} from '../facade/lang';
/**
* @experimental Animation support is experimental.
*/
export abstract class AnimationPlayer {
abstract onDone(fn: () => void): void;
abstract onStart(fn: () => void): void;
abstract onDestroy(fn: () => void): void;
abstract init(): void;
abstract hasStarted(): boolean;
abstract play(): void;
abstract pause(): void;
abstract restart(): void;
abstract finish(): void;
abstract destroy(): void;
abstract reset(): void;
abstract setPosition(p: any /** TODO #9100 */): void;
abstract getPosition(): number;
get parentPlayer(): AnimationPlayer { throw new Error('NOT IMPLEMENTED: Base Class'); }
set parentPlayer(player: AnimationPlayer) { throw new Error('NOT IMPLEMENTED: Base Class'); }
}
export class NoOpAnimationPlayer implements AnimationPlayer {
private _onDoneFns: Function[] = [];
private _onStartFns: Function[] = [];
private _onDestroyFns: Function[] = [];
private _started = false;
private _destroyed = false;
private _finished = false;
public parentPlayer: AnimationPlayer = null;
constructor() { scheduleMicroTask(() => this._onFinish()); }
private _onFinish() {
if (!this._finished) {
this._finished = true;
this._onDoneFns.forEach(fn => fn());
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; }
init(): void {}
play(): void {
if (!this.hasStarted()) {
this._onStartFns.forEach(fn => fn());
this._onStartFns = [];
}
this._started = true;
}
pause(): void {}
restart(): void {}
finish(): void { this._onFinish(); }
destroy(): void {
if (!this._destroyed) {
this._destroyed = true;
this.finish();
this._onDestroyFns.forEach(fn => fn());
this._onDestroyFns = [];
}
}
reset(): void {}
setPosition(p: number): void {}
getPosition(): number { return 0; }
}

View File

@ -1,51 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {Injectable} from '../di/metadata';
import {NgZone} from '../zone/ng_zone';
import {AnimationPlayer} from './animation_player';
@Injectable()
export class AnimationQueue {
public entries: AnimationPlayer[] = [];
constructor(private _zone: NgZone) {}
enqueue(player: AnimationPlayer) { this.entries.push(player); }
flush() {
// given that each animation player may set aside
// microtasks and rely on DOM-based events, this
// will cause Angular to run change detection after
// each request. This sidesteps the issue. If a user
// hooks into an animation via (@anim.start) or (@anim.done)
// then those methods will automatically trigger change
// detection by wrapping themselves inside of a zone
if (this.entries.length) {
this._zone.runOutsideAngular(() => {
// this code is wrapped into a single promise such that the
// onStart and onDone player callbacks are triggered outside
// of the digest cycle of animations
Promise.resolve(null).then(() => this._triggerAnimations());
});
}
}
private _triggerAnimations() {
NgZone.assertNotInAngularZone();
while (this.entries.length) {
const player = this.entries.shift();
// in the event that an animation throws an error then we do
// not want to re-run animations on any previous animations
// if they have already been kicked off beforehand
if (!player.hasStarted()) {
player.play();
}
}
}
}

View File

@ -1,117 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {isPresent, scheduleMicroTask} from '../facade/lang';
import {AnimationPlayer, NoOpAnimationPlayer} from './animation_player';
export class AnimationSequencePlayer implements AnimationPlayer {
private _currentIndex: number = 0;
private _activePlayer: AnimationPlayer;
private _onDoneFns: Function[] = [];
private _onStartFns: Function[] = [];
private _onDestroyFns: Function[] = [];
private _finished = false;
private _started = false;
private _destroyed = false;
public parentPlayer: AnimationPlayer = null;
constructor(private _players: AnimationPlayer[]) {
this._players.forEach(player => { player.parentPlayer = this; });
this._onNext(false);
}
private _onNext(start: boolean) {
if (this._finished) return;
if (this._players.length == 0) {
this._activePlayer = new NoOpAnimationPlayer();
scheduleMicroTask(() => this._onFinish());
} else if (this._currentIndex >= this._players.length) {
this._activePlayer = new NoOpAnimationPlayer();
this._onFinish();
} else {
const player = this._players[this._currentIndex++];
player.onDone(() => this._onNext(true));
this._activePlayer = player;
if (start) {
player.play();
}
}
}
private _onFinish() {
if (!this._finished) {
this._finished = true;
this._onDoneFns.forEach(fn => fn());
this._onDoneFns = [];
}
}
init(): void { this._players.forEach(player => player.init()); }
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() { return this._started; }
play(): void {
if (!isPresent(this.parentPlayer)) {
this.init();
}
if (!this.hasStarted()) {
this._onStartFns.forEach(fn => fn());
this._onStartFns = [];
this._started = true;
}
this._activePlayer.play();
}
pause(): void { this._activePlayer.pause(); }
restart(): void {
this.reset();
if (this._players.length > 0) {
this._players[0].restart();
}
}
reset(): void {
this._players.forEach(player => player.reset());
this._destroyed = false;
this._finished = false;
this._started = false;
}
finish(): void {
this._onFinish();
this._players.forEach(player => player.finish());
}
destroy(): void {
if (!this._destroyed) {
this._onFinish();
this._players.forEach(player => player.destroy());
this._destroyed = true;
this._activePlayer = new NoOpAnimationPlayer();
this._onDestroyFns.forEach(fn => fn());
this._onDestroyFns = [];
}
}
setPosition(p: number): void { this._players[0].setPosition(p); }
getPosition(): number { return this._players[0].getPosition(); }
get players(): AnimationPlayer[] { return this._players; }
}

View File

@ -1,128 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {StringMapWrapper} from '../facade/collection';
import {isPresent} from '../facade/lang';
import {FILL_STYLE_FLAG} from './animation_constants';
import {AUTO_STYLE} from './metadata';
export function prepareFinalAnimationStyles(
previousStyles: {[key: string]: string | number}, newStyles: {[key: string]: string | number},
nullValue: string = null): {[key: string]: string} {
const finalStyles: {[key: string]: string} = {};
Object.keys(newStyles).forEach(prop => {
const value = newStyles[prop];
finalStyles[prop] = value == AUTO_STYLE ? nullValue : value.toString();
});
Object.keys(previousStyles).forEach(prop => {
if (!isPresent(finalStyles[prop])) {
finalStyles[prop] = nullValue;
}
});
return finalStyles;
}
export function balanceAnimationKeyframes(
collectedStyles: {[key: string]: string | number},
finalStateStyles: {[key: string]: string | number}, keyframes: any[]): any[] {
const limit = keyframes.length - 1;
const firstKeyframe = keyframes[0];
// phase 1: copy all the styles from the first keyframe into the lookup map
const flatenedFirstKeyframeStyles = flattenStyles(firstKeyframe.styles.styles);
const extraFirstKeyframeStyles: {[key: string]: string} = {};
let hasExtraFirstStyles = false;
Object.keys(collectedStyles).forEach(prop => {
const value = collectedStyles[prop] as string;
// if the style is already defined in the first keyframe then
// we do not replace it.
if (!flatenedFirstKeyframeStyles[prop]) {
flatenedFirstKeyframeStyles[prop] = value;
extraFirstKeyframeStyles[prop] = value;
hasExtraFirstStyles = true;
}
});
const keyframeCollectedStyles = StringMapWrapper.merge({}, flatenedFirstKeyframeStyles);
// phase 2: normalize the final keyframe
const finalKeyframe = keyframes[limit];
finalKeyframe.styles.styles.unshift(finalStateStyles);
const flatenedFinalKeyframeStyles = flattenStyles(finalKeyframe.styles.styles);
const extraFinalKeyframeStyles: {[key: string]: string} = {};
let hasExtraFinalStyles = false;
Object.keys(keyframeCollectedStyles).forEach(prop => {
if (!isPresent(flatenedFinalKeyframeStyles[prop])) {
extraFinalKeyframeStyles[prop] = AUTO_STYLE;
hasExtraFinalStyles = true;
}
});
if (hasExtraFinalStyles) {
finalKeyframe.styles.styles.push(extraFinalKeyframeStyles);
}
Object.keys(flatenedFinalKeyframeStyles).forEach(prop => {
if (!isPresent(flatenedFirstKeyframeStyles[prop])) {
extraFirstKeyframeStyles[prop] = AUTO_STYLE;
hasExtraFirstStyles = true;
}
});
if (hasExtraFirstStyles) {
firstKeyframe.styles.styles.push(extraFirstKeyframeStyles);
}
collectAndResolveStyles(collectedStyles, [finalStateStyles]);
return keyframes;
}
export function clearStyles(styles: {[key: string]: string | number}): {[key: string]: string} {
const finalStyles: {[key: string]: string} = {};
Object.keys(styles).forEach(key => { finalStyles[key] = null; });
return finalStyles;
}
export function collectAndResolveStyles(
collection: {[key: string]: string | number}, styles: {[key: string]: string | number}[]) {
return styles.map(entry => {
const stylesObj: {[key: string]: string | number} = {};
Object.keys(entry).forEach(prop => {
let value = entry[prop];
if (value == FILL_STYLE_FLAG) {
value = collection[prop];
if (!isPresent(value)) {
value = AUTO_STYLE;
}
}
collection[prop] = value;
stylesObj[prop] = value;
});
return stylesObj;
});
}
export function renderStyles(
element: any, renderer: any, styles: {[key: string]: string | number}): void {
Object.keys(styles).forEach(prop => { renderer.setElementStyle(element, prop, styles[prop]); });
}
export function flattenStyles(styles: {[key: string]: string | number}[]): {[key: string]: string} {
const finalStyles: {[key: string]: string} = {};
styles.forEach(entry => {
Object.keys(entry).forEach(prop => { finalStyles[prop] = entry[prop] as string; });
});
return finalStyles;
}

View File

@ -1,25 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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
*/
// having an import prevents dgeni from truncating out
// the class description in the docs. DO NOT REMOVE.
import {isPresent} from '../facade/lang';
/**
* `AnimationStyles` consists of a collection of key/value maps containing CSS-based style data
* that can either be used as initial styling data or apart of a series of keyframes within an
* animation.
* This class is mostly internal, and it is designed to be used alongside
* {@link AnimationKeyframe `AnimationKeyframe`} and {@link Renderer#animate-anchor
* `Renderer.animate`}.
*
* @experimental Animation support is experimental
*/
export class AnimationStyles {
constructor(public styles: {[key: string]: string | number}[]) {}
}

View File

@ -1,40 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {ElementRef} from '../linker/element_ref';
import {AnimationPlayer} from './animation_player';
import {AnimationTransitionEvent} from './animation_transition_event';
export class AnimationTransition {
constructor(
private _player: AnimationPlayer, private _element: ElementRef, private _triggerName: string,
private _fromState: string, private _toState: string, private _totalTime: number) {}
private _createEvent(phaseName: string): AnimationTransitionEvent {
return new AnimationTransitionEvent({
fromState: this._fromState,
toState: this._toState,
totalTime: this._totalTime,
phaseName: phaseName,
element: this._element,
triggerName: this._triggerName
});
}
onStart(callback: (event: AnimationTransitionEvent) => any): void {
const fn =
<() => void>Zone.current.wrap(() => callback(this._createEvent('start')), 'player.onStart');
this._player.onStart(fn);
}
onDone(callback: (event: AnimationTransitionEvent) => any): void {
const fn =
<() => void>Zone.current.wrap(() => callback(this._createEvent('done')), 'player.onDone');
this._player.onDone(fn);
}
}

View File

@ -1,64 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {ElementRef} from '../linker/element_ref';
/**
* An instance of this class is returned as an event parameter when an animation
* callback is captured for an animation either during the start or done phase.
*
* ```typescript
* @Component({
* host: {
* '[@myAnimationTrigger]': 'someExpression',
* '(@myAnimationTrigger.start)': 'captureStartEvent($event)',
* '(@myAnimationTrigger.done)': 'captureDoneEvent($event)',
* },
* animations: [
* trigger("myAnimationTrigger", [
* // ...
* ])
* ]
* })
* class MyComponent {
* someExpression: any = false;
* captureStartEvent(event: AnimationTransitionEvent) {
* // the toState, fromState and totalTime data is accessible from the event variable
* }
*
* captureDoneEvent(event: AnimationTransitionEvent) {
* // the toState, fromState and totalTime data is accessible from the event variable
* }
* }
* ```
*
* @experimental Animation support is experimental.
*/
export class AnimationTransitionEvent {
public fromState: string;
public toState: string;
public totalTime: number;
public phaseName: string;
public element: ElementRef;
public triggerName: string;
constructor({fromState, toState, totalTime, phaseName, element, triggerName}: {
fromState: string,
toState: string,
totalTime: number,
phaseName: string,
element: any,
triggerName: string
}) {
this.fromState = fromState;
this.toState = toState;
this.totalTime = totalTime;
this.phaseName = phaseName;
this.element = new ElementRef(element);
this.triggerName = triggerName;
}
}

View File

@ -1,644 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {isPresent} from '../facade/lang';
/**
* @experimental Animation support is experimental.
*/
export const AUTO_STYLE = '*';
/**
* Metadata representing the entry of animations.
* Instances of this class are provided via the animation DSL when the {@link trigger trigger
* animation function} is called.
*
* @experimental Animation support is experimental.
*/
export class AnimationEntryMetadata {
constructor(public name: string, public definitions: AnimationStateMetadata[]) {}
}
/**
* @experimental Animation support is experimental.
*/
export abstract class AnimationStateMetadata {}
/**
* Metadata representing the entry of animations.
* Instances of this class are provided via the animation DSL when the {@link state state animation
* function} is called.
*
* @experimental Animation support is experimental.
*/
export class AnimationStateDeclarationMetadata extends AnimationStateMetadata {
constructor(public stateNameExpr: string, public styles: AnimationStyleMetadata) { super(); }
}
/**
* Metadata representing the entry of animations.
* Instances of this class are provided via the animation DSL when the
* {@link transition transition animation function} is called.
*
* @experimental Animation support is experimental.
*/
export class AnimationStateTransitionMetadata extends AnimationStateMetadata {
constructor(
public stateChangeExpr: string|((fromState: string, toState: string) => boolean),
public steps: AnimationMetadata) {
super();
}
}
/**
* @experimental Animation support is experimental.
*/
export abstract class AnimationMetadata {}
/**
* Metadata representing the entry of animations.
* Instances of this class are provided via the animation DSL when the {@link keyframes keyframes
* animation function} is called.
*
* @experimental Animation support is experimental.
*/
export class AnimationKeyframesSequenceMetadata extends AnimationMetadata {
constructor(public steps: AnimationStyleMetadata[]) { super(); }
}
/**
* Metadata representing the entry of animations.
* Instances of this class are provided via the animation DSL when the {@link style style animation
* function} is called.
*
* @experimental Animation support is experimental.
*/
export class AnimationStyleMetadata extends AnimationMetadata {
constructor(
public styles: Array<string|{[key: string]: string | number}>, public offset: number = null) {
super();
}
}
/**
* Metadata representing the entry of animations.
* Instances of this class are provided via the animation DSL when the {@link animate animate
* animation function} is called.
*
* @experimental Animation support is experimental.
*/
export class AnimationAnimateMetadata extends AnimationMetadata {
constructor(
public timings: string|number,
public styles: AnimationStyleMetadata|AnimationKeyframesSequenceMetadata) {
super();
}
}
/**
* @experimental Animation support is experimental.
*/
export abstract class AnimationWithStepsMetadata extends AnimationMetadata {
constructor() { super(); }
get steps(): AnimationMetadata[] { throw new Error('NOT IMPLEMENTED: Base Class'); }
}
/**
* Metadata representing the entry of animations.
* Instances of this class are provided via the animation DSL when the {@link sequence sequence
* animation function} is called.
*
* @experimental Animation support is experimental.
*/
export class AnimationSequenceMetadata extends AnimationWithStepsMetadata {
constructor(private _steps: AnimationMetadata[]) { super(); }
get steps(): AnimationMetadata[] { return this._steps; }
}
/**
* Metadata representing the entry of animations.
* Instances of this class are provided via the animation DSL when the {@link group group animation
* function} is called.
*
* @experimental Animation support is experimental.
*/
export class AnimationGroupMetadata extends AnimationWithStepsMetadata {
constructor(private _steps: AnimationMetadata[]) { super(); }
get steps(): AnimationMetadata[] { return this._steps; }
}
/**
* `animate` is an animation-specific function that is designed to be used inside of Angular2's
* animation
* DSL language. If this information is new, please navigate to the
* {@link Component#animations-anchor component animations metadata
* page} to gain a better understanding of how animations in Angular2 are used.
*
* `animate` specifies an animation step that will apply the provided `styles` data for a given
* amount of
* time based on the provided `timing` expression value. Calls to `animate` are expected to be
* used within {@link sequence an animation sequence}, {@link group group}, or {@link transition
* transition}.
*
* ### Usage
*
* The `animate` function accepts two input parameters: `timing` and `styles`:
*
* - `timing` is a string based value that can be a combination of a duration with optional
* delay and easing values. The format for the expression breaks down to `duration delay easing`
* (therefore a value such as `1s 100ms ease-out` will be parse itself into `duration=1000,
* delay=100, easing=ease-out`.
* If a numeric value is provided then that will be used as the `duration` value in millisecond
* form.
* - `styles` is the style input data which can either be a call to {@link style style} or {@link
* keyframes keyframes}.
* If left empty then the styles from the destination state will be collected and used (this is
* useful when
* describing an animation step that will complete an animation by {@link
* transition#the-final-animate-call animating to the final state}).
*
* ```typescript
* // various functions for specifying timing data
* animate(500, style(...))
* animate("1s", style(...))
* animate("100ms 0.5s", style(...))
* animate("5s ease", style(...))
* animate("5s 10ms cubic-bezier(.17,.67,.88,.1)", style(...))
*
* // either style() of keyframes() can be used
* animate(500, style({ background: "red" }))
* animate(500, keyframes([
* style({ background: "blue" })),
* style({ background: "red" }))
* ])
* ```
*
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
*
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
*
* @experimental Animation support is experimental.
*/
export function animate(
timing: string | number, styles: AnimationStyleMetadata | AnimationKeyframesSequenceMetadata =
null): AnimationAnimateMetadata {
let stylesEntry = styles;
if (!isPresent(stylesEntry)) {
const EMPTY_STYLE: {[key: string]: string | number} = {};
stylesEntry = new AnimationStyleMetadata([EMPTY_STYLE], 1);
}
return new AnimationAnimateMetadata(timing, stylesEntry);
}
/**
* `group` is an animation-specific function that is designed to be used inside of Angular2's
* animation
* DSL language. If this information is new, please navigate to the
* {@link Component#animations-anchor component animations metadata
* page} to gain a better understanding of how animations in Angular2 are used.
*
* `group` specifies a list of animation steps that are all run in parallel. Grouped animations
* are useful when a series of styles must be animated/closed off
* at different statrting/ending times.
*
* The `group` function can either be used within a {@link sequence sequence} or a {@link transition
* transition}
* and it will only continue to the next instruction once all of the inner animation steps
* have completed.
*
* ### Usage
*
* The `steps` data that is passed into the `group` animation function can either consist
* of {@link style style} or {@link animate animate} function calls. Each call to `style()` or
* `animate()`
* within a group will be executed instantly (use {@link keyframes keyframes} or a
* {@link animate#usage animate() with a delay value} to offset styles to be applied at a later
* time).
*
* ```typescript
* group([
* animate("1s", { background: "black" }))
* animate("2s", { color: "white" }))
* ])
* ```
*
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
*
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
*
* @experimental Animation support is experimental.
*/
export function group(steps: AnimationMetadata[]): AnimationGroupMetadata {
return new AnimationGroupMetadata(steps);
}
/**
* `sequence` is an animation-specific function that is designed to be used inside of Angular2's
* animation
* DSL language. If this information is new, please navigate to the
* {@link Component#animations-anchor component animations metadata
* page} to gain a better understanding of how animations in Angular2 are used.
*
* `sequence` Specifies a list of animation steps that are run one by one. (`sequence` is used
* by default when an array is passed as animation data into {@link transition transition}.)
*
* The `sequence` function can either be used within a {@link group group} or a {@link transition
* transition}
* and it will only continue to the next instruction once each of the inner animation steps
* have completed.
*
* To perform animation styling in parallel with other animation steps then
* have a look at the {@link group group} animation function.
*
* ### Usage
*
* The `steps` data that is passed into the `sequence` animation function can either consist
* of {@link style style} or {@link animate animate} function calls. A call to `style()` will apply
* the
* provided styling data immediately while a call to `animate()` will apply its styling
* data over a given time depending on its timing data.
*
* ```typescript
* sequence([
* style({ opacity: 0 })),
* animate("1s", { opacity: 1 }))
* ])
* ```
*
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
*
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
*
* @experimental Animation support is experimental.
*/
export function sequence(steps: AnimationMetadata[]): AnimationSequenceMetadata {
return new AnimationSequenceMetadata(steps);
}
/**
* `style` is an animation-specific function that is designed to be used inside of Angular2's
* animation
* DSL language. If this information is new, please navigate to the
* {@link Component#animations-anchor component animations metadata
* page} to gain a better understanding of how animations in Angular2 are used.
*
* `style` declares a key/value object containing CSS properties/styles that can then
* be used for {@link state animation states}, within an {@link sequence animation sequence}, or as
* styling data for both {@link animate animate} and {@link keyframes keyframes}.
*
* ### Usage
*
* `style` takes in a key/value string map as data and expects one or more CSS property/value
* pairs to be defined.
*
* ```typescript
* // string values are used for css properties
* style({ background: "red", color: "blue" })
*
* // numerical (pixel) values are also supported
* style({ width: 100, height: 0 })
* ```
*
* #### Auto-styles (using `*`)
*
* When an asterix (`*`) character is used as a value then it will be detected from the element
* being animated
* and applied as animation data when the animation starts.
*
* This feature proves useful for a state depending on layout and/or environment factors; in such
* cases
* the styles are calculated just before the animation starts.
*
* ```typescript
* // the steps below will animate from 0 to the
* // actual height of the element
* style({ height: 0 }),
* animate("1s", style({ height: "*" }))
* ```
*
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
*
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
*
* @experimental Animation support is experimental.
*/
export function style(
tokens: string | {[key: string]: string | number} |
Array<string|{[key: string]: string | number}>): AnimationStyleMetadata {
let input: Array<{[key: string]: string | number}|string>;
let offset: number = null;
if (typeof tokens === 'string') {
input = [<string>tokens];
} else {
if (Array.isArray(tokens)) {
input = <Array<{[key: string]: string | number}>>tokens;
} else {
input = [<{[key: string]: string | number}>tokens];
}
input.forEach(entry => {
const entryOffset = (entry as any /** TODO #9100 */)['offset'];
if (isPresent(entryOffset)) {
offset = offset == null ? parseFloat(entryOffset) : offset;
}
});
}
return new AnimationStyleMetadata(input, offset);
}
/**
* `state` is an animation-specific function that is designed to be used inside of Angular2's
* animation
* DSL language. If this information is new, please navigate to the
* {@link Component#animations-anchor component animations metadata
* page} to gain a better understanding of how animations in Angular2 are used.
*
* `state` declares an animation state within the given trigger. When a state is
* active within a component then its associated styles will persist on
* the element that the trigger is attached to (even when the animation ends).
*
* To animate between states, have a look at the animation {@link transition transition}
* DSL function. To register states to an animation trigger please have a look
* at the {@link trigger trigger} function.
*
* #### The `void` state
*
* The `void` state value is a reserved word that angular uses to determine when the element is not
* apart
* of the application anymore (e.g. when an `ngIf` evaluates to false then the state of the
* associated element
* is void).
*
* #### The `*` (default) state
*
* The `*` state (when styled) is a fallback state that will be used if
* the state that is being animated is not declared within the trigger.
*
* ### Usage
*
* `state` will declare an animation state with its associated styles
* within the given trigger.
*
* - `stateNameExpr` can be one or more state names separated by commas.
* - `styles` refers to the {@link style styling data} that will be persisted on the element once
* the state
* has been reached.
*
* ```typescript
* // "void" is a reserved name for a state and is used to represent
* // the state in which an element is detached from from the application.
* state("void", style({ height: 0 }))
*
* // user-defined states
* state("closed", style({ height: 0 }))
* state("open, visible", style({ height: "*" }))
* ```
*
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
*
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
*
* @experimental Animation support is experimental.
*/
export function state(
stateNameExpr: string, styles: AnimationStyleMetadata): AnimationStateDeclarationMetadata {
return new AnimationStateDeclarationMetadata(stateNameExpr, styles);
}
/**
* `keyframes` is an animation-specific function that is designed to be used inside of Angular2's
* animation
* DSL language. If this information is new, please navigate to the
* {@link Component#animations-anchor component animations metadata
* page} to gain a better understanding of how animations in Angular2 are used.
*
* `keyframes` specifies a collection of {@link style style} entries each optionally characterized
* by an `offset` value.
*
* ### Usage
*
* The `keyframes` animation function is designed to be used alongside the {@link animate animate}
* animation function. Instead of applying animations from where they are
* currently to their destination, keyframes can describe how each style entry is applied
* and at what point within the animation arc (much like CSS Keyframe Animations do).
*
* For each `style()` entry an `offset` value can be set. Doing so allows to specifiy at
* what percentage of the animate time the styles will be applied.
*
* ```typescript
* // the provided offset values describe when each backgroundColor value is applied.
* animate("5s", keyframes([
* style({ backgroundColor: "red", offset: 0 }),
* style({ backgroundColor: "blue", offset: 0.2 }),
* style({ backgroundColor: "orange", offset: 0.3 }),
* style({ backgroundColor: "black", offset: 1 })
* ]))
* ```
*
* Alternatively, if there are no `offset` values used within the style entries then the offsets
* will
* be calculated automatically.
*
* ```typescript
* animate("5s", keyframes([
* style({ backgroundColor: "red" }) // offset = 0
* style({ backgroundColor: "blue" }) // offset = 0.33
* style({ backgroundColor: "orange" }) // offset = 0.66
* style({ backgroundColor: "black" }) // offset = 1
* ]))
* ```
*
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
*
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
*
* @experimental Animation support is experimental.
*/
export function keyframes(steps: AnimationStyleMetadata[]): AnimationKeyframesSequenceMetadata {
return new AnimationKeyframesSequenceMetadata(steps);
}
/**
* `transition` is an animation-specific function that is designed to be used inside of Angular2's
* animation
* DSL language. If this information is new, please navigate to the
* {@link Component#animations-anchor component animations metadata
* page} to gain a better understanding of how animations in Angular2 are used.
*
* `transition` declares the {@link sequence sequence of animation steps} that will be run when the
* provided
* `stateChangeExpr` value is satisfied. The `stateChangeExpr` consists of a `state1 => state2`
* which consists
* of two known states (use an asterix (`*`) to refer to a dynamic starting and/or ending state).
*
* A function can also be provided as the `stateChangeExpr` argument for a transition and this
* function will be executed each time a state change occurs. If the value returned within the
* function is true then the associated animation will be run.
*
* Animation transitions are placed within an {@link trigger animation trigger}. For an transition
* to animate to
* a state value and persist its styles then one or more {@link state animation states} is expected
* to be defined.
*
* ### Usage
*
* An animation transition is kicked off the `stateChangeExpr` predicate evaluates to true based on
* what the
* previous state is and what the current state has become. In other words, if a transition is
* defined that
* matches the old/current state criteria then the associated animation will be triggered.
*
* ```typescript
* // all transition/state changes are defined within an animation trigger
* trigger("myAnimationTrigger", [
* // if a state is defined then its styles will be persisted when the
* // animation has fully completed itself
* state("on", style({ background: "green" })),
* state("off", style({ background: "grey" })),
*
* // a transition animation that will be kicked off when the state value
* // bound to "myAnimationTrigger" changes from "on" to "off"
* transition("on => off", animate(500)),
*
* // it is also possible to do run the same animation for both directions
* transition("on <=> off", animate(500)),
*
* // or to define multiple states pairs separated by commas
* transition("on => off, off => void", animate(500)),
*
* // this is a catch-all state change for when an element is inserted into
* // the page and the destination state is unknown
* transition("void => *", [
* style({ opacity: 0 }),
* animate(500)
* ]),
*
* // this will capture a state change between any states
* transition("* => *", animate("1s 0s")),
*
* // you can also go full out and include a function
* transition((fromState, toState) => {
* // when `true` then it will allow the animation below to be invoked
* return fromState == "off" && toState == "on";
* }, animate("1s 0s"))
* ])
* ```
*
* The template associated with this component will make use of the `myAnimationTrigger`
* animation trigger by binding to an element within its template code.
*
* ```html
* <!-- somewhere inside of my-component-tpl.html -->
* <div [@myAnimationTrigger]="myStatusExp">...</div>
* ```
*
* #### The final `animate` call
*
* If the final step within the transition steps is a call to `animate()` that **only**
* uses a timing value with **no style data** then it will be automatically used as the final
* animation
* arc for the element to animate itself to the final state. This involves an automatic mix of
* adding/removing CSS styles so that the element will be in the exact state it should be for the
* applied state to be presented correctly.
*
* ```
* // start off by hiding the element, but make sure that it animates properly to whatever state
* // is currently active for "myAnimationTrigger"
* transition("void => *", [
* style({ opacity: 0 }),
* animate(500)
* ])
* ```
*
* ### Transition Aliases (`:enter` and `:leave`)
*
* Given that enter (insertion) and leave (removal) animations are so common,
* the `transition` function accepts both `:enter` and `:leave` values which
* are aliases for the `void => *` and `* => void` state changes.
*
* ```
* transition(":enter", [
* style({ opacity: 0 }),
* animate(500, style({ opacity: 1 }))
* ])
* transition(":leave", [
* animate(500, style({ opacity: 0 }))
* ])
* ```
*
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
*
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
*
* @experimental Animation support is experimental.
*/
export function transition(
stateChangeExpr: string | ((fromState: string, toState: string) => boolean),
steps: AnimationMetadata | AnimationMetadata[]): AnimationStateTransitionMetadata {
const animationData = Array.isArray(steps) ? new AnimationSequenceMetadata(steps) : steps;
return new AnimationStateTransitionMetadata(stateChangeExpr, animationData);
}
/**
* `trigger` is an animation-specific function that is designed to be used inside of Angular2's
* animation
* DSL language. If this information is new, please navigate to the
* {@link Component#animations-anchor component animations metadata
* page} to gain a better understanding of how animations in Angular2 are used.
*
* `trigger` Creates an animation trigger which will a list of {@link state state} and {@link
* transition transition}
* entries that will be evaluated when the expression bound to the trigger changes.
*
* Triggers are registered within the component annotation data under the
* {@link Component#animations-anchor animations section}. An animation trigger can
* be placed on an element within a template by referencing the name of the
* trigger followed by the expression value that the trigger is bound to
* (in the form of `[@triggerName]="expression"`.
*
* ### Usage
*
* `trigger` will create an animation trigger reference based on the provided `name` value.
* The provided `animation` value is expected to be an array consisting of {@link state state} and
* {@link transition transition}
* declarations.
*
* ```typescript
* @Component({
* selector: 'my-component',
* templateUrl: 'my-component-tpl.html',
* animations: [
* trigger("myAnimationTrigger", [
* state(...),
* state(...),
* transition(...),
* transition(...)
* ])
* ]
* })
* class MyComponent {
* myStatusExp = "something";
* }
* ```
*
* The template associated with this component will make use of the `myAnimationTrigger`
* animation trigger by binding to an element within its template code.
*
* ```html
* <!-- somewhere inside of my-component-tpl.html -->
* <div [@myAnimationTrigger]="myStatusExp">...</div>
* ```
*
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
*
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
*
* @experimental Animation support is experimental.
*/
export function trigger(name: string, animation: AnimationMetadata[]): AnimationEntryMetadata {
return new AnimationEntryMetadata(name, animation);
}

View File

@ -1,62 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {isPresent} from '../facade/lang';
import {AnimationPlayer} from './animation_player';
export class ViewAnimationMap {
private _map = new Map<any, {[key: string]: AnimationPlayer}>();
private _allPlayers: AnimationPlayer[] = [];
find(element: any, animationName: string): AnimationPlayer {
const playersByAnimation = this._map.get(element);
if (isPresent(playersByAnimation)) {
return playersByAnimation[animationName];
}
}
findAllPlayersByElement(element: any): AnimationPlayer[] {
const el = this._map.get(element);
return el ? Object.keys(el).map(k => el[k]) : [];
}
set(element: any, animationName: string, player: AnimationPlayer): void {
let playersByAnimation = this._map.get(element);
if (!isPresent(playersByAnimation)) {
playersByAnimation = {};
}
const existingEntry = playersByAnimation[animationName];
if (isPresent(existingEntry)) {
this.remove(element, animationName);
}
playersByAnimation[animationName] = player;
this._allPlayers.push(player);
this._map.set(element, playersByAnimation);
}
getAllPlayers(): AnimationPlayer[] { return this._allPlayers; }
remove(element: any, animationName: string, targetPlayer: AnimationPlayer = null): void {
const playersByAnimation = this._map.get(element);
if (playersByAnimation) {
const player = playersByAnimation[animationName];
if (!targetPlayer || player === targetPlayer) {
delete playersByAnimation[animationName];
const index = this._allPlayers.indexOf(player);
this._allPlayers.splice(index, 1);
if (Object.keys(playersByAnimation).length === 0) {
this._map.delete(element);
}
}
}
}
}

View File

@ -6,7 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AnimationQueue} from './animation/animation_queue';
import {APP_INITIALIZER, ApplicationInitStatus} from './application_init';
import {ApplicationRef, ApplicationRef_} from './application_ref';
import {APP_ID_RANDOM_PROVIDER} from './application_tokens';
@ -14,7 +13,6 @@ import {IterableDiffers, KeyValueDiffers, defaultIterableDiffers, defaultKeyValu
import {Inject, Optional, SkipSelf} from './di/metadata';
import {LOCALE_ID} from './i18n/tokens';
import {Compiler} from './linker/compiler';
import {ViewUtils} from './linker/view_utils';
import {NgModule} from './metadata';
import {initServicesIfNeeded} from './view/index';
@ -47,8 +45,6 @@ export function _initViewEngine() {
ApplicationInitStatus,
Compiler,
APP_ID_RANDOM_PROVIDER,
ViewUtils,
AnimationQueue,
{provide: IterableDiffers, useFactory: _iterableDiffersFactory},
{provide: KeyValueDiffers, useFactory: _keyValueDiffersFactory},
{

View File

@ -26,7 +26,6 @@ import {CompilerFactory, CompilerOptions} from './linker/compiler';
import {ComponentFactory, ComponentRef} from './linker/component_factory';
import {ComponentFactoryResolver} from './linker/component_factory_resolver';
import {NgModuleFactory, NgModuleInjector, NgModuleRef} from './linker/ng_module_factory';
import {AppView} from './linker/view';
import {InternalViewRef, ViewRef} from './linker/view_ref';
import {WtfScopeFn, wtfCreateScope, wtfLeave} from './profile/profile';
import {Testability, TestabilityRegistry} from './testability/testability';

View File

@ -6,24 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
export {AnimationGroupPlayer as ɵAnimationGroupPlayer} from './animation/animation_group_player';
export {AnimationKeyframe as ɵAnimationKeyframe} from './animation/animation_keyframe';
export {NoOpAnimationPlayer as ɵNoOpAnimationPlayer} from './animation/animation_player';
export {AnimationSequencePlayer as ɵAnimationSequencePlayer} from './animation/animation_sequence_player';
export {balanceAnimationKeyframes as ɵbalanceAnimationKeyframes, clearStyles as ɵclearStyles, collectAndResolveStyles as ɵcollectAndResolveStyles, prepareFinalAnimationStyles as ɵprepareFinalAnimationStyles, renderStyles as ɵrenderStyles} from './animation/animation_style_util';
export {AnimationStyles as ɵAnimationStyles} from './animation/animation_styles';
export {AnimationTransition as ɵAnimationTransition} from './animation/animation_transition';
export {ValueUnwrapper as ɵValueUnwrapper, devModeEqual as ɵdevModeEqual} from './change_detection/change_detection_util';
export {ChangeDetectorStatus as ɵChangeDetectorStatus} from './change_detection/constants';
export {ComponentRef_ as ɵComponentRef_} from './linker/component_factory';
export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} from './linker/component_factory_resolver';
export {DebugContext as ɵDebugContext, StaticNodeDebugInfo as ɵStaticNodeDebugInfo} from './linker/debug_context';
export {NgModuleInjector as ɵNgModuleInjector} from './linker/ng_module_factory';
export {registerModuleFactory as ɵregisterModuleFactory} from './linker/ng_module_factory_loader';
export {TemplateRef_ as ɵTemplateRef_} from './linker/template_ref';
export {AppView as ɵAppView, DebugAppView as ɵDebugAppView} from './linker/view';
export {ViewContainer as ɵViewContainer} from './linker/view_container';
export {ViewType as ɵViewType} from './linker/view_type';
export {EMPTY_ARRAY as ɵEMPTY_ARRAY, EMPTY_INLINE_ARRAY as ɵEMPTY_INLINE_ARRAY, EMPTY_MAP as ɵEMPTY_MAP, InlineArray16 as ɵInlineArray16, InlineArray2 as ɵInlineArray2, InlineArray4 as ɵInlineArray4, InlineArray8 as ɵInlineArray8, InlineArrayDynamic as ɵInlineArrayDynamic, ViewUtils as ɵViewUtils, castByValue as ɵcastByValue, checkBinding as ɵcheckBinding, checkBindingChange as ɵcheckBindingChange, checkRenderAttribute as ɵcheckRenderAttribute, checkRenderClass as ɵcheckRenderClass, checkRenderProperty as ɵcheckRenderProperty, checkRenderStyle as ɵcheckRenderStyle, checkRenderText as ɵcheckRenderText, createRenderComponentType as ɵcreateRenderComponentType, createRenderElement as ɵcreateRenderElement, getComponentFactoryViewClass as ɵgetComponentFactoryViewClass, inlineInterpolate as ɵinlineInterpolate, interpolate as ɵinterpolate, noop as ɵnoop, pureProxy1 as ɵpureProxy1, pureProxy10 as ɵpureProxy10, pureProxy2 as ɵpureProxy2, pureProxy3 as ɵpureProxy3, pureProxy4 as ɵpureProxy4, pureProxy5 as ɵpureProxy5, pureProxy6 as ɵpureProxy6, pureProxy7 as ɵpureProxy7, pureProxy8 as ɵpureProxy8, pureProxy9 as ɵpureProxy9, selectOrCreateRenderHostElement as ɵselectOrCreateRenderHostElement, setBindingDebugInfo as ɵsetBindingDebugInfo, setBindingDebugInfoForChanges as ɵsetBindingDebugInfoForChanges, subscribeToRenderElement as ɵsubscribeToRenderElement} from './linker/view_utils';
export {reflector as ɵreflector} from './reflection/reflection';
export {ArgumentType as ɵArgumentType, BindingType as ɵBindingType, DepFlags as ɵDepFlags, NodeFlags as ɵNodeFlags, QueryBindingType as ɵQueryBindingType, QueryValueType as ɵQueryValueType, ViewDefinition as ɵViewDefinition, ViewFlags as ɵViewFlags, anchorDef as ɵand, createComponentFactory as ɵccf, createRendererTypeV2 as ɵcrt, directiveDef as ɵdid, elementDef as ɵeld, elementEventFullName as ɵelementEventFullName, ngContentDef as ɵncd, nodeValue as ɵnov, pipeDef as ɵpid, providerDef as ɵprd, pureArrayDef as ɵpad, pureObjectDef as ɵpod, purePipeDef as ɵppd, queryDef as ɵqud, textDef as ɵted, unwrapValue as ɵunv, viewDef as ɵvid} from './view/index';
export {ArgumentType as ɵArgumentType, BindingType as ɵBindingType, DepFlags as ɵDepFlags, EMPTY_ARRAY as ɵEMPTY_ARRAY, EMPTY_MAP as ɵEMPTY_MAP, NodeFlags as ɵNodeFlags, QueryBindingType as ɵQueryBindingType, QueryValueType as ɵQueryValueType, ViewDefinition as ɵViewDefinition, ViewFlags as ɵViewFlags, anchorDef as ɵand, createComponentFactory as ɵccf, createRendererTypeV2 as ɵcrt, directiveDef as ɵdid, elementDef as ɵeld, elementEventFullName as ɵelementEventFullName, getComponentViewDefinitionFactory as ɵgetComponentViewDefinitionFactory, inlineInterpolate as ɵinlineInterpolate, interpolate as ɵinterpolate, ngContentDef as ɵncd, nodeValue as ɵnov, pipeDef as ɵpid, providerDef as ɵprd, pureArrayDef as ɵpad, pureObjectDef as ɵpod, purePipeDef as ɵppd, queryDef as ɵqud, textDef as ɵted, unwrapValue as ɵunv, viewDef as ɵvid} from './view/index';

View File

@ -32,20 +32,31 @@ export {Type} from './type';
export {EventEmitter} from './facade/async';
export {ErrorHandler} from './error_handler';
export * from './core_private_export';
export {AnimationPlayer} from './animation/animation_player';
export {AnimationStyles} from './animation/animation_styles';
export {AnimationKeyframe} from './animation/animation_keyframe';
export {Sanitizer, SecurityContext} from './security';
export * from './codegen_private_exports';
export * from './animation_next/animation_metadata_wrapped';
export * from './animation/animation_metadata_wrapped';
import {AnimationTriggerMetadata} from './animation/animation_metadata_wrapped';
// For backwards compatibility.
/**
* @deprecated
* @deprecated from v4
*/
export type AnimationEntryMetadata = any;
/**
* @deprecated
* @deprecated from v4
*/
export type AnimationStateTransitionMetadata = any;
/**
* @deprecated from v4
*/
export type AnimationPlayer = any;
/**
* @deprecated from v4
*/
export type AnimationStyles = any;
/**
* @deprecated from v4
*/
export type AnimationKeyframe = any;

View File

@ -6,27 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
export {ANY_STATE as ɵANY_STATE, DEFAULT_STATE as ɵDEFAULT_STATE, EMPTY_STATE as ɵEMPTY_STATE, FILL_STYLE_FLAG as ɵFILL_STYLE_FLAG} from './animation/animation_constants';
export {AnimationGroupPlayer as ɵAnimationGroupPlayer} from './animation/animation_group_player';
export {AnimationKeyframe as ɵAnimationKeyframe} from './animation/animation_keyframe';
export {AnimationPlayer as ɵAnimationPlayer, NoOpAnimationPlayer as ɵNoOpAnimationPlayer} from './animation/animation_player';
export {AnimationSequencePlayer as ɵAnimationSequencePlayer} from './animation/animation_sequence_player';
export {balanceAnimationKeyframes as ɵbalanceAnimationKeyframes, clearStyles as ɵclearStyles, collectAndResolveStyles as ɵcollectAndResolveStyles, flattenStyles as ɵflattenStyles, prepareFinalAnimationStyles as ɵprepareFinalAnimationStyles, renderStyles as ɵrenderStyles} from './animation/animation_style_util';
export {AnimationStyles as ɵAnimationStyles} from './animation/animation_styles';
export {AnimationTransition as ɵAnimationTransition} from './animation/animation_transition';
export {ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS} from './application_ref';
export {APP_ID_RANDOM_PROVIDER as ɵAPP_ID_RANDOM_PROVIDER} from './application_tokens';
export {ValueUnwrapper as ɵValueUnwrapper, devModeEqual as ɵdevModeEqual} from './change_detection/change_detection_util';
export {ChangeDetectorStatus as ɵChangeDetectorStatus, isDefaultChangeDetectionStrategy as ɵisDefaultChangeDetectionStrategy} from './change_detection/constants';
export {Console as ɵConsole} from './console';
export {DebugDomRootRenderer as ɵDebugDomRootRenderer} from './debug/debug_renderer';
export {ERROR_COMPONENT_TYPE as ɵERROR_COMPONENT_TYPE} from './errors';
export {ComponentFactory as ɵComponentFactory} from './linker/component_factory';
export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} from './linker/component_factory_resolver';
export {DebugContext as ɵDebugContext, StaticNodeDebugInfo as ɵStaticNodeDebugInfo} from './linker/debug_context';
export {AppView as ɵAppView, DebugAppView as ɵDebugAppView} from './linker/view';
export {ViewContainer as ɵViewContainer} from './linker/view_container';
export {ViewType as ɵViewType} from './linker/view_type';
export {LIFECYCLE_HOOKS_VALUES as ɵLIFECYCLE_HOOKS_VALUES, LifecycleHooks as ɵLifecycleHooks} from './metadata/lifecycle_hooks';
export {ViewMetadata as ɵViewMetadata} from './metadata/view';
export {Reflector as ɵReflector, reflector as ɵreflector} from './reflection/reflection';

View File

@ -1,161 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {AnimationKeyframe} from '../animation/animation_keyframe';
import {AnimationPlayer} from '../animation/animation_player';
import {AnimationStyles} from '../animation/animation_styles';
import {isPresent} from '../facade/lang';
import {RenderComponentType, RenderDebugInfo, Renderer, RootRenderer} from '../render/api';
import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from './debug_node';
export class DebugDomRootRenderer implements RootRenderer {
constructor(private _delegate: RootRenderer) {
throw new Error(
'RootRenderer is no longer supported. Please use the `RendererFactoryV2` instead!');
}
renderComponent(componentProto: RenderComponentType): Renderer {
return new DebugDomRenderer(this._delegate.renderComponent(componentProto));
}
}
export class DebugDomRenderer implements Renderer {
constructor(private _delegate: Renderer) {}
selectRootElement(selectorOrNode: string|any, debugInfo?: RenderDebugInfo): any {
const nativeEl = this._delegate.selectRootElement(selectorOrNode, debugInfo);
const debugEl = new DebugElement(nativeEl, null, debugInfo);
indexDebugNode(debugEl);
return nativeEl;
}
createElement(parentElement: any, name: string, debugInfo?: RenderDebugInfo): any {
const nativeEl = this._delegate.createElement(parentElement, name, debugInfo);
const debugEl = new DebugElement(nativeEl, getDebugNode(parentElement), debugInfo);
debugEl.name = name;
indexDebugNode(debugEl);
return nativeEl;
}
createViewRoot(hostElement: any): any { return this._delegate.createViewRoot(hostElement); }
createTemplateAnchor(parentElement: any, debugInfo?: RenderDebugInfo): any {
const comment = this._delegate.createTemplateAnchor(parentElement, debugInfo);
const debugEl = new DebugNode(comment, getDebugNode(parentElement), debugInfo);
indexDebugNode(debugEl);
return comment;
}
createText(parentElement: any, value: string, debugInfo?: RenderDebugInfo): any {
const text = this._delegate.createText(parentElement, value, debugInfo);
const debugEl = new DebugNode(text, getDebugNode(parentElement), debugInfo);
indexDebugNode(debugEl);
return text;
}
projectNodes(parentElement: any, nodes: any[]) {
const debugParent = getDebugNode(parentElement);
if (isPresent(debugParent) && debugParent instanceof DebugElement) {
const debugElement = debugParent;
nodes.forEach((node) => { debugElement.addChild(getDebugNode(node)); });
}
this._delegate.projectNodes(parentElement, nodes);
}
attachViewAfter(node: any, viewRootNodes: any[]) {
const debugNode = getDebugNode(node);
if (isPresent(debugNode)) {
const debugParent = debugNode.parent;
if (viewRootNodes.length > 0 && isPresent(debugParent)) {
const debugViewRootNodes: DebugNode[] = [];
viewRootNodes.forEach((rootNode) => debugViewRootNodes.push(getDebugNode(rootNode)));
debugParent.insertChildrenAfter(debugNode, debugViewRootNodes);
}
}
this._delegate.attachViewAfter(node, viewRootNodes);
}
detachView(viewRootNodes: any[]) {
viewRootNodes.forEach((node) => {
const debugNode = getDebugNode(node);
if (debugNode && debugNode.parent) {
debugNode.parent.removeChild(debugNode);
}
});
this._delegate.detachView(viewRootNodes);
}
destroyView(hostElement: any, viewAllNodes: any[]) {
viewAllNodes = viewAllNodes || [];
viewAllNodes.forEach((node) => { removeDebugNodeFromIndex(getDebugNode(node)); });
this._delegate.destroyView(hostElement, viewAllNodes);
}
listen(renderElement: any, name: string, callback: Function): Function {
const debugEl = getDebugNode(renderElement);
if (isPresent(debugEl)) {
debugEl.listeners.push(new EventListener(name, callback));
}
return this._delegate.listen(renderElement, name, callback);
}
listenGlobal(target: string, name: string, callback: Function): Function {
return this._delegate.listenGlobal(target, name, callback);
}
setElementProperty(renderElement: any, propertyName: string, propertyValue: any) {
const debugEl = getDebugNode(renderElement);
if (isPresent(debugEl) && debugEl instanceof DebugElement) {
debugEl.properties[propertyName] = propertyValue;
}
this._delegate.setElementProperty(renderElement, propertyName, propertyValue);
}
setElementAttribute(renderElement: any, attributeName: string, attributeValue: string) {
const debugEl = getDebugNode(renderElement);
if (isPresent(debugEl) && debugEl instanceof DebugElement) {
debugEl.attributes[attributeName] = attributeValue;
}
this._delegate.setElementAttribute(renderElement, attributeName, attributeValue);
}
setBindingDebugInfo(renderElement: any, propertyName: string, propertyValue: string) {
this._delegate.setBindingDebugInfo(renderElement, propertyName, propertyValue);
}
setElementClass(renderElement: any, className: string, isAdd: boolean) {
const debugEl = getDebugNode(renderElement);
if (isPresent(debugEl) && debugEl instanceof DebugElement) {
debugEl.classes[className] = isAdd;
}
this._delegate.setElementClass(renderElement, className, isAdd);
}
setElementStyle(renderElement: any, styleName: string, styleValue: string) {
const debugEl = getDebugNode(renderElement);
if (isPresent(debugEl) && debugEl instanceof DebugElement) {
debugEl.styles[styleName] = styleValue;
}
this._delegate.setElementStyle(renderElement, styleName, styleValue);
}
invokeElementMethod(renderElement: any, methodName: string, args?: any[]) {
this._delegate.invokeElementMethod(renderElement, methodName, args);
}
setText(renderNode: any, text: string) { this._delegate.setText(renderNode, text); }
animate(
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],
duration: number, delay: number, easing: string,
previousPlayers: AnimationPlayer[] = []): AnimationPlayer {
return this._delegate.animate(
element, startingStyles, keyframes, duration, delay, easing, previousPlayers);
}
}

View File

@ -1,57 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {AnimationGroupPlayer} from '../animation/animation_group_player';
import {AnimationPlayer} from '../animation/animation_player';
import {AnimationQueue} from '../animation/animation_queue';
import {AnimationSequencePlayer} from '../animation/animation_sequence_player';
import {ViewAnimationMap} from '../animation/view_animation_map';
export class AnimationViewContext {
private _players = new ViewAnimationMap();
constructor(private _animationQueue: AnimationQueue) {}
onAllActiveAnimationsDone(callback: () => any): void {
const activeAnimationPlayers = this._players.getAllPlayers();
// we check for the length to avoid having GroupAnimationPlayer
// issue an unnecessary microtask when zero players are passed in
if (activeAnimationPlayers.length) {
new AnimationGroupPlayer(activeAnimationPlayers).onDone(() => callback());
} else {
callback();
}
}
queueAnimation(element: any, animationName: string, player: AnimationPlayer): void {
this._animationQueue.enqueue(player);
this._players.set(element, animationName, player);
player.onDone(() => this._players.remove(element, animationName, player));
}
getAnimationPlayers(element: any, animationName: string = null): AnimationPlayer[] {
const players: AnimationPlayer[] = [];
if (animationName) {
const currentPlayer = this._players.find(element, animationName);
if (currentPlayer) {
_recursePlayers(currentPlayer, players);
}
} else {
this._players.findAllPlayersByElement(element).forEach(
player => _recursePlayers(player, players));
}
return players;
}
}
function _recursePlayers(player: AnimationPlayer, collectedPlayers: AnimationPlayer[]) {
if ((player instanceof AnimationGroupPlayer) || (player instanceof AnimationSequencePlayer)) {
player.players.forEach(player => _recursePlayers(player, collectedPlayers));
} else {
collectedPlayers.push(player);
}
}

View File

@ -11,11 +11,7 @@ import {Injector} from '../di/injector';
import {Type} from '../type';
import {ElementRef} from './element_ref';
import {AppView} from './view';
import {ViewRef} from './view_ref';
import {ViewUtils} from './view_utils';
/**
* Represents an instance of a Component created via a {@link ComponentFactory}.
@ -67,53 +63,15 @@ export abstract class ComponentRef<C> {
abstract onDestroy(callback: Function): void;
}
/**
* workaround https://github.com/angular/tsickle/issues/350
* @suppress {checkTypes}
*/
export class ComponentRef_<C> extends ComponentRef<C> {
constructor(
private _index: number, private _parentView: AppView<any>, private _nativeElement: any,
private _component: C) {
super();
}
get location(): ElementRef { return new ElementRef(this._nativeElement); }
get injector(): Injector { return this._parentView.injector(this._index); }
get instance(): C { return this._component; };
get hostView(): ViewRef { return this._parentView.ref; };
get changeDetectorRef(): ChangeDetectorRef { return this._parentView.ref; };
get componentType(): Type<any> { return <any>this._component.constructor; }
destroy(): void { this._parentView.detachAndDestroy(); }
onDestroy(callback: Function): void { this.hostView.onDestroy(callback); }
}
/**
* @stable
*/
export class ComponentFactory<C> {
/**
* TODO(tbosch): type this properly to ViewDefinitionFactory again once the view engine
* is the default.
* @internal
*/
_viewClass: any;
constructor(
public selector: string, _viewClass: Type<AppView<any>>, public componentType: Type<any>) {
this._viewClass = _viewClass;
}
export abstract class ComponentFactory<C> {
abstract get selector(): string;
abstract get componentType(): Type<any>;
/**
* Creates a new component.
*/
create(
injector: Injector, projectableNodes: any[][] = null,
rootSelectorOrNode: string|any = null): ComponentRef<C> {
const vu: ViewUtils = injector.get(ViewUtils);
if (!projectableNodes) {
projectableNodes = [];
}
const hostView: AppView<any> = new this._viewClass(vu, null, null, null);
return hostView.createHostView(rootSelectorOrNode, injector, projectableNodes);
}
abstract create(injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string|any):
ComponentRef<C>;
}

View File

@ -1,80 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {Injector} from '../di';
import {isBlank, isPresent} from '../facade/lang';
import {RenderDebugInfo} from '../render/api';
import {DebugAppView} from './view';
import {ViewType} from './view_type';
export class StaticNodeDebugInfo {
constructor(
public providerTokens: any[], public componentToken: any,
public refTokens: {[key: string]: any}) {}
}
export class DebugContext implements RenderDebugInfo {
constructor(
private _view: DebugAppView<any>, private _nodeIndex: number, private _tplRow: number,
private _tplCol: number) {}
private get _staticNodeInfo(): StaticNodeDebugInfo {
return isPresent(this._nodeIndex) ? this._view.staticNodeDebugInfos[this._nodeIndex] : null;
}
get context() { return this._view.context; }
get component() {
const staticNodeInfo = this._staticNodeInfo;
if (isPresent(staticNodeInfo) && isPresent(staticNodeInfo.componentToken)) {
return this.injector.get(staticNodeInfo.componentToken);
}
return null;
}
get componentRenderElement() {
let componentView = this._view;
while (isPresent(componentView.parentView) && componentView.type !== ViewType.COMPONENT) {
componentView = <DebugAppView<any>>componentView.parentView;
}
return componentView.parentElement;
}
get injector(): Injector { return this._view.injector(this._nodeIndex); }
get renderNode(): any {
if (isPresent(this._nodeIndex) && this._view.allNodes) {
return this._view.allNodes[this._nodeIndex];
} else {
return null;
}
}
get providerTokens(): any[] {
const staticNodeInfo = this._staticNodeInfo;
return isPresent(staticNodeInfo) ? staticNodeInfo.providerTokens : null;
}
get source(): string {
return `${this._view.componentType.templateUrl}:${this._tplRow}:${this._tplCol}`;
}
get references(): {[key: string]: any} {
const varValues: {[key: string]: string} = {};
const staticNodeInfo = this._staticNodeInfo;
if (isPresent(staticNodeInfo)) {
const refs = staticNodeInfo.refTokens;
Object.keys(refs).forEach(refName => {
const refToken = refs[refName];
let varValue: any;
if (isBlank(refToken)) {
varValue = this._view.allNodes ? this._view.allNodes[this._nodeIndex] : null;
} else {
varValue = this._view.injectorGet(refToken, this._nodeIndex, null);
}
varValues[refName] = varValue;
});
}
return varValues;
}
}

View File

@ -1,18 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
import {AppView} from './view';
export class ElementInjector extends Injector {
constructor(private _view: AppView<any>, private _nodeIndex: number) { super(); }
get(token: any, notFoundValue: any = THROW_IF_NOT_FOUND): any {
return this._view.injectorGet(token, this._nodeIndex, notFoundValue);
}
}

View File

@ -1,81 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {wrappedError} from '../error_handler';
import {ERROR_DEBUG_CONTEXT, ERROR_TYPE} from '../errors';
import {DebugContext} from './debug_context';
/**
* An error thrown if application changes model breaking the top-down data flow.
*
* This exception is only thrown in dev mode.
*
* <!-- TODO: Add a link once the dev mode option is configurable -->
*
* ### Example
*
* ```typescript
* @Component({
* selector: 'parent',
* template: '<child [prop]="parentProp"></child>',
* })
* class Parent {
* parentProp = 'init';
* }
*
* @Directive({selector: 'child', inputs: ['prop']})
* class Child {
* constructor(public parent: Parent) {}
*
* set prop(v) {
* // this updates the parent property, which is disallowed during change detection
* // this will result in ExpressionChangedAfterItHasBeenCheckedError
* this.parent.parentProp = 'updated';
* }
* }
* ```
*/
export function expressionChangedAfterItHasBeenCheckedError(
oldValue: any, currValue: any, isFirstCheck: boolean) {
let msg =
`Expression has changed after it was checked. Previous value: '${oldValue}'. Current value: '${currValue}'.`;
if (isFirstCheck) {
msg +=
` It seems like the view has been created after its parent and its children have been dirty checked.` +
` Has it been created in a change detection hook ?`;
}
const error = Error(msg);
(error as any)[ERROR_TYPE] = expressionChangedAfterItHasBeenCheckedError;
return error;
}
/**
* Thrown when an exception was raised during view creation, change detection or destruction.
*
* This error wraps the original exception to attach additional contextual information that can
* be useful for debugging.
*/
export function viewWrappedError(originalError: any, context: DebugContext): Error {
const error = wrappedError(`Error in ${context.source}`, originalError);
(error as any)[ERROR_DEBUG_CONTEXT] = context;
(error as any)[ERROR_TYPE] = viewWrappedError;
return error;
}
/**
* Thrown when a destroyed view is used.
*
* This error indicates a bug in the framework.
*
* This is an internal Angular error.
*/
export function viewDestroyedError(details: string) {
return Error(`Attempt to use a destroyed view: ${details}`);
}

View File

@ -7,7 +7,6 @@
*/
import {ElementRef} from './element_ref';
import {AppView} from './view';
import {EmbeddedViewRef} from './view_ref';
@ -41,22 +40,3 @@ export abstract class TemplateRef<C> {
abstract createEmbeddedView(context: C): EmbeddedViewRef<C>;
}
/**
* workaround https://github.com/angular/tsickle/issues/350
* @suppress {checkTypes}
*/
export class TemplateRef_<C> extends TemplateRef<C> {
constructor(
private _parentView: AppView<any>, private _nodeIndex: number, private _nativeElement: any) {
super();
}
createEmbeddedView(context: C): EmbeddedViewRef<C> {
const view = this._parentView.createEmbeddedViewInternal(this._nodeIndex);
view.create(context || <any>{});
return view.ref;
}
get elementRef(): ElementRef { return new ElementRef(this._nativeElement); }
}

View File

@ -1,472 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {ApplicationRef} from '../application_ref';
import {ChangeDetectorRef, ChangeDetectorStatus} from '../change_detection/change_detection';
import {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
import {getType} from '../errors';
import {isPresent} from '../facade/lang';
import {WtfScopeFn, wtfCreateScope, wtfLeave} from '../profile/profile';
import {DirectRenderer, RenderComponentType, Renderer} from '../render/api';
import {AnimationViewContext} from './animation_view_context';
import {ComponentRef} from './component_factory';
import {DebugContext, StaticNodeDebugInfo} from './debug_context';
import {ElementInjector} from './element_injector';
import {expressionChangedAfterItHasBeenCheckedError, viewDestroyedError, viewWrappedError} from './errors';
import {ViewContainer} from './view_container';
import {ViewRef_} from './view_ref';
import {ViewType} from './view_type';
import {ViewUtils, addToArray} from './view_utils';
const _scope_check: WtfScopeFn = wtfCreateScope(`AppView#check(ascii id)`);
/**
* @experimental
*/
const EMPTY_CONTEXT = new Object();
const UNDEFINED = new Object();
/**
* Cost of making objects: http://jsperf.com/instantiate-size-of-object
*
*/
export abstract class AppView<T> {
ref: ViewRef_<T>;
lastRootNode: any;
allNodes: any[];
disposables: Function[];
viewContainer: ViewContainer;
// This will be set if a view is directly attached to an ApplicationRef
// and not to a view container.
appRef: ApplicationRef;
numberOfChecks: number = 0;
throwOnChange: boolean = false;
renderer: Renderer;
private _hasExternalHostElement: boolean;
private _hostInjector: Injector;
private _hostProjectableNodes: any[][];
private _animationContext: AnimationViewContext;
private _directRenderer: DirectRenderer;
public context: T;
constructor(
public clazz: any, public componentType: RenderComponentType, public type: ViewType,
public viewUtils: ViewUtils, public parentView: AppView<any>, public parentIndex: number,
public parentElement: any, public cdMode: ChangeDetectorStatus,
public declaredViewContainer: ViewContainer = null) {
this.ref = new ViewRef_(this, viewUtils.animationQueue);
if (type === ViewType.COMPONENT || type === ViewType.HOST) {
this.renderer = viewUtils.renderComponent(componentType);
} else {
this.renderer = parentView.renderer;
}
this._directRenderer = (this.renderer as any).directRenderer;
}
get animationContext(): AnimationViewContext {
if (!this._animationContext) {
this._animationContext = new AnimationViewContext(this.viewUtils.animationQueue);
}
return this._animationContext;
}
get destroyed(): boolean { return this.cdMode === ChangeDetectorStatus.Destroyed; }
create(context: T) {
this.context = context;
return this.createInternal(null);
}
createHostView(rootSelectorOrNode: string|any, hostInjector: Injector, projectableNodes: any[][]):
ComponentRef<any> {
this.context = <any>EMPTY_CONTEXT;
this._hasExternalHostElement = isPresent(rootSelectorOrNode);
this._hostInjector = hostInjector;
this._hostProjectableNodes = projectableNodes;
return this.createInternal(rootSelectorOrNode);
}
/**
* Overwritten by implementations.
* Returns the ComponentRef for the host element for ViewType.HOST.
*/
createInternal(rootSelectorOrNode: string|any): ComponentRef<any> { return null; }
/**
* Overwritten by implementations.
*/
createEmbeddedViewInternal(templateNodeIndex: number): AppView<any> { return null; }
init(lastRootNode: any, allNodes: any[], disposables: Function[]) {
this.lastRootNode = lastRootNode;
this.allNodes = allNodes;
this.disposables = disposables;
if (this.type === ViewType.COMPONENT) {
this.dirtyParentQueriesInternal();
}
}
injectorGet(token: any, nodeIndex: number, notFoundValue: any = THROW_IF_NOT_FOUND): any {
let result = UNDEFINED;
let view: AppView<any> = this;
while (result === UNDEFINED) {
if (isPresent(nodeIndex)) {
result = view.injectorGetInternal(token, nodeIndex, UNDEFINED);
}
if (result === UNDEFINED && view.type === ViewType.HOST) {
result = view._hostInjector.get(token, notFoundValue);
}
nodeIndex = view.parentIndex;
view = view.parentView;
}
return result;
}
/**
* Overwritten by implementations
*/
injectorGetInternal(token: any, nodeIndex: number, notFoundResult: any): any {
return notFoundResult;
}
injector(nodeIndex: number): Injector { return new ElementInjector(this, nodeIndex); }
detachAndDestroy() {
if (this.viewContainer) {
this.viewContainer.detachView(this.viewContainer.nestedViews.indexOf(this));
} else if (this.appRef) {
this.appRef.detachView(this.ref);
} else if (this._hasExternalHostElement) {
this.detach();
}
this.destroy();
}
destroy() {
if (this.cdMode === ChangeDetectorStatus.Destroyed) {
return;
}
const hostElement = this.type === ViewType.COMPONENT ? this.parentElement : null;
if (this.disposables) {
for (let i = 0; i < this.disposables.length; i++) {
this.disposables[i]();
}
}
this.destroyInternal();
this.dirtyParentQueriesInternal();
if (this._animationContext) {
this._animationContext.onAllActiveAnimationsDone(
() => this.renderer.destroyView(hostElement, this.allNodes));
} else {
this.renderer.destroyView(hostElement, this.allNodes);
}
this.cdMode = ChangeDetectorStatus.Destroyed;
}
/**
* Overwritten by implementations
*/
destroyInternal(): void {}
/**
* Overwritten by implementations
*/
detachInternal(): void {}
detach(): void {
this.detachInternal();
if (this._animationContext) {
this._animationContext.onAllActiveAnimationsDone(() => this._renderDetach());
} else {
this._renderDetach();
}
if (this.declaredViewContainer && this.declaredViewContainer !== this.viewContainer &&
this.declaredViewContainer.projectedViews) {
const projectedViews = this.declaredViewContainer.projectedViews;
const index = projectedViews.indexOf(this);
// perf: pop is faster than splice!
if (index >= projectedViews.length - 1) {
projectedViews.pop();
} else {
projectedViews.splice(index, 1);
}
}
this.appRef = null;
this.viewContainer = null;
this.dirtyParentQueriesInternal();
}
private _renderDetach() {
if (this._directRenderer) {
this.visitRootNodesInternal(this._directRenderer.remove, null);
} else {
this.renderer.detachView(this.flatRootNodes);
}
}
attachToAppRef(appRef: ApplicationRef) {
if (this.viewContainer) {
throw new Error('This view is already attached to a ViewContainer!');
}
this.appRef = appRef;
this.dirtyParentQueriesInternal();
}
attachAfter(viewContainer: ViewContainer, prevView: AppView<any>) {
if (this.appRef) {
throw new Error('This view is already attached directly to the ApplicationRef!');
}
this._renderAttach(viewContainer, prevView);
this.viewContainer = viewContainer;
if (this.declaredViewContainer && this.declaredViewContainer !== viewContainer) {
if (!this.declaredViewContainer.projectedViews) {
this.declaredViewContainer.projectedViews = [];
}
this.declaredViewContainer.projectedViews.push(this);
}
this.dirtyParentQueriesInternal();
}
moveAfter(viewContainer: ViewContainer, prevView: AppView<any>) {
this._renderAttach(viewContainer, prevView);
this.dirtyParentQueriesInternal();
}
private _renderAttach(viewContainer: ViewContainer, prevView: AppView<any>) {
const prevNode = prevView ? prevView.lastRootNode : viewContainer.nativeElement;
if (this._directRenderer) {
const nextSibling = this._directRenderer.nextSibling(prevNode);
if (nextSibling) {
this.visitRootNodesInternal(this._directRenderer.insertBefore, nextSibling);
} else {
const parentElement = this._directRenderer.parentElement(prevNode);
if (parentElement) {
this.visitRootNodesInternal(this._directRenderer.appendChild, parentElement);
}
}
} else {
this.renderer.attachViewAfter(prevNode, this.flatRootNodes);
}
}
get changeDetectorRef(): ChangeDetectorRef { return this.ref; }
get flatRootNodes(): any[] {
const nodes: any[] = [];
this.visitRootNodesInternal(addToArray, nodes);
return nodes;
}
projectNodes(parentElement: any, ngContentIndex: number) {
if (this._directRenderer) {
this.visitProjectedNodes(ngContentIndex, this._directRenderer.appendChild, parentElement);
} else {
const nodes: any[] = [];
this.visitProjectedNodes(ngContentIndex, addToArray, nodes);
this.renderer.projectNodes(parentElement, nodes);
}
}
visitProjectedNodes<C>(ngContentIndex: number, cb: (node: any, ctx: C) => void, c: C): void {
switch (this.type) {
case ViewType.EMBEDDED:
this.parentView.visitProjectedNodes(ngContentIndex, cb, c);
break;
case ViewType.COMPONENT:
if (this.parentView.type === ViewType.HOST) {
const nodes = this.parentView._hostProjectableNodes[ngContentIndex] || [];
for (let i = 0; i < nodes.length; i++) {
cb(nodes[i], c);
}
} else {
this.parentView.visitProjectableNodesInternal(this.parentIndex, ngContentIndex, cb, c);
}
break;
}
}
/**
* Overwritten by implementations
*/
visitRootNodesInternal<C>(cb: (node: any, ctx: C) => void, c: C): void {}
/**
* Overwritten by implementations
*/
visitProjectableNodesInternal<C>(
nodeIndex: number, ngContentIndex: number, cb: (node: any, ctx: C) => void, c: C): void {}
/**
* Overwritten by implementations
*/
dirtyParentQueriesInternal(): void {}
internalDetectChanges(throwOnChange: boolean): void {
if (this.cdMode !== ChangeDetectorStatus.Detached) {
this.detectChanges(throwOnChange);
}
}
detectChanges(throwOnChange: boolean): void {
const s = _scope_check(this.clazz);
if (this.cdMode === ChangeDetectorStatus.Checked ||
this.cdMode === ChangeDetectorStatus.Errored)
return;
if (this.cdMode === ChangeDetectorStatus.Destroyed) {
this.throwDestroyedError('detectChanges');
}
this.throwOnChange = throwOnChange;
this.detectChangesInternal();
if (this.cdMode === ChangeDetectorStatus.CheckOnce) this.cdMode = ChangeDetectorStatus.Checked;
this.numberOfChecks++;
wtfLeave(s);
}
/**
* Overwritten by implementations
*/
detectChangesInternal(): void {}
markAsCheckOnce(): void { this.cdMode = ChangeDetectorStatus.CheckOnce; }
markPathToRootAsCheckOnce(): void {
let c: AppView<any> = this;
while (isPresent(c) && c.cdMode !== ChangeDetectorStatus.Detached) {
if (c.cdMode === ChangeDetectorStatus.Checked) {
c.cdMode = ChangeDetectorStatus.CheckOnce;
}
if (c.type === ViewType.COMPONENT) {
c = c.parentView;
} else {
c = c.viewContainer ? c.viewContainer.parentView : null;
}
}
}
eventHandler<E, R>(cb: (eventName: string, event?: E) => R): (eventName: string, event?: E) => R {
return cb;
}
throwDestroyedError(details: string): void { throw viewDestroyedError(details); }
}
export class DebugAppView<T> extends AppView<T> {
private _currentDebugContext: DebugContext = null;
constructor(
clazz: any, componentType: RenderComponentType, type: ViewType, viewUtils: ViewUtils,
parentView: AppView<any>, parentIndex: number, parentNode: any, cdMode: ChangeDetectorStatus,
public staticNodeDebugInfos: StaticNodeDebugInfo[],
declaredViewContainer: ViewContainer = null) {
super(
clazz, componentType, type, viewUtils, parentView, parentIndex, parentNode, cdMode,
declaredViewContainer);
}
create(context: T) {
this._resetDebug();
try {
return super.create(context);
} catch (e) {
this._rethrowWithContext(e);
throw e;
}
}
createHostView(
rootSelectorOrNode: string|any, injector: Injector,
projectableNodes: any[][] = null): ComponentRef<any> {
this._resetDebug();
try {
return super.createHostView(rootSelectorOrNode, injector, projectableNodes);
} catch (e) {
this._rethrowWithContext(e);
throw e;
}
}
injectorGet(token: any, nodeIndex: number, notFoundResult?: any): any {
this._resetDebug();
try {
return super.injectorGet(token, nodeIndex, notFoundResult);
} catch (e) {
this._rethrowWithContext(e);
throw e;
}
}
detach(): void {
this._resetDebug();
try {
super.detach();
} catch (e) {
this._rethrowWithContext(e);
throw e;
}
}
destroy() {
this._resetDebug();
try {
super.destroy();
} catch (e) {
this._rethrowWithContext(e);
throw e;
}
}
detectChanges(throwOnChange: boolean): void {
this._resetDebug();
try {
super.detectChanges(throwOnChange);
} catch (e) {
this._rethrowWithContext(e);
throw e;
}
}
private _resetDebug() { this._currentDebugContext = null; }
debug(nodeIndex: number, rowNum: number, colNum: number): DebugContext {
return this._currentDebugContext = new DebugContext(this, nodeIndex, rowNum, colNum);
}
private _rethrowWithContext(e: any) {
if (!(getType(e) == viewWrappedError)) {
if (!(getType(e) == expressionChangedAfterItHasBeenCheckedError)) {
this.cdMode = ChangeDetectorStatus.Errored;
}
if (isPresent(this._currentDebugContext)) {
throw viewWrappedError(e, this._currentDebugContext);
}
}
}
eventHandler<E, R>(cb: (eventName: string, event?: E) => R): (eventName: string, event?: E) => R {
const superHandler = super.eventHandler(cb);
return (eventName: string, event?: any) => {
this._resetDebug();
try {
return superHandler.call(this, eventName, event);
} catch (e) {
this._rethrowWithContext(e);
throw e;
}
};
}
}

View File

@ -1,132 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {Injector} from '../di/injector';
import {ElementRef} from './element_ref';
import {AppView} from './view';
import {ViewContainerRef_} from './view_container_ref';
import {ViewType} from './view_type';
/**
* A ViewContainer is created for elements that have a ViewContainerRef
* to keep track of the nested views.
*/
export class ViewContainer {
public nestedViews: AppView<any>[];
// views that have been declared at the place of this view container,
// but inserted into another view container
public projectedViews: AppView<any>[];
constructor(
public index: number, public parentIndex: number, public parentView: AppView<any>,
public nativeElement: any) {}
get elementRef(): ElementRef { return new ElementRef(this.nativeElement); }
get vcRef(): ViewContainerRef_ { return new ViewContainerRef_(this); }
get parentInjector(): Injector { return this.parentView.injector(this.parentIndex); }
get injector(): Injector { return this.parentView.injector(this.index); }
detectChangesInNestedViews(throwOnChange: boolean): void {
if (this.nestedViews) {
for (let i = 0; i < this.nestedViews.length; i++) {
this.nestedViews[i].detectChanges(throwOnChange);
}
}
}
destroyNestedViews(): void {
if (this.nestedViews) {
for (let i = 0; i < this.nestedViews.length; i++) {
this.nestedViews[i].destroy();
}
}
}
visitNestedViewRootNodes<C>(cb: (node: any, ctx: C) => void, c: C): void {
if (this.nestedViews) {
for (let i = 0; i < this.nestedViews.length; i++) {
this.nestedViews[i].visitRootNodesInternal(cb, c);
}
}
}
mapNestedViews(nestedViewClass: any, callback: Function): any[] {
const result: any[] = [];
if (this.nestedViews) {
for (let i = 0; i < this.nestedViews.length; i++) {
const nestedView = this.nestedViews[i];
if (nestedView.clazz === nestedViewClass) {
result.push(callback(nestedView));
}
}
}
if (this.projectedViews) {
for (let i = 0; i < this.projectedViews.length; i++) {
const projectedView = this.projectedViews[i];
if (projectedView.clazz === nestedViewClass) {
result.push(callback(projectedView));
}
}
}
return result;
}
moveView(view: AppView<any>, toIndex: number) {
const fromIndex = this.nestedViews.indexOf(view);
if (view.type === ViewType.COMPONENT) {
throw new Error(`Component views can't be moved!`);
}
let nestedViews = this.nestedViews;
if (nestedViews == null) {
nestedViews = [];
this.nestedViews = nestedViews;
}
nestedViews.splice(fromIndex, 1);
nestedViews.splice(toIndex, 0, view);
const prevView = toIndex > 0 ? nestedViews[toIndex - 1] : null;
view.moveAfter(this, prevView);
}
attachView(view: AppView<any>, viewIndex: number) {
if (view.type === ViewType.COMPONENT) {
throw new Error(`Component views can't be moved!`);
}
let nestedViews = this.nestedViews;
if (nestedViews == null) {
nestedViews = [];
this.nestedViews = nestedViews;
}
// perf: array.push is faster than array.splice!
if (viewIndex >= nestedViews.length) {
nestedViews.push(view);
} else {
nestedViews.splice(viewIndex, 0, view);
}
const prevView = viewIndex > 0 ? nestedViews[viewIndex - 1] : null;
view.attachAfter(this, prevView);
}
detachView(viewIndex: number): AppView<any> {
const view = this.nestedViews[viewIndex];
// perf: array.pop is faster than array.splice!
if (viewIndex >= this.nestedViews.length - 1) {
this.nestedViews.pop();
} else {
this.nestedViews.splice(viewIndex, 1);
}
if (view.type === ViewType.COMPONENT) {
throw new Error(`Component views can't be moved!`);
}
view.detach();
return view;
}
}

View File

@ -7,14 +7,10 @@
*/
import {Injector} from '../di/injector';
import {WtfScopeFn, wtfCreateScope, wtfLeave} from '../profile/profile';
import {ComponentFactory, ComponentRef} from './component_factory';
import {ElementRef} from './element_ref';
import {TemplateRef} from './template_ref';
import {ViewContainer} from './view_container';
import {EmbeddedViewRef, ViewRef, ViewRef_} from './view_ref';
import {EmbeddedViewRef, ViewRef} from './view_ref';
/**
@ -125,97 +121,3 @@ export abstract class ViewContainerRef {
*/
abstract detach(index?: number): ViewRef;
}
export class ViewContainerRef_ implements ViewContainerRef {
constructor(private _element: ViewContainer) {}
get(index: number): ViewRef { return this._element.nestedViews[index].ref; }
get length(): number {
const views = this._element.nestedViews;
return views ? views.length : 0;
}
get element(): ElementRef { return this._element.elementRef; }
get injector(): Injector { return this._element.injector; }
get parentInjector(): Injector { return this._element.parentInjector; }
// TODO(rado): profile and decide whether bounds checks should be added
// to the methods below.
createEmbeddedView<C>(templateRef: TemplateRef<C>, context: C = null, index: number = -1):
EmbeddedViewRef<C> {
const viewRef: EmbeddedViewRef<any> = templateRef.createEmbeddedView(context);
this.insert(viewRef, index);
return viewRef;
}
/** @internal */
_createComponentInContainerScope: WtfScopeFn =
wtfCreateScope('ViewContainerRef#createComponent()');
createComponent<C>(
componentFactory: ComponentFactory<C>, index: number = -1, injector: Injector = null,
projectableNodes: any[][] = null): ComponentRef<C> {
const s = this._createComponentInContainerScope();
const contextInjector = injector || this._element.parentInjector;
const componentRef = componentFactory.create(contextInjector, projectableNodes);
this.insert(componentRef.hostView, index);
return wtfLeave(s, componentRef);
}
/** @internal */
_insertScope = wtfCreateScope('ViewContainerRef#insert()');
// TODO(i): refactor insert+remove into move
insert(viewRef: ViewRef, index: number = -1): ViewRef {
const s = this._insertScope();
if (index == -1) index = this.length;
const viewRef_ = <ViewRef_<any>>viewRef;
this._element.attachView(viewRef_.internalView, index);
return wtfLeave(s, viewRef_);
}
move(viewRef: ViewRef, currentIndex: number): ViewRef {
const s = this._insertScope();
if (currentIndex == -1) return;
const viewRef_ = <ViewRef_<any>>viewRef;
this._element.moveView(viewRef_.internalView, currentIndex);
return wtfLeave(s, viewRef_);
}
indexOf(viewRef: ViewRef): number {
return this.length ? this._element.nestedViews.indexOf((<ViewRef_<any>>viewRef).internalView) :
-1;
}
/** @internal */
_removeScope = wtfCreateScope('ViewContainerRef#remove()');
// TODO(i): rename to destroy
remove(index: number = -1): void {
const s = this._removeScope();
if (index == -1) index = this.length - 1;
const view = this._element.detachView(index);
view.destroy();
// view is intentionally not returned to the client.
wtfLeave(s);
}
/** @internal */
_detachScope = wtfCreateScope('ViewContainerRef#detach()');
// TODO(i): refactor insert+remove into move
detach(index: number = -1): ViewRef {
const s = this._detachScope();
if (index == -1) index = this.length - 1;
const view = this._element.detachView(index);
return wtfLeave(s, view.ref);
}
clear(): void {
for (let i = this.length - 1; i >= 0; i--) {
this.remove(i);
}
}
}

View File

@ -6,12 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AnimationQueue} from '../animation/animation_queue';
import {ApplicationRef} from '../application_ref';
import {ChangeDetectorRef} from '../change_detection/change_detector_ref';
import {ChangeDetectorStatus} from '../change_detection/constants';
import {AppView} from './view';
/**
@ -92,46 +88,3 @@ export interface InternalViewRef extends ViewRef {
detachFromAppRef(): void;
attachToAppRef(appRef: ApplicationRef): void;
}
export class ViewRef_<C> implements EmbeddedViewRef<C>, ChangeDetectorRef, InternalViewRef {
/** @internal */
_originalMode: ChangeDetectorStatus;
constructor(private _view: AppView<C>, public animationQueue: AnimationQueue) {
this._view = _view;
this._originalMode = this._view.cdMode;
}
get internalView(): AppView<C> { return this._view; }
get rootNodes(): any[] { return this._view.flatRootNodes; }
get context() { return this._view.context; }
get destroyed(): boolean { return this._view.destroyed; }
markForCheck(): void { this._view.markPathToRootAsCheckOnce(); }
detach(): void { this._view.cdMode = ChangeDetectorStatus.Detached; }
detectChanges(): void {
this._view.detectChanges(false);
this.animationQueue.flush();
}
checkNoChanges(): void { this._view.detectChanges(true); }
reattach(): void {
this._view.cdMode = this._originalMode;
this.markForCheck();
}
onDestroy(callback: Function) {
if (!this._view.disposables) {
this._view.disposables = [];
}
this._view.disposables.push(callback);
}
destroy() { this._view.detachAndDestroy(); }
detachFromAppRef() { this._view.detach(); }
attachToAppRef(appRef: ApplicationRef) { this._view.attachToAppRef(appRef); }
}

View File

@ -1,17 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 enum ViewType {
// A view that contains the host element with bound component directive.
// Contains a COMPONENT view
HOST,
// The view of the component can contain 0 to n EMBEDDED views
COMPONENT,
// A view is embedded into another View via a <ng-template> element inside of a COMPONENT view
EMBEDDED
}

View File

@ -1,736 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {AnimationQueue} from '../animation/animation_queue';
import {SimpleChange, devModeEqual} from '../change_detection/change_detection';
import {Injectable} from '../di';
import {isPresent, looseIdentical} from '../facade/lang';
import {ViewEncapsulation} from '../metadata/view';
import {RenderComponentType, RenderDebugInfo, Renderer, RootRenderer} from '../render/api';
import {Sanitizer, SecurityContext} from '../security';
import {Type} from '../type';
import {VERSION} from '../version';
import {ComponentFactory} from './component_factory';
import {expressionChangedAfterItHasBeenCheckedError} from './errors';
import {AppView} from './view';
@Injectable()
export class ViewUtils {
sanitizer: Sanitizer;
constructor(
private _renderer: RootRenderer, sanitizer: Sanitizer,
public animationQueue: AnimationQueue) {
this.sanitizer = sanitizer;
}
/** @internal */
renderComponent(renderComponentType: RenderComponentType): Renderer {
return this._renderer.renderComponent(renderComponentType);
}
}
let nextRenderComponentTypeId = 0;
export function createRenderComponentType(
templateUrl: string, slotCount: number, encapsulation: ViewEncapsulation,
styles: Array<string|any[]>, animations: any): RenderComponentType {
return new RenderComponentType(
`${nextRenderComponentTypeId++}`, templateUrl, slotCount, encapsulation, styles, animations);
}
export function addToArray(e: any, array: any[]) {
array.push(e);
}
export function interpolate(valueCount: number, constAndInterp: string[]): string {
let result = '';
for (let i = 0; i < valueCount * 2; i = i + 2) {
result = result + constAndInterp[i] + _toStringWithNull(constAndInterp[i + 1]);
}
return result + constAndInterp[valueCount * 2];
}
export function inlineInterpolate(
valueCount: number, c0: string, a1: any, c1: string, a2?: any, c2?: string, a3?: any,
c3?: string, a4?: any, c4?: string, a5?: any, c5?: string, a6?: any, c6?: string, a7?: any,
c7?: string, a8?: any, c8?: string, a9?: any, c9?: string): string {
switch (valueCount) {
case 1:
return c0 + _toStringWithNull(a1) + c1;
case 2:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2;
case 3:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
c3;
case 4:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
c3 + _toStringWithNull(a4) + c4;
case 5:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5;
case 6:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) + c6;
case 7:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) +
c6 + _toStringWithNull(a7) + c7;
case 8:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) +
c6 + _toStringWithNull(a7) + c7 + _toStringWithNull(a8) + c8;
case 9:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) +
c6 + _toStringWithNull(a7) + c7 + _toStringWithNull(a8) + c8 + _toStringWithNull(a9) + c9;
default:
throw new Error(`Does not support more than 9 expressions`);
}
}
function _toStringWithNull(v: any): string {
return v != null ? v.toString() : '';
}
export function checkBinding(
view: AppView<any>, oldValue: any, newValue: any, forceUpdate: boolean): boolean {
const isFirstCheck = view.numberOfChecks === 0;
if (view.throwOnChange) {
if (isFirstCheck || !devModeEqual(oldValue, newValue)) {
throw expressionChangedAfterItHasBeenCheckedError(oldValue, newValue, isFirstCheck);
}
return false;
} else {
return isFirstCheck || forceUpdate || !looseIdentical(oldValue, newValue);
}
}
export function checkBindingChange(
view: AppView<any>, oldValue: any, newValue: any, forceUpdate: boolean): SimpleChange {
if (checkBinding(view, oldValue, newValue, forceUpdate)) {
return new SimpleChange(oldValue, newValue, view.numberOfChecks === 0);
}
}
export function checkRenderText(
view: AppView<any>, renderElement: any, oldValue: any, newValue: any, forceUpdate: boolean) {
if (checkBinding(view, oldValue, newValue, forceUpdate)) {
view.renderer.setText(renderElement, newValue);
}
}
export function checkRenderProperty(
view: AppView<any>, renderElement: any, propName: string, oldValue: any, newValue: any,
forceUpdate: boolean, securityContext: SecurityContext) {
if (checkBinding(view, oldValue, newValue, forceUpdate)) {
let renderValue =
securityContext ? view.viewUtils.sanitizer.sanitize(securityContext, newValue) : newValue;
view.renderer.setElementProperty(renderElement, propName, renderValue);
}
}
export function checkRenderAttribute(
view: AppView<any>, renderElement: any, attrName: string, oldValue: any, newValue: any,
forceUpdate: boolean, securityContext: SecurityContext) {
if (checkBinding(view, oldValue, newValue, forceUpdate)) {
let renderValue =
securityContext ? view.viewUtils.sanitizer.sanitize(securityContext, newValue) : newValue;
renderValue = renderValue != null ? renderValue.toString() : null;
view.renderer.setElementAttribute(renderElement, attrName, renderValue);
}
}
export function checkRenderClass(
view: AppView<any>, renderElement: any, className: string, oldValue: any, newValue: any,
forceUpdate: boolean) {
if (checkBinding(view, oldValue, newValue, forceUpdate)) {
view.renderer.setElementClass(renderElement, className, newValue);
}
}
export function checkRenderStyle(
view: AppView<any>, renderElement: any, styleName: string, unit: string, oldValue: any,
newValue: any, forceUpdate: boolean, securityContext: SecurityContext) {
if (checkBinding(view, oldValue, newValue, forceUpdate)) {
let renderValue =
securityContext ? view.viewUtils.sanitizer.sanitize(securityContext, newValue) : newValue;
if (renderValue != null) {
renderValue = renderValue.toString();
if (unit != null) {
renderValue = renderValue + unit;
}
} else {
renderValue = null;
}
view.renderer.setElementStyle(renderElement, styleName, renderValue);
}
}
export function castByValue<T>(input: any, value: T): T {
return <T>input;
}
export const EMPTY_ARRAY: any[] = [];
export const EMPTY_MAP = {};
export function pureProxy1<P0, R>(fn: (p0: P0) => R): (p0: P0) => R {
let numberOfChecks = 0;
let result: R;
let v0: any;
return (p0) => {
if (!numberOfChecks++ || !looseIdentical(v0, p0)) {
v0 = p0;
result = fn(p0);
}
return result;
};
}
export function pureProxy2<P0, P1, R>(fn: (p0: P0, p1: P1) => R): (p0: P0, p1: P1) => R {
let numberOfChecks = 0;
let result: R;
let v0: any;
let v1: any;
return (p0, p1) => {
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1)) {
v0 = p0;
v1 = p1;
result = fn(p0, p1);
}
return result;
};
}
export function pureProxy3<P0, P1, P2, R>(fn: (p0: P0, p1: P1, p2: P2) => R): (
p0: P0, p1: P1, p2: P2) => R {
let numberOfChecks = 0;
let result: R;
let v0: any;
let v1: any;
let v2: any;
return (p0, p1, p2) => {
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
!looseIdentical(v2, p2)) {
v0 = p0;
v1 = p1;
v2 = p2;
result = fn(p0, p1, p2);
}
return result;
};
}
export function pureProxy4<P0, P1, P2, P3, R>(fn: (p0: P0, p1: P1, p2: P2, p3: P3) => R): (
p0: P0, p1: P1, p2: P2, p3: P3) => R {
let numberOfChecks = 0;
let result: R;
let v0: any, v1: any, v2: any, v3: any;
v0 = v1 = v2 = v3;
return (p0, p1, p2, p3) => {
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
!looseIdentical(v2, p2) || !looseIdentical(v3, p3)) {
v0 = p0;
v1 = p1;
v2 = p2;
v3 = p3;
result = fn(p0, p1, p2, p3);
}
return result;
};
}
export function pureProxy5<P0, P1, P2, P3, P4, R>(
fn: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => R): (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) =>
R {
let numberOfChecks = 0;
let result: R;
let v0: any, v1: any, v2: any, v3: any, v4: any;
v0 = v1 = v2 = v3 = v4;
return (p0, p1, p2, p3, p4) => {
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
!looseIdentical(v2, p2) || !looseIdentical(v3, p3) || !looseIdentical(v4, p4)) {
v0 = p0;
v1 = p1;
v2 = p2;
v3 = p3;
v4 = p4;
result = fn(p0, p1, p2, p3, p4);
}
return result;
};
}
export function pureProxy6<P0, P1, P2, P3, P4, P5, R>(
fn: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) =>
R): (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => R {
let numberOfChecks = 0;
let result: R;
let v0: any, v1: any, v2: any, v3: any, v4: any, v5: any;
v0 = v1 = v2 = v3 = v4 = v5;
return (p0, p1, p2, p3, p4, p5) => {
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
!looseIdentical(v2, p2) || !looseIdentical(v3, p3) || !looseIdentical(v4, p4) ||
!looseIdentical(v5, p5)) {
v0 = p0;
v1 = p1;
v2 = p2;
v3 = p3;
v4 = p4;
v5 = p5;
result = fn(p0, p1, p2, p3, p4, p5);
}
return result;
};
}
export function pureProxy7<P0, P1, P2, P3, P4, P5, P6, R>(
fn: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) =>
R): (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) => R {
let numberOfChecks = 0;
let result: R;
let v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any;
v0 = v1 = v2 = v3 = v4 = v5 = v6;
return (p0, p1, p2, p3, p4, p5, p6) => {
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
!looseIdentical(v2, p2) || !looseIdentical(v3, p3) || !looseIdentical(v4, p4) ||
!looseIdentical(v5, p5) || !looseIdentical(v6, p6)) {
v0 = p0;
v1 = p1;
v2 = p2;
v3 = p3;
v4 = p4;
v5 = p5;
v6 = p6;
result = fn(p0, p1, p2, p3, p4, p5, p6);
}
return result;
};
}
export function pureProxy8<P0, P1, P2, P3, P4, P5, P6, P7, R>(
fn: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) =>
R): (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) => R {
let numberOfChecks = 0;
let result: R;
let v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any;
v0 = v1 = v2 = v3 = v4 = v5 = v6 = v7;
return (p0, p1, p2, p3, p4, p5, p6, p7) => {
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
!looseIdentical(v2, p2) || !looseIdentical(v3, p3) || !looseIdentical(v4, p4) ||
!looseIdentical(v5, p5) || !looseIdentical(v6, p6) || !looseIdentical(v7, p7)) {
v0 = p0;
v1 = p1;
v2 = p2;
v3 = p3;
v4 = p4;
v5 = p5;
v6 = p6;
v7 = p7;
result = fn(p0, p1, p2, p3, p4, p5, p6, p7);
}
return result;
};
}
export function pureProxy9<P0, P1, P2, P3, P4, P5, P6, P7, P8, R>(
fn: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8) =>
R): (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8) => R {
let numberOfChecks = 0;
let result: R;
let v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any, v8: any;
v0 = v1 = v2 = v3 = v4 = v5 = v6 = v7 = v8;
return (p0, p1, p2, p3, p4, p5, p6, p7, p8) => {
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
!looseIdentical(v2, p2) || !looseIdentical(v3, p3) || !looseIdentical(v4, p4) ||
!looseIdentical(v5, p5) || !looseIdentical(v6, p6) || !looseIdentical(v7, p7) ||
!looseIdentical(v8, p8)) {
v0 = p0;
v1 = p1;
v2 = p2;
v3 = p3;
v4 = p4;
v5 = p5;
v6 = p6;
v7 = p7;
v8 = p8;
result = fn(p0, p1, p2, p3, p4, p5, p6, p7, p8);
}
return result;
};
}
export function pureProxy10<P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, R>(
fn: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9) =>
R): (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9) => R {
let numberOfChecks = 0;
let result: R;
let v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any, v8: any, v9: any;
v0 = v1 = v2 = v3 = v4 = v5 = v6 = v7 = v8 = v9;
return (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9) => {
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
!looseIdentical(v2, p2) || !looseIdentical(v3, p3) || !looseIdentical(v4, p4) ||
!looseIdentical(v5, p5) || !looseIdentical(v6, p6) || !looseIdentical(v7, p7) ||
!looseIdentical(v8, p8) || !looseIdentical(v9, p9)) {
v0 = p0;
v1 = p1;
v2 = p2;
v3 = p3;
v4 = p4;
v5 = p5;
v6 = p6;
v7 = p7;
v8 = p8;
v9 = p9;
result = fn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
}
return result;
};
}
export function setBindingDebugInfoForChanges(
renderer: Renderer, el: any, changes: {[key: string]: SimpleChange}) {
Object.keys(changes).forEach((propName) => {
setBindingDebugInfo(renderer, el, propName, changes[propName].currentValue);
});
}
export function setBindingDebugInfo(renderer: Renderer, el: any, propName: string, value: any) {
try {
renderer.setBindingDebugInfo(
el, `ng-reflect-${camelCaseToDashCase(propName)}`, value ? value.toString() : null);
} catch (e) {
renderer.setBindingDebugInfo(
el, `ng-reflect-${camelCaseToDashCase(propName)}`,
'[ERROR] Exception while trying to serialize the value');
}
}
const CAMEL_CASE_REGEXP = /([A-Z])/g;
function camelCaseToDashCase(input: string): string {
return input.replace(CAMEL_CASE_REGEXP, (...m: any[]) => '-' + m[1].toLowerCase());
}
export function createRenderElement(
renderer: Renderer, parentElement: any, name: string, attrs: InlineArray<string>,
debugInfo?: RenderDebugInfo): any {
const el = renderer.createElement(parentElement, name, debugInfo);
for (let i = 0; i < attrs.length; i += 2) {
renderer.setElementAttribute(el, attrs.get(i), attrs.get(i + 1));
}
return el;
}
export function selectOrCreateRenderHostElement(
renderer: Renderer, elementName: string, attrs: InlineArray<string>,
rootSelectorOrNode: string | any, debugInfo?: RenderDebugInfo): any {
let hostElement: any;
if (isPresent(rootSelectorOrNode)) {
hostElement = renderer.selectRootElement(rootSelectorOrNode, debugInfo);
for (let i = 0; i < attrs.length; i += 2) {
renderer.setElementAttribute(hostElement, attrs.get(i), attrs.get(i + 1));
}
renderer.setElementAttribute(hostElement, 'ng-version', VERSION.full);
} else {
hostElement = createRenderElement(renderer, null, elementName, attrs, debugInfo);
}
return hostElement;
}
export function subscribeToRenderElement(
view: AppView<any>, element: any, eventNamesAndTargets: InlineArray<string>,
listener: (eventName: string, event: any) => any) {
const disposables = createEmptyInlineArray(eventNamesAndTargets.length / 2);
for (let i = 0; i < eventNamesAndTargets.length; i += 2) {
const eventName = eventNamesAndTargets.get(i);
const eventTarget = eventNamesAndTargets.get(i + 1);
let disposable: Function;
if (eventTarget) {
disposable = view.renderer.listenGlobal(
eventTarget, eventName, listener.bind(view, `${eventTarget}:${eventName}`));
} else {
disposable = view.renderer.listen(element, eventName, listener.bind(view, eventName));
}
disposables.set(i / 2, disposable);
}
return disposeInlineArray.bind(null, disposables);
}
function disposeInlineArray(disposables: InlineArray<Function>) {
for (let i = 0; i < disposables.length; i++) {
disposables.get(i)();
}
}
export function noop() {}
export interface InlineArray<T> {
length: number;
get(index: number): T;
set(index: number, value: T): void;
}
function createEmptyInlineArray<T>(length: number): InlineArray<T> {
let ctor: any;
if (length <= 2) {
ctor = InlineArray2;
} else if (length <= 4) {
ctor = InlineArray4;
} else if (length <= 8) {
ctor = InlineArray8;
} else if (length <= 16) {
ctor = InlineArray16;
} else {
ctor = InlineArrayDynamic;
}
return new ctor(length);
}
class InlineArray0 implements InlineArray<any> {
length = 0;
get(index: number): any { return undefined; }
set(index: number, value: any): void {}
}
export class InlineArray2<T> implements InlineArray<T> {
constructor(public length: number, private _v0?: T, private _v1?: T) {}
get(index: number) {
switch (index) {
case 0:
return this._v0;
case 1:
return this._v1;
default:
return undefined;
}
}
set(index: number, value: T) {
switch (index) {
case 0:
this._v0 = value;
break;
case 1:
this._v1 = value;
break;
}
}
}
export class InlineArray4<T> implements InlineArray<T> {
constructor(
public length: number, private _v0?: T, private _v1?: T, private _v2?: T, private _v3?: T) {}
get(index: number) {
switch (index) {
case 0:
return this._v0;
case 1:
return this._v1;
case 2:
return this._v2;
case 3:
return this._v3;
default:
return undefined;
}
}
set(index: number, value: T) {
switch (index) {
case 0:
this._v0 = value;
break;
case 1:
this._v1 = value;
break;
case 2:
this._v2 = value;
break;
case 3:
this._v3 = value;
break;
}
}
}
export class InlineArray8<T> implements InlineArray<T> {
constructor(
public length: number, private _v0?: T, private _v1?: T, private _v2?: T, private _v3?: T,
private _v4?: T, private _v5?: T, private _v6?: T, private _v7?: T) {}
get(index: number) {
switch (index) {
case 0:
return this._v0;
case 1:
return this._v1;
case 2:
return this._v2;
case 3:
return this._v3;
case 4:
return this._v4;
case 5:
return this._v5;
case 6:
return this._v6;
case 7:
return this._v7;
default:
return undefined;
}
}
set(index: number, value: T) {
switch (index) {
case 0:
this._v0 = value;
break;
case 1:
this._v1 = value;
break;
case 2:
this._v2 = value;
break;
case 3:
this._v3 = value;
break;
case 4:
this._v4 = value;
break;
case 5:
this._v5 = value;
break;
case 6:
this._v6 = value;
break;
case 7:
this._v7 = value;
break;
}
}
}
export class InlineArray16<T> implements InlineArray<T> {
constructor(
public length: number, private _v0?: T, private _v1?: T, private _v2?: T, private _v3?: T,
private _v4?: T, private _v5?: T, private _v6?: T, private _v7?: T, private _v8?: T,
private _v9?: T, private _v10?: T, private _v11?: T, private _v12?: T, private _v13?: T,
private _v14?: T, private _v15?: T) {}
get(index: number) {
switch (index) {
case 0:
return this._v0;
case 1:
return this._v1;
case 2:
return this._v2;
case 3:
return this._v3;
case 4:
return this._v4;
case 5:
return this._v5;
case 6:
return this._v6;
case 7:
return this._v7;
case 8:
return this._v8;
case 9:
return this._v9;
case 10:
return this._v10;
case 11:
return this._v11;
case 12:
return this._v12;
case 13:
return this._v13;
case 14:
return this._v14;
case 15:
return this._v15;
default:
return undefined;
}
}
set(index: number, value: T) {
switch (index) {
case 0:
this._v0 = value;
break;
case 1:
this._v1 = value;
break;
case 2:
this._v2 = value;
break;
case 3:
this._v3 = value;
break;
case 4:
this._v4 = value;
break;
case 5:
this._v5 = value;
break;
case 6:
this._v6 = value;
break;
case 7:
this._v7 = value;
break;
case 8:
this._v8 = value;
break;
case 9:
this._v9 = value;
break;
case 10:
this._v10 = value;
break;
case 11:
this._v11 = value;
break;
case 12:
this._v12 = value;
break;
case 13:
this._v13 = value;
break;
case 14:
this._v14 = value;
break;
case 15:
this._v15 = value;
break;
}
}
}
export class InlineArrayDynamic<T> implements InlineArray<T> {
private _values: any[];
// Note: We still take the length argument so this class can be created
// in the same ways as the other classes!
constructor(public length: number, ...values: any[]) { this._values = values; }
get(index: number) { return this._values[index]; }
set(index: number, value: T) { this._values[index] = value; }
}
export const EMPTY_INLINE_ARRAY: InlineArray<any> = new InlineArray0();
/**
* This is a private API only used by the compiler to read the view class.
*/
export function getComponentFactoryViewClass(componentFactory: ComponentFactory<any>): Type<any> {
return componentFactory._viewClass;
}

View File

@ -6,7 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AnimationEntryMetadata} from '../animation/metadata';
import {ChangeDetectionStrategy} from '../change_detection/constants';
import {Provider} from '../di';
import {Type} from '../type';
@ -651,7 +650,7 @@ export interface Component extends Directive {
* - {@link animate animate()}
* - {@link keyframes keyframes()}
*/
animations?: AnimationEntryMetadata[];
animations?: any[];
/**
* Specifies how the template and the styles should be encapsulated:

View File

@ -6,8 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AnimationEntryMetadata} from '../animation/metadata';
/**
* Defines template and style encapsulation options available for Component's {@link Component}.
*
@ -74,7 +72,7 @@ export class ViewMetadata {
/** {@link Component.encapsulation} */
encapsulation: ViewEncapsulation;
/** {@link Component.animation} */
animations: AnimationEntryMetadata[];
animations: any[];
/** {@link Component.interpolation} */
interpolation: [string, string];
@ -85,7 +83,7 @@ export class ViewMetadata {
encapsulation?: ViewEncapsulation,
styles?: string[],
styleUrls?: string[],
animations?: AnimationEntryMetadata[],
animations?: any[],
interpolation?: [string, string]
} = {}) {
this.templateUrl = templateUrl;

View File

@ -6,9 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AnimationKeyframe} from '../../src/animation/animation_keyframe';
import {AnimationPlayer} from '../../src/animation/animation_player';
import {AnimationStyles} from '../../src/animation/animation_styles';
import {InjectionToken, Injector} from '../di';
import {ViewEncapsulation} from '../metadata/view';
@ -91,9 +88,8 @@ export abstract class Renderer {
abstract setText(renderNode: any, text: string): void;
abstract animate(
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],
duration: number, delay: number, easing: string,
previousPlayers?: AnimationPlayer[]): AnimationPlayer;
element: any, startingStyles: any, keyframes: any[], duration: number, delay: number,
easing: string, previousPlayers?: any[]): any;
}
export const RendererV2Interceptor = new InjectionToken<RendererV2[]>('RendererV2Interceptor');

View File

@ -11,10 +11,10 @@ export {ngContentDef} from './ng_content';
export {directiveDef, pipeDef, providerDef} from './provider';
export {pureArrayDef, pureObjectDef, purePipeDef} from './pure_expression';
export {queryDef} from './query';
export {ViewRef_, createComponentFactory, nodeValue} from './refs';
export {ViewRef_, createComponentFactory, getComponentViewDefinitionFactory, nodeValue} from './refs';
export {initServicesIfNeeded} from './services';
export {textDef} from './text';
export {createRendererTypeV2, elementEventFullName, rootRenderNodes, unwrapValue} from './util';
export {EMPTY_ARRAY, EMPTY_MAP, createRendererTypeV2, elementEventFullName, inlineInterpolate, interpolate, rootRenderNodes, unwrapValue} from './util';
export {viewDef} from './view';
export {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView} from './view_attach';

View File

@ -6,7 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {NoOpAnimationPlayer} from '../animation/animation_player';
import {ApplicationRef} from '../application_ref';
import {ChangeDetectorRef} from '../change_detection/change_detection';
import {Injector} from '../di';
@ -31,9 +30,22 @@ export function createComponentFactory(
return new ComponentFactory_(selector, componentType, viewDefFactory);
}
export function getComponentViewDefinitionFactory(componentFactory: ComponentFactory<any>):
ViewDefinitionFactory {
return (componentFactory as ComponentFactory_).viewDefFactory;
}
class ComponentFactory_ extends ComponentFactory<any> {
constructor(selector: string, componentType: Type<any>, viewDefFactory: ViewDefinitionFactory) {
super(selector, <any>viewDefFactory, componentType);
/**
* @internal
*/
viewDefFactory: ViewDefinitionFactory;
constructor(
public selector: string, public componentType: Type<any>,
viewDefFactory: ViewDefinitionFactory) {
super();
this.viewDefFactory = viewDefFactory;
}
/**
@ -42,7 +54,7 @@ class ComponentFactory_ extends ComponentFactory<any> {
create(
injector: Injector, projectableNodes: any[][] = null,
rootSelectorOrNode: string|any = null): ComponentRef<any> {
const viewDef = resolveViewDefinition(this._viewClass);
const viewDef = resolveViewDefinition(this.viewDefFactory);
const componentNodeIndex = viewDef.nodes[0].element.componentProvider.index;
const view = Services.createRootView(
injector, projectableNodes || [], rootSelectorOrNode, viewDef, EMPTY_CONTEXT);
@ -386,5 +398,5 @@ class RendererAdapter implements RendererV1 {
setText(renderNode: Text, text: string): void { this.delegate.setValue(renderNode, text); }
animate(): NoOpAnimationPlayer { return new NoOpAnimationPlayer(); }
animate(): any { throw new Error('Renderer.animate is no longer supported!'); }
}

View File

@ -337,3 +337,56 @@ export function splitNamespace(name: string): string[] {
}
return ['', name];
}
export function interpolate(valueCount: number, constAndInterp: string[]): string {
let result = '';
for (let i = 0; i < valueCount * 2; i = i + 2) {
result = result + constAndInterp[i] + _toStringWithNull(constAndInterp[i + 1]);
}
return result + constAndInterp[valueCount * 2];
}
export function inlineInterpolate(
valueCount: number, c0: string, a1: any, c1: string, a2?: any, c2?: string, a3?: any,
c3?: string, a4?: any, c4?: string, a5?: any, c5?: string, a6?: any, c6?: string, a7?: any,
c7?: string, a8?: any, c8?: string, a9?: any, c9?: string): string {
switch (valueCount) {
case 1:
return c0 + _toStringWithNull(a1) + c1;
case 2:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2;
case 3:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
c3;
case 4:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
c3 + _toStringWithNull(a4) + c4;
case 5:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5;
case 6:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) + c6;
case 7:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) +
c6 + _toStringWithNull(a7) + c7;
case 8:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) +
c6 + _toStringWithNull(a7) + c7 + _toStringWithNull(a8) + c8;
case 9:
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) +
c6 + _toStringWithNull(a7) + c7 + _toStringWithNull(a8) + c8 + _toStringWithNull(a9) + c9;
default:
throw new Error(`Does not support more than 9 expressions`);
}
}
function _toStringWithNull(v: any): string {
return v != null ? v.toString() : '';
}
export const EMPTY_ARRAY: any[] = [];
export const EMPTY_MAP: {[key: string]: any} = {};

View File

@ -1,76 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {el} from '@angular/platform-browser/testing/browser_util';
import {ViewAnimationMap} from '../../src/animation/view_animation_map';
import {MockAnimationPlayer} from '../../testing/mock_animation_player';
import {beforeEach, describe, expect, it} from '../../testing/testing_internal';
export function main() {
describe('ActiveAnimationsPlayersMap', function() {
let playersMap: any /** TODO #9100 */;
let elementNode: any /** TODO #9100 */;
const animationName = 'animationName';
beforeEach(() => {
playersMap = new ViewAnimationMap();
elementNode = el('<div></div>');
});
afterEach(() => {
getDOM().remove(elementNode);
elementNode = null;
});
it('should register a player an allow it to be accessed', () => {
const player = new MockAnimationPlayer();
playersMap.set(elementNode, animationName, player);
expect(playersMap.find(elementNode, animationName)).toBe(player);
expect(playersMap.findAllPlayersByElement(elementNode)).toEqual([player]);
expect(playersMap.getAllPlayers()).toEqual([player]);
expect(countPlayers(playersMap)).toEqual(1);
});
it('should remove a registered player when remove() is called', () => {
const player = new MockAnimationPlayer();
playersMap.set(elementNode, animationName, player);
expect(playersMap.find(elementNode, animationName)).toBe(player);
expect(countPlayers(playersMap)).toEqual(1);
playersMap.remove(elementNode, animationName);
expect(playersMap.find(elementNode, animationName)).not.toBe(player);
expect(countPlayers(playersMap)).toEqual(0);
});
it('should allow multiple players to be registered on the same element', () => {
const player1 = new MockAnimationPlayer();
const player2 = new MockAnimationPlayer();
playersMap.set(elementNode, 'myAnimation1', player1);
playersMap.set(elementNode, 'myAnimation2', player2);
expect(countPlayers(playersMap)).toEqual(2);
expect(playersMap.findAllPlayersByElement(elementNode)).toEqual([player1, player2]);
});
it('should only allow one player to be set for a given element/animationName pair', () => {
const player1 = new MockAnimationPlayer();
const player2 = new MockAnimationPlayer();
playersMap.set(elementNode, animationName, player1);
expect(playersMap.find(elementNode, animationName)).toBe(player1);
expect(countPlayers(playersMap)).toEqual(1);
playersMap.set(elementNode, animationName, player2);
expect(playersMap.find(elementNode, animationName)).toBe(player2);
expect(countPlayers(playersMap)).toEqual(1);
});
});
}
function countPlayers(map: ViewAnimationMap): number {
return map.getAllPlayers().length;
}

View File

@ -1,204 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {AnimationGroupPlayer} from '../../src/animation/animation_group_player';
import {fakeAsync, flushMicrotasks} from '../../testing';
import {MockAnimationPlayer} from '../../testing/mock_animation_player';
import {beforeEach, describe, expect, it} from '../../testing/testing_internal';
export function main() {
describe('AnimationGroupPlayer', function() {
let players: any /** TODO #9100 */;
beforeEach(() => {
players = [
new MockAnimationPlayer(),
new MockAnimationPlayer(),
new MockAnimationPlayer(),
];
});
const assertLastStatus =
(player: MockAnimationPlayer, status: string, match: boolean, iOffset: number = 0) => {
const index = player.log.length - 1 + iOffset;
const actual = player.log.length > 0 ? player.log[index] : null;
if (match) {
expect(actual).toEqual(status);
} else {
expect(actual).not.toEqual(status);
}
};
const assertPlaying = (player: MockAnimationPlayer, isPlaying: boolean) => {
assertLastStatus(player, 'play', isPlaying);
};
it('should play and pause all players in parallel', () => {
const group = new AnimationGroupPlayer(players);
assertPlaying(players[0], false);
assertPlaying(players[1], false);
assertPlaying(players[2], false);
group.play();
assertPlaying(players[0], true);
assertPlaying(players[1], true);
assertPlaying(players[2], true);
group.pause();
assertPlaying(players[0], false);
assertPlaying(players[1], false);
assertPlaying(players[2], false);
});
it('should finish when all players have finished', () => {
const group = new AnimationGroupPlayer(players);
let completed = false;
group.onDone(() => completed = true);
group.play();
expect(completed).toBeFalsy();
players[0].finish();
expect(completed).toBeFalsy();
players[1].finish();
expect(completed).toBeFalsy();
players[2].finish();
expect(completed).toBeTruthy();
});
it('should restart all the players', () => {
const group = new AnimationGroupPlayer(players);
group.play();
assertLastStatus(players[0], 'restart', false);
assertLastStatus(players[1], 'restart', false);
assertLastStatus(players[2], 'restart', false);
group.restart();
assertLastStatus(players[0], 'restart', true);
assertLastStatus(players[1], 'restart', true);
assertLastStatus(players[2], 'restart', true);
});
it('should not destroy the inner the players when finished', () => {
const group = new AnimationGroupPlayer(players);
let completed = false;
group.onDone(() => completed = true);
expect(completed).toBeFalsy();
group.play();
assertLastStatus(players[0], 'finish', false);
assertLastStatus(players[1], 'finish', false);
assertLastStatus(players[2], 'finish', false);
expect(completed).toBeFalsy();
group.finish();
assertLastStatus(players[0], 'finish', true);
assertLastStatus(players[1], 'finish', true);
assertLastStatus(players[2], 'finish', true);
expect(completed).toBeTruthy();
});
it('should not call destroy automatically when finished even if a parent player finishes',
() => {
const group = new AnimationGroupPlayer(players);
const parent = new AnimationGroupPlayer([group, new MockAnimationPlayer()]);
group.play();
assertLastStatus(players[0], 'destroy', false);
assertLastStatus(players[1], 'destroy', false);
assertLastStatus(players[2], 'destroy', false);
group.finish();
assertLastStatus(players[0], 'destroy', false);
assertLastStatus(players[1], 'destroy', false);
assertLastStatus(players[2], 'destroy', false);
parent.finish();
assertLastStatus(players[0], 'destroy', false);
assertLastStatus(players[1], 'destroy', false);
assertLastStatus(players[2], 'destroy', false);
});
it('should function without any players', () => {
const group = new AnimationGroupPlayer([]);
group.onDone(() => {});
group.pause();
group.play();
group.finish();
group.restart();
group.destroy();
});
it('should run the onStart method when started but only once', () => {
const player = new AnimationGroupPlayer([]);
let calls = 0;
player.onStart(() => calls++);
expect(calls).toEqual(0);
player.play();
expect(calls).toEqual(1);
player.pause();
player.play();
expect(calls).toEqual(1);
});
it('should call onDone after the next microtask if no players are provided', fakeAsync(() => {
const group = new AnimationGroupPlayer([]);
let completed = false;
group.onDone(() => completed = true);
expect(completed).toEqual(false);
flushMicrotasks();
expect(completed).toEqual(true);
}));
it('should not allow the player to be destroyed if it already has been destroyed unless reset',
fakeAsync(() => {
const p1 = new MockAnimationPlayer();
const p2 = new MockAnimationPlayer();
const innerPlayers = [p1, p2];
const groupPlayer = new AnimationGroupPlayer(innerPlayers);
expect(p1.log[p1.log.length - 1]).not.toContain('destroy');
expect(p2.log[p2.log.length - 1]).not.toContain('destroy');
groupPlayer.destroy();
expect(p1.log[p1.log.length - 1]).toContain('destroy');
expect(p2.log[p2.log.length - 1]).toContain('destroy');
p1.log = p2.log = [];
groupPlayer.destroy();
expect(p1.log[p1.log.length - 1]).not.toContain('destroy');
expect(p2.log[p2.log.length - 1]).not.toContain('destroy');
groupPlayer.reset();
groupPlayer.destroy();
expect(p1.log[p1.log.length - 1]).toContain('destroy');
expect(p2.log[p2.log.length - 1]).toContain('destroy');
}));
});
}

View File

@ -6,7 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AUTO_STYLE, AnimationEvent, animate, keyframes, state, style, transition, trigger} from '@angular/animations';
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
import {Component, HostBinding, HostListener, ViewChild} from '@angular/core';
import {AnimationDriver, BrowserAnimationsModule, ɵAnimationEngine} from '@angular/platform-browser/animations';
import {MockAnimationDriver, MockAnimationPlayer} from '@angular/platform-browser/animations/testing';
@ -14,22 +13,6 @@ import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {TestBed} from '../../testing';
export function main() {
describe('view engine', () => {
beforeEach(() => {
TestBed.configureCompiler({
useJit: true,
providers: [{
provide: USE_VIEW_ENGINE,
useValue: true,
}],
});
});
declareTests({useJit: true});
});
}
function declareTests({useJit}: {useJit: boolean}) {
// these tests are only mean't to be run within the DOM (for now)
if (typeof Element == 'undefined') return;

View File

@ -1,45 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {NoOpAnimationPlayer} from '../../src/animation/animation_player';
import {fakeAsync, flushMicrotasks} from '../../testing';
import {describe, expect, it} from '../../testing/testing_internal';
export function main() {
describe('NoOpAnimationPlayer', function() {
it('should call onDone after the next microtask when constructed', fakeAsync(() => {
const player = new NoOpAnimationPlayer();
let completed = false;
player.onDone(() => completed = true);
expect(completed).toEqual(false);
flushMicrotasks();
expect(completed).toEqual(true);
}));
it('should be able to run each of the player methods', fakeAsync(() => {
const player = new NoOpAnimationPlayer();
player.pause();
player.play();
player.finish();
player.restart();
player.destroy();
}));
it('should run the onStart method when started but only once', fakeAsync(() => {
const player = new NoOpAnimationPlayer();
let calls = 0;
player.onStart(() => calls++);
expect(calls).toEqual(0);
player.play();
expect(calls).toEqual(1);
player.pause();
player.play();
expect(calls).toEqual(1);
}));
});
}

View File

@ -1,143 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {AnimationQueue} from '@angular/core/src/animation/animation_queue';
import {NgZone} from '../../src/zone/ng_zone';
import {TestBed, fakeAsync, flushMicrotasks} from '../../testing';
import {MockAnimationPlayer} from '../../testing/mock_animation_player';
import {beforeEach, describe, expect, it} from '../../testing/testing_internal';
export function main() {
describe('AnimationQueue', function() {
beforeEach(() => { TestBed.configureTestingModule({declarations: [], imports: []}); });
it('should queue animation players and run when flushed, but only as the next scheduled microtask',
fakeAsync(() => {
const zone = TestBed.get(NgZone);
const queue = new AnimationQueue(zone);
const log: string[] = [];
const p1 = new MockAnimationPlayer();
const p2 = new MockAnimationPlayer();
const p3 = new MockAnimationPlayer();
p1.onStart(() => log.push('1'));
p2.onStart(() => log.push('2'));
p3.onStart(() => log.push('3'));
queue.enqueue(p1);
queue.enqueue(p2);
queue.enqueue(p3);
expect(log).toEqual([]);
queue.flush();
expect(log).toEqual([]);
flushMicrotasks();
expect(log).toEqual(['1', '2', '3']);
}));
it('should always run each of the animation players outside of the angular zone on start',
fakeAsync(() => {
const zone = TestBed.get(NgZone);
const queue = new AnimationQueue(zone);
const player = new MockAnimationPlayer();
let eventHasRun = false;
player.onStart(() => {
NgZone.assertNotInAngularZone();
eventHasRun = true;
});
zone.run(() => {
NgZone.assertInAngularZone();
queue.enqueue(player);
queue.flush();
flushMicrotasks();
});
expect(eventHasRun).toBe(true);
}));
it('should always run each of the animation players outside of the angular zone on done',
fakeAsync(() => {
const zone = TestBed.get(NgZone);
const queue = new AnimationQueue(zone);
const player = new MockAnimationPlayer();
let eventHasRun = false;
player.onDone(() => {
NgZone.assertNotInAngularZone();
eventHasRun = true;
});
zone.run(() => {
NgZone.assertInAngularZone();
queue.enqueue(player);
queue.flush();
flushMicrotasks();
});
expect(eventHasRun).toBe(false);
player.finish();
expect(eventHasRun).toBe(true);
}));
it('should not run animations again incase an animation midway fails', fakeAsync(() => {
const zone = TestBed.get(NgZone);
const queue = new AnimationQueue(zone);
const log: string[] = [];
const p1 = new PlayerThatFails(false);
const p2 = new PlayerThatFails(true);
const p3 = new PlayerThatFails(false);
p1.onStart(() => log.push('1'));
p2.onStart(() => log.push('2'));
p3.onStart(() => log.push('3'));
queue.enqueue(p1);
queue.enqueue(p2);
queue.enqueue(p3);
queue.flush();
expect(() => flushMicrotasks()).toThrowError();
expect(log).toEqual(['1', '2']);
// let's reset this so that it gets triggered again
p2.reset();
p2.onStart(() => log.push('2'));
queue.flush();
expect(() => flushMicrotasks()).not.toThrowError();
expect(log).toEqual(['1', '2', '3']);
}));
});
}
class PlayerThatFails extends MockAnimationPlayer {
private _animationStarted = false;
constructor(public doFail: boolean) { super(); }
play() {
super.play();
this._animationStarted = true;
if (this.doFail) {
throw new Error('Oh nooooo');
}
}
reset() { this._animationStarted = false; }
hasStarted() { return this._animationStarted; }
}

View File

@ -1,226 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {AnimationSequencePlayer} from '../../src/animation/animation_sequence_player';
import {fakeAsync, flushMicrotasks} from '../../testing';
import {MockAnimationPlayer} from '../../testing/mock_animation_player';
import {beforeEach, describe, expect, it} from '../../testing/testing_internal';
export function main() {
describe('AnimationSequencePlayer', function() {
let players: any /** TODO #9100 */;
beforeEach(() => {
players = [
new MockAnimationPlayer(),
new MockAnimationPlayer(),
new MockAnimationPlayer(),
];
});
const assertLastStatus =
(player: MockAnimationPlayer, status: string, match: boolean, iOffset: number = 0) => {
const index = player.log.length - 1 + iOffset;
const actual = player.log.length > 0 ? player.log[index] : null;
if (match) {
expect(actual).toEqual(status);
} else {
expect(actual).not.toEqual(status);
}
};
const assertPlaying = (player: MockAnimationPlayer, isPlaying: boolean) => {
assertLastStatus(player, 'play', isPlaying);
};
it('should pause/play the active player', () => {
const sequence = new AnimationSequencePlayer(players);
assertPlaying(players[0], false);
assertPlaying(players[1], false);
assertPlaying(players[2], false);
sequence.play();
assertPlaying(players[0], true);
assertPlaying(players[1], false);
assertPlaying(players[2], false);
sequence.pause();
assertPlaying(players[0], false);
assertPlaying(players[1], false);
assertPlaying(players[2], false);
sequence.play();
players[0].finish();
assertPlaying(players[0], false);
assertPlaying(players[1], true);
assertPlaying(players[2], false);
players[1].finish();
assertPlaying(players[0], false);
assertPlaying(players[1], false);
assertPlaying(players[2], true);
players[2].finish();
sequence.pause();
assertPlaying(players[0], false);
assertPlaying(players[1], false);
assertPlaying(players[2], false);
});
it('should finish when all players have finished', () => {
const sequence = new AnimationSequencePlayer(players);
let completed = false;
sequence.onDone(() => completed = true);
sequence.play();
expect(completed).toBeFalsy();
players[0].finish();
expect(completed).toBeFalsy();
players[1].finish();
expect(completed).toBeFalsy();
players[2].finish();
expect(completed).toBeTruthy();
});
it('should restart all the players', () => {
const sequence = new AnimationSequencePlayer(players);
sequence.play();
assertPlaying(players[0], true);
assertPlaying(players[1], false);
assertPlaying(players[2], false);
players[0].finish();
assertPlaying(players[0], false);
assertPlaying(players[1], true);
assertPlaying(players[2], false);
sequence.restart();
assertLastStatus(players[0], 'restart', true);
assertLastStatus(players[1], 'reset', true);
assertLastStatus(players[2], 'reset', true);
});
it('should finish all the players', () => {
const sequence = new AnimationSequencePlayer(players);
let completed = false;
sequence.onDone(() => completed = true);
sequence.play();
assertLastStatus(players[0], 'finish', false);
assertLastStatus(players[1], 'finish', false);
assertLastStatus(players[2], 'finish', false);
sequence.finish();
assertLastStatus(players[0], 'finish', true);
assertLastStatus(players[1], 'finish', true);
assertLastStatus(players[2], 'finish', true);
expect(completed).toBeTruthy();
});
it('should not call destroy automatically when finished even if a parent player is present',
() => {
const sequence = new AnimationSequencePlayer(players);
const parent = new AnimationSequencePlayer([sequence, new MockAnimationPlayer()]);
sequence.play();
assertLastStatus(players[0], 'destroy', false);
assertLastStatus(players[1], 'destroy', false);
assertLastStatus(players[2], 'destroy', false);
sequence.finish();
assertLastStatus(players[0], 'destroy', false);
assertLastStatus(players[1], 'destroy', false);
assertLastStatus(players[2], 'destroy', false);
parent.finish();
assertLastStatus(players[0], 'destroy', false);
assertLastStatus(players[1], 'destroy', false);
assertLastStatus(players[2], 'destroy', false);
});
it('should function without any players', () => {
const sequence = new AnimationSequencePlayer([]);
sequence.onDone(() => {});
sequence.pause();
sequence.play();
sequence.finish();
sequence.restart();
sequence.destroy();
});
it('should run the onStart method when started but only once', () => {
const player = new AnimationSequencePlayer([]);
let calls = 0;
player.onStart(() => calls++);
expect(calls).toEqual(0);
player.play();
expect(calls).toEqual(1);
player.pause();
player.play();
expect(calls).toEqual(1);
});
it('should call onDone after the next microtask if no players are provided', fakeAsync(() => {
const sequence = new AnimationSequencePlayer([]);
let completed = false;
sequence.onDone(() => completed = true);
expect(completed).toEqual(false);
flushMicrotasks();
expect(completed).toEqual(true);
}));
it('should not allow the player to be destroyed if it already has been destroyed unless reset',
fakeAsync(() => {
const p1 = new MockAnimationPlayer();
const p2 = new MockAnimationPlayer();
const innerPlayers = [p1, p2];
const sequencePlayer = new AnimationSequencePlayer(innerPlayers);
expect(p1.log[p1.log.length - 1]).not.toContain('destroy');
expect(p2.log[p2.log.length - 1]).not.toContain('destroy');
sequencePlayer.destroy();
expect(p1.log[p1.log.length - 1]).toContain('destroy');
expect(p2.log[p2.log.length - 1]).toContain('destroy');
p1.log = p2.log = [];
sequencePlayer.destroy();
expect(p1.log[p1.log.length - 1]).not.toContain('destroy');
expect(p2.log[p2.log.length - 1]).not.toContain('destroy');
sequencePlayer.reset();
sequencePlayer.destroy();
expect(p1.log[p1.log.length - 1]).toContain('destroy');
expect(p2.log[p2.log.length - 1]).toContain('destroy');
}));
});
}

View File

@ -1,148 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {FILL_STYLE_FLAG} from '../../src/animation/animation_constants';
import {AnimationKeyframe} from '../../src/animation/animation_keyframe';
import * as animationUtils from '../../src/animation/animation_style_util';
import {AnimationStyles} from '../../src/animation/animation_styles';
import {AUTO_STYLE} from '../../src/animation/metadata';
import {describe, expect, it} from '../../testing/testing_internal';
export function main() {
describe('Animation Style Utils', function() {
describe('prepareFinalAnimationStyles', () => {
it('should set all non-shared styles to the provided null value between the two sets of styles',
() => {
const styles = {opacity: 0, color: 'red'};
const newStyles = {background: 'red'};
const flag = '*';
const result = animationUtils.prepareFinalAnimationStyles(styles, newStyles, flag);
expect(result).toEqual({opacity: flag, color: flag, background: 'red'});
});
it('should handle an empty set of styles', () => {
const value = '*';
expect(animationUtils.prepareFinalAnimationStyles({}, {opacity: '0'}, value)).toEqual({
opacity: '0'
});
expect(animationUtils.prepareFinalAnimationStyles({opacity: '0'}, {}, value)).toEqual({
opacity: value
});
});
it('should set all AUTO styles to the null value', () => {
const styles = {opacity: 0};
const newStyles = {color: '*', border: '*'};
const flag = '*';
const result = animationUtils.prepareFinalAnimationStyles(styles, newStyles, null);
expect(result).toEqual({opacity: null, color: null, border: null});
});
});
describe('balanceAnimationKeyframes', () => {
it('should balance both the starting and final keyframes with thep provided styles', () => {
const collectedStyles = {width: 100, height: 200};
const finalStyles = {background: 'red', border: '1px solid black'};
const keyframes = [
new AnimationKeyframe(0, new AnimationStyles([{height: 100, opacity: 1}])),
new AnimationKeyframe(
1, new AnimationStyles([{background: 'blue', left: '100px', top: '100px'}]))
];
const result =
animationUtils.balanceAnimationKeyframes(collectedStyles, finalStyles, keyframes);
expect(animationUtils.flattenStyles(result[0].styles.styles)).toEqual({
'width': 100,
'height': 100,
'opacity': 1,
'background': '*',
'border': '*',
'left': '*',
'top': '*'
});
expect(animationUtils.flattenStyles(result[1].styles.styles)).toEqual({
'width': '*',
'height': '*',
'opacity': '*',
'background': 'blue',
'border': '1px solid black',
'left': '100px',
'top': '100px'
});
});
it('should perform balancing when no collected and final styles are provided', () => {
const keyframes = [
new AnimationKeyframe(0, new AnimationStyles([{height: 100, opacity: 1}])),
new AnimationKeyframe(1, new AnimationStyles([{width: 100}]))
];
const result = animationUtils.balanceAnimationKeyframes({}, {}, keyframes);
expect(animationUtils.flattenStyles(result[0].styles.styles))
.toEqual({'height': 100, 'opacity': 1, 'width': '*'});
expect(animationUtils.flattenStyles(result[1].styles.styles))
.toEqual({'width': 100, 'height': '*', 'opacity': '*'});
});
});
describe('clearStyles', () => {
it('should set all the style values to "null"', () => {
const styles: {[key: string]:
string | number} = {'opacity': 0, 'width': 100, 'color': 'red'};
const expectedResult: {[key: string]: string |
number} = {'opacity': null, 'width': null, 'color': null};
expect(animationUtils.clearStyles(styles)).toEqual(expectedResult);
});
it('should handle an empty set of styles',
() => { expect(animationUtils.clearStyles({})).toEqual({}); });
});
describe('collectAndResolveStyles', () => {
it('should keep a record of the styles as they are called', () => {
const styles1 = [{'opacity': 0, 'width': 100}];
const styles2 = [{'height': 999, 'opacity': 1}];
const collection: {[key: string]: string | number} = {};
expect(animationUtils.collectAndResolveStyles(collection, styles1)).toEqual(styles1);
expect(collection).toEqual({'opacity': 0, 'width': 100});
expect(animationUtils.collectAndResolveStyles(collection, styles2)).toEqual(styles2);
expect(collection).toEqual({'opacity': 1, 'width': 100, 'height': 999});
});
it('should resolve styles if they contain a FILL_STYLE_FLAG value', () => {
const styles1 = [{'opacity': 0, 'width': FILL_STYLE_FLAG}];
const styles2 = [{'height': 999, 'opacity': FILL_STYLE_FLAG}];
const collection = {};
expect(animationUtils.collectAndResolveStyles(collection, styles1)).toEqual([
{'opacity': 0, 'width': AUTO_STYLE}
]);
expect(animationUtils.collectAndResolveStyles(collection, styles2)).toEqual([
{'opacity': 0, 'height': 999}
]);
});
});
});
}

View File

@ -6,9 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ERROR_DEBUG_CONTEXT} from '@angular/core/src/errors';
import {DebugContext} from '@angular/core/src/linker/debug_context';
import {viewWrappedError} from '@angular/core/src/linker/errors';
import {ERROR_DEBUG_CONTEXT, ERROR_TYPE} from '@angular/core/src/errors';
import {ErrorHandler, wrappedError} from '../src/error_handler';
@ -99,3 +97,10 @@ Context`);
});
});
}
function viewWrappedError(originalError: any, context: any): Error {
const error = wrappedError(`Error in ${context.source}`, originalError);
(error as any)[ERROR_DEBUG_CONTEXT] = context;
(error as any)[ERROR_TYPE] = viewWrappedError;
return error;
}

View File

@ -1,62 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {el} from '@angular/platform-browser/testing/browser_util';
import {NoOpAnimationPlayer} from '../../src/animation/animation_player';
import {AnimationQueue} from '../../src/animation/animation_queue';
import {AnimationViewContext} from '../../src/linker/animation_view_context';
import {TestBed, fakeAsync, flushMicrotasks} from '../../testing';
import {describe, expect, iit, it} from '../../testing/testing_internal';
export function main() {
describe('AnimationViewContext', function() {
let elm: any;
beforeEach(() => { elm = el('<div></div>'); });
function getPlayers(vc: any) { return vc.getAnimationPlayers(elm); }
it('should remove the player from the registry once the animation is complete',
fakeAsync(() => {
const player = new NoOpAnimationPlayer();
const animationQueue = TestBed.get(AnimationQueue) as AnimationQueue;
const vc = new AnimationViewContext(animationQueue);
expect(getPlayers(vc).length).toEqual(0);
vc.queueAnimation(elm, 'someAnimation', player);
expect(getPlayers(vc).length).toEqual(1);
player.finish();
expect(getPlayers(vc).length).toEqual(0);
}));
it('should not remove a follow-up player from the registry if another player is queued',
fakeAsync(() => {
const player1 = new NoOpAnimationPlayer();
const player2 = new NoOpAnimationPlayer();
const animationQueue = TestBed.get(AnimationQueue) as AnimationQueue;
const vc = new AnimationViewContext(animationQueue);
vc.queueAnimation(elm, 'someAnimation', player1);
expect(getPlayers(vc).length).toBe(1);
expect(getPlayers(vc)[0]).toBe(player1);
vc.queueAnimation(elm, 'someAnimation', player2);
expect(getPlayers(vc).length).toBe(1);
expect(getPlayers(vc)[0]).toBe(player2);
player1.finish();
expect(getPlayers(vc).length).toBe(1);
expect(getPlayers(vc)[0]).toBe(player2);
player2.finish();
expect(getPlayers(vc).length).toBe(0);
}));
});
}

View File

@ -6,37 +6,17 @@
* found in the LICENSE file at https://angular.io/license
*/
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
import {ElementSchemaRegistry} from '@angular/compiler/src/schema/element_schema_registry';
import {TEST_COMPILER_PROVIDERS} from '@angular/compiler/testing/test_bindings';
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, DebugElement, Directive, DoCheck, Inject, Injectable, Input, OnChanges, OnDestroy, OnInit, Output, Pipe, PipeTransform, RenderComponentType, Renderer, RendererFactoryV2, RootRenderer, SimpleChange, SimpleChanges, TemplateRef, Type, ViewChild, ViewContainerRef, WrappedValue} from '@angular/core';
import {DebugDomRenderer} from '@angular/core/src/debug/debug_renderer';
import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing';
import {By} from '@angular/platform-browser/src/dom/debug/by';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {DomRootRenderer} from '@angular/platform-browser/src/dom/dom_renderer';
import {MockSchemaRegistry} from '../../../compiler/testing/index';
import {EventEmitter} from '../../src/facade/async';
export function main() {
describe('Current compiler', () => { createTests({viewEngine: false}); });
describe('View Engine compiler', () => {
beforeEach(() => {
TestBed.configureCompiler({
useJit: true,
providers: [
{provide: USE_VIEW_ENGINE, useValue: true},
]
});
});
createTests({viewEngine: true});
});
}
function createTests({viewEngine}: {viewEngine: boolean}) {
let elSchema: MockSchemaRegistry;
let renderLog: RenderLog;
let directiveLog: DirectiveLog;
@ -123,7 +103,6 @@ function createTests({viewEngine}: {viewEngine: boolean}) {
providers: [
RenderLog,
DirectiveLog,
{provide: RootRenderer, useClass: LoggingRootRenderer},
],
});
});
@ -1286,26 +1265,6 @@ class RenderLog {
}
}
@Injectable()
class LoggingRootRenderer implements RootRenderer {
constructor(private _delegate: DomRootRenderer, private _log: RenderLog) {}
renderComponent(componentProto: RenderComponentType): Renderer {
return new LoggingRenderer(this._delegate.renderComponent(componentProto), this._log);
}
}
class LoggingRenderer extends DebugDomRenderer {
constructor(delegate: Renderer, private _log: RenderLog) { super(delegate); }
setElementProperty(renderElement: any, propertyName: string, propertyValue: any) {
this._log.setElementProperty(renderElement, propertyName, propertyValue);
super.setElementProperty(renderElement, propertyName, propertyValue);
}
setText(renderNode: any, value: string) { this._log.setText(renderNode, value); }
}
class DirectiveLogEntry {
constructor(public directiveName: string, public method: string) {}
}

View File

@ -1,185 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {Component, ContentChild, Injectable, Input, RenderComponentType, Renderer, RootRenderer, TemplateRef} from '@angular/core';
import {DebugDomRenderer} from '@angular/core/src/debug/debug_renderer';
import {DirectRenderer} from '@angular/core/src/render/api';
import {TestBed, inject} from '@angular/core/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {DIRECT_DOM_RENDERER, DomRootRenderer} from '@angular/platform-browser/src/dom/dom_renderer';
import {expect} from '@angular/platform-browser/testing/matchers';
let directRenderer: any;
let destroyViewLogs: any[];
export function main() {
// Don't run on server...
if (!getDOM().supportsDOMEvents()) return;
// TODO(tbosch): delete the tests here as they use the old renderer.
xdescribe('direct dom integration tests', function() {
beforeEach(() => {
directRenderer = DIRECT_DOM_RENDERER;
destroyViewLogs = [];
spyOn(directRenderer, 'remove').and.callThrough();
spyOn(directRenderer, 'appendChild').and.callThrough();
spyOn(directRenderer, 'insertBefore').and.callThrough();
TestBed.configureTestingModule(
{providers: [{provide: RootRenderer, useClass: DirectRootRenderer}]});
});
it('should attach views as last nodes in a parent', () => {
@Component({template: '<div *ngIf="true">hello</div>'})
class MyComp {
}
TestBed.configureTestingModule({declarations: [MyComp]});
const fixture = TestBed.createComponent(MyComp);
directRenderer.insertBefore.calls.reset();
directRenderer.appendChild.calls.reset();
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('hello');
expect(directRenderer.insertBefore).not.toHaveBeenCalled();
expect(directRenderer.appendChild).toHaveBeenCalled();
});
it('should attach views as non last nodes in a parent', () => {
@Component({template: '<div *ngIf="true">hello</div>after'})
class MyComp {
}
TestBed.configureTestingModule({declarations: [MyComp]});
const fixture = TestBed.createComponent(MyComp);
directRenderer.insertBefore.calls.reset();
directRenderer.appendChild.calls.reset();
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('helloafter');
expect(directRenderer.insertBefore).toHaveBeenCalled();
expect(directRenderer.appendChild).not.toHaveBeenCalled();
});
it('should detach views', () => {
@Component({template: '<div *ngIf="shown">hello</div>'})
class MyComp {
shown = true;
}
TestBed.configureTestingModule({declarations: [MyComp]});
const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges();
directRenderer.remove.calls.reset();
fixture.componentInstance.shown = false;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('');
expect(directRenderer.remove).toHaveBeenCalled();
});
it('should pass null as all nodes to destroyView', () => {
@Component({template: '<div *ngIf="shown">hello</div>'})
class MyComp {
shown = true;
}
TestBed.configureTestingModule({declarations: [MyComp]});
const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges();
destroyViewLogs.length = 0;
fixture.componentInstance.shown = false;
fixture.detectChanges();
expect(destroyViewLogs).toEqual([[null, null]]);
});
it('should project nodes', () => {
@Component({template: '<child>hello</child>'})
class Parent {
}
@Component({selector: 'child', template: '(<ng-content></ng-content>)'})
class Child {
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
const fixture = TestBed.createComponent(Parent);
expect(fixture.nativeElement).toHaveText('(hello)');
const childHostEl = fixture.nativeElement.children[0];
const projectedNode = childHostEl.childNodes[1];
expect(directRenderer.appendChild).toHaveBeenCalledWith(projectedNode, childHostEl);
});
it('should support using structural directives with ngTemplateOutlet', () => {
@Component({
template:
'<child [templateCtx]="templateCtx"><ng-template let-shown="shown" #tpl><span *ngIf="shown">hello</span></ng-template></child>'
})
class Parent {
templateCtx = {shown: false};
}
@Component({
selector: 'child',
template:
'(<ng-container [ngTemplateOutlet]="templateRef" [ngOutletContext]="templateCtx"></ng-container>)'
})
class Child {
@Input()
templateCtx: any;
@ContentChild('tpl')
templateRef: TemplateRef<any>;
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
let fixture = TestBed.createComponent(Parent);
fixture.componentInstance.templateCtx.shown = false;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('()');
fixture.destroy();
fixture = TestBed.createComponent(Parent);
fixture.componentInstance.templateCtx.shown = true;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('(hello)');
fixture.componentInstance.templateCtx.shown = false;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('()');
});
});
}
@Injectable()
class DirectRootRenderer implements RootRenderer {
constructor(private _delegate: DomRootRenderer) {}
renderComponent(componentType: RenderComponentType): Renderer {
const renderer = new DebugDomRenderer(this._delegate.renderComponent(componentType));
(renderer as any).directRenderer = directRenderer;
const originalDestroyView = renderer.destroyView;
renderer.destroyView = function(...args: any[]) {
destroyViewLogs.push(args);
return originalDestroyView.apply(this, args);
};
return renderer;
}
}

View File

@ -6,7 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
import {ANALYZE_FOR_ENTRY_COMPONENTS, Component, ComponentFactoryResolver} from '@angular/core';
import {noComponentFactoryError} from '@angular/core/src/linker/component_factory_resolver';
import {TestBed} from '@angular/core/testing';
@ -15,19 +14,6 @@ import {Console} from '../../src/console';
export function main() {
describe('Current compiler', () => { createTests({viewEngine: false}); });
describe('View Engine compiler', () => {
beforeEach(() => {
TestBed.configureCompiler(
{useJit: true, providers: [{provide: USE_VIEW_ENGINE, useValue: true}]});
});
createTests({viewEngine: true});
});
}
function createTests({viewEngine}: {viewEngine: boolean}) {
describe('jit', () => { declareTests({useJit: true}); });
describe('no jit', () => { declareTests({useJit: false}); });
}

View File

@ -7,14 +7,13 @@
*/
import {CommonModule} from '@angular/common';
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
import {ComponentFactory, Host, Inject, Injectable, InjectionToken, Injector, NO_ERRORS_SCHEMA, NgModule, OnDestroy, ReflectiveInjector, SkipSelf} from '@angular/core';
import {ChangeDetectionStrategy, ChangeDetectorRef, PipeTransform} from '@angular/core/src/change_detection/change_detection';
import {getDebugContext} from '@angular/core/src/errors';
import {ComponentFactoryResolver} from '@angular/core/src/linker/component_factory_resolver';
import {ElementRef} from '@angular/core/src/linker/element_ref';
import {QueryList} from '@angular/core/src/linker/query_list';
import {TemplateRef, TemplateRef_} from '@angular/core/src/linker/template_ref';
import {TemplateRef} from '@angular/core/src/linker/template_ref';
import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref';
import {EmbeddedViewRef} from '@angular/core/src/linker/view_ref';
import {Attribute, Component, ContentChildren, Directive, HostBinding, HostListener, Input, Output, Pipe} from '@angular/core/src/metadata';
@ -30,27 +29,13 @@ import {stringify} from '../../src/facade/lang';
const ANCHOR_ELEMENT = new InjectionToken('AnchorElement');
export function main() {
describe('jit', () => { declareTests({useJit: true, viewEngine: false}); });
describe('jit', () => { declareTests({useJit: true}); });
describe('no jit', () => { declareTests({useJit: false, viewEngine: false}); });
describe('view engine', () => {
beforeEach(() => {
TestBed.configureCompiler({
useJit: true,
providers: [{
provide: USE_VIEW_ENGINE,
useValue: true,
}],
});
});
declareTests({useJit: true, viewEngine: true});
});
describe('no jit', () => { declareTests({useJit: false}); });
}
function declareTests({useJit, viewEngine}: {useJit: boolean, viewEngine: boolean}) {
function declareTests({useJit}: {useJit: boolean}) {
describe('integration tests', function() {
beforeEach(() => { TestBed.configureCompiler({useJit}); });
@ -1290,7 +1275,7 @@ function declareTests({useJit, viewEngine}: {useJit: boolean, viewEngine: boolea
});
});
viewEngine || describe('error handling', () => {
describe('error handling', () => {
it('should report a meaningful error when a directive is missing annotation', () => {
TestBed.configureTestingModule({declarations: [MyComp, SomeDirectiveMissingAnnotation]});

View File

@ -6,7 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
import {Component, Directive, ElementRef, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {By} from '@angular/platform-browser/src/dom/debug/by';
@ -14,19 +13,6 @@ import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {expect} from '@angular/platform-browser/testing/matchers';
export function main() {
describe('Current compiler', () => { createTests({viewEngine: false}); });
describe('View Engine compiler', () => {
beforeEach(() => {
TestBed.configureCompiler(
{useJit: true, providers: [{provide: USE_VIEW_ENGINE, useValue: true}]});
});
createTests({viewEngine: true});
});
}
function createTests({viewEngine}: {viewEngine: boolean}) {
describe('projection', () => {
beforeEach(() => TestBed.configureTestingModule({declarations: [MainComp, OtherComp, Simple]}));

View File

@ -6,7 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, ContentChild, ContentChildren, Directive, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef, asNativeElements} from '@angular/core';
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/matchers';
@ -14,19 +13,6 @@ import {expect} from '@angular/platform-browser/testing/matchers';
import {stringify} from '../../src/facade/lang';
export function main() {
describe('Current compiler', () => { createTests({viewEngine: false}); });
describe('View Engine compiler', () => {
beforeEach(() => {
TestBed.configureCompiler(
{useJit: true, providers: [{provide: USE_VIEW_ENGINE, useValue: true}]});
});
createTests({viewEngine: true});
});
}
function createTests({viewEngine}: {viewEngine: boolean}) {
describe('Query API', () => {
beforeEach(() => TestBed.configureTestingModule({

View File

@ -6,7 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
import {Attribute, ChangeDetectionStrategy, ChangeDetectorRef, Component, DebugElement, Directive, ElementRef, Host, Inject, InjectionToken, Input, Optional, Pipe, PipeTransform, Provider, Self, SkipSelf, TemplateRef, Type, ViewContainerRef} from '@angular/core';
import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
@ -184,19 +183,6 @@ class TestComp {
}
export function main() {
describe('Current compiler', () => { createTests({viewEngine: false}); });
describe('View Engine compiler', () => {
beforeEach(() => {
TestBed.configureCompiler(
{useJit: true, providers: [{provide: USE_VIEW_ENGINE, useValue: true}]});
});
createTests({viewEngine: true});
});
}
function createTests({viewEngine}: {viewEngine: boolean}) {
function createComponentFixture<T>(
template: string, providers: Provider[] = null, comp: Type<T> = null): ComponentFixture<T> {
if (!comp) {

View File

@ -1,115 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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} from '@angular/core';
export class MockAnimationPlayer implements AnimationPlayer {
private _onDoneFns: Function[] = [];
private _onStartFns: Function[] = [];
private _onDestroyFns: Function[] = [];
private _finished = false;
private _destroyed = false;
private _started = false;
public parentPlayer: AnimationPlayer = null;
public previousStyles: {[styleName: string]: string | number} = {};
public log: any[] = [];
constructor(
public startingStyles: {[key: string]: string | number} = {},
public keyframes: Array<[number, {[style: string]: string | number}]> = [],
previousPlayers: AnimationPlayer[] = []) {
previousPlayers.forEach(player => {
if (player instanceof MockAnimationPlayer) {
const styles = player._captureStyles();
Object.keys(styles).forEach(prop => this.previousStyles[prop] = styles[prop]);
}
});
}
private _onFinish(): void {
if (!this._finished) {
this._finished = true;
this.log.push('finish');
this._onDoneFns.forEach(fn => fn());
this._onDoneFns = [];
}
}
init(): void { this.log.push('init'); }
onDone(fn: () => void): void { this._onDoneFns.push(fn); }
onStart(fn: () => void): void { this._onStartFns.push(fn); }
onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); }
hasStarted() { return this._started; }
play(): void {
if (!this.hasStarted()) {
this._onStartFns.forEach(fn => fn());
this._onStartFns = [];
this._started = true;
}
this.log.push('play');
}
pause(): void { this.log.push('pause'); }
restart(): void { this.log.push('restart'); }
finish(): void { this._onFinish(); }
reset(): void {
this.log.push('reset');
this._destroyed = false;
this._finished = false;
this._started = false;
}
destroy(): void {
if (!this._destroyed) {
this._destroyed = true;
this.finish();
this.log.push('destroy');
this._onDestroyFns.forEach(fn => fn());
this._onDestroyFns = [];
}
}
setPosition(p: number): void {}
getPosition(): number { return 0; }
private _captureStyles(): {[styleName: string]: string | number} {
const captures: {[prop: string]: string | number} = {};
if (this.hasStarted()) {
// when assembling the captured styles, it's important that
// we build the keyframe styles in the following order:
// {startingStyles, ... other styles within keyframes, ... previousStyles }
Object.keys(this.startingStyles).forEach(prop => {
captures[prop] = this.startingStyles[prop];
});
this.keyframes.forEach(kf => {
const [offset, styles] = kf;
const newStyles: {[prop: string]: string | number} = {};
Object.keys(styles).forEach(
prop => { captures[prop] = this._finished ? styles[prop] : AUTO_STYLE; });
});
}
Object.keys(this.previousStyles).forEach(prop => {
captures[prop] = this.previousStyles[prop];
});
return captures;
}
}

View File

@ -6,5 +6,4 @@
* found in the LICENSE file at https://angular.io/license
*/
export {MockAnimationPlayer as ɵMockAnimationPlayer} from './mock_animation_player';
export {TestingCompiler as ɵTestingCompiler, TestingCompilerFactory as ɵTestingCompilerFactory} from './test_compiler';

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