Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
6b79ab5abe | |||
53c12a84dc | |||
ca665303f4 | |||
0fe4985756 | |||
74087cb39d | |||
902bb2f026 | |||
23bf34853c | |||
8c4b963927 | |||
bfa4f70204 | |||
d481f6d150 | |||
fd6114561b | |||
c82851172e | |||
75478b2078 | |||
cdbb3dbd2a | |||
e72124c888 | |||
b8c0a97e35 | |||
5597fd3180 | |||
a88413f871 | |||
aa116524e6 | |||
4a5ad7ba30 | |||
d74e4d0633 | |||
a2c2b87aa3 | |||
8f4ea3e4b8 | |||
bf25e94f19 | |||
7983414e6a | |||
8248eba3e2 | |||
a65487528f | |||
426b3a19b7 | |||
2360676a7b | |||
ce3e03ff1a | |||
858c11cf7b | |||
95afaf495b | |||
d92930e975 | |||
c2892dada3 | |||
b2b1195534 | |||
e1b09e3bcc | |||
c65b75443e | |||
db0dca3fc1 |
@ -176,7 +176,8 @@ groups:
|
||||
- "packages/language-service/*"
|
||||
users:
|
||||
- chuckjaz #primary
|
||||
# needs secondary
|
||||
- tbosch #secondary
|
||||
- vicb
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
|
||||
|
30
CHANGELOG.md
30
CHANGELOG.md
@ -1,5 +1,33 @@
|
||||
<a name="4.0.1"></a>
|
||||
## [4.0.1](https://github.com/angular/angular/compare/4.0.0...4.0.1) (2017-03-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **animations:** make sure style calculations are not computed too early ([#15540](https://github.com/angular/angular/issues/15540)) ([c828511](https://github.com/angular/angular/commit/c828511)), closes [#15507](https://github.com/angular/angular/issues/15507)
|
||||
* **compiler:** allow single quotes into named interpolations ([#15461](https://github.com/angular/angular/issues/15461)) ([a654875](https://github.com/angular/angular/commit/a654875)), closes [#15318](https://github.com/angular/angular/issues/15318)
|
||||
* **compiler:** ignore errors when evaluating base classes ([#15560](https://github.com/angular/angular/issues/15560)) ([a88413f](https://github.com/angular/angular/commit/a88413f)), closes [#15536](https://github.com/angular/angular/issues/15536)
|
||||
* **compiler:** throw when a component defines both template and templateUrl ([#15572](https://github.com/angular/angular/issues/15572)) ([902bb2f](https://github.com/angular/angular/commit/902bb2f)), closes [#15566](https://github.com/angular/angular/issues/15566)
|
||||
* **core:** check for undefined on normalizeDebugBindingValue ([#15503](https://github.com/angular/angular/issues/15503)) ([b8c0a97](https://github.com/angular/angular/commit/b8c0a97)), closes [#15494](https://github.com/angular/angular/issues/15494)
|
||||
* **core:** fix inheritance in JIT mode for TS 2.1 ([#15599](https://github.com/angular/angular/issues/15599)) ([ca66530](https://github.com/angular/angular/commit/ca66530)), closes [#15502](https://github.com/angular/angular/issues/15502)
|
||||
* **core:** fix the key/value differ ([#15539](https://github.com/angular/angular/issues/15539)) ([e72124c](https://github.com/angular/angular/commit/e72124c)), closes [#15457](https://github.com/angular/angular/issues/15457)
|
||||
* **core:** improve error msg for invalid KeyValueDiffer.diff arg ([#15489](https://github.com/angular/angular/issues/15489)) ([d74e4d0](https://github.com/angular/angular/commit/d74e4d0)), closes [#15402](https://github.com/angular/angular/issues/15402)
|
||||
* **core:** Update types for TypeScript nullability support ([#15472](https://github.com/angular/angular/issues/15472)) ([8c4b963](https://github.com/angular/angular/commit/8c4b963))
|
||||
* **language-service:** be resilient to invalidate ordering ([#15470](https://github.com/angular/angular/issues/15470)) ([a2c2b87](https://github.com/angular/angular/commit/a2c2b87)), closes [#15466](https://github.com/angular/angular/issues/15466)
|
||||
* **language-service:** correctly determine base members of types ([#15600](https://github.com/angular/angular/issues/15600)) ([0fe4985](https://github.com/angular/angular/commit/0fe4985)), closes [#15460](https://github.com/angular/angular/issues/15460)
|
||||
* **language-service:** don't require `reflect-metadata` module to be provided ([#15569](https://github.com/angular/angular/issues/15569)) ([bfa4f70](https://github.com/angular/angular/commit/bfa4f70)), closes [#15568](https://github.com/angular/angular/issues/15568)
|
||||
* **language-service:** guard access to `Symbol.members` ([#15529](https://github.com/angular/angular/issues/15529)) ([bf25e94](https://github.com/angular/angular/commit/bf25e94)), closes [#15528](https://github.com/angular/angular/issues/15528)
|
||||
* **language-service:** improve performance of `updateModuleAnalysis()` ([#15543](https://github.com/angular/angular/issues/15543)) ([5597fd3](https://github.com/angular/angular/commit/5597fd3))
|
||||
* **router:** should run CanActivate after CanDeactivate guards ([75478b2](https://github.com/angular/angular/commit/75478b2)), closes [#14059](https://github.com/angular/angular/issues/14059) [#15467](https://github.com/angular/angular/issues/15467)
|
||||
* **router:** shouldn't execute CanLoad when a route has been loaded ([2360676](https://github.com/angular/angular/commit/2360676)), closes [#14475](https://github.com/angular/angular/issues/14475) [#15438](https://github.com/angular/angular/issues/15438)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **router:** don't create new serializer every time UrlTree.toString is called ([#15565](https://github.com/angular/angular/issues/15565)) ([fd61145](https://github.com/angular/angular/commit/fd61145))
|
||||
|
||||
<a name="4.0.0"></a>
|
||||
# [4.0.0](https://github.com/angular/angular/compare/4.0.0-rc.6...4.0.0) (2017-03-23)
|
||||
# [4.0.0](https://github.com/angular/angular/compare/4.0.0-rc.6...4.0.0) invisible-makeover (2017-03-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
@ -147,7 +147,7 @@ To ensure consistency throughout the source code, keep these rules in mind as yo
|
||||
* All public API methods **must be documented**. (Details TBC).
|
||||
* We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at
|
||||
**100 characters**. An automated formatter is available, see
|
||||
[DEVELOPER.md](DEVELOPER.md#clang-format).
|
||||
[DEVELOPER.md](docs/DEVELOPER.md#clang-format).
|
||||
|
||||
## <a name="commit"></a> Commit Message Guidelines
|
||||
|
||||
@ -263,7 +263,7 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
|
||||
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md
|
||||
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
|
||||
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
|
||||
[dev-doc]: https://github.com/angular/angular/blob/master/DEVELOPER.md
|
||||
[dev-doc]: https://github.com/angular/angular/blob/master/docs/DEVELOPER.md
|
||||
[github]: https://github.com/angular/angular
|
||||
[gitter]: https://gitter.im/angular/angular
|
||||
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
|
@ -32,7 +32,7 @@ We explicitly don't consider the following to be our public API surface:
|
||||
|
||||
- any file/import paths within our package except for the `/`, `/testing` and `/bundles/*`
|
||||
- constructors of injectable classes (services and directives) - please use DI to obtain instances of these classes
|
||||
- any class members or symbols marked as `private` or prefixed with underscore
|
||||
- any class members or symbols marked as `private`, or prefixed with underscore (`_`) and [barred latin o](https://en.wikipedia.org/wiki/%C6%9F) (`ɵ`)
|
||||
- extending any of our classes unless the support for this is specifically documented in the API docs
|
||||
- the contents and API surface of the code generated by Angular's compiler (with one notable exception: the existence and name of `NgModuleFactory` instances exported from generated code is guaranteed)
|
||||
|
||||
|
@ -26,9 +26,9 @@ Thanks for reporting this issue. However this issue is a duplicate of an existin
|
||||
```
|
||||
|
||||
|
||||
## Angular: Insufficient Information Provided (v2)
|
||||
## Angular: Insufficient Information Provided (v1)
|
||||
```
|
||||
Thanks for reporting this issue. However, you didn't provide sufficient information for us to understand and reproduce the problem. Please check out [our submission guidelines](https://github.com/angular/angular/blob/master/docs/CONTRIBUTING.md#-submitting-an-issue) to understand why we can't act on issues that are lacking important information.
|
||||
Thanks for reporting this issue. However, you didn't provide sufficient information for us to understand and reproduce the problem. Please check out [our submission guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-submitting-an-issue) to understand why we can't act on issues that are lacking important information.
|
||||
|
||||
If the problem still persists, please file a new issue and ensure you provide all of the required information when filling out the issue template.
|
||||
```
|
||||
@ -39,11 +39,11 @@ I'm sorry but this issue is not caused by Angular. Please contact the author(s)
|
||||
```
|
||||
|
||||
|
||||
## Angular: Non-reproducible (v2)
|
||||
## Angular: Non-reproducible (v1)
|
||||
```
|
||||
I'm sorry but we can't reproduce the problem following the instructions you provided.
|
||||
|
||||
If the problem still exists please open a new issue following [our submission guidelines](https://github.com/angular/angular/blob/master/docs/CONTRIBUTING.md#-submitting-an-issue).
|
||||
If the problem still exists please open a new issue following [our submission guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-submitting-an-issue).
|
||||
```
|
||||
|
||||
## Angular: Obsolete (v1)
|
||||
@ -54,9 +54,9 @@ If the problem still persists, please file a new issue and ensure you provide th
|
||||
```
|
||||
|
||||
|
||||
## Angular: Support Request (v2)
|
||||
## Angular: Support Request (v1)
|
||||
```
|
||||
Hello, we reviewed this issue and determined that it doesn't fall into the bug report or feature request category. This issue tracker is not suitable for support requests, please repost your issue on [StackOverflow](http://stackoverflow.com/) using tag `angular`.
|
||||
|
||||
If you are wondering why we don't resolve support issues via the issue tracker, please [check out this explanation](https://github.com/angular/angular/blob/master/docs/CONTRIBUTING.md#-got-a-question-or-problem).
|
||||
If you are wondering why we don't resolve support issues via the issue tracker, please [check out this explanation](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-got-a-question-or-problem).
|
||||
```
|
||||
|
@ -40,7 +40,7 @@ export function init(moduleRef: NgModuleRef<AppModule>) {
|
||||
|
||||
const injector = moduleRef.injector;
|
||||
appRef = injector.get(ApplicationRef);
|
||||
const numberOfChecksEl = document.getElementById('numberOfChecks');
|
||||
const numberOfChecksEl = document.getElementById('numberOfChecks') !;
|
||||
|
||||
tree = appRef.components[0].instance;
|
||||
|
||||
|
@ -13,10 +13,10 @@ export class TreeNode {
|
||||
children: TreeNode[];
|
||||
|
||||
constructor(
|
||||
public value: string, public depth: number, public maxDepth: number, public left: TreeNode,
|
||||
public right: TreeNode) {
|
||||
public value: string, public depth: number, public maxDepth: number,
|
||||
public left: TreeNode|null, public right: TreeNode|null) {
|
||||
this.transitiveChildCount = Math.pow(2, (this.maxDepth - this.depth + 1)) - 1;
|
||||
this.children = this.left ? [this.left, this.right] : [];
|
||||
this.children = this.left ? [this.left, this.right !] : [];
|
||||
}
|
||||
|
||||
// Needed for Polymer as it does not support ternary nor modulo operator
|
||||
|
@ -35,7 +35,7 @@ export function getStringParameter(name: string) {
|
||||
}
|
||||
|
||||
export function bindAction(selector: string, callback: () => void) {
|
||||
document.querySelector(selector).addEventListener('click', callback);
|
||||
document.querySelector(selector) !.addEventListener('click', callback);
|
||||
}
|
||||
|
||||
|
||||
@ -60,7 +60,7 @@ export function profile(create: () => void, destroy: () => void, name: string) {
|
||||
function urlParamsToForm() {
|
||||
const regex = /(\w+)=(\w+)/g;
|
||||
const search = decodeURIComponent(location.search);
|
||||
let match: any[];
|
||||
let match: any[]|null;
|
||||
while (match = regex.exec(search)) {
|
||||
const name = match[1];
|
||||
const value = match[2];
|
||||
@ -75,4 +75,4 @@ function urlParamsToForm() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "angular-srcs",
|
||||
"version": "4.0.0",
|
||||
"version": "4.0.1",
|
||||
"private": true,
|
||||
"branchPattern": "2.0.*",
|
||||
"description": "Angular - a web framework for modern web apps",
|
||||
|
@ -13,3 +13,4 @@ export {NoopAnimationDriver as ɵNoopAnimationDriver} from './render/animation_d
|
||||
export {DomAnimationEngine as ɵDomAnimationEngine} from './render/dom_animation_engine';
|
||||
export {NoopAnimationEngine as ɵNoopAnimationEngine} from './render/noop_animation_engine';
|
||||
export {WebAnimationsDriver as ɵWebAnimationsDriver, supportsWebAnimations as ɵsupportsWebAnimations} from './render/web_animations/web_animations_driver';
|
||||
export {WebAnimationsPlayer as ɵWebAnimationsPlayer} from './render/web_animations/web_animations_player';
|
||||
|
@ -259,8 +259,6 @@ export class DomAnimationEngine {
|
||||
const player = this._buildPlayer(element, instruction, previousPlayers, i);
|
||||
player.onDestroy(
|
||||
() => { deleteFromArrayMap(this._activeElementAnimations, element, player); });
|
||||
player.init();
|
||||
|
||||
this._markPlayerAsActive(element, player);
|
||||
return player;
|
||||
});
|
||||
@ -354,6 +352,7 @@ export class DomAnimationEngine {
|
||||
// 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
|
||||
player.init();
|
||||
if (!player.hasStarted()) {
|
||||
player.play();
|
||||
}
|
||||
|
@ -87,6 +87,22 @@ export function main() {
|
||||
expect(engine.queuedPlayers.pop() instanceof NoopAnimationPlayer).toBe(true);
|
||||
});
|
||||
|
||||
it('should not initialize the animation until the engine has been flushed', () => {
|
||||
const engine = makeEngine();
|
||||
engine.registerTrigger(trigger(
|
||||
'trig', [transition('* => something', [animate(1000, style({color: 'gold'}))])]));
|
||||
|
||||
engine.setProperty(element, 'trig', 'something');
|
||||
const player = engine.queuedPlayers.pop() as MockAnimationPlayer;
|
||||
|
||||
let initialized = false;
|
||||
player.onInit(() => initialized = true);
|
||||
|
||||
expect(initialized).toBe(false);
|
||||
engine.flush();
|
||||
expect(initialized).toBe(true);
|
||||
});
|
||||
|
||||
it('should not queue an animation if the property value has not changed at all', () => {
|
||||
const engine = makeEngine();
|
||||
|
||||
|
@ -31,6 +31,7 @@ export class MockAnimationDriver implements AnimationDriver {
|
||||
export class MockAnimationPlayer extends NoopAnimationPlayer {
|
||||
private __finished = false;
|
||||
public previousStyles: {[key: string]: string | number} = {};
|
||||
private _onInitFns: (() => any)[] = [];
|
||||
|
||||
constructor(
|
||||
public element: any, public keyframes: {[key: string]: string | number}[],
|
||||
@ -45,6 +46,16 @@ export class MockAnimationPlayer extends NoopAnimationPlayer {
|
||||
});
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
onInit(fn: () => any) { this._onInitFns.push(fn); }
|
||||
|
||||
/* @internal */
|
||||
init() {
|
||||
super.init();
|
||||
this._onInitFns.forEach(fn => fn());
|
||||
this._onInitFns = [];
|
||||
}
|
||||
|
||||
finish(): void {
|
||||
super.finish();
|
||||
this.__finished = true;
|
||||
|
@ -98,7 +98,7 @@ export interface AnimationStyleMetadata extends AnimationMetadata {
|
||||
*/
|
||||
export interface AnimationAnimateMetadata extends AnimationMetadata {
|
||||
timings: string|number|AnimateTimings;
|
||||
styles: AnimationStyleMetadata|AnimationKeyframesSequenceMetadata;
|
||||
styles: AnimationStyleMetadata|AnimationKeyframesSequenceMetadata|null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,10 +118,10 @@ export interface AnimationSequenceMetadata extends AnimationMetadata { steps: An
|
||||
export interface AnimationGroupMetadata extends AnimationMetadata { steps: AnimationMetadata[]; }
|
||||
|
||||
/**
|
||||
* `trigger` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* `trigger` is an animation-specific function that is designed to be used inside of Angular'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.
|
||||
how animations in Angular 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
|
||||
@ -173,10 +173,10 @@ export function trigger(name: string, definitions: AnimationMetadata[]): Animati
|
||||
}
|
||||
|
||||
/**
|
||||
* `animate` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* `animate` is an animation-specific function that is designed to be used inside of Angular'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.
|
||||
* how animations in Angular 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
|
||||
@ -218,16 +218,16 @@ export function trigger(name: string, definitions: AnimationMetadata[]): Animati
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export function animate(
|
||||
timings: string | number, styles: AnimationStyleMetadata | AnimationKeyframesSequenceMetadata =
|
||||
null): AnimationAnimateMetadata {
|
||||
timings: string | number, styles: AnimationStyleMetadata | AnimationKeyframesSequenceMetadata |
|
||||
null = null): AnimationAnimateMetadata {
|
||||
return {type: AnimationMetadataType.Animate, styles: styles, timings: timings};
|
||||
}
|
||||
|
||||
/**
|
||||
* `group` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* `group` is an animation-specific function that is designed to be used inside of Angular'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.
|
||||
* how animations in Angular 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.
|
||||
@ -259,10 +259,10 @@ export function group(steps: AnimationMetadata[]): AnimationGroupMetadata {
|
||||
}
|
||||
|
||||
/**
|
||||
* `sequence` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* `sequence` is an animation-specific function that is designed to be used inside of Angular'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.
|
||||
* how animations in Angular 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}.)
|
||||
@ -297,10 +297,10 @@ export function sequence(steps: AnimationMetadata[]): AnimationSequenceMetadata
|
||||
}
|
||||
|
||||
/**
|
||||
* `style` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* `style` is an animation-specific function that is designed to be used inside of Angular'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.
|
||||
* how animations in Angular 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
|
||||
@ -345,10 +345,10 @@ export function style(
|
||||
}
|
||||
|
||||
/**
|
||||
* `state` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* `state` is an animation-specific function that is designed to be used inside of Angular'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.
|
||||
* how animations in Angular 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
|
||||
@ -397,10 +397,10 @@ export function state(name: string, styles: AnimationStyleMetadata): AnimationSt
|
||||
}
|
||||
|
||||
/**
|
||||
* `keyframes` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* `keyframes` is an animation-specific function that is designed to be used inside of Angular'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.
|
||||
* how animations in Angular are used.
|
||||
*
|
||||
* `keyframes` specifies a collection of {@link style style} entries each optionally characterized
|
||||
* by an `offset` value.
|
||||
@ -446,10 +446,10 @@ export function keyframes(steps: AnimationStyleMetadata[]): AnimationKeyframesSe
|
||||
}
|
||||
|
||||
/**
|
||||
* `transition` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* `transition` is an animation-specific function that is designed to be used inside of Angular'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.
|
||||
* how animations in Angular 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 =>
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// Must be imported first, because angular2 decorators throws on load.
|
||||
// Must be imported first, because Angular decorators throw on load.
|
||||
import 'reflect-metadata';
|
||||
|
||||
export {InjectionToken, Injector, Provider, ReflectiveInjector} from '@angular/core';
|
||||
|
@ -72,7 +72,7 @@ export class NgLocaleLocalization extends NgLocalization {
|
||||
}
|
||||
|
||||
// This is generated code DO NOT MODIFY
|
||||
// see angular2/script/cldr/gen_plural_rules.js
|
||||
// see angular/script/cldr/gen_plural_rules.js
|
||||
|
||||
/** @experimental */
|
||||
export enum Plural {
|
||||
|
@ -30,7 +30,7 @@ function getSourcePositionForStack(stack: string): {source: string, line: number
|
||||
const htmlLocations = stack
|
||||
.split('\n')
|
||||
// e.g. at View_MyComp_0 (...html:153:40)
|
||||
.map(line => /\((.*\.html):(\d+):(\d+)/.exec(line))
|
||||
.map(line => /\((.*\.html):(\d+):(\d+)/.exec(line) !)
|
||||
.filter(match => !!match)
|
||||
.map(match => ({
|
||||
source: match[1],
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
/* tslint:disable:no-console */
|
||||
|
||||
// Must be imported first, because angular2 decorators throws on load.
|
||||
// Must be imported first, because Angular decorators throw on load.
|
||||
import 'reflect-metadata';
|
||||
|
||||
import * as path from 'path';
|
||||
@ -67,9 +67,9 @@ function codeGenTest() {
|
||||
angularCompilerOptions: config.ngOptions,
|
||||
|
||||
// i18n options.
|
||||
i18nFormat: null,
|
||||
i18nFile: null,
|
||||
locale: null,
|
||||
i18nFormat: undefined,
|
||||
i18nFile: undefined,
|
||||
locale: undefined,
|
||||
|
||||
readResource: (fileName: string) => {
|
||||
readResources.push(fileName);
|
||||
@ -131,8 +131,8 @@ function i18nTest() {
|
||||
compilerOptions: config.parsed.options, program, host,
|
||||
angularCompilerOptions: config.ngOptions,
|
||||
i18nFormat: 'xlf',
|
||||
locale: null,
|
||||
outFile: null,
|
||||
locale: undefined,
|
||||
outFile: undefined,
|
||||
readResource: (fileName: string) => {
|
||||
readResources.push(fileName);
|
||||
return hostContext.readResource(fileName);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
/* tslint:disable:no-console */
|
||||
|
||||
// Must be imported first, because angular2 decorators throws on load.
|
||||
// Must be imported first, because Angular decorators throw on load.
|
||||
import 'reflect-metadata';
|
||||
|
||||
import * as path from 'path';
|
||||
@ -34,7 +34,8 @@ function main() {
|
||||
if (/.*\/node_modules\/.*/.test(fileName) && !/.*ngsummary\.json$/.test(fileName) &&
|
||||
!/package\.json$/.test(fileName)) {
|
||||
// Only allow to read summaries and package.json files from node_modules
|
||||
return null;
|
||||
// TODO (mhevery): Fix this. TypeScript.d.ts does not allow returning null.
|
||||
return null !;
|
||||
}
|
||||
readFiles.push(path.relative(basePath, fileName));
|
||||
return super.readFile(fileName);
|
||||
|
@ -13,7 +13,7 @@ import {platformServer} from '@angular/platform-server';
|
||||
import {MainModule} from '../src/module';
|
||||
import {MainModuleNgFactory} from '../src/module.ngfactory';
|
||||
|
||||
let mainModuleRef: NgModuleRef<MainModule> = null;
|
||||
let mainModuleRef: NgModuleRef<MainModule> = null !;
|
||||
beforeEach((done) => {
|
||||
platformServer().bootstrapModuleFactory(MainModuleNgFactory).then((moduleRef: any) => {
|
||||
mainModuleRef = moduleRef;
|
||||
@ -29,5 +29,5 @@ export function createComponent<C>(comp: {new (...args: any[]): C}): ComponentFi
|
||||
const moduleRef = createModule();
|
||||
const compRef =
|
||||
moduleRef.componentFactoryResolver.resolveComponentFactory(comp).create(moduleRef.injector);
|
||||
return new ComponentFixture(compRef, null, null);
|
||||
return new ComponentFixture(compRef, null, false);
|
||||
}
|
||||
|
@ -10,6 +10,8 @@
|
||||
"target": "es5",
|
||||
"experimentalDecorators": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "node",
|
||||
"rootDir": "",
|
||||
"declaration": true,
|
||||
@ -32,4 +34,4 @@
|
||||
"benchmarks/src/largetable/ng2/index_aot.ts",
|
||||
"benchmarks/src/largetable/ng2_switch/index_aot.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
"ng-xi18n": "./src/extract_i18n.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/tsc-wrapped": "4.0.0",
|
||||
"@angular/tsc-wrapped": "4.0.1",
|
||||
"reflect-metadata": "^0.1.2",
|
||||
"minimist": "^1.2.0"
|
||||
},
|
||||
|
@ -33,6 +33,7 @@ export class CompilerHost implements AotCompilerHost {
|
||||
private resolverCache = new Map<string, ModuleMetadata[]>();
|
||||
private bundleIndexCache = new Map<string, boolean>();
|
||||
private bundleIndexNames = new Set<string>();
|
||||
private moduleFileNames = new Map<string, string>();
|
||||
protected resolveModuleNameHost: CompilerHostContext;
|
||||
|
||||
constructor(
|
||||
@ -69,19 +70,25 @@ export class CompilerHost implements AotCompilerHost {
|
||||
getCanonicalFileName(fileName: string): string { return fileName; }
|
||||
|
||||
moduleNameToFileName(m: string, containingFile: string): string|null {
|
||||
if (!containingFile || !containingFile.length) {
|
||||
if (m.indexOf('.') === 0) {
|
||||
throw new Error('Resolution of relative paths requires a containing file.');
|
||||
const key = m + ':' + (containingFile || '');
|
||||
let result = this.moduleFileNames.get(key);
|
||||
if (!result) {
|
||||
if (!containingFile || !containingFile.length) {
|
||||
if (m.indexOf('.') === 0) {
|
||||
throw new Error('Resolution of relative paths requires a containing file.');
|
||||
}
|
||||
// Any containing file gives the same result for absolute imports
|
||||
containingFile = this.getCanonicalFileName(path.join(this.basePath, 'index.ts'));
|
||||
}
|
||||
// Any containing file gives the same result for absolute imports
|
||||
containingFile = this.getCanonicalFileName(path.join(this.basePath, 'index.ts'));
|
||||
m = m.replace(EXT, '');
|
||||
const resolved =
|
||||
ts.resolveModuleName(
|
||||
m, containingFile.replace(/\\/g, '/'), this.options, this.resolveModuleNameHost)
|
||||
.resolvedModule;
|
||||
result = resolved ? this.getCanonicalFileName(resolved.resolvedFileName) : null;
|
||||
this.moduleFileNames.set(key, result);
|
||||
}
|
||||
m = m.replace(EXT, '');
|
||||
const resolved =
|
||||
ts.resolveModuleName(
|
||||
m, containingFile.replace(/\\/g, '/'), this.options, this.resolveModuleNameHost)
|
||||
.resolvedModule;
|
||||
return resolved ? this.getCanonicalFileName(resolved.resolvedFileName) : null;
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -11,7 +11,7 @@
|
||||
/**
|
||||
* Extract i18n messages from source code
|
||||
*/
|
||||
// Must be imported first, because angular2 decorators throws on load.
|
||||
// Must be imported first, because Angular decorators throw on load.
|
||||
import 'reflect-metadata';
|
||||
|
||||
import * as tsc from '@angular/tsc-wrapped';
|
||||
|
@ -10,7 +10,7 @@
|
||||
/**
|
||||
* Extract i18n messages from source code
|
||||
*/
|
||||
// Must be imported first, because angular2 decorators throws on load.
|
||||
// Must be imported first, because Angular decorators throw on load.
|
||||
import 'reflect-metadata';
|
||||
|
||||
import * as compiler from '@angular/compiler';
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
|
||||
// Must be imported first, because angular2 decorators throws on load.
|
||||
// Must be imported first, because Angular decorators throw on load.
|
||||
import 'reflect-metadata';
|
||||
|
||||
import * as ts from 'typescript';
|
||||
|
@ -32,9 +32,9 @@ export interface NgTools_InternalApi_NG2_CodeGen_Options {
|
||||
angularCompilerOptions: AngularCompilerOptions;
|
||||
|
||||
// i18n options.
|
||||
i18nFormat: string;
|
||||
i18nFile: string;
|
||||
locale: string;
|
||||
i18nFormat?: string;
|
||||
i18nFile?: string;
|
||||
locale?: string;
|
||||
|
||||
readResource: (fileName: string) => Promise<string>;
|
||||
|
||||
@ -58,7 +58,7 @@ export interface NgTools_InternalApi_NG2_ExtractI18n_Options {
|
||||
program: ts.Program;
|
||||
host: ts.CompilerHost;
|
||||
angularCompilerOptions: AngularCompilerOptions;
|
||||
i18nFormat: string;
|
||||
i18nFormat?: string;
|
||||
readResource: (fileName: string) => Promise<string>;
|
||||
// Every new property under this line should be optional.
|
||||
locale?: string;
|
||||
|
@ -118,7 +118,7 @@ export class StaticReflector implements ɵReflectorReader {
|
||||
const classMetadata = this.getTypeMetadata(type);
|
||||
propMetadata = {};
|
||||
if (classMetadata['extends']) {
|
||||
const parentType = this.simplify(type, classMetadata['extends']);
|
||||
const parentType = this.trySimplify(type, classMetadata['extends']);
|
||||
if (parentType instanceof StaticSymbol) {
|
||||
const parentPropMetadata = this.propMetadata(parentType);
|
||||
Object.keys(parentPropMetadata).forEach((parentProp) => {
|
||||
@ -176,7 +176,7 @@ export class StaticReflector implements ɵReflectorReader {
|
||||
parameters.push(nestedResult);
|
||||
});
|
||||
} else if (classMetadata['extends']) {
|
||||
const parentType = this.simplify(type, classMetadata['extends']);
|
||||
const parentType = this.trySimplify(type, classMetadata['extends']);
|
||||
if (parentType instanceof StaticSymbol) {
|
||||
parameters = this.parameters(parentType);
|
||||
}
|
||||
@ -199,7 +199,7 @@ export class StaticReflector implements ɵReflectorReader {
|
||||
const classMetadata = this.getTypeMetadata(type);
|
||||
methodNames = {};
|
||||
if (classMetadata['extends']) {
|
||||
const parentType = this.simplify(type, classMetadata['extends']);
|
||||
const parentType = this.trySimplify(type, classMetadata['extends']);
|
||||
if (parentType instanceof StaticSymbol) {
|
||||
const parentMethodNames = this._methodNames(parentType);
|
||||
Object.keys(parentMethodNames).forEach((parentProp) => {
|
||||
|
@ -59,6 +59,7 @@ export class StaticSymbolResolver {
|
||||
// Note: this will only contain StaticSymbols without members!
|
||||
private importAs = new Map<StaticSymbol, StaticSymbol>();
|
||||
private symbolResourcePaths = new Map<StaticSymbol, string>();
|
||||
private symbolFromFile = new Map<string, StaticSymbol[]>();
|
||||
|
||||
constructor(
|
||||
private host: StaticSymbolResolverHost, private staticSymbolCache: StaticSymbolCache,
|
||||
@ -143,6 +144,25 @@ export class StaticSymbolResolver {
|
||||
this.importAs.set(sourceSymbol, targetSymbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate all information derived from the given file.
|
||||
*
|
||||
* @param fileName the file to invalidate
|
||||
*/
|
||||
invalidateFile(fileName: string) {
|
||||
this.metadataCache.delete(fileName);
|
||||
this.resolvedFilePaths.delete(fileName);
|
||||
const symbols = this.symbolFromFile.get(fileName);
|
||||
if (symbols) {
|
||||
this.symbolFromFile.delete(fileName);
|
||||
for (const symbol of symbols) {
|
||||
this.resolvedSymbols.delete(symbol);
|
||||
this.importAs.delete(symbol);
|
||||
this.symbolResourcePaths.delete(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _resolveSymbolMembers(staticSymbol: StaticSymbol): ResolvedStaticSymbol {
|
||||
const members = staticSymbol.members;
|
||||
const baseResolvedSymbol =
|
||||
@ -281,6 +301,7 @@ export class StaticSymbolResolver {
|
||||
}
|
||||
resolvedSymbols.forEach(
|
||||
(resolvedSymbol) => this.resolvedSymbols.set(resolvedSymbol.symbol, resolvedSymbol));
|
||||
this.symbolFromFile.set(filePath, resolvedSymbols.map(resolvedSymbol => resolvedSymbol.symbol));
|
||||
}
|
||||
|
||||
private createResolvedSymbol(
|
||||
|
@ -65,6 +65,10 @@ export class DirectiveNormalizer {
|
||||
let normalizedTemplateSync: CompileTemplateMetadata = null;
|
||||
let normalizedTemplateAsync: Promise<CompileTemplateMetadata>;
|
||||
if (prenormData.template != null) {
|
||||
if (prenormData.templateUrl != null) {
|
||||
throw syntaxError(
|
||||
`'${stringify(prenormData.componentType)}' component cannot define both template and templateUrl`);
|
||||
}
|
||||
if (typeof prenormData.template !== 'string') {
|
||||
throw syntaxError(
|
||||
`The template specified for component ${stringify(prenormData.componentType)} is not a string`);
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, Directive, HostBinding, HostListener, Input, Output, Query, Type, resolveForwardRef, ɵReflectorReader, ɵmerge as merge, ɵreflector, ɵstringify as stringify} from '@angular/core';
|
||||
import {Component, Directive, HostBinding, HostListener, Input, Output, Query, Type, resolveForwardRef, ɵReflectorReader, ɵreflector, ɵstringify as stringify} from '@angular/core';
|
||||
import {CompilerInjectable} from './injectable';
|
||||
import {splitAtColon} from './util';
|
||||
|
||||
@ -124,8 +124,8 @@ export class DirectiveResolver {
|
||||
this._dedupeBindings(directive.inputs ? directive.inputs.concat(inputs) : inputs);
|
||||
const mergedOutputs =
|
||||
this._dedupeBindings(directive.outputs ? directive.outputs.concat(outputs) : outputs);
|
||||
const mergedHost = directive.host ? merge(directive.host, host) : host;
|
||||
const mergedQueries = directive.queries ? merge(directive.queries, queries) : queries;
|
||||
const mergedHost = directive.host ? {...directive.host, ...host} : host;
|
||||
const mergedQueries = directive.queries ? {...directive.queries, ...queries} : queries;
|
||||
|
||||
if (directive instanceof Component) {
|
||||
return new Component({
|
||||
|
@ -161,8 +161,9 @@ class _I18nVisitor implements html.Visitor {
|
||||
}
|
||||
}
|
||||
|
||||
const _CUSTOM_PH_EXP = /\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*"([\s\S]*?)"[\s\S]*\)/g;
|
||||
const _CUSTOM_PH_EXP =
|
||||
/\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*("|')([\s\S]*?)\1[\s\S]*\)/g;
|
||||
|
||||
function _extractPlaceholderName(input: string): string {
|
||||
return input.split(_CUSTOM_PH_EXP)[1];
|
||||
return input.split(_CUSTOM_PH_EXP)[2];
|
||||
}
|
||||
|
@ -644,8 +644,8 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
||||
return EventHandlerVars.event;
|
||||
}
|
||||
let currViewExpr: o.Expression = VIEW_VAR;
|
||||
for (let currBuilder: ViewBuilder = this; currBuilder;
|
||||
currBuilder = currBuilder.parent, currViewExpr = currViewExpr.prop('parent')) {
|
||||
for (let currBuilder: ViewBuilder = this; currBuilder; currBuilder = currBuilder.parent,
|
||||
currViewExpr = currViewExpr.prop('parent').cast(o.DYNAMIC_TYPE)) {
|
||||
// check references
|
||||
const refNodeIndex = currBuilder.refNodeIndices[name];
|
||||
if (refNodeIndex != null) {
|
||||
@ -717,7 +717,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
||||
let compBuilder: ViewBuilder = this;
|
||||
while (compBuilder.parent) {
|
||||
compBuilder = compBuilder.parent;
|
||||
compViewExpr = compViewExpr.prop('parent');
|
||||
compViewExpr = compViewExpr.prop('parent').cast(o.DYNAMIC_TYPE);
|
||||
}
|
||||
const pipeNodeIndex = compBuilder.purePipeNodeIndices[name];
|
||||
const pipeValueExpr: o.Expression =
|
||||
|
@ -495,6 +495,31 @@ describe('StaticReflector', () => {
|
||||
expect(() => reflector.propMetadata(appComponent)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should not throw with an invalid extends', () => {
|
||||
const data = Object.create(DEFAULT_TEST_DATA);
|
||||
const file = '/tmp/src/invalid-component.ts';
|
||||
data[file] = `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
function InvalidParent() {
|
||||
return InvalidParent;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'tmp',
|
||||
template: '',
|
||||
})
|
||||
export class BadComponent extends InvalidParent() {
|
||||
|
||||
}
|
||||
`;
|
||||
init(data);
|
||||
const badComponent = reflector.getStaticSymbol(file, 'BadComponent');
|
||||
expect(reflector.propMetadata(badComponent)).toEqual({});
|
||||
expect(reflector.parameters(badComponent)).toEqual([]);
|
||||
expect(reflector.hasLifecycleHook(badComponent, 'onDestroy')).toEqual(false);
|
||||
});
|
||||
|
||||
it('should produce a annotation even if it contains errors', () => {
|
||||
const data = Object.create(DEFAULT_TEST_DATA);
|
||||
const file = '/tmp/src/invalid-component.ts';
|
||||
|
@ -51,6 +51,16 @@ export function main() {
|
||||
templateUrl: <any>{}
|
||||
})).toThrowError('The templateUrl specified for component SomeComp is not a string');
|
||||
}));
|
||||
it('should throw if both template and templateUrl are defined',
|
||||
inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => {
|
||||
expect(() => normalizer.normalizeTemplate({
|
||||
ngModuleType: null,
|
||||
componentType: SomeComp,
|
||||
moduleUrl: SOME_MODULE_URL,
|
||||
template: '',
|
||||
templateUrl: '',
|
||||
})).toThrowError(`'SomeComp' component cannot define both template and templateUrl`);
|
||||
}));
|
||||
});
|
||||
|
||||
describe('normalizeTemplateSync', () => {
|
||||
|
@ -125,6 +125,12 @@ export function main() {
|
||||
.toEqual([
|
||||
[['[before, <ph name="TEST"> exp //i18n(ph="teSt") </ph>, after]'], 'm', 'd'],
|
||||
]);
|
||||
|
||||
expect(
|
||||
_humanizeMessages('<div i18n=\'m|d\'>before{{ exp //i18n(ph=\'teSt\') }}after</div>'))
|
||||
.toEqual([
|
||||
[[`[before, <ph name="TEST"> exp //i18n(ph='teSt') </ph>, after]`], 'm', 'd'],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
|
158
packages/compiler/test/i18n/integration_common.ts
Normal file
158
packages/compiler/test/i18n/integration_common.ts
Normal file
@ -0,0 +1,158 @@
|
||||
/**
|
||||
* @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 {NgLocalization} from '@angular/common';
|
||||
import {Component, DebugElement} from '@angular/core';
|
||||
import {ComponentFixture} from '@angular/core/testing';
|
||||
|
||||
import {By} from '@angular/platform-browser/src/dom/debug/by';
|
||||
import {stringifyElement} from '@angular/platform-browser/testing/src/browser_util';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
@Component({
|
||||
selector: 'i18n-cmp',
|
||||
template: '',
|
||||
})
|
||||
export class I18nComponent {
|
||||
count: number;
|
||||
sex: string;
|
||||
sexB: string;
|
||||
response: any = {getItemsList: (): any[] => []};
|
||||
}
|
||||
|
||||
export class FrLocalization extends NgLocalization {
|
||||
getPluralCategory(value: number): string {
|
||||
switch (value) {
|
||||
case 0:
|
||||
case 1:
|
||||
return 'one';
|
||||
default:
|
||||
return 'other';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function validateHtml(
|
||||
tb: ComponentFixture<I18nComponent>, cmp: I18nComponent, el: DebugElement) {
|
||||
expectHtml(el, 'h1').toBe('<h1>attributs i18n sur les balises</h1>');
|
||||
expectHtml(el, '#i18n-1').toBe('<div id="i18n-1"><p>imbriqué</p></div>');
|
||||
expectHtml(el, '#i18n-2').toBe('<div id="i18n-2"><p>imbriqué</p></div>');
|
||||
expectHtml(el, '#i18n-3').toBe('<div id="i18n-3"><p><i>avec des espaces réservés</i></p></div>');
|
||||
expectHtml(el, '#i18n-3b')
|
||||
.toBe(
|
||||
'<div id="i18n-3b"><p><i class="preserved-on-placeholders">avec des espaces réservés</i></p></div>');
|
||||
expectHtml(el, '#i18n-4').toBe('<p id="i18n-4" title="sur des balises non traductibles"></p>');
|
||||
expectHtml(el, '#i18n-5').toBe('<p id="i18n-5" title="sur des balises traductibles"></p>');
|
||||
expectHtml(el, '#i18n-6').toBe('<p id="i18n-6" title=""></p>');
|
||||
|
||||
cmp.count = 0;
|
||||
tb.detectChanges();
|
||||
expect(el.query(By.css('#i18n-7')).nativeElement).toHaveText('zero');
|
||||
expect(el.query(By.css('#i18n-14')).nativeElement).toHaveText('zero');
|
||||
cmp.count = 1;
|
||||
tb.detectChanges();
|
||||
expect(el.query(By.css('#i18n-7')).nativeElement).toHaveText('un');
|
||||
expect(el.query(By.css('#i18n-14')).nativeElement).toHaveText('un');
|
||||
expect(el.query(By.css('#i18n-17')).nativeElement).toHaveText('un');
|
||||
cmp.count = 2;
|
||||
tb.detectChanges();
|
||||
expect(el.query(By.css('#i18n-7')).nativeElement).toHaveText('deux');
|
||||
expect(el.query(By.css('#i18n-14')).nativeElement).toHaveText('deux');
|
||||
expect(el.query(By.css('#i18n-17')).nativeElement).toHaveText('deux');
|
||||
cmp.count = 3;
|
||||
tb.detectChanges();
|
||||
expect(el.query(By.css('#i18n-7')).nativeElement).toHaveText('beaucoup');
|
||||
expect(el.query(By.css('#i18n-14')).nativeElement).toHaveText('beaucoup');
|
||||
expect(el.query(By.css('#i18n-17')).nativeElement).toHaveText('beaucoup');
|
||||
|
||||
cmp.sex = 'm';
|
||||
cmp.sexB = 'f';
|
||||
tb.detectChanges();
|
||||
expect(el.query(By.css('#i18n-8')).nativeElement).toHaveText('homme');
|
||||
expect(el.query(By.css('#i18n-8b')).nativeElement).toHaveText('femme');
|
||||
cmp.sex = 'f';
|
||||
tb.detectChanges();
|
||||
expect(el.query(By.css('#i18n-8')).nativeElement).toHaveText('femme');
|
||||
|
||||
cmp.count = 123;
|
||||
tb.detectChanges();
|
||||
expectHtml(el, '#i18n-9').toEqual('<div id="i18n-9">count = 123</div>');
|
||||
|
||||
cmp.sex = 'f';
|
||||
tb.detectChanges();
|
||||
expectHtml(el, '#i18n-10').toEqual('<div id="i18n-10">sexe = f</div>');
|
||||
|
||||
expectHtml(el, '#i18n-11').toEqual('<div id="i18n-11">custom name</div>');
|
||||
expectHtml(el, '#i18n-12').toEqual('<h1 id="i18n-12">Balises dans les commentaires html</h1>');
|
||||
expectHtml(el, '#i18n-13').toBe('<div id="i18n-13" title="dans une section traductible"></div>');
|
||||
expectHtml(el, '#i18n-15').toMatch(/ca <b>devrait<\/b> marcher/);
|
||||
expectHtml(el, '#i18n-16').toMatch(/avec un ID explicite/);
|
||||
expectHtml(el, '#i18n-18')
|
||||
.toEqual('<div id="i18n-18">FOO<a title="dans une section traductible">BAR</a></div>');
|
||||
}
|
||||
|
||||
function expectHtml(el: DebugElement, cssSelector: string): any {
|
||||
return expect(stringifyElement(el.query(By.css(cssSelector)).nativeElement));
|
||||
}
|
||||
|
||||
export const HTML = `
|
||||
<div>
|
||||
<h1 i18n>i18n attribute on tags</h1>
|
||||
|
||||
<div id="i18n-1"><p i18n>nested</p></div>
|
||||
|
||||
<div id="i18n-2"><p i18n="different meaning|">nested</p></div>
|
||||
|
||||
<div id="i18n-3"><p i18n><i>with placeholders</i></p></div>
|
||||
<div id="i18n-3b"><p i18n><i class="preserved-on-placeholders">with placeholders</i></p></div>
|
||||
|
||||
<div>
|
||||
<p id="i18n-4" i18n-title title="on not translatable node"></p>
|
||||
<p id="i18n-5" i18n i18n-title title="on translatable node"></p>
|
||||
<p id="i18n-6" i18n-title title></p>
|
||||
</div>
|
||||
|
||||
<!-- no ph below because the ICU node is the only child of the div, i.e. no text nodes -->
|
||||
<div i18n id="i18n-7">{count, plural, =0 {zero} =1 {one} =2 {two} other {<b>many</b>}}</div>
|
||||
|
||||
<div i18n id="i18n-8">
|
||||
{sex, select, m {male} f {female}}
|
||||
</div>
|
||||
<div i18n id="i18n-8b">
|
||||
{sexB, select, m {male} f {female}}
|
||||
</div>
|
||||
|
||||
<div i18n id="i18n-9">{{ "count = " + count }}</div>
|
||||
<div i18n id="i18n-10">sex = {{ sex }}</div>
|
||||
<div i18n id="i18n-11">{{ "custom name" //i18n(ph="CUSTOM_NAME") }}</div>
|
||||
</div>
|
||||
|
||||
<!-- i18n -->
|
||||
<h1 id="i18n-12" >Markers in html comments</h1>
|
||||
<div id="i18n-13" i18n-title title="in a translatable section"></div>
|
||||
<div id="i18n-14">{count, plural, =0 {zero} =1 {one} =2 {two} other {<b>many</b>}}</div>
|
||||
<!-- /i18n -->
|
||||
|
||||
<div id="i18n-15"><ng-container i18n>it <b>should</b> work</ng-container></div>
|
||||
|
||||
<div id="i18n-16" i18n="@@i18n16">with an explicit ID</div>
|
||||
<div id="i18n-17" i18n="@@i18n17">{count, plural, =0 {zero} =1 {one} =2 {two} other {<b>many</b>}}</div>
|
||||
|
||||
<!-- make sure that ICU messages are not treated as text nodes -->
|
||||
<div i18n="desc">{
|
||||
response.getItemsList().length,
|
||||
plural,
|
||||
=0 {Found no results}
|
||||
=1 {Found one result}
|
||||
other {Found {{response.getItemsList().length}} results}
|
||||
}</div>
|
||||
|
||||
<div i18n id="i18n-18">foo<a i18n-title title="in a translatable section">bar</a></div>
|
||||
|
||||
<div i18n>{{ 'test' //i18n(ph="map name") }}</div>
|
||||
`;
|
@ -12,16 +12,16 @@ import {MessageBundle} from '@angular/compiler/src/i18n/message_bundle';
|
||||
import {Xmb} from '@angular/compiler/src/i18n/serializers/xmb';
|
||||
import {HtmlParser} from '@angular/compiler/src/ml_parser/html_parser';
|
||||
import {DEFAULT_INTERPOLATION_CONFIG} from '@angular/compiler/src/ml_parser/interpolation_config';
|
||||
import {Component, DebugElement, TRANSLATIONS, TRANSLATIONS_FORMAT} from '@angular/core';
|
||||
import {TestBed, async} from '@angular/core/testing';
|
||||
import {By} from '@angular/platform-browser/src/dom/debug/by';
|
||||
import {stringifyElement} from '@angular/platform-browser/testing/src/browser_util';
|
||||
import {DebugElement, TRANSLATIONS, TRANSLATIONS_FORMAT} from '@angular/core';
|
||||
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
import {SpyResourceLoader} from '../spies';
|
||||
|
||||
import {FrLocalization, HTML, I18nComponent, validateHtml} from './integration_common';
|
||||
|
||||
export function main() {
|
||||
describe('i18n integration spec', () => {
|
||||
describe('i18n XMB/XTB integration spec', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureCompiler({
|
||||
@ -45,100 +45,16 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should translate templates', () => {
|
||||
const tb = TestBed.overrideTemplate(I18nComponent, HTML).createComponent(I18nComponent);
|
||||
const cmp = tb.componentInstance;
|
||||
const el = tb.debugElement;
|
||||
const tb: ComponentFixture<I18nComponent> =
|
||||
TestBed.overrideTemplate(I18nComponent, HTML).createComponent(I18nComponent);
|
||||
const cmp: I18nComponent = tb.componentInstance;
|
||||
const el: DebugElement = tb.debugElement;
|
||||
|
||||
expectHtml(el, 'h1').toBe('<h1>attributs i18n sur les balises</h1>');
|
||||
expectHtml(el, '#i18n-1').toBe('<div id="i18n-1"><p>imbriqué</p></div>');
|
||||
expectHtml(el, '#i18n-2').toBe('<div id="i18n-2"><p>imbriqué</p></div>');
|
||||
expectHtml(el, '#i18n-3')
|
||||
.toBe('<div id="i18n-3"><p><i>avec des espaces réservés</i></p></div>');
|
||||
expectHtml(el, '#i18n-3b')
|
||||
.toBe(
|
||||
'<div id="i18n-3b"><p><i class="preserved-on-placeholders">avec des espaces réservés</i></p></div>');
|
||||
expectHtml(el, '#i18n-4')
|
||||
.toBe('<p id="i18n-4" title="sur des balises non traductibles"></p>');
|
||||
expectHtml(el, '#i18n-5').toBe('<p id="i18n-5" title="sur des balises traductibles"></p>');
|
||||
expectHtml(el, '#i18n-6').toBe('<p id="i18n-6" title=""></p>');
|
||||
|
||||
cmp.count = 0;
|
||||
tb.detectChanges();
|
||||
expect(el.query(By.css('#i18n-7')).nativeElement).toHaveText('zero');
|
||||
expect(el.query(By.css('#i18n-14')).nativeElement).toHaveText('zero');
|
||||
cmp.count = 1;
|
||||
tb.detectChanges();
|
||||
expect(el.query(By.css('#i18n-7')).nativeElement).toHaveText('un');
|
||||
expect(el.query(By.css('#i18n-14')).nativeElement).toHaveText('un');
|
||||
expect(el.query(By.css('#i18n-17')).nativeElement).toHaveText('un');
|
||||
cmp.count = 2;
|
||||
tb.detectChanges();
|
||||
expect(el.query(By.css('#i18n-7')).nativeElement).toHaveText('deux');
|
||||
expect(el.query(By.css('#i18n-14')).nativeElement).toHaveText('deux');
|
||||
expect(el.query(By.css('#i18n-17')).nativeElement).toHaveText('deux');
|
||||
cmp.count = 3;
|
||||
tb.detectChanges();
|
||||
expect(el.query(By.css('#i18n-7')).nativeElement).toHaveText('beaucoup');
|
||||
expect(el.query(By.css('#i18n-14')).nativeElement).toHaveText('beaucoup');
|
||||
expect(el.query(By.css('#i18n-17')).nativeElement).toHaveText('beaucoup');
|
||||
|
||||
cmp.sex = 'm';
|
||||
cmp.sexB = 'f';
|
||||
tb.detectChanges();
|
||||
expect(el.query(By.css('#i18n-8')).nativeElement).toHaveText('homme');
|
||||
expect(el.query(By.css('#i18n-8b')).nativeElement).toHaveText('femme');
|
||||
cmp.sex = 'f';
|
||||
tb.detectChanges();
|
||||
expect(el.query(By.css('#i18n-8')).nativeElement).toHaveText('femme');
|
||||
|
||||
cmp.count = 123;
|
||||
tb.detectChanges();
|
||||
expectHtml(el, '#i18n-9').toEqual('<div id="i18n-9">count = 123</div>');
|
||||
|
||||
cmp.sex = 'f';
|
||||
tb.detectChanges();
|
||||
expectHtml(el, '#i18n-10').toEqual('<div id="i18n-10">sexe = f</div>');
|
||||
|
||||
expectHtml(el, '#i18n-11').toEqual('<div id="i18n-11">custom name</div>');
|
||||
expectHtml(el, '#i18n-12')
|
||||
.toEqual('<h1 id="i18n-12">Balises dans les commentaires html</h1>');
|
||||
expectHtml(el, '#i18n-13')
|
||||
.toBe('<div id="i18n-13" title="dans une section traductible"></div>');
|
||||
expectHtml(el, '#i18n-15').toMatch(/ca <b>devrait<\/b> marcher/);
|
||||
expectHtml(el, '#i18n-16').toMatch(/avec un ID explicite/);
|
||||
expectHtml(el, '#i18n-18')
|
||||
.toEqual('<div id="i18n-18">FOO<a title="dans une section traductible">BAR</a></div>');
|
||||
validateHtml(tb, cmp, el);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function expectHtml(el: DebugElement, cssSelector: string): any {
|
||||
return expect(stringifyElement(el.query(By.css(cssSelector)).nativeElement));
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'i18n-cmp',
|
||||
template: '',
|
||||
})
|
||||
class I18nComponent {
|
||||
count: number;
|
||||
sex: string;
|
||||
sexB: string;
|
||||
response: any = {getItemsList: (): any[] => []};
|
||||
}
|
||||
|
||||
class FrLocalization extends NgLocalization {
|
||||
getPluralCategory(value: number): string {
|
||||
switch (value) {
|
||||
case 0:
|
||||
case 1:
|
||||
return 'one';
|
||||
default:
|
||||
return 'other';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const XTB = `
|
||||
<translationbundle>
|
||||
<translation id="615790887472569365">attributs i18n sur les balises</translation>
|
||||
@ -194,60 +110,3 @@ const XMB = ` <msg id="615790887472569365">i18n attribute on tags</msg>
|
||||
<msg id="4085484936881858615" desc="desc">{VAR_PLURAL, plural, =0 {Found no results} =1 {Found one result} other {Found <ph name="INTERPOLATION"><ex>INTERPOLATION</ex></ph> results} }</msg>
|
||||
<msg id="4035252431381981115">foo<ph name="START_LINK"><ex><a></ex></ph>bar<ph name="CLOSE_LINK"><ex></a></ex></ph></msg>
|
||||
<msg id="5339604010413301604"><ph name="MAP_NAME"><ex>MAP_NAME</ex></ph></msg>`;
|
||||
|
||||
const HTML = `
|
||||
<div>
|
||||
<h1 i18n>i18n attribute on tags</h1>
|
||||
|
||||
<div id="i18n-1"><p i18n>nested</p></div>
|
||||
|
||||
<div id="i18n-2"><p i18n="different meaning|">nested</p></div>
|
||||
|
||||
<div id="i18n-3"><p i18n><i>with placeholders</i></p></div>
|
||||
<div id="i18n-3b"><p i18n><i class="preserved-on-placeholders">with placeholders</i></p></div>
|
||||
|
||||
<div>
|
||||
<p id="i18n-4" i18n-title title="on not translatable node"></p>
|
||||
<p id="i18n-5" i18n i18n-title title="on translatable node"></p>
|
||||
<p id="i18n-6" i18n-title title></p>
|
||||
</div>
|
||||
|
||||
<!-- no ph below because the ICU node is the only child of the div, i.e. no text nodes -->
|
||||
<div i18n id="i18n-7">{count, plural, =0 {zero} =1 {one} =2 {two} other {<b>many</b>}}</div>
|
||||
|
||||
<div i18n id="i18n-8">
|
||||
{sex, select, m {male} f {female}}
|
||||
</div>
|
||||
<div i18n id="i18n-8b">
|
||||
{sexB, select, m {male} f {female}}
|
||||
</div>
|
||||
|
||||
<div i18n id="i18n-9">{{ "count = " + count }}</div>
|
||||
<div i18n id="i18n-10">sex = {{ sex }}</div>
|
||||
<div i18n id="i18n-11">{{ "custom name" //i18n(ph="CUSTOM_NAME") }}</div>
|
||||
</div>
|
||||
|
||||
<!-- i18n -->
|
||||
<h1 id="i18n-12" >Markers in html comments</h1>
|
||||
<div id="i18n-13" i18n-title title="in a translatable section"></div>
|
||||
<div id="i18n-14">{count, plural, =0 {zero} =1 {one} =2 {two} other {<b>many</b>}}</div>
|
||||
<!-- /i18n -->
|
||||
|
||||
<div id="i18n-15"><ng-container i18n>it <b>should</b> work</ng-container></div>
|
||||
|
||||
<div id="i18n-16" i18n="@@i18n16">with an explicit ID</div>
|
||||
<div id="i18n-17" i18n="@@i18n17">{count, plural, =0 {zero} =1 {one} =2 {two} other {<b>many</b>}}</div>
|
||||
|
||||
<!-- make sure that ICU messages are not treated as text nodes -->
|
||||
<div i18n="desc">{
|
||||
response.getItemsList().length,
|
||||
plural,
|
||||
=0 {Found no results}
|
||||
=1 {Found one result}
|
||||
other {Found {{response.getItemsList().length}} results}
|
||||
}</div>
|
||||
|
||||
<div i18n id="i18n-18">foo<a i18n-title title="in a translatable section">bar</a></div>
|
||||
|
||||
<div i18n>{{ 'test' //i18n(ph="map name") }}</div>
|
||||
`;
|
@ -62,7 +62,7 @@ export interface AnimationStyleMetadata extends AnimationMetadata {
|
||||
*/
|
||||
export interface AnimationAnimateMetadata extends AnimationMetadata {
|
||||
timings: string|number|AnimateTimings;
|
||||
styles: AnimationStyleMetadata|AnimationKeyframesSequenceMetadata;
|
||||
styles: AnimationStyleMetadata|AnimationKeyframesSequenceMetadata|null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,8 +86,8 @@ export function trigger(name: string, definitions: AnimationMetadata[]): Animati
|
||||
* @deprecated This symbol has moved. Please Import from @angular/animations instead!
|
||||
*/
|
||||
export function animate(
|
||||
timings: string | number, styles: AnimationStyleMetadata | AnimationKeyframesSequenceMetadata =
|
||||
null): AnimationAnimateMetadata {
|
||||
timings: string | number, styles?: AnimationStyleMetadata |
|
||||
AnimationKeyframesSequenceMetadata): AnimationAnimateMetadata {
|
||||
return _animate(timings, styles);
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ export function createPlatform(injector: Injector): PlatformRef {
|
||||
* @experimental APIs related to application bootstrap are currently under review.
|
||||
*/
|
||||
export function createPlatformFactory(
|
||||
parentPlatformFactory: (extraProviders?: Provider[]) => PlatformRef, name: string,
|
||||
parentPlatformFactory: ((extraProviders?: Provider[]) => PlatformRef) | null, name: string,
|
||||
providers: Provider[] = []): (extraProviders?: Provider[]) => PlatformRef {
|
||||
const marker = new InjectionToken(`Platform: ${name}`);
|
||||
return (extraProviders: Provider[] = []) => {
|
||||
@ -153,7 +153,7 @@ export function destroyPlatform(): void {
|
||||
*
|
||||
* @experimental APIs related to application bootstrap are currently under review.
|
||||
*/
|
||||
export function getPlatform(): PlatformRef {
|
||||
export function getPlatform(): PlatformRef|null {
|
||||
return _platform && !_platform.destroyed ? _platform : null;
|
||||
}
|
||||
|
||||
@ -278,10 +278,10 @@ export class PlatformRef_ extends PlatformRef {
|
||||
}
|
||||
|
||||
bootstrapModuleFactory<M>(moduleFactory: NgModuleFactory<M>): Promise<NgModuleRef<M>> {
|
||||
return this._bootstrapModuleFactoryWithZone(moduleFactory, null);
|
||||
return this._bootstrapModuleFactoryWithZone(moduleFactory);
|
||||
}
|
||||
|
||||
private _bootstrapModuleFactoryWithZone<M>(moduleFactory: NgModuleFactory<M>, ngZone: NgZone):
|
||||
private _bootstrapModuleFactoryWithZone<M>(moduleFactory: NgModuleFactory<M>, ngZone?: NgZone):
|
||||
Promise<NgModuleRef<M>> {
|
||||
// Note: We need to create the NgZone _before_ we instantiate the module,
|
||||
// as instantiating the module creates some providers eagerly.
|
||||
@ -299,7 +299,7 @@ export class PlatformRef_ extends PlatformRef {
|
||||
throw new Error('No ErrorHandler. Is platform module (BrowserModule) included?');
|
||||
}
|
||||
moduleRef.onDestroy(() => remove(this._modules, moduleRef));
|
||||
ngZone.onError.subscribe({next: (error: any) => { exceptionHandler.handleError(error); }});
|
||||
ngZone !.onError.subscribe({next: (error: any) => { exceptionHandler.handleError(error); }});
|
||||
return _callAndReportToErrorHandler(exceptionHandler, () => {
|
||||
const initStatus: ApplicationInitStatus = moduleRef.injector.get(ApplicationInitStatus);
|
||||
return initStatus.donePromise.then(() => {
|
||||
@ -312,12 +312,12 @@ export class PlatformRef_ extends PlatformRef {
|
||||
|
||||
bootstrapModule<M>(moduleType: Type<M>, compilerOptions: CompilerOptions|CompilerOptions[] = []):
|
||||
Promise<NgModuleRef<M>> {
|
||||
return this._bootstrapModuleWithZone(moduleType, compilerOptions, null);
|
||||
return this._bootstrapModuleWithZone(moduleType, compilerOptions);
|
||||
}
|
||||
|
||||
private _bootstrapModuleWithZone<M>(
|
||||
moduleType: Type<M>, compilerOptions: CompilerOptions|CompilerOptions[] = [],
|
||||
ngZone: NgZone = null): Promise<NgModuleRef<M>> {
|
||||
ngZone?: NgZone): Promise<NgModuleRef<M>> {
|
||||
const compilerFactory: CompilerFactory = this.injector.get(CompilerFactory);
|
||||
const compiler = compilerFactory.createCompiler(
|
||||
Array.isArray(compilerOptions) ? compilerOptions : [compilerOptions]);
|
||||
@ -500,7 +500,8 @@ export class ApplicationRef_ extends ApplicationRef {
|
||||
if (componentOrFactory instanceof ComponentFactory) {
|
||||
componentFactory = componentOrFactory;
|
||||
} else {
|
||||
componentFactory = this._componentFactoryResolver.resolveComponentFactory(componentOrFactory);
|
||||
componentFactory =
|
||||
this._componentFactoryResolver.resolveComponentFactory(componentOrFactory) !;
|
||||
}
|
||||
this._rootComponentTypes.push(componentFactory.componentType);
|
||||
|
||||
|
@ -15,16 +15,15 @@ import {IterableChangeRecord, IterableChanges, IterableDiffer, IterableDifferFac
|
||||
|
||||
export class DefaultIterableDifferFactory implements IterableDifferFactory {
|
||||
constructor() {}
|
||||
supports(obj: Object): boolean { return isListLikeIterable(obj); }
|
||||
supports(obj: Object|null|undefined): boolean { return isListLikeIterable(obj); }
|
||||
|
||||
create<V>(trackByFn?: TrackByFunction<any>): DefaultIterableDiffer<V>;
|
||||
create<V>(trackByFn?: TrackByFunction<V>): DefaultIterableDiffer<V>;
|
||||
|
||||
/**
|
||||
* @deprecated v4.0.0 - ChangeDetectorRef is not used and is no longer a parameter
|
||||
*/
|
||||
create<V>(
|
||||
cdRefOrTrackBy?: ChangeDetectorRef|TrackByFunction<any>,
|
||||
trackByFn?: TrackByFunction<any>): DefaultIterableDiffer<V> {
|
||||
create<V>(cdRefOrTrackBy?: ChangeDetectorRef|TrackByFunction<V>, trackByFn?: TrackByFunction<V>):
|
||||
DefaultIterableDiffer<V> {
|
||||
return new DefaultIterableDiffer<V>(trackByFn || <TrackByFunction<any>>cdRefOrTrackBy);
|
||||
}
|
||||
}
|
||||
@ -35,27 +34,28 @@ const trackByIdentity = (index: number, item: any) => item;
|
||||
* @deprecated v4.0.0 - Should not be part of public API.
|
||||
*/
|
||||
export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChanges<V> {
|
||||
private _length: number = null;
|
||||
private _collection: NgIterable<V> = null;
|
||||
private _length: number = 0;
|
||||
private _collection: NgIterable<V>|null = null;
|
||||
// Keeps track of the used records at any point in time (during & across `_check()` calls)
|
||||
private _linkedRecords: _DuplicateMap<V> = null;
|
||||
private _linkedRecords: _DuplicateMap<V>|null = null;
|
||||
// Keeps track of the removed records at any point in time during `_check()` calls.
|
||||
private _unlinkedRecords: _DuplicateMap<V> = null;
|
||||
private _previousItHead: IterableChangeRecord_<V> = null;
|
||||
private _itHead: IterableChangeRecord_<V> = null;
|
||||
private _itTail: IterableChangeRecord_<V> = null;
|
||||
private _additionsHead: IterableChangeRecord_<V> = null;
|
||||
private _additionsTail: IterableChangeRecord_<V> = null;
|
||||
private _movesHead: IterableChangeRecord_<V> = null;
|
||||
private _movesTail: IterableChangeRecord_<V> = null;
|
||||
private _removalsHead: IterableChangeRecord_<V> = null;
|
||||
private _removalsTail: IterableChangeRecord_<V> = null;
|
||||
private _unlinkedRecords: _DuplicateMap<V>|null = null;
|
||||
private _previousItHead: IterableChangeRecord_<V>|null = null;
|
||||
private _itHead: IterableChangeRecord_<V>|null = null;
|
||||
private _itTail: IterableChangeRecord_<V>|null = null;
|
||||
private _additionsHead: IterableChangeRecord_<V>|null = null;
|
||||
private _additionsTail: IterableChangeRecord_<V>|null = null;
|
||||
private _movesHead: IterableChangeRecord_<V>|null = null;
|
||||
private _movesTail: IterableChangeRecord_<V>|null = null;
|
||||
private _removalsHead: IterableChangeRecord_<V>|null = null;
|
||||
private _removalsTail: IterableChangeRecord_<V>|null = null;
|
||||
// Keeps track of records where custom track by is the same, but item identity has changed
|
||||
private _identityChangesHead: IterableChangeRecord_<V> = null;
|
||||
private _identityChangesTail: IterableChangeRecord_<V> = null;
|
||||
private _identityChangesHead: IterableChangeRecord_<V>|null = null;
|
||||
private _identityChangesTail: IterableChangeRecord_<V>|null = null;
|
||||
private _trackByFn: TrackByFunction<V>
|
||||
|
||||
constructor(private _trackByFn?: TrackByFunction<V>) {
|
||||
this._trackByFn = this._trackByFn || trackByIdentity;
|
||||
constructor(trackByFn?: TrackByFunction<V>) {
|
||||
this._trackByFn = trackByFn || trackByIdentity;
|
||||
}
|
||||
|
||||
get collection() { return this._collection; }
|
||||
@ -63,25 +63,27 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
|
||||
get length(): number { return this._length; }
|
||||
|
||||
forEachItem(fn: (record: IterableChangeRecord_<V>) => void) {
|
||||
let record: IterableChangeRecord_<V>;
|
||||
let record: IterableChangeRecord_<V>|null;
|
||||
for (record = this._itHead; record !== null; record = record._next) {
|
||||
fn(record);
|
||||
}
|
||||
}
|
||||
|
||||
forEachOperation(
|
||||
fn: (item: IterableChangeRecord_<V>, previousIndex: number, currentIndex: number) => void) {
|
||||
fn: (item: IterableChangeRecord<V>, previousIndex: number|null, currentIndex: number|null) =>
|
||||
void) {
|
||||
let nextIt = this._itHead;
|
||||
let nextRemove = this._removalsHead;
|
||||
let addRemoveOffset = 0;
|
||||
let moveOffsets: number[] = null;
|
||||
let moveOffsets: number[]|null = null;
|
||||
while (nextIt || nextRemove) {
|
||||
// Figure out which is the next record to process
|
||||
// Order: remove, add, move
|
||||
const record = !nextRemove ||
|
||||
const record: IterableChangeRecord<V> = !nextRemove ||
|
||||
nextIt &&
|
||||
nextIt.currentIndex < getPreviousIndex(nextRemove, addRemoveOffset, moveOffsets) ?
|
||||
nextIt :
|
||||
nextIt.currentIndex ! <
|
||||
getPreviousIndex(nextRemove, addRemoveOffset, moveOffsets) ?
|
||||
nextIt ! :
|
||||
nextRemove;
|
||||
const adjPreviousIndex = getPreviousIndex(record, addRemoveOffset, moveOffsets);
|
||||
const currentIndex = record.currentIndex;
|
||||
@ -91,14 +93,14 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
|
||||
addRemoveOffset--;
|
||||
nextRemove = nextRemove._nextRemoved;
|
||||
} else {
|
||||
nextIt = nextIt._next;
|
||||
nextIt = nextIt !._next;
|
||||
if (record.previousIndex == null) {
|
||||
addRemoveOffset++;
|
||||
} else {
|
||||
// INVARIANT: currentIndex < previousIndex
|
||||
if (!moveOffsets) moveOffsets = [];
|
||||
const localMovePreviousIndex = adjPreviousIndex - addRemoveOffset;
|
||||
const localCurrentIndex = currentIndex - addRemoveOffset;
|
||||
const localCurrentIndex = currentIndex ! - addRemoveOffset;
|
||||
if (localMovePreviousIndex != localCurrentIndex) {
|
||||
for (let i = 0; i < localMovePreviousIndex; i++) {
|
||||
const offset = i < moveOffsets.length ? moveOffsets[i] : (moveOffsets[i] = 0);
|
||||
@ -120,44 +122,45 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
|
||||
}
|
||||
|
||||
forEachPreviousItem(fn: (record: IterableChangeRecord_<V>) => void) {
|
||||
let record: IterableChangeRecord_<V>;
|
||||
let record: IterableChangeRecord_<V>|null;
|
||||
for (record = this._previousItHead; record !== null; record = record._nextPrevious) {
|
||||
fn(record);
|
||||
}
|
||||
}
|
||||
|
||||
forEachAddedItem(fn: (record: IterableChangeRecord_<V>) => void) {
|
||||
let record: IterableChangeRecord_<V>;
|
||||
let record: IterableChangeRecord_<V>|null;
|
||||
for (record = this._additionsHead; record !== null; record = record._nextAdded) {
|
||||
fn(record);
|
||||
}
|
||||
}
|
||||
|
||||
forEachMovedItem(fn: (record: IterableChangeRecord_<V>) => void) {
|
||||
let record: IterableChangeRecord_<V>;
|
||||
let record: IterableChangeRecord_<V>|null;
|
||||
for (record = this._movesHead; record !== null; record = record._nextMoved) {
|
||||
fn(record);
|
||||
}
|
||||
}
|
||||
|
||||
forEachRemovedItem(fn: (record: IterableChangeRecord_<V>) => void) {
|
||||
let record: IterableChangeRecord_<V>;
|
||||
let record: IterableChangeRecord_<V>|null;
|
||||
for (record = this._removalsHead; record !== null; record = record._nextRemoved) {
|
||||
fn(record);
|
||||
}
|
||||
}
|
||||
|
||||
forEachIdentityChange(fn: (record: IterableChangeRecord_<V>) => void) {
|
||||
let record: IterableChangeRecord_<V>;
|
||||
let record: IterableChangeRecord_<V>|null;
|
||||
for (record = this._identityChangesHead; record !== null; record = record._nextIdentityChange) {
|
||||
fn(record);
|
||||
}
|
||||
}
|
||||
|
||||
diff(collection: NgIterable<V>): DefaultIterableDiffer<V> {
|
||||
diff(collection: NgIterable<V>): DefaultIterableDiffer<V>|null {
|
||||
if (collection == null) collection = [];
|
||||
if (!isListLikeIterable(collection)) {
|
||||
throw new Error(`Error trying to diff '${collection}'`);
|
||||
throw new Error(
|
||||
`Error trying to diff '${stringify(collection)}'. Only arrays and iterables are allowed`);
|
||||
}
|
||||
|
||||
if (this.check(collection)) {
|
||||
@ -173,7 +176,7 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
|
||||
check(collection: NgIterable<V>): boolean {
|
||||
this._reset();
|
||||
|
||||
let record: IterableChangeRecord_<V> = this._itHead;
|
||||
let record: IterableChangeRecord_<V>|null = this._itHead;
|
||||
let mayBeDirty: boolean = false;
|
||||
let index: number;
|
||||
let item: V;
|
||||
@ -240,8 +243,8 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
|
||||
*/
|
||||
_reset() {
|
||||
if (this.isDirty) {
|
||||
let record: IterableChangeRecord_<V>;
|
||||
let nextRecord: IterableChangeRecord_<V>;
|
||||
let record: IterableChangeRecord_<V>|null;
|
||||
let nextRecord: IterableChangeRecord_<V>|null;
|
||||
|
||||
for (record = this._previousItHead = this._itHead; record !== null; record = record._next) {
|
||||
record._nextPrevious = record._next;
|
||||
@ -275,15 +278,15 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
_mismatch(record: IterableChangeRecord_<V>, item: V, itemTrackBy: any, index: number):
|
||||
_mismatch(record: IterableChangeRecord_<V>|null, item: V, itemTrackBy: any, index: number):
|
||||
IterableChangeRecord_<V> {
|
||||
// The previous record after which we will append the current one.
|
||||
let previousRecord: IterableChangeRecord_<V>;
|
||||
|
||||
if (record === null) {
|
||||
previousRecord = this._itTail;
|
||||
previousRecord = this._itTail !;
|
||||
} else {
|
||||
previousRecord = record._prev;
|
||||
previousRecord = record._prev !;
|
||||
// Remove the record from the collection since we know it does not match the item.
|
||||
this._remove(record);
|
||||
}
|
||||
@ -298,7 +301,7 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
|
||||
this._moveAfter(record, previousRecord, index);
|
||||
} else {
|
||||
// Never seen it, check evicted list.
|
||||
record = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy);
|
||||
record = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null);
|
||||
if (record !== null) {
|
||||
// It is an item which we have evicted earlier: reinsert it back into the list.
|
||||
// But first we need to check if identity changed, so we can update in view if necessary
|
||||
@ -343,10 +346,10 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
|
||||
*/
|
||||
_verifyReinsertion(record: IterableChangeRecord_<V>, item: V, itemTrackBy: any, index: number):
|
||||
IterableChangeRecord_<V> {
|
||||
let reinsertRecord: IterableChangeRecord_<V> =
|
||||
this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy);
|
||||
let reinsertRecord: IterableChangeRecord_<V>|null =
|
||||
this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null);
|
||||
if (reinsertRecord !== null) {
|
||||
record = this._reinsertAfter(reinsertRecord, record._prev, index);
|
||||
record = this._reinsertAfter(reinsertRecord, record._prev !, index);
|
||||
} else if (record.currentIndex != index) {
|
||||
record.currentIndex = index;
|
||||
this._addToMoves(record, index);
|
||||
@ -361,10 +364,10 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
_truncate(record: IterableChangeRecord_<V>) {
|
||||
_truncate(record: IterableChangeRecord_<V>|null) {
|
||||
// Anything after that needs to be removed;
|
||||
while (record !== null) {
|
||||
const nextRecord: IterableChangeRecord_<V> = record._next;
|
||||
const nextRecord: IterableChangeRecord_<V>|null = record._next;
|
||||
this._addToRemovals(this._unlink(record));
|
||||
record = nextRecord;
|
||||
}
|
||||
@ -451,7 +454,8 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
|
||||
// assert(record._next === null);
|
||||
// assert(record._prev === null);
|
||||
|
||||
const next: IterableChangeRecord_<V> = prevRecord === null ? this._itHead : prevRecord._next;
|
||||
const next: IterableChangeRecord_<V>|null =
|
||||
prevRecord === null ? this._itHead : prevRecord._next;
|
||||
// todo(vicb)
|
||||
// assert(next != record);
|
||||
// assert(prevRecord != record);
|
||||
@ -598,29 +602,29 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
|
||||
* @stable
|
||||
*/
|
||||
export class IterableChangeRecord_<V> implements IterableChangeRecord<V> {
|
||||
currentIndex: number = null;
|
||||
previousIndex: number = null;
|
||||
currentIndex: number|null = null;
|
||||
previousIndex: number|null = null;
|
||||
|
||||
/** @internal */
|
||||
_nextPrevious: IterableChangeRecord_<V> = null;
|
||||
_nextPrevious: IterableChangeRecord_<V>|null = null;
|
||||
/** @internal */
|
||||
_prev: IterableChangeRecord_<V> = null;
|
||||
_prev: IterableChangeRecord_<V>|null = null;
|
||||
/** @internal */
|
||||
_next: IterableChangeRecord_<V> = null;
|
||||
_next: IterableChangeRecord_<V>|null = null;
|
||||
/** @internal */
|
||||
_prevDup: IterableChangeRecord_<V> = null;
|
||||
_prevDup: IterableChangeRecord_<V>|null = null;
|
||||
/** @internal */
|
||||
_nextDup: IterableChangeRecord_<V> = null;
|
||||
_nextDup: IterableChangeRecord_<V>|null = null;
|
||||
/** @internal */
|
||||
_prevRemoved: IterableChangeRecord_<V> = null;
|
||||
_prevRemoved: IterableChangeRecord_<V>|null = null;
|
||||
/** @internal */
|
||||
_nextRemoved: IterableChangeRecord_<V> = null;
|
||||
_nextRemoved: IterableChangeRecord_<V>|null = null;
|
||||
/** @internal */
|
||||
_nextAdded: IterableChangeRecord_<V> = null;
|
||||
_nextAdded: IterableChangeRecord_<V>|null = null;
|
||||
/** @internal */
|
||||
_nextMoved: IterableChangeRecord_<V> = null;
|
||||
_nextMoved: IterableChangeRecord_<V>|null = null;
|
||||
/** @internal */
|
||||
_nextIdentityChange: IterableChangeRecord_<V> = null;
|
||||
_nextIdentityChange: IterableChangeRecord_<V>|null = null;
|
||||
|
||||
|
||||
constructor(public item: V, public trackById: any) {}
|
||||
@ -635,9 +639,9 @@ export class IterableChangeRecord_<V> implements IterableChangeRecord<V> {
|
||||
// A linked list of CollectionChangeRecords with the same IterableChangeRecord_.item
|
||||
class _DuplicateItemRecordList<V> {
|
||||
/** @internal */
|
||||
_head: IterableChangeRecord_<V> = null;
|
||||
_head: IterableChangeRecord_<V>|null = null;
|
||||
/** @internal */
|
||||
_tail: IterableChangeRecord_<V> = null;
|
||||
_tail: IterableChangeRecord_<V>|null = null;
|
||||
|
||||
/**
|
||||
* Append the record to the list of duplicates.
|
||||
@ -653,7 +657,7 @@ class _DuplicateItemRecordList<V> {
|
||||
// todo(vicb)
|
||||
// assert(record.item == _head.item ||
|
||||
// record.item is num && record.item.isNaN && _head.item is num && _head.item.isNaN);
|
||||
this._tail._nextDup = record;
|
||||
this._tail !._nextDup = record;
|
||||
record._prevDup = this._tail;
|
||||
record._nextDup = null;
|
||||
this._tail = record;
|
||||
@ -662,8 +666,8 @@ class _DuplicateItemRecordList<V> {
|
||||
|
||||
// Returns a IterableChangeRecord_ having IterableChangeRecord_.trackById == trackById and
|
||||
// IterableChangeRecord_.currentIndex >= afterIndex
|
||||
get(trackById: any, afterIndex: number): IterableChangeRecord_<V> {
|
||||
let record: IterableChangeRecord_<V>;
|
||||
get(trackById: any, afterIndex: number|null): IterableChangeRecord_<V>|null {
|
||||
let record: IterableChangeRecord_<V>|null;
|
||||
for (record = this._head; record !== null; record = record._nextDup) {
|
||||
if ((afterIndex === null || afterIndex < record.currentIndex) &&
|
||||
looseIdentical(record.trackById, trackById)) {
|
||||
@ -688,8 +692,8 @@ class _DuplicateItemRecordList<V> {
|
||||
// return false;
|
||||
//});
|
||||
|
||||
const prev: IterableChangeRecord_<V> = record._prevDup;
|
||||
const next: IterableChangeRecord_<V> = record._nextDup;
|
||||
const prev: IterableChangeRecord_<V>|null = record._prevDup;
|
||||
const next: IterableChangeRecord_<V>|null = record._nextDup;
|
||||
if (prev === null) {
|
||||
this._head = next;
|
||||
} else {
|
||||
@ -725,7 +729,7 @@ class _DuplicateMap<V> {
|
||||
* Use case: `[a, b, c, a, a]` if we are at index `3` which is the second `a` then asking if we
|
||||
* have any more `a`s needs to return the last `a` not the first or second.
|
||||
*/
|
||||
get(trackById: any, afterIndex: number = null): IterableChangeRecord_<V> {
|
||||
get(trackById: any, afterIndex: number|null): IterableChangeRecord_<V>|null {
|
||||
const key = trackById;
|
||||
const recordList = this.map.get(key);
|
||||
return recordList ? recordList.get(trackById, afterIndex) : null;
|
||||
@ -738,7 +742,7 @@ class _DuplicateMap<V> {
|
||||
*/
|
||||
remove(record: IterableChangeRecord_<V>): IterableChangeRecord_<V> {
|
||||
const key = record.trackById;
|
||||
const recordList: _DuplicateItemRecordList<V> = this.map.get(key);
|
||||
const recordList: _DuplicateItemRecordList<V> = this.map.get(key) !;
|
||||
// Remove the list of duplicates when it gets empty
|
||||
if (recordList.remove(record)) {
|
||||
this.map.delete(key);
|
||||
@ -753,7 +757,8 @@ class _DuplicateMap<V> {
|
||||
toString(): string { return '_DuplicateMap(' + stringify(this.map) + ')'; }
|
||||
}
|
||||
|
||||
function getPreviousIndex(item: any, addRemoveOffset: number, moveOffsets: number[]): number {
|
||||
function getPreviousIndex(
|
||||
item: any, addRemoveOffset: number, moveOffsets: number[] | null): number {
|
||||
const previousIndex = item.previousIndex;
|
||||
if (previousIndex === null) return previousIndex;
|
||||
let moveOffset = 0;
|
||||
|
@ -9,7 +9,6 @@
|
||||
import {looseIdentical, stringify} from '../../util';
|
||||
import {isJsObject} from '../change_detection_util';
|
||||
import {ChangeDetectorRef} from '../change_detector_ref';
|
||||
|
||||
import {KeyValueChangeRecord, KeyValueChanges, KeyValueDiffer, KeyValueDifferFactory} from './keyvalue_differs';
|
||||
|
||||
|
||||
@ -28,15 +27,17 @@ export class DefaultKeyValueDifferFactory<K, V> implements KeyValueDifferFactory
|
||||
}
|
||||
|
||||
export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyValueChanges<K, V> {
|
||||
private _records: Map<K, V> = new Map<K, V>();
|
||||
private _mapHead: KeyValueChangeRecord_<K, V> = null;
|
||||
private _previousMapHead: KeyValueChangeRecord_<K, V> = null;
|
||||
private _changesHead: KeyValueChangeRecord_<K, V> = null;
|
||||
private _changesTail: KeyValueChangeRecord_<K, V> = null;
|
||||
private _additionsHead: KeyValueChangeRecord_<K, V> = null;
|
||||
private _additionsTail: KeyValueChangeRecord_<K, V> = null;
|
||||
private _removalsHead: KeyValueChangeRecord_<K, V> = null;
|
||||
private _removalsTail: KeyValueChangeRecord_<K, V> = null;
|
||||
private _records = new Map<K, KeyValueChangeRecord_<K, V>>();
|
||||
private _mapHead: KeyValueChangeRecord_<K, V>|null = null;
|
||||
// _appendAfter is used in the check loop
|
||||
private _appendAfter: KeyValueChangeRecord_<K, V>|null = null;
|
||||
private _previousMapHead: KeyValueChangeRecord_<K, V>|null = null;
|
||||
private _changesHead: KeyValueChangeRecord_<K, V>|null = null;
|
||||
private _changesTail: KeyValueChangeRecord_<K, V>|null = null;
|
||||
private _additionsHead: KeyValueChangeRecord_<K, V>|null = null;
|
||||
private _additionsTail: KeyValueChangeRecord_<K, V>|null = null;
|
||||
private _removalsHead: KeyValueChangeRecord_<K, V>|null = null;
|
||||
private _removalsTail: KeyValueChangeRecord_<K, V>|null = null;
|
||||
|
||||
get isDirty(): boolean {
|
||||
return this._additionsHead !== null || this._changesHead !== null ||
|
||||
@ -44,45 +45,46 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal
|
||||
}
|
||||
|
||||
forEachItem(fn: (r: KeyValueChangeRecord<K, V>) => void) {
|
||||
let record: KeyValueChangeRecord_<K, V>;
|
||||
let record: KeyValueChangeRecord_<K, V>|null;
|
||||
for (record = this._mapHead; record !== null; record = record._next) {
|
||||
fn(record);
|
||||
}
|
||||
}
|
||||
|
||||
forEachPreviousItem(fn: (r: KeyValueChangeRecord<K, V>) => void) {
|
||||
let record: KeyValueChangeRecord_<K, V>;
|
||||
let record: KeyValueChangeRecord_<K, V>|null;
|
||||
for (record = this._previousMapHead; record !== null; record = record._nextPrevious) {
|
||||
fn(record);
|
||||
}
|
||||
}
|
||||
|
||||
forEachChangedItem(fn: (r: KeyValueChangeRecord<K, V>) => void) {
|
||||
let record: KeyValueChangeRecord_<K, V>;
|
||||
let record: KeyValueChangeRecord_<K, V>|null;
|
||||
for (record = this._changesHead; record !== null; record = record._nextChanged) {
|
||||
fn(record);
|
||||
}
|
||||
}
|
||||
|
||||
forEachAddedItem(fn: (r: KeyValueChangeRecord<K, V>) => void) {
|
||||
let record: KeyValueChangeRecord_<K, V>;
|
||||
let record: KeyValueChangeRecord_<K, V>|null;
|
||||
for (record = this._additionsHead; record !== null; record = record._nextAdded) {
|
||||
fn(record);
|
||||
}
|
||||
}
|
||||
|
||||
forEachRemovedItem(fn: (r: KeyValueChangeRecord<K, V>) => void) {
|
||||
let record: KeyValueChangeRecord_<K, V>;
|
||||
let record: KeyValueChangeRecord_<K, V>|null;
|
||||
for (record = this._removalsHead; record !== null; record = record._nextRemoved) {
|
||||
fn(record);
|
||||
}
|
||||
}
|
||||
|
||||
diff(map: Map<any, any>|{[k: string]: any}): any {
|
||||
diff(map?: Map<any, any>|{[k: string]: any}|null): any {
|
||||
if (!map) {
|
||||
map = new Map();
|
||||
} else if (!(map instanceof Map || isJsObject(map))) {
|
||||
throw new Error(`Error trying to diff '${map}'`);
|
||||
throw new Error(
|
||||
`Error trying to diff '${stringify(map)}'. Only maps and objects are allowed`);
|
||||
}
|
||||
|
||||
return this.check(map) ? this : null;
|
||||
@ -90,67 +92,130 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal
|
||||
|
||||
onDestroy() {}
|
||||
|
||||
/**
|
||||
* Check the current state of the map vs the previous.
|
||||
* The algorithm is optimised for when the keys do no change.
|
||||
*/
|
||||
check(map: Map<any, any>|{[k: string]: any}): boolean {
|
||||
this._reset();
|
||||
const records = this._records;
|
||||
let oldSeqRecord: KeyValueChangeRecord_<K, V> = this._mapHead;
|
||||
let lastOldSeqRecord: KeyValueChangeRecord_<K, V> = null;
|
||||
let lastNewSeqRecord: KeyValueChangeRecord_<K, V> = null;
|
||||
let seqChanged: boolean = false;
|
||||
|
||||
let insertBefore = this._mapHead;
|
||||
this._appendAfter = null;
|
||||
|
||||
this._forEach(map, (value: any, key: any) => {
|
||||
let newSeqRecord: any;
|
||||
if (oldSeqRecord && key === oldSeqRecord.key) {
|
||||
newSeqRecord = oldSeqRecord;
|
||||
this._maybeAddToChanges(newSeqRecord, value);
|
||||
if (insertBefore && insertBefore.key === key) {
|
||||
this._maybeAddToChanges(insertBefore, value);
|
||||
this._appendAfter = insertBefore;
|
||||
insertBefore = insertBefore._next;
|
||||
} else {
|
||||
seqChanged = true;
|
||||
if (oldSeqRecord !== null) {
|
||||
this._removeFromSeq(lastOldSeqRecord, oldSeqRecord);
|
||||
this._addToRemovals(oldSeqRecord);
|
||||
}
|
||||
if (records.has(key)) {
|
||||
newSeqRecord = records.get(key);
|
||||
this._maybeAddToChanges(newSeqRecord, value);
|
||||
} else {
|
||||
newSeqRecord = new KeyValueChangeRecord_<K, V>(key);
|
||||
records.set(key, newSeqRecord);
|
||||
newSeqRecord.currentValue = value;
|
||||
this._addToAdditions(newSeqRecord);
|
||||
}
|
||||
const record = this._getOrCreateRecordForKey(key, value);
|
||||
insertBefore = this._insertBeforeOrAppend(insertBefore, record);
|
||||
}
|
||||
});
|
||||
|
||||
// Items remaining at the end of the list have been deleted
|
||||
if (insertBefore) {
|
||||
if (insertBefore._prev) {
|
||||
insertBefore._prev._next = null;
|
||||
}
|
||||
|
||||
if (seqChanged) {
|
||||
if (this._isInRemovals(newSeqRecord)) {
|
||||
this._removeFromRemovals(newSeqRecord);
|
||||
}
|
||||
if (lastNewSeqRecord == null) {
|
||||
this._mapHead = newSeqRecord;
|
||||
} else {
|
||||
lastNewSeqRecord._next = newSeqRecord;
|
||||
this._removalsHead = insertBefore;
|
||||
this._removalsTail = insertBefore;
|
||||
|
||||
for (let record = insertBefore; record !== null; record = record._nextRemoved) {
|
||||
if (record === this._mapHead) {
|
||||
this._mapHead = null;
|
||||
}
|
||||
this._records.delete(record.key);
|
||||
record._nextRemoved = record._next;
|
||||
record.previousValue = record.currentValue;
|
||||
record.currentValue = null;
|
||||
record._prev = null;
|
||||
record._next = null;
|
||||
}
|
||||
lastOldSeqRecord = oldSeqRecord;
|
||||
lastNewSeqRecord = newSeqRecord;
|
||||
oldSeqRecord = oldSeqRecord && oldSeqRecord._next;
|
||||
});
|
||||
this._truncate(lastOldSeqRecord, oldSeqRecord);
|
||||
}
|
||||
|
||||
return this.isDirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a record before `before` or append at the end of the list when `before` is null.
|
||||
*
|
||||
* Notes:
|
||||
* - This method appends at `this._appendAfter`,
|
||||
* - This method updates `this._appendAfter`,
|
||||
* - The return value is the new value for the insertion pointer.
|
||||
*/
|
||||
private _insertBeforeOrAppend(
|
||||
before: KeyValueChangeRecord_<K, V>,
|
||||
record: KeyValueChangeRecord_<K, V>): KeyValueChangeRecord_<K, V> {
|
||||
if (before) {
|
||||
const prev = before._prev;
|
||||
record._next = before;
|
||||
record._prev = prev;
|
||||
before._prev = record;
|
||||
if (prev) {
|
||||
prev._next = record;
|
||||
}
|
||||
if (before === this._mapHead) {
|
||||
this._mapHead = record;
|
||||
}
|
||||
|
||||
this._appendAfter = before;
|
||||
return before;
|
||||
}
|
||||
|
||||
if (this._appendAfter) {
|
||||
this._appendAfter._next = record;
|
||||
record._prev = this._appendAfter;
|
||||
} else {
|
||||
this._mapHead = record;
|
||||
}
|
||||
|
||||
this._appendAfter = record;
|
||||
return null;
|
||||
}
|
||||
|
||||
private _getOrCreateRecordForKey(key: K, value: V): KeyValueChangeRecord_<K, V> {
|
||||
if (this._records.has(key)) {
|
||||
const record = this._records.get(key);
|
||||
this._maybeAddToChanges(record, value);
|
||||
const prev = record._prev;
|
||||
const next = record._next;
|
||||
if (prev) {
|
||||
prev._next = next;
|
||||
}
|
||||
if (next) {
|
||||
next._prev = prev;
|
||||
}
|
||||
record._next = null;
|
||||
record._prev = null;
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
const record = new KeyValueChangeRecord_<K, V>(key);
|
||||
this._records.set(key, record);
|
||||
record.currentValue = value;
|
||||
this._addToAdditions(record);
|
||||
return record;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_reset() {
|
||||
if (this.isDirty) {
|
||||
let record: KeyValueChangeRecord_<K, V>;
|
||||
// Record the state of the mapping
|
||||
for (record = this._previousMapHead = this._mapHead; record !== null; record = record._next) {
|
||||
let record: KeyValueChangeRecord_<K, V>|null;
|
||||
// let `_previousMapHead` contain the state of the map before the changes
|
||||
this._previousMapHead = this._mapHead;
|
||||
for (record = this._previousMapHead; record !== null; record = record._next) {
|
||||
record._nextPrevious = record._next;
|
||||
}
|
||||
|
||||
// Update `record.previousValue` with the value of the item before the changes
|
||||
// We need to update all changed items (that's those which have been added and changed)
|
||||
for (record = this._changesHead; record !== null; record = record._nextChanged) {
|
||||
record.previousValue = record.currentValue;
|
||||
}
|
||||
|
||||
for (record = this._additionsHead; record != null; record = record._nextAdded) {
|
||||
record.previousValue = record.currentValue;
|
||||
}
|
||||
@ -161,27 +226,7 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal
|
||||
}
|
||||
}
|
||||
|
||||
private _truncate(lastRecord: KeyValueChangeRecord_<K, V>, record: KeyValueChangeRecord_<K, V>) {
|
||||
while (record !== null) {
|
||||
if (lastRecord === null) {
|
||||
this._mapHead = null;
|
||||
} else {
|
||||
lastRecord._next = null;
|
||||
}
|
||||
const nextRecord = record._next;
|
||||
this._addToRemovals(record);
|
||||
lastRecord = record;
|
||||
record = nextRecord;
|
||||
}
|
||||
|
||||
for (let rec: KeyValueChangeRecord_<K, V> = this._removalsHead; rec !== null;
|
||||
rec = rec._nextRemoved) {
|
||||
rec.previousValue = rec.currentValue;
|
||||
rec.currentValue = null;
|
||||
this._records.delete(rec.key);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the record or a given key to the list of changes only when the value has actually changed
|
||||
private _maybeAddToChanges(record: KeyValueChangeRecord_<K, V>, newValue: any): void {
|
||||
if (!looseIdentical(newValue, record.currentValue)) {
|
||||
record.previousValue = record.currentValue;
|
||||
@ -190,52 +235,11 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal
|
||||
}
|
||||
}
|
||||
|
||||
private _isInRemovals(record: KeyValueChangeRecord_<K, V>) {
|
||||
return record === this._removalsHead || record._nextRemoved !== null ||
|
||||
record._prevRemoved !== null;
|
||||
}
|
||||
|
||||
private _addToRemovals(record: KeyValueChangeRecord_<K, V>) {
|
||||
if (this._removalsHead === null) {
|
||||
this._removalsHead = this._removalsTail = record;
|
||||
} else {
|
||||
this._removalsTail._nextRemoved = record;
|
||||
record._prevRemoved = this._removalsTail;
|
||||
this._removalsTail = record;
|
||||
}
|
||||
}
|
||||
|
||||
private _removeFromSeq(prev: KeyValueChangeRecord_<K, V>, record: KeyValueChangeRecord_<K, V>) {
|
||||
const next = record._next;
|
||||
if (prev === null) {
|
||||
this._mapHead = next;
|
||||
} else {
|
||||
prev._next = next;
|
||||
}
|
||||
record._next = null;
|
||||
}
|
||||
|
||||
private _removeFromRemovals(record: KeyValueChangeRecord_<K, V>) {
|
||||
const prev = record._prevRemoved;
|
||||
const next = record._nextRemoved;
|
||||
if (prev === null) {
|
||||
this._removalsHead = next;
|
||||
} else {
|
||||
prev._nextRemoved = next;
|
||||
}
|
||||
if (next === null) {
|
||||
this._removalsTail = prev;
|
||||
} else {
|
||||
next._prevRemoved = prev;
|
||||
}
|
||||
record._prevRemoved = record._nextRemoved = null;
|
||||
}
|
||||
|
||||
private _addToAdditions(record: KeyValueChangeRecord_<K, V>) {
|
||||
if (this._additionsHead === null) {
|
||||
this._additionsHead = this._additionsTail = record;
|
||||
} else {
|
||||
this._additionsTail._nextAdded = record;
|
||||
this._additionsTail !._nextAdded = record;
|
||||
this._additionsTail = record;
|
||||
}
|
||||
}
|
||||
@ -244,7 +248,7 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal
|
||||
if (this._changesHead === null) {
|
||||
this._changesHead = this._changesTail = record;
|
||||
} else {
|
||||
this._changesTail._nextChanged = record;
|
||||
this._changesTail !._nextChanged = record;
|
||||
this._changesTail = record;
|
||||
}
|
||||
}
|
||||
@ -255,7 +259,7 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal
|
||||
const changes: any[] = [];
|
||||
const additions: any[] = [];
|
||||
const removals: any[] = [];
|
||||
let record: KeyValueChangeRecord_<K, V>;
|
||||
let record: KeyValueChangeRecord_<K, V>|null;
|
||||
|
||||
for (record = this._mapHead; record !== null; record = record._next) {
|
||||
items.push(stringify(record));
|
||||
@ -295,21 +299,21 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal
|
||||
* @stable
|
||||
*/
|
||||
class KeyValueChangeRecord_<K, V> implements KeyValueChangeRecord<K, V> {
|
||||
previousValue: V = null;
|
||||
currentValue: V = null;
|
||||
previousValue: V|null = null;
|
||||
currentValue: V|null = null;
|
||||
|
||||
/** @internal */
|
||||
_nextPrevious: KeyValueChangeRecord_<K, V> = null;
|
||||
_nextPrevious: KeyValueChangeRecord_<K, V>|null = null;
|
||||
/** @internal */
|
||||
_next: KeyValueChangeRecord_<K, V> = null;
|
||||
_next: KeyValueChangeRecord_<K, V>|null = null;
|
||||
/** @internal */
|
||||
_nextAdded: KeyValueChangeRecord_<K, V> = null;
|
||||
_prev: KeyValueChangeRecord_<K, V>|null = null;
|
||||
/** @internal */
|
||||
_nextRemoved: KeyValueChangeRecord_<K, V> = null;
|
||||
_nextAdded: KeyValueChangeRecord_<K, V>|null = null;
|
||||
/** @internal */
|
||||
_prevRemoved: KeyValueChangeRecord_<K, V> = null;
|
||||
_nextRemoved: KeyValueChangeRecord_<K, V>|null = null;
|
||||
/** @internal */
|
||||
_nextChanged: KeyValueChangeRecord_<K, V> = null;
|
||||
_nextChanged: KeyValueChangeRecord_<K, V>|null = null;
|
||||
|
||||
constructor(public key: K) {}
|
||||
|
||||
|
@ -30,7 +30,7 @@ export interface IterableDiffer<V> {
|
||||
* @returns an object describing the difference. The return value is only valid until the next
|
||||
* `diff()` invocation.
|
||||
*/
|
||||
diff(object: NgIterable<V>): IterableChanges<V>;
|
||||
diff(object: NgIterable<V>): IterableChanges<V>|null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -92,20 +92,16 @@ export interface IterableChanges<V> {
|
||||
*/
|
||||
export interface IterableChangeRecord<V> {
|
||||
/** Current index of the item in `Iterable` or null if removed. */
|
||||
// TODO(TS2.1): make readonly once we move to TS v2.1
|
||||
/* readonly */ currentIndex: number;
|
||||
readonly currentIndex: number|null;
|
||||
|
||||
/** Previous index of the item in `Iterable` or null if added. */
|
||||
// TODO(TS2.1): make readonly once we move to TS v2.1
|
||||
/* readonly */ previousIndex: number;
|
||||
readonly previousIndex: number|null;
|
||||
|
||||
/** The item. */
|
||||
// TODO(TS2.1): make readonly once we move to TS v2.1
|
||||
/* readonly */ item: V;
|
||||
readonly item: V;
|
||||
|
||||
/** Track by identity as computed by the `trackByFn`. */
|
||||
// TODO(TS2.1): make readonly once we move to TS v2.1
|
||||
/* readonly */ trackById: any;
|
||||
readonly trackById: any;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,17 +82,17 @@ export interface KeyValueChangeRecord<K, V> {
|
||||
/**
|
||||
* Current key in the Map.
|
||||
*/
|
||||
/* readonly */ key: K;
|
||||
readonly key: K;
|
||||
|
||||
/**
|
||||
* Current value for the key or `undefined` if removed.
|
||||
* Current value for the key or `null` if removed.
|
||||
*/
|
||||
/* readonly */ currentValue: V;
|
||||
readonly currentValue: V|null;
|
||||
|
||||
/**
|
||||
* Previous value for the key or `undefined` if added.
|
||||
* Previous value for the key or `null` if added.
|
||||
*/
|
||||
/* readonly */ previousValue: V;
|
||||
readonly previousValue: V|null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,5 +25,5 @@ export {GetterFn as ɵGetterFn, MethodFn as ɵMethodFn, SetterFn as ɵSetterFn}
|
||||
export {DirectRenderer as ɵDirectRenderer, RenderDebugInfo as ɵRenderDebugInfo} from './render/api';
|
||||
export {global as ɵglobal, looseIdentical as ɵlooseIdentical, stringify as ɵstringify} from './util';
|
||||
export {makeDecorator as ɵmakeDecorator} from './util/decorators';
|
||||
export {isObservable as ɵisObservable, isPromise as ɵisPromise, merge as ɵmerge} from './util/lang';
|
||||
export {isObservable as ɵisObservable, isPromise as ɵisPromise} from './util/lang';
|
||||
export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider';
|
||||
|
@ -17,9 +17,9 @@ export class EventListener { constructor(public name: string, public callback: F
|
||||
export class DebugNode {
|
||||
nativeNode: any;
|
||||
listeners: EventListener[];
|
||||
parent: DebugElement;
|
||||
parent: DebugElement|null;
|
||||
|
||||
constructor(nativeNode: any, parent: DebugNode, private _debugContext: DebugContext) {
|
||||
constructor(nativeNode: any, parent: DebugNode|null, private _debugContext: DebugContext) {
|
||||
this.nativeNode = nativeNode;
|
||||
if (parent && parent instanceof DebugElement) {
|
||||
parent.addChild(this);
|
||||
@ -29,19 +29,15 @@ export class DebugNode {
|
||||
this.listeners = [];
|
||||
}
|
||||
|
||||
get injector(): Injector { return this._debugContext ? this._debugContext.injector : null; }
|
||||
get injector(): Injector { return this._debugContext.injector; }
|
||||
|
||||
get componentInstance(): any { return this._debugContext ? this._debugContext.component : null; }
|
||||
get componentInstance(): any { return this._debugContext.component; }
|
||||
|
||||
get context(): any { return this._debugContext ? this._debugContext.context : null; }
|
||||
get context(): any { return this._debugContext.context; }
|
||||
|
||||
get references(): {[key: string]: any} {
|
||||
return this._debugContext ? this._debugContext.references : null;
|
||||
}
|
||||
get references(): {[key: string]: any} { return this._debugContext.references; }
|
||||
|
||||
get providerTokens(): any[] {
|
||||
return this._debugContext ? this._debugContext.providerTokens : null;
|
||||
}
|
||||
get providerTokens(): any[] { return this._debugContext.providerTokens; }
|
||||
|
||||
/**
|
||||
* @deprecated since v4
|
||||
@ -55,9 +51,9 @@ export class DebugNode {
|
||||
export class DebugElement extends DebugNode {
|
||||
name: string;
|
||||
properties: {[key: string]: any};
|
||||
attributes: {[key: string]: string};
|
||||
attributes: {[key: string]: string | null};
|
||||
classes: {[key: string]: boolean};
|
||||
styles: {[key: string]: string};
|
||||
styles: {[key: string]: string | null};
|
||||
childNodes: DebugNode[];
|
||||
nativeElement: any;
|
||||
|
||||
@ -181,8 +177,8 @@ const _nativeNodeToDebugNode = new Map<any, DebugNode>();
|
||||
/**
|
||||
* @experimental
|
||||
*/
|
||||
export function getDebugNode(nativeNode: any): DebugNode {
|
||||
return _nativeNodeToDebugNode.get(nativeNode);
|
||||
export function getDebugNode(nativeNode: any): DebugNode|null {
|
||||
return _nativeNodeToDebugNode.get(nativeNode) || null;
|
||||
}
|
||||
|
||||
export function getAllDebugNodes(): DebugNode[] {
|
||||
@ -203,4 +199,4 @@ export function removeDebugNodeFromIndex(node: DebugNode) {
|
||||
*
|
||||
* @experimental All debugging apis are currently experimental.
|
||||
*/
|
||||
export interface Predicate<T> { (value: T, index?: number, array?: T[]): boolean; }
|
||||
export interface Predicate<T> { (value: T): boolean; }
|
||||
|
@ -42,8 +42,8 @@ export class OpaqueToken {
|
||||
* runtime representation) such as when injecting an interface, callable type, array or
|
||||
* parametrized type.
|
||||
*
|
||||
* `InjectionToken` is parametrize on `T` which is the type of object which will be returned by the
|
||||
* `Injector`. This provides additional level of type safety.
|
||||
* `InjectionToken` is parameterized on `T` which is the type of object which will be returned by
|
||||
* the `Injector`. This provides additional level of type safety.
|
||||
*
|
||||
* ```
|
||||
* interface MyInterface {...}
|
||||
@ -53,7 +53,7 @@ export class OpaqueToken {
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* {@example core/di/ts/injector_spec.ts region='Injector'}
|
||||
* {@example core/di/ts/injector_spec.ts region='InjectionToken'}
|
||||
*
|
||||
* @stable
|
||||
*/
|
||||
|
@ -56,7 +56,7 @@ export abstract class Injector {
|
||||
*/
|
||||
abstract get<T>(token: Type<T>|InjectionToken<T>, notFoundValue?: T): T;
|
||||
/**
|
||||
* @deprecated from v4.0.0 use Type<T> or InjectToken<T>
|
||||
* @deprecated from v4.0.0 use Type<T> or InjectionToken<T>
|
||||
* @suppress {duplicate}
|
||||
*/
|
||||
abstract get(token: any, notFoundValue?: any): any;
|
||||
|
@ -115,7 +115,7 @@ export abstract class ReflectiveInjector implements Injector {
|
||||
* because it needs to resolve the passed-in providers first.
|
||||
* See {@link Injector#resolve} and {@link Injector#fromResolvedProviders}.
|
||||
*/
|
||||
static resolveAndCreate(providers: Provider[], parent: Injector = null): ReflectiveInjector {
|
||||
static resolveAndCreate(providers: Provider[], parent?: Injector): ReflectiveInjector {
|
||||
const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
|
||||
return ReflectiveInjector.fromResolvedProviders(ResolvedReflectiveProviders, parent);
|
||||
}
|
||||
@ -143,7 +143,7 @@ export abstract class ReflectiveInjector implements Injector {
|
||||
* ```
|
||||
* @experimental
|
||||
*/
|
||||
static fromResolvedProviders(providers: ResolvedReflectiveProvider[], parent: Injector = null):
|
||||
static fromResolvedProviders(providers: ResolvedReflectiveProvider[], parent?: Injector):
|
||||
ReflectiveInjector {
|
||||
return new ReflectiveInjector_(providers, parent);
|
||||
}
|
||||
@ -163,7 +163,7 @@ export abstract class ReflectiveInjector implements Injector {
|
||||
* expect(child.parent).toBe(parent);
|
||||
* ```
|
||||
*/
|
||||
abstract get parent(): Injector;
|
||||
abstract get parent(): Injector|null;
|
||||
|
||||
/**
|
||||
* Resolves an array of providers and creates a child injector from those providers.
|
||||
@ -282,16 +282,16 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
|
||||
/** @internal */
|
||||
public _providers: ResolvedReflectiveProvider[];
|
||||
/** @internal */
|
||||
public _parent: Injector;
|
||||
public _parent: Injector|null;
|
||||
|
||||
keyIds: number[];
|
||||
objs: any[];
|
||||
/**
|
||||
* Private
|
||||
*/
|
||||
constructor(_providers: ResolvedReflectiveProvider[], _parent: Injector = null) {
|
||||
constructor(_providers: ResolvedReflectiveProvider[], _parent?: Injector) {
|
||||
this._providers = _providers;
|
||||
this._parent = _parent;
|
||||
this._parent = _parent || null;
|
||||
|
||||
const len = _providers.length;
|
||||
|
||||
@ -308,7 +308,7 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
|
||||
return this._getByKey(ReflectiveKey.get(token), null, notFoundValue);
|
||||
}
|
||||
|
||||
get parent(): Injector { return this._parent; }
|
||||
get parent(): Injector|null { return this._parent; }
|
||||
|
||||
resolveAndCreateChild(providers: Provider[]): ReflectiveInjector {
|
||||
const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
|
||||
@ -388,7 +388,7 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
|
||||
return this._getByKey(dep.key, dep.visibility, dep.optional ? null : THROW_IF_NOT_FOUND);
|
||||
}
|
||||
|
||||
private _getByKey(key: ReflectiveKey, visibility: Self|SkipSelf, notFoundValue: any): any {
|
||||
private _getByKey(key: ReflectiveKey, visibility: Self|SkipSelf|null, notFoundValue: any): any {
|
||||
if (key === INJECTOR_KEY) {
|
||||
return this;
|
||||
}
|
||||
@ -431,8 +431,8 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_getByKeyDefault(key: ReflectiveKey, notFoundValue: any, visibility: Self|SkipSelf): any {
|
||||
let inj: Injector;
|
||||
_getByKeyDefault(key: ReflectiveKey, notFoundValue: any, visibility: Self|SkipSelf|null): any {
|
||||
let inj: Injector|null;
|
||||
|
||||
if (visibility instanceof SkipSelf) {
|
||||
inj = this._parent;
|
||||
|
@ -64,7 +64,7 @@ export class KeyRegistry {
|
||||
if (token instanceof ReflectiveKey) return token;
|
||||
|
||||
if (this._allKeys.has(token)) {
|
||||
return this._allKeys.get(token);
|
||||
return this._allKeys.get(token) !;
|
||||
}
|
||||
|
||||
const newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys);
|
||||
|
@ -26,7 +26,7 @@ interface NormalizedProvider extends TypeProvider, ValueProvider, ClassProvider,
|
||||
*/
|
||||
export class ReflectiveDependency {
|
||||
constructor(
|
||||
public key: ReflectiveKey, public optional: boolean, public visibility: Self|SkipSelf) {}
|
||||
public key: ReflectiveKey, public optional: boolean, public visibility: Self|SkipSelf|null) {}
|
||||
|
||||
static fromKey(key: ReflectiveKey): ReflectiveDependency {
|
||||
return new ReflectiveDependency(key, false, null);
|
||||
@ -128,7 +128,8 @@ function resolveReflectiveFactory(provider: NormalizedProvider): ResolvedReflect
|
||||
*/
|
||||
function resolveReflectiveProvider(provider: NormalizedProvider): ResolvedReflectiveProvider {
|
||||
return new ResolvedReflectiveProvider_(
|
||||
ReflectiveKey.get(provider.provide), [resolveReflectiveFactory(provider)], provider.multi);
|
||||
ReflectiveKey.get(provider.provide), [resolveReflectiveFactory(provider)],
|
||||
provider.multi || false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -198,7 +199,7 @@ function _normalizeProviders(providers: Provider[], res: Provider[]): Provider[]
|
||||
}
|
||||
|
||||
export function constructDependencies(
|
||||
typeOrFunc: any, dependencies: any[]): ReflectiveDependency[] {
|
||||
typeOrFunc: any, dependencies?: any[]): ReflectiveDependency[] {
|
||||
if (!dependencies) {
|
||||
return _dependenciesFor(typeOrFunc);
|
||||
} else {
|
||||
@ -230,7 +231,7 @@ function _extractToken(
|
||||
}
|
||||
}
|
||||
|
||||
let visibility: Self|SkipSelf = null;
|
||||
let visibility: Self|SkipSelf|null = null;
|
||||
|
||||
for (let i = 0; i < metadata.length; ++i) {
|
||||
const paramMetadata = metadata[i];
|
||||
@ -261,6 +262,6 @@ function _extractToken(
|
||||
}
|
||||
|
||||
function _createDependency(
|
||||
token: any, optional: boolean, visibility: Self | SkipSelf): ReflectiveDependency {
|
||||
token: any, optional: boolean, visibility: Self | SkipSelf | null): ReflectiveDependency {
|
||||
return new ReflectiveDependency(ReflectiveKey.get(token), optional, visibility);
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ export class CodegenComponentFactoryResolver implements ComponentFactoryResolver
|
||||
resolveComponentFactory<T>(component: {new (...args: any[]): T}): ComponentFactory<T> {
|
||||
let factory = this._factories.get(component) || this._parent.resolveComponentFactory(component);
|
||||
|
||||
return factory ? new ComponentFactoryBoundToModule(factory, this._ngModule) : null;
|
||||
return new ComponentFactoryBoundToModule(factory, this._ngModule);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ export class NgModuleFactory<T> {
|
||||
|
||||
get moduleType(): Type<T> { return this._moduleType; }
|
||||
|
||||
create(parentInjector: Injector): NgModuleRef<T> {
|
||||
create(parentInjector: Injector|null): NgModuleRef<T> {
|
||||
const instance = new this._injectorClass(parentInjector || Injector.NULL);
|
||||
instance.create();
|
||||
return instance;
|
||||
|
@ -63,7 +63,9 @@ export class QueryList<T>/* implements Iterable<T> */ {
|
||||
* See
|
||||
* [Array.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find)
|
||||
*/
|
||||
find(fn: (item: T, index: number, array: T[]) => boolean): T { return this._results.find(fn); }
|
||||
find(fn: (item: T, index: number, array: T[]) => boolean): T|undefined {
|
||||
return this._results.find(fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* See
|
||||
|
@ -51,7 +51,7 @@ export abstract class ViewContainerRef {
|
||||
/**
|
||||
* Returns the {@link ViewRef} for the View located in this container at the specified index.
|
||||
*/
|
||||
abstract get(index: number): ViewRef;
|
||||
abstract get(index: number): ViewRef|null;
|
||||
|
||||
/**
|
||||
* Returns the number of Views currently attached to this container.
|
||||
@ -120,5 +120,5 @@ export abstract class ViewContainerRef {
|
||||
*
|
||||
* If the `index` param is omitted, the last {@link ViewRef} is detached.
|
||||
*/
|
||||
abstract detach(index?: number): ViewRef;
|
||||
abstract detach(index?: number): ViewRef|null;
|
||||
}
|
||||
|
@ -639,7 +639,7 @@ export interface Component extends Directive {
|
||||
* ### DSL Animation Functions
|
||||
*
|
||||
* Please visit each of the animation DSL functions listed below to gain a better understanding
|
||||
* of how and why they are used for crafting animations in Angular2:
|
||||
* of how and why they are used for crafting animations in Angular:
|
||||
*
|
||||
* - {@link trigger trigger()}
|
||||
* - {@link state state()}
|
||||
|
@ -62,19 +62,19 @@ export enum ViewEncapsulation {
|
||||
*/
|
||||
export class ViewMetadata {
|
||||
/** {@link Component.templateUrl} */
|
||||
templateUrl: string;
|
||||
templateUrl: string|undefined;
|
||||
/** {@link Component.template} */
|
||||
template: string;
|
||||
template: string|undefined;
|
||||
/** {@link Component.stylesUrl} */
|
||||
styleUrls: string[];
|
||||
styleUrls: string[]|undefined;
|
||||
/** {@link Component.styles} */
|
||||
styles: string[];
|
||||
styles: string[]|undefined;
|
||||
/** {@link Component.encapsulation} */
|
||||
encapsulation: ViewEncapsulation;
|
||||
encapsulation: ViewEncapsulation|undefined;
|
||||
/** {@link Component.animation} */
|
||||
animations: any[];
|
||||
animations: any[]|undefined;
|
||||
/** {@link Component.interpolation} */
|
||||
interpolation: [string, string];
|
||||
interpolation: [string, string]|undefined;
|
||||
|
||||
constructor(
|
||||
{templateUrl, template, encapsulation, styles, styleUrls, animations, interpolation}: {
|
||||
|
@ -53,7 +53,9 @@ export function createScope(signature: string, flags: any = null): any {
|
||||
return events.createScope(signature, flags);
|
||||
}
|
||||
|
||||
export function leave<T>(scope: Scope, returnValue?: T): T {
|
||||
export function leave<T>(scope: Scope): void;
|
||||
export function leave<T>(scope: Scope, returnValue?: T): T;
|
||||
export function leave<T>(scope: Scope, returnValue?: any): any {
|
||||
trace.leaveScope(scope, returnValue);
|
||||
return returnValue;
|
||||
}
|
||||
|
@ -21,6 +21,6 @@ export interface PlatformReflectionCapabilities {
|
||||
method(name: string): MethodFn;
|
||||
importUri(type: Type<any>): string;
|
||||
resourceUri(type: Type<any>): string;
|
||||
resolveIdentifier(name: string, moduleUrl: string, members: string[], runtime: any): any;
|
||||
resolveIdentifier(name: string, moduleUrl: string, members: string[]|null, runtime: any): any;
|
||||
resolveEnum(enumIdentifier: any, name: string): any;
|
||||
}
|
||||
|
@ -14,8 +14,7 @@ import {GetterFn, MethodFn, SetterFn} from './types';
|
||||
/**
|
||||
* Attention: This regex has to hold even if the code is minified!
|
||||
*/
|
||||
export const DELEGATE_CTOR =
|
||||
/^function\s+\S+\(\)\s*{\s*("use strict";)?\s*(return\s+)?(\S+\s+!==\s+null\s+&&\s+)?\S+\.apply\(this,\s*arguments\)/;
|
||||
export const DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*arguments\)/;
|
||||
|
||||
export class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||
private _reflect: any;
|
||||
@ -54,7 +53,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||
return result;
|
||||
}
|
||||
|
||||
private _ownParameters(type: Type<any>, parentCtor: any): any[][] {
|
||||
private _ownParameters(type: Type<any>, parentCtor: any): any[][]|null {
|
||||
// If we have no decorators, we only have function.length as metadata.
|
||||
// In that case, to detect whether a child class declared an own constructor or not,
|
||||
// we need to look inside of that constructor to check whether it is
|
||||
@ -115,7 +114,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||
return parameters || [];
|
||||
}
|
||||
|
||||
private _ownAnnotations(typeOrFunc: Type<any>, parentCtor: any): any[] {
|
||||
private _ownAnnotations(typeOrFunc: Type<any>, parentCtor: any): any[]|null {
|
||||
// Prefer the direct API.
|
||||
if ((<any>typeOrFunc).annotations && (<any>typeOrFunc).annotations !== parentCtor.annotations) {
|
||||
let annotations = (<any>typeOrFunc).annotations;
|
||||
@ -134,6 +133,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||
if (this._reflect && this._reflect.getOwnMetadata) {
|
||||
return this._reflect.getOwnMetadata('annotations', typeOrFunc);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
annotations(typeOrFunc: Type<any>): any[] {
|
||||
@ -146,7 +146,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||
return parentAnnotations.concat(ownAnnotations);
|
||||
}
|
||||
|
||||
private _ownPropMetadata(typeOrFunc: any, parentCtor: any): {[key: string]: any[]} {
|
||||
private _ownPropMetadata(typeOrFunc: any, parentCtor: any): {[key: string]: any[]}|null {
|
||||
// Prefer the direct API.
|
||||
if ((<any>typeOrFunc).propMetadata &&
|
||||
(<any>typeOrFunc).propMetadata !== parentCtor.propMetadata) {
|
||||
@ -172,6 +172,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||
if (this._reflect && this._reflect.getOwnMetadata) {
|
||||
return this._reflect.getOwnMetadata('propMetadata', typeOrFunc);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
propMetadata(typeOrFunc: any): {[key: string]: any[]} {
|
||||
|
@ -51,7 +51,7 @@ export class Reflector extends ReflectorReader {
|
||||
|
||||
resourceUri(type: any): string { return this.reflectionCapabilities.resourceUri(type); }
|
||||
|
||||
resolveIdentifier(name: string, moduleUrl: string, members: string[], runtime: any): any {
|
||||
resolveIdentifier(name: string, moduleUrl: string, members: string[]|null, runtime: any): any {
|
||||
return this.reflectionCapabilities.resolveIdentifier(name, moduleUrl, members, runtime);
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ export abstract class ReflectorReader {
|
||||
abstract parameters(typeOrFunc: /*Type*/ any): any[][];
|
||||
abstract annotations(typeOrFunc: /*Type*/ any): any[];
|
||||
abstract propMetadata(typeOrFunc: /*Type*/ any): {[key: string]: any[]};
|
||||
abstract importUri(typeOrFunc: /*Type*/ any): string;
|
||||
abstract importUri(typeOrFunc: /*Type*/ any): string|null;
|
||||
abstract resourceUri(typeOrFunc: /*Type*/ any): string;
|
||||
abstract resolveIdentifier(name: string, moduleUrl: string, members: string[], runtime: any): any;
|
||||
abstract resolveEnum(identifier: any, name: string): any;
|
||||
|
@ -126,7 +126,7 @@ export interface RendererType2 {
|
||||
* @experimental
|
||||
*/
|
||||
export abstract class RendererFactory2 {
|
||||
abstract createRenderer(hostElement: any, type: RendererType2): Renderer2;
|
||||
abstract createRenderer(hostElement: any, type: RendererType2|null): Renderer2;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -148,7 +148,7 @@ export abstract class Renderer2 {
|
||||
abstract get data(): {[key: string]: any};
|
||||
|
||||
abstract destroy(): void;
|
||||
abstract createElement(name: string, namespace?: string): any;
|
||||
abstract createElement(name: string, namespace?: string|null): any;
|
||||
abstract createComment(value: string): any;
|
||||
abstract createText(value: string): any;
|
||||
/**
|
||||
@ -156,7 +156,7 @@ export abstract class Renderer2 {
|
||||
* in which case the view engine won't call it.
|
||||
* This is used as a performance optimization for production mode.
|
||||
*/
|
||||
destroyNode: (node: any) => void | null;
|
||||
destroyNode: ((node: any) => void)|null;
|
||||
abstract appendChild(parent: any, newChild: any): void;
|
||||
abstract insertBefore(parent: any, newChild: any, refChild: any): void;
|
||||
abstract removeChild(parent: any, oldChild: any): void;
|
||||
@ -173,8 +173,8 @@ export abstract class Renderer2 {
|
||||
* the caller can't rely on checking whether this is null or not.
|
||||
*/
|
||||
abstract nextSibling(node: any): any;
|
||||
abstract setAttribute(el: any, name: string, value: string, namespace?: string): void;
|
||||
abstract removeAttribute(el: any, name: string, namespace?: string): void;
|
||||
abstract setAttribute(el: any, name: string, value: string, namespace?: string|null): void;
|
||||
abstract removeAttribute(el: any, name: string, namespace?: string|null): void;
|
||||
abstract addClass(el: any, name: string): void;
|
||||
abstract removeClass(el: any, name: string): void;
|
||||
abstract setStyle(el: any, style: string, value: any, flags?: RendererStyleFlags2): void;
|
||||
|
@ -92,7 +92,7 @@ export class Testability implements PublicTestability {
|
||||
// Schedules the call backs in a new frame so that it is always async.
|
||||
scheduleMicroTask(() => {
|
||||
while (this._callbacks.length !== 0) {
|
||||
(this._callbacks.pop())(this._didWork);
|
||||
(this._callbacks.pop() !)(this._didWork);
|
||||
}
|
||||
this._didWork = false;
|
||||
});
|
||||
@ -136,13 +136,13 @@ export class TestabilityRegistry {
|
||||
this._applications.set(token, testability);
|
||||
}
|
||||
|
||||
getTestability(elem: any): Testability { return this._applications.get(elem); }
|
||||
getTestability(elem: any): Testability|null { return this._applications.get(elem) || null; }
|
||||
|
||||
getAllTestabilities(): Testability[] { return Array.from(this._applications.values()); }
|
||||
|
||||
getAllRootElements(): any[] { return Array.from(this._applications.keys()); }
|
||||
|
||||
findTestabilityInTree(elem: Node, findInAncestors: boolean = true): Testability {
|
||||
findTestabilityInTree(elem: Node, findInAncestors: boolean = true): Testability|null {
|
||||
return _testabilityGetter.findTestabilityInTree(this, elem, findInAncestors);
|
||||
}
|
||||
}
|
||||
@ -157,13 +157,13 @@ export class TestabilityRegistry {
|
||||
export interface GetTestability {
|
||||
addToWindow(registry: TestabilityRegistry): void;
|
||||
findTestabilityInTree(registry: TestabilityRegistry, elem: any, findInAncestors: boolean):
|
||||
Testability;
|
||||
Testability|null;
|
||||
}
|
||||
|
||||
class _NoopGetTestability implements GetTestability {
|
||||
addToWindow(registry: TestabilityRegistry): void {}
|
||||
findTestabilityInTree(registry: TestabilityRegistry, elem: any, findInAncestors: boolean):
|
||||
Testability {
|
||||
Testability|null {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ function extractAnnotation(annotation: any): any {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
function applyParams(fnOrArray: (Function | any[]), key: string): Function {
|
||||
function applyParams(fnOrArray: Function | any[] | undefined, key: string): Function {
|
||||
if (fnOrArray === Object || fnOrArray === String || fnOrArray === Function ||
|
||||
fnOrArray === Number || fnOrArray === Array) {
|
||||
throw new Error(`Can not use native ${stringify(fnOrArray)} as constructor`);
|
||||
@ -107,7 +107,7 @@ function applyParams(fnOrArray: (Function | any[]), key: string): Function {
|
||||
}
|
||||
|
||||
if (Array.isArray(fnOrArray)) {
|
||||
const annotations: any[] = fnOrArray;
|
||||
const annotations: any[] = fnOrArray as any[];
|
||||
const annoLength = annotations.length - 1;
|
||||
const fn: Function = fnOrArray[annoLength];
|
||||
if (typeof fn !== 'function') {
|
||||
@ -263,7 +263,7 @@ export function Class(clsDef: ClassDefinition): Type<any> {
|
||||
*/
|
||||
export function makeDecorator(
|
||||
name: string, props: {[name: string]: any}, parentClass?: any,
|
||||
chainFn: (fn: Function) => void = null): (...args: any[]) => (cls: any) => any {
|
||||
chainFn?: (fn: Function) => void): (...args: any[]) => (cls: any) => any {
|
||||
const metaCtor = makeMetadataCtor([props]);
|
||||
|
||||
function DecoratorFactory(objOrType: any): (cls: any) => any {
|
||||
@ -332,7 +332,7 @@ export function makeParamDecorator(
|
||||
return ParamDecorator;
|
||||
|
||||
function ParamDecorator(cls: any, unusedKey: any, index: number): any {
|
||||
const parameters: any[][] = Reflect.getOwnMetadata('parameters', cls) || [];
|
||||
const parameters: (any[] | null)[] = Reflect.getOwnMetadata('parameters', cls) || [];
|
||||
|
||||
// there might be gaps if some in between parameters do not have annotations.
|
||||
// we pad with nulls.
|
||||
@ -341,7 +341,7 @@ export function makeParamDecorator(
|
||||
}
|
||||
|
||||
parameters[index] = parameters[index] || [];
|
||||
parameters[index].push(annotationInstance);
|
||||
parameters[index] !.push(annotationInstance);
|
||||
|
||||
Reflect.defineMetadata('parameters', parameters, cls);
|
||||
return cls;
|
||||
|
@ -24,18 +24,3 @@ export function isObservable(obj: any | Observable<any>): obj is Observable<any>
|
||||
// TODO use Symbol.observable when https://github.com/ReactiveX/rxjs/issues/2415 will be resolved
|
||||
return !!obj && typeof obj.subscribe === 'function';
|
||||
}
|
||||
|
||||
// TODO(misko): replace with Object.assign once we require ES6.
|
||||
export function merge<V>(m1: {[key: string]: V}, m2: {[key: string]: V}): {[key: string]: V} {
|
||||
const m: {[key: string]: V} = {};
|
||||
|
||||
for (const k of Object.keys(m1)) {
|
||||
m[k] = m1[k];
|
||||
}
|
||||
|
||||
for (const k of Object.keys(m2)) {
|
||||
m[k] = m2[k];
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
@ -16,20 +16,17 @@ export function anchorDef(
|
||||
flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][],
|
||||
ngContentIndex: number, childCount: number, handleEvent?: ElementHandleEventFn,
|
||||
templateFactory?: ViewDefinitionFactory): NodeDef {
|
||||
if (!handleEvent) {
|
||||
handleEvent = NOOP;
|
||||
}
|
||||
flags |= NodeFlags.TypeElement;
|
||||
const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl);
|
||||
const template = templateFactory ? resolveViewDefinition(templateFactory) : null;
|
||||
|
||||
return {
|
||||
// will bet set by the view definition
|
||||
index: undefined,
|
||||
parent: undefined,
|
||||
renderParent: undefined,
|
||||
bindingIndex: undefined,
|
||||
outputIndex: undefined,
|
||||
index: -1,
|
||||
parent: null,
|
||||
renderParent: null,
|
||||
bindingIndex: -1,
|
||||
outputIndex: -1,
|
||||
// regular values
|
||||
flags,
|
||||
childFlags: 0,
|
||||
@ -39,19 +36,20 @@ export function anchorDef(
|
||||
bindingFlags: 0,
|
||||
outputs: [],
|
||||
element: {
|
||||
ns: undefined,
|
||||
name: undefined,
|
||||
attrs: undefined, template,
|
||||
componentProvider: undefined,
|
||||
componentView: undefined,
|
||||
componentRendererType: undefined,
|
||||
publicProviders: undefined,
|
||||
allProviders: undefined, handleEvent
|
||||
ns: null,
|
||||
name: null,
|
||||
attrs: null, template,
|
||||
componentProvider: null,
|
||||
componentView: null,
|
||||
componentRendererType: null,
|
||||
publicProviders: null,
|
||||
allProviders: null,
|
||||
handleEvent: handleEvent || NOOP
|
||||
},
|
||||
provider: undefined,
|
||||
text: undefined,
|
||||
query: undefined,
|
||||
ngContent: undefined
|
||||
provider: null,
|
||||
text: null,
|
||||
query: null,
|
||||
ngContent: null
|
||||
};
|
||||
}
|
||||
|
||||
@ -61,13 +59,13 @@ export function elementDef(
|
||||
fixedAttrs: [string, string][] = [],
|
||||
bindings?: [BindingFlags, string, string | SecurityContext][], outputs?: ([string, string])[],
|
||||
handleEvent?: ElementHandleEventFn, componentView?: ViewDefinitionFactory,
|
||||
componentRendererType?: RendererType2): NodeDef {
|
||||
componentRendererType?: RendererType2 | null): NodeDef {
|
||||
if (!handleEvent) {
|
||||
handleEvent = NOOP;
|
||||
}
|
||||
const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl);
|
||||
let ns: string;
|
||||
let name: string;
|
||||
let ns: string = null !;
|
||||
let name: string = null !;
|
||||
if (namespaceAndName) {
|
||||
[ns, name] = splitNamespace(namespaceAndName);
|
||||
}
|
||||
@ -77,8 +75,8 @@ export function elementDef(
|
||||
const [bindingFlags, namespaceAndName, suffixOrSecurityContext] = bindings[i];
|
||||
|
||||
const [ns, name] = splitNamespace(namespaceAndName);
|
||||
let securityContext: SecurityContext;
|
||||
let suffix: string;
|
||||
let securityContext: SecurityContext = undefined !;
|
||||
let suffix: string = undefined !;
|
||||
switch (bindingFlags & BindingFlags.Types) {
|
||||
case BindingFlags.TypeElementStyle:
|
||||
suffix = <string>suffixOrSecurityContext;
|
||||
@ -98,7 +96,7 @@ export function elementDef(
|
||||
outputDefs[i] = {
|
||||
type: OutputType.ElementOutput,
|
||||
target: <any>target, eventName,
|
||||
propName: undefined
|
||||
propName: null
|
||||
};
|
||||
}
|
||||
fixedAttrs = fixedAttrs || [];
|
||||
@ -113,11 +111,11 @@ export function elementDef(
|
||||
flags |= NodeFlags.TypeElement;
|
||||
return {
|
||||
// will bet set by the view definition
|
||||
index: undefined,
|
||||
parent: undefined,
|
||||
renderParent: undefined,
|
||||
bindingIndex: undefined,
|
||||
outputIndex: undefined,
|
||||
index: -1,
|
||||
parent: null,
|
||||
renderParent: null,
|
||||
bindingIndex: -1,
|
||||
outputIndex: -1,
|
||||
// regular values
|
||||
flags,
|
||||
childFlags: 0,
|
||||
@ -130,21 +128,24 @@ export function elementDef(
|
||||
ns,
|
||||
name,
|
||||
attrs,
|
||||
template: undefined,
|
||||
template: null,
|
||||
// will bet set by the view definition
|
||||
componentProvider: undefined, componentView, componentRendererType,
|
||||
publicProviders: undefined,
|
||||
allProviders: undefined, handleEvent,
|
||||
componentProvider: null,
|
||||
componentView: componentView || null,
|
||||
componentRendererType: componentRendererType,
|
||||
publicProviders: null,
|
||||
allProviders: null,
|
||||
handleEvent: handleEvent || NOOP,
|
||||
},
|
||||
provider: undefined,
|
||||
text: undefined,
|
||||
query: undefined,
|
||||
ngContent: undefined
|
||||
provider: null,
|
||||
text: null,
|
||||
query: null,
|
||||
ngContent: null
|
||||
};
|
||||
}
|
||||
|
||||
export function createElement(view: ViewData, renderHost: any, def: NodeDef): ElementData {
|
||||
const elDef = def.element;
|
||||
const elDef = def.element !;
|
||||
const rootSelectorOrNode = view.root.selectorOrNode;
|
||||
const renderer = view.renderer;
|
||||
let el: any;
|
||||
@ -175,7 +176,7 @@ export function listenToElementOutputs(view: ViewData, compView: ViewData, def:
|
||||
const output = def.outputs[i];
|
||||
const handleEventClosure = renderEventHandlerClosure(
|
||||
view, def.index, elementEventFullName(output.target, output.eventName));
|
||||
let listenTarget = output.target;
|
||||
let listenTarget: 'window'|'document'|'body'|'component'|null = output.target;
|
||||
let listenerView = view;
|
||||
if (output.target === 'component') {
|
||||
listenTarget = null;
|
||||
@ -183,7 +184,7 @@ export function listenToElementOutputs(view: ViewData, compView: ViewData, def:
|
||||
}
|
||||
const disposable =
|
||||
<any>listenerView.renderer.listen(listenTarget || el, output.eventName, handleEventClosure);
|
||||
view.disposables[def.outputIndex + i] = disposable;
|
||||
view.disposables ![def.outputIndex + i] = disposable;
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,7 +226,7 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu
|
||||
const binding = def.bindings[bindingIdx];
|
||||
const elData = asElementData(view, def.index);
|
||||
const renderNode = elData.renderElement;
|
||||
const name = binding.name;
|
||||
const name = binding.name !;
|
||||
switch (binding.flags & BindingFlags.Types) {
|
||||
case BindingFlags.TypeElementAttribute:
|
||||
setElementAttribute(view, binding, renderNode, binding.ns, name, value);
|
||||
@ -248,7 +249,8 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu
|
||||
}
|
||||
|
||||
function setElementAttribute(
|
||||
view: ViewData, binding: BindingDef, renderNode: any, ns: string, name: string, value: any) {
|
||||
view: ViewData, binding: BindingDef, renderNode: any, ns: string | null, name: string,
|
||||
value: any) {
|
||||
const securityContext = binding.securityContext;
|
||||
let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value;
|
||||
renderValue = renderValue != null ? renderValue.toString() : null;
|
||||
@ -271,7 +273,7 @@ function setElementClass(view: ViewData, renderNode: any, name: string, value: b
|
||||
|
||||
function setElementStyle(
|
||||
view: ViewData, binding: BindingDef, renderNode: any, name: string, value: any) {
|
||||
let renderValue = view.root.sanitizer.sanitize(SecurityContext.STYLE, value);
|
||||
let renderValue: string|null = view.root.sanitizer.sanitize(SecurityContext.STYLE, value);
|
||||
if (renderValue != null) {
|
||||
renderValue = renderValue.toString();
|
||||
const unit = binding.suffix;
|
||||
|
@ -12,11 +12,11 @@ import {RenderNodeAction, getParentRenderElement, visitProjectedRenderNodes} fro
|
||||
export function ngContentDef(ngContentIndex: number, index: number): NodeDef {
|
||||
return {
|
||||
// will bet set by the view definition
|
||||
index: undefined,
|
||||
parent: undefined,
|
||||
renderParent: undefined,
|
||||
bindingIndex: undefined,
|
||||
outputIndex: undefined,
|
||||
index: -1,
|
||||
parent: null,
|
||||
renderParent: null,
|
||||
bindingIndex: -1,
|
||||
outputIndex: -1,
|
||||
// regular values
|
||||
flags: NodeFlags.TypeNgContent,
|
||||
childFlags: 0,
|
||||
@ -29,10 +29,10 @@ export function ngContentDef(ngContentIndex: number, index: number): NodeDef {
|
||||
bindings: [],
|
||||
bindingFlags: 0,
|
||||
outputs: [],
|
||||
element: undefined,
|
||||
provider: undefined,
|
||||
text: undefined,
|
||||
query: undefined,
|
||||
element: null,
|
||||
provider: null,
|
||||
text: null,
|
||||
query: null,
|
||||
ngContent: {index}
|
||||
};
|
||||
}
|
||||
@ -43,7 +43,7 @@ export function appendNgContent(view: ViewData, renderHost: any, def: NodeDef) {
|
||||
// Nothing to do if there is no parent element.
|
||||
return;
|
||||
}
|
||||
const ngContentIndex = def.ngContent.index;
|
||||
const ngContentIndex = def.ngContent !.index;
|
||||
visitProjectedRenderNodes(
|
||||
view, ngContentIndex, RenderNodeAction.AppendChild, parentEl, undefined, undefined);
|
||||
view, ngContentIndex, RenderNodeAction.AppendChild, parentEl, null, undefined);
|
||||
}
|
||||
|
@ -38,9 +38,9 @@ export function directiveDef(
|
||||
bindings[bindingIndex] = {
|
||||
flags: BindingFlags.TypeProperty,
|
||||
name: prop, nonMinifiedName,
|
||||
ns: undefined,
|
||||
securityContext: undefined,
|
||||
suffix: undefined
|
||||
ns: null,
|
||||
securityContext: null,
|
||||
suffix: null
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -67,9 +67,9 @@ export function providerDef(
|
||||
}
|
||||
|
||||
export function _def(
|
||||
flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][], childCount: number,
|
||||
token: any, value: any, deps: ([DepFlags, any] | any)[], bindings?: BindingDef[],
|
||||
outputs?: OutputDef[]): NodeDef {
|
||||
flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][] | null,
|
||||
childCount: number, token: any, value: any, deps: ([DepFlags, any] | any)[],
|
||||
bindings?: BindingDef[], outputs?: OutputDef[]): NodeDef {
|
||||
const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl);
|
||||
if (!outputs) {
|
||||
outputs = [];
|
||||
@ -92,23 +92,23 @@ export function _def(
|
||||
|
||||
return {
|
||||
// will bet set by the view definition
|
||||
index: undefined,
|
||||
parent: undefined,
|
||||
renderParent: undefined,
|
||||
bindingIndex: undefined,
|
||||
outputIndex: undefined,
|
||||
index: -1,
|
||||
parent: null,
|
||||
renderParent: null,
|
||||
bindingIndex: -1,
|
||||
outputIndex: -1,
|
||||
// regular values
|
||||
flags,
|
||||
childFlags: 0,
|
||||
directChildFlags: 0,
|
||||
childMatchedQueries: 0, matchedQueries, matchedQueryIds, references,
|
||||
ngContentIndex: undefined, childCount, bindings,
|
||||
ngContentIndex: -1, childCount, bindings,
|
||||
bindingFlags: calcBindingFlags(bindings), outputs,
|
||||
element: undefined,
|
||||
element: null,
|
||||
provider: {token, tokenKey: tokenKey(token), value, deps: depDefs},
|
||||
text: undefined,
|
||||
query: undefined,
|
||||
ngContent: undefined
|
||||
text: null,
|
||||
query: null,
|
||||
ngContent: null
|
||||
};
|
||||
}
|
||||
|
||||
@ -126,22 +126,22 @@ export function createPipeInstance(view: ViewData, def: NodeDef): any {
|
||||
const allowPrivateServices = true;
|
||||
// pipes are always eager and classes!
|
||||
return createClass(
|
||||
compView.parent, viewParentEl(compView), allowPrivateServices, def.provider.value,
|
||||
def.provider.deps);
|
||||
compView.parent !, viewParentEl(compView) !, allowPrivateServices, def.provider !.value,
|
||||
def.provider !.deps);
|
||||
}
|
||||
|
||||
export function createDirectiveInstance(view: ViewData, def: NodeDef): any {
|
||||
// components can see other private services, other directives can't.
|
||||
const allowPrivateServices = (def.flags & NodeFlags.Component) > 0;
|
||||
// directives are always eager and classes!
|
||||
const instance =
|
||||
createClass(view, def.parent, allowPrivateServices, def.provider.value, def.provider.deps);
|
||||
const instance = createClass(
|
||||
view, def.parent !, allowPrivateServices, def.provider !.value, def.provider !.deps);
|
||||
if (def.outputs.length) {
|
||||
for (let i = 0; i < def.outputs.length; i++) {
|
||||
const output = def.outputs[i];
|
||||
const subscription = instance[output.propName].subscribe(
|
||||
eventHandlerClosure(view, def.parent.index, output.eventName));
|
||||
view.disposables[def.outputIndex + i] = subscription.unsubscribe.bind(subscription);
|
||||
const subscription = instance[output.propName !].subscribe(
|
||||
eventHandlerClosure(view, def.parent !.index, output.eventName));
|
||||
view.disposables ![def.outputIndex + i] = subscription.unsubscribe.bind(subscription);
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
@ -157,48 +157,48 @@ export function checkAndUpdateDirectiveInline(
|
||||
const providerData = asProviderData(view, def.index);
|
||||
const directive = providerData.instance;
|
||||
let changed = false;
|
||||
let changes: SimpleChanges;
|
||||
let changes: SimpleChanges = undefined !;
|
||||
const bindLen = def.bindings.length;
|
||||
if (bindLen > 0 && checkBinding(view, def, 0, v0)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 0, v0, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 1 && checkBinding(view, def, 1, v1)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 1, v1, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 2 && checkBinding(view, def, 2, v2)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 2, v2, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 3 && checkBinding(view, def, 3, v3)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 3, v3, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 4 && checkBinding(view, def, 4, v4)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 4, v4, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 5 && checkBinding(view, def, 5, v5)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 5, v5, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 6 && checkBinding(view, def, 6, v6)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 6, v6, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 7 && checkBinding(view, def, 7, v7)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 7, v7, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 8 && checkBinding(view, def, 8, v8)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 8, v8, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 9 && checkBinding(view, def, 9, v9)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 9, v9, changes);
|
||||
};
|
||||
}
|
||||
if (changes) {
|
||||
directive.ngOnChanges(changes);
|
||||
}
|
||||
@ -216,7 +216,7 @@ export function checkAndUpdateDirectiveDynamic(
|
||||
const providerData = asProviderData(view, def.index);
|
||||
const directive = providerData.instance;
|
||||
let changed = false;
|
||||
let changes: SimpleChanges;
|
||||
let changes: SimpleChanges = undefined !;
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
if (checkBinding(view, def, i, values[i])) {
|
||||
changed = true;
|
||||
@ -242,18 +242,18 @@ function _createProviderInstance(view: ViewData, def: NodeDef): any {
|
||||
let injectable: any;
|
||||
switch (def.flags & NodeFlags.Types) {
|
||||
case NodeFlags.TypeClassProvider:
|
||||
injectable =
|
||||
createClass(view, def.parent, allowPrivateServices, providerDef.value, providerDef.deps);
|
||||
injectable = createClass(
|
||||
view, def.parent !, allowPrivateServices, providerDef !.value, providerDef !.deps);
|
||||
break;
|
||||
case NodeFlags.TypeFactoryProvider:
|
||||
injectable =
|
||||
callFactory(view, def.parent, allowPrivateServices, providerDef.value, providerDef.deps);
|
||||
injectable = callFactory(
|
||||
view, def.parent !, allowPrivateServices, providerDef !.value, providerDef !.deps);
|
||||
break;
|
||||
case NodeFlags.TypeUseExistingProvider:
|
||||
injectable = resolveDep(view, def.parent, allowPrivateServices, providerDef.deps[0]);
|
||||
injectable = resolveDep(view, def.parent !, allowPrivateServices, providerDef !.deps[0]);
|
||||
break;
|
||||
case NodeFlags.TypeValueProvider:
|
||||
injectable = providerDef.value;
|
||||
injectable = providerDef !.value;
|
||||
break;
|
||||
}
|
||||
return injectable;
|
||||
@ -345,7 +345,7 @@ export const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
|
||||
|
||||
export function resolveDep(
|
||||
view: ViewData, elDef: NodeDef, allowPrivateServices: boolean, depDef: DepDef,
|
||||
notFoundValue = Injector.THROW_IF_NOT_FOUND): any {
|
||||
notFoundValue: any = Injector.THROW_IF_NOT_FOUND): any {
|
||||
if (depDef.flags & DepFlags.Value) {
|
||||
return depDef.token;
|
||||
}
|
||||
@ -357,7 +357,7 @@ export function resolveDep(
|
||||
|
||||
if (elDef && (depDef.flags & DepFlags.SkipSelf)) {
|
||||
allowPrivateServices = false;
|
||||
elDef = elDef.parent;
|
||||
elDef = elDef.parent !;
|
||||
}
|
||||
|
||||
while (view) {
|
||||
@ -376,7 +376,7 @@ export function resolveDep(
|
||||
case ViewContainerRefTokenKey:
|
||||
return asElementData(view, elDef.index).viewContainer;
|
||||
case TemplateRefTokenKey: {
|
||||
if (elDef.element.template) {
|
||||
if (elDef.element !.template) {
|
||||
return asElementData(view, elDef.index).template;
|
||||
}
|
||||
break;
|
||||
@ -389,8 +389,8 @@ export function resolveDep(
|
||||
return createInjector(view, elDef);
|
||||
default:
|
||||
const providerDef =
|
||||
(allowPrivateServices ? elDef.element.allProviders :
|
||||
elDef.element.publicProviders)[tokenKey];
|
||||
(allowPrivateServices ? elDef.element !.allProviders :
|
||||
elDef.element !.publicProviders) ![tokenKey];
|
||||
if (providerDef) {
|
||||
const providerData = asProviderData(view, providerDef.index);
|
||||
if (providerData.instance === NOT_CREATED) {
|
||||
@ -401,8 +401,8 @@ export function resolveDep(
|
||||
}
|
||||
}
|
||||
allowPrivateServices = isComponentView(view);
|
||||
elDef = viewParentEl(view);
|
||||
view = view.parent;
|
||||
elDef = viewParentEl(view) !;
|
||||
view = view.parent !;
|
||||
}
|
||||
|
||||
const value = startView.root.injector.get(depDef.token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR);
|
||||
@ -437,13 +437,13 @@ function updateProp(
|
||||
view: ViewData, providerData: ProviderData, def: NodeDef, bindingIdx: number, value: any,
|
||||
changes: SimpleChanges): SimpleChanges {
|
||||
if (def.flags & NodeFlags.Component) {
|
||||
const compView = asElementData(view, def.parent.index).componentView;
|
||||
const compView = asElementData(view, def.parent !.index).componentView;
|
||||
if (compView.def.flags & ViewFlags.OnPush) {
|
||||
compView.state |= ViewState.ChecksEnabled;
|
||||
}
|
||||
}
|
||||
const binding = def.bindings[bindingIdx];
|
||||
const propName = binding.name;
|
||||
const propName = binding.name !;
|
||||
// Note: This is still safe with Closure Compiler as
|
||||
// the user passed in the property name as an object has to `providerDef`,
|
||||
// so Closure Compiler will have renamed the property correctly already.
|
||||
@ -455,7 +455,7 @@ function updateProp(
|
||||
oldValue = oldValue.wrapped;
|
||||
}
|
||||
const binding = def.bindings[bindingIdx];
|
||||
changes[binding.nonMinifiedName] =
|
||||
changes[binding.nonMinifiedName !] =
|
||||
new SimpleChange(oldValue, value, (view.state & ViewState.FirstCheck) !== 0);
|
||||
}
|
||||
view.oldValues[def.bindingIndex + bindingIdx] = value;
|
||||
|
@ -29,19 +29,19 @@ function _pureExpressionDef(flags: NodeFlags, propertyNames: string[]): NodeDef
|
||||
bindings[i] = {
|
||||
flags: BindingFlags.TypeProperty,
|
||||
name: prop,
|
||||
ns: undefined,
|
||||
ns: null,
|
||||
nonMinifiedName: prop,
|
||||
securityContext: undefined,
|
||||
suffix: undefined
|
||||
securityContext: null,
|
||||
suffix: null
|
||||
};
|
||||
}
|
||||
return {
|
||||
// will bet set by the view definition
|
||||
index: undefined,
|
||||
parent: undefined,
|
||||
renderParent: undefined,
|
||||
bindingIndex: undefined,
|
||||
outputIndex: undefined,
|
||||
index: -1,
|
||||
parent: null,
|
||||
renderParent: null,
|
||||
bindingIndex: -1,
|
||||
outputIndex: -1,
|
||||
// regular values
|
||||
flags,
|
||||
childFlags: 0,
|
||||
@ -50,15 +50,15 @@ function _pureExpressionDef(flags: NodeFlags, propertyNames: string[]): NodeDef
|
||||
matchedQueries: {},
|
||||
matchedQueryIds: 0,
|
||||
references: {},
|
||||
ngContentIndex: undefined,
|
||||
ngContentIndex: -1,
|
||||
childCount: 0, bindings,
|
||||
bindingFlags: calcBindingFlags(bindings),
|
||||
outputs: [],
|
||||
element: undefined,
|
||||
provider: undefined,
|
||||
text: undefined,
|
||||
query: undefined,
|
||||
ngContent: undefined
|
||||
element: null,
|
||||
provider: null,
|
||||
text: null,
|
||||
query: null,
|
||||
ngContent: null
|
||||
};
|
||||
}
|
||||
|
||||
@ -102,16 +102,16 @@ export function checkAndUpdatePureExpressionInline(
|
||||
break;
|
||||
case NodeFlags.TypePureObject:
|
||||
value = {};
|
||||
if (bindLen > 0) value[bindings[0].name] = v0;
|
||||
if (bindLen > 1) value[bindings[1].name] = v1;
|
||||
if (bindLen > 2) value[bindings[2].name] = v2;
|
||||
if (bindLen > 3) value[bindings[3].name] = v3;
|
||||
if (bindLen > 4) value[bindings[4].name] = v4;
|
||||
if (bindLen > 5) value[bindings[5].name] = v5;
|
||||
if (bindLen > 6) value[bindings[6].name] = v6;
|
||||
if (bindLen > 7) value[bindings[7].name] = v7;
|
||||
if (bindLen > 8) value[bindings[8].name] = v8;
|
||||
if (bindLen > 9) value[bindings[9].name] = v9;
|
||||
if (bindLen > 0) value[bindings[0].name !] = v0;
|
||||
if (bindLen > 1) value[bindings[1].name !] = v1;
|
||||
if (bindLen > 2) value[bindings[2].name !] = v2;
|
||||
if (bindLen > 3) value[bindings[3].name !] = v3;
|
||||
if (bindLen > 4) value[bindings[4].name !] = v4;
|
||||
if (bindLen > 5) value[bindings[5].name !] = v5;
|
||||
if (bindLen > 6) value[bindings[6].name !] = v6;
|
||||
if (bindLen > 7) value[bindings[7].name !] = v7;
|
||||
if (bindLen > 8) value[bindings[8].name !] = v8;
|
||||
if (bindLen > 9) value[bindings[9].name !] = v9;
|
||||
break;
|
||||
case NodeFlags.TypePurePipe:
|
||||
const pipe = v0;
|
||||
@ -175,7 +175,7 @@ export function checkAndUpdatePureExpressionDynamic(
|
||||
case NodeFlags.TypePureObject:
|
||||
value = {};
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
value[bindings[i].name] = values[i];
|
||||
value[bindings[i].name !] = values[i];
|
||||
}
|
||||
break;
|
||||
case NodeFlags.TypePurePipe:
|
||||
|
@ -22,17 +22,17 @@ export function queryDef(
|
||||
|
||||
return {
|
||||
// will bet set by the view definition
|
||||
index: undefined,
|
||||
parent: undefined,
|
||||
renderParent: undefined,
|
||||
bindingIndex: undefined,
|
||||
outputIndex: undefined,
|
||||
index: -1,
|
||||
parent: null,
|
||||
renderParent: null,
|
||||
bindingIndex: -1,
|
||||
outputIndex: -1,
|
||||
// regular values
|
||||
flags,
|
||||
childFlags: 0,
|
||||
directChildFlags: 0,
|
||||
childMatchedQueries: 0,
|
||||
ngContentIndex: undefined,
|
||||
ngContentIndex: -1,
|
||||
matchedQueries: {},
|
||||
matchedQueryIds: 0,
|
||||
references: {},
|
||||
@ -40,11 +40,11 @@ export function queryDef(
|
||||
bindings: [],
|
||||
bindingFlags: 0,
|
||||
outputs: [],
|
||||
element: undefined,
|
||||
provider: undefined,
|
||||
text: undefined,
|
||||
element: null,
|
||||
provider: null,
|
||||
text: null,
|
||||
query: {id, filterId: filterQueryId(id), bindings: bindingDefs},
|
||||
ngContent: undefined
|
||||
ngContent: null
|
||||
};
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ export function createQuery(): QueryList<any> {
|
||||
export function dirtyParentQueries(view: ViewData) {
|
||||
const queryIds = view.def.nodeMatchedQueries;
|
||||
while (view.parent && isEmbeddedView(view)) {
|
||||
let tplDef = view.parentNodeDef;
|
||||
let tplDef = view.parentNodeDef !;
|
||||
view = view.parent;
|
||||
// content queries
|
||||
const end = tplDef.index + tplDef.childCount;
|
||||
@ -63,7 +63,7 @@ export function dirtyParentQueries(view: ViewData) {
|
||||
const nodeDef = view.def.nodes[i];
|
||||
if ((nodeDef.flags & NodeFlags.TypeContentQuery) &&
|
||||
(nodeDef.flags & NodeFlags.DynamicQuery) &&
|
||||
(nodeDef.query.filterId & queryIds) === nodeDef.query.filterId) {
|
||||
(nodeDef.query !.filterId & queryIds) === nodeDef.query !.filterId) {
|
||||
asQueryList(view, i).setDirty();
|
||||
}
|
||||
if ((nodeDef.flags & NodeFlags.TypeElement && i + nodeDef.childCount < tplDef.index) ||
|
||||
@ -94,18 +94,18 @@ export function checkAndUpdateQuery(view: ViewData, nodeDef: NodeDef) {
|
||||
return;
|
||||
}
|
||||
let directiveInstance: any;
|
||||
let newValues: any[];
|
||||
let newValues: any[] = undefined !;
|
||||
if (nodeDef.flags & NodeFlags.TypeContentQuery) {
|
||||
const elementDef = nodeDef.parent.parent;
|
||||
const elementDef = nodeDef.parent !.parent !;
|
||||
newValues = calcQueryValues(
|
||||
view, elementDef.index, elementDef.index + elementDef.childCount, nodeDef.query, []);
|
||||
directiveInstance = asProviderData(view, nodeDef.parent.index).instance;
|
||||
view, elementDef.index, elementDef.index + elementDef.childCount, nodeDef.query !, []);
|
||||
directiveInstance = asProviderData(view, nodeDef.parent !.index).instance;
|
||||
} else if (nodeDef.flags & NodeFlags.TypeViewQuery) {
|
||||
newValues = calcQueryValues(view, 0, view.def.nodes.length - 1, nodeDef.query, []);
|
||||
newValues = calcQueryValues(view, 0, view.def.nodes.length - 1, nodeDef.query !, []);
|
||||
directiveInstance = view.component;
|
||||
}
|
||||
queryList.reset(newValues);
|
||||
const bindings = nodeDef.query.bindings;
|
||||
const bindings = nodeDef.query !.bindings;
|
||||
let notify = false;
|
||||
for (let i = 0; i < bindings.length; i++) {
|
||||
const binding = bindings[i];
|
||||
@ -135,12 +135,13 @@ function calcQueryValues(
|
||||
if (valueType != null) {
|
||||
values.push(getQueryValue(view, nodeDef, valueType));
|
||||
}
|
||||
if (nodeDef.flags & NodeFlags.TypeElement && nodeDef.element.template &&
|
||||
(nodeDef.element.template.nodeMatchedQueries & queryDef.filterId) === queryDef.filterId) {
|
||||
if (nodeDef.flags & NodeFlags.TypeElement && nodeDef.element !.template &&
|
||||
(nodeDef.element !.template !.nodeMatchedQueries & queryDef.filterId) ===
|
||||
queryDef.filterId) {
|
||||
// check embedded views that were attached at the place of their template.
|
||||
const elementData = asElementData(view, i);
|
||||
if (nodeDef.flags & NodeFlags.EmbeddedViews) {
|
||||
const embeddedViews = elementData.viewContainer._embeddedViews;
|
||||
const embeddedViews = elementData.viewContainer !._embeddedViews;
|
||||
for (let k = 0; k < embeddedViews.length; k++) {
|
||||
const embeddedView = embeddedViews[k];
|
||||
const dvc = declaredViewContainer(embeddedView);
|
||||
|
@ -85,7 +85,7 @@ class ComponentFactory_ extends ComponentFactory<any> {
|
||||
throw new Error('ngModule should be provided');
|
||||
}
|
||||
const viewDef = resolveViewDefinition(this.viewDefFactory);
|
||||
const componentNodeIndex = viewDef.nodes[0].element.componentProvider.index;
|
||||
const componentNodeIndex = viewDef.nodes[0].element !.componentProvider !.index;
|
||||
const view = Services.createRootView(
|
||||
injector, projectableNodes || [], rootSelectorOrNode, viewDef, ngModule, EMPTY_CONTEXT);
|
||||
const component = asProviderData(view, componentNodeIndex).instance;
|
||||
@ -135,7 +135,7 @@ class ViewContainerRef_ implements ViewContainerData {
|
||||
let elDef = this._elDef.parent;
|
||||
while (!elDef && view) {
|
||||
elDef = viewParentEl(view);
|
||||
view = view.parent;
|
||||
view = view.parent !;
|
||||
}
|
||||
|
||||
return view ? new Injector_(view, elDef) : new Injector_(this._view, null);
|
||||
@ -144,12 +144,12 @@ class ViewContainerRef_ implements ViewContainerData {
|
||||
clear(): void {
|
||||
const len = this._embeddedViews.length;
|
||||
for (let i = len - 1; i >= 0; i--) {
|
||||
const view = detachEmbeddedView(this._data, i);
|
||||
const view = detachEmbeddedView(this._data, i) !;
|
||||
Services.destroyView(view);
|
||||
}
|
||||
}
|
||||
|
||||
get(index: number): ViewRef {
|
||||
get(index: number): ViewRef|null {
|
||||
const view = this._embeddedViews[index];
|
||||
if (view) {
|
||||
const ref = new ViewRef_(view);
|
||||
@ -206,7 +206,7 @@ class ViewContainerRef_ implements ViewContainerData {
|
||||
}
|
||||
}
|
||||
|
||||
detach(index?: number): ViewRef {
|
||||
detach(index?: number): ViewRef|null {
|
||||
const view = detachEmbeddedView(this._data, index);
|
||||
return view ? new ViewRef_(view) : null;
|
||||
}
|
||||
@ -219,8 +219,8 @@ export function createChangeDetectorRef(view: ViewData): ChangeDetectorRef {
|
||||
export class ViewRef_ implements EmbeddedViewRef<any>, InternalViewRef {
|
||||
/** @internal */
|
||||
_view: ViewData;
|
||||
private _viewContainerRef: ViewContainerRef;
|
||||
private _appRef: ApplicationRef;
|
||||
private _viewContainerRef: ViewContainerRef|null;
|
||||
private _appRef: ApplicationRef|null;
|
||||
|
||||
constructor(_view: ViewData) {
|
||||
this._view = _view;
|
||||
@ -317,7 +317,7 @@ export function nodeValue(view: ViewData, index: number): any {
|
||||
const def = view.def.nodes[index];
|
||||
if (def.flags & NodeFlags.TypeElement) {
|
||||
const elData = asElementData(view, def.index);
|
||||
return def.element.template ? elData.template : elData.renderElement;
|
||||
return def.element !.template ? elData.template : elData.renderElement;
|
||||
} else if (def.flags & NodeFlags.TypeText) {
|
||||
return asTextData(view, def.index).renderText;
|
||||
} else if (def.flags & (NodeFlags.CatProvider | NodeFlags.TypePipe)) {
|
||||
@ -387,7 +387,7 @@ class RendererAdapter implements RendererV1 {
|
||||
|
||||
destroyView(hostElement: Element|DocumentFragment, viewAllNodes: Node[]) {
|
||||
for (let i = 0; i < viewAllNodes.length; i++) {
|
||||
this.delegate.destroyNode(viewAllNodes[i]);
|
||||
this.delegate.destroyNode !(viewAllNodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -439,4 +439,4 @@ class RendererAdapter implements RendererV1 {
|
||||
setText(renderNode: Text, text: string): void { this.delegate.setValue(renderNode, text); }
|
||||
|
||||
animate(): any { throw new Error('Renderer.animate is no longer supported!'); }
|
||||
}
|
||||
}
|
||||
|
@ -159,9 +159,9 @@ enum DebugAction {
|
||||
|
||||
let _currentAction: DebugAction;
|
||||
let _currentView: ViewData;
|
||||
let _currentNodeIndex: number;
|
||||
let _currentNodeIndex: number|null;
|
||||
|
||||
function debugSetCurrentNode(view: ViewData, nodeIndex: number) {
|
||||
function debugSetCurrentNode(view: ViewData, nodeIndex: number | null) {
|
||||
_currentView = view;
|
||||
_currentNodeIndex = nodeIndex;
|
||||
}
|
||||
@ -231,13 +231,13 @@ function debugCheckAndUpdateNode(
|
||||
const binding = nodeDef.bindings[i];
|
||||
const value = values[i];
|
||||
if (binding.flags & BindingFlags.TypeProperty) {
|
||||
bindingValues[normalizeDebugBindingName(binding.nonMinifiedName)] =
|
||||
bindingValues[normalizeDebugBindingName(binding.nonMinifiedName !)] =
|
||||
normalizeDebugBindingValue(value);
|
||||
}
|
||||
}
|
||||
const elDef = nodeDef.parent;
|
||||
const elDef = nodeDef.parent !;
|
||||
const el = asElementData(view, elDef.index).renderElement;
|
||||
if (!elDef.element.name) {
|
||||
if (!elDef.element !.name) {
|
||||
// a comment.
|
||||
view.renderer.setValue(el, `bindings=${JSON.stringify(bindingValues, null, 2)}`);
|
||||
} else {
|
||||
@ -275,37 +275,37 @@ function camelCaseToDashCase(input: string): string {
|
||||
function normalizeDebugBindingValue(value: any): string {
|
||||
try {
|
||||
// Limit the size of the value as otherwise the DOM just gets polluted.
|
||||
return value ? value.toString().slice(0, 30) : value;
|
||||
return value != null ? value.toString().slice(0, 30) : value;
|
||||
} catch (e) {
|
||||
return '[ERROR] Exception while trying to serialize the value';
|
||||
}
|
||||
}
|
||||
|
||||
function nextDirectiveWithBinding(view: ViewData, nodeIndex: number): number {
|
||||
function nextDirectiveWithBinding(view: ViewData, nodeIndex: number): number|null {
|
||||
for (let i = nodeIndex; i < view.def.nodes.length; i++) {
|
||||
const nodeDef = view.def.nodes[i];
|
||||
if (nodeDef.flags & NodeFlags.TypeDirective && nodeDef.bindings && nodeDef.bindings.length) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
|
||||
function nextRenderNodeWithBinding(view: ViewData, nodeIndex: number): number {
|
||||
function nextRenderNodeWithBinding(view: ViewData, nodeIndex: number): number|null {
|
||||
for (let i = nodeIndex; i < view.def.nodes.length; i++) {
|
||||
const nodeDef = view.def.nodes[i];
|
||||
if ((nodeDef.flags & NodeFlags.CatRenderNode) && nodeDef.bindings && nodeDef.bindings.length) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
|
||||
class DebugContext_ implements DebugContext {
|
||||
private nodeDef: NodeDef;
|
||||
private elView: ViewData;
|
||||
private elDef: NodeDef;
|
||||
constructor(public view: ViewData, public nodeIndex: number) {
|
||||
constructor(public view: ViewData, public nodeIndex: number|null) {
|
||||
if (nodeIndex == null) {
|
||||
this.nodeIndex = nodeIndex = 0;
|
||||
}
|
||||
@ -313,12 +313,12 @@ class DebugContext_ implements DebugContext {
|
||||
let elDef = this.nodeDef;
|
||||
let elView = view;
|
||||
while (elDef && (elDef.flags & NodeFlags.TypeElement) === 0) {
|
||||
elDef = elDef.parent;
|
||||
elDef = elDef.parent !;
|
||||
}
|
||||
if (!elDef) {
|
||||
while (!elDef && elView) {
|
||||
elDef = viewParentEl(elView);
|
||||
elView = elView.parent;
|
||||
elDef = viewParentEl(elView) !;
|
||||
elView = elView.parent !;
|
||||
}
|
||||
}
|
||||
this.elDef = elDef;
|
||||
@ -337,7 +337,7 @@ class DebugContext_ implements DebugContext {
|
||||
for (let i = this.elDef.index + 1; i <= this.elDef.index + this.elDef.childCount; i++) {
|
||||
const childDef = this.elView.def.nodes[i];
|
||||
if (childDef.flags & NodeFlags.CatProvider) {
|
||||
tokens.push(childDef.provider.token);
|
||||
tokens.push(childDef.provider !.token);
|
||||
}
|
||||
i += childDef.childCount;
|
||||
}
|
||||
@ -389,7 +389,7 @@ class DebugContext_ implements DebugContext {
|
||||
return NOOP;
|
||||
}
|
||||
};
|
||||
logViewDef.factory(nodeLogger);
|
||||
logViewDef.factory !(nodeLogger);
|
||||
if (currRenderNodeIndex < renderNodeIndex) {
|
||||
console.error('Illegal state: the ViewDefinitionFactory did not call the logger!');
|
||||
(<any>console.error)(...values);
|
||||
@ -408,14 +408,14 @@ function getRenderNodeIndex(viewDef: ViewDefinition, nodeIndex: number): number
|
||||
return renderNodeIndex;
|
||||
}
|
||||
|
||||
function findHostElement(view: ViewData): ElementData {
|
||||
function findHostElement(view: ViewData): ElementData|null {
|
||||
while (view && !isComponentView(view)) {
|
||||
view = view.parent;
|
||||
view = view.parent !;
|
||||
}
|
||||
if (view.parent) {
|
||||
return asElementData(view.parent, viewParentEl(view).index);
|
||||
return asElementData(view.parent, viewParentEl(view) !.index);
|
||||
}
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
|
||||
function collectReferences(view: ViewData, nodeDef: NodeDef, references: {[key: string]: any}) {
|
||||
@ -440,11 +440,11 @@ function callWithDebugContext(action: DebugAction, fn: any, self: any, args: any
|
||||
throw e;
|
||||
}
|
||||
_currentView.state |= ViewState.Errored;
|
||||
throw viewWrappedDebugError(e, getCurrentDebugContext());
|
||||
throw viewWrappedDebugError(e, getCurrentDebugContext() !);
|
||||
}
|
||||
}
|
||||
|
||||
export function getCurrentDebugContext(): DebugContext {
|
||||
export function getCurrentDebugContext(): DebugContext|null {
|
||||
return _currentView ? new DebugContext_(_currentView, _currentNodeIndex) : null;
|
||||
}
|
||||
|
||||
@ -452,7 +452,7 @@ export function getCurrentDebugContext(): DebugContext {
|
||||
class DebugRendererFactory2 implements RendererFactory2 {
|
||||
constructor(private delegate: RendererFactory2) {}
|
||||
|
||||
createRenderer(element: any, renderData: RendererType2): Renderer2 {
|
||||
createRenderer(element: any, renderData: RendererType2|null): Renderer2 {
|
||||
return new DebugRenderer2(this.delegate.createRenderer(element, renderData));
|
||||
}
|
||||
}
|
||||
@ -464,7 +464,7 @@ class DebugRenderer2 implements Renderer2 {
|
||||
get data() { return this.delegate.data; }
|
||||
|
||||
destroyNode(node: any) {
|
||||
removeDebugNodeFromIndex(getDebugNode(node));
|
||||
removeDebugNodeFromIndex(getDebugNode(node) !);
|
||||
if (this.delegate.destroyNode) {
|
||||
this.delegate.destroyNode(node);
|
||||
}
|
||||
@ -513,7 +513,7 @@ class DebugRenderer2 implements Renderer2 {
|
||||
insertBefore(parent: any, newChild: any, refChild: any): void {
|
||||
const debugEl = getDebugNode(parent);
|
||||
const debugChildEl = getDebugNode(newChild);
|
||||
const debugRefEl = getDebugNode(refChild);
|
||||
const debugRefEl = getDebugNode(refChild) !;
|
||||
if (debugEl && debugChildEl && debugEl instanceof DebugElement) {
|
||||
debugEl.insertBefore(debugRefEl, debugChildEl);
|
||||
}
|
||||
|
@ -14,21 +14,21 @@ export function textDef(ngContentIndex: number, constants: string[]): NodeDef {
|
||||
for (let i = 1; i < constants.length; i++) {
|
||||
bindings[i - 1] = {
|
||||
flags: BindingFlags.TypeProperty,
|
||||
name: undefined,
|
||||
ns: undefined,
|
||||
nonMinifiedName: undefined,
|
||||
securityContext: undefined,
|
||||
name: null,
|
||||
ns: null,
|
||||
nonMinifiedName: null,
|
||||
securityContext: null,
|
||||
suffix: constants[i]
|
||||
};
|
||||
}
|
||||
const flags = NodeFlags.TypeText;
|
||||
return {
|
||||
// will bet set by the view definition
|
||||
index: undefined,
|
||||
parent: undefined,
|
||||
renderParent: undefined,
|
||||
bindingIndex: undefined,
|
||||
outputIndex: undefined,
|
||||
index: -1,
|
||||
parent: null,
|
||||
renderParent: null,
|
||||
bindingIndex: -1,
|
||||
outputIndex: -1,
|
||||
// regular values
|
||||
flags,
|
||||
childFlags: 0,
|
||||
@ -40,18 +40,18 @@ export function textDef(ngContentIndex: number, constants: string[]): NodeDef {
|
||||
childCount: 0, bindings,
|
||||
bindingFlags: calcBindingFlags(bindings),
|
||||
outputs: [],
|
||||
element: undefined,
|
||||
provider: undefined,
|
||||
element: null,
|
||||
provider: null,
|
||||
text: {prefix: constants[0]},
|
||||
query: undefined,
|
||||
ngContent: undefined
|
||||
query: null,
|
||||
ngContent: null
|
||||
};
|
||||
}
|
||||
|
||||
export function createText(view: ViewData, renderHost: any, def: NodeDef): TextData {
|
||||
let renderNode: any;
|
||||
const renderer = view.renderer;
|
||||
renderNode = renderer.createText(def.text.prefix);
|
||||
renderNode = renderer.createText(def.text !.prefix);
|
||||
const parentEl = getParentRenderElement(view, renderHost, def);
|
||||
if (parentEl) {
|
||||
renderer.appendChild(parentEl, renderNode);
|
||||
@ -77,7 +77,7 @@ export function checkAndUpdateTextInline(
|
||||
if (bindLen > 9 && checkAndUpdateBinding(view, def, 9, v9)) changed = true;
|
||||
|
||||
if (changed) {
|
||||
let value = def.text.prefix;
|
||||
let value = def.text !.prefix;
|
||||
if (bindLen > 0) value += _addInterpolationPart(v0, bindings[0]);
|
||||
if (bindLen > 1) value += _addInterpolationPart(v1, bindings[1]);
|
||||
if (bindLen > 2) value += _addInterpolationPart(v2, bindings[2]);
|
||||
@ -109,7 +109,7 @@ export function checkAndUpdateTextDynamic(view: ViewData, def: NodeDef, values:
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
value = value + _addInterpolationPart(values[i], bindings[i]);
|
||||
}
|
||||
value = def.text.prefix + value;
|
||||
value = def.text !.prefix + value;
|
||||
const renderNode = asTextData(view, def.index).renderText;
|
||||
view.renderer.setValue(renderNode, value);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ import {Sanitizer, SecurityContext} from '../security';
|
||||
// -------------------------------------
|
||||
|
||||
export interface ViewDefinition {
|
||||
factory: ViewDefinitionFactory;
|
||||
factory: ViewDefinitionFactory|null;
|
||||
flags: ViewFlags;
|
||||
updateDirectives: ViewUpdateFn;
|
||||
updateRenderer: ViewUpdateFn;
|
||||
@ -32,7 +32,7 @@ export interface ViewDefinition {
|
||||
/** aggregated NodeFlags for all nodes **/
|
||||
nodeFlags: NodeFlags;
|
||||
rootNodeFlags: NodeFlags;
|
||||
lastRenderRootNode: NodeDef;
|
||||
lastRenderRootNode: NodeDef|null;
|
||||
bindingCount: number;
|
||||
outputCount: number;
|
||||
/**
|
||||
@ -91,8 +91,8 @@ export const enum ViewFlags {
|
||||
export interface NodeDef {
|
||||
flags: NodeFlags;
|
||||
index: number;
|
||||
parent: NodeDef;
|
||||
renderParent: NodeDef;
|
||||
parent: NodeDef|null;
|
||||
renderParent: NodeDef|null;
|
||||
/** this is checked against NgContentDef.index to find matched nodes */
|
||||
ngContentIndex: number;
|
||||
/** number of transitive children */
|
||||
@ -123,11 +123,11 @@ export interface NodeDef {
|
||||
* Used as a bloom filter.
|
||||
*/
|
||||
childMatchedQueries: number;
|
||||
element: ElementDef;
|
||||
provider: ProviderDef;
|
||||
text: TextDef;
|
||||
query: QueryDef;
|
||||
ngContent: NgContentDef;
|
||||
element: ElementDef|null;
|
||||
provider: ProviderDef|null;
|
||||
text: TextDef|null;
|
||||
query: QueryDef|null;
|
||||
ngContent: NgContentDef|null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -179,11 +179,11 @@ export const enum NodeFlags {
|
||||
|
||||
export interface BindingDef {
|
||||
flags: BindingFlags;
|
||||
ns: string;
|
||||
name: string;
|
||||
nonMinifiedName: string;
|
||||
securityContext: SecurityContext;
|
||||
suffix: string;
|
||||
ns: string|null;
|
||||
name: string|null;
|
||||
nonMinifiedName: string|null;
|
||||
securityContext: SecurityContext|null;
|
||||
suffix: string|null;
|
||||
}
|
||||
|
||||
export const enum BindingFlags {
|
||||
@ -201,9 +201,9 @@ export const enum BindingFlags {
|
||||
|
||||
export interface OutputDef {
|
||||
type: OutputType;
|
||||
target: 'window'|'document'|'body'|'component';
|
||||
target: 'window'|'document'|'body'|'component'|null;
|
||||
eventName: string;
|
||||
propName: string;
|
||||
propName: string|null;
|
||||
}
|
||||
|
||||
export const enum OutputType {ElementOutput, DirectiveOutput}
|
||||
@ -217,26 +217,26 @@ export const enum QueryValueType {
|
||||
}
|
||||
|
||||
export interface ElementDef {
|
||||
name: string;
|
||||
ns: string;
|
||||
name: string|null;
|
||||
ns: string|null;
|
||||
/** ns, name, value */
|
||||
attrs: [string, string, string][];
|
||||
template: ViewDefinition;
|
||||
componentProvider: NodeDef;
|
||||
componentRendererType: RendererType2;
|
||||
attrs: [string, string, string][]|null;
|
||||
template: ViewDefinition|null;
|
||||
componentProvider: NodeDef|null;
|
||||
componentRendererType: RendererType2|null;
|
||||
// closure to allow recursive components
|
||||
componentView: ViewDefinitionFactory;
|
||||
componentView: ViewDefinitionFactory|null;
|
||||
/**
|
||||
* visible public providers for DI in the view,
|
||||
* as see from this element. This does not include private providers.
|
||||
*/
|
||||
publicProviders: {[tokenKey: string]: NodeDef};
|
||||
publicProviders: {[tokenKey: string]: NodeDef}|null;
|
||||
/**
|
||||
* same as visiblePublicProviders, but also includes private providers
|
||||
* that are located on this element.
|
||||
*/
|
||||
allProviders: {[tokenKey: string]: NodeDef};
|
||||
handleEvent: ElementHandleEventFn;
|
||||
allProviders: {[tokenKey: string]: NodeDef}|null;
|
||||
handleEvent: ElementHandleEventFn|null;
|
||||
}
|
||||
|
||||
export interface ElementHandleEventFn { (view: ViewData, eventName: string, event: any): boolean; }
|
||||
@ -303,9 +303,9 @@ export interface ViewData {
|
||||
root: RootData;
|
||||
renderer: Renderer2;
|
||||
// index of component provider / anchor.
|
||||
parentNodeDef: NodeDef;
|
||||
parent: ViewData;
|
||||
viewContainerParent: ViewData;
|
||||
parentNodeDef: NodeDef|null;
|
||||
parent: ViewData|null;
|
||||
viewContainerParent: ViewData|null;
|
||||
component: any;
|
||||
context: any;
|
||||
// Attention: Never loop over this, as this will
|
||||
@ -316,7 +316,7 @@ export interface ViewData {
|
||||
nodes: {[key: number]: NodeData};
|
||||
state: ViewState;
|
||||
oldValues: any[];
|
||||
disposables: DisposableFn[];
|
||||
disposables: DisposableFn[]|null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -366,7 +366,7 @@ export function asTextData(view: ViewData, index: number): TextData {
|
||||
export interface ElementData {
|
||||
renderElement: any;
|
||||
componentView: ViewData;
|
||||
viewContainer: ViewContainerData;
|
||||
viewContainer: ViewContainerData|null;
|
||||
template: TemplateData;
|
||||
}
|
||||
|
||||
@ -434,7 +434,7 @@ export interface RootData {
|
||||
|
||||
export abstract class DebugContext {
|
||||
abstract get view(): ViewData;
|
||||
abstract get nodeIndex(): number;
|
||||
abstract get nodeIndex(): number|null;
|
||||
abstract get injector(): Injector;
|
||||
abstract get component(): any;
|
||||
abstract get providerTokens(): any[];
|
||||
@ -461,7 +461,7 @@ export interface Services {
|
||||
checkNoChangesView(view: ViewData): void;
|
||||
destroyView(view: ViewData): void;
|
||||
resolveDep(
|
||||
view: ViewData, elDef: NodeDef, allowPrivateServices: boolean, depDef: DepDef,
|
||||
view: ViewData, elDef: NodeDef|null, allowPrivateServices: boolean, depDef: DepDef,
|
||||
notFoundValue?: any): any;
|
||||
createDebugContext(view: ViewData, nodeIndex: number): DebugContext;
|
||||
handleEvent: ViewHandleEventFn;
|
||||
@ -475,16 +475,16 @@ export interface Services {
|
||||
* debug mode can hook it. It is lazily filled when `isDevMode` is known.
|
||||
*/
|
||||
export const Services: Services = {
|
||||
setCurrentNode: undefined,
|
||||
createRootView: undefined,
|
||||
createEmbeddedView: undefined,
|
||||
checkAndUpdateView: undefined,
|
||||
checkNoChangesView: undefined,
|
||||
destroyView: undefined,
|
||||
resolveDep: undefined,
|
||||
createDebugContext: undefined,
|
||||
handleEvent: undefined,
|
||||
updateDirectives: undefined,
|
||||
updateRenderer: undefined,
|
||||
dirtyParentQueries: undefined,
|
||||
setCurrentNode: undefined !,
|
||||
createRootView: undefined !,
|
||||
createEmbeddedView: undefined !,
|
||||
checkAndUpdateView: undefined !,
|
||||
checkNoChangesView: undefined !,
|
||||
destroyView: undefined !,
|
||||
resolveDep: undefined !,
|
||||
createDebugContext: undefined !,
|
||||
handleEvent: undefined !,
|
||||
updateDirectives: undefined !,
|
||||
updateRenderer: undefined !,
|
||||
dirtyParentQueries: undefined !,
|
||||
};
|
||||
|
@ -60,7 +60,7 @@ export function createRendererType2(values: {
|
||||
|
||||
let _renderCompCount = 0;
|
||||
|
||||
export function resolveRendererType2(type: RendererType2): RendererType2 {
|
||||
export function resolveRendererType2(type?: RendererType2 | null): RendererType2|null {
|
||||
if (type && type.id === UNDEFINED_RENDERER_TYPE_ID) {
|
||||
// first time we see this RendererType2. Initialize it...
|
||||
const isFilled =
|
||||
@ -75,7 +75,7 @@ export function resolveRendererType2(type: RendererType2): RendererType2 {
|
||||
if (type && type.id === EMPTY_RENDERER_TYPE_ID) {
|
||||
type = null;
|
||||
}
|
||||
return type;
|
||||
return type || null;
|
||||
}
|
||||
|
||||
export function checkBinding(
|
||||
@ -108,7 +108,7 @@ export function checkBindingNoChanges(
|
||||
}
|
||||
|
||||
export function markParentViewsForCheck(view: ViewData) {
|
||||
let currView = view;
|
||||
let currView: ViewData|null = view;
|
||||
while (currView) {
|
||||
if (currView.def.flags & ViewFlags.OnPush) {
|
||||
currView.state |= ViewState.ChecksEnabled;
|
||||
@ -126,12 +126,12 @@ export function dispatchEvent(
|
||||
return Services.handleEvent(view, nodeIndex, eventName, event);
|
||||
}
|
||||
|
||||
export function declaredViewContainer(view: ViewData): ElementData {
|
||||
export function declaredViewContainer(view: ViewData): ElementData|null {
|
||||
if (view.parent) {
|
||||
const parentView = view.parent;
|
||||
return asElementData(parentView, view.parentNodeDef.index);
|
||||
return asElementData(parentView, view.parentNodeDef !.index);
|
||||
}
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -139,10 +139,10 @@ export function declaredViewContainer(view: ViewData): ElementData {
|
||||
* for embedded views, this is the index of the parent node
|
||||
* that contains the view container.
|
||||
*/
|
||||
export function viewParentEl(view: ViewData): NodeDef {
|
||||
export function viewParentEl(view: ViewData): NodeDef|null {
|
||||
const parentView = view.parent;
|
||||
if (parentView) {
|
||||
return view.parentNodeDef.parent;
|
||||
return view.parentNodeDef !.parent;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@ -157,23 +157,24 @@ export function renderNode(view: ViewData, def: NodeDef): any {
|
||||
}
|
||||
}
|
||||
|
||||
export function elementEventFullName(target: string, name: string): string {
|
||||
export function elementEventFullName(target: string | null, name: string): string {
|
||||
return target ? `${target}:${name}` : name;
|
||||
}
|
||||
|
||||
export function isComponentView(view: ViewData): boolean {
|
||||
return !!view.parent && !!(view.parentNodeDef.flags & NodeFlags.Component);
|
||||
return !!view.parent && !!(view.parentNodeDef !.flags & NodeFlags.Component);
|
||||
}
|
||||
|
||||
export function isEmbeddedView(view: ViewData): boolean {
|
||||
return !!view.parent && !(view.parentNodeDef.flags & NodeFlags.Component);
|
||||
return !!view.parent && !(view.parentNodeDef !.flags & NodeFlags.Component);
|
||||
}
|
||||
|
||||
export function filterQueryId(queryId: number): number {
|
||||
return 1 << (queryId % 32);
|
||||
}
|
||||
|
||||
export function splitMatchedQueriesDsl(matchedQueriesDsl: [string | number, QueryValueType][]): {
|
||||
export function splitMatchedQueriesDsl(
|
||||
matchedQueriesDsl: [string | number, QueryValueType][] | null): {
|
||||
matchedQueries: {[queryId: string]: QueryValueType},
|
||||
references: {[refId: string]: QueryValueType},
|
||||
matchedQueryIds: number
|
||||
@ -199,11 +200,12 @@ export function getParentRenderElement(view: ViewData, renderHost: any, def: Nod
|
||||
if (renderParent) {
|
||||
if ((renderParent.flags & NodeFlags.TypeElement) === 0 ||
|
||||
(renderParent.flags & NodeFlags.ComponentView) === 0 ||
|
||||
(renderParent.element.componentRendererType &&
|
||||
renderParent.element.componentRendererType.encapsulation === ViewEncapsulation.Native)) {
|
||||
(renderParent.element !.componentRendererType &&
|
||||
renderParent.element !.componentRendererType !.encapsulation ===
|
||||
ViewEncapsulation.Native)) {
|
||||
// only children of non components, or children of components with native encapsulation should
|
||||
// be attached.
|
||||
return asElementData(view, def.renderParent.index).renderElement;
|
||||
return asElementData(view, def.renderParent !.index).renderElement;
|
||||
}
|
||||
} else {
|
||||
return renderHost;
|
||||
@ -213,7 +215,7 @@ export function getParentRenderElement(view: ViewData, renderHost: any, def: Nod
|
||||
const VIEW_DEFINITION_CACHE = new WeakMap<any, ViewDefinition>();
|
||||
|
||||
export function resolveViewDefinition(factory: ViewDefinitionFactory): ViewDefinition {
|
||||
let value: ViewDefinition = VIEW_DEFINITION_CACHE.get(factory);
|
||||
let value: ViewDefinition = VIEW_DEFINITION_CACHE.get(factory) !;
|
||||
if (!value) {
|
||||
value = factory(() => NOOP);
|
||||
value.factory = factory;
|
||||
@ -231,10 +233,10 @@ export function rootRenderNodes(view: ViewData): any[] {
|
||||
export const enum RenderNodeAction {Collect, AppendChild, InsertBefore, RemoveChild}
|
||||
|
||||
export function visitRootRenderNodes(
|
||||
view: ViewData, action: RenderNodeAction, parentNode: any, nextSibling: any, target: any[]) {
|
||||
view: ViewData, action: RenderNodeAction, parentNode: any, nextSibling: any, target?: any[]) {
|
||||
// We need to re-compute the parent node in case the nodes have been moved around manually
|
||||
if (action === RenderNodeAction.RemoveChild) {
|
||||
parentNode = view.renderer.parentNode(renderNode(view, view.def.lastRenderRootNode));
|
||||
parentNode = view.renderer.parentNode(renderNode(view, view.def.lastRenderRootNode !));
|
||||
}
|
||||
visitSiblingRenderNodes(
|
||||
view, action, 0, view.def.nodes.length - 1, parentNode, nextSibling, target);
|
||||
@ -242,7 +244,7 @@ export function visitRootRenderNodes(
|
||||
|
||||
export function visitSiblingRenderNodes(
|
||||
view: ViewData, action: RenderNodeAction, startIndex: number, endIndex: number, parentNode: any,
|
||||
nextSibling: any, target: any[]) {
|
||||
nextSibling: any, target?: any[]) {
|
||||
for (let i = startIndex; i <= endIndex; i++) {
|
||||
const nodeDef = view.def.nodes[i];
|
||||
if (nodeDef.flags & (NodeFlags.TypeElement | NodeFlags.TypeText | NodeFlags.TypeNgContent)) {
|
||||
@ -255,24 +257,24 @@ export function visitSiblingRenderNodes(
|
||||
|
||||
export function visitProjectedRenderNodes(
|
||||
view: ViewData, ngContentIndex: number, action: RenderNodeAction, parentNode: any,
|
||||
nextSibling: any, target: any[]) {
|
||||
let compView = view;
|
||||
nextSibling: any, target?: any[]) {
|
||||
let compView: ViewData|null = view;
|
||||
while (compView && !isComponentView(compView)) {
|
||||
compView = compView.parent;
|
||||
}
|
||||
const hostView = compView.parent;
|
||||
const hostElDef = viewParentEl(compView);
|
||||
const startIndex = hostElDef.index + 1;
|
||||
const endIndex = hostElDef.index + hostElDef.childCount;
|
||||
const hostView = compView !.parent;
|
||||
const hostElDef = viewParentEl(compView !);
|
||||
const startIndex = hostElDef !.index + 1;
|
||||
const endIndex = hostElDef !.index + hostElDef !.childCount;
|
||||
for (let i = startIndex; i <= endIndex; i++) {
|
||||
const nodeDef = hostView.def.nodes[i];
|
||||
const nodeDef = hostView !.def.nodes[i];
|
||||
if (nodeDef.ngContentIndex === ngContentIndex) {
|
||||
visitRenderNode(hostView, nodeDef, action, parentNode, nextSibling, target);
|
||||
visitRenderNode(hostView !, nodeDef, action, parentNode, nextSibling, target);
|
||||
}
|
||||
// jump to next sibling
|
||||
i += nodeDef.childCount;
|
||||
}
|
||||
if (!hostView.parent) {
|
||||
if (!hostView !.parent) {
|
||||
// a root view
|
||||
const projectedNodes = view.root.projectableNodes[ngContentIndex];
|
||||
if (projectedNodes) {
|
||||
@ -285,10 +287,10 @@ export function visitProjectedRenderNodes(
|
||||
|
||||
function visitRenderNode(
|
||||
view: ViewData, nodeDef: NodeDef, action: RenderNodeAction, parentNode: any, nextSibling: any,
|
||||
target: any[]) {
|
||||
target?: any[]) {
|
||||
if (nodeDef.flags & NodeFlags.TypeNgContent) {
|
||||
visitProjectedRenderNodes(
|
||||
view, nodeDef.ngContent.index, action, parentNode, nextSibling, target);
|
||||
view, nodeDef.ngContent !.index, action, parentNode, nextSibling, target);
|
||||
} else {
|
||||
const rn = renderNode(view, nodeDef);
|
||||
if (action === RenderNodeAction.RemoveChild && (nodeDef.flags & NodeFlags.ComponentView) &&
|
||||
@ -305,12 +307,12 @@ function visitRenderNode(
|
||||
execRenderNodeAction(view, rn, action, parentNode, nextSibling, target);
|
||||
}
|
||||
if (nodeDef.flags & NodeFlags.EmbeddedViews) {
|
||||
const embeddedViews = asElementData(view, nodeDef.index).viewContainer._embeddedViews;
|
||||
const embeddedViews = asElementData(view, nodeDef.index).viewContainer !._embeddedViews;
|
||||
for (let k = 0; k < embeddedViews.length; k++) {
|
||||
visitRootRenderNodes(embeddedViews[k], action, parentNode, nextSibling, target);
|
||||
}
|
||||
}
|
||||
if (nodeDef.flags & NodeFlags.TypeElement && !nodeDef.element.name) {
|
||||
if (nodeDef.flags & NodeFlags.TypeElement && !nodeDef.element !.name) {
|
||||
visitSiblingRenderNodes(
|
||||
view, action, nodeDef.index + 1, nodeDef.index + nodeDef.childCount, parentNode,
|
||||
nextSibling, target);
|
||||
@ -320,7 +322,7 @@ function visitRenderNode(
|
||||
|
||||
function execRenderNodeAction(
|
||||
view: ViewData, renderNode: any, action: RenderNodeAction, parentNode: any, nextSibling: any,
|
||||
target: any[]) {
|
||||
target?: any[]) {
|
||||
const renderer = view.renderer;
|
||||
switch (action) {
|
||||
case RenderNodeAction.AppendChild:
|
||||
@ -333,7 +335,7 @@ function execRenderNodeAction(
|
||||
renderer.removeChild(parentNode, renderNode);
|
||||
break;
|
||||
case RenderNodeAction.Collect:
|
||||
target.push(renderNode);
|
||||
target !.push(renderNode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -342,7 +344,7 @@ const NS_PREFIX_RE = /^:([^:]+):(.+)$/;
|
||||
|
||||
export function splitNamespace(name: string): string[] {
|
||||
if (name[0] === ':') {
|
||||
const match = name.match(NS_PREFIX_RE);
|
||||
const match = name.match(NS_PREFIX_RE) !;
|
||||
return [match[1], match[2]];
|
||||
}
|
||||
return ['', name];
|
||||
|
@ -28,15 +28,15 @@ export function viewDef(
|
||||
let viewNodeFlags = 0;
|
||||
let viewRootNodeFlags = 0;
|
||||
let viewMatchedQueries = 0;
|
||||
let currentParent: NodeDef = null;
|
||||
let currentParent: NodeDef|null = null;
|
||||
let currentElementHasPublicProviders = false;
|
||||
let currentElementHasPrivateProviders = false;
|
||||
let lastRenderRootNode: NodeDef = null;
|
||||
let lastRenderRootNode: NodeDef|null = null;
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
while (currentParent && i > currentParent.index + currentParent.childCount) {
|
||||
const newParent = currentParent.parent;
|
||||
const newParent: NodeDef|null = currentParent.parent;
|
||||
if (newParent) {
|
||||
newParent.childFlags |= currentParent.childFlags;
|
||||
newParent.childFlags |= currentParent.childFlags !;
|
||||
newParent.childMatchedQueries |= currentParent.childMatchedQueries;
|
||||
}
|
||||
currentParent = newParent;
|
||||
@ -48,9 +48,9 @@ export function viewDef(
|
||||
node.outputIndex = viewDisposableCount;
|
||||
|
||||
// renderParent needs to account for ng-container!
|
||||
let currentRenderParent: NodeDef;
|
||||
let currentRenderParent: NodeDef|null;
|
||||
if (currentParent && currentParent.flags & NodeFlags.TypeElement &&
|
||||
!currentParent.element.name) {
|
||||
!currentParent.element !.name) {
|
||||
currentRenderParent = currentParent.renderParent;
|
||||
} else {
|
||||
currentRenderParent = currentParent;
|
||||
@ -60,7 +60,7 @@ export function viewDef(
|
||||
if (node.element) {
|
||||
const elDef = node.element;
|
||||
elDef.publicProviders =
|
||||
currentParent ? currentParent.element.publicProviders : Object.create(null);
|
||||
currentParent ? currentParent.element !.publicProviders : Object.create(null);
|
||||
elDef.allProviders = elDef.publicProviders;
|
||||
// Note: We assume that all providers of an element are before any child element!
|
||||
currentElementHasPublicProviders = false;
|
||||
@ -94,24 +94,25 @@ export function viewDef(
|
||||
if (!currentElementHasPublicProviders) {
|
||||
currentElementHasPublicProviders = true;
|
||||
// Use prototypical inheritance to not get O(n^2) complexity...
|
||||
currentParent.element.publicProviders =
|
||||
Object.create(currentParent.element.publicProviders);
|
||||
currentParent.element.allProviders = currentParent.element.publicProviders;
|
||||
currentParent !.element !.publicProviders =
|
||||
Object.create(currentParent !.element !.publicProviders);
|
||||
currentParent !.element !.allProviders = currentParent !.element !.publicProviders;
|
||||
}
|
||||
const isPrivateService = (node.flags & NodeFlags.PrivateProvider) !== 0;
|
||||
const isComponent = (node.flags & NodeFlags.Component) !== 0;
|
||||
if (!isPrivateService || isComponent) {
|
||||
currentParent.element.publicProviders[node.provider.tokenKey] = node;
|
||||
currentParent !.element !.publicProviders ![node.provider !.tokenKey] = node;
|
||||
} else {
|
||||
if (!currentElementHasPrivateProviders) {
|
||||
currentElementHasPrivateProviders = true;
|
||||
// Use protoyypical inheritance to not get O(n^2) complexity...
|
||||
currentParent.element.allProviders = Object.create(currentParent.element.publicProviders);
|
||||
currentParent !.element !.allProviders =
|
||||
Object.create(currentParent !.element !.publicProviders);
|
||||
}
|
||||
currentParent.element.allProviders[node.provider.tokenKey] = node;
|
||||
currentParent !.element !.allProviders ![node.provider !.tokenKey] = node;
|
||||
}
|
||||
if (isComponent) {
|
||||
currentParent.element.componentProvider = node;
|
||||
currentParent !.element !.componentProvider = node;
|
||||
}
|
||||
}
|
||||
if (node.childCount) {
|
||||
@ -127,10 +128,10 @@ export function viewDef(
|
||||
currentParent = newParent;
|
||||
}
|
||||
const handleEvent: ViewHandleEventFn = (view, nodeIndex, eventName, event) =>
|
||||
nodes[nodeIndex].element.handleEvent(view, eventName, event);
|
||||
nodes[nodeIndex].element !.handleEvent !(view, eventName, event);
|
||||
return {
|
||||
// Will be filled later...
|
||||
factory: undefined,
|
||||
factory: null,
|
||||
nodeFlags: viewNodeFlags,
|
||||
rootNodeFlags: viewRootNodeFlags,
|
||||
nodeMatchedQueries: viewMatchedQueries, flags,
|
||||
@ -143,7 +144,7 @@ export function viewDef(
|
||||
};
|
||||
}
|
||||
|
||||
function validateNode(parent: NodeDef, node: NodeDef, nodeCount: number) {
|
||||
function validateNode(parent: NodeDef | null, node: NodeDef, nodeCount: number) {
|
||||
const template = node.element && node.element.template;
|
||||
if (template) {
|
||||
if (!template.lastRenderRootNode) {
|
||||
@ -156,7 +157,7 @@ function validateNode(parent: NodeDef, node: NodeDef, nodeCount: number) {
|
||||
}
|
||||
}
|
||||
if (node.flags & NodeFlags.CatProvider) {
|
||||
const parentFlags = parent ? parent.flags : null;
|
||||
const parentFlags = parent ? parent.flags : 0;
|
||||
if ((parentFlags & NodeFlags.TypeElement) === 0) {
|
||||
throw new Error(
|
||||
`Illegal State: Provider/Directive nodes need to be children of elements or anchors, at index ${node.index}!`);
|
||||
@ -186,7 +187,7 @@ export function createEmbeddedView(parent: ViewData, anchorDef: NodeDef, context
|
||||
// embedded views are seen as siblings to the anchor, so we need
|
||||
// to get the parent of the anchor and use it as parentIndex.
|
||||
const view =
|
||||
createView(parent.root, parent.renderer, parent, anchorDef, anchorDef.element.template);
|
||||
createView(parent.root, parent.renderer, parent, anchorDef, anchorDef.element !.template !);
|
||||
initView(view, parent.component, context);
|
||||
createViewNodes(view);
|
||||
return view;
|
||||
@ -200,16 +201,16 @@ export function createRootView(root: RootData, def: ViewDefinition, context?: an
|
||||
}
|
||||
|
||||
function createView(
|
||||
root: RootData, renderer: Renderer2, parent: ViewData, parentNodeDef: NodeDef,
|
||||
root: RootData, renderer: Renderer2, parent: ViewData | null, parentNodeDef: NodeDef | null,
|
||||
def: ViewDefinition): ViewData {
|
||||
const nodes: NodeData[] = new Array(def.nodes.length);
|
||||
const disposables = def.outputCount ? new Array(def.outputCount) : undefined;
|
||||
const disposables = def.outputCount ? new Array(def.outputCount) : null;
|
||||
const view: ViewData = {
|
||||
def,
|
||||
parent,
|
||||
viewContainerParent: undefined, parentNodeDef,
|
||||
context: undefined,
|
||||
component: undefined, nodes,
|
||||
viewContainerParent: null, parentNodeDef,
|
||||
context: null,
|
||||
component: null, nodes,
|
||||
state: ViewState.FirstCheck | ViewState.ChecksEnabled, root, renderer,
|
||||
oldValues: new Array(def.bindingCount), disposables
|
||||
};
|
||||
@ -225,7 +226,7 @@ function createViewNodes(view: ViewData) {
|
||||
let renderHost: any;
|
||||
if (isComponentView(view)) {
|
||||
const hostDef = view.parentNodeDef;
|
||||
renderHost = asElementData(view.parent, hostDef.parent.index).renderElement;
|
||||
renderHost = asElementData(view.parent !, hostDef !.parent !.index).renderElement;
|
||||
}
|
||||
const def = view.def;
|
||||
const nodes = view.nodes;
|
||||
@ -236,10 +237,10 @@ function createViewNodes(view: ViewData) {
|
||||
switch (nodeDef.flags & NodeFlags.Types) {
|
||||
case NodeFlags.TypeElement:
|
||||
const el = createElement(view, renderHost, nodeDef) as any;
|
||||
let componentView: ViewData;
|
||||
let componentView: ViewData = undefined !;
|
||||
if (nodeDef.flags & NodeFlags.ComponentView) {
|
||||
const compViewDef = resolveViewDefinition(nodeDef.element.componentView);
|
||||
const rendererType = nodeDef.element.componentRendererType;
|
||||
const compViewDef = resolveViewDefinition(nodeDef.element !.componentView !);
|
||||
const rendererType = nodeDef.element !.componentRendererType;
|
||||
let compRenderer: Renderer2;
|
||||
if (!rendererType) {
|
||||
compRenderer = view.root.renderer;
|
||||
@ -247,14 +248,14 @@ function createViewNodes(view: ViewData) {
|
||||
compRenderer = view.root.rendererFactory.createRenderer(el, rendererType);
|
||||
}
|
||||
componentView = createView(
|
||||
view.root, compRenderer, view, nodeDef.element.componentProvider, compViewDef);
|
||||
view.root, compRenderer, view, nodeDef.element !.componentProvider, compViewDef);
|
||||
}
|
||||
listenToElementOutputs(view, componentView, nodeDef, el);
|
||||
nodeData = <ElementData>{
|
||||
renderElement: el,
|
||||
componentView,
|
||||
viewContainer: undefined,
|
||||
template: nodeDef.element.template ? createTemplateData(view, nodeDef) : undefined
|
||||
viewContainer: null,
|
||||
template: nodeDef.element !.template ? createTemplateData(view, nodeDef) : undefined
|
||||
};
|
||||
if (nodeDef.flags & NodeFlags.EmbeddedViews) {
|
||||
nodeData.viewContainer = createViewContainerData(view, nodeDef, nodeData);
|
||||
@ -280,7 +281,7 @@ function createViewNodes(view: ViewData) {
|
||||
const instance = createDirectiveInstance(view, nodeDef);
|
||||
nodeData = <ProviderData>{instance};
|
||||
if (nodeDef.flags & NodeFlags.Component) {
|
||||
const compView = asElementData(view, nodeDef.parent.index).componentView;
|
||||
const compView = asElementData(view, nodeDef.parent !.index).componentView;
|
||||
initView(compView, instance, instance);
|
||||
}
|
||||
break;
|
||||
@ -451,8 +452,8 @@ function checkNoChangesQuery(view: ViewData, nodeDef: NodeDef) {
|
||||
const queryList = asQueryList(view, nodeDef.index);
|
||||
if (queryList.dirty) {
|
||||
throw expressionChangedAfterItHasBeenCheckedError(
|
||||
Services.createDebugContext(view, nodeDef.index), `Query ${nodeDef.query.id} not dirty`,
|
||||
`Query ${nodeDef.query.id} dirty`, (view.state & ViewState.FirstCheck) !== 0);
|
||||
Services.createDebugContext(view, nodeDef.index), `Query ${nodeDef.query!.id} not dirty`,
|
||||
`Query ${nodeDef.query!.id} dirty`, (view.state & ViewState.FirstCheck) !== 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -482,9 +483,9 @@ function destroyViewNodes(view: ViewData) {
|
||||
for (let i = 0; i < len; i++) {
|
||||
const def = view.def.nodes[i];
|
||||
if (def.flags & NodeFlags.TypeElement) {
|
||||
view.renderer.destroyNode(asElementData(view, i).renderElement);
|
||||
view.renderer.destroyNode !(asElementData(view, i).renderElement);
|
||||
} else if (def.flags & NodeFlags.TypeText) {
|
||||
view.renderer.destroyNode(asTextData(view, i).renderText);
|
||||
view.renderer.destroyNode !(asTextData(view, i).renderText);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -524,7 +525,7 @@ function execEmbeddedViewsAction(view: ViewData, action: ViewAction) {
|
||||
const nodeDef = def.nodes[i];
|
||||
if (nodeDef.flags & NodeFlags.EmbeddedViews) {
|
||||
// a leaf
|
||||
const embeddedViews = asElementData(view, i).viewContainer._embeddedViews;
|
||||
const embeddedViews = asElementData(view, i).viewContainer !._embeddedViews;
|
||||
for (let k = 0; k < embeddedViews.length; k++) {
|
||||
callViewAction(embeddedViews[k], action);
|
||||
}
|
||||
|
@ -10,13 +10,14 @@ import {ElementData, Services, ViewData} from './types';
|
||||
import {RenderNodeAction, declaredViewContainer, renderNode, visitRootRenderNodes} from './util';
|
||||
|
||||
export function attachEmbeddedView(
|
||||
parentView: ViewData, elementData: ElementData, viewIndex: number, view: ViewData) {
|
||||
let embeddedViews = elementData.viewContainer._embeddedViews;
|
||||
if (viewIndex == null) {
|
||||
parentView: ViewData, elementData: ElementData, viewIndex: number | undefined | null,
|
||||
view: ViewData) {
|
||||
let embeddedViews = elementData.viewContainer !._embeddedViews;
|
||||
if (viewIndex === null || viewIndex === undefined) {
|
||||
viewIndex = embeddedViews.length;
|
||||
}
|
||||
view.viewContainerParent = parentView;
|
||||
addToArray(embeddedViews, viewIndex, view);
|
||||
addToArray(embeddedViews, viewIndex !, view);
|
||||
const dvcElementData = declaredViewContainer(view);
|
||||
if (dvcElementData && dvcElementData !== elementData) {
|
||||
let projectedViews = dvcElementData.template._projectedViews;
|
||||
@ -28,12 +29,12 @@ export function attachEmbeddedView(
|
||||
|
||||
Services.dirtyParentQueries(view);
|
||||
|
||||
const prevView = viewIndex > 0 ? embeddedViews[viewIndex - 1] : null;
|
||||
const prevView = viewIndex ! > 0 ? embeddedViews[viewIndex ! - 1] : null;
|
||||
renderAttachEmbeddedView(elementData, prevView, view);
|
||||
}
|
||||
|
||||
export function detachEmbeddedView(elementData: ElementData, viewIndex: number): ViewData {
|
||||
const embeddedViews = elementData.viewContainer._embeddedViews;
|
||||
export function detachEmbeddedView(elementData: ElementData, viewIndex?: number): ViewData|null {
|
||||
const embeddedViews = elementData.viewContainer !._embeddedViews;
|
||||
if (viewIndex == null || viewIndex >= embeddedViews.length) {
|
||||
viewIndex = embeddedViews.length - 1;
|
||||
}
|
||||
@ -41,7 +42,7 @@ export function detachEmbeddedView(elementData: ElementData, viewIndex: number):
|
||||
return null;
|
||||
}
|
||||
const view = embeddedViews[viewIndex];
|
||||
view.viewContainerParent = undefined;
|
||||
view.viewContainerParent = null;
|
||||
removeFromArray(embeddedViews, viewIndex);
|
||||
|
||||
const dvcElementData = declaredViewContainer(view);
|
||||
@ -59,7 +60,7 @@ export function detachEmbeddedView(elementData: ElementData, viewIndex: number):
|
||||
|
||||
export function moveEmbeddedView(
|
||||
elementData: ElementData, oldViewIndex: number, newViewIndex: number): ViewData {
|
||||
const embeddedViews = elementData.viewContainer._embeddedViews;
|
||||
const embeddedViews = elementData.viewContainer !._embeddedViews;
|
||||
const view = embeddedViews[oldViewIndex];
|
||||
removeFromArray(embeddedViews, oldViewIndex);
|
||||
if (newViewIndex == null) {
|
||||
@ -79,9 +80,10 @@ export function moveEmbeddedView(
|
||||
return view;
|
||||
}
|
||||
|
||||
function renderAttachEmbeddedView(elementData: ElementData, prevView: ViewData, view: ViewData) {
|
||||
const prevRenderNode =
|
||||
prevView ? renderNode(prevView, prevView.def.lastRenderRootNode) : elementData.renderElement;
|
||||
function renderAttachEmbeddedView(
|
||||
elementData: ElementData, prevView: ViewData | null, view: ViewData) {
|
||||
const prevRenderNode = prevView ? renderNode(prevView, prevView.def.lastRenderRootNode !) :
|
||||
elementData.renderElement;
|
||||
const parentNode = view.renderer.parentNode(prevRenderNode);
|
||||
const nextSibling = view.renderer.nextSibling(prevRenderNode);
|
||||
// Note: We can't check if `nextSibling` is present, as on WebWorkers it will always be!
|
||||
|
@ -60,7 +60,7 @@ export function main() {
|
||||
engine.flush();
|
||||
|
||||
expect(getLog().length).toEqual(1);
|
||||
expect(getLog().pop().keyframes).toEqual([
|
||||
expect(getLog().pop() !.keyframes).toEqual([
|
||||
{offset: 0, opacity: '0'}, {offset: 1, opacity: '1'}
|
||||
]);
|
||||
});
|
||||
@ -96,7 +96,7 @@ export function main() {
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
expect(getLog().pop().keyframes).toEqual([
|
||||
expect(getLog().pop() !.keyframes).toEqual([
|
||||
{offset: 0, width: '0px'}, {offset: 1, width: '100px'}
|
||||
]);
|
||||
|
||||
@ -105,7 +105,7 @@ export function main() {
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
expect(getLog().pop().keyframes).toEqual([
|
||||
expect(getLog().pop() !.keyframes).toEqual([
|
||||
{offset: 0, height: '0px'}, {offset: 1, height: '100px'}
|
||||
]);
|
||||
|
||||
@ -114,7 +114,7 @@ export function main() {
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
expect(getLog().pop().keyframes).toEqual([
|
||||
expect(getLog().pop() !.keyframes).toEqual([
|
||||
{offset: 0, height: '0px'}, {offset: 1, height: '100px'}
|
||||
]);
|
||||
|
||||
@ -123,7 +123,7 @@ export function main() {
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
expect(getLog().pop().keyframes).toEqual([
|
||||
expect(getLog().pop() !.keyframes).toEqual([
|
||||
{offset: 0, height: '0px'}, {offset: 1, height: '100px'}
|
||||
]);
|
||||
|
||||
@ -132,7 +132,7 @@ export function main() {
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
expect(getLog().pop().keyframes).toEqual([
|
||||
expect(getLog().pop() !.keyframes).toEqual([
|
||||
{offset: 0, height: '0px'}, {offset: 1, height: '100px'}
|
||||
]);
|
||||
|
||||
@ -142,7 +142,7 @@ export function main() {
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
expect(getLog().pop().keyframes).toEqual([
|
||||
expect(getLog().pop() !.keyframes).toEqual([
|
||||
{offset: 0, width: '0px'}, {offset: 1, width: '100px'}
|
||||
]);
|
||||
});
|
||||
@ -174,7 +174,7 @@ export function main() {
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
expect(getLog().pop().keyframes).toEqual([
|
||||
expect(getLog().pop() !.keyframes).toEqual([
|
||||
{offset: 0, opacity: '0'}, {offset: 1, opacity: '1'}
|
||||
]);
|
||||
|
||||
@ -182,7 +182,7 @@ export function main() {
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
expect(getLog().pop().keyframes).toEqual([
|
||||
expect(getLog().pop() !.keyframes).toEqual([
|
||||
{offset: 0, opacity: '1'}, {offset: 1, opacity: '0'}
|
||||
]);
|
||||
});
|
||||
@ -233,7 +233,7 @@ export function main() {
|
||||
engine.flush();
|
||||
expect(getLog().length).toEqual(1);
|
||||
|
||||
const data = getLog().pop();
|
||||
const data = getLog().pop() !;
|
||||
expect(data.element).toEqual(fixture.elementRef.nativeElement);
|
||||
expect(data.keyframes).toEqual([{offset: 0, opacity: '0'}, {offset: 1, opacity: '1'}]);
|
||||
}));
|
||||
@ -679,8 +679,8 @@ export function main() {
|
||||
|
||||
expect(getLog().length).toEqual(2);
|
||||
|
||||
const player2 = getLog().pop();
|
||||
const player1 = getLog().pop();
|
||||
const player2 = getLog().pop() !;
|
||||
const player1 = getLog().pop() !;
|
||||
|
||||
expect(player2.keyframes).toEqual([
|
||||
{width: AUTO_STYLE, offset: 0},
|
||||
@ -712,7 +712,7 @@ export function main() {
|
||||
]
|
||||
})
|
||||
class Cmp {
|
||||
public exp: string;
|
||||
public exp: string|null;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||
|
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* @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 {animate, style, transition, trigger} from '@angular/animations';
|
||||
import {AnimationDriver, ɵAnimationEngine} from '@angular/animations/browser';
|
||||
import {ɵDomAnimationEngine, ɵWebAnimationsDriver, ɵWebAnimationsPlayer, ɵsupportsWebAnimations} from '@angular/animations/browser'
|
||||
import {Component, ViewChild} from '@angular/core';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
|
||||
import {TestBed} from '../../testing';
|
||||
|
||||
export function main() {
|
||||
// these tests are only mean't to be run within the DOM (for now)
|
||||
if (typeof Element == 'undefined' || !ɵsupportsWebAnimations()) return;
|
||||
|
||||
describe('animation integration tests using web animations', function() {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{provide: AnimationDriver, useClass: ɵWebAnimationsDriver}],
|
||||
imports: [BrowserAnimationsModule]
|
||||
});
|
||||
});
|
||||
|
||||
it('should animate a component that captures height during an animation', () => {
|
||||
@Component({
|
||||
selector: 'if-cmp',
|
||||
template: `
|
||||
<div *ngIf="exp" #element [@myAnimation]="exp">
|
||||
hello {{ text }}
|
||||
</div>
|
||||
`,
|
||||
animations: [trigger(
|
||||
'myAnimation',
|
||||
[
|
||||
transition('* => *', [style({height: '0px'}), animate(1000, style({height: '*'}))]),
|
||||
])]
|
||||
})
|
||||
class Cmp {
|
||||
exp: any = false;
|
||||
text: string;
|
||||
|
||||
@ViewChild('element') public element: any;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||
|
||||
const engine = TestBed.get(ɵAnimationEngine);
|
||||
const fixture = TestBed.createComponent(Cmp);
|
||||
const cmp = fixture.componentInstance;
|
||||
cmp.exp = 1;
|
||||
cmp.text = '';
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
const element = cmp.element.nativeElement;
|
||||
element.style.lineHeight = '20px';
|
||||
element.style.width = '50px';
|
||||
|
||||
cmp.exp = 2;
|
||||
cmp.text = '12345';
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
let player = engine.activePlayers.pop() as ɵWebAnimationsPlayer;
|
||||
player.setPosition(1);
|
||||
|
||||
assertStyleBetween(element, 'height', 15, 25);
|
||||
|
||||
cmp.exp = 3;
|
||||
cmp.text = '12345-12345-12345-12345';
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
player = engine.activePlayers.pop() as ɵWebAnimationsPlayer;
|
||||
player.setPosition(1);
|
||||
assertStyleBetween(element, 'height', 35, 45);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function assertStyleBetween(
|
||||
element: any, prop: string, start: string | number, end: string | number) {
|
||||
const style = (window.getComputedStyle(element) as any)[prop] as string;
|
||||
if (typeof start == 'number' && typeof end == 'number') {
|
||||
const value = parseFloat(style);
|
||||
expect(value).toBeGreaterThan(start);
|
||||
expect(value).toBeLessThan(end);
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ export function main() {
|
||||
|
||||
function createModule(providers?: any[]): Type<any>;
|
||||
function createModule(options: CreateModuleOptions): Type<any>;
|
||||
function createModule(providersOrOptions: any[] | CreateModuleOptions): Type<any> {
|
||||
function createModule(providersOrOptions: any[] | CreateModuleOptions | undefined): Type<any> {
|
||||
let options: CreateModuleOptions = {};
|
||||
if (providersOrOptions instanceof Array) {
|
||||
options = {providers: providersOrOptions};
|
||||
@ -92,7 +92,8 @@ export function main() {
|
||||
createRootEl();
|
||||
const modFactory = compiler.compileModuleSync(SomeModule);
|
||||
const module = modFactory.create(TestBed);
|
||||
const cmpFactory = module.componentFactoryResolver.resolveComponentFactory(SomeComponent);
|
||||
const cmpFactory =
|
||||
module.componentFactoryResolver.resolveComponentFactory(SomeComponent) !;
|
||||
const component = app.bootstrap(cmpFactory);
|
||||
|
||||
// The component should see the child module providers
|
||||
@ -388,7 +389,7 @@ export function main() {
|
||||
vc.insert(hostView);
|
||||
expect(() => appRef.attachView(hostView))
|
||||
.toThrowError('This view is already attached to a ViewContainer!');
|
||||
hostView = vc.detach(0);
|
||||
hostView = vc.detach(0) !;
|
||||
|
||||
appRef.attachView(hostView);
|
||||
expect(() => vc.insert(hostView))
|
||||
|
@ -309,7 +309,7 @@ export function main() {
|
||||
|
||||
function modifyArrayUsingOperation(
|
||||
arr: number[], endData: any[], prev: number, next: number) {
|
||||
let value: number = null;
|
||||
let value: number = null !;
|
||||
if (prev == null) {
|
||||
value = endData[next];
|
||||
arr.splice(next, 0, value);
|
||||
@ -472,7 +472,7 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should throw when given an invalid collection', () => {
|
||||
expect(() => differ.diff('invalid')).toThrowError('Error trying to diff \'invalid\'');
|
||||
expect(() => differ.diff('invalid')).toThrowError(/Error trying to diff 'invalid'/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import {DefaultKeyValueDiffer, DefaultKeyValueDifferFactory} from '@angular/core/src/change_detection/differs/default_keyvalue_differ';
|
||||
import {afterEach, beforeEach, describe, expect, it} from '@angular/core/testing/src/testing_internal';
|
||||
import {kvChangesAsString} from '../../change_detection/util';
|
||||
|
||||
// todo(vicb): Update the code & tests for object equality
|
||||
@ -22,7 +21,7 @@ export function main() {
|
||||
m = new Map();
|
||||
});
|
||||
|
||||
afterEach(() => { differ = null; });
|
||||
afterEach(() => { differ = null !; });
|
||||
|
||||
it('should detect additions', () => {
|
||||
differ.check(m);
|
||||
@ -55,21 +54,17 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should expose previous and current value', () => {
|
||||
let previous: any /** TODO #9100 */, current: any /** TODO #9100 */;
|
||||
|
||||
m.set(1, 10);
|
||||
differ.check(m);
|
||||
|
||||
m.set(1, 20);
|
||||
differ.check(m);
|
||||
|
||||
differ.forEachChangedItem((record: any /** TODO #9100 */) => {
|
||||
previous = record.previousValue;
|
||||
current = record.currentValue;
|
||||
differ.forEachChangedItem((record: any) => {
|
||||
expect(record.previousValue).toEqual(10);
|
||||
expect(record.currentValue).toEqual(20);
|
||||
});
|
||||
|
||||
expect(previous).toEqual(10);
|
||||
expect(current).toEqual(20);
|
||||
});
|
||||
|
||||
it('should do basic map watching', () => {
|
||||
@ -198,6 +193,19 @@ export function main() {
|
||||
changes: ['b[0->1]', 'a[0->1]']
|
||||
}));
|
||||
});
|
||||
|
||||
it('should when the first item is moved', () => {
|
||||
differ.check({a: 'a', b: 'b'});
|
||||
differ.check({c: 'c', a: 'a'});
|
||||
|
||||
expect(differ.toString()).toEqual(kvChangesAsString({
|
||||
map: ['c[null->c]', 'a'],
|
||||
previous: ['a', 'b[b->null]'],
|
||||
additions: ['c[null->c]'],
|
||||
removals: ['b[b->null]']
|
||||
}));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('diff', () => {
|
||||
@ -220,8 +228,7 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should throw when given an invalid collection', () => {
|
||||
expect(() => differ.diff(<any>'invalid'))
|
||||
.toThrowError('Error trying to diff \'invalid\'');
|
||||
expect(() => differ.diff(<any>'invalid')).toThrowError(/Error trying to diff 'invalid'/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -318,7 +318,7 @@ export function main() {
|
||||
fixture = TestBed.createComponent(LocalsComp);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.debugElement.children[0].references['alice']).toBeAnInstanceOf(MyDir);
|
||||
expect(fixture.debugElement.children[0].references !['alice']).toBeAnInstanceOf(MyDir);
|
||||
});
|
||||
|
||||
it('should allow injecting from the element injector', () => {
|
||||
|
@ -79,7 +79,7 @@ export function main() {
|
||||
];
|
||||
|
||||
function createInjector(
|
||||
providers: Provider[], parent: ReflectiveInjector = null): ReflectiveInjector_ {
|
||||
providers: Provider[], parent?: ReflectiveInjector | null): ReflectiveInjector_ {
|
||||
const resolvedProviders = ReflectiveInjector.resolve(providers.concat(dynamicProviders));
|
||||
if (parent != null) {
|
||||
return <ReflectiveInjector_>parent.createChildFromResolved(resolvedProviders);
|
||||
|
@ -100,7 +100,7 @@ export function main() {
|
||||
const headEl = defaultDoc.head;
|
||||
getDOM().appendChild(headEl, baseEl);
|
||||
|
||||
const baseHref = getDOM().getBaseHref(defaultDoc);
|
||||
const baseHref = getDOM().getBaseHref(defaultDoc) !;
|
||||
getDOM().removeChild(headEl, baseEl);
|
||||
getDOM().resetBaseElement();
|
||||
|
||||
|
@ -261,14 +261,14 @@ export function main() {
|
||||
describe('safe navigation operator', () => {
|
||||
it('should support reading properties of nulls', fakeAsync(() => {
|
||||
const ctx = _bindSimpleValue('address?.city', Person);
|
||||
ctx.componentInstance.address = null;
|
||||
ctx.componentInstance.address = null !;
|
||||
ctx.detectChanges(false);
|
||||
expect(renderLog.log).toEqual(['someProp=null']);
|
||||
}));
|
||||
|
||||
it('should support calling methods on nulls', fakeAsync(() => {
|
||||
const ctx = _bindSimpleValue('address?.toString()', Person);
|
||||
ctx.componentInstance.address = null;
|
||||
ctx.componentInstance.address = null !;
|
||||
ctx.detectChanges(false);
|
||||
expect(renderLog.log).toEqual(['someProp=null']);
|
||||
}));
|
||||
@ -289,7 +289,7 @@ export function main() {
|
||||
|
||||
it('should support short-circuting safe navigation', fakeAsync(() => {
|
||||
const ctx = _bindSimpleValue('value?.address.city', PersonHolder);
|
||||
ctx.componentInstance.value = null;
|
||||
ctx.componentInstance.value = null !;
|
||||
ctx.detectChanges(false);
|
||||
expect(renderLog.log).toEqual(['someProp=null']);
|
||||
}));
|
||||
@ -317,7 +317,7 @@ export function main() {
|
||||
expect(() => {
|
||||
const ctx = _bindSimpleValue('value?.address.city', PersonHolder);
|
||||
const person = new Person();
|
||||
person.address = null;
|
||||
person.address = null !;
|
||||
ctx.componentInstance.value = person;
|
||||
ctx.detectChanges(false);
|
||||
}).toThrow();
|
||||
@ -553,7 +553,7 @@ export function main() {
|
||||
it('should call pure pipes only if the arguments change', fakeAsync(() => {
|
||||
const ctx = _bindSimpleValue('name | countingPipe', Person);
|
||||
// change from undefined -> null
|
||||
ctx.componentInstance.name = null;
|
||||
ctx.componentInstance.name = null !;
|
||||
ctx.detectChanges(false);
|
||||
expect(renderLog.loggedValues).toEqual(['null state:0']);
|
||||
ctx.detectChanges(false);
|
||||
@ -1620,10 +1620,10 @@ class TestLocals {
|
||||
class Person {
|
||||
age: number;
|
||||
name: string;
|
||||
address: Address = null;
|
||||
address: Address|null = null;
|
||||
phones: number[];
|
||||
|
||||
init(name: string, address: Address = null) {
|
||||
init(name: string, address: Address|null = null) {
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
const compFixture = TestBed.createComponent(MainComp);
|
||||
const mainComp: MainComp = compFixture.componentInstance;
|
||||
expect(compFixture.componentRef.injector.get(ComponentFactoryResolver)).toBe(mainComp.cfr);
|
||||
const cf = mainComp.cfr.resolveComponentFactory(ChildComp);
|
||||
const cf = mainComp.cfr.resolveComponentFactory(ChildComp) !;
|
||||
expect(cf.componentType).toBe(ChildComp);
|
||||
});
|
||||
|
||||
@ -51,8 +51,8 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
const mainComp: CompWithAnalyzeEntryComponentsProvider = compFixture.componentInstance;
|
||||
const cfr: ComponentFactoryResolver =
|
||||
compFixture.componentRef.injector.get(ComponentFactoryResolver);
|
||||
expect(cfr.resolveComponentFactory(ChildComp).componentType).toBe(ChildComp);
|
||||
expect(cfr.resolveComponentFactory(NestedChildComp).componentType).toBe(NestedChildComp);
|
||||
expect(cfr.resolveComponentFactory(ChildComp) !.componentType).toBe(ChildComp);
|
||||
expect(cfr.resolveComponentFactory(NestedChildComp) !.componentType).toBe(NestedChildComp);
|
||||
});
|
||||
|
||||
it('should be able to get a component form a parent component (view hiearchy)', () => {
|
||||
@ -62,10 +62,10 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
const childCompEl = compFixture.debugElement.children[0];
|
||||
const childComp: ChildComp = childCompEl.componentInstance;
|
||||
// declared on ChildComp directly
|
||||
expect(childComp.cfr.resolveComponentFactory(NestedChildComp).componentType)
|
||||
expect(childComp.cfr.resolveComponentFactory(NestedChildComp) !.componentType)
|
||||
.toBe(NestedChildComp);
|
||||
// inherited from MainComp
|
||||
expect(childComp.cfr.resolveComponentFactory(ChildComp).componentType).toBe(ChildComp);
|
||||
expect(childComp.cfr.resolveComponentFactory(ChildComp) !.componentType).toBe(ChildComp);
|
||||
});
|
||||
|
||||
it('should not be able to get components from a parent component (content hierarchy)', () => {
|
||||
@ -75,7 +75,8 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
const compFixture = TestBed.createComponent(MainComp);
|
||||
const nestedChildCompEl = compFixture.debugElement.children[0].children[0];
|
||||
const nestedChildComp: NestedChildComp = nestedChildCompEl.componentInstance;
|
||||
expect(nestedChildComp.cfr.resolveComponentFactory(ChildComp).componentType).toBe(ChildComp);
|
||||
expect(nestedChildComp.cfr.resolveComponentFactory(ChildComp) !.componentType)
|
||||
.toBe(ChildComp);
|
||||
expect(() => nestedChildComp.cfr.resolveComponentFactory(NestedChildComp))
|
||||
.toThrow(noComponentFactoryError(NestedChildComp));
|
||||
});
|
||||
|
@ -56,7 +56,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
const template = '<div>{{null}}{{ctxProp}}</div>';
|
||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
fixture.componentInstance.ctxProp = null;
|
||||
fixture.componentInstance.ctxProp = null !;
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('');
|
||||
@ -134,7 +134,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
expect(getDOM().getAttribute(fixture.debugElement.children[0].nativeElement, 'foo'))
|
||||
.toEqual('bar');
|
||||
|
||||
fixture.componentInstance.ctxProp = null;
|
||||
fixture.componentInstance.ctxProp = null !;
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().hasAttribute(fixture.debugElement.children[0].nativeElement, 'foo'))
|
||||
.toBeFalsy();
|
||||
@ -151,7 +151,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
expect(getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'height'))
|
||||
.toEqual('10px');
|
||||
|
||||
fixture.componentInstance.ctxProp = null;
|
||||
fixture.componentInstance.ctxProp = null !;
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'height'))
|
||||
.toEqual('');
|
||||
@ -264,7 +264,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
fixture.componentInstance.ctxProp = 'a';
|
||||
fixture.detectChanges();
|
||||
|
||||
const dir = fixture.debugElement.children[0].references['dir'];
|
||||
const dir = fixture.debugElement.children[0].references !['dir'];
|
||||
expect(dir.dirProp).toEqual('aa');
|
||||
});
|
||||
});
|
||||
@ -450,7 +450,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
expect(fixture.debugElement.children[0].children[0].references['alice'])
|
||||
expect(fixture.debugElement.children[0].children[0].references !['alice'])
|
||||
.toBeAnInstanceOf(ChildComp);
|
||||
});
|
||||
|
||||
@ -460,7 +460,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
expect(fixture.debugElement.children[0].children[0].references['localdir'])
|
||||
expect(fixture.debugElement.children[0].children[0].references !['localdir'])
|
||||
.toBeAnInstanceOf(ExportDir);
|
||||
});
|
||||
|
||||
@ -486,8 +486,8 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
|
||||
const pEl = fixture.debugElement.children[0];
|
||||
|
||||
const alice = pEl.children[0].references['alice'];
|
||||
const bob = pEl.children[1].references['bob'];
|
||||
const alice = pEl.children[0].references !['alice'];
|
||||
const bob = pEl.children[1].references !['bob'];
|
||||
expect(alice).toBeAnInstanceOf(ChildComp);
|
||||
expect(bob).toBeAnInstanceOf(ChildComp);
|
||||
expect(alice).not.toBe(bob);
|
||||
@ -499,7 +499,8 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
expect(fixture.debugElement.children[0].references['alice']).toBeAnInstanceOf(ChildComp);
|
||||
expect(fixture.debugElement.children[0].references !['alice'])
|
||||
.toBeAnInstanceOf(ChildComp);
|
||||
});
|
||||
|
||||
it('should assign the element instance to a user-defined variable', () => {
|
||||
@ -508,7 +509,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
const value = fixture.debugElement.children[0].children[0].references['alice'];
|
||||
const value = fixture.debugElement.children[0].children[0].references !['alice'];
|
||||
expect(value).not.toBe(null);
|
||||
expect(value.tagName.toLowerCase()).toEqual('div');
|
||||
});
|
||||
@ -520,7 +521,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
MyComp, {set: {template: '<ng-template ref-alice></ng-template>'}})
|
||||
.createComponent(MyComp);
|
||||
|
||||
const value = fixture.debugElement.childNodes[0].references['alice'];
|
||||
const value = fixture.debugElement.childNodes[0].references !['alice'];
|
||||
expect(value.createEmbeddedView).toBeTruthy();
|
||||
});
|
||||
|
||||
@ -530,7 +531,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
expect(fixture.debugElement.children[0].children[0].references['superAlice'])
|
||||
expect(fixture.debugElement.children[0].children[0].references !['superAlice'])
|
||||
.toBeAnInstanceOf(ChildComp);
|
||||
});
|
||||
});
|
||||
@ -559,7 +560,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
const cmp = fixture.debugElement.children[0].references['cmp'];
|
||||
const cmp = fixture.debugElement.children[0].references !['cmp'];
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(cmp.numberOfChecks).toEqual(1);
|
||||
@ -580,7 +581,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
const cmp = fixture.debugElement.children[0].references['cmp'];
|
||||
const cmp = fixture.debugElement.children[0].references !['cmp'];
|
||||
|
||||
fixture.componentInstance.ctxProp = 'one';
|
||||
fixture.detectChanges();
|
||||
@ -654,7 +655,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
const cmp = fixture.debugElement.children[0].references['cmp'];
|
||||
const cmp = fixture.debugElement.children[0].references !['cmp'];
|
||||
|
||||
fixture.componentInstance.ctxProp = 'one';
|
||||
fixture.detectChanges();
|
||||
@ -675,7 +676,8 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
|
||||
tick();
|
||||
|
||||
const cmp: PushCmpWithAsyncPipe = fixture.debugElement.children[0].references['cmp'];
|
||||
const cmp: PushCmpWithAsyncPipe =
|
||||
fixture.debugElement.children[0].references !['cmp'];
|
||||
fixture.detectChanges();
|
||||
expect(cmp.numberOfChecks).toEqual(1);
|
||||
|
||||
@ -707,7 +709,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
const childComponent =
|
||||
fixture.debugElement.children[0].children[0].children[0].references['child'];
|
||||
fixture.debugElement.children[0].children[0].children[0].references !['child'];
|
||||
expect(childComponent.myHost).toBeAnInstanceOf(SomeDirective);
|
||||
});
|
||||
|
||||
@ -729,7 +731,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
|
||||
const tc = fixture.debugElement.children[0].children[0].children[0];
|
||||
|
||||
const childComponent = tc.references['child'];
|
||||
const childComponent = tc.references !['child'];
|
||||
expect(childComponent.myHost).toBeAnInstanceOf(SomeDirective);
|
||||
});
|
||||
|
||||
@ -1232,7 +1234,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
const comp = fixture.debugElement.children[0].children[0].references['consuming'];
|
||||
const comp = fixture.debugElement.children[0].children[0].references !['consuming'];
|
||||
expect(comp.injectable).toBeAnInstanceOf(InjectableService);
|
||||
});
|
||||
|
||||
@ -1248,7 +1250,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
TestBed.overrideComponent(DirectiveProvidingInjectableInView, {set: {template}});
|
||||
const fixture = TestBed.createComponent(DirectiveProvidingInjectableInView);
|
||||
|
||||
const comp = fixture.debugElement.children[0].references['consuming'];
|
||||
const comp = fixture.debugElement.children[0].references !['consuming'];
|
||||
expect(comp.injectable).toBeAnInstanceOf(InjectableService);
|
||||
});
|
||||
|
||||
@ -1276,7 +1278,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
const comp = fixture.debugElement.children[0].children[0].references['dir'];
|
||||
const comp = fixture.debugElement.children[0].children[0].references !['dir'];
|
||||
expect(comp.directive.injectable).toBeAnInstanceOf(InjectableService);
|
||||
});
|
||||
|
||||
@ -1326,7 +1328,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
const providing = fixture.debugElement.children[0].references['providing'];
|
||||
const providing = fixture.debugElement.children[0].references !['providing'];
|
||||
expect(providing.created).toBe(false);
|
||||
|
||||
fixture.componentInstance.ctxBoolProp = true;
|
||||
@ -1363,7 +1365,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
});
|
||||
|
||||
it('should use a default element name for components without selectors', () => {
|
||||
let noSelectorComponentFactory: ComponentFactory<SomeComponent>;
|
||||
let noSelectorComponentFactory: ComponentFactory<SomeComponent> = undefined !;
|
||||
|
||||
@Component({template: '----'})
|
||||
class NoSelectorComponent {
|
||||
@ -1374,7 +1376,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
constructor(componentFactoryResolver: ComponentFactoryResolver) {
|
||||
// grab its own component factory
|
||||
noSelectorComponentFactory =
|
||||
componentFactoryResolver.resolveComponentFactory(NoSelectorComponent);
|
||||
componentFactoryResolver.resolveComponentFactory(NoSelectorComponent) !;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1843,7 +1845,8 @@ class DynamicViewport {
|
||||
|
||||
this.injector = ReflectiveInjector.resolveAndCreate(
|
||||
[{provide: MyService, useValue: myService}], vc.injector);
|
||||
this.componentFactory = componentFactoryResolver.resolveComponentFactory(ChildCompUsingService);
|
||||
this.componentFactory =
|
||||
componentFactoryResolver.resolveComponentFactory(ChildCompUsingService) !;
|
||||
}
|
||||
|
||||
create() { this.vc.createComponent(this.componentFactory, this.vc.length, this.injector); }
|
||||
@ -1970,7 +1973,7 @@ class MyComp {
|
||||
})
|
||||
class ChildComp {
|
||||
ctxProp: string;
|
||||
dirProp: string;
|
||||
dirProp: string|null;
|
||||
constructor(service: MyService) {
|
||||
this.ctxProp = service.greeting;
|
||||
this.dirProp = null;
|
||||
@ -2006,7 +2009,7 @@ class CompWithHost {
|
||||
@Component({selector: '[child-cmp2]', viewProviders: [MyService]})
|
||||
class ChildComp2 {
|
||||
ctxProp: string;
|
||||
dirProp: string;
|
||||
dirProp: string|null;
|
||||
constructor(service: MyService) {
|
||||
this.ctxProp = service.greeting;
|
||||
this.dirProp = null;
|
||||
@ -2277,7 +2280,7 @@ class EventBus {
|
||||
|
||||
@Directive({
|
||||
selector: 'grand-parent-providing-event-bus',
|
||||
providers: [{provide: EventBus, useValue: new EventBus(null, 'grandparent')}]
|
||||
providers: [{provide: EventBus, useValue: new EventBus(null !, 'grandparent')}]
|
||||
})
|
||||
class GrandParentProvidingEventBus {
|
||||
bus: EventBus;
|
||||
@ -2313,7 +2316,7 @@ class ChildConsumingEventBus {
|
||||
|
||||
@Directive({selector: '[someImpvp]', inputs: ['someImpvp']})
|
||||
class SomeImperativeViewport {
|
||||
view: EmbeddedViewRef<Object>;
|
||||
view: EmbeddedViewRef<Object>|null;
|
||||
anchor: any;
|
||||
constructor(
|
||||
public vc: ViewContainerRef, public templateRef: TemplateRef<Object>,
|
||||
|
@ -132,7 +132,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
fixture.detectChanges();
|
||||
const q = fixture.debugElement.children[0].references['q'];
|
||||
const q = fixture.debugElement.children[0].references !['q'];
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(q.textDirChildren.length).toEqual(1);
|
||||
@ -145,7 +145,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
fixture.detectChanges();
|
||||
const q = fixture.debugElement.children[0].references['q'];
|
||||
const q = fixture.debugElement.children[0].references !['q'];
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(q.textDirChildren.length).toEqual(1);
|
||||
@ -156,7 +156,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
|
||||
@Directive({selector: '[text]'})
|
||||
class TextDirective {
|
||||
@Input() public text: string = null;
|
||||
@Input() public text: string|null = null;
|
||||
}
|
||||
|
||||
@Component({selector: 'needs-content-children', template: ''})
|
||||
|
@ -125,18 +125,19 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
injector = _injector;
|
||||
}));
|
||||
|
||||
function createModule<T>(moduleType: Type<T>, parentInjector: Injector = null): NgModuleRef<T> {
|
||||
function createModule<T>(
|
||||
moduleType: Type<T>, parentInjector?: Injector | null): NgModuleRef<T> {
|
||||
return compiler.compileModuleSync(moduleType).create(parentInjector);
|
||||
}
|
||||
|
||||
function createComp<T>(compType: Type<T>, moduleType: Type<any>): ComponentFixture<T> {
|
||||
const ngModule = createModule(moduleType, injector);
|
||||
|
||||
const cf = ngModule.componentFactoryResolver.resolveComponentFactory(compType);
|
||||
const cf = ngModule.componentFactoryResolver.resolveComponentFactory(compType) !;
|
||||
|
||||
const comp = cf.create(Injector.NULL);
|
||||
|
||||
return new ComponentFixture(comp, null, false);
|
||||
return new ComponentFixture(comp, null !, false);
|
||||
}
|
||||
|
||||
describe('errors', () => {
|
||||
@ -291,7 +292,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
}
|
||||
|
||||
const ngModule = createModule(SomeModule);
|
||||
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp).componentType)
|
||||
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType)
|
||||
.toBe(SomeComp);
|
||||
expect(ngModule.injector.get(ComponentFactoryResolver)
|
||||
.resolveComponentFactory(SomeComp)
|
||||
@ -341,7 +342,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
}
|
||||
|
||||
const ngModule = createModule(SomeModule);
|
||||
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp).componentType)
|
||||
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType)
|
||||
.toBe(SomeComp);
|
||||
expect(ngModule.injector.get(ComponentFactoryResolver)
|
||||
.resolveComponentFactory(SomeComp)
|
||||
@ -359,7 +360,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
}
|
||||
|
||||
const ngModule = createModule(SomeModule);
|
||||
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp).componentType)
|
||||
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType)
|
||||
.toBe(SomeComp);
|
||||
expect(ngModule.injector.get(ComponentFactoryResolver)
|
||||
.resolveComponentFactory(SomeComp)
|
||||
@ -377,7 +378,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
}
|
||||
|
||||
const ngModule = createModule(SomeModule);
|
||||
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp).componentType)
|
||||
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType)
|
||||
.toBe(SomeComp);
|
||||
expect(ngModule.injector.get(ComponentFactoryResolver)
|
||||
.resolveComponentFactory(SomeComp)
|
||||
@ -394,7 +395,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
}
|
||||
|
||||
const ngModule = createModule(SomeModule);
|
||||
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp).componentType)
|
||||
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType)
|
||||
.toBe(SomeComp);
|
||||
});
|
||||
|
||||
@ -605,7 +606,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
let moduleType: any = null;
|
||||
|
||||
|
||||
function createInjector(providers: Provider[], parent: Injector = null): Injector {
|
||||
function createInjector(providers: Provider[], parent?: Injector | null): Injector {
|
||||
@NgModule({providers: providers})
|
||||
class SomeModule {
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should support moving non projected light dom around', () => {
|
||||
let sourceDirective: ManualViewportDirective;
|
||||
let sourceDirective: ManualViewportDirective = undefined !;
|
||||
|
||||
@Directive({selector: '[manual]'})
|
||||
class ManualViewportDirective {
|
||||
|
@ -67,7 +67,7 @@ export function main() {
|
||||
'<needs-content-children #q><div text="foo"></div></needs-content-children>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
|
||||
const q = view.debugElement.children[0].references['q'];
|
||||
const q = view.debugElement.children[0].references !['q'];
|
||||
view.detectChanges();
|
||||
expect(q.textDirChildren.length).toEqual(1);
|
||||
expect(q.numberOfChildrenAfterContentInit).toEqual(1);
|
||||
@ -79,7 +79,7 @@ export function main() {
|
||||
const view = createTestCmp(MyComp0, template);
|
||||
view.componentInstance.shouldShow = true;
|
||||
view.detectChanges();
|
||||
const q: NeedsContentChild = view.debugElement.children[0].references['q'];
|
||||
const q: NeedsContentChild = view.debugElement.children[0].references !['q'];
|
||||
expect(q.logs).toEqual([['setter', 'foo'], ['init', 'foo'], ['check', 'foo']]);
|
||||
|
||||
view.componentInstance.shouldShow = false;
|
||||
@ -93,7 +93,7 @@ export function main() {
|
||||
const template = '<needs-view-child #q></needs-view-child>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
|
||||
const q: NeedsViewChild = view.debugElement.children[0].references['q'];
|
||||
const q: NeedsViewChild = view.debugElement.children[0].references !['q'];
|
||||
expect(q.logs).toEqual([['setter', 'foo'], ['init', 'foo'], ['check', 'foo']]);
|
||||
|
||||
q.shouldShow = false;
|
||||
@ -107,7 +107,7 @@ export function main() {
|
||||
const template =
|
||||
'<needs-static-content-view-child #q><div text="contentFoo"></div></needs-static-content-view-child>';
|
||||
const view = createTestCmp(MyComp0, template);
|
||||
const q: NeedsStaticContentAndViewChild = view.debugElement.children[0].references['q'];
|
||||
const q: NeedsStaticContentAndViewChild = view.debugElement.children[0].references !['q'];
|
||||
expect(q.contentChild.text).toBeFalsy();
|
||||
expect(q.viewChild.text).toBeFalsy();
|
||||
|
||||
@ -128,7 +128,7 @@ export function main() {
|
||||
const view = TestBed.createComponent(MyComp0);
|
||||
|
||||
view.detectChanges();
|
||||
const q: NeedsViewChild = view.debugElement.children[0].references['q'];
|
||||
const q: NeedsViewChild = view.debugElement.children[0].references !['q'];
|
||||
expect(q.logs).toEqual([['setter', 'foo'], ['init', 'foo'], ['check', 'foo']]);
|
||||
|
||||
q.shouldShow = false;
|
||||
@ -312,7 +312,7 @@ export function main() {
|
||||
'</needs-query>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
|
||||
const q = view.debugElement.children[0].references['q'];
|
||||
const q = view.debugElement.children[0].references !['q'];
|
||||
|
||||
q.query.changes.subscribe({
|
||||
next: () => {
|
||||
@ -333,14 +333,14 @@ export function main() {
|
||||
view.componentInstance.shouldShow = true;
|
||||
view.detectChanges();
|
||||
|
||||
const q: NeedsQuery = view.debugElement.children[0].references['q'];
|
||||
const q: NeedsQuery = view.debugElement.children[0].references !['q'];
|
||||
expect(q.query.length).toEqual(1);
|
||||
|
||||
view.componentInstance.shouldShow = false;
|
||||
view.detectChanges();
|
||||
view.componentInstance.shouldShow = true;
|
||||
view.detectChanges();
|
||||
const q2: NeedsQuery = view.debugElement.children[0].references['q'];
|
||||
const q2: NeedsQuery = view.debugElement.children[0].references !['q'];
|
||||
|
||||
expect(q2.query.length).toEqual(1);
|
||||
});
|
||||
@ -353,7 +353,7 @@ export function main() {
|
||||
'<div *ngFor="let item of list" [text]="item" #textLabel="textDir"></div>' +
|
||||
'</needs-query-by-ref-binding>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
const q = view.debugElement.children[0].references['q'];
|
||||
const q = view.debugElement.children[0].references !['q'];
|
||||
|
||||
view.componentInstance.list = ['1d', '2d'];
|
||||
view.detectChanges();
|
||||
@ -367,7 +367,7 @@ export function main() {
|
||||
'<div text="two" #textLabel2="textDir"></div>' +
|
||||
'</needs-query-by-ref-bindings>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
const q = view.debugElement.children[0].references['q'];
|
||||
const q = view.debugElement.children[0].references !['q'];
|
||||
|
||||
expect(q.query.first.text).toEqual('one');
|
||||
expect(q.query.last.text).toEqual('two');
|
||||
@ -378,7 +378,7 @@ export function main() {
|
||||
'<div *ngFor="let item of list" [text]="item" #textLabel="textDir"></div>' +
|
||||
'</needs-query-by-ref-binding>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
const q = view.debugElement.children[0].references['q'];
|
||||
const q = view.debugElement.children[0].references !['q'];
|
||||
|
||||
view.componentInstance.list = ['1d', '2d'];
|
||||
view.detectChanges();
|
||||
@ -394,7 +394,7 @@ export function main() {
|
||||
'</div>' +
|
||||
'</needs-query-by-ref-binding>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
const q = view.debugElement.children[0].references['q'];
|
||||
const q = view.debugElement.children[0].references !['q'];
|
||||
|
||||
view.componentInstance.list = ['1d', '2d'];
|
||||
view.detectChanges();
|
||||
@ -415,14 +415,14 @@ export function main() {
|
||||
const template = '<needs-view-query-by-ref-binding #q></needs-view-query-by-ref-binding>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
|
||||
const q: NeedsViewQueryByLabel = view.debugElement.children[0].references['q'];
|
||||
const q: NeedsViewQueryByLabel = view.debugElement.children[0].references !['q'];
|
||||
expect(q.query.first.nativeElement).toHaveText('text');
|
||||
});
|
||||
|
||||
it('should contain all child directives in the view dom', () => {
|
||||
const template = '<needs-view-children #q></needs-view-children>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
const q = view.debugElement.children[0].references['q'];
|
||||
const q = view.debugElement.children[0].references !['q'];
|
||||
expect(q.textDirChildren.length).toEqual(1);
|
||||
expect(q.numberOfChildrenAfterViewInit).toEqual(1);
|
||||
});
|
||||
@ -432,21 +432,21 @@ export function main() {
|
||||
it('should contain all the elements in the view with that have the given directive', () => {
|
||||
const template = '<needs-view-query #q><div text="ignoreme"></div></needs-view-query>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
const q: NeedsViewQuery = view.debugElement.children[0].references['q'];
|
||||
const q: NeedsViewQuery = view.debugElement.children[0].references !['q'];
|
||||
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']);
|
||||
});
|
||||
|
||||
it('should not include directive present on the host element', () => {
|
||||
const template = '<needs-view-query #q text="self"></needs-view-query>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
const q: NeedsViewQuery = view.debugElement.children[0].references['q'];
|
||||
const q: NeedsViewQuery = view.debugElement.children[0].references !['q'];
|
||||
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']);
|
||||
});
|
||||
|
||||
it('should reflect changes in the component', () => {
|
||||
const template = '<needs-view-query-if #q></needs-view-query-if>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
const q: NeedsViewQueryIf = view.debugElement.children[0].references['q'];
|
||||
const q: NeedsViewQueryIf = view.debugElement.children[0].references !['q'];
|
||||
expect(q.query.length).toBe(0);
|
||||
|
||||
q.show = true;
|
||||
@ -458,7 +458,7 @@ export function main() {
|
||||
it('should not be affected by other changes in the component', () => {
|
||||
const template = '<needs-view-query-nested-if #q></needs-view-query-nested-if>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
const q: NeedsViewQueryNestedIf = view.debugElement.children[0].references['q'];
|
||||
const q: NeedsViewQueryNestedIf = view.debugElement.children[0].references !['q'];
|
||||
|
||||
expect(q.query.length).toEqual(1);
|
||||
expect(q.query.first.text).toEqual('1');
|
||||
@ -473,7 +473,7 @@ export function main() {
|
||||
() => {
|
||||
const template = '<needs-view-query-order #q></needs-view-query-order>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
const q: NeedsViewQueryOrder = view.debugElement.children[0].references['q'];
|
||||
const q: NeedsViewQueryOrder = view.debugElement.children[0].references !['q'];
|
||||
|
||||
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']);
|
||||
|
||||
@ -486,7 +486,7 @@ export function main() {
|
||||
() => {
|
||||
const template = '<needs-view-query-order-with-p #q></needs-view-query-order-with-p>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
const q: NeedsViewQueryOrderWithParent = view.debugElement.children[0].references['q'];
|
||||
const q: NeedsViewQueryOrderWithParent = view.debugElement.children[0].references !['q'];
|
||||
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']);
|
||||
|
||||
q.list = ['-3', '2'];
|
||||
@ -497,7 +497,7 @@ export function main() {
|
||||
it('should handle long ngFor cycles', () => {
|
||||
const template = '<needs-view-query-order #q></needs-view-query-order>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
const q: NeedsViewQueryOrder = view.debugElement.children[0].references['q'];
|
||||
const q: NeedsViewQueryOrder = view.debugElement.children[0].references !['q'];
|
||||
|
||||
// no significance to 50, just a reasonably large cycle.
|
||||
for (let i = 0; i < 50; i++) {
|
||||
@ -511,7 +511,7 @@ export function main() {
|
||||
it('should support more than three queries', () => {
|
||||
const template = '<needs-four-queries #q><div text="1"></div></needs-four-queries>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
const q = view.debugElement.children[0].references['q'];
|
||||
const q = view.debugElement.children[0].references !['q'];
|
||||
expect(q.query1).toBeDefined();
|
||||
expect(q.query2).toBeDefined();
|
||||
expect(q.query3).toBeDefined();
|
||||
@ -524,7 +524,7 @@ export function main() {
|
||||
const template =
|
||||
'<manual-projecting #q><ng-template><div text="1"></div></ng-template></manual-projecting>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
const q = view.debugElement.children[0].references['q'];
|
||||
const q = view.debugElement.children[0].references !['q'];
|
||||
expect(q.query.length).toBe(0);
|
||||
|
||||
q.create();
|
||||
@ -553,7 +553,7 @@ export function main() {
|
||||
'<auto-projecting #q><ng-template><div text="1"></div></ng-template></auto-projecting>';
|
||||
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||
|
||||
const q = view.debugElement.children[0].references['q'];
|
||||
const q = view.debugElement.children[0].references !['q'];
|
||||
// This should be 1, but due to
|
||||
// https://github.com/angular/angular/issues/15117 this is 0.
|
||||
expect(q.query.length).toBe(0);
|
||||
@ -812,7 +812,7 @@ class NeedsViewContainerWithRead {
|
||||
|
||||
@Component({selector: 'has-null-query-condition', template: '<div></div>'})
|
||||
class HasNullQueryCondition {
|
||||
@ContentChildren(null) errorTrigger: any;
|
||||
@ContentChildren(null !) errorTrigger: any;
|
||||
}
|
||||
|
||||
@Component({selector: 'my-comp', template: ''})
|
||||
|
@ -75,7 +75,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||
});
|
||||
|
||||
// should not throw for inputs starting with "on"
|
||||
let cmp: ComponentFixture<SecuredComponent>;
|
||||
let cmp: ComponentFixture<SecuredComponent> = undefined !;
|
||||
expect(() => cmp = TestBed.createComponent(SecuredComponent)).not.toThrow();
|
||||
|
||||
// must bind to the directive not to the property of the div
|
||||
|
@ -26,15 +26,15 @@ export function main() {
|
||||
});
|
||||
|
||||
function getErrorLoggerStack(e: Error): string {
|
||||
let logStack: string;
|
||||
getErrorLogger(e)(<any>{error: () => logStack = new Error().stack}, e.message);
|
||||
let logStack: string = undefined !;
|
||||
getErrorLogger(e)(<any>{error: () => logStack = new Error().stack !}, e.message);
|
||||
return logStack;
|
||||
}
|
||||
|
||||
function getSourceMap(genFile: string): SourceMap {
|
||||
const jitSources = jitSpy.calls.all().map((call) => call.args[call.args.length - 1]);
|
||||
return jitSources.map(source => extractSourceMap(source))
|
||||
.find(map => map && map.file === genFile);
|
||||
.find(map => !!(map && map.file === genFile)) !;
|
||||
}
|
||||
|
||||
function getSourcePositionForStack(stack: string):
|
||||
@ -46,9 +46,9 @@ export function main() {
|
||||
.map(line => /\((.*\.ngfactory\.js):(\d+):(\d+)/.exec(line))
|
||||
.filter(match => !!match)
|
||||
.map(match => ({
|
||||
file: match[1],
|
||||
line: parseInt(match[2], 10),
|
||||
column: parseInt(match[3], 10)
|
||||
file: match ![1],
|
||||
line: parseInt(match ![2], 10),
|
||||
column: parseInt(match ![3], 10)
|
||||
}));
|
||||
const ngFactoryLocation = ngFactoryLocations[0];
|
||||
|
||||
|
@ -184,19 +184,19 @@ class TestComp {
|
||||
|
||||
export function main() {
|
||||
function createComponentFixture<T>(
|
||||
template: string, providers: Provider[] = null, comp: Type<T> = null): ComponentFixture<T> {
|
||||
template: string, providers?: Provider[] | null, comp?: Type<T>): ComponentFixture<T> {
|
||||
if (!comp) {
|
||||
comp = <any>TestComp;
|
||||
}
|
||||
TestBed.overrideComponent(comp, {set: {template}});
|
||||
TestBed.overrideComponent(comp !, {set: {template}});
|
||||
if (providers && providers.length) {
|
||||
TestBed.overrideComponent(comp, {add: {providers: providers}});
|
||||
TestBed.overrideComponent(comp !, {add: {providers: providers}});
|
||||
}
|
||||
return TestBed.createComponent(comp);
|
||||
return TestBed.createComponent(comp !);
|
||||
}
|
||||
|
||||
function createComponent(
|
||||
template: string, providers: Provider[] = null, comp: Type<any> = null): DebugElement {
|
||||
template: string, providers?: Provider[], comp?: Type<any>): DebugElement {
|
||||
const fixture = createComponentFixture(template, providers, comp);
|
||||
fixture.detectChanges();
|
||||
return fixture.debugElement;
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
import {Reflector} from '@angular/core/src/reflection/reflection';
|
||||
import {DELEGATE_CTOR, ReflectionCapabilities} from '@angular/core/src/reflection/reflection_capabilities';
|
||||
import {global} from '@angular/core/src/util';
|
||||
import {makeDecorator, makeParamDecorator, makePropDecorator} from '@angular/core/src/util/decorators';
|
||||
|
||||
interface ClassDecoratorFactory {
|
||||
@ -171,8 +172,12 @@ export function main() {
|
||||
class ChildWithCtor extends Parent {
|
||||
constructor() { super(); }
|
||||
}
|
||||
class ChildNoCtorPrivateProps extends Parent {
|
||||
private x = 10;
|
||||
}
|
||||
|
||||
expect(DELEGATE_CTOR.exec(ChildNoCtor.toString())).toBeTruthy();
|
||||
expect(DELEGATE_CTOR.exec(ChildNoCtorPrivateProps.toString())).toBeTruthy();
|
||||
expect(DELEGATE_CTOR.exec(ChildWithCtor.toString())).toBeFalsy();
|
||||
});
|
||||
});
|
||||
@ -205,7 +210,7 @@ export function main() {
|
||||
expect(reflector.annotations(NoDecorators)).toEqual([]);
|
||||
expect(reflector.annotations(<any>{})).toEqual([]);
|
||||
expect(reflector.annotations(<any>1)).toEqual([]);
|
||||
expect(reflector.annotations(null)).toEqual([]);
|
||||
expect(reflector.annotations(null !)).toEqual([]);
|
||||
});
|
||||
|
||||
it('should inherit parameters', () => {
|
||||
@ -222,15 +227,24 @@ export function main() {
|
||||
|
||||
class Child extends Parent {}
|
||||
|
||||
@ClassDecorator({value: 'child'})
|
||||
class ChildWithDecorator extends Parent {
|
||||
}
|
||||
|
||||
@ClassDecorator({value: 'child'})
|
||||
class ChildWithDecoratorAndProps extends Parent {
|
||||
private x = 10;
|
||||
}
|
||||
|
||||
// Note: We need the class decorator as well,
|
||||
// as otherwise TS won't capture the ctor arguments!
|
||||
@ClassDecorator({value: 'child'})
|
||||
class ChildWithCtor extends Parent {
|
||||
constructor(@ParamDecorator('c') c: C) { super(null, null); }
|
||||
constructor(@ParamDecorator('c') c: C) { super(null !, null !); }
|
||||
}
|
||||
|
||||
class ChildWithCtorNoDecorator extends Parent {
|
||||
constructor(a: any, b: any, c: any) { super(null, null); }
|
||||
constructor(a: any, b: any, c: any) { super(null !, null !); }
|
||||
}
|
||||
|
||||
class NoDecorators {}
|
||||
@ -244,6 +258,14 @@ export function main() {
|
||||
[A, new ParamDecorator('a')], [B, new ParamDecorator('b')]
|
||||
]);
|
||||
|
||||
expect(reflector.parameters(ChildWithDecorator)).toEqual([
|
||||
[A, new ParamDecorator('a')], [B, new ParamDecorator('b')]
|
||||
]);
|
||||
|
||||
expect(reflector.parameters(ChildWithDecoratorAndProps)).toEqual([
|
||||
[A, new ParamDecorator('a')], [B, new ParamDecorator('b')]
|
||||
]);
|
||||
|
||||
expect(reflector.parameters(ChildWithCtor)).toEqual([[C, new ParamDecorator('c')]]);
|
||||
|
||||
// If we have no decorator, we don't get metadata about the ctor params.
|
||||
@ -255,7 +277,7 @@ export function main() {
|
||||
expect(reflector.parameters(NoDecorators)).toEqual([]);
|
||||
expect(reflector.parameters(<any>{})).toEqual([]);
|
||||
expect(reflector.parameters(<any>1)).toEqual([]);
|
||||
expect(reflector.parameters(null)).toEqual([]);
|
||||
expect(reflector.parameters(null !)).toEqual([]);
|
||||
});
|
||||
|
||||
it('should inherit property metadata', () => {
|
||||
@ -294,7 +316,7 @@ export function main() {
|
||||
expect(reflector.propMetadata(NoDecorators)).toEqual({});
|
||||
expect(reflector.propMetadata(<any>{})).toEqual({});
|
||||
expect(reflector.propMetadata(<any>1)).toEqual({});
|
||||
expect(reflector.propMetadata(null)).toEqual({});
|
||||
expect(reflector.propMetadata(null !)).toEqual({});
|
||||
});
|
||||
|
||||
it('should inherit lifecycle hooks', () => {
|
||||
|
@ -11,9 +11,9 @@ import {stringify} from '../src/util';
|
||||
export function main() {
|
||||
describe('stringify', () => {
|
||||
it('should return string undefined when toString returns undefined',
|
||||
() => expect(stringify({toString: (): string => undefined})).toBe('undefined'));
|
||||
() => expect(stringify({toString: (): any => undefined})).toBe('undefined'));
|
||||
|
||||
it('should return string null when toString returns null',
|
||||
() => expect(stringify({toString: (): string => null})).toBe('null'));
|
||||
() => expect(stringify({toString: (): any => null})).toBe('null'));
|
||||
});
|
||||
}
|
||||
|
@ -30,23 +30,23 @@ export function main() {
|
||||
describe('create', () => {
|
||||
it('should create anchor nodes without parents', () => {
|
||||
const rootNodes = createAndGetRootNodes(compViewDef([
|
||||
anchorDef(NodeFlags.None, null, null, 0)
|
||||
anchorDef(NodeFlags.None, null !, null !, 0)
|
||||
])).rootNodes;
|
||||
expect(rootNodes.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should create views with multiple root anchor nodes', () => {
|
||||
const rootNodes =
|
||||
createAndGetRootNodes(compViewDef([
|
||||
anchorDef(NodeFlags.None, null, null, 0), anchorDef(NodeFlags.None, null, null, 0)
|
||||
])).rootNodes;
|
||||
const rootNodes = createAndGetRootNodes(compViewDef([
|
||||
anchorDef(NodeFlags.None, null !, null !, 0),
|
||||
anchorDef(NodeFlags.None, null !, null !, 0)
|
||||
])).rootNodes;
|
||||
expect(rootNodes.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should create anchor nodes with parents', () => {
|
||||
const rootNodes = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, null, 1, 'div'),
|
||||
anchorDef(NodeFlags.None, null, null, 0),
|
||||
elementDef(NodeFlags.None, null !, null !, 1, 'div'),
|
||||
anchorDef(NodeFlags.None, null !, null !, 0),
|
||||
])).rootNodes;
|
||||
expect(getDOM().childNodes(rootNodes[0]).length).toBe(1);
|
||||
});
|
||||
@ -54,8 +54,8 @@ export function main() {
|
||||
it('should add debug information to the renderer', () => {
|
||||
const someContext = new Object();
|
||||
const {view, rootNodes} = createAndGetRootNodes(
|
||||
compViewDef([anchorDef(NodeFlags.None, null, null, 0)]), someContext);
|
||||
expect(getDebugNode(rootNodes[0]).nativeNode).toBe(asElementData(view, 0).renderElement);
|
||||
compViewDef([anchorDef(NodeFlags.None, null !, null !, 0)]), someContext);
|
||||
expect(getDebugNode(rootNodes[0]) !.nativeNode).toBe(asElementData(view, 0).renderElement);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -13,300 +13,292 @@ import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
import {createRootView, isBrowser, removeNodes} from './helper';
|
||||
|
||||
export function main() {
|
||||
describe(
|
||||
`Component Views`, () => {
|
||||
function compViewDef(
|
||||
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
|
||||
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
|
||||
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
|
||||
}
|
||||
describe(`Component Views`, () => {
|
||||
function compViewDef(
|
||||
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
|
||||
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
|
||||
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
|
||||
}
|
||||
|
||||
function createAndGetRootNodes(viewDef: ViewDefinition):
|
||||
{rootNodes: any[], view: ViewData} {
|
||||
const view = createRootView(viewDef);
|
||||
const rootNodes = rootRenderNodes(view);
|
||||
return {rootNodes, view};
|
||||
}
|
||||
function createAndGetRootNodes(viewDef: ViewDefinition): {rootNodes: any[], view: ViewData} {
|
||||
const view = createRootView(viewDef);
|
||||
const rootNodes = rootRenderNodes(view);
|
||||
return {rootNodes, view};
|
||||
}
|
||||
|
||||
it('should create and attach component views', () => {
|
||||
let instance: AComp;
|
||||
class AComp {
|
||||
constructor() { instance = this; }
|
||||
}
|
||||
it('should create and attach component views', () => {
|
||||
let instance: AComp = undefined !;
|
||||
class AComp {
|
||||
constructor() { instance = this; }
|
||||
}
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(
|
||||
NodeFlags.None, null, null, 1, 'div', null, null, null, null,
|
||||
() => compViewDef([
|
||||
elementDef(NodeFlags.None, null, null, 0, 'span'),
|
||||
])),
|
||||
directiveDef(NodeFlags.Component, null, 0, AComp, []),
|
||||
]));
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(
|
||||
NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !,
|
||||
() => compViewDef([
|
||||
elementDef(NodeFlags.None, null !, null !, 0, 'span'),
|
||||
])),
|
||||
directiveDef(NodeFlags.Component, null !, 0, AComp, []),
|
||||
]));
|
||||
|
||||
const compView = asElementData(view, 0).componentView;
|
||||
const compView = asElementData(view, 0).componentView;
|
||||
|
||||
expect(compView.context).toBe(instance);
|
||||
expect(compView.component).toBe(instance);
|
||||
expect(compView.context).toBe(instance);
|
||||
expect(compView.component).toBe(instance);
|
||||
|
||||
const compRootEl = getDOM().childNodes(rootNodes[0])[0];
|
||||
expect(getDOM().nodeName(compRootEl).toLowerCase()).toBe('span');
|
||||
const compRootEl = getDOM().childNodes(rootNodes[0])[0];
|
||||
expect(getDOM().nodeName(compRootEl).toLowerCase()).toBe('span');
|
||||
});
|
||||
|
||||
if (isBrowser()) {
|
||||
describe('root views', () => {
|
||||
let rootNode: HTMLElement;
|
||||
beforeEach(() => {
|
||||
rootNode = document.createElement('root');
|
||||
document.body.appendChild(rootNode);
|
||||
removeNodes.push(rootNode);
|
||||
});
|
||||
|
||||
if (isBrowser()) {
|
||||
describe('root views', () => {
|
||||
let rootNode: HTMLElement;
|
||||
beforeEach(() => {
|
||||
rootNode = document.createElement('root');
|
||||
document.body.appendChild(rootNode);
|
||||
removeNodes.push(rootNode);
|
||||
});
|
||||
it('should select root elements based on a selector', () => {
|
||||
const view = createRootView(
|
||||
compViewDef([
|
||||
elementDef(NodeFlags.None, null !, null !, 0, 'div'),
|
||||
]),
|
||||
{}, [], 'root');
|
||||
const rootNodes = rootRenderNodes(view);
|
||||
expect(rootNodes).toEqual([rootNode]);
|
||||
});
|
||||
|
||||
it('should select root elements based on a selector', () => {
|
||||
const view = createRootView(
|
||||
compViewDef([
|
||||
elementDef(NodeFlags.None, null, null, 0, 'div'),
|
||||
]),
|
||||
{}, [], 'root');
|
||||
const rootNodes = rootRenderNodes(view);
|
||||
expect(rootNodes).toEqual([rootNode]);
|
||||
});
|
||||
it('should select root elements based on a node', () => {
|
||||
const view = createRootView(
|
||||
compViewDef([
|
||||
elementDef(NodeFlags.None, null !, null !, 0, 'div'),
|
||||
]),
|
||||
{}, [], rootNode);
|
||||
const rootNodes = rootRenderNodes(view);
|
||||
expect(rootNodes).toEqual([rootNode]);
|
||||
});
|
||||
|
||||
it('should select root elements based on a node', () => {
|
||||
const view = createRootView(
|
||||
compViewDef([
|
||||
elementDef(NodeFlags.None, null, null, 0, 'div'),
|
||||
]),
|
||||
{}, [], rootNode);
|
||||
const rootNodes = rootRenderNodes(view);
|
||||
expect(rootNodes).toEqual([rootNode]);
|
||||
});
|
||||
it('should set attributes on the root node', () => {
|
||||
const view = createRootView(
|
||||
compViewDef([
|
||||
elementDef(NodeFlags.None, null !, null !, 0, 'div', [['a', 'b']]),
|
||||
]),
|
||||
{}, [], rootNode);
|
||||
expect(rootNode.getAttribute('a')).toBe('b');
|
||||
});
|
||||
|
||||
it('should set attributes on the root node', () => {
|
||||
const view = createRootView(
|
||||
compViewDef([
|
||||
elementDef(NodeFlags.None, null, null, 0, 'div', [['a', 'b']]),
|
||||
]),
|
||||
{}, [], rootNode);
|
||||
expect(rootNode.getAttribute('a')).toBe('b');
|
||||
});
|
||||
it('should clear the content of the root node', () => {
|
||||
rootNode.appendChild(document.createElement('div'));
|
||||
const view = createRootView(
|
||||
compViewDef([
|
||||
elementDef(NodeFlags.None, null !, null !, 0, 'div', [['a', 'b']]),
|
||||
]),
|
||||
{}, [], rootNode);
|
||||
expect(rootNode.childNodes.length).toBe(0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
it('should clear the content of the root node', () => {
|
||||
rootNode.appendChild(document.createElement('div'));
|
||||
const view = createRootView(
|
||||
compViewDef([
|
||||
elementDef(NodeFlags.None, null, null, 0, 'div', [['a', 'b']]),
|
||||
]),
|
||||
{}, [], rootNode);
|
||||
expect(rootNode.childNodes.length).toBe(0);
|
||||
});
|
||||
});
|
||||
describe('data binding', () => {
|
||||
it('should dirty check component views', () => {
|
||||
let value: any;
|
||||
class AComp {
|
||||
a: any;
|
||||
}
|
||||
|
||||
describe(
|
||||
'data binding', () => {
|
||||
it('should dirty check component views',
|
||||
() => {
|
||||
let value: any;
|
||||
class AComp {
|
||||
a: any;
|
||||
}
|
||||
const update =
|
||||
jasmine.createSpy('updater').and.callFake((check: NodeCheckFn, view: ViewData) => {
|
||||
check(view, 0, ArgumentType.Inline, value);
|
||||
});
|
||||
|
||||
const update = jasmine.createSpy('updater').and.callFake(
|
||||
(check: NodeCheckFn, view: ViewData) => {
|
||||
check(view, 0, ArgumentType.Inline, value);
|
||||
});
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(
|
||||
const {view, rootNodes} = createAndGetRootNodes(
|
||||
compViewDef([
|
||||
elementDef(NodeFlags.None, null, null, 1, 'div', null, null, null, null, () => compViewDef(
|
||||
elementDef(NodeFlags.None, null!, null!, 1, 'div', null!, null!, null!, null!, () => compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, null, null, 0, 'span', null, [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]]),
|
||||
], null, update
|
||||
elementDef(NodeFlags.None, null!, null!, 0, 'span', null!, [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]]),
|
||||
], null!, update
|
||||
)),
|
||||
directiveDef(NodeFlags.Component, null, 0, AComp, []),
|
||||
directiveDef(NodeFlags.Component, null!, 0, AComp, []),
|
||||
]));
|
||||
const compView = asElementData(view, 0).componentView;
|
||||
const compView = asElementData(view, 0).componentView;
|
||||
|
||||
value = 'v1';
|
||||
Services.checkAndUpdateView(view);
|
||||
value = 'v1';
|
||||
Services.checkAndUpdateView(view);
|
||||
|
||||
expect(update.calls.mostRecent().args[1]).toBe(compView);
|
||||
expect(update.calls.mostRecent().args[1]).toBe(compView);
|
||||
|
||||
update.calls.reset();
|
||||
Services.checkNoChangesView(view);
|
||||
update.calls.reset();
|
||||
Services.checkNoChangesView(view);
|
||||
|
||||
expect(update.calls.mostRecent().args[1]).toBe(compView);
|
||||
expect(update.calls.mostRecent().args[1]).toBe(compView);
|
||||
|
||||
value = 'v2';
|
||||
expect(() => Services.checkNoChangesView(view))
|
||||
.toThrowError(
|
||||
`ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'v1'. Current value: 'v2'.`);
|
||||
});
|
||||
value = 'v2';
|
||||
expect(() => Services.checkNoChangesView(view))
|
||||
.toThrowError(
|
||||
`ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'v1'. Current value: 'v2'.`);
|
||||
});
|
||||
|
||||
it('should support detaching and attaching component views for dirty checking',
|
||||
() => {
|
||||
class AComp {
|
||||
a: any;
|
||||
}
|
||||
it('should support detaching and attaching component views for dirty checking', () => {
|
||||
class AComp {
|
||||
a: any;
|
||||
}
|
||||
|
||||
const update = jasmine.createSpy('updater');
|
||||
const update = jasmine.createSpy('updater');
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(
|
||||
NodeFlags.None, null, null, 1, 'div', null, null, null, null,
|
||||
() => compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, null, null, 0, 'span'),
|
||||
],
|
||||
update)),
|
||||
directiveDef(NodeFlags.Component, null, 0, AComp, [], null, null),
|
||||
]));
|
||||
|
||||
const compView = asElementData(view, 0).componentView;
|
||||
|
||||
Services.checkAndUpdateView(view);
|
||||
update.calls.reset();
|
||||
|
||||
compView.state &= ~ViewState.ChecksEnabled;
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).not.toHaveBeenCalled();
|
||||
|
||||
compView.state |= ViewState.ChecksEnabled;
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
if (isBrowser()) {
|
||||
it('should support OnPush components', () => {
|
||||
let compInputValue: any;
|
||||
class AComp {
|
||||
a: any;
|
||||
}
|
||||
|
||||
const update = jasmine.createSpy('updater');
|
||||
|
||||
const addListenerSpy =
|
||||
spyOn(HTMLElement.prototype, 'addEventListener').and.callThrough();
|
||||
|
||||
const {view} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(
|
||||
NodeFlags.None, null, null, 1, 'div', null, null, null, null,
|
||||
() => {
|
||||
return compViewDef(
|
||||
[
|
||||
elementDef(
|
||||
NodeFlags.None, null, null, 0, 'span', null, null,
|
||||
[[null, 'click']]),
|
||||
],
|
||||
update, null, ViewFlags.OnPush);
|
||||
}),
|
||||
directiveDef(NodeFlags.Component, null, 0, AComp, [], {a: [0, 'a']}),
|
||||
],
|
||||
(check, view) => { check(view, 1, ArgumentType.Inline, compInputValue); }));
|
||||
|
||||
Services.checkAndUpdateView(view);
|
||||
|
||||
// auto detach
|
||||
update.calls.reset();
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).not.toHaveBeenCalled();
|
||||
|
||||
// auto attach on input changes
|
||||
update.calls.reset();
|
||||
compInputValue = 'v1';
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).toHaveBeenCalled();
|
||||
|
||||
// auto detach
|
||||
update.calls.reset();
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).not.toHaveBeenCalled();
|
||||
|
||||
// auto attach on events
|
||||
addListenerSpy.calls.mostRecent().args[1]('SomeEvent');
|
||||
update.calls.reset();
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).toHaveBeenCalled();
|
||||
|
||||
// auto detach
|
||||
update.calls.reset();
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).not.toHaveBeenCalled();
|
||||
});
|
||||
}
|
||||
|
||||
it('should stop dirty checking views that threw errors in change detection',
|
||||
() => {
|
||||
class AComp {
|
||||
a: any;
|
||||
}
|
||||
|
||||
const update = jasmine.createSpy('updater');
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, null, 1, 'div', null, null, null, null, () => compViewDef(
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(
|
||||
NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !,
|
||||
() => compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, null, null, 0, 'span', null, [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]]),
|
||||
elementDef(NodeFlags.None, null !, null !, 0, 'span'),
|
||||
],
|
||||
null, update)),
|
||||
update)),
|
||||
directiveDef(NodeFlags.Component, null !, 0, AComp, [], null !, null !),
|
||||
]));
|
||||
|
||||
const compView = asElementData(view, 0).componentView;
|
||||
|
||||
Services.checkAndUpdateView(view);
|
||||
update.calls.reset();
|
||||
|
||||
compView.state &= ~ViewState.ChecksEnabled;
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).not.toHaveBeenCalled();
|
||||
|
||||
compView.state |= ViewState.ChecksEnabled;
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
if (isBrowser()) {
|
||||
it('should support OnPush components', () => {
|
||||
let compInputValue: any;
|
||||
class AComp {
|
||||
a: any;
|
||||
}
|
||||
|
||||
const update = jasmine.createSpy('updater');
|
||||
|
||||
const addListenerSpy = spyOn(HTMLElement.prototype, 'addEventListener').and.callThrough();
|
||||
|
||||
const {view} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(
|
||||
NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !,
|
||||
() => {
|
||||
return compViewDef(
|
||||
[
|
||||
elementDef(
|
||||
NodeFlags.None, null !, null !, 0, 'span', null !, null !,
|
||||
[[null !, 'click']]),
|
||||
],
|
||||
update, null !, ViewFlags.OnPush);
|
||||
}),
|
||||
directiveDef(NodeFlags.Component, null !, 0, AComp, [], {a: [0, 'a']}),
|
||||
],
|
||||
(check, view) => { check(view, 1, ArgumentType.Inline, compInputValue); }));
|
||||
|
||||
Services.checkAndUpdateView(view);
|
||||
|
||||
// auto detach
|
||||
update.calls.reset();
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).not.toHaveBeenCalled();
|
||||
|
||||
// auto attach on input changes
|
||||
update.calls.reset();
|
||||
compInputValue = 'v1';
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).toHaveBeenCalled();
|
||||
|
||||
// auto detach
|
||||
update.calls.reset();
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).not.toHaveBeenCalled();
|
||||
|
||||
// auto attach on events
|
||||
addListenerSpy.calls.mostRecent().args[1]('SomeEvent');
|
||||
update.calls.reset();
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).toHaveBeenCalled();
|
||||
|
||||
// auto detach
|
||||
update.calls.reset();
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).not.toHaveBeenCalled();
|
||||
});
|
||||
}
|
||||
|
||||
it('should stop dirty checking views that threw errors in change detection', () => {
|
||||
class AComp {
|
||||
a: any;
|
||||
}
|
||||
|
||||
const update = jasmine.createSpy('updater');
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null!, null!, 1, 'div', null!, null!, null!, null!, () => compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, null!, null!, 0, 'span', null!, [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]]),
|
||||
],
|
||||
null!, update)),
|
||||
directiveDef(
|
||||
NodeFlags.Component, null, 0, AComp, [], null, null,
|
||||
NodeFlags.Component, null!, 0, AComp, [], null!, null!,
|
||||
),
|
||||
]));
|
||||
|
||||
const compView = asElementData(view, 0).componentView;
|
||||
const compView = asElementData(view, 0).componentView;
|
||||
|
||||
update.and.callFake(
|
||||
(check: NodeCheckFn, view: ViewData) => { throw new Error('Test'); });
|
||||
expect(() => Services.checkAndUpdateView(view)).toThrowError('Test');
|
||||
expect(update).toHaveBeenCalled();
|
||||
|
||||
update.calls.reset();
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('destroy', () => {
|
||||
it('should destroy component views', () => {
|
||||
const log: string[] = [];
|
||||
|
||||
class AComp {}
|
||||
|
||||
class ChildProvider {
|
||||
ngOnDestroy() { log.push('ngOnDestroy'); };
|
||||
}
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(
|
||||
NodeFlags.None, null, null, 1, 'div', null, null, null, null,
|
||||
() => compViewDef([
|
||||
elementDef(NodeFlags.None, null, null, 1, 'span'),
|
||||
directiveDef(NodeFlags.OnDestroy, null, 0, ChildProvider, [])
|
||||
])),
|
||||
directiveDef(NodeFlags.Component, null, 0, AComp, [], null, null, ),
|
||||
]));
|
||||
|
||||
Services.destroyView(view);
|
||||
|
||||
expect(log).toEqual(['ngOnDestroy']);
|
||||
});
|
||||
|
||||
it('should throw on dirty checking destroyed views', () => {
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, null, null, 0, 'div'),
|
||||
],
|
||||
(view) => {}));
|
||||
|
||||
Services.destroyView(view);
|
||||
|
||||
expect(() => Services.checkAndUpdateView(view))
|
||||
.toThrowError('ViewDestroyedError: Attempt to use a destroyed view: detectChanges');
|
||||
});
|
||||
});
|
||||
update.and.callFake((check: NodeCheckFn, view: ViewData) => { throw new Error('Test'); });
|
||||
expect(() => Services.checkAndUpdateView(view)).toThrowError('Test');
|
||||
expect(update).toHaveBeenCalled();
|
||||
|
||||
update.calls.reset();
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(update).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('destroy', () => {
|
||||
it('should destroy component views', () => {
|
||||
const log: string[] = [];
|
||||
|
||||
class AComp {}
|
||||
|
||||
class ChildProvider {
|
||||
ngOnDestroy() { log.push('ngOnDestroy'); };
|
||||
}
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(
|
||||
NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !,
|
||||
() => compViewDef([
|
||||
elementDef(NodeFlags.None, null !, null !, 1, 'span'),
|
||||
directiveDef(NodeFlags.OnDestroy, null !, 0, ChildProvider, [])
|
||||
])),
|
||||
directiveDef(NodeFlags.Component, null !, 0, AComp, [], null !, null !, ),
|
||||
]));
|
||||
|
||||
Services.destroyView(view);
|
||||
|
||||
expect(log).toEqual(['ngOnDestroy']);
|
||||
});
|
||||
|
||||
it('should throw on dirty checking destroyed views', () => {
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, null !, null !, 0, 'div'),
|
||||
],
|
||||
(view) => {}));
|
||||
|
||||
Services.destroyView(view);
|
||||
|
||||
expect(() => Services.checkAndUpdateView(view))
|
||||
.toThrowError('ViewDestroyedError: Attempt to use a destroyed view: detectChanges');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user