Compare commits
113 Commits
11.0.0-nex
...
zone.js-0.
Author | SHA1 | Date | |
---|---|---|---|
a38293d213 | |||
4dc8d83d84 | |||
492e236ae6 | |||
34b74cecb6 | |||
81aa119739 | |||
49197d12a0 | |||
9ec2bad4dc | |||
e8d47c2d41 | |||
765fa337e3 | |||
6570292672 | |||
4610093c87 | |||
a3812c6cbd | |||
96f59f64a0 | |||
5bda62c51d | |||
f9f3c54c9a | |||
7669827436 | |||
178a0437b7 | |||
34dbba4a90 | |||
ef608bff83 | |||
06d0d8e31d | |||
60f761b4c2 | |||
93437bbc16 | |||
85be258845 | |||
56ab6d56e9 | |||
6e18d2dacc | |||
9bfb508b87 | |||
497af77d7a | |||
822b838fbc | |||
ac0016cd82 | |||
eb9eebbb45 | |||
aee2d3f994 | |||
8f1317f06f | |||
a83693ddd9 | |||
dd66aa290a | |||
0e5a945ed4 | |||
90e9574ac7 | |||
cdf642b609 | |||
a5d8d03edb | |||
5cfe81f919 | |||
0ec7043490 | |||
c4becca0e4 | |||
b0a8b69ae8 | |||
93ee05d92a | |||
783a5bd7bb | |||
c6350116b5 | |||
898be92f70 | |||
f6d5cdfbd7 | |||
5913e5c4e8 | |||
929e0df377 | |||
c53f19ac47 | |||
ffc3332dcd | |||
8fd25d9614 | |||
a051d97429 | |||
0001dbdede | |||
cbef410e3f | |||
db37c17e02 | |||
61e6ca9b1f | |||
78a33eeef9 | |||
584f37cfca | |||
7d4929918d | |||
b642f0bf45 | |||
520911efd4 | |||
0875fd2360 | |||
c4266fb729 | |||
5ce71e0fbc | |||
437e563507 | |||
b0b4953fd6 | |||
72f4497f11 | |||
96dd78e0c6 | |||
c9b36f9150 | |||
c76dda6aeb | |||
6947ceaf44 | |||
5471789664 | |||
952710b43b | |||
2736a43ecb | |||
f4fee86f77 | |||
47eab61cad | |||
0accd1e68d | |||
2c0282f4c2 | |||
6650d71fe2 | |||
65997c0649 | |||
1d6e67478e | |||
5038e5741b | |||
11485d96fb | |||
acfce0ba1b | |||
ed81588c79 | |||
87274e3eec | |||
a5a7845593 | |||
f35e9158b2 | |||
cee393d0da | |||
118f37b174 | |||
e930b0cd19 | |||
62945efab7 | |||
4cc5982e58 | |||
a84976fdfc | |||
bf717b1a31 | |||
9f3388e491 | |||
b2342d4116 | |||
7f689a291a | |||
ca4ef61c06 | |||
4a1c12c773 | |||
0e733f3689 | |||
0a16e60afa | |||
f84b3786dc | |||
4b06ef75aa | |||
42a164f522 | |||
049b453149 | |||
dace4aacb6 | |||
63624a2d46 | |||
4604fe9ed2 | |||
01ec0f0933 | |||
de66818cf6 | |||
4ede190571 |
4
.bazelrc
4
.bazelrc
@ -74,8 +74,8 @@ test --test_output=errors
|
||||
# Trick bazel into treating BUILD files under integration/bazel as being regular files
|
||||
# This lets us glob() up all the files inside this integration test to make them inputs to tests
|
||||
# (Note, we cannot use common --deleted_packages because the bazel version command doesn't support it)
|
||||
build --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/test/e2e
|
||||
query --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/test/e2e
|
||||
build --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/tools,integration/bazel/test/e2e
|
||||
query --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/tools,integration/bazel/test/e2e
|
||||
|
||||
################################
|
||||
# Temporary Settings for Ivy #
|
||||
|
@ -27,8 +27,6 @@ var_3: &cache_key v7-angular-node-12-{{ checksum ".bazelversion" }}-{{ checksum
|
||||
# folder will contain all previously used versions and ultimately cause the cache restoring to
|
||||
# be slower due to its growing size.
|
||||
var_4: &cache_key_fallback v7-angular-node-12-{{ checksum ".bazelversion" }}
|
||||
var_3_win: &cache_key_win v7-angular-win-node-12-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }}
|
||||
var_4_win: &cache_key_win_fallback v7-angular-win-node-12-{{ checksum ".bazelversion" }}
|
||||
|
||||
# Cache key for the `components-repo-unit-tests` job. **Note** when updating the SHA in the
|
||||
# cache keys also update the SHA for the "COMPONENTS_REPO_COMMIT" environment variable.
|
||||
@ -183,23 +181,12 @@ commands:
|
||||
setup_win:
|
||||
description: Setup windows node environment
|
||||
steps:
|
||||
# Use the Linux workspace directly, as it already has checkout, rebased and node modules.
|
||||
- custom_attach_workspace
|
||||
- checkout
|
||||
# Install Bazel pre-requisites that aren't in the preconfigured CircleCI Windows VM.
|
||||
- run: ./.circleci/windows-env.ps1
|
||||
- run: node --version
|
||||
- run: yarn --version
|
||||
- restore_cache:
|
||||
keys:
|
||||
- *cache_key_win
|
||||
- *cache_key_win_fallback
|
||||
# Reinstall to get windows binaries.
|
||||
- run: yarn install --frozen-lockfile --non-interactive
|
||||
# Install @bazel/bazelisk globally and use that for the first run.
|
||||
# Workaround for https://github.com/bazelbuild/rules_nodejs/issues/894
|
||||
# NB: the issue was for @bazel/bazel but the same problem applies to @bazel/bazelisk
|
||||
- run: yarn global add @bazel/bazelisk@$env:BAZELISK_VERSION
|
||||
- run: bazelisk info
|
||||
|
||||
notify_webhook_on_fail:
|
||||
description: Notify a webhook about failure
|
||||
@ -766,12 +753,6 @@ jobs:
|
||||
# Probably a powershell command parsing thing. There's no problem using a yarn script though.
|
||||
command: yarn circleci-win-ve
|
||||
no_output_timeout: 45m
|
||||
# Save bazel repository cache to use on subsequent runs.
|
||||
# We don't save node_modules because it's faster to use the linux workspace and reinstall.
|
||||
- save_cache:
|
||||
key: *cache_key_win
|
||||
paths:
|
||||
- "C:/Users/circleci/bazel_repository_cache"
|
||||
|
||||
test_ivy_aot_win:
|
||||
executor: windows-executor
|
||||
@ -863,26 +844,25 @@ workflows:
|
||||
- build-npm-packages
|
||||
- build-ivy-npm-packages
|
||||
- legacy-unit-tests-saucelabs
|
||||
- components-repo-unit-tests:
|
||||
requires:
|
||||
- build-npm-packages
|
||||
# Temporarily disabled components-repo-unit-tests to update rules_nodejs to 2.0.0. Breaking changes in
|
||||
# rules_nodejs create a dependency sandwich between angular/angular & angular/components that are very
|
||||
# difficult and time consuming to resolve and involve patching @angular/bazel in components repo such
|
||||
# as https://github.com/angular/components/commit/9e7ba251207df77164d73d66620e619bcbc4d2ad. It is simpler to
|
||||
# 1) land angular/angular upgrade to rule_nodejs 2.0.0 which has breaking changes
|
||||
# 2) land angular/components upgrade to rules_nodejs 2.0.0 using the @angular/bazel builds snapshot
|
||||
# 3) update angular/angular to the landed components commit and re-enable these tests
|
||||
# - components-repo-unit-tests:
|
||||
# requires:
|
||||
# - build-npm-packages
|
||||
- test_zonejs:
|
||||
requires:
|
||||
- setup
|
||||
# Windows Jobs
|
||||
# These are very slow so we run them on non-PRs only for now.
|
||||
# TODO: remove the filter when CircleCI makes Windows FS faster.
|
||||
# The Windows jobs are only run after their non-windows counterparts finish successfully.
|
||||
# This isn't strictly necessary as there is no artifact dependency, but helps economize
|
||||
# CI resources by not attempting to build when we know should fail.
|
||||
- test_win:
|
||||
<<: *skip_on_pull_requests
|
||||
requires:
|
||||
- test
|
||||
- setup
|
||||
- test_ivy_aot_win:
|
||||
<<: *skip_on_pull_requests
|
||||
requires:
|
||||
- test_ivy_aot
|
||||
- setup
|
||||
|
||||
monitoring:
|
||||
jobs:
|
||||
|
@ -2,8 +2,8 @@
|
||||
# https://docs.bazel.build/versions/master/install-windows.html
|
||||
# https://docs.bazel.build/versions/master/windows.html
|
||||
# Install MSYS2 and packages
|
||||
choco install msys2 --version 20180531.0.0 --no-progress --package-parameters "/NoUpdate"
|
||||
C:\tools\msys64\usr\bin\bash.exe -l -c "pacman --needed --noconfirm -S zip unzip patch diffutils git"
|
||||
choco install msys2 --version 20200903.0.0 --no-progress --package-parameters "/NoUpdate"
|
||||
C:\tools\msys64\usr\bin\bash.exe -l -c "pacman --needed --noconfirm -S zip unzip patch diffutils"
|
||||
|
||||
# Add PATH modifications to the Powershell profile. This is the win equivalent of .bash_profile.
|
||||
# https://docs.microsoft.com/en-us/previous-versions//bb613488(v=vs.85)
|
||||
|
@ -9,11 +9,11 @@ export const caretaker: CaretakerConfig = {
|
||||
},
|
||||
{
|
||||
name: 'Merge Assistance Queue',
|
||||
query: `is:pr is:open status:success label:"action: merge-assistance"`,
|
||||
query: `is:pr is:open label:"action: merge-assistance"`,
|
||||
},
|
||||
{
|
||||
name: 'Initial Triage Queue',
|
||||
query: `is:open is:issue no:milestone`,
|
||||
query: `is:open no:milestone`,
|
||||
}
|
||||
]
|
||||
};
|
||||
|
@ -26,7 +26,7 @@ export const release: ReleaseConfig = {
|
||||
],
|
||||
// TODO: Implement release package building here.
|
||||
buildPackages: async () => [],
|
||||
// TODO: This can be removed once there is a org-wide tool for changelog generation.
|
||||
// TODO: This can be removed once there is an org-wide tool for changelog generation.
|
||||
generateReleaseNotesForHead: async () => {
|
||||
exec('yarn -s gulp changelog', {cwd: join(__dirname, '../')});
|
||||
},
|
||||
|
@ -186,6 +186,7 @@ groups:
|
||||
- IgorMinar # Igor Minar
|
||||
- jbogarthyde # Judy Bogart
|
||||
- jelbourn # Jeremy Elbourn
|
||||
- jessicajaniuk # Jessica Janiuk
|
||||
- JiaLiPassion # Jia Li
|
||||
- JoostK # Joost Koehoorn
|
||||
- josephperrott # Joey Perrott
|
||||
@ -405,6 +406,7 @@ groups:
|
||||
'aio/content/guide/structural-directives.md',
|
||||
'aio/content/examples/structural-directives/**',
|
||||
'aio/content/guide/svg-in-templates.md',
|
||||
'aio/content/guide/style-precedence.md',
|
||||
'aio/content/images/guide/structural-directives/**',
|
||||
'aio/content/guide/template-statements.md',
|
||||
'aio/content/guide/user-input.md',
|
||||
@ -1120,6 +1122,7 @@ groups:
|
||||
'docs/SAVED_REPLIES.md',
|
||||
'docs/TOOLS.md',
|
||||
'docs/TRIAGE_AND_LABELS.md',
|
||||
'docs/images/**',
|
||||
'goldens/*',
|
||||
'modules/*',
|
||||
'packages/*',
|
||||
|
@ -47,3 +47,9 @@ filegroup(
|
||||
"@npm//:node_modules/angular-mocks-1.6/angular-mocks.js",
|
||||
],
|
||||
)
|
||||
|
||||
# Detect if the build is running under --stamp
|
||||
config_setting(
|
||||
name = "stamp",
|
||||
values = {"stamp": "true"},
|
||||
)
|
||||
|
77
CHANGELOG.md
77
CHANGELOG.md
@ -1,3 +1,80 @@
|
||||
<a name="11.0.0-next.6"></a>
|
||||
# 11.0.0-next.6 (2020-10-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler-cli:** type checking of expressions within ICUs ([#39072](https://github.com/angular/angular/issues/39072)) ([0a16e60](https://github.com/angular/angular/commit/0a16e60)), closes [#39064](https://github.com/angular/angular/issues/39064)
|
||||
* **core:** migrate relative link resolution with single quotes ([#39102](https://github.com/angular/angular/issues/39102)) ([049b453](https://github.com/angular/angular/commit/049b453)), closes [#39082](https://github.com/angular/angular/issues/39082)
|
||||
* **core:** use Trusted Types policy in inert DOM builder ([#39208](https://github.com/angular/angular/issues/39208)) ([7d49299](https://github.com/angular/angular/commit/7d49299))
|
||||
* **core:** use Trusted Types policy in named_array_type ([#39209](https://github.com/angular/angular/issues/39209)) ([f6d5cdf](https://github.com/angular/angular/commit/f6d5cdf))
|
||||
* **router:** Allow undefined inputs on routerLink ([#39151](https://github.com/angular/angular/issues/39151)) ([b0b4953](https://github.com/angular/angular/commit/b0b4953))
|
||||
* **router:** create schematic for preserveQueryParams ([#38762](https://github.com/angular/angular/issues/38762)) ([93ee05d](https://github.com/angular/angular/commit/93ee05d))
|
||||
* **router:** remove preserveQueryParams symbol ([#38762](https://github.com/angular/angular/issues/38762)) ([783a5bd](https://github.com/angular/angular/commit/783a5bd))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **core:** add automated migration to replace async with waitForAsync ([#39212](https://github.com/angular/angular/issues/39212)) ([5ce71e0](https://github.com/angular/angular/commit/5ce71e0))
|
||||
* **core:** add automated migration to replace ViewEncapsulation.Native ([#38882](https://github.com/angular/angular/issues/38882)) ([0e733f3](https://github.com/angular/angular/commit/0e733f3))
|
||||
* **core:** add initialNavigation schematic ([#36926](https://github.com/angular/angular/issues/36926)) ([0ec7043](https://github.com/angular/angular/commit/0ec7043))
|
||||
* **core:** add Trusted Types workaround for Function constructor ([#39209](https://github.com/angular/angular/issues/39209)) ([5913e5c](https://github.com/angular/angular/commit/5913e5c))
|
||||
* **core:** create internal Trusted Types module ([#39207](https://github.com/angular/angular/issues/39207)) ([0875fd2](https://github.com/angular/angular/commit/0875fd2))
|
||||
* **core:** depend on type definitions for Trusted Types ([#39207](https://github.com/angular/angular/issues/39207)) ([c4266fb](https://github.com/angular/angular/commit/c4266fb))
|
||||
* **core:** remove ViewEncapsulation.Native ([#38882](https://github.com/angular/angular/issues/38882)) ([4a1c12c](https://github.com/angular/angular/commit/4a1c12c))
|
||||
* **language-service:** [Ivy] getSemanticDiagnostics for external templates ([#39065](https://github.com/angular/angular/issues/39065)) ([63624a2](https://github.com/angular/angular/commit/63624a2))
|
||||
* **language-service:** Add getTypeDefinitionAtPosition (go to type definition) ([#39145](https://github.com/angular/angular/issues/39145)) ([a84976f](https://github.com/angular/angular/commit/a84976f))
|
||||
* **language-service:** Add module name to directive quick info ([#39121](https://github.com/angular/angular/issues/39121)) ([4604fe9](https://github.com/angular/angular/commit/4604fe9))
|
||||
* **router:** add new initialNavigation options to replace legacy ([#37480](https://github.com/angular/angular/issues/37480)) ([c4becca](https://github.com/angular/angular/commit/c4becca))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* **router:** * The `initialNavigation` property for the options in
|
||||
`RouterModule.forRoot` no longer supports `legacy_disabled`,
|
||||
`legacy_enabled`, `true`, or `false` as valid values.
|
||||
`legacy_enabled` (the old default) is instead `enabledNonBlocking`
|
||||
* `enabled` is deprecated as a valid value for the
|
||||
`RouterModule.forRoot` `initialNavigation` option. `enabledBlocking`
|
||||
has been introduced to replace it
|
||||
* **router:** preserveQueryParams has been removed, use
|
||||
queryParamsHandling="preserve" instead
|
||||
* **router:** If you were accessing the `RouterLink` values of `queryParams`,
|
||||
`fragment` or `queryParamsHandling` you might need to relax the typing to also
|
||||
accept `undefined` and `null`. ([#39151](https://github.com/angular/angular/issues/39151))
|
||||
* **core:** * `ViewEncapsulation.Native` has been removed. Use `ViewEncapsulation.ShadowDom` instead. Existing
|
||||
usages will be updated automatically by `ng update`.
|
||||
* **compiler-cli:** Expressions within ICUs are now type-checked again, fixing a regression
|
||||
in Ivy. This may cause compilation failures if errors are found in
|
||||
expressions that appear within an ICU. Please correct these expressions
|
||||
to resolve the type-check errors.
|
||||
|
||||
|
||||
<a name="10.1.6"></a>
|
||||
## 10.1.6 (2020-10-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler:** incorrectly encapsulating [@import](https://github.com/import) containing colons and semicolons ([#38716](https://github.com/angular/angular/issues/38716)) ([52a0c6b](https://github.com/angular/angular/commit/52a0c6b)), closes [#38587](https://github.com/angular/angular/issues/38587)
|
||||
* **compiler-cli:** support namespaced query types in directives ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([f752ab9](https://github.com/angular/angular/commit/f752ab9))
|
||||
* **elements:** detect matchesSelector prototype without IIFE ([#37799](https://github.com/angular/angular/issues/37799)) ([952fd86](https://github.com/angular/angular/commit/952fd86)), closes [#24551](https://github.com/angular/angular/issues/24551)
|
||||
* **ngcc:** ensure that "inline exports" can be interpreted correctly ([#39272](https://github.com/angular/angular/issues/39272)) ([e08d021](https://github.com/angular/angular/commit/e08d021))
|
||||
* **ngcc:** handle aliases in UMD export declarations ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([9963c5d](https://github.com/angular/angular/commit/9963c5d)), closes [#38947](https://github.com/angular/angular/issues/38947)
|
||||
* **ngcc:** map `exports` to the current module in UMD files ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([13c4a7b](https://github.com/angular/angular/commit/13c4a7b))
|
||||
* **ngcc:** support inline export declarations in UMD files ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([9c875b3](https://github.com/angular/angular/commit/9c875b3)), closes [#38947](https://github.com/angular/angular/issues/38947)
|
||||
|
||||
|
||||
### build
|
||||
|
||||
* upgrade angular build, integration/bazel and [@angular](https://github.com/angular)/bazel package to rule_nodejs 2.2.0 ([#39182](https://github.com/angular/angular/issues/39182)) ([7628c36](https://github.com/angular/angular/commit/7628c36))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **ngcc:** do not rescan program source files when referenced from multiple root files ([#39254](https://github.com/angular/angular/issues/39254)) ([5221df8](https://github.com/angular/angular/commit/5221df8)), closes [#39240](https://github.com/angular/angular/issues/39240)
|
||||
|
||||
|
||||
<a name="11.0.0-next.5"></a>
|
||||
# 11.0.0-next.5 (2020-10-07)
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
As contributors and maintainers of the Angular project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities.
|
||||
|
||||
Communication through any of Angular's channels (GitHub, Gitter, IRC, mailing lists, Google+, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
||||
Communication through any of Angular's channels (GitHub, Discord, Gitter, IRC, mailing lists, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
||||
|
||||
We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to the Angular project to do the same.
|
||||
|
||||
|
@ -32,7 +32,7 @@ Stack Overflow is a much better place to ask questions since:
|
||||
|
||||
To save your and our time, we will systematically close all issues that are requests for general support and redirect people to Stack Overflow.
|
||||
|
||||
If you would like to chat about the question in real-time, you can reach out via [our gitter channel][gitter].
|
||||
If you would like to chat about the question in real-time, you can reach out via [our Discord server][discord].
|
||||
|
||||
|
||||
## <a name="issue"></a> Found a Bug?
|
||||
@ -137,17 +137,37 @@ If we ask for changes via code reviews then:
|
||||
|
||||
For more info on working with fixup commits see [here](docs/FIXUP_COMMITS.md).
|
||||
|
||||
> Fixup commits (as shown above) are preferred when addressing review feedback, but in some cases you may need to amend the original commit instead of creating a fixup commit (for example, if you want to update the commit message).
|
||||
> To amend the last commit and update the Pull Request:
|
||||
>
|
||||
> ```shell
|
||||
> git commit --all --amend
|
||||
> git push --force-with-lease
|
||||
> ```
|
||||
|
||||
That's it! Thank you for your contribution!
|
||||
|
||||
|
||||
##### Updating the commit message
|
||||
|
||||
A reviewer might often suggest changes to a commit message (for example, to add more context for a change or adhere to our [commit message guidelines](#commit)).
|
||||
In order to update the commit message of the last commit on your branch:
|
||||
|
||||
1. Check out your branch:
|
||||
|
||||
```shell
|
||||
git checkout my-fix-branch
|
||||
```
|
||||
|
||||
2. Amend the last commit and modify the commit message:
|
||||
|
||||
```shell
|
||||
git commit --amend
|
||||
```
|
||||
|
||||
3. Push to your GitHub repository:
|
||||
|
||||
```shell
|
||||
git push --force-with-lease
|
||||
```
|
||||
|
||||
> NOTE:<br />
|
||||
> If you need to update the commit message of an earlier commit, you can use `git rebase` in interactive mode.
|
||||
> See the [git docs](https://git-scm.com/docs/git-rebase#_interactive_mode) for more details.
|
||||
|
||||
|
||||
#### After your pull request is merged
|
||||
|
||||
After your pull request is merged, you can safely delete your branch and pull the changes from the main (upstream) repository:
|
||||
@ -362,7 +382,7 @@ The following documents can help you sort out issues with GitHub accounts and mu
|
||||
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
|
||||
[dev-doc]: https://github.com/angular/angular/blob/master/docs/DEVELOPER.md
|
||||
[github]: https://github.com/angular/angular
|
||||
[gitter]: https://gitter.im/angular/angular
|
||||
[discord]: https://discord.gg/angular
|
||||
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
|
||||
[js-style-guide]: https://google.github.io/styleguide/jsguide.html
|
||||
[jsfiddle]: http://jsfiddle.net
|
||||
|
145
README.md
145
README.md
@ -1,26 +1,151 @@
|
||||
[](https://circleci.com/gh/angular/workflows/angular/tree/master)
|
||||
[](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://www.npmjs.com/@angular/core)
|
||||
<h1 align="center">Angular - One framework. Mobile & desktop.</h1>
|
||||
|
||||
<p align="center">
|
||||
<img src="aio/src/assets/images/logos/angular/angular.png" alt="angular-logo" width="120px" height="120px"/>
|
||||
<br>
|
||||
<i>Angular is a development platform for building mobile and desktop web applications
|
||||
<br> using Typescript/JavaScript and other languages.</i>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
# Angular
|
||||
<p align="center">
|
||||
<a href="https://www.angular.io"><strong>www.angular.io</strong></a>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
Angular is a development platform for building mobile and desktop web applications using TypeScript/JavaScript and other languages.
|
||||
<p align="center">
|
||||
<a href="CONTRIBUTING.md">Contributing Guidelines</a>
|
||||
·
|
||||
<a href="https://github.com/angular/angular/issues">Submit an Issue</a>
|
||||
·
|
||||
<a href="https://blog.angular.io/">Blog</a>
|
||||
<br>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://circleci.com/gh/angular/workflows/angular/tree/master">
|
||||
<img src="https://img.shields.io/circleci/build/github/angular/angular/master.svg?logo=circleci&logoColor=fff&label=CircleCI" alt="CI status" />
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/@angular/core">
|
||||
<img src="https://img.shields.io/npm/v/@angular/core.svg?logo=npm&logoColor=fff&label=NPM+package&color=limegreen" alt="Angular on npm" />
|
||||
</a>
|
||||
<a href="https://discord.gg/angular">
|
||||
<img src="https://img.shields.io/discord/463752820026376202.svg?logo=discord&logoColor=fff&label=Discord&color=7389d8" alt="Discord conversation" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
|
||||
## Documentation
|
||||
|
||||
Get started with Angular, learn the fundamentals and explore advanced topics on our documentation website.
|
||||
|
||||
- [Getting Started][quickstart]
|
||||
- [Architecture][architecture]
|
||||
- [Components and Templates][componentstemplates]
|
||||
- [Forms][forms]
|
||||
- [API][api]
|
||||
|
||||
### Advanced
|
||||
|
||||
- [Angular Elements][angularelements]
|
||||
- [Server Side Rendering][ssr]
|
||||
- [Schematics][schematics]
|
||||
- [Lazy Loading][lazyloading]
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Install [Node.js] which includes [Node Package Manager][npm]
|
||||
|
||||
### Setting Up a Project
|
||||
|
||||
Intall the Angular CLI globally:
|
||||
|
||||
```
|
||||
npm install -g @angular/cli
|
||||
```
|
||||
|
||||
Create workspace:
|
||||
|
||||
```
|
||||
ng new [PROJECT NAME]
|
||||
```
|
||||
|
||||
Run the application:
|
||||
|
||||
```
|
||||
cd [PROJECT NAME]
|
||||
ng serve
|
||||
```
|
||||
|
||||
## Quickstart
|
||||
|
||||
[Get started in 5 minutes][quickstart].
|
||||
|
||||
## Ecosystem
|
||||
|
||||
<p>
|
||||
<img src="/docs/images/angular-ecosystem-logos.png" alt="angular ecosystem logos" width="500px" height="auto">
|
||||
</p>
|
||||
|
||||
- [Angular Command Line (CLI)][cli]
|
||||
- [Angular Material][angularmaterial]
|
||||
|
||||
## Changelog
|
||||
|
||||
[Learn about the latest improvements][changelog].
|
||||
|
||||
## Want to help?
|
||||
## Upgrading
|
||||
|
||||
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our
|
||||
guidelines for [contributing][contributing] and then check out one of our issues in the [hotlist: community-help](https://github.com/angular/angular/labels/hotlist%3A%20community-help).
|
||||
Check out our [upgrade guide](https://update.angular.io/) to find out the best way to upgrade your project.
|
||||
|
||||
[contributing]: https://github.com/angular/angular/blob/master/CONTRIBUTING.md
|
||||
## Contributing
|
||||
|
||||
### Contributing Guidelines
|
||||
|
||||
Read through our [contributing guidelines][contributing] to learn about our submission process, coding rules and more.
|
||||
|
||||
### Want to Help?
|
||||
|
||||
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our guidelines for [contributing][contributing] and then check out one of our issues in the [hotlist: community-help](https://github.com/angular/angular/labels/hotlist%3A%20community-help).
|
||||
|
||||
### Code of Conduct
|
||||
|
||||
Help us keep Angular open and inclusive. Please read and follow our [Code of Conduct][codeofconduct].
|
||||
|
||||
## Community
|
||||
|
||||
Join the conversation and help the community.
|
||||
|
||||
- [Twitter][twitter]
|
||||
- [Gitter][gitter]
|
||||
- Find a Local [Meetup][meetup]
|
||||
|
||||
[](https://www.github.com/angular/angular)
|
||||
|
||||
**Love Angular? Give our repo a star :star: :arrow_up:.**
|
||||
|
||||
[contributing]: CONTRIBUTING.md
|
||||
[quickstart]: https://angular.io/start
|
||||
[changelog]: https://github.com/angular/angular/blob/master/CHANGELOG.md
|
||||
[changelog]: CHANGELOG.md
|
||||
[ng]: https://angular.io
|
||||
[documentation]: https://angular.io/docs
|
||||
[angularmaterial]: https://material.angular.io/
|
||||
[cli]: https://cli.angular.io/
|
||||
[architecture]: https://angular.io/guide/architecture
|
||||
[componentstemplates]: https://angular.io/guide/displaying-data
|
||||
[forms]: https://angular.io/guide/forms-overview
|
||||
[api]: https://angular.io/api
|
||||
[angularelements]: https://angular.io/guide/elements
|
||||
[ssr]: https://angular.io/guide/universal
|
||||
[schematics]: https://angular.io/guide/schematics
|
||||
[lazyloading]: https://angular.io/guide/lazy-loading-ngmodules
|
||||
[node.js]: https://nodejs.org/
|
||||
[npm]: https://www.npmjs.com/get-npm
|
||||
[codeofconduct]: CODE_OF_CONDUCT.md
|
||||
[twitter]: https://www.twitter.com/angular
|
||||
[gitter]: https://gitter.im/angular/angular
|
||||
[meetup]: https://www.meetup.com/find/?keywords=angular"
|
||||
|
20
WORKSPACE
20
WORKSPACE
@ -8,8 +8,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
# Fetch rules_nodejs so we can install our npm dependencies
|
||||
http_archive(
|
||||
name = "build_bazel_rules_nodejs",
|
||||
sha256 = "84abf7ac4234a70924628baa9a73a5a5cbad944c4358cf9abdb4aab29c9a5b77",
|
||||
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.7.0/rules_nodejs-1.7.0.tar.gz"],
|
||||
sha256 = "4952ef879704ab4ad6729a29007e7094aef213ea79e9f2e94cbe1c9a753e63ef",
|
||||
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/2.2.0/rules_nodejs-2.2.0.tar.gz"],
|
||||
)
|
||||
|
||||
# Check the rules_nodejs version and download npm dependencies
|
||||
@ -17,7 +17,7 @@ http_archive(
|
||||
# assert on that.
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "check_rules_nodejs_version", "node_repositories", "yarn_install")
|
||||
|
||||
check_rules_nodejs_version(minimum_version_string = "1.7.0")
|
||||
check_rules_nodejs_version(minimum_version_string = "2.2.0")
|
||||
|
||||
# Setup the Node.js toolchain
|
||||
node_repositories(
|
||||
@ -39,23 +39,18 @@ yarn_install(
|
||||
yarn_lock = "//:yarn.lock",
|
||||
)
|
||||
|
||||
# Install all bazel dependencies of the @npm npm packages
|
||||
load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
|
||||
|
||||
install_bazel_dependencies()
|
||||
|
||||
# Load angular dependencies
|
||||
load("//packages/bazel:package.bzl", "rules_angular_dev_dependencies")
|
||||
|
||||
rules_angular_dev_dependencies()
|
||||
|
||||
# Load protractor dependencies
|
||||
load("@npm_bazel_protractor//:package.bzl", "npm_bazel_protractor_dependencies")
|
||||
load("@npm//@bazel/protractor:package.bzl", "npm_bazel_protractor_dependencies")
|
||||
|
||||
npm_bazel_protractor_dependencies()
|
||||
|
||||
# Load karma dependencies
|
||||
load("@npm_bazel_karma//:package.bzl", "npm_bazel_karma_dependencies")
|
||||
load("@npm//@bazel/karma:package.bzl", "npm_bazel_karma_dependencies")
|
||||
|
||||
npm_bazel_karma_dependencies()
|
||||
|
||||
@ -68,11 +63,6 @@ load("//dev-infra/browsers:browser_repositories.bzl", "browser_repositories")
|
||||
|
||||
browser_repositories()
|
||||
|
||||
# Setup the rules_typescript tooolchain
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_setup_workspace")
|
||||
|
||||
ts_setup_workspace()
|
||||
|
||||
# Setup the rules_sass toolchain
|
||||
load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories")
|
||||
|
||||
|
@ -36,8 +36,9 @@ Here are the most important tasks you might need to use:
|
||||
|
||||
* `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally.
|
||||
* `yarn boilerplate:add:viewengine` - same as `boilerplate:add` but also turns on `ViewEngine` (pre-Ivy) mode.
|
||||
|
||||
* `yarn boilerplate:remove` - remove all the boilerplate code that was added via `yarn boilerplate:add`.
|
||||
* `yarn create-example` - create a new example directory containing initial source files.
|
||||
|
||||
* `yarn generate-stackblitz` - generate the stackblitz files that are used by the `live-example` tags in the docs.
|
||||
* `yarn generate-zips` - generate the zip files from the examples. Zip available via the `live-example` tags in the docs.
|
||||
|
||||
|
2
aio/content/examples/.gitignore
vendored
2
aio/content/examples/.gitignore
vendored
@ -32,6 +32,8 @@
|
||||
**/karma-test-shim.js
|
||||
**/browser-test-shim.js
|
||||
**/node_modules
|
||||
**/yarn.lock
|
||||
**/package-lock.json
|
||||
|
||||
# built files
|
||||
*.map
|
||||
|
@ -3,8 +3,10 @@
|
||||
<h2>Attribute binding</h2>
|
||||
<!-- #docregion attrib-binding-colspan -->
|
||||
<table border=1>
|
||||
<!-- #docregion colspan -->
|
||||
<!-- expression calculates colspan=2 -->
|
||||
<tr><td [attr.colspan]="1 + 1">One-Two</td></tr>
|
||||
<!-- #enddocregion colspan -->
|
||||
|
||||
<!-- ERROR: There is no `colspan` property to set!
|
||||
<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
|
||||
@ -32,31 +34,31 @@
|
||||
<!-- #docregion basic-specificity -->
|
||||
<h3>Basic specificity</h3>
|
||||
|
||||
<!-- The `class.special` binding will override any value for the `special` class in `classExpr`. -->
|
||||
<div [class.special]="isSpecial" [class]="classExpr">Some text.</div>
|
||||
<!-- The `class.special` binding overrides any value for the `special` class in `classExpression`. -->
|
||||
<div [class.special]="isSpecial" [class]="classExpression">Some text.</div>
|
||||
|
||||
<!-- The `style.color` binding will override any value for the `color` property in `styleExpr`. -->
|
||||
<div [style.color]="color" [style]="styleExpr">Some text.</div>
|
||||
<!-- The `style.color` binding overrides any value for the `color` property in `styleExpression`. -->
|
||||
<div [style.color]="color" [style]="styleExpression">Some text.</div>
|
||||
<!-- #enddocregion basic-specificity -->
|
||||
|
||||
<!-- #docregion source-specificity -->
|
||||
<h3>Source specificity</h3>
|
||||
|
||||
<!-- The `class.special` template binding will override any host binding to the `special` class set by `dirWithClassBinding` or `comp-with-host-binding`.-->
|
||||
<!-- The `class.special` template binding overrides any host binding to the `special` class set by `dirWithClassBinding` or `comp-with-host-binding`.-->
|
||||
<comp-with-host-binding [class.special]="isSpecial" dirWithClassBinding>Some text.</comp-with-host-binding>
|
||||
|
||||
<!-- The `style.color` template binding will override any host binding to the `color` property set by `dirWithStyleBinding` or `comp-with-host-binding`. -->
|
||||
<!-- The `style.color` template binding overrides any host binding to the `color` property set by `dirWithStyleBinding` or `comp-with-host-binding`. -->
|
||||
<comp-with-host-binding [style.color]="color" dirWithStyleBinding>Some text.</comp-with-host-binding>
|
||||
<!-- #enddocregion source-specificity -->
|
||||
|
||||
<!-- #docregion dynamic-priority -->
|
||||
<h3>Dynamic vs static</h3>
|
||||
|
||||
<!-- If `classExpr` has a value for the `special` class, this value will override the `class="special"` below -->
|
||||
<div class="special" [class]="classExpr">Some text.</div>
|
||||
<!-- If `classExpression` has a value for the `special` class, this value overrides the `class="special"` below -->
|
||||
<div class="special" [class]="classExpression">Some text.</div>
|
||||
|
||||
<!-- If `styleExpr` has a value for the `color` property, this value will override the `style="color: blue"` below -->
|
||||
<div style="color: blue" [style]="styleExpr">Some text.</div>
|
||||
<!-- If `styleExpression` has a value for the `color` property, this value overrides the `style="color: blue"` below -->
|
||||
<div style="color: blue" [style]="styleExpression">Some text.</div>
|
||||
|
||||
<!-- #enddocregion dynamic-priority -->
|
||||
|
||||
|
@ -9,7 +9,7 @@ export class AppComponent {
|
||||
actionName = 'Go for it';
|
||||
isSpecial = true;
|
||||
canSave = true;
|
||||
classExpr = 'special clearance';
|
||||
styleExpr = 'color: red';
|
||||
classExpression = 'special clearance';
|
||||
styleExpression = 'color: red';
|
||||
color = 'blue';
|
||||
}
|
||||
|
@ -11,6 +11,9 @@ export class CompWithHostBindingComponent {
|
||||
@HostBinding('style.color')
|
||||
color = 'green';
|
||||
|
||||
// #docregion hostbinding
|
||||
@HostBinding('style.width')
|
||||
width = '200px';
|
||||
// #enddocregion hostbinding
|
||||
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ import { Component, ViewEncapsulation } from '@angular/core';
|
||||
export class QuestSummaryComponent { }
|
||||
// #enddocregion
|
||||
/*
|
||||
// #docregion encapsulation.native
|
||||
// #docregion encapsulation.shadow
|
||||
// warning: few browsers support shadow DOM encapsulation at this time
|
||||
encapsulation: ViewEncapsulation.Native
|
||||
// #enddocregion encapsulation.native
|
||||
encapsulation: ViewEncapsulation.ShadowDom
|
||||
// #enddocregion encapsulation.shadow
|
||||
*/
|
||||
|
@ -23,13 +23,13 @@ describe('retry-on-error', () => {
|
||||
docRegionDefault(mockConsole, ajax);
|
||||
expect(mockConsole.log.calls.allArgs()).toEqual([
|
||||
['Subscribed to AJAX'],
|
||||
['Error occured.'],
|
||||
['Error occurred.'],
|
||||
['Subscribed to AJAX'],
|
||||
['Error occured.'],
|
||||
['Error occurred.'],
|
||||
['Subscribed to AJAX'],
|
||||
['Error occured.'],
|
||||
['Error occurred.'],
|
||||
['Subscribed to AJAX'],
|
||||
['Error occured.'],
|
||||
['Error occurred.'],
|
||||
['data: ', []],
|
||||
]);
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ export function docRegionDefault(console, ajax) {
|
||||
const apiData = ajax('/api/data').pipe(
|
||||
map((res: any) => {
|
||||
if (!res.response) {
|
||||
console.log('Error occured.');
|
||||
console.log('Error occurred.');
|
||||
throw new Error('Value expected!');
|
||||
}
|
||||
return res.response;
|
||||
|
@ -89,7 +89,7 @@ This example from the `HeroListComponent` template uses three of these forms.
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.1.html" header="src/app/hero-list.component.html (binding)" region="binding"></code-example>
|
||||
|
||||
* The `{{hero.name}}` [*interpolation*](guide/displaying-data#interpolation)
|
||||
* The `{{hero.name}}` [*interpolation*](guide/interpolation)
|
||||
displays the component's `hero.name` property value within the `<li>` element.
|
||||
|
||||
* The `[hero]` [*property binding*](guide/property-binding) passes the value of
|
||||
@ -166,8 +166,8 @@ The example template uses two built-in structural directives to add application
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.1.html" header="src/app/hero-list.component.html (structural)" region="structural"></code-example>
|
||||
|
||||
* [`*ngFor`](guide/displaying-data#ngFor) is an iterative; it tells Angular to stamp out one `<li>` per hero in the `heroes` list.
|
||||
* [`*ngIf`](guide/displaying-data#ngIf) is a conditional; it includes the `HeroDetail` component only if a selected hero exists.
|
||||
* [`*ngFor`](guide/structural-directives#inside-ngfor) is an iterative; it tells Angular to stamp out one `<li>` per hero in the `heroes` list.
|
||||
* [`*ngIf`](guide/structural-directives#ngif-case-study) is a conditional; it includes the `HeroDetail` component only if a selected hero exists.
|
||||
|
||||
#### Attribute directives
|
||||
|
||||
|
@ -11,7 +11,7 @@ about the features and tools that can help you develop and deliver Angular appli
|
||||
|
||||
## Application architecture
|
||||
|
||||
* The [Components and templates](guide/displaying-data) guide explains how to connect the application data in your [components](guide/glossary#component) to your page-display [templates](guide/glossary#template), to create a complete interactive application.
|
||||
* The **Main Concepts** section located in the table of contents contains several topics that explain how to connect the application data in your [components](guide/glossary#component) to your page-display [templates](guide/glossary#template), to create a complete interactive application.
|
||||
|
||||
* The [NgModules](guide/ngmodules) guide provides in-depth information on the modular structure of an Angular application.
|
||||
|
||||
@ -21,7 +21,7 @@ about the features and tools that can help you develop and deliver Angular appli
|
||||
|
||||
## Responsive programming
|
||||
|
||||
The **Components and Templates** guide provides guidance and details of the [template syntax](guide/template-syntax) that you use to display your component data when and where you want it within a view, and to collect input from users that you can respond to.
|
||||
The [template syntax](guide/template-syntax) and related topics contain details about how to display your component data when and where you want it within a view, and how to collect input from users that you can respond to.
|
||||
|
||||
Additional pages and sections describe some basic programming techniques for Angular apps.
|
||||
|
||||
@ -52,8 +52,6 @@ For some platforms and applications, you might also want to use the PWA (Progres
|
||||
|
||||
## Support for the development cycle
|
||||
|
||||
The **Development Workflow** section describes the tools and processes you use to compile, test, and deploy Angular applications.
|
||||
|
||||
* [CLI Command Reference](cli): The Angular CLI is a command-line tool that you use to create projects, generate application and library code, and perform a variety of ongoing development tasks such as testing, bundling, and deployment.
|
||||
|
||||
* [Compilation](guide/aot-compiler): Angular provides just-in-time (JIT) compilation for the development environment, and ahead-of-time (AOT) compilation for the production environment.
|
||||
@ -68,7 +66,6 @@ The **Development Workflow** section describes the tools and processes you use t
|
||||
|
||||
* [Accessibility](guide/accessibility): Make your app accessible to all users.
|
||||
|
||||
|
||||
## File structure, configuration, and dependencies
|
||||
|
||||
* [Workspace and file structure](guide/file-structure): Understand the structure of Angular workspace and project folders.
|
||||
|
@ -1,6 +1,7 @@
|
||||
# Attribute, class, and style bindings
|
||||
|
||||
The template syntax provides specialized one-way bindings for scenarios less well-suited to property binding.
|
||||
Attribute binding in Angular helps you set values for attributes directly.
|
||||
With attribute binding, you can improve accessibility, style your application dynamically, and manage multiple CSS classes or styles simultaneously.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@ -8,23 +9,36 @@ See the <live-example></live-example> for a working example containing the code
|
||||
|
||||
</div>
|
||||
|
||||
## Binding to an attribute
|
||||
|
||||
## Attribute binding
|
||||
It is recommended that you set an element property with a [property binding](guide/property-binding) whenever possible.
|
||||
However, sometimes you don't have an element property to bind.
|
||||
In those situations, you can use attribute binding.
|
||||
|
||||
Set the value of an attribute directly with an **attribute binding**. This is the only exception to the rule that a binding sets a target property and the only binding that creates and sets an attribute.
|
||||
For example, [ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) and
|
||||
[SVG](https://developer.mozilla.org/en-US/docs/Web/SVG) are purely attributes.
|
||||
Neither ARIA nor SVG correspond to element properties and don't set element properties.
|
||||
In these cases, you must use attribute binding because there are no corresponding property targets.
|
||||
|
||||
Usually, setting an element property with a [property binding](guide/property-binding)
|
||||
is preferable to setting the attribute with a string. However, sometimes
|
||||
there is no element property to bind, so attribute binding is the solution.
|
||||
|
||||
Consider the [ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) and
|
||||
[SVG](https://developer.mozilla.org/en-US/docs/Web/SVG). They are purely attributes, don't correspond to element properties, and don't set element properties. In these cases, there are no property targets to bind to.
|
||||
## Syntax
|
||||
|
||||
Attribute binding syntax resembles property binding, but
|
||||
instead of an element property between brackets, start with the prefix `attr`,
|
||||
followed by a dot (`.`), and the name of the attribute.
|
||||
You then set the attribute value, using an expression that resolves to a string,
|
||||
or remove the attribute when the expression resolves to `null`.
|
||||
Attribute binding syntax resembles [property binding](guide/property-binding), but instead of an element property between brackets, you precede the name of the attribute with the prefix `attr`, followed by a dot.
|
||||
Then, you set the attribute value with an expression that resolves to a string.
|
||||
|
||||
<code-example language="html">
|
||||
|
||||
<p [attr.attribute-you-are-targeting]="expression"></p>
|
||||
|
||||
</code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
When the expression resolves to `null`, Angular removes the attribute altogether.
|
||||
|
||||
</div>
|
||||
|
||||
## Binding ARIA attributes
|
||||
|
||||
One of the primary use cases for attribute binding
|
||||
is to set ARIA attributes, as in this example:
|
||||
@ -33,32 +47,30 @@ is to set ARIA attributes, as in this example:
|
||||
|
||||
{@a colspan}
|
||||
|
||||
## Binding to `colspan`
|
||||
|
||||
Another common use case for attribute binding is with the `colspan` attribute in tables.
|
||||
Binding to the `colspan` attribute helps you keep your tables programmatically dynamic.
|
||||
Depending on the amount of data that your application populates a table with, the number of columns that a row spans could change.
|
||||
|
||||
To use attribute binding with the `<td>` attribute `colspan`:
|
||||
|
||||
1. Specify the `colspan` attribute by using the following syntax: `[attr.colspan]`.
|
||||
1. Set `[attr.colspan]` equal to an expression.
|
||||
|
||||
In the following example, binds the `colspan` attribute to the expression `1 + 1`.
|
||||
|
||||
<code-example path="attribute-binding/src/app/app.component.html" region="colspan" header="src/app/app.component.html"></code-example>
|
||||
|
||||
This binding causes the `<tr>` to span two columns.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
#### `colspan` and `colSpan`
|
||||
Sometimes there are differences between the name of property and an attribute.
|
||||
|
||||
Notice the difference between the `colspan` attribute and the `colSpan` property.
|
||||
|
||||
If you wrote something like this:
|
||||
|
||||
<code-example language="html">
|
||||
<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
|
||||
</code-example>
|
||||
|
||||
You'd get this error:
|
||||
|
||||
<code-example language="bash">
|
||||
Template parse errors:
|
||||
Can't bind to 'colspan' since it isn't a known native property
|
||||
</code-example>
|
||||
|
||||
As the message says, the `<td>` element does not have a `colspan` property. This is true
|
||||
because `colspan` is an attribute—`colSpan`, with a capital `S`, is the
|
||||
corresponding property. Interpolation and property binding can set only *properties*, not attributes.
|
||||
|
||||
Instead, you'd use property binding and write it like this:
|
||||
|
||||
<code-example path="attribute-binding/src/app/app.component.html" region="colSpan" header="src/app/app.component.html"></code-example>
|
||||
`colspan` is an attribute of `<tr>`, while `colSpan` with a capital "S" is a property.
|
||||
When using attribute binding, use `colspan` with a lowercase "s".
|
||||
For more information on how to bind to the `colSpan` property, see the [`colspan` and `colSpan`](guide/property-binding#colspan) section of [Property Binding](guide/property-binding).
|
||||
|
||||
</div>
|
||||
|
||||
@ -66,28 +78,32 @@ Instead, you'd use property binding and write it like this:
|
||||
|
||||
{@a class-binding}
|
||||
|
||||
## Class binding
|
||||
## Binding to the `class` attribute
|
||||
|
||||
Here's how to set the `class` attribute without a binding in plain HTML:
|
||||
You can use class binding to add and remove CSS class names from an element's `class` attribute.
|
||||
|
||||
```html
|
||||
<!-- standard class attribute setting -->
|
||||
<div class="foo bar">Some text</div>
|
||||
```
|
||||
### Binding to a single CSS `class`
|
||||
|
||||
You can also add and remove CSS class names from an element's `class` attribute with a **class binding**.
|
||||
To create a single class binding, use the prefix `class` followed by a dot and the name of the CSS class—for example, `[class.sale]="onSale"`.
|
||||
Angular adds the class when the bound expression, `onSale` is truthy, and it removes the class when the expression is falsy—with the exception of `undefined`.
|
||||
See [styling delegation](guide/style-precedence#styling-delegation) for more information.
|
||||
|
||||
To create a single class binding, start with the prefix `class` followed by a dot (`.`) and the name of the CSS class (for example, `[class.foo]="hasFoo"`).
|
||||
Angular adds the class when the bound expression is truthy, and it removes the class when the expression is falsy (with the exception of `undefined`, see [styling delegation](#styling-delegation)).
|
||||
### Binding to multiple CSS classes
|
||||
|
||||
To create a binding to multiple classes, use a generic `[class]` binding without the dot (for example, `[class]="classExpr"`).
|
||||
The expression can be a space-delimited string of class names, or you can format it as an object with class names as the keys and truthy/falsy expressions as the values.
|
||||
With object format, Angular will add a class only if its associated value is truthy.
|
||||
To bind to multiple classes, use `[class]` set to an expression—for example, `[class]="classExpression"`.
|
||||
The expression can be a space-delimited string of class names, or an object with class names as the keys and truthy or falsy expressions as the values.
|
||||
With an object format, Angular adds a class only if its associated value is truthy.
|
||||
|
||||
It's important to note that with any object-like expression (`object`, `Array`, `Map`, `Set`, etc), the identity of the object must change for the class list to be updated.
|
||||
Updating the property without changing object identity will have no effect.
|
||||
<div class="alert is-important">
|
||||
|
||||
If there are multiple bindings to the same class name, conflicts are resolved using [styling precedence](#styling-precedence).
|
||||
With any object-like expression—such as `object`, `Array`, `Map`, or `Set`—the identity of the object must change for Angular to update the class list.
|
||||
Updating the property without changing object identity has no effect.
|
||||
|
||||
</div>
|
||||
|
||||
If there are multiple bindings to the same class name, Angular uses [styling precedence](guide/style-precedence) to determine which binding to use.
|
||||
|
||||
The following table summarizes class binding syntax.
|
||||
|
||||
<style>
|
||||
td, th {vertical-align: top}
|
||||
@ -118,13 +134,13 @@ If there are multiple bindings to the same class name, conflicts are resolved us
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Single class binding</td>
|
||||
<td><code>[class.foo]="hasFoo"</code></td>
|
||||
<td><code>[class.sale]="onSale"</code></td>
|
||||
<td><code>boolean | undefined | null</code></td>
|
||||
<td><code>true</code>, <code>false</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan=3>Multi-class binding</td>
|
||||
<td rowspan=3><code>[class]="classExpr"</code></td>
|
||||
<td rowspan=3><code>[class]="classExpression"</code></td>
|
||||
<td><code>string</code></td>
|
||||
<td><code>"my-class-1 my-class-2 my-class-3"</code></td>
|
||||
</tr>
|
||||
@ -138,44 +154,44 @@ If there are multiple bindings to the same class name, conflicts are resolved us
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
The [NgClass](guide/built-in-directives/#ngclass) directive can be used as an alternative to direct `[class]` bindings.
|
||||
However, using the above class binding syntax without `NgClass` is preferred because due to improvements in class binding in Angular, `NgClass` no longer provides significant value, and might eventually be removed in the future.
|
||||
|
||||
|
||||
<hr/>
|
||||
|
||||
## Style binding
|
||||
{@a style-binding}
|
||||
|
||||
Here's how to set the `style` attribute without a binding in plain HTML:
|
||||
## Binding to the style attribute
|
||||
|
||||
```html
|
||||
<!-- standard style attribute setting -->
|
||||
<div style="color: blue">Some text</div>
|
||||
```
|
||||
You can use style binding to set styles dynamically.
|
||||
|
||||
You can also set styles dynamically with a **style binding**.
|
||||
### Binding to a single style
|
||||
|
||||
To create a single style binding, start with the prefix `style` followed by a dot (`.`) and the name of the CSS style property (for example, `[style.width]="width"`).
|
||||
The property will be set to the value of the bound expression, which is normally a string.
|
||||
To create a single style binding, use the prefix `style` followed by a dot and the name of the CSS style property—for example, `[style.width]="width"`.
|
||||
Angular sets the property to the value of the bound expression, which is usually a string.
|
||||
Optionally, you can add a unit extension like `em` or `%`, which requires a number type.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Note that a _style property_ name can be written in either
|
||||
[dash-case](guide/glossary#dash-case), as shown above, or
|
||||
[camelCase](guide/glossary#camelcase), such as `fontSize`.
|
||||
You can write a style property name in either [dash-case](guide/glossary#dash-case), or
|
||||
[camelCase](guide/glossary#camelcase).
|
||||
|
||||
</div>
|
||||
|
||||
If there are multiple styles you'd like to toggle, you can bind to the `[style]` property directly without the dot (for example, `[style]="styleExpr"`).
|
||||
The expression attached to the `[style]` binding is most often a string list of styles like `"width: 100px; height: 100px;"`.
|
||||
### Binding to multiple styles
|
||||
|
||||
You can also format the expression as an object with style names as the keys and style values as the values, like `{width: '100px', height: '100px'}`.
|
||||
It's important to note that with any object-like expression (`object`, `Array`, `Map`, `Set`, etc), the identity of the object must change for the class list to be updated.
|
||||
Updating the property without changing object identity will have no effect.
|
||||
To toggle multiple styles, bind to the `[style]` attribute—for example, `[style]="styleExpression"`).
|
||||
The expression is often a string list of styles such as `"width: 100px; height: 100px;"`.
|
||||
|
||||
If there are multiple bindings to the same style property, conflicts are resolved using [styling precedence rules](#styling-precedence).
|
||||
You can also format the expression as an object with style names as the keys and style values as the values, such as `{width: '100px', height: '100px'}`.
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
With any object-like expression—such as `object`, `Array`, `Map`, or `Set`—the identity of the object must change for Angular to update the class list.
|
||||
Updating the property without changing object identity has no effect.
|
||||
|
||||
</div>
|
||||
|
||||
If there are multiple bindings to the same style attribute, Angular uses [styling precedence](guide/style-precedence) to determine which binding to use.
|
||||
|
||||
The following table summarizes style binding syntax.
|
||||
|
||||
<style>
|
||||
td, th {vertical-align: top}
|
||||
@ -219,7 +235,7 @@ If there are multiple bindings to the same style property, conflicts are resolve
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan=3>Multi-style binding</td>
|
||||
<td rowspan=3><code>[style]="styleExpr"</code></td>
|
||||
<td rowspan=3><code>[style]="styleExpression"</code></td>
|
||||
<td><code>string</code></td>
|
||||
<td><code>"width: 100px; height: 100px"</code></td>
|
||||
</tr>
|
||||
@ -232,72 +248,3 @@ If there are multiple bindings to the same style property, conflicts are resolve
|
||||
<td><code>['width', '100px']</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
The [NgStyle](guide/built-in-directives/#ngstyle) directive can be used as an alternative to direct `[style]` bindings.
|
||||
However, using the above style binding syntax without `NgStyle` is preferred because due to improvements in style binding in Angular, `NgStyle` no longer provides significant value, and might eventually be removed in the future.
|
||||
|
||||
|
||||
<hr/>
|
||||
|
||||
{@a styling-precedence}
|
||||
|
||||
## Styling Precedence
|
||||
|
||||
A single HTML element can have its CSS class list and style values bound to multiple sources (for example, host bindings from multiple directives).
|
||||
|
||||
When there are multiple bindings to the same class name or style property, Angular uses a set of precedence rules to resolve conflicts and determine which classes or styles are ultimately applied to the element.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
<h4>Styling precedence (highest to lowest)</h4>
|
||||
|
||||
1. Template bindings
|
||||
1. Property binding (for example, `<div [class.foo]="hasFoo">` or `<div [style.color]="color">`)
|
||||
1. Map binding (for example, `<div [class]="classExpr">` or `<div [style]="styleExpr">`)
|
||||
1. Static value (for example, `<div class="foo">` or `<div style="color: blue">`)
|
||||
1. Directive host bindings
|
||||
1. Property binding (for example, `host: {'[class.foo]': 'hasFoo'}` or `host: {'[style.color]': 'color'}`)
|
||||
1. Map binding (for example, `host: {'[class]': 'classExpr'}` or `host: {'[style]': 'styleExpr'}`)
|
||||
1. Static value (for example, `host: {'class': 'foo'}` or `host: {'style': 'color: blue'}`)
|
||||
1. Component host bindings
|
||||
1. Property binding (for example, `host: {'[class.foo]': 'hasFoo'}` or `host: {'[style.color]': 'color'}`)
|
||||
1. Map binding (for example, `host: {'[class]': 'classExpr'}` or `host: {'[style]': 'styleExpr'}`)
|
||||
1. Static value (for example, `host: {'class': 'foo'}` or `host: {'style': 'color: blue'}`)
|
||||
|
||||
</div>
|
||||
|
||||
The more specific a class or style binding is, the higher its precedence.
|
||||
|
||||
A binding to a specific class (for example, `[class.foo]`) will take precedence over a generic `[class]` binding, and a binding to a specific style (for example, `[style.bar]`) will take precedence over a generic `[style]` binding.
|
||||
|
||||
<code-example path="attribute-binding/src/app/app.component.html" region="basic-specificity" header="src/app/app.component.html"></code-example>
|
||||
|
||||
Specificity rules also apply when it comes to bindings that originate from different sources.
|
||||
It's possible for an element to have bindings in the template where it's declared, from host bindings on matched directives, and from host bindings on matched components.
|
||||
|
||||
Template bindings are the most specific because they apply to the element directly and exclusively, so they have the highest precedence.
|
||||
|
||||
Directive host bindings are considered less specific because directives can be used in multiple locations, so they have a lower precedence than template bindings.
|
||||
|
||||
Directives often augment component behavior, so host bindings from components have the lowest precedence.
|
||||
|
||||
<code-example path="attribute-binding/src/app/app.component.html" region="source-specificity" header="src/app/app.component.html"></code-example>
|
||||
|
||||
In addition, bindings take precedence over static attributes.
|
||||
|
||||
In the following case, `class` and `[class]` have similar specificity, but the `[class]` binding will take precedence because it is dynamic.
|
||||
|
||||
<code-example path="attribute-binding/src/app/app.component.html" region="dynamic-priority" header="src/app/app.component.html"></code-example>
|
||||
|
||||
{@a styling-delegation}
|
||||
### Delegating to styles with lower precedence
|
||||
|
||||
It is possible for higher precedence styles to "delegate" to lower precedence styles using `undefined` values.
|
||||
Whereas setting a style property to `null` ensures the style is removed, setting it to `undefined` will cause Angular to fall back to the next-highest precedence binding to that style.
|
||||
|
||||
For example, consider the following template:
|
||||
|
||||
<code-example path="attribute-binding/src/app/app.component.html" region="style-delegation" header="src/app/app.component.html"></code-example>
|
||||
|
||||
Imagine that the `dirWithHostBinding` directive and the `comp-with-host-binding` component both have a `[style.width]` host binding.
|
||||
In that case, if `dirWithHostBinding` sets its binding to `undefined`, the `width` property will fall back to the value of the `comp-with-host-binding` host binding.
|
||||
However, if `dirWithHostBinding` sets its binding to `null`, the `width` property will be removed entirely.
|
||||
|
@ -194,7 +194,7 @@ which explains the following:
|
||||
* Using [`<ng-container>`](guide/structural-directives#ngcontainer "<ng-container>")
|
||||
to group elements when there is no suitable host element for the directive.
|
||||
* How to write your own structural directive.
|
||||
* That you can only apply [one structural directive](guide/structural-directives#one-per-element "one per host element") to an element.
|
||||
* Why you [can only apply one structural directive](guide/structural-directives#one-per-element "one per host element") to an element.
|
||||
|
||||
</div>
|
||||
|
||||
@ -281,7 +281,7 @@ You define a block of HTML that defines how a single item should be displayed
|
||||
and then you tell Angular to use that block as a template for rendering each item in the list.
|
||||
The text assigned to `*ngFor` is the instruction that guides the repeater process.
|
||||
|
||||
The following example shows `NgFor` applied to a simple `<div>`. (Don't forget the asterisk (`*`) in front of `ngFor`.)
|
||||
The following example shows `NgFor` applied to a simple `<div>`.
|
||||
|
||||
<code-example path="built-in-directives/src/app/app.component.html" region="NgFor-1" header="src/app/app.component.html"></code-example>
|
||||
|
||||
|
@ -97,7 +97,7 @@ For the simplest deployment, create a production build and copy the output direc
|
||||
</code-example>
|
||||
|
||||
|
||||
2. Copy _everything_ within the output folder (`dist/` by default) to a folder on the server.
|
||||
2. Copy _everything_ within the output folder (`dist/project-name/` by default) to a folder on the server.
|
||||
|
||||
3. Configure the server to redirect requests for missing files to `index.html`.
|
||||
Learn more about server-side redirects [below](#fallback).
|
||||
@ -211,11 +211,11 @@ modified to serve `index.html`:
|
||||
# .
|
||||
# -- server.rb
|
||||
# -- public
|
||||
# |-- dist
|
||||
# |-- project-name
|
||||
# |-- index.html
|
||||
|
||||
get '/' do
|
||||
folderDir = settings.public_folder + '/dist' # ng build output folder
|
||||
folderDir = settings.public_folder + '/project-name' # ng build output folder
|
||||
send_file File.join(folderDir, 'index.html')
|
||||
end
|
||||
```
|
||||
@ -383,11 +383,11 @@ Build your app for production _including the source maps_
|
||||
|
||||
</code-example>
|
||||
|
||||
List the generated bundles in the `dist/` folder.
|
||||
List the generated bundles in the `dist/project-name/` folder.
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
|
||||
ls dist/*.js
|
||||
ls dist/project-name/*.js
|
||||
|
||||
</code-example>
|
||||
|
||||
@ -396,7 +396,7 @@ The following example displays the graph for the _main_ bundle.
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
|
||||
node_modules/.bin/source-map-explorer dist/main*
|
||||
node_modules/.bin/source-map-explorer dist/project-name/main*
|
||||
|
||||
</code-example>
|
||||
|
||||
|
@ -41,10 +41,8 @@ v9 - v12
|
||||
| `@angular/core` | [`DefaultIterableDiffer`](#core) | <!--v7--> v11 |
|
||||
| `@angular/core` | [`ReflectiveKey`](#core) | <!--v8--> v11 |
|
||||
| `@angular/core` | [`RenderComponentType`](#core) | <!--v7--> v11 |
|
||||
| `@angular/core` | [`ViewEncapsulation.Native`](#core) | <!--v6--> v11 |
|
||||
| `@angular/core` | [`WrappedValue`](#core) | <!--v10--> v12 |
|
||||
| `@angular/forms` | [`ngModel` with reactive forms](#ngmodel-reactive) | <!--v6--> v11 |
|
||||
| `@angular/router` | [`preserveQueryParams`](#router) | <!--v7--> v11 |
|
||||
| `@angular/upgrade` | [`@angular/upgrade`](#upgrade) | <!--v8--> v11 |
|
||||
| `@angular/upgrade` | [`getAngularLib`](#upgrade-static) | <!--v8--> v11 |
|
||||
| `@angular/upgrade` | [`setAngularLib`](#upgrade-static) | <!--v8--> v11 |
|
||||
@ -89,7 +87,6 @@ Tip: In the [API reference section](api) of this doc site, deprecated APIs are i
|
||||
| [`DefaultIterableDiffer`](api/core/DefaultIterableDiffer) | n/a | v4 | Not part of public API. |
|
||||
| [`ReflectiveInjector`](api/core/ReflectiveInjector) | [`Injector.create`](api/core/Injector#create) | v5 | See [`ReflectiveInjector`](#reflectiveinjector) |
|
||||
| [`ReflectiveKey`](api/core/ReflectiveKey) | none | v5 | none |
|
||||
| [`ViewEncapsulation.Native`](api/core/ViewEncapsulation#Native) | [`ViewEncapsulation.ShadowDom`](api/core/ViewEncapsulation#ShadowDom) | v6 | Use the native encapsulation mechanism of the renderer. See [view.ts](https://github.com/angular/angular/blob/3e992e18ebf51d6036818f26c3d77b52d3ec48eb/packages/core/src/metadata/view.ts#L32).
|
||||
| [`defineInjectable`](api/core/defineInjectable) | `ɵɵdefineInjectable` | v8 | Used only in generated code. No source code should depend on this API. |
|
||||
| [`entryComponents`](api/core/NgModule#entryComponents) | none | v9 | See [`entryComponents`](#entryComponents) |
|
||||
| [`ANALYZE_FOR_ENTRY_COMPONENTS`](api/core/ANALYZE_FOR_ENTRY_COMPONENTS) | none | v9 | See [`ANALYZE_FOR_ENTRY_COMPONENTS`](#entryComponents) |
|
||||
@ -115,12 +112,6 @@ Tip: In the [API reference section](api) of this doc site, deprecated APIs are i
|
||||
| --- | ----------- | --------------------- | ----- |
|
||||
| [`ngModel` with reactive forms](#ngmodel-reactive) | [`FormControlDirective`](api/forms/FormControlDirective) | v6 | none |
|
||||
|
||||
{@a router}
|
||||
### @angular/router
|
||||
|
||||
| API | Replacement | Deprecation announced | Notes |
|
||||
| --- | ----------- | --------------------- | ----- |
|
||||
| [`preserveQueryParams`](api/router/UrlCreationOptions#preserveQueryParams) | [`queryParamsHandling`](api/router/UrlCreationOptions#queryParamsHandling) | v4 | none |
|
||||
|
||||
{@a upgrade}
|
||||
### @angular/upgrade
|
||||
@ -490,15 +481,13 @@ This section contains a complete list all of the currently deprecated CLI flags.
|
||||
{@a removed}
|
||||
## Removed APIs
|
||||
|
||||
The following APIs have been removed starting with version 10.0.0*:
|
||||
The following APIs have been removed starting with version 11.0.0*:
|
||||
|
||||
| Package | API | Replacement | Notes |
|
||||
| ---------------- | -------------- | ----------- | ----- |
|
||||
| `@angular/core` | Undecorated base classes that use Angular features | Add Angular decorator | See [migration guide](guide/migration-undecorated-classes) for more info |
|
||||
| `@angular/core` | `ModuleWithProviders` without a generic | `ModuleWithProviders` with a generic | See [migration guide](guide/migration-module-with-providers) for more info |
|
||||
| `@angular/core` | Style Sanitization | no action needed | See [style sanitization API removal](#style-sanitization) for more info
|
||||
| `@angular/router` | `preserveQueryParams` | [`queryParamsHandling`](api/router/UrlCreationOptions#queryParamsHandling) | |
|
||||
|
||||
*To see APIs removed in version 9, check out this guide on the [version 9 docs site](https://v9.angular.io/guide/deprecations#removed).
|
||||
*To see APIs removed in version 10, check out this guide on the [version 10 docs site](https://v10.angular.io/guide/deprecations#removed).
|
||||
|
||||
|
||||
{@a esm5-fesm5}
|
||||
|
@ -1,312 +0,0 @@
|
||||
# Displaying data in views
|
||||
|
||||
Angular [components](guide/glossary#component) form the data structure of your application.
|
||||
The HTML [template](guide/glossary#template) associated with a component provides the means to display that data in the context of a web page.
|
||||
Together, a component's class and template form a [view](guide/glossary#view) of your application data.
|
||||
|
||||
The process of combining data values with their representation on the page is called [data binding](guide/glossary#data-binding).
|
||||
You display your data to a user (and collect data from the user) by *binding* controls in the HTML template to the data properties of the component class.
|
||||
|
||||
In addition, you can add logic to the template by including [directives](guide/glossary#directive), which tell Angular how to modify the page as it is rendered.
|
||||
|
||||
Angular defines a *template language* that expands HTML notation with syntax that allows you to define various kinds of data binding and logical directives.
|
||||
When the page is rendered, Angular interprets the template syntax to update the HTML according to your logic and current data state.
|
||||
Before you read the complete [template syntax guide](guide/template-syntax), the exercises on this page give you a quick demonstration of how template syntax works.
|
||||
|
||||
In this demo, you'll create a component with a list of heroes.
|
||||
You'll display the list of hero names and conditionally show a message below the list.
|
||||
The final UI looks like this:
|
||||
|
||||
<div class="lightbox">
|
||||
<img src="generated/images/guide/displaying-data/final.png" alt="Final UI">
|
||||
</div>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
The <live-example></live-example> demonstrates all of the syntax and code snippets described in this page.
|
||||
|
||||
</div>
|
||||
|
||||
{@a interpolation}
|
||||
|
||||
## Showing component properties with interpolation
|
||||
The easiest way to display a component property is to bind the property name through interpolation.
|
||||
With interpolation, you put the property name in the view template, enclosed in double curly braces: `{{myHero}}`.
|
||||
|
||||
Use the CLI command [`ng new displaying-data`](cli/new) to create a workspace and app named `displaying-data`.
|
||||
|
||||
Delete the <code>app.component.html</code> file. It is not needed for this example.
|
||||
|
||||
Then modify the <code>app.component.ts</code> file by
|
||||
changing the template and the body of the component.
|
||||
|
||||
When you're done, it should look like this:
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.1.ts" header="src/app/app.component.ts"></code-example>
|
||||
|
||||
You added two properties to the formerly empty component: `title` and `myHero`.
|
||||
|
||||
The template displays the two component properties using double curly brace
|
||||
interpolation:
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.1.ts" header="src/app/app.component.ts (template)" region="template"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
The template is a multi-line string within ECMAScript 2015 backticks (<code>\`</code>).
|
||||
The backtick (<code>\`</code>)—which is *not* the same character as a single
|
||||
quote (`'`)—allows you to compose a string over several lines, which makes the
|
||||
HTML more readable.
|
||||
|
||||
</div>
|
||||
|
||||
Angular automatically pulls the value of the `title` and `myHero` properties from the component and
|
||||
inserts those values into the browser. Angular updates the display
|
||||
when these properties change.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
More precisely, the redisplay occurs after some kind of asynchronous event related to
|
||||
the view, such as a keystroke, a timer completion, or a response to an HTTP request.
|
||||
|
||||
</div>
|
||||
|
||||
Notice that you don't call **new** to create an instance of the `AppComponent` class.
|
||||
Angular is creating an instance for you. How?
|
||||
|
||||
The CSS `selector` in the `@Component` decorator specifies an element named `<app-root>`.
|
||||
That element is a placeholder in the body of your `index.html` file:
|
||||
|
||||
<code-example path="displaying-data/src/index.html" header="src/index.html (body)" region="body"></code-example>
|
||||
|
||||
When you bootstrap with the `AppComponent` class (in <code>main.ts</code>), Angular looks for a `<app-root>`
|
||||
in the `index.html`, finds it, instantiates an instance of `AppComponent`, and renders it
|
||||
inside the `<app-root>` tag.
|
||||
|
||||
Now run the app. It should display the title and hero name:
|
||||
|
||||
<div class="lightbox">
|
||||
<img src="generated/images/guide/displaying-data/title-and-hero.png" alt="Title and Hero">
|
||||
</div>
|
||||
|
||||
The next few sections review some of the coding choices in the app.
|
||||
|
||||
|
||||
## Choosing the template source
|
||||
|
||||
The `@Component` metadata tells Angular where to find the component's template.
|
||||
You can store your component's template in one of two places.
|
||||
|
||||
* You can define the template *inline* using the `template` property of the `@Component` decorator. An inline template is useful for a small demo or test.
|
||||
* Alternatively, you can define the template in a separate HTML file and link to that file in the `templateUrl` property of the `@Component` decorator. This configuration is typical for anything more complex than a small test or demo, and is the default when you generate a new component.
|
||||
|
||||
In either style, the template data bindings have the same access to the component's properties.
|
||||
Here the app uses inline HTML because the template is small and the demo is simpler without the additional HTML file.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
By default, the Angular CLI command [`ng generate component`](cli/generate) generates components with a template file.
|
||||
You can override that by adding the "-t" (short for `inlineTemplate=true`) option:
|
||||
|
||||
<code-example hideCopy language="sh" class="code-shell">
|
||||
ng generate component hero -t
|
||||
</code-example>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
## Initialization
|
||||
|
||||
The following example uses variable assignment to initialize the components.
|
||||
|
||||
<code-example path="displaying-data/src/app/app-ctor.component.1.ts" region="class"></code-example>
|
||||
|
||||
You could instead declare and initialize the properties using a constructor.
|
||||
This app uses more terse "variable assignment" style simply for brevity.
|
||||
|
||||
|
||||
{@a ngFor}
|
||||
|
||||
## Add logic to loop through data
|
||||
|
||||
The `*ngFor` directive (predefined by Angular) lets you loop through data. The following example uses the directive to show all of the values in an array property.
|
||||
|
||||
To display a list of heroes, begin by adding an array of hero names to the component and redefine `myHero` to be the first name in the array.
|
||||
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.2.ts" header="src/app/app.component.ts (class)" region="class"></code-example>
|
||||
|
||||
|
||||
Now use the Angular `ngFor` directive in the template to display each item in the `heroes` list.
|
||||
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.2.ts" header="src/app/app.component.ts (template)" region="template"></code-example>
|
||||
|
||||
|
||||
This UI uses the HTML unordered list with `<ul>` and `<li>` tags. The `*ngFor`
|
||||
in the `<li>` element is the Angular "repeater" directive.
|
||||
It marks that `<li>` element (and its children) as the "repeater template":
|
||||
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.2.ts" header="src/app/app.component.ts (li)" region="li"></code-example>
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
Don't forget the leading asterisk (\*) in `*ngFor`. It is an essential part of the syntax.
|
||||
Read more about `ngFor` and `*` in the [ngFor section](guide/built-in-directives#ngfor) of the [Built-in directives](guide/built-in-directives) page.
|
||||
|
||||
</div>
|
||||
|
||||
Notice the `hero` in the `ngFor` double-quoted instruction;
|
||||
it is an example of a template input variable. Read
|
||||
more about template input variables in the [microsyntax](guide/built-in-directives#microsyntax) section of
|
||||
the [Built-in directives](guide/built-in-directives) page.
|
||||
|
||||
Angular duplicates the `<li>` for each item in the list, setting the `hero` variable
|
||||
to the item (the hero) in the current iteration. Angular uses that variable as the
|
||||
context for the interpolation in the double curly braces.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
In this case, `ngFor` is displaying an array, but `ngFor` can
|
||||
repeat items for any [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) object.
|
||||
|
||||
</div>
|
||||
|
||||
Now the heroes appear in an unordered list.
|
||||
|
||||
<div class="lightbox">
|
||||
<img src="generated/images/guide/displaying-data/hero-names-list.png" alt="After ngfor">
|
||||
</div>
|
||||
|
||||
|
||||
## Creating a class for the data
|
||||
|
||||
The app's code defines the data directly inside the component, which isn't best practice.
|
||||
In a simple demo, however, it's fine.
|
||||
|
||||
At the moment, the binding is to an array of strings.
|
||||
In real applications, most bindings are to more specialized objects.
|
||||
|
||||
To convert this binding to use specialized objects, turn the array
|
||||
of hero names into an array of `Hero` objects. For that you'll need a `Hero` class:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng generate class hero
|
||||
</code-example>
|
||||
|
||||
This command creates the following code.
|
||||
|
||||
|
||||
<code-example path="displaying-data/src/app/hero.ts" header="src/app/hero.ts"></code-example>
|
||||
|
||||
You've defined a class with a constructor and two properties: `id` and `name`.
|
||||
|
||||
It might not look like the class has properties, but it does.
|
||||
The declaration of the constructor parameters takes advantage of a TypeScript shortcut.
|
||||
|
||||
Consider the first parameter:
|
||||
|
||||
|
||||
<code-example path="displaying-data/src/app/hero.ts" header="src/app/hero.ts (id)" region="id"></code-example>
|
||||
|
||||
That brief syntax does a lot:
|
||||
|
||||
* Declares a constructor parameter and its type.
|
||||
* Declares a public property of the same name.
|
||||
* Initializes that property with the corresponding argument when creating an instance of the class.
|
||||
|
||||
|
||||
### Using the Hero class
|
||||
|
||||
After importing the `Hero` class, the `AppComponent.heroes` property can return a _typed_ array
|
||||
of `Hero` objects:
|
||||
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.3.ts" header="src/app/app.component.ts (heroes)" region="heroes"></code-example>
|
||||
|
||||
|
||||
|
||||
Next, update the template.
|
||||
At the moment it displays the hero's `id` and `name`.
|
||||
Fix that to display only the hero's `name` property.
|
||||
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.3.ts" header="src/app/app.component.ts (template)" region="template"></code-example>
|
||||
|
||||
|
||||
The display looks the same, but the code is clearer.
|
||||
|
||||
{@a ngIf}
|
||||
|
||||
## Conditional display with NgIf
|
||||
|
||||
Sometimes an app needs to display a view or a portion of a view only under specific circumstances.
|
||||
|
||||
Let's change the example to display a message if there are more than three heroes.
|
||||
|
||||
The Angular `ngIf` directive inserts or removes an element based on a _truthy/falsy_ condition.
|
||||
To see it in action, add the following paragraph at the bottom of the template:
|
||||
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.ts" header="src/app/app.component.ts (message)" region="message"></code-example>
|
||||
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
Don't forget the leading asterisk (\*) in `*ngIf`. It is an essential part of the syntax.
|
||||
Read more about `ngIf` and `*` in the [ngIf section](guide/built-in-directives#ngIf) of the [Built-in directives](guide/built-in-directives) page.
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
The template expression inside the double quotes,
|
||||
`*ngIf="heroes.length > 3"`, looks and behaves much like TypeScript.
|
||||
When the component's list of heroes has more than three items, Angular adds the paragraph
|
||||
to the DOM and the message appears.
|
||||
If there are three or fewer items, Angular omits the paragraph, so no message appears.
|
||||
|
||||
For more information, see [template expression operators](guide/interpolation#template-expressions).
|
||||
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Angular isn't showing and hiding the message. It is adding and removing the paragraph element from the DOM. That improves performance, especially in larger projects when conditionally including or excluding
|
||||
big chunks of HTML with many data bindings.
|
||||
|
||||
</div>
|
||||
|
||||
Try it out. Because the array has four items, the message should appear.
|
||||
Go back into <code>app.component.ts</code> and delete or comment out one of the elements from the heroes array.
|
||||
The browser should refresh automatically and the message should disappear.
|
||||
|
||||
|
||||
## Summary
|
||||
Now you know how to use:
|
||||
|
||||
* **Interpolation** with double curly braces to display a component property.
|
||||
* **ngFor** to display an array of items.
|
||||
* A TypeScript class to shape the **model data** for your component and display properties of that model.
|
||||
* **ngIf** to conditionally display a chunk of HTML based on a boolean expression.
|
||||
|
||||
Here's the final code:
|
||||
|
||||
<code-tabs>
|
||||
|
||||
<code-pane header="src/app/app.component.ts" path="displaying-data/src/app/app.component.ts" region="final">
|
||||
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/hero.ts" path="displaying-data/src/app/hero.ts">
|
||||
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/app.module.ts" path="displaying-data/src/app/app.module.ts">
|
||||
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="main.ts" path="displaying-data/src/main.ts">
|
||||
|
||||
</code-pane>
|
||||
|
||||
</code-tabs>
|
@ -4,7 +4,7 @@ An entry component is any component that Angular loads imperatively, (which mean
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
To contrast the two types of components, there are components which are included in the template, which are declarative. Additionally, there are components which you load imperatively; that is, entry components.
|
||||
To contrast the two types of components, there are components which are included in the template, which are declarative. Additionally, there are components which you load imperatively; that is, entry components.
|
||||
|
||||
</div>
|
||||
|
||||
@ -75,11 +75,10 @@ All router components must be entry components. Because this would require you t
|
||||
|
||||
|
||||
## The `entryComponents` array
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Since 9.0.0 with Ivy, the `entryComponents` property is no longer necessary. See [deprecations guide](guide/deprecations#entryComponents).
|
||||
|
||||
|
||||
Since 9.0.0 with Ivy, the `entryComponents` property is no longer necessary. See [deprecations guide](guide/deprecations#entryComponents).
|
||||
|
||||
</div>
|
||||
|
||||
Though the `@NgModule` decorator has an `entryComponents` array, most of the time
|
||||
|
@ -627,10 +627,11 @@ The [npm package manager](https://docs.npmjs.com/getting-started/what-is-npm) is
|
||||
|
||||
Learn more about how Angular uses [Npm Packages](guide/npm-packages).
|
||||
|
||||
{@ ngc}
|
||||
{@a ngc}
|
||||
|
||||
## ngc
|
||||
`ngc` is a Typescript-to-Javascript transpiler that processes Angular decorators, metadata, and templates, and emits JavaScript code.
|
||||
The most recent implementation is internally refered to as `ngtsc` because it's a minimalistic wrapper around the TypeScript compiler `tsc` that adds a transform for processing Angular code.
|
||||
The most recent implementation is internally referred to as `ngtsc` because it's a minimalistic wrapper around the TypeScript compiler `tsc` that adds a transform for processing Angular code.
|
||||
|
||||
{@a O}
|
||||
|
||||
|
@ -39,7 +39,34 @@ which is the attribute, spelled with a lowercase `s`.
|
||||
|
||||
For more details, see the [MDN HTMLTableCellElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement) documentation.
|
||||
|
||||
For more information about `colSpan` and `colspan`, see the [Attribute binding](guide/attribute-binding#colspan) guide.
|
||||
{@a colspan}
|
||||
|
||||
#### `colspan` and `colSpan`
|
||||
|
||||
A common point of confusion is between the attribute, `colspan`, and the property, `colSpan`.
|
||||
Notice that these two names differ by only a single letter.
|
||||
|
||||
If you wrote something like this:
|
||||
|
||||
<code-example language="html">
|
||||
<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
|
||||
</code-example>
|
||||
|
||||
You'd get this error:
|
||||
|
||||
<code-example language="bash">
|
||||
Template parse errors:
|
||||
Can't bind to 'colspan' since it isn't a known native property
|
||||
</code-example>
|
||||
|
||||
As the message says, the `<td>` element does not have a `colspan` property. This is true
|
||||
because `colspan` is an attribute—`colSpan`, with a capital `S`, is the
|
||||
corresponding property. Interpolation and property binding can set only *properties*, not attributes.
|
||||
|
||||
Instead, you'd use property binding and write it like this:
|
||||
|
||||
<code-example path="attribute-binding/src/app/app.component.html" region="colSpan" header="src/app/app.component.html"></code-example>
|
||||
|
||||
|
||||
Another example is disabling a button when the component says that it `isUnchanged`:
|
||||
|
||||
|
@ -180,7 +180,7 @@ A form group tracks the status and changes for each of its controls, so if one o
|
||||
|
||||
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="formgroup" header="src/app/profile-editor/profile-editor.component.html (template form group)"></code-example>
|
||||
|
||||
Note that just as a form group contains a group of controls, the *profile form* `FormGroup` is bound to the `form` element with the `FormGroup` directive, creating a communication layer between the model and the form containing the inputs. The `formControlName` input provided by the `FormControlName` directive binds each individual input to the form control defined in `FormGroup`. The form controls communicate with their respective elements. They also communicate changes to the form group instance, which provides the source of truth for the model value.
|
||||
Note that just as a form group contains a group of controls, the *profileForm* `FormGroup` is bound to the `form` element with the `FormGroup` directive, creating a communication layer between the model and the form containing the inputs. The `formControlName` input provided by the `FormControlName` directive binds each individual input to the form control defined in `FormGroup`. The form controls communicate with their respective elements. They also communicate changes to the form group instance, which provides the source of truth for the model value.
|
||||
|
||||
**Save form data**
|
||||
|
||||
|
@ -1656,7 +1656,7 @@ _before_ the `AppRoutingModule`:
|
||||
|
||||
</code-tabs>
|
||||
|
||||
Remove the initial crisis center route from the `app-routing.module.ts` because now the `HeroesModule` and the `CrisisCenter` modules provide teh feature routes.
|
||||
Remove the initial crisis center route from the `app-routing.module.ts` because now the `HeroesModule` and the `CrisisCenter` modules provide the feature routes.
|
||||
|
||||
The `app-routing.module.ts` file retains the top-level application routes such as the default and wildcard routes.
|
||||
|
||||
|
133
aio/content/guide/style-precedence.md
Normal file
133
aio/content/guide/style-precedence.md
Normal file
@ -0,0 +1,133 @@
|
||||
# Style Precedence
|
||||
|
||||
When there are multiple bindings to the same class name or style attribute, Angular uses a set of precedence rules to determine which classes or styles to apply to the element.
|
||||
These rules specify an order for which style- and class-related bindings have priority.
|
||||
This styling precedence is as follows, from the most specific with the highest priority to least specific with the lowest priorty:
|
||||
|
||||
1. Template bindings are the most specific because they apply to the element directly and exclusively, so they have the highest precedence.
|
||||
<table width="100%">
|
||||
<col width="40%"></col>
|
||||
<col width="60%"></col>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Binding type</th>
|
||||
<th>Example</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Property binding</td>
|
||||
<td><code><div [class.foo]="hasFoo"></code><br><code><div [style.color]="color"></code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Map binding</td>
|
||||
<td><code><div [class]="classExpression"></code><br><code><div [style]="styleExpression"></code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Static value</td>
|
||||
<td><code><div class="foo"></code><br><code><div style="color: blue"></code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
1. Directive host bindings are less specific because you can use directives in multiple locations, so they have a lower precedence than template bindings.
|
||||
<table width="100%">
|
||||
<col width="40%"></col>
|
||||
<col width="60%"></col>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Binding type</th>
|
||||
<th>Example</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Property binding</td>
|
||||
<td><code>host: {'[class.foo]': 'hasFoo'}</code><br><code>host: {'[style.color]': 'color'}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Map binding</td>
|
||||
<td><code>host: {'[class]': 'classExpr'}</code><br><code>host: {'[style]': 'styleExpr'}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Static value</td>
|
||||
<td><code>host: {'class': 'foo'}</code><br><code>host: {'style': 'color: blue'}</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
1. Component host bindings have the lowest precedence.
|
||||
<table width="100%">
|
||||
<col width="40%"></col>
|
||||
<col width="60%"></col>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Binding type</th>
|
||||
<th>Example</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Property binding</td>
|
||||
<td><code>host: {'[class.foo]': 'hasFoo'}</code><br><code>host: {'[style.color]': 'color'}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Map binding</td>
|
||||
<td><code>host: {'[class]': 'classExpression'}</code><br><code>host: {'[style]': 'styleExpression'}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Static value</td>
|
||||
<td><code>host: {'class': 'foo'}</code><br><code>host: {'style': 'color: blue'}</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Precedence and specificity
|
||||
|
||||
In the following example, binding to a specific class, as in `[class.special]`, takes precedence over a generic `[class]` binding.
|
||||
Similarly, binding to a specific style, as in `[style.color]`, takes precedence over a generic `[style]` binding.
|
||||
|
||||
<code-example path="attribute-binding/src/app/app.component.html" region="basic-specificity" header="src/app/app.component.html"></code-example>
|
||||
|
||||
## Precedence and bindings from different sources
|
||||
|
||||
Specificity rules also apply to bindings even when they originate from different sources.
|
||||
An element can have bindings that originate from its own template, from host bindings on matched directives, and from host bindings on matched components.
|
||||
|
||||
<code-example path="attribute-binding/src/app/app.component.html" region="source-specificity" header="src/app/app.component.html"></code-example>
|
||||
|
||||
## Precedence of bindings and static attributes
|
||||
|
||||
Bindings take precedence over static attributes because they are dynamic.
|
||||
In the following case, `class` and `[class]` have similar specificity, but the `[class]` binding takes precedence.
|
||||
|
||||
<code-example path="attribute-binding/src/app/app.component.html" region="dynamic-priority" header="src/app/app.component.html"></code-example>
|
||||
|
||||
{@a styling-delegation}
|
||||
|
||||
## Delegating to styles with lower precedence
|
||||
|
||||
Higher precedence styles can defer to lower precedence styles using `undefined` values.
|
||||
For example, consider the following template:
|
||||
|
||||
<code-example path="attribute-binding/src/app/app.component.html" region="style-delegation" header="src/app/app.component.html"></code-example>
|
||||
|
||||
Imagine that the `dirWithHostBinding` directive and the `comp-with-host-binding` component both have a `[style.width]` host binding.
|
||||
|
||||
<code-example path="attribute-binding/src/app/comp-with-host-binding.component.ts" region="hostbinding" header="src/app/comp-with-host-binding.component.ts and dirWithHostBinding.directive.ts"></code-example>
|
||||
|
||||
If `dirWithHostBinding` sets its binding to `undefined`, the `width` property falls back to the value of the `comp-with-host-binding` host binding.
|
||||
|
||||
<code-example header="dirWithHostBinding directive">
|
||||
@HostBinding('style.width')
|
||||
width = ''; // undefined
|
||||
</code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
If `dirWithHostBinding` sets its binding to `null`, Angular removes the `width` property entirely.
|
||||
|
||||
<code-example header="dirWithHostBinding">
|
||||
@HostBinding('style.width')
|
||||
width = null;
|
||||
</code-example>
|
||||
|
||||
</div>
|
@ -14,7 +14,7 @@ In the following example, the template statement `deleteHero()` appears in quote
|
||||
|
||||
<code-example path="template-syntax/src/app/app.component.html" region="context-component-statement" header="src/app/app.component.html"></code-example>
|
||||
|
||||
When the user clicks the **Delete hero** button, Angular calls the `deleteHero()` function in the component class.
|
||||
When the user clicks the **Delete hero** button, Angular calls the `deleteHero()` method in the component class.
|
||||
|
||||
You can use template statements with elements, components, or directives in response to events.
|
||||
|
||||
|
@ -234,8 +234,8 @@ To fix this issue, listen to both the _Enter_ key and the _blur_ event.
|
||||
|
||||
|
||||
## Put it all together
|
||||
The previous page showed how to [display data](guide/displaying-data).
|
||||
This page demonstrated event binding techniques.
|
||||
|
||||
This page demonstrated several event binding techniques.
|
||||
|
||||
Now, put it all together in a micro-app
|
||||
that can display a list of heroes and add new heroes to the list.
|
||||
|
@ -13,8 +13,6 @@ Choose from the following modes:
|
||||
to attach a shadow DOM to the component's host element, and then puts the component
|
||||
view inside that shadow DOM. The component's styles are included within the shadow DOM.
|
||||
|
||||
* `Native` view encapsulation uses a now deprecated version of the browser's native shadow DOM implementation - [learn about the changes](https://hayato.io/2016/shadowdomv1/).
|
||||
|
||||
* `Emulated` view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing
|
||||
(and renaming) the CSS code to effectively scope the CSS to the component's view.
|
||||
For details, see [Inspecting generated CSS](guide/view-encapsulation#inspect-generated-css) below.
|
||||
@ -26,7 +24,7 @@ Choose from the following modes:
|
||||
|
||||
To set the components encapsulation mode, use the `encapsulation` property in the component metadata:
|
||||
|
||||
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" header="src/app/quest-summary.component.ts"></code-example>
|
||||
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.shadow" header="src/app/quest-summary.component.ts"></code-example>
|
||||
|
||||
`ShadowDom` view encapsulation only works on browsers that have native support
|
||||
for shadow DOM (see [Shadow DOM v1](https://caniuse.com/#feat=shadowdomv1) on the
|
||||
@ -80,4 +78,4 @@ by the generated component styles, which are in the `<head>` section of the DOM:
|
||||
|
||||
These styles are post-processed so that each selector is augmented
|
||||
with `_nghost` or `_ngcontent` attribute selectors.
|
||||
These extra selectors enable the scoping rules described in this page.
|
||||
These extra selectors enable the scoping rules described in this page.
|
||||
|
@ -9,7 +9,7 @@ To understand the benefits of `NgZone`, it is important to have a clear grasp of
|
||||
|
||||
### Displaying and updating data in Angular
|
||||
|
||||
In Angular, you can [display data](guide/displaying-data) by binding controls in an HTML template to the properties of an Angular component.
|
||||
In Angular, you can display data by binding controls in an HTML template to the properties of an Angular component.
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.1.ts" header="src/app/app.component.ts"></code-example>
|
||||
|
||||
@ -102,13 +102,13 @@ In Angular, this step is unnecessary. Whenever you update the data, your HTML is
|
||||
|
||||
To understand how change detection works, first consider when the application needs to update the HTML. Typically, updates occur for one of the following reasons:
|
||||
|
||||
1. Component initialization. For example, when bootstrapping an Angular application, Angular loads the bootstrap component and triggers the [ApplicationRef.tick()](api/core/ApplicationRef#tick) to call change detection and View Rendering. Just as in the [displaying data](guide/displaying-data) sample, the `AppComponent` is the bootstrap component. This component has the properties `title` and `myHero`, which the application renders in the HTML.
|
||||
1. Component initialization. For example, when bootstrapping an Angular application, Angular loads the bootstrap component and triggers the [ApplicationRef.tick()](api/core/ApplicationRef#tick) to call change detection and View Rendering.
|
||||
|
||||
2. Event listener. The DOM event listener can update the data in an Angular component and also trigger change detection, as in the following example.
|
||||
1. Event listener. The DOM event listener can update the data in an Angular component and also trigger change detection, as in the following example.
|
||||
|
||||
<code-example path="user-input/src/app/click-me.component.ts" region="click-me-component" header="src/app/click-me.component.ts"></code-example>
|
||||
|
||||
3. HTTP Data Request. You can also get data from a server through an HTTP request. For example:
|
||||
1. HTTP Data Request. You can also get data from a server through an HTTP request. For example:
|
||||
|
||||
```typescript
|
||||
@Component({
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 56 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 257 KiB After Width: | Height: | Size: 79 KiB |
@ -461,8 +461,8 @@
|
||||
"name": "Sajeetharan Sinnathurai",
|
||||
"picture": "sajee.jpg",
|
||||
"twitter": "kokkisajee",
|
||||
"website": "https://sajeetharan.herokuapp.com/",
|
||||
"bio": "Sajeetharan is a Developer, Top contributor on stackoverflow for #Angular, ng-SriLanka organizer. He makes use of his extensive knowledge over the past years to contribute to community to make the world a better place.",
|
||||
"website": "https://sajeetharan.com/",
|
||||
"bio": "Sajeetharan is a Cloud Architect, Top contributor on stackoverflow for #Angular, ng-SriLanka organizer. He makes use of his extensive knowledge over the past years to contribute to community to make the world a better place.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
"lacolaco": {
|
||||
|
@ -106,17 +106,12 @@
|
||||
"title": "User Input",
|
||||
"tooltip": "User input triggers DOM events. Angular listens to those events with event bindings that funnel updated values back into your app's components and models."
|
||||
},
|
||||
{
|
||||
"url": "guide/pipes",
|
||||
"title": "Pipes",
|
||||
"tooltip": "Pipes transform displayed values within a template."
|
||||
},
|
||||
{
|
||||
"url": "guide/lifecycle-hooks",
|
||||
"title": "Component Lifecycle",
|
||||
"tooltip": "Angular calls lifecycle hook methods on directives and components as it creates, changes, and destroys them."
|
||||
},
|
||||
{
|
||||
{
|
||||
"url": "guide/view-encapsulation",
|
||||
"title": "View Encapsulation",
|
||||
"tooltip": "Describes how component CSS styles are encapsulated into a component's view."
|
||||
@ -131,6 +126,11 @@
|
||||
"title": "Component Styles",
|
||||
"tooltip": "Add CSS styles that are specific to a component."
|
||||
},
|
||||
{
|
||||
"url": "guide/inputs-outputs",
|
||||
"title": "Inputs and Outputs",
|
||||
"tooltip": "Introductory guide to sharing data between parent and child directives or components."
|
||||
},
|
||||
{
|
||||
"url": "guide/dynamic-component-loader",
|
||||
"title": "Dynamic Components",
|
||||
@ -162,6 +162,11 @@
|
||||
"title": "Template statements",
|
||||
"tooltip": "Introductory guide to statements in templates that respond to events that components, directives, or elements raise."
|
||||
},
|
||||
{
|
||||
"url": "guide/pipes",
|
||||
"title": "Pipes",
|
||||
"tooltip": "Pipes transform displayed values within a template."
|
||||
},
|
||||
{
|
||||
"url": "guide/binding-syntax",
|
||||
"title": "Binding syntax",
|
||||
@ -192,11 +197,6 @@
|
||||
"title": "Template reference variables",
|
||||
"tooltip": "Introductory guide to referring to DOM elements within a template."
|
||||
},
|
||||
{
|
||||
"url": "guide/inputs-outputs",
|
||||
"title": "Inputs and Outputs",
|
||||
"tooltip": "Introductory guide to sharing data between parent and child directives or components."
|
||||
},
|
||||
{
|
||||
"url": "guide/template-expression-operators",
|
||||
"title": "Template expression operators",
|
||||
@ -609,11 +609,6 @@
|
||||
"title": "Building a Template-driven Form",
|
||||
"tooltip": "Create a template-driven form using directives and Angular template syntax."
|
||||
},
|
||||
{
|
||||
"url": "guide/displaying-data",
|
||||
"title": "Data binding",
|
||||
"tooltip": "Property binding helps show app data in the UI."
|
||||
},
|
||||
{
|
||||
"url": "guide/web-worker",
|
||||
"title": "Web Workers",
|
||||
@ -1009,6 +1004,11 @@
|
||||
"title": "Stack Overflow",
|
||||
"tooltip": "Stack Overflow: where the community answers your technical Angular questions."
|
||||
},
|
||||
{
|
||||
"url": "https://discord.gg/angular",
|
||||
"title": "Join Discord",
|
||||
"tooltip": "Join the discussions at Angular Community Discord server."
|
||||
},
|
||||
{
|
||||
"url": "https://gitter.im/angular/angular",
|
||||
"title": "Gitter",
|
||||
|
@ -31,6 +31,7 @@
|
||||
{"type": 301, "source": "/guide/quickstart", "destination": "/start"},
|
||||
{"type": 301, "source": "/getting-started", "destination": "/start"},
|
||||
{"type": 301, "source": "/getting-started/:rest*", "destination": "/start/:rest*"},
|
||||
{"type": 301, "source": "/guide/displaying-data", "destination": "/start#template-syntax"},
|
||||
|
||||
// Renaming of Getting Started topics
|
||||
{"type": 301, "source": "/start/data", "destination": "/start/start-data"},
|
||||
@ -128,7 +129,8 @@
|
||||
// The below paths are referenced in users projects generated by the CLI
|
||||
{"type": 301, "source": "/config/tsconfig", "destination": "/guide/typescript-configuration"},
|
||||
{"type": 301, "source": "/config/solution-tsconfig", "destination": "https://devblogs.microsoft.com/typescript/announcing-typescript-3-9/#solution-style-tsconfig"},
|
||||
{"type": 301, "source": "/config/app-package-json", "destination": "/guide/strict-mode#non-local-side-effects-in-applications"}
|
||||
{"type": 301, "source": "/config/app-package-json", "destination": "/guide/strict-mode#non-local-side-effects-in-applications"},
|
||||
{"type": 301, "source": "/strict", "destination": "/guide/strict-mode"}
|
||||
],
|
||||
"rewrites": [
|
||||
{
|
||||
|
@ -102,6 +102,9 @@
|
||||
"!/guide/cli-quickstart",
|
||||
"!/guide/cli-quickstart.html",
|
||||
"!/guide/cli-quickstart/",
|
||||
"!/guide/displaying-data",
|
||||
"!/guide/displaying-data.html",
|
||||
"!/guide/displaying-data/",
|
||||
"!/guide/learning-angular",
|
||||
"!/guide/learning-angular.html",
|
||||
"!/guide/learning-angular/",
|
||||
@ -148,6 +151,7 @@
|
||||
"!/styleguide/**",
|
||||
"!/testing",
|
||||
"!/testing/**",
|
||||
"!/config/**"
|
||||
"!/config/**",
|
||||
"!/strict"
|
||||
]
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
"build-local-with-viewengine": "yarn ~~build",
|
||||
"prebuild-local-with-viewengine-ci": "node scripts/switch-to-viewengine && yarn setup-local-ci",
|
||||
"build-local-with-viewengine-ci": "yarn ~~build --progress=false",
|
||||
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js 65fb6788d",
|
||||
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js 06ad10668",
|
||||
"lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint",
|
||||
"test": "yarn check-env && ng test",
|
||||
"pree2e": "yarn check-env && yarn update-webdriver",
|
||||
@ -64,13 +64,14 @@
|
||||
"tools-lint": "tslint --config \"tools/tslint.json\" --project \"tools/firebase-test-utils\"",
|
||||
"tools-test": "./scripts/deploy-to-firebase.test.sh && yarn docs-test && yarn boilerplate:test && jasmine tools/ng-packages-installer/index.spec.js && yarn firebase-utils-test",
|
||||
"preserve-and-sync": "yarn docs",
|
||||
"serve-and-sync": "run-p \"start\" \"docs-watch --watch-only\"",
|
||||
"serve-and-sync": "run-p \"docs-watch --watch-only\" \"start {@}\" --",
|
||||
"boilerplate:add": "node ./tools/examples/example-boilerplate add",
|
||||
"boilerplate:add:viewengine": "yarn boilerplate:add --viewengine",
|
||||
"boilerplate:remove": "node ./tools/examples/example-boilerplate remove",
|
||||
"boilerplate:test": "node tools/examples/test.js",
|
||||
"generate-stackblitz": "node ./tools/stackblitz-builder/generateStackblitz",
|
||||
"generate-zips": "node ./tools/example-zipper/generateZips",
|
||||
"create-example": "node ./tools/examples/create-example.js",
|
||||
"build-404-page": "node scripts/build-404-page",
|
||||
"update-webdriver": "node ../scripts/webdriver-manager-update.js",
|
||||
"~~audit-web-app": "node scripts/audit-web-app",
|
||||
@ -153,7 +154,7 @@
|
||||
"lunr": "^2.1.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"protractor": "~5.4.4",
|
||||
"puppeteer": "3.3.0",
|
||||
"puppeteer": "5.1.0",
|
||||
"rehype": "^6.0.0",
|
||||
"rehype-slug": "^2.0.0",
|
||||
"remark": "^9.0.0",
|
||||
@ -172,6 +173,6 @@
|
||||
"unist-util-visit-parents": "^1.1.1",
|
||||
"watchr": "^3.0.1",
|
||||
"xregexp": "^4.0.0",
|
||||
"yargs": "^7.0.2"
|
||||
"yargs": "^16.1.0"
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ const initialDocViewerContent = initialDocViewerElement ? initialDocViewerElemen
|
||||
selector: 'aio-doc-viewer',
|
||||
template: ''
|
||||
// TODO(robwormald): shadow DOM and emulated don't work here (?!)
|
||||
// encapsulation: ViewEncapsulation.Native
|
||||
// encapsulation: ViewEncapsulation.ShadowDom
|
||||
})
|
||||
export class DocViewerComponent implements OnDestroy {
|
||||
// Enable/Disable view transition animations.
|
||||
|
@ -18,7 +18,7 @@
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
/** IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/**
|
||||
|
@ -38,7 +38,11 @@
|
||||
margin: 0;
|
||||
clear: left;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
color: $blue;
|
||||
@include font-size(14);
|
||||
}
|
||||
.show-all {
|
||||
display: initial;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ export function createCustomEvent(doc: Document, name: string, detail: any): Cus
|
||||
const bubbles = false;
|
||||
const cancelable = false;
|
||||
|
||||
// On IE9-11, `CustomEvent` is not a constructor.
|
||||
// On IE11, `CustomEvent` is not a constructor.
|
||||
if (typeof CustomEvent !== 'function') {
|
||||
const event = doc.createEvent('CustomEvent');
|
||||
event.initCustomEvent(name, bubbles, cancelable, detail);
|
||||
|
@ -177,6 +177,7 @@
|
||||
/getting-started/forms /start/start-forms
|
||||
/getting-started/deployment /start/start-deployment
|
||||
/guide/cli-quickstart /start
|
||||
/guide/displaying-data /start#template-syntax
|
||||
/guide/learning-angular /start
|
||||
/guide/learning-angular.html /start
|
||||
/guide/metadata /guide/aot-compiler
|
||||
|
@ -29,11 +29,12 @@ sub-folder. Also there are a number of common boilerplate files that are needed
|
||||
example's project. We maintain these common boilerplate files centrally to reduce the amount of effort
|
||||
if one of them needs to change.
|
||||
|
||||
This `examples` tool folder contains two utilities:
|
||||
This `examples` tool folder contains three utilities:
|
||||
|
||||
* example-boilerplate.js - install/remove the npm dependencies and boilerplate files into/from each of the
|
||||
examples' subfolders.
|
||||
* run-example-e2e.js - run the e2e tests for one or more examples
|
||||
* create-example.js - create a new example from the `example-scaffold/` directory or by importing files from a CLI project.
|
||||
|
||||
See the [README.md](examples/README.md) for more details.
|
||||
|
||||
|
@ -150,6 +150,14 @@ See [aio/README.md](../../README.md#developer-tasks) for the available command-l
|
||||
|
||||
Running the script will create an `aio/protractor-results.txt` file with the results of the tests.
|
||||
|
||||
### `create-example.js`
|
||||
|
||||
The [create-example.js](./create-example.js) script creates a new example under the `aio/content/examples` directory.
|
||||
|
||||
You must provide a new name for the example.
|
||||
By default the script will place basic scaffold files into the new example (from [shared/example-scaffold](./shared/example-scaffold)).
|
||||
But you can also specify the path to a separate CLI project, from which the script will copy files that would not be considered "boilerplate".
|
||||
See the [Boilerplate overview](#boilerplate-overview) for more information.
|
||||
|
||||
### Updating example dependencies
|
||||
|
||||
|
@ -7,9 +7,9 @@ Follow these steps to update the examples to the latest versions of Angular (and
|
||||
> NOTE:
|
||||
> The [angular-cli-diff](https://github.com/cexbrayat/angular-cli-diff) repo can be a useful resource for discovering what dependency versions are used for a basic CLI app at a specific CLI version.
|
||||
|
||||
- In the [shared/](./shared) folder, run `yarn` to update the dependencies in the [shared/node_modules/](./shared/node_modules) folder and the [shared/yarn.lock](./shared/yarn.lock) file.
|
||||
- In the [shared/](./shared) directory, run `yarn` to update the dependencies in the [shared/node_modules/](./shared/node_modules) directory and the [shared/yarn.lock](./shared/yarn.lock) file.
|
||||
|
||||
- In the [shared/](./shared) folder, run `yarn sync-deps` to update the dependency versions of the `package.json` files in each sub-folder of [shared/boilerplate/](./shared/boilerplate) to match the ones in [shared/package.json](./shared/package.json).
|
||||
- In the [shared/](./shared) directory, run `yarn sync-deps` to update the dependency versions of the `package.json` files in each sub-folder of [shared/boilerplate/](./shared/boilerplate) to match the ones in [shared/package.json](./shared/package.json).
|
||||
|
||||
- Follow the steps in the following section to update the rest of the boilerplate files.
|
||||
|
||||
@ -24,7 +24,7 @@ Any necessary changes to boilerplate files will be done automatically through mi
|
||||
> You have to make these changes (if any) manually.
|
||||
> Again, the [angular-cli-diff](https://github.com/cexbrayat/angular-cli-diff) repo can be a useful resource for discovering changes between versions.
|
||||
|
||||
- In the [shared/boilerplate/cli/](./shared/boilerplate/cli) folder, run the following commands to migrate the the project to the current versions of Angular CLI and the Angular framework (updated in previous steps):
|
||||
- In the [shared/boilerplate/cli/](./shared/boilerplate/cli) directory, run the following commands to migrate the the project to the current versions of Angular CLI and the Angular framework (updated in previous steps):
|
||||
```sh
|
||||
# Ensure dependencies are installed.
|
||||
yarn install
|
||||
@ -38,8 +38,11 @@ Any necessary changes to boilerplate files will be done automatically through mi
|
||||
> In order for `ng update` to work, there must be a `node_modules/` directory with installed dependencies inside the [shared/boilerplate/cli/](./shared/boilerplate/cli) directory.
|
||||
> This `node_modules/` directory is only needed during the update operation and is otherwise ignored (both by git and by the [example-boilerplate.js](./example-boilerplate.js) script) by means of the [shared/boilerplate/.gitignore](./shared/boilerplate/.gitignore) file.
|
||||
|
||||
- The previous command made any necessary changes to boilerplate files inside the `cli/` folder, but the same changes need to be applied to the other CLI-based boilerplate folders.
|
||||
Inspect the changes in `cli/` and manually apply the necessary ones to other CLI-based boilerplate folders.
|
||||
- The previous command made any necessary changes to boilerplate files inside the `cli/` directory, but the same changes need to be applied to the other CLI-based boilerplate directories.
|
||||
Inspect the changes in `cli/` and manually apply the necessary ones to other CLI-based boilerplate directories.
|
||||
|
||||
- Also ensure that any relevant changes in the [shared/boilerplate/cli/](./shared/boilerplate/cli) directory are copied to the [shared/example-scaffold/](./shared/example-scaffold) directory, which is used when creating new examples (via `yarn create-example ...`).
|
||||
Only files that would not be considered boilerplate should be added to the `example-scaffold/` directory.
|
||||
|
||||
- Ensure any changes to [cli/tslint.json](./shared/boilerplate/cli/tslint.json) are ported over to [systemjs/tslint.json](./shared/boilerplate/systemjs/tslint.json) and also [aio/content/examples/tslint.json](../../content/examples/tslint.json).
|
||||
This last part is important, since this file is used to lint example code on CI.
|
||||
|
6
aio/tools/examples/constants.js
Normal file
6
aio/tools/examples/constants.js
Normal file
@ -0,0 +1,6 @@
|
||||
const path = require('canonical-path');
|
||||
|
||||
exports.EXAMPLES_BASE_PATH = path.resolve(__dirname, '../../content/examples');
|
||||
exports.EXAMPLE_CONFIG_FILENAME = 'example-config.json';
|
||||
exports.SHARED_PATH = path.resolve(__dirname, 'shared');
|
||||
exports.STACKBLITZ_CONFIG_FILENAME = 'stackblitz.json';
|
140
aio/tools/examples/create-example.js
Normal file
140
aio/tools/examples/create-example.js
Normal file
@ -0,0 +1,140 @@
|
||||
const fs = require('fs-extra');
|
||||
const glob = require('glob');
|
||||
const ignore = require('ignore');
|
||||
const path = require('canonical-path');
|
||||
const shelljs = require('shelljs');
|
||||
const yargs = require('yargs');
|
||||
|
||||
const {EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, SHARED_PATH, STACKBLITZ_CONFIG_FILENAME} =
|
||||
require('./constants');
|
||||
const BASIC_SOURCE_PATH = path.resolve(SHARED_PATH, 'example-scaffold');
|
||||
|
||||
shelljs.set('-e');
|
||||
|
||||
if (require.main === module) {
|
||||
const options =
|
||||
yargs(process.argv.slice(2))
|
||||
.command(
|
||||
'$0 <name> [source]',
|
||||
[
|
||||
'Create a new <name> example.',
|
||||
'',
|
||||
'If [source] is provided then the relevant files from the CLI project at that path are copied into the example.',
|
||||
].join('\n'))
|
||||
.strict()
|
||||
.version(false)
|
||||
.argv;
|
||||
|
||||
const exampleName = options.name;
|
||||
const examplePath = path.resolve(EXAMPLES_BASE_PATH, exampleName);
|
||||
|
||||
console.log('Creating new example at', examplePath);
|
||||
createEmptyExample(exampleName, examplePath);
|
||||
|
||||
const sourcePath =
|
||||
options.source !== undefined ? path.resolve(options.source) : BASIC_SOURCE_PATH;
|
||||
console.log('Copying files from', sourcePath);
|
||||
copyExampleFiles(sourcePath, examplePath, exampleName);
|
||||
|
||||
console.log(`The new "${exampleName}" example has been created.`);
|
||||
console.log('Now run "yarn boilerplate:add" to set it up for development.');
|
||||
console.log(
|
||||
'You can find more info on working with docs examples in aio/tools/examples/README.md.')
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the directory and marker files for the new example.
|
||||
*/
|
||||
function createEmptyExample(exampleName, examplePath) {
|
||||
ensureExamplePath(examplePath);
|
||||
writeExampleConfigFile(examplePath);
|
||||
writeStackBlitzFile(exampleName, examplePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the new example directory exists.
|
||||
*/
|
||||
function ensureExamplePath(examplePath) {
|
||||
if (fs.existsSync(examplePath)) {
|
||||
throw new Error(
|
||||
`Unable to create example. The path to the new example already exists: ${examplePath}`);
|
||||
}
|
||||
fs.ensureDirSync(examplePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the `example-config.json` file to the new example.
|
||||
*/
|
||||
function writeExampleConfigFile(examplePath) {
|
||||
fs.writeFileSync(path.resolve(examplePath, EXAMPLE_CONFIG_FILENAME), '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the `stackblitz.json` file into the new example.
|
||||
*/
|
||||
function writeStackBlitzFile(exampleName, examplePath) {
|
||||
const config = {
|
||||
description: titleize(exampleName),
|
||||
files: ['!**/*.d.ts', '!**/*.js', '!**/*.[1,2].*'],
|
||||
tags: [exampleName.split('-')]
|
||||
};
|
||||
fs.writeFileSync(
|
||||
path.resolve(examplePath, STACKBLITZ_CONFIG_FILENAME),
|
||||
JSON.stringify(config, null, 2) + '\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all the files from the `sourcePath`, which are not ignored by the `.gitignore` file in the
|
||||
* `EXAMPLES_BASE_PATH`, to the `examplePath`.
|
||||
*/
|
||||
function copyExampleFiles(sourcePath, examplePath, exampleName) {
|
||||
const gitIgnoreSource = getGitIgnore(sourcePath);
|
||||
const gitIgnoreExamples = getGitIgnore(EXAMPLES_BASE_PATH);
|
||||
|
||||
// Grab the files in the source folder and filter them based on the gitignore rules.
|
||||
const sourceFiles =
|
||||
glob.sync('**/*', {
|
||||
cwd: sourcePath,
|
||||
dot: true,
|
||||
ignore: ['**/node_modules/**', '.git/**', '.gitignore'],
|
||||
mark: true
|
||||
})
|
||||
// Filter out the directories, leaving only files
|
||||
.filter(filePath => !/\/$/.test(filePath))
|
||||
// Filter out files that match the source directory .gitignore rules
|
||||
.filter(filePath => !gitIgnoreSource.ignores(filePath))
|
||||
// Filter out files that match the examples directory .gitignore rules
|
||||
.filter(filePath => !gitIgnoreExamples.ignores(path.join(exampleName, filePath)));
|
||||
|
||||
for (const sourceFile of sourceFiles) {
|
||||
console.log(' - ', sourceFile);
|
||||
const destPath = path.resolve(examplePath, sourceFile)
|
||||
fs.ensureDirSync(path.dirname(destPath));
|
||||
fs.copySync(path.resolve(sourcePath, sourceFile), destPath);
|
||||
}
|
||||
}
|
||||
|
||||
function getGitIgnore(directory) {
|
||||
const gitIgnoreMatcher = ignore();
|
||||
const gitignoreFilePath = path.resolve(directory, '.gitignore');
|
||||
if (fs.existsSync(gitignoreFilePath)) {
|
||||
const gitignoreFile = fs.readFileSync(gitignoreFilePath, 'utf8');
|
||||
gitIgnoreMatcher.add(gitignoreFile);
|
||||
}
|
||||
return gitIgnoreMatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a kebab-case string to space separated Title Case string.
|
||||
*/
|
||||
function titleize(input) {
|
||||
return input.replace(
|
||||
/(-|^)(.)/g, (_, pre, char) => `${pre === '-' ? ' ' : ''}${char.toUpperCase()}`);
|
||||
}
|
||||
|
||||
exports.createEmptyExample = createEmptyExample;
|
||||
exports.ensureExamplePath = ensureExamplePath;
|
||||
exports.writeExampleConfigFile = writeExampleConfigFile;
|
||||
exports.writeStackBlitzFile = writeStackBlitzFile;
|
||||
exports.copyExampleFiles = copyExampleFiles;
|
||||
exports.titleize = titleize;
|
130
aio/tools/examples/create-example.spec.js
Normal file
130
aio/tools/examples/create-example.spec.js
Normal file
@ -0,0 +1,130 @@
|
||||
const path = require('canonical-path');
|
||||
const fs = require('fs-extra');
|
||||
const {glob} = require('glob');
|
||||
|
||||
const {EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, SHARED_PATH, STACKBLITZ_CONFIG_FILENAME} =
|
||||
require('./constants');
|
||||
|
||||
const {
|
||||
copyExampleFiles,
|
||||
createEmptyExample,
|
||||
ensureExamplePath,
|
||||
titleize,
|
||||
writeExampleConfigFile,
|
||||
writeStackBlitzFile
|
||||
} = require('./create-example');
|
||||
|
||||
describe('create-example tool', () => {
|
||||
describe('createEmptyExample', () => {
|
||||
it('should create an empty example with marker files', () => {
|
||||
spyOn(fs, 'existsSync').and.returnValue(false);
|
||||
spyOn(fs, 'ensureDirSync');
|
||||
const writeFileSpy = spyOn(fs, 'writeFileSync');
|
||||
|
||||
createEmptyExample('foo-bar', '/path/to/foo-bar');
|
||||
expect(writeFileSpy).toHaveBeenCalledTimes(2);
|
||||
expect(writeFileSpy)
|
||||
.toHaveBeenCalledWith(`/path/to/foo-bar/${EXAMPLE_CONFIG_FILENAME}`, jasmine.any(String));
|
||||
expect(writeFileSpy)
|
||||
.toHaveBeenCalledWith(
|
||||
`/path/to/foo-bar/${STACKBLITZ_CONFIG_FILENAME}`, jasmine.any(String));
|
||||
});
|
||||
});
|
||||
|
||||
describe('ensureExamplePath', () => {
|
||||
it('should error if the path already exists', () => {
|
||||
spyOn(fs, 'existsSync').and.returnValue(true);
|
||||
expect(() => ensureExamplePath('foo/bar'))
|
||||
.toThrowError(
|
||||
`Unable to create example. The path to the new example already exists: foo/bar`);
|
||||
});
|
||||
|
||||
it('should create the directory on disk', () => {
|
||||
spyOn(fs, 'existsSync').and.returnValue(false);
|
||||
const spy = spyOn(fs, 'ensureDirSync');
|
||||
ensureExamplePath('foo/bar');
|
||||
expect(spy).toHaveBeenCalledWith('foo/bar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('writeExampleConfigFile', () => {
|
||||
it('should write a JSON file to disk', () => {
|
||||
const spy = spyOn(fs, 'writeFileSync');
|
||||
writeExampleConfigFile('/foo/bar');
|
||||
expect(spy).toHaveBeenCalledWith(`/foo/bar/${EXAMPLE_CONFIG_FILENAME}`, '');
|
||||
});
|
||||
});
|
||||
|
||||
describe('writeStackBlitzFile', () => {
|
||||
it('should write a JSON file to disk', () => {
|
||||
const spy = spyOn(fs, 'writeFileSync');
|
||||
writeStackBlitzFile('bar-bar', '/foo/bar-bar');
|
||||
expect(spy).toHaveBeenCalledWith(`/foo/bar-bar/${STACKBLITZ_CONFIG_FILENAME}`, [
|
||||
'{',
|
||||
' "description": "Bar Bar",',
|
||||
' "files": [',
|
||||
' "!**/*.d.ts",',
|
||||
' "!**/*.js",',
|
||||
' "!**/*.[1,2].*"',
|
||||
' ],',
|
||||
' "tags": [',
|
||||
' [',
|
||||
' "bar",',
|
||||
' "bar"',
|
||||
' ]',
|
||||
' ]',
|
||||
'}',
|
||||
'',
|
||||
].join('\n'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('copyExampleFiles', () => {
|
||||
it('should copy over files that are not ignored by git', () => {
|
||||
const examplesGitIgnorePath = path.resolve(EXAMPLES_BASE_PATH, '.gitignore');
|
||||
const sourceGitIgnorePath = path.resolve('/source/path', '.gitignore');
|
||||
|
||||
spyOn(console, 'log');
|
||||
spyOn(fs, 'existsSync').and.returnValue(true);
|
||||
const readFileSyncSpy = spyOn(fs, 'readFileSync').and.callFake(p => {
|
||||
switch (p) {
|
||||
case examplesGitIgnorePath:
|
||||
return '**/a/b/**';
|
||||
case sourceGitIgnorePath:
|
||||
return '**/*.bad';
|
||||
default:
|
||||
throw new Error('Unexpected path');
|
||||
}
|
||||
});
|
||||
spyOn(glob, 'sync').and.returnValue([
|
||||
'a/', 'a/b/', 'a/c', 'x.ts', 'x.bad', 'a/b/y.ts', 'a/b/y.bad'
|
||||
]);
|
||||
const ensureDirSyncSpy = spyOn(fs, 'ensureDirSync');
|
||||
const copySyncSpy = spyOn(fs, 'copySync');
|
||||
|
||||
copyExampleFiles('/source/path', '/path/to/test-example', 'test-example');
|
||||
|
||||
expect(readFileSyncSpy).toHaveBeenCalledWith(examplesGitIgnorePath, 'utf8');
|
||||
expect(readFileSyncSpy).toHaveBeenCalledWith(sourceGitIgnorePath, 'utf8');
|
||||
|
||||
expect(ensureDirSyncSpy.calls.allArgs()).toEqual([
|
||||
['/path/to/test-example/a'],
|
||||
['/path/to/test-example'],
|
||||
]);
|
||||
|
||||
expect(copySyncSpy.calls.allArgs()).toEqual([
|
||||
['/source/path/a/c', '/path/to/test-example/a/c'],
|
||||
['/source/path/x.ts', '/path/to/test-example/x.ts'],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('titleize', () => {
|
||||
it('should convert a kebab-case string to title-case', () => {
|
||||
expect(titleize('abc')).toEqual('Abc');
|
||||
expect(titleize('abc-def')).toEqual('Abc Def');
|
||||
expect(titleize('123')).toEqual('123');
|
||||
expect(titleize('abc---def')).toEqual('Abc - Def');
|
||||
});
|
||||
});
|
||||
});
|
@ -4,8 +4,8 @@ const ignore = require('ignore');
|
||||
const path = require('canonical-path');
|
||||
const shelljs = require('shelljs');
|
||||
const yargs = require('yargs');
|
||||
const {EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, SHARED_PATH} = require('./constants');
|
||||
|
||||
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');
|
||||
@ -13,9 +13,6 @@ const BOILERPLATE_CLI_PATH = path.resolve(BOILERPLATE_BASE_PATH, 'cli');
|
||||
const BOILERPLATE_COMMON_PATH = path.resolve(BOILERPLATE_BASE_PATH, 'common');
|
||||
const BOILERPLATE_VIEWENGINE_PATH = path.resolve(BOILERPLATE_BASE_PATH, 'viewengine');
|
||||
|
||||
const EXAMPLES_BASE_PATH = path.resolve(__dirname, '../../content/examples');
|
||||
const EXAMPLE_CONFIG_FILENAME = 'example-config.json';
|
||||
|
||||
class ExampleBoilerPlate {
|
||||
/**
|
||||
* Add boilerplate files to all the examples
|
||||
|
@ -14,5 +14,4 @@ last 2 Edge major versions
|
||||
last 2 Safari major versions
|
||||
last 2 iOS major versions
|
||||
Firefox ESR
|
||||
not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line.
|
||||
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
|
||||
|
@ -18,7 +18,7 @@
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
/** IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/**
|
||||
|
@ -18,7 +18,7 @@
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
/** IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/**
|
||||
|
@ -22,7 +22,7 @@ import '@angular/localize/init';
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
/** IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,20 @@
|
||||
import { AppPage } from './app.po';
|
||||
import { browser, logging } from 'protractor';
|
||||
|
||||
describe('workspace-project App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
// Add your e2e tests here
|
||||
|
||||
afterEach(async () => {
|
||||
// Assert that there are no errors emitted from the browser
|
||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||
expect(logs).not.toContain(jasmine.objectContaining({
|
||||
level: logging.Level.SEVERE,
|
||||
} as logging.Entry));
|
||||
});
|
||||
});
|
@ -0,0 +1 @@
|
||||
<h1>Replace the src folder in this {{title}} with yours.</h1>
|
@ -0,0 +1,20 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
// Add your unit tests here
|
||||
});
|
@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css'],
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'example';
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
13
aio/tools/examples/shared/example-scaffold/src/index.html
Normal file
13
aio/tools/examples/shared/example-scaffold/src/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Ponyracer</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
12
aio/tools/examples/shared/example-scaffold/src/main.ts
Normal file
12
aio/tools/examples/shared/example-scaffold/src/main.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
@ -76,7 +76,7 @@
|
||||
"lite-server": "^2.2.2",
|
||||
"lodash": "^4.16.2",
|
||||
"protractor": "~7.0.0",
|
||||
"puppeteer": "3.3.0",
|
||||
"puppeteer": "5.1.0",
|
||||
"rimraf": "^2.5.4",
|
||||
"rollup": "^1.1.0",
|
||||
"rollup-plugin-commonjs": "^9.2.1",
|
||||
|
@ -4336,6 +4336,11 @@ dev-ip@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0"
|
||||
|
||||
devtools-protocol@0.0.767361:
|
||||
version "0.0.767361"
|
||||
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.767361.tgz#5977f2558b84f9df36f62501bdddb82f3ae7b66b"
|
||||
integrity sha512-ziRTdhEVQ9jEwedaUaXZ7kl9w9TF/7A3SXQ0XuqrJB+hMS62POHZUWTbumDN2ehRTfvWqTPc2Jw4gUl/jggmHA==
|
||||
|
||||
dezalgo@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456"
|
||||
@ -7704,6 +7709,11 @@ mitt@^1.1.3:
|
||||
resolved "https://registry.yarnpkg.com/mitt/-/mitt-1.2.0.tgz#cb24e6569c806e31bd4e3995787fe38a04fdf90d"
|
||||
integrity sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==
|
||||
|
||||
mitt@^2.0.1:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mitt/-/mitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230"
|
||||
integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==
|
||||
|
||||
mixin-deep@^1.2.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.0.tgz#47a8732ba97799457c8c1eca28f95132d7e8150a"
|
||||
@ -8759,7 +8769,7 @@ pkg-dir@^3.0.0:
|
||||
dependencies:
|
||||
find-up "^3.0.0"
|
||||
|
||||
pkg-dir@^4.1.0:
|
||||
pkg-dir@^4.1.0, pkg-dir@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
|
||||
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
|
||||
@ -9363,15 +9373,18 @@ punycode@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
puppeteer@3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-3.3.0.tgz#95839af9fdc0aa4de7e5ee073a4c0adeb9e2d3d7"
|
||||
integrity sha512-23zNqRltZ1PPoK28uRefWJ/zKb5Jhnzbbwbpcna2o5+QMn17F0khq5s1bdH3vPlyj+J36pubccR8wiNA/VE0Vw==
|
||||
puppeteer@5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-5.1.0.tgz#e7bae2caa6e3a13a622755e4c27689d9812c38ca"
|
||||
integrity sha512-IZBFG8XcA+oHxYo5rEpJI/HQignUis2XPijPoFpNxla2O+WufonGsUsSqrhRXgBKOME5zNfhRdUY2LvxAiKlhw==
|
||||
dependencies:
|
||||
debug "^4.1.0"
|
||||
devtools-protocol "0.0.767361"
|
||||
extract-zip "^2.0.0"
|
||||
https-proxy-agent "^4.0.0"
|
||||
mime "^2.0.3"
|
||||
mitt "^2.0.1"
|
||||
pkg-dir "^4.2.0"
|
||||
progress "^2.0.1"
|
||||
proxy-from-env "^1.0.0"
|
||||
rimraf "^3.0.2"
|
||||
|
@ -132,11 +132,11 @@
|
||||
<summary>
|
||||
<div class="icon-action-header">
|
||||
<h4 class="no-anchor">{$ method.overloads.length $} overloads...</h4>
|
||||
<a>
|
||||
<span class="actions">
|
||||
<span class="show-all">Show All</span>
|
||||
<span class="collapse-all">Hide All</span>
|
||||
<i class="material-icons expand">expand_more</i>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</summary>
|
||||
<div class="detail-contents">
|
||||
|
178
aio/yarn.lock
178
aio/yarn.lock
@ -3075,11 +3075,6 @@ camelcase@^2.0.1:
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
|
||||
integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
|
||||
|
||||
camelcase@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
|
||||
integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo=
|
||||
|
||||
camelcase@^4.0.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
|
||||
@ -3459,7 +3454,7 @@ cli-width@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
|
||||
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
|
||||
|
||||
cliui@^3.0.3, cliui@^3.2.0:
|
||||
cliui@^3.0.3:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
|
||||
integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=
|
||||
@ -3495,6 +3490,15 @@ cliui@^6.0.0:
|
||||
strip-ansi "^6.0.0"
|
||||
wrap-ansi "^6.2.0"
|
||||
|
||||
cliui@^7.0.2:
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.2.tgz#e3a412e1d5ec0ccbe50d1b4120fc8164e97881f4"
|
||||
integrity sha512-lhpKkuUj67j5JgZIPZxLe7nSa4MQoojzRVWQyzMqBp2hBg6gwRjUDAwC1YDeBaC3APDBKNnjWbv2mlDF4XgOSA==
|
||||
dependencies:
|
||||
string-width "^4.2.0"
|
||||
strip-ansi "^6.0.0"
|
||||
wrap-ansi "^7.0.0"
|
||||
|
||||
clone@^1.0.2:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
|
||||
@ -4509,6 +4513,11 @@ detect-node@^2.0.4:
|
||||
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
|
||||
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
|
||||
|
||||
devtools-protocol@0.0.767361:
|
||||
version "0.0.767361"
|
||||
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.767361.tgz#5977f2558b84f9df36f62501bdddb82f3ae7b66b"
|
||||
integrity sha512-ziRTdhEVQ9jEwedaUaXZ7kl9w9TF/7A3SXQ0XuqrJB+hMS62POHZUWTbumDN2ehRTfvWqTPc2Jw4gUl/jggmHA==
|
||||
|
||||
dezalgo@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456"
|
||||
@ -4900,7 +4909,7 @@ errno@^0.1.1, errno@^0.1.3, errno@~0.1.7:
|
||||
dependencies:
|
||||
prr "~1.0.1"
|
||||
|
||||
error-ex@^1.2.0, error-ex@^1.3.1:
|
||||
error-ex@^1.3.1:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
|
||||
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
|
||||
@ -5012,6 +5021,11 @@ es6-weak-map@^2.0.1, es6-weak-map@^2.0.2:
|
||||
es6-iterator "^2.0.3"
|
||||
es6-symbol "^3.1.1"
|
||||
|
||||
escalade@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
||||
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
|
||||
|
||||
escape-html@~1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||
@ -5578,14 +5592,6 @@ find-free-port@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/find-free-port/-/find-free-port-2.0.0.tgz#4b22e5f6579eb1a38c41ac6bcb3efed1b6da9b1b"
|
||||
integrity sha1-SyLl9leesaOMQaxryz7+0bbamxs=
|
||||
|
||||
find-up@^1.0.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
|
||||
integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
|
||||
dependencies:
|
||||
path-exists "^2.0.0"
|
||||
pinkie-promise "^2.0.0"
|
||||
|
||||
find-up@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
|
||||
@ -5920,7 +5926,7 @@ get-caller-file@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
|
||||
integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
|
||||
|
||||
get-caller-file@^2.0.1:
|
||||
get-caller-file@^2.0.1, get-caller-file@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
||||
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
||||
@ -7369,11 +7375,6 @@ is-url@^1.2.2:
|
||||
resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52"
|
||||
integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==
|
||||
|
||||
is-utf8@^0.2.0:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
|
||||
integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
|
||||
|
||||
is-whitespace-character@^1.0.0:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7"
|
||||
@ -8132,17 +8133,6 @@ listenercount@~1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937"
|
||||
integrity sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=
|
||||
|
||||
load-json-file@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
|
||||
integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
parse-json "^2.2.0"
|
||||
pify "^2.0.0"
|
||||
pinkie-promise "^2.0.0"
|
||||
strip-bom "^2.0.0"
|
||||
|
||||
load-json-file@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
|
||||
@ -8926,6 +8916,11 @@ mississippi@^3.0.0:
|
||||
stream-each "^1.1.0"
|
||||
through2 "^2.0.0"
|
||||
|
||||
mitt@^2.0.1:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mitt/-/mitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230"
|
||||
integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==
|
||||
|
||||
mixin-deep@^1.2.0:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
|
||||
@ -9814,13 +9809,6 @@ parse-entities@^1.0.2, parse-entities@^1.1.0:
|
||||
is-decimal "^1.0.0"
|
||||
is-hexadecimal "^1.0.0"
|
||||
|
||||
parse-json@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
|
||||
integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
|
||||
dependencies:
|
||||
error-ex "^1.2.0"
|
||||
|
||||
parse-json@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
|
||||
@ -9900,13 +9888,6 @@ path-dirname@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
|
||||
integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
|
||||
|
||||
path-exists@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
|
||||
integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
|
||||
dependencies:
|
||||
pinkie-promise "^2.0.0"
|
||||
|
||||
path-exists@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
|
||||
@ -9949,15 +9930,6 @@ path-to-regexp@^1.7.0:
|
||||
dependencies:
|
||||
isarray "0.0.1"
|
||||
|
||||
path-type@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
|
||||
integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
pify "^2.0.0"
|
||||
pinkie-promise "^2.0.0"
|
||||
|
||||
path-type@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
|
||||
@ -10040,7 +10012,7 @@ pkg-dir@^3.0.0:
|
||||
dependencies:
|
||||
find-up "^3.0.0"
|
||||
|
||||
pkg-dir@^4.1.0:
|
||||
pkg-dir@^4.1.0, pkg-dir@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
|
||||
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
|
||||
@ -10695,15 +10667,18 @@ punycode@^2.1.0, punycode@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
puppeteer@3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-3.3.0.tgz#95839af9fdc0aa4de7e5ee073a4c0adeb9e2d3d7"
|
||||
integrity sha512-23zNqRltZ1PPoK28uRefWJ/zKb5Jhnzbbwbpcna2o5+QMn17F0khq5s1bdH3vPlyj+J36pubccR8wiNA/VE0Vw==
|
||||
puppeteer@5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-5.1.0.tgz#e7bae2caa6e3a13a622755e4c27689d9812c38ca"
|
||||
integrity sha512-IZBFG8XcA+oHxYo5rEpJI/HQignUis2XPijPoFpNxla2O+WufonGsUsSqrhRXgBKOME5zNfhRdUY2LvxAiKlhw==
|
||||
dependencies:
|
||||
debug "^4.1.0"
|
||||
devtools-protocol "0.0.767361"
|
||||
extract-zip "^2.0.0"
|
||||
https-proxy-agent "^4.0.0"
|
||||
mime "^2.0.3"
|
||||
mitt "^2.0.1"
|
||||
pkg-dir "^4.2.0"
|
||||
progress "^2.0.1"
|
||||
proxy-from-env "^1.0.0"
|
||||
rimraf "^3.0.2"
|
||||
@ -10859,23 +10834,6 @@ read-package-tree@5.3.1:
|
||||
readdir-scoped-modules "^1.0.0"
|
||||
util-promisify "^2.1.0"
|
||||
|
||||
read-pkg-up@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
|
||||
integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
|
||||
dependencies:
|
||||
find-up "^1.0.0"
|
||||
read-pkg "^1.0.0"
|
||||
|
||||
read-pkg@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
|
||||
integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
|
||||
dependencies:
|
||||
load-json-file "^1.0.0"
|
||||
normalize-package-data "^2.3.2"
|
||||
path-type "^1.0.0"
|
||||
|
||||
read-pkg@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
|
||||
@ -12368,7 +12326,7 @@ string-length@^1.0.0:
|
||||
dependencies:
|
||||
strip-ansi "^3.0.0"
|
||||
|
||||
string-width@^1.0.1, string-width@^1.0.2:
|
||||
string-width@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
|
||||
integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
|
||||
@ -12500,13 +12458,6 @@ strip-ansi@^6.0.0:
|
||||
dependencies:
|
||||
ansi-regex "^5.0.0"
|
||||
|
||||
strip-bom@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
|
||||
integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
|
||||
dependencies:
|
||||
is-utf8 "^0.2.0"
|
||||
|
||||
strip-bom@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
|
||||
@ -13997,11 +13948,6 @@ when@~3.6.x:
|
||||
resolved "https://registry.yarnpkg.com/when/-/when-3.6.4.tgz#473b517ec159e2b85005497a13983f095412e34e"
|
||||
integrity sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=
|
||||
|
||||
which-module@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
|
||||
integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=
|
||||
|
||||
which-module@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
|
||||
@ -14101,6 +14047,15 @@ wrap-ansi@^6.2.0:
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
dependencies:
|
||||
ansi-styles "^4.0.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
@ -14233,7 +14188,7 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1:
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
||||
|
||||
y18n@^3.2.0, y18n@^3.2.1:
|
||||
y18n@^3.2.0:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
|
||||
integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
|
||||
@ -14243,6 +14198,11 @@ y18n@^3.2.0, y18n@^3.2.1:
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
|
||||
integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
|
||||
|
||||
y18n@^5.0.2:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.3.tgz#978115b82befe2b5c762bf55980b7b01a4a2d5d9"
|
||||
integrity sha512-JeFbcHQ/7hVmMBXW6UB6Tg7apStHd/ztGz1JN78y3pFi/q0Ht1eA6PVkvw56gm7UA8fcJR/ziRlYEDMGoju0yQ==
|
||||
|
||||
yallist@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||
@ -14282,12 +14242,10 @@ yargs-parser@^18.1.0, yargs-parser@^18.1.1, yargs-parser@^18.1.3:
|
||||
camelcase "^5.0.0"
|
||||
decamelize "^1.2.0"
|
||||
|
||||
yargs-parser@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"
|
||||
integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=
|
||||
dependencies:
|
||||
camelcase "^3.0.0"
|
||||
yargs-parser@^20.2.2:
|
||||
version "20.2.2"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.2.tgz#84562c6b1c41ccec2f13d346c7dd83f8d1a0dc70"
|
||||
integrity sha512-XmrpXaTl6noDsf1dKpBuUNCOHqjs0g3jRMXf/ztRxdOmb+er8kE5z5b55Lz3p5u2T8KJ59ENBnASS8/iapVJ5g==
|
||||
|
||||
yargs@15.3.0:
|
||||
version "15.3.0"
|
||||
@ -14370,24 +14328,18 @@ yargs@^15.3.1:
|
||||
y18n "^4.0.0"
|
||||
yargs-parser "^18.1.1"
|
||||
|
||||
yargs@^7.0.2:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"
|
||||
integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=
|
||||
yargs@^16.1.0:
|
||||
version "16.1.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.1.0.tgz#fc333fe4791660eace5a894b39d42f851cd48f2a"
|
||||
integrity sha512-upWFJOmDdHN0syLuESuvXDmrRcWd1QafJolHskzaw79uZa7/x53gxQKiR07W59GWY1tFhhU/Th9DrtSfpS782g==
|
||||
dependencies:
|
||||
camelcase "^3.0.0"
|
||||
cliui "^3.2.0"
|
||||
decamelize "^1.1.1"
|
||||
get-caller-file "^1.0.1"
|
||||
os-locale "^1.4.0"
|
||||
read-pkg-up "^1.0.1"
|
||||
cliui "^7.0.2"
|
||||
escalade "^3.1.1"
|
||||
get-caller-file "^2.0.5"
|
||||
require-directory "^2.1.1"
|
||||
require-main-filename "^1.0.1"
|
||||
set-blocking "^2.0.0"
|
||||
string-width "^1.0.2"
|
||||
which-module "^1.0.0"
|
||||
y18n "^3.2.1"
|
||||
yargs-parser "^5.0.0"
|
||||
string-width "^4.2.0"
|
||||
y18n "^5.0.2"
|
||||
yargs-parser "^20.2.2"
|
||||
|
||||
yauzl@^2.10.0:
|
||||
version "2.10.0"
|
||||
|
@ -1,5 +1,5 @@
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm")
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "cli",
|
||||
@ -49,7 +49,7 @@ pkg_npm(
|
||||
# substitutions to replace these in the published version of dev-infra.
|
||||
"//dev-infra/": "@npm_angular_dev_infra_private//",
|
||||
"//packages/benchpress": "@npm//@angular/benchpress",
|
||||
"//packages/bazel/": "@npm_angular_bazel//",
|
||||
"//packages/bazel": "@npm//@angular/bazel",
|
||||
"//packages/zone.js/bundles:zone.umd.js": "@npm//:node_modules/zone.js/dist/zone.js",
|
||||
"//packages/core": "@npm//@angular/core",
|
||||
"//packages/platform-browser": "@npm//@angular/platform-browser",
|
||||
@ -57,7 +57,7 @@ pkg_npm(
|
||||
# This substitution is particularly verbose because we need to make sure
|
||||
# that only things available via Angular Bazel are imported from
|
||||
# tools/defaults.bzl.
|
||||
"load\(\"//tools:defaults.bzl\", \"ng_module\"\)": "load(\"@npm_angular_bazel//:index.bzl\", \"ng_module\")",
|
||||
"load\(\"//tools:defaults.bzl\", \"ng_module\"\)": "load(\"@npm//@angular/bazel:index.bzl\", \"ng_module\")",
|
||||
},
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_protractor//:index.bzl", "protractor_web_test_suite")
|
||||
load("@npm//@bazel/protractor:index.bzl", "protractor_web_test_suite")
|
||||
|
||||
"""
|
||||
Macro that can be used to define a benchmark test. This differentiates from
|
||||
|
@ -1,6 +1,6 @@
|
||||
load("//dev-infra/benchmark/ng_rollup_bundle:ng_rollup_bundle.bzl", "ng_rollup_bundle")
|
||||
load("//tools:defaults.bzl", "ng_module")
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_devserver", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_devserver", "ts_library")
|
||||
load(":benchmark_test.bzl", "benchmark_test")
|
||||
|
||||
def copy_default_file(origin, destination):
|
||||
|
@ -1,6 +1,6 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "driver-utilities",
|
||||
|
@ -4,8 +4,8 @@
|
||||
# found in the LICENSE file at https://angular.io/license
|
||||
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "npm_package_bin")
|
||||
load("@npm_bazel_terser//:index.bzl", "terser_minified")
|
||||
load("@npm_bazel_rollup//:index.bzl", "rollup_bundle")
|
||||
load("@npm//@bazel/terser:index.bzl", "terser_minified")
|
||||
load("@npm//@bazel/rollup:index.bzl", "rollup_bundle")
|
||||
load("//dev-infra/bazel:expand_template.bzl", "expand_template")
|
||||
|
||||
def ng_rollup_bundle(
|
||||
|
@ -12,47 +12,47 @@ def define_chromium_repositories():
|
||||
platform_http_file(
|
||||
name = "org_chromium_chromium_amd64",
|
||||
licenses = ["notice"], # BSD 3-clause (maybe more?)
|
||||
sha256 = "2cfd74ee58c79d8b7aada05c899a930967e2fd8bb0186582cde02c7340863f64",
|
||||
# 83.0.4103
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/756066/chrome-linux.zip"],
|
||||
sha256 = "0e303931d9c3e065a160f5d31f1178c647f0748fb0b58b1945b84b04fe1c1165",
|
||||
# 84.0.4147
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/768968/chrome-linux.zip"],
|
||||
)
|
||||
|
||||
platform_http_file(
|
||||
name = "org_chromium_chromium_macos",
|
||||
licenses = ["notice"], # BSD 3-clause (maybe more?)
|
||||
sha256 = "b841ec5ad03b08422d97593fc719f1c5b038703388ad65e6cd8cc8272d58958c",
|
||||
# 83.0.4103
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/756053/chrome-mac.zip"],
|
||||
sha256 = "39118c96db1b3fdb0129f434912a329c5ca07d3a1c6c6cda673d3383d83e2f9a",
|
||||
# 84.0.4147
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/768968/chrome-mac.zip"],
|
||||
)
|
||||
|
||||
platform_http_file(
|
||||
name = "org_chromium_chromium_windows",
|
||||
licenses = ["notice"], # BSD 3-clause (maybe more?)
|
||||
sha256 = "4683d7ac88dfec4b98d1da3012ecc8e42cc8c1a560a7b95589ad4cc96bf90fcb",
|
||||
# 83.0.4103
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Win/756065/chrome-win.zip"],
|
||||
sha256 = "3429746fa80c917c6f4d5d96aba4e58894b905a2b8392e43ddb470c5ba612d60",
|
||||
# 84.0.4147
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Win/768975/chrome-win.zip"],
|
||||
)
|
||||
|
||||
platform_http_file(
|
||||
name = "org_chromium_chromedriver_amd64",
|
||||
licenses = ["reciprocal"], # BSD 3-clause, ICU, MPL 1.1, libpng (BSD/MIT-like), Academic Free License v. 2.0, BSD 2-clause, MIT
|
||||
sha256 = "95dded16000b82e31445361da7d251ed707e027a4b61e9a3ec5fbd1cc2f62bb1",
|
||||
# 83.0.4103
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/756066/chromedriver_linux64.zip"],
|
||||
sha256 = "f6b9852031d185739a2c1816508fe8158eb92782d13e831b8345957ef2506fe8",
|
||||
# 84.0.4147
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/768968/chromedriver_linux64.zip"],
|
||||
)
|
||||
|
||||
platform_http_file(
|
||||
name = "org_chromium_chromedriver_macos",
|
||||
licenses = ["reciprocal"], # BSD 3-clause, ICU, MPL 1.1, libpng (BSD/MIT-like), Academic Free License v. 2.0, BSD 2-clause, MIT
|
||||
sha256 = "17260e9b2222b0c905a1861285210192baef830f4281778903e7cebb8db683cc",
|
||||
# 83.0.4103
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/756053/chromedriver_mac64.zip"],
|
||||
sha256 = "aa0124085146556d5d32ad172670e5dcef79b7429380112ad02898047ba7a8b7",
|
||||
# 84.0.4147
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/768968/chromedriver_mac64.zip"],
|
||||
)
|
||||
|
||||
platform_http_file(
|
||||
name = "org_chromium_chromedriver_windows",
|
||||
licenses = ["reciprocal"], # BSD 3-clause, ICU, MPL 1.1, libpng (BSD/MIT-like), Academic Free License v. 2.0, BSD 2-clause, MIT
|
||||
sha256 = "de1423b2d69f96e451e902d686e8d471610d786c345a8de59dd1a5a436e45fc2",
|
||||
# 83.0.4103
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Win/756065/chromedriver_win32.zip"],
|
||||
sha256 = "c4b04fd263e757d3aa99c596832f2c414f9f00e80d2769590e2b9044072b140e",
|
||||
# 84.0.4147
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Win/768975/chromedriver_win32.zip"],
|
||||
)
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "caretaker",
|
||||
|
@ -35,31 +35,17 @@ export async function printG3Comparison(git: GitClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** Random prefix to create unique branch names. */
|
||||
const randomPrefix = `prefix${Math.floor(Math.random() * 1000000)}`;
|
||||
/** Ref name of the temporary master branch. */
|
||||
const masterRef = `${randomPrefix}-master`;
|
||||
/** Ref name of the temporary g3 branch. */
|
||||
const g3Ref = `${randomPrefix}-g3`;
|
||||
/** Url of the ref for fetching master and g3 branches. */
|
||||
const refUrl = `https://github.com/${git.remoteConfig.owner}/${git.remoteConfig.name}.git`;
|
||||
/** The result fo the fetch command. */
|
||||
const fetchResult =
|
||||
git.runGraceful(['fetch', '-q', refUrl, `master:${masterRef}`, `g3:${g3Ref}`]);
|
||||
/** The latest sha for the g3 branch. */
|
||||
const g3Ref = getShaForBranchLatest('g3');
|
||||
/** The latest sha for the master branch. */
|
||||
const masterRef = getShaForBranchLatest('master');
|
||||
|
||||
// If the upstream repository does not have a g3 branch to compare to, skip the comparison.
|
||||
if (fetchResult.status !== 0) {
|
||||
if (fetchResult.stderr.includes(`couldn't find remote ref g3`)) {
|
||||
return debug('No g3 branch exists on upstream, skipping.');
|
||||
}
|
||||
throw Error('Fetch of master and g3 branches for comparison failed.');
|
||||
if (!g3Ref && !masterRef) {
|
||||
return debug('Exiting early as either the g3 or master was unable to be retrieved');
|
||||
}
|
||||
|
||||
/** The statistical information about the git diff between master and g3. */
|
||||
const stats = getDiffStats(git);
|
||||
|
||||
// Delete the temporarily created mater and g3 branches.
|
||||
git.runGraceful(['branch', '-D', masterRef, g3Ref]);
|
||||
const stats = getDiffStats();
|
||||
|
||||
info.group(bold('g3 branch check'));
|
||||
info(`${stats.commits} commits between g3 and master`);
|
||||
@ -73,11 +59,27 @@ export async function printG3Comparison(git: GitClient) {
|
||||
info();
|
||||
|
||||
|
||||
/** Fetch and retrieve the latest sha for a specific branch. */
|
||||
function getShaForBranchLatest(branch: string) {
|
||||
/** The result fo the fetch command. */
|
||||
const fetchResult = git.runGraceful([
|
||||
'fetch', '-q', `https://github.com/${git.remoteConfig.owner}/${git.remoteConfig.name}.git`,
|
||||
branch
|
||||
]);
|
||||
|
||||
if (fetchResult.status !== 0 &&
|
||||
fetchResult.stderr.includes(`couldn't find remote ref ${branch}`)) {
|
||||
debug(`No '${branch}' branch exists on upstream, skipping.`);
|
||||
return false;
|
||||
}
|
||||
return git.runGraceful(['rev-parse', 'FETCH_HEAD']).stdout.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get git diff stats between master and g3, for all files and filtered to only g3 affecting
|
||||
* files.
|
||||
*/
|
||||
function getDiffStats(git: GitClient) {
|
||||
function getDiffStats() {
|
||||
/** The diff stats to be returned. */
|
||||
const stats = {
|
||||
insertions: 0,
|
||||
@ -86,7 +88,6 @@ export async function printG3Comparison(git: GitClient) {
|
||||
commits: 0,
|
||||
};
|
||||
|
||||
|
||||
// Determine the number of commits between master and g3 refs. */
|
||||
stats.commits = parseInt(git.run(['rev-list', '--count', `${g3Ref}..${masterRef}`]).stdout, 10);
|
||||
|
||||
|
@ -6,12 +6,17 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {alias, params, types} from 'typed-graphqlify';
|
||||
import {alias, onUnion, params, types} from 'typed-graphqlify';
|
||||
|
||||
import {bold, debug, info} from '../../utils/console';
|
||||
import {GitClient} from '../../utils/git';
|
||||
import {CaretakerConfig} from '../config';
|
||||
|
||||
/**
|
||||
* Cap the returned issues in the queries to an arbitrary 100. At that point, caretaker has a lot
|
||||
* of work to do and showing more than that isn't really useful.
|
||||
*/
|
||||
const MAX_RETURNED_ISSUES = 20;
|
||||
|
||||
/** Retrieve the number of matching issues for each github query. */
|
||||
export async function printGithubTasks(git: GitClient, config?: CaretakerConfig) {
|
||||
@ -19,7 +24,7 @@ export async function printGithubTasks(git: GitClient, config?: CaretakerConfig)
|
||||
debug('No github queries defined in the configuration, skipping.');
|
||||
return;
|
||||
}
|
||||
info.group(bold('Github Tasks'));
|
||||
info.group(bold(`Github Tasks`));
|
||||
await getGithubInfo(git, config);
|
||||
info.groupEnd();
|
||||
info();
|
||||
@ -28,7 +33,12 @@ export async function printGithubTasks(git: GitClient, config?: CaretakerConfig)
|
||||
/** Retrieve query match counts and log discovered counts to the console. */
|
||||
async function getGithubInfo(git: GitClient, {githubQueries: queries = []}: CaretakerConfig) {
|
||||
/** The query object for graphql. */
|
||||
const graphQlQuery: {[key: string]: {issueCount: number}} = {};
|
||||
const graphQlQuery: {
|
||||
[key: string]: {
|
||||
issueCount: number,
|
||||
nodes: Array<{url: string}>,
|
||||
}
|
||||
} = {};
|
||||
/** The Github search filter for the configured repository. */
|
||||
const repoFilter = `repo:${git.remoteConfig.owner}/${git.remoteConfig.name}`;
|
||||
queries.forEach(({name, query}) => {
|
||||
@ -37,14 +47,37 @@ async function getGithubInfo(git: GitClient, {githubQueries: queries = []}: Care
|
||||
graphQlQuery[queryKey] = params(
|
||||
{
|
||||
type: 'ISSUE',
|
||||
first: MAX_RETURNED_ISSUES,
|
||||
query: `"${repoFilter} ${query.replace(/"/g, '\\"')}"`,
|
||||
},
|
||||
{issueCount: types.number},
|
||||
{
|
||||
issueCount: types.number,
|
||||
nodes: [{...onUnion({
|
||||
PullRequest: {
|
||||
url: types.string,
|
||||
},
|
||||
Issue: {
|
||||
url: types.string,
|
||||
},
|
||||
})}],
|
||||
},
|
||||
);
|
||||
});
|
||||
/** The results of the generated github query. */
|
||||
const results = await git.github.graphql.query(graphQlQuery);
|
||||
Object.values(results).forEach((result, i) => {
|
||||
info(`${queries[i]?.name.padEnd(25)} ${result.issueCount}`);
|
||||
if (result.issueCount > 0) {
|
||||
const {owner, name: repo} = git.remoteConfig;
|
||||
const url = encodeURI(`https://github.com/${owner}/${repo}/issues?q=${queries[i]?.query}`);
|
||||
info.group(`${url}`);
|
||||
if (result.nodes.length === MAX_RETURNED_ISSUES && result.nodes.length < result.issueCount) {
|
||||
info(`(first ${MAX_RETURNED_ISSUES})`);
|
||||
}
|
||||
for (const node of result.nodes) {
|
||||
info(`- ${node.url}`);
|
||||
}
|
||||
info.groupEnd();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
load("//tools:defaults.bzl", "jasmine_node_test")
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "commit-message",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "format",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "ngbot",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "pr",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "checkout",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "common",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "discover-new-conflicts",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
load("//tools:defaults.bzl", "jasmine_node_test")
|
||||
|
||||
ts_library(
|
||||
|
@ -41,8 +41,8 @@ export async function getDefaultTargetLabelConfiguration(
|
||||
// allow merging of PRs with `target: major`.
|
||||
if (!next.isMajor) {
|
||||
throw new InvalidTargetLabelError(
|
||||
`Unable to merge pull request. The "${nextBranchName}" branch will be ` +
|
||||
`released as a minor version.`);
|
||||
`Unable to merge pull request. The "${nextBranchName}" branch will be released as ` +
|
||||
'a minor version.');
|
||||
}
|
||||
return [nextBranchName];
|
||||
},
|
||||
|
@ -30,8 +30,8 @@ export async function assertActiveLtsBranch(
|
||||
const ltsNpmTag = getLtsNpmDistTagOfMajor(version.major);
|
||||
const ltsVersion = semver.parse(distTags[ltsNpmTag]);
|
||||
|
||||
// Ensure that there is a LTS version tagged for the given version-branch major. e.g.
|
||||
// if the version branch is `9.2.x` then we want to make sure that there is a LTS
|
||||
// Ensure that there is an LTS version tagged for the given version-branch major. e.g.
|
||||
// if the version branch is `9.2.x` then we want to make sure that there is an LTS
|
||||
// version tagged in NPM for `v9`, following the `v{major}-lts` tag convention.
|
||||
if (ltsVersion === null) {
|
||||
throw new InvalidTargetBranchError(`No LTS version tagged for v${version.major} in NPM.`);
|
||||
|
@ -33,7 +33,7 @@ export async function mergePullRequest(
|
||||
prNumber: number, githubToken: string, projectRoot: string = getRepoBaseDir(),
|
||||
config?: MergeConfigWithRemote) {
|
||||
// Set the environment variable to skip all git commit hooks triggered by husky. We are unable to
|
||||
// rely on `---no-verify` as some hooks still run, notably the `prepare-commit-msg` hook.
|
||||
// rely on `--no-verify` as some hooks still run, notably the `prepare-commit-msg` hook.
|
||||
process.env['HUSKY_SKIP_HOOKS'] = '1';
|
||||
|
||||
const api = await createPullRequestMergeTask(githubToken, projectRoot, config);
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "rebase",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
load("//tools:defaults.bzl", "jasmine_node_test")
|
||||
|
||||
ts_library(
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "release",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
load("//tools:defaults.bzl", "jasmine_node_test")
|
||||
|
||||
ts_library(
|
||||
|
@ -60,7 +60,7 @@ describe('ng-dev release build', () => {
|
||||
});
|
||||
|
||||
it('should error if package has not been built', async () => {
|
||||
// Set up a NPM package that is not built.
|
||||
// Set up an NPM package that is not built.
|
||||
npmPackages.push('@angular/non-existent');
|
||||
|
||||
spyOn(console, 'error');
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "config",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "publish",
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {promises as fs} from 'fs';
|
||||
import * as Ora from 'ora';
|
||||
import * as ora from 'ora';
|
||||
import {join} from 'path';
|
||||
import * as semver from 'semver';
|
||||
|
||||
@ -44,7 +44,7 @@ export interface PullRequest {
|
||||
forkBranch: string;
|
||||
}
|
||||
|
||||
/** Constructor type for a instantiating a release action */
|
||||
/** Constructor type for instantiating a release action */
|
||||
export interface ReleaseActionConstructor<T extends ReleaseAction = ReleaseAction> {
|
||||
/** Whether the release action is currently active. */
|
||||
isActive(active: ActiveReleaseTrains): Promise<boolean>;
|
||||
@ -107,25 +107,22 @@ export abstract class ReleaseAction {
|
||||
if (state === 'failure') {
|
||||
error(
|
||||
red(` ✘ Cannot stage release. Commit "${commitSha}" does not pass all github ` +
|
||||
`status checks. Please make sure this commit passes all checks before re-running.`));
|
||||
'status checks. Please make sure this commit passes all checks before re-running.'));
|
||||
error(` Please have a look at: ${branchCommitsUrl}`);
|
||||
|
||||
if (await promptConfirm('Do you want to ignore the Github status and proceed?')) {
|
||||
info(yellow(
|
||||
` ⚠ Upstream commit is failing CI checks, but status has been ` +
|
||||
`forcibly ignored.`));
|
||||
' ⚠ Upstream commit is failing CI checks, but status has been forcibly ignored.'));
|
||||
return;
|
||||
}
|
||||
throw new UserAbortedReleaseActionError();
|
||||
} else if (state === 'pending') {
|
||||
error(
|
||||
red(` ✘ Commit "${commitSha}" still has pending github statuses that ` +
|
||||
`need to succeed before staging a release.`));
|
||||
'need to succeed before staging a release.'));
|
||||
error(red(` Please have a look at: ${branchCommitsUrl}`));
|
||||
if (await promptConfirm('Do you want to ignore the Github status and proceed?')) {
|
||||
info(yellow(
|
||||
` ⚠ Upstream commit is pending CI, but status has been ` +
|
||||
`forcibly ignored.`));
|
||||
info(yellow(' ⚠ Upstream commit is pending CI, but status has been forcibly ignored.'));
|
||||
return;
|
||||
}
|
||||
throw new UserAbortedReleaseActionError();
|
||||
@ -157,9 +154,9 @@ export abstract class ReleaseAction {
|
||||
*/
|
||||
protected async waitForEditsAndCreateReleaseCommit(newVersion: semver.SemVer) {
|
||||
info(yellow(
|
||||
` ⚠ Please review the changelog and ensure that the log contains only changes ` +
|
||||
`that apply to the public API surface. Manual changes can be made. When done, please ` +
|
||||
`proceed with the prompt below.`));
|
||||
' ⚠ Please review the changelog and ensure that the log contains only changes ' +
|
||||
'that apply to the public API surface. Manual changes can be made. When done, please ' +
|
||||
'proceed with the prompt below.'));
|
||||
|
||||
if (!await promptConfirm('Do you want to proceed and commit the changes?')) {
|
||||
throw new UserAbortedReleaseActionError();
|
||||
@ -188,7 +185,7 @@ export abstract class ReleaseAction {
|
||||
const forks = result.repository.forks.nodes;
|
||||
|
||||
if (forks.length === 0) {
|
||||
error(red(` ✘ Unable to find fork for currently authenticated user.`));
|
||||
error(red(' ✘ Unable to find fork for currently authenticated user.'));
|
||||
error(red(` Please ensure you created a fork of: ${owner}/${name}.`));
|
||||
throw new FatalReleaseActionError();
|
||||
}
|
||||
@ -304,7 +301,7 @@ export abstract class ReleaseAction {
|
||||
return new Promise((resolve, reject) => {
|
||||
debug(`Waiting for pull request #${id} to be merged.`);
|
||||
|
||||
const spinner = Ora().start(`Waiting for pull request #${id} to be merged.`);
|
||||
const spinner = ora().start(`Waiting for pull request #${id} to be merged.`);
|
||||
const intervalId = setInterval(async () => {
|
||||
const prState = await getPullRequestState(this.git, id);
|
||||
if (prState === 'merged') {
|
||||
@ -451,7 +448,7 @@ export abstract class ReleaseAction {
|
||||
|
||||
info(green(
|
||||
` ✓ Pull request for cherry-picking the changelog into "${nextBranch}" ` +
|
||||
`has been created.`));
|
||||
'has been created.'));
|
||||
info(yellow(` Please ask team members to review: ${url}.`));
|
||||
return true;
|
||||
}
|
||||
@ -490,7 +487,7 @@ export abstract class ReleaseAction {
|
||||
|
||||
if (!await this._isCommitForVersionStaging(newVersion, versionBumpCommitSha)) {
|
||||
error(red(` ✘ Latest commit in "${publishBranch}" branch is not a staging commit.`));
|
||||
error(red(` Please make sure the staging pull request has been merged.`));
|
||||
error(red(' Please make sure the staging pull request has been merged.'));
|
||||
throw new FatalReleaseActionError();
|
||||
}
|
||||
|
||||
@ -514,13 +511,13 @@ export abstract class ReleaseAction {
|
||||
await this._publishBuiltPackageToNpm(builtPackage, npmDistTag);
|
||||
}
|
||||
|
||||
info(green(` ✓ Published all packages successfully`));
|
||||
info(green(' ✓ Published all packages successfully'));
|
||||
}
|
||||
|
||||
/** Publishes the given built package to NPM with the specified NPM dist tag. */
|
||||
private async _publishBuiltPackageToNpm(pkg: BuiltPackage, npmDistTag: string) {
|
||||
debug(`Starting publish of "${pkg.name}".`);
|
||||
const spinner = Ora().start(`Publishing "${pkg.name}"`);
|
||||
const spinner = ora().start(`Publishing "${pkg.name}"`);
|
||||
|
||||
try {
|
||||
await runNpmPublish(pkg.outputPath, npmDistTag, this.config.publishRegistry);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user