diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 202ffbdec415..c7b68e623491 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,3 +1,7 @@
+
+
**I'm submitting a ...** (check one with "x")
```
[ ] bug report => search github for a similar issue or PR before submitting
@@ -5,14 +9,18 @@
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
```
-**Current behavior**
+**Current behavior**
**Expected behavior**
-**Reproduction of the problem**
-
+**Minimal reproduction of the problem with instructions**
+
**What is the motivation / use case for changing the behavior?**
@@ -20,12 +28,12 @@
**Please tell us about your environment:**
-* **Angular version:** 2.0.0-rc.X
+* **Angular version:** 2.0.X
-* **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 ]
* **Language:** [all | TypeScript X.X | ES6/7 | ES5]
-
+
* **Node (for AoT issues):** `node --version` =
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f864ee961570..5b6c83b7a768 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,45 @@
+
+## [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 `` ctype names ([7578d85](https://github.com/angular/angular/commit/7578d85)), closes [#12000](https://github.com/angular/angular/issues/12000)
+
+
+
+## [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)
+
+
+
# [2.0.0](https://github.com/angular/angular/compare/2.0.0-rc.7...2.0.0) (2016-09-14)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ca3f837068ad..cadac6f60bd3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -18,7 +18,7 @@ Help us keep Angular open and inclusive. Please read and follow our [Code of Con
## Got a Question or Problem?
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].
## Found an Issue?
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
## Want a Feature?
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
-a proposal for your work first, to be sure that we can use it. Angular 2 is in developer preview
-and we are not ready to accept major contributions ahead of the full release.
+a proposal for your work first, to be sure that we can use it.
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
diff --git a/DEVELOPER.md b/DEVELOPER.md
index ac7e15f44f35..2ce368ab814f 100644
--- a/DEVELOPER.md
+++ b/DEVELOPER.md
@@ -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.
- 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
diff --git a/README.md b/README.md
index c6d25eb346a5..65727f024bb5 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,6 @@
[](http://issuestats.com/github/angular/angular)
[](http://issuestats.com/github/angular/angular)
[](https://badge.fury.io/js/%40angular%2Fcore)
-[](https://npmjs.org/package/angular2)
[](https://saucelabs.com/u/angular2-ci)
*Safari (7+), iOS (7+), Edge (14) and IE mobile (11) are tested on [BrowserStack][browserstack].*
diff --git a/TRIAGE_AND_LABELS.md b/TRIAGE_AND_LABELS.md
index d184f5df779b..e50dc9436f53 100644
--- a/TRIAGE_AND_LABELS.md
+++ b/TRIAGE_AND_LABELS.md
@@ -17,9 +17,9 @@ with it.
* `comp: animations`: `@matsko`
* `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: 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.
* `comp: forms`: `@kara`
* `comp: http`: `@jeffbcross`
@@ -29,14 +29,14 @@ with it.
* `comp: testing`: `@juliemr`
* `comp: upgrade`: `@mhevery`
* `comp: web-worker`: `@vicb`
-* `comp: zone`: `@mhevery`
+* `comp: zones`: `@mhevery`
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
even thought no specific source tree is associated with them.
* `comp: documentation`: `@naomiblack`
-* `comp: packaging`: `@mhevery`
+* `comp: packaging`: `@IgorMinar`
* `comp: performance`: `@tbosch`
* `comp: security`: `@IgorMinar`
diff --git a/browser-providers.conf.js b/browser-providers.conf.js
index 5143e9adca6e..5e75463f1290 100644
--- a/browser-providers.conf.js
+++ b/browser-providers.conf.js
@@ -1,216 +1,98 @@
-// Unique place to configure the browsers which are used in the different CI jobs in Sauce Labs (SL) and BrowserStack (BS).
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+// Unique place to configure the browsers which are used in the different CI jobs in Sauce Labs (SL)
+// and BrowserStack (BS).
// If the target is set to null, then the browser is not run anywhere during CI.
-// If 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 = {
- 'Chrome': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
- 'Firefox': { 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}},
// FirefoxBeta and ChromeBeta should be target:'BS' or target:'SL', and required:true
// Currently deactivated due to https://github.com/angular/angular/issues/7560
- 'ChromeBeta': { unitTest: {target: null, required: true}, e2e: {target: null, required: false}},
- 'FirefoxBeta': { unitTest: {target: null, required: false}, e2e: {target: null, required: false}},
- 'ChromeDev': { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
- 'FirefoxDev': { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
- 'IE9': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
- 'IE10': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
- 'IE11': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
- 'Edge': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
- 'Android4.1': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
- 'Android4.2': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
- 'Android4.3': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
- 'Android4.4': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
- 'Android5': { unitTest: {target: 'SL', 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}},
- 'Safari9': { unitTest: {target: 'BS', required: false}, 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}},
- 'iOS9': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
- 'WindowsPhone': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
+ 'ChromeBeta': {unitTest: {target: null, required: true}, e2e: {target: null, required: false}},
+ 'FirefoxBeta': {unitTest: {target: null, required: false}, e2e: {target: null, required: false}},
+ 'ChromeDev': {unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
+ 'FirefoxDev': {unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
+ 'IE9': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
+ 'IE10': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
+ 'IE11': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
+ 'Edge': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
+ 'Android4.1': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
+ 'Android4.2': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
+ 'Android4.3': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
+ 'Android4.4': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
+ 'Android5': {unitTest: {target: 'SL', 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}},
+ '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}},
+ 'iOS8': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
+ 'iOS9': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
+ 'iOS10': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
+ 'WindowsPhone': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
};
var customLaunchers = {
- 'DartiumWithWebPlatform': {
- base: 'Dartium',
- flags: ['--enable-experimental-web-platform-features'] },
- 'ChromeNoSandbox': {
- base: 'Chrome',
- flags: ['--no-sandbox'] },
- 'SL_CHROME': {
- base: 'SauceLabs',
- browserName: 'chrome',
- version: '52'
- },
- 'SL_CHROMEBETA': {
- base: 'SauceLabs',
- browserName: 'chrome',
- version: 'beta'
- },
- 'SL_CHROMEDEV': {
- base: 'SauceLabs',
- browserName: 'chrome',
- version: 'dev'
- },
- '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'
- },
+ 'DartiumWithWebPlatform':
+ {base: 'Dartium', flags: ['--enable-experimental-web-platform-features']},
+ 'ChromeNoSandbox': {base: 'Chrome', flags: ['--no-sandbox']},
+ 'SL_CHROME': {base: 'SauceLabs', browserName: 'chrome', version: '52'},
+ 'SL_CHROMEBETA': {base: 'SauceLabs', browserName: 'chrome', version: 'beta'},
+ 'SL_CHROMEDEV': {base: 'SauceLabs', browserName: 'chrome', version: 'dev'},
+ '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_SAFARI10':
+ {base: 'SauceLabs', browserName: 'safari', platform: 'OS X 10.12', version: '10.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_IOS10': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '10.0'},
+ 'SL_IE9':
+ {base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 2008', version: '9'},
'SL_IE10': {
base: 'SauceLabs',
browserName: 'internet explorer',
platform: 'Windows 2012',
version: '10'
},
- 'SL_IE11': {
- base: 'SauceLabs',
- browserName: 'internet explorer',
- platform: 'Windows 8.1',
- version: '11'
- },
+ 'SL_IE11':
+ {base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 8.1', version: '11'},
'SL_EDGE': {
base: 'SauceLabs',
browserName: 'MicrosoftEdge',
platform: 'Windows 10',
version: '13.10586'
},
- 'SL_ANDROID4.1': {
- base: 'SauceLabs',
- browserName: 'android',
- platform: 'Linux',
- version: '4.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'
- },
+ 'SL_ANDROID4.1': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.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': {
- base: 'BrowserStack',
- browser: 'chrome',
- os: 'OS X',
- os_version: 'Yosemite'
- },
- 'BS_FIREFOX': {
- base: 'BrowserStack',
- browser: 'firefox',
- os: 'Windows',
- os_version: '10'
- },
- '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_CHROME': {base: 'BrowserStack', browser: 'chrome', os: 'OS X', os_version: 'Yosemite'},
+ 'BS_FIREFOX': {base: 'BrowserStack', browser: 'firefox', os: 'Windows', os_version: '10'},
+ '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_SAFARI10': {base: 'BrowserStack', browser: 'safari', os: 'OS X', os_version: 'Sierra'},
+ '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_IOS10': {base: 'BrowserStack', device: 'iPhone SE', os: 'ios', os_version: '10.0'},
+ 'BS_IE9':
+ {base: 'BrowserStack', browser: 'ie', browser_version: '9.0', os: 'Windows', os_version: '7'},
'BS_IE10': {
base: 'BrowserStack',
browser: 'ie',
@@ -225,58 +107,35 @@ var customLaunchers = {
os: 'Windows',
os_version: '10'
},
- 'BS_EDGE': {
- base: 'BrowserStack',
- browser: 'edge',
- os: 'Windows',
- os_version: '10'
- },
- 'BS_WINDOWSPHONE' : {
- base: 'BrowserStack',
- device: 'Nokia Lumia 930',
- os: 'winphone',
- os_version: '8.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'
- }
+ 'BS_EDGE': {base: 'BrowserStack', browser: 'edge', os: 'Windows', os_version: '10'},
+ 'BS_WINDOWSPHONE':
+ {base: 'BrowserStack', device: 'Nokia Lumia 930', os: 'winphone', os_version: '8.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 = {
- 'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'SauceLabs';}),
- 'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
- 'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
+ 'ALL': Object.keys(customLaunchers).filter(function(item) {
+ return customLaunchers[item].base == 'SauceLabs';
+ }),
+ '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'],
'IE': ['SL_IE9', 'SL_IE10', 'SL_IE11'],
- 'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
- 'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
+ 'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9', 'SL_IOS10'],
+ 'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9', 'SL_SAFARI10'],
'BETA': ['SL_CHROMEBETA', 'SL_FIREFOXBETA'],
'DEV': ['SL_CHROMEDEV', 'SL_FIREFOXDEV'],
'CI_REQUIRED': buildConfiguration('unitTest', 'SL', true),
@@ -284,13 +143,20 @@ var sauceAliases = {
};
var browserstackAliases = {
- 'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'BrowserStack';}),
- 'DESKTOP': ['BS_CHROME', 'BS_FIREFOX', 'BS_IE9', 'BS_IE10', 'BS_IE11', 'BS_EDGE', 'BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
- 'MOBILE': ['BS_ANDROID4.3', 'BS_ANDROID4.4', 'BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_WINDOWSPHONE'],
+ 'ALL': Object.keys(customLaunchers).filter(function(item) {
+ return customLaunchers[item].base == 'BrowserStack';
+ }),
+ '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'],
'IE': ['BS_IE9', 'BS_IE10', 'BS_IE11'],
- 'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9'],
- 'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
+ 'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_IOS10'],
+ 'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9', 'BS_SAFARI10'],
'CI_REQUIRED': buildConfiguration('unitTest', 'BS', true),
'CI_OPTIONAL': buildConfiguration('unitTest', 'BS', false)
};
@@ -303,11 +169,9 @@ module.exports = {
function buildConfiguration(type, target, required) {
return Object.keys(CIconfiguration)
- .filter((item) => {
- var conf = CIconfiguration[item][type];
- return conf.required === required && conf.target === target;
- })
- .map((item) => {
- return target + '_' + item.toUpperCase();
- });
+ .filter((item) => {
+ var conf = CIconfiguration[item][type];
+ return conf.required === required && conf.target === target;
+ })
+ .map((item) => target + '_' + item.toUpperCase());
}
diff --git a/gulpfile.js b/gulpfile.js
index 99abcbec26c1..ce41eeeb2921 100644
--- a/gulpfile.js
+++ b/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';
// THIS CHECK SHOULD BE THE FIRST THING IN THIS FILE
@@ -13,12 +21,14 @@ const os = require('os');
// clang-format entry points
const srcsToFmt = [
- 'modules/@angular/**/*.ts',
- 'modules/benchmarks/**/*.ts',
- 'modules/e2e_util/**/*.ts',
- 'modules/playground/**/*.ts',
- 'tools/**/*.ts',
+ 'modules/@angular/**/*.{js,ts}',
+ 'modules/benchmarks/**/*.{js,ts}',
+ 'modules/e2e_util/**/*.{js,ts}',
+ 'modules/playground/**/*.{js,ts}',
+ 'tools/**/*.{js,ts}',
'!tools/public_api_guard/**/*.d.ts',
+ './*.{js,ts}',
+ '!shims_for_IE.js',
];
// Check source code for formatting errors (clang-format)
@@ -26,15 +36,16 @@ gulp.task('format:enforce', () => {
const format = require('gulp-clang-format');
const clangFormat = require('clang-format');
return gulp.src(srcsToFmt).pipe(
- format.checkFormat('file', clangFormat, {verbose: true, fail: true}));
+ format.checkFormat('file', clangFormat, {verbose: true, fail: true}));
});
// Format the source code with clang-format (see .clang-format)
gulp.task('format', () => {
const format = require('gulp-clang-format');
const clangFormat = require('clang-format');
- return gulp.src(srcsToFmt, { base: '.' }).pipe(
- format.format('file', clangFormat)).pipe(gulp.dest('.'));
+ return gulp.src(srcsToFmt, {base: '.'})
+ .pipe(format.format('file', clangFormat))
+ .pipe(gulp.dest('.'));
});
const entrypoints = [
@@ -62,12 +73,18 @@ const entrypoints = [
];
const publicApiDir = path.normalize('tools/public_api_guard');
const publicApiArgs = [
- '--rootDir', 'dist/packages-dist',
- '--stripExportPattern', '^__',
- '--allowModuleIdentifiers', 'jasmine',
- '--allowModuleIdentifiers', 'protractor',
- '--allowModuleIdentifiers', 'angular',
- '--onStabilityMissing', 'error',
+ '--rootDir',
+ 'dist/packages-dist',
+ '--stripExportPattern',
+ '^__',
+ '--allowModuleIdentifiers',
+ 'jasmine',
+ '--allowModuleIdentifiers',
+ 'protractor',
+ '--allowModuleIdentifiers',
+ 'angular',
+ '--onStabilityMissing',
+ 'error',
].concat(entrypoints);
// Build angular
@@ -83,17 +100,17 @@ gulp.task('public-api:enforce', (done) => {
const childProcess = require('child_process');
childProcess
- .spawn(
- path.join(__dirname, platformScriptPath(`/node_modules/.bin/ts-api-guardian`)),
- ['--verifyDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
- .on('close', (errorCode) => {
- if (errorCode !== 0) {
- done(new Error(
- 'Public API differs from golden file. Please run `gulp public-api:update`.'));
- } else {
- done();
- }
- });
+ .spawn(
+ path.join(__dirname, platformScriptPath(`/node_modules/.bin/ts-api-guardian`)),
+ ['--verifyDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
+ .on('close', (errorCode) => {
+ if (errorCode !== 0) {
+ done(new Error(
+ 'Public API differs from golden file. Please run `gulp public-api:update`.'));
+ } else {
+ done();
+ }
+ });
});
// Generate the public API golden files
@@ -101,20 +118,24 @@ gulp.task('public-api:update', ['build.sh'], (done) => {
const childProcess = require('child_process');
childProcess
- .spawn(
- path.join(__dirname, platformScriptPath(`/node_modules/.bin/ts-api-guardian`)),
- ['--outDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
- .on('close', done);
+ .spawn(
+ path.join(__dirname, platformScriptPath(`/node_modules/.bin/ts-api-guardian`)),
+ ['--outDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
+ .on('close', done);
});
-// Checks tests for presence of ddescribe, fdescribe, fit, iit and fails the build if one of the focused tests is found.
-// Currently xdescribe and xit are _not_ reported as errors since there are a couple of excluded tests in our code base.
+// Checks tests for presence of ddescribe, fdescribe, fit, iit and fails the build if one of the
+// focused tests is found.
+// Currently xdescribe and xit are _not_ reported as errors since there are a couple of excluded
+// tests in our code base.
gulp.task('check-tests', function() {
const ddescribeIit = require('gulp-ddescribe-iit');
- return gulp.src([
- 'modules/**/*.spec.ts',
- 'modules/**/*_spec.ts',
- ]).pipe(ddescribeIit({allowDisabledTests: true}));
+ return gulp
+ .src([
+ 'modules/**/*.spec.ts',
+ 'modules/**/*_spec.ts',
+ ])
+ .pipe(ddescribeIit({allowDisabledTests: true}));
});
// Check the coding standards and programming errors
@@ -123,14 +144,21 @@ gulp.task('lint', ['check-tests', 'format:enforce', 'tools:build'], () => {
// Built-in rules are at
// https://github.com/palantir/tslint#supported-rules
const tslintConfig = require('./tslint.json');
- return gulp.src(['modules/@angular/**/*.ts', 'modules/benchpress/**/*.ts'])
- .pipe(tslint({
- tslint: require('tslint').default,
- configuration: tslintConfig,
- rulesDirectory: 'dist/tools/tslint',
- formatter: 'prose',
- }))
- .pipe(tslint.report({emitError: true}));
+ 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({
+ tslint: require('tslint').default,
+ configuration: tslintConfig,
+ rulesDirectory: 'dist/tools/tslint',
+ formatter: 'prose',
+ }))
+ .pipe(tslint.report({emitError: true}));
});
gulp.task('tools:build', (done) => { tsc('tools/', done); });
@@ -142,7 +170,7 @@ gulp.task('check-cycle', (done) => {
const dependencyObject = madge(['dist/all/'], {
format: 'cjs',
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();
if (circularDependencies.length > 0) {
@@ -173,11 +201,11 @@ gulp.task('serve-examples', () => {
const cors = require('cors');
connect.server({
- root: `${__dirname}/dist/examples`,
- port: 8001,
- livereload: false,
- open: false,
- middleware: (connect, opt) => [cors()],
+ root: `${__dirname}/dist/examples`,
+ port: 8001,
+ livereload: false,
+ open: false,
+ middleware: (connect, opt) => [cors()],
});
});
@@ -187,16 +215,13 @@ gulp.task('changelog', () => {
const conventionalChangelog = require('gulp-conventional-changelog');
return gulp.src('CHANGELOG.md')
- .pipe(conventionalChangelog({
- preset: 'angular',
- releaseCount: 1
- }, {
- // Conventional Changelog Context
- // 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
- currentTag: require('./package.json').version
- }))
- .pipe(gulp.dest('./'));
+ .pipe(conventionalChangelog({preset: 'angular', releaseCount: 1}, {
+ // Conventional Changelog Context
+ // 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
+ currentTag: require('./package.json').version
+ }))
+ .pipe(gulp.dest('./'));
});
function tsc(projectPath, done) {
@@ -205,8 +230,7 @@ function tsc(projectPath, done) {
childProcess
.spawn(
path.normalize(platformScriptPath(`${__dirname}/node_modules/.bin/tsc`)),
- ['-p', path.join(__dirname, projectPath)],
- {stdio: 'inherit'})
+ ['-p', path.join(__dirname, projectPath)], {stdio: 'inherit'})
.on('close', done);
}
diff --git a/karma-js.conf.js b/karma-js.conf.js
index 7a4d3cedc12a..443bf417df4e 100644
--- a/karma-js.conf.js
+++ b/karma-js.conf.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
+ */
+
var browserProvidersConf = require('./browser-providers.conf.js');
var internalAngularReporter = require('./tools/karma/reporter.js');
@@ -17,24 +25,25 @@ module.exports = function(config) {
// include Angular v1 for upgrade module testing
'node_modules/angular/angular.min.js',
- 'node_modules/zone.js/dist/zone.js',
- 'node_modules/zone.js/dist/long-stack-trace-zone.js',
- 'node_modules/zone.js/dist/proxy.js',
- 'node_modules/zone.js/dist/sync-test.js',
- 'node_modules/zone.js/dist/jasmine-patch.js',
- 'node_modules/zone.js/dist/async-test.js',
+ 'node_modules/zone.js/dist/zone.js', 'node_modules/zone.js/dist/long-stack-trace-zone.js',
+ 'node_modules/zone.js/dist/proxy.js', 'node_modules/zone.js/dist/sync-test.js',
+ 'node_modules/zone.js/dist/jasmine-patch.js', 'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/fake-async-test.js',
// Including systemjs because it defines `__eval`, which produces correct stack traces.
- 'shims_for_IE.js',
- 'node_modules/systemjs/dist/system.src.js',
+ 'shims_for_IE.js', 'node_modules/systemjs/dist/system.src.js',
{pattern: 'node_modules/rxjs/**', included: false, watched: false, served: true},
- 'node_modules/reflect-metadata/Reflect.js',
- 'tools/build/file2modulename.js',
- 'test-main.js',
- {pattern: 'dist/all/empty.*', included: false, watched: false},
- {pattern: 'modules/@angular/platform-browser/test/static_assets/**', included: false, watched: false},
- {pattern: 'modules/@angular/platform-browser/test/browser/static_assets/**', included: false, watched: false}
+ 'node_modules/reflect-metadata/Reflect.js', 'tools/build/file2modulename.js', 'test-main.js',
+ {pattern: 'dist/all/empty.*', included: false, watched: false}, {
+ pattern: 'modules/@angular/platform-browser/test/static_assets/**',
+ included: false,
+ watched: false
+ },
+ {
+ pattern: 'modules/@angular/platform-browser/test/browser/static_assets/**',
+ included: false,
+ watched: false,
+ }
],
exclude: [
@@ -44,7 +53,7 @@ module.exports = function(config) {
'dist/all/@angular/benchpress/**',
'dist/all/angular1_router.js',
'dist/all/@angular/platform-browser/testing/e2e_util.js',
- 'dist/examples/**/e2e_test/**'
+ 'dist/examples/**/e2e_test/**',
],
customLaunchers: browserProvidersConf.customLaunchers,
@@ -55,11 +64,11 @@ module.exports = function(config) {
'karma-sauce-launcher',
'karma-chrome-launcher',
'karma-sourcemap-loader',
- internalAngularReporter
+ internalAngularReporter,
],
preprocessors: {
- '**/*.js': ['sourcemap']
+ '**/*.js': ['sourcemap'],
},
reporters: ['internal-angular'],
@@ -73,7 +82,7 @@ module.exports = function(config) {
'selenium-version': '2.53.0',
'command-timeout': 600,
'idle-timeout': 600,
- 'max-duration': 5400
+ 'max-duration': 5400,
}
},
@@ -82,20 +91,21 @@ module.exports = function(config) {
startTunnel: false,
retryLimit: 3,
timeout: 600,
- pollingTimeout: 10000
+ pollingTimeout: 10000,
},
browsers: ['Chrome'],
port: 9876,
captureTimeout: 60000,
- browserDisconnectTimeout : 60000,
- browserDisconnectTolerance : 3,
- browserNoActivityTimeout : 60000,
+ browserDisconnectTimeout: 60000,
+ browserDisconnectTolerance: 3,
+ browserNoActivityTimeout: 60000,
});
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')) {
config.sauceLabs.build = buildId;
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
diff --git a/modules/@angular/benchpress/src/common_options.ts b/modules/@angular/benchpress/src/common_options.ts
index 7dc5b72730c3..255862e629d3 100644
--- a/modules/@angular/benchpress/src/common_options.ts
+++ b/modules/@angular/benchpress/src/common_options.ts
@@ -9,8 +9,6 @@
import {OpaqueToken} from '@angular/core';
import * as fs from 'fs';
-import {DateWrapper} from './facade/lang';
-
export class Options {
static SAMPLE_ID = new OpaqueToken('Options.sampleId');
static DEFAULT_DESCRIPTION = new OpaqueToken('Options.defaultDescription');
@@ -34,7 +32,7 @@ export class Options {
{provide: Options.FORCE_GC, useValue: false},
{provide: Options.PREPARE, useValue: Options.NO_PREPARE},
{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.REQUEST_COUNT, useValue: false},
{provide: Options.CAPTURE_FRAMES, useValue: false},
diff --git a/modules/@angular/benchpress/src/measure_values.ts b/modules/@angular/benchpress/src/measure_values.ts
index c8ef430a4086..13a67238dc41 100644
--- a/modules/@angular/benchpress/src/measure_values.ts
+++ b/modules/@angular/benchpress/src/measure_values.ts
@@ -6,18 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {Map} from './facade/collection';
-import {Date, DateWrapper} from './facade/lang';
-
export class MeasureValues {
constructor(
public runIndex: number, public timeStamp: Date, public values: {[key: string]: any}) {}
toJson() {
return {
- 'timeStamp': DateWrapper.toJson(this.timeStamp),
+ 'timeStamp': this.timeStamp.toJSON(),
'runIndex': this.runIndex,
- 'values': this.values
+ 'values': this.values,
};
}
}
diff --git a/modules/@angular/benchpress/src/metric/multi_metric.ts b/modules/@angular/benchpress/src/metric/multi_metric.ts
index 09b4668836a4..1a92a3320023 100644
--- a/modules/@angular/benchpress/src/metric/multi_metric.ts
+++ b/modules/@angular/benchpress/src/metric/multi_metric.ts
@@ -7,7 +7,6 @@
*/
import {Injector, OpaqueToken} from '@angular/core';
-import {StringMapWrapper} from '../facade/collection';
import {Metric} from '../metric';
@@ -57,8 +56,7 @@ export class MultiMetric extends Metric {
function mergeStringMaps(maps: {[key: string]: string}[]): {[key: string]: string} {
var result: {[key: string]: string} = {};
- maps.forEach(
- map => { StringMapWrapper.forEach(map, (value, prop) => { result[prop] = value; }); });
+ maps.forEach(map => { Object.keys(map).forEach(prop => { result[prop] = map[prop]; }); });
return result;
}
diff --git a/modules/@angular/benchpress/src/metric/user_metric.ts b/modules/@angular/benchpress/src/metric/user_metric.ts
index 05d43e5d98e1..e1c221df268e 100644
--- a/modules/@angular/benchpress/src/metric/user_metric.ts
+++ b/modules/@angular/benchpress/src/metric/user_metric.ts
@@ -6,10 +6,9 @@
* 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 {StringMapWrapper} from '../facade/collection';
import {isNumber} from '../facade/lang';
import {Metric} from '../metric';
import {WebDriverAdapter} from '../web_driver_adapter';
@@ -40,7 +39,7 @@ export class UserMetric extends Metric {
reject = rej;
});
let adapter = this._wdAdapter;
- let names = StringMapWrapper.keys(this._userMetrics);
+ let names = Object.keys(this._userMetrics);
function getAndClearValues() {
Promise.all(names.map(name => adapter.executeScript(`return window.${name}`)))
@@ -48,9 +47,9 @@ export class UserMetric extends Metric {
if (values.every(isNumber)) {
Promise.all(names.map(name => adapter.executeScript(`delete window.${name}`)))
.then((_: any[]) => {
- let map = StringMapWrapper.create();
+ let map: {[k: string]: any} = {};
for (let i = 0, n = names.length; i < n; i++) {
- StringMapWrapper.set(map, names[i], values[i]);
+ map[names[i]] = values[i];
}
resolve(map);
}, reject);
diff --git a/modules/@angular/benchpress/src/reporter/console_reporter.ts b/modules/@angular/benchpress/src/reporter/console_reporter.ts
index 8a4a5198afdf..96187a311f80 100644
--- a/modules/@angular/benchpress/src/reporter/console_reporter.ts
+++ b/modules/@angular/benchpress/src/reporter/console_reporter.ts
@@ -7,10 +7,7 @@
*/
import {Inject, Injectable, OpaqueToken} from '@angular/core';
-
-import {ListWrapper, StringMapWrapper} from '../facade/collection';
-import {NumberWrapper, isBlank, isPresent, print} from '../facade/lang';
-import {Math} from '../facade/math';
+import {print} from '../facade/lang';
import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter';
import {SampleDescription} from '../sample_description';
diff --git a/modules/@angular/benchpress/src/reporter/json_file_reporter.ts b/modules/@angular/benchpress/src/reporter/json_file_reporter.ts
index 814aac37bc17..67c28a592b92 100644
--- a/modules/@angular/benchpress/src/reporter/json_file_reporter.ts
+++ b/modules/@angular/benchpress/src/reporter/json_file_reporter.ts
@@ -9,7 +9,7 @@
import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Options} from '../common_options';
-import {DateWrapper, Json, isBlank, isPresent} from '../facade/lang';
+import {Json} from '../facade/lang';
import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter';
import {SampleDescription} from '../sample_description';
@@ -45,8 +45,7 @@ export class JsonFileReporter extends Reporter {
'completeSample': completeSample,
'validSample': validSample,
});
- var filePath =
- `${this._path}/${this._description.id}_${DateWrapper.toMillis(this._now())}.json`;
+ var filePath = `${this._path}/${this._description.id}_${this._now().getTime()}.json`;
return this._writeFile(filePath, content);
}
}
diff --git a/modules/@angular/benchpress/src/reporter/util.ts b/modules/@angular/benchpress/src/reporter/util.ts
index afe417c5ba57..d04371cc1ca6 100644
--- a/modules/@angular/benchpress/src/reporter/util.ts
+++ b/modules/@angular/benchpress/src/reporter/util.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {StringMapWrapper} from '../facade/collection';
+
import {NumberWrapper} from '../facade/lang';
import {MeasureValues} from '../measure_values';
import {Statistic} from '../statistic';
@@ -17,7 +17,7 @@ export function formatNum(n: number) {
export function sortedProps(obj: {[key: string]: any}) {
var props: string[] = [];
- StringMapWrapper.forEach(obj, (value, prop) => props.push(prop));
+ props.push(...Object.keys(obj));
props.sort();
return props;
}
@@ -30,4 +30,4 @@ export function formatStats(validSamples: MeasureValues[], metricName: string):
// Note: Don't use the unicode character for +- as it might cause
// hickups for consoles...
return NumberWrapper.isNaN(cv) ? formattedMean : `${formattedMean}+-${Math.floor(cv)}%`;
-}
\ No newline at end of file
+}
diff --git a/modules/@angular/benchpress/src/runner.ts b/modules/@angular/benchpress/src/runner.ts
index 5ad1674c9942..f684cb12a5ed 100644
--- a/modules/@angular/benchpress/src/runner.ts
+++ b/modules/@angular/benchpress/src/runner.ts
@@ -9,7 +9,7 @@
import {Provider, ReflectiveInjector} from '@angular/core';
import {Options} from './common_options';
-import {isBlank, isPresent} from './facade/lang';
+import {isPresent} from './facade/lang';
import {Metric} from './metric';
import {MultiMetric} from './metric/multi_metric';
import {PerflogMetric} from './metric/perflog_metric';
diff --git a/modules/@angular/benchpress/src/sample_description.ts b/modules/@angular/benchpress/src/sample_description.ts
index 3cf5a99a3f41..a82e5e1b5eaa 100644
--- a/modules/@angular/benchpress/src/sample_description.ts
+++ b/modules/@angular/benchpress/src/sample_description.ts
@@ -9,7 +9,6 @@
import {OpaqueToken} from '@angular/core';
import {Options} from './common_options';
-import {StringMapWrapper} from './facade/collection';
import {Metric} from './metric';
import {Validator} from './validator';
@@ -42,7 +41,7 @@ export class SampleDescription {
public metrics: {[key: string]: any}) {
this.description = {};
descriptions.forEach(description => {
- StringMapWrapper.forEach(description, (value, prop) => this.description[prop] = value);
+ Object.keys(description).forEach(prop => { this.description[prop] = description[prop]; });
});
}
diff --git a/modules/@angular/benchpress/src/sampler.ts b/modules/@angular/benchpress/src/sampler.ts
index 6576f0f7a1bd..f080827e6893 100644
--- a/modules/@angular/benchpress/src/sampler.ts
+++ b/modules/@angular/benchpress/src/sampler.ts
@@ -6,10 +6,10 @@
* 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 {Date, DateWrapper, isBlank, isPresent} from './facade/lang';
+import {isPresent} from './facade/lang';
import {MeasureValues} from './measure_values';
import {Metric} from './metric';
import {Reporter} from './reporter';
diff --git a/modules/@angular/benchpress/src/web_driver_extension.ts b/modules/@angular/benchpress/src/web_driver_extension.ts
index afd680f37223..83e605c7f749 100644
--- a/modules/@angular/benchpress/src/web_driver_extension.ts
+++ b/modules/@angular/benchpress/src/web_driver_extension.ts
@@ -9,7 +9,6 @@
import {Injector, OpaqueToken} from '@angular/core';
import {Options} from './common_options';
-import {isBlank, isPresent} from './facade/lang';
export type PerfLogEvent = {
[key: string]: any
@@ -50,7 +49,7 @@ export abstract class WebDriverExtension {
delegate = extension;
}
});
- if (isBlank(delegate)) {
+ if (!delegate) {
throw new Error('Could not find a delegate for given capabilities!');
}
return delegate;
diff --git a/modules/@angular/benchpress/src/webdriver/chrome_driver_extension.ts b/modules/@angular/benchpress/src/webdriver/chrome_driver_extension.ts
index 384ae4a0fdac..e89d4264e335 100644
--- a/modules/@angular/benchpress/src/webdriver/chrome_driver_extension.ts
+++ b/modules/@angular/benchpress/src/webdriver/chrome_driver_extension.ts
@@ -169,7 +169,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
eventCategories: string[], eventName: string, expectedCategories: string[],
expectedName: string = null): boolean {
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;
}
diff --git a/modules/@angular/benchpress/src/webdriver/ios_driver_extension.ts b/modules/@angular/benchpress/src/webdriver/ios_driver_extension.ts
index 0259485bcb0b..00bc1d98084a 100644
--- a/modules/@angular/benchpress/src/webdriver/ios_driver_extension.ts
+++ b/modules/@angular/benchpress/src/webdriver/ios_driver_extension.ts
@@ -52,7 +52,7 @@ export class IOsDriverExtension extends WebDriverExtension {
/** @internal */
private _convertPerfRecordsToEvents(records: any[], events: PerfLogEvent[] = null) {
- if (isBlank(events)) {
+ if (!events) {
events = [];
}
records.forEach((record) => {
diff --git a/modules/@angular/benchpress/test/metric/multi_metric_spec.ts b/modules/@angular/benchpress/test/metric/multi_metric_spec.ts
index 95c05220d76f..9ee463253fc5 100644
--- a/modules/@angular/benchpress/test/metric/multi_metric_spec.ts
+++ b/modules/@angular/benchpress/test/metric/multi_metric_spec.ts
@@ -6,14 +6,14 @@
* 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';
export function main() {
function createMetric(ids: any[]) {
var m = ReflectiveInjector
.resolveAndCreate([
- ids.map(id => { return {provide: id, useValue: new MockMetric(id)}; }),
+ ids.map(id => ({provide: id, useValue: new MockMetric(id)})),
MultiMetric.provideWith(ids)
])
.get(MultiMetric);
diff --git a/modules/@angular/benchpress/test/metric/perflog_metric_spec.ts b/modules/@angular/benchpress/test/metric/perflog_metric_spec.ts
index d844fdc066e9..bf933e1ad880 100644
--- a/modules/@angular/benchpress/test/metric/perflog_metric_spec.ts
+++ b/modules/@angular/benchpress/test/metric/perflog_metric_spec.ts
@@ -7,11 +7,10 @@
*/
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 {StringMapWrapper} from '../../src/facade/collection';
-import {isBlank, isPresent} from '../../src/facade/lang';
+import {isPresent} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory';
export function main() {
@@ -28,12 +27,12 @@ export function main() {
requestCount?: boolean
} = {}): Metric {
commandLog = [];
- if (isBlank(perfLogFeatures)) {
+ if (!perfLogFeatures) {
perfLogFeatures =
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
}
- if (isBlank(microMetrics)) {
- microMetrics = StringMapWrapper.create();
+ if (!microMetrics) {
+ microMetrics = {};
}
var providers: Provider[] = [
Options.DEFAULT_PROVIDERS, PerflogMetric.PROVIDERS,
@@ -68,7 +67,7 @@ export function main() {
function sortedKeys(stringMap: {[key: string]: any}) {
var res: string[] = [];
- StringMapWrapper.forEach(stringMap, (_, key) => { res.push(key); });
+ res.push(...Object.keys(stringMap));
res.sort();
return res;
}
diff --git a/modules/@angular/benchpress/test/metric/user_metric_spec.ts b/modules/@angular/benchpress/test/metric/user_metric_spec.ts
index 48b33db31f29..22ebb452763b 100644
--- a/modules/@angular/benchpress/test/metric/user_metric_spec.ts
+++ b/modules/@angular/benchpress/test/metric/user_metric_spec.ts
@@ -7,11 +7,9 @@
*/
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 {StringMapWrapper} from '../../src/facade/collection';
-import {Json, isBlank, isPresent} from '../../src/facade/lang';
+import {Options, PerfLogEvent, PerfLogFeatures, UserMetric, WebDriverAdapter} from '../../index';
export function main() {
var wdAdapter: MockDriverAdapter;
@@ -19,12 +17,12 @@ export function main() {
function createMetric(
perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
{userMetrics}: {userMetrics?: {[key: string]: string}} = {}): UserMetric {
- if (isBlank(perfLogFeatures)) {
+ if (!perfLogFeatures) {
perfLogFeatures =
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
}
- if (isBlank(userMetrics)) {
- userMetrics = StringMapWrapper.create();
+ if (!userMetrics) {
+ userMetrics = {};
}
wdAdapter = new MockDriverAdapter();
var providers: Provider[] = [
diff --git a/modules/@angular/benchpress/test/reporter/console_reporter_spec.ts b/modules/@angular/benchpress/test/reporter/console_reporter_spec.ts
index f5bf67eac405..6420ba30c666 100644
--- a/modules/@angular/benchpress/test/reporter/console_reporter_spec.ts
+++ b/modules/@angular/benchpress/test/reporter/console_reporter_spec.ts
@@ -7,10 +7,10 @@
*/
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 {Date, DateWrapper, isBlank, isPresent} from '../../src/facade/lang';
+import {ConsoleReporter, MeasureValues, ReflectiveInjector, SampleDescription} from '../../index';
+import {isBlank, isPresent} from '../../src/facade/lang';
export function main() {
describe('console reporter', () => {
@@ -25,7 +25,7 @@ export function main() {
metrics?: {[key: string]: any}
}) {
log = [];
- if (isBlank(descriptions)) {
+ if (!descriptions) {
descriptions = [];
}
if (isBlank(sampleId)) {
@@ -90,5 +90,5 @@ export function main() {
}
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);
}
diff --git a/modules/@angular/benchpress/test/reporter/json_file_reporter_spec.ts b/modules/@angular/benchpress/test/reporter/json_file_reporter_spec.ts
index ba3f181d7534..3036f6c33e9a 100644
--- a/modules/@angular/benchpress/test/reporter/json_file_reporter_spec.ts
+++ b/modules/@angular/benchpress/test/reporter/json_file_reporter_spec.ts
@@ -6,10 +6,10 @@
* 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 {DateWrapper, Json, isPresent} from '../../src/facade/lang';
+import {Json, isPresent} from '../../src/facade/lang';
export function main() {
describe('file reporter', () => {
@@ -27,7 +27,7 @@ export function main() {
useValue: new SampleDescription(sampleId, descriptions, metrics)
},
{provide: JsonFileReporter.PATH, useValue: path},
- {provide: Options.NOW, useValue: () => DateWrapper.fromMillis(1234)}, {
+ {provide: Options.NOW, useValue: () => new Date(1234)}, {
provide: Options.WRITE_FILE,
useValue: (filename: string, content: string) => {
loggedFile = {'filename': filename, 'content': content};
@@ -77,5 +77,5 @@ export function main() {
}
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);
}
diff --git a/modules/@angular/benchpress/test/reporter/multi_reporter_spec.ts b/modules/@angular/benchpress/test/reporter/multi_reporter_spec.ts
index 9d4c1b9ac12d..f52588d808ec 100644
--- a/modules/@angular/benchpress/test/reporter/multi_reporter_spec.ts
+++ b/modules/@angular/benchpress/test/reporter/multi_reporter_spec.ts
@@ -6,16 +6,15 @@
* 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 {DateWrapper} from '../../src/facade/lang';
export function main() {
function createReporters(ids: any[]) {
var r = ReflectiveInjector
.resolveAndCreate([
- ids.map(id => { return {provide: id, useValue: new MockReporter(id)}; }),
+ ids.map(id => ({provide: id, useValue: new MockReporter(id)})),
MultiReporter.provideWith(ids)
])
.get(MultiReporter);
@@ -26,7 +25,7 @@ export function main() {
it('should reportMeasureValues to all',
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) => {
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) => {
- var completeSample = [
- new MeasureValues(0, DateWrapper.now(), {}), new MeasureValues(1, DateWrapper.now(), {})
- ];
+ var completeSample =
+ [new MeasureValues(0, new Date(), {}), new MeasureValues(1, new Date(), {})];
var validSample = [completeSample[1]];
createReporters(['m1', 'm2'])
diff --git a/modules/@angular/benchpress/test/runner_spec.ts b/modules/@angular/benchpress/test/runner_spec.ts
index f63a8a569402..d5399a247e9a 100644
--- a/modules/@angular/benchpress/test/runner_spec.ts
+++ b/modules/@angular/benchpress/test/runner_spec.ts
@@ -6,10 +6,9 @@
* 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 {isBlank} from '../src/facade/lang';
export function main() {
describe('runner', () => {
@@ -17,7 +16,7 @@ export function main() {
var runner: Runner;
function createRunner(defaultProviders: any[] = null): Runner {
- if (isBlank(defaultProviders)) {
+ if (!defaultProviders) {
defaultProviders = [];
}
runner = new Runner([
diff --git a/modules/@angular/benchpress/test/sampler_spec.ts b/modules/@angular/benchpress/test/sampler_spec.ts
index 5df862a3bae1..2f6bc0ad1273 100644
--- a/modules/@angular/benchpress/test/sampler_spec.ts
+++ b/modules/@angular/benchpress/test/sampler_spec.ts
@@ -6,10 +6,10 @@
* 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 {Date, DateWrapper, isBlank, isPresent, stringify} from '../src/facade/lang';
+import {isBlank, isPresent} from '../src/facade/lang';
export function main() {
var EMPTY_EXECUTE = () => {};
@@ -26,10 +26,10 @@ export function main() {
execute?: any
} = {}) {
var time = 1000;
- if (isBlank(metric)) {
+ if (!metric) {
metric = new MockMetric([]);
}
- if (isBlank(reporter)) {
+ if (!reporter) {
reporter = new MockReporter([]);
}
if (isBlank(driver)) {
@@ -39,7 +39,7 @@ export function main() {
Options.DEFAULT_PROVIDERS, Sampler.PROVIDERS, {provide: Metric, useValue: metric},
{provide: Reporter, useValue: reporter}, {provide: WebDriverAdapter, useValue: driver},
{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)) {
providers.push({provide: Options.PREPARE, useValue: prepare});
@@ -60,8 +60,8 @@ export function main() {
createSampler({
driver: driver,
validator: createCountingValidator(2),
- prepare: () => { return count++; },
- execute: () => { return count++; }
+ prepare: () => count++,
+ execute: () => count++,
});
sampler.sample().then((_) => {
expect(count).toBe(4);
@@ -204,7 +204,7 @@ export function main() {
}
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(
@@ -221,7 +221,7 @@ function createCountingValidator(
function createCountingMetric(log: any[] = []) {
var scriptTime = 0;
- return new MockMetric(log, () => { return {'script': scriptTime++}; });
+ return new MockMetric(log, () => ({'script': scriptTime++}));
}
class MockDriverAdapter extends WebDriverAdapter {
diff --git a/modules/@angular/benchpress/test/statistic_spec.ts b/modules/@angular/benchpress/test/statistic_spec.ts
index 075023d5033f..23124061a099 100644
--- a/modules/@angular/benchpress/test/statistic_spec.ts
+++ b/modules/@angular/benchpress/test/statistic_spec.ts
@@ -6,7 +6,7 @@
* 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';
export function main() {
diff --git a/modules/@angular/benchpress/test/validator/regression_slope_validator_spec.ts b/modules/@angular/benchpress/test/validator/regression_slope_validator_spec.ts
index c77459787064..9b7be2606334 100644
--- a/modules/@angular/benchpress/test/validator/regression_slope_validator_spec.ts
+++ b/modules/@angular/benchpress/test/validator/regression_slope_validator_spec.ts
@@ -6,11 +6,10 @@
* 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 {ListWrapper} from '../../src/facade/collection';
-import {Date, DateWrapper} from '../../src/facade/lang';
export function main() {
describe('regression slope validator', () => {
@@ -62,5 +61,5 @@ export function main() {
}
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);
}
diff --git a/modules/@angular/benchpress/test/validator/size_validator_spec.ts b/modules/@angular/benchpress/test/validator/size_validator_spec.ts
index e9d0e4e144ff..6cdb21eff80a 100644
--- a/modules/@angular/benchpress/test/validator/size_validator_spec.ts
+++ b/modules/@angular/benchpress/test/validator/size_validator_spec.ts
@@ -6,11 +6,10 @@
* 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 {Date, DateWrapper} from '../../src/facade/lang';
export function main() {
describe('size validator', () => {
@@ -47,5 +46,5 @@ export function main() {
}
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);
}
diff --git a/modules/@angular/benchpress/test/web_driver_extension_spec.ts b/modules/@angular/benchpress/test/web_driver_extension_spec.ts
index 5eaa2865d5b5..eb968cfa5e34 100644
--- a/modules/@angular/benchpress/test/web_driver_extension_spec.ts
+++ b/modules/@angular/benchpress/test/web_driver_extension_spec.ts
@@ -6,7 +6,7 @@
* 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 {StringWrapper, isPresent} from '../src/facade/lang';
@@ -17,7 +17,7 @@ export function main() {
try {
res(ReflectiveInjector
.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},
WebDriverExtension.provideFirstSupported(ids)
])
diff --git a/modules/@angular/benchpress/test/webdriver/chrome_driver_extension_spec.ts b/modules/@angular/benchpress/test/webdriver/chrome_driver_extension_spec.ts
index ac7f054b8615..5c1376f08ec1 100644
--- a/modules/@angular/benchpress/test/webdriver/chrome_driver_extension_spec.ts
+++ b/modules/@angular/benchpress/test/webdriver/chrome_driver_extension_spec.ts
@@ -6,7 +6,7 @@
* 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 {Json, isBlank} from '../../src/facade/lang';
@@ -35,7 +35,7 @@ export function main() {
function createExtension(
perfRecords: any[] = null, userAgent: string = null,
messageMethod = 'Tracing.dataCollected'): WebDriverExtension {
- if (isBlank(perfRecords)) {
+ if (!perfRecords) {
perfRecords = [];
}
if (isBlank(userAgent)) {
@@ -396,11 +396,11 @@ class MockDriverAdapter extends WebDriverAdapter {
logs(type: string) {
this._log.push(['logs', type]);
if (type === 'performance') {
- return Promise.resolve(this._events.map((event) => {
- return {
- 'message': Json.stringify({'message': {'method': this._messageMethod, 'params': event}})
- };
- }));
+ return Promise.resolve(this._events.map(
+ (event) => ({
+ 'message':
+ Json.stringify({'message': {'method': this._messageMethod, 'params': event}})
+ })));
} else {
return null;
}
diff --git a/modules/@angular/benchpress/test/webdriver/ios_driver_extension_spec.ts b/modules/@angular/benchpress/test/webdriver/ios_driver_extension_spec.ts
index b749e939a59a..5ed46b5fd559 100644
--- a/modules/@angular/benchpress/test/webdriver/ios_driver_extension_spec.ts
+++ b/modules/@angular/benchpress/test/webdriver/ios_driver_extension_spec.ts
@@ -6,10 +6,10 @@
* 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 {Json, isBlank, isPresent} from '../../src/facade/lang';
+import {Json} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory';
export function main() {
@@ -20,7 +20,7 @@ export function main() {
var normEvents = new TraceEventFactory('timeline', 'pid0');
function createExtension(perfRecords: any[] = null): WebDriverExtension {
- if (isBlank(perfRecords)) {
+ if (!perfRecords) {
perfRecords = [];
}
log = [];
@@ -156,7 +156,7 @@ function timeEndRecord(name: string, time: number) {
}
function durationRecord(type: string, startTime: number, endTime: number, children: any[] = null) {
- if (isBlank(children)) {
+ if (!children) {
children = [];
}
return {'type': type, 'startTime': startTime, 'endTime': endTime, 'children': children};
diff --git a/modules/@angular/common/rollup-testing.config.js b/modules/@angular/common/rollup-testing.config.js
index 3a0e5d02362f..8c0e1d761806 100644
--- a/modules/@angular/common/rollup-testing.config.js
+++ b/modules/@angular/common/rollup-testing.config.js
@@ -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 {
entry: '../../../dist/packages-dist/common/testing/index.js',
@@ -10,4 +17,4 @@ export default {
'rxjs/Observable': 'Rx',
'rxjs/Subject': 'Rx'
}
-}
+};
diff --git a/modules/@angular/common/rollup.config.js b/modules/@angular/common/rollup.config.js
index 0ff5c1a5df9a..1e6b494fc8e4 100644
--- a/modules/@angular/common/rollup.config.js
+++ b/modules/@angular/common/rollup.config.js
@@ -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 {
entry: '../../../dist/packages-dist/common/index.js',
@@ -7,6 +14,6 @@ export default {
globals: {
'@angular/core': 'ng.core',
'rxjs/Observable': 'Rx',
- 'rxjs/Subject': 'Rx'
+ 'rxjs/Subject': 'Rx',
}
-}
+};
diff --git a/modules/@angular/common/src/directives/ng_plural.ts b/modules/@angular/common/src/directives/ng_plural.ts
index a34919570f64..0f4aa616e30b 100644
--- a/modules/@angular/common/src/directives/ng_plural.ts
+++ b/modules/@angular/common/src/directives/ng_plural.ts
@@ -61,8 +61,7 @@ export class NgPlural {
addCase(value: string, switchView: SwitchView): void { this._caseViews[value] = switchView; }
- /** @internal */
- _updateView(): void {
+ private _updateView(): void {
this._clearViews();
const cases = Object.keys(this._caseViews);
@@ -70,13 +69,11 @@ export class NgPlural {
this._activateView(this._caseViews[key]);
}
- /** @internal */
- _clearViews() {
+ private _clearViews() {
if (this._activeView) this._activeView.destroy();
}
- /** @internal */
- _activateView(view: SwitchView) {
+ private _activateView(view: SwitchView) {
if (view) {
this._activeView = view;
this._activeView.create();
diff --git a/modules/@angular/common/src/directives/ng_style.ts b/modules/@angular/common/src/directives/ng_style.ts
index dcedef2f4f59..26a57948086f 100644
--- a/modules/@angular/common/src/directives/ng_style.ts
+++ b/modules/@angular/common/src/directives/ng_style.ts
@@ -32,10 +32,8 @@ import {Directive, DoCheck, ElementRef, Input, KeyValueChangeRecord, KeyValueDif
*/
@Directive({selector: '[ngStyle]'})
export class NgStyle implements DoCheck {
- /** @internal */
- _ngStyle: {[key: string]: string};
- /** @internal */
- _differ: KeyValueDiffer;
+ private _ngStyle: {[key: string]: string};
+ private _differ: KeyValueDiffer;
constructor(
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 {
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);
}
diff --git a/modules/@angular/common/src/directives/ng_switch.ts b/modules/@angular/common/src/directives/ng_switch.ts
index 05a4d8bdee94..32b3254d05a1 100644
--- a/modules/@angular/common/src/directives/ng_switch.ts
+++ b/modules/@angular/common/src/directives/ng_switch.ts
@@ -111,8 +111,7 @@ export class NgSwitch {
}
}
- /** @internal */
- _emptyAllActiveViews(): void {
+ private _emptyAllActiveViews(): void {
const activeContainers = this._activeViews;
for (var i = 0; i < activeContainers.length; i++) {
activeContainers[i].destroy();
@@ -120,9 +119,7 @@ export class NgSwitch {
this._activeViews = [];
}
- /** @internal */
- _activateViews(views: SwitchView[]): void {
- // TODO(vicb): assert(this._activeViews.length === 0);
+ private _activateViews(views: SwitchView[]): void {
if (views) {
for (var i = 0; i < views.length; i++) {
views[i].create();
@@ -141,8 +138,7 @@ export class NgSwitch {
views.push(view);
}
- /** @internal */
- _deregisterView(value: any, view: SwitchView): void {
+ private _deregisterView(value: any, view: SwitchView): void {
// `_CASE_DEFAULT` is used a marker for non-registered cases
if (value === _CASE_DEFAULT) return;
const views = this._valueViews.get(value);
@@ -181,10 +177,8 @@ export class NgSwitch {
@Directive({selector: '[ngSwitchCase]'})
export class NgSwitchCase {
// `_CASE_DEFAULT` is used as a marker for a not yet initialized value
- /** @internal */
- _value: any = _CASE_DEFAULT;
- /** @internal */
- _view: SwitchView;
+ private _value: any = _CASE_DEFAULT;
+ private _view: SwitchView;
private _switch: NgSwitch;
constructor(
diff --git a/modules/@angular/common/src/localization.ts b/modules/@angular/common/src/localization.ts
index a84e73442a6b..a6c64c6fa2ef 100644
--- a/modules/@angular/common/src/localization.ts
+++ b/modules/@angular/common/src/localization.ts
@@ -67,7 +67,7 @@ export enum Plural {
Two,
Few,
Many,
- Other
+ Other,
}
/**
diff --git a/modules/@angular/common/src/location/location.ts b/modules/@angular/common/src/location/location.ts
index 8ff9dc494c2f..dab13b008745 100644
--- a/modules/@angular/common/src/location/location.ts
+++ b/modules/@angular/common/src/location/location.ts
@@ -49,16 +49,20 @@ export class Location {
_subject: EventEmitter = new EventEmitter();
/** @internal */
_baseHref: string;
-
/** @internal */
_platformStrategy: LocationStrategy;
constructor(platformStrategy: LocationStrategy) {
this._platformStrategy = platformStrategy;
- var browserBaseHref = this._platformStrategy.getBaseHref();
+ const browserBaseHref = this._platformStrategy.getBaseHref();
this._baseHref = Location.stripTrailingSlash(_stripIndexHtml(browserBaseHref));
- this._platformStrategy.onPopState(
- (ev) => { this._subject.emit({'url': this.path(true), 'pop': true, 'type': ev.type}); });
+ this._platformStrategy.onPopState((ev) => {
+ this._subject.emit({
+ 'url': this.path(true),
+ 'pop': true,
+ 'type': ev.type,
+ });
+ });
}
/**
diff --git a/modules/@angular/common/test/directives/ng_class_spec.ts b/modules/@angular/common/test/directives/ng_class_spec.ts
index 5c962840c0a6..15369390554a 100644
--- a/modules/@angular/common/test/directives/ng_class_spec.ts
+++ b/modules/@angular/common/test/directives/ng_class_spec.ts
@@ -8,7 +8,7 @@
import {Component} from '@angular/core';
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() {
describe('binding to CSS class list', () => {
diff --git a/modules/@angular/common/test/localization_spec.ts b/modules/@angular/common/test/localization_spec.ts
index afec2c0dcbba..28d82716fd31 100644
--- a/modules/@angular/common/test/localization_spec.ts
+++ b/modules/@angular/common/test/localization_spec.ts
@@ -8,7 +8,7 @@
import {LOCALE_ID} from '@angular/core';
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 {NgLocaleLocalization, NgLocalization, getPluralCategory} from '../src/localization';
diff --git a/modules/@angular/common/test/pipes/async_pipe_spec.ts b/modules/@angular/common/test/pipes/async_pipe_spec.ts
index a0240a89e1b1..4f4f0309f692 100644
--- a/modules/@angular/common/test/pipes/async_pipe_spec.ts
+++ b/modules/@angular/common/test/pipes/async_pipe_spec.ts
@@ -8,12 +8,11 @@
import {AsyncPipe} from '@angular/common';
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 {browserDetection} from '@angular/platform-browser/testing/browser_util';
import {EventEmitter} from '../../src/facade/async';
-import {isBlank} from '../../src/facade/lang';
import {SpyChangeDetectorRef} from '../spies';
export function main() {
@@ -112,7 +111,7 @@ export function main() {
var promise: Promise;
var ref: SpyChangeDetectorRef;
// adds longer timers for passing tests in IE
- var timer = (!isBlank(getDOM()) && browserDetection.isIE) ? 50 : 10;
+ var timer = (getDOM() && browserDetection.isIE) ? 50 : 10;
beforeEach(() => {
promise = new Promise((res, rej) => {
diff --git a/modules/@angular/common/test/pipes/date_pipe_spec.ts b/modules/@angular/common/test/pipes/date_pipe_spec.ts
index 25e58c8bebb9..2667f88e1f99 100644
--- a/modules/@angular/common/test/pipes/date_pipe_spec.ts
+++ b/modules/@angular/common/test/pipes/date_pipe_spec.ts
@@ -8,11 +8,9 @@
import {DatePipe} from '@angular/common';
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 {DateWrapper} from '../../src/facade/lang';
-
export function main() {
describe('DatePipe', () => {
var date: Date;
@@ -27,7 +25,7 @@ export function main() {
// Tracking issue: https://github.com/angular/angular/issues/11187
beforeEach(() => {
- date = DateWrapper.create(2015, 6, 15, 9, 3, 1);
+ date = new Date(2015, 5, 15, 9, 3, 1);
pipe = new DatePipe('en-US');
});
diff --git a/modules/@angular/common/test/pipes/i18n_plural_pipe_spec.ts b/modules/@angular/common/test/pipes/i18n_plural_pipe_spec.ts
index 5f0198bc132a..f042f777bfcd 100644
--- a/modules/@angular/common/test/pipes/i18n_plural_pipe_spec.ts
+++ b/modules/@angular/common/test/pipes/i18n_plural_pipe_spec.ts
@@ -8,7 +8,7 @@
import {I18nPluralPipe, NgLocalization} from '@angular/common';
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() {
describe('I18nPluralPipe', () => {
diff --git a/modules/@angular/common/test/pipes/i18n_select_pipe_spec.ts b/modules/@angular/common/test/pipes/i18n_select_pipe_spec.ts
index bd4874dedaf9..2cecbf1bfd56 100644
--- a/modules/@angular/common/test/pipes/i18n_select_pipe_spec.ts
+++ b/modules/@angular/common/test/pipes/i18n_select_pipe_spec.ts
@@ -8,7 +8,7 @@
import {I18nSelectPipe} from '@angular/common';
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() {
describe('I18nSelectPipe', () => {
diff --git a/modules/@angular/common/test/pipes/lowercase_pipe_spec.ts b/modules/@angular/common/test/pipes/lowercase_pipe_spec.ts
index 31d699007c5f..c508525e3f01 100644
--- a/modules/@angular/common/test/pipes/lowercase_pipe_spec.ts
+++ b/modules/@angular/common/test/pipes/lowercase_pipe_spec.ts
@@ -7,7 +7,7 @@
*/
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() {
describe('LowerCasePipe', () => {
diff --git a/modules/@angular/common/test/pipes/number_pipe_spec.ts b/modules/@angular/common/test/pipes/number_pipe_spec.ts
index e19a9e8786f1..29c8e80206ca 100644
--- a/modules/@angular/common/test/pipes/number_pipe_spec.ts
+++ b/modules/@angular/common/test/pipes/number_pipe_spec.ts
@@ -7,7 +7,7 @@
*/
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';
export function main() {
diff --git a/modules/@angular/common/test/pipes/slice_pipe_spec.ts b/modules/@angular/common/test/pipes/slice_pipe_spec.ts
index 683f9bb5a603..c3cbdea10eb3 100644
--- a/modules/@angular/common/test/pipes/slice_pipe_spec.ts
+++ b/modules/@angular/common/test/pipes/slice_pipe_spec.ts
@@ -9,7 +9,6 @@
import {CommonModule, SlicePipe} from '@angular/common';
import {Component} from '@angular/core';
import {TestBed, async} from '@angular/core/testing';
-import {browserDetection} from '@angular/platform-browser/testing/browser_util';
import {expect} from '@angular/platform-browser/testing/matchers';
export function main() {
diff --git a/modules/@angular/common/test/pipes/uppercase_pipe_spec.ts b/modules/@angular/common/test/pipes/uppercase_pipe_spec.ts
index e8bb9a469446..c4e391c78d76 100644
--- a/modules/@angular/common/test/pipes/uppercase_pipe_spec.ts
+++ b/modules/@angular/common/test/pipes/uppercase_pipe_spec.ts
@@ -7,7 +7,7 @@
*/
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() {
describe('UpperCasePipe', () => {
diff --git a/modules/@angular/common/test/spies.ts b/modules/@angular/common/test/spies.ts
index 6c4d6bb722d3..6338e5252c98 100644
--- a/modules/@angular/common/test/spies.ts
+++ b/modules/@angular/common/test/spies.ts
@@ -7,7 +7,7 @@
*/
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 {
constructor() {
diff --git a/modules/@angular/common/testing/location_mock.ts b/modules/@angular/common/testing/location_mock.ts
index 7b448bf44269..5b4d0c95908b 100644
--- a/modules/@angular/common/testing/location_mock.ts
+++ b/modules/@angular/common/testing/location_mock.ts
@@ -18,9 +18,7 @@ import {EventEmitter, Injectable} from '@angular/core';
@Injectable()
export class SpyLocation implements Location {
urlChanges: string[] = [];
- /** @internal */
private _history: LocationState[] = [new LocationState('', '')];
- /** @internal */
private _historyIndex: number = 0;
/** @internal */
_subject: EventEmitter = new EventEmitter();
diff --git a/modules/@angular/compiler-cli/integrationtest/test/i18n_spec.ts b/modules/@angular/compiler-cli/integrationtest/test/i18n_spec.ts
index c4fdabd964cc..ace7ec35a584 100644
--- a/modules/@angular/compiler-cli/integrationtest/test/i18n_spec.ts
+++ b/modules/@angular/compiler-cli/integrationtest/test/i18n_spec.ts
@@ -36,25 +36,27 @@ const EXPECTED_XMB = `
translate me
Welcome
- `;
+
+`;
const EXPECTED_XLIFF = `
-
-
-
- translate me
-
- desc
- meaning
-
-
- Welcome
-
-
-
-
- `;
+
+
+
+ translate me
+
+ desc
+ meaning
+
+
+ Welcome
+
+
+
+
+
+`;
describe('template i18n extraction output', () => {
const outDir = '';
diff --git a/modules/@angular/compiler-cli/integrationtest/webpack.config.js b/modules/@angular/compiler-cli/integrationtest/webpack.config.js
index 5478a9431cc2..90d348e286bc 100644
--- a/modules/@angular/compiler-cli/integrationtest/webpack.config.js
+++ b/modules/@angular/compiler-cli/integrationtest/webpack.config.js
@@ -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 = {
target: 'node',
entry: './test/all_spec.js',
- output: {
- filename: './all_spec.js'
- },
- resolve: {
- extensions: ['.js']
- },
+ output: {filename: './all_spec.js'},
+ resolve: {extensions: ['.js']},
};
diff --git a/modules/@angular/compiler-cli/package.json b/modules/@angular/compiler-cli/package.json
index 85ed03595d0b..9cf0d04f6952 100644
--- a/modules/@angular/compiler-cli/package.json
+++ b/modules/@angular/compiler-cli/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@angular/tsc-wrapped": "^0.3.0",
"reflect-metadata": "^0.1.2",
- "parse5": "1.3.2",
+ "parse5": "^2.2.1",
"minimist": "^1.2.0"
},
"peerDependencies": {
diff --git a/modules/@angular/compiler-cli/src/codegen.ts b/modules/@angular/compiler-cli/src/codegen.ts
index 91048668a019..354ee466c108 100644
--- a/modules/@angular/compiler-cli/src/codegen.ts
+++ b/modules/@angular/compiler-cli/src/codegen.ts
@@ -126,7 +126,7 @@ export class CodeGenerator {
static create(
options: AngularCompilerOptions, cliOptions: NgcCliOptions, program: ts.Program,
compilerHost: ts.CompilerHost, reflectorHostContext?: ReflectorHostContext,
- resourceLoader?: compiler.ResourceLoader): CodeGenerator {
+ resourceLoader?: compiler.ResourceLoader, reflectorHost?: ReflectorHost): CodeGenerator {
resourceLoader = resourceLoader || {
get: (s: string) => {
if (!compilerHost.fileExists(s)) {
@@ -148,10 +148,12 @@ export class CodeGenerator {
}
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
- const usePathMapping = !!options.rootDirs && options.rootDirs.length > 0;
- const reflectorHost = usePathMapping ?
- new PathMappedReflectorHost(program, compilerHost, options, reflectorHostContext) :
- new ReflectorHost(program, compilerHost, options, reflectorHostContext);
+ if (!reflectorHost) {
+ const usePathMapping = !!options.rootDirs && options.rootDirs.length > 0;
+ reflectorHost = usePathMapping ?
+ new PathMappedReflectorHost(program, compilerHost, options, reflectorHostContext) :
+ new ReflectorHost(program, compilerHost, options, reflectorHostContext);
+ }
const staticReflector = new StaticReflector(reflectorHost);
StaticAndDynamicReflectionCapabilities.install(staticReflector);
const htmlParser =
diff --git a/modules/@angular/compiler-cli/src/static_reflector.ts b/modules/@angular/compiler-cli/src/static_reflector.ts
index 4bd14ddd4013..eac7121917af 100644
--- a/modules/@angular/compiler-cli/src/static_reflector.ts
+++ b/modules/@angular/compiler-cli/src/static_reflector.ts
@@ -6,7 +6,7 @@
* 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';
diff --git a/modules/@angular/compiler-cli/test/reflector_host_spec.ts b/modules/@angular/compiler-cli/test/reflector_host_spec.ts
index c37284bff31f..a0dc2c3e8d08 100644
--- a/modules/@angular/compiler-cli/test/reflector_host_spec.ts
+++ b/modules/@angular/compiler-cli/test/reflector_host_spec.ts
@@ -6,7 +6,7 @@
* 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 {ReflectorHost} from '../src/reflector_host';
diff --git a/modules/@angular/compiler-cli/test/static_reflector_spec.ts b/modules/@angular/compiler-cli/test/static_reflector_spec.ts
index d44e8c212183..feb2d553eeb6 100644
--- a/modules/@angular/compiler-cli/test/static_reflector_spec.ts
+++ b/modules/@angular/compiler-cli/test/static_reflector_spec.ts
@@ -9,7 +9,6 @@
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 {ListWrapper} from '@angular/facade/src/collection';
-import {isBlank} from '@angular/facade/src/lang';
import {MetadataCollector} from '@angular/tsc-wrapped';
import * as ts from 'typescript';
@@ -454,7 +453,7 @@ class MockReflectorHost implements StaticReflectorHost {
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
var cacheKey = `${declarationFile}:${name}${members?'.'+members.join('.'):''}`;
var result = this.staticTypeCache.get(cacheKey);
- if (isBlank(result)) {
+ if (!result) {
result = new StaticSymbol(declarationFile, name, members);
this.staticTypeCache.set(cacheKey, result);
}
diff --git a/modules/@angular/compiler/rollup-testing.config.js b/modules/@angular/compiler/rollup-testing.config.js
index dbc0d14d4e9b..8772530d02f6 100644
--- a/modules/@angular/compiler/rollup-testing.config.js
+++ b/modules/@angular/compiler/rollup-testing.config.js
@@ -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 {
entry: '../../../dist/packages-dist/compiler/testing/index.js',
@@ -11,4 +18,4 @@ export default {
'rxjs/Observable': 'Rx',
'rxjs/Subject': 'Rx'
}
-}
+};
diff --git a/modules/@angular/compiler/rollup.config.js b/modules/@angular/compiler/rollup.config.js
index 3f6d4454907a..4aa577765164 100644
--- a/modules/@angular/compiler/rollup.config.js
+++ b/modules/@angular/compiler/rollup.config.js
@@ -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 {
entry: '../../../dist/packages-dist/compiler/index.js',
@@ -7,9 +14,9 @@ export default {
globals: {
'@angular/core': 'ng.core',
'rxjs/Observable': 'Rx',
- 'rxjs/Subject': 'Rx'
+ 'rxjs/Subject': 'Rx',
},
plugins: [
-// nodeResolve({ jsnext: true, main: true }),
+ // nodeResolve({ jsnext: true, main: true }),
]
-}
+};
diff --git a/modules/@angular/compiler/src/animation/animation_compiler.ts b/modules/@angular/compiler/src/animation/animation_compiler.ts
index f80ac3cc3e41..edb53987011b 100644
--- a/modules/@angular/compiler/src/animation/animation_compiler.ts
+++ b/modules/@angular/compiler/src/animation/animation_compiler.ts
@@ -6,75 +6,26 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {CompileDirectiveMetadata} from '../compile_metadata';
-import {StringMapWrapper} from '../facade/collection';
-import {isBlank, isPresent} from '../facade/lang';
+
+import {isPresent} from '../facade/lang';
import {Identifiers, resolveIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
-import {ANY_STATE, AnimationOutput, 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 {AnimationParseError, ParsedAnimationResult, parseAnimationEntry, parseAnimationOutputName} from './animation_parser';
-
-const animationCompilationCache =
- new Map();
+import {ANY_STATE, DEFAULT_STATE, EMPTY_STATE} from '../private_import_core';
-export class CompiledAnimationTriggerResult {
- constructor(
- public name: string, public statesMapStatement: o.Statement,
- public statesVariableName: string, public fnStatement: o.Statement,
- public fnVariable: o.Expression) {}
-}
+import {AnimationAst, AnimationAstVisitor, AnimationEntryAst, AnimationGroupAst, AnimationKeyframeAst, AnimationSequenceAst, AnimationStateDeclarationAst, AnimationStateTransitionAst, AnimationStepAst, AnimationStylesAst} from './animation_ast';
-export class CompiledComponentAnimationResult {
- constructor(
- public outputs: AnimationOutput[], public triggers: CompiledAnimationTriggerResult[]) {}
+export class AnimationEntryCompileResult {
+ constructor(public name: string, public statements: o.Statement[], public fnExp: o.Expression) {}
}
export class AnimationCompiler {
- compileComponent(component: CompileDirectiveMetadata, template: t.TemplateAst[]):
- CompiledComponentAnimationResult {
- var compiledAnimations: CompiledAnimationTriggerResult[] = [];
- var groupedErrors: string[] = [];
- var triggerLookup: {[key: string]: CompiledAnimationTriggerResult} = {};
- var componentName = component.type.name;
-
- 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;
- }
+ compile(factoryNamePrefix: string, parsedAnimations: AnimationEntryAst[]):
+ AnimationEntryCompileResult[] {
+ return parsedAnimations.map(entry => {
+ const factoryName = `${factoryNamePrefix}_${entry.name}`;
+ const visitor = new _AnimationBuilder(entry.name, factoryName);
+ return visitor.build(entry);
});
-
- 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 => {
- stylesArr.push(
- o.literalMap(StringMapWrapper.keys(entry).map(key => [key, o.literal(entry[key])])));
+ stylesArr.push(o.literalMap(Object.keys(entry).map(key => [key, o.literal(entry[key])])));
});
return o.importExpr(resolveIdentifier(Identifiers.AnimationStyles)).instantiate([
@@ -182,9 +132,8 @@ class _AnimationBuilder implements AnimationAstVisitor {
visitAnimationStateDeclaration(
ast: AnimationStateDeclarationAst, context: _AnimationBuilderContext): void {
var flatStyles: {[key: string]: string | number} = {};
- _getStylesArray(ast).forEach(entry => {
- StringMapWrapper.forEach(entry, (value: string, key: string) => { flatStyles[key] = value; });
- });
+ _getStylesArray(ast).forEach(
+ entry => { Object.keys(entry).forEach(key => { flatStyles[key] = entry[key]; }); });
context.stateMap.registerState(ast.stateName, flatStyles);
}
@@ -334,28 +283,27 @@ class _AnimationBuilder implements AnimationAstVisitor {
statements);
}
- build(ast: AnimationAst): CompiledAnimationTriggerResult {
+ build(ast: AnimationAst): AnimationEntryCompileResult {
var context = new _AnimationBuilderContext();
var fnStatement = ast.visit(this, context).toDeclStmt(this._fnVarName);
var fnVariable = o.variable(this._fnVarName);
var lookupMap: any[] = [];
- StringMapWrapper.forEach(
- context.stateMap.states, (value: {[key: string]: string}, stateName: string) => {
- var variableValue = EMPTY_MAP;
- if (isPresent(value)) {
- let styleMap: any[] = [];
- StringMapWrapper.forEach(value, (value: string, key: string) => {
- styleMap.push([key, o.literal(value)]);
- });
- variableValue = o.literalMap(styleMap);
- }
- lookupMap.push([stateName, variableValue]);
- });
-
- var compiledStatesMapExpr = this._statesMapVar.set(o.literalMap(lookupMap)).toDeclStmt();
- return new CompiledAnimationTriggerResult(
- this.animationName, compiledStatesMapExpr, this._statesMapVarName, fnStatement, fnVariable);
+ Object.keys(context.stateMap.states).forEach(stateName => {
+ const value = context.stateMap.states[stateName];
+ var variableValue = EMPTY_MAP;
+ if (isPresent(value)) {
+ let styleMap: any[] = [];
+ Object.keys(value).forEach(key => { styleMap.push([key, o.literal(value[key])]); });
+ variableValue = o.literalMap(styleMap);
+ }
+ lookupMap.push([stateName, variableValue]);
+ });
+
+ const compiledStatesMapStmt = this._statesMapVar.set(o.literalMap(lookupMap)).toDeclStmt();
+ const statements: o.Statement[] = [compiledStatesMapStmt, fnStatement];
+
+ return new AnimationEntryCompileResult(this.animationName, statements, fnVariable);
}
}
@@ -371,7 +319,7 @@ class _AnimationBuilderStateMap {
get states() { return this._states; }
registerState(name: string, value: {[prop: string]: string | number} = null): void {
var existingEntry = this._states[name];
- if (isBlank(existingEntry)) {
+ if (!existingEntry) {
this._states[name] = value;
}
}
@@ -397,7 +345,7 @@ function _isEndStateAnimateStep(step: AnimationAst): boolean {
if (step instanceof AnimationStepAst && step.duration > 0 && step.keyframes.length == 2) {
var styles1 = _getStylesArray(step.keyframes[0])[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;
}
@@ -405,99 +353,3 @@ function _isEndStateAnimateStep(step: AnimationAst): boolean {
function _getStylesArray(obj: any): {[key: string]: any}[] {
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 {}
-}
diff --git a/modules/@angular/compiler/src/animation/animation_parser.ts b/modules/@angular/compiler/src/animation/animation_parser.ts
index 4870b2804d9d..d30456fcdbcb 100644
--- a/modules/@angular/compiler/src/animation/animation_parser.ts
+++ b/modules/@angular/compiler/src/animation/animation_parser.ts
@@ -6,13 +6,13 @@
* 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 {isArray, isBlank, isPresent, isString, isStringMap} from '../facade/lang';
import {Math} from '../facade/math';
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 {StylesCollection} from './styles_collection';
@@ -20,73 +20,85 @@ const _INITIAL_KEYFRAME = 0;
const _TERMINAL_KEYFRAME = 1;
const _ONE_SECOND = 1000;
+declare type Styles = {
+ [key: string]: string | number
+};
+
export class AnimationParseError extends ParseError {
- constructor(message: any /** TODO #9100 */) { super(null, message); }
+ constructor(message: string) { super(null, message); }
toString(): string { return `${this.msg}`; }
}
-export class ParsedAnimationResult {
+export class AnimationEntryParseResult {
constructor(public ast: AnimationEntryAst, public errors: AnimationParseError[]) {}
}
-export function parseAnimationEntry(entry: CompileAnimationEntryMetadata): ParsedAnimationResult {
- var errors: AnimationParseError[] = [];
- var stateStyles: {[key: string]: AnimationStylesAst} = {};
- var transitions: CompileAnimationStateTransitionMetadata[] = [];
-
- var stateDeclarationAsts: any[] /** TODO #9100 */ = [];
- entry.definitions.forEach(def => {
- if (def instanceof CompileAnimationStateDeclarationMetadata) {
- _parseAnimationDeclarationStates(def, errors).forEach(ast => {
- stateDeclarationAsts.push(ast);
- stateStyles[ast.stateName] = ast.styles;
- });
- } else {
- transitions.push(def);
+export class AnimationParser {
+ parseComponent(component: CompileDirectiveMetadata): AnimationEntryAst[] {
+ const errors: string[] = [];
+ const componentName = component.type.name;
+ const animationTriggerNames = new Set();
+ 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}`);
}
- });
- var stateTransitionAsts =
- transitions.map(transDef => _parseAnimationStateTransition(transDef, stateStyles, errors));
+ return asts;
+ }
- var ast = new AnimationEntryAst(entry.name, stateDeclarationAsts, stateTransitionAsts);
- return new ParsedAnimationResult(ast, errors);
-}
+ parseEntry(entry: CompileAnimationEntryMetadata): AnimationEntryParseResult {
+ var errors: AnimationParseError[] = [];
+ var stateStyles: {[key: string]: AnimationStylesAst} = {};
+ var transitions: CompileAnimationStateTransitionMetadata[] = [];
+
+ var stateDeclarationAsts: AnimationStateDeclarationAst[] = [];
+ entry.definitions.forEach(def => {
+ if (def instanceof CompileAnimationStateDeclarationMetadata) {
+ _parseAnimationDeclarationStates(def, errors).forEach(ast => {
+ stateDeclarationAsts.push(ast);
+ stateStyles[ast.stateName] = ast.styles;
+ });
+ } else {
+ transitions.push(def);
+ }
+ });
-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)`));
+ var stateTransitionAsts =
+ transitions.map(transDef => _parseAnimationStateTransition(transDef, stateStyles, errors));
+
+ var ast = new AnimationEntryAst(entry.name, stateDeclarationAsts, stateTransitionAsts);
+ return new AnimationEntryParseResult(ast, errors);
}
- return new AnimationOutput(name, phase, outputName);
}
function _parseAnimationDeclarationStates(
stateMetadata: CompileAnimationStateDeclarationMetadata,
errors: AnimationParseError[]): AnimationStateDeclarationAst[] {
- var styleValues: {[key: string]: string | number}[] = [];
+ var styleValues: Styles[] = [];
stateMetadata.styles.styles.forEach(stylesEntry => {
// TODO (matsko): change this when we get CSS class integration support
if (isStringMap(stylesEntry)) {
- styleValues.push(<{[key: string]: string | number}>stylesEntry);
+ styleValues.push(stylesEntry as Styles);
} else {
errors.push(new AnimationParseError(
`State based animations cannot contain references to other states`));
@@ -145,16 +157,6 @@ function _parseAnimationTransitionExpr(
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[]):
CompileAnimationMetadata {
return isArray(entry) ? new CompileAnimationSequenceMetadata(entry) :
@@ -210,7 +212,7 @@ function _normalizeStyleStepEntry(
}
var newSteps: CompileAnimationMetadata[] = [];
- var combinedStyles: {[key: string]: string | number}[];
+ var combinedStyles: Styles[];
steps.forEach(step => {
if (step instanceof CompileAnimationStyleMetadata) {
// this occurs when a style step is followed by a previous style step
@@ -266,7 +268,7 @@ function _normalizeStyleStepEntry(
function _resolveStylesFromState(
stateName: string, stateStyles: {[key: string]: AnimationStylesAst},
errors: AnimationParseError[]) {
- var styles: {[key: string]: string | number}[] = [];
+ var styles: Styles[] = [];
if (stateName[0] != ':') {
errors.push(new AnimationParseError(`Animation states via styles must be prefixed with a ":"`));
} else {
@@ -278,7 +280,7 @@ function _resolveStylesFromState(
} else {
value.styles.forEach(stylesEntry => {
if (isStringMap(stylesEntry)) {
- styles.push(<{[key: string]: string | number}>stylesEntry);
+ styles.push(stylesEntry as Styles);
}
});
}
@@ -312,15 +314,13 @@ function _parseAnimationKeyframes(
var lastOffset = 0;
keyframeSequence.steps.forEach(styleMetadata => {
var offset = styleMetadata.offset;
- var keyframeStyles: {[key: string]: string | number} = {};
+ var keyframeStyles: Styles = {};
styleMetadata.styles.forEach(entry => {
- StringMapWrapper.forEach(
- <{[key: string]: string | number}>entry,
- (value: any /** TODO #9100 */, prop: any /** TODO #9100 */) => {
- if (prop != 'offset') {
- keyframeStyles[prop] = value;
- }
- });
+ Object.keys(entry).forEach(prop => {
+ if (prop != 'offset') {
+ keyframeStyles[prop] = (entry as Styles)[prop];
+ }
+ });
});
if (isPresent(offset)) {
@@ -357,24 +357,22 @@ function _parseAnimationKeyframes(
let entry = rawKeyframes[i];
let styles = entry[1];
- StringMapWrapper.forEach(
- styles, (value: any /** TODO #9100 */, prop: any /** TODO #9100 */) => {
- if (!isPresent(firstKeyframeStyles[prop])) {
- firstKeyframeStyles[prop] = FILL_STYLE_FLAG;
- }
- });
+ Object.keys(styles).forEach(prop => {
+ if (!isPresent(firstKeyframeStyles[prop])) {
+ firstKeyframeStyles[prop] = FILL_STYLE_FLAG;
+ }
+ });
}
for (i = limit - 1; i >= 0; i--) {
let entry = rawKeyframes[i];
let styles = entry[1];
- StringMapWrapper.forEach(
- styles, (value: any /** TODO #9100 */, prop: any /** TODO #9100 */) => {
- if (!isPresent(lastKeyframeStyles[prop])) {
- lastKeyframeStyles[prop] = value;
- }
- });
+ Object.keys(styles).forEach(prop => {
+ if (!isPresent(lastKeyframeStyles[prop])) {
+ lastKeyframeStyles[prop] = styles[prop];
+ }
+ });
}
return rawKeyframes.map(
@@ -398,11 +396,9 @@ function _parseTransitionAnimation(
if (entry instanceof CompileAnimationStyleMetadata) {
entry.styles.forEach(stylesEntry => {
// by this point we know that we only have stringmap values
- var map = <{[key: string]: string | number}>stylesEntry;
- StringMapWrapper.forEach(
- map, (value: any /** TODO #9100 */, prop: any /** TODO #9100 */) => {
- collectedStyles.insertAtTime(prop, time, value);
- });
+ var map = stylesEntry as Styles;
+ Object.keys(map).forEach(
+ prop => { collectedStyles.insertAtTime(prop, time, map[prop]); });
});
previousStyles = entry.styles;
return;
@@ -448,7 +444,7 @@ function _parseTransitionAnimation(
} else {
let styleData = styles;
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);
keyframes = [keyframe];
}
@@ -460,9 +456,8 @@ function _parseTransitionAnimation(
keyframes.forEach(
(keyframe: any /** TODO #9100 */) => keyframe.styles.styles.forEach(
- (entry: any /** TODO #9100 */) => StringMapWrapper.forEach(
- entry, (value: any /** TODO #9100 */, prop: any /** TODO #9100 */) =>
- collectedStyles.insertAtTime(prop, currentTime, value))));
+ (entry: any /** TODO #9100 */) => Object.keys(entry).forEach(
+ prop => { collectedStyles.insertAtTime(prop, currentTime, entry[prop]); })));
} else {
// if the code reaches this stage then an error
// has already been populated within the _normalizeStyleSteps()
@@ -535,10 +530,11 @@ function _parseTimeExpression(
function _createStartKeyframeFromEndKeyframe(
endKeyframe: AnimationKeyframeAst, startTime: number, duration: number,
collectedStyles: StylesCollection, errors: AnimationParseError[]): AnimationKeyframeAst {
- var values: {[key: string]: string | number} = {};
+ var values: Styles = {};
var endTime = startTime + duration;
- endKeyframe.styles.styles.forEach((styleData: {[key: string]: string | number}) => {
- StringMapWrapper.forEach(styleData, (val: any /** TODO #9100 */, prop: any /** TODO #9100 */) => {
+ endKeyframe.styles.styles.forEach((styleData: Styles) => {
+ Object.keys(styleData).forEach(prop => {
+ const val = styleData[prop];
if (prop == 'offset') return;
var resultIndex = collectedStyles.indexOfAtOrBeforeTime(prop, startTime);
diff --git a/modules/@angular/compiler/src/compile_metadata.ts b/modules/@angular/compiler/src/compile_metadata.ts
index e7eddf4f4adf..a067044c6330 100644
--- a/modules/@angular/compiler/src/compile_metadata.ts
+++ b/modules/@angular/compiler/src/compile_metadata.ts
@@ -8,11 +8,10 @@
import {ChangeDetectionStrategy, SchemaMetadata, Type, ViewEncapsulation} from '@angular/core';
-import {ListWrapper, MapWrapper, StringMapWrapper} from './facade/collection';
-import {isBlank, isPresent, isStringMap, normalizeBlank, normalizeBool} from './facade/lang';
-import {LifecycleHooks, reflector} from './private_import_core';
+import {ListWrapper, MapWrapper} from './facade/collection';
+import {isPresent, isStringMap, normalizeBlank, normalizeBool} from './facade/lang';
+import {LifecycleHooks} from './private_import_core';
import {CssSelector} from './selector';
-import {getUrlScheme} from './url_resolver';
import {sanitizeIdentifier, splitAtColon} from './util';
function unimplemented(): any {
@@ -343,7 +342,8 @@ export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
var hostProperties: {[key: string]: string} = {};
var hostAttributes: {[key: string]: string} = {};
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);
if (matches === null) {
hostAttributes[key] = value;
diff --git a/modules/@angular/compiler/src/compiler.ts b/modules/@angular/compiler/src/compiler.ts
index f23e7f20f6aa..b0f2633695c2 100644
--- a/modules/@angular/compiler/src/compiler.ts
+++ b/modules/@angular/compiler/src/compiler.ts
@@ -6,7 +6,7 @@
* 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 {TEMPLATE_TRANSFORMS} from './template_parser/template_parser';
diff --git a/modules/@angular/compiler/src/css_parser/css_lexer.ts b/modules/@angular/compiler/src/css_parser/css_lexer.ts
index f616b85af87f..3966f203ed9d 100644
--- a/modules/@angular/compiler/src/css_parser/css_lexer.ts
+++ b/modules/@angular/compiler/src/css_parser/css_lexer.ts
@@ -9,7 +9,7 @@
import * as chars from '../chars';
import {BaseError} from '../facade/errors';
-import {StringWrapper, isPresent, resolveEnumToken} from '../facade/lang';
+import {StringWrapper, isPresent} from '../facade/lang';
export enum CssTokenType {
EOF,
@@ -223,8 +223,8 @@ export class CssScanner {
var error: CssScannerError = null;
if (!isMatchingType || (isPresent(value) && value != next.strValue)) {
- var errorMessage = resolveEnumToken(CssTokenType, next.type) + ' does not match expected ' +
- resolveEnumToken(CssTokenType, type) + ' value';
+ var errorMessage =
+ CssTokenType[next.type] + ' does not match expected ' + CssTokenType[type] + ' value';
if (isPresent(value)) {
errorMessage += ' ("' + next.strValue + '" should match "' + value + '")';
diff --git a/modules/@angular/compiler/src/directive_normalizer.ts b/modules/@angular/compiler/src/directive_normalizer.ts
index a8e067d89cc7..729b55f37288 100644
--- a/modules/@angular/compiler/src/directive_normalizer.ts
+++ b/modules/@angular/compiler/src/directive_normalizer.ts
@@ -115,27 +115,27 @@ export class DirectiveNormalizer {
const templateStyles = this.normalizeStylesheet(new CompileStylesheetMetadata(
{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;
if (isBlank(encapsulation)) {
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;
}
+
return new CompileTemplateMetadata({
encapsulation,
- template: template,
- templateUrl: templateAbsUrl,
- styles: allStyles,
- styleUrls: allStyleUrls,
+ template,
+ templateUrl: templateAbsUrl, styles, styleUrls,
externalStylesheets: templateMeta.externalStylesheets,
ngContentSelectors: visitor.ngContentSelectors,
animations: templateMeta.animations,
- interpolation: templateMeta.interpolation
+ interpolation: templateMeta.interpolation,
});
}
@@ -251,7 +251,6 @@ function _cloneDirectiveWithTemplate(
viewProviders: directive.viewProviders,
queries: directive.queries,
viewQueries: directive.viewQueries,
- entryComponents: directive.entryComponents,
- template: template
+ entryComponents: directive.entryComponents, template,
});
}
diff --git a/modules/@angular/compiler/src/directive_resolver.ts b/modules/@angular/compiler/src/directive_resolver.ts
index f01a86f3a43e..5b473c86a7ed 100644
--- a/modules/@angular/compiler/src/directive_resolver.ts
+++ b/modules/@angular/compiler/src/directive_resolver.ts
@@ -9,14 +9,10 @@
import {Component, Directive, HostBinding, HostListener, Injectable, Input, Output, Query, Type, resolveForwardRef} from '@angular/core';
import {StringMapWrapper} from './facade/collection';
-import {isPresent, stringify} from './facade/lang';
+import {stringify} from './facade/lang';
import {ReflectorReader, reflector} from './private_import_core';
import {splitAtColon} from './util';
-function _isDirectiveMetadata(type: any): type is Directive {
- return type instanceof Directive;
-}
-
/*
* Resolve a `Type` for {@link Directive}.
*
@@ -32,54 +28,57 @@ export class DirectiveResolver {
* Return {@link Directive} for a given `Type`.
*/
resolve(type: Type, throwIfNotFound = true): Directive {
- var typeMetadata = this._reflector.annotations(resolveForwardRef(type));
- if (isPresent(typeMetadata)) {
- var metadata = typeMetadata.find(_isDirectiveMetadata);
- if (isPresent(metadata)) {
- var propertyMetadata = this._reflector.propMetadata(type);
+ const typeMetadata = this._reflector.annotations(resolveForwardRef(type));
+ if (typeMetadata) {
+ const metadata = typeMetadata.find(isDirectiveMetadata);
+ if (metadata) {
+ const propertyMetadata = this._reflector.propMetadata(type);
return this._mergeWithPropertyMetadata(metadata, propertyMetadata, type);
}
}
+
if (throwIfNotFound) {
throw new Error(`No Directive annotation found on ${stringify(type)}`);
}
+
return null;
}
private _mergeWithPropertyMetadata(
dm: Directive, propertyMetadata: {[key: string]: any[]},
directiveType: Type): Directive {
- var inputs: string[] = [];
- var outputs: string[] = [];
- var host: {[key: string]: string} = {};
- var queries: {[key: string]: any} = {};
+ const inputs: string[] = [];
+ const outputs: string[] = [];
+ const host: {[key: string]: string} = {};
+ const queries: {[key: string]: any} = {};
+
+ Object.keys(propertyMetadata).forEach((propName: string) => {
- StringMapWrapper.forEach(propertyMetadata, (metadata: any[], propName: string) => {
- metadata.forEach(a => {
+ propertyMetadata[propName].forEach(a => {
if (a instanceof Input) {
- if (isPresent(a.bindingPropertyName)) {
+ if (a.bindingPropertyName) {
inputs.push(`${propName}: ${a.bindingPropertyName}`);
} else {
inputs.push(propName);
}
} else if (a instanceof Output) {
const output: Output = a;
- if (isPresent(output.bindingPropertyName)) {
+ if (output.bindingPropertyName) {
outputs.push(`${propName}: ${output.bindingPropertyName}`);
} else {
outputs.push(propName);
}
} else if (a instanceof HostBinding) {
const hostBinding: HostBinding = a;
- if (isPresent(hostBinding.hostPropertyName)) {
+ if (hostBinding.hostPropertyName) {
host[`[${hostBinding.hostPropertyName}]`] = propName;
} else {
host[`[${propName}]`] = propName;
}
} else if (a instanceof HostListener) {
const hostListener: HostListener = a;
- var args = isPresent(hostListener.args) ? (hostListener.args).join(', ') : '';
- host[`(${hostListener.eventName})`] = `${propName}(${args})`;
+ const args = hostListener.args || [];
+ host[`(${hostListener.eventName})`] = `${propName}(${args.join(',')})`;
} else if (a instanceof Query) {
queries[propName] = a;
}
@@ -91,13 +90,14 @@ export class DirectiveResolver {
private _extractPublicName(def: string) { return splitAtColon(def, [null, def])[1].trim(); }
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): Directive {
- let mergedInputs: string[];
+ const mergedInputs: string[] = inputs;
- if (isPresent(dm.inputs)) {
+ if (directive.inputs) {
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) => {
const publicName = this._extractPublicName(inputDef);
if (inputNames.indexOf(publicName) > -1) {
@@ -105,16 +105,15 @@ export class DirectiveResolver {
`Input '${publicName}' defined multiple times in '${stringify(directiveType)}'`);
}
});
- mergedInputs = dm.inputs.concat(inputs);
- } else {
- mergedInputs = inputs;
+
+ mergedInputs.unshift(...directive.inputs);
}
- let mergedOutputs: string[];
+ let mergedOutputs: string[] = outputs;
- if (isPresent(dm.outputs)) {
+ if (directive.outputs) {
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) => {
const publicName = this._extractPublicName(outputDef);
@@ -123,47 +122,48 @@ export class DirectiveResolver {
`Output event '${publicName}' defined multiple times in '${stringify(directiveType)}'`);
}
});
- mergedOutputs = dm.outputs.concat(outputs);
- } else {
- mergedOutputs = outputs;
+ mergedOutputs.unshift(...directive.outputs);
}
- var mergedHost = isPresent(dm.host) ? StringMapWrapper.merge(dm.host, host) : host;
- var mergedQueries =
- isPresent(dm.queries) ? StringMapWrapper.merge(dm.queries, queries) : queries;
+ const mergedHost = directive.host ? StringMapWrapper.merge(directive.host, host) : host;
+ const mergedQueries =
+ directive.queries ? StringMapWrapper.merge(directive.queries, queries) : queries;
- if (dm instanceof Component) {
+ if (directive instanceof Component) {
return new Component({
- selector: dm.selector,
+ selector: directive.selector,
inputs: mergedInputs,
outputs: mergedOutputs,
host: mergedHost,
- exportAs: dm.exportAs,
- moduleId: dm.moduleId,
+ exportAs: directive.exportAs,
+ moduleId: directive.moduleId,
queries: mergedQueries,
- changeDetection: dm.changeDetection,
- providers: dm.providers,
- viewProviders: dm.viewProviders,
- entryComponents: dm.entryComponents,
- template: dm.template,
- templateUrl: dm.templateUrl,
- styles: dm.styles,
- styleUrls: dm.styleUrls,
- encapsulation: dm.encapsulation,
- animations: dm.animations,
- interpolation: dm.interpolation
+ changeDetection: directive.changeDetection,
+ providers: directive.providers,
+ viewProviders: directive.viewProviders,
+ entryComponents: directive.entryComponents,
+ template: directive.template,
+ templateUrl: directive.templateUrl,
+ styles: directive.styles,
+ styleUrls: directive.styleUrls,
+ encapsulation: directive.encapsulation,
+ animations: directive.animations,
+ interpolation: directive.interpolation
});
-
} else {
return new Directive({
- selector: dm.selector,
+ selector: directive.selector,
inputs: mergedInputs,
outputs: mergedOutputs,
host: mergedHost,
- exportAs: dm.exportAs,
+ exportAs: directive.exportAs,
queries: mergedQueries,
- providers: dm.providers
+ providers: directive.providers
});
}
}
}
+
+function isDirectiveMetadata(type: any): type is Directive {
+ return type instanceof Directive;
+}
diff --git a/modules/@angular/compiler/src/expression_parser/ast.ts b/modules/@angular/compiler/src/expression_parser/ast.ts
index 331fe62d66ef..340c47981ea2 100644
--- a/modules/@angular/compiler/src/expression_parser/ast.ts
+++ b/modules/@angular/compiler/src/expression_parser/ast.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {ListWrapper} from '../facade/collection';
+
import {isBlank} from '../facade/lang';
export class ParserError {
@@ -376,7 +376,7 @@ export class AstTransformer implements AstVisitor {
}
visitAll(asts: any[]): any[] {
- var res = ListWrapper.createFixedSize(asts.length);
+ var res = new Array(asts.length);
for (var i = 0; i < asts.length; ++i) {
res[i] = asts[i].visit(this);
}
diff --git a/modules/@angular/compiler/src/i18n/serializers/xliff.ts b/modules/@angular/compiler/src/i18n/serializers/xliff.ts
index c1fc9540bcb1..2600af3f7feb 100644
--- a/modules/@angular/compiler/src/i18n/serializers/xliff.ts
+++ b/modules/@angular/compiler/src/i18n/serializers/xliff.ts
@@ -27,7 +27,6 @@ const _PLACEHOLDER_TAG = 'x';
const _SOURCE_TAG = 'source';
const _TARGET_TAG = 'target';
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/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'});
transUnit.children.push(
- _CR(8), new xml.Tag(_SOURCE_TAG, {}, visitor.serialize(message.nodes)), _CR(8),
- new xml.Tag(_TARGET_TAG));
+ new xml.CR(8), new xml.Tag(_SOURCE_TAG, {}, visitor.serialize(message.nodes)),
+ new xml.CR(8), new xml.Tag(_TARGET_TAG));
if (message.description) {
transUnit.children.push(
- _CR(8),
+ new xml.CR(8),
new xml.Tag(
'note', {priority: '1', from: 'description'}, [new xml.Text(message.description)]));
}
if (message.meaning) {
transUnit.children.push(
- _CR(8),
+ new xml.CR(8),
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(
'file', {'source-language': _SOURCE_LANG, datatype: 'plaintext', original: 'ng2.template'},
- [_CR(4), body, _CR(2)]);
- const xliff = new xml.Tag('xliff', {version: _VERSION, xmlns: _XMLNS}, [_CR(2), file, _CR()]);
+ [new xml.CR(4), body, new xml.CR(2)]);
+ 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[]} {
@@ -137,13 +139,15 @@ class _WriteVisitor implements i18n.Visitor {
}
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) {
// void tags have no children nor closing tags
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];
}
@@ -287,3 +291,14 @@ class _LoadVisitor implements ml.Visitor {
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}`;
+ }
+}
\ No newline at end of file
diff --git a/modules/@angular/compiler/src/i18n/serializers/xmb.ts b/modules/@angular/compiler/src/i18n/serializers/xmb.ts
index e19391fd4b60..d582ef569bed 100644
--- a/modules/@angular/compiler/src/i18n/serializers/xmb.ts
+++ b/modules/@angular/compiler/src/i18n/serializers/xmb.ts
@@ -43,7 +43,6 @@ export class Xmb implements Serializer {
write(messageMap: {[k: string]: i18n.Message}): string {
const visitor = new _Visitor();
let rootNode = new xml.Tag(_MESSAGES_TAG);
- rootNode.children.push(new xml.Text('\n'));
Object.keys(messageMap).forEach((id) => {
const message = messageMap[id];
@@ -58,16 +57,18 @@ export class Xmb implements Serializer {
}
rootNode.children.push(
- new xml.Text(' '), new xml.Tag(_MESSAGE_TAG, attrs, visitor.serialize(message.nodes)),
- new xml.Text('\n'));
+ new xml.CR(2), new xml.Tag(_MESSAGE_TAG, attrs, visitor.serialize(message.nodes)));
});
+ rootNode.children.push(new xml.CR());
+
return xml.serialize([
new xml.Declaration({version: '1.0', encoding: 'UTF-8'}),
- new xml.Text('\n'),
+ new xml.CR(),
new xml.Doctype(_MESSAGES_TAG, _DOCTYPE),
- new xml.Text('\n'),
+ new xml.CR(),
rootNode,
+ new xml.CR(),
]);
}
diff --git a/modules/@angular/compiler/src/i18n/serializers/xml_helper.ts b/modules/@angular/compiler/src/i18n/serializers/xml_helper.ts
index d5d142581d87..e7cbc8bbcbc1 100644
--- a/modules/@angular/compiler/src/i18n/serializers/xml_helper.ts
+++ b/modules/@angular/compiler/src/i18n/serializers/xml_helper.ts
@@ -88,6 +88,10 @@ export class Text implements Node {
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][] = [
[/&/g, '&'],
[/"/g, '"'],
diff --git a/modules/@angular/compiler/src/identifiers.ts b/modules/@angular/compiler/src/identifiers.ts
index a81eeb81c9e2..f1008b45c776 100644
--- a/modules/@angular/compiler/src/identifiers.ts
+++ b/modules/@angular/compiler/src/identifiers.ts
@@ -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 {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';
var APP_VIEW_MODULE_URL = assetUrl('core', 'linker/view');
@@ -266,11 +266,6 @@ export class Identifiers {
moduleUrl: assetUrl('core', 'i18n/tokens'),
runtime: TRANSLATIONS_FORMAT_
};
- static AnimationOutput: IdentifierSpec = {
- name: 'AnimationOutput',
- moduleUrl: assetUrl('core', 'animation/animation_output'),
- runtime: AnimationOutput
- };
}
export function resolveIdentifier(identifier: IdentifierSpec) {
diff --git a/modules/@angular/compiler/src/ml_parser/parser.ts b/modules/@angular/compiler/src/ml_parser/parser.ts
index 1dcf48a14a9c..47e7c6272edf 100644
--- a/modules/@angular/compiler/src/ml_parser/parser.ts
+++ b/modules/@angular/compiler/src/ml_parser/parser.ts
@@ -123,7 +123,7 @@ class _TreeBuilder {
// read =
while (this._peek.type === lex.TokenType.EXPANSION_CASE_VALUE) {
let expCase = this._parseExpansionCase();
- if (isBlank(expCase)) return; // error
+ if (!expCase) return; // error
cases.push(expCase);
}
@@ -154,7 +154,7 @@ class _TreeBuilder {
const start = this._advance();
const exp = this._collectExpansionExpTokens(start);
- if (isBlank(exp)) return null;
+ if (!exp) return null;
const end = this._advance();
exp.push(new lex.Token(lex.TokenType.EOF, [], end.sourceSpan));
diff --git a/modules/@angular/compiler/src/ng_module_compiler.ts b/modules/@angular/compiler/src/ng_module_compiler.ts
index 4c0871818f3a..480ee0fadf7f 100644
--- a/modules/@angular/compiler/src/ng_module_compiler.ts
+++ b/modules/@angular/compiler/src/ng_module_compiler.ts
@@ -9,8 +9,8 @@
import {Injectable} from '@angular/core';
import {CompileDiDependencyMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileProviderMetadata, CompileTokenMetadata} from './compile_metadata';
-import {isBlank, isPresent} from './facade/lang';
-import {Identifiers, identifierToken, resolveIdentifier, resolveIdentifierToken} from './identifiers';
+import {isPresent} from './facade/lang';
+import {Identifiers, resolveIdentifier, resolveIdentifierToken} from './identifiers';
import * as o from './output/output_ast';
import {convertValueToOutputAst} from './output/value_util';
import {ParseLocation, ParseSourceFile, ParseSourceSpan} from './parse_util';
@@ -190,7 +190,7 @@ class _InjectorBuilder {
resolvedProviderValueExpr = providerValueExpressions[0];
type = providerValueExpressions[0].type;
}
- if (isBlank(type)) {
+ if (!type) {
type = o.DYNAMIC_TYPE;
}
if (isEager) {
@@ -223,11 +223,11 @@ class _InjectorBuilder {
resolveIdentifierToken(Identifiers.ComponentFactoryResolver).reference)) {
result = o.THIS_EXPR;
}
- if (isBlank(result)) {
+ if (!result) {
result = this._instances.get(dep.token.reference);
}
}
- if (isBlank(result)) {
+ if (!result) {
var args = [createDiTokenExpression(dep.token)];
if (dep.isOptional) {
args.push(o.NULL_EXPR);
diff --git a/modules/@angular/compiler/src/offline_compiler.ts b/modules/@angular/compiler/src/offline_compiler.ts
index 90bd832096c4..e7cdaeb34f26 100644
--- a/modules/@angular/compiler/src/offline_compiler.ts
+++ b/modules/@angular/compiler/src/offline_compiler.ts
@@ -8,7 +8,9 @@
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 {Identifiers, resolveIdentifier, resolveIdentifierToken} from './identifiers';
import {CompileMetadataResolver} from './metadata_resolver';
@@ -28,6 +30,9 @@ export class NgModulesSummary {
}
export class OfflineCompiler {
+ private _animationParser = new AnimationParser();
+ private _animationCompiler = new AnimationCompiler();
+
constructor(
private _metadataResolver: CompileMetadataResolver,
private _directiveNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser,
@@ -162,14 +167,19 @@ export class OfflineCompiler {
compMeta: CompileDirectiveMetadata, directives: CompileDirectiveMetadata[],
pipes: CompilePipeMetadata[], schemas: SchemaMetadata[], componentStyles: CompiledStylesheet,
fileSuffix: string, targetStatements: o.Statement[]): string {
+ const parsedAnimations = this._animationParser.parseComponent(compMeta);
const parsedTemplate = this._templateParser.parse(
compMeta, compMeta.template.template, directives, pipes, schemas, compMeta.type.name);
const stylesExpr = componentStyles ? o.variable(componentStyles.stylesVar) : o.literalArr([]);
- const viewResult =
- this._viewCompiler.compileComponent(compMeta, parsedTemplate, stylesExpr, pipes);
+ const compiledAnimations =
+ this._animationCompiler.compile(compMeta.type.name, parsedAnimations);
+ const viewResult = this._viewCompiler.compileComponent(
+ compMeta, parsedTemplate, stylesExpr, pipes, compiledAnimations);
if (componentStyles) {
targetStatements.push(..._resolveStyleStatements(componentStyles, fileSuffix));
}
+ compiledAnimations.forEach(
+ entry => { entry.statements.forEach(statement => { targetStatements.push(statement); }); });
targetStatements.push(..._resolveViewStatements(viewResult));
return viewResult.viewFactoryVar;
}
diff --git a/modules/@angular/compiler/src/output/abstract_emitter.ts b/modules/@angular/compiler/src/output/abstract_emitter.ts
index 54dc6b1981a9..f9ed12a5fea9 100644
--- a/modules/@angular/compiler/src/output/abstract_emitter.ts
+++ b/modules/@angular/compiler/src/output/abstract_emitter.ts
@@ -400,7 +400,7 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex
}
visitAllStatements(statements: o.Statement[], ctx: EmitterVisitorContext): void {
- statements.forEach((stmt) => { return stmt.visitStatement(this, ctx); });
+ statements.forEach((stmt) => stmt.visitStatement(this, ctx));
}
}
diff --git a/modules/@angular/compiler/src/output/js_emitter.ts b/modules/@angular/compiler/src/output/js_emitter.ts
index c59e5584172d..2a34751137c0 100644
--- a/modules/@angular/compiler/src/output/js_emitter.ts
+++ b/modules/@angular/compiler/src/output/js_emitter.ts
@@ -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 {AbstractJsEmitterVisitor} from './abstract_js_emitter';
diff --git a/modules/@angular/compiler/src/output/output_ast.ts b/modules/@angular/compiler/src/output/output_ast.ts
index f148d402b3d4..d64eb1b4c9eb 100644
--- a/modules/@angular/compiler/src/output/output_ast.ts
+++ b/modules/@angular/compiler/src/output/output_ast.ts
@@ -8,9 +8,7 @@
import {CompileIdentifierMetadata} from '../compile_metadata';
-import {StringMapWrapper} from '../facade/collection';
-import {isBlank, isPresent, isString} from '../facade/lang';
-import {ValueTransformer, visitValue} from '../util';
+import {isPresent, isString} from '../facade/lang';
@@ -21,7 +19,7 @@ export enum TypeModifier {
export abstract class Type {
constructor(public modifiers: TypeModifier[] = null) {
- if (isBlank(modifiers)) {
+ if (!modifiers) {
this.modifiers = [];
}
}
@@ -464,7 +462,7 @@ export enum StmtModifier {
export abstract class Statement {
constructor(public modifiers: StmtModifier[] = null) {
- if (isBlank(modifiers)) {
+ if (!modifiers) {
this.modifiers = [];
}
}
@@ -519,7 +517,7 @@ export class ReturnStatement extends Statement {
export class AbstractClassPart {
constructor(public type: Type = null, public modifiers: StmtModifier[]) {
- if (isBlank(modifiers)) {
+ if (!modifiers) {
this.modifiers = [];
}
}
diff --git a/modules/@angular/compiler/src/output/path_util.ts b/modules/@angular/compiler/src/output/path_util.ts
index f9f762deb44b..aebfb7bbabb2 100644
--- a/modules/@angular/compiler/src/output/path_util.ts
+++ b/modules/@angular/compiler/src/output/path_util.ts
@@ -6,11 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {Injectable} from '@angular/core';
-
-import {Math, isBlank, isPresent} from '../facade/lang';
-
-
// asset://
var _ASSET_URL_RE = /asset:([^\/]+)\/([^\/]+)\/(.+)/;
diff --git a/modules/@angular/compiler/src/output/value_util.ts b/modules/@angular/compiler/src/output/value_util.ts
index 9b0df14bc032..37ac5756ec2d 100644
--- a/modules/@angular/compiler/src/output/value_util.ts
+++ b/modules/@angular/compiler/src/output/value_util.ts
@@ -8,7 +8,6 @@
import {CompileIdentifierMetadata} from '../compile_metadata';
-import {StringMapWrapper} from '../facade/collection';
import {ValueTransformer, visitValue} from '../util';
import * as o from './output_ast';
@@ -24,9 +23,7 @@ class _ValueOutputAstTransformer implements ValueTransformer {
visitStringMap(map: {[key: string]: any}, type: o.MapType): o.Expression {
var entries: Array[] = [];
- StringMapWrapper.forEach(map, (value: any, key: string) => {
- entries.push([key, visitValue(value, this, null)]);
- });
+ Object.keys(map).forEach(key => { entries.push([key, visitValue(map[key], this, null)]); });
return o.literalMap(entries, type);
}
diff --git a/modules/@angular/compiler/src/private_import_core.ts b/modules/@angular/compiler/src/private_import_core.ts
index 5bd4cd4df19e..8936e825f448 100644
--- a/modules/@angular/compiler/src/private_import_core.ts
+++ b/modules/@angular/compiler/src/private_import_core.ts
@@ -12,7 +12,6 @@ export const isDefaultChangeDetectionStrategy: typeof r.isDefaultChangeDetection
r.isDefaultChangeDetectionStrategy;
export type ChangeDetectorStatus = typeof r._ChangeDetectorStatus;
export const ChangeDetectorStatus: typeof r.ChangeDetectorStatus = r.ChangeDetectorStatus;
-r.CHANGE_DETECTION_STRATEGY_VALUES;
export type LifecycleHooks = typeof r._LifecycleHooks;
export const LifecycleHooks: typeof r.LifecycleHooks = r.LifecycleHooks;
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 type AnimationStyles = typeof 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 DEFAULT_STATE = r.DEFAULT_STATE;
export const EMPTY_STATE = r.EMPTY_STATE;
diff --git a/modules/@angular/compiler/src/provider_analyzer.ts b/modules/@angular/compiler/src/provider_analyzer.ts
index 52f7c7114226..f1c2901d997a 100644
--- a/modules/@angular/compiler/src/provider_analyzer.ts
+++ b/modules/@angular/compiler/src/provider_analyzer.ts
@@ -12,7 +12,7 @@ import {ListWrapper, MapWrapper} from './facade/collection';
import {isArray, isBlank, isPresent, normalizeBlank} from './facade/lang';
import {Identifiers, resolveIdentifierToken} from './identifiers';
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 {
constructor(message: string, span: ParseSourceSpan) { super(span, message); }
@@ -50,14 +50,14 @@ export class ProviderElementContext {
private _hasViewContainer: boolean = false;
constructor(
- private _viewContext: ProviderViewContext, private _parent: ProviderElementContext,
+ public viewContext: ProviderViewContext, private _parent: ProviderElementContext,
private _isViewRoot: boolean, private _directiveAsts: DirectiveAst[], attrs: AttrAst[],
refs: ReferenceAst[], private _sourceSpan: ParseSourceSpan) {
this._attrs = {};
attrs.forEach((attrAst) => this._attrs[attrAst.name] = attrAst.value);
var directivesMeta = _directiveAsts.map(directiveAst => directiveAst.directive);
this._allProviders =
- _resolveProvidersFromDirectives(directivesMeta, _sourceSpan, _viewContext.errors);
+ _resolveProvidersFromDirectives(directivesMeta, _sourceSpan, viewContext.errors);
this._contentQueries = _getContentQueries(directivesMeta);
var queriedTokens = new Map();
MapWrapper.values(this._allProviders).forEach((provider) => {
@@ -124,7 +124,7 @@ export class ProviderElementContext {
}
currentEl = currentEl._parent;
}
- queries = this._viewContext.viewQueries.get(token.reference);
+ queries = this.viewContext.viewQueries.get(token.reference);
if (isPresent(queries)) {
ListWrapper.addAll(result, queries);
}
@@ -136,10 +136,9 @@ export class ProviderElementContext {
requestingProviderType: ProviderAstType, token: CompileTokenMetadata,
eager: boolean): ProviderAst {
var resolvedProvider = this._allProviders.get(token.reference);
- if (isBlank(resolvedProvider) ||
- ((requestingProviderType === ProviderAstType.Directive ||
- requestingProviderType === ProviderAstType.PublicService) &&
- resolvedProvider.providerType === ProviderAstType.PrivateService) ||
+ if (!resolvedProvider || ((requestingProviderType === ProviderAstType.Directive ||
+ requestingProviderType === ProviderAstType.PublicService) &&
+ resolvedProvider.providerType === ProviderAstType.PrivateService) ||
((requestingProviderType === ProviderAstType.PrivateService ||
requestingProviderType === ProviderAstType.PublicService) &&
resolvedProvider.providerType === ProviderAstType.Builtin)) {
@@ -150,7 +149,7 @@ export class ProviderElementContext {
return transformedProviderAst;
}
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));
return null;
}
@@ -239,12 +238,12 @@ export class ProviderElementContext {
result = this._getLocalDependency(requestingProviderType, dep, eager);
}
if (dep.isSelf) {
- if (isBlank(result) && dep.isOptional) {
+ if (!result && dep.isOptional) {
result = new CompileDiDependencyMetadata({isValue: true, value: null});
}
} else {
// check parent elements
- while (isBlank(result) && isPresent(currElement._parent)) {
+ while (!result && isPresent(currElement._parent)) {
var prevElement = currElement;
currElement = currElement._parent;
if (prevElement._isViewRoot) {
@@ -253,10 +252,10 @@ export class ProviderElementContext {
result = currElement._getLocalDependency(ProviderAstType.PublicService, dep, currEager);
}
// check @Host restriction
- if (isBlank(result)) {
- if (!dep.isHost || this._viewContext.component.type.isHost ||
- this._viewContext.component.type.reference === dep.token.reference ||
- isPresent(this._viewContext.viewProviders.get(dep.token.reference))) {
+ if (!result) {
+ if (!dep.isHost || this.viewContext.component.type.isHost ||
+ this.viewContext.component.type.reference === dep.token.reference ||
+ isPresent(this.viewContext.viewProviders.get(dep.token.reference))) {
result = dep;
} else {
result = dep.isOptional ?
@@ -265,8 +264,8 @@ export class ProviderElementContext {
}
}
}
- if (isBlank(result)) {
- this._viewContext.errors.push(
+ if (!result) {
+ this.viewContext.errors.push(
new ProviderError(`No provider for ${dep.token.name}`, this._sourceSpan));
}
return result;
@@ -311,7 +310,7 @@ export class NgModuleProviderAnalyzer {
private _getOrCreateLocalProvider(token: CompileTokenMetadata, eager: boolean): ProviderAst {
var resolvedProvider = this._allProviders.get(token.reference);
- if (isBlank(resolvedProvider)) {
+ if (!resolvedProvider) {
return null;
}
var transformedProviderAst = this._transformedProviders.get(token.reference);
@@ -414,7 +413,7 @@ function _normalizeProviders(
providers: Array,
sourceSpan: ParseSourceSpan, targetErrors: ParseError[],
targetProviders: CompileProviderMetadata[] = null): CompileProviderMetadata[] {
- if (isBlank(targetProviders)) {
+ if (!targetProviders) {
targetProviders = [];
}
if (isPresent(providers)) {
@@ -479,7 +478,7 @@ function _resolveProviders(
`Mixing multi and non multi provider is not possible for token ${resolvedProvider.token.name}`,
sourceSpan));
}
- if (isBlank(resolvedProvider)) {
+ if (!resolvedProvider) {
const lifecycleHooks =
provider.token.identifier && provider.token.identifier instanceof CompileTypeMetadata ?
provider.token.identifier.lifecycleHooks :
@@ -530,7 +529,7 @@ function _getContentQueries(directives: CompileDirectiveMetadata[]):
function _addQueryToTokenMap(map: Map, query: CompileQueryMetadata) {
query.selectors.forEach((token: CompileTokenMetadata) => {
var entry = map.get(token.reference);
- if (isBlank(entry)) {
+ if (!entry) {
entry = [];
map.set(token.reference, entry);
}
diff --git a/modules/@angular/compiler/src/runtime_compiler.ts b/modules/@angular/compiler/src/runtime_compiler.ts
index 768380339ecc..f91af0272e00 100644
--- a/modules/@angular/compiler/src/runtime_compiler.ts
+++ b/modules/@angular/compiler/src/runtime_compiler.ts
@@ -6,12 +6,13 @@
* 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 {CompilerConfig} from './config';
import {DirectiveNormalizer} from './directive_normalizer';
-import {isBlank, stringify} from './facade/lang';
+import {stringify} from './facade/lang';
import {CompileMetadataResolver} from './metadata_resolver';
import {NgModuleCompiler} from './ng_module_compiler';
import * as ir from './output/output_ast';
@@ -23,8 +24,6 @@ import {TemplateParser} from './template_parser/template_parser';
import {SyncAsyncResult} from './util';
import {ComponentFactoryDependency, ViewCompiler, ViewFactoryDependency} from './view_compiler/view_compiler';
-
-
/**
* An internal module of the Angular compiler that begins with component types,
* extracts templates, and eventually produces a compiled version of the component
@@ -39,6 +38,8 @@ export class RuntimeCompiler implements Compiler {
private _compiledTemplateCache = new Map, CompiledTemplate>();
private _compiledHostTemplateCache = new Map, CompiledTemplate>();
private _compiledNgModuleCache = new Map, NgModuleFactory>();
+ private _animationParser = new AnimationParser();
+ private _animationCompiler = new AnimationCompiler();
constructor(
private _injector: Injector, private _metadataResolver: CompileMetadataResolver,
@@ -190,7 +191,7 @@ export class RuntimeCompiler implements Compiler {
private _createCompiledHostTemplate(compType: Type): CompiledTemplate {
var compiledTemplate = this._compiledHostTemplateCache.get(compType);
- if (isBlank(compiledTemplate)) {
+ if (!compiledTemplate) {
var compMeta = this._metadataResolver.getDirectiveMetadata(compType);
assertComponent(compMeta);
var hostMeta = createHostComponentMeta(compMeta);
@@ -205,7 +206,7 @@ export class RuntimeCompiler implements Compiler {
private _createCompiledTemplate(
compMeta: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata): CompiledTemplate {
var compiledTemplate = this._compiledTemplateCache.get(compMeta.type.reference);
- if (isBlank(compiledTemplate)) {
+ if (!compiledTemplate) {
assertComponent(compMeta);
compiledTemplate = new CompiledTemplate(
false, compMeta.selector, compMeta.type, ngModule.transitiveModule.directives,
@@ -253,12 +254,15 @@ export class RuntimeCompiler implements Compiler {
stylesCompileResult.componentStylesheet, externalStylesheetsByModuleUrl);
const viewCompMetas = template.viewComponentTypes.map(
(compType) => this._assertComponentLoaded(compType, false).normalizedCompMeta);
+ const parsedAnimations = this._animationParser.parseComponent(compMeta);
const parsedTemplate = this._templateParser.parse(
compMeta, compMeta.template.template, template.viewDirectives.concat(viewCompMetas),
template.viewPipes, template.schemas, compMeta.type.name);
+ const compiledAnimations =
+ this._animationCompiler.compile(compMeta.type.name, parsedAnimations);
const compileResult = this._viewCompiler.compileComponent(
compMeta, parsedTemplate, ir.variable(stylesCompileResult.componentStylesheet.stylesVar),
- template.viewPipes);
+ template.viewPipes, compiledAnimations);
compileResult.dependencies.forEach((dep) => {
let depTemplate: CompiledTemplate;
if (dep instanceof ViewFactoryDependency) {
@@ -275,6 +279,8 @@ export class RuntimeCompiler implements Compiler {
});
const statements =
stylesCompileResult.componentStylesheet.statements.concat(compileResult.statements);
+ compiledAnimations.forEach(
+ entry => { entry.statements.forEach(statement => { statements.push(statement); }); });
let factory: any;
if (!this._compilerConfig.useJit) {
factory = interpretStatements(statements, compileResult.viewFactoryVar);
diff --git a/modules/@angular/compiler/src/schema/dom_element_schema_registry.ts b/modules/@angular/compiler/src/schema/dom_element_schema_registry.ts
index 90f83fee1b63..929b1f40aab9 100644
--- a/modules/@angular/compiler/src/schema/dom_element_schema_registry.ts
+++ b/modules/@angular/compiler/src/schema/dom_element_schema_registry.ts
@@ -344,4 +344,26 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry {
getMappedPropName(propName: string): string { return _ATTR_TO_PROP[propName] || propName; }
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};
+ }
+ }
}
diff --git a/modules/@angular/compiler/src/schema/element_schema_registry.ts b/modules/@angular/compiler/src/schema/element_schema_registry.ts
index b16428f9e372..52ed080d9680 100644
--- a/modules/@angular/compiler/src/schema/element_schema_registry.ts
+++ b/modules/@angular/compiler/src/schema/element_schema_registry.ts
@@ -14,4 +14,6 @@ export abstract class ElementSchemaRegistry {
abstract securityContext(tagName: string, propName: string): any;
abstract getMappedPropName(propName: string): string;
abstract getDefaultComponentElementName(): string;
+ abstract validateProperty(name: string): {error: boolean, msg?: string};
+ abstract validateAttribute(name: string): {error: boolean, msg?: string};
}
diff --git a/modules/@angular/compiler/src/selector.ts b/modules/@angular/compiler/src/selector.ts
index b1408f8e9df0..df3878627db5 100644
--- a/modules/@angular/compiler/src/selector.ts
+++ b/modules/@angular/compiler/src/selector.ts
@@ -6,18 +6,13 @@
* 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';
-const _EMPTY_ATTR_VALUE = '';
-
const _SELECTOR_REGEXP = new RegExp(
'(\\:not\\()|' + //":not("
'([-\\w]+)|' + // "tag"
'(?:\\.([-\\w]+))|' + // ".class"
- '(?:\\[([-\\w*]+)(?:=([^\\]]*))?\\])|' + // "[name]", "[name=value]" or "[name*=value]"
+ '(?:\\[([-\\w*]+)(?:=([^\\]]*))?\\])|' + // "[name]", "[name=value]"
'(\\))|' + // ")"
'(\\s*,\\s*)', // ","
'g');
@@ -34,21 +29,21 @@ export class CssSelector {
notSelectors: CssSelector[] = [];
static parse(selector: string): CssSelector[] {
- var results: CssSelector[] = [];
- var _addResult = (res: CssSelector[], cssSel: CssSelector) => {
- if (cssSel.notSelectors.length > 0 && isBlank(cssSel.element) &&
- ListWrapper.isEmpty(cssSel.classNames) && ListWrapper.isEmpty(cssSel.attrs)) {
+ const results: CssSelector[] = [];
+ const _addResult = (res: CssSelector[], cssSel: CssSelector) => {
+ if (cssSel.notSelectors.length > 0 && !cssSel.element && cssSel.classNames.length == 0 &&
+ cssSel.attrs.length == 0) {
cssSel.element = '*';
}
res.push(cssSel);
};
- var cssSelector = new CssSelector();
- var match: string[];
- var current = cssSelector;
- var inNot = false;
+ let cssSelector = new CssSelector();
+ let match: string[];
+ let current = cssSelector;
+ let inNot = false;
_SELECTOR_REGEXP.lastIndex = 0;
- while (isPresent(match = _SELECTOR_REGEXP.exec(selector))) {
- if (isPresent(match[1])) {
+ while (match = _SELECTOR_REGEXP.exec(selector)) {
+ if (match[1]) {
if (inNot) {
throw new Error('Nesting :not is not allowed in a selector');
}
@@ -56,20 +51,20 @@ export class CssSelector {
current = new CssSelector();
cssSelector.notSelectors.push(current);
}
- if (isPresent(match[2])) {
+ if (match[2]) {
current.setElement(match[2]);
}
- if (isPresent(match[3])) {
+ if (match[3]) {
current.addClassName(match[3]);
}
- if (isPresent(match[4])) {
+ if (match[4]) {
current.addAttribute(match[4], match[5]);
}
- if (isPresent(match[6])) {
+ if (match[6]) {
inNot = false;
current = cssSelector;
}
- if (isPresent(match[7])) {
+ if (match[7]) {
if (inNot) {
throw new Error('Multiple selectors in :not are not supported');
}
@@ -106,37 +101,22 @@ export class CssSelector {
`<${tagName}${classAttr}${attrs}>${tagName}>`;
}
- addAttribute(name: string, value: string = _EMPTY_ATTR_VALUE) {
- this.attrs.push(name);
- if (isPresent(value)) {
- value = value.toLowerCase();
- } else {
- value = _EMPTY_ATTR_VALUE;
- }
- this.attrs.push(value);
+ addAttribute(name: string, value: string = '') {
+ this.attrs.push(name, value && value.toLowerCase() || '');
}
addClassName(name: string) { this.classNames.push(name.toLowerCase()); }
toString(): string {
- var res = '';
- if (isPresent(this.element)) {
- res += this.element;
+ let res: string = this.element || '';
+ if (this.classNames) {
+ this.classNames.forEach(klass => res += `.${klass}`);
}
- if (isPresent(this.classNames)) {
- for (var i = 0; i < this.classNames.length; i++) {
- res += '.' + this.classNames[i];
- }
- }
- 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 += ']';
+ if (this.attrs) {
+ for (let i = 0; i < this.attrs.length; i += 2) {
+ const name = this.attrs[i];
+ const value = this.attrs[i + 1];
+ res += `[${name}${value ? '=' + value : ''}]`;
}
}
this.notSelectors.forEach(notSelector => res += `:not(${notSelector})`);
@@ -150,26 +130,26 @@ export class CssSelector {
*/
export class SelectorMatcher {
static createNotMatcher(notSelectors: CssSelector[]): SelectorMatcher {
- var notMatcher = new SelectorMatcher();
+ const notMatcher = new SelectorMatcher();
notMatcher.addSelectables(notSelectors, null);
return notMatcher;
}
- private _elementMap = new Map();
- private _elementPartialMap = new Map();
- private _classMap = new Map();
- private _classPartialMap = new Map();
- private _attrValueMap = new Map>();
- private _attrValuePartialMap = new Map>();
+ private _elementMap: {[k: string]: SelectorContext[]} = {};
+ private _elementPartialMap: {[k: string]: SelectorMatcher} = {};
+ private _classMap: {[k: string]: SelectorContext[]} = {};
+ private _classPartialMap: {[k: string]: SelectorMatcher} = {};
+ private _attrValueMap: {[k: string]: {[k: string]: SelectorContext[]}} = {};
+ private _attrValuePartialMap: {[k: string]: {[k: string]: SelectorMatcher}} = {};
private _listContexts: SelectorListContext[] = [];
addSelectables(cssSelectors: CssSelector[], callbackCtxt?: any) {
- var listContext: SelectorListContext = null;
+ let listContext: SelectorListContext = null;
if (cssSelectors.length > 1) {
listContext = new SelectorListContext(cssSelectors);
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);
}
}
@@ -181,14 +161,14 @@ export class SelectorMatcher {
*/
private _addSelectable(
cssSelector: CssSelector, callbackCtxt: any, listContext: SelectorListContext) {
- var matcher: SelectorMatcher = this;
- var element = cssSelector.element;
- var classNames = cssSelector.classNames;
- var attrs = cssSelector.attrs;
- var selectable = new SelectorContext(cssSelector, callbackCtxt, listContext);
-
- if (isPresent(element)) {
- var isTerminal = attrs.length === 0 && classNames.length === 0;
+ let matcher: SelectorMatcher = this;
+ const element = cssSelector.element;
+ const classNames = cssSelector.classNames;
+ const attrs = cssSelector.attrs;
+ const selectable = new SelectorContext(cssSelector, callbackCtxt, listContext);
+
+ if (element) {
+ const isTerminal = attrs.length === 0 && classNames.length === 0;
if (isTerminal) {
this._addTerminal(matcher._elementMap, element, selectable);
} else {
@@ -196,10 +176,10 @@ export class SelectorMatcher {
}
}
- if (isPresent(classNames)) {
- for (var index = 0; index < classNames.length; index++) {
- var isTerminal = attrs.length === 0 && index === classNames.length - 1;
- var className = classNames[index];
+ if (classNames) {
+ for (let i = 0; i < classNames.length; i++) {
+ const isTerminal = attrs.length === 0 && i === classNames.length - 1;
+ const className = classNames[i];
if (isTerminal) {
this._addTerminal(matcher._classMap, className, selectable);
} else {
@@ -208,47 +188,47 @@ export class SelectorMatcher {
}
}
- if (isPresent(attrs)) {
- for (var index = 0; index < attrs.length;) {
- var isTerminal = index === attrs.length - 2;
- var attrName = attrs[index++];
- var attrValue = attrs[index++];
+ if (attrs) {
+ for (let i = 0; i < attrs.length; i += 2) {
+ const isTerminal = i === attrs.length - 2;
+ const name = attrs[i];
+ const value = attrs[i + 1];
if (isTerminal) {
- var terminalMap = matcher._attrValueMap;
- var terminalValuesMap = terminalMap.get(attrName);
- if (isBlank(terminalValuesMap)) {
- terminalValuesMap = new Map();
- terminalMap.set(attrName, terminalValuesMap);
+ const terminalMap = matcher._attrValueMap;
+ let terminalValuesMap = terminalMap[name];
+ if (!terminalValuesMap) {
+ terminalValuesMap = {};
+ terminalMap[name] = terminalValuesMap;
}
- this._addTerminal(terminalValuesMap, attrValue, selectable);
+ this._addTerminal(terminalValuesMap, value, selectable);
} else {
- var parttialMap = matcher._attrValuePartialMap;
- var partialValuesMap = parttialMap.get(attrName);
- if (isBlank(partialValuesMap)) {
- partialValuesMap = new Map();
- parttialMap.set(attrName, partialValuesMap);
+ let partialMap = matcher._attrValuePartialMap;
+ let partialValuesMap = partialMap[name];
+ if (!partialValuesMap) {
+ partialValuesMap = {};
+ partialMap[name] = partialValuesMap;
}
- matcher = this._addPartial(partialValuesMap, attrValue);
+ matcher = this._addPartial(partialValuesMap, value);
}
}
}
}
private _addTerminal(
- map: Map, name: string, selectable: SelectorContext) {
- var terminalList = map.get(name);
- if (isBlank(terminalList)) {
+ map: {[k: string]: SelectorContext[]}, name: string, selectable: SelectorContext) {
+ let terminalList = map[name];
+ if (!terminalList) {
terminalList = [];
- map.set(name, terminalList);
+ map[name] = terminalList;
}
terminalList.push(selectable);
}
- private _addPartial(map: Map, name: string): SelectorMatcher {
- var matcher = map.get(name);
- if (isBlank(matcher)) {
+ private _addPartial(map: {[k: string]: SelectorMatcher}, name: string): SelectorMatcher {
+ let matcher = map[name];
+ if (!matcher) {
matcher = new SelectorMatcher();
- map.set(name, matcher);
+ map[name] = matcher;
}
return matcher;
}
@@ -261,12 +241,12 @@ export class SelectorMatcher {
* @return boolean true if a match was found
*/
match(cssSelector: CssSelector, matchedCallback: (c: CssSelector, a: any) => void): boolean {
- var result = false;
- var element = cssSelector.element;
- var classNames = cssSelector.classNames;
- var attrs = cssSelector.attrs;
+ let result = false;
+ const element = cssSelector.element;
+ const classNames = cssSelector.classNames;
+ 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;
}
@@ -274,9 +254,9 @@ export class SelectorMatcher {
result = this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) ||
result;
- if (isPresent(classNames)) {
- for (var index = 0; index < classNames.length; index++) {
- var className = classNames[index];
+ if (classNames) {
+ for (let i = 0; i < classNames.length; i++) {
+ const className = classNames[i];
result =
this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result;
result =
@@ -285,28 +265,25 @@ export class SelectorMatcher {
}
}
- if (isPresent(attrs)) {
- for (var index = 0; index < attrs.length;) {
- var attrName = attrs[index++];
- var attrValue = attrs[index++];
+ if (attrs) {
+ for (let i = 0; i < attrs.length; i += 2) {
+ const name = attrs[i];
+ const value = attrs[i + 1];
- var terminalValuesMap = this._attrValueMap.get(attrName);
- if (!StringWrapper.equals(attrValue, _EMPTY_ATTR_VALUE)) {
- result = this._matchTerminal(
- terminalValuesMap, _EMPTY_ATTR_VALUE, cssSelector, matchedCallback) ||
- result;
+ const terminalValuesMap = this._attrValueMap[name];
+ if (value) {
+ result =
+ this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result;
}
- result = this._matchTerminal(terminalValuesMap, attrValue, cssSelector, matchedCallback) ||
- result;
+ result =
+ this._matchTerminal(terminalValuesMap, value, 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;
+ const partialValuesMap = this._attrValuePartialMap[name];
+ if (value) {
+ result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result;
}
result =
- this._matchPartial(partialValuesMap, attrValue, cssSelector, matchedCallback) || result;
+ this._matchPartial(partialValuesMap, value, cssSelector, matchedCallback) || result;
}
}
return result;
@@ -314,24 +291,24 @@ export class SelectorMatcher {
/** @internal */
_matchTerminal(
- map: Map, name: string, cssSelector: CssSelector,
+ map: {[k: string]: SelectorContext[]}, name: string, cssSelector: CssSelector,
matchedCallback: (c: CssSelector, a: any) => void): boolean {
- if (isBlank(map) || isBlank(name)) {
+ if (!map || typeof name !== 'string') {
return false;
}
- var selectables = map.get(name);
- var starSelectables = map.get('*');
- if (isPresent(starSelectables)) {
+ let selectables = map[name];
+ const starSelectables = map['*'];
+ if (starSelectables) {
selectables = selectables.concat(starSelectables);
}
- if (isBlank(selectables)) {
+ if (!selectables) {
return false;
}
- var selectable: SelectorContext;
- var result = false;
- for (var index = 0; index < selectables.length; index++) {
- selectable = selectables[index];
+ let selectable: SelectorContext;
+ let result = false;
+ for (let i = 0; i < selectables.length; i++) {
+ selectable = selectables[i];
result = selectable.finalize(cssSelector, matchedCallback) || result;
}
return result;
@@ -339,13 +316,14 @@ export class SelectorMatcher {
/** @internal */
_matchPartial(
- map: Map, name: string, cssSelector: CssSelector,
+ map: {[k: string]: SelectorMatcher}, name: string, cssSelector: CssSelector,
matchedCallback: (c: CssSelector, a: any) => void): boolean {
- if (isBlank(map) || isBlank(name)) {
+ if (!map || typeof name !== 'string') {
return false;
}
- var nestedSelector = map.get(name);
- if (isBlank(nestedSelector)) {
+
+ const nestedSelector = map[name];
+ if (!nestedSelector) {
return false;
}
// 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 {
- var result = true;
- if (this.notSelectors.length > 0 &&
- (isBlank(this.listContext) || !this.listContext.alreadyMatched)) {
- var notMatcher = SelectorMatcher.createNotMatcher(this.notSelectors);
+ let result = true;
+ if (this.notSelectors.length > 0 && (!this.listContext || !this.listContext.alreadyMatched)) {
+ const notMatcher = SelectorMatcher.createNotMatcher(this.notSelectors);
result = !notMatcher.match(cssSelector, null);
}
- if (result && isPresent(callback) &&
- (isBlank(this.listContext) || !this.listContext.alreadyMatched)) {
- if (isPresent(this.listContext)) {
+ if (result && callback && (!this.listContext || !this.listContext.alreadyMatched)) {
+ if (this.listContext) {
this.listContext.alreadyMatched = true;
}
callback(this.selector, this.cbContext);
diff --git a/modules/@angular/compiler/src/shadow_css.ts b/modules/@angular/compiler/src/shadow_css.ts
index 03ab00b165a7..ddc30555e30d 100644
--- a/modules/@angular/compiler/src/shadow_css.ts
+++ b/modules/@angular/compiler/src/shadow_css.ts
@@ -6,8 +6,6 @@
* 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.
*
@@ -175,9 +173,8 @@ export class ShadowCss {
**/
private _insertPolyfillDirectivesInCssText(cssText: string): string {
// Difference with webcomponents.js: does not handle comments
- return StringWrapper.replaceAllMapped(
- cssText, _cssContentNextSelectorRe,
- function(m: any /** TODO #9100 */) { return m[1] + '{'; });
+ return cssText.replace(
+ _cssContentNextSelectorRe, function(...m: string[]) { return m[2] + '{'; });
}
/*
@@ -197,13 +194,10 @@ export class ShadowCss {
**/
private _insertPolyfillRulesInCssText(cssText: string): string {
// Difference with webcomponents.js: does not handle comments
- return StringWrapper.replaceAllMapped(
- cssText, _cssContentRuleRe, function(m: any /** TODO #9100 */) {
- let rule = m[0];
- rule = StringWrapper.replace(rule, m[1], '');
- rule = StringWrapper.replace(rule, m[2], '');
- return m[3] + rule;
- });
+ return cssText.replace(_cssContentRuleRe, (...m: string[]) => {
+ const rule = m[0].replace(m[1], '').replace(m[2], '');
+ return m[4] + rule;
+ });
}
/* Ensure styles are scoped. Pseudo-scoping takes a rule like:
@@ -215,15 +209,16 @@ export class ShadowCss {
* scopeName .foo { ... }
*/
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._convertColonHost(cssText);
cssText = this._convertColonHostContext(cssText);
cssText = this._convertShadowDOMSelectors(cssText);
- if (isPresent(scopeSelector)) {
+ if (scopeSelector) {
cssText = this._scopeSelectors(cssText, scopeSelector, hostSelector);
}
- cssText = cssText + '\n' + unscoped;
+ cssText = cssText + '\n' + unscopedRules;
return cssText.trim();
}
@@ -248,9 +243,7 @@ export class ShadowCss {
let m: RegExpExecArray;
_cssContentUnscopedRuleRe.lastIndex = 0;
while ((m = _cssContentUnscopedRuleRe.exec(cssText)) !== null) {
- let rule = m[0];
- rule = StringWrapper.replace(rule, m[2], '');
- rule = StringWrapper.replace(rule, m[1], m[3]);
+ const rule = m[0].replace(m[2], '').replace(m[1], m[4]);
r += rule + '\n\n';
}
return r;
@@ -261,7 +254,7 @@ export class ShadowCss {
*
* to
*
- * scopeName.foo > .bar
+ * .foo > .bar
*/
private _convertColonHost(cssText: string): string {
return this._convertColonRule(cssText, _cssColonHostRe, this._colonHostPartReplacer);
@@ -272,7 +265,7 @@ export class ShadowCss {
*
* to
*
- * scopeName.foo > .bar, .foo scopeName > .bar { }
+ * .foo > .bar, .foo scopeName > .bar { }
*
* and
*
@@ -280,7 +273,7 @@ export class ShadowCss {
*
* to
*
- * scopeName.foo .bar { ... }
+ * .foo .bar { ... }
*/
private _convertColonHostContext(cssText: string): string {
return this._convertColonRule(
@@ -288,14 +281,14 @@ export class ShadowCss {
}
private _convertColonRule(cssText: string, regExp: RegExp, partReplacer: Function): string {
- // p1 = :host, p2 = contents of (), p3 rest of rule
- return StringWrapper.replaceAllMapped(cssText, regExp, function(m: any /** TODO #9100 */) {
- if (isPresent(m[2])) {
- const parts = m[2].split(','), r: any[] /** TODO #9100 */ = [];
+ // m[1] = :host(-context), m[2] = contents of (), m[3] rest of rule
+ return cssText.replace(regExp, function(...m: string[]) {
+ if (m[2]) {
+ const parts = m[2].split(',');
+ const r: string[] = [];
for (let i = 0; i < parts.length; i++) {
- let p = parts[i];
- if (isBlank(p)) break;
- p = p.trim();
+ let p = parts[i].trim();
+ if (!p) break;
r.push(partReplacer(_polyfillHostNoCombinator, p, m[3]));
}
return r.join(',');
@@ -306,7 +299,7 @@ export class ShadowCss {
}
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);
} else {
return host + part + suffix + ', ' + part + ' ' + host + suffix;
@@ -314,7 +307,7 @@ export class ShadowCss {
}
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.
*/
private _convertShadowDOMSelectors(cssText: string): string {
- return _shadowDOMSelectorsRe.reduce(
- (result, pattern) => { return StringWrapper.replaceAll(result, pattern, ' '); }, cssText);
+ return _shadowDOMSelectorsRe.reduce((result, pattern) => result.replace(pattern, ' '), cssText);
}
// change a selector like 'div' to 'name div'
@@ -331,10 +323,12 @@ export class ShadowCss {
return processRules(cssText, (rule: CssRule) => {
let selector = rule.selector;
let content = rule.content;
- if (rule.selector[0] != '@' || rule.selector.startsWith('@page')) {
+ if (rule.selector[0] != '@') {
selector =
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);
}
return new CssRule(selector, content);
@@ -369,8 +363,7 @@ export class ShadowCss {
private _makeScopeMatcher(scopeSelector: string): RegExp {
const lre = /\[/g;
const rre = /\]/g;
- scopeSelector = StringWrapper.replaceAll(scopeSelector, lre, '\\[');
- scopeSelector = StringWrapper.replaceAll(scopeSelector, rre, '\\]');
+ scopeSelector = scopeSelector.replace(lre, '\\[').replace(rre, '\\]');
return new RegExp('^(' + scopeSelector + ')' + _selectorReSuffix, 'm');
}
@@ -385,13 +378,14 @@ export class ShadowCss {
string {
// In Android browser, the lastIndex is not reset when the regex is used in String.replace()
_polyfillHostRe.lastIndex = 0;
+
if (_polyfillHostRe.test(selector)) {
const replaceBy = this.strictStyling ? `[${hostSelector}]` : scopeSelector;
- selector = StringWrapper.replace(selector, _polyfillHostNoCombinator, replaceBy);
- return StringWrapper.replaceAll(selector, _polyfillHostRe, replaceBy + ' ');
- } else {
- return scopeSelector + ' ' + selector;
+ return selector.replace(_polyfillHostNoCombinatorRe, (hnc, selector) => selector + replaceBy)
+ .replace(_polyfillHostRe, replaceBy + ' ');
}
+
+ return scopeSelector + ' ' + selector;
}
// return a selector with [name] suffix on each simple selector
@@ -404,9 +398,9 @@ export class ShadowCss {
const attrName = '[' + scopeSelector + ']';
const _scopeSelectorPart = (p: string) => {
- var scopedP = p.trim();
+ let scopedP = p.trim();
- if (scopedP.length == 0) {
+ if (!scopedP) {
return '';
}
@@ -426,12 +420,23 @@ export class ShadowCss {
return scopedP;
};
- const sep = /( |>|\+|~(?!=))\s*/g;
- const scopeAfter = selector.indexOf(_polyfillHostNoCombinator);
+ let attrSelectorIndex = 0;
+ 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 res: RegExpExecArray;
+ const sep = /( |>|\+|~(?!=))\s*/g;
+ const scopeAfter = selector.indexOf(_polyfillHostNoCombinator);
while ((res = sep.exec(selector)) !== null) {
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
// matches on ancestor elements and not on elements in the host's shadow
const scopedPart = startIndex >= scopeAfter ? _scopeSelectorPart(part) : part;
- scoped += `${scopedPart} ${separator} `;
+ scopedSelector += `${scopedPart} ${separator} `;
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 {
@@ -451,10 +460,10 @@ export class ShadowCss {
}
}
const _cssContentNextSelectorRe =
- /polyfill-next-selector[^}]*content:[\s]*?['"](.*?)['"][;\s]*}([^{]*?){/gim;
-const _cssContentRuleRe = /(polyfill-rule)[^}]*(content:[\s]*['"](.*?)['"])[;\s]*[^}]*}/gim;
+ /polyfill-next-selector[^}]*content:[\s]*?(['"])(.*?)\1[;\s]*}([^{]*?){/gim;
+const _cssContentRuleRe = /(polyfill-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim;
const _cssContentUnscopedRuleRe =
- /(polyfill-unscoped-rule)[^}]*(content:[\s]*['"](.*?)['"])[;\s]*[^}]*}/gim;
+ /(polyfill-unscoped-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim;
const _polyfillHost = '-shadowcsshost';
// note: :host-context pre-processed to -shadowcsshostcontext.
const _polyfillHostContext = '-shadowcsscontext';
@@ -464,6 +473,7 @@ const _parenSuffix = ')(?:\\((' +
const _cssColonHostRe = new RegExp('(' + _polyfillHost + _parenSuffix, 'gim');
const _cssColonHostContextRe = new RegExp('(' + _polyfillHostContext + _parenSuffix, 'gim');
const _polyfillHostNoCombinator = _polyfillHost + '-no-combinator';
+const _polyfillHostNoCombinatorRe = /-shadowcsshost-no-combinator([^\s]*)/;
const _shadowDOMSelectorsRe = [
/::shadow/g,
/::content/g,
@@ -480,7 +490,7 @@ const _colonHostContextRe = /:host-context/gim;
const _commentRe = /\/\*\s*[\s\S]*?\*\//g;
function stripComments(input: string): string {
- return StringWrapper.replaceAllMapped(input, _commentRe, (_: any /** TODO #9100 */) => '');
+ return input.replace(_commentRe, '');
}
// all comments except inline source mapping
@@ -501,23 +511,22 @@ export class CssRule {
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);
let nextBlockIndex = 0;
- return StringWrapper.replaceAllMapped(
- inputWithEscapedBlocks.escapedString, _ruleRe, function(m: any /** TODO #9100 */) {
- const selector = m[2];
- let content = '';
- let suffix = m[4];
- let contentPrefix = '';
- if (isPresent(m[4]) && m[4].startsWith('{' + BLOCK_PLACEHOLDER)) {
- content = inputWithEscapedBlocks.blocks[nextBlockIndex++];
- suffix = m[4].substring(BLOCK_PLACEHOLDER.length + 1);
- contentPrefix = '{';
- }
- const rule = ruleCallback(new CssRule(selector, content));
- return `${m[1]}${rule.selector}${m[3]}${contentPrefix}${rule.content}${suffix}`;
- });
+ return inputWithEscapedBlocks.escapedString.replace(_ruleRe, function(...m: string[]) {
+ const selector = m[2];
+ let content = '';
+ let suffix = m[4];
+ let contentPrefix = '';
+ if (suffix && suffix.startsWith('{' + BLOCK_PLACEHOLDER)) {
+ content = inputWithEscapedBlocks.blocks[nextBlockIndex++];
+ suffix = suffix.substring(BLOCK_PLACEHOLDER.length + 1);
+ contentPrefix = '{';
+ }
+ const rule = ruleCallback(new CssRule(selector, content));
+ return `${m[1]}${rule.selector}${m[3]}${contentPrefix}${rule.content}${suffix}`;
+ });
}
class StringWithEscapedBlocks {
@@ -525,11 +534,11 @@ class StringWithEscapedBlocks {
}
function escapeBlocks(input: string): StringWithEscapedBlocks {
- const inputParts = StringWrapper.split(input, _curlyRe);
- const resultParts: any[] /** TODO #9100 */ = [];
- const escapedBlocks: any[] /** TODO #9100 */ = [];
+ const inputParts = input.split(_curlyRe);
+ const resultParts: string[] = [];
+ const escapedBlocks: string[] = [];
let bracketCount = 0;
- let currentBlockParts: any[] /** TODO #9100 */ = [];
+ let currentBlockParts: string[] = [];
for (let partIndex = 0; partIndex < inputParts.length; partIndex++) {
const part = inputParts[partIndex];
if (part == CLOSE_CURLY) {
diff --git a/modules/@angular/compiler/src/template_parser/template_ast.ts b/modules/@angular/compiler/src/template_parser/template_ast.ts
index 11f57a0e43e8..d8d916e1739a 100644
--- a/modules/@angular/compiler/src/template_parser/template_ast.ts
+++ b/modules/@angular/compiler/src/template_parser/template_ast.ts
@@ -12,11 +12,8 @@ import {CompileDirectiveMetadata, CompileProviderMetadata, CompileTokenMetadata}
import {AST} from '../expression_parser/ast';
import {isPresent} from '../facade/lang';
import {ParseSourceSpan} from '../parse_util';
-
import {LifecycleHooks} from '../private_import_core';
-
-
/**
* 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 {
constructor(
@@ -71,14 +69,16 @@ export class BoundElementPropertyAst implements TemplateAst {
visit(visitor: TemplateAstVisitor, context: any): any {
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 {
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) {}
visit(visitor: TemplateAstVisitor, context: any): any {
return visitor.visitEvent(this, context);
@@ -90,6 +90,7 @@ export class BoundEventAst implements TemplateAst {
return this.name;
}
}
+ get isAnimation(): boolean { return !!this.phase; }
}
/**
diff --git a/modules/@angular/compiler/src/template_parser/template_parser.ts b/modules/@angular/compiler/src/template_parser/template_parser.ts
index 01fb272b1041..0f884f25e53c 100644
--- a/modules/@angular/compiler/src/template_parser/template_parser.ts
+++ b/modules/@angular/compiler/src/template_parser/template_parser.ts
@@ -8,11 +8,10 @@
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 {Parser} from '../expression_parser/parser';
-import {StringMapWrapper} from '../facade/collection';
-import {isBlank, isPresent, isString} from '../facade/lang';
+import {isPresent, isString} from '../facade/lang';
import {I18NHtmlParser} from '../i18n/i18n_html_parser';
import {Identifiers, identifierToken, resolveIdentifierToken} from '../identifiers';
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 {CssSelector, SelectorMatcher} from '../selector';
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 {PreparsedElementType, preparseElement} from './template_preparser';
+
// Group 1 = "bind-"
// Group 2 = "let-"
// Group 3 = "ref-/#"
@@ -142,7 +142,6 @@ export class TemplateParser {
const parseVisitor = new TemplateParseVisitor(
providerViewContext, uniqDirectives, uniqPipes, schemas, this._exprParser,
this._schemaRegistry);
-
result = html.visitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT);
errors.push(...parseVisitor.errors, ...providerViewContext.errors);
} else {
@@ -444,6 +443,15 @@ class TemplateParseVisitor implements html.Visitor {
providerContext.transformedDirectiveAsts, providerContext.transformProviders,
providerContext.transformedHasViewContainer, children,
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) {
@@ -469,9 +477,36 @@ class TemplateParseVisitor implements html.Visitor {
templateProviderContext.transformedHasViewContainer, [parsedElement], ngContentIndex,
element.sourceSpan);
}
+
return parsedElement;
}
+ private _validateElementAnimationInputOutputs(
+ inputs: BoundElementPropertyAst[], outputs: BoundEventAst[],
+ template: CompileTemplateMetadata) {
+ const triggerLookup = new Set();
+ 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(
attr: html.Attribute, targetMatchableAttrs: string[][],
targetProps: BoundElementOrDirectiveProperty[], targetVars: VariableAst[]): boolean {
@@ -533,7 +568,7 @@ class TemplateParseVisitor implements html.Visitor {
this._parseReference(identifier, value, srcSpan, targetRefs);
} else if (bindParts[KW_ON_IDX]) {
- this._parseEvent(
+ this._parseEventOrAnimationEvent(
bindParts[IDENT_KW_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
} else if (bindParts[KW_BINDON_IDX]) {
@@ -544,7 +579,7 @@ class TemplateParseVisitor implements html.Visitor {
bindParts[IDENT_KW_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
} else if (bindParts[KW_AT_IDX]) {
- if (name[0] == '@' && isPresent(value) && value.length > 0) {
+ if (_isAnimationLabel(name) && isPresent(value) && value.length > 0) {
this._reportError(
`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.`,
@@ -565,7 +600,7 @@ class TemplateParseVisitor implements html.Visitor {
targetAnimationProps);
} else if (bindParts[IDENT_EVENT_IDX]) {
- this._parseEvent(
+ this._parseEventOrAnimationEvent(
bindParts[IDENT_EVENT_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
}
} else {
@@ -608,7 +643,7 @@ class TemplateParseVisitor implements html.Visitor {
targetMatchableAttrs: string[][], targetProps: BoundElementOrDirectiveProperty[],
targetAnimationProps: BoundElementPropertyAst[]) {
const animatePropLength = ANIMATE_PROP_PREFIX.length;
- var isAnimationProp = name[0] == '@';
+ var isAnimationProp = _isAnimationLabel(name);
var animationPrefixLength = 1;
if (name.substring(0, animatePropLength) == ANIMATE_PROP_PREFIX) {
isAnimationProp = true;
@@ -635,6 +670,7 @@ class TemplateParseVisitor implements html.Visitor {
if (!isPresent(expression) || expression.length == 0) {
expression = 'null';
}
+
const ast = this._parseBinding(expression, sourceSpan);
targetMatchableAttrs.push([name, ast.source]);
targetAnimationProps.push(new BoundElementPropertyAst(
@@ -662,20 +698,56 @@ class TemplateParseVisitor implements html.Visitor {
private _parseAssignmentEvent(
name: string, expression: string, sourceSpan: ParseSourceSpan,
targetMatchableAttrs: string[][], targetEvents: BoundEventAst[]) {
- this._parseEvent(
+ this._parseEventOrAnimationEvent(
`${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(
name: string, expression: string, sourceSpan: ParseSourceSpan,
targetMatchableAttrs: string[][], targetEvents: BoundEventAst[]) {
// long format: 'target: eventName'
- const parts = splitAtColon(name, [null, name]);
- const target = parts[0];
- const eventName = parts[1];
+ const [target, eventName] = splitAtColon(name, [null, name]);
const ast = this._parseAction(expression, sourceSpan);
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,
// 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,
targetPropertyAsts: BoundElementPropertyAst[]) {
if (hostProps) {
- StringMapWrapper.forEach(hostProps, (expression: string, propName: string) => {
+ Object.keys(hostProps).forEach(propName => {
+ const expression = hostProps[propName];
if (isString(expression)) {
const exprAst = this._parseBinding(expression, sourceSpan);
targetPropertyAsts.push(
@@ -777,9 +850,10 @@ class TemplateParseVisitor implements html.Visitor {
hostListeners: {[key: string]: string}, sourceSpan: ParseSourceSpan,
targetEventAsts: BoundEventAst[]) {
if (hostListeners) {
- StringMapWrapper.forEach(hostListeners, (expression: string, propName: string) => {
+ Object.keys(hostListeners).forEach(propName => {
+ const expression = hostListeners[propName];
if (isString(expression)) {
- this._parseEvent(propName, expression, sourceSpan, [], targetEventAsts);
+ this._parseEventOrAnimationEvent(propName, expression, sourceSpan, [], targetEventAsts);
} else {
this._reportError(
`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();
boundProps.forEach(boundProp => {
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
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);
// 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) => {
- if (!prop.isLiteral && isBlank(boundDirectivePropsIndex.get(prop.name))) {
+ if (!prop.isLiteral && !boundDirectivePropsIndex.get(prop.name)) {
boundElementProps.push(this._createElementPropertyAst(
elementName, prop.name, prop.expression, prop.sourceSpan));
}
@@ -846,7 +921,7 @@ class TemplateParseVisitor implements html.Visitor {
if (parts.length === 1) {
var partValue = parts[0];
- if (partValue[0] == '@') {
+ if (_isAnimationLabel(partValue)) {
boundPropertyName = partValue.substr(1);
bindingType = PropertyBindingType.Animation;
securityContext = SecurityContext.NONE;
@@ -854,7 +929,7 @@ class TemplateParseVisitor implements html.Visitor {
boundPropertyName = this._schemaRegistry.getMappedPropName(partValue);
securityContext = this._schemaRegistry.securityContext(elementName, boundPropertyName);
bindingType = PropertyBindingType.Property;
- this._assertNoEventBinding(boundPropertyName, sourceSpan);
+ this._validatePropertyOrAttributeName(boundPropertyName, sourceSpan, false);
if (!this._schemaRegistry.hasProperty(elementName, boundPropertyName, this._schemas)) {
let errorMsg =
`Can't bind to '${boundPropertyName}' since it isn't a known property of '${elementName}'.`;
@@ -869,7 +944,7 @@ class TemplateParseVisitor implements html.Visitor {
} else {
if (parts[0] == ATTRIBUTE_PREFIX) {
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.
const mapPropName = this._schemaRegistry.getMappedPropName(boundPropertyName);
securityContext = this._schemaRegistry.securityContext(elementName, mapPropName);
@@ -902,24 +977,29 @@ class TemplateParseVisitor implements html.Visitor {
boundPropertyName, bindingType, securityContext, ast, unit, sourceSpan);
}
- private _assertNoEventBinding(propName: string, sourceSpan: ParseSourceSpan): void {
- if (propName.toLowerCase().startsWith('on')) {
- this._reportError(
- `Binding to event attribute '${propName}' is disallowed ` +
- `for security reasons, please use (${propName.slice(2)})=...`,
- sourceSpan, ParseErrorLevel.FATAL);
+
+ /**
+ * @param propName the name of the property / attribute
+ * @param sourceSpan
+ * @param isAttr true when binding to an attribute
+ * @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 _findComponentDirectives(directives: DirectiveAst[]): DirectiveAst[] {
+ return directives.filter(directive => directive.directive.isComponent);
+ }
+
private _findComponentDirectiveNames(directives: DirectiveAst[]): string[] {
- const componentTypeNames: string[] = [];
- directives.forEach(directive => {
- const typeName = directive.directive.type.name;
- if (directive.directive.isComponent) {
- componentTypeNames.push(typeName);
- }
- });
- return componentTypeNames;
+ return this._findComponentDirectives(directives)
+ .map(directive => directive.directive.type.name);
}
private _assertOnlyOneComponent(directives: DirectiveAst[], sourceSpan: ParseSourceSpan) {
@@ -969,7 +1049,8 @@ class TemplateParseVisitor implements html.Visitor {
const allDirectiveEvents = new Set();
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);
});
});
@@ -1103,3 +1184,7 @@ export class PipeCollector extends RecursiveAstVisitor {
return null;
}
}
+
+function _isAnimationLabel(name: string): boolean {
+ return name[0] == '@';
+}
diff --git a/modules/@angular/compiler/src/util.ts b/modules/@angular/compiler/src/util.ts
index fd8cf945f3d1..0cc67890327e 100644
--- a/modules/@angular/compiler/src/util.ts
+++ b/modules/@angular/compiler/src/util.ts
@@ -7,7 +7,6 @@
*/
import {CompileTokenMetadata} from './compile_metadata';
-import {StringMapWrapper} from './facade/collection';
import {StringWrapper, isArray, isBlank, isPresent, isPrimitive, isStrictStringMap} from './facade/lang';
import * as o from './output/output_ast';
@@ -17,13 +16,21 @@ var CAMEL_CASE_REGEXP = /([A-Z])/g;
export function camelCaseToDashCase(input: string): string {
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[] {
- const colonIndex = input.indexOf(':');
- if (colonIndex == -1) return defaultValues;
- return [input.slice(0, colonIndex).trim(), input.slice(colonIndex + 1).trim()];
+ return _splitAt(input, ':', defaultValues);
+}
+
+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 {
@@ -55,9 +62,8 @@ export class ValueTransformer implements ValueVisitor {
}
visitStringMap(map: {[key: string]: any}, context: any): any {
var result = {};
- StringMapWrapper.forEach(map, (value: any /** TODO #9100 */, key: any /** TODO #9100 */) => {
- (result as any /** TODO #9100 */)[key] = visitValue(value, this, context);
- });
+ Object.keys(map).forEach(
+ key => { (result as any /** TODO #9100 */)[key] = visitValue(map[key], this, context); });
return result;
}
visitPrimitive(value: any, context: any): any { return value; }
diff --git a/modules/@angular/compiler/src/view_compiler/compile_element.ts b/modules/@angular/compiler/src/view_compiler/compile_element.ts
index f394d68dd9ad..8986330e89f3 100644
--- a/modules/@angular/compiler/src/view_compiler/compile_element.ts
+++ b/modules/@angular/compiler/src/view_compiler/compile_element.ts
@@ -8,8 +8,8 @@
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileIdentifierMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata} from '../compile_metadata';
-import {ListWrapper, MapWrapper, StringMapWrapper} from '../facade/collection';
-import {isBlank, isPresent} from '../facade/lang';
+import {ListWrapper, MapWrapper} from '../facade/collection';
+import {isPresent} from '../facade/lang';
import {Identifiers, identifierToken, resolveIdentifier, resolveIdentifierToken} from '../identifiers';
import * as o from '../output/output_ast';
import {convertValueToOutputAst} from '../output/value_util';
@@ -27,7 +27,7 @@ export class CompileNode {
public parent: CompileElement, public view: CompileView, public nodeIndex: number,
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; }
}
@@ -117,7 +117,7 @@ export class CompileElement extends CompileNode {
setComponentView(compViewExpr: o.Expression) {
this._compViewExpr = compViewExpr;
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++) {
this.contentNodesByNgContentIndex[i] = [];
}
@@ -192,7 +192,7 @@ export class CompileElement extends CompileNode {
queriesWithReads,
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 varValue: o.Expression;
if (isPresent(token)) {
@@ -313,12 +313,12 @@ export class CompileElement extends CompileNode {
requestingProviderType: ProviderAstType, dep: CompileDiDependencyMetadata): o.Expression {
var result: o.Expression = null;
// constructor content query
- if (isBlank(result) && isPresent(dep.query)) {
+ if (!result && isPresent(dep.query)) {
result = this._addQuery(dep.query, null).queryList;
}
// constructor view query
- if (isBlank(result) && isPresent(dep.viewQuery)) {
+ if (!result && isPresent(dep.viewQuery)) {
result = createQueryList(
dep.viewQuery, null,
`_viewQuery_${dep.viewQuery.selectors[0].name}_${this.nodeIndex}_${this._componentConstructorViewQueryLists.length}`,
@@ -328,7 +328,7 @@ export class CompileElement extends CompileNode {
if (isPresent(dep.token)) {
// access builtins with special visibility
- if (isBlank(result)) {
+ if (!result) {
if (dep.token.reference ===
resolveIdentifierToken(Identifiers.ChangeDetectorRef).reference) {
if (requestingProviderType === ProviderAstType.Component) {
@@ -339,7 +339,7 @@ export class CompileElement extends CompileNode {
}
}
// access regular providers on the element
- if (isBlank(result)) {
+ if (!result) {
let resolvedProvider = this._resolvedProviders.get(dep.token.reference);
// don't allow directives / public services to access private services.
// only components and private services can access private services.
@@ -361,20 +361,20 @@ export class CompileElement extends CompileNode {
if (dep.isValue) {
result = o.literal(dep.value);
}
- if (isBlank(result) && !dep.isSkipSelf) {
+ if (!result && !dep.isSkipSelf) {
result = this._getLocalDependency(requestingProviderType, dep);
}
// check parent elements
- while (isBlank(result) && !currElement.parent.isNull()) {
+ while (!result && !currElement.parent.isNull()) {
currElement = currElement.parent;
result = currElement._getLocalDependency(
ProviderAstType.PublicService, new CompileDiDependencyMetadata({token: dep.token}));
}
- if (isBlank(result)) {
+ if (!result) {
result = injectFromViewParentInjector(dep.token, dep.isOptional);
}
- if (isBlank(result)) {
+ if (!result) {
result = o.NULL_EXPR;
}
return getPropertyInView(result, this.view, currElement.view);
@@ -411,7 +411,7 @@ function createProviderProperty(
resolvedProviderValueExpr = providerValueExpressions[0];
type = providerValueExpressions[0].type;
}
- if (isBlank(type)) {
+ if (!type) {
type = o.DYNAMIC_TYPE;
}
if (isEager) {
diff --git a/modules/@angular/compiler/src/view_compiler/compile_pipe.ts b/modules/@angular/compiler/src/view_compiler/compile_pipe.ts
index 56ba18b9398d..ff5a02983f95 100644
--- a/modules/@angular/compiler/src/view_compiler/compile_pipe.ts
+++ b/modules/@angular/compiler/src/view_compiler/compile_pipe.ts
@@ -8,8 +8,7 @@
import {CompilePipeMetadata} from '../compile_metadata';
-import {isBlank, 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 {CompileView} from './compile_view';
@@ -23,7 +22,7 @@ export class CompilePipe {
if (meta.pure) {
// pure pipes live on the component view
pipe = compView.purePipes.get(name);
- if (isBlank(pipe)) {
+ if (!pipe) {
pipe = new CompilePipe(compView, meta);
compView.purePipes.set(name, pipe);
compView.pipes.push(pipe);
@@ -85,7 +84,7 @@ function _findPipeMeta(view: CompileView, name: string): CompilePipeMetadata {
break;
}
}
- if (isBlank(pipeMeta)) {
+ if (!pipeMeta) {
throw new Error(
`Illegal state: Could not find pipe ${name} although the parser should have detected this error!`);
}
diff --git a/modules/@angular/compiler/src/view_compiler/compile_query.ts b/modules/@angular/compiler/src/view_compiler/compile_query.ts
index 1069455bfa1d..ab7b71e77c3e 100644
--- a/modules/@angular/compiler/src/view_compiler/compile_query.ts
+++ b/modules/@angular/compiler/src/view_compiler/compile_query.ts
@@ -6,9 +6,9 @@
* 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 {isBlank, isPresent} from '../facade/lang';
+import {isPresent} from '../facade/lang';
import {Identifiers, resolveIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
@@ -101,9 +101,8 @@ function createQueryValues(viewValues: ViewQueryValues): o.Expression[] {
function mapNestedViews(
declarationAppElement: o.Expression, view: CompileView,
expressions: o.Expression[]): o.Expression {
- var adjustedExpressions: o.Expression[] = expressions.map((expr) => {
- return o.replaceVarInExpression(o.THIS_EXPR.name, o.variable('nestedView'), expr);
- });
+ var adjustedExpressions: o.Expression[] = expressions.map(
+ (expr) => o.replaceVarInExpression(o.THIS_EXPR.name, o.variable('nestedView'), expr));
return declarationAppElement.callMethod('mapNestedViews', [
o.variable(view.className),
o.fn(
@@ -129,7 +128,7 @@ export function createQueryList(
export function addQueryToTokenMap(map: Map, query: CompileQuery) {
query.meta.selectors.forEach((selector) => {
var entry = map.get(selector.reference);
- if (isBlank(entry)) {
+ if (!entry) {
entry = [];
map.set(selector.reference, entry);
}
diff --git a/modules/@angular/compiler/src/view_compiler/compile_view.ts b/modules/@angular/compiler/src/view_compiler/compile_view.ts
index 9f78ba78b53d..eab5c45bf331 100644
--- a/modules/@angular/compiler/src/view_compiler/compile_view.ts
+++ b/modules/@angular/compiler/src/view_compiler/compile_view.ts
@@ -6,15 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {CompiledAnimationTriggerResult} from '../animation/animation_compiler';
-import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeMetadata, CompileTokenMetadata} from '../compile_metadata';
+import {AnimationEntryCompileResult} from '../animation/animation_compiler';
+import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeMetadata} from '../compile_metadata';
import {CompilerConfig} from '../config';
import {ListWrapper, MapWrapper} from '../facade/collection';
-import {isBlank, isPresent} from '../facade/lang';
+import {isPresent} from '../facade/lang';
import {Identifiers, resolveIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {ViewType} from '../private_import_core';
-import {createDiTokenExpression} from '../util';
import {CompileBinding} from './compile_binding';
import {CompileElement, CompileNode} from './compile_element';
@@ -23,7 +22,7 @@ import {CompilePipe} from './compile_pipe';
import {CompileQuery, addQueryToTokenMap, createQueryList} from './compile_query';
import {EventHandlerVars} from './constants';
import {NameResolver} from './expression_converter';
-import {createPureProxy, getPropertyInView, getViewFactoryName, injectFromViewParentInjector} from './util';
+import {createPureProxy, getPropertyInView, getViewFactoryName} from './util';
export class CompileView implements NameResolver {
public viewType: ViewType;
@@ -72,7 +71,7 @@ export class CompileView implements NameResolver {
constructor(
public component: CompileDirectiveMetadata, public genConfig: CompilerConfig,
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[][]) {
this.createMethod = new CompileMethod(this);
this.animationBindingsMethod = new CompileMethod(this);
@@ -139,7 +138,7 @@ export class CompileView implements NameResolver {
}
var currView: CompileView = this;
var result = currView.locals.get(name);
- while (isBlank(result) && isPresent(currView.declarationElement.view)) {
+ while (!result && isPresent(currView.declarationElement.view)) {
currView = currView.declarationElement.view;
result = currView.locals.get(name);
}
diff --git a/modules/@angular/compiler/src/view_compiler/constants.ts b/modules/@angular/compiler/src/view_compiler/constants.ts
index b6dc075f147f..f97a4ff565e4 100644
--- a/modules/@angular/compiler/src/view_compiler/constants.ts
+++ b/modules/@angular/compiler/src/view_compiler/constants.ts
@@ -9,7 +9,6 @@
import {ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core';
import {CompileIdentifierMetadata} from '../compile_metadata';
-import {isBlank} from '../facade/lang';
import {Identifiers, resolveEnumIdentifier, resolveIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
diff --git a/modules/@angular/compiler/src/view_compiler/event_binder.ts b/modules/@angular/compiler/src/view_compiler/event_binder.ts
index 947e6241f447..504923a7dff1 100644
--- a/modules/@angular/compiler/src/view_compiler/event_binder.ts
+++ b/modules/@angular/compiler/src/view_compiler/event_binder.ts
@@ -7,11 +7,9 @@
*/
import {CompileDirectiveMetadata} from '../compile_metadata';
-import {ListWrapper, StringMapWrapper} from '../facade/collection';
-import {StringWrapper, isBlank, isPresent} from '../facade/lang';
-import {Identifiers, identifierToken, resolveIdentifier} from '../identifiers';
+import {StringWrapper, isPresent} from '../facade/lang';
+import {identifierToken} from '../identifiers';
import * as o from '../output/output_ast';
-import {AnimationOutput} from '../private_import_core';
import {BoundEventAst, DirectiveAst} from '../template_parser/template_ast';
import {CompileBinding} from './compile_binding';
@@ -20,10 +18,6 @@ import {CompileMethod} from './compile_method';
import {EventHandlerVars, ViewProperties} from './constants';
import {convertCdStatementToIr} from './expression_converter';
-export class CompileElementAnimationOutput {
- constructor(public listener: CompileEventListener, public output: AnimationOutput) {}
-}
-
export class CompileEventListener {
private _method: CompileMethod;
private _hasComponentHostListener: boolean = false;
@@ -32,13 +26,14 @@ export class CompileEventListener {
private _actionResultExprs: o.Expression[] = [];
static getOrCreate(
- compileElement: CompileElement, eventTarget: string, eventName: string,
+ compileElement: CompileElement, eventTarget: string, eventName: string, eventPhase: string,
targetEventListeners: CompileEventListener[]): CompileEventListener {
var listener = targetEventListeners.find(
- listener => listener.eventTarget == eventTarget && listener.eventName == eventName);
- if (isBlank(listener)) {
+ listener => listener.eventTarget == eventTarget && listener.eventName == eventName &&
+ listener.eventPhase == eventPhase);
+ if (!listener) {
listener = new CompileEventListener(
- compileElement, eventTarget, eventName, targetEventListeners.length);
+ compileElement, eventTarget, eventName, eventPhase, targetEventListeners.length);
targetEventListeners.push(listener);
}
return listener;
@@ -48,7 +43,7 @@ export class CompileEventListener {
constructor(
public compileElement: CompileElement, public eventTarget: string, public eventName: string,
- listenerIndex: number) {
+ public eventPhase: string, listenerIndex: number) {
this._method = new CompileMethod(compileElement.view);
this._methodName =
`_handle_${santitizeEventName(eventName)}_${compileElement.nodeIndex}_${listenerIndex}`;
@@ -119,7 +114,7 @@ export class CompileEventListener {
disposable.set(listenExpr).toDeclStmt(o.FUNCTION_TYPE, [o.StmtModifier.Private]));
}
- listenToAnimation(output: AnimationOutput) {
+ listenToAnimation() {
var outputListener = o.THIS_EXPR.callMethod(
'eventHandler',
[o.THIS_EXPR.prop(this._methodName).callMethod(o.BuiltinMethod.Bind, [o.THIS_EXPR])]);
@@ -129,11 +124,8 @@ export class CompileEventListener {
.callMethod(
'registerAnimationOutput',
[
- this.compileElement.renderNode,
- o.importExpr(resolveIdentifier(Identifiers.AnimationOutput)).instantiate([
- o.literal(output.name), o.literal(output.phase)
- ]),
- outputListener
+ this.compileElement.renderNode, o.literal(this.eventName),
+ o.literal(this.eventPhase), outputListener
])
.toStmt();
this.compileElement.view.createMethod.addStmt(stmt);
@@ -160,7 +152,7 @@ export function collectEventListeners(
hostEvents.forEach((hostEvent) => {
compileElement.view.bindings.push(new CompileBinding(compileElement, hostEvent));
var listener = CompileEventListener.getOrCreate(
- compileElement, hostEvent.target, hostEvent.name, eventListeners);
+ compileElement, hostEvent.target, hostEvent.name, hostEvent.phase, eventListeners);
listener.addAction(hostEvent, null, null);
});
dirs.forEach((directiveAst) => {
@@ -169,7 +161,7 @@ export function collectEventListeners(
directiveAst.hostEvents.forEach((hostEvent) => {
compileElement.view.bindings.push(new CompileBinding(compileElement, hostEvent));
var listener = CompileEventListener.getOrCreate(
- compileElement, hostEvent.target, hostEvent.name, eventListeners);
+ compileElement, hostEvent.target, hostEvent.name, hostEvent.phase, eventListeners);
listener.addAction(hostEvent, directiveAst.directive, directiveInstance);
});
});
@@ -180,21 +172,22 @@ export function collectEventListeners(
export function bindDirectiveOutputs(
directiveAst: DirectiveAst, directiveInstance: o.Expression,
eventListeners: CompileEventListener[]) {
- StringMapWrapper.forEach(
- directiveAst.directive.outputs,
- (eventName: any /** TODO #9100 */, observablePropName: any /** TODO #9100 */) => {
- eventListeners.filter(listener => listener.eventName == eventName).forEach((listener) => {
- listener.listenToDirective(directiveInstance, observablePropName);
- });
- });
+ Object.keys(directiveAst.directive.outputs).forEach(observablePropName => {
+ const eventName = directiveAst.directive.outputs[observablePropName];
+ eventListeners.filter(listener => listener.eventName == eventName).forEach((listener) => {
+ listener.listenToDirective(directiveInstance, observablePropName);
+ });
+ });
}
export function bindRenderOutputs(eventListeners: CompileEventListener[]) {
- eventListeners.forEach(listener => listener.listenToRenderer());
-}
-
-export function bindAnimationOutputs(eventListeners: CompileElementAnimationOutput[]) {
- eventListeners.forEach(entry => { entry.listener.listenToAnimation(entry.output); });
+ eventListeners.forEach(listener => {
+ if (listener.eventPhase) {
+ listener.listenToAnimation();
+ } else {
+ listener.listenToRenderer();
+ }
+ });
}
function convertStmtIntoExpression(stmt: o.Statement): o.Expression {
diff --git a/modules/@angular/compiler/src/view_compiler/expression_converter.ts b/modules/@angular/compiler/src/view_compiler/expression_converter.ts
index fd44f95452ed..5fc635c58cc6 100644
--- a/modules/@angular/compiler/src/view_compiler/expression_converter.ts
+++ b/modules/@angular/compiler/src/view_compiler/expression_converter.ts
@@ -340,7 +340,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
// Notice that the first guard condition is the left hand of the left most safe access node
// which comes in as leftMostSafe to this routine.
- let guardedExpression = this.visit(leftMostSafe.receiver, mode);
+ let guardedExpression = this.visit(leftMostSafe.receiver, _Mode.Expression);
let temporary: o.ReadVarExpr;
if (this.needsTemporary(leftMostSafe.receiver)) {
// If the expression has method calls or pipes then we need to save the result into a
@@ -369,7 +369,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
}
// Recursively convert the node now without the guarded member access.
- const access = this.visit(ast, mode);
+ const access = this.visit(ast, _Mode.Expression);
// Remove the mapping. This is not strictly required as the converter only traverses each node
// once but is safer if the conversion is changed to traverse the nodes more than once.
@@ -381,7 +381,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
}
// Produce the conditional
- return condition.conditional(o.literal(null), access);
+ return convertToStatementIfNeeded(mode, condition.conditional(o.literal(null), access));
}
// Given a expression of the form a?.b.c?.d.e the the left most safe node is
diff --git a/modules/@angular/compiler/src/view_compiler/property_binder.ts b/modules/@angular/compiler/src/view_compiler/property_binder.ts
index 026efece67f4..192ec98db2d2 100644
--- a/modules/@angular/compiler/src/view_compiler/property_binder.ts
+++ b/modules/@angular/compiler/src/view_compiler/property_binder.ts
@@ -9,7 +9,7 @@
import {SecurityContext} from '@angular/core';
import * as cdAst from '../expression_parser/ast';
-import {isBlank, isPresent} from '../facade/lang';
+import {isPresent} from '../facade/lang';
import {Identifiers, resolveIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {EMPTY_STATE as EMPTY_ANIMATION_STATE, LifecycleHooks, isDefaultChangeDetectionStrategy} from '../private_import_core';
@@ -31,15 +31,13 @@ function createCurrValueExpr(exprIndex: number): o.ReadVarExpr {
return o.variable(`currVal_${exprIndex}`); // fix syntax highlighting: `
}
-const _animationViewCheckedFlagMap = new Map();
-
function bind(
view: CompileView, currValExpr: o.ReadVarExpr, fieldExpr: o.ReadPropExpr,
parsedExpression: cdAst.AST, context: o.Expression, actions: o.Statement[],
method: CompileMethod, bindingIndex: number) {
var checkExpression = convertCdExpressionToIr(
view, context, parsedExpression, DetectChangesVars.valUnwrapper, bindingIndex);
- if (isBlank(checkExpression.expression)) {
+ if (!checkExpression.expression) {
// e.g. an empty expression was given
return;
}
diff --git a/modules/@angular/compiler/src/view_compiler/util.ts b/modules/@angular/compiler/src/view_compiler/util.ts
index cb422b6e949a..59b66bf26d46 100644
--- a/modules/@angular/compiler/src/view_compiler/util.ts
+++ b/modules/@angular/compiler/src/view_compiler/util.ts
@@ -8,7 +8,7 @@
import {CompileDirectiveMetadata, CompileTokenMetadata} from '../compile_metadata';
-import {isBlank, isPresent} from '../facade/lang';
+import {isPresent} from '../facade/lang';
import {Identifiers, resolveIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {createDiTokenExpression} from '../util';
@@ -84,7 +84,7 @@ export function createPureProxy(
view.fields.push(new o.ClassField(pureProxyProp.name, null));
var pureProxyId =
argCount < Identifiers.pureProxies.length ? Identifiers.pureProxies[argCount] : null;
- if (isBlank(pureProxyId)) {
+ if (!pureProxyId) {
throw new Error(`Unsupported number of argument for pure functions: ${argCount}`);
}
view.createMethod.addStmt(o.THIS_EXPR.prop(pureProxyProp.name)
diff --git a/modules/@angular/compiler/src/view_compiler/view_binder.ts b/modules/@angular/compiler/src/view_compiler/view_binder.ts
index 403e6cfe514c..5c81bbef54f1 100644
--- a/modules/@angular/compiler/src/view_compiler/view_binder.ts
+++ b/modules/@angular/compiler/src/view_compiler/view_binder.ts
@@ -5,20 +5,17 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
-import {ListWrapper} from '../facade/collection';
-import {identifierToken} from '../identifiers';
-import {AnimationOutput} from '../private_import_core';
+
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
-import {CompileElement, CompileNode} from './compile_element';
+import {CompileElement} from './compile_element';
import {CompileView} from './compile_view';
-import {CompileElementAnimationOutput, CompileEventListener, bindAnimationOutputs, bindDirectiveOutputs, bindRenderOutputs, collectEventListeners} from './event_binder';
+import {CompileEventListener, bindDirectiveOutputs, bindRenderOutputs, collectEventListeners} from './event_binder';
import {bindDirectiveAfterContentLifecycleCallbacks, bindDirectiveAfterViewLifecycleCallbacks, bindDirectiveDetectChangesLifecycleCallbacks, bindInjectableDestroyLifecycleCallbacks, bindPipeDestroyLifecycleCallbacks} from './lifecycle_binder';
import {bindDirectiveHostProps, bindDirectiveInputs, bindRenderInputs, bindRenderText} from './property_binder';
-export function bindView(
- view: CompileView, parsedTemplate: TemplateAst[], animationOutputs: AnimationOutput[]): void {
- var visitor = new ViewBinderVisitor(view, animationOutputs);
+export function bindView(view: CompileView, parsedTemplate: TemplateAst[]): void {
+ var visitor = new ViewBinderVisitor(view);
templateVisitAll(visitor, parsedTemplate);
view.pipes.forEach(
(pipe) => { bindPipeDestroyLifecycleCallbacks(pipe.meta, pipe.instance, pipe.view); });
@@ -26,12 +23,8 @@ export function bindView(
class ViewBinderVisitor implements TemplateAstVisitor {
private _nodeIndex: number = 0;
- private _animationOutputsMap: {[key: string]: AnimationOutput} = {};
- constructor(public view: CompileView, public animationOutputs: AnimationOutput[]) {
- animationOutputs.forEach(
- entry => { this._animationOutputsMap[entry.fullPropertyName] = entry; });
- }
+ constructor(public view: CompileView) {}
visitBoundText(ast: BoundTextAst, parent: CompileElement): any {
var node = this.view.nodes[this._nodeIndex++];
@@ -48,22 +41,9 @@ class ViewBinderVisitor implements TemplateAstVisitor {
visitElement(ast: ElementAst, parent: CompileElement): any {
var compileElement = this.view.nodes[this._nodeIndex++];
var eventListeners: CompileEventListener[] = [];
- var animationEventListeners: CompileElementAnimationOutput[] = [];
collectEventListeners(ast.outputs, ast.directives, compileElement).forEach(entry => {
- // TODO: figure out how to abstract this `if` statement elsewhere
- if (entry.eventName[0] == '@') {
- let animationOutputName = entry.eventName.substr(1);
- let output = this._animationOutputsMap[animationOutputName];
- // no need to report an error here since the parser will
- // have caught the missing animation trigger definition
- if (output) {
- animationEventListeners.push(new CompileElementAnimationOutput(entry, output));
- }
- } else {
- eventListeners.push(entry);
- }
+ eventListeners.push(entry);
});
- bindAnimationOutputs(animationEventListeners);
bindRenderInputs(ast.inputs, compileElement);
bindRenderOutputs(eventListeners);
ast.directives.forEach((directiveAst) => {
@@ -108,7 +88,7 @@ class ViewBinderVisitor implements TemplateAstVisitor {
var providerInstance = compileElement.instances.get(providerAst.token.reference);
bindInjectableDestroyLifecycleCallbacks(providerAst, providerInstance, compileElement);
});
- bindView(compileElement.embeddedView, ast.children, this.animationOutputs);
+ bindView(compileElement.embeddedView, ast.children);
return null;
}
diff --git a/modules/@angular/compiler/src/view_compiler/view_builder.ts b/modules/@angular/compiler/src/view_compiler/view_builder.ts
index ace3e903cb34..4fdb24f7d10d 100644
--- a/modules/@angular/compiler/src/view_compiler/view_builder.ts
+++ b/modules/@angular/compiler/src/view_compiler/view_builder.ts
@@ -6,16 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core';
+import {ViewEncapsulation} from '@angular/core';
-import {AnimationCompiler} from '../animation/animation_compiler';
-import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileTokenMetadata, CompileTypeMetadata} from '../compile_metadata';
-import {ListWrapper, SetWrapper, StringMapWrapper} from '../facade/collection';
+import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileTokenMetadata} from '../compile_metadata';
+import {ListWrapper} from '../facade/collection';
import {StringWrapper, isPresent} from '../facade/lang';
-import {Identifiers, identifierToken, resolveIdentifier, resolveIdentifierToken} from '../identifiers';
+import {Identifiers, identifierToken, resolveIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {ChangeDetectorStatus, ViewType, isDefaultChangeDetectionStrategy} from '../private_import_core';
-import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ProviderAst, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
+import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
import {createDiTokenExpression} from '../util';
import {CompileElement, CompileNode} from './compile_element';
@@ -65,8 +64,6 @@ export function finishView(view: CompileView, targetStatements: o.Statement[]) {
class ViewBuilderVisitor implements TemplateAstVisitor {
nestedViewCount: number = 0;
- private _animationCompiler = new AnimationCompiler();
-
constructor(
public view: CompileView,
public targetDependencies: Array) {}
@@ -279,12 +276,10 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
ast.hasViewContainer, true, ast.references);
this.view.nodes.push(compileElement);
- var compiledAnimations = this._animationCompiler.compileComponent(this.view.component, [ast]);
-
this.nestedViewCount++;
var embeddedView = new CompileView(
this.view.component, this.view.genConfig, this.view.pipeMetas, o.NULL_EXPR,
- compiledAnimations.triggers, this.view.viewIndex + this.nestedViewCount, compileElement,
+ this.view.animations, this.view.viewIndex + this.nestedViewCount, compileElement,
templateVariableBindings);
this.nestedViewCount += buildView(embeddedView, ast.children, this.targetDependencies);
@@ -351,10 +346,10 @@ function _mergeHtmlAndDirectiveAttrs(
declaredHtmlAttrs: {[key: string]: string},
directives: CompileDirectiveMetadata[]): string[][] {
var result: {[key: string]: string} = {};
- StringMapWrapper.forEach(
- declaredHtmlAttrs, (value: string, key: string) => { result[key] = value; });
+ Object.keys(declaredHtmlAttrs).forEach(key => { result[key] = declaredHtmlAttrs[key]; });
directives.forEach(directiveMeta => {
- StringMapWrapper.forEach(directiveMeta.hostAttributes, (value: string, name: string) => {
+ Object.keys(directiveMeta.hostAttributes).forEach(name => {
+ const value = directiveMeta.hostAttributes[name];
var prevValue = result[name];
result[name] = isPresent(prevValue) ? mergeAttributeValue(name, prevValue, value) : value;
});
@@ -378,9 +373,7 @@ function mergeAttributeValue(attrName: string, attrValue1: string, attrValue2: s
function mapToKeyValueArray(data: {[key: string]: string}): string[][] {
var entryArray: string[][] = [];
- StringMapWrapper.forEach(data, (value: string, name: string) => {
- entryArray.push([name, value]);
- });
+ Object.keys(data).forEach(name => { entryArray.push([name, data[name]]); });
// We need to sort to get a defined output order
// for tests and for caching generated artifacts...
ListWrapper.sort(entryArray, (entry1, entry2) => StringWrapper.compare(entry1[0], entry2[0]));
@@ -426,11 +419,11 @@ function createStaticNodeDebugInfo(node: CompileNode): o.Expression {
if (isPresent(compileElement.component)) {
componentToken = createDiTokenExpression(identifierToken(compileElement.component.type));
}
- StringMapWrapper.forEach(
- compileElement.referenceTokens, (token: CompileTokenMetadata, varName: string) => {
- varTokenEntries.push(
- [varName, isPresent(token) ? createDiTokenExpression(token) : o.NULL_EXPR]);
- });
+ Object.keys(compileElement.referenceTokens).forEach(varName => {
+ const token = compileElement.referenceTokens[varName];
+ varTokenEntries.push(
+ [varName, isPresent(token) ? createDiTokenExpression(token) : o.NULL_EXPR]);
+ });
}
return o.importExpr(resolveIdentifier(Identifiers.StaticNodeDebugInfo))
.instantiate(
@@ -518,19 +511,20 @@ function createViewFactory(
templateUrlInfo = view.component.template.templateUrl;
}
if (view.viewIndex === 0) {
- var animationsExpr = o.literalMap(view.animations.map(entry => [entry.name, entry.fnVariable]));
- initRenderCompTypeStmts = [new o.IfStmt(renderCompTypeVar.identical(o.NULL_EXPR), [
- renderCompTypeVar
- .set(ViewConstructorVars.viewUtils.callMethod(
- 'createRenderComponentType',
- [
- o.literal(templateUrlInfo),
- o.literal(view.component.template.ngContentSelectors.length),
- ViewEncapsulationEnum.fromValue(view.component.template.encapsulation), view.styles,
- animationsExpr
- ]))
- .toStmt()
- ])];
+ var animationsExpr = o.literalMap(view.animations.map(entry => [entry.name, entry.fnExp]));
+ initRenderCompTypeStmts = [new o.IfStmt(
+ renderCompTypeVar.identical(o.NULL_EXPR),
+ [renderCompTypeVar
+ .set(ViewConstructorVars.viewUtils.callMethod(
+ 'createRenderComponentType',
+ [
+ view.genConfig.genDebugInfo ? o.literal(templateUrlInfo) : o.literal(''),
+ o.literal(view.component.template.ngContentSelectors.length),
+ ViewEncapsulationEnum.fromValue(view.component.template.encapsulation),
+ view.styles,
+ animationsExpr,
+ ]))
+ .toStmt()])];
}
return o
.fn(viewFactoryArgs, initRenderCompTypeStmts.concat([new o.ReturnStatement(
@@ -602,15 +596,15 @@ function generateDetectChangesMethod(view: CompileView): o.Statement[] {
var varStmts: any[] = [];
var readVars = o.findReadVarNames(stmts);
- if (SetWrapper.has(readVars, DetectChangesVars.changed.name)) {
+ if (readVars.has(DetectChangesVars.changed.name)) {
varStmts.push(DetectChangesVars.changed.set(o.literal(true)).toDeclStmt(o.BOOL_TYPE));
}
- if (SetWrapper.has(readVars, DetectChangesVars.changes.name)) {
+ if (readVars.has(DetectChangesVars.changes.name)) {
varStmts.push(
DetectChangesVars.changes.set(o.NULL_EXPR)
.toDeclStmt(new o.MapType(o.importType(resolveIdentifier(Identifiers.SimpleChange)))));
}
- if (SetWrapper.has(readVars, DetectChangesVars.valUnwrapper.name)) {
+ if (readVars.has(DetectChangesVars.valUnwrapper.name)) {
varStmts.push(
DetectChangesVars.valUnwrapper
.set(o.importExpr(resolveIdentifier(Identifiers.ValueUnwrapper)).instantiate([]))
diff --git a/modules/@angular/compiler/src/view_compiler/view_compiler.ts b/modules/@angular/compiler/src/view_compiler/view_compiler.ts
index 073c92cb4167..2a67f7bdbd1e 100644
--- a/modules/@angular/compiler/src/view_compiler/view_compiler.ts
+++ b/modules/@angular/compiler/src/view_compiler/view_compiler.ts
@@ -8,7 +8,7 @@
import {Injectable} from '@angular/core';
-import {AnimationCompiler} from '../animation/animation_compiler';
+import {AnimationCompiler, AnimationEntryCompileResult} from '../animation/animation_compiler';
import {CompileDirectiveMetadata, CompilePipeMetadata} from '../compile_metadata';
import {CompilerConfig} from '../config';
import * as o from '../output/output_ast';
@@ -34,22 +34,18 @@ export class ViewCompiler {
compileComponent(
component: CompileDirectiveMetadata, template: TemplateAst[], styles: o.Expression,
- pipes: CompilePipeMetadata[]): ViewCompileResult {
- var dependencies: Array = [];
- var compiledAnimations = this._animationCompiler.compileComponent(component, template);
- var statements: o.Statement[] = [];
- var animationTriggers = compiledAnimations.triggers;
- animationTriggers.forEach(entry => {
- statements.push(entry.statesMapStatement);
- statements.push(entry.fnStatement);
- });
- var view = new CompileView(
- component, this._genConfig, pipes, styles, animationTriggers, 0,
+ pipes: CompilePipeMetadata[],
+ compiledAnimations: AnimationEntryCompileResult[]): ViewCompileResult {
+ const dependencies: Array = [];
+ const view = new CompileView(
+ component, this._genConfig, pipes, styles, compiledAnimations, 0,
CompileElement.createNull(), []);
+
+ const statements: o.Statement[] = [];
buildView(view, template, dependencies);
// Need to separate binding from creation to be able to refer to
// variables that have been declared after usage.
- bindView(view, template, compiledAnimations.outputs);
+ bindView(view, template);
finishView(view, statements);
return new ViewCompileResult(statements, view.viewFactory.name, dependencies);
diff --git a/modules/@angular/compiler/test/animation/animation_compiler_spec.ts b/modules/@angular/compiler/test/animation/animation_compiler_spec.ts
index 094a3da956a3..ca758524fb40 100644
--- a/modules/@angular/compiler/test/animation/animation_compiler_spec.ts
+++ b/modules/@angular/compiler/test/animation/animation_compiler_spec.ts
@@ -6,11 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {AnimationMetadata, animate, group, sequence, style, transition, trigger} from '@angular/core';
-import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
-
-import {StringMapWrapper} from '../../../platform-browser-dynamic/src/facade/collection';
-import {AnimationCompiler, CompiledAnimationTriggerResult} from '../../src/animation/animation_compiler';
+import {AnimationMetadata, animate, sequence, style, transition, trigger} from '@angular/core';
+import {beforeEach, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
+import {AnimationCompiler, AnimationEntryCompileResult} from '../../src/animation/animation_compiler';
+import {AnimationParser} from '../../src/animation/animation_parser';
import {CompileAnimationEntryMetadata, CompileDirectiveMetadata, CompileTemplateMetadata, CompileTypeMetadata} from '../../src/compile_metadata';
import {CompileMetadataResolver} from '../../src/metadata_resolver';
@@ -20,12 +19,13 @@ export function main() {
beforeEach(
inject([CompileMetadataResolver], (res: CompileMetadataResolver) => { resolver = res; }));
- var compiler = new AnimationCompiler();
+ const parser = new AnimationParser();
+ const compiler = new AnimationCompiler();
var compileAnimations =
- (component: CompileDirectiveMetadata): CompiledAnimationTriggerResult => {
- var result = compiler.compileComponent(component, []);
- return result.triggers[0];
+ (component: CompileDirectiveMetadata): AnimationEntryCompileResult[] => {
+ const parsedAnimations = parser.parseComponent(component);
+ return compiler.compile(component.type.name, parsedAnimations);
};
var compileTriggers = (input: any[]) => {
@@ -66,14 +66,5 @@ export function main() {
expect(capturedErrorMessage)
.toMatch(/Animation states via styles must be prefixed with a ":"/);
});
-
- it('should throw an error when two or more animation triggers contain the same name', () => {
- var t1Data: any[] = [];
- var t2Data: any[] = [];
-
- expect(() => {
- compileTriggers([['myTrigger', t1Data], ['myTrigger', t2Data]]);
- }).toThrowError(/The animation trigger "myTrigger" has already been registered on "myCmp"/);
- });
});
}
diff --git a/modules/@angular/compiler/test/animation/animation_parser_spec.ts b/modules/@angular/compiler/test/animation/animation_parser_spec.ts
index b5688715205a..a726fd23fb92 100644
--- a/modules/@angular/compiler/test/animation/animation_parser_spec.ts
+++ b/modules/@angular/compiler/test/animation/animation_parser_spec.ts
@@ -6,13 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {AnimationAnimateMetadata, AnimationGroupMetadata, AnimationMetadata, AnimationSequenceMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
-import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
+import {AnimationMetadata, animate, group, keyframes, sequence, style, transition, trigger} from '@angular/core';
+import {beforeEach, describe, inject, it} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing/matchers';
-import {AnimationAst, AnimationEntryAst, AnimationGroupAst, AnimationKeyframeAst, AnimationSequenceAst, AnimationStateTransitionAst, AnimationStepAst, AnimationStylesAst} from '../../src/animation/animation_ast';
-import {parseAnimationEntry} from '../../src/animation/animation_parser';
-import {StringMapWrapper} from '../../src/facade/collection';
+import {AnimationEntryAst, AnimationGroupAst, AnimationKeyframeAst, AnimationSequenceAst, AnimationStepAst, AnimationStylesAst} from '../../src/animation/animation_ast';
+import {AnimationParser} from '../../src/animation/animation_parser';
import {CompileMetadataResolver} from '../../src/metadata_resolver';
import {FILL_STYLE_FLAG, flattenStyles} from '../private_import_core';
@@ -21,15 +20,13 @@ export function main() {
var combineStyles = (styles: AnimationStylesAst): {[key: string]: string | number} => {
var flatStyles: {[key: string]: string | number} = {};
styles.styles.forEach(
- entry => StringMapWrapper.forEach(
- entry, (val: any /** TODO #9100 */, prop: any /** TODO #9100 */) => {
- flatStyles[prop] = val;
- }));
+ entry => Object.keys(entry).forEach(prop => { flatStyles[prop] = entry[prop]; }));
return flatStyles;
};
- var collectKeyframeStyles = (keyframe: AnimationKeyframeAst):
- {[key: string]: string | number} => { return combineStyles(keyframe.styles); };
+ var collectKeyframeStyles =
+ (keyframe: AnimationKeyframeAst): {[key: string]: string | number} =>
+ combineStyles(keyframe.styles);
var collectStepStyles = (step: AnimationStepAst): Array<{[key: string]: string | number}> => {
var keyframes = step.keyframes;
@@ -46,17 +43,17 @@ export function main() {
inject([CompileMetadataResolver], (res: CompileMetadataResolver) => { resolver = res; }));
var parseAnimation = (data: AnimationMetadata[]) => {
- var entry = trigger('myAnimation', [transition('state1 => state2', sequence(data))]);
- var compiledAnimationEntry = resolver.getAnimationEntryMetadata(entry);
- return parseAnimationEntry(compiledAnimationEntry);
+ const entry = trigger('myAnimation', [transition('state1 => state2', sequence(data))]);
+ const compiledAnimationEntry = resolver.getAnimationEntryMetadata(entry);
+ const parser = new AnimationParser();
+ return parser.parseEntry(compiledAnimationEntry);
};
var getAnimationAstFromEntryAst =
(ast: AnimationEntryAst) => { return ast.stateTransitions[0].animation; };
- var parseAnimationAst = (data: AnimationMetadata[]) => {
- return getAnimationAstFromEntryAst(parseAnimation(data).ast);
- };
+ var parseAnimationAst = (data: AnimationMetadata[]) =>
+ getAnimationAstFromEntryAst(parseAnimation(data).ast);
var parseAnimationAndGetErrors = (data: AnimationMetadata[]) => parseAnimation(data).errors;
diff --git a/modules/@angular/compiler/test/css_parser/css_lexer_spec.ts b/modules/@angular/compiler/test/css_parser/css_lexer_spec.ts
index 04539fbdde31..781a44a2d666 100644
--- a/modules/@angular/compiler/test/css_parser/css_lexer_spec.ts
+++ b/modules/@angular/compiler/test/css_parser/css_lexer_spec.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '../../../core/testing/testing_internal';
+import {describe, expect, it} from '../../../core/testing/testing_internal';
import {CssLexer, CssLexerMode, CssScannerError, CssToken, CssTokenType} from '../../src/css_parser/css_lexer';
import {isPresent} from '../../src/facade/lang';
diff --git a/modules/@angular/compiler/test/css_parser/css_parser_spec.ts b/modules/@angular/compiler/test/css_parser/css_parser_spec.ts
index 86710adfb90c..024f59f03a02 100644
--- a/modules/@angular/compiler/test/css_parser/css_parser_spec.ts
+++ b/modules/@angular/compiler/test/css_parser/css_parser_spec.ts
@@ -7,7 +7,7 @@
*/
-import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '../../../core/testing/testing_internal';
+import {describe, expect, it} from '../../../core/testing/testing_internal';
import {CssBlockAst, CssBlockDefinitionRuleAst, CssBlockRuleAst, CssDefinitionAst, CssInlineRuleAst, CssKeyframeDefinitionAst, CssKeyframeRuleAst, CssMediaQueryRuleAst, CssSelectorRuleAst, CssStyleSheetAst, CssStyleValueAst} from '../../src/css_parser/css_ast';
import {BlockType, CssParseError, CssParser, CssToken, ParsedCssResult} from '../../src/css_parser/css_parser';
import {ParseLocation} from '../../src/parse_util';
diff --git a/modules/@angular/compiler/test/css_parser/css_visitor_spec.ts b/modules/@angular/compiler/test/css_parser/css_visitor_spec.ts
index e59014822e8c..19d2a63bf370 100644
--- a/modules/@angular/compiler/test/css_parser/css_visitor_spec.ts
+++ b/modules/@angular/compiler/test/css_parser/css_visitor_spec.ts
@@ -7,8 +7,8 @@
*/
-import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '../../../core/testing/testing_internal';
-import {CssAst, CssAstVisitor, CssAtRulePredicateAst, CssBlockAst, CssBlockDefinitionRuleAst, CssBlockRuleAst, CssDefinitionAst, CssInlineRuleAst, CssKeyframeDefinitionAst, CssKeyframeRuleAst, CssMediaQueryRuleAst, CssPseudoSelectorAst, CssRuleAst, CssSelectorAst, CssSelectorRuleAst, CssSimpleSelectorAst, CssStyleSheetAst, CssStyleValueAst, CssStylesBlockAst, CssUnknownRuleAst, CssUnknownTokenListAst} from '../../src/css_parser/css_ast';
+import {beforeEach, describe, expect, it} from '../../../core/testing/testing_internal';
+import {CssAst, CssAstVisitor, CssAtRulePredicateAst, CssBlockAst, CssDefinitionAst, CssInlineRuleAst, CssKeyframeDefinitionAst, CssKeyframeRuleAst, CssMediaQueryRuleAst, CssPseudoSelectorAst, CssRuleAst, CssSelectorAst, CssSelectorRuleAst, CssSimpleSelectorAst, CssStyleSheetAst, CssStyleValueAst, CssStylesBlockAst, CssUnknownRuleAst, CssUnknownTokenListAst} from '../../src/css_parser/css_ast';
import {BlockType, CssParseError, CssParser, CssToken} from '../../src/css_parser/css_parser';
import {isPresent} from '../../src/facade/lang';
diff --git a/modules/@angular/compiler/test/directive_lifecycle_spec.ts b/modules/@angular/compiler/test/directive_lifecycle_spec.ts
index d4b62ba40be4..aaee9d17edae 100644
--- a/modules/@angular/compiler/test/directive_lifecycle_spec.ts
+++ b/modules/@angular/compiler/test/directive_lifecycle_spec.ts
@@ -8,7 +8,7 @@
import {hasLifecycleHook} from '@angular/compiler/src/lifecycle_reflector';
import {LifecycleHooks} from '@angular/core/src/metadata/lifecycle_hooks';
-import {beforeEach, ddescribe, describe, expect, iit, inject, it, xdescribe} from '@angular/core/testing/testing_internal';
+import {describe, expect, it} from '@angular/core/testing/testing_internal';
export function main() {
describe('Create Directive', () => {
diff --git a/modules/@angular/compiler/test/directive_normalizer_spec.ts b/modules/@angular/compiler/test/directive_normalizer_spec.ts
index 839b0be86213..6e5ca9547450 100644
--- a/modules/@angular/compiler/test/directive_normalizer_spec.ts
+++ b/modules/@angular/compiler/test/directive_normalizer_spec.ts
@@ -14,7 +14,7 @@ import {MockResourceLoader} from '@angular/compiler/testing/resource_loader_mock
import {TEST_COMPILER_PROVIDERS} from '@angular/compiler/testing/test_bindings';
import {ViewEncapsulation} from '@angular/core/src/metadata/view';
import {TestBed} from '@angular/core/testing';
-import {AsyncTestCompleter, beforeEach, beforeEachProviders, 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 {SpyResourceLoader} from './spies';
diff --git a/modules/@angular/compiler/test/directive_resolver_spec.ts b/modules/@angular/compiler/test/directive_resolver_spec.ts
index 28b4552435c6..7e75be9e1d71 100644
--- a/modules/@angular/compiler/test/directive_resolver_spec.ts
+++ b/modules/@angular/compiler/test/directive_resolver_spec.ts
@@ -108,16 +108,25 @@ class SomeDirectiveWithViewChild {
class ComponentWithTemplate {
}
+@Directive({
+ selector: 'someDirective',
+ host: {'[decorator]': 'decorator'},
+ inputs: ['decorator'],
+})
+class SomeDirectiveWithSameHostBindingAndInput {
+ @Input() @HostBinding() prop: any;
+}
+
class SomeDirectiveWithoutMetadata {}
export function main() {
describe('DirectiveResolver', () => {
- var resolver: DirectiveResolver;
+ let resolver: DirectiveResolver;
beforeEach(() => { resolver = new DirectiveResolver(); });
it('should read out the Directive metadata', () => {
- var directiveMetadata = resolver.resolve(SomeDirective);
+ const directiveMetadata = resolver.resolve(SomeDirective);
expect(directiveMetadata)
.toEqual(new Directive(
{selector: 'someDirective', inputs: [], outputs: [], host: {}, queries: {}}));
@@ -130,7 +139,7 @@ export function main() {
});
it('should not read parent class Directive metadata', function() {
- var directiveMetadata = resolver.resolve(SomeChildDirective);
+ const directiveMetadata = resolver.resolve(SomeChildDirective);
expect(directiveMetadata)
.toEqual(new Directive(
{selector: 'someChildDirective', inputs: [], outputs: [], host: {}, queries: {}}));
@@ -138,12 +147,12 @@ export function main() {
describe('inputs', () => {
it('should append directive inputs', () => {
- var directiveMetadata = resolver.resolve(SomeDirectiveWithInputs);
+ const directiveMetadata = resolver.resolve(SomeDirectiveWithInputs);
expect(directiveMetadata.inputs).toEqual(['c', 'a', 'b: renamed']);
});
it('should work with getters and setters', () => {
- var directiveMetadata = resolver.resolve(SomeDirectiveWithSetterProps);
+ const directiveMetadata = resolver.resolve(SomeDirectiveWithSetterProps);
expect(directiveMetadata.inputs).toEqual(['a: renamed']);
});
@@ -162,12 +171,12 @@ export function main() {
describe('outputs', () => {
it('should append directive outputs', () => {
- var directiveMetadata = resolver.resolve(SomeDirectiveWithOutputs);
+ const directiveMetadata = resolver.resolve(SomeDirectiveWithOutputs);
expect(directiveMetadata.outputs).toEqual(['c', 'a', 'b: renamed']);
});
it('should work with getters and setters', () => {
- var directiveMetadata = resolver.resolve(SomeDirectiveWithGetterOutputs);
+ const directiveMetadata = resolver.resolve(SomeDirectiveWithGetterOutputs);
expect(directiveMetadata.outputs).toEqual(['a: renamed']);
});
@@ -186,12 +195,18 @@ export function main() {
describe('host', () => {
it('should append host bindings', () => {
- var directiveMetadata = resolver.resolve(SomeDirectiveWithHostBindings);
+ const directiveMetadata = resolver.resolve(SomeDirectiveWithHostBindings);
expect(directiveMetadata.host).toEqual({'[c]': 'c', '[a]': 'a', '[renamed]': 'b'});
});
+ it('should append host binding and input on the same property', () => {
+ const directiveMetadata = resolver.resolve(SomeDirectiveWithSameHostBindingAndInput);
+ expect(directiveMetadata.host).toEqual({'[decorator]': 'decorator', '[prop]': 'prop'});
+ expect(directiveMetadata.inputs).toEqual(['decorator', 'prop']);
+ });
+
it('should append host listeners', () => {
- var directiveMetadata = resolver.resolve(SomeDirectiveWithHostListeners);
+ const directiveMetadata = resolver.resolve(SomeDirectiveWithHostListeners);
expect(directiveMetadata.host)
.toEqual({'(c)': 'onC()', '(a)': 'onA()', '(b)': 'onB($event.value)'});
});
@@ -199,33 +214,33 @@ export function main() {
describe('queries', () => {
it('should append ContentChildren', () => {
- var directiveMetadata = resolver.resolve(SomeDirectiveWithContentChildren);
+ const directiveMetadata = resolver.resolve(SomeDirectiveWithContentChildren);
expect(directiveMetadata.queries)
.toEqual({'cs': new ContentChildren('c'), 'as': new ContentChildren('a')});
});
it('should append ViewChildren', () => {
- var directiveMetadata = resolver.resolve(SomeDirectiveWithViewChildren);
+ const directiveMetadata = resolver.resolve(SomeDirectiveWithViewChildren);
expect(directiveMetadata.queries)
.toEqual({'cs': new ViewChildren('c'), 'as': new ViewChildren('a')});
});
it('should append ContentChild', () => {
- var directiveMetadata = resolver.resolve(SomeDirectiveWithContentChild);
+ const directiveMetadata = resolver.resolve(SomeDirectiveWithContentChild);
expect(directiveMetadata.queries)
.toEqual({'c': new ContentChild('c'), 'a': new ContentChild('a')});
});
it('should append ViewChild', () => {
- var directiveMetadata = resolver.resolve(SomeDirectiveWithViewChild);
+ const directiveMetadata = resolver.resolve(SomeDirectiveWithViewChild);
expect(directiveMetadata.queries)
.toEqual({'c': new ViewChild('c'), 'a': new ViewChild('a')});
});
});
- describe('view', () => {
+ describe('Component', () => {
it('should read out the template related metadata from the Component metadata', () => {
- var compMetadata = resolver.resolve(ComponentWithTemplate);
+ const compMetadata: Component = resolver.resolve(ComponentWithTemplate);
expect(compMetadata.template).toEqual('some template');
expect(compMetadata.styles).toEqual(['some styles']);
});
diff --git a/modules/@angular/compiler/test/expression_parser/unparser.ts b/modules/@angular/compiler/test/expression_parser/unparser.ts
index 6d1c835d9c4f..54ddf0790cc9 100644
--- a/modules/@angular/compiler/test/expression_parser/unparser.ts
+++ b/modules/@angular/compiler/test/expression_parser/unparser.ts
@@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {AST, AstVisitor, Binary, BindingPipe, Chain, Conditional, EmptyExpr, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead} from '../../src/expression_parser/ast';
-import {StringWrapper, isPresent, isString} from '../../src/facade/lang';
+import {AST, AstVisitor, Binary, BindingPipe, Chain, Conditional, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead} from '../../src/expression_parser/ast';
+import {StringWrapper, isString} from '../../src/facade/lang';
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../src/ml_parser/interpolation_config';
class Unparser implements AstVisitor {
diff --git a/modules/@angular/compiler/test/expression_parser/validator.ts b/modules/@angular/compiler/test/expression_parser/validator.ts
index f386352bf536..5b176976b3d5 100644
--- a/modules/@angular/compiler/test/expression_parser/validator.ts
+++ b/modules/@angular/compiler/test/expression_parser/validator.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {AST, Binary, BindingPipe, Chain, Conditional, EmptyExpr, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, ParseSpan, PrefixNot, PropertyRead, PropertyWrite, Quote, RecursiveAstVisitor, SafeMethodCall, SafePropertyRead} from '../../src/expression_parser/ast';
+import {AST, Binary, BindingPipe, Chain, Conditional, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, ParseSpan, PrefixNot, PropertyRead, PropertyWrite, Quote, RecursiveAstVisitor, SafeMethodCall, SafePropertyRead} from '../../src/expression_parser/ast';
import {unparse} from './unparser';
diff --git a/modules/@angular/compiler/test/i18n/digest_spec.ts b/modules/@angular/compiler/test/i18n/digest_spec.ts
index 08e45480a64c..b6c7c8055162 100644
--- a/modules/@angular/compiler/test/i18n/digest_spec.ts
+++ b/modules/@angular/compiler/test/i18n/digest_spec.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {beforeEach, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
+import {describe, expect, it} from '@angular/core/testing/testing_internal';
import {sha1} from '../../src/i18n/digest';
diff --git a/modules/@angular/compiler/test/i18n/extractor_merger_spec.ts b/modules/@angular/compiler/test/i18n/extractor_merger_spec.ts
index fc51c963a239..dcb36154c78f 100644
--- a/modules/@angular/compiler/test/i18n/extractor_merger_spec.ts
+++ b/modules/@angular/compiler/test/i18n/extractor_merger_spec.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {beforeEach, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
+import {describe, expect, it} from '@angular/core/testing/testing_internal';
import {digestMessage, serializeNodes as serializeI18nNodes} from '../../src/i18n/digest';
import {extractMessages, mergeTranslations} from '../../src/i18n/extractor_merger';
diff --git a/modules/@angular/compiler/test/i18n/i18n_parser_spec.ts b/modules/@angular/compiler/test/i18n/i18n_parser_spec.ts
index 7a0063ed3521..1c6ae8940358 100644
--- a/modules/@angular/compiler/test/i18n/i18n_parser_spec.ts
+++ b/modules/@angular/compiler/test/i18n/i18n_parser_spec.ts
@@ -8,7 +8,7 @@
import {extractMessages} from '@angular/compiler/src/i18n/extractor_merger';
import {Message} from '@angular/compiler/src/i18n/i18n_ast';
-import {ddescribe, describe, expect, iit, it} from '@angular/core/testing/testing_internal';
+import {describe, expect, it} from '@angular/core/testing/testing_internal';
import {serializeNodes} from '../../src/i18n/digest';
import {HtmlParser} from '../../src/ml_parser/html_parser';
diff --git a/modules/@angular/compiler/test/i18n/message_bundle_spec.ts b/modules/@angular/compiler/test/i18n/message_bundle_spec.ts
index 2848bda17c28..c47c4e0bc426 100644
--- a/modules/@angular/compiler/test/i18n/message_bundle_spec.ts
+++ b/modules/@angular/compiler/test/i18n/message_bundle_spec.ts
@@ -8,7 +8,7 @@
import * as i18n from '@angular/compiler/src/i18n/i18n_ast';
import {Serializer} from '@angular/compiler/src/i18n/serializers/serializer';
-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';
import {serializeNodes} from '../../src/i18n/digest';
import {MessageBundle} from '../../src/i18n/message_bundle';
diff --git a/modules/@angular/compiler/test/i18n/serializers/placeholder_spec.ts b/modules/@angular/compiler/test/i18n/serializers/placeholder_spec.ts
index 3d24f7a3d790..ce6e3b181147 100644
--- a/modules/@angular/compiler/test/i18n/serializers/placeholder_spec.ts
+++ b/modules/@angular/compiler/test/i18n/serializers/placeholder_spec.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-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';
import {PlaceholderRegistry} from '../../../src/i18n/serializers/placeholder';
diff --git a/modules/@angular/compiler/test/i18n/serializers/xliff_spec.ts b/modules/@angular/compiler/test/i18n/serializers/xliff_spec.ts
index 93457db3f02c..6a6b9a71cb08 100644
--- a/modules/@angular/compiler/test/i18n/serializers/xliff_spec.ts
+++ b/modules/@angular/compiler/test/i18n/serializers/xliff_spec.ts
@@ -7,7 +7,7 @@
*/
import {Xliff} from '@angular/compiler/src/i18n/serializers/xliff';
-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';
import {MessageBundle} from '../../../src/i18n/message_bundle';
import {HtmlParser} from '../../../src/ml_parser/html_parser';
import {DEFAULT_INTERPOLATION_CONFIG} from '../../../src/ml_parser/interpolation_config';
@@ -17,51 +17,64 @@ const HTML = `
not translatable
translatable element with placeholders {{ interpolation}}
foo
+
`;
const WRITE_XLIFF = `
-
-
-
- translatable attribute
-
-
-
- translatable element with placeholders
-
-
-
- foo
-
- d
- m
-
-
-
- `;
+
+
+
+ translatable attribute
+
+
+
+ translatable element with placeholders
+
+
+
+ foo
+
+ d
+ m
+
+
+
+
+ ph names
+
+
+
+
+`;
const LOAD_XLIFF = `
-
-
-
- translatable attribute
- etubirtta elbatalsnart
-
-
- translatable element with placeholders
- footnemele elbatalsnart sredlohecalp htiw
-
-
- foo
- oof
- d
- m
-
-
-
- `;
+
+
+
+ translatable attribute
+ etubirtta elbatalsnart
+
+
+ translatable element with placeholders
+ footnemele elbatalsnart sredlohecalp htiw
+
+
+ foo
+ oof
+ d
+ m
+
+
+
+
+ ph names
+
+
+
+
+`;
export function main(): void {
let serializer: Xliff;
@@ -103,6 +116,7 @@ export function main(): void {
'ec1d033f2436133c14ab038286c4f5df4697484a':
'{{ interpolation}} footnemele elbatalsnart sredlohecalp htiw ',
'db3e0a6a5a96481f60aec61d98c3eecddef5ac23': 'oof',
+ 'd7fa2d59aaedcaa5309f13028c59af8c85b8c49d': '
',
});
});
});
diff --git a/modules/@angular/compiler/test/i18n/serializers/xmb_spec.ts b/modules/@angular/compiler/test/i18n/serializers/xmb_spec.ts
index 817351737c7d..89a5daa75ca9 100644
--- a/modules/@angular/compiler/test/i18n/serializers/xmb_spec.ts
+++ b/modules/@angular/compiler/test/i18n/serializers/xmb_spec.ts
@@ -6,12 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
+import {MessageBundle} from '@angular/compiler/src/i18n/message_bundle';
import {Xmb} from '@angular/compiler/src/i18n/serializers/xmb';
-import {beforeEach, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
-
-import {MessageBundle} from '../../../src/i18n/message_bundle';
-import {HtmlParser} from '../../../src/ml_parser/html_parser';
-import {DEFAULT_INTERPOLATION_CONFIG} from '../../../src/ml_parser/interpolation_config';
+import {HtmlParser} from '@angular/compiler/src/ml_parser/html_parser';
+import {DEFAULT_INTERPOLATION_CONFIG} from '@angular/compiler/src/ml_parser/interpolation_config';
export function main(): void {
describe('XMB serializer', () => {
@@ -49,7 +47,8 @@ export function main(): void {
{ count, plural, =0 {<p> test</p> } }
foo
{ count, plural, =0 {{ sex, gender, other {<p> deeply nested</p> } } } }
-`;
+
+`;
it('should write a valid xmb file', () => { expect(toXmb(HTML)).toEqual(XMB); });
diff --git a/modules/@angular/compiler/test/i18n/serializers/xml_helper_spec.ts b/modules/@angular/compiler/test/i18n/serializers/xml_helper_spec.ts
index 98972f05cf1e..8bcd7e3d302a 100644
--- a/modules/@angular/compiler/test/i18n/serializers/xml_helper_spec.ts
+++ b/modules/@angular/compiler/test/i18n/serializers/xml_helper_spec.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {beforeEach, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
+import {describe, expect, it} from '@angular/core/testing/testing_internal';
import * as xml from '../../../src/i18n/serializers/xml_helper';
diff --git a/modules/@angular/compiler/test/i18n/serializers/xtb_spec.ts b/modules/@angular/compiler/test/i18n/serializers/xtb_spec.ts
index 6511a3c2b36b..f096b0863dd8 100644
--- a/modules/@angular/compiler/test/i18n/serializers/xtb_spec.ts
+++ b/modules/@angular/compiler/test/i18n/serializers/xtb_spec.ts
@@ -7,7 +7,7 @@
*/
import {escapeRegExp} from '@angular/core/src/facade/lang';
-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';
import {MessageBundle} from '../../../src/i18n/message_bundle';
import {Xtb} from '../../../src/i18n/serializers/xtb';
diff --git a/modules/@angular/compiler/test/ml_parser/ast_serializer_spec.ts b/modules/@angular/compiler/test/ml_parser/ast_serializer_spec.ts
index 4e5536f1da09..129e2e76584e 100644
--- a/modules/@angular/compiler/test/ml_parser/ast_serializer_spec.ts
+++ b/modules/@angular/compiler/test/ml_parser/ast_serializer_spec.ts
@@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {beforeEach, ddescribe, describe, expect, it} from '../../../core/testing/testing_internal';
-import * as html from '../../src/ml_parser/ast';
-import {HtmlParser} from '../../src/ml_parser/html_parser';
+import * as html from '@angular/compiler/src/ml_parser/ast';
+import {HtmlParser} from '@angular/compiler/src/ml_parser/html_parser';
+import {getHtmlTagDefinition} from '@angular/compiler/src/ml_parser/html_tags';
export function main() {
describe('Node serializer', () => {
@@ -62,6 +62,10 @@ export function main() {
class _SerializerVisitor implements html.Visitor {
visitElement(element: html.Element, context: any): any {
+ if (getHtmlTagDefinition(element.name).isVoid) {
+ return `<${element.name}${this._visitAll(element.attrs, ' ')}/>`;
+ }
+
return `<${element.name}${this._visitAll(element.attrs, ' ')}>${this._visitAll(element.children)}${element.name}>`;
}
diff --git a/modules/@angular/compiler/test/ml_parser/html_parser_spec.ts b/modules/@angular/compiler/test/ml_parser/html_parser_spec.ts
index 49bb0e2ce981..f185c179df47 100644
--- a/modules/@angular/compiler/test/ml_parser/html_parser_spec.ts
+++ b/modules/@angular/compiler/test/ml_parser/html_parser_spec.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '../../../core/testing/testing_internal';
+import {beforeEach, describe, expect, it} from '../../../core/testing/testing_internal';
import * as html from '../../src/ml_parser/ast';
import {HtmlParser, ParseTreeResult, TreeError} from '../../src/ml_parser/html_parser';
import {TokenType} from '../../src/ml_parser/lexer';
diff --git a/modules/@angular/compiler/test/ml_parser/icu_ast_expander_spec.ts b/modules/@angular/compiler/test/ml_parser/icu_ast_expander_spec.ts
index ee1126ccba29..e216462e3281 100644
--- a/modules/@angular/compiler/test/ml_parser/icu_ast_expander_spec.ts
+++ b/modules/@angular/compiler/test/ml_parser/icu_ast_expander_spec.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {ddescribe, describe, expect, iit, it} from '../../../core/testing/testing_internal';
+import {describe, expect, it} from '../../../core/testing/testing_internal';
import * as html from '../../src/ml_parser/ast';
import {HtmlParser} from '../../src/ml_parser/html_parser';
import {ExpansionResult, expandNodes} from '../../src/ml_parser/icu_ast_expander';
diff --git a/modules/@angular/compiler/test/ml_parser/lexer_spec.ts b/modules/@angular/compiler/test/ml_parser/lexer_spec.ts
index c0910886bd4b..3ca4ced01358 100644
--- a/modules/@angular/compiler/test/ml_parser/lexer_spec.ts
+++ b/modules/@angular/compiler/test/ml_parser/lexer_spec.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '../../../core/testing/testing_internal';
+import {describe, expect, it} from '../../../core/testing/testing_internal';
import {getHtmlTagDefinition} from '../../src/ml_parser/html_tags';
import {InterpolationConfig} from '../../src/ml_parser/interpolation_config';
import * as lex from '../../src/ml_parser/lexer';
diff --git a/modules/@angular/compiler/test/ng_module_resolver_mock_spec.ts b/modules/@angular/compiler/test/ng_module_resolver_mock_spec.ts
index eb409c350a89..6ad7df44d96b 100644
--- a/modules/@angular/compiler/test/ng_module_resolver_mock_spec.ts
+++ b/modules/@angular/compiler/test/ng_module_resolver_mock_spec.ts
@@ -7,9 +7,7 @@
*/
import {Injector, NgModule} from '@angular/core';
-import {beforeEach, ddescribe, describe, expect, iit, inject, it} from '@angular/core/testing/testing_internal';
-
-import {isBlank, stringify} from '../src/facade/lang';
+import {beforeEach, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {MockNgModuleResolver} from '../testing/index';
export function main() {
diff --git a/modules/@angular/compiler/test/output/abstract_emitter_spec.ts b/modules/@angular/compiler/test/output/abstract_emitter_spec.ts
index d5b885e4b1c5..008c26a5f0ba 100644
--- a/modules/@angular/compiler/test/output/abstract_emitter_spec.ts
+++ b/modules/@angular/compiler/test/output/abstract_emitter_spec.ts
@@ -7,7 +7,7 @@
*/
import {escapeIdentifier} from '@angular/compiler/src/output/abstract_emitter';
-import {beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
+import {describe, expect, it} from '@angular/core/testing/testing_internal';
export function main() {
describe('AbstractEmitter', () => {
diff --git a/modules/@angular/compiler/test/output/js_emitter_spec.ts b/modules/@angular/compiler/test/output/js_emitter_spec.ts
index 77f0a28b700f..387292a2fbef 100644
--- a/modules/@angular/compiler/test/output/js_emitter_spec.ts
+++ b/modules/@angular/compiler/test/output/js_emitter_spec.ts
@@ -9,9 +9,7 @@
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
import {JavaScriptEmitter} from '@angular/compiler/src/output/js_emitter';
import * as o from '@angular/compiler/src/output/output_ast';
-import {beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
-
-import {isBlank} from '../../src/facade/lang';
+import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
import {SimpleJsImportGenerator} from './output_emitter_util';
@@ -39,7 +37,7 @@ export function main() {
});
function emitStmt(stmt: o.Statement, exportedVars: string[] = null): string {
- if (isBlank(exportedVars)) {
+ if (!exportedVars) {
exportedVars = [];
}
return emitter.emitStatements(someModuleUrl, [stmt], exportedVars);
diff --git a/modules/@angular/compiler/test/output/output_emitter_codegen_typed.ts b/modules/@angular/compiler/test/output/output_emitter_codegen_typed.ts
index 40512a07725e..d614cc5160f3 100644
--- a/modules/@angular/compiler/test/output/output_emitter_codegen_typed.ts
+++ b/modules/@angular/compiler/test/output/output_emitter_codegen_typed.ts
@@ -7,7 +7,7 @@
*/
// ATTENTION: This file will be overwritten with generated code by main()
-import * as o from '@angular/compiler/src/output/output_ast';
+
import {TypeScriptEmitter} from '@angular/compiler/src/output/ts_emitter';
import {print} from '../../src/facade/lang';
diff --git a/modules/@angular/compiler/test/output/output_emitter_spec.ts b/modules/@angular/compiler/test/output/output_emitter_spec.ts
index 186f1dc32fa0..72ce118ebaff 100644
--- a/modules/@angular/compiler/test/output/output_emitter_spec.ts
+++ b/modules/@angular/compiler/test/output/output_emitter_spec.ts
@@ -10,7 +10,7 @@ import {interpretStatements} from '@angular/compiler/src/output/output_interpret
import {jitStatements} from '@angular/compiler/src/output/output_jit';
import {EventEmitter} from '@angular/core';
import {ViewType} from '@angular/core/src/linker/view_type';
-import {beforeEach, ddescribe, describe, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
+import {beforeEach, describe, it} from '@angular/core/testing/testing_internal';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
import {expect} from '@angular/platform-browser/testing/matchers';
diff --git a/modules/@angular/compiler/test/output/ts_emitter_spec.ts b/modules/@angular/compiler/test/output/ts_emitter_spec.ts
index 562c8dd10713..e60c3205bb0a 100644
--- a/modules/@angular/compiler/test/output/ts_emitter_spec.ts
+++ b/modules/@angular/compiler/test/output/ts_emitter_spec.ts
@@ -9,9 +9,7 @@
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
import * as o from '@angular/compiler/src/output/output_ast';
import {TypeScriptEmitter} from '@angular/compiler/src/output/ts_emitter';
-import {beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
-
-import {isBlank} from '../../src/facade/lang';
+import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
import {SimpleJsImportGenerator} from './output_emitter_util';
@@ -39,7 +37,7 @@ export function main() {
});
function emitStmt(stmt: o.Statement, exportedVars: string[] = null): string {
- if (isBlank(exportedVars)) {
+ if (!exportedVars) {
exportedVars = [];
}
return emitter.emitStatements(someModuleUrl, [stmt], exportedVars);
diff --git a/modules/@angular/compiler/test/pipe_resolver_mock_spec.ts b/modules/@angular/compiler/test/pipe_resolver_mock_spec.ts
index 272767d98c84..4c5b51d77ce3 100644
--- a/modules/@angular/compiler/test/pipe_resolver_mock_spec.ts
+++ b/modules/@angular/compiler/test/pipe_resolver_mock_spec.ts
@@ -7,9 +7,7 @@
*/
import {Injector, Pipe} from '@angular/core';
-import {beforeEach, ddescribe, describe, expect, iit, inject, it} from '@angular/core/testing/testing_internal';
-
-import {isBlank, stringify} from '../src/facade/lang';
+import {beforeEach, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {MockPipeResolver} from '../testing/index';
export function main() {
diff --git a/modules/@angular/compiler/test/resource_loader_mock_spec.ts b/modules/@angular/compiler/test/resource_loader_mock_spec.ts
index 9c22276e07b0..cda7fde65441 100644
--- a/modules/@angular/compiler/test/resource_loader_mock_spec.ts
+++ b/modules/@angular/compiler/test/resource_loader_mock_spec.ts
@@ -7,7 +7,7 @@
*/
import {MockResourceLoader} from '@angular/compiler/testing/resource_loader_mock';
-import {AsyncTestCompleter, beforeEach, ddescribe, describe, expect, iit, inject, it} from '@angular/core/testing/testing_internal';
+import {AsyncTestCompleter, beforeEach, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {isPresent} from '../src/facade/lang';
export function main() {
diff --git a/modules/@angular/compiler/test/runtime_compiler_spec.ts b/modules/@angular/compiler/test/runtime_compiler_spec.ts
index fc6bfe60e2a2..ca161ee9280b 100644
--- a/modules/@angular/compiler/test/runtime_compiler_spec.ts
+++ b/modules/@angular/compiler/test/runtime_compiler_spec.ts
@@ -7,9 +7,9 @@
*/
import {DirectiveResolver, ResourceLoader} from '@angular/compiler';
-import {Compiler, Component, ComponentFactory, Injectable, Injector, Input, NgModule, NgModuleFactory, Type} from '@angular/core';
-import {ComponentFixture, TestBed, async, fakeAsync, getTestBed, tick} from '@angular/core/testing';
-import {beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
+import {Compiler, Component, Injector, NgModule, NgModuleFactory} from '@angular/core';
+import {TestBed, async, fakeAsync, tick} from '@angular/core/testing';
+import {beforeEach, describe, inject, it} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing/matchers';
import {stringify} from '../src/facade/lang';
diff --git a/modules/@angular/compiler/test/schema/dom_element_schema_registry_spec.ts b/modules/@angular/compiler/test/schema/dom_element_schema_registry_spec.ts
index 4e4ecbce43bb..dee9bd9b4078 100644
--- a/modules/@angular/compiler/test/schema/dom_element_schema_registry_spec.ts
+++ b/modules/@angular/compiler/test/schema/dom_element_schema_registry_spec.ts
@@ -8,7 +8,7 @@
import {DomElementSchemaRegistry} from '@angular/compiler/src/schema/dom_element_schema_registry';
import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SecurityContext} from '@angular/core';
-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';
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
import {Element} from '../../src/ml_parser/ast';
@@ -105,6 +105,47 @@ export function main() {
expect(registry.getMappedPropName('exotic-unknown')).toEqual('exotic-unknown');
});
+ it('should return an error message when asserting event properties', () => {
+ let report = registry.validateProperty('onClick');
+ expect(report.error).toBeTruthy();
+ expect(report.msg)
+ .toEqual(
+ `Binding to event property 'onClick' is disallowed for security reasons, please use (Click)=...
+If 'onClick' is a directive input, make sure the directive is imported by the current module.`);
+
+ report = registry.validateProperty('onAnything');
+ expect(report.error).toBeTruthy();
+ expect(report.msg)
+ .toEqual(
+ `Binding to event property 'onAnything' is disallowed for security reasons, please use (Anything)=...
+If 'onAnything' is a directive input, make sure the directive is imported by the current module.`);
+ });
+
+ it('should return an error message when asserting event attributes', () => {
+ let report = registry.validateAttribute('onClick');
+ expect(report.error).toBeTruthy();
+ expect(report.msg)
+ .toEqual(
+ `Binding to event attribute 'onClick' is disallowed for security reasons, please use (Click)=...`);
+
+ report = registry.validateAttribute('onAnything');
+ expect(report.error).toBeTruthy();
+ expect(report.msg)
+ .toEqual(
+ `Binding to event attribute 'onAnything' is disallowed for security reasons, please use (Anything)=...`);
+ });
+
+ it('should not return an error message when asserting non-event properties or attributes',
+ () => {
+ let report = registry.validateProperty('title');
+ expect(report.error).toBeFalsy();
+ expect(report.msg).not.toBeDefined();
+
+ report = registry.validateProperty('exotic-unknown');
+ expect(report.error).toBeFalsy();
+ expect(report.msg).not.toBeDefined();
+ });
+
it('should return security contexts for elements', () => {
expect(registry.securityContext('iframe', 'srcdoc')).toBe(SecurityContext.HTML);
expect(registry.securityContext('p', 'innerHTML')).toBe(SecurityContext.HTML);
diff --git a/modules/@angular/compiler/test/shadow_css_spec.ts b/modules/@angular/compiler/test/shadow_css_spec.ts
index 4298e7a18b0e..6afb87de01da 100644
--- a/modules/@angular/compiler/test/shadow_css_spec.ts
+++ b/modules/@angular/compiler/test/shadow_css_spec.ts
@@ -7,7 +7,6 @@
*/
import {CssRule, ShadowCss, processRules} from '@angular/compiler/src/shadow_css';
-import {beforeEach, ddescribe, describe, expect, iit, it} from '@angular/core/testing/testing_internal';
import {normalizeCSS} from '@angular/platform-browser/testing/browser_util';
export function main() {
@@ -53,6 +52,18 @@ export function main() {
expect(s(css, 'a')).toEqual(expected);
});
+ it('should handle page rules', () => {
+ const css = '@page {div {font-size:50px;}}';
+ const expected = '@page {div[a] {font-size:50px;}}';
+ expect(s(css, 'a')).toEqual(expected);
+ });
+
+ it('should handle document rules', () => {
+ const css = '@document url(http://www.w3.org/) {div {font-size:50px;}}';
+ const expected = '@document url(http://www.w3.org/) {div[a] {font-size:50px;}}';
+ expect(s(css, 'a')).toEqual(expected);
+ });
+
it('should handle media rules with simple rules', () => {
const css = '@media screen and (max-width: 800px) {div {font-size: 50px;}} div {}';
const expected = '@media screen and (max-width:800px) {div[a] {font-size:50px;}} div[a] {}';
@@ -92,23 +103,66 @@ export function main() {
expect(s('one[attr*="value"] {}', 'a')).toEqual('one[attr*="value"][a] {}');
expect(s('one[attr|="value"] {}', 'a')).toEqual('one[attr|="value"][a] {}');
expect(s('one[attr~="value"] {}', 'a')).toEqual('one[attr~="value"][a] {}');
+ expect(s('one[attr="va lue"] {}', 'a')).toEqual('one[attr="va lue"][a] {}');
expect(s('one[attr] {}', 'a')).toEqual('one[attr][a] {}');
expect(s('[is="one"] {}', 'a')).toEqual('[is="one"][a] {}');
});
- it('should handle :host', () => {
- expect(s(':host {}', 'a', 'a-host')).toEqual('[a-host] {}');
+ describe((':host'), () => {
+ it('should handle no context',
+ () => { expect(s(':host {}', 'a', 'a-host')).toEqual('[a-host] {}'); });
+
+ it('should handle tag selector', () => {
+ expect(s(':host(ul) {}', 'a', 'a-host')).toEqual('ul[a-host] {}');
- expect(s(':host(.x,.y) {}', 'a', 'a-host')).toEqual('[a-host].x, [a-host].y {}');
+ });
+
+ it('should handle class selector',
+ () => { expect(s(':host(.x) {}', 'a', 'a-host')).toEqual('.x[a-host] {}'); });
+
+ it('should handle attribute selector', () => {
+ expect(s(':host([a="b"]) {}', 'a', 'a-host')).toEqual('[a="b"][a-host] {}');
+ expect(s(':host([a=b]) {}', 'a', 'a-host')).toEqual('[a="b"][a-host] {}');
+ });
+
+ it('should handle multiple tag selectors', () => {
+ expect(s(':host(ul,li) {}', 'a', 'a-host')).toEqual('ul[a-host], li[a-host] {}');
+ expect(s(':host(ul,li) > .z {}', 'a', 'a-host'))
+ .toEqual('ul[a-host] > .z[a], li[a-host] > .z[a] {}');
+ });
- expect(s(':host(.x,.y) > .z {}', 'a', 'a-host'))
- .toEqual('[a-host].x > .z[a], [a-host].y > .z[a] {}');
+ it('should handle multiple class selectors', () => {
+ expect(s(':host(.x,.y) {}', 'a', 'a-host')).toEqual('.x[a-host], .y[a-host] {}');
+ expect(s(':host(.x,.y) > .z {}', 'a', 'a-host'))
+ .toEqual('.x[a-host] > .z[a], .y[a-host] > .z[a] {}');
+ });
+
+ it('should handle multiple attribute selectors', () => {
+ expect(s(':host([a="b"],[c=d]) {}', 'a', 'a-host'))
+ .toEqual('[a="b"][a-host], [c="d"][a-host] {}');
+ });
});
- it('should handle :host-context', () => {
- expect(s(':host-context(.x) {}', 'a', 'a-host')).toEqual('[a-host].x, .x [a-host] {}');
- expect(s(':host-context(.x) > .y {}', 'a', 'a-host'))
- .toEqual('[a-host].x > .y[a], .x [a-host] > .y[a] {}');
+ describe((':host-context'), () => {
+ it('should handle tag selector', () => {
+ expect(s(':host-context(div) {}', 'a', 'a-host')).toEqual('div[a-host], div [a-host] {}');
+ expect(s(':host-context(ul) > .y {}', 'a', 'a-host'))
+ .toEqual('ul[a-host] > .y[a], ul [a-host] > .y[a] {}');
+ });
+
+ it('should handle class selector', () => {
+ expect(s(':host-context(.x) {}', 'a', 'a-host')).toEqual('.x[a-host], .x [a-host] {}');
+
+ expect(s(':host-context(.x) > .y {}', 'a', 'a-host'))
+ .toEqual('.x[a-host] > .y[a], .x [a-host] > .y[a] {}');
+ });
+
+ it('should handle attribute selector', () => {
+ expect(s(':host-context([a="b"]) {}', 'a', 'a-host'))
+ .toEqual('[a="b"][a-host], [a="b"] [a-host] {}');
+ expect(s(':host-context([a=b]) {}', 'a', 'a-host'))
+ .toEqual('[a=b][a-host], [a="b"] [a-host] {}');
+ });
});
it('should support polyfill-next-selector', () => {
@@ -117,6 +171,9 @@ export function main() {
css = s('polyfill-next-selector {content: "x > y"} z {}', 'a');
expect(css).toEqual('x[a] > y[a]{}');
+
+ css = s(`polyfill-next-selector {content: 'button[priority="1"]'} z {}`, 'a');
+ expect(css).toEqual('button[priority="1"][a]{}');
});
it('should support polyfill-unscoped-rule', () => {
@@ -125,6 +182,9 @@ export function main() {
css = s('polyfill-unscoped-rule {content: "#menu > .bar";color: blue;}', 'a');
expect(css).toContain('#menu > .bar {;color:blue;}');
+
+ css = s(`polyfill-unscoped-rule {content: 'button[priority="1"]'}`, 'a');
+ expect(css).toContain('button[priority="1"] {}');
});
it('should support multiple instances polyfill-unscoped-rule', () => {
@@ -138,10 +198,13 @@ export function main() {
it('should support polyfill-rule', () => {
let css = s('polyfill-rule {content: \':host.foo .bar\';color: blue;}', 'a', 'a-host');
- expect(css).toEqual('[a-host].foo .bar[a] {;color:blue;}');
+ expect(css).toEqual('.foo[a-host] .bar[a] {;color:blue;}');
css = s('polyfill-rule {content: ":host.foo .bar";color:blue;}', 'a', 'a-host');
- expect(css).toEqual('[a-host].foo .bar[a] {;color:blue;}');
+ expect(css).toEqual('.foo[a-host] .bar[a] {;color:blue;}');
+
+ css = s(`polyfill-rule {content: 'button[priority="1"]'}`, 'a', 'a-host');
+ expect(css).toEqual('button[priority="1"][a] {}');
});
it('should handle ::shadow', () => {
@@ -196,8 +259,8 @@ export function main() {
describe('processRules', () => {
describe('parse rules', () => {
function captureRules(input: string): CssRule[] {
- const result: any[] /** TODO #9100 */ = [];
- processRules(input, (cssRule: any /** TODO #9100 */) => {
+ const result: CssRule[] = [];
+ processRules(input, (cssRule) => {
result.push(cssRule);
return cssRule;
});
@@ -228,15 +291,15 @@ export function main() {
describe('modify rules', () => {
it('should allow to change the selector while preserving whitespaces', () => {
expect(processRules(
- '@import a; b {c {d}} e {f}', (cssRule: any /** TODO #9100 */) => new CssRule(
- cssRule.selector + '2', cssRule.content)))
+ '@import a; b {c {d}} e {f}',
+ (cssRule: CssRule) => new CssRule(cssRule.selector + '2', cssRule.content)))
.toEqual('@import a2; b2 {c {d}} e2 {f}');
});
it('should allow to change the content', () => {
expect(processRules(
- 'a {b}', (cssRule: any /** TODO #9100 */) =>
- new CssRule(cssRule.selector, cssRule.content + '2')))
+ 'a {b}',
+ (cssRule: CssRule) => new CssRule(cssRule.selector, cssRule.content + '2')))
.toEqual('a {b2}');
});
});
diff --git a/modules/@angular/compiler/test/spies.ts b/modules/@angular/compiler/test/spies.ts
index 88d92fb263fa..118808a2c93b 100644
--- a/modules/@angular/compiler/test/spies.ts
+++ b/modules/@angular/compiler/test/spies.ts
@@ -8,7 +8,7 @@
import {ResourceLoader} from '@angular/compiler/src/resource_loader';
-import {SpyObject, proxy} from '@angular/core/testing/testing_internal';
+import {SpyObject} from '@angular/core/testing/testing_internal';
export class SpyResourceLoader extends SpyObject {
constructor() { super(ResourceLoader); }
diff --git a/modules/@angular/compiler/test/template_parser/template_parser_spec.ts b/modules/@angular/compiler/test/template_parser/template_parser_spec.ts
index 00a4842d46c0..f3786927888e 100644
--- a/modules/@angular/compiler/test/template_parser/template_parser_spec.ts
+++ b/modules/@angular/compiler/test/template_parser/template_parser_spec.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompilePipeMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata} from '@angular/compiler/src/compile_metadata';
+import {CompileAnimationEntryMetadata, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompilePipeMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata} from '@angular/compiler/src/compile_metadata';
import {DomElementSchemaRegistry} from '@angular/compiler/src/schema/dom_element_schema_registry';
import {ElementSchemaRegistry} from '@angular/compiler/src/schema/element_schema_registry';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAstType, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '@angular/compiler/src/template_parser/template_ast';
@@ -15,8 +15,7 @@ import {TEST_COMPILER_PROVIDERS} from '@angular/compiler/testing/test_bindings';
import {SchemaMetadata, SecurityContext, Type} from '@angular/core';
import {Console} from '@angular/core/src/console';
import {TestBed} from '@angular/core/testing';
-import {afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
-
+import {beforeEach, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {Identifiers, identifierToken, resolveIdentifierToken} from '../../src/identifiers';
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../src/ml_parser/interpolation_config';
import {MockSchemaRegistry} from '../../testing/index';
@@ -27,14 +26,15 @@ const someModuleUrl = 'package:someModule';
const MOCK_SCHEMA_REGISTRY = [{
provide: ElementSchemaRegistry,
useValue: new MockSchemaRegistry(
- {'invalidProp': false}, {'mappedAttr': 'mappedProp'}, {'unknown': false, 'un-known': false}),
+ {'invalidProp': false}, {'mappedAttr': 'mappedProp'}, {'unknown': false, 'un-known': false},
+ ['onEvent'], ['onEvent']),
}];
export function main() {
var ngIf: CompileDirectiveMetadata;
- var parse:
- (template: string, directives: CompileDirectiveMetadata[], pipes?: CompilePipeMetadata[]) =>
- TemplateAst[];
+ var parse: (
+ template: string, directives: CompileDirectiveMetadata[], pipes?: CompilePipeMetadata[],
+ schemas?: SchemaMetadata[]) => TemplateAst[];
var console: ArrayConsole;
function commonBeforeEach() {
@@ -43,14 +43,18 @@ export function main() {
TestBed.configureCompiler({providers: [{provide: Console, useValue: console}]});
});
beforeEach(inject([TemplateParser], (parser: TemplateParser) => {
+ var someAnimation = new CompileAnimationEntryMetadata('someAnimation', []);
+ var someTemplate = new CompileTemplateMetadata({animations: [someAnimation]});
var component = CompileDirectiveMetadata.create({
selector: 'root',
+ template: someTemplate,
type: new CompileTypeMetadata(
{moduleUrl: someModuleUrl, name: 'Root', reference: {} as Type}),
isComponent: true
});
ngIf = CompileDirectiveMetadata.create({
selector: '[ngIf]',
+ template: someTemplate,
type: new CompileTypeMetadata(
{moduleUrl: someModuleUrl, name: 'NgIf', reference: {} as Type}),
inputs: ['ngIf']
@@ -138,1487 +142,1529 @@ export function main() {
});
});
- describe('TemplateParser', () => {
- beforeEach(() => {
- TestBed.configureCompiler({providers: [TEST_COMPILER_PROVIDERS, MOCK_SCHEMA_REGISTRY]});
- });
+ describe(
+ 'TemplateParser', () => {
+ beforeEach(() => {
+ TestBed.configureCompiler({providers: [TEST_COMPILER_PROVIDERS, MOCK_SCHEMA_REGISTRY]});
+ });
- commonBeforeEach();
+ commonBeforeEach();
- describe('parse', () => {
- describe('nodes without bindings', () => {
+ describe('parse', () => {
+ describe('nodes without bindings', () => {
- it('should parse text nodes', () => {
- expect(humanizeTplAst(parse('a', []))).toEqual([[TextAst, 'a']]);
- });
+ it('should parse text nodes', () => {
+ expect(humanizeTplAst(parse('a', []))).toEqual([[TextAst, 'a']]);
+ });
- it('should parse elements with attributes', () => {
- expect(humanizeTplAst(parse('', [
- ]))).toEqual([[ElementAst, 'div'], [AttrAst, 'a', 'b']]);
- });
- });
+ it('should parse elements with attributes', () => {
+ expect(humanizeTplAst(parse('
', [
+ ]))).toEqual([[ElementAst, 'div'], [AttrAst, 'a', 'b']]);
+ });
+ });
- it('should parse ngContent', () => {
- var parsed = parse('
', []);
- expect(humanizeTplAst(parsed)).toEqual([[NgContentAst]]);
- });
+ it('should parse ngContent', () => {
+ var parsed = parse('', []);
+ expect(humanizeTplAst(parsed)).toEqual([[NgContentAst]]);
+ });
- it('should parse ngContent regardless the namespace', () => {
- var parsed = parse(' ', []);
- expect(humanizeTplAst(parsed)).toEqual([
- [ElementAst, ':svg:svg'],
- [NgContentAst],
- ]);
- });
+ it('should parse ngContent regardless the namespace', () => {
+ var parsed = parse(' ', []);
+ expect(humanizeTplAst(parsed)).toEqual([
+ [ElementAst, ':svg:svg'],
+ [NgContentAst],
+ ]);
+ });
- it('should parse bound text nodes', () => {
- expect(humanizeTplAst(parse('{{a}}', []))).toEqual([[BoundTextAst, '{{ a }}']]);
- });
+ it('should parse bound text nodes', () => {
+ expect(humanizeTplAst(parse('{{a}}', []))).toEqual([[BoundTextAst, '{{ a }}']]);
+ });
- it('should parse with custom interpolation config',
- inject([TemplateParser], (parser: TemplateParser) => {
- const component = CompileDirectiveMetadata.create({
- selector: 'test',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'Test', reference: {} as Type}),
- isComponent: true,
- template: new CompileTemplateMetadata({interpolation: ['{%', '%}']})
- });
- expect(humanizeTplAst(parser.parse(component, '{%a%}', [], [], [], 'TestComp'), {
- start: '{%',
- end: '%}'
- })).toEqual([[BoundTextAst, '{% a %}']]);
- }));
-
- describe('bound properties', () => {
-
- it('should parse mixed case bound properties', () => {
- expect(humanizeTplAst(parse('', []))).toEqual([
- [ElementAst, 'div'],
- [BoundElementPropertyAst, PropertyBindingType.Property, 'someProp', 'v', null]
- ]);
- });
+ it('should parse with custom interpolation config',
+ inject([TemplateParser], (parser: TemplateParser) => {
+ const component = CompileDirectiveMetadata.create({
+ selector: 'test',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'Test', reference: {} as Type
}),
+ isComponent: true,
+ template: new CompileTemplateMetadata({interpolation: ['{%', '%}']})
+ });
+ expect(humanizeTplAst(parser.parse(component, '{%a%}', [], [], [], 'TestComp'), {
+ start: '{%',
+ end: '%}'
+ })).toEqual([[BoundTextAst, '{% a %}']]);
+ }));
+
+ describe('bound properties', () => {
+
+ it('should parse mixed case bound properties', () => {
+ expect(humanizeTplAst(parse('', []))).toEqual([
+ [ElementAst, 'div'],
+ [BoundElementPropertyAst, PropertyBindingType.Property, 'someProp', 'v', null]
+ ]);
+ });
- it('should parse dash case bound properties', () => {
- expect(humanizeTplAst(parse('
', []))).toEqual([
- [ElementAst, 'div'],
- [BoundElementPropertyAst, PropertyBindingType.Property, 'some-prop', 'v', null]
- ]);
- });
+ it('should parse dash case bound properties', () => {
+ expect(humanizeTplAst(parse('
', []))).toEqual([
+ [ElementAst, 'div'],
+ [BoundElementPropertyAst, PropertyBindingType.Property, 'some-prop', 'v', null]
+ ]);
+ });
- it('should normalize property names via the element schema', () => {
- expect(humanizeTplAst(parse('
', []))).toEqual([
- [ElementAst, 'div'],
- [BoundElementPropertyAst, PropertyBindingType.Property, 'mappedProp', 'v', null]
- ]);
- });
+ it('should normalize property names via the element schema', () => {
+ expect(humanizeTplAst(parse('
', []))).toEqual([
+ [ElementAst, 'div'],
+ [BoundElementPropertyAst, PropertyBindingType.Property, 'mappedProp', 'v', null]
+ ]);
+ });
- it('should parse mixed case bound attributes', () => {
- expect(humanizeTplAst(parse('
', []))).toEqual([
- [ElementAst, 'div'],
- [BoundElementPropertyAst, PropertyBindingType.Attribute, 'someAttr', 'v', null]
- ]);
- });
+ it('should parse mixed case bound attributes', () => {
+ expect(humanizeTplAst(parse('
', []))).toEqual([
+ [ElementAst, 'div'],
+ [BoundElementPropertyAst, PropertyBindingType.Attribute, 'someAttr', 'v', null]
+ ]);
+ });
- it('should parse and dash case bound classes', () => {
- expect(humanizeTplAst(parse('
', []))).toEqual([
- [ElementAst, 'div'],
- [BoundElementPropertyAst, PropertyBindingType.Class, 'some-class', 'v', null]
- ]);
- });
+ it('should parse and dash case bound classes', () => {
+ expect(humanizeTplAst(parse('
', []))).toEqual([
+ [ElementAst, 'div'],
+ [BoundElementPropertyAst, PropertyBindingType.Class, 'some-class', 'v', null]
+ ]);
+ });
- it('should parse mixed case bound classes', () => {
- expect(humanizeTplAst(parse('
', []))).toEqual([
- [ElementAst, 'div'],
- [BoundElementPropertyAst, PropertyBindingType.Class, 'someClass', 'v', null]
- ]);
- });
+ it('should parse mixed case bound classes', () => {
+ expect(humanizeTplAst(parse('
', []))).toEqual([
+ [ElementAst, 'div'],
+ [BoundElementPropertyAst, PropertyBindingType.Class, 'someClass', 'v', null]
+ ]);
+ });
- it('should parse mixed case bound styles', () => {
- expect(humanizeTplAst(parse('
', []))).toEqual([
- [ElementAst, 'div'],
- [BoundElementPropertyAst, PropertyBindingType.Style, 'someStyle', 'v', null]
- ]);
- });
+ it('should parse mixed case bound styles', () => {
+ expect(humanizeTplAst(parse('
', []))).toEqual([
+ [ElementAst, 'div'],
+ [BoundElementPropertyAst, PropertyBindingType.Style, 'someStyle', 'v', null]
+ ]);
+ });
- it('should report invalid prefixes', () => {
- expect(() => parse('
', []))
- .toThrowError(
- `Template parse errors:\nInvalid property name 'atTr.foo' ("
][atTr.foo]>"): TestComp@0:3`);
- expect(() => parse('
', []))
- .toThrowError(
- `Template parse errors:\nInvalid property name 'sTyle.foo' ("
][sTyle.foo]>"): TestComp@0:3`);
- expect(() => parse('
', []))
- .toThrowError(
- `Template parse errors:\nInvalid property name 'Class.foo' ("
][Class.foo]>"): TestComp@0:3`);
- expect(() => parse('
', []))
- .toThrowError(
- `Template parse errors:\nInvalid property name 'bar.foo' ("
][bar.foo]>"): TestComp@0:3`);
- });
+ it('should report invalid prefixes', () => {
+ expect(() => parse('
', []))
+ .toThrowError(
+ `Template parse errors:\nInvalid property name 'atTr.foo' ("
][atTr.foo]>"): TestComp@0:3`);
+ expect(() => parse('
', []))
+ .toThrowError(
+ `Template parse errors:\nInvalid property name 'sTyle.foo' ("
][sTyle.foo]>"): TestComp@0:3`);
+ expect(() => parse('
', []))
+ .toThrowError(
+ `Template parse errors:\nInvalid property name 'Class.foo' ("
][Class.foo]>"): TestComp@0:3`);
+ expect(() => parse('
', []))
+ .toThrowError(
+ `Template parse errors:\nInvalid property name 'bar.foo' ("
][bar.foo]>"): TestComp@0:3`);
+ });
- describe('errors', () => {
- it('should throw error when binding to an unknown property', () => {
- expect(() => parse(' ', []))
- .toThrowError(`Template parse errors:
+ describe('errors', () => {
+ it('should throw error when binding to an unknown property', () => {
+ expect(() => parse(' ', []))
+ .toThrowError(`Template parse errors:
Can't bind to 'invalidProp' since it isn't a known property of 'my-component'.
1. If 'my-component' is an Angular component and it has 'invalidProp' input, then verify that it is part of this module.
2. If 'my-component' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message.
("][invalidProp]="bar"> "): TestComp@0:14`);
- });
+ });
- it('should throw error when binding to an unknown element w/o bindings', () => {
- expect(() => parse(' ', [])).toThrowError(`Template parse errors:
+ it('should throw error when binding to an unknown element w/o bindings', () => {
+ expect(() => parse(' ', [])).toThrowError(`Template parse errors:
'unknown' is not a known element:
1. If 'unknown' is an Angular component, then verify that it is part of this module.
2. If 'unknown' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("[ERROR ->] "): TestComp@0:0`);
- });
+ });
- it('should throw error when binding to an unknown custom element w/o bindings', () => {
- expect(() => parse(' ', [])).toThrowError(`Template parse errors:
+ it('should throw error when binding to an unknown custom element w/o bindings',
+ () => {
+ expect(() => parse(' ', []))
+ .toThrowError(`Template parse errors:
'un-known' is not a known element:
1. If 'un-known' is an Angular component, then verify that it is part of this module.
2. If 'un-known' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("[ERROR ->] "): TestComp@0:0`);
- });
- });
-
- it('should parse bound properties via [...] and not report them as attributes', () => {
- expect(humanizeTplAst(parse('
', []))).toEqual([
- [ElementAst, 'div'],
- [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null]
- ]);
- });
+ });
+
+ it('should throw error when binding to an invalid property', () => {
+ expect(() => parse('
', []))
+ .toThrowError(`Template parse errors:
+Binding to property 'onEvent' is disallowed for security reasons ("
][onEvent]="bar"> "): TestComp@0:14`);
+ });
+
+ it('should throw error when binding to an invalid attribute', () => {
+ expect(() => parse('
', []))
+ .toThrowError(`Template parse errors:
+Binding to attribute 'onEvent' is disallowed for security reasons ("
][attr.onEvent]="bar"> "): TestComp@0:14`);
+ });
+ });
- it('should parse bound properties via bind- and not report them as attributes', () => {
- expect(humanizeTplAst(parse('
', []))).toEqual([
- [ElementAst, 'div'],
- [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null]
- ]);
- });
+ it('should parse bound properties via [...] and not report them as attributes', () => {
+ expect(humanizeTplAst(parse('
', []))).toEqual([
+ [ElementAst, 'div'],
+ [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null]
+ ]);
+ });
- it('should parse bound properties via {{...}} and not report them as attributes', () => {
- expect(humanizeTplAst(parse('
', []))).toEqual([
- [ElementAst, 'div'],
- [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', '{{ v }}', null]
- ]);
- });
+ it('should parse bound properties via bind- and not report them as attributes', () => {
+ expect(humanizeTplAst(parse('
', []))).toEqual([
+ [ElementAst, 'div'],
+ [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null]
+ ]);
+ });
- it('should parse bound properties via bind-animate- and not report them as animation properties',
- () => {
- expect(humanizeTplAst(parse('
', []))).toEqual([
- [ElementAst, 'div'],
- [
- BoundElementPropertyAst, PropertyBindingType.Animation, 'something', 'value2', null
- ]
- ]);
- });
-
- it('should throw an error when parsing detects non-bound properties via @ that contain a value',
- () => {
- expect(() => { parse('
', []); })
- .toThrowError(
- /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. \("
\]@something="value2">"\): TestComp@0:5/);
- });
-
- it('should not issue a warning when host attributes contain a valid property-bound animation trigger',
- () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: 'div',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
}),
- host: {'[@prop]': 'expr'}
- });
+ it('should parse bound properties via {{...}} and not report them as attributes',
+ () => {
+ expect(humanizeTplAst(parse('', []))).toEqual([
+ [ElementAst, 'div'],
+ [
+ BoundElementPropertyAst, PropertyBindingType.Property, 'prop', '{{ v }}', null
+ ]
+ ]);
+ });
+
+ it('should parse bound properties via bind-animate- and not report them as attributes',
+ () => {
+ expect(
+ humanizeTplAst(parse('
', [], [], [])))
+ .toEqual([
+ [ElementAst, 'div'],
+ [
+ BoundElementPropertyAst, PropertyBindingType.Animation, 'someAnimation',
+ 'value2', null
+ ]
+ ]);
+ });
+
+ it('should throw an error when parsing detects non-bound properties via @ that contain a value',
+ () => {
+ expect(() => { parse('
', [], [], []); })
+ .toThrowError(
+ /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. \("
\]@someAnimation="value2">"\): TestComp@0:5/);
+ });
+
+ it('should not issue a warning when host attributes contain a valid property-bound animation trigger',
+ () => {
+ const animationEntries = [new CompileAnimationEntryMetadata('prop', [])];
+ var dirA = CompileDirectiveMetadata.create({
+ selector: 'div',
+ template: new CompileTemplateMetadata({animations: animationEntries}),
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
}),
+ host: {'[@prop]': 'expr'}
+ });
+
+ humanizeTplAst(parse('
', [dirA]));
+ expect(console.warnings.length).toEqual(0);
+ });
+
+ it('should throw descriptive error when a host binding is not a string expression', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: 'broken',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
+ host: {'[class.foo]': null}
+ });
+
+ expect(() => { parse(' ', [dirA]); })
+ .toThrowError(
+ `Template parse errors:\nValue of the host property binding "class.foo" needs to be a string representing an expression but got "null" (object) ("[ERROR ->] "): TestComp@0:0, Directive DirA`);
+ });
- humanizeTplAst(parse('
', [dirA]));
- expect(console.warnings.length).toEqual(0);
- });
+ it('should throw descriptive error when a host event is not a string expression', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: 'broken',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
+ host: {'(click)': null}
+ });
+
+ expect(() => { parse(' ', [dirA]); })
+ .toThrowError(
+ `Template parse errors:\nValue of the host listener "click" needs to be a string representing an expression but got "null" (object) ("[ERROR ->] "): TestComp@0:0, Directive DirA`);
+ });
- it('should throw descriptive error when a host binding is not a string expression', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: 'broken',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
- host: {'[class.foo]': null}
+ it('should not issue a warning when an animation property is bound without an expression',
+ () => {
+ humanizeTplAst(parse('', [], [], []));
+ expect(console.warnings.length).toEqual(0);
+ });
+
+ it('should parse bound properties via [@] and not report them as attributes', () => {
+ expect(humanizeTplAst(parse('
', [], [], []))).toEqual([
+ [ElementAst, 'div'],
+ [
+ BoundElementPropertyAst, PropertyBindingType.Animation, 'someAnimation', 'value2',
+ null
+ ]
+ ]);
+ });
});
- expect(() => { parse('
', [dirA]); })
- .toThrowError(
- `Template parse errors:\nValue of the host property binding "class.foo" needs to be a string representing an expression but got "null" (object) ("[ERROR ->]
"): TestComp@0:0, Directive DirA`);
- });
+ describe('events', () => {
- it('should throw descriptive error when a host event is not a string expression', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: 'broken',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
}),
- host: {'(click)': null}
- });
+ it('should parse bound events with a target', () => {
+ expect(humanizeTplAst(parse('', []))).toEqual([
+ [ElementAst, 'div'],
+ [BoundEventAst, 'event', 'window', 'v'],
+ ]);
+ });
- expect(() => { parse('
', [dirA]); })
- .toThrowError(
- `Template parse errors:\nValue of the host listener "click" needs to be a string representing an expression but got "null" (object) ("[ERROR ->]
"): TestComp@0:0, Directive DirA`);
- });
+ it('should report an error on empty expression', () => {
+ expect(() => parse('
', []))
+ .toThrowError(/Empty expressions are not allowed/);
- it('should not issue a warning when an animation property is bound without an expression',
- () => {
- humanizeTplAst(parse('
', []));
- expect(console.warnings.length).toEqual(0);
- });
-
- it('should parse bound properties via [@] and not report them as attributes', () => {
- expect(humanizeTplAst(parse('
', []))).toEqual([
- [ElementAst, 'div'],
- [BoundElementPropertyAst, PropertyBindingType.Animation, 'something', 'value2', null]
- ]);
- });
- });
+ expect(() => parse('
', []))
+ .toThrowError(/Empty expressions are not allowed/);
+ });
- describe('events', () => {
+ it('should parse bound events via (...) and not report them as attributes', () => {
+ expect(humanizeTplAst(parse('
', [
+ ]))).toEqual([[ElementAst, 'div'], [BoundEventAst, 'event', null, 'v']]);
+ });
- it('should parse bound events with a target', () => {
- expect(humanizeTplAst(parse('
', []))).toEqual([
- [ElementAst, 'div'],
- [BoundEventAst, 'event', 'window', 'v'],
- ]);
- });
+ it('should parse event names case sensitive', () => {
+ expect(humanizeTplAst(parse('
', [
+ ]))).toEqual([[ElementAst, 'div'], [BoundEventAst, 'some-event', null, 'v']]);
+ expect(humanizeTplAst(parse('
', [
+ ]))).toEqual([[ElementAst, 'div'], [BoundEventAst, 'someEvent', null, 'v']]);
+ });
- it('should report an error on empty expression', () => {
- expect(() => parse('
', []))
- .toThrowError(/Empty expressions are not allowed/);
+ it('should parse bound events via on- and not report them as attributes', () => {
+ expect(humanizeTplAst(parse('
', [
+ ]))).toEqual([[ElementAst, 'div'], [BoundEventAst, 'event', null, 'v']]);
+ });
- expect(() => parse('
', []))
- .toThrowError(/Empty expressions are not allowed/);
- });
+ it('should allow events on explicit embedded templates that are emitted by a directive',
+ () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: 'template',
+ outputs: ['e'],
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
})
+ });
+ expect(humanizeTplAst(parse(' ', [dirA]))).toEqual([
+ [EmbeddedTemplateAst],
+ [BoundEventAst, 'e', null, 'f'],
+ [DirectiveAst, dirA],
+ ]);
+ });
+ });
- it('should parse bound events via (...) and not report them as attributes', () => {
- expect(humanizeTplAst(parse('', [
- ]))).toEqual([[ElementAst, 'div'], [BoundEventAst, 'event', null, 'v']]);
- });
+ describe('bindon', () => {
+ it('should parse bound events and properties via [(...)] and not report them as attributes',
+ () => {
+ expect(humanizeTplAst(parse('
', []))).toEqual([
+ [ElementAst, 'div'],
+ [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null],
+ [BoundEventAst, 'propChange', null, 'v = $event']
+ ]);
+ });
+
+ it('should parse bound events and properties via bindon- and not report them as attributes',
+ () => {
+ expect(humanizeTplAst(parse('
', []))).toEqual([
+ [ElementAst, 'div'],
+ [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null],
+ [BoundEventAst, 'propChange', null, 'v = $event']
+ ]);
+ });
- it('should parse event names case sensitive', () => {
- expect(humanizeTplAst(parse('
', [
- ]))).toEqual([[ElementAst, 'div'], [BoundEventAst, 'some-event', null, 'v']]);
- expect(humanizeTplAst(parse('
', [
- ]))).toEqual([[ElementAst, 'div'], [BoundEventAst, 'someEvent', null, 'v']]);
- });
+ });
- it('should parse bound events via on- and not report them as attributes', () => {
- expect(humanizeTplAst(parse('
', [
- ]))).toEqual([[ElementAst, 'div'], [BoundEventAst, 'event', null, 'v']]);
- });
+ describe('directives', () => {
+ it('should order directives by the directives array in the View and match them only once',
+ () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: '[a]',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
})
+ });
+ var dirB = CompileDirectiveMetadata.create({
+ selector: '[b]',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type})
+ });
+ var dirC = CompileDirectiveMetadata.create({
+ selector: '[c]',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirC', reference: {} as Type})
+ });
+ expect(humanizeTplAst(parse('', [dirA, dirB, dirC]))).toEqual([
+ [ElementAst, 'div'], [AttrAst, 'a', ''], [AttrAst, 'c', ''], [AttrAst, 'b', ''],
+ [AttrAst, 'a', ''], [AttrAst, 'b', ''], [DirectiveAst, dirA],
+ [DirectiveAst, dirB], [DirectiveAst, dirC]
+ ]);
+ });
+
+ it('should locate directives in property bindings', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: '[a=b]',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
})
+ });
+ var dirB = CompileDirectiveMetadata.create({
+ selector: '[b]',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type})
+ });
+ expect(humanizeTplAst(parse('', [dirA, dirB]))).toEqual([
+ [ElementAst, 'div'],
+ [BoundElementPropertyAst, PropertyBindingType.Property, 'a', 'b', null],
+ [DirectiveAst, dirA]
+ ]);
+ });
- it('should allow events on explicit embedded templates that are emitted by a directive',
- () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: 'template',
- outputs: ['e'],
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
})
- });
- expect(humanizeTplAst(parse(' ', [dirA]))).toEqual([
- [EmbeddedTemplateAst],
- [BoundEventAst, 'e', null, 'f'],
- [DirectiveAst, dirA],
- ]);
- });
- });
+ it('should locate directives in event bindings', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: '[a]',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type})
+ });
- describe('bindon', () => {
- it('should parse bound events and properties via [(...)] and not report them as attributes',
- () => {
- expect(humanizeTplAst(parse('', []))).toEqual([
- [ElementAst, 'div'],
- [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null],
- [BoundEventAst, 'propChange', null, 'v = $event']
- ]);
- });
-
- it('should parse bound events and properties via bindon- and not report them as attributes',
- () => {
- expect(humanizeTplAst(parse('
', []))).toEqual([
- [ElementAst, 'div'],
- [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null],
- [BoundEventAst, 'propChange', null, 'v = $event']
- ]);
- });
+ expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
+ [ElementAst, 'div'], [BoundEventAst, 'a', null, 'b'], [DirectiveAst, dirA]
+ ]);
+ });
- });
+ it('should parse directive host properties', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: 'div',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
}),
+ host: {'[a]': 'expr'}
+ });
+ expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
+ [ElementAst, 'div'], [DirectiveAst, dirA],
+ [BoundElementPropertyAst, PropertyBindingType.Property, 'a', 'expr', null]
+ ]);
+ });
- describe('directives', () => {
- it('should order directives by the directives array in the View and match them only once',
- () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: '[a]',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type})
- });
- var dirB = CompileDirectiveMetadata.create({
- selector: '[b]',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type})
- });
- var dirC = CompileDirectiveMetadata.create({
- selector: '[c]',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirC', reference: {} as Type})
- });
- expect(humanizeTplAst(parse('', [dirA, dirB, dirC]))).toEqual([
- [ElementAst, 'div'], [AttrAst, 'a', ''], [AttrAst, 'c', ''], [AttrAst, 'b', ''],
- [AttrAst, 'a', ''], [AttrAst, 'b', ''], [DirectiveAst, dirA], [DirectiveAst, dirB],
- [DirectiveAst, dirC]
- ]);
- });
-
- it('should locate directives in property bindings', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: '[a=b]',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
})
- });
- var dirB = CompileDirectiveMetadata.create({
- selector: '[b]',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type})
- });
- expect(humanizeTplAst(parse('', [dirA, dirB]))).toEqual([
- [ElementAst, 'div'],
- [BoundElementPropertyAst, PropertyBindingType.Property, 'a', 'b', null],
- [DirectiveAst, dirA]
- ]);
- });
+ it('should parse directive host listeners', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: 'div',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
}),
+ host: {'(a)': 'expr'}
+ });
+ expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
+ [ElementAst, 'div'], [DirectiveAst, dirA], [BoundEventAst, 'a', null, 'expr']
+ ]);
+ });
- it('should locate directives in event bindings', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: '[a]',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type})
- });
+ it('should parse directive properties', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: 'div',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
+ inputs: ['aProp']
+ });
+ expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
+ [ElementAst, 'div'], [DirectiveAst, dirA],
+ [BoundDirectivePropertyAst, 'aProp', 'expr']
+ ]);
+ });
- expect(humanizeTplAst(parse('', [dirA]))).toEqual([
- [ElementAst, 'div'], [BoundEventAst, 'a', null, 'b'], [DirectiveAst, dirA]
- ]);
- });
+ it('should parse renamed directive properties', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: 'div',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
}),
+ inputs: ['b:a']
+ });
+ expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
+ [ElementAst, 'div'], [DirectiveAst, dirA],
+ [BoundDirectivePropertyAst, 'b', 'expr']
+ ]);
+ });
- it('should parse directive host properties', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: 'div',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
- host: {'[a]': 'expr'}
- });
- expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
- [ElementAst, 'div'], [DirectiveAst, dirA],
- [BoundElementPropertyAst, PropertyBindingType.Property, 'a', 'expr', null]
- ]);
- });
+ it('should parse literal directive properties', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: 'div',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
+ inputs: ['a']
+ });
+ expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
+ [ElementAst, 'div'], [AttrAst, 'a', 'literal'], [DirectiveAst, dirA],
+ [BoundDirectivePropertyAst, 'a', '"literal"']
+ ]);
+ });
- it('should parse directive host listeners', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: 'div',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
- host: {'(a)': 'expr'}
- });
- expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
- [ElementAst, 'div'], [DirectiveAst, dirA], [BoundEventAst, 'a', null, 'expr']
- ]);
- });
+ it('should favor explicit bound properties over literal properties', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: 'div',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
+ inputs: ['a']
+ });
+ expect(humanizeTplAst(parse('
', [dirA])))
+ .toEqual([
+ [ElementAst, 'div'], [AttrAst, 'a', 'literal'], [DirectiveAst, dirA],
+ [BoundDirectivePropertyAst, 'a', '"literal2"']
+ ]);
+ });
- it('should parse directive properties', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: 'div',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
- inputs: ['aProp']
- });
- expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
- [ElementAst, 'div'], [DirectiveAst, dirA],
- [BoundDirectivePropertyAst, 'aProp', 'expr']
- ]);
- });
+ it('should support optional directive properties', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: 'div',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
+ inputs: ['a']
+ });
+ expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
+ [ElementAst, 'div'], [DirectiveAst, dirA]
+ ]);
+ });
- it('should parse renamed directive properties', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: 'div',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
- inputs: ['b:a']
});
- expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
- [ElementAst, 'div'], [DirectiveAst, dirA], [BoundDirectivePropertyAst, 'b', 'expr']
- ]);
- });
- it('should parse literal directive properties', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: 'div',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
- inputs: ['a']
- });
- expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
- [ElementAst, 'div'], [AttrAst, 'a', 'literal'], [DirectiveAst, dirA],
- [BoundDirectivePropertyAst, 'a', '"literal"']
- ]);
- });
+ describe('providers', () => {
+ var nextProviderId: number;
+
+ function createToken(value: string): CompileTokenMetadata {
+ let token: CompileTokenMetadata;
+ if (value.startsWith('type:')) {
+ const name = value.substring(5);
+ token = new CompileTokenMetadata({
+ identifier: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name, reference: name as any as Type})
+ });
+ } else {
+ token = new CompileTokenMetadata({value: value});
+ }
+ return token;
+ }
- it('should favor explicit bound properties over literal properties', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: 'div',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
- inputs: ['a']
- });
- expect(humanizeTplAst(parse('
', [dirA])))
- .toEqual([
- [ElementAst, 'div'], [AttrAst, 'a', 'literal'], [DirectiveAst, dirA],
- [BoundDirectivePropertyAst, 'a', '"literal2"']
- ]);
- });
+ function createDep(value: string): CompileDiDependencyMetadata {
+ var isOptional = false;
+ if (value.startsWith('optional:')) {
+ isOptional = true;
+ value = value.substring(9);
+ }
+ var isSelf = false;
+ if (value.startsWith('self:')) {
+ isSelf = true;
+ value = value.substring(5);
+ }
+ var isHost = false;
+ if (value.startsWith('host:')) {
+ isHost = true;
+ value = value.substring(5);
+ }
+ return new CompileDiDependencyMetadata({
+ token: createToken(value),
+ isOptional: isOptional,
+ isSelf: isSelf,
+ isHost: isHost
+ });
+ }
- it('should support optional directive properties', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: 'div',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
- inputs: ['a']
- });
- expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
- [ElementAst, 'div'], [DirectiveAst, dirA]
- ]);
- });
+ function createProvider(
+ token: string, {multi = false, deps = []}: {multi?: boolean, deps?: string[]} = {}):
+ CompileProviderMetadata {
+ const name = `provider${nextProviderId++}`;
+ return new CompileProviderMetadata({
+ token: createToken(token),
+ multi: multi,
+ useClass: new CompileTypeMetadata({name, reference: name as any as Type}),
+ deps: deps.map(createDep)
+ });
+ }
- });
+ function createDir(
+ selector: string,
+ {providers = null, viewProviders = null, deps = [], queries = []}: {
+ providers?: CompileProviderMetadata[],
+ viewProviders?: CompileProviderMetadata[],
+ deps?: string[],
+ queries?: string[]
+ } = {}): CompileDirectiveMetadata {
+ var isComponent = !selector.startsWith('[');
+ return CompileDirectiveMetadata.create({
+ selector: selector,
+ type: new CompileTypeMetadata({
+ moduleUrl: someModuleUrl,
+ name: selector,
+ diDeps: deps.map(createDep),
+ reference: selector as any as Type
+ }),
+ isComponent: isComponent,
+ template: new CompileTemplateMetadata({ngContentSelectors: []}),
+ providers: providers,
+ viewProviders: viewProviders,
+ queries: queries.map(
+ (value) => new CompileQueryMetadata({selectors: [createToken(value)]}))
+ });
+ }
- describe('providers', () => {
- var nextProviderId: number;
+ beforeEach(() => { nextProviderId = 0; });
- function createToken(value: string): CompileTokenMetadata {
- let token: CompileTokenMetadata;
- if (value.startsWith('type:')) {
- const name = value.substring(5);
- token = new CompileTokenMetadata({
- identifier: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name, reference: name as any as Type})
+ it('should provide a component', () => {
+ var comp = createDir('my-comp');
+ var elAst: ElementAst = parse('', [comp])[0];
+ expect(elAst.providers.length).toBe(1);
+ expect(elAst.providers[0].providerType).toBe(ProviderAstType.Component);
+ expect(elAst.providers[0].providers[0].useClass).toBe(comp.type);
});
- } else {
- token = new CompileTokenMetadata({value: value});
- }
- return token;
- }
-
- function createDep(value: string): CompileDiDependencyMetadata {
- var isOptional = false;
- if (value.startsWith('optional:')) {
- isOptional = true;
- value = value.substring(9);
- }
- var isSelf = false;
- if (value.startsWith('self:')) {
- isSelf = true;
- value = value.substring(5);
- }
- var isHost = false;
- if (value.startsWith('host:')) {
- isHost = true;
- value = value.substring(5);
- }
- return new CompileDiDependencyMetadata(
- {token: createToken(value), isOptional: isOptional, isSelf: isSelf, isHost: isHost});
- }
-
- function createProvider(
- token: string, {multi = false, deps = []}: {multi?: boolean, deps?: string[]} = {}):
- CompileProviderMetadata {
- const name = `provider${nextProviderId++}`;
- return new CompileProviderMetadata({
- token: createToken(token),
- multi: multi,
- useClass: new CompileTypeMetadata({name, reference: name as any as Type}),
- deps: deps.map(createDep)
- });
- }
-
- function createDir(
- selector: string, {providers = null, viewProviders = null, deps = [], queries = []}: {
- providers?: CompileProviderMetadata[],
- viewProviders?: CompileProviderMetadata[],
- deps?: string[],
- queries?: string[]
- } = {}): CompileDirectiveMetadata {
- var isComponent = !selector.startsWith('[');
- return CompileDirectiveMetadata.create({
- selector: selector,
- type: new CompileTypeMetadata({
- moduleUrl: someModuleUrl,
- name: selector,
- diDeps: deps.map(createDep),
- reference: selector as any as Type
- }),
- isComponent: isComponent,
- template: new CompileTemplateMetadata({ngContentSelectors: []}),
- providers: providers,
- viewProviders: viewProviders,
- queries: queries.map(
- (value) => new CompileQueryMetadata({selectors: [createToken(value)]}))
- });
- }
-
- beforeEach(() => { nextProviderId = 0; });
-
- it('should provide a component', () => {
- var comp = createDir('my-comp');
- var elAst: ElementAst = parse('', [comp])[0];
- expect(elAst.providers.length).toBe(1);
- expect(elAst.providers[0].providerType).toBe(ProviderAstType.Component);
- expect(elAst.providers[0].providers[0].useClass).toBe(comp.type);
- });
- it('should provide a directive', () => {
- var dirA = createDir('[dirA]');
- var elAst: ElementAst = parse('', [dirA])[0];
- expect(elAst.providers.length).toBe(1);
- expect(elAst.providers[0].providerType).toBe(ProviderAstType.Directive);
- expect(elAst.providers[0].providers[0].useClass).toBe(dirA.type);
- });
+ it('should provide a directive', () => {
+ var dirA = createDir('[dirA]');
+ var elAst: ElementAst =
parse('', [dirA])[0];
+ expect(elAst.providers.length).toBe(1);
+ expect(elAst.providers[0].providerType).toBe(ProviderAstType.Directive);
+ expect(elAst.providers[0].providers[0].useClass).toBe(dirA.type);
+ });
- it('should use the public providers of a directive', () => {
- var provider = createProvider('service');
- var dirA = createDir('[dirA]', {providers: [provider]});
- var elAst: ElementAst =
parse('', [dirA])[0];
- expect(elAst.providers.length).toBe(2);
- expect(elAst.providers[1].providerType).toBe(ProviderAstType.PublicService);
- expect(elAst.providers[1].providers).toEqual([provider]);
- });
+ it('should use the public providers of a directive', () => {
+ var provider = createProvider('service');
+ var dirA = createDir('[dirA]', {providers: [provider]});
+ var elAst: ElementAst =
parse('', [dirA])[0];
+ expect(elAst.providers.length).toBe(2);
+ expect(elAst.providers[1].providerType).toBe(ProviderAstType.PublicService);
+ expect(elAst.providers[1].providers).toEqual([provider]);
+ });
- it('should use the private providers of a component', () => {
- var provider = createProvider('service');
- var comp = createDir('my-comp', {viewProviders: [provider]});
- var elAst: ElementAst =
parse('', [comp])[0];
- expect(elAst.providers.length).toBe(2);
- expect(elAst.providers[1].providerType).toBe(ProviderAstType.PrivateService);
- expect(elAst.providers[1].providers).toEqual([provider]);
- });
+ it('should use the private providers of a component', () => {
+ var provider = createProvider('service');
+ var comp = createDir('my-comp', {viewProviders: [provider]});
+ var elAst: ElementAst = parse('', [comp])[0];
+ expect(elAst.providers.length).toBe(2);
+ expect(elAst.providers[1].providerType).toBe(ProviderAstType.PrivateService);
+ expect(elAst.providers[1].providers).toEqual([provider]);
+ });
- it('should support multi providers', () => {
- var provider0 = createProvider('service0', {multi: true});
- var provider1 = createProvider('service1', {multi: true});
- var provider2 = createProvider('service0', {multi: true});
- var dirA = createDir('[dirA]', {providers: [provider0, provider1]});
- var dirB = createDir('[dirB]', {providers: [provider2]});
- var elAst: ElementAst = parse('', [dirA, dirB])[0];
- expect(elAst.providers.length).toBe(4);
- expect(elAst.providers[2].providers).toEqual([provider0, provider2]);
- expect(elAst.providers[3].providers).toEqual([provider1]);
- });
+ it('should support multi providers', () => {
+ var provider0 = createProvider('service0', {multi: true});
+ var provider1 = createProvider('service1', {multi: true});
+ var provider2 = createProvider('service0', {multi: true});
+ var dirA = createDir('[dirA]', {providers: [provider0, provider1]});
+ var dirB = createDir('[dirB]', {providers: [provider2]});
+ var elAst: ElementAst =
parse('', [dirA, dirB])[0];
+ expect(elAst.providers.length).toBe(4);
+ expect(elAst.providers[2].providers).toEqual([provider0, provider2]);
+ expect(elAst.providers[3].providers).toEqual([provider1]);
+ });
- it('should overwrite non multi providers', () => {
- var provider1 = createProvider('service0');
- var provider2 = createProvider('service1');
- var provider3 = createProvider('service0');
- var dirA = createDir('[dirA]', {providers: [provider1, provider2]});
- var dirB = createDir('[dirB]', {providers: [provider3]});
- var elAst: ElementAst =
parse('', [dirA, dirB])[0];
- expect(elAst.providers.length).toBe(4);
- expect(elAst.providers[2].providers).toEqual([provider3]);
- expect(elAst.providers[3].providers).toEqual([provider2]);
- });
+ it('should overwrite non multi providers', () => {
+ var provider1 = createProvider('service0');
+ var provider2 = createProvider('service1');
+ var provider3 = createProvider('service0');
+ var dirA = createDir('[dirA]', {providers: [provider1, provider2]});
+ var dirB = createDir('[dirB]', {providers: [provider3]});
+ var elAst: ElementAst =
parse('', [dirA, dirB])[0];
+ expect(elAst.providers.length).toBe(4);
+ expect(elAst.providers[2].providers).toEqual([provider3]);
+ expect(elAst.providers[3].providers).toEqual([provider2]);
+ });
- it('should overwrite component providers by directive providers', () => {
- var compProvider = createProvider('service0');
- var dirProvider = createProvider('service0');
- var comp = createDir('my-comp', {providers: [compProvider]});
- var dirA = createDir('[dirA]', {providers: [dirProvider]});
- var elAst: ElementAst =
parse('', [dirA, comp])[0];
- expect(elAst.providers.length).toBe(3);
- expect(elAst.providers[2].providers).toEqual([dirProvider]);
- });
+ it('should overwrite component providers by directive providers', () => {
+ var compProvider = createProvider('service0');
+ var dirProvider = createProvider('service0');
+ var comp = createDir('my-comp', {providers: [compProvider]});
+ var dirA = createDir('[dirA]', {providers: [dirProvider]});
+ var elAst: ElementAst = parse('', [dirA, comp])[0];
+ expect(elAst.providers.length).toBe(3);
+ expect(elAst.providers[2].providers).toEqual([dirProvider]);
+ });
- it('should overwrite view providers by directive providers', () => {
- var viewProvider = createProvider('service0');
- var dirProvider = createProvider('service0');
- var comp = createDir('my-comp', {viewProviders: [viewProvider]});
- var dirA = createDir('[dirA]', {providers: [dirProvider]});
- var elAst: ElementAst = parse('', [dirA, comp])[0];
- expect(elAst.providers.length).toBe(3);
- expect(elAst.providers[2].providers).toEqual([dirProvider]);
- });
+ it('should overwrite view providers by directive providers', () => {
+ var viewProvider = createProvider('service0');
+ var dirProvider = createProvider('service0');
+ var comp = createDir('my-comp', {viewProviders: [viewProvider]});
+ var dirA = createDir('[dirA]', {providers: [dirProvider]});
+ var elAst: ElementAst = parse('', [dirA, comp])[0];
+ expect(elAst.providers.length).toBe(3);
+ expect(elAst.providers[2].providers).toEqual([dirProvider]);
+ });
- it('should overwrite directives by providers', () => {
- var dirProvider = createProvider('type:my-comp');
- var comp = createDir('my-comp', {providers: [dirProvider]});
- var elAst: ElementAst = parse('', [comp])[0];
- expect(elAst.providers.length).toBe(1);
- expect(elAst.providers[0].providers).toEqual([dirProvider]);
- });
+ it('should overwrite directives by providers', () => {
+ var dirProvider = createProvider('type:my-comp');
+ var comp = createDir('my-comp', {providers: [dirProvider]});
+ var elAst: ElementAst = parse('', [comp])[0];
+ expect(elAst.providers.length).toBe(1);
+ expect(elAst.providers[0].providers).toEqual([dirProvider]);
+ });
- it('if mixing multi and non multi providers', () => {
- var provider0 = createProvider('service0');
- var provider1 = createProvider('service0', {multi: true});
- var dirA = createDir('[dirA]', {providers: [provider0]});
- var dirB = createDir('[dirB]', {providers: [provider1]});
- expect(() => parse('', [dirA, dirB]))
- .toThrowError(
- `Template parse errors:\n` +
- `Mixing multi and non multi provider is not possible for token service0 ("[ERROR ->]
"): TestComp@0:0`);
- });
+ it('if mixing multi and non multi providers', () => {
+ var provider0 = createProvider('service0');
+ var provider1 = createProvider('service0', {multi: true});
+ var dirA = createDir('[dirA]', {providers: [provider0]});
+ var dirB = createDir('[dirB]', {providers: [provider1]});
+ expect(() => parse('
', [dirA, dirB]))
+ .toThrowError(
+ `Template parse errors:\n` +
+ `Mixing multi and non multi provider is not possible for token service0 ("[ERROR ->]
"): TestComp@0:0`);
+ });
- it('should sort providers by their DI order', () => {
- var provider0 = createProvider('service0', {deps: ['type:[dir2]']});
- var provider1 = createProvider('service1');
- var dir2 = createDir('[dir2]', {deps: ['service1']});
- var comp = createDir('my-comp', {providers: [provider0, provider1]});
- var elAst: ElementAst =
parse('', [comp, dir2])[0];
- expect(elAst.providers.length).toBe(4);
- expect(elAst.providers[0].providers[0].useClass).toEqual(comp.type);
- expect(elAst.providers[1].providers).toEqual([provider1]);
- expect(elAst.providers[2].providers[0].useClass).toEqual(dir2.type);
- expect(elAst.providers[3].providers).toEqual([provider0]);
- });
+ it('should sort providers by their DI order', () => {
+ var provider0 = createProvider('service0', {deps: ['type:[dir2]']});
+ var provider1 = createProvider('service1');
+ var dir2 = createDir('[dir2]', {deps: ['service1']});
+ var comp = createDir('my-comp', {providers: [provider0, provider1]});
+ var elAst: ElementAst = parse('', [comp, dir2])[0];
+ expect(elAst.providers.length).toBe(4);
+ expect(elAst.providers[0].providers[0].useClass).toEqual(comp.type);
+ expect(elAst.providers[1].providers).toEqual([provider1]);
+ expect(elAst.providers[2].providers[0].useClass).toEqual(dir2.type);
+ expect(elAst.providers[3].providers).toEqual([provider0]);
+ });
- it('should sort directives by their DI order', () => {
- var dir0 = createDir('[dir0]', {deps: ['type:my-comp']});
- var dir1 = createDir('[dir1]', {deps: ['type:[dir0]']});
- var dir2 = createDir('[dir2]', {deps: ['type:[dir1]']});
- var comp = createDir('my-comp');
- var elAst: ElementAst =
- parse('', [comp, dir2, dir0, dir1])[0];
- expect(elAst.providers.length).toBe(4);
- expect(elAst.directives[0].directive).toBe(comp);
- expect(elAst.directives[1].directive).toBe(dir0);
- expect(elAst.directives[2].directive).toBe(dir1);
- expect(elAst.directives[3].directive).toBe(dir2);
- });
+ it('should sort directives by their DI order', () => {
+ var dir0 = createDir('[dir0]', {deps: ['type:my-comp']});
+ var dir1 = createDir('[dir1]', {deps: ['type:[dir0]']});
+ var dir2 = createDir('[dir2]', {deps: ['type:[dir1]']});
+ var comp = createDir('my-comp');
+ var elAst: ElementAst =
+ parse('', [comp, dir2, dir0, dir1])[0];
+ expect(elAst.providers.length).toBe(4);
+ expect(elAst.directives[0].directive).toBe(comp);
+ expect(elAst.directives[1].directive).toBe(dir0);
+ expect(elAst.directives[2].directive).toBe(dir1);
+ expect(elAst.directives[3].directive).toBe(dir2);
+ });
- it('should mark directives and dependencies of directives as eager', () => {
- var provider0 = createProvider('service0');
- var provider1 = createProvider('service1');
- var dirA = createDir('[dirA]', {providers: [provider0, provider1], deps: ['service0']});
- var elAst: ElementAst = parse('', [dirA])[0];
- expect(elAst.providers.length).toBe(3);
- expect(elAst.providers[0].providers).toEqual([provider0]);
- expect(elAst.providers[0].eager).toBe(true);
- expect(elAst.providers[1].providers[0].useClass).toEqual(dirA.type);
- expect(elAst.providers[1].eager).toBe(true);
- expect(elAst.providers[2].providers).toEqual([provider1]);
- expect(elAst.providers[2].eager).toBe(false);
- });
+ it('should mark directives and dependencies of directives as eager', () => {
+ var provider0 = createProvider('service0');
+ var provider1 = createProvider('service1');
+ var dirA =
+ createDir('[dirA]', {providers: [provider0, provider1], deps: ['service0']});
+ var elAst: ElementAst =
parse('', [dirA])[0];
+ expect(elAst.providers.length).toBe(3);
+ expect(elAst.providers[0].providers).toEqual([provider0]);
+ expect(elAst.providers[0].eager).toBe(true);
+ expect(elAst.providers[1].providers[0].useClass).toEqual(dirA.type);
+ expect(elAst.providers[1].eager).toBe(true);
+ expect(elAst.providers[2].providers).toEqual([provider1]);
+ expect(elAst.providers[2].eager).toBe(false);
+ });
- it('should mark dependencies on parent elements as eager', () => {
- var provider0 = createProvider('service0');
- var provider1 = createProvider('service1');
- var dirA = createDir('[dirA]', {providers: [provider0, provider1]});
- var dirB = createDir('[dirB]', {deps: ['service0']});
- var elAst: ElementAst =
-
parse('', [dirA, dirB])[0];
- expect(elAst.providers.length).toBe(3);
- expect(elAst.providers[0].providers[0].useClass).toEqual(dirA.type);
- expect(elAst.providers[0].eager).toBe(true);
- expect(elAst.providers[1].providers).toEqual([provider0]);
- expect(elAst.providers[1].eager).toBe(true);
- expect(elAst.providers[2].providers).toEqual([provider1]);
- expect(elAst.providers[2].eager).toBe(false);
- });
+ it('should mark dependencies on parent elements as eager', () => {
+ var provider0 = createProvider('service0');
+ var provider1 = createProvider('service1');
+ var dirA = createDir('[dirA]', {providers: [provider0, provider1]});
+ var dirB = createDir('[dirB]', {deps: ['service0']});
+ var elAst: ElementAst =
+ parse('', [dirA, dirB])[0];
+ expect(elAst.providers.length).toBe(3);
+ expect(elAst.providers[0].providers[0].useClass).toEqual(dirA.type);
+ expect(elAst.providers[0].eager).toBe(true);
+ expect(elAst.providers[1].providers).toEqual([provider0]);
+ expect(elAst.providers[1].eager).toBe(true);
+ expect(elAst.providers[2].providers).toEqual([provider1]);
+ expect(elAst.providers[2].eager).toBe(false);
+ });
- it('should mark queried providers as eager', () => {
- var provider0 = createProvider('service0');
- var provider1 = createProvider('service1');
- var dirA =
- createDir('[dirA]', {providers: [provider0, provider1], queries: ['service0']});
- var elAst: ElementAst = parse('
', [dirA])[0];
- expect(elAst.providers.length).toBe(3);
- expect(elAst.providers[0].providers[0].useClass).toEqual(dirA.type);
- expect(elAst.providers[0].eager).toBe(true);
- expect(elAst.providers[1].providers).toEqual([provider0]);
- expect(elAst.providers[1].eager).toBe(true);
- expect(elAst.providers[2].providers).toEqual([provider1]);
- expect(elAst.providers[2].eager).toBe(false);
- });
+ it('should mark queried providers as eager', () => {
+ var provider0 = createProvider('service0');
+ var provider1 = createProvider('service1');
+ var dirA =
+ createDir('[dirA]', {providers: [provider0, provider1], queries: ['service0']});
+ var elAst: ElementAst = parse('
', [dirA])[0];
+ expect(elAst.providers.length).toBe(3);
+ expect(elAst.providers[0].providers[0].useClass).toEqual(dirA.type);
+ expect(elAst.providers[0].eager).toBe(true);
+ expect(elAst.providers[1].providers).toEqual([provider0]);
+ expect(elAst.providers[1].eager).toBe(true);
+ expect(elAst.providers[2].providers).toEqual([provider1]);
+ expect(elAst.providers[2].eager).toBe(false);
+ });
- it('should not mark dependencies accross embedded views as eager', () => {
- var provider0 = createProvider('service0');
- var dirA = createDir('[dirA]', {providers: [provider0]});
- var dirB = createDir('[dirB]', {deps: ['service0']});
- var elAst: ElementAst =
- parse('', [dirA, dirB])[0];
- expect(elAst.providers.length).toBe(2);
- expect(elAst.providers[0].providers[0].useClass).toEqual(dirA.type);
- expect(elAst.providers[0].eager).toBe(true);
- expect(elAst.providers[1].providers).toEqual([provider0]);
- expect(elAst.providers[1].eager).toBe(false);
- });
+ it('should not mark dependencies accross embedded views as eager', () => {
+ var provider0 = createProvider('service0');
+ var dirA = createDir('[dirA]', {providers: [provider0]});
+ var dirB = createDir('[dirB]', {deps: ['service0']});
+ var elAst: ElementAst =
+ parse('', [dirA, dirB])[0];
+ expect(elAst.providers.length).toBe(2);
+ expect(elAst.providers[0].providers[0].useClass).toEqual(dirA.type);
+ expect(elAst.providers[0].eager).toBe(true);
+ expect(elAst.providers[1].providers).toEqual([provider0]);
+ expect(elAst.providers[1].eager).toBe(false);
+ });
- it('should report missing @Self() deps as errors', () => {
- var dirA = createDir('[dirA]', {deps: ['self:provider0']});
- expect(() => parse('
', [dirA]))
- .toThrowError(
- 'Template parse errors:\nNo provider for provider0 ("[ERROR ->]
"): TestComp@0:0');
- });
+ it('should report missing @Self() deps as errors', () => {
+ var dirA = createDir('[dirA]', {deps: ['self:provider0']});
+ expect(() => parse('
', [dirA]))
+ .toThrowError(
+ 'Template parse errors:\nNo provider for provider0 ("[ERROR ->]
"): TestComp@0:0');
+ });
- it('should change missing @Self() that are optional to nulls', () => {
- var dirA = createDir('[dirA]', {deps: ['optional:self:provider0']});
- var elAst: ElementAst = parse('
', [dirA])[0];
- expect(elAst.providers[0].providers[0].deps[0].isValue).toBe(true);
- expect(elAst.providers[0].providers[0].deps[0].value).toBe(null);
- });
+ it('should change missing @Self() that are optional to nulls', () => {
+ var dirA = createDir('[dirA]', {deps: ['optional:self:provider0']});
+ var elAst: ElementAst = parse('
', [dirA])[0];
+ expect(elAst.providers[0].providers[0].deps[0].isValue).toBe(true);
+ expect(elAst.providers[0].providers[0].deps[0].value).toBe(null);
+ });
- it('should report missing @Host() deps as errors', () => {
- var dirA = createDir('[dirA]', {deps: ['host:provider0']});
- expect(() => parse('
', [dirA]))
- .toThrowError(
- 'Template parse errors:\nNo provider for provider0 ("[ERROR ->]
"): TestComp@0:0');
- });
+ it('should report missing @Host() deps as errors', () => {
+ var dirA = createDir('[dirA]', {deps: ['host:provider0']});
+ expect(() => parse('
', [dirA]))
+ .toThrowError(
+ 'Template parse errors:\nNo provider for provider0 ("[ERROR ->]
"): TestComp@0:0');
+ });
- it('should change missing @Host() that are optional to nulls', () => {
- var dirA = createDir('[dirA]', {deps: ['optional:host:provider0']});
- var elAst: ElementAst = parse('
', [dirA])[0];
- expect(elAst.providers[0].providers[0].deps[0].isValue).toBe(true);
- expect(elAst.providers[0].providers[0].deps[0].value).toBe(null);
- });
- });
+ it('should change missing @Host() that are optional to nulls', () => {
+ var dirA = createDir('[dirA]', {deps: ['optional:host:provider0']});
+ var elAst: ElementAst = parse('
', [dirA])[0];
+ expect(elAst.providers[0].providers[0].deps[0].isValue).toBe(true);
+ expect(elAst.providers[0].providers[0].deps[0].value).toBe(null);
+ });
+ });
- describe('references', () => {
+ describe('references', () => {
- it('should parse references via #... and not report them as attributes', () => {
- expect(humanizeTplAst(parse('', [
- ]))).toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]);
- });
+ it('should parse references via #... and not report them as attributes', () => {
+ expect(humanizeTplAst(parse('
', [
+ ]))).toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]);
+ });
- it('should parse references via ref-... and not report them as attributes', () => {
- expect(humanizeTplAst(parse('
', [
- ]))).toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]);
- });
+ it('should parse references via ref-... and not report them as attributes', () => {
+ expect(humanizeTplAst(parse('
', [
+ ]))).toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]);
+ });
- it('should parse camel case references', () => {
- expect(humanizeTplAst(parse('
', [
- ]))).toEqual([[ElementAst, 'div'], [ReferenceAst, 'someA', null]]);
- });
+ it('should parse camel case references', () => {
+ expect(humanizeTplAst(parse('
', [
+ ]))).toEqual([[ElementAst, 'div'], [ReferenceAst, 'someA', null]]);
+ });
- it('should assign references with empty value to the element', () => {
- expect(humanizeTplAst(parse('
', [
- ]))).toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]);
- });
+ it('should assign references with empty value to the element', () => {
+ expect(humanizeTplAst(parse('
', [
+ ]))).toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]);
+ });
- it('should assign references to directives via exportAs', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: '[a]',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
}),
- exportAs: 'dirA'
- });
- expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
- [ElementAst, 'div'],
- [AttrAst, 'a', ''],
- [ReferenceAst, 'a', identifierToken(dirA.type)],
- [DirectiveAst, dirA],
- ]);
- });
+ it('should assign references to directives via exportAs', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: '[a]',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
+ exportAs: 'dirA'
+ });
+ expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
+ [ElementAst, 'div'],
+ [AttrAst, 'a', ''],
+ [ReferenceAst, 'a', identifierToken(dirA.type)],
+ [DirectiveAst, dirA],
+ ]);
+ });
- it('should report references with values that dont match a directive as errors', () => {
- expect(() => parse('
', [])).toThrowError(`Template parse errors:
+ it('should report references with values that dont match a directive as errors', () => {
+ expect(() => parse('
', [])).toThrowError(`Template parse errors:
There is no directive with "exportAs" set to "dirA" ("]#a="dirA">
"): TestComp@0:5`);
- });
+ });
- it('should report invalid reference names', () => {
- expect(() => parse('
', [])).toThrowError(`Template parse errors:
+ it('should report invalid reference names', () => {
+ expect(() => parse('
', [])).toThrowError(`Template parse errors:
"-" is not allowed in reference names ("]#a-b>
"): TestComp@0:5`);
- });
+ });
- it('should report variables as errors', () => {
- expect(() => parse('
', [])).toThrowError(`Template parse errors:
+ it('should report variables as errors', () => {
+ expect(() => parse('
', [])).toThrowError(`Template parse errors:
"let-" is only supported on template elements. ("]let-a>
"): TestComp@0:5`);
- });
+ });
- it('should report duplicate reference names', () => {
- expect(() => parse('
', []))
- .toThrowError(`Template parse errors:
+ it('should report duplicate reference names', () => {
+ expect(() => parse('
', []))
+ .toThrowError(`Template parse errors:
Reference "#a" is defined several times ("
]#a>
"): TestComp@0:19`);
- });
+ });
- it('should not throw error when there is same reference name in different templates',
- () => {
- expect(() => parse('OK
', []))
- .not.toThrowError();
-
- });
-
- it('should assign references with empty value to components', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: '[a]',
- isComponent: true,
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
- exportAs: 'dirA',
- template: new CompileTemplateMetadata({ngContentSelectors: []})
- });
- expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
- [ElementAst, 'div'],
- [AttrAst, 'a', ''],
- [ReferenceAst, 'a', identifierToken(dirA.type)],
- [DirectiveAst, dirA],
- ]);
- });
+ it('should not throw error when there is same reference name in different templates',
+ () => {
+ expect(() => parse('OK
', []))
+ .not.toThrowError();
+
+ });
+
+ it('should assign references with empty value to components', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: '[a]',
+ isComponent: true,
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
+ exportAs: 'dirA',
+ template: new CompileTemplateMetadata({ngContentSelectors: []})
+ });
+ expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
+ [ElementAst, 'div'],
+ [AttrAst, 'a', ''],
+ [ReferenceAst, 'a', identifierToken(dirA.type)],
+ [DirectiveAst, dirA],
+ ]);
+ });
- it('should not locate directives in references', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: '[a]',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type})
+ it('should not locate directives in references', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: '[a]',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type})
+ });
+ expect(humanizeTplAst(parse('', [dirA]))).toEqual([
+ [ElementAst, 'div'], [ReferenceAst, 'a', null]
+ ]);
+ });
});
- expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
- [ElementAst, 'div'], [ReferenceAst, 'a', null]
- ]);
- });
- });
- describe('explicit templates', () => {
- it('should create embedded templates for
elements', () => {
- expect(humanizeTplAst(parse(' ', [
- ]))).toEqual([[EmbeddedTemplateAst]]);
- expect(humanizeTplAst(parse(' ', [
- ]))).toEqual([[EmbeddedTemplateAst]]);
- });
-
- it('should create embedded templates for elements regardless the namespace',
- () => {
- expect(humanizeTplAst(parse(' ', []))).toEqual([
- [ElementAst, ':svg:svg'],
- [EmbeddedTemplateAst],
- ]);
- });
-
- it('should support references via #...', () => {
- expect(humanizeTplAst(parse('', []))).toEqual([
- [EmbeddedTemplateAst],
- [ReferenceAst, 'a', resolveIdentifierToken(Identifiers.TemplateRef)]
- ]);
- });
+ describe('explicit templates', () => {
+ it('should create embedded templates for elements', () => {
+ expect(humanizeTplAst(parse(' ', [
+ ]))).toEqual([[EmbeddedTemplateAst]]);
+ expect(humanizeTplAst(parse(' ', [
+ ]))).toEqual([[EmbeddedTemplateAst]]);
+ });
- it('should support references via ref-...', () => {
- expect(humanizeTplAst(parse('', []))).toEqual([
- [EmbeddedTemplateAst],
- [ReferenceAst, 'a', resolveIdentifierToken(Identifiers.TemplateRef)]
- ]);
- });
+ it('should create embedded templates for elements regardless the namespace',
+ () => {
+ expect(humanizeTplAst(parse(' ', []))).toEqual([
+ [ElementAst, ':svg:svg'],
+ [EmbeddedTemplateAst],
+ ]);
+ });
- it('should parse variables via let-...', () => {
- expect(humanizeTplAst(parse('', [
- ]))).toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b']]);
- });
+ it('should support references via #...', () => {
+ expect(humanizeTplAst(parse('', []))).toEqual([
+ [EmbeddedTemplateAst],
+ [ReferenceAst, 'a', resolveIdentifierToken(Identifiers.TemplateRef)]
+ ]);
+ });
- it('should not locate directives in variables', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: '[a]',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type})
- });
- expect(humanizeTplAst(parse(' ', [dirA]))).toEqual([
- [EmbeddedTemplateAst], [VariableAst, 'a', 'b']
- ]);
- });
+ it('should support references via ref-...', () => {
+ expect(humanizeTplAst(parse('', []))).toEqual([
+ [EmbeddedTemplateAst],
+ [ReferenceAst, 'a', resolveIdentifierToken(Identifiers.TemplateRef)]
+ ]);
+ });
- });
+ it('should parse variables via let-...', () => {
+ expect(humanizeTplAst(parse('', [
+ ]))).toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b']]);
+ });
- describe('inline templates', () => {
- it('should wrap the element into an EmbeddedTemplateAST', () => {
- expect(humanizeTplAst(parse('', [
- ]))).toEqual([[EmbeddedTemplateAst], [ElementAst, 'div']]);
- });
+ it('should not locate directives in variables', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: '[a]',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
})
+ });
+ expect(humanizeTplAst(parse(' ', [dirA]))).toEqual([
+ [EmbeddedTemplateAst], [VariableAst, 'a', 'b']
+ ]);
+ });
- it('should wrap the element with data-template attribute into an EmbeddedTemplateAST ',
- () => {
- expect(humanizeTplAst(parse('', [
- ]))).toEqual([[EmbeddedTemplateAst], [ElementAst, 'div']]);
- });
-
- it('should parse bound properties', () => {
- expect(humanizeTplAst(parse('
', [ngIf]))).toEqual([
- [EmbeddedTemplateAst], [DirectiveAst, ngIf],
- [BoundDirectivePropertyAst, 'ngIf', 'test'], [ElementAst, 'div']
- ]);
- });
+ });
- it('should report an error on variables declared with #', () => {
- expect(() => humanizeTplAst(parse('
', [])))
- .toThrowError(/Parser Error: Unexpected token # at column 6/);
- });
+ describe('inline templates', () => {
+ it('should wrap the element into an EmbeddedTemplateAST', () => {
+ expect(humanizeTplAst(parse('
', [
+ ]))).toEqual([[EmbeddedTemplateAst], [ElementAst, 'div']]);
+ });
- it('should parse variables via let ...', () => {
- expect(humanizeTplAst(parse('
', [
- ]))).toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b'], [ElementAst, 'div']]);
- });
+ it('should wrap the element with data-template attribute into an EmbeddedTemplateAST ',
+ () => {
+ expect(humanizeTplAst(parse('
', [
+ ]))).toEqual([[EmbeddedTemplateAst], [ElementAst, 'div']]);
+ });
- describe('directives', () => {
- it('should locate directives in property bindings', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: '[a=b]',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
}),
- inputs: ['a']
+ it('should parse bound properties', () => {
+ expect(humanizeTplAst(parse('', [ngIf]))).toEqual([
+ [EmbeddedTemplateAst], [DirectiveAst, ngIf],
+ [BoundDirectivePropertyAst, 'ngIf', 'test'], [ElementAst, 'div']
+ ]);
});
- var dirB = CompileDirectiveMetadata.create({
- selector: '[b]',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type
})
+
+ it('should report an error on variables declared with #', () => {
+ expect(() => humanizeTplAst(parse('', [])))
+ .toThrowError(/Parser Error: Unexpected token # at column 6/);
});
- expect(humanizeTplAst(parse('
', [dirA, dirB]))).toEqual([
- [EmbeddedTemplateAst], [DirectiveAst, dirA], [BoundDirectivePropertyAst, 'a', 'b'],
- [ElementAst, 'div'], [AttrAst, 'b', ''], [DirectiveAst, dirB]
- ]);
- });
- it('should not locate directives in variables', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: '[a]',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
})
+ it('should parse variables via let ...', () => {
+ expect(humanizeTplAst(parse('', [
+ ]))).toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b'], [ElementAst, 'div']]);
});
- expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
- [EmbeddedTemplateAst], [VariableAst, 'a', 'b'], [ElementAst, 'div']
- ]);
- });
- it('should not locate directives in references', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: '[a]',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
})
+ describe('directives', () => {
+ it('should locate directives in property bindings', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: '[a=b]',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
+ inputs: ['a']
+ });
+ var dirB = CompileDirectiveMetadata.create({
+ selector: '[b]',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type})
+ });
+ expect(humanizeTplAst(parse('', [dirA, dirB]))).toEqual([
+ [EmbeddedTemplateAst], [DirectiveAst, dirA],
+ [BoundDirectivePropertyAst, 'a', 'b'], [ElementAst, 'div'], [AttrAst, 'b', ''],
+ [DirectiveAst, dirB]
+ ]);
+ });
+
+ it('should not locate directives in variables', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: '[a]',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
})
+ });
+ expect(humanizeTplAst(parse('', [dirA]))).toEqual([
+ [EmbeddedTemplateAst], [VariableAst, 'a', 'b'], [ElementAst, 'div']
+ ]);
+ });
+
+ it('should not locate directives in references', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: '[a]',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
})
+ });
+ expect(humanizeTplAst(parse('', [dirA]))).toEqual([
+ [ElementAst, 'div'], [ReferenceAst, 'a', null]
+ ]);
+ });
+
});
- expect(humanizeTplAst(parse('
', [dirA]))).toEqual([
- [ElementAst, 'div'], [ReferenceAst, 'a', null]
- ]);
- });
- });
+ it('should work with *... and use the attribute name as property binding name', () => {
+ expect(humanizeTplAst(parse('
', [ngIf]))).toEqual([
+ [EmbeddedTemplateAst], [DirectiveAst, ngIf],
+ [BoundDirectivePropertyAst, 'ngIf', 'test'], [ElementAst, 'div']
+ ]);
+ });
- it('should work with *... and use the attribute name as property binding name', () => {
- expect(humanizeTplAst(parse('
', [ngIf]))).toEqual([
- [EmbeddedTemplateAst], [DirectiveAst, ngIf],
- [BoundDirectivePropertyAst, 'ngIf', 'test'], [ElementAst, 'div']
- ]);
+ it('should work with *... and empty value', () => {
+ expect(humanizeTplAst(parse('
', [ngIf]))).toEqual([
+ [EmbeddedTemplateAst], [DirectiveAst, ngIf],
+ [BoundDirectivePropertyAst, 'ngIf', 'null'], [ElementAst, 'div']
+ ]);
+ });
+ });
});
- it('should work with *... and empty value', () => {
- expect(humanizeTplAst(parse('
', [ngIf]))).toEqual([
- [EmbeddedTemplateAst], [DirectiveAst, ngIf],
- [BoundDirectivePropertyAst, 'ngIf', 'null'], [ElementAst, 'div']
- ]);
- });
- });
- });
+ describe('content projection', () => {
+ var compCounter: any /** TODO #9100 */;
+ beforeEach(() => { compCounter = 0; });
+
+ function createComp(
+ selector: string, ngContentSelectors: string[]): CompileDirectiveMetadata {
+ return CompileDirectiveMetadata.create({
+ selector: selector,
+ isComponent: true,
+ type: new CompileTypeMetadata({
+ moduleUrl: someModuleUrl,
+ name: `SomeComp${compCounter++}`,
+ reference: {} as Type
+ }),
+ template: new CompileTemplateMetadata({ngContentSelectors: ngContentSelectors})
+ });
+ }
- describe('content projection', () => {
- var compCounter: any /** TODO #9100 */;
- beforeEach(() => { compCounter = 0; });
-
- function createComp(
- selector: string, ngContentSelectors: string[]): CompileDirectiveMetadata {
- return CompileDirectiveMetadata.create({
- selector: selector,
- isComponent: true,
- type: new CompileTypeMetadata({
- moduleUrl: someModuleUrl,
- name: `SomeComp${compCounter++}`,
- reference: {} as Type
- }),
- template: new CompileTemplateMetadata({ngContentSelectors: ngContentSelectors})
- });
- }
+ function createDir(selector: string): CompileDirectiveMetadata {
+ return CompileDirectiveMetadata.create({
+ selector: selector,
+ type: new CompileTypeMetadata({
+ moduleUrl: someModuleUrl,
+ name: `SomeDir${compCounter++}`,
+ reference: {} as Type
+ })
+ });
+ }
- function createDir(selector: string): CompileDirectiveMetadata {
- return CompileDirectiveMetadata.create({
- selector: selector,
- type: new CompileTypeMetadata({
- moduleUrl: someModuleUrl,
- name: `SomeDir${compCounter++}`,
- reference: {} as Type
- })
- });
- }
+ describe('project text nodes', () => {
+ it('should project text nodes with wildcard selector', () => {
+ expect(humanizeContentProjection(parse('hello
', [
+ createComp('div', ['*'])
+ ]))).toEqual([['div', null], ['#text(hello)', 0]]);
+ });
+ });
- describe('project text nodes', () => {
- it('should project text nodes with wildcard selector', () => {
- expect(humanizeContentProjection(parse('hello
', [createComp('div', ['*'])])))
- .toEqual([['div', null], ['#text(hello)', 0]]);
- });
- });
+ describe('project elements', () => {
+ it('should project elements with wildcard selector', () => {
+ expect(humanizeContentProjection(parse('
', [
+ createComp('div', ['*'])
+ ]))).toEqual([['div', null], ['span', 0]]);
+ });
- describe('project elements', () => {
- it('should project elements with wildcard selector', () => {
- expect(humanizeContentProjection(parse('
', [
- createComp('div', ['*'])
- ]))).toEqual([['div', null], ['span', 0]]);
- });
+ it('should project elements with css selector', () => {
+ expect(humanizeContentProjection(parse('', [
+ createComp('div', ['a[x]'])
+ ]))).toEqual([['div', null], ['a', 0], ['b', null]]);
+ });
+ });
- it('should project elements with css selector', () => {
- expect(humanizeContentProjection(parse('', [
- createComp('div', ['a[x]'])
- ]))).toEqual([['div', null], ['a', 0], ['b', null]]);
- });
- });
+ describe('embedded templates', () => {
+ it('should project embedded templates with wildcard selector', () => {
+ expect(humanizeContentProjection(parse('
', [
+ createComp('div', ['*'])
+ ]))).toEqual([['div', null], ['template', 0]]);
+ });
- describe('embedded templates', () => {
- it('should project embedded templates with wildcard selector', () => {
- expect(humanizeContentProjection(parse('
', [
- createComp('div', ['*'])
- ]))).toEqual([['div', null], ['template', 0]]);
- });
+ it('should project embedded templates with css selector', () => {
+ expect(humanizeContentProjection(parse(
+ '
',
+ [createComp('div', ['template[x]'])])))
+ .toEqual([['div', null], ['template', 0], ['template', null]]);
+ });
+ });
- it('should project embedded templates with css selector', () => {
- expect(humanizeContentProjection(parse(
- '
',
- [createComp('div', ['template[x]'])])))
- .toEqual([['div', null], ['template', 0], ['template', null]]);
- });
- });
+ describe('ng-content', () => {
+ it('should project ng-content with wildcard selector', () => {
+ expect(humanizeContentProjection(parse('
', [
+ createComp('div', ['*'])
+ ]))).toEqual([['div', null], ['ng-content', 0]]);
+ });
- describe('ng-content', () => {
- it('should project ng-content with wildcard selector', () => {
- expect(humanizeContentProjection(parse('
', [
- createComp('div', ['*'])
- ]))).toEqual([['div', null], ['ng-content', 0]]);
- });
+ it('should project ng-content with css selector', () => {
+ expect(humanizeContentProjection(parse(
+ '
',
+ [createComp('div', ['ng-content[x]'])])))
+ .toEqual([['div', null], ['ng-content', 0], ['ng-content', null]]);
+ });
+ });
- it('should project ng-content with css selector', () => {
- expect(humanizeContentProjection(parse(
- '
',
- [createComp('div', ['ng-content[x]'])])))
- .toEqual([['div', null], ['ng-content', 0], ['ng-content', null]]);
- });
- });
+ it('should project into the first matching ng-content', () => {
+ expect(humanizeContentProjection(parse('', [
+ createComp('div', ['a', 'b', '*'])
+ ]))).toEqual([['div', null], ['#text(hello)', 2], ['b', 1], ['a', 0]]);
+ });
- it('should project into the first matching ng-content', () => {
- expect(humanizeContentProjection(parse('', [
- createComp('div', ['a', 'b', '*'])
- ]))).toEqual([['div', null], ['#text(hello)', 2], ['b', 1], ['a', 0]]);
- });
+ it('should project into wildcard ng-content last', () => {
+ expect(humanizeContentProjection(parse('', [
+ createComp('div', ['*', 'a'])
+ ]))).toEqual([['div', null], ['#text(hello)', 0], ['a', 1]]);
+ });
- it('should project into wildcard ng-content last', () => {
- expect(humanizeContentProjection(parse('', [
- createComp('div', ['*', 'a'])
- ]))).toEqual([['div', null], ['#text(hello)', 0], ['a', 1]]);
- });
+ it('should only project direct child nodes', () => {
+ expect(humanizeContentProjection(parse('', [
+ createComp('div', ['a'])
+ ]))).toEqual([['div', null], ['span', null], ['a', null], ['a', 0]]);
+ });
- it('should only project direct child nodes', () => {
- expect(humanizeContentProjection(parse('', [
- createComp('div', ['a'])
- ]))).toEqual([['div', null], ['span', null], ['a', null], ['a', 0]]);
- });
+ it('should project nodes of nested components', () => {
+ expect(humanizeContentProjection(parse('hello ', [
+ createComp('a', ['*']), createComp('b', ['*'])
+ ]))).toEqual([['a', null], ['b', 0], ['#text(hello)', 0]]);
+ });
- it('should project nodes of nested components', () => {
- expect(humanizeContentProjection(parse('hello ', [
- createComp('a', ['*']), createComp('b', ['*'])
- ]))).toEqual([['a', null], ['b', 0], ['#text(hello)', 0]]);
- });
+ it('should project children of components with ngNonBindable', () => {
+ expect(
+ humanizeContentProjection(parse(
+ '{{hello}}
', [createComp('div', ['*'])])))
+ .toEqual([['div', null], ['#text({{hello}})', 0], ['span', 0]]);
+ });
- it('should project children of components with ngNonBindable', () => {
- expect(humanizeContentProjection(parse('{{hello}}
', [
- createComp('div', ['*'])
- ]))).toEqual([['div', null], ['#text({{hello}})', 0], ['span', 0]]);
- });
+ it('should match the element when there is an inline template', () => {
+ expect(humanizeContentProjection(parse('
', [
+ createComp('div', ['a', 'b']), ngIf
+ ]))).toEqual([['div', null], ['template', 1], ['b', null]]);
+ });
- it('should match the element when there is an inline template', () => {
- expect(humanizeContentProjection(parse('
', [
- createComp('div', ['a', 'b']), ngIf
- ]))).toEqual([['div', null], ['template', 1], ['b', null]]);
- });
+ describe('ngProjectAs', () => {
+ it('should override elements', () => {
+ expect(humanizeContentProjection(parse('', [
+ createComp('div', ['a', 'b'])
+ ]))).toEqual([['div', null], ['a', 1]]);
+ });
- describe('ngProjectAs', () => {
- it('should override elements', () => {
- expect(humanizeContentProjection(parse('', [
- createComp('div', ['a', 'b'])
- ]))).toEqual([['div', null], ['a', 1]]);
- });
+ it('should override ', () => {
+ expect(humanizeContentProjection(parse(
+ '
',
+ [createComp('div', ['ng-content', 'b'])])))
+ .toEqual([['div', null], ['ng-content', 1]]);
+ });
- it('should override ', () => {
- expect(humanizeContentProjection(parse(
- '
',
- [createComp('div', ['ng-content', 'b'])])))
- .toEqual([['div', null], ['ng-content', 1]]);
- });
+ it('should override ', () => {
+ expect(humanizeContentProjection(parse(
+ '
',
+ [createComp('div', ['template', 'b'])])))
+ .toEqual([['div', null], ['template', 1]]);
+ });
- it('should override ', () => {
- expect(humanizeContentProjection(parse(
- '
',
- [createComp('div', ['template', 'b'])])))
- .toEqual([['div', null], ['template', 1]]);
- });
+ it('should override inline templates', () => {
+ expect(humanizeContentProjection(parse(
+ '',
+ [createComp('div', ['a', 'b']), ngIf])))
+ .toEqual([['div', null], ['template', 1], ['a', null]]);
+ });
+ });
- it('should override inline templates', () => {
- expect(humanizeContentProjection(parse(
- '',
- [createComp('div', ['a', 'b']), ngIf])))
- .toEqual([['div', null], ['template', 1], ['a', null]]);
+ it('should support other directives before the component', () => {
+ expect(humanizeContentProjection(parse('hello
', [
+ createDir('div'), createComp('div', ['*'])
+ ]))).toEqual([['div', null], ['#text(hello)', 0]]);
+ });
});
- });
- it('should support other directives before the component', () => {
- expect(humanizeContentProjection(parse('hello
', [
- createDir('div'), createComp('div', ['*'])
- ]))).toEqual([['div', null], ['#text(hello)', 0]]);
- });
- });
+ describe('splitClasses', () => {
+ it('should keep an empty class', () => { expect(splitClasses('a')).toEqual(['a']); });
- describe('splitClasses', () => {
- it('should keep an empty class', () => { expect(splitClasses('a')).toEqual(['a']); });
+ it('should split 2 classes', () => { expect(splitClasses('a b')).toEqual(['a', 'b']); });
- it('should split 2 classes', () => { expect(splitClasses('a b')).toEqual(['a', 'b']); });
-
- it('should trim classes', () => { expect(splitClasses(' a b ')).toEqual(['a', 'b']); });
- });
+ it('should trim classes', () => { expect(splitClasses(' a b ')).toEqual(['a', 'b']); });
+ });
- describe('error cases', () => {
- it('should report when ng-content has content', () => {
- expect(() => parse('content ', []))
- .toThrowError(`Template parse errors:
+ describe('error cases', () => {
+ it('should report when ng-content has content', () => {
+ expect(() => parse('content ', []))
+ .toThrowError(`Template parse errors:
element cannot have content. must be immediately followed by ("[ERROR ->]content "): TestComp@0:0`);
- });
+ });
- it('should treat *attr on a template element as valid',
- () => { expect(() => parse('', [])).not.toThrowError(); });
+ it('should treat *attr on a template element as valid',
+ () => { expect(() => parse('', [])).not.toThrowError(); });
- it('should treat template attribute on a template element as valid',
- () => { expect(() => parse('', [])).not.toThrowError(); });
+ it('should treat template attribute on a template element as valid',
+ () => { expect(() => parse('', [])).not.toThrowError(); });
- it('should report when mutliple *attrs are used on the same element', () => {
- expect(() => parse('', [])).toThrowError(`Template parse errors:
+ it('should report when mutliple *attrs are used on the same element', () => {
+ expect(() => parse('
', [])).toThrowError(`Template parse errors:
Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with * ("
]*ngFor>"): TestComp@0:11`);
- });
+ });
- it('should report when mix of template and *attrs are used on the same element', () => {
- expect(() => parse('
', []))
- .toThrowError(`Template parse errors:
+ it('should report when mix of template and *attrs are used on the same element', () => {
+ expect(() => parse('', []))
+ .toThrowError(`Template parse errors:
Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with * ("]*ngFor>"): TestComp@0:22`);
- });
+ });
- it('should report invalid property names', () => {
- expect(() => parse('
', [])).toThrowError(`Template parse errors:
+ it('should report invalid property names', () => {
+ expect(() => parse('
', []))
+ .toThrowError(`Template parse errors:
Can't bind to 'invalidProp' since it isn't a known property of 'div'. ("][invalidProp]>
"): TestComp@0:5`);
- });
+ });
- it('should report invalid host property names', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: 'div',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
- host: {'[invalidProp]': 'someProp'}
- });
- expect(() => parse('
', [dirA])).toThrowError(`Template parse errors:
+ it('should report invalid host property names', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: 'div',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
+ host: {'[invalidProp]': 'someProp'}
+ });
+ expect(() => parse('
', [dirA])).toThrowError(`Template parse errors:
Can't bind to 'invalidProp' since it isn't a known property of 'div'. ("[ERROR ->]
"): TestComp@0:0, Directive DirA`);
- });
+ });
- it('should report errors in expressions', () => {
- expect(() => parse('
', [])).toThrowError(`Template parse errors:
+ it('should report errors in expressions', () => {
+ expect(() => parse('
', [])).toThrowError(`Template parse errors:
Parser Error: Unexpected token 'b' at column 3 in [a b] in TestComp@0:5 ("][prop]="a b">
"): TestComp@0:5`);
- });
+ });
- it('should not throw on invalid property names if the property is used by a directive',
- () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: 'div',
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
- inputs: ['invalidProp']
- });
- expect(() => parse('
', [dirA])).not.toThrow();
- });
-
- it('should not allow more than 1 component per element', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: 'div',
- isComponent: true,
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
- template: new CompileTemplateMetadata({ngContentSelectors: []})
- });
- var dirB = CompileDirectiveMetadata.create({
- selector: 'div',
- isComponent: true,
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type}),
- template: new CompileTemplateMetadata({ngContentSelectors: []})
- });
- expect(() => parse('', [dirB, dirA])).toThrowError(`Template parse errors:
+ it('should not throw on invalid property names if the property is used by a directive',
+ () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: 'div',
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
}),
+ inputs: ['invalidProp']
+ });
+ expect(() => parse('
', [dirA])).not.toThrow();
+ });
+
+ it('should not allow more than 1 component per element', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: 'div',
+ isComponent: true,
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
+ template: new CompileTemplateMetadata({ngContentSelectors: []})
+ });
+ var dirB = CompileDirectiveMetadata.create({
+ selector: 'div',
+ isComponent: true,
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type}),
+ template: new CompileTemplateMetadata({ngContentSelectors: []})
+ });
+ expect(() => parse('', [dirB, dirA])).toThrowError(`Template parse errors:
More than one component: DirB,DirA ("[ERROR ->]
"): TestComp@0:0`);
- });
+ });
- it('should not allow components or element bindings nor dom events on explicit embedded templates',
- () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: '[a]',
- isComponent: true,
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type
}),
- template: new CompileTemplateMetadata({ngContentSelectors: []})
- });
- expect(() => parse(' ', [dirA]))
- .toThrowError(`Template parse errors:
+ it('should not allow components or element bindings nor dom events on explicit embedded templates',
+ () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: '[a]',
+ isComponent: true,
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
+ template: new CompileTemplateMetadata({ngContentSelectors: []})
+ });
+ expect(() => parse(' ', [dirA]))
+ .toThrowError(`Template parse errors:
Event binding e not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "directives" section. ("](e)="f"> "): TestComp@0:18
Components on an embedded template: DirA ("[ERROR ->] "): TestComp@0:0
Property binding a not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "directives" section. ("[ERROR ->] "): TestComp@0:0`);
- });
-
- it('should not allow components or element bindings on inline embedded templates', () => {
- var dirA = CompileDirectiveMetadata.create({
- selector: '[a]',
- isComponent: true,
- type: new CompileTypeMetadata(
- {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
- template: new CompileTemplateMetadata({ngContentSelectors: []})
- });
- expect(() => parse('
', [dirA])).toThrowError(`Template parse errors:
+ });
+
+ it('should not allow components or element bindings on inline embedded templates', () => {
+ var dirA = CompileDirectiveMetadata.create({
+ selector: '[a]',
+ isComponent: true,
+ type: new CompileTypeMetadata(
+ {moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type}),
+ template: new CompileTemplateMetadata({ngContentSelectors: []})
+ });
+ expect(() => parse('
', [dirA])).toThrowError(`Template parse errors:
Components on an embedded template: DirA ("[ERROR ->]
"): TestComp@0:0
Property binding a not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "directives" section. ("[ERROR ->]
"): TestComp@0:0`);
- });
- });
+ });
+ });
- describe('ignore elements', () => {
- it('should ignore a', []))).toEqual([[TextAst, 'a']]);
+ describe('ignore elements', () => {
+ it('should ignore a', []))).toEqual([[TextAst, 'a']]);
- });
+ });
- it('should ignore a', []))).toEqual([[TextAst, 'a']]);
- });
+ it('should ignore a', []))).toEqual([[TextAst, 'a']]);
+ });
- describe(' ', () => {
+ describe(' ', () => {
+
+ it('should keep elements if they have an absolute non package: url',
+ () => {
+ expect(humanizeTplAst(parse(' a', [])))
+ .toEqual([
+ [ElementAst, 'link'], [AttrAst, 'rel', 'stylesheet'],
+ [AttrAst, 'href', 'http://someurl'], [TextAst, 'a']
+ ]);
+ });
+
+ it('should keep elements if they have no uri', () => {
+ expect(humanizeTplAst(parse(' a', [
+ ]))).toEqual([[ElementAst, 'link'], [AttrAst, 'rel', 'stylesheet'], [TextAst, 'a']]);
+ expect(humanizeTplAst(parse(' a', [
+ ]))).toEqual([[ElementAst, 'link'], [AttrAst, 'REL', 'stylesheet'], [TextAst, 'a']]);
+ });
- it('should keep elements if they have an absolute non package: url',
- () => {
- expect(humanizeTplAst(parse(' a', [])))
- .toEqual([
- [ElementAst, 'link'], [AttrAst, 'rel', 'stylesheet'],
- [AttrAst, 'href', 'http://someurl'], [TextAst, 'a']
- ]);
- });
+ it('should ignore elements if they have a relative uri', () => {
+ expect(humanizeTplAst(parse(' a', [
+ ]))).toEqual([[TextAst, 'a']]);
+ expect(humanizeTplAst(parse(' a', [
+ ]))).toEqual([[TextAst, 'a']]);
+ });
- it('should keep elements if they have no uri', () => {
- expect(humanizeTplAst(parse(' a', [
- ]))).toEqual([[ElementAst, 'link'], [AttrAst, 'rel', 'stylesheet'], [TextAst, 'a']]);
- expect(humanizeTplAst(parse(' a', [
- ]))).toEqual([[ElementAst, 'link'], [AttrAst, 'REL', 'stylesheet'], [TextAst, 'a']]);
- });
+ it('should ignore elements if they have a package: uri', () => {
+ expect(humanizeTplAst(parse(' a', [
+ ]))).toEqual([[TextAst, 'a']]);
+ });
- it('should ignore elements if they have a relative uri', () => {
- expect(humanizeTplAst(parse(' a', [
- ]))).toEqual([[TextAst, 'a']]);
- expect(humanizeTplAst(parse(' a', [
- ]))).toEqual([[TextAst, 'a']]);
- });
+ });
- it('should ignore elements if they have a package: uri', () => {
- expect(humanizeTplAst(parse(' a', [
- ]))).toEqual([[TextAst, 'a']]);
- });
+ it('should ignore bindings on children of elements with ngNonBindable', () => {
+ expect(humanizeTplAst(parse('{{b}}
', [
+ ]))).toEqual([[ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [TextAst, '{{b}}']]);
+ });
- });
+ it('should keep nested children of elements with ngNonBindable', () => {
+ expect(humanizeTplAst(parse('