Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
79fb9d449c | |||
73a93d3ab6 | |||
8eda5a152b | |||
7b82ce0c67 | |||
2eb5fe699f | |||
f99febcdf9 | |||
36cbfb1771 | |||
1f5315f6f7 | |||
eeebe621fe | |||
05f279df49 | |||
485d67bfed | |||
a1592f5a20 | |||
a251374ecd | |||
2b00c17091 | |||
81724f5790 | |||
1f06b6c99b | |||
6790709b93 | |||
9f7f67121c | |||
db49beae15 | |||
97609daea9 | |||
abcb03cb82 | |||
4f09f7db73 | |||
f1e14a3224 | |||
50de03a83a | |||
65555fe35d | |||
6da3867d63 |
@ -56,6 +56,7 @@ env:
|
|||||||
matrix:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
allow_failures:
|
allow_failures:
|
||||||
|
- env: "CI_MODE=aio_local"
|
||||||
- env: "CI_MODE=saucelabs_optional"
|
- env: "CI_MODE=saucelabs_optional"
|
||||||
- env: "CI_MODE=browserstack_optional"
|
- env: "CI_MODE=browserstack_optional"
|
||||||
|
|
||||||
|
@ -71,6 +71,8 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
|||||||
|
|
||||||
1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR
|
1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR
|
||||||
that relates to your submission. You don't want to duplicate effort.
|
that relates to your submission. You don't want to duplicate effort.
|
||||||
|
1. Be sure that an issue describes the problem you're fixing, or documents the design for the feature you'd like to add.
|
||||||
|
Discussing the design up front helps to ensure that we're ready to accept your work.
|
||||||
1. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
|
1. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
|
||||||
We cannot accept code without this. Make sure you sign with the primary email address of the Git identity that has been granted access to the Angular repository.
|
We cannot accept code without this. Make sure you sign with the primary email address of the Git identity that has been granted access to the Angular repository.
|
||||||
1. Fork the angular/angular repo.
|
1. Fork the angular/angular repo.
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
"@types/shelljs": "^0.8.0",
|
"@types/shelljs": "^0.8.0",
|
||||||
"@types/supertest": "^2.0.5",
|
"@types/supertest": "^2.0.5",
|
||||||
"nodemon": "^1.18.3",
|
"nodemon": "^1.18.3",
|
||||||
"npm-run-all": "^4.1.3",
|
"npm-run-all": "^4.1.5",
|
||||||
"supertest": "^3.1.0",
|
"supertest": "^3.1.0",
|
||||||
"tslint": "^5.11.0",
|
"tslint": "^5.11.0",
|
||||||
"tslint-jasmine-noSkipOrFocus": "^1.0.9",
|
"tslint-jasmine-noSkipOrFocus": "^1.0.9",
|
||||||
|
@ -129,7 +129,7 @@ ansi-styles@^2.2.1:
|
|||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
|
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
|
||||||
|
|
||||||
ansi-styles@^3.2.0, ansi-styles@^3.2.1:
|
ansi-styles@^3.2.1:
|
||||||
version "3.2.1"
|
version "3.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
|
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -384,7 +384,7 @@ chalk@^1.1.3:
|
|||||||
strip-ansi "^3.0.0"
|
strip-ansi "^3.0.0"
|
||||||
supports-color "^2.0.0"
|
supports-color "^2.0.0"
|
||||||
|
|
||||||
chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0:
|
chalk@^2.0.1, chalk@^2.3.0:
|
||||||
version "2.4.1"
|
version "2.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -392,6 +392,15 @@ chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0:
|
|||||||
escape-string-regexp "^1.0.5"
|
escape-string-regexp "^1.0.5"
|
||||||
supports-color "^5.3.0"
|
supports-color "^5.3.0"
|
||||||
|
|
||||||
|
chalk@^2.4.1:
|
||||||
|
version "2.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||||
|
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||||
|
dependencies:
|
||||||
|
ansi-styles "^3.2.1"
|
||||||
|
escape-string-regexp "^1.0.5"
|
||||||
|
supports-color "^5.3.0"
|
||||||
|
|
||||||
check-error@^1.0.1:
|
check-error@^1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
|
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
|
||||||
@ -532,9 +541,10 @@ cross-spawn@^5.0.1:
|
|||||||
shebang-command "^1.2.0"
|
shebang-command "^1.2.0"
|
||||||
which "^1.2.9"
|
which "^1.2.9"
|
||||||
|
|
||||||
cross-spawn@^6.0.4:
|
cross-spawn@^6.0.5:
|
||||||
version "6.0.5"
|
version "6.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||||
|
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
nice-try "^1.0.4"
|
nice-try "^1.0.4"
|
||||||
path-key "^2.0.1"
|
path-key "^2.0.1"
|
||||||
@ -1630,16 +1640,17 @@ npm-packlist@^1.1.6:
|
|||||||
ignore-walk "^3.0.1"
|
ignore-walk "^3.0.1"
|
||||||
npm-bundled "^1.0.1"
|
npm-bundled "^1.0.1"
|
||||||
|
|
||||||
npm-run-all@^4.1.3:
|
npm-run-all@^4.1.5:
|
||||||
version "4.1.3"
|
version "4.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.3.tgz#49f15b55a66bb4101664ce270cb18e7103f8f185"
|
resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba"
|
||||||
|
integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-styles "^3.2.0"
|
ansi-styles "^3.2.1"
|
||||||
chalk "^2.1.0"
|
chalk "^2.4.1"
|
||||||
cross-spawn "^6.0.4"
|
cross-spawn "^6.0.5"
|
||||||
memorystream "^0.3.1"
|
memorystream "^0.3.1"
|
||||||
minimatch "^3.0.4"
|
minimatch "^3.0.4"
|
||||||
ps-tree "^1.1.0"
|
pidtree "^0.3.0"
|
||||||
read-pkg "^3.0.0"
|
read-pkg "^3.0.0"
|
||||||
shell-quote "^1.6.1"
|
shell-quote "^1.6.1"
|
||||||
string.prototype.padend "^3.0.0"
|
string.prototype.padend "^3.0.0"
|
||||||
@ -1786,6 +1797,11 @@ pause-stream@0.0.11:
|
|||||||
dependencies:
|
dependencies:
|
||||||
through "~2.3"
|
through "~2.3"
|
||||||
|
|
||||||
|
pidtree@^0.3.0:
|
||||||
|
version "0.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.0.tgz#f6fada10fccc9f99bf50e90d0b23d72c9ebc2e6b"
|
||||||
|
integrity sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==
|
||||||
|
|
||||||
pify@^2.3.0:
|
pify@^2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
||||||
|
@ -17,7 +17,7 @@ Here are some key features.
|
|||||||
* [Server-side Rendering](guide/universal): Angular Universal generates static application pages on the server through server-side rendering (SSR). This allows you to run your Angular app on the server in order to improve performance and show the first page quickly on mobile and low-powered devices, and also facilitate web crawlers.
|
* [Server-side Rendering](guide/universal): Angular Universal generates static application pages on the server through server-side rendering (SSR). This allows you to run your Angular app on the server in order to improve performance and show the first page quickly on mobile and low-powered devices, and also facilitate web crawlers.
|
||||||
|
|
||||||
* [Service Workers](guide/service-worker-intro): Use a service worker to reduce dependency on the network
|
* [Service Workers](guide/service-worker-intro): Use a service worker to reduce dependency on the network
|
||||||
significantly improving the use experience.
|
significantly improving the user experience.
|
||||||
|
|
||||||
## Domain-specific libraries
|
## Domain-specific libraries
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ The `@Injectable()` decorator is the standard decorator for service classes.
|
|||||||
|
|
||||||
<div class="alert-is-helpful">
|
<div class="alert-is-helpful">
|
||||||
|
|
||||||
The decorator requirement is imposed by TypeScript. TypeScript normally discards parameter type information when it [transpiles]((guide/glossary#transpile) the code to JavaScript. TypeScript preserves this information if the class has a decorator and the `emitDecoratorMetadata` compiler option is set `true` in TypeScript's `tsconfig.json` configuration file. The CLI configures `tsconfig.json` with `emitDecoratorMetadata: true`.
|
The decorator requirement is imposed by TypeScript. TypeScript normally discards parameter type information when it [transpiles](guide/glossary#transpile) the code to JavaScript. TypeScript preserves this information if the class has a decorator and the `emitDecoratorMetadata` compiler option is set `true` in TypeScript's `tsconfig.json` configuration file. The CLI configures `tsconfig.json` with `emitDecoratorMetadata: true`.
|
||||||
|
|
||||||
This means you're responsible for putting `@Injectable()` on your service classes.
|
This means you're responsible for putting `@Injectable()` on your service classes.
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,12 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
<!-- AngularMix -->
|
||||||
|
<tr>
|
||||||
|
<th><a href="https://angularmix.com/" title="AngularMix">AngularMix</a></th>
|
||||||
|
<td>Orlando, Florida</td>
|
||||||
|
<td>October 10-12, 2018</td>
|
||||||
|
</tr>
|
||||||
<!-- ReactiveConf -->
|
<!-- ReactiveConf -->
|
||||||
<tr>
|
<tr>
|
||||||
<th><a href="https://reactiveconf.com/" title="ReactiveConf">ReactiveConf</a></th>
|
<th><a href="https://reactiveconf.com/" title="ReactiveConf">ReactiveConf</a></th>
|
||||||
@ -59,13 +65,13 @@
|
|||||||
<!-- ngconf 2018-->
|
<!-- ngconf 2018-->
|
||||||
<tr>
|
<tr>
|
||||||
<th><a href="https://www.ng-conf.org/" title="ng-conf">ng-conf</a></th>
|
<th><a href="https://www.ng-conf.org/" title="ng-conf">ng-conf</a></th>
|
||||||
<td>Salt Lake City, UT</td>
|
<td>Salt Lake City, Utah</td>
|
||||||
<td>April 18-20, 2018</td>
|
<td>April 18-20, 2018</td>
|
||||||
</tr>
|
</tr>
|
||||||
<!-- WeRDevs-->
|
<!-- WeRDevs-->
|
||||||
<tr>
|
<tr>
|
||||||
<th><a href="https://www.wearedevelopers.com/" title="WeAreDevs">WeAreDevelopers</a></th>
|
<th><a href="https://www.wearedevelopers.com/" title="WeAreDevs">WeAreDevelopers</a></th>
|
||||||
<td>Vienna</td>
|
<td>Vienna, Austria</td>
|
||||||
<td>May 16-18, 2018</td>
|
<td>May 16-18, 2018</td>
|
||||||
</tr>
|
</tr>
|
||||||
<!-- ngJapan-->
|
<!-- ngJapan-->
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
"postsetup-local": "yarn postsetup",
|
"postsetup-local": "yarn postsetup",
|
||||||
"set-opensearch-url": "node --eval \"const sh = require('shelljs'); sh.set('-e'); sh.sed('-i', /PLACEHOLDER_URL/g, process.argv[1], 'dist/assets/opensearch.xml');\"",
|
"set-opensearch-url": "node --eval \"const sh = require('shelljs'); sh.set('-e'); sh.sed('-i', /PLACEHOLDER_URL/g, process.argv[1], 'dist/assets/opensearch.xml');\"",
|
||||||
"test-pwa-score": "node scripts/test-pwa-score",
|
"test-pwa-score": "node scripts/test-pwa-score",
|
||||||
"test-pwa-score-localhost": "run-p --race \"~~http-server dist -p 4200 --silent\" \"test-pwa-score http://localhost:4200 {1}\" --",
|
"test-pwa-score-localhost": "run-p --race \"~~http-server dist -p 4200 --silent\" \"test-pwa-score http://localhost:4200 {1} {2}\" --",
|
||||||
"example-e2e": "yarn example-check-local && node ./tools/examples/run-example-e2e",
|
"example-e2e": "yarn example-check-local && node ./tools/examples/run-example-e2e",
|
||||||
"example-lint": "tslint -c \"content/examples/tslint.json\" \"content/examples/**/*.ts\" -e \"content/examples/styleguide/**/*.avoid.ts\"",
|
"example-lint": "tslint -c \"content/examples/tslint.json\" \"content/examples/**/*.ts\" -e \"content/examples/styleguide/**/*.avoid.ts\"",
|
||||||
"example-use-local": "node tools/ng-packages-installer overwrite ./tools/examples/shared --debug",
|
"example-use-local": "node tools/ng-packages-installer overwrite ./tools/examples/shared --debug",
|
||||||
@ -71,17 +71,17 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^7.0.0-rc.0",
|
"@angular/animations": "^7.0.0-rc.1",
|
||||||
"@angular/cdk": "6.0.2",
|
"@angular/cdk": "7.0.0-rc.1",
|
||||||
"@angular/common": "^7.0.0-rc.0",
|
"@angular/common": "^7.0.0-rc.1",
|
||||||
"@angular/core": "^7.0.0-rc.0",
|
"@angular/core": "^7.0.0-rc.1",
|
||||||
"@angular/elements": "^7.0.0-rc.0",
|
"@angular/elements": "^7.0.0-rc.1",
|
||||||
"@angular/forms": "^7.0.0-rc.0",
|
"@angular/forms": "^7.0.0-rc.1",
|
||||||
"@angular/material": "6.0.2",
|
"@angular/material": "7.0.0-rc.1",
|
||||||
"@angular/platform-browser": "^7.0.0-rc.0",
|
"@angular/platform-browser": "^7.0.0-rc.1",
|
||||||
"@angular/platform-browser-dynamic": "^7.0.0-rc.0",
|
"@angular/platform-browser-dynamic": "^7.0.0-rc.1",
|
||||||
"@angular/router": "^7.0.0-rc.0",
|
"@angular/router": "^7.0.0-rc.1",
|
||||||
"@angular/service-worker": "^7.0.0-rc.0",
|
"@angular/service-worker": "^7.0.0-rc.1",
|
||||||
"@webcomponents/custom-elements": "^1.2.0",
|
"@webcomponents/custom-elements": "^1.2.0",
|
||||||
"classlist.js": "^1.1.20150312",
|
"classlist.js": "^1.1.20150312",
|
||||||
"core-js": "^2.4.1",
|
"core-js": "^2.4.1",
|
||||||
@ -91,14 +91,15 @@
|
|||||||
"zone.js": "^0.8.26"
|
"zone.js": "^0.8.26"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "^0.8.3",
|
"@angular-devkit/build-angular": "~0.9.0-rc.1",
|
||||||
"@angular/cli": "^6.2.3",
|
"@angular/cli": "^7.0.0-rc.2",
|
||||||
"@angular/compiler": "^7.0.0-rc.0",
|
"@angular/compiler": "^7.0.0-rc.1",
|
||||||
"@angular/compiler-cli": "^7.0.0-rc.0",
|
"@angular/compiler-cli": "^7.0.0-rc.1",
|
||||||
"@angular/language-service": "^7.0.0-rc.0",
|
"@angular/language-service": "^7.0.0-rc.1",
|
||||||
"@types/jasmine": "^2.5.52",
|
"@types/jasmine": "^2.5.52",
|
||||||
"@types/jasminewd2": "^2.0.3",
|
"@types/jasminewd2": "^2.0.4",
|
||||||
"@types/node": "~6.0.60",
|
"@types/node": "~6.0.60",
|
||||||
|
"@yarnpkg/lockfile": "^1.1.0",
|
||||||
"archiver": "^1.3.0",
|
"archiver": "^1.3.0",
|
||||||
"canonical-path": "^0.0.2",
|
"canonical-path": "^0.0.2",
|
||||||
"chalk": "^2.1.0",
|
"chalk": "^2.1.0",
|
||||||
@ -111,7 +112,7 @@
|
|||||||
"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",
|
||||||
"firebase-tools": "^3.2.1",
|
"firebase-tools": "^5.1.1",
|
||||||
"fs-extra": "^2.1.2",
|
"fs-extra": "^2.1.2",
|
||||||
"globby": "^6.1.0",
|
"globby": "^6.1.0",
|
||||||
"hast-util-is-element": "^1.0.0",
|
"hast-util-is-element": "^1.0.0",
|
||||||
@ -132,10 +133,10 @@
|
|||||||
"karma-coverage-istanbul-reporter": "^1.3.0",
|
"karma-coverage-istanbul-reporter": "^1.3.0",
|
||||||
"karma-jasmine": "^1.1.0",
|
"karma-jasmine": "^1.1.0",
|
||||||
"karma-jasmine-html-reporter": "^0.2.2",
|
"karma-jasmine-html-reporter": "^0.2.2",
|
||||||
"lighthouse": "^2.5.0",
|
"lighthouse": "^3.2.1",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"lunr": "^2.1.0",
|
"lunr": "^2.1.0",
|
||||||
"npm-run-all": "^4.1.3",
|
"npm-run-all": "^4.1.5",
|
||||||
"protractor": "^5.2.0",
|
"protractor": "^5.2.0",
|
||||||
"rehype": "^4.0.0",
|
"rehype": "^4.0.0",
|
||||||
"rehype-slug": "^2.0.0",
|
"rehype-slug": "^2.0.0",
|
||||||
@ -147,7 +148,7 @@
|
|||||||
"tree-kill": "^1.1.0",
|
"tree-kill": "^1.1.0",
|
||||||
"ts-node": "^3.3.0",
|
"ts-node": "^3.3.0",
|
||||||
"tslint": "~5.9.1",
|
"tslint": "~5.9.1",
|
||||||
"typescript": "^3.1.1",
|
"typescript": "^3.1.2",
|
||||||
"uglify-js": "^3.0.15",
|
"uglify-js": "^3.0.15",
|
||||||
"unist-util-filter": "^0.2.1",
|
"unist-util-filter": "^0.2.1",
|
||||||
"unist-util-source": "^1.0.1",
|
"unist-util-source": "^1.0.1",
|
||||||
@ -159,4 +160,4 @@
|
|||||||
"xregexp": "^4.0.0",
|
"xregexp": "^4.0.0",
|
||||||
"yargs": "^7.0.2"
|
"yargs": "^7.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
"master": {
|
"master": {
|
||||||
"uncompressed": {
|
"uncompressed": {
|
||||||
"runtime": 3173,
|
"runtime": 3173,
|
||||||
"main": 483428,
|
"main": 494475,
|
||||||
"polyfills": 53920,
|
"polyfills": 53926,
|
||||||
"prettify": 14913
|
"prettify": 14917
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,8 +100,8 @@ fi
|
|||||||
yarn payload-size
|
yarn payload-size
|
||||||
|
|
||||||
# Deploy to Firebase
|
# Deploy to Firebase
|
||||||
firebase use "$projectId" --token "$firebaseToken"
|
yarn firebase use "$projectId" --token "$firebaseToken"
|
||||||
firebase deploy --message "Commit: $TRAVIS_COMMIT" --non-interactive --token "$firebaseToken"
|
yarn firebase deploy --message "Commit: $TRAVIS_COMMIT" --non-interactive --token "$firebaseToken"
|
||||||
|
|
||||||
# Run PWA-score tests
|
# Run PWA-score tests
|
||||||
yarn test-pwa-score "$deployedUrl" "$AIO_MIN_PWA_SCORE"
|
yarn test-pwa-score "$deployedUrl" "$AIO_MIN_PWA_SCORE"
|
||||||
|
@ -11,13 +11,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Imports
|
// Imports
|
||||||
|
const chromeLauncher = require('chrome-launcher');
|
||||||
const lighthouse = require('lighthouse');
|
const lighthouse = require('lighthouse');
|
||||||
const chromeLauncher = require('lighthouse/chrome-launcher');
|
|
||||||
const printer = require('lighthouse/lighthouse-cli/printer');
|
const printer = require('lighthouse/lighthouse-cli/printer');
|
||||||
const config = require('lighthouse/lighthouse-core/config/default.js');
|
const config = require('lighthouse/lighthouse-core/config/default-config.js');
|
||||||
|
const logger = require('lighthouse-logger');
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
const CHROME_LAUNCH_OPTS = {};
|
const CHROME_LAUNCH_OPTS = {};
|
||||||
|
const LIGHTHOUSE_FLAGS = {logLevel: 'info'};
|
||||||
const SKIPPED_HTTPS_AUDITS = ['redirects-http'];
|
const SKIPPED_HTTPS_AUDITS = ['redirects-http'];
|
||||||
const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer/';
|
const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer/';
|
||||||
|
|
||||||
@ -26,6 +28,7 @@ const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer/';
|
|||||||
if (process.env.TRAVIS) {
|
if (process.env.TRAVIS) {
|
||||||
process.env.LIGHTHOUSE_CHROMIUM_PATH = process.env.CHROME_BIN;
|
process.env.LIGHTHOUSE_CHROMIUM_PATH = process.env.CHROME_BIN;
|
||||||
CHROME_LAUNCH_OPTS.chromeFlags = ['--no-sandbox'];
|
CHROME_LAUNCH_OPTS.chromeFlags = ['--no-sandbox'];
|
||||||
|
LIGHTHOUSE_FLAGS.logLevel = 'error';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run
|
// Run
|
||||||
@ -42,18 +45,20 @@ function _main(args) {
|
|||||||
skipHttpsAudits(config);
|
skipHttpsAudits(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
launchChromeAndRunLighthouse(url, {}, config).
|
logger.setLevel(LIGHTHOUSE_FLAGS.logLevel);
|
||||||
|
|
||||||
|
launchChromeAndRunLighthouse(url, LIGHTHOUSE_FLAGS, config).
|
||||||
then(results => processResults(results, logFile)).
|
then(results => processResults(results, logFile)).
|
||||||
then(score => evaluateScore(minScore, score)).
|
then(score => evaluateScore(minScore, score)).
|
||||||
catch(onError);
|
catch(onError);
|
||||||
}
|
}
|
||||||
|
|
||||||
function evaluateScore(expectedScore, actualScore) {
|
function evaluateScore(expectedScore, actualScore) {
|
||||||
console.log('Lighthouse PWA score:');
|
console.log('\nLighthouse PWA score:');
|
||||||
console.log(` - Expected: ${expectedScore} / 100 (or higher)`);
|
console.log(` - Expected: ${expectedScore.toFixed(0).padStart(3)} / 100 (or higher)`);
|
||||||
console.log(` - Actual: ${actualScore} / 100`);
|
console.log(` - Actual: ${actualScore.toFixed(0).padStart(3)} / 100\n`);
|
||||||
|
|
||||||
if (actualScore < expectedScore) {
|
if (isNaN(actualScore) || (actualScore < expectedScore)) {
|
||||||
throw new Error(`PWA score is too low. (${actualScore} < ${expectedScore})`);
|
throw new Error(`PWA score is too low. (${actualScore} < ${expectedScore})`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,20 +92,30 @@ function parseInput(args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function processResults(results, logFile) {
|
function processResults(results, logFile) {
|
||||||
let promise = Promise.resolve();
|
const categories = results.lhr.categories;
|
||||||
|
const report = results.report;
|
||||||
|
|
||||||
if (logFile) {
|
return Promise.resolve().
|
||||||
console.log(`Saving results in '${logFile}'...`);
|
then(() => {
|
||||||
console.log(`(LightHouse viewer: ${VIEWER_URL})`);
|
if (logFile) {
|
||||||
|
console.log(`Saving results in '${logFile}'...`);
|
||||||
|
console.log(`(LightHouse viewer: ${VIEWER_URL})`);
|
||||||
|
|
||||||
// Remove the artifacts, which are not necessary for the report.
|
return printer.write(report, printer.OutputMode.json, logFile);
|
||||||
// (Saves ~1,500,000 lines of formatted JSON output \o/)
|
}
|
||||||
results.artifacts = undefined;
|
}).
|
||||||
|
then(() => {
|
||||||
|
const categoryData = Object.keys(categories).map(name => categories[name]);
|
||||||
|
const maxTitleLen = Math.max(...categoryData.map(({title}) => title.length));
|
||||||
|
|
||||||
promise = printer.write(results, 'json', logFile);
|
console.log('\nAudit scores:');
|
||||||
}
|
categoryData.forEach(({title, score}) => {
|
||||||
|
const paddedTitle = `${title}:`.padEnd(maxTitleLen + 1);
|
||||||
return promise.then(() => Math.round(results.score));
|
const paddedScore = (score * 100).toFixed(0).padStart(3);
|
||||||
|
console.log(` - ${paddedTitle} ${paddedScore} / 100`);
|
||||||
|
});
|
||||||
|
}).
|
||||||
|
then(() => categories.pwa.score * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
function skipHttpsAudits(config) {
|
function skipHttpsAudits(config) {
|
||||||
|
@ -164,10 +164,10 @@ describe('AppComponent', () => {
|
|||||||
|
|
||||||
describe('onScroll', () => {
|
describe('onScroll', () => {
|
||||||
it('should update `tocMaxHeight` accordingly', () => {
|
it('should update `tocMaxHeight` accordingly', () => {
|
||||||
expect(component.tocMaxHeight).toBeUndefined();
|
component.tocMaxHeight = '';
|
||||||
|
|
||||||
component.onScroll();
|
component.onScroll();
|
||||||
expect(component.tocMaxHeight).toBeGreaterThan(0);
|
|
||||||
|
expect(component.tocMaxHeight).toMatch(/^\d+\.\d{2}$/);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -654,12 +654,13 @@ describe('AppComponent', () => {
|
|||||||
it('should update the TOC container\'s `maxHeight` based on `tocMaxHeight`', () => {
|
it('should update the TOC container\'s `maxHeight` based on `tocMaxHeight`', () => {
|
||||||
setHasFloatingToc(true);
|
setHasFloatingToc(true);
|
||||||
|
|
||||||
expect(tocContainer!.style['max-height']).toBe('');
|
|
||||||
|
|
||||||
component.tocMaxHeight = '100';
|
component.tocMaxHeight = '100';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
expect(tocContainer!.style['max-height']).toBe('100px');
|
expect(tocContainer!.style['max-height']).toBe('100px');
|
||||||
|
|
||||||
|
component.tocMaxHeight = '200';
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(tocContainer!.style['max-height']).toBe('200px');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should restrain scrolling inside the ToC container', () => {
|
it('should restrain scrolling inside the ToC container', () => {
|
||||||
|
@ -349,12 +349,17 @@ export class AppComponent implements OnInit {
|
|||||||
@HostListener('window:scroll')
|
@HostListener('window:scroll')
|
||||||
onScroll() {
|
onScroll() {
|
||||||
if (!this.tocMaxHeightOffset) {
|
if (!this.tocMaxHeightOffset) {
|
||||||
// Must wait until now for mat-toolbar to be measurable.
|
// Must wait until `mat-toolbar` is measurable.
|
||||||
const el = this.hostElement.nativeElement as Element;
|
const el = this.hostElement.nativeElement as Element;
|
||||||
this.tocMaxHeightOffset =
|
const headerEl = el.querySelector('.app-toolbar');
|
||||||
el.querySelector('footer')!.clientHeight +
|
const footerEl = el.querySelector('footer');
|
||||||
el.querySelector('.app-toolbar')!.clientHeight +
|
|
||||||
24; // fudge margin
|
if (headerEl && footerEl) {
|
||||||
|
this.tocMaxHeightOffset =
|
||||||
|
headerEl.clientHeight +
|
||||||
|
footerEl.clientHeight +
|
||||||
|
24; // fudge margin
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tocMaxHeight = (document.body.scrollHeight - window.pageYOffset - this.tocMaxHeightOffset).toFixed(2);
|
this.tocMaxHeight = (document.body.scrollHeight - window.pageYOffset - this.tocMaxHeightOffset).toFixed(2);
|
||||||
|
@ -115,6 +115,7 @@ button.vertical-menu-item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.heading-children.collapsed {
|
.heading-children.collapsed {
|
||||||
|
overflow: hidden; // Needed to prevent unnecessary sidenav scrollbar.
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
max-height: 1px; // Must have measurement to transition height.
|
max-height: 1px; // Must have measurement to transition height.
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
"@types/angular-route": "^1.3.5",
|
"@types/angular-route": "^1.3.5",
|
||||||
"@types/express": "^4.0.35",
|
"@types/express": "^4.0.35",
|
||||||
"@types/jasmine": "~2.8.0",
|
"@types/jasmine": "~2.8.0",
|
||||||
"@types/jasminewd2": "^2.0.3",
|
"@types/jasminewd2": "^2.0.4",
|
||||||
"@types/jquery": "^3.3.4",
|
"@types/jquery": "^3.3.4",
|
||||||
"@types/node": "^6.0.45",
|
"@types/node": "^6.0.45",
|
||||||
"canonical-path": "0.0.2",
|
"canonical-path": "0.0.2",
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2,11 +2,14 @@
|
|||||||
|
|
||||||
const chalk = require('chalk');
|
const chalk = require('chalk');
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
|
const lockfile = require('@yarnpkg/lockfile');
|
||||||
const path = require('canonical-path');
|
const path = require('canonical-path');
|
||||||
|
const semver = require('semver');
|
||||||
const shelljs = require('shelljs');
|
const shelljs = require('shelljs');
|
||||||
const yargs = require('yargs');
|
const yargs = require('yargs');
|
||||||
|
|
||||||
const PACKAGE_JSON = 'package.json';
|
const PACKAGE_JSON = 'package.json';
|
||||||
|
const YARN_LOCK = 'yarn.lock';
|
||||||
const LOCAL_MARKER_PATH = 'node_modules/_local_.json';
|
const LOCAL_MARKER_PATH = 'node_modules/_local_.json';
|
||||||
const PACKAGE_JSON_REGEX = /^[^/]+\/package\.json$/;
|
const PACKAGE_JSON_REGEX = /^[^/]+\/package\.json$/;
|
||||||
|
|
||||||
@ -62,8 +65,10 @@ class NgPackagesInstaller {
|
|||||||
* contents and acts as an indicator that dependencies have been overridden.
|
* contents and acts as an indicator that dependencies have been overridden.
|
||||||
*/
|
*/
|
||||||
installLocalDependencies() {
|
installLocalDependencies() {
|
||||||
if (this._checkLocalMarker() !== true || this.force) {
|
if (this.force || !this._checkLocalMarker()) {
|
||||||
const pathToPackageConfig = path.resolve(this.projectDir, PACKAGE_JSON);
|
const pathToPackageConfig = path.resolve(this.projectDir, PACKAGE_JSON);
|
||||||
|
const pathToLockfile = path.resolve(this.projectDir, YARN_LOCK);
|
||||||
|
const parsedLockfile = this._parseLockfile(pathToLockfile);
|
||||||
const packages = this._getDistPackages();
|
const packages = this._getDistPackages();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -88,17 +93,17 @@ class NgPackagesInstaller {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.writeFileSync(pkg.packageJsonPath, JSON.stringify(tmpConfig));
|
fs.writeFileSync(pkg.packageJsonPath, JSON.stringify(tmpConfig, null, 2));
|
||||||
});
|
});
|
||||||
|
|
||||||
const packageConfigFile = fs.readFileSync(pathToPackageConfig);
|
const packageConfigFile = fs.readFileSync(pathToPackageConfig, 'utf8');
|
||||||
const packageConfig = JSON.parse(packageConfigFile);
|
const packageConfig = JSON.parse(packageConfigFile);
|
||||||
|
|
||||||
const [dependencies, peers] = this._collectDependencies(packageConfig.dependencies || {}, packages);
|
const [dependencies, peers] = this._collectDependencies(packageConfig.dependencies || {}, packages);
|
||||||
const [devDependencies, devPeers] = this._collectDependencies(packageConfig.devDependencies || {}, packages);
|
const [devDependencies, devPeers] = this._collectDependencies(packageConfig.devDependencies || {}, packages);
|
||||||
|
|
||||||
this._assignPeerDependencies(peers, dependencies, devDependencies);
|
this._assignPeerDependencies(peers, dependencies, devDependencies, parsedLockfile);
|
||||||
this._assignPeerDependencies(devPeers, dependencies, devDependencies);
|
this._assignPeerDependencies(devPeers, dependencies, devDependencies, parsedLockfile);
|
||||||
|
|
||||||
const localPackageConfig = Object.assign(Object.create(null), packageConfig, { dependencies, devDependencies });
|
const localPackageConfig = Object.assign(Object.create(null), packageConfig, { dependencies, devDependencies });
|
||||||
localPackageConfig.__angular = { local: true };
|
localPackageConfig.__angular = { local: true };
|
||||||
@ -107,7 +112,7 @@ class NgPackagesInstaller {
|
|||||||
try {
|
try {
|
||||||
this._log(`Writing temporary local ${PACKAGE_JSON} to ${pathToPackageConfig}`);
|
this._log(`Writing temporary local ${PACKAGE_JSON} to ${pathToPackageConfig}`);
|
||||||
fs.writeFileSync(pathToPackageConfig, localPackageConfigJson);
|
fs.writeFileSync(pathToPackageConfig, localPackageConfigJson);
|
||||||
this._installDeps('--no-lockfile', '--check-files');
|
this._installDeps('--pure-lockfile', '--check-files');
|
||||||
this._setLocalMarker(localPackageConfigJson);
|
this._setLocalMarker(localPackageConfigJson);
|
||||||
} finally {
|
} finally {
|
||||||
this._log(`Restoring original ${PACKAGE_JSON} to ${pathToPackageConfig}`);
|
this._log(`Restoring original ${PACKAGE_JSON} to ${pathToPackageConfig}`);
|
||||||
@ -118,7 +123,7 @@ class NgPackagesInstaller {
|
|||||||
this._log(`Restoring original ${PACKAGE_JSON} for local Angular packages.`);
|
this._log(`Restoring original ${PACKAGE_JSON} for local Angular packages.`);
|
||||||
Object.keys(packages).forEach(key => {
|
Object.keys(packages).forEach(key => {
|
||||||
const pkg = packages[key];
|
const pkg = packages[key];
|
||||||
fs.writeFileSync(pkg.packageJsonPath, JSON.stringify(pkg.config));
|
fs.writeFileSync(pkg.packageJsonPath, JSON.stringify(pkg.config, null, 2));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,15 +139,23 @@ class NgPackagesInstaller {
|
|||||||
|
|
||||||
// Protected helpers
|
// Protected helpers
|
||||||
|
|
||||||
_assignPeerDependencies(peerDependencies, dependencies, devDependencies) {
|
_assignPeerDependencies(peerDependencies, dependencies, devDependencies, parsedLockfile) {
|
||||||
Object.keys(peerDependencies).forEach(key => {
|
Object.keys(peerDependencies).forEach(key => {
|
||||||
|
const peerDepRange = peerDependencies[key];
|
||||||
|
|
||||||
|
// Ignore peerDependencies whose range is already satisfied by current version in lockfile.
|
||||||
|
const originalRange = dependencies[key] || devDependencies[key];
|
||||||
|
const lockfileVersion = originalRange && parsedLockfile[`${key}@${originalRange}`].version;
|
||||||
|
|
||||||
|
if (lockfileVersion && semver.satisfies(lockfileVersion, peerDepRange)) return;
|
||||||
|
|
||||||
// If there is already an equivalent dependency then override it - otherwise assign/override the devDependency
|
// If there is already an equivalent dependency then override it - otherwise assign/override the devDependency
|
||||||
if (dependencies[key]) {
|
if (dependencies[key]) {
|
||||||
this._log(`Overriding dependency with peerDependency: ${key}: ${peerDependencies[key]}`);
|
this._log(`Overriding dependency with peerDependency: ${key}: ${peerDepRange}`);
|
||||||
dependencies[key] = peerDependencies[key];
|
dependencies[key] = peerDepRange;
|
||||||
} else {
|
} else {
|
||||||
this._log(`${devDependencies[key] ? 'Overriding' : 'Assigning'} devDependency with peerDependency: ${key}: ${peerDependencies[key]}`);
|
this._log(`${devDependencies[key] ? 'Overriding' : 'Assigning'} devDependency with peerDependency: ${key}: ${peerDepRange}`);
|
||||||
devDependencies[key] = peerDependencies[key];
|
devDependencies[key] = peerDepRange;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -166,11 +179,6 @@ class NgPackagesInstaller {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// FIXME: Temporarily use RxJS from root `node_modules/`.
|
|
||||||
if (peerDependencies.rxjs) {
|
|
||||||
peerDependencies.rxjs = `file:${ANGULAR_ROOT_DIR}/node_modules/rxjs`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [mergedDependencies, peerDependencies];
|
return [mergedDependencies, peerDependencies];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +234,20 @@ class NgPackagesInstaller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse and return a `yarn.lock` file.
|
||||||
|
*/
|
||||||
|
_parseLockfile(lockfilePath) {
|
||||||
|
const lockfileContent = fs.readFileSync(lockfilePath, 'utf8');
|
||||||
|
const parsed = lockfile.parse(lockfileContent);
|
||||||
|
|
||||||
|
if (parsed.type !== 'success') {
|
||||||
|
throw new Error(`[${NgPackagesInstaller.name}]: Error parsing lockfile '${lockfilePath}' (result type: ${parsed.type}).`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed.object;
|
||||||
|
}
|
||||||
|
|
||||||
_printWarning() {
|
_printWarning() {
|
||||||
const relativeScriptPath = path.relative('.', __filename.replace(/\.js$/, ''));
|
const relativeScriptPath = path.relative('.', __filename.replace(/\.js$/, ''));
|
||||||
const absoluteProjectDir = path.resolve(this.projectDir);
|
const absoluteProjectDir = path.resolve(this.projectDir);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
|
const lockfile = require('@yarnpkg/lockfile');
|
||||||
const path = require('canonical-path');
|
const path = require('canonical-path');
|
||||||
const shelljs = require('shelljs');
|
const shelljs = require('shelljs');
|
||||||
|
|
||||||
@ -11,6 +12,7 @@ describe('NgPackagesInstaller', () => {
|
|||||||
const absoluteRootDir = path.resolve(rootDir);
|
const absoluteRootDir = path.resolve(rootDir);
|
||||||
const nodeModulesDir = path.resolve(absoluteRootDir, 'node_modules');
|
const nodeModulesDir = path.resolve(absoluteRootDir, 'node_modules');
|
||||||
const packageJsonPath = path.resolve(absoluteRootDir, 'package.json');
|
const packageJsonPath = path.resolve(absoluteRootDir, 'package.json');
|
||||||
|
const yarnLockPath = path.resolve(absoluteRootDir, 'yarn.lock');
|
||||||
const packagesDir = path.resolve(path.resolve(__dirname, '../../../dist/packages-dist'));
|
const packagesDir = path.resolve(path.resolve(__dirname, '../../../dist/packages-dist'));
|
||||||
const toolsDir = path.resolve(path.resolve(__dirname, '../../../dist/tools/@angular'));
|
const toolsDir = path.resolve(path.resolve(__dirname, '../../../dist/tools/@angular'));
|
||||||
let installer;
|
let installer;
|
||||||
@ -52,13 +54,26 @@ describe('NgPackagesInstaller', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyOn(installer, '_checkLocalMarker');
|
spyOn(installer, '_checkLocalMarker');
|
||||||
|
spyOn(installer, '_installDeps');
|
||||||
|
spyOn(installer, '_setLocalMarker');
|
||||||
|
|
||||||
|
spyOn(installer, '_parseLockfile').and.returnValue({
|
||||||
|
'rxjs@^6.3.0': {version: '6.3.3'},
|
||||||
|
'zone.js@^0.8.26': {version: '0.8.27'}
|
||||||
|
});
|
||||||
|
|
||||||
// These are the packages that are "found" in the dist directory
|
// These are the packages that are "found" in the dist directory
|
||||||
dummyNgPackages = {
|
dummyNgPackages = {
|
||||||
'@angular/core': {
|
'@angular/core': {
|
||||||
parentDir: packagesDir,
|
parentDir: packagesDir,
|
||||||
packageJsonPath: `${packagesDir}/core/package.json`,
|
packageJsonPath: `${packagesDir}/core/package.json`,
|
||||||
config: { peerDependencies: { 'some-package': '5.0.1' } }
|
config: {
|
||||||
|
peerDependencies: {
|
||||||
|
'rxjs': '^6.4.0',
|
||||||
|
'some-package': '5.0.1',
|
||||||
|
'zone.js': '~0.8.26'
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'@angular/common': {
|
'@angular/common': {
|
||||||
parentDir: packagesDir,
|
parentDir: packagesDir,
|
||||||
@ -93,10 +108,12 @@ describe('NgPackagesInstaller', () => {
|
|||||||
dummyPackage = {
|
dummyPackage = {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'@angular/core': '4.4.1',
|
'@angular/core': '4.4.1',
|
||||||
'@angular/common': '4.4.1'
|
'@angular/common': '4.4.1',
|
||||||
|
rxjs: '^6.3.0'
|
||||||
},
|
},
|
||||||
devDependencies: {
|
devDependencies: {
|
||||||
'@angular/compiler-cli': '4.4.1'
|
'@angular/compiler-cli': '4.4.1',
|
||||||
|
'zone.js': '^0.8.26'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
dummyPackageJson = JSON.stringify(dummyPackage);
|
dummyPackageJson = JSON.stringify(dummyPackage);
|
||||||
@ -104,14 +121,23 @@ describe('NgPackagesInstaller', () => {
|
|||||||
|
|
||||||
// This is the package.json that is temporarily written to the "test" folder
|
// This is the package.json that is temporarily written to the "test" folder
|
||||||
// Note that the Angular (dev)dependencies have been modified to use a "file:" path
|
// Note that the Angular (dev)dependencies have been modified to use a "file:" path
|
||||||
// And that the peerDependencies from `dummyNgPackages` have been added as (dev)dependencies.
|
// And that the peerDependencies from `dummyNgPackages` have been updated or added as
|
||||||
|
// (dev)dependencies (unless the current version in lockfile satisfies semver).
|
||||||
|
//
|
||||||
|
// For example, `zone.js@0.8.27` (from lockfile) satisfies `zone.js@~0.8.26` (from
|
||||||
|
// `@angular/core`), thus `zone.js: ^0.8.26` (from original `package.json`) is retained.
|
||||||
|
// In contrast, `rxjs@6.3.3` (from lockfile) does not satisfy `rxjs@^6.4.0 (from
|
||||||
|
// `@angular/core`), thus `rxjs: ^6.3.0` (from original `package.json`) is replaced with
|
||||||
|
// `rxjs: ^6.4.0` (from `@angular/core`).
|
||||||
expectedModifiedPackage = {
|
expectedModifiedPackage = {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'@angular/core': `file:${packagesDir}/core`,
|
'@angular/core': `file:${packagesDir}/core`,
|
||||||
'@angular/common': `file:${packagesDir}/common`
|
'@angular/common': `file:${packagesDir}/common`,
|
||||||
|
'rxjs': '^6.4.0'
|
||||||
},
|
},
|
||||||
devDependencies: {
|
devDependencies: {
|
||||||
'@angular/compiler-cli': `file:${toolsDir}/compiler-cli`,
|
'@angular/compiler-cli': `file:${toolsDir}/compiler-cli`,
|
||||||
|
'zone.js': '^0.8.26',
|
||||||
'some-package': '5.0.1',
|
'some-package': '5.0.1',
|
||||||
typescript: '^2.4.2'
|
typescript: '^2.4.2'
|
||||||
},
|
},
|
||||||
@ -121,12 +147,20 @@ describe('NgPackagesInstaller', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('when there is a local package marker', () => {
|
describe('when there is a local package marker', () => {
|
||||||
|
beforeEach(() => installer._checkLocalMarker.and.returnValue(true));
|
||||||
|
|
||||||
it('should not continue processing', () => {
|
it('should not continue processing', () => {
|
||||||
installer._checkLocalMarker.and.returnValue(true);
|
|
||||||
installer.installLocalDependencies();
|
installer.installLocalDependencies();
|
||||||
expect(installer._checkLocalMarker).toHaveBeenCalled();
|
expect(installer._checkLocalMarker).toHaveBeenCalled();
|
||||||
expect(installer._getDistPackages).not.toHaveBeenCalled();
|
expect(installer._getDistPackages).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should continue processing (without checking for local marker) if `force` is true', () => {
|
||||||
|
installer.force = true;
|
||||||
|
installer.installLocalDependencies();
|
||||||
|
expect(installer._checkLocalMarker).not.toHaveBeenCalled();
|
||||||
|
expect(installer._getDistPackages).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when there is no local package marker', () => {
|
describe('when there is no local package marker', () => {
|
||||||
@ -135,14 +169,14 @@ describe('NgPackagesInstaller', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
log = [];
|
log = [];
|
||||||
fs.writeFileSync.and.callFake((filePath, contents) => filePath === packageJsonPath && log.push(`writeFile: ${contents}`));
|
fs.writeFileSync.and.callFake((filePath, contents) => filePath === packageJsonPath && log.push(`writeFile: ${contents}`));
|
||||||
spyOn(installer, '_installDeps').and.callFake(() => log.push('installDeps:'));
|
installer._installDeps.and.callFake((...args) => log.push(`installDeps: ${args.join(' ')}`));
|
||||||
spyOn(installer, '_setLocalMarker');
|
|
||||||
installer._checkLocalMarker.and.returnValue(false);
|
installer._checkLocalMarker.and.returnValue(false);
|
||||||
installer.installLocalDependencies();
|
installer.installLocalDependencies();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get the dist packages', () => {
|
it('should parse the lockfile and get the dist packages', () => {
|
||||||
expect(installer._checkLocalMarker).toHaveBeenCalled();
|
expect(installer._checkLocalMarker).toHaveBeenCalled();
|
||||||
|
expect(installer._parseLockfile).toHaveBeenCalledWith(yarnLockPath);
|
||||||
expect(installer._getDistPackages).toHaveBeenCalled();
|
expect(installer._getDistPackages).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -150,31 +184,32 @@ describe('NgPackagesInstaller', () => {
|
|||||||
const pkgJsonFor = pkgName => dummyNgPackages[`@angular/${pkgName}`].packageJsonPath;
|
const pkgJsonFor = pkgName => dummyNgPackages[`@angular/${pkgName}`].packageJsonPath;
|
||||||
const pkgConfigFor = pkgName => copyJsonObj(dummyNgPackages[`@angular/${pkgName}`].config);
|
const pkgConfigFor = pkgName => copyJsonObj(dummyNgPackages[`@angular/${pkgName}`].config);
|
||||||
const overwriteConfigFor = (pkgName, newProps) => Object.assign(pkgConfigFor(pkgName), newProps);
|
const overwriteConfigFor = (pkgName, newProps) => Object.assign(pkgConfigFor(pkgName), newProps);
|
||||||
|
const stringifyConfig = config => JSON.stringify(config, null, 2);
|
||||||
|
|
||||||
const allArgs = fs.writeFileSync.calls.allArgs();
|
const allArgs = fs.writeFileSync.calls.allArgs();
|
||||||
const firstFiveArgs = allArgs.slice(0, 5);
|
const firstFiveArgs = allArgs.slice(0, 5);
|
||||||
const lastFiveArgs = allArgs.slice(-5);
|
const lastFiveArgs = allArgs.slice(-5);
|
||||||
|
|
||||||
expect(firstFiveArgs).toEqual([
|
expect(firstFiveArgs).toEqual([
|
||||||
[pkgJsonFor('core'), JSON.stringify(overwriteConfigFor('core', {private: true}))],
|
[pkgJsonFor('core'), stringifyConfig(overwriteConfigFor('core', {private: true}))],
|
||||||
[pkgJsonFor('common'), JSON.stringify(overwriteConfigFor('common', {private: true}))],
|
[pkgJsonFor('common'), stringifyConfig(overwriteConfigFor('common', {private: true}))],
|
||||||
[pkgJsonFor('compiler'), JSON.stringify(overwriteConfigFor('compiler', {private: true}))],
|
[pkgJsonFor('compiler'), stringifyConfig(overwriteConfigFor('compiler', {private: true}))],
|
||||||
[pkgJsonFor('compiler-cli'), JSON.stringify(overwriteConfigFor('compiler-cli', {
|
[pkgJsonFor('compiler-cli'), stringifyConfig(overwriteConfigFor('compiler-cli', {
|
||||||
private: true,
|
private: true,
|
||||||
dependencies: { '@angular/tsc-wrapped': `file:${toolsDir}/tsc-wrapped` }
|
dependencies: { '@angular/tsc-wrapped': `file:${toolsDir}/tsc-wrapped` }
|
||||||
}))],
|
}))],
|
||||||
[pkgJsonFor('tsc-wrapped'), JSON.stringify(overwriteConfigFor('tsc-wrapped', {
|
[pkgJsonFor('tsc-wrapped'), stringifyConfig(overwriteConfigFor('tsc-wrapped', {
|
||||||
private: true,
|
private: true,
|
||||||
devDependencies: { '@angular/common': `file:${packagesDir}/common` }
|
devDependencies: { '@angular/common': `file:${packagesDir}/common` }
|
||||||
}))],
|
}))],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(lastFiveArgs).toEqual(['core', 'common', 'compiler', 'compiler-cli', 'tsc-wrapped']
|
expect(lastFiveArgs).toEqual(['core', 'common', 'compiler', 'compiler-cli', 'tsc-wrapped']
|
||||||
.map(pkgName => [pkgJsonFor(pkgName), JSON.stringify(pkgConfigFor(pkgName))]));
|
.map(pkgName => [pkgJsonFor(pkgName), stringifyConfig(pkgConfigFor(pkgName))]));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load the package.json', () => {
|
it('should load the package.json', () => {
|
||||||
expect(fs.readFileSync).toHaveBeenCalledWith(packageJsonPath);
|
expect(fs.readFileSync).toHaveBeenCalledWith(packageJsonPath, 'utf8');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should overwrite package.json with modified config', () => {
|
it('should overwrite package.json with modified config', () => {
|
||||||
@ -188,7 +223,7 @@ describe('NgPackagesInstaller', () => {
|
|||||||
it('should overwrite package.json, then install deps, then restore original package.json', () => {
|
it('should overwrite package.json, then install deps, then restore original package.json', () => {
|
||||||
expect(log).toEqual([
|
expect(log).toEqual([
|
||||||
`writeFile: ${expectedModifiedPackageJson}`,
|
`writeFile: ${expectedModifiedPackageJson}`,
|
||||||
`installDeps:`,
|
`installDeps: --pure-lockfile --check-files`,
|
||||||
`writeFile: ${dummyPackageJson}`
|
`writeFile: ${dummyPackageJson}`
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
@ -264,6 +299,42 @@ describe('NgPackagesInstaller', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('_parseLockfile()', () => {
|
||||||
|
let originalLockfileParseDescriptor;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// Workaround for `lockfile.parse()` being non-writable.
|
||||||
|
let parse = lockfile.parse;
|
||||||
|
originalLockfileParseDescriptor = Object.getOwnPropertyDescriptor(lockfile, 'parse');
|
||||||
|
Object.defineProperty(lockfile, 'parse', {
|
||||||
|
get() { return parse; },
|
||||||
|
set(newParse) { parse = newParse; },
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.readFileSync.and.returnValue('mock content');
|
||||||
|
spyOn(lockfile, 'parse').and.returnValue({type: 'success', object: {foo: {version: 'bar'}}});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => Object.defineProperty(lockfile, 'parse', originalLockfileParseDescriptor));
|
||||||
|
|
||||||
|
it('should parse the specified lockfile', () => {
|
||||||
|
installer._parseLockfile('/foo/bar/yarn.lock');
|
||||||
|
expect(fs.readFileSync).toHaveBeenCalledWith('/foo/bar/yarn.lock', 'utf8');
|
||||||
|
expect(lockfile.parse).toHaveBeenCalledWith('mock content');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw if parsing the lockfile fails', () => {
|
||||||
|
lockfile.parse.and.returnValue({type: 'not success'});
|
||||||
|
expect(() => installer._parseLockfile('/foo/bar/yarn.lock')).toThrowError(
|
||||||
|
'[NgPackagesInstaller]: Error parsing lockfile \'/foo/bar/yarn.lock\' (result type: not success).');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the parsed lockfile content as an object', () => {
|
||||||
|
const parsed = installer._parseLockfile('/foo/bar/yarn.lock');
|
||||||
|
expect(parsed).toEqual({foo: {version: 'bar'}});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('_printWarning()', () => {
|
describe('_printWarning()', () => {
|
||||||
it('should mention the message passed in the warning', () => {
|
it('should mention the message passed in the warning', () => {
|
||||||
installer._printWarning();
|
installer._printWarning();
|
||||||
|
@ -208,7 +208,7 @@
|
|||||||
{% set nonInternalMembers = ancestor.doc[collectionName] | filterByPropertyValue('internal', undefined) %}
|
{% set nonInternalMembers = ancestor.doc[collectionName] | filterByPropertyValue('internal', undefined) %}
|
||||||
{% if nonInternalMembers.length -%}
|
{% if nonInternalMembers.length -%}
|
||||||
<section class="inherited-members-list">
|
<section class="inherited-members-list">
|
||||||
<h3>Inherited from <code>{$ ancestor.doc.id $}</code></h3>
|
<h3>Inherited from <code><a class="code-anchor" href="{$ ancestor.doc.path $}">{$ ancestor.doc.name $}</a></code></h3>
|
||||||
<ul>
|
<ul>
|
||||||
{% for member in nonInternalMembers %}
|
{% for member in nonInternalMembers %}
|
||||||
<li>
|
<li>
|
||||||
|
3999
aio/yarn.lock
3999
aio/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -32,7 +32,7 @@
|
|||||||
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
||||||
"@angular/language-service": "file:../../dist/packages-dist/language-service",
|
"@angular/language-service": "file:../../dist/packages-dist/language-service",
|
||||||
"@types/jasmine": "~2.8.3",
|
"@types/jasmine": "~2.8.3",
|
||||||
"@types/jasminewd2": "~2.0.2",
|
"@types/jasminewd2": "~2.0.4",
|
||||||
"@types/node": "~6.0.60",
|
"@types/node": "~6.0.60",
|
||||||
"codelyzer": "^4.3.0",
|
"codelyzer": "^4.3.0",
|
||||||
"jasmine-core": "~2.8.0",
|
"jasmine-core": "~2.8.0",
|
||||||
|
@ -206,9 +206,9 @@
|
|||||||
version "2.8.6"
|
version "2.8.6"
|
||||||
resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.6.tgz#14445b6a1613cf4e05dd61c3c3256d0e95c0421e"
|
resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.6.tgz#14445b6a1613cf4e05dd61c3c3256d0e95c0421e"
|
||||||
|
|
||||||
"@types/jasminewd2@~2.0.2":
|
"@types/jasminewd2@~2.0.4":
|
||||||
version "2.0.3"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.3.tgz#0d2886b0cbdae4c0eeba55e30792f584bf040a95"
|
resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.4.tgz#12422ee719f372d30c3cc7d99cc72dadba6ace01"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/jasmine" "*"
|
"@types/jasmine" "*"
|
||||||
|
|
||||||
|
1
modules/types.d.ts
vendored
1
modules/types.d.ts
vendored
@ -13,6 +13,5 @@
|
|||||||
/// <reference types="jasminewd2" />
|
/// <reference types="jasminewd2" />
|
||||||
/// <reference types="node" />
|
/// <reference types="node" />
|
||||||
/// <reference types="zone.js" />
|
/// <reference types="zone.js" />
|
||||||
/// <reference path="../tools/types-ext/jasminewd2.d.ts" />
|
|
||||||
/// <reference path="./es6-subset.d.ts" />
|
/// <reference path="./es6-subset.d.ts" />
|
||||||
/// <reference path="./system.d.ts" />
|
/// <reference path="./system.d.ts" />
|
||||||
|
@ -43,12 +43,12 @@
|
|||||||
"@types/angular": "^1.6.47",
|
"@types/angular": "^1.6.47",
|
||||||
"@types/base64-js": "1.2.5",
|
"@types/base64-js": "1.2.5",
|
||||||
"@types/chai": "^4.1.2",
|
"@types/chai": "^4.1.2",
|
||||||
"@types/chokidar": "1.7.3",
|
"@types/chokidar": "^1.7.5",
|
||||||
"@types/diff": "^3.2.2",
|
"@types/diff": "^3.2.2",
|
||||||
"@types/fs-extra": "4.0.2",
|
"@types/fs-extra": "4.0.2",
|
||||||
"@types/hammerjs": "2.0.35",
|
"@types/hammerjs": "2.0.35",
|
||||||
"@types/jasmine": "^2.8.8",
|
"@types/jasmine": "^2.8.8",
|
||||||
"@types/jasminewd2": "^2.0.3",
|
"@types/jasminewd2": "^2.0.4",
|
||||||
"@types/minimist": "^1.2.0",
|
"@types/minimist": "^1.2.0",
|
||||||
"@types/node": "6.0.88",
|
"@types/node": "6.0.88",
|
||||||
"@types/selenium-webdriver": "3.0.7",
|
"@types/selenium-webdriver": "3.0.7",
|
||||||
@ -66,7 +66,7 @@
|
|||||||
"bower": "1.8.2",
|
"bower": "1.8.2",
|
||||||
"browserstacktunnel-wrapper": "2.0.1",
|
"browserstacktunnel-wrapper": "2.0.1",
|
||||||
"canonical-path": "0.0.2",
|
"canonical-path": "0.0.2",
|
||||||
"chokidar": "1.7.0",
|
"chokidar": "^2.1.1",
|
||||||
"clang-format": "1.0.41",
|
"clang-format": "1.0.41",
|
||||||
"cldr": "4.10.0",
|
"cldr": "4.10.0",
|
||||||
"cldr-data-downloader": "0.3.2",
|
"cldr-data-downloader": "0.3.2",
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
"reflect-metadata": "^0.1.2",
|
"reflect-metadata": "^0.1.2",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
"tsickle": "^0.32.1",
|
"tsickle": "^0.32.1",
|
||||||
"chokidar": "^1.4.2"
|
"chokidar": "^2.1.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": ">=2.7.2 <2.10",
|
"typescript": ">=2.7.2 <2.10",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
"include": [
|
"include": [
|
||||||
"../../node_modules/@types/jasminewd2/index.d.ts",
|
"../../node_modules/@types/jasminewd2/index.d.ts",
|
||||||
"../../tools/types-ext/jasminewd2.d.ts",
|
|
||||||
"../types.d.ts",
|
"../types.d.ts",
|
||||||
"**/*.ts"
|
"**/*.ts"
|
||||||
]
|
]
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
"include": [
|
"include": [
|
||||||
"../../node_modules/@types/jasminewd2/index.d.ts",
|
"../../node_modules/@types/jasminewd2/index.d.ts",
|
||||||
"../../tools/types-ext/jasminewd2.d.ts",
|
|
||||||
"../types.d.ts",
|
"../types.d.ts",
|
||||||
"**/e2e_test/*"
|
"**/e2e_test/*"
|
||||||
],
|
],
|
||||||
|
@ -214,24 +214,29 @@ export interface INgModelController {
|
|||||||
$name: string;
|
$name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function noNg() {
|
function noNg(): never {
|
||||||
throw new Error('AngularJS v1.x is not loaded!');
|
throw new Error('AngularJS v1.x is not loaded!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const noNgElement: typeof angular.element = (() => noNg()) as any;
|
||||||
|
noNgElement.cleanData = noNg;
|
||||||
|
|
||||||
let angular: {
|
let angular: {
|
||||||
bootstrap: (e: Element, modules: (string | IInjectable)[], config?: IAngularBootstrapConfig) =>
|
bootstrap: (e: Element, modules: (string | IInjectable)[], config?: IAngularBootstrapConfig) =>
|
||||||
IInjectorService,
|
IInjectorService,
|
||||||
module: (prefix: string, dependencies?: string[]) => IModule,
|
module: (prefix: string, dependencies?: string[]) => IModule,
|
||||||
element: (e: string | Element | Document | IAugmentedJQuery) => IAugmentedJQuery,
|
element: {
|
||||||
|
(e: string | Element | Document | IAugmentedJQuery): IAugmentedJQuery;
|
||||||
|
cleanData: (nodes: Node[] | NodeList) => void;
|
||||||
|
},
|
||||||
version: {major: number},
|
version: {major: number},
|
||||||
resumeBootstrap: () => void,
|
resumeBootstrap: () => void,
|
||||||
getTestability: (e: Element) => ITestabilityService
|
getTestability: (e: Element) => ITestabilityService
|
||||||
} = <any>{
|
} = {
|
||||||
bootstrap: noNg,
|
bootstrap: noNg,
|
||||||
module: noNg,
|
module: noNg,
|
||||||
element: noNg,
|
element: noNgElement,
|
||||||
version: undefined,
|
version: undefined as any,
|
||||||
resumeBootstrap: noNg,
|
resumeBootstrap: noNg,
|
||||||
getTestability: noNg
|
getTestability: noNg
|
||||||
};
|
};
|
||||||
@ -281,7 +286,8 @@ export const bootstrap: typeof angular.bootstrap = (e, modules, config?) =>
|
|||||||
export const module: typeof angular.module = (prefix, dependencies?) =>
|
export const module: typeof angular.module = (prefix, dependencies?) =>
|
||||||
angular.module(prefix, dependencies);
|
angular.module(prefix, dependencies);
|
||||||
|
|
||||||
export const element: typeof angular.element = e => angular.element(e);
|
export const element: typeof angular.element = (e => angular.element(e)) as typeof angular.element;
|
||||||
|
element.cleanData = nodes => angular.element.cleanData(nodes);
|
||||||
|
|
||||||
export const resumeBootstrap: typeof angular.resumeBootstrap = () => angular.resumeBootstrap();
|
export const resumeBootstrap: typeof angular.resumeBootstrap = () => angular.resumeBootstrap();
|
||||||
|
|
||||||
|
@ -124,7 +124,15 @@ export class UpgradeHelper {
|
|||||||
controllerInstance.$onDestroy();
|
controllerInstance.$onDestroy();
|
||||||
}
|
}
|
||||||
$scope.$destroy();
|
$scope.$destroy();
|
||||||
this.$element.triggerHandler !('$destroy');
|
|
||||||
|
// Clean the jQuery/jqLite data on the component+child elements.
|
||||||
|
// Equivelent to how jQuery/jqLite invoke `cleanData` on an Element (this.element)
|
||||||
|
// https://github.com/jquery/jquery/blob/e743cbd28553267f955f71ea7248377915613fd9/src/manipulation.js#L223
|
||||||
|
// https://github.com/angular/angular.js/blob/26ddc5f830f902a3d22f4b2aab70d86d4d688c82/src/jqLite.js#L306-L312
|
||||||
|
// `cleanData` will invoke the AngularJS `$destroy` DOM event
|
||||||
|
// https://github.com/angular/angular.js/blob/26ddc5f830f902a3d22f4b2aab70d86d4d688c82/src/Angular.js#L1911-L1924
|
||||||
|
angular.element.cleanData([this.element]);
|
||||||
|
angular.element.cleanData(this.element.querySelectorAll('*'));
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareTransclusion(): angular.ILinkFn|undefined {
|
prepareTransclusion(): angular.ILinkFn|undefined {
|
||||||
|
@ -12,6 +12,7 @@ import {BrowserModule} from '@angular/platform-browser';
|
|||||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||||
import * as angular from '@angular/upgrade/src/common/angular1';
|
import * as angular from '@angular/upgrade/src/common/angular1';
|
||||||
import {UpgradeAdapter, UpgradeAdapterRef} from '@angular/upgrade/src/dynamic/upgrade_adapter';
|
import {UpgradeAdapter, UpgradeAdapterRef} from '@angular/upgrade/src/dynamic/upgrade_adapter';
|
||||||
|
|
||||||
import {$apply, $digest, html, multiTrim, withEachNg1Version} from './test_helpers';
|
import {$apply, $digest, html, multiTrim, withEachNg1Version} from './test_helpers';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@ -2177,9 +2178,10 @@ withEachNg1Version(() => {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should emit `$destroy` on `$element`', fakeAsync(() => {
|
it('should emit `$destroy` on `$element` and descendants', fakeAsync(() => {
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
const elementDestroyListener = jasmine.createSpy('elementDestroyListener');
|
const elementDestroyListener = jasmine.createSpy('elementDestroyListener');
|
||||||
|
const descendantDestroyListener = jasmine.createSpy('descendantDestroyListener');
|
||||||
let ng2ComponentInstance: Ng2Component;
|
let ng2ComponentInstance: Ng2Component;
|
||||||
|
|
||||||
@Component({selector: 'ng2', template: '<div *ngIf="!ng2Destroy"><ng1></ng1></div>'})
|
@Component({selector: 'ng2', template: '<div *ngIf="!ng2Destroy"><ng1></ng1></div>'})
|
||||||
@ -2194,9 +2196,13 @@ withEachNg1Version(() => {
|
|||||||
// Mocking animations (via `ngAnimateMock`) avoids the issue.
|
// Mocking animations (via `ngAnimateMock`) avoids the issue.
|
||||||
angular.module('ng1', ['ngAnimateMock'])
|
angular.module('ng1', ['ngAnimateMock'])
|
||||||
.component('ng1', {
|
.component('ng1', {
|
||||||
controller: function($element: angular.IAugmentedJQuery) {
|
controller: class {
|
||||||
$element.on !('$destroy', elementDestroyListener);
|
constructor(private $element: angular.IAugmentedJQuery) {} $onInit() {
|
||||||
|
this.$element.on !('$destroy', elementDestroyListener);
|
||||||
|
this.$element.contents !().on !('$destroy', descendantDestroyListener);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
template: '<div></div>'
|
||||||
})
|
})
|
||||||
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
|
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
|
||||||
|
|
||||||
@ -2210,14 +2216,150 @@ withEachNg1Version(() => {
|
|||||||
const element = html('<ng2></ng2>');
|
const element = html('<ng2></ng2>');
|
||||||
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
const $rootScope = ref.ng1RootScope as any;
|
const $rootScope = ref.ng1RootScope as any;
|
||||||
|
tick();
|
||||||
|
$rootScope.$digest();
|
||||||
|
|
||||||
expect(elementDestroyListener).not.toHaveBeenCalled();
|
expect(elementDestroyListener).not.toHaveBeenCalled();
|
||||||
|
expect(descendantDestroyListener).not.toHaveBeenCalled();
|
||||||
|
|
||||||
ng2ComponentInstance.ng2Destroy = true;
|
ng2ComponentInstance.ng2Destroy = true;
|
||||||
tick();
|
tick();
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
|
|
||||||
expect(elementDestroyListener).toHaveBeenCalledTimes(1);
|
expect(elementDestroyListener).toHaveBeenCalledTimes(1);
|
||||||
|
expect(descendantDestroyListener).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should clear data on `$element` and descendants', fakeAsync(() => {
|
||||||
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
|
let ng1ComponentElement: angular.IAugmentedJQuery;
|
||||||
|
let ng2ComponentAInstance: Ng2ComponentA;
|
||||||
|
|
||||||
|
// Define `ng1Component`
|
||||||
|
const ng1Component: angular.IComponent = {
|
||||||
|
controller: class {
|
||||||
|
constructor(private $element: angular.IAugmentedJQuery) {} $onInit() {
|
||||||
|
this.$element.data !('test', 1);
|
||||||
|
this.$element.contents !().data !('test', 2);
|
||||||
|
|
||||||
|
ng1ComponentElement = this.$element;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: '<div></div>'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define `Ng2Component`
|
||||||
|
@Component({selector: 'ng2A', template: '<ng2B *ngIf="!destroyIt"></ng2B>'})
|
||||||
|
class Ng2ComponentA {
|
||||||
|
destroyIt = false;
|
||||||
|
|
||||||
|
constructor() { ng2ComponentAInstance = this; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'ng2B', template: '<ng1></ng1>'})
|
||||||
|
class Ng2ComponentB {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define `ng1Module`
|
||||||
|
angular.module('ng1Module', [])
|
||||||
|
.component('ng1', ng1Component)
|
||||||
|
.directive('ng2A', adapter.downgradeNg2Component(Ng2ComponentA));
|
||||||
|
|
||||||
|
// Define `Ng2Module`
|
||||||
|
@NgModule({
|
||||||
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2ComponentA, Ng2ComponentB],
|
||||||
|
entryComponents: [Ng2ComponentA],
|
||||||
|
imports: [BrowserModule]
|
||||||
|
})
|
||||||
|
class Ng2Module {
|
||||||
|
ngDoBootstrap() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bootstrap
|
||||||
|
const element = html(`<ng2-a></ng2-a>`);
|
||||||
|
|
||||||
|
adapter.bootstrap(element, ['ng1Module']).ready((ref) => {
|
||||||
|
const $rootScope = ref.ng1RootScope as any;
|
||||||
|
tick();
|
||||||
|
$rootScope.$digest();
|
||||||
|
expect(ng1ComponentElement.data !('test')).toBe(1);
|
||||||
|
expect(ng1ComponentElement.contents !().data !('test')).toBe(2);
|
||||||
|
|
||||||
|
ng2ComponentAInstance.destroyIt = true;
|
||||||
|
tick();
|
||||||
|
$rootScope.$digest();
|
||||||
|
|
||||||
|
expect(ng1ComponentElement.data !('test')).toBeUndefined();
|
||||||
|
expect(ng1ComponentElement.contents !().data !('test')).toBeUndefined();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should clear dom listeners on `$element` and descendants`', fakeAsync(() => {
|
||||||
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
|
const elementClickListener = jasmine.createSpy('elementClickListener');
|
||||||
|
const descendantClickListener = jasmine.createSpy('descendantClickListener');
|
||||||
|
let ng1DescendantElement: angular.IAugmentedJQuery;
|
||||||
|
let ng2ComponentAInstance: Ng2ComponentA;
|
||||||
|
|
||||||
|
// Define `ng1Component`
|
||||||
|
const ng1Component: angular.IComponent = {
|
||||||
|
controller: class {
|
||||||
|
constructor(private $element: angular.IAugmentedJQuery) {} $onInit() {
|
||||||
|
ng1DescendantElement = this.$element.contents !();
|
||||||
|
|
||||||
|
this.$element.on !('click', elementClickListener);
|
||||||
|
ng1DescendantElement.on !('click', descendantClickListener);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: '<div></div>'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define `Ng2Component`
|
||||||
|
@Component({selector: 'ng2A', template: '<ng2B *ngIf="!destroyIt"></ng2B>'})
|
||||||
|
class Ng2ComponentA {
|
||||||
|
destroyIt = false;
|
||||||
|
|
||||||
|
constructor() { ng2ComponentAInstance = this; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'ng2B', template: '<ng1></ng1>'})
|
||||||
|
class Ng2ComponentB {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define `ng1Module`
|
||||||
|
angular.module('ng1Module', [])
|
||||||
|
.component('ng1', ng1Component)
|
||||||
|
.directive('ng2A', adapter.downgradeNg2Component(Ng2ComponentA));
|
||||||
|
|
||||||
|
// Define `Ng2Module`
|
||||||
|
@NgModule({
|
||||||
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2ComponentA, Ng2ComponentB],
|
||||||
|
entryComponents: [Ng2ComponentA],
|
||||||
|
imports: [BrowserModule]
|
||||||
|
})
|
||||||
|
class Ng2Module {
|
||||||
|
ngDoBootstrap() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bootstrap
|
||||||
|
const element = html(`<ng2-a></ng2-a>`);
|
||||||
|
|
||||||
|
adapter.bootstrap(element, ['ng1Module']).ready((ref) => {
|
||||||
|
const $rootScope = ref.ng1RootScope as any;
|
||||||
|
tick();
|
||||||
|
$rootScope.$digest();
|
||||||
|
(ng1DescendantElement[0] as HTMLElement).click();
|
||||||
|
expect(elementClickListener).toHaveBeenCalledTimes(1);
|
||||||
|
expect(descendantClickListener).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
ng2ComponentAInstance.destroyIt = true;
|
||||||
|
tick();
|
||||||
|
$rootScope.$digest();
|
||||||
|
|
||||||
|
(ng1DescendantElement[0] as HTMLElement).click();
|
||||||
|
expect(elementClickListener).toHaveBeenCalledTimes(1);
|
||||||
|
expect(descendantClickListener).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
@ -3633,8 +3633,9 @@ withEachNg1Version(() => {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should emit `$destroy` on `$element`', async(() => {
|
it('should emit `$destroy` on `$element` and descendants', async(() => {
|
||||||
const elementDestroyListener = jasmine.createSpy('elementDestroyListener');
|
const elementDestroyListener = jasmine.createSpy('elementDestroyListener');
|
||||||
|
const descendantDestroyListener = jasmine.createSpy('descendantDestroyListener');
|
||||||
let ng2ComponentAInstance: Ng2ComponentA;
|
let ng2ComponentAInstance: Ng2ComponentA;
|
||||||
|
|
||||||
// Define `ng1Component`
|
// Define `ng1Component`
|
||||||
@ -3642,8 +3643,10 @@ withEachNg1Version(() => {
|
|||||||
controller: class {
|
controller: class {
|
||||||
constructor($element: angular.IAugmentedJQuery) {
|
constructor($element: angular.IAugmentedJQuery) {
|
||||||
$element.on !('$destroy', elementDestroyListener);
|
$element.on !('$destroy', elementDestroyListener);
|
||||||
|
$element.contents !().on !('$destroy', descendantDestroyListener);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
template: '<div></div>'
|
||||||
};
|
};
|
||||||
|
|
||||||
// Define `Ng1ComponentFacade`
|
// Define `Ng1ComponentFacade`
|
||||||
@ -3686,11 +3689,151 @@ withEachNg1Version(() => {
|
|||||||
|
|
||||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => {
|
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => {
|
||||||
expect(elementDestroyListener).not.toHaveBeenCalled();
|
expect(elementDestroyListener).not.toHaveBeenCalled();
|
||||||
|
expect(descendantDestroyListener).not.toHaveBeenCalled();
|
||||||
|
|
||||||
ng2ComponentAInstance.destroyIt = true;
|
ng2ComponentAInstance.destroyIt = true;
|
||||||
$digest(adapter);
|
$digest(adapter);
|
||||||
|
|
||||||
expect(elementDestroyListener).toHaveBeenCalledTimes(1);
|
expect(elementDestroyListener).toHaveBeenCalledTimes(1);
|
||||||
|
expect(descendantDestroyListener).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should clear data on `$element` and descendants`', async(() => {
|
||||||
|
let ng1ComponentElement: angular.IAugmentedJQuery;
|
||||||
|
let ng2ComponentAInstance: Ng2ComponentA;
|
||||||
|
|
||||||
|
// Define `ng1Component`
|
||||||
|
const ng1Component: angular.IComponent = {
|
||||||
|
controller: class {
|
||||||
|
constructor($element: angular.IAugmentedJQuery) {
|
||||||
|
$element.data !('test', 1);
|
||||||
|
$element.contents !().data !('test', 2);
|
||||||
|
|
||||||
|
ng1ComponentElement = $element;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: '<div></div>'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define `Ng1ComponentFacade`
|
||||||
|
@Directive({selector: 'ng1'})
|
||||||
|
class Ng1ComponentFacade extends UpgradeComponent {
|
||||||
|
constructor(elementRef: ElementRef, injector: Injector) {
|
||||||
|
super('ng1', elementRef, injector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define `Ng2Component`
|
||||||
|
@Component({selector: 'ng2A', template: '<ng2B *ngIf="!destroyIt"></ng2B>'})
|
||||||
|
class Ng2ComponentA {
|
||||||
|
destroyIt = false;
|
||||||
|
|
||||||
|
constructor() { ng2ComponentAInstance = this; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'ng2B', template: '<ng1></ng1>'})
|
||||||
|
class Ng2ComponentB {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define `ng1Module`
|
||||||
|
const ng1Module = angular.module('ng1Module', [])
|
||||||
|
.component('ng1', ng1Component)
|
||||||
|
.directive('ng2A', downgradeComponent({component: Ng2ComponentA}));
|
||||||
|
|
||||||
|
// Define `Ng2Module`
|
||||||
|
@NgModule({
|
||||||
|
declarations: [Ng1ComponentFacade, Ng2ComponentA, Ng2ComponentB],
|
||||||
|
entryComponents: [Ng2ComponentA],
|
||||||
|
imports: [BrowserModule, UpgradeModule]
|
||||||
|
})
|
||||||
|
class Ng2Module {
|
||||||
|
ngDoBootstrap() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bootstrap
|
||||||
|
const element = html(`<ng2-a></ng2-a>`);
|
||||||
|
|
||||||
|
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => {
|
||||||
|
expect(ng1ComponentElement.data !('test')).toBe(1);
|
||||||
|
expect(ng1ComponentElement.contents !().data !('test')).toBe(2);
|
||||||
|
|
||||||
|
ng2ComponentAInstance.destroyIt = true;
|
||||||
|
$digest(adapter);
|
||||||
|
|
||||||
|
expect(ng1ComponentElement.data !('test')).toBeUndefined();
|
||||||
|
expect(ng1ComponentElement.contents !().data !('test')).toBeUndefined();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should clear dom listeners on `$element` and descendants`', async(() => {
|
||||||
|
const elementClickListener = jasmine.createSpy('elementClickListener');
|
||||||
|
const descendantClickListener = jasmine.createSpy('descendantClickListener');
|
||||||
|
let ng1DescendantElement: angular.IAugmentedJQuery;
|
||||||
|
let ng2ComponentAInstance: Ng2ComponentA;
|
||||||
|
|
||||||
|
// Define `ng1Component`
|
||||||
|
const ng1Component: angular.IComponent = {
|
||||||
|
controller: class {
|
||||||
|
constructor($element: angular.IAugmentedJQuery) {
|
||||||
|
ng1DescendantElement = $element.contents !();
|
||||||
|
|
||||||
|
$element.on !('click', elementClickListener);
|
||||||
|
ng1DescendantElement.on !('click', descendantClickListener);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: '<div></div>'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define `Ng1ComponentFacade`
|
||||||
|
@Directive({selector: 'ng1'})
|
||||||
|
class Ng1ComponentFacade extends UpgradeComponent {
|
||||||
|
constructor(elementRef: ElementRef, injector: Injector) {
|
||||||
|
super('ng1', elementRef, injector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define `Ng2Component`
|
||||||
|
@Component({selector: 'ng2A', template: '<ng2B *ngIf="!destroyIt"></ng2B>'})
|
||||||
|
class Ng2ComponentA {
|
||||||
|
destroyIt = false;
|
||||||
|
|
||||||
|
constructor() { ng2ComponentAInstance = this; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'ng2B', template: '<ng1></ng1>'})
|
||||||
|
class Ng2ComponentB {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define `ng1Module`
|
||||||
|
const ng1Module = angular.module('ng1Module', [])
|
||||||
|
.component('ng1', ng1Component)
|
||||||
|
.directive('ng2A', downgradeComponent({component: Ng2ComponentA}));
|
||||||
|
|
||||||
|
// Define `Ng2Module`
|
||||||
|
@NgModule({
|
||||||
|
declarations: [Ng1ComponentFacade, Ng2ComponentA, Ng2ComponentB],
|
||||||
|
entryComponents: [Ng2ComponentA],
|
||||||
|
imports: [BrowserModule, UpgradeModule]
|
||||||
|
})
|
||||||
|
class Ng2Module {
|
||||||
|
ngDoBootstrap() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bootstrap
|
||||||
|
const element = html(`<ng2-a></ng2-a>`);
|
||||||
|
|
||||||
|
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => {
|
||||||
|
(ng1DescendantElement[0] as HTMLElement).click();
|
||||||
|
expect(elementClickListener).toHaveBeenCalledTimes(1);
|
||||||
|
expect(descendantClickListener).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
ng2ComponentAInstance.destroyIt = true;
|
||||||
|
$digest(adapter);
|
||||||
|
|
||||||
|
(ng1DescendantElement[0] as HTMLElement).click();
|
||||||
|
expect(elementClickListener).toHaveBeenCalledTimes(1);
|
||||||
|
expect(descendantClickListener).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
30
tools/types-ext/jasminewd2.d.ts
vendored
30
tools/types-ext/jasminewd2.d.ts
vendored
@ -1,30 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// <reference types="jasminewd2" />
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extended typings for `jasminewd2`.
|
|
||||||
*
|
|
||||||
* The currently used `jasminewd2` version (v2.1.0), supports passing a `done` callback to a spec,
|
|
||||||
* but the latest typings on [DefinitelyTyped][1] do not reflect that.
|
|
||||||
* Overwrite the relevant function signatures to add a `done` callback.
|
|
||||||
*
|
|
||||||
* [1]:
|
|
||||||
* https://github.com/DefinitelyTyped/DefinitelyTyped/blob/566e0394859fdc1dc893658ccec6b06372d56a91/types/jasminewd2/index.d.ts#L9-L15
|
|
||||||
*/
|
|
||||||
declare function it(
|
|
||||||
expectation: string, assertion?: (done: DoneFn) => Promise<void>, timeout?: number): void;
|
|
||||||
declare function fit(
|
|
||||||
expectation: string, assertion?: (done: DoneFn) => Promise<void>, timeout?: number): void;
|
|
||||||
declare function xit(
|
|
||||||
expectation: string, assertion?: (done: DoneFn) => Promise<void>, timeout?: number): void;
|
|
||||||
declare function beforeEach(action: (done: DoneFn) => Promise<void>, timeout?: number): void;
|
|
||||||
declare function afterEach(action: (done: DoneFn) => Promise<void>, timeout?: number): void;
|
|
||||||
declare function beforeAll(action: (done: DoneFn) => Promise<void>, timeout?: number): void;
|
|
||||||
declare function afterAll(action: (done: DoneFn) => Promise<void>, timeout?: number): void;
|
|
Reference in New Issue
Block a user