Compare commits

...

20 Commits

Author SHA1 Message Date
c01bd0fe8e release: cut the v10.1.0 release 2020-09-02 12:51:31 -07:00
5588324802 build: add configuration for the caretaker command (#38601)
Add configuration information for the new caretaker command

PR Close #38601
2020-09-01 13:05:43 -07:00
437ecc8090 feat(dev-infra): check services/status information of the repository for caretaker (#38601)
The angular team relies on a number of services for hosting code, running CI, etc. This
tool allows for checking the operational status of all services at once as well as the current
state of the repository with respect to merge and triage ready issues and prs.

PR Close #38601
2020-09-01 13:05:40 -07:00
0dda97ea66 fix(compiler): incorrectly inferring namespace for HTML nodes inside SVG (#38477)
The HTML parser gets an element's namespace either from the tag name
(e.g. `<svg:rect>`) or from its parent element `<svg><rect></svg>`) which
breaks down when an element is inside of an SVG `foreignElement`,
because foreign elements allow nodes from a different namespace to be
inserted into an SVG.

These changes add another flag to the tag definitions which tells child
nodes whether to try to inherit their namespaces from their parents.
It also adds a definition for `foreignObject` with the new flag,
allowing elements placed inside it to infer their namespaces instead.

Fixes #37218.

PR Close #38477
2020-08-31 13:25:43 -07:00
5e4aeaa348 refactor(dev-infra): use a mixin to require a github-token for an ng-dev command (#38630)
Creates a mixin for requiring a github token to be provided to a command.  This mixin
allows for a centralized management of the requirement and handling of the github-token.

PR Close #38630
2020-08-31 12:32:32 -07:00
cbbf8b542f docs: Remove confusion between do/avoid templates (#38647)
PR Close #38647
2020-08-31 10:25:21 -07:00
91dfb18840 refactor(forms): remove extra space in error message (#38637)
Remove extra whitespace at package/forms/model.ts error messages

PR Close #38637
2020-08-31 09:32:00 -07:00
e44ddf5baa refactor(dev-infra): improve error message for unexpected version branches (#38622)
Currently the merge script default branch configuration throws an error
if an unexpected version branch is discovered. The error right now
assumes to much knowledge of the logic and the document outlining
the release trains conceptually.

We change it to something more easy to understand that doesn't require
full understanding of the versioning/labeling/branching document that
has been created for the Angular organization.

PR Close #38622
2020-08-31 09:30:03 -07:00
6b1a505566 feat(dev-infra): write outputs of command runs to ng-dev log file (#38599)
Creates infrastructure to write outputs of command runs to ng-dev log file.
Additionally, on commands which fail with an exit code greater than 1, an
error log file is created with the posix timestamp of the commands run time
as an identifier.

PR Close #38599
2020-08-31 08:47:20 -07:00
659705ad78 docs: ng generate module command doc change (#38480)
PR Close #38480
2020-08-31 08:43:24 -07:00
8864b0ed69 docs: remove first person and space in CircleCI in the testing guide. (#38631)
PR Close #38631
2020-08-31 08:42:09 -07:00
4e596b672f docs: remove double space in start-data. (#38642)
PR Close #38642
2020-08-31 08:41:35 -07:00
83866827c3 docs: fix broken markdown in start/start-data (#38644)
PR Close #38644
2020-08-31 08:41:02 -07:00
7006cac50a refactor(dev-infra): remove style type from commit style guide (#38639)
The `style` commit type is not part of the commit parser config,
it should be removed from the documentation.

PR Close #38639
2020-08-31 08:40:19 -07:00
dd82f2fefd fix(bazel): fix integration test for bazel building (#38629)
Update the API used to request a timestamp.  The previous API we relied on for this
test application, worldclockapi.com no longer serves times and simply 403s on all
requests.  This caused our test to timeout as the HTTP request did not handle a failure
case.  By moving to a new api, the HTTP request responds as expected and timeouts
are corrected as there is not longer a pending microtask in the queue.

PR Close #38629
2020-08-28 11:16:45 -07:00
bf003340ab build: update ng-dev merge config to reflect new label updates (#38620)
Update the ng-dev merge configuration to reflect the new label updates

PR Close #38620
2020-08-28 08:03:31 -07:00
5e35edd724 ci: update angular robot to be based on new label updates (#38620)
Update the angular robot configuration to reflect the new label updates

PR Close #38620
2020-08-28 08:03:28 -07:00
c132dcd0ae ci: update github robot to reflect new target labels (#38428)
Updates the Github robot to reflect the updated target
labels that are used as part of the canonical versioning
and labeling for the Angular organization.

PR Close #38428
2020-08-28 08:02:28 -07:00
bbe331569b build: use new labeling and branching in merge script (#38428)
We introduced a new shared configuration for merge script
labels that follow the proposal of:
https://docs.google.com/document/d/197kVillDwx-RZtSVOBtPb4BBIAw0E9RT3q3v6DZkykU

These label semantics and the branching are set up for the Angular
framework with this commit. The goal is that labeling and merging
is consistent between all Angular projects and that clear rules
are defined for branching. This was previously not the case.

PR Close #38428
2020-08-28 08:02:21 -07:00
21e9a0032c docs(forms): exclude internal-only methods and properties from docs (#38583)
Prior to this commit, a lot of internal-only class properties and methods (such as `ngOnChanges`)
of the Forms package directives were exposed on angular.io website. These fields are not expected
to be called externally (they are used/invoked by framework only), since they are part of internal
implementations of the following interfaces:

* Angular lifecycle hook interfaces
* ControlValueAccessor interface
* Validator interface

Having these internal-only fields in docs creates unnecessary noise on directive detail pages.
This commit adds the `@nodoc` annotation to these properties and methods to keep fields in the
golden files, but hide them in docs.

PR Close #38583
2020-08-27 16:39:43 -07:00
55 changed files with 883 additions and 530 deletions

View File

@ -73,15 +73,14 @@ merge:
- "packages/zone.js/scripts/**"
# comment that will be added to a PR when there is a conflict, leave empty or set to false to disable
mergeConflictComment: "Hi @{{PRAuthor}}! This PR has merge conflicts due to recent upstream merges.
\nPlease help to unblock it by resolving these conflicts. Thanks!"
mergeConflictComment: "Hi @{{PRAuthor}}! This PR has merge conflicts due to recent upstream merges.\nPlease help to unblock it by resolving these conflicts. Thanks!"
# label to monitor
mergeLabel: "PR action: merge"
mergeLabel: "action: merge"
# adding any of these labels will also add the merge label
mergeLinkedLabels:
- "PR action: merge-assistance"
- "action: merge-assistance"
# list of checks that will determine if the merge label can be added
checks:
@ -94,17 +93,17 @@ merge:
# whether the PR shouldn't have a conflict with the base branch
noConflict: true
# list of labels that a PR needs to have, checked with a regexp (e.g. "PR target:" will work for the label "PR target: master")
# list of labels that a PR needs to have, checked with a regexp (e.g. "target:" will work for the label "target: master")
requiredLabels:
- "PR target: *"
- "target: *"
- "cla: yes"
# list of labels that a PR shouldn't have, checked after the required labels with a regexp
forbiddenLabels:
- "PR target: TBD"
- "PR action: cleanup"
- "PR action: review"
- "PR state: blocked"
- "target: TBD"
- "action: cleanup"
- "action: review"
- "state: blocked"
- "cla: no"
# list of PR statuses that need to be successful
@ -121,12 +120,7 @@ merge:
# the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable
# {{MERGE_LABEL}} will be replaced by the value of the mergeLabel option
# {{PLACEHOLDER}} will be replaced by the list of failing checks
mergeRemovedComment: "I see that you just added the `{{MERGE_LABEL}}` label, but the following checks are still failing:
\n{{PLACEHOLDER}}
\n
\n**If you want your PR to be merged, it has to pass all the CI checks.**
\n
\nIf you can't get the PR to a green state due to flakes or broken master, please try rebasing to master and/or restarting the CI job. If that fails and you believe that the issue is not due to your change, please contact the caretaker and ask for help."
mergeRemovedComment: "I see that you just added the `{{MERGE_LABEL}}` label, but the following checks are still failing:\n{{PLACEHOLDER}}\n\n**If you want your PR to be merged, it has to pass all the CI checks.**\n\nIf you can't get the PR to a green state due to flakes or broken master, please try rebasing to master and/or restarting the CI job. If that fails and you believe that the issue is not due to your change, please contact the caretaker and ask for help."
# options for the triage plugin
triage:
@ -186,4 +180,4 @@ rerunCircleCI:
# set to true to disable
disabled: false
# the label which when added triggers a rerun of the default CircleCI workflow
triggerRerunLabel: "PR action: rerun CI at HEAD"
triggerRerunLabel: "action: rerun CI at HEAD"

19
.ng-dev/caretaker.ts Normal file
View File

@ -0,0 +1,19 @@
import {CaretakerConfig} from '../dev-infra/caretaker/config';
/** The configuration for `ng-dev caretaker` commands. */
export const caretaker: CaretakerConfig = {
githubQueries: [
{
name: 'Merge Queue',
query: `is:pr is:open status:success label:"action: merge"`,
},
{
name: 'Merge Assistance Queue',
query: `is:pr is:open status:success label:"action: merge-assistance"`,
},
{
name: 'Primary Triage Queue',
query: `is:open is:issue no:milestone`,
}
]
};

View File

@ -1,3 +1,4 @@
import {caretaker} from './caretaker';
import {commitMessage} from './commit-message';
import {format} from './format';
import {github} from './github';
@ -8,4 +9,5 @@ module.exports = {
format,
github,
merge,
caretaker,
};

View File

@ -1,38 +1,25 @@
import {MergeConfig} from '../dev-infra/pr/merge/config';
import {DevInfraMergeConfig} from '../dev-infra/pr/merge/config';
import {getDefaultTargetLabelConfiguration} from '../dev-infra/pr/merge/defaults';
import {github} from './github';
/**
* Configuration for the merge tool in `ng-dev`. This sets up the labels which
* are respected by the merge script (e.g. the target labels).
*/
export const merge = (): MergeConfig => {
// TODO: resume dynamically determining patch branch
const patch = '10.0.x';
export const merge: DevInfraMergeConfig['merge'] = async api => {
return {
githubApiMerge: false,
claSignedLabel: 'cla: yes',
mergeReadyLabel: /^PR action: merge(-assistance)?/,
caretakerNoteLabel: 'PR action: merge-assistance',
mergeReadyLabel: /^action: merge(-assistance)?/,
caretakerNoteLabel: 'action: merge-assistance',
commitMessageFixupLabel: 'commit message fixup',
labels: [
{
pattern: 'PR target: master-only',
branches: ['master'],
},
{
pattern: 'PR target: patch-only',
branches: [patch],
},
{
pattern: 'PR target: master & patch',
branches: ['master', patch],
},
],
labels: await getDefaultTargetLabelConfiguration(api, github, '@angular/core'),
requiredBaseCommits: {
// PRs that target either `master` or the patch branch, need to be rebased
// on top of the latest commit message validation fix.
// These SHAs are the commits that update the required license text in the header.
'master': '5aeb9a4124922d8ac08eb73b8f322905a32b0b3a',
[patch]: '27b95ba64a5d99757f4042073fd1860e20e3ed24'
'10.0.x': '27b95ba64a5d99757f4042073fd1860e20e3ed24',
},
};
};

View File

@ -1,11 +1,74 @@
<a name="10.1.0-rc.0"></a>
# 10.1.0-rc.0 (2020-08-26)
<a name="10.1.0"></a>
# 10.1.0 (2020-09-02)
### Features
* **bazel:** provide LinkablePackageInfo from ng_module ([#37623](https://github.com/angular/angular/issues/37623)) ([6898eab](https://github.com/angular/angular/commit/6898eab))
* **common:** add ReadonlyMap in place of Map in keyValuePipe ([#37311](https://github.com/angular/angular/issues/37311)) ([3373453](https://github.com/angular/angular/commit/3373453)), closes [#37308](https://github.com/angular/angular/issues/37308)
* **compiler-cli:** add `SourceFile.getOriginalLocation()` to sourcemaps package ([#32912](https://github.com/angular/angular/issues/32912)) ([6abb8d0](https://github.com/angular/angular/commit/6abb8d0))
* **compiler-cli:** Add compiler option to report errors when assigning to restricted input fields ([#38249](https://github.com/angular/angular/issues/38249)) ([71138f6](https://github.com/angular/angular/commit/71138f6))
* **compiler-cli:** add support for TypeScript 4.0 ([#38076](https://github.com/angular/angular/issues/38076)) ([0fc44e0](https://github.com/angular/angular/commit/0fc44e0))
* **compiler-cli:** explain why an expression cannot be used in AOT compilations ([#37587](https://github.com/angular/angular/issues/37587)) ([712f1bd](https://github.com/angular/angular/commit/712f1bd))
* **compiler:** support unary operators for more accurate type checking ([#37918](https://github.com/angular/angular/issues/37918)) ([874792d](https://github.com/angular/angular/commit/874792d)), closes [#20845](https://github.com/angular/angular/issues/20845) [#36178](https://github.com/angular/angular/issues/36178)
* **core:** rename async to waitForAsync to avoid confusing ([#37583](https://github.com/angular/angular/issues/37583)) ([8f07429](https://github.com/angular/angular/commit/8f07429))
* **core:** support injection token as predicate in queries ([#37506](https://github.com/angular/angular/issues/37506)) ([97dc85b](https://github.com/angular/angular/commit/97dc85b)), closes [#21152](https://github.com/angular/angular/issues/21152) [#36144](https://github.com/angular/angular/issues/36144)
* **core:** update reference and doc to change `async` to `waitAsync`. ([#37583](https://github.com/angular/angular/issues/37583)) ([8fbf40b](https://github.com/angular/angular/commit/8fbf40b))
* **forms:** AbstractControl to store raw validators in addition to combined validators function ([#37881](https://github.com/angular/angular/issues/37881)) ([ad7046b](https://github.com/angular/angular/commit/ad7046b))
* **localize:** allow duplicate messages to be handled during extraction ([#38082](https://github.com/angular/angular/issues/38082)) ([cf9a47b](https://github.com/angular/angular/commit/cf9a47b)), closes [#38077](https://github.com/angular/angular/issues/38077)
* **localize:** expose `canParse()` diagnostics ([#37909](https://github.com/angular/angular/issues/37909)) ([ec32eba](https://github.com/angular/angular/commit/ec32eba)), closes [#37901](https://github.com/angular/angular/issues/37901)
* **localize:** implement message extraction tool ([#32912](https://github.com/angular/angular/issues/32912)) ([190561d](https://github.com/angular/angular/commit/190561d))
* **platform-browser:** Allow `sms`-URLs ([#31463](https://github.com/angular/angular/issues/31463)) ([fc5c34d](https://github.com/angular/angular/commit/fc5c34d)), closes [#31462](https://github.com/angular/angular/issues/31462)
* **platform-server:** add option for absolute URL HTTP support ([#37539](https://github.com/angular/angular/issues/37539)) ([d37049a](https://github.com/angular/angular/commit/d37049a)), closes [#37071](https://github.com/angular/angular/issues/37071)
* **router:** better warning message when a router outlet has not been instantiated ([#30246](https://github.com/angular/angular/issues/30246)) ([1609815](https://github.com/angular/angular/commit/1609815))
### Bug Fixes
* **bazel:** fix integration test for bazel building ([#38629](https://github.com/angular/angular/issues/38629)) ([dd82f2f](https://github.com/angular/angular/commit/dd82f2f))
* **common:** date pipe gives wrong week number ([#37632](https://github.com/angular/angular/issues/37632)) ([ef1fb6d](https://github.com/angular/angular/commit/ef1fb6d)), closes [#33961](https://github.com/angular/angular/issues/33961)
* **common:** narrow `NgIf` context variables in template type checker ([#36627](https://github.com/angular/angular/issues/36627)) ([9c8bc4a](https://github.com/angular/angular/commit/9c8bc4a))
* **compiler-cli:** avoid creating value expressions for symbols from type-only imports ([#37912](https://github.com/angular/angular/issues/37912)) ([18098d3](https://github.com/angular/angular/commit/18098d3)), closes [#37900](https://github.com/angular/angular/issues/37900)
* **compiler-cli:** ensure source-maps can handle webpack:// protocol ([#32912](https://github.com/angular/angular/issues/32912)) ([decd95e](https://github.com/angular/angular/commit/decd95e))
* **compiler-cli:** only read source-map comment from last line ([#32912](https://github.com/angular/angular/issues/32912)) ([07a07e3](https://github.com/angular/angular/commit/07a07e3))
* **compiler-cli:** type-check inputs that include undefined when there's coercion members ([#38273](https://github.com/angular/angular/issues/38273)) ([7525f3a](https://github.com/angular/angular/commit/7525f3a))
* **compiler:** incorrectly inferring namespace for HTML nodes inside SVG ([#38477](https://github.com/angular/angular/issues/38477)) ([0dda97e](https://github.com/angular/angular/commit/0dda97e)), closes [#37218](https://github.com/angular/angular/issues/37218)
* **compiler:** mark `NgModuleFactory` construction as not side effectful ([#38147](https://github.com/angular/angular/issues/38147)) ([7f8c222](https://github.com/angular/angular/commit/7f8c222))
* **core:** Allow modification of lifecycle hooks any time before bootstrap ([#35464](https://github.com/angular/angular/issues/35464)) ([737506e](https://github.com/angular/angular/commit/737506e)), closes [#30497](https://github.com/angular/angular/issues/30497)
* **core:** detect DI parameters in JIT mode for downleveled ES2015 classes ([#38463](https://github.com/angular/angular/issues/38463)) ([ca07da4](https://github.com/angular/angular/commit/ca07da4)), closes [#38453](https://github.com/angular/angular/issues/38453)
* **core:** determine required DOMParser feature availability ([#36578](https://github.com/angular/angular/issues/36578)) ([#36578](https://github.com/angular/angular/issues/36578)) ([c509243](https://github.com/angular/angular/commit/c509243))
* **core:** do not trigger CSP alert/report in Firefox and Chrome ([#36578](https://github.com/angular/angular/issues/36578)) ([#36578](https://github.com/angular/angular/issues/36578)) ([b950d46](https://github.com/angular/angular/commit/b950d46)), closes [#25214](https://github.com/angular/angular/issues/25214)
* **core:** move generated i18n statements to the `consts` field of ComponentDef ([#38404](https://github.com/angular/angular/issues/38404)) ([cb05c01](https://github.com/angular/angular/commit/cb05c01))
* **elements:** run strategy methods in correct zone ([#37814](https://github.com/angular/angular/issues/37814)) ([8df888d](https://github.com/angular/angular/commit/8df888d)), closes [#24181](https://github.com/angular/angular/issues/24181)
* **forms:** handle form groups/arrays own pending async validation ([#22575](https://github.com/angular/angular/issues/22575)) ([77b62a5](https://github.com/angular/angular/commit/77b62a5)), closes [#10064](https://github.com/angular/angular/issues/10064)
* **language-service:** non-existent module format in package output ([#37623](https://github.com/angular/angular/issues/37623)) ([413a0fb](https://github.com/angular/angular/commit/413a0fb))
* **localize:** ensure required XLIFF parameters are serialized ([#38575](https://github.com/angular/angular/issues/38575)) ([f0af387](https://github.com/angular/angular/commit/f0af387)), closes [#38570](https://github.com/angular/angular/issues/38570)
* **localize:** extract the correct message ids ([#38498](https://github.com/angular/angular/issues/38498)) ([ac461e1](https://github.com/angular/angular/commit/ac461e1))
* **localize:** render ICU placeholders in extracted translation files ([#38484](https://github.com/angular/angular/issues/38484)) ([81c3e80](https://github.com/angular/angular/commit/81c3e80))
* **localize:** render text of extracted placeholders ([#38536](https://github.com/angular/angular/issues/38536)) ([14e90be](https://github.com/angular/angular/commit/14e90be))
* **ngcc:** detect synthesized delegate constructors for downleveled ES2015 classes ([#38463](https://github.com/angular/angular/issues/38463)) ([3b9c802](https://github.com/angular/angular/commit/3b9c802)), closes [#38453](https://github.com/angular/angular/issues/38453) [#38453](https://github.com/angular/angular/issues/38453)
* **router:** defer loading of wildcard module until needed ([#38348](https://github.com/angular/angular/issues/38348)) ([8f708b5](https://github.com/angular/angular/commit/8f708b5)), closes [#25494](https://github.com/angular/angular/issues/25494)
* **router:** fix navigation ignoring logic to compare to the browser url ([#37716](https://github.com/angular/angular/issues/37716)) ([a5ffca0](https://github.com/angular/angular/commit/a5ffca0)), closes [#16710](https://github.com/angular/angular/issues/16710) [#13586](https://github.com/angular/angular/issues/13586)
* **router:** properly compare array queryParams for equality ([#37709](https://github.com/angular/angular/issues/37709)) ([#37860](https://github.com/angular/angular/issues/37860)) ([1801d0c](https://github.com/angular/angular/commit/1801d0c))
* **router:** remove parenthesis for primary outlet segment after removing auxiliary outlet segment ([#24656](https://github.com/angular/angular/issues/24656)) ([#37163](https://github.com/angular/angular/issues/37163)) ([71f008f](https://github.com/angular/angular/commit/71f008f))
* **router:** restore 'history.state' object for navigations coming from Angular router ([#28108](https://github.com/angular/angular/issues/28108)) ([#28176](https://github.com/angular/angular/issues/28176)) ([df76a20](https://github.com/angular/angular/commit/df76a20))
* **router:** support lazy loading for empty path named outlets ([#38379](https://github.com/angular/angular/issues/38379)) ([7ad3264](https://github.com/angular/angular/commit/7ad3264)), closes [#12842](https://github.com/angular/angular/issues/12842)
### Code Refactoring
* **router:** export DefaultRouteReuseStrategy to Router public_api ([#31575](https://github.com/angular/angular/issues/31575)) ([ca79880](https://github.com/angular/angular/commit/ca79880))
### Performance Improvements
* **compiler-cli:** don't emit template guards when child scope is empty ([#38418](https://github.com/angular/angular/issues/38418)) ([1388c17](https://github.com/angular/angular/commit/1388c17))
* **compiler-cli:** fix regressions in incremental program reuse ([#37641](https://github.com/angular/angular/issues/37641)) ([5103d90](https://github.com/angular/angular/commit/5103d90))
* **compiler-cli:** only generate directive declarations when used ([#38418](https://github.com/angular/angular/issues/38418)) ([fb8f4b4](https://github.com/angular/angular/commit/fb8f4b4))
* **compiler-cli:** only generate type-check code for referenced DOM elements ([#38418](https://github.com/angular/angular/issues/38418)) ([f42e6ce](https://github.com/angular/angular/commit/f42e6ce))
* **forms:** use internal `ngDevMode` flag to tree-shake error messages in prod builds ([#37821](https://github.com/angular/angular/issues/37821)) ([201a546](https://github.com/angular/angular/commit/201a546)), closes [#37697](https://github.com/angular/angular/issues/37697)
* **ngcc:** shortcircuit tokenizing in ESM dependency host ([#37639](https://github.com/angular/angular/issues/37639)) ([bd7f440](https://github.com/angular/angular/commit/bd7f440))
* **ngcc:** use `EntryPointManifest` to speed up noop `ProgramBaseEntryPointFinder` ([#37665](https://github.com/angular/angular/issues/37665)) ([9318e23](https://github.com/angular/angular/commit/9318e23))
* **router:** apply prioritizedGuardValue operator to optimize CanLoad guards ([#37523](https://github.com/angular/angular/issues/37523)) ([d7dd295](https://github.com/angular/angular/commit/d7dd295))
@ -13,29 +76,6 @@
## 10.0.14 (2020-08-26)
<a name="10.1.0-next.8"></a>
# 10.1.0-next.8 (2020-08-24)
### Bug Fixes
* **localize:** extract the correct message ids ([#38498](https://github.com/angular/angular/issues/38498)) ([ac461e1](https://github.com/angular/angular/commit/ac461e1))
* **router:** support lazy loading for empty path named outlets ([#38379](https://github.com/angular/angular/issues/38379)) ([7ad3264](https://github.com/angular/angular/commit/7ad3264)), closes [#12842](https://github.com/angular/angular/issues/12842)
### Features
* **compiler:** support unary operators for more accurate type checking ([#37918](https://github.com/angular/angular/issues/37918)) ([874792d](https://github.com/angular/angular/commit/874792d)), closes [#20845](https://github.com/angular/angular/issues/20845) [#36178](https://github.com/angular/angular/issues/36178)
* **compiler-cli:** add support for TypeScript 4.0 ([#38076](https://github.com/angular/angular/issues/38076)) ([0fc44e0](https://github.com/angular/angular/commit/0fc44e0))
### Performance Improvements
* **forms:** use internal `ngDevMode` flag to tree-shake error messages in prod builds ([#37821](https://github.com/angular/angular/issues/37821)) ([201a546](https://github.com/angular/angular/commit/201a546)), closes [#37697](https://github.com/angular/angular/issues/37697)
<a name="10.0.12"></a>
## 10.0.12 (2020-08-24)
@ -53,13 +93,6 @@
* **language-service:** introduce hybrid visitor to locate AST node ([#38540](https://github.com/angular/angular/issues/38540)) ([66d8c22](https://github.com/angular/angular/commit/66d8c22))
<a name="10.1.0-next.7"></a>
# 10.1.0-next.7 (2020-08-19)
This release contains various API docs improvements.
<a name="10.0.11"></a>
## 10.0.11 (2020-08-19)
@ -70,29 +103,6 @@ This release contains various API docs improvements.
<a name="10.1.0-next.6"></a>
# 10.1.0-next.6 (2020-08-17)
### Bug Fixes
* **core:** detect DI parameters in JIT mode for downleveled ES2015 classes ([#38463](https://github.com/angular/angular/issues/38463)) ([ca07da4](https://github.com/angular/angular/commit/ca07da4)), closes [#38453](https://github.com/angular/angular/issues/38453)
* **core:** move generated i18n statements to the `consts` field of ComponentDef ([#38404](https://github.com/angular/angular/issues/38404)) ([cb05c01](https://github.com/angular/angular/commit/cb05c01))
* **localize:** render ICU placeholders in extracted translation files ([#38484](https://github.com/angular/angular/issues/38484)) ([81c3e80](https://github.com/angular/angular/commit/81c3e80))
* **ngcc:** detect synthesized delegate constructors for downleveled ES2015 classes ([#38463](https://github.com/angular/angular/issues/38463)) ([3b9c802](https://github.com/angular/angular/commit/3b9c802)), closes [#38453](https://github.com/angular/angular/issues/38453) [#38453](https://github.com/angular/angular/issues/38453)
### Performance Improvements
* **compiler-cli:** don't emit template guards when child scope is empty ([#38418](https://github.com/angular/angular/issues/38418)) ([1388c17](https://github.com/angular/angular/commit/1388c17))
* **compiler-cli:** only generate directive declarations when used ([#38418](https://github.com/angular/angular/issues/38418)) ([fb8f4b4](https://github.com/angular/angular/commit/fb8f4b4))
* **compiler-cli:** only generate type-check code for referenced DOM elements ([#38418](https://github.com/angular/angular/issues/38418)) ([f42e6ce](https://github.com/angular/angular/commit/f42e6ce))
### Code Refactoring
* **router:** export DefaultRouteReuseStrategy to Router public_api ([#31575](https://github.com/angular/angular/issues/31575)) ([ca79880](https://github.com/angular/angular/commit/ca79880))
<a name="10.0.10"></a>
## 10.0.10 (2020-08-17)
@ -108,25 +118,6 @@ This release contains various API docs improvements.
<a name="10.1.0-next.5"></a>
# 10.1.0-next.5 (2020-08-12)
### Bug Fixes
* **compiler-cli:** avoid creating value expressions for symbols from type-only imports ([#37912](https://github.com/angular/angular/issues/37912)) ([18098d3](https://github.com/angular/angular/commit/18098d3)), closes [#37900](https://github.com/angular/angular/issues/37900)
* **compiler-cli:** type-check inputs that include undefined when there's coercion members ([#38273](https://github.com/angular/angular/issues/38273)) ([7525f3a](https://github.com/angular/angular/commit/7525f3a))
* **router:** defer loading of wildcard module until needed ([#38348](https://github.com/angular/angular/issues/38348)) ([8f708b5](https://github.com/angular/angular/commit/8f708b5)), closes [#25494](https://github.com/angular/angular/issues/25494)
* **router:** restore 'history.state' object for navigations coming from Angular router ([#28108](https://github.com/angular/angular/issues/28108)) ([#28176](https://github.com/angular/angular/issues/28176)) ([df76a20](https://github.com/angular/angular/commit/df76a20))
### Features
* **compiler-cli:** Add compiler option to report errors when assigning to restricted input fields ([#38249](https://github.com/angular/angular/issues/38249)) ([71138f6](https://github.com/angular/angular/commit/71138f6))
* **router:** better warning message when a router outlet has not been instantiated ([#30246](https://github.com/angular/angular/issues/30246)) ([1609815](https://github.com/angular/angular/commit/1609815))
<a name="10.0.9"></a>
## 10.0.9 (2020-08-12)
@ -148,24 +139,6 @@ This release contains various API docs improvements.
* **service-worker:** fix the chrome debugger syntax highlighter ([#38332](https://github.com/angular/angular/issues/38332)) ([f5d5bac](https://github.com/angular/angular/commit/f5d5bac))
<a name="10.1.0-next.4"></a>
# 10.1.0-next.4 (2020-08-04)
### Bug Fixes
* **common:** narrow `NgIf` context variables in template type checker ([#36627](https://github.com/angular/angular/issues/36627)) ([9c8bc4a](https://github.com/angular/angular/commit/9c8bc4a))
* **compiler:** mark `NgModuleFactory` construction as not side effectful ([#38147](https://github.com/angular/angular/issues/38147)) ([7f8c222](https://github.com/angular/angular/commit/7f8c222))
### Features
* **core:** rename async to waitForAsync to avoid confusing ([#37583](https://github.com/angular/angular/issues/37583)) ([8f07429](https://github.com/angular/angular/commit/8f07429))
* **core:** update reference and doc to change `async` to `waitAsync`. ([#37583](https://github.com/angular/angular/issues/37583)) ([8fbf40b](https://github.com/angular/angular/commit/8fbf40b))
<a name="10.0.8"></a>
## 10.0.8 (2020-08-04)
@ -187,16 +160,6 @@ This release contains various API docs improvements.
<a name="10.1.0-next.3"></a>
# 10.1.0-next.3 (2020-07-28)
### Bug Fixes
* **elements:** run strategy methods in correct zone ([#37814](https://github.com/angular/angular/issues/37814)) ([8df888d](https://github.com/angular/angular/commit/8df888d)), closes [#24181](https://github.com/angular/angular/issues/24181)
<a name="10.0.6"></a>
## 10.0.6 (2020-07-28)
@ -210,23 +173,6 @@ This release contains various API docs improvements.
<a name="10.1.0-next.2"></a>
# 10.1.0-next.2 (2020-07-22)
### Bug Fixes
* **core:** Allow modification of lifecycle hooks any time before bootstrap ([#35464](https://github.com/angular/angular/issues/35464)) ([737506e](https://github.com/angular/angular/commit/737506e)), closes [#30497](https://github.com/angular/angular/issues/30497)
### Features
* **common:** add ReadonlyMap in place of Map in keyValuePipe ([#37311](https://github.com/angular/angular/issues/37311)) ([3373453](https://github.com/angular/angular/commit/3373453)), closes [#37308](https://github.com/angular/angular/issues/37308)
* **forms:** AbstractControl to store raw validators in addition to combined validators function ([#37881](https://github.com/angular/angular/issues/37881)) ([ad7046b](https://github.com/angular/angular/commit/ad7046b))
* **localize:** allow duplicate messages to be handled during extraction ([#38082](https://github.com/angular/angular/issues/38082)) ([cf9a47b](https://github.com/angular/angular/commit/cf9a47b)), closes [#38077](https://github.com/angular/angular/issues/38077)
<a name="10.0.5"></a>
## 10.0.5 (2020-07-22)
@ -261,62 +207,6 @@ This release contains various API docs improvements.
* **bazel:** provide LinkablePackageInfo from ng_module ([#37778](https://github.com/angular/angular/issues/37778)) ([6cd10a1](https://github.com/angular/angular/commit/6cd10a1)), closes [/github.com/bazelbuild/rules_nodejs/blob/9a5de3728b05bf1647bbb87ad99f54e626604705/internal/linker/link_node_modules.bzl#L144-L146](https://github.com//github.com/bazelbuild/rules_nodejs/blob/9a5de3728b05bf1647bbb87ad99f54e626604705/internal/linker/link_node_modules.bzl/issues/L144-L146)
<a name="10.1.0-next.1"></a>
# 10.1.0-next.1 (2020-07-15)
### Bug Fixes
* **bazel:** ng_module rule does not expose flat module information in Ivy ([#36971](https://github.com/angular/angular/issues/36971)) ([1550663](https://github.com/angular/angular/commit/1550663))
* **compiler:** check more cases for pipe usage inside host bindings ([#37883](https://github.com/angular/angular/issues/37883)) ([9322b9a](https://github.com/angular/angular/commit/9322b9a)), closes [#34655](https://github.com/angular/angular/issues/34655) [#37610](https://github.com/angular/angular/issues/37610)
* **compiler-cli:** ensure file_system handles mixed Windows drives ([#37959](https://github.com/angular/angular/issues/37959)) ([6b31155](https://github.com/angular/angular/commit/6b31155)), closes [#36777](https://github.com/angular/angular/issues/36777)
* **language-service:** remove completion for string ([#37983](https://github.com/angular/angular/issues/37983)) ([10aba15](https://github.com/angular/angular/commit/10aba15))
* **ngcc:** report a warning if ngcc tries to use a solution-style tsconfig ([#38003](https://github.com/angular/angular/issues/38003)) ([b358495](https://github.com/angular/angular/commit/b358495)), closes [#36386](https://github.com/angular/angular/issues/36386)
* **router:** ensure duplicate popstate/hashchange events are handled correctly ([#37674](https://github.com/angular/angular/issues/37674)) ([9185c6e](https://github.com/angular/angular/commit/9185c6e)), closes [/github.com/angular/angular/issues/16710#issuecomment-646919529](https://github.com//github.com/angular/angular/issues/16710/issues/issuecomment-646919529) [#16710](https://github.com/angular/angular/issues/16710)
* **service-worker:** correctly handle relative base href ([#37922](https://github.com/angular/angular/issues/37922)) ([d19ef65](https://github.com/angular/angular/commit/d19ef65)), closes [#25055](https://github.com/angular/angular/issues/25055) [#25055](https://github.com/angular/angular/issues/25055)
* **service-worker:** correctly serve `ngsw/state` with a non-root SW scope ([#37922](https://github.com/angular/angular/issues/37922)) ([2156bee](https://github.com/angular/angular/commit/2156bee)), closes [#30505](https://github.com/angular/angular/issues/30505)
<a name="10.1.0-next.0"></a>
# 10.1.0-next.0 (2020-07-08)
### Bug Fixes
* **common:** date pipe gives wrong week number ([#37632](https://github.com/angular/angular/issues/37632)) ([ef1fb6d](https://github.com/angular/angular/commit/ef1fb6d)), closes [#33961](https://github.com/angular/angular/issues/33961)
* **compiler-cli:** ensure source-maps can handle webpack:// protocol ([#32912](https://github.com/angular/angular/issues/32912)) ([decd95e](https://github.com/angular/angular/commit/decd95e))
* **compiler-cli:** only read source-map comment from last line ([#32912](https://github.com/angular/angular/issues/32912)) ([07a07e3](https://github.com/angular/angular/commit/07a07e3))
* **core:** determine required DOMParser feature availability ([#36578](https://github.com/angular/angular/issues/36578)) ([#36578](https://github.com/angular/angular/issues/36578)) ([c509243](https://github.com/angular/angular/commit/c509243))
* **core:** do not trigger CSP alert/report in Firefox and Chrome ([#36578](https://github.com/angular/angular/issues/36578)) ([#36578](https://github.com/angular/angular/issues/36578)) ([b950d46](https://github.com/angular/angular/commit/b950d46)), closes [#25214](https://github.com/angular/angular/issues/25214)
* **forms:** handle form groups/arrays own pending async validation ([#22575](https://github.com/angular/angular/issues/22575)) ([77b62a5](https://github.com/angular/angular/commit/77b62a5)), closes [#10064](https://github.com/angular/angular/issues/10064)
* **language-service:** non-existent module format in package output ([#37623](https://github.com/angular/angular/issues/37623)) ([413a0fb](https://github.com/angular/angular/commit/413a0fb))
* **router:** fix navigation ignoring logic to compare to the browser url ([#37716](https://github.com/angular/angular/issues/37716)) ([a5ffca0](https://github.com/angular/angular/commit/a5ffca0)), closes [#16710](https://github.com/angular/angular/issues/16710) [#13586](https://github.com/angular/angular/issues/13586)
* **router:** properly compare array queryParams for equality ([#37709](https://github.com/angular/angular/issues/37709)) ([#37860](https://github.com/angular/angular/issues/37860)) ([1801d0c](https://github.com/angular/angular/commit/1801d0c))
* **router:** remove parenthesis for primary outlet segment after removing auxiliary outlet segment ([#24656](https://github.com/angular/angular/issues/24656)) ([#37163](https://github.com/angular/angular/issues/37163)) ([71f008f](https://github.com/angular/angular/commit/71f008f))
### Features
* **bazel:** provide LinkablePackageInfo from ng_module ([#37623](https://github.com/angular/angular/issues/37623)) ([6898eab](https://github.com/angular/angular/commit/6898eab))
* **compiler-cli:** add `SourceFile.getOriginalLocation()` to sourcemaps package ([#32912](https://github.com/angular/angular/issues/32912)) ([6abb8d0](https://github.com/angular/angular/commit/6abb8d0))
* **compiler-cli:** explain why an expression cannot be used in AOT compilations ([#37587](https://github.com/angular/angular/issues/37587)) ([712f1bd](https://github.com/angular/angular/commit/712f1bd))
* **core:** support injection token as predicate in queries ([#37506](https://github.com/angular/angular/issues/37506)) ([97dc85b](https://github.com/angular/angular/commit/97dc85b)), closes [#21152](https://github.com/angular/angular/issues/21152) [#36144](https://github.com/angular/angular/issues/36144)
* **localize:** expose `canParse()` diagnostics ([#37909](https://github.com/angular/angular/issues/37909)) ([ec32eba](https://github.com/angular/angular/commit/ec32eba)), closes [#37901](https://github.com/angular/angular/issues/37901)
* **localize:** implement message extraction tool ([#32912](https://github.com/angular/angular/issues/32912)) ([190561d](https://github.com/angular/angular/commit/190561d))
* **platform-browser:** Allow `sms`-URLs ([#31463](https://github.com/angular/angular/issues/31463)) ([fc5c34d](https://github.com/angular/angular/commit/fc5c34d)), closes [#31462](https://github.com/angular/angular/issues/31462)
* **platform-server:** add option for absolute URL HTTP support ([#37539](https://github.com/angular/angular/issues/37539)) ([d37049a](https://github.com/angular/angular/commit/d37049a)), closes [#37071](https://github.com/angular/angular/issues/37071)
### Performance Improvements
* **compiler-cli:** fix regressions in incremental program reuse ([#37641](https://github.com/angular/angular/issues/37641)) ([5103d90](https://github.com/angular/angular/commit/5103d90))
* **ngcc:** shortcircuit tokenizing in ESM dependency host ([#37639](https://github.com/angular/angular/issues/37639)) ([bd7f440](https://github.com/angular/angular/commit/bd7f440))
* **ngcc:** use `EntryPointManifest` to speed up noop `ProgramBaseEntryPointFinder` ([#37665](https://github.com/angular/angular/issues/37665)) ([9318e23](https://github.com/angular/angular/commit/9318e23))
* **router:** apply prioritizedGuardValue operator to optimize CanLoad guards ([#37523](https://github.com/angular/angular/issues/37523)) ([d7dd295](https://github.com/angular/angular/commit/d7dd295))
<a name="10.0.3"></a>
## 10.0.3 (2020-07-08)
@ -598,12 +488,12 @@ https://github.com/microsoft/TypeScript/issues/38374 for more
information and updates.
If you used Closure Compiler with Angular in the past, you will likely
be better off consuming Angular packages built from sources directly
be better off consuming Angular packages built from sources directly
rather than consuming the version we publish on npm,
which is primarily optimized for Webpack/Rollup + Terser build pipeline.
As a temporary workaround, you might consider using your current build
pipeline with Closure flag `--compilation_level=SIMPLE`. This flag
pipeline with Closure flag `--compilation_level=SIMPLE`. This flag
will ensure that your build pipeline produces buildable and
runnable artifacts, at the cost of increased payload size due to
advanced optimizations being disabled.
@ -611,17 +501,17 @@ advanced optimizations being disabled.
If you were affected by this change, please help us understand your
needs by leaving a comment on https://github.com/angular/angular/issues/37234.
* **core:** make generic mandatory for ModuleWithProviders
* **core:** make generic mandatory for ModuleWithProviders
A generic type parameter has always been required for the `ModuleWithProviders` pattern to work with Ivy, but prior to this commit, View Engine allowed the generic type to be omitted (though support was officially deprecated).
If you're using `ModuleWithProviders` without a generic type in your application code, a v10 migration will update your code for you.
If you're using `ModuleWithProviders` without a generic type in your application code, a v10 migration will update your code for you.
However, if you are using View Engine and also depending on a library that omits the generic type, you will now get a build time error similar to:
```
error TS2314: Generic type 'ModuleWithProviders<T>' requires 1 type argument(s).
```
In this case, ngcc won't help you (because it's Ivy-only) and the migration only covers application code.
You should contact the library author to fix their library to provide a type parameter when they use this class.
@ -1949,7 +1839,7 @@ API surface going forward.
* **core:** Injector.get now accepts abstract classes to return
type-safe values. Previous implementation returned `any` through the
deprecated implementation.
* Angular now compiles with Ivy by default ([#32219](https://github.com/angular/angular/issues/32219)) ([ec4381d](https://github.com/angular/angular/commit/ec4381d)).
* Angular now compiles with Ivy by default ([#32219](https://github.com/angular/angular/issues/32219)) ([ec4381d](https://github.com/angular/angular/commit/ec4381d)).
If you aren't familiar with Ivy, read our [blog post about the Ivy preview](https://blog.angular.io/its-time-for-the-compatibility-opt-in-preview-of-ivy-38f3542a282f?gi=8bfeb44b05c) and see the list of changes [here](https://docs.google.com/document/d/1Dije0AsJ0PxL3NaeNPxpYDeapj30b_QC0xfeIvIIzgg/preview).

View File

@ -230,7 +230,6 @@ Must be one of the following:
* **fix**: A bug fix
* **perf**: A code change that improves performance
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
* **test**: Adding missing tests or correcting existing tests

View File

@ -10,8 +10,8 @@ import { Hero } from '../shared/hero.model';
template: `
<section>
Our list of heroes:
<hero-profile *ngFor="let hero of heroes" [hero]="hero">
</hero-profile>
<toh-hero *ngFor="let hero of heroes" [hero]="hero">
</toh-hero>
Total powers: {{totalPowers}}<br>
Average power: {{totalPowers / heroes.length}}
</section>

View File

@ -87,7 +87,7 @@ To make one, enter the following command in the terminal, where `customers` is t
ng generate module customers --route customers --module app.module
</code-example>
This creates a `customers` folder with the new lazy-loadable module `CustomersModule` defined in the `customers.module.ts` file. The command automatically declares the `CustomersComponent` inside the new feature module.
This creates a `customers` folder having the new lazy-loadable feature module `CustomersModule` defined in the `customers.module.ts` file and the routing module `CustomersRoutingModule` defined in the `customers-routing.module.ts` file. The command automatically declares the `CustomersComponent` and imports `CustomersRoutingModule` inside the new feature module.
Because the new module is meant to be lazy-loaded, the command does NOT add a reference to the new feature module in the application's root module file, `app.module.ts`.
Instead, it adds the declared route, `customers` to the `routes` array declared in the module provided as the `--module` option.

View File

@ -217,7 +217,7 @@ script:
- npm run e2e -- --protractor-config=e2e/protractor-ci.conf.js
```
This does the same things as the Circle CI configuration, except that Travis doesn't come with Chrome, so we use Chromium instead.
This does the same things as the CircleCI configuration, except that Travis doesn't come with Chrome, so use Chromium instead.
Step 2: Commit your changes and push them to your repository.

View File

@ -40,7 +40,7 @@ A later part of this tutorial, [Use forms for user input](start/start-forms "Try
<code-example header="src/app/cart.service.ts" path="getting-started/src/app/cart.service.1.ts"></code-example>
<div class="alert is-helpful>
<div class="alert is-helpful">
The StackBlitz generator might provide the cart service in `app.module.ts` by default. That differs from the example, which uses a bundle-optimization technique, an `@Injectable()` decorator with the `{ providedIn: 'root' }` statement.
For more information about services, see [Introduction to Services and Dependency Injection](guide/architecture-services "Concepts > Intro to Services and DI").
@ -236,7 +236,7 @@ For more information about services, see [Introduction to Services and Dependenc
<!-- Accessing data with the HTTP client -->
Servers often return data in the form of a stream.
Streams are useful because they make it easy to transform the returned data and make modifications to the way you request that data.
Streams are useful because they make it easy to transform the returned data and make modifications to the way you request that data.
The Angular HTTP client, `HttpClient`, is a built-in way to fetch data from external APIs and provide them to your app as a stream.
This section shows you how to use the HTTP client to retrieve shipping prices from an external file.

View File

@ -8,6 +8,7 @@ ts_library(
],
module_name = "@angular/dev-infra-private",
deps = [
"//dev-infra/caretaker",
"//dev-infra/commit-message",
"//dev-infra/format",
"//dev-infra/pr",

View File

@ -0,0 +1,26 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
ts_library(
name = "caretaker",
srcs = [
"cli.ts",
],
module_name = "@angular/dev-infra-private/caretaker",
visibility = ["//dev-infra:__subpackages__"],
deps = [
"//dev-infra/caretaker/check",
"@npm//@types/yargs",
"@npm//yargs",
],
)
ts_library(
name = "config",
srcs = [
"config.ts",
],
visibility = ["//dev-infra:__subpackages__"],
deps = [
"//dev-infra/utils",
],
)

View File

@ -0,0 +1,21 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
ts_library(
name = "check",
srcs = glob(["*.ts"]),
module_name = "@angular/dev-infra-private/caretaker/service-statuses",
visibility = ["//dev-infra:__subpackages__"],
deps = [
"//dev-infra/caretaker:config",
"//dev-infra/utils",
"@npm//@types/fs-extra",
"@npm//@types/node",
"@npm//@types/node-fetch",
"@npm//@types/yargs",
"@npm//multimatch",
"@npm//node-fetch",
"@npm//typed-graphqlify",
"@npm//yaml",
"@npm//yargs",
],
)

View File

@ -0,0 +1,27 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {GitClient} from '../../utils/git';
import {getCaretakerConfig} from '../config';
import {printG3Comparison} from './g3';
import {printGithubTasks} from './github';
import {printServiceStatuses} from './services';
/** Check the status of services which Angular caretakers need to monitor. */
export async function checkServiceStatuses(githubToken: string) {
/** The configuration for the caretaker commands. */
const config = getCaretakerConfig();
/** The GitClient for interacting with git and Github. */
const git = new GitClient(githubToken, config);
await printServiceStatuses();
await printGithubTasks(git, config.caretaker);
await printG3Comparison(git);
}

View File

@ -0,0 +1,39 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Arguments, Argv, CommandModule} from 'yargs';
import {addGithubTokenFlag} from '../../utils/yargs';
import {checkServiceStatuses} from './check';
export interface CaretakerCheckOptions {
githubToken: string;
}
/** URL to the Github page where personal access tokens can be generated. */
export const GITHUB_TOKEN_GENERATE_URL = `https://github.com/settings/tokens`;
/** Builds the command. */
function builder(yargs: Argv) {
return addGithubTokenFlag(yargs);
}
/** Handles the command. */
async function handler({githubToken}: Arguments<CaretakerCheckOptions>) {
await checkServiceStatuses(githubToken);
}
/** yargs command module for checking status information for the repository */
export const CheckModule: CommandModule<{}, CaretakerCheckOptions> = {
handler,
builder,
command: 'check',
describe: 'Check the status of information the caretaker manages for the repository',
};

View File

@ -0,0 +1,123 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {existsSync, readFileSync} from 'fs-extra';
import * as multimatch from 'multimatch';
import {join} from 'path';
import {parse as parseYaml} from 'yaml';
import {getRepoBaseDir} from '../../utils/config';
import {bold, debug, info} from '../../utils/console';
import {GitClient} from '../../utils/git';
/** Compare the upstream master to the upstream g3 branch, if it exists. */
export async function printG3Comparison(git: GitClient) {
const angularRobotFilePath = join(getRepoBaseDir(), '.github/angular-robot.yml');
if (!existsSync(angularRobotFilePath)) {
return debug('No angular robot configuration file exists, skipping.');
}
/** The configuration defined for the angular robot. */
const robotConfig = parseYaml(readFileSync(angularRobotFilePath).toString());
/** The files to be included in the g3 sync. */
const includeFiles = robotConfig?.merge?.g3Status?.include || [];
/** The files to be expected in the g3 sync. */
const excludeFiles = robotConfig?.merge?.g3Status?.exclude || [];
if (includeFiles.length === 0 && excludeFiles.length === 0) {
debug('No g3Status include or exclude lists are defined in the angular robot configuration,');
debug('skipping.');
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', refUrl, `master:${masterRef}`, `g3:${g3Ref}`]);
// 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.');
}
/** 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]);
info.group(bold('g3 branch check'));
info(`${stats.commits} commits between g3 and master`);
if (stats.files === 0) {
info('✅ No sync is needed at this time');
} else {
info(`${stats.files} files changed, ${stats.insertions} insertions(+), ${
stats.deletions} deletions(-) will be included in the next sync`);
}
info.groupEnd();
info();
/**
* Get git diff stats between master and g3, for all files and filtered to only g3 affecting
* files.
*/
function getDiffStats(git: GitClient) {
/** The diff stats to be returned. */
const stats = {
insertions: 0,
deletions: 0,
files: 0,
commits: 0,
};
// Determine the number of commits between master and g3 refs. */
stats.commits = parseInt(git.run(['rev-list', '--count', `${g3Ref}..${masterRef}`]).stdout, 10);
// Get the numstat information between master and g3
git.run(['diff', `${g3Ref}...${masterRef}`, '--numstat'])
.stdout
// Remove the extra space after git's output.
.trim()
// Split each line of git output into array
.split('\n')
// Split each line from the git output into components parts: insertions,
// deletions and file name respectively
.map(line => line.split('\t'))
// Parse number value from the insertions and deletions values
// Example raw line input:
// 10\t5\tsrc/file/name.ts
.map(line => [Number(line[0]), Number(line[1]), line[2]] as [number, number, string])
// Add each line's value to the diff stats, and conditionally to the g3
// stats as well if the file name is included in the files synced to g3.
.forEach(([insertions, deletions, fileName]) => {
if (checkMatchAgainstIncludeAndExclude(fileName, includeFiles, excludeFiles)) {
stats.insertions += insertions;
stats.deletions += deletions;
stats.files += 1;
}
});
return stats;
}
/** Determine whether the file name passes both include and exclude checks. */
function checkMatchAgainstIncludeAndExclude(
file: string, includes: string[], excludes: string[]) {
return multimatch(multimatch(file, includes), excludes, {flipNegate: true}).length !== 0;
}
}

View File

@ -0,0 +1,56 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {alias, params, types} from 'typed-graphqlify';
import {bold, debug, info} from '../../utils/console';
import {GitClient} from '../../utils/git';
import {CaretakerConfig} from '../config';
interface GithubInfoQuery {
[key: string]: {
issueCount: number,
};
}
/** Retrieve the number of matching issues for each github query. */
export async function printGithubTasks(git: GitClient, config: CaretakerConfig) {
if (!config.githubQueries?.length) {
debug('No github queries defined in the configuration, skipping.');
return;
}
info.group(bold('Github Tasks'));
await getGithubInfo(git, config);
info.groupEnd();
info();
}
/** 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}} = {};
/** The Github search filter for the configured repository. */
const repoFilter = `repo:${git.remoteConfig.owner}/${git.remoteConfig.name}`;
queries.forEach(({name, query}) => {
/** The name of the query, with spaces removed to match GraphQL requirements. */
const queryKey = alias(name.replace(/ /g, ''), 'search');
graphQlQuery[queryKey] = params(
{
type: 'ISSUE',
query: `"${repoFilter} ${query.replace(/"/g, '\\"')}"`,
},
{issueCount: types.number},
);
});
/** 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}`);
});
}

View File

@ -0,0 +1,79 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import fetch from 'node-fetch';
import {bold, green, info, red} from '../../utils/console';
/** The status levels for services. */
enum ServiceStatus {
GREEN,
RED
}
/** The results of checking the status of a service */
interface StatusCheckResult {
status: ServiceStatus;
description: string;
lastUpdated: Date;
}
/** Retrieve and log stasuses for all of the services of concern. */
export async function printServiceStatuses() {
info.group(bold(`Service Statuses (checked: ${new Date().toLocaleString()})`));
logStatus('CircleCI', await getCircleCiStatus());
logStatus('Github', await getGithubStatus());
logStatus('NPM', await getNpmStatus());
logStatus('Saucelabs', await getSaucelabsStatus());
info.groupEnd();
info();
}
/** Log the status of the service to the console. */
function logStatus(serviceName: string, status: StatusCheckResult) {
serviceName = serviceName.padEnd(15);
if (status.status === ServiceStatus.GREEN) {
info(`${serviceName} ${green('✅')}`);
} else if (status.status === ServiceStatus.RED) {
info.group(`${serviceName} ${red('❌')} (Updated: ${status.lastUpdated.toLocaleString()})`);
info(` Details: ${status.description}`);
info.groupEnd();
}
}
/** Gets the service status information for Saucelabs. */
async function getSaucelabsStatus(): Promise<StatusCheckResult> {
return getStatusFromStandardApi('https://status.us-west-1.saucelabs.com/api/v2/status.json');
}
/** Gets the service status information for NPM. */
async function getNpmStatus(): Promise<StatusCheckResult> {
return getStatusFromStandardApi('https://status.npmjs.org/api/v2/status.json');
}
/** Gets the service status information for CircleCI. */
async function getCircleCiStatus(): Promise<StatusCheckResult> {
return getStatusFromStandardApi('https://status.circleci.com/api/v2/status.json');
}
/** Gets the service status information for Github. */
async function getGithubStatus(): Promise<StatusCheckResult> {
return getStatusFromStandardApi('https://www.githubstatus.com/api/v2/status.json');
}
/** Retrieve the status information for a service which uses a standard API response. */
async function getStatusFromStandardApi(url: string) {
const result = await fetch(url).then(result => result.json());
const status = result.status.indicator === 'none' ? ServiceStatus.GREEN : ServiceStatus.RED;
return {
status,
description: result.status.description,
lastUpdated: new Date(result.page.updated_at)
};
}

View File

@ -0,0 +1,16 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Argv} from 'yargs';
import {CheckModule} from './check/cli';
/** Build the parser for the caretaker commands. */
export function buildCaretakerParser(yargs: Argv) {
return yargs.command(CheckModule);
}

View File

@ -0,0 +1,24 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {assertNoErrors, getConfig, NgDevConfig} from '../utils/config';
export interface CaretakerConfig {
githubQueries?: {name: string; query: string;}[];
}
/** Retrieve and validate the config as `CaretakerConfig`. */
export function getCaretakerConfig() {
// List of errors encountered validating the config.
const errors: string[] = [];
// The non-validated config object.
const config: Partial<NgDevConfig<{caretaker: CaretakerConfig}>> = getConfig();
assertNoErrors(errors);
return config as Required<typeof config>;
}

View File

@ -13,8 +13,11 @@ import {buildCommitMessageParser} from './commit-message/cli';
import {buildFormatParser} from './format/cli';
import {buildReleaseParser} from './release/cli';
import {buildPrParser} from './pr/cli';
import {captureLogOutputForCommand} from './utils/console';
import {buildCaretakerParser} from './caretaker/cli';
yargs.scriptName('ng-dev')
.middleware(captureLogOutputForCommand)
.demandCommand()
.recommendCommands()
.command('commit-message <command>', '', buildCommitMessageParser)
@ -23,6 +26,7 @@ yargs.scriptName('ng-dev')
.command('pullapprove <command>', '', buildPullapproveParser)
.command('release <command>', '', buildReleaseParser)
.command('ts-circular-deps <command>', '', tsCircularDependenciesBuilder)
.command('caretaker <command>', '', buildCaretakerParser)
.wrap(120)
.strict()
.parse();

View File

@ -8,35 +8,21 @@
import {Arguments, Argv, CommandModule} from 'yargs';
import {error} from '../../utils/console';
import {addGithubTokenFlag} from '../../utils/yargs';
import {checkOutPullRequestLocally} from '../common/checkout-pr';
export interface CheckoutOptions {
prNumber: number;
'github-token'?: string;
githubToken: string;
}
/** URL to the Github page where personal access tokens can be generated. */
export const GITHUB_TOKEN_GENERATE_URL = `https://github.com/settings/tokens`;
/** Builds the checkout pull request command. */
function builder(yargs: Argv) {
return yargs.positional('prNumber', {type: 'number', demandOption: true}).option('github-token', {
type: 'string',
description: 'Github token. If not set, token is retrieved from the environment variables.'
});
return addGithubTokenFlag(yargs).positional('prNumber', {type: 'number', demandOption: true});
}
/** Handles the checkout pull request command. */
async function handler({prNumber, 'github-token': token}: Arguments<CheckoutOptions>) {
const githubToken = token || process.env.GITHUB_TOKEN || process.env.TOKEN;
if (!githubToken) {
error('No Github token set. Please set the `GITHUB_TOKEN` environment variable.');
error('Alternatively, pass the `--github-token` command line flag.');
error(`You can generate a token here: ${GITHUB_TOKEN_GENERATE_URL}`);
process.exitCode = 1;
return;
}
async function handler({prNumber, githubToken}: Arguments<CheckoutOptions>) {
const prCheckoutOptions = {allowIfMaintainerCannotModify: true, branchName: `pr-${prNumber}`};
await checkOutPullRequestLocally(prNumber, githubToken, prCheckoutOptions);
}

View File

@ -8,36 +8,24 @@
import {Arguments, Argv} from 'yargs';
import {error, red, yellow} from '../../utils/console';
import {addGithubTokenFlag} from '../../utils/yargs';
import {GITHUB_TOKEN_GENERATE_URL, mergePullRequest} from './index';
import {mergePullRequest} from './index';
/** The options available to the merge command via CLI. */
export interface MergeCommandOptions {
'github-token'?: string;
githubToken: string;
'pr-number': number;
}
/** Builds the options for the merge command. */
export function buildMergeCommand(yargs: Argv): Argv<MergeCommandOptions> {
return yargs.help()
.strict()
.positional('pr-number', {demandOption: true, type: 'number'})
.option('github-token', {
type: 'string',
description: 'Github token. If not set, token is retrieved from the environment variables.'
});
return addGithubTokenFlag(yargs).help().strict().positional(
'pr-number', {demandOption: true, type: 'number'});
}
/** Handles the merge command. i.e. performs the merge of a specified pull request. */
export async function handleMergeCommand(args: Arguments<MergeCommandOptions>) {
const githubToken = args['github-token'] || process.env.GITHUB_TOKEN || process.env.TOKEN;
if (!githubToken) {
error(red('No Github token set. Please set the `GITHUB_TOKEN` environment variable.'));
error(red('Alternatively, pass the `--github-token` command line flag.'));
error(yellow(`You can generate a token here: ${GITHUB_TOKEN_GENERATE_URL}`));
process.exit(1);
}
await mergePullRequest(args['pr-number'], githubToken);
export async function handleMergeCommand(
{'pr-number': pr, githubToken}: Arguments<MergeCommandOptions>) {
await mergePullRequest(pr, githubToken);
}

View File

@ -165,6 +165,11 @@ export async function findActiveVersionBranches(
latestVersionBranch: string | null,
releaseCandidateBranch: string | null,
}> {
// Version representing the release-train currently in the next phase. Note that we ignore
// patch and pre-release segments in order to be able to compare the next release train to
// other release trains from version branches (which follow the `N.N.x` pattern).
const nextReleaseTrainVersion = semver.parse(`${nextVersion.major}.${nextVersion.minor}.0`)!;
let latestVersionBranch: string|null = null;
let releaseCandidateBranch: string|null = null;
@ -177,15 +182,21 @@ export async function findActiveVersionBranches(
// next version-branch as that one is supposed to be the latest active version-branch. If it
// is not, then an error will be thrown due to two FF/RC branches existing at the same time.
for (const {name, parsed} of branches) {
// It can happen that version branches that are more recent than the version in the next
// branch (i.e. `master`) have been created. We could ignore such branches silently, but
// it might actually be symptomatic for an outdated version in the `next` branch, or an
// It can happen that version branches have been accidentally created which are more recent
// than the release-train in the next branch (i.e. `master`). We could ignore such branches
// silently, but it might be symptomatic for an outdated version in the `next` branch, or an
// accidentally created branch by the caretaker. In either way we want to raise awareness.
if (semver.gte(parsed, nextVersion)) {
if (semver.gt(parsed, nextReleaseTrainVersion)) {
throw Error(
`Discovered unexpected version-branch that is representing a minor ` +
`version more recent than the one in the "${nextBranchName}" branch. Consider ` +
`deleting the branch, or check if the version in "${nextBranchName}" is outdated.`);
`Discovered unexpected version-branch "${name}" for a release-train that is ` +
`more recent than the release-train currently in the "${nextBranchName}" branch. ` +
`Please either delete the branch if created by accident, or update the outdated ` +
`version in the next branch (${nextBranchName}).`);
} else if (semver.eq(parsed, nextReleaseTrainVersion)) {
throw Error(
`Discovered unexpected version-branch "${name}" for a release-train that is already ` +
`active in the "${nextBranchName}" branch. Please either delete the branch if ` +
`created by accident, or update the version in the next branch (${nextBranchName}).`);
}
const version = await getVersionOfBranch(repo, name);

View File

@ -280,7 +280,21 @@ describe('default target labels', () => {
.toBeRejectedWithError('Invalid version detected in following branch: 11.1.x.');
});
it('should error if branch more recent than version in "next" branch is found', async () => {
it('should error if version-branch more recent than "next" is discovered', async () => {
interceptBranchVersionRequest('master', '11.2.0-next.0');
interceptBranchVersionRequest('11.3.x', '11.3.0-next.0');
interceptBranchVersionRequest('11.1.x', '11.1.5');
interceptBranchesListRequest(['11.1.x', '11.3.x']);
await expectAsync(getBranchesForLabel('target: lts', '10.2.x'))
.toBeRejectedWithError(
'Discovered unexpected version-branch "11.3.x" for a release-train that is ' +
'more recent than the release-train currently in the "master" branch. Please ' +
'either delete the branch if created by accident, or update the outdated version ' +
'in the next branch (master).');
});
it('should error if branch is matching with release-train in the "next" branch', async () => {
interceptBranchVersionRequest('master', '11.2.0-next.0');
interceptBranchVersionRequest('11.2.x', '11.2.0-next.0');
interceptBranchVersionRequest('11.1.x', '11.1.5');
@ -288,9 +302,9 @@ describe('default target labels', () => {
await expectAsync(getBranchesForLabel('target: lts', '10.2.x'))
.toBeRejectedWithError(
'Discovered unexpected version-branch that is representing a minor version more ' +
'recent than the one in the "master" branch. Consider deleting the branch, or check ' +
'if the version in "master" is outdated.');
'Discovered unexpected version-branch "11.2.x" for a release-train that is already ' +
'active in the "master" branch. Please either delete the branch if created by ' +
'accident, or update the version in the next branch (master).');
});
it('should allow merging PR only into patch branch with "target: patch"', async () => {

View File

@ -11,13 +11,11 @@ import {getConfig, getRepoBaseDir} from '../../utils/config';
import {error, green, info, promptConfirm, red, yellow} from '../../utils/console';
import {GitClient} from '../../utils/git';
import {GithubApiRequestError} from '../../utils/git/github';
import {GITHUB_TOKEN_GENERATE_URL} from '../../utils/yargs';
import {loadAndValidateConfig, MergeConfig, MergeConfigWithRemote} from './config';
import {loadAndValidateConfig, MergeConfigWithRemote} from './config';
import {MergeResult, MergeStatus, PullRequestMergeTask} from './task';
/** URL to the Github page where personal access tokens can be generated. */
export const GITHUB_TOKEN_GENERATE_URL = `https://github.com/settings/tokens`;
/**
* Merges a given pull request based on labels configured in the given merge configuration.

View File

@ -8,39 +8,23 @@
import {Arguments, Argv} from 'yargs';
import {error} from '../../utils/console';
import {addGithubTokenFlag} from '../../utils/yargs';
import {rebasePr} from './index';
/** URL to the Github page where personal access tokens can be generated. */
export const GITHUB_TOKEN_GENERATE_URL = `https://github.com/settings/tokens`;
/** The options available to the rebase command via CLI. */
export interface RebaseCommandOptions {
'github-token'?: string;
githubToken: string;
prNumber: number;
}
/** Builds the rebase pull request command. */
export function buildRebaseCommand(yargs: Argv): Argv<RebaseCommandOptions> {
return yargs
.option('github-token', {
type: 'string',
description: 'Github token. If not set, token is retrieved from the environment variables.'
})
.positional('prNumber', {type: 'number', demandOption: true});
return addGithubTokenFlag(yargs).positional('prNumber', {type: 'number', demandOption: true});
}
/** Handles the rebase pull request command. */
export async function handleRebaseCommand(args: Arguments<RebaseCommandOptions>) {
const githubToken = args['github-token'] || process.env.GITHUB_TOKEN || process.env.TOKEN;
if (!githubToken) {
error('No Github token set. Please set the `GITHUB_TOKEN` environment variable.');
error('Alternatively, pass the `--github-token` command line flag.');
error(`You can generate a token here: ${GITHUB_TOKEN_GENERATE_URL}`);
process.exit(1);
}
await rebasePr(args.prNumber, githubToken);
export async function handleRebaseCommand(
{prNumber, githubToken}: Arguments<RebaseCommandOptions>) {
await rebasePr(prNumber, githubToken);
}

View File

@ -12,14 +12,18 @@ ts_library(
"@npm//@octokit/graphql",
"@npm//@octokit/rest",
"@npm//@octokit/types",
"@npm//@types/fs-extra",
"@npm//@types/inquirer",
"@npm//@types/node",
"@npm//@types/shelljs",
"@npm//@types/yargs",
"@npm//chalk",
"@npm//fs-extra",
"@npm//inquirer",
"@npm//inquirer-autocomplete-prompt",
"@npm//shelljs",
"@npm//tslib",
"@npm//typed-graphqlify",
"@npm//yargs",
],
)

View File

@ -7,14 +7,19 @@
*/
import chalk from 'chalk';
import {writeFileSync} from 'fs-extra';
import {createPromptModule, ListChoiceOptions, prompt} from 'inquirer';
import * as inquirerAutocomplete from 'inquirer-autocomplete-prompt';
import {join} from 'path';
import {Arguments} from 'yargs';
import {getRepoBaseDir} from './config';
/** Reexport of chalk colors for convenient access. */
export const red: typeof chalk = chalk.red;
export const green: typeof chalk = chalk.green;
export const yellow: typeof chalk = chalk.yellow;
export const bold: typeof chalk = chalk.bold;
/** Prompts the user with a confirmation question and a specified message. */
export async function promptConfirm(message: string, defaultValue = false): Promise<boolean> {
@ -140,6 +145,7 @@ function runConsoleCommand(loadCommand: () => Function, logLevel: LOG_LEVELS, ..
if (getLogLevel() >= logLevel) {
loadCommand()(...text);
}
printToLogFile(logLevel, ...text);
}
/**
@ -155,3 +161,56 @@ function getLogLevel() {
}
return logLevel;
}
/** All text to write to the log file. */
let LOGGED_TEXT = '';
/** Whether file logging as been enabled. */
let FILE_LOGGING_ENABLED = false;
/**
* The number of columns used in the prepended log level information on each line of the logging
* output file.
*/
const LOG_LEVEL_COLUMNS = 7;
/**
* Enable writing the logged outputs to the log file on process exit, sets initial lines from the
* command execution, containing information about the timing and command parameters.
*
* This is expected to be called only once during a command run, and should be called by the
* middleware of yargs to enable the file logging before the rest of the command parsing and
* response is executed.
*/
export function captureLogOutputForCommand(argv: Arguments) {
if (FILE_LOGGING_ENABLED) {
throw Error('`captureLogOutputForCommand` cannot be called multiple times');
}
/** The date time used for timestamping when the command was invoked. */
const now = new Date();
/** Header line to separate command runs in log files. */
const headerLine = Array(100).fill('#').join('');
LOGGED_TEXT += `${headerLine}\nCommand: ${argv.$0} ${argv._.join(' ')}\nRan at: ${now}\n`;
// On process exit, write the logged output to the appropriate log files
process.on('exit', (code: number) => {
LOGGED_TEXT += `Command ran in ${new Date().getTime() - now.getTime()}ms`;
/** Path to the log file location. */
const logFilePath = join(getRepoBaseDir(), '.ng-dev.log');
writeFileSync(logFilePath, LOGGED_TEXT);
// For failure codes greater than 1, the new logged lines should be written to a specific log
// file for the command run failure.
if (code > 1) {
writeFileSync(join(getRepoBaseDir(), `.ng-dev.err-${now.getTime()}.log`), LOGGED_TEXT);
}
});
// Mark file logging as enabled to prevent the function from executing multiple times.
FILE_LOGGING_ENABLED = true;
}
/** Write the provided text to the log file, prepending each line with the log level. */
function printToLogFile(logLevel: LOG_LEVELS, ...text: string[]) {
const logLevelText = `${LOG_LEVELS[logLevel]}:`.padEnd(LOG_LEVEL_COLUMNS);
LOGGED_TEXT += text.join(' ').split('\n').map(l => `${logLevelText} ${l}\n`).join('');
}

View File

@ -86,10 +86,10 @@ export class GitClient {
/**
* Spawns a given Git command process. Does not throw if the command fails. Additionally,
* if there is any stderr output, the output will be printed. This makes it easier to
* debug failed commands.
* info failed commands.
*/
runGraceful(args: string[], options: SpawnSyncOptions = {}): SpawnSyncReturns<string> {
// To improve the debugging experience in case something fails, we print all executed
// To improve the infoging experience in case something fails, we print all executed
// Git commands. Note that we do not want to print the token if is contained in the
// command. It's common to share errors with others if the tool failed.
info('Executing: git', this.omitGithubTokenFromMessage(args.join(' ')));

37
dev-infra/utils/yargs.ts Normal file
View File

@ -0,0 +1,37 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Argv} from 'yargs';
import {error, red, yellow} from './console';
export type ArgvWithGithubToken = Argv<{githubToken: string}>;
export function addGithubTokenFlag(yargs: Argv): ArgvWithGithubToken {
return yargs
// 'github-token' is casted to 'githubToken' to properly set up typings to reflect the key in
// the Argv object being camelCase rather than kebob case due to the `camel-case-expansion`
// config: https://github.com/yargs/yargs-parser#camel-case-expansion
.option('github-token' as 'githubToken', {
type: 'string',
description: 'Github token. If not set, token is retrieved from the environment variables.',
coerce: (token: string) => {
const githubToken = token || process.env.GITHUB_TOKEN || process.env.TOKEN;
if (!githubToken) {
error(red('No Github token set. Please set the `GITHUB_TOKEN` environment variable.'));
error(red('Alternatively, pass the `--github-token` command line flag.'));
error(yellow(`You can generate a token here: ${GITHUB_TOKEN_GENERATE_URL}`));
process.exit(1);
}
return githubToken;
},
})
.default('github-token' as 'githubToken', '', '<LOCAL TOKEN>');
}
/** URL to the Github page where personal access tokens can be generated. */
export const GITHUB_TOKEN_GENERATE_URL = 'https://github.com/settings/tokens/new';

View File

@ -15,6 +15,6 @@ export class AppComponent {
constructor(private http: HttpClient) {}
time$: Observable<string> =
this.http.get('http://worldclockapi.com/api/json/pst/now')
.pipe(map((result: any) => result.currentDateTime), startWith(['...']));
this.http.get('http://worldtimeapi.org/api/timezone/America/Los_Angeles.json')
.pipe(map((result: any) => result.datetime), startWith(['...']));
}

View File

@ -1,6 +1,6 @@
{
"name": "angular-srcs",
"version": "10.1.0-rc.0",
"version": "10.1.0",
"private": true,
"description": "Angular - a web framework for modern web apps",
"homepage": "https://github.com/angular/angular",
@ -81,13 +81,14 @@
"@types/jasmine-ajax": "^3.3.1",
"@types/jasminewd2": "^2.0.8",
"@types/minimist": "^1.2.0",
"@types/multimatch": "^4.0.0",
"@types/node": "^12.11.1",
"@types/node-fetch": "^2.5.7",
"@types/selenium-webdriver": "3.0.7",
"@types/semver": "^6.0.2",
"@types/shelljs": "^0.8.6",
"@types/systemjs": "0.19.32",
"@types/yaml": "^1.2.0",
"@types/yaml": "^1.9.7",
"@types/yargs": "^15.0.5",
"@webcomponents/custom-elements": "^1.1.0",
"angular": "npm:angular@1.7",
@ -152,7 +153,7 @@
"tslint": "6.1.3",
"typescript": "~4.0.2",
"xhr2": "0.2.0",
"yaml": "^1.7.2",
"yaml": "^1.10.0",
"yargs": "^15.4.1"
},
"// 2": "devDependencies are not used under Bazel. Many can be removed after test.sh is deleted.",

View File

@ -2017,6 +2017,28 @@ export declare class AnimationEvent {
expect(diags.length).toBe(0);
});
it('should allow HTML elements without explicit namespace inside SVG foreignObject', () => {
env.write('test.ts', `
import {Component, NgModule} from '@angular/core';
@Component({
template: \`
<svg>
<foreignObject>
<div>Hello</div>
</foreignObject>
</svg>
\`,
})
export class FooCmp {}
@NgModule({
declarations: [FooCmp],
})
export class FooModule {}
`);
const diags = env.driveDiagnostics();
expect(diags.length).toBe(0);
});
it('should check for unknown elements inside an SVG foreignObject', () => {
env.write('test.ts', `
import {Component, NgModule} from '@angular/core';
@ -2042,6 +2064,33 @@ export declare class AnimationEvent {
1. If 'foo' is an Angular component, then verify that it is part of this module.
2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`);
});
it('should check for unknown elements without explicit namespace inside an SVG foreignObject',
() => {
env.write('test.ts', `
import {Component, NgModule} from '@angular/core';
@Component({
selector: 'blah',
template: \`
<svg>
<foreignObject>
<foo>Hello</foo>
</foreignObject>
</svg>
\`,
})
export class FooCmp {}
@NgModule({
declarations: [FooCmp],
})
export class FooModule {}
`);
const diags = env.driveDiagnostics();
expect(diags.length).toBe(1);
expect(diags[0].messageText).toBe(`'foo' is not a known element:
1. If 'foo' is an Angular component, then verify that it is part of this module.
2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`);
});
});
// Test both sync and async compilations, see https://github.com/angular/angular/issues/32538

View File

@ -17,6 +17,7 @@ export class HtmlTagDefinition implements TagDefinition {
isVoid: boolean;
ignoreFirstLf: boolean;
canSelfClose: boolean = false;
preventNamespaceInheritance: boolean;
constructor({
closedByChildren,
@ -24,14 +25,16 @@ export class HtmlTagDefinition implements TagDefinition {
contentType = TagContentType.PARSABLE_DATA,
closedByParent = false,
isVoid = false,
ignoreFirstLf = false
ignoreFirstLf = false,
preventNamespaceInheritance = false
}: {
closedByChildren?: string[],
closedByParent?: boolean,
implicitNamespacePrefix?: string,
contentType?: TagContentType,
isVoid?: boolean,
ignoreFirstLf?: boolean
ignoreFirstLf?: boolean,
preventNamespaceInheritance?: boolean
} = {}) {
if (closedByChildren && closedByChildren.length > 0) {
closedByChildren.forEach(tagName => this.closedByChildren[tagName] = true);
@ -41,6 +44,7 @@ export class HtmlTagDefinition implements TagDefinition {
this.implicitNamespacePrefix = implicitNamespacePrefix || null;
this.contentType = contentType;
this.ignoreFirstLf = ignoreFirstLf;
this.preventNamespaceInheritance = preventNamespaceInheritance;
}
isClosedByChild(name: string): boolean {
@ -88,6 +92,17 @@ export function getHtmlTagDefinition(tagName: string): HtmlTagDefinition {
'th': new HtmlTagDefinition({closedByChildren: ['td', 'th'], closedByParent: true}),
'col': new HtmlTagDefinition({isVoid: true}),
'svg': new HtmlTagDefinition({implicitNamespacePrefix: 'svg'}),
'foreignObject': new HtmlTagDefinition({
// Usually the implicit namespace here would be redundant since it will be inherited from
// the parent `svg`, but we have to do it for `foreignObject`, because the way the parser
// works is that the parent node of an end tag is its own start tag which means that
// the `preventNamespaceInheritance` on `foreignObject` would have it default to the
// implicit namespace which is `html`, unless specified otherwise.
implicitNamespacePrefix: 'svg',
// We want to prevent children of foreignObject from inheriting its namespace, because
// the point of the element is to allow nodes from other namespaces to be inserted.
preventNamespaceInheritance: true,
}),
'math': new HtmlTagDefinition({implicitNamespacePrefix: 'math'}),
'li': new HtmlTagDefinition({closedByChildren: ['li'], closedByParent: true}),
'dt': new HtmlTagDefinition({closedByChildren: ['dt', 'dd']}),
@ -111,5 +126,8 @@ export function getHtmlTagDefinition(tagName: string): HtmlTagDefinition {
{contentType: TagContentType.ESCAPABLE_RAW_TEXT, ignoreFirstLf: true}),
};
}
return TAG_DEFINITIONS[tagName.toLowerCase()] || _DEFAULT_TAG_DEFINITION;
// We have to make both a case-sensitive and a case-insesitive lookup, because
// HTML tag names are case insensitive, whereas some SVG tags are case sensitive.
return TAG_DEFINITIONS[tagName] ?? TAG_DEFINITIONS[tagName.toLowerCase()] ??
_DEFAULT_TAG_DEFINITION;
}

View File

@ -10,7 +10,7 @@ import {ParseError, ParseSourceSpan} from '../parse_util';
import * as html from './ast';
import * as lex from './lexer';
import {getNsPrefix, isNgContainer, mergeNsAndName, TagDefinition} from './tags';
import {getNsPrefix, mergeNsAndName, splitNsName, TagDefinition} from './tags';
export class TreeError extends ParseError {
static create(elementName: string|null, span: ParseSourceSpan, msg: string): TreeError {
@ -353,7 +353,11 @@ class _TreeBuilder {
if (prefix === '') {
prefix = this.getTagDefinition(localName).implicitNamespacePrefix || '';
if (prefix === '' && parentElement != null) {
prefix = getNsPrefix(parentElement.name);
const parentTagName = splitNsName(parentElement.name)[1];
const parentTagDefinition = this.getTagDefinition(parentTagName);
if (!parentTagDefinition.preventNamespaceInheritance) {
prefix = getNsPrefix(parentElement.name);
}
}
}

View File

@ -19,6 +19,7 @@ export interface TagDefinition {
isVoid: boolean;
ignoreFirstLf: boolean;
canSelfClose: boolean;
preventNamespaceInheritance: boolean;
isClosedByChild(name: string): boolean;
}

View File

@ -20,6 +20,7 @@ export class XmlTagDefinition implements TagDefinition {
isVoid: boolean = false;
ignoreFirstLf: boolean = false;
canSelfClose: boolean = true;
preventNamespaceInheritance: boolean = false;
requireExtraParent(currentParent: string): boolean {
return false;

View File

@ -52,23 +52,17 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn
// TODO(issue/24571): remove '!'.
_asyncValidators!: any[];
/**
* @description
* An internal callback method triggered on the instance after the inputs are set.
* Registers the group with its parent group.
*/
/** @nodoc */
ngOnInit(): void {
this._checkParentType();
// Register the group with its parent group.
this.formDirective!.addFormGroup(this);
}
/**
* @description
* An internal callback method triggered before the instance is destroyed.
* Removes the group from its parent group.
*/
/** @nodoc */
ngOnDestroy(): void {
if (this.formDirective) {
// Remove the group from its parent group.
this.formDirective.removeFormGroup(this);
}
}

View File

@ -47,14 +47,14 @@ export const CHECKBOX_VALUE_ACCESSOR: any = {
})
export class CheckboxControlValueAccessor implements ControlValueAccessor {
/**
* @description
* The registered callback function called when a change event occurs on the input element.
* @nodoc
*/
onChange = (_: any) => {};
/**
* @description
* The registered callback function called when a blur event occurs on the input element.
* @nodoc
*/
onTouched = () => {};
@ -62,28 +62,23 @@ export class CheckboxControlValueAccessor implements ControlValueAccessor {
/**
* Sets the "checked" property on the input element.
*
* @param value The checked value
* @nodoc
*/
writeValue(value: any): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'checked', value);
}
/**
* @description
* Registers a function called when the control value changes.
*
* @param fn The callback function
* @nodoc
*/
registerOnChange(fn: (_: any) => {}): void {
this.onChange = fn;
}
/**
* @description
* Registers a function called when the control is touched.
*
* @param fn The callback function
* @nodoc
*/
registerOnTouched(fn: () => {}): void {
this.onTouched = fn;
@ -91,8 +86,7 @@ export class CheckboxControlValueAccessor implements ControlValueAccessor {
/**
* Sets the "disabled" property on the input element.
*
* @param isDisabled The disabled value
* @nodoc
*/
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);

View File

@ -75,14 +75,14 @@ export const COMPOSITION_BUFFER_MODE = new InjectionToken<boolean>('CompositionE
})
export class DefaultValueAccessor implements ControlValueAccessor {
/**
* @description
* The registered callback function called when an input event occurs on the input element.
* @nodoc
*/
onChange = (_: any) => {};
/**
* @description
* The registered callback function called when a blur event occurs on the input element.
* @nodoc
*/
onTouched = () => {};
@ -99,8 +99,7 @@ export class DefaultValueAccessor implements ControlValueAccessor {
/**
* Sets the "value" property on the input element.
*
* @param value The checked value
* @nodoc
*/
writeValue(value: any): void {
const normalizedValue = value == null ? '' : value;
@ -108,20 +107,16 @@ export class DefaultValueAccessor implements ControlValueAccessor {
}
/**
* @description
* Registers a function called when the control value changes.
*
* @param fn The callback function
* @nodoc
*/
registerOnChange(fn: (_: any) => void): void {
this.onChange = fn;
}
/**
* @description
* Registers a function called when the control is touched.
*
* @param fn The callback function
* @nodoc
*/
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
@ -129,8 +124,7 @@ export class DefaultValueAccessor implements ControlValueAccessor {
/**
* Sets the "disabled" property on the input element.
*
* @param isDisabled The disabled value
* @nodoc
*/
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);

View File

@ -137,10 +137,7 @@ export class NgForm extends ControlContainer implements Form, AfterViewInit {
new FormGroup({}, composeValidators(validators), composeAsyncValidators(asyncValidators));
}
/**
* @description
* Lifecycle method called after the view is initialized. For internal use only.
*/
/** @nodoc */
ngAfterViewInit() {
this._setUpdateStrategy();
}

View File

@ -149,8 +149,8 @@ export class NgModel extends NgControl implements OnChanges, OnDestroy {
_registered = false;
/**
* @description
* Internal reference to the view model value.
* @nodoc
*/
viewModel: any;
@ -213,13 +213,7 @@ export class NgModel extends NgControl implements OnChanges, OnDestroy {
this.valueAccessor = selectValueAccessor(this, valueAccessors);
}
/**
* @description
* A lifecycle method called when the directive's inputs change. For internal use
* only.
*
* @param changes A object of key/value pairs for the set of changed inputs.
*/
/** @nodoc */
ngOnChanges(changes: SimpleChanges) {
this._checkForErrors();
if (!this._registered) this._setUpControl();
@ -233,11 +227,7 @@ export class NgModel extends NgControl implements OnChanges, OnDestroy {
}
}
/**
* @description
* Lifecycle method called before the directive's instance is destroyed. For internal
* use only.
*/
/** @nodoc */
ngOnDestroy(): void {
this.formDirective && this.formDirective.removeControl(this);
}

View File

@ -19,7 +19,7 @@ export const NUMBER_VALUE_ACCESSOR: any = {
/**
* @description
* The `ControlValueAccessor` for writing a number value and listening to number input changes.
* The value accessor is used by the `FormControlDirective`, `FormControlName`, and `NgModel`
* The value accessor is used by the `FormControlDirective`, `FormControlName`, and `NgModel`
* directives.
*
* @usageNotes
@ -48,15 +48,15 @@ export const NUMBER_VALUE_ACCESSOR: any = {
})
export class NumberValueAccessor implements ControlValueAccessor {
/**
* @description
* The registered callback function called when a change or input event occurs on the input
* element.
* @nodoc
*/
onChange = (_: any) => {};
/**
* @description
* The registered callback function called when a blur event occurs on the input element.
* @nodoc
*/
onTouched = () => {};
@ -64,8 +64,7 @@ export class NumberValueAccessor implements ControlValueAccessor {
/**
* Sets the "value" property on the input element.
*
* @param value The checked value
* @nodoc
*/
writeValue(value: number): void {
// The value needs to be normalized for IE9, otherwise it is set to 'null' when null
@ -74,10 +73,8 @@ export class NumberValueAccessor implements ControlValueAccessor {
}
/**
* @description
* Registers a function called when the control value changes.
*
* @param fn The callback function
* @nodoc
*/
registerOnChange(fn: (_: number|null) => void): void {
this.onChange = (value) => {
@ -86,10 +83,8 @@ export class NumberValueAccessor implements ControlValueAccessor {
}
/**
* @description
* Registers a function called when the control is touched.
*
* @param fn The callback function
* @nodoc
*/
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
@ -97,8 +92,7 @@ export class NumberValueAccessor implements ControlValueAccessor {
/**
* Sets the "disabled" property on the input element.
*
* @param isDisabled The disabled value
* @nodoc
*/
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);

View File

@ -112,14 +112,14 @@ export class RadioControlValueAccessor implements ControlValueAccessor, OnDestro
_fn!: Function;
/**
* @description
* The registered callback function called when a change event occurs on the input element.
* @nodoc
*/
onChange = () => {};
/**
* @description
* The registered callback function called when a blur event occurs on the input element.
* @nodoc
*/
onTouched = () => {};
@ -148,29 +148,21 @@ export class RadioControlValueAccessor implements ControlValueAccessor, OnDestro
private _renderer: Renderer2, private _elementRef: ElementRef,
private _registry: RadioControlRegistry, private _injector: Injector) {}
/**
* @description
* A lifecycle method called when the directive is initialized. For internal use only.
*/
/** @nodoc */
ngOnInit(): void {
this._control = this._injector.get(NgControl);
this._checkName();
this._registry.add(this._control, this);
}
/**
* @description
* Lifecycle method called before the directive's instance is destroyed. For internal use only.
*/
/** @nodoc */
ngOnDestroy(): void {
this._registry.remove(this);
}
/**
* @description
* Sets the "checked" property value on the radio input element.
*
* @param value The checked value
* @nodoc
*/
writeValue(value: any): void {
this._state = value === this.value;
@ -178,10 +170,8 @@ export class RadioControlValueAccessor implements ControlValueAccessor, OnDestro
}
/**
* @description
* Registers a function called when the control value changes.
*
* @param fn The callback function
* @nodoc
*/
registerOnChange(fn: (_: any) => {}): void {
this._fn = fn;
@ -201,10 +191,8 @@ export class RadioControlValueAccessor implements ControlValueAccessor, OnDestro
}
/**
* @description
* Registers a function called when the control is touched.
*
* @param fn The callback function
* @nodoc
*/
registerOnTouched(fn: () => {}): void {
this.onTouched = fn;
@ -212,8 +200,7 @@ export class RadioControlValueAccessor implements ControlValueAccessor, OnDestro
/**
* Sets the "disabled" property on the input element.
*
* @param isDisabled The disabled value
* @nodoc
*/
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);

View File

@ -52,15 +52,15 @@ export const RANGE_VALUE_ACCESSOR: StaticProvider = {
})
export class RangeValueAccessor implements ControlValueAccessor {
/**
* @description
* The registered callback function called when a change or input event occurs on the input
* element.
* @nodoc
*/
onChange = (_: any) => {};
/**
* @description
* The registered callback function called when a blur event occurs on the input element.
* @nodoc
*/
onTouched = () => {};
@ -68,18 +68,15 @@ export class RangeValueAccessor implements ControlValueAccessor {
/**
* Sets the "value" property on the input element.
*
* @param value The checked value
* @nodoc
*/
writeValue(value: any): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'value', parseFloat(value));
}
/**
* @description
* Registers a function called when the control value changes.
*
* @param fn The callback function
* @nodoc
*/
registerOnChange(fn: (_: number|null) => void): void {
this.onChange = (value) => {
@ -88,10 +85,8 @@ export class RangeValueAccessor implements ControlValueAccessor {
}
/**
* @description
* Registers a function called when the control is touched.
*
* @param fn The callback function
* @nodoc
*/
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
@ -99,8 +94,7 @@ export class RangeValueAccessor implements ControlValueAccessor {
/**
* Sets the "disabled" property on the range input element.
*
* @param isDisabled The disabled value
* @nodoc
*/
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);

View File

@ -54,8 +54,8 @@ export const formControlBinding: any = {
export class FormControlDirective extends NgControl implements OnChanges {
/**
* @description
* Internal reference to the view model value.
* @nodoc
*/
viewModel: any;
@ -116,13 +116,7 @@ export class FormControlDirective extends NgControl implements OnChanges {
this.valueAccessor = selectValueAccessor(this, valueAccessors);
}
/**
* @description
* A lifecycle method called when the directive's inputs change. For internal use
* only.
*
* @param changes A object of key/value pairs for the set of changed inputs.
*/
/** @nodoc */
ngOnChanges(changes: SimpleChanges): void {
if (this._isControlChanged(changes)) {
setUpControl(this.form, this);

View File

@ -65,7 +65,6 @@ export const controlNameBinding: any = {
export class FormControlName extends NgControl implements OnChanges, OnDestroy {
private _added = false;
/**
* @description
* Internal reference to the view model value.
* @internal
*/
@ -142,12 +141,7 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy {
this.valueAccessor = selectValueAccessor(this, valueAccessors);
}
/**
* @description
* A lifecycle method called when the directive's inputs change. For internal use only.
*
* @param changes A object of key/value pairs for the set of changed inputs.
*/
/** @nodoc */
ngOnChanges(changes: SimpleChanges) {
if (!this._added) this._setUpControl();
if (isPropertyUpdated(changes, this.viewModel)) {
@ -157,10 +151,7 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy {
}
}
/**
* @description
* Lifecycle method called before the directive's instance is destroyed. For internal use only.
*/
/** @nodoc */
ngOnDestroy(): void {
if (this.formDirective) {
this.formDirective.removeControl(this);

View File

@ -86,12 +86,7 @@ export class FormGroupDirective extends ControlContainer implements Form, OnChan
super();
}
/**
* @description
* A lifecycle method called when the directive's inputs change. For internal use only.
*
* @param changes A object of key/value pairs for the set of changed inputs.
*/
/** @nodoc */
ngOnChanges(changes: SimpleChanges): void {
this._checkFormPresent();
if (changes.hasOwnProperty('form')) {

View File

@ -165,10 +165,9 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy
}
/**
* @description
* A lifecycle method called when the directive's inputs are initialized. For internal use only.
*
* @throws If the directive does not have a valid parent.
* @nodoc
*/
ngOnInit(): void {
this._checkParentType();
@ -176,8 +175,8 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy
}
/**
* @description
* A lifecycle method called before the directive's instance is destroyed. For internal use only.
* @nodoc
*/
ngOnDestroy(): void {
if (this.formDirective) {

View File

@ -90,21 +90,24 @@ function _extractId(valueString: string): string {
providers: [SELECT_VALUE_ACCESSOR]
})
export class SelectControlValueAccessor implements ControlValueAccessor {
/** @nodoc */
value: any;
/** @internal */
_optionMap: Map<string, any> = new Map<string, any>();
/** @internal */
_idCounter: number = 0;
/**
* @description
* The registered callback function called when a change event occurs on the input element.
* @nodoc
*/
onChange = (_: any) => {};
/**
* @description
* The registered callback function called when a blur event occurs on the input element.
* @nodoc
*/
onTouched = () => {};
@ -128,8 +131,7 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
/**
* Sets the "value" property on the input element. The "selectedIndex"
* property is also set if an ID is provided on the option element.
*
* @param value The checked value
* @nodoc
*/
writeValue(value: any): void {
this.value = value;
@ -142,10 +144,8 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
}
/**
* @description
* Registers a function called when the control value changes.
*
* @param fn The callback function
* @nodoc
*/
registerOnChange(fn: (value: any) => any): void {
this.onChange = (valueString: string) => {
@ -155,10 +155,8 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
}
/**
* @description
* Registers a function called when the control is touched.
*
* @param fn The callback function
* @nodoc
*/
registerOnTouched(fn: () => any): void {
this.onTouched = fn;
@ -166,8 +164,7 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
/**
* Sets the "disabled" property on the select input element.
*
* @param isDisabled The disabled value
* @nodoc
*/
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
@ -247,10 +244,7 @@ export class NgSelectOption implements OnDestroy {
this._renderer.setProperty(this._element.nativeElement, 'value', value);
}
/**
* @description
* Lifecycle method called before the directive's instance is destroyed. For internal use only.
*/
/** @nodoc */
ngOnDestroy(): void {
if (this._select) {
this._select._optionMap.delete(this.id);

View File

@ -83,25 +83,26 @@ abstract class HTMLCollection {
})
export class SelectMultipleControlValueAccessor implements ControlValueAccessor {
/**
* @description
* The current value
* The current value.
* @nodoc
*/
value: any;
/** @internal */
_optionMap: Map<string, ɵNgSelectMultipleOption> = new Map<string, ɵNgSelectMultipleOption>();
/** @internal */
_idCounter: number = 0;
/**
* @description
* The registered callback function called when a change event occurs on the input element.
* @nodoc
*/
onChange = (_: any) => {};
/**
* @description
* The registered callback function called when a blur event occurs on the input element.
* @nodoc
*/
onTouched = () => {};
@ -123,11 +124,8 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor
constructor(private _renderer: Renderer2, private _elementRef: ElementRef) {}
/**
* @description
* Sets the "value" property on one or of more
* of the select's options.
*
* @param value The value
* Sets the "value" property on one or of more of the select's options.
* @nodoc
*/
writeValue(value: any): void {
this.value = value;
@ -147,11 +145,9 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor
}
/**
* @description
* Registers a function called when the control value changes
* and writes an array of the selected options.
*
* @param fn The callback function
* @nodoc
*/
registerOnChange(fn: (value: any) => any): void {
this.onChange = (_: any) => {
@ -181,10 +177,8 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor
}
/**
* @description
* Registers a function called when the control is touched.
*
* @param fn The callback function
* @nodoc
*/
registerOnTouched(fn: () => any): void {
this.onTouched = fn;
@ -192,8 +186,7 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor
/**
* Sets the "disabled" property on the select input element.
*
* @param isDisabled The disabled value
* @nodoc
*/
setDisabledState(isDisabled: boolean): void {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
@ -285,10 +278,7 @@ export class ɵNgSelectMultipleOption implements OnDestroy {
this._renderer.setProperty(this._element.nativeElement, 'selected', selected);
}
/**
* @description
* Lifecycle method called before the directive's instance is destroyed. For internal use only.
*/
/** @nodoc */
ngOnDestroy(): void {
if (this._select) {
this._select._optionMap.delete(this.id);

View File

@ -176,19 +176,17 @@ export class RequiredValidator implements Validator {
}
/**
* @description
* Method that validates whether the control is empty.
* Returns the validation result if enabled, otherwise null.
* @nodoc
*/
validate(control: AbstractControl): ValidationErrors|null {
return this.required ? Validators.required(control) : null;
}
/**
* @description
* Registers a callback function to call when the validator inputs change.
*
* @param fn The callback function
* @nodoc
*/
registerOnValidatorChange(fn: () => void): void {
this._onChange = fn;
@ -225,9 +223,9 @@ export class RequiredValidator implements Validator {
})
export class CheckboxRequiredValidator extends RequiredValidator {
/**
* @description
* Method that validates whether or not the checkbox has been checked.
* Returns the validation result if enabled, otherwise null.
* @nodoc
*/
validate(control: AbstractControl): ValidationErrors|null {
return this.required ? Validators.requiredTrue(control) : null;
@ -286,19 +284,17 @@ export class EmailValidator implements Validator {
}
/**
* @description
* Method that validates whether an email address is valid.
* Returns the validation result if enabled, otherwise null.
* @nodoc
*/
validate(control: AbstractControl): ValidationErrors|null {
return this._enabled ? Validators.email(control) : null;
}
/**
* @description
* Registers a callback function to call when the validator inputs change.
*
* @param fn The callback function
* @nodoc
*/
registerOnValidatorChange(fn: () => void): void {
this._onChange = fn;
@ -374,13 +370,7 @@ export class MinLengthValidator implements Validator, OnChanges {
@Input()
minlength!: string|number; // This input is always defined, since the name matches selector.
/**
* @description
* A lifecycle method called when the directive's inputs change. For internal use
* only.
*
* @param changes A object of key/value pairs for the set of changed inputs.
*/
/** @nodoc */
ngOnChanges(changes: SimpleChanges): void {
if ('minlength' in changes) {
this._createValidator();
@ -389,19 +379,17 @@ export class MinLengthValidator implements Validator, OnChanges {
}
/**
* @description
* Method that validates whether the value meets a minimum length
* requirement. Returns the validation result if enabled, otherwise null.
* Method that validates whether the value meets a minimum length requirement.
* Returns the validation result if enabled, otherwise null.
* @nodoc
*/
validate(control: AbstractControl): ValidationErrors|null {
return this.minlength == null ? null : this._validator(control);
}
/**
* @description
* Registers a callback function to call when the validator inputs change.
*
* @param fn The callback function
* @nodoc
*/
registerOnValidatorChange(fn: () => void): void {
this._onChange = fn;
@ -460,13 +448,7 @@ export class MaxLengthValidator implements Validator, OnChanges {
@Input()
maxlength!: string|number; // This input is always defined, since the name matches selector.
/**
* @description
* A lifecycle method called when the directive's inputs change. For internal use
* only.
*
* @param changes A object of key/value pairs for the set of changed inputs.
*/
/** @nodoc */
ngOnChanges(changes: SimpleChanges): void {
if ('maxlength' in changes) {
this._createValidator();
@ -475,19 +457,16 @@ export class MaxLengthValidator implements Validator, OnChanges {
}
/**
* @description
* Method that validates whether the value exceeds
* the maximum length requirement.
* Method that validates whether the value exceeds the maximum length requirement.
* @nodoc
*/
validate(control: AbstractControl): ValidationErrors|null {
return this.maxlength != null ? this._validator(control) : null;
}
/**
* @description
* Registers a callback function to call when the validator inputs change.
*
* @param fn The callback function
* @nodoc
*/
registerOnValidatorChange(fn: () => void): void {
this._onChange = fn;
@ -549,13 +528,7 @@ export class PatternValidator implements Validator, OnChanges {
@Input()
pattern!: string|RegExp; // This input is always defined, since the name matches selector.
/**
* @description
* A lifecycle method called when the directive's inputs change. For internal use
* only.
*
* @param changes A object of key/value pairs for the set of changed inputs.
*/
/** @nodoc */
ngOnChanges(changes: SimpleChanges): void {
if ('pattern' in changes) {
this._createValidator();
@ -564,19 +537,16 @@ export class PatternValidator implements Validator, OnChanges {
}
/**
* @description
* Method that validates whether the value matches the
* the pattern requirement.
* Method that validates whether the value matches the the pattern requirement.
* @nodoc
*/
validate(control: AbstractControl): ValidationErrors|null {
return this._validator(control);
}
/**
* @description
* Registers a callback function to call when the validator inputs change.
*
* @param fn The callback function
* @nodoc
*/
registerOnValidatorChange(fn: () => void): void {
this._onChange = fn;

View File

@ -1659,7 +1659,7 @@ export class FormGroup extends AbstractControl {
_throwIfControlMissing(name: string): void {
if (!Object.keys(this.controls).length) {
throw new Error(`
There are no form controls registered with this group yet. If you're using ngModel,
There are no form controls registered with this group yet. If you're using ngModel,
you may want to check next tick (e.g. use setTimeout).
`);
}
@ -2101,7 +2101,7 @@ export class FormArray extends AbstractControl {
_throwIfControlMissing(index: number): void {
if (!this.controls.length) {
throw new Error(`
There are no form controls registered with this array yet. If you're using ngModel,
There are no form controls registered with this array yet. If you're using ngModel,
you may want to check next tick (e.g. use setTimeout).
`);
}

View File

@ -2243,6 +2243,13 @@
resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6"
integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=
"@types/multimatch@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/multimatch/-/multimatch-4.0.0.tgz#e14237ade6cba7b79fe3a1a5d4e9579613cee6b6"
integrity sha512-xS26gtqY5QASmfU/6jb5vj7F0D0SctgRGtwXsKSNng1knk/OewjISlkMwGonkMCbZCqSoW3s6nL0sAtTlzbL/g==
dependencies:
multimatch "*"
"@types/node-fetch@^2.5.7":
version "2.5.7"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c"
@ -2347,10 +2354,12 @@
"@types/source-list-map" "*"
source-map "^0.6.1"
"@types/yaml@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@types/yaml/-/yaml-1.2.0.tgz#4ed577fc4ebbd6b829b28734e56d10c9e6984e09"
integrity sha512-GW8b9qM+ebgW3/zjzPm0I1NxMvLaz/YKT9Ph6tTb+Fkeyzd9yLTvQ6ciQ2MorTRmb/qXmfjMerRpG4LviixaqQ==
"@types/yaml@^1.9.7":
version "1.9.7"
resolved "https://registry.yarnpkg.com/@types/yaml/-/yaml-1.9.7.tgz#2331f36e0aac91311a63d33eb026c21687729679"
integrity sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==
dependencies:
yaml "*"
"@types/yargs-parser@*":
version "15.0.0"
@ -10714,7 +10723,7 @@ multicast-dns@^6.0.1:
dns-packet "^1.3.1"
thunky "^1.0.2"
multimatch@^4.0.0:
multimatch@*, multimatch@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3"
integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==
@ -16342,6 +16351,11 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yaml@*, yaml@^1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e"
integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==
yaml@^1.7.2:
version "1.8.3"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.8.3.tgz#2f420fca58b68ce3a332d0ca64be1d191dd3f87a"