Compare commits
197 Commits
5.1.0-rc.1
...
5.0.3
Author | SHA1 | Date | |
---|---|---|---|
65a40e659b | |||
215832d8c6 | |||
686c4efe6d | |||
efce39605b | |||
b567f9cc21 | |||
4ff60c3562 | |||
bc904b19a4 | |||
135cf226bf | |||
0550383fc9 | |||
07699cbaec | |||
e4bb077d27 | |||
27e7439c3b | |||
66d160215e | |||
0feba49c4b | |||
9ca6ee9eed | |||
a5a82296b7 | |||
f9f2c20a57 | |||
662422a67e | |||
b53ead4c45 | |||
d0abfa3acc | |||
3bf36e9492 | |||
82aace63ea | |||
15795d09cf | |||
8ddbed8f7b | |||
81f1d42328 | |||
3df1542c87 | |||
8e1e7faef4 | |||
27f8c69d8a | |||
5d0dd97402 | |||
814f06289b | |||
b1f8eb14c8 | |||
f983d1cc50 | |||
12857922c5 | |||
dbdf9f76be | |||
d5eaf4de3c | |||
2d6126ec1b | |||
259f6bf638 | |||
03d549be05 | |||
bc4b4b5b55 | |||
00f2055c59 | |||
91efc7f70b | |||
8b1a6b1f24 | |||
b732fb935b | |||
0e2d962acb | |||
7acbc19b94 | |||
c69eda8f60 | |||
210ff78f4d | |||
96766f7336 | |||
52b50c4b6c | |||
398690d47c | |||
dc01fb167b | |||
7c26c06495 | |||
82dc7fa628 | |||
3101e89cf5 | |||
79c3e1b968 | |||
c96967b235 | |||
422cd0b665 | |||
eea2039bce | |||
612f508dff | |||
aa3d75ba83 | |||
4cc6abbbf8 | |||
222758bed3 | |||
516107fd04 | |||
bd70aece52 | |||
2ca6bdd110 | |||
2aefac841f | |||
ec496c2fda | |||
346dbcf24a | |||
48843a9f47 | |||
8f2fb02048 | |||
89e4262188 | |||
424a323316 | |||
28985cb2de | |||
5d1cd57787 | |||
9de45fa650 | |||
953a0e07d6 | |||
511e56d633 | |||
1f1741c5ad | |||
408ffb634e | |||
73d857cb38 | |||
3ab0963309 | |||
da22c48ef1 | |||
f80d41f3e5 | |||
2b7ca4e9f8 | |||
4292540939 | |||
708379128f | |||
131368c774 | |||
94e0ef77ea | |||
e4cd3b0564 | |||
22dc3ad94c | |||
7077a61614 | |||
9811bef278 | |||
3298c4a79f | |||
5a6efa7a3f | |||
a8c786c8c9 | |||
799cbb932c | |||
e6f16a7629 | |||
1bb0333c23 | |||
9fa0ffd8a5 | |||
678d1cfae1 | |||
a897d6842f | |||
25843fed53 | |||
762da3b154 | |||
37a740b5b2 | |||
067e926c08 | |||
bc52e97eba | |||
9b579d85be | |||
895d78c0ed | |||
803b0f0fb3 | |||
86399958dd | |||
d550b6872a | |||
92e4c34d01 | |||
e84695389b | |||
4e48bdff22 | |||
2185e466db | |||
6f05dab2fc | |||
18197bd56d | |||
c75740e585 | |||
16d72584cb | |||
9c9867e840 | |||
55092ace87 | |||
70edca3cec | |||
120ebe8225 | |||
7695ad570b | |||
7a708ad387 | |||
71f1ed5795 | |||
ced5186ca4 | |||
e48dc270b5 | |||
aa574710c9 | |||
d62ef132d2 | |||
428f80e8ae | |||
260c9b763c | |||
5f6d71d39a | |||
8133a8d335 | |||
3e05d62a99 | |||
db7f2a9ca7 | |||
59a2fbe74f | |||
3274e1a79a | |||
6979a29d1f | |||
9da5ca7ae6 | |||
e51ac3671f | |||
3393009b69 | |||
12e4b5667e | |||
0f8b83200a | |||
253e89dfac | |||
c4772ee002 | |||
35ec4af2b1 | |||
19b48429ef | |||
b796419e7e | |||
a1ec65b1dd | |||
851e1cfcfd | |||
a363be6b5c | |||
e1fb65cac4 | |||
b497e9e6ee | |||
706ba38498 | |||
78052e4984 | |||
bf861f5539 | |||
d99a5ec494 | |||
d651fc0d6a | |||
5775376bcf | |||
896b853519 | |||
5225fdbc0e | |||
f5b7f2b9a5 | |||
509f392ab0 | |||
cf5fce8d5e | |||
f1248b69e6 | |||
4498dddbe3 | |||
812786f44e | |||
de24d54517 | |||
c295aeeca2 | |||
a8add78fe1 | |||
e3a16ed02d | |||
fd37f3fbab | |||
85e95cc32b | |||
de71ba74bb | |||
a01c877534 | |||
2d508a3ef0 | |||
4285b6c3e3 | |||
5542517b9c | |||
fef3539608 | |||
f4d5729cb3 | |||
d343bf7885 | |||
9ce7f0e538 | |||
4a23df3909 | |||
14016c781f | |||
47caebfe86 | |||
5cfd9c6020 | |||
47bc6f105d | |||
40fa2593a9 | |||
680bcf7b8a | |||
ef08330341 | |||
6cc042e2ba | |||
9b26455740 | |||
18bce5987c | |||
f1108fea76 | |||
64b3e3e41a | |||
a82f863e24 |
18
.bazelrc
Normal file
18
.bazelrc
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Make compilation fast, by keeping a few copies of the compilers
|
||||||
|
# running as daemons, and cache SourceFile AST's to reduce parse time.
|
||||||
|
build --strategy=TypeScriptCompile=worker
|
||||||
|
build --strategy=AngularTemplateCompile=worker
|
||||||
|
|
||||||
|
# Don't create bazel-* symlinks in the WORKSPACE directory.
|
||||||
|
# These require .gitignore and may scare users.
|
||||||
|
# Also, it's a workaround for https://github.com/bazelbuild/rules_typescript/issues/12
|
||||||
|
# which affects the common case of having `tsconfig.json` in the WORKSPACE directory.
|
||||||
|
#
|
||||||
|
# Instead, you should run `bazel info bazel-bin` to find out where the outputs went.
|
||||||
|
build --symlink_prefix=/
|
||||||
|
|
||||||
|
# Performance: avoid stat'ing input files
|
||||||
|
build --watchfs
|
||||||
|
|
||||||
|
# Don't print all the .d.ts output locations after builds
|
||||||
|
build --show_result=0
|
@ -279,7 +279,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
|
||||||
|
137
CHANGELOG.md
137
CHANGELOG.md
@ -1,102 +1,3 @@
|
|||||||
<a name="5.1.0-rc.1"></a>
|
|
||||||
# [5.1.0-rc.1](https://github.com/angular/angular/compare/5.1.0-rc.0...5.1.0-rc.1) (2017-12-01)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **compiler-cli:** propagate ts.SourceFile moduleName into metadata ([f841fbe](https://github.com/angular/angular/commit/f841fbe))
|
|
||||||
* **service-worker:** allow disabling SW while still using services ([65f4fad](https://github.com/angular/angular/commit/65f4fad))
|
|
||||||
* **service-worker:** don't crash if SW not supported ([b9a91a5](https://github.com/angular/angular/commit/b9a91a5))
|
|
||||||
* **service-worker:** send initialization signal from the application ([3fbcde9](https://github.com/angular/angular/commit/3fbcde9))
|
|
||||||
* **service-worker:** use relative path for ngsw.json ([f582620](https://github.com/angular/angular/commit/f582620))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="5.0.5"></a>
|
|
||||||
## [5.0.5](https://github.com/angular/angular/compare/5.0.4...5.0.5) (2017-12-01)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **compiler-cli:** propagate ts.SourceFile moduleName into metadata ([a2ff4ab](https://github.com/angular/angular/commit/a2ff4ab))
|
|
||||||
* **service-worker:** allow disabling SW while still using services ([f99335b](https://github.com/angular/angular/commit/f99335b))
|
|
||||||
* **service-worker:** don't crash if SW not supported ([ee37d4b](https://github.com/angular/angular/commit/ee37d4b))
|
|
||||||
* **service-worker:** send initialization signal from the application ([6bf07b4](https://github.com/angular/angular/commit/6bf07b4))
|
|
||||||
* **service-worker:** use relative path for ngsw.json ([56c98f7](https://github.com/angular/angular/commit/56c98f7))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="5.1.0-rc.0"></a>
|
|
||||||
# [5.1.0-rc.0](https://github.com/angular/angular/compare/5.1.0-beta.2...5.1.0-rc.0) (2017-12-01)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **animations:** ensure multi-level enter animations work ([#19455](https://github.com/angular/angular/issues/19455)) ([dd6237e](https://github.com/angular/angular/commit/dd6237e))
|
|
||||||
* **animations:** ensure multi-level enter animations work ([#19455](https://github.com/angular/angular/issues/19455)) ([b2a586c](https://github.com/angular/angular/commit/b2a586c))
|
|
||||||
* **animations:** ensure multi-level leave animations work ([#19455](https://github.com/angular/angular/issues/19455)) ([1366762](https://github.com/angular/angular/commit/1366762))
|
|
||||||
* **animations:** ensure multi-level leave animations work ([#19455](https://github.com/angular/angular/issues/19455)) ([c2b3792](https://github.com/angular/angular/commit/c2b3792))
|
|
||||||
* **bazel:** produce named AMD modules for codegen ([#20547](https://github.com/angular/angular/issues/20547)) ([6e83204](https://github.com/angular/angular/commit/6e83204)), closes [#19422](https://github.com/angular/angular/issues/19422)
|
|
||||||
* **common:** accept falsy values as HTTP bodies ([#19958](https://github.com/angular/angular/issues/19958)) ([15a54df](https://github.com/angular/angular/commit/15a54df)), closes [#19825](https://github.com/angular/angular/issues/19825) [#19195](https://github.com/angular/angular/issues/19195)
|
|
||||||
* **common:** don't strip XSSI prefix for if error isn't JSON ([#19958](https://github.com/angular/angular/issues/19958)) ([aafa75d](https://github.com/angular/angular/commit/aafa75d))
|
|
||||||
* **common:** remove useless guard in HttpClient ([#19958](https://github.com/angular/angular/issues/19958)) ([eb01ad5](https://github.com/angular/angular/commit/eb01ad5)), closes [#19223](https://github.com/angular/angular/issues/19223)
|
|
||||||
* **common:** treat an empty body as null when parsing JSON in HttpClient ([#19958](https://github.com/angular/angular/issues/19958)) ([503be69](https://github.com/angular/angular/commit/503be69)), closes [#18680](https://github.com/angular/angular/issues/18680) [#19413](https://github.com/angular/angular/issues/19413) [#19502](https://github.com/angular/angular/issues/19502) [#19555](https://github.com/angular/angular/issues/19555)
|
|
||||||
* **compiler:** correctly detect when to serialze summary metadata ([#20668](https://github.com/angular/angular/issues/20668)) ([8bb42df](https://github.com/angular/angular/commit/8bb42df))
|
|
||||||
* **compiler-cli:** fix memory leak in program creation ([#20692](https://github.com/angular/angular/issues/20692)) ([71e5de6](https://github.com/angular/angular/commit/71e5de6)), closes [#20691](https://github.com/angular/angular/issues/20691)
|
|
||||||
* **compiler-cli:** normalize sourcepaths for i18n extracted files ([#20417](https://github.com/angular/angular/issues/20417)) ([de78307](https://github.com/angular/angular/commit/de78307)), closes [#20416](https://github.com/angular/angular/issues/20416)
|
|
||||||
* **core:** should use native addEventListener in ngZone ([#20672](https://github.com/angular/angular/issues/20672)) ([65a2cb8](https://github.com/angular/angular/commit/65a2cb8))
|
|
||||||
* **language-service:** Allow empty templates ([#20651](https://github.com/angular/angular/issues/20651)) ([3203069](https://github.com/angular/angular/commit/3203069)), closes [#19406](https://github.com/angular/angular/issues/19406)
|
|
||||||
* **language-service:** Fix crash when no script files are found ([#20550](https://github.com/angular/angular/issues/20550)) ([54bfe14](https://github.com/angular/angular/commit/54bfe14)), closes [#19325](https://github.com/angular/angular/issues/19325)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **common:** add locale id parameter to `registerLocaleData` ([#20623](https://github.com/angular/angular/issues/20623)) ([24bf3e2](https://github.com/angular/angular/commit/24bf3e2))
|
|
||||||
* **compiler-cli:** improve error messages produced during structural errors ([#20459](https://github.com/angular/angular/issues/20459)) ([8ecda94](https://github.com/angular/angular/commit/8ecda94))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="5.0.4"></a>
|
|
||||||
## [5.0.4](https://github.com/angular/angular/compare/5.0.3...5.0.4) (2017-12-01)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **animations:** ensure multi-level enter animations work ([#19455](https://github.com/angular/angular/issues/19455)) ([22bbd6e](https://github.com/angular/angular/commit/22bbd6e))
|
|
||||||
* **animations:** ensure multi-level leave animations work ([#19455](https://github.com/angular/angular/issues/19455)) ([c7b211c](https://github.com/angular/angular/commit/c7b211c))
|
|
||||||
* **common:** accept falsy values as HTTP bodies ([#19958](https://github.com/angular/angular/issues/19958)) ([66fd1f8](https://github.com/angular/angular/commit/66fd1f8)), closes [#19825](https://github.com/angular/angular/issues/19825) [#19195](https://github.com/angular/angular/issues/19195)
|
|
||||||
* **common:** don't strip XSSI prefix for if error isn't JSON ([#19958](https://github.com/angular/angular/issues/19958)) ([ead7596](https://github.com/angular/angular/commit/ead7596))
|
|
||||||
* **common:** remove useless guard in HttpClient ([#19958](https://github.com/angular/angular/issues/19958)) ([e099911](https://github.com/angular/angular/commit/e099911)), closes [#19223](https://github.com/angular/angular/issues/19223)
|
|
||||||
* **common:** treat an empty body as null when parsing JSON in HttpClient ([#19958](https://github.com/angular/angular/issues/19958)) ([bdaee50](https://github.com/angular/angular/commit/bdaee50)), closes [#18680](https://github.com/angular/angular/issues/18680) [#19413](https://github.com/angular/angular/issues/19413) [#19502](https://github.com/angular/angular/issues/19502) [#19555](https://github.com/angular/angular/issues/19555)
|
|
||||||
* **compiler-cli:** fix memory leak in program creation ([#20692](https://github.com/angular/angular/issues/20692)) ([38be44d](https://github.com/angular/angular/commit/38be44d)), closes [#20691](https://github.com/angular/angular/issues/20691)
|
|
||||||
* **compiler-cli:** normalize sourcepaths for i18n extracted files ([#20417](https://github.com/angular/angular/issues/20417)) ([2b0c896](https://github.com/angular/angular/commit/2b0c896)), closes [#20416](https://github.com/angular/angular/issues/20416)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="5.1.0-beta.2"></a>
|
|
||||||
# [5.1.0-beta.2](https://github.com/angular/angular/compare/5.1.0-beta.1...5.1.0-beta.2) (2017-11-22)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **animations:** always fire inner trigger callbacks even if blocked by parent animations ([#19753](https://github.com/angular/angular/issues/19753)) ([0e012c9](https://github.com/angular/angular/commit/0e012c9)), closes [#19100](https://github.com/angular/angular/issues/19100)
|
|
||||||
* **animations:** always fire start and done callbacks in order for noop animations ([#20570](https://github.com/angular/angular/issues/20570)) ([ffb6dbe](https://github.com/angular/angular/commit/ffb6dbe))
|
|
||||||
* **animations:** validate against trigger() names that use @ symbols ([#20326](https://github.com/angular/angular/issues/20326)) ([1861e41](https://github.com/angular/angular/commit/1861e41))
|
|
||||||
* **benchpress:** Allow ignoring navigationStart events in perflog metric. ([#20312](https://github.com/angular/angular/issues/20312)) ([717ac5a](https://github.com/angular/angular/commit/717ac5a))
|
|
||||||
* **common:** return ISubscription from Location.subscribe() ([#20429](https://github.com/angular/angular/issues/20429)) ([437a044](https://github.com/angular/angular/commit/437a044)), closes [#20406](https://github.com/angular/angular/issues/20406)
|
|
||||||
* **compiler:** emit correct type-check-blocks with TemplateRef's ([#20463](https://github.com/angular/angular/issues/20463)) ([68b53c0](https://github.com/angular/angular/commit/68b53c0))
|
|
||||||
* **compiler:** support event bindings in `fullTemplateTypeCheck` ([#20490](https://github.com/angular/angular/issues/20490)) ([4ed0439](https://github.com/angular/angular/commit/4ed0439))
|
|
||||||
* **core:** fix [#20532](https://github.com/angular/angular/issues/20532), should be able to cancel listener from mixed zone ([#20538](https://github.com/angular/angular/issues/20538)) ([a740e4f](https://github.com/angular/angular/commit/a740e4f))
|
|
||||||
* **core:** should support event.stopImmediatePropagation ([#20469](https://github.com/angular/angular/issues/20469)) ([997336b](https://github.com/angular/angular/commit/997336b))
|
|
||||||
* **forms:** updateOn should check if change occurred ([#20358](https://github.com/angular/angular/issues/20358)) ([69c53c3](https://github.com/angular/angular/commit/69c53c3)), closes [#20259](https://github.com/angular/angular/issues/20259)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **platform-browser-dynamic:** export `JitCompilerFactory` ([#20478](https://github.com/angular/angular/issues/20478)) ([d7a727c](https://github.com/angular/angular/commit/d7a727c)), closes [#20125](https://github.com/angular/angular/issues/20125)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="5.0.3"></a>
|
<a name="5.0.3"></a>
|
||||||
## [5.0.3](https://github.com/angular/angular/compare/5.0.2...5.0.3) (2017-11-22)
|
## [5.0.3](https://github.com/angular/angular/compare/5.0.2...5.0.3) (2017-11-22)
|
||||||
|
|
||||||
@ -114,28 +15,6 @@
|
|||||||
* **forms:** updateOn should check if change occurred ([#20358](https://github.com/angular/angular/issues/20358)) ([f9f2c20](https://github.com/angular/angular/commit/f9f2c20)), closes [#20259](https://github.com/angular/angular/issues/20259)
|
* **forms:** updateOn should check if change occurred ([#20358](https://github.com/angular/angular/issues/20358)) ([f9f2c20](https://github.com/angular/angular/commit/f9f2c20)), closes [#20259](https://github.com/angular/angular/issues/20259)
|
||||||
|
|
||||||
|
|
||||||
<a name="5.1.0-beta.1"></a>
|
|
||||||
# [5.1.0-beta.1](https://github.com/angular/angular/compare/5.1.0-beta.0...5.1.0-beta.1) (2017-11-16)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **animations:** always fire inner trigger callbacks even if blocked by parent animations ([#19753](https://github.com/angular/angular/issues/19753)) ([d47b2a6](https://github.com/angular/angular/commit/d47b2a6)), closes [#19100](https://github.com/angular/angular/issues/19100)
|
|
||||||
* **animations:** ensure final state() styles are applied within @.disabled animations ([#20267](https://github.com/angular/angular/issues/20267)) ([20aafff](https://github.com/angular/angular/commit/20aafff)), closes [#20266](https://github.com/angular/angular/issues/20266)
|
|
||||||
* **bazel:** adjust mock of tsconfig for ng_module rule unit test ([#20175](https://github.com/angular/angular/issues/20175)) ([c2a24b4](https://github.com/angular/angular/commit/c2a24b4))
|
|
||||||
* **compiler:** fix corner cases in shadow CSS ([c32f5fd](https://github.com/angular/angular/commit/c32f5fd))
|
|
||||||
* **compiler:** recognize @NgModule with a redundant @Injectable ([#20320](https://github.com/angular/angular/issues/20320)) ([c33a576](https://github.com/angular/angular/commit/c33a576))
|
|
||||||
* **compiler:** show explanatory text in template errors ([#20313](https://github.com/angular/angular/issues/20313)) ([3257fcd](https://github.com/angular/angular/commit/3257fcd))
|
|
||||||
* **core:** ensure init lifecycle events are called ([#20258](https://github.com/angular/angular/issues/20258)) ([24cf8b3](https://github.com/angular/angular/commit/24cf8b3))
|
|
||||||
* **language-service:** pass compilerOptions.paths to ReflectorHost ([#20222](https://github.com/angular/angular/issues/20222)) ([eb8013e](https://github.com/angular/angular/commit/eb8013e))
|
|
||||||
* **router:** 'merge' queryParamHandling strategy should be able to remove query params ([#19733](https://github.com/angular/angular/issues/19733)) ([a622e19](https://github.com/angular/angular/commit/a622e19)), closes [#18463](https://github.com/angular/angular/issues/18463) [#17202](https://github.com/angular/angular/issues/17202)
|
|
||||||
* Update test code to type-check under TS 2.5 ([#20175](https://github.com/angular/angular/issues/20175)) ([5ec1717](https://github.com/angular/angular/commit/5ec1717))
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **typescript:** support TypeScript 2.5 ([a9f3e2b](https://github.com/angular/angular/commit/a9f3e2b)), closes [#20175](https://github.com/angular/angular/issues/20175)
|
|
||||||
|
|
||||||
> Note, if you do `Injector.get(Token)` where `Token` has static members, you'll run into https://github.com/Microsoft/TypeScript/issues/20102 where the returned type is `{}` rather than `Token`. Use `Injector.get<Token>(Token)` to work around.
|
|
||||||
|
|
||||||
<a name="5.0.2"></a>
|
<a name="5.0.2"></a>
|
||||||
## [5.0.2](https://github.com/angular/angular/compare/5.0.1...5.0.2) (2017-11-16)
|
## [5.0.2](https://github.com/angular/angular/compare/5.0.1...5.0.2) (2017-11-16)
|
||||||
@ -150,22 +29,6 @@
|
|||||||
* **router:** 'merge' queryParamHandling strategy should be able to remove query params ([#19733](https://github.com/angular/angular/issues/19733)) ([b732fb9](https://github.com/angular/angular/commit/b732fb9)), closes [#18463](https://github.com/angular/angular/issues/18463) [#17202](https://github.com/angular/angular/issues/17202)
|
* **router:** 'merge' queryParamHandling strategy should be able to remove query params ([#19733](https://github.com/angular/angular/issues/19733)) ([b732fb9](https://github.com/angular/angular/commit/b732fb9)), closes [#18463](https://github.com/angular/angular/issues/18463) [#17202](https://github.com/angular/angular/issues/17202)
|
||||||
|
|
||||||
|
|
||||||
<a name="5.1.0-beta.0"></a>
|
|
||||||
# [5.1.0-beta.0](https://github.com/angular/angular/compare/5.0.0-rc.4...5.1.0-beta.0) (2017-11-08)
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **compiler:** don't overwrite missingTranslation's value in JIT ([#19952](https://github.com/angular/angular/issues/19952)) ([799cbb9](https://github.com/angular/angular/commit/799cbb9))
|
|
||||||
* **compiler:** report a reasonable error with invalid metadata ([#20062](https://github.com/angular/angular/issues/20062)) ([da22c48](https://github.com/angular/angular/commit/da22c48))
|
|
||||||
* **compiler-cli:** don't report emit diagnostics when `--noEmitOnError` is off ([#20063](https://github.com/angular/angular/issues/20063)) ([8639995](https://github.com/angular/angular/commit/8639995))
|
|
||||||
* **core:** `__symbol__` should return `__zone_symbol__` without zone.js loaded ([#19541](https://github.com/angular/angular/issues/19541)) ([678d1cf](https://github.com/angular/angular/commit/678d1cf))
|
|
||||||
* **core:** should support event.stopImmediatePropagation ([#19222](https://github.com/angular/angular/issues/19222)) ([7083791](https://github.com/angular/angular/commit/7083791))
|
|
||||||
* **platform-browser:** support Symbols in custom `jasmineToString()` method ([#19794](https://github.com/angular/angular/issues/19794)) ([5a6efa7](https://github.com/angular/angular/commit/5a6efa7))
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **compiler:** introduce `TestBed.overrideTemplateUsingTestingModule` ([a460066](https://github.com/angular/angular/commit/a460066)), closes [#19815](https://github.com/angular/angular/issues/19815)
|
|
||||||
|
|
||||||
|
|
||||||
<a name="5.0.1"></a>
|
<a name="5.0.1"></a>
|
||||||
## [5.0.1](https://github.com/angular/angular/compare/5.0.0...5.0.1) (2017-11-08)
|
## [5.0.1](https://github.com/angular/angular/compare/5.0.0...5.0.1) (2017-11-08)
|
||||||
|
@ -69,22 +69,21 @@ You can file new issues by filling out our [new issue form](https://github.com/a
|
|||||||
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
|
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
|
||||||
Before you submit your Pull Request (PR) consider the following guidelines:
|
Before you submit your Pull Request (PR) consider the following guidelines:
|
||||||
|
|
||||||
1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR
|
* Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR
|
||||||
that relates to your submission. You don't want to duplicate effort.
|
that relates to your submission. You don't want to duplicate effort.
|
||||||
1. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
|
* Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
|
||||||
We cannot accept code without this.
|
We cannot accept code without this.
|
||||||
1. Fork the angular/angular repo.
|
* Make your changes in a new git branch:
|
||||||
1. Make your changes in a new git branch:
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git checkout -b my-fix-branch master
|
git checkout -b my-fix-branch master
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Create your patch, **including appropriate test cases**.
|
* Create your patch, **including appropriate test cases**.
|
||||||
1. Follow our [Coding Rules](#rules).
|
* Follow our [Coding Rules](#rules).
|
||||||
1. Run the full Angular test suite, as described in the [developer documentation][dev-doc],
|
* Run the full Angular test suite, as described in the [developer documentation][dev-doc],
|
||||||
and ensure that all tests pass.
|
and ensure that all tests pass.
|
||||||
1. Commit your changes using a descriptive commit message that follows our
|
* Commit your changes using a descriptive commit message that follows our
|
||||||
[commit message conventions](#commit). Adherence to these conventions
|
[commit message conventions](#commit). Adherence to these conventions
|
||||||
is necessary because release notes are automatically generated from these messages.
|
is necessary because release notes are automatically generated from these messages.
|
||||||
|
|
||||||
@ -93,13 +92,13 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
|||||||
```
|
```
|
||||||
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
|
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
|
||||||
|
|
||||||
1. Push your branch to GitHub:
|
* Push your branch to GitHub:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git push origin my-fix-branch
|
git push origin my-fix-branch
|
||||||
```
|
```
|
||||||
|
|
||||||
1. In GitHub, send a pull request to `angular:master`.
|
* In GitHub, send a pull request to `angular:master`.
|
||||||
* If we suggest changes then:
|
* If we suggest changes then:
|
||||||
* Make the required updates.
|
* Make the required updates.
|
||||||
* Re-run the Angular test suites to ensure tests are still passing.
|
* Re-run the Angular test suites to ensure tests are still passing.
|
||||||
|
@ -5,7 +5,8 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
|||||||
git_repository(
|
git_repository(
|
||||||
name = "build_bazel_rules_nodejs",
|
name = "build_bazel_rules_nodejs",
|
||||||
remote = "https://github.com/bazelbuild/rules_nodejs.git",
|
remote = "https://github.com/bazelbuild/rules_nodejs.git",
|
||||||
commit = "0.2.1",
|
# TODO(alexeagle): use the correct tag here.
|
||||||
|
commit = "2c6243df53fd33fdab283ebdd01582e4eb815db8",
|
||||||
)
|
)
|
||||||
|
|
||||||
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories")
|
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories")
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<!-- #docregion built-in, asterisk, ngif -->
|
<!-- #docregion built-in, asterisk, ngif -->
|
||||||
<div *ngIf="hero" class="name">{{hero.name}}</div>
|
<div *ngIf="hero" >{{hero.name}}</div>
|
||||||
<!-- #enddocregion built-in, asterisk, ngif -->
|
<!-- #enddocregion built-in, asterisk, ngif -->
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
@ -51,7 +51,7 @@
|
|||||||
<p><ng-template> element</p>
|
<p><ng-template> element</p>
|
||||||
<!-- #docregion ngif-template -->
|
<!-- #docregion ngif-template -->
|
||||||
<ng-template [ngIf]="hero">
|
<ng-template [ngIf]="hero">
|
||||||
<div class="name">{{hero.name}}</div>
|
<div>{{hero.name}}</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<!-- #enddocregion ngif-template -->
|
<!-- #enddocregion ngif-template -->
|
||||||
|
|
||||||
|
@ -74,8 +74,8 @@ Generate a new project and skeleton application by running the following command
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Patience, please.
|
Patience please.
|
||||||
It takes time to set up a new project; most of it is spent installing npm packages.
|
It takes time to set up a new project, most of it spent installing npm packages.
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 85 KiB |
@ -241,12 +241,6 @@
|
|||||||
"UI Components": {
|
"UI Components": {
|
||||||
"order": 4,
|
"order": 4,
|
||||||
"resources": {
|
"resources": {
|
||||||
"IgniteUIforAngular": {
|
|
||||||
"desc": "Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps.",
|
|
||||||
"rev": true,
|
|
||||||
"title": "Ignite UI for Angular",
|
|
||||||
"url": "https://www.infragistics.com/products/ignite-ui-angular"
|
|
||||||
},
|
|
||||||
"DevExtreme": {
|
"DevExtreme": {
|
||||||
"desc": "50+ UI components including data grid, pivot grid, scheduler, charts, editors, maps and other multi-purpose controls for creating highly responsive web applications for touch devices and traditional desktops.",
|
"desc": "50+ UI components including data grid, pivot grid, scheduler, charts, editors, maps and other multi-purpose controls for creating highly responsive web applications for touch devices and traditional desktops.",
|
||||||
"rev": true,
|
"rev": true,
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
The Tour of Heroes `HeroesComponent` is currently getting and displaying fake data.
|
The Tour of Heroes `HeroesComponent` is currently getting and displaying fake data.
|
||||||
|
|
||||||
After the refactoring in this tutorial, `HeroesComponent` will be lean and focused on supporting the view.
|
After the refactoring in this tutorial, `HeroesComponent` will be lean and focused on supporting the view.
|
||||||
It will also be easier to unit-test with a mock service.
|
It will also be easier to unit-test with a mock services.
|
||||||
|
|
||||||
## Why services
|
## Why services
|
||||||
|
|
||||||
|
@ -80,6 +80,8 @@ describe('site App', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO(https://github.com/angular/angular/issues/19785): Activate this again
|
||||||
|
// once it is no more flaky.
|
||||||
describe('google analytics', () => {
|
describe('google analytics', () => {
|
||||||
|
|
||||||
it('should call ga with initial URL', done => {
|
it('should call ga with initial URL', done => {
|
||||||
|
@ -29,7 +29,10 @@ export class SitePage {
|
|||||||
locationPath() { return browser.executeScript('return document.location.pathname') as promise.Promise<string>; }
|
locationPath() { return browser.executeScript('return document.location.pathname') as promise.Promise<string>; }
|
||||||
|
|
||||||
navigateTo(pageUrl = '') {
|
navigateTo(pageUrl = '') {
|
||||||
return browser.get('/' + pageUrl);
|
return browser.get('/' + pageUrl)
|
||||||
|
// We need to tell the index.html not to load the real analytics library
|
||||||
|
// See the GA snippet in index.html
|
||||||
|
.then(() => browser.executeScript('sessionStorage.setItem("__e2e__", true);'));
|
||||||
}
|
}
|
||||||
|
|
||||||
getDocViewerText() {
|
getDocViewerText() {
|
||||||
|
@ -100,7 +100,7 @@
|
|||||||
"cross-spawn": "^5.1.0",
|
"cross-spawn": "^5.1.0",
|
||||||
"css-selector-parser": "^1.3.0",
|
"css-selector-parser": "^1.3.0",
|
||||||
"dgeni": "^0.4.7",
|
"dgeni": "^0.4.7",
|
||||||
"dgeni-packages": "0.22.1",
|
"dgeni-packages": "0.22.0",
|
||||||
"entities": "^1.1.1",
|
"entities": "^1.1.1",
|
||||||
"eslint": "^3.19.0",
|
"eslint": "^3.19.0",
|
||||||
"eslint-plugin-jasmine": "^2.2.0",
|
"eslint-plugin-jasmine": "^2.2.0",
|
||||||
|
@ -34,13 +34,11 @@
|
|||||||
|
|
||||||
<!-- Google Analytics -->
|
<!-- Google Analytics -->
|
||||||
<script>
|
<script>
|
||||||
// Note this is a customised version of the GA tracking snippet
|
// Note this is a customised version of the GA tracking snippet to aid e2e testing
|
||||||
// See the comments below for more info
|
// See the bit between /**/.../**/
|
||||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;
|
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;/**/i.sessionStorage.__e2e__||/**/m.parentNode.insertBefore(a,m)
|
||||||
~i.name.indexOf('NG_DEFER_BOOTSTRAP')|| // only load library if not running e2e tests
|
|
||||||
m.parentNode.insertBefore(a,m)
|
|
||||||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||||
</script>
|
</script>
|
||||||
<!-- End Google Analytics -->
|
<!-- End Google Analytics -->
|
||||||
|
@ -62,7 +62,7 @@ class ExampleZipper {
|
|||||||
let exampleZipName;
|
let exampleZipName;
|
||||||
const exampleType = this._getExampleType(path.join(sourceDirName, relativeDirName));
|
const exampleType = this._getExampleType(path.join(sourceDirName, relativeDirName));
|
||||||
if (relativeDirName.indexOf('/') !== -1) { // Special example
|
if (relativeDirName.indexOf('/') !== -1) { // Special example
|
||||||
exampleZipName = relativeDirName.split('/').join('-');
|
exampleZipName = relativeDirName.split('/')[0];
|
||||||
} else {
|
} else {
|
||||||
exampleZipName = jsonFileName.replace(/(plnkr|zipper).json/, relativeDirName);
|
exampleZipName = jsonFileName.replace(/(plnkr|zipper).json/, relativeDirName);
|
||||||
}
|
}
|
||||||
|
@ -26,13 +26,13 @@
|
|||||||
"zone.js": "^0.8.14"
|
"zone.js": "^0.8.14"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/cli": "1.5.4",
|
"@angular/cli": "1.5.0",
|
||||||
"@angular/compiler-cli": "^5.0.0",
|
"@angular/compiler-cli": "^5.0.0",
|
||||||
"@angular/language-service": "^5.0.0",
|
"@angular/language-service": "^5.0.0",
|
||||||
"@types/jasmine": "~2.5.53",
|
"@types/jasmine": "~2.5.53",
|
||||||
"@types/jasminewd2": "~2.0.2",
|
"@types/jasminewd2": "~2.0.2",
|
||||||
"@types/node": "~6.0.60",
|
"@types/node": "~6.0.60",
|
||||||
"codelyzer": "^4.0.1",
|
"codelyzer": "~3.2.0",
|
||||||
"jasmine-core": "~2.6.2",
|
"jasmine-core": "~2.6.2",
|
||||||
"jasmine-spec-reporter": "~4.1.0",
|
"jasmine-spec-reporter": "~4.1.0",
|
||||||
"karma": "~1.7.0",
|
"karma": "~1.7.0",
|
||||||
|
@ -2287,9 +2287,9 @@ devtools-timeline-model@1.1.6:
|
|||||||
chrome-devtools-frontend "1.0.401423"
|
chrome-devtools-frontend "1.0.401423"
|
||||||
resolve "1.1.7"
|
resolve "1.1.7"
|
||||||
|
|
||||||
dgeni-packages@0.22.1:
|
dgeni-packages@0.22.0:
|
||||||
version "0.22.1"
|
version "0.22.0"
|
||||||
resolved "https://registry.yarnpkg.com/dgeni-packages/-/dgeni-packages-0.22.1.tgz#c4587a765689c4c9d48ed661517ed2249403bfb2"
|
resolved "https://registry.yarnpkg.com/dgeni-packages/-/dgeni-packages-0.22.0.tgz#7ed07af9074f6547847256c1a65b488a5a17ad03"
|
||||||
dependencies:
|
dependencies:
|
||||||
canonical-path "0.0.2"
|
canonical-path "0.0.2"
|
||||||
catharsis "^0.8.1"
|
catharsis "^0.8.1"
|
||||||
|
@ -3,7 +3,7 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
|||||||
git_repository(
|
git_repository(
|
||||||
name = "build_bazel_rules_nodejs",
|
name = "build_bazel_rules_nodejs",
|
||||||
remote = "https://github.com/bazelbuild/rules_nodejs.git",
|
remote = "https://github.com/bazelbuild/rules_nodejs.git",
|
||||||
tag = "0.2.1",
|
tag = "0.0.2",
|
||||||
)
|
)
|
||||||
|
|
||||||
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories")
|
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories")
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import { AppPage } from './app.po';
|
|
||||||
|
|
||||||
describe('dynamic-compiler App', () => {
|
|
||||||
let page: AppPage;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
page = new AppPage();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display welcome message', () => {
|
|
||||||
page.navigateTo();
|
|
||||||
expect(page.getParagraphText()).toEqual('Hello world!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display lazy-loaded component', () => {
|
|
||||||
page.navigateTo();
|
|
||||||
expect(page.getLazyLoadedText()).toEqual('Lazy-loaded component!');
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,16 +0,0 @@
|
|||||||
import {browser, by, element, protractor} from 'protractor';
|
|
||||||
|
|
||||||
export class AppPage {
|
|
||||||
navigateTo() {
|
|
||||||
return browser.get('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
getParagraphText() {
|
|
||||||
return element(by.css('app-root h1')).getText();
|
|
||||||
}
|
|
||||||
|
|
||||||
getLazyLoadedText() {
|
|
||||||
const el = element(by.css('app-root lazy-component'));
|
|
||||||
return browser.wait(protractor.ExpectedConditions.presenceOf(el)).then(() => el.getText(), err => el.getText());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"open": false,
|
|
||||||
"logLevel": "silent",
|
|
||||||
"port": 8080,
|
|
||||||
"server": {
|
|
||||||
"baseDir": ".",
|
|
||||||
"routes": {
|
|
||||||
"/dist": "dist",
|
|
||||||
"/node_modules": "node_modules"
|
|
||||||
},
|
|
||||||
"middleware": {
|
|
||||||
"0": null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
exports.config = {
|
|
||||||
specs: [
|
|
||||||
'../dist/e2e/*.e2e-spec.js'
|
|
||||||
],
|
|
||||||
capabilities: {
|
|
||||||
browserName: 'chrome',
|
|
||||||
chromeOptions: {
|
|
||||||
args: ['--no-sandbox'],
|
|
||||||
binary: process.env.CHROME_BIN,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
directConnect: true,
|
|
||||||
baseUrl: 'http://localhost:8080/',
|
|
||||||
framework: 'jasmine',
|
|
||||||
useAllAngular2AppRoots: true
|
|
||||||
};
|
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "../dist/e2e",
|
|
||||||
"types": ["jasmine"],
|
|
||||||
"skipLibCheck": true
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title></title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<app-root></app-root>
|
|
||||||
<script src="/node_modules/zone.js/dist/zone.js"></script>
|
|
||||||
<script src="/node_modules/reflect-metadata/Reflect.js"></script>
|
|
||||||
<script src="/node_modules/systemjs/dist/system.js"></script>
|
|
||||||
<script src="/dist/bundle.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "dynamic-compiler",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"build": "npm run clean && npm run ngc && npm run rollup && npm run rollup:lazy && npm run es5 && npm run es5:lazy",
|
|
||||||
"clean": "rm -rf dist",
|
|
||||||
"es5": "tsc --target es5 --skipLibCheck --allowJs dist/bundle.es2015.js --out dist/bundle.js",
|
|
||||||
"es5:lazy": "tsc --target es5 --skipLibCheck --allowJs dist/lazy.bundle.es2015.js --out dist/lazy.bundle.js",
|
|
||||||
"ngc": "ngc -p tsconfig.json",
|
|
||||||
"rollup": "rollup -f iife -c rollup.config.js -o dist/bundle.es2015.js",
|
|
||||||
"rollup:lazy": "rollup -f cjs -c rollup.lazy.config.js -o dist/lazy.bundle.es2015.js",
|
|
||||||
"postinstall": "webdriver-manager update --gecko false",
|
|
||||||
"preprotractor": "tsc -p e2e",
|
|
||||||
"protractor": "protractor e2e/protractor.config.js",
|
|
||||||
"serve": "lite-server -c e2e/browser.config.json",
|
|
||||||
"test": "npm run build && concurrently \"yarn run serve\" \"yarn run protractor\" --kill-others --success first"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/jasmine": "file:../../node_modules/@types/jasmine",
|
|
||||||
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
|
||||||
"concurrently": "3.4.0",
|
|
||||||
"lite-server": "2.2.2",
|
|
||||||
"protractor": "file:../../node_modules/protractor",
|
|
||||||
"rollup": "file:../../node_modules/rollup",
|
|
||||||
"rollup-plugin-commonjs": "file:../../node_modules/rollup-plugin-commonjs",
|
|
||||||
"rollup-plugin-node-resolve": "file:../../node_modules/rollup-plugin-node-resolve",
|
|
||||||
"typescript": "file:../../node_modules/typescript"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@angular/animations": "file:../../dist/packages-dist/animations",
|
|
||||||
"@angular/common": "file:../../dist/packages-dist/common",
|
|
||||||
"@angular/compiler": "file:../../dist/packages-dist/compiler",
|
|
||||||
"@angular/core": "file:../../dist/packages-dist/core",
|
|
||||||
"@angular/platform-browser": "file:../../dist/packages-dist/platform-browser",
|
|
||||||
"@angular/platform-browser-dynamic": "file:../../dist/packages-dist/platform-browser-dynamic",
|
|
||||||
"@angular/platform-server": "file:../../dist/packages-dist/platform-server",
|
|
||||||
"core-js": "file:../../node_modules/core-js",
|
|
||||||
"rxjs": "file:../../node_modules/rxjs",
|
|
||||||
"systemjs": "file:../../node_modules/systemjs",
|
|
||||||
"zone.js": "file:../../node_modules/zone.js"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
import nodeResolve from 'rollup-plugin-node-resolve';
|
|
||||||
import commonjs from 'rollup-plugin-commonjs';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
entry: 'dist/src/main.js',
|
|
||||||
sourceMap: true,
|
|
||||||
treeshake: true,
|
|
||||||
moduleName: 'main',
|
|
||||||
plugins: [
|
|
||||||
commonjs({
|
|
||||||
include: 'node_modules/**'
|
|
||||||
}),
|
|
||||||
nodeResolve({
|
|
||||||
jsnext: true, main: true, module: true
|
|
||||||
})
|
|
||||||
]
|
|
||||||
};
|
|
@ -1,19 +0,0 @@
|
|||||||
import nodeResolve from 'rollup-plugin-node-resolve';
|
|
||||||
import commonjs from 'rollup-plugin-commonjs';
|
|
||||||
|
|
||||||
// a real app should make a common bundle for libraries instead of bundling them
|
|
||||||
// in both the main module & the lazy module, but we don't care about size here
|
|
||||||
export default {
|
|
||||||
entry: 'dist/src/lazy.module.js',
|
|
||||||
sourceMap: true,
|
|
||||||
treeshake: true,
|
|
||||||
moduleName: 'lazy',
|
|
||||||
plugins: [
|
|
||||||
commonjs({
|
|
||||||
include: 'node_modules/**'
|
|
||||||
}),
|
|
||||||
nodeResolve({
|
|
||||||
jsnext: true, main: true, module: true
|
|
||||||
})
|
|
||||||
]
|
|
||||||
};
|
|
@ -1,27 +0,0 @@
|
|||||||
import {AfterViewInit, Compiler, Component, ViewChild, ViewContainerRef} from '@angular/core';
|
|
||||||
|
|
||||||
declare var System: any;
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-root',
|
|
||||||
template: `
|
|
||||||
<h1>Hello world!</h1>
|
|
||||||
<div #vc></div>
|
|
||||||
`,
|
|
||||||
})
|
|
||||||
export class AppComponent implements AfterViewInit {
|
|
||||||
@ViewChild('vc', {read: ViewContainerRef}) container: ViewContainerRef;
|
|
||||||
|
|
||||||
constructor(private compiler: Compiler) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ngAfterViewInit() {
|
|
||||||
System.import('./dist/lazy.bundle.js').then((module: any) => {
|
|
||||||
this.compiler.compileModuleAndAllComponentsAsync(module.LazyModule)
|
|
||||||
.then((compiled) => {
|
|
||||||
const factory = compiled.componentFactories[0];
|
|
||||||
this.container.createComponent(factory);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
import {Compiler, COMPILER_OPTIONS, CompilerFactory, NgModule} from '@angular/core';
|
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
|
||||||
import {JitCompilerFactory} from '@angular/platform-browser-dynamic';
|
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
|
||||||
|
|
||||||
export function createCompiler(compilerFactory: CompilerFactory) {
|
|
||||||
return compilerFactory.createCompiler();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [BrowserModule],
|
|
||||||
bootstrap: [AppComponent],
|
|
||||||
declarations: [AppComponent],
|
|
||||||
providers: [
|
|
||||||
{provide: COMPILER_OPTIONS, useValue: {}, multi: true},
|
|
||||||
{provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS]},
|
|
||||||
{provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory]}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
export class AppModule {}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
|||||||
import {NgModule} from "@angular/core";
|
|
||||||
import {Component} from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'lazy-component',
|
|
||||||
template: 'Lazy-loaded component!'
|
|
||||||
})
|
|
||||||
export class LazyComponent {
|
|
||||||
constructor() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [LazyComponent]
|
|
||||||
})
|
|
||||||
export class LazyModule {
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
import { enableProdMode } from '@angular/core';
|
|
||||||
import { platformBrowser } from '@angular/platform-browser';
|
|
||||||
|
|
||||||
import { AppModuleNgFactory } from './app.module.ngfactory';
|
|
||||||
|
|
||||||
enableProdMode();
|
|
||||||
|
|
||||||
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
|
|
@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es2015",
|
|
||||||
"module": "es2015",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"declaration": false,
|
|
||||||
"removeComments": true,
|
|
||||||
"noLib": false,
|
|
||||||
"emitDecoratorMetadata": true,
|
|
||||||
"experimentalDecorators": true,
|
|
||||||
"lib": ["es6", "es2015", "dom"],
|
|
||||||
"sourceMap": true,
|
|
||||||
"pretty": true,
|
|
||||||
"allowUnreachableCode": false,
|
|
||||||
"allowUnusedLabels": false,
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"noImplicitReturns": true,
|
|
||||||
"noImplicitUseStrict": false,
|
|
||||||
"noFallthroughCasesInSwitch": true,
|
|
||||||
"outDir": "./dist",
|
|
||||||
"types": [
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"src/main.ts",
|
|
||||||
"src/lazy.module.ts"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "angular-integration",
|
"name": "angular-integration",
|
||||||
"description": "Assert that users with TypeScript 2.4 can type-check an Angular application",
|
"description": "Assert that users with TypeScript 2.2 can type-check an Angular application",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -18,7 +18,7 @@
|
|||||||
"@angular/upgrade": "file:../../dist/packages-dist/upgrade",
|
"@angular/upgrade": "file:../../dist/packages-dist/upgrade",
|
||||||
"@types/jasmine": "2.5.41",
|
"@types/jasmine": "2.5.41",
|
||||||
"rxjs": "file:../../node_modules/rxjs",
|
"rxjs": "file:../../node_modules/rxjs",
|
||||||
"typescript": "2.4.x",
|
"typescript": "file:../../node_modules/typescript",
|
||||||
"zone.js": "file:../../node_modules/zone.js"
|
"zone.js": "file:../../node_modules/zone.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
import * as compiler from '@angular/compiler';
|
|
||||||
import * as compilerTesting from '@angular/compiler/testing';
|
|
||||||
import * as core from '@angular/core';
|
|
||||||
import * as coreTesting from '@angular/core/testing';
|
|
||||||
import * as forms from '@angular/forms';
|
|
||||||
import * as http from '@angular/http';
|
|
||||||
import * as httpTesting from '@angular/http/testing';
|
|
||||||
import * as platformBrowserDynamic from '@angular/platform-browser-dynamic';
|
|
||||||
import * as platformBrowser from '@angular/platform-browser';
|
|
||||||
import * as platformBrowserTesting from '@angular/platform-browser/testing';
|
|
||||||
import * as platformServer from '@angular/platform-server';
|
|
||||||
import * as platformServerTesting from '@angular/platform-server/testing';
|
|
||||||
import * as router from '@angular/router';
|
|
||||||
import * as routerTesting from '@angular/router/testing';
|
|
||||||
import * as upgrade from '@angular/upgrade';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
compiler,
|
|
||||||
compilerTesting,
|
|
||||||
core,
|
|
||||||
coreTesting,
|
|
||||||
forms,
|
|
||||||
http,
|
|
||||||
httpTesting,
|
|
||||||
platformBrowser,
|
|
||||||
platformBrowserTesting,
|
|
||||||
platformBrowserDynamic,
|
|
||||||
platformServer,
|
|
||||||
platformServerTesting,
|
|
||||||
router,
|
|
||||||
routerTesting,
|
|
||||||
upgrade
|
|
||||||
};
|
|
@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "angular-integration",
|
|
||||||
"description": "Assert that users with TypeScript 2.5 can type-check an Angular application",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@angular/animations": "file:../../dist/packages-dist/animations",
|
|
||||||
"@angular/common": "file:../../dist/packages-dist/common",
|
|
||||||
"@angular/compiler": "file:../../dist/packages-dist/compiler",
|
|
||||||
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
|
||||||
"@angular/core": "file:../../dist/packages-dist/core",
|
|
||||||
"@angular/forms": "file:../../dist/packages-dist/forms",
|
|
||||||
"@angular/http": "file:../../dist/packages-dist/http",
|
|
||||||
"@angular/platform-browser": "file:../../dist/packages-dist/platform-browser",
|
|
||||||
"@angular/platform-browser-dynamic": "file:../../dist/packages-dist/platform-browser-dynamic",
|
|
||||||
"@angular/platform-server": "file:../../dist/packages-dist/platform-server",
|
|
||||||
"@angular/router": "file:../../dist/packages-dist/router",
|
|
||||||
"@angular/upgrade": "file:../../dist/packages-dist/upgrade",
|
|
||||||
"@types/jasmine": "2.5.41",
|
|
||||||
"rxjs": "file:../../node_modules/rxjs",
|
|
||||||
"typescript": "2.5.x",
|
|
||||||
"zone.js": "file:../../node_modules/zone.js"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "tsc"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"emitDecoratorMetadata": true,
|
|
||||||
"experimentalDecorators": true,
|
|
||||||
"module": "commonjs",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"outDir": "../../dist/typings_test_ts25/",
|
|
||||||
"rootDir": ".",
|
|
||||||
"target": "es5",
|
|
||||||
"lib": [
|
|
||||||
"es5",
|
|
||||||
"dom",
|
|
||||||
"es2015.collection",
|
|
||||||
"es2015.iterable",
|
|
||||||
"es2015.promise"
|
|
||||||
],
|
|
||||||
"types": [],
|
|
||||||
"strictNullChecks": true
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"include-all.ts",
|
|
||||||
"node_modules/@types/jasmine/index.d.ts"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "angular-srcs",
|
"name": "angular-srcs",
|
||||||
"version": "5.1.0-rc.1",
|
"version": "5.0.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",
|
||||||
@ -32,7 +32,7 @@
|
|||||||
"fsevents": "1.1.2"
|
"fsevents": "1.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@bazel/typescript": "0.3.2",
|
"@bazel/typescript": "0.2.x",
|
||||||
"@types/angularjs": "1.5.14-alpha",
|
"@types/angularjs": "1.5.14-alpha",
|
||||||
"@types/base64-js": "1.2.5",
|
"@types/base64-js": "1.2.5",
|
||||||
"@types/chokidar": "1.7.3",
|
"@types/chokidar": "1.7.3",
|
||||||
@ -95,10 +95,10 @@
|
|||||||
"source-map-support": "0.4.18",
|
"source-map-support": "0.4.18",
|
||||||
"systemjs": "0.18.10",
|
"systemjs": "0.18.10",
|
||||||
"ts-api-guardian": "0.2.2",
|
"ts-api-guardian": "0.2.2",
|
||||||
"tsickle": "0.25.5",
|
"tsickle": "0.24.x",
|
||||||
"tslint": "5.7.0",
|
"tslint": "5.7.0",
|
||||||
"tslint-eslint-rules": "4.1.1",
|
"tslint-eslint-rules": "4.1.1",
|
||||||
"typescript": "2.5.x",
|
"typescript": "2.4.2",
|
||||||
"uglify-js": "2.8.29",
|
"uglify-js": "2.8.29",
|
||||||
"universal-analytics": "0.4.15",
|
"universal-analytics": "0.4.15",
|
||||||
"vlq": "0.2.2",
|
"vlq": "0.2.2",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
import {AnimationMetadata, AnimationMetadataType, AnimationOptions, ɵStyleData} from '@angular/animations';
|
import {AnimationMetadata, AnimationMetadataType, AnimationOptions, ɵStyleData} from '@angular/animations';
|
||||||
|
|
||||||
import {AnimationDriver} from '../render/animation_driver';
|
import {AnimationDriver} from '../render/animation_driver';
|
||||||
import {ENTER_CLASSNAME, LEAVE_CLASSNAME, normalizeStyles} from '../util';
|
import {normalizeStyles} from '../util';
|
||||||
|
|
||||||
import {Ast} from './animation_ast';
|
import {Ast} from './animation_ast';
|
||||||
import {buildAnimationAst} from './animation_ast_builder';
|
import {buildAnimationAst} from './animation_ast_builder';
|
||||||
@ -39,8 +39,7 @@ export class Animation {
|
|||||||
const errors: any = [];
|
const errors: any = [];
|
||||||
subInstructions = subInstructions || new ElementInstructionMap();
|
subInstructions = subInstructions || new ElementInstructionMap();
|
||||||
const result = buildAnimationTimelines(
|
const result = buildAnimationTimelines(
|
||||||
this._driver, element, this._animationAst, ENTER_CLASSNAME, LEAVE_CLASSNAME, start, dest,
|
this._driver, element, this._animationAst, start, dest, options, subInstructions, errors);
|
||||||
options, subInstructions, errors);
|
|
||||||
if (errors.length) {
|
if (errors.length) {
|
||||||
const errorMessage = `animation building failed:\n${errors.join("\n")}`;
|
const errorMessage = `animation building failed:\n${errors.join("\n")}`;
|
||||||
throw new Error(errorMessage);
|
throw new Error(errorMessage);
|
||||||
|
@ -60,6 +60,10 @@ export function buildAnimationAst(
|
|||||||
return new AnimationAstBuilderVisitor(driver).build(metadata, errors);
|
return new AnimationAstBuilderVisitor(driver).build(metadata, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LEAVE_TOKEN = ':leave';
|
||||||
|
const LEAVE_TOKEN_REGEX = new RegExp(LEAVE_TOKEN, 'g');
|
||||||
|
const ENTER_TOKEN = ':enter';
|
||||||
|
const ENTER_TOKEN_REGEX = new RegExp(ENTER_TOKEN, 'g');
|
||||||
const ROOT_SELECTOR = '';
|
const ROOT_SELECTOR = '';
|
||||||
|
|
||||||
export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
|
export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
|
||||||
@ -474,8 +478,9 @@ function normalizeSelector(selector: string): [string, boolean] {
|
|||||||
selector = selector.replace(SELF_TOKEN_REGEX, '');
|
selector = selector.replace(SELF_TOKEN_REGEX, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
// the :enter and :leave selectors are filled in at runtime during timeline building
|
selector = selector.replace(ENTER_TOKEN_REGEX, ENTER_SELECTOR)
|
||||||
selector = selector.replace(/@\*/g, NG_TRIGGER_SELECTOR)
|
.replace(LEAVE_TOKEN_REGEX, LEAVE_SELECTOR)
|
||||||
|
.replace(/@\*/g, NG_TRIGGER_SELECTOR)
|
||||||
.replace(/@\w+/g, match => NG_TRIGGER_SELECTOR + '-' + match.substr(1))
|
.replace(/@\w+/g, match => NG_TRIGGER_SELECTOR + '-' + match.substr(1))
|
||||||
.replace(/:animating/g, NG_ANIMATING_SELECTOR);
|
.replace(/:animating/g, NG_ANIMATING_SELECTOR);
|
||||||
|
|
||||||
|
@ -15,10 +15,6 @@ import {AnimationTimelineInstruction, createTimelineInstruction} from './animati
|
|||||||
import {ElementInstructionMap} from './element_instruction_map';
|
import {ElementInstructionMap} from './element_instruction_map';
|
||||||
|
|
||||||
const ONE_FRAME_IN_MILLISECONDS = 1;
|
const ONE_FRAME_IN_MILLISECONDS = 1;
|
||||||
const ENTER_TOKEN = ':enter';
|
|
||||||
const ENTER_TOKEN_REGEX = new RegExp(ENTER_TOKEN, 'g');
|
|
||||||
const LEAVE_TOKEN = ':leave';
|
|
||||||
const LEAVE_TOKEN_REGEX = new RegExp(LEAVE_TOKEN, 'g');
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The code within this file aims to generate web-animations-compatible keyframes from Angular's
|
* The code within this file aims to generate web-animations-compatible keyframes from Angular's
|
||||||
@ -106,23 +102,19 @@ const LEAVE_TOKEN_REGEX = new RegExp(LEAVE_TOKEN, 'g');
|
|||||||
*/
|
*/
|
||||||
export function buildAnimationTimelines(
|
export function buildAnimationTimelines(
|
||||||
driver: AnimationDriver, rootElement: any, ast: Ast<AnimationMetadataType>,
|
driver: AnimationDriver, rootElement: any, ast: Ast<AnimationMetadataType>,
|
||||||
enterClassName: string, leaveClassName: string, startingStyles: ɵStyleData = {},
|
startingStyles: ɵStyleData = {}, finalStyles: ɵStyleData = {}, options: AnimationOptions,
|
||||||
finalStyles: ɵStyleData = {}, options: AnimationOptions,
|
|
||||||
subInstructions?: ElementInstructionMap, errors: any[] = []): AnimationTimelineInstruction[] {
|
subInstructions?: ElementInstructionMap, errors: any[] = []): AnimationTimelineInstruction[] {
|
||||||
return new AnimationTimelineBuilderVisitor().buildKeyframes(
|
return new AnimationTimelineBuilderVisitor().buildKeyframes(
|
||||||
driver, rootElement, ast, enterClassName, leaveClassName, startingStyles, finalStyles,
|
driver, rootElement, ast, startingStyles, finalStyles, options, subInstructions, errors);
|
||||||
options, subInstructions, errors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AnimationTimelineBuilderVisitor implements AstVisitor {
|
export class AnimationTimelineBuilderVisitor implements AstVisitor {
|
||||||
buildKeyframes(
|
buildKeyframes(
|
||||||
driver: AnimationDriver, rootElement: any, ast: Ast<AnimationMetadataType>,
|
driver: AnimationDriver, rootElement: any, ast: Ast<AnimationMetadataType>,
|
||||||
enterClassName: string, leaveClassName: string, startingStyles: ɵStyleData,
|
startingStyles: ɵStyleData, finalStyles: ɵStyleData, options: AnimationOptions,
|
||||||
finalStyles: ɵStyleData, options: AnimationOptions, subInstructions?: ElementInstructionMap,
|
subInstructions?: ElementInstructionMap, errors: any[] = []): AnimationTimelineInstruction[] {
|
||||||
errors: any[] = []): AnimationTimelineInstruction[] {
|
|
||||||
subInstructions = subInstructions || new ElementInstructionMap();
|
subInstructions = subInstructions || new ElementInstructionMap();
|
||||||
const context = new AnimationTimelineContext(
|
const context = new AnimationTimelineContext(driver, rootElement, subInstructions, errors, []);
|
||||||
driver, rootElement, subInstructions, enterClassName, leaveClassName, errors, []);
|
|
||||||
context.options = options;
|
context.options = options;
|
||||||
context.currentTimeline.setStyles([startingStyles], null, context.errors, options);
|
context.currentTimeline.setStyles([startingStyles], null, context.errors, options);
|
||||||
|
|
||||||
@ -453,9 +445,8 @@ export class AnimationTimelineContext {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _driver: AnimationDriver, public element: any,
|
private _driver: AnimationDriver, public element: any,
|
||||||
public subInstructions: ElementInstructionMap, private _enterClassName: string,
|
public subInstructions: ElementInstructionMap, public errors: any[],
|
||||||
private _leaveClassName: string, public errors: any[], public timelines: TimelineBuilder[],
|
public timelines: TimelineBuilder[], initialTimeline?: TimelineBuilder) {
|
||||||
initialTimeline?: TimelineBuilder) {
|
|
||||||
this.currentTimeline = initialTimeline || new TimelineBuilder(this._driver, element, 0);
|
this.currentTimeline = initialTimeline || new TimelineBuilder(this._driver, element, 0);
|
||||||
timelines.push(this.currentTimeline);
|
timelines.push(this.currentTimeline);
|
||||||
}
|
}
|
||||||
@ -508,8 +499,8 @@ export class AnimationTimelineContext {
|
|||||||
AnimationTimelineContext {
|
AnimationTimelineContext {
|
||||||
const target = element || this.element;
|
const target = element || this.element;
|
||||||
const context = new AnimationTimelineContext(
|
const context = new AnimationTimelineContext(
|
||||||
this._driver, target, this.subInstructions, this._enterClassName, this._leaveClassName,
|
this._driver, target, this.subInstructions, this.errors, this.timelines,
|
||||||
this.errors, this.timelines, this.currentTimeline.fork(target, newTime || 0));
|
this.currentTimeline.fork(target, newTime || 0));
|
||||||
context.previousNode = this.previousNode;
|
context.previousNode = this.previousNode;
|
||||||
context.currentAnimateTimings = this.currentAnimateTimings;
|
context.currentAnimateTimings = this.currentAnimateTimings;
|
||||||
|
|
||||||
@ -564,8 +555,6 @@ export class AnimationTimelineContext {
|
|||||||
results.push(this.element);
|
results.push(this.element);
|
||||||
}
|
}
|
||||||
if (selector.length > 0) { // if :self is only used then the selector is empty
|
if (selector.length > 0) { // if :self is only used then the selector is empty
|
||||||
selector = selector.replace(ENTER_TOKEN_REGEX, '.' + this._enterClassName);
|
|
||||||
selector = selector.replace(LEAVE_TOKEN_REGEX, '.' + this._leaveClassName);
|
|
||||||
const multi = limit != 1;
|
const multi = limit != 1;
|
||||||
let elements = this._driver.query(this.element, selector, multi);
|
let elements = this._driver.query(this.element, selector, multi);
|
||||||
if (limit !== 0) {
|
if (limit !== 0) {
|
||||||
|
@ -37,8 +37,7 @@ export class AnimationTransitionFactory {
|
|||||||
|
|
||||||
build(
|
build(
|
||||||
driver: AnimationDriver, element: any, currentState: any, nextState: any,
|
driver: AnimationDriver, element: any, currentState: any, nextState: any,
|
||||||
enterClassName: string, leaveClassName: string, currentOptions?: AnimationOptions,
|
currentOptions?: AnimationOptions, nextOptions?: AnimationOptions,
|
||||||
nextOptions?: AnimationOptions,
|
|
||||||
subInstructions?: ElementInstructionMap): AnimationTransitionInstruction {
|
subInstructions?: ElementInstructionMap): AnimationTransitionInstruction {
|
||||||
const errors: any[] = [];
|
const errors: any[] = [];
|
||||||
|
|
||||||
@ -56,8 +55,8 @@ export class AnimationTransitionFactory {
|
|||||||
const animationOptions = {params: {...transitionAnimationParams, ...nextAnimationParams}};
|
const animationOptions = {params: {...transitionAnimationParams, ...nextAnimationParams}};
|
||||||
|
|
||||||
const timelines = buildAnimationTimelines(
|
const timelines = buildAnimationTimelines(
|
||||||
driver, element, this.ast.animation, enterClassName, leaveClassName, currentStateStyles,
|
driver, element, this.ast.animation, currentStateStyles, nextStateStyles, animationOptions,
|
||||||
nextStateStyles, animationOptions, subInstructions, errors);
|
subInstructions, errors);
|
||||||
|
|
||||||
if (errors.length) {
|
if (errors.length) {
|
||||||
return createTransitionInstruction(
|
return createTransitionInstruction(
|
||||||
|
@ -13,7 +13,6 @@ import {buildAnimationTimelines} from '../dsl/animation_timeline_builder';
|
|||||||
import {AnimationTimelineInstruction} from '../dsl/animation_timeline_instruction';
|
import {AnimationTimelineInstruction} from '../dsl/animation_timeline_instruction';
|
||||||
import {ElementInstructionMap} from '../dsl/element_instruction_map';
|
import {ElementInstructionMap} from '../dsl/element_instruction_map';
|
||||||
import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_style_normalizer';
|
import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_style_normalizer';
|
||||||
import {ENTER_CLASSNAME, LEAVE_CLASSNAME} from '../util';
|
|
||||||
|
|
||||||
import {AnimationDriver} from './animation_driver';
|
import {AnimationDriver} from './animation_driver';
|
||||||
import {getOrSetAsInMap, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer} from './shared';
|
import {getOrSetAsInMap, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer} from './shared';
|
||||||
@ -56,8 +55,7 @@ export class TimelineAnimationEngine {
|
|||||||
|
|
||||||
if (ast) {
|
if (ast) {
|
||||||
instructions = buildAnimationTimelines(
|
instructions = buildAnimationTimelines(
|
||||||
this._driver, element, ast, ENTER_CLASSNAME, LEAVE_CLASSNAME, {}, {}, options,
|
this._driver, element, ast, {}, {}, options, EMPTY_INSTRUCTION_MAP, errors);
|
||||||
EMPTY_INSTRUCTION_MAP, errors);
|
|
||||||
instructions.forEach(inst => {
|
instructions.forEach(inst => {
|
||||||
const styles = getOrSetAsInMap(autoStylesMap, inst.element, {});
|
const styles = getOrSetAsInMap(autoStylesMap, inst.element, {});
|
||||||
inst.postStyleProps.forEach(prop => styles[prop] = null);
|
inst.postStyleProps.forEach(prop => styles[prop] = null);
|
||||||
|
@ -13,7 +13,7 @@ import {AnimationTransitionInstruction} from '../dsl/animation_transition_instru
|
|||||||
import {AnimationTrigger} from '../dsl/animation_trigger';
|
import {AnimationTrigger} from '../dsl/animation_trigger';
|
||||||
import {ElementInstructionMap} from '../dsl/element_instruction_map';
|
import {ElementInstructionMap} from '../dsl/element_instruction_map';
|
||||||
import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_style_normalizer';
|
import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_style_normalizer';
|
||||||
import {ENTER_CLASSNAME, LEAVE_CLASSNAME, NG_ANIMATING_CLASSNAME, NG_ANIMATING_SELECTOR, NG_TRIGGER_CLASSNAME, NG_TRIGGER_SELECTOR, copyObj, eraseStyles, iteratorToArray, setStyles} from '../util';
|
import {ENTER_CLASSNAME, LEAVE_CLASSNAME, NG_ANIMATING_CLASSNAME, NG_ANIMATING_SELECTOR, NG_TRIGGER_CLASSNAME, NG_TRIGGER_SELECTOR, copyObj, eraseStyles, setStyles} from '../util';
|
||||||
|
|
||||||
import {AnimationDriver} from './animation_driver';
|
import {AnimationDriver} from './animation_driver';
|
||||||
import {getBodyNode, getOrSetAsInMap, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer} from './shared';
|
import {getBodyNode, getOrSetAsInMap, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer} from './shared';
|
||||||
@ -22,8 +22,6 @@ const QUEUED_CLASSNAME = 'ng-animate-queued';
|
|||||||
const QUEUED_SELECTOR = '.ng-animate-queued';
|
const QUEUED_SELECTOR = '.ng-animate-queued';
|
||||||
const DISABLED_CLASSNAME = 'ng-animate-disabled';
|
const DISABLED_CLASSNAME = 'ng-animate-disabled';
|
||||||
const DISABLED_SELECTOR = '.ng-animate-disabled';
|
const DISABLED_SELECTOR = '.ng-animate-disabled';
|
||||||
const STAR_CLASSNAME = 'ng-star-inserted';
|
|
||||||
const STAR_SELECTOR = '.ng-star-inserted';
|
|
||||||
|
|
||||||
const EMPTY_PLAYER_ARRAY: TransitionAnimationPlayer[] = [];
|
const EMPTY_PLAYER_ARRAY: TransitionAnimationPlayer[] = [];
|
||||||
const NULL_REMOVAL_STATE: ElementAnimationState = {
|
const NULL_REMOVAL_STATE: ElementAnimationState = {
|
||||||
@ -716,12 +714,10 @@ export class TransitionAnimationEngine {
|
|||||||
return () => {};
|
return () => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
private _buildInstruction(
|
private _buildInstruction(entry: QueueInstruction, subTimelines: ElementInstructionMap) {
|
||||||
entry: QueueInstruction, subTimelines: ElementInstructionMap, enterClassName: string,
|
|
||||||
leaveClassName: string) {
|
|
||||||
return entry.transition.build(
|
return entry.transition.build(
|
||||||
this.driver, entry.element, entry.fromState.value, entry.toState.value, enterClassName,
|
this.driver, entry.element, entry.fromState.value, entry.toState.value,
|
||||||
leaveClassName, entry.fromState.options, entry.toState.options, subTimelines);
|
entry.fromState.options, entry.toState.options, subTimelines);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyInnerAnimations(containerElement: any) {
|
destroyInnerAnimations(containerElement: any) {
|
||||||
@ -802,13 +798,6 @@ export class TransitionAnimationEngine {
|
|||||||
this.newHostElements.clear();
|
this.newHostElements.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.totalAnimations && this.collectedEnterElements.length) {
|
|
||||||
for (let i = 0; i < this.collectedEnterElements.length; i++) {
|
|
||||||
const elm = this.collectedEnterElements[i];
|
|
||||||
addClass(elm, STAR_CLASSNAME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._namespaceList.length &&
|
if (this._namespaceList.length &&
|
||||||
(this.totalQueuedPlayers || this.collectedLeaveElements.length)) {
|
(this.totalQueuedPlayers || this.collectedLeaveElements.length)) {
|
||||||
const cleanupFns: Function[] = [];
|
const cleanupFns: Function[] = [];
|
||||||
@ -873,57 +862,37 @@ export class TransitionAnimationEngine {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const bodyNode = getBodyNode();
|
const bodyNode = getBodyNode();
|
||||||
const allTriggerElements = Array.from(this.statesByElement.keys());
|
const allEnterNodes: any[] = this.collectedEnterElements.length ?
|
||||||
const enterNodeMap = buildRootMap(allTriggerElements, this.collectedEnterElements);
|
this.collectedEnterElements.filter(createIsRootFilterFn(this.collectedEnterElements)) :
|
||||||
|
[];
|
||||||
|
|
||||||
// this must occur before the instructions are built below such that
|
// this must occur before the instructions are built below such that
|
||||||
// the :enter queries match the elements (since the timeline queries
|
// the :enter queries match the elements (since the timeline queries
|
||||||
// are fired during instruction building).
|
// are fired during instruction building).
|
||||||
const enterNodeMapIds = new Map<any, string>();
|
for (let i = 0; i < allEnterNodes.length; i++) {
|
||||||
let i = 0;
|
addClass(allEnterNodes[i], ENTER_CLASSNAME);
|
||||||
enterNodeMap.forEach((nodes, root) => {
|
}
|
||||||
const className = ENTER_CLASSNAME + i++;
|
|
||||||
enterNodeMapIds.set(root, className);
|
|
||||||
nodes.forEach(node => addClass(node, className));
|
|
||||||
});
|
|
||||||
|
|
||||||
const allLeaveNodes: any[] = [];
|
const allLeaveNodes: any[] = [];
|
||||||
const mergedLeaveNodes = new Set<any>();
|
|
||||||
const leaveNodesWithoutAnimations = new Set<any>();
|
const leaveNodesWithoutAnimations = new Set<any>();
|
||||||
for (let i = 0; i < this.collectedLeaveElements.length; i++) {
|
for (let i = 0; i < this.collectedLeaveElements.length; i++) {
|
||||||
const element = this.collectedLeaveElements[i];
|
const element = this.collectedLeaveElements[i];
|
||||||
const details = element[REMOVAL_FLAG] as ElementAnimationState;
|
const details = element[REMOVAL_FLAG] as ElementAnimationState;
|
||||||
if (details && details.setForRemoval) {
|
if (details && details.setForRemoval) {
|
||||||
|
addClass(element, LEAVE_CLASSNAME);
|
||||||
allLeaveNodes.push(element);
|
allLeaveNodes.push(element);
|
||||||
mergedLeaveNodes.add(element);
|
if (!details.hasAnimation) {
|
||||||
if (details.hasAnimation) {
|
|
||||||
this.driver.query(element, STAR_SELECTOR, true).forEach(elm => mergedLeaveNodes.add(elm));
|
|
||||||
} else {
|
|
||||||
leaveNodesWithoutAnimations.add(element);
|
leaveNodesWithoutAnimations.add(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const leaveNodeMapIds = new Map<any, string>();
|
|
||||||
const leaveNodeMap = buildRootMap(allTriggerElements, Array.from(mergedLeaveNodes));
|
|
||||||
leaveNodeMap.forEach((nodes, root) => {
|
|
||||||
const className = LEAVE_CLASSNAME + i++;
|
|
||||||
leaveNodeMapIds.set(root, className);
|
|
||||||
nodes.forEach(node => addClass(node, className));
|
|
||||||
});
|
|
||||||
|
|
||||||
cleanupFns.push(() => {
|
cleanupFns.push(() => {
|
||||||
enterNodeMap.forEach((nodes, root) => {
|
allEnterNodes.forEach(element => removeClass(element, ENTER_CLASSNAME));
|
||||||
const className = enterNodeMapIds.get(root) !;
|
allLeaveNodes.forEach(element => {
|
||||||
nodes.forEach(node => removeClass(node, className));
|
removeClass(element, LEAVE_CLASSNAME);
|
||||||
|
this.processLeaveNode(element);
|
||||||
});
|
});
|
||||||
|
|
||||||
leaveNodeMap.forEach((nodes, root) => {
|
|
||||||
const className = leaveNodeMapIds.get(root) !;
|
|
||||||
nodes.forEach(node => removeClass(node, className));
|
|
||||||
});
|
|
||||||
|
|
||||||
allLeaveNodes.forEach(element => { this.processLeaveNode(element); });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const allPlayers: TransitionAnimationPlayer[] = [];
|
const allPlayers: TransitionAnimationPlayer[] = [];
|
||||||
@ -940,10 +909,7 @@ export class TransitionAnimationEngine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const leaveClassName = leaveNodeMapIds.get(element) !;
|
const instruction = this._buildInstruction(entry, subTimelines) !;
|
||||||
const enterClassName = enterNodeMapIds.get(element) !;
|
|
||||||
const instruction =
|
|
||||||
this._buildInstruction(entry, subTimelines, enterClassName, leaveClassName) !;
|
|
||||||
if (instruction.errors && instruction.errors.length) {
|
if (instruction.errors && instruction.errors.length) {
|
||||||
erroneousTransitions.push(instruction);
|
erroneousTransitions.push(instruction);
|
||||||
return;
|
return;
|
||||||
@ -1007,6 +973,18 @@ export class TransitionAnimationEngine {
|
|||||||
this.reportError(errors);
|
this.reportError(errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// these can only be detected here since we have a map of all the elements
|
||||||
|
// that have animations attached to them... We use a set here in the event
|
||||||
|
// multiple enter captures on the same element were caught in different
|
||||||
|
// renderer namespaces (e.g. when a @trigger was on a host binding that had *ngIf)
|
||||||
|
const enterNodesWithoutAnimations = new Set<any>();
|
||||||
|
for (let i = 0; i < allEnterNodes.length; i++) {
|
||||||
|
const element = allEnterNodes[i];
|
||||||
|
if (!subTimelines.has(element)) {
|
||||||
|
enterNodesWithoutAnimations.add(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const allPreviousPlayersMap = new Map<any, TransitionAnimationPlayer[]>();
|
const allPreviousPlayersMap = new Map<any, TransitionAnimationPlayer[]>();
|
||||||
// this map works to tell which element in the DOM tree is contained by
|
// this map works to tell which element in the DOM tree is contained by
|
||||||
// which animation. Further down below this map will get populated once
|
// which animation. Further down below this map will get populated once
|
||||||
@ -1044,9 +1022,8 @@ export class TransitionAnimationEngine {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// POST STAGE: fill the * styles
|
// POST STAGE: fill the * styles
|
||||||
const postStylesMap = new Map<any, ɵStyleData>();
|
const [postStylesMap, allLeaveQueriedNodes] = cloakAndComputeStyles(
|
||||||
const allLeaveQueriedNodes = cloakAndComputeStyles(
|
this.driver, leaveNodesWithoutAnimations, allPostStyleElements, AUTO_STYLE);
|
||||||
postStylesMap, this.driver, leaveNodesWithoutAnimations, allPostStyleElements, AUTO_STYLE);
|
|
||||||
|
|
||||||
allLeaveQueriedNodes.forEach(node => {
|
allLeaveQueriedNodes.forEach(node => {
|
||||||
if (replacePostStylesAsPre(node, allPreStyleElements, allPostStyleElements)) {
|
if (replacePostStylesAsPre(node, allPreStyleElements, allPostStyleElements)) {
|
||||||
@ -1055,11 +1032,10 @@ export class TransitionAnimationEngine {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// PRE STAGE: fill the ! styles
|
// PRE STAGE: fill the ! styles
|
||||||
const preStylesMap = new Map<any, ɵStyleData>();
|
const [preStylesMap] = allPreStyleElements.size ?
|
||||||
enterNodeMap.forEach((nodes, root) => {
|
|
||||||
cloakAndComputeStyles(
|
cloakAndComputeStyles(
|
||||||
preStylesMap, this.driver, new Set(nodes), allPreStyleElements, PRE_STYLE);
|
this.driver, enterNodesWithoutAnimations, allPreStyleElements, PRE_STYLE) :
|
||||||
});
|
[new Map<any, ɵStyleData>()];
|
||||||
|
|
||||||
replaceNodes.forEach(node => {
|
replaceNodes.forEach(node => {
|
||||||
const post = postStylesMap.get(node);
|
const post = postStylesMap.get(node);
|
||||||
@ -1529,11 +1505,12 @@ function cloakElement(element: any, value?: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function cloakAndComputeStyles(
|
function cloakAndComputeStyles(
|
||||||
valuesMap: Map<any, ɵStyleData>, driver: AnimationDriver, elements: Set<any>,
|
driver: AnimationDriver, elements: Set<any>, elementPropsMap: Map<any, Set<string>>,
|
||||||
elementPropsMap: Map<any, Set<string>>, defaultStyle: string): any[] {
|
defaultStyle: string): [Map<any, ɵStyleData>, any[]] {
|
||||||
const cloakVals: string[] = [];
|
const cloakVals: string[] = [];
|
||||||
elements.forEach(element => cloakVals.push(cloakElement(element)));
|
elements.forEach(element => cloakVals.push(cloakElement(element)));
|
||||||
|
|
||||||
|
const valuesMap = new Map<any, ɵStyleData>();
|
||||||
const failedElements: any[] = [];
|
const failedElements: any[] = [];
|
||||||
|
|
||||||
elementPropsMap.forEach((props: Set<string>, element: any) => {
|
elementPropsMap.forEach((props: Set<string>, element: any) => {
|
||||||
@ -1555,57 +1532,39 @@ function cloakAndComputeStyles(
|
|||||||
// an index value for the closure (but instead just the value)
|
// an index value for the closure (but instead just the value)
|
||||||
let i = 0;
|
let i = 0;
|
||||||
elements.forEach(element => cloakElement(element, cloakVals[i++]));
|
elements.forEach(element => cloakElement(element, cloakVals[i++]));
|
||||||
|
return [valuesMap, failedElements];
|
||||||
return failedElements;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Since the Angular renderer code will return a collection of inserted
|
Since the Angular renderer code will return a collection of inserted
|
||||||
nodes in all areas of a DOM tree, it's up to this algorithm to figure
|
nodes in all areas of a DOM tree, it's up to this algorithm to figure
|
||||||
out which nodes are roots for each animation @trigger.
|
out which nodes are roots.
|
||||||
|
|
||||||
By placing each inserted node into a Set and traversing upwards, it
|
By placing all nodes into a set and traversing upwards to the edge,
|
||||||
is possible to find the @trigger elements and well any direct *star
|
the recursive code can figure out if a clean path from the DOM node
|
||||||
insertion nodes, if a @trigger root is found then the enter element
|
to the edge container is clear. If no other node is detected in the
|
||||||
is placed into the Map[@trigger] spot.
|
set then it is a root element.
|
||||||
|
|
||||||
|
This algorithm also keeps track of all nodes along the path so that
|
||||||
|
if other sibling nodes are also tracked then the lookup process can
|
||||||
|
skip a lot of steps in between and avoid traversing the entire tree
|
||||||
|
multiple times to the edge.
|
||||||
*/
|
*/
|
||||||
function buildRootMap(roots: any[], nodes: any[]): Map<any, any[]> {
|
function createIsRootFilterFn(nodes: any): (node: any) => boolean {
|
||||||
const rootMap = new Map<any, any[]>();
|
|
||||||
roots.forEach(root => rootMap.set(root, []));
|
|
||||||
|
|
||||||
if (nodes.length == 0) return rootMap;
|
|
||||||
|
|
||||||
const NULL_NODE = 1;
|
|
||||||
const nodeSet = new Set(nodes);
|
const nodeSet = new Set(nodes);
|
||||||
const localRootMap = new Map<any, any>();
|
const knownRootContainer = new Set();
|
||||||
|
let isRoot: (node: any) => boolean;
|
||||||
function getRoot(node: any): any {
|
isRoot = node => {
|
||||||
if (!node) return NULL_NODE;
|
if (!node) return true;
|
||||||
|
if (nodeSet.has(node.parentNode)) return false;
|
||||||
let root = localRootMap.get(node);
|
if (knownRootContainer.has(node.parentNode)) return true;
|
||||||
if (root) return root;
|
if (isRoot(node.parentNode)) {
|
||||||
|
knownRootContainer.add(node);
|
||||||
const parent = node.parentNode;
|
return true;
|
||||||
if (rootMap.has(parent)) { // ngIf inside @trigger
|
|
||||||
root = parent;
|
|
||||||
} else if (nodeSet.has(parent)) { // ngIf inside ngIf
|
|
||||||
root = NULL_NODE;
|
|
||||||
} else { // recurse upwards
|
|
||||||
root = getRoot(parent);
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
localRootMap.set(node, root);
|
};
|
||||||
return root;
|
return isRoot;
|
||||||
}
|
|
||||||
|
|
||||||
nodes.forEach(node => {
|
|
||||||
const root = getRoot(node);
|
|
||||||
if (root !== NULL_NODE) {
|
|
||||||
rootMap.get(root) !.push(node);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return rootMap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const CLASSES_CACHE_KEY = '$$classes';
|
const CLASSES_CACHE_KEY = '$$classes';
|
||||||
|
@ -10,7 +10,6 @@ import {AnimationOptions, animate, state, style, transition} from '@angular/anim
|
|||||||
import {AnimationTransitionInstruction} from '@angular/animations/browser/src/dsl/animation_transition_instruction';
|
import {AnimationTransitionInstruction} from '@angular/animations/browser/src/dsl/animation_transition_instruction';
|
||||||
import {AnimationTrigger} from '@angular/animations/browser/src/dsl/animation_trigger';
|
import {AnimationTrigger} from '@angular/animations/browser/src/dsl/animation_trigger';
|
||||||
|
|
||||||
import {ENTER_CLASSNAME, LEAVE_CLASSNAME} from '../../src/util';
|
|
||||||
import {MockAnimationDriver} from '../../testing';
|
import {MockAnimationDriver} from '../../testing';
|
||||||
import {makeTrigger} from '../shared';
|
import {makeTrigger} from '../shared';
|
||||||
|
|
||||||
@ -229,9 +228,7 @@ function buildTransition(
|
|||||||
const trans = trigger.matchTransition(fromState, toState) !;
|
const trans = trigger.matchTransition(fromState, toState) !;
|
||||||
if (trans) {
|
if (trans) {
|
||||||
const driver = new MockAnimationDriver();
|
const driver = new MockAnimationDriver();
|
||||||
return trans.build(
|
return trans.build(driver, element, fromState, toState, fromOptions, toOptions) !;
|
||||||
driver, element, fromState, toState, ENTER_CLASSNAME, LEAVE_CLASSNAME, fromOptions,
|
|
||||||
toOptions) !;
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -62,8 +62,8 @@ export class NoopAnimationPlayer implements AnimationPlayer {
|
|||||||
init(): void {}
|
init(): void {}
|
||||||
play(): void {
|
play(): void {
|
||||||
if (!this.hasStarted()) {
|
if (!this.hasStarted()) {
|
||||||
this._onStart();
|
|
||||||
this.triggerMicrotask();
|
this.triggerMicrotask();
|
||||||
|
this._onStart();
|
||||||
}
|
}
|
||||||
this._started = true;
|
this._started = true;
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {fakeAsync} from '@angular/core/testing';
|
import {fakeAsync} from '@angular/core/testing';
|
||||||
|
|
||||||
import {flushMicrotasks} from '../../core/testing/src/fake_async';
|
import {flushMicrotasks} from '../../core/testing/src/fake_async';
|
||||||
import {NoopAnimationPlayer} from '../src/players/animation_player';
|
import {NoopAnimationPlayer} from '../src/players/animation_player';
|
||||||
import {scheduleMicroTask} from '../src/util';
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('NoopAnimationPlayer', function() {
|
describe('NoopAnimationPlayer', function() {
|
||||||
@ -61,21 +61,6 @@ export function main() {
|
|||||||
player.finish();
|
player.finish();
|
||||||
expect(log).toEqual(['started', 'done']);
|
expect(log).toEqual(['started', 'done']);
|
||||||
|
|
||||||
flushMicrotasks();
|
|
||||||
expect(log).toEqual(['started', 'done']);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should fire off start callbacks before triggering the finish callback', fakeAsync(() => {
|
|
||||||
const log: string[] = [];
|
|
||||||
|
|
||||||
const player = new NoopAnimationPlayer();
|
|
||||||
player.onStart(() => { scheduleMicroTask(() => log.push('started')); });
|
|
||||||
player.onDone(() => log.push('done'));
|
|
||||||
expect(log).toEqual([]);
|
|
||||||
|
|
||||||
player.play();
|
|
||||||
expect(log).toEqual([]);
|
|
||||||
|
|
||||||
flushMicrotasks();
|
flushMicrotasks();
|
||||||
expect(log).toEqual(['started', 'done']);
|
expect(log).toEqual(['started', 'done']);
|
||||||
}));
|
}));
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@angular/compiler-cli": "0.0.0-PLACEHOLDER",
|
"@angular/compiler-cli": "0.0.0-PLACEHOLDER",
|
||||||
"typescript": ">=2.4.2 <2.6"
|
"typescript": ">=2.4.2 <2.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bazel/typescript": "0.3.2",
|
"@bazel/typescript": "0.2.x",
|
||||||
"@types/node": "6.0.84"
|
"@types/node": "6.0.84"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -5,7 +5,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
|
||||||
*/
|
*/
|
||||||
|
// TODO(tbosch): figure out why we need this as it breaks node code within ngc-wrapped
|
||||||
|
/// <reference types="node" />
|
||||||
import * as ng from '@angular/compiler-cli';
|
import * as ng from '@angular/compiler-cli';
|
||||||
import {BazelOptions, CachedFileLoader, CompilerHost, FileCache, FileLoader, UncachedFileLoader, constructManifest, debug, fixUmdModuleDeclarations, parseTsconfig, runAsWorker, runWorkerLoop} from '@bazel/typescript';
|
import {BazelOptions, CachedFileLoader, CompilerHost, FileCache, FileLoader, UncachedFileLoader, constructManifest, debug, fixUmdModuleDeclarations, parseTsconfig, runAsWorker, runWorkerLoop} from '@bazel/typescript';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
@ -164,19 +165,11 @@ export function compile({allowNonHermeticReads, allDepsCompiledWithBazel = true,
|
|||||||
}
|
}
|
||||||
return origBazelHostFileExist.call(bazelHost, fileName);
|
return origBazelHostFileExist.call(bazelHost, fileName);
|
||||||
};
|
};
|
||||||
const origBazelHostShouldNameModule = bazelHost.shouldNameModule.bind(bazelHost);
|
|
||||||
bazelHost.shouldNameModule = (fileName: string) =>
|
|
||||||
origBazelHostShouldNameModule(fileName) || NGC_GEN_FILES.test(fileName);
|
|
||||||
|
|
||||||
const ngHost = ng.createCompilerHost({options: compilerOpts, tsHost: bazelHost});
|
const ngHost = ng.createCompilerHost({options: compilerOpts, tsHost: bazelHost});
|
||||||
|
|
||||||
ngHost.fileNameToModuleName = (importedFilePath: string, containingFilePath: string) => {
|
ngHost.fileNameToModuleName = (importedFilePath: string, containingFilePath: string) =>
|
||||||
if ((compilerOpts.module === ts.ModuleKind.UMD || compilerOpts.module === ts.ModuleKind.AMD) &&
|
relativeToRootDirs(importedFilePath, compilerOpts.rootDirs).replace(EXT, '');
|
||||||
ngHost.amdModuleName) {
|
|
||||||
return ngHost.amdModuleName({ fileName: importedFilePath } as ts.SourceFile);
|
|
||||||
}
|
|
||||||
return relativeToRootDirs(importedFilePath, compilerOpts.rootDirs).replace(EXT, '');
|
|
||||||
};
|
|
||||||
ngHost.toSummaryFileName = (fileName: string, referringSrcFileName: string) =>
|
ngHost.toSummaryFileName = (fileName: string, referringSrcFileName: string) =>
|
||||||
ngHost.fileNameToModuleName(fileName, referringSrcFileName);
|
ngHost.fileNameToModuleName(fileName, referringSrcFileName);
|
||||||
if (allDepsCompiledWithBazel) {
|
if (allDepsCompiledWithBazel) {
|
||||||
|
@ -64,10 +64,6 @@ export function createTsConfig(options: TsConfigOptions) {
|
|||||||
'es5Mode': true,
|
'es5Mode': true,
|
||||||
'manifest': createManifestPath(options),
|
'manifest': createManifestPath(options),
|
||||||
'compilationTargetSrc': options.compilationTargetSrc,
|
'compilationTargetSrc': options.compilationTargetSrc,
|
||||||
// Override this property from the real tsconfig we read
|
|
||||||
// Because we ask for :empty_tsconfig.json, we get the ES6 version which
|
|
||||||
// expects to write externs, yet that doesn't work under this fixture.
|
|
||||||
'tsickleExternsPath': '',
|
|
||||||
},
|
},
|
||||||
'files': options.files,
|
'files': options.files,
|
||||||
'angularCompilerOptions': {
|
'angularCompilerOptions': {
|
||||||
|
@ -81,9 +81,7 @@ export class Runner {
|
|||||||
{provide: WebDriverAdapter, useValue: adapter}
|
{provide: WebDriverAdapter, useValue: adapter}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// TODO: With TypeScript 2.5 injector.get does not infer correctly the
|
const sampler = injector.get(Sampler);
|
||||||
// return type. Remove 'any' and investigate the issue.
|
|
||||||
const sampler = injector.get(Sampler) as any;
|
|
||||||
return sampler.sample();
|
return sampler.sample();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ export function main() {
|
|||||||
ids.map(id => ({provide: id, useValue: new MockMetric(id)})),
|
ids.map(id => ({provide: id, useValue: new MockMetric(id)})),
|
||||||
MultiMetric.provideWith(ids)
|
MultiMetric.provideWith(ids)
|
||||||
])
|
])
|
||||||
.get<MultiMetric>(MultiMetric);
|
.get(MultiMetric);
|
||||||
return Promise.resolve(m);
|
return Promise.resolve(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ export function main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
return Injector.create(providers).get<JsonFileReporter>(JsonFileReporter);
|
return Injector.create(providers).get(JsonFileReporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should write all data into a file',
|
it('should write all data into a file',
|
||||||
|
@ -17,7 +17,7 @@ export function main() {
|
|||||||
ids.map(id => ({provide: id, useValue: new MockReporter(id)})),
|
ids.map(id => ({provide: id, useValue: new MockReporter(id)})),
|
||||||
MultiReporter.provideWith(ids)
|
MultiReporter.provideWith(ids)
|
||||||
])
|
])
|
||||||
.get<MultiReporter>(MultiReporter);
|
.get(MultiReporter);
|
||||||
return Promise.resolve(r);
|
return Promise.resolve(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,11 +352,13 @@ export class HttpClient {
|
|||||||
|
|
||||||
// Figure out the headers.
|
// Figure out the headers.
|
||||||
let headers: HttpHeaders|undefined = undefined;
|
let headers: HttpHeaders|undefined = undefined;
|
||||||
|
if (!!options.headers !== undefined) {
|
||||||
if (options.headers instanceof HttpHeaders) {
|
if (options.headers instanceof HttpHeaders) {
|
||||||
headers = options.headers;
|
headers = options.headers;
|
||||||
} else {
|
} else {
|
||||||
headers = new HttpHeaders(options.headers);
|
headers = new HttpHeaders(options.headers);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sort out parameters.
|
// Sort out parameters.
|
||||||
let params: HttpParams|undefined = undefined;
|
let params: HttpParams|undefined = undefined;
|
||||||
@ -369,7 +371,7 @@ export class HttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Construct the request.
|
// Construct the request.
|
||||||
req = new HttpRequest(first, url !, (options.body !== undefined ? options.body : null), {
|
req = new HttpRequest(first, url !, options.body || null, {
|
||||||
headers,
|
headers,
|
||||||
params,
|
params,
|
||||||
reportProgress: options.reportProgress,
|
reportProgress: options.reportProgress,
|
||||||
|
@ -171,7 +171,7 @@ export class HttpRequest<T> {
|
|||||||
// the body argument is to use a known no-body method like GET.
|
// the body argument is to use a known no-body method like GET.
|
||||||
if (mightHaveBody(this.method) || !!fourth) {
|
if (mightHaveBody(this.method) || !!fourth) {
|
||||||
// Body is the third argument, options are the fourth.
|
// Body is the third argument, options are the fourth.
|
||||||
this.body = (third !== undefined) ? third as T : null;
|
this.body = third as T || null;
|
||||||
options = fourth;
|
options = fourth;
|
||||||
} else {
|
} else {
|
||||||
// No body required, options are the third argument. The body stays null.
|
// No body required, options are the third argument. The body stays null.
|
||||||
|
@ -262,7 +262,7 @@ export class HttpResponse<T> extends HttpResponseBase {
|
|||||||
body?: T | null, headers?: HttpHeaders; status?: number; statusText?: string; url?: string;
|
body?: T | null, headers?: HttpHeaders; status?: number; statusText?: string; url?: string;
|
||||||
} = {}) {
|
} = {}) {
|
||||||
super(init);
|
super(init);
|
||||||
this.body = init.body !== undefined ? init.body : null;
|
this.body = init.body || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly type: HttpEventType.Response = HttpEventType.Response;
|
readonly type: HttpEventType.Response = HttpEventType.Response;
|
||||||
|
@ -180,27 +180,24 @@ export class HttpXhrBackend implements HttpBackend {
|
|||||||
|
|
||||||
// Check whether the body needs to be parsed as JSON (in many cases the browser
|
// Check whether the body needs to be parsed as JSON (in many cases the browser
|
||||||
// will have done that already).
|
// will have done that already).
|
||||||
if (req.responseType === 'json' && typeof body === 'string') {
|
if (ok && req.responseType === 'json' && typeof body === 'string') {
|
||||||
// Save the original body, before attempting XSSI prefix stripping.
|
// Attempt the parse. If it fails, a parse error should be delivered to the user.
|
||||||
const originalBody = body;
|
|
||||||
body = body.replace(XSSI_PREFIX, '');
|
body = body.replace(XSSI_PREFIX, '');
|
||||||
try {
|
try {
|
||||||
// Attempt the parse. If it fails, a parse error should be delivered to the user.
|
body = JSON.parse(body);
|
||||||
body = body !== '' ? JSON.parse(body) : null;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Since the JSON.parse failed, it's reasonable to assume this might not have been a
|
|
||||||
// JSON response. Restore the original body (including any XSSI prefix) to deliver
|
|
||||||
// a better error response.
|
|
||||||
body = originalBody;
|
|
||||||
|
|
||||||
// If this was an error request to begin with, leave it as a string, it probably
|
|
||||||
// just isn't JSON. Otherwise, deliver the parsing error to the user.
|
|
||||||
if (ok) {
|
|
||||||
// Even though the response status was 2xx, this is still an error.
|
// Even though the response status was 2xx, this is still an error.
|
||||||
ok = false;
|
ok = false;
|
||||||
// The parse error contains the text of the body that failed to parse.
|
// The parse error contains the text of the body that failed to parse.
|
||||||
body = { error, text: body } as HttpJsonParseError;
|
body = { error, text: body } as HttpJsonParseError;
|
||||||
}
|
}
|
||||||
|
} else if (!ok && req.responseType === 'json' && typeof body === 'string') {
|
||||||
|
try {
|
||||||
|
// Attempt to parse the body as JSON.
|
||||||
|
body = JSON.parse(body);
|
||||||
|
} catch (error) {
|
||||||
|
// Cannot be certain that the body was meant to be parsed as JSON.
|
||||||
|
// Leave the body as a string.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,26 +115,6 @@ export function main() {
|
|||||||
expect(testReq.request.body).toBe(body);
|
expect(testReq.request.body).toBe(body);
|
||||||
testReq.flush('hello world');
|
testReq.flush('hello world');
|
||||||
});
|
});
|
||||||
it('with a json body of false', (done: DoneFn) => {
|
|
||||||
client.post('/test', false, {observe: 'response', responseType: 'text'}).subscribe(res => {
|
|
||||||
expect(res.ok).toBeTruthy();
|
|
||||||
expect(res.status).toBe(200);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
const testReq = backend.expectOne('/test');
|
|
||||||
expect(testReq.request.body).toBe(false);
|
|
||||||
testReq.flush('hello world');
|
|
||||||
});
|
|
||||||
it('with a json body of 0', (done: DoneFn) => {
|
|
||||||
client.post('/test', 0, {observe: 'response', responseType: 'text'}).subscribe(res => {
|
|
||||||
expect(res.ok).toBeTruthy();
|
|
||||||
expect(res.status).toBe(200);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
const testReq = backend.expectOne('/test');
|
|
||||||
expect(testReq.request.body).toBe(0);
|
|
||||||
testReq.flush('hello world');
|
|
||||||
});
|
|
||||||
it('with an arraybuffer', (done: DoneFn) => {
|
it('with an arraybuffer', (done: DoneFn) => {
|
||||||
const body = new ArrayBuffer(4);
|
const body = new ArrayBuffer(4);
|
||||||
client.post('/test', body, {observe: 'response', responseType: 'text'}).subscribe(res => {
|
client.post('/test', body, {observe: 'response', responseType: 'text'}).subscribe(res => {
|
||||||
|
@ -40,10 +40,6 @@ export function main() {
|
|||||||
expect(resp.ok).toBeTruthy();
|
expect(resp.ok).toBeTruthy();
|
||||||
expect(resp.url).toBeNull();
|
expect(resp.url).toBeNull();
|
||||||
});
|
});
|
||||||
it('accepts a falsy body', () => {
|
|
||||||
expect(new HttpResponse({body: false}).body).toEqual(false);
|
|
||||||
expect(new HttpResponse({body: 0}).body).toEqual(0);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
it('.ok is determined by status', () => {
|
it('.ok is determined by status', () => {
|
||||||
const good = new HttpResponse({status: 200});
|
const good = new HttpResponse({status: 200});
|
||||||
|
@ -25,8 +25,6 @@ const TEST_POST = new HttpRequest('POST', '/test', 'some body', {
|
|||||||
responseType: 'text',
|
responseType: 'text',
|
||||||
});
|
});
|
||||||
|
|
||||||
const XSSI_PREFIX = ')]}\'\n';
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('XhrBackend', () => {
|
describe('XhrBackend', () => {
|
||||||
let factory: MockXhrFactory = null !;
|
let factory: MockXhrFactory = null !;
|
||||||
@ -94,13 +92,6 @@ export function main() {
|
|||||||
const res = events[1] as HttpResponse<{data: string}>;
|
const res = events[1] as HttpResponse<{data: string}>;
|
||||||
expect(res.body !.data).toBe('some data');
|
expect(res.body !.data).toBe('some data');
|
||||||
});
|
});
|
||||||
it('handles a blank json response', () => {
|
|
||||||
const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'})));
|
|
||||||
factory.mock.mockFlush(200, 'OK', '');
|
|
||||||
expect(events.length).toBe(2);
|
|
||||||
const res = events[1] as HttpResponse<{data: string}>;
|
|
||||||
expect(res.body).toBeNull();
|
|
||||||
});
|
|
||||||
it('handles a json error response', () => {
|
it('handles a json error response', () => {
|
||||||
const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'})));
|
const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'})));
|
||||||
factory.mock.mockFlush(500, 'Error', JSON.stringify({data: 'some data'}));
|
factory.mock.mockFlush(500, 'Error', JSON.stringify({data: 'some data'}));
|
||||||
@ -108,13 +99,6 @@ export function main() {
|
|||||||
const res = events[1] as any as HttpErrorResponse;
|
const res = events[1] as any as HttpErrorResponse;
|
||||||
expect(res.error !.data).toBe('some data');
|
expect(res.error !.data).toBe('some data');
|
||||||
});
|
});
|
||||||
it('handles a json error response with XSSI prefix', () => {
|
|
||||||
const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'})));
|
|
||||||
factory.mock.mockFlush(500, 'Error', XSSI_PREFIX + JSON.stringify({data: 'some data'}));
|
|
||||||
expect(events.length).toBe(2);
|
|
||||||
const res = events[1] as any as HttpErrorResponse;
|
|
||||||
expect(res.error !.data).toBe('some data');
|
|
||||||
});
|
|
||||||
it('handles a json string response', () => {
|
it('handles a json string response', () => {
|
||||||
const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'})));
|
const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'})));
|
||||||
expect(factory.mock.responseType).toEqual('text');
|
expect(factory.mock.responseType).toEqual('text');
|
||||||
@ -125,7 +109,7 @@ export function main() {
|
|||||||
});
|
});
|
||||||
it('handles a json response with an XSSI prefix', () => {
|
it('handles a json response with an XSSI prefix', () => {
|
||||||
const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'})));
|
const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'})));
|
||||||
factory.mock.mockFlush(200, 'OK', XSSI_PREFIX + JSON.stringify({data: 'some data'}));
|
factory.mock.mockFlush(200, 'OK', ')]}\'\n' + JSON.stringify({data: 'some data'}));
|
||||||
expect(events.length).toBe(2);
|
expect(events.length).toBe(2);
|
||||||
const res = events[1] as HttpResponse<{data: string}>;
|
const res = events[1] as HttpResponse<{data: string}>;
|
||||||
expect(res.body !.data).toBe('some data');
|
expect(res.body !.data).toBe('some data');
|
||||||
|
@ -4895,5 +4895,6 @@ switch (goog.LOCALE) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (l) {
|
if (l) {
|
||||||
registerLocaleData(l, goog.LOCALE);
|
l[0] = goog.LOCALE;
|
||||||
|
registerLocaleData(l);
|
||||||
}
|
}
|
||||||
|
@ -17,17 +17,9 @@ export const LOCALE_DATA: {[localeId: string]: any} = {};
|
|||||||
*
|
*
|
||||||
* @experimental i18n support is experimental.
|
* @experimental i18n support is experimental.
|
||||||
*/
|
*/
|
||||||
// The signature registerLocaleData(data: any, extraData?: any) is deprecated since v5.1
|
export function registerLocaleData(data: any, extraData?: any) {
|
||||||
export function registerLocaleData(data: any, localeId?: string | any, extraData?: any): void {
|
const localeId = data[LocaleDataIndex.LocaleId].toLowerCase().replace(/_/g, '-');
|
||||||
if (typeof localeId !== 'string') {
|
|
||||||
extraData = localeId;
|
|
||||||
localeId = data[LocaleDataIndex.LocaleId];
|
|
||||||
}
|
|
||||||
|
|
||||||
localeId = localeId.toLowerCase().replace(/_/g, '-');
|
|
||||||
|
|
||||||
LOCALE_DATA[localeId] = data;
|
LOCALE_DATA[localeId] = data;
|
||||||
|
|
||||||
if (extraData) {
|
if (extraData) {
|
||||||
LOCALE_DATA[localeId][LocaleDataIndex.ExtraData] = extraData;
|
LOCALE_DATA[localeId][LocaleDataIndex.ExtraData] = extraData;
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,8 @@ import localeCaESVALENCIA from '../../locales/ca-ES-VALENCIA';
|
|||||||
import localeEn from '../../locales/en';
|
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 {findLocaleData} from '../../src/i18n/locale_data_api';
|
import {findLocaleData} from '../../src/i18n/locale_data_api';
|
||||||
|
import {registerLocaleData} from '../../src/i18n/locale_data';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('locale data api', () => {
|
describe('locale data api', () => {
|
||||||
@ -20,8 +20,6 @@ export function main() {
|
|||||||
registerLocaleData(localeEn);
|
registerLocaleData(localeEn);
|
||||||
registerLocaleData(localeFr);
|
registerLocaleData(localeFr);
|
||||||
registerLocaleData(localeFrCA);
|
registerLocaleData(localeFrCA);
|
||||||
registerLocaleData(localeFr, 'fake-id');
|
|
||||||
registerLocaleData(localeFrCA, 'fake_Id2');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('findLocaleData', () => {
|
describe('findLocaleData', () => {
|
||||||
@ -44,12 +42,6 @@ export function main() {
|
|||||||
expect(findLocaleData('ca-ES-VALENCIA')).toEqual(localeCaESVALENCIA);
|
expect(findLocaleData('ca-ES-VALENCIA')).toEqual(localeCaESVALENCIA);
|
||||||
expect(findLocaleData('CA_es_Valencia')).toEqual(localeCaESVALENCIA);
|
expect(findLocaleData('CA_es_Valencia')).toEqual(localeCaESVALENCIA);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should find the LOCALE_DATA if the locale id was registered`, () => {
|
|
||||||
expect(findLocaleData('fake-id')).toEqual(localeFr);
|
|
||||||
expect(findLocaleData('fake_iD')).toEqual(localeFr);
|
|
||||||
expect(findLocaleData('fake-id2')).toEqual(localeFrCA);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -42,9 +42,7 @@ export class SpyLocation implements Location {
|
|||||||
return currPath == givenPath + (query.length > 0 ? ('?' + query) : '');
|
return currPath == givenPath + (query.length > 0 ? ('?' + query) : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
simulateUrlPop(pathname: string) {
|
simulateUrlPop(pathname: string) { this._subject.emit({'url': pathname, 'pop': true}); }
|
||||||
this._subject.emit({'url': pathname, 'pop': true, 'type': 'popstate'});
|
|
||||||
}
|
|
||||||
|
|
||||||
simulateHashChange(pathname: string) {
|
simulateHashChange(pathname: string) {
|
||||||
// Because we don't prevent the native event, the browser will independently update the path
|
// Because we don't prevent the native event, the browser will independently update the path
|
||||||
|
@ -11,11 +11,11 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"reflect-metadata": "^0.1.2",
|
"reflect-metadata": "^0.1.2",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
"tsickle": "^0.25.5",
|
"tsickle": "^0.24.0",
|
||||||
"chokidar": "^1.4.2"
|
"chokidar": "^1.4.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": ">=2.4.2 <2.6",
|
"typescript": ">=2.4.2 <2.5",
|
||||||
"@angular/compiler": "0.0.0-PLACEHOLDER"
|
"@angular/compiler": "0.0.0-PLACEHOLDER"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -20,6 +20,7 @@ import {GENERATED_FILES} from './transformers/util';
|
|||||||
|
|
||||||
import {exitCodeFromResult, performCompilation, readConfiguration, formatDiagnostics, Diagnostics, ParsedConfiguration, PerformCompilationResult, filterErrorsAndWarnings} from './perform_compile';
|
import {exitCodeFromResult, performCompilation, readConfiguration, formatDiagnostics, Diagnostics, ParsedConfiguration, PerformCompilationResult, filterErrorsAndWarnings} from './perform_compile';
|
||||||
import {performWatchCompilation, createPerformWatchHost} from './perform_watch';
|
import {performWatchCompilation, createPerformWatchHost} from './perform_watch';
|
||||||
|
import {isSyntaxError} from '@angular/compiler';
|
||||||
|
|
||||||
export function main(
|
export function main(
|
||||||
args: string[], consoleError: (s: string) => void = console.error,
|
args: string[], consoleError: (s: string) => void = console.error,
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {Evaluator, errorSymbol, recordMapEntry} from './evaluator';
|
import {Evaluator, errorSymbol} from './evaluator';
|
||||||
import {ClassMetadata, ConstructorMetadata, FunctionMetadata, InterfaceMetadata, METADATA_VERSION, MemberMetadata, MetadataEntry, MetadataError, MetadataMap, MetadataSymbolicBinaryExpression, MetadataSymbolicCallExpression, MetadataSymbolicExpression, MetadataSymbolicIfExpression, MetadataSymbolicIndexExpression, MetadataSymbolicPrefixExpression, MetadataSymbolicReferenceExpression, MetadataSymbolicSelectExpression, MetadataSymbolicSpreadExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportDefaultReference, isMetadataImportedSymbolReferenceExpression, isMetadataSymbolicExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSelectExpression, isMethodMetadata} from './schema';
|
import {ClassMetadata, ConstructorMetadata, FunctionMetadata, InterfaceMetadata, METADATA_VERSION, MemberMetadata, MetadataEntry, MetadataError, MetadataMap, MetadataSymbolicBinaryExpression, MetadataSymbolicCallExpression, MetadataSymbolicExpression, MetadataSymbolicIfExpression, MetadataSymbolicIndexExpression, MetadataSymbolicPrefixExpression, MetadataSymbolicReferenceExpression, MetadataSymbolicSelectExpression, MetadataSymbolicSpreadExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataSymbolicExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSelectExpression, isMethodMetadata} from './schema';
|
||||||
import {Symbols} from './symbols';
|
import {Symbols} from './symbols';
|
||||||
|
|
||||||
const isStatic = (node: ts.Node) => ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Static;
|
const isStatic = (node: ts.Node) => ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Static;
|
||||||
@ -76,7 +76,8 @@ export class MetadataCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function recordEntry<T extends MetadataEntry>(entry: T, node: ts.Node): T {
|
function recordEntry<T extends MetadataEntry>(entry: T, node: ts.Node): T {
|
||||||
return recordMapEntry(entry, node, nodeMap, sourceFile);
|
nodeMap.set(entry, node);
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
function errorSym(
|
function errorSym(
|
||||||
@ -115,8 +116,8 @@ export class MetadataCollector {
|
|||||||
function classMetadataOf(classDeclaration: ts.ClassDeclaration): ClassMetadata {
|
function classMetadataOf(classDeclaration: ts.ClassDeclaration): ClassMetadata {
|
||||||
const result: ClassMetadata = {__symbolic: 'class'};
|
const result: ClassMetadata = {__symbolic: 'class'};
|
||||||
|
|
||||||
function getDecorators(decorators: ReadonlyArray<ts.Decorator>| undefined):
|
function getDecorators(decorators: ts.Decorator[] | undefined): MetadataSymbolicExpression[]|
|
||||||
MetadataSymbolicExpression[]|undefined {
|
undefined {
|
||||||
if (decorators && decorators.length)
|
if (decorators && decorators.length)
|
||||||
return decorators.map(decorator => objFromDecorator(decorator));
|
return decorators.map(decorator => objFromDecorator(decorator));
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -550,7 +551,6 @@ export class MetadataCollector {
|
|||||||
__symbolic: 'module',
|
__symbolic: 'module',
|
||||||
version: this.options.version || METADATA_VERSION, metadata
|
version: this.options.version || METADATA_VERSION, metadata
|
||||||
};
|
};
|
||||||
if (sourceFile.moduleName) result.importAs = sourceFile.moduleName;
|
|
||||||
if (exports) result.exports = exports;
|
if (exports) result.exports = exports;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,10 @@
|
|||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {CollectorOptions} from './collector';
|
import {CollectorOptions} from './collector';
|
||||||
import {ClassMetadata, FunctionMetadata, InterfaceMetadata, MetadataEntry, MetadataError, MetadataImportedSymbolReferenceExpression, MetadataSourceLocationInfo, MetadataSymbolicCallExpression, MetadataValue, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportDefaultReference, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSpreadExpression} from './schema';
|
import {MetadataEntry, MetadataError, MetadataImportedSymbolReferenceExpression, MetadataSymbolicCallExpression, MetadataValue, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSpreadExpression} from './schema';
|
||||||
import {Symbols} from './symbols';
|
import {Symbols} from './symbols';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// In TypeScript 2.1 the spread element kind was renamed.
|
// In TypeScript 2.1 the spread element kind was renamed.
|
||||||
const spreadElementSyntaxKind: ts.SyntaxKind =
|
const spreadElementSyntaxKind: ts.SyntaxKind =
|
||||||
(ts.SyntaxKind as any).SpreadElement || (ts.SyntaxKind as any).SpreadElementExpression;
|
(ts.SyntaxKind as any).SpreadElement || (ts.SyntaxKind as any).SpreadElementExpression;
|
||||||
@ -39,24 +38,6 @@ function isCallOf(callExpression: ts.CallExpression, ident: string): boolean {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @internal */
|
|
||||||
export function recordMapEntry<T extends MetadataEntry>(
|
|
||||||
entry: T, node: ts.Node,
|
|
||||||
nodeMap: Map<MetadataValue|ClassMetadata|InterfaceMetadata|FunctionMetadata, ts.Node>,
|
|
||||||
sourceFile?: ts.SourceFile) {
|
|
||||||
if (!nodeMap.has(entry)) {
|
|
||||||
nodeMap.set(entry, node);
|
|
||||||
if (node && (isMetadataImportedSymbolReferenceExpression(entry) ||
|
|
||||||
isMetadataImportDefaultReference(entry)) &&
|
|
||||||
entry.line == null) {
|
|
||||||
const info = sourceInfo(node, sourceFile);
|
|
||||||
if (info.line != null) entry.line = info.line;
|
|
||||||
if (info.character != null) entry.character = info.character;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ts.forEachChild stops iterating children when the callback return a truthy value.
|
* ts.forEachChild stops iterating children when the callback return a truthy value.
|
||||||
* This method inverts this to implement an `every` style iterator. It will return
|
* This method inverts this to implement an `every` style iterator. It will return
|
||||||
@ -95,23 +76,22 @@ function getSourceFileOfNode(node: ts.Node | undefined): ts.SourceFile {
|
|||||||
return <ts.SourceFile>node;
|
return <ts.SourceFile>node;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @internal */
|
|
||||||
export function sourceInfo(
|
|
||||||
node: ts.Node | undefined, sourceFile: ts.SourceFile | undefined): MetadataSourceLocationInfo {
|
|
||||||
if (node) {
|
|
||||||
sourceFile = sourceFile || getSourceFileOfNode(node);
|
|
||||||
if (sourceFile) {
|
|
||||||
return ts.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* @internal */
|
/* @internal */
|
||||||
export function errorSymbol(
|
export function errorSymbol(
|
||||||
message: string, node?: ts.Node, context?: {[name: string]: string},
|
message: string, node?: ts.Node, context?: {[name: string]: string},
|
||||||
sourceFile?: ts.SourceFile): MetadataError {
|
sourceFile?: ts.SourceFile): MetadataError {
|
||||||
const result: MetadataError = {__symbolic: 'error', message, ...sourceInfo(node, sourceFile)};
|
let result: MetadataError|undefined = undefined;
|
||||||
|
if (node) {
|
||||||
|
sourceFile = sourceFile || getSourceFileOfNode(node);
|
||||||
|
if (sourceFile) {
|
||||||
|
const {line, character} =
|
||||||
|
ts.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile));
|
||||||
|
result = {__symbolic: 'error', message, line, character};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!result) {
|
||||||
|
result = {__symbolic: 'error', message};
|
||||||
|
}
|
||||||
if (context) {
|
if (context) {
|
||||||
result.context = context;
|
result.context = context;
|
||||||
}
|
}
|
||||||
@ -262,7 +242,8 @@ export class Evaluator {
|
|||||||
}
|
}
|
||||||
entry = newEntry;
|
entry = newEntry;
|
||||||
}
|
}
|
||||||
return recordMapEntry(entry, node, t.nodeMap);
|
t.nodeMap.set(entry, node);
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFoldableError(value: any): value is MetadataError {
|
function isFoldableError(value: any): value is MetadataError {
|
||||||
@ -275,9 +256,6 @@ export class Evaluator {
|
|||||||
// Encode as a global reference. StaticReflector will check the reference.
|
// Encode as a global reference. StaticReflector will check the reference.
|
||||||
return recordEntry({__symbolic: 'reference', name}, node);
|
return recordEntry({__symbolic: 'reference', name}, node);
|
||||||
}
|
}
|
||||||
if (reference && isMetadataSymbolicReferenceExpression(reference)) {
|
|
||||||
return recordEntry({...reference}, node);
|
|
||||||
}
|
|
||||||
return reference;
|
return reference;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -650,7 +628,7 @@ export class Evaluator {
|
|||||||
return recordEntry({__symbolic: 'if', condition, thenExpression, elseExpression}, node);
|
return recordEntry({__symbolic: 'if', condition, thenExpression, elseExpression}, node);
|
||||||
case ts.SyntaxKind.FunctionExpression:
|
case ts.SyntaxKind.FunctionExpression:
|
||||||
case ts.SyntaxKind.ArrowFunction:
|
case ts.SyntaxKind.ArrowFunction:
|
||||||
return recordEntry(errorSymbol('Lambda not supported', node), node);
|
return recordEntry(errorSymbol('Function call not supported', node), node);
|
||||||
case ts.SyntaxKind.TaggedTemplateExpression:
|
case ts.SyntaxKind.TaggedTemplateExpression:
|
||||||
return recordEntry(
|
return recordEntry(
|
||||||
errorSymbol('Tagged template expressions are not supported in metadata', node), node);
|
errorSymbol('Tagged template expressions are not supported in metadata', node), node);
|
||||||
|
@ -178,20 +178,7 @@ export function isMetadataSymbolicIfExpression(value: any): value is MetadataSym
|
|||||||
return value && value.__symbolic === 'if';
|
return value && value.__symbolic === 'if';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetadataSourceLocationInfo {
|
export interface MetadataGlobalReferenceExpression extends MetadataSymbolicExpression {
|
||||||
/**
|
|
||||||
* The line number of the error in the .ts file the metadata was created for.
|
|
||||||
*/
|
|
||||||
line?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of utf8 code-units from the beginning of the file of the error.
|
|
||||||
*/
|
|
||||||
character?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MetadataGlobalReferenceExpression extends MetadataSymbolicExpression,
|
|
||||||
MetadataSourceLocationInfo {
|
|
||||||
__symbolic: 'reference';
|
__symbolic: 'reference';
|
||||||
name: string;
|
name: string;
|
||||||
arguments?: MetadataValue[];
|
arguments?: MetadataValue[];
|
||||||
@ -201,8 +188,7 @@ export function isMetadataGlobalReferenceExpression(value: any):
|
|||||||
return value && value.name && !value.module && isMetadataSymbolicReferenceExpression(value);
|
return value && value.name && !value.module && isMetadataSymbolicReferenceExpression(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetadataModuleReferenceExpression extends MetadataSymbolicExpression,
|
export interface MetadataModuleReferenceExpression extends MetadataSymbolicExpression {
|
||||||
MetadataSourceLocationInfo {
|
|
||||||
__symbolic: 'reference';
|
__symbolic: 'reference';
|
||||||
module: string;
|
module: string;
|
||||||
}
|
}
|
||||||
@ -212,8 +198,7 @@ export function isMetadataModuleReferenceExpression(value: any):
|
|||||||
isMetadataSymbolicReferenceExpression(value);
|
isMetadataSymbolicReferenceExpression(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetadataImportedSymbolReferenceExpression extends MetadataSymbolicExpression,
|
export interface MetadataImportedSymbolReferenceExpression extends MetadataSymbolicExpression {
|
||||||
MetadataSourceLocationInfo {
|
|
||||||
__symbolic: 'reference';
|
__symbolic: 'reference';
|
||||||
module: string;
|
module: string;
|
||||||
name: string;
|
name: string;
|
||||||
@ -224,8 +209,7 @@ export function isMetadataImportedSymbolReferenceExpression(value: any):
|
|||||||
return value && value.module && !!value.name && isMetadataSymbolicReferenceExpression(value);
|
return value && value.module && !!value.name && isMetadataSymbolicReferenceExpression(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetadataImportedDefaultReferenceExpression extends MetadataSymbolicExpression,
|
export interface MetadataImportedDefaultReferenceExpression extends MetadataSymbolicExpression {
|
||||||
MetadataSourceLocationInfo {
|
|
||||||
__symbolic: 'reference';
|
__symbolic: 'reference';
|
||||||
module: string;
|
module: string;
|
||||||
default:
|
default:
|
||||||
@ -234,7 +218,7 @@ export interface MetadataImportedDefaultReferenceExpression extends MetadataSymb
|
|||||||
}
|
}
|
||||||
export function isMetadataImportDefaultReference(value: any):
|
export function isMetadataImportDefaultReference(value: any):
|
||||||
value is MetadataImportedDefaultReferenceExpression {
|
value is MetadataImportedDefaultReferenceExpression {
|
||||||
return value && value.module && value.default && isMetadataSymbolicReferenceExpression(value);
|
return value.module && value.default && isMetadataSymbolicReferenceExpression(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MetadataSymbolicReferenceExpression = MetadataGlobalReferenceExpression |
|
export type MetadataSymbolicReferenceExpression = MetadataGlobalReferenceExpression |
|
||||||
@ -264,7 +248,7 @@ export function isMetadataSymbolicSpreadExpression(value: any):
|
|||||||
return value && value.__symbolic === 'spread';
|
return value && value.__symbolic === 'spread';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetadataError extends MetadataSourceLocationInfo {
|
export interface MetadataError {
|
||||||
__symbolic: 'error';
|
__symbolic: 'error';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -275,6 +259,16 @@ export interface MetadataError extends MetadataSourceLocationInfo {
|
|||||||
*/
|
*/
|
||||||
message: string;
|
message: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The line number of the error in the .ts file the metadata was created for.
|
||||||
|
*/
|
||||||
|
line?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of utf8 code-units from the beginning of the file of the error.
|
||||||
|
*/
|
||||||
|
character?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The module of the error (only used in bundled metadata)
|
* The module of the error (only used in bundled metadata)
|
||||||
*/
|
*/
|
||||||
@ -286,7 +280,6 @@ export interface MetadataError extends MetadataSourceLocationInfo {
|
|||||||
*/
|
*/
|
||||||
context?: {[name: string]: string};
|
context?: {[name: string]: string};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isMetadataError(value: any): value is MetadataError {
|
export function isMetadataError(value: any): value is MetadataError {
|
||||||
return value && value.__symbolic === 'error';
|
return value && value.__symbolic === 'error';
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Position, isSyntaxError, syntaxError} from '@angular/compiler';
|
import {isSyntaxError, syntaxError} from '@angular/compiler';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
@ -29,77 +29,31 @@ const defaultFormatHost: ts.FormatDiagnosticsHost = {
|
|||||||
getNewLine: () => ts.sys.newLine
|
getNewLine: () => ts.sys.newLine
|
||||||
};
|
};
|
||||||
|
|
||||||
function displayFileName(fileName: string, host: ts.FormatDiagnosticsHost): string {
|
|
||||||
return path.relative(host.getCurrentDirectory(), host.getCanonicalFileName(fileName));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formatDiagnosticPosition(
|
|
||||||
position: Position, host: ts.FormatDiagnosticsHost = defaultFormatHost): string {
|
|
||||||
return `${displayFileName(position.fileName, host)}(${position.line + 1},${position.column+1})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function flattenDiagnosticMessageChain(
|
|
||||||
chain: api.DiagnosticMessageChain, host: ts.FormatDiagnosticsHost = defaultFormatHost): string {
|
|
||||||
let result = chain.messageText;
|
|
||||||
let indent = 1;
|
|
||||||
let current = chain.next;
|
|
||||||
const newLine = host.getNewLine();
|
|
||||||
while (current) {
|
|
||||||
result += newLine;
|
|
||||||
for (let i = 0; i < indent; i++) {
|
|
||||||
result += ' ';
|
|
||||||
}
|
|
||||||
result += current.messageText;
|
|
||||||
const position = current.position;
|
|
||||||
if (position) {
|
|
||||||
result += ` at ${formatDiagnosticPosition(position, host)}`;
|
|
||||||
}
|
|
||||||
current = current.next;
|
|
||||||
indent++;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formatDiagnostic(
|
|
||||||
diagnostic: api.Diagnostic, host: ts.FormatDiagnosticsHost = defaultFormatHost) {
|
|
||||||
let result = '';
|
|
||||||
const newLine = host.getNewLine();
|
|
||||||
const span = diagnostic.span;
|
|
||||||
if (span) {
|
|
||||||
result += `${formatDiagnosticPosition({
|
|
||||||
fileName: span.start.file.url,
|
|
||||||
line: span.start.line,
|
|
||||||
column: span.start.col
|
|
||||||
}, host)}: `;
|
|
||||||
} else if (diagnostic.position) {
|
|
||||||
result += `${formatDiagnosticPosition(diagnostic.position, host)}: `;
|
|
||||||
}
|
|
||||||
if (diagnostic.span && diagnostic.span.details) {
|
|
||||||
result += `: ${diagnostic.span.details}, ${diagnostic.messageText}${newLine}`;
|
|
||||||
} else if (diagnostic.chain) {
|
|
||||||
result += `${flattenDiagnosticMessageChain(diagnostic.chain, host)}.${newLine}`;
|
|
||||||
} else {
|
|
||||||
result += `: ${diagnostic.messageText}${newLine}`;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formatDiagnostics(
|
export function formatDiagnostics(
|
||||||
diags: Diagnostics, host: ts.FormatDiagnosticsHost = defaultFormatHost): string {
|
diags: Diagnostics, tsFormatHost: ts.FormatDiagnosticsHost = defaultFormatHost): string {
|
||||||
if (diags && diags.length) {
|
if (diags && diags.length) {
|
||||||
return diags
|
return diags
|
||||||
.map(diagnostic => {
|
.map(d => {
|
||||||
if (api.isTsDiagnostic(diagnostic)) {
|
if (api.isTsDiagnostic(d)) {
|
||||||
return ts.formatDiagnostics([diagnostic], host);
|
return ts.formatDiagnostics([d], tsFormatHost);
|
||||||
} else {
|
} else {
|
||||||
return formatDiagnostic(diagnostic, host);
|
let res = ts.DiagnosticCategory[d.category];
|
||||||
|
if (d.span) {
|
||||||
|
res +=
|
||||||
|
` at ${d.span.start.file.url}(${d.span.start.line + 1},${d.span.start.col + 1})`;
|
||||||
|
}
|
||||||
|
if (d.span && d.span.details) {
|
||||||
|
res += `: ${d.span.details}, ${d.messageText}\n`;
|
||||||
|
} else {
|
||||||
|
res += `: ${d.messageText}\n`;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.join('');
|
.join('');
|
||||||
} else {
|
} else
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export interface ParsedConfiguration {
|
export interface ParsedConfiguration {
|
||||||
project: string;
|
project: string;
|
||||||
|
@ -6,24 +6,16 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {GeneratedFile, ParseSourceSpan, Position} from '@angular/compiler';
|
import {GeneratedFile, ParseSourceSpan} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
export const DEFAULT_ERROR_CODE = 100;
|
export const DEFAULT_ERROR_CODE = 100;
|
||||||
export const UNKNOWN_ERROR_CODE = 500;
|
export const UNKNOWN_ERROR_CODE = 500;
|
||||||
export const SOURCE = 'angular' as 'angular';
|
export const SOURCE = 'angular' as 'angular';
|
||||||
|
|
||||||
export interface DiagnosticMessageChain {
|
|
||||||
messageText: string;
|
|
||||||
position?: Position;
|
|
||||||
next?: DiagnosticMessageChain;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Diagnostic {
|
export interface Diagnostic {
|
||||||
messageText: string;
|
messageText: string;
|
||||||
span?: ParseSourceSpan;
|
span?: ParseSourceSpan;
|
||||||
position?: Position;
|
|
||||||
chain?: DiagnosticMessageChain;
|
|
||||||
category: ts.DiagnosticCategory;
|
category: ts.DiagnosticCategory;
|
||||||
code: number;
|
code: number;
|
||||||
source: 'angular';
|
source: 'angular';
|
||||||
@ -200,13 +192,6 @@ export interface CompilerHost extends ts.CompilerHost {
|
|||||||
* cause a diagnostics diagnostic error or an exception to be thrown.
|
* cause a diagnostics diagnostic error or an exception to be thrown.
|
||||||
*/
|
*/
|
||||||
readResource?(fileName: string): Promise<string>|string;
|
readResource?(fileName: string): Promise<string>|string;
|
||||||
/**
|
|
||||||
* Produce an AMD module name for the source file. Used in Bazel.
|
|
||||||
*
|
|
||||||
* An AMD module can have an arbitrary name, so that it is require'd by name
|
|
||||||
* rather than by path. See http://requirejs.org/docs/whyamd.html#namedmodules
|
|
||||||
*/
|
|
||||||
amdModuleName?(sf: ts.SourceFile): string|undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum EmitFlags {
|
export enum EmitFlags {
|
||||||
|
@ -41,13 +41,6 @@ export interface CodeGenerator {
|
|||||||
findGeneratedFileNames(fileName: string): string[];
|
findGeneratedFileNames(fileName: string): string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function assert<T>(condition: T | null | undefined) {
|
|
||||||
if (!condition) {
|
|
||||||
// TODO(chuckjaz): do the right thing
|
|
||||||
}
|
|
||||||
return condition !;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the following hosts based on an api.CompilerHost:
|
* Implements the following hosts based on an api.CompilerHost:
|
||||||
* - ts.CompilerHost to be consumed by a ts.Program
|
* - ts.CompilerHost to be consumed by a ts.Program
|
||||||
@ -120,7 +113,7 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos
|
|||||||
return sf ? this.metadataProvider.getMetadata(sf) : undefined;
|
return sf ? this.metadataProvider.getMetadata(sf) : undefined;
|
||||||
},
|
},
|
||||||
fileExists: (filePath) => this.originalFileExists(filePath),
|
fileExists: (filePath) => this.originalFileExists(filePath),
|
||||||
readFile: (filePath) => assert(this.context.readFile(filePath)),
|
readFile: (filePath) => this.context.readFile(filePath),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,11 +296,6 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos
|
|||||||
/* emitSourceMaps */ false);
|
/* emitSourceMaps */ false);
|
||||||
const sf = ts.createSourceFile(
|
const sf = ts.createSourceFile(
|
||||||
genFile.genFileUrl, sourceText, this.options.target || ts.ScriptTarget.Latest);
|
genFile.genFileUrl, sourceText, this.options.target || ts.ScriptTarget.Latest);
|
||||||
if ((this.options.module === ts.ModuleKind.AMD || this.options.module === ts.ModuleKind.UMD) &&
|
|
||||||
this.context.amdModuleName) {
|
|
||||||
const moduleName = this.context.amdModuleName(sf);
|
|
||||||
if (moduleName) sf.moduleName = moduleName;
|
|
||||||
}
|
|
||||||
this.generatedSourceFiles.set(genFile.genFileUrl, {
|
this.generatedSourceFiles.set(genFile.genFileUrl, {
|
||||||
sourceFile: sf,
|
sourceFile: sf,
|
||||||
emitCtx: context, externalReferences,
|
emitCtx: context, externalReferences,
|
||||||
@ -433,7 +421,7 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos
|
|||||||
return summary.text;
|
return summary.text;
|
||||||
}
|
}
|
||||||
if (this.originalFileExists(filePath)) {
|
if (this.originalFileExists(filePath)) {
|
||||||
return assert(this.context.readFile(filePath));
|
return this.context.readFile(filePath);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -484,7 +472,7 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos
|
|||||||
if (!this.originalFileExists(filePath)) {
|
if (!this.originalFileExists(filePath)) {
|
||||||
throw syntaxError(`Error: Resource file not found: ${filePath}`);
|
throw syntaxError(`Error: Resource file not found: ${filePath}`);
|
||||||
}
|
}
|
||||||
return assert(this.context.readFile(filePath));
|
return this.context.readFile(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private hasBundleIndex(filePath: string): boolean {
|
private hasBundleIndex(filePath: string): boolean {
|
||||||
@ -502,13 +490,13 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos
|
|||||||
if (this.originalFileExists(packageFile)) {
|
if (this.originalFileExists(packageFile)) {
|
||||||
// Once we see a package.json file, assume false until it we find the bundle index.
|
// Once we see a package.json file, assume false until it we find the bundle index.
|
||||||
result = false;
|
result = false;
|
||||||
const packageContent: any = JSON.parse(assert(this.context.readFile(packageFile)));
|
const packageContent: any = JSON.parse(this.context.readFile(packageFile));
|
||||||
if (packageContent.typings) {
|
if (packageContent.typings) {
|
||||||
const typings = path.normalize(path.join(directory, packageContent.typings));
|
const typings = path.normalize(path.join(directory, packageContent.typings));
|
||||||
if (DTS.test(typings)) {
|
if (DTS.test(typings)) {
|
||||||
const metadataFile = typings.replace(DTS, '.metadata.json');
|
const metadataFile = typings.replace(DTS, '.metadata.json');
|
||||||
if (this.originalFileExists(metadataFile)) {
|
if (this.originalFileExists(metadataFile)) {
|
||||||
const metadata = JSON.parse(assert(this.context.readFile(metadataFile)));
|
const metadata = JSON.parse(this.context.readFile(metadataFile));
|
||||||
if (metadata.flatModuleIndexRedirect) {
|
if (metadata.flatModuleIndexRedirect) {
|
||||||
this.flatModuleIndexRedirectNames.add(typings);
|
this.flatModuleIndexRedirectNames.add(typings);
|
||||||
// Note: don't set result = true,
|
// Note: don't set result = true,
|
||||||
|
@ -112,7 +112,6 @@ function upgradeMetadataWithDtsData(
|
|||||||
newMetadata.metadata[prop] = dtsMetadata.metadata[prop];
|
newMetadata.metadata[prop] = dtsMetadata.metadata[prop];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dtsMetadata['importAs']) newMetadata['importAs'] = dtsMetadata['importAs'];
|
|
||||||
|
|
||||||
// Only copy exports from exports from metadata prior to version 3.
|
// Only copy exports from exports from metadata prior to version 3.
|
||||||
// Starting with version 3 the collector began collecting exports and
|
// Starting with version 3 the collector began collecting exports and
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AotCompiler, AotCompilerHost, AotCompilerOptions, EmitterVisitorContext, FormattedMessageChain, GeneratedFile, MessageBundle, NgAnalyzedFile, NgAnalyzedModules, ParseSourceSpan, Position, Serializer, TypeScriptEmitter, Xliff, Xliff2, Xmb, core, createAotCompiler, getParseErrors, isFormattedError, isSyntaxError} from '@angular/compiler';
|
import {AotCompiler, AotCompilerHost, AotCompilerOptions, EmitterVisitorContext, GeneratedFile, MessageBundle, NgAnalyzedFile, NgAnalyzedModules, ParseSourceSpan, Serializer, TypeScriptEmitter, Xliff, Xliff2, Xmb, core, createAotCompiler, getParseErrors, isSyntaxError} from '@angular/compiler';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
@ -14,13 +14,14 @@ import * as ts from 'typescript';
|
|||||||
import {TypeCheckHost, translateDiagnostics} from '../diagnostics/translate_diagnostics';
|
import {TypeCheckHost, translateDiagnostics} from '../diagnostics/translate_diagnostics';
|
||||||
import {ModuleMetadata, createBundleIndexHost} from '../metadata/index';
|
import {ModuleMetadata, createBundleIndexHost} from '../metadata/index';
|
||||||
|
|
||||||
import {CompilerHost, CompilerOptions, CustomTransformers, DEFAULT_ERROR_CODE, Diagnostic, DiagnosticMessageChain, EmitFlags, LazyRoute, LibrarySummary, Program, SOURCE, TsEmitArguments, TsEmitCallback} from './api';
|
import {CompilerHost, CompilerOptions, CustomTransformers, DEFAULT_ERROR_CODE, Diagnostic, EmitFlags, LazyRoute, LibrarySummary, Program, SOURCE, TsEmitArguments, TsEmitCallback} from './api';
|
||||||
import {CodeGenerator, TsCompilerAotCompilerTypeCheckHostAdapter, getOriginalReferences} from './compiler_host';
|
import {CodeGenerator, TsCompilerAotCompilerTypeCheckHostAdapter, getOriginalReferences} from './compiler_host';
|
||||||
import {LowerMetadataCache, getExpressionLoweringTransformFactory} from './lower_expressions';
|
import {LowerMetadataCache, getExpressionLoweringTransformFactory} from './lower_expressions';
|
||||||
import {getAngularEmitterTransformFactory} from './node_emitter_transform';
|
import {getAngularEmitterTransformFactory} from './node_emitter_transform';
|
||||||
import {GENERATED_FILES, StructureIsReused, createMessageDiagnostic, isInRootDir, ngToTsDiagnostic, tsStructureIsReused} from './util';
|
import {GENERATED_FILES, StructureIsReused, createMessageDiagnostic, isInRootDir, ngToTsDiagnostic, tsStructureIsReused} from './util';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum number of files that are emitable via calling ts.Program.emit
|
* Maximum number of files that are emitable via calling ts.Program.emit
|
||||||
* passing individual targetSourceFiles.
|
* passing individual targetSourceFiles.
|
||||||
@ -61,7 +62,7 @@ class AngularCompilerProgram implements Program {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private rootNames: string[], private options: CompilerOptions, private host: CompilerHost,
|
private rootNames: string[], private options: CompilerOptions, private host: CompilerHost,
|
||||||
oldProgram?: Program) {
|
private oldProgram?: Program) {
|
||||||
const [major, minor] = ts.version.split('.');
|
const [major, minor] = ts.version.split('.');
|
||||||
if (Number(major) < 2 || (Number(major) === 2 && Number(minor) < 4)) {
|
if (Number(major) < 2 || (Number(major) === 2 && Number(minor) < 4)) {
|
||||||
throw new Error('The Angular Compiler requires TypeScript >= 2.4.');
|
throw new Error('The Angular Compiler requires TypeScript >= 2.4.');
|
||||||
@ -377,12 +378,10 @@ class AngularCompilerProgram implements Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private get structuralDiagnostics(): Diagnostic[] {
|
private get structuralDiagnostics(): Diagnostic[] {
|
||||||
let diagnostics = this._structuralDiagnostics;
|
if (!this._structuralDiagnostics) {
|
||||||
if (!diagnostics) {
|
|
||||||
this.initSync();
|
this.initSync();
|
||||||
diagnostics = (this._structuralDiagnostics = this._structuralDiagnostics || []);
|
|
||||||
}
|
}
|
||||||
return diagnostics;
|
return this._structuralDiagnostics !;
|
||||||
}
|
}
|
||||||
|
|
||||||
private get tsProgram(): ts.Program {
|
private get tsProgram(): ts.Program {
|
||||||
@ -431,9 +430,16 @@ class AngularCompilerProgram implements Program {
|
|||||||
this.rootNames, this.options, this.host, this.metadataCache, codegen,
|
this.rootNames, this.options, this.host, this.metadataCache, codegen,
|
||||||
this.oldProgramLibrarySummaries);
|
this.oldProgramLibrarySummaries);
|
||||||
const aotOptions = getAotCompilerOptions(this.options);
|
const aotOptions = getAotCompilerOptions(this.options);
|
||||||
const errorCollector = (this.options.collectAllErrors || this.options.fullTemplateTypeCheck) ?
|
this._structuralDiagnostics = [];
|
||||||
(err: any) => this._addStructuralDiagnostics(err) :
|
const errorCollector =
|
||||||
undefined;
|
(this.options.collectAllErrors || this.options.fullTemplateTypeCheck) ? (err: any) => {
|
||||||
|
this._structuralDiagnostics !.push({
|
||||||
|
messageText: err.toString(),
|
||||||
|
category: ts.DiagnosticCategory.Error,
|
||||||
|
source: SOURCE,
|
||||||
|
code: DEFAULT_ERROR_CODE
|
||||||
|
});
|
||||||
|
} : undefined;
|
||||||
this._compiler = createAotCompiler(this._hostAdapter, aotOptions, errorCollector).compiler;
|
this._compiler = createAotCompiler(this._hostAdapter, aotOptions, errorCollector).compiler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,24 +522,31 @@ class AngularCompilerProgram implements Program {
|
|||||||
this._hostAdapter.isSourceFile = () => false;
|
this._hostAdapter.isSourceFile = () => false;
|
||||||
this._tsProgram = ts.createProgram(this.rootNames, this.options, this.hostAdapter);
|
this._tsProgram = ts.createProgram(this.rootNames, this.options, this.hostAdapter);
|
||||||
if (isSyntaxError(e)) {
|
if (isSyntaxError(e)) {
|
||||||
this._addStructuralDiagnostics(e);
|
const parserErrors = getParseErrors(e);
|
||||||
return;
|
if (parserErrors && parserErrors.length) {
|
||||||
}
|
this._structuralDiagnostics = [
|
||||||
throw e;
|
...(this._structuralDiagnostics || []),
|
||||||
}
|
...parserErrors.map<Diagnostic>(e => ({
|
||||||
|
messageText: e.contextualMessage(),
|
||||||
private _addStructuralDiagnostics(error: Error) {
|
category: ts.DiagnosticCategory.Error,
|
||||||
const diagnostics = this._structuralDiagnostics || (this._structuralDiagnostics = []);
|
span: e.span,
|
||||||
if (isSyntaxError(error)) {
|
source: SOURCE,
|
||||||
diagnostics.push(...syntaxErrorToDiagnostics(error));
|
code: DEFAULT_ERROR_CODE
|
||||||
|
}))
|
||||||
|
];
|
||||||
} else {
|
} else {
|
||||||
diagnostics.push({
|
this._structuralDiagnostics = [
|
||||||
messageText: error.toString(),
|
...(this._structuralDiagnostics || []), {
|
||||||
|
messageText: e.message,
|
||||||
category: ts.DiagnosticCategory.Error,
|
category: ts.DiagnosticCategory.Error,
|
||||||
source: SOURCE,
|
source: SOURCE,
|
||||||
code: DEFAULT_ERROR_CODE
|
code: DEFAULT_ERROR_CODE
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this returns a ts.Diagnostic so that we
|
// Note: this returns a ts.Diagnostic so that we
|
||||||
@ -593,8 +606,7 @@ class AngularCompilerProgram implements Program {
|
|||||||
|
|
||||||
private writeFile(
|
private writeFile(
|
||||||
outFileName: string, outData: string, writeByteOrderMark: boolean,
|
outFileName: string, outData: string, writeByteOrderMark: boolean,
|
||||||
onError?: (message: string) => void, genFile?: GeneratedFile,
|
onError?: (message: string) => void, genFile?: GeneratedFile, sourceFiles?: ts.SourceFile[]) {
|
||||||
sourceFiles?: ReadonlyArray<ts.SourceFile>) {
|
|
||||||
// collect emittedLibrarySummaries
|
// collect emittedLibrarySummaries
|
||||||
let baseFile: ts.SourceFile|undefined;
|
let baseFile: ts.SourceFile|undefined;
|
||||||
if (genFile) {
|
if (genFile) {
|
||||||
@ -641,8 +653,7 @@ class AngularCompilerProgram implements Program {
|
|||||||
if (baseFile) {
|
if (baseFile) {
|
||||||
sourceFiles = sourceFiles ? [...sourceFiles, baseFile] : [baseFile];
|
sourceFiles = sourceFiles ? [...sourceFiles, baseFile] : [baseFile];
|
||||||
}
|
}
|
||||||
// TODO: remove any when TS 2.4 support is removed.
|
this.host.writeFile(outFileName, outData, writeByteOrderMark, onError, sourceFiles);
|
||||||
this.host.writeFile(outFileName, outData, writeByteOrderMark, onError, sourceFiles as any);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -790,16 +801,9 @@ export function i18nSerialize(
|
|||||||
default:
|
default:
|
||||||
serializer = new Xliff();
|
serializer = new Xliff();
|
||||||
}
|
}
|
||||||
|
return bundle.write(
|
||||||
return bundle.write(serializer, getPathNormalizer(options.basePath));
|
serializer, (sourcePath: string) =>
|
||||||
}
|
options.basePath ? path.relative(options.basePath, sourcePath) : sourcePath);
|
||||||
|
|
||||||
function getPathNormalizer(basePath?: string) {
|
|
||||||
// normalize sourcepaths by removing the base path and always using "/" as a separator
|
|
||||||
return (sourcePath: string) => {
|
|
||||||
sourcePath = basePath ? path.relative(basePath, sourcePath) : sourcePath;
|
|
||||||
return sourcePath.split(path.sep).join('/');
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function i18nGetExtension(formatName: string): string {
|
export function i18nGetExtension(formatName: string): string {
|
||||||
@ -830,56 +834,3 @@ function mergeEmitResults(emitResults: ts.EmitResult[]): ts.EmitResult {
|
|||||||
}
|
}
|
||||||
return {diagnostics, emitSkipped, emittedFiles};
|
return {diagnostics, emitSkipped, emittedFiles};
|
||||||
}
|
}
|
||||||
|
|
||||||
function diagnosticSourceOfSpan(span: ParseSourceSpan): ts.SourceFile {
|
|
||||||
// For diagnostics, TypeScript only uses the fileName and text properties.
|
|
||||||
// The redundant '()' are here is to avoid having clang-format breaking the line incorrectly.
|
|
||||||
return ({ fileName: span.start.file.url, text: span.start.file.content } as any);
|
|
||||||
}
|
|
||||||
|
|
||||||
function diagnosticSourceOfFileName(fileName: string, program: ts.Program): ts.SourceFile {
|
|
||||||
const sourceFile = program.getSourceFile(fileName);
|
|
||||||
if (sourceFile) return sourceFile;
|
|
||||||
|
|
||||||
// If we are reporting diagnostics for a source file that is not in the project then we need
|
|
||||||
// to fake a source file so the diagnostic formatting routines can emit the file name.
|
|
||||||
// The redundant '()' are here is to avoid having clang-format breaking the line incorrectly.
|
|
||||||
return ({ fileName, text: '' } as any);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function diagnosticChainFromFormattedDiagnosticChain(chain: FormattedMessageChain):
|
|
||||||
DiagnosticMessageChain {
|
|
||||||
return {
|
|
||||||
messageText: chain.message,
|
|
||||||
next: chain.next && diagnosticChainFromFormattedDiagnosticChain(chain.next),
|
|
||||||
position: chain.position
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function syntaxErrorToDiagnostics(error: Error): Diagnostic[] {
|
|
||||||
const parserErrors = getParseErrors(error);
|
|
||||||
if (parserErrors && parserErrors.length) {
|
|
||||||
return parserErrors.map<Diagnostic>(e => ({
|
|
||||||
messageText: e.contextualMessage(),
|
|
||||||
file: diagnosticSourceOfSpan(e.span),
|
|
||||||
start: e.span.start.offset,
|
|
||||||
length: e.span.end.offset - e.span.start.offset,
|
|
||||||
category: ts.DiagnosticCategory.Error,
|
|
||||||
source: SOURCE,
|
|
||||||
code: DEFAULT_ERROR_CODE
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
if (isFormattedError(error)) {
|
|
||||||
return [{
|
|
||||||
messageText: error.message,
|
|
||||||
chain: error.chain && diagnosticChainFromFormattedDiagnosticChain(error.chain),
|
|
||||||
category: ts.DiagnosticCategory.Error,
|
|
||||||
source: SOURCE,
|
|
||||||
code: DEFAULT_ERROR_CODE,
|
|
||||||
position: error.position
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
@ -27,7 +27,7 @@ describe('metadata bundler', () => {
|
|||||||
|
|
||||||
const originalOne = './src/one';
|
const originalOne = './src/one';
|
||||||
const originalTwo = './src/two/index';
|
const originalTwo = './src/two/index';
|
||||||
expect(Object.keys(result.metadata.origins !)
|
expect(Object.keys(result.metadata.origins)
|
||||||
.sort()
|
.sort()
|
||||||
.map(name => ({name, value: result.metadata.origins ![name]})))
|
.map(name => ({name, value: result.metadata.origins ![name]})))
|
||||||
.toEqual([
|
.toEqual([
|
||||||
|
@ -45,7 +45,6 @@ describe('Collector', () => {
|
|||||||
're-exports.ts',
|
're-exports.ts',
|
||||||
're-exports-2.ts',
|
're-exports-2.ts',
|
||||||
'export-as.d.ts',
|
'export-as.d.ts',
|
||||||
'named-module.d.ts',
|
|
||||||
'static-field-reference.ts',
|
'static-field-reference.ts',
|
||||||
'static-method.ts',
|
'static-method.ts',
|
||||||
'static-method-call.ts',
|
'static-method-call.ts',
|
||||||
@ -102,12 +101,6 @@ describe('Collector', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should preserve module names from TypeScript sources', () => {
|
|
||||||
const sourceFile = program.getSourceFile('named-module.d.ts');
|
|
||||||
const metadata = collector.getMetadata(sourceFile);
|
|
||||||
expect(metadata !['importAs']).toEqual('some-named-module');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to collect a simple component\'s metadata', () => {
|
it('should be able to collect a simple component\'s metadata', () => {
|
||||||
const sourceFile = program.getSourceFile('app/hero-detail.component.ts');
|
const sourceFile = program.getSourceFile('app/hero-detail.component.ts');
|
||||||
const metadata = collector.getMetadata(sourceFile);
|
const metadata = collector.getMetadata(sourceFile);
|
||||||
@ -119,13 +112,7 @@ describe('Collector', () => {
|
|||||||
__symbolic: 'class',
|
__symbolic: 'class',
|
||||||
decorators: [{
|
decorators: [{
|
||||||
__symbolic: 'call',
|
__symbolic: 'call',
|
||||||
expression: {
|
expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Component'},
|
||||||
__symbolic: 'reference',
|
|
||||||
module: 'angular2/core',
|
|
||||||
name: 'Component',
|
|
||||||
line: 4,
|
|
||||||
character: 7
|
|
||||||
},
|
|
||||||
arguments: [{
|
arguments: [{
|
||||||
selector: 'my-hero-detail',
|
selector: 'my-hero-detail',
|
||||||
template: `
|
template: `
|
||||||
@ -145,13 +132,8 @@ describe('Collector', () => {
|
|||||||
__symbolic: 'property',
|
__symbolic: 'property',
|
||||||
decorators: [{
|
decorators: [{
|
||||||
__symbolic: 'call',
|
__symbolic: 'call',
|
||||||
expression: {
|
expression:
|
||||||
__symbolic: 'reference',
|
{__symbolic: 'reference', module: 'angular2/core', name: 'Input'}
|
||||||
module: 'angular2/core',
|
|
||||||
name: 'Input',
|
|
||||||
line: 18,
|
|
||||||
character: 9
|
|
||||||
}
|
|
||||||
}]
|
}]
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
@ -171,13 +153,7 @@ describe('Collector', () => {
|
|||||||
__symbolic: 'class',
|
__symbolic: 'class',
|
||||||
decorators: [{
|
decorators: [{
|
||||||
__symbolic: 'call',
|
__symbolic: 'call',
|
||||||
expression: {
|
expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Component'},
|
||||||
__symbolic: 'reference',
|
|
||||||
module: 'angular2/core',
|
|
||||||
name: 'Component',
|
|
||||||
line: 9,
|
|
||||||
character: 7
|
|
||||||
},
|
|
||||||
arguments: [{
|
arguments: [{
|
||||||
selector: 'my-app',
|
selector: 'my-app',
|
||||||
template: `
|
template: `
|
||||||
@ -196,52 +172,20 @@ describe('Collector', () => {
|
|||||||
__symbolic: 'reference',
|
__symbolic: 'reference',
|
||||||
module: './hero-detail.component',
|
module: './hero-detail.component',
|
||||||
name: 'HeroDetailComponent',
|
name: 'HeroDetailComponent',
|
||||||
line: 22,
|
|
||||||
character: 21
|
|
||||||
},
|
},
|
||||||
{
|
{__symbolic: 'reference', module: 'angular2/common', name: 'NgFor'}
|
||||||
__symbolic: 'reference',
|
|
||||||
module: 'angular2/common',
|
|
||||||
name: 'NgFor',
|
|
||||||
line: 22,
|
|
||||||
character: 42
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
providers: [{
|
providers: [{__symbolic: 'reference', module: './hero.service', default: true}],
|
||||||
__symbolic: 'reference',
|
|
||||||
module: './hero.service',
|
|
||||||
default: true,
|
|
||||||
line: 23,
|
|
||||||
character: 20
|
|
||||||
}],
|
|
||||||
pipes: [
|
pipes: [
|
||||||
{
|
{__symbolic: 'reference', module: 'angular2/common', name: 'LowerCasePipe'},
|
||||||
__symbolic: 'reference',
|
{__symbolic: 'reference', module: 'angular2/common', name: 'UpperCasePipe'}
|
||||||
module: 'angular2/common',
|
|
||||||
name: 'LowerCasePipe',
|
|
||||||
line: 24,
|
|
||||||
character: 16
|
|
||||||
},
|
|
||||||
{
|
|
||||||
__symbolic: 'reference',
|
|
||||||
module: 'angular2/common',
|
|
||||||
name: 'UpperCasePipe',
|
|
||||||
line: 24,
|
|
||||||
character: 38
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}]
|
}]
|
||||||
}],
|
}],
|
||||||
members: {
|
members: {
|
||||||
__ctor__: [{
|
__ctor__: [{
|
||||||
__symbolic: 'constructor',
|
__symbolic: 'constructor',
|
||||||
parameters: [{
|
parameters: [{__symbolic: 'reference', module: './hero.service', default: true}]
|
||||||
__symbolic: 'reference',
|
|
||||||
module: './hero.service',
|
|
||||||
default: true,
|
|
||||||
line: 31,
|
|
||||||
character: 42
|
|
||||||
}]
|
|
||||||
}],
|
}],
|
||||||
onSelect: [{__symbolic: 'method'}],
|
onSelect: [{__symbolic: 'method'}],
|
||||||
ngOnInit: [{__symbolic: 'method'}],
|
ngOnInit: [{__symbolic: 'method'}],
|
||||||
@ -292,23 +236,22 @@ describe('Collector', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should record annotations on set and get declarations', () => {
|
it('should record annotations on set and get declarations', () => {
|
||||||
const propertyData = (line: number) => ({
|
const propertyData = {
|
||||||
name: [{
|
name: [{
|
||||||
__symbolic: 'property',
|
__symbolic: 'property',
|
||||||
decorators: [{
|
decorators: [{
|
||||||
__symbolic: 'call',
|
__symbolic: 'call',
|
||||||
expression:
|
expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Input'},
|
||||||
{__symbolic: 'reference', module: 'angular2/core', name: 'Input', line, character: 9},
|
|
||||||
arguments: ['firstName']
|
arguments: ['firstName']
|
||||||
}]
|
}]
|
||||||
}]
|
}]
|
||||||
});
|
};
|
||||||
const caseGetProp = <ClassMetadata>casesMetadata.metadata['GetProp'];
|
const caseGetProp = <ClassMetadata>casesMetadata.metadata['GetProp'];
|
||||||
expect(caseGetProp.members).toEqual(propertyData(11));
|
expect(caseGetProp.members).toEqual(propertyData);
|
||||||
const caseSetProp = <ClassMetadata>casesMetadata.metadata['SetProp'];
|
const caseSetProp = <ClassMetadata>casesMetadata.metadata['SetProp'];
|
||||||
expect(caseSetProp.members).toEqual(propertyData(19));
|
expect(caseSetProp.members).toEqual(propertyData);
|
||||||
const caseFullProp = <ClassMetadata>casesMetadata.metadata['FullProp'];
|
const caseFullProp = <ClassMetadata>casesMetadata.metadata['FullProp'];
|
||||||
expect(caseFullProp.members).toEqual(propertyData(27));
|
expect(caseFullProp.members).toEqual(propertyData);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should record references to parameterized types', () => {
|
it('should record references to parameterized types', () => {
|
||||||
@ -317,13 +260,7 @@ describe('Collector', () => {
|
|||||||
__symbolic: 'class',
|
__symbolic: 'class',
|
||||||
decorators: [{
|
decorators: [{
|
||||||
__symbolic: 'call',
|
__symbolic: 'call',
|
||||||
expression: {
|
expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Injectable'}
|
||||||
__symbolic: 'reference',
|
|
||||||
module: 'angular2/core',
|
|
||||||
name: 'Injectable',
|
|
||||||
line: 40,
|
|
||||||
character: 7
|
|
||||||
}
|
|
||||||
}],
|
}],
|
||||||
members: {
|
members: {
|
||||||
__ctor__: [{
|
__ctor__: [{
|
||||||
@ -376,7 +313,7 @@ describe('Collector', () => {
|
|||||||
const ctor = <ConstructorMetadata>someClass.members !['__ctor__'][0];
|
const ctor = <ConstructorMetadata>someClass.members !['__ctor__'][0];
|
||||||
const parameters = ctor.parameters;
|
const parameters = ctor.parameters;
|
||||||
expect(parameters).toEqual([
|
expect(parameters).toEqual([
|
||||||
{__symbolic: 'reference', module: 'angular2/common', name: 'NgFor', line: 6, character: 29}
|
{__symbolic: 'reference', module: 'angular2/common', name: 'NgFor'}
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -461,7 +398,7 @@ describe('Collector', () => {
|
|||||||
const ctor = <ConstructorMetadata>someClass.members !['__ctor__'][0];
|
const ctor = <ConstructorMetadata>someClass.members !['__ctor__'][0];
|
||||||
const parameters = ctor.parameters;
|
const parameters = ctor.parameters;
|
||||||
expect(parameters).toEqual([
|
expect(parameters).toEqual([
|
||||||
{__symbolic: 'reference', module: 'angular2/common', name: 'NgFor', line: 6, character: 29}
|
{__symbolic: 'reference', module: 'angular2/common', name: 'NgFor'}
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -490,13 +427,7 @@ describe('Collector', () => {
|
|||||||
B: 1,
|
B: 1,
|
||||||
C: 30,
|
C: 30,
|
||||||
D: 40,
|
D: 40,
|
||||||
E: {
|
E: {__symbolic: 'reference', module: './exported-consts', name: 'constValue'}
|
||||||
__symbolic: 'reference',
|
|
||||||
module: './exported-consts',
|
|
||||||
name: 'constValue',
|
|
||||||
line: 5,
|
|
||||||
character: 75
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -526,25 +457,13 @@ describe('Collector', () => {
|
|||||||
expect(classData).toBeDefined();
|
expect(classData).toBeDefined();
|
||||||
expect(classData.decorators).toEqual([{
|
expect(classData.decorators).toEqual([{
|
||||||
__symbolic: 'call',
|
__symbolic: 'call',
|
||||||
expression: {
|
expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Component'},
|
||||||
__symbolic: 'reference',
|
|
||||||
module: 'angular2/core',
|
|
||||||
name: 'Component',
|
|
||||||
line: 4,
|
|
||||||
character: 5
|
|
||||||
},
|
|
||||||
arguments: [{
|
arguments: [{
|
||||||
providers: {
|
providers: {
|
||||||
__symbolic: 'call',
|
__symbolic: 'call',
|
||||||
expression: {
|
expression: {
|
||||||
__symbolic: 'select',
|
__symbolic: 'select',
|
||||||
expression: {
|
expression: {__symbolic: 'reference', module: './static-method', name: 'MyModule'},
|
||||||
__symbolic: 'reference',
|
|
||||||
module: './static-method',
|
|
||||||
name: 'MyModule',
|
|
||||||
line: 5,
|
|
||||||
character: 17
|
|
||||||
},
|
|
||||||
member: 'with'
|
member: 'with'
|
||||||
},
|
},
|
||||||
arguments: ['a']
|
arguments: ['a']
|
||||||
@ -570,25 +489,13 @@ describe('Collector', () => {
|
|||||||
expect(classData).toBeDefined();
|
expect(classData).toBeDefined();
|
||||||
expect(classData.decorators).toEqual([{
|
expect(classData.decorators).toEqual([{
|
||||||
__symbolic: 'call',
|
__symbolic: 'call',
|
||||||
expression: {
|
expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Component'},
|
||||||
__symbolic: 'reference',
|
|
||||||
module: 'angular2/core',
|
|
||||||
name: 'Component',
|
|
||||||
line: 4,
|
|
||||||
character: 5
|
|
||||||
},
|
|
||||||
arguments: [{
|
arguments: [{
|
||||||
providers: [{
|
providers: [{
|
||||||
provide: 'a',
|
provide: 'a',
|
||||||
useValue: {
|
useValue: {
|
||||||
__symbolic: 'select',
|
__symbolic: 'select',
|
||||||
expression: {
|
expression: {__symbolic: 'reference', module: './static-field', name: 'MyModule'},
|
||||||
__symbolic: 'reference',
|
|
||||||
module: './static-field',
|
|
||||||
name: 'MyModule',
|
|
||||||
line: 5,
|
|
||||||
character: 45
|
|
||||||
},
|
|
||||||
member: 'VALUE'
|
member: 'VALUE'
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
@ -671,20 +578,8 @@ describe('Collector', () => {
|
|||||||
const metadata = collector.getMetadata(source) !;
|
const metadata = collector.getMetadata(source) !;
|
||||||
expect(metadata.metadata).toEqual({
|
expect(metadata.metadata).toEqual({
|
||||||
MyClass: Object({__symbolic: 'class'}),
|
MyClass: Object({__symbolic: 'class'}),
|
||||||
OtherModule: {
|
OtherModule: {__symbolic: 'reference', module: './static-field-reference', name: 'Foo'},
|
||||||
__symbolic: 'reference',
|
MyOtherModule: {__symbolic: 'reference', module: './static-field', name: 'MyModule'}
|
||||||
module: './static-field-reference',
|
|
||||||
name: 'Foo',
|
|
||||||
line: 4,
|
|
||||||
character: 12
|
|
||||||
},
|
|
||||||
MyOtherModule: {
|
|
||||||
__symbolic: 'reference',
|
|
||||||
module: './static-field',
|
|
||||||
name: 'MyModule',
|
|
||||||
line: 4,
|
|
||||||
character: 25
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -703,13 +598,7 @@ describe('Collector', () => {
|
|||||||
__symbolic: 'class',
|
__symbolic: 'class',
|
||||||
decorators: [{
|
decorators: [{
|
||||||
__symbolic: 'call',
|
__symbolic: 'call',
|
||||||
expression: {
|
expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Component'},
|
||||||
__symbolic: 'reference',
|
|
||||||
module: 'angular2/core',
|
|
||||||
name: 'Component',
|
|
||||||
line: 11,
|
|
||||||
character: 5
|
|
||||||
},
|
|
||||||
arguments: [{providers: [{__symbolic: 'reference', name: 'REQUIRED_VALIDATOR'}]}]
|
arguments: [{providers: [{__symbolic: 'reference', name: 'REQUIRED_VALIDATOR'}]}]
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
@ -731,13 +620,7 @@ describe('Collector', () => {
|
|||||||
__symbolic: 'class',
|
__symbolic: 'class',
|
||||||
decorators: [{
|
decorators: [{
|
||||||
__symbolic: 'call',
|
__symbolic: 'call',
|
||||||
expression: {
|
expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Component'},
|
||||||
__symbolic: 'reference',
|
|
||||||
module: 'angular2/core',
|
|
||||||
name: 'Component',
|
|
||||||
line: 11,
|
|
||||||
character: 5
|
|
||||||
},
|
|
||||||
arguments: [{providers: [{__symbolic: 'reference', name: 'REQUIRED_VALIDATOR'}]}]
|
arguments: [{providers: [{__symbolic: 'reference', name: 'REQUIRED_VALIDATOR'}]}]
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
@ -770,13 +653,7 @@ describe('Collector', () => {
|
|||||||
__symbolic: 'constructor',
|
__symbolic: 'constructor',
|
||||||
parameterDecorators: [[{
|
parameterDecorators: [[{
|
||||||
__symbolic: 'call',
|
__symbolic: 'call',
|
||||||
expression: {
|
expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Inject'},
|
||||||
__symbolic: 'reference',
|
|
||||||
module: 'angular2/core',
|
|
||||||
name: 'Inject',
|
|
||||||
line: 6,
|
|
||||||
character: 19
|
|
||||||
},
|
|
||||||
arguments: ['a']
|
arguments: ['a']
|
||||||
}]],
|
}]],
|
||||||
parameters: [{__symbolic: 'reference', name: 'any'}]
|
parameters: [{__symbolic: 'reference', name: 'any'}]
|
||||||
@ -810,20 +687,13 @@ describe('Collector', () => {
|
|||||||
__symbolic: 'reference',
|
__symbolic: 'reference',
|
||||||
module: './external',
|
module: './external',
|
||||||
name: 'external',
|
name: 'external',
|
||||||
line: 0,
|
|
||||||
character: 68,
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should simplify a redundant template', () => {
|
it('should simplify a redundant template', () => {
|
||||||
e('`${external}`', 'import {external} from "./external";').toEqual({
|
e('`${external}`', 'import {external} from "./external";')
|
||||||
__symbolic: 'reference',
|
.toEqual({__symbolic: 'reference', module: './external', name: 'external'});
|
||||||
module: './external',
|
|
||||||
name: 'external',
|
|
||||||
line: 0,
|
|
||||||
character: 59
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to collect complex template with imported references', () => {
|
it('should be able to collect complex template with imported references', () => {
|
||||||
@ -840,18 +710,11 @@ describe('Collector', () => {
|
|||||||
__symbolic: 'binop',
|
__symbolic: 'binop',
|
||||||
operator: '+',
|
operator: '+',
|
||||||
left: 'foo:',
|
left: 'foo:',
|
||||||
right: {
|
right: {__symbolic: 'reference', module: './external', name: 'foo'}
|
||||||
__symbolic: 'reference',
|
|
||||||
module: './external',
|
|
||||||
name: 'foo',
|
|
||||||
line: 0,
|
|
||||||
character: 63
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
right: ', bar:'
|
right: ', bar:'
|
||||||
},
|
},
|
||||||
right:
|
right: {__symbolic: 'reference', module: './external', name: 'bar'}
|
||||||
{__symbolic: 'reference', module: './external', name: 'bar', line: 0, character: 75}
|
|
||||||
},
|
},
|
||||||
right: ', end'
|
right: ', end'
|
||||||
});
|
});
|
||||||
@ -878,11 +741,11 @@ describe('Collector', () => {
|
|||||||
__ctor__: [{
|
__ctor__: [{
|
||||||
__symbolic: 'constructor',
|
__symbolic: 'constructor',
|
||||||
parameters: [
|
parameters: [
|
||||||
{__symbolic: 'reference', module: './foo', name: 'Foo', line: 3, character: 24},
|
{__symbolic: 'reference', module: './foo', name: 'Foo'},
|
||||||
{__symbolic: 'reference', module: './foo', name: 'Foo', line: 3, character: 24},
|
{__symbolic: 'reference', module: './foo', name: 'Foo'},
|
||||||
{__symbolic: 'reference', module: './foo', name: 'Foo', line: 3, character: 24},
|
{__symbolic: 'reference', module: './foo', name: 'Foo'},
|
||||||
{__symbolic: 'reference', module: './foo', name: 'Foo', line: 3, character: 24},
|
{__symbolic: 'reference', module: './foo', name: 'Foo'},
|
||||||
{__symbolic: 'reference', module: './foo', name: 'Foo', line: 3, character: 24}
|
{__symbolic: 'reference', module: './foo', name: 'Foo'}
|
||||||
]
|
]
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
@ -962,9 +825,7 @@ describe('Collector', () => {
|
|||||||
extends: {
|
extends: {
|
||||||
__symbolic: 'reference',
|
__symbolic: 'reference',
|
||||||
module: './class-inheritance-parent',
|
module: './class-inheritance-parent',
|
||||||
name: 'ParentClassFromOtherFile',
|
name: 'ParentClassFromOtherFile'
|
||||||
line: 9,
|
|
||||||
character: 45,
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1522,10 +1383,6 @@ const FILES: Directory = {
|
|||||||
'export-as.d.ts': `
|
'export-as.d.ts': `
|
||||||
declare function someFunction(): void;
|
declare function someFunction(): void;
|
||||||
export { someFunction as SomeFunction };
|
export { someFunction as SomeFunction };
|
||||||
`,
|
|
||||||
'named-module.d.ts': `
|
|
||||||
/// <amd-module name="some-named-module" />
|
|
||||||
export type SomeType = 'a';
|
|
||||||
`,
|
`,
|
||||||
'local-symbol-ref.ts': `
|
'local-symbol-ref.ts': `
|
||||||
import {Component, Validators} from 'angular2/core';
|
import {Component, Validators} from 'angular2/core';
|
||||||
|
@ -149,14 +149,12 @@ describe('Evaluator', () => {
|
|||||||
const newExpression = program.getSourceFile('newExpression.ts');
|
const newExpression = program.getSourceFile('newExpression.ts');
|
||||||
expect(evaluator.evaluateNode(findVarInitializer(newExpression, 'someValue'))).toEqual({
|
expect(evaluator.evaluateNode(findVarInitializer(newExpression, 'someValue'))).toEqual({
|
||||||
__symbolic: 'new',
|
__symbolic: 'new',
|
||||||
expression:
|
expression: {__symbolic: 'reference', name: 'Value', module: './classes'},
|
||||||
{__symbolic: 'reference', name: 'Value', module: './classes', line: 4, character: 33},
|
|
||||||
arguments: ['name', 12]
|
arguments: ['name', 12]
|
||||||
});
|
});
|
||||||
expect(evaluator.evaluateNode(findVarInitializer(newExpression, 'complex'))).toEqual({
|
expect(evaluator.evaluateNode(findVarInitializer(newExpression, 'complex'))).toEqual({
|
||||||
__symbolic: 'new',
|
__symbolic: 'new',
|
||||||
expression:
|
expression: {__symbolic: 'reference', name: 'Value', module: './classes'},
|
||||||
{__symbolic: 'reference', name: 'Value', module: './classes', line: 5, character: 42},
|
|
||||||
arguments: ['name', 12]
|
arguments: ['name', 12]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -175,7 +173,8 @@ describe('Evaluator', () => {
|
|||||||
const errors = program.getSourceFile('errors.ts');
|
const errors = program.getSourceFile('errors.ts');
|
||||||
const fDecl = findVar(errors, 'f') !;
|
const fDecl = findVar(errors, 'f') !;
|
||||||
expect(evaluator.evaluateNode(fDecl.initializer !))
|
expect(evaluator.evaluateNode(fDecl.initializer !))
|
||||||
.toEqual({__symbolic: 'error', message: 'Lambda not supported', line: 1, character: 12});
|
.toEqual(
|
||||||
|
{__symbolic: 'error', message: 'Function call not supported', line: 1, character: 12});
|
||||||
const eDecl = findVar(errors, 'e') !;
|
const eDecl = findVar(errors, 'e') !;
|
||||||
expect(evaluator.evaluateNode(eDecl.type !)).toEqual({
|
expect(evaluator.evaluateNode(eDecl.type !)).toEqual({
|
||||||
__symbolic: 'error',
|
__symbolic: 'error',
|
||||||
|
@ -102,7 +102,6 @@ export class MockNode implements ts.Node {
|
|||||||
|
|
||||||
export class MockIdentifier extends MockNode implements ts.Identifier {
|
export class MockIdentifier extends MockNode implements ts.Identifier {
|
||||||
public text: string;
|
public text: string;
|
||||||
public escapedText: ts.__String;
|
|
||||||
// tslint:disable
|
// tslint:disable
|
||||||
public _primaryExpressionBrand: any;
|
public _primaryExpressionBrand: any;
|
||||||
public _memberExpressionBrand: any;
|
public _memberExpressionBrand: any;
|
||||||
@ -138,14 +137,12 @@ export class MockVariableDeclaration extends MockNode implements ts.VariableDecl
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class MockSymbol implements ts.Symbol {
|
export class MockSymbol implements ts.Symbol {
|
||||||
public escapedName: ts.__String;
|
|
||||||
constructor(
|
constructor(
|
||||||
public name: string, private node: ts.Declaration = MockVariableDeclaration.of(name),
|
public name: string, private node: ts.Declaration = MockVariableDeclaration.of(name),
|
||||||
public flags: ts.SymbolFlags = 0) {}
|
public flags: ts.SymbolFlags = 0) {}
|
||||||
|
|
||||||
getFlags(): ts.SymbolFlags { return this.flags; }
|
getFlags(): ts.SymbolFlags { return this.flags; }
|
||||||
getName(): string { return this.name; }
|
getName(): string { return this.name; }
|
||||||
getEscapedName(): ts.__String { return this.escapedName; }
|
|
||||||
getDeclarations(): ts.Declaration[] { return [this.node]; }
|
getDeclarations(): ts.Declaration[] { return [this.node]; }
|
||||||
getDocumentationComment(): ts.SymbolDisplayPart[] { return []; }
|
getDocumentationComment(): ts.SymbolDisplayPart[] { return []; }
|
||||||
// TODO(vicb): removed in TS 2.2
|
// TODO(vicb): removed in TS 2.2
|
||||||
|
@ -184,7 +184,8 @@ describe('ngc transformer command-line', () => {
|
|||||||
|
|
||||||
const exitCode = main(['-p', basePath], errorSpy);
|
const exitCode = main(['-p', basePath], errorSpy);
|
||||||
expect(errorSpy).toHaveBeenCalledTimes(1);
|
expect(errorSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(errorSpy.calls.mostRecent().args[0]).toContain('mymodule.ts.MyComp.html');
|
expect(errorSpy.calls.mostRecent().args[0])
|
||||||
|
.toContain('Error at ' + path.join(basePath, 'mymodule.ts.MyComp.html'));
|
||||||
expect(errorSpy.calls.mostRecent().args[0])
|
expect(errorSpy.calls.mostRecent().args[0])
|
||||||
.toContain(`Property 'unknownProp' does not exist on type 'MyComp'`);
|
.toContain(`Property 'unknownProp' does not exist on type 'MyComp'`);
|
||||||
|
|
||||||
@ -214,7 +215,8 @@ describe('ngc transformer command-line', () => {
|
|||||||
|
|
||||||
const exitCode = main(['-p', basePath], errorSpy);
|
const exitCode = main(['-p', basePath], errorSpy);
|
||||||
expect(errorSpy).toHaveBeenCalledTimes(1);
|
expect(errorSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(errorSpy.calls.mostRecent().args[0]).toContain('my.component.html(1,5):');
|
expect(errorSpy.calls.mostRecent().args[0])
|
||||||
|
.toContain('Error at ' + path.join(basePath, 'my.component.html(1,5):'));
|
||||||
expect(errorSpy.calls.mostRecent().args[0])
|
expect(errorSpy.calls.mostRecent().args[0])
|
||||||
.toContain(`Property 'unknownProp' does not exist on type 'MyComp'`);
|
.toContain(`Property 'unknownProp' does not exist on type 'MyComp'`);
|
||||||
|
|
||||||
@ -1564,49 +1566,4 @@ describe('ngc transformer command-line', () => {
|
|||||||
expect(main(['-p', path.join(basePath, 'src/tsconfig.json')])).toBe(0);
|
expect(main(['-p', path.join(basePath, 'src/tsconfig.json')])).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('formatted messages', () => {
|
|
||||||
it('should emit a formatted error message for a structural error', () => {
|
|
||||||
write('src/tsconfig.json', `{
|
|
||||||
"extends": "../tsconfig-base.json",
|
|
||||||
"files": ["test-module.ts"]
|
|
||||||
}`);
|
|
||||||
write('src/lib/indirect2.ts', `
|
|
||||||
declare var f: any;
|
|
||||||
|
|
||||||
export const t2 = f\`<p>hello</p>\`;
|
|
||||||
`);
|
|
||||||
write('src/lib/indirect1.ts', `
|
|
||||||
import {t2} from './indirect2';
|
|
||||||
export const t1 = t2 + ' ';
|
|
||||||
`);
|
|
||||||
write('src/lib/test.component.ts', `
|
|
||||||
import {Component} from '@angular/core';
|
|
||||||
import {t1} from './indirect1';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
template: t1,
|
|
||||||
styleUrls: ['./test.component.css']
|
|
||||||
})
|
|
||||||
export class TestComponent {}
|
|
||||||
`);
|
|
||||||
write('src/test-module.ts', `
|
|
||||||
import {NgModule} from '@angular/core';
|
|
||||||
import {TestComponent} from './lib/test.component';
|
|
||||||
|
|
||||||
@NgModule({declarations: [TestComponent]})
|
|
||||||
export class TestModule {}
|
|
||||||
`);
|
|
||||||
const messages: string[] = [];
|
|
||||||
const exitCode =
|
|
||||||
main(['-p', path.join(basePath, 'src/tsconfig.json')], message => messages.push(message));
|
|
||||||
expect(exitCode).toBe(1, 'Compile was expected to fail');
|
|
||||||
expect(messages[0])
|
|
||||||
.toEqual(`lib/test.component.ts(6,21): Error during template compile of 'TestComponent'
|
|
||||||
Tagged template expressions are not supported in metadata in 't1'
|
|
||||||
't1' references 't2' at lib/indirect1.ts(3,27)
|
|
||||||
't2' contains the error at lib/indirect2.ts(4,27).
|
|
||||||
`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
@ -119,7 +119,7 @@ describe('perform watch', () => {
|
|||||||
const errorFileContent = `
|
const errorFileContent = `
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
|
|
||||||
@NgModule((() => (1===1 ? null as any : null as any)) as any)
|
@NgModule(() => (1===1 ? null as any : null as any))
|
||||||
export class MyModule {}
|
export class MyModule {}
|
||||||
`;
|
`;
|
||||||
const indexTsPath = path.resolve(testSupport.basePath, 'src', 'index.ts');
|
const indexTsPath = path.resolve(testSupport.basePath, 'src', 'index.ts');
|
||||||
@ -143,7 +143,7 @@ describe('perform watch', () => {
|
|||||||
|
|
||||||
const errDiags = host.diagnostics.filter(d => d.category === ts.DiagnosticCategory.Error);
|
const errDiags = host.diagnostics.filter(d => d.category === ts.DiagnosticCategory.Error);
|
||||||
expect(errDiags.length).toBe(1);
|
expect(errDiags.length).toBe(1);
|
||||||
expect(errDiags[0].messageText).toContain('Function expressions are not supported');
|
expect(errDiags[0].messageText).toContain('Function calls are not supported.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -325,7 +325,7 @@ describe('ng program', () => {
|
|||||||
'src/main.ts': `
|
'src/main.ts': `
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
|
|
||||||
@NgModule((() => {if (1==1) return null as any;}) as any)
|
@NgModule(() => {if (1==1) return null as any;})
|
||||||
export class SomeClassWithInvalidMetadata {}
|
export class SomeClassWithInvalidMetadata {}
|
||||||
`,
|
`,
|
||||||
});
|
});
|
||||||
@ -930,7 +930,7 @@ describe('ng program', () => {
|
|||||||
|
|
||||||
const structuralErrors = program.getNgStructuralDiagnostics();
|
const structuralErrors = program.getNgStructuralDiagnostics();
|
||||||
expect(structuralErrors.length).toBe(1);
|
expect(structuralErrors.length).toBe(1);
|
||||||
expect(structuralErrors[0].messageText).toContain('Function expressions are not supported');
|
expect(structuralErrors[0].messageText).toContain('Function calls are not supported.');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not throw on structural errors but collect them (loadNgStructureAsync)', (done) => {
|
it('should not throw on structural errors but collect them (loadNgStructureAsync)', (done) => {
|
||||||
@ -943,7 +943,7 @@ describe('ng program', () => {
|
|||||||
program.loadNgStructureAsync().then(() => {
|
program.loadNgStructureAsync().then(() => {
|
||||||
const structuralErrors = program.getNgStructuralDiagnostics();
|
const structuralErrors = program.getNgStructuralDiagnostics();
|
||||||
expect(structuralErrors.length).toBe(1);
|
expect(structuralErrors.length).toBe(1);
|
||||||
expect(structuralErrors[0].messageText).toContain('Function expressions are not supported');
|
expect(structuralErrors[0].messageText).toContain('Function calls are not supported.');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -982,8 +982,7 @@ describe('ng program', () => {
|
|||||||
const program = ng.createProgram({rootNames: allRootNames, options, host});
|
const program = ng.createProgram({rootNames: allRootNames, options, host});
|
||||||
const structuralErrors = program.getNgStructuralDiagnostics();
|
const structuralErrors = program.getNgStructuralDiagnostics();
|
||||||
expect(structuralErrors.length).toBe(1);
|
expect(structuralErrors.length).toBe(1);
|
||||||
expect(structuralErrors[0].messageText)
|
expect(structuralErrors[0].messageText).toContain('Function calls are not supported.');
|
||||||
.toContain('Function expressions are not supported');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {syntaxError} from '../util';
|
|
||||||
|
|
||||||
export interface Position {
|
|
||||||
fileName: string;
|
|
||||||
line: number;
|
|
||||||
column: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FormattedMessageChain {
|
|
||||||
message: string;
|
|
||||||
position?: Position;
|
|
||||||
next?: FormattedMessageChain;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type FormattedError = Error & {
|
|
||||||
chain: FormattedMessageChain;
|
|
||||||
position?: Position;
|
|
||||||
};
|
|
||||||
|
|
||||||
const FORMATTED_MESSAGE = 'ngFormattedMessage';
|
|
||||||
|
|
||||||
function indentStr(level: number): string {
|
|
||||||
if (level <= 0) return '';
|
|
||||||
if (level < 6) return ['', ' ', ' ', ' ', ' ', ' '][level];
|
|
||||||
const half = indentStr(Math.floor(level / 2));
|
|
||||||
return half + half + (level % 2 === 1 ? ' ' : '');
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatChain(chain: FormattedMessageChain | undefined, indent: number = 0): string {
|
|
||||||
if (!chain) return '';
|
|
||||||
const position = chain.position ?
|
|
||||||
`${chain.position.fileName}(${chain.position.line+1},${chain.position.column+1})` :
|
|
||||||
'';
|
|
||||||
const prefix = position && indent === 0 ? `${position}: ` : '';
|
|
||||||
const postfix = position && indent !== 0 ? ` at ${position}` : '';
|
|
||||||
const message = `${prefix}${chain.message}${postfix}`;
|
|
||||||
|
|
||||||
return `${indentStr(indent)}${message}${(chain.next && ('\n' + formatChain(chain.next, indent + 2))) || ''}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formattedError(chain: FormattedMessageChain): FormattedError {
|
|
||||||
const message = formatChain(chain) + '.';
|
|
||||||
const error = syntaxError(message) as FormattedError;
|
|
||||||
(error as any)[FORMATTED_MESSAGE] = true;
|
|
||||||
error.chain = chain;
|
|
||||||
error.position = chain.position;
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isFormattedError(error: Error): error is FormattedError {
|
|
||||||
return !!(error as any)[FORMATTED_MESSAGE];
|
|
||||||
}
|
|
@ -13,7 +13,6 @@ import * as o from '../output/output_ast';
|
|||||||
import {SummaryResolver} from '../summary_resolver';
|
import {SummaryResolver} from '../summary_resolver';
|
||||||
import {syntaxError} from '../util';
|
import {syntaxError} from '../util';
|
||||||
|
|
||||||
import {FormattedMessageChain, formattedError} from './formatted_error';
|
|
||||||
import {StaticSymbol} from './static_symbol';
|
import {StaticSymbol} from './static_symbol';
|
||||||
import {StaticSymbolResolver} from './static_symbol_resolver';
|
import {StaticSymbolResolver} from './static_symbol_resolver';
|
||||||
|
|
||||||
@ -99,17 +98,12 @@ export class StaticReflector implements CompileReflector {
|
|||||||
|
|
||||||
findSymbolDeclaration(symbol: StaticSymbol): StaticSymbol {
|
findSymbolDeclaration(symbol: StaticSymbol): StaticSymbol {
|
||||||
const resolvedSymbol = this.symbolResolver.resolveSymbol(symbol);
|
const resolvedSymbol = this.symbolResolver.resolveSymbol(symbol);
|
||||||
if (resolvedSymbol) {
|
if (resolvedSymbol && resolvedSymbol.metadata instanceof StaticSymbol) {
|
||||||
let resolvedMetadata = resolvedSymbol.metadata;
|
|
||||||
if (resolvedMetadata && resolvedMetadata.__symbolic === 'resolved') {
|
|
||||||
resolvedMetadata = resolvedMetadata.symbol;
|
|
||||||
}
|
|
||||||
if (resolvedMetadata instanceof StaticSymbol) {
|
|
||||||
return this.findSymbolDeclaration(resolvedSymbol.metadata);
|
return this.findSymbolDeclaration(resolvedSymbol.metadata);
|
||||||
}
|
} else {
|
||||||
}
|
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public annotations(type: StaticSymbol): any[] {
|
public annotations(type: StaticSymbol): any[] {
|
||||||
let annotations = this.annotationCache.get(type);
|
let annotations = this.annotationCache.get(type);
|
||||||
@ -136,12 +130,9 @@ export class StaticReflector implements CompileReflector {
|
|||||||
(requiredType) => ownAnnotations.some(ann => requiredType.isTypeOf(ann)));
|
(requiredType) => ownAnnotations.some(ann => requiredType.isTypeOf(ann)));
|
||||||
if (!typeHasRequiredAnnotation) {
|
if (!typeHasRequiredAnnotation) {
|
||||||
this.reportError(
|
this.reportError(
|
||||||
formatMetadataError(
|
syntaxError(
|
||||||
metadataError(
|
`Class ${type.name} in ${type.filePath} extends from a ${CompileSummaryKind[summary.type.summaryKind!]} in another compilation unit without duplicating the decorator. ` +
|
||||||
`Class ${type.name} in ${type.filePath} extends from a ${CompileSummaryKind[summary.type.summaryKind!]} in another compilation unit without duplicating the decorator`,
|
`Please add a ${requiredAnnotationTypes.map((type) => type.ngMetadataName).join(' or ')} decorator to the class.`),
|
||||||
/* summary */ undefined,
|
|
||||||
`Please add a ${requiredAnnotationTypes.map((type) => type.ngMetadataName).join(' or ')} decorator to the class`),
|
|
||||||
type),
|
|
||||||
type);
|
type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -343,6 +334,14 @@ export class StaticReflector implements CompileReflector {
|
|||||||
return this.symbolResolver.getStaticSymbol(declarationFile, name, members);
|
return this.symbolResolver.getStaticSymbol(declarationFile, name, members);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private reportError(error: Error, context: StaticSymbol, path?: string) {
|
||||||
|
if (this.errorRecorder) {
|
||||||
|
this.errorRecorder(error, (context && context.filePath) || path);
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simplify but discard any errors
|
* Simplify but discard any errors
|
||||||
*/
|
*/
|
||||||
@ -359,7 +358,6 @@ export class StaticReflector implements CompileReflector {
|
|||||||
const self = this;
|
const self = this;
|
||||||
let scope = BindingScope.empty;
|
let scope = BindingScope.empty;
|
||||||
const calling = new Map<StaticSymbol, boolean>();
|
const calling = new Map<StaticSymbol, boolean>();
|
||||||
const rootContext = context;
|
|
||||||
|
|
||||||
function simplifyInContext(
|
function simplifyInContext(
|
||||||
context: StaticSymbol, value: any, depth: number, references: number): any {
|
context: StaticSymbol, value: any, depth: number, references: number): any {
|
||||||
@ -368,64 +366,17 @@ export class StaticReflector implements CompileReflector {
|
|||||||
return resolvedSymbol ? resolvedSymbol.metadata : null;
|
return resolvedSymbol ? resolvedSymbol.metadata : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function simplifyEagerly(value: any): any {
|
function simplifyCall(functionSymbol: StaticSymbol, targetFunction: any, args: any[]) {
|
||||||
return simplifyInContext(context, value, depth, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function simplifyLazily(value: any): any {
|
|
||||||
return simplifyInContext(context, value, depth, references + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function simplifyNested(nestedContext: StaticSymbol, value: any): any {
|
|
||||||
if (nestedContext === context) {
|
|
||||||
// If the context hasn't changed let the exception propagate unmodified.
|
|
||||||
return simplifyInContext(nestedContext, value, depth + 1, references);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return simplifyInContext(nestedContext, value, depth + 1, references);
|
|
||||||
} catch (e) {
|
|
||||||
if (isMetadataError(e)) {
|
|
||||||
// Propagate the message text up but add a message to the chain that explains how we got
|
|
||||||
// here.
|
|
||||||
// e.chain implies e.symbol
|
|
||||||
const summaryMsg = e.chain ? 'references \'' + e.symbol !.name + '\'' : errorSummary(e);
|
|
||||||
const summary = `'${nestedContext.name}' ${summaryMsg}`;
|
|
||||||
const chain = {message: summary, position: e.position, next: e.chain};
|
|
||||||
// TODO(chuckj): retrieve the position information indirectly from the collectors node
|
|
||||||
// map if the metadata is from a .ts file.
|
|
||||||
self.error(
|
|
||||||
{
|
|
||||||
message: e.message,
|
|
||||||
advise: e.advise,
|
|
||||||
context: e.context, chain,
|
|
||||||
symbol: nestedContext
|
|
||||||
},
|
|
||||||
context);
|
|
||||||
} else {
|
|
||||||
// It is probably an internal error.
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function simplifyCall(
|
|
||||||
functionSymbol: StaticSymbol, targetFunction: any, args: any[], targetExpression: any) {
|
|
||||||
if (targetFunction && targetFunction['__symbolic'] == 'function') {
|
if (targetFunction && targetFunction['__symbolic'] == 'function') {
|
||||||
if (calling.get(functionSymbol)) {
|
if (calling.get(functionSymbol)) {
|
||||||
self.error(
|
throw new Error('Recursion not supported');
|
||||||
{
|
|
||||||
message: 'Recursion is not supported',
|
|
||||||
summary: `called '${functionSymbol.name}' recursively`,
|
|
||||||
value: targetFunction
|
|
||||||
},
|
|
||||||
functionSymbol);
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const value = targetFunction['value'];
|
const value = targetFunction['value'];
|
||||||
if (value && (depth != 0 || value.__symbolic != 'error')) {
|
if (value && (depth != 0 || value.__symbolic != 'error')) {
|
||||||
const parameters: string[] = targetFunction['parameters'];
|
const parameters: string[] = targetFunction['parameters'];
|
||||||
const defaults: any[] = targetFunction.defaults;
|
const defaults: any[] = targetFunction.defaults;
|
||||||
args = args.map(arg => simplifyNested(context, arg))
|
args = args.map(arg => simplifyInContext(context, arg, depth + 1, references))
|
||||||
.map(arg => shouldIgnore(arg) ? undefined : arg);
|
.map(arg => shouldIgnore(arg) ? undefined : arg);
|
||||||
if (defaults && defaults.length > args.length) {
|
if (defaults && defaults.length > args.length) {
|
||||||
args.push(...defaults.slice(args.length).map((value: any) => simplify(value)));
|
args.push(...defaults.slice(args.length).map((value: any) => simplify(value)));
|
||||||
@ -439,7 +390,7 @@ export class StaticReflector implements CompileReflector {
|
|||||||
let result: any;
|
let result: any;
|
||||||
try {
|
try {
|
||||||
scope = functionScope.done();
|
scope = functionScope.done();
|
||||||
result = simplifyNested(functionSymbol, value);
|
result = simplifyInContext(functionSymbol, value, depth + 1, references);
|
||||||
} finally {
|
} finally {
|
||||||
scope = oldScope;
|
scope = oldScope;
|
||||||
}
|
}
|
||||||
@ -456,22 +407,8 @@ export class StaticReflector implements CompileReflector {
|
|||||||
// non-angular decorator, and we should just ignore it.
|
// non-angular decorator, and we should just ignore it.
|
||||||
return IGNORE;
|
return IGNORE;
|
||||||
}
|
}
|
||||||
let position: Position|undefined = undefined;
|
return simplify(
|
||||||
if (targetExpression && targetExpression.__symbolic == 'resolved') {
|
{__symbolic: 'error', message: 'Function call not supported', context: functionSymbol});
|
||||||
const line = targetExpression.line;
|
|
||||||
const character = targetExpression.character;
|
|
||||||
const fileName = targetExpression.fileName;
|
|
||||||
if (fileName != null && line != null && character != null) {
|
|
||||||
position = {fileName, line, column: character};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.error(
|
|
||||||
{
|
|
||||||
message: FUNCTION_CALL_NOT_SUPPORTED,
|
|
||||||
context: functionSymbol,
|
|
||||||
value: targetFunction, position
|
|
||||||
},
|
|
||||||
context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function simplify(expression: any): any {
|
function simplify(expression: any): any {
|
||||||
@ -485,7 +422,7 @@ export class StaticReflector implements CompileReflector {
|
|||||||
if (item && item.__symbolic === 'spread') {
|
if (item && item.__symbolic === 'spread') {
|
||||||
// We call with references as 0 because we require the actual value and cannot
|
// We call with references as 0 because we require the actual value and cannot
|
||||||
// tolerate a reference here.
|
// tolerate a reference here.
|
||||||
const spreadArray = simplifyEagerly(item.expression);
|
const spreadArray = simplifyInContext(context, item.expression, depth, 0);
|
||||||
if (Array.isArray(spreadArray)) {
|
if (Array.isArray(spreadArray)) {
|
||||||
for (const spreadItem of spreadArray) {
|
for (const spreadItem of spreadArray) {
|
||||||
result.push(spreadItem);
|
result.push(spreadItem);
|
||||||
@ -511,7 +448,7 @@ export class StaticReflector implements CompileReflector {
|
|||||||
const staticSymbol = expression;
|
const staticSymbol = expression;
|
||||||
const declarationValue = resolveReferenceValue(staticSymbol);
|
const declarationValue = resolveReferenceValue(staticSymbol);
|
||||||
if (declarationValue != null) {
|
if (declarationValue != null) {
|
||||||
return simplifyNested(staticSymbol, declarationValue);
|
return simplifyInContext(staticSymbol, declarationValue, depth + 1, references);
|
||||||
} else {
|
} else {
|
||||||
return staticSymbol;
|
return staticSymbol;
|
||||||
}
|
}
|
||||||
@ -588,8 +525,8 @@ export class StaticReflector implements CompileReflector {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
case 'index':
|
case 'index':
|
||||||
let indexTarget = simplifyEagerly(expression['expression']);
|
let indexTarget = simplifyInContext(context, expression['expression'], depth, 0);
|
||||||
let index = simplifyEagerly(expression['index']);
|
let index = simplifyInContext(context, expression['index'], depth, 0);
|
||||||
if (indexTarget && isPrimitive(index)) return indexTarget[index];
|
if (indexTarget && isPrimitive(index)) return indexTarget[index];
|
||||||
return null;
|
return null;
|
||||||
case 'select':
|
case 'select':
|
||||||
@ -602,41 +539,26 @@ export class StaticReflector implements CompileReflector {
|
|||||||
self.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
|
self.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
|
||||||
const declarationValue = resolveReferenceValue(selectContext);
|
const declarationValue = resolveReferenceValue(selectContext);
|
||||||
if (declarationValue != null) {
|
if (declarationValue != null) {
|
||||||
return simplifyNested(selectContext, declarationValue);
|
return simplifyInContext(
|
||||||
|
selectContext, declarationValue, depth + 1, references);
|
||||||
} else {
|
} else {
|
||||||
return selectContext;
|
return selectContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (selectTarget && isPrimitive(member))
|
if (selectTarget && isPrimitive(member))
|
||||||
return simplifyNested(selectContext, selectTarget[member]);
|
return simplifyInContext(
|
||||||
|
selectContext, selectTarget[member], depth + 1, references);
|
||||||
return null;
|
return null;
|
||||||
case 'reference':
|
case 'reference':
|
||||||
// Note: This only has to deal with variable references, as symbol references have
|
// Note: This only has to deal with variable references,
|
||||||
// been converted into 'resolved'
|
// as symbol references have been converted into StaticSymbols already
|
||||||
// in the StaticSymbolResolver.
|
// in the StaticSymbolResolver!
|
||||||
const name: string = expression['name'];
|
const name: string = expression['name'];
|
||||||
const localValue = scope.resolve(name);
|
const localValue = scope.resolve(name);
|
||||||
if (localValue != BindingScope.missing) {
|
if (localValue != BindingScope.missing) {
|
||||||
return localValue;
|
return localValue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'resolved':
|
|
||||||
try {
|
|
||||||
return simplify(expression.symbol);
|
|
||||||
} catch (e) {
|
|
||||||
// If an error is reported evaluating the symbol record the position of the
|
|
||||||
// reference in the error so it can
|
|
||||||
// be reported in the error message generated from the exception.
|
|
||||||
if (isMetadataError(e) && expression.fileName != null &&
|
|
||||||
expression.line != null && expression.character != null) {
|
|
||||||
e.position = {
|
|
||||||
fileName: expression.fileName,
|
|
||||||
line: expression.line,
|
|
||||||
column: expression.character
|
|
||||||
};
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
case 'class':
|
case 'class':
|
||||||
return context;
|
return context;
|
||||||
case 'function':
|
case 'function':
|
||||||
@ -658,34 +580,29 @@ export class StaticReflector implements CompileReflector {
|
|||||||
const argExpressions: any[] = expression['arguments'] || [];
|
const argExpressions: any[] = expression['arguments'] || [];
|
||||||
let converter = self.conversionMap.get(staticSymbol);
|
let converter = self.conversionMap.get(staticSymbol);
|
||||||
if (converter) {
|
if (converter) {
|
||||||
const args = argExpressions.map(arg => simplifyNested(context, arg))
|
const args =
|
||||||
|
argExpressions
|
||||||
|
.map(arg => simplifyInContext(context, arg, depth + 1, references))
|
||||||
.map(arg => shouldIgnore(arg) ? undefined : arg);
|
.map(arg => shouldIgnore(arg) ? undefined : arg);
|
||||||
return converter(context, args);
|
return converter(context, args);
|
||||||
} else {
|
} else {
|
||||||
// Determine if the function is one we can simplify.
|
// Determine if the function is one we can simplify.
|
||||||
const targetFunction = resolveReferenceValue(staticSymbol);
|
const targetFunction = resolveReferenceValue(staticSymbol);
|
||||||
return simplifyCall(
|
return simplifyCall(staticSymbol, targetFunction, argExpressions);
|
||||||
staticSymbol, targetFunction, argExpressions, expression['expression']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return IGNORE;
|
return IGNORE;
|
||||||
case 'error':
|
case 'error':
|
||||||
let message = expression.message;
|
let message = produceErrorMessage(expression);
|
||||||
if (expression['line'] != null) {
|
if (expression['line']) {
|
||||||
self.error(
|
message =
|
||||||
{
|
`${message} (position ${expression['line']+1}:${expression['character']+1} in the original .ts file)`;
|
||||||
message,
|
self.reportError(
|
||||||
context: expression.context,
|
positionalError(
|
||||||
value: expression,
|
message, context.filePath, expression['line'], expression['character']),
|
||||||
position: {
|
|
||||||
fileName: expression['fileName'],
|
|
||||||
line: expression['line'],
|
|
||||||
column: expression['character']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
context);
|
context);
|
||||||
} else {
|
} else {
|
||||||
self.error({message, context: expression.context}, context);
|
self.reportError(new Error(message), context);
|
||||||
}
|
}
|
||||||
return IGNORE;
|
return IGNORE;
|
||||||
case 'ignore':
|
case 'ignore':
|
||||||
@ -703,7 +620,7 @@ export class StaticReflector implements CompileReflector {
|
|||||||
return simplify(value);
|
return simplify(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return simplifyLazily(value);
|
return simplifyInContext(context, value, depth, references + 1);
|
||||||
}
|
}
|
||||||
return simplify(value);
|
return simplify(value);
|
||||||
});
|
});
|
||||||
@ -711,19 +628,29 @@ export class StaticReflector implements CompileReflector {
|
|||||||
return IGNORE;
|
return IGNORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
return simplify(value);
|
return simplify(value);
|
||||||
|
} catch (e) {
|
||||||
|
const members = context.members.length ? `.${context.members.join('.')}` : '';
|
||||||
|
const message =
|
||||||
|
`${e.message}, resolving symbol ${context.name}${members} in ${context.filePath}`;
|
||||||
|
if (e.fileName) {
|
||||||
|
throw positionalError(message, e.fileName, e.line, e.column);
|
||||||
|
}
|
||||||
|
throw syntaxError(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let result: any;
|
const recordedSimplifyInContext = (context: StaticSymbol, value: any) => {
|
||||||
try {
|
try {
|
||||||
result = simplifyInContext(context, value, 0, 0);
|
return simplifyInContext(context, value, 0, 0);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (this.errorRecorder) {
|
|
||||||
this.reportError(e, context);
|
this.reportError(e, context);
|
||||||
} else {
|
|
||||||
throw formatMetadataError(e, context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = this.errorRecorder ? recordedSimplifyInContext(context, value) :
|
||||||
|
simplifyInContext(context, value, 0, 0);
|
||||||
if (shouldIgnore(result)) {
|
if (shouldIgnore(result)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -735,166 +662,40 @@ export class StaticReflector implements CompileReflector {
|
|||||||
return resolvedSymbol && resolvedSymbol.metadata ? resolvedSymbol.metadata :
|
return resolvedSymbol && resolvedSymbol.metadata ? resolvedSymbol.metadata :
|
||||||
{__symbolic: 'class'};
|
{__symbolic: 'class'};
|
||||||
}
|
}
|
||||||
|
|
||||||
private reportError(error: Error, context: StaticSymbol, path?: string) {
|
|
||||||
if (this.errorRecorder) {
|
|
||||||
this.errorRecorder(
|
|
||||||
formatMetadataError(error, context), (context && context.filePath) || path);
|
|
||||||
} else {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private error(
|
function expandedMessage(error: any): string {
|
||||||
{message, summary, advise, position, context, value, symbol, chain}: {
|
|
||||||
message: string,
|
|
||||||
summary?: string,
|
|
||||||
advise?: string,
|
|
||||||
position?: Position,
|
|
||||||
context?: any,
|
|
||||||
value?: any,
|
|
||||||
symbol?: StaticSymbol,
|
|
||||||
chain?: MetadataMessageChain
|
|
||||||
},
|
|
||||||
reportingContext: StaticSymbol) {
|
|
||||||
this.reportError(
|
|
||||||
metadataError(message, summary, advise, position, symbol, context, chain),
|
|
||||||
reportingContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Position {
|
|
||||||
fileName: string;
|
|
||||||
line: number;
|
|
||||||
column: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MetadataMessageChain {
|
|
||||||
message: string;
|
|
||||||
summary?: string;
|
|
||||||
position?: Position;
|
|
||||||
context?: any;
|
|
||||||
symbol?: StaticSymbol;
|
|
||||||
next?: MetadataMessageChain;
|
|
||||||
}
|
|
||||||
|
|
||||||
type MetadataError = Error & {
|
|
||||||
position?: Position;
|
|
||||||
advise?: string;
|
|
||||||
summary?: string;
|
|
||||||
context?: any;
|
|
||||||
symbol?: StaticSymbol;
|
|
||||||
chain?: MetadataMessageChain;
|
|
||||||
};
|
|
||||||
|
|
||||||
const METADATA_ERROR = 'ngMetadataError';
|
|
||||||
|
|
||||||
function metadataError(
|
|
||||||
message: string, summary?: string, advise?: string, position?: Position, symbol?: StaticSymbol,
|
|
||||||
context?: any, chain?: MetadataMessageChain): MetadataError {
|
|
||||||
const error = syntaxError(message) as MetadataError;
|
|
||||||
(error as any)[METADATA_ERROR] = true;
|
|
||||||
if (advise) error.advise = advise;
|
|
||||||
if (position) error.position = position;
|
|
||||||
if (summary) error.summary = summary;
|
|
||||||
if (context) error.context = context;
|
|
||||||
if (chain) error.chain = chain;
|
|
||||||
if (symbol) error.symbol = symbol;
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isMetadataError(error: Error): error is MetadataError {
|
|
||||||
return !!(error as any)[METADATA_ERROR];
|
|
||||||
}
|
|
||||||
|
|
||||||
const REFERENCE_TO_NONEXPORTED_CLASS = 'Reference to non-exported class';
|
|
||||||
const VARIABLE_NOT_INITIALIZED = 'Variable not initialized';
|
|
||||||
const DESTRUCTURE_NOT_SUPPORTED = 'Destructuring not supported';
|
|
||||||
const COULD_NOT_RESOLVE_TYPE = 'Could not resolve type';
|
|
||||||
const FUNCTION_CALL_NOT_SUPPORTED = 'Function call not supported';
|
|
||||||
const REFERENCE_TO_LOCAL_SYMBOL = 'Reference to a local symbol';
|
|
||||||
const LAMBDA_NOT_SUPPORTED = 'Lambda not supported';
|
|
||||||
|
|
||||||
function expandedMessage(message: string, context: any): string {
|
|
||||||
switch (message) {
|
|
||||||
case REFERENCE_TO_NONEXPORTED_CLASS:
|
|
||||||
if (context && context.className) {
|
|
||||||
return `References to a non-exported class are not supported in decorators but ${context.className} was referenced.`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VARIABLE_NOT_INITIALIZED:
|
|
||||||
return 'Only initialized variables and constants can be referenced in decorators because the value of this variable is needed by the template compiler';
|
|
||||||
case DESTRUCTURE_NOT_SUPPORTED:
|
|
||||||
return 'Referencing an exported destructured variable or constant is not supported in decorators and this value is needed by the template compiler';
|
|
||||||
case COULD_NOT_RESOLVE_TYPE:
|
|
||||||
if (context && context.typeName) {
|
|
||||||
return `Could not resolve type ${context.typeName}`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FUNCTION_CALL_NOT_SUPPORTED:
|
|
||||||
if (context && context.name) {
|
|
||||||
return `Function calls are not supported in decorators but '${context.name}' was called`;
|
|
||||||
}
|
|
||||||
return 'Function calls are not supported in decorators';
|
|
||||||
case REFERENCE_TO_LOCAL_SYMBOL:
|
|
||||||
if (context && context.name) {
|
|
||||||
return `Reference to a local (non-exported) symbols are not supported in decorators but '${context.name}' was referenced`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LAMBDA_NOT_SUPPORTED:
|
|
||||||
return `Function expressions are not supported in decorators`;
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
function messageAdvise(message: string, context: any): string|undefined {
|
|
||||||
switch (message) {
|
|
||||||
case REFERENCE_TO_NONEXPORTED_CLASS:
|
|
||||||
if (context && context.className) {
|
|
||||||
return `Consider exporting '${context.className}'`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DESTRUCTURE_NOT_SUPPORTED:
|
|
||||||
return 'Consider simplifying to avoid destructuring';
|
|
||||||
case REFERENCE_TO_LOCAL_SYMBOL:
|
|
||||||
if (context && context.name) {
|
|
||||||
return `Consider exporting '${context.name}'`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LAMBDA_NOT_SUPPORTED:
|
|
||||||
return `Consider changing the function expression into an exported function`;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
function errorSummary(error: MetadataError): string {
|
|
||||||
if (error.summary) {
|
|
||||||
return error.summary;
|
|
||||||
}
|
|
||||||
switch (error.message) {
|
switch (error.message) {
|
||||||
case REFERENCE_TO_NONEXPORTED_CLASS:
|
case 'Reference to non-exported class':
|
||||||
if (error.context && error.context.className) {
|
if (error.context && error.context.className) {
|
||||||
return `references non-exported class ${error.context.className}`;
|
return `Reference to a non-exported class ${error.context.className}. Consider exporting the class`;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VARIABLE_NOT_INITIALIZED:
|
case 'Variable not initialized':
|
||||||
return 'is not initialized';
|
return 'Only initialized variables and constants can be referenced because the value of this variable is needed by the template compiler';
|
||||||
case DESTRUCTURE_NOT_SUPPORTED:
|
case 'Destructuring not supported':
|
||||||
return 'is a destructured variable';
|
return 'Referencing an exported destructured variable or constant is not supported by the template compiler. Consider simplifying this to avoid destructuring';
|
||||||
case COULD_NOT_RESOLVE_TYPE:
|
case 'Could not resolve type':
|
||||||
return 'could not be resolved';
|
if (error.context && error.context.typeName) {
|
||||||
case FUNCTION_CALL_NOT_SUPPORTED:
|
return `Could not resolve type ${error.context.typeName}`;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'Function call not supported':
|
||||||
|
let prefix =
|
||||||
|
error.context && error.context.name ? `Calling function '${error.context.name}', f` : 'F';
|
||||||
|
return prefix +
|
||||||
|
'unction calls are not supported. Consider replacing the function or lambda with a reference to an exported function';
|
||||||
|
case 'Reference to a local symbol':
|
||||||
if (error.context && error.context.name) {
|
if (error.context && error.context.name) {
|
||||||
return `calls '${error.context.name}'`;
|
return `Reference to a local (non-exported) symbol '${error.context.name}'. Consider exporting the symbol`;
|
||||||
}
|
}
|
||||||
return `calls a function`;
|
break;
|
||||||
case REFERENCE_TO_LOCAL_SYMBOL:
|
|
||||||
if (error.context && error.context.name) {
|
|
||||||
return `references local variable ${error.context.name}`;
|
|
||||||
}
|
}
|
||||||
return `references a local variable`;
|
return error.message;
|
||||||
}
|
}
|
||||||
return 'contains the error';
|
|
||||||
|
function produceErrorMessage(error: any): string {
|
||||||
|
return `Error encountered resolving symbol values statically. ${expandedMessage(error)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStringMap(input: {[key: string]: any}, transform: (value: any, key: string) => any):
|
function mapStringMap(input: {[key: string]: any}, transform: (value: any, key: string) => any):
|
||||||
@ -950,30 +751,10 @@ class PopulatedScope extends BindingScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatMetadataMessageChain(
|
function positionalError(message: string, fileName: string, line: number, column: number): Error {
|
||||||
chain: MetadataMessageChain, advise: string | undefined): FormattedMessageChain {
|
const result = syntaxError(message);
|
||||||
const expanded = expandedMessage(chain.message, chain.context);
|
(result as any).fileName = fileName;
|
||||||
const nesting = chain.symbol ? ` in '${chain.symbol.name}'` : '';
|
(result as any).line = line;
|
||||||
const message = `${expanded}${nesting}`;
|
(result as any).column = column;
|
||||||
const position = chain.position;
|
return result;
|
||||||
const next: FormattedMessageChain|undefined = chain.next ?
|
|
||||||
formatMetadataMessageChain(chain.next, advise) :
|
|
||||||
advise ? {message: advise} : undefined;
|
|
||||||
return {message, position, next};
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatMetadataError(e: Error, context: StaticSymbol): Error {
|
|
||||||
if (isMetadataError(e)) {
|
|
||||||
// Produce a formatted version of the and leaving enough information in the original error
|
|
||||||
// to recover the formatting information to eventually produce a diagnostic error message.
|
|
||||||
const position = e.position;
|
|
||||||
const chain: MetadataMessageChain = {
|
|
||||||
message: `Error during template compile of '${context.name}'`,
|
|
||||||
position: position,
|
|
||||||
next: {message: e.message, next: e.chain, context: e.context, symbol: e.symbol}
|
|
||||||
};
|
|
||||||
const advise = e.advise || messageAdvise(e.message, e.context);
|
|
||||||
return formattedError(formatMetadataMessageChain(chain, advise));
|
|
||||||
}
|
|
||||||
return e;
|
|
||||||
}
|
}
|
@ -146,9 +146,9 @@ export class StaticSymbolResolver {
|
|||||||
if (isGeneratedFile(staticSymbol.filePath)) {
|
if (isGeneratedFile(staticSymbol.filePath)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let resolvedSymbol = unwrapResolvedMetadata(this.resolveSymbol(staticSymbol));
|
let resolvedSymbol = this.resolveSymbol(staticSymbol);
|
||||||
while (resolvedSymbol && resolvedSymbol.metadata instanceof StaticSymbol) {
|
while (resolvedSymbol && resolvedSymbol.metadata instanceof StaticSymbol) {
|
||||||
resolvedSymbol = unwrapResolvedMetadata(this.resolveSymbol(resolvedSymbol.metadata));
|
resolvedSymbol = this.resolveSymbol(resolvedSymbol.metadata);
|
||||||
}
|
}
|
||||||
return (resolvedSymbol && resolvedSymbol.metadata && resolvedSymbol.metadata.arity) || null;
|
return (resolvedSymbol && resolvedSymbol.metadata && resolvedSymbol.metadata.arity) || null;
|
||||||
}
|
}
|
||||||
@ -204,7 +204,7 @@ export class StaticSymbolResolver {
|
|||||||
if (!baseResolvedSymbol) {
|
if (!baseResolvedSymbol) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let baseMetadata = unwrapResolvedMetadata(baseResolvedSymbol.metadata);
|
const baseMetadata = baseResolvedSymbol.metadata;
|
||||||
if (baseMetadata instanceof StaticSymbol) {
|
if (baseMetadata instanceof StaticSymbol) {
|
||||||
return new ResolvedStaticSymbol(
|
return new ResolvedStaticSymbol(
|
||||||
staticSymbol, this.getStaticSymbol(baseMetadata.filePath, baseMetadata.name, members));
|
staticSymbol, this.getStaticSymbol(baseMetadata.filePath, baseMetadata.name, members));
|
||||||
@ -374,19 +374,6 @@ export class StaticSymbolResolver {
|
|||||||
return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
|
return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
let _originalFileMemo: string|undefined;
|
|
||||||
const getOriginalName: () => string = () => {
|
|
||||||
if (!_originalFileMemo) {
|
|
||||||
// Guess what hte original file name is from the reference. If it has a `.d.ts` extension
|
|
||||||
// replace it with `.ts`. If it already has `.ts` just leave it in place. If it doesn't have
|
|
||||||
// .ts or .d.ts, append `.ts'. Also, if it is in `node_modules`, trim the `node_module`
|
|
||||||
// location as it is not important to finding the file.
|
|
||||||
_originalFileMemo =
|
|
||||||
topLevelPath.replace(/((\.ts)|(\.d\.ts)|)$/, '.ts').replace(/^.*node_modules[/\\]/, '');
|
|
||||||
}
|
|
||||||
return _originalFileMemo;
|
|
||||||
};
|
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
class ReferenceTransformer extends ValueTransformer {
|
class ReferenceTransformer extends ValueTransformer {
|
||||||
@ -410,19 +397,10 @@ export class StaticSymbolResolver {
|
|||||||
if (!filePath) {
|
if (!filePath) {
|
||||||
return {
|
return {
|
||||||
__symbolic: 'error',
|
__symbolic: 'error',
|
||||||
message: `Could not resolve ${module} relative to ${sourceSymbol.filePath}.`,
|
message: `Could not resolve ${module} relative to ${sourceSymbol.filePath}.`
|
||||||
line: map.line,
|
|
||||||
character: map.character,
|
|
||||||
fileName: getOriginalName()
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return self.getStaticSymbol(filePath, name);
|
||||||
__symbolic: 'resolved',
|
|
||||||
symbol: self.getStaticSymbol(filePath, name),
|
|
||||||
line: map.line,
|
|
||||||
character: map.character,
|
|
||||||
fileName: getOriginalName()
|
|
||||||
};
|
|
||||||
} else if (functionParams.indexOf(name) >= 0) {
|
} else if (functionParams.indexOf(name) >= 0) {
|
||||||
// reference to a function parameter
|
// reference to a function parameter
|
||||||
return {__symbolic: 'reference', name: name};
|
return {__symbolic: 'reference', name: name};
|
||||||
@ -433,17 +411,14 @@ export class StaticSymbolResolver {
|
|||||||
// ambient value
|
// ambient value
|
||||||
null;
|
null;
|
||||||
}
|
}
|
||||||
} else if (symbolic === 'error') {
|
|
||||||
return {...map, fileName: getOriginalName()};
|
|
||||||
} else {
|
} else {
|
||||||
return super.visitStringMap(map, functionParams);
|
return super.visitStringMap(map, functionParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const transformedMeta = visitValue(metadata, new ReferenceTransformer(), []);
|
const transformedMeta = visitValue(metadata, new ReferenceTransformer(), []);
|
||||||
let unwrappedTransformedMeta = unwrapResolvedMetadata(transformedMeta);
|
if (transformedMeta instanceof StaticSymbol) {
|
||||||
if (unwrappedTransformedMeta instanceof StaticSymbol) {
|
return this.createExport(sourceSymbol, transformedMeta);
|
||||||
return this.createExport(sourceSymbol, unwrappedTransformedMeta);
|
|
||||||
}
|
}
|
||||||
return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
|
return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
|
||||||
}
|
}
|
||||||
@ -530,10 +505,3 @@ export class StaticSymbolResolver {
|
|||||||
export function unescapeIdentifier(identifier: string): string {
|
export function unescapeIdentifier(identifier: string): string {
|
||||||
return identifier.startsWith('___') ? identifier.substr(1) : identifier;
|
return identifier.startsWith('___') ? identifier.substr(1) : identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function unwrapResolvedMetadata(metadata: any): any {
|
|
||||||
if (metadata && metadata.__symbolic === 'resolved') {
|
|
||||||
return metadata.symbol;
|
|
||||||
}
|
|
||||||
return metadata;
|
|
||||||
}
|
|
@ -11,7 +11,7 @@ import {Summary, SummaryResolver} from '../summary_resolver';
|
|||||||
import {OutputContext, ValueTransformer, ValueVisitor, visitValue} from '../util';
|
import {OutputContext, ValueTransformer, ValueVisitor, visitValue} from '../util';
|
||||||
|
|
||||||
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
||||||
import {ResolvedStaticSymbol, StaticSymbolResolver, unwrapResolvedMetadata} from './static_symbol_resolver';
|
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
|
||||||
import {isLoweredSymbol, ngfactoryFilePath, summaryForJitFileName, summaryForJitName} from './util';
|
import {isLoweredSymbol, ngfactoryFilePath, summaryForJitFileName, summaryForJitName} from './util';
|
||||||
|
|
||||||
export function serializeSummaries(
|
export function serializeSummaries(
|
||||||
@ -453,10 +453,10 @@ function isCall(metadata: any): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isFunctionCall(metadata: any): boolean {
|
function isFunctionCall(metadata: any): boolean {
|
||||||
return isCall(metadata) && unwrapResolvedMetadata(metadata.expression) instanceof StaticSymbol;
|
return isCall(metadata) && metadata.expression instanceof StaticSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMethodCallOnVariable(metadata: any): boolean {
|
function isMethodCallOnVariable(metadata: any): boolean {
|
||||||
return isCall(metadata) && metadata.expression && metadata.expression.__symbolic === 'select' &&
|
return isCall(metadata) && metadata.expression && metadata.expression.__symbolic === 'select' &&
|
||||||
unwrapResolvedMetadata(metadata.expression.expression) instanceof StaticSymbol;
|
metadata.expression.expression instanceof StaticSymbol;
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,6 @@ export * from './aot/compiler';
|
|||||||
export * from './aot/generated_file';
|
export * from './aot/generated_file';
|
||||||
export * from './aot/compiler_options';
|
export * from './aot/compiler_options';
|
||||||
export * from './aot/compiler_host';
|
export * from './aot/compiler_host';
|
||||||
export * from './aot/formatted_error';
|
|
||||||
export * from './aot/static_reflector';
|
export * from './aot/static_reflector';
|
||||||
export * from './aot/static_symbol';
|
export * from './aot/static_symbol';
|
||||||
export * from './aot/static_symbol_resolver';
|
export * from './aot/static_symbol_resolver';
|
||||||
|
@ -42,7 +42,6 @@ export class JitCompiler {
|
|||||||
private _compiledDirectiveWrapperCache = new Map<Type, Type>();
|
private _compiledDirectiveWrapperCache = new Map<Type, Type>();
|
||||||
private _compiledNgModuleCache = new Map<Type, object>();
|
private _compiledNgModuleCache = new Map<Type, object>();
|
||||||
private _sharedStylesheetCount = 0;
|
private _sharedStylesheetCount = 0;
|
||||||
private _addedAotSummaries = new Set<() => any[]>();
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _metadataResolver: CompileMetadataResolver, private _templateParser: TemplateParser,
|
private _metadataResolver: CompileMetadataResolver, private _templateParser: TemplateParser,
|
||||||
@ -75,25 +74,10 @@ export class JitCompiler {
|
|||||||
|
|
||||||
loadAotSummaries(summaries: () => any[]) {
|
loadAotSummaries(summaries: () => any[]) {
|
||||||
this.clearCache();
|
this.clearCache();
|
||||||
this._addAotSummaries(summaries);
|
flattenSummaries(summaries).forEach((summary) => {
|
||||||
}
|
|
||||||
|
|
||||||
private _addAotSummaries(fn: () => any[]) {
|
|
||||||
if (this._addedAotSummaries.has(fn)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._addedAotSummaries.add(fn);
|
|
||||||
const summaries = fn();
|
|
||||||
for (let i = 0; i < summaries.length; i++) {
|
|
||||||
const entry = summaries[i];
|
|
||||||
if (typeof entry === 'function') {
|
|
||||||
this._addAotSummaries(entry);
|
|
||||||
} else {
|
|
||||||
const summary = entry as CompileTypeSummary;
|
|
||||||
this._summaryResolver.addSummary(
|
this._summaryResolver.addSummary(
|
||||||
{symbol: summary.type.reference, metadata: null, type: summary});
|
{symbol: summary.type.reference, metadata: null, type: summary});
|
||||||
}
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hasAotSummary(ref: Type) { return !!this._summaryResolver.resolveSummary(ref); }
|
hasAotSummary(ref: Type) { return !!this._summaryResolver.resolveSummary(ref); }
|
||||||
@ -216,7 +200,6 @@ export class JitCompiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clearCache(): void {
|
clearCache(): void {
|
||||||
// Note: don't clear the _addedAotSummaries, as they don't change!
|
|
||||||
this._metadataResolver.clearCache();
|
this._metadataResolver.clearCache();
|
||||||
this._compiledTemplateCache.clear();
|
this._compiledTemplateCache.clear();
|
||||||
this._compiledHostTemplateCache.clear();
|
this._compiledHostTemplateCache.clear();
|
||||||
@ -352,6 +335,25 @@ function assertComponent(meta: CompileDirectiveMetadata) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function flattenSummaries(
|
||||||
|
fn: () => any[], out: CompileTypeSummary[] = [],
|
||||||
|
seen = new Set<() => any[]>()): CompileTypeSummary[] {
|
||||||
|
if (seen.has(fn)) {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
seen.add(fn);
|
||||||
|
const summaries = fn();
|
||||||
|
for (let i = 0; i < summaries.length; i++) {
|
||||||
|
const entry = summaries[i];
|
||||||
|
if (typeof entry === 'function') {
|
||||||
|
flattenSummaries(entry, out, seen);
|
||||||
|
} else {
|
||||||
|
out.push(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
function createOutputContext(): OutputContext {
|
function createOutputContext(): OutputContext {
|
||||||
const importExpr = (symbol: any) =>
|
const importExpr = (symbol: any) =>
|
||||||
ir.importExpr({name: identifierName(symbol), moduleName: null, runtime: symbol});
|
ir.importExpr({name: identifierName(symbol), moduleName: null, runtime: symbol});
|
||||||
|
@ -768,9 +768,9 @@ describe('compiler (unbundled Angular)', () => {
|
|||||||
childClassDecorator: '',
|
childClassDecorator: '',
|
||||||
childModuleDecorator: '@NgModule({providers: [Extends]})',
|
childModuleDecorator: '@NgModule({providers: [Extends]})',
|
||||||
}))
|
}))
|
||||||
.toThrowError(`Error during template compile of 'Extends'
|
.toThrowError(
|
||||||
Class Extends in /app/main.ts extends from a Injectable in another compilation unit without duplicating the decorator
|
'Class Extends in /app/main.ts extends from a Injectable in another compilation unit without duplicating the decorator. ' +
|
||||||
Please add a Injectable or Pipe or Directive or Component or NgModule decorator to the class.`);
|
'Please add a Injectable or Pipe or Directive or Component or NgModule decorator to the class.');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -792,9 +792,9 @@ describe('compiler (unbundled Angular)', () => {
|
|||||||
childClassDecorator: '',
|
childClassDecorator: '',
|
||||||
childModuleDecorator: '@NgModule({declarations: [Extends]})',
|
childModuleDecorator: '@NgModule({declarations: [Extends]})',
|
||||||
}))
|
}))
|
||||||
.toThrowError(`Error during template compile of 'Extends'
|
.toThrowError(
|
||||||
Class Extends in /app/main.ts extends from a Directive in another compilation unit without duplicating the decorator
|
'Class Extends in /app/main.ts extends from a Directive in another compilation unit without duplicating the decorator. ' +
|
||||||
Please add a Directive or Component decorator to the class.`);
|
'Please add a Directive or Component decorator to the class.');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -816,9 +816,9 @@ describe('compiler (unbundled Angular)', () => {
|
|||||||
childClassDecorator: '',
|
childClassDecorator: '',
|
||||||
childModuleDecorator: '@NgModule({declarations: [Extends]})',
|
childModuleDecorator: '@NgModule({declarations: [Extends]})',
|
||||||
}))
|
}))
|
||||||
.toThrowError(`Error during template compile of 'Extends'
|
.toThrowError(
|
||||||
Class Extends in /app/main.ts extends from a Directive in another compilation unit without duplicating the decorator
|
'Class Extends in /app/main.ts extends from a Directive in another compilation unit without duplicating the decorator. ' +
|
||||||
Please add a Directive or Component decorator to the class.`);
|
'Please add a Directive or Component decorator to the class.');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -840,9 +840,9 @@ describe('compiler (unbundled Angular)', () => {
|
|||||||
childClassDecorator: '',
|
childClassDecorator: '',
|
||||||
childModuleDecorator: '@NgModule({declarations: [Extends]})',
|
childModuleDecorator: '@NgModule({declarations: [Extends]})',
|
||||||
}))
|
}))
|
||||||
.toThrowError(`Error during template compile of 'Extends'
|
.toThrowError(
|
||||||
Class Extends in /app/main.ts extends from a Pipe in another compilation unit without duplicating the decorator
|
'Class Extends in /app/main.ts extends from a Pipe in another compilation unit without duplicating the decorator. ' +
|
||||||
Please add a Pipe decorator to the class.`);
|
'Please add a Pipe decorator to the class.');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -864,9 +864,9 @@ describe('compiler (unbundled Angular)', () => {
|
|||||||
childClassDecorator: '',
|
childClassDecorator: '',
|
||||||
childModuleDecorator: '',
|
childModuleDecorator: '',
|
||||||
}))
|
}))
|
||||||
.toThrowError(`Error during template compile of 'Extends'
|
.toThrowError(
|
||||||
Class Extends in /app/main.ts extends from a NgModule in another compilation unit without duplicating the decorator
|
'Class Extends in /app/main.ts extends from a NgModule in another compilation unit without duplicating the decorator. ' +
|
||||||
Please add a NgModule decorator to the class.`);
|
'Please add a NgModule decorator to the class.');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -107,11 +107,8 @@ describe('StaticReflector', () => {
|
|||||||
it('should provide context for errors reported by the collector', () => {
|
it('should provide context for errors reported by the collector', () => {
|
||||||
const SomeClass = reflector.findDeclaration('src/error-reporting', 'SomeClass');
|
const SomeClass = reflector.findDeclaration('src/error-reporting', 'SomeClass');
|
||||||
expect(() => reflector.annotations(SomeClass))
|
expect(() => reflector.annotations(SomeClass))
|
||||||
.toThrow(new Error(`Error during template compile of 'SomeClass'
|
.toThrow(new Error(
|
||||||
A reasonable error message in 'Link1'
|
'Error encountered resolving symbol values statically. A reasonable error message (position 13:34 in the original .ts file), resolving symbol ErrorSym in /tmp/src/error-references.d.ts, resolving symbol Link2 in /tmp/src/error-references.d.ts, resolving symbol Link1 in /tmp/src/error-references.d.ts, resolving symbol SomeClass in /tmp/src/error-reporting.d.ts, resolving symbol SomeClass in /tmp/src/error-reporting.d.ts'));
|
||||||
'Link1' references 'Link2'
|
|
||||||
'Link2' references 'ErrorSym'
|
|
||||||
'ErrorSym' contains the error at /tmp/src/error-references.ts(13,34).`));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should simplify primitive into itself', () => {
|
it('should simplify primitive into itself', () => {
|
||||||
@ -333,12 +330,10 @@ describe('StaticReflector', () => {
|
|||||||
it('should error on direct recursive calls', () => {
|
it('should error on direct recursive calls', () => {
|
||||||
expect(
|
expect(
|
||||||
() => simplify(
|
() => simplify(
|
||||||
reflector.getStaticSymbol('/tmp/src/function-reference.ts', 'MyComp'),
|
reflector.getStaticSymbol('/tmp/src/function-reference.ts', ''),
|
||||||
reflector.getStaticSymbol('/tmp/src/function-reference.ts', 'recursion')))
|
reflector.getStaticSymbol('/tmp/src/function-reference.ts', 'recursion')))
|
||||||
.toThrow(new Error(`Error during template compile of 'MyComp'
|
.toThrow(new Error(
|
||||||
Recursion is not supported in 'recursion'
|
'Recursion not supported, resolving symbol recursive in /tmp/src/function-recursive.d.ts, resolving symbol recursion in /tmp/src/function-reference.ts, resolving symbol in /tmp/src/function-reference.ts'));
|
||||||
'recursion' references 'recursive'
|
|
||||||
'recursive' called 'recursive' recursively.`));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw a SyntaxError without stack trace when the required resource cannot be resolved',
|
it('should throw a SyntaxError without stack trace when the required resource cannot be resolved',
|
||||||
@ -350,8 +345,8 @@ describe('StaticReflector', () => {
|
|||||||
message:
|
message:
|
||||||
'Could not resolve ./does-not-exist.component relative to /tmp/src/function-reference.ts'
|
'Could not resolve ./does-not-exist.component relative to /tmp/src/function-reference.ts'
|
||||||
})))
|
})))
|
||||||
.toThrowError(`Error during template compile of 'AppModule'
|
.toThrowError(
|
||||||
Could not resolve ./does-not-exist.component relative to /tmp/src/function-reference.ts.`);
|
'Error encountered resolving symbol values statically. Could not resolve ./does-not-exist.component relative to /tmp/src/function-reference.ts, resolving symbol AppModule in /tmp/src/function-reference.ts');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should record data about the error in the exception', () => {
|
it('should record data about the error in the exception', () => {
|
||||||
@ -366,7 +361,7 @@ describe('StaticReflector', () => {
|
|||||||
simplify(
|
simplify(
|
||||||
reflector.getStaticSymbol('/tmp/src/invalid-metadata.ts', ''), classData.decorators[0]);
|
reflector.getStaticSymbol('/tmp/src/invalid-metadata.ts', ''), classData.decorators[0]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.position).toBeDefined();
|
expect(e.fileName).toBe('/tmp/src/invalid-metadata.ts');
|
||||||
threw = true;
|
threw = true;
|
||||||
}
|
}
|
||||||
expect(threw).toBe(true);
|
expect(threw).toBe(true);
|
||||||
@ -375,13 +370,10 @@ describe('StaticReflector', () => {
|
|||||||
it('should error on indirect recursive calls', () => {
|
it('should error on indirect recursive calls', () => {
|
||||||
expect(
|
expect(
|
||||||
() => simplify(
|
() => simplify(
|
||||||
reflector.getStaticSymbol('/tmp/src/function-reference.ts', 'MyComp'),
|
reflector.getStaticSymbol('/tmp/src/function-reference.ts', ''),
|
||||||
reflector.getStaticSymbol('/tmp/src/function-reference.ts', 'indirectRecursion')))
|
reflector.getStaticSymbol('/tmp/src/function-reference.ts', 'indirectRecursion')))
|
||||||
.toThrow(new Error(`Error during template compile of 'MyComp'
|
.toThrow(new Error(
|
||||||
Recursion is not supported in 'indirectRecursion'
|
'Recursion not supported, resolving symbol indirectRecursion2 in /tmp/src/function-recursive.d.ts, resolving symbol indirectRecursion1 in /tmp/src/function-recursive.d.ts, resolving symbol indirectRecursion in /tmp/src/function-reference.ts, resolving symbol in /tmp/src/function-reference.ts'));
|
||||||
'indirectRecursion' references 'indirectRecursion1'
|
|
||||||
'indirectRecursion1' references 'indirectRecursion2'
|
|
||||||
'indirectRecursion2' called 'indirectRecursion1' recursively.`));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should simplify a spread expression', () => {
|
it('should simplify a spread expression', () => {
|
||||||
@ -409,8 +401,7 @@ describe('StaticReflector', () => {
|
|||||||
() => reflector.annotations(
|
() => reflector.annotations(
|
||||||
reflector.getStaticSymbol('/tmp/src/invalid-calls.ts', 'MyComponent')))
|
reflector.getStaticSymbol('/tmp/src/invalid-calls.ts', 'MyComponent')))
|
||||||
.toThrow(new Error(
|
.toThrow(new Error(
|
||||||
`/tmp/src/invalid-calls.ts(8,29): Error during template compile of 'MyComponent'
|
`Error encountered resolving symbol values statically. Calling function 'someFunction', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol MyComponent in /tmp/src/invalid-calls.ts, resolving symbol MyComponent in /tmp/src/invalid-calls.ts`));
|
||||||
Function calls are not supported in decorators but 'someFunction' was called.`));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to get metadata for a class containing a static method call', () => {
|
it('should be able to get metadata for a class containing a static method call', () => {
|
||||||
@ -971,7 +962,7 @@ describe('StaticReflector', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Regression #18170
|
// Regression #18170
|
||||||
it('should eagerly evaluate enums selects', () => {
|
it('should agressively evaluate enums selects', () => {
|
||||||
const data = Object.create(DEFAULT_TEST_DATA);
|
const data = Object.create(DEFAULT_TEST_DATA);
|
||||||
const file = '/tmp/src/my_component.ts';
|
const file = '/tmp/src/my_component.ts';
|
||||||
data[file] = `
|
data[file] = `
|
||||||
@ -1087,228 +1078,6 @@ describe('StaticReflector', () => {
|
|||||||
expect(symbolResolver.getKnownModuleName(symbol.filePath)).toBe('a');
|
expect(symbolResolver.getKnownModuleName(symbol.filePath)).toBe('a');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('formatted error reporting', () => {
|
|
||||||
describe('function calls', () => {
|
|
||||||
const fileName = '/tmp/src/invalid/components.ts';
|
|
||||||
beforeEach(() => {
|
|
||||||
const localData = {
|
|
||||||
'/tmp/src/invalid/function-call.ts': `
|
|
||||||
import {functionToCall} from 'some-module';
|
|
||||||
export const CALL_FUNCTION = functionToCall();
|
|
||||||
`,
|
|
||||||
'/tmp/src/invalid/indirect.ts': `
|
|
||||||
import {CALL_FUNCTION} from './function-call';
|
|
||||||
|
|
||||||
export const INDIRECT_CALL_FUNCTION = CALL_FUNCTION + 1;
|
|
||||||
`,
|
|
||||||
'/tmp/src/invalid/two-levels-indirect.ts': `
|
|
||||||
import {INDIRECT_CALL_FUNCTION} from './indirect';
|
|
||||||
|
|
||||||
export const TWO_LEVELS_INDIRECT_CALL_FUNCTION = INDIRECT_CALL_FUNCTION + 1;
|
|
||||||
`,
|
|
||||||
'/tmp/src/invalid/components.ts': `
|
|
||||||
import {functionToCall} from 'some-module';
|
|
||||||
import {Component} from '@angular/core';
|
|
||||||
import {CALL_FUNCTION} from './function-call';
|
|
||||||
import {INDIRECT_CALL_FUNCTION} from './indirect';
|
|
||||||
import {TWO_LEVELS_INDIRECT_CALL_FUNCTION} from './two-levels-indirect';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
value: functionToCall()
|
|
||||||
})
|
|
||||||
export class CallImportedFunction {}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
value: CALL_FUNCTION
|
|
||||||
})
|
|
||||||
export class ReferenceCalledFunction {}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
value: INDIRECT_CALL_FUNCTION
|
|
||||||
})
|
|
||||||
export class IndirectReferenceCalledFunction {}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
value: TWO_LEVELS_INDIRECT_CALL_FUNCTION
|
|
||||||
})
|
|
||||||
export class TwoLevelsIndirectReferenceCalledFunction {}
|
|
||||||
`
|
|
||||||
};
|
|
||||||
init({...DEFAULT_TEST_DATA, ...localData});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should report a formatted error for a direct function call', () => {
|
|
||||||
expect(() => {
|
|
||||||
return reflector.annotations(reflector.getStaticSymbol(fileName, 'CallImportedFunction'));
|
|
||||||
})
|
|
||||||
.toThrowError(
|
|
||||||
`/tmp/src/invalid/components.ts(9,18): Error during template compile of 'CallImportedFunction'
|
|
||||||
Function calls are not supported in decorators but 'functionToCall' was called.`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should report a formatted error for a refernce to a function call', () => {
|
|
||||||
expect(() => {
|
|
||||||
return reflector.annotations(
|
|
||||||
reflector.getStaticSymbol(fileName, 'ReferenceCalledFunction'));
|
|
||||||
})
|
|
||||||
.toThrowError(
|
|
||||||
`/tmp/src/invalid/components.ts(14,18): Error during template compile of 'ReferenceCalledFunction'
|
|
||||||
Function calls are not supported in decorators but 'functionToCall' was called in 'CALL_FUNCTION'
|
|
||||||
'CALL_FUNCTION' calls 'functionToCall' at /tmp/src/invalid/function-call.ts(3,38).`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should report a formatted error for an indirect reference to a function call', () => {
|
|
||||||
expect(() => {
|
|
||||||
return reflector.annotations(
|
|
||||||
reflector.getStaticSymbol(fileName, 'IndirectReferenceCalledFunction'));
|
|
||||||
})
|
|
||||||
.toThrowError(
|
|
||||||
`/tmp/src/invalid/components.ts(19,18): Error during template compile of 'IndirectReferenceCalledFunction'
|
|
||||||
Function calls are not supported in decorators but 'functionToCall' was called in 'INDIRECT_CALL_FUNCTION'
|
|
||||||
'INDIRECT_CALL_FUNCTION' references 'CALL_FUNCTION' at /tmp/src/invalid/indirect.ts(4,47)
|
|
||||||
'CALL_FUNCTION' calls 'functionToCall' at /tmp/src/invalid/function-call.ts(3,38).`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should report a formatted error for a double-indirect refernce to a function call', () => {
|
|
||||||
expect(() => {
|
|
||||||
return reflector.annotations(
|
|
||||||
reflector.getStaticSymbol(fileName, 'TwoLevelsIndirectReferenceCalledFunction'));
|
|
||||||
})
|
|
||||||
.toThrowError(
|
|
||||||
`/tmp/src/invalid/components.ts(24,18): Error during template compile of 'TwoLevelsIndirectReferenceCalledFunction'
|
|
||||||
Function calls are not supported in decorators but 'functionToCall' was called in 'TWO_LEVELS_INDIRECT_CALL_FUNCTION'
|
|
||||||
'TWO_LEVELS_INDIRECT_CALL_FUNCTION' references 'INDIRECT_CALL_FUNCTION' at /tmp/src/invalid/two-levels-indirect.ts(4,58)
|
|
||||||
'INDIRECT_CALL_FUNCTION' references 'CALL_FUNCTION' at /tmp/src/invalid/indirect.ts(4,47)
|
|
||||||
'CALL_FUNCTION' calls 'functionToCall' at /tmp/src/invalid/function-call.ts(3,38).`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('macro functions', () => {
|
|
||||||
const fileName = '/tmp/src/invalid/components.ts';
|
|
||||||
beforeEach(() => {
|
|
||||||
const localData = {
|
|
||||||
'/tmp/src/invalid/function-call.ts': `
|
|
||||||
import {functionToCall} from 'some-module';
|
|
||||||
export const CALL_FUNCTION = functionToCall();
|
|
||||||
`,
|
|
||||||
'/tmp/src/invalid/indirect.ts': `
|
|
||||||
import {CALL_FUNCTION} from './function-call';
|
|
||||||
|
|
||||||
export const INDIRECT_CALL_FUNCTION = CALL_FUNCTION + 1;
|
|
||||||
`,
|
|
||||||
'/tmp/src/invalid/macros.ts': `
|
|
||||||
export function someMacro(value: any) {
|
|
||||||
return [ { provide: 'key', value: value } ];
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
'/tmp/src/invalid/components.ts': `
|
|
||||||
import {Component} from '@angular/core';
|
|
||||||
import {functionToCall} from 'some-module';
|
|
||||||
import {someMacro} from './macros';
|
|
||||||
import {CALL_FUNCTION} from './function-call';
|
|
||||||
import {INDIRECT_CALL_FUNCTION} from './indirect';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
template: someMacro(functionToCall())
|
|
||||||
})
|
|
||||||
export class DirectCall {}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
template: someMacro(CALL_FUNCTION)
|
|
||||||
})
|
|
||||||
export class IndirectCall {}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
template: someMacro(INDIRECT_CALL_FUNCTION)
|
|
||||||
})
|
|
||||||
export class DoubleIndirectCall {}
|
|
||||||
`
|
|
||||||
};
|
|
||||||
init({...DEFAULT_TEST_DATA, ...localData});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should report a formatted error for a direct function call', () => {
|
|
||||||
expect(() => {
|
|
||||||
return reflector.annotations(reflector.getStaticSymbol(fileName, 'DirectCall'));
|
|
||||||
})
|
|
||||||
.toThrowError(
|
|
||||||
`/tmp/src/invalid/components.ts(9,31): Error during template compile of 'DirectCall'
|
|
||||||
Function calls are not supported in decorators but 'functionToCall' was called.`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should report a formatted error for a reference to a function call', () => {
|
|
||||||
expect(() => {
|
|
||||||
return reflector.annotations(reflector.getStaticSymbol(fileName, 'IndirectCall'));
|
|
||||||
})
|
|
||||||
.toThrowError(
|
|
||||||
`/tmp/src/invalid/components.ts(14,31): Error during template compile of 'IndirectCall'
|
|
||||||
Function calls are not supported in decorators but 'functionToCall' was called in 'CALL_FUNCTION'
|
|
||||||
'CALL_FUNCTION' calls 'functionToCall' at /tmp/src/invalid/function-call.ts(3,38).`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should report a formatted error for an indirect refernece to a function call', () => {
|
|
||||||
expect(() => {
|
|
||||||
return reflector.annotations(reflector.getStaticSymbol(fileName, 'DoubleIndirectCall'));
|
|
||||||
})
|
|
||||||
.toThrowError(
|
|
||||||
`/tmp/src/invalid/components.ts(19,31): Error during template compile of 'DoubleIndirectCall'
|
|
||||||
Function calls are not supported in decorators but 'functionToCall' was called in 'INDIRECT_CALL_FUNCTION'
|
|
||||||
'INDIRECT_CALL_FUNCTION' references 'CALL_FUNCTION' at /tmp/src/invalid/indirect.ts(4,47)
|
|
||||||
'CALL_FUNCTION' calls 'functionToCall' at /tmp/src/invalid/function-call.ts(3,38).`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('and give advice', () => {
|
|
||||||
// If in a reference expression, advice the user to replace with a reference.
|
|
||||||
const fileName = '/tmp/src/invalid/components.ts';
|
|
||||||
|
|
||||||
function collectError(symbol: string): string {
|
|
||||||
try {
|
|
||||||
reflector.annotations(reflector.getStaticSymbol(fileName, symbol));
|
|
||||||
} catch (e) {
|
|
||||||
return e.message;
|
|
||||||
}
|
|
||||||
fail('Expected an exception to be thrown');
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function initWith(content: string) {
|
|
||||||
init({
|
|
||||||
...DEFAULT_TEST_DATA,
|
|
||||||
[fileName]: `import {Component} from '@angular/core';\n${content}`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should advise exorting a local', () => {
|
|
||||||
initWith(`const f: string; @Component({value: f}) export class MyComp {}`);
|
|
||||||
expect(collectError('MyComp')).toContain(`Consider exporting 'f'`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should advise export a class', () => {
|
|
||||||
initWith('class Foo {} @Component({value: Foo}) export class MyComp {}');
|
|
||||||
expect(collectError('MyComp')).toContain(`Consider exporting 'Foo'`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should advise avoiding destructuring', () => {
|
|
||||||
initWith(
|
|
||||||
'export const {foo, bar} = {foo: 1, bar: 2}; @Component({value: foo}) export class MyComp {}');
|
|
||||||
expect(collectError('MyComp')).toContain(`Consider simplifying to avoid destructuring`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should advise converting an arrow function into an exported function', () => {
|
|
||||||
initWith('@Component({value: () => true}) export class MyComp {}');
|
|
||||||
expect(collectError('MyComp'))
|
|
||||||
.toContain(`Consider changing the function expression into an exported function`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should advise converting a function expression into an exported function', () => {
|
|
||||||
initWith('@Component({value: function () { return true; }}) export class MyComp {}');
|
|
||||||
expect(collectError('MyComp'))
|
|
||||||
.toContain(`Consider changing the function expression into an exported function`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const DEFAULT_TEST_DATA: {[key: string]: any} = {
|
const DEFAULT_TEST_DATA: {[key: string]: any} = {
|
||||||
@ -1698,5 +1467,5 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
|
|||||||
export class Dep {
|
export class Dep {
|
||||||
@Input f: Forward;
|
@Input f: Forward;
|
||||||
}
|
}
|
||||||
`,
|
`
|
||||||
};
|
};
|
||||||
|
@ -234,25 +234,15 @@ describe('StaticSymbolResolver', () => {
|
|||||||
});
|
});
|
||||||
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'a')).metadata)
|
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'a')).metadata)
|
||||||
.toEqual(symbolCache.get('/test2.ts', 'b'));
|
.toEqual(symbolCache.get('/test2.ts', 'b'));
|
||||||
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'x')).metadata).toEqual([{
|
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'x')).metadata).toEqual([
|
||||||
__symbolic: 'resolved',
|
symbolCache.get('/test2.ts', 'y')
|
||||||
symbol: symbolCache.get('/test2.ts', 'y'),
|
]);
|
||||||
line: 3,
|
|
||||||
character: 24,
|
|
||||||
fileName: '/test.ts'
|
|
||||||
}]);
|
|
||||||
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'simpleFn')).metadata).toEqual({
|
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'simpleFn')).metadata).toEqual({
|
||||||
__symbolic: 'function',
|
__symbolic: 'function',
|
||||||
parameters: ['fnArg'],
|
parameters: ['fnArg'],
|
||||||
value: [
|
value: [
|
||||||
symbolCache.get('/test.ts', 'a'), {
|
symbolCache.get('/test.ts', 'a'), symbolCache.get('/test2.ts', 'y'),
|
||||||
__symbolic: 'resolved',
|
Object({__symbolic: 'reference', name: 'fnArg'})
|
||||||
symbol: symbolCache.get('/test2.ts', 'y'),
|
|
||||||
line: 6,
|
|
||||||
character: 21,
|
|
||||||
fileName: '/test.ts'
|
|
||||||
},
|
|
||||||
{__symbolic: 'reference', name: 'fnArg'}
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -430,41 +430,5 @@ export function main() {
|
|||||||
importAs: symbolCache.get('someFile.ngfactory.d.ts', 'lib_1')
|
importAs: symbolCache.get('someFile.ngfactory.d.ts', 'lib_1')
|
||||||
}]);
|
}]);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('with resolved symbols', () => {
|
|
||||||
it('should be able to serialize a call', () => {
|
|
||||||
init();
|
|
||||||
const serialized = serializeSummaries(
|
|
||||||
'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, [{
|
|
||||||
symbol: symbolCache.get('/tmp/test.ts', 'main'),
|
|
||||||
metadata: {
|
|
||||||
__symbolic: 'call',
|
|
||||||
expression:
|
|
||||||
{__symbolic: 'resolved', symbol: symbolCache.get('/tmp/test2.ts', 'ref')}
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
[]);
|
|
||||||
expect(serialized.json).not.toContain('error');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to serialize a call to a method', () => {
|
|
||||||
init();
|
|
||||||
const serialized = serializeSummaries(
|
|
||||||
'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, [{
|
|
||||||
symbol: symbolCache.get('/tmp/test.ts', 'main'),
|
|
||||||
metadata: {
|
|
||||||
__symbolic: 'call',
|
|
||||||
expression: {
|
|
||||||
__symbolic: 'select',
|
|
||||||
expression:
|
|
||||||
{__symbolic: 'resolved', symbol: symbolCache.get('/tmp/test2.ts', 'ref')},
|
|
||||||
name: 'foo'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
[]);
|
|
||||||
expect(serialized.json).not.toContain('error');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -20,5 +20,5 @@ export {DirectRenderer as ɵDirectRenderer, RenderDebugInfo as ɵRenderDebugInfo
|
|||||||
export {global as ɵglobal, looseIdentical as ɵlooseIdentical, stringify as ɵstringify} from './util';
|
export {global as ɵglobal, looseIdentical as ɵlooseIdentical, stringify as ɵstringify} from './util';
|
||||||
export {makeDecorator as ɵmakeDecorator} from './util/decorators';
|
export {makeDecorator as ɵmakeDecorator} from './util/decorators';
|
||||||
export {isObservable as ɵisObservable, isPromise as ɵisPromise} from './util/lang';
|
export {isObservable as ɵisObservable, isPromise as ɵisPromise} from './util/lang';
|
||||||
export {clearOverrides as ɵclearOverrides, overrideComponentView as ɵoverrideComponentView, overrideProvider as ɵoverrideProvider} from './view/index';
|
export {clearProviderOverrides as ɵclearProviderOverrides, overrideProvider as ɵoverrideProvider} from './view/index';
|
||||||
export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider';
|
export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider';
|
||||||
|
@ -7,12 +7,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Injector} from '../di/injector';
|
import {Injector} from '../di/injector';
|
||||||
import {ComponentFactory} from '../linker/component_factory';
|
|
||||||
import {NgModuleFactory, NgModuleRef} from '../linker/ng_module_factory';
|
import {NgModuleFactory, NgModuleRef} from '../linker/ng_module_factory';
|
||||||
import {Type} from '../type';
|
import {Type} from '../type';
|
||||||
|
|
||||||
import {initServicesIfNeeded} from './services';
|
import {initServicesIfNeeded} from './services';
|
||||||
import {NgModuleDefinitionFactory, ProviderOverride, Services, ViewDefinition} from './types';
|
import {NgModuleDefinitionFactory, ProviderOverride, Services} from './types';
|
||||||
import {resolveDefinition} from './util';
|
import {resolveDefinition} from './util';
|
||||||
|
|
||||||
export function overrideProvider(override: ProviderOverride) {
|
export function overrideProvider(override: ProviderOverride) {
|
||||||
@ -20,14 +19,9 @@ export function overrideProvider(override: ProviderOverride) {
|
|||||||
return Services.overrideProvider(override);
|
return Services.overrideProvider(override);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function overrideComponentView(comp: Type<any>, componentFactory: ComponentFactory<any>) {
|
export function clearProviderOverrides() {
|
||||||
initServicesIfNeeded();
|
initServicesIfNeeded();
|
||||||
return Services.overrideComponentView(comp, componentFactory);
|
return Services.clearProviderOverrides();
|
||||||
}
|
|
||||||
|
|
||||||
export function clearOverrides() {
|
|
||||||
initServicesIfNeeded();
|
|
||||||
return Services.clearOverrides();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attention: this function is called as top level function.
|
// Attention: this function is called as top level function.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export {anchorDef, elementDef} from './element';
|
export {anchorDef, elementDef} from './element';
|
||||||
export {clearOverrides, createNgModuleFactory, overrideComponentView, overrideProvider} from './entrypoint';
|
export {clearProviderOverrides, createNgModuleFactory, overrideProvider} from './entrypoint';
|
||||||
export {ngContentDef} from './ng_content';
|
export {ngContentDef} from './ng_content';
|
||||||
export {moduleDef, moduleProvideDef} from './ng_module';
|
export {moduleDef, moduleProvideDef} from './ng_module';
|
||||||
export {directiveDef, pipeDef, providerDef} from './provider';
|
export {directiveDef, pipeDef, providerDef} from './provider';
|
||||||
|
@ -14,7 +14,7 @@ import {ViewContainerRef} from '../linker/view_container_ref';
|
|||||||
import {Renderer as RendererV1, Renderer2} from '../render/api';
|
import {Renderer as RendererV1, Renderer2} from '../render/api';
|
||||||
|
|
||||||
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} from './types';
|
||||||
import {calcBindingFlags, checkBinding, dispatchEvent, isComponentView, splitDepsDsl, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
|
import {calcBindingFlags, checkBinding, dispatchEvent, isComponentView, splitDepsDsl, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
|
||||||
|
|
||||||
const RendererV1TokenKey = tokenKey(RendererV1);
|
const RendererV1TokenKey = tokenKey(RendererV1);
|
||||||
@ -198,8 +198,7 @@ export function checkAndUpdateDirectiveInline(
|
|||||||
if (changes) {
|
if (changes) {
|
||||||
directive.ngOnChanges(changes);
|
directive.ngOnChanges(changes);
|
||||||
}
|
}
|
||||||
if ((def.flags & NodeFlags.OnInit) &&
|
if ((view.state & ViewState.FirstCheck) && (def.flags & NodeFlags.OnInit)) {
|
||||||
shouldCallLifecycleInitHook(view, ViewState.InitState_CallingOnInit, def.nodeIndex)) {
|
|
||||||
directive.ngOnInit();
|
directive.ngOnInit();
|
||||||
}
|
}
|
||||||
if (def.flags & NodeFlags.DoCheck) {
|
if (def.flags & NodeFlags.DoCheck) {
|
||||||
@ -223,8 +222,7 @@ export function checkAndUpdateDirectiveDynamic(
|
|||||||
if (changes) {
|
if (changes) {
|
||||||
directive.ngOnChanges(changes);
|
directive.ngOnChanges(changes);
|
||||||
}
|
}
|
||||||
if ((def.flags & NodeFlags.OnInit) &&
|
if ((view.state & ViewState.FirstCheck) && (def.flags & NodeFlags.OnInit)) {
|
||||||
shouldCallLifecycleInitHook(view, ViewState.InitState_CallingOnInit, def.nodeIndex)) {
|
|
||||||
directive.ngOnInit();
|
directive.ngOnInit();
|
||||||
}
|
}
|
||||||
if (def.flags & NodeFlags.DoCheck) {
|
if (def.flags & NodeFlags.DoCheck) {
|
||||||
@ -449,61 +447,17 @@ function updateProp(
|
|||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function calls the ngAfterContentCheck, ngAfterContentInit,
|
|
||||||
// ngAfterViewCheck, and ngAfterViewInit lifecycle hooks (depending on the node
|
|
||||||
// flags in lifecycle). Unlike ngDoCheck, ngOnChanges and ngOnInit, which are
|
|
||||||
// called during a pre-order traversal of the view tree (that is calling the
|
|
||||||
// parent hooks before the child hooks) these events are sent in using a
|
|
||||||
// post-order traversal of the tree (children before parents). This changes the
|
|
||||||
// meaning of initIndex in the view state. For ngOnInit, initIndex tracks the
|
|
||||||
// expected nodeIndex which a ngOnInit should be called. When sending
|
|
||||||
// ngAfterContentInit and ngAfterViewInit it is the expected count of
|
|
||||||
// ngAfterContentInit or ngAfterViewInit methods that have been called. This
|
|
||||||
// ensure that dispite being called recursively or after picking up after an
|
|
||||||
// exception, the ngAfterContentInit or ngAfterViewInit will be called on the
|
|
||||||
// correct nodes. Consider for example, the following (where E is an element
|
|
||||||
// and D is a directive)
|
|
||||||
// Tree: pre-order index post-order index
|
|
||||||
// E1 0 6
|
|
||||||
// E2 1 1
|
|
||||||
// D3 2 0
|
|
||||||
// E4 3 5
|
|
||||||
// E5 4 4
|
|
||||||
// E6 5 2
|
|
||||||
// E7 6 3
|
|
||||||
// As can be seen, the post-order index has an unclear relationship to the
|
|
||||||
// pre-order index (postOrderIndex === preOrderIndex - parentCount +
|
|
||||||
// childCount). Since number of calls to ngAfterContentInit and ngAfterViewInit
|
|
||||||
// are stable (will be the same for the same view regardless of exceptions or
|
|
||||||
// recursion) we just need to count them which will roughly correspond to the
|
|
||||||
// post-order index (it skips elements and directives that do not have
|
|
||||||
// lifecycle hooks).
|
|
||||||
//
|
|
||||||
// For example, if an exception is raised in the E6.onAfterViewInit() the
|
|
||||||
// initIndex is left at 3 (by shouldCallLifecycleInitHook() which set it to
|
|
||||||
// initIndex + 1). When checkAndUpdateView() is called again D3, E2 and E6 will
|
|
||||||
// not have their ngAfterViewInit() called but, starting with E7, the rest of
|
|
||||||
// the view will begin getting ngAfterViewInit() called until a check and
|
|
||||||
// pass is complete.
|
|
||||||
//
|
|
||||||
// This algorthim also handles recursion. Consider if E4's ngAfterViewInit()
|
|
||||||
// indirectly calls E1's ChangeDetectorRef.detectChanges(). The expected
|
|
||||||
// initIndex is set to 6, the recusive checkAndUpdateView() starts walk again.
|
|
||||||
// D3, E2, E6, E7, E5 and E4 are skipped, ngAfterViewInit() is called on E1.
|
|
||||||
// When the recursion returns the initIndex will be 7 so E1 is skipped as it
|
|
||||||
// has already been called in the recursively called checkAnUpdateView().
|
|
||||||
export function callLifecycleHooksChildrenFirst(view: ViewData, lifecycles: NodeFlags) {
|
export function callLifecycleHooksChildrenFirst(view: ViewData, lifecycles: NodeFlags) {
|
||||||
if (!(view.def.nodeFlags & lifecycles)) {
|
if (!(view.def.nodeFlags & lifecycles)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const nodes = view.def.nodes;
|
const nodes = view.def.nodes;
|
||||||
let initIndex = 0;
|
|
||||||
for (let i = 0; i < nodes.length; i++) {
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
const nodeDef = nodes[i];
|
const nodeDef = nodes[i];
|
||||||
let parent = nodeDef.parent;
|
let parent = nodeDef.parent;
|
||||||
if (!parent && nodeDef.flags & lifecycles) {
|
if (!parent && nodeDef.flags & lifecycles) {
|
||||||
// matching root node (e.g. a pipe)
|
// matching root node (e.g. a pipe)
|
||||||
callProviderLifecycles(view, i, nodeDef.flags & lifecycles, initIndex++);
|
callProviderLifecycles(view, i, nodeDef.flags & lifecycles);
|
||||||
}
|
}
|
||||||
if ((nodeDef.childFlags & lifecycles) === 0) {
|
if ((nodeDef.childFlags & lifecycles) === 0) {
|
||||||
// no child matches one of the lifecycles
|
// no child matches one of the lifecycles
|
||||||
@ -513,28 +467,25 @@ export function callLifecycleHooksChildrenFirst(view: ViewData, lifecycles: Node
|
|||||||
i === parent.nodeIndex + parent.childCount) {
|
i === parent.nodeIndex + parent.childCount) {
|
||||||
// last child of an element
|
// last child of an element
|
||||||
if (parent.directChildFlags & lifecycles) {
|
if (parent.directChildFlags & lifecycles) {
|
||||||
initIndex = callElementProvidersLifecycles(view, parent, lifecycles, initIndex);
|
callElementProvidersLifecycles(view, parent, lifecycles);
|
||||||
}
|
}
|
||||||
parent = parent.parent;
|
parent = parent.parent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function callElementProvidersLifecycles(
|
function callElementProvidersLifecycles(view: ViewData, elDef: NodeDef, lifecycles: NodeFlags) {
|
||||||
view: ViewData, elDef: NodeDef, lifecycles: NodeFlags, initIndex: number): number {
|
|
||||||
for (let i = elDef.nodeIndex + 1; i <= elDef.nodeIndex + elDef.childCount; i++) {
|
for (let i = elDef.nodeIndex + 1; i <= elDef.nodeIndex + elDef.childCount; i++) {
|
||||||
const nodeDef = view.def.nodes[i];
|
const nodeDef = view.def.nodes[i];
|
||||||
if (nodeDef.flags & lifecycles) {
|
if (nodeDef.flags & lifecycles) {
|
||||||
callProviderLifecycles(view, i, nodeDef.flags & lifecycles, initIndex++);
|
callProviderLifecycles(view, i, nodeDef.flags & lifecycles);
|
||||||
}
|
}
|
||||||
// only visit direct children
|
// only visit direct children
|
||||||
i += nodeDef.childCount;
|
i += nodeDef.childCount;
|
||||||
}
|
}
|
||||||
return initIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function callProviderLifecycles(
|
function callProviderLifecycles(view: ViewData, index: number, lifecycles: NodeFlags) {
|
||||||
view: ViewData, index: number, lifecycles: NodeFlags, initIndex: number) {
|
|
||||||
const providerData = asProviderData(view, index);
|
const providerData = asProviderData(view, index);
|
||||||
if (!providerData) {
|
if (!providerData) {
|
||||||
return;
|
return;
|
||||||
@ -544,15 +495,13 @@ function callProviderLifecycles(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Services.setCurrentNode(view, index);
|
Services.setCurrentNode(view, index);
|
||||||
if (lifecycles & NodeFlags.AfterContentInit &&
|
if (lifecycles & NodeFlags.AfterContentInit) {
|
||||||
shouldCallLifecycleInitHook(view, ViewState.InitState_CallingAfterContentInit, initIndex)) {
|
|
||||||
provider.ngAfterContentInit();
|
provider.ngAfterContentInit();
|
||||||
}
|
}
|
||||||
if (lifecycles & NodeFlags.AfterContentChecked) {
|
if (lifecycles & NodeFlags.AfterContentChecked) {
|
||||||
provider.ngAfterContentChecked();
|
provider.ngAfterContentChecked();
|
||||||
}
|
}
|
||||||
if (lifecycles & NodeFlags.AfterViewInit &&
|
if (lifecycles & NodeFlags.AfterViewInit) {
|
||||||
shouldCallLifecycleInitHook(view, ViewState.InitState_CallingAfterViewInit, initIndex)) {
|
|
||||||
provider.ngAfterViewInit();
|
provider.ngAfterViewInit();
|
||||||
}
|
}
|
||||||
if (lifecycles & NodeFlags.AfterViewChecked) {
|
if (lifecycles & NodeFlags.AfterViewChecked) {
|
||||||
|
@ -10,7 +10,6 @@ import {isDevMode} from '../application_ref';
|
|||||||
import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from '../debug/debug_node';
|
import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from '../debug/debug_node';
|
||||||
import {Injector} from '../di';
|
import {Injector} from '../di';
|
||||||
import {ErrorHandler} from '../error_handler';
|
import {ErrorHandler} from '../error_handler';
|
||||||
import {ComponentFactory} from '../linker/component_factory';
|
|
||||||
import {NgModuleRef} from '../linker/ng_module_factory';
|
import {NgModuleRef} from '../linker/ng_module_factory';
|
||||||
import {Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2} from '../render/api';
|
import {Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2} from '../render/api';
|
||||||
import {Sanitizer} from '../security';
|
import {Sanitizer} from '../security';
|
||||||
@ -19,9 +18,9 @@ import {Type} from '../type';
|
|||||||
import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors';
|
import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors';
|
||||||
import {resolveDep} from './provider';
|
import {resolveDep} from './provider';
|
||||||
import {dirtyParentQueries, getQueryValue} from './query';
|
import {dirtyParentQueries, getQueryValue} from './query';
|
||||||
import {createInjector, createNgModuleRef, getComponentViewDefinitionFactory} from './refs';
|
import {createInjector, createNgModuleRef} from './refs';
|
||||||
import {ArgumentType, BindingFlags, CheckType, DebugContext, DepDef, ElementData, NgModuleDefinition, NgModuleProviderDef, NodeDef, NodeFlags, NodeLogger, ProviderOverride, RootData, Services, ViewData, ViewDefinition, ViewState, asElementData, asPureExpressionData} from './types';
|
import {ArgumentType, BindingFlags, CheckType, DebugContext, DepDef, ElementData, NgModuleDefinition, NgModuleProviderDef, NodeDef, NodeFlags, NodeLogger, ProviderOverride, RootData, Services, ViewData, ViewDefinition, ViewState, asElementData, asPureExpressionData} from './types';
|
||||||
import {NOOP, isComponentView, renderNode, resolveDefinition, splitDepsDsl, viewParentEl} from './util';
|
import {NOOP, isComponentView, renderNode, splitDepsDsl, viewParentEl} from './util';
|
||||||
import {checkAndUpdateNode, checkAndUpdateView, checkNoChangesNode, checkNoChangesView, createComponentView, createEmbeddedView, createRootView, destroyView} from './view';
|
import {checkAndUpdateNode, checkAndUpdateView, checkNoChangesNode, checkNoChangesView, createComponentView, createEmbeddedView, createRootView, destroyView} from './view';
|
||||||
|
|
||||||
|
|
||||||
@ -39,8 +38,7 @@ export function initServicesIfNeeded() {
|
|||||||
Services.createComponentView = services.createComponentView;
|
Services.createComponentView = services.createComponentView;
|
||||||
Services.createNgModuleRef = services.createNgModuleRef;
|
Services.createNgModuleRef = services.createNgModuleRef;
|
||||||
Services.overrideProvider = services.overrideProvider;
|
Services.overrideProvider = services.overrideProvider;
|
||||||
Services.overrideComponentView = services.overrideComponentView;
|
Services.clearProviderOverrides = services.clearProviderOverrides;
|
||||||
Services.clearOverrides = services.clearOverrides;
|
|
||||||
Services.checkAndUpdateView = services.checkAndUpdateView;
|
Services.checkAndUpdateView = services.checkAndUpdateView;
|
||||||
Services.checkNoChangesView = services.checkNoChangesView;
|
Services.checkNoChangesView = services.checkNoChangesView;
|
||||||
Services.destroyView = services.destroyView;
|
Services.destroyView = services.destroyView;
|
||||||
@ -60,8 +58,7 @@ function createProdServices() {
|
|||||||
createComponentView: createComponentView,
|
createComponentView: createComponentView,
|
||||||
createNgModuleRef: createNgModuleRef,
|
createNgModuleRef: createNgModuleRef,
|
||||||
overrideProvider: NOOP,
|
overrideProvider: NOOP,
|
||||||
overrideComponentView: NOOP,
|
clearProviderOverrides: NOOP,
|
||||||
clearOverrides: NOOP,
|
|
||||||
checkAndUpdateView: checkAndUpdateView,
|
checkAndUpdateView: checkAndUpdateView,
|
||||||
checkNoChangesView: checkNoChangesView,
|
checkNoChangesView: checkNoChangesView,
|
||||||
destroyView: destroyView,
|
destroyView: destroyView,
|
||||||
@ -87,8 +84,7 @@ function createDebugServices() {
|
|||||||
createComponentView: debugCreateComponentView,
|
createComponentView: debugCreateComponentView,
|
||||||
createNgModuleRef: debugCreateNgModuleRef,
|
createNgModuleRef: debugCreateNgModuleRef,
|
||||||
overrideProvider: debugOverrideProvider,
|
overrideProvider: debugOverrideProvider,
|
||||||
overrideComponentView: debugOverrideComponentView,
|
clearProviderOverrides: debugClearProviderOverrides,
|
||||||
clearOverrides: debugClearOverrides,
|
|
||||||
checkAndUpdateView: debugCheckAndUpdateView,
|
checkAndUpdateView: debugCheckAndUpdateView,
|
||||||
checkNoChangesView: debugCheckNoChangesView,
|
checkNoChangesView: debugCheckNoChangesView,
|
||||||
destroyView: debugDestroyView,
|
destroyView: debugDestroyView,
|
||||||
@ -143,15 +139,10 @@ function debugCreateEmbeddedView(
|
|||||||
|
|
||||||
function debugCreateComponentView(
|
function debugCreateComponentView(
|
||||||
parentView: ViewData, nodeDef: NodeDef, viewDef: ViewDefinition, hostElement: any): ViewData {
|
parentView: ViewData, nodeDef: NodeDef, viewDef: ViewDefinition, hostElement: any): ViewData {
|
||||||
const overrideComponentView =
|
const defWithOverride = applyProviderOverridesToView(viewDef);
|
||||||
viewDefOverrides.get(nodeDef.element !.componentProvider !.provider !.token);
|
|
||||||
if (overrideComponentView) {
|
|
||||||
viewDef = overrideComponentView;
|
|
||||||
} else {
|
|
||||||
viewDef = applyProviderOverridesToView(viewDef);
|
|
||||||
}
|
|
||||||
return callWithDebugContext(
|
return callWithDebugContext(
|
||||||
DebugAction.create, createComponentView, null, [parentView, nodeDef, viewDef, hostElement]);
|
DebugAction.create, createComponentView, null,
|
||||||
|
[parentView, nodeDef, defWithOverride, hostElement]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function debugCreateNgModuleRef(
|
function debugCreateNgModuleRef(
|
||||||
@ -162,21 +153,13 @@ function debugCreateNgModuleRef(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const providerOverrides = new Map<any, ProviderOverride>();
|
const providerOverrides = new Map<any, ProviderOverride>();
|
||||||
const viewDefOverrides = new Map<any, ViewDefinition>();
|
|
||||||
|
|
||||||
function debugOverrideProvider(override: ProviderOverride) {
|
function debugOverrideProvider(override: ProviderOverride) {
|
||||||
providerOverrides.set(override.token, override);
|
providerOverrides.set(override.token, override);
|
||||||
}
|
}
|
||||||
|
|
||||||
function debugOverrideComponentView(comp: any, compFactory: ComponentFactory<any>) {
|
function debugClearProviderOverrides() {
|
||||||
const hostViewDef = resolveDefinition(getComponentViewDefinitionFactory(compFactory));
|
|
||||||
const compViewDef = resolveDefinition(hostViewDef.nodes[0].element !.componentView !);
|
|
||||||
viewDefOverrides.set(comp, compViewDef);
|
|
||||||
}
|
|
||||||
|
|
||||||
function debugClearOverrides() {
|
|
||||||
providerOverrides.clear();
|
providerOverrides.clear();
|
||||||
viewDefOverrides.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notes about the algorithm:
|
// Notes about the algorithm:
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
import {Injector} from '../di';
|
import {Injector} from '../di';
|
||||||
import {ErrorHandler} from '../error_handler';
|
import {ErrorHandler} from '../error_handler';
|
||||||
import {ComponentFactory} from '../linker/component_factory';
|
|
||||||
import {NgModuleRef} from '../linker/ng_module_factory';
|
import {NgModuleRef} from '../linker/ng_module_factory';
|
||||||
import {QueryList} from '../linker/query_list';
|
import {QueryList} from '../linker/query_list';
|
||||||
import {TemplateRef} from '../linker/template_ref';
|
import {TemplateRef} from '../linker/template_ref';
|
||||||
@ -17,7 +16,6 @@ import {Renderer2, RendererFactory2, RendererType2} from '../render/api';
|
|||||||
import {Sanitizer, SecurityContext} from '../security';
|
import {Sanitizer, SecurityContext} from '../security';
|
||||||
import {Type} from '../type';
|
import {Type} from '../type';
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
// Defs
|
// Defs
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
@ -354,7 +352,6 @@ export interface ViewData {
|
|||||||
state: ViewState;
|
state: ViewState;
|
||||||
oldValues: any[];
|
oldValues: any[];
|
||||||
disposables: DisposableFn[]|null;
|
disposables: DisposableFn[]|null;
|
||||||
initIndex: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -370,52 +367,8 @@ export const enum ViewState {
|
|||||||
CheckProjectedViews = 1 << 6,
|
CheckProjectedViews = 1 << 6,
|
||||||
Destroyed = 1 << 7,
|
Destroyed = 1 << 7,
|
||||||
|
|
||||||
// InitState Uses 3 bits
|
|
||||||
InitState_Mask = 7 << 8,
|
|
||||||
InitState_BeforeInit = 0 << 8,
|
|
||||||
InitState_CallingOnInit = 1 << 8,
|
|
||||||
InitState_CallingAfterContentInit = 2 << 8,
|
|
||||||
InitState_CallingAfterViewInit = 3 << 8,
|
|
||||||
InitState_AfterInit = 4 << 8,
|
|
||||||
|
|
||||||
CatDetectChanges = Attached | ChecksEnabled,
|
CatDetectChanges = Attached | ChecksEnabled,
|
||||||
CatInit = BeforeFirstCheck | CatDetectChanges | InitState_BeforeInit
|
CatInit = BeforeFirstCheck | CatDetectChanges
|
||||||
}
|
|
||||||
|
|
||||||
// Called before each cycle of a view's check to detect whether this is in the
|
|
||||||
// initState for which we need to call ngOnInit, ngAfterContentInit or ngAfterViewInit
|
|
||||||
// lifecycle methods. Returns true if this check cycle should call lifecycle
|
|
||||||
// methods.
|
|
||||||
export function shiftInitState(
|
|
||||||
view: ViewData, priorInitState: ViewState, newInitState: ViewState): boolean {
|
|
||||||
// Only update the InitState if we are currently in the prior state.
|
|
||||||
// For example, only move into CallingInit if we are in BeforeInit. Only
|
|
||||||
// move into CallingContentInit if we are in CallingInit. Normally this will
|
|
||||||
// always be true because of how checkCycle is called in checkAndUpdateView.
|
|
||||||
// However, if checkAndUpdateView is called recursively or if an exception is
|
|
||||||
// thrown while checkAndUpdateView is running, checkAndUpdateView starts over
|
|
||||||
// from the beginning. This ensures the state is monotonically increasing,
|
|
||||||
// terminating in the AfterInit state, which ensures the Init methods are called
|
|
||||||
// at least once and only once.
|
|
||||||
const state = view.state;
|
|
||||||
const initState = state & ViewState.InitState_Mask;
|
|
||||||
if (initState === priorInitState) {
|
|
||||||
view.state = (state & ~ViewState.InitState_Mask) | newInitState;
|
|
||||||
view.initIndex = -1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return initState === newInitState;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if the lifecycle init method should be called for the node with
|
|
||||||
// the given init index.
|
|
||||||
export function shouldCallLifecycleInitHook(
|
|
||||||
view: ViewData, initState: ViewState, index: number): boolean {
|
|
||||||
if ((view.state & ViewState.InitState_Mask) === initState && view.initIndex <= index) {
|
|
||||||
view.initIndex = index + 1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DisposableFn { (): void; }
|
export interface DisposableFn { (): void; }
|
||||||
@ -569,8 +522,7 @@ export interface Services {
|
|||||||
moduleType: Type<any>, parent: Injector, bootstrapComponents: Type<any>[],
|
moduleType: Type<any>, parent: Injector, bootstrapComponents: Type<any>[],
|
||||||
def: NgModuleDefinition): NgModuleRef<any>;
|
def: NgModuleDefinition): NgModuleRef<any>;
|
||||||
overrideProvider(override: ProviderOverride): void;
|
overrideProvider(override: ProviderOverride): void;
|
||||||
overrideComponentView(compType: Type<any>, compFactory: ComponentFactory<any>): void;
|
clearProviderOverrides(): void;
|
||||||
clearOverrides(): void;
|
|
||||||
checkAndUpdateView(view: ViewData): void;
|
checkAndUpdateView(view: ViewData): void;
|
||||||
checkNoChangesView(view: ViewData): void;
|
checkNoChangesView(view: ViewData): void;
|
||||||
destroyView(view: ViewData): void;
|
destroyView(view: ViewData): void;
|
||||||
@ -595,8 +547,7 @@ export const Services: Services = {
|
|||||||
createComponentView: undefined !,
|
createComponentView: undefined !,
|
||||||
createNgModuleRef: undefined !,
|
createNgModuleRef: undefined !,
|
||||||
overrideProvider: undefined !,
|
overrideProvider: undefined !,
|
||||||
overrideComponentView: undefined !,
|
clearProviderOverrides: undefined !,
|
||||||
clearOverrides: undefined !,
|
|
||||||
checkAndUpdateView: undefined !,
|
checkAndUpdateView: undefined !,
|
||||||
checkNoChangesView: undefined !,
|
checkNoChangesView: undefined !,
|
||||||
destroyView: undefined !,
|
destroyView: undefined !,
|
||||||
|
@ -16,7 +16,7 @@ import {checkAndUpdatePureExpressionDynamic, checkAndUpdatePureExpressionInline,
|
|||||||
import {checkAndUpdateQuery, createQuery} from './query';
|
import {checkAndUpdateQuery, createQuery} from './query';
|
||||||
import {createTemplateData, createViewContainerData} from './refs';
|
import {createTemplateData, createViewContainerData} from './refs';
|
||||||
import {checkAndUpdateTextDynamic, checkAndUpdateTextInline, createText} from './text';
|
import {checkAndUpdateTextDynamic, checkAndUpdateTextInline, createText} from './text';
|
||||||
import {ArgumentType, CheckType, ElementData, NodeData, NodeDef, NodeFlags, ProviderData, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewState, ViewUpdateFn, asElementData, asQueryList, asTextData, shiftInitState} from './types';
|
import {ArgumentType, CheckType, ElementData, NodeData, NodeDef, NodeFlags, ProviderData, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewState, ViewUpdateFn, asElementData, asQueryList, asTextData} from './types';
|
||||||
import {NOOP, checkBindingNoChanges, isComponentView, markParentViewsForCheckProjectedViews, resolveDefinition, tokenKey} from './util';
|
import {NOOP, checkBindingNoChanges, isComponentView, markParentViewsForCheckProjectedViews, resolveDefinition, tokenKey} from './util';
|
||||||
import {detachProjectedView} from './view_attach';
|
import {detachProjectedView} from './view_attach';
|
||||||
|
|
||||||
@ -236,8 +236,7 @@ function createView(
|
|||||||
context: null,
|
context: null,
|
||||||
component: null, nodes,
|
component: null, nodes,
|
||||||
state: ViewState.CatInit, root, renderer,
|
state: ViewState.CatInit, root, renderer,
|
||||||
oldValues: new Array(def.bindingCount), disposables,
|
oldValues: new Array(def.bindingCount), disposables
|
||||||
initIndex: -1
|
|
||||||
};
|
};
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
@ -354,32 +353,29 @@ export function checkAndUpdateView(view: ViewData) {
|
|||||||
} else {
|
} else {
|
||||||
view.state &= ~ViewState.FirstCheck;
|
view.state &= ~ViewState.FirstCheck;
|
||||||
}
|
}
|
||||||
shiftInitState(view, ViewState.InitState_BeforeInit, ViewState.InitState_CallingOnInit);
|
|
||||||
markProjectedViewsForCheck(view);
|
markProjectedViewsForCheck(view);
|
||||||
Services.updateDirectives(view, CheckType.CheckAndUpdate);
|
Services.updateDirectives(view, CheckType.CheckAndUpdate);
|
||||||
execEmbeddedViewsAction(view, ViewAction.CheckAndUpdate);
|
execEmbeddedViewsAction(view, ViewAction.CheckAndUpdate);
|
||||||
execQueriesAction(
|
execQueriesAction(
|
||||||
view, NodeFlags.TypeContentQuery, NodeFlags.DynamicQuery, CheckType.CheckAndUpdate);
|
view, NodeFlags.TypeContentQuery, NodeFlags.DynamicQuery, CheckType.CheckAndUpdate);
|
||||||
let callInit = shiftInitState(
|
|
||||||
view, ViewState.InitState_CallingOnInit, ViewState.InitState_CallingAfterContentInit);
|
|
||||||
callLifecycleHooksChildrenFirst(
|
callLifecycleHooksChildrenFirst(
|
||||||
view, NodeFlags.AfterContentChecked | (callInit ? NodeFlags.AfterContentInit : 0));
|
view, NodeFlags.AfterContentChecked |
|
||||||
|
(view.state & ViewState.FirstCheck ? NodeFlags.AfterContentInit : 0));
|
||||||
|
|
||||||
Services.updateRenderer(view, CheckType.CheckAndUpdate);
|
Services.updateRenderer(view, CheckType.CheckAndUpdate);
|
||||||
|
|
||||||
execComponentViewsAction(view, ViewAction.CheckAndUpdate);
|
execComponentViewsAction(view, ViewAction.CheckAndUpdate);
|
||||||
execQueriesAction(
|
execQueriesAction(
|
||||||
view, NodeFlags.TypeViewQuery, NodeFlags.DynamicQuery, CheckType.CheckAndUpdate);
|
view, NodeFlags.TypeViewQuery, NodeFlags.DynamicQuery, CheckType.CheckAndUpdate);
|
||||||
callInit = shiftInitState(
|
|
||||||
view, ViewState.InitState_CallingAfterContentInit, ViewState.InitState_CallingAfterViewInit);
|
|
||||||
callLifecycleHooksChildrenFirst(
|
callLifecycleHooksChildrenFirst(
|
||||||
view, NodeFlags.AfterViewChecked | (callInit ? NodeFlags.AfterViewInit : 0));
|
view, NodeFlags.AfterViewChecked |
|
||||||
|
(view.state & ViewState.FirstCheck ? NodeFlags.AfterViewInit : 0));
|
||||||
|
|
||||||
if (view.def.flags & ViewFlags.OnPush) {
|
if (view.def.flags & ViewFlags.OnPush) {
|
||||||
view.state &= ~ViewState.ChecksEnabled;
|
view.state &= ~ViewState.ChecksEnabled;
|
||||||
}
|
}
|
||||||
view.state &= ~(ViewState.CheckProjectedViews | ViewState.CheckProjectedView);
|
view.state &= ~(ViewState.CheckProjectedViews | ViewState.CheckProjectedView);
|
||||||
shiftInitState(view, ViewState.InitState_CallingAfterViewInit, ViewState.InitState_AfterInit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkAndUpdateNode(
|
export function checkAndUpdateNode(
|
||||||
|
@ -31,7 +31,7 @@ import {EventEmitter} from '../event_emitter';
|
|||||||
* import {NgIf} from '@angular/common';
|
* import {NgIf} from '@angular/common';
|
||||||
*
|
*
|
||||||
* @Component({
|
* @Component({
|
||||||
* selector: 'ng-zone-demo',
|
* selector: 'ng-zone-demo'.
|
||||||
* template: `
|
* template: `
|
||||||
* <h2>Demo: NgZone</h2>
|
* <h2>Demo: NgZone</h2>
|
||||||
*
|
*
|
||||||
@ -64,9 +64,8 @@ import {EventEmitter} from '../event_emitter';
|
|||||||
* this._ngZone.runOutsideAngular(() => {
|
* this._ngZone.runOutsideAngular(() => {
|
||||||
* this._increaseProgress(() => {
|
* this._increaseProgress(() => {
|
||||||
* // reenter the Angular zone and display done
|
* // reenter the Angular zone and display done
|
||||||
* this._ngZone.run(() => { console.log('Outside Done!'); });
|
* this._ngZone.run(() => {console.log('Outside Done!') });
|
||||||
* });
|
* }}));
|
||||||
* });
|
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* _increaseProgress(doneCallback: () => void) {
|
* _increaseProgress(doneCallback: () => void) {
|
||||||
@ -74,7 +73,7 @@ import {EventEmitter} from '../event_emitter';
|
|||||||
* console.log(`Current progress: ${this.progress}%`);
|
* console.log(`Current progress: ${this.progress}%`);
|
||||||
*
|
*
|
||||||
* if (this.progress < 100) {
|
* if (this.progress < 100) {
|
||||||
* window.setTimeout(() => this._increaseProgress(doneCallback), 10);
|
* window.setTimeout(() => this._increaseProgress(doneCallback)), 10)
|
||||||
* } else {
|
* } else {
|
||||||
* doneCallback();
|
* doneCallback();
|
||||||
* }
|
* }
|
||||||
|
@ -80,38 +80,6 @@ export function main() {
|
|||||||
flushMicrotasks();
|
flushMicrotasks();
|
||||||
expect(cmp.status).toEqual('done');
|
expect(cmp.status).toEqual('done');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should always run .start callbacks before .done callbacks even for noop animations',
|
|
||||||
fakeAsync(() => {
|
|
||||||
@Component({
|
|
||||||
selector: 'cmp',
|
|
||||||
template: `
|
|
||||||
<div [@myAnimation]="exp" (@myAnimation.start)="cb('start')" (@myAnimation.done)="cb('done')"></div>
|
|
||||||
`,
|
|
||||||
animations: [
|
|
||||||
trigger(
|
|
||||||
'myAnimation',
|
|
||||||
[
|
|
||||||
transition('* => go', []),
|
|
||||||
]),
|
|
||||||
]
|
|
||||||
})
|
|
||||||
class Cmp {
|
|
||||||
exp: any = false;
|
|
||||||
log: string[] = [];
|
|
||||||
cb(status: string) { this.log.push(status); }
|
|
||||||
}
|
|
||||||
|
|
||||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
|
||||||
const fixture = TestBed.createComponent(Cmp);
|
|
||||||
const cmp = fixture.componentInstance;
|
|
||||||
cmp.exp = 'go';
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(cmp.log).toEqual([]);
|
|
||||||
|
|
||||||
flushMicrotasks();
|
|
||||||
expect(cmp.log).toEqual(['start', 'done']);
|
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('component fixture integration', () => {
|
describe('component fixture integration', () => {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user