Compare commits

..

63 Commits

Author SHA1 Message Date
6353b77f89 docs: add changelog for 5.1.2 2017-12-20 12:50:50 -08:00
d9c40b7dd5 release: cut the 5.1.2 release 2017-12-20 12:49:12 -08:00
a36dfd453b ci(router): update the public API guard for the router
This fixes a badly applied revert earlier.
2017-12-20 12:03:51 -08:00
ced575fd10 fix(compiler): report an error for recursive module references
Modules that directly or indirectly export or imported themselves
reports an error instead of generating a stack fault.

Fixes: #19979
2017-12-20 10:54:58 -08:00
3b63e168e2 fix(compiler-cli): do not force type checking on .js files
The compiler host would force any file that is in node_modules
into the list of files that needed to be type checked which
captures .js files if `allowJs` is set to `true`. This should
have only forced .d.ts files into the project to enable
generation of factories.

Fixes: #19757
2017-12-20 10:01:30 -08:00
a1d4c2dbf1 fix(compiler-cli): do not emit invalid .metadata.json files
If no metadata is collected the `ngc` would generate file
that contained `[null]` instead of eliding the `.metadata.json`
file.

Fixes: #20479
2017-12-20 09:59:06 -08:00
a33182c4ee fix(service-worker): check for updates on navigation
Currently the Service Worker checks for updates only on SW startup,
an event which happens frequently but also nondeterministically. This
makes it hard for developers to observe the update process or reason
about how updates will be delivered to users. This problem is
exacerbated by the DevTools behavior of keeping the SW alive
indefinitely while opened, effectively preventing the page from
updating at all.

This change causes the SW to additionally check for updates on
navigation requests (app page reloads). This creates deterministic
update behavior, and is much easier for developers to reason about.
It does leave the old update-on-SW-startup behavior in place, as
removing that would be a breaking change.

Fixes #20877
2017-12-20 08:37:20 -08:00
66cc2fabf1 fix(upgrade): replaces get/setAngularLib with get/setAngularJSGlobal
The current names are confusing because Angular should refer to the latest version of the framework.
2017-12-20 08:37:02 -08:00
cf8269ee94 docs(aio): Rename service worker files, update examples, move service worker under Techniques 2017-12-19 11:08:25 -08:00
c7241ca0e6 docs(aio): fix inconsistency in lifecycle hooks table 2017-12-19 10:58:43 -08:00
4a49e19bd7 ci: add router/testing to public API guard 2017-12-19 10:58:43 -08:00
4a3a74b7b0 fix(aio): improve transitions between pages
- Avoid unnecessary animations, style transitions, repositioning on
  initial rendering.
- Better handle transitioning from/to Home page (which is the only page
  with transparent top-menu).
- Better coordinate sidenav and hamburger animations with page
  transitions.
- Improve fade-in/out animations.

Fixes #20996
2017-12-19 10:58:43 -08:00
6aa013cb63 refactor(aio): clean up top-menu CSS
- Clean-up and re-organize top-menu styles.
- Clean-up and merge hamburger styles into top-menu styles.
2017-12-19 10:58:43 -08:00
b9531f90b8 feat(aio): support disabling DocViewer animations via class 2017-12-19 10:58:43 -08:00
f239e8496e build(aio): make zipper work correctly with CLI projects 2017-12-19 10:58:43 -08:00
57bed3fe73 docs(core): move core examples into examples/core/ directory
This allows examples to be found during aio's `yarn serve-and-sync`, which only
looks for examples in `packages/examples/<packageName>/**/*`, where
`packageName` is the name of the package that the modified file belonged to;
e.g. `core`, `common`, etc.).
2017-12-18 12:11:07 -08:00
c011ffae30 test(aio): correct usage of fakeAsync and inject together in test
Corrects a test which wrapped the fakeAsync call in an inject call.  This caused
the test to not actually run.
2017-12-15 07:55:23 -08:00
756dd34519 fix(compiler): make tsx file aot compatible
fixes #20555
2017-12-15 07:54:02 -08:00
267ebf323e fix(common): fix a Closure compilation issue.
Closure Compiler cannot infer that the swtich statement is exhaustive,
which causes it to complain that the method does not always return a
value.

Work around the problem by throwing an exception in the default case,
and using the `: never` type to ensure the code is unreachable.
2017-12-15 07:52:09 -08:00
49c45f336e ci(aio): move e2e tests to non-optional job
This essentially reverts #20178, since the flakes should be gone after
pinning ChromeDriver and Chrome versions to 2.32 and 59 respectively.
2017-12-14 08:56:22 -08:00
71236737ab ci: downgrade Chromium to a version that does not cause flakes
There seems to be some issue that causes Chrome/ChromeDriver to
unexpectedly reload during the aio e2e tests, causing flakes. It is not
clear what exactly is causing the reloading, but to the best of my
knowledge it is something inside Chrome or ChromeDriver.

Pinning Chrome to r494239 (between 62.0.3185.0 and 62.0.3186.0) fixes
the flakes.

