Compare commits
130 Commits
4.3.2
...
5.0.0-beta
Author | SHA1 | Date | |
---|---|---|---|
1e1af7ffcb | |||
a84b2bc945 | |||
7abcb99d57 | |||
49cd8513e4 | |||
82b067fc40 | |||
9479a106bb | |||
e64b54b67b | |||
cc2a4c41f9 | |||
a11542a375 | |||
b6c4af6495 | |||
67dff7bd5d | |||
381471d338 | |||
ebef5e697a | |||
d71ae278ef | |||
46207538ef | |||
71eb7437b6 | |||
b5ffbe342b | |||
0f79223008 | |||
a085223331 | |||
c383048259 | |||
b18eb04b46 | |||
c8c2ab012a | |||
ecff8e6c93 | |||
51f1da1b85 | |||
a5e18c4cdf | |||
cf6284656f | |||
3182ddaf3e | |||
416ed691e5 | |||
0fb7484d51 | |||
6a3454e81e | |||
c3fbe87012 | |||
24117d7a49 | |||
5808153359 | |||
9030c8a03e | |||
b14fc06fa2 | |||
a7f2468184 | |||
fae47d86b3 | |||
d20ac14fe2 | |||
cae3e6dca0 | |||
086f4aa72c | |||
82923a381d | |||
5152abb037 | |||
67f7032321 | |||
205abe8140 | |||
b582e2b311 | |||
91ab39cc55 | |||
38ec05f533 | |||
b3085e96c2 | |||
4cea2bd612 | |||
ce47546188 | |||
6279e50d78 | |||
8bcb268140 | |||
6fc5940959 | |||
0317c4c478 | |||
b7a6f52d59 | |||
7ae7573bc8 | |||
abee785821 | |||
619e625ee2 | |||
a6c635e69e | |||
e0a9625e46 | |||
fd0cc01eed | |||
1bfc77bf8c | |||
a094769bca | |||
b4c98305da | |||
a3a54299af | |||
15a3e2d307 | |||
54e0244954 | |||
43c33d5663 | |||
6d7799fce9 | |||
d31dc7b2b3 | |||
4cd4f7a208 | |||
72fe45db2b | |||
8d2819121b | |||
073e8ba2f2 | |||
5d1864fe68 | |||
eaa843b55f | |||
c6cf678a07 | |||
31cb418370 | |||
8de44cf5e3 | |||
c67bad4f43 | |||
410f21c75c | |||
54ea5b6ffd | |||
0af03beaed | |||
d71fa734f5 | |||
6f45519d6f | |||
65c9e13105 | |||
9208f0beea | |||
5344be5182 | |||
5db6f38b73 | |||
d22f8f54db | |||
23146c9201 | |||
a5205c686e | |||
807648251f | |||
5c62e300e1 | |||
256bc8acdd | |||
59c23c7bd7 | |||
e03adb9edd | |||
b399cb26d9 | |||
3b588fe2b0 | |||
95635c18c7 | |||
e20cfe1bbc | |||
eb6fb5f87e | |||
ad3029e786 | |||
2a2fe11e8d | |||
7d0f2cd51e | |||
36faba1aab | |||
92179bcc64 | |||
cdb069ab0e | |||
c453b7bcfa | |||
9d97163c64 | |||
f054c8360b | |||
758848961e | |||
99b666614d | |||
3f331b53b2 | |||
375d598a9f | |||
cd67fced1c | |||
a77cf7ee37 | |||
2150b45954 | |||
9f99f4fae2 | |||
c6ad212a98 | |||
47b3ecd9a3 | |||
8c81c62d46 | |||
7e72317059 | |||
0bb8423df9 | |||
95698d93ad | |||
c649da9f0a | |||
0bf0c35bca | |||
97e6901ded | |||
30e76fcd80 | |||
44b50427d9 |
@ -42,7 +42,7 @@ jobs:
|
|||||||
key: angular-{{ .Branch }}-{{ checksum "npm-shrinkwrap.json" }}
|
key: angular-{{ .Branch }}-{{ checksum "npm-shrinkwrap.json" }}
|
||||||
|
|
||||||
- run: bazel run @build_bazel_rules_typescript_node//:bin/npm install
|
- run: bazel run @build_bazel_rules_typescript_node//:bin/npm install
|
||||||
- run: bazel build ...
|
- run: bazel build packages/...
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: angular-{{ .Branch }}-{{ checksum "npm-shrinkwrap.json" }}
|
key: angular-{{ .Branch }}-{{ checksum "npm-shrinkwrap.json" }}
|
||||||
paths:
|
paths:
|
||||||
|
@ -69,8 +69,8 @@ groups:
|
|||||||
- "*.lock"
|
- "*.lock"
|
||||||
- "tools/*"
|
- "tools/*"
|
||||||
exclude:
|
exclude:
|
||||||
- "tools/@angular/tsc-wrapped/*"
|
|
||||||
- "tools/public_api_guard/*"
|
- "tools/public_api_guard/*"
|
||||||
|
- "tools/ngc-wrapped/*"
|
||||||
- "aio/*"
|
- "aio/*"
|
||||||
users:
|
users:
|
||||||
- IgorMinar #primary
|
- IgorMinar #primary
|
||||||
@ -136,8 +136,9 @@ groups:
|
|||||||
compiler-cli:
|
compiler-cli:
|
||||||
conditions:
|
conditions:
|
||||||
files:
|
files:
|
||||||
- "tools/@angular/tsc-wrapped/*"
|
- "packages/tsc-wrapped/*"
|
||||||
- "packages/compiler-cli/*"
|
- "packages/compiler-cli/*"
|
||||||
|
- "tools/ngc-wrapped/*"
|
||||||
users:
|
users:
|
||||||
- alexeagle
|
- alexeagle
|
||||||
- chuckjaz
|
- chuckjaz
|
||||||
|
@ -55,7 +55,8 @@ env:
|
|||||||
- CI_MODE=browserstack_optional
|
- CI_MODE=browserstack_optional
|
||||||
- CI_MODE=docs_test
|
- CI_MODE=docs_test
|
||||||
- CI_MODE=aio
|
- CI_MODE=aio
|
||||||
- CI_MODE=aio_e2e
|
- CI_MODE=aio_e2e AIO_SHARD=0
|
||||||
|
- CI_MODE=aio_e2e AIO_SHARD=1
|
||||||
- CI_MODE=bazel
|
- CI_MODE=bazel
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
@ -63,7 +64,6 @@ matrix:
|
|||||||
allow_failures:
|
allow_failures:
|
||||||
- env: "CI_MODE=saucelabs_optional"
|
- env: "CI_MODE=saucelabs_optional"
|
||||||
- env: "CI_MODE=browserstack_optional"
|
- env: "CI_MODE=browserstack_optional"
|
||||||
- env: "CI_MODE=aio_e2e"
|
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
# source the env.sh script so that the exported variables are available to other scripts later on
|
# source the env.sh script so that the exported variables are available to other scripts later on
|
||||||
|
85
CHANGELOG.md
@ -1,3 +1,59 @@
|
|||||||
|
<a name="5.0.0-beta.2"></a>
|
||||||
|
# [5.0.0-beta.2](https://github.com/angular/angular/compare/5.0.0-beta.1...5.0.0-beta.2) (2017-08-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** do not consider arguments when determining recursion ([e64b54b](https://github.com/angular/angular/commit/e64b54b))
|
||||||
|
* **compiler:** fix for element needing implicit parent placed in top-level ng-container ([381471d](https://github.com/angular/angular/commit/381471d)), closes [#18314](https://github.com/angular/angular/issues/18314)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **forms:** add options arg to abstract controls ([ebef5e6](https://github.com/angular/angular/commit/ebef5e6))
|
||||||
|
* **router:** add events tracking activation of individual routes ([49cd851](https://github.com/angular/angular/commit/49cd851))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="4.3.3"></a>
|
||||||
|
## [4.3.3](https://github.com/angular/angular/compare/4.3.2...4.3.3) (2017-08-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** fix for element needing implicit parent placed in top-level ng-container ([f5cbc2e](https://github.com/angular/angular/commit/f5cbc2e)), closes [#18314](https://github.com/angular/angular/issues/18314)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="5.0.0-beta.1"></a>
|
||||||
|
# [5.0.0-beta.1](https://github.com/angular/angular/compare/5.0.0-beta.0...5.0.0-beta.1) (2017-07-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **animations:** export BrowserModule as apart of BrowserAnimationsModule ([#18263](https://github.com/angular/angular/issues/18263)) ([fd0cc01](https://github.com/angular/angular/commit/fd0cc01))
|
||||||
|
* **compiler:** add equiv & disp attributes to Xliff2 ICU placeholders ([#18283](https://github.com/angular/angular/issues/18283)) ([38ec05f](https://github.com/angular/angular/commit/38ec05f)), closes [#17344](https://github.com/angular/angular/issues/17344)
|
||||||
|
* **compiler:** allow numbers for ICU message cases in lexer ([#18095](https://github.com/angular/angular/issues/18095)) ([a3a5429](https://github.com/angular/angular/commit/a3a5429)), closes [#17799](https://github.com/angular/angular/issues/17799)
|
||||||
|
* **core:** invoke error handler outside of the Angular Zone ([#18269](https://github.com/angular/angular/issues/18269)) ([7ae7573](https://github.com/angular/angular/commit/7ae7573)), closes [#17073](https://github.com/angular/angular/issues/17073) [#7774](https://github.com/angular/angular/issues/7774)
|
||||||
|
* **platform-server:** don't clobber parse5 properties when setting ([#18237](https://github.com/angular/angular/issues/18237)) ([a094769](https://github.com/angular/angular/commit/a094769)), closes [#17050](https://github.com/angular/angular/issues/17050)
|
||||||
|
* **router:** child CanActivate guard should wait for parent to complete ([#18110](https://github.com/angular/angular/issues/18110)) ([086f4aa](https://github.com/angular/angular/commit/086f4aa)), closes [#15670](https://github.com/angular/angular/issues/15670)
|
||||||
|
* **router:** should throw when lazy loaded module doesn't define any routes ([#15001](https://github.com/angular/angular/issues/15001)) ([82923a3](https://github.com/angular/angular/commit/82923a3)), closes [#14596](https://github.com/angular/angular/issues/14596)
|
||||||
|
* **upgrade:** ensure downgraded components are created in the Angular zone ([#18209](https://github.com/angular/angular/issues/18209)) ([43c33d5](https://github.com/angular/angular/commit/43c33d5))
|
||||||
|
* **upgrade:** throw error if trying to get injector before setting ([#18209](https://github.com/angular/angular/issues/18209)) ([d31dc7b](https://github.com/angular/angular/commit/d31dc7b))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **compiler:** add representation of placeholders to xliff & xmb ([b3085e9](https://github.com/angular/angular/commit/b3085e9)), closes [#17345](https://github.com/angular/angular/issues/17345)
|
||||||
|
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* latest tsickle to tree shake: abstract class methods & interfaces ([#18236](https://github.com/angular/angular/issues/18236)) ([b7a6f52](https://github.com/angular/angular/commit/b7a6f52))
|
||||||
|
* **core:** use native addEventListener for faster rendering. ([#18107](https://github.com/angular/angular/issues/18107)) ([6279e50](https://github.com/angular/angular/commit/6279e50))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="4.3.2"></a>
|
<a name="4.3.2"></a>
|
||||||
## [4.3.2](https://github.com/angular/angular/compare/4.3.1...4.3.2) (2017-07-26)
|
## [4.3.2](https://github.com/angular/angular/compare/4.3.1...4.3.2) (2017-07-26)
|
||||||
|
|
||||||
@ -15,6 +71,35 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="5.0.0-beta.0"></a>
|
||||||
|
# [5.0.0-beta.0](https://github.com/angular/angular/compare/4.3.0...5.0.0-beta.0) (2017-07-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **animations:** always camelcase style property names that contain auto styles ([d22f8f5](https://github.com/angular/angular/commit/d22f8f5)), closes [#17938](https://github.com/angular/angular/issues/17938)
|
||||||
|
* **animations:** capture cancelled animation styles within grouped animations ([23146c9](https://github.com/angular/angular/commit/23146c9)), closes [#17170](https://github.com/angular/angular/issues/17170)
|
||||||
|
* **animations:** do not crash animations if a nested component fires CD during CD ([5db6f38](https://github.com/angular/angular/commit/5db6f38)), closes [#18193](https://github.com/angular/angular/issues/18193)
|
||||||
|
* **animations:** make sure @.disabled works in non-animation components ([5344be5](https://github.com/angular/angular/commit/5344be5))
|
||||||
|
* **common:** send flushed body as error instead of null ([5c62e30](https://github.com/angular/angular/commit/5c62e30)), closes [#18181](https://github.com/angular/angular/issues/18181)
|
||||||
|
* **compiler:** ensure jit external id arguments names are unique ([95635c1](https://github.com/angular/angular/commit/95635c1))
|
||||||
|
* **compiler-cli:** don't generate empty <target/> when extracting xliff ([65c9e13](https://github.com/angular/angular/commit/65c9e13)), closes [#15754](https://github.com/angular/angular/issues/15754)
|
||||||
|
* **platform-server:** provide XhrFactory for HttpClient ([8076482](https://github.com/angular/angular/commit/8076482))
|
||||||
|
* **router:** canDeactivate guards should run from bottom to top ([e20cfe1](https://github.com/angular/angular/commit/e20cfe1)), closes [#15657](https://github.com/angular/angular/issues/15657)
|
||||||
|
* **router:** should navigate to the same url when config changes ([eb6fb5f](https://github.com/angular/angular/commit/eb6fb5f)), closes [#15535](https://github.com/angular/angular/issues/15535)
|
||||||
|
* **router:** should run resolvers for the same route concurrently ([ad3029e](https://github.com/angular/angular/commit/ad3029e)), closes [#14279](https://github.com/angular/angular/issues/14279)
|
||||||
|
* **router:** terminal route in custom matcher ([b399cb2](https://github.com/angular/angular/commit/b399cb2))
|
||||||
|
* **upgrade:** allow accessing AngularJS injector from downgraded module ([a5205c6](https://github.com/angular/angular/commit/a5205c6))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **animations:** support :increment and :decrement transition aliases ([6f45519](https://github.com/angular/angular/commit/6f45519))
|
||||||
|
* **upgrade:** propagate touched state of NgModelController ([59c23c7](https://github.com/angular/angular/commit/59c23c7))
|
||||||
|
* **upgrade:** support lazy-loading Angular module into AngularJS app ([30e76fc](https://github.com/angular/angular/commit/30e76fc))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="4.3.1"></a>
|
<a name="4.3.1"></a>
|
||||||
## [4.3.1](https://github.com/angular/angular/compare/4.3.0...4.3.1) (2017-07-19)
|
## [4.3.1](https://github.com/angular/angular/compare/4.3.0...4.3.1) (2017-07-19)
|
||||||
|
|
||||||
|
10
aio/content/examples/.gitignore
vendored
@ -43,13 +43,9 @@ dist/
|
|||||||
**/app/**/*.ajs.js
|
**/app/**/*.ajs.js
|
||||||
|
|
||||||
# aot
|
# aot
|
||||||
**/*.ngfactory.ts
|
*/aot/**/*
|
||||||
**/*.ngsummary.json
|
!*/aot/bs-config.json
|
||||||
**/*.ngsummary.ts
|
!*/aot/index.html
|
||||||
**/*.shim.ngstyle.ts
|
|
||||||
**/*.metadata.json
|
|
||||||
!aot/bs-config.json
|
|
||||||
!aot/index.html
|
|
||||||
!rollup-config.js
|
!rollup-config.js
|
||||||
|
|
||||||
# i18n
|
# i18n
|
||||||
|
@ -9,7 +9,7 @@ export class AppComponent {
|
|||||||
wolves = 0;
|
wolves = 0;
|
||||||
gender = 'f';
|
gender = 'f';
|
||||||
fly = true;
|
fly = true;
|
||||||
logo = 'https://angular.io/resources/images/logos/angular/angular.png';
|
logo = 'https://angular.io/assets/images/logos/angular/angular.png';
|
||||||
count = 3;
|
count = 3;
|
||||||
heroes: string[] = ['Magneta', 'Celeritas', 'Dynama'];
|
heroes: string[] = ['Magneta', 'Celeritas', 'Dynama'];
|
||||||
inc(i: number) {
|
inc(i: number) {
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
/* #docregion , quickstart, toh */
|
|
||||||
/* Master Styles */
|
|
||||||
h1 {
|
|
||||||
color: #369;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
font-size: 250%;
|
|
||||||
}
|
|
||||||
h2, h3 {
|
|
||||||
color: #444;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
font-weight: lighter;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
margin: 2em;
|
|
||||||
}
|
|
||||||
/* #enddocregion quickstart */
|
|
||||||
body, input[text], button {
|
|
||||||
color: #888;
|
|
||||||
font-family: Cambria, Georgia;
|
|
||||||
}
|
|
||||||
/* #enddocregion toh */
|
|
||||||
a {
|
|
||||||
cursor: pointer;
|
|
||||||
cursor: hand;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
font-family: Arial;
|
|
||||||
background-color: #eee;
|
|
||||||
border: none;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
cursor: hand;
|
|
||||||
}
|
|
||||||
button:hover {
|
|
||||||
background-color: #cfd8dc;
|
|
||||||
}
|
|
||||||
button:disabled {
|
|
||||||
background-color: #eee;
|
|
||||||
color: #aaa;
|
|
||||||
cursor: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Navigation link styles */
|
|
||||||
nav a {
|
|
||||||
padding: 5px 10px;
|
|
||||||
text-decoration: none;
|
|
||||||
margin-right: 10px;
|
|
||||||
margin-top: 10px;
|
|
||||||
display: inline-block;
|
|
||||||
background-color: #eee;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
nav a:visited, a:link {
|
|
||||||
color: #607D8B;
|
|
||||||
}
|
|
||||||
nav a:hover {
|
|
||||||
color: #039be5;
|
|
||||||
background-color: #CFD8DC;
|
|
||||||
}
|
|
||||||
nav a.active {
|
|
||||||
color: #039be5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* items class */
|
|
||||||
.items {
|
|
||||||
margin: 0 0 2em 0;
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
width: 24em;
|
|
||||||
}
|
|
||||||
.items li {
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
left: 0;
|
|
||||||
background-color: #EEE;
|
|
||||||
margin: .5em;
|
|
||||||
padding: .3em 0;
|
|
||||||
height: 1.6em;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
.items li:hover {
|
|
||||||
color: #607D8B;
|
|
||||||
background-color: #DDD;
|
|
||||||
left: .1em;
|
|
||||||
}
|
|
||||||
.items li.selected {
|
|
||||||
background-color: #CFD8DC;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.items li.selected:hover {
|
|
||||||
background-color: #BBD8DC;
|
|
||||||
}
|
|
||||||
.items .text {
|
|
||||||
position: relative;
|
|
||||||
top: -3px;
|
|
||||||
}
|
|
||||||
.items .badge {
|
|
||||||
display: inline-block;
|
|
||||||
font-size: small;
|
|
||||||
color: white;
|
|
||||||
padding: 0.8em 0.7em 0 0.7em;
|
|
||||||
background-color: #607D8B;
|
|
||||||
line-height: 1em;
|
|
||||||
position: relative;
|
|
||||||
left: -1px;
|
|
||||||
top: -4px;
|
|
||||||
height: 1.8em;
|
|
||||||
margin-right: .8em;
|
|
||||||
border-radius: 4px 0 0 4px;
|
|
||||||
}
|
|
||||||
/* #docregion toh */
|
|
||||||
/* everywhere else */
|
|
||||||
* {
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
}
|
|
@ -9,7 +9,8 @@ describe('PhoneCat Application', function() {
|
|||||||
|
|
||||||
it('should redirect `index.html` to `index.html#!/phones', function() {
|
it('should redirect `index.html` to `index.html#!/phones', function() {
|
||||||
browser.get('index.html');
|
browser.get('index.html');
|
||||||
expect(browser.getLocationAbsUrl()).toBe('/phones');
|
browser.sleep(1000); // Not sure why this is needed but it is. The route change works fine.
|
||||||
|
expect(browser.getCurrentUrl()).toMatch(/\/phones$/);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('View: Phone list', function() {
|
describe('View: Phone list', function() {
|
||||||
@ -65,7 +66,7 @@ describe('PhoneCat Application', function() {
|
|||||||
|
|
||||||
element.all(by.css('.phones li a')).first().click();
|
element.all(by.css('.phones li a')).first().click();
|
||||||
browser.sleep(1000); // Not sure why this is needed but it is. The route change works fine.
|
browser.sleep(1000); // Not sure why this is needed but it is. The route change works fine.
|
||||||
expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s');
|
expect(browser.getCurrentUrl()).toMatch(/\/phones\/nexus-s$/);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
176
aio/content/guide/language-service.md
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
# Angular Language Service
|
||||||
|
|
||||||
|
The Angular Language Service is a way to get completions, errors,
|
||||||
|
hints, and navigation inside your Angular templates whether they
|
||||||
|
are external in an HTML file or embedded in annotations/decorators
|
||||||
|
in a string. The Angular Language Service autodetects that you are
|
||||||
|
opening an Angular file, reads your `tsconfig.json` file, finds all the
|
||||||
|
templates you have in your application, and then provides language
|
||||||
|
services for any templates that you open.
|
||||||
|
|
||||||
|
|
||||||
|
## Autocompletion
|
||||||
|
|
||||||
|
Autocompletion can speed up your development time by providing you with
|
||||||
|
contextual possibilities and hints as you type. This example shows
|
||||||
|
autocomplete in an interpolation. As you type it out,
|
||||||
|
you can hit tab to complete.
|
||||||
|
|
||||||
|
<figure>
|
||||||
|
<img src="generated/images/guide/language-service/language-completion.gif" alt="autocompletion">
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
There are also completions within
|
||||||
|
elements. Any elements you have as a component selector will
|
||||||
|
show up in the completion list.
|
||||||
|
|
||||||
|
## Error checking
|
||||||
|
|
||||||
|
The Angular Language Service can also forewarn you of mistakes in your code.
|
||||||
|
In this example, Angular doesn't know what `orders` is or where it comes from.
|
||||||
|
|
||||||
|
<figure>
|
||||||
|
<img src="generated/images/guide/language-service/language-error.gif" alt="error checking">
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
## Navigation
|
||||||
|
|
||||||
|
Navigation allows you to hover to
|
||||||
|
see where a component, directive, module, etc. is from and then
|
||||||
|
click and press F12 to go directly to its definition.
|
||||||
|
|
||||||
|
<figure>
|
||||||
|
<img src="generated/images/guide/language-service/language-navigation.gif" alt="navigation">
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
|
||||||
|
## Angular Language Service in your editor
|
||||||
|
|
||||||
|
Angular Language Service is currently available for [Visual Studio Code](https://code.visualstudio.com/) and
|
||||||
|
[WebStorm](https://www.jetbrains.com/webstorm).
|
||||||
|
|
||||||
|
### Visual Studio Code
|
||||||
|
|
||||||
|
In Visual Studio Code, install Angular Language Service from the store,
|
||||||
|
which is accessible from the bottom icon on the left menu pane.
|
||||||
|
You can also use the VS Quick Open (⌘+P) to search for the extension. When you've opened it,
|
||||||
|
enter the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ext install ng-template
|
||||||
|
```
|
||||||
|
|
||||||
|
Then click the install button to install the Angular Language Service.
|
||||||
|
|
||||||
|
|
||||||
|
### WebStorm
|
||||||
|
|
||||||
|
In webstorm, you have to install the language service as a dev dependency.
|
||||||
|
When Angular sees this dev dependency, it provides the
|
||||||
|
language service inside of WebStorm. Webstorm then gives you
|
||||||
|
colorization inside the template and autocomplete in addition to the Angular Language Service.
|
||||||
|
|
||||||
|
Here's the dev dependency
|
||||||
|
you need to have in `package.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
|
||||||
|
devDependencies {
|
||||||
|
"@angular/language-service": "^4.0.0"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then in the terminal window at the root of your project,
|
||||||
|
install the `devDependencies` with `npm` or `yarn`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
*OR*
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn
|
||||||
|
```
|
||||||
|
|
||||||
|
*OR*
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Sublime Text
|
||||||
|
|
||||||
|
In [Sublime Text](https://www.sublimetext.com/), you first need an extension to allow Typescript.
|
||||||
|
Install the latest version of typescript in a local `node_modules` directory:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install --save-dev typescript
|
||||||
|
```
|
||||||
|
|
||||||
|
Then install the Angular Language Service in the same location:
|
||||||
|
```sh
|
||||||
|
npm install --save-dev @angular/language-service
|
||||||
|
```
|
||||||
|
|
||||||
|
Starting with TypeScript 2.3, TypeScript has a language service plugin model that the language service can use.
|
||||||
|
|
||||||
|
Next, in your user preferences (`Cmd+,` or `Ctrl+,`), add:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"typescript-tsdk": "<path to your folder>/node_modules/typescript/lib"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Installing in your project
|
||||||
|
|
||||||
|
You can also install Angular Language Service in your project with the
|
||||||
|
following `npm` command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install --save-dev @angular/language-service
|
||||||
|
```
|
||||||
|
Additionally, add the following to the `"compilerOptions"` section of
|
||||||
|
your project's `tsconfig.json`.
|
||||||
|
|
||||||
|
```json
|
||||||
|
"plugins": [
|
||||||
|
{"name": "@angular/language-service"}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
Note that this only provides diagnostics and completions in `.ts`
|
||||||
|
files. You need a custom sublime plugin (or modifications to the current plugin)
|
||||||
|
for completions in HTML files.
|
||||||
|
|
||||||
|
|
||||||
|
## How the Language Service works
|
||||||
|
|
||||||
|
When you use an editor with a language service, there's an
|
||||||
|
editor process which starts a separate language process/service
|
||||||
|
to which it speaks through an [RPC](https://en.wikipedia.org/wiki/Remote_procedure_call).
|
||||||
|
Any time you type inside of the editor, it sends information to the other process to
|
||||||
|
track the state of your project. When you trigger a completion list within a template, the editor process first parses the template into an HTML AST, or [abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree). Then the Angular compiler interprets
|
||||||
|
what module the template is part of, the scope you're in, and the component selector. Then it figures out where in the template AST your cursor is. When it determines the
|
||||||
|
context, it can then determine what the children can be.
|
||||||
|
|
||||||
|
It's a little more involved if you are in an interpolation. If you have an interpolation of `{{data.---}}` inside a `div` and need the completion list after `data.---`, the compiler can't use the HTML AST to find the answer. The HTML AST can only tell the compiler that there is some text with the characters "`{{data.---}}`". That's when the template parser produces an expression AST, which resides within the template AST. The Angular Language Services then looks at `data.---` within its context and asks the TypeScript Language Service what the members of data are. TypeScript then returns the list of possibilities.
|
||||||
|
|
||||||
|
|
||||||
|
For more in-depth information, see the
|
||||||
|
[Angular Language Service API](https://github.com/angular/angular/blob/master/packages/language-service/src/types.ts)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
## More on Information
|
||||||
|
|
||||||
|
For more information, see [Chuck Jazdzewski's presentation](https://www.youtube.com/watch?v=ez3R0Gi4z5A&t=368s) on the Angular Language
|
||||||
|
Service from [ng-conf](https://www.ng-conf.org/) 2017.
|
||||||
|
|
||||||
|
|
@ -1080,8 +1080,11 @@ To get access to the `FormArray` class, import it into `hero-detail.component.ts
|
|||||||
|
|
||||||
|
|
||||||
To _work_ with a `FormArray` you do the following:
|
To _work_ with a `FormArray` you do the following:
|
||||||
|
|
||||||
1. Define the items (`FormControls` or `FormGroups`) in the array.
|
1. Define the items (`FormControls` or `FormGroups`) in the array.
|
||||||
|
|
||||||
1. Initialize the array with items created from data in the _data model_.
|
1. Initialize the array with items created from data in the _data model_.
|
||||||
|
|
||||||
1. Add and remove items as the user requires.
|
1. Add and remove items as the user requires.
|
||||||
|
|
||||||
In this guide, you define a `FormArray` for `Hero.addresses` and
|
In this guide, you define a `FormArray` for `Hero.addresses` and
|
||||||
|
@ -1830,7 +1830,7 @@ Finally, you activate the observable with `subscribe` method and (re)set the com
|
|||||||
|
|
||||||
#### _ParamMap_ API
|
#### _ParamMap_ API
|
||||||
|
|
||||||
The `ParamMap` API is inspired by the [URLSearchParams interface](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParamsOPut). It provides methods
|
The `ParamMap` API is inspired by the [URLSearchParams interface](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams). It provides methods
|
||||||
to handle parameter access for both route parameters (`paramMap`) and query parameters (`queryParamMap`).
|
to handle parameter access for both route parameters (`paramMap`) and query parameters (`queryParamMap`).
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 132 KiB |
BIN
aio/content/images/guide/language-service/language-error.gif
Normal file
After Width: | Height: | Size: 274 KiB |
After Width: | Height: | Size: 857 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 257 KiB After Width: | Height: | Size: 257 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
@ -8,7 +8,7 @@
|
|||||||
<div class="feature-section">
|
<div class="feature-section">
|
||||||
<div class="feature-header">
|
<div class="feature-header">
|
||||||
<div class="text-headline">Cross Platform</div>
|
<div class="text-headline">Cross Platform</div>
|
||||||
<img src="assets/images/icons/feature-icon.svg" height="70px">
|
<img src="generated/images/marketing/features/feature-icon.svg" height="70px">
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-row">
|
<div class="feature-row">
|
||||||
|
|
||||||
@ -34,7 +34,7 @@
|
|||||||
<div class="feature-section">
|
<div class="feature-section">
|
||||||
<div class="feature-header">
|
<div class="feature-header">
|
||||||
<div class="text-headline">Speed and Performance</div>
|
<div class="text-headline">Speed and Performance</div>
|
||||||
<img src="assets/images/icons/feature-icon.svg" height="70px">
|
<img src="generated/images/marketing/features/feature-icon.svg" height="70px">
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-row">
|
<div class="feature-row">
|
||||||
|
|
||||||
@ -59,7 +59,7 @@
|
|||||||
<div class="feature-section">
|
<div class="feature-section">
|
||||||
<div class="feature-header">
|
<div class="feature-header">
|
||||||
<div class="text-headline">Productivity</div>
|
<div class="text-headline">Productivity</div>
|
||||||
<img src="assets/images/icons/feature-icon.svg" height="70px">
|
<img src="generated/images/marketing/features/feature-icon.svg" height="70px">
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-row">
|
<div class="feature-row">
|
||||||
|
|
||||||
@ -84,7 +84,7 @@
|
|||||||
<div class="feature-section">
|
<div class="feature-section">
|
||||||
<div class="feature-header">
|
<div class="feature-header">
|
||||||
<div class="text-headline">Full Development Story</div>
|
<div class="text-headline">Full Development Story</div>
|
||||||
<img src="assets/images/icons/feature-icon.svg" height="70px">
|
<img src="generated/images/marketing/features/feature-icon.svg" height="70px">
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-row">
|
<div class="feature-row">
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<!--FULL HEADER BLOCK-->
|
<!-- FULL HEADER BLOCK -->
|
||||||
<header>
|
<header>
|
||||||
|
|
||||||
<!--BACKGROUND IMAGE-->
|
<!-- BACKGROUND IMAGE -->
|
||||||
<div class="background-sky hero"></div>
|
<div class="background-sky hero"></div>
|
||||||
|
|
||||||
<!--INTRO SECTION -->
|
<!-- INTRO SECTION -->
|
||||||
<section id="intro">
|
<section id="intro">
|
||||||
|
|
||||||
<!-- LOGO -->
|
<!-- LOGO -->
|
||||||
@ -12,35 +12,37 @@
|
|||||||
<img src="assets/images/logos/angular/angular.svg"/>
|
<img src="assets/images/logos/angular/angular.svg"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- CONTAINER -->
|
<!-- CONTAINER -->
|
||||||
<div class="homepage-container">
|
<div class="homepage-container">
|
||||||
<!-- container content starts -->
|
|
||||||
|
|
||||||
<div class="hero-headline no-toc">One framework.<br>Mobile & desktop.</div>
|
<div class="hero-headline no-toc">One framework.<br>Mobile & desktop.</div>
|
||||||
<a class="button hero-cta" href="guide/quickstart">Get Started</a>
|
<a class="button hero-cta" href="guide/quickstart">Get Started</a>
|
||||||
</div><!-- CONTAINER END -->
|
</div>
|
||||||
</section>
|
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
<!-- MAIN CONTENT -->
|
||||||
<article>
|
<article>
|
||||||
|
|
||||||
|
<h1 class="no-toc" style="display: none"></h1>
|
||||||
|
|
||||||
<div class="home-rows">
|
<div class="home-rows">
|
||||||
|
|
||||||
<!--Announcement Bar-->
|
<!-- Announcement Bar -->
|
||||||
<div class="homepage-container">
|
<div class="homepage-container">
|
||||||
<div class="announcement-bar">
|
<div class="announcement-bar">
|
||||||
<img src="generated/images/marketing/angular-mix.png" height="40" width="151">
|
<img src="generated/images/marketing/home/angular-mix.png" height="40" width="151">
|
||||||
<p>Join us at our newest event, October 2017</p>
|
<p>Join us at our newest event, October 2017</p>
|
||||||
<a class="button" href="https://angularmix.com/">Learn More</a>
|
<a class="button" href="https://angularmix.com/">Learn More</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Group 1-->
|
<!-- Group 1 -->
|
||||||
<div layout="row" layout-xs="column" class="home-row homepage-container">
|
<div layout="row" layout-xs="column" class="home-row homepage-container">
|
||||||
<div class="promo-img-container promo-1">
|
<div class="promo-img-container promo-1">
|
||||||
<div>
|
<div>
|
||||||
<img height="222" width="340" src="assets/images/home/responsive-framework.svg" alt="responsive framework">
|
<img height="222" width="340" src="generated/images/marketing/home/responsive-framework.svg" alt="responsive framework">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -53,7 +55,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<!-- Group 2-->
|
|
||||||
|
<!-- Group 2 -->
|
||||||
<div layout="row" layout-xs="column" class="home-row">
|
<div layout="row" layout-xs="column" class="home-row">
|
||||||
<div class="text-container">
|
<div class="text-container">
|
||||||
<div class="text-block">
|
<div class="text-block">
|
||||||
@ -65,16 +68,16 @@
|
|||||||
|
|
||||||
<div class="promo-img-container promo-2">
|
<div class="promo-img-container promo-2">
|
||||||
<div>
|
<div>
|
||||||
<img height="222" width="323" src="assets/images/home/speed-performance.svg" alt="speed and performance">
|
<img height="222" width="323" src="generated/images/marketing/home/speed-performance.svg" alt="speed and performance">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<!-- Group 3-->
|
<!-- Group 3 -->
|
||||||
<div layout="row" layout-xs="column" class="home-row">
|
<div layout="row" layout-xs="column" class="home-row">
|
||||||
<div class="promo-img-container promo-3">
|
<div class="promo-img-container promo-3">
|
||||||
<div><img src="assets/images/home/joyful-development.png" alt="IDE example"></div>
|
<div><img src="generated/images/marketing/home/joyful-development.svg" alt="IDE example"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-container">
|
<div class="text-container">
|
||||||
@ -88,9 +91,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<!-- Group 4-->
|
<!-- Group 4 -->
|
||||||
<div layout="row" layout-xs="column" class="home-row">
|
<div layout="row" layout-xs="column" class="home-row">
|
||||||
|
|
||||||
<div class="text-container">
|
<div class="text-container">
|
||||||
<div class="text-block l-pad-top-2">
|
<div class="text-block l-pad-top-2">
|
||||||
<div class="text-headline">Loved by Millions</div>
|
<div class="text-headline">Loved by Millions</div>
|
||||||
@ -100,25 +102,24 @@
|
|||||||
|
|
||||||
<div class="promo-img-container promo-4">
|
<div class="promo-img-container promo-4">
|
||||||
<div>
|
<div>
|
||||||
<img src="assets/images/home/loved-by-millions.png" alt="angular on the map" width="455" height="228">
|
<img src="generated/images/marketing/home/loved-by-millions.svg" alt="angular on the map" width="455" height="228">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- CTA CARDS -->
|
<!-- CTA CARDS -->
|
||||||
<div layout="row" layout-xs="column" class="home-row">
|
<div layout="row" layout-xs="column" class="home-row">
|
||||||
|
<a href="guide/quickstart">
|
||||||
<a href="guide/quickstart">
|
<div class="card">
|
||||||
<div class="card">
|
<img src="generated/images/marketing/home/code-icon.svg" height="70px">
|
||||||
<img src="assets/images/icons/code-icon.svg" height="70px">
|
|
||||||
<div class="card-text-container">
|
<div class="card-text-container">
|
||||||
<div class="text-headline">Get Started</div>
|
<div class="text-headline">Get Started</div>
|
||||||
<p>Start building your Angular application.</p>
|
<p>Start building your Angular application.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div> <!-- end of home rows -->
|
</div><!-- end of home rows -->
|
||||||
|
|
||||||
</article>
|
</article>
|
||||||
|
@ -282,6 +282,11 @@
|
|||||||
"title": "Internationalization (i18n)",
|
"title": "Internationalization (i18n)",
|
||||||
"tooltip": "Translate the app's template text into multiple languages."
|
"tooltip": "Translate the app's template text into multiple languages."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"url": "guide/language-service",
|
||||||
|
"title": "Language Service",
|
||||||
|
"tooltip": "Use Angular Language Service to speed up dev time."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"url": "guide/security",
|
"url": "guide/security",
|
||||||
"title": "Security",
|
"title": "Security",
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
},
|
},
|
||||||
"static.ignore": [
|
"static.ignore": [
|
||||||
"\\.js\\.map$",
|
"\\.js\\.map$",
|
||||||
"^/assets/images/.*/unused/",
|
"^(?:/|\\\\)assets(?:/|\\\\)images(?:/|\\\\).*(?:/|\\\\)_unused(?:/|\\\\)",
|
||||||
"^/generated/(?:docs/(?!api/api-list\\.json).*|images|live-examples|zips)/"
|
"^(?:/|\\\\)generated(?:/|\\\\)(?:docs(?:/|\\\\)(?!api(?:/|\\\\)api-list\\.json).*|images(?:/|\\\\)(?!marketing(?:/|\\\\)).*|live-examples|zips)(?:/|\\\\)"
|
||||||
],
|
],
|
||||||
"static.versioned": [
|
"static.versioned": [
|
||||||
"\\.[0-9a-z]{20}\\."
|
"\\.[0-9a-z]{20}\\."
|
||||||
|
@ -33,8 +33,9 @@
|
|||||||
"docs-test": "node tools/transforms/test.js",
|
"docs-test": "node tools/transforms/test.js",
|
||||||
"serve-and-sync": "concurrently --kill-others \"yarn docs-watch\" \"yarn start\"",
|
"serve-and-sync": "concurrently --kill-others \"yarn docs-watch\" \"yarn start\"",
|
||||||
"~~update-webdriver": "webdriver-manager update --standalone false --gecko false",
|
"~~update-webdriver": "webdriver-manager update --standalone false --gecko false",
|
||||||
"boilerplate:add": "node ./tools/examples/add-example-boilerplate add",
|
"boilerplate:add": "node ./tools/examples/example-boilerplate add",
|
||||||
"boilerplate:remove": "node ./tools/examples/add-example-boilerplate remove",
|
"boilerplate:remove": "node ./tools/examples/example-boilerplate remove",
|
||||||
|
"boilerplate:test": "node tools/examples/test.js",
|
||||||
"generate-plunkers": "node ./tools/plunker-builder/generatePlunkers",
|
"generate-plunkers": "node ./tools/plunker-builder/generatePlunkers",
|
||||||
"generate-zips": "node ./tools/example-zipper/generateZips",
|
"generate-zips": "node ./tools/example-zipper/generateZips",
|
||||||
"sw-manifest": "ngu-sw-manifest --dist dist --in ngsw-manifest.json --out dist/ngsw-manifest.json",
|
"sw-manifest": "ngu-sw-manifest --dist dist --in ngsw-manifest.json --out dist/ngsw-manifest.json",
|
||||||
@ -48,17 +49,18 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^4.2.4",
|
"@angular/animations": "^4.3.1",
|
||||||
"@angular/common": "^4.2.4",
|
"@angular/cdk": "^2.0.0-beta.8",
|
||||||
"@angular/compiler": "^4.2.4",
|
"@angular/common": "^4.3.1",
|
||||||
"@angular/core": "^4.2.4",
|
"@angular/compiler": "^4.3.1",
|
||||||
"@angular/forms": "^4.2.4",
|
"@angular/core": "^4.3.1",
|
||||||
"@angular/http": "^4.2.4",
|
"@angular/forms": "^4.3.1",
|
||||||
"@angular/material": "^2.0.0-beta.7",
|
"@angular/http": "^4.3.1",
|
||||||
"@angular/platform-browser": "^4.2.4",
|
"@angular/material": "^2.0.0-beta.8",
|
||||||
"@angular/platform-browser-dynamic": "^4.2.4",
|
"@angular/platform-browser": "^4.3.1",
|
||||||
"@angular/platform-server": "^4.2.4",
|
"@angular/platform-browser-dynamic": "^4.3.1",
|
||||||
"@angular/router": "^4.2.4",
|
"@angular/platform-server": "^4.3.1",
|
||||||
|
"@angular/router": "^4.3.1",
|
||||||
"@angular/service-worker": "^1.0.0-beta.16",
|
"@angular/service-worker": "^1.0.0-beta.16",
|
||||||
"classlist.js": "^1.1.20150312",
|
"classlist.js": "^1.1.20150312",
|
||||||
"core-js": "^2.4.1",
|
"core-js": "^2.4.1",
|
||||||
@ -72,7 +74,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/cli": "angular/cli-builds#webpack-next",
|
"@angular/cli": "angular/cli-builds#webpack-next",
|
||||||
"@angular/compiler-cli": "^4.2.4",
|
"@angular/compiler-cli": "^4.3.1",
|
||||||
"@types/jasmine": "^2.5.52",
|
"@types/jasmine": "^2.5.52",
|
||||||
"@types/node": "~6.0.60",
|
"@types/node": "~6.0.60",
|
||||||
"archiver": "^1.3.0",
|
"archiver": "^1.3.0",
|
||||||
@ -81,7 +83,7 @@
|
|||||||
"concurrently": "^3.4.0",
|
"concurrently": "^3.4.0",
|
||||||
"cross-spawn": "^5.1.0",
|
"cross-spawn": "^5.1.0",
|
||||||
"dgeni": "^0.4.7",
|
"dgeni": "^0.4.7",
|
||||||
"dgeni-packages": "^0.20.0-rc.6",
|
"dgeni-packages": "^0.20.0",
|
||||||
"entities": "^1.1.1",
|
"entities": "^1.1.1",
|
||||||
"eslint": "^3.19.0",
|
"eslint": "^3.19.0",
|
||||||
"eslint-plugin-jasmine": "^2.2.0",
|
"eslint-plugin-jasmine": "^2.2.0",
|
||||||
|
@ -76,8 +76,8 @@ export class AppComponent implements OnInit {
|
|||||||
|
|
||||||
get homeImageUrl() {
|
get homeImageUrl() {
|
||||||
return this.isSideBySide ?
|
return this.isSideBySide ?
|
||||||
'assets/images/logos/standard/logo-nav@2x.png' :
|
'assets/images/logos/angular/logo-nav@2x.png' :
|
||||||
'assets/images/logos/standard/shield-large.svg';
|
'assets/images/logos/angular/shield-large.svg';
|
||||||
}
|
}
|
||||||
get isOpened() { return this.isSideBySide && this.isSideNavDoc; }
|
get isOpened() { return this.isSideBySide && this.isSideNavDoc; }
|
||||||
get mode() { return this.isSideBySide ? 'side' : 'over'; }
|
get mode() { return this.isSideBySide ? 'side' : 'over'; }
|
||||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 178 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 1.7 MiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 519 B After Width: | Height: | Size: 519 B |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 213 B After Width: | Height: | Size: 213 B |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 481 B After Width: | Height: | Size: 481 B |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 131 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 422 B After Width: | Height: | Size: 422 B |
Before Width: | Height: | Size: 783 B After Width: | Height: | Size: 783 B |
Before Width: | Height: | Size: 452 B After Width: | Height: | Size: 452 B |
Before Width: | Height: | Size: 864 B After Width: | Height: | Size: 864 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 782 B After Width: | Height: | Size: 782 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 609 B After Width: | Height: | Size: 609 B |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
@ -1,148 +0,0 @@
|
|||||||
const fs = fsExtra = require('fs-extra');
|
|
||||||
const globby = require('globby');
|
|
||||||
const path = require('path');
|
|
||||||
const Q = require("q");
|
|
||||||
const shelljs = require('shelljs');
|
|
||||||
|
|
||||||
const EXAMPLES_PATH = path.join(__dirname, '/../../content/examples');
|
|
||||||
const SHARED_PATH = path.join(__dirname, '/shared');
|
|
||||||
const BOILERPLATE_PATH = path.join(SHARED_PATH, 'boilerplate');
|
|
||||||
const EXAMPLES_TESTING_PATH = path.join(EXAMPLES_PATH, 'testing');
|
|
||||||
|
|
||||||
const files = {
|
|
||||||
exampleBoilerplate: [
|
|
||||||
'src/styles.css',
|
|
||||||
'src/systemjs-angular-loader.js',
|
|
||||||
'src/systemjs.config.js',
|
|
||||||
'src/tsconfig.json',
|
|
||||||
'bs-config.json',
|
|
||||||
'bs-config.e2e.json',
|
|
||||||
'package.json',
|
|
||||||
'tslint.json'
|
|
||||||
],
|
|
||||||
exampleUnitTestingBoilerplate: [
|
|
||||||
'src/browser-test-shim.js',
|
|
||||||
'karma-test-shim.js',
|
|
||||||
'karma.conf.js'
|
|
||||||
],
|
|
||||||
exampleConfigFilename: 'example-config.json'
|
|
||||||
};
|
|
||||||
|
|
||||||
// requires admin access because it adds symlinks
|
|
||||||
function add() {
|
|
||||||
const realPath = path.join(SHARED_PATH, '/node_modules');
|
|
||||||
const nodeModulesPaths = getNodeModulesPaths(EXAMPLES_PATH);
|
|
||||||
|
|
||||||
// we install the examples modules first
|
|
||||||
installNodeModules();
|
|
||||||
|
|
||||||
nodeModulesPaths.map((linkPath) => {
|
|
||||||
fs.ensureSymlinkSync(realPath, linkPath);
|
|
||||||
});
|
|
||||||
|
|
||||||
return copyExampleBoilerplate();
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyExampleBoilerplate() {
|
|
||||||
console.log('Copying example boilerplate files');
|
|
||||||
const examplePaths = getExamplePaths(EXAMPLES_PATH);
|
|
||||||
// Make boilerplate files read-only to avoid that they be edited by mistake.
|
|
||||||
const destFileMode = '444';
|
|
||||||
let foo = copyFiles(files.exampleBoilerplate, BOILERPLATE_PATH, examplePaths, destFileMode)
|
|
||||||
// copy the unit test boilerplate
|
|
||||||
.then(() => {
|
|
||||||
const unittestPaths = getUnitTestingPaths(EXAMPLES_PATH);
|
|
||||||
return copyFiles(files.exampleUnitTestingBoilerplate, EXAMPLES_TESTING_PATH, unittestPaths, destFileMode);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error(err);
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copies fileNames into destPaths, setting the mode of the
|
|
||||||
// files at the destination as optional_destFileMode if given.
|
|
||||||
// returns a promise
|
|
||||||
function copyFiles(fileNames, originPath, destPaths, optional_destFileMode) {
|
|
||||||
const copy = Q.denodeify(fsExtra.copy);
|
|
||||||
const chmod = Q.denodeify(fsExtra.chmod);
|
|
||||||
let copyPromises = [];
|
|
||||||
destPaths.map((destPath) => {
|
|
||||||
fileNames.forEach((fileName) => {
|
|
||||||
const originName = path.join(originPath, fileName);
|
|
||||||
const destName = path.join(destPath, fileName);
|
|
||||||
let p = copy(originName, destName, { clobber: true});
|
|
||||||
if(optional_destFileMode !== undefined) {
|
|
||||||
p = p.then(() => {
|
|
||||||
return chmod(destName, optional_destFileMode);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
copyPromises.push(p);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return Q.all(copyPromises);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getExamplePaths(basePath, includeBase) {
|
|
||||||
// includeBase defaults to false
|
|
||||||
return getPaths(basePath, files.exampleConfigFilename, includeBase);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFilenames(basePath, filename, includeBase) {
|
|
||||||
let includePatterns = [path.join(basePath, "**/" + filename)];
|
|
||||||
if (!includeBase) {
|
|
||||||
// ignore (skip) the top level version.
|
|
||||||
includePatterns.push("!" + path.join(basePath, "/" + filename));
|
|
||||||
}
|
|
||||||
// ignore (skip) the files in BOILERPLATE_PATH.
|
|
||||||
includePatterns.push("!" + path.join(BOILERPLATE_PATH, "/" + filename));
|
|
||||||
const nmPattern = path.join(basePath, "**/node_modules/**");
|
|
||||||
return globby.sync(includePatterns, {ignore: [nmPattern]});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNodeModulesPaths(basePath) {
|
|
||||||
return getExamplePaths(basePath).map((examplePath) => {
|
|
||||||
return path.join(examplePath, "/node_modules");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPaths(basePath, filename, includeBase) {
|
|
||||||
const filenames = getFilenames(basePath, filename, includeBase);
|
|
||||||
return filenames.map((fileName) => {
|
|
||||||
return path.dirname(fileName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUnitTestingPaths(basePath) {
|
|
||||||
const examples = getPaths(basePath, files.exampleConfigFilename, true);
|
|
||||||
return examples.filter((example) => {
|
|
||||||
const exampleConfig = fs.readJsonSync(`${example}/${files.exampleConfigFilename}`, {throws: false});
|
|
||||||
return exampleConfig && !!exampleConfig.unittesting;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function installNodeModules() {
|
|
||||||
shelljs.exec('yarn', {cwd: SHARED_PATH});
|
|
||||||
}
|
|
||||||
|
|
||||||
function remove() {
|
|
||||||
shelljs.exec('git clean -xdf', {cwd: EXAMPLES_PATH});
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
add: add,
|
|
||||||
remove: remove
|
|
||||||
};
|
|
||||||
|
|
||||||
// being executed from shell script
|
|
||||||
switch (process.argv[2]) {
|
|
||||||
case 'add':
|
|
||||||
add();
|
|
||||||
break;
|
|
||||||
case 'remove':
|
|
||||||
remove();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.error(`There is no function with the name: ${process.argv}`);
|
|
||||||
}
|
|
140
aio/tools/examples/example-boilerplate.js
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
const fs = require('fs-extra');
|
||||||
|
const glob = require('glob');
|
||||||
|
const path = require('canonical-path');
|
||||||
|
const shelljs = require('shelljs');
|
||||||
|
const yargs = require('yargs');
|
||||||
|
|
||||||
|
const SHARED_PATH = path.resolve(__dirname, 'shared');
|
||||||
|
const SHARED_NODE_MODULES_PATH = path.resolve(SHARED_PATH, 'node_modules');
|
||||||
|
const BOILERPLATE_BASE_PATH = path.resolve(SHARED_PATH, 'boilerplate');
|
||||||
|
const EXAMPLES_BASE_PATH = path.resolve(__dirname, '../../content/examples');
|
||||||
|
const TESTING_BASE_PATH = path.resolve(EXAMPLES_BASE_PATH, 'testing');
|
||||||
|
|
||||||
|
const BOILERPLATE_SRC_PATHS = [
|
||||||
|
'src/styles.css',
|
||||||
|
'src/systemjs-angular-loader.js',
|
||||||
|
'src/systemjs.config.js',
|
||||||
|
'src/tsconfig.json',
|
||||||
|
'bs-config.json',
|
||||||
|
'bs-config.e2e.json',
|
||||||
|
'package.json',
|
||||||
|
'tslint.json'
|
||||||
|
];
|
||||||
|
|
||||||
|
const BOILERPLATE_TEST_PATHS = [
|
||||||
|
'src/browser-test-shim.js',
|
||||||
|
'karma-test-shim.js',
|
||||||
|
'karma.conf.js'
|
||||||
|
];
|
||||||
|
|
||||||
|
const ANGULAR_DIST_PATH = path.resolve(__dirname, '../../../dist');
|
||||||
|
const ANGULAR_PACKAGES_PATH = path.resolve(ANGULAR_DIST_PATH, 'packages-dist');
|
||||||
|
const ANGULAR_PACKAGES = [
|
||||||
|
'animations',
|
||||||
|
'common',
|
||||||
|
'compiler',
|
||||||
|
'compiler-cli',
|
||||||
|
'core',
|
||||||
|
'forms',
|
||||||
|
'http',
|
||||||
|
'platform-browser',
|
||||||
|
'platform-browser-dynamic',
|
||||||
|
'platform-server',
|
||||||
|
'router',
|
||||||
|
'upgrade',
|
||||||
|
];
|
||||||
|
const ANGULAR_TOOLS_PACKAGES_PATH = path.resolve(ANGULAR_DIST_PATH, 'tools', '@angular');
|
||||||
|
const ANGULAR_TOOLS_PACKAGES = [
|
||||||
|
'tsc-wrapped'
|
||||||
|
];
|
||||||
|
|
||||||
|
const EXAMPLE_CONFIG_FILENAME = 'example-config.json';
|
||||||
|
|
||||||
|
class ExampleBoilerPlate {
|
||||||
|
/**
|
||||||
|
* Add boilerplate files to all the examples
|
||||||
|
*
|
||||||
|
* @param useLocal if true then overwrite the Angular library files with locally built ones
|
||||||
|
*/
|
||||||
|
add(useLocal) {
|
||||||
|
// first install the shared node_modules
|
||||||
|
this.installNodeModules(SHARED_PATH);
|
||||||
|
|
||||||
|
// Replace the Angular packages with those from the dist folder, if necessary
|
||||||
|
if (useLocal) {
|
||||||
|
ANGULAR_PACKAGES.forEach(packageName => this.overridePackage(ANGULAR_PACKAGES_PATH, packageName));
|
||||||
|
ANGULAR_TOOLS_PACKAGES.forEach(packageName => this.overridePackage(ANGULAR_TOOLS_PACKAGES_PATH, packageName));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all the examples folders, indicated by those that contain a `example-config.json` file
|
||||||
|
const exampleFolders = this.getFoldersContaining(EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, 'node_modules');
|
||||||
|
exampleFolders.forEach(exampleFolder => {
|
||||||
|
|
||||||
|
// Link the node modules - requires admin access (on Windows) because it adds symlinks
|
||||||
|
const destinationNodeModules = path.resolve(exampleFolder, 'node_modules');
|
||||||
|
fs.ensureSymlinkSync(SHARED_NODE_MODULES_PATH, destinationNodeModules);
|
||||||
|
|
||||||
|
// Copy the boilerplate source files
|
||||||
|
BOILERPLATE_SRC_PATHS.forEach(filePath => this.copyFile(BOILERPLATE_BASE_PATH, exampleFolder, filePath));
|
||||||
|
|
||||||
|
// Copy the boilerplate test files (if the example is configured to do unit testing)
|
||||||
|
const exampleConfig = this.loadJsonFile(path.resolve(exampleFolder, EXAMPLE_CONFIG_FILENAME));
|
||||||
|
if (exampleConfig.unittesting) {
|
||||||
|
BOILERPLATE_TEST_PATHS.forEach(filePath => this.copyFile(TESTING_BASE_PATH, exampleFolder, filePath));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all the boilerplate files from all the examples
|
||||||
|
*/
|
||||||
|
remove() {
|
||||||
|
shelljs.exec('git clean -xdfq', {cwd: EXAMPLES_BASE_PATH});
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
yargs
|
||||||
|
.usage('$0 <cmd> [args]')
|
||||||
|
.command('add [--local]', 'add the boilerplate to each example',
|
||||||
|
{ local: { describe: 'Use the locally built Angular libraries, rather than ones from npm.' } },
|
||||||
|
argv => this.add(argv.local))
|
||||||
|
.command('remove', 'remove the boilerplate from each example', () => this.remove())
|
||||||
|
.demandCommand(1, 'Please supply a command from the list above')
|
||||||
|
.argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
installNodeModules(basePath) {
|
||||||
|
shelljs.exec('yarn', {cwd: basePath});
|
||||||
|
}
|
||||||
|
|
||||||
|
overridePackage(basePath, packageName) {
|
||||||
|
const sourceFolder = path.resolve(basePath, packageName);
|
||||||
|
const destinationFolder = path.resolve(SHARED_NODE_MODULES_PATH, '@angular', packageName);
|
||||||
|
shelljs.rm('-rf', destinationFolder);
|
||||||
|
fs.ensureSymlinkSync(sourceFolder, destinationFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFoldersContaining(basePath, filename, ignore) {
|
||||||
|
const pattern = path.resolve(basePath, '**', filename);
|
||||||
|
const ignorePattern = path.resolve(basePath, '**', ignore, '**');
|
||||||
|
return glob.sync(pattern, { ignore: [ignorePattern] }).map(file => path.dirname(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
copyFile(sourceFolder, destinationFolder, filePath) {
|
||||||
|
const sourcePath = path.resolve(sourceFolder, filePath);
|
||||||
|
const destinationPath = path.resolve(destinationFolder, filePath);
|
||||||
|
fs.copySync(sourcePath, destinationPath, { overwrite: true });
|
||||||
|
fs.chmodSync(destinationPath, 444);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadJsonFile(filePath) {
|
||||||
|
return fs.readJsonSync(filePath, {throws: false}) || {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new ExampleBoilerPlate();
|
||||||
|
|
||||||
|
// If this file was run directly then run the main function,
|
||||||
|
if (require.main === module) {
|
||||||
|
module.exports.main();
|
||||||
|
}
|
143
aio/tools/examples/example-boilerplate.spec.js
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
const exampleBoilerPlate = require('./example-boilerplate');
|
||||||
|
const shelljs = require('shelljs');
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
const glob = require('glob');
|
||||||
|
const path = require('canonical-path');
|
||||||
|
|
||||||
|
describe('example-boilerplate tool', () => {
|
||||||
|
describe('add', () => {
|
||||||
|
const numberOfBoilerPlateFiles = 8;
|
||||||
|
const numberOfBoilerPlateTestFiles = 3;
|
||||||
|
const exampleFolders = ['a/b', 'c/d'];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(exampleBoilerPlate, 'installNodeModules');
|
||||||
|
spyOn(exampleBoilerPlate, 'overridePackage');
|
||||||
|
spyOn(exampleBoilerPlate, 'getFoldersContaining').and.returnValue(exampleFolders);
|
||||||
|
spyOn(fs, 'ensureSymlinkSync');
|
||||||
|
spyOn(exampleBoilerPlate, 'copyFile');
|
||||||
|
spyOn(exampleBoilerPlate, 'loadJsonFile').and.returnValue({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should install the node modules', () => {
|
||||||
|
exampleBoilerPlate.add();
|
||||||
|
expect(exampleBoilerPlate.installNodeModules).toHaveBeenCalledWith(path.resolve(__dirname, 'shared'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should override the Angular node_modules with the locally built Angular packages if `useLocal` is true', () => {
|
||||||
|
const numberOfAngularPackages = 12;
|
||||||
|
const numberOfAngularToolsPackages = 1;
|
||||||
|
exampleBoilerPlate.add(true);
|
||||||
|
expect(exampleBoilerPlate.overridePackage).toHaveBeenCalledTimes(numberOfAngularPackages + numberOfAngularToolsPackages);
|
||||||
|
// for example
|
||||||
|
expect(exampleBoilerPlate.overridePackage).toHaveBeenCalledWith(path.resolve(__dirname, '../../../dist/packages-dist'), 'core');
|
||||||
|
expect(exampleBoilerPlate.overridePackage).toHaveBeenCalledWith(path.resolve(__dirname, '../../../dist/tools/@angular'), 'tsc-wrapped');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should process all the example folders', () => {
|
||||||
|
exampleBoilerPlate.add();
|
||||||
|
expect(exampleBoilerPlate.getFoldersContaining).toHaveBeenCalledWith(path.resolve(__dirname, '../../content/examples'), 'example-config.json', 'node_modules');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should symlink the node_modules', () => {
|
||||||
|
exampleBoilerPlate.add();
|
||||||
|
expect(fs.ensureSymlinkSync).toHaveBeenCalledTimes(exampleFolders.length);
|
||||||
|
expect(fs.ensureSymlinkSync).toHaveBeenCalledWith(path.resolve(__dirname, 'shared/node_modules'), path.resolve('a/b/node_modules'));
|
||||||
|
expect(fs.ensureSymlinkSync).toHaveBeenCalledWith(path.resolve(__dirname, 'shared/node_modules'), path.resolve('c/d/node_modules'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should copy all the source boilerplate files', () => {
|
||||||
|
exampleBoilerPlate.add();
|
||||||
|
expect(exampleBoilerPlate.copyFile).toHaveBeenCalledTimes(numberOfBoilerPlateFiles * exampleFolders.length);
|
||||||
|
// for example
|
||||||
|
expect(exampleBoilerPlate.copyFile).toHaveBeenCalledWith(path.resolve(__dirname, 'shared/boilerplate'), 'a/b', 'package.json');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should try to load the example config file', () => {
|
||||||
|
exampleBoilerPlate.add();
|
||||||
|
expect(exampleBoilerPlate.loadJsonFile).toHaveBeenCalledTimes(exampleFolders.length);
|
||||||
|
expect(exampleBoilerPlate.loadJsonFile).toHaveBeenCalledWith(path.resolve('a/b/example-config.json'));
|
||||||
|
expect(exampleBoilerPlate.loadJsonFile).toHaveBeenCalledWith(path.resolve('c/d/example-config.json'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should copy all the test boilerplate files if unit testing is configured', () => {
|
||||||
|
// configure unit testing for example a/b and not c/d
|
||||||
|
exampleBoilerPlate.loadJsonFile.and.callFake(filePath => filePath.indexOf('a/b') !== -1 ? { unittesting: true } : {});
|
||||||
|
exampleBoilerPlate.add();
|
||||||
|
expect(exampleBoilerPlate.copyFile).toHaveBeenCalledTimes((numberOfBoilerPlateFiles * 2) + numberOfBoilerPlateTestFiles);
|
||||||
|
// for example
|
||||||
|
expect(exampleBoilerPlate.copyFile).toHaveBeenCalledWith(path.resolve(__dirname, '../../content/examples/testing'), 'a/b', 'karma.conf.js');
|
||||||
|
expect(exampleBoilerPlate.copyFile).not.toHaveBeenCalledWith(path.resolve(__dirname, '../../content/examples/testing'), 'c/d', 'karma.conf.js');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('remove', () => {
|
||||||
|
it('should run `git clean`', () => {
|
||||||
|
spyOn(shelljs, 'exec');
|
||||||
|
exampleBoilerPlate.remove();
|
||||||
|
expect(shelljs.exec).toHaveBeenCalledWith('git clean -xdfq', {cwd: path.resolve(__dirname, '../../content/examples') });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('installNodeModules', () => {
|
||||||
|
it('should run `yarn` in the base path', () => {
|
||||||
|
spyOn(shelljs, 'exec');
|
||||||
|
exampleBoilerPlate.installNodeModules('some/base/path');
|
||||||
|
expect(shelljs.exec).toHaveBeenCalledWith('yarn', { cwd: 'some/base/path' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('overridePackage', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(shelljs, 'rm');
|
||||||
|
spyOn(fs, 'ensureSymlinkSync');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove the original package from the shared node_modules folder', () => {
|
||||||
|
exampleBoilerPlate.overridePackage('base/path', 'somePackage');
|
||||||
|
expect(shelljs.rm).toHaveBeenCalledWith('-rf', path.resolve(__dirname, 'shared/node_modules/@angular/somePackage'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should symlink the source folder to the shared node_modules folder', () => {
|
||||||
|
exampleBoilerPlate.overridePackage('base/path', 'somePackage');
|
||||||
|
expect(fs.ensureSymlinkSync).toHaveBeenCalledWith(path.resolve('base/path/somePackage'), path.resolve(__dirname, 'shared/node_modules/@angular/somePackage'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getFoldersContaining', () => {
|
||||||
|
it('should use glob.sync', () => {
|
||||||
|
spyOn(glob, 'sync').and.returnValue(['a/b/config.json', 'c/d/config.json']);
|
||||||
|
const result = exampleBoilerPlate.getFoldersContaining('base/path', 'config.json', 'node_modules');
|
||||||
|
expect(glob.sync).toHaveBeenCalledWith(path.resolve('base/path/**/config.json'), { ignore: [path.resolve('base/path/**/node_modules/**')] });
|
||||||
|
expect(result).toEqual(['a/b', 'c/d']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('copyFile', () => {
|
||||||
|
it('should use copySync and chmodSync', () => {
|
||||||
|
spyOn(fs, 'copySync');
|
||||||
|
spyOn(fs, 'chmodSync');
|
||||||
|
exampleBoilerPlate.copyFile('source/folder', 'destination/folder', 'some/file/path');
|
||||||
|
expect(fs.copySync).toHaveBeenCalledWith(
|
||||||
|
path.resolve('source/folder/some/file/path'),
|
||||||
|
path.resolve('destination/folder/some/file/path'),
|
||||||
|
{ overwrite: true });
|
||||||
|
expect(fs.chmodSync).toHaveBeenCalledWith(path.resolve('destination/folder/some/file/path'), 444);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('loadJsonFile', () => {
|
||||||
|
it('should use fs.readJsonSync', () => {
|
||||||
|
spyOn(fs, 'readJsonSync').and.returnValue({ some: 'value' });
|
||||||
|
const result = exampleBoilerPlate.loadJsonFile('some/file');
|
||||||
|
expect(fs.readJsonSync).toHaveBeenCalledWith('some/file', {throws: false});
|
||||||
|
expect(result).toEqual({ some: 'value' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an empty object if readJsonSync fails', () => {
|
||||||
|
spyOn(fs, 'readJsonSync').and.returnValue(null);
|
||||||
|
const result = exampleBoilerPlate.loadJsonFile('some/file');
|
||||||
|
expect(result).toEqual({});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -22,15 +22,24 @@ const IGNORED_EXAMPLES = [
|
|||||||
* --filter to filter/select _example app subdir names
|
* --filter to filter/select _example app subdir names
|
||||||
* e.g. --filter=foo // all example apps with 'foo' in their folder names.
|
* e.g. --filter=foo // all example apps with 'foo' in their folder names.
|
||||||
*
|
*
|
||||||
* --setup run yarn install, copy boilerplate and update webdriver
|
* --setup run yarn install, copy boilerplate and update webdriver
|
||||||
* e.g. --setup
|
* e.g. --setup
|
||||||
|
*
|
||||||
|
* --local to use the locally built Angular packages, rather than versions from npm
|
||||||
|
* Must be used in conjunction with --setup as this is when the packages are copied.
|
||||||
|
* e.g. --setup --local
|
||||||
|
*
|
||||||
|
* --shard to shard the specs into groups to allow you to run them in parallel
|
||||||
|
* e.g. --shard=0/2 // the even specs: 0, 2, 4, etc
|
||||||
|
* e.g. --shard=1/2 // the odd specs: 1, 3, 5, etc
|
||||||
|
* e.g. --shard=1/3 // the second of every three specs: 1, 4, 7, etc
|
||||||
*/
|
*/
|
||||||
function runE2e() {
|
function runE2e() {
|
||||||
let promise = Promise.resolve();
|
let promise = Promise.resolve();
|
||||||
if (argv.setup) {
|
if (argv.setup) {
|
||||||
// Run setup.
|
// Run setup.
|
||||||
console.log('runE2e: copy boilerplate');
|
console.log('runE2e: copy boilerplate');
|
||||||
const spawnInfo = spawnExt('yarn', ['boilerplate:add'], { cwd: AIO_PATH });
|
const spawnInfo = spawnExt('yarn', ['boilerplate:add', argv.local ? '-- --local': ''], { cwd: AIO_PATH });
|
||||||
promise = spawnInfo.promise
|
promise = spawnInfo.promise
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log('runE2e: update webdriver');
|
console.log('runE2e: update webdriver');
|
||||||
@ -41,7 +50,7 @@ function runE2e() {
|
|||||||
const outputFile = path.join(AIO_PATH, './protractor-results.txt');
|
const outputFile = path.join(AIO_PATH, './protractor-results.txt');
|
||||||
|
|
||||||
return promise
|
return promise
|
||||||
.then(() => findAndRunE2eTests(argv.filter, outputFile))
|
.then(() => findAndRunE2eTests(argv.filter, outputFile, argv.shard))
|
||||||
.then((status) => {
|
.then((status) => {
|
||||||
reportStatus(status, outputFile);
|
reportStatus(status, outputFile);
|
||||||
if (status.failed.length > 0) {
|
if (status.failed.length > 0) {
|
||||||
@ -55,7 +64,12 @@ function runE2e() {
|
|||||||
|
|
||||||
// Finds all of the *e2e-spec.tests under the examples folder along with the corresponding apps
|
// Finds all of the *e2e-spec.tests under the examples folder along with the corresponding apps
|
||||||
// that they should run under. Then run each app/spec collection sequentially.
|
// that they should run under. Then run each app/spec collection sequentially.
|
||||||
function findAndRunE2eTests(filter, outputFile) {
|
function findAndRunE2eTests(filter, outputFile, shard) {
|
||||||
|
|
||||||
|
const shardParts = shard ? shard.split('/') : [0,1];
|
||||||
|
const shardModulo = parseInt(shardParts[0], 10);
|
||||||
|
const shardDivider = parseInt(shardParts[1], 10);
|
||||||
|
|
||||||
// create an output file with header.
|
// create an output file with header.
|
||||||
const startTime = new Date().getTime();
|
const startTime = new Date().getTime();
|
||||||
let header = `Doc Sample Protractor Results on ${new Date().toLocaleString()}\n`;
|
let header = `Doc Sample Protractor Results on ${new Date().toLocaleString()}\n`;
|
||||||
@ -65,7 +79,9 @@ function findAndRunE2eTests(filter, outputFile) {
|
|||||||
// Run the tests sequentially.
|
// Run the tests sequentially.
|
||||||
const status = { passed: [], failed: [] };
|
const status = { passed: [], failed: [] };
|
||||||
return getE2eSpecPaths(EXAMPLES_PATH, filter)
|
return getE2eSpecPaths(EXAMPLES_PATH, filter)
|
||||||
.then(e2eSpecPaths => e2eSpecPaths.reduce((promise, specPath) => {
|
.then(e2eSpecPaths => e2eSpecPaths
|
||||||
|
.filter((paths, index) => index % shardDivider === shardModulo)
|
||||||
|
.reduce((promise, specPath) => {
|
||||||
return promise.then(() => {
|
return promise.then(() => {
|
||||||
const examplePath = path.dirname(specPath);
|
const examplePath = path.dirname(specPath);
|
||||||
return runE2eTests(examplePath, outputFile).then((ok) => {
|
return runE2eTests(examplePath, outputFile).then((ok) => {
|
||||||
|
17
aio/tools/examples/test.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* Use this script to run the tests for the doc generation
|
||||||
|
* We cannot use the Jasmine CLI directly because it doesn't seem to
|
||||||
|
* understand the glob and only runs one spec file.
|
||||||
|
*
|
||||||
|
* Equally we cannot use a jasmine.json config file because it doesn't
|
||||||
|
* allow us to set the projectBaseDir, which means that you have to run
|
||||||
|
* jasmine CLI from this directory.
|
||||||
|
*
|
||||||
|
* Using a file like this gives us full control and keeps the package.json
|
||||||
|
* file clean and simple.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const Jasmine = require('jasmine');
|
||||||
|
const jasmine = new Jasmine({ projectBaseDir: __dirname });
|
||||||
|
jasmine.loadConfig({ spec_files: ['*.spec.js'] });
|
||||||
|
jasmine.execute();
|
@ -34,5 +34,5 @@ function getText(h1) {
|
|||||||
(node.properties.ariaHidden === 'true' || node.properties['aria-hidden'] === 'true')
|
(node.properties.ariaHidden === 'true' || node.properties['aria-hidden'] === 'true')
|
||||||
));
|
));
|
||||||
|
|
||||||
return toString(cleaned);
|
return cleaned ? toString(cleaned) : '';
|
||||||
}
|
}
|
||||||
|