Compare commits
70 Commits
Author | SHA1 | Date | |
---|---|---|---|
91f7aa3b15 | |||
58b8091097 | |||
0fde7ecd0f | |||
d25cd244af | |||
e00de0c606 | |||
205103bdaa | |||
0528dcb9dc | |||
6f7ed32154 | |||
1bd8ba80a7 | |||
adb17fed98 | |||
3067ce6eb4 | |||
e102cd4757 | |||
db00ba7ae7 | |||
5a8f116687 | |||
02a862f8af | |||
7578d8573b | |||
de56e31cf0 | |||
eb85a7709a | |||
c99ef4938f | |||
7395400066 | |||
d985cc0253 | |||
aca117ac56 | |||
2c3825f2c8 | |||
ea6defcf11 | |||
975aca95bb | |||
5cb78566c2 | |||
9bacb32ec5 | |||
6970991546 | |||
bd012efcc4 | |||
2dd399658d | |||
d0dea574cb | |||
f7864edd4b | |||
9cc0a4ed10 | |||
3ee8c75eff | |||
b39d3a173e | |||
a4af1561b7 | |||
0851238e78 | |||
d2d98dad61 | |||
826c98e50c | |||
830e6352dd | |||
5911c3bd43 | |||
51e1994af0 | |||
faf5d90bf6 | |||
7e5413da89 | |||
e82a78e641 | |||
c13e55c8c3 | |||
a153504212 | |||
b8a75818ee | |||
f633826e99 | |||
0a8887240a | |||
6d606dd02b | |||
5c4215ccb4 | |||
85489a166e | |||
cf750e17ed | |||
712d1a7c37 | |||
16601f9359 | |||
b81e2e7a31 | |||
98fac36706 | |||
3e780c032e | |||
e09882180e | |||
0e18c57a17 | |||
51e2b9c073 | |||
f218e240d3 | |||
af6b219f8e | |||
20addf5f9f | |||
2860418a3c | |||
39e251eea7 | |||
d7d716d5db | |||
a95d65241c | |||
fdb22bd185 |
14
.github/ISSUE_TEMPLATE.md
vendored
14
.github/ISSUE_TEMPLATE.md
vendored
@ -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 ]
|
||||||
|
42
CHANGELOG.md
42
CHANGELOG.md
@ -1,3 +1,45 @@
|
|||||||
|
<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))
|
||||||
|
* **forms:** properly validate empty strings with patterns ([#11450](https://github.com/angular/angular/issues/11450)) ([e00de0c](https://github.com/angular/angular/commit/e00de0c))
|
||||||
|
* **http:** preserve case of the first init, `set()` or `append()` ([#12023](https://github.com/angular/angular/issues/12023)) ([adb17fe](https://github.com/angular/angular/commit/adb17fe)), closes [#11624](https://github.com/angular/angular/issues/11624)
|
||||||
|
* **compiler-cli:** allow ReflectorHost passed as argument to CodeGenerator#create ([#11951](https://github.com/angular/angular/issues/11951)) ([826c98e](https://github.com/angular/angular/commit/826c98e))
|
||||||
|
* **router:** do not reset the router state when updating the component ([#11867](https://github.com/angular/angular/issues/11867)) ([cf750e1](https://github.com/angular/angular/commit/cf750e1))
|
||||||
|
* **compiler:** fix `:host(tag)` and `:host-context(tag)` ([a6bb84e0](https://github.com/angular/angular/commit/a6bb84e02b7579f8d957ef6ba5b10d83482ed756)), closes [#11972](https://github.com/angular/angular/issues/11972)
|
||||||
|
* **compiler:** fix attribute selectors in :host and :host-context ([#12056](https://github.com/angular/angular/issues/12056)) ([6f7ed32](https://github.com/angular/angular/commit/6f7ed32)), closes [#11917](https://github.com/angular/angular/issues/11917)
|
||||||
|
* **compiler:** support `[@page](https://github.com/page)` and `[@document](https://github.com/document)` CSS rules ([#11878](https://github.com/angular/angular/issues/11878)) ([c99ef49](https://github.com/angular/angular/commit/c99ef49)), closes [#11860](https://github.com/angular/angular/issues/11860)
|
||||||
|
* **compiler:** support `[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)
|
||||||
|
* **upgrade:** bind optional properties when upgrading from ng1 ([#11411](https://github.com/angular/angular/issues/11411)) ([0851238](https://github.com/angular/angular/commit/0851238)), closes [#10181](https://github.com/angular/angular/issues/10181)
|
||||||
|
* **http:** change a behavior when a param value is null or undefined ([#11990](https://github.com/angular/angular/issues/11990)) ([9cc0a4e](https://github.com/angular/angular/commit/9cc0a4e))
|
||||||
|
* **compiler:** fix `<x>` ctype names ([7578d85](https://github.com/angular/angular/commit/7578d85)), closes [#12000](https://github.com/angular/angular/issues/12000)
|
||||||
|
|
||||||
|
|
||||||
|
<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)
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ 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]
|
If you have questions about how to *use* Angular, please direct them to the [Google Group][angular-group]
|
||||||
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].
|
discussion list or [StackOverflow][stackoverflow]. Please note that the Angular team's capacity to answer usage questions is limited. We are also available on [Gitter][gitter].
|
||||||
|
|
||||||
## <a name="issue"></a> Found an Issue?
|
## <a name="issue"></a> Found an Issue?
|
||||||
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
|
||||||
@ -28,8 +28,7 @@ If you find a bug in the source code, you can help us by
|
|||||||
## <a name="feature"></a> Want a Feature?
|
## <a name="feature"></a> Want 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][github]. 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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
[](http://issuestats.com/github/angular/angular)
|
[](http://issuestats.com/github/angular/angular)
|
||||||
[](http://issuestats.com/github/angular/angular)
|
[](http://issuestats.com/github/angular/angular)
|
||||||
[](https://badge.fury.io/js/%40angular%2Fcore)
|
[](https://badge.fury.io/js/%40angular%2Fcore)
|
||||||
[](https://npmjs.org/package/angular2)
|
|
||||||
|
|
||||||
[](https://saucelabs.com/u/angular2-ci)
|
[](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].*
|
||||||
|
@ -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: documentation`: `@naomiblack`
|
||||||
* `comp: packaging`: `@mhevery`
|
* `comp: packaging`: `@IgorMinar`
|
||||||
* `comp: performance`: `@tbosch`
|
* `comp: performance`: `@tbosch`
|
||||||
* `comp: security`: `@IgorMinar`
|
* `comp: security`: `@IgorMinar`
|
||||||
|
|
||||||
|
@ -1,6 +1,16 @@
|
|||||||
// 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}},
|
||||||
@ -22,195 +32,67 @@ var CIconfiguration = {
|
|||||||
'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}},
|
||||||
|
'Safari10': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||||
'iOS7': {unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}},
|
'iOS7': {unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}},
|
||||||
'iOS8': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
'iOS8': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||||
'iOS9': {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}}
|
'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)
|
||||||
};
|
};
|
||||||
@ -307,7 +173,5 @@ function buildConfiguration(type, target, required) {
|
|||||||
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();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
74
gulpfile.js
74
gulpfile.js
@ -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)
|
||||||
@ -33,8 +43,9 @@ gulp.task('format:enforce', () => {
|
|||||||
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
|
||||||
@ -107,14 +124,18 @@ gulp.task('public-api:update', ['build.sh'], (done) => {
|
|||||||
.on('close', done);
|
.on('close', done);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Checks tests for presence of ddescribe, fdescribe, fit, iit and fails the build if one of the focused tests is found.
|
// 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
|
||||||
|
.src([
|
||||||
'modules/**/*.spec.ts',
|
'modules/**/*.spec.ts',
|
||||||
'modules/**/*_spec.ts',
|
'modules/**/*_spec.ts',
|
||||||
]).pipe(ddescribeIit({allowDisabledTests: true}));
|
])
|
||||||
|
.pipe(ddescribeIit({allowDisabledTests: true}));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check the coding standards and programming errors
|
// Check the coding standards and programming errors
|
||||||
@ -123,7 +144,14 @@ 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
|
||||||
|
.src([
|
||||||
|
// todo(vicb): add .js files when supported
|
||||||
|
// see https://github.com/palantir/tslint/pull/1515
|
||||||
|
'modules/@angular/**/*.ts',
|
||||||
|
'modules/benchpress/**/*.ts',
|
||||||
|
'./*.ts',
|
||||||
|
])
|
||||||
.pipe(tslint({
|
.pipe(tslint({
|
||||||
tslint: require('tslint').default,
|
tslint: require('tslint').default,
|
||||||
configuration: tslintConfig,
|
configuration: tslintConfig,
|
||||||
@ -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) {
|
||||||
@ -187,10 +215,7 @@ 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',
|
|
||||||
releaseCount: 1
|
|
||||||
}, {
|
|
||||||
// Conventional Changelog Context
|
// Conventional Changelog Context
|
||||||
// We have to manually set version number so it doesn't get prefixed with `v`
|
// 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
|
// See https://github.com/conventional-changelog/conventional-changelog-core/issues/10
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,7 +91,7 @@ module.exports = function(config) {
|
|||||||
startTunnel: false,
|
startTunnel: false,
|
||||||
retryLimit: 3,
|
retryLimit: 3,
|
||||||
timeout: 600,
|
timeout: 600,
|
||||||
pollingTimeout: 10000
|
pollingTimeout: 10000,
|
||||||
},
|
},
|
||||||
|
|
||||||
browsers: ['Chrome'],
|
browsers: ['Chrome'],
|
||||||
@ -95,7 +104,8 @@ module.exports = function(config) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
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;
|
||||||
|
@ -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},
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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';
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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';
|
||||||
|
@ -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]; });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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';
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) => {
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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[] = [
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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'])
|
||||||
|
@ -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([
|
||||||
|
@ -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(
|
||||||
@ -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 {
|
||||||
|
@ -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() {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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 {Options, ReflectiveInjector, WebDriverExtension} from '../index';
|
import {Options, ReflectiveInjector, WebDriverExtension} from '../index';
|
||||||
import {StringWrapper, isPresent} from '../src/facade/lang';
|
import {StringWrapper, isPresent} from '../src/facade/lang';
|
||||||
@ -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)
|
||||||
])
|
])
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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};
|
||||||
|
@ -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'
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
@ -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',
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
@ -67,7 +67,7 @@ export enum Plural {
|
|||||||
Two,
|
Two,
|
||||||
Few,
|
Few,
|
||||||
Many,
|
Many,
|
||||||
Other
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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,
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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', () => {
|
||||||
|
@ -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';
|
||||||
|
@ -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) => {
|
||||||
|
@ -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');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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', () => {
|
||||||
|
@ -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', () => {
|
||||||
|
@ -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', () => {
|
||||||
|
@ -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() {
|
||||||
|
@ -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() {
|
||||||
|
@ -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', () => {
|
||||||
|
@ -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() {
|
||||||
|
@ -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();
|
||||||
|
@ -36,7 +36,8 @@ 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">
|
||||||
@ -54,7 +55,8 @@ const EXPECTED_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>`;
|
</xliff>
|
||||||
|
`;
|
||||||
|
|
||||||
describe('template i18n extraction output', () => {
|
describe('template i18n extraction output', () => {
|
||||||
const outDir = '';
|
const outDir = '';
|
||||||
|
@ -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']
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"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",
|
"parse5": "^2.2.1",
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
@ -126,7 +126,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 +148,12 @@ export class CodeGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
|
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
|
||||||
|
if (!reflectorHost) {
|
||||||
const usePathMapping = !!options.rootDirs && options.rootDirs.length > 0;
|
const usePathMapping = !!options.rootDirs && options.rootDirs.length > 0;
|
||||||
const reflectorHost = usePathMapping ?
|
reflectorHost = usePathMapping ?
|
||||||
new PathMappedReflectorHost(program, compilerHost, options, reflectorHostContext) :
|
new PathMappedReflectorHost(program, compilerHost, options, reflectorHostContext) :
|
||||||
new ReflectorHost(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 =
|
||||||
|
@ -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';
|
||||||
|
|
||||||
|
@ -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';
|
||||||
|
@ -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';
|
||||||
|
|
||||||
@ -454,7 +453,7 @@ class MockReflectorHost implements StaticReflectorHost {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -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'
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
@ -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 }),
|
||||||
]
|
]
|
||||||
}
|
};
|
||||||
|
@ -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,7 @@ class _AnimationBuilder implements AnimationAstVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ast.styles.forEach(entry => {
|
ast.styles.forEach(entry => {
|
||||||
stylesArr.push(
|
stylesArr.push(o.literalMap(Object.keys(entry).map(key => [key, o.literal(entry[key])])));
|
||||||
o.literalMap(StringMapWrapper.keys(entry).map(key => [key, o.literal(entry[key])])));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return o.importExpr(resolveIdentifier(Identifiers.AnimationStyles)).instantiate([
|
return o.importExpr(resolveIdentifier(Identifiers.AnimationStyles)).instantiate([
|
||||||
@ -182,9 +132,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 +283,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 +319,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 +345,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 +353,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 {}
|
|
||||||
}
|
|
||||||
|
@ -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,21 +20,58 @@ 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 {
|
||||||
|
parseComponent(component: CompileDirectiveMetadata): AnimationEntryAst[] {
|
||||||
|
const errors: string[] = [];
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (errors.length > 0) {
|
||||||
|
const errorString = errors.join('\n');
|
||||||
|
throw new Error(`Animation parse errors:\n${errorString}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return asts;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseEntry(entry: CompileAnimationEntryMetadata): AnimationEntryParseResult {
|
||||||
var errors: AnimationParseError[] = [];
|
var errors: AnimationParseError[] = [];
|
||||||
var stateStyles: {[key: string]: AnimationStylesAst} = {};
|
var stateStyles: {[key: string]: AnimationStylesAst} = {};
|
||||||
var transitions: CompileAnimationStateTransitionMetadata[] = [];
|
var transitions: CompileAnimationStateTransitionMetadata[] = [];
|
||||||
|
|
||||||
var stateDeclarationAsts: any[] /** TODO #9100 */ = [];
|
var stateDeclarationAsts: AnimationStateDeclarationAst[] = [];
|
||||||
entry.definitions.forEach(def => {
|
entry.definitions.forEach(def => {
|
||||||
if (def instanceof CompileAnimationStateDeclarationMetadata) {
|
if (def instanceof CompileAnimationStateDeclarationMetadata) {
|
||||||
_parseAnimationDeclarationStates(def, errors).forEach(ast => {
|
_parseAnimationDeclarationStates(def, errors).forEach(ast => {
|
||||||
@ -50,43 +87,18 @@ export function parseAnimationEntry(entry: CompileAnimationEntryMetadata): Parse
|
|||||||
transitions.map(transDef => _parseAnimationStateTransition(transDef, stateStyles, errors));
|
transitions.map(transDef => _parseAnimationStateTransition(transDef, stateStyles, errors));
|
||||||
|
|
||||||
var ast = new AnimationEntryAst(entry.name, stateDeclarationAsts, stateTransitionAsts);
|
var ast = new AnimationEntryAst(entry.name, stateDeclarationAsts, stateTransitionAsts);
|
||||||
return new ParsedAnimationResult(ast, errors);
|
return new AnimationEntryParseResult(ast, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseAnimationOutputName(
|
|
||||||
outputName: string, errors: AnimationParseError[]): AnimationOutput {
|
|
||||||
var values = outputName.split('.');
|
|
||||||
var name: string;
|
|
||||||
var phase: string = '';
|
|
||||||
if (values.length > 1) {
|
|
||||||
name = values[0];
|
|
||||||
let parsedPhase = values[1];
|
|
||||||
switch (parsedPhase) {
|
|
||||||
case 'start':
|
|
||||||
case 'done':
|
|
||||||
phase = parsedPhase;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
errors.push(new AnimationParseError(
|
|
||||||
`The provided animation output phase value "${parsedPhase}" for "@${name}" is not supported (use start or done)`));
|
|
||||||
}
|
|
||||||
} 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`));
|
||||||
@ -145,16 +157,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) :
|
||||||
@ -210,7 +212,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 +268,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 +280,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,13 +314,11 @@ 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,
|
|
||||||
(value: any /** TODO #9100 */, prop: any /** TODO #9100 */) => {
|
|
||||||
if (prop != 'offset') {
|
if (prop != 'offset') {
|
||||||
keyframeStyles[prop] = value;
|
keyframeStyles[prop] = (entry as Styles)[prop];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -357,8 +357,7 @@ function _parseAnimationKeyframes(
|
|||||||
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;
|
||||||
}
|
}
|
||||||
@ -369,10 +368,9 @@ function _parseAnimationKeyframes(
|
|||||||
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] = value;
|
lastKeyframeStyles[prop] = styles[prop];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -398,11 +396,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 +444,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 +456,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 +530,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);
|
||||||
|
@ -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 {
|
||||||
@ -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;
|
||||||
|
@ -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';
|
||||||
|
@ -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 {StringWrapper, isPresent} from '../facade/lang';
|
||||||
|
|
||||||
export enum CssTokenType {
|
export enum CssTokenType {
|
||||||
EOF,
|
EOF,
|
||||||
@ -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 + '")';
|
||||||
|
@ -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
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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,57 @@ 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) {
|
||||||
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 +90,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 +105,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 +122,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;
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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}`;
|
||||||
|
}
|
||||||
|
}
|
@ -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(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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, '&'],
|
[/&/g, '&'],
|
||||||
[/"/g, '"'],
|
[/"/g, '"'],
|
||||||
|
@ -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) {
|
||||||
|
@ -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));
|
||||||
|
@ -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';
|
||||||
@ -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);
|
||||||
|
@ -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';
|
||||||
@ -28,6 +30,9 @@ export class NgModulesSummary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
@ -162,14 +167,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;
|
||||||
}
|
}
|
||||||
|
@ -400,7 +400,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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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';
|
||||||
|
@ -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 = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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:([^\/]+)\/([^\/]+)\/(.+)/;
|
||||||
|
|
||||||
|
@ -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';
|
||||||
@ -24,9 +23,7 @@ class _ValueOutputAstTransformer implements ValueTransformer {
|
|||||||
|
|
||||||
visitStringMap(map: {[key: string]: any}, type: o.MapType): o.Expression {
|
visitStringMap(map: {[key: string]: any}, type: o.MapType): o.Expression {
|
||||||
var entries: Array<string|o.Expression>[] = [];
|
var entries: Array<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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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) => {
|
||||||
@ -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,8 +136,7 @@ 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 ||
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
@ -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);
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -344,4 +344,26 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry {
|
|||||||
getMappedPropName(propName: string): string { return _ATTR_TO_PROP[propName] || propName; }
|
getMappedPropName(propName: string): string { return _ATTR_TO_PROP[propName] || propName; }
|
||||||
|
|
||||||
getDefaultComponentElementName(): string { return 'ng-component'; }
|
getDefaultComponentElementName(): string { return 'ng-component'; }
|
||||||
|
|
||||||
|
validateProperty(name: string): {error: boolean, msg?: string} {
|
||||||
|
if (name.toLowerCase().startsWith('on')) {
|
||||||
|
const msg = `Binding to event property '${name}' is disallowed for security reasons, ` +
|
||||||
|
`please use (${name.slice(2)})=...` +
|
||||||
|
`\nIf '${name}' is a directive input, make sure the directive is imported by the` +
|
||||||
|
` current module.`;
|
||||||
|
return {error: true, msg: msg};
|
||||||
|
} else {
|
||||||
|
return {error: false};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateAttribute(name: string): {error: boolean, msg?: string} {
|
||||||
|
if (name.toLowerCase().startsWith('on')) {
|
||||||
|
const msg = `Binding to event attribute '${name}' is disallowed for security reasons, ` +
|
||||||
|
`please use (${name.slice(2)})=...`;
|
||||||
|
return {error: true, msg: msg};
|
||||||
|
} else {
|
||||||
|
return {error: false};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,6 @@ export abstract class ElementSchemaRegistry {
|
|||||||
abstract securityContext(tagName: string, propName: string): any;
|
abstract securityContext(tagName: string, propName: string): any;
|
||||||
abstract getMappedPropName(propName: string): string;
|
abstract getMappedPropName(propName: string): string;
|
||||||
abstract getDefaultComponentElementName(): string;
|
abstract getDefaultComponentElementName(): string;
|
||||||
|
abstract validateProperty(name: string): {error: boolean, msg?: string};
|
||||||
|
abstract validateAttribute(name: string): {error: boolean, msg?: string};
|
||||||
}
|
}
|
||||||
|
@ -6,18 +6,13 @@
|
|||||||
* 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 {StringWrapper, isBlank, isPresent} from './facade/lang';
|
|
||||||
import {getHtmlTagDefinition} from './ml_parser/html_tags';
|
import {getHtmlTagDefinition} from './ml_parser/html_tags';
|
||||||
|
|
||||||
const _EMPTY_ATTR_VALUE = '';
|
|
||||||
|
|
||||||
const _SELECTOR_REGEXP = new RegExp(
|
const _SELECTOR_REGEXP = new RegExp(
|
||||||
'(\\:not\\()|' + //":not("
|
'(\\:not\\()|' + //":not("
|
||||||
'([-\\w]+)|' + // "tag"
|
'([-\\w]+)|' + // "tag"
|
||||||
'(?:\\.([-\\w]+))|' + // ".class"
|
'(?:\\.([-\\w]+))|' + // ".class"
|
||||||
'(?:\\[([-\\w*]+)(?:=([^\\]]*))?\\])|' + // "[name]", "[name=value]" or "[name*=value]"
|
'(?:\\[([-\\w*]+)(?:=([^\\]]*))?\\])|' + // "[name]", "[name=value]"
|
||||||
'(\\))|' + // ")"
|
'(\\))|' + // ")"
|
||||||
'(\\s*,\\s*)', // ","
|
'(\\s*,\\s*)', // ","
|
||||||
'g');
|
'g');
|
||||||
@ -34,21 +29,21 @@ export class CssSelector {
|
|||||||
notSelectors: CssSelector[] = [];
|
notSelectors: CssSelector[] = [];
|
||||||
|
|
||||||
static parse(selector: string): CssSelector[] {
|
static parse(selector: string): CssSelector[] {
|
||||||
var results: CssSelector[] = [];
|
const results: CssSelector[] = [];
|
||||||
var _addResult = (res: CssSelector[], cssSel: CssSelector) => {
|
const _addResult = (res: CssSelector[], cssSel: CssSelector) => {
|
||||||
if (cssSel.notSelectors.length > 0 && isBlank(cssSel.element) &&
|
if (cssSel.notSelectors.length > 0 && !cssSel.element && cssSel.classNames.length == 0 &&
|
||||||
ListWrapper.isEmpty(cssSel.classNames) && ListWrapper.isEmpty(cssSel.attrs)) {
|
cssSel.attrs.length == 0) {
|
||||||
cssSel.element = '*';
|
cssSel.element = '*';
|
||||||
}
|
}
|
||||||
res.push(cssSel);
|
res.push(cssSel);
|
||||||
};
|
};
|
||||||
var cssSelector = new CssSelector();
|
let cssSelector = new CssSelector();
|
||||||
var match: string[];
|
let match: string[];
|
||||||
var current = cssSelector;
|
let current = cssSelector;
|
||||||
var inNot = false;
|
let inNot = false;
|
||||||
_SELECTOR_REGEXP.lastIndex = 0;
|
_SELECTOR_REGEXP.lastIndex = 0;
|
||||||
while (isPresent(match = _SELECTOR_REGEXP.exec(selector))) {
|
while (match = _SELECTOR_REGEXP.exec(selector)) {
|
||||||
if (isPresent(match[1])) {
|
if (match[1]) {
|
||||||
if (inNot) {
|
if (inNot) {
|
||||||
throw new Error('Nesting :not is not allowed in a selector');
|
throw new Error('Nesting :not is not allowed in a selector');
|
||||||
}
|
}
|
||||||
@ -56,20 +51,20 @@ export class CssSelector {
|
|||||||
current = new CssSelector();
|
current = new CssSelector();
|
||||||
cssSelector.notSelectors.push(current);
|
cssSelector.notSelectors.push(current);
|
||||||
}
|
}
|
||||||
if (isPresent(match[2])) {
|
if (match[2]) {
|
||||||
current.setElement(match[2]);
|
current.setElement(match[2]);
|
||||||
}
|
}
|
||||||
if (isPresent(match[3])) {
|
if (match[3]) {
|
||||||
current.addClassName(match[3]);
|
current.addClassName(match[3]);
|
||||||
}
|
}
|
||||||
if (isPresent(match[4])) {
|
if (match[4]) {
|
||||||
current.addAttribute(match[4], match[5]);
|
current.addAttribute(match[4], match[5]);
|
||||||
}
|
}
|
||||||
if (isPresent(match[6])) {
|
if (match[6]) {
|
||||||
inNot = false;
|
inNot = false;
|
||||||
current = cssSelector;
|
current = cssSelector;
|
||||||
}
|
}
|
||||||
if (isPresent(match[7])) {
|
if (match[7]) {
|
||||||
if (inNot) {
|
if (inNot) {
|
||||||
throw new Error('Multiple selectors in :not are not supported');
|
throw new Error('Multiple selectors in :not are not supported');
|
||||||
}
|
}
|
||||||
@ -106,37 +101,22 @@ export class CssSelector {
|
|||||||
`<${tagName}${classAttr}${attrs}></${tagName}>`;
|
`<${tagName}${classAttr}${attrs}></${tagName}>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
addAttribute(name: string, value: string = _EMPTY_ATTR_VALUE) {
|
addAttribute(name: string, value: string = '') {
|
||||||
this.attrs.push(name);
|
this.attrs.push(name, value && value.toLowerCase() || '');
|
||||||
if (isPresent(value)) {
|
|
||||||
value = value.toLowerCase();
|
|
||||||
} else {
|
|
||||||
value = _EMPTY_ATTR_VALUE;
|
|
||||||
}
|
|
||||||
this.attrs.push(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addClassName(name: string) { this.classNames.push(name.toLowerCase()); }
|
addClassName(name: string) { this.classNames.push(name.toLowerCase()); }
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
var res = '';
|
let res: string = this.element || '';
|
||||||
if (isPresent(this.element)) {
|
if (this.classNames) {
|
||||||
res += this.element;
|
this.classNames.forEach(klass => res += `.${klass}`);
|
||||||
}
|
}
|
||||||
if (isPresent(this.classNames)) {
|
if (this.attrs) {
|
||||||
for (var i = 0; i < this.classNames.length; i++) {
|
for (let i = 0; i < this.attrs.length; i += 2) {
|
||||||
res += '.' + this.classNames[i];
|
const name = this.attrs[i];
|
||||||
}
|
const value = this.attrs[i + 1];
|
||||||
}
|
res += `[${name}${value ? '=' + value : ''}]`;
|
||||||
if (isPresent(this.attrs)) {
|
|
||||||
for (var i = 0; i < this.attrs.length;) {
|
|
||||||
var attrName = this.attrs[i++];
|
|
||||||
var attrValue = this.attrs[i++];
|
|
||||||
res += '[' + attrName;
|
|
||||||
if (attrValue.length > 0) {
|
|
||||||
res += '=' + attrValue;
|
|
||||||
}
|
|
||||||
res += ']';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.notSelectors.forEach(notSelector => res += `:not(${notSelector})`);
|
this.notSelectors.forEach(notSelector => res += `:not(${notSelector})`);
|
||||||
@ -150,26 +130,26 @@ export class CssSelector {
|
|||||||
*/
|
*/
|
||||||
export class SelectorMatcher {
|
export class SelectorMatcher {
|
||||||
static createNotMatcher(notSelectors: CssSelector[]): SelectorMatcher {
|
static createNotMatcher(notSelectors: CssSelector[]): SelectorMatcher {
|
||||||
var notMatcher = new SelectorMatcher();
|
const notMatcher = new SelectorMatcher();
|
||||||
notMatcher.addSelectables(notSelectors, null);
|
notMatcher.addSelectables(notSelectors, null);
|
||||||
return notMatcher;
|
return notMatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _elementMap = new Map<string, SelectorContext[]>();
|
private _elementMap: {[k: string]: SelectorContext[]} = {};
|
||||||
private _elementPartialMap = new Map<string, SelectorMatcher>();
|
private _elementPartialMap: {[k: string]: SelectorMatcher} = {};
|
||||||
private _classMap = new Map<string, SelectorContext[]>();
|
private _classMap: {[k: string]: SelectorContext[]} = {};
|
||||||
private _classPartialMap = new Map<string, SelectorMatcher>();
|
private _classPartialMap: {[k: string]: SelectorMatcher} = {};
|
||||||
private _attrValueMap = new Map<string, Map<string, SelectorContext[]>>();
|
private _attrValueMap: {[k: string]: {[k: string]: SelectorContext[]}} = {};
|
||||||
private _attrValuePartialMap = new Map<string, Map<string, SelectorMatcher>>();
|
private _attrValuePartialMap: {[k: string]: {[k: string]: SelectorMatcher}} = {};
|
||||||
private _listContexts: SelectorListContext[] = [];
|
private _listContexts: SelectorListContext[] = [];
|
||||||
|
|
||||||
addSelectables(cssSelectors: CssSelector[], callbackCtxt?: any) {
|
addSelectables(cssSelectors: CssSelector[], callbackCtxt?: any) {
|
||||||
var listContext: SelectorListContext = null;
|
let listContext: SelectorListContext = null;
|
||||||
if (cssSelectors.length > 1) {
|
if (cssSelectors.length > 1) {
|
||||||
listContext = new SelectorListContext(cssSelectors);
|
listContext = new SelectorListContext(cssSelectors);
|
||||||
this._listContexts.push(listContext);
|
this._listContexts.push(listContext);
|
||||||
}
|
}
|
||||||
for (var i = 0; i < cssSelectors.length; i++) {
|
for (let i = 0; i < cssSelectors.length; i++) {
|
||||||
this._addSelectable(cssSelectors[i], callbackCtxt, listContext);
|
this._addSelectable(cssSelectors[i], callbackCtxt, listContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -181,14 +161,14 @@ export class SelectorMatcher {
|
|||||||
*/
|
*/
|
||||||
private _addSelectable(
|
private _addSelectable(
|
||||||
cssSelector: CssSelector, callbackCtxt: any, listContext: SelectorListContext) {
|
cssSelector: CssSelector, callbackCtxt: any, listContext: SelectorListContext) {
|
||||||
var matcher: SelectorMatcher = this;
|
let matcher: SelectorMatcher = this;
|
||||||
var element = cssSelector.element;
|
const element = cssSelector.element;
|
||||||
var classNames = cssSelector.classNames;
|
const classNames = cssSelector.classNames;
|
||||||
var attrs = cssSelector.attrs;
|
const attrs = cssSelector.attrs;
|
||||||
var selectable = new SelectorContext(cssSelector, callbackCtxt, listContext);
|
const selectable = new SelectorContext(cssSelector, callbackCtxt, listContext);
|
||||||
|
|
||||||
if (isPresent(element)) {
|
if (element) {
|
||||||
var isTerminal = attrs.length === 0 && classNames.length === 0;
|
const isTerminal = attrs.length === 0 && classNames.length === 0;
|
||||||
if (isTerminal) {
|
if (isTerminal) {
|
||||||
this._addTerminal(matcher._elementMap, element, selectable);
|
this._addTerminal(matcher._elementMap, element, selectable);
|
||||||
} else {
|
} else {
|
||||||
@ -196,10 +176,10 @@ export class SelectorMatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPresent(classNames)) {
|
if (classNames) {
|
||||||
for (var index = 0; index < classNames.length; index++) {
|
for (let i = 0; i < classNames.length; i++) {
|
||||||
var isTerminal = attrs.length === 0 && index === classNames.length - 1;
|
const isTerminal = attrs.length === 0 && i === classNames.length - 1;
|
||||||
var className = classNames[index];
|
const className = classNames[i];
|
||||||
if (isTerminal) {
|
if (isTerminal) {
|
||||||
this._addTerminal(matcher._classMap, className, selectable);
|
this._addTerminal(matcher._classMap, className, selectable);
|
||||||
} else {
|
} else {
|
||||||
@ -208,47 +188,47 @@ export class SelectorMatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPresent(attrs)) {
|
if (attrs) {
|
||||||
for (var index = 0; index < attrs.length;) {
|
for (let i = 0; i < attrs.length; i += 2) {
|
||||||
var isTerminal = index === attrs.length - 2;
|
const isTerminal = i === attrs.length - 2;
|
||||||
var attrName = attrs[index++];
|
const name = attrs[i];
|
||||||
var attrValue = attrs[index++];
|
const value = attrs[i + 1];
|
||||||
if (isTerminal) {
|
if (isTerminal) {
|
||||||
var terminalMap = matcher._attrValueMap;
|
const terminalMap = matcher._attrValueMap;
|
||||||
var terminalValuesMap = terminalMap.get(attrName);
|
let terminalValuesMap = terminalMap[name];
|
||||||
if (isBlank(terminalValuesMap)) {
|
if (!terminalValuesMap) {
|
||||||
terminalValuesMap = new Map<string, SelectorContext[]>();
|
terminalValuesMap = {};
|
||||||
terminalMap.set(attrName, terminalValuesMap);
|
terminalMap[name] = terminalValuesMap;
|
||||||
}
|
}
|
||||||
this._addTerminal(terminalValuesMap, attrValue, selectable);
|
this._addTerminal(terminalValuesMap, value, selectable);
|
||||||
} else {
|
} else {
|
||||||
var parttialMap = matcher._attrValuePartialMap;
|
let partialMap = matcher._attrValuePartialMap;
|
||||||
var partialValuesMap = parttialMap.get(attrName);
|
let partialValuesMap = partialMap[name];
|
||||||
if (isBlank(partialValuesMap)) {
|
if (!partialValuesMap) {
|
||||||
partialValuesMap = new Map<string, SelectorMatcher>();
|
partialValuesMap = {};
|
||||||
parttialMap.set(attrName, partialValuesMap);
|
partialMap[name] = partialValuesMap;
|
||||||
}
|
}
|
||||||
matcher = this._addPartial(partialValuesMap, attrValue);
|
matcher = this._addPartial(partialValuesMap, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _addTerminal(
|
private _addTerminal(
|
||||||
map: Map<string, SelectorContext[]>, name: string, selectable: SelectorContext) {
|
map: {[k: string]: SelectorContext[]}, name: string, selectable: SelectorContext) {
|
||||||
var terminalList = map.get(name);
|
let terminalList = map[name];
|
||||||
if (isBlank(terminalList)) {
|
if (!terminalList) {
|
||||||
terminalList = [];
|
terminalList = [];
|
||||||
map.set(name, terminalList);
|
map[name] = terminalList;
|
||||||
}
|
}
|
||||||
terminalList.push(selectable);
|
terminalList.push(selectable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _addPartial(map: Map<string, SelectorMatcher>, name: string): SelectorMatcher {
|
private _addPartial(map: {[k: string]: SelectorMatcher}, name: string): SelectorMatcher {
|
||||||
var matcher = map.get(name);
|
let matcher = map[name];
|
||||||
if (isBlank(matcher)) {
|
if (!matcher) {
|
||||||
matcher = new SelectorMatcher();
|
matcher = new SelectorMatcher();
|
||||||
map.set(name, matcher);
|
map[name] = matcher;
|
||||||
}
|
}
|
||||||
return matcher;
|
return matcher;
|
||||||
}
|
}
|
||||||
@ -261,12 +241,12 @@ export class SelectorMatcher {
|
|||||||
* @return boolean true if a match was found
|
* @return boolean true if a match was found
|
||||||
*/
|
*/
|
||||||
match(cssSelector: CssSelector, matchedCallback: (c: CssSelector, a: any) => void): boolean {
|
match(cssSelector: CssSelector, matchedCallback: (c: CssSelector, a: any) => void): boolean {
|
||||||
var result = false;
|
let result = false;
|
||||||
var element = cssSelector.element;
|
const element = cssSelector.element;
|
||||||
var classNames = cssSelector.classNames;
|
const classNames = cssSelector.classNames;
|
||||||
var attrs = cssSelector.attrs;
|
const attrs = cssSelector.attrs;
|
||||||
|
|
||||||
for (var i = 0; i < this._listContexts.length; i++) {
|
for (let i = 0; i < this._listContexts.length; i++) {
|
||||||
this._listContexts[i].alreadyMatched = false;
|
this._listContexts[i].alreadyMatched = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,9 +254,9 @@ export class SelectorMatcher {
|
|||||||
result = this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) ||
|
result = this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) ||
|
||||||
result;
|
result;
|
||||||
|
|
||||||
if (isPresent(classNames)) {
|
if (classNames) {
|
||||||
for (var index = 0; index < classNames.length; index++) {
|
for (let i = 0; i < classNames.length; i++) {
|
||||||
var className = classNames[index];
|
const className = classNames[i];
|
||||||
result =
|
result =
|
||||||
this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result;
|
this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result;
|
||||||
result =
|
result =
|
||||||
@ -285,28 +265,25 @@ export class SelectorMatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPresent(attrs)) {
|
if (attrs) {
|
||||||
for (var index = 0; index < attrs.length;) {
|
for (let i = 0; i < attrs.length; i += 2) {
|
||||||
var attrName = attrs[index++];
|
const name = attrs[i];
|
||||||
var attrValue = attrs[index++];
|
const value = attrs[i + 1];
|
||||||
|
|
||||||
var terminalValuesMap = this._attrValueMap.get(attrName);
|
const terminalValuesMap = this._attrValueMap[name];
|
||||||
if (!StringWrapper.equals(attrValue, _EMPTY_ATTR_VALUE)) {
|
if (value) {
|
||||||
result = this._matchTerminal(
|
result =
|
||||||
terminalValuesMap, _EMPTY_ATTR_VALUE, cssSelector, matchedCallback) ||
|
this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result;
|
||||||
result;
|
|
||||||
}
|
|
||||||
result = this._matchTerminal(terminalValuesMap, attrValue, cssSelector, matchedCallback) ||
|
|
||||||
result;
|
|
||||||
|
|
||||||
var partialValuesMap = this._attrValuePartialMap.get(attrName);
|
|
||||||
if (!StringWrapper.equals(attrValue, _EMPTY_ATTR_VALUE)) {
|
|
||||||
result = this._matchPartial(
|
|
||||||
partialValuesMap, _EMPTY_ATTR_VALUE, cssSelector, matchedCallback) ||
|
|
||||||
result;
|
|
||||||
}
|
}
|
||||||
result =
|
result =
|
||||||
this._matchPartial(partialValuesMap, attrValue, cssSelector, matchedCallback) || result;
|
this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result;
|
||||||
|
|
||||||
|
const partialValuesMap = this._attrValuePartialMap[name];
|
||||||
|
if (value) {
|
||||||
|
result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result;
|
||||||
|
}
|
||||||
|
result =
|
||||||
|
this._matchPartial(partialValuesMap, value, cssSelector, matchedCallback) || result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -314,24 +291,24 @@ export class SelectorMatcher {
|
|||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_matchTerminal(
|
_matchTerminal(
|
||||||
map: Map<string, SelectorContext[]>, name: string, cssSelector: CssSelector,
|
map: {[k: string]: SelectorContext[]}, name: string, cssSelector: CssSelector,
|
||||||
matchedCallback: (c: CssSelector, a: any) => void): boolean {
|
matchedCallback: (c: CssSelector, a: any) => void): boolean {
|
||||||
if (isBlank(map) || isBlank(name)) {
|
if (!map || typeof name !== 'string') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectables = map.get(name);
|
let selectables = map[name];
|
||||||
var starSelectables = map.get('*');
|
const starSelectables = map['*'];
|
||||||
if (isPresent(starSelectables)) {
|
if (starSelectables) {
|
||||||
selectables = selectables.concat(starSelectables);
|
selectables = selectables.concat(starSelectables);
|
||||||
}
|
}
|
||||||
if (isBlank(selectables)) {
|
if (!selectables) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var selectable: SelectorContext;
|
let selectable: SelectorContext;
|
||||||
var result = false;
|
let result = false;
|
||||||
for (var index = 0; index < selectables.length; index++) {
|
for (let i = 0; i < selectables.length; i++) {
|
||||||
selectable = selectables[index];
|
selectable = selectables[i];
|
||||||
result = selectable.finalize(cssSelector, matchedCallback) || result;
|
result = selectable.finalize(cssSelector, matchedCallback) || result;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -339,13 +316,14 @@ export class SelectorMatcher {
|
|||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_matchPartial(
|
_matchPartial(
|
||||||
map: Map<string, SelectorMatcher>, name: string, cssSelector: CssSelector,
|
map: {[k: string]: SelectorMatcher}, name: string, cssSelector: CssSelector,
|
||||||
matchedCallback: (c: CssSelector, a: any) => void): boolean {
|
matchedCallback: (c: CssSelector, a: any) => void): boolean {
|
||||||
if (isBlank(map) || isBlank(name)) {
|
if (!map || typeof name !== 'string') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var nestedSelector = map.get(name);
|
|
||||||
if (isBlank(nestedSelector)) {
|
const nestedSelector = map[name];
|
||||||
|
if (!nestedSelector) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// TODO(perf): get rid of recursion and measure again
|
// TODO(perf): get rid of recursion and measure again
|
||||||
@ -373,15 +351,13 @@ export class SelectorContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
finalize(cssSelector: CssSelector, callback: (c: CssSelector, a: any) => void): boolean {
|
finalize(cssSelector: CssSelector, callback: (c: CssSelector, a: any) => void): boolean {
|
||||||
var result = true;
|
let result = true;
|
||||||
if (this.notSelectors.length > 0 &&
|
if (this.notSelectors.length > 0 && (!this.listContext || !this.listContext.alreadyMatched)) {
|
||||||
(isBlank(this.listContext) || !this.listContext.alreadyMatched)) {
|
const notMatcher = SelectorMatcher.createNotMatcher(this.notSelectors);
|
||||||
var notMatcher = SelectorMatcher.createNotMatcher(this.notSelectors);
|
|
||||||
result = !notMatcher.match(cssSelector, null);
|
result = !notMatcher.match(cssSelector, null);
|
||||||
}
|
}
|
||||||
if (result && isPresent(callback) &&
|
if (result && callback && (!this.listContext || !this.listContext.alreadyMatched)) {
|
||||||
(isBlank(this.listContext) || !this.listContext.alreadyMatched)) {
|
if (this.listContext) {
|
||||||
if (isPresent(this.listContext)) {
|
|
||||||
this.listContext.alreadyMatched = true;
|
this.listContext.alreadyMatched = true;
|
||||||
}
|
}
|
||||||
callback(this.selector, this.cbContext);
|
callback(this.selector, this.cbContext);
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {StringWrapper, isBlank, isPresent} from './facade/lang';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is a port of shadowCSS from webcomponents.js to TypeScript.
|
* This file is a port of shadowCSS from webcomponents.js to TypeScript.
|
||||||
*
|
*
|
||||||
@ -175,9 +173,8 @@ export class ShadowCss {
|
|||||||
**/
|
**/
|
||||||
private _insertPolyfillDirectivesInCssText(cssText: string): string {
|
private _insertPolyfillDirectivesInCssText(cssText: string): string {
|
||||||
// Difference with webcomponents.js: does not handle comments
|
// Difference with webcomponents.js: does not handle comments
|
||||||
return StringWrapper.replaceAllMapped(
|
return cssText.replace(
|
||||||
cssText, _cssContentNextSelectorRe,
|
_cssContentNextSelectorRe, function(...m: string[]) { return m[2] + '{'; });
|
||||||
function(m: any /** TODO #9100 */) { return m[1] + '{'; });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -197,12 +194,9 @@ export class ShadowCss {
|
|||||||
**/
|
**/
|
||||||
private _insertPolyfillRulesInCssText(cssText: string): string {
|
private _insertPolyfillRulesInCssText(cssText: string): string {
|
||||||
// Difference with webcomponents.js: does not handle comments
|
// Difference with webcomponents.js: does not handle comments
|
||||||
return StringWrapper.replaceAllMapped(
|
return cssText.replace(_cssContentRuleRe, (...m: string[]) => {
|
||||||
cssText, _cssContentRuleRe, function(m: any /** TODO #9100 */) {
|
const rule = m[0].replace(m[1], '').replace(m[2], '');
|
||||||
let rule = m[0];
|
return m[4] + rule;
|
||||||
rule = StringWrapper.replace(rule, m[1], '');
|
|
||||||
rule = StringWrapper.replace(rule, m[2], '');
|
|
||||||
return m[3] + rule;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,15 +209,16 @@ export class ShadowCss {
|
|||||||
* scopeName .foo { ... }
|
* scopeName .foo { ... }
|
||||||
*/
|
*/
|
||||||
private _scopeCssText(cssText: string, scopeSelector: string, hostSelector: string): string {
|
private _scopeCssText(cssText: string, scopeSelector: string, hostSelector: string): string {
|
||||||
const unscoped = this._extractUnscopedRulesFromCssText(cssText);
|
const unscopedRules = this._extractUnscopedRulesFromCssText(cssText);
|
||||||
|
// replace :host and :host-context -shadowcsshost and -shadowcsshost respectively
|
||||||
cssText = this._insertPolyfillHostInCssText(cssText);
|
cssText = this._insertPolyfillHostInCssText(cssText);
|
||||||
cssText = this._convertColonHost(cssText);
|
cssText = this._convertColonHost(cssText);
|
||||||
cssText = this._convertColonHostContext(cssText);
|
cssText = this._convertColonHostContext(cssText);
|
||||||
cssText = this._convertShadowDOMSelectors(cssText);
|
cssText = this._convertShadowDOMSelectors(cssText);
|
||||||
if (isPresent(scopeSelector)) {
|
if (scopeSelector) {
|
||||||
cssText = this._scopeSelectors(cssText, scopeSelector, hostSelector);
|
cssText = this._scopeSelectors(cssText, scopeSelector, hostSelector);
|
||||||
}
|
}
|
||||||
cssText = cssText + '\n' + unscoped;
|
cssText = cssText + '\n' + unscopedRules;
|
||||||
return cssText.trim();
|
return cssText.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,9 +243,7 @@ export class ShadowCss {
|
|||||||
let m: RegExpExecArray;
|
let m: RegExpExecArray;
|
||||||
_cssContentUnscopedRuleRe.lastIndex = 0;
|
_cssContentUnscopedRuleRe.lastIndex = 0;
|
||||||
while ((m = _cssContentUnscopedRuleRe.exec(cssText)) !== null) {
|
while ((m = _cssContentUnscopedRuleRe.exec(cssText)) !== null) {
|
||||||
let rule = m[0];
|
const rule = m[0].replace(m[2], '').replace(m[1], m[4]);
|
||||||
rule = StringWrapper.replace(rule, m[2], '');
|
|
||||||
rule = StringWrapper.replace(rule, m[1], m[3]);
|
|
||||||
r += rule + '\n\n';
|
r += rule + '\n\n';
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
@ -261,7 +254,7 @@ export class ShadowCss {
|
|||||||
*
|
*
|
||||||
* to
|
* to
|
||||||
*
|
*
|
||||||
* scopeName.foo > .bar
|
* .foo<scopeName> > .bar
|
||||||
*/
|
*/
|
||||||
private _convertColonHost(cssText: string): string {
|
private _convertColonHost(cssText: string): string {
|
||||||
return this._convertColonRule(cssText, _cssColonHostRe, this._colonHostPartReplacer);
|
return this._convertColonRule(cssText, _cssColonHostRe, this._colonHostPartReplacer);
|
||||||
@ -272,7 +265,7 @@ export class ShadowCss {
|
|||||||
*
|
*
|
||||||
* to
|
* to
|
||||||
*
|
*
|
||||||
* scopeName.foo > .bar, .foo scopeName > .bar { }
|
* .foo<scopeName> > .bar, .foo scopeName > .bar { }
|
||||||
*
|
*
|
||||||
* and
|
* and
|
||||||
*
|
*
|
||||||
@ -280,7 +273,7 @@ export class ShadowCss {
|
|||||||
*
|
*
|
||||||
* to
|
* to
|
||||||
*
|
*
|
||||||
* scopeName.foo .bar { ... }
|
* .foo<scopeName> .bar { ... }
|
||||||
*/
|
*/
|
||||||
private _convertColonHostContext(cssText: string): string {
|
private _convertColonHostContext(cssText: string): string {
|
||||||
return this._convertColonRule(
|
return this._convertColonRule(
|
||||||
@ -288,14 +281,14 @@ export class ShadowCss {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _convertColonRule(cssText: string, regExp: RegExp, partReplacer: Function): string {
|
private _convertColonRule(cssText: string, regExp: RegExp, partReplacer: Function): string {
|
||||||
// p1 = :host, p2 = contents of (), p3 rest of rule
|
// m[1] = :host(-context), m[2] = contents of (), m[3] rest of rule
|
||||||
return StringWrapper.replaceAllMapped(cssText, regExp, function(m: any /** TODO #9100 */) {
|
return cssText.replace(regExp, function(...m: string[]) {
|
||||||
if (isPresent(m[2])) {
|
if (m[2]) {
|
||||||
const parts = m[2].split(','), r: any[] /** TODO #9100 */ = [];
|
const parts = m[2].split(',');
|
||||||
|
const r: string[] = [];
|
||||||
for (let i = 0; i < parts.length; i++) {
|
for (let i = 0; i < parts.length; i++) {
|
||||||
let p = parts[i];
|
let p = parts[i].trim();
|
||||||
if (isBlank(p)) break;
|
if (!p) break;
|
||||||
p = p.trim();
|
|
||||||
r.push(partReplacer(_polyfillHostNoCombinator, p, m[3]));
|
r.push(partReplacer(_polyfillHostNoCombinator, p, m[3]));
|
||||||
}
|
}
|
||||||
return r.join(',');
|
return r.join(',');
|
||||||
@ -306,7 +299,7 @@ export class ShadowCss {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _colonHostContextPartReplacer(host: string, part: string, suffix: string): string {
|
private _colonHostContextPartReplacer(host: string, part: string, suffix: string): string {
|
||||||
if (StringWrapper.contains(part, _polyfillHost)) {
|
if (part.indexOf(_polyfillHost) > -1) {
|
||||||
return this._colonHostPartReplacer(host, part, suffix);
|
return this._colonHostPartReplacer(host, part, suffix);
|
||||||
} else {
|
} else {
|
||||||
return host + part + suffix + ', ' + part + ' ' + host + suffix;
|
return host + part + suffix + ', ' + part + ' ' + host + suffix;
|
||||||
@ -314,7 +307,7 @@ export class ShadowCss {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _colonHostPartReplacer(host: string, part: string, suffix: string): string {
|
private _colonHostPartReplacer(host: string, part: string, suffix: string): string {
|
||||||
return host + StringWrapper.replace(part, _polyfillHost, '') + suffix;
|
return host + part.replace(_polyfillHost, '') + suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -322,8 +315,7 @@ export class ShadowCss {
|
|||||||
* by replacing with space.
|
* by replacing with space.
|
||||||
*/
|
*/
|
||||||
private _convertShadowDOMSelectors(cssText: string): string {
|
private _convertShadowDOMSelectors(cssText: string): string {
|
||||||
return _shadowDOMSelectorsRe.reduce(
|
return _shadowDOMSelectorsRe.reduce((result, pattern) => result.replace(pattern, ' '), cssText);
|
||||||
(result, pattern) => { return StringWrapper.replaceAll(result, pattern, ' '); }, cssText);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// change a selector like 'div' to 'name div'
|
// change a selector like 'div' to 'name div'
|
||||||
@ -331,10 +323,12 @@ export class ShadowCss {
|
|||||||
return processRules(cssText, (rule: CssRule) => {
|
return processRules(cssText, (rule: CssRule) => {
|
||||||
let selector = rule.selector;
|
let selector = rule.selector;
|
||||||
let content = rule.content;
|
let content = rule.content;
|
||||||
if (rule.selector[0] != '@' || rule.selector.startsWith('@page')) {
|
if (rule.selector[0] != '@') {
|
||||||
selector =
|
selector =
|
||||||
this._scopeSelector(rule.selector, scopeSelector, hostSelector, this.strictStyling);
|
this._scopeSelector(rule.selector, scopeSelector, hostSelector, this.strictStyling);
|
||||||
} else if (rule.selector.startsWith('@media') || rule.selector.startsWith('@supports')) {
|
} else if (
|
||||||
|
rule.selector.startsWith('@media') || rule.selector.startsWith('@supports') ||
|
||||||
|
rule.selector.startsWith('@page') || rule.selector.startsWith('@document')) {
|
||||||
content = this._scopeSelectors(rule.content, scopeSelector, hostSelector);
|
content = this._scopeSelectors(rule.content, scopeSelector, hostSelector);
|
||||||
}
|
}
|
||||||
return new CssRule(selector, content);
|
return new CssRule(selector, content);
|
||||||
@ -369,8 +363,7 @@ export class ShadowCss {
|
|||||||
private _makeScopeMatcher(scopeSelector: string): RegExp {
|
private _makeScopeMatcher(scopeSelector: string): RegExp {
|
||||||
const lre = /\[/g;
|
const lre = /\[/g;
|
||||||
const rre = /\]/g;
|
const rre = /\]/g;
|
||||||
scopeSelector = StringWrapper.replaceAll(scopeSelector, lre, '\\[');
|
scopeSelector = scopeSelector.replace(lre, '\\[').replace(rre, '\\]');
|
||||||
scopeSelector = StringWrapper.replaceAll(scopeSelector, rre, '\\]');
|
|
||||||
return new RegExp('^(' + scopeSelector + ')' + _selectorReSuffix, 'm');
|
return new RegExp('^(' + scopeSelector + ')' + _selectorReSuffix, 'm');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,13 +378,14 @@ export class ShadowCss {
|
|||||||
string {
|
string {
|
||||||
// In Android browser, the lastIndex is not reset when the regex is used in String.replace()
|
// In Android browser, the lastIndex is not reset when the regex is used in String.replace()
|
||||||
_polyfillHostRe.lastIndex = 0;
|
_polyfillHostRe.lastIndex = 0;
|
||||||
|
|
||||||
if (_polyfillHostRe.test(selector)) {
|
if (_polyfillHostRe.test(selector)) {
|
||||||
const replaceBy = this.strictStyling ? `[${hostSelector}]` : scopeSelector;
|
const replaceBy = this.strictStyling ? `[${hostSelector}]` : scopeSelector;
|
||||||
selector = StringWrapper.replace(selector, _polyfillHostNoCombinator, replaceBy);
|
return selector.replace(_polyfillHostNoCombinatorRe, (hnc, selector) => selector + replaceBy)
|
||||||
return StringWrapper.replaceAll(selector, _polyfillHostRe, replaceBy + ' ');
|
.replace(_polyfillHostRe, replaceBy + ' ');
|
||||||
} else {
|
|
||||||
return scopeSelector + ' ' + selector;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return scopeSelector + ' ' + selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return a selector with [name] suffix on each simple selector
|
// return a selector with [name] suffix on each simple selector
|
||||||
@ -404,9 +398,9 @@ export class ShadowCss {
|
|||||||
const attrName = '[' + scopeSelector + ']';
|
const attrName = '[' + scopeSelector + ']';
|
||||||
|
|
||||||
const _scopeSelectorPart = (p: string) => {
|
const _scopeSelectorPart = (p: string) => {
|
||||||
var scopedP = p.trim();
|
let scopedP = p.trim();
|
||||||
|
|
||||||
if (scopedP.length == 0) {
|
if (!scopedP) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,12 +420,23 @@ export class ShadowCss {
|
|||||||
return scopedP;
|
return scopedP;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sep = /( |>|\+|~(?!=))\s*/g;
|
let attrSelectorIndex = 0;
|
||||||
const scopeAfter = selector.indexOf(_polyfillHostNoCombinator);
|
const attrSelectors: string[] = [];
|
||||||
|
|
||||||
let scoped = '';
|
// replace attribute selectors with placeholders to avoid issue with white space being treated
|
||||||
|
// as separator
|
||||||
|
selector = selector.replace(/\[[^\]]*\]/g, (attrSelector) => {
|
||||||
|
const replaceBy = `__attr_sel_${attrSelectorIndex}__`;
|
||||||
|
attrSelectors.push(attrSelector);
|
||||||
|
attrSelectorIndex++;
|
||||||
|
return replaceBy;
|
||||||
|
});
|
||||||
|
|
||||||
|
let scopedSelector = '';
|
||||||
let startIndex = 0;
|
let startIndex = 0;
|
||||||
let res: RegExpExecArray;
|
let res: RegExpExecArray;
|
||||||
|
const sep = /( |>|\+|~(?!=))\s*/g;
|
||||||
|
const scopeAfter = selector.indexOf(_polyfillHostNoCombinator);
|
||||||
|
|
||||||
while ((res = sep.exec(selector)) !== null) {
|
while ((res = sep.exec(selector)) !== null) {
|
||||||
const separator = res[1];
|
const separator = res[1];
|
||||||
@ -439,10 +444,14 @@ export class ShadowCss {
|
|||||||
// if a selector appears before :host-context it should not be shimmed as it
|
// if a selector appears before :host-context it should not be shimmed as it
|
||||||
// matches on ancestor elements and not on elements in the host's shadow
|
// matches on ancestor elements and not on elements in the host's shadow
|
||||||
const scopedPart = startIndex >= scopeAfter ? _scopeSelectorPart(part) : part;
|
const scopedPart = startIndex >= scopeAfter ? _scopeSelectorPart(part) : part;
|
||||||
scoped += `${scopedPart} ${separator} `;
|
scopedSelector += `${scopedPart} ${separator} `;
|
||||||
startIndex = sep.lastIndex;
|
startIndex = sep.lastIndex;
|
||||||
}
|
}
|
||||||
return scoped + _scopeSelectorPart(selector.substring(startIndex));
|
|
||||||
|
scopedSelector += _scopeSelectorPart(selector.substring(startIndex));
|
||||||
|
|
||||||
|
// replace the placeholders with their original values
|
||||||
|
return scopedSelector.replace(/__attr_sel_(\d+)__/g, (ph, index) => attrSelectors[+index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _insertPolyfillHostInCssText(selector: string): string {
|
private _insertPolyfillHostInCssText(selector: string): string {
|
||||||
@ -451,10 +460,10 @@ export class ShadowCss {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const _cssContentNextSelectorRe =
|
const _cssContentNextSelectorRe =
|
||||||
/polyfill-next-selector[^}]*content:[\s]*?['"](.*?)['"][;\s]*}([^{]*?){/gim;
|
/polyfill-next-selector[^}]*content:[\s]*?(['"])(.*?)\1[;\s]*}([^{]*?){/gim;
|
||||||
const _cssContentRuleRe = /(polyfill-rule)[^}]*(content:[\s]*['"](.*?)['"])[;\s]*[^}]*}/gim;
|
const _cssContentRuleRe = /(polyfill-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim;
|
||||||
const _cssContentUnscopedRuleRe =
|
const _cssContentUnscopedRuleRe =
|
||||||
/(polyfill-unscoped-rule)[^}]*(content:[\s]*['"](.*?)['"])[;\s]*[^}]*}/gim;
|
/(polyfill-unscoped-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim;
|
||||||
const _polyfillHost = '-shadowcsshost';
|
const _polyfillHost = '-shadowcsshost';
|
||||||
// note: :host-context pre-processed to -shadowcsshostcontext.
|
// note: :host-context pre-processed to -shadowcsshostcontext.
|
||||||
const _polyfillHostContext = '-shadowcsscontext';
|
const _polyfillHostContext = '-shadowcsscontext';
|
||||||
@ -464,6 +473,7 @@ const _parenSuffix = ')(?:\\((' +
|
|||||||
const _cssColonHostRe = new RegExp('(' + _polyfillHost + _parenSuffix, 'gim');
|
const _cssColonHostRe = new RegExp('(' + _polyfillHost + _parenSuffix, 'gim');
|
||||||
const _cssColonHostContextRe = new RegExp('(' + _polyfillHostContext + _parenSuffix, 'gim');
|
const _cssColonHostContextRe = new RegExp('(' + _polyfillHostContext + _parenSuffix, 'gim');
|
||||||
const _polyfillHostNoCombinator = _polyfillHost + '-no-combinator';
|
const _polyfillHostNoCombinator = _polyfillHost + '-no-combinator';
|
||||||
|
const _polyfillHostNoCombinatorRe = /-shadowcsshost-no-combinator([^\s]*)/;
|
||||||
const _shadowDOMSelectorsRe = [
|
const _shadowDOMSelectorsRe = [
|
||||||
/::shadow/g,
|
/::shadow/g,
|
||||||
/::content/g,
|
/::content/g,
|
||||||
@ -480,7 +490,7 @@ const _colonHostContextRe = /:host-context/gim;
|
|||||||
const _commentRe = /\/\*\s*[\s\S]*?\*\//g;
|
const _commentRe = /\/\*\s*[\s\S]*?\*\//g;
|
||||||
|
|
||||||
function stripComments(input: string): string {
|
function stripComments(input: string): string {
|
||||||
return StringWrapper.replaceAllMapped(input, _commentRe, (_: any /** TODO #9100 */) => '');
|
return input.replace(_commentRe, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
// all comments except inline source mapping
|
// all comments except inline source mapping
|
||||||
@ -501,18 +511,17 @@ export class CssRule {
|
|||||||
constructor(public selector: string, public content: string) {}
|
constructor(public selector: string, public content: string) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function processRules(input: string, ruleCallback: Function): string {
|
export function processRules(input: string, ruleCallback: (rule: CssRule) => CssRule): string {
|
||||||
const inputWithEscapedBlocks = escapeBlocks(input);
|
const inputWithEscapedBlocks = escapeBlocks(input);
|
||||||
let nextBlockIndex = 0;
|
let nextBlockIndex = 0;
|
||||||
return StringWrapper.replaceAllMapped(
|
return inputWithEscapedBlocks.escapedString.replace(_ruleRe, function(...m: string[]) {
|
||||||
inputWithEscapedBlocks.escapedString, _ruleRe, function(m: any /** TODO #9100 */) {
|
|
||||||
const selector = m[2];
|
const selector = m[2];
|
||||||
let content = '';
|
let content = '';
|
||||||
let suffix = m[4];
|
let suffix = m[4];
|
||||||
let contentPrefix = '';
|
let contentPrefix = '';
|
||||||
if (isPresent(m[4]) && m[4].startsWith('{' + BLOCK_PLACEHOLDER)) {
|
if (suffix && suffix.startsWith('{' + BLOCK_PLACEHOLDER)) {
|
||||||
content = inputWithEscapedBlocks.blocks[nextBlockIndex++];
|
content = inputWithEscapedBlocks.blocks[nextBlockIndex++];
|
||||||
suffix = m[4].substring(BLOCK_PLACEHOLDER.length + 1);
|
suffix = suffix.substring(BLOCK_PLACEHOLDER.length + 1);
|
||||||
contentPrefix = '{';
|
contentPrefix = '{';
|
||||||
}
|
}
|
||||||
const rule = ruleCallback(new CssRule(selector, content));
|
const rule = ruleCallback(new CssRule(selector, content));
|
||||||
@ -525,11 +534,11 @@ class StringWithEscapedBlocks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function escapeBlocks(input: string): StringWithEscapedBlocks {
|
function escapeBlocks(input: string): StringWithEscapedBlocks {
|
||||||
const inputParts = StringWrapper.split(input, _curlyRe);
|
const inputParts = input.split(_curlyRe);
|
||||||
const resultParts: any[] /** TODO #9100 */ = [];
|
const resultParts: string[] = [];
|
||||||
const escapedBlocks: any[] /** TODO #9100 */ = [];
|
const escapedBlocks: string[] = [];
|
||||||
let bracketCount = 0;
|
let bracketCount = 0;
|
||||||
let currentBlockParts: any[] /** TODO #9100 */ = [];
|
let currentBlockParts: string[] = [];
|
||||||
for (let partIndex = 0; partIndex < inputParts.length; partIndex++) {
|
for (let partIndex = 0; partIndex < inputParts.length; partIndex++) {
|
||||||
const part = inputParts[partIndex];
|
const part = inputParts[partIndex];
|
||||||
if (part == CLOSE_CURLY) {
|
if (part == CLOSE_CURLY) {
|
||||||
|
@ -12,11 +12,8 @@ import {CompileDirectiveMetadata, CompileProviderMetadata, CompileTokenMetadata}
|
|||||||
import {AST} from '../expression_parser/ast';
|
import {AST} from '../expression_parser/ast';
|
||||||
import {isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
import {ParseSourceSpan} from '../parse_util';
|
import {ParseSourceSpan} from '../parse_util';
|
||||||
|
|
||||||
import {LifecycleHooks} from '../private_import_core';
|
import {LifecycleHooks} from '../private_import_core';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Abstract Syntax Tree node representing part of a parsed Angular template.
|
* An Abstract Syntax Tree node representing part of a parsed Angular template.
|
||||||
*/
|
*/
|
||||||
@ -61,7 +58,8 @@ export class AttrAst implements TemplateAst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A binding for an element property (e.g. `[property]="expression"`).
|
* A binding for an element property (e.g. `[property]="expression"`) or an animation trigger (e.g.
|
||||||
|
* `[@trigger]="stateExp"`)
|
||||||
*/
|
*/
|
||||||
export class BoundElementPropertyAst implements TemplateAst {
|
export class BoundElementPropertyAst implements TemplateAst {
|
||||||
constructor(
|
constructor(
|
||||||
@ -71,14 +69,16 @@ export class BoundElementPropertyAst implements TemplateAst {
|
|||||||
visit(visitor: TemplateAstVisitor, context: any): any {
|
visit(visitor: TemplateAstVisitor, context: any): any {
|
||||||
return visitor.visitElementProperty(this, context);
|
return visitor.visitElementProperty(this, context);
|
||||||
}
|
}
|
||||||
|
get isAnimation(): boolean { return this.type === PropertyBindingType.Animation; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A binding for an element event (e.g. `(event)="handler()"`).
|
* A binding for an element event (e.g. `(event)="handler()"`) or an animation trigger event (e.g.
|
||||||
|
* `(@trigger.phase)="callback($event)"`).
|
||||||
*/
|
*/
|
||||||
export class BoundEventAst implements TemplateAst {
|
export class BoundEventAst implements TemplateAst {
|
||||||
constructor(
|
constructor(
|
||||||
public name: string, public target: string, public handler: AST,
|
public name: string, public target: string, public phase: string, public handler: AST,
|
||||||
public sourceSpan: ParseSourceSpan) {}
|
public sourceSpan: ParseSourceSpan) {}
|
||||||
visit(visitor: TemplateAstVisitor, context: any): any {
|
visit(visitor: TemplateAstVisitor, context: any): any {
|
||||||
return visitor.visitEvent(this, context);
|
return visitor.visitEvent(this, context);
|
||||||
@ -90,6 +90,7 @@ export class BoundEventAst implements TemplateAst {
|
|||||||
return this.name;
|
return this.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
get isAnimation(): boolean { return !!this.phase; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,11 +8,10 @@
|
|||||||
|
|
||||||
import {Inject, Injectable, OpaqueToken, Optional, SchemaMetadata, SecurityContext} from '@angular/core';
|
import {Inject, Injectable, OpaqueToken, Optional, SchemaMetadata, SecurityContext} from '@angular/core';
|
||||||
|
|
||||||
import {CompileDirectiveMetadata, CompilePipeMetadata, CompileTokenMetadata, removeIdentifierDuplicates} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompilePipeMetadata, CompileTemplateMetadata, CompileTokenMetadata, removeIdentifierDuplicates} from '../compile_metadata';
|
||||||
import {AST, ASTWithSource, BindingPipe, EmptyExpr, Interpolation, ParserError, RecursiveAstVisitor, TemplateBinding} from '../expression_parser/ast';
|
import {AST, ASTWithSource, BindingPipe, EmptyExpr, Interpolation, ParserError, RecursiveAstVisitor, TemplateBinding} from '../expression_parser/ast';
|
||||||
import {Parser} from '../expression_parser/parser';
|
import {Parser} from '../expression_parser/parser';
|
||||||
import {StringMapWrapper} from '../facade/collection';
|
import {isPresent, isString} from '../facade/lang';
|
||||||
import {isBlank, isPresent, isString} from '../facade/lang';
|
|
||||||
import {I18NHtmlParser} from '../i18n/i18n_html_parser';
|
import {I18NHtmlParser} from '../i18n/i18n_html_parser';
|
||||||
import {Identifiers, identifierToken, resolveIdentifierToken} from '../identifiers';
|
import {Identifiers, identifierToken, resolveIdentifierToken} from '../identifiers';
|
||||||
import * as html from '../ml_parser/ast';
|
import * as html from '../ml_parser/ast';
|
||||||
@ -26,12 +25,13 @@ import {ProviderElementContext, ProviderViewContext} from '../provider_analyzer'
|
|||||||
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
|
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
|
||||||
import {CssSelector, SelectorMatcher} from '../selector';
|
import {CssSelector, SelectorMatcher} from '../selector';
|
||||||
import {isStyleUrlResolvable} from '../style_url_resolver';
|
import {isStyleUrlResolvable} from '../style_url_resolver';
|
||||||
import {splitAtColon} from '../util';
|
import {splitAtColon, splitAtPeriod} from '../util';
|
||||||
|
|
||||||
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from './template_ast';
|
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from './template_ast';
|
||||||
import {PreparsedElementType, preparseElement} from './template_preparser';
|
import {PreparsedElementType, preparseElement} from './template_preparser';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Group 1 = "bind-"
|
// Group 1 = "bind-"
|
||||||
// Group 2 = "let-"
|
// Group 2 = "let-"
|
||||||
// Group 3 = "ref-/#"
|
// Group 3 = "ref-/#"
|
||||||
@ -142,7 +142,6 @@ export class TemplateParser {
|
|||||||
const parseVisitor = new TemplateParseVisitor(
|
const parseVisitor = new TemplateParseVisitor(
|
||||||
providerViewContext, uniqDirectives, uniqPipes, schemas, this._exprParser,
|
providerViewContext, uniqDirectives, uniqPipes, schemas, this._exprParser,
|
||||||
this._schemaRegistry);
|
this._schemaRegistry);
|
||||||
|
|
||||||
result = html.visitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT);
|
result = html.visitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT);
|
||||||
errors.push(...parseVisitor.errors, ...providerViewContext.errors);
|
errors.push(...parseVisitor.errors, ...providerViewContext.errors);
|
||||||
} else {
|
} else {
|
||||||
@ -444,6 +443,15 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
providerContext.transformedDirectiveAsts, providerContext.transformProviders,
|
providerContext.transformedDirectiveAsts, providerContext.transformProviders,
|
||||||
providerContext.transformedHasViewContainer, children,
|
providerContext.transformedHasViewContainer, children,
|
||||||
hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
|
hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
|
||||||
|
|
||||||
|
this._findComponentDirectives(directiveAsts)
|
||||||
|
.forEach(
|
||||||
|
componentDirectiveAst => this._validateElementAnimationInputOutputs(
|
||||||
|
componentDirectiveAst.hostProperties, componentDirectiveAst.hostEvents,
|
||||||
|
componentDirectiveAst.directive.template));
|
||||||
|
|
||||||
|
const componentTemplate = providerContext.viewContext.component.template;
|
||||||
|
this._validateElementAnimationInputOutputs(elementProps, events, componentTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasInlineTemplates) {
|
if (hasInlineTemplates) {
|
||||||
@ -469,9 +477,36 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
templateProviderContext.transformedHasViewContainer, [parsedElement], ngContentIndex,
|
templateProviderContext.transformedHasViewContainer, [parsedElement], ngContentIndex,
|
||||||
element.sourceSpan);
|
element.sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsedElement;
|
return parsedElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _validateElementAnimationInputOutputs(
|
||||||
|
inputs: BoundElementPropertyAst[], outputs: BoundEventAst[],
|
||||||
|
template: CompileTemplateMetadata) {
|
||||||
|
const triggerLookup = new Set<string>();
|
||||||
|
template.animations.forEach(entry => { triggerLookup.add(entry.name); });
|
||||||
|
|
||||||
|
const animationInputs = inputs.filter(input => input.isAnimation);
|
||||||
|
animationInputs.forEach(input => {
|
||||||
|
const name = input.name;
|
||||||
|
if (!triggerLookup.has(name)) {
|
||||||
|
this._reportError(`Couldn't find an animation entry for "${name}"`, input.sourceSpan);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
outputs.forEach(output => {
|
||||||
|
if (output.isAnimation) {
|
||||||
|
const found = animationInputs.find(input => input.name == output.name);
|
||||||
|
if (!found) {
|
||||||
|
this._reportError(
|
||||||
|
`Unable to listen on (@${output.name}.${output.phase}) because the animation trigger [@${output.name}] isn't being used on the same element`,
|
||||||
|
output.sourceSpan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private _parseInlineTemplateBinding(
|
private _parseInlineTemplateBinding(
|
||||||
attr: html.Attribute, targetMatchableAttrs: string[][],
|
attr: html.Attribute, targetMatchableAttrs: string[][],
|
||||||
targetProps: BoundElementOrDirectiveProperty[], targetVars: VariableAst[]): boolean {
|
targetProps: BoundElementOrDirectiveProperty[], targetVars: VariableAst[]): boolean {
|
||||||
@ -533,7 +568,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
this._parseReference(identifier, value, srcSpan, targetRefs);
|
this._parseReference(identifier, value, srcSpan, targetRefs);
|
||||||
|
|
||||||
} else if (bindParts[KW_ON_IDX]) {
|
} else if (bindParts[KW_ON_IDX]) {
|
||||||
this._parseEvent(
|
this._parseEventOrAnimationEvent(
|
||||||
bindParts[IDENT_KW_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
|
bindParts[IDENT_KW_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
|
||||||
|
|
||||||
} else if (bindParts[KW_BINDON_IDX]) {
|
} else if (bindParts[KW_BINDON_IDX]) {
|
||||||
@ -544,7 +579,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
bindParts[IDENT_KW_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
|
bindParts[IDENT_KW_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
|
||||||
|
|
||||||
} else if (bindParts[KW_AT_IDX]) {
|
} else if (bindParts[KW_AT_IDX]) {
|
||||||
if (name[0] == '@' && isPresent(value) && value.length > 0) {
|
if (_isAnimationLabel(name) && isPresent(value) && value.length > 0) {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
`Assigning animation triggers via @prop="exp" attributes with an expression is invalid.` +
|
`Assigning animation triggers via @prop="exp" attributes with an expression is invalid.` +
|
||||||
` Use property bindings (e.g. [@prop]="exp") or use an attribute without a value (e.g. @prop) instead.`,
|
` Use property bindings (e.g. [@prop]="exp") or use an attribute without a value (e.g. @prop) instead.`,
|
||||||
@ -565,7 +600,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
targetAnimationProps);
|
targetAnimationProps);
|
||||||
|
|
||||||
} else if (bindParts[IDENT_EVENT_IDX]) {
|
} else if (bindParts[IDENT_EVENT_IDX]) {
|
||||||
this._parseEvent(
|
this._parseEventOrAnimationEvent(
|
||||||
bindParts[IDENT_EVENT_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
|
bindParts[IDENT_EVENT_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -608,7 +643,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
targetMatchableAttrs: string[][], targetProps: BoundElementOrDirectiveProperty[],
|
targetMatchableAttrs: string[][], targetProps: BoundElementOrDirectiveProperty[],
|
||||||
targetAnimationProps: BoundElementPropertyAst[]) {
|
targetAnimationProps: BoundElementPropertyAst[]) {
|
||||||
const animatePropLength = ANIMATE_PROP_PREFIX.length;
|
const animatePropLength = ANIMATE_PROP_PREFIX.length;
|
||||||
var isAnimationProp = name[0] == '@';
|
var isAnimationProp = _isAnimationLabel(name);
|
||||||
var animationPrefixLength = 1;
|
var animationPrefixLength = 1;
|
||||||
if (name.substring(0, animatePropLength) == ANIMATE_PROP_PREFIX) {
|
if (name.substring(0, animatePropLength) == ANIMATE_PROP_PREFIX) {
|
||||||
isAnimationProp = true;
|
isAnimationProp = true;
|
||||||
@ -635,6 +670,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
if (!isPresent(expression) || expression.length == 0) {
|
if (!isPresent(expression) || expression.length == 0) {
|
||||||
expression = 'null';
|
expression = 'null';
|
||||||
}
|
}
|
||||||
|
|
||||||
const ast = this._parseBinding(expression, sourceSpan);
|
const ast = this._parseBinding(expression, sourceSpan);
|
||||||
targetMatchableAttrs.push([name, ast.source]);
|
targetMatchableAttrs.push([name, ast.source]);
|
||||||
targetAnimationProps.push(new BoundElementPropertyAst(
|
targetAnimationProps.push(new BoundElementPropertyAst(
|
||||||
@ -662,20 +698,56 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
private _parseAssignmentEvent(
|
private _parseAssignmentEvent(
|
||||||
name: string, expression: string, sourceSpan: ParseSourceSpan,
|
name: string, expression: string, sourceSpan: ParseSourceSpan,
|
||||||
targetMatchableAttrs: string[][], targetEvents: BoundEventAst[]) {
|
targetMatchableAttrs: string[][], targetEvents: BoundEventAst[]) {
|
||||||
this._parseEvent(
|
this._parseEventOrAnimationEvent(
|
||||||
`${name}Change`, `${expression}=$event`, sourceSpan, targetMatchableAttrs, targetEvents);
|
`${name}Change`, `${expression}=$event`, sourceSpan, targetMatchableAttrs, targetEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _parseEventOrAnimationEvent(
|
||||||
|
name: string, expression: string, sourceSpan: ParseSourceSpan,
|
||||||
|
targetMatchableAttrs: string[][], targetEvents: BoundEventAst[]) {
|
||||||
|
if (_isAnimationLabel(name)) {
|
||||||
|
name = name.substr(1);
|
||||||
|
this._parseAnimationEvent(name, expression, sourceSpan, targetEvents);
|
||||||
|
} else {
|
||||||
|
this._parseEvent(name, expression, sourceSpan, targetMatchableAttrs, targetEvents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _parseAnimationEvent(
|
||||||
|
name: string, expression: string, sourceSpan: ParseSourceSpan,
|
||||||
|
targetEvents: BoundEventAst[]) {
|
||||||
|
const matches = splitAtPeriod(name, [name, '']);
|
||||||
|
const eventName = matches[0];
|
||||||
|
const phase = matches[1].toLowerCase();
|
||||||
|
if (phase) {
|
||||||
|
switch (phase) {
|
||||||
|
case 'start':
|
||||||
|
case 'done':
|
||||||
|
const ast = this._parseAction(expression, sourceSpan);
|
||||||
|
targetEvents.push(new BoundEventAst(eventName, null, phase, ast, sourceSpan));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
this._reportError(
|
||||||
|
`The provided animation output phase value "${phase}" for "@${eventName}" is not supported (use start or done)`,
|
||||||
|
sourceSpan);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._reportError(
|
||||||
|
`The animation trigger output event (@${eventName}) is missing its phase value name (start or done are currently supported)`,
|
||||||
|
sourceSpan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _parseEvent(
|
private _parseEvent(
|
||||||
name: string, expression: string, sourceSpan: ParseSourceSpan,
|
name: string, expression: string, sourceSpan: ParseSourceSpan,
|
||||||
targetMatchableAttrs: string[][], targetEvents: BoundEventAst[]) {
|
targetMatchableAttrs: string[][], targetEvents: BoundEventAst[]) {
|
||||||
// long format: 'target: eventName'
|
// long format: 'target: eventName'
|
||||||
const parts = splitAtColon(name, [null, name]);
|
const [target, eventName] = splitAtColon(name, [null, name]);
|
||||||
const target = parts[0];
|
|
||||||
const eventName = parts[1];
|
|
||||||
const ast = this._parseAction(expression, sourceSpan);
|
const ast = this._parseAction(expression, sourceSpan);
|
||||||
targetMatchableAttrs.push([name, ast.source]);
|
targetMatchableAttrs.push([name, ast.source]);
|
||||||
targetEvents.push(new BoundEventAst(eventName, target, ast, sourceSpan));
|
targetEvents.push(new BoundEventAst(eventName, target, null, ast, sourceSpan));
|
||||||
// Don't detect directives for event names for now,
|
// Don't detect directives for event names for now,
|
||||||
// so don't add the event name to the matchableAttrs
|
// so don't add the event name to the matchableAttrs
|
||||||
}
|
}
|
||||||
@ -759,7 +831,8 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
elementName: string, hostProps: {[key: string]: string}, sourceSpan: ParseSourceSpan,
|
elementName: string, hostProps: {[key: string]: string}, sourceSpan: ParseSourceSpan,
|
||||||
targetPropertyAsts: BoundElementPropertyAst[]) {
|
targetPropertyAsts: BoundElementPropertyAst[]) {
|
||||||
if (hostProps) {
|
if (hostProps) {
|
||||||
StringMapWrapper.forEach(hostProps, (expression: string, propName: string) => {
|
Object.keys(hostProps).forEach(propName => {
|
||||||
|
const expression = hostProps[propName];
|
||||||
if (isString(expression)) {
|
if (isString(expression)) {
|
||||||
const exprAst = this._parseBinding(expression, sourceSpan);
|
const exprAst = this._parseBinding(expression, sourceSpan);
|
||||||
targetPropertyAsts.push(
|
targetPropertyAsts.push(
|
||||||
@ -777,9 +850,10 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
hostListeners: {[key: string]: string}, sourceSpan: ParseSourceSpan,
|
hostListeners: {[key: string]: string}, sourceSpan: ParseSourceSpan,
|
||||||
targetEventAsts: BoundEventAst[]) {
|
targetEventAsts: BoundEventAst[]) {
|
||||||
if (hostListeners) {
|
if (hostListeners) {
|
||||||
StringMapWrapper.forEach(hostListeners, (expression: string, propName: string) => {
|
Object.keys(hostListeners).forEach(propName => {
|
||||||
|
const expression = hostListeners[propName];
|
||||||
if (isString(expression)) {
|
if (isString(expression)) {
|
||||||
this._parseEvent(propName, expression, sourceSpan, [], targetEventAsts);
|
this._parseEventOrAnimationEvent(propName, expression, sourceSpan, [], targetEventAsts);
|
||||||
} else {
|
} else {
|
||||||
this._reportError(
|
this._reportError(
|
||||||
`Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`,
|
`Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`,
|
||||||
@ -796,13 +870,14 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
const boundPropsByName = new Map<string, BoundElementOrDirectiveProperty>();
|
const boundPropsByName = new Map<string, BoundElementOrDirectiveProperty>();
|
||||||
boundProps.forEach(boundProp => {
|
boundProps.forEach(boundProp => {
|
||||||
const prevValue = boundPropsByName.get(boundProp.name);
|
const prevValue = boundPropsByName.get(boundProp.name);
|
||||||
if (isBlank(prevValue) || prevValue.isLiteral) {
|
if (!prevValue || prevValue.isLiteral) {
|
||||||
// give [a]="b" a higher precedence than a="b" on the same element
|
// give [a]="b" a higher precedence than a="b" on the same element
|
||||||
boundPropsByName.set(boundProp.name, boundProp);
|
boundPropsByName.set(boundProp.name, boundProp);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
StringMapWrapper.forEach(directiveProperties, (elProp: string, dirProp: string) => {
|
Object.keys(directiveProperties).forEach(dirProp => {
|
||||||
|
const elProp = directiveProperties[dirProp];
|
||||||
const boundProp = boundPropsByName.get(elProp);
|
const boundProp = boundPropsByName.get(elProp);
|
||||||
|
|
||||||
// Bindings are optional, so this binding only needs to be set up if an expression is given.
|
// Bindings are optional, so this binding only needs to be set up if an expression is given.
|
||||||
@ -827,7 +902,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
});
|
});
|
||||||
|
|
||||||
props.forEach((prop: BoundElementOrDirectiveProperty) => {
|
props.forEach((prop: BoundElementOrDirectiveProperty) => {
|
||||||
if (!prop.isLiteral && isBlank(boundDirectivePropsIndex.get(prop.name))) {
|
if (!prop.isLiteral && !boundDirectivePropsIndex.get(prop.name)) {
|
||||||
boundElementProps.push(this._createElementPropertyAst(
|
boundElementProps.push(this._createElementPropertyAst(
|
||||||
elementName, prop.name, prop.expression, prop.sourceSpan));
|
elementName, prop.name, prop.expression, prop.sourceSpan));
|
||||||
}
|
}
|
||||||
@ -846,7 +921,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
|
|
||||||
if (parts.length === 1) {
|
if (parts.length === 1) {
|
||||||
var partValue = parts[0];
|
var partValue = parts[0];
|
||||||
if (partValue[0] == '@') {
|
if (_isAnimationLabel(partValue)) {
|
||||||
boundPropertyName = partValue.substr(1);
|
boundPropertyName = partValue.substr(1);
|
||||||
bindingType = PropertyBindingType.Animation;
|
bindingType = PropertyBindingType.Animation;
|
||||||
securityContext = SecurityContext.NONE;
|
securityContext = SecurityContext.NONE;
|
||||||
@ -854,7 +929,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
boundPropertyName = this._schemaRegistry.getMappedPropName(partValue);
|
boundPropertyName = this._schemaRegistry.getMappedPropName(partValue);
|
||||||
securityContext = this._schemaRegistry.securityContext(elementName, boundPropertyName);
|
securityContext = this._schemaRegistry.securityContext(elementName, boundPropertyName);
|
||||||
bindingType = PropertyBindingType.Property;
|
bindingType = PropertyBindingType.Property;
|
||||||
this._assertNoEventBinding(boundPropertyName, sourceSpan);
|
this._validatePropertyOrAttributeName(boundPropertyName, sourceSpan, false);
|
||||||
if (!this._schemaRegistry.hasProperty(elementName, boundPropertyName, this._schemas)) {
|
if (!this._schemaRegistry.hasProperty(elementName, boundPropertyName, this._schemas)) {
|
||||||
let errorMsg =
|
let errorMsg =
|
||||||
`Can't bind to '${boundPropertyName}' since it isn't a known property of '${elementName}'.`;
|
`Can't bind to '${boundPropertyName}' since it isn't a known property of '${elementName}'.`;
|
||||||
@ -869,7 +944,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
} else {
|
} else {
|
||||||
if (parts[0] == ATTRIBUTE_PREFIX) {
|
if (parts[0] == ATTRIBUTE_PREFIX) {
|
||||||
boundPropertyName = parts[1];
|
boundPropertyName = parts[1];
|
||||||
this._assertNoEventBinding(boundPropertyName, sourceSpan);
|
this._validatePropertyOrAttributeName(boundPropertyName, sourceSpan, true);
|
||||||
// NB: For security purposes, use the mapped property name, not the attribute name.
|
// NB: For security purposes, use the mapped property name, not the attribute name.
|
||||||
const mapPropName = this._schemaRegistry.getMappedPropName(boundPropertyName);
|
const mapPropName = this._schemaRegistry.getMappedPropName(boundPropertyName);
|
||||||
securityContext = this._schemaRegistry.securityContext(elementName, mapPropName);
|
securityContext = this._schemaRegistry.securityContext(elementName, mapPropName);
|
||||||
@ -902,24 +977,29 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
boundPropertyName, bindingType, securityContext, ast, unit, sourceSpan);
|
boundPropertyName, bindingType, securityContext, ast, unit, sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _assertNoEventBinding(propName: string, sourceSpan: ParseSourceSpan): void {
|
|
||||||
if (propName.toLowerCase().startsWith('on')) {
|
/**
|
||||||
this._reportError(
|
* @param propName the name of the property / attribute
|
||||||
`Binding to event attribute '${propName}' is disallowed ` +
|
* @param sourceSpan
|
||||||
`for security reasons, please use (${propName.slice(2)})=...`,
|
* @param isAttr true when binding to an attribute
|
||||||
sourceSpan, ParseErrorLevel.FATAL);
|
* @private
|
||||||
|
*/
|
||||||
|
private _validatePropertyOrAttributeName(
|
||||||
|
propName: string, sourceSpan: ParseSourceSpan, isAttr: boolean): void {
|
||||||
|
const report = isAttr ? this._schemaRegistry.validateAttribute(propName) :
|
||||||
|
this._schemaRegistry.validateProperty(propName);
|
||||||
|
if (report.error) {
|
||||||
|
this._reportError(report.msg, sourceSpan, ParseErrorLevel.FATAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _findComponentDirectiveNames(directives: DirectiveAst[]): string[] {
|
private _findComponentDirectives(directives: DirectiveAst[]): DirectiveAst[] {
|
||||||
const componentTypeNames: string[] = [];
|
return directives.filter(directive => directive.directive.isComponent);
|
||||||
directives.forEach(directive => {
|
|
||||||
const typeName = directive.directive.type.name;
|
|
||||||
if (directive.directive.isComponent) {
|
|
||||||
componentTypeNames.push(typeName);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
return componentTypeNames;
|
private _findComponentDirectiveNames(directives: DirectiveAst[]): string[] {
|
||||||
|
return this._findComponentDirectives(directives)
|
||||||
|
.map(directive => directive.directive.type.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _assertOnlyOneComponent(directives: DirectiveAst[], sourceSpan: ParseSourceSpan) {
|
private _assertOnlyOneComponent(directives: DirectiveAst[], sourceSpan: ParseSourceSpan) {
|
||||||
@ -969,7 +1049,8 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
const allDirectiveEvents = new Set<string>();
|
const allDirectiveEvents = new Set<string>();
|
||||||
|
|
||||||
directives.forEach(directive => {
|
directives.forEach(directive => {
|
||||||
StringMapWrapper.forEach(directive.directive.outputs, (eventName: string) => {
|
Object.keys(directive.directive.outputs).forEach(k => {
|
||||||
|
const eventName = directive.directive.outputs[k];
|
||||||
allDirectiveEvents.add(eventName);
|
allDirectiveEvents.add(eventName);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1103,3 +1184,7 @@ export class PipeCollector extends RecursiveAstVisitor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _isAnimationLabel(name: string): boolean {
|
||||||
|
return name[0] == '@';
|
||||||
|
}
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompileTokenMetadata} from './compile_metadata';
|
import {CompileTokenMetadata} from './compile_metadata';
|
||||||
import {StringMapWrapper} from './facade/collection';
|
|
||||||
import {StringWrapper, isArray, isBlank, isPresent, isPrimitive, isStrictStringMap} from './facade/lang';
|
import {StringWrapper, isArray, isBlank, isPresent, isPrimitive, isStrictStringMap} from './facade/lang';
|
||||||
import * as o from './output/output_ast';
|
import * as o from './output/output_ast';
|
||||||
|
|
||||||
@ -17,13 +16,21 @@ var CAMEL_CASE_REGEXP = /([A-Z])/g;
|
|||||||
|
|
||||||
export function camelCaseToDashCase(input: string): string {
|
export function camelCaseToDashCase(input: string): string {
|
||||||
return StringWrapper.replaceAllMapped(
|
return StringWrapper.replaceAllMapped(
|
||||||
input, CAMEL_CASE_REGEXP, (m: string[]) => { return '-' + m[1].toLowerCase(); });
|
input, CAMEL_CASE_REGEXP, (m: string[]) => '-' + m[1].toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function splitAtColon(input: string, defaultValues: string[]): string[] {
|
export function splitAtColon(input: string, defaultValues: string[]): string[] {
|
||||||
const colonIndex = input.indexOf(':');
|
return _splitAt(input, ':', defaultValues);
|
||||||
if (colonIndex == -1) return defaultValues;
|
}
|
||||||
return [input.slice(0, colonIndex).trim(), input.slice(colonIndex + 1).trim()];
|
|
||||||
|
export function splitAtPeriod(input: string, defaultValues: string[]): string[] {
|
||||||
|
return _splitAt(input, '.', defaultValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _splitAt(input: string, character: string, defaultValues: string[]): string[] {
|
||||||
|
const characterIndex = input.indexOf(character);
|
||||||
|
if (characterIndex == -1) return defaultValues;
|
||||||
|
return [input.slice(0, characterIndex).trim(), input.slice(characterIndex + 1).trim()];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sanitizeIdentifier(name: string): string {
|
export function sanitizeIdentifier(name: string): string {
|
||||||
@ -55,9 +62,8 @@ export class ValueTransformer implements ValueVisitor {
|
|||||||
}
|
}
|
||||||
visitStringMap(map: {[key: string]: any}, context: any): any {
|
visitStringMap(map: {[key: string]: any}, context: any): any {
|
||||||
var result = {};
|
var result = {};
|
||||||
StringMapWrapper.forEach(map, (value: any /** TODO #9100 */, key: any /** TODO #9100 */) => {
|
Object.keys(map).forEach(
|
||||||
(result as any /** TODO #9100 */)[key] = visitValue(value, this, context);
|
key => { (result as any /** TODO #9100 */)[key] = visitValue(map[key], this, context); });
|
||||||
});
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
visitPrimitive(value: any, context: any): any { return value; }
|
visitPrimitive(value: any, context: any): any { return value; }
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
|
|
||||||
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileIdentifierMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata} from '../compile_metadata';
|
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileIdentifierMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata} from '../compile_metadata';
|
||||||
import {ListWrapper, MapWrapper, StringMapWrapper} from '../facade/collection';
|
import {ListWrapper, MapWrapper} from '../facade/collection';
|
||||||
import {isBlank, isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
import {Identifiers, identifierToken, resolveIdentifier, resolveIdentifierToken} from '../identifiers';
|
import {Identifiers, identifierToken, 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';
|
||||||
@ -27,7 +27,7 @@ export class CompileNode {
|
|||||||
public parent: CompileElement, public view: CompileView, public nodeIndex: number,
|
public parent: CompileElement, public view: CompileView, public nodeIndex: number,
|
||||||
public renderNode: o.Expression, public sourceAst: TemplateAst) {}
|
public renderNode: o.Expression, public sourceAst: TemplateAst) {}
|
||||||
|
|
||||||
isNull(): boolean { return isBlank(this.renderNode); }
|
isNull(): boolean { return !this.renderNode; }
|
||||||
|
|
||||||
isRootElement(): boolean { return this.view != this.parent.view; }
|
isRootElement(): boolean { return this.view != this.parent.view; }
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ export class CompileElement extends CompileNode {
|
|||||||
setComponentView(compViewExpr: o.Expression) {
|
setComponentView(compViewExpr: o.Expression) {
|
||||||
this._compViewExpr = compViewExpr;
|
this._compViewExpr = compViewExpr;
|
||||||
this.contentNodesByNgContentIndex =
|
this.contentNodesByNgContentIndex =
|
||||||
ListWrapper.createFixedSize(this.component.template.ngContentSelectors.length);
|
new Array(this.component.template.ngContentSelectors.length);
|
||||||
for (var i = 0; i < this.contentNodesByNgContentIndex.length; i++) {
|
for (var i = 0; i < this.contentNodesByNgContentIndex.length; i++) {
|
||||||
this.contentNodesByNgContentIndex[i] = [];
|
this.contentNodesByNgContentIndex[i] = [];
|
||||||
}
|
}
|
||||||
@ -192,7 +192,7 @@ export class CompileElement extends CompileNode {
|
|||||||
queriesWithReads,
|
queriesWithReads,
|
||||||
queriesForProvider.map(query => new _QueryWithRead(query, resolvedProvider.token)));
|
queriesForProvider.map(query => new _QueryWithRead(query, resolvedProvider.token)));
|
||||||
});
|
});
|
||||||
StringMapWrapper.forEach(this.referenceTokens, (_: CompileTokenMetadata, varName: string) => {
|
Object.keys(this.referenceTokens).forEach(varName => {
|
||||||
var token = this.referenceTokens[varName];
|
var token = this.referenceTokens[varName];
|
||||||
var varValue: o.Expression;
|
var varValue: o.Expression;
|
||||||
if (isPresent(token)) {
|
if (isPresent(token)) {
|
||||||
@ -313,12 +313,12 @@ export class CompileElement extends CompileNode {
|
|||||||
requestingProviderType: ProviderAstType, dep: CompileDiDependencyMetadata): o.Expression {
|
requestingProviderType: ProviderAstType, dep: CompileDiDependencyMetadata): o.Expression {
|
||||||
var result: o.Expression = null;
|
var result: o.Expression = null;
|
||||||
// constructor content query
|
// constructor content query
|
||||||
if (isBlank(result) && isPresent(dep.query)) {
|
if (!result && isPresent(dep.query)) {
|
||||||
result = this._addQuery(dep.query, null).queryList;
|
result = this._addQuery(dep.query, null).queryList;
|
||||||
}
|
}
|
||||||
|
|
||||||
// constructor view query
|
// constructor view query
|
||||||
if (isBlank(result) && isPresent(dep.viewQuery)) {
|
if (!result && isPresent(dep.viewQuery)) {
|
||||||
result = createQueryList(
|
result = createQueryList(
|
||||||
dep.viewQuery, null,
|
dep.viewQuery, null,
|
||||||
`_viewQuery_${dep.viewQuery.selectors[0].name}_${this.nodeIndex}_${this._componentConstructorViewQueryLists.length}`,
|
`_viewQuery_${dep.viewQuery.selectors[0].name}_${this.nodeIndex}_${this._componentConstructorViewQueryLists.length}`,
|
||||||
@ -328,7 +328,7 @@ export class CompileElement extends CompileNode {
|
|||||||
|
|
||||||
if (isPresent(dep.token)) {
|
if (isPresent(dep.token)) {
|
||||||
// access builtins with special visibility
|
// access builtins with special visibility
|
||||||
if (isBlank(result)) {
|
if (!result) {
|
||||||
if (dep.token.reference ===
|
if (dep.token.reference ===
|
||||||
resolveIdentifierToken(Identifiers.ChangeDetectorRef).reference) {
|
resolveIdentifierToken(Identifiers.ChangeDetectorRef).reference) {
|
||||||
if (requestingProviderType === ProviderAstType.Component) {
|
if (requestingProviderType === ProviderAstType.Component) {
|
||||||
@ -339,7 +339,7 @@ export class CompileElement extends CompileNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// access regular providers on the element
|
// access regular providers on the element
|
||||||
if (isBlank(result)) {
|
if (!result) {
|
||||||
let resolvedProvider = this._resolvedProviders.get(dep.token.reference);
|
let resolvedProvider = this._resolvedProviders.get(dep.token.reference);
|
||||||
// don't allow directives / public services to access private services.
|
// don't allow directives / public services to access private services.
|
||||||
// only components and private services can access private services.
|
// only components and private services can access private services.
|
||||||
@ -361,20 +361,20 @@ export class CompileElement extends CompileNode {
|
|||||||
if (dep.isValue) {
|
if (dep.isValue) {
|
||||||
result = o.literal(dep.value);
|
result = o.literal(dep.value);
|
||||||
}
|
}
|
||||||
if (isBlank(result) && !dep.isSkipSelf) {
|
if (!result && !dep.isSkipSelf) {
|
||||||
result = this._getLocalDependency(requestingProviderType, dep);
|
result = this._getLocalDependency(requestingProviderType, dep);
|
||||||
}
|
}
|
||||||
// check parent elements
|
// check parent elements
|
||||||
while (isBlank(result) && !currElement.parent.isNull()) {
|
while (!result && !currElement.parent.isNull()) {
|
||||||
currElement = currElement.parent;
|
currElement = currElement.parent;
|
||||||
result = currElement._getLocalDependency(
|
result = currElement._getLocalDependency(
|
||||||
ProviderAstType.PublicService, new CompileDiDependencyMetadata({token: dep.token}));
|
ProviderAstType.PublicService, new CompileDiDependencyMetadata({token: dep.token}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isBlank(result)) {
|
if (!result) {
|
||||||
result = injectFromViewParentInjector(dep.token, dep.isOptional);
|
result = injectFromViewParentInjector(dep.token, dep.isOptional);
|
||||||
}
|
}
|
||||||
if (isBlank(result)) {
|
if (!result) {
|
||||||
result = o.NULL_EXPR;
|
result = o.NULL_EXPR;
|
||||||
}
|
}
|
||||||
return getPropertyInView(result, this.view, currElement.view);
|
return getPropertyInView(result, this.view, currElement.view);
|
||||||
@ -411,7 +411,7 @@ function createProviderProperty(
|
|||||||
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) {
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import {CompilePipeMetadata} from '../compile_metadata';
|
import {CompilePipeMetadata} from '../compile_metadata';
|
||||||
import {isBlank, isPresent} from '../facade/lang';
|
import {Identifiers, resolveIdentifier, resolveIdentifierToken} from '../identifiers';
|
||||||
import {Identifiers, identifierToken, resolveIdentifier, resolveIdentifierToken} from '../identifiers';
|
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
|
|
||||||
import {CompileView} from './compile_view';
|
import {CompileView} from './compile_view';
|
||||||
@ -23,7 +22,7 @@ export class CompilePipe {
|
|||||||
if (meta.pure) {
|
if (meta.pure) {
|
||||||
// pure pipes live on the component view
|
// pure pipes live on the component view
|
||||||
pipe = compView.purePipes.get(name);
|
pipe = compView.purePipes.get(name);
|
||||||
if (isBlank(pipe)) {
|
if (!pipe) {
|
||||||
pipe = new CompilePipe(compView, meta);
|
pipe = new CompilePipe(compView, meta);
|
||||||
compView.purePipes.set(name, pipe);
|
compView.purePipes.set(name, pipe);
|
||||||
compView.pipes.push(pipe);
|
compView.pipes.push(pipe);
|
||||||
@ -85,7 +84,7 @@ function _findPipeMeta(view: CompileView, name: string): CompilePipeMetadata {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isBlank(pipeMeta)) {
|
if (!pipeMeta) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Illegal state: Could not find pipe ${name} although the parser should have detected this error!`);
|
`Illegal state: Could not find pipe ${name} although the parser should have detected this error!`);
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompileQueryMetadata, CompileTokenMetadata} from '../compile_metadata';
|
import {CompileQueryMetadata} from '../compile_metadata';
|
||||||
import {ListWrapper} from '../facade/collection';
|
import {ListWrapper} from '../facade/collection';
|
||||||
import {isBlank, isPresent} from '../facade/lang';
|
import {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';
|
||||||
|
|
||||||
@ -101,9 +101,8 @@ function createQueryValues(viewValues: ViewQueryValues): o.Expression[] {
|
|||||||
function mapNestedViews(
|
function mapNestedViews(
|
||||||
declarationAppElement: o.Expression, view: CompileView,
|
declarationAppElement: o.Expression, view: CompileView,
|
||||||
expressions: o.Expression[]): o.Expression {
|
expressions: o.Expression[]): o.Expression {
|
||||||
var adjustedExpressions: o.Expression[] = expressions.map((expr) => {
|
var adjustedExpressions: o.Expression[] = expressions.map(
|
||||||
return o.replaceVarInExpression(o.THIS_EXPR.name, o.variable('nestedView'), expr);
|
(expr) => o.replaceVarInExpression(o.THIS_EXPR.name, o.variable('nestedView'), expr));
|
||||||
});
|
|
||||||
return declarationAppElement.callMethod('mapNestedViews', [
|
return declarationAppElement.callMethod('mapNestedViews', [
|
||||||
o.variable(view.className),
|
o.variable(view.className),
|
||||||
o.fn(
|
o.fn(
|
||||||
@ -129,7 +128,7 @@ export function createQueryList(
|
|||||||
export function addQueryToTokenMap(map: Map<any, CompileQuery[]>, query: CompileQuery) {
|
export function addQueryToTokenMap(map: Map<any, CompileQuery[]>, query: CompileQuery) {
|
||||||
query.meta.selectors.forEach((selector) => {
|
query.meta.selectors.forEach((selector) => {
|
||||||
var entry = map.get(selector.reference);
|
var entry = map.get(selector.reference);
|
||||||
if (isBlank(entry)) {
|
if (!entry) {
|
||||||
entry = [];
|
entry = [];
|
||||||
map.set(selector.reference, entry);
|
map.set(selector.reference, entry);
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,14 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompiledAnimationTriggerResult} from '../animation/animation_compiler';
|
import {AnimationEntryCompileResult} from '../animation/animation_compiler';
|
||||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeMetadata, CompileTokenMetadata} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeMetadata} from '../compile_metadata';
|
||||||
import {CompilerConfig} from '../config';
|
import {CompilerConfig} from '../config';
|
||||||
import {ListWrapper, MapWrapper} from '../facade/collection';
|
import {ListWrapper, MapWrapper} from '../facade/collection';
|
||||||
import {isBlank, isPresent} from '../facade/lang';
|
import {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 {ViewType} from '../private_import_core';
|
import {ViewType} from '../private_import_core';
|
||||||
import {createDiTokenExpression} from '../util';
|
|
||||||
|
|
||||||
import {CompileBinding} from './compile_binding';
|
import {CompileBinding} from './compile_binding';
|
||||||
import {CompileElement, CompileNode} from './compile_element';
|
import {CompileElement, CompileNode} from './compile_element';
|
||||||
@ -23,7 +22,7 @@ import {CompilePipe} from './compile_pipe';
|
|||||||
import {CompileQuery, addQueryToTokenMap, createQueryList} from './compile_query';
|
import {CompileQuery, addQueryToTokenMap, createQueryList} from './compile_query';
|
||||||
import {EventHandlerVars} from './constants';
|
import {EventHandlerVars} from './constants';
|
||||||
import {NameResolver} from './expression_converter';
|
import {NameResolver} from './expression_converter';
|
||||||
import {createPureProxy, getPropertyInView, getViewFactoryName, injectFromViewParentInjector} from './util';
|
import {createPureProxy, getPropertyInView, getViewFactoryName} from './util';
|
||||||
|
|
||||||
export class CompileView implements NameResolver {
|
export class CompileView implements NameResolver {
|
||||||
public viewType: ViewType;
|
public viewType: ViewType;
|
||||||
@ -72,7 +71,7 @@ export class CompileView implements NameResolver {
|
|||||||
constructor(
|
constructor(
|
||||||
public component: CompileDirectiveMetadata, public genConfig: CompilerConfig,
|
public component: CompileDirectiveMetadata, public genConfig: CompilerConfig,
|
||||||
public pipeMetas: CompilePipeMetadata[], public styles: o.Expression,
|
public pipeMetas: CompilePipeMetadata[], public styles: o.Expression,
|
||||||
public animations: CompiledAnimationTriggerResult[], public viewIndex: number,
|
public animations: AnimationEntryCompileResult[], public viewIndex: number,
|
||||||
public declarationElement: CompileElement, public templateVariableBindings: string[][]) {
|
public declarationElement: CompileElement, public templateVariableBindings: string[][]) {
|
||||||
this.createMethod = new CompileMethod(this);
|
this.createMethod = new CompileMethod(this);
|
||||||
this.animationBindingsMethod = new CompileMethod(this);
|
this.animationBindingsMethod = new CompileMethod(this);
|
||||||
@ -139,7 +138,7 @@ export class CompileView implements NameResolver {
|
|||||||
}
|
}
|
||||||
var currView: CompileView = this;
|
var currView: CompileView = this;
|
||||||
var result = currView.locals.get(name);
|
var result = currView.locals.get(name);
|
||||||
while (isBlank(result) && isPresent(currView.declarationElement.view)) {
|
while (!result && isPresent(currView.declarationElement.view)) {
|
||||||
currView = currView.declarationElement.view;
|
currView = currView.declarationElement.view;
|
||||||
result = currView.locals.get(name);
|
result = currView.locals.get(name);
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
import {ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core';
|
import {ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core';
|
||||||
|
|
||||||
import {CompileIdentifierMetadata} from '../compile_metadata';
|
import {CompileIdentifierMetadata} from '../compile_metadata';
|
||||||
import {isBlank} from '../facade/lang';
|
|
||||||
import {Identifiers, resolveEnumIdentifier, resolveIdentifier} from '../identifiers';
|
import {Identifiers, resolveEnumIdentifier, resolveIdentifier} from '../identifiers';
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
|
|
||||||
|
@ -7,11 +7,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompileDirectiveMetadata} from '../compile_metadata';
|
import {CompileDirectiveMetadata} from '../compile_metadata';
|
||||||
import {ListWrapper, StringMapWrapper} from '../facade/collection';
|
import {StringWrapper, isPresent} from '../facade/lang';
|
||||||
import {StringWrapper, isBlank, isPresent} from '../facade/lang';
|
import {identifierToken} from '../identifiers';
|
||||||
import {Identifiers, identifierToken, resolveIdentifier} from '../identifiers';
|
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
import {AnimationOutput} from '../private_import_core';
|
|
||||||
import {BoundEventAst, DirectiveAst} from '../template_parser/template_ast';
|
import {BoundEventAst, DirectiveAst} from '../template_parser/template_ast';
|
||||||
|
|
||||||
import {CompileBinding} from './compile_binding';
|
import {CompileBinding} from './compile_binding';
|
||||||
@ -20,10 +18,6 @@ import {CompileMethod} from './compile_method';
|
|||||||
import {EventHandlerVars, ViewProperties} from './constants';
|
import {EventHandlerVars, ViewProperties} from './constants';
|
||||||
import {convertCdStatementToIr} from './expression_converter';
|
import {convertCdStatementToIr} from './expression_converter';
|
||||||
|
|
||||||
export class CompileElementAnimationOutput {
|
|
||||||
constructor(public listener: CompileEventListener, public output: AnimationOutput) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CompileEventListener {
|
export class CompileEventListener {
|
||||||
private _method: CompileMethod;
|
private _method: CompileMethod;
|
||||||
private _hasComponentHostListener: boolean = false;
|
private _hasComponentHostListener: boolean = false;
|
||||||
@ -32,13 +26,14 @@ export class CompileEventListener {
|
|||||||
private _actionResultExprs: o.Expression[] = [];
|
private _actionResultExprs: o.Expression[] = [];
|
||||||
|
|
||||||
static getOrCreate(
|
static getOrCreate(
|
||||||
compileElement: CompileElement, eventTarget: string, eventName: string,
|
compileElement: CompileElement, eventTarget: string, eventName: string, eventPhase: string,
|
||||||
targetEventListeners: CompileEventListener[]): CompileEventListener {
|
targetEventListeners: CompileEventListener[]): CompileEventListener {
|
||||||
var listener = targetEventListeners.find(
|
var listener = targetEventListeners.find(
|
||||||
listener => listener.eventTarget == eventTarget && listener.eventName == eventName);
|
listener => listener.eventTarget == eventTarget && listener.eventName == eventName &&
|
||||||
if (isBlank(listener)) {
|
listener.eventPhase == eventPhase);
|
||||||
|
if (!listener) {
|
||||||
listener = new CompileEventListener(
|
listener = new CompileEventListener(
|
||||||
compileElement, eventTarget, eventName, targetEventListeners.length);
|
compileElement, eventTarget, eventName, eventPhase, targetEventListeners.length);
|
||||||
targetEventListeners.push(listener);
|
targetEventListeners.push(listener);
|
||||||
}
|
}
|
||||||
return listener;
|
return listener;
|
||||||
@ -48,7 +43,7 @@ export class CompileEventListener {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public compileElement: CompileElement, public eventTarget: string, public eventName: string,
|
public compileElement: CompileElement, public eventTarget: string, public eventName: string,
|
||||||
listenerIndex: number) {
|
public eventPhase: string, listenerIndex: number) {
|
||||||
this._method = new CompileMethod(compileElement.view);
|
this._method = new CompileMethod(compileElement.view);
|
||||||
this._methodName =
|
this._methodName =
|
||||||
`_handle_${santitizeEventName(eventName)}_${compileElement.nodeIndex}_${listenerIndex}`;
|
`_handle_${santitizeEventName(eventName)}_${compileElement.nodeIndex}_${listenerIndex}`;
|
||||||
@ -119,7 +114,7 @@ export class CompileEventListener {
|
|||||||
disposable.set(listenExpr).toDeclStmt(o.FUNCTION_TYPE, [o.StmtModifier.Private]));
|
disposable.set(listenExpr).toDeclStmt(o.FUNCTION_TYPE, [o.StmtModifier.Private]));
|
||||||
}
|
}
|
||||||
|
|
||||||
listenToAnimation(output: AnimationOutput) {
|
listenToAnimation() {
|
||||||
var outputListener = o.THIS_EXPR.callMethod(
|
var outputListener = o.THIS_EXPR.callMethod(
|
||||||
'eventHandler',
|
'eventHandler',
|
||||||
[o.THIS_EXPR.prop(this._methodName).callMethod(o.BuiltinMethod.Bind, [o.THIS_EXPR])]);
|
[o.THIS_EXPR.prop(this._methodName).callMethod(o.BuiltinMethod.Bind, [o.THIS_EXPR])]);
|
||||||
@ -129,11 +124,8 @@ export class CompileEventListener {
|
|||||||
.callMethod(
|
.callMethod(
|
||||||
'registerAnimationOutput',
|
'registerAnimationOutput',
|
||||||
[
|
[
|
||||||
this.compileElement.renderNode,
|
this.compileElement.renderNode, o.literal(this.eventName),
|
||||||
o.importExpr(resolveIdentifier(Identifiers.AnimationOutput)).instantiate([
|
o.literal(this.eventPhase), outputListener
|
||||||
o.literal(output.name), o.literal(output.phase)
|
|
||||||
]),
|
|
||||||
outputListener
|
|
||||||
])
|
])
|
||||||
.toStmt();
|
.toStmt();
|
||||||
this.compileElement.view.createMethod.addStmt(stmt);
|
this.compileElement.view.createMethod.addStmt(stmt);
|
||||||
@ -160,7 +152,7 @@ export function collectEventListeners(
|
|||||||
hostEvents.forEach((hostEvent) => {
|
hostEvents.forEach((hostEvent) => {
|
||||||
compileElement.view.bindings.push(new CompileBinding(compileElement, hostEvent));
|
compileElement.view.bindings.push(new CompileBinding(compileElement, hostEvent));
|
||||||
var listener = CompileEventListener.getOrCreate(
|
var listener = CompileEventListener.getOrCreate(
|
||||||
compileElement, hostEvent.target, hostEvent.name, eventListeners);
|
compileElement, hostEvent.target, hostEvent.name, hostEvent.phase, eventListeners);
|
||||||
listener.addAction(hostEvent, null, null);
|
listener.addAction(hostEvent, null, null);
|
||||||
});
|
});
|
||||||
dirs.forEach((directiveAst) => {
|
dirs.forEach((directiveAst) => {
|
||||||
@ -169,7 +161,7 @@ export function collectEventListeners(
|
|||||||
directiveAst.hostEvents.forEach((hostEvent) => {
|
directiveAst.hostEvents.forEach((hostEvent) => {
|
||||||
compileElement.view.bindings.push(new CompileBinding(compileElement, hostEvent));
|
compileElement.view.bindings.push(new CompileBinding(compileElement, hostEvent));
|
||||||
var listener = CompileEventListener.getOrCreate(
|
var listener = CompileEventListener.getOrCreate(
|
||||||
compileElement, hostEvent.target, hostEvent.name, eventListeners);
|
compileElement, hostEvent.target, hostEvent.name, hostEvent.phase, eventListeners);
|
||||||
listener.addAction(hostEvent, directiveAst.directive, directiveInstance);
|
listener.addAction(hostEvent, directiveAst.directive, directiveInstance);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -180,9 +172,8 @@ export function collectEventListeners(
|
|||||||
export function bindDirectiveOutputs(
|
export function bindDirectiveOutputs(
|
||||||
directiveAst: DirectiveAst, directiveInstance: o.Expression,
|
directiveAst: DirectiveAst, directiveInstance: o.Expression,
|
||||||
eventListeners: CompileEventListener[]) {
|
eventListeners: CompileEventListener[]) {
|
||||||
StringMapWrapper.forEach(
|
Object.keys(directiveAst.directive.outputs).forEach(observablePropName => {
|
||||||
directiveAst.directive.outputs,
|
const eventName = directiveAst.directive.outputs[observablePropName];
|
||||||
(eventName: any /** TODO #9100 */, observablePropName: any /** TODO #9100 */) => {
|
|
||||||
eventListeners.filter(listener => listener.eventName == eventName).forEach((listener) => {
|
eventListeners.filter(listener => listener.eventName == eventName).forEach((listener) => {
|
||||||
listener.listenToDirective(directiveInstance, observablePropName);
|
listener.listenToDirective(directiveInstance, observablePropName);
|
||||||
});
|
});
|
||||||
@ -190,11 +181,13 @@ export function bindDirectiveOutputs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function bindRenderOutputs(eventListeners: CompileEventListener[]) {
|
export function bindRenderOutputs(eventListeners: CompileEventListener[]) {
|
||||||
eventListeners.forEach(listener => listener.listenToRenderer());
|
eventListeners.forEach(listener => {
|
||||||
|
if (listener.eventPhase) {
|
||||||
|
listener.listenToAnimation();
|
||||||
|
} else {
|
||||||
|
listener.listenToRenderer();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
export function bindAnimationOutputs(eventListeners: CompileElementAnimationOutput[]) {
|
|
||||||
eventListeners.forEach(entry => { entry.listener.listenToAnimation(entry.output); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertStmtIntoExpression(stmt: o.Statement): o.Expression {
|
function convertStmtIntoExpression(stmt: o.Statement): o.Expression {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user