Compare commits

...

130 Commits
2.0.x ... 2.1.0

Author SHA1 Message Date
07bd4b0630 chore: bump version number and generate CHANGELOG (#12247) 2016-10-12 13:19:31 -07:00
df1718d624 fix(compiler): allow WS as <ng-content> content (#12225) 2016-10-12 07:58:06 -07:00
17e3410d98 Form submit event (#11989)
* feat(forms): ngSubmit event exposes $event from original submit event as local variable

Modify NgForm directive and FormGroup directive to expose the original submit event as $event in the ngSubmit event. Modify docs to reflect changes.

This resolves #10920.

* refactor: code cleanup
2016-10-11 15:49:36 -07:00
5effc330ed feat(upgrade): compilerOptions in bootstrap (#10575) 2016-10-11 15:48:08 -07:00
3df00828d7 docs(router): fix CanActivateChild API docs (#12128)
fixes #12127
2016-10-11 15:47:57 -07:00
8c477b2f45 fix(compiler-cli): don't clone static symbols when simplifying annotation metadata (#12158) 2016-10-11 15:47:44 -07:00
7787771aba refactor(core): cleanup decorators.ts (#12161) 2016-10-11 15:47:20 -07:00
7275e1beb3 refactor(compiler): add optional visit() to TemplateAstVisitor (#12209) 2016-10-11 15:46:11 -07:00
12ba62e5e2 refactor(compiler): expose template parser phases (#12210) 2016-10-11 15:45:27 -07:00
e6e007e2f1 refactor(core): cleanup SpyObject (#12221) 2016-10-11 15:44:48 -07:00
91dd138fa5 docs(animations): document :enter and :leave transition aliases (#12222) 2016-10-11 15:44:38 -07:00
d972d82354 refactor: simplify isPresent(x) ? x : y to x || y (#12166)
Closes #12166
2016-10-10 09:20:58 -07:00
bdcf46f82e refactor(compiler): improve types, misc 2016-10-10 09:20:58 -07:00
79e1c7b807 refactor(upgrade): unify spec code (#12190)
- replace all variable declarations using 'var' by 'const' or 'let'
- replace es5 function declaration by arrow function where applicable
2016-10-10 09:18:33 -07:00
d22eeb70b8 fix(forms): allow optional fields with pattern and minlength validators (#12147) 2016-10-10 09:17:45 -07:00
aa92512ac6 fix(compiler): properly shim :host:before and :host(:before) (#12171)
fixes #12165
2016-10-10 09:15:15 -07:00
f782b08f58 docs: Minor typo fix (#12151) 2016-10-10 09:14:35 -07:00
4202936bbf refactor(compiler): add optional visit() to html AST Visitor (#12135) 2016-10-10 09:13:50 -07:00
e1faca6386 refactor(compiler): template element ast has endSourceSpan (#12138) 2016-10-10 09:12:05 -07:00
f5b0e22d35 docs(public_api): fix missing backtick 2016-10-07 17:23:08 -07:00
00693d70a2 docs: add PUBLIC_API.md 2016-10-07 14:29:16 -07:00
bcef5efffe fix(platform-browser-dynamic): mark platformBrowserDynamic as stable API (#12154)
Everyone building Angular apps need to use this api to bootstrap or AoT compile, so it can't be experimental.
2016-10-07 13:54:06 -07:00
13ecc140e8 fix(compiler): validate @HostBinding name (#12139)
relates to #7500
2016-10-07 13:53:53 -07:00
709a6dea06 refactor(compiler): attribute ast records span of the value (#12132) 2016-10-07 13:53:29 -07:00
16cfb88c00 refactor(compiler): refactor analyzeModules() out of OfflineCompiler (#12137) 2016-10-07 13:52:53 -07:00
efee6f5199 docs(saved-replies): order the replies as shown in github (#12153)
github sorts the replies by reply name.
2016-10-07 13:52:18 -07:00
2aa8aae76d docs(saved-replies): add document with saved replies for our issue tracker 2016-10-07 09:21:20 -07:00
afb4bd9ef6 refactor(NgZone): merge NgZoneImpl and NgZone (#12104) 2016-10-06 15:23:37 -07:00
d641c36a45 fix(compiler): interpolation expressions report the correct offset (#12125) 2016-10-06 15:22:10 -07:00
f4566f8128 fix(http): fix Headers initialization from Headers and Object (#12106) 2016-10-06 15:21:27 -07:00
a67c06708d fix(http): Headers.append should append to the list 2016-10-06 15:21:03 -07:00
d9d57d71dd refactor(http): move one Headers test inside the main describe 2016-10-06 15:21:03 -07:00
e06303a987 fix(router): improve error message (#12102) 2016-10-06 15:19:22 -07:00
40b92ddf21 fix(router): wildcards routes should support lazy loading
Closes #12024
2016-10-06 15:19:09 -07:00
1681e4f57f fix(router): parent resolve should complete before merging resolved data
Closes #12032
2016-10-06 15:19:09 -07:00
71b7654660 fix(compiler-cli): remove peerDependency on @angular/platform-server (#12122)
There is no runtime dependency from the compiler-cli on @angular/platform-server - it was most likely added to package.json by mistake.
2016-10-06 15:16:41 -07:00
eaaec6979c fix(compiler-cli): remove unused parse5 dependency from package.json
This was added in error or is an obsolete dependency. We don't need parse5 for the compiler-cli's runtime.
2016-10-06 15:16:22 -07:00
c587c63591 docs(changelog): fix mentions, backticks and a misplaced line ending (#12109)
* docs(changelog): fix mentions and backticks

`@page` and `@document` were both incorrectly linking to GitHub repositories.
`:enter` and `:leave` in the *Features* section were missing backticks.

* Fix misplaced line ending.
2016-10-06 15:12:41 -07:00
f50c1da4e2 fix(forms): properly validate blank strings with minlength (#12091) 2016-10-06 15:12:09 -07:00
0254ce1f6c refactor(core): simplify Reflector code, add types (#12099) 2016-10-06 15:11:16 -07:00
c9b765f5c0 refactor(compiler): module collector is reusable (#12095) 2016-10-06 15:10:44 -07:00
8c975ed156 refactor(facade): inline StringWrapper (#12051) 2016-10-06 15:10:27 -07:00
bb35fcb562 docs(contributing): remove references to Angular 2
It's just Angular.
2016-10-06 15:07:46 -07:00
57230b70a9 docs(contributing): update the "Submitting an Issue" section 2016-10-06 15:06:37 -07:00
43dc60ce4f docs(contributing): update "got a question or a problem" section
Inspired by: https://github.com/ng-bootstrap/ng-bootstrap#getting-help
2016-10-06 13:58:14 -07:00
230b3b73d8 chore(benchpress): fix the license (#12090)
It's not Apache MIT 2.0, that's a mishmash of Apache 2.0 and MIT
2016-10-06 10:24:01 -07:00
0b7dc2f9ff docs(RouterTestingModule) change modules to imports in example (#12118) 2016-10-06 10:22:39 -07:00
de1f44f51f fix(benchmarks): allow ng2_switch benchmark to be used with AoT. (#12124) 2016-10-06 10:22:08 -07:00
f1cfddf6d6 refactor(benchmarks): add index_aot to support AoT bootstrap. (#12105)
Note: This only make sure it can compile the AoT version, but does not yet use it in e2e tests.
2016-10-06 08:37:37 -07:00
ef621a2f00 docs(changelog): tweak changelog 2016-10-06 06:43:17 -07:00
df9761951b docs(changelog): added changelog for 2.1.0-rc.0 2016-10-05 16:48:22 -07:00
f786c560f1 doc(triage): add info about user pain, frequency and severity labels 2016-10-05 15:58:45 -07:00
c5557de3e7 doc(triage): correct existing incorrect info 2016-10-05 15:58:45 -07:00
ec3a5b54de docs(readme): remove incorrect download count badge
npm doesn't currently support download counts for scoped packages, so there is no replacement right now.
2016-10-05 11:37:28 -07:00
cf269d9ff4 refactor: add license header to JS files & format files (#12081) 2016-10-04 20:39:20 -07:00
5fa5ffb82a refactor(benchmarks): refactor to support AOT bootstrap in G3 (#12075) 2016-10-04 16:27:45 -07:00
4a57dcfd8d fix(forms): properly validate empty strings with patterns (#11450) 2016-10-04 16:14:23 -07:00
43923ffcf5 docs(traige): update triaging doc 2016-10-04 16:13:32 -07:00
50c37d45dc refactor: simplify arrow functions (#12057) 2016-10-04 15:57:37 -07:00
a63359689f fix(ShadowCss): fix attribute selectors in :host and :host-context (#12056)
Fix a regression introduced in #11917 while fixing #6249
2016-10-04 15:40:31 -07:00
43d3a84df3 Revert "refactor: add license header to JS files & format files (#12035)"
This reverts commit 8310c91823.
2016-10-04 14:06:41 -07:00
8310c91823 refactor: add license header to JS files & format files (#12035) 2016-10-04 13:15:49 -07:00
b64b5ece65 refactor(facade): Remove most of StringMapWrapper facade. (#12022)
This change mostly automated by
12012b07a2
with some manual fixes.
2016-10-03 16:46:05 -07:00
ed9c2b6281 fix(Header): preserve case of the first init, set() or append() (#12023)
fixes #11624
2016-10-03 15:27:56 -07:00
1cf5f5fa38 docs(NgModule): Fixed docs for NgModule.entryComponents (#12006)
* docs(NgModule): Corrected the wording of the documentation of `entryComponents`, fixed some minor grammar issues

* docs(NgModule): Remove redundant ComponentFactory mentions

* docs(NgModule): Restore ComponentFactory/ComponentResolver links
2016-10-03 10:19:03 -07:00
a32078f85e docs(DEVELOPER.md): fix typos on "Tests" section (#12029) 2016-10-02 14:19:47 -07:00
decd129a4d refactor(facade): remove DateWrapper (#12027) 2016-10-02 14:12:14 -07:00
c3c9ecb302 text(offline compiler): fix expected output 2016-09-30 17:59:43 -07:00
af520947aa test(AstSerializer): fix serializing void tags 2016-09-30 17:59:43 -07:00
040bf57966 fix(xlif): fix <x> ctype names
fixes #12000
see http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html#ctype
2016-09-30 17:59:43 -07:00
65a60b7456 style(I18N): Carriage returns in serialized files 2016-09-30 17:59:43 -07:00
756ef09d12 docs(gh): try to improve the issue template (#11891) 2016-09-30 16:40:56 -07:00
9316f95467 fix(ShadowCss): support @page and @document CSS rules (#11878)
fixes #11860
2016-09-30 16:26:24 -07:00
83d94b7504 fix(ShadowCss): support quoted attribute values
fixes #6085
2016-09-30 14:37:41 -07:00
a121136fae refactor(ShadowCss): add missing types 2016-09-30 14:37:41 -07:00
a6bb84e02b fix(ShadowCss): fix :host(tag) and :host-context(tag)
fixes #11972
2016-09-30 14:37:41 -07:00
3898dc488e fix(BrowserAdapter): correctly removes styles on IE
fixes #7916
2016-09-30 11:18:17 -07:00
ca3f9926f9 refactor(BrowserAdapter): cleanup 2016-09-30 11:18:17 -07:00
1c012a035f refactor(CssSelector): misc cleanup 2016-09-30 11:06:24 -07:00
38c5304b7f docs(CssSelector): [name*=value] is not supported
fixes #6042
2016-09-30 11:06:24 -07:00
9a049be67f feat(Parse5): update to the latest version 2.2.1
fixes #6237
2016-09-30 10:46:49 -07:00
2045c9e8ee docs: update docs for ng2_ftl benchmark 2016-09-30 10:42:21 -07:00
6c4ec05a4a fix(ShadowCss): support [attr="value with space"]
fixes #6249
2016-09-30 10:27:35 -07:00
f7bfda31ff refactor(ShadowCss): cleanup 2016-09-30 10:27:35 -07:00
a92b573309 test(DirectiveResolver): test that a prop can have both @Input and @HostBinding 2016-09-30 10:08:52 -07:00
4fd13d71c8 refactor(DirectiveResolver): cleanup 2016-09-30 10:08:52 -07:00
bf7b82b658 fix(UrlSearchParams): change a behavior when a param value is null or undefined (#11990) 2016-09-30 09:57:26 -07:00
c143fee849 refactor(routerLinkActive): optimised routerLinkActive active check code (#11968)
Modify routerLinkActive to optimise performance by removing unnecessary iteration. By replacing Array.reduce with Array.some, the loop will break when it finds an active link. Useful if used on the parent of a large group of routerLinks. Furthermore, if a RouterLink is active it will not check the RouterLinkWithHrefs.
2016-09-30 09:42:54 -07:00
0286956107 refactor(facade): Inline isBlank called with object-type argument (#11992) 2016-09-30 09:26:53 -07:00
e884f4854d feat(animations): provide aliases for :enter and :leave transitions (#11991) 2016-09-30 09:15:56 -07:00
df1822fc2a benchmarks: add ng2_ftl and ng2_switch_ftl benchmarks (#11963)
These benchmarks take the output of AoT
and manually tweaks it to explore possible
future changes to the compiler to produce
this output directly.
2016-09-30 09:09:31 -07:00
42b4b6d21b fix(upgrade): bind optional properties when upgrading from ng1 (#11411)
Previously, optional properties of a directive/component would be wrongly mapped and thus ignored.

Closes #10181
2016-09-29 09:45:28 -07:00
36bc2ff269 docs(forms): Added FormControl initialization information (#11948) 2016-09-28 13:59:08 -07:00
1564042fe8 fix(ngc): allow ReflectorHost passed as argument to CodeGenerator#create (#11951) 2016-09-27 17:12:57 -07:00
41c8c30973 chore(lint): remove unused imports (#11923)
This was done automatically by tslint, which can now fix issues it finds.
The fixer is still pending in PR https://github.com/palantir/tslint/pull/1568
Also I have a local bugfix for https://github.com/palantir/tslint/issues/1569
which causes too many imports to be deleted.
2016-09-27 17:12:25 -07:00
61129fa12d fix(compiler): move detection of unsafe properties for binding to ElementSchemaRegistry (#11378) 2016-09-27 17:10:02 -07:00
3a5b4882bc fix(compiler): Do not embed templateUrl in view factories in non-debug mode. (#11818)
Fixes #11117.
2016-09-27 17:09:44 -07:00
425c1e6042 refactor: remove dead code 2016-09-27 16:13:09 -07:00
58605cf350 refactor(facade): remove useless facades 2016-09-27 16:13:09 -07:00
34b31dea7c docs(upgrade): rename undeclared Ng2 to Ng2Component (#11950) 2016-09-27 16:11:41 -07:00
a241ab7c07 (docs): removing addProvider from UpgradeAdapter (#11934)
The `addProvider` function in the `UpgradeAdapter` was deprecated in this [commit](d21331e902 (diff-77163e956a7842149f583846c1c01651)) and has been removed in final. Given this, the documentation for downgrading ng2 providers for use in ng1 is invalid.
2016-09-27 10:10:45 -07:00
745e10e6d2 docs(router_config): add missing quote (#11925) 2016-09-27 10:10:12 -07:00
33340dbbd1 docs: remove outdated docs (#11875) 2016-09-24 08:23:28 +09:00
52812c08e2 chore(CHANGELOG): fix wrong issue link (#11871) 2016-09-24 07:13:24 +09:00
52f5ae1961 chore(compiler): followup fix for PR#11846 (#11870)
Original PR set [] to any, but any[], is a tighter type and still
works for SNC enabled consumers of the emit.
2016-09-24 07:13:05 +09:00
9be895b6da docs(ExceptionHandler): fix API docs (#11772)
fixes #11769
2016-09-24 07:05:43 +09:00
9f1c82537e ci(travis): increase node's heap size to prevent OOM on travis (#11869) 2016-09-24 06:04:29 +09:00
5ab5cc77bb Fix(http): invalidStateError if response body without content (#11786)
Fix(http): invalidStateError if response body without content
If the responseType has been specified and other than 'text', responseText throw an InvalidStateError exception

See XHR doc => https://xhr.spec.whatwg.org/#the-responsetext-attribute

Unit Test to prevent invalidStateError
2016-09-24 05:44:01 +09:00
f1b6c6efa1 refactor(animations): ensure animation input/outputs are managed within the template parser (#11782)
Closes #11782
Closes #11601
Related #11707
2016-09-24 05:37:04 +09:00
45ad13560b docs(changelog): remove info about an internal change 2016-09-23 12:02:56 -07:00
2045268cec chore(release): v2.1.0-beta.0 2016-09-23 11:41:35 -07:00
fb1076b44a docs(changelog): release notes for 2.1.0-beta.0 2016-09-23 11:37:28 -07:00
6fc46526ae fix(upgrade): allow attribute selectors for components in ng2 which are not part of upgrade (#11808)
fixes #11280
2016-09-24 02:47:16 +09:00
3ef5ede6d6 chore(compiler): emit ([] as any[]) instead of purely []. (#11846)
In SNC mode `[]` has type of never[], so we cast it to any[] to
typecheck correctly see
https://github.com/Microsoft/TypeScript/issues/10479.

This is temporary workaround, until we fully
migrate the framework to TS 2.0 and strictNullChecks.
2016-09-24 02:21:59 +09:00
136621ebc9 docs(Component): API docs for .encapsulation and .interpolation 2016-09-22 11:01:16 -07:00
f23b22a0f4 refactor: misc cleanup 2016-09-22 11:01:16 -07:00
0ca971c5bd refactor(common): cleanup (#11668) 2016-09-22 10:34:00 -07:00
3a6fcee0e6 docs(core): mark TestBed as stable api and add preliminary docs (#11767)
TestBed was accidentaly ommited from the 'stable' api list during the API sweep before final. We do consider it to be stable.
2016-09-22 10:32:17 -07:00
8972137c29 docs(contributing): remove preview references (#11795) 2016-09-22 10:31:56 -07:00
cc6481077f ci(BrowserStack): add Safari 10 (#11796) 2016-09-22 10:31:38 -07:00
c041b93418 refactor(TemplateParser): clearer error message for on* binding (#11802)
fixes #11756
2016-09-22 10:31:18 -07:00
bc33765913 chore(ISSUE_TEMPLATE): update Angular version field (#11821) 2016-09-22 10:29:12 -07:00
31dce72b7b fix(router): update the router not to reset router state when updating root component (#11799) 2016-09-21 11:37:43 -07:00
212f8dbde7 fix(forms): disable all radios with disable() 2016-09-20 15:00:12 -07:00
44da4984f9 fix(forms): support unbound disabled in ngModel (#11736) 2016-09-20 14:55:47 -07:00
d95344430c chore(zone.js): update to 0.6.25 (#11725) 2016-09-20 14:55:07 -07:00
131626fc61 fix(compiler): Safe property access expressions work in event bindings (#11724) 2016-09-20 14:54:53 -07:00
676bb0fa7d feat(router): update dts files 2016-09-20 14:53:52 -07:00
5a849829c4 feat(router): add router preloader to optimistically preload routes 2016-09-20 14:53:52 -07:00
671f73448c refactor: misc cleanup (#11654) 2016-09-19 17:15:57 -07:00
545 changed files with 9700 additions and 8212 deletions

View File

@ -1,3 +1,7 @@
<!--
IF YOU DON'T FILL OUT THE FOLLOWING INFORMATION WE MIGHT CLOSE YOUR ISSUE WITHOUT INVESTIGATING
-->
**I'm submitting a ...** (check one with "x") **I'm submitting a ...** (check one with "x")
``` ```
[ ] bug report => search github for a similar issue or PR before submitting [ ] bug report => search github for a similar issue or PR before submitting
@ -11,8 +15,12 @@
**Expected behavior** **Expected behavior**
<!-- Describe what the behavior would be without the bug. --> <!-- Describe what the behavior would be without the bug. -->
**Reproduction of the problem** **Minimal reproduction of the problem with instructions**
<!-- If the current behavior is a bug or you can illustrate your feature request better with an example, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5). --> <!--
If the current behavior is a bug or you can illustrate your feature request better with an example,
please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the problem via
https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5).
-->
**What is the motivation / use case for changing the behavior?** **What is the motivation / use case for changing the behavior?**
<!-- Describe the motivation or the concrete use case --> <!-- Describe the motivation or the concrete use case -->
@ -20,7 +28,7 @@
**Please tell us about your environment:** **Please tell us about your environment:**
<!-- Operating system, IDE, package manager, HTTP server, ... --> <!-- Operating system, IDE, package manager, HTTP server, ... -->
* **Angular version:** 2.0.0-rc.X * **Angular version:** 2.0.X
<!-- Check whether this is still an issue in the most recent Angular version --> <!-- Check whether this is still an issue in the most recent Angular version -->
* **Browser:** [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ] * **Browser:** [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]

View File

@ -1,3 +1,97 @@
<a name="2.1.0"></a>
# [2.1.0](https://github.com/angular/angular/compare/2.1.0-rc.0...2.1.0) (2016-10-12)
### Bug Fixes
* **benchmarks:** allow ng2_switch benchmark to be used with AoT. ([#12124](https://github.com/angular/angular/issues/12124)) ([de1f44f](https://github.com/angular/angular/commit/de1f44f))
* **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](https://github.com/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.0.2"></a>
## [2.0.2](https://github.com/angular/angular/compare/2.0.1...2.0.2) (2016-10-05)
### Bug Fixes
* **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:** 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:** 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:** 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 quoted attribute values ([7395400](https://github.com/angular/angular/commit/7395400)), closes [#6085](https://github.com/angular/angular/issues/6085)
* **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.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.1"></a>
## [2.0.1](https://github.com/angular/angular/compare/2.0.0...2.0.1) (2016-09-23)
### Bug Fixes
* **common:** fix ngOnChanges signature of NgTemplateOutlet directive ([14ee759](https://github.com/angular/angular/commit/14ee759))
* **compiler:** `[attribute~=value]` selector ([#11696](https://github.com/angular/angular/issues/11696)) ([734b8b8](https://github.com/angular/angular/commit/734b8b8)), closes [#9644](https://github.com/angular/angular/issues/9644)
* **compiler:** safe property access expressions work in event bindings ([#11724](https://github.com/angular/angular/issues/11724)) ([a95d652](https://github.com/angular/angular/commit/a95d652))
* **compiler:** throw when Component.moduleId is not a string ([bd4045b](https://github.com/angular/angular/commit/bd4045b)), closes [#11590](https://github.com/angular/angular/issues/11590)
* **compiler:** do not provide I18N values when they're not specified ([03aedbe](https://github.com/angular/angular/commit/03aedbe)), closes [#11643](https://github.com/angular/angular/issues/11643)
* **core:** ContentChild descendants should be queried by default ([0dc15eb](https://github.com/angular/angular/commit/0dc15eb)), closes [#11645](https://github.com/angular/angular/issues/11645)
* **forms:** disable all radios with disable() ([2860418](https://github.com/angular/angular/commit/2860418))
* **forms:** make setDisabledState optional for reactive form directives ([#11731](https://github.com/angular/angular/issues/11731)) ([51d73d3](https://github.com/angular/angular/commit/51d73d3)), closes [#11719](https://github.com/angular/angular/issues/11719)
* **forms:** support unbound disabled in ngModel ([#11736](https://github.com/angular/angular/issues/11736)) ([39e251e](https://github.com/angular/angular/commit/39e251e))
* **upgrade:** allow attribute selectors for components in ng2 which are not part of upgrade ([#11808](https://github.com/angular/angular/issues/11808)) ([b81e2e7](https://github.com/angular/angular/commit/b81e2e7)), closes [#11280](https://github.com/angular/angular/issues/11280)
<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](https://github.com/angular/angular/compare/2.0.0-rc.7...2.0.0) (2016-09-14)

View File

@ -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,19 +17,27 @@ 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 Angular 2 is still in early developer preview, and the core 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. Angular 2 is in developer preview a proposal for your work first, to be sure that we can use it.
and we are not ready to accept major contributions ahead of the full release.
Please consider what kind of change it is: Please consider what kind of change it is:
* For a **Major Feature**, first open an issue and outline your proposal so that it can be * For a **Major Feature**, first open an issue and outline your proposal so that it can be
@ -40,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 reproductions, 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)
@ -95,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

View File

@ -114,7 +114,7 @@ You should execute the 3 test suites before submitting a PR to github.
All the tests are executed on our Continuous Integration infrastructure and a PR could only be merged once the tests pass. All the tests are executed on our Continuous Integration infrastructure and a PR could only be merged once the tests pass.
- CircleCI fails if your code is not formatted properly, - CircleCI fails if your code is not formatted properly,
- Travis CI fails if any of the test suite describe above fails. - Travis CI fails if any of the test suites described above fails.
## Update the public API tests ## Update the public API tests

View File

@ -4,7 +4,6 @@
[![Issue Stats](http://issuestats.com/github/angular/angular/badge/pr?style=flat)](http://issuestats.com/github/angular/angular) [![Issue Stats](http://issuestats.com/github/angular/angular/badge/pr?style=flat)](http://issuestats.com/github/angular/angular)
[![Issue Stats](http://issuestats.com/github/angular/angular/badge/issue?style=flat)](http://issuestats.com/github/angular/angular) [![Issue Stats](http://issuestats.com/github/angular/angular/badge/issue?style=flat)](http://issuestats.com/github/angular/angular)
[![npm version](https://badge.fury.io/js/%40angular%2Fcore.svg)](https://badge.fury.io/js/%40angular%2Fcore) [![npm version](https://badge.fury.io/js/%40angular%2Fcore.svg)](https://badge.fury.io/js/%40angular%2Fcore)
[![Downloads](http://img.shields.io/npm/dm/angular2.svg)](https://npmjs.org/package/angular2)
[![Sauce Test Status](https://saucelabs.com/browser-matrix/angular2-ci.svg)](https://saucelabs.com/u/angular2-ci) [![Sauce Test Status](https://saucelabs.com/browser-matrix/angular2-ci.svg)](https://saucelabs.com/u/angular2-ci)
*Safari (7+), iOS (7+), Edge (14) and IE mobile (11) are tested on [BrowserStack][browserstack].* *Safari (7+), iOS (7+), Edge (14) and IE mobile (11) are tested on [BrowserStack][browserstack].*

62
SAVED_REPLIES.md Normal file
View 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).
```

View File

@ -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.
@ -17,9 +17,9 @@ with it.
* `comp: animations`: `@matsko` * `comp: animations`: `@matsko`
* `comp: benchpress`: `@tbosch` * `comp: benchpress`: `@tbosch`
* `comp: build/ci`: `@IgorMinar` -- All build and CI scripts * `comp: build & ci`: `@IgorMinar` -- All build and CI scripts
* `comp: common`: `@mhevery` -- This includes core components / pipes. * `comp: common`: `@mhevery` -- This includes core components / pipes.
* `comp: core/compiler`: `@tbosch` -- Because core and compiler are very * `comp: core & compiler`: `@tbosch` -- Because core and compiler are very
intertwined, we will be treating them as one. intertwined, we will be treating them as one.
* `comp: forms`: `@kara` * `comp: forms`: `@kara`
* `comp: http`: `@jeffbcross` * `comp: http`: `@jeffbcross`
@ -29,14 +29,14 @@ with it.
* `comp: testing`: `@juliemr` * `comp: testing`: `@juliemr`
* `comp: upgrade`: `@mhevery` * `comp: upgrade`: `@mhevery`
* `comp: web-worker`: `@vicb` * `comp: web-worker`: `@vicb`
* `comp: zone`: `@mhevery` * `comp: zones`: `@mhevery`
There are few components which are cross-cutting. They don't have 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`: `@mhevery` * `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:

View File

@ -1,216 +1,98 @@
// Unique place to configure the browsers which are used in the different CI jobs in Sauce Labs (SL) and BrowserStack (BS). /**
* @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
*/
// Unique place to configure the browsers which are used in the different CI jobs in Sauce Labs (SL)
// and BrowserStack (BS).
// If the target is set to null, then the browser is not run anywhere during CI. // If the target is set to null, then the browser is not run anywhere during CI.
// If a category becomes empty (e.g. BS and required), then the corresponding job must be commented out in Travis configuration. // If a category becomes empty (e.g. BS and required), then the corresponding job must be commented
// out in Travis configuration.
var CIconfiguration = { var CIconfiguration = {
'Chrome': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}}, 'Chrome': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'Firefox': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}}, 'Firefox': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
// FirefoxBeta and ChromeBeta should be target:'BS' or target:'SL', and required:true // FirefoxBeta and ChromeBeta should be target:'BS' or target:'SL', and required:true
// Currently deactivated due to https://github.com/angular/angular/issues/7560 // Currently deactivated due to https://github.com/angular/angular/issues/7560
'ChromeBeta': { unitTest: {target: null, required: true}, e2e: {target: null, required: false}}, 'ChromeBeta': {unitTest: {target: null, required: true}, e2e: {target: null, required: false}},
'FirefoxBeta': { unitTest: {target: null, required: false}, e2e: {target: null, required: false}}, 'FirefoxBeta': {unitTest: {target: null, required: false}, e2e: {target: null, required: false}},
'ChromeDev': { unitTest: {target: null, required: true}, e2e: {target: null, required: true}}, 'ChromeDev': {unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
'FirefoxDev': { unitTest: {target: null, required: true}, e2e: {target: null, required: true}}, 'FirefoxDev': {unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
'IE9': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}}, 'IE9': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'IE10': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}}, 'IE10': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'IE11': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}}, 'IE11': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'Edge': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}, 'Edge': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'Android4.1': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}}, 'Android4.1': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android4.2': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}}, 'Android4.2': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android4.3': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}}, 'Android4.3': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android4.4': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}}, 'Android4.4': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android5': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}}, 'Android5': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Safari7': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}, 'Safari7': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'Safari8': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}, 'Safari8': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'Safari9': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}, 'Safari9': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'iOS7': { unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}}, 'Safari10': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'iOS8': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}, 'iOS7': {unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}},
'iOS9': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}, 'iOS8': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'WindowsPhone': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}} 'iOS9': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'iOS10': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'WindowsPhone': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
}; };
var customLaunchers = { var customLaunchers = {
'DartiumWithWebPlatform': { 'DartiumWithWebPlatform':
base: 'Dartium', {base: 'Dartium', flags: ['--enable-experimental-web-platform-features']},
flags: ['--enable-experimental-web-platform-features'] }, 'ChromeNoSandbox': {base: 'Chrome', flags: ['--no-sandbox']},
'ChromeNoSandbox': { 'SL_CHROME': {base: 'SauceLabs', browserName: 'chrome', version: '52'},
base: 'Chrome', 'SL_CHROMEBETA': {base: 'SauceLabs', browserName: 'chrome', version: 'beta'},
flags: ['--no-sandbox'] }, 'SL_CHROMEDEV': {base: 'SauceLabs', browserName: 'chrome', version: 'dev'},
'SL_CHROME': { 'SL_FIREFOX': {base: 'SauceLabs', browserName: 'firefox', version: '46'},
base: 'SauceLabs', 'SL_FIREFOXBETA': {base: 'SauceLabs', browserName: 'firefox', version: 'beta'},
browserName: 'chrome', 'SL_FIREFOXDEV': {base: 'SauceLabs', browserName: 'firefox', version: 'dev'},
version: '52' 'SL_SAFARI7': {base: 'SauceLabs', browserName: 'safari', platform: 'OS X 10.9', version: '7.0'},
}, 'SL_SAFARI8': {base: 'SauceLabs', browserName: 'safari', platform: 'OS X 10.10', version: '8.0'},
'SL_CHROMEBETA': { 'SL_SAFARI9': {base: 'SauceLabs', browserName: 'safari', platform: 'OS X 10.11', version: '9.0'},
base: 'SauceLabs', 'SL_SAFARI10':
browserName: 'chrome', {base: 'SauceLabs', browserName: 'safari', platform: 'OS X 10.12', version: '10.0'},
version: 'beta' 'SL_IOS7': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '7.1'},
}, 'SL_IOS8': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '8.4'},
'SL_CHROMEDEV': { 'SL_IOS9': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '9.3'},
base: 'SauceLabs', 'SL_IOS10': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '10.0'},
browserName: 'chrome', 'SL_IE9':
version: 'dev' {base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 2008', version: '9'},
},
'SL_FIREFOX': {
base: 'SauceLabs',
browserName: 'firefox',
version: '46'
},
'SL_FIREFOXBETA': {
base: 'SauceLabs',
browserName: 'firefox',
version: 'beta'
},
'SL_FIREFOXDEV': {
base: 'SauceLabs',
browserName: 'firefox',
version: 'dev'
},
'SL_SAFARI7': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.9',
version: '7.0'
},
'SL_SAFARI8': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.10',
version: '8.0'
},
'SL_SAFARI9': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.11',
version: '9.0'
},
'SL_IOS7': {
base: 'SauceLabs',
browserName: 'iphone',
platform: 'OS X 10.10',
version: '7.1'
},
'SL_IOS8': {
base: 'SauceLabs',
browserName: 'iphone',
platform: 'OS X 10.10',
version: '8.4'
},
'SL_IOS9': {
base: 'SauceLabs',
browserName: 'iphone',
platform: 'OS X 10.10',
version: '9.3'
},
'SL_IE9': {
base: 'SauceLabs',
browserName: 'internet explorer',
platform: 'Windows 2008',
version: '9'
},
'SL_IE10': { 'SL_IE10': {
base: 'SauceLabs', base: 'SauceLabs',
browserName: 'internet explorer', browserName: 'internet explorer',
platform: 'Windows 2012', platform: 'Windows 2012',
version: '10' version: '10'
}, },
'SL_IE11': { 'SL_IE11':
base: 'SauceLabs', {base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 8.1', version: '11'},
browserName: 'internet explorer',
platform: 'Windows 8.1',
version: '11'
},
'SL_EDGE': { 'SL_EDGE': {
base: 'SauceLabs', base: 'SauceLabs',
browserName: 'MicrosoftEdge', browserName: 'MicrosoftEdge',
platform: 'Windows 10', platform: 'Windows 10',
version: '13.10586' version: '13.10586'
}, },
'SL_ANDROID4.1': { 'SL_ANDROID4.1': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.1'},
base: 'SauceLabs', 'SL_ANDROID4.2': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.2'},
browserName: 'android', 'SL_ANDROID4.3': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.3'},
platform: 'Linux', 'SL_ANDROID4.4': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.4'},
version: '4.1' 'SL_ANDROID5': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '5.1'},
},
'SL_ANDROID4.2': {
base: 'SauceLabs',
browserName: 'android',
platform: 'Linux',
version: '4.2'
},
'SL_ANDROID4.3': {
base: 'SauceLabs',
browserName: 'android',
platform: 'Linux',
version: '4.3'
},
'SL_ANDROID4.4': {
base: 'SauceLabs',
browserName: 'android',
platform: 'Linux',
version: '4.4'
},
'SL_ANDROID5': {
base: 'SauceLabs',
browserName: 'android',
platform: 'Linux',
version: '5.1'
},
'BS_CHROME': { 'BS_CHROME': {base: 'BrowserStack', browser: 'chrome', os: 'OS X', os_version: 'Yosemite'},
base: 'BrowserStack', 'BS_FIREFOX': {base: 'BrowserStack', browser: 'firefox', os: 'Windows', os_version: '10'},
browser: 'chrome', 'BS_SAFARI7': {base: 'BrowserStack', browser: 'safari', os: 'OS X', os_version: 'Mavericks'},
os: 'OS X', 'BS_SAFARI8': {base: 'BrowserStack', browser: 'safari', os: 'OS X', os_version: 'Yosemite'},
os_version: 'Yosemite' 'BS_SAFARI9': {base: 'BrowserStack', browser: 'safari', os: 'OS X', os_version: 'El Capitan'},
}, 'BS_SAFARI10': {base: 'BrowserStack', browser: 'safari', os: 'OS X', os_version: 'Sierra'},
'BS_FIREFOX': { 'BS_IOS7': {base: 'BrowserStack', device: 'iPhone 5S', os: 'ios', os_version: '7.0'},
base: 'BrowserStack', 'BS_IOS8': {base: 'BrowserStack', device: 'iPhone 6', os: 'ios', os_version: '8.3'},
browser: 'firefox', 'BS_IOS9': {base: 'BrowserStack', device: 'iPhone 6S', os: 'ios', os_version: '9.1'},
os: 'Windows', 'BS_IOS10': {base: 'BrowserStack', device: 'iPhone SE', os: 'ios', os_version: '10.0'},
os_version: '10' 'BS_IE9':
}, {base: 'BrowserStack', browser: 'ie', browser_version: '9.0', os: 'Windows', os_version: '7'},
'BS_SAFARI7': {
base: 'BrowserStack',
browser: 'safari',
os: 'OS X',
os_version: 'Mavericks'
},
'BS_SAFARI8': {
base: 'BrowserStack',
browser: 'safari',
os: 'OS X',
os_version: 'Yosemite'
},
'BS_SAFARI9': {
base: 'BrowserStack',
browser: 'safari',
os: 'OS X',
os_version: 'El Capitan'
},
'BS_IOS7': {
base: 'BrowserStack',
device: 'iPhone 5S',
os: 'ios',
os_version: '7.0'
},
'BS_IOS8': {
base: 'BrowserStack',
device: 'iPhone 6',
os: 'ios',
os_version: '8.3'
},
'BS_IOS9': {
base: 'BrowserStack',
device: 'iPhone 6S',
os: 'ios',
os_version: '9.1'
},
'BS_IE9': {
base: 'BrowserStack',
browser: 'ie',
browser_version: '9.0',
os: 'Windows',
os_version: '7'
},
'BS_IE10': { 'BS_IE10': {
base: 'BrowserStack', base: 'BrowserStack',
browser: 'ie', browser: 'ie',
@ -225,58 +107,35 @@ var customLaunchers = {
os: 'Windows', os: 'Windows',
os_version: '10' os_version: '10'
}, },
'BS_EDGE': { 'BS_EDGE': {base: 'BrowserStack', browser: 'edge', os: 'Windows', os_version: '10'},
base: 'BrowserStack', 'BS_WINDOWSPHONE':
browser: 'edge', {base: 'BrowserStack', device: 'Nokia Lumia 930', os: 'winphone', os_version: '8.1'},
os: 'Windows', 'BS_ANDROID5': {base: 'BrowserStack', device: 'Google Nexus 5', os: 'android', os_version: '5.0'},
os_version: '10' 'BS_ANDROID4.4': {base: 'BrowserStack', device: 'HTC One M8', os: 'android', os_version: '4.4'},
}, 'BS_ANDROID4.3':
'BS_WINDOWSPHONE' : { {base: 'BrowserStack', device: 'Samsung Galaxy S4', os: 'android', os_version: '4.3'},
base: 'BrowserStack', 'BS_ANDROID4.2':
device: 'Nokia Lumia 930', {base: 'BrowserStack', device: 'Google Nexus 4', os: 'android', os_version: '4.2'},
os: 'winphone', 'BS_ANDROID4.1':
os_version: '8.1' {base: 'BrowserStack', device: 'Google Nexus 7', os: 'android', os_version: '4.1'}
},
'BS_ANDROID5': {
base: 'BrowserStack',
device: 'Google Nexus 5',
os: 'android',
os_version: '5.0'
},
'BS_ANDROID4.4': {
base: 'BrowserStack',
device: 'HTC One M8',
os: 'android',
os_version: '4.4'
},
'BS_ANDROID4.3': {
base: 'BrowserStack',
device: 'Samsung Galaxy S4',
os: 'android',
os_version: '4.3'
},
'BS_ANDROID4.2': {
base: 'BrowserStack',
device: 'Google Nexus 4',
os: 'android',
os_version: '4.2'
},
'BS_ANDROID4.1': {
base: 'BrowserStack',
device: 'Google Nexus 7',
os: 'android',
os_version: '4.1'
}
}; };
var sauceAliases = { var sauceAliases = {
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'SauceLabs';}), 'ALL': Object.keys(customLaunchers).filter(function(item) {
'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'], return customLaunchers[item].base == 'SauceLabs';
'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'], }),
'DESKTOP': [
'SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7',
'SL_SAFARI8', 'SL_SAFARI9', 'SL_SAFARI10'
],
'MOBILE': [
'SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5', 'SL_IOS7',
'SL_IOS8', 'SL_IOS9', 'SL_IOS10'
],
'ANDROID': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5'], 'ANDROID': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5'],
'IE': ['SL_IE9', 'SL_IE10', 'SL_IE11'], 'IE': ['SL_IE9', 'SL_IE10', 'SL_IE11'],
'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9'], 'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9', 'SL_IOS10'],
'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'], 'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9', 'SL_SAFARI10'],
'BETA': ['SL_CHROMEBETA', 'SL_FIREFOXBETA'], 'BETA': ['SL_CHROMEBETA', 'SL_FIREFOXBETA'],
'DEV': ['SL_CHROMEDEV', 'SL_FIREFOXDEV'], 'DEV': ['SL_CHROMEDEV', 'SL_FIREFOXDEV'],
'CI_REQUIRED': buildConfiguration('unitTest', 'SL', true), 'CI_REQUIRED': buildConfiguration('unitTest', 'SL', true),
@ -284,13 +143,20 @@ var sauceAliases = {
}; };
var browserstackAliases = { var browserstackAliases = {
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'BrowserStack';}), 'ALL': Object.keys(customLaunchers).filter(function(item) {
'DESKTOP': ['BS_CHROME', 'BS_FIREFOX', 'BS_IE9', 'BS_IE10', 'BS_IE11', 'BS_EDGE', 'BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'], return customLaunchers[item].base == 'BrowserStack';
'MOBILE': ['BS_ANDROID4.3', 'BS_ANDROID4.4', 'BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_WINDOWSPHONE'], }),
'DESKTOP': [
'BS_CHROME', 'BS_FIREFOX', 'BS_IE9', 'BS_IE10', 'BS_IE11', 'BS_EDGE', 'BS_SAFARI7',
'BS_SAFARI8', 'BS_SAFARI9', 'BS_SAFARI10'
],
'MOBILE': [
'BS_ANDROID4.3', 'BS_ANDROID4.4', 'BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_IOS10', 'BS_WINDOWSPHONE'
],
'ANDROID': ['BS_ANDROID4.3', 'BS_ANDROID4.4'], 'ANDROID': ['BS_ANDROID4.3', 'BS_ANDROID4.4'],
'IE': ['BS_IE9', 'BS_IE10', 'BS_IE11'], 'IE': ['BS_IE9', 'BS_IE10', 'BS_IE11'],
'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9'], 'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_IOS10'],
'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'], 'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9', 'BS_SAFARI10'],
'CI_REQUIRED': buildConfiguration('unitTest', 'BS', true), 'CI_REQUIRED': buildConfiguration('unitTest', 'BS', true),
'CI_OPTIONAL': buildConfiguration('unitTest', 'BS', false) 'CI_OPTIONAL': buildConfiguration('unitTest', 'BS', false)
}; };
@ -303,11 +169,9 @@ module.exports = {
function buildConfiguration(type, target, required) { function buildConfiguration(type, target, required) {
return Object.keys(CIconfiguration) return Object.keys(CIconfiguration)
.filter((item) => { .filter((item) => {
var conf = CIconfiguration[item][type]; var conf = CIconfiguration[item][type];
return conf.required === required && conf.target === target; return conf.required === required && conf.target === target;
}) })
.map((item) => { .map((item) => target + '_' + item.toUpperCase());
return target + '_' + item.toUpperCase();
});
} }

40
docs/PUBLIC_API.md Normal file
View 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.

View File

@ -1,3 +1,11 @@
/**
* @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
*/
'use strict'; 'use strict';
// THIS CHECK SHOULD BE THE FIRST THING IN THIS FILE // THIS CHECK SHOULD BE THE FIRST THING IN THIS FILE
@ -13,12 +21,14 @@ const os = require('os');
// clang-format entry points // clang-format entry points
const srcsToFmt = [ const srcsToFmt = [
'modules/@angular/**/*.ts', 'modules/@angular/**/*.{js,ts}',
'modules/benchmarks/**/*.ts', 'modules/benchmarks/**/*.{js,ts}',
'modules/e2e_util/**/*.ts', 'modules/e2e_util/**/*.{js,ts}',
'modules/playground/**/*.ts', 'modules/playground/**/*.{js,ts}',
'tools/**/*.ts', 'tools/**/*.{js,ts}',
'!tools/public_api_guard/**/*.d.ts', '!tools/public_api_guard/**/*.d.ts',
'./*.{js,ts}',
'!shims_for_IE.js',
]; ];
// Check source code for formatting errors (clang-format) // Check source code for formatting errors (clang-format)
@ -26,15 +36,16 @@ gulp.task('format:enforce', () => {
const format = require('gulp-clang-format'); const format = require('gulp-clang-format');
const clangFormat = require('clang-format'); const clangFormat = require('clang-format');
return gulp.src(srcsToFmt).pipe( return gulp.src(srcsToFmt).pipe(
format.checkFormat('file', clangFormat, {verbose: true, fail: true})); format.checkFormat('file', clangFormat, {verbose: true, fail: true}));
}); });
// Format the source code with clang-format (see .clang-format) // Format the source code with clang-format (see .clang-format)
gulp.task('format', () => { gulp.task('format', () => {
const format = require('gulp-clang-format'); const format = require('gulp-clang-format');
const clangFormat = require('clang-format'); const clangFormat = require('clang-format');
return gulp.src(srcsToFmt, { base: '.' }).pipe( return gulp.src(srcsToFmt, {base: '.'})
format.format('file', clangFormat)).pipe(gulp.dest('.')); .pipe(format.format('file', clangFormat))
.pipe(gulp.dest('.'));
}); });
const entrypoints = [ const entrypoints = [
@ -62,12 +73,18 @@ const entrypoints = [
]; ];
const publicApiDir = path.normalize('tools/public_api_guard'); const publicApiDir = path.normalize('tools/public_api_guard');
const publicApiArgs = [ const publicApiArgs = [
'--rootDir', 'dist/packages-dist', '--rootDir',
'--stripExportPattern', '^__', 'dist/packages-dist',
'--allowModuleIdentifiers', 'jasmine', '--stripExportPattern',
'--allowModuleIdentifiers', 'protractor', '^__',
'--allowModuleIdentifiers', 'angular', '--allowModuleIdentifiers',
'--onStabilityMissing', 'error', 'jasmine',
'--allowModuleIdentifiers',
'protractor',
'--allowModuleIdentifiers',
'angular',
'--onStabilityMissing',
'error',
].concat(entrypoints); ].concat(entrypoints);
// Build angular // Build angular
@ -83,17 +100,17 @@ gulp.task('public-api:enforce', (done) => {
const childProcess = require('child_process'); const childProcess = require('child_process');
childProcess childProcess
.spawn( .spawn(
path.join(__dirname, platformScriptPath(`/node_modules/.bin/ts-api-guardian`)), path.join(__dirname, platformScriptPath(`/node_modules/.bin/ts-api-guardian`)),
['--verifyDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'}) ['--verifyDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
.on('close', (errorCode) => { .on('close', (errorCode) => {
if (errorCode !== 0) { if (errorCode !== 0) {
done(new Error( done(new Error(
'Public API differs from golden file. Please run `gulp public-api:update`.')); 'Public API differs from golden file. Please run `gulp public-api:update`.'));
} else { } else {
done(); done();
} }
}); });
}); });
// Generate the public API golden files // Generate the public API golden files
@ -101,20 +118,24 @@ gulp.task('public-api:update', ['build.sh'], (done) => {
const childProcess = require('child_process'); const childProcess = require('child_process');
childProcess childProcess
.spawn( .spawn(
path.join(__dirname, platformScriptPath(`/node_modules/.bin/ts-api-guardian`)), path.join(__dirname, platformScriptPath(`/node_modules/.bin/ts-api-guardian`)),
['--outDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'}) ['--outDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
.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. // Checks tests for presence of ddescribe, fdescribe, fit, iit and fails the build if one of the
// Currently xdescribe and xit are _not_ reported as errors since there are a couple of excluded tests in our code base. // 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() { gulp.task('check-tests', function() {
const ddescribeIit = require('gulp-ddescribe-iit'); const ddescribeIit = require('gulp-ddescribe-iit');
return gulp.src([ return gulp
'modules/**/*.spec.ts', .src([
'modules/**/*_spec.ts', 'modules/**/*.spec.ts',
]).pipe(ddescribeIit({allowDisabledTests: true})); 'modules/**/*_spec.ts',
])
.pipe(ddescribeIit({allowDisabledTests: true}));
}); });
// Check the coding standards and programming errors // Check the coding standards and programming errors
@ -123,14 +144,21 @@ gulp.task('lint', ['check-tests', 'format:enforce', 'tools:build'], () => {
// Built-in rules are at // Built-in rules are at
// https://github.com/palantir/tslint#supported-rules // https://github.com/palantir/tslint#supported-rules
const tslintConfig = require('./tslint.json'); const tslintConfig = require('./tslint.json');
return gulp.src(['modules/@angular/**/*.ts', 'modules/benchpress/**/*.ts']) return gulp
.pipe(tslint({ .src([
tslint: require('tslint').default, // todo(vicb): add .js files when supported
configuration: tslintConfig, // see https://github.com/palantir/tslint/pull/1515
rulesDirectory: 'dist/tools/tslint', 'modules/@angular/**/*.ts',
formatter: 'prose', 'modules/benchpress/**/*.ts',
})) './*.ts',
.pipe(tslint.report({emitError: true})); ])
.pipe(tslint({
tslint: require('tslint').default,
configuration: tslintConfig,
rulesDirectory: 'dist/tools/tslint',
formatter: 'prose',
}))
.pipe(tslint.report({emitError: true}));
}); });
gulp.task('tools:build', (done) => { tsc('tools/', done); }); gulp.task('tools:build', (done) => { tsc('tools/', done); });
@ -142,7 +170,7 @@ gulp.task('check-cycle', (done) => {
const dependencyObject = madge(['dist/all/'], { const dependencyObject = madge(['dist/all/'], {
format: 'cjs', format: 'cjs',
extensions: ['.js'], extensions: ['.js'],
onParseFile: function(data) { data.src = data.src.replace(/\/\* circular \*\//g, "//"); } onParseFile: function(data) { data.src = data.src.replace(/\/\* circular \*\//g, '//'); }
}); });
const circularDependencies = dependencyObject.circular().getArray(); const circularDependencies = dependencyObject.circular().getArray();
if (circularDependencies.length > 0) { if (circularDependencies.length > 0) {
@ -173,11 +201,11 @@ gulp.task('serve-examples', () => {
const cors = require('cors'); const cors = require('cors');
connect.server({ connect.server({
root: `${__dirname}/dist/examples`, root: `${__dirname}/dist/examples`,
port: 8001, port: 8001,
livereload: false, livereload: false,
open: false, open: false,
middleware: (connect, opt) => [cors()], middleware: (connect, opt) => [cors()],
}); });
}); });
@ -187,16 +215,13 @@ gulp.task('changelog', () => {
const conventionalChangelog = require('gulp-conventional-changelog'); const conventionalChangelog = require('gulp-conventional-changelog');
return gulp.src('CHANGELOG.md') return gulp.src('CHANGELOG.md')
.pipe(conventionalChangelog({ .pipe(conventionalChangelog({preset: 'angular', releaseCount: 1}, {
preset: 'angular', // Conventional Changelog Context
releaseCount: 1 // We have to manually set version number so it doesn't get prefixed with `v`
}, { // See https://github.com/conventional-changelog/conventional-changelog-core/issues/10
// Conventional Changelog Context currentTag: require('./package.json').version
// We have to manually set version number so it doesn't get prefixed with `v` }))
// See https://github.com/conventional-changelog/conventional-changelog-core/issues/10 .pipe(gulp.dest('./'));
currentTag: require('./package.json').version
}))
.pipe(gulp.dest('./'));
}); });
function tsc(projectPath, done) { function tsc(projectPath, done) {
@ -205,8 +230,7 @@ function tsc(projectPath, done) {
childProcess childProcess
.spawn( .spawn(
path.normalize(platformScriptPath(`${__dirname}/node_modules/.bin/tsc`)), path.normalize(platformScriptPath(`${__dirname}/node_modules/.bin/tsc`)),
['-p', path.join(__dirname, projectPath)], ['-p', path.join(__dirname, projectPath)], {stdio: 'inherit'})
{stdio: 'inherit'})
.on('close', done); .on('close', done);
} }

View File

@ -1,3 +1,11 @@
/**
* @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
*/
var browserProvidersConf = require('./browser-providers.conf.js'); var browserProvidersConf = require('./browser-providers.conf.js');
var internalAngularReporter = require('./tools/karma/reporter.js'); var internalAngularReporter = require('./tools/karma/reporter.js');
@ -17,24 +25,25 @@ module.exports = function(config) {
// include Angular v1 for upgrade module testing // include Angular v1 for upgrade module testing
'node_modules/angular/angular.min.js', 'node_modules/angular/angular.min.js',
'node_modules/zone.js/dist/zone.js', 'node_modules/zone.js/dist/zone.js', 'node_modules/zone.js/dist/long-stack-trace-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/jasmine-patch.js', 'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/sync-test.js',
'node_modules/zone.js/dist/jasmine-patch.js',
'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/fake-async-test.js', 'node_modules/zone.js/dist/fake-async-test.js',
// Including systemjs because it defines `__eval`, which produces correct stack traces. // Including systemjs because it defines `__eval`, which produces correct stack traces.
'shims_for_IE.js', 'shims_for_IE.js', 'node_modules/systemjs/dist/system.src.js',
'node_modules/systemjs/dist/system.src.js',
{pattern: 'node_modules/rxjs/**', included: false, watched: false, served: true}, {pattern: 'node_modules/rxjs/**', included: false, watched: false, served: true},
'node_modules/reflect-metadata/Reflect.js', 'node_modules/reflect-metadata/Reflect.js', 'tools/build/file2modulename.js', 'test-main.js',
'tools/build/file2modulename.js', {pattern: 'dist/all/empty.*', included: false, watched: false}, {
'test-main.js', pattern: 'modules/@angular/platform-browser/test/static_assets/**',
{pattern: 'dist/all/empty.*', included: false, watched: false}, included: false,
{pattern: 'modules/@angular/platform-browser/test/static_assets/**', included: false, watched: false}, watched: false
{pattern: 'modules/@angular/platform-browser/test/browser/static_assets/**', included: false, watched: false} },
{
pattern: 'modules/@angular/platform-browser/test/browser/static_assets/**',
included: false,
watched: false,
}
], ],
exclude: [ exclude: [
@ -44,7 +53,7 @@ module.exports = function(config) {
'dist/all/@angular/benchpress/**', 'dist/all/@angular/benchpress/**',
'dist/all/angular1_router.js', 'dist/all/angular1_router.js',
'dist/all/@angular/platform-browser/testing/e2e_util.js', 'dist/all/@angular/platform-browser/testing/e2e_util.js',
'dist/examples/**/e2e_test/**' 'dist/examples/**/e2e_test/**',
], ],
customLaunchers: browserProvidersConf.customLaunchers, customLaunchers: browserProvidersConf.customLaunchers,
@ -55,11 +64,11 @@ module.exports = function(config) {
'karma-sauce-launcher', 'karma-sauce-launcher',
'karma-chrome-launcher', 'karma-chrome-launcher',
'karma-sourcemap-loader', 'karma-sourcemap-loader',
internalAngularReporter internalAngularReporter,
], ],
preprocessors: { preprocessors: {
'**/*.js': ['sourcemap'] '**/*.js': ['sourcemap'],
}, },
reporters: ['internal-angular'], reporters: ['internal-angular'],
@ -73,7 +82,7 @@ module.exports = function(config) {
'selenium-version': '2.53.0', 'selenium-version': '2.53.0',
'command-timeout': 600, 'command-timeout': 600,
'idle-timeout': 600, 'idle-timeout': 600,
'max-duration': 5400 'max-duration': 5400,
} }
}, },
@ -82,20 +91,21 @@ module.exports = function(config) {
startTunnel: false, startTunnel: false,
retryLimit: 3, retryLimit: 3,
timeout: 600, timeout: 600,
pollingTimeout: 10000 pollingTimeout: 10000,
}, },
browsers: ['Chrome'], browsers: ['Chrome'],
port: 9876, port: 9876,
captureTimeout: 60000, captureTimeout: 60000,
browserDisconnectTimeout : 60000, browserDisconnectTimeout: 60000,
browserDisconnectTolerance : 3, browserDisconnectTolerance: 3,
browserNoActivityTimeout : 60000, browserNoActivityTimeout: 60000,
}); });
if (process.env.TRAVIS) { if (process.env.TRAVIS) {
var buildId = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')'; var buildId =
'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
if (process.env.CI_MODE.startsWith('saucelabs')) { if (process.env.CI_MODE.startsWith('saucelabs')) {
config.sauceLabs.build = buildId; config.sauceLabs.build = buildId;
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER; config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;

View File

@ -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?

View File

@ -9,8 +9,6 @@
import {OpaqueToken} from '@angular/core'; import {OpaqueToken} from '@angular/core';
import * as fs from 'fs'; import * as fs from 'fs';
import {DateWrapper} from './facade/lang';
export class Options { export class Options {
static SAMPLE_ID = new OpaqueToken('Options.sampleId'); static SAMPLE_ID = new OpaqueToken('Options.sampleId');
static DEFAULT_DESCRIPTION = new OpaqueToken('Options.defaultDescription'); static DEFAULT_DESCRIPTION = new OpaqueToken('Options.defaultDescription');
@ -34,7 +32,7 @@ export class Options {
{provide: Options.FORCE_GC, useValue: false}, {provide: Options.FORCE_GC, useValue: false},
{provide: Options.PREPARE, useValue: Options.NO_PREPARE}, {provide: Options.PREPARE, useValue: Options.NO_PREPARE},
{provide: Options.MICRO_METRICS, useValue: {}}, {provide: Options.USER_METRICS, useValue: {}}, {provide: Options.MICRO_METRICS, useValue: {}}, {provide: Options.USER_METRICS, useValue: {}},
{provide: Options.NOW, useValue: () => DateWrapper.now()}, {provide: Options.NOW, useValue: () => new Date()},
{provide: Options.RECEIVED_DATA, useValue: false}, {provide: Options.RECEIVED_DATA, useValue: false},
{provide: Options.REQUEST_COUNT, useValue: false}, {provide: Options.REQUEST_COUNT, useValue: false},
{provide: Options.CAPTURE_FRAMES, useValue: false}, {provide: Options.CAPTURE_FRAMES, useValue: false},

View File

@ -6,18 +6,15 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Map} from './facade/collection';
import {Date, DateWrapper} from './facade/lang';
export class MeasureValues { export class MeasureValues {
constructor( constructor(
public runIndex: number, public timeStamp: Date, public values: {[key: string]: any}) {} public runIndex: number, public timeStamp: Date, public values: {[key: string]: any}) {}
toJson() { toJson() {
return { return {
'timeStamp': DateWrapper.toJson(this.timeStamp), 'timeStamp': this.timeStamp.toJSON(),
'runIndex': this.runIndex, 'runIndex': this.runIndex,
'values': this.values 'values': this.values,
}; };
} }
} }

View File

@ -7,7 +7,6 @@
*/ */
import {Injector, OpaqueToken} from '@angular/core'; import {Injector, OpaqueToken} from '@angular/core';
import {StringMapWrapper} from '../facade/collection';
import {Metric} from '../metric'; import {Metric} from '../metric';
@ -57,8 +56,7 @@ export class MultiMetric extends Metric {
function mergeStringMaps(maps: {[key: string]: string}[]): {[key: string]: string} { function mergeStringMaps(maps: {[key: string]: string}[]): {[key: string]: string} {
var result: {[key: string]: string} = {}; var result: {[key: string]: string} = {};
maps.forEach( maps.forEach(map => { Object.keys(map).forEach(prop => { result[prop] = map[prop]; }); });
map => { StringMapWrapper.forEach(map, (value, prop) => { result[prop] = value; }); });
return result; return result;
} }

View File

@ -6,10 +6,9 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Inject, Injectable, OpaqueToken, Provider} from '@angular/core'; import {Inject, Injectable} from '@angular/core';
import {Options} from '../common_options'; import {Options} from '../common_options';
import {StringMapWrapper} from '../facade/collection';
import {isNumber} from '../facade/lang'; 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';
@ -40,7 +39,7 @@ export class UserMetric extends Metric {
reject = rej; reject = rej;
}); });
let adapter = this._wdAdapter; let adapter = this._wdAdapter;
let names = StringMapWrapper.keys(this._userMetrics); let names = Object.keys(this._userMetrics);
function getAndClearValues() { function getAndClearValues() {
Promise.all(names.map(name => adapter.executeScript(`return window.${name}`))) Promise.all(names.map(name => adapter.executeScript(`return window.${name}`)))
@ -48,9 +47,9 @@ export class UserMetric extends Metric {
if (values.every(isNumber)) { if (values.every(isNumber)) {
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 = StringMapWrapper.create(); let map: {[k: string]: any} = {};
for (let i = 0, n = names.length; i < n; i++) { for (let i = 0, n = names.length; i < n; i++) {
StringMapWrapper.set(map, names[i], values[i]); map[names[i]] = values[i];
} }
resolve(map); resolve(map);
}, reject); }, reject);

View File

@ -7,10 +7,7 @@
*/ */
import {Inject, Injectable, OpaqueToken} from '@angular/core'; import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {print} from '../facade/lang';
import {ListWrapper, StringMapWrapper} from '../facade/collection';
import {NumberWrapper, isBlank, isPresent, print} from '../facade/lang';
import {Math} from '../facade/math';
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';

View File

@ -9,7 +9,7 @@
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 {DateWrapper, Json, isBlank, isPresent} from '../facade/lang'; 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';
@ -45,8 +45,7 @@ export class JsonFileReporter extends Reporter {
'completeSample': completeSample, 'completeSample': completeSample,
'validSample': validSample, 'validSample': validSample,
}); });
var filePath = var filePath = `${this._path}/${this._description.id}_${this._now().getTime()}.json`;
`${this._path}/${this._description.id}_${DateWrapper.toMillis(this._now())}.json`;
return this._writeFile(filePath, content); return this._writeFile(filePath, content);
} }
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {StringMapWrapper} from '../facade/collection';
import {NumberWrapper} from '../facade/lang'; import {NumberWrapper} from '../facade/lang';
import {MeasureValues} from '../measure_values'; import {MeasureValues} from '../measure_values';
import {Statistic} from '../statistic'; import {Statistic} from '../statistic';
@ -17,7 +17,7 @@ export function formatNum(n: number) {
export function sortedProps(obj: {[key: string]: any}) { export function sortedProps(obj: {[key: string]: any}) {
var props: string[] = []; var props: string[] = [];
StringMapWrapper.forEach(obj, (value, prop) => props.push(prop)); props.push(...Object.keys(obj));
props.sort(); props.sort();
return props; return props;
} }

View File

@ -9,7 +9,7 @@
import {Provider, ReflectiveInjector} from '@angular/core'; import {Provider, ReflectiveInjector} from '@angular/core';
import {Options} from './common_options'; import {Options} from './common_options';
import {isBlank, isPresent} from './facade/lang'; import {isPresent} from './facade/lang';
import {Metric} from './metric'; import {Metric} from './metric';
import {MultiMetric} from './metric/multi_metric'; import {MultiMetric} from './metric/multi_metric';
import {PerflogMetric} from './metric/perflog_metric'; import {PerflogMetric} from './metric/perflog_metric';

View File

@ -9,7 +9,6 @@
import {OpaqueToken} from '@angular/core'; import {OpaqueToken} from '@angular/core';
import {Options} from './common_options'; import {Options} from './common_options';
import {StringMapWrapper} from './facade/collection';
import {Metric} from './metric'; import {Metric} from './metric';
import {Validator} from './validator'; import {Validator} from './validator';
@ -42,7 +41,7 @@ export class SampleDescription {
public metrics: {[key: string]: any}) { public metrics: {[key: string]: any}) {
this.description = {}; this.description = {};
descriptions.forEach(description => { descriptions.forEach(description => {
StringMapWrapper.forEach(description, (value, prop) => this.description[prop] = value); Object.keys(description).forEach(prop => { this.description[prop] = description[prop]; });
}); });
} }

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Inject, Injectable, OpaqueToken} from '@angular/core'; import {Inject, Injectable} from '@angular/core';
import {Options} from './common_options'; import {Options} from './common_options';
import {Date, DateWrapper, isBlank, isPresent} from './facade/lang'; import {isPresent} from './facade/lang';
import {MeasureValues} from './measure_values'; import {MeasureValues} from './measure_values';
import {Metric} from './metric'; import {Metric} from './metric';
import {Reporter} from './reporter'; import {Reporter} from './reporter';

View File

@ -9,7 +9,6 @@
import {Injector, OpaqueToken} from '@angular/core'; import {Injector, OpaqueToken} from '@angular/core';
import {Options} from './common_options'; import {Options} from './common_options';
import {isBlank, isPresent} from './facade/lang';
export type PerfLogEvent = { export type PerfLogEvent = {
[key: string]: any [key: string]: any
@ -50,7 +49,7 @@ export abstract class WebDriverExtension {
delegate = extension; delegate = extension;
} }
}); });
if (isBlank(delegate)) { if (!delegate) {
throw new Error('Could not find a delegate for given capabilities!'); throw new Error('Could not find a delegate for given capabilities!');
} }
return delegate; return delegate;

View File

@ -169,7 +169,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
eventCategories: string[], eventName: string, expectedCategories: string[], eventCategories: string[], eventName: string, expectedCategories: string[],
expectedName: string = null): boolean { expectedName: string = null): boolean {
var hasCategories = expectedCategories.reduce( var hasCategories = expectedCategories.reduce(
(value, cat) => { return value && eventCategories.indexOf(cat) !== -1; }, true); (value, cat) => value && eventCategories.indexOf(cat) !== -1, true);
return !expectedName ? hasCategories : hasCategories && eventName === expectedName; return !expectedName ? hasCategories : hasCategories && eventName === expectedName;
} }

View File

@ -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';
} }
} }

View File

@ -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']);
} }
}); });
@ -52,7 +52,7 @@ export class IOsDriverExtension extends WebDriverExtension {
/** @internal */ /** @internal */
private _convertPerfRecordsToEvents(records: any[], events: PerfLogEvent[] = null) { private _convertPerfRecordsToEvents(records: any[], events: PerfLogEvent[] = null) {
if (isBlank(events)) { if (!events) {
events = []; events = [];
} }
records.forEach((record) => { records.forEach((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' && (isBlank(data) || 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';
} }
} }

View File

@ -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 {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {Metric, MultiMetric, ReflectiveInjector} from '../../index'; import {Metric, MultiMetric, ReflectiveInjector} from '../../index';
export function main() { export function main() {
function createMetric(ids: any[]) { function createMetric(ids: any[]) {
var m = ReflectiveInjector var m = ReflectiveInjector
.resolveAndCreate([ .resolveAndCreate([
ids.map(id => { return {provide: id, useValue: new MockMetric(id)}; }), ids.map(id => ({provide: id, useValue: new MockMetric(id)})),
MultiMetric.provideWith(ids) MultiMetric.provideWith(ids)
]) ])
.get(MultiMetric); .get(MultiMetric);

View File

@ -7,11 +7,10 @@
*/ */
import {Provider} from '@angular/core'; import {Provider} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, beforeEach, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {Metric, Options, PerfLogEvent, PerfLogFeatures, PerflogMetric, ReflectiveInjector, WebDriverExtension} from '../../index'; import {Metric, Options, PerfLogEvent, PerfLogFeatures, PerflogMetric, ReflectiveInjector, WebDriverExtension} from '../../index';
import {StringMapWrapper} from '../../src/facade/collection'; import {isPresent} from '../../src/facade/lang';
import {isBlank, isPresent} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory'; import {TraceEventFactory} from '../trace_event_factory';
export function main() { export function main() {
@ -28,12 +27,12 @@ export function main() {
requestCount?: boolean requestCount?: boolean
} = {}): Metric { } = {}): Metric {
commandLog = []; commandLog = [];
if (isBlank(perfLogFeatures)) { if (!perfLogFeatures) {
perfLogFeatures = perfLogFeatures =
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true}); new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
} }
if (isBlank(microMetrics)) { if (!microMetrics) {
microMetrics = StringMapWrapper.create(); microMetrics = {};
} }
var providers: Provider[] = [ var providers: Provider[] = [
Options.DEFAULT_PROVIDERS, PerflogMetric.PROVIDERS, Options.DEFAULT_PROVIDERS, PerflogMetric.PROVIDERS,
@ -68,7 +67,7 @@ export function main() {
function sortedKeys(stringMap: {[key: string]: any}) { function sortedKeys(stringMap: {[key: string]: any}) {
var res: string[] = []; var res: string[] = [];
StringMapWrapper.forEach(stringMap, (_, key) => { res.push(key); }); res.push(...Object.keys(stringMap));
res.sort(); res.sort();
return res; return res;
} }

View File

@ -7,11 +7,9 @@
*/ */
import {Provider, ReflectiveInjector} from '@angular/core'; import {Provider, ReflectiveInjector} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {Injector, Metric, MultiMetric, Options, PerfLogEvent, PerfLogFeatures, PerflogMetric, UserMetric, WebDriverAdapter, WebDriverExtension} from '../../index'; import {Options, PerfLogEvent, PerfLogFeatures, UserMetric, WebDriverAdapter} from '../../index';
import {StringMapWrapper} from '../../src/facade/collection';
import {Json, isBlank, isPresent} from '../../src/facade/lang';
export function main() { export function main() {
var wdAdapter: MockDriverAdapter; var wdAdapter: MockDriverAdapter;
@ -19,12 +17,12 @@ export function main() {
function createMetric( function createMetric(
perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures, perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
{userMetrics}: {userMetrics?: {[key: string]: string}} = {}): UserMetric { {userMetrics}: {userMetrics?: {[key: string]: string}} = {}): UserMetric {
if (isBlank(perfLogFeatures)) { if (!perfLogFeatures) {
perfLogFeatures = perfLogFeatures =
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true}); new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
} }
if (isBlank(userMetrics)) { if (!userMetrics) {
userMetrics = StringMapWrapper.create(); userMetrics = {};
} }
wdAdapter = new MockDriverAdapter(); wdAdapter = new MockDriverAdapter();
var providers: Provider[] = [ var providers: Provider[] = [

View File

@ -7,10 +7,10 @@
*/ */
import {Provider} from '@angular/core'; import {Provider} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {describe, expect, it} from '@angular/core/testing/testing_internal';
import {ConsoleReporter, MeasureValues, ReflectiveInjector, Reporter, SampleDescription, SampleState} from '../../index'; import {ConsoleReporter, MeasureValues, ReflectiveInjector, SampleDescription} from '../../index';
import {Date, DateWrapper, isBlank, isPresent} from '../../src/facade/lang'; import {isBlank, isPresent} from '../../src/facade/lang';
export function main() { export function main() {
describe('console reporter', () => { describe('console reporter', () => {
@ -25,7 +25,7 @@ export function main() {
metrics?: {[key: string]: any} metrics?: {[key: string]: any}
}) { }) {
log = []; log = [];
if (isBlank(descriptions)) { if (!descriptions) {
descriptions = []; descriptions = [];
} }
if (isBlank(sampleId)) { if (isBlank(sampleId)) {
@ -90,5 +90,5 @@ export function main() {
} }
function mv(runIndex: number, time: number, values: {[key: string]: number}) { function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values); return new MeasureValues(runIndex, new Date(time), values);
} }

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} 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 {DateWrapper, Json, isPresent} from '../../src/facade/lang'; import {Json, isPresent} from '../../src/facade/lang';
export function main() { export function main() {
describe('file reporter', () => { describe('file reporter', () => {
@ -27,7 +27,7 @@ export function main() {
useValue: new SampleDescription(sampleId, descriptions, metrics) useValue: new SampleDescription(sampleId, descriptions, metrics)
}, },
{provide: JsonFileReporter.PATH, useValue: path}, {provide: JsonFileReporter.PATH, useValue: path},
{provide: Options.NOW, useValue: () => DateWrapper.fromMillis(1234)}, { {provide: Options.NOW, useValue: () => new Date(1234)}, {
provide: Options.WRITE_FILE, provide: Options.WRITE_FILE,
useValue: (filename: string, content: string) => { useValue: (filename: string, content: string) => {
loggedFile = {'filename': filename, 'content': content}; loggedFile = {'filename': filename, 'content': content};
@ -77,5 +77,5 @@ export function main() {
} }
function mv(runIndex: number, time: number, values: {[key: string]: number}) { function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values); return new MeasureValues(runIndex, new Date(time), values);
} }

View File

@ -6,16 +6,15 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {MeasureValues, MultiReporter, ReflectiveInjector, Reporter} from '../../index'; import {MeasureValues, MultiReporter, ReflectiveInjector, Reporter} from '../../index';
import {DateWrapper} from '../../src/facade/lang';
export function main() { export function main() {
function createReporters(ids: any[]) { function createReporters(ids: any[]) {
var r = ReflectiveInjector var r = ReflectiveInjector
.resolveAndCreate([ .resolveAndCreate([
ids.map(id => { return {provide: id, useValue: new MockReporter(id)}; }), ids.map(id => ({provide: id, useValue: new MockReporter(id)})),
MultiReporter.provideWith(ids) MultiReporter.provideWith(ids)
]) ])
.get(MultiReporter); .get(MultiReporter);
@ -26,7 +25,7 @@ export function main() {
it('should reportMeasureValues to all', it('should reportMeasureValues to all',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var mv = new MeasureValues(0, DateWrapper.now(), {}); var mv = new MeasureValues(0, new Date(), {});
createReporters(['m1', 'm2']).then((r) => r.reportMeasureValues(mv)).then((values) => { createReporters(['m1', 'm2']).then((r) => r.reportMeasureValues(mv)).then((values) => {
expect(values).toEqual([{'id': 'm1', 'values': mv}, {'id': 'm2', 'values': mv}]); expect(values).toEqual([{'id': 'm1', 'values': mv}, {'id': 'm2', 'values': mv}]);
@ -35,9 +34,8 @@ export function main() {
})); }));
it('should reportSample to call', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { it('should reportSample to call', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var completeSample = [ var completeSample =
new MeasureValues(0, DateWrapper.now(), {}), new MeasureValues(1, DateWrapper.now(), {}) [new MeasureValues(0, new Date(), {}), new MeasureValues(1, new Date(), {})];
];
var validSample = [completeSample[1]]; var validSample = [completeSample[1]];
createReporters(['m1', 'm2']) createReporters(['m1', 'm2'])

View File

@ -6,10 +6,9 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {Injector, Metric, Options, ReflectiveInjector, Runner, SampleDescription, SampleState, Sampler, Validator, WebDriverAdapter} from '../index'; import {Injector, Metric, Options, ReflectiveInjector, Runner, SampleDescription, SampleState, Sampler, Validator, WebDriverAdapter} from '../index';
import {isBlank} from '../src/facade/lang';
export function main() { export function main() {
describe('runner', () => { describe('runner', () => {
@ -17,7 +16,7 @@ export function main() {
var runner: Runner; var runner: Runner;
function createRunner(defaultProviders: any[] = null): Runner { function createRunner(defaultProviders: any[] = null): Runner {
if (isBlank(defaultProviders)) { if (!defaultProviders) {
defaultProviders = []; defaultProviders = [];
} }
runner = new Runner([ runner = new Runner([

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {MeasureValues, Metric, Options, ReflectiveInjector, Reporter, Sampler, Validator, WebDriverAdapter} from '../index'; import {MeasureValues, Metric, Options, ReflectiveInjector, Reporter, Sampler, Validator, WebDriverAdapter} from '../index';
import {Date, DateWrapper, isBlank, isPresent, stringify} from '../src/facade/lang'; import {isBlank, isPresent} from '../src/facade/lang';
export function main() { export function main() {
var EMPTY_EXECUTE = () => {}; var EMPTY_EXECUTE = () => {};
@ -26,10 +26,10 @@ export function main() {
execute?: any execute?: any
} = {}) { } = {}) {
var time = 1000; var time = 1000;
if (isBlank(metric)) { if (!metric) {
metric = new MockMetric([]); metric = new MockMetric([]);
} }
if (isBlank(reporter)) { if (!reporter) {
reporter = new MockReporter([]); reporter = new MockReporter([]);
} }
if (isBlank(driver)) { if (isBlank(driver)) {
@ -39,7 +39,7 @@ export function main() {
Options.DEFAULT_PROVIDERS, Sampler.PROVIDERS, {provide: Metric, useValue: metric}, Options.DEFAULT_PROVIDERS, Sampler.PROVIDERS, {provide: Metric, useValue: metric},
{provide: Reporter, useValue: reporter}, {provide: WebDriverAdapter, useValue: driver}, {provide: Reporter, useValue: reporter}, {provide: WebDriverAdapter, useValue: driver},
{provide: Options.EXECUTE, useValue: execute}, {provide: Validator, useValue: validator}, {provide: Options.EXECUTE, useValue: execute}, {provide: Validator, useValue: validator},
{provide: Options.NOW, useValue: () => DateWrapper.fromMillis(time++)} {provide: Options.NOW, useValue: () => new Date(time++)}
]; ];
if (isPresent(prepare)) { if (isPresent(prepare)) {
providers.push({provide: Options.PREPARE, useValue: prepare}); providers.push({provide: Options.PREPARE, useValue: prepare});
@ -60,8 +60,8 @@ export function main() {
createSampler({ createSampler({
driver: driver, driver: driver,
validator: createCountingValidator(2), validator: createCountingValidator(2),
prepare: () => { return count++; }, prepare: () => count++,
execute: () => { return count++; } execute: () => count++,
}); });
sampler.sample().then((_) => { sampler.sample().then((_) => {
expect(count).toBe(4); expect(count).toBe(4);
@ -204,7 +204,7 @@ export function main() {
} }
function mv(runIndex: number, time: number, values: {[key: string]: number}) { function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values); return new MeasureValues(runIndex, new Date(time), values);
} }
function createCountingValidator( function createCountingValidator(
@ -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;
} }
@ -221,7 +221,7 @@ function createCountingValidator(
function createCountingMetric(log: any[] = []) { function createCountingMetric(log: any[] = []) {
var scriptTime = 0; var scriptTime = 0;
return new MockMetric(log, () => { return {'script': scriptTime++}; }); return new MockMetric(log, () => ({'script': scriptTime++}));
} }
class MockDriverAdapter extends WebDriverAdapter { class MockDriverAdapter extends WebDriverAdapter {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {describe, expect, it} from '@angular/core/testing/testing_internal';
import {Statistic} from '../src/statistic'; import {Statistic} from '../src/statistic';
export function main() { export function main() {

View File

@ -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 {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} 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'; import {ListWrapper} from '../../src/facade/collection';
import {Date, DateWrapper} from '../../src/facade/lang';
export function main() { export function main() {
describe('regression slope validator', () => { describe('regression slope validator', () => {
@ -62,5 +61,5 @@ export function main() {
} }
function mv(runIndex: number, time: number, values: {[key: string]: number}) { function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values); return new MeasureValues(runIndex, new Date(time), values);
} }

View File

@ -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 {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {describe, expect, it} from '@angular/core/testing/testing_internal';
import {MeasureValues, ReflectiveInjector, SizeValidator, Validator} from '../../index'; import {MeasureValues, ReflectiveInjector, SizeValidator} from '../../index';
import {ListWrapper} from '../../src/facade/collection'; import {ListWrapper} from '../../src/facade/collection';
import {Date, DateWrapper} from '../../src/facade/lang';
export function main() { export function main() {
describe('size validator', () => { describe('size validator', () => {
@ -47,5 +46,5 @@ export function main() {
} }
function mv(runIndex: number, time: number, values: {[key: string]: number}) { function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values); return new MeasureValues(runIndex, new Date(time), values);
} }

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} 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) {
@ -17,7 +17,7 @@ export function main() {
try { try {
res(ReflectiveInjector res(ReflectiveInjector
.resolveAndCreate([ .resolveAndCreate([
ids.map((id) => { return {provide: id, useValue: new MockExtension(id)}; }), ids.map((id) => ({provide: id, useValue: new MockExtension(id)})),
{provide: Options.CAPABILITIES, useValue: caps}, {provide: Options.CAPABILITIES, useValue: caps},
WebDriverExtension.provideFirstSupported(ids) WebDriverExtension.provideFirstSupported(ids)
]) ])
@ -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;
} }
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} 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 {Json, isBlank} from '../../src/facade/lang';
@ -35,7 +35,7 @@ export function main() {
function createExtension( function createExtension(
perfRecords: any[] = null, userAgent: string = null, perfRecords: any[] = null, userAgent: string = null,
messageMethod = 'Tracing.dataCollected'): WebDriverExtension { messageMethod = 'Tracing.dataCollected'): WebDriverExtension {
if (isBlank(perfRecords)) { if (!perfRecords) {
perfRecords = []; perfRecords = [];
} }
if (isBlank(userAgent)) { if (isBlank(userAgent)) {
@ -396,11 +396,11 @@ class MockDriverAdapter extends WebDriverAdapter {
logs(type: string) { logs(type: string) {
this._log.push(['logs', type]); this._log.push(['logs', type]);
if (type === 'performance') { if (type === 'performance') {
return Promise.resolve(this._events.map((event) => { return Promise.resolve(this._events.map(
return { (event) => ({
'message': Json.stringify({'message': {'method': this._messageMethod, 'params': event}}) 'message':
}; Json.stringify({'message': {'method': this._messageMethod, 'params': event}})
})); })));
} else { } else {
return null; return null;
} }

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} 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, isBlank, isPresent} from '../../src/facade/lang'; import {Json} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory'; import {TraceEventFactory} from '../trace_event_factory';
export function main() { export function main() {
@ -20,7 +20,7 @@ export function main() {
var normEvents = new TraceEventFactory('timeline', 'pid0'); var normEvents = new TraceEventFactory('timeline', 'pid0');
function createExtension(perfRecords: any[] = null): WebDriverExtension { function createExtension(perfRecords: any[] = null): WebDriverExtension {
if (isBlank(perfRecords)) { if (!perfRecords) {
perfRecords = []; perfRecords = [];
} }
log = []; log = [];
@ -156,7 +156,7 @@ function timeEndRecord(name: string, time: number) {
} }
function durationRecord(type: string, startTime: number, endTime: number, children: any[] = null) { function durationRecord(type: string, startTime: number, endTime: number, children: any[] = null) {
if (isBlank(children)) { if (!children) {
children = []; children = [];
} }
return {'type': type, 'startTime': startTime, 'endTime': endTime, 'children': children}; return {'type': type, 'startTime': startTime, 'endTime': endTime, 'children': children};

View File

@ -1,3 +1,10 @@
/**
* @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
*/
export default { export default {
entry: '../../../dist/packages-dist/common/testing/index.js', entry: '../../../dist/packages-dist/common/testing/index.js',
@ -10,4 +17,4 @@ export default {
'rxjs/Observable': 'Rx', 'rxjs/Observable': 'Rx',
'rxjs/Subject': 'Rx' 'rxjs/Subject': 'Rx'
} }
} };

View File

@ -1,3 +1,10 @@
/**
* @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
*/
export default { export default {
entry: '../../../dist/packages-dist/common/index.js', entry: '../../../dist/packages-dist/common/index.js',
@ -7,6 +14,6 @@ export default {
globals: { globals: {
'@angular/core': 'ng.core', '@angular/core': 'ng.core',
'rxjs/Observable': 'Rx', 'rxjs/Observable': 'Rx',
'rxjs/Subject': 'Rx' 'rxjs/Subject': 'Rx',
} }
} };

View File

@ -61,8 +61,7 @@ export class NgPlural {
addCase(value: string, switchView: SwitchView): void { this._caseViews[value] = switchView; } addCase(value: string, switchView: SwitchView): void { this._caseViews[value] = switchView; }
/** @internal */ private _updateView(): void {
_updateView(): void {
this._clearViews(); this._clearViews();
const cases = Object.keys(this._caseViews); const cases = Object.keys(this._caseViews);
@ -70,13 +69,11 @@ export class NgPlural {
this._activateView(this._caseViews[key]); this._activateView(this._caseViews[key]);
} }
/** @internal */ private _clearViews() {
_clearViews() {
if (this._activeView) this._activeView.destroy(); if (this._activeView) this._activeView.destroy();
} }
/** @internal */ private _activateView(view: SwitchView) {
_activateView(view: SwitchView) {
if (view) { if (view) {
this._activeView = view; this._activeView = view;
this._activeView.create(); this._activeView.create();

View File

@ -32,10 +32,8 @@ import {Directive, DoCheck, ElementRef, Input, KeyValueChangeRecord, KeyValueDif
*/ */
@Directive({selector: '[ngStyle]'}) @Directive({selector: '[ngStyle]'})
export class NgStyle implements DoCheck { export class NgStyle implements DoCheck {
/** @internal */ private _ngStyle: {[key: string]: string};
_ngStyle: {[key: string]: string}; private _differ: KeyValueDiffer;
/** @internal */
_differ: KeyValueDiffer;
constructor( constructor(
private _differs: KeyValueDiffers, private _ngEl: ElementRef, private _renderer: Renderer) {} private _differs: KeyValueDiffers, private _ngEl: ElementRef, private _renderer: Renderer) {}
@ -69,7 +67,7 @@ export class NgStyle implements DoCheck {
private _setStyle(nameAndUnit: string, value: string): void { private _setStyle(nameAndUnit: string, value: string): void {
const [name, unit] = nameAndUnit.split('.'); const [name, unit] = nameAndUnit.split('.');
value = value !== null && value !== void(0) && unit ? `${value}${unit}` : value; value = value && unit ? `${value}${unit}` : value;
this._renderer.setElementStyle(this._ngEl.nativeElement, name, value); this._renderer.setElementStyle(this._ngEl.nativeElement, name, value);
} }

View File

@ -111,8 +111,7 @@ export class NgSwitch {
} }
} }
/** @internal */ private _emptyAllActiveViews(): void {
_emptyAllActiveViews(): void {
const activeContainers = this._activeViews; const activeContainers = this._activeViews;
for (var i = 0; i < activeContainers.length; i++) { for (var i = 0; i < activeContainers.length; i++) {
activeContainers[i].destroy(); activeContainers[i].destroy();
@ -120,9 +119,7 @@ export class NgSwitch {
this._activeViews = []; this._activeViews = [];
} }
/** @internal */ private _activateViews(views: SwitchView[]): void {
_activateViews(views: SwitchView[]): void {
// TODO(vicb): assert(this._activeViews.length === 0);
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();
@ -141,8 +138,7 @@ export class NgSwitch {
views.push(view); views.push(view);
} }
/** @internal */ private _deregisterView(value: any, view: SwitchView): void {
_deregisterView(value: any, view: SwitchView): void {
// `_CASE_DEFAULT` is used a marker for non-registered cases // `_CASE_DEFAULT` is used a marker for non-registered cases
if (value === _CASE_DEFAULT) return; if (value === _CASE_DEFAULT) return;
const views = this._valueViews.get(value); const views = this._valueViews.get(value);
@ -181,10 +177,8 @@ export class NgSwitch {
@Directive({selector: '[ngSwitchCase]'}) @Directive({selector: '[ngSwitchCase]'})
export class NgSwitchCase { export class NgSwitchCase {
// `_CASE_DEFAULT` is used as a marker for a not yet initialized value // `_CASE_DEFAULT` is used as a marker for a not yet initialized value
/** @internal */ private _value: any = _CASE_DEFAULT;
_value: any = _CASE_DEFAULT; private _view: SwitchView;
/** @internal */
_view: SwitchView;
private _switch: NgSwitch; private _switch: NgSwitch;
constructor( constructor(

View File

@ -67,7 +67,7 @@ export enum Plural {
Two, Two,
Few, Few,
Many, Many,
Other Other,
} }
/** /**

View File

@ -49,16 +49,20 @@ export class Location {
_subject: EventEmitter<any> = new EventEmitter(); _subject: EventEmitter<any> = new EventEmitter();
/** @internal */ /** @internal */
_baseHref: string; _baseHref: string;
/** @internal */ /** @internal */
_platformStrategy: LocationStrategy; _platformStrategy: LocationStrategy;
constructor(platformStrategy: LocationStrategy) { constructor(platformStrategy: LocationStrategy) {
this._platformStrategy = platformStrategy; this._platformStrategy = platformStrategy;
var browserBaseHref = this._platformStrategy.getBaseHref(); const browserBaseHref = this._platformStrategy.getBaseHref();
this._baseHref = Location.stripTrailingSlash(_stripIndexHtml(browserBaseHref)); this._baseHref = Location.stripTrailingSlash(_stripIndexHtml(browserBaseHref));
this._platformStrategy.onPopState( this._platformStrategy.onPopState((ev) => {
(ev) => { this._subject.emit({'url': this.path(true), 'pop': true, 'type': ev.type}); }); this._subject.emit({
'url': this.path(true),
'pop': true,
'type': ev.type,
});
});
} }
/** /**

View File

@ -8,7 +8,7 @@
import {Component} from '@angular/core'; import {Component} from '@angular/core';
import {ComponentFixture, TestBed, async} from '@angular/core/testing'; import {ComponentFixture, TestBed, async} from '@angular/core/testing';
import {beforeEach, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal'; import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
export function main() { export function main() {
describe('binding to CSS class list', () => { describe('binding to CSS class list', () => {

View File

@ -8,7 +8,7 @@
import {LOCALE_ID} from '@angular/core'; import {LOCALE_ID} from '@angular/core';
import {TestBed} from '@angular/core/testing'; import {TestBed} from '@angular/core/testing';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {beforeEach, describe, inject, it} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing/matchers'; import {expect} from '@angular/platform-browser/testing/matchers';
import {NgLocaleLocalization, NgLocalization, getPluralCategory} from '../src/localization'; import {NgLocaleLocalization, NgLocalization, getPluralCategory} from '../src/localization';

View File

@ -8,12 +8,11 @@
import {AsyncPipe} from '@angular/common'; import {AsyncPipe} from '@angular/common';
import {WrappedValue} from '@angular/core'; import {WrappedValue} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter, beforeEach, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {browserDetection} from '@angular/platform-browser/testing/browser_util'; import {browserDetection} from '@angular/platform-browser/testing/browser_util';
import {EventEmitter} from '../../src/facade/async'; import {EventEmitter} from '../../src/facade/async';
import {isBlank} from '../../src/facade/lang';
import {SpyChangeDetectorRef} from '../spies'; import {SpyChangeDetectorRef} from '../spies';
export function main() { export function main() {
@ -112,7 +111,7 @@ export function main() {
var promise: Promise<any>; var promise: Promise<any>;
var ref: SpyChangeDetectorRef; var ref: SpyChangeDetectorRef;
// adds longer timers for passing tests in IE // adds longer timers for passing tests in IE
var timer = (!isBlank(getDOM()) && browserDetection.isIE) ? 50 : 10; var timer = (getDOM() && browserDetection.isIE) ? 50 : 10;
beforeEach(() => { beforeEach(() => {
promise = new Promise((res, rej) => { promise = new Promise((res, rej) => {

View File

@ -8,11 +8,9 @@
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 {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal'; 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';
import {DateWrapper} from '../../src/facade/lang';
export function main() { export function main() {
describe('DatePipe', () => { describe('DatePipe', () => {
var date: Date; var date: Date;
@ -27,7 +25,7 @@ export function main() {
// Tracking issue: https://github.com/angular/angular/issues/11187 // Tracking issue: https://github.com/angular/angular/issues/11187
beforeEach(() => { beforeEach(() => {
date = DateWrapper.create(2015, 6, 15, 9, 3, 1); date = new Date(2015, 5, 15, 9, 3, 1);
pipe = new DatePipe('en-US'); pipe = new DatePipe('en-US');
}); });

View File

@ -8,7 +8,7 @@
import {I18nPluralPipe, NgLocalization} from '@angular/common'; import {I18nPluralPipe, NgLocalization} from '@angular/common';
import {PipeResolver} from '@angular/compiler/src/pipe_resolver'; import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal'; import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
export function main() { export function main() {
describe('I18nPluralPipe', () => { describe('I18nPluralPipe', () => {

View File

@ -8,7 +8,7 @@
import {I18nSelectPipe} from '@angular/common'; import {I18nSelectPipe} from '@angular/common';
import {PipeResolver} from '@angular/compiler/src/pipe_resolver'; import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal'; import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
export function main() { export function main() {
describe('I18nSelectPipe', () => { describe('I18nSelectPipe', () => {

View File

@ -11,7 +11,7 @@ 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'; import {Json} from '../../src/facade/lang';
export function main() { export function main() {
describe('JsonPipe', () => { describe('JsonPipe', () => {
@ -20,7 +20,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'}}};

View File

@ -7,7 +7,7 @@
*/ */
import {LowerCasePipe} from '@angular/common'; import {LowerCasePipe} from '@angular/common';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal'; import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
export function main() { export function main() {
describe('LowerCasePipe', () => { describe('LowerCasePipe', () => {

View File

@ -7,7 +7,7 @@
*/ */
import {CurrencyPipe, DecimalPipe, PercentPipe} from '@angular/common'; import {CurrencyPipe, DecimalPipe, PercentPipe} from '@angular/common';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal'; 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() {

View File

@ -9,7 +9,6 @@
import {CommonModule, SlicePipe} from '@angular/common'; import {CommonModule, SlicePipe} from '@angular/common';
import {Component} from '@angular/core'; import {Component} from '@angular/core';
import {TestBed, async} from '@angular/core/testing'; import {TestBed, async} from '@angular/core/testing';
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
import {expect} from '@angular/platform-browser/testing/matchers'; import {expect} from '@angular/platform-browser/testing/matchers';
export function main() { export function main() {

View File

@ -7,7 +7,7 @@
*/ */
import {UpperCasePipe} from '@angular/common'; import {UpperCasePipe} from '@angular/common';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal'; import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
export function main() { export function main() {
describe('UpperCasePipe', () => { describe('UpperCasePipe', () => {

View File

@ -7,7 +7,7 @@
*/ */
import {ChangeDetectorRef} from '@angular/core/src/change_detection/change_detector_ref'; import {ChangeDetectorRef} from '@angular/core/src/change_detection/change_detector_ref';
import {SpyObject, proxy} from '@angular/core/testing/testing_internal'; import {SpyObject} from '@angular/core/testing/testing_internal';
export class SpyChangeDetectorRef extends SpyObject { export class SpyChangeDetectorRef extends SpyObject {
constructor() { constructor() {

View File

@ -18,9 +18,7 @@ import {EventEmitter, Injectable} from '@angular/core';
@Injectable() @Injectable()
export class SpyLocation implements Location { export class SpyLocation implements Location {
urlChanges: string[] = []; urlChanges: string[] = [];
/** @internal */
private _history: LocationState[] = [new LocationState('', '')]; private _history: LocationState[] = [new LocationState('', '')];
/** @internal */
private _historyIndex: number = 0; private _historyIndex: number = 0;
/** @internal */ /** @internal */
_subject: EventEmitter<any> = new EventEmitter(); _subject: EventEmitter<any> = new EventEmitter();

View File

@ -0,0 +1,6 @@
# Overview
This folder will be filled with the benchmark sources
so that we can do offline compilation for them.

View File

@ -36,25 +36,27 @@ const EXPECTED_XMB = `<?xml version="1.0" encoding="UTF-8" ?>
<messagebundle> <messagebundle>
<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>
`;
const EXPECTED_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> 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="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" datatype="html"> <trans-unit id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" datatype="html">
<source>translate me</source> <source>translate me</source>
<target/> <target/>
<note priority="1" from="description">desc</note> <note priority="1" from="description">desc</note>
<note priority="1" from="meaning">meaning</note> <note priority="1" from="meaning">meaning</note>
</trans-unit> </trans-unit>
<trans-unit id="65cc4ab3b4c438e07c89be2b677d08369fb62da2" datatype="html"> <trans-unit id="65cc4ab3b4c438e07c89be2b677d08369fb62da2" datatype="html">
<source>Welcome</source> <source>Welcome</source>
<target/> <target/>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>
</xliff>`; </xliff>
`;
describe('template i18n extraction output', () => { describe('template i18n extraction output', () => {
const outDir = ''; const outDir = '';

View File

@ -15,5 +15,15 @@
"declaration": true, "declaration": true,
"lib": ["es6", "dom"], "lib": ["es6", "dom"],
"baseUrl": "." "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"
]
} }

View File

@ -1,10 +1,14 @@
/**
* @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.exports = { module.exports = {
target: 'node', target: 'node',
entry: './test/all_spec.js', entry: './test/all_spec.js',
output: { output: {filename: './all_spec.js'},
filename: './all_spec.js' resolve: {extensions: ['.js']},
},
resolve: {
extensions: ['.js']
},
}; };

View File

@ -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": "1.3.2",
"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": {

View File

@ -21,7 +21,7 @@ import {CompileMetadataResolver, DirectiveNormalizer, DomElementSchemaRegistry,
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');
@ -36,11 +36,26 @@ const PREAMBLE = `/**
`; `;
export class CodeGenerator { export class CodeGeneratorModuleCollector {
constructor( constructor(
private options: AngularCompilerOptions, private program: ts.Program, private staticReflector: StaticReflector, private reflectorHost: StaticReflectorHost,
public host: ts.CompilerHost, private staticReflector: StaticReflector, private program: ts.Program, private options: AngularCompilerOptions) {}
private compiler: compiler.OfflineCompiler, private reflectorHost: ReflectorHost) {}
getModuleSymbols(program: ts.Program): {fileMetas: FileMetadata[], ngModules: StaticSymbol[]} {
// Compare with false since the default should be true
const skipFileNames = (this.options.generateCodeForLibraries === false) ?
GENERATED_OR_DTS_FILES :
GENERATED_FILES;
let filePaths = this.program.getSourceFiles()
.filter(sf => !skipFileNames.test(sf.fileName))
.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[]>[]);
return {fileMetas, ngModules};
}
private readFileMetadata(absSourcePath: string): FileMetadata { private readFileMetadata(absSourcePath: string): FileMetadata {
const moduleMetadata = this.staticReflector.getModuleMetadata(absSourcePath); const moduleMetadata = this.staticReflector.getModuleMetadata(absSourcePath);
@ -71,6 +86,18 @@ export class CodeGenerator {
} }
return result; return result;
} }
}
export class CodeGenerator {
private moduleCollector: CodeGeneratorModuleCollector;
constructor(
private options: AngularCompilerOptions, private program: ts.Program,
public host: ts.CompilerHost, private staticReflector: StaticReflector,
private compiler: compiler.OfflineCompiler, private reflectorHost: StaticReflectorHost) {
this.moduleCollector =
new CodeGeneratorModuleCollector(staticReflector, reflectorHost, program, options);
}
// 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 {
@ -95,18 +122,7 @@ export class CodeGenerator {
} }
codegen(): Promise<any> { codegen(): Promise<any> {
// Compare with false since the default should be true const {fileMetas, ngModules} = this.moduleCollector.getModuleSymbols(this.program);
const skipFileNames = (this.options.generateCodeForLibraries === false) ?
GENERATED_OR_DTS_FILES :
GENERATED_FILES;
let filePaths = this.program.getSourceFiles()
.filter(sf => !skipFileNames.test(sf.fileName))
.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); const analyzedNgModules = this.compiler.analyzeModules(ngModules);
return Promise.all(fileMetas.map( return Promise.all(fileMetas.map(
(fileMeta) => (fileMeta) =>
@ -126,7 +142,7 @@ export class CodeGenerator {
static create( static create(
options: AngularCompilerOptions, cliOptions: NgcCliOptions, program: ts.Program, options: AngularCompilerOptions, cliOptions: NgcCliOptions, program: ts.Program,
compilerHost: ts.CompilerHost, reflectorHostContext?: ReflectorHostContext, compilerHost: ts.CompilerHost, reflectorHostContext?: ReflectorHostContext,
resourceLoader?: compiler.ResourceLoader): CodeGenerator { resourceLoader?: compiler.ResourceLoader, reflectorHost?: ReflectorHost): CodeGenerator {
resourceLoader = resourceLoader || { resourceLoader = resourceLoader || {
get: (s: string) => { get: (s: string) => {
if (!compilerHost.fileExists(s)) { if (!compilerHost.fileExists(s)) {
@ -148,10 +164,12 @@ export class CodeGenerator {
} }
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver(); const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
const usePathMapping = !!options.rootDirs && options.rootDirs.length > 0; if (!reflectorHost) {
const reflectorHost = usePathMapping ? const usePathMapping = !!options.rootDirs && options.rootDirs.length > 0;
new PathMappedReflectorHost(program, compilerHost, options, reflectorHostContext) : reflectorHost = usePathMapping ?
new ReflectorHost(program, compilerHost, options, reflectorHostContext); new PathMappedReflectorHost(program, compilerHost, options, reflectorHostContext) :
new ReflectorHost(program, compilerHost, options, reflectorHostContext);
}
const staticReflector = new StaticReflector(reflectorHost); const staticReflector = new StaticReflector(reflectorHost);
StaticAndDynamicReflectionCapabilities.install(staticReflector); StaticAndDynamicReflectionCapabilities.install(staticReflector);
const htmlParser = const htmlParser =
@ -183,7 +201,7 @@ export class CodeGenerator {
} }
} }
interface FileMetadata { export interface FileMetadata {
fileUrl: string; fileUrl: string;
components: StaticSymbol[]; components: StaticSymbol[];
ngModules: StaticSymbol[]; ngModules: StaticSymbol[];

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Attribute, Component, ContentChild, ContentChildren, Directive, Host, HostBinding, HostListener, Inject, Injectable, Input, NgModule, Optional, Output, Pipe, Query, Self, SkipSelf, ViewChild, ViewChildren, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core'; import {Attribute, Component, ContentChild, ContentChildren, Directive, Host, HostBinding, HostListener, Inject, Injectable, Input, NgModule, Optional, Output, Pipe, Self, SkipSelf, ViewChild, ViewChildren, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
import {ReflectorReader} from './private_import_core'; import {ReflectorReader} from './private_import_core';
@ -44,6 +44,8 @@ export interface StaticReflectorHost {
animationMetadata: string, animationMetadata: string,
provider: string provider: string
}; };
getCanonicalFileName(fileName: string): string;
} }
/** /**
@ -366,6 +368,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;

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {beforeEach, ddescribe, describe, expect, iit, it} from '@angular/core/testing/testing_internal'; import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
import * as ts from 'typescript'; import * as ts from 'typescript';
import {ReflectorHost} from '../src/reflector_host'; import {ReflectorHost} from '../src/reflector_host';

View File

@ -9,7 +9,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 {ListWrapper} from '@angular/facade/src/collection';
import {isBlank} from '@angular/facade/src/lang';
import {MetadataCollector} from '@angular/tsc-wrapped'; import {MetadataCollector} from '@angular/tsc-wrapped';
import * as ts from 'typescript'; import * as ts from 'typescript';
@ -120,6 +119,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]);
}); });
@ -451,10 +455,13 @@ 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);
if (isBlank(result)) { if (!result) {
result = new StaticSymbol(declarationFile, name, members); result = new StaticSymbol(declarationFile, name, members);
this.staticTypeCache.set(cacheKey, result); this.staticTypeCache.set(cacheKey, result);
} }

View File

@ -1,3 +1,10 @@
/**
* @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
*/
export default { export default {
entry: '../../../dist/packages-dist/compiler/testing/index.js', entry: '../../../dist/packages-dist/compiler/testing/index.js',
@ -11,4 +18,4 @@ export default {
'rxjs/Observable': 'Rx', 'rxjs/Observable': 'Rx',
'rxjs/Subject': 'Rx' 'rxjs/Subject': 'Rx'
} }
} };

View File

@ -1,3 +1,10 @@
/**
* @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
*/
export default { export default {
entry: '../../../dist/packages-dist/compiler/index.js', entry: '../../../dist/packages-dist/compiler/index.js',
@ -7,9 +14,9 @@ export default {
globals: { globals: {
'@angular/core': 'ng.core', '@angular/core': 'ng.core',
'rxjs/Observable': 'Rx', 'rxjs/Observable': 'Rx',
'rxjs/Subject': 'Rx' 'rxjs/Subject': 'Rx',
}, },
plugins: [ plugins: [
// nodeResolve({ jsnext: true, main: true }), // nodeResolve({ jsnext: true, main: true }),
] ]
} };

View File

@ -6,75 +6,26 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {CompileDirectiveMetadata} from '../compile_metadata';
import {StringMapWrapper} from '../facade/collection'; import {isPresent} from '../facade/lang';
import {isBlank, isPresent} from '../facade/lang';
import {Identifiers, resolveIdentifier} from '../identifiers'; import {Identifiers, resolveIdentifier} from '../identifiers';
import * as o from '../output/output_ast'; import * as o from '../output/output_ast';
import {ANY_STATE, AnimationOutput, DEFAULT_STATE, EMPTY_STATE} from '../private_import_core'; import {ANY_STATE, DEFAULT_STATE, EMPTY_STATE} from '../private_import_core';
import * as t from '../template_parser/template_ast';
import {AnimationAst, AnimationAstVisitor, AnimationEntryAst, AnimationGroupAst, AnimationKeyframeAst, AnimationSequenceAst, AnimationStateAst, AnimationStateDeclarationAst, AnimationStateTransitionAst, AnimationStepAst, AnimationStylesAst} from './animation_ast'; import {AnimationAst, AnimationAstVisitor, AnimationEntryAst, AnimationGroupAst, AnimationKeyframeAst, AnimationSequenceAst, AnimationStateDeclarationAst, AnimationStateTransitionAst, AnimationStepAst, AnimationStylesAst} from './animation_ast';
import {AnimationParseError, ParsedAnimationResult, parseAnimationEntry, parseAnimationOutputName} from './animation_parser';
const animationCompilationCache = export class AnimationEntryCompileResult {
new Map<CompileDirectiveMetadata, CompiledAnimationTriggerResult[]>(); constructor(public name: string, public statements: o.Statement[], public fnExp: o.Expression) {}
export class CompiledAnimationTriggerResult {
constructor(
public name: string, public statesMapStatement: o.Statement,
public statesVariableName: string, public fnStatement: o.Statement,
public fnVariable: o.Expression) {}
}
export class CompiledComponentAnimationResult {
constructor(
public outputs: AnimationOutput[], public triggers: CompiledAnimationTriggerResult[]) {}
} }
export class AnimationCompiler { export class AnimationCompiler {
compileComponent(component: CompileDirectiveMetadata, template: t.TemplateAst[]): compile(factoryNamePrefix: string, parsedAnimations: AnimationEntryAst[]):
CompiledComponentAnimationResult { AnimationEntryCompileResult[] {
var compiledAnimations: CompiledAnimationTriggerResult[] = []; return parsedAnimations.map(entry => {
var groupedErrors: string[] = []; const factoryName = `${factoryNamePrefix}_${entry.name}`;
var triggerLookup: {[key: string]: CompiledAnimationTriggerResult} = {}; const visitor = new _AnimationBuilder(entry.name, factoryName);
var componentName = component.type.name; return visitor.build(entry);
component.template.animations.forEach(entry => {
var result = parseAnimationEntry(entry);
var triggerName = entry.name;
if (result.errors.length > 0) {
var errorMessage =
`Unable to parse the animation sequence for "${triggerName}" due to the following errors:`;
result.errors.forEach(
(error: AnimationParseError) => { errorMessage += '\n-- ' + error.msg; });
groupedErrors.push(errorMessage);
}
if (triggerLookup[triggerName]) {
groupedErrors.push(
`The animation trigger "${triggerName}" has already been registered on "${componentName}"`);
} else {
var factoryName = `${componentName}_${entry.name}`;
var visitor = new _AnimationBuilder(triggerName, factoryName);
var compileResult = visitor.build(result.ast);
compiledAnimations.push(compileResult);
triggerLookup[entry.name] = compileResult;
}
}); });
var validatedProperties = _validateAnimationProperties(compiledAnimations, template);
validatedProperties.errors.forEach(error => { groupedErrors.push(error.msg); });
if (groupedErrors.length > 0) {
var errorMessageStr =
`Animation parsing for ${component.type.name} has failed due to the following errors:`;
groupedErrors.forEach(error => errorMessageStr += `\n- ${error}`);
throw new Error(errorMessageStr);
}
animationCompilationCache.set(component, compiledAnimations);
return new CompiledComponentAnimationResult(validatedProperties.outputs, compiledAnimations);
} }
} }
@ -110,8 +61,9 @@ class _AnimationBuilder implements AnimationAstVisitor {
} }
ast.styles.forEach(entry => { ast.styles.forEach(entry => {
stylesArr.push( const entries =
o.literalMap(StringMapWrapper.keys(entry).map(key => [key, o.literal(entry[key])]))); 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([
@ -182,9 +134,8 @@ class _AnimationBuilder implements AnimationAstVisitor {
visitAnimationStateDeclaration( visitAnimationStateDeclaration(
ast: AnimationStateDeclarationAst, context: _AnimationBuilderContext): void { ast: AnimationStateDeclarationAst, context: _AnimationBuilderContext): void {
var flatStyles: {[key: string]: string | number} = {}; var flatStyles: {[key: string]: string | number} = {};
_getStylesArray(ast).forEach(entry => { _getStylesArray(ast).forEach(
StringMapWrapper.forEach(entry, (value: string, key: string) => { flatStyles[key] = value; }); entry => { Object.keys(entry).forEach(key => { flatStyles[key] = entry[key]; }); });
});
context.stateMap.registerState(ast.stateName, flatStyles); context.stateMap.registerState(ast.stateName, flatStyles);
} }
@ -334,28 +285,27 @@ class _AnimationBuilder implements AnimationAstVisitor {
statements); statements);
} }
build(ast: AnimationAst): CompiledAnimationTriggerResult { build(ast: AnimationAst): AnimationEntryCompileResult {
var context = new _AnimationBuilderContext(); var context = new _AnimationBuilderContext();
var fnStatement = ast.visit(this, context).toDeclStmt(this._fnVarName); var fnStatement = ast.visit(this, context).toDeclStmt(this._fnVarName);
var fnVariable = o.variable(this._fnVarName); var fnVariable = o.variable(this._fnVarName);
var lookupMap: any[] = []; var lookupMap: any[] = [];
StringMapWrapper.forEach( Object.keys(context.stateMap.states).forEach(stateName => {
context.stateMap.states, (value: {[key: string]: string}, stateName: string) => { const value = context.stateMap.states[stateName];
var variableValue = EMPTY_MAP; var variableValue = EMPTY_MAP;
if (isPresent(value)) { if (isPresent(value)) {
let styleMap: any[] = []; let styleMap: any[] = [];
StringMapWrapper.forEach(value, (value: string, key: string) => { Object.keys(value).forEach(key => { styleMap.push([key, o.literal(value[key])]); });
styleMap.push([key, o.literal(value)]); variableValue = o.literalMap(styleMap);
}); }
variableValue = o.literalMap(styleMap); lookupMap.push([stateName, variableValue]);
} });
lookupMap.push([stateName, variableValue]);
});
var compiledStatesMapExpr = this._statesMapVar.set(o.literalMap(lookupMap)).toDeclStmt(); const compiledStatesMapStmt = this._statesMapVar.set(o.literalMap(lookupMap)).toDeclStmt();
return new CompiledAnimationTriggerResult( const statements: o.Statement[] = [compiledStatesMapStmt, fnStatement];
this.animationName, compiledStatesMapExpr, this._statesMapVarName, fnStatement, fnVariable);
return new AnimationEntryCompileResult(this.animationName, statements, fnVariable);
} }
} }
@ -371,7 +321,7 @@ class _AnimationBuilderStateMap {
get states() { return this._states; } get states() { return this._states; }
registerState(name: string, value: {[prop: string]: string | number} = null): void { registerState(name: string, value: {[prop: string]: string | number} = null): void {
var existingEntry = this._states[name]; var existingEntry = this._states[name];
if (isBlank(existingEntry)) { if (!existingEntry) {
this._states[name] = value; this._states[name] = value;
} }
} }
@ -397,7 +347,7 @@ function _isEndStateAnimateStep(step: AnimationAst): boolean {
if (step instanceof AnimationStepAst && step.duration > 0 && step.keyframes.length == 2) { if (step instanceof AnimationStepAst && step.duration > 0 && step.keyframes.length == 2) {
var styles1 = _getStylesArray(step.keyframes[0])[0]; var styles1 = _getStylesArray(step.keyframes[0])[0];
var styles2 = _getStylesArray(step.keyframes[1])[0]; var styles2 = _getStylesArray(step.keyframes[1])[0];
return StringMapWrapper.isEmpty(styles1) && StringMapWrapper.isEmpty(styles2); return Object.keys(styles1).length === 0 && Object.keys(styles2).length === 0;
} }
return false; return false;
} }
@ -405,99 +355,3 @@ function _isEndStateAnimateStep(step: AnimationAst): boolean {
function _getStylesArray(obj: any): {[key: string]: any}[] { function _getStylesArray(obj: any): {[key: string]: any}[] {
return obj.styles.styles; return obj.styles.styles;
} }
function _validateAnimationProperties(
compiledAnimations: CompiledAnimationTriggerResult[],
template: t.TemplateAst[]): AnimationPropertyValidationOutput {
var visitor = new _AnimationTemplatePropertyVisitor(compiledAnimations);
t.templateVisitAll(visitor, template);
return new AnimationPropertyValidationOutput(visitor.outputs, visitor.errors);
}
export class AnimationPropertyValidationOutput {
constructor(public outputs: AnimationOutput[], public errors: AnimationParseError[]) {}
}
class _AnimationTemplatePropertyVisitor implements t.TemplateAstVisitor {
private _animationRegistry: {[key: string]: boolean};
public errors: AnimationParseError[] = [];
public outputs: AnimationOutput[] = [];
constructor(animations: CompiledAnimationTriggerResult[]) {
this._animationRegistry = this._buildCompileAnimationLookup(animations);
}
private _buildCompileAnimationLookup(animations: CompiledAnimationTriggerResult[]):
{[key: string]: boolean} {
var map: {[key: string]: boolean} = {};
animations.forEach(entry => { map[entry.name] = true; });
return map;
}
private _validateAnimationInputOutputPairs(
inputAsts: t.BoundElementPropertyAst[], outputAsts: t.BoundEventAst[],
animationRegistry: {[key: string]: any}, isHostLevel: boolean): void {
var detectedAnimationInputs: {[key: string]: boolean} = {};
inputAsts.forEach(input => {
if (input.type == t.PropertyBindingType.Animation) {
var triggerName = input.name;
if (isPresent(animationRegistry[triggerName])) {
detectedAnimationInputs[triggerName] = true;
} else {
this.errors.push(
new AnimationParseError(`Couldn't find an animation entry for ${triggerName}`));
}
}
});
outputAsts.forEach(output => {
if (output.name[0] == '@') {
var normalizedOutputData = parseAnimationOutputName(output.name.substr(1), this.errors);
let triggerName = normalizedOutputData.name;
let triggerEventPhase = normalizedOutputData.phase;
if (!animationRegistry[triggerName]) {
this.errors.push(new AnimationParseError(
`Couldn't find the corresponding ${isHostLevel ? 'host-level ' : '' }animation trigger definition for (@${triggerName})`));
} else if (!detectedAnimationInputs[triggerName]) {
this.errors.push(new AnimationParseError(
`Unable to listen on (@${triggerName}.${triggerEventPhase}) because the animation trigger [@${triggerName}] isn't being used on the same element`));
} else {
this.outputs.push(normalizedOutputData);
}
}
});
}
visitElement(ast: t.ElementAst, ctx: any): any {
this._validateAnimationInputOutputPairs(
ast.inputs, ast.outputs, this._animationRegistry, false);
var componentOnElement: t.DirectiveAst =
ast.directives.find(directive => directive.directive.isComponent);
if (componentOnElement) {
let cachedComponentAnimations = animationCompilationCache.get(componentOnElement.directive);
if (cachedComponentAnimations) {
this._validateAnimationInputOutputPairs(
componentOnElement.hostProperties, componentOnElement.hostEvents,
this._buildCompileAnimationLookup(cachedComponentAnimations), true);
}
}
t.templateVisitAll(this, ast.children);
}
visitEmbeddedTemplate(ast: t.EmbeddedTemplateAst, ctx: any): any {
t.templateVisitAll(this, ast.children);
}
visitEvent(ast: t.BoundEventAst, ctx: any): any {}
visitBoundText(ast: t.BoundTextAst, ctx: any): any {}
visitText(ast: t.TextAst, ctx: any): any {}
visitNgContent(ast: t.NgContentAst, ctx: any): any {}
visitAttr(ast: t.AttrAst, ctx: any): any {}
visitDirective(ast: t.DirectiveAst, ctx: any): any {}
visitReference(ast: t.ReferenceAst, ctx: any): any {}
visitVariable(ast: t.VariableAst, ctx: any): any {}
visitDirectiveProperty(ast: t.BoundDirectivePropertyAst, ctx: any): any {}
visitElementProperty(ast: t.BoundElementPropertyAst, ctx: any): any {}
}

View File

@ -6,13 +6,13 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {CompileAnimationAnimateMetadata, CompileAnimationEntryMetadata, CompileAnimationGroupMetadata, CompileAnimationKeyframesSequenceMetadata, CompileAnimationMetadata, CompileAnimationSequenceMetadata, CompileAnimationStateDeclarationMetadata, CompileAnimationStateTransitionMetadata, CompileAnimationStyleMetadata, CompileAnimationWithStepsMetadata} 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 {ListWrapper, StringMapWrapper} from '../facade/collection';
import {isArray, isBlank, isPresent, isString, isStringMap} from '../facade/lang'; import {isArray, isBlank, isPresent, isString, isStringMap} from '../facade/lang';
import {Math} from '../facade/math'; 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, AnimationOutput, FILL_STYLE_FLAG} from '../private_import_core';
import {AnimationAst, AnimationEntryAst, AnimationGroupAst, AnimationKeyframeAst, AnimationSequenceAst, AnimationStateDeclarationAst, AnimationStateTransitionAst, AnimationStateTransitionExpression, AnimationStepAst, AnimationStylesAst, AnimationWithStepsAst} from './animation_ast'; import {AnimationAst, AnimationEntryAst, AnimationGroupAst, AnimationKeyframeAst, AnimationSequenceAst, AnimationStateDeclarationAst, AnimationStateTransitionAst, AnimationStateTransitionExpression, AnimationStepAst, AnimationStylesAst, AnimationWithStepsAst} from './animation_ast';
import {StylesCollection} from './styles_collection'; import {StylesCollection} from './styles_collection';
@ -20,73 +20,85 @@ const _INITIAL_KEYFRAME = 0;
const _TERMINAL_KEYFRAME = 1; const _TERMINAL_KEYFRAME = 1;
const _ONE_SECOND = 1000; const _ONE_SECOND = 1000;
declare type Styles = {
[key: string]: string | number
};
export class AnimationParseError extends ParseError { export class AnimationParseError extends ParseError {
constructor(message: any /** TODO #9100 */) { super(null, message); } constructor(message: string) { super(null, message); }
toString(): string { return `${this.msg}`; } toString(): string { return `${this.msg}`; }
} }
export class ParsedAnimationResult { export class AnimationEntryParseResult {
constructor(public ast: AnimationEntryAst, public errors: AnimationParseError[]) {} constructor(public ast: AnimationEntryAst, public errors: AnimationParseError[]) {}
} }
export function parseAnimationEntry(entry: CompileAnimationEntryMetadata): ParsedAnimationResult { export class AnimationParser {
var errors: AnimationParseError[] = []; parseComponent(component: CompileDirectiveMetadata): AnimationEntryAst[] {
var stateStyles: {[key: string]: AnimationStylesAst} = {}; const errors: string[] = [];
var transitions: CompileAnimationStateTransitionMetadata[] = []; const componentName = component.type.name;
const animationTriggerNames = new Set<string>();
const asts = component.template.animations.map(entry => {
const result = this.parseEntry(entry);
const ast = result.ast;
const triggerName = ast.name;
if (animationTriggerNames.has(triggerName)) {
result.errors.push(new AnimationParseError(
`The animation trigger "${triggerName}" has already been registered for the ${componentName} component`));
} else {
animationTriggerNames.add(triggerName);
}
if (result.errors.length > 0) {
let errorMessage =
`- Unable to parse the animation sequence for "${triggerName}" on the ${componentName} component due to the following errors:`;
result.errors.forEach(
(error: AnimationParseError) => { errorMessage += '\n-- ' + error.msg; });
errors.push(errorMessage);
}
return ast;
});
var stateDeclarationAsts: any[] /** TODO #9100 */ = []; if (errors.length > 0) {
entry.definitions.forEach(def => { const errorString = errors.join('\n');
if (def instanceof CompileAnimationStateDeclarationMetadata) { throw new Error(`Animation parse errors:\n${errorString}`);
_parseAnimationDeclarationStates(def, errors).forEach(ast => {
stateDeclarationAsts.push(ast);
stateStyles[ast.stateName] = ast.styles;
});
} else {
transitions.push(<CompileAnimationStateTransitionMetadata>def);
} }
});
var stateTransitionAsts = return asts;
transitions.map(transDef => _parseAnimationStateTransition(transDef, stateStyles, errors)); }
var ast = new AnimationEntryAst(entry.name, stateDeclarationAsts, stateTransitionAsts); parseEntry(entry: CompileAnimationEntryMetadata): AnimationEntryParseResult {
return new ParsedAnimationResult(ast, errors); var errors: AnimationParseError[] = [];
} var stateStyles: {[key: string]: AnimationStylesAst} = {};
var transitions: CompileAnimationStateTransitionMetadata[] = [];
export function parseAnimationOutputName(
outputName: string, errors: AnimationParseError[]): AnimationOutput { var stateDeclarationAsts: AnimationStateDeclarationAst[] = [];
var values = outputName.split('.'); entry.definitions.forEach(def => {
var name: string; if (def instanceof CompileAnimationStateDeclarationMetadata) {
var phase: string = ''; _parseAnimationDeclarationStates(def, errors).forEach(ast => {
if (values.length > 1) { stateDeclarationAsts.push(ast);
name = values[0]; stateStyles[ast.stateName] = ast.styles;
let parsedPhase = values[1]; });
switch (parsedPhase) { } else {
case 'start': transitions.push(<CompileAnimationStateTransitionMetadata>def);
case 'done': }
phase = parsedPhase; });
break;
var stateTransitionAsts =
default: transitions.map(transDef => _parseAnimationStateTransition(transDef, stateStyles, errors));
errors.push(new AnimationParseError(
`The provided animation output phase value "${parsedPhase}" for "@${name}" is not supported (use start or done)`)); var ast = new AnimationEntryAst(entry.name, stateDeclarationAsts, stateTransitionAsts);
} return new AnimationEntryParseResult(ast, errors);
} else {
name = outputName;
errors.push(new AnimationParseError(
`The animation trigger output event (@${name}) is missing its phase value name (start or done are currently supported)`));
} }
return new AnimationOutput(name, phase, outputName);
} }
function _parseAnimationDeclarationStates( function _parseAnimationDeclarationStates(
stateMetadata: CompileAnimationStateDeclarationMetadata, stateMetadata: CompileAnimationStateDeclarationMetadata,
errors: AnimationParseError[]): AnimationStateDeclarationAst[] { errors: AnimationParseError[]): AnimationStateDeclarationAst[] {
var styleValues: {[key: string]: string | number}[] = []; 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 (isStringMap(stylesEntry)) {
styleValues.push(<{[key: string]: string | number}>stylesEntry); styleValues.push(stylesEntry as Styles);
} else { } else {
errors.push(new AnimationParseError( errors.push(new AnimationParseError(
`State based animations cannot contain references to other states`)); `State based animations cannot contain references to other states`));
@ -103,13 +115,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);
@ -124,9 +133,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`));
@ -145,16 +170,6 @@ function _parseAnimationTransitionExpr(
return expressions; return expressions;
} }
function _fetchSylesFromState(stateName: string, stateStyles: {[key: string]: AnimationStylesAst}):
CompileAnimationStyleMetadata {
var entry = stateStyles[stateName];
if (isPresent(entry)) {
var styles = <{[key: string]: string | number}[]>entry.styles;
return new CompileAnimationStyleMetadata(0, styles);
}
return null;
}
function _normalizeAnimationEntry(entry: CompileAnimationMetadata | CompileAnimationMetadata[]): function _normalizeAnimationEntry(entry: CompileAnimationMetadata | CompileAnimationMetadata[]):
CompileAnimationMetadata { CompileAnimationMetadata {
return isArray(entry) ? new CompileAnimationSequenceMetadata(<CompileAnimationMetadata[]>entry) : return isArray(entry) ? new CompileAnimationSequenceMetadata(<CompileAnimationMetadata[]>entry) :
@ -163,8 +178,8 @@ function _normalizeAnimationEntry(entry: CompileAnimationMetadata | CompileAnima
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 (isString(styleEntry)) {
ListWrapper.addAll( ListWrapper.addAll(
@ -210,7 +225,7 @@ function _normalizeStyleStepEntry(
} }
var newSteps: CompileAnimationMetadata[] = []; var newSteps: CompileAnimationMetadata[] = [];
var combinedStyles: {[key: string]: string | number}[]; var combinedStyles: Styles[];
steps.forEach(step => { steps.forEach(step => {
if (step instanceof CompileAnimationStyleMetadata) { if (step instanceof CompileAnimationStyleMetadata) {
// this occurs when a style step is followed by a previous style step // this occurs when a style step is followed by a previous style step
@ -266,7 +281,7 @@ function _normalizeStyleStepEntry(
function _resolveStylesFromState( function _resolveStylesFromState(
stateName: string, stateStyles: {[key: string]: AnimationStylesAst}, stateName: string, stateStyles: {[key: string]: AnimationStylesAst},
errors: AnimationParseError[]) { errors: AnimationParseError[]) {
var styles: {[key: string]: string | number}[] = []; var styles: Styles[] = [];
if (stateName[0] != ':') { if (stateName[0] != ':') {
errors.push(new AnimationParseError(`Animation states via styles must be prefixed with a ":"`)); errors.push(new AnimationParseError(`Animation states via styles must be prefixed with a ":"`));
} else { } else {
@ -278,7 +293,7 @@ function _resolveStylesFromState(
} else { } else {
value.styles.forEach(stylesEntry => { value.styles.forEach(stylesEntry => {
if (isStringMap(stylesEntry)) { if (isStringMap(stylesEntry)) {
styles.push(<{[key: string]: string | number}>stylesEntry); styles.push(stylesEntry as Styles);
} }
}); });
} }
@ -312,15 +327,13 @@ function _parseAnimationKeyframes(
var lastOffset = 0; var lastOffset = 0;
keyframeSequence.steps.forEach(styleMetadata => { keyframeSequence.steps.forEach(styleMetadata => {
var offset = styleMetadata.offset; var offset = styleMetadata.offset;
var keyframeStyles: {[key: string]: string | number} = {}; var keyframeStyles: Styles = {};
styleMetadata.styles.forEach(entry => { styleMetadata.styles.forEach(entry => {
StringMapWrapper.forEach( Object.keys(entry).forEach(prop => {
<{[key: string]: string | number}>entry, if (prop != 'offset') {
(value: any /** TODO #9100 */, prop: any /** TODO #9100 */) => { keyframeStyles[prop] = (entry as Styles)[prop];
if (prop != 'offset') { }
keyframeStyles[prop] = value; });
}
});
}); });
if (isPresent(offset)) { if (isPresent(offset)) {
@ -338,7 +351,6 @@ function _parseAnimationKeyframes(
ListWrapper.sort(rawKeyframes, (a, b) => a[0] <= b[0] ? -1 : 1); ListWrapper.sort(rawKeyframes, (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, {}]); ListWrapper.insert(rawKeyframes, 0, firstKeyframe = [_INITIAL_KEYFRAME, {}]);
@ -353,28 +365,26 @@ 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];
StringMapWrapper.forEach( Object.keys(styles).forEach(prop => {
styles, (value: any /** TODO #9100 */, prop: any /** TODO #9100 */) => { if (!isPresent(firstKeyframeStyles[prop])) {
if (!isPresent(firstKeyframeStyles[prop])) { firstKeyframeStyles[prop] = FILL_STYLE_FLAG;
firstKeyframeStyles[prop] = FILL_STYLE_FLAG; }
} });
});
} }
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];
StringMapWrapper.forEach( Object.keys(styles).forEach(prop => {
styles, (value: any /** TODO #9100 */, prop: any /** TODO #9100 */) => { if (!isPresent(lastKeyframeStyles[prop])) {
if (!isPresent(lastKeyframeStyles[prop])) { lastKeyframeStyles[prop] = styles[prop];
lastKeyframeStyles[prop] = value; }
} });
});
} }
return rawKeyframes.map( return rawKeyframes.map(
@ -398,11 +408,9 @@ function _parseTransitionAnimation(
if (entry instanceof CompileAnimationStyleMetadata) { if (entry instanceof CompileAnimationStyleMetadata) {
entry.styles.forEach(stylesEntry => { entry.styles.forEach(stylesEntry => {
// by this point we know that we only have stringmap values // by this point we know that we only have stringmap values
var map = <{[key: string]: string | number}>stylesEntry; var map = stylesEntry as Styles;
StringMapWrapper.forEach( Object.keys(map).forEach(
map, (value: any /** TODO #9100 */, prop: any /** TODO #9100 */) => { prop => { collectedStyles.insertAtTime(prop, time, map[prop]); });
collectedStyles.insertAtTime(prop, time, value);
});
}); });
previousStyles = entry.styles; previousStyles = entry.styles;
return; return;
@ -448,7 +456,7 @@ function _parseTransitionAnimation(
} else { } else {
let styleData = <CompileAnimationStyleMetadata>styles; let styleData = <CompileAnimationStyleMetadata>styles;
let offset = _TERMINAL_KEYFRAME; let offset = _TERMINAL_KEYFRAME;
let styleAst = new AnimationStylesAst(<{[key: string]: string | number}[]>styleData.styles); let styleAst = new AnimationStylesAst(styleData.styles as Styles[]);
var keyframe = new AnimationKeyframeAst(offset, styleAst); var keyframe = new AnimationKeyframeAst(offset, styleAst);
keyframes = [keyframe]; keyframes = [keyframe];
} }
@ -460,9 +468,8 @@ function _parseTransitionAnimation(
keyframes.forEach( keyframes.forEach(
(keyframe: any /** TODO #9100 */) => keyframe.styles.styles.forEach( (keyframe: any /** TODO #9100 */) => keyframe.styles.styles.forEach(
(entry: any /** TODO #9100 */) => StringMapWrapper.forEach( (entry: any /** TODO #9100 */) => Object.keys(entry).forEach(
entry, (value: any /** TODO #9100 */, prop: any /** TODO #9100 */) => prop => { collectedStyles.insertAtTime(prop, currentTime, entry[prop]); })));
collectedStyles.insertAtTime(prop, currentTime, value))));
} else { } else {
// if the code reaches this stage then an error // if the code reaches this stage then an error
// has already been populated within the _normalizeStyleSteps() // has already been populated within the _normalizeStyleSteps()
@ -535,10 +542,11 @@ function _parseTimeExpression(
function _createStartKeyframeFromEndKeyframe( function _createStartKeyframeFromEndKeyframe(
endKeyframe: AnimationKeyframeAst, startTime: number, duration: number, endKeyframe: AnimationKeyframeAst, startTime: number, duration: number,
collectedStyles: StylesCollection, errors: AnimationParseError[]): AnimationKeyframeAst { collectedStyles: StylesCollection, errors: AnimationParseError[]): AnimationKeyframeAst {
var values: {[key: string]: string | number} = {}; var values: Styles = {};
var endTime = startTime + duration; var endTime = startTime + duration;
endKeyframe.styles.styles.forEach((styleData: {[key: string]: string | number}) => { endKeyframe.styles.styles.forEach((styleData: Styles) => {
StringMapWrapper.forEach(styleData, (val: any /** TODO #9100 */, prop: any /** TODO #9100 */) => { Object.keys(styleData).forEach(prop => {
const val = styleData[prop];
if (prop == 'offset') return; if (prop == 'offset') return;
var resultIndex = collectedStyles.indexOfAtOrBeforeTime(prop, startTime); var resultIndex = collectedStyles.indexOfAtOrBeforeTime(prop, startTime);

View File

@ -8,11 +8,10 @@
import {ChangeDetectionStrategy, SchemaMetadata, Type, ViewEncapsulation} from '@angular/core'; import {ChangeDetectionStrategy, SchemaMetadata, Type, ViewEncapsulation} from '@angular/core';
import {ListWrapper, MapWrapper, StringMapWrapper} from './facade/collection'; import {ListWrapper, MapWrapper} from './facade/collection';
import {isBlank, isPresent, isStringMap, normalizeBlank, normalizeBool} from './facade/lang'; import {isPresent, isStringMap, normalizeBlank, normalizeBool} from './facade/lang';
import {LifecycleHooks, reflector} from './private_import_core'; import {LifecycleHooks} from './private_import_core';
import {CssSelector} from './selector'; import {CssSelector} from './selector';
import {getUrlScheme} from './url_resolver';
import {sanitizeIdentifier, splitAtColon} from './util'; import {sanitizeIdentifier, splitAtColon} from './util';
function unimplemented(): any { function unimplemented(): any {
@ -305,7 +304,7 @@ export class CompileTemplateMetadata {
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 = isPresent(animations) ? ListWrapper.flatten(animations) : [];
this.ngContentSelectors = isPresent(ngContentSelectors) ? ngContentSelectors : []; this.ngContentSelectors = ngContentSelectors || [];
if (isPresent(interpolation) && interpolation.length != 2) { if (isPresent(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.`);
} }
@ -343,7 +342,8 @@ export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
var hostProperties: {[key: string]: string} = {}; var hostProperties: {[key: string]: string} = {};
var hostAttributes: {[key: string]: string} = {}; var hostAttributes: {[key: string]: string} = {};
if (isPresent(host)) { if (isPresent(host)) {
StringMapWrapper.forEach(host, (value: string, key: string) => { Object.keys(host).forEach(key => {
const value = host[key];
const matches = key.match(HOST_REG_EXP); const matches = key.match(HOST_REG_EXP);
if (matches === null) { if (matches === null) {
hostAttributes[key] = value; hostAttributes[key] = value;
@ -590,7 +590,7 @@ export function removeIdentifierDuplicates<T extends CompileMetadataWithIdentifi
} }
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 {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {COMPILER_OPTIONS, ClassProvider, Compiler, CompilerFactory, CompilerOptions, Component, ExistingProvider, FactoryProvider, Inject, Injectable, Optional, PLATFORM_INITIALIZER, PlatformRef, Provider, ReflectiveInjector, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, TypeProvider, ValueProvider, 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 * from './template_parser/template_ast';
export {TEMPLATE_TRANSFORMS} from './template_parser/template_parser'; export {TEMPLATE_TRANSFORMS} from './template_parser/template_parser';

View File

@ -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, resolveEnumToken} 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 {
@ -223,8 +223,8 @@ export class CssScanner {
var error: CssScannerError = null; var error: CssScannerError = null;
if (!isMatchingType || (isPresent(value) && value != next.strValue)) { if (!isMatchingType || (isPresent(value) && value != next.strValue)) {
var errorMessage = resolveEnumToken(CssTokenType, next.type) + ' does not match expected ' + var errorMessage =
resolveEnumToken(CssTokenType, type) + ' value'; CssTokenType[next.type] + ' does not match expected ' + CssTokenType[type] + ' value';
if (isPresent(value)) { if (isPresent(value)) {
errorMessage += ' ("' + next.strValue + '" should match "' + value + '")'; errorMessage += ' ("' + next.strValue + '" should match "' + value + '")';
@ -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 {

View File

@ -115,27 +115,27 @@ export class DirectiveNormalizer {
const templateStyles = this.normalizeStylesheet(new CompileStylesheetMetadata( const templateStyles = this.normalizeStylesheet(new CompileStylesheetMetadata(
{styles: visitor.styles, styleUrls: visitor.styleUrls, moduleUrl: templateAbsUrl})); {styles: visitor.styles, styleUrls: visitor.styleUrls, moduleUrl: templateAbsUrl}));
const allStyles = templateMetadataStyles.styles.concat(templateStyles.styles);
const allStyleUrls = templateMetadataStyles.styleUrls.concat(templateStyles.styleUrls);
let encapsulation = templateMeta.encapsulation; let encapsulation = templateMeta.encapsulation;
if (isBlank(encapsulation)) { if (isBlank(encapsulation)) {
encapsulation = this._config.defaultEncapsulation; encapsulation = this._config.defaultEncapsulation;
} }
if (encapsulation === ViewEncapsulation.Emulated && allStyles.length === 0 &&
allStyleUrls.length === 0) { const styles = templateMetadataStyles.styles.concat(templateStyles.styles);
const styleUrls = templateMetadataStyles.styleUrls.concat(templateStyles.styleUrls);
if (encapsulation === ViewEncapsulation.Emulated && styles.length === 0 &&
styleUrls.length === 0) {
encapsulation = ViewEncapsulation.None; encapsulation = ViewEncapsulation.None;
} }
return new CompileTemplateMetadata({ return new CompileTemplateMetadata({
encapsulation, encapsulation,
template: template, template,
templateUrl: templateAbsUrl, templateUrl: templateAbsUrl, styles, styleUrls,
styles: allStyles,
styleUrls: allStyleUrls,
externalStylesheets: templateMeta.externalStylesheets, externalStylesheets: templateMeta.externalStylesheets,
ngContentSelectors: visitor.ngContentSelectors, ngContentSelectors: visitor.ngContentSelectors,
animations: templateMeta.animations, animations: templateMeta.animations,
interpolation: templateMeta.interpolation interpolation: templateMeta.interpolation,
}); });
} }
@ -251,7 +251,6 @@ function _cloneDirectiveWithTemplate(
viewProviders: directive.viewProviders, viewProviders: directive.viewProviders,
queries: directive.queries, queries: directive.queries,
viewQueries: directive.viewQueries, viewQueries: directive.viewQueries,
entryComponents: directive.entryComponents, entryComponents: directive.entryComponents, template,
template: template
}); });
} }

View File

@ -9,14 +9,10 @@
import {Component, Directive, HostBinding, HostListener, Injectable, Input, Output, Query, Type, resolveForwardRef} from '@angular/core'; import {Component, Directive, HostBinding, HostListener, Injectable, Input, Output, Query, Type, resolveForwardRef} from '@angular/core';
import {StringMapWrapper} from './facade/collection'; import {StringMapWrapper} from './facade/collection';
import {isPresent, stringify} from './facade/lang'; import {stringify} from './facade/lang';
import {ReflectorReader, reflector} from './private_import_core'; import {ReflectorReader, reflector} from './private_import_core';
import {splitAtColon} from './util'; import {splitAtColon} from './util';
function _isDirectiveMetadata(type: any): type is Directive {
return type instanceof Directive;
}
/* /*
* Resolve a `Type` for {@link Directive}. * Resolve a `Type` for {@link Directive}.
* *
@ -32,54 +28,64 @@ export class DirectiveResolver {
* Return {@link Directive} for a given `Type`. * Return {@link Directive} for a given `Type`.
*/ */
resolve(type: Type<any>, throwIfNotFound = true): Directive { resolve(type: Type<any>, throwIfNotFound = true): Directive {
var typeMetadata = this._reflector.annotations(resolveForwardRef(type)); const typeMetadata = this._reflector.annotations(resolveForwardRef(type));
if (isPresent(typeMetadata)) { if (typeMetadata) {
var metadata = typeMetadata.find(_isDirectiveMetadata); const metadata = typeMetadata.find(isDirectiveMetadata);
if (isPresent(metadata)) { if (metadata) {
var propertyMetadata = this._reflector.propMetadata(type); const propertyMetadata = this._reflector.propMetadata(type);
return this._mergeWithPropertyMetadata(metadata, propertyMetadata, type); return this._mergeWithPropertyMetadata(metadata, propertyMetadata, type);
} }
} }
if (throwIfNotFound) { if (throwIfNotFound) {
throw new Error(`No Directive annotation found on ${stringify(type)}`); throw new Error(`No Directive annotation found on ${stringify(type)}`);
} }
return null; return null;
} }
private _mergeWithPropertyMetadata( private _mergeWithPropertyMetadata(
dm: Directive, propertyMetadata: {[key: string]: any[]}, dm: Directive, propertyMetadata: {[key: string]: any[]},
directiveType: Type<any>): Directive { directiveType: Type<any>): Directive {
var inputs: string[] = []; const inputs: string[] = [];
var outputs: string[] = []; const outputs: string[] = [];
var host: {[key: string]: string} = {}; const host: {[key: string]: string} = {};
var queries: {[key: string]: any} = {}; const queries: {[key: string]: any} = {};
StringMapWrapper.forEach(propertyMetadata, (metadata: any[], propName: string) => { Object.keys(propertyMetadata).forEach((propName: string) => {
metadata.forEach(a => {
propertyMetadata[propName].forEach(a => {
if (a instanceof Input) { if (a instanceof Input) {
if (isPresent(a.bindingPropertyName)) { if (a.bindingPropertyName) {
inputs.push(`${propName}: ${a.bindingPropertyName}`); inputs.push(`${propName}: ${a.bindingPropertyName}`);
} else { } else {
inputs.push(propName); inputs.push(propName);
} }
} else if (a instanceof Output) { } else if (a instanceof Output) {
const output: Output = a; const output: Output = a;
if (isPresent(output.bindingPropertyName)) { if (output.bindingPropertyName) {
outputs.push(`${propName}: ${output.bindingPropertyName}`); outputs.push(`${propName}: ${output.bindingPropertyName}`);
} else { } else {
outputs.push(propName); outputs.push(propName);
} }
} else if (a instanceof HostBinding) { } else if (a instanceof HostBinding) {
const hostBinding: HostBinding = a; const hostBinding: HostBinding = a;
if (isPresent(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;
} }
} else if (a instanceof HostListener) { } else if (a instanceof HostListener) {
const hostListener: HostListener = a; const hostListener: HostListener = a;
var args = isPresent(hostListener.args) ? (<any[]>hostListener.args).join(', ') : ''; const args = hostListener.args || [];
host[`(${hostListener.eventName})`] = `${propName}(${args})`; host[`(${hostListener.eventName})`] = `${propName}(${args.join(',')})`;
} else if (a instanceof Query) { } else if (a instanceof Query) {
queries[propName] = a; queries[propName] = a;
} }
@ -91,13 +97,14 @@ export class DirectiveResolver {
private _extractPublicName(def: string) { return splitAtColon(def, [null, def])[1].trim(); } private _extractPublicName(def: string) { return splitAtColon(def, [null, def])[1].trim(); }
private _merge( private _merge(
dm: Directive, inputs: string[], outputs: string[], host: {[key: string]: string}, directive: Directive, inputs: string[], outputs: string[], host: {[key: string]: string},
queries: {[key: string]: any}, directiveType: Type<any>): Directive { queries: {[key: string]: any}, directiveType: Type<any>): Directive {
let mergedInputs: string[]; const mergedInputs: string[] = inputs;
if (isPresent(dm.inputs)) { if (directive.inputs) {
const inputNames: string[] = const inputNames: string[] =
dm.inputs.map((def: string): string => this._extractPublicName(def)); directive.inputs.map((def: string): string => this._extractPublicName(def));
inputs.forEach((inputDef: string) => { inputs.forEach((inputDef: string) => {
const publicName = this._extractPublicName(inputDef); const publicName = this._extractPublicName(inputDef);
if (inputNames.indexOf(publicName) > -1) { if (inputNames.indexOf(publicName) > -1) {
@ -105,16 +112,15 @@ export class DirectiveResolver {
`Input '${publicName}' defined multiple times in '${stringify(directiveType)}'`); `Input '${publicName}' defined multiple times in '${stringify(directiveType)}'`);
} }
}); });
mergedInputs = dm.inputs.concat(inputs);
} else { mergedInputs.unshift(...directive.inputs);
mergedInputs = inputs;
} }
let mergedOutputs: string[]; let mergedOutputs: string[] = outputs;
if (isPresent(dm.outputs)) { if (directive.outputs) {
const outputNames: string[] = const outputNames: string[] =
dm.outputs.map((def: string): string => this._extractPublicName(def)); directive.outputs.map((def: string): string => this._extractPublicName(def));
outputs.forEach((outputDef: string) => { outputs.forEach((outputDef: string) => {
const publicName = this._extractPublicName(outputDef); const publicName = this._extractPublicName(outputDef);
@ -123,47 +129,48 @@ export class DirectiveResolver {
`Output event '${publicName}' defined multiple times in '${stringify(directiveType)}'`); `Output event '${publicName}' defined multiple times in '${stringify(directiveType)}'`);
} }
}); });
mergedOutputs = dm.outputs.concat(outputs); mergedOutputs.unshift(...directive.outputs);
} else {
mergedOutputs = outputs;
} }
var mergedHost = isPresent(dm.host) ? StringMapWrapper.merge(dm.host, host) : host; const mergedHost = directive.host ? StringMapWrapper.merge(directive.host, host) : host;
var mergedQueries = const mergedQueries =
isPresent(dm.queries) ? StringMapWrapper.merge(dm.queries, queries) : queries; directive.queries ? StringMapWrapper.merge(directive.queries, queries) : queries;
if (dm instanceof Component) { if (directive instanceof Component) {
return new Component({ return new Component({
selector: dm.selector, selector: directive.selector,
inputs: mergedInputs, inputs: mergedInputs,
outputs: mergedOutputs, outputs: mergedOutputs,
host: mergedHost, host: mergedHost,
exportAs: dm.exportAs, exportAs: directive.exportAs,
moduleId: dm.moduleId, moduleId: directive.moduleId,
queries: mergedQueries, queries: mergedQueries,
changeDetection: dm.changeDetection, changeDetection: directive.changeDetection,
providers: dm.providers, providers: directive.providers,
viewProviders: dm.viewProviders, viewProviders: directive.viewProviders,
entryComponents: dm.entryComponents, entryComponents: directive.entryComponents,
template: dm.template, template: directive.template,
templateUrl: dm.templateUrl, templateUrl: directive.templateUrl,
styles: dm.styles, styles: directive.styles,
styleUrls: dm.styleUrls, styleUrls: directive.styleUrls,
encapsulation: dm.encapsulation, encapsulation: directive.encapsulation,
animations: dm.animations, animations: directive.animations,
interpolation: dm.interpolation interpolation: directive.interpolation
}); });
} else { } else {
return new Directive({ return new Directive({
selector: dm.selector, selector: directive.selector,
inputs: mergedInputs, inputs: mergedInputs,
outputs: mergedOutputs, outputs: mergedOutputs,
host: mergedHost, host: mergedHost,
exportAs: dm.exportAs, exportAs: directive.exportAs,
queries: mergedQueries, queries: mergedQueries,
providers: dm.providers providers: directive.providers
}); });
} }
} }
} }
function isDirectiveMetadata(type: any): type is Directive {
return type instanceof Directive;
}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {ListWrapper} from '../facade/collection';
import {isBlank} from '../facade/lang'; import {isBlank} from '../facade/lang';
export class ParserError { export class ParserError {
@ -376,7 +376,7 @@ export class AstTransformer implements AstVisitor {
} }
visitAll(asts: any[]): any[] { visitAll(asts: any[]): any[] {
var res = ListWrapper.createFixedSize(asts.length); var res = new Array(asts.length);
for (var i = 0; i < asts.length; ++i) { for (var i = 0; i < asts.length; ++i) {
res[i] = asts[i].visit(this); res[i] = asts[i].visit(this);
} }

View File

@ -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, StringJoiner, 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 {
@ -310,7 +309,7 @@ class _Scanner {
unescapedCode = unescape(this.peek); unescapedCode = unescape(this.peek);
this.advance(); this.advance();
} }
buffer.add(StringWrapper.fromCharCode(unescapedCode)); buffer.add(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);

View File

@ -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);
} }
@ -79,8 +83,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 +103,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 +116,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 +136,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 +162,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 +179,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 +196,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 +227,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 +239,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 +260,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 +332,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('|'));
} }

View File

@ -27,7 +27,6 @@ const _PLACEHOLDER_TAG = 'x';
const _SOURCE_TAG = 'source'; const _SOURCE_TAG = 'source';
const _TARGET_TAG = 'target'; const _TARGET_TAG = 'target';
const _UNIT_TAG = 'trans-unit'; const _UNIT_TAG = 'trans-unit';
const _CR = (ws: number = 0) => new xml.Text(`\n${new Array(ws).join(' ')}`);
// http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html // http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html
// http://docs.oasis-open.org/xliff/v1.2/xliff-profile-html/xliff-profile-html-1.2.html // http://docs.oasis-open.org/xliff/v1.2/xliff-profile-html/xliff-profile-html-1.2.html
@ -44,34 +43,37 @@ export class Xliff implements Serializer {
let transUnit = new xml.Tag(_UNIT_TAG, {id: id, datatype: 'html'}); let transUnit = new xml.Tag(_UNIT_TAG, {id: id, datatype: 'html'});
transUnit.children.push( transUnit.children.push(
_CR(8), new xml.Tag(_SOURCE_TAG, {}, visitor.serialize(message.nodes)), _CR(8), new xml.CR(8), new xml.Tag(_SOURCE_TAG, {}, visitor.serialize(message.nodes)),
new xml.Tag(_TARGET_TAG)); new xml.CR(8), new xml.Tag(_TARGET_TAG));
if (message.description) { if (message.description) {
transUnit.children.push( transUnit.children.push(
_CR(8), new xml.CR(8),
new xml.Tag( new xml.Tag(
'note', {priority: '1', from: 'description'}, [new xml.Text(message.description)])); 'note', {priority: '1', from: 'description'}, [new xml.Text(message.description)]));
} }
if (message.meaning) { if (message.meaning) {
transUnit.children.push( transUnit.children.push(
_CR(8), new xml.CR(8),
new xml.Tag('note', {priority: '1', from: 'meaning'}, [new xml.Text(message.meaning)])); new xml.Tag('note', {priority: '1', from: 'meaning'}, [new xml.Text(message.meaning)]));
} }
transUnit.children.push(_CR(6)); transUnit.children.push(new xml.CR(6));
transUnits.push(_CR(6), transUnit); transUnits.push(new xml.CR(6), transUnit);
}); });
const body = new xml.Tag('body', {}, [...transUnits, _CR(4)]); const body = new xml.Tag('body', {}, [...transUnits, new xml.CR(4)]);
const file = new xml.Tag( const file = new xml.Tag(
'file', {'source-language': _SOURCE_LANG, datatype: 'plaintext', original: 'ng2.template'}, 'file', {'source-language': _SOURCE_LANG, datatype: 'plaintext', original: 'ng2.template'},
[_CR(4), body, _CR(2)]); [new xml.CR(4), body, new xml.CR(2)]);
const xliff = new xml.Tag('xliff', {version: _VERSION, xmlns: _XMLNS}, [_CR(2), file, _CR()]); const xliff = new xml.Tag(
'xliff', {version: _VERSION, xmlns: _XMLNS}, [new xml.CR(2), file, new xml.CR()]);
return xml.serialize([new xml.Declaration({version: '1.0', encoding: 'UTF-8'}), _CR(), xliff]); return xml.serialize([
new xml.Declaration({version: '1.0', encoding: 'UTF-8'}), new xml.CR(), xliff, new xml.CR()
]);
} }
load(content: string, url: string, messageBundle: MessageBundle): {[id: string]: ml.Node[]} { load(content: string, url: string, messageBundle: MessageBundle): {[id: string]: ml.Node[]} {
@ -137,13 +139,15 @@ class _WriteVisitor implements i18n.Visitor {
} }
visitTagPlaceholder(ph: i18n.TagPlaceholder, context?: any): xml.Node[] { visitTagPlaceholder(ph: i18n.TagPlaceholder, context?: any): xml.Node[] {
const startTagPh = new xml.Tag(_PLACEHOLDER_TAG, {id: ph.startName, ctype: ph.tag}); const ctype = getCtypeForTag(ph.tag);
const startTagPh = new xml.Tag(_PLACEHOLDER_TAG, {id: ph.startName, ctype});
if (ph.isVoid) { if (ph.isVoid) {
// void tags have no children nor closing tags // void tags have no children nor closing tags
return [startTagPh]; return [startTagPh];
} }
const closeTagPh = new xml.Tag(_PLACEHOLDER_TAG, {id: ph.closeName, ctype: ph.tag}); const closeTagPh = new xml.Tag(_PLACEHOLDER_TAG, {id: ph.closeName, ctype});
return [startTagPh, ...this.serialize(ph.children), closeTagPh]; return [startTagPh, ...this.serialize(ph.children), closeTagPh];
} }
@ -287,3 +291,14 @@ class _LoadVisitor implements ml.Visitor {
this._errors.push(new I18nError(node.sourceSpan, message)); this._errors.push(new I18nError(node.sourceSpan, message));
} }
} }
function getCtypeForTag(tag: string): string {
switch (tag.toLowerCase()) {
case 'br':
return 'lb';
case 'img':
return 'image';
default:
return `x-${tag}`;
}
}

View File

@ -43,7 +43,6 @@ export class Xmb implements Serializer {
write(messageMap: {[k: string]: i18n.Message}): string { write(messageMap: {[k: string]: i18n.Message}): string {
const visitor = new _Visitor(); const visitor = new _Visitor();
let rootNode = new xml.Tag(_MESSAGES_TAG); let rootNode = new xml.Tag(_MESSAGES_TAG);
rootNode.children.push(new xml.Text('\n'));
Object.keys(messageMap).forEach((id) => { Object.keys(messageMap).forEach((id) => {
const message = messageMap[id]; const message = messageMap[id];
@ -58,16 +57,18 @@ export class Xmb implements Serializer {
} }
rootNode.children.push( rootNode.children.push(
new xml.Text(' '), new xml.Tag(_MESSAGE_TAG, attrs, visitor.serialize(message.nodes)), new xml.CR(2), new xml.Tag(_MESSAGE_TAG, attrs, visitor.serialize(message.nodes)));
new xml.Text('\n'));
}); });
rootNode.children.push(new xml.CR());
return xml.serialize([ return xml.serialize([
new xml.Declaration({version: '1.0', encoding: 'UTF-8'}), new xml.Declaration({version: '1.0', encoding: 'UTF-8'}),
new xml.Text('\n'), new xml.CR(),
new xml.Doctype(_MESSAGES_TAG, _DOCTYPE), new xml.Doctype(_MESSAGES_TAG, _DOCTYPE),
new xml.Text('\n'), new xml.CR(),
rootNode, rootNode,
new xml.CR(),
]); ]);
} }

View File

@ -88,6 +88,10 @@ export class Text implements Node {
visit(visitor: IVisitor): any { return visitor.visitText(this); } visit(visitor: IVisitor): any { return visitor.visitText(this); }
} }
export class CR extends Text {
constructor(ws: number = 0) { super(`\n${new Array(ws + 1).join(' ')}`); }
}
const _ESCAPED_CHARS: [RegExp, string][] = [ const _ESCAPED_CHARS: [RegExp, string][] = [
[/&/g, '&amp;'], [/&/g, '&amp;'],
[/"/g, '&quot;'], [/"/g, '&quot;'],

View File

@ -9,7 +9,7 @@
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, 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 {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata'; import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
import {AnimationGroupPlayer, AnimationKeyframe, AnimationOutput, 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, 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 {assetUrl} from './util'; import {assetUrl} from './util';
var APP_VIEW_MODULE_URL = assetUrl('core', 'linker/view'); var APP_VIEW_MODULE_URL = assetUrl('core', 'linker/view');
@ -266,11 +266,6 @@ export class Identifiers {
moduleUrl: assetUrl('core', 'i18n/tokens'), moduleUrl: assetUrl('core', 'i18n/tokens'),
runtime: TRANSLATIONS_FORMAT_ runtime: TRANSLATIONS_FORMAT_
}; };
static AnimationOutput: IdentifierSpec = {
name: 'AnimationOutput',
moduleUrl: assetUrl('core', 'animation/animation_output'),
runtime: AnimationOutput
};
} }
export function resolveIdentifier(identifier: IdentifierSpec) { export function resolveIdentifier(identifier: IdentifierSpec) {

View File

@ -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);
} }

View File

@ -123,7 +123,7 @@ class _TreeBuilder {
// read = // read =
while (this._peek.type === lex.TokenType.EXPANSION_CASE_VALUE) { while (this._peek.type === lex.TokenType.EXPANSION_CASE_VALUE) {
let expCase = this._parseExpansionCase(); let expCase = this._parseExpansionCase();
if (isBlank(expCase)) return; // error if (!expCase) return; // error
cases.push(expCase); cases.push(expCase);
} }
@ -154,7 +154,7 @@ class _TreeBuilder {
const start = this._advance(); const start = this._advance();
const exp = this._collectExpansionExpTokens(start); const exp = this._collectExpansionExpTokens(start);
if (isBlank(exp)) return null; if (!exp) return null;
const end = this._advance(); const end = this._advance();
exp.push(new lex.Token(lex.TokenType.EOF, [], end.sourceSpan)); exp.push(new lex.Token(lex.TokenType.EOF, [], end.sourceSpan));
@ -331,12 +331,15 @@ 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 {

View File

@ -9,8 +9,8 @@
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 {isBlank, isPresent} from './facade/lang'; import {isPresent} from './facade/lang';
import {Identifiers, identifierToken, resolveIdentifier, resolveIdentifierToken} from './identifiers'; import {Identifiers, resolveIdentifier, resolveIdentifierToken} from './identifiers';
import * as o from './output/output_ast'; import * as o from './output/output_ast';
import {convertValueToOutputAst} from './output/value_util'; import {convertValueToOutputAst} from './output/value_util';
import {ParseLocation, ParseSourceFile, ParseSourceSpan} from './parse_util'; import {ParseLocation, ParseSourceFile, ParseSourceSpan} from './parse_util';
@ -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));
@ -190,7 +190,7 @@ class _InjectorBuilder {
resolvedProviderValueExpr = providerValueExpressions[0]; resolvedProviderValueExpr = providerValueExpressions[0];
type = providerValueExpressions[0].type; type = providerValueExpressions[0].type;
} }
if (isBlank(type)) { if (!type) {
type = o.DYNAMIC_TYPE; type = o.DYNAMIC_TYPE;
} }
if (isEager) { if (isEager) {
@ -223,11 +223,11 @@ class _InjectorBuilder {
resolveIdentifierToken(Identifiers.ComponentFactoryResolver).reference)) { resolveIdentifierToken(Identifiers.ComponentFactoryResolver).reference)) {
result = o.THIS_EXPR; result = o.THIS_EXPR;
} }
if (isBlank(result)) { if (!result) {
result = this._instances.get(dep.token.reference); result = this._instances.get(dep.token.reference);
} }
} }
if (isBlank(result)) { if (!result) {
var args = [createDiTokenExpression(dep.token)]; var args = [createDiTokenExpression(dep.token)];
if (dep.isOptional) { if (dep.isOptional) {
args.push(o.NULL_EXPR); args.push(o.NULL_EXPR);

View File

@ -8,7 +8,9 @@
import {SchemaMetadata} from '@angular/core'; import {SchemaMetadata} from '@angular/core';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, CompileProviderMetadata, CompileTokenMetadata, StaticSymbol, createHostComponentMeta} from './compile_metadata'; import {AnimationCompiler} from './animation/animation_compiler';
import {AnimationParser} from './animation/animation_parser';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, CompileProviderMetadata, StaticSymbol, createHostComponentMeta} from './compile_metadata';
import {DirectiveNormalizer} from './directive_normalizer'; import {DirectiveNormalizer} from './directive_normalizer';
import {Identifiers, resolveIdentifier, resolveIdentifierToken} from './identifiers'; import {Identifiers, resolveIdentifier, resolveIdentifierToken} from './identifiers';
import {CompileMetadataResolver} from './metadata_resolver'; import {CompileMetadataResolver} from './metadata_resolver';
@ -24,10 +26,32 @@ export class SourceModule {
} }
export class NgModulesSummary { export class NgModulesSummary {
constructor(public ngModuleByComponent: Map<StaticSymbol, CompileNgModuleMetadata>) {} constructor(
public ngModuleByComponent: Map<StaticSymbol, CompileNgModuleMetadata>,
public ngModules: CompileNgModuleMetadata[]) {}
}
export function analyzeModules(
ngModules: StaticSymbol[], metadataResolver: CompileMetadataResolver) {
const ngModuleByComponent = new Map<StaticSymbol, CompileNgModuleMetadata>();
const modules: CompileNgModuleMetadata[] = [];
ngModules.forEach((ngModule) => {
const ngModuleMeta = metadataResolver.getNgModuleMetadata(<any>ngModule);
modules.push(ngModuleMeta);
ngModuleMeta.declaredDirectives.forEach((dirMeta: CompileDirectiveMetadata) => {
if (dirMeta.isComponent) {
ngModuleByComponent.set(dirMeta.type.reference, ngModuleMeta);
}
});
});
return new NgModulesSummary(ngModuleByComponent, modules);
} }
export class OfflineCompiler { export class OfflineCompiler {
private _animationParser = new AnimationParser();
private _animationCompiler = new AnimationCompiler();
constructor( constructor(
private _metadataResolver: CompileMetadataResolver, private _metadataResolver: CompileMetadataResolver,
private _directiveNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser, private _directiveNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser,
@ -36,17 +60,7 @@ export class OfflineCompiler {
private _localeId: string, private _translationFormat: string) {} private _localeId: string, private _translationFormat: string) {}
analyzeModules(ngModules: StaticSymbol[]): NgModulesSummary { analyzeModules(ngModules: StaticSymbol[]): NgModulesSummary {
const ngModuleByComponent = new Map<StaticSymbol, CompileNgModuleMetadata>(); return analyzeModules(ngModules, this._metadataResolver);
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() {
@ -162,14 +176,19 @@ export class OfflineCompiler {
compMeta: CompileDirectiveMetadata, directives: CompileDirectiveMetadata[], compMeta: CompileDirectiveMetadata, directives: CompileDirectiveMetadata[],
pipes: CompilePipeMetadata[], schemas: SchemaMetadata[], componentStyles: CompiledStylesheet, pipes: CompilePipeMetadata[], schemas: SchemaMetadata[], componentStyles: CompiledStylesheet,
fileSuffix: string, targetStatements: o.Statement[]): string { fileSuffix: string, targetStatements: o.Statement[]): string {
const parsedAnimations = this._animationParser.parseComponent(compMeta);
const parsedTemplate = this._templateParser.parse( const parsedTemplate = this._templateParser.parse(
compMeta, compMeta.template.template, directives, pipes, schemas, compMeta.type.name); compMeta, compMeta.template.template, directives, pipes, schemas, compMeta.type.name);
const stylesExpr = componentStyles ? o.variable(componentStyles.stylesVar) : o.literalArr([]); const stylesExpr = componentStyles ? o.variable(componentStyles.stylesVar) : o.literalArr([]);
const viewResult = const compiledAnimations =
this._viewCompiler.compileComponent(compMeta, parsedTemplate, stylesExpr, pipes); this._animationCompiler.compile(compMeta.type.name, parsedAnimations);
const viewResult = this._viewCompiler.compileComponent(
compMeta, parsedTemplate, stylesExpr, pipes, compiledAnimations);
if (componentStyles) { if (componentStyles) {
targetStatements.push(..._resolveStyleStatements(componentStyles, fileSuffix)); targetStatements.push(..._resolveStyleStatements(componentStyles, fileSuffix));
} }
compiledAnimations.forEach(
entry => { entry.statements.forEach(statement => { targetStatements.push(statement); }); });
targetStatements.push(..._resolveViewStatements(viewResult)); targetStatements.push(..._resolveViewStatements(viewResult));
return viewResult.viewFactoryVar; return viewResult.viewFactoryVar;
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {StringWrapper, isBlank, isPresent, isString} from '../facade/lang'; import {isBlank, isPresent, isString} from '../facade/lang';
import * as o from './output_ast'; import * as o from './output_ast';
@ -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) {
@ -400,7 +399,7 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex
} }
visitAllStatements(statements: o.Statement[], ctx: EmitterVisitorContext): void { visitAllStatements(statements: o.Statement[], ctx: EmitterVisitorContext): void {
statements.forEach((stmt) => { return stmt.visitStatement(this, ctx); }); statements.forEach((stmt) => stmt.visitStatement(this, ctx));
} }
} }
@ -409,18 +408,17 @@ 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') { return '\\n';
return '\\n'; } else if (match[0] == '\r') {
} else if (match[0] == '\r') { return '\\r';
return '\\r'; } else {
} else { return `\\${match[0]}`;
return `\\${match[0]}`; }
} });
});
let requiresQuotes = alwaysQuote || !_LEGAL_IDENTIFIER_RE.test(body); let requiresQuotes = alwaysQuote || !_LEGAL_IDENTIFIER_RE.test(body);
return requiresQuotes ? `'${body}'` : body; return requiresQuotes ? `'${body}'` : body;
} }

View File

@ -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';

View File

@ -7,7 +7,7 @@
*/ */
import {StringWrapper, evalExpression, isBlank, isPresent, isString} from '../facade/lang'; import {isBlank, isPresent} from '../facade/lang';
import {EmitterVisitorContext, OutputEmitter} from './abstract_emitter'; import {EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
import {AbstractJsEmitterVisitor} from './abstract_js_emitter'; import {AbstractJsEmitterVisitor} from './abstract_js_emitter';
@ -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(

View File

@ -8,9 +8,7 @@
import {CompileIdentifierMetadata} from '../compile_metadata'; import {CompileIdentifierMetadata} from '../compile_metadata';
import {StringMapWrapper} from '../facade/collection'; import {isPresent, isString} from '../facade/lang';
import {isBlank, isPresent, isString} from '../facade/lang';
import {ValueTransformer, visitValue} from '../util';
@ -21,7 +19,7 @@ export enum TypeModifier {
export abstract class Type { export abstract class Type {
constructor(public modifiers: TypeModifier[] = null) { constructor(public modifiers: TypeModifier[] = null) {
if (isBlank(modifiers)) { if (!modifiers) {
this.modifiers = []; this.modifiers = [];
} }
} }
@ -217,7 +215,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;
} }
@ -235,7 +233,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 {
@ -248,7 +246,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 {
@ -324,7 +322,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 {
@ -371,7 +369,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 {
@ -418,7 +416,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;
@ -464,7 +462,7 @@ export enum StmtModifier {
export abstract class Statement { export abstract class Statement {
constructor(public modifiers: StmtModifier[] = null) { constructor(public modifiers: StmtModifier[] = null) {
if (isBlank(modifiers)) { if (!modifiers) {
this.modifiers = []; this.modifiers = [];
} }
} }
@ -481,7 +479,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 {
@ -519,7 +517,7 @@ export class ReturnStatement extends Statement {
export class AbstractClassPart { export class AbstractClassPart {
constructor(public type: Type = null, public modifiers: StmtModifier[]) { constructor(public type: Type = null, public modifiers: StmtModifier[]) {
if (isBlank(modifiers)) { if (!modifiers) {
this.modifiers = []; this.modifiers = [];
} }
} }
@ -627,7 +625,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);
@ -675,9 +673,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));
@ -883,8 +883,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);
} }

View File

@ -26,9 +26,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;
} }

View File

@ -6,11 +6,6 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Injectable} from '@angular/core';
import {Math, isBlank, isPresent} from '../facade/lang';
// asset:<package-name>/<realm>/<path-to-module> // asset:<package-name>/<realm>/<path-to-module>
var _ASSET_URL_RE = /asset:([^\/]+)\/([^\/]+)\/(.+)/; var _ASSET_URL_RE = /asset:([^\/]+)\/([^\/]+)\/(.+)/;

View File

@ -46,7 +46,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 +75,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 +243,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 +307,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 +336,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(`>`);
} }
} }

View File

@ -8,7 +8,6 @@
import {CompileIdentifierMetadata} from '../compile_metadata'; import {CompileIdentifierMetadata} from '../compile_metadata';
import {StringMapWrapper} from '../facade/collection';
import {ValueTransformer, visitValue} from '../util'; import {ValueTransformer, visitValue} from '../util';
import * as o from './output_ast'; import * as o from './output_ast';
@ -23,10 +22,8 @@ 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][] = [];
StringMapWrapper.forEach(map, (value: any, key: string) => { Object.keys(map).forEach(key => { entries.push([key, visitValue(map[key], this, null)]); });
entries.push([key, visitValue(value, this, null)]);
});
return o.literalMap(entries, type); return o.literalMap(entries, type);
} }

View File

@ -12,7 +12,6 @@ export const isDefaultChangeDetectionStrategy: typeof r.isDefaultChangeDetection
r.isDefaultChangeDetectionStrategy; r.isDefaultChangeDetectionStrategy;
export type ChangeDetectorStatus = typeof r._ChangeDetectorStatus; export type ChangeDetectorStatus = typeof r._ChangeDetectorStatus;
export const ChangeDetectorStatus: typeof r.ChangeDetectorStatus = r.ChangeDetectorStatus; export const ChangeDetectorStatus: typeof r.ChangeDetectorStatus = r.ChangeDetectorStatus;
r.CHANGE_DETECTION_STRATEGY_VALUES;
export type LifecycleHooks = typeof r._LifecycleHooks; export type LifecycleHooks = typeof r._LifecycleHooks;
export const LifecycleHooks: typeof r.LifecycleHooks = r.LifecycleHooks; export const LifecycleHooks: typeof r.LifecycleHooks = r.LifecycleHooks;
export const LIFECYCLE_HOOKS_VALUES: typeof r.LIFECYCLE_HOOKS_VALUES = r.LIFECYCLE_HOOKS_VALUES; export const LIFECYCLE_HOOKS_VALUES: typeof r.LIFECYCLE_HOOKS_VALUES = r.LIFECYCLE_HOOKS_VALUES;
@ -75,8 +74,6 @@ export type AnimationKeyframe = typeof r._AnimationKeyframe;
export const AnimationKeyframe: typeof r.AnimationKeyframe = r.AnimationKeyframe; export const AnimationKeyframe: typeof r.AnimationKeyframe = r.AnimationKeyframe;
export type AnimationStyles = typeof r._AnimationStyles; export type AnimationStyles = typeof r._AnimationStyles;
export const AnimationStyles: typeof r.AnimationStyles = r.AnimationStyles; export const AnimationStyles: typeof r.AnimationStyles = r.AnimationStyles;
export type AnimationOutput = typeof r._AnimationOutput;
export const AnimationOutput: typeof r.AnimationOutput = r.AnimationOutput;
export const ANY_STATE = r.ANY_STATE; export const ANY_STATE = r.ANY_STATE;
export const DEFAULT_STATE = r.DEFAULT_STATE; export const DEFAULT_STATE = r.DEFAULT_STATE;
export const EMPTY_STATE = r.EMPTY_STATE; export const EMPTY_STATE = r.EMPTY_STATE;

View File

@ -12,7 +12,7 @@ import {ListWrapper, MapWrapper} from './facade/collection';
import {isArray, isBlank, isPresent, normalizeBlank} from './facade/lang'; import {isArray, isBlank, isPresent, normalizeBlank} from './facade/lang';
import {Identifiers, resolveIdentifierToken} from './identifiers'; import {Identifiers, resolveIdentifierToken} from './identifiers';
import {ParseError, ParseSourceSpan} from './parse_util'; import {ParseError, ParseSourceSpan} from './parse_util';
import {AttrAst, DirectiveAst, ProviderAst, ProviderAstType, ReferenceAst, VariableAst} from './template_parser/template_ast'; import {AttrAst, DirectiveAst, ProviderAst, ProviderAstType, ReferenceAst} from './template_parser/template_ast';
export class ProviderError extends ParseError { export class ProviderError extends ParseError {
constructor(message: string, span: ParseSourceSpan) { super(span, message); } constructor(message: string, span: ParseSourceSpan) { super(span, message); }
@ -50,14 +50,14 @@ export class ProviderElementContext {
private _hasViewContainer: boolean = false; private _hasViewContainer: boolean = false;
constructor( constructor(
private _viewContext: ProviderViewContext, private _parent: ProviderElementContext, public viewContext: ProviderViewContext, private _parent: ProviderElementContext,
private _isViewRoot: boolean, private _directiveAsts: DirectiveAst[], attrs: AttrAst[], private _isViewRoot: boolean, private _directiveAsts: DirectiveAst[], attrs: AttrAst[],
refs: ReferenceAst[], private _sourceSpan: ParseSourceSpan) { refs: ReferenceAst[], private _sourceSpan: ParseSourceSpan) {
this._attrs = {}; this._attrs = {};
attrs.forEach((attrAst) => this._attrs[attrAst.name] = attrAst.value); attrs.forEach((attrAst) => this._attrs[attrAst.name] = attrAst.value);
var directivesMeta = _directiveAsts.map(directiveAst => directiveAst.directive); var directivesMeta = _directiveAsts.map(directiveAst => directiveAst.directive);
this._allProviders = this._allProviders =
_resolveProvidersFromDirectives(directivesMeta, _sourceSpan, _viewContext.errors); _resolveProvidersFromDirectives(directivesMeta, _sourceSpan, viewContext.errors);
this._contentQueries = _getContentQueries(directivesMeta); this._contentQueries = _getContentQueries(directivesMeta);
var queriedTokens = new Map<any, boolean>(); var queriedTokens = new Map<any, boolean>();
MapWrapper.values(this._allProviders).forEach((provider) => { MapWrapper.values(this._allProviders).forEach((provider) => {
@ -102,7 +102,7 @@ export class ProviderElementContext {
private _addQueryReadsTo(token: CompileTokenMetadata, queryReadTokens: Map<any, boolean>) { private _addQueryReadsTo(token: CompileTokenMetadata, queryReadTokens: Map<any, boolean>) {
this._getQueriesFor(token).forEach((query) => { this._getQueriesFor(token).forEach((query) => {
const queryReadToken = isPresent(query.read) ? query.read : token; const queryReadToken = query.read || token;
if (isBlank(queryReadTokens.get(queryReadToken.reference))) { if (isBlank(queryReadTokens.get(queryReadToken.reference))) {
queryReadTokens.set(queryReadToken.reference, true); queryReadTokens.set(queryReadToken.reference, true);
} }
@ -124,7 +124,7 @@ export class ProviderElementContext {
} }
currentEl = currentEl._parent; currentEl = currentEl._parent;
} }
queries = this._viewContext.viewQueries.get(token.reference); queries = this.viewContext.viewQueries.get(token.reference);
if (isPresent(queries)) { if (isPresent(queries)) {
ListWrapper.addAll(result, queries); ListWrapper.addAll(result, queries);
} }
@ -136,10 +136,9 @@ export class ProviderElementContext {
requestingProviderType: ProviderAstType, token: CompileTokenMetadata, requestingProviderType: ProviderAstType, token: CompileTokenMetadata,
eager: boolean): ProviderAst { eager: boolean): ProviderAst {
var resolvedProvider = this._allProviders.get(token.reference); var resolvedProvider = this._allProviders.get(token.reference);
if (isBlank(resolvedProvider) || if (!resolvedProvider || ((requestingProviderType === ProviderAstType.Directive ||
((requestingProviderType === ProviderAstType.Directive || requestingProviderType === ProviderAstType.PublicService) &&
requestingProviderType === ProviderAstType.PublicService) && resolvedProvider.providerType === ProviderAstType.PrivateService) ||
resolvedProvider.providerType === ProviderAstType.PrivateService) ||
((requestingProviderType === ProviderAstType.PrivateService || ((requestingProviderType === ProviderAstType.PrivateService ||
requestingProviderType === ProviderAstType.PublicService) && requestingProviderType === ProviderAstType.PublicService) &&
resolvedProvider.providerType === ProviderAstType.Builtin)) { resolvedProvider.providerType === ProviderAstType.Builtin)) {
@ -150,7 +149,7 @@ export class ProviderElementContext {
return transformedProviderAst; return transformedProviderAst;
} }
if (isPresent(this._seenProviders.get(token.reference))) { if (isPresent(this._seenProviders.get(token.reference))) {
this._viewContext.errors.push(new ProviderError( this.viewContext.errors.push(new ProviderError(
`Cannot instantiate cyclic dependency! ${token.name}`, this._sourceSpan)); `Cannot instantiate cyclic dependency! ${token.name}`, this._sourceSpan));
return null; return null;
} }
@ -170,11 +169,11 @@ export class ProviderElementContext {
transformedUseValue = existingDiDep.value; transformedUseValue = existingDiDep.value;
} }
} 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;
transformedDeps = transformedDeps =
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager)); deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager));
} 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;
transformedDeps = transformedDeps =
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager)); deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager));
} }
@ -239,12 +238,12 @@ export class ProviderElementContext {
result = this._getLocalDependency(requestingProviderType, dep, eager); result = this._getLocalDependency(requestingProviderType, dep, eager);
} }
if (dep.isSelf) { if (dep.isSelf) {
if (isBlank(result) && dep.isOptional) { if (!result && dep.isOptional) {
result = new CompileDiDependencyMetadata({isValue: true, value: null}); result = new CompileDiDependencyMetadata({isValue: true, value: null});
} }
} else { } else {
// check parent elements // check parent elements
while (isBlank(result) && isPresent(currElement._parent)) { while (!result && isPresent(currElement._parent)) {
var prevElement = currElement; var prevElement = currElement;
currElement = currElement._parent; currElement = currElement._parent;
if (prevElement._isViewRoot) { if (prevElement._isViewRoot) {
@ -253,10 +252,10 @@ export class ProviderElementContext {
result = currElement._getLocalDependency(ProviderAstType.PublicService, dep, currEager); result = currElement._getLocalDependency(ProviderAstType.PublicService, dep, currEager);
} }
// check @Host restriction // check @Host restriction
if (isBlank(result)) { if (!result) {
if (!dep.isHost || this._viewContext.component.type.isHost || if (!dep.isHost || this.viewContext.component.type.isHost ||
this._viewContext.component.type.reference === dep.token.reference || this.viewContext.component.type.reference === dep.token.reference ||
isPresent(this._viewContext.viewProviders.get(dep.token.reference))) { isPresent(this.viewContext.viewProviders.get(dep.token.reference))) {
result = dep; result = dep;
} else { } else {
result = dep.isOptional ? result = dep.isOptional ?
@ -265,8 +264,8 @@ export class ProviderElementContext {
} }
} }
} }
if (isBlank(result)) { if (!result) {
this._viewContext.errors.push( this.viewContext.errors.push(
new ProviderError(`No provider for ${dep.token.name}`, this._sourceSpan)); new ProviderError(`No provider for ${dep.token.name}`, this._sourceSpan));
} }
return result; return result;
@ -311,7 +310,7 @@ export class NgModuleProviderAnalyzer {
private _getOrCreateLocalProvider(token: CompileTokenMetadata, eager: boolean): ProviderAst { private _getOrCreateLocalProvider(token: CompileTokenMetadata, eager: boolean): ProviderAst {
var resolvedProvider = this._allProviders.get(token.reference); var resolvedProvider = this._allProviders.get(token.reference);
if (isBlank(resolvedProvider)) { if (!resolvedProvider) {
return null; return null;
} }
var transformedProviderAst = this._transformedProviders.get(token.reference); var transformedProviderAst = this._transformedProviders.get(token.reference);
@ -339,11 +338,11 @@ export class NgModuleProviderAnalyzer {
transformedUseValue = existingDiDep.value; transformedUseValue = existingDiDep.value;
} }
} 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;
transformedDeps = transformedDeps =
deps.map((dep) => this._getDependency(dep, eager, resolvedProvider.sourceSpan)); deps.map((dep) => this._getDependency(dep, eager, resolvedProvider.sourceSpan));
} 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;
transformedDeps = transformedDeps =
deps.map((dep) => this._getDependency(dep, eager, resolvedProvider.sourceSpan)); deps.map((dep) => this._getDependency(dep, eager, resolvedProvider.sourceSpan));
} }
@ -414,7 +413,7 @@ function _normalizeProviders(
providers: Array<CompileProviderMetadata|CompileTypeMetadata|any[]>, providers: Array<CompileProviderMetadata|CompileTypeMetadata|any[]>,
sourceSpan: ParseSourceSpan, targetErrors: ParseError[], sourceSpan: ParseSourceSpan, targetErrors: ParseError[],
targetProviders: CompileProviderMetadata[] = null): CompileProviderMetadata[] { targetProviders: CompileProviderMetadata[] = null): CompileProviderMetadata[] {
if (isBlank(targetProviders)) { if (!targetProviders) {
targetProviders = []; targetProviders = [];
} }
if (isPresent(providers)) { if (isPresent(providers)) {
@ -479,7 +478,7 @@ function _resolveProviders(
`Mixing multi and non multi provider is not possible for token ${resolvedProvider.token.name}`, `Mixing multi and non multi provider is not possible for token ${resolvedProvider.token.name}`,
sourceSpan)); sourceSpan));
} }
if (isBlank(resolvedProvider)) { if (!resolvedProvider) {
const lifecycleHooks = const lifecycleHooks =
provider.token.identifier && provider.token.identifier instanceof CompileTypeMetadata ? provider.token.identifier && provider.token.identifier instanceof CompileTypeMetadata ?
provider.token.identifier.lifecycleHooks : provider.token.identifier.lifecycleHooks :
@ -530,7 +529,7 @@ function _getContentQueries(directives: CompileDirectiveMetadata[]):
function _addQueryToTokenMap(map: Map<any, CompileQueryMetadata[]>, query: CompileQueryMetadata) { function _addQueryToTokenMap(map: Map<any, CompileQueryMetadata[]>, query: CompileQueryMetadata) {
query.selectors.forEach((token: CompileTokenMetadata) => { query.selectors.forEach((token: CompileTokenMetadata) => {
var entry = map.get(token.reference); var entry = map.get(token.reference);
if (isBlank(entry)) { if (!entry) {
entry = []; entry = [];
map.set(token.reference, entry); map.set(token.reference, entry);
} }

View File

@ -6,12 +6,13 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Compiler, ComponentFactory, Injectable, Injector, ModuleWithComponentFactories, NgModuleFactory, Optional, Provider, SchemaMetadata, SkipSelf, Type} from '@angular/core'; import {Compiler, ComponentFactory, Injectable, Injector, ModuleWithComponentFactories, NgModuleFactory, SchemaMetadata, Type} from '@angular/core';
import {AnimationCompiler} from './animation/animation_compiler';
import {AnimationParser} from './animation/animation_parser';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, ProviderMeta, createHostComponentMeta} from './compile_metadata'; import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, ProviderMeta, createHostComponentMeta} from './compile_metadata';
import {CompilerConfig} from './config'; import {CompilerConfig} from './config';
import {DirectiveNormalizer} from './directive_normalizer'; import {DirectiveNormalizer} from './directive_normalizer';
import {isBlank, stringify} from './facade/lang'; import {stringify} from './facade/lang';
import {CompileMetadataResolver} from './metadata_resolver'; import {CompileMetadataResolver} from './metadata_resolver';
import {NgModuleCompiler} from './ng_module_compiler'; import {NgModuleCompiler} from './ng_module_compiler';
import * as ir from './output/output_ast'; import * as ir from './output/output_ast';
@ -23,8 +24,6 @@ import {TemplateParser} from './template_parser/template_parser';
import {SyncAsyncResult} from './util'; import {SyncAsyncResult} from './util';
import {ComponentFactoryDependency, ViewCompiler, ViewFactoryDependency} from './view_compiler/view_compiler'; import {ComponentFactoryDependency, ViewCompiler, ViewFactoryDependency} from './view_compiler/view_compiler';
/** /**
* An internal module of the Angular compiler that begins with component types, * An internal module of the Angular compiler that begins with component types,
* extracts templates, and eventually produces a compiled version of the component * extracts templates, and eventually produces a compiled version of the component
@ -39,6 +38,8 @@ export class RuntimeCompiler implements Compiler {
private _compiledTemplateCache = new Map<Type<any>, CompiledTemplate>(); private _compiledTemplateCache = new Map<Type<any>, CompiledTemplate>();
private _compiledHostTemplateCache = new Map<Type<any>, CompiledTemplate>(); private _compiledHostTemplateCache = new Map<Type<any>, CompiledTemplate>();
private _compiledNgModuleCache = new Map<Type<any>, NgModuleFactory<any>>(); private _compiledNgModuleCache = new Map<Type<any>, NgModuleFactory<any>>();
private _animationParser = new AnimationParser();
private _animationCompiler = new AnimationCompiler();
constructor( constructor(
private _injector: Injector, private _metadataResolver: CompileMetadataResolver, private _injector: Injector, private _metadataResolver: CompileMetadataResolver,
@ -190,7 +191,7 @@ export class RuntimeCompiler implements Compiler {
private _createCompiledHostTemplate(compType: Type<any>): CompiledTemplate { private _createCompiledHostTemplate(compType: Type<any>): CompiledTemplate {
var compiledTemplate = this._compiledHostTemplateCache.get(compType); var compiledTemplate = this._compiledHostTemplateCache.get(compType);
if (isBlank(compiledTemplate)) { if (!compiledTemplate) {
var compMeta = this._metadataResolver.getDirectiveMetadata(compType); var compMeta = this._metadataResolver.getDirectiveMetadata(compType);
assertComponent(compMeta); assertComponent(compMeta);
var hostMeta = createHostComponentMeta(compMeta); var hostMeta = createHostComponentMeta(compMeta);
@ -205,7 +206,7 @@ export class RuntimeCompiler implements Compiler {
private _createCompiledTemplate( private _createCompiledTemplate(
compMeta: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata): CompiledTemplate { compMeta: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata): CompiledTemplate {
var compiledTemplate = this._compiledTemplateCache.get(compMeta.type.reference); var compiledTemplate = this._compiledTemplateCache.get(compMeta.type.reference);
if (isBlank(compiledTemplate)) { if (!compiledTemplate) {
assertComponent(compMeta); assertComponent(compMeta);
compiledTemplate = new CompiledTemplate( compiledTemplate = new CompiledTemplate(
false, compMeta.selector, compMeta.type, ngModule.transitiveModule.directives, false, compMeta.selector, compMeta.type, ngModule.transitiveModule.directives,
@ -253,12 +254,15 @@ export class RuntimeCompiler implements Compiler {
stylesCompileResult.componentStylesheet, externalStylesheetsByModuleUrl); stylesCompileResult.componentStylesheet, externalStylesheetsByModuleUrl);
const viewCompMetas = template.viewComponentTypes.map( const viewCompMetas = template.viewComponentTypes.map(
(compType) => this._assertComponentLoaded(compType, false).normalizedCompMeta); (compType) => this._assertComponentLoaded(compType, false).normalizedCompMeta);
const parsedAnimations = this._animationParser.parseComponent(compMeta);
const parsedTemplate = this._templateParser.parse( const parsedTemplate = this._templateParser.parse(
compMeta, compMeta.template.template, template.viewDirectives.concat(viewCompMetas), compMeta, compMeta.template.template, template.viewDirectives.concat(viewCompMetas),
template.viewPipes, template.schemas, compMeta.type.name); template.viewPipes, template.schemas, compMeta.type.name);
const compiledAnimations =
this._animationCompiler.compile(compMeta.type.name, parsedAnimations);
const compileResult = this._viewCompiler.compileComponent( const compileResult = this._viewCompiler.compileComponent(
compMeta, parsedTemplate, ir.variable(stylesCompileResult.componentStylesheet.stylesVar), compMeta, parsedTemplate, ir.variable(stylesCompileResult.componentStylesheet.stylesVar),
template.viewPipes); template.viewPipes, compiledAnimations);
compileResult.dependencies.forEach((dep) => { compileResult.dependencies.forEach((dep) => {
let depTemplate: CompiledTemplate; let depTemplate: CompiledTemplate;
if (dep instanceof ViewFactoryDependency) { if (dep instanceof ViewFactoryDependency) {
@ -275,6 +279,8 @@ export class RuntimeCompiler implements Compiler {
}); });
const statements = const statements =
stylesCompileResult.componentStylesheet.statements.concat(compileResult.statements); stylesCompileResult.componentStylesheet.statements.concat(compileResult.statements);
compiledAnimations.forEach(
entry => { entry.statements.forEach(statement => { statements.push(statement); }); });
let factory: any; let factory: any;
if (!this._compilerConfig.useJit) { if (!this._compilerConfig.useJit) {
factory = interpretStatements(statements, compileResult.viewFactoryVar); factory = interpretStatements(statements, compileResult.viewFactoryVar);

Some files were not shown because too many files have changed in this diff Show More