Fixes #20159
2017-12-14 08:56:22 -08:00
390837f76e test(aio): disable DocViewer animations during e2e tests 2017-12-14 08:56:22 -08:00
fbcf7dc889 test(aio): fix and clean up e2e tests 2017-12-14 08:56:22 -08:00
5c8c7d8515 build(common): don't generate .d.ts & .metadata.json files for i18n locales
Fixes #20880
2017-12-14 08:55:50 -08:00
99cc591f63 ci: parallelize bazel build and test
The current setup can cause a de-optimization where unit tests can't start running until the slowest build target completes.
2017-12-14 08:55:42 -08:00
e3140ae888 docs: add changelog for 5.1.1 2017-12-13 11:26:01 -08:00
ca815106c9 release: cut the 5.1.1. release 2017-12-13 11:24:54 -08:00
d6da7988c0 fix(compiler): support referencing enums in namespaces (#20947)
Due to an overly agressive assert the compiler would generate
an internal error when referencing an enum declared in
namspace.

Fixes #18170

PR Close #20947
2017-12-12 11:56:41 -08:00
41e1951ffb ci: clean up circleci/config.yml (#20954)
PR Close #20954
2017-12-12 11:56:37 -08:00
c02f97ce4e ci: allow me to approve circleCI changes (#20957)
Removes the root group from the pullapprove settings for .circleci/*
PR Close #20957
2017-12-12 11:56:31 -08:00
be9a7371b8 fix(compiler-cli): merge @fileoverview comments. (#20870)
Previously, this code would unconditionally add a @fileoverview
comment to generated files, and only if the contained any code at all.

However often existing fileoverview comments should be copied from the
file the generated file was originally based off of. This allows users
to e.g. include Closure Compiler directives in their original
`component.ts` file, which will then automaticallly also apply to code
generated from it.

This special cases `@license` comments, as Closure disregards directives
in comments containing `@license`.

PR Close #20870
2017-12-12 11:38:04 -08:00
1f469497da ci: use container version in cache key (#20952)
PR Close #20952
2017-12-11 16:07:34 -08:00
8a5f0f7a64 build: pin ChromeDriver version (#20940)
Since our version of Chromium is also pinned, a new ChromeDriver (that
drops support for our Chromium version) can cause random (and unrelated
to the corresponding changes) errors on CI.
This commit pins the version of ChromeDriver and it should now be
manually upgraded to a vrsion that is compatible with th currently used
Chromium version.

PR Close #20940
2017-12-11 15:53:22 -08:00
8bcb093bfa build: update node version number in .nvmrc (#20832)
PR Close #20832
2017-12-11 12:59:37 -08:00
abc3a1e844 docs: update DEVELOPER.md with the node and yarn info (#20832)
I intentionally removed version numbers so that we don't need to update them in this file -
because we usually forget.

PR Close #20832
2017-12-11 12:59:37 -08:00
9fbf850897 build: remove bazel option --noshow_results (#20943)
I originally added this when I was trying to build `//packages/core`, which is not what users will do often.
This makes it harder for team members to understand what Bazel is doing. I find myself suggesting to turn it off, so it's better to just remove it.
PR Close #20943
2017-12-11 11:18:18 -08:00
0c9f7b032a fix(bazel): don't equate moduleName with fileName (#20895)
Fixes broken material build.
/cc @jelbourn
PR Close #20895
2017-12-11 11:18:13 -08:00
8b21be5da3 build: require bazel 0.8 (#20897)
Users should get an error if they are running an older version of Bazel than we have on CI.
PR Close #20897
2017-12-11 11:18:07 -08:00
0a9a16183f build: new docker image, faster to boot on circleci 2017-12-11 11:18:00 -08:00
28555bc1e7 ci: print the buildifier command when BUILD lint fails (#20882)
PR Close #20882
2017-12-11 11:17:16 -08:00
d09d4971b3 fix(animations): ensure multi-level route leave animations are queryable (#20787)
Closes #19807

PR Close #20787
2017-12-08 13:44:20 -08:00
f8a4d14c8f ci: remove obsolete chromedriverpatch (#18515)
Dart(ium) is not used anymore in Angular so this file should be obsolete

PR Close #18515
2017-12-08 13:44:17 -08:00
d713225128 refactor(common): update i18n locale data to CLDR v32 (#20830)
List of changes between v31.0.1 and v32: http://cldr.unicode.org/index/downloads/cldr-32
PR Close #20830
2017-12-08 10:25:01 -08:00
5d3af4cad4 docs(common): fix mistakes in number pipe example (#20788)
PR Close #20788
2017-12-08 10:24:46 -08:00
a7fe063aa5 ci: add IgorMinar to bazel pullapprove group (#20843)
PR Close #20843
2017-12-08 10:24:41 -08:00
affa54ddf9 build(aio): upgrade to latest @angular/cli (#18428)
PR Close #18428
2017-12-08 10:11:22 -08:00
02782c10ea build(aio): upgrade to latest @angular/material and @angular/cdk (#18428)
PR Close #18428
2017-12-08 10:11:22 -08:00
8e5a3a42d6 build(aio): upgrade to latest @angular/* (#18428)
PR Close #18428
2017-12-08 10:11:22 -08:00
dbef8ff2b0 build(aio): upgrade to latest rxjs (#18428)
PR Close #18428
2017-12-08 10:11:22 -08:00
c0f08be3fb fix(aio): fix embedded ToC and improve ToC, destroying components and scroll timing (#18428)
- Fix embedded ToC:
  Previously, the element was added too late and was never instantiated.

- Improve ToC update timing:
  Previously, the ToC was updated after the entering animation was over, which
  resulted in the ToC being outdated for the duration of the animation.

- Improve destroying components timing:
  Previously, the old embedded components were destroyed as soon as a
  new document was requested. Even if the transition ended up never
  happening (e.g. due to error while preparing the new document), the
  embedded components would have been destroyed and the displayed
  document would not work as expected.
  Now the old embedded components are destroyed only after the new
  document has been fully prepared.

- Improve scroll-to-top timing:
  Previously, the page was scrolled to top after the entering animation was
  over, which resulted in "jumpi-ness". Now the scrolling happens after the
  leaving document has been removed and before the entering document has been
  inserted.

PR Close #18428
2017-12-08 10:11:22 -08:00
f56cbcc1e5 feat(aio): animate the leaving/entering documents (#18428)
This commit adds a simple fade-in/out animation.

Fixes #15629

PR Close #18428
2017-12-08 10:11:22 -08:00
1b86570b60 fix(aio): do not show new document until embedded components are ready (#18428)
Previously, the document was shown as soon as the HTML was received, but before
the embedded components were ready (e.g. downloaded and instantiated). This
caused FOUC (Flash Of Uninstantiated Components).
This commit fixes it by preparing the new document in an off-DOM node and
swapping the nodes when the embedded components are ready.

PR Close #18428
2017-12-08 10:11:22 -08:00
923227dec2 feat(aio): lazy-load embedded components (#18428)
Fixes #16127

PR Close #18428
2017-12-08 10:11:22 -08:00
53b9de300b docs(aio): fix typo for missing quote (#20888)
PR Close #20888
2017-12-08 10:06:46 -08:00
da587cb9ef fix(aio): tsconfig.app.json excludes all testing files (#20779)
Fixes app build error in testing guide which has testing folder at multiple levels,
with files in them referring to files in the root `testing` folder.
Also removed the exclusion of files with `.1` in the name because
all app `.ts` files must be buildable per aio policy.
must build

PR Close #20779
2017-12-08 10:05:51 -08:00
e6a28054d8 fix(animations): properly recover and cleanup DOM when CD failures occur (#20719)
Closes #19093

PR Close #20719
2017-12-07 17:17:47 -08:00
69ed916b42 refactor(animations): instantiate Set-matching code with values in constructor (#20725)
For some reason, prior to this fix, the boolean set matching
code (within `animation_transition_expr.ts`) failed to remain
the same when compiled with closure. This refactor makes sure
that the code stays in tact.

Reproduction Details:
Passes without `ng build --prod`: https://burger.stackblitz.io/
Fails with `ng build --prod`: http://burger.fxck.cz/

Closes #20374

PR Close #20725
2017-12-07 17:17:43 -08:00
c3e8731145 fix(animations): ensure the web-animations driver properly handles empty keyframes (#20648)
Closes #15858

PR Close #20648
2017-12-07 17:17:32 -08:00
501f01e9ac fix(animations): support webkit-based vendor prefixes for prop validations (#19055)
Closes #18921

PR Close #19055
2017-12-07 17:17:27 -08:00
baeec4dbe2 fix(router): NavigatonError and NavigationCancel should be emitted after resetting the URL (#20803)
PR Close #20803
2017-12-07 13:34:40 -08:00
160a154553 fix(compiler-cli): disable checkTypes in emit. (#20828)
Closure Compiler by default will report diagnostics from type checks in
any JavaScript code, including code emitted by the Angular compiler.
Disabling `checkTypes` substantially reduces warning spam for users, and
allows them to run with stricter compiler flags (e.g. treating actual
diagnostics from user code as errors).

Closure Compiler will still type check the code and use types (where
found and correct) for optimizations.

PR Close #20828
2017-12-07 13:34:32 -08:00
9dd60a5fb0 build: upgrade bazel rules to latest (#20768)
Add enough BUILD files to make it possible to
`bazel build packages/core/test`

Also re-format BUILD.bazel files with Buildifier.
Add a CI lint check that they stay formatted.

PR Close #20768
2017-12-07 13:25:47 -08:00
672733608b fix(compiler-cli): Fix swallowed Error messages (#20846)
This commit fixes a bug in which non-formatted errors are silently
dropped.

Internal issue: b/67739418

PR Close #20846
2017-12-06 17:42:19 -08:00
60 changed files with 216 additions and 1274 deletions

View File

@ -25,6 +25,7 @@
# tinayuangao - Tina Gao
# vicb - Victor Berchet
# vikerman - Vikram Subramanian
# wardbell - Ward Bell
version: 2
@ -311,6 +312,7 @@ groups:
- juleskremer #primary
- Foxandxss
- stephenfluin
- wardbell
- petebacondarwin
- gkalpak
- IgorMinar #fallback

View File

@ -1,20 +1,3 @@
<a name="5.2.0-beta.1"></a>
# [5.2.0-beta.1](https://github.com/angular/angular/compare/5.2.0-beta.0...5.2.0-beta.1) (2017-12-20)
### Bug Fixes
* **compiler:** generate the correct imports for summary type-check ([d91ff17](https://github.com/angular/angular/commit/d91ff17))
* **forms:** avoid producing an error with hostBindingTypeCheck ([d213a20](https://github.com/angular/angular/commit/d213a20))
### Features
* **compiler:** allow ngIf to use the ngIf expression directly as a guard ([82bcd83](https://github.com/angular/angular/commit/82bcd83))
* **router:** add "paramsInheritanceStrategy" router configuration option ([5efea2f](https://github.com/angular/angular/commit/5efea2f)), closes [#20572](https://github.com/angular/angular/issues/20572)
<a name="5.1.2"></a>
## [5.1.2](https://github.com/angular/angular/compare/5.1.1...5.1.2) (2017-12-20)
@ -31,20 +14,6 @@
<a name="5.2.0-beta.0"></a>
# [5.2.0-beta.0](https://github.com/angular/angular/compare/5.1.0...5.2.0-beta.0) (2017-12-13)
### Features
* **animations:** re-introduce support for transition matching functions ([#20723](https://github.com/angular/angular/issues/20723)) ([590d93b](https://github.com/angular/angular/commit/590d93b)), closes [#18959](https://github.com/angular/angular/issues/18959)
* **compiler:** add a pseudo $any() function to disable type checking ([#20876](https://github.com/angular/angular/issues/20876)) ([70cd124](https://github.com/angular/angular/commit/70cd124))
* **compiler:** narrow types of expressions used in *ngIf ([#20702](https://github.com/angular/angular/issues/20702)) ([e7d9cb3](https://github.com/angular/angular/commit/e7d9cb3))
* **core:** add source to `StaticInjectorError` message ([#20817](https://github.com/angular/angular/issues/20817)) ([b7738e1](https://github.com/angular/angular/commit/b7738e1)), closes [#19302](https://github.com/angular/angular/issues/19302)
* **forms:** allow nulls on setAsyncValidators ([#20327](https://github.com/angular/angular/issues/20327)) ([d41d2c4](https://github.com/angular/angular/commit/d41d2c4)), closes [#20296](https://github.com/angular/angular/issues/20296)
<a name="5.1.1"></a>
## [5.1.1](https://github.com/angular/angular/compare/5.1.0...5.1.1) (2017-12-13)

View File

@ -1,6 +1,6 @@
{
"name": "angular-srcs",
"version": "5.2.0-beta.1",
"version": "5.1.2",
"private": true,
"branchPattern": "2.0.*",
"description": "Angular - a web framework for modern web apps",

View File

@ -1393,10 +1393,10 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
public markedForDestroy: boolean = false;
readonly queued: boolean = true;
constructor(public namespaceId: string, public triggerName: string, public element: any) {}
get queued() { return this._containsRealPlayer == false; }
setRealPlayer(player: AnimationPlayer) {
if (this._containsRealPlayer) return;
@ -1407,7 +1407,6 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
});
this._queuedCallbacks = {};
this._containsRealPlayer = true;
(this as{queued: boolean}).queued = false;
}
getRealPlayer() { return this._player; }

View File

@ -115,7 +115,7 @@ export interface AnimationStateMetadata extends AnimationMetadata {
* @experimental Animation support is experimental.
*/
export interface AnimationTransitionMetadata extends AnimationMetadata {
expr: string|((fromState: string, toState: string) => boolean);
expr: string;
animation: AnimationMetadata|AnimationMetadata[];
options: AnimationOptions|null;
}
@ -836,8 +836,7 @@ export function keyframes(steps: AnimationStyleMetadata[]): AnimationKeyframesSe
* @experimental Animation support is experimental.
*/
export function transition(
stateChangeExpr: string | ((fromState: string, toState: string) => boolean),
steps: AnimationMetadata | AnimationMetadata[],
stateChangeExpr: string, steps: AnimationMetadata | AnimationMetadata[],
options: AnimationOptions | null = null): AnimationTransitionMetadata {
return {type: AnimationMetadataType.Transition, expr: stateChangeExpr, animation: steps, options};
}

View File

@ -23,12 +23,13 @@ export class MockScriptElement {
export class MockDocument {
mock: MockScriptElement|null;
readonly body: any = this;
createElement(tag: 'script'): HTMLScriptElement {
return new MockScriptElement() as any as HTMLScriptElement;
}
get body(): any { return this; }
appendChild(node: any): void { this.mock = node; }
removeNode(node: any): void {
@ -40,4 +41,4 @@ export class MockDocument {
mockLoad(): void { this.mock !.listeners.load !(null as any); }
mockError(err: Error) { this.mock !.listeners.error !(err); }
}
}

View File

@ -151,9 +151,6 @@ export class NgIf {
}
}
}
/** @internal */
public static ngIfUseIfTypeGuard: void;
}
/**

View File

@ -48,11 +48,11 @@ describe('ng type checker', () => {
}
function reject(
message: string | RegExp, location: RegExp | null, files: MockFiles,
message: string | RegExp, location: RegExp, files: MockFiles,
overrideOptions: ng.CompilerOptions = {}) {
const diagnostics = compileAndCheck([QUICKSTART, files], overrideOptions);
if (!diagnostics || !diagnostics.length) {
throw new Error('Expected a diagnostic error message');
throw new Error('Expected a diagnostic erorr message');
} else {
const matches: (d: ng.Diagnostic) => boolean = typeof message === 'string' ?
d => ng.isNgDiagnostic(d)&& d.messageText == message :
@ -63,13 +63,11 @@ describe('ng type checker', () => {
`Expected a diagnostics matching ${message}, received\n ${diagnostics.map(d => d.messageText).join('\n ')}`);
}
if (location) {
const span = matchingDiagnostics[0].span;
if (!span) {
throw new Error('Expected a sourceSpan');
}
expect(`${span.start.file.url}@${span.start.line}:${span.start.offset}`).toMatch(location);
const span = matchingDiagnostics[0].span;
if (!span) {
throw new Error('Expected a sourceSpan');
}
expect(`${span.start.file.url}@${span.start.line}:${span.start.offset}`).toMatch(location);
}
}
@ -83,543 +81,6 @@ describe('ng type checker', () => {
});
});
describe('type narrowing', () => {
const a = (files: MockFiles, options: object = {}) => {
accept(files, {fullTemplateTypeCheck: true, ...options});
};
it('should narrow an *ngIf like directive', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *myIf="person"> {{person.name}} </div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfTypeGuard: <T>(v: T | null | undefined | false) => v is T;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow a renamed *ngIf like directive', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *my-if="person"> {{person.name}} </div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[my-if]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input('my-if')
set myIf(condition: any) {}
static myIfTypeGuard: <T>(v: T | null | undefined | false) => v is T;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow a type in a nested *ngIf like directive', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Address {
street: string;
}
export interface Person {
name: string;
address?: Address;
}
@Component({
selector: 'comp',
template: '<div *myIf="person"> {{person.name}} <span *myIf="person.address">{{person.address.street}}</span></div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfTypeGuard: <T>(v: T | null | undefined | false) => v is T;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow an *ngIf like directive with UseIf', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *myIf="person"> {{person.name}} </div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfUseIfTypeGuard: void;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow a renamed *ngIf like directive with UseIf', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *my-if="person"> {{person.name}} </div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[my-if]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input('my-if')
set myIf(condition: any) {}
static myIfUseIfTypeGuard: void;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow a type in a nested *ngIf like directive with UseIf', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Address {
street: string;
}
export interface Person {
name: string;
address?: Address;
}
@Component({
selector: 'comp',
template: '<div *myIf="person"> {{person.name}} <span *myIf="person.address">{{person.address.street}}</span></div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfUseIfTypeGuard: void;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow an *ngIf like directive with UseIf and &&', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Address {
street: string;
}
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *myIf="person && address"> {{person.name}} lives at {{address.street}} </div>'
})
export class MainComp {
person?: Person;
address?: Address;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfUseIfTypeGuard: void;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow an *ngIf like directive with UseIf and !!', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *myIf="!!person"> {{person.name}} </div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfUseIfTypeGuard: void;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow an *ngIf like directive with UseIf and != null', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *myIf="person != null"> {{person.name}} </div>'
})
export class MainComp {
person: Person | null = null;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfUseIfTypeGuard: void;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow an *ngIf like directive with UseIf and != undefined', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *myIf="person != undefined"> {{person.name}} </div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfUseIfTypeGuard: void;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
});
describe('casting $any', () => {
const a = (files: MockFiles, options: object = {}) => {
accept(
{'src/app.component.ts': '', 'src/lib.ts': '', ...files},
{fullTemplateTypeCheck: true, ...options});
};
const r =
(message: string | RegExp, location: RegExp | null, files: MockFiles,
options: object = {}) => {
reject(
message, location, {'src/app.component.ts': '', 'src/lib.ts': '', ...files},
{fullTemplateTypeCheck: true, ...options});
};
it('should allow member access of an expression', () => {
a({
'src/app.module.ts': `
import {NgModule, Component} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: ' {{$any(person).address}}'
})
export class MainComp {
person: Person;
}
@NgModule({
declarations: [MainComp],
})
export class MainModule {
}`
});
});
it('should allow invalid this.member access', () => {
a({
'src/app.module.ts': `
import {NgModule, Component} from '@angular/core';
@Component({
selector: 'comp',
template: ' {{$any(this).missing}}'
})
export class MainComp { }
@NgModule({
declarations: [MainComp],
})
export class MainModule {
}`
});
});
it('should reject too few parameters to $any', () => {
r(/Invalid call to \$any, expected 1 argument but received none/, null, {
'src/app.module.ts': `
import {NgModule, Component} from '@angular/core';
@Component({
selector: 'comp',
template: ' {{$any().missing}}'
})
export class MainComp { }
@NgModule({
declarations: [MainComp],
})
export class MainModule {
}`
});
});
it('should reject too many parameters to $any', () => {
r(/Invalid call to \$any, expected 1 argument but received 2/, null, {
'src/app.module.ts': `
import {NgModule, Component} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: ' {{$any(person, 12).missing}}'
})
export class MainComp {
person: Person;
}
@NgModule({
declarations: [MainComp],
})
export class MainModule {
}`
});
});
});
describe('regressions ', () => {
const a = (files: MockFiles, options: object = {}) => {
accept(files, {fullTemplateTypeCheck: true, ...options});

View File

@ -1038,25 +1038,6 @@ describe('Collector', () => {
expect(metadata).toBeUndefined();
});
it('should collect type guards', () => {
const metadata = collectSource(`
import {Directive, Input, TemplateRef} from '@angular/core';
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(private templateRef: TemplateRef) {}
@Input() myIf: any;
static typeGuard: <T>(v: T | null | undefined): v is T;
}
`);
expect((metadata.metadata.MyIf as any).statics.typeGuard)
.not.toBeUndefined('typeGuard was not collected');
});
it('should be able to collect an invalid access expression', () => {
const source = createSource(`
import {Component} from '@angular/core';

View File

@ -12,7 +12,6 @@ import * as path from 'path';
import * as ts from 'typescript';
import * as ng from '../index';
// TEST_TMPDIR is set by bazel.
const tmpdir = process.env.TEST_TMPDIR || os.tmpdir();
function getNgRootDir() {
@ -22,6 +21,7 @@ function getNgRootDir() {
}
export function writeTempFile(name: string, contents: string): string {
// TEST_TMPDIR is set by bazel.
const id = (Math.random() * 1000000).toFixed(0);
const fn = path.join(tmpdir, `tmp.${id}.${name}`);
fs.writeFileSync(fn, contents);
@ -29,12 +29,8 @@ export function writeTempFile(name: string, contents: string): string {
}
export function makeTempDir(): string {
let dir: string;
while (true) {
const id = (Math.random() * 1000000).toFixed(0);
dir = path.join(tmpdir, `tmp.${id}`);
if (!fs.existsSync(dir)) break;
}
const id = (Math.random() * 1000000).toFixed(0);
const dir = path.join(tmpdir, `tmp.${id}`);
fs.mkdirSync(dir);
return dir;
}

View File

@ -218,14 +218,15 @@ export class AotCompiler {
const externalReferenceVars = new Map<any, string>();
externalReferences.forEach((ref, typeIndex) => {
externalReferenceVars.set(ref, `_decl${ngModuleIndex}_${typeIndex}`);
if (this._host.isSourceFile(ref.filePath)) {
externalReferenceVars.set(ref, `_decl${ngModuleIndex}_${typeIndex}`);
}
});
externalReferenceVars.forEach((varName, reference) => {
outputCtx.statements.push(
o.variable(varName)
.set(o.NULL_EXPR.cast(o.DYNAMIC_TYPE))
.toDeclStmt(o.expressionType(outputCtx.importExpr(
reference, /* typeParams */ null, /* useSummaries */ false))));
.toDeclStmt(o.expressionType(outputCtx.importExpr(reference))));
});
if (emitFlags & StubEmitFlags.TypeCheck) {
@ -270,7 +271,7 @@ export class AotCompiler {
const {template: parsedTemplate, pipes: usedPipes} =
this._parseTemplate(compMeta, moduleMeta, directives);
ctx.statements.push(...this._typeCheckCompiler.compileComponent(
componentId, compMeta, parsedTemplate, usedPipes, externalReferenceVars, ctx));
componentId, compMeta, parsedTemplate, usedPipes, externalReferenceVars));
}
emitMessageBundle(analyzeResult: NgAnalyzedModules, locale: string|null): MessageBundle {
@ -514,38 +515,35 @@ export class AotCompiler {
}
private _createOutputContext(genFilePath: string): OutputContext {
const importExpr =
(symbol: StaticSymbol, typeParams: o.Type[] | null = null,
useSummaries: boolean = true) => {
if (!(symbol instanceof StaticSymbol)) {
throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
}
const arity = this._symbolResolver.getTypeArity(symbol) || 0;
const {filePath, name, members} =
this._symbolResolver.getImportAs(symbol, useSummaries) || symbol;
const importModule = this._fileNameToModuleName(filePath, genFilePath);
const importExpr = (symbol: StaticSymbol, typeParams: o.Type[] | null = null) => {
if (!(symbol instanceof StaticSymbol)) {
throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
}
const arity = this._symbolResolver.getTypeArity(symbol) || 0;
const {filePath, name, members} = this._symbolResolver.getImportAs(symbol) || symbol;
const importModule = this._fileNameToModuleName(filePath, genFilePath);
// It should be good enough to compare filePath to genFilePath and if they are equal
// there is a self reference. However, ngfactory files generate to .ts but their
// symbols have .d.ts so a simple compare is insufficient. They should be canonical
// and is tracked by #17705.
const selfReference = this._fileNameToModuleName(genFilePath, genFilePath);
const moduleName = importModule === selfReference ? null : importModule;
// It should be good enough to compare filePath to genFilePath and if they are equal
// there is a self reference. However, ngfactory files generate to .ts but their
// symbols have .d.ts so a simple compare is insufficient. They should be canonical
// and is tracked by #17705.
const selfReference = this._fileNameToModuleName(genFilePath, genFilePath);
const moduleName = importModule === selfReference ? null : importModule;
// If we are in a type expression that refers to a generic type then supply
// the required type parameters. If there were not enough type parameters
// supplied, supply any as the type. Outside a type expression the reference
// should not supply type parameters and be treated as a simple value reference
// to the constructor function itself.
const suppliedTypeParams = typeParams || [];
const missingTypeParamsCount = arity - suppliedTypeParams.length;
const allTypeParams =
suppliedTypeParams.concat(new Array(missingTypeParamsCount).fill(o.DYNAMIC_TYPE));
return members.reduce(
(expr, memberName) => expr.prop(memberName),
<o.Expression>o.importExpr(
new o.ExternalReference(moduleName, name, null), allTypeParams));
};
// If we are in a type expression that refers to a generic type then supply
// the required type parameters. If there were not enough type parameters
// supplied, supply any as the type. Outside a type expression the reference
// should not supply type parameters and be treated as a simple value reference
// to the constructor function itself.
const suppliedTypeParams = typeParams || [];
const missingTypeParamsCount = arity - suppliedTypeParams.length;
const allTypeParams =
suppliedTypeParams.concat(new Array(missingTypeParamsCount).fill(o.DYNAMIC_TYPE));
return members.reduce(
(expr, memberName) => expr.prop(memberName),
<o.Expression>o.importExpr(
new o.ExternalReference(moduleName, name, null), allTypeParams));
};
return {statements: [], genFilePath, importExpr};
}

View File

@ -29,8 +29,6 @@ const IGNORE = {
const USE_VALUE = 'useValue';
const PROVIDE = 'provide';
const REFERENCE_SET = new Set([USE_VALUE, 'useFactory', 'data']);
const TYPEGUARD_POSTFIX = 'TypeGuard';
const USE_IF = 'UseIf';
function shouldIgnore(value: any): boolean {
return value && value.__symbolic == 'ignore';
@ -45,7 +43,6 @@ export class StaticReflector implements CompileReflector {
private propertyCache = new Map<StaticSymbol, {[key: string]: any[]}>();
private parameterCache = new Map<StaticSymbol, any[]>();
private methodCache = new Map<StaticSymbol, {[key: string]: boolean}>();
private staticCache = new Map<StaticSymbol, string[]>();
private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
private injectionToken: StaticSymbol;
private opaqueToken: StaticSymbol;
@ -254,18 +251,6 @@ export class StaticReflector implements CompileReflector {
return methodNames;
}
private _staticMembers(type: StaticSymbol): string[] {
let staticMembers = this.staticCache.get(type);
if (!staticMembers) {
const classMetadata = this.getTypeMetadata(type);
const staticMemberData = classMetadata['statics'] || {};
staticMembers = Object.keys(staticMemberData);
this.staticCache.set(type, staticMembers);
}
return staticMembers;
}
private findParentType(type: StaticSymbol, classMetadata: any): StaticSymbol|undefined {
const parentType = this.trySimplify(type, classMetadata['extends']);
if (parentType instanceof StaticSymbol) {
@ -288,30 +273,6 @@ export class StaticReflector implements CompileReflector {
}
}
guards(type: any): {[key: string]: StaticSymbol} {
if (!(type instanceof StaticSymbol)) {
this.reportError(
new Error(`guards received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
return {};
}
const staticMembers = this._staticMembers(type);
const result: {[key: string]: StaticSymbol} = {};
for (let name of staticMembers) {
if (name.endsWith(TYPEGUARD_POSTFIX)) {
let property = name.substr(0, name.length - TYPEGUARD_POSTFIX.length);
let value: any;
if (property.endsWith(USE_IF)) {
property = name.substr(0, property.length - USE_IF.length);
value = USE_IF;
} else {
value = this.getStaticSymbol(type.filePath, type.name, [name]);
}
result[property] = value;
}
}
return result;
}
private _registerDecoratorOrConstructor(type: StaticSymbol, ctor: any): void {
this.conversionMap.set(type, (context: StaticSymbol, args: any[]) => new ctor(...args));
}

View File

@ -98,10 +98,10 @@ export class StaticSymbolResolver {
*
* @param staticSymbol the symbol for which to generate a import symbol
*/
getImportAs(staticSymbol: StaticSymbol, useSummaries: boolean = true): StaticSymbol|null {
getImportAs(staticSymbol: StaticSymbol): StaticSymbol|null {
if (staticSymbol.members.length) {
const baseSymbol = this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name);
const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
const baseImportAs = this.getImportAs(baseSymbol);
return baseImportAs ?
this.getStaticSymbol(baseImportAs.filePath, baseImportAs.name, staticSymbol.members) :
null;
@ -111,14 +111,14 @@ export class StaticSymbolResolver {
const summarizedName = stripSummaryForJitNameSuffix(staticSymbol.name);
const baseSymbol =
this.getStaticSymbol(summarizedFileName, summarizedName, staticSymbol.members);
const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
const baseImportAs = this.getImportAs(baseSymbol);
return baseImportAs ?
this.getStaticSymbol(
summaryForJitFileName(baseImportAs.filePath), summaryForJitName(baseImportAs.name),
baseSymbol.members) :
null;
}
let result = (useSummaries && this.summaryResolver.getImportAs(staticSymbol)) || null;
let result = this.summaryResolver.getImportAs(staticSymbol);
if (!result) {
result = this.importAs.get(staticSymbol) !;
}

View File

@ -254,7 +254,6 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
providers: CompileProviderMetadata[];
viewProviders: CompileProviderMetadata[];
queries: CompileQueryMetadata[];
guards: {[key: string]: any};
viewQueries: CompileQueryMetadata[];
entryComponents: CompileEntryComponentMetadata[];
changeDetection: ChangeDetectionStrategy|null;
@ -269,8 +268,8 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
*/
export class CompileDirectiveMetadata {
static create({isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs,
host, providers, viewProviders, queries, guards, viewQueries, entryComponents,
template, componentViewType, rendererType, componentFactory}: {
host, providers, viewProviders, queries, viewQueries, entryComponents, template,
componentViewType, rendererType, componentFactory}: {
isHost: boolean,
type: CompileTypeMetadata,
isComponent: boolean,
@ -283,7 +282,6 @@ export class CompileDirectiveMetadata {
providers: CompileProviderMetadata[],
viewProviders: CompileProviderMetadata[],
queries: CompileQueryMetadata[],
guards: {[key: string]: any};
viewQueries: CompileQueryMetadata[],
entryComponents: CompileEntryComponentMetadata[],
template: CompileTemplateMetadata,
@ -338,7 +336,6 @@ export class CompileDirectiveMetadata {
providers,
viewProviders,
queries,
guards,
viewQueries,
entryComponents,
template,
@ -361,7 +358,6 @@ export class CompileDirectiveMetadata {
providers: CompileProviderMetadata[];
viewProviders: CompileProviderMetadata[];
queries: CompileQueryMetadata[];
guards: {[key: string]: any};
viewQueries: CompileQueryMetadata[];
entryComponents: CompileEntryComponentMetadata[];
@ -371,27 +367,10 @@ export class CompileDirectiveMetadata {
rendererType: StaticSymbol|object|null;
componentFactory: StaticSymbol|object|null;
constructor({isHost,
type,
isComponent,
selector,
exportAs,
changeDetection,
inputs,
outputs,
hostListeners,
hostProperties,
hostAttributes,
providers,
viewProviders,
queries,
guards,
viewQueries,
entryComponents,
template,
componentViewType,
rendererType,
componentFactory}: {
constructor({isHost, type, isComponent, selector, exportAs,
changeDetection, inputs, outputs, hostListeners, hostProperties,
hostAttributes, providers, viewProviders, queries, viewQueries,
entryComponents, template, componentViewType, rendererType, componentFactory}: {
isHost: boolean,
type: CompileTypeMetadata,
isComponent: boolean,
@ -406,7 +385,6 @@ export class CompileDirectiveMetadata {
providers: CompileProviderMetadata[],
viewProviders: CompileProviderMetadata[],
queries: CompileQueryMetadata[],
guards: {[key: string]: any},
viewQueries: CompileQueryMetadata[],
entryComponents: CompileEntryComponentMetadata[],
template: CompileTemplateMetadata|null,
@ -428,7 +406,6 @@ export class CompileDirectiveMetadata {
this.providers = _normalizeArray(providers);
this.viewProviders = _normalizeArray(viewProviders);
this.queries = _normalizeArray(queries);
this.guards = guards;
this.viewQueries = _normalizeArray(viewQueries);
this.entryComponents = _normalizeArray(entryComponents);
this.template = template;
@ -453,7 +430,6 @@ export class CompileDirectiveMetadata {
providers: this.providers,
viewProviders: this.viewProviders,
queries: this.queries,
guards: this.guards,
viewQueries: this.viewQueries,
entryComponents: this.entryComponents,
changeDetection: this.changeDetection,

View File

@ -17,7 +17,6 @@ export abstract class CompileReflector {
abstract annotations(typeOrFunc: /*Type*/ any): any[];
abstract propMetadata(typeOrFunc: /*Type*/ any): {[key: string]: any[]};
abstract hasLifecycleHook(type: any, lcProperty: string): boolean;
abstract guards(typeOrFunc: /* Type */ any): {[key: string]: any};
abstract componentModuleUrl(type: /*Type*/ any, cmpMetadata: Component): string;
abstract resolveExternalReference(ref: o.ExternalReference): any;
}

View File

@ -90,14 +90,6 @@ export class ConvertPropertyBindingResult {
constructor(public stmts: o.Statement[], public currValExpr: o.Expression) {}
}
export enum BindingForm {
// The general form of binding expression, supports all expressions.
General,
// Try to generate a simple binding (no temporaries or statements)
// otherise generate a general binding
TrySimple,
}
/**
* Converts the given expression AST into an executable output AST, assuming the expression
* is used in property binding. The expression has to be preprocessed via
@ -105,8 +97,7 @@ export enum BindingForm {
*/
export function convertPropertyBinding(
localResolver: LocalResolver | null, implicitReceiver: o.Expression,
expressionWithoutBuiltins: cdAst.AST, bindingId: string,
form: BindingForm): ConvertPropertyBindingResult {
expressionWithoutBuiltins: cdAst.AST, bindingId: string): ConvertPropertyBindingResult {
if (!localResolver) {
localResolver = new DefaultLocalResolver();
}
@ -119,11 +110,9 @@ export function convertPropertyBinding(
for (let i = 0; i < visitor.temporaryCount; i++) {
stmts.push(temporaryDeclaration(bindingId, i));
}
} else if (form == BindingForm.TrySimple) {
return new ConvertPropertyBindingResult([], outputExpr);
}
stmts.push(currValExpr.set(outputExpr).toDeclStmt(o.DYNAMIC_TYPE, [o.StmtModifier.Final]));
stmts.push(currValExpr.set(outputExpr).toDeclStmt(null, [o.StmtModifier.Final]));
return new ConvertPropertyBindingResult(stmts, currValExpr);
}
@ -334,27 +323,12 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
}
visitLiteralPrimitive(ast: cdAst.LiteralPrimitive, mode: _Mode): any {
// For literal values of null, undefined, true, or false allow type inteference
// to infer the type.
const type =
ast.value === null || ast.value === undefined || ast.value === true || ast.value === true ?
o.INFERRED_TYPE :
undefined;
return convertToStatementIfNeeded(mode, o.literal(ast.value, type));
return convertToStatementIfNeeded(mode, o.literal(ast.value));
}
private _getLocal(name: string): o.Expression|null { return this._localResolver.getLocal(name); }
visitMethodCall(ast: cdAst.MethodCall, mode: _Mode): any {
if (ast.receiver instanceof cdAst.ImplicitReceiver && ast.name == '$any') {
const args = this.visitAll(ast.args, _Mode.Expression) as any[];
if (args.length != 1) {
throw new Error(
`Invalid call to $any, expected 1 argument but received ${args.length || 'none'}`);
}
return (args[0] as o.Expression).cast(o.DYNAMIC_TYPE);
}
const leftMostSafe = this.leftMostSafeNode(ast);
if (leftMostSafe) {
return this.convertSafeAccess(ast, leftMostSafe, mode);

View File

@ -51,7 +51,6 @@ export interface Directive {
providers?: Provider[];
exportAs?: string;
queries?: {[key: string]: any};
guards?: {[key: string]: any};
}
export const createDirective =
makeMetadataFactory<Directive>('Directive', (dir: Directive = {}) => dir);

View File

@ -44,8 +44,7 @@ export class DirectiveResolver {
const metadata = findLast(typeMetadata, isDirectiveMetadata);
if (metadata) {
const propertyMetadata = this._reflector.propMetadata(type);
const guards = this._reflector.guards(type);
return this._mergeWithPropertyMetadata(metadata, propertyMetadata, guards, type);
return this._mergeWithPropertyMetadata(metadata, propertyMetadata, type);
}
}
@ -57,12 +56,12 @@ export class DirectiveResolver {
}
private _mergeWithPropertyMetadata(
dm: Directive, propertyMetadata: {[key: string]: any[]}, guards: {[key: string]: any},
directiveType: Type): Directive {
dm: Directive, propertyMetadata: {[key: string]: any[]}, directiveType: Type): Directive {
const inputs: string[] = [];
const outputs: string[] = [];
const host: {[key: string]: string} = {};
const queries: {[key: string]: any} = {};
Object.keys(propertyMetadata).forEach((propName: string) => {
const input = findLast(propertyMetadata[propName], (a) => createInput.isTypeOf(a));
if (input) {
@ -106,20 +105,18 @@ export class DirectiveResolver {
queries[propName] = query;
}
});
return this._merge(dm, inputs, outputs, host, queries, guards, directiveType);
return this._merge(dm, inputs, outputs, host, queries, directiveType);
}
private _extractPublicName(def: string) { return splitAtColon(def, [null !, def])[1].trim(); }
private _dedupeBindings(bindings: string[]): string[] {
const names = new Set<string>();
const publicNames = new Set<string>();
const reversedResult: string[] = [];
// go last to first to allow later entries to overwrite previous entries
for (let i = bindings.length - 1; i >= 0; i--) {
const binding = bindings[i];
const name = this._extractPublicName(binding);
publicNames.add(name);
if (!names.has(name)) {
names.add(name);
reversedResult.push(binding);
@ -130,13 +127,14 @@ export class DirectiveResolver {
private _merge(
directive: Directive, inputs: string[], outputs: string[], host: {[key: string]: string},
queries: {[key: string]: any}, guards: {[key: string]: any}, directiveType: Type): Directive {
queries: {[key: string]: any}, directiveType: Type): Directive {
const mergedInputs =
this._dedupeBindings(directive.inputs ? directive.inputs.concat(inputs) : inputs);
const mergedOutputs =
this._dedupeBindings(directive.outputs ? directive.outputs.concat(outputs) : outputs);
const mergedHost = directive.host ? {...directive.host, ...host} : host;
const mergedQueries = directive.queries ? {...directive.queries, ...queries} : queries;
if (createComponent.isTypeOf(directive)) {
const comp = directive as Component;
return createComponent({
@ -168,7 +166,7 @@ export class DirectiveResolver {
host: mergedHost,
exportAs: directive.exportAs,
queries: mergedQueries,
providers: directive.providers, guards
providers: directive.providers
});
}
}

View File

@ -208,7 +208,6 @@ export class CompileMetadataResolver {
providers: [],
viewProviders: [],
queries: [],
guards: {},
viewQueries: [],
componentViewType: hostViewType,
rendererType:
@ -241,7 +240,6 @@ export class CompileMetadataResolver {
providers: metadata.providers,
viewProviders: metadata.viewProviders,
queries: metadata.queries,
guards: metadata.guards,
viewQueries: metadata.viewQueries,
entryComponents: metadata.entryComponents,
componentViewType: metadata.componentViewType,
@ -385,7 +383,6 @@ export class CompileMetadataResolver {
providers: providers || [],
viewProviders: viewProviders || [],
queries: queries || [],
guards: dirMeta.guards || {},
viewQueries: viewQueries || [],
entryComponents: entryComponentMetadata,
componentViewType: nonNormalizedTemplateMetadata ? this.getComponentViewClass(directiveType) :

View File

@ -152,7 +152,7 @@ export function utf8Encode(str: string): string {
export interface OutputContext {
genFilePath: string;
statements: o.Statement[];
importExpr(reference: any, typeParams?: o.Type[]|null, useSummaries?: boolean): o.Expression;
importExpr(reference: any, typeParams?: o.Type[]|null): o.Expression;
}
export function stringify(token: any): string {

View File

@ -10,15 +10,13 @@ import {AotCompilerOptions} from '../aot/compiler_options';
import {StaticReflector} from '../aot/static_reflector';
import {StaticSymbol} from '../aot/static_symbol';
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompilePipeSummary} from '../compile_metadata';
import {BindingForm, BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
import {BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
import {AST, ASTWithSource, Interpolation} from '../expression_parser/ast';
import {Identifiers} from '../identifiers';
import * as o from '../output/output_ast';
import {convertValueToOutputAst} from '../output/value_util';
import {ParseSourceSpan} from '../parse_util';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, ProviderAstType, QueryMatch, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
import {OutputContext} from '../util';
/**
* Generates code that is used to type check templates.
@ -36,34 +34,27 @@ export class TypeCheckCompiler {
*/
compileComponent(
componentId: string, component: CompileDirectiveMetadata, template: TemplateAst[],
usedPipes: CompilePipeSummary[], externalReferenceVars: Map<StaticSymbol, string>,
ctx: OutputContext): o.Statement[] {
usedPipes: CompilePipeSummary[],
externalReferenceVars: Map<StaticSymbol, string>): o.Statement[] {
const pipes = new Map<string, StaticSymbol>();
usedPipes.forEach(p => pipes.set(p.name, p.type.reference));
let embeddedViewCount = 0;
const viewBuilderFactory =
(parent: ViewBuilder | null, guards: GuardExpression[]): ViewBuilder => {
const embeddedViewIndex = embeddedViewCount++;
return new ViewBuilder(
this.options, this.reflector, externalReferenceVars, parent, component.type.reference,
component.isHost, embeddedViewIndex, pipes, guards, ctx, viewBuilderFactory);
};
const viewBuilderFactory = (parent: ViewBuilder | null): ViewBuilder => {
const embeddedViewIndex = embeddedViewCount++;
return new ViewBuilder(
this.options, this.reflector, externalReferenceVars, parent, component.type.reference,
component.isHost, embeddedViewIndex, pipes, viewBuilderFactory);
};
const visitor = viewBuilderFactory(null, []);
const visitor = viewBuilderFactory(null);
visitor.visitAll([], template);
return visitor.build(componentId);
}
}
interface GuardExpression {
guard: StaticSymbol;
useIf: boolean;
expression: Expression;
}
interface ViewBuilderFactory {
(parent: ViewBuilder, guards: GuardExpression[]): ViewBuilder;
(parent: ViewBuilder): ViewBuilder;
}
// Note: This is used as key in Map and should therefore be
@ -103,7 +94,6 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
private externalReferenceVars: Map<StaticSymbol, string>, private parent: ViewBuilder|null,
private component: StaticSymbol, private isHostComponent: boolean,
private embeddedViewIndex: number, private pipes: Map<string, StaticSymbol>,
private guards: GuardExpression[], private ctx: OutputContext,
private viewBuilderFactory: ViewBuilderFactory) {}
private getOutputVar(type: o.BuiltinTypeName|StaticSymbol): string {
@ -122,24 +112,6 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
return varName;
}
private getTypeGuardExpressions(ast: EmbeddedTemplateAst): GuardExpression[] {
const result = [...this.guards];
for (let directive of ast.directives) {
for (let input of directive.inputs) {
const guard = directive.directive.guards[input.directiveName];
if (guard) {
const useIf = guard === 'UseIf';
result.push({
guard,
useIf,
expression: {context: this.component, value: input.value} as Expression
});
}
}
}
return result;
}
visitAll(variables: VariableAst[], astNodes: TemplateAst[]) {
this.variables = variables;
templateVisitAll(this, astNodes);
@ -147,7 +119,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
build(componentId: string, targetStatements: o.Statement[] = []): o.Statement[] {
this.children.forEach((child) => child.build(componentId, targetStatements));
let viewStmts: o.Statement[] =
const viewStmts: o.Statement[] =
[o.variable(DYNAMIC_VAR_NAME).set(o.NULL_EXPR).toDeclStmt(o.DYNAMIC_TYPE)];
let bindingCount = 0;
this.updates.forEach((expression) => {
@ -155,8 +127,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
const bindingId = `${bindingCount++}`;
const nameResolver = context === this.component ? this : defaultResolver;
const {stmts, currValExpr} = convertPropertyBinding(
nameResolver, o.variable(this.getOutputVar(context)), value, bindingId,
BindingForm.General);
nameResolver, o.variable(this.getOutputVar(context)), value, bindingId);
stmts.push(new o.ExpressionStatement(currValExpr));
viewStmts.push(...stmts.map(
(stmt: o.Statement) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
@ -171,28 +142,6 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
(stmt: o.Statement) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
});
if (this.guards.length) {
let guardExpression: o.Expression|undefined = undefined;
for (const guard of this.guards) {
const {context, value} = this.preprocessUpdateExpression(guard.expression);
const bindingId = `${bindingCount++}`;
const nameResolver = context === this.component ? this : defaultResolver;
// We only support support simple expressions and ignore others as they
// are unlikely to affect type narrowing.
const {stmts, currValExpr} = convertPropertyBinding(
nameResolver, o.variable(this.getOutputVar(context)), value, bindingId,
BindingForm.TrySimple);
if (stmts.length == 0) {
const guardClause =
guard.useIf ? currValExpr : this.ctx.importExpr(guard.guard).callFn([currValExpr]);
guardExpression = guardExpression ? guardExpression.and(guardClause) : guardClause;
}
}
if (guardExpression) {
viewStmts = [new o.IfStmt(guardExpression, viewStmts)];
}
}
const viewName = `_View_${componentId}_${this.embeddedViewIndex}`;
const viewFactory = new o.DeclareFunctionStmt(viewName, [], viewStmts);
targetStatements.push(viewFactory);
@ -214,12 +163,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
// for the context in any embedded view.
// We keep this behaivor behind a flag for now.
if (this.options.fullTemplateTypeCheck) {
// Find any applicable type guards. For example, NgIf has a type guard on ngIf
// (see NgIf.ngIfTypeGuard) that can be used to indicate that a template is only
// stamped out if ngIf is truthy so any bindings in the template can assume that,
// if a nullable type is used for ngIf, that expression is not null or undefined.
const guards = this.getTypeGuardExpressions(ast);
const childVisitor = this.viewBuilderFactory(this, guards);
const childVisitor = this.viewBuilderFactory(this);
this.children.push(childVisitor);
childVisitor.visitAll(ast.variables, ast.children);
}

View File

@ -8,7 +8,7 @@
import {CompileDirectiveMetadata, CompilePipeSummary, rendererTypeName, tokenReference, viewClassName} from '../compile_metadata';
import {CompileReflector} from '../compile_reflector';
import {BindingForm, BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
import {BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
import {ArgumentType, BindingFlags, ChangeDetectionStrategy, NodeFlags, QueryBindingType, QueryValueType, ViewFlags} from '../core';
import {AST, ASTWithSource, Interpolation} from '../expression_parser/ast';
import {Identifiers} from '../identifiers';
@ -859,7 +859,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
const bindingId = `${updateBindingCount++}`;
const nameResolver = context === COMP_VAR ? self : null;
const {stmts, currValExpr} =
convertPropertyBinding(nameResolver, context, value, bindingId, BindingForm.General);
convertPropertyBinding(nameResolver, context, value, bindingId);
updateStmts.push(...stmts.map(
(stmt: o.Statement) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
return o.applySourceSpanToExpressionIfNeeded(currValExpr, sourceSpan);

View File

@ -196,25 +196,6 @@ describe('StaticSymbolResolver', () => {
.toBe(symbolCache.get('/test3.d.ts', 'b'));
});
it('should ignore summaries for inputAs if requested', () => {
init(
{
'/test.ts': `
export {a} from './test2';
`
},
[], [{
symbol: symbolCache.get('/test2.d.ts', 'a'),
importAs: symbolCache.get('/test3.d.ts', 'b')
}]);
symbolResolver.getSymbolsOf('/test.ts');
expect(
symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'a'), /* useSummaries */ false))
.toBeUndefined();
});
it('should calculate importAs for symbols with members based on importAs for symbols without',
() => {
init(

View File

@ -126,7 +126,6 @@ export function main() {
outputs: [],
host: {},
queries: {},
guards: {},
exportAs: undefined,
providers: undefined
}));
@ -155,7 +154,6 @@ export function main() {
outputs: [],
host: {},
queries: {},
guards: {},
exportAs: undefined,
providers: undefined
}));
@ -166,7 +164,6 @@ export function main() {
outputs: [],
host: {},
queries: {},
guards: {},
exportAs: undefined,
providers: undefined
}));

View File

@ -38,29 +38,28 @@ function createTypeMeta({reference, diDeps}: {reference: any, diDeps?: any[]}):
return {reference: reference, diDeps: diDeps || [], lifecycleHooks: []};
}
function compileDirectiveMetadataCreate(
{isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host,
providers, viewProviders, queries, guards, viewQueries, entryComponents, template,
componentViewType, rendererType}: {
isHost?: boolean,
type?: CompileTypeMetadata,
isComponent?: boolean,
selector?: string | null,
exportAs?: string | null,
changeDetection?: ChangeDetectionStrategy | null,
inputs?: string[],
outputs?: string[],
host?: {[key: string]: string},
providers?: CompileProviderMetadata[] | null,
viewProviders?: CompileProviderMetadata[] | null,
queries?: CompileQueryMetadata[] | null,
guards?: {[key: string]: any},
viewQueries?: CompileQueryMetadata[],
entryComponents?: CompileEntryComponentMetadata[],
template?: CompileTemplateMetadata,
componentViewType?: StaticSymbol | ProxyClass | null,
rendererType?: StaticSymbol | RendererType2 | null,
}) {
function compileDirectiveMetadataCreate({isHost, type, isComponent, selector, exportAs,
changeDetection, inputs, outputs, host, providers,
viewProviders, queries, viewQueries, entryComponents,
template, componentViewType, rendererType}: {
isHost?: boolean,
type?: CompileTypeMetadata,
isComponent?: boolean,
selector?: string | null,
exportAs?: string | null,
changeDetection?: ChangeDetectionStrategy | null,
inputs?: string[],
outputs?: string[],
host?: {[key: string]: string},
providers?: CompileProviderMetadata[] | null,
viewProviders?: CompileProviderMetadata[] | null,
queries?: CompileQueryMetadata[] | null,
viewQueries?: CompileQueryMetadata[],
entryComponents?: CompileEntryComponentMetadata[],
template?: CompileTemplateMetadata,
componentViewType?: StaticSymbol | ProxyClass | null,
rendererType?: StaticSymbol | RendererType2 | null,
}) {
return CompileDirectiveMetadata.create({
isHost: !!isHost,
type: noUndefined(type) !,
@ -74,7 +73,6 @@ function compileDirectiveMetadataCreate(
providers: providers || [],
viewProviders: viewProviders || [],
queries: queries || [],
guards: guards || {},
viewQueries: viewQueries || [],
entryComponents: entryComponents || [],
template: noUndefined(template) !,
@ -392,7 +390,6 @@ export function main() {
providers: [],
viewProviders: [],
queries: [],
guards: {},
viewQueries: [],
entryComponents: [],
componentViewType: null,

View File

@ -102,8 +102,7 @@ export function createPlatformFactory(
parentPlatformFactory: ((extraProviders?: StaticProvider[]) => PlatformRef) | null,
name: string, providers: StaticProvider[] = []): (extraProviders?: StaticProvider[]) =>
PlatformRef {
const desc = `Platform: ${name}`;
const marker = new InjectionToken(desc);
const marker = new InjectionToken(`Platform: ${name}`);
return (extraProviders: StaticProvider[] = []) => {
let platform = getPlatform();
if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
@ -111,9 +110,8 @@ export function createPlatformFactory(
parentPlatformFactory(
providers.concat(extraProviders).concat({provide: marker, useValue: true}));
} else {
const injectedProviders: StaticProvider[] =
providers.concat(extraProviders).concat({provide: marker, useValue: true});
createPlatform(Injector.create({providers: injectedProviders, name: desc}));
createPlatform(Injector.create(
providers.concat(extraProviders).concat({provide: marker, useValue: true})));
}
}
return assertPlatform(marker);
@ -226,12 +224,10 @@ export class PlatformRef {
// pass that as parent to the NgModuleFactory.
const ngZoneOption = options ? options.ngZone : undefined;
const ngZone = getNgZone(ngZoneOption);
const providers: StaticProvider[] = [{provide: NgZone, useValue: ngZone}];
// Attention: Don't use ApplicationRef.run here,
// as we want to be sure that all possible constructor calls are inside `ngZone.run`!
return ngZone.run(() => {
const ngZoneInjector = Injector.create(
{providers: providers, parent: this.injector, name: moduleFactory.moduleType.name});
const ngZoneInjector = Injector.create([{provide: NgZone, useValue: ngZone}], this.injector);
const moduleRef = <InternalNgModuleRef<M>>moduleFactory.create(ngZoneInjector);
const exceptionHandler: ErrorHandler = moduleRef.injector.get(ErrorHandler, null);
if (!exceptionHandler) {

View File

@ -8,12 +8,12 @@
import {Type} from '../type';
import {stringify} from '../util';
import {resolveForwardRef} from './forward_ref';
import {InjectionToken} from './injection_token';
import {Inject, Optional, Self, SkipSelf} from './metadata';
import {ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, ValueProvider} from './provider';
export const SOURCE = '__source';
const _THROW_IF_NOT_FOUND = new Object();
export const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
@ -64,13 +64,6 @@ export abstract class Injector {
*/
abstract get(token: any, notFoundValue?: any): any;
/**
* @deprecated from v5 use the new signature Injector.create(options)
*/
static create(providers: StaticProvider[], parent?: Injector): Injector;
static create(options: {providers: StaticProvider[], parent?: Injector, name?: string}): Injector;
/**
* Create a new Injector which is configure using `StaticProvider`s.
*
@ -78,14 +71,8 @@ export abstract class Injector {
*
* {@example core/di/ts/provider_spec.ts region='ConstructorProvider'}
*/
static create(
options: StaticProvider[]|{providers: StaticProvider[], parent?: Injector, name?: string},
parent?: Injector): Injector {
if (Array.isArray(options)) {
return new StaticInjector(options, parent);
} else {
return new StaticInjector(options.providers, options.parent, options.name || null);
}
static create(providers: StaticProvider[], parent?: Injector): Injector {
return new StaticInjector(providers, parent);
}
}
@ -116,14 +103,11 @@ const NO_NEW_LINE = 'ɵ';
export class StaticInjector implements Injector {
readonly parent: Injector;
readonly source: string|null;
private _records: Map<any, Record>;
constructor(
providers: StaticProvider[], parent: Injector = NULL_INJECTOR, source: string|null = null) {
constructor(providers: StaticProvider[], parent: Injector = NULL_INJECTOR) {
this.parent = parent;
this.source = source;
const records = this._records = new Map<any, Record>();
records.set(
Injector, <Record>{token: Injector, fn: IDENT, deps: EMPTY, value: this, useNew: false});
@ -138,10 +122,7 @@ export class StaticInjector implements Injector {
return tryResolveToken(token, record, this._records, this.parent, notFoundValue);
} catch (e) {
const tokenPath: any[] = e[NG_TEMP_TOKEN_PATH];
if (token[SOURCE]) {
tokenPath.unshift(token[SOURCE]);
}
e.message = formatError('\n' + e.message, tokenPath, this.source);
e.message = formatError('\n' + e.message, tokenPath);
e[NG_TOKEN_PATH] = tokenPath;
e[NG_TEMP_TOKEN_PATH] = null;
throw e;
@ -355,7 +336,7 @@ function computeDeps(provider: StaticProvider): DependencyRecord[] {
return deps;
}
function formatError(text: string, obj: any, source: string | null = null): string {
function formatError(text: string, obj: any): string {
text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.substr(2) : text;
let context = stringify(obj);
if (obj instanceof Array) {
@ -371,7 +352,7 @@ function formatError(text: string, obj: any, source: string | null = null): stri
}
context = `{${parts.join(', ')}}`;
}
return `StaticInjectorError${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`;
return `StaticInjectorError[${context}]: ${text.replace(NEW_LINE, '\n ')}`;
}
function staticError(text: string, obj: any): Error {

View File

@ -71,13 +71,11 @@ export interface ResolvedReflectiveProvider {
}
export class ResolvedReflectiveProvider_ implements ResolvedReflectiveProvider {
readonly resolvedFactory: ResolvedReflectiveFactory;
constructor(
public key: ReflectiveKey, public resolvedFactories: ResolvedReflectiveFactory[],
public multiProvider: boolean) {
this.resolvedFactory = this.resolvedFactories[0];
}
public multiProvider: boolean) {}
get resolvedFactory(): ResolvedReflectiveFactory { return this.resolvedFactories[0]; }
}
/**

View File

@ -66,20 +66,13 @@ export class CodegenComponentFactoryResolver implements ComponentFactoryResolver
}
export class ComponentFactoryBoundToModule<C> extends ComponentFactory<C> {
readonly selector: string;
readonly componentType: Type<any>;
readonly ngContentSelectors: string[];
readonly inputs: {propName: string, templateName: string}[];
readonly outputs: {propName: string, templateName: string}[];
constructor(private factory: ComponentFactory<C>, private ngModule: NgModuleRef<any>) { super(); }
constructor(private factory: ComponentFactory<C>, private ngModule: NgModuleRef<any>) {
super();
this.selector = factory.selector;
this.componentType = factory.componentType;
this.ngContentSelectors = factory.ngContentSelectors;
this.inputs = factory.inputs;
this.outputs = factory.outputs;
}
get selector() { return this.factory.selector; }
get componentType() { return this.factory.componentType; }
get ngContentSelectors() { return this.factory.ngContentSelectors; }
get inputs() { return this.factory.inputs; }
get outputs() { return this.factory.outputs; }
create(
injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string|any,

View File

@ -41,9 +41,9 @@ export class QueryList<T>/* implements Iterable<T> */ {
private _results: Array<T> = [];
public readonly changes: Observable<any> = new EventEmitter();
readonly length: number;
readonly first: T;
readonly last: T;
get length(): number { return this._results.length; }
get first(): T { return this._results[0]; }
get last(): T { return this._results[this.length - 1]; }
/**
* See
@ -98,9 +98,6 @@ export class QueryList<T>/* implements Iterable<T> */ {
reset(res: Array<T|any[]>): void {
this._results = flatten(res);
(this as{dirty: boolean}).dirty = false;
(this as{length: number}).length = this._results.length;
(this as{last: T}).last = this._results[this.length - 1];
(this as{first: T}).first = this._results[0];
}
notifyOnChanges(): void { (this.changes as EventEmitter<any>).emit(this); }

View File

@ -13,7 +13,6 @@ export interface PlatformReflectionCapabilities {
isReflectionEnabled(): boolean;
factory(type: Type<any>): Function;
hasLifecycleHook(type: any, lcProperty: string): boolean;
guards(type: any): {[key: string]: any};
/**
* Return a list of annotations/types for constructor parameters

View File

@ -207,8 +207,6 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
return type instanceof Type && lcProperty in type.prototype;
}
guards(type: any): {[key: string]: any} { return {}; }
getter(name: string): GetterFn { return <GetterFn>new Function('o', 'return o.' + name + ';'); }
setter(name: string): SetterFn {

View File

@ -9,7 +9,6 @@
import {resolveForwardRef} from '../di/forward_ref';
import {Injector} from '../di/injector';
import {NgModuleRef} from '../linker/ng_module_factory';
import {stringify} from '../util';
import {DepDef, DepFlags, NgModuleData, NgModuleDefinition, NgModuleProviderDef, NodeFlags} from './types';
import {splitDepsDsl, tokenKey} from './util';
@ -26,7 +25,7 @@ export function moduleProvideDef(
// lowered the expression and then stopped evaluating it,
// i.e. also didn't unwrap it.
value = resolveForwardRef(value);
const depDefs = splitDepsDsl(deps, stringify(token));
const depDefs = splitDepsDsl(deps);
return {
// will bet set by the module definition
index: -1,

View File

@ -12,7 +12,7 @@ import {ElementRef} from '../linker/element_ref';
import {TemplateRef} from '../linker/template_ref';
import {ViewContainerRef} from '../linker/view_container_ref';
import {Renderer as RendererV1, Renderer2} from '../render/api';
import {stringify} from '../util';
import {createChangeDetectorRef, createInjector, createRendererV1} from './refs';
import {BindingDef, BindingFlags, DepDef, DepFlags, NodeDef, NodeFlags, OutputDef, OutputType, ProviderData, QueryValueType, Services, ViewData, ViewFlags, ViewState, asElementData, asProviderData, shouldCallLifecycleInitHook} from './types';
import {calcBindingFlags, checkBinding, dispatchEvent, isComponentView, splitDepsDsl, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
@ -83,7 +83,7 @@ export function _def(
// i.e. also didn't unwrap it.
value = resolveForwardRef(value);
const depDefs = splitDepsDsl(deps, stringify(token));
const depDefs = splitDepsDsl(deps);
return {
// will bet set by the view definition

View File

@ -481,8 +481,6 @@ class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> {
/** @internal */
_providers: any[];
readonly injector: Injector = this;
constructor(
private _moduleType: Type<any>, public _parent: Injector,
public _bootstrapComponents: Type<any>[], public _def: NgModuleDefinition) {
@ -498,6 +496,8 @@ class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> {
get componentFactoryResolver() { return this.get(ComponentFactoryResolver); }
get injector(): Injector { return this; }
destroy(): void {
if (this._destroyed) {
throw new Error(

View File

@ -649,8 +649,9 @@ class DebugRendererFactory2 implements RendererFactory2 {
class DebugRenderer2 implements Renderer2 {
readonly data: {[key: string]: any};
constructor(private delegate: Renderer2) { this.data = this.delegate.data; }
constructor(private delegate: Renderer2) {}
get data() { return this.delegate.data; }
destroyNode(node: any) {
removeDebugNodeFromIndex(getDebugNode(node) !);

View File

@ -7,10 +7,10 @@
*/
import {WrappedValue, devModeEqual} from '../change_detection/change_detection';
import {SOURCE} from '../di/injector';
import {ViewEncapsulation} from '../metadata/view';
import {RendererType2} from '../render/api';
import {looseIdentical, stringify} from '../util';
import {expressionChangedAfterItHasBeenCheckedError} from './errors';
import {BindingDef, BindingFlags, Definition, DefinitionFactory, DepDef, DepFlags, ElementData, NodeDef, NodeFlags, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewState, asElementData, asTextData} from './types';
@ -209,7 +209,7 @@ export function splitMatchedQueriesDsl(
return {matchedQueries, references, matchedQueryIds};
}
export function splitDepsDsl(deps: ([DepFlags, any] | any)[], sourceName?: string): DepDef[] {
export function splitDepsDsl(deps: ([DepFlags, any] | any)[]): DepDef[] {
return deps.map(value => {
let token: any;
let flags: DepFlags;
@ -219,9 +219,6 @@ export function splitDepsDsl(deps: ([DepFlags, any] | any)[], sourceName?: strin
flags = DepFlags.None;
token = value;
}
if (token && (typeof token === 'function' || typeof token === 'object') && sourceName) {
Object.defineProperty(token, SOURCE, {value: sourceName, configurable: true});
}
return {flags, token, tokenKey: tokenKey(token)};
});
}

View File

@ -255,45 +255,6 @@ export function main() {
]);
});
it('should allow a transition to use a function to determine what method to run', () => {
let valueToMatch = '';
const transitionFn =
(fromState: string, toState: string) => { return toState == valueToMatch; };
@Component({
selector: 'if-cmp',
template: '<div [@myAnimation]="exp"></div>',
animations: [
trigger('myAnimation', [transition(
transitionFn,
[style({opacity: 0}), animate(1234, style({opacity: 1}))])]),
]
})
class Cmp {
exp: any = '';
}
TestBed.configureTestingModule({declarations: [Cmp]});
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
valueToMatch = cmp.exp = 'something';
fixture.detectChanges();
let players = getLog();
expect(players.length).toEqual(1);
let [p1] = players;
expect(p1.totalTime).toEqual(1234);
resetLog();
valueToMatch = 'something-else';
cmp.exp = 'this-wont-match';
fixture.detectChanges();
players = getLog();
expect(players.length).toEqual(0);
});
it('should allow a state value to be `0`', () => {
@Component({
selector: 'if-cmp',

View File

@ -147,8 +147,8 @@ export function main() {
expect(() => createAndGetRootNodes(compViewDef(rootElNodes)))
.toThrowError(
'StaticInjectorError(DynamicTestModule)[SomeService -> Dep]: \n' +
' StaticInjectorError(Platform: core)[SomeService -> Dep]: \n' +
'StaticInjectorError[Dep]: \n' +
' StaticInjectorError[Dep]: \n' +
' NullInjectorError: No provider for Dep!');
const nonRootElNodes = [
@ -161,8 +161,8 @@ export function main() {
expect(() => createAndGetRootNodes(compViewDef(nonRootElNodes)))
.toThrowError(
'StaticInjectorError(DynamicTestModule)[SomeService -> Dep]: \n' +
' StaticInjectorError(Platform: core)[SomeService -> Dep]: \n' +
'StaticInjectorError[Dep]: \n' +
' StaticInjectorError[Dep]: \n' +
' NullInjectorError: No provider for Dep!');
});
@ -186,8 +186,8 @@ export function main() {
directiveDef(1, NodeFlags.None, null, 0, SomeService, ['nonExistingDep'])
])))
.toThrowError(
'StaticInjectorError(DynamicTestModule)[nonExistingDep]: \n' +
' StaticInjectorError(Platform: core)[nonExistingDep]: \n' +
'StaticInjectorError[nonExistingDep]: \n' +
' StaticInjectorError[nonExistingDep]: \n' +
' NullInjectorError: No provider for nonExistingDep!');
});

View File

@ -355,12 +355,8 @@ export class TestBed implements Injector {
}
const ngZone = new NgZone({enableLongStackTrace: true});
const providers: StaticProvider[] = [{provide: NgZone, useValue: ngZone}];
const ngZoneInjector = Injector.create({
providers: providers,
parent: this.platform.injector,
name: this._moduleFactory.moduleType.name
});
const ngZoneInjector =
Injector.create([{provide: NgZone, useValue: ngZone}], this.platform.injector);
this._moduleRef = this._moduleFactory.create(ngZoneInjector);
// ApplicationInitStatus.runInitializers() is marked @internal to core. So casting to any
// before accessing it.

View File

@ -135,7 +135,7 @@ export function main() {
name = 'square';
}
const injector = Injector.create({providers: [{provide: Square, deps: []}]});
const injector = Injector.create([{provide: Square, deps: []}]);
const shape: Square = injector.get(Square);
expect(shape.name).toEqual('square');

View File

@ -49,10 +49,10 @@ export const COMPOSITION_BUFFER_MODE = new InjectionToken<boolean>('CompositionE
// https://github.com/angular/angular/issues/3011 is implemented
// selector: '[ngModel],[formControl],[formControlName]',
host: {
'(input)': '$any(this)._handleInput($event.target.value)',
'(input)': '_handleInput($event.target.value)',
'(blur)': 'onTouched()',
'(compositionstart)': '$any(this)._compositionStart()',
'(compositionend)': '$any(this)._compositionEnd($event.target.value)'
'(compositionstart)': '_compositionStart()',
'(compositionend)': '_compositionEnd($event.target.value)'
},
providers: [DEFAULT_VALUE_ACCESSOR]
})

View File

@ -253,7 +253,7 @@ export abstract class AbstractControl {
* Sets the async validators that are active on this control. Calling this
* will overwrite any existing async validators.
*/
setAsyncValidators(newValidator: AsyncValidatorFn|AsyncValidatorFn[]|null): void {
setAsyncValidators(newValidator: AsyncValidatorFn|AsyncValidatorFn[]): void {
this.asyncValidator = coerceToAsyncValidator(newValidator);
}

View File

@ -42,7 +42,6 @@ export class JitReflector implements CompileReflector {
hasLifecycleHook(type: any, lcProperty: string): boolean {
return this.reflectionCapabilities.hasLifecycleHook(type, lcProperty);
}
guards(type: any): {[key: string]: any} { return this.reflectionCapabilities.guards(type); }
resolveExternalReference(ref: ExternalReference): any {
return builtinExternalReferences.get(ref) || ref.runtime;
}

View File

@ -7,12 +7,12 @@
*/
import {isPlatformBrowser} from '@angular/common';
import {APP_INITIALIZER, CUSTOM_ELEMENTS_SCHEMA, Compiler, Component, Directive, ErrorHandler, Inject, Input, LOCALE_ID, NgModule, OnDestroy, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, Provider, StaticProvider, Type, VERSION, createPlatformFactory} from '@angular/core';
import {APP_INITIALIZER, CUSTOM_ELEMENTS_SCHEMA, Compiler, Component, Directive, ErrorHandler, Inject, Input, LOCALE_ID, NgModule, OnDestroy, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, Provider, StaticProvider, VERSION, createPlatformFactory, ɵstringify as stringify} from '@angular/core';
import {ApplicationRef, destroyPlatform} from '@angular/core/src/application_ref';
import {Console} from '@angular/core/src/console';
import {ComponentRef} from '@angular/core/src/linker/component_factory';
import {Testability, TestabilityRegistry} from '@angular/core/src/testability/testability';
import {AsyncTestCompleter, Log, afterEach, beforeEach, beforeEachProviders, describe, iit, inject, it} from '@angular/core/testing/src/testing_internal';
import {AsyncTestCompleter, Log, afterEach, beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it} from '@angular/core/testing/src/testing_internal';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
@ -112,11 +112,10 @@ class DummyConsole implements Console {
class TestModule {}
function bootstrap(
cmpType: any, providers: Provider[] = [], platformProviders: StaticProvider[] = [],
imports: Type<any>[] = []): Promise<any> {
function bootstrap(cmpType: any, providers: Provider[] = [], platformProviders: StaticProvider[] = [
]): Promise<any> {
@NgModule({
imports: [BrowserModule, ...imports],
imports: [BrowserModule],
declarations: [cmpType],
bootstrap: [cmpType],
providers: providers,
@ -184,40 +183,6 @@ export function main() {
});
}));
it('should throw if no provider', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const logger = new MockConsole();
const errorHandler = new ErrorHandler();
errorHandler._console = logger as any;
class IDontExist {}
@Component({selector: 'cmp', template: 'Cmp'})
class CustomCmp {
constructor(iDontExist: IDontExist) {}
}
@Component({
selector: 'hello-app',
template: '<cmp></cmp>',
})
class RootCmp {
}
@NgModule({declarations: [CustomCmp], exports: [CustomCmp]})
class CustomModule {
}
bootstrap(RootCmp, [{provide: ErrorHandler, useValue: errorHandler}], [], [
CustomModule
]).then(null, (e: Error) => {
expect(e.message).toContain(`StaticInjectorError(TestModule)[CustomCmp -> IDontExist]:
StaticInjectorError(Platform: core)[CustomCmp -> IDontExist]:
NullInjectorError: No provider for IDontExist!`);
async.done();
return null;
});
}));
if (getDOM().supportsDOMEvents()) {
it('should forward the error to promise when bootstrap fails',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {

View File

@ -21,15 +21,13 @@ import {reduce} from 'rxjs/operator/reduce';
import {LoadedRouterConfig, ResolveData, RunGuardsAndResolvers} from './config';
import {ActivationStart, ChildActivationStart, Event} from './events';
import {ChildrenOutletContexts, OutletContext} from './router_outlet_context';
import {ActivatedRouteSnapshot, ParamsInheritanceStrategy, RouterStateSnapshot, equalParamsAndUrlSegments, inheritedParamsDataResolve} from './router_state';
import {ActivatedRouteSnapshot, RouterStateSnapshot, equalParamsAndUrlSegments, inheritedParamsDataResolve} from './router_state';
import {andObservables, forEach, shallowEqual, wrapIntoObservable} from './utils/collection';
import {TreeNode, nodeChildrenAsMap} from './utils/tree';
class CanActivate {
readonly route: ActivatedRouteSnapshot;
constructor(public path: ActivatedRouteSnapshot[]) {
this.route = this.path[this.path.length - 1];
}
constructor(public path: ActivatedRouteSnapshot[]) {}
get route(): ActivatedRouteSnapshot { return this.path[this.path.length - 1]; }
}
class CanDeactivate {
@ -63,11 +61,11 @@ export class PreActivation {
(canDeactivate: boolean) => canDeactivate ? this.runCanActivateChecks() : of (false));
}
resolveData(paramsInheritanceStrategy: ParamsInheritanceStrategy): Observable<any> {
resolveData(): Observable<any> {
if (!this.isActivating()) return of (null);
const checks$ = from(this.canActivateChecks);
const runningChecks$ = concatMap.call(
checks$, (check: CanActivate) => this.runResolve(check.route, paramsInheritanceStrategy));
const runningChecks$ =
concatMap.call(checks$, (check: CanActivate) => this.runResolve(check.route));
return reduce.call(runningChecks$, (_: any, __: any) => _);
}
@ -306,14 +304,11 @@ export class PreActivation {
return every.call(canDeactivate$, (result: any) => result === true);
}
private runResolve(
future: ActivatedRouteSnapshot,
paramsInheritanceStrategy: ParamsInheritanceStrategy): Observable<any> {
private runResolve(future: ActivatedRouteSnapshot): Observable<any> {
const resolve = future._resolve;
return map.call(this.resolveNode(resolve, future), (resolvedData: any): any => {
future._resolvedData = resolvedData;
future.data = {...future.data,
...inheritedParamsDataResolve(future, paramsInheritanceStrategy).resolve};
future.data = {...future.data, ...inheritedParamsDataResolve(future).resolve};
return null;
});
}

View File

@ -12,7 +12,7 @@ import {Observer} from 'rxjs/Observer';
import {of } from 'rxjs/observable/of';
import {Data, ResolveData, Route, Routes} from './config';
import {ActivatedRouteSnapshot, ParamsInheritanceStrategy, RouterStateSnapshot, inheritedParamsDataResolve} from './router_state';
import {ActivatedRouteSnapshot, RouterStateSnapshot, inheritedParamsDataResolve} from './router_state';
import {PRIMARY_OUTLET, defaultUrlMatcher} from './shared';
import {UrlSegment, UrlSegmentGroup, UrlTree, mapChildrenIntoArray} from './url_tree';
import {forEach, last} from './utils/collection';
@ -21,17 +21,15 @@ import {TreeNode} from './utils/tree';
class NoMatch {}
export function recognize(
rootComponentType: Type<any>| null, config: Routes, urlTree: UrlTree, url: string,
paramsInheritanceStrategy: ParamsInheritanceStrategy =
'emptyOnly'): Observable<RouterStateSnapshot> {
return new Recognizer(rootComponentType, config, urlTree, url, paramsInheritanceStrategy)
.recognize();
rootComponentType: Type<any>| null, config: Routes, urlTree: UrlTree,
url: string): Observable<RouterStateSnapshot> {
return new Recognizer(rootComponentType, config, urlTree, url).recognize();
}
class Recognizer {
constructor(
private rootComponentType: Type<any>|null, private config: Routes, private urlTree: UrlTree,
private url: string, private paramsInheritanceStrategy: ParamsInheritanceStrategy) {}
private url: string) {}
recognize(): Observable<RouterStateSnapshot> {
try {
@ -57,7 +55,7 @@ class Recognizer {
inheritParamsAndData(routeNode: TreeNode<ActivatedRouteSnapshot>): void {
const route = routeNode.value;
const i = inheritedParamsDataResolve(route, this.paramsInheritanceStrategy);
const i = inheritedParamsDataResolve(route);
route.params = Object.freeze(i.params);
route.data = Object.freeze(i.data);

View File

@ -27,7 +27,7 @@ import {recognize} from './recognize';
import {DefaultRouteReuseStrategy, DetachedRouteHandleInternal, RouteReuseStrategy} from './route_reuse_strategy';
import {RouterConfigLoader} from './router_config_loader';
import {ChildrenOutletContexts} from './router_outlet_context';
import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState, inheritedParamsDataResolve} from './router_state';
import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState} from './router_state';
import {Params, isNavigationCancelingError} from './shared';
import {DefaultUrlHandlingStrategy, UrlHandlingStrategy} from './url_handling_strategy';
import {UrlSerializer, UrlTree, containsTree, createEmptyUrlTree} from './url_tree';
@ -249,16 +249,6 @@ export class Router {
*/
onSameUrlNavigation: 'reload'|'ignore' = 'ignore';
/**
* Defines how the router merges params, data and resolved data from parent to child
* routes. Available options are:
*
* - `'emptyOnly'`, the default, only inherits parent params for path-less or component-less
* routes.
* - `'always'`, enables unconditional inheritance of parent params.
*/
paramsInheritanceStrategy: 'emptyOnly'|'always' = 'emptyOnly';
/**
* Creates the router service.
*/
@ -621,8 +611,7 @@ export class Router {
urlAndSnapshot$ = mergeMap.call(redirectsApplied$, (appliedUrl: UrlTree) => {
return map.call(
recognize(
this.rootComponentType, this.config, appliedUrl, this.serializeUrl(appliedUrl),
this.paramsInheritanceStrategy),
this.rootComponentType, this.config, appliedUrl, this.serializeUrl(appliedUrl)),
(snapshot: any) => {
(this.events as Subject<Event>)
@ -678,7 +667,7 @@ export class Router {
if (p.shouldActivate && preActivation.isActivating()) {
this.triggerEvent(
new ResolveStart(id, this.serializeUrl(url), p.appliedUrl, p.snapshot));
return map.call(preActivation.resolveData(this.paramsInheritanceStrategy), () => {
return map.call(preActivation.resolveData(), () => {
this.triggerEvent(
new ResolveEnd(id, this.serializeUrl(url), p.appliedUrl, p.snapshot));
return p;

View File

@ -278,16 +278,6 @@ export interface ExtraOptions {
* current URL. Default is 'ignore'.
*/
onSameUrlNavigation?: 'reload'|'ignore';
/**
* Defines how the router merges params, data and resolved data from parent to child
* routes. Available options are:
*
* - `'emptyOnly'`, the default, only inherits parent params for path-less or component-less
* routes.
* - `'always'`, enables unconditional inheritance of parent params.
*/
paramsInheritanceStrategy?: 'emptyOnly'|'always';
}
export function setupRouter(
@ -324,10 +314,6 @@ export function setupRouter(
router.onSameUrlNavigation = opts.onSameUrlNavigation;
}
if (opts.paramsInheritanceStrategy) {
router.paramsInheritanceStrategy = opts.paramsInheritanceStrategy;
}
return router;
}

View File

@ -18,7 +18,6 @@ import {shallowEqual, shallowEqualArrays} from './utils/collection';
import {Tree, TreeNode} from './utils/tree';
/**
* @whatItDoes Represents the state of the router.
*
@ -175,9 +174,6 @@ export class ActivatedRoute {
}
}
/** @internal */
export type ParamsInheritanceStrategy = 'emptyOnly' | 'always';
/** @internal */
export type Inherited = {
params: Params,
@ -185,43 +181,29 @@ export type Inherited = {
resolve: Data,
};
/**
* Returns the inherited params, data, and resolve for a given route.
* By default, this only inherits values up to the nearest path-less or component-less route.
* @internal
*/
export function inheritedParamsDataResolve(
route: ActivatedRouteSnapshot,
paramsInheritanceStrategy: ParamsInheritanceStrategy = 'emptyOnly'): Inherited {
const pathFromRoot = route.pathFromRoot;
/** @internal */
export function inheritedParamsDataResolve(route: ActivatedRouteSnapshot): Inherited {
const pathToRoot = route.pathFromRoot;
let inheritingStartingFrom = 0;
if (paramsInheritanceStrategy !== 'always') {
inheritingStartingFrom = pathFromRoot.length - 1;
let inhertingStartingFrom = pathToRoot.length - 1;
while (inheritingStartingFrom >= 1) {
const current = pathFromRoot[inheritingStartingFrom];
const parent = pathFromRoot[inheritingStartingFrom - 1];
// current route is an empty path => inherits its parent's params and data
if (current.routeConfig && current.routeConfig.path === '') {
inheritingStartingFrom--;
while (inhertingStartingFrom >= 1) {
const current = pathToRoot[inhertingStartingFrom];
const parent = pathToRoot[inhertingStartingFrom - 1];
// current route is an empty path => inherits its parent's params and data
if (current.routeConfig && current.routeConfig.path === '') {
inhertingStartingFrom--;
// parent is componentless => current route should inherit its params and data
} else if (!parent.component) {
inheritingStartingFrom--;
// parent is componentless => current route should inherit its params and data
} else if (!parent.component) {
inhertingStartingFrom--;
} else {
break;
}
} else {
break;
}
}
return flattenInherited(pathFromRoot.slice(inheritingStartingFrom));
}
/** @internal */
function flattenInherited(pathFromRoot: ActivatedRouteSnapshot[]): Inherited {
return pathFromRoot.reduce((res, curr) => {
return pathToRoot.slice(inhertingStartingFrom).reduce((res, curr) => {
const params = {...res.params, ...curr.params};
const data = {...res.data, ...curr.data};
const resolve = {...res.resolve, ...curr._resolvedData};
@ -370,7 +352,7 @@ function setRouterState<U, T extends{_routerState: U}>(state: U, node: TreeNode<
}
function serializeNode(node: TreeNode<ActivatedRouteSnapshot>): string {
const c = node.children.length > 0 ? ` { ${node.children.map(serializeNode).join(', ')} } ` : '';
const c = node.children.length > 0 ? ` { ${node.children.map(serializeNode).join(", ")} } ` : '';
return `${node.value}${c}`;
}

View File

@ -3794,19 +3794,6 @@ describe('Integration', () => {
});
});
describe('Testing router options', () => {
describe('paramsInheritanceStrategy', () => {
beforeEach(() => {
TestBed.configureTestingModule(
{imports: [RouterTestingModule.withRoutes([], {paramsInheritanceStrategy: 'always'})]});
});
it('should configure the router', fakeAsync(inject([Router], (router: Router) => {
expect(router.paramsInheritanceStrategy).toEqual('always');
})));
});
});
function expectEvents(events: Event[], pairs: any[]) {
expect(events.length).toEqual(pairs.length);
for (let i = 0; i < events.length; ++i) {

View File

@ -8,7 +8,7 @@
import {Routes} from '../src/config';
import {recognize} from '../src/recognize';
import {ActivatedRouteSnapshot, ParamsInheritanceStrategy, RouterStateSnapshot, inheritedParamsDataResolve} from '../src/router_state';
import {ActivatedRouteSnapshot, RouterStateSnapshot} from '../src/router_state';
import {PRIMARY_OUTLET, Params} from '../src/shared';
import {DefaultUrlSerializer, UrlTree} from '../src/url_tree';
@ -201,7 +201,7 @@ describe('recognize', () => {
});
});
it('should inherit componentless route\'s data', () => {
it('should merge componentless route\'s data', () => {
checkRecognize(
[{
path: 'a',
@ -214,34 +214,6 @@ describe('recognize', () => {
});
});
it('should not inherit route\'s data if it has component', () => {
checkRecognize(
[{
path: 'a',
component: ComponentA,
data: {one: 1},
children: [{path: 'b', data: {two: 2}, component: ComponentB}]
}],
'a/b', (s: RouterStateSnapshot) => {
const r: ActivatedRouteSnapshot = s.firstChild(<any>s.firstChild(s.root)) !;
expect(r.data).toEqual({two: 2});
});
});
it('should inherit route\'s data if paramsInheritanceStrategy is \'always\'', () => {
checkRecognize(
[{
path: 'a',
component: ComponentA,
data: {one: 1},
children: [{path: 'b', data: {two: 2}, component: ComponentB}]
}],
'a/b', (s: RouterStateSnapshot) => {
const r: ActivatedRouteSnapshot = s.firstChild(<any>s.firstChild(s.root)) !;
expect(r.data).toEqual({one: 1, two: 2});
}, 'always');
});
it('should set resolved data', () => {
checkRecognize(
[{path: 'a', resolve: {one: 'some-token'}, component: ComponentA}], 'a',
@ -335,7 +307,7 @@ describe('recognize', () => {
});
});
it('should match (non-terminal) when both primary and secondary and primary has a child',
it('should match (non-termianl) when both primary and secondary and primary has a child',
() => {
const config = [{
path: 'parent',
@ -607,7 +579,7 @@ describe('recognize', () => {
});
});
it('should inherit params until encounters a normal route', () => {
it('should merge params until encounters a normal route', () => {
checkRecognize(
[{
path: 'p/:id',
@ -634,25 +606,6 @@ describe('recognize', () => {
checkActivatedRoute(c, 'c', {}, ComponentC);
});
});
it('should inherit all params if paramsInheritanceStrategy is \'always\'', () => {
checkRecognize(
[{
path: 'p/:id',
children: [{
path: 'a/:name',
children: [{
path: 'b',
component: ComponentB,
children: [{path: 'c', component: ComponentC}]
}]
}]
}],
'p/11/a/victor/b/c', (s: RouterStateSnapshot) => {
const c = s.firstChild(s.firstChild(s.firstChild(s.firstChild(s.root) !) !) !) !;
checkActivatedRoute(c, 'c', {id: '11', name: 'victor'}, ComponentC);
}, 'always');
});
});
describe('empty URL leftovers', () => {
@ -769,11 +722,8 @@ describe('recognize', () => {
});
});
function checkRecognize(
config: Routes, url: string, callback: any,
paramsInheritanceStrategy?: ParamsInheritanceStrategy): void {
recognize(RootComponent, config, tree(url), url, paramsInheritanceStrategy)
.subscribe(callback, e => { throw e; });
function checkRecognize(config: Routes, url: string, callback: any): void {
recognize(RootComponent, config, tree(url), url).subscribe(callback, e => { throw e; });
}
function checkActivatedRoute(

View File

@ -498,7 +498,7 @@ function checkResolveData(
future: RouterStateSnapshot, curr: RouterStateSnapshot, injector: any, check: any): void {
const p = new PreActivation(future, curr, injector);
p.initialize(new ChildrenOutletContexts());
p.resolveData('emptyOnly').subscribe(check, (e) => { throw e; });
p.resolveData().subscribe(check, (e) => { throw e; });
}
function checkGuards(

View File

@ -9,7 +9,7 @@
import {Location, LocationStrategy} from '@angular/common';
import {MockLocationStrategy, SpyLocation} from '@angular/common/testing';
import {Compiler, Injectable, Injector, ModuleWithProviders, NgModule, NgModuleFactory, NgModuleFactoryLoader, Optional} from '@angular/core';
import {ChildrenOutletContexts, ExtraOptions, NoPreloading, PreloadingStrategy, ROUTER_CONFIGURATION, ROUTES, Route, Router, RouterModule, Routes, UrlHandlingStrategy, UrlSerializer, provideRoutes, ɵROUTER_PROVIDERS as ROUTER_PROVIDERS, ɵflatten as flatten} from '@angular/router';
import {ChildrenOutletContexts, NoPreloading, PreloadingStrategy, ROUTES, Route, Router, RouterModule, Routes, UrlHandlingStrategy, UrlSerializer, provideRoutes, ɵROUTER_PROVIDERS as ROUTER_PROVIDERS, ɵflatten as flatten} from '@angular/router';
@ -76,13 +76,6 @@ export class SpyNgModuleFactoryLoader implements NgModuleFactoryLoader {
}
}
function isUrlHandlingStrategy(opts: ExtraOptions | UrlHandlingStrategy):
opts is UrlHandlingStrategy {
// This property check is needed because UrlHandlingStrategy is an interface and doesn't exist at
// runtime.
return 'shouldProcessUrl' in opts;
}
/**
* Router setup factory function used for testing.
*
@ -91,39 +84,9 @@ function isUrlHandlingStrategy(opts: ExtraOptions | UrlHandlingStrategy):
export function setupTestingRouter(
urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts, location: Location,
loader: NgModuleFactoryLoader, compiler: Compiler, injector: Injector, routes: Route[][],
opts?: ExtraOptions, urlHandlingStrategy?: UrlHandlingStrategy): Router;
/**
* Router setup factory function used for testing.
*
* @deprecated As of v5.2. The 2nd-to-last argument should be `ExtraOptions`, not
* `UrlHandlingStrategy`
*/
export function setupTestingRouter(
urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts, location: Location,
loader: NgModuleFactoryLoader, compiler: Compiler, injector: Injector, routes: Route[][],
urlHandlingStrategy?: UrlHandlingStrategy): Router;
/**
* Router setup factory function used for testing.
*
* @stable
*/
export function setupTestingRouter(
urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts, location: Location,
loader: NgModuleFactoryLoader, compiler: Compiler, injector: Injector, routes: Route[][],
opts?: ExtraOptions | UrlHandlingStrategy, urlHandlingStrategy?: UrlHandlingStrategy) {
urlHandlingStrategy?: UrlHandlingStrategy) {
const router = new Router(
null !, urlSerializer, contexts, location, injector, loader, compiler, flatten(routes));
// Handle deprecated argument ordering.
if (opts) {
if (isUrlHandlingStrategy(opts)) {
router.urlHandlingStrategy = opts;
} else if (opts.paramsInheritanceStrategy) {
router.paramsInheritanceStrategy = opts.paramsInheritanceStrategy;
}
}
if (urlHandlingStrategy) {
router.urlHandlingStrategy = urlHandlingStrategy;
}
@ -165,20 +128,14 @@ export function setupTestingRouter(
useFactory: setupTestingRouter,
deps: [
UrlSerializer, ChildrenOutletContexts, Location, NgModuleFactoryLoader, Compiler, Injector,
ROUTES, ROUTER_CONFIGURATION, [UrlHandlingStrategy, new Optional()]
ROUTES, [UrlHandlingStrategy, new Optional()]
]
},
{provide: PreloadingStrategy, useExisting: NoPreloading}, provideRoutes([])
]
})
export class RouterTestingModule {
static withRoutes(routes: Routes, config?: ExtraOptions): ModuleWithProviders {
return {
ngModule: RouterTestingModule,
providers: [
provideRoutes(routes),
{provide: ROUTER_CONFIGURATION, useValue: config ? config : {}},
]
};
static withRoutes(routes: Routes): ModuleWithProviders {
return {ngModule: RouterTestingModule, providers: [provideRoutes(routes)]};
}
}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ApplicationRef, ChangeDetectorRef, ComponentFactory, ComponentRef, EventEmitter, Injector, OnChanges, SimpleChange, SimpleChanges, StaticProvider, Testability, TestabilityRegistry, Type} from '@angular/core';
import {ApplicationRef, ChangeDetectorRef, ComponentFactory, ComponentRef, EventEmitter, Injector, OnChanges, SimpleChange, SimpleChanges, Testability, TestabilityRegistry, Type} from '@angular/core';
import * as angular from './angular1';
import {PropertyBinding} from './component_info';
@ -54,9 +54,8 @@ export class DowngradeComponentAdapter {
}
createComponent(projectableNodes: Node[][]) {
const providers: StaticProvider[] = [{provide: $SCOPE, useValue: this.componentScope}];
const childInjector = Injector.create(
{providers: providers, parent: this.parentInjector, name: 'DowngradeComponentAdapter'});
const childInjector =
Injector.create([{provide: $SCOPE, useValue: this.componentScope}], this.parentInjector);
this.componentRef =
this.componentFactory.create(childInjector, projectableNodes, this.element[0]);

View File

@ -172,7 +172,7 @@ export interface AnimationStyleMetadata extends AnimationMetadata {
/** @experimental */
export interface AnimationTransitionMetadata extends AnimationMetadata {
animation: AnimationMetadata | AnimationMetadata[];
expr: string | ((fromState: string, toState: string) => boolean);
expr: string;
options: AnimationOptions | null;
}
@ -240,7 +240,7 @@ export declare function style(tokens: '*' | {
}>): AnimationStyleMetadata;
/** @experimental */
export declare function transition(stateChangeExpr: string | ((fromState: string, toState: string) => boolean), steps: AnimationMetadata | AnimationMetadata[], options?: AnimationOptions | null): AnimationTransitionMetadata;
export declare function transition(stateChangeExpr: string, steps: AnimationMetadata | AnimationMetadata[], options?: AnimationOptions | null): AnimationTransitionMetadata;
/** @experimental */
export declare function trigger(name: string, definitions: AnimationMetadata[]): AnimationTriggerMetadata;

View File

@ -476,12 +476,7 @@ export declare abstract class Injector {
/** @deprecated */ abstract get(token: any, notFoundValue?: any): any;
static NULL: Injector;
static THROW_IF_NOT_FOUND: Object;
/** @deprecated */ static create(providers: StaticProvider[], parent?: Injector): Injector;
static create(options: {
providers: StaticProvider[];
parent?: Injector;
name?: string;
}): Injector;
static create(providers: StaticProvider[], parent?: Injector): Injector;
}
/** @stable */

View File

@ -50,7 +50,7 @@ export declare abstract class AbstractControl {
}): void;
abstract patchValue(value: any, options?: Object): void;
abstract reset(value?: any, options?: Object): void;
setAsyncValidators(newValidator: AsyncValidatorFn | AsyncValidatorFn[] | null): void;
setAsyncValidators(newValidator: AsyncValidatorFn | AsyncValidatorFn[]): void;
setErrors(errors: ValidationErrors | null, opts?: {
emitEvent?: boolean;
}): void;

View File

@ -127,7 +127,6 @@ export interface ExtraOptions {
errorHandler?: ErrorHandler;
initialNavigation?: InitialNavigation;
onSameUrlNavigation?: 'reload' | 'ignore';
paramsInheritanceStrategy?: 'emptyOnly' | 'always';
preloadingStrategy?: any;
useHash?: boolean;
}
@ -330,7 +329,6 @@ export declare class Router {
readonly events: Observable<Event>;
navigated: boolean;
onSameUrlNavigation: 'reload' | 'ignore';
paramsInheritanceStrategy: 'emptyOnly' | 'always';
routeReuseStrategy: RouteReuseStrategy;
readonly routerState: RouterState;
readonly url: string;

View File

@ -1,10 +1,10 @@
/** @stable */
export declare class RouterTestingModule {
static withRoutes(routes: Routes, config?: ExtraOptions): ModuleWithProviders;
static withRoutes(routes: Routes): ModuleWithProviders;
}
/** @stable */
export declare function setupTestingRouter(urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts, location: Location, loader: NgModuleFactoryLoader, compiler: Compiler, injector: Injector, routes: Route[][], opts?: ExtraOptions, urlHandlingStrategy?: UrlHandlingStrategy): Router;
export declare function setupTestingRouter(urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts, location: Location, loader: NgModuleFactoryLoader, compiler: Compiler, injector: Injector, routes: Route[][], urlHandlingStrategy?: UrlHandlingStrategy): Router;
/** @stable */
export declare class SpyNgModuleFactoryLoader implements NgModuleFactoryLoader {