Compare commits
113 Commits
manughub-r
...
5.1.x
Author | SHA1 | Date | |
---|---|---|---|
96efb4b165 | |||
7c34807765 | |||
84f6b148d5 | |||
39f81b210e | |||
0602aaa06c | |||
a73b0b64fb | |||
fda3815395 | |||
4f7c13d554 | |||
4947454344 | |||
e86ce590fe | |||
1bd03a4081 | |||
8b197b24f5 | |||
8f3ea339f7 | |||
839d24e427 | |||
a1af559e16 | |||
e2cc4dbfc0 | |||
5dd2df6a58 | |||
52cb79ccb5 | |||
17e85cd9a5 | |||
8dd93f844f | |||
c809545c77 | |||
d3c0425786 | |||
088c1e3286 | |||
d79a0ba5b6 | |||
b7307c9517 | |||
cc0b0a4729 | |||
5efb751a09 | |||
b9d8ac5b2d | |||
fc217f552a | |||
d138b38bdb | |||
4f409954f8 | |||
00308fcc9f | |||
a7a7bd3ca0 | |||
67630f82b6 | |||
8006be8d8c | |||
48a1f32222 | |||
521f0d4c7d | |||
941cd102b8 | |||
66043e09a2 | |||
12702b20c7 | |||
5de91fe93e | |||
d787b55b31 | |||
3e34fa8651 | |||
8c991756fa | |||
fa0e8ef92c | |||
41abcc34f4 | |||
0aa6341e31 | |||
43377684d9 | |||
dc53248b15 | |||
d1f45002d3 | |||
6353b77f89 | |||
d9c40b7dd5 | |||
a36dfd453b | |||
ced575fd10 | |||
3b63e168e2 | |||
a1d4c2dbf1 | |||
a33182c4ee | |||
66cc2fabf1 | |||
cf8269ee94 | |||
c7241ca0e6 | |||
4a49e19bd7 | |||
4a3a74b7b0 | |||
6aa013cb63 | |||
b9531f90b8 | |||
f239e8496e | |||
57bed3fe73 | |||
c011ffae30 | |||
756dd34519 | |||
267ebf323e | |||
49c45f336e | |||
71236737ab | |||
390837f76e | |||
fbcf7dc889 | |||
5c8c7d8515 | |||
99cc591f63 | |||
e3140ae888 | |||
ca815106c9 | |||
d6da7988c0 | |||
41e1951ffb | |||
c02f97ce4e | |||
be9a7371b8 | |||
1f469497da | |||
8a5f0f7a64 | |||
8bcb093bfa | |||
abc3a1e844 | |||
9fbf850897 | |||
0c9f7b032a | |||
8b21be5da3 | |||
0a9a16183f | |||
28555bc1e7 | |||
d09d4971b3 | |||
f8a4d14c8f | |||
d713225128 | |||
5d3af4cad4 | |||
a7fe063aa5 | |||
affa54ddf9 | |||
02782c10ea | |||
8e5a3a42d6 | |||
dbef8ff2b0 | |||
c0f08be3fb | |||
f56cbcc1e5 | |||
1b86570b60 | |||
923227dec2 | |||
53b9de300b | |||
da587cb9ef | |||
e6a28054d8 | |||
69ed916b42 | |||
c3e8731145 | |||
501f01e9ac | |||
baeec4dbe2 | |||
160a154553 | |||
9dd60a5fb0 | |||
672733608b |
@ -12,8 +12,8 @@
|
|||||||
## IMPORTANT
|
## IMPORTANT
|
||||||
# If you change the `docker_image` version, also change the `cache_key` suffix and the version of
|
# If you change the `docker_image` version, also change the `cache_key` suffix and the version of
|
||||||
# `com_github_bazelbuild_buildtools` in the `/WORKSPACE` file.
|
# `com_github_bazelbuild_buildtools` in the `/WORKSPACE` file.
|
||||||
var_1: &docker_image angular/ngcontainer:0.0.8
|
var_1: &docker_image angular/ngcontainer:0.1.0
|
||||||
var_2: &cache_key angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.0.8
|
var_2: &cache_key angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.1.0
|
||||||
|
|
||||||
# Settings common to each job
|
# Settings common to each job
|
||||||
anchor_1: &job_defaults
|
anchor_1: &job_defaults
|
||||||
@ -38,7 +38,10 @@ jobs:
|
|||||||
# Then we don't need any exclude pattern to avoid checking those files
|
# Then we don't need any exclude pattern to avoid checking those files
|
||||||
- run: 'buildifier -mode=check $(find . -type f \( -name BUILD.bazel -or -name BUILD \)) ||
|
- run: 'buildifier -mode=check $(find . -type f \( -name BUILD.bazel -or -name BUILD \)) ||
|
||||||
(echo "BUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)'
|
(echo "BUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)'
|
||||||
|
# Run the skylark linter to check our Bazel rules
|
||||||
|
- run: 'find . -type f -name "*.bzl" |
|
||||||
|
xargs java -jar /usr/local/bin/Skylint_deploy.jar ||
|
||||||
|
(echo -e "\n.bzl files have lint errors. Please run ''yarn skylint''"; exit 1)'
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
key: *cache_key
|
key: *cache_key
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
# hansl - Hans Larsen
|
# hansl - Hans Larsen
|
||||||
# IgorMinar - Igor Minar
|
# IgorMinar - Igor Minar
|
||||||
# jasonaden - Jason Aden
|
# jasonaden - Jason Aden
|
||||||
# juleskremer - Jules Kremer
|
|
||||||
# kara - Kara Erickson
|
# kara - Kara Erickson
|
||||||
# matsko - Matias Niemelä
|
# matsko - Matias Niemelä
|
||||||
# mhevery - Misko Hevery
|
# mhevery - Misko Hevery
|
||||||
@ -25,6 +24,7 @@
|
|||||||
# tinayuangao - Tina Gao
|
# tinayuangao - Tina Gao
|
||||||
# vicb - Victor Berchet
|
# vicb - Victor Berchet
|
||||||
# vikerman - Vikram Subramanian
|
# vikerman - Vikram Subramanian
|
||||||
|
# wardbell - Ward Bell
|
||||||
|
|
||||||
|
|
||||||
version: 2
|
version: 2
|
||||||
@ -35,14 +35,32 @@ group_defaults:
|
|||||||
enabled: true
|
enabled: true
|
||||||
approve_by_comment:
|
approve_by_comment:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
# see http://docs.pullapprove.com/groups/author_approval/
|
||||||
|
author_approval:
|
||||||
|
# If the author is a reviewer on the PR, they will automatically have an "approved" status.
|
||||||
|
auto: true
|
||||||
|
|
||||||
groups:
|
groups:
|
||||||
|
# Require all PRs to have at least one approval from *someone*
|
||||||
|
all:
|
||||||
|
users: all
|
||||||
|
required: 1
|
||||||
|
# In this group, your self-approval does not count
|
||||||
|
author_approval:
|
||||||
|
auto: false
|
||||||
|
ignored: true
|
||||||
|
files:
|
||||||
|
include:
|
||||||
|
- "*"
|
||||||
|
|
||||||
root:
|
root:
|
||||||
conditions:
|
conditions:
|
||||||
files:
|
files:
|
||||||
include:
|
include:
|
||||||
- "*"
|
- "*"
|
||||||
exclude:
|
exclude:
|
||||||
|
- "WORKSPACE"
|
||||||
|
- "BUILD.bazel"
|
||||||
- ".circleci/*"
|
- ".circleci/*"
|
||||||
- "aio/*"
|
- "aio/*"
|
||||||
- "integration/*"
|
- "integration/*"
|
||||||
@ -70,6 +88,7 @@ groups:
|
|||||||
- "*.bazel"
|
- "*.bazel"
|
||||||
- "*.bzl"
|
- "*.bzl"
|
||||||
- "packages/bazel/*"
|
- "packages/bazel/*"
|
||||||
|
- "tools/bazel.rc"
|
||||||
users:
|
users:
|
||||||
- alexeagle #primary
|
- alexeagle #primary
|
||||||
- chuckjaz
|
- chuckjaz
|
||||||
@ -85,6 +104,7 @@ groups:
|
|||||||
- "*.lock"
|
- "*.lock"
|
||||||
- "tools/*"
|
- "tools/*"
|
||||||
exclude:
|
exclude:
|
||||||
|
- "tools/bazel.rc"
|
||||||
- "tools/public_api_guard/*"
|
- "tools/public_api_guard/*"
|
||||||
- "aio/*"
|
- "aio/*"
|
||||||
users:
|
users:
|
||||||
@ -280,7 +300,7 @@ groups:
|
|||||||
files:
|
files:
|
||||||
- "packages/benchpress/*"
|
- "packages/benchpress/*"
|
||||||
users:
|
users:
|
||||||
# needs primary
|
- alxhub # primary
|
||||||
# needs secondary
|
# needs secondary
|
||||||
- IgorMinar #fallback
|
- IgorMinar #fallback
|
||||||
- mhevery #fallback
|
- mhevery #fallback
|
||||||
@ -308,9 +328,8 @@ groups:
|
|||||||
- "aio/content/navigation.json"
|
- "aio/content/navigation.json"
|
||||||
- "aio/content/license.md"
|
- "aio/content/license.md"
|
||||||
users:
|
users:
|
||||||
- juleskremer #primary
|
|
||||||
- Foxandxss
|
|
||||||
- stephenfluin
|
- stephenfluin
|
||||||
|
- Foxandxss
|
||||||
- petebacondarwin
|
- petebacondarwin
|
||||||
- gkalpak
|
- gkalpak
|
||||||
- IgorMinar #fallback
|
- IgorMinar #fallback
|
||||||
@ -324,7 +343,6 @@ groups:
|
|||||||
- "aio/content/navigation.json"
|
- "aio/content/navigation.json"
|
||||||
- "aio/content/license.md"
|
- "aio/content/license.md"
|
||||||
users:
|
users:
|
||||||
- juleskremer #primary
|
|
||||||
- stephenfluin
|
- stephenfluin
|
||||||
- petebacondarwin
|
- petebacondarwin
|
||||||
- gkalpak
|
- gkalpak
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
sudo: false
|
# Work-around for https://github.com/travis-ci/travis-ci/issues/8836#issuecomment-356362524.
|
||||||
|
# (Restore `sudo: false` once that is resolved.)
|
||||||
|
sudo: required
|
||||||
dist: trusty
|
dist: trusty
|
||||||
node_js:
|
node_js:
|
||||||
- '8.9.1'
|
- '8.9.1'
|
||||||
|
33
CHANGELOG.md
33
CHANGELOG.md
@ -1,17 +1,14 @@
|
|||||||
<a name="5.2.0-beta.1"></a>
|
<a name="5.1.3"></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)
|
## [5.1.3](https://github.com/angular/angular/compare/5.1.2...5.1.3) (2018-01-03)
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
* **compiler:** generate the correct imports for summary type-check ([d91ff17](https://github.com/angular/angular/commit/d91ff17))
|
* **animations:** avoid infinite loop with multiple blocked sub triggers ([#21119](https://github.com/angular/angular/issues/21119)) ([3e34fa8](https://github.com/angular/angular/commit/3e34fa8))
|
||||||
* **forms:** avoid producing an error with hostBindingTypeCheck ([d213a20](https://github.com/angular/angular/commit/d213a20))
|
* **animations:** renaming issue with DOMAnimation. ([#21125](https://github.com/angular/angular/issues/21125)) ([d1f4500](https://github.com/angular/angular/commit/d1f4500))
|
||||||
|
* **common:** handle JS floating point errors in percent pipe ([#20329](https://github.com/angular/angular/issues/20329)) ([fa0e8ef](https://github.com/angular/angular/commit/fa0e8ef)), closes [#20136](https://github.com/angular/angular/issues/20136)
|
||||||
|
* **language-service:** ignore null metadatas ([#20557](https://github.com/angular/angular/issues/20557)) ([48a1f32](https://github.com/angular/angular/commit/48a1f32)), closes [#20260](https://github.com/angular/angular/issues/20260)
|
||||||
### Features
|
* **router:** fix wildcard route with lazy loaded module (again) ([#18139](https://github.com/angular/angular/issues/18139)) ([8c99175](https://github.com/angular/angular/commit/8c99175)), closes [#13848](https://github.com/angular/angular/issues/13848)
|
||||||
|
|
||||||
* **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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -31,20 +28,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>
|
<a name="5.1.1"></a>
|
||||||
## [5.1.1](https://github.com/angular/angular/compare/5.1.0...5.1.1) (2017-12-13)
|
## [5.1.1](https://github.com/angular/angular/compare/5.1.0...5.1.1) (2017-12-13)
|
||||||
|
|
||||||
@ -60,7 +43,7 @@
|
|||||||
* **compiler-cli:** disable checkTypes in emit. ([#20828](https://github.com/angular/angular/issues/20828)) ([160a154](https://github.com/angular/angular/commit/160a154))
|
* **compiler-cli:** disable checkTypes in emit. ([#20828](https://github.com/angular/angular/issues/20828)) ([160a154](https://github.com/angular/angular/commit/160a154))
|
||||||
* **compiler-cli:** fix swallowed Error messages ([#20846](https://github.com/angular/angular/issues/20846)) ([6727336](https://github.com/angular/angular/commit/6727336))
|
* **compiler-cli:** fix swallowed Error messages ([#20846](https://github.com/angular/angular/issues/20846)) ([6727336](https://github.com/angular/angular/commit/6727336))
|
||||||
* **compiler-cli:** merge [@fileoverview](https://github.com/fileoverview) comments. ([#20870](https://github.com/angular/angular/issues/20870)) ([be9a737](https://github.com/angular/angular/commit/be9a737))
|
* **compiler-cli:** merge [@fileoverview](https://github.com/fileoverview) comments. ([#20870](https://github.com/angular/angular/issues/20870)) ([be9a737](https://github.com/angular/angular/commit/be9a737))
|
||||||
* **router:** NavigatonError and NavigationCancel should be emitted after resetting the URL ([#20803](https://github.com/angular/angular/issues/20803)) ([baeec4d](https://github.com/angular/angular/commit/baeec4d))
|
* **router:** NavigationError and NavigationCancel should be emitted after resetting the URL ([#20803](https://github.com/angular/angular/issues/20803)) ([baeec4d](https://github.com/angular/angular/commit/baeec4d))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
The MIT License
|
The MIT License
|
||||||
|
|
||||||
Copyright (c) 2014-2017 Google, Inc. http://angular.io
|
Copyright (c) 2014-2018 Google, Inc. http://angular.io
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
[](https://circleci.com/gh/angular/angular/tree/master)
|
[](https://circleci.com/gh/angular/angular/tree/master)
|
||||||
[](https://www.browserstack.com/automate/public-build/LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06)
|
[](https://www.browserstack.com/automate/public-build/LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06)
|
||||||
[](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
[](http://issuestats.com/github/angular/angular)
|
|
||||||
[](http://issuestats.com/github/angular/angular)
|
|
||||||
[](https://www.npmjs.com/@angular/core)
|
[](https://www.npmjs.com/@angular/core)
|
||||||
|
|
||||||
|
|
||||||
|
12
WORKSPACE
12
WORKSPACE
@ -10,13 +10,13 @@ git_repository(
|
|||||||
|
|
||||||
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories")
|
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories")
|
||||||
|
|
||||||
check_bazel_version("0.8.1")
|
check_bazel_version("0.9.0")
|
||||||
node_repositories(package_json = ["//:package.json"])
|
node_repositories(package_json = ["//:package.json"])
|
||||||
|
|
||||||
git_repository(
|
git_repository(
|
||||||
name = "build_bazel_rules_typescript",
|
name = "build_bazel_rules_typescript",
|
||||||
remote = "https://github.com/bazelbuild/rules_typescript.git",
|
remote = "https://github.com/bazelbuild/rules_typescript.git",
|
||||||
tag = "0.6.0",
|
tag = "0.6.2",
|
||||||
)
|
)
|
||||||
|
|
||||||
load("@build_bazel_rules_typescript//:defs.bzl", "ts_repositories")
|
load("@build_bazel_rules_typescript//:defs.bzl", "ts_repositories")
|
||||||
@ -53,3 +53,11 @@ load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_too
|
|||||||
go_rules_dependencies()
|
go_rules_dependencies()
|
||||||
|
|
||||||
go_register_toolchains()
|
go_register_toolchains()
|
||||||
|
|
||||||
|
# Fetching the Bazel source code allows us to compile the Skylark linter
|
||||||
|
http_archive(
|
||||||
|
name = "io_bazel",
|
||||||
|
url = "https://github.com/bazelbuild/bazel/archive/9755c72b48866ed034bd28aa033e9abd27431b1e.zip",
|
||||||
|
strip_prefix = "bazel-9755c72b48866ed034bd28aa033e9abd27431b1e",
|
||||||
|
sha256 = "5b8443fc3481b5fcd9e7f348e1dd93c1397f78b223623c39eb56494c55f41962",
|
||||||
|
)
|
||||||
|
@ -130,7 +130,7 @@ function tests() {
|
|||||||
it('can get RouterLinks from template', () => {
|
it('can get RouterLinks from template', () => {
|
||||||
expect(links.length).toBe(3, 'should have 3 links');
|
expect(links.length).toBe(3, 'should have 3 links');
|
||||||
expect(links[0].linkParams).toBe('/dashboard', '1st link should go to Dashboard');
|
expect(links[0].linkParams).toBe('/dashboard', '1st link should go to Dashboard');
|
||||||
expect(links[1].linkParams).toBe('/heroes', '1st link should go to Heroes');
|
expect(links[1].linkParams).toBe('/heroes', '2nd link should go to Heroes');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can click Heroes link in template', () => {
|
it('can click Heroes link in template', () => {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
The Angular Ahead-of-Time (AOT) compiler converts your Angular HTML and TypeScript code into efficient JavaScript code during the build phase _before_ the browser downloads and runs that code.
|
The Angular Ahead-of-Time (AOT) compiler converts your Angular HTML and TypeScript code into efficient JavaScript code during the build phase _before_ the browser downloads and runs that code.
|
||||||
|
|
||||||
This guide explains how to build with the AOT compiler and how to write Angular metadata that AOT can compile.
|
This guide explains how to build with the AOT compiler using different compiler options and how to write Angular metadata that AOT can compile.
|
||||||
|
|
||||||
<div class="l-sub-section">
|
<div class="l-sub-section">
|
||||||
|
|
||||||
@ -77,6 +77,174 @@ AOT compiles HTML templates and components into JavaScript files long before the
|
|||||||
With no templates to read and no risky client-side HTML or JavaScript evaluation,
|
With no templates to read and no risky client-side HTML or JavaScript evaluation,
|
||||||
there are fewer opportunities for injection attacks.
|
there are fewer opportunities for injection attacks.
|
||||||
|
|
||||||
|
{@a compiler-options}
|
||||||
|
|
||||||
|
## Angular Compiler Options
|
||||||
|
|
||||||
|
You can control your app compilation by providing template compiler options in the `tsconfig.json` file along with the options supplied to the TypeScript compiler. The template compiler options are specified as members of
|
||||||
|
`"angularCompilerOptions"` object as shown below:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
...
|
||||||
|
},
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"fullTemplateTypeCheck": true,
|
||||||
|
"preserveWhiteSpace": false,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### *skipMetadataEmit*
|
||||||
|
|
||||||
|
This option tells the compiler not to produce `.metadata.json` files.
|
||||||
|
The option is `false` by default.
|
||||||
|
|
||||||
|
`.metadata.json` files contain infomration needed by the template compiler from a `.ts`
|
||||||
|
file that is not included in the `.d.ts` file produced by the TypeScript compiler. This information contains,
|
||||||
|
for example, the content of annotations (such as a component's template) which TypeScript
|
||||||
|
emits to the `.js` file but not to the `.d.ts` file.
|
||||||
|
|
||||||
|
This option should be set to `true` if using TypeScript's `--outFile` option, as the metadata files
|
||||||
|
are not valid for this style of TypeScript output. It is not recommeded to use `--outFile` with
|
||||||
|
Angular. Use a bundler, such as [webpack](https://webpack.js.org/), instead.
|
||||||
|
|
||||||
|
This option can also be set to `true` when using factory summaries as the factory summaries
|
||||||
|
include a copy of the information that is in the `.metadata.json` file.
|
||||||
|
|
||||||
|
### *strictMetadataEmit*
|
||||||
|
|
||||||
|
This option tells the template compiler to report an error to the `.metadata.json`
|
||||||
|
file if `"skipMetadataEmit"` is `false` . This option is `false` by default. This should only be used when `"skipMetadataEmit"` is `false` and `"skipTemplateCodeGen"` is `true`.
|
||||||
|
|
||||||
|
It is intended to validate the `.metadata.json` files emitted for bundling with an `npm` package. The validation is overly strict and can emit errors for metadata that would never produce an error when used by the template compiler. You can choose to suppress the error emitted by this option for an exported symbol by including `@dynamic` in the comment documenting the symbol.
|
||||||
|
|
||||||
|
It is valid for `.metadata.json` files to contain errors. The template compiler reports these errors
|
||||||
|
if the metadata is used to determine the contents of an annotation. The metadata
|
||||||
|
collector cannot predict the symbols that are designed to use in an annotation, so it will preemptively
|
||||||
|
include error nodes in the metadata for the exported symbols. The template compiler can then use the error
|
||||||
|
nodes to report an error if these symbols are used. If the client of a library intends to use a symbol in an annotation, the template compiler will not normally report
|
||||||
|
this until the client uses the symbol. This option allows detecting these errors during the build phase of
|
||||||
|
the library and is used, for example, in producing Angular libraries themselves.
|
||||||
|
|
||||||
|
### *skipTemplateCodegen*
|
||||||
|
|
||||||
|
This option tells the compiler to suppress emitting `.ngfactory.js` and `.ngstyle.js` files. When set,
|
||||||
|
this turns off most of the template compiler and disables reporting template diagnostics.
|
||||||
|
This option can be used to instruct the
|
||||||
|
template compiler to produce `.metadata.json` files for distribution with an `npm` package while
|
||||||
|
avoiding the production of `.ngfactory.js` and `.ngstyle.js` files that cannot be distributed to
|
||||||
|
`npm`.
|
||||||
|
|
||||||
|
### *strictInjectionParameters*
|
||||||
|
|
||||||
|
When set to `true`, this options tells the compiler to report an error for a parameter supplied
|
||||||
|
whose injection type cannot be determined. When this value option is not provided or is `false`, constructor parameters of classes marked with `@Injectable` whose type cannot be resolved will
|
||||||
|
produce a warning.
|
||||||
|
|
||||||
|
*Note*: It is recommended to change this option explicitly to `true` as this option will default to `true` in the future.
|
||||||
|
|
||||||
|
### *flatModuleOutFile*
|
||||||
|
|
||||||
|
When set to `true`, this option tells the template compiler to generate a flat module
|
||||||
|
index of the given file name and the corresponding flat module metadata. Use this option when creating
|
||||||
|
flat modules that are packaged similarly to `@angular/core` and `@angular/common`. When this option
|
||||||
|
is used, the `package.json` for the library should refer
|
||||||
|
to the generated flat module index instead of the library index file. With this
|
||||||
|
option only one `.metadata.json` file is produced that contains all the metadata necessary
|
||||||
|
for symbols exported from the library index. In the generated `.ngfactory.js` files, the flat
|
||||||
|
module index is used to import symbols that includes both the public API from the library index
|
||||||
|
as well as shrowded internal symbols.
|
||||||
|
|
||||||
|
By default the `.ts` file supplied in the `files` field is assumed to be library index.
|
||||||
|
If more than one `.ts` file is specified, `libraryIndex` is used to select the file to use.
|
||||||
|
If more than one `.ts` file is supplied without a `libraryIndex`, an error is produced. A flat module
|
||||||
|
index `.d.ts` and `.js` will be created with the given `flatModuleOutFile` name in the same
|
||||||
|
location as the library index `.d.ts` file. For example, if a library uses
|
||||||
|
`public_api.ts` file as the library index of the module, the `tsconfig.json` `files` field
|
||||||
|
would be `["public_api.ts"]`. The `flatModuleOutFile` options could then be set to, for
|
||||||
|
example `"index.js"`, which produces `index.d.ts` and `index.metadata.json` files. The
|
||||||
|
library's `package.json`'s `module` field would be `"index.js"` and the `typings` field
|
||||||
|
would be `"index.d.ts"`.
|
||||||
|
|
||||||
|
### *flatModuleId*
|
||||||
|
|
||||||
|
This option specifies the preferred module id to use for importing a flat module.
|
||||||
|
References generated by the template compiler will use this module name when importing symbols
|
||||||
|
from the flat module.
|
||||||
|
This is only meaningful when `flatModuleOutFile` is also supplied. Otherwise the compiler ignores
|
||||||
|
this option.
|
||||||
|
|
||||||
|
### *generateCodeForLibraries*
|
||||||
|
|
||||||
|
This option tells the template compiler to generate factory files (`.ngfactory.js` and `.ngstyle.js`)
|
||||||
|
for `.d.ts` files with a corresponding `.metadata.json` file. This option defaults to
|
||||||
|
`true`. When this option is `false`, factory files are generated only for `.ts` files.
|
||||||
|
|
||||||
|
This option should be set to `false` when using factory summaries.
|
||||||
|
|
||||||
|
### *fullTemplateTypeCheck*
|
||||||
|
|
||||||
|
This option tells the compiler to enable the [binding expression validation](#binding-expresion-validation)
|
||||||
|
phase of the template compiler which uses TypeScript to validate binding expressions.
|
||||||
|
|
||||||
|
This option is `false` by default.
|
||||||
|
|
||||||
|
*Note*: It is recommended to set this to `true` as this option will default to `true` in the future.
|
||||||
|
|
||||||
|
### *annotateForClosureCompiler*
|
||||||
|
|
||||||
|
This option tells the compiler to use [Tsickle](https://github.com/angular/tsickle) to annotate the emitted
|
||||||
|
JavaScript with [JsDoc](http://usejsdoc.org/) comments needed by the
|
||||||
|
[Closure Compiler](https://github.com/google/closure-compiler). This option defaults to `false`.
|
||||||
|
|
||||||
|
### *annotationsAs*
|
||||||
|
|
||||||
|
Use this option to modify how the Angular specific annotations are emitted to improve tree-shaking. Non-Angular
|
||||||
|
annotations and decorators are unnaffected. Default is `static fields`.
|
||||||
|
|
||||||
|
value | description
|
||||||
|
----------------|-------------------------------------------------------------
|
||||||
|
`decorators` | Leave the Decorators in-place. This makes compilation faster. TypeScript will emit calls to the __decorate helper. Use `--emitDecoratorMetadata` for runtime reflection. However, the resulting code will not properly tree-shake.
|
||||||
|
`static fields` | Replace decorators with a static field in the class. Allows advanced tree-shakers like [Closure Compiler](https://github.com/google/closure-compiler) to remove unused classes.
|
||||||
|
|
||||||
|
### *trace*
|
||||||
|
|
||||||
|
This tells the compiler to print extra information while compiling templates.
|
||||||
|
|
||||||
|
### *enableLegacyTemplate*
|
||||||
|
|
||||||
|
The use of `<template>` element was deprecated starting in Angular 4.0 in favor of using
|
||||||
|
`<ng-template>` to avoid colliding with the DOM's element of the same name. Setting this option to
|
||||||
|
`true` enables the use of the deprecated `<template>` element . This option
|
||||||
|
is `false` by default. This option might be required by some third-party Angular libraries.
|
||||||
|
|
||||||
|
### *disableExpressionLowering*
|
||||||
|
|
||||||
|
The Angular template compiler transforms code that is used, or could be used, in an annotation
|
||||||
|
to allow it to be imported from template factory modules. See
|
||||||
|
[metadata rewriting](#metadata-rewriting) for more information.
|
||||||
|
|
||||||
|
Setting this option to `false` disables this rewriting, requiring the rewriting to be
|
||||||
|
done manually.
|
||||||
|
|
||||||
|
### *preserveWhitespaces*
|
||||||
|
|
||||||
|
This option tells the compiler whether to remove blank text nodes from compiled templates.
|
||||||
|
This option is `true` by default.
|
||||||
|
|
||||||
|
*Note*: It is recommended to set this explicitly to `false` as it emits smaller template factory modules and might be set to `false` by default in the future.
|
||||||
|
|
||||||
|
### *allowEmptyCodegenFiles*
|
||||||
|
|
||||||
|
Tells the compiler to generate all the possible generated files even if they are empty. This option is
|
||||||
|
`false` by default. This is an option used by `bazel` build rules and is needed to simplify
|
||||||
|
how `bazel` rules track file dependencies. It is not recommended to use this option outside of the `bazel`
|
||||||
|
rules.
|
||||||
|
|
||||||
## Angular Metadata and AOT
|
## Angular Metadata and AOT
|
||||||
|
|
||||||
The Angular **AOT compiler** extracts and interprets **metadata** about the parts of the application that Angular is supposed to manage.
|
The Angular **AOT compiler** extracts and interprets **metadata** about the parts of the application that Angular is supposed to manage.
|
||||||
@ -212,6 +380,7 @@ export function serverFactory() {
|
|||||||
|
|
||||||
Beginning in version 5, the compiler automatically performs this rewritting while emitting the `.js` file.
|
Beginning in version 5, the compiler automatically performs this rewritting while emitting the `.js` file.
|
||||||
|
|
||||||
|
{@a function-calls}
|
||||||
### Limited function calls
|
### Limited function calls
|
||||||
|
|
||||||
The _collector_ can represent a function call or object creation with `new` as long as the syntax is valid. The _collector_ only cares about proper syntax.
|
The _collector_ can represent a function call or object creation with `new` as long as the syntax is valid. The _collector_ only cares about proper syntax.
|
||||||
@ -411,6 +580,7 @@ The Angular [`RouterModule`](api/router/RouterModule) exports two macro static m
|
|||||||
Review the [source code](https://github.com/angular/angular/blob/master/packages/router/src/router_module.ts#L139 "RouterModule.forRoot source code")
|
Review the [source code](https://github.com/angular/angular/blob/master/packages/router/src/router_module.ts#L139 "RouterModule.forRoot source code")
|
||||||
for these methods to see how macros can simplify configuration of complex [NgModules](guide/ngmodule).
|
for these methods to see how macros can simplify configuration of complex [NgModules](guide/ngmodule).
|
||||||
|
|
||||||
|
{@ metadata-rewriting}
|
||||||
### Metadata rewriting
|
### Metadata rewriting
|
||||||
|
|
||||||
The compiler treats object literals containing the fields `useClass`, `useValue`, `useFactory`, and `data` specially. The compiler converts the expression initializing one of these fields into an exported variable, which replaces the expression. This process of rewriting these expressions removes all the restrictions on what can be in them because
|
The compiler treats object literals containing the fields `useClass`, `useValue`, `useFactory`, and `data` specially. The compiler converts the expression initializing one of these fields into an exported variable, which replaces the expression. This process of rewriting these expressions removes all the restrictions on what can be in them because
|
||||||
@ -961,7 +1131,155 @@ This error can occur if you use an expression in the `extends` clause of a class
|
|||||||
Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](https://github.com/angular/angular/pull/17712#discussion_r132025495).
|
Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](https://github.com/angular/angular/pull/17712#discussion_r132025495).
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
{@a binding-expresion-validation}
|
||||||
|
|
||||||
|
## Phase 3: binding expression validation
|
||||||
|
|
||||||
|
In the validation phase, the Angular template compiler uses the TypeScript compiler to validate the
|
||||||
|
binding expressions in templates. Enable this phase explicity by adding the compiler
|
||||||
|
option `"fullTemplateTypeCheck"` in the `"angularCompilerOptions"` of the project's `tsconfig.json` (see
|
||||||
|
[Angular Compiler Options](#compiler-options)).
|
||||||
|
|
||||||
|
Template validation produces error messages when a type error is detected in a template binding
|
||||||
|
expression, similar to how type errors are reported by the TypeScript compiler against code in a `.ts`
|
||||||
|
file.
|
||||||
|
|
||||||
|
For example, consider the following component:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
@Component({
|
||||||
|
selector: 'my-component',
|
||||||
|
template: '{{person.addresss.street}}'
|
||||||
|
})
|
||||||
|
class MyComponent {
|
||||||
|
person?: Person;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This will produce the following error:
|
||||||
|
|
||||||
|
```
|
||||||
|
my.component.ts.MyComponent.html(1,1): : Property 'addresss' does not exist on type 'Person'. Did you mean 'address'?
|
||||||
|
```
|
||||||
|
|
||||||
|
The file name reported in the error message, `my.component.ts.MyComponent.html`, is a synthetic file
|
||||||
|
generated by the template compiler that holds contents of the `MyComponent` class template.
|
||||||
|
Compiler never writes this file to disk. The line and column numbers are relative to the template string
|
||||||
|
in the `@Component` annotation of the class, `MyComponent` in this case. If a component uses
|
||||||
|
`templateUrl` instead of `template`, the errors are reported in the HTML file refereneced by the
|
||||||
|
`templateUrl` instead of a synthetic file.
|
||||||
|
|
||||||
|
The error location is the beginning of the text node that contains the interpolation expression with
|
||||||
|
the error. If the error is in an attribute binding such as `[value]="person.address.street"`, the error
|
||||||
|
location is the location of the attribute that contains the error.
|
||||||
|
|
||||||
|
The validation uses the TypeScript type checker and the options supplied to the TypeScript compiler to control
|
||||||
|
how detailed the type validation is. For example, if the `strictTypeChecks` is specified, the error ```my.component.ts.MyComponent.html(1,1): : Object is possibly 'undefined'``` is reported as well as the above error message.
|
||||||
|
|
||||||
|
### Type narrowing
|
||||||
|
|
||||||
|
The expression used in an `ngIf` directive is used to narrow type unions in the Angular
|
||||||
|
template compiler, the same way the `if` expression does in TypeScript. For example, to avoid
|
||||||
|
`Object is possibly 'undefined'` error in the template above, modify it to only emit the
|
||||||
|
interpolation if the value of `person` is initialized as shown below:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
@Component({
|
||||||
|
selector: 'my-component',
|
||||||
|
template: '<span *ngIf="person"> {{person.addresss.street}} </span>'
|
||||||
|
})
|
||||||
|
class MyComponent {
|
||||||
|
person?: Person;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Using `*ngIf` allows the TypeScript compiler to infer that the `person` used in the
|
||||||
|
binding expression will never be `undefined`.
|
||||||
|
|
||||||
|
#### Custom `ngIf` like directives
|
||||||
|
|
||||||
|
Directives that behave like `*ngIf` can declare that they want the same treatment by including
|
||||||
|
a static member marker that is a signal to the template compiler to treat them
|
||||||
|
like `*ngIf`. This static member for `*ngIf` is:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
public static ngIfUseIfTypeGuard: void;
|
||||||
|
```
|
||||||
|
|
||||||
|
This declares that the input property `ngIf` of the `NgIf` directive should be treated as a
|
||||||
|
guard to the use of its template, implying that the template will only be instantiated if
|
||||||
|
the `ngIf` input property is true.
|
||||||
|
|
||||||
|
|
||||||
|
### Non-null type assertion operator
|
||||||
|
|
||||||
|
Use the [non-null type assertion operator](guide/template-syntax#non-null-assertion-operator)
|
||||||
|
to suppress the `Object is possibly 'undefined'` error when it is incovienent to use
|
||||||
|
`*ngIf` or when some constraint in the component ensures that the expression is always
|
||||||
|
non-null when the binding expression is interpolated.
|
||||||
|
|
||||||
|
In the following example, the `person` and `address` properties are always set together,
|
||||||
|
implying that `address` is always non-null if `person` is non-null. There is no convenient
|
||||||
|
way to describe this constraint to TypeScript and the template compiler, but the error
|
||||||
|
is suppressed in the example by using `address!.street`.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
@Component({
|
||||||
|
selector: 'my-component',
|
||||||
|
template: '<span *ngIf="person"> {{person.name}} lives on {{address!.street}} </span>'
|
||||||
|
})
|
||||||
|
class MyComponent {
|
||||||
|
person?: Person;
|
||||||
|
address?: Address;
|
||||||
|
|
||||||
|
setData(person: Person, address: Address) {
|
||||||
|
this.person = person;
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The non-null assertion operator should be used sparingly as refactoring of the component
|
||||||
|
might break this constraint.
|
||||||
|
|
||||||
|
In this example it is recommended to include the checking of `address`
|
||||||
|
in the `*ngIf`as shown below:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
@Component({
|
||||||
|
selector: 'my-component',
|
||||||
|
template: '<span *ngIf="person && address"> {{person.name}} lives on {{address.street}} </span>'
|
||||||
|
})
|
||||||
|
class MyComponent {
|
||||||
|
person?: Person;
|
||||||
|
address?: Address;
|
||||||
|
|
||||||
|
setData(person: Person, address: Address) {
|
||||||
|
this.person = person;
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Disabling type checking using `$any()`
|
||||||
|
|
||||||
|
Disable checking of a binding expression by surrounding the expression
|
||||||
|
in a call to the [`$any()` cast pseudo-function](guide/template-syntax).
|
||||||
|
The compiler treats it as a cast to the `any` type just like in TypeScript when a `<any>`
|
||||||
|
or `as any` cast is used.
|
||||||
|
|
||||||
|
In the following example, the error `Property addresss does not exist` is suppressed
|
||||||
|
by casting `person` to the `any` type.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
@Component({
|
||||||
|
selector: 'my-component',
|
||||||
|
template: '{{$any(person).addresss.street}}'
|
||||||
|
})
|
||||||
|
class MyComponent {
|
||||||
|
person?: Person;
|
||||||
|
}
|
||||||
|
```
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
* What the AOT compiler does and why it is important.
|
* What the AOT compiler does and why it is important.
|
||||||
@ -970,3 +1288,5 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
|
|||||||
* Other restrictions on metadata definition.
|
* Other restrictions on metadata definition.
|
||||||
* Macro-functions and macro-static methods.
|
* Macro-functions and macro-static methods.
|
||||||
* Compiler errors related to metadata.
|
* Compiler errors related to metadata.
|
||||||
|
* Validation of binding expressions
|
||||||
|
|
||||||
|
@ -371,7 +371,7 @@ and to
|
|||||||
|
|
||||||
Angular developers may encounter a
|
Angular developers may encounter a
|
||||||
<a href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing" title="Cross-origin resource sharing">
|
<a href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing" title="Cross-origin resource sharing">
|
||||||
<i>cross-origin resource sharing</i></a> error when making a service request (typically a data service request).
|
<i>cross-origin resource sharing</i></a> error when making a service request (typically a data service request)
|
||||||
to a server other than the application's own host server.
|
to a server other than the application's own host server.
|
||||||
Browsers forbid such requests unless the server permits them explicitly.
|
Browsers forbid such requests unless the server permits them explicitly.
|
||||||
|
|
||||||
|
@ -273,6 +273,8 @@ has a single `intercept()` method. Here is a simple interceptor which does nothi
|
|||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
|
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
|
||||||
|
|
||||||
|
import {Observable} from 'rxjs/Observable';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NoopInterceptor implements HttpInterceptor {
|
export class NoopInterceptor implements HttpInterceptor {
|
||||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
@ -297,6 +299,8 @@ Simply declaring the `NoopInterceptor` above doesn't cause your app to use it. Y
|
|||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {HTTP_INTERCEPTORS} from '@angular/common/http';
|
import {HTTP_INTERCEPTORS} from '@angular/common/http';
|
||||||
|
|
||||||
|
import {NoopInterceptor} from 'noop.interceptor.ts';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
providers: [{
|
providers: [{
|
||||||
provide: HTTP_INTERCEPTORS,
|
provide: HTTP_INTERCEPTORS,
|
||||||
@ -547,12 +551,12 @@ In order to prevent collisions in environments where multiple Angular apps share
|
|||||||
|
|
||||||
### Configuring custom cookie/header names
|
### Configuring custom cookie/header names
|
||||||
|
|
||||||
If your backend service uses different names for the XSRF token cookie or header, use `HttpClientXsrfModule.withConfig()` to override the defaults.
|
If your backend service uses different names for the XSRF token cookie or header, use `HttpClientXsrfModule.withOptions()` to override the defaults.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
imports: [
|
imports: [
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
HttpClientXsrfModule.withConfig({
|
HttpClientXsrfModule.withOptions({
|
||||||
cookieName: 'My-Xsrf-Cookie',
|
cookieName: 'My-Xsrf-Cookie',
|
||||||
headerName: 'My-Xsrf-Header',
|
headerName: 'My-Xsrf-Header',
|
||||||
}),
|
}),
|
||||||
|
@ -200,8 +200,8 @@ versions are safe to use, so existing tabs continue to run from
|
|||||||
cache, but new loads of the app will be served from the network.
|
cache, but new loads of the app will be served from the network.
|
||||||
|
|
||||||
* `SAFE_MODE`: the service worker cannot guarantee the safety of
|
* `SAFE_MODE`: the service worker cannot guarantee the safety of
|
||||||
using cached data. Either an unexpected error occurred or all c
|
using cached data. Either an unexpected error occurred or all
|
||||||
ached versions are invalid. All traffic will be served from the
|
cached versions are invalid. All traffic will be served from the
|
||||||
network, running as little service worker code as possible.
|
network, running as little service worker code as possible.
|
||||||
|
|
||||||
In both cases, the parenthetical annotation provides the
|
In both cases, the parenthetical annotation provides the
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
@description
|
@description
|
||||||
The MIT License
|
The MIT License
|
||||||
|
|
||||||
Copyright (c) 2014-2017 Google, Inc.
|
Copyright (c) 2014-2018 Google, Inc.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -121,7 +121,7 @@ Import the `HeroService` instead.
|
|||||||
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" title="src/app/heroes/heroes.component.ts (import HeroService)" region="hero-service-import">
|
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" title="src/app/heroes/heroes.component.ts (import HeroService)" region="hero-service-import">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Replace the the definition of the `heroes` property with a simple declaration.
|
Replace the definition of the `heroes` property with a simple declaration.
|
||||||
|
|
||||||
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="heroes">
|
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="heroes">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
@ -58,6 +58,7 @@ describe('site App', function() {
|
|||||||
expect(page.getScrollTop()).toBeGreaterThan(0);
|
expect(page.getScrollTop()).toBeGreaterThan(0);
|
||||||
|
|
||||||
page.getNavItem(/api/i).click();
|
page.getNavItem(/api/i).click();
|
||||||
|
browser.waitForAngular();
|
||||||
expect(page.locationPath()).toBe('/api');
|
expect(page.locationPath()).toBe('/api');
|
||||||
expect(page.getScrollTop()).toBe(0);
|
expect(page.getScrollTop()).toBe(0);
|
||||||
});
|
});
|
||||||
@ -69,6 +70,7 @@ describe('site App', function() {
|
|||||||
expect(page.getScrollTop()).toBeGreaterThan(0);
|
expect(page.getScrollTop()).toBeGreaterThan(0);
|
||||||
|
|
||||||
page.getNavItem(/security/i).click();
|
page.getNavItem(/security/i).click();
|
||||||
|
browser.waitForAngular();
|
||||||
expect(page.locationPath()).toBe('/guide/security');
|
expect(page.locationPath()).toBe('/guide/security');
|
||||||
expect(page.getScrollTop()).toBe(0);
|
expect(page.getScrollTop()).toBe(0);
|
||||||
});
|
});
|
||||||
|
@ -84,7 +84,7 @@
|
|||||||
"rxjs": "^5.5.2",
|
"rxjs": "^5.5.2",
|
||||||
"tslib": "^1.7.1",
|
"tslib": "^1.7.1",
|
||||||
"web-animations-js": "^2.2.5",
|
"web-animations-js": "^2.2.5",
|
||||||
"zone.js": "0.8.16"
|
"zone.js": "^0.8.19"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/cli": "^1.6.0-rc.0",
|
"@angular/cli": "^1.6.0-rc.0",
|
||||||
|
@ -4,17 +4,17 @@
|
|||||||
"gzip7": {
|
"gzip7": {
|
||||||
"inline": 941,
|
"inline": 941,
|
||||||
"main": 116124,
|
"main": 116124,
|
||||||
"polyfills": 11860
|
"polyfills": 13102
|
||||||
},
|
},
|
||||||
"gzip9": {
|
"gzip9": {
|
||||||
"inline": 941,
|
"inline": 941,
|
||||||
"main": 115954,
|
"main": 115954,
|
||||||
"polyfills": 11858
|
"polyfills": 13104
|
||||||
},
|
},
|
||||||
"uncompressed": {
|
"uncompressed": {
|
||||||
"inline": 1558,
|
"inline": 1558,
|
||||||
"main": 456432,
|
"main": 456432,
|
||||||
"polyfills": 37070
|
"polyfills": 40684
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -723,14 +723,14 @@ describe('AppComponent', () => {
|
|||||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should redirect to `docs` if deployment mode is `next` and not at a docs page', () => {
|
it('should not redirect if deployment mode is `next`', () => {
|
||||||
createTestingModule('', 'next');
|
createTestingModule('', 'next');
|
||||||
initializeTest();
|
initializeTest();
|
||||||
expect(TestBed.get(LocationService).replace).toHaveBeenCalledWith('docs');
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||||
|
|
||||||
createTestingModule('resources', 'next');
|
createTestingModule('resources', 'next');
|
||||||
initializeTest();
|
initializeTest();
|
||||||
expect(TestBed.get(LocationService).replace).toHaveBeenCalledWith('docs');
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||||
|
|
||||||
createTestingModule('guide/aot-compiler', 'next');
|
createTestingModule('guide/aot-compiler', 'next');
|
||||||
initializeTest();
|
initializeTest();
|
||||||
@ -757,7 +757,7 @@ describe('AppComponent', () => {
|
|||||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not redirect to `docs` if deployment mode is `stable` and not at a docs page', () => {
|
it('should not redirect to `docs` if deployment mode is `stable`', () => {
|
||||||
createTestingModule('', 'stable');
|
createTestingModule('', 'stable');
|
||||||
initializeTest();
|
initializeTest();
|
||||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||||
|
@ -121,9 +121,9 @@ export class AppComponent implements OnInit {
|
|||||||
this.documentService.currentDocument.first().subscribe(doc => this.updateHostClassesForDoc(doc));
|
this.documentService.currentDocument.first().subscribe(doc => this.updateHostClassesForDoc(doc));
|
||||||
|
|
||||||
this.locationService.currentPath.subscribe(path => {
|
this.locationService.currentPath.subscribe(path => {
|
||||||
// Redirect to docs if we are in not in stable mode and are not hitting a docs page
|
// Redirect to docs if we are in archive mode and are not hitting a docs page
|
||||||
// (i.e. we have arrived at a marketing page)
|
// (i.e. we have arrived at a marketing page)
|
||||||
if (this.deployment.mode !== 'stable' && !/^(docs$|api|guide|tutorial)/.test(path)) {
|
if (this.deployment.mode === 'archive' && !/^(docs$|api|guide|tutorial)/.test(path)) {
|
||||||
this.locationService.replace('docs');
|
this.locationService.replace('docs');
|
||||||
}
|
}
|
||||||
if (path === this.currentPath) {
|
if (path === this.currentPath) {
|
||||||
|
@ -43,15 +43,15 @@ export class ApiListComponent implements OnInit {
|
|||||||
// API types
|
// API types
|
||||||
types: Option[] = [
|
types: Option[] = [
|
||||||
{ value: 'all', title: 'All' },
|
{ value: 'all', title: 'All' },
|
||||||
{ value: 'directive', title: 'Directive' },
|
|
||||||
{ value: 'pipe', title: 'Pipe'},
|
|
||||||
{ value: 'decorator', title: 'Decorator' },
|
|
||||||
{ value: 'class', title: 'Class' },
|
{ value: 'class', title: 'Class' },
|
||||||
{ value: 'interface', title: 'Interface' },
|
{ value: 'const', title: 'Const' },
|
||||||
{ value: 'function', title: 'Function' },
|
{ value: 'decorator', title: 'Decorator' },
|
||||||
|
{ value: 'directive', title: 'Directive' },
|
||||||
{ value: 'enum', title: 'Enum' },
|
{ value: 'enum', title: 'Enum' },
|
||||||
{ value: 'type-alias', title: 'Type Alias' },
|
{ value: 'function', title: 'Function' },
|
||||||
{ value: 'const', title: 'Const'}
|
{ value: 'interface', title: 'Interface' },
|
||||||
|
{ value: 'pipe', title: 'Pipe' },
|
||||||
|
{ value: 'type-alias', title: 'Type Alias' }
|
||||||
];
|
];
|
||||||
|
|
||||||
statuses: Option[] = [
|
statuses: Option[] = [
|
||||||
|
@ -536,7 +536,7 @@ describe('DocViewerComponent', () => {
|
|||||||
expect(swapViewsSpy).not.toHaveBeenCalled();
|
expect(swapViewsSpy).not.toHaveBeenCalled();
|
||||||
expect(docViewer.nextViewContainer.innerHTML).toBe('');
|
expect(docViewer.nextViewContainer.innerHTML).toBe('');
|
||||||
expect(logger.output.error).toEqual([
|
expect(logger.output.error).toEqual([
|
||||||
['[DocViewer]: Error preparing document \'foo\'.', error],
|
[`[DocViewer] Error preparing document 'foo': ${error.stack}`],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -555,7 +555,7 @@ describe('DocViewerComponent', () => {
|
|||||||
expect(swapViewsSpy).not.toHaveBeenCalled();
|
expect(swapViewsSpy).not.toHaveBeenCalled();
|
||||||
expect(docViewer.nextViewContainer.innerHTML).toBe('');
|
expect(docViewer.nextViewContainer.innerHTML).toBe('');
|
||||||
expect(logger.output.error).toEqual([
|
expect(logger.output.error).toEqual([
|
||||||
['[DocViewer]: Error preparing document \'bar\'.', error],
|
[`[DocViewer] Error preparing document 'bar': ${error.stack}`],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -574,7 +574,7 @@ describe('DocViewerComponent', () => {
|
|||||||
expect(swapViewsSpy).not.toHaveBeenCalled();
|
expect(swapViewsSpy).not.toHaveBeenCalled();
|
||||||
expect(docViewer.nextViewContainer.innerHTML).toBe('');
|
expect(docViewer.nextViewContainer.innerHTML).toBe('');
|
||||||
expect(logger.output.error).toEqual([
|
expect(logger.output.error).toEqual([
|
||||||
['[DocViewer]: Error preparing document \'baz\'.', error],
|
[`[DocViewer] Error preparing document 'baz': ${error.stack}`],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -593,7 +593,23 @@ describe('DocViewerComponent', () => {
|
|||||||
expect(swapViewsSpy).toHaveBeenCalledTimes(1);
|
expect(swapViewsSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(docViewer.nextViewContainer.innerHTML).toBe('');
|
expect(docViewer.nextViewContainer.innerHTML).toBe('');
|
||||||
expect(logger.output.error).toEqual([
|
expect(logger.output.error).toEqual([
|
||||||
['[DocViewer]: Error preparing document \'qux\'.', error],
|
[`[DocViewer] Error preparing document 'qux': ${error.stack}`],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('when something fails with non-Error', async () => {
|
||||||
|
const error = 'Typical string error';
|
||||||
|
swapViewsSpy.and.callFake(() => {
|
||||||
|
expect(docViewer.nextViewContainer.innerHTML).not.toBe('');
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
|
||||||
|
await doRender('Some content', 'qux');
|
||||||
|
|
||||||
|
expect(swapViewsSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(docViewer.nextViewContainer.innerHTML).toBe('');
|
||||||
|
expect(logger.output.error).toEqual([
|
||||||
|
[`[DocViewer] Error preparing document 'qux': ${error}`],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -153,8 +153,9 @@ export class DocViewerComponent implements DoCheck, OnDestroy {
|
|||||||
.switchMap(() => this.swapViews(addTitleAndToc))
|
.switchMap(() => this.swapViews(addTitleAndToc))
|
||||||
.do(() => this.docRendered.emit())
|
.do(() => this.docRendered.emit())
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
|
const errorMessage = (err instanceof Error) ? err.stack : err;
|
||||||
|
this.logger.error(`[DocViewer] Error preparing document '${doc.id}': ${errorMessage}`);
|
||||||
this.nextViewContainer.innerHTML = '';
|
this.nextViewContainer.innerHTML = '';
|
||||||
this.logger.error(`[DocViewer]: Error preparing document '${doc.id}'.`, err);
|
|
||||||
return this.void$;
|
return this.void$;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Powered by Google ©2010-2017.
|
Powered by Google ©2010-2018.
|
||||||
Code licensed under an <a href="license" title="License text" >MIT-style License</a>.
|
Code licensed under an <a href="license" title="License text" >MIT-style License</a>.
|
||||||
Documentation licensed under
|
Documentation licensed under
|
||||||
<a href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.
|
<a href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.
|
||||||
|
@ -11,8 +11,9 @@ interface StringMap { [index: string]: string; }
|
|||||||
export function getAttrs(el: HTMLElement | ElementRef): StringMap {
|
export function getAttrs(el: HTMLElement | ElementRef): StringMap {
|
||||||
const attrs: NamedNodeMap = el instanceof ElementRef ? el.nativeElement.attributes : el.attributes;
|
const attrs: NamedNodeMap = el instanceof ElementRef ? el.nativeElement.attributes : el.attributes;
|
||||||
const attrMap = {};
|
const attrMap = {};
|
||||||
Object.keys(attrs).forEach(key =>
|
for (const attr of attrs as any /* cast due to https://github.com/Microsoft/TypeScript/issues/2695 */) {
|
||||||
attrMap[(attrs[key] as Attr).name.toLowerCase()] = (attrs[key] as Attr).value);
|
attrMap[attr.name.toLowerCase()] = attr.value;
|
||||||
|
}
|
||||||
return attrMap;
|
return attrMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,11 @@ exports.config = {
|
|||||||
'./e2e/**/*.e2e-spec.ts'
|
'./e2e/**/*.e2e-spec.ts'
|
||||||
],
|
],
|
||||||
capabilities: {
|
capabilities: {
|
||||||
'browserName': 'chrome'
|
'browserName': 'chrome',
|
||||||
|
// For Travis CI only
|
||||||
|
chromeOptions: {
|
||||||
|
binary: process.env.CHROME_BIN
|
||||||
|
}
|
||||||
},
|
},
|
||||||
directConnect: true,
|
directConnect: true,
|
||||||
baseUrl: 'http://localhost:4200/',
|
baseUrl: 'http://localhost:4200/',
|
||||||
|
@ -45,7 +45,7 @@ class PlunkerBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_buildCopyrightStrings() {
|
_buildCopyrightStrings() {
|
||||||
var copyright = 'Copyright 2017 Google Inc. All Rights Reserved.\n'
|
var copyright = 'Copyright 2017-2018 Google Inc. All Rights Reserved.\n'
|
||||||
+ 'Use of this source code is governed by an MIT-style license that\n'
|
+ 'Use of this source code is governed by an MIT-style license that\n'
|
||||||
+ 'can be found in the LICENSE file at http://angular.io/license';
|
+ 'can be found in the LICENSE file at http://angular.io/license';
|
||||||
var pad = '\n\n';
|
var pad = '\n\n';
|
||||||
@ -152,6 +152,7 @@ class PlunkerBuilder {
|
|||||||
// Matches main.ts or main.1.ts
|
// Matches main.ts or main.1.ts
|
||||||
if (/^main(?:[.-]\w+)?\.ts$/.test(relativeFileName)) {
|
if (/^main(?:[.-]\w+)?\.ts$/.test(relativeFileName)) {
|
||||||
content = fileTranslator.translate(content, mainTsRules);
|
content = fileTranslator.translate(content, mainTsRules);
|
||||||
|
relativeFileName = 'main.ts';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (relativeFileName == 'systemjs.config.extras.js') {
|
if (relativeFileName == 'systemjs.config.extras.js') {
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Use this tag to ensure that dgeni does not include this code item
|
||||||
|
* in the rendered docs.
|
||||||
|
*
|
||||||
|
* The `@internal` tag indicates to the compiler not to include the
|
||||||
|
* item in the public typings file.
|
||||||
|
* Use the `@nodoc` alias if you only want to hide the item from the
|
||||||
|
* docs but not from the typings file.
|
||||||
|
*/
|
||||||
module.exports = function() {
|
module.exports = function() {
|
||||||
return {
|
return {
|
||||||
name: 'internal', transforms: function() { return true; }
|
name: 'internal',
|
||||||
|
aliases: ['nodoc'],
|
||||||
|
transforms: function() { return true; }
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -9424,10 +9424,10 @@ zip-stream@~0.6.0:
|
|||||||
lodash "~3.10.1"
|
lodash "~3.10.1"
|
||||||
readable-stream "~1.0.26"
|
readable-stream "~1.0.26"
|
||||||
|
|
||||||
zone.js@0.8.16:
|
|
||||||
version "0.8.16"
|
|
||||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.16.tgz#ac31b6c418f88c0f918ad6acd8a402aca9313abb"
|
|
||||||
|
|
||||||
zone.js@^0.8.14:
|
zone.js@^0.8.14:
|
||||||
version "0.8.18"
|
version "0.8.18"
|
||||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.18.tgz#8cecb3977fcd1b3090562ff4570e2847e752b48d"
|
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.18.tgz#8cecb3977fcd1b3090562ff4570e2847e752b48d"
|
||||||
|
|
||||||
|
zone.js@^0.8.19:
|
||||||
|
version "0.8.19"
|
||||||
|
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.19.tgz#a4b522cd9e8b7b616a638c297d720d4c7f292f71"
|
||||||
|
2
build.sh
2
build.sh
@ -206,7 +206,7 @@ minify() {
|
|||||||
base_file=$( basename "${file}" )
|
base_file=$( basename "${file}" )
|
||||||
if [[ "${base_file}" =~ $regex && "${base_file##*.}" != "map" ]]; then
|
if [[ "${base_file}" =~ $regex && "${base_file##*.}" != "map" ]]; then
|
||||||
local out_file=$(dirname "${file}")/${BASH_REMATCH[1]}.min.js
|
local out_file=$(dirname "${file}")/${BASH_REMATCH[1]}.min.js
|
||||||
$UGLIFYJS -c --screw-ie8 --comments -o ${out_file} --source-map ${out_file}.map --source-map-include-sources ${file}
|
$UGLIFYJS -c --screw-ie8 --comments -o ${out_file} --source-map ${out_file}.map --prefix relative --source-map-include-sources ${file}
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
@ -7,30 +7,11 @@ Caretaker is responsible for merging PRs into the individual branches and intern
|
|||||||
- Draining the queue of PRs ready to be merged. (PRs with [`PR action: merge`](https://github.com/angular/angular/pulls?q=is%3Aopen+is%3Apr+label%3A%22PR+action%3A+merge%22) label)
|
- Draining the queue of PRs ready to be merged. (PRs with [`PR action: merge`](https://github.com/angular/angular/pulls?q=is%3Aopen+is%3Apr+label%3A%22PR+action%3A+merge%22) label)
|
||||||
- Assigining [new issues](https://github.com/angular/angular/issues?q=is%3Aopen+is%3Aissue+no%3Alabel) to individual component authors.
|
- Assigining [new issues](https://github.com/angular/angular/issues?q=is%3Aopen+is%3Aissue+no%3Alabel) to individual component authors.
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
### Set `upstream` to fetch PRs into your local repo
|
|
||||||
|
|
||||||
Use this conmmands to configure your `git` to fetch PRs into your local repo.
|
|
||||||
|
|
||||||
```
|
|
||||||
git remote add upstream git@github.com:angular/angular.git
|
|
||||||
git config --add remote.upstream.fetch +refs/pull/*/head:refs/remotes/upstream/pr/*
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Merging the PR
|
## Merging the PR
|
||||||
|
|
||||||
A PR needs to have `PR action: merge` and `PR target: *` labels to be considered
|
A PR needs to have `PR action: merge` and `PR target: *` labels to be considered
|
||||||
ready to merge. Merging is performed by running `merge-pr` with a PR number to merge.
|
ready to merge. Merging is performed by running `merge-pr` with a PR number to merge.
|
||||||
|
|
||||||
NOTE: before running `merge-pr` ensure that you have synced all of the PRs
|
|
||||||
locally by running:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ git fetch upstream
|
|
||||||
```
|
|
||||||
|
|
||||||
To merge a PR run:
|
To merge a PR run:
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -40,6 +21,7 @@ $ ./scripts/github/merge-pr 1234
|
|||||||
The `merge-pr` script will:
|
The `merge-pr` script will:
|
||||||
- Ensure that all approriate labels are on the PR.
|
- Ensure that all approriate labels are on the PR.
|
||||||
- That the current branch (`master` or `?.?.x` patch) mathches the `PR target: *` label.
|
- That the current branch (`master` or `?.?.x` patch) mathches the `PR target: *` label.
|
||||||
|
- Fetches the latest PR code from the `angular/angular` repo.
|
||||||
- It will `cherry-pick` all of the SHAs from the PR into the current branch.
|
- It will `cherry-pick` all of the SHAs from the PR into the current branch.
|
||||||
- It will rewrite commit history by automatically adding `Close #1234` and `(#1234)` into the commit message.
|
- It will rewrite commit history by automatically adding `Close #1234` and `(#1234)` into the commit message.
|
||||||
|
|
||||||
@ -53,8 +35,8 @@ $ ./scripts/github/merge-pr 1234
|
|||||||
======================
|
======================
|
||||||
GitHub Merge PR Steps
|
GitHub Merge PR Steps
|
||||||
======================
|
======================
|
||||||
git cherry-pick upstream/pr/1234~1..upstream/pr/1234
|
git cherry-pick angular/pr/1234~1..angular/pr/1234
|
||||||
git filter-branch -f --msg-filter "/usr/local/google/home/misko/angular-pr/scripts/github/utils/github.closes 1234" HEAD~1..HEAD
|
git filter-branch -f --msg-filter "/home/misko/angular/scripts/github/utils/github.closes 1234" HEAD~1..HEAD
|
||||||
```
|
```
|
||||||
|
|
||||||
If the `cherry-pick` command fails than resolve conflicts and use `git cherry-pick --continue` once ready. After the `cherry-pick` is done cut&paste and run the `filter-branch` command to properly rewrite the messages
|
If the `cherry-pick` command fails than resolve conflicts and use `git cherry-pick --continue` once ready. After the `cherry-pick` is done cut&paste and run the `filter-branch` command to properly rewrite the messages
|
||||||
|
@ -17,7 +17,7 @@ In such case, we'll update this document accordingly.
|
|||||||
|
|
||||||
The dates are just a guidance and might be adjusted slightly if necessary.
|
The dates are just a guidance and might be adjusted slightly if necessary.
|
||||||
|
|
||||||
## Tentative Schedule Until December 2017
|
## Tentative Schedule Until September 2017
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
The table below is formatted so that it's easy to read and edit in both markdown and rendered html form.
|
The table below is formatted so that it's easy to read and edit in both markdown and rendered html form.
|
||||||
@ -25,54 +25,43 @@ The table below is formatted so that it's easy to read and edit in both markdown
|
|||||||
In order to deal with undesirable line breaks, two special characters are occasionally used:
|
In order to deal with undesirable line breaks, two special characters are occasionally used:
|
||||||
|
|
||||||
- non-breaking hyphen: "‑" http://www.fileformat.info/info/unicode/char/2011/index.htm
|
- non-breaking hyphen: "‑" http://www.fileformat.info/info/unicode/char/2011/index.htm
|
||||||
- non-breaking space: " " http://www.fileformat.info/info/unicode/char/00a0/index.htm
|
- non-breaking space: " " http://www.fileformat.info/info/unicode/char/00a0/index.htm
|
||||||
|
|
||||||
If you see undesirable wrapping issues in the rendered form, please copy&paste the quoted characters and use them in the table below where needed.
|
If you see undesirable wrapping issues in the rendered form, please copy&paste the quoted characters and use them in the table below where needed.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
Week Of | Stable Release<br>(@latest npm tag) | Beta/RC Release<br>(@next npm tag) | Note
|
Week Of | Stable Release<br>(@latest npm tag) | Beta/RC Release<br>(@next npm tag) | Note
|
||||||
------------- | ----------------------------------- | ---------------------------------- | ---------------------
|
------------- | ----------------------------------- | ---------------------------------- | ---------------------
|
||||||
2017‑05‑01 | 4.1.1 | 4.2.0‑beta.0 |
|
2017‑05‑01 | 4.1.1 | 4.2.0‑beta.0 |
|
||||||
2017‑05‑08 | 4.1.2 | 4.2.0‑beta.1 |
|
2017‑05‑08 | 4.1.2 | 4.2.0‑beta.1 |
|
||||||
2017‑05‑15 | 4.1.3 | 4.2.0‑rc.0 |
|
2017‑05‑15 | 4.1.3 | 4.2.0‑rc.0 |
|
||||||
2017‑05‑26 | ‑ | 4.2.0‑rc.1 |
|
2017‑05‑26 | ‑ | 4.2.0‑rc.1 |
|
||||||
2017‑06‑01 | ‑ | 4.2.0‑rc.2 |
|
2017‑06‑01 | ‑ | 4.2.0‑rc.2 |
|
||||||
2017‑06‑05 | 4.2.0 | ‑ | Minor Version Release
|
2017‑06‑05 | 4.2.0 | ‑ | Minor Version Release
|
||||||
*2017‑06‑09* | 4.2.1 | ‑ | *Regression Patch Release*
|
*2017‑06‑09* | 4.2.1 | ‑ | *Regression Patch Release*
|
||||||
2017-06-12 | 4.2.2 | ‑ |
|
2017-06-12 | 4.2.2 | ‑ |
|
||||||
*2017-06-16* | 4.2.3 | ‑ | *Regression Patch Release*
|
*2017-06-16* | 4.2.3 | ‑ | *Regression Patch Release*
|
||||||
2017‑06‑19 | 4.2.4 | 4.3.0‑beta.0 |
|
2017‑06‑19 | 4.2.4 | 4.3.0‑beta.0 |
|
||||||
2017‑06‑26 | 4.2.5 | 4.3.0‑beta.1 |
|
2017‑06‑26 | 4.2.5 | 4.3.0‑beta.1 |
|
||||||
2017‑07‑03 | 4.2.6 | 4.3.0‑rc.0 |
|
2017‑07‑03 | 4.2.6 | 4.3.0‑rc.0 |
|
||||||
2017‑07‑10 | 4.3.0 | - | Minor Version Release
|
2017‑07‑10 | 4.3.0 | - | Minor Version Release
|
||||||
2017‑07‑17 | 4.3.1 | 5.0.0‑beta.0 |
|
2017‑07‑17 | 4.3.1 | 5.0.0‑beta.0 |
|
||||||
2017‑07‑24 | 4.3.2 | 5.0.0‑beta.1 |
|
2017‑07‑24 | 4.3.2 | 5.0.0‑beta.1 |
|
||||||
2017‑07‑31 | 4.3.3 | 5.0.0‑beta.2 |
|
2017‑07‑31 | 4.3.3 | 5.0.0‑beta.2 |
|
||||||
2017‑08‑07 | 4.3.4 | 5.0.0‑beta.3 |
|
2017‑08‑07 | 4.3.4 | 5.0.0‑beta.3 |
|
||||||
2017‑08‑14 | 4.3.5 | 5.0.0‑beta.4 |
|
2017‑08‑14 | 4.3.5 | 5.0.0‑beta.4 |
|
||||||
2017‑08‑21 | 4.3.6 | - |
|
2017‑08‑21 | 4.3.6 | - |
|
||||||
2017‑08‑28 | - | 5.0.0‑beta.5 |
|
2017‑08‑28 | - | 5.0.0‑beta.5 |
|
||||||
2017‑09‑04 | - | 5.0.0‑beta.6 |
|
2017‑09‑04 | - | 5.0.0‑beta.6 |
|
||||||
2017‑09‑11 | 4.4.0 | 5.0.0-beta.7 |
|
2017‑09‑11 | 4.4.0 | 5.0.0-beta.7 |
|
||||||
2017‑09‑18 | 4.4.1 | 5.0.0‑beta.8 |
|
2017‑09‑18 | 4.4.1 | 5.0.0‑beta.8 |
|
||||||
2017‑09‑25 | 4.4.2 | 5.0.0‑rc.0 |
|
2017‑09‑25 | 4.4.2 | 5.0.0‑rc.0 |
|
||||||
2017‑10‑02 | 4.4.3 | 5.0.0‑rc.1 |
|
2017‑10‑02 | 4.4.3 | 5.0.0‑rc.1 |
|
||||||
2017‑10‑09 | 4.4.4 | 5.0.0‑rc.2 |
|
2017‑10‑09 | 4.4.4 | 5.0.0‑rc.2 |
|
||||||
2017‑10‑16 | 4.4.5 | 5.0.0‑rc.3 |
|
2017‑10‑16 | 4.4.5 | 5.0.0‑rc.3 |
|
||||||
2017‑11-01 | 5.0.0 | ‑ | Major Version Release
|
2017‑10‑23 | 5.0.0 | ‑ | Major Version Release
|
||||||
2017-11-08 | 5.0.1 | 5.1.0.Beta.0 | *Regression Patch Release*
|
|
||||||
2017-11-16 | 5.0.2 | 5.1.0.Beta.1 | *Regression Patch Release*
|
|
||||||
2017-11-22 | 5.0.3 | 5.1.0.beta.2 | *Regression Patch Release*
|
|
||||||
2017-11-30 | 5.0.4 | 5.1.0.rc.0 |
|
|
||||||
2017-12-01 | 5.0.5 | 5.1.0.rc.1 |
|
|
||||||
2017-12-06 | 5.1.0 | | Minor Version Release
|
|
||||||
2017-12-13 | 5.1.1 | 5.2.0.beta.0 |
|
|
||||||
2017-12-20 | 5.1.2 | |
|
|
||||||
|
|
||||||
|
## Tentative Schedule After September 2017
|
||||||
|
|
||||||
|
|
||||||
## Tentative Schedule After December 2017
|
|
||||||
|
|
||||||
Date | Stable Release | Compatibility`*`
|
Date | Stable Release | Compatibility`*`
|
||||||
---------------------- | -------------- | ----------------
|
---------------------- | -------------- | ----------------
|
||||||
|
@ -1,4 +1,34 @@
|
|||||||
{
|
{
|
||||||
"cli-hello-world":{"master":{"gzip7":{"inline":847,"main":42533,"polyfills":20207},"gzip9":{"inline":847,"main":42483,"polyfills":20204},"uncompressed":{"inline":1447,"main":154295,"polyfills":61254}}},
|
"cli-hello-world": {
|
||||||
"hello_world__closure":{"master":{"gzip7":{"bundle":32793},"gzip9":{"bundle":32758},"uncompressed":{"bundle":100661}}}
|
"master": {
|
||||||
|
"gzip7": {
|
||||||
|
"inline": 847,
|
||||||
|
"main": 41943,
|
||||||
|
"polyfills": 20207
|
||||||
|
},
|
||||||
|
"gzip9": {
|
||||||
|
"inline": 847,
|
||||||
|
"main": 41874,
|
||||||
|
"polyfills": 20204
|
||||||
|
},
|
||||||
|
"uncompressed": {
|
||||||
|
"inline": 1447,
|
||||||
|
"main": 151849,
|
||||||
|
"polyfills": 61254
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hello_world__closure": {
|
||||||
|
"master": {
|
||||||
|
"gzip7": {
|
||||||
|
"bundle": 32793
|
||||||
|
},
|
||||||
|
"gzip9": {
|
||||||
|
"bundle": 32758
|
||||||
|
},
|
||||||
|
"uncompressed": {
|
||||||
|
"bundle": 100661
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ node_repositories(package_json = ["//:package.json"])
|
|||||||
git_repository(
|
git_repository(
|
||||||
name = "build_bazel_rules_typescript",
|
name = "build_bazel_rules_typescript",
|
||||||
remote = "https://github.com/bazelbuild/rules_typescript.git",
|
remote = "https://github.com/bazelbuild/rules_typescript.git",
|
||||||
tag = "0.6.0",
|
tag = "0.6.2",
|
||||||
)
|
)
|
||||||
|
|
||||||
load("@build_bazel_rules_typescript//:defs.bzl", "ts_repositories")
|
load("@build_bazel_rules_typescript//:defs.bzl", "ts_repositories")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "angular-srcs",
|
"name": "angular-srcs",
|
||||||
"version": "5.2.0-beta.1",
|
"version": "5.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"branchPattern": "2.0.*",
|
"branchPattern": "2.0.*",
|
||||||
"description": "Angular - a web framework for modern web apps",
|
"description": "Angular - a web framework for modern web apps",
|
||||||
@ -16,7 +16,10 @@
|
|||||||
"url": "https://github.com/angular/angular.git"
|
"url": "https://github.com/angular/angular.git"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"buildifier": "bazel build @com_github_bazelbuild_buildtools//buildifier && find . -type f \\( -name BUILD -or -name BUILD.bazel \\) ! -path \"*/node_modules/*\" | xargs $(bazel info bazel-bin)/external/com_github_bazelbuild_buildtools/buildifier/buildifier",
|
"preskylint": "bazel build --noshow_progress @io_bazel//src/tools/skylark/java/com/google/devtools/skylark/skylint:Skylint",
|
||||||
|
"skylint": "find . -type f -name \"*.bzl\" ! -path \"*/node_modules/*\" ! -path \"./dist/*\" | xargs $(bazel info bazel-bin)/external/io_bazel/src/tools/skylark/java/com/google/devtools/skylark/skylint/Skylint",
|
||||||
|
"prebuildifier": "bazel build --noshow_progress @com_github_bazelbuild_buildtools//buildifier",
|
||||||
|
"buildifier": "find . -type f \\( -name BUILD -or -name BUILD.bazel \\) ! -path \"*/node_modules/*\" | xargs $(bazel info bazel-bin)/external/com_github_bazelbuild_buildtools/buildifier/buildifier",
|
||||||
"preinstall": "node -e \"if(process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Please use Yarn instead of NPM to install dependencies. See: https://yarnpkg.com/lang/en/docs/install/')\"",
|
"preinstall": "node -e \"if(process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Please use Yarn instead of NPM to install dependencies. See: https://yarnpkg.com/lang/en/docs/install/')\"",
|
||||||
"postinstall": "yarn update-webdriver",
|
"postinstall": "yarn update-webdriver",
|
||||||
"update-webdriver": "webdriver-manager update --gecko false $CHROMEDRIVER_VERSION_ARG",
|
"update-webdriver": "webdriver-manager update --gecko false $CHROMEDRIVER_VERSION_ARG",
|
||||||
|
@ -1393,10 +1393,10 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
|
|||||||
|
|
||||||
public markedForDestroy: boolean = false;
|
public markedForDestroy: boolean = false;
|
||||||
|
|
||||||
readonly queued: boolean = true;
|
|
||||||
|
|
||||||
constructor(public namespaceId: string, public triggerName: string, public element: any) {}
|
constructor(public namespaceId: string, public triggerName: string, public element: any) {}
|
||||||
|
|
||||||
|
get queued() { return this._containsRealPlayer == false; }
|
||||||
|
|
||||||
setRealPlayer(player: AnimationPlayer) {
|
setRealPlayer(player: AnimationPlayer) {
|
||||||
if (this._containsRealPlayer) return;
|
if (this._containsRealPlayer) return;
|
||||||
|
|
||||||
@ -1407,7 +1407,6 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
|
|||||||
});
|
});
|
||||||
this._queuedCallbacks = {};
|
this._queuedCallbacks = {};
|
||||||
this._containsRealPlayer = true;
|
this._containsRealPlayer = true;
|
||||||
(this as{queued: boolean}).queued = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getRealPlayer() { return this._player; }
|
getRealPlayer() { return this._player; }
|
||||||
|
@ -6,7 +6,15 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface DOMAnimation {
|
/**
|
||||||
|
* DOMAnimation represents the Animation Web API.
|
||||||
|
*
|
||||||
|
* It is an external API by the browser, and must thus use "declare interface",
|
||||||
|
* to prevent renaming by Closure Compiler.
|
||||||
|
*
|
||||||
|
* @see https://developer.mozilla.org/de/docs/Web/API/Animation
|
||||||
|
*/
|
||||||
|
export declare interface DOMAnimation {
|
||||||
cancel(): void;
|
cancel(): void;
|
||||||
play(): void;
|
play(): void;
|
||||||
pause(): void;
|
pause(): void;
|
||||||
|
@ -115,7 +115,7 @@ export interface AnimationStateMetadata extends AnimationMetadata {
|
|||||||
* @experimental Animation support is experimental.
|
* @experimental Animation support is experimental.
|
||||||
*/
|
*/
|
||||||
export interface AnimationTransitionMetadata extends AnimationMetadata {
|
export interface AnimationTransitionMetadata extends AnimationMetadata {
|
||||||
expr: string|((fromState: string, toState: string) => boolean);
|
expr: string;
|
||||||
animation: AnimationMetadata|AnimationMetadata[];
|
animation: AnimationMetadata|AnimationMetadata[];
|
||||||
options: AnimationOptions|null;
|
options: AnimationOptions|null;
|
||||||
}
|
}
|
||||||
@ -836,8 +836,7 @@ export function keyframes(steps: AnimationStyleMetadata[]): AnimationKeyframesSe
|
|||||||
* @experimental Animation support is experimental.
|
* @experimental Animation support is experimental.
|
||||||
*/
|
*/
|
||||||
export function transition(
|
export function transition(
|
||||||
stateChangeExpr: string | ((fromState: string, toState: string) => boolean),
|
stateChangeExpr: string, steps: AnimationMetadata | AnimationMetadata[],
|
||||||
steps: AnimationMetadata | AnimationMetadata[],
|
|
||||||
options: AnimationOptions | null = null): AnimationTransitionMetadata {
|
options: AnimationOptions | null = null): AnimationTransitionMetadata {
|
||||||
return {type: AnimationMetadataType.Transition, expr: stateChangeExpr, animation: steps, options};
|
return {type: AnimationMetadataType.Transition, expr: stateChangeExpr, animation: steps, options};
|
||||||
}
|
}
|
||||||
|
@ -33,17 +33,17 @@ export class AnimationGroupPlayer implements AnimationPlayer {
|
|||||||
} else {
|
} else {
|
||||||
this.players.forEach(player => {
|
this.players.forEach(player => {
|
||||||
player.onDone(() => {
|
player.onDone(() => {
|
||||||
if (++doneCount >= total) {
|
if (++doneCount == total) {
|
||||||
this._onFinish();
|
this._onFinish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
player.onDestroy(() => {
|
player.onDestroy(() => {
|
||||||
if (++destroyCount >= total) {
|
if (++destroyCount == total) {
|
||||||
this._onDestroy();
|
this._onDestroy();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
player.onStart(() => {
|
player.onStart(() => {
|
||||||
if (++startCount >= total) {
|
if (++startCount == total) {
|
||||||
this._onStart();
|
this._onStart();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -67,9 +67,9 @@ export class AnimationGroupPlayer implements AnimationPlayer {
|
|||||||
|
|
||||||
private _onStart() {
|
private _onStart() {
|
||||||
if (!this.hasStarted()) {
|
if (!this.hasStarted()) {
|
||||||
|
this._started = true;
|
||||||
this._onStartFns.forEach(fn => fn());
|
this._onStartFns.forEach(fn => fn());
|
||||||
this._onStartFns = [];
|
this._onStartFns = [];
|
||||||
this._started = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
# Use of this source code is governed by an MIT-style license that can be
|
# Use of this source code is governed by an MIT-style license that can be
|
||||||
# found in the LICENSE file at https://angular.io/license
|
# found in the LICENSE file at https://angular.io/license
|
||||||
""" Public API surface is re-exported here.
|
""" Public API surface is re-exported here.
|
||||||
|
|
||||||
Users should not load files under "/src"
|
Users should not load files under "/src"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
load("//src:ng_module.bzl", "ng_module")
|
load("//src:ng_module.bzl", _ng_module = "ng_module")
|
||||||
|
|
||||||
|
ng_module = _ng_module
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
#
|
#
|
||||||
# Use of this source code is governed by an MIT-style license that can be
|
# Use of this source code is governed by an MIT-style license that can be
|
||||||
# found in the LICENSE file at https://angular.io/license
|
# found in the LICENSE file at https://angular.io/license
|
||||||
|
"""Implementation of the ng_module rule.
|
||||||
|
"""
|
||||||
|
|
||||||
load(":rules_typescript.bzl",
|
load(":rules_typescript.bzl",
|
||||||
"tsc_wrapped_tsconfig",
|
"tsc_wrapped_tsconfig",
|
||||||
@ -10,20 +12,17 @@ load(":rules_typescript.bzl",
|
|||||||
"compile_ts",
|
"compile_ts",
|
||||||
"DEPS_ASPECTS",
|
"DEPS_ASPECTS",
|
||||||
"ts_providers_dict_to_struct",
|
"ts_providers_dict_to_struct",
|
||||||
"json_marshal",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Calculate the expected output of the template compiler for every source in
|
# Calculate the expected output of the template compiler for every source in
|
||||||
# in the library. Most of these will be produced as empty files but it is
|
# in the library. Most of these will be produced as empty files but it is
|
||||||
# unknown, without parsing, which will be empty.
|
# unknown, without parsing, which will be empty.
|
||||||
def _expected_outs(ctx, label):
|
def _expected_outs(ctx):
|
||||||
devmode_js_files = []
|
devmode_js_files = []
|
||||||
closure_js_files = []
|
closure_js_files = []
|
||||||
declaration_files = []
|
declaration_files = []
|
||||||
summary_files = []
|
summary_files = []
|
||||||
|
|
||||||
codegen_inputs = ctx.files.srcs
|
|
||||||
|
|
||||||
for src in ctx.files.srcs + ctx.files.assets:
|
for src in ctx.files.srcs + ctx.files.assets:
|
||||||
if src.short_path.endswith(".ts") and not src.short_path.endswith(".d.ts"):
|
if src.short_path.endswith(".ts") and not src.short_path.endswith(".d.ts"):
|
||||||
basename = src.short_path[len(ctx.label.package) + 1:-len(".ts")]
|
basename = src.short_path[len(ctx.label.package) + 1:-len(".ts")]
|
||||||
@ -42,6 +41,9 @@ def _expected_outs(ctx, label):
|
|||||||
]
|
]
|
||||||
summaries = []
|
summaries = []
|
||||||
|
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
closure_js = [f.replace(".js", ".closure.js") for f in devmode_js]
|
closure_js = [f.replace(".js", ".closure.js") for f in devmode_js]
|
||||||
declarations = [f.replace(".js", ".d.ts") for f in devmode_js]
|
declarations = [f.replace(".js", ".d.ts") for f in devmode_js]
|
||||||
|
|
||||||
@ -61,7 +63,7 @@ def _expected_outs(ctx, label):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _ngc_tsconfig(ctx, files, srcs, **kwargs):
|
def _ngc_tsconfig(ctx, files, srcs, **kwargs):
|
||||||
outs = _expected_outs(ctx, ctx.label)
|
outs = _expected_outs(ctx)
|
||||||
if "devmode_manifest" in kwargs:
|
if "devmode_manifest" in kwargs:
|
||||||
expected_outs = outs.devmode_js + outs.declarations + outs.summaries
|
expected_outs = outs.devmode_js + outs.declarations + outs.summaries
|
||||||
else:
|
else:
|
||||||
@ -79,7 +81,7 @@ def _ngc_tsconfig(ctx, files, srcs, **kwargs):
|
|||||||
})
|
})
|
||||||
|
|
||||||
def _collect_summaries_aspect_impl(target, ctx):
|
def _collect_summaries_aspect_impl(target, ctx):
|
||||||
results = target.angular.summaries if hasattr(target, "angular") else depset()
|
results = depset(target.angular.summaries if hasattr(target, "angular") else [])
|
||||||
|
|
||||||
# If we are visiting empty-srcs ts_library, this is a re-export
|
# If we are visiting empty-srcs ts_library, this is a re-export
|
||||||
srcs = ctx.rule.attr.srcs if hasattr(ctx.rule.attr, "srcs") else []
|
srcs = ctx.rule.attr.srcs if hasattr(ctx.rule.attr, "srcs") else []
|
||||||
@ -88,7 +90,7 @@ def _collect_summaries_aspect_impl(target, ctx):
|
|||||||
if not srcs:
|
if not srcs:
|
||||||
for dep in ctx.rule.attr.deps:
|
for dep in ctx.rule.attr.deps:
|
||||||
if (hasattr(dep, "angular")):
|
if (hasattr(dep, "angular")):
|
||||||
results += dep.angular.summaries
|
results = depset(dep.angular.summaries, transitive = [results])
|
||||||
|
|
||||||
return struct(collect_summaries_aspect_result = results)
|
return struct(collect_summaries_aspect_result = results)
|
||||||
|
|
||||||
@ -105,9 +107,28 @@ _EXTRA_NODE_OPTIONS_FLAGS = [
|
|||||||
|
|
||||||
def ngc_compile_action(ctx, label, inputs, outputs, messages_out, config_file_path,
|
def ngc_compile_action(ctx, label, inputs, outputs, messages_out, config_file_path,
|
||||||
locale=None, i18n_args=[]):
|
locale=None, i18n_args=[]):
|
||||||
|
"""Helper function to create the ngc action.
|
||||||
|
|
||||||
|
This is exposed for google3 to wire up i18n replay rules, and is not intended
|
||||||
|
as part of the public API.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ctx: skylark context
|
||||||
|
label: the label of the ng_module being compiled
|
||||||
|
inputs: passed to the ngc action's inputs
|
||||||
|
outputs: passed to the ngc action's outputs
|
||||||
|
messages_out: produced xmb files
|
||||||
|
config_file_path: path to the tsconfig file
|
||||||
|
locale: i18n locale, or None
|
||||||
|
i18n_args: additional command-line arguments to ngc
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
the parameters of the compilation which will be used to replay the ngc action for i18N.
|
||||||
|
"""
|
||||||
|
|
||||||
mnemonic = "AngularTemplateCompile"
|
mnemonic = "AngularTemplateCompile"
|
||||||
progress_message = "Compiling Angular templates (ngc) %s" % label
|
progress_message = "Compiling Angular templates (ngc) %s" % label
|
||||||
supports_workers = "0"
|
|
||||||
if locale:
|
if locale:
|
||||||
mnemonic = "AngularI18NMerging"
|
mnemonic = "AngularI18NMerging"
|
||||||
supports_workers = "0"
|
supports_workers = "0"
|
||||||
@ -152,8 +173,6 @@ def ngc_compile_action(ctx, label, inputs, outputs, messages_out, config_file_pa
|
|||||||
progress_message = "Extracting Angular 2 messages (ng_xi18n)",
|
progress_message = "Extracting Angular 2 messages (ng_xi18n)",
|
||||||
mnemonic = "Angular2MessageExtractor")
|
mnemonic = "Angular2MessageExtractor")
|
||||||
|
|
||||||
# Return the parameters of the compilation which will be used to replay the
|
|
||||||
# ngc action for i18N.
|
|
||||||
if not locale and not ctx.attr.no_i18n:
|
if not locale and not ctx.attr.no_i18n:
|
||||||
return struct(
|
return struct(
|
||||||
label = label,
|
label = label,
|
||||||
@ -162,46 +181,68 @@ def ngc_compile_action(ctx, label, inputs, outputs, messages_out, config_file_pa
|
|||||||
outputs = outputs,
|
outputs = outputs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def _compile_action(ctx, inputs, outputs, messages_out, config_file_path):
|
def _compile_action(ctx, inputs, outputs, messages_out, config_file_path):
|
||||||
summaries = depset()
|
# Give the Angular compiler all the user-listed assets
|
||||||
for dep in ctx.attr.deps:
|
file_inputs = list(ctx.files.assets)
|
||||||
if hasattr(dep, "collect_summaries_aspect_result"):
|
|
||||||
summaries += dep.collect_summaries_aspect_result
|
|
||||||
|
|
||||||
action_inputs = inputs + summaries.to_list() + ctx.files.assets
|
|
||||||
# print("ASSETS", [a.path for a in ctx.files.assets])
|
|
||||||
# print("INPUTS", ctx.label, [o.path for o in summaries if o.path.find("core/src") > 0])
|
|
||||||
|
|
||||||
|
# The compiler only needs to see TypeScript sources from the npm dependencies,
|
||||||
|
# but may need to look at package.json and ngsummary.json files as well.
|
||||||
if hasattr(ctx.attr, "node_modules"):
|
if hasattr(ctx.attr, "node_modules"):
|
||||||
action_inputs += [f for f in ctx.files.node_modules
|
file_inputs += [f for f in ctx.files.node_modules
|
||||||
if f.path.endswith(".ts") or f.path.endswith(".json")]
|
if f.path.endswith(".ts") or f.path.endswith(".json")]
|
||||||
|
|
||||||
|
# If the user supplies a tsconfig.json file, the Angular compiler needs to read it
|
||||||
if hasattr(ctx.attr, "tsconfig") and ctx.file.tsconfig:
|
if hasattr(ctx.attr, "tsconfig") and ctx.file.tsconfig:
|
||||||
action_inputs += [ctx.file.tsconfig]
|
file_inputs.append(ctx.file.tsconfig)
|
||||||
|
|
||||||
|
# Collect the inputs and summary files from our deps
|
||||||
|
action_inputs = depset(file_inputs,
|
||||||
|
transitive = [inputs] + [dep.collect_summaries_aspect_result for dep in ctx.attr.deps
|
||||||
|
if hasattr(dep, "collect_summaries_aspect_result")])
|
||||||
|
|
||||||
return ngc_compile_action(ctx, ctx.label, action_inputs, outputs, messages_out, config_file_path)
|
return ngc_compile_action(ctx, ctx.label, action_inputs, outputs, messages_out, config_file_path)
|
||||||
|
|
||||||
|
|
||||||
def _prodmode_compile_action(ctx, inputs, outputs, config_file_path):
|
def _prodmode_compile_action(ctx, inputs, outputs, config_file_path):
|
||||||
outs = _expected_outs(ctx, ctx.label)
|
outs = _expected_outs(ctx)
|
||||||
return _compile_action(ctx, inputs, outputs + outs.closure_js, outs.i18n_messages, config_file_path)
|
return _compile_action(ctx, inputs, outputs + outs.closure_js, outs.i18n_messages, config_file_path)
|
||||||
|
|
||||||
def _devmode_compile_action(ctx, inputs, outputs, config_file_path):
|
def _devmode_compile_action(ctx, inputs, outputs, config_file_path):
|
||||||
outs = _expected_outs(ctx, ctx.label)
|
outs = _expected_outs(ctx)
|
||||||
_compile_action(ctx, inputs, outputs + outs.devmode_js + outs.declarations + outs.summaries, None, config_file_path)
|
_compile_action(ctx, inputs, outputs + outs.devmode_js + outs.declarations + outs.summaries, None, config_file_path)
|
||||||
|
|
||||||
|
def _ts_expected_outs(ctx, label):
|
||||||
|
# rules_typescript expects a function with two arguments, but our
|
||||||
|
# implementation doesn't use the label
|
||||||
|
_ignored = [label]
|
||||||
|
return _expected_outs(ctx)
|
||||||
|
|
||||||
def ng_module_impl(ctx, ts_compile_actions):
|
def ng_module_impl(ctx, ts_compile_actions):
|
||||||
|
"""Implementation function for the ng_module rule.
|
||||||
|
|
||||||
|
This is exposed so that google3 can have its own entry point that re-uses this
|
||||||
|
and is not meant as a public API.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ctx: the skylark rule context
|
||||||
|
ts_compile_actions: generates all the actions to run an ngc compilation
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
the result of the ng_module rule as a dict, suitable for
|
||||||
|
conversion by ts_providers_dict_to_struct
|
||||||
|
"""
|
||||||
|
|
||||||
providers = ts_compile_actions(
|
providers = ts_compile_actions(
|
||||||
ctx, is_library=True, compile_action=_prodmode_compile_action,
|
ctx, is_library=True, compile_action=_prodmode_compile_action,
|
||||||
devmode_compile_action=_devmode_compile_action,
|
devmode_compile_action=_devmode_compile_action,
|
||||||
tsc_wrapped_tsconfig=_ngc_tsconfig,
|
tsc_wrapped_tsconfig=_ngc_tsconfig,
|
||||||
outputs = _expected_outs)
|
outputs = _ts_expected_outs)
|
||||||
|
|
||||||
#addl_declarations = [_expected_outs(ctx)]
|
outs = _expected_outs(ctx)
|
||||||
#providers["typescript"]["declarations"] += addl_declarations
|
|
||||||
#providers["typescript"]["transitive_declarations"] += addl_declarations
|
|
||||||
outs = _expected_outs(ctx, ctx.label)
|
|
||||||
providers["angular"] = {
|
providers["angular"] = {
|
||||||
"summaries": _expected_outs(ctx, ctx.label).summaries
|
"summaries": _expected_outs(ctx).summaries
|
||||||
}
|
}
|
||||||
providers["ngc_messages"] = outs.i18n_messages
|
providers["ngc_messages"] = outs.i18n_messages
|
||||||
|
|
||||||
@ -240,7 +281,7 @@ NG_MODULE_ATTRIBUTES = {
|
|||||||
|
|
||||||
ng_module = rule(
|
ng_module = rule(
|
||||||
implementation = _ng_module_impl,
|
implementation = _ng_module_impl,
|
||||||
attrs = COMMON_ATTRIBUTES + NG_MODULE_ATTRIBUTES + {
|
attrs = dict(dict(COMMON_ATTRIBUTES, **NG_MODULE_ATTRIBUTES), **{
|
||||||
"tsconfig": attr.label(allow_files = True, single_file = True),
|
"tsconfig": attr.label(allow_files = True, single_file = True),
|
||||||
|
|
||||||
# @// is special syntax for the "main" repository
|
# @// is special syntax for the "main" repository
|
||||||
@ -249,6 +290,6 @@ ng_module = rule(
|
|||||||
"node_modules": attr.label(
|
"node_modules": attr.label(
|
||||||
default = Label("@//:node_modules")
|
default = Label("@//:node_modules")
|
||||||
),
|
),
|
||||||
},
|
}),
|
||||||
outputs = COMMON_OUTPUTS,
|
outputs = COMMON_OUTPUTS,
|
||||||
)
|
)
|
||||||
|
@ -27,6 +27,8 @@ const ALLOW_NON_HERMETIC_READS = true;
|
|||||||
// Note: We compile the content of node_modules with plain ngc command line.
|
// Note: We compile the content of node_modules with plain ngc command line.
|
||||||
const ALL_DEPS_COMPILED_WITH_BAZEL = false;
|
const ALL_DEPS_COMPILED_WITH_BAZEL = false;
|
||||||
|
|
||||||
|
const NODE_MODULES = 'node_modules/';
|
||||||
|
|
||||||
export function main(args) {
|
export function main(args) {
|
||||||
if (runAsWorker(args)) {
|
if (runAsWorker(args)) {
|
||||||
runWorkerLoop(runOneBuild);
|
runWorkerLoop(runOneBuild);
|
||||||
@ -175,7 +177,11 @@ export function compile({allowNonHermeticReads, allDepsCompiledWithBazel = true,
|
|||||||
ngHost.amdModuleName) {
|
ngHost.amdModuleName) {
|
||||||
return ngHost.amdModuleName({ fileName: importedFilePath } as ts.SourceFile);
|
return ngHost.amdModuleName({ fileName: importedFilePath } as ts.SourceFile);
|
||||||
}
|
}
|
||||||
return relativeToRootDirs(importedFilePath, compilerOpts.rootDirs).replace(EXT, '');
|
const result = relativeToRootDirs(importedFilePath, compilerOpts.rootDirs).replace(EXT, '');
|
||||||
|
if (result.startsWith(NODE_MODULES)) {
|
||||||
|
return result.substr(NODE_MODULES.length);
|
||||||
|
}
|
||||||
|
return bazelOpts.workspaceName + '/' + result;
|
||||||
};
|
};
|
||||||
ngHost.toSummaryFileName = (fileName: string, referringSrcFileName: string) =>
|
ngHost.toSummaryFileName = (fileName: string, referringSrcFileName: string) =>
|
||||||
relativeToRootDirs(fileName, compilerOpts.rootDirs).replace(EXT, '');
|
relativeToRootDirs(fileName, compilerOpts.rootDirs).replace(EXT, '');
|
||||||
|
@ -1,12 +1,26 @@
|
|||||||
# Allows different paths for these imports in google3
|
"""Allows different paths for these imports in google3.
|
||||||
load("@build_bazel_rules_typescript//internal:build_defs.bzl", "tsc_wrapped_tsconfig")
|
"""
|
||||||
|
|
||||||
load("@build_bazel_rules_typescript//internal:common/compilation.bzl",
|
load("@build_bazel_rules_typescript//internal:build_defs.bzl",
|
||||||
"COMMON_ATTRIBUTES",
|
_tsc_wrapped_tsconfig = "tsc_wrapped_tsconfig",
|
||||||
"COMMON_OUTPUTS",
|
|
||||||
"compile_ts",
|
|
||||||
"DEPS_ASPECTS",
|
|
||||||
"ts_providers_dict_to_struct",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
load("@build_bazel_rules_typescript//internal:common/json_marshal.bzl", "json_marshal")
|
load("@build_bazel_rules_typescript//internal:common/compilation.bzl",
|
||||||
|
_COMMON_ATTRIBUTES = "COMMON_ATTRIBUTES",
|
||||||
|
_COMMON_OUTPUTS = "COMMON_OUTPUTS",
|
||||||
|
_compile_ts = "compile_ts",
|
||||||
|
_DEPS_ASPECTS = "DEPS_ASPECTS",
|
||||||
|
_ts_providers_dict_to_struct = "ts_providers_dict_to_struct",
|
||||||
|
)
|
||||||
|
|
||||||
|
load("@build_bazel_rules_typescript//internal:common/json_marshal.bzl",
|
||||||
|
_json_marshal = "json_marshal",
|
||||||
|
)
|
||||||
|
|
||||||
|
tsc_wrapped_tsconfig = _tsc_wrapped_tsconfig
|
||||||
|
COMMON_ATTRIBUTES = _COMMON_ATTRIBUTES
|
||||||
|
COMMON_OUTPUTS = _COMMON_OUTPUTS
|
||||||
|
compile_ts = _compile_ts
|
||||||
|
DEPS_ASPECTS = _DEPS_ASPECTS
|
||||||
|
ts_providers_dict_to_struct = _ts_providers_dict_to_struct
|
||||||
|
json_marshal = _json_marshal
|
||||||
|
@ -249,6 +249,9 @@ export class PerflogMetric extends Metric {
|
|||||||
// not all events have been received, no further processing for now
|
// not all events have been received, no further processing for now
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (markStartEvent.pid !== markEndEvent.pid) {
|
||||||
|
result['invalid'] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
let gcTimeInScript = 0;
|
let gcTimeInScript = 0;
|
||||||
let renderTimeInScript = 0;
|
let renderTimeInScript = 0;
|
||||||
|
@ -63,7 +63,12 @@ export class Sampler {
|
|||||||
}
|
}
|
||||||
return resultPromise.then((_) => this._driver.waitFor(this._execute))
|
return resultPromise.then((_) => this._driver.waitFor(this._execute))
|
||||||
.then((_) => this._metric.endMeasure(this._prepare === Options.NO_PREPARE))
|
.then((_) => this._metric.endMeasure(this._prepare === Options.NO_PREPARE))
|
||||||
.then((measureValues) => this._report(lastState, measureValues));
|
.then((measureValues) => {
|
||||||
|
if (!!measureValues['invalid']) {
|
||||||
|
return lastState;
|
||||||
|
}
|
||||||
|
return this._report(lastState, measureValues);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _report(state: SampleState, metricValues: {[key: string]: any}): Promise<SampleState> {
|
private _report(state: SampleState, metricValues: {[key: string]: any}): Promise<SampleState> {
|
||||||
|
@ -34,7 +34,9 @@ export class SeleniumWebDriverAdapter extends WebDriverAdapter {
|
|||||||
capabilities(): Promise<{[key: string]: any}> {
|
capabilities(): Promise<{[key: string]: any}> {
|
||||||
return this._driver.getCapabilities().then((capsObject: any) => {
|
return this._driver.getCapabilities().then((capsObject: any) => {
|
||||||
const localData: {[key: string]: any} = {};
|
const localData: {[key: string]: any} = {};
|
||||||
capsObject.forEach((value: any, key: string) => { localData[key] = value; });
|
for (const key of capsObject.keys()) {
|
||||||
|
localData[key] = capsObject.get(key);
|
||||||
|
}
|
||||||
return localData;
|
return localData;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -537,6 +537,24 @@ export function main() {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should mark a run as invalid if the start and end marks are different',
|
||||||
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||||
|
const otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1');
|
||||||
|
const metric = createMetric(
|
||||||
|
[[
|
||||||
|
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 0, null),
|
||||||
|
eventFactory.end('script', 5, null),
|
||||||
|
otherProcessEventFactory.start('script', 10, null),
|
||||||
|
otherProcessEventFactory.end('script', 17, null),
|
||||||
|
otherProcessEventFactory.markEnd('benchpress0', 20)
|
||||||
|
]],
|
||||||
|
null !);
|
||||||
|
metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => {
|
||||||
|
expect(data['invalid']).toBe(1);
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
it('should support scriptTime metric',
|
it('should support scriptTime metric',
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||||
aggregate([
|
aggregate([
|
||||||
|
@ -23,12 +23,13 @@ export class MockScriptElement {
|
|||||||
|
|
||||||
export class MockDocument {
|
export class MockDocument {
|
||||||
mock: MockScriptElement|null;
|
mock: MockScriptElement|null;
|
||||||
readonly body: any = this;
|
|
||||||
|
|
||||||
createElement(tag: 'script'): HTMLScriptElement {
|
createElement(tag: 'script'): HTMLScriptElement {
|
||||||
return new MockScriptElement() as any as HTMLScriptElement;
|
return new MockScriptElement() as any as HTMLScriptElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get body(): any { return this; }
|
||||||
|
|
||||||
appendChild(node: any): void { this.mock = node; }
|
appendChild(node: any): void { this.mock = node; }
|
||||||
|
|
||||||
removeNode(node: any): void {
|
removeNode(node: any): void {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"declaration": false,
|
"declaration": true,
|
||||||
"stripInternal": true,
|
"stripInternal": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"module": "es2015",
|
"module": "es2015",
|
||||||
|
@ -14,8 +14,7 @@
|
|||||||
export * from './location/index';
|
export * from './location/index';
|
||||||
export {NgLocaleLocalization, NgLocalization} from './i18n/localization';
|
export {NgLocaleLocalization, NgLocalization} from './i18n/localization';
|
||||||
export {registerLocaleData} from './i18n/locale_data';
|
export {registerLocaleData} from './i18n/locale_data';
|
||||||
export {Plural, NumberFormatStyle, FormStyle, Time, TranslationWidth, FormatWidth, NumberSymbol, WeekDay, getLocaleDayPeriods, getLocaleDayNames, getLocaleMonthNames, getLocaleId, getLocaleEraNames, getLocaleWeekEndRange, getLocaleFirstDayOfWeek, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocalePluralCase, getLocaleTimeFormat, getLocaleNumberSymbol, getLocaleNumberFormat, getLocaleCurrencyName, getLocaleCurrencySymbol} from './i18n/locale_data_api';
|
export {Plural, NumberFormatStyle, FormStyle, Time, TranslationWidth, FormatWidth, NumberSymbol, WeekDay, getCurrencySymbol, getLocaleDayPeriods, getLocaleDayNames, getLocaleMonthNames, getLocaleId, getLocaleEraNames, getLocaleWeekEndRange, getLocaleFirstDayOfWeek, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocalePluralCase, getLocaleTimeFormat, getLocaleNumberSymbol, getLocaleNumberFormat, getLocaleCurrencyName, getLocaleCurrencySymbol} from './i18n/locale_data_api';
|
||||||
export {CURRENCIES} from './i18n/currencies';
|
|
||||||
export {parseCookieValue as ɵparseCookieValue} from './cookie';
|
export {parseCookieValue as ɵparseCookieValue} from './cookie';
|
||||||
export {CommonModule, DeprecatedI18NPipesModule} from './common_module';
|
export {CommonModule, DeprecatedI18NPipesModule} from './common_module';
|
||||||
export {NgClass, NgForOf, NgForOfContext, NgIf, NgIfContext, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet, NgComponentOutlet} from './directives/index';
|
export {NgClass, NgForOf, NgForOfContext, NgIf, NgIfContext, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet, NgComponentOutlet} from './directives/index';
|
||||||
|
@ -151,9 +151,6 @@ export class NgIf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
public static ngIfUseIfTypeGuard: void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
// THIS CODE IS GENERATED - DO NOT MODIFY
|
// THIS CODE IS GENERATED - DO NOT MODIFY
|
||||||
// See angular/tools/gulp-tasks/cldr/extract.js
|
// See angular/tools/gulp-tasks/cldr/extract.js
|
||||||
|
|
||||||
/** @experimental */
|
/** @internal */
|
||||||
export const CURRENCIES: {[code: string]: (string | undefined)[]} = {
|
export const CURRENCIES: {[code: string]: (string | undefined)[]} = {
|
||||||
'AOA': [, 'Kz'],
|
'AOA': [, 'Kz'],
|
||||||
'ARS': [, '$'],
|
'ARS': [, '$'],
|
||||||
|
@ -46,11 +46,6 @@ export function formatNumber(
|
|||||||
num = value;
|
num = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (style === NumberFormatStyle.Percent) {
|
|
||||||
num = num * 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
const numStr = Math.abs(num) + '';
|
|
||||||
const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign));
|
const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign));
|
||||||
let formattedText = '';
|
let formattedText = '';
|
||||||
let isZero = false;
|
let isZero = false;
|
||||||
@ -58,7 +53,11 @@ export function formatNumber(
|
|||||||
if (!isFinite(num)) {
|
if (!isFinite(num)) {
|
||||||
formattedText = getLocaleNumberSymbol(locale, NumberSymbol.Infinity);
|
formattedText = getLocaleNumberSymbol(locale, NumberSymbol.Infinity);
|
||||||
} else {
|
} else {
|
||||||
const parsedNumber = parseNumber(numStr);
|
let parsedNumber = parseNumber(num);
|
||||||
|
|
||||||
|
if (style === NumberFormatStyle.Percent) {
|
||||||
|
parsedNumber = toPercent(parsedNumber);
|
||||||
|
}
|
||||||
|
|
||||||
let minInt = pattern.minInt;
|
let minInt = pattern.minInt;
|
||||||
let minFraction = pattern.minFrac;
|
let minFraction = pattern.minFrac;
|
||||||
@ -249,11 +248,35 @@ interface ParsedNumber {
|
|||||||
integerLen: number;
|
integerLen: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transforms a parsed number into a percentage by multiplying it by 100
|
||||||
|
function toPercent(parsedNumber: ParsedNumber): ParsedNumber {
|
||||||
|
// if the number is 0, don't do anything
|
||||||
|
if (parsedNumber.digits[0] === 0) {
|
||||||
|
return parsedNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getting the current number of decimals
|
||||||
|
const fractionLen = parsedNumber.digits.length - parsedNumber.integerLen;
|
||||||
|
if (parsedNumber.exponent) {
|
||||||
|
parsedNumber.exponent += 2;
|
||||||
|
} else {
|
||||||
|
if (fractionLen === 0) {
|
||||||
|
parsedNumber.digits.push(0, 0);
|
||||||
|
} else if (fractionLen === 1) {
|
||||||
|
parsedNumber.digits.push(0);
|
||||||
|
}
|
||||||
|
parsedNumber.integerLen += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedNumber;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a number (as a string)
|
* Parses a number.
|
||||||
* Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/
|
* Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/
|
||||||
*/
|
*/
|
||||||
function parseNumber(numStr: string): ParsedNumber {
|
function parseNumber(num: number): ParsedNumber {
|
||||||
|
let numStr = Math.abs(num) + '';
|
||||||
let exponent = 0, digits, integerLen;
|
let exponent = 0, digits, integerLen;
|
||||||
let i, j, zeros;
|
let i, j, zeros;
|
||||||
|
|
||||||
@ -356,12 +379,23 @@ function roundNumber(parsedNumber: ParsedNumber, minFrac: number, maxFrac: numbe
|
|||||||
// Pad out with zeros to get the required fraction length
|
// Pad out with zeros to get the required fraction length
|
||||||
for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);
|
for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);
|
||||||
|
|
||||||
|
let dropTrailingZeros = fractionSize !== 0;
|
||||||
|
// Minimal length = nb of decimals required + current nb of integers
|
||||||
|
// Any number besides that is optional and can be removed if it's a trailing 0
|
||||||
|
const minLen = minFrac + parsedNumber.integerLen;
|
||||||
// Do any carrying, e.g. a digit was rounded up to 10
|
// Do any carrying, e.g. a digit was rounded up to 10
|
||||||
const carry = digits.reduceRight(function(carry, d, i, digits) {
|
const carry = digits.reduceRight(function(carry, d, i, digits) {
|
||||||
d = d + carry;
|
d = d + carry;
|
||||||
digits[i] = d % 10;
|
digits[i] = d < 10 ? d : d - 10; // d % 10
|
||||||
return Math.floor(d / 10);
|
if (dropTrailingZeros) {
|
||||||
|
// Do not keep meaningless fractional trailing zeros (e.g. 15.52000 --> 15.52)
|
||||||
|
if (digits[i] === 0 && i >= minLen) {
|
||||||
|
digits.pop();
|
||||||
|
} else {
|
||||||
|
dropTrailingZeros = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d >= 10 ? 1 : 0; // Math.floor(d / 10);
|
||||||
}, 0);
|
}, 0);
|
||||||
if (carry) {
|
if (carry) {
|
||||||
digits.unshift(carry);
|
digits.unshift(carry);
|
||||||
|
@ -527,12 +527,17 @@ export function findLocaleData(locale: string): any {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the currency symbol for a given currency code, or the code if no symbol available
|
* Return the currency symbol for a given currency code, or the code if no symbol available
|
||||||
* (e.g.: $, US$, or USD)
|
* (e.g.: format narrow = $, format wide = US$, code = USD)
|
||||||
*
|
*
|
||||||
* @internal
|
* @experimental i18n support is experimental.
|
||||||
*/
|
*/
|
||||||
export function findCurrencySymbol(code: string, format: 'wide' | 'narrow') {
|
export function getCurrencySymbol(code: string, format: 'wide' | 'narrow'): string {
|
||||||
const currency = CURRENCIES[code] || {};
|
const currency = CURRENCIES[code] || [];
|
||||||
const symbol = currency[0] || code;
|
const symbolNarrow = currency[1];
|
||||||
return format === 'wide' ? symbol : currency[1] || symbol;
|
|
||||||
|
if (format === 'narrow' && typeof symbolNarrow === 'string') {
|
||||||
|
return symbolNarrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
return currency[0] || code;
|
||||||
}
|
}
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import {Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core';
|
import {Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core';
|
||||||
import {formatNumber} from '../i18n/format_number';
|
import {formatNumber} from '../i18n/format_number';
|
||||||
import {NumberFormatStyle, findCurrencySymbol, getLocaleCurrencyName, getLocaleCurrencySymbol} from '../i18n/locale_data_api';
|
import {NumberFormatStyle, getCurrencySymbol, getLocaleCurrencyName, getLocaleCurrencySymbol} from '../i18n/locale_data_api';
|
||||||
import {invalidPipeArgumentError} from './invalid_pipe_argument_error';
|
import {invalidPipeArgumentError} from './invalid_pipe_argument_error';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -143,7 +143,7 @@ export class CurrencyPipe implements PipeTransform {
|
|||||||
|
|
||||||
let currency = currencyCode || 'USD';
|
let currency = currencyCode || 'USD';
|
||||||
if (display !== 'code') {
|
if (display !== 'code') {
|
||||||
currency = findCurrencySymbol(currency, display === 'symbol' ? 'wide' : 'narrow');
|
currency = getCurrencySymbol(currency, display === 'symbol' ? 'wide' : 'narrow');
|
||||||
}
|
}
|
||||||
|
|
||||||
const {str, error} = formatNumber(value, locale, NumberFormatStyle.Currency, digits, currency);
|
const {str, error} = formatNumber(value, locale, NumberFormatStyle.Currency, digits, currency);
|
||||||
|
@ -11,7 +11,7 @@ import localeEn from '../../locales/en';
|
|||||||
import localeFr from '../../locales/fr';
|
import localeFr from '../../locales/fr';
|
||||||
import localeFrCA from '../../locales/fr-CA';
|
import localeFrCA from '../../locales/fr-CA';
|
||||||
import {registerLocaleData} from '../../src/i18n/locale_data';
|
import {registerLocaleData} from '../../src/i18n/locale_data';
|
||||||
import {findLocaleData} from '../../src/i18n/locale_data_api';
|
import {findLocaleData, getCurrencySymbol} from '../../src/i18n/locale_data_api';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('locale data api', () => {
|
describe('locale data api', () => {
|
||||||
@ -51,5 +51,18 @@ export function main() {
|
|||||||
expect(findLocaleData('fake-id2')).toEqual(localeFrCA);
|
expect(findLocaleData('fake-id2')).toEqual(localeFrCA);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getCurrencySymbolElseCode', () => {
|
||||||
|
it('should return the correct symbol', () => {
|
||||||
|
expect(getCurrencySymbol('USD', 'wide')).toEqual('$');
|
||||||
|
expect(getCurrencySymbol('USD', 'narrow')).toEqual('$');
|
||||||
|
expect(getCurrencySymbol('AUD', 'wide')).toEqual('A$');
|
||||||
|
expect(getCurrencySymbol('AUD', 'narrow')).toEqual('$');
|
||||||
|
expect(getCurrencySymbol('CRC', 'wide')).toEqual('CRC');
|
||||||
|
expect(getCurrencySymbol('CRC', 'narrow')).toEqual('₡');
|
||||||
|
expect(getCurrencySymbol('FAKE', 'wide')).toEqual('FAKE');
|
||||||
|
expect(getCurrencySymbol('FAKE', 'narrow')).toEqual('FAKE');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,22 @@ export function main() {
|
|||||||
expect(pipe.transform(1.2, '.2')).toEqual('120.00%');
|
expect(pipe.transform(1.2, '.2')).toEqual('120.00%');
|
||||||
expect(pipe.transform(1.2, '4.2')).toEqual('0,120.00%');
|
expect(pipe.transform(1.2, '4.2')).toEqual('0,120.00%');
|
||||||
expect(pipe.transform(1.2, '4.2', 'fr')).toEqual('0 120,00 %');
|
expect(pipe.transform(1.2, '4.2', 'fr')).toEqual('0 120,00 %');
|
||||||
|
// see issue #20136
|
||||||
|
expect(pipe.transform(0.12345674, '0.0-10')).toEqual('12.345674%');
|
||||||
|
expect(pipe.transform(0, '0.0-10')).toEqual('0%');
|
||||||
|
expect(pipe.transform(0.00, '0.0-10')).toEqual('0%');
|
||||||
|
expect(pipe.transform(1, '0.0-10')).toEqual('100%');
|
||||||
|
expect(pipe.transform(0.1, '0.0-10')).toEqual('10%');
|
||||||
|
expect(pipe.transform(0.12, '0.0-10')).toEqual('12%');
|
||||||
|
expect(pipe.transform(0.123, '0.0-10')).toEqual('12.3%');
|
||||||
|
expect(pipe.transform(12.3456, '0.0-10')).toEqual('1,234.56%');
|
||||||
|
expect(pipe.transform(12.345600, '0.0-10')).toEqual('1,234.56%');
|
||||||
|
expect(pipe.transform(12.345699999, '0.0-6')).toEqual('1,234.57%');
|
||||||
|
expect(pipe.transform(12.345699999, '0.4-6')).toEqual('1,234.5700%');
|
||||||
|
expect(pipe.transform(100, '0.4-6')).toEqual('10,000.0000%');
|
||||||
|
expect(pipe.transform(100, '0.0-10')).toEqual('10,000%');
|
||||||
|
expect(pipe.transform(1.5e2)).toEqual('15,000%');
|
||||||
|
expect(pipe.transform(1e100)).toEqual('1E+102%');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not support other objects', () => {
|
it('should not support other objects', () => {
|
||||||
@ -106,6 +122,7 @@ export function main() {
|
|||||||
expect(pipe.transform(5.1234, 'CAD', 'symbol-narrow', '5.2-2')).toEqual('$00,005.12');
|
expect(pipe.transform(5.1234, 'CAD', 'symbol-narrow', '5.2-2')).toEqual('$00,005.12');
|
||||||
expect(pipe.transform(5.1234, 'CAD', 'symbol-narrow', '5.2-2', 'fr'))
|
expect(pipe.transform(5.1234, 'CAD', 'symbol-narrow', '5.2-2', 'fr'))
|
||||||
.toEqual('00 005,12 $');
|
.toEqual('00 005,12 $');
|
||||||
|
expect(pipe.transform(5.1234, 'FAKE', 'symbol')).toEqual('FAKE5.12');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not support other objects', () => {
|
it('should not support other objects', () => {
|
||||||
|
@ -57,7 +57,7 @@ export interface CompilerOptions extends ts.CompilerOptions {
|
|||||||
// Produce an error if the metadata written for a class would produce an error if used.
|
// Produce an error if the metadata written for a class would produce an error if used.
|
||||||
strictMetadataEmit?: boolean;
|
strictMetadataEmit?: boolean;
|
||||||
|
|
||||||
// Don't produce .ngfactory.ts or .ngstyle.ts files
|
// Don't produce .ngfactory.js or .ngstyle.js files
|
||||||
skipTemplateCodegen?: boolean;
|
skipTemplateCodegen?: boolean;
|
||||||
|
|
||||||
// Always report errors when the type of a parameter supplied whose injection type cannot
|
// Always report errors when the type of a parameter supplied whose injection type cannot
|
||||||
|
@ -48,11 +48,11 @@ describe('ng type checker', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function reject(
|
function reject(
|
||||||
message: string | RegExp, location: RegExp | null, files: MockFiles,
|
message: string | RegExp, location: RegExp, files: MockFiles,
|
||||||
overrideOptions: ng.CompilerOptions = {}) {
|
overrideOptions: ng.CompilerOptions = {}) {
|
||||||
const diagnostics = compileAndCheck([QUICKSTART, files], overrideOptions);
|
const diagnostics = compileAndCheck([QUICKSTART, files], overrideOptions);
|
||||||
if (!diagnostics || !diagnostics.length) {
|
if (!diagnostics || !diagnostics.length) {
|
||||||
throw new Error('Expected a diagnostic error message');
|
throw new Error('Expected a diagnostic erorr message');
|
||||||
} else {
|
} else {
|
||||||
const matches: (d: ng.Diagnostic) => boolean = typeof message === 'string' ?
|
const matches: (d: ng.Diagnostic) => boolean = typeof message === 'string' ?
|
||||||
d => ng.isNgDiagnostic(d)&& d.messageText == message :
|
d => ng.isNgDiagnostic(d)&& d.messageText == message :
|
||||||
@ -63,7 +63,6 @@ describe('ng type checker', () => {
|
|||||||
`Expected a diagnostics matching ${message}, received\n ${diagnostics.map(d => d.messageText).join('\n ')}`);
|
`Expected a diagnostics matching ${message}, received\n ${diagnostics.map(d => d.messageText).join('\n ')}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (location) {
|
|
||||||
const span = matchingDiagnostics[0].span;
|
const span = matchingDiagnostics[0].span;
|
||||||
if (!span) {
|
if (!span) {
|
||||||
throw new Error('Expected a sourceSpan');
|
throw new Error('Expected a sourceSpan');
|
||||||
@ -71,7 +70,6 @@ describe('ng type checker', () => {
|
|||||||
expect(`${span.start.file.url}@${span.start.line}:${span.start.offset}`).toMatch(location);
|
expect(`${span.start.file.url}@${span.start.line}:${span.start.offset}`).toMatch(location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
it('should accept unmodified QuickStart', () => { accept(); });
|
it('should accept unmodified QuickStart', () => { accept(); });
|
||||||
|
|
||||||
@ -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 ', () => {
|
describe('regressions ', () => {
|
||||||
const a = (files: MockFiles, options: object = {}) => {
|
const a = (files: MockFiles, options: object = {}) => {
|
||||||
accept(files, {fullTemplateTypeCheck: true, ...options});
|
accept(files, {fullTemplateTypeCheck: true, ...options});
|
||||||
|
@ -1038,25 +1038,6 @@ describe('Collector', () => {
|
|||||||
expect(metadata).toBeUndefined();
|
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', () => {
|
it('should be able to collect an invalid access expression', () => {
|
||||||
const source = createSource(`
|
const source = createSource(`
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
|
@ -12,7 +12,6 @@ import * as path from 'path';
|
|||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import * as ng from '../index';
|
import * as ng from '../index';
|
||||||
|
|
||||||
// TEST_TMPDIR is set by bazel.
|
|
||||||
const tmpdir = process.env.TEST_TMPDIR || os.tmpdir();
|
const tmpdir = process.env.TEST_TMPDIR || os.tmpdir();
|
||||||
|
|
||||||
function getNgRootDir() {
|
function getNgRootDir() {
|
||||||
@ -22,6 +21,7 @@ function getNgRootDir() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function writeTempFile(name: string, contents: string): string {
|
export function writeTempFile(name: string, contents: string): string {
|
||||||
|
// TEST_TMPDIR is set by bazel.
|
||||||
const id = (Math.random() * 1000000).toFixed(0);
|
const id = (Math.random() * 1000000).toFixed(0);
|
||||||
const fn = path.join(tmpdir, `tmp.${id}.${name}`);
|
const fn = path.join(tmpdir, `tmp.${id}.${name}`);
|
||||||
fs.writeFileSync(fn, contents);
|
fs.writeFileSync(fn, contents);
|
||||||
@ -29,12 +29,8 @@ export function writeTempFile(name: string, contents: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function makeTempDir(): string {
|
export function makeTempDir(): string {
|
||||||
let dir: string;
|
|
||||||
while (true) {
|
|
||||||
const id = (Math.random() * 1000000).toFixed(0);
|
const id = (Math.random() * 1000000).toFixed(0);
|
||||||
dir = path.join(tmpdir, `tmp.${id}`);
|
const dir = path.join(tmpdir, `tmp.${id}`);
|
||||||
if (!fs.existsSync(dir)) break;
|
|
||||||
}
|
|
||||||
fs.mkdirSync(dir);
|
fs.mkdirSync(dir);
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
@ -218,14 +218,15 @@ export class AotCompiler {
|
|||||||
|
|
||||||
const externalReferenceVars = new Map<any, string>();
|
const externalReferenceVars = new Map<any, string>();
|
||||||
externalReferences.forEach((ref, typeIndex) => {
|
externalReferences.forEach((ref, typeIndex) => {
|
||||||
|
if (this._host.isSourceFile(ref.filePath)) {
|
||||||
externalReferenceVars.set(ref, `_decl${ngModuleIndex}_${typeIndex}`);
|
externalReferenceVars.set(ref, `_decl${ngModuleIndex}_${typeIndex}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
externalReferenceVars.forEach((varName, reference) => {
|
externalReferenceVars.forEach((varName, reference) => {
|
||||||
outputCtx.statements.push(
|
outputCtx.statements.push(
|
||||||
o.variable(varName)
|
o.variable(varName)
|
||||||
.set(o.NULL_EXPR.cast(o.DYNAMIC_TYPE))
|
.set(o.NULL_EXPR.cast(o.DYNAMIC_TYPE))
|
||||||
.toDeclStmt(o.expressionType(outputCtx.importExpr(
|
.toDeclStmt(o.expressionType(outputCtx.importExpr(reference))));
|
||||||
reference, /* typeParams */ null, /* useSummaries */ false))));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (emitFlags & StubEmitFlags.TypeCheck) {
|
if (emitFlags & StubEmitFlags.TypeCheck) {
|
||||||
@ -270,7 +271,7 @@ export class AotCompiler {
|
|||||||
const {template: parsedTemplate, pipes: usedPipes} =
|
const {template: parsedTemplate, pipes: usedPipes} =
|
||||||
this._parseTemplate(compMeta, moduleMeta, directives);
|
this._parseTemplate(compMeta, moduleMeta, directives);
|
||||||
ctx.statements.push(...this._typeCheckCompiler.compileComponent(
|
ctx.statements.push(...this._typeCheckCompiler.compileComponent(
|
||||||
componentId, compMeta, parsedTemplate, usedPipes, externalReferenceVars, ctx));
|
componentId, compMeta, parsedTemplate, usedPipes, externalReferenceVars));
|
||||||
}
|
}
|
||||||
|
|
||||||
emitMessageBundle(analyzeResult: NgAnalyzedModules, locale: string|null): MessageBundle {
|
emitMessageBundle(analyzeResult: NgAnalyzedModules, locale: string|null): MessageBundle {
|
||||||
@ -514,15 +515,12 @@ export class AotCompiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _createOutputContext(genFilePath: string): OutputContext {
|
private _createOutputContext(genFilePath: string): OutputContext {
|
||||||
const importExpr =
|
const importExpr = (symbol: StaticSymbol, typeParams: o.Type[] | null = null) => {
|
||||||
(symbol: StaticSymbol, typeParams: o.Type[] | null = null,
|
|
||||||
useSummaries: boolean = true) => {
|
|
||||||
if (!(symbol instanceof StaticSymbol)) {
|
if (!(symbol instanceof StaticSymbol)) {
|
||||||
throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
|
throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
|
||||||
}
|
}
|
||||||
const arity = this._symbolResolver.getTypeArity(symbol) || 0;
|
const arity = this._symbolResolver.getTypeArity(symbol) || 0;
|
||||||
const {filePath, name, members} =
|
const {filePath, name, members} = this._symbolResolver.getImportAs(symbol) || symbol;
|
||||||
this._symbolResolver.getImportAs(symbol, useSummaries) || symbol;
|
|
||||||
const importModule = this._fileNameToModuleName(filePath, genFilePath);
|
const importModule = this._fileNameToModuleName(filePath, genFilePath);
|
||||||
|
|
||||||
// It should be good enough to compare filePath to genFilePath and if they are equal
|
// It should be good enough to compare filePath to genFilePath and if they are equal
|
||||||
|
@ -29,8 +29,6 @@ const IGNORE = {
|
|||||||
const USE_VALUE = 'useValue';
|
const USE_VALUE = 'useValue';
|
||||||
const PROVIDE = 'provide';
|
const PROVIDE = 'provide';
|
||||||
const REFERENCE_SET = new Set([USE_VALUE, 'useFactory', 'data']);
|
const REFERENCE_SET = new Set([USE_VALUE, 'useFactory', 'data']);
|
||||||
const TYPEGUARD_POSTFIX = 'TypeGuard';
|
|
||||||
const USE_IF = 'UseIf';
|
|
||||||
|
|
||||||
function shouldIgnore(value: any): boolean {
|
function shouldIgnore(value: any): boolean {
|
||||||
return value && value.__symbolic == 'ignore';
|
return value && value.__symbolic == 'ignore';
|
||||||
@ -45,7 +43,6 @@ export class StaticReflector implements CompileReflector {
|
|||||||
private propertyCache = new Map<StaticSymbol, {[key: string]: any[]}>();
|
private propertyCache = new Map<StaticSymbol, {[key: string]: any[]}>();
|
||||||
private parameterCache = new Map<StaticSymbol, any[]>();
|
private parameterCache = new Map<StaticSymbol, any[]>();
|
||||||
private methodCache = new Map<StaticSymbol, {[key: string]: boolean}>();
|
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 conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
|
||||||
private injectionToken: StaticSymbol;
|
private injectionToken: StaticSymbol;
|
||||||
private opaqueToken: StaticSymbol;
|
private opaqueToken: StaticSymbol;
|
||||||
@ -254,18 +251,6 @@ export class StaticReflector implements CompileReflector {
|
|||||||
return methodNames;
|
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 {
|
private findParentType(type: StaticSymbol, classMetadata: any): StaticSymbol|undefined {
|
||||||
const parentType = this.trySimplify(type, classMetadata['extends']);
|
const parentType = this.trySimplify(type, classMetadata['extends']);
|
||||||
if (parentType instanceof StaticSymbol) {
|
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 {
|
private _registerDecoratorOrConstructor(type: StaticSymbol, ctor: any): void {
|
||||||
this.conversionMap.set(type, (context: StaticSymbol, args: any[]) => new ctor(...args));
|
this.conversionMap.set(type, (context: StaticSymbol, args: any[]) => new ctor(...args));
|
||||||
}
|
}
|
||||||
|
@ -98,10 +98,10 @@ export class StaticSymbolResolver {
|
|||||||
*
|
*
|
||||||
* @param staticSymbol the symbol for which to generate a import symbol
|
* @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) {
|
if (staticSymbol.members.length) {
|
||||||
const baseSymbol = this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name);
|
const baseSymbol = this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name);
|
||||||
const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
|
const baseImportAs = this.getImportAs(baseSymbol);
|
||||||
return baseImportAs ?
|
return baseImportAs ?
|
||||||
this.getStaticSymbol(baseImportAs.filePath, baseImportAs.name, staticSymbol.members) :
|
this.getStaticSymbol(baseImportAs.filePath, baseImportAs.name, staticSymbol.members) :
|
||||||
null;
|
null;
|
||||||
@ -111,14 +111,14 @@ export class StaticSymbolResolver {
|
|||||||
const summarizedName = stripSummaryForJitNameSuffix(staticSymbol.name);
|
const summarizedName = stripSummaryForJitNameSuffix(staticSymbol.name);
|
||||||
const baseSymbol =
|
const baseSymbol =
|
||||||
this.getStaticSymbol(summarizedFileName, summarizedName, staticSymbol.members);
|
this.getStaticSymbol(summarizedFileName, summarizedName, staticSymbol.members);
|
||||||
const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
|
const baseImportAs = this.getImportAs(baseSymbol);
|
||||||
return baseImportAs ?
|
return baseImportAs ?
|
||||||
this.getStaticSymbol(
|
this.getStaticSymbol(
|
||||||
summaryForJitFileName(baseImportAs.filePath), summaryForJitName(baseImportAs.name),
|
summaryForJitFileName(baseImportAs.filePath), summaryForJitName(baseImportAs.name),
|
||||||
baseSymbol.members) :
|
baseSymbol.members) :
|
||||||
null;
|
null;
|
||||||
}
|
}
|
||||||
let result = (useSummaries && this.summaryResolver.getImportAs(staticSymbol)) || null;
|
let result = this.summaryResolver.getImportAs(staticSymbol);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
result = this.importAs.get(staticSymbol) !;
|
result = this.importAs.get(staticSymbol) !;
|
||||||
}
|
}
|
||||||
@ -481,7 +481,7 @@ export class StaticSymbolResolver {
|
|||||||
if (moduleMetadatas) {
|
if (moduleMetadatas) {
|
||||||
let maxVersion = -1;
|
let maxVersion = -1;
|
||||||
moduleMetadatas.forEach((md) => {
|
moduleMetadatas.forEach((md) => {
|
||||||
if (md['version'] > maxVersion) {
|
if (md && md['version'] > maxVersion) {
|
||||||
maxVersion = md['version'];
|
maxVersion = md['version'];
|
||||||
moduleMetadata = md;
|
moduleMetadata = md;
|
||||||
}
|
}
|
||||||
|
@ -254,7 +254,6 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
|
|||||||
providers: CompileProviderMetadata[];
|
providers: CompileProviderMetadata[];
|
||||||
viewProviders: CompileProviderMetadata[];
|
viewProviders: CompileProviderMetadata[];
|
||||||
queries: CompileQueryMetadata[];
|
queries: CompileQueryMetadata[];
|
||||||
guards: {[key: string]: any};
|
|
||||||
viewQueries: CompileQueryMetadata[];
|
viewQueries: CompileQueryMetadata[];
|
||||||
entryComponents: CompileEntryComponentMetadata[];
|
entryComponents: CompileEntryComponentMetadata[];
|
||||||
changeDetection: ChangeDetectionStrategy|null;
|
changeDetection: ChangeDetectionStrategy|null;
|
||||||
@ -269,8 +268,8 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
|
|||||||
*/
|
*/
|
||||||
export class CompileDirectiveMetadata {
|
export class CompileDirectiveMetadata {
|
||||||
static create({isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs,
|
static create({isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs,
|
||||||
host, providers, viewProviders, queries, guards, viewQueries, entryComponents,
|
host, providers, viewProviders, queries, viewQueries, entryComponents, template,
|
||||||
template, componentViewType, rendererType, componentFactory}: {
|
componentViewType, rendererType, componentFactory}: {
|
||||||
isHost: boolean,
|
isHost: boolean,
|
||||||
type: CompileTypeMetadata,
|
type: CompileTypeMetadata,
|
||||||
isComponent: boolean,
|
isComponent: boolean,
|
||||||
@ -283,7 +282,6 @@ export class CompileDirectiveMetadata {
|
|||||||
providers: CompileProviderMetadata[],
|
providers: CompileProviderMetadata[],
|
||||||
viewProviders: CompileProviderMetadata[],
|
viewProviders: CompileProviderMetadata[],
|
||||||
queries: CompileQueryMetadata[],
|
queries: CompileQueryMetadata[],
|
||||||
guards: {[key: string]: any};
|
|
||||||
viewQueries: CompileQueryMetadata[],
|
viewQueries: CompileQueryMetadata[],
|
||||||
entryComponents: CompileEntryComponentMetadata[],
|
entryComponents: CompileEntryComponentMetadata[],
|
||||||
template: CompileTemplateMetadata,
|
template: CompileTemplateMetadata,
|
||||||
@ -338,7 +336,6 @@ export class CompileDirectiveMetadata {
|
|||||||
providers,
|
providers,
|
||||||
viewProviders,
|
viewProviders,
|
||||||
queries,
|
queries,
|
||||||
guards,
|
|
||||||
viewQueries,
|
viewQueries,
|
||||||
entryComponents,
|
entryComponents,
|
||||||
template,
|
template,
|
||||||
@ -361,7 +358,6 @@ export class CompileDirectiveMetadata {
|
|||||||
providers: CompileProviderMetadata[];
|
providers: CompileProviderMetadata[];
|
||||||
viewProviders: CompileProviderMetadata[];
|
viewProviders: CompileProviderMetadata[];
|
||||||
queries: CompileQueryMetadata[];
|
queries: CompileQueryMetadata[];
|
||||||
guards: {[key: string]: any};
|
|
||||||
viewQueries: CompileQueryMetadata[];
|
viewQueries: CompileQueryMetadata[];
|
||||||
entryComponents: CompileEntryComponentMetadata[];
|
entryComponents: CompileEntryComponentMetadata[];
|
||||||
|
|
||||||
@ -371,27 +367,10 @@ export class CompileDirectiveMetadata {
|
|||||||
rendererType: StaticSymbol|object|null;
|
rendererType: StaticSymbol|object|null;
|
||||||
componentFactory: StaticSymbol|object|null;
|
componentFactory: StaticSymbol|object|null;
|
||||||
|
|
||||||
constructor({isHost,
|
constructor({isHost, type, isComponent, selector, exportAs,
|
||||||
type,
|
changeDetection, inputs, outputs, hostListeners, hostProperties,
|
||||||
isComponent,
|
hostAttributes, providers, viewProviders, queries, viewQueries,
|
||||||
selector,
|
entryComponents, template, componentViewType, rendererType, componentFactory}: {
|
||||||
exportAs,
|
|
||||||
changeDetection,
|
|
||||||
inputs,
|
|
||||||
outputs,
|
|
||||||
hostListeners,
|
|
||||||
hostProperties,
|
|
||||||
hostAttributes,
|
|
||||||
providers,
|
|
||||||
viewProviders,
|
|
||||||
queries,
|
|
||||||
guards,
|
|
||||||
viewQueries,
|
|
||||||
entryComponents,
|
|
||||||
template,
|
|
||||||
componentViewType,
|
|
||||||
rendererType,
|
|
||||||
componentFactory}: {
|
|
||||||
isHost: boolean,
|
isHost: boolean,
|
||||||
type: CompileTypeMetadata,
|
type: CompileTypeMetadata,
|
||||||
isComponent: boolean,
|
isComponent: boolean,
|
||||||
@ -406,7 +385,6 @@ export class CompileDirectiveMetadata {
|
|||||||
providers: CompileProviderMetadata[],
|
providers: CompileProviderMetadata[],
|
||||||
viewProviders: CompileProviderMetadata[],
|
viewProviders: CompileProviderMetadata[],
|
||||||
queries: CompileQueryMetadata[],
|
queries: CompileQueryMetadata[],
|
||||||
guards: {[key: string]: any},
|
|
||||||
viewQueries: CompileQueryMetadata[],
|
viewQueries: CompileQueryMetadata[],
|
||||||
entryComponents: CompileEntryComponentMetadata[],
|
entryComponents: CompileEntryComponentMetadata[],
|
||||||
template: CompileTemplateMetadata|null,
|
template: CompileTemplateMetadata|null,
|
||||||
@ -428,7 +406,6 @@ export class CompileDirectiveMetadata {
|
|||||||
this.providers = _normalizeArray(providers);
|
this.providers = _normalizeArray(providers);
|
||||||
this.viewProviders = _normalizeArray(viewProviders);
|
this.viewProviders = _normalizeArray(viewProviders);
|
||||||
this.queries = _normalizeArray(queries);
|
this.queries = _normalizeArray(queries);
|
||||||
this.guards = guards;
|
|
||||||
this.viewQueries = _normalizeArray(viewQueries);
|
this.viewQueries = _normalizeArray(viewQueries);
|
||||||
this.entryComponents = _normalizeArray(entryComponents);
|
this.entryComponents = _normalizeArray(entryComponents);
|
||||||
this.template = template;
|
this.template = template;
|
||||||
@ -453,7 +430,6 @@ export class CompileDirectiveMetadata {
|
|||||||
providers: this.providers,
|
providers: this.providers,
|
||||||
viewProviders: this.viewProviders,
|
viewProviders: this.viewProviders,
|
||||||
queries: this.queries,
|
queries: this.queries,
|
||||||
guards: this.guards,
|
|
||||||
viewQueries: this.viewQueries,
|
viewQueries: this.viewQueries,
|
||||||
entryComponents: this.entryComponents,
|
entryComponents: this.entryComponents,
|
||||||
changeDetection: this.changeDetection,
|
changeDetection: this.changeDetection,
|
||||||
|
@ -17,7 +17,6 @@ export abstract class CompileReflector {
|
|||||||
abstract annotations(typeOrFunc: /*Type*/ any): any[];
|
abstract annotations(typeOrFunc: /*Type*/ any): any[];
|
||||||
abstract propMetadata(typeOrFunc: /*Type*/ any): {[key: string]: any[]};
|
abstract propMetadata(typeOrFunc: /*Type*/ any): {[key: string]: any[]};
|
||||||
abstract hasLifecycleHook(type: any, lcProperty: string): boolean;
|
abstract hasLifecycleHook(type: any, lcProperty: string): boolean;
|
||||||
abstract guards(typeOrFunc: /* Type */ any): {[key: string]: any};
|
|
||||||
abstract componentModuleUrl(type: /*Type*/ any, cmpMetadata: Component): string;
|
abstract componentModuleUrl(type: /*Type*/ any, cmpMetadata: Component): string;
|
||||||
abstract resolveExternalReference(ref: o.ExternalReference): any;
|
abstract resolveExternalReference(ref: o.ExternalReference): any;
|
||||||
}
|
}
|
||||||
|
@ -90,14 +90,6 @@ export class ConvertPropertyBindingResult {
|
|||||||
constructor(public stmts: o.Statement[], public currValExpr: o.Expression) {}
|
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
|
* 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
|
* is used in property binding. The expression has to be preprocessed via
|
||||||
@ -105,8 +97,7 @@ export enum BindingForm {
|
|||||||
*/
|
*/
|
||||||
export function convertPropertyBinding(
|
export function convertPropertyBinding(
|
||||||
localResolver: LocalResolver | null, implicitReceiver: o.Expression,
|
localResolver: LocalResolver | null, implicitReceiver: o.Expression,
|
||||||
expressionWithoutBuiltins: cdAst.AST, bindingId: string,
|
expressionWithoutBuiltins: cdAst.AST, bindingId: string): ConvertPropertyBindingResult {
|
||||||
form: BindingForm): ConvertPropertyBindingResult {
|
|
||||||
if (!localResolver) {
|
if (!localResolver) {
|
||||||
localResolver = new DefaultLocalResolver();
|
localResolver = new DefaultLocalResolver();
|
||||||
}
|
}
|
||||||
@ -119,11 +110,9 @@ export function convertPropertyBinding(
|
|||||||
for (let i = 0; i < visitor.temporaryCount; i++) {
|
for (let i = 0; i < visitor.temporaryCount; i++) {
|
||||||
stmts.push(temporaryDeclaration(bindingId, 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);
|
return new ConvertPropertyBindingResult(stmts, currValExpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,27 +323,12 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitLiteralPrimitive(ast: cdAst.LiteralPrimitive, mode: _Mode): any {
|
visitLiteralPrimitive(ast: cdAst.LiteralPrimitive, mode: _Mode): any {
|
||||||
// For literal values of null, undefined, true, or false allow type inteference
|
return convertToStatementIfNeeded(mode, o.literal(ast.value));
|
||||||
// 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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getLocal(name: string): o.Expression|null { return this._localResolver.getLocal(name); }
|
private _getLocal(name: string): o.Expression|null { return this._localResolver.getLocal(name); }
|
||||||
|
|
||||||
visitMethodCall(ast: cdAst.MethodCall, mode: _Mode): any {
|
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);
|
const leftMostSafe = this.leftMostSafeNode(ast);
|
||||||
if (leftMostSafe) {
|
if (leftMostSafe) {
|
||||||
return this.convertSafeAccess(ast, leftMostSafe, mode);
|
return this.convertSafeAccess(ast, leftMostSafe, mode);
|
||||||
|
@ -51,7 +51,6 @@ export interface Directive {
|
|||||||
providers?: Provider[];
|
providers?: Provider[];
|
||||||
exportAs?: string;
|
exportAs?: string;
|
||||||
queries?: {[key: string]: any};
|
queries?: {[key: string]: any};
|
||||||
guards?: {[key: string]: any};
|
|
||||||
}
|
}
|
||||||
export const createDirective =
|
export const createDirective =
|
||||||
makeMetadataFactory<Directive>('Directive', (dir: Directive = {}) => dir);
|
makeMetadataFactory<Directive>('Directive', (dir: Directive = {}) => dir);
|
||||||
|
@ -44,8 +44,7 @@ export class DirectiveResolver {
|
|||||||
const metadata = findLast(typeMetadata, isDirectiveMetadata);
|
const metadata = findLast(typeMetadata, isDirectiveMetadata);
|
||||||
if (metadata) {
|
if (metadata) {
|
||||||
const propertyMetadata = this._reflector.propMetadata(type);
|
const propertyMetadata = this._reflector.propMetadata(type);
|
||||||
const guards = this._reflector.guards(type);
|
return this._mergeWithPropertyMetadata(metadata, propertyMetadata, type);
|
||||||
return this._mergeWithPropertyMetadata(metadata, propertyMetadata, guards, type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,12 +56,12 @@ export class DirectiveResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _mergeWithPropertyMetadata(
|
private _mergeWithPropertyMetadata(
|
||||||
dm: Directive, propertyMetadata: {[key: string]: any[]}, guards: {[key: string]: any},
|
dm: Directive, propertyMetadata: {[key: string]: any[]}, directiveType: Type): Directive {
|
||||||
directiveType: Type): Directive {
|
|
||||||
const inputs: string[] = [];
|
const inputs: string[] = [];
|
||||||
const outputs: string[] = [];
|
const outputs: string[] = [];
|
||||||
const host: {[key: string]: string} = {};
|
const host: {[key: string]: string} = {};
|
||||||
const queries: {[key: string]: any} = {};
|
const queries: {[key: string]: any} = {};
|
||||||
|
|
||||||
Object.keys(propertyMetadata).forEach((propName: string) => {
|
Object.keys(propertyMetadata).forEach((propName: string) => {
|
||||||
const input = findLast(propertyMetadata[propName], (a) => createInput.isTypeOf(a));
|
const input = findLast(propertyMetadata[propName], (a) => createInput.isTypeOf(a));
|
||||||
if (input) {
|
if (input) {
|
||||||
@ -106,20 +105,18 @@ export class DirectiveResolver {
|
|||||||
queries[propName] = query;
|
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 _extractPublicName(def: string) { return splitAtColon(def, [null !, def])[1].trim(); }
|
||||||
|
|
||||||
private _dedupeBindings(bindings: string[]): string[] {
|
private _dedupeBindings(bindings: string[]): string[] {
|
||||||
const names = new Set<string>();
|
const names = new Set<string>();
|
||||||
const publicNames = new Set<string>();
|
|
||||||
const reversedResult: string[] = [];
|
const reversedResult: string[] = [];
|
||||||
// go last to first to allow later entries to overwrite previous entries
|
// go last to first to allow later entries to overwrite previous entries
|
||||||
for (let i = bindings.length - 1; i >= 0; i--) {
|
for (let i = bindings.length - 1; i >= 0; i--) {
|
||||||
const binding = bindings[i];
|
const binding = bindings[i];
|
||||||
const name = this._extractPublicName(binding);
|
const name = this._extractPublicName(binding);
|
||||||
publicNames.add(name);
|
|
||||||
if (!names.has(name)) {
|
if (!names.has(name)) {
|
||||||
names.add(name);
|
names.add(name);
|
||||||
reversedResult.push(binding);
|
reversedResult.push(binding);
|
||||||
@ -130,13 +127,14 @@ export class DirectiveResolver {
|
|||||||
|
|
||||||
private _merge(
|
private _merge(
|
||||||
directive: Directive, inputs: string[], outputs: string[], host: {[key: string]: string},
|
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 =
|
const mergedInputs =
|
||||||
this._dedupeBindings(directive.inputs ? directive.inputs.concat(inputs) : inputs);
|
this._dedupeBindings(directive.inputs ? directive.inputs.concat(inputs) : inputs);
|
||||||
const mergedOutputs =
|
const mergedOutputs =
|
||||||
this._dedupeBindings(directive.outputs ? directive.outputs.concat(outputs) : outputs);
|
this._dedupeBindings(directive.outputs ? directive.outputs.concat(outputs) : outputs);
|
||||||
const mergedHost = directive.host ? {...directive.host, ...host} : host;
|
const mergedHost = directive.host ? {...directive.host, ...host} : host;
|
||||||
const mergedQueries = directive.queries ? {...directive.queries, ...queries} : queries;
|
const mergedQueries = directive.queries ? {...directive.queries, ...queries} : queries;
|
||||||
|
|
||||||
if (createComponent.isTypeOf(directive)) {
|
if (createComponent.isTypeOf(directive)) {
|
||||||
const comp = directive as Component;
|
const comp = directive as Component;
|
||||||
return createComponent({
|
return createComponent({
|
||||||
@ -168,7 +166,7 @@ export class DirectiveResolver {
|
|||||||
host: mergedHost,
|
host: mergedHost,
|
||||||
exportAs: directive.exportAs,
|
exportAs: directive.exportAs,
|
||||||
queries: mergedQueries,
|
queries: mergedQueries,
|
||||||
providers: directive.providers, guards
|
providers: directive.providers
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,6 @@ export class CompileMetadataResolver {
|
|||||||
providers: [],
|
providers: [],
|
||||||
viewProviders: [],
|
viewProviders: [],
|
||||||
queries: [],
|
queries: [],
|
||||||
guards: {},
|
|
||||||
viewQueries: [],
|
viewQueries: [],
|
||||||
componentViewType: hostViewType,
|
componentViewType: hostViewType,
|
||||||
rendererType:
|
rendererType:
|
||||||
@ -241,7 +240,6 @@ export class CompileMetadataResolver {
|
|||||||
providers: metadata.providers,
|
providers: metadata.providers,
|
||||||
viewProviders: metadata.viewProviders,
|
viewProviders: metadata.viewProviders,
|
||||||
queries: metadata.queries,
|
queries: metadata.queries,
|
||||||
guards: metadata.guards,
|
|
||||||
viewQueries: metadata.viewQueries,
|
viewQueries: metadata.viewQueries,
|
||||||
entryComponents: metadata.entryComponents,
|
entryComponents: metadata.entryComponents,
|
||||||
componentViewType: metadata.componentViewType,
|
componentViewType: metadata.componentViewType,
|
||||||
@ -385,7 +383,6 @@ export class CompileMetadataResolver {
|
|||||||
providers: providers || [],
|
providers: providers || [],
|
||||||
viewProviders: viewProviders || [],
|
viewProviders: viewProviders || [],
|
||||||
queries: queries || [],
|
queries: queries || [],
|
||||||
guards: dirMeta.guards || {},
|
|
||||||
viewQueries: viewQueries || [],
|
viewQueries: viewQueries || [],
|
||||||
entryComponents: entryComponentMetadata,
|
entryComponents: entryComponentMetadata,
|
||||||
componentViewType: nonNormalizedTemplateMetadata ? this.getComponentViewClass(directiveType) :
|
componentViewType: nonNormalizedTemplateMetadata ? this.getComponentViewClass(directiveType) :
|
||||||
|
@ -152,7 +152,7 @@ export function utf8Encode(str: string): string {
|
|||||||
export interface OutputContext {
|
export interface OutputContext {
|
||||||
genFilePath: string;
|
genFilePath: string;
|
||||||
statements: o.Statement[];
|
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 {
|
export function stringify(token: any): string {
|
||||||
|
@ -10,15 +10,13 @@ import {AotCompilerOptions} from '../aot/compiler_options';
|
|||||||
import {StaticReflector} from '../aot/static_reflector';
|
import {StaticReflector} from '../aot/static_reflector';
|
||||||
import {StaticSymbol} from '../aot/static_symbol';
|
import {StaticSymbol} from '../aot/static_symbol';
|
||||||
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompilePipeSummary} from '../compile_metadata';
|
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 {AST, ASTWithSource, Interpolation} from '../expression_parser/ast';
|
||||||
import {Identifiers} from '../identifiers';
|
import {Identifiers} from '../identifiers';
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
import {convertValueToOutputAst} from '../output/value_util';
|
import {convertValueToOutputAst} from '../output/value_util';
|
||||||
import {ParseSourceSpan} from '../parse_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 {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.
|
* Generates code that is used to type check templates.
|
||||||
@ -36,34 +34,27 @@ export class TypeCheckCompiler {
|
|||||||
*/
|
*/
|
||||||
compileComponent(
|
compileComponent(
|
||||||
componentId: string, component: CompileDirectiveMetadata, template: TemplateAst[],
|
componentId: string, component: CompileDirectiveMetadata, template: TemplateAst[],
|
||||||
usedPipes: CompilePipeSummary[], externalReferenceVars: Map<StaticSymbol, string>,
|
usedPipes: CompilePipeSummary[],
|
||||||
ctx: OutputContext): o.Statement[] {
|
externalReferenceVars: Map<StaticSymbol, string>): o.Statement[] {
|
||||||
const pipes = new Map<string, StaticSymbol>();
|
const pipes = new Map<string, StaticSymbol>();
|
||||||
usedPipes.forEach(p => pipes.set(p.name, p.type.reference));
|
usedPipes.forEach(p => pipes.set(p.name, p.type.reference));
|
||||||
let embeddedViewCount = 0;
|
let embeddedViewCount = 0;
|
||||||
const viewBuilderFactory =
|
const viewBuilderFactory = (parent: ViewBuilder | null): ViewBuilder => {
|
||||||
(parent: ViewBuilder | null, guards: GuardExpression[]): ViewBuilder => {
|
|
||||||
const embeddedViewIndex = embeddedViewCount++;
|
const embeddedViewIndex = embeddedViewCount++;
|
||||||
return new ViewBuilder(
|
return new ViewBuilder(
|
||||||
this.options, this.reflector, externalReferenceVars, parent, component.type.reference,
|
this.options, this.reflector, externalReferenceVars, parent, component.type.reference,
|
||||||
component.isHost, embeddedViewIndex, pipes, guards, ctx, viewBuilderFactory);
|
component.isHost, embeddedViewIndex, pipes, viewBuilderFactory);
|
||||||
};
|
};
|
||||||
|
|
||||||
const visitor = viewBuilderFactory(null, []);
|
const visitor = viewBuilderFactory(null);
|
||||||
visitor.visitAll([], template);
|
visitor.visitAll([], template);
|
||||||
|
|
||||||
return visitor.build(componentId);
|
return visitor.build(componentId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GuardExpression {
|
|
||||||
guard: StaticSymbol;
|
|
||||||
useIf: boolean;
|
|
||||||
expression: Expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ViewBuilderFactory {
|
interface ViewBuilderFactory {
|
||||||
(parent: ViewBuilder, guards: GuardExpression[]): ViewBuilder;
|
(parent: ViewBuilder): ViewBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: This is used as key in Map and should therefore be
|
// 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 externalReferenceVars: Map<StaticSymbol, string>, private parent: ViewBuilder|null,
|
||||||
private component: StaticSymbol, private isHostComponent: boolean,
|
private component: StaticSymbol, private isHostComponent: boolean,
|
||||||
private embeddedViewIndex: number, private pipes: Map<string, StaticSymbol>,
|
private embeddedViewIndex: number, private pipes: Map<string, StaticSymbol>,
|
||||||
private guards: GuardExpression[], private ctx: OutputContext,
|
|
||||||
private viewBuilderFactory: ViewBuilderFactory) {}
|
private viewBuilderFactory: ViewBuilderFactory) {}
|
||||||
|
|
||||||
private getOutputVar(type: o.BuiltinTypeName|StaticSymbol): string {
|
private getOutputVar(type: o.BuiltinTypeName|StaticSymbol): string {
|
||||||
@ -122,24 +112,6 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
|||||||
return varName;
|
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[]) {
|
visitAll(variables: VariableAst[], astNodes: TemplateAst[]) {
|
||||||
this.variables = variables;
|
this.variables = variables;
|
||||||
templateVisitAll(this, astNodes);
|
templateVisitAll(this, astNodes);
|
||||||
@ -147,7 +119,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
|||||||
|
|
||||||
build(componentId: string, targetStatements: o.Statement[] = []): o.Statement[] {
|
build(componentId: string, targetStatements: o.Statement[] = []): o.Statement[] {
|
||||||
this.children.forEach((child) => child.build(componentId, targetStatements));
|
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)];
|
[o.variable(DYNAMIC_VAR_NAME).set(o.NULL_EXPR).toDeclStmt(o.DYNAMIC_TYPE)];
|
||||||
let bindingCount = 0;
|
let bindingCount = 0;
|
||||||
this.updates.forEach((expression) => {
|
this.updates.forEach((expression) => {
|
||||||
@ -155,8 +127,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
|||||||
const bindingId = `${bindingCount++}`;
|
const bindingId = `${bindingCount++}`;
|
||||||
const nameResolver = context === this.component ? this : defaultResolver;
|
const nameResolver = context === this.component ? this : defaultResolver;
|
||||||
const {stmts, currValExpr} = convertPropertyBinding(
|
const {stmts, currValExpr} = convertPropertyBinding(
|
||||||
nameResolver, o.variable(this.getOutputVar(context)), value, bindingId,
|
nameResolver, o.variable(this.getOutputVar(context)), value, bindingId);
|
||||||
BindingForm.General);
|
|
||||||
stmts.push(new o.ExpressionStatement(currValExpr));
|
stmts.push(new o.ExpressionStatement(currValExpr));
|
||||||
viewStmts.push(...stmts.map(
|
viewStmts.push(...stmts.map(
|
||||||
(stmt: o.Statement) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
|
(stmt: o.Statement) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
|
||||||
@ -171,28 +142,6 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
|||||||
(stmt: o.Statement) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
|
(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 viewName = `_View_${componentId}_${this.embeddedViewIndex}`;
|
||||||
const viewFactory = new o.DeclareFunctionStmt(viewName, [], viewStmts);
|
const viewFactory = new o.DeclareFunctionStmt(viewName, [], viewStmts);
|
||||||
targetStatements.push(viewFactory);
|
targetStatements.push(viewFactory);
|
||||||
@ -214,12 +163,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
|||||||
// for the context in any embedded view.
|
// for the context in any embedded view.
|
||||||
// We keep this behaivor behind a flag for now.
|
// We keep this behaivor behind a flag for now.
|
||||||
if (this.options.fullTemplateTypeCheck) {
|
if (this.options.fullTemplateTypeCheck) {
|
||||||
// Find any applicable type guards. For example, NgIf has a type guard on ngIf
|
const childVisitor = this.viewBuilderFactory(this);
|
||||||
// (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);
|
|
||||||
this.children.push(childVisitor);
|
this.children.push(childVisitor);
|
||||||
childVisitor.visitAll(ast.variables, ast.children);
|
childVisitor.visitAll(ast.variables, ast.children);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import {CompileDirectiveMetadata, CompilePipeSummary, rendererTypeName, tokenReference, viewClassName} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompilePipeSummary, rendererTypeName, tokenReference, viewClassName} from '../compile_metadata';
|
||||||
import {CompileReflector} from '../compile_reflector';
|
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 {ArgumentType, BindingFlags, ChangeDetectionStrategy, NodeFlags, QueryBindingType, QueryValueType, ViewFlags} from '../core';
|
||||||
import {AST, ASTWithSource, Interpolation} from '../expression_parser/ast';
|
import {AST, ASTWithSource, Interpolation} from '../expression_parser/ast';
|
||||||
import {Identifiers} from '../identifiers';
|
import {Identifiers} from '../identifiers';
|
||||||
@ -859,7 +859,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
|||||||
const bindingId = `${updateBindingCount++}`;
|
const bindingId = `${updateBindingCount++}`;
|
||||||
const nameResolver = context === COMP_VAR ? self : null;
|
const nameResolver = context === COMP_VAR ? self : null;
|
||||||
const {stmts, currValExpr} =
|
const {stmts, currValExpr} =
|
||||||
convertPropertyBinding(nameResolver, context, value, bindingId, BindingForm.General);
|
convertPropertyBinding(nameResolver, context, value, bindingId);
|
||||||
updateStmts.push(...stmts.map(
|
updateStmts.push(...stmts.map(
|
||||||
(stmt: o.Statement) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
|
(stmt: o.Statement) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
|
||||||
return o.applySourceSpanToExpressionIfNeeded(currValExpr, sourceSpan);
|
return o.applySourceSpanToExpressionIfNeeded(currValExpr, sourceSpan);
|
||||||
|
@ -196,25 +196,6 @@ describe('StaticSymbolResolver', () => {
|
|||||||
.toBe(symbolCache.get('/test3.d.ts', 'b'));
|
.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',
|
it('should calculate importAs for symbols with members based on importAs for symbols without',
|
||||||
() => {
|
() => {
|
||||||
init(
|
init(
|
||||||
|
@ -126,7 +126,6 @@ export function main() {
|
|||||||
outputs: [],
|
outputs: [],
|
||||||
host: {},
|
host: {},
|
||||||
queries: {},
|
queries: {},
|
||||||
guards: {},
|
|
||||||
exportAs: undefined,
|
exportAs: undefined,
|
||||||
providers: undefined
|
providers: undefined
|
||||||
}));
|
}));
|
||||||
@ -155,7 +154,6 @@ export function main() {
|
|||||||
outputs: [],
|
outputs: [],
|
||||||
host: {},
|
host: {},
|
||||||
queries: {},
|
queries: {},
|
||||||
guards: {},
|
|
||||||
exportAs: undefined,
|
exportAs: undefined,
|
||||||
providers: undefined
|
providers: undefined
|
||||||
}));
|
}));
|
||||||
@ -166,7 +164,6 @@ export function main() {
|
|||||||
outputs: [],
|
outputs: [],
|
||||||
host: {},
|
host: {},
|
||||||
queries: {},
|
queries: {},
|
||||||
guards: {},
|
|
||||||
exportAs: undefined,
|
exportAs: undefined,
|
||||||
providers: undefined
|
providers: undefined
|
||||||
}));
|
}));
|
||||||
|
@ -38,10 +38,10 @@ function createTypeMeta({reference, diDeps}: {reference: any, diDeps?: any[]}):
|
|||||||
return {reference: reference, diDeps: diDeps || [], lifecycleHooks: []};
|
return {reference: reference, diDeps: diDeps || [], lifecycleHooks: []};
|
||||||
}
|
}
|
||||||
|
|
||||||
function compileDirectiveMetadataCreate(
|
function compileDirectiveMetadataCreate({isHost, type, isComponent, selector, exportAs,
|
||||||
{isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host,
|
changeDetection, inputs, outputs, host, providers,
|
||||||
providers, viewProviders, queries, guards, viewQueries, entryComponents, template,
|
viewProviders, queries, viewQueries, entryComponents,
|
||||||
componentViewType, rendererType}: {
|
template, componentViewType, rendererType}: {
|
||||||
isHost?: boolean,
|
isHost?: boolean,
|
||||||
type?: CompileTypeMetadata,
|
type?: CompileTypeMetadata,
|
||||||
isComponent?: boolean,
|
isComponent?: boolean,
|
||||||
@ -54,7 +54,6 @@ function compileDirectiveMetadataCreate(
|
|||||||
providers?: CompileProviderMetadata[] | null,
|
providers?: CompileProviderMetadata[] | null,
|
||||||
viewProviders?: CompileProviderMetadata[] | null,
|
viewProviders?: CompileProviderMetadata[] | null,
|
||||||
queries?: CompileQueryMetadata[] | null,
|
queries?: CompileQueryMetadata[] | null,
|
||||||
guards?: {[key: string]: any},
|
|
||||||
viewQueries?: CompileQueryMetadata[],
|
viewQueries?: CompileQueryMetadata[],
|
||||||
entryComponents?: CompileEntryComponentMetadata[],
|
entryComponents?: CompileEntryComponentMetadata[],
|
||||||
template?: CompileTemplateMetadata,
|
template?: CompileTemplateMetadata,
|
||||||
@ -74,7 +73,6 @@ function compileDirectiveMetadataCreate(
|
|||||||
providers: providers || [],
|
providers: providers || [],
|
||||||
viewProviders: viewProviders || [],
|
viewProviders: viewProviders || [],
|
||||||
queries: queries || [],
|
queries: queries || [],
|
||||||
guards: guards || {},
|
|
||||||
viewQueries: viewQueries || [],
|
viewQueries: viewQueries || [],
|
||||||
entryComponents: entryComponents || [],
|
entryComponents: entryComponents || [],
|
||||||
template: noUndefined(template) !,
|
template: noUndefined(template) !,
|
||||||
@ -392,7 +390,6 @@ export function main() {
|
|||||||
providers: [],
|
providers: [],
|
||||||
viewProviders: [],
|
viewProviders: [],
|
||||||
queries: [],
|
queries: [],
|
||||||
guards: {},
|
|
||||||
viewQueries: [],
|
viewQueries: [],
|
||||||
entryComponents: [],
|
entryComponents: [],
|
||||||
componentViewType: null,
|
componentViewType: null,
|
||||||
|
@ -102,8 +102,7 @@ export function createPlatformFactory(
|
|||||||
parentPlatformFactory: ((extraProviders?: StaticProvider[]) => PlatformRef) | null,
|
parentPlatformFactory: ((extraProviders?: StaticProvider[]) => PlatformRef) | null,
|
||||||
name: string, providers: StaticProvider[] = []): (extraProviders?: StaticProvider[]) =>
|
name: string, providers: StaticProvider[] = []): (extraProviders?: StaticProvider[]) =>
|
||||||
PlatformRef {
|
PlatformRef {
|
||||||
const desc = `Platform: ${name}`;
|
const marker = new InjectionToken(`Platform: ${name}`);
|
||||||
const marker = new InjectionToken(desc);
|
|
||||||
return (extraProviders: StaticProvider[] = []) => {
|
return (extraProviders: StaticProvider[] = []) => {
|
||||||
let platform = getPlatform();
|
let platform = getPlatform();
|
||||||
if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
|
if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
|
||||||
@ -111,9 +110,8 @@ export function createPlatformFactory(
|
|||||||
parentPlatformFactory(
|
parentPlatformFactory(
|
||||||
providers.concat(extraProviders).concat({provide: marker, useValue: true}));
|
providers.concat(extraProviders).concat({provide: marker, useValue: true}));
|
||||||
} else {
|
} else {
|
||||||
const injectedProviders: StaticProvider[] =
|
createPlatform(Injector.create(
|
||||||
providers.concat(extraProviders).concat({provide: marker, useValue: true});
|
providers.concat(extraProviders).concat({provide: marker, useValue: true})));
|
||||||
createPlatform(Injector.create({providers: injectedProviders, name: desc}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return assertPlatform(marker);
|
return assertPlatform(marker);
|
||||||
@ -226,12 +224,10 @@ export class PlatformRef {
|
|||||||
// pass that as parent to the NgModuleFactory.
|
// pass that as parent to the NgModuleFactory.
|
||||||
const ngZoneOption = options ? options.ngZone : undefined;
|
const ngZoneOption = options ? options.ngZone : undefined;
|
||||||
const ngZone = getNgZone(ngZoneOption);
|
const ngZone = getNgZone(ngZoneOption);
|
||||||
const providers: StaticProvider[] = [{provide: NgZone, useValue: ngZone}];
|
|
||||||
// Attention: Don't use ApplicationRef.run here,
|
// Attention: Don't use ApplicationRef.run here,
|
||||||
// as we want to be sure that all possible constructor calls are inside `ngZone.run`!
|
// as we want to be sure that all possible constructor calls are inside `ngZone.run`!
|
||||||
return ngZone.run(() => {
|
return ngZone.run(() => {
|
||||||
const ngZoneInjector = Injector.create(
|
const ngZoneInjector = Injector.create([{provide: NgZone, useValue: ngZone}], this.injector);
|
||||||
{providers: providers, parent: this.injector, name: moduleFactory.moduleType.name});
|
|
||||||
const moduleRef = <InternalNgModuleRef<M>>moduleFactory.create(ngZoneInjector);
|
const moduleRef = <InternalNgModuleRef<M>>moduleFactory.create(ngZoneInjector);
|
||||||
const exceptionHandler: ErrorHandler = moduleRef.injector.get(ErrorHandler, null);
|
const exceptionHandler: ErrorHandler = moduleRef.injector.get(ErrorHandler, null);
|
||||||
if (!exceptionHandler) {
|
if (!exceptionHandler) {
|
||||||
|
@ -8,12 +8,12 @@
|
|||||||
|
|
||||||
import {Type} from '../type';
|
import {Type} from '../type';
|
||||||
import {stringify} from '../util';
|
import {stringify} from '../util';
|
||||||
|
|
||||||
import {resolveForwardRef} from './forward_ref';
|
import {resolveForwardRef} from './forward_ref';
|
||||||
import {InjectionToken} from './injection_token';
|
import {InjectionToken} from './injection_token';
|
||||||
import {Inject, Optional, Self, SkipSelf} from './metadata';
|
import {Inject, Optional, Self, SkipSelf} from './metadata';
|
||||||
import {ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, ValueProvider} from './provider';
|
import {ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, ValueProvider} from './provider';
|
||||||
|
|
||||||
export const SOURCE = '__source';
|
|
||||||
const _THROW_IF_NOT_FOUND = new Object();
|
const _THROW_IF_NOT_FOUND = new Object();
|
||||||
export const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
|
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;
|
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.
|
* 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'}
|
* {@example core/di/ts/provider_spec.ts region='ConstructorProvider'}
|
||||||
*/
|
*/
|
||||||
static create(
|
static create(providers: StaticProvider[], parent?: Injector): Injector {
|
||||||
options: StaticProvider[]|{providers: StaticProvider[], parent?: Injector, name?: string},
|
return new StaticInjector(providers, parent);
|
||||||
parent?: Injector): Injector {
|
|
||||||
if (Array.isArray(options)) {
|
|
||||||
return new StaticInjector(options, parent);
|
|
||||||
} else {
|
|
||||||
return new StaticInjector(options.providers, options.parent, options.name || null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,14 +103,11 @@ const NO_NEW_LINE = 'ɵ';
|
|||||||
|
|
||||||
export class StaticInjector implements Injector {
|
export class StaticInjector implements Injector {
|
||||||
readonly parent: Injector;
|
readonly parent: Injector;
|
||||||
readonly source: string|null;
|
|
||||||
|
|
||||||
private _records: Map<any, Record>;
|
private _records: Map<any, Record>;
|
||||||
|
|
||||||
constructor(
|
constructor(providers: StaticProvider[], parent: Injector = NULL_INJECTOR) {
|
||||||
providers: StaticProvider[], parent: Injector = NULL_INJECTOR, source: string|null = null) {
|
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.source = source;
|
|
||||||
const records = this._records = new Map<any, Record>();
|
const records = this._records = new Map<any, Record>();
|
||||||
records.set(
|
records.set(
|
||||||
Injector, <Record>{token: Injector, fn: IDENT, deps: EMPTY, value: this, useNew: false});
|
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);
|
return tryResolveToken(token, record, this._records, this.parent, notFoundValue);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const tokenPath: any[] = e[NG_TEMP_TOKEN_PATH];
|
const tokenPath: any[] = e[NG_TEMP_TOKEN_PATH];
|
||||||
if (token[SOURCE]) {
|
e.message = formatError('\n' + e.message, tokenPath);
|
||||||
tokenPath.unshift(token[SOURCE]);
|
|
||||||
}
|
|
||||||
e.message = formatError('\n' + e.message, tokenPath, this.source);
|
|
||||||
e[NG_TOKEN_PATH] = tokenPath;
|
e[NG_TOKEN_PATH] = tokenPath;
|
||||||
e[NG_TEMP_TOKEN_PATH] = null;
|
e[NG_TEMP_TOKEN_PATH] = null;
|
||||||
throw e;
|
throw e;
|
||||||
@ -355,7 +336,7 @@ function computeDeps(provider: StaticProvider): DependencyRecord[] {
|
|||||||
return deps;
|
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;
|
text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.substr(2) : text;
|
||||||
let context = stringify(obj);
|
let context = stringify(obj);
|
||||||
if (obj instanceof Array) {
|
if (obj instanceof Array) {
|
||||||
@ -371,7 +352,7 @@ function formatError(text: string, obj: any, source: string | null = null): stri
|
|||||||
}
|
}
|
||||||
context = `{${parts.join(', ')}}`;
|
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 {
|
function staticError(text: string, obj: any): Error {
|
||||||
|
@ -71,13 +71,11 @@ export interface ResolvedReflectiveProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ResolvedReflectiveProvider_ implements ResolvedReflectiveProvider {
|
export class ResolvedReflectiveProvider_ implements ResolvedReflectiveProvider {
|
||||||
readonly resolvedFactory: ResolvedReflectiveFactory;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public key: ReflectiveKey, public resolvedFactories: ResolvedReflectiveFactory[],
|
public key: ReflectiveKey, public resolvedFactories: ResolvedReflectiveFactory[],
|
||||||
public multiProvider: boolean) {
|
public multiProvider: boolean) {}
|
||||||
this.resolvedFactory = this.resolvedFactories[0];
|
|
||||||
}
|
get resolvedFactory(): ResolvedReflectiveFactory { return this.resolvedFactories[0]; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,20 +66,13 @@ export class CodegenComponentFactoryResolver implements ComponentFactoryResolver
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ComponentFactoryBoundToModule<C> extends ComponentFactory<C> {
|
export class ComponentFactoryBoundToModule<C> extends ComponentFactory<C> {
|
||||||
readonly selector: string;
|
constructor(private factory: ComponentFactory<C>, private ngModule: NgModuleRef<any>) { super(); }
|
||||||
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>) {
|
get selector() { return this.factory.selector; }
|
||||||
super();
|
get componentType() { return this.factory.componentType; }
|
||||||
this.selector = factory.selector;
|
get ngContentSelectors() { return this.factory.ngContentSelectors; }
|
||||||
this.componentType = factory.componentType;
|
get inputs() { return this.factory.inputs; }
|
||||||
this.ngContentSelectors = factory.ngContentSelectors;
|
get outputs() { return this.factory.outputs; }
|
||||||
this.inputs = factory.inputs;
|
|
||||||
this.outputs = factory.outputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
create(
|
create(
|
||||||
injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string|any,
|
injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string|any,
|
||||||
|
@ -41,9 +41,9 @@ export class QueryList<T>/* implements Iterable<T> */ {
|
|||||||
private _results: Array<T> = [];
|
private _results: Array<T> = [];
|
||||||
public readonly changes: Observable<any> = new EventEmitter();
|
public readonly changes: Observable<any> = new EventEmitter();
|
||||||
|
|
||||||
readonly length: number;
|
get length(): number { return this._results.length; }
|
||||||
readonly first: T;
|
get first(): T { return this._results[0]; }
|
||||||
readonly last: T;
|
get last(): T { return this._results[this.length - 1]; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See
|
* See
|
||||||
@ -98,9 +98,6 @@ export class QueryList<T>/* implements Iterable<T> */ {
|
|||||||
reset(res: Array<T|any[]>): void {
|
reset(res: Array<T|any[]>): void {
|
||||||
this._results = flatten(res);
|
this._results = flatten(res);
|
||||||
(this as{dirty: boolean}).dirty = false;
|
(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); }
|
notifyOnChanges(): void { (this.changes as EventEmitter<any>).emit(this); }
|
||||||
|
@ -13,7 +13,6 @@ export interface PlatformReflectionCapabilities {
|
|||||||
isReflectionEnabled(): boolean;
|
isReflectionEnabled(): boolean;
|
||||||
factory(type: Type<any>): Function;
|
factory(type: Type<any>): Function;
|
||||||
hasLifecycleHook(type: any, lcProperty: string): boolean;
|
hasLifecycleHook(type: any, lcProperty: string): boolean;
|
||||||
guards(type: any): {[key: string]: any};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a list of annotations/types for constructor parameters
|
* Return a list of annotations/types for constructor parameters
|
||||||
|
@ -207,8 +207,6 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
|||||||
return type instanceof Type && lcProperty in type.prototype;
|
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 + ';'); }
|
getter(name: string): GetterFn { return <GetterFn>new Function('o', 'return o.' + name + ';'); }
|
||||||
|
|
||||||
setter(name: string): SetterFn {
|
setter(name: string): SetterFn {
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
import {resolveForwardRef} from '../di/forward_ref';
|
import {resolveForwardRef} from '../di/forward_ref';
|
||||||
import {Injector} from '../di/injector';
|
import {Injector} from '../di/injector';
|
||||||
import {NgModuleRef} from '../linker/ng_module_factory';
|
import {NgModuleRef} from '../linker/ng_module_factory';
|
||||||
import {stringify} from '../util';
|
|
||||||
|
|
||||||
import {DepDef, DepFlags, NgModuleData, NgModuleDefinition, NgModuleProviderDef, NodeFlags} from './types';
|
import {DepDef, DepFlags, NgModuleData, NgModuleDefinition, NgModuleProviderDef, NodeFlags} from './types';
|
||||||
import {splitDepsDsl, tokenKey} from './util';
|
import {splitDepsDsl, tokenKey} from './util';
|
||||||
@ -26,7 +25,7 @@ export function moduleProvideDef(
|
|||||||
// lowered the expression and then stopped evaluating it,
|
// lowered the expression and then stopped evaluating it,
|
||||||
// i.e. also didn't unwrap it.
|
// i.e. also didn't unwrap it.
|
||||||
value = resolveForwardRef(value);
|
value = resolveForwardRef(value);
|
||||||
const depDefs = splitDepsDsl(deps, stringify(token));
|
const depDefs = splitDepsDsl(deps);
|
||||||
return {
|
return {
|
||||||
// will bet set by the module definition
|
// will bet set by the module definition
|
||||||
index: -1,
|
index: -1,
|
||||||
|
@ -12,7 +12,7 @@ import {ElementRef} from '../linker/element_ref';
|
|||||||
import {TemplateRef} from '../linker/template_ref';
|
import {TemplateRef} from '../linker/template_ref';
|
||||||
import {ViewContainerRef} from '../linker/view_container_ref';
|
import {ViewContainerRef} from '../linker/view_container_ref';
|
||||||
import {Renderer as RendererV1, Renderer2} from '../render/api';
|
import {Renderer as RendererV1, Renderer2} from '../render/api';
|
||||||
import {stringify} from '../util';
|
|
||||||
import {createChangeDetectorRef, createInjector, createRendererV1} from './refs';
|
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 {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';
|
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.
|
// i.e. also didn't unwrap it.
|
||||||
value = resolveForwardRef(value);
|
value = resolveForwardRef(value);
|
||||||
|
|
||||||
const depDefs = splitDepsDsl(deps, stringify(token));
|
const depDefs = splitDepsDsl(deps);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// will bet set by the view definition
|
// will bet set by the view definition
|
||||||
|
@ -481,8 +481,6 @@ class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> {
|
|||||||
/** @internal */
|
/** @internal */
|
||||||
_providers: any[];
|
_providers: any[];
|
||||||
|
|
||||||
readonly injector: Injector = this;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _moduleType: Type<any>, public _parent: Injector,
|
private _moduleType: Type<any>, public _parent: Injector,
|
||||||
public _bootstrapComponents: Type<any>[], public _def: NgModuleDefinition) {
|
public _bootstrapComponents: Type<any>[], public _def: NgModuleDefinition) {
|
||||||
@ -498,6 +496,8 @@ class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> {
|
|||||||
|
|
||||||
get componentFactoryResolver() { return this.get(ComponentFactoryResolver); }
|
get componentFactoryResolver() { return this.get(ComponentFactoryResolver); }
|
||||||
|
|
||||||
|
get injector(): Injector { return this; }
|
||||||
|
|
||||||
destroy(): void {
|
destroy(): void {
|
||||||
if (this._destroyed) {
|
if (this._destroyed) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -649,8 +649,9 @@ class DebugRendererFactory2 implements RendererFactory2 {
|
|||||||
|
|
||||||
|
|
||||||
class DebugRenderer2 implements Renderer2 {
|
class DebugRenderer2 implements Renderer2 {
|
||||||
readonly data: {[key: string]: any};
|
constructor(private delegate: Renderer2) {}
|
||||||
constructor(private delegate: Renderer2) { this.data = this.delegate.data; }
|
|
||||||
|
get data() { return this.delegate.data; }
|
||||||
|
|
||||||
destroyNode(node: any) {
|
destroyNode(node: any) {
|
||||||
removeDebugNodeFromIndex(getDebugNode(node) !);
|
removeDebugNodeFromIndex(getDebugNode(node) !);
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {WrappedValue, devModeEqual} from '../change_detection/change_detection';
|
import {WrappedValue, devModeEqual} from '../change_detection/change_detection';
|
||||||
import {SOURCE} from '../di/injector';
|
|
||||||
import {ViewEncapsulation} from '../metadata/view';
|
import {ViewEncapsulation} from '../metadata/view';
|
||||||
import {RendererType2} from '../render/api';
|
import {RendererType2} from '../render/api';
|
||||||
import {looseIdentical, stringify} from '../util';
|
import {looseIdentical, stringify} from '../util';
|
||||||
|
|
||||||
import {expressionChangedAfterItHasBeenCheckedError} from './errors';
|
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';
|
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};
|
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 => {
|
return deps.map(value => {
|
||||||
let token: any;
|
let token: any;
|
||||||
let flags: DepFlags;
|
let flags: DepFlags;
|
||||||
@ -219,9 +219,6 @@ export function splitDepsDsl(deps: ([DepFlags, any] | any)[], sourceName?: strin
|
|||||||
flags = DepFlags.None;
|
flags = DepFlags.None;
|
||||||
token = value;
|
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)};
|
return {flags, token, tokenKey: tokenKey(token)};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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`', () => {
|
it('should allow a state value to be `0`', () => {
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'if-cmp',
|
selector: 'if-cmp',
|
||||||
|
@ -2823,6 +2823,96 @@ export function main() {
|
|||||||
expect(child.log).toEqual(['child-start', 'child-done']);
|
expect(child.log).toEqual(['child-start', 'child-done']);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should fire and synchronize the start/done callbacks on multiple blocked sub triggers',
|
||||||
|
fakeAsync(() => {
|
||||||
|
@Component({
|
||||||
|
selector: 'cmp',
|
||||||
|
animations: [
|
||||||
|
trigger(
|
||||||
|
'parent1',
|
||||||
|
[
|
||||||
|
transition(
|
||||||
|
'* => go, * => go-again',
|
||||||
|
[
|
||||||
|
style({opacity: 0}),
|
||||||
|
animate('1s', style({opacity: 1})),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
trigger(
|
||||||
|
'parent2',
|
||||||
|
[
|
||||||
|
transition(
|
||||||
|
'* => go, * => go-again',
|
||||||
|
[
|
||||||
|
style({lineHeight: '0px'}),
|
||||||
|
animate('1s', style({lineHeight: '10px'})),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
trigger(
|
||||||
|
'child1',
|
||||||
|
[
|
||||||
|
transition(
|
||||||
|
'* => go, * => go-again',
|
||||||
|
[
|
||||||
|
style({width: '0px'}),
|
||||||
|
animate('1s', style({width: '100px'})),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
trigger(
|
||||||
|
'child2',
|
||||||
|
[
|
||||||
|
transition(
|
||||||
|
'* => go, * => go-again',
|
||||||
|
[
|
||||||
|
style({height: '0px'}),
|
||||||
|
animate('1s', style({height: '100px'})),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
template: `
|
||||||
|
<div [@parent1]="parent1Exp" (@parent1.start)="track($event)"
|
||||||
|
[@parent2]="parent2Exp" (@parent2.start)="track($event)">
|
||||||
|
<div [@child1]="child1Exp" (@child1.start)="track($event)"
|
||||||
|
[@child2]="child2Exp" (@child2.start)="track($event)"></div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class Cmp {
|
||||||
|
public parent1Exp = '';
|
||||||
|
public parent2Exp = '';
|
||||||
|
public child1Exp = '';
|
||||||
|
public child2Exp = '';
|
||||||
|
public log: string[] = [];
|
||||||
|
|
||||||
|
track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); }
|
||||||
|
}
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||||
|
const engine = TestBed.get(ɵAnimationEngine);
|
||||||
|
const fixture = TestBed.createComponent(Cmp);
|
||||||
|
fixture.detectChanges();
|
||||||
|
flushMicrotasks();
|
||||||
|
|
||||||
|
const cmp = fixture.componentInstance;
|
||||||
|
cmp.log = [];
|
||||||
|
cmp.parent1Exp = 'go';
|
||||||
|
cmp.parent2Exp = 'go';
|
||||||
|
cmp.child1Exp = 'go';
|
||||||
|
cmp.child2Exp = 'go';
|
||||||
|
fixture.detectChanges();
|
||||||
|
flushMicrotasks();
|
||||||
|
|
||||||
|
expect(cmp.log).toEqual(
|
||||||
|
['parent1-start', 'parent2-start', 'child1-start', 'child2-start']);
|
||||||
|
|
||||||
|
cmp.parent1Exp = 'go-again';
|
||||||
|
cmp.parent2Exp = 'go-again';
|
||||||
|
cmp.child1Exp = 'go-again';
|
||||||
|
cmp.child2Exp = 'go-again';
|
||||||
|
fixture.detectChanges();
|
||||||
|
flushMicrotasks();
|
||||||
|
}));
|
||||||
|
|
||||||
it('should stretch the starting keyframe of a child animation queries are issued by the parent',
|
it('should stretch the starting keyframe of a child animation queries are issued by the parent',
|
||||||
() => {
|
() => {
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -147,8 +147,8 @@ export function main() {
|
|||||||
|
|
||||||
expect(() => createAndGetRootNodes(compViewDef(rootElNodes)))
|
expect(() => createAndGetRootNodes(compViewDef(rootElNodes)))
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
'StaticInjectorError(DynamicTestModule)[SomeService -> Dep]: \n' +
|
'StaticInjectorError[Dep]: \n' +
|
||||||
' StaticInjectorError(Platform: core)[SomeService -> Dep]: \n' +
|
' StaticInjectorError[Dep]: \n' +
|
||||||
' NullInjectorError: No provider for Dep!');
|
' NullInjectorError: No provider for Dep!');
|
||||||
|
|
||||||
const nonRootElNodes = [
|
const nonRootElNodes = [
|
||||||
@ -161,8 +161,8 @@ export function main() {
|
|||||||
|
|
||||||
expect(() => createAndGetRootNodes(compViewDef(nonRootElNodes)))
|
expect(() => createAndGetRootNodes(compViewDef(nonRootElNodes)))
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
'StaticInjectorError(DynamicTestModule)[SomeService -> Dep]: \n' +
|
'StaticInjectorError[Dep]: \n' +
|
||||||
' StaticInjectorError(Platform: core)[SomeService -> Dep]: \n' +
|
' StaticInjectorError[Dep]: \n' +
|
||||||
' NullInjectorError: No provider for Dep!');
|
' NullInjectorError: No provider for Dep!');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -186,8 +186,8 @@ export function main() {
|
|||||||
directiveDef(1, NodeFlags.None, null, 0, SomeService, ['nonExistingDep'])
|
directiveDef(1, NodeFlags.None, null, 0, SomeService, ['nonExistingDep'])
|
||||||
])))
|
])))
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
'StaticInjectorError(DynamicTestModule)[nonExistingDep]: \n' +
|
'StaticInjectorError[nonExistingDep]: \n' +
|
||||||
' StaticInjectorError(Platform: core)[nonExistingDep]: \n' +
|
' StaticInjectorError[nonExistingDep]: \n' +
|
||||||
' NullInjectorError: No provider for nonExistingDep!');
|
' NullInjectorError: No provider for nonExistingDep!');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -355,12 +355,8 @@ export class TestBed implements Injector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ngZone = new NgZone({enableLongStackTrace: true});
|
const ngZone = new NgZone({enableLongStackTrace: true});
|
||||||
const providers: StaticProvider[] = [{provide: NgZone, useValue: ngZone}];
|
const ngZoneInjector =
|
||||||
const ngZoneInjector = Injector.create({
|
Injector.create([{provide: NgZone, useValue: ngZone}], this.platform.injector);
|
||||||
providers: providers,
|
|
||||||
parent: this.platform.injector,
|
|
||||||
name: this._moduleFactory.moduleType.name
|
|
||||||
});
|
|
||||||
this._moduleRef = this._moduleFactory.create(ngZoneInjector);
|
this._moduleRef = this._moduleFactory.create(ngZoneInjector);
|
||||||
// ApplicationInitStatus.runInitializers() is marked @internal to core. So casting to any
|
// ApplicationInitStatus.runInitializers() is marked @internal to core. So casting to any
|
||||||
// before accessing it.
|
// before accessing it.
|
||||||
|
@ -135,7 +135,7 @@ export function main() {
|
|||||||
name = 'square';
|
name = 'square';
|
||||||
}
|
}
|
||||||
|
|
||||||
const injector = Injector.create({providers: [{provide: Square, deps: []}]});
|
const injector = Injector.create([{provide: Square, deps: []}]);
|
||||||
|
|
||||||
const shape: Square = injector.get(Square);
|
const shape: Square = injector.get(Square);
|
||||||
expect(shape.name).toEqual('square');
|
expect(shape.name).toEqual('square');
|
||||||
|
@ -49,10 +49,10 @@ export const COMPOSITION_BUFFER_MODE = new InjectionToken<boolean>('CompositionE
|
|||||||
// https://github.com/angular/angular/issues/3011 is implemented
|
// https://github.com/angular/angular/issues/3011 is implemented
|
||||||
// selector: '[ngModel],[formControl],[formControlName]',
|
// selector: '[ngModel],[formControl],[formControlName]',
|
||||||
host: {
|
host: {
|
||||||
'(input)': '$any(this)._handleInput($event.target.value)',
|
'(input)': '_handleInput($event.target.value)',
|
||||||
'(blur)': 'onTouched()',
|
'(blur)': 'onTouched()',
|
||||||
'(compositionstart)': '$any(this)._compositionStart()',
|
'(compositionstart)': '_compositionStart()',
|
||||||
'(compositionend)': '$any(this)._compositionEnd($event.target.value)'
|
'(compositionend)': '_compositionEnd($event.target.value)'
|
||||||
},
|
},
|
||||||
providers: [DEFAULT_VALUE_ACCESSOR]
|
providers: [DEFAULT_VALUE_ACCESSOR]
|
||||||
})
|
})
|
||||||
|
@ -253,7 +253,7 @@ export abstract class AbstractControl {
|
|||||||
* Sets the async validators that are active on this control. Calling this
|
* Sets the async validators that are active on this control. Calling this
|
||||||
* will overwrite any existing async validators.
|
* will overwrite any existing async validators.
|
||||||
*/
|
*/
|
||||||
setAsyncValidators(newValidator: AsyncValidatorFn|AsyncValidatorFn[]|null): void {
|
setAsyncValidators(newValidator: AsyncValidatorFn|AsyncValidatorFn[]): void {
|
||||||
this.asyncValidator = coerceToAsyncValidator(newValidator);
|
this.asyncValidator = coerceToAsyncValidator(newValidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +75,8 @@ const EMAIL_REGEXP =
|
|||||||
export class Validators {
|
export class Validators {
|
||||||
/**
|
/**
|
||||||
* Validator that requires controls to have a value greater than a number.
|
* Validator that requires controls to have a value greater than a number.
|
||||||
|
*`min()` exists only as a function, not as a directive. For example,
|
||||||
|
* `control = new FormControl('', Validators.min(3));`.
|
||||||
*/
|
*/
|
||||||
static min(min: number): ValidatorFn {
|
static min(min: number): ValidatorFn {
|
||||||
return (control: AbstractControl): ValidationErrors | null => {
|
return (control: AbstractControl): ValidationErrors | null => {
|
||||||
@ -90,6 +92,8 @@ export class Validators {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Validator that requires controls to have a value less than a number.
|
* Validator that requires controls to have a value less than a number.
|
||||||
|
* `max()` exists only as a function, not as a directive. For example,
|
||||||
|
* `control = new FormControl('', Validators.max(15));`.
|
||||||
*/
|
*/
|
||||||
static max(max: number): ValidatorFn {
|
static max(max: number): ValidatorFn {
|
||||||
return (control: AbstractControl): ValidationErrors | null => {
|
return (control: AbstractControl): ValidationErrors | null => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @license Angular v0.0.0-PLACEHOLDER
|
* @license Angular v0.0.0-PLACEHOLDER
|
||||||
* (c) 2010-2017 Google, Inc. https://angular.io/
|
* (c) 2010-2018 Google, Inc. https://angular.io/
|
||||||
* License: MIT
|
* License: MIT
|
||||||
*/
|
*/
|
||||||
|
@ -42,7 +42,6 @@ export class JitReflector implements CompileReflector {
|
|||||||
hasLifecycleHook(type: any, lcProperty: string): boolean {
|
hasLifecycleHook(type: any, lcProperty: string): boolean {
|
||||||
return this.reflectionCapabilities.hasLifecycleHook(type, lcProperty);
|
return this.reflectionCapabilities.hasLifecycleHook(type, lcProperty);
|
||||||
}
|
}
|
||||||
guards(type: any): {[key: string]: any} { return this.reflectionCapabilities.guards(type); }
|
|
||||||
resolveExternalReference(ref: ExternalReference): any {
|
resolveExternalReference(ref: ExternalReference): any {
|
||||||
return builtinExternalReferences.get(ref) || ref.runtime;
|
return builtinExternalReferences.get(ref) || ref.runtime;
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {isPlatformBrowser} from '@angular/common';
|
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 {ApplicationRef, destroyPlatform} from '@angular/core/src/application_ref';
|
||||||
import {Console} from '@angular/core/src/console';
|
import {Console} from '@angular/core/src/console';
|
||||||
import {ComponentRef} from '@angular/core/src/linker/component_factory';
|
import {ComponentRef} from '@angular/core/src/linker/component_factory';
|
||||||
import {Testability, TestabilityRegistry} from '@angular/core/src/testability/testability';
|
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 {BrowserModule} from '@angular/platform-browser';
|
||||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||||
@ -112,11 +112,10 @@ class DummyConsole implements Console {
|
|||||||
|
|
||||||
|
|
||||||
class TestModule {}
|
class TestModule {}
|
||||||
function bootstrap(
|
function bootstrap(cmpType: any, providers: Provider[] = [], platformProviders: StaticProvider[] = [
|
||||||
cmpType: any, providers: Provider[] = [], platformProviders: StaticProvider[] = [],
|
]): Promise<any> {
|
||||||
imports: Type<any>[] = []): Promise<any> {
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [BrowserModule, ...imports],
|
imports: [BrowserModule],
|
||||||
declarations: [cmpType],
|
declarations: [cmpType],
|
||||||
bootstrap: [cmpType],
|
bootstrap: [cmpType],
|
||||||
providers: providers,
|
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()) {
|
if (getDOM().supportsDOMEvents()) {
|
||||||
it('should forward the error to promise when bootstrap fails',
|
it('should forward the error to promise when bootstrap fails',
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
The MIT License
|
The MIT License
|
||||||
|
|
||||||
Copyright (c) 2017 Google, Inc. http://angular.io
|
Copyright (c) 2017-2018 Google, Inc. http://angular.io
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -277,11 +277,11 @@ export type UrlMatchResult = {
|
|||||||
* For instance, the following matcher matches html files.
|
* For instance, the following matcher matches html files.
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* function htmlFiles(url: UrlSegment[]) {
|
* export function htmlFiles(url: UrlSegment[]) {
|
||||||
* return url.length === 1 && url[0].path.endsWith('.html') ? ({consumed: url}) : null;
|
* return url.length === 1 && url[0].path.endsWith('.html') ? ({consumed: url}) : null;
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* const routes = [{ matcher: htmlFiles, component: HtmlCmp }];
|
* export const routes = [{ matcher: htmlFiles, component: AnyComponent }];
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @experimental
|
* @experimental
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user