Compare commits
250 Commits
2.0.2
...
2.2.0-rc.0
Author | SHA1 | Date | |
---|---|---|---|
953cb50fa5 | |||
3fffcf6645 | |||
d509ee078b | |||
8e221b826f | |||
830a780cb3 | |||
6fda97287e | |||
234c5599f1 | |||
f6710fefeb | |||
bda1909ede | |||
b3e3cd3add | |||
e5fdf4c70a | |||
97471d74b6 | |||
1de04b23b1 | |||
a178bc6c83 | |||
642c1db9ef | |||
579deeb9c5 | |||
bad58824a0 | |||
5494169fb4 | |||
5a3d7a62a2 | |||
a382d6dd20 | |||
52bf188b8f | |||
6f412bb449 | |||
e9fd8645ed | |||
a0aecac0e5 | |||
938ed1c76d | |||
eb8288f76c | |||
0936ceeab4 | |||
e0ad413a8e | |||
3045d02b9a | |||
e86573bac8 | |||
0a94845435 | |||
262bd23b84 | |||
7b8dae19af | |||
7c16ef942e | |||
a318b57257 | |||
fe47e6b783 | |||
091c390032 | |||
e391cacdf9 | |||
32feb8a532 | |||
a664aba2c9 | |||
d520fae70e | |||
fa93fd672e | |||
f4be2f907d | |||
2ea27a76d3 | |||
ec0acf9a1b | |||
a26dd28bdb | |||
7742ec00e7 | |||
2b5c983c13 | |||
ef153649b3 | |||
d321b0ebf5 | |||
b4265e0685 | |||
178fb79b5c | |||
5a7a58b1e0 | |||
f66ac821a2 | |||
fe299f4dfc | |||
4cac650675 | |||
cb7643ccea | |||
faa3478514 | |||
bc3f4bc816 | |||
c9f58cf78c | |||
6ccbfd41dd | |||
7d2554baa1 | |||
52a853e257 | |||
8f2fa0f766 | |||
fc60fa790c | |||
b74185369f | |||
7221632228 | |||
02f1222a8d | |||
c27ce7318f | |||
a838aba756 | |||
bfc97ff2cd | |||
57051f01ce | |||
e319cfefc3 | |||
444014ad96 | |||
867494a060 | |||
69ad99dca6 | |||
da5fc696bb | |||
b44b6ef8f5 | |||
0f21a5823b | |||
5ae6915600 | |||
8b9ab44eee | |||
b0a03fcab3 | |||
c951822c35 | |||
acda82c1ed | |||
a8815d6b08 | |||
d6791ff0e0 | |||
a2d35641e3 | |||
76dd026447 | |||
0ecd9b2df0 | |||
0e9503b500 | |||
f77ab6a2d2 | |||
97bc97153b | |||
445e5922ec | |||
b9fc090143 | |||
592f40aa9c | |||
24facdea2d | |||
aa2d3372a5 | |||
bf60418fdc | |||
cca4a5c519 | |||
6e5f8b59b3 | |||
8409b65153 | |||
38e2203b24 | |||
bd1dcb5f11 | |||
3993279527 | |||
bf1e2613b2 | |||
f7db0668d1 | |||
27d76776b8 | |||
8603d9c269 | |||
d55f747858 | |||
52de0fa558 | |||
d61ecf0663 | |||
5a9c5f28b8 | |||
15fc5dd7ee | |||
a5419608e0 | |||
5f95bf1dd2 | |||
33c8948fd3 | |||
606e51881a | |||
fdf4309b50 | |||
af996ef0c4 | |||
68d2dfdd2a | |||
07bd4b0630 | |||
df1718d624 | |||
17e3410d98 | |||
5effc330ed | |||
3df00828d7 | |||
8c477b2f45 | |||
7787771aba | |||
7275e1beb3 | |||
12ba62e5e2 | |||
e6e007e2f1 | |||
91dd138fa5 | |||
d972d82354 | |||
bdcf46f82e | |||
79e1c7b807 | |||
d22eeb70b8 | |||
aa92512ac6 | |||
f782b08f58 | |||
4202936bbf | |||
e1faca6386 | |||
f5b0e22d35 | |||
00693d70a2 | |||
bcef5efffe | |||
13ecc140e8 | |||
709a6dea06 | |||
16cfb88c00 | |||
efee6f5199 | |||
2aa8aae76d | |||
afb4bd9ef6 | |||
d641c36a45 | |||
f4566f8128 | |||
a67c06708d | |||
d9d57d71dd | |||
e06303a987 | |||
40b92ddf21 | |||
1681e4f57f | |||
71b7654660 | |||
eaaec6979c | |||
c587c63591 | |||
f50c1da4e2 | |||
0254ce1f6c | |||
c9b765f5c0 | |||
8c975ed156 | |||
bb35fcb562 | |||
57230b70a9 | |||
43dc60ce4f | |||
230b3b73d8 | |||
0b7dc2f9ff | |||
de1f44f51f | |||
f1cfddf6d6 | |||
ef621a2f00 | |||
df9761951b | |||
f786c560f1 | |||
c5557de3e7 | |||
ec3a5b54de | |||
cf269d9ff4 | |||
5fa5ffb82a | |||
4a57dcfd8d | |||
43923ffcf5 | |||
50c37d45dc | |||
a63359689f | |||
43d3a84df3 | |||
8310c91823 | |||
b64b5ece65 | |||
ed9c2b6281 | |||
1cf5f5fa38 | |||
a32078f85e | |||
decd129a4d | |||
c3c9ecb302 | |||
af520947aa | |||
040bf57966 | |||
65a60b7456 | |||
756ef09d12 | |||
9316f95467 | |||
83d94b7504 | |||
a121136fae | |||
a6bb84e02b | |||
3898dc488e | |||
ca3f9926f9 | |||
1c012a035f | |||
38c5304b7f | |||
9a049be67f | |||
2045c9e8ee | |||
6c4ec05a4a | |||
f7bfda31ff | |||
a92b573309 | |||
4fd13d71c8 | |||
bf7b82b658 | |||
c143fee849 | |||
0286956107 | |||
e884f4854d | |||
df1822fc2a | |||
42b4b6d21b | |||
36bc2ff269 | |||
1564042fe8 | |||
41c8c30973 | |||
61129fa12d | |||
3a5b4882bc | |||
425c1e6042 | |||
58605cf350 | |||
34b31dea7c | |||
a241ab7c07 | |||
745e10e6d2 | |||
33340dbbd1 | |||
52812c08e2 | |||
52f5ae1961 | |||
9be895b6da | |||
9f1c82537e | |||
5ab5cc77bb | |||
f1b6c6efa1 | |||
45ad13560b | |||
2045268cec | |||
fb1076b44a | |||
6fc46526ae | |||
3ef5ede6d6 | |||
136621ebc9 | |||
f23b22a0f4 | |||
0ca971c5bd | |||
3a6fcee0e6 | |||
8972137c29 | |||
cc6481077f | |||
c041b93418 | |||
bc33765913 | |||
31dce72b7b | |||
212f8dbde7 | |||
44da4984f9 | |||
d95344430c | |||
131626fc61 | |||
676bb0fa7d | |||
5a849829c4 | |||
671f73448c |
176
CHANGELOG.md
176
CHANGELOG.md
@ -1,3 +1,163 @@
|
|||||||
|
<a name="2.2.0-rc.0"></a>
|
||||||
|
# [2.2.0-rc.0](https://github.com/angular/angular/compare/2.2.0-beta.1...2.2.0-rc.0) (2016-11-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** dedupe NgModule declarations, … ([a178bc6](https://github.com/angular/angular/commit/a178bc6))
|
||||||
|
* **compiler:** don’t double bind functions ([e391cac](https://github.com/angular/angular/commit/e391cac))
|
||||||
|
* **compiler:** Don’t throw on empty property bindings ([642c1db](https://github.com/angular/angular/commit/642c1db)), closes [#12583](https://github.com/angular/angular/issues/12583)
|
||||||
|
* **compiler:** support multiple components in a view container ([6fda972](https://github.com/angular/angular/commit/6fda972))
|
||||||
|
* **core:** improve error when multiple components match the same element ([e9fd864](https://github.com/angular/angular/commit/e9fd864)), closes [#7067](https://github.com/angular/angular/issues/7067)
|
||||||
|
* **router:** call data observers when the path changes ([1de04b2](https://github.com/angular/angular/commit/1de04b2))
|
||||||
|
* **router:** CanDeactivate receives a wrong component ([830a780](https://github.com/angular/angular/commit/830a780)), closes [#12592](https://github.com/angular/angular/issues/12592)
|
||||||
|
* **router:** rerun resolvers when url changes ([fe47e6b](https://github.com/angular/angular/commit/fe47e6b)), closes [#12603](https://github.com/angular/angular/issues/12603)
|
||||||
|
* **router:** reset URL to the stable state when a navigation gets canceled ([d509ee0](https://github.com/angular/angular/commit/d509ee0)), closes [#10321](https://github.com/angular/angular/issues/10321)
|
||||||
|
* **router:** routerLink should not prevent default on non-link elements ([8e221b8](https://github.com/angular/angular/commit/8e221b8))
|
||||||
|
* **router:** run navigations serially ([091c390](https://github.com/angular/angular/commit/091c390)), closes [#11754](https://github.com/angular/angular/issues/11754)
|
||||||
|
* **upgrade:** silent bootstrap failures ([fa93fd6](https://github.com/angular/angular/commit/fa93fd6)), closes [#12062](https://github.com/angular/angular/issues/12062)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **core:** add the find method to QueryList ([7c16ef9](https://github.com/angular/angular/commit/7c16ef9))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="2.1.2"></a>
|
||||||
|
# [2.1.2](https://github.com/angular/angular/compare/2.1.1...2.1.2) (2016-10-27)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** don't access view local variables nor pipes in host expressions ([#12396](https://github.com/angular/angular/issues/12396)) ([867494a](https://github.com/angular/angular/commit/867494a)), closes [#12004](https://github.com/angular/angular/issues/12004) [#12071](https://github.com/angular/angular/issues/12071)
|
||||||
|
* **compiler:** walk third party modules ([#12453](https://github.com/angular/angular/issues/12453)) ([a838aba](https://github.com/angular/angular/commit/a838aba)), closes [#11889](https://github.com/angular/angular/issues/11889) [#12428](https://github.com/angular/angular/issues/12428)
|
||||||
|
* **compiler:** remove double exports of template_ast ([7742ec0](https://github.com/angular/angular/commit/7742ec0))
|
||||||
|
* **compiler:** use Maps instead of objects in selector implementation ([d321b0e](https://github.com/angular/angular/commit/d321b0e))
|
||||||
|
* **compiler-cli:** fix types ([ef15364](https://github.com/angular/angular/commit/ef15364))
|
||||||
|
* **compiler-cli:** assert that all pipes and directives are declared by a module ([7221632](https://github.com/angular/angular/commit/7221632))
|
||||||
|
* **http:** overwrite already set xsrf header ([b4265e0](https://github.com/angular/angular/commit/b4265e0))
|
||||||
|
* **router:** add a test to make sure canDeactivate guards are called for aux routes ([fc60fa7](https://github.com/angular/angular/commit/fc60fa7)), closes [#11345](https://github.com/angular/angular/issues/11345)
|
||||||
|
* **router:** canDeactivate guards are not triggered for componentless routes ([b741853](https://github.com/angular/angular/commit/b741853)), closes [#12375](https://github.com/angular/angular/issues/12375)
|
||||||
|
* **router:** change router not to deactivate aux routes when navigating from a componentless routes ([52a853e](https://github.com/angular/angular/commit/52a853e))
|
||||||
|
* **router:** disallow component routes with named outlets ([8f2fa0f](https://github.com/angular/angular/commit/8f2fa0f)), closes [#11208](https://github.com/angular/angular/issues/11208) [#11082](https://github.com/angular/angular/issues/11082)
|
||||||
|
* **router:** preserve resolve data ([6ccbfd4](https://github.com/angular/angular/commit/6ccbfd4)), closes [#12306](https://github.com/angular/angular/issues/12306)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="2.2.0-beta.1"></a>
|
||||||
|
# [2.2.0-beta.1](https://github.com/angular/angular/compare/2.2.0-beta.0...2.2.0-beta.1) (2016-10-27)
|
||||||
|
|
||||||
|
### Code Refactoring
|
||||||
|
|
||||||
|
* **upgrade:** re-export the new static upgrade APIs on new entry ([a26dd28](https://github.com/angular/angular/commit/a26dd28))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **router:** export routerLinkActive w/ isActive property ([c9f58cf](https://github.com/angular/angular/commit/c9f58cf))
|
||||||
|
|
||||||
|
|
||||||
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
* upgrade: Four newly added APIs in 2.2.0-beta:
|
||||||
|
downgradeComponent, downgradeInjectable, UpgradeComponent, and UpgradeModule are no longer exported by @angular/upgrade.
|
||||||
|
Import these from @angular/upgrade/static instead.
|
||||||
|
|
||||||
|
|
||||||
|
Note: The 2.2.0-beta.1 release also contains all the changes present in the 2.1.2 release.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [2.1.1](https://github.com/angular/angular/compare/2.1.0...2.1.1) (2016-10-20)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** generate aot code for animation trigger output events ([#12291](https://github.com/angular/angular/issues/12291)) ([6e5f8b5](https://github.com/angular/angular/commit/6e5f8b5)), closes [#11707](https://github.com/angular/angular/issues/11707)
|
||||||
|
* **compiler:** don't redeclare a var in the same scope ([#12386](https://github.com/angular/angular/issues/12386)) ([cca4a5c](https://github.com/angular/angular/commit/cca4a5c))
|
||||||
|
* **core:** fix decorator default values ([bd1dcb5](https://github.com/angular/angular/commit/bd1dcb5))
|
||||||
|
* **core:** fix property decorators ([3993279](https://github.com/angular/angular/commit/3993279)), closes [#12224](https://github.com/angular/angular/issues/12224)
|
||||||
|
* **http:** make normalizeMethodName optimizer-compatible. ([#12370](https://github.com/angular/angular/issues/12370)) ([8409b65](https://github.com/angular/angular/commit/8409b65))
|
||||||
|
* **router:** correctly export filter operator in es5 ([#12286](https://github.com/angular/angular/issues/12286)) ([27d7677](https://github.com/angular/angular/commit/27d7677))
|
||||||
|
* **router:** do not update primary route if only secondary outlet is given ([#11797](https://github.com/angular/angular/issues/11797)) ([da5fc69](https://github.com/angular/angular/commit/da5fc69))
|
||||||
|
* **router:** fix lazy loading triggered by redirects from wildcard routes ([5ae6915](https://github.com/angular/angular/commit/5ae6915)), closes [#12183](https://github.com/angular/angular/issues/12183)
|
||||||
|
* **router:** module loader should start compiling modules when stubbedModules are set ([#11742](https://github.com/angular/angular/issues/11742)) ([b44b6ef](https://github.com/angular/angular/commit/b44b6ef))
|
||||||
|
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* **common:** optimize NgSwitch default case ([fdf4309](https://github.com/angular/angular/commit/fdf4309))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="2.2.0-beta.0"></a>
|
||||||
|
# [2.2.0-beta.0](https://github.com/angular/angular/compare/2.1.0...2.2.0-beta.0) (2016-10-20)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **common:** support narrow forms for month and weekdays in DatePipe ([#12297](https://github.com/angular/angular/issues/12297)) ([f77ab6a](https://github.com/angular/angular/commit/f77ab6a)), closes [#12294](https://github.com/angular/angular/issues/12294)
|
||||||
|
* **forms:** add hasError and getError to AbstractControlDirective ([#11985](https://github.com/angular/angular/issues/11985)) ([592f40a](https://github.com/angular/angular/commit/592f40a)), closes [#7255](https://github.com/angular/angular/issues/7255)
|
||||||
|
* **forms:** add ng-pending CSS class during async validation ([#11243](https://github.com/angular/angular/issues/11243)) ([97bc971](https://github.com/angular/angular/commit/97bc971)), closes [#10336](https://github.com/angular/angular/issues/10336)
|
||||||
|
* **forms:** Added emitEvent to AbstractControl methods ([#11949](https://github.com/angular/angular/issues/11949)) ([b9fc090](https://github.com/angular/angular/commit/b9fc090))
|
||||||
|
* **forms:** make 'parent' a public property of 'AbstractControl' ([#11855](https://github.com/angular/angular/issues/11855)) ([445e592](https://github.com/angular/angular/commit/445e592))
|
||||||
|
* **forms:** Validator.pattern accepts a RegExp ([#12323](https://github.com/angular/angular/issues/12323)) ([bf60418](https://github.com/angular/angular/commit/bf60418))
|
||||||
|
* **upgrade:** add support for AoT compiled upgrade applications ([d6791ff](https://github.com/angular/angular/commit/d6791ff)), closes [#12239](https://github.com/angular/angular/issues/12239)
|
||||||
|
* **router:** add support for ng1/ng2 migration ([#12160](https://github.com/angular/angular/issues/12160)) ([8b9ab44](https://github.com/angular/angular/commit/8b9ab44))
|
||||||
|
|
||||||
|
Note: The 2.2.0-beta.0 release also contains all the changes present in the 2.1.1 release.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="2.1.0"></a>
|
||||||
|
# [2.1.0 incremental-metamorphosis](https://github.com/angular/angular/compare/2.1.0-rc.0...2.1.0) (2016-10-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** allow whitespace as `<ng-content>` content ([#12225](https://github.com/angular/angular/issues/12225)) ([df1718d](https://github.com/angular/angular/commit/df1718d))
|
||||||
|
* **compiler:** interpolation expressions report the correct offset ([#12125](https://github.com/angular/angular/issues/12125)) ([d641c36](https://github.com/angular/angular/commit/d641c36))
|
||||||
|
* **compiler:** properly shim `:host:before` and `:host(:before)` ([#12171](https://github.com/angular/angular/issues/12171)) ([aa92512](https://github.com/angular/angular/commit/aa92512)), closes [#12165](https://github.com/angular/angular/issues/12165)
|
||||||
|
* **compiler:** validate `@HostBinding` name ([#12139](https://github.com/angular/angular/issues/12139)) ([13ecc14](https://github.com/angular/angular/commit/13ecc14))
|
||||||
|
* **compiler-cli:** don't clone static symbols when simplifying annotation metadata ([#12158](https://github.com/angular/angular/issues/12158)) ([8c477b2](https://github.com/angular/angular/commit/8c477b2))
|
||||||
|
* **compiler-cli:** remove peerDependency on [@angular](https://github.com/angular)/platform-server ([#12122](https://github.com/angular/angular/issues/12122)) ([71b7654](https://github.com/angular/angular/commit/71b7654))
|
||||||
|
* **compiler-cli:** remove unused parse5 dependency from package.json ([eaaec69](https://github.com/angular/angular/commit/eaaec69))
|
||||||
|
* **forms:** allow optional fields with pattern and minlength validators ([#12147](https://github.com/angular/angular/issues/12147)) ([d22eeb7](https://github.com/angular/angular/commit/d22eeb7))
|
||||||
|
* **forms:** properly validate blank strings with minlength ([#12091](https://github.com/angular/angular/issues/12091)) ([f50c1da](https://github.com/angular/angular/commit/f50c1da))
|
||||||
|
* **http:** fix Headers initialization from Headers and Object ([#12106](https://github.com/angular/angular/issues/12106)) ([f4566f8](https://github.com/angular/angular/commit/f4566f8))
|
||||||
|
* **http:** Headers.append should append to the list ([a67c067](https://github.com/angular/angular/commit/a67c067))
|
||||||
|
* **platform-browser-dynamic:** mark platformBrowserDynamic as stable API ([#12154](https://github.com/angular/angular/issues/12154)) ([bcef5ef](https://github.com/angular/angular/commit/bcef5ef))
|
||||||
|
* **router:** improve error message ([#12102](https://github.com/angular/angular/issues/12102)) ([e06303a](https://github.com/angular/angular/commit/e06303a))
|
||||||
|
* **router:** parent resolve should complete before merging resolved data ([1681e4f](https://github.com/angular/angular/commit/1681e4f)), closes [#12032](https://github.com/angular/angular/issues/12032)
|
||||||
|
* **router:** wildcards routes should support lazy loading ([40b92dd](https://github.com/angular/angular/commit/40b92dd)), closes [#12024](https://github.com/angular/angular/issues/12024)
|
||||||
|
* **upgrade:** allow compilerOptions in bootstrap ([#10575](https://github.com/angular/angular/issues/10575)) ([5effc33](https://github.com/angular/angular/commit/5effc33))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="2.1.0-rc.0"></a>
|
||||||
|
# [2.1.0-rc.0](https://github.com/angular/angular/compare/2.1.0-beta.0...2.1.0-rc.0) (2016-10-05)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **animations:** provide aliases for `:enter` and `:leave` transitions ([#11991](https://github.com/angular/angular/issues/11991)) ([e884f48](https://github.com/angular/angular/commit/e884f48))
|
||||||
|
|
||||||
|
Note: 2.1.0-rc.0 release also contains all the changes present in the 2.0.2 release.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="2.1.0-beta.0"></a>
|
||||||
|
# [2.1.0-beta.0](https://github.com/angular/angular/compare/2.0.0...2.1.0-beta.0) (2016-09-23)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **router:** add router preloader to optimistically preload routes ([5a84982](https://github.com/angular/angular/commit/5a84982))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
* **router:** update the router not to reset router state when updating root component ([#11799](https://github.com/angular/angular/issues/11799)) ([31dce72](https://github.com/angular/angular/commit/31dce72))
|
||||||
|
|
||||||
|
Note: 2.1.0-beta.0 release also contains all the changes present in the 2.0.1 release.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="2.0.2"></a>
|
<a name="2.0.2"></a>
|
||||||
## [2.0.2](https://github.com/angular/angular/compare/2.0.1...2.0.2) (2016-10-05)
|
## [2.0.2](https://github.com/angular/angular/compare/2.0.1...2.0.2) (2016-10-05)
|
||||||
|
|
||||||
@ -7,18 +167,18 @@
|
|||||||
* **common:** correctly removes styles on IE ([#11953](https://github.com/angular/angular/pull/11953)), closes [#7916](https://github.com/angular/angular/issues/7916)
|
* **common:** correctly removes styles on IE ([#11953](https://github.com/angular/angular/pull/11953)), closes [#7916](https://github.com/angular/angular/issues/7916)
|
||||||
* **compiler:** do not embed templateUrl in view factories in non-debug mode. ([#11818](https://github.com/angular/angular/issues/11818)) ([51e1994](https://github.com/angular/angular/commit/51e1994)), closes [#11117](https://github.com/angular/angular/issues/11117)
|
* **compiler:** do not embed templateUrl in view factories in non-debug mode. ([#11818](https://github.com/angular/angular/issues/11818)) ([51e1994](https://github.com/angular/angular/commit/51e1994)), closes [#11117](https://github.com/angular/angular/issues/11117)
|
||||||
* **compiler:** move detection of unsafe properties for binding to ElementSchemaRegistry ([#11378](https://github.com/angular/angular/issues/11378)) ([5911c3b](https://github.com/angular/angular/commit/5911c3b))
|
* **compiler:** move detection of unsafe properties for binding to ElementSchemaRegistry ([#11378](https://github.com/angular/angular/issues/11378)) ([5911c3b](https://github.com/angular/angular/commit/5911c3b))
|
||||||
* **forms:** properly validate empty strings with patterns ([#11450](https://github.com/angular/angular/issues/11450)) ([e00de0c](https://github.com/angular/angular/commit/e00de0c))
|
|
||||||
* **http:** preserve case of the first init, `set()` or `append()` ([#12023](https://github.com/angular/angular/issues/12023)) ([adb17fe](https://github.com/angular/angular/commit/adb17fe)), closes [#11624](https://github.com/angular/angular/issues/11624)
|
|
||||||
* **compiler-cli:** allow ReflectorHost passed as argument to CodeGenerator#create ([#11951](https://github.com/angular/angular/issues/11951)) ([826c98e](https://github.com/angular/angular/commit/826c98e))
|
|
||||||
* **router:** do not reset the router state when updating the component ([#11867](https://github.com/angular/angular/issues/11867)) ([cf750e1](https://github.com/angular/angular/commit/cf750e1))
|
|
||||||
* **compiler:** fix `:host(tag)` and `:host-context(tag)` ([a6bb84e0](https://github.com/angular/angular/commit/a6bb84e02b7579f8d957ef6ba5b10d83482ed756)), closes [#11972](https://github.com/angular/angular/issues/11972)
|
* **compiler:** fix `:host(tag)` and `:host-context(tag)` ([a6bb84e0](https://github.com/angular/angular/commit/a6bb84e02b7579f8d957ef6ba5b10d83482ed756)), closes [#11972](https://github.com/angular/angular/issues/11972)
|
||||||
* **compiler:** fix attribute selectors in :host and :host-context ([#12056](https://github.com/angular/angular/issues/12056)) ([6f7ed32](https://github.com/angular/angular/commit/6f7ed32)), closes [#11917](https://github.com/angular/angular/issues/11917)
|
* **compiler:** fix attribute selectors in :host and :host-context ([#12056](https://github.com/angular/angular/issues/12056)) ([6f7ed32](https://github.com/angular/angular/commit/6f7ed32)), closes [#11917](https://github.com/angular/angular/issues/11917)
|
||||||
* **compiler:** support `[@page](https://github.com/page)` and `[@document](https://github.com/document)` CSS rules ([#11878](https://github.com/angular/angular/issues/11878)) ([c99ef49](https://github.com/angular/angular/commit/c99ef49)), closes [#11860](https://github.com/angular/angular/issues/11860)
|
* **compiler:** support `@page` and `@document` CSS rules ([#11878](https://github.com/angular/angular/issues/11878)) ([c99ef49](https://github.com/angular/angular/commit/c99ef49)), closes [#11860](https://github.com/angular/angular/issues/11860)
|
||||||
* **compiler:** support `[attr="value with space"]` ([bd012ef](https://github.com/angular/angular/commit/bd012ef)), closes [#6249](https://github.com/angular/angular/issues/6249)
|
* **compiler:** support `[attr="value with space"]` ([bd012ef](https://github.com/angular/angular/commit/bd012ef)), closes [#6249](https://github.com/angular/angular/issues/6249)
|
||||||
* **compiler:** support quoted attribute values ([7395400](https://github.com/angular/angular/commit/7395400)), closes [#6085](https://github.com/angular/angular/issues/6085)
|
* **compiler:** support quoted attribute values ([7395400](https://github.com/angular/angular/commit/7395400)), closes [#6085](https://github.com/angular/angular/issues/6085)
|
||||||
* **upgrade:** bind optional properties when upgrading from ng1 ([#11411](https://github.com/angular/angular/issues/11411)) ([0851238](https://github.com/angular/angular/commit/0851238)), closes [#10181](https://github.com/angular/angular/issues/10181)
|
|
||||||
* **http:** change a behavior when a param value is null or undefined ([#11990](https://github.com/angular/angular/issues/11990)) ([9cc0a4e](https://github.com/angular/angular/commit/9cc0a4e))
|
|
||||||
* **compiler:** fix `<x>` ctype names ([7578d85](https://github.com/angular/angular/commit/7578d85)), closes [#12000](https://github.com/angular/angular/issues/12000)
|
* **compiler:** fix `<x>` ctype names ([7578d85](https://github.com/angular/angular/commit/7578d85)), closes [#12000](https://github.com/angular/angular/issues/12000)
|
||||||
|
* **compiler-cli:** allow ReflectorHost passed as argument to CodeGenerator#create ([#11951](https://github.com/angular/angular/issues/11951)) ([826c98e](https://github.com/angular/angular/commit/826c98e))
|
||||||
|
* **forms:** properly validate empty strings with patterns ([#11450](https://github.com/angular/angular/issues/11450)) ([e00de0c](https://github.com/angular/angular/commit/e00de0c))
|
||||||
|
* **http:** preserve case of the first init, `set()` or `append()` ([#12023](https://github.com/angular/angular/issues/12023)) ([adb17fe](https://github.com/angular/angular/commit/adb17fe)), closes [#11624](https://github.com/angular/angular/issues/11624)
|
||||||
|
* **http:** remove url params if provided value is null or undefined ([#11990](https://github.com/angular/angular/issues/11990)) ([9cc0a4e](https://github.com/angular/angular/commit/9cc0a4e))
|
||||||
|
* **router:** do not reset the router state when updating the component ([#11867](https://github.com/angular/angular/issues/11867)) ([cf750e1](https://github.com/angular/angular/commit/cf750e1))
|
||||||
|
* **upgrade:** bind optional properties when upgrading from ng1 ([#11411](https://github.com/angular/angular/issues/11411)) ([0851238](https://github.com/angular/angular/commit/0851238)), closes [#10181](https://github.com/angular/angular/issues/10181)
|
||||||
|
|
||||||
|
|
||||||
<a name="2.0.1"></a>
|
<a name="2.0.1"></a>
|
||||||
@ -41,7 +201,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<a name="2.0.0"></a>
|
<a name="2.0.0"></a>
|
||||||
# [2.0.0](https://github.com/angular/angular/compare/2.0.0-rc.7...2.0.0) (2016-09-14)
|
# [2.0.0 proprioception-reinforcement](https://github.com/angular/angular/compare/2.0.0-rc.7...2.0.0) (2016-09-14)
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# Contributing to Angular 2
|
# Contributing to Angular
|
||||||
|
|
||||||
We would love for you to contribute to Angular 2 and help make it even better than it is
|
We would love for you to contribute to Angular and help make it even better than it is
|
||||||
today! As a contributor, here are the guidelines we would like you to follow:
|
today! As a contributor, here are the guidelines we would like you to follow:
|
||||||
|
|
||||||
- [Code of Conduct](#coc)
|
- [Code of Conduct](#coc)
|
||||||
@ -17,17 +17,26 @@ Help us keep Angular open and inclusive. Please read and follow our [Code of Con
|
|||||||
|
|
||||||
## <a name="question"></a> Got a Question or Problem?
|
## <a name="question"></a> Got a Question or Problem?
|
||||||
|
|
||||||
If you have questions about how to *use* Angular, please direct them to the [Google Group][angular-group]
|
Please, do not open issues for the general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [StackOverflow](stackoverflow.com/questions/tagged/angular) where the questions should be tagged with tag `angular`.
|
||||||
discussion list or [StackOverflow][stackoverflow]. Please note that the Angular team's capacity to answer usage questions is limited. We are also available on [Gitter][gitter].
|
|
||||||
|
|
||||||
## <a name="issue"></a> Found an Issue?
|
StackOverflow is a much better place to ask questions since:
|
||||||
|
|
||||||
|
- there are thousands of people willing to help on StackOverflow
|
||||||
|
- questions and answers stay available for public viewing so your question / answer might help someone else
|
||||||
|
- StackOverflow's voting system assures that the best answers are prominently visible.
|
||||||
|
|
||||||
|
To save your and our time we will be systematically closing all the issues that are requests for general support and redirecting people to StackOverflow.
|
||||||
|
|
||||||
|
If you would like to chat about the question in real-time, you can reach out via [our gitter channel][gitter].
|
||||||
|
|
||||||
|
## <a name="issue"></a> Found a Bug?
|
||||||
If you find a bug in the source code, you can help us by
|
If you find a bug in the source code, you can help us by
|
||||||
[submitting an issue](#submit-issue) to our [GitHub Repository][github]. Even better, you can
|
[submitting an issue](#submit-issue) to our [GitHub Repository][github]. Even better, you can
|
||||||
[submit a Pull Request](#submit-pr) with a fix.
|
[submit a Pull Request](#submit-pr) with a fix.
|
||||||
|
|
||||||
## <a name="feature"></a> Want a Feature?
|
## <a name="feature"></a> Missing a Feature?
|
||||||
You can *request* a new feature by [submitting an issue](#submit-issue) to our [GitHub
|
You can *request* a new feature by [submitting an issue](#submit-issue) to our GitHub
|
||||||
Repository][github]. If you would like to *implement* a new feature, please submit an issue with
|
Repository. If you would like to *implement* a new feature, please submit an issue with
|
||||||
a proposal for your work first, to be sure that we can use it.
|
a proposal for your work first, to be sure that we can use it.
|
||||||
Please consider what kind of change it is:
|
Please consider what kind of change it is:
|
||||||
|
|
||||||
@ -39,24 +48,22 @@ and help you to craft the change so that it is successfully accepted into the pr
|
|||||||
## <a name="submit"></a> Submission Guidelines
|
## <a name="submit"></a> Submission Guidelines
|
||||||
|
|
||||||
### <a name="submit-issue"></a> Submitting an Issue
|
### <a name="submit-issue"></a> Submitting an Issue
|
||||||
Before you submit an issue, search the archive, maybe your question was already answered.
|
|
||||||
|
|
||||||
If your issue appears to be a bug, and hasn't been reported, open a new issue.
|
Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available.
|
||||||
Help us to maximize the effort we can spend fixing issues and adding new
|
|
||||||
features, by not reporting duplicate issues. Providing the following information will increase the
|
|
||||||
chances of your issue being dealt with quickly:
|
|
||||||
|
|
||||||
* **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
|
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will systematically ask you to provide a minimal reproduction scenario using http://plnkr.co. Having a live, reproducible scenario gives us wealth of important information without going back & forth to you with additional questions like:
|
||||||
* **Angular Version** - what version of Angular is affected (e.g. 2.0.0-alpha.53)
|
|
||||||
* **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you
|
|
||||||
* **Browsers and Operating System** - is this a problem with all browsers?
|
|
||||||
* **Reproduce the Error** - provide a live example (using [Plunker][plunker],
|
|
||||||
[JSFiddle][jsfiddle] or [Runnable][runnable]) or a unambiguous set of steps
|
|
||||||
* **Related Issues** - has a similar issue been reported before?
|
|
||||||
* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
|
|
||||||
causing the problem (line of code or commit)
|
|
||||||
|
|
||||||
You can file new issues by providing the above information [here](https://github.com/angular/angular/issues/new).
|
- version of Angular used
|
||||||
|
- 3rd-party libraries and their versions
|
||||||
|
- and most importantly - a use-case that fails
|
||||||
|
|
||||||
|
A minimal reproduce scenario using http://plnkr.co/ allows us to quickly confirm a bug (or point out coding problem) as well as confirm that we are fixing the right problem. If plunker is not a suitable way to demostrate the problem (for example for issues related to our npm packaging), please create a standalone git repository demostrating the problem.
|
||||||
|
|
||||||
|
We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal plunk. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it.
|
||||||
|
|
||||||
|
Unfortunately we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that don't have enough info to be reproduced.
|
||||||
|
|
||||||
|
You can file new issues by filling out our [new issue form](https://github.com/angular/angular/issues/new).
|
||||||
|
|
||||||
|
|
||||||
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
|
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
|
||||||
@ -94,7 +101,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
|||||||
* 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 2 test suites to ensure tests are still passing.
|
* Re-run the Angular test suites to ensure tests are still passing.
|
||||||
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
62
SAVED_REPLIES.md
Normal file
62
SAVED_REPLIES.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# Saved Responses for Angular's Issue Tracker
|
||||||
|
|
||||||
|
The following are canned responses that the Angular team should use to close issues on our issue tracker that fall into the listed resolution categories.
|
||||||
|
|
||||||
|
Since GitHub currently doesn't allow us to have a repository-wide or organization-wide list of [saved replies](https://help.github.com/articles/working-with-saved-replies/), these replies need to be maintained by individual team members. Since the responses can be modified in the future, all responses are versioned to simplify the process of keeping the responses up to date.
|
||||||
|
|
||||||
|
|
||||||
|
## Angular: Already Fixed (v1)
|
||||||
|
```
|
||||||
|
Thanks for reporting this issue. Luckily it has already been fixed in one of the recent releases. Please update to the most recent version to resolve the problem.
|
||||||
|
|
||||||
|
If after upgrade the problem still exists in your application please open a new issue and provide a plunker reproducing the problem and describing the difference between the expected and current behavior. You can use this plunker template: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5?p=catalogue
|
||||||
|
```
|
||||||
|
|
||||||
|
## Angular: Don't Understand (v1)
|
||||||
|
```
|
||||||
|
I'm sorry but we don't understand the problem you are reporting.
|
||||||
|
|
||||||
|
If the problem still exists please open a new issue and provide a plunker reproducing the problem and describing the difference between the expected and current behavior. You can use this plunker template: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5?p=catalogue
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Angular: Duplicate (v1)
|
||||||
|
```
|
||||||
|
Thanks for reporting this issue. However this issue is a duplicate of an existing issue #<ISSUE_NUMBER>. Please subscribe to that issue for future updates.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Angular: Insufficient Information Provided (v1)
|
||||||
|
```
|
||||||
|
Thanks for reporting this issue. However, you didn't provide sufficient information for us to understand and reproduce the problem. Please check out [our submission guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-submitting-an-issue) to understand why we can't act on issues that are lacking important information.
|
||||||
|
|
||||||
|
If the problem still persists, please file a new issue and ensure you provide all of the required information when filling out the issue template.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Angular: Issue Outside of Angular (v1)
|
||||||
|
```
|
||||||
|
I'm sorry but this issue is not caused by Angular. Please contact the author(s) of project <PROJECT NAME> or file issue on their issue tracker.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Angular: Non-reproducible (v1)
|
||||||
|
```
|
||||||
|
I'm sorry but we can't reproduce the problem following the instructions you provided.
|
||||||
|
|
||||||
|
If the problem still exists please open a new issue following [our submission guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-submitting-an-issue).
|
||||||
|
```
|
||||||
|
|
||||||
|
## Angular: Obsolete (v1)
|
||||||
|
```
|
||||||
|
Thanks for reporting this issue. This issue is now obsolete due to changes in the recent releases. Please update to the most recent Angular version.
|
||||||
|
|
||||||
|
If the problem still persists, please file a new issue and ensure you provide the version of Angular affected and include the steps to reproduce the problem when filling out the issue template.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Angular: Support Request (v1)
|
||||||
|
```
|
||||||
|
Hello, we reviewed this issue and determined that it doesn't fall into the bug report or feature request category. This issue tracker is not suitable for support requests, please repost your issue on [StackOverflow](http://stackoverflow.com/) using tag `angular`.
|
||||||
|
|
||||||
|
If you are wondering why we don't resolve support issues via the issue tracker, please [check out this explanation](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-got-a-question-or-problem).
|
||||||
|
```
|
@ -1,7 +1,7 @@
|
|||||||
# Triage Process and Github Labels for Angular 2
|
# Triage Process and Github Labels for Angular 2
|
||||||
|
|
||||||
This document describes how the Angular team uses labels and milestones
|
This document describes how the Angular team uses labels and milestones
|
||||||
to triage issues on github. The basic idea of the new process is that
|
to triage issues on github. The basic idea of the process is that
|
||||||
caretaker only assigns a component and type (bug, feature) label. The
|
caretaker only assigns a component and type (bug, feature) label. The
|
||||||
owner of the component than is in full control of how the issues should
|
owner of the component than is in full control of how the issues should
|
||||||
be triaged further.
|
be triaged further.
|
||||||
@ -35,7 +35,7 @@ There are few components which are cross-cutting. They don't have
|
|||||||
a clear location in the source tree. We will treat them as a component
|
a clear location in the source tree. We will treat them as a component
|
||||||
even thought no specific source tree is associated with them.
|
even thought no specific source tree is associated with them.
|
||||||
|
|
||||||
* `comp: documentation`: `@naomiblack`
|
* `comp: docs`: `@naomiblack`
|
||||||
* `comp: packaging`: `@IgorMinar`
|
* `comp: packaging`: `@IgorMinar`
|
||||||
* `comp: performance`: `@tbosch`
|
* `comp: performance`: `@tbosch`
|
||||||
* `comp: security`: `@IgorMinar`
|
* `comp: security`: `@IgorMinar`
|
||||||
@ -53,11 +53,11 @@ What kind of problem is this?
|
|||||||
|
|
||||||
## Caretaker Triage Process
|
## Caretaker Triage Process
|
||||||
|
|
||||||
It is the caretaker's responsibility to assign `comp: *` and `type: *`
|
It is the caretaker's responsibility to assign `comp: *` to each new
|
||||||
to each new issue as they come in. The reason why we limit the
|
issue as they come in. The reason why we limit the responsibility of the
|
||||||
responsibility of the caretaker to these two labels is that it is
|
caretaker to this one label is that it is likely that without domain
|
||||||
unlikely that without domain knowledge the caretaker could add any
|
knowledge the caretaker could mislabel issues or lack knowledge of
|
||||||
additional labels of value.
|
duplicate issues.
|
||||||
|
|
||||||
|
|
||||||
## Component's owner Triage Process
|
## Component's owner Triage Process
|
||||||
@ -68,11 +68,37 @@ process for their component.
|
|||||||
It will be up to the component owner to determine the order in which the
|
It will be up to the component owner to determine the order in which the
|
||||||
issues within the component will be resolved.
|
issues within the component will be resolved.
|
||||||
|
|
||||||
|
Several owners have adopted the issue categorization based on
|
||||||
|
[user pain](http://www.lostgarden.com/2008/05/improving-bug-triage-with-user-pain.html)
|
||||||
|
used by Angular 1. In this system every issue is assigned frequency and
|
||||||
|
severity based on which the total user pain score is calculated.
|
||||||
|
|
||||||
|
Following is the definition of various frequency and severity levels:
|
||||||
|
|
||||||
|
1. `freq(score): *` – How often does this issue come up? How many developers does this affect?
|
||||||
|
* low (1) - obscure issue affecting a handful of developers
|
||||||
|
* moderate (2) - impacts auxiliary usage patterns, only small number of applications are affected
|
||||||
|
* high (3) - impacts primary usage patterns, affecting most Angular apps
|
||||||
|
* critical (4) - impacts all Angular apps
|
||||||
|
1. `severity(score): *` - How bad is the issue?
|
||||||
|
* inconvenience (1) - causes ugly/boilerplate code in apps
|
||||||
|
* confusing (2) - unexpected or inconsistent behavior; hard-to-debug
|
||||||
|
* broken expected use (3) - it's hard or impossible for a developer using Angular to accomplish something that Angular should be able to do
|
||||||
|
* memory leak (4)
|
||||||
|
* regression (5) - functionality that used to work no longer works in a new release due to an unintentional change
|
||||||
|
* security issue (6)
|
||||||
|
|
||||||
|
|
||||||
|
These criteria are then used to calculate a "user pain" score as follows:
|
||||||
|
|
||||||
|
`pain = severity × frequency`
|
||||||
|
|
||||||
|
|
||||||
### Assigning Issues to Milestones
|
### Assigning Issues to Milestones
|
||||||
|
|
||||||
Any issue that is being worked on must have:
|
Any issue that is being worked on must have:
|
||||||
|
|
||||||
* An `assignee`: The person doing the work.
|
* An `Assignee`: The person doing the work.
|
||||||
* A `Milestone`: When we expect to complete this work.
|
* A `Milestone`: When we expect to complete this work.
|
||||||
|
|
||||||
We aim to only have at most three milestones open at a time:
|
We aim to only have at most three milestones open at a time:
|
||||||
|
15
build.sh
15
build.sh
@ -67,6 +67,7 @@ if [[ ${BUILD_ALL} == true ]]; then
|
|||||||
ln -s ../../../../node_modules/reflect-metadata/Reflect.js .
|
ln -s ../../../../node_modules/reflect-metadata/Reflect.js .
|
||||||
ln -s ../../../../node_modules/rxjs .
|
ln -s ../../../../node_modules/rxjs .
|
||||||
ln -s ../../../../node_modules/angular/angular.js .
|
ln -s ../../../../node_modules/angular/angular.js .
|
||||||
|
ln -s ../../../../node_modules/hammerjs/hammer.js .
|
||||||
cd -
|
cd -
|
||||||
|
|
||||||
echo "====== Copying files needed for benchmarks ====="
|
echo "====== Copying files needed for benchmarks ====="
|
||||||
@ -101,7 +102,9 @@ do
|
|||||||
DESTDIR=${PWD}/dist/packages-dist/${PACKAGE}
|
DESTDIR=${PWD}/dist/packages-dist/${PACKAGE}
|
||||||
UMD_ES5_PATH=${DESTDIR}/bundles/${PACKAGE}.umd.js
|
UMD_ES5_PATH=${DESTDIR}/bundles/${PACKAGE}.umd.js
|
||||||
UMD_TESTING_ES5_PATH=${DESTDIR}/bundles/${PACKAGE}-testing.umd.js
|
UMD_TESTING_ES5_PATH=${DESTDIR}/bundles/${PACKAGE}-testing.umd.js
|
||||||
|
UMD_STATIC_ES5_PATH=${DESTDIR}/bundles/${PACKAGE}-static.umd.js
|
||||||
UMD_ES5_MIN_PATH=${DESTDIR}/bundles/${PACKAGE}.umd.min.js
|
UMD_ES5_MIN_PATH=${DESTDIR}/bundles/${PACKAGE}.umd.min.js
|
||||||
|
UMD_STATIC_ES5_MIN_PATH=${DESTDIR}/bundles/${PACKAGE}-static.umd.min.js
|
||||||
LICENSE_BANNER=${PWD}/modules/@angular/license-banner.txt
|
LICENSE_BANNER=${PWD}/modules/@angular/license-banner.txt
|
||||||
|
|
||||||
rm -rf ${DESTDIR}
|
rm -rf ${DESTDIR}
|
||||||
@ -157,6 +160,18 @@ do
|
|||||||
cat ${UMD_TESTING_ES5_PATH} >> ${UMD_TESTING_ES5_PATH}.tmp
|
cat ${UMD_TESTING_ES5_PATH} >> ${UMD_TESTING_ES5_PATH}.tmp
|
||||||
mv ${UMD_TESTING_ES5_PATH}.tmp ${UMD_TESTING_ES5_PATH}
|
mv ${UMD_TESTING_ES5_PATH}.tmp ${UMD_TESTING_ES5_PATH}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ -e rollup-static.config.js ]]; then
|
||||||
|
echo "====== Rollup ${PACKAGE} static"
|
||||||
|
../../../node_modules/.bin/rollup -c rollup-static.config.js
|
||||||
|
# create dir because it doesn't exist yet, we should move the src code here and remove this line
|
||||||
|
mkdir ${DESTDIR}/static
|
||||||
|
echo "{\"main\": \"../bundles/${PACKAGE}-static.umd.js\"}" > ${DESTDIR}/static/package.json
|
||||||
|
cat ${LICENSE_BANNER} > ${UMD_STATIC_ES5_PATH}.tmp
|
||||||
|
cat ${UMD_STATIC_ES5_PATH} >> ${UMD_STATIC_ES5_PATH}.tmp
|
||||||
|
mv ${UMD_STATIC_ES5_PATH}.tmp ${UMD_STATIC_ES5_PATH}
|
||||||
|
$UGLIFYJS -c --screw-ie8 --comments -o ${UMD_STATIC_ES5_MIN_PATH} ${UMD_STATIC_ES5_PATH}
|
||||||
|
fi
|
||||||
) 2>&1 | grep -v "as external dependency"
|
) 2>&1 | grep -v "as external dependency"
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
40
docs/PUBLIC_API.md
Normal file
40
docs/PUBLIC_API.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Supported Public API Surface of Angular
|
||||||
|
|
||||||
|
Our SemVer, timed-release cycle and deprecation policy currently applies to these npm packages:
|
||||||
|
|
||||||
|
- `@angular/core`
|
||||||
|
- `@angular/common`
|
||||||
|
- `@angular/platform-browser`
|
||||||
|
- `@angular/platform-browser-dynamic`
|
||||||
|
- `@angular/platform-server`
|
||||||
|
- `@angular/platform-webworker`
|
||||||
|
- `@angular/platform-webworker-dynamic`
|
||||||
|
- `@angular/upgrade`
|
||||||
|
- `@angular/router`
|
||||||
|
- `@angular/forms`
|
||||||
|
- `@angular/http`
|
||||||
|
|
||||||
|
|
||||||
|
One intentional omission from this list is `@angular/compiler`, which is currently considered a low level api and is subject to internal changes. These changes will not affect any applications or libraries using the higher-level apis (the command line interface or JIT compilation via `@angular/platform-browser-dynamic`). Only very specific use-cases require direct access to the compiler API (mostly tooling integration for IDEs, linters, etc). If you are working on this kind of integration, please reach out to us first.
|
||||||
|
|
||||||
|
Additionally only the command line usage (not direct use of APIs) of `@angular/compiler-cli` is covered.
|
||||||
|
|
||||||
|
Other projects developed by the Angular team like angular-cli, Angular Material, benchpress, will be covered by these or similar guarantees in the future as they mature.
|
||||||
|
|
||||||
|
Within the supported packages, we provide guarantees for:
|
||||||
|
|
||||||
|
- symbols exported via the main entry point (e.g. `@angular/core`) and testing entry point (e.g. `@angular/core/testing`). This applies to both runtime/JavaScript values and TypeScript types.
|
||||||
|
- symbols exported via global namespace `ng` (e.g. `ng.core`)
|
||||||
|
- bundles located in the `bundles/` directory of our npm packages (e.g. `@angular/core/bundles/core.umd.js`)
|
||||||
|
|
||||||
|
|
||||||
|
We explicitly don't consider the following to be our public API surface:
|
||||||
|
|
||||||
|
- any file/import paths within our package except for the `/`, `/testing` and `/bundles/*`
|
||||||
|
- constructors of injectable classes (services and directives) - please use DI to obtain instances of these classes
|
||||||
|
- any class members or symbols marked as `private` or prefixed with underscore
|
||||||
|
- extending any of our classes unless the support for this is specifically documented in the API docs
|
||||||
|
- the contents and API surface of the code generated by Angular's compiler (with one notable exception: the existence and name of `NgModuleFactory` instances exported from generated code is guaranteed)
|
||||||
|
|
||||||
|
|
||||||
|
Our peer dependencies (e.g. typescript, zone.js, or rxjs) are not considered part of our API surface, but they are included in our SemVer policies. We might update the required version of any of these dependencies in minor releases if the update doesn't cause breaking changes for Angular applications. Peer dependency updates that result in non-trivial breaking changes must be deferred to major Angular releases.
|
32
gulpfile.js
32
gulpfile.js
@ -58,6 +58,7 @@ const entrypoints = [
|
|||||||
//'dist/packages-dist/compiler/index.d.ts',
|
//'dist/packages-dist/compiler/index.d.ts',
|
||||||
//'dist/packages-dist/compiler/testing.d.ts',
|
//'dist/packages-dist/compiler/testing.d.ts',
|
||||||
'dist/packages-dist/upgrade/index.d.ts',
|
'dist/packages-dist/upgrade/index.d.ts',
|
||||||
|
'dist/packages-dist/upgrade/static.d.ts',
|
||||||
'dist/packages-dist/platform-browser/index.d.ts',
|
'dist/packages-dist/platform-browser/index.d.ts',
|
||||||
'dist/packages-dist/platform-browser/testing/index.d.ts',
|
'dist/packages-dist/platform-browser/testing/index.d.ts',
|
||||||
'dist/packages-dist/platform-browser-dynamic/index.d.ts',
|
'dist/packages-dist/platform-browser-dynamic/index.d.ts',
|
||||||
@ -124,38 +125,31 @@ gulp.task('public-api:update', ['build.sh'], (done) => {
|
|||||||
.on('close', done);
|
.on('close', done);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Checks tests for presence of ddescribe, fdescribe, fit, iit and fails the build if one of the
|
|
||||||
// focused tests is found.
|
|
||||||
// Currently xdescribe and xit are _not_ reported as errors since there are a couple of excluded
|
|
||||||
// tests in our code base.
|
|
||||||
gulp.task('check-tests', function() {
|
|
||||||
const ddescribeIit = require('gulp-ddescribe-iit');
|
|
||||||
return gulp
|
|
||||||
.src([
|
|
||||||
'modules/**/*.spec.ts',
|
|
||||||
'modules/**/*_spec.ts',
|
|
||||||
])
|
|
||||||
.pipe(ddescribeIit({allowDisabledTests: true}));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check the coding standards and programming errors
|
// Check the coding standards and programming errors
|
||||||
gulp.task('lint', ['check-tests', 'format:enforce', 'tools:build'], () => {
|
gulp.task('lint', ['format:enforce', 'tools:build'], () => {
|
||||||
const tslint = require('gulp-tslint');
|
const tslint = require('gulp-tslint');
|
||||||
// Built-in rules are at
|
// Built-in rules are at
|
||||||
// https://github.com/palantir/tslint#supported-rules
|
// https://palantir.github.io/tslint/rules/
|
||||||
const tslintConfig = require('./tslint.json');
|
const tslintConfig = require('./tslint.json');
|
||||||
return gulp
|
return gulp
|
||||||
.src([
|
.src([
|
||||||
// todo(vicb): add .js files when supported
|
// todo(vicb): add .js files when supported
|
||||||
// see https://github.com/palantir/tslint/pull/1515
|
// see https://github.com/palantir/tslint/pull/1515
|
||||||
'modules/@angular/**/*.ts',
|
'./modules/**/*.ts',
|
||||||
'modules/benchpress/**/*.ts',
|
'./tools/**/*.ts',
|
||||||
'./*.ts',
|
'./*.ts',
|
||||||
|
|
||||||
|
// Ignore TypeScript mocks because it's not managed by us
|
||||||
|
'!./tools/@angular/tsc-wrapped/test/typescript.mocks.ts',
|
||||||
|
|
||||||
|
// Ignore generated files due to lack of copyright header
|
||||||
|
// todo(alfaproject): make generated files lintable
|
||||||
|
'!**/*.d.ts',
|
||||||
|
'!**/*.ngfactory.ts',
|
||||||
])
|
])
|
||||||
.pipe(tslint({
|
.pipe(tslint({
|
||||||
tslint: require('tslint').default,
|
tslint: require('tslint').default,
|
||||||
configuration: tslintConfig,
|
configuration: tslintConfig,
|
||||||
rulesDirectory: 'dist/tools/tslint',
|
|
||||||
formatter: 'prose',
|
formatter: 'prose',
|
||||||
}))
|
}))
|
||||||
.pipe(tslint.report({emitError: true}));
|
.pipe(tslint.report({emitError: true}));
|
||||||
|
@ -23,7 +23,7 @@ module.exports = function(config) {
|
|||||||
|
|
||||||
'node_modules/core-js/client/core.js',
|
'node_modules/core-js/client/core.js',
|
||||||
// include Angular v1 for upgrade module testing
|
// include Angular v1 for upgrade module testing
|
||||||
'node_modules/angular/angular.min.js',
|
'node_modules/angular/angular.js',
|
||||||
|
|
||||||
'node_modules/zone.js/dist/zone.js', 'node_modules/zone.js/dist/long-stack-trace-zone.js',
|
'node_modules/zone.js/dist/zone.js', 'node_modules/zone.js/dist/long-stack-trace-zone.js',
|
||||||
'node_modules/zone.js/dist/proxy.js', 'node_modules/zone.js/dist/sync-test.js',
|
'node_modules/zone.js/dist/proxy.js', 'node_modules/zone.js/dist/sync-test.js',
|
||||||
|
@ -5,7 +5,7 @@ See [here for an example project](https://github.com/angular/benchpress-tree).
|
|||||||
|
|
||||||
The sources for this package are in the main [Angular2](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo.
|
The sources for this package are in the main [Angular2](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo.
|
||||||
|
|
||||||
License: Apache MIT 2.0
|
License: MIT
|
||||||
|
|
||||||
# Why?
|
# Why?
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
import {Inject, Injectable} from '@angular/core';
|
import {Inject, Injectable} from '@angular/core';
|
||||||
|
|
||||||
import {Options} from '../common_options';
|
import {Options} from '../common_options';
|
||||||
import {isNumber} from '../facade/lang';
|
|
||||||
import {Metric} from '../metric';
|
import {Metric} from '../metric';
|
||||||
import {WebDriverAdapter} from '../web_driver_adapter';
|
import {WebDriverAdapter} from '../web_driver_adapter';
|
||||||
|
|
||||||
@ -44,7 +43,7 @@ export class UserMetric extends Metric {
|
|||||||
function getAndClearValues() {
|
function getAndClearValues() {
|
||||||
Promise.all(names.map(name => adapter.executeScript(`return window.${name}`)))
|
Promise.all(names.map(name => adapter.executeScript(`return window.${name}`)))
|
||||||
.then((values: any[]) => {
|
.then((values: any[]) => {
|
||||||
if (values.every(isNumber)) {
|
if (values.every(v => typeof v === 'number')) {
|
||||||
Promise.all(names.map(name => adapter.executeScript(`delete window.${name}`)))
|
Promise.all(names.map(name => adapter.executeScript(`delete window.${name}`)))
|
||||||
.then((_: any[]) => {
|
.then((_: any[]) => {
|
||||||
let map: {[k: string]: any} = {};
|
let map: {[k: string]: any} = {};
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
import {Inject, Injectable, OpaqueToken} from '@angular/core';
|
import {Inject, Injectable, OpaqueToken} from '@angular/core';
|
||||||
|
|
||||||
import {Options} from '../common_options';
|
import {Options} from '../common_options';
|
||||||
import {Json} from '../facade/lang';
|
|
||||||
import {MeasureValues} from '../measure_values';
|
import {MeasureValues} from '../measure_values';
|
||||||
import {Reporter} from '../reporter';
|
import {Reporter} from '../reporter';
|
||||||
import {SampleDescription} from '../sample_description';
|
import {SampleDescription} from '../sample_description';
|
||||||
@ -39,12 +38,14 @@ export class JsonFileReporter extends Reporter {
|
|||||||
sortedProps(this._description.metrics).forEach((metricName) => {
|
sortedProps(this._description.metrics).forEach((metricName) => {
|
||||||
stats[metricName] = formatStats(validSample, metricName);
|
stats[metricName] = formatStats(validSample, metricName);
|
||||||
});
|
});
|
||||||
var content = Json.stringify({
|
var content = JSON.stringify(
|
||||||
|
{
|
||||||
'description': this._description,
|
'description': this._description,
|
||||||
'stats': stats,
|
'stats': stats,
|
||||||
'completeSample': completeSample,
|
'completeSample': completeSample,
|
||||||
'validSample': validSample,
|
'validSample': validSample,
|
||||||
});
|
},
|
||||||
|
null, 2);
|
||||||
var filePath = `${this._path}/${this._description.id}_${this._now().getTime()}.json`;
|
var filePath = `${this._path}/${this._description.id}_${this._now().getTime()}.json`;
|
||||||
return this._writeFile(filePath, content);
|
return this._writeFile(filePath, content);
|
||||||
}
|
}
|
||||||
|
@ -6,20 +6,15 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import {NumberWrapper} from '../facade/lang';
|
|
||||||
import {MeasureValues} from '../measure_values';
|
import {MeasureValues} from '../measure_values';
|
||||||
import {Statistic} from '../statistic';
|
import {Statistic} from '../statistic';
|
||||||
|
|
||||||
export function formatNum(n: number) {
|
export function formatNum(n: number) {
|
||||||
return NumberWrapper.toFixed(n, 2);
|
return n.toFixed(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sortedProps(obj: {[key: string]: any}) {
|
export function sortedProps(obj: {[key: string]: any}) {
|
||||||
var props: string[] = [];
|
return Object.keys(obj).sort();
|
||||||
props.push(...Object.keys(obj));
|
|
||||||
props.sort();
|
|
||||||
return props;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatStats(validSamples: MeasureValues[], metricName: string): string {
|
export function formatStats(validSamples: MeasureValues[], metricName: string): string {
|
||||||
@ -29,5 +24,5 @@ export function formatStats(validSamples: MeasureValues[], metricName: string):
|
|||||||
var formattedMean = formatNum(mean);
|
var formattedMean = formatNum(mean);
|
||||||
// Note: Don't use the unicode character for +- as it might cause
|
// Note: Don't use the unicode character for +- as it might cause
|
||||||
// hickups for consoles...
|
// hickups for consoles...
|
||||||
return NumberWrapper.isNaN(cv) ? formattedMean : `${formattedMean}+-${Math.floor(cv)}%`;
|
return isNaN(cv) ? formattedMean : `${formattedMean}+-${Math.floor(cv)}%`;
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Math} from './facade/math';
|
|
||||||
|
|
||||||
export class Statistic {
|
export class Statistic {
|
||||||
static calculateCoefficientOfVariation(sample: number[], mean: number) {
|
static calculateCoefficientOfVariation(sample: number[], mean: number) {
|
||||||
return Statistic.calculateStandardDeviation(sample, mean) / mean * 100;
|
return Statistic.calculateStandardDeviation(sample, mean) / mean * 100;
|
||||||
|
@ -8,13 +8,10 @@
|
|||||||
|
|
||||||
import {Inject, Injectable, OpaqueToken} from '@angular/core';
|
import {Inject, Injectable, OpaqueToken} from '@angular/core';
|
||||||
|
|
||||||
import {ListWrapper} from '../facade/collection';
|
|
||||||
import {MeasureValues} from '../measure_values';
|
import {MeasureValues} from '../measure_values';
|
||||||
import {Statistic} from '../statistic';
|
import {Statistic} from '../statistic';
|
||||||
import {Validator} from '../validator';
|
import {Validator} from '../validator';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A validator that checks the regression slope of a specific metric.
|
* A validator that checks the regression slope of a specific metric.
|
||||||
* Waits for the regression slope to be >=0.
|
* Waits for the regression slope to be >=0.
|
||||||
@ -40,17 +37,17 @@ export class RegressionSlopeValidator extends Validator {
|
|||||||
|
|
||||||
validate(completeSample: MeasureValues[]): MeasureValues[] {
|
validate(completeSample: MeasureValues[]): MeasureValues[] {
|
||||||
if (completeSample.length >= this._sampleSize) {
|
if (completeSample.length >= this._sampleSize) {
|
||||||
var latestSample = ListWrapper.slice(
|
const latestSample =
|
||||||
completeSample, completeSample.length - this._sampleSize, completeSample.length);
|
completeSample.slice(completeSample.length - this._sampleSize, completeSample.length);
|
||||||
var xValues: number[] = [];
|
const xValues: number[] = [];
|
||||||
var yValues: number[] = [];
|
const yValues: number[] = [];
|
||||||
for (var i = 0; i < latestSample.length; i++) {
|
for (let i = 0; i < latestSample.length; i++) {
|
||||||
// For now, we only use the array index as x value.
|
// For now, we only use the array index as x value.
|
||||||
// TODO(tbosch): think about whether we should use time here instead
|
// TODO(tbosch): think about whether we should use time here instead
|
||||||
xValues.push(i);
|
xValues.push(i);
|
||||||
yValues.push(latestSample[i].values[this._metric]);
|
yValues.push(latestSample[i].values[this._metric]);
|
||||||
}
|
}
|
||||||
var regressionSlope = Statistic.calculateRegressionSlope(
|
const regressionSlope = Statistic.calculateRegressionSlope(
|
||||||
xValues, Statistic.calculateMean(xValues), yValues, Statistic.calculateMean(yValues));
|
xValues, Statistic.calculateMean(xValues), yValues, Statistic.calculateMean(yValues));
|
||||||
return regressionSlope >= 0 ? latestSample : null;
|
return regressionSlope >= 0 ? latestSample : null;
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,12 +8,9 @@
|
|||||||
|
|
||||||
import {Inject, Injectable, OpaqueToken} from '@angular/core';
|
import {Inject, Injectable, OpaqueToken} from '@angular/core';
|
||||||
|
|
||||||
import {ListWrapper} from '../facade/collection';
|
|
||||||
import {MeasureValues} from '../measure_values';
|
import {MeasureValues} from '../measure_values';
|
||||||
import {Validator} from '../validator';
|
import {Validator} from '../validator';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A validator that waits for the sample to have a certain size.
|
* A validator that waits for the sample to have a certain size.
|
||||||
*/
|
*/
|
||||||
@ -28,8 +25,7 @@ export class SizeValidator extends Validator {
|
|||||||
|
|
||||||
validate(completeSample: MeasureValues[]): MeasureValues[] {
|
validate(completeSample: MeasureValues[]): MeasureValues[] {
|
||||||
if (completeSample.length >= this._sampleSize) {
|
if (completeSample.length >= this._sampleSize) {
|
||||||
return ListWrapper.slice(
|
return completeSample.slice(completeSample.length - this._sampleSize, completeSample.length);
|
||||||
completeSample, completeSample.length - this._sampleSize, completeSample.length);
|
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
|
|
||||||
import {StringWrapper, isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
import {WebDriverAdapter} from '../web_driver_adapter';
|
import {WebDriverAdapter} from '../web_driver_adapter';
|
||||||
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
|
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
|
||||||
|
|
||||||
@ -48,6 +48,6 @@ export class FirefoxDriverExtension extends WebDriverExtension {
|
|||||||
perfLogFeatures(): PerfLogFeatures { return new PerfLogFeatures({render: true, gc: true}); }
|
perfLogFeatures(): PerfLogFeatures { return new PerfLogFeatures({render: true, gc: true}); }
|
||||||
|
|
||||||
supports(capabilities: {[key: string]: any}): boolean {
|
supports(capabilities: {[key: string]: any}): boolean {
|
||||||
return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'firefox');
|
return capabilities['browserName'].toLowerCase() === 'firefox';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
|
|
||||||
import {StringWrapper, isBlank, isPresent} from '../facade/lang';
|
import {isBlank, isPresent} from '../facade/lang';
|
||||||
import {WebDriverAdapter} from '../web_driver_adapter';
|
import {WebDriverAdapter} from '../web_driver_adapter';
|
||||||
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
|
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ export class IOsDriverExtension extends WebDriverExtension {
|
|||||||
var records: any[] = [];
|
var records: any[] = [];
|
||||||
entries.forEach(entry => {
|
entries.forEach(entry => {
|
||||||
var message = JSON.parse(entry['message'])['message'];
|
var message = JSON.parse(entry['message'])['message'];
|
||||||
if (StringWrapper.equals(message['method'], 'Timeline.eventRecorded')) {
|
if (message['method'] === 'Timeline.eventRecorded') {
|
||||||
records.push(message['params']['record']);
|
records.push(message['params']['record']);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -62,19 +62,16 @@ export class IOsDriverExtension extends WebDriverExtension {
|
|||||||
var startTime = record['startTime'];
|
var startTime = record['startTime'];
|
||||||
var endTime = record['endTime'];
|
var endTime = record['endTime'];
|
||||||
|
|
||||||
if (StringWrapper.equals(type, 'FunctionCall') &&
|
if (type === 'FunctionCall' && (data == null || data['scriptName'] !== 'InjectedScript')) {
|
||||||
(isBlank(data) || !StringWrapper.equals(data['scriptName'], 'InjectedScript'))) {
|
|
||||||
events.push(createStartEvent('script', startTime));
|
events.push(createStartEvent('script', startTime));
|
||||||
endEvent = createEndEvent('script', endTime);
|
endEvent = createEndEvent('script', endTime);
|
||||||
} else if (StringWrapper.equals(type, 'Time')) {
|
} else if (type === 'Time') {
|
||||||
events.push(createMarkStartEvent(data['message'], startTime));
|
events.push(createMarkStartEvent(data['message'], startTime));
|
||||||
} else if (StringWrapper.equals(type, 'TimeEnd')) {
|
} else if (type === 'TimeEnd') {
|
||||||
events.push(createMarkEndEvent(data['message'], startTime));
|
events.push(createMarkEndEvent(data['message'], startTime));
|
||||||
} else if (
|
} else if (
|
||||||
StringWrapper.equals(type, 'RecalculateStyles') || StringWrapper.equals(type, 'Layout') ||
|
type === 'RecalculateStyles' || type === 'Layout' || type === 'UpdateLayerTree' ||
|
||||||
StringWrapper.equals(type, 'UpdateLayerTree') || StringWrapper.equals(type, 'Paint') ||
|
type === 'Paint' || type === 'Rasterize' || type === 'CompositeLayers') {
|
||||||
StringWrapper.equals(type, 'Rasterize') ||
|
|
||||||
StringWrapper.equals(type, 'CompositeLayers')) {
|
|
||||||
events.push(createStartEvent('render', startTime));
|
events.push(createStartEvent('render', startTime));
|
||||||
endEvent = createEndEvent('render', endTime);
|
endEvent = createEndEvent('render', endTime);
|
||||||
}
|
}
|
||||||
@ -92,7 +89,7 @@ export class IOsDriverExtension extends WebDriverExtension {
|
|||||||
perfLogFeatures(): PerfLogFeatures { return new PerfLogFeatures({render: true}); }
|
perfLogFeatures(): PerfLogFeatures { return new PerfLogFeatures({render: true}); }
|
||||||
|
|
||||||
supports(capabilities: {[key: string]: any}): boolean {
|
supports(capabilities: {[key: string]: any}): boolean {
|
||||||
return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'safari');
|
return capabilities['browserName'].toLowerCase() === 'safari';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ export function main() {
|
|||||||
if (!descriptions) {
|
if (!descriptions) {
|
||||||
descriptions = [];
|
descriptions = [];
|
||||||
}
|
}
|
||||||
if (isBlank(sampleId)) {
|
if (sampleId == null) {
|
||||||
sampleId = 'null';
|
sampleId = 'null';
|
||||||
}
|
}
|
||||||
var providers: Provider[] = [
|
var providers: Provider[] = [
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
|
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
|
||||||
|
|
||||||
import {JsonFileReporter, MeasureValues, Options, ReflectiveInjector, SampleDescription} from '../../index';
|
import {JsonFileReporter, MeasureValues, Options, ReflectiveInjector, SampleDescription} from '../../index';
|
||||||
import {Json, isPresent} from '../../src/facade/lang';
|
import {isPresent} from '../../src/facade/lang';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('file reporter', () => {
|
describe('file reporter', () => {
|
||||||
@ -51,7 +51,7 @@ export function main() {
|
|||||||
[mv(0, 0, {'a': 3, 'b': 6}), mv(1, 1, {'a': 5, 'b': 9})]);
|
[mv(0, 0, {'a': 3, 'b': 6}), mv(1, 1, {'a': 5, 'b': 9})]);
|
||||||
var regExp = /somePath\/someId_\d+\.json/;
|
var regExp = /somePath\/someId_\d+\.json/;
|
||||||
expect(isPresent(loggedFile['filename'].match(regExp))).toBe(true);
|
expect(isPresent(loggedFile['filename'].match(regExp))).toBe(true);
|
||||||
var parsedContent = Json.parse(loggedFile['content']);
|
var parsedContent = JSON.parse(loggedFile['content']);
|
||||||
expect(parsedContent).toEqual({
|
expect(parsedContent).toEqual({
|
||||||
'description': {
|
'description': {
|
||||||
'id': 'someId',
|
'id': 'someId',
|
||||||
|
@ -212,7 +212,7 @@ function createCountingValidator(
|
|||||||
return new MockValidator(log, (completeSample: MeasureValues[]) => {
|
return new MockValidator(log, (completeSample: MeasureValues[]) => {
|
||||||
count--;
|
count--;
|
||||||
if (count === 0) {
|
if (count === 0) {
|
||||||
return isPresent(validSample) ? validSample : completeSample;
|
return validSample || completeSample;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
import {describe, expect, it} from '@angular/core/testing/testing_internal';
|
import {describe, expect, it} from '@angular/core/testing/testing_internal';
|
||||||
|
|
||||||
import {MeasureValues, ReflectiveInjector, RegressionSlopeValidator} from '../../index';
|
import {MeasureValues, ReflectiveInjector, RegressionSlopeValidator} from '../../index';
|
||||||
import {ListWrapper} from '../../src/facade/collection';
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('regression slope validator', () => {
|
describe('regression slope validator', () => {
|
||||||
@ -44,17 +43,15 @@ export function main() {
|
|||||||
it('should return the last sampleSize runs when the regression slope is ==0', () => {
|
it('should return the last sampleSize runs when the regression slope is ==0', () => {
|
||||||
createValidator({size: 2, metric: 'script'});
|
createValidator({size: 2, metric: 'script'});
|
||||||
var sample = [mv(0, 0, {'script': 1}), mv(1, 1, {'script': 1}), mv(2, 2, {'script': 1})];
|
var sample = [mv(0, 0, {'script': 1}), mv(1, 1, {'script': 1}), mv(2, 2, {'script': 1})];
|
||||||
expect(validator.validate(ListWrapper.slice(sample, 0, 2)))
|
expect(validator.validate(sample.slice(0, 2))).toEqual(sample.slice(0, 2));
|
||||||
.toEqual(ListWrapper.slice(sample, 0, 2));
|
expect(validator.validate(sample)).toEqual(sample.slice(1, 3));
|
||||||
expect(validator.validate(sample)).toEqual(ListWrapper.slice(sample, 1, 3));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the last sampleSize runs when the regression slope is >0', () => {
|
it('should return the last sampleSize runs when the regression slope is >0', () => {
|
||||||
createValidator({size: 2, metric: 'script'});
|
createValidator({size: 2, metric: 'script'});
|
||||||
var sample = [mv(0, 0, {'script': 1}), mv(1, 1, {'script': 2}), mv(2, 2, {'script': 3})];
|
var sample = [mv(0, 0, {'script': 1}), mv(1, 1, {'script': 2}), mv(2, 2, {'script': 3})];
|
||||||
expect(validator.validate(ListWrapper.slice(sample, 0, 2)))
|
expect(validator.validate(sample.slice(0, 2))).toEqual(sample.slice(0, 2));
|
||||||
.toEqual(ListWrapper.slice(sample, 0, 2));
|
expect(validator.validate(sample)).toEqual(sample.slice(1, 3));
|
||||||
expect(validator.validate(sample)).toEqual(ListWrapper.slice(sample, 1, 3));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
import {describe, expect, it} from '@angular/core/testing/testing_internal';
|
import {describe, expect, it} from '@angular/core/testing/testing_internal';
|
||||||
|
|
||||||
import {MeasureValues, ReflectiveInjector, SizeValidator} from '../../index';
|
import {MeasureValues, ReflectiveInjector, SizeValidator} from '../../index';
|
||||||
import {ListWrapper} from '../../src/facade/collection';
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('size validator', () => {
|
describe('size validator', () => {
|
||||||
@ -37,9 +36,8 @@ export function main() {
|
|||||||
it('should return the last sampleSize runs when it has at least the given size', () => {
|
it('should return the last sampleSize runs when it has at least the given size', () => {
|
||||||
createValidator(2);
|
createValidator(2);
|
||||||
var sample = [mv(0, 0, {'a': 1}), mv(1, 1, {'b': 2}), mv(2, 2, {'c': 3})];
|
var sample = [mv(0, 0, {'a': 1}), mv(1, 1, {'b': 2}), mv(2, 2, {'c': 3})];
|
||||||
expect(validator.validate(ListWrapper.slice(sample, 0, 2)))
|
expect(validator.validate(sample.slice(0, 2))).toEqual(sample.slice(0, 2));
|
||||||
.toEqual(ListWrapper.slice(sample, 0, 2));
|
expect(validator.validate(sample)).toEqual(sample.slice(1, 3));
|
||||||
expect(validator.validate(sample)).toEqual(ListWrapper.slice(sample, 1, 3));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
|
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
|
||||||
|
|
||||||
import {Options, ReflectiveInjector, WebDriverExtension} from '../index';
|
import {Options, ReflectiveInjector, WebDriverExtension} from '../index';
|
||||||
import {StringWrapper, isPresent} from '../src/facade/lang';
|
import {isPresent} from '../src/facade/lang';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
function createExtension(ids: any[], caps: any) {
|
function createExtension(ids: any[], caps: any) {
|
||||||
@ -52,6 +52,6 @@ class MockExtension extends WebDriverExtension {
|
|||||||
constructor(public id: string) { super(); }
|
constructor(public id: string) { super(); }
|
||||||
|
|
||||||
supports(capabilities: {[key: string]: any}): boolean {
|
supports(capabilities: {[key: string]: any}): boolean {
|
||||||
return StringWrapper.equals(capabilities['browser'], this.id);
|
return capabilities['browser'] === this.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
|
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
|
||||||
|
|
||||||
import {ChromeDriverExtension, Options, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
|
import {ChromeDriverExtension, Options, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
|
||||||
import {Json, isBlank} from '../../src/facade/lang';
|
import {isBlank} from '../../src/facade/lang';
|
||||||
import {TraceEventFactory} from '../trace_event_factory';
|
import {TraceEventFactory} from '../trace_event_factory';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
@ -398,8 +398,8 @@ class MockDriverAdapter extends WebDriverAdapter {
|
|||||||
if (type === 'performance') {
|
if (type === 'performance') {
|
||||||
return Promise.resolve(this._events.map(
|
return Promise.resolve(this._events.map(
|
||||||
(event) => ({
|
(event) => ({
|
||||||
'message':
|
'message': JSON.stringify(
|
||||||
Json.stringify({'message': {'method': this._messageMethod, 'params': event}})
|
{'message': {'method': this._messageMethod, 'params': event}}, null, 2)
|
||||||
})));
|
})));
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
|
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
|
||||||
|
|
||||||
import {IOsDriverExtension, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
|
import {IOsDriverExtension, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
|
||||||
import {Json} from '../../src/facade/lang';
|
|
||||||
import {TraceEventFactory} from '../trace_event_factory';
|
import {TraceEventFactory} from '../trace_event_factory';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
@ -184,8 +183,9 @@ class MockDriverAdapter extends WebDriverAdapter {
|
|||||||
if (type === 'performance') {
|
if (type === 'performance') {
|
||||||
return Promise.resolve(this._perfRecords.map(function(record) {
|
return Promise.resolve(this._perfRecords.map(function(record) {
|
||||||
return {
|
return {
|
||||||
'message': Json.stringify(
|
'message': JSON.stringify(
|
||||||
{'message': {'method': 'Timeline.eventRecorded', 'params': {'record': record}}})
|
{'message': {'method': 'Timeline.eventRecorded', 'params': {'record': record}}}, null,
|
||||||
|
2)
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
|
@ -11,8 +11,6 @@ import {CollectionChangeRecord, Directive, DoCheck, ElementRef, Input, IterableD
|
|||||||
import {isListLikeIterable} from '../facade/collection';
|
import {isListLikeIterable} from '../facade/collection';
|
||||||
import {isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngModule CommonModule
|
* @ngModule CommonModule
|
||||||
*
|
*
|
||||||
@ -31,11 +29,11 @@ import {isPresent} from '../facade/lang';
|
|||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
*
|
*
|
||||||
* The CSS classes are updated as follow depending on the type of the expression evaluation:
|
* The CSS classes are updated as follows, depending on the type of the expression evaluation:
|
||||||
* - `string` - the CSS classes listed in a string (space delimited) are added,
|
* - `string` - the CSS classes listed in the string (space delimited) are added,
|
||||||
* - `Array` - the CSS classes (Array elements) are added,
|
* - `Array` - the CSS classes declared as Array elements are added,
|
||||||
* - `Object` - keys are CSS class names that get added when the expression given in the value
|
* - `Object` - keys are CSS classes that get added when the expression given in the value
|
||||||
* evaluates to a truthy value, otherwise class are removed.
|
* evaluates to a truthy value, otherwise they are removed.
|
||||||
*
|
*
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
@ -50,7 +48,6 @@ export class NgClass implements DoCheck {
|
|||||||
private _iterableDiffers: IterableDiffers, private _keyValueDiffers: KeyValueDiffers,
|
private _iterableDiffers: IterableDiffers, private _keyValueDiffers: KeyValueDiffers,
|
||||||
private _ngEl: ElementRef, private _renderer: Renderer) {}
|
private _ngEl: ElementRef, private _renderer: Renderer) {}
|
||||||
|
|
||||||
|
|
||||||
@Input('class')
|
@Input('class')
|
||||||
set klass(v: string) {
|
set klass(v: string) {
|
||||||
this._applyInitialClasses(true);
|
this._applyInitialClasses(true);
|
||||||
|
@ -11,14 +11,14 @@ import {Directive, Input, TemplateRef, ViewContainerRef} from '@angular/core';
|
|||||||
/**
|
/**
|
||||||
* Removes or recreates a portion of the DOM tree based on an {expression}.
|
* Removes or recreates a portion of the DOM tree based on an {expression}.
|
||||||
*
|
*
|
||||||
* If the expression assigned to `ngIf` evaluates to a false value then the element
|
* If the expression assigned to `ngIf` evaluates to a falsy value then the element
|
||||||
* is removed from the DOM, otherwise a clone of the element is reinserted into the DOM.
|
* is removed from the DOM, otherwise a clone of the element is reinserted into the DOM.
|
||||||
*
|
*
|
||||||
* ### Example ([live demo](http://plnkr.co/edit/fe0kgemFBtmQOY31b4tw?p=preview)):
|
* ### Example ([live demo](http://plnkr.co/edit/fe0kgemFBtmQOY31b4tw?p=preview)):
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* <div *ngIf="errorCount > 0" class="error">
|
* <div *ngIf="errorCount > 0" class="error">
|
||||||
* <!-- Error message displayed when the errorCount property on the current context is greater
|
* <!-- Error message displayed when the errorCount property in the current context is greater
|
||||||
* than 0. -->
|
* than 0. -->
|
||||||
* {{errorCount}} errors detected
|
* {{errorCount}} errors detected
|
||||||
* </div>
|
* </div>
|
||||||
@ -34,7 +34,7 @@ import {Directive, Input, TemplateRef, ViewContainerRef} from '@angular/core';
|
|||||||
*/
|
*/
|
||||||
@Directive({selector: '[ngIf]'})
|
@Directive({selector: '[ngIf]'})
|
||||||
export class NgIf {
|
export class NgIf {
|
||||||
private _hasView: boolean = false;
|
private _hasView = false;
|
||||||
|
|
||||||
constructor(private _viewContainer: ViewContainerRef, private _template: TemplateRef<Object>) {}
|
constructor(private _viewContainer: ViewContainerRef, private _template: TemplateRef<Object>) {}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import {Directive, Host, Input, TemplateRef, ViewContainerRef} from '@angular/co
|
|||||||
|
|
||||||
import {ListWrapper} from '../facade/collection';
|
import {ListWrapper} from '../facade/collection';
|
||||||
|
|
||||||
const _CASE_DEFAULT = new Object();
|
const _CASE_DEFAULT = {};
|
||||||
|
|
||||||
export class SwitchView {
|
export class SwitchView {
|
||||||
constructor(
|
constructor(
|
||||||
@ -38,7 +38,7 @@ export class SwitchView {
|
|||||||
* <inner-element></inner-element>
|
* <inner-element></inner-element>
|
||||||
* <inner-other-element></inner-other-element>
|
* <inner-other-element></inner-other-element>
|
||||||
* </ng-container>
|
* </ng-container>
|
||||||
* <some-element *ngSwitchDefault>...</p>
|
* <some-element *ngSwitchDefault>...</some-element>
|
||||||
* </container-element>
|
* </container-element>
|
||||||
* ```
|
* ```
|
||||||
* @description
|
* @description
|
||||||
@ -53,8 +53,7 @@ export class SwitchView {
|
|||||||
* root elements.
|
* root elements.
|
||||||
*
|
*
|
||||||
* Elements within `NgSwitch` but outside of a `NgSwitchCase` or `NgSwitchDefault` directives will
|
* Elements within `NgSwitch` but outside of a `NgSwitchCase` or `NgSwitchDefault` directives will
|
||||||
* be
|
* be preserved at the location.
|
||||||
* preserved at the location.
|
|
||||||
*
|
*
|
||||||
* The `ngSwitchCase` directive informs the parent `NgSwitch` of which view to display when the
|
* The `ngSwitchCase` directive informs the parent `NgSwitch` of which view to display when the
|
||||||
* expression is evaluated.
|
* expression is evaluated.
|
||||||
@ -72,18 +71,23 @@ export class NgSwitch {
|
|||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set ngSwitch(value: any) {
|
set ngSwitch(value: any) {
|
||||||
// Empty the currently active ViewContainers
|
// Set of views to display for this value
|
||||||
this._emptyAllActiveViews();
|
|
||||||
|
|
||||||
// Add the ViewContainers matching the value (with a fallback to default)
|
|
||||||
this._useDefault = false;
|
|
||||||
let views = this._valueViews.get(value);
|
let views = this._valueViews.get(value);
|
||||||
if (!views) {
|
|
||||||
this._useDefault = true;
|
|
||||||
views = this._valueViews.get(_CASE_DEFAULT) || null;
|
|
||||||
}
|
|
||||||
this._activateViews(views);
|
|
||||||
|
|
||||||
|
if (views) {
|
||||||
|
this._useDefault = false;
|
||||||
|
} else {
|
||||||
|
// No view to display for the current value -> default case
|
||||||
|
// Nothing to do if the default case was already active
|
||||||
|
if (this._useDefault) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._useDefault = true;
|
||||||
|
views = this._valueViews.get(_CASE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._emptyAllActiveViews();
|
||||||
|
this._activateViews(views);
|
||||||
this._switchValue = value;
|
this._switchValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +123,7 @@ export class NgSwitch {
|
|||||||
this._activeViews = [];
|
this._activeViews = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
private _activateViews(views: SwitchView[]): void {
|
private _activateViews(views?: SwitchView[]): void {
|
||||||
if (views) {
|
if (views) {
|
||||||
for (var i = 0; i < views.length; i++) {
|
for (var i = 0; i < views.length; i++) {
|
||||||
views[i].create();
|
views[i].create();
|
||||||
|
@ -33,21 +33,21 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
|
|||||||
* - `'shortTime'`: equivalent to `'jm'` (e.g. `12:05 PM` for `en-US`)
|
* - `'shortTime'`: equivalent to `'jm'` (e.g. `12:05 PM` for `en-US`)
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* | Component | Symbol | Short Form | Long Form | Numeric | 2-digit |
|
* | Component | Symbol | Narrow | Short Form | Long Form | Numeric | 2-digit |
|
||||||
* |-----------|:------:|--------------|-------------------|-----------|-----------|
|
* |-----------|:------:|--------|--------------|-------------------|-----------|-----------|
|
||||||
* | era | G | G (AD) | GGGG (Anno Domini)| - | - |
|
* | era | G | G (A) | GGG (AD) | GGGG (Anno Domini)| - | - |
|
||||||
* | year | y | - | - | y (2015) | yy (15) |
|
* | year | y | - | - | - | y (2015) | yy (15) |
|
||||||
* | month | M | MMM (Sep) | MMMM (September) | M (9) | MM (09) |
|
* | month | M | L (S) | MMM (Sep) | MMMM (September) | M (9) | MM (09) |
|
||||||
* | day | d | - | - | d (3) | dd (03) |
|
* | day | d | - | - | - | d (3) | dd (03) |
|
||||||
* | weekday | E | EEE (Sun) | EEEE (Sunday) | - | - |
|
* | weekday | E | E (S) | EEE (Sun) | EEEE (Sunday) | - | - |
|
||||||
* | hour | j | - | - | j (13) | jj (13) |
|
* | hour | j | - | - | - | j (13) | jj (13) |
|
||||||
* | hour12 | h | - | - | h (1 PM) | hh (01 PM)|
|
* | hour12 | h | - | - | - | h (1 PM) | hh (01 PM)|
|
||||||
* | hour24 | H | - | - | H (13) | HH (13) |
|
* | hour24 | H | - | - | - | H (13) | HH (13) |
|
||||||
* | minute | m | - | - | m (5) | mm (05) |
|
* | minute | m | - | - | - | m (5) | mm (05) |
|
||||||
* | second | s | - | - | s (9) | ss (09) |
|
* | second | s | - | - | - | s (9) | ss (09) |
|
||||||
* | timezone | z | - | z (Pacific Standard Time)| - | - |
|
* | timezone | z | - | - | z (Pacific Standard Time)| - | - |
|
||||||
* | timezone | Z | Z (GMT-8:00) | - | - | - |
|
* | timezone | Z | - | Z (GMT-8:00) | - | - | - |
|
||||||
* | timezone | a | a (PM) | - | - | - |
|
* | timezone | a | - | a (PM) | - | - | - |
|
||||||
*
|
*
|
||||||
* In javascript, only the components specified will be respected (not the ordering,
|
* In javascript, only the components specified will be respected (not the ordering,
|
||||||
* punctuations, ...) and details of the formatting will be dependent on the locale.
|
* punctuations, ...) and details of the formatting will be dependent on the locale.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Pipe, PipeTransform} from '@angular/core';
|
import {Pipe, PipeTransform} from '@angular/core';
|
||||||
import {isBlank, isStringMap} from '../facade/lang';
|
import {isBlank} from '../facade/lang';
|
||||||
import {NgLocalization, getPluralCategory} from '../localization';
|
import {NgLocalization, getPluralCategory} from '../localization';
|
||||||
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
|
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ export class I18nPluralPipe implements PipeTransform {
|
|||||||
transform(value: number, pluralMap: {[count: string]: string}): string {
|
transform(value: number, pluralMap: {[count: string]: string}): string {
|
||||||
if (isBlank(value)) return '';
|
if (isBlank(value)) return '';
|
||||||
|
|
||||||
if (!isStringMap(pluralMap)) {
|
if (typeof pluralMap !== 'object' || pluralMap === null) {
|
||||||
throw new InvalidPipeArgumentError(I18nPluralPipe, pluralMap);
|
throw new InvalidPipeArgumentError(I18nPluralPipe, pluralMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Pipe, PipeTransform} from '@angular/core';
|
import {Pipe, PipeTransform} from '@angular/core';
|
||||||
import {isBlank, isStringMap} from '../facade/lang';
|
import {isBlank} from '../facade/lang';
|
||||||
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
|
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,10 +31,10 @@ export class I18nSelectPipe implements PipeTransform {
|
|||||||
transform(value: string, mapping: {[key: string]: string}): string {
|
transform(value: string, mapping: {[key: string]: string}): string {
|
||||||
if (isBlank(value)) return '';
|
if (isBlank(value)) return '';
|
||||||
|
|
||||||
if (!isStringMap(mapping)) {
|
if (typeof mapping !== 'object' || mapping === null) {
|
||||||
throw new InvalidPipeArgumentError(I18nSelectPipe, mapping);
|
throw new InvalidPipeArgumentError(I18nSelectPipe, mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapping.hasOwnProperty(value) ? mapping[value] : '';
|
return mapping[value] || '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,6 @@
|
|||||||
|
|
||||||
import {Pipe, PipeTransform} from '@angular/core';
|
import {Pipe, PipeTransform} from '@angular/core';
|
||||||
|
|
||||||
import {Json} from '../facade/lang';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngModule CommonModule
|
* @ngModule CommonModule
|
||||||
* @whatItDoes Converts value into JSON string.
|
* @whatItDoes Converts value into JSON string.
|
||||||
@ -27,5 +23,5 @@ import {Json} from '../facade/lang';
|
|||||||
*/
|
*/
|
||||||
@Pipe({name: 'json', pure: false})
|
@Pipe({name: 'json', pure: false})
|
||||||
export class JsonPipe implements PipeTransform {
|
export class JsonPipe implements PipeTransform {
|
||||||
transform(value: any): string { return Json.stringify(value); }
|
transform(value: any): string { return JSON.stringify(value, null, 2); }
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
|
|||||||
* @howToUse `expression | lowercase`
|
* @howToUse `expression | lowercase`
|
||||||
* @description
|
* @description
|
||||||
*
|
*
|
||||||
* Converts value into lowercase string using `String.prototype.toLowerCase()`.
|
* Converts value into a lowercase string using `String.prototype.toLowerCase()`.
|
||||||
*
|
*
|
||||||
* ### Example
|
* ### Example
|
||||||
*
|
*
|
||||||
|
@ -16,7 +16,7 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
|
|||||||
* @howToUse `expression | uppercase`
|
* @howToUse `expression | uppercase`
|
||||||
* @description
|
* @description
|
||||||
*
|
*
|
||||||
* Converts value into lowercase string using `String.prototype.toUpperCase()`.
|
* Converts value into an uppercase string using `String.prototype.toUpperCase()`.
|
||||||
*
|
*
|
||||||
* ### Example
|
* ### Example
|
||||||
*
|
*
|
||||||
|
@ -50,25 +50,6 @@ export function main() {
|
|||||||
detectChangesAndExpectText('when b');
|
detectChangesAndExpectText('when b');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// TODO(robwormald): deprecate and remove
|
|
||||||
it('should switch amongst when values using switchCase', async(() => {
|
|
||||||
const template = '<div>' +
|
|
||||||
'<ul [ngSwitch]="switchValue">' +
|
|
||||||
'<template ngSwitchCase="a"><li>when a</li></template>' +
|
|
||||||
'<template ngSwitchCase="b"><li>when b</li></template>' +
|
|
||||||
'</ul></div>';
|
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
|
||||||
|
|
||||||
detectChangesAndExpectText('');
|
|
||||||
|
|
||||||
getComponent().switchValue = 'a';
|
|
||||||
detectChangesAndExpectText('when a');
|
|
||||||
|
|
||||||
getComponent().switchValue = 'b';
|
|
||||||
detectChangesAndExpectText('when b');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should switch amongst when values with fallback to default', async(() => {
|
it('should switch amongst when values with fallback to default', async(() => {
|
||||||
const template = '<div>' +
|
const template = '<div>' +
|
||||||
'<ul [ngSwitch]="switchValue">' +
|
'<ul [ngSwitch]="switchValue">' +
|
||||||
@ -84,6 +65,9 @@ export function main() {
|
|||||||
|
|
||||||
getComponent().switchValue = 'b';
|
getComponent().switchValue = 'b';
|
||||||
detectChangesAndExpectText('when default');
|
detectChangesAndExpectText('when default');
|
||||||
|
|
||||||
|
getComponent().switchValue = 'c';
|
||||||
|
detectChangesAndExpectText('when default');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should support multiple whens with the same value', async(() => {
|
it('should support multiple whens with the same value', async(() => {
|
||||||
|
@ -8,13 +8,12 @@
|
|||||||
|
|
||||||
import {DatePipe} from '@angular/common';
|
import {DatePipe} from '@angular/common';
|
||||||
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
|
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
|
||||||
import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
|
|
||||||
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
|
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('DatePipe', () => {
|
describe('DatePipe', () => {
|
||||||
var date: Date;
|
let date: Date;
|
||||||
var pipe: DatePipe;
|
let pipe: DatePipe;
|
||||||
|
|
||||||
// TODO: reactivate the disabled expectations once emulators are fixed in SauceLabs
|
// TODO: reactivate the disabled expectations once emulators are fixed in SauceLabs
|
||||||
// In some old versions of Chrome in Android emulators, time formatting returns dates in the
|
// In some old versions of Chrome in Android emulators, time formatting returns dates in the
|
||||||
@ -34,7 +33,9 @@ export function main() {
|
|||||||
|
|
||||||
describe('supports', () => {
|
describe('supports', () => {
|
||||||
it('should support date', () => { expect(() => pipe.transform(date)).not.toThrow(); });
|
it('should support date', () => { expect(() => pipe.transform(date)).not.toThrow(); });
|
||||||
|
|
||||||
it('should support int', () => { expect(() => pipe.transform(123456789)).not.toThrow(); });
|
it('should support int', () => { expect(() => pipe.transform(123456789)).not.toThrow(); });
|
||||||
|
|
||||||
it('should support numeric strings',
|
it('should support numeric strings',
|
||||||
() => { expect(() => pipe.transform('123456789')).not.toThrow(); });
|
() => { expect(() => pipe.transform('123456789')).not.toThrow(); });
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ export function main() {
|
|||||||
expect(pipe.transform(date, 'MMM')).toEqual('Jun');
|
expect(pipe.transform(date, 'MMM')).toEqual('Jun');
|
||||||
expect(pipe.transform(date, 'MMMM')).toEqual('June');
|
expect(pipe.transform(date, 'MMMM')).toEqual('June');
|
||||||
expect(pipe.transform(date, 'd')).toEqual('15');
|
expect(pipe.transform(date, 'd')).toEqual('15');
|
||||||
expect(pipe.transform(date, 'E')).toEqual('Mon');
|
expect(pipe.transform(date, 'EEE')).toEqual('Mon');
|
||||||
expect(pipe.transform(date, 'EEEE')).toEqual('Monday');
|
expect(pipe.transform(date, 'EEEE')).toEqual('Monday');
|
||||||
if (!browserDetection.isOldChrome) {
|
if (!browserDetection.isOldChrome) {
|
||||||
expect(pipe.transform(date, 'h')).toEqual('9');
|
expect(pipe.transform(date, 'h')).toEqual('9');
|
||||||
@ -72,6 +73,9 @@ export function main() {
|
|||||||
if (!browserDetection.isOldChrome) {
|
if (!browserDetection.isOldChrome) {
|
||||||
expect(pipe.transform(date, 'HH')).toEqual('09');
|
expect(pipe.transform(date, 'HH')).toEqual('09');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expect(pipe.transform(date, 'E')).toEqual('M');
|
||||||
|
expect(pipe.transform(date, 'L')).toEqual('J');
|
||||||
expect(pipe.transform(date, 'm')).toEqual('3');
|
expect(pipe.transform(date, 'm')).toEqual('3');
|
||||||
expect(pipe.transform(date, 's')).toEqual('1');
|
expect(pipe.transform(date, 's')).toEqual('1');
|
||||||
expect(pipe.transform(date, 'mm')).toEqual('03');
|
expect(pipe.transform(date, 'mm')).toEqual('03');
|
||||||
@ -81,13 +85,13 @@ export function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should format common multi component patterns', () => {
|
it('should format common multi component patterns', () => {
|
||||||
expect(pipe.transform(date, 'E, M/d/y')).toEqual('Mon, 6/15/2015');
|
expect(pipe.transform(date, 'EEE, M/d/y')).toEqual('Mon, 6/15/2015');
|
||||||
expect(pipe.transform(date, 'E, M/d')).toEqual('Mon, 6/15');
|
expect(pipe.transform(date, 'EEE, M/d')).toEqual('Mon, 6/15');
|
||||||
expect(pipe.transform(date, 'MMM d')).toEqual('Jun 15');
|
expect(pipe.transform(date, 'MMM d')).toEqual('Jun 15');
|
||||||
expect(pipe.transform(date, 'dd/MM/yyyy')).toEqual('15/06/2015');
|
expect(pipe.transform(date, 'dd/MM/yyyy')).toEqual('15/06/2015');
|
||||||
expect(pipe.transform(date, 'MM/dd/yyyy')).toEqual('06/15/2015');
|
expect(pipe.transform(date, 'MM/dd/yyyy')).toEqual('06/15/2015');
|
||||||
expect(pipe.transform(date, 'yMEd')).toEqual('20156Mon15');
|
expect(pipe.transform(date, 'yMEEEd')).toEqual('20156Mon15');
|
||||||
expect(pipe.transform(date, 'MEd')).toEqual('6Mon15');
|
expect(pipe.transform(date, 'MEEEd')).toEqual('6Mon15');
|
||||||
expect(pipe.transform(date, 'MMMd')).toEqual('Jun15');
|
expect(pipe.transform(date, 'MMMd')).toEqual('Jun15');
|
||||||
expect(pipe.transform(date, 'yMMMMEEEEd')).toEqual('Monday, June 15, 2015');
|
expect(pipe.transform(date, 'yMMMMEEEEd')).toEqual('Monday, June 15, 2015');
|
||||||
// IE and Edge can't format a date to minutes and seconds without hours
|
// IE and Edge can't format a date to minutes and seconds without hours
|
||||||
|
@ -11,8 +11,6 @@ import {Component} from '@angular/core';
|
|||||||
import {TestBed, async} from '@angular/core/testing';
|
import {TestBed, async} from '@angular/core/testing';
|
||||||
import {expect} from '@angular/platform-browser/testing/matchers';
|
import {expect} from '@angular/platform-browser/testing/matchers';
|
||||||
|
|
||||||
import {Json, StringWrapper} from '../../src/facade/lang';
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('JsonPipe', () => {
|
describe('JsonPipe', () => {
|
||||||
var regNewLine = '\n';
|
var regNewLine = '\n';
|
||||||
@ -20,7 +18,7 @@ export function main() {
|
|||||||
var inceptionObjString: string;
|
var inceptionObjString: string;
|
||||||
var pipe: JsonPipe;
|
var pipe: JsonPipe;
|
||||||
|
|
||||||
function normalize(obj: string): string { return StringWrapper.replace(obj, regNewLine, ''); }
|
function normalize(obj: string): string { return obj.replace(regNewLine, ''); }
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
inceptionObj = {dream: {dream: {dream: 'Limbo'}}};
|
inceptionObj = {dream: {dream: {dream: 'Limbo'}}};
|
||||||
@ -48,7 +46,7 @@ export function main() {
|
|||||||
|
|
||||||
it('should return JSON-formatted string similar to Json.stringify', () => {
|
it('should return JSON-formatted string similar to Json.stringify', () => {
|
||||||
var dream1 = normalize(pipe.transform(inceptionObj));
|
var dream1 = normalize(pipe.transform(inceptionObj));
|
||||||
var dream2 = normalize(Json.stringify(inceptionObj));
|
var dream2 = normalize(JSON.stringify(inceptionObj, null, 2));
|
||||||
expect(dream1).toEqual(dream2);
|
expect(dream1).toEqual(dream2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -74,7 +72,6 @@ export function main() {
|
|||||||
mutable.push(2);
|
mutable.push(2);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(fixture.nativeElement).toHaveText('[\n 1,\n 2\n]');
|
expect(fixture.nativeElement).toHaveText('[\n 1,\n 2\n]');
|
||||||
|
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -27,7 +27,7 @@ Then you can add an import statement in the `bootstrap` allowing you to bootstra
|
|||||||
generated code:
|
generated code:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
main_module.ts
|
main.module.ts
|
||||||
-------------
|
-------------
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import {Component, NgModule, ApplicationRef} from '@angular/core';
|
import {Component, NgModule, ApplicationRef} from '@angular/core';
|
||||||
@ -49,7 +49,7 @@ export class MainModule {
|
|||||||
bootstrap.ts
|
bootstrap.ts
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
import {MainModuleNgFactory} from './main_module.ngfactory';
|
import {MainModuleNgFactory} from './main.module.ngfactory';
|
||||||
import {platformBrowser} from '@angular/platform-browser';
|
import {platformBrowser} from '@angular/platform-browser';
|
||||||
|
|
||||||
platformBrowser().bootstrapModuleFactory(MainModuleNgFactory);
|
platformBrowser().bootstrapModuleFactory(MainModuleNgFactory);
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export {CodeGenerator} from './src/codegen';
|
export {CodeGenerator} from './src/codegen';
|
||||||
|
export {Extractor} from './src/extractor';
|
||||||
export {NodeReflectorHostContext, ReflectorHost, ReflectorHostContext} from './src/reflector_host';
|
export {NodeReflectorHostContext, ReflectorHost, ReflectorHostContext} from './src/reflector_host';
|
||||||
export {StaticReflector, StaticReflectorHost, StaticSymbol} from './src/static_reflector';
|
export {StaticReflector, StaticReflectorHost, StaticSymbol} from './src/static_reflector';
|
||||||
|
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
# Overview
|
||||||
|
|
||||||
|
This folder will be filled with the benchmark sources
|
||||||
|
so that we can do offline compilation for them.
|
||||||
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Component} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'use-third-party',
|
||||||
|
template: '<third-party-comp [thirdParty]="title"></third-party-comp>' +
|
||||||
|
'<another-third-party-comp></another-third-party-comp>',
|
||||||
|
})
|
||||||
|
export class ComponentUsingThirdParty {
|
||||||
|
title: string = 'from 3rd party';
|
||||||
|
}
|
@ -12,6 +12,10 @@
|
|||||||
<source>Welcome</source>
|
<source>Welcome</source>
|
||||||
<target>tervetuloa</target>
|
<target>tervetuloa</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="63a85808f03b8181e36a952e0fa38202c2304862" datatype="html">
|
||||||
|
<source>other-3rdP-component</source>
|
||||||
|
<target>other-3rdP-component</target>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
@ -9,4 +9,5 @@
|
|||||||
<translationbundle>
|
<translationbundle>
|
||||||
<translation id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4">käännä teksti</translation>
|
<translation id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4">käännä teksti</translation>
|
||||||
<translation id="65cc4ab3b4c438e07c89be2b677d08369fb62da2">tervetuloa</translation>
|
<translation id="65cc4ab3b4c438e07c89be2b677d08369fb62da2">tervetuloa</translation>
|
||||||
|
<translation id="63a85808f03b8181e36a952e0fa38202c2304862">other-3rdP-component</translation>
|
||||||
</translationbundle>
|
</translationbundle>
|
||||||
|
@ -11,9 +11,12 @@ import {FormsModule} from '@angular/forms';
|
|||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import {MdButtonModule} from '@angular2-material/button';
|
import {MdButtonModule} from '@angular2-material/button';
|
||||||
|
|
||||||
|
import {ThirdpartyModule} from '../third_party_src/module';
|
||||||
|
|
||||||
import {MultipleComponentsMyComp, NextComp} from './a/multiple_components';
|
import {MultipleComponentsMyComp, NextComp} from './a/multiple_components';
|
||||||
import {AnimateCmp} from './animate';
|
import {AnimateCmp} from './animate';
|
||||||
import {BasicComp} from './basic';
|
import {BasicComp} from './basic';
|
||||||
|
import {ComponentUsingThirdParty} from './comp_using_3rdp';
|
||||||
import {CompWithAnalyzeEntryComponentsProvider, CompWithEntryComponents} from './entry_components';
|
import {CompWithAnalyzeEntryComponentsProvider, CompWithEntryComponents} from './entry_components';
|
||||||
import {CompConsumingEvents, CompUsingPipes, CompWithProviders, CompWithReferences, DirPublishingEvents, ModuleUsingCustomElements} from './features';
|
import {CompConsumingEvents, CompUsingPipes, CompWithProviders, CompWithReferences, DirPublishingEvents, ModuleUsingCustomElements} from './features';
|
||||||
import {CompUsingRootModuleDirectiveAndPipe, SomeDirectiveInRootModule, SomePipeInRootModule, SomeService, someLibModuleWithProviders} from './module_fixtures';
|
import {CompUsingRootModuleDirectiveAndPipe, SomeDirectiveInRootModule, SomePipeInRootModule, SomeService, someLibModuleWithProviders} from './module_fixtures';
|
||||||
@ -22,35 +25,47 @@ import {CompForChildQuery, CompWithChildQuery, CompWithDirectiveChild, Directive
|
|||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
SomeDirectiveInRootModule,
|
|
||||||
SomePipeInRootModule,
|
|
||||||
AnimateCmp,
|
AnimateCmp,
|
||||||
BasicComp,
|
BasicComp,
|
||||||
|
CompConsumingEvents,
|
||||||
CompForChildQuery,
|
CompForChildQuery,
|
||||||
CompWithEntryComponents,
|
CompUsingPipes,
|
||||||
|
CompUsingRootModuleDirectiveAndPipe,
|
||||||
CompWithAnalyzeEntryComponentsProvider,
|
CompWithAnalyzeEntryComponentsProvider,
|
||||||
ProjectingComp,
|
|
||||||
CompWithChildQuery,
|
CompWithChildQuery,
|
||||||
CompWithDirectiveChild,
|
CompWithDirectiveChild,
|
||||||
|
CompWithEntryComponents,
|
||||||
CompWithNgContent,
|
CompWithNgContent,
|
||||||
CompUsingRootModuleDirectiveAndPipe,
|
|
||||||
CompWithProviders,
|
CompWithProviders,
|
||||||
CompWithReferences,
|
CompWithReferences,
|
||||||
CompUsingPipes,
|
DirectiveForQuery,
|
||||||
CompConsumingEvents,
|
|
||||||
DirPublishingEvents,
|
DirPublishingEvents,
|
||||||
MultipleComponentsMyComp,
|
MultipleComponentsMyComp,
|
||||||
DirectiveForQuery,
|
|
||||||
NextComp,
|
NextComp,
|
||||||
|
ProjectingComp,
|
||||||
|
SomeDirectiveInRootModule,
|
||||||
|
SomePipeInRootModule,
|
||||||
|
ComponentUsingThirdParty,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule, FormsModule, someLibModuleWithProviders(), ModuleUsingCustomElements,
|
BrowserModule,
|
||||||
MdButtonModule
|
FormsModule,
|
||||||
|
MdButtonModule,
|
||||||
|
ModuleUsingCustomElements,
|
||||||
|
someLibModuleWithProviders(),
|
||||||
|
ThirdpartyModule,
|
||||||
],
|
],
|
||||||
providers: [SomeService],
|
providers: [SomeService],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
AnimateCmp, BasicComp, CompWithEntryComponents, CompWithAnalyzeEntryComponentsProvider,
|
AnimateCmp,
|
||||||
ProjectingComp, CompWithChildQuery, CompUsingRootModuleDirectiveAndPipe, CompWithReferences
|
BasicComp,
|
||||||
|
CompUsingRootModuleDirectiveAndPipe,
|
||||||
|
CompWithAnalyzeEntryComponentsProvider,
|
||||||
|
CompWithChildQuery,
|
||||||
|
CompWithEntryComponents,
|
||||||
|
CompWithReferences,
|
||||||
|
ProjectingComp,
|
||||||
|
ComponentUsingThirdParty,
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class MainModule {
|
export class MainModule {
|
||||||
|
@ -43,13 +43,13 @@ describe('template codegen output', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to create the basic component', () => {
|
it('should be able to create the basic component', () => {
|
||||||
var compFixture = createComponent(BasicComp);
|
const compFixture = createComponent(BasicComp);
|
||||||
expect(compFixture.componentInstance).toBeTruthy();
|
expect(compFixture.componentInstance).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support ngIf', () => {
|
it('should support ngIf', () => {
|
||||||
var compFixture = createComponent(BasicComp);
|
const compFixture = createComponent(BasicComp);
|
||||||
var debugElement = compFixture.debugElement;
|
const debugElement = compFixture.debugElement;
|
||||||
expect(debugElement.children.length).toBe(3);
|
expect(debugElement.children.length).toBe(3);
|
||||||
|
|
||||||
compFixture.componentInstance.ctxBool = true;
|
compFixture.componentInstance.ctxBool = true;
|
||||||
@ -59,8 +59,8 @@ describe('template codegen output', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should support ngFor', () => {
|
it('should support ngFor', () => {
|
||||||
var compFixture = createComponent(BasicComp);
|
const compFixture = createComponent(BasicComp);
|
||||||
var debugElement = compFixture.debugElement;
|
const debugElement = compFixture.debugElement;
|
||||||
expect(debugElement.children.length).toBe(3);
|
expect(debugElement.children.length).toBe(3);
|
||||||
|
|
||||||
// test NgFor
|
// test NgFor
|
||||||
@ -83,11 +83,9 @@ describe('template codegen output', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should support i18n for content tags', () => {
|
it('should support i18n for content tags', () => {
|
||||||
const compFixture = createComponent(BasicComp);
|
const containerElement = createComponent(BasicComp).nativeElement;
|
||||||
const debugElement = compFixture.debugElement;
|
const pElement = containerElement.children.find((c: any) => c.name == 'p');
|
||||||
const containerElement = <any>debugElement.nativeElement;
|
const pText = pElement.children.map((c: any) => c.data).join('').trim();
|
||||||
const pElement = <any>containerElement.children.find((c: any) => c.name == 'p');
|
|
||||||
const pText = <string>pElement.children.map((c: any) => c.data).join('').trim();
|
|
||||||
expect(pText).toBe('tervetuloa');
|
expect(pText).toBe('tervetuloa');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -34,6 +34,7 @@ const EXPECTED_XMB = `<?xml version="1.0" encoding="UTF-8" ?>
|
|||||||
<!ELEMENT ex (#PCDATA)>
|
<!ELEMENT ex (#PCDATA)>
|
||||||
]>
|
]>
|
||||||
<messagebundle>
|
<messagebundle>
|
||||||
|
<msg id="63a85808f03b8181e36a952e0fa38202c2304862">other-3rdP-component</msg>
|
||||||
<msg id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" desc="desc" meaning="meaning">translate me</msg>
|
<msg id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" desc="desc" meaning="meaning">translate me</msg>
|
||||||
<msg id="65cc4ab3b4c438e07c89be2b677d08369fb62da2">Welcome</msg>
|
<msg id="65cc4ab3b4c438e07c89be2b677d08369fb62da2">Welcome</msg>
|
||||||
</messagebundle>
|
</messagebundle>
|
||||||
@ -43,6 +44,10 @@ const EXPECTED_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
|
|||||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<file source-language="en" datatype="plaintext" original="ng2.template">
|
<file source-language="en" datatype="plaintext" original="ng2.template">
|
||||||
<body>
|
<body>
|
||||||
|
<trans-unit id="63a85808f03b8181e36a952e0fa38202c2304862" datatype="html">
|
||||||
|
<source>other-3rdP-component</source>
|
||||||
|
<target/>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" datatype="html">
|
<trans-unit id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" datatype="html">
|
||||||
<source>translate me</source>
|
<source>translate me</source>
|
||||||
<target/>
|
<target/>
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
import './init';
|
import './init';
|
||||||
|
|
||||||
|
import {ComponentUsingThirdParty} from '../src/comp_using_3rdp';
|
||||||
import {MainModule} from '../src/module';
|
import {MainModule} from '../src/module';
|
||||||
import {CompUsingLibModuleDirectiveAndPipe, CompUsingRootModuleDirectiveAndPipe, SOME_TOKEN, ServiceUsingLibModule, SomeLibModule, SomeService} from '../src/module_fixtures';
|
import {CompUsingLibModuleDirectiveAndPipe, CompUsingRootModuleDirectiveAndPipe, SOME_TOKEN, ServiceUsingLibModule, SomeLibModule, SomeService} from '../src/module_fixtures';
|
||||||
|
|
||||||
@ -15,9 +16,9 @@ import {createComponent, createModule} from './util';
|
|||||||
describe('NgModule', () => {
|
describe('NgModule', () => {
|
||||||
it('should support providers', () => {
|
it('should support providers', () => {
|
||||||
const moduleRef = createModule();
|
const moduleRef = createModule();
|
||||||
expect(moduleRef.instance instanceof MainModule).toBe(true);
|
expect(moduleRef.instance instanceof MainModule).toEqual(true);
|
||||||
expect(moduleRef.injector.get(MainModule) instanceof MainModule).toBe(true);
|
expect(moduleRef.injector.get(MainModule) instanceof MainModule).toEqual(true);
|
||||||
expect(moduleRef.injector.get(SomeService) instanceof SomeService).toBe(true);
|
expect(moduleRef.injector.get(SomeService) instanceof SomeService).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support entryComponents components', () => {
|
it('should support entryComponents components', () => {
|
||||||
@ -26,7 +27,7 @@ describe('NgModule', () => {
|
|||||||
CompUsingRootModuleDirectiveAndPipe);
|
CompUsingRootModuleDirectiveAndPipe);
|
||||||
expect(cf.componentType).toBe(CompUsingRootModuleDirectiveAndPipe);
|
expect(cf.componentType).toBe(CompUsingRootModuleDirectiveAndPipe);
|
||||||
const compRef = cf.create(moduleRef.injector);
|
const compRef = cf.create(moduleRef.injector);
|
||||||
expect(compRef.instance instanceof CompUsingRootModuleDirectiveAndPipe).toBe(true);
|
expect(compRef.instance instanceof CompUsingRootModuleDirectiveAndPipe).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support entryComponents via the ANALYZE_FOR_ENTRY_COMPONENTS provider and function providers in components',
|
it('should support entryComponents via the ANALYZE_FOR_ENTRY_COMPONENTS provider and function providers in components',
|
||||||
@ -42,12 +43,30 @@ describe('NgModule', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('third-party modules', () => {
|
||||||
|
// https://github.com/angular/angular/issues/11889
|
||||||
|
it('should support third party entryComponents components', () => {
|
||||||
|
const fixture = createComponent(ComponentUsingThirdParty);
|
||||||
|
const thirdPComps = fixture.nativeElement.children;
|
||||||
|
expect(thirdPComps[0].children[0].children[0].data).toEqual('3rdP-component');
|
||||||
|
expect(thirdPComps[1].children[0].children[0].data).toEqual('other-3rdP-component');
|
||||||
|
});
|
||||||
|
|
||||||
|
// https://github.com/angular/angular/issues/12428
|
||||||
|
it('should support third party directives', () => {
|
||||||
|
const fixture = createComponent(ComponentUsingThirdParty);
|
||||||
|
const debugElement = fixture.debugElement;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(debugElement.children[0].properties['title']).toEqual('from 3rd party');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should support module directives and pipes', () => {
|
it('should support module directives and pipes', () => {
|
||||||
const compFixture = createComponent(CompUsingRootModuleDirectiveAndPipe);
|
const compFixture = createComponent(CompUsingRootModuleDirectiveAndPipe);
|
||||||
compFixture.detectChanges();
|
compFixture.detectChanges();
|
||||||
|
|
||||||
const debugElement = compFixture.debugElement;
|
const debugElement = compFixture.debugElement;
|
||||||
expect(debugElement.children[0].properties['title']).toBe('transformed someValue');
|
expect(debugElement.children[0].properties['title']).toEqual('transformed someValue');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support module directives and pipes on lib modules', () => {
|
it('should support module directives and pipes on lib modules', () => {
|
||||||
@ -55,10 +74,10 @@ describe('NgModule', () => {
|
|||||||
compFixture.detectChanges();
|
compFixture.detectChanges();
|
||||||
|
|
||||||
const debugElement = compFixture.debugElement;
|
const debugElement = compFixture.debugElement;
|
||||||
expect(debugElement.children[0].properties['title']).toBe('transformed someValue');
|
expect(debugElement.children[0].properties['title']).toEqual('transformed someValue');
|
||||||
|
|
||||||
expect(debugElement.injector.get(SomeLibModule) instanceof SomeLibModule).toBe(true);
|
expect(debugElement.injector.get(SomeLibModule) instanceof SomeLibModule).toEqual(true);
|
||||||
expect(debugElement.injector.get(ServiceUsingLibModule) instanceof ServiceUsingLibModule)
|
expect(debugElement.injector.get(ServiceUsingLibModule) instanceof ServiceUsingLibModule)
|
||||||
.toBe(true);
|
.toEqual(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
This folder emulates consuming precompiled modules and components.
|
||||||
|
It is compiled separately from the other sources under `src`
|
||||||
|
to only generate `*.js` / `*.d.ts` / `*.metadata.json` files,
|
||||||
|
but no `*.ngfactory.ts` files.
|
||||||
|
|
||||||
|
** WARNING **
|
||||||
|
Do not import components/directives from here directly as we want to test that ngc still compiles
|
||||||
|
them when they are not imported.
|
@ -6,7 +6,11 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {global} from './lang';
|
import {Component} from '@angular/core';
|
||||||
|
|
||||||
export var Math = global.Math;
|
@Component({
|
||||||
export var NaN: any /** TODO #???? */ = typeof NaN;
|
selector: 'third-party-comp',
|
||||||
|
template: '<div>3rdP-component</div>',
|
||||||
|
})
|
||||||
|
export class ThirdPartyComponent {
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* @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 {Directive, Input} from '@angular/core';
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: '[thirdParty]',
|
||||||
|
host: {'[title]': 'thirdParty'},
|
||||||
|
})
|
||||||
|
export class ThirdPartyDirective {
|
||||||
|
@Input() thirdParty: string;
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* @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 {NgModule} from '@angular/core';
|
||||||
|
|
||||||
|
import {ThirdPartyComponent} from './comp';
|
||||||
|
import {ThirdPartyDirective} from './directive';
|
||||||
|
import {AnotherThirdPartyModule} from './other_module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
ThirdPartyComponent,
|
||||||
|
ThirdPartyDirective,
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
AnotherThirdPartyModule,
|
||||||
|
ThirdPartyComponent,
|
||||||
|
ThirdPartyDirective,
|
||||||
|
],
|
||||||
|
imports: [AnotherThirdPartyModule]
|
||||||
|
})
|
||||||
|
export class ThirdpartyModule {
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Component} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'another-third-party-comp',
|
||||||
|
template: '<div i18n>other-3rdP-component</div>',
|
||||||
|
})
|
||||||
|
export class AnotherThirdpartyComponent {
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* @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 {NgModule} from '@angular/core';
|
||||||
|
import {AnotherThirdpartyComponent} from './other_comp';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [AnotherThirdpartyComponent],
|
||||||
|
exports: [AnotherThirdpartyComponent],
|
||||||
|
})
|
||||||
|
export class AnotherThirdPartyModule {
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
// For TypeScript 1.8, we have to lay out generated files
|
||||||
|
// in the same source directory with your code.
|
||||||
|
"genDir": ".",
|
||||||
|
"debug": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"rootDir": "",
|
||||||
|
"declaration": true,
|
||||||
|
"lib": ["es6", "dom"],
|
||||||
|
"baseUrl": ".",
|
||||||
|
"outDir": "../node_modules/third_party"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
// For TypeScript 1.8, we have to lay out generated files
|
||||||
|
// in the same source directory with your code.
|
||||||
|
"genDir": ".",
|
||||||
|
"debug": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"rootDir": "",
|
||||||
|
"declaration": true,
|
||||||
|
"lib": ["es6", "dom"],
|
||||||
|
"baseUrl": "."
|
||||||
|
},
|
||||||
|
|
||||||
|
"files": [
|
||||||
|
"src/module",
|
||||||
|
"src/bootstrap",
|
||||||
|
"test/all_spec",
|
||||||
|
"benchmarks/src/tree/ng2/index_aot.ts",
|
||||||
|
"benchmarks/src/tree/ng2_switch/index_aot.ts",
|
||||||
|
"benchmarks/src/largetable/ng2/index_aot.ts",
|
||||||
|
"benchmarks/src/largetable/ng2_switch/index_aot.ts"
|
||||||
|
]
|
||||||
|
}
|
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"angularCompilerOptions": {
|
|
||||||
// For TypeScript 1.8, we have to lay out generated files
|
|
||||||
// in the same source directory with your code.
|
|
||||||
"genDir": ".",
|
|
||||||
"debug": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es5",
|
|
||||||
"experimentalDecorators": true,
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"rootDir": "",
|
|
||||||
"declaration": true,
|
|
||||||
"lib": ["es6", "dom"],
|
|
||||||
"baseUrl": "."
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,13 +11,11 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/tsc-wrapped": "^0.3.0",
|
"@angular/tsc-wrapped": "^0.3.0",
|
||||||
"reflect-metadata": "^0.1.2",
|
"reflect-metadata": "^0.1.2",
|
||||||
"parse5": "^2.2.1",
|
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "^2.0.2",
|
"typescript": "^2.0.2",
|
||||||
"@angular/compiler": "0.0.0-PLACEHOLDER",
|
"@angular/compiler": "0.0.0-PLACEHOLDER",
|
||||||
"@angular/platform-server": "0.0.0-PLACEHOLDER",
|
|
||||||
"@angular/core": "0.0.0-PLACEHOLDER"
|
"@angular/core": "0.0.0-PLACEHOLDER"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -11,17 +11,16 @@
|
|||||||
* Intended to be used in a build step.
|
* Intended to be used in a build step.
|
||||||
*/
|
*/
|
||||||
import * as compiler from '@angular/compiler';
|
import * as compiler from '@angular/compiler';
|
||||||
import {Component, NgModule, ViewEncapsulation} from '@angular/core';
|
import {ViewEncapsulation} from '@angular/core';
|
||||||
import {AngularCompilerOptions, NgcCliOptions} from '@angular/tsc-wrapped';
|
import {AngularCompilerOptions, NgcCliOptions} from '@angular/tsc-wrapped';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {PathMappedReflectorHost} from './path_mapped_reflector_host';
|
import {PathMappedReflectorHost} from './path_mapped_reflector_host';
|
||||||
import {CompileMetadataResolver, DirectiveNormalizer, DomElementSchemaRegistry, HtmlParser, Lexer, NgModuleCompiler, Parser, StyleCompiler, TemplateParser, TypeScriptEmitter, ViewCompiler} from './private_import_compiler';
|
|
||||||
import {Console} from './private_import_core';
|
import {Console} from './private_import_core';
|
||||||
import {ReflectorHost, ReflectorHostContext} from './reflector_host';
|
import {ReflectorHost, ReflectorHostContext} from './reflector_host';
|
||||||
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
|
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
|
||||||
import {StaticReflector, StaticSymbol} from './static_reflector';
|
import {StaticReflector, StaticReflectorHost, StaticSymbol} from './static_reflector';
|
||||||
|
|
||||||
const nodeFs = require('fs');
|
const nodeFs = require('fs');
|
||||||
|
|
||||||
@ -40,42 +39,12 @@ export class CodeGenerator {
|
|||||||
constructor(
|
constructor(
|
||||||
private options: AngularCompilerOptions, private program: ts.Program,
|
private options: AngularCompilerOptions, private program: ts.Program,
|
||||||
public host: ts.CompilerHost, private staticReflector: StaticReflector,
|
public host: ts.CompilerHost, private staticReflector: StaticReflector,
|
||||||
private compiler: compiler.OfflineCompiler, private reflectorHost: ReflectorHost) {}
|
private compiler: compiler.OfflineCompiler, private reflectorHost: StaticReflectorHost) {}
|
||||||
|
|
||||||
private readFileMetadata(absSourcePath: string): FileMetadata {
|
|
||||||
const moduleMetadata = this.staticReflector.getModuleMetadata(absSourcePath);
|
|
||||||
const result: FileMetadata = {components: [], ngModules: [], fileUrl: absSourcePath};
|
|
||||||
if (!moduleMetadata) {
|
|
||||||
console.log(`WARNING: no metadata found for ${absSourcePath}`);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
const metadata = moduleMetadata['metadata'];
|
|
||||||
const symbols = metadata && Object.keys(metadata);
|
|
||||||
if (!symbols || !symbols.length) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
for (const symbol of symbols) {
|
|
||||||
if (metadata[symbol] && metadata[symbol].__symbolic == 'error') {
|
|
||||||
// Ignore symbols that are only included to record error information.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const staticType = this.reflectorHost.findDeclaration(absSourcePath, symbol, absSourcePath);
|
|
||||||
const annotations = this.staticReflector.annotations(staticType);
|
|
||||||
annotations.forEach((annotation) => {
|
|
||||||
if (annotation instanceof NgModule) {
|
|
||||||
result.ngModules.push(staticType);
|
|
||||||
} else if (annotation instanceof Component) {
|
|
||||||
result.components.push(staticType);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write codegen in a directory structure matching the sources.
|
// Write codegen in a directory structure matching the sources.
|
||||||
private calculateEmitPath(filePath: string): string {
|
private calculateEmitPath(filePath: string): string {
|
||||||
let root = this.options.basePath;
|
let root = this.options.basePath;
|
||||||
for (let eachRootDir of this.options.rootDirs || []) {
|
for (const eachRootDir of this.options.rootDirs || []) {
|
||||||
if (this.options.trace) {
|
if (this.options.trace) {
|
||||||
console.log(`Check if ${filePath} is under rootDirs element ${eachRootDir}`);
|
console.log(`Check if ${filePath} is under rootDirs element ${eachRootDir}`);
|
||||||
}
|
}
|
||||||
@ -85,42 +54,28 @@ export class CodeGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// transplant the codegen path to be inside the `genDir`
|
// transplant the codegen path to be inside the `genDir`
|
||||||
var relativePath: string = path.relative(root, filePath);
|
let relativePath: string = path.relative(root, filePath);
|
||||||
while (relativePath.startsWith('..' + path.sep)) {
|
while (relativePath.startsWith('..' + path.sep)) {
|
||||||
// Strip out any `..` path such as: `../node_modules/@foo` as we want to put everything
|
// Strip out any `..` path such as: `../node_modules/@foo` as we want to put everything
|
||||||
// into `genDir`.
|
// into `genDir`.
|
||||||
relativePath = relativePath.substr(3);
|
relativePath = relativePath.substr(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
return path.join(this.options.genDir, relativePath);
|
return path.join(this.options.genDir, relativePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
codegen(): Promise<any> {
|
codegen(options: {transitiveModules: boolean}): Promise<any> {
|
||||||
// Compare with false since the default should be true
|
const staticSymbols =
|
||||||
const skipFileNames = (this.options.generateCodeForLibraries === false) ?
|
extractProgramSymbols(this.program, this.staticReflector, this.reflectorHost, this.options);
|
||||||
GENERATED_OR_DTS_FILES :
|
|
||||||
GENERATED_FILES;
|
return this.compiler.compileModules(staticSymbols, options).then(generatedModules => {
|
||||||
let filePaths = this.program.getSourceFiles()
|
generatedModules.forEach(generatedModule => {
|
||||||
.filter(sf => !skipFileNames.test(sf.fileName))
|
const sourceFile = this.program.getSourceFile(generatedModule.fileUrl);
|
||||||
.map(sf => this.reflectorHost.getCanonicalFileName(sf.fileName));
|
|
||||||
const fileMetas = filePaths.map((filePath) => this.readFileMetadata(filePath));
|
|
||||||
const ngModules = fileMetas.reduce((ngModules, fileMeta) => {
|
|
||||||
ngModules.push(...fileMeta.ngModules);
|
|
||||||
return ngModules;
|
|
||||||
}, <StaticSymbol[]>[]);
|
|
||||||
const analyzedNgModules = this.compiler.analyzeModules(ngModules);
|
|
||||||
return Promise.all(fileMetas.map(
|
|
||||||
(fileMeta) =>
|
|
||||||
this.compiler
|
|
||||||
.compile(
|
|
||||||
fileMeta.fileUrl, analyzedNgModules, fileMeta.components, fileMeta.ngModules)
|
|
||||||
.then((generatedModules) => {
|
|
||||||
generatedModules.forEach((generatedModule) => {
|
|
||||||
const sourceFile = this.program.getSourceFile(fileMeta.fileUrl);
|
|
||||||
const emitPath = this.calculateEmitPath(generatedModule.moduleUrl);
|
const emitPath = this.calculateEmitPath(generatedModule.moduleUrl);
|
||||||
this.host.writeFile(
|
this.host.writeFile(
|
||||||
emitPath, PREAMBLE + generatedModule.source, false, () => {}, [sourceFile]);
|
emitPath, PREAMBLE + generatedModule.source, false, () => {}, [sourceFile]);
|
||||||
});
|
});
|
||||||
})));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static create(
|
static create(
|
||||||
@ -157,36 +112,72 @@ export class CodeGenerator {
|
|||||||
const staticReflector = new StaticReflector(reflectorHost);
|
const staticReflector = new StaticReflector(reflectorHost);
|
||||||
StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
||||||
const htmlParser =
|
const htmlParser =
|
||||||
new compiler.I18NHtmlParser(new HtmlParser(), transContent, cliOptions.i18nFormat);
|
new compiler.I18NHtmlParser(new compiler.HtmlParser(), transContent, cliOptions.i18nFormat);
|
||||||
const config = new compiler.CompilerConfig({
|
const config = new compiler.CompilerConfig({
|
||||||
genDebugInfo: options.debug === true,
|
genDebugInfo: options.debug === true,
|
||||||
defaultEncapsulation: ViewEncapsulation.Emulated,
|
defaultEncapsulation: ViewEncapsulation.Emulated,
|
||||||
logBindingUpdate: false,
|
logBindingUpdate: false,
|
||||||
useJit: false
|
useJit: false
|
||||||
});
|
});
|
||||||
const normalizer = new DirectiveNormalizer(resourceLoader, urlResolver, htmlParser, config);
|
const normalizer =
|
||||||
const expressionParser = new Parser(new Lexer());
|
new compiler.DirectiveNormalizer(resourceLoader, urlResolver, htmlParser, config);
|
||||||
const elementSchemaRegistry = new DomElementSchemaRegistry();
|
const expressionParser = new compiler.Parser(new compiler.Lexer());
|
||||||
|
const elementSchemaRegistry = new compiler.DomElementSchemaRegistry();
|
||||||
const console = new Console();
|
const console = new Console();
|
||||||
const tmplParser =
|
const tmplParser = new compiler.TemplateParser(
|
||||||
new TemplateParser(expressionParser, elementSchemaRegistry, htmlParser, console, []);
|
expressionParser, elementSchemaRegistry, htmlParser, console, []);
|
||||||
const resolver = new CompileMetadataResolver(
|
const resolver = new compiler.CompileMetadataResolver(
|
||||||
new compiler.NgModuleResolver(staticReflector),
|
new compiler.NgModuleResolver(staticReflector),
|
||||||
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
|
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
|
||||||
elementSchemaRegistry, staticReflector);
|
elementSchemaRegistry, staticReflector);
|
||||||
// TODO(vicb): do not pass cliOptions.i18nFormat here
|
// TODO(vicb): do not pass cliOptions.i18nFormat here
|
||||||
const offlineCompiler = new compiler.OfflineCompiler(
|
const offlineCompiler = new compiler.OfflineCompiler(
|
||||||
resolver, normalizer, tmplParser, new StyleCompiler(urlResolver), new ViewCompiler(config),
|
resolver, normalizer, tmplParser, new compiler.StyleCompiler(urlResolver),
|
||||||
new NgModuleCompiler(), new TypeScriptEmitter(reflectorHost), cliOptions.locale,
|
new compiler.ViewCompiler(config, elementSchemaRegistry),
|
||||||
cliOptions.i18nFormat);
|
new compiler.DirectiveWrapperCompiler(
|
||||||
|
config, expressionParser, elementSchemaRegistry, console),
|
||||||
|
new compiler.NgModuleCompiler(), new compiler.TypeScriptEmitter(reflectorHost),
|
||||||
|
cliOptions.locale, cliOptions.i18nFormat);
|
||||||
|
|
||||||
return new CodeGenerator(
|
return new CodeGenerator(
|
||||||
options, program, compilerHost, staticReflector, offlineCompiler, reflectorHost);
|
options, program, compilerHost, staticReflector, offlineCompiler, reflectorHost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FileMetadata {
|
export function extractProgramSymbols(
|
||||||
fileUrl: string;
|
program: ts.Program, staticReflector: StaticReflector, reflectorHost: StaticReflectorHost,
|
||||||
components: StaticSymbol[];
|
options: AngularCompilerOptions): StaticSymbol[] {
|
||||||
ngModules: StaticSymbol[];
|
// Compare with false since the default should be true
|
||||||
|
const skipFileNames =
|
||||||
|
options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES : GENERATED_FILES;
|
||||||
|
|
||||||
|
const staticSymbols: StaticSymbol[] = [];
|
||||||
|
|
||||||
|
program.getSourceFiles()
|
||||||
|
.filter(sourceFile => !skipFileNames.test(sourceFile.fileName))
|
||||||
|
.forEach(sourceFile => {
|
||||||
|
const absSrcPath = reflectorHost.getCanonicalFileName(sourceFile.fileName);
|
||||||
|
|
||||||
|
const moduleMetadata = staticReflector.getModuleMetadata(absSrcPath);
|
||||||
|
if (!moduleMetadata) {
|
||||||
|
console.log(`WARNING: no metadata found for ${absSrcPath}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const metadata = moduleMetadata['metadata'];
|
||||||
|
|
||||||
|
if (!metadata) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const symbol of Object.keys(metadata)) {
|
||||||
|
if (metadata[symbol] && metadata[symbol].__symbolic == 'error') {
|
||||||
|
// Ignore symbols that are only included to record error information.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
staticSymbols.push(reflectorHost.findDeclaration(absSrcPath, symbol, absSrcPath));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return staticSymbols;
|
||||||
}
|
}
|
@ -10,28 +10,32 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract i18n messages from source code
|
* Extract i18n messages from source code
|
||||||
*
|
|
||||||
* TODO(vicb): factorize code with the CodeGenerator
|
|
||||||
*/
|
*/
|
||||||
// Must be imported first, because angular2 decorators throws on load.
|
// Must be imported first, because angular2 decorators throws on load.
|
||||||
import 'reflect-metadata';
|
import 'reflect-metadata';
|
||||||
|
|
||||||
import * as compiler from '@angular/compiler';
|
import * as compiler from '@angular/compiler';
|
||||||
import {Component, NgModule, ViewEncapsulation} from '@angular/core';
|
import * as tsc from '@angular/tsc-wrapped';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import * as tsc from '@angular/tsc-wrapped';
|
|
||||||
import {CompileMetadataResolver, DirectiveNormalizer, DomElementSchemaRegistry, HtmlParser, Lexer, NgModuleCompiler, Parser, StyleCompiler, TemplateParser, TypeScriptEmitter, ViewCompiler, ParseError} from './private_import_compiler';
|
import {Extractor} from './extractor';
|
||||||
import {Console} from './private_import_core';
|
|
||||||
import {ReflectorHost, ReflectorHostContext} from './reflector_host';
|
|
||||||
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
|
|
||||||
import {StaticReflector, StaticSymbol} from './static_reflector';
|
|
||||||
|
|
||||||
function extract(
|
function extract(
|
||||||
ngOptions: tsc.AngularCompilerOptions, cliOptions: tsc.I18nExtractionCliOptions,
|
ngOptions: tsc.AngularCompilerOptions, cliOptions: tsc.I18nExtractionCliOptions,
|
||||||
program: ts.Program, host: ts.CompilerHost) {
|
program: ts.Program, host: ts.CompilerHost) {
|
||||||
const htmlParser = new compiler.I18NHtmlParser(new HtmlParser());
|
const resourceLoader: compiler.ResourceLoader = {
|
||||||
const extractor = Extractor.create(ngOptions, cliOptions.i18nFormat, program, host, htmlParser);
|
get: (s: string) => {
|
||||||
|
if (!host.fileExists(s)) {
|
||||||
|
// TODO: We should really have a test for error cases like this!
|
||||||
|
throw new Error(`Compilation failed. Resource file not found: ${s}`);
|
||||||
|
}
|
||||||
|
return Promise.resolve(host.readFile(s));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const extractor =
|
||||||
|
Extractor.create(ngOptions, cliOptions.i18nFormat, program, host, resourceLoader);
|
||||||
|
|
||||||
const bundlePromise: Promise<compiler.MessageBundle> = extractor.extract();
|
const bundlePromise: Promise<compiler.MessageBundle> = extractor.extract();
|
||||||
|
|
||||||
return (bundlePromise).then(messageBundle => {
|
return (bundlePromise).then(messageBundle => {
|
||||||
@ -47,6 +51,7 @@ function extract(
|
|||||||
case 'xliff':
|
case 'xliff':
|
||||||
case 'xlf':
|
case 'xlf':
|
||||||
default:
|
default:
|
||||||
|
const htmlParser = new compiler.I18NHtmlParser(new compiler.HtmlParser());
|
||||||
ext = 'xlf';
|
ext = 'xlf';
|
||||||
serializer = new compiler.Xliff(htmlParser, compiler.DEFAULT_INTERPOLATION_CONFIG);
|
serializer = new compiler.Xliff(htmlParser, compiler.DEFAULT_INTERPOLATION_CONFIG);
|
||||||
break;
|
break;
|
||||||
@ -57,146 +62,6 @@ function extract(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const GENERATED_FILES = /\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
|
||||||
|
|
||||||
export class Extractor {
|
|
||||||
constructor(
|
|
||||||
private program: ts.Program, public host: ts.CompilerHost,
|
|
||||||
private staticReflector: StaticReflector, private messageBundle: compiler.MessageBundle,
|
|
||||||
private reflectorHost: ReflectorHost, private metadataResolver: CompileMetadataResolver,
|
|
||||||
private directiveNormalizer: DirectiveNormalizer,
|
|
||||||
private compiler: compiler.OfflineCompiler) {}
|
|
||||||
|
|
||||||
private readFileMetadata(absSourcePath: string): FileMetadata {
|
|
||||||
const moduleMetadata = this.staticReflector.getModuleMetadata(absSourcePath);
|
|
||||||
const result: FileMetadata = {components: [], ngModules: [], fileUrl: absSourcePath};
|
|
||||||
if (!moduleMetadata) {
|
|
||||||
console.log(`WARNING: no metadata found for ${absSourcePath}`);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
const metadata = moduleMetadata['metadata'];
|
|
||||||
const symbols = metadata && Object.keys(metadata);
|
|
||||||
if (!symbols || !symbols.length) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
for (const symbol of symbols) {
|
|
||||||
if (metadata[symbol] && metadata[symbol].__symbolic == 'error') {
|
|
||||||
// Ignore symbols that are only included to record error information.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const staticType = this.reflectorHost.findDeclaration(absSourcePath, symbol, absSourcePath);
|
|
||||||
const annotations = this.staticReflector.annotations(staticType);
|
|
||||||
annotations.forEach((annotation) => {
|
|
||||||
if (annotation instanceof NgModule) {
|
|
||||||
result.ngModules.push(staticType);
|
|
||||||
} else if (annotation instanceof Component) {
|
|
||||||
result.components.push(staticType);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
extract(): Promise<compiler.MessageBundle> {
|
|
||||||
const filePaths =
|
|
||||||
this.program.getSourceFiles().map(sf => sf.fileName).filter(f => !GENERATED_FILES.test(f));
|
|
||||||
const fileMetas = filePaths.map((filePath) => this.readFileMetadata(filePath));
|
|
||||||
const ngModules = fileMetas.reduce((ngModules, fileMeta) => {
|
|
||||||
ngModules.push(...fileMeta.ngModules);
|
|
||||||
return ngModules;
|
|
||||||
}, <StaticSymbol[]>[]);
|
|
||||||
const analyzedNgModules = this.compiler.analyzeModules(ngModules);
|
|
||||||
const errors: ParseError[] = [];
|
|
||||||
|
|
||||||
let bundlePromise =
|
|
||||||
Promise
|
|
||||||
.all(fileMetas.map((fileMeta) => {
|
|
||||||
const url = fileMeta.fileUrl;
|
|
||||||
return Promise.all(fileMeta.components.map(compType => {
|
|
||||||
const compMeta = this.metadataResolver.getDirectiveMetadata(<any>compType);
|
|
||||||
const ngModule = analyzedNgModules.ngModuleByComponent.get(compType);
|
|
||||||
if (!ngModule) {
|
|
||||||
throw new Error(
|
|
||||||
`Cannot determine the module for component ${compMeta.type.name}!`);
|
|
||||||
}
|
|
||||||
return Promise
|
|
||||||
.all([compMeta, ...ngModule.transitiveModule.directives].map(
|
|
||||||
dirMeta =>
|
|
||||||
this.directiveNormalizer.normalizeDirective(dirMeta).asyncResult))
|
|
||||||
.then((normalizedCompWithDirectives) => {
|
|
||||||
const compMeta = normalizedCompWithDirectives[0];
|
|
||||||
const html = compMeta.template.template;
|
|
||||||
const interpolationConfig =
|
|
||||||
compiler.InterpolationConfig.fromArray(compMeta.template.interpolation);
|
|
||||||
errors.push(
|
|
||||||
...this.messageBundle.updateFromTemplate(html, url, interpolationConfig));
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
}))
|
|
||||||
.then(_ => this.messageBundle);
|
|
||||||
|
|
||||||
if (errors.length) {
|
|
||||||
throw new Error(errors.map(e => e.toString()).join('\n'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return bundlePromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
static create(
|
|
||||||
options: tsc.AngularCompilerOptions, translationsFormat: string, program: ts.Program,
|
|
||||||
compilerHost: ts.CompilerHost, htmlParser: compiler.I18NHtmlParser,
|
|
||||||
reflectorHostContext?: ReflectorHostContext): Extractor {
|
|
||||||
const resourceLoader: compiler.ResourceLoader = {
|
|
||||||
get: (s: string) => {
|
|
||||||
if (!compilerHost.fileExists(s)) {
|
|
||||||
// TODO: We should really have a test for error cases like this!
|
|
||||||
throw new Error(`Compilation failed. Resource file not found: ${s}`);
|
|
||||||
}
|
|
||||||
return Promise.resolve(compilerHost.readFile(s));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
|
|
||||||
const reflectorHost = new ReflectorHost(program, compilerHost, options, reflectorHostContext);
|
|
||||||
const staticReflector = new StaticReflector(reflectorHost);
|
|
||||||
StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
|
||||||
|
|
||||||
const config = new compiler.CompilerConfig({
|
|
||||||
genDebugInfo: options.debug === true,
|
|
||||||
defaultEncapsulation: ViewEncapsulation.Emulated,
|
|
||||||
logBindingUpdate: false,
|
|
||||||
useJit: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const normalizer = new DirectiveNormalizer(resourceLoader, urlResolver, htmlParser, config);
|
|
||||||
const expressionParser = new Parser(new Lexer());
|
|
||||||
const elementSchemaRegistry = new DomElementSchemaRegistry();
|
|
||||||
const console = new Console();
|
|
||||||
const tmplParser =
|
|
||||||
new TemplateParser(expressionParser, elementSchemaRegistry, htmlParser, console, []);
|
|
||||||
const resolver = new CompileMetadataResolver(
|
|
||||||
new compiler.NgModuleResolver(staticReflector),
|
|
||||||
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
|
|
||||||
elementSchemaRegistry, staticReflector);
|
|
||||||
const offlineCompiler = new compiler.OfflineCompiler(
|
|
||||||
resolver, normalizer, tmplParser, new StyleCompiler(urlResolver), new ViewCompiler(config),
|
|
||||||
new NgModuleCompiler(), new TypeScriptEmitter(reflectorHost), null, null);
|
|
||||||
|
|
||||||
// TODO(vicb): implicit tags & attributes
|
|
||||||
let messageBundle = new compiler.MessageBundle(htmlParser, [], {});
|
|
||||||
|
|
||||||
return new Extractor(
|
|
||||||
program, compilerHost, staticReflector, messageBundle, reflectorHost, resolver, normalizer,
|
|
||||||
offlineCompiler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface FileMetadata {
|
|
||||||
fileUrl: string;
|
|
||||||
components: StaticSymbol[];
|
|
||||||
ngModules: StaticSymbol[];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entry point
|
// Entry point
|
||||||
if (require.main === module) {
|
if (require.main === module) {
|
||||||
const args = require('minimist')(process.argv.slice(2));
|
const args = require('minimist')(process.argv.slice(2));
|
||||||
|
110
modules/@angular/compiler-cli/src/extractor.ts
Normal file
110
modules/@angular/compiler-cli/src/extractor.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract i18n messages from source code
|
||||||
|
*/
|
||||||
|
// Must be imported first, because angular2 decorators throws on load.
|
||||||
|
import 'reflect-metadata';
|
||||||
|
|
||||||
|
import * as compiler from '@angular/compiler';
|
||||||
|
import {ViewEncapsulation} from '@angular/core';
|
||||||
|
import * as tsc from '@angular/tsc-wrapped';
|
||||||
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
|
import {extractProgramSymbols} from './codegen';
|
||||||
|
import {ReflectorHost} from './reflector_host';
|
||||||
|
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
|
||||||
|
import {StaticReflector, StaticSymbol} from './static_reflector';
|
||||||
|
|
||||||
|
export class Extractor {
|
||||||
|
constructor(
|
||||||
|
private options: tsc.AngularCompilerOptions, private program: ts.Program,
|
||||||
|
public host: ts.CompilerHost, private staticReflector: StaticReflector,
|
||||||
|
private messageBundle: compiler.MessageBundle, private reflectorHost: ReflectorHost,
|
||||||
|
private metadataResolver: compiler.CompileMetadataResolver,
|
||||||
|
private directiveNormalizer: compiler.DirectiveNormalizer) {}
|
||||||
|
|
||||||
|
extract(): Promise<compiler.MessageBundle> {
|
||||||
|
const programSymbols: StaticSymbol[] =
|
||||||
|
extractProgramSymbols(this.program, this.staticReflector, this.reflectorHost, this.options);
|
||||||
|
|
||||||
|
const files =
|
||||||
|
compiler.analyzeNgModules(programSymbols, {transitiveModules: true}, this.metadataResolver)
|
||||||
|
.files;
|
||||||
|
const errors: compiler.ParseError[] = [];
|
||||||
|
const filePromises: Promise<any>[] = [];
|
||||||
|
|
||||||
|
files.forEach(file => {
|
||||||
|
const cmpPromises: Promise<compiler.CompileDirectiveMetadata>[] = [];
|
||||||
|
file.directives.forEach(directiveType => {
|
||||||
|
const dirMeta = this.metadataResolver.getDirectiveMetadata(directiveType);
|
||||||
|
if (dirMeta.isComponent) {
|
||||||
|
cmpPromises.push(this.directiveNormalizer.normalizeDirective(dirMeta).asyncResult);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (cmpPromises.length) {
|
||||||
|
const done =
|
||||||
|
Promise.all(cmpPromises).then((compMetas: compiler.CompileDirectiveMetadata[]) => {
|
||||||
|
compMetas.forEach(compMeta => {
|
||||||
|
const html = compMeta.template.template;
|
||||||
|
const interpolationConfig =
|
||||||
|
compiler.InterpolationConfig.fromArray(compMeta.template.interpolation);
|
||||||
|
errors.push(...this.messageBundle.updateFromTemplate(
|
||||||
|
html, file.srcUrl, interpolationConfig));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
filePromises.push(done);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (errors.length) {
|
||||||
|
throw new Error(errors.map(e => e.toString()).join('\n'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(filePromises).then(_ => this.messageBundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static create(
|
||||||
|
options: tsc.AngularCompilerOptions, translationsFormat: string, program: ts.Program,
|
||||||
|
compilerHost: ts.CompilerHost, resourceLoader: compiler.ResourceLoader,
|
||||||
|
reflectorHost?: ReflectorHost): Extractor {
|
||||||
|
const htmlParser = new compiler.I18NHtmlParser(new compiler.HtmlParser());
|
||||||
|
|
||||||
|
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
|
||||||
|
if (!reflectorHost) reflectorHost = new ReflectorHost(program, compilerHost, options);
|
||||||
|
const staticReflector = new StaticReflector(reflectorHost);
|
||||||
|
StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
||||||
|
|
||||||
|
const config = new compiler.CompilerConfig({
|
||||||
|
genDebugInfo: options.debug === true,
|
||||||
|
defaultEncapsulation: ViewEncapsulation.Emulated,
|
||||||
|
logBindingUpdate: false,
|
||||||
|
useJit: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const normalizer =
|
||||||
|
new compiler.DirectiveNormalizer(resourceLoader, urlResolver, htmlParser, config);
|
||||||
|
const elementSchemaRegistry = new compiler.DomElementSchemaRegistry();
|
||||||
|
const resolver = new compiler.CompileMetadataResolver(
|
||||||
|
new compiler.NgModuleResolver(staticReflector),
|
||||||
|
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
|
||||||
|
elementSchemaRegistry, staticReflector);
|
||||||
|
|
||||||
|
// TODO(vicb): implicit tags & attributes
|
||||||
|
let messageBundle = new compiler.MessageBundle(htmlParser, [], {});
|
||||||
|
|
||||||
|
return new Extractor(
|
||||||
|
options, program, compilerHost, staticReflector, messageBundle, reflectorHost, resolver,
|
||||||
|
normalizer);
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,9 @@ import {CodeGenerator} from './codegen';
|
|||||||
function codegen(
|
function codegen(
|
||||||
ngOptions: tsc.AngularCompilerOptions, cliOptions: tsc.NgcCliOptions, program: ts.Program,
|
ngOptions: tsc.AngularCompilerOptions, cliOptions: tsc.NgcCliOptions, program: ts.Program,
|
||||||
host: ts.CompilerHost) {
|
host: ts.CompilerHost) {
|
||||||
return CodeGenerator.create(ngOptions, cliOptions, program, host).codegen();
|
return CodeGenerator.create(ngOptions, cliOptions, program, host).codegen({
|
||||||
|
transitiveModules: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// CLI entry point
|
// CLI entry point
|
||||||
|
@ -1,54 +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 {__compiler_private__ as _} from '@angular/compiler';
|
|
||||||
|
|
||||||
export type AssetUrl = typeof _._AssetUrl;
|
|
||||||
export var AssetUrl: typeof _.AssetUrl = _.AssetUrl;
|
|
||||||
|
|
||||||
export type ImportGenerator = typeof _._ImportGenerator;
|
|
||||||
export var ImportGenerator: typeof _.ImportGenerator = _.ImportGenerator;
|
|
||||||
|
|
||||||
export type CompileMetadataResolver = typeof _._CompileMetadataResolver;
|
|
||||||
export var CompileMetadataResolver: typeof _.CompileMetadataResolver = _.CompileMetadataResolver;
|
|
||||||
|
|
||||||
export type HtmlParser = typeof _._HtmlParser;
|
|
||||||
export var HtmlParser: typeof _.HtmlParser = _.HtmlParser;
|
|
||||||
|
|
||||||
export type ParseError = typeof _._ParseError;
|
|
||||||
export var ParseError: typeof _.ParseError = _.ParseError;
|
|
||||||
|
|
||||||
export type InterpolationConfig = typeof _._InterpolationConfig;
|
|
||||||
export var InterpolationConfig: typeof _.InterpolationConfig = _.InterpolationConfig;
|
|
||||||
|
|
||||||
export type DirectiveNormalizer = typeof _._DirectiveNormalizer;
|
|
||||||
export var DirectiveNormalizer: typeof _.DirectiveNormalizer = _.DirectiveNormalizer;
|
|
||||||
|
|
||||||
export type Lexer = typeof _._Lexer;
|
|
||||||
export var Lexer: typeof _.Lexer = _.Lexer;
|
|
||||||
|
|
||||||
export type Parser = typeof _._Parser;
|
|
||||||
export var Parser: typeof _.Parser = _.Parser;
|
|
||||||
|
|
||||||
export type TemplateParser = typeof _._TemplateParser;
|
|
||||||
export var TemplateParser: typeof _.TemplateParser = _.TemplateParser;
|
|
||||||
|
|
||||||
export type DomElementSchemaRegistry = typeof _._DomElementSchemaRegistry;
|
|
||||||
export var DomElementSchemaRegistry: typeof _.DomElementSchemaRegistry = _.DomElementSchemaRegistry;
|
|
||||||
|
|
||||||
export type StyleCompiler = typeof _._StyleCompiler;
|
|
||||||
export var StyleCompiler: typeof _.StyleCompiler = _.StyleCompiler;
|
|
||||||
|
|
||||||
export type ViewCompiler = typeof _._ViewCompiler;
|
|
||||||
export var ViewCompiler: typeof _.ViewCompiler = _.ViewCompiler;
|
|
||||||
|
|
||||||
export type NgModuleCompiler = typeof _._NgModuleCompiler;
|
|
||||||
export var NgModuleCompiler: typeof _.NgModuleCompiler = _.NgModuleCompiler;
|
|
||||||
|
|
||||||
export type TypeScriptEmitter = typeof _._TypeScriptEmitter;
|
|
||||||
export var TypeScriptEmitter: typeof _.TypeScriptEmitter = _.TypeScriptEmitter;
|
|
@ -6,12 +6,12 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {AssetUrl, ImportGenerator} from '@angular/compiler';
|
||||||
import {AngularCompilerOptions, MetadataCollector, ModuleMetadata} from '@angular/tsc-wrapped';
|
import {AngularCompilerOptions, MetadataCollector, ModuleMetadata} from '@angular/tsc-wrapped';
|
||||||
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';
|
||||||
|
|
||||||
import {AssetUrl, ImportGenerator} from './private_import_compiler';
|
|
||||||
import {StaticReflectorHost, StaticSymbol} from './static_reflector';
|
import {StaticReflectorHost, StaticSymbol} from './static_reflector';
|
||||||
|
|
||||||
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
||||||
@ -250,6 +250,12 @@ export class ReflectorHost implements StaticReflectorHost, ImportGenerator {
|
|||||||
} else {
|
} else {
|
||||||
const sf = this.program.getSourceFile(filePath);
|
const sf = this.program.getSourceFile(filePath);
|
||||||
if (!sf) {
|
if (!sf) {
|
||||||
|
if (this.context.fileExists(filePath)) {
|
||||||
|
const sourceText = this.context.readFile(filePath);
|
||||||
|
return this.metadataCollector.getMetadata(
|
||||||
|
ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true));
|
||||||
|
}
|
||||||
|
|
||||||
throw new Error(`Source file ${filePath} not present in program.`);
|
throw new Error(`Source file ${filePath} not present in program.`);
|
||||||
}
|
}
|
||||||
return this.metadataCollector.getMetadata(sf);
|
return this.metadataCollector.getMetadata(sf);
|
||||||
|
@ -20,11 +20,10 @@ export class StaticAndDynamicReflectionCapabilities {
|
|||||||
|
|
||||||
isReflectionEnabled(): boolean { return true; }
|
isReflectionEnabled(): boolean { return true; }
|
||||||
factory(type: any): Function { return this.dynamicDelegate.factory(type); }
|
factory(type: any): Function { return this.dynamicDelegate.factory(type); }
|
||||||
interfaces(type: any): any[] { return this.dynamicDelegate.interfaces(type); }
|
|
||||||
hasLifecycleHook(type: any, lcInterface: /*Type*/ any, lcProperty: string): boolean {
|
hasLifecycleHook(type: any, lcProperty: string): boolean {
|
||||||
return isStaticType(type) ?
|
return isStaticType(type) ? this.staticDelegate.hasLifecycleHook(type, lcProperty) :
|
||||||
this.staticDelegate.hasLifecycleHook(type, lcInterface, lcProperty) :
|
this.dynamicDelegate.hasLifecycleHook(type, lcProperty);
|
||||||
this.dynamicDelegate.hasLifecycleHook(type, lcInterface, lcProperty);
|
|
||||||
}
|
}
|
||||||
parameters(type: any): any[][] {
|
parameters(type: any): any[][] {
|
||||||
return isStaticType(type) ? this.staticDelegate.parameters(type) :
|
return isStaticType(type) ? this.staticDelegate.parameters(type) :
|
||||||
|
@ -25,7 +25,7 @@ export interface StaticReflectorHost {
|
|||||||
* @param modulePath is a string identifier for a module as an absolute path.
|
* @param modulePath is a string identifier for a module as an absolute path.
|
||||||
* @returns the metadata for the given module.
|
* @returns the metadata for the given module.
|
||||||
*/
|
*/
|
||||||
getMetadataFor(modulePath: string): {[key: string]: any};
|
getMetadataFor(modulePath: string): {[key: string]: any}|{[key: string]: any}[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve a symbol from an import statement form, to the file where it is declared.
|
* Resolve a symbol from an import statement form, to the file where it is declared.
|
||||||
@ -44,6 +44,8 @@ export interface StaticReflectorHost {
|
|||||||
animationMetadata: string,
|
animationMetadata: string,
|
||||||
provider: string
|
provider: string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getCanonicalFileName(fileName: string): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,13 +72,12 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
constructor(private host: StaticReflectorHost) { this.initializeConversionMap(); }
|
constructor(private host: StaticReflectorHost) { this.initializeConversionMap(); }
|
||||||
|
|
||||||
importUri(typeOrFunc: StaticSymbol): string {
|
importUri(typeOrFunc: StaticSymbol): string {
|
||||||
var staticSymbol = this.host.findDeclaration(typeOrFunc.filePath, typeOrFunc.name, '');
|
const staticSymbol = this.host.findDeclaration(typeOrFunc.filePath, typeOrFunc.name, '');
|
||||||
return staticSymbol ? staticSymbol.filePath : null;
|
return staticSymbol ? staticSymbol.filePath : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveIdentifier(name: string, moduleUrl: string, runtime: any): any {
|
resolveIdentifier(name: string, moduleUrl: string, runtime: any): any {
|
||||||
const result = this.host.findDeclaration(moduleUrl, name, '');
|
return this.host.findDeclaration(moduleUrl, name, '');
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveEnum(enumIdentifier: any, name: string): any {
|
resolveEnum(enumIdentifier: any, name: string): any {
|
||||||
@ -157,14 +158,15 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasLifecycleHook(type: any, lcInterface: /*Type*/ any, lcProperty: string): boolean {
|
hasLifecycleHook(type: any, lcProperty: string): boolean {
|
||||||
if (!(type instanceof StaticSymbol)) {
|
if (!(type instanceof StaticSymbol)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`hasLifecycleHook received ${JSON.stringify(type)} which is not a StaticSymbol`);
|
`hasLifecycleHook received ${JSON.stringify(type)} which is not a StaticSymbol`);
|
||||||
}
|
}
|
||||||
let classMetadata = this.getTypeMetadata(type);
|
const classMetadata = this.getTypeMetadata(type);
|
||||||
let members = classMetadata ? classMetadata['members'] : null;
|
const members = classMetadata ? classMetadata['members'] : null;
|
||||||
let member: any[] = members ? members[lcProperty] : null;
|
const member: any[] =
|
||||||
|
members && members.hasOwnProperty(lcProperty) ? members[lcProperty] : null;
|
||||||
return member ? member.some(a => a['__symbolic'] == 'method') : false;
|
return member ? member.some(a => a['__symbolic'] == 'method') : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,9 +237,9 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
public simplify(context: StaticSymbol, value: any): any {
|
public simplify(context: StaticSymbol, value: any): any {
|
||||||
let _this = this;
|
const _this = this;
|
||||||
let scope = BindingScope.empty;
|
let scope = BindingScope.empty;
|
||||||
let calling = new Map<StaticSymbol, boolean>();
|
const calling = new Map<StaticSymbol, boolean>();
|
||||||
|
|
||||||
function simplifyInContext(context: StaticSymbol, value: any, depth: number): any {
|
function simplifyInContext(context: StaticSymbol, value: any, depth: number): any {
|
||||||
function resolveReference(context: StaticSymbol, expression: any): StaticSymbol {
|
function resolveReference(context: StaticSymbol, expression: any): StaticSymbol {
|
||||||
@ -252,16 +254,15 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resolveReferenceValue(staticSymbol: StaticSymbol): any {
|
function resolveReferenceValue(staticSymbol: StaticSymbol): any {
|
||||||
let result: any = staticSymbol;
|
const moduleMetadata = _this.getModuleMetadata(staticSymbol.filePath);
|
||||||
let moduleMetadata = _this.getModuleMetadata(staticSymbol.filePath);
|
const declarationValue =
|
||||||
let declarationValue =
|
|
||||||
moduleMetadata ? moduleMetadata['metadata'][staticSymbol.name] : null;
|
moduleMetadata ? moduleMetadata['metadata'][staticSymbol.name] : null;
|
||||||
return declarationValue;
|
return declarationValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isOpaqueToken(context: StaticSymbol, value: any): boolean {
|
function isOpaqueToken(context: StaticSymbol, value: any): boolean {
|
||||||
if (value && value.__symbolic === 'new' && value.expression) {
|
if (value && value.__symbolic === 'new' && value.expression) {
|
||||||
let target = value.expression;
|
const target = value.expression;
|
||||||
if (target.__symbolic == 'reference') {
|
if (target.__symbolic == 'reference') {
|
||||||
return sameSymbol(resolveReference(context, target), _this.opaqueToken);
|
return sameSymbol(resolveReference(context, target), _this.opaqueToken);
|
||||||
}
|
}
|
||||||
@ -366,6 +367,9 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
if (expression instanceof StaticSymbol) {
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
if (expression) {
|
if (expression) {
|
||||||
if (expression['__symbolic']) {
|
if (expression['__symbolic']) {
|
||||||
let staticSymbol: StaticSymbol;
|
let staticSymbol: StaticSymbol;
|
||||||
@ -529,7 +533,7 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = simplifyInContext(context, value, 0);
|
const result = simplifyInContext(context, value, 0);
|
||||||
if (shouldIgnore(result)) {
|
if (shouldIgnore(result)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -544,8 +548,7 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
if (!moduleMetadata) {
|
if (!moduleMetadata) {
|
||||||
moduleMetadata = this.host.getMetadataFor(module);
|
moduleMetadata = this.host.getMetadataFor(module);
|
||||||
if (Array.isArray(moduleMetadata)) {
|
if (Array.isArray(moduleMetadata)) {
|
||||||
moduleMetadata = (<Array<any>>moduleMetadata)
|
moduleMetadata = moduleMetadata.find(md => md['version'] === SUPPORTED_SCHEMA_VERSION) ||
|
||||||
.find(element => element.version === SUPPORTED_SCHEMA_VERSION) ||
|
|
||||||
moduleMetadata[0];
|
moduleMetadata[0];
|
||||||
}
|
}
|
||||||
if (!moduleMetadata) {
|
if (!moduleMetadata) {
|
||||||
@ -562,12 +565,8 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getTypeMetadata(type: StaticSymbol): {[key: string]: any} {
|
private getTypeMetadata(type: StaticSymbol): {[key: string]: any} {
|
||||||
let moduleMetadata = this.getModuleMetadata(type.filePath);
|
const moduleMetadata = this.getModuleMetadata(type.filePath);
|
||||||
let result = moduleMetadata['metadata'][type.name];
|
return moduleMetadata['metadata'][type.name] || {__symbolic: 'class'};
|
||||||
if (!result) {
|
|
||||||
result = {__symbolic: 'class'};
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,7 +606,7 @@ function produceErrorMessage(error: any): string {
|
|||||||
function mapStringMap(input: {[key: string]: any}, transform: (value: any, key: string) => any):
|
function mapStringMap(input: {[key: string]: any}, transform: (value: any, key: string) => any):
|
||||||
{[key: string]: any} {
|
{[key: string]: any} {
|
||||||
if (!input) return {};
|
if (!input) return {};
|
||||||
var result: {[key: string]: any} = {};
|
const result: {[key: string]: any} = {};
|
||||||
Object.keys(input).forEach((key) => {
|
Object.keys(input).forEach((key) => {
|
||||||
let value = transform(input[key], key);
|
let value = transform(input[key], key);
|
||||||
if (!shouldIgnore(value)) {
|
if (!shouldIgnore(value)) {
|
||||||
@ -632,8 +631,7 @@ abstract class BindingScope {
|
|||||||
public static empty: BindingScope = {resolve: name => BindingScope.missing};
|
public static empty: BindingScope = {resolve: name => BindingScope.missing};
|
||||||
|
|
||||||
public static build(): BindingScopeBuilder {
|
public static build(): BindingScopeBuilder {
|
||||||
let current = new Map<string, any>();
|
const current = new Map<string, any>();
|
||||||
let parent: BindingScope = undefined;
|
|
||||||
return {
|
return {
|
||||||
define: function(name, value) {
|
define: function(name, value) {
|
||||||
current.set(name, value);
|
current.set(name, value);
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
import {StaticReflector, StaticReflectorHost, StaticSymbol} from '@angular/compiler-cli/src/static_reflector';
|
import {StaticReflector, StaticReflectorHost, StaticSymbol} from '@angular/compiler-cli/src/static_reflector';
|
||||||
import {HostListener, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
|
import {HostListener, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
|
||||||
import {ListWrapper} from '@angular/facade/src/collection';
|
|
||||||
import {MetadataCollector} from '@angular/tsc-wrapped';
|
import {MetadataCollector} from '@angular/tsc-wrapped';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
@ -119,6 +118,11 @@ describe('StaticReflector', () => {
|
|||||||
expect(simplify(noContext, 'some value')).toBe('some value');
|
expect(simplify(noContext, 'some value')).toBe('some value');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should simplify a static symbol into itself', () => {
|
||||||
|
const staticSymbol = new StaticSymbol('', '');
|
||||||
|
expect(simplify(noContext, staticSymbol)).toBe(staticSymbol);
|
||||||
|
});
|
||||||
|
|
||||||
it('should simplify an array into a copy of the array', () => {
|
it('should simplify an array into a copy of the array', () => {
|
||||||
expect(simplify(noContext, [1, 2, 3])).toEqual([1, 2, 3]);
|
expect(simplify(noContext, [1, 2, 3])).toEqual([1, 2, 3]);
|
||||||
});
|
});
|
||||||
@ -450,6 +454,9 @@ class MockReflectorHost implements StaticReflectorHost {
|
|||||||
provider: 'angular2/src/core/di/provider'
|
provider: 'angular2/src/core/di/provider'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCanonicalFileName(fileName: string): string { return fileName; }
|
||||||
|
|
||||||
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
||||||
var cacheKey = `${declarationFile}:${name}${members?'.'+members.join('.'):''}`;
|
var cacheKey = `${declarationFile}:${name}${members?'.'+members.join('.'):''}`;
|
||||||
var result = this.staticTypeCache.get(cacheKey);
|
var result = this.staticTypeCache.get(cacheKey);
|
||||||
@ -466,7 +473,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
|||||||
|
|
||||||
function resolvePath(pathParts: string[]): string {
|
function resolvePath(pathParts: string[]): string {
|
||||||
let result: string[] = [];
|
let result: string[] = [];
|
||||||
ListWrapper.forEachWithIndex(pathParts, (part, index) => {
|
pathParts.forEach((part, index) => {
|
||||||
switch (part) {
|
switch (part) {
|
||||||
case '':
|
case '':
|
||||||
case '.':
|
case '.':
|
||||||
|
@ -21,6 +21,36 @@
|
|||||||
* </p>
|
* </p>
|
||||||
* </div>
|
* </div>
|
||||||
*/
|
*/
|
||||||
export * from './src/index';
|
export * from './src/template_parser/template_ast';
|
||||||
|
export {TEMPLATE_TRANSFORMS} from './src/template_parser/template_parser';
|
||||||
|
export {CompilerConfig, RenderTypes} from './src/config';
|
||||||
|
export * from './src/compile_metadata';
|
||||||
|
export * from './src/offline_compiler';
|
||||||
|
export {RuntimeCompiler} from './src/runtime_compiler';
|
||||||
|
export * from './src/url_resolver';
|
||||||
|
export * from './src/resource_loader';
|
||||||
|
export * from './src/compiler';
|
||||||
|
export {DirectiveResolver} from './src/directive_resolver';
|
||||||
|
export {PipeResolver} from './src/pipe_resolver';
|
||||||
|
export {NgModuleResolver} from './src/ng_module_resolver';
|
||||||
|
export {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from './src/ml_parser/interpolation_config';
|
||||||
|
export * from './src/schema/element_schema_registry';
|
||||||
|
export * from './src/i18n/index';
|
||||||
|
export * from './src/directive_normalizer';
|
||||||
|
export * from './src/expression_parser/lexer';
|
||||||
|
export * from './src/expression_parser/parser';
|
||||||
|
export * from './src/metadata_resolver';
|
||||||
|
export * from './src/ml_parser/html_parser';
|
||||||
|
export * from './src/ml_parser/interpolation_config';
|
||||||
|
export {NgModuleCompiler} from './src/ng_module_compiler';
|
||||||
|
export {DirectiveWrapperCompiler} from './src/directive_wrapper_compiler';
|
||||||
|
export * from './src/output/path_util';
|
||||||
|
export * from './src/output/ts_emitter';
|
||||||
|
export * from './src/parse_util';
|
||||||
|
export * from './src/schema/dom_element_schema_registry';
|
||||||
|
export * from './src/selector';
|
||||||
|
export * from './src/style_compiler';
|
||||||
|
export * from './src/template_parser/template_parser';
|
||||||
|
export {ViewCompiler} from './src/view_compiler/view_compiler';
|
||||||
|
|
||||||
// This file only reexports content of the `src` folder. Keep it that way.
|
// This file only reexports content of the `src` folder. Keep it that way.
|
||||||
|
@ -32,6 +32,7 @@ export class AnimationCompiler {
|
|||||||
var _ANIMATION_FACTORY_ELEMENT_VAR = o.variable('element');
|
var _ANIMATION_FACTORY_ELEMENT_VAR = o.variable('element');
|
||||||
var _ANIMATION_DEFAULT_STATE_VAR = o.variable('defaultStateStyles');
|
var _ANIMATION_DEFAULT_STATE_VAR = o.variable('defaultStateStyles');
|
||||||
var _ANIMATION_FACTORY_VIEW_VAR = o.variable('view');
|
var _ANIMATION_FACTORY_VIEW_VAR = o.variable('view');
|
||||||
|
var _ANIMATION_FACTORY_VIEW_CONTEXT = _ANIMATION_FACTORY_VIEW_VAR.prop('animationContext');
|
||||||
var _ANIMATION_FACTORY_RENDERER_VAR = _ANIMATION_FACTORY_VIEW_VAR.prop('renderer');
|
var _ANIMATION_FACTORY_RENDERER_VAR = _ANIMATION_FACTORY_VIEW_VAR.prop('renderer');
|
||||||
var _ANIMATION_CURRENT_STATE_VAR = o.variable('currentState');
|
var _ANIMATION_CURRENT_STATE_VAR = o.variable('currentState');
|
||||||
var _ANIMATION_NEXT_STATE_VAR = o.variable('nextState');
|
var _ANIMATION_NEXT_STATE_VAR = o.variable('nextState');
|
||||||
@ -61,7 +62,9 @@ class _AnimationBuilder implements AnimationAstVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ast.styles.forEach(entry => {
|
ast.styles.forEach(entry => {
|
||||||
stylesArr.push(o.literalMap(Object.keys(entry).map(key => [key, o.literal(entry[key])])));
|
const entries =
|
||||||
|
Object.keys(entry).map((key): [string, o.Expression] => [key, o.literal(entry[key])]);
|
||||||
|
stylesArr.push(o.literalMap(entries));
|
||||||
});
|
});
|
||||||
|
|
||||||
return o.importExpr(resolveIdentifier(Identifiers.AnimationStyles)).instantiate([
|
return o.importExpr(resolveIdentifier(Identifiers.AnimationStyles)).instantiate([
|
||||||
@ -184,7 +187,7 @@ class _AnimationBuilder implements AnimationAstVisitor {
|
|||||||
context.stateMap.registerState(DEFAULT_STATE, {});
|
context.stateMap.registerState(DEFAULT_STATE, {});
|
||||||
|
|
||||||
var statements: o.Statement[] = [];
|
var statements: o.Statement[] = [];
|
||||||
statements.push(_ANIMATION_FACTORY_VIEW_VAR
|
statements.push(_ANIMATION_FACTORY_VIEW_CONTEXT
|
||||||
.callMethod(
|
.callMethod(
|
||||||
'cancelActiveAnimation',
|
'cancelActiveAnimation',
|
||||||
[
|
[
|
||||||
@ -261,16 +264,21 @@ class _AnimationBuilder implements AnimationAstVisitor {
|
|||||||
.toStmt()])])
|
.toStmt()])])
|
||||||
.toStmt());
|
.toStmt());
|
||||||
|
|
||||||
statements.push(_ANIMATION_FACTORY_VIEW_VAR
|
statements.push(_ANIMATION_FACTORY_VIEW_CONTEXT
|
||||||
.callMethod(
|
.callMethod(
|
||||||
'queueAnimation',
|
'queueAnimation',
|
||||||
[
|
[
|
||||||
_ANIMATION_FACTORY_ELEMENT_VAR, o.literal(this.animationName),
|
_ANIMATION_FACTORY_ELEMENT_VAR, o.literal(this.animationName),
|
||||||
_ANIMATION_PLAYER_VAR, _ANIMATION_TIME_VAR,
|
_ANIMATION_PLAYER_VAR
|
||||||
_ANIMATION_CURRENT_STATE_VAR, _ANIMATION_NEXT_STATE_VAR
|
|
||||||
])
|
])
|
||||||
.toStmt());
|
.toStmt());
|
||||||
|
|
||||||
|
statements.push(new o.ReturnStatement(
|
||||||
|
o.importExpr(resolveIdentifier(Identifiers.AnimationTransition)).instantiate([
|
||||||
|
_ANIMATION_PLAYER_VAR, _ANIMATION_CURRENT_STATE_VAR, _ANIMATION_NEXT_STATE_VAR,
|
||||||
|
_ANIMATION_TIME_VAR
|
||||||
|
])));
|
||||||
|
|
||||||
return o.fn(
|
return o.fn(
|
||||||
[
|
[
|
||||||
new o.FnParam(
|
new o.FnParam(
|
||||||
@ -280,7 +288,7 @@ class _AnimationBuilder implements AnimationAstVisitor {
|
|||||||
new o.FnParam(_ANIMATION_CURRENT_STATE_VAR.name, o.DYNAMIC_TYPE),
|
new o.FnParam(_ANIMATION_CURRENT_STATE_VAR.name, o.DYNAMIC_TYPE),
|
||||||
new o.FnParam(_ANIMATION_NEXT_STATE_VAR.name, o.DYNAMIC_TYPE)
|
new o.FnParam(_ANIMATION_NEXT_STATE_VAR.name, o.DYNAMIC_TYPE)
|
||||||
],
|
],
|
||||||
statements);
|
statements, o.importType(resolveIdentifier(Identifiers.AnimationTransition)));
|
||||||
}
|
}
|
||||||
|
|
||||||
build(ast: AnimationAst): AnimationEntryCompileResult {
|
build(ast: AnimationAst): AnimationEntryCompileResult {
|
||||||
|
@ -7,9 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompileAnimationAnimateMetadata, CompileAnimationEntryMetadata, CompileAnimationGroupMetadata, CompileAnimationKeyframesSequenceMetadata, CompileAnimationMetadata, CompileAnimationSequenceMetadata, CompileAnimationStateDeclarationMetadata, CompileAnimationStateTransitionMetadata, CompileAnimationStyleMetadata, CompileAnimationWithStepsMetadata, CompileDirectiveMetadata} from '../compile_metadata';
|
import {CompileAnimationAnimateMetadata, CompileAnimationEntryMetadata, CompileAnimationGroupMetadata, CompileAnimationKeyframesSequenceMetadata, CompileAnimationMetadata, CompileAnimationSequenceMetadata, CompileAnimationStateDeclarationMetadata, CompileAnimationStateTransitionMetadata, CompileAnimationStyleMetadata, CompileAnimationWithStepsMetadata, CompileDirectiveMetadata} from '../compile_metadata';
|
||||||
import {ListWrapper, StringMapWrapper} from '../facade/collection';
|
import {StringMapWrapper} from '../facade/collection';
|
||||||
import {isArray, isBlank, isPresent, isString, isStringMap} from '../facade/lang';
|
import {isBlank, isPresent} from '../facade/lang';
|
||||||
import {Math} from '../facade/math';
|
|
||||||
import {ParseError} from '../parse_util';
|
import {ParseError} from '../parse_util';
|
||||||
import {ANY_STATE, FILL_STYLE_FLAG} from '../private_import_core';
|
import {ANY_STATE, FILL_STYLE_FLAG} from '../private_import_core';
|
||||||
|
|
||||||
@ -97,7 +96,7 @@ function _parseAnimationDeclarationStates(
|
|||||||
var styleValues: Styles[] = [];
|
var styleValues: Styles[] = [];
|
||||||
stateMetadata.styles.styles.forEach(stylesEntry => {
|
stateMetadata.styles.styles.forEach(stylesEntry => {
|
||||||
// TODO (matsko): change this when we get CSS class integration support
|
// TODO (matsko): change this when we get CSS class integration support
|
||||||
if (isStringMap(stylesEntry)) {
|
if (typeof stylesEntry === 'object' && stylesEntry !== null) {
|
||||||
styleValues.push(stylesEntry as Styles);
|
styleValues.push(stylesEntry as Styles);
|
||||||
} else {
|
} else {
|
||||||
errors.push(new AnimationParseError(
|
errors.push(new AnimationParseError(
|
||||||
@ -115,13 +114,10 @@ function _parseAnimationStateTransition(
|
|||||||
stateStyles: {[key: string]: AnimationStylesAst},
|
stateStyles: {[key: string]: AnimationStylesAst},
|
||||||
errors: AnimationParseError[]): AnimationStateTransitionAst {
|
errors: AnimationParseError[]): AnimationStateTransitionAst {
|
||||||
var styles = new StylesCollection();
|
var styles = new StylesCollection();
|
||||||
var transitionExprs: any[] /** TODO #9100 */ = [];
|
var transitionExprs: AnimationStateTransitionExpression[] = [];
|
||||||
var transitionStates = transitionStateMetadata.stateChangeExpr.split(/\s*,\s*/);
|
var transitionStates = transitionStateMetadata.stateChangeExpr.split(/\s*,\s*/);
|
||||||
transitionStates.forEach(expr => {
|
transitionStates.forEach(
|
||||||
_parseAnimationTransitionExpr(expr, errors).forEach(transExpr => {
|
expr => { transitionExprs.push(..._parseAnimationTransitionExpr(expr, errors)); });
|
||||||
transitionExprs.push(transExpr);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
var entry = _normalizeAnimationEntry(transitionStateMetadata.steps);
|
var entry = _normalizeAnimationEntry(transitionStateMetadata.steps);
|
||||||
var animation = _normalizeStyleSteps(entry, stateStyles, errors);
|
var animation = _normalizeStyleSteps(entry, stateStyles, errors);
|
||||||
var animationAst = _parseTransitionAnimation(animation, 0, styles, stateStyles, errors);
|
var animationAst = _parseTransitionAnimation(animation, 0, styles, stateStyles, errors);
|
||||||
@ -136,9 +132,25 @@ function _parseAnimationStateTransition(
|
|||||||
return new AnimationStateTransitionAst(transitionExprs, stepsAst);
|
return new AnimationStateTransitionAst(transitionExprs, stepsAst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _parseAnimationAlias(alias: string, errors: AnimationParseError[]): string {
|
||||||
|
switch (alias) {
|
||||||
|
case ':enter':
|
||||||
|
return 'void => *';
|
||||||
|
case ':leave':
|
||||||
|
return '* => void';
|
||||||
|
default:
|
||||||
|
errors.push(
|
||||||
|
new AnimationParseError(`the transition alias value "${alias}" is not supported`));
|
||||||
|
return '* => *';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function _parseAnimationTransitionExpr(
|
function _parseAnimationTransitionExpr(
|
||||||
eventStr: string, errors: AnimationParseError[]): AnimationStateTransitionExpression[] {
|
eventStr: string, errors: AnimationParseError[]): AnimationStateTransitionExpression[] {
|
||||||
var expressions: any[] /** TODO #9100 */ = [];
|
var expressions: AnimationStateTransitionExpression[] = [];
|
||||||
|
if (eventStr[0] == ':') {
|
||||||
|
eventStr = _parseAnimationAlias(eventStr, errors);
|
||||||
|
}
|
||||||
var match = eventStr.match(/^(\*|[-\w]+)\s*(<?[=-]>)\s*(\*|[-\w]+)$/);
|
var match = eventStr.match(/^(\*|[-\w]+)\s*(<?[=-]>)\s*(\*|[-\w]+)$/);
|
||||||
if (!isPresent(match) || match.length < 4) {
|
if (!isPresent(match) || match.length < 4) {
|
||||||
errors.push(new AnimationParseError(`the provided ${eventStr} is not of a supported format`));
|
errors.push(new AnimationParseError(`the provided ${eventStr} is not of a supported format`));
|
||||||
@ -159,18 +171,16 @@ function _parseAnimationTransitionExpr(
|
|||||||
|
|
||||||
function _normalizeAnimationEntry(entry: CompileAnimationMetadata | CompileAnimationMetadata[]):
|
function _normalizeAnimationEntry(entry: CompileAnimationMetadata | CompileAnimationMetadata[]):
|
||||||
CompileAnimationMetadata {
|
CompileAnimationMetadata {
|
||||||
return isArray(entry) ? new CompileAnimationSequenceMetadata(<CompileAnimationMetadata[]>entry) :
|
return Array.isArray(entry) ? new CompileAnimationSequenceMetadata(entry) : entry;
|
||||||
<CompileAnimationMetadata>entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _normalizeStyleMetadata(
|
function _normalizeStyleMetadata(
|
||||||
entry: CompileAnimationStyleMetadata, stateStyles: {[key: string]: AnimationStylesAst},
|
entry: CompileAnimationStyleMetadata, stateStyles: {[key: string]: AnimationStylesAst},
|
||||||
errors: AnimationParseError[]): Array<{[key: string]: string | number}> {
|
errors: AnimationParseError[]): {[key: string]: string | number}[] {
|
||||||
var normalizedStyles: any[] /** TODO #9100 */ = [];
|
var normalizedStyles: {[key: string]: string | number}[] = [];
|
||||||
entry.styles.forEach(styleEntry => {
|
entry.styles.forEach(styleEntry => {
|
||||||
if (isString(styleEntry)) {
|
if (typeof styleEntry === 'string') {
|
||||||
ListWrapper.addAll(
|
normalizedStyles.push(..._resolveStylesFromState(<string>styleEntry, stateStyles, errors));
|
||||||
normalizedStyles, _resolveStylesFromState(<string>styleEntry, stateStyles, errors));
|
|
||||||
} else {
|
} else {
|
||||||
normalizedStyles.push(<{[key: string]: string | number}>styleEntry);
|
normalizedStyles.push(<{[key: string]: string | number}>styleEntry);
|
||||||
}
|
}
|
||||||
@ -189,10 +199,10 @@ function _normalizeStyleSteps(
|
|||||||
|
|
||||||
function _mergeAnimationStyles(
|
function _mergeAnimationStyles(
|
||||||
stylesList: any[], newItem: {[key: string]: string | number} | string) {
|
stylesList: any[], newItem: {[key: string]: string | number} | string) {
|
||||||
if (isStringMap(newItem) && stylesList.length > 0) {
|
if (typeof newItem === 'object' && newItem !== null && stylesList.length > 0) {
|
||||||
var lastIndex = stylesList.length - 1;
|
var lastIndex = stylesList.length - 1;
|
||||||
var lastItem = stylesList[lastIndex];
|
var lastItem = stylesList[lastIndex];
|
||||||
if (isStringMap(lastItem)) {
|
if (typeof lastItem === 'object' && lastItem !== null) {
|
||||||
stylesList[lastIndex] = StringMapWrapper.merge(
|
stylesList[lastIndex] = StringMapWrapper.merge(
|
||||||
<{[key: string]: string | number}>lastItem, <{[key: string]: string | number}>newItem);
|
<{[key: string]: string | number}>lastItem, <{[key: string]: string | number}>newItem);
|
||||||
return;
|
return;
|
||||||
@ -279,7 +289,7 @@ function _resolveStylesFromState(
|
|||||||
`Unable to apply styles due to missing a state: "${normalizedStateName}"`));
|
`Unable to apply styles due to missing a state: "${normalizedStateName}"`));
|
||||||
} else {
|
} else {
|
||||||
value.styles.forEach(stylesEntry => {
|
value.styles.forEach(stylesEntry => {
|
||||||
if (isStringMap(stylesEntry)) {
|
if (typeof stylesEntry === 'object' && stylesEntry !== null) {
|
||||||
styles.push(stylesEntry as Styles);
|
styles.push(stylesEntry as Styles);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -335,13 +345,12 @@ function _parseAnimationKeyframes(
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (doSortKeyframes) {
|
if (doSortKeyframes) {
|
||||||
ListWrapper.sort(rawKeyframes, (a, b) => a[0] <= b[0] ? -1 : 1);
|
rawKeyframes.sort((a, b) => a[0] <= b[0] ? -1 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var i: any /** TODO #9100 */;
|
|
||||||
var firstKeyframe = rawKeyframes[0];
|
var firstKeyframe = rawKeyframes[0];
|
||||||
if (firstKeyframe[0] != _INITIAL_KEYFRAME) {
|
if (firstKeyframe[0] != _INITIAL_KEYFRAME) {
|
||||||
ListWrapper.insert(rawKeyframes, 0, firstKeyframe = [_INITIAL_KEYFRAME, {}]);
|
rawKeyframes.splice(0, 0, firstKeyframe = [_INITIAL_KEYFRAME, {}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var firstKeyframeStyles = firstKeyframe[1];
|
var firstKeyframeStyles = firstKeyframe[1];
|
||||||
@ -353,7 +362,7 @@ function _parseAnimationKeyframes(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var lastKeyframeStyles = lastKeyframe[1];
|
var lastKeyframeStyles = lastKeyframe[1];
|
||||||
for (i = 1; i <= limit; i++) {
|
for (let i = 1; i <= limit; i++) {
|
||||||
let entry = rawKeyframes[i];
|
let entry = rawKeyframes[i];
|
||||||
let styles = entry[1];
|
let styles = entry[1];
|
||||||
|
|
||||||
@ -364,7 +373,7 @@ function _parseAnimationKeyframes(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = limit - 1; i >= 0; i--) {
|
for (let i = limit - 1; i >= 0; i--) {
|
||||||
let entry = rawKeyframes[i];
|
let entry = rawKeyframes[i];
|
||||||
let styles = entry[1];
|
let styles = entry[1];
|
||||||
|
|
||||||
@ -411,7 +420,7 @@ function _parseTransitionAnimation(
|
|||||||
steps.push(new AnimationStepAst(startingStyles, [], 0, 0, ''));
|
steps.push(new AnimationStepAst(startingStyles, [], 0, 0, ''));
|
||||||
} else {
|
} else {
|
||||||
var innerStep = <AnimationStepAst>innerAst;
|
var innerStep = <AnimationStepAst>innerAst;
|
||||||
ListWrapper.addAll(innerStep.startingStyles.styles, previousStyles);
|
innerStep.startingStyles.styles.push(...previousStyles);
|
||||||
}
|
}
|
||||||
previousStyles = null;
|
previousStyles = null;
|
||||||
}
|
}
|
||||||
@ -492,7 +501,7 @@ function _parseTimeExpression(
|
|||||||
var duration: number;
|
var duration: number;
|
||||||
var delay: number = 0;
|
var delay: number = 0;
|
||||||
var easing: string = null;
|
var easing: string = null;
|
||||||
if (isString(exp)) {
|
if (typeof exp === 'string') {
|
||||||
const matches = exp.match(regex);
|
const matches = exp.match(regex);
|
||||||
if (matches === null) {
|
if (matches === null) {
|
||||||
errors.push(new AnimationParseError(`The provided timing value "${exp}" is invalid.`));
|
errors.push(new AnimationParseError(`The provided timing value "${exp}" is invalid.`));
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ListWrapper} from '../facade/collection';
|
|
||||||
import {isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
|
|
||||||
export class StylesCollectionEntry {
|
export class StylesCollectionEntry {
|
||||||
@ -37,7 +36,7 @@ export class StylesCollection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListWrapper.insert(entries, insertionIndex, tuple);
|
entries.splice(insertionIndex, 0, tuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
getByIndex(property: string, index: number): StylesCollectionEntry {
|
getByIndex(property: string, index: number): StylesCollectionEntry {
|
||||||
|
@ -8,17 +8,17 @@
|
|||||||
|
|
||||||
import {isDevMode} from '@angular/core';
|
import {isDevMode} from '@angular/core';
|
||||||
|
|
||||||
import {isArray, isBlank, isPresent, isString} from '../src/facade/lang';
|
import {isBlank, isPresent} from '../src/facade/lang';
|
||||||
|
|
||||||
export function assertArrayOfStrings(identifier: string, value: any) {
|
export function assertArrayOfStrings(identifier: string, value: any) {
|
||||||
if (!isDevMode() || isBlank(value)) {
|
if (!isDevMode() || isBlank(value)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isArray(value)) {
|
if (!Array.isArray(value)) {
|
||||||
throw new Error(`Expected '${identifier}' to be an array of strings.`);
|
throw new Error(`Expected '${identifier}' to be an array of strings.`);
|
||||||
}
|
}
|
||||||
for (var i = 0; i < value.length; i += 1) {
|
for (var i = 0; i < value.length; i += 1) {
|
||||||
if (!isString(value[i])) {
|
if (typeof value[i] !== 'string') {
|
||||||
throw new Error(`Expected '${identifier}' to be an array of strings.`);
|
throw new Error(`Expected '${identifier}' to be an array of strings.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ const INTERPOLATION_BLACKLIST_REGEXPS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export function assertInterpolationSymbols(identifier: string, value: any): void {
|
export function assertInterpolationSymbols(identifier: string, value: any): void {
|
||||||
if (isPresent(value) && !(isArray(value) && value.length == 2)) {
|
if (isPresent(value) && !(Array.isArray(value) && value.length == 2)) {
|
||||||
throw new Error(`Expected '${identifier}' to be an array, [start, end].`);
|
throw new Error(`Expected '${identifier}' to be an array, [start, end].`);
|
||||||
} else if (isDevMode() && !isBlank(value)) {
|
} else if (isDevMode() && !isBlank(value)) {
|
||||||
const start = value[0] as string;
|
const start = value[0] as string;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import {ChangeDetectionStrategy, SchemaMetadata, Type, ViewEncapsulation} from '@angular/core';
|
import {ChangeDetectionStrategy, SchemaMetadata, Type, ViewEncapsulation} from '@angular/core';
|
||||||
|
|
||||||
import {ListWrapper, MapWrapper} from './facade/collection';
|
import {ListWrapper, MapWrapper} from './facade/collection';
|
||||||
import {isPresent, isStringMap, normalizeBlank, normalizeBool} from './facade/lang';
|
import {isPresent} from './facade/lang';
|
||||||
import {LifecycleHooks} from './private_import_core';
|
import {LifecycleHooks} from './private_import_core';
|
||||||
import {CssSelector} from './selector';
|
import {CssSelector} from './selector';
|
||||||
import {sanitizeIdentifier, splitAtColon} from './util';
|
import {sanitizeIdentifier, splitAtColon} from './util';
|
||||||
@ -23,7 +23,6 @@ function unimplemented(): any {
|
|||||||
// group 2: "event" from "(event)"
|
// group 2: "event" from "(event)"
|
||||||
// group 3: "@trigger" from "@trigger"
|
// group 3: "@trigger" from "@trigger"
|
||||||
const HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))|(\@[-\w]+)$/;
|
const HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))|(\@[-\w]+)$/;
|
||||||
const UNDEFINED = new Object();
|
|
||||||
|
|
||||||
export abstract class CompileMetadataWithIdentifier {
|
export abstract class CompileMetadataWithIdentifier {
|
||||||
get identifier(): CompileIdentifierMetadata { return <CompileIdentifierMetadata>unimplemented(); }
|
get identifier(): CompileIdentifierMetadata { return <CompileIdentifierMetadata>unimplemented(); }
|
||||||
@ -106,14 +105,10 @@ export class CompileDiDependencyMetadata {
|
|||||||
isSkipSelf: boolean;
|
isSkipSelf: boolean;
|
||||||
isOptional: boolean;
|
isOptional: boolean;
|
||||||
isValue: boolean;
|
isValue: boolean;
|
||||||
query: CompileQueryMetadata;
|
|
||||||
viewQuery: CompileQueryMetadata;
|
|
||||||
token: CompileTokenMetadata;
|
token: CompileTokenMetadata;
|
||||||
value: any;
|
value: any;
|
||||||
|
|
||||||
constructor(
|
constructor({isAttribute, isSelf, isHost, isSkipSelf, isOptional, isValue, token, value}: {
|
||||||
{isAttribute, isSelf, isHost, isSkipSelf, isOptional, isValue, query, viewQuery, token,
|
|
||||||
value}: {
|
|
||||||
isAttribute?: boolean,
|
isAttribute?: boolean,
|
||||||
isSelf?: boolean,
|
isSelf?: boolean,
|
||||||
isHost?: boolean,
|
isHost?: boolean,
|
||||||
@ -125,14 +120,12 @@ export class CompileDiDependencyMetadata {
|
|||||||
token?: CompileTokenMetadata,
|
token?: CompileTokenMetadata,
|
||||||
value?: any
|
value?: any
|
||||||
} = {}) {
|
} = {}) {
|
||||||
this.isAttribute = normalizeBool(isAttribute);
|
this.isAttribute = !!isAttribute;
|
||||||
this.isSelf = normalizeBool(isSelf);
|
this.isSelf = !!isSelf;
|
||||||
this.isHost = normalizeBool(isHost);
|
this.isHost = !!isHost;
|
||||||
this.isSkipSelf = normalizeBool(isSkipSelf);
|
this.isSkipSelf = !!isSkipSelf;
|
||||||
this.isOptional = normalizeBool(isOptional);
|
this.isOptional = !!isOptional;
|
||||||
this.isValue = normalizeBool(isValue);
|
this.isValue = !!isValue;
|
||||||
this.query = query;
|
|
||||||
this.viewQuery = viewQuery;
|
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
@ -161,8 +154,8 @@ export class CompileProviderMetadata {
|
|||||||
this.useValue = useValue;
|
this.useValue = useValue;
|
||||||
this.useExisting = useExisting;
|
this.useExisting = useExisting;
|
||||||
this.useFactory = useFactory;
|
this.useFactory = useFactory;
|
||||||
this.deps = normalizeBlank(deps);
|
this.deps = deps || null;
|
||||||
this.multi = normalizeBool(multi);
|
this.multi = !!multi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +185,7 @@ export class CompileTokenMetadata implements CompileMetadataWithIdentifier {
|
|||||||
{value?: any, identifier?: CompileIdentifierMetadata, identifierIsInstance?: boolean}) {
|
{value?: any, identifier?: CompileIdentifierMetadata, identifierIsInstance?: boolean}) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.identifier = identifier;
|
this.identifier = identifier;
|
||||||
this.identifierIsInstance = normalizeBool(identifierIsInstance);
|
this.identifierIsInstance = !!identifierIsInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
get reference(): any {
|
get reference(): any {
|
||||||
@ -227,7 +220,7 @@ export class CompileTypeMetadata extends CompileIdentifierMetadata {
|
|||||||
lifecycleHooks?: LifecycleHooks[];
|
lifecycleHooks?: LifecycleHooks[];
|
||||||
} = {}) {
|
} = {}) {
|
||||||
super({reference: reference, name: name, moduleUrl: moduleUrl, prefix: prefix, value: value});
|
super({reference: reference, name: name, moduleUrl: moduleUrl, prefix: prefix, value: value});
|
||||||
this.isHost = normalizeBool(isHost);
|
this.isHost = !!isHost;
|
||||||
this.diDeps = _normalizeArray(diDeps);
|
this.diDeps = _normalizeArray(diDeps);
|
||||||
this.lifecycleHooks = _normalizeArray(lifecycleHooks);
|
this.lifecycleHooks = _normalizeArray(lifecycleHooks);
|
||||||
}
|
}
|
||||||
@ -248,8 +241,8 @@ export class CompileQueryMetadata {
|
|||||||
read?: CompileTokenMetadata
|
read?: CompileTokenMetadata
|
||||||
} = {}) {
|
} = {}) {
|
||||||
this.selectors = selectors;
|
this.selectors = selectors;
|
||||||
this.descendants = normalizeBool(descendants);
|
this.descendants = !!descendants;
|
||||||
this.first = normalizeBool(first);
|
this.first = !!first;
|
||||||
this.propertyName = propertyName;
|
this.propertyName = propertyName;
|
||||||
this.read = read;
|
this.read = read;
|
||||||
}
|
}
|
||||||
@ -303,9 +296,9 @@ export class CompileTemplateMetadata {
|
|||||||
this.styles = _normalizeArray(styles);
|
this.styles = _normalizeArray(styles);
|
||||||
this.styleUrls = _normalizeArray(styleUrls);
|
this.styleUrls = _normalizeArray(styleUrls);
|
||||||
this.externalStylesheets = _normalizeArray(externalStylesheets);
|
this.externalStylesheets = _normalizeArray(externalStylesheets);
|
||||||
this.animations = isPresent(animations) ? ListWrapper.flatten(animations) : [];
|
this.animations = animations ? ListWrapper.flatten(animations) : [];
|
||||||
this.ngContentSelectors = isPresent(ngContentSelectors) ? ngContentSelectors : [];
|
this.ngContentSelectors = ngContentSelectors || [];
|
||||||
if (isPresent(interpolation) && interpolation.length != 2) {
|
if (interpolation && interpolation.length != 2) {
|
||||||
throw new Error(`'interpolation' should have a start and an end symbol.`);
|
throw new Error(`'interpolation' should have a start and an end symbol.`);
|
||||||
}
|
}
|
||||||
this.interpolation = interpolation;
|
this.interpolation = interpolation;
|
||||||
@ -375,7 +368,7 @@ export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
|
|||||||
|
|
||||||
return new CompileDirectiveMetadata({
|
return new CompileDirectiveMetadata({
|
||||||
type,
|
type,
|
||||||
isComponent: normalizeBool(isComponent), selector, exportAs, changeDetection,
|
isComponent: !!isComponent, selector, exportAs, changeDetection,
|
||||||
inputs: inputsMap,
|
inputs: inputsMap,
|
||||||
outputs: outputsMap,
|
outputs: outputsMap,
|
||||||
hostListeners,
|
hostListeners,
|
||||||
@ -503,13 +496,13 @@ export class CompilePipeMetadata implements CompileMetadataWithIdentifier {
|
|||||||
} = {}) {
|
} = {}) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.pure = normalizeBool(pure);
|
this.pure = !!pure;
|
||||||
}
|
}
|
||||||
get identifier(): CompileIdentifierMetadata { return this.type; }
|
get identifier(): CompileIdentifierMetadata { return this.type; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Metadata regarding compilation of a directive.
|
* Metadata regarding compilation of a module.
|
||||||
*/
|
*/
|
||||||
export class CompileNgModuleMetadata implements CompileMetadataWithIdentifier {
|
export class CompileNgModuleMetadata implements CompileMetadataWithIdentifier {
|
||||||
type: CompileTypeMetadata;
|
type: CompileTypeMetadata;
|
||||||
@ -569,6 +562,7 @@ export class CompileNgModuleMetadata implements CompileMetadataWithIdentifier {
|
|||||||
export class TransitiveCompileNgModuleMetadata {
|
export class TransitiveCompileNgModuleMetadata {
|
||||||
directivesSet = new Set<Type<any>>();
|
directivesSet = new Set<Type<any>>();
|
||||||
pipesSet = new Set<Type<any>>();
|
pipesSet = new Set<Type<any>>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public modules: CompileNgModuleMetadata[], public providers: CompileProviderMetadata[],
|
public modules: CompileNgModuleMetadata[], public providers: CompileProviderMetadata[],
|
||||||
public entryComponents: CompileTypeMetadata[], public directives: CompileDirectiveMetadata[],
|
public entryComponents: CompileTypeMetadata[], public directives: CompileDirectiveMetadata[],
|
||||||
@ -581,20 +575,22 @@ export class TransitiveCompileNgModuleMetadata {
|
|||||||
export function removeIdentifierDuplicates<T extends CompileMetadataWithIdentifier>(items: T[]):
|
export function removeIdentifierDuplicates<T extends CompileMetadataWithIdentifier>(items: T[]):
|
||||||
T[] {
|
T[] {
|
||||||
const map = new Map<any, T>();
|
const map = new Map<any, T>();
|
||||||
|
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
if (!map.get(item.identifier.reference)) {
|
if (!map.get(item.identifier.reference)) {
|
||||||
map.set(item.identifier.reference, item);
|
map.set(item.identifier.reference, item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return MapWrapper.values(map);
|
return MapWrapper.values(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _normalizeArray(obj: any[]): any[] {
|
function _normalizeArray(obj: any[]): any[] {
|
||||||
return isPresent(obj) ? obj : [];
|
return obj || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isStaticSymbol(value: any): value is StaticSymbol {
|
export function isStaticSymbol(value: any): value is StaticSymbol {
|
||||||
return isStringMap(value) && isPresent(value['name']) && isPresent(value['filePath']);
|
return typeof value === 'object' && value !== null && value['name'] && value['filePath'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StaticSymbol {
|
export interface StaticSymbol {
|
||||||
|
@ -8,39 +8,27 @@
|
|||||||
|
|
||||||
import {COMPILER_OPTIONS, Compiler, CompilerFactory, CompilerOptions, Inject, Injectable, Optional, PLATFORM_INITIALIZER, PlatformRef, Provider, ReflectiveInjector, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, ViewEncapsulation, createPlatformFactory, isDevMode, platformCore} from '@angular/core';
|
import {COMPILER_OPTIONS, Compiler, CompilerFactory, CompilerOptions, Inject, Injectable, Optional, PLATFORM_INITIALIZER, PlatformRef, Provider, ReflectiveInjector, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, ViewEncapsulation, createPlatformFactory, isDevMode, platformCore} from '@angular/core';
|
||||||
|
|
||||||
export * from './template_parser/template_ast';
|
|
||||||
export {TEMPLATE_TRANSFORMS} from './template_parser/template_parser';
|
|
||||||
export {CompilerConfig, RenderTypes} from './config';
|
|
||||||
export * from './compile_metadata';
|
|
||||||
export * from './offline_compiler';
|
|
||||||
export {RuntimeCompiler} from './runtime_compiler';
|
|
||||||
export * from './url_resolver';
|
|
||||||
export * from './resource_loader';
|
|
||||||
|
|
||||||
export {DirectiveResolver} from './directive_resolver';
|
|
||||||
export {PipeResolver} from './pipe_resolver';
|
|
||||||
export {NgModuleResolver} from './ng_module_resolver';
|
|
||||||
|
|
||||||
import {TemplateParser} from './template_parser/template_parser';
|
|
||||||
import {HtmlParser} from './ml_parser/html_parser';
|
|
||||||
import {DirectiveNormalizer} from './directive_normalizer';
|
|
||||||
import {CompileMetadataResolver} from './metadata_resolver';
|
|
||||||
import {StyleCompiler} from './style_compiler';
|
|
||||||
import {ViewCompiler} from './view_compiler/view_compiler';
|
|
||||||
import {NgModuleCompiler} from './ng_module_compiler';
|
|
||||||
import {CompilerConfig} from './config';
|
import {CompilerConfig} from './config';
|
||||||
import {RuntimeCompiler} from './runtime_compiler';
|
import {DirectiveNormalizer} from './directive_normalizer';
|
||||||
import {ElementSchemaRegistry} from './schema/element_schema_registry';
|
|
||||||
import {DomElementSchemaRegistry} from './schema/dom_element_schema_registry';
|
|
||||||
import {UrlResolver, DEFAULT_PACKAGE_URL_PROVIDER} from './url_resolver';
|
|
||||||
import {Parser} from './expression_parser/parser';
|
|
||||||
import {Lexer} from './expression_parser/lexer';
|
|
||||||
import {DirectiveResolver} from './directive_resolver';
|
import {DirectiveResolver} from './directive_resolver';
|
||||||
import {PipeResolver} from './pipe_resolver';
|
import {DirectiveWrapperCompiler} from './directive_wrapper_compiler';
|
||||||
import {NgModuleResolver} from './ng_module_resolver';
|
import {Lexer} from './expression_parser/lexer';
|
||||||
import {Console, Reflector, reflector, ReflectorReader, ReflectionCapabilities} from './private_import_core';
|
import {Parser} from './expression_parser/parser';
|
||||||
import {ResourceLoader} from './resource_loader';
|
|
||||||
import * as i18n from './i18n/index';
|
import * as i18n from './i18n/index';
|
||||||
|
import {CompileMetadataResolver} from './metadata_resolver';
|
||||||
|
import {HtmlParser} from './ml_parser/html_parser';
|
||||||
|
import {NgModuleCompiler} from './ng_module_compiler';
|
||||||
|
import {NgModuleResolver} from './ng_module_resolver';
|
||||||
|
import {PipeResolver} from './pipe_resolver';
|
||||||
|
import {Console, ReflectionCapabilities, Reflector, ReflectorReader, reflector} from './private_import_core';
|
||||||
|
import {ResourceLoader} from './resource_loader';
|
||||||
|
import {RuntimeCompiler} from './runtime_compiler';
|
||||||
|
import {DomElementSchemaRegistry} from './schema/dom_element_schema_registry';
|
||||||
|
import {ElementSchemaRegistry} from './schema/element_schema_registry';
|
||||||
|
import {StyleCompiler} from './style_compiler';
|
||||||
|
import {TemplateParser} from './template_parser/template_parser';
|
||||||
|
import {DEFAULT_PACKAGE_URL_PROVIDER, UrlResolver} from './url_resolver';
|
||||||
|
import {ViewCompiler} from './view_compiler/view_compiler';
|
||||||
|
|
||||||
const _NO_RESOURCE_LOADER: ResourceLoader = {
|
const _NO_RESOURCE_LOADER: ResourceLoader = {
|
||||||
get(url: string): Promise<string>{
|
get(url: string): Promise<string>{
|
||||||
@ -77,6 +65,7 @@ export const COMPILER_PROVIDERS: Array<any|Type<any>|{[k: string]: any}|any[]> =
|
|||||||
StyleCompiler,
|
StyleCompiler,
|
||||||
ViewCompiler,
|
ViewCompiler,
|
||||||
NgModuleCompiler,
|
NgModuleCompiler,
|
||||||
|
DirectiveWrapperCompiler,
|
||||||
{provide: CompilerConfig, useValue: new CompilerConfig()},
|
{provide: CompilerConfig, useValue: new CompilerConfig()},
|
||||||
RuntimeCompiler,
|
RuntimeCompiler,
|
||||||
{provide: Compiler, useExisting: RuntimeCompiler},
|
{provide: Compiler, useExisting: RuntimeCompiler},
|
||||||
|
48
modules/@angular/compiler/src/compiler_util/binding_util.ts
Normal file
48
modules/@angular/compiler/src/compiler_util/binding_util.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* @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 {Identifiers, resolveIdentifier} from '../identifiers';
|
||||||
|
import {ClassBuilder} from '../output/class_builder';
|
||||||
|
import * as o from '../output/output_ast';
|
||||||
|
|
||||||
|
import {ConvertPropertyBindingResult} from './expression_converter';
|
||||||
|
|
||||||
|
export class CheckBindingField {
|
||||||
|
constructor(public expression: o.ReadPropExpr, public bindingId: string) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createCheckBindingField(builder: ClassBuilder): CheckBindingField {
|
||||||
|
const bindingId = `${builder.fields.length}`;
|
||||||
|
const fieldExpr = createBindFieldExpr(bindingId);
|
||||||
|
// private is fine here as no child view will reference the cached value...
|
||||||
|
builder.fields.push(new o.ClassField(fieldExpr.name, null, [o.StmtModifier.Private]));
|
||||||
|
builder.ctorStmts.push(o.THIS_EXPR.prop(fieldExpr.name)
|
||||||
|
.set(o.importExpr(resolveIdentifier(Identifiers.UNINITIALIZED)))
|
||||||
|
.toStmt());
|
||||||
|
return new CheckBindingField(fieldExpr, bindingId);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createCheckBindingStmt(
|
||||||
|
evalResult: ConvertPropertyBindingResult, fieldExpr: o.ReadPropExpr,
|
||||||
|
throwOnChangeVar: o.Expression, actions: o.Statement[]): o.Statement[] {
|
||||||
|
var condition: o.Expression = o.importExpr(resolveIdentifier(Identifiers.checkBinding)).callFn([
|
||||||
|
throwOnChangeVar, fieldExpr, evalResult.currValExpr
|
||||||
|
]);
|
||||||
|
if (evalResult.forceUpdate) {
|
||||||
|
condition = evalResult.forceUpdate.or(condition);
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
...evalResult.stmts, new o.IfStmt(condition, actions.concat([
|
||||||
|
<o.Statement>o.THIS_EXPR.prop(fieldExpr.name).set(evalResult.currValExpr).toStmt()
|
||||||
|
]))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function createBindFieldExpr(bindingId: string): o.ReadPropExpr {
|
||||||
|
return o.THIS_EXPR.prop(`_expr_${bindingId}`);
|
||||||
|
}
|
@ -8,54 +8,132 @@
|
|||||||
|
|
||||||
|
|
||||||
import * as cdAst from '../expression_parser/ast';
|
import * as cdAst from '../expression_parser/ast';
|
||||||
import {isArray, isBlank, isPresent} from '../facade/lang';
|
import {isBlank, isPresent} from '../facade/lang';
|
||||||
import {Identifiers, resolveIdentifier} from '../identifiers';
|
import {Identifiers, resolveIdentifier} from '../identifiers';
|
||||||
|
import {ClassBuilder} from '../output/class_builder';
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
|
|
||||||
|
import {createPureProxy} from './identifier_util';
|
||||||
|
|
||||||
|
const VAL_UNWRAPPER_VAR = o.variable(`valUnwrapper`);
|
||||||
|
|
||||||
export interface NameResolver {
|
export interface NameResolver {
|
||||||
callPipe(name: string, input: o.Expression, args: o.Expression[]): o.Expression;
|
callPipe(name: string, input: o.Expression, args: o.Expression[]): o.Expression;
|
||||||
getLocal(name: string): o.Expression;
|
getLocal(name: string): o.Expression;
|
||||||
createLiteralArray(values: o.Expression[]): o.Expression;
|
|
||||||
createLiteralMap(values: Array<Array<string|o.Expression>>): o.Expression;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExpressionWithWrappedValueInfo {
|
export class EventHandlerVars { static event = o.variable('$event'); }
|
||||||
|
|
||||||
|
export class ConvertPropertyBindingResult {
|
||||||
constructor(
|
constructor(
|
||||||
public expression: o.Expression, public needsValueUnwrapper: boolean,
|
public stmts: o.Statement[], public currValExpr: o.Expression,
|
||||||
public temporaryCount: number) {}
|
public forceUpdate: o.Expression) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertCdExpressionToIr(
|
/**
|
||||||
nameResolver: NameResolver, implicitReceiver: o.Expression, expression: cdAst.AST,
|
* Converts the given expression AST into an executable output AST, assuming the expression is
|
||||||
valueUnwrapper: o.ReadVarExpr, bindingIndex: number): ExpressionWithWrappedValueInfo {
|
* used in a property binding.
|
||||||
const visitor = new _AstToIrVisitor(nameResolver, implicitReceiver, valueUnwrapper, bindingIndex);
|
*/
|
||||||
const irAst: o.Expression = expression.visit(visitor, _Mode.Expression);
|
export function convertPropertyBinding(
|
||||||
return new ExpressionWithWrappedValueInfo(
|
builder: ClassBuilder, nameResolver: NameResolver, implicitReceiver: o.Expression,
|
||||||
irAst, visitor.needsValueUnwrapper, visitor.temporaryCount);
|
expression: cdAst.AST, bindingId: string): ConvertPropertyBindingResult {
|
||||||
|
const currValExpr = createCurrValueExpr(bindingId);
|
||||||
|
const stmts: o.Statement[] = [];
|
||||||
|
if (!nameResolver) {
|
||||||
|
nameResolver = new DefaultNameResolver();
|
||||||
|
}
|
||||||
|
const visitor = new _AstToIrVisitor(
|
||||||
|
builder, nameResolver, implicitReceiver, VAL_UNWRAPPER_VAR, bindingId, false);
|
||||||
|
const outputExpr: o.Expression = expression.visit(visitor, _Mode.Expression);
|
||||||
|
|
||||||
|
if (!outputExpr) {
|
||||||
|
// e.g. an empty expression was given
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visitor.temporaryCount) {
|
||||||
|
for (let i = 0; i < visitor.temporaryCount; i++) {
|
||||||
|
stmts.push(temporaryDeclaration(bindingId, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visitor.needsValueUnwrapper) {
|
||||||
|
var initValueUnwrapperStmt = VAL_UNWRAPPER_VAR.callMethod('reset', []).toStmt();
|
||||||
|
stmts.push(initValueUnwrapperStmt);
|
||||||
|
}
|
||||||
|
stmts.push(currValExpr.set(outputExpr).toDeclStmt(null, [o.StmtModifier.Final]));
|
||||||
|
if (visitor.needsValueUnwrapper) {
|
||||||
|
return new ConvertPropertyBindingResult(
|
||||||
|
stmts, currValExpr, VAL_UNWRAPPER_VAR.prop('hasWrappedValue'));
|
||||||
|
} else {
|
||||||
|
return new ConvertPropertyBindingResult(stmts, currValExpr, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertCdStatementToIr(
|
export class ConvertActionBindingResult {
|
||||||
nameResolver: NameResolver, implicitReceiver: o.Expression, stmt: cdAst.AST,
|
constructor(public stmts: o.Statement[], public preventDefault: o.ReadVarExpr) {}
|
||||||
bindingIndex: number): o.Statement[] {
|
|
||||||
const visitor = new _AstToIrVisitor(nameResolver, implicitReceiver, null, bindingIndex);
|
|
||||||
let statements: o.Statement[] = [];
|
|
||||||
flattenStatements(stmt.visit(visitor, _Mode.Statement), statements);
|
|
||||||
prependTemporaryDecls(visitor.temporaryCount, bindingIndex, statements);
|
|
||||||
return statements;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function temporaryName(bindingIndex: number, temporaryNumber: number): string {
|
/**
|
||||||
return `tmp_${bindingIndex}_${temporaryNumber}`;
|
* Converts the given expression AST into an executable output AST, assuming the expression is
|
||||||
|
* used in an action binding (e.g. an event handler).
|
||||||
|
*/
|
||||||
|
export function convertActionBinding(
|
||||||
|
builder: ClassBuilder, nameResolver: NameResolver, implicitReceiver: o.Expression,
|
||||||
|
action: cdAst.AST, bindingId: string): ConvertActionBindingResult {
|
||||||
|
if (!nameResolver) {
|
||||||
|
nameResolver = new DefaultNameResolver();
|
||||||
|
}
|
||||||
|
const visitor =
|
||||||
|
new _AstToIrVisitor(builder, nameResolver, implicitReceiver, null, bindingId, true);
|
||||||
|
let actionStmts: o.Statement[] = [];
|
||||||
|
flattenStatements(action.visit(visitor, _Mode.Statement), actionStmts);
|
||||||
|
prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts);
|
||||||
|
var lastIndex = actionStmts.length - 1;
|
||||||
|
var preventDefaultVar: o.ReadVarExpr = null;
|
||||||
|
if (lastIndex >= 0) {
|
||||||
|
var lastStatement = actionStmts[lastIndex];
|
||||||
|
var returnExpr = convertStmtIntoExpression(lastStatement);
|
||||||
|
if (returnExpr) {
|
||||||
|
// Note: We need to cast the result of the method call to dynamic,
|
||||||
|
// as it might be a void method!
|
||||||
|
preventDefaultVar = createPreventDefaultVar(bindingId);
|
||||||
|
actionStmts[lastIndex] =
|
||||||
|
preventDefaultVar.set(returnExpr.cast(o.DYNAMIC_TYPE).notIdentical(o.literal(false)))
|
||||||
|
.toDeclStmt(null, [o.StmtModifier.Final]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ConvertActionBindingResult(actionStmts, preventDefaultVar);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function temporaryDeclaration(bindingIndex: number, temporaryNumber: number): o.Statement {
|
/**
|
||||||
return new o.DeclareVarStmt(temporaryName(bindingIndex, temporaryNumber), o.NULL_EXPR);
|
* Creates variables that are shared by multiple calls to `convertActionBinding` /
|
||||||
|
* `convertPropertyBinding`
|
||||||
|
*/
|
||||||
|
export function createSharedBindingVariablesIfNeeded(stmts: o.Statement[]): o.Statement[] {
|
||||||
|
const unwrapperStmts: o.Statement[] = [];
|
||||||
|
var readVars = o.findReadVarNames(stmts);
|
||||||
|
if (readVars.has(VAL_UNWRAPPER_VAR.name)) {
|
||||||
|
unwrapperStmts.push(
|
||||||
|
VAL_UNWRAPPER_VAR
|
||||||
|
.set(o.importExpr(resolveIdentifier(Identifiers.ValueUnwrapper)).instantiate([]))
|
||||||
|
.toDeclStmt(null, [o.StmtModifier.Final]));
|
||||||
|
}
|
||||||
|
return unwrapperStmts;
|
||||||
|
}
|
||||||
|
|
||||||
|
function temporaryName(bindingId: string, temporaryNumber: number): string {
|
||||||
|
return `tmp_${bindingId}_${temporaryNumber}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function temporaryDeclaration(bindingId: string, temporaryNumber: number): o.Statement {
|
||||||
|
return new o.DeclareVarStmt(temporaryName(bindingId, temporaryNumber), o.NULL_EXPR);
|
||||||
}
|
}
|
||||||
|
|
||||||
function prependTemporaryDecls(
|
function prependTemporaryDecls(
|
||||||
temporaryCount: number, bindingIndex: number, statements: o.Statement[]) {
|
temporaryCount: number, bindingId: string, statements: o.Statement[]) {
|
||||||
for (let i = temporaryCount - 1; i >= 0; i--) {
|
for (let i = temporaryCount - 1; i >= 0; i--) {
|
||||||
statements.unshift(temporaryDeclaration(bindingIndex, i));
|
statements.unshift(temporaryDeclaration(bindingId, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,8 +170,9 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
public temporaryCount: number = 0;
|
public temporaryCount: number = 0;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _nameResolver: NameResolver, private _implicitReceiver: o.Expression,
|
private _builder: ClassBuilder, private _nameResolver: NameResolver,
|
||||||
private _valueUnwrapper: o.ReadVarExpr, private bindingIndex: number) {}
|
private _implicitReceiver: o.Expression, private _valueUnwrapper: o.ReadVarExpr,
|
||||||
|
private bindingId: string, private isAction: boolean) {}
|
||||||
|
|
||||||
visitBinary(ast: cdAst.Binary, mode: _Mode): any {
|
visitBinary(ast: cdAst.Binary, mode: _Mode): any {
|
||||||
var op: o.BinaryOperator;
|
var op: o.BinaryOperator;
|
||||||
@ -170,6 +249,9 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
const input = this.visit(ast.exp, _Mode.Expression);
|
const input = this.visit(ast.exp, _Mode.Expression);
|
||||||
const args = this.visitAll(ast.args, _Mode.Expression);
|
const args = this.visitAll(ast.args, _Mode.Expression);
|
||||||
const value = this._nameResolver.callPipe(ast.name, input, args);
|
const value = this._nameResolver.callPipe(ast.name, input, args);
|
||||||
|
if (!value) {
|
||||||
|
throw new Error(`Illegal state: Pipe ${ast.name} is not allowed here!`);
|
||||||
|
}
|
||||||
this.needsValueUnwrapper = true;
|
this.needsValueUnwrapper = true;
|
||||||
return convertToStatementIfNeeded(mode, this._valueUnwrapper.callMethod('unwrap', [value]));
|
return convertToStatementIfNeeded(mode, this._valueUnwrapper.callMethod('unwrap', [value]));
|
||||||
}
|
}
|
||||||
@ -209,8 +291,10 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitLiteralArray(ast: cdAst.LiteralArray, mode: _Mode): any {
|
visitLiteralArray(ast: cdAst.LiteralArray, mode: _Mode): any {
|
||||||
return convertToStatementIfNeeded(
|
const parts = this.visitAll(ast.expressions, mode);
|
||||||
mode, this._nameResolver.createLiteralArray(this.visitAll(ast.expressions, mode)));
|
const literalArr =
|
||||||
|
this.isAction ? o.literalArr(parts) : createCachedLiteralArray(this._builder, parts);
|
||||||
|
return convertToStatementIfNeeded(mode, literalArr);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitLiteralMap(ast: cdAst.LiteralMap, mode: _Mode): any {
|
visitLiteralMap(ast: cdAst.LiteralMap, mode: _Mode): any {
|
||||||
@ -218,13 +302,22 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
for (let i = 0; i < ast.keys.length; i++) {
|
for (let i = 0; i < ast.keys.length; i++) {
|
||||||
parts.push([ast.keys[i], this.visit(ast.values[i], _Mode.Expression)]);
|
parts.push([ast.keys[i], this.visit(ast.values[i], _Mode.Expression)]);
|
||||||
}
|
}
|
||||||
return convertToStatementIfNeeded(mode, this._nameResolver.createLiteralMap(parts));
|
const literalMap =
|
||||||
|
this.isAction ? o.literalMap(parts) : createCachedLiteralMap(this._builder, parts);
|
||||||
|
return convertToStatementIfNeeded(mode, literalMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitLiteralPrimitive(ast: cdAst.LiteralPrimitive, mode: _Mode): any {
|
visitLiteralPrimitive(ast: cdAst.LiteralPrimitive, mode: _Mode): any {
|
||||||
return convertToStatementIfNeeded(mode, o.literal(ast.value));
|
return convertToStatementIfNeeded(mode, o.literal(ast.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _getLocal(name: string): o.Expression {
|
||||||
|
if (this.isAction && name == EventHandlerVars.event.name) {
|
||||||
|
return EventHandlerVars.event;
|
||||||
|
}
|
||||||
|
return this._nameResolver.getLocal(name);
|
||||||
|
}
|
||||||
|
|
||||||
visitMethodCall(ast: cdAst.MethodCall, mode: _Mode): any {
|
visitMethodCall(ast: cdAst.MethodCall, mode: _Mode): any {
|
||||||
const leftMostSafe = this.leftMostSafeNode(ast);
|
const leftMostSafe = this.leftMostSafeNode(ast);
|
||||||
if (leftMostSafe) {
|
if (leftMostSafe) {
|
||||||
@ -234,7 +327,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
let result: any = null;
|
let result: any = null;
|
||||||
let receiver = this.visit(ast.receiver, _Mode.Expression);
|
let receiver = this.visit(ast.receiver, _Mode.Expression);
|
||||||
if (receiver === this._implicitReceiver) {
|
if (receiver === this._implicitReceiver) {
|
||||||
var varExpr = this._nameResolver.getLocal(ast.name);
|
var varExpr = this._getLocal(ast.name);
|
||||||
if (isPresent(varExpr)) {
|
if (isPresent(varExpr)) {
|
||||||
result = varExpr.callFn(args);
|
result = varExpr.callFn(args);
|
||||||
}
|
}
|
||||||
@ -258,7 +351,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
let result: any = null;
|
let result: any = null;
|
||||||
var receiver = this.visit(ast.receiver, _Mode.Expression);
|
var receiver = this.visit(ast.receiver, _Mode.Expression);
|
||||||
if (receiver === this._implicitReceiver) {
|
if (receiver === this._implicitReceiver) {
|
||||||
result = this._nameResolver.getLocal(ast.name);
|
result = this._getLocal(ast.name);
|
||||||
}
|
}
|
||||||
if (isBlank(result)) {
|
if (isBlank(result)) {
|
||||||
result = receiver.prop(ast.name);
|
result = receiver.prop(ast.name);
|
||||||
@ -270,7 +363,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
visitPropertyWrite(ast: cdAst.PropertyWrite, mode: _Mode): any {
|
visitPropertyWrite(ast: cdAst.PropertyWrite, mode: _Mode): any {
|
||||||
let receiver: o.Expression = this.visit(ast.receiver, _Mode.Expression);
|
let receiver: o.Expression = this.visit(ast.receiver, _Mode.Expression);
|
||||||
if (receiver === this._implicitReceiver) {
|
if (receiver === this._implicitReceiver) {
|
||||||
var varExpr = this._nameResolver.getLocal(ast.name);
|
var varExpr = this._getLocal(ast.name);
|
||||||
if (isPresent(varExpr)) {
|
if (isPresent(varExpr)) {
|
||||||
throw new Error('Cannot assign to a reference or variable!');
|
throw new Error('Cannot assign to a reference or variable!');
|
||||||
}
|
}
|
||||||
@ -459,21 +552,87 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
private allocateTemporary(): o.ReadVarExpr {
|
private allocateTemporary(): o.ReadVarExpr {
|
||||||
const tempNumber = this._currentTemporary++;
|
const tempNumber = this._currentTemporary++;
|
||||||
this.temporaryCount = Math.max(this._currentTemporary, this.temporaryCount);
|
this.temporaryCount = Math.max(this._currentTemporary, this.temporaryCount);
|
||||||
return new o.ReadVarExpr(temporaryName(this.bindingIndex, tempNumber));
|
return new o.ReadVarExpr(temporaryName(this.bindingId, tempNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
private releaseTemporary(temporary: o.ReadVarExpr) {
|
private releaseTemporary(temporary: o.ReadVarExpr) {
|
||||||
this._currentTemporary--;
|
this._currentTemporary--;
|
||||||
if (temporary.name != temporaryName(this.bindingIndex, this._currentTemporary)) {
|
if (temporary.name != temporaryName(this.bindingId, this._currentTemporary)) {
|
||||||
throw new Error(`Temporary ${temporary.name} released out of order`);
|
throw new Error(`Temporary ${temporary.name} released out of order`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function flattenStatements(arg: any, output: o.Statement[]) {
|
function flattenStatements(arg: any, output: o.Statement[]) {
|
||||||
if (isArray(arg)) {
|
if (Array.isArray(arg)) {
|
||||||
(<any[]>arg).forEach((entry) => flattenStatements(entry, output));
|
(<any[]>arg).forEach((entry) => flattenStatements(entry, output));
|
||||||
} else {
|
} else {
|
||||||
output.push(arg);
|
output.push(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createCachedLiteralArray(builder: ClassBuilder, values: o.Expression[]): o.Expression {
|
||||||
|
if (values.length === 0) {
|
||||||
|
return o.importExpr(resolveIdentifier(Identifiers.EMPTY_ARRAY));
|
||||||
|
}
|
||||||
|
var proxyExpr = o.THIS_EXPR.prop(`_arr_${builder.fields.length}`);
|
||||||
|
var proxyParams: o.FnParam[] = [];
|
||||||
|
var proxyReturnEntries: o.Expression[] = [];
|
||||||
|
for (var i = 0; i < values.length; i++) {
|
||||||
|
var paramName = `p${i}`;
|
||||||
|
proxyParams.push(new o.FnParam(paramName));
|
||||||
|
proxyReturnEntries.push(o.variable(paramName));
|
||||||
|
}
|
||||||
|
createPureProxy(
|
||||||
|
o.fn(
|
||||||
|
proxyParams, [new o.ReturnStatement(o.literalArr(proxyReturnEntries))],
|
||||||
|
new o.ArrayType(o.DYNAMIC_TYPE)),
|
||||||
|
values.length, proxyExpr, builder);
|
||||||
|
return proxyExpr.callFn(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCachedLiteralMap(
|
||||||
|
builder: ClassBuilder, entries: [string, o.Expression][]): o.Expression {
|
||||||
|
if (entries.length === 0) {
|
||||||
|
return o.importExpr(resolveIdentifier(Identifiers.EMPTY_MAP));
|
||||||
|
}
|
||||||
|
const proxyExpr = o.THIS_EXPR.prop(`_map_${builder.fields.length}`);
|
||||||
|
const proxyParams: o.FnParam[] = [];
|
||||||
|
const proxyReturnEntries: [string, o.Expression][] = [];
|
||||||
|
const values: o.Expression[] = [];
|
||||||
|
for (var i = 0; i < entries.length; i++) {
|
||||||
|
const paramName = `p${i}`;
|
||||||
|
proxyParams.push(new o.FnParam(paramName));
|
||||||
|
proxyReturnEntries.push([entries[i][0], o.variable(paramName)]);
|
||||||
|
values.push(<o.Expression>entries[i][1]);
|
||||||
|
}
|
||||||
|
createPureProxy(
|
||||||
|
o.fn(
|
||||||
|
proxyParams, [new o.ReturnStatement(o.literalMap(proxyReturnEntries))],
|
||||||
|
new o.MapType(o.DYNAMIC_TYPE)),
|
||||||
|
entries.length, proxyExpr, builder);
|
||||||
|
return proxyExpr.callFn(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultNameResolver implements NameResolver {
|
||||||
|
callPipe(name: string, input: o.Expression, args: o.Expression[]): o.Expression { return null; }
|
||||||
|
getLocal(name: string): o.Expression { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCurrValueExpr(bindingId: string): o.ReadVarExpr {
|
||||||
|
return o.variable(`currVal_${bindingId}`); // fix syntax highlighting: `
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPreventDefaultVar(bindingId: string): o.ReadVarExpr {
|
||||||
|
return o.variable(`pd_${bindingId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertStmtIntoExpression(stmt: o.Statement): o.Expression {
|
||||||
|
if (stmt instanceof o.ExpressionStatement) {
|
||||||
|
return stmt.expr;
|
||||||
|
} else if (stmt instanceof o.ReturnStatement) {
|
||||||
|
return stmt.value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {CompileTokenMetadata} from '../compile_metadata';
|
||||||
|
import {isPresent} from '../facade/lang';
|
||||||
|
import {IdentifierSpec, Identifiers, resolveEnumIdentifier, resolveIdentifier} from '../identifiers';
|
||||||
|
import * as o from '../output/output_ast';
|
||||||
|
|
||||||
|
export function createDiTokenExpression(token: CompileTokenMetadata): o.Expression {
|
||||||
|
if (isPresent(token.value)) {
|
||||||
|
return o.literal(token.value);
|
||||||
|
} else if (token.identifierIsInstance) {
|
||||||
|
return o.importExpr(token.identifier)
|
||||||
|
.instantiate([], o.importType(token.identifier, [], [o.TypeModifier.Const]));
|
||||||
|
} else {
|
||||||
|
return o.importExpr(token.identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createInlineArray(values: o.Expression[]): o.Expression {
|
||||||
|
if (values.length === 0) {
|
||||||
|
return o.importExpr(resolveIdentifier(Identifiers.EMPTY_INLINE_ARRAY));
|
||||||
|
}
|
||||||
|
const log2 = Math.log(values.length) / Math.log(2);
|
||||||
|
const index = Math.ceil(log2);
|
||||||
|
const identifierSpec = index < Identifiers.inlineArrays.length ? Identifiers.inlineArrays[index] :
|
||||||
|
Identifiers.InlineArrayDynamic;
|
||||||
|
const identifier = resolveIdentifier(identifierSpec);
|
||||||
|
return o.importExpr(identifier).instantiate([
|
||||||
|
<o.Expression>o.literal(values.length)
|
||||||
|
].concat(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createPureProxy(
|
||||||
|
fn: o.Expression, argCount: number, pureProxyProp: o.ReadPropExpr,
|
||||||
|
builder: {fields: o.ClassField[], ctorStmts: {push: (stmt: o.Statement) => void}}) {
|
||||||
|
builder.fields.push(new o.ClassField(pureProxyProp.name, null));
|
||||||
|
var pureProxyId =
|
||||||
|
argCount < Identifiers.pureProxies.length ? Identifiers.pureProxies[argCount] : null;
|
||||||
|
if (!pureProxyId) {
|
||||||
|
throw new Error(`Unsupported number of argument for pure functions: ${argCount}`);
|
||||||
|
}
|
||||||
|
builder.ctorStmts.push(o.THIS_EXPR.prop(pureProxyProp.name)
|
||||||
|
.set(o.importExpr(resolveIdentifier(pureProxyId)).callFn([fn]))
|
||||||
|
.toStmt());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createEnumExpression(enumType: IdentifierSpec, enumValue: any): o.Expression {
|
||||||
|
const enumName =
|
||||||
|
Object.keys(enumType.runtime).find((propName) => enumType.runtime[propName] === enumValue);
|
||||||
|
if (!enumName) {
|
||||||
|
throw new Error(`Unknown enum value ${enumValue} in ${enumType.name}`);
|
||||||
|
}
|
||||||
|
return o.importExpr(resolveEnumIdentifier(resolveIdentifier(enumType), enumName));
|
||||||
|
}
|
146
modules/@angular/compiler/src/compiler_util/render_util.ts
Normal file
146
modules/@angular/compiler/src/compiler_util/render_util.ts
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
import {SecurityContext} from '@angular/core';
|
||||||
|
|
||||||
|
import {isPresent} from '../facade/lang';
|
||||||
|
import {Identifiers, resolveIdentifier} from '../identifiers';
|
||||||
|
import * as o from '../output/output_ast';
|
||||||
|
import {EMPTY_STATE as EMPTY_ANIMATION_STATE} from '../private_import_core';
|
||||||
|
import {BoundElementPropertyAst, BoundEventAst, PropertyBindingType} from '../template_parser/template_ast';
|
||||||
|
|
||||||
|
import {createEnumExpression} from './identifier_util';
|
||||||
|
|
||||||
|
export function writeToRenderer(
|
||||||
|
view: o.Expression, boundProp: BoundElementPropertyAst, renderElement: o.Expression,
|
||||||
|
renderValue: o.Expression, logBindingUpdate: boolean,
|
||||||
|
securityContextExpression?: o.Expression): o.Statement[] {
|
||||||
|
const updateStmts: o.Statement[] = [];
|
||||||
|
const renderer = view.prop('renderer');
|
||||||
|
renderValue = sanitizedValue(view, boundProp, renderValue, securityContextExpression);
|
||||||
|
switch (boundProp.type) {
|
||||||
|
case PropertyBindingType.Property:
|
||||||
|
if (logBindingUpdate) {
|
||||||
|
updateStmts.push(
|
||||||
|
o.importExpr(resolveIdentifier(Identifiers.setBindingDebugInfo))
|
||||||
|
.callFn([renderer, renderElement, o.literal(boundProp.name), renderValue])
|
||||||
|
.toStmt());
|
||||||
|
}
|
||||||
|
updateStmts.push(
|
||||||
|
renderer
|
||||||
|
.callMethod(
|
||||||
|
'setElementProperty', [renderElement, o.literal(boundProp.name), renderValue])
|
||||||
|
.toStmt());
|
||||||
|
break;
|
||||||
|
case PropertyBindingType.Attribute:
|
||||||
|
renderValue =
|
||||||
|
renderValue.isBlank().conditional(o.NULL_EXPR, renderValue.callMethod('toString', []));
|
||||||
|
updateStmts.push(
|
||||||
|
renderer
|
||||||
|
.callMethod(
|
||||||
|
'setElementAttribute', [renderElement, o.literal(boundProp.name), renderValue])
|
||||||
|
.toStmt());
|
||||||
|
break;
|
||||||
|
case PropertyBindingType.Class:
|
||||||
|
updateStmts.push(
|
||||||
|
renderer
|
||||||
|
.callMethod(
|
||||||
|
'setElementClass', [renderElement, o.literal(boundProp.name), renderValue])
|
||||||
|
.toStmt());
|
||||||
|
break;
|
||||||
|
case PropertyBindingType.Style:
|
||||||
|
var strValue: o.Expression = renderValue.callMethod('toString', []);
|
||||||
|
if (isPresent(boundProp.unit)) {
|
||||||
|
strValue = strValue.plus(o.literal(boundProp.unit));
|
||||||
|
}
|
||||||
|
|
||||||
|
renderValue = renderValue.isBlank().conditional(o.NULL_EXPR, strValue);
|
||||||
|
updateStmts.push(
|
||||||
|
renderer
|
||||||
|
.callMethod(
|
||||||
|
'setElementStyle', [renderElement, o.literal(boundProp.name), renderValue])
|
||||||
|
.toStmt());
|
||||||
|
break;
|
||||||
|
case PropertyBindingType.Animation:
|
||||||
|
throw new Error('Illegal state: Should not come here!');
|
||||||
|
}
|
||||||
|
return updateStmts;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sanitizedValue(
|
||||||
|
view: o.Expression, boundProp: BoundElementPropertyAst, renderValue: o.Expression,
|
||||||
|
securityContextExpression?: o.Expression): o.Expression {
|
||||||
|
if (boundProp.securityContext === SecurityContext.NONE) {
|
||||||
|
return renderValue; // No sanitization needed.
|
||||||
|
}
|
||||||
|
if (!boundProp.needsRuntimeSecurityContext) {
|
||||||
|
securityContextExpression =
|
||||||
|
createEnumExpression(Identifiers.SecurityContext, boundProp.securityContext);
|
||||||
|
}
|
||||||
|
if (!securityContextExpression) {
|
||||||
|
throw new Error(`internal error, no SecurityContext given ${boundProp.name}`);
|
||||||
|
}
|
||||||
|
let ctx = view.prop('viewUtils').prop('sanitizer');
|
||||||
|
let args = [securityContextExpression, renderValue];
|
||||||
|
return ctx.callMethod('sanitize', args);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function triggerAnimation(
|
||||||
|
view: o.Expression, componentView: o.Expression, boundProp: BoundElementPropertyAst,
|
||||||
|
eventListener: o.Expression, renderElement: o.Expression, renderValue: o.Expression,
|
||||||
|
lastRenderValue: o.Expression) {
|
||||||
|
const detachStmts: o.Statement[] = [];
|
||||||
|
const updateStmts: o.Statement[] = [];
|
||||||
|
|
||||||
|
const animationName = boundProp.name;
|
||||||
|
|
||||||
|
const animationFnExpr =
|
||||||
|
componentView.prop('componentType').prop('animations').key(o.literal(animationName));
|
||||||
|
|
||||||
|
// it's important to normalize the void value as `void` explicitly
|
||||||
|
// so that the styles data can be obtained from the stringmap
|
||||||
|
const emptyStateValue = o.literal(EMPTY_ANIMATION_STATE);
|
||||||
|
const unitializedValue = o.importExpr(resolveIdentifier(Identifiers.UNINITIALIZED));
|
||||||
|
const animationTransitionVar = o.variable('animationTransition_' + animationName);
|
||||||
|
|
||||||
|
updateStmts.push(
|
||||||
|
animationTransitionVar
|
||||||
|
.set(animationFnExpr.callFn([
|
||||||
|
view, renderElement,
|
||||||
|
lastRenderValue.equals(unitializedValue).conditional(emptyStateValue, lastRenderValue),
|
||||||
|
renderValue.equals(unitializedValue).conditional(emptyStateValue, renderValue)
|
||||||
|
]))
|
||||||
|
.toDeclStmt());
|
||||||
|
|
||||||
|
detachStmts.push(
|
||||||
|
animationTransitionVar
|
||||||
|
.set(animationFnExpr.callFn([view, renderElement, lastRenderValue, emptyStateValue]))
|
||||||
|
.toDeclStmt());
|
||||||
|
|
||||||
|
const registerStmts = [
|
||||||
|
animationTransitionVar
|
||||||
|
.callMethod(
|
||||||
|
'onStart',
|
||||||
|
[eventListener.callMethod(
|
||||||
|
o.BuiltinMethod.Bind,
|
||||||
|
[view, o.literal(BoundEventAst.calcFullName(animationName, null, 'start'))])])
|
||||||
|
.toStmt(),
|
||||||
|
animationTransitionVar
|
||||||
|
.callMethod(
|
||||||
|
'onDone',
|
||||||
|
[eventListener.callMethod(
|
||||||
|
o.BuiltinMethod.Bind,
|
||||||
|
[view, o.literal(BoundEventAst.calcFullName(animationName, null, 'done'))])])
|
||||||
|
.toStmt(),
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
updateStmts.push(...registerStmts);
|
||||||
|
detachStmts.push(...registerStmts);
|
||||||
|
|
||||||
|
return {updateStmts, detachStmts};
|
||||||
|
}
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
import * as chars from '../chars';
|
import * as chars from '../chars';
|
||||||
import {BaseError} from '../facade/errors';
|
import {BaseError} from '../facade/errors';
|
||||||
import {StringWrapper, isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
|
|
||||||
export enum CssTokenType {
|
export enum CssTokenType {
|
||||||
EOF,
|
EOF,
|
||||||
@ -155,7 +155,7 @@ export class CssScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
peekAt(index: number): number {
|
peekAt(index: number): number {
|
||||||
return index >= this.length ? chars.$EOF : StringWrapper.charCodeAt(this.input, index);
|
return index >= this.length ? chars.$EOF : this.input.charCodeAt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
consumeEmptyStatements(): void {
|
consumeEmptyStatements(): void {
|
||||||
@ -310,7 +310,7 @@ export class CssScanner {
|
|||||||
return this.scanCharacter();
|
return this.scanCharacter();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.error(`Unexpected character [${StringWrapper.fromCharCode(peek)}]`);
|
return this.error(`Unexpected character [${String.fromCharCode(peek)}]`);
|
||||||
}
|
}
|
||||||
|
|
||||||
scanComment(): CssToken {
|
scanComment(): CssToken {
|
||||||
@ -476,8 +476,7 @@ export class CssScanner {
|
|||||||
var index: number = this.index;
|
var index: number = this.index;
|
||||||
var column: number = this.column;
|
var column: number = this.column;
|
||||||
var line: number = this.line;
|
var line: number = this.line;
|
||||||
errorTokenValue =
|
errorTokenValue = errorTokenValue || String.fromCharCode(this.peek);
|
||||||
isPresent(errorTokenValue) ? errorTokenValue : StringWrapper.fromCharCode(this.peek);
|
|
||||||
var invalidToken = new CssToken(index, column, line, CssTokenType.Invalid, errorTokenValue);
|
var invalidToken = new CssToken(index, column, line, CssTokenType.Invalid, errorTokenValue);
|
||||||
var errorMessage =
|
var errorMessage =
|
||||||
generateErrorMessage(this.input, message, errorTokenValue, index, line, column);
|
generateErrorMessage(this.input, message, errorTokenValue, index, line, column);
|
||||||
@ -696,11 +695,11 @@ function isValidCssCharacter(code: number, mode: CssLexerMode): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function charCode(input: string, index: number): number {
|
function charCode(input: string, index: number): number {
|
||||||
return index >= input.length ? chars.$EOF : StringWrapper.charCodeAt(input, index);
|
return index >= input.length ? chars.$EOF : input.charCodeAt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
function charStr(code: number): string {
|
function charStr(code: number): string {
|
||||||
return StringWrapper.fromCharCode(code);
|
return String.fromCharCode(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNewline(code: number): boolean {
|
export function isNewline(code: number): boolean {
|
||||||
|
@ -330,7 +330,7 @@ export class CssParser {
|
|||||||
var span: ParseSourceSpan;
|
var span: ParseSourceSpan;
|
||||||
var startSelector = selectors[0];
|
var startSelector = selectors[0];
|
||||||
if (isPresent(block)) {
|
if (isPresent(block)) {
|
||||||
var span = this._generateSourceSpan(startSelector, block);
|
span = this._generateSourceSpan(startSelector, block);
|
||||||
ruleAst = new CssSelectorRuleAst(span, selectors, block);
|
ruleAst = new CssSelectorRuleAst(span, selectors, block);
|
||||||
} else {
|
} else {
|
||||||
var name = this._extractSourceContent(start, this._getScannerIndex() - 1);
|
var name = this._extractSourceContent(start, this._getScannerIndex() - 1);
|
||||||
|
@ -71,6 +71,13 @@ export class DirectiveResolver {
|
|||||||
} else if (a instanceof HostBinding) {
|
} else if (a instanceof HostBinding) {
|
||||||
const hostBinding: HostBinding = a;
|
const hostBinding: HostBinding = a;
|
||||||
if (hostBinding.hostPropertyName) {
|
if (hostBinding.hostPropertyName) {
|
||||||
|
const startWith = hostBinding.hostPropertyName[0];
|
||||||
|
if (startWith === '(') {
|
||||||
|
throw new Error(`@HostBinding can not bind to events. Use @HostListener instead.`);
|
||||||
|
} else if (startWith === '[') {
|
||||||
|
throw new Error(
|
||||||
|
`@HostBinding parameter should be a property name, 'class.<name>', or 'attr.<name>'.`);
|
||||||
|
}
|
||||||
host[`[${hostBinding.hostPropertyName}]`] = propName;
|
host[`[${hostBinding.hostPropertyName}]`] = propName;
|
||||||
} else {
|
} else {
|
||||||
host[`[${propName}]`] = propName;
|
host[`[${propName}]`] = propName;
|
||||||
|
458
modules/@angular/compiler/src/directive_wrapper_compiler.ts
Normal file
458
modules/@angular/compiler/src/directive_wrapper_compiler.ts
Normal file
@ -0,0 +1,458 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
|
||||||
|
import {CompileDirectiveMetadata, CompileIdentifierMetadata} from './compile_metadata';
|
||||||
|
import {createCheckBindingField, createCheckBindingStmt} from './compiler_util/binding_util';
|
||||||
|
import {EventHandlerVars, convertActionBinding, convertPropertyBinding} from './compiler_util/expression_converter';
|
||||||
|
import {triggerAnimation, writeToRenderer} from './compiler_util/render_util';
|
||||||
|
import {CompilerConfig} from './config';
|
||||||
|
import {Parser} from './expression_parser/parser';
|
||||||
|
import {Identifiers, resolveIdentifier} from './identifiers';
|
||||||
|
import {DEFAULT_INTERPOLATION_CONFIG} from './ml_parser/interpolation_config';
|
||||||
|
import {ClassBuilder, createClassStmt} from './output/class_builder';
|
||||||
|
import * as o from './output/output_ast';
|
||||||
|
import {ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan} from './parse_util';
|
||||||
|
import {Console, LifecycleHooks, isDefaultChangeDetectionStrategy} from './private_import_core';
|
||||||
|
import {ElementSchemaRegistry} from './schema/element_schema_registry';
|
||||||
|
import {BindingParser} from './template_parser/binding_parser';
|
||||||
|
import {BoundElementPropertyAst, BoundEventAst} from './template_parser/template_ast';
|
||||||
|
|
||||||
|
export class DirectiveWrapperCompileResult {
|
||||||
|
constructor(public statements: o.Statement[], public dirWrapperClassVar: string) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CONTEXT_FIELD_NAME = 'context';
|
||||||
|
const CHANGES_FIELD_NAME = '_changes';
|
||||||
|
const CHANGED_FIELD_NAME = '_changed';
|
||||||
|
const EVENT_HANDLER_FIELD_NAME = '_eventHandler';
|
||||||
|
|
||||||
|
const CURR_VALUE_VAR = o.variable('currValue');
|
||||||
|
const THROW_ON_CHANGE_VAR = o.variable('throwOnChange');
|
||||||
|
const FORCE_UPDATE_VAR = o.variable('forceUpdate');
|
||||||
|
const VIEW_VAR = o.variable('view');
|
||||||
|
const COMPONENT_VIEW_VAR = o.variable('componentView');
|
||||||
|
const RENDER_EL_VAR = o.variable('el');
|
||||||
|
const EVENT_NAME_VAR = o.variable('eventName');
|
||||||
|
|
||||||
|
const RESET_CHANGES_STMT = o.THIS_EXPR.prop(CHANGES_FIELD_NAME).set(o.literalMap([])).toStmt();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We generate directive wrappers to prevent code bloat when a directive is used.
|
||||||
|
* A directive wrapper encapsulates
|
||||||
|
* the dirty checking for `@Input`, the handling of `@HostListener` / `@HostBinding`
|
||||||
|
* and calling the lifecyclehooks `ngOnInit`, `ngOnChanges`, `ngDoCheck`.
|
||||||
|
*
|
||||||
|
* So far, only `@Input` and the lifecycle hooks have been implemented.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class DirectiveWrapperCompiler {
|
||||||
|
static dirWrapperClassName(id: CompileIdentifierMetadata) { return `Wrapper_${id.name}`; }
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private compilerConfig: CompilerConfig, private _exprParser: Parser,
|
||||||
|
private _schemaRegistry: ElementSchemaRegistry, private _console: Console) {}
|
||||||
|
|
||||||
|
compile(dirMeta: CompileDirectiveMetadata): DirectiveWrapperCompileResult {
|
||||||
|
const hostParseResult = parseHostBindings(dirMeta, this._exprParser, this._schemaRegistry);
|
||||||
|
reportParseErrors(hostParseResult.errors, this._console);
|
||||||
|
|
||||||
|
const builder = new DirectiveWrapperBuilder(this.compilerConfig, dirMeta);
|
||||||
|
Object.keys(dirMeta.inputs).forEach((inputFieldName) => {
|
||||||
|
addCheckInputMethod(inputFieldName, builder);
|
||||||
|
});
|
||||||
|
addNgDoCheckMethod(builder);
|
||||||
|
addCheckHostMethod(hostParseResult.hostProps, builder);
|
||||||
|
addHandleEventMethod(hostParseResult.hostListeners, builder);
|
||||||
|
addSubscribeMethod(dirMeta, builder);
|
||||||
|
|
||||||
|
const classStmt = builder.build();
|
||||||
|
return new DirectiveWrapperCompileResult([classStmt], classStmt.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DirectiveWrapperBuilder implements ClassBuilder {
|
||||||
|
fields: o.ClassField[] = [];
|
||||||
|
getters: o.ClassGetter[] = [];
|
||||||
|
methods: o.ClassMethod[] = [];
|
||||||
|
ctorStmts: o.Statement[] = [];
|
||||||
|
detachStmts: o.Statement[] = [];
|
||||||
|
destroyStmts: o.Statement[] = [];
|
||||||
|
|
||||||
|
genChanges: boolean;
|
||||||
|
ngOnChanges: boolean;
|
||||||
|
ngOnInit: boolean;
|
||||||
|
ngDoCheck: boolean;
|
||||||
|
ngOnDestroy: boolean;
|
||||||
|
|
||||||
|
constructor(public compilerConfig: CompilerConfig, public dirMeta: CompileDirectiveMetadata) {
|
||||||
|
const dirLifecycleHooks = dirMeta.type.lifecycleHooks;
|
||||||
|
this.genChanges = dirLifecycleHooks.indexOf(LifecycleHooks.OnChanges) !== -1 ||
|
||||||
|
this.compilerConfig.logBindingUpdate;
|
||||||
|
this.ngOnChanges = dirLifecycleHooks.indexOf(LifecycleHooks.OnChanges) !== -1;
|
||||||
|
this.ngOnInit = dirLifecycleHooks.indexOf(LifecycleHooks.OnInit) !== -1;
|
||||||
|
this.ngDoCheck = dirLifecycleHooks.indexOf(LifecycleHooks.DoCheck) !== -1;
|
||||||
|
this.ngOnDestroy = dirLifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1;
|
||||||
|
if (this.ngOnDestroy) {
|
||||||
|
this.destroyStmts.push(
|
||||||
|
o.THIS_EXPR.prop(CONTEXT_FIELD_NAME).callMethod('ngOnDestroy', []).toStmt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
build(): o.ClassStmt {
|
||||||
|
const dirDepParamNames: string[] = [];
|
||||||
|
for (let i = 0; i < this.dirMeta.type.diDeps.length; i++) {
|
||||||
|
dirDepParamNames.push(`p${i}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const methods = [
|
||||||
|
new o.ClassMethod(
|
||||||
|
'ngOnDetach',
|
||||||
|
[
|
||||||
|
new o.FnParam(
|
||||||
|
VIEW_VAR.name,
|
||||||
|
o.importType(resolveIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
|
||||||
|
new o.FnParam(
|
||||||
|
COMPONENT_VIEW_VAR.name,
|
||||||
|
o.importType(resolveIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
|
||||||
|
new o.FnParam(RENDER_EL_VAR.name, o.DYNAMIC_TYPE),
|
||||||
|
],
|
||||||
|
this.detachStmts),
|
||||||
|
new o.ClassMethod('ngOnDestroy', [], this.destroyStmts),
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
const fields: o.ClassField[] = [
|
||||||
|
new o.ClassField(EVENT_HANDLER_FIELD_NAME, o.FUNCTION_TYPE, [o.StmtModifier.Private]),
|
||||||
|
new o.ClassField(CONTEXT_FIELD_NAME, o.importType(this.dirMeta.type)),
|
||||||
|
new o.ClassField(CHANGED_FIELD_NAME, o.BOOL_TYPE, [o.StmtModifier.Private]),
|
||||||
|
];
|
||||||
|
const ctorStmts: o.Statement[] =
|
||||||
|
[o.THIS_EXPR.prop(CHANGED_FIELD_NAME).set(o.literal(false)).toStmt()];
|
||||||
|
if (this.genChanges) {
|
||||||
|
fields.push(new o.ClassField(
|
||||||
|
CHANGES_FIELD_NAME, new o.MapType(o.DYNAMIC_TYPE), [o.StmtModifier.Private]));
|
||||||
|
ctorStmts.push(RESET_CHANGES_STMT);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctorStmts.push(
|
||||||
|
o.THIS_EXPR.prop(CONTEXT_FIELD_NAME)
|
||||||
|
.set(o.importExpr(this.dirMeta.type)
|
||||||
|
.instantiate(dirDepParamNames.map((paramName) => o.variable(paramName))))
|
||||||
|
.toStmt());
|
||||||
|
|
||||||
|
return createClassStmt({
|
||||||
|
name: DirectiveWrapperCompiler.dirWrapperClassName(this.dirMeta.type),
|
||||||
|
ctorParams: dirDepParamNames.map((paramName) => new o.FnParam(paramName, o.DYNAMIC_TYPE)),
|
||||||
|
builders: [{fields, ctorStmts, methods}, this]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addNgDoCheckMethod(builder: DirectiveWrapperBuilder) {
|
||||||
|
const changedVar = o.variable('changed');
|
||||||
|
const stmts: o.Statement[] = [
|
||||||
|
changedVar.set(o.THIS_EXPR.prop(CHANGED_FIELD_NAME)).toDeclStmt(),
|
||||||
|
o.THIS_EXPR.prop(CHANGED_FIELD_NAME).set(o.literal(false)).toStmt(),
|
||||||
|
];
|
||||||
|
const lifecycleStmts: o.Statement[] = [];
|
||||||
|
|
||||||
|
if (builder.genChanges) {
|
||||||
|
const onChangesStmts: o.Statement[] = [];
|
||||||
|
if (builder.ngOnChanges) {
|
||||||
|
onChangesStmts.push(o.THIS_EXPR.prop(CONTEXT_FIELD_NAME)
|
||||||
|
.callMethod('ngOnChanges', [o.THIS_EXPR.prop(CHANGES_FIELD_NAME)])
|
||||||
|
.toStmt());
|
||||||
|
}
|
||||||
|
if (builder.compilerConfig.logBindingUpdate) {
|
||||||
|
onChangesStmts.push(
|
||||||
|
o.importExpr(resolveIdentifier(Identifiers.setBindingDebugInfoForChanges))
|
||||||
|
.callFn(
|
||||||
|
[VIEW_VAR.prop('renderer'), RENDER_EL_VAR, o.THIS_EXPR.prop(CHANGES_FIELD_NAME)])
|
||||||
|
.toStmt());
|
||||||
|
}
|
||||||
|
onChangesStmts.push(RESET_CHANGES_STMT);
|
||||||
|
lifecycleStmts.push(new o.IfStmt(changedVar, onChangesStmts));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (builder.ngOnInit) {
|
||||||
|
lifecycleStmts.push(new o.IfStmt(
|
||||||
|
VIEW_VAR.prop('numberOfChecks').identical(new o.LiteralExpr(0)),
|
||||||
|
[o.THIS_EXPR.prop(CONTEXT_FIELD_NAME).callMethod('ngOnInit', []).toStmt()]));
|
||||||
|
}
|
||||||
|
if (builder.ngDoCheck) {
|
||||||
|
lifecycleStmts.push(o.THIS_EXPR.prop(CONTEXT_FIELD_NAME).callMethod('ngDoCheck', []).toStmt());
|
||||||
|
}
|
||||||
|
if (lifecycleStmts.length > 0) {
|
||||||
|
stmts.push(new o.IfStmt(o.not(THROW_ON_CHANGE_VAR), lifecycleStmts));
|
||||||
|
}
|
||||||
|
stmts.push(new o.ReturnStatement(changedVar));
|
||||||
|
|
||||||
|
builder.methods.push(new o.ClassMethod(
|
||||||
|
'ngDoCheck',
|
||||||
|
[
|
||||||
|
new o.FnParam(
|
||||||
|
VIEW_VAR.name, o.importType(resolveIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
|
||||||
|
new o.FnParam(RENDER_EL_VAR.name, o.DYNAMIC_TYPE),
|
||||||
|
new o.FnParam(THROW_ON_CHANGE_VAR.name, o.BOOL_TYPE),
|
||||||
|
],
|
||||||
|
stmts, o.BOOL_TYPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCheckInputMethod(input: string, builder: DirectiveWrapperBuilder) {
|
||||||
|
const field = createCheckBindingField(builder);
|
||||||
|
var onChangeStatements: o.Statement[] = [
|
||||||
|
o.THIS_EXPR.prop(CHANGED_FIELD_NAME).set(o.literal(true)).toStmt(),
|
||||||
|
o.THIS_EXPR.prop(CONTEXT_FIELD_NAME).prop(input).set(CURR_VALUE_VAR).toStmt(),
|
||||||
|
];
|
||||||
|
if (builder.genChanges) {
|
||||||
|
onChangeStatements.push(o.THIS_EXPR.prop(CHANGES_FIELD_NAME)
|
||||||
|
.key(o.literal(input))
|
||||||
|
.set(o.importExpr(resolveIdentifier(Identifiers.SimpleChange))
|
||||||
|
.instantiate([field.expression, CURR_VALUE_VAR]))
|
||||||
|
.toStmt());
|
||||||
|
}
|
||||||
|
|
||||||
|
var methodBody: o.Statement[] = createCheckBindingStmt(
|
||||||
|
{currValExpr: CURR_VALUE_VAR, forceUpdate: FORCE_UPDATE_VAR, stmts: []}, field.expression,
|
||||||
|
THROW_ON_CHANGE_VAR, onChangeStatements);
|
||||||
|
builder.methods.push(new o.ClassMethod(
|
||||||
|
`check_${input}`,
|
||||||
|
[
|
||||||
|
new o.FnParam(CURR_VALUE_VAR.name, o.DYNAMIC_TYPE),
|
||||||
|
new o.FnParam(THROW_ON_CHANGE_VAR.name, o.BOOL_TYPE),
|
||||||
|
new o.FnParam(FORCE_UPDATE_VAR.name, o.BOOL_TYPE),
|
||||||
|
],
|
||||||
|
methodBody));
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCheckHostMethod(
|
||||||
|
hostProps: BoundElementPropertyAst[], builder: DirectiveWrapperBuilder) {
|
||||||
|
const stmts: o.Statement[] = [];
|
||||||
|
const methodParams: o.FnParam[] = [
|
||||||
|
new o.FnParam(
|
||||||
|
VIEW_VAR.name, o.importType(resolveIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
|
||||||
|
new o.FnParam(
|
||||||
|
COMPONENT_VIEW_VAR.name,
|
||||||
|
o.importType(resolveIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
|
||||||
|
new o.FnParam(RENDER_EL_VAR.name, o.DYNAMIC_TYPE),
|
||||||
|
new o.FnParam(THROW_ON_CHANGE_VAR.name, o.BOOL_TYPE),
|
||||||
|
];
|
||||||
|
hostProps.forEach((hostProp, hostPropIdx) => {
|
||||||
|
const field = createCheckBindingField(builder);
|
||||||
|
const evalResult = convertPropertyBinding(
|
||||||
|
builder, null, o.THIS_EXPR.prop(CONTEXT_FIELD_NAME), hostProp.value, field.bindingId);
|
||||||
|
if (!evalResult) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let securityContextExpr: o.ReadVarExpr;
|
||||||
|
if (hostProp.needsRuntimeSecurityContext) {
|
||||||
|
securityContextExpr = o.variable(`secCtx_${methodParams.length}`);
|
||||||
|
methodParams.push(new o.FnParam(
|
||||||
|
securityContextExpr.name, o.importType(resolveIdentifier(Identifiers.SecurityContext))));
|
||||||
|
}
|
||||||
|
let checkBindingStmts: o.Statement[];
|
||||||
|
if (hostProp.isAnimation) {
|
||||||
|
const {updateStmts, detachStmts} = triggerAnimation(
|
||||||
|
VIEW_VAR, COMPONENT_VIEW_VAR, hostProp,
|
||||||
|
o.THIS_EXPR.prop(EVENT_HANDLER_FIELD_NAME)
|
||||||
|
.or(o.importExpr(resolveIdentifier(Identifiers.noop))),
|
||||||
|
RENDER_EL_VAR, evalResult.currValExpr, field.expression);
|
||||||
|
checkBindingStmts = updateStmts;
|
||||||
|
builder.detachStmts.push(...detachStmts);
|
||||||
|
} else {
|
||||||
|
checkBindingStmts = writeToRenderer(
|
||||||
|
VIEW_VAR, hostProp, RENDER_EL_VAR, evalResult.currValExpr,
|
||||||
|
builder.compilerConfig.logBindingUpdate, securityContextExpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
stmts.push(...createCheckBindingStmt(
|
||||||
|
evalResult, field.expression, THROW_ON_CHANGE_VAR, checkBindingStmts));
|
||||||
|
});
|
||||||
|
builder.methods.push(new o.ClassMethod('checkHost', methodParams, stmts));
|
||||||
|
}
|
||||||
|
|
||||||
|
function addHandleEventMethod(hostListeners: BoundEventAst[], builder: DirectiveWrapperBuilder) {
|
||||||
|
const resultVar = o.variable(`result`);
|
||||||
|
const actionStmts: o.Statement[] = [resultVar.set(o.literal(true)).toDeclStmt(o.BOOL_TYPE)];
|
||||||
|
hostListeners.forEach((hostListener, eventIdx) => {
|
||||||
|
const evalResult = convertActionBinding(
|
||||||
|
builder, null, o.THIS_EXPR.prop(CONTEXT_FIELD_NAME), hostListener.handler,
|
||||||
|
`sub_${eventIdx}`);
|
||||||
|
const trueStmts = evalResult.stmts;
|
||||||
|
if (evalResult.preventDefault) {
|
||||||
|
trueStmts.push(resultVar.set(evalResult.preventDefault.and(resultVar)).toStmt());
|
||||||
|
}
|
||||||
|
// TODO(tbosch): convert this into a `switch` once our OutputAst supports it.
|
||||||
|
actionStmts.push(
|
||||||
|
new o.IfStmt(EVENT_NAME_VAR.equals(o.literal(hostListener.fullName)), trueStmts));
|
||||||
|
});
|
||||||
|
actionStmts.push(new o.ReturnStatement(resultVar));
|
||||||
|
builder.methods.push(new o.ClassMethod(
|
||||||
|
'handleEvent',
|
||||||
|
[
|
||||||
|
new o.FnParam(EVENT_NAME_VAR.name, o.STRING_TYPE),
|
||||||
|
new o.FnParam(EventHandlerVars.event.name, o.DYNAMIC_TYPE)
|
||||||
|
],
|
||||||
|
actionStmts, o.BOOL_TYPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSubscribeMethod(dirMeta: CompileDirectiveMetadata, builder: DirectiveWrapperBuilder) {
|
||||||
|
const methodParams: o.FnParam[] = [
|
||||||
|
new o.FnParam(
|
||||||
|
VIEW_VAR.name, o.importType(resolveIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
|
||||||
|
new o.FnParam(EVENT_HANDLER_FIELD_NAME, o.DYNAMIC_TYPE)
|
||||||
|
];
|
||||||
|
const stmts: o.Statement[] = [
|
||||||
|
o.THIS_EXPR.prop(EVENT_HANDLER_FIELD_NAME).set(o.variable(EVENT_HANDLER_FIELD_NAME)).toStmt()
|
||||||
|
];
|
||||||
|
Object.keys(dirMeta.outputs).forEach((emitterPropName, emitterIdx) => {
|
||||||
|
const eventName = dirMeta.outputs[emitterPropName];
|
||||||
|
const paramName = `emit${emitterIdx}`;
|
||||||
|
methodParams.push(new o.FnParam(paramName, o.BOOL_TYPE));
|
||||||
|
const subscriptionFieldName = `subscription${emitterIdx}`;
|
||||||
|
builder.fields.push(new o.ClassField(subscriptionFieldName, o.DYNAMIC_TYPE));
|
||||||
|
stmts.push(new o.IfStmt(o.variable(paramName), [
|
||||||
|
o.THIS_EXPR.prop(subscriptionFieldName)
|
||||||
|
.set(o.THIS_EXPR.prop(CONTEXT_FIELD_NAME)
|
||||||
|
.prop(emitterPropName)
|
||||||
|
.callMethod(
|
||||||
|
o.BuiltinMethod.SubscribeObservable,
|
||||||
|
[o.variable(EVENT_HANDLER_FIELD_NAME)
|
||||||
|
.callMethod(o.BuiltinMethod.Bind, [VIEW_VAR, o.literal(eventName)])]))
|
||||||
|
.toStmt()
|
||||||
|
]));
|
||||||
|
builder.destroyStmts.push(
|
||||||
|
o.THIS_EXPR.prop(subscriptionFieldName)
|
||||||
|
.and(o.THIS_EXPR.prop(subscriptionFieldName).callMethod('unsubscribe', []))
|
||||||
|
.toStmt());
|
||||||
|
});
|
||||||
|
builder.methods.push(new o.ClassMethod('subscribe', methodParams, stmts));
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParseResult {
|
||||||
|
constructor(
|
||||||
|
public hostProps: BoundElementPropertyAst[], public hostListeners: BoundEventAst[],
|
||||||
|
public errors: ParseError[]) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseHostBindings(
|
||||||
|
dirMeta: CompileDirectiveMetadata, exprParser: Parser,
|
||||||
|
schemaRegistry: ElementSchemaRegistry): ParseResult {
|
||||||
|
const errors: ParseError[] = [];
|
||||||
|
const parser =
|
||||||
|
new BindingParser(exprParser, DEFAULT_INTERPOLATION_CONFIG, schemaRegistry, [], errors);
|
||||||
|
const sourceFileName = dirMeta.type.moduleUrl ?
|
||||||
|
`in Directive ${dirMeta.type.name} in ${dirMeta.type.moduleUrl}` :
|
||||||
|
`in Directive ${dirMeta.type.name}`;
|
||||||
|
const sourceFile = new ParseSourceFile('', sourceFileName);
|
||||||
|
const sourceSpan = new ParseSourceSpan(
|
||||||
|
new ParseLocation(sourceFile, null, null, null),
|
||||||
|
new ParseLocation(sourceFile, null, null, null));
|
||||||
|
const parsedHostProps = parser.createDirectiveHostPropertyAsts(dirMeta, sourceSpan);
|
||||||
|
const parsedHostListeners = parser.createDirectiveHostEventAsts(dirMeta, sourceSpan);
|
||||||
|
|
||||||
|
return new ParseResult(parsedHostProps, parsedHostListeners, errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reportParseErrors(parseErrors: ParseError[], console: Console) {
|
||||||
|
const warnings = parseErrors.filter(error => error.level === ParseErrorLevel.WARNING);
|
||||||
|
const errors = parseErrors.filter(error => error.level === ParseErrorLevel.FATAL);
|
||||||
|
|
||||||
|
if (warnings.length > 0) {
|
||||||
|
this._console.warn(`Directive parse warnings:\n${warnings.join('\n')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.length > 0) {
|
||||||
|
throw new Error(`Directive parse errors:\n${errors.join('\n')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DirectiveWrapperExpressions {
|
||||||
|
static create(dir: CompileIdentifierMetadata, depsExpr: o.Expression[]): o.Expression {
|
||||||
|
return o.importExpr(dir).instantiate(depsExpr, o.importType(dir));
|
||||||
|
}
|
||||||
|
static context(dirWrapper: o.Expression): o.ReadPropExpr {
|
||||||
|
return dirWrapper.prop(CONTEXT_FIELD_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ngDoCheck(
|
||||||
|
dirWrapper: o.Expression, view: o.Expression, renderElement: o.Expression,
|
||||||
|
throwOnChange: o.Expression): o.Expression {
|
||||||
|
return dirWrapper.callMethod('ngDoCheck', [view, renderElement, throwOnChange]);
|
||||||
|
}
|
||||||
|
static checkHost(
|
||||||
|
hostProps: BoundElementPropertyAst[], dirWrapper: o.Expression, view: o.Expression,
|
||||||
|
componentView: o.Expression, renderElement: o.Expression, throwOnChange: o.Expression,
|
||||||
|
runtimeSecurityContexts: o.Expression[]): o.Statement[] {
|
||||||
|
if (hostProps.length) {
|
||||||
|
return [dirWrapper
|
||||||
|
.callMethod(
|
||||||
|
'checkHost', [view, componentView, renderElement, throwOnChange].concat(
|
||||||
|
runtimeSecurityContexts))
|
||||||
|
.toStmt()];
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static ngOnDetach(
|
||||||
|
hostProps: BoundElementPropertyAst[], dirWrapper: o.Expression, view: o.Expression,
|
||||||
|
componentView: o.Expression, renderEl: o.Expression): o.Statement[] {
|
||||||
|
if (hostProps.some(prop => prop.isAnimation)) {
|
||||||
|
return [dirWrapper
|
||||||
|
.callMethod(
|
||||||
|
'ngOnDetach',
|
||||||
|
[
|
||||||
|
view,
|
||||||
|
componentView,
|
||||||
|
renderEl,
|
||||||
|
])
|
||||||
|
.toStmt()];
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static ngOnDestroy(dir: CompileDirectiveMetadata, dirWrapper: o.Expression): o.Statement[] {
|
||||||
|
if (dir.type.lifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1 ||
|
||||||
|
Object.keys(dir.outputs).length > 0) {
|
||||||
|
return [dirWrapper.callMethod('ngOnDestroy', []).toStmt()];
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static subscribe(
|
||||||
|
dirMeta: CompileDirectiveMetadata, hostProps: BoundElementPropertyAst[], usedEvents: string[],
|
||||||
|
dirWrapper: o.Expression, view: o.Expression, eventListener: o.Expression): o.Statement[] {
|
||||||
|
let needsSubscribe = false;
|
||||||
|
let eventFlags: o.Expression[] = [];
|
||||||
|
Object.keys(dirMeta.outputs).forEach((propName) => {
|
||||||
|
const eventName = dirMeta.outputs[propName];
|
||||||
|
const eventUsed = usedEvents.indexOf(eventName) > -1;
|
||||||
|
needsSubscribe = needsSubscribe || eventUsed;
|
||||||
|
eventFlags.push(o.literal(eventUsed));
|
||||||
|
});
|
||||||
|
hostProps.forEach((hostProp) => {
|
||||||
|
if (hostProp.isAnimation && usedEvents.length > 0) {
|
||||||
|
needsSubscribe = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (needsSubscribe) {
|
||||||
|
return [
|
||||||
|
dirWrapper.callMethod('subscribe', [view, eventListener].concat(eventFlags)).toStmt()
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static handleEvent(
|
||||||
|
hostEvents: BoundEventAst[], dirWrapper: o.Expression, eventName: o.Expression,
|
||||||
|
event: o.Expression): o.Expression {
|
||||||
|
return dirWrapper.callMethod('handleEvent', [eventName, event]);
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import * as chars from '../chars';
|
import * as chars from '../chars';
|
||||||
import {NumberWrapper, StringJoiner, StringWrapper, isPresent} from '../facade/lang';
|
import {NumberWrapper, isPresent} from '../facade/lang';
|
||||||
|
|
||||||
export enum TokenType {
|
export enum TokenType {
|
||||||
Character,
|
Character,
|
||||||
@ -93,7 +93,7 @@ export class Token {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function newCharacterToken(index: number, code: number): Token {
|
function newCharacterToken(index: number, code: number): Token {
|
||||||
return new Token(index, TokenType.Character, code, StringWrapper.fromCharCode(code));
|
return new Token(index, TokenType.Character, code, String.fromCharCode(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
function newIdentifierToken(index: number, text: string): Token {
|
function newIdentifierToken(index: number, text: string): Token {
|
||||||
@ -133,8 +133,7 @@ class _Scanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
advance() {
|
advance() {
|
||||||
this.peek =
|
this.peek = ++this.index >= this.length ? chars.$EOF : this.input.charCodeAt(this.index);
|
||||||
++this.index >= this.length ? chars.$EOF : StringWrapper.charCodeAt(this.input, this.index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scanToken(): Token {
|
scanToken(): Token {
|
||||||
@ -146,7 +145,7 @@ class _Scanner {
|
|||||||
peek = chars.$EOF;
|
peek = chars.$EOF;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
peek = StringWrapper.charCodeAt(input, index);
|
peek = input.charCodeAt(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,16 +186,16 @@ class _Scanner {
|
|||||||
case chars.$SLASH:
|
case chars.$SLASH:
|
||||||
case chars.$PERCENT:
|
case chars.$PERCENT:
|
||||||
case chars.$CARET:
|
case chars.$CARET:
|
||||||
return this.scanOperator(start, StringWrapper.fromCharCode(peek));
|
return this.scanOperator(start, String.fromCharCode(peek));
|
||||||
case chars.$QUESTION:
|
case chars.$QUESTION:
|
||||||
return this.scanComplexOperator(start, '?', chars.$PERIOD, '.');
|
return this.scanComplexOperator(start, '?', chars.$PERIOD, '.');
|
||||||
case chars.$LT:
|
case chars.$LT:
|
||||||
case chars.$GT:
|
case chars.$GT:
|
||||||
return this.scanComplexOperator(start, StringWrapper.fromCharCode(peek), chars.$EQ, '=');
|
return this.scanComplexOperator(start, String.fromCharCode(peek), chars.$EQ, '=');
|
||||||
case chars.$BANG:
|
case chars.$BANG:
|
||||||
case chars.$EQ:
|
case chars.$EQ:
|
||||||
return this.scanComplexOperator(
|
return this.scanComplexOperator(
|
||||||
start, StringWrapper.fromCharCode(peek), chars.$EQ, '=', chars.$EQ, '=');
|
start, String.fromCharCode(peek), chars.$EQ, '=', chars.$EQ, '=');
|
||||||
case chars.$AMPERSAND:
|
case chars.$AMPERSAND:
|
||||||
return this.scanComplexOperator(start, '&', chars.$AMPERSAND, '&');
|
return this.scanComplexOperator(start, '&', chars.$AMPERSAND, '&');
|
||||||
case chars.$BAR:
|
case chars.$BAR:
|
||||||
@ -207,7 +206,7 @@ class _Scanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.advance();
|
this.advance();
|
||||||
return this.error(`Unexpected character [${StringWrapper.fromCharCode(peek)}]`, 0);
|
return this.error(`Unexpected character [${String.fromCharCode(peek)}]`, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
scanCharacter(start: number, code: number): Token {
|
scanCharacter(start: number, code: number): Token {
|
||||||
@ -275,42 +274,41 @@ class _Scanner {
|
|||||||
}
|
}
|
||||||
this.advance();
|
this.advance();
|
||||||
}
|
}
|
||||||
var str: string = this.input.substring(start, this.index);
|
const str: string = this.input.substring(start, this.index);
|
||||||
var value: number = simple ? NumberWrapper.parseIntAutoRadix(str) : parseFloat(str);
|
const value: number = simple ? NumberWrapper.parseIntAutoRadix(str) : parseFloat(str);
|
||||||
return newNumberToken(start, value);
|
return newNumberToken(start, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
scanString(): Token {
|
scanString(): Token {
|
||||||
var start: number = this.index;
|
const start: number = this.index;
|
||||||
var quote: number = this.peek;
|
const quote: number = this.peek;
|
||||||
this.advance(); // Skip initial quote.
|
this.advance(); // Skip initial quote.
|
||||||
|
|
||||||
var buffer: StringJoiner;
|
let buffer: string = '';
|
||||||
var marker: number = this.index;
|
let marker: number = this.index;
|
||||||
var input: string = this.input;
|
let input: string = this.input;
|
||||||
|
|
||||||
while (this.peek != quote) {
|
while (this.peek != quote) {
|
||||||
if (this.peek == chars.$BACKSLASH) {
|
if (this.peek == chars.$BACKSLASH) {
|
||||||
if (buffer == null) buffer = new StringJoiner();
|
buffer += input.substring(marker, this.index);
|
||||||
buffer.add(input.substring(marker, this.index));
|
|
||||||
this.advance();
|
this.advance();
|
||||||
var unescapedCode: number;
|
let unescapedCode: number;
|
||||||
if (this.peek == chars.$u) {
|
if (this.peek == chars.$u) {
|
||||||
// 4 character hex code for unicode character.
|
// 4 character hex code for unicode character.
|
||||||
var hex: string = input.substring(this.index + 1, this.index + 5);
|
const hex: string = input.substring(this.index + 1, this.index + 5);
|
||||||
try {
|
try {
|
||||||
unescapedCode = NumberWrapper.parseInt(hex, 16);
|
unescapedCode = NumberWrapper.parseInt(hex, 16);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return this.error(`Invalid unicode escape [\\u${hex}]`, 0);
|
return this.error(`Invalid unicode escape [\\u${hex}]`, 0);
|
||||||
}
|
}
|
||||||
for (var i: number = 0; i < 5; i++) {
|
for (let i: number = 0; i < 5; i++) {
|
||||||
this.advance();
|
this.advance();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unescapedCode = unescape(this.peek);
|
unescapedCode = unescape(this.peek);
|
||||||
this.advance();
|
this.advance();
|
||||||
}
|
}
|
||||||
buffer.add(StringWrapper.fromCharCode(unescapedCode));
|
buffer += String.fromCharCode(unescapedCode);
|
||||||
marker = this.index;
|
marker = this.index;
|
||||||
} else if (this.peek == chars.$EOF) {
|
} else if (this.peek == chars.$EOF) {
|
||||||
return this.error('Unterminated quote', 0);
|
return this.error('Unterminated quote', 0);
|
||||||
@ -319,16 +317,10 @@ class _Scanner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var last: string = input.substring(marker, this.index);
|
const last: string = input.substring(marker, this.index);
|
||||||
this.advance(); // Skip terminating quote.
|
this.advance(); // Skip terminating quote.
|
||||||
|
|
||||||
// Compute the unescaped string value.
|
return newStringToken(start, buffer + last);
|
||||||
var unescaped: string = last;
|
|
||||||
if (buffer != null) {
|
|
||||||
buffer.add(last);
|
|
||||||
unescaped = buffer.toString();
|
|
||||||
}
|
|
||||||
return newStringToken(start, unescaped);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error(message: string, offset: number): Token {
|
error(message: string, offset: number): Token {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
|
|
||||||
import * as chars from '../chars';
|
import * as chars from '../chars';
|
||||||
import {StringWrapper, escapeRegExp, isBlank, isPresent} from '../facade/lang';
|
import {escapeRegExp, isBlank, isPresent} from '../facade/lang';
|
||||||
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../ml_parser/interpolation_config';
|
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../ml_parser/interpolation_config';
|
||||||
|
|
||||||
import {AST, ASTWithSource, AstVisitor, Binary, BindingPipe, Chain, Conditional, EmptyExpr, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, ParseSpan, ParserError, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead, TemplateBinding} from './ast';
|
import {AST, ASTWithSource, AstVisitor, Binary, BindingPipe, Chain, Conditional, EmptyExpr, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, ParseSpan, ParserError, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead, TemplateBinding} from './ast';
|
||||||
@ -17,7 +17,7 @@ import {EOF, Lexer, Token, TokenType, isIdentifier, isQuote} from './lexer';
|
|||||||
|
|
||||||
|
|
||||||
export class SplitInterpolation {
|
export class SplitInterpolation {
|
||||||
constructor(public strings: string[], public expressions: string[]) {}
|
constructor(public strings: string[], public expressions: string[], public offsets: number[]) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TemplateBindingParseResult {
|
export class TemplateBindingParseResult {
|
||||||
@ -41,8 +41,12 @@ export class Parser {
|
|||||||
input: string, location: any,
|
input: string, location: any,
|
||||||
interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): ASTWithSource {
|
interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): ASTWithSource {
|
||||||
this._checkNoInterpolation(input, location, interpolationConfig);
|
this._checkNoInterpolation(input, location, interpolationConfig);
|
||||||
|
const sourceToLex = this._stripComments(input);
|
||||||
const tokens = this._lexer.tokenize(this._stripComments(input));
|
const tokens = this._lexer.tokenize(this._stripComments(input));
|
||||||
const ast = new _ParseAST(input, location, tokens, true, this.errors).parseChain();
|
const ast = new _ParseAST(
|
||||||
|
input, location, tokens, sourceToLex.length, true, this.errors,
|
||||||
|
input.length - sourceToLex.length)
|
||||||
|
.parseChain();
|
||||||
return new ASTWithSource(ast, input, location, this.errors);
|
return new ASTWithSource(ast, input, location, this.errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,10 +60,11 @@ export class Parser {
|
|||||||
parseSimpleBinding(
|
parseSimpleBinding(
|
||||||
input: string, location: string,
|
input: string, location: string,
|
||||||
interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): ASTWithSource {
|
interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): ASTWithSource {
|
||||||
var ast = this._parseBindingAst(input, location, interpolationConfig);
|
const ast = this._parseBindingAst(input, location, interpolationConfig);
|
||||||
if (!SimpleExpressionChecker.check(ast)) {
|
const errors = SimpleExpressionChecker.check(ast);
|
||||||
|
if (errors.length > 0) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
'Host binding expression can only contain field access and constants', input, location);
|
`Host binding expression cannot contain ${errors.join(' ')}`, input, location);
|
||||||
}
|
}
|
||||||
return new ASTWithSource(ast, input, location, this.errors);
|
return new ASTWithSource(ast, input, location, this.errors);
|
||||||
}
|
}
|
||||||
@ -79,8 +84,12 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._checkNoInterpolation(input, location, interpolationConfig);
|
this._checkNoInterpolation(input, location, interpolationConfig);
|
||||||
var tokens = this._lexer.tokenize(this._stripComments(input));
|
const sourceToLex = this._stripComments(input);
|
||||||
return new _ParseAST(input, location, tokens, false, this.errors).parseChain();
|
const tokens = this._lexer.tokenize(sourceToLex);
|
||||||
|
return new _ParseAST(
|
||||||
|
input, location, tokens, sourceToLex.length, false, this.errors,
|
||||||
|
input.length - sourceToLex.length)
|
||||||
|
.parseChain();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _parseQuote(input: string, location: any): AST {
|
private _parseQuote(input: string, location: any): AST {
|
||||||
@ -95,7 +104,8 @@ export class Parser {
|
|||||||
|
|
||||||
parseTemplateBindings(input: string, location: any): TemplateBindingParseResult {
|
parseTemplateBindings(input: string, location: any): TemplateBindingParseResult {
|
||||||
var tokens = this._lexer.tokenize(input);
|
var tokens = this._lexer.tokenize(input);
|
||||||
return new _ParseAST(input, location, tokens, false, this.errors).parseTemplateBindings();
|
return new _ParseAST(input, location, tokens, input.length, false, this.errors, 0)
|
||||||
|
.parseTemplateBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
parseInterpolation(
|
parseInterpolation(
|
||||||
@ -107,8 +117,13 @@ export class Parser {
|
|||||||
let expressions: AST[] = [];
|
let expressions: AST[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < split.expressions.length; ++i) {
|
for (let i = 0; i < split.expressions.length; ++i) {
|
||||||
var tokens = this._lexer.tokenize(this._stripComments(split.expressions[i]));
|
const expressionText = split.expressions[i];
|
||||||
var ast = new _ParseAST(input, location, tokens, false, this.errors).parseChain();
|
const sourceToLex = this._stripComments(expressionText);
|
||||||
|
const tokens = this._lexer.tokenize(this._stripComments(split.expressions[i]));
|
||||||
|
const ast = new _ParseAST(
|
||||||
|
input, location, tokens, sourceToLex.length, false, this.errors,
|
||||||
|
split.offsets[i] + (expressionText.length - sourceToLex.length))
|
||||||
|
.parseChain();
|
||||||
expressions.push(ast);
|
expressions.push(ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,20 +137,25 @@ export class Parser {
|
|||||||
input: string, location: string,
|
input: string, location: string,
|
||||||
interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): SplitInterpolation {
|
interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): SplitInterpolation {
|
||||||
const regexp = _createInterpolateRegExp(interpolationConfig);
|
const regexp = _createInterpolateRegExp(interpolationConfig);
|
||||||
const parts = StringWrapper.split(input, regexp);
|
const parts = input.split(regexp);
|
||||||
if (parts.length <= 1) {
|
if (parts.length <= 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const strings: string[] = [];
|
const strings: string[] = [];
|
||||||
const expressions: string[] = [];
|
const expressions: string[] = [];
|
||||||
|
const offsets: number[] = [];
|
||||||
|
let offset = 0;
|
||||||
for (let i = 0; i < parts.length; i++) {
|
for (let i = 0; i < parts.length; i++) {
|
||||||
var part: string = parts[i];
|
var part: string = parts[i];
|
||||||
if (i % 2 === 0) {
|
if (i % 2 === 0) {
|
||||||
// fixed string
|
// fixed string
|
||||||
strings.push(part);
|
strings.push(part);
|
||||||
|
offset += part.length;
|
||||||
} else if (part.trim().length > 0) {
|
} else if (part.trim().length > 0) {
|
||||||
|
offset += interpolationConfig.start.length;
|
||||||
expressions.push(part);
|
expressions.push(part);
|
||||||
|
offsets.push(offset);
|
||||||
|
offset += part.length + interpolationConfig.end.length;
|
||||||
} else {
|
} else {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
'Blank expressions are not allowed in interpolated strings', input,
|
'Blank expressions are not allowed in interpolated strings', input,
|
||||||
@ -143,7 +163,7 @@ export class Parser {
|
|||||||
location);
|
location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new SplitInterpolation(strings, expressions);
|
return new SplitInterpolation(strings, expressions, offsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapLiteralPrimitive(input: string, location: any): ASTWithSource {
|
wrapLiteralPrimitive(input: string, location: any): ASTWithSource {
|
||||||
@ -160,8 +180,8 @@ export class Parser {
|
|||||||
private _commentStart(input: string): number {
|
private _commentStart(input: string): number {
|
||||||
var outerQuote: number = null;
|
var outerQuote: number = null;
|
||||||
for (let i = 0; i < input.length - 1; i++) {
|
for (let i = 0; i < input.length - 1; i++) {
|
||||||
const char = StringWrapper.charCodeAt(input, i);
|
const char = input.charCodeAt(i);
|
||||||
const nextChar = StringWrapper.charCodeAt(input, i + 1);
|
const nextChar = input.charCodeAt(i + 1);
|
||||||
|
|
||||||
if (char === chars.$SLASH && nextChar == chars.$SLASH && isBlank(outerQuote)) return i;
|
if (char === chars.$SLASH && nextChar == chars.$SLASH && isBlank(outerQuote)) return i;
|
||||||
|
|
||||||
@ -177,7 +197,7 @@ export class Parser {
|
|||||||
private _checkNoInterpolation(
|
private _checkNoInterpolation(
|
||||||
input: string, location: any, interpolationConfig: InterpolationConfig): void {
|
input: string, location: any, interpolationConfig: InterpolationConfig): void {
|
||||||
var regexp = _createInterpolateRegExp(interpolationConfig);
|
var regexp = _createInterpolateRegExp(interpolationConfig);
|
||||||
var parts = StringWrapper.split(input, regexp);
|
var parts = input.split(regexp);
|
||||||
if (parts.length > 1) {
|
if (parts.length > 1) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
`Got interpolation (${interpolationConfig.start}${interpolationConfig.end}) where expression was expected`,
|
`Got interpolation (${interpolationConfig.start}${interpolationConfig.end}) where expression was expected`,
|
||||||
@ -208,8 +228,9 @@ export class _ParseAST {
|
|||||||
index: number = 0;
|
index: number = 0;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public input: string, public location: any, public tokens: any[], public parseAction: boolean,
|
public input: string, public location: any, public tokens: Token[],
|
||||||
private errors: ParserError[]) {}
|
public inputLength: number, public parseAction: boolean, private errors: ParserError[],
|
||||||
|
private offset: number) {}
|
||||||
|
|
||||||
peek(offset: number): Token {
|
peek(offset: number): Token {
|
||||||
var i = this.index + offset;
|
var i = this.index + offset;
|
||||||
@ -219,7 +240,8 @@ export class _ParseAST {
|
|||||||
get next(): Token { return this.peek(0); }
|
get next(): Token { return this.peek(0); }
|
||||||
|
|
||||||
get inputIndex(): number {
|
get inputIndex(): number {
|
||||||
return (this.index < this.tokens.length) ? this.next.index : this.input.length;
|
return (this.index < this.tokens.length) ? this.next.index + this.offset :
|
||||||
|
this.inputLength + this.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
span(start: number) { return new ParseSpan(start, this.inputIndex); }
|
span(start: number) { return new ParseSpan(start, this.inputIndex); }
|
||||||
@ -239,7 +261,7 @@ export class _ParseAST {
|
|||||||
|
|
||||||
expectCharacter(code: number) {
|
expectCharacter(code: number) {
|
||||||
if (this.optionalCharacter(code)) return;
|
if (this.optionalCharacter(code)) return;
|
||||||
this.error(`Missing expected ${StringWrapper.fromCharCode(code)}`);
|
this.error(`Missing expected ${String.fromCharCode(code)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
optionalOperator(op: string): boolean {
|
optionalOperator(op: string): boolean {
|
||||||
@ -311,7 +333,7 @@ export class _ParseAST {
|
|||||||
while (this.optionalCharacter(chars.$COLON)) {
|
while (this.optionalCharacter(chars.$COLON)) {
|
||||||
args.push(this.parseExpression());
|
args.push(this.parseExpression());
|
||||||
}
|
}
|
||||||
result = new BindingPipe(this.span(result.span.start), result, name, args);
|
result = new BindingPipe(this.span(result.span.start - this.offset), result, name, args);
|
||||||
} while (this.optionalOperator('|'));
|
} while (this.optionalOperator('|'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -730,51 +752,51 @@ export class _ParseAST {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SimpleExpressionChecker implements AstVisitor {
|
class SimpleExpressionChecker implements AstVisitor {
|
||||||
static check(ast: AST): boolean {
|
static check(ast: AST): string[] {
|
||||||
var s = new SimpleExpressionChecker();
|
var s = new SimpleExpressionChecker();
|
||||||
ast.visit(s);
|
ast.visit(s);
|
||||||
return s.simple;
|
return s.errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
simple = true;
|
errors: string[] = [];
|
||||||
|
|
||||||
visitImplicitReceiver(ast: ImplicitReceiver, context: any) {}
|
visitImplicitReceiver(ast: ImplicitReceiver, context: any) {}
|
||||||
|
|
||||||
visitInterpolation(ast: Interpolation, context: any) { this.simple = false; }
|
visitInterpolation(ast: Interpolation, context: any) {}
|
||||||
|
|
||||||
visitLiteralPrimitive(ast: LiteralPrimitive, context: any) {}
|
visitLiteralPrimitive(ast: LiteralPrimitive, context: any) {}
|
||||||
|
|
||||||
visitPropertyRead(ast: PropertyRead, context: any) {}
|
visitPropertyRead(ast: PropertyRead, context: any) {}
|
||||||
|
|
||||||
visitPropertyWrite(ast: PropertyWrite, context: any) { this.simple = false; }
|
visitPropertyWrite(ast: PropertyWrite, context: any) {}
|
||||||
|
|
||||||
visitSafePropertyRead(ast: SafePropertyRead, context: any) { this.simple = false; }
|
visitSafePropertyRead(ast: SafePropertyRead, context: any) {}
|
||||||
|
|
||||||
visitMethodCall(ast: MethodCall, context: any) { this.simple = false; }
|
visitMethodCall(ast: MethodCall, context: any) {}
|
||||||
|
|
||||||
visitSafeMethodCall(ast: SafeMethodCall, context: any) { this.simple = false; }
|
visitSafeMethodCall(ast: SafeMethodCall, context: any) {}
|
||||||
|
|
||||||
visitFunctionCall(ast: FunctionCall, context: any) { this.simple = false; }
|
visitFunctionCall(ast: FunctionCall, context: any) {}
|
||||||
|
|
||||||
visitLiteralArray(ast: LiteralArray, context: any) { this.visitAll(ast.expressions); }
|
visitLiteralArray(ast: LiteralArray, context: any) { this.visitAll(ast.expressions); }
|
||||||
|
|
||||||
visitLiteralMap(ast: LiteralMap, context: any) { this.visitAll(ast.values); }
|
visitLiteralMap(ast: LiteralMap, context: any) { this.visitAll(ast.values); }
|
||||||
|
|
||||||
visitBinary(ast: Binary, context: any) { this.simple = false; }
|
visitBinary(ast: Binary, context: any) {}
|
||||||
|
|
||||||
visitPrefixNot(ast: PrefixNot, context: any) { this.simple = false; }
|
visitPrefixNot(ast: PrefixNot, context: any) {}
|
||||||
|
|
||||||
visitConditional(ast: Conditional, context: any) { this.simple = false; }
|
visitConditional(ast: Conditional, context: any) {}
|
||||||
|
|
||||||
visitPipe(ast: BindingPipe, context: any) { this.simple = false; }
|
visitPipe(ast: BindingPipe, context: any) { this.errors.push('pipes'); }
|
||||||
|
|
||||||
visitKeyedRead(ast: KeyedRead, context: any) { this.simple = false; }
|
visitKeyedRead(ast: KeyedRead, context: any) {}
|
||||||
|
|
||||||
visitKeyedWrite(ast: KeyedWrite, context: any) { this.simple = false; }
|
visitKeyedWrite(ast: KeyedWrite, context: any) {}
|
||||||
|
|
||||||
visitAll(asts: any[]): any[] { return asts.map(node => node.visit(this)); }
|
visitAll(asts: any[]): any[] { return asts.map(node => node.visit(this)); }
|
||||||
|
|
||||||
visitChain(ast: Chain, context: any) { this.simple = false; }
|
visitChain(ast: Chain, context: any) {}
|
||||||
|
|
||||||
visitQuote(ast: Quote, context: any) { this.simple = false; }
|
visitQuote(ast: Quote, context: any) {}
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,10 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ElementRef, Injector, LOCALE_ID as LOCALE_ID_, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TRANSLATIONS_FORMAT as TRANSLATIONS_FORMAT_, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
|
import {ANALYZE_FOR_ENTRY_COMPONENTS, AnimationTransitionEvent, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ElementRef, Injector, LOCALE_ID, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TRANSLATIONS_FORMAT, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
|
||||||
|
|
||||||
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
|
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
|
||||||
import {AnimationGroupPlayer, AnimationKeyframe, AnimationSequencePlayer, AnimationStyles, AppElement, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, DebugAppView, DebugContext, EMPTY_ARRAY, EMPTY_MAP, NgModuleInjector, NoOpAnimationPlayer, StaticNodeDebugInfo, TemplateRef_, UNINITIALIZED, ValueUnwrapper, ViewType, ViewUtils, balanceAnimationKeyframes, castByValue, checkBinding, clearStyles, collectAndResolveStyles, devModeEqual, flattenNestedViewRenderNodes, interpolate, prepareFinalAnimationStyles, pureProxy1, pureProxy10, pureProxy2, pureProxy3, pureProxy4, pureProxy5, pureProxy6, pureProxy7, pureProxy8, pureProxy9, reflector, registerModuleFactory, renderStyles} from './private_import_core';
|
import {AnimationGroupPlayer, AnimationKeyframe, AnimationSequencePlayer, AnimationStyles, AnimationTransition, AppElement, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, DebugAppView, DebugContext, NgModuleInjector, NoOpAnimationPlayer, StaticNodeDebugInfo, TemplateRef_, UNINITIALIZED, ValueUnwrapper, ViewType, balanceAnimationKeyframes, clearStyles, collectAndResolveStyles, devModeEqual, prepareFinalAnimationStyles, reflector, registerModuleFactory, renderStyles, view_utils} from './private_import_core';
|
||||||
import {assetUrl} from './util';
|
|
||||||
|
|
||||||
var APP_VIEW_MODULE_URL = assetUrl('core', 'linker/view');
|
var APP_VIEW_MODULE_URL = assetUrl('core', 'linker/view');
|
||||||
var VIEW_UTILS_MODULE_URL = assetUrl('core', 'linker/view_utils');
|
var VIEW_UTILS_MODULE_URL = assetUrl('core', 'linker/view_utils');
|
||||||
@ -33,7 +32,7 @@ export class Identifiers {
|
|||||||
static ViewUtils: IdentifierSpec = {
|
static ViewUtils: IdentifierSpec = {
|
||||||
name: 'ViewUtils',
|
name: 'ViewUtils',
|
||||||
moduleUrl: assetUrl('core', 'linker/view_utils'),
|
moduleUrl: assetUrl('core', 'linker/view_utils'),
|
||||||
runtime: ViewUtils
|
runtime: view_utils.ViewUtils
|
||||||
};
|
};
|
||||||
static AppView:
|
static AppView:
|
||||||
IdentifierSpec = {name: 'AppView', moduleUrl: APP_VIEW_MODULE_URL, runtime: AppView};
|
IdentifierSpec = {name: 'AppView', moduleUrl: APP_VIEW_MODULE_URL, runtime: AppView};
|
||||||
@ -161,45 +160,52 @@ export class Identifiers {
|
|||||||
static checkBinding: IdentifierSpec = {
|
static checkBinding: IdentifierSpec = {
|
||||||
name: 'checkBinding',
|
name: 'checkBinding',
|
||||||
moduleUrl: VIEW_UTILS_MODULE_URL,
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
runtime: checkBinding
|
runtime: view_utils.checkBinding
|
||||||
};
|
|
||||||
static flattenNestedViewRenderNodes: IdentifierSpec = {
|
|
||||||
name: 'flattenNestedViewRenderNodes',
|
|
||||||
moduleUrl: VIEW_UTILS_MODULE_URL,
|
|
||||||
runtime: flattenNestedViewRenderNodes
|
|
||||||
};
|
};
|
||||||
static devModeEqual:
|
static devModeEqual:
|
||||||
IdentifierSpec = {name: 'devModeEqual', moduleUrl: CD_MODULE_URL, runtime: devModeEqual};
|
IdentifierSpec = {name: 'devModeEqual', moduleUrl: CD_MODULE_URL, runtime: devModeEqual};
|
||||||
static interpolate: IdentifierSpec = {
|
static interpolate: IdentifierSpec = {
|
||||||
name: 'interpolate',
|
name: 'interpolate',
|
||||||
moduleUrl: VIEW_UTILS_MODULE_URL,
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
runtime: interpolate
|
runtime: view_utils.interpolate
|
||||||
};
|
};
|
||||||
static castByValue: IdentifierSpec = {
|
static castByValue: IdentifierSpec = {
|
||||||
name: 'castByValue',
|
name: 'castByValue',
|
||||||
moduleUrl: VIEW_UTILS_MODULE_URL,
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
runtime: castByValue
|
runtime: view_utils.castByValue
|
||||||
};
|
};
|
||||||
static EMPTY_ARRAY: IdentifierSpec = {
|
static EMPTY_ARRAY: IdentifierSpec = {
|
||||||
name: 'EMPTY_ARRAY',
|
name: 'EMPTY_ARRAY',
|
||||||
moduleUrl: VIEW_UTILS_MODULE_URL,
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
runtime: EMPTY_ARRAY
|
runtime: view_utils.EMPTY_ARRAY
|
||||||
};
|
};
|
||||||
static EMPTY_MAP:
|
static EMPTY_MAP: IdentifierSpec = {
|
||||||
IdentifierSpec = {name: 'EMPTY_MAP', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: EMPTY_MAP};
|
name: 'EMPTY_MAP',
|
||||||
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
static pureProxies = [
|
runtime: view_utils.EMPTY_MAP
|
||||||
|
};
|
||||||
|
static createRenderElement: IdentifierSpec = {
|
||||||
|
name: 'createRenderElement',
|
||||||
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
|
runtime: view_utils.createRenderElement
|
||||||
|
};
|
||||||
|
static selectOrCreateRenderHostElement: IdentifierSpec = {
|
||||||
|
name: 'selectOrCreateRenderHostElement',
|
||||||
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
|
runtime: view_utils.selectOrCreateRenderHostElement
|
||||||
|
};
|
||||||
|
static pureProxies: IdentifierSpec[] = [
|
||||||
null,
|
null,
|
||||||
{name: 'pureProxy1', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy1},
|
{name: 'pureProxy1', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.pureProxy1},
|
||||||
{name: 'pureProxy2', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy2},
|
{name: 'pureProxy2', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.pureProxy2},
|
||||||
{name: 'pureProxy3', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy3},
|
{name: 'pureProxy3', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.pureProxy3},
|
||||||
{name: 'pureProxy4', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy4},
|
{name: 'pureProxy4', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.pureProxy4},
|
||||||
{name: 'pureProxy5', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy5},
|
{name: 'pureProxy5', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.pureProxy5},
|
||||||
{name: 'pureProxy6', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy6},
|
{name: 'pureProxy6', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.pureProxy6},
|
||||||
{name: 'pureProxy7', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy7},
|
{name: 'pureProxy7', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.pureProxy7},
|
||||||
{name: 'pureProxy8', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy8},
|
{name: 'pureProxy8', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.pureProxy8},
|
||||||
{name: 'pureProxy9', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy9},
|
{name: 'pureProxy9', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.pureProxy9},
|
||||||
{name: 'pureProxy10', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy10},
|
{name: 'pureProxy10', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.pureProxy10},
|
||||||
];
|
];
|
||||||
static SecurityContext: IdentifierSpec = {
|
static SecurityContext: IdentifierSpec = {
|
||||||
name: 'SecurityContext',
|
name: 'SecurityContext',
|
||||||
@ -259,13 +265,64 @@ export class Identifiers {
|
|||||||
static LOCALE_ID: IdentifierSpec = {
|
static LOCALE_ID: IdentifierSpec = {
|
||||||
name: 'LOCALE_ID',
|
name: 'LOCALE_ID',
|
||||||
moduleUrl: assetUrl('core', 'i18n/tokens'),
|
moduleUrl: assetUrl('core', 'i18n/tokens'),
|
||||||
runtime: LOCALE_ID_
|
runtime: LOCALE_ID
|
||||||
};
|
};
|
||||||
static TRANSLATIONS_FORMAT: IdentifierSpec = {
|
static TRANSLATIONS_FORMAT: IdentifierSpec = {
|
||||||
name: 'TRANSLATIONS_FORMAT',
|
name: 'TRANSLATIONS_FORMAT',
|
||||||
moduleUrl: assetUrl('core', 'i18n/tokens'),
|
moduleUrl: assetUrl('core', 'i18n/tokens'),
|
||||||
runtime: TRANSLATIONS_FORMAT_
|
runtime: TRANSLATIONS_FORMAT
|
||||||
};
|
};
|
||||||
|
static setBindingDebugInfo: IdentifierSpec = {
|
||||||
|
name: 'setBindingDebugInfo',
|
||||||
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
|
runtime: view_utils.setBindingDebugInfo
|
||||||
|
};
|
||||||
|
static setBindingDebugInfoForChanges: IdentifierSpec = {
|
||||||
|
name: 'setBindingDebugInfoForChanges',
|
||||||
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
|
runtime: view_utils.setBindingDebugInfoForChanges
|
||||||
|
};
|
||||||
|
static AnimationTransition: IdentifierSpec = {
|
||||||
|
name: 'AnimationTransition',
|
||||||
|
moduleUrl: assetUrl('core', 'animation/animation_transition'),
|
||||||
|
runtime: AnimationTransition
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is just the interface!
|
||||||
|
static InlineArray:
|
||||||
|
IdentifierSpec = {name: 'InlineArray', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: null};
|
||||||
|
static inlineArrays: IdentifierSpec[] = [
|
||||||
|
{name: 'InlineArray2', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.InlineArray2},
|
||||||
|
{name: 'InlineArray2', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.InlineArray2},
|
||||||
|
{name: 'InlineArray4', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.InlineArray4},
|
||||||
|
{name: 'InlineArray8', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.InlineArray8},
|
||||||
|
{name: 'InlineArray16', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.InlineArray16},
|
||||||
|
];
|
||||||
|
static EMPTY_INLINE_ARRAY: IdentifierSpec = {
|
||||||
|
name: 'EMPTY_INLINE_ARRAY',
|
||||||
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
|
runtime: view_utils.EMPTY_INLINE_ARRAY
|
||||||
|
};
|
||||||
|
static InlineArrayDynamic: IdentifierSpec = {
|
||||||
|
name: 'InlineArrayDynamic',
|
||||||
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
|
runtime: view_utils.InlineArrayDynamic
|
||||||
|
};
|
||||||
|
static subscribeToRenderElement: IdentifierSpec = {
|
||||||
|
name: 'subscribeToRenderElement',
|
||||||
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
|
runtime: view_utils.subscribeToRenderElement
|
||||||
|
};
|
||||||
|
static noop:
|
||||||
|
IdentifierSpec = {name: 'noop', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.noop};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assetUrl(pkg: string, path: string = null, type: string = 'src'): string {
|
||||||
|
if (path == null) {
|
||||||
|
return `asset:@angular/lib/${pkg}/index`;
|
||||||
|
} else {
|
||||||
|
return `asset:@angular/lib/${pkg}/src/${path}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveIdentifier(identifier: IdentifierSpec) {
|
export function resolveIdentifier(identifier: IdentifierSpec) {
|
||||||
|
@ -1,20 +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
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @module
|
|
||||||
* @description
|
|
||||||
* Starting point to import all compiler APIs.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export {COMPILER_PROVIDERS, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileFactoryMetadata, CompileIdentifierMetadata, CompileMetadataWithIdentifier, CompilePipeMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata, CompilerConfig, DEFAULT_PACKAGE_URL_PROVIDER, DirectiveResolver, NgModuleResolver, OfflineCompiler, PipeResolver, RenderTypes, ResourceLoader, RuntimeCompiler, SourceModule, TEMPLATE_TRANSFORMS, UrlResolver, createOfflineCompileUrlResolver, platformCoreDynamic} from './compiler';
|
|
||||||
export {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from './ml_parser/interpolation_config';
|
|
||||||
export {ElementSchemaRegistry} from './schema/element_schema_registry';
|
|
||||||
export * from './i18n/index';
|
|
||||||
export * from './template_parser/template_ast';
|
|
||||||
export * from './private_export';
|
|
@ -6,35 +6,30 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, DoCheck, OnChanges, OnDestroy, OnInit, Type} from '@angular/core';
|
|
||||||
|
|
||||||
import {MapWrapper} from './facade/collection';
|
|
||||||
import {LifecycleHooks, reflector} from './private_import_core';
|
import {LifecycleHooks, reflector} from './private_import_core';
|
||||||
|
|
||||||
const LIFECYCLE_INTERFACES: Map<any, Type<any>> = MapWrapper.createFromPairs([
|
|
||||||
[LifecycleHooks.OnInit, OnInit],
|
|
||||||
[LifecycleHooks.OnDestroy, OnDestroy],
|
|
||||||
[LifecycleHooks.DoCheck, DoCheck],
|
|
||||||
[LifecycleHooks.OnChanges, OnChanges],
|
|
||||||
[LifecycleHooks.AfterContentInit, AfterContentInit],
|
|
||||||
[LifecycleHooks.AfterContentChecked, AfterContentChecked],
|
|
||||||
[LifecycleHooks.AfterViewInit, AfterViewInit],
|
|
||||||
[LifecycleHooks.AfterViewChecked, AfterViewChecked],
|
|
||||||
]);
|
|
||||||
|
|
||||||
const LIFECYCLE_PROPS: Map<any, string> = MapWrapper.createFromPairs([
|
|
||||||
[LifecycleHooks.OnInit, 'ngOnInit'],
|
|
||||||
[LifecycleHooks.OnDestroy, 'ngOnDestroy'],
|
|
||||||
[LifecycleHooks.DoCheck, 'ngDoCheck'],
|
|
||||||
[LifecycleHooks.OnChanges, 'ngOnChanges'],
|
|
||||||
[LifecycleHooks.AfterContentInit, 'ngAfterContentInit'],
|
|
||||||
[LifecycleHooks.AfterContentChecked, 'ngAfterContentChecked'],
|
|
||||||
[LifecycleHooks.AfterViewInit, 'ngAfterViewInit'],
|
|
||||||
[LifecycleHooks.AfterViewChecked, 'ngAfterViewChecked'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
export function hasLifecycleHook(hook: LifecycleHooks, token: any): boolean {
|
export function hasLifecycleHook(hook: LifecycleHooks, token: any): boolean {
|
||||||
var lcInterface = LIFECYCLE_INTERFACES.get(hook);
|
return reflector.hasLifecycleHook(token, getHookName(hook));
|
||||||
var lcProp = LIFECYCLE_PROPS.get(hook);
|
}
|
||||||
return reflector.hasLifecycleHook(token, lcInterface, lcProp);
|
|
||||||
|
function getHookName(hook: LifecycleHooks): string {
|
||||||
|
switch (hook) {
|
||||||
|
case LifecycleHooks.OnInit:
|
||||||
|
return 'ngOnInit';
|
||||||
|
case LifecycleHooks.OnDestroy:
|
||||||
|
return 'ngOnDestroy';
|
||||||
|
case LifecycleHooks.DoCheck:
|
||||||
|
return 'ngDoCheck';
|
||||||
|
case LifecycleHooks.OnChanges:
|
||||||
|
return 'ngOnChanges';
|
||||||
|
case LifecycleHooks.AfterContentInit:
|
||||||
|
return 'ngAfterContentInit';
|
||||||
|
case LifecycleHooks.AfterContentChecked:
|
||||||
|
return 'ngAfterContentChecked';
|
||||||
|
case LifecycleHooks.AfterViewInit:
|
||||||
|
return 'ngAfterViewInit';
|
||||||
|
case LifecycleHooks.AfterViewChecked:
|
||||||
|
return 'ngAfterViewChecked';
|
||||||
|
}
|
||||||
}
|
}
|
@ -11,7 +11,7 @@ import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata
|
|||||||
import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
|
import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
|
||||||
import * as cpl from './compile_metadata';
|
import * as cpl from './compile_metadata';
|
||||||
import {DirectiveResolver} from './directive_resolver';
|
import {DirectiveResolver} from './directive_resolver';
|
||||||
import {isBlank, isPresent, isString, stringify} from './facade/lang';
|
import {isBlank, isPresent, stringify} from './facade/lang';
|
||||||
import {Identifiers, resolveIdentifierToken} from './identifiers';
|
import {Identifiers, resolveIdentifierToken} from './identifiers';
|
||||||
import {hasLifecycleHook} from './lifecycle_reflector';
|
import {hasLifecycleHook} from './lifecycle_reflector';
|
||||||
import {NgModuleResolver} from './ng_module_resolver';
|
import {NgModuleResolver} from './ng_module_resolver';
|
||||||
@ -116,8 +116,7 @@ export class CompileMetadataResolver {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDirectiveMetadata(directiveType: Type<any>, throwIfNotFound = true):
|
getDirectiveMetadata(directiveType: any, throwIfNotFound = true): cpl.CompileDirectiveMetadata {
|
||||||
cpl.CompileDirectiveMetadata {
|
|
||||||
directiveType = resolveForwardRef(directiveType);
|
directiveType = resolveForwardRef(directiveType);
|
||||||
let meta = this._directiveCache.get(directiveType);
|
let meta = this._directiveCache.get(directiveType);
|
||||||
if (!meta) {
|
if (!meta) {
|
||||||
@ -161,7 +160,7 @@ export class CompileMetadataResolver {
|
|||||||
moduleUrl = componentModuleUrl(this._reflector, directiveType, dirMeta);
|
moduleUrl = componentModuleUrl(this._reflector, directiveType, dirMeta);
|
||||||
if (dirMeta.entryComponents) {
|
if (dirMeta.entryComponents) {
|
||||||
entryComponentMetadata =
|
entryComponentMetadata =
|
||||||
flattenArray(dirMeta.entryComponents)
|
flattenAndDedupeArray(dirMeta.entryComponents)
|
||||||
.map((type) => this.getTypeMetadata(type, staticTypeModuleUrl(type)))
|
.map((type) => this.getTypeMetadata(type, staticTypeModuleUrl(type)))
|
||||||
.concat(entryComponentMetadata);
|
.concat(entryComponentMetadata);
|
||||||
}
|
}
|
||||||
@ -229,7 +228,7 @@ export class CompileMetadataResolver {
|
|||||||
const schemas: SchemaMetadata[] = [];
|
const schemas: SchemaMetadata[] = [];
|
||||||
|
|
||||||
if (meta.imports) {
|
if (meta.imports) {
|
||||||
flattenArray(meta.imports).forEach((importedType) => {
|
flattenAndDedupeArray(meta.imports).forEach((importedType) => {
|
||||||
let importedModuleType: Type<any>;
|
let importedModuleType: Type<any>;
|
||||||
if (isValidType(importedType)) {
|
if (isValidType(importedType)) {
|
||||||
importedModuleType = importedType;
|
importedModuleType = importedType;
|
||||||
@ -258,7 +257,7 @@ export class CompileMetadataResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (meta.exports) {
|
if (meta.exports) {
|
||||||
flattenArray(meta.exports).forEach((exportedType) => {
|
flattenAndDedupeArray(meta.exports).forEach((exportedType) => {
|
||||||
if (!isValidType(exportedType)) {
|
if (!isValidType(exportedType)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unexpected value '${stringify(exportedType)}' exported by the module '${stringify(moduleType)}'`);
|
`Unexpected value '${stringify(exportedType)}' exported by the module '${stringify(moduleType)}'`);
|
||||||
@ -284,7 +283,7 @@ export class CompileMetadataResolver {
|
|||||||
const transitiveModule =
|
const transitiveModule =
|
||||||
this._getTransitiveNgModuleMetadata(importedModules, exportedModules);
|
this._getTransitiveNgModuleMetadata(importedModules, exportedModules);
|
||||||
if (meta.declarations) {
|
if (meta.declarations) {
|
||||||
flattenArray(meta.declarations).forEach((declaredType) => {
|
flattenAndDedupeArray(meta.declarations).forEach((declaredType) => {
|
||||||
if (!isValidType(declaredType)) {
|
if (!isValidType(declaredType)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unexpected value '${stringify(declaredType)}' declared by the module '${stringify(moduleType)}'`);
|
`Unexpected value '${stringify(declaredType)}' declared by the module '${stringify(moduleType)}'`);
|
||||||
@ -314,12 +313,12 @@ export class CompileMetadataResolver {
|
|||||||
|
|
||||||
if (meta.entryComponents) {
|
if (meta.entryComponents) {
|
||||||
entryComponents.push(
|
entryComponents.push(
|
||||||
...flattenArray(meta.entryComponents)
|
...flattenAndDedupeArray(meta.entryComponents)
|
||||||
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
|
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta.bootstrap) {
|
if (meta.bootstrap) {
|
||||||
const typeMetadata = flattenArray(meta.bootstrap).map(type => {
|
const typeMetadata = flattenAndDedupeArray(meta.bootstrap).map(type => {
|
||||||
if (!isValidType(type)) {
|
if (!isValidType(type)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unexpected value '${stringify(type)}' used in the bootstrap property of module '${stringify(moduleType)}'`);
|
`Unexpected value '${stringify(type)}' used in the bootstrap property of module '${stringify(moduleType)}'`);
|
||||||
@ -332,7 +331,7 @@ export class CompileMetadataResolver {
|
|||||||
entryComponents.push(...bootstrapComponents);
|
entryComponents.push(...bootstrapComponents);
|
||||||
|
|
||||||
if (meta.schemas) {
|
if (meta.schemas) {
|
||||||
schemas.push(...flattenArray(meta.schemas));
|
schemas.push(...flattenAndDedupeArray(meta.schemas));
|
||||||
}
|
}
|
||||||
|
|
||||||
transitiveModule.entryComponents.push(...entryComponents);
|
transitiveModule.entryComponents.push(...entryComponents);
|
||||||
@ -379,15 +378,15 @@ export class CompileMetadataResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _getTypeDescriptor(type: Type<any>): string {
|
private _getTypeDescriptor(type: Type<any>): string {
|
||||||
if (this._directiveResolver.resolve(type, false) !== null) {
|
if (this._directiveResolver.resolve(type, false)) {
|
||||||
return 'directive';
|
return 'directive';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._pipeResolver.resolve(type, false) !== null) {
|
if (this._pipeResolver.resolve(type, false)) {
|
||||||
return 'pipe';
|
return 'pipe';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._ngModuleResolver.resolve(type, false) !== null) {
|
if (this._ngModuleResolver.resolve(type, false)) {
|
||||||
return 'module';
|
return 'module';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,9 +506,7 @@ export class CompileMetadataResolver {
|
|||||||
let isSelf = false;
|
let isSelf = false;
|
||||||
let isSkipSelf = false;
|
let isSkipSelf = false;
|
||||||
let isOptional = false;
|
let isOptional = false;
|
||||||
let query: Query = null;
|
let token: any = null;
|
||||||
let viewQuery: Query = null;
|
|
||||||
var token: any = null;
|
|
||||||
if (Array.isArray(param)) {
|
if (Array.isArray(param)) {
|
||||||
param.forEach((paramEntry) => {
|
param.forEach((paramEntry) => {
|
||||||
if (paramEntry instanceof Host) {
|
if (paramEntry instanceof Host) {
|
||||||
@ -523,12 +520,6 @@ export class CompileMetadataResolver {
|
|||||||
} else if (paramEntry instanceof Attribute) {
|
} else if (paramEntry instanceof Attribute) {
|
||||||
isAttribute = true;
|
isAttribute = true;
|
||||||
token = paramEntry.attributeName;
|
token = paramEntry.attributeName;
|
||||||
} else if (paramEntry instanceof Query) {
|
|
||||||
if (paramEntry.isViewQuery) {
|
|
||||||
viewQuery = paramEntry;
|
|
||||||
} else {
|
|
||||||
query = paramEntry;
|
|
||||||
}
|
|
||||||
} else if (paramEntry instanceof Inject) {
|
} else if (paramEntry instanceof Inject) {
|
||||||
token = paramEntry.token;
|
token = paramEntry.token;
|
||||||
} else if (isValidType(paramEntry) && isBlank(token)) {
|
} else if (isValidType(paramEntry) && isBlank(token)) {
|
||||||
@ -549,8 +540,6 @@ export class CompileMetadataResolver {
|
|||||||
isSelf,
|
isSelf,
|
||||||
isSkipSelf,
|
isSkipSelf,
|
||||||
isOptional,
|
isOptional,
|
||||||
query: query ? this.getQueryMetadata(query, null, typeOrFunc) : null,
|
|
||||||
viewQuery: viewQuery ? this.getQueryMetadata(viewQuery, null, typeOrFunc) : null,
|
|
||||||
token: this.getTokenMetadata(token)
|
token: this.getTokenMetadata(token)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -569,7 +558,7 @@ export class CompileMetadataResolver {
|
|||||||
getTokenMetadata(token: any): cpl.CompileTokenMetadata {
|
getTokenMetadata(token: any): cpl.CompileTokenMetadata {
|
||||||
token = resolveForwardRef(token);
|
token = resolveForwardRef(token);
|
||||||
let compileToken: cpl.CompileTokenMetadata;
|
let compileToken: cpl.CompileTokenMetadata;
|
||||||
if (isString(token)) {
|
if (typeof token === 'string') {
|
||||||
compileToken = new cpl.CompileTokenMetadata({value: token});
|
compileToken = new cpl.CompileTokenMetadata({value: token});
|
||||||
} else {
|
} else {
|
||||||
compileToken = new cpl.CompileTokenMetadata({
|
compileToken = new cpl.CompileTokenMetadata({
|
||||||
@ -606,7 +595,8 @@ export class CompileMetadataResolver {
|
|||||||
} else if (isValidType(provider)) {
|
} else if (isValidType(provider)) {
|
||||||
compileProvider = this.getTypeMetadata(provider, staticTypeModuleUrl(provider));
|
compileProvider = this.getTypeMetadata(provider, staticTypeModuleUrl(provider));
|
||||||
} else {
|
} else {
|
||||||
let providersInfo = (<string[]>providers.reduce(
|
const providersInfo =
|
||||||
|
(<string[]>providers.reduce(
|
||||||
(soFar: string[], seenProvider: any, seenProviderIdx: number) => {
|
(soFar: string[], seenProvider: any, seenProviderIdx: number) => {
|
||||||
if (seenProviderIdx < providerIdx) {
|
if (seenProviderIdx < providerIdx) {
|
||||||
soFar.push(`${stringify(seenProvider)}`);
|
soFar.push(`${stringify(seenProvider)}`);
|
||||||
@ -736,7 +726,6 @@ function getTransitiveModules(
|
|||||||
return targetModules;
|
return targetModules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function flattenArray(tree: any[], out: Array<any> = []): Array<any> {
|
function flattenArray(tree: any[], out: Array<any> = []): Array<any> {
|
||||||
if (tree) {
|
if (tree) {
|
||||||
for (let i = 0; i < tree.length; i++) {
|
for (let i = 0; i < tree.length; i++) {
|
||||||
@ -751,6 +740,17 @@ function flattenArray(tree: any[], out: Array<any> = []): Array<any> {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function dedupeArray(array: any[]): Array<any> {
|
||||||
|
if (array) {
|
||||||
|
return Array.from(new Set(array));
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function flattenAndDedupeArray(tree: any[]): Array<any> {
|
||||||
|
return dedupeArray(flattenArray(tree));
|
||||||
|
}
|
||||||
|
|
||||||
function isValidType(value: any): boolean {
|
function isValidType(value: any): boolean {
|
||||||
return cpl.isStaticSymbol(value) || (value instanceof Type);
|
return cpl.isStaticSymbol(value) || (value instanceof Type);
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,9 @@ export class ExpansionCase implements Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Attribute implements Node {
|
export class Attribute implements Node {
|
||||||
constructor(public name: string, public value: string, public sourceSpan: ParseSourceSpan) {}
|
constructor(
|
||||||
|
public name: string, public value: string, public sourceSpan: ParseSourceSpan,
|
||||||
|
public valueSpan?: ParseSourceSpan) {}
|
||||||
visit(visitor: Visitor, context: any): any { return visitor.visitAttribute(this, context); }
|
visit(visitor: Visitor, context: any): any { return visitor.visitAttribute(this, context); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,6 +54,10 @@ export class Comment implements Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Visitor {
|
export interface Visitor {
|
||||||
|
// Returning a truthy value from `visit()` will prevent `visitAll()` from the call to the typed
|
||||||
|
// method and result returned will become the result included in `visitAll()`s result array.
|
||||||
|
visit?(node: Node, context: any): any;
|
||||||
|
|
||||||
visitElement(element: Element, context: any): any;
|
visitElement(element: Element, context: any): any;
|
||||||
visitAttribute(attribute: Attribute, context: any): any;
|
visitAttribute(attribute: Attribute, context: any): any;
|
||||||
visitText(text: Text, context: any): any;
|
visitText(text: Text, context: any): any;
|
||||||
@ -62,8 +68,12 @@ export interface Visitor {
|
|||||||
|
|
||||||
export function visitAll(visitor: Visitor, nodes: Node[], context: any = null): any[] {
|
export function visitAll(visitor: Visitor, nodes: Node[], context: any = null): any[] {
|
||||||
let result: any[] = [];
|
let result: any[] = [];
|
||||||
|
|
||||||
|
let visit = visitor.visit ?
|
||||||
|
(ast: Node) => visitor.visit(ast, context) || ast.visit(visitor, context) :
|
||||||
|
(ast: Node) => ast.visit(visitor, context);
|
||||||
nodes.forEach(ast => {
|
nodes.forEach(ast => {
|
||||||
const astResult = ast.visit(visitor, context);
|
const astResult = visit(ast);
|
||||||
if (astResult) {
|
if (astResult) {
|
||||||
result.push(astResult);
|
result.push(astResult);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ListWrapper} from '../facade/collection';
|
|
||||||
import {isBlank, isPresent} from '../facade/lang';
|
import {isBlank, isPresent} from '../facade/lang';
|
||||||
import {ParseError, ParseSourceSpan} from '../parse_util';
|
import {ParseError, ParseSourceSpan} from '../parse_util';
|
||||||
|
|
||||||
@ -231,7 +230,7 @@ class _TreeBuilder {
|
|||||||
|
|
||||||
private _closeVoidElement(): void {
|
private _closeVoidElement(): void {
|
||||||
if (this._elementStack.length > 0) {
|
if (this._elementStack.length > 0) {
|
||||||
const el = ListWrapper.last(this._elementStack);
|
const el = this._elementStack[this._elementStack.length - 1];
|
||||||
|
|
||||||
if (this.getTagDefinition(el.name).isVoid) {
|
if (this.getTagDefinition(el.name).isVoid) {
|
||||||
this._elementStack.pop();
|
this._elementStack.pop();
|
||||||
@ -275,7 +274,7 @@ class _TreeBuilder {
|
|||||||
|
|
||||||
private _pushElement(el: html.Element) {
|
private _pushElement(el: html.Element) {
|
||||||
if (this._elementStack.length > 0) {
|
if (this._elementStack.length > 0) {
|
||||||
const parentEl = ListWrapper.last(this._elementStack);
|
const parentEl = this._elementStack[this._elementStack.length - 1];
|
||||||
if (this.getTagDefinition(parentEl.name).isClosedByChild(el.name)) {
|
if (this.getTagDefinition(parentEl.name).isClosedByChild(el.name)) {
|
||||||
this._elementStack.pop();
|
this._elementStack.pop();
|
||||||
}
|
}
|
||||||
@ -316,7 +315,7 @@ class _TreeBuilder {
|
|||||||
for (let stackIndex = this._elementStack.length - 1; stackIndex >= 0; stackIndex--) {
|
for (let stackIndex = this._elementStack.length - 1; stackIndex >= 0; stackIndex--) {
|
||||||
const el = this._elementStack[stackIndex];
|
const el = this._elementStack[stackIndex];
|
||||||
if (el.name == fullName) {
|
if (el.name == fullName) {
|
||||||
ListWrapper.splice(this._elementStack, stackIndex, this._elementStack.length - stackIndex);
|
this._elementStack.splice(stackIndex, this._elementStack.length - stackIndex);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,16 +330,19 @@ class _TreeBuilder {
|
|||||||
const fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]);
|
const fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]);
|
||||||
let end = attrName.sourceSpan.end;
|
let end = attrName.sourceSpan.end;
|
||||||
let value = '';
|
let value = '';
|
||||||
|
let valueSpan: ParseSourceSpan;
|
||||||
if (this._peek.type === lex.TokenType.ATTR_VALUE) {
|
if (this._peek.type === lex.TokenType.ATTR_VALUE) {
|
||||||
const valueToken = this._advance();
|
const valueToken = this._advance();
|
||||||
value = valueToken.parts[0];
|
value = valueToken.parts[0];
|
||||||
end = valueToken.sourceSpan.end;
|
end = valueToken.sourceSpan.end;
|
||||||
|
valueSpan = valueToken.sourceSpan;
|
||||||
}
|
}
|
||||||
return new html.Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, end));
|
return new html.Attribute(
|
||||||
|
fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, end), valueSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getParentElement(): html.Element {
|
private _getParentElement(): html.Element {
|
||||||
return this._elementStack.length > 0 ? ListWrapper.last(this._elementStack) : null;
|
return this._elementStack.length > 0 ? this._elementStack[this._elementStack.length - 1] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -358,7 +360,7 @@ class _TreeBuilder {
|
|||||||
container = this._elementStack[i];
|
container = this._elementStack[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return {parent: ListWrapper.last(this._elementStack), container};
|
return {parent: this._elementStack[this._elementStack.length - 1], container};
|
||||||
}
|
}
|
||||||
|
|
||||||
private _addToParent(node: html.Node) {
|
private _addToParent(node: html.Node) {
|
||||||
|
@ -9,15 +9,16 @@
|
|||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
|
|
||||||
import {CompileDiDependencyMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileProviderMetadata, CompileTokenMetadata} from './compile_metadata';
|
import {CompileDiDependencyMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileProviderMetadata, CompileTokenMetadata} from './compile_metadata';
|
||||||
|
import {createDiTokenExpression} from './compiler_util/identifier_util';
|
||||||
import {isPresent} from './facade/lang';
|
import {isPresent} from './facade/lang';
|
||||||
import {Identifiers, resolveIdentifier, resolveIdentifierToken} from './identifiers';
|
import {Identifiers, resolveIdentifier, resolveIdentifierToken} from './identifiers';
|
||||||
|
import {ClassBuilder, createClassStmt} from './output/class_builder';
|
||||||
import * as o from './output/output_ast';
|
import * as o from './output/output_ast';
|
||||||
import {convertValueToOutputAst} from './output/value_util';
|
import {convertValueToOutputAst} from './output/value_util';
|
||||||
import {ParseLocation, ParseSourceFile, ParseSourceSpan} from './parse_util';
|
import {ParseLocation, ParseSourceFile, ParseSourceSpan} from './parse_util';
|
||||||
import {LifecycleHooks} from './private_import_core';
|
import {LifecycleHooks} from './private_import_core';
|
||||||
import {NgModuleProviderAnalyzer} from './provider_analyzer';
|
import {NgModuleProviderAnalyzer} from './provider_analyzer';
|
||||||
import {ProviderAst} from './template_parser/template_ast';
|
import {ProviderAst} from './template_parser/template_ast';
|
||||||
import {createDiTokenExpression} from './util';
|
|
||||||
|
|
||||||
export class ComponentFactoryDependency {
|
export class ComponentFactoryDependency {
|
||||||
constructor(
|
constructor(
|
||||||
@ -82,13 +83,15 @@ export class NgModuleCompiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _InjectorBuilder {
|
class _InjectorBuilder implements ClassBuilder {
|
||||||
|
fields: o.ClassField[] = [];
|
||||||
|
getters: o.ClassGetter[] = [];
|
||||||
|
methods: o.ClassMethod[] = [];
|
||||||
|
ctorStmts: o.Statement[] = [];
|
||||||
private _tokens: CompileTokenMetadata[] = [];
|
private _tokens: CompileTokenMetadata[] = [];
|
||||||
private _instances = new Map<any, o.Expression>();
|
private _instances = new Map<any, o.Expression>();
|
||||||
private _fields: o.ClassField[] = [];
|
|
||||||
private _createStmts: o.Statement[] = [];
|
private _createStmts: o.Statement[] = [];
|
||||||
private _destroyStmts: o.Statement[] = [];
|
private _destroyStmts: o.Statement[] = [];
|
||||||
private _getters: o.ClassGetter[] = [];
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _ngModuleMeta: CompileNgModuleMetadata,
|
private _ngModuleMeta: CompileNgModuleMetadata,
|
||||||
@ -136,26 +139,23 @@ class _InjectorBuilder {
|
|||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
var ctor = new o.ClassMethod(
|
var parentArgs = [
|
||||||
null,
|
|
||||||
[new o.FnParam(
|
|
||||||
InjectorProps.parent.name, o.importType(resolveIdentifier(Identifiers.Injector)))],
|
|
||||||
[o.SUPER_EXPR
|
|
||||||
.callFn([
|
|
||||||
o.variable(InjectorProps.parent.name),
|
o.variable(InjectorProps.parent.name),
|
||||||
o.literalArr(this._entryComponentFactories.map(
|
o.literalArr(
|
||||||
(componentFactory) => o.importExpr(componentFactory))),
|
this._entryComponentFactories.map((componentFactory) => o.importExpr(componentFactory))),
|
||||||
o.literalArr(this._bootstrapComponentFactories.map(
|
o.literalArr(this._bootstrapComponentFactories.map(
|
||||||
(componentFactory) => o.importExpr(componentFactory)))
|
(componentFactory) => o.importExpr(componentFactory)))
|
||||||
])
|
];
|
||||||
.toStmt()]);
|
|
||||||
|
|
||||||
var injClassName = `${this._ngModuleMeta.type.name}Injector`;
|
var injClassName = `${this._ngModuleMeta.type.name}Injector`;
|
||||||
return new o.ClassStmt(
|
return createClassStmt({
|
||||||
injClassName, o.importExpr(
|
name: injClassName,
|
||||||
resolveIdentifier(Identifiers.NgModuleInjector),
|
ctorParams: [new o.FnParam(
|
||||||
[o.importType(this._ngModuleMeta.type)]),
|
InjectorProps.parent.name, o.importType(resolveIdentifier(Identifiers.Injector)))],
|
||||||
this._fields, this._getters, ctor, methods);
|
parent: o.importExpr(
|
||||||
|
resolveIdentifier(Identifiers.NgModuleInjector), [o.importType(this._ngModuleMeta.type)]),
|
||||||
|
parentArgs: parentArgs,
|
||||||
|
builders: [{methods}, this]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getProviderValue(provider: CompileProviderMetadata): o.Expression {
|
private _getProviderValue(provider: CompileProviderMetadata): o.Expression {
|
||||||
@ -163,11 +163,11 @@ class _InjectorBuilder {
|
|||||||
if (isPresent(provider.useExisting)) {
|
if (isPresent(provider.useExisting)) {
|
||||||
result = this._getDependency(new CompileDiDependencyMetadata({token: provider.useExisting}));
|
result = this._getDependency(new CompileDiDependencyMetadata({token: provider.useExisting}));
|
||||||
} else if (isPresent(provider.useFactory)) {
|
} else if (isPresent(provider.useFactory)) {
|
||||||
var deps = isPresent(provider.deps) ? provider.deps : provider.useFactory.diDeps;
|
var deps = provider.deps || provider.useFactory.diDeps;
|
||||||
var depsExpr = deps.map((dep) => this._getDependency(dep));
|
var depsExpr = deps.map((dep) => this._getDependency(dep));
|
||||||
result = o.importExpr(provider.useFactory).callFn(depsExpr);
|
result = o.importExpr(provider.useFactory).callFn(depsExpr);
|
||||||
} else if (isPresent(provider.useClass)) {
|
} else if (isPresent(provider.useClass)) {
|
||||||
var deps = isPresent(provider.deps) ? provider.deps : provider.useClass.diDeps;
|
var deps = provider.deps || provider.useClass.diDeps;
|
||||||
var depsExpr = deps.map((dep) => this._getDependency(dep));
|
var depsExpr = deps.map((dep) => this._getDependency(dep));
|
||||||
result =
|
result =
|
||||||
o.importExpr(provider.useClass).instantiate(depsExpr, o.importType(provider.useClass));
|
o.importExpr(provider.useClass).instantiate(depsExpr, o.importType(provider.useClass));
|
||||||
@ -194,11 +194,11 @@ class _InjectorBuilder {
|
|||||||
type = o.DYNAMIC_TYPE;
|
type = o.DYNAMIC_TYPE;
|
||||||
}
|
}
|
||||||
if (isEager) {
|
if (isEager) {
|
||||||
this._fields.push(new o.ClassField(propName, type));
|
this.fields.push(new o.ClassField(propName, type));
|
||||||
this._createStmts.push(o.THIS_EXPR.prop(propName).set(resolvedProviderValueExpr).toStmt());
|
this._createStmts.push(o.THIS_EXPR.prop(propName).set(resolvedProviderValueExpr).toStmt());
|
||||||
} else {
|
} else {
|
||||||
var internalField = `_${propName}`;
|
var internalField = `_${propName}`;
|
||||||
this._fields.push(new o.ClassField(internalField, type));
|
this.fields.push(new o.ClassField(internalField, type));
|
||||||
// Note: Equals is important for JS so that it also checks the undefined case!
|
// Note: Equals is important for JS so that it also checks the undefined case!
|
||||||
var getterStmts = [
|
var getterStmts = [
|
||||||
new o.IfStmt(
|
new o.IfStmt(
|
||||||
@ -206,7 +206,7 @@ class _InjectorBuilder {
|
|||||||
[o.THIS_EXPR.prop(internalField).set(resolvedProviderValueExpr).toStmt()]),
|
[o.THIS_EXPR.prop(internalField).set(resolvedProviderValueExpr).toStmt()]),
|
||||||
new o.ReturnStatement(o.THIS_EXPR.prop(internalField))
|
new o.ReturnStatement(o.THIS_EXPR.prop(internalField))
|
||||||
];
|
];
|
||||||
this._getters.push(new o.ClassGetter(propName, getterStmts, type));
|
this.getters.push(new o.ClassGetter(propName, getterStmts, type));
|
||||||
}
|
}
|
||||||
return o.THIS_EXPR.prop(propName);
|
return o.THIS_EXPR.prop(propName);
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ import {AnimationCompiler} from './animation/animation_compiler';
|
|||||||
import {AnimationParser} from './animation/animation_parser';
|
import {AnimationParser} from './animation/animation_parser';
|
||||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, CompileProviderMetadata, StaticSymbol, createHostComponentMeta} from './compile_metadata';
|
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, CompileProviderMetadata, StaticSymbol, createHostComponentMeta} from './compile_metadata';
|
||||||
import {DirectiveNormalizer} from './directive_normalizer';
|
import {DirectiveNormalizer} from './directive_normalizer';
|
||||||
|
import {DirectiveWrapperCompileResult, DirectiveWrapperCompiler} from './directive_wrapper_compiler';
|
||||||
|
import {ListWrapper, MapWrapper} from './facade/collection';
|
||||||
import {Identifiers, resolveIdentifier, resolveIdentifierToken} from './identifiers';
|
import {Identifiers, resolveIdentifier, resolveIdentifierToken} from './identifiers';
|
||||||
import {CompileMetadataResolver} from './metadata_resolver';
|
import {CompileMetadataResolver} from './metadata_resolver';
|
||||||
import {NgModuleCompiler} from './ng_module_compiler';
|
import {NgModuleCompiler} from './ng_module_compiler';
|
||||||
@ -19,14 +21,91 @@ import {OutputEmitter} from './output/abstract_emitter';
|
|||||||
import * as o from './output/output_ast';
|
import * as o from './output/output_ast';
|
||||||
import {CompiledStylesheet, StyleCompiler} from './style_compiler';
|
import {CompiledStylesheet, StyleCompiler} from './style_compiler';
|
||||||
import {TemplateParser} from './template_parser/template_parser';
|
import {TemplateParser} from './template_parser/template_parser';
|
||||||
import {ComponentFactoryDependency, ViewCompileResult, ViewCompiler, ViewFactoryDependency} from './view_compiler/view_compiler';
|
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewCompileResult, ViewCompiler, ViewFactoryDependency} from './view_compiler/view_compiler';
|
||||||
|
|
||||||
export class SourceModule {
|
export class SourceModule {
|
||||||
constructor(public moduleUrl: string, public source: string) {}
|
constructor(public fileUrl: string, public moduleUrl: string, public source: string) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NgModulesSummary {
|
// Returns all the source files and a mapping from modules to directives
|
||||||
constructor(public ngModuleByComponent: Map<StaticSymbol, CompileNgModuleMetadata>) {}
|
export function analyzeNgModules(
|
||||||
|
programStaticSymbols: StaticSymbol[], options: {transitiveModules: boolean},
|
||||||
|
metadataResolver: CompileMetadataResolver): {
|
||||||
|
ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>,
|
||||||
|
files: Array<{srcUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]}>
|
||||||
|
} {
|
||||||
|
const {
|
||||||
|
ngModules: programNgModules,
|
||||||
|
pipesAndDirectives: programPipesOrDirectives,
|
||||||
|
} = _extractModulesAndPipesOrDirectives(programStaticSymbols, metadataResolver);
|
||||||
|
|
||||||
|
const moduleMetasByRef = new Map<any, CompileNgModuleMetadata>();
|
||||||
|
|
||||||
|
programNgModules.forEach(modMeta => {
|
||||||
|
if (options.transitiveModules) {
|
||||||
|
// For every input modules add the list of transitively included modules
|
||||||
|
modMeta.transitiveModule.modules.forEach(
|
||||||
|
modMeta => { moduleMetasByRef.set(modMeta.type.reference, modMeta); });
|
||||||
|
} else {
|
||||||
|
moduleMetasByRef.set(modMeta.type.reference, modMeta);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const ngModuleMetas = MapWrapper.values(moduleMetasByRef);
|
||||||
|
const ngModuleByPipeOrDirective = new Map<StaticSymbol, CompileNgModuleMetadata>();
|
||||||
|
const ngModulesByFile = new Map<string, StaticSymbol[]>();
|
||||||
|
const ngDirectivesByFile = new Map<string, StaticSymbol[]>();
|
||||||
|
const filePaths = new Set<string>();
|
||||||
|
|
||||||
|
// Looping over all modules to construct:
|
||||||
|
// - a map from file to modules `ngModulesByFile`,
|
||||||
|
// - a map from file to directives `ngDirectivesByFile`,
|
||||||
|
// - a map from directive/pipe to module `ngModuleByPipeOrDirective`.
|
||||||
|
ngModuleMetas.forEach((ngModuleMeta) => {
|
||||||
|
const srcFileUrl = ngModuleMeta.type.reference.filePath;
|
||||||
|
filePaths.add(srcFileUrl);
|
||||||
|
ngModulesByFile.set(
|
||||||
|
srcFileUrl, (ngModulesByFile.get(srcFileUrl) || []).concat(ngModuleMeta.type.reference));
|
||||||
|
|
||||||
|
ngModuleMeta.declaredDirectives.forEach((dirMeta: CompileDirectiveMetadata) => {
|
||||||
|
const fileUrl = dirMeta.type.reference.filePath;
|
||||||
|
filePaths.add(fileUrl);
|
||||||
|
ngDirectivesByFile.set(
|
||||||
|
fileUrl, (ngDirectivesByFile.get(fileUrl) || []).concat(dirMeta.type.reference));
|
||||||
|
ngModuleByPipeOrDirective.set(dirMeta.type.reference, ngModuleMeta);
|
||||||
|
});
|
||||||
|
|
||||||
|
ngModuleMeta.declaredPipes.forEach((pipeMeta: CompilePipeMetadata) => {
|
||||||
|
const fileUrl = pipeMeta.type.reference.filePath;
|
||||||
|
filePaths.add(fileUrl);
|
||||||
|
ngModuleByPipeOrDirective.set(pipeMeta.type.reference, ngModuleMeta);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Throw an error if any of the program pipe or directives is not declared by a module
|
||||||
|
const symbolsMissingModule =
|
||||||
|
programPipesOrDirectives.filter(s => !ngModuleByPipeOrDirective.has(s));
|
||||||
|
|
||||||
|
if (symbolsMissingModule.length) {
|
||||||
|
const messages = symbolsMissingModule.map(
|
||||||
|
s => `Cannot determine the module for class ${s.name} in ${s.filePath}!`);
|
||||||
|
throw new Error(messages.join('\n'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const files: {srcUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]}[] = [];
|
||||||
|
|
||||||
|
filePaths.forEach((srcUrl) => {
|
||||||
|
const directives = ngDirectivesByFile.get(srcUrl) || [];
|
||||||
|
const ngModules = ngModulesByFile.get(srcUrl) || [];
|
||||||
|
files.push({srcUrl, directives, ngModules});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
// map directive/pipe to module
|
||||||
|
ngModuleByPipeOrDirective,
|
||||||
|
// list modules and directives for every source file
|
||||||
|
files,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OfflineCompiler {
|
export class OfflineCompiler {
|
||||||
@ -37,32 +116,32 @@ export class OfflineCompiler {
|
|||||||
private _metadataResolver: CompileMetadataResolver,
|
private _metadataResolver: CompileMetadataResolver,
|
||||||
private _directiveNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser,
|
private _directiveNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser,
|
||||||
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
|
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
|
||||||
|
private _dirWrapperCompiler: DirectiveWrapperCompiler,
|
||||||
private _ngModuleCompiler: NgModuleCompiler, private _outputEmitter: OutputEmitter,
|
private _ngModuleCompiler: NgModuleCompiler, private _outputEmitter: OutputEmitter,
|
||||||
private _localeId: string, private _translationFormat: string) {}
|
private _localeId: string, private _translationFormat: string) {}
|
||||||
|
|
||||||
analyzeModules(ngModules: StaticSymbol[]): NgModulesSummary {
|
|
||||||
const ngModuleByComponent = new Map<StaticSymbol, CompileNgModuleMetadata>();
|
|
||||||
|
|
||||||
ngModules.forEach((ngModule) => {
|
|
||||||
const ngModuleMeta = this._metadataResolver.getNgModuleMetadata(<any>ngModule);
|
|
||||||
ngModuleMeta.declaredDirectives.forEach((dirMeta) => {
|
|
||||||
if (dirMeta.isComponent) {
|
|
||||||
ngModuleByComponent.set(dirMeta.type.reference, ngModuleMeta);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return new NgModulesSummary(ngModuleByComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearCache() {
|
clearCache() {
|
||||||
this._directiveNormalizer.clearCache();
|
this._directiveNormalizer.clearCache();
|
||||||
this._metadataResolver.clearCache();
|
this._metadataResolver.clearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
compile(
|
compileModules(staticSymbols: StaticSymbol[], options: {transitiveModules: boolean}):
|
||||||
moduleUrl: string, ngModulesSummary: NgModulesSummary, components: StaticSymbol[],
|
Promise<SourceModule[]> {
|
||||||
ngModules: StaticSymbol[]): Promise<SourceModule[]> {
|
const {ngModuleByPipeOrDirective, files} =
|
||||||
const fileSuffix = _splitTypescriptSuffix(moduleUrl)[1];
|
analyzeNgModules(staticSymbols, options, this._metadataResolver);
|
||||||
|
|
||||||
|
const sourceModules = files.map(
|
||||||
|
file => this._compileSrcFile(
|
||||||
|
file.srcUrl, ngModuleByPipeOrDirective, file.directives, file.ngModules));
|
||||||
|
|
||||||
|
return Promise.all(sourceModules)
|
||||||
|
.then((modules: SourceModule[][]) => ListWrapper.flatten(modules));
|
||||||
|
}
|
||||||
|
|
||||||
|
private _compileSrcFile(
|
||||||
|
srcFileUrl: string, ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>,
|
||||||
|
directives: StaticSymbol[], ngModules: StaticSymbol[]): Promise<SourceModule[]> {
|
||||||
|
const fileSuffix = _splitTypescriptSuffix(srcFileUrl)[1];
|
||||||
const statements: o.Statement[] = [];
|
const statements: o.Statement[] = [];
|
||||||
const exportedVars: string[] = [];
|
const exportedVars: string[] = [];
|
||||||
const outputSourceModules: SourceModule[] = [];
|
const outputSourceModules: SourceModule[] = [];
|
||||||
@ -71,13 +150,21 @@ export class OfflineCompiler {
|
|||||||
exportedVars.push(
|
exportedVars.push(
|
||||||
...ngModules.map((ngModuleType) => this._compileModule(ngModuleType, statements)));
|
...ngModules.map((ngModuleType) => this._compileModule(ngModuleType, statements)));
|
||||||
|
|
||||||
|
// compile directive wrappers
|
||||||
|
exportedVars.push(...directives.map(
|
||||||
|
(directiveType) => this._compileDirectiveWrapper(directiveType, statements)));
|
||||||
|
|
||||||
// compile components
|
// compile components
|
||||||
return Promise
|
return Promise
|
||||||
.all(components.map((compType) => {
|
.all(directives.map((dirType) => {
|
||||||
const compMeta = this._metadataResolver.getDirectiveMetadata(<any>compType);
|
const compMeta = this._metadataResolver.getDirectiveMetadata(<any>dirType);
|
||||||
const ngModule = ngModulesSummary.ngModuleByComponent.get(compType);
|
if (!compMeta.isComponent) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
const ngModule = ngModuleByPipeOrDirective.get(dirType);
|
||||||
if (!ngModule) {
|
if (!ngModule) {
|
||||||
throw new Error(`Cannot determine the module for component ${compMeta.type.name}!`);
|
throw new Error(
|
||||||
|
`Internal Error: cannot determine the module for component ${compMeta.type.name}!`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise
|
return Promise
|
||||||
@ -90,7 +177,8 @@ export class OfflineCompiler {
|
|||||||
// compile styles
|
// compile styles
|
||||||
const stylesCompileResults = this._styleCompiler.compileComponent(compMeta);
|
const stylesCompileResults = this._styleCompiler.compileComponent(compMeta);
|
||||||
stylesCompileResults.externalStylesheets.forEach((compiledStyleSheet) => {
|
stylesCompileResults.externalStylesheets.forEach((compiledStyleSheet) => {
|
||||||
outputSourceModules.push(this._codgenStyles(compiledStyleSheet, fileSuffix));
|
outputSourceModules.push(
|
||||||
|
this._codgenStyles(srcFileUrl, compiledStyleSheet, fileSuffix));
|
||||||
});
|
});
|
||||||
|
|
||||||
// compile components
|
// compile components
|
||||||
@ -103,8 +191,9 @@ export class OfflineCompiler {
|
|||||||
}))
|
}))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (statements.length > 0) {
|
if (statements.length > 0) {
|
||||||
outputSourceModules.unshift(this._codegenSourceModule(
|
const srcModule = this._codegenSourceModule(
|
||||||
_ngfactoryModuleUrl(moduleUrl), statements, exportedVars));
|
srcFileUrl, _ngfactoryModuleUrl(srcFileUrl), statements, exportedVars);
|
||||||
|
outputSourceModules.unshift(srcModule);
|
||||||
}
|
}
|
||||||
return outputSourceModules;
|
return outputSourceModules;
|
||||||
});
|
});
|
||||||
@ -139,6 +228,15 @@ export class OfflineCompiler {
|
|||||||
return appCompileResult.ngModuleFactoryVar;
|
return appCompileResult.ngModuleFactoryVar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _compileDirectiveWrapper(directiveType: StaticSymbol, targetStatements: o.Statement[]):
|
||||||
|
string {
|
||||||
|
const dirMeta = this._metadataResolver.getDirectiveMetadata(directiveType);
|
||||||
|
const dirCompileResult = this._dirWrapperCompiler.compile(dirMeta);
|
||||||
|
|
||||||
|
targetStatements.push(...dirCompileResult.statements);
|
||||||
|
return dirCompileResult.dirWrapperClassVar;
|
||||||
|
}
|
||||||
|
|
||||||
private _compileComponentFactory(
|
private _compileComponentFactory(
|
||||||
compMeta: CompileDirectiveMetadata, fileSuffix: string,
|
compMeta: CompileDirectiveMetadata, fileSuffix: string,
|
||||||
targetStatements: o.Statement[]): string {
|
targetStatements: o.Statement[]): string {
|
||||||
@ -184,18 +282,21 @@ export class OfflineCompiler {
|
|||||||
return viewResult.viewFactoryVar;
|
return viewResult.viewFactoryVar;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _codgenStyles(stylesCompileResult: CompiledStylesheet, fileSuffix: string): SourceModule {
|
private _codgenStyles(
|
||||||
|
fileUrl: string, stylesCompileResult: CompiledStylesheet, fileSuffix: string): SourceModule {
|
||||||
_resolveStyleStatements(stylesCompileResult, fileSuffix);
|
_resolveStyleStatements(stylesCompileResult, fileSuffix);
|
||||||
return this._codegenSourceModule(
|
return this._codegenSourceModule(
|
||||||
_stylesModuleUrl(
|
fileUrl, _stylesModuleUrl(
|
||||||
stylesCompileResult.meta.moduleUrl, stylesCompileResult.isShimmed, fileSuffix),
|
stylesCompileResult.meta.moduleUrl, stylesCompileResult.isShimmed, fileSuffix),
|
||||||
stylesCompileResult.statements, [stylesCompileResult.stylesVar]);
|
stylesCompileResult.statements, [stylesCompileResult.stylesVar]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _codegenSourceModule(
|
private _codegenSourceModule(
|
||||||
moduleUrl: string, statements: o.Statement[], exportedVars: string[]): SourceModule {
|
fileUrl: string, moduleUrl: string, statements: o.Statement[],
|
||||||
|
exportedVars: string[]): SourceModule {
|
||||||
return new SourceModule(
|
return new SourceModule(
|
||||||
moduleUrl, this._outputEmitter.emitStatements(moduleUrl, statements, exportedVars));
|
fileUrl, moduleUrl,
|
||||||
|
this._outputEmitter.emitStatements(moduleUrl, statements, exportedVars));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,6 +309,9 @@ function _resolveViewStatements(compileResult: ViewCompileResult): o.Statement[]
|
|||||||
const cfd = <ComponentFactoryDependency>dep;
|
const cfd = <ComponentFactoryDependency>dep;
|
||||||
cfd.placeholder.name = _componentFactoryName(cfd.comp);
|
cfd.placeholder.name = _componentFactoryName(cfd.comp);
|
||||||
cfd.placeholder.moduleUrl = _ngfactoryModuleUrl(cfd.comp.moduleUrl);
|
cfd.placeholder.moduleUrl = _ngfactoryModuleUrl(cfd.comp.moduleUrl);
|
||||||
|
} else if (dep instanceof DirectiveWrapperDependency) {
|
||||||
|
const dwd = <DirectiveWrapperDependency>dep;
|
||||||
|
dwd.placeholder.moduleUrl = _ngfactoryModuleUrl(dwd.dir.moduleUrl);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return compileResult.statements;
|
return compileResult.statements;
|
||||||
@ -222,8 +326,8 @@ function _resolveStyleStatements(
|
|||||||
return compileResult.statements;
|
return compileResult.statements;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _ngfactoryModuleUrl(compUrl: string): string {
|
function _ngfactoryModuleUrl(dirUrl: string): string {
|
||||||
const urlWithSuffix = _splitTypescriptSuffix(compUrl);
|
const urlWithSuffix = _splitTypescriptSuffix(dirUrl);
|
||||||
return `${urlWithSuffix[0]}.ngfactory${urlWithSuffix[1]}`;
|
return `${urlWithSuffix[0]}.ngfactory${urlWithSuffix[1]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,3 +358,28 @@ function _splitTypescriptSuffix(path: string): string[] {
|
|||||||
|
|
||||||
return [path, ''];
|
return [path, ''];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Group the symbols by types:
|
||||||
|
// - NgModules,
|
||||||
|
// - Pipes and Directives.
|
||||||
|
function _extractModulesAndPipesOrDirectives(
|
||||||
|
programStaticSymbols: StaticSymbol[], metadataResolver: CompileMetadataResolver) {
|
||||||
|
const ngModules: CompileNgModuleMetadata[] = [];
|
||||||
|
const pipesAndDirectives: StaticSymbol[] = [];
|
||||||
|
|
||||||
|
programStaticSymbols.forEach(staticSymbol => {
|
||||||
|
const ngModule = metadataResolver.getNgModuleMetadata(staticSymbol, false);
|
||||||
|
const directive = metadataResolver.getDirectiveMetadata(staticSymbol, false);
|
||||||
|
const pipe = metadataResolver.getPipeMetadata(<any>staticSymbol, false);
|
||||||
|
|
||||||
|
if (ngModule) {
|
||||||
|
ngModules.push(ngModule);
|
||||||
|
} else if (directive) {
|
||||||
|
pipesAndDirectives.push(staticSymbol);
|
||||||
|
} else if (pipe) {
|
||||||
|
pipesAndDirectives.push(staticSymbol);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {ngModules, pipesAndDirectives};
|
||||||
|
}
|
||||||
|
@ -6,14 +6,14 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {StringWrapper, isBlank, isPresent, isString} from '../facade/lang';
|
import {isBlank, isPresent} from '../facade/lang';
|
||||||
|
|
||||||
import * as o from './output_ast';
|
import * as o from './output_ast';
|
||||||
|
|
||||||
var _SINGLE_QUOTE_ESCAPE_STRING_RE = /'|\\|\n|\r|\$/g;
|
const _SINGLE_QUOTE_ESCAPE_STRING_RE = /'|\\|\n|\r|\$/g;
|
||||||
var _LEGAL_IDENTIFIER_RE = /^[$A-Z_][0-9A-Z_$]*$/i;
|
const _LEGAL_IDENTIFIER_RE = /^[$A-Z_][0-9A-Z_$]*$/i;
|
||||||
export var CATCH_ERROR_VAR = o.variable('error');
|
export const CATCH_ERROR_VAR = o.variable('error');
|
||||||
export var CATCH_STACK_VAR = o.variable('stack');
|
export const CATCH_STACK_VAR = o.variable('stack');
|
||||||
|
|
||||||
export abstract class OutputEmitter {
|
export abstract class OutputEmitter {
|
||||||
abstract emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string;
|
abstract emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string;
|
||||||
@ -253,7 +253,7 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex
|
|||||||
visitLiteralExpr(ast: o.LiteralExpr, ctx: EmitterVisitorContext, absentValue: string = 'null'):
|
visitLiteralExpr(ast: o.LiteralExpr, ctx: EmitterVisitorContext, absentValue: string = 'null'):
|
||||||
any {
|
any {
|
||||||
var value = ast.value;
|
var value = ast.value;
|
||||||
if (isString(value)) {
|
if (typeof value === 'string') {
|
||||||
ctx.print(escapeIdentifier(value, this._escapeDollarInStrings));
|
ctx.print(escapeIdentifier(value, this._escapeDollarInStrings));
|
||||||
} else if (isBlank(value)) {
|
} else if (isBlank(value)) {
|
||||||
ctx.print(absentValue);
|
ctx.print(absentValue);
|
||||||
@ -368,7 +368,7 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex
|
|||||||
var useNewLine = ast.entries.length > 1;
|
var useNewLine = ast.entries.length > 1;
|
||||||
ctx.print(`{`, useNewLine);
|
ctx.print(`{`, useNewLine);
|
||||||
ctx.incIndent();
|
ctx.incIndent();
|
||||||
this.visitAllObjects((entry: any /** TODO #9100 */) => {
|
this.visitAllObjects(entry => {
|
||||||
ctx.print(`${escapeIdentifier(entry[0], this._escapeDollarInStrings, false)}: `);
|
ctx.print(`${escapeIdentifier(entry[0], this._escapeDollarInStrings, false)}: `);
|
||||||
entry[1].visitExpression(this, ctx);
|
entry[1].visitExpression(this, ctx);
|
||||||
}, ast.entries, ctx, ',', useNewLine);
|
}, ast.entries, ctx, ',', useNewLine);
|
||||||
@ -381,12 +381,11 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex
|
|||||||
expressions: o.Expression[], ctx: EmitterVisitorContext, separator: string,
|
expressions: o.Expression[], ctx: EmitterVisitorContext, separator: string,
|
||||||
newLine: boolean = false): void {
|
newLine: boolean = false): void {
|
||||||
this.visitAllObjects(
|
this.visitAllObjects(
|
||||||
(expr: any /** TODO #9100 */) => expr.visitExpression(this, ctx), expressions, ctx,
|
expr => expr.visitExpression(this, ctx), expressions, ctx, separator, newLine);
|
||||||
separator, newLine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
visitAllObjects(
|
visitAllObjects<T>(
|
||||||
handler: Function, expressions: any, ctx: EmitterVisitorContext, separator: string,
|
handler: (t: T) => void, expressions: T[], ctx: EmitterVisitorContext, separator: string,
|
||||||
newLine: boolean = false): void {
|
newLine: boolean = false): void {
|
||||||
for (var i = 0; i < expressions.length; i++) {
|
for (var i = 0; i < expressions.length; i++) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
@ -409,8 +408,7 @@ export function escapeIdentifier(
|
|||||||
if (isBlank(input)) {
|
if (isBlank(input)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var body = StringWrapper.replaceAllMapped(
|
var body = input.replace(_SINGLE_QUOTE_ESCAPE_STRING_RE, (...match: string[]) => {
|
||||||
input, _SINGLE_QUOTE_ESCAPE_STRING_RE, (match: any /** TODO #9100 */) => {
|
|
||||||
if (match[0] == '$') {
|
if (match[0] == '$') {
|
||||||
return escapeDollar ? '\\$' : '$';
|
return escapeDollar ? '\\$' : '$';
|
||||||
} else if (match[0] == '\n') {
|
} else if (match[0] == '\n') {
|
||||||
|
@ -144,11 +144,11 @@ export abstract class AbstractJsEmitterVisitor extends AbstractEmitterVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _visitParams(params: o.FnParam[], ctx: EmitterVisitorContext): void {
|
private _visitParams(params: o.FnParam[], ctx: EmitterVisitorContext): void {
|
||||||
this.visitAllObjects((param: any /** TODO #9100 */) => ctx.print(param.name), params, ctx, ',');
|
this.visitAllObjects(param => ctx.print(param.name), params, ctx, ',');
|
||||||
}
|
}
|
||||||
|
|
||||||
getBuiltinMethodName(method: o.BuiltinMethod): string {
|
getBuiltinMethodName(method: o.BuiltinMethod): string {
|
||||||
var name: any /** TODO #9100 */;
|
var name: string;
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case o.BuiltinMethod.ConcatArray:
|
case o.BuiltinMethod.ConcatArray:
|
||||||
name = 'concat';
|
name = 'concat';
|
||||||
|
60
modules/@angular/compiler/src/output/class_builder.ts
Normal file
60
modules/@angular/compiler/src/output/class_builder.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as o from './output_ast';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new class stmts based on the given data.
|
||||||
|
*/
|
||||||
|
export function createClassStmt(config: {
|
||||||
|
name: string,
|
||||||
|
parent?: o.Expression,
|
||||||
|
parentArgs?: o.Expression[],
|
||||||
|
ctorParams?: o.FnParam[],
|
||||||
|
builders: ClassBuilderPart | ClassBuilderPart[], modifiers?: o.StmtModifier[]
|
||||||
|
}): o.ClassStmt {
|
||||||
|
const parentArgs = config.parentArgs || [];
|
||||||
|
const superCtorStmts = config.parent ? [o.SUPER_EXPR.callFn(parentArgs).toStmt()] : [];
|
||||||
|
const builder =
|
||||||
|
concatClassBuilderParts(Array.isArray(config.builders) ? config.builders : [config.builders]);
|
||||||
|
const ctor =
|
||||||
|
new o.ClassMethod(null, config.ctorParams || [], superCtorStmts.concat(builder.ctorStmts));
|
||||||
|
|
||||||
|
return new o.ClassStmt(
|
||||||
|
config.name, config.parent, builder.fields, builder.getters, ctor, builder.methods,
|
||||||
|
config.modifiers || []);
|
||||||
|
}
|
||||||
|
|
||||||
|
function concatClassBuilderParts(builders: ClassBuilderPart[]) {
|
||||||
|
return {
|
||||||
|
fields: [].concat(...builders.map(builder => builder.fields || [])),
|
||||||
|
methods: [].concat(...builders.map(builder => builder.methods || [])),
|
||||||
|
getters: [].concat(...builders.map(builder => builder.getters || [])),
|
||||||
|
ctorStmts: [].concat(...builders.map(builder => builder.ctorStmts || [])),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects data for a generated class.
|
||||||
|
*/
|
||||||
|
export interface ClassBuilderPart {
|
||||||
|
fields?: o.ClassField[];
|
||||||
|
methods?: o.ClassMethod[];
|
||||||
|
getters?: o.ClassGetter[];
|
||||||
|
ctorStmts?: o.Statement[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects data for a generated class.
|
||||||
|
*/
|
||||||
|
export interface ClassBuilder {
|
||||||
|
fields: o.ClassField[];
|
||||||
|
methods: o.ClassMethod[];
|
||||||
|
getters: o.ClassGetter[];
|
||||||
|
ctorStmts: o.Statement[];
|
||||||
|
}
|
@ -20,7 +20,7 @@ export class JavaScriptEmitter implements OutputEmitter {
|
|||||||
var converter = new JsEmitterVisitor(moduleUrl);
|
var converter = new JsEmitterVisitor(moduleUrl);
|
||||||
var ctx = EmitterVisitorContext.createRoot(exportedVars);
|
var ctx = EmitterVisitorContext.createRoot(exportedVars);
|
||||||
converter.visitAllStatements(stmts, ctx);
|
converter.visitAllStatements(stmts, ctx);
|
||||||
var srcParts: any[] /** TODO #9100 */ = [];
|
var srcParts: string[] = [];
|
||||||
converter.importsWithPrefixes.forEach((prefix, importedModuleUrl) => {
|
converter.importsWithPrefixes.forEach((prefix, importedModuleUrl) => {
|
||||||
// Note: can't write the real word for import as it screws up system.js auto detection...
|
// Note: can't write the real word for import as it screws up system.js auto detection...
|
||||||
srcParts.push(
|
srcParts.push(
|
||||||
|
@ -8,9 +8,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import {CompileIdentifierMetadata} from '../compile_metadata';
|
import {CompileIdentifierMetadata} from '../compile_metadata';
|
||||||
import {isPresent, isString} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//// Types
|
//// Types
|
||||||
export enum TypeModifier {
|
export enum TypeModifier {
|
||||||
@ -196,7 +194,7 @@ export class ReadVarExpr extends Expression {
|
|||||||
|
|
||||||
constructor(name: string|BuiltinVar, type: Type = null) {
|
constructor(name: string|BuiltinVar, type: Type = null) {
|
||||||
super(type);
|
super(type);
|
||||||
if (isString(name)) {
|
if (typeof name === 'string') {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.builtin = null;
|
this.builtin = null;
|
||||||
} else {
|
} else {
|
||||||
@ -215,7 +213,7 @@ export class ReadVarExpr extends Expression {
|
|||||||
export class WriteVarExpr extends Expression {
|
export class WriteVarExpr extends Expression {
|
||||||
public value: Expression;
|
public value: Expression;
|
||||||
constructor(public name: string, value: Expression, type: Type = null) {
|
constructor(public name: string, value: Expression, type: Type = null) {
|
||||||
super(isPresent(type) ? type : value.type);
|
super(type || value.type);
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +231,7 @@ export class WriteKeyExpr extends Expression {
|
|||||||
public value: Expression;
|
public value: Expression;
|
||||||
constructor(
|
constructor(
|
||||||
public receiver: Expression, public index: Expression, value: Expression, type: Type = null) {
|
public receiver: Expression, public index: Expression, value: Expression, type: Type = null) {
|
||||||
super(isPresent(type) ? type : value.type);
|
super(type || value.type);
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
@ -246,7 +244,7 @@ export class WritePropExpr extends Expression {
|
|||||||
public value: Expression;
|
public value: Expression;
|
||||||
constructor(
|
constructor(
|
||||||
public receiver: Expression, public name: string, value: Expression, type: Type = null) {
|
public receiver: Expression, public name: string, value: Expression, type: Type = null) {
|
||||||
super(isPresent(type) ? type : value.type);
|
super(type || value.type);
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
@ -267,7 +265,7 @@ export class InvokeMethodExpr extends Expression {
|
|||||||
public receiver: Expression, method: string|BuiltinMethod, public args: Expression[],
|
public receiver: Expression, method: string|BuiltinMethod, public args: Expression[],
|
||||||
type: Type = null) {
|
type: Type = null) {
|
||||||
super(type);
|
super(type);
|
||||||
if (isString(method)) {
|
if (typeof method === 'string') {
|
||||||
this.name = method;
|
this.name = method;
|
||||||
this.builtin = null;
|
this.builtin = null;
|
||||||
} else {
|
} else {
|
||||||
@ -322,7 +320,7 @@ export class ConditionalExpr extends Expression {
|
|||||||
constructor(
|
constructor(
|
||||||
public condition: Expression, trueCase: Expression, public falseCase: Expression = null,
|
public condition: Expression, trueCase: Expression, public falseCase: Expression = null,
|
||||||
type: Type = null) {
|
type: Type = null) {
|
||||||
super(isPresent(type) ? type : trueCase.type);
|
super(type || trueCase.type);
|
||||||
this.trueCase = trueCase;
|
this.trueCase = trueCase;
|
||||||
}
|
}
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
@ -369,7 +367,7 @@ export class BinaryOperatorExpr extends Expression {
|
|||||||
public lhs: Expression;
|
public lhs: Expression;
|
||||||
constructor(
|
constructor(
|
||||||
public operator: BinaryOperator, lhs: Expression, public rhs: Expression, type: Type = null) {
|
public operator: BinaryOperator, lhs: Expression, public rhs: Expression, type: Type = null) {
|
||||||
super(isPresent(type) ? type : lhs.type);
|
super(type || lhs.type);
|
||||||
this.lhs = lhs;
|
this.lhs = lhs;
|
||||||
}
|
}
|
||||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||||
@ -416,7 +414,7 @@ export class LiteralArrayExpr extends Expression {
|
|||||||
|
|
||||||
export class LiteralMapExpr extends Expression {
|
export class LiteralMapExpr extends Expression {
|
||||||
public valueType: Type = null;
|
public valueType: Type = null;
|
||||||
constructor(public entries: Array<Array<string|Expression>>, type: MapType = null) {
|
constructor(public entries: [string, Expression][], type: MapType = null) {
|
||||||
super(type);
|
super(type);
|
||||||
if (isPresent(type)) {
|
if (isPresent(type)) {
|
||||||
this.valueType = type.valueType;
|
this.valueType = type.valueType;
|
||||||
@ -479,7 +477,7 @@ export class DeclareVarStmt extends Statement {
|
|||||||
public name: string, public value: Expression, type: Type = null,
|
public name: string, public value: Expression, type: Type = null,
|
||||||
modifiers: StmtModifier[] = null) {
|
modifiers: StmtModifier[] = null) {
|
||||||
super(modifiers);
|
super(modifiers);
|
||||||
this.type = isPresent(type) ? type : value.type;
|
this.type = type || value.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||||
@ -625,7 +623,7 @@ export class ExpressionTransformer implements StatementVisitor, ExpressionVisito
|
|||||||
expr.value.visitExpression(this, context));
|
expr.value.visitExpression(this, context));
|
||||||
}
|
}
|
||||||
visitInvokeMethodExpr(ast: InvokeMethodExpr, context: any): any {
|
visitInvokeMethodExpr(ast: InvokeMethodExpr, context: any): any {
|
||||||
var method = isPresent(ast.builtin) ? ast.builtin : ast.name;
|
var method = ast.builtin || ast.name;
|
||||||
return new InvokeMethodExpr(
|
return new InvokeMethodExpr(
|
||||||
ast.receiver.visitExpression(this, context), method,
|
ast.receiver.visitExpression(this, context), method,
|
||||||
this.visitAllExpressions(ast.args, context), ast.type);
|
this.visitAllExpressions(ast.args, context), ast.type);
|
||||||
@ -673,9 +671,11 @@ export class ExpressionTransformer implements StatementVisitor, ExpressionVisito
|
|||||||
visitLiteralArrayExpr(ast: LiteralArrayExpr, context: any): any {
|
visitLiteralArrayExpr(ast: LiteralArrayExpr, context: any): any {
|
||||||
return new LiteralArrayExpr(this.visitAllExpressions(ast.entries, context));
|
return new LiteralArrayExpr(this.visitAllExpressions(ast.entries, context));
|
||||||
}
|
}
|
||||||
|
|
||||||
visitLiteralMapExpr(ast: LiteralMapExpr, context: any): any {
|
visitLiteralMapExpr(ast: LiteralMapExpr, context: any): any {
|
||||||
return new LiteralMapExpr(ast.entries.map(
|
const entries = ast.entries.map(
|
||||||
(entry) => [entry[0], (<Expression>entry[1]).visitExpression(this, context)]));
|
(entry): [string, Expression] => [entry[0], entry[1].visitExpression(this, context), ]);
|
||||||
|
return new LiteralMapExpr(entries);
|
||||||
}
|
}
|
||||||
visitAllExpressions(exprs: Expression[], context: any): Expression[] {
|
visitAllExpressions(exprs: Expression[], context: any): Expression[] {
|
||||||
return exprs.map(expr => expr.visitExpression(this, context));
|
return exprs.map(expr => expr.visitExpression(this, context));
|
||||||
@ -881,8 +881,7 @@ export function literalArr(values: Expression[], type: Type = null): LiteralArra
|
|||||||
return new LiteralArrayExpr(values, type);
|
return new LiteralArrayExpr(values, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function literalMap(
|
export function literalMap(values: [string, Expression][], type: MapType = null): LiteralMapExpr {
|
||||||
values: Array<Array<string|Expression>>, type: MapType = null): LiteralMapExpr {
|
|
||||||
return new LiteralMapExpr(values, type);
|
return new LiteralMapExpr(values, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import {ListWrapper} from '../facade/collection';
|
|
||||||
import {isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
|
|
||||||
import * as o from './output_ast';
|
import * as o from './output_ast';
|
||||||
@ -81,7 +80,7 @@ function createDynamicClass(
|
|||||||
_executeFunctionStatements(
|
_executeFunctionStatements(
|
||||||
ctorParamNames, args, _classStmt.constructorMethod.body, instanceCtx, _visitor);
|
ctorParamNames, args, _classStmt.constructorMethod.body, instanceCtx, _visitor);
|
||||||
};
|
};
|
||||||
var superClass = _classStmt.parent.visitExpression(_visitor, _ctx);
|
var superClass = _classStmt.parent ? _classStmt.parent.visitExpression(_visitor, _ctx) : Object;
|
||||||
ctor.prototype = Object.create(superClass.prototype, propertyDescriptors);
|
ctor.prototype = Object.create(superClass.prototype, propertyDescriptors);
|
||||||
return ctor;
|
return ctor;
|
||||||
}
|
}
|
||||||
@ -153,13 +152,13 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
|||||||
if (isPresent(expr.builtin)) {
|
if (isPresent(expr.builtin)) {
|
||||||
switch (expr.builtin) {
|
switch (expr.builtin) {
|
||||||
case o.BuiltinMethod.ConcatArray:
|
case o.BuiltinMethod.ConcatArray:
|
||||||
result = ListWrapper.concat(receiver, args[0]);
|
result = receiver.concat(...args);
|
||||||
break;
|
break;
|
||||||
case o.BuiltinMethod.SubscribeObservable:
|
case o.BuiltinMethod.SubscribeObservable:
|
||||||
result = receiver.subscribe({next: args[0]});
|
result = receiver.subscribe({next: args[0]});
|
||||||
break;
|
break;
|
||||||
case o.BuiltinMethod.Bind:
|
case o.BuiltinMethod.Bind:
|
||||||
result = receiver.bind(args[0]);
|
result = receiver.bind(...args);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unknown builtin method ${expr.builtin}`);
|
throw new Error(`Unknown builtin method ${expr.builtin}`);
|
||||||
|
@ -6,13 +6,26 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {evalExpression, isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
import {sanitizeIdentifier} from '../util';
|
import {sanitizeIdentifier} from '../util';
|
||||||
|
|
||||||
import {EmitterVisitorContext} from './abstract_emitter';
|
import {EmitterVisitorContext} from './abstract_emitter';
|
||||||
import {AbstractJsEmitterVisitor} from './abstract_js_emitter';
|
import {AbstractJsEmitterVisitor} from './abstract_js_emitter';
|
||||||
import * as o from './output_ast';
|
import * as o from './output_ast';
|
||||||
|
|
||||||
|
function evalExpression(
|
||||||
|
sourceUrl: string, expr: string, declarations: string, vars: {[key: string]: any}): any {
|
||||||
|
const fnBody = `${declarations}\nreturn ${expr}\n//# sourceURL=${sourceUrl}`;
|
||||||
|
const fnArgNames: string[] = [];
|
||||||
|
const fnArgValues: any[] = [];
|
||||||
|
for (const argName in vars) {
|
||||||
|
fnArgNames.push(argName);
|
||||||
|
fnArgValues.push(vars[argName]);
|
||||||
|
}
|
||||||
|
return new Function(...fnArgNames.concat(fnBody))(...fnArgValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function jitStatements(
|
export function jitStatements(
|
||||||
sourceUrl: string, statements: o.Statement[], resultVar: string): any {
|
sourceUrl: string, statements: o.Statement[], resultVar: string): any {
|
||||||
var converter = new JitEmitterVisitor();
|
var converter = new JitEmitterVisitor();
|
||||||
@ -26,9 +39,9 @@ class JitEmitterVisitor extends AbstractJsEmitterVisitor {
|
|||||||
private _evalArgValues: any[] = [];
|
private _evalArgValues: any[] = [];
|
||||||
|
|
||||||
getArgs(): {[key: string]: any} {
|
getArgs(): {[key: string]: any} {
|
||||||
var result = {};
|
var result: {[key: string]: any} = {};
|
||||||
for (var i = 0; i < this._evalArgNames.length; i++) {
|
for (var i = 0; i < this._evalArgNames.length; i++) {
|
||||||
(result as any /** TODO #9100 */)[this._evalArgNames[i]] = this._evalArgValues[i];
|
result[this._evalArgNames[i]] = this._evalArgValues[i];
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -8,24 +8,20 @@
|
|||||||
|
|
||||||
|
|
||||||
import {CompileIdentifierMetadata} from '../compile_metadata';
|
import {CompileIdentifierMetadata} from '../compile_metadata';
|
||||||
import {isArray, isBlank, isPresent} from '../facade/lang';
|
import {isBlank, isPresent} from '../facade/lang';
|
||||||
|
|
||||||
import {AbstractEmitterVisitor, CATCH_ERROR_VAR, CATCH_STACK_VAR, EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
|
import {AbstractEmitterVisitor, CATCH_ERROR_VAR, CATCH_STACK_VAR, EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
|
||||||
import * as o from './output_ast';
|
import * as o from './output_ast';
|
||||||
import {ImportGenerator} from './path_util';
|
import {ImportGenerator} from './path_util';
|
||||||
|
|
||||||
var _debugModuleUrl = 'asset://debug/lib';
|
const _debugModuleUrl = 'asset://debug/lib';
|
||||||
|
|
||||||
export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.Type | any[]):
|
export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.Type | any[]):
|
||||||
string {
|
string {
|
||||||
var converter = new _TsEmitterVisitor(_debugModuleUrl);
|
const converter = new _TsEmitterVisitor(_debugModuleUrl);
|
||||||
var ctx = EmitterVisitorContext.createRoot([]);
|
const ctx = EmitterVisitorContext.createRoot([]);
|
||||||
var asts: any[];
|
const asts: any[] = Array.isArray(ast) ? ast : [ast];
|
||||||
if (isArray(ast)) {
|
|
||||||
asts = <any[]>ast;
|
|
||||||
} else {
|
|
||||||
asts = [ast];
|
|
||||||
}
|
|
||||||
asts.forEach((ast) => {
|
asts.forEach((ast) => {
|
||||||
if (ast instanceof o.Statement) {
|
if (ast instanceof o.Statement) {
|
||||||
ast.visitStatement(converter, ctx);
|
ast.visitStatement(converter, ctx);
|
||||||
@ -46,7 +42,7 @@ export class TypeScriptEmitter implements OutputEmitter {
|
|||||||
var converter = new _TsEmitterVisitor(moduleUrl);
|
var converter = new _TsEmitterVisitor(moduleUrl);
|
||||||
var ctx = EmitterVisitorContext.createRoot(exportedVars);
|
var ctx = EmitterVisitorContext.createRoot(exportedVars);
|
||||||
converter.visitAllStatements(stmts, ctx);
|
converter.visitAllStatements(stmts, ctx);
|
||||||
var srcParts: any[] /** TODO #9100 */ = [];
|
var srcParts: string[] = [];
|
||||||
converter.importsWithPrefixes.forEach((prefix, importedModuleUrl) => {
|
converter.importsWithPrefixes.forEach((prefix, importedModuleUrl) => {
|
||||||
// Note: can't write the real word for import as it screws up system.js auto detection...
|
// Note: can't write the real word for import as it screws up system.js auto detection...
|
||||||
srcParts.push(
|
srcParts.push(
|
||||||
@ -75,6 +71,22 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
|||||||
super.visitLiteralExpr(ast, ctx, '(null as any)');
|
super.visitLiteralExpr(ast, ctx, '(null as any)');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Temporary workaround to support strictNullCheck enabled consumers of ngc emit.
|
||||||
|
// In SNC mode, [] have the type never[], so we cast here to any[].
|
||||||
|
// TODO: narrow the cast to a more explicit type, or use a pattern that does not
|
||||||
|
// start with [].concat. see https://github.com/angular/angular/pull/11846
|
||||||
|
visitLiteralArrayExpr(ast: o.LiteralArrayExpr, ctx: EmitterVisitorContext): any {
|
||||||
|
if (ast.entries.length === 0) {
|
||||||
|
ctx.print('(');
|
||||||
|
}
|
||||||
|
const result = super.visitLiteralArrayExpr(ast, ctx);
|
||||||
|
if (ast.entries.length === 0) {
|
||||||
|
ctx.print(' as any[])');
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
|
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
|
||||||
this._visitIdentifier(ast.value, ast.typeParams, ctx);
|
this._visitIdentifier(ast.value, ast.typeParams, ctx);
|
||||||
return null;
|
return null;
|
||||||
@ -227,7 +239,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitBuiltintType(type: o.BuiltinType, ctx: EmitterVisitorContext): any {
|
visitBuiltintType(type: o.BuiltinType, ctx: EmitterVisitorContext): any {
|
||||||
var typeStr: any /** TODO #9100 */;
|
var typeStr: string;
|
||||||
switch (type.name) {
|
switch (type.name) {
|
||||||
case o.BuiltinTypeName.Bool:
|
case o.BuiltinTypeName.Bool:
|
||||||
typeStr = 'boolean';
|
typeStr = 'boolean';
|
||||||
@ -291,7 +303,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _visitParams(params: o.FnParam[], ctx: EmitterVisitorContext): void {
|
private _visitParams(params: o.FnParam[], ctx: EmitterVisitorContext): void {
|
||||||
this.visitAllObjects((param: any /** TODO #9100 */) => {
|
this.visitAllObjects(param => {
|
||||||
ctx.print(param.name);
|
ctx.print(param.name);
|
||||||
ctx.print(':');
|
ctx.print(':');
|
||||||
this.visitType(param.type, ctx);
|
this.visitType(param.type, ctx);
|
||||||
@ -320,8 +332,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
|||||||
}
|
}
|
||||||
if (isPresent(typeParams) && typeParams.length > 0) {
|
if (isPresent(typeParams) && typeParams.length > 0) {
|
||||||
ctx.print(`<`);
|
ctx.print(`<`);
|
||||||
this.visitAllObjects(
|
this.visitAllObjects(type => type.visitType(this, ctx), typeParams, ctx, ',');
|
||||||
(type: any /** TODO #9100 */) => type.visitType(this, ctx), typeParams, ctx, ',');
|
|
||||||
ctx.print(`>`);
|
ctx.print(`>`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ class _ValueOutputAstTransformer implements ValueTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitStringMap(map: {[key: string]: any}, type: o.MapType): o.Expression {
|
visitStringMap(map: {[key: string]: any}, type: o.MapType): o.Expression {
|
||||||
var entries: Array<string|o.Expression>[] = [];
|
const entries: [string, o.Expression][] = [];
|
||||||
Object.keys(map).forEach(key => { entries.push([key, visitValue(map[key], this, null)]); });
|
Object.keys(map).forEach(key => { entries.push([key, visitValue(map[key], this, null)]); });
|
||||||
return o.literalMap(entries, type);
|
return o.literalMap(entries, type);
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user