Compare commits

..

80 Commits

Author SHA1 Message Date
5db7b4c354 release: cut the v10.1.6 release 2020-10-14 13:33:19 -07:00
e08d02145e fix(ngcc): ensure that "inline exports" can be interpreted correctly (#39272)
Previously, inline exports of the form `exports.foo = <implementation>;` were
being interpreted (by the ngtsc `PartialInterpeter`) as `Reference` objects.
This is not what is desired since it prevents the value of the export
from being unpacked, such as when analyzing `NgModule` declarations:

```
exports.directives = [Directive1, Directive2];

@NgImport({declarations: [exports.directives]})
class AppModule {}
```

In this example the interpreter would think that `exports.directives`
was a reference rather than an array that needs to be unpacked.

This bug was picked up by the ngcc-validation repository. See
https://github.com/angular/ngcc-validation/pull/1990 and
https://circleci.com/gh/angular/ngcc-validation/17130

PR Close #39272
2020-10-14 12:59:07 -07:00
dae3a77c43 refactor(compiler-cli): visit inline declarations with implementations differently (#39272)
Some inline declarations are of the form:

```
exports.<name> = <implementation>;
```

In this case the declaration `node` is `exports.<name>`.
When interpreting such inline declarations we actually want
to visit the `implementation` expression rather than visiting
the declaration `node`.

This commit adds `implementation?: ts.Expression` to the
`InlineDeclaration` type and updates the interpreter to visit
these expressions as described above.

PR Close #39272
2020-10-14 12:59:07 -07:00
02e75df3e7 refactor(compiler-cli): ensure isNamed....() helpers check name is identity (#38959) (#39272)
Previously the `node.name` property was only checked to ensure it was
defined. But that meant that it was a `ts.BindingName`, which also includes
`ts.BindingPattern`, which we do not support. But these helper methods were
forcefully casting the value to `ts.Identifier.

Now we also check that the `node.name` is actually an `ts.Identifier`.

PR Close #38959

PR Close #39272
2020-10-14 12:59:07 -07:00
f752ab9367 fix(compiler-cli): support namespaced query types in directives (#38959) (#39272)
Previously directive "queries" that relied upon a namespaced type

```ts
queries: {
  'mcontent': new core.ContentChild('test2'),
}
```

caused an error to be thrown. This is now supported.

PR Close #38959

PR Close #39272
2020-10-14 12:59:07 -07:00
9c875b30dc fix(ngcc): support inline export declarations in UMD files (#38959) (#39272)
Previously, any declarations that were defined "inline" were not
recognised by the `UmdReflectionHost`.

For example, the following syntax was completely unrecognized:

```ts
var Foo_1;
exports.Foo = Foo_1 = (function() {
  function Foo() {}
  return Foo;
})();
exports.Foo = Foo_1 = __decorate(SomeDecorator, Foo);
```

Such inline classes were ignored and not processed by ngcc.

This lack of processing led to failures in Ivy applications that relied
on UMD formats of libraries such as `syncfusion/ej2-angular-ui-components`.

Now all known inline UMD exports are recognized and processed accordingly.

Fixes #38947

PR Close #38959

PR Close #39272
2020-10-14 12:59:07 -07:00
8fa78d10ab test(ngcc): use isNamedDeclaration() helper to simplify tests (#38959) (#39272)
Previously these tests were checking multiple specific expression
types. The new helper function is more general and will also support
`PropertyAccessExpression` nodes for `InlineDeclaration` types.

PR Close #38959

PR Close #39272
2020-10-14 12:59:07 -07:00
26988f0d62 refactor(compiler-cli): implement DeclarationNode node type (#38959) (#39272)
Previously the `ConcreteDeclaration` and `InlineDeclaration` had
different properties for the underlying node type. And the `InlineDeclaration`
did not store a value that represented its declaration.

It turns out that a natural declaration node for an inline type is the
expression. For example in UMD/CommonJS this would be the `exports.<name>`
property access node.

So this expression is now used for the `node` of `InlineDeclaration` types
and the `expression` property is dropped.

To support this the codebase has been refactored to use a new `DeclarationNode`
type which is a union of `ts.Declaration|ts.Expression` instead of `ts.Declaration`
throughout.

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
6acf117386 test(ngcc): use isNamedFunctionDeclaration() in UMD tests (#38959) (#39272)
This makes these tests more resilient to changes in the test code
structure. For example switching from

```
var SomeClass = <implementation>;
exports.SomeClass = SomeClass;
```

to

```
exports.SomeClass = <implementation>;
```

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
8b731e374d test(compiler-cli): make the getDeclaration() utility more resilient to code format (#38959) (#39272)
Previously `getDeclaration()` would only return the first node that matched
the name passed in and then assert the predicate on this single node.
It also only considered a subset of possible declaration types that we might
care about.

Now the function will parse the whole tree collecting an array of all the
nodes that match the name. It then filters this array based on the predicate
and only errors if the filtered array is empty.

This makes this function much more resilient to more esoteric code formats
such as UMD.

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
5378f78e79 refactor(ngcc): simplify and break up ES2015 functions with helpers (#38959) (#39272)
The protected helper functions can then be overridden by subclasses of the
Esm2015ReflectionHost.

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
495c40e31c refactor(ngcc): simplify and rename getClassDeclarationFromInnerDeclaration() (#38959) (#39272)
The new function does not try to restrict the kind of AST node that it
finds, leaving that to the caller. This will make it more resuable in the
UMD reflection host.

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
9963c5d8f7 fix(ngcc): handle aliases in UMD export declarations (#38959) (#39272)
Sometimes UMD exports appear in the following form:

```
exports.MyClass = alias1 = alias2 = <<declaration>>
```

Previously the declaration of the export would have been captured
as `alias1 = alias2 = <<declaration>>`, which the `PartialInterpreter`
would have failed on, since it cannot handle assignments.

Now we skip over these aliases capturing only the `<<declaration>>`
expression.

Fixes #38947

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
13c4a7b1da fix(ngcc): map exports to the current module in UMD files (#38959) (#39272)
UMD files export values by assigning them to an `exports` variable.
When evaluating expressions ngcc was failing to cope with expressions
like `exports.MyComponent`.

This commit fixes the `UmdReflectionHost.getDeclarationOfIdentifier()`
method to map the `exports` variable to the current source file.

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
70e85d226c test(ngcc): fix incorrect test setup (#38959) (#39272)
The `SIMPLE_CLASS_FILE` contained a `ChildClass` that had an
internal aliases implementation and extended a `SuperClass` base
class. The call to `__extends` was using the wrong argument for
the child class.

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
dfb129dbfa refactor(compiler-cli): move map creation to avoid unnecessary work (#38959) (#39272)
If the `symbol` for the given `node` does not exist then there is no
point in creating the `map`.

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
1a1407aef6 refactor(ngcc): rename ExportStatement to ExportsStatement (#38959) (#39272)
This clarifies that this is specifically about statements of the form
`exports.<name> = <declaration>`, rather than a general export
statement such as `export class <ClassName> { ... }`.

PR Close #38959

PR Close #39272
2020-10-14 12:59:05 -07:00
da71f76a6a refactor(ngcc): remove unused imports (#38959) (#39272)
The `isAssignment` and `isAssignmentStatement` are not used in this file.

PR Close #38959

PR Close #39272
2020-10-14 12:59:05 -07:00
0c9b76e9e7 refactor(compiler-cli): remove unnecessary constraint on isDeclarationReference() (#38959) (#39272)
There is no need to check that the `ref.node` is of any particular type
because immediately after this check the entry is tested to see if it passes
`isClassDeclarationReference()`.

The only difference is that the error that is reported is slightly different
in the case that it is a `ref` but not one of the TS node types.

Previously:

```
`Value at position ${idx} in the NgModule.${arrayName} of ${
                className} is not a reference`
```

now

```
`Value at position ${idx} in the NgModule.${arrayName} of ${
                  className} is not a class`
```

Arguably the previous message was wrong, since this entry IS a reference
but is not a class.

PR Close #38959

PR Close #39272
2020-10-14 12:59:05 -07:00
db34b23ab5 test(compiler-cli): improve error message if a unit test is bad (#38959) (#39272)
The message now also reports the name of the predicate function
that failed.

PR Close #38959

PR Close #39272
2020-10-14 12:59:05 -07:00
df0941554b docs: add Discord as an official communication channel (#39149)
PR Close #39149
2020-10-14 10:23:16 -07:00
5221df8e92 perf(ngcc): do not rescan program source files when referenced from multiple root files (#39254)
When ngcc is configured to run with the `--use-program-dependencies`
flag, as is the case in the CLI's asynchronous processing, it will scan
all source files in the program, starting from the program's root files
as configured in the tsconfig. Each individual root file could
potentially rescan files that had already been scanned for an earlier
root file, causing a severe performance penalty if the number of root
files is large. This would be the case if glob patterns are used in the
"include" specification of a tsconfig file.

This commit avoids the performance penalty by keeping track of the files
that have been scanned across all root files, such that no source file
is scanned multiple times.

Fixes #39240

PR Close #39254
2020-10-14 09:34:11 -07:00
bc35c6a8ed refactor(dev-infra): Adjust caretaker queries (#39257)
- The current initial triage does not include PRs. This includes them by removing the issue filter
- The merge assistance label is often applied to PRs that do not have
status=success. Caretaker should handle these as well

PR Close #39257
2020-10-14 09:07:05 -07:00
23fc2b43ac updated sajee's profile (#39019)
PR Close #39019
2020-10-13 14:59:04 -07:00
c16995eb59 docs: fix typo in the Reactive Forms guide #5 (#39245)
PR Close #39245
2020-10-13 13:38:29 -07:00
3487d5a13a docs: move Inputs and Outputs topic to Components section (#38984)
PR Close #38984
2020-10-12 12:40:50 -07:00
1efc75cd72 fix(dev-infra): detect all commit message keywords that can close a PR (#39229)
Previously, the `isCommitClosingPullRequest()` method (used in
`ng-dev release` to detect whether a commit is closing a PR based on
keywords found in the commit message) was only able to detect a subset
of the keywords supported by GitHub.

This is fine currently, because the merge script adds `PR Close #XYZ`
when merging a PR, but it might break in the future.

This commit makes the code more robust by ensuring the method can detect
all keywords supported by GitHub for automatically closing a PR based on
a commit message.

Original discussion:
https://github.com/angular/angular/pull/39135#discussion_r503440973

PR Close #39229
2020-10-12 12:02:49 -07:00
c4190e3142 fix(dev-infra): fix error message in invokeSetNpmDistCommand() function (#39229)
In #39135, the commit message string was accidentally changed from a
template literal to a regular string literal. This prevented the
`npmDistTag` variable from being correctly displayed in the error
message.

This commit fixes it by switching it back to a template literal.

NOTE:
This was pointed out in
https://github.com/angular/angular/pull/39135#discussion_r503361412, but
the PR was accidentally merged before the review feedback had been
addressed.

PR Close #39229
2020-10-12 12:02:49 -07:00
5d98834585 fix(dev-infra): correctly check for commit that closes PR (#39135)
The `ng-dev release publish` command needs to check whether a commit
closed a pull request. This is implemented via checking the commit
message for specific closing keywords referencing the pull request
number.

The regex used previously failed to correctly ensure that the specified
pull request was referenced. For example, it would allow `#12345` to
also match for `#1234`.

This commit fixes the regex.

PR Close #39135
2020-10-12 10:47:14 -07:00
529ff73200 refactor(dev-infra): several code style and typo fixes (#39135)
This commit addresses comments from [my review][1] on PR #38656 (which
was merged without comments addressed). The changes are mostly related
to code style and typos.

[1]: https://github.com/angular/angular/pull/38656#pullrequestreview-482129333

PR Close #39135
2020-10-12 10:47:14 -07:00
791205005c refactor(animations): do not assign to innerHTML (#37397)
This should not change behavior, but it prevents false-positive warnings in various static analysis
tools, including tools used internally at Google.

PR Close #37397
2020-10-12 10:45:00 -07:00
2d37e47e95 build(docs-infra): support passing args to ng serve via serve-and-sync (#39201)
When working on the docs, it is helpful to run a local instance of the
angular.io app and run scripts that watch both the docs contents and the
app build artifacts to automatically update the running instance on
changes. Typically, this is achieved via the `start` and `docs-watch`
npm scripts. As a convenience, one can run the `serve-and-sync` script,
which runs both in one terminal.

Previously, it was not possible to pass arguments to `ng nerve` (which
is what the `start` script runs under the hood) when running it via
`serve-and-sync`.

This commit adds support for passing any arguments passed to
`serve-and-sync` through to the `start` script. This can be useful for
things like specifying a custom host or port.

PR Close #39201
2020-10-12 08:27:01 -07:00
27c8066641 docs: add linkable section about updating commit messages in CONTRIBUTING.md (#39215)
A common review request is updating the commit message of a commit.
Since this is something that is not straight forward for inexperienced
contributors, it is useful to be able to point a contributor to some
docs outlining the process.

This commit adds such a section in `CONTRIBUTING.md` (as discussed in
https://github.com/angular/angular/pull/39110#discussion_r499935502).

PR Close #39215
2020-10-12 08:26:09 -07:00
952fd8662c fix(elements): detect matchesSelector prototype without IIFE (#37799)
Although in SSR we patch the global prototypes with DOM globals
like Element and Node, this patch does not occur before the
matches function is called in Angular Elements. This is similar
to the behavior in @angular/upgrade.

Fixes #24551

PR Close #37799
2020-10-09 10:02:25 -07:00
42be9047d8 feat(dev-infra): Add github links to caretaker checks (#39185)
This commit adds links to the PR/Issue for queries in the caretaker check.

PR Close #39185
2020-10-09 09:39:33 -07:00
52a0c6b36e fix(compiler): incorrectly encapsulating @import containing colons and semicolons (#38716)
At a high level, the current shadow DOM shim logic works by escaping the content of a CSS rule
(e.g. `div {color: red;}` becomes `div {%BLOCK%}`), using a regex to parse out things like the
selector and the rule body, and then re-adding the content after the selector has been modified.
The problem is that the regex has to be very broad in order capture all of the different use cases,
which can cause it to match strings suffixed with a semi-colon in some places where it shouldn't,
like this URL from Google Fonts `https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&display=swap`.
Most of the time this is fine, because the logic that escapes the rule content to `%BLOCK%` will
have converted it to something that won't be matched by the regex. However, it breaks down for rules
like `@import` which don't have a body, but can still have quoted content with characters that can
match the regex.

These changes resolve the issue by making a second pass over the escaped string and replacing all
of the remaining quoted content with `%QUOTED%` before parsing it with the regex. Once everything
has been processed, we make a final pass where we restore the quoted content.

In a previous iteration of this PR, I went with a shorter approach which narrowed down the
regex so that it doesn't capture rules without a body. It fixed the issue, but it also ended
up breaking some of the more contrived unit test cases. I decided not to pursue it further, because
we would've ended up with a very long and brittle regex that likely would've broken in even weirder
ways.

Fixes #38587.

PR Close #38716
2020-10-09 08:33:05 -07:00
8913aee527 build: bump Chromium to next stable version: 84.0.4147 (#39179)
Bump Chrome to the next stable release (84.0.4147) by following the
instructions in dev-infra/browsers/README.md.

With Chrome 86 about to be released as stable, the current local version
(Chrome 83) is starting to lag behind. It also contains a bug that
blocks Angular unit and integration tests from using Trusted Types.

PR Close #39179
2020-10-09 07:53:12 -07:00
7628c36f49 build: upgrade angular build, integration/bazel and @angular/bazel package to rule_nodejs 2.2.0 (#39182)
Updates to rules_nodejs 2.2.0. This is the first major release in 7 months and includes a number of features as well
as breaking changes.

Release notes: https://github.com/bazelbuild/rules_nodejs/releases/tag/2.0.0

Features of note for angular/angular:

* stdout/stderr/exit code capture; this could be potentially be useful

* TypeScript (ts_project); a simpler tsc rule that ts_library that can be used in the repo where ts_library is too
  heavy weight

Breaking changes of note for angular/angular:

* loading custom rules from npm packages: `ts_library` is no longer loaded from `@npm_bazel_typescript//:index.bzl`
  (which no longer exists) but is now loaded from `@npm//@bazel/typescript:index.bzl`

* with the loading changes above, `load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")` is
  no longer needed in the WORKSPACE which also means that yarn_install does not need to run unless building/testing
  a target that depends on @npm. In angular/angular this is a minor improvement as almost everything depends on @npm.

* @angular/bazel package is also updated in this PR to support the new load location; Angular + Bazel users that
  require it for ng_package (ng_module is no longer needed in OSS with Angular 10) will need to load from
  `@npm//@angular/bazel:index.bzl`. I investigated if it was possible to maintain backward compatability for the old
  load location `@npm_angular_bazel` but it is not since the package itself needs to be updated to load from
  `@npm//@bazel/typescript:index.bzl` instead of `@npm_bazel_typescript//:index.bzl` as it depends on ts_library
  internals for ng_module.

* runfiles.resolve will now throw instead of returning undefined to match behavior of node require

Other changes in angular/angular:

* integration/bazel has been updated to use both ng_module and ts_libary with use_angular_plugin=true.
  The latter is the recommended way for rules_nodejs users to compile Angular 10 with Ivy. Bazel + Angular ViewEngine is
  supported with @angular/bazel <= 9.0.5 and Angular <= 8. There is still Angular ViewEngine example on rules_nodejs
  https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular_view_engine on these older versions but users
  that want to update to Angular 10 and are on Bazel must switch to Ivy and at that point ts_library with
  use_angular_plugin=true is more performant that ng_module. Angular example in rules_nodejs is configured this way
  as well: https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular. As an aside, we also have an
  example of building Angular 10 with architect() rule directly instead of using ts_library with angular plugin:
  https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular_bazel_architect.

NB: ng_module is still required for angular/angular repository as it still builds ViewEngine & @angular/bazel
also provides the ng_package rule. ng_module can be removed in the future if ViewEngine is no longer needed in
angular repo.

* JSModuleInfo provider added to ng_module. this is for forward compat for future rules_nodejs versions.

PR Close #39182
2020-10-08 11:55:00 -07:00
b417dd7b9c docs: fix for HttpRequest expansion panel (#39166)
Fixes #39156

PR Close #39166
2020-10-08 09:38:10 -07:00
8cf16b4815 feat(docs-infra): add short url for strict mode guide (#39129)
With this change we add a short url to strict mode guide
(angular.io/strict -> angular.io/guide/strict-mode). This is important because
of two reasons.

1) Reduce the clutter in the terminal when we include the strict mode guide url in a prompt.
2) Easiler to share in conferences, slides etc..

PR Close #39129
2020-10-08 08:45:03 -07:00
806aed63f4 test(compiler-cli): temporarily disable integrationtest (#39168)
Temporarily disable the //packages/compiler-cli/integrationtest:integrationtest
target while continuing to investigate its unknown failures

PR Close #39168
2020-10-08 08:43:49 -07:00
eb34037cd7 Revert "refactor(compiler-cli): wrap RHS of property write in parens (#39143)" (#39171)
This reverts commit ba0df5250f.
Causes CI failures

PR Close #39171
2020-10-07 16:09:07 -07:00
ba0df5250f refactor(compiler-cli): wrap RHS of property write in parens (#39143)
The right needs to be wrapped in parens or we cannot accurately match its
span to just the RHS. For example, the span in `e = $event /*0,10*/` is ambiguous.
It could refer to either the whole binary expression or just the RHS.
We should instead generate `e = ($event /*0,10*/)` so we know the span 0,10 matches RHS.
This is specifically needed for the TemplateTypeChecker/Language Service
when mapping template positions to items in the TCB.

PR Close #39143
2020-10-07 14:49:47 -07:00
c4553bbed9 release: cut the v10.1.5 release 2020-10-07 14:20:12 -07:00
cc13b37446 build(docs-infra): render optional decorator options with a ? (#39167)
Decorator API pages list all their available options in an overview
table and also in a detailed view. Now the rendered syntax of each
option will show a `?` after the name if the option is not required.
This is inline with how class and interface members are rendered.

PR Close #39167
2020-10-07 13:33:26 -07:00
166df5d2ca refactor(common): remove i (ignore case) regex flag where it is not needed (#39077)
It is not necessary to set IGNORECASE flag when the regex pattern does
not contain alphabetic characters

PR Close #39077
2020-10-07 13:32:00 -07:00
a5b474580c docs: change heading to a sub-heading (#39131)
This commit changes the heading of the section
`Use TypeScript path mapping for peer dependencies` to a sub-heading of
`Linked Libraries`.

Fixes #39130

PR Close #39131
2020-10-07 13:31:24 -07:00
9f132d0d93 docs: remove explicit boolean type in examples as TS infers it automatically (#39081)
In the `packages/examples/common/ngif/module.ts` file, the field `show` is given an explicit
boolean type. Since typescript infers boolean type, it is redundant and this commit removes it.

PR Close #39081
2020-10-06 08:39:02 -07:00
8dee378b3e docs: add info about working with fixup commits (#39110)
Using fixup commits when addressing review feedback can considerably
improve the review experience on subsequent reviews.

This commit adds information and guidelines for contributors on how to
work with fixup commits.

Fixes #33042

PR Close #39110
2020-10-06 08:38:35 -07:00
0845d1148f build: update bazelversion (#39123)
Updates to the latest version of bazel

PR Close #39123
2020-10-05 17:08:08 -07:00
7cfa57a5f7 ci: use larger resource classes for bazel builds (#39124)
Migrates to using larger resource classes for windows CI runs as well as updating
the bazel rcs for windows and linux to use all/more of the resources available in
the executors

PR Close #39124
2020-10-05 17:06:49 -07:00
f80c22002b test(compiler): add tests for parsing of malformed property reads (#38998)
The expression parser already has support for recovering on malformed
property reads, but did not have tests describing the recovered ast in
such cases. This commit adds tests to demonstrate such cases; in
particular, the recovered ast is a full PropertyRead but with an empty
property name. This is likely the most preferred option, as it does not
constrain consumers of the AST to what the property name should look
like. Furthermore, we cannot mark the property name as empty in any
other way (e.g. an EmptyExpr) because the property name, as of present,
is a string field rather than an AST itself.

Note that tokens past a malformed property read are not preserved in the
AST (for example in `foo.1234`, `1234` is not preserved in the AST).
This is because the extra tokens do not belong to the singular
expression created by the property read, and there is not a meaningful
way to interpret a secondary expression in a single parsed expression.

Part of #38596

PR Close #38998
2020-10-05 14:24:47 -07:00
7aa12412f3 docs: Migrate section, view encapsulation, from Component Styles topic into its own topic. (#38986)
PR Close #38986
2020-10-05 13:23:41 -07:00
072b707b38 ci: update to latest version of sauce-connect (#39073)
Update to the latest version of sauce-connect, 4.6.2.

PR Close #39073
2020-10-05 12:53:28 -07:00
223b80cb7d docs(common): update docs for HttpClient methods (#38878)
PR Close #38878
2020-10-05 12:43:48 -07:00
416403fc63 docs: Made a minor change in the documentation (#38917)
PR Close #38917
2020-10-05 12:43:15 -07:00
878e2f0deb feat(dev-infra): show CI status of all active release trains (#39067)
As part of the ng-dev caretaker check command, show the status of the
lastest CircleCI run for each active release train.

PR Close #39067
2020-10-05 10:23:34 -07:00
4c30f5135b docs(upgrade): expand upon change detection implications for downgraded components (#39100)
PR Close #39100
2020-10-05 08:08:31 -07:00
6791cd79af refactor(compiler): iteratively parse interpolations (#38977)
This patch refactors the interpolation parser to do so iteratively
rather than using a regex. Doing so prepares us for supporting granular
recovery on poorly-formed interpolations, for example when an
interpolation does not terminate (`{{ 1 + 2`) or is not terminated
properly (`{{ 1 + 2 {{ 2 + 3 }}`).

Part of #38596

PR Close #38977
2020-10-02 15:13:24 -07:00
f50313f54d feat(compiler): Recover on malformed keyed reads and keyed writes (#39004)
This patch adds support for recovering well-formed (and near-complete)
ASTs for semantically malformed keyed reads and keyed writes. See the
added tests for details on the types of semantics we can now recover;
in particular, notice that some assumptions are made about the form of
a keyed read/write intended by a user. For example, in the malformed
expression `a[1 + = 2`, we assume that the user meant to write a binary
expression for the key of `a`, and assign that key the value `2`. In
particular, we now parse this as `a[1 + <empty expression>] = 2`. There
are some different interpretations that can be made here, but I think
this is reasonable.

The actual changes in the parser code are fairly minimal (a nice
surprise!); the biggest addition is a `writeContext` that marks whether
the `=` operator can serve as a recovery point after error detection.

Part of #38596

PR Close #39004
2020-10-02 11:37:03 -07:00
30433a0710 fix(docs-infra): better distinguish wrapped headings from other entries in TOC (#39092)
Previously, when a heading was longer than the Table of Content's  (TOC)
width and it had to be wrapped into multiple lines, it was hard to
distinguish the subsequent lines from other TOC entries (i.e. other
headings).

This commit makes it easier to visually distinguish wrapped heading
lines from other headings by reducing the spacing between wrapped lines
of the same heading (making it more obvious that they belong together).

PR Close #39092
2020-10-02 10:59:41 -07:00
86ab9f92b4 Revert "build: upgrade angular build, integration/bazel and @angular/bazel package to rule_nodejs 2.2.0 (#37727)" (#39097)
This reverts commit db56cf18ba.

PR Close #39097
2020-10-02 10:56:53 -07:00
42f9679376 build: upgrade angular build, integration/bazel and @angular/bazel package to rule_nodejs 2.2.0 (#37727)
Updates to rules_nodejs 2.2.0. This is the first major release in 7 months and includes a number of features as well
as breaking changes.

Release notes: https://github.com/bazelbuild/rules_nodejs/releases/tag/2.0.0

Features of note for angular/angular:

* stdout/stderr/exit code capture; this could be potentially be useful

* TypeScript (ts_project); a simpler tsc rule that ts_library that can be used in the repo where ts_library is too
  heavy weight

Breaking changes of note for angular/angular:

* loading custom rules from npm packages: `ts_library` is no longer loaded from `@npm_bazel_typescript//:index.bzl`
  (which no longer exists) but is now loaded from `@npm//@bazel/typescript:index.bzl`

* with the loading changes above, `load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")` is
  no longer needed in the WORKSPACE which also means that yarn_install does not need to run unless building/testing
  a target that depends on @npm. In angular/angular this is a minor improvement as almost everything depends on @npm.

* @angular/bazel package is also updated in this PR to support the new load location; Angular + Bazel users that
  require it for ng_package (ng_module is no longer needed in OSS with Angular 10) will need to load from
  `@npm//@angular/bazel:index.bzl`. I investigated if it was possible to maintain backward compatability for the old
  load location `@npm_angular_bazel` but it is not since the package itself needs to be updated to load from
  `@npm//@bazel/typescript:index.bzl` instead of `@npm_bazel_typescript//:index.bzl` as it depends on ts_library
  internals for ng_module.

* runfiles.resolve will now throw instead of returning undefined to match behavior of node require

Other changes in angular/angular:

* integration/bazel has been updated to use both ng_module and ts_libary with use_angular_plugin=true.
  The latter is the recommended way for rules_nodejs users to compile Angular 10 with Ivy. Bazel + Angular ViewEngine is
  supported with @angular/bazel <= 9.0.5 and Angular <= 8. There is still Angular ViewEngine example on rules_nodejs
  https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular_view_engine on these older versions but users
  that want to update to Angular 10 and are on Bazel must switch to Ivy and at that point ts_library with
  use_angular_plugin=true is more performant that ng_module. Angular example in rules_nodejs is configured this way
  as well: https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular. As an aside, we also have an
  example of building Angular 10 with architect() rule directly instead of using ts_library with angular plugin:
  https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular_bazel_architect.

NB: ng_module is still required for angular/angular repository as it still builds ViewEngine & @angular/bazel
also provides the ng_package rule. ng_module can be removed in the future if ViewEngine is no longer needed in
angular repo.

* JSModuleInfo provider added to ng_module. this is for forward compat for future rules_nodejs versions.
  @josephperrott, this touches `packages/bazel/src/external.bzl` which will make the sync to g3 non-trivial.

PR Close #37727
2020-10-01 15:34:37 -07:00
bee10574d8 ci: update g3 synced file list (#39084) (#39087)
Update the list of files synced into g3

PR Close #39087
2020-10-01 15:33:17 -07:00
afce0f5038 fix(dev-infra): correct matching logic for g3 comparison (#39084) (#39087)
Corrects the matching logic for g3 comparison check, previously more matches were
found than were correct.

PR Close #39087
2020-10-01 15:33:17 -07:00
bb19e61848 feat(dev-infra): add a command to verify NgBot YAML config syntax (#39071)
This commit adds a new command to the `ng-dev` suite, which verifies that the NgBot YAML config is
correct. It also adds this command to the `lint` CircleCI job so that we execute this check while
running CI.

This should help prevent syntax errors similar to the one introduced in:
393ce5574b

PR Close #39071
2020-10-01 12:31:45 -07:00
50e83e2566 refactor(docs-infra): leave TODO comments for aligning tslint with CLI (#39018)
This commit adds some TODO comments in `tslint.json` regardling rules
that need to be enabled or removed to more closely align `tslint.json`
with the one generated by the latest Angular CLI for new apps.

Updating these rules generates a lot of linting failures, so fixing
them is outside the scope of this PR.

PR Close #39018
2020-10-01 09:32:58 -07:00
d80c4890be build(docs-infra): remove the only-arrow-functions tslint rule to align with CLI (#39018)
This commit removes the `only-arrow-functions: false` tslint rule to
more closely align `tslint.json` with the one generated by the latest
Angular CLI for new apps.

PR Close #39018
2020-10-01 09:32:58 -07:00
4f8b716c13 build(docs-infra): update the object-literal-key-quotes tslint rule to align with CLI (#39018)
This commit updates the `object-literal-key-quotes` tslint rule to more
closely align `tslint.json` with the one generated by the latest Angular
CLI for new apps.

PR Close #39018
2020-10-01 09:32:58 -07:00
cb85d69450 build(docs-infra): remove the no-string-literal tslint rule to align with CLI (#39018)
This commit removes the `no-string-literal: false` tslint rule to
more closely align `tslint.json` with the one generated by the latest
Angular CLI for new apps.

PR Close #39018
2020-10-01 09:32:58 -07:00
4a446878fa build(docs-infra): enable the no-redundant-jsdoc tslint rule to align with CLI (#39018)
This commit enables the `no-redundant-jsdoc` tslint rule to more closely
align `tslint.json` with the one generated by the latest Angular CLI for
new apps.

PR Close #39018
2020-10-01 09:32:57 -07:00
cb80f46c64 refactor(docs-infra): more closely align tslint.json with CLI (#39018)
This commit re-organizes the `tslint.json` configuration file to more
closely align with the one generated by the latest Angular CLI for new
apps. This makes it easier to see the difference with new CLI versions
in the future and keep our `tslint.json` up-to-date (while keeping our
own rules).

NOTE:
This commit only re-orders rules and removes redundant ones. It does not
change the linting behavior.

PR Close #39018
2020-10-01 09:32:57 -07:00
5199d55d45 fix(dev-infra): run git fetch in quiet mode (#39068)
Runs git fetch with the -q flag during fetch while comparing the master and
g3 branches.

PR Close #39068
2020-10-01 09:30:15 -07:00
bb11fd9058 ci: change required labels for issue triage (#38932)
Issue triage _currently_ requires a component to be set and one of the following to be true for an issue to be
considered triaged:
* Marked as a bug _and_ has a severity _and_ has a frequency
* Mark as a feature
* Marked as a refactor
* Marked as a discussion
* Marked as "confusing"
* Marked as "use-case"

This PR changes the rules so that (in addition to the component), triage
requires:
* A priority label (P0 through P5)
* Marked as a feature
* Marked as a discussion

Triage may also apply additional, optional info labels to issues.

[This document outlines the new priority
scheme](https://docs.google.com/document/d/1mN2zWsr1pxChSTHC7UkOgl4PhhuoFONtG_zcMWeqLwA/preview).

While this PR is focused on issue triage and not PR triage, I have
changed the PR section triage to remove reference to the "effort: *" and
"risk: *" labels. Looking through recent PRs, Kapunahele is the only
person applying these, so it's clear that this bit is no longer widely
practiced.

This is just one step in the always-ongoing process of managing GitHub
labels. More adjustments will come over time. In writing this PR, I have
already unearthed a few more areas that can be polished in follow-ups.

PR Close #38932
2020-10-01 08:32:21 -07:00
771f7318f0 fix(router): update getRouteGuards to check if the context outlet is activated (#39049)
In certain circumstances (errors during component constructor) the router outlet may not be activated before
redirecting to a new route. If the new route requires running guards and resolvers the current logic will throw
when accessing outlet.component due to an isActivated check within the property getter.  This update brings the
logic inline with deactivateRouterAndItsChildren, namely checking outlet.isActivated before trying to access
outlet.component.

Fixes #39030

PR Close #39049
2020-09-30 14:58:47 -07:00
5d584b7728 ci: remove errant comma from angular robot config (#39066)
Remove superfluous comma from exclude list for g3 status in the angular
robot config.

PR Close #39066
2020-09-30 13:27:31 -07:00
1b5f6ee7a6 refactor(localize): avoid free-standing FileSystem functions (#39006)
These free standing functions rely upon the "current" `FileSystem`,
but it is safer to explicitly pass the `FileSystem` into functions or
classes that need it.

Fixes #38711

PR Close #39006
2020-09-30 12:49:44 -07:00
669e07580c refactor(compiler-cli): avoid free-standing FileSystem functions (#39006)
These free standing functions rely upon the "current" `FileSystem`,
but it is safer to explicitly pass the `FileSystem` into functions or
classes that need it.

PR Close #39006
2020-09-30 12:49:43 -07:00
965249d1da docs(localize): add public api markers for CLI integration (#39006)
This commit marks the functions and classes that are
used by the CLI.

PR Close #39006
2020-09-30 12:49:43 -07:00
3a01856e7c docs: fix typo in Pipes guide (aynchronous --> asynchronous) (#38996)
PR Close #38996
2020-09-30 12:46:27 -07:00
250 changed files with 5709 additions and 3997 deletions

View File

@ -74,8 +74,8 @@ test --test_output=errors
# Trick bazel into treating BUILD files under integration/bazel as being regular files
# This lets us glob() up all the files inside this integration test to make them inputs to tests
# (Note, we cannot use common --deleted_packages because the bazel version command doesn't support it)
build --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/test/e2e
query --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/test/e2e
build --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/tools,integration/bazel/test/e2e
query --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/tools,integration/bazel/test/e2e
################################
# Temporary Settings for Ivy #

View File

@ -1,3 +1,3 @@
3.2.0
3.5.1
# [NB: this comment has to be after the first line, see https://github.com/bazelbuild/bazelisk/issues/117]
# When updating the Bazel version you also need to update the RBE toolchains version in package.bzl

View File

@ -14,8 +14,8 @@ build --repository_cache=/home/circleci/bazel_repository_cache
# Bazel doesn't calculate the memory ceiling correctly when running under Docker.
# Limit Bazel to consuming resources that fit in CircleCI "xlarge" class
# https://circleci.com/docs/2.0/configuration-reference/#resource_class
build --local_cpu_resources=8
build --local_ram_resources=14336
build --local_cpu_resources=20
build --local_ram_resources=32768
# All build executed remotely should be done using our RBE configuration.
build:remote --google_default_credentials

View File

@ -11,8 +11,8 @@ try-import %workspace%/.circleci/bazel.common.rc
build --repository_cache=C:/Users/circleci/bazel_repository_cache
# Manually set the local resources used in windows CI runs
build --local_ram_resources=13500
build --local_cpu_resources=4
build --local_ram_resources=120000
build --local_cpu_resources=32
# All windows jobs run on master and should use http caching
build --remote_http_cache=https://storage.googleapis.com/angular-team-cache

View File

@ -80,7 +80,7 @@ executors:
windows-executor:
working_directory: ~/ng
resource_class: windows.medium
resource_class: windows.2xlarge
# CircleCI windows VMs do have the GitBash shell available:
# https://github.com/CircleCI-Public/windows-preview-docs#shells
# But in this specific case we really should not use it because Bazel must not be ran from
@ -273,6 +273,7 @@ jobs:
- run: yarn -s ng-dev format changed $CI_GIT_BASE_REVISION --check
- run: yarn -s ts-circular-deps:check
- run: yarn -s ng-dev pullapprove verify
- run: yarn -s ng-dev ngbot verify
- run: yarn -s ng-dev commit-message validate-range --range $CI_COMMIT_RANGE
test:
@ -857,9 +858,16 @@ workflows:
- build-npm-packages
- build-ivy-npm-packages
- legacy-unit-tests-saucelabs
- components-repo-unit-tests:
requires:
- build-npm-packages
# Temporarily disabled components-repo-unit-tests to update rules_nodejs to 2.0.0. Breaking changes in
# rules_nodejs create a dependency sandwich between angular/angular & angular/components that are very
# difficult and time consuming to resolve and involve patching @angular/bazel in components repo such
# as https://github.com/angular/components/commit/9e7ba251207df77164d73d66620e619bcbc4d2ad. It is simpler to
# 1) land angular/angular upgrade to rule_nodejs 2.0.0 which has breaking changes
# 2) land angular/components upgrade to rules_nodejs 2.0.0 using the @angular/bazel builds snapshot
# 3) update angular/angular to the landed components commit and re-enable these tests
# - components-repo-unit-tests:
# requires:
# - build-npm-packages
- test_zonejs:
requires:
- setup

View File

@ -41,7 +41,8 @@ copy .circleci\bazel.windows.rc ${Env:USERPROFILE}\.bazelrc
####################################################################################################
# Install specific version of node.
####################################################################################################
choco install nodejs --version 12.14.1 --no-progress
nvm install 12.14.1
nvm use 12.14.1
# These Bazel prereqs aren't needed because the CircleCI image already includes them.
# choco install yarn --version 1.16.0 --no-progress

View File

@ -38,6 +38,7 @@ merge:
- "modules/benchmarks/**"
- "modules/system.d.ts"
- "packages/**"
- "dev-infra/benchmark/driver-utilities/**"
# list of patterns to ignore for the files changed by the PR
exclude:
- "packages/*"
@ -47,8 +48,10 @@ merge:
- "packages/bazel/src/ng_package/**"
- "packages/bazel/src/protractor/**"
- "packages/bazel/src/schematics/**"
- "packages/compiler-cli/src/ngcc/**"
- "packages/compiler-cli/linker/**"
- "packages/compiler-cli/ngcc/**"
- "packages/compiler-cli/src/ngtsc/sourcemaps/**",
- "packages/compiler-cli/src/ngtsc/sourcemaps/**"
- "packages/docs/**"
- "packages/elements/schematics/**"
- "packages/examples/**"
@ -56,6 +59,8 @@ merge:
- "packages/localize/**"
- "packages/private/**"
- "packages/service-worker/**"
- "packages/common/locales/**"
- "packages/http/**"
- "**/.gitignore"
- "**/.gitkeep"
- "**/yarn.lock"
@ -137,24 +142,28 @@ triage:
# arrays of labels that determine if an issue has been fully triaged
l2TriageLabels:
-
- "type: bug/fix"
- "severity*"
- "freq*"
- "P0"
- "comp: *"
-
- "type: feature"
- "P1"
- "comp: *"
-
- "type: refactor"
- "P2"
- "comp: *"
-
- "type: RFC / Discussion / question"
- "P3"
- "comp: *"
-
- "type: confusing"
- "P4"
- "comp: *"
-
- "type: use-case"
- "P5"
- "comp: *"
-
- "feature"
- "comp: *"
-
- "discussion"
- "comp: *"
# options for the triage PR plugin

View File

@ -9,11 +9,11 @@ export const caretaker: CaretakerConfig = {
},
{
name: 'Merge Assistance Queue',
query: `is:pr is:open status:success label:"action: merge-assistance"`,
query: `is:pr is:open label:"action: merge-assistance"`,
},
{
name: 'Primary Triage Queue',
query: `is:open is:issue no:milestone`,
name: 'Initial Triage Queue',
query: `is:open no:milestone`,
}
]
};

View File

@ -26,7 +26,7 @@ export const release: ReleaseConfig = {
],
// TODO: Implement release package building here.
buildPackages: async () => [],
// TODO: This can be removed once there is a org-wide tool for changelog generation.
// TODO: This can be removed once there is an org-wide tool for changelog generation.
generateReleaseNotesForHead: async () => {
exec('yarn -s gulp changelog', {cwd: join(__dirname, '../')});
},

View File

@ -326,6 +326,7 @@ groups:
'aio/content/examples/component-interaction/**',
'aio/content/images/guide/component-interaction/**',
'aio/content/guide/component-styles.md',
'aio/content/guide/view-encapsulation.md',
'aio/content/examples/component-styles/**',
'aio/content/guide/dependency-injection.md',
'aio/content/examples/dependency-injection/**',
@ -1115,6 +1116,7 @@ groups:
'docs/DEBUG.md',
'docs/DEBUG_COMPONENTS_REPO_IVY.md',
'docs/DEVELOPER.md',
'docs/FIXUP_COMMITS.md',
'docs/GITHUB_PROCESS.md',
'docs/PR_REVIEW.md',
'docs/SAVED_REPLIES.md',

View File

@ -47,3 +47,9 @@ filegroup(
"@npm//:node_modules/angular-mocks-1.6/angular-mocks.js",
],
)
# Detect if the build is running under --stamp
config_setting(
name = "stamp",
values = {"stamp": "true"},
)

View File

@ -1,3 +1,39 @@
<a name="10.1.6"></a>
## 10.1.6 (2020-10-14)
### Bug Fixes
* **compiler:** incorrectly encapsulating [@import](https://github.com/import) containing colons and semicolons ([#38716](https://github.com/angular/angular/issues/38716)) ([52a0c6b](https://github.com/angular/angular/commit/52a0c6b)), closes [#38587](https://github.com/angular/angular/issues/38587)
* **compiler-cli:** support namespaced query types in directives ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([f752ab9](https://github.com/angular/angular/commit/f752ab9))
* **elements:** detect matchesSelector prototype without IIFE ([#37799](https://github.com/angular/angular/issues/37799)) ([952fd86](https://github.com/angular/angular/commit/952fd86)), closes [#24551](https://github.com/angular/angular/issues/24551)
* **ngcc:** ensure that "inline exports" can be interpreted correctly ([#39272](https://github.com/angular/angular/issues/39272)) ([e08d021](https://github.com/angular/angular/commit/e08d021))
* **ngcc:** handle aliases in UMD export declarations ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([9963c5d](https://github.com/angular/angular/commit/9963c5d)), closes [#38947](https://github.com/angular/angular/issues/38947)
* **ngcc:** map `exports` to the current module in UMD files ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([13c4a7b](https://github.com/angular/angular/commit/13c4a7b))
* **ngcc:** support inline export declarations in UMD files ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([9c875b3](https://github.com/angular/angular/commit/9c875b3)), closes [#38947](https://github.com/angular/angular/issues/38947)
### build
* upgrade angular build, integration/bazel and [@angular](https://github.com/angular)/bazel package to rule_nodejs 2.2.0 ([#39182](https://github.com/angular/angular/issues/39182)) ([7628c36](https://github.com/angular/angular/commit/7628c36))
### Performance Improvements
* **ngcc:** do not rescan program source files when referenced from multiple root files ([#39254](https://github.com/angular/angular/issues/39254)) ([5221df8](https://github.com/angular/angular/commit/5221df8)), closes [#39240](https://github.com/angular/angular/issues/39240)
<a name="10.1.5"></a>
## 10.1.5 (2020-10-07)
### Bug Fixes
* **router:** update getRouteGuards to check if the context outlet is activated ([#39049](https://github.com/angular/angular/issues/39049)) ([771f731](https://github.com/angular/angular/commit/771f731)), closes [#39030](https://github.com/angular/angular/issues/39030)
* **compiler:** Recover on malformed keyed reads and keyed writes ([#39004](https://github.com/angular/angular/issues/39004)) ([f50313f](https://github.com/angular/angular/commit/f50313f)), closes [#38596](https://github.com/angular/angular/issues/38596)
<a name="10.1.4"></a>
## 10.1.4 (2020-09-30)

View File

@ -3,7 +3,7 @@
As contributors and maintainers of the Angular project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities.
Communication through any of Angular's channels (GitHub, Gitter, IRC, mailing lists, Google+, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
Communication through any of Angular's channels (GitHub, Discord, Gitter, IRC, mailing lists, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to the Angular project to do the same.

View File

@ -32,7 +32,7 @@ Stack Overflow is a much better place to ask questions since:
To save your and our time, we will systematically close all issues that are requests for general support and redirect people to Stack Overflow.
If you would like to chat about the question in real-time, you can reach out via [our gitter channel][gitter].
If you would like to chat about the question in real-time, you can reach out via [our Discord server][discord].
## <a name="issue"></a> Found a Bug?
@ -107,7 +107,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
Adherence to these conventions is necessary because release notes are automatically generated from these messages.
```shell
git commit -a
git commit --all
```
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
@ -119,20 +119,55 @@ Before you submit your Pull Request (PR) consider the following guidelines:
11. In GitHub, send a pull request to `angular:master`.
If we ask for changes via code reviews then:
* Make the required updates.
* Re-run the Angular test suites to ensure tests are still passing.
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
#### Addressing review feedback
```shell
git rebase master -i
git push -f
```
If we ask for changes via code reviews then:
1. Make the required updates to the code.
2. Re-run the Angular test suites to ensure tests are still passing.
3. Create a fixup commit and push to your GitHub repository (this will update your Pull Request):
```shell
git commit --all --fixup HEAD
git push
```
For more info on working with fixup commits see [here](docs/FIXUP_COMMITS.md).
That's it! Thank you for your contribution!
##### Updating the commit message
A reviewer might often suggest changes to a commit message (for example, to add more context for a change or adhere to our [commit message guidelines](#commit)).
In order to update the commit message of the last commit on your branch:
1. Check out your branch:
```shell
git checkout my-fix-branch
```
2. Amend the last commit and modify the commit message:
```shell
git commit --amend
```
3. Push to your GitHub repository:
```shell
git push --force-with-lease
```
> NOTE:<br />
> If you need to update the commit message of an earlier commit, you can use `git rebase` in interactive mode.
> See the [git docs](https://git-scm.com/docs/git-rebase#_interactive_mode) for more details.
#### After your pull request is merged
After your pull request is merged, you can safely delete your branch and pull the changes from the main (upstream) repository:
@ -349,7 +384,7 @@ The following documents can help you sort out issues with GitHub accounts and mu
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
[dev-doc]: https://github.com/angular/angular/blob/master/docs/DEVELOPER.md
[github]: https://github.com/angular/angular
[gitter]: https://gitter.im/angular/angular
[discord]: https://discord.gg/angular
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
[js-style-guide]: https://google.github.io/styleguide/jsguide.html
[jsfiddle]: http://jsfiddle.net

View File

@ -1,4 +1,5 @@
[![CircleCI](https://circleci.com/gh/angular/angular/tree/master.svg?style=shield)](https://circleci.com/gh/angular/workflows/angular/tree/master)
[![Discord](https://img.shields.io/discord/463752820026376202.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/angular)
[![Join the chat at https://gitter.im/angular/angular](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![npm version](https://badge.fury.io/js/%40angular%2Fcore.svg)](https://www.npmjs.com/@angular/core)

View File

@ -8,8 +8,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# Fetch rules_nodejs so we can install our npm dependencies
http_archive(
name = "build_bazel_rules_nodejs",
sha256 = "84abf7ac4234a70924628baa9a73a5a5cbad944c4358cf9abdb4aab29c9a5b77",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.7.0/rules_nodejs-1.7.0.tar.gz"],
sha256 = "4952ef879704ab4ad6729a29007e7094aef213ea79e9f2e94cbe1c9a753e63ef",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/2.2.0/rules_nodejs-2.2.0.tar.gz"],
)
# Check the rules_nodejs version and download npm dependencies
@ -17,7 +17,7 @@ http_archive(
# assert on that.
load("@build_bazel_rules_nodejs//:index.bzl", "check_rules_nodejs_version", "node_repositories", "yarn_install")
check_rules_nodejs_version(minimum_version_string = "1.7.0")
check_rules_nodejs_version(minimum_version_string = "2.2.0")
# Setup the Node.js toolchain
node_repositories(
@ -39,23 +39,18 @@ yarn_install(
yarn_lock = "//:yarn.lock",
)
# Install all bazel dependencies of the @npm npm packages
load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
install_bazel_dependencies()
# Load angular dependencies
load("//packages/bazel:package.bzl", "rules_angular_dev_dependencies")
rules_angular_dev_dependencies()
# Load protractor dependencies
load("@npm_bazel_protractor//:package.bzl", "npm_bazel_protractor_dependencies")
load("@npm//@bazel/protractor:package.bzl", "npm_bazel_protractor_dependencies")
npm_bazel_protractor_dependencies()
# Load karma dependencies
load("@npm_bazel_karma//:package.bzl", "npm_bazel_karma_dependencies")
load("@npm//@bazel/karma:package.bzl", "npm_bazel_karma_dependencies")
npm_bazel_karma_dependencies()
@ -68,11 +63,6 @@ load("//dev-infra/browsers:browser_repositories.bzl", "browser_repositories")
browser_repositories()
# Setup the rules_typescript tooolchain
load("@npm_bazel_typescript//:index.bzl", "ts_setup_workspace")
ts_setup_workspace()
# Setup the rules_sass toolchain
load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories")
@ -91,8 +81,8 @@ rbe_autoconfig(
# Need to specify a base container digest in order to ensure that we can use the checked-in
# platform configurations for the "ubuntu16_04" image. Otherwise the autoconfig rule would
# need to pull the image and run it in order determine the toolchain configuration. See:
# https://github.com/bazelbuild/bazel-toolchains/blob/3.2.0/configs/ubuntu16_04_clang/versions.bzl
base_container_digest = "sha256:5e750dd878df9fcf4e185c6f52b9826090f6e532b097f286913a428290622332",
# https://github.com/bazelbuild/bazel-toolchains/blob/3.5.1/configs/ubuntu16_04_clang/versions.bzl
base_container_digest = "sha256:f6568d8168b14aafd1b707019927a63c2d37113a03bcee188218f99bd0327ea1",
# Note that if you change the `digest`, you might also need to update the
# `base_container_digest` to make sure marketplace.gcr.io/google/rbe-ubuntu16-04-webtest:<digest>
# and marketplace.gcr.io/google/rbe-ubuntu16-04:<base_container_digest> have

View File

@ -119,7 +119,7 @@ The `/deep/` combinator also has the aliases `>>>`, and `::ng-deep`.
Use `/deep/`, `>>>` and `::ng-deep` only with *emulated* view encapsulation.
Emulated is the default and most commonly used view encapsulation. For more information, see the
[Controlling view encapsulation](guide/component-styles#view-encapsulation) section.
[View Encapsulation](guide/view-encapsulation) section.
</div>
@ -267,89 +267,3 @@ as explained in the [CLI wiki](https://github.com/angular/angular-cli/wiki/stori
Style strings added to the `@Component.styles` array _must be written in CSS_ because the CLI cannot apply a preprocessor to inline styles.
</div>
{@a view-encapsulation}
## View encapsulation
As discussed earlier, component CSS styles are encapsulated into the component's view and don't
affect the rest of the application.
To control how this encapsulation happens on a *per
component* basis, you can set the *view encapsulation mode* in the component metadata.
Choose from the following modes:
* `ShadowDom` view encapsulation uses the browser's native shadow DOM implementation (see
[Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
on the [MDN](https://developer.mozilla.org) site)
to attach a shadow DOM to the component's host element, and then puts the component
view inside that shadow DOM. The component's styles are included within the shadow DOM.
* `Native` view encapsulation uses a now deprecated version of the browser's native shadow DOM implementation - [learn about the changes](https://hayato.io/2016/shadowdomv1/).
* `Emulated` view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing
(and renaming) the CSS code to effectively scope the CSS to the component's view.
For details, see [Inspecting generated CSS](guide/component-styles#inspect-generated-css) below.
* `None` means that Angular does no view encapsulation.
Angular adds the CSS to the global styles.
The scoping rules, isolations, and protections discussed earlier don't apply.
This is essentially the same as pasting the component's styles into the HTML.
To set the components encapsulation mode, use the `encapsulation` property in the component metadata:
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" header="src/app/quest-summary.component.ts"></code-example>
`ShadowDom` view encapsulation only works on browsers that have native support
for shadow DOM (see [Shadow DOM v1](https://caniuse.com/#feat=shadowdomv1) on the
[Can I use](http://caniuse.com) site). The support is still limited,
which is why `Emulated` view encapsulation is the default mode and recommended
in most cases.
{@a inspect-generated-css}
## Inspecting generated CSS
When using emulated view encapsulation, Angular preprocesses
all component styles so that they approximate the standard shadow CSS scoping rules.
In the DOM of a running Angular application with emulated view
encapsulation enabled, each DOM element has some extra attributes
attached to it:
<code-example format="">
&lt;hero-details _nghost-pmm-5>
&lt;h2 _ngcontent-pmm-5>Mister Fantastic&lt;/h2>
&lt;hero-team _ngcontent-pmm-5 _nghost-pmm-6>
&lt;h3 _ngcontent-pmm-6>Team&lt;/h3>
&lt;/hero-team>
&lt;/hero-detail>
</code-example>
There are two kinds of generated attributes:
* An element that would be a shadow DOM host in native encapsulation has a
generated `_nghost` attribute. This is typically the case for component host elements.
* An element within a component's view has a `_ngcontent` attribute
that identifies to which host's emulated shadow DOM this element belongs.
The exact values of these attributes aren't important. They are automatically
generated and you never refer to them in application code. But they are targeted
by the generated component styles, which are in the `<head>` section of the DOM:
<code-example format="">
[_nghost-pmm-5] {
display: block;
border: 1px solid black;
}
h3[_ngcontent-pmm-6] {
background-color: white;
border: 1px solid #777;
}
</code-example>
These styles are post-processed so that each selector is augmented
with `_nghost` or `_ngcontent` attribute selectors.
These extra selectors enable the scoping rules described in this page.

View File

@ -156,7 +156,7 @@ The library must be rebuilt on every change.
When linking a library, make sure that the build step runs in watch mode, and that the library's `package.json` configuration points at the correct entry points.
For example, `main` should point at a JavaScript file, not a TypeScript file.
## Use TypeScript path mapping for peer dependencies
### Use TypeScript path mapping for peer dependencies
Angular libraries should list all `@angular/*` dependencies as peer dependencies.
This ensures that when modules ask for Angular, they all get the exact same module.

View File

@ -397,7 +397,7 @@ The following code example binds an observable of message strings
## Caching HTTP requests
To [communicate with backend services using HTTP](/guide/http "Communicating with backend services using HTTP"), the `HttpClient` service uses observables and offers the `HTTPClient.get()` method to fetch data from a server.
The aynchronous method sends an HTTP request, and returns an observable that emits the requested data for the response.
The asynchronous method sends an HTTP request, and returns an observable that emits the requested data for the response.
As shown in the previous section, you can use the impure `AsyncPipe` to accept an observable as input and subscribe to the input automatically.
You can also create an impure pipe to make and cache an HTTP request.

View File

@ -180,7 +180,7 @@ A form group tracks the status and changes for each of its controls, so if one o
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="formgroup" header="src/app/profile-editor/profile-editor.component.html (template form group)"></code-example>
Note that just as a form group contains a group of controls, the *profile form* `FormGroup` is bound to the `form` element with the `FormGroup` directive, creating a communication layer between the model and the form containing the inputs. The `formControlName` input provided by the `FormControlName` directive binds each individual input to the form control defined in `FormGroup`. The form controls communicate with their respective elements. They also communicate changes to the form group instance, which provides the source of truth for the model value.
Note that just as a form group contains a group of controls, the *profileForm* `FormGroup` is bound to the `form` element with the `FormGroup` directive, creating a communication layer between the model and the form containing the inputs. The `formControlName` input provided by the `FormControlName` directive binds each individual input to the form control defined in `FormGroup`. The form controls communicate with their respective elements. They also communicate changes to the form group instance, which provides the source of truth for the model value.
**Save form data**

View File

@ -479,6 +479,15 @@ using the `downgradeComponent()` method. The result is an AngularJS
<code-example path="upgrade-module/src/app/downgrade-static/app.module.ts" region="downgradecomponent" header="app.module.ts">
</code-example>
<div class="alert is-helpful">
By default, Angular change detection will also run on the component for every
AngularJS `$digest` cycle. If you wish to only have change detection run when
the inputs change, you can set `propagateDigest` to `false` when calling
`downgradeComponent()`.
</div>
Because `HeroDetailComponent` is an Angular component, you must also add it to the
`declarations` in the `AppModule`.

View File

@ -0,0 +1,83 @@
# View encapsulation
In Angular, component CSS styles are encapsulated into the component's view and don't
affect the rest of the application.
To control how this encapsulation happens on a *per
component* basis, you can set the *view encapsulation mode* in the component metadata.
Choose from the following modes:
* `ShadowDom` view encapsulation uses the browser's native shadow DOM implementation (see
[Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
on the [MDN](https://developer.mozilla.org) site)
to attach a shadow DOM to the component's host element, and then puts the component
view inside that shadow DOM. The component's styles are included within the shadow DOM.
* `Native` view encapsulation uses a now deprecated version of the browser's native shadow DOM implementation - [learn about the changes](https://hayato.io/2016/shadowdomv1/).
* `Emulated` view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing
(and renaming) the CSS code to effectively scope the CSS to the component's view.
For details, see [Inspecting generated CSS](guide/view-encapsulation#inspect-generated-css) below.
* `None` means that Angular does no view encapsulation.
Angular adds the CSS to the global styles.
The scoping rules, isolations, and protections discussed earlier don't apply.
This is essentially the same as pasting the component's styles into the HTML.
To set the components encapsulation mode, use the `encapsulation` property in the component metadata:
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" header="src/app/quest-summary.component.ts"></code-example>
`ShadowDom` view encapsulation only works on browsers that have native support
for shadow DOM (see [Shadow DOM v1](https://caniuse.com/#feat=shadowdomv1) on the
[Can I use](http://caniuse.com) site). The support is still limited,
which is why `Emulated` view encapsulation is the default mode and recommended
in most cases.
{@a inspect-generated-css}
## Inspecting generated CSS
When using emulated view encapsulation, Angular preprocesses
all component styles so that they approximate the standard shadow CSS scoping rules.
In the DOM of a running Angular application with emulated view
encapsulation enabled, each DOM element has some extra attributes
attached to it:
<code-example format="">
&lt;hero-details _nghost-pmm-5>
&lt;h2 _ngcontent-pmm-5>Mister Fantastic&lt;/h2>
&lt;hero-team _ngcontent-pmm-5 _nghost-pmm-6>
&lt;h3 _ngcontent-pmm-6>Team&lt;/h3>
&lt;/hero-team>
&lt;/hero-detail>
</code-example>
There are two kinds of generated attributes:
* An element that would be a shadow DOM host in native encapsulation has a
generated `_nghost` attribute. This is typically the case for component host elements.
* An element within a component's view has a `_ngcontent` attribute
that identifies to which host's emulated shadow DOM this element belongs.
The exact values of these attributes aren't important. They are automatically
generated and you never refer to them in application code. But they are targeted
by the generated component styles, which are in the `<head>` section of the DOM:
<code-example format="">
[_nghost-pmm-5] {
display: block;
border: 1px solid black;
}
h3[_ngcontent-pmm-6] {
background-color: white;
border: 1px solid #777;
}
</code-example>
These styles are post-processed so that each selector is augmented
with `_nghost` or `_ngcontent` attribute selectors.
These extra selectors enable the scoping rules described in this page.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -458,8 +458,8 @@
"name": "Sajeetharan Sinnathurai",
"picture": "sajee.jpg",
"twitter": "kokkisajee",
"website": "https://sajeetharan.herokuapp.com/",
"bio": "Sajeetharan is a Developer, Top contributor on stackoverflow for #Angular, ng-SriLanka organizer. He makes use of his extensive knowledge over the past years to contribute to community to make the world a better place.",
"website": "https://sajeetharan.com/",
"bio": "Sajeetharan is a Cloud Architect, Top contributor on stackoverflow for #Angular, ng-SriLanka organizer. He makes use of his extensive knowledge over the past years to contribute to community to make the world a better place.",
"groups": ["GDE"]
},
"lacolaco": {

View File

@ -46,7 +46,7 @@ Most Angular code can be written with just the latest JavaScript, using [types](
<h3>You can sit with us!</h3>
We want to hear from you. [Report problems or submit suggestions for future docs.](https://github.com/angular/angular/issues/new/choose "Angular GitHub repository new issue form")
We want to hear from you. [Report problems or submit suggestions for future docs](https://github.com/angular/angular/issues/new/choose "Angular GitHub repository new issue form").
Contribute to Angular docs by creating
[pull requests](https://github.com/angular/angular/pulls "Angular Github pull requests")

View File

@ -116,6 +116,11 @@
"title": "Component Lifecycle",
"tooltip": "Angular calls lifecycle hook methods on directives and components as it creates, changes, and destroys them."
},
{
"url": "guide/view-encapsulation",
"title": "View Encapsulation",
"tooltip": "Describes how component CSS styles are encapsulated into a component's view."
},
{
"url": "guide/component-interaction",
"title": "Component Interaction",
@ -126,6 +131,11 @@
"title": "Component Styles",
"tooltip": "Add CSS styles that are specific to a component."
},
{
"url": "guide/inputs-outputs",
"title": "Inputs and Outputs",
"tooltip": "Introductory guide to sharing data between parent and child directives or components."
},
{
"url": "guide/dynamic-component-loader",
"title": "Dynamic Components",
@ -187,11 +197,6 @@
"title": "Template reference variables",
"tooltip": "Introductory guide to referring to DOM elements within a template."
},
{
"url": "guide/inputs-outputs",
"title": "Inputs and Outputs",
"tooltip": "Introductory guide to sharing data between parent and child directives or components."
},
{
"url": "guide/template-expression-operators",
"title": "Template expression operators",
@ -1004,6 +1009,11 @@
"title": "Stack Overflow",
"tooltip": "Stack Overflow: where the community answers your technical Angular questions."
},
{
"url": "https://discord.gg/angular",
"title": "Join Discord",
"tooltip": "Join the discussions at Angular Community Discord server."
},
{
"url": "https://gitter.im/angular/angular",
"title": "Gitter",

View File

@ -128,7 +128,8 @@
// The below paths are referenced in users projects generated by the CLI
{"type": 301, "source": "/config/tsconfig", "destination": "/guide/typescript-configuration"},
{"type": 301, "source": "/config/solution-tsconfig", "destination": "https://devblogs.microsoft.com/typescript/announcing-typescript-3-9/#solution-style-tsconfig"},
{"type": 301, "source": "/config/app-package-json", "destination": "/guide/strict-mode#non-local-side-effects-in-applications"}
{"type": 301, "source": "/config/app-package-json", "destination": "/guide/strict-mode#non-local-side-effects-in-applications"},
{"type": 301, "source": "/strict", "destination": "/guide/strict-mode"}
],
"rewrites": [
{

View File

@ -148,6 +148,7 @@
"!/styleguide/**",
"!/testing",
"!/testing/**",
"!/config/**"
"!/config/**",
"!/strict"
]
}

View File

@ -64,7 +64,7 @@
"tools-lint": "tslint --config \"tools/tslint.json\" --project \"tools/firebase-test-utils\"",
"tools-test": "./scripts/deploy-to-firebase.test.sh && yarn docs-test && yarn boilerplate:test && jasmine tools/ng-packages-installer/index.spec.js && yarn firebase-utils-test",
"preserve-and-sync": "yarn docs",
"serve-and-sync": "run-p \"start\" \"docs-watch --watch-only\"",
"serve-and-sync": "run-p \"docs-watch --watch-only\" \"start {@}\" --",
"boilerplate:add": "node ./tools/examples/example-boilerplate add",
"boilerplate:add:viewengine": "yarn boilerplate:add --viewengine",
"boilerplate:remove": "node ./tools/examples/example-boilerplate remove",
@ -153,7 +153,7 @@
"lunr": "^2.1.0",
"npm-run-all": "^4.1.5",
"protractor": "~5.4.4",
"puppeteer": "3.3.0",
"puppeteer": "5.1.0",
"rehype": "^6.0.0",
"rehype-slug": "^2.0.0",
"remark": "^9.0.0",

View File

@ -782,7 +782,7 @@ describe('AppComponent', () => {
it('should grab focus when the / key is pressed', () => {
const searchBox: SearchBoxComponent = fixture.debugElement.query(By.directive(SearchBoxComponent)).componentInstance;
spyOn(searchBox, 'focus');
window.document.dispatchEvent(new KeyboardEvent('keyup', { 'key': '/' }));
window.document.dispatchEvent(new KeyboardEvent('keyup', { key: '/' }));
fixture.detectChanges();
expect(searchBox.focus).toHaveBeenCalled();
});
@ -791,7 +791,7 @@ describe('AppComponent', () => {
const searchBox: SearchBoxComponent = fixture.debugElement.query(By.directive(SearchBoxComponent)).componentInstance;
spyOn(searchBox, 'focus');
component.showSearchResults = true;
window.document.dispatchEvent(new KeyboardEvent('keyup', { 'key': 'Escape' }));
window.document.dispatchEvent(new KeyboardEvent('keyup', { key: 'Escape' }));
fixture.detectChanges();
expect(searchBox.focus).toHaveBeenCalled();
});
@ -968,23 +968,23 @@ describe('AppComponent', () => {
// Initially, `isTransitoning` is true.
expect(component.isTransitioning).toBe(true);
expect(toolbar.classes['transitioning']).toBe(true);
expect(toolbar.classes.transitioning).toBe(true);
triggerDocViewerEvent('docRendered');
fixture.detectChanges();
expect(component.isTransitioning).toBe(false);
expect(toolbar.classes['transitioning']).toBeFalsy();
expect(toolbar.classes.transitioning).toBeFalsy();
// While a document is being rendered, `isTransitoning` is set to true.
triggerDocViewerEvent('docReady');
fixture.detectChanges();
expect(component.isTransitioning).toBe(true);
expect(toolbar.classes['transitioning']).toBe(true);
expect(toolbar.classes.transitioning).toBe(true);
triggerDocViewerEvent('docRendered');
fixture.detectChanges();
expect(component.isTransitioning).toBe(false);
expect(toolbar.classes['transitioning']).toBeFalsy();
expect(toolbar.classes.transitioning).toBeFalsy();
});
it('should update the sidenav state as soon as a new document is inserted (but not before)', () => {
@ -1031,15 +1031,15 @@ describe('AppComponent', () => {
navigateTo('guide/pipes');
expect(component.pageId).toEqual('guide-pipes');
expect(container.properties['id']).toEqual('guide-pipes');
expect(container.properties.id).toEqual('guide-pipes');
navigateTo('news');
expect(component.pageId).toEqual('news');
expect(container.properties['id']).toEqual('news');
expect(container.properties.id).toEqual('news');
navigateTo('');
expect(component.pageId).toEqual('home');
expect(container.properties['id']).toEqual('home');
expect(container.properties.id).toEqual('home');
});
it('should not be affected by changes to the query', () => {
@ -1050,7 +1050,7 @@ describe('AppComponent', () => {
navigateTo('guide/other?search=http');
expect(component.pageId).toEqual('guide-other');
expect(container.properties['id']).toEqual('guide-other');
expect(container.properties.id).toEqual('guide-other');
});
});
@ -1125,7 +1125,7 @@ describe('AppComponent', () => {
function checkHostClass(type: string, value: string) {
const host = fixture.debugElement;
const classes: string = host.properties['className'];
const classes: string = host.properties.className;
const classArray = classes.split(' ').filter(c => c.indexOf(`${type}-`) === 0);
expect(classArray.length).toBeLessThanOrEqual(1, `"${classes}" should have only one class matching ${type}-*`);
expect(classArray).toEqual([`${type}-${value}`], `"${classes}" should contain ${type}-${value}`);
@ -1311,42 +1311,42 @@ class TestHttpClient {
// tslint:disable:quotemark
navJson = {
"TopBar": [
TopBar: [
{
"url": "features",
"title": "Features"
url: 'features',
title: 'Features',
},
{
"url": "no-title",
"title": "No Title"
url: 'no-title',
title: 'No Title',
},
],
"SideNav": [
SideNav: [
{
"title": "Core",
"tooltip": "Learn the core capabilities of Angular",
"children": [
title: 'Core',
tooltip: 'Learn the core capabilities of Angular',
children: [
{
"url": "guide/pipes",
"title": "Pipes",
"tooltip": "Pipes transform displayed values within a template."
url: 'guide/pipes',
title: 'Pipes',
tooltip: 'Pipes transform displayed values within a template.',
},
{
"url": "guide/bags",
"title": "Bags",
"tooltip": "Pack your bags for a code adventure."
}
]
url: 'guide/bags',
title: 'Bags',
tooltip: 'Pack your bags for a code adventure.',
},
],
},
{
"url": "api",
"title": "API",
"tooltip": "Details of the Angular classes and values."
}
url: 'api',
title: 'API',
tooltip: 'Details of the Angular classes and values.',
},
],
"docVersions": TestHttpClient.docVersions,
docVersions: TestHttpClient.docVersions,
"__versionInfo": TestHttpClient.versionInfo,
__versionInfo: TestHttpClient.versionInfo,
};
get(url: string) {

View File

@ -147,7 +147,7 @@ export class AppComponent implements OnInit {
// Compute the version picker list from the current version and the versions in the navigation map
combineLatest([
this.navigationService.versionInfo,
this.navigationService.navigationViews.pipe(map(views => views['docVersions'])),
this.navigationService.navigationViews.pipe(map(views => views.docVersions)),
]).subscribe(([versionInfo, versions]) => {
// TODO(pbd): consider whether we can lookup the stable and next versions from the internet
const computedVersions: NavigationNode[] = [
@ -167,10 +167,10 @@ export class AppComponent implements OnInit {
});
this.navigationService.navigationViews.subscribe(views => {
this.footerNodes = views['Footer'] || [];
this.sideNavNodes = views['SideNav'] || [];
this.topMenuNodes = views['TopBar'] || [];
this.topMenuNarrowNodes = views['TopBarNarrow'] || this.topMenuNodes;
this.footerNodes = views.Footer || [];
this.sideNavNodes = views.SideNav || [];
this.topMenuNodes = views.TopBar || [];
this.topMenuNarrowNodes = views.TopBarNarrow || this.topMenuNodes;
});
this.navigationService.versionInfo.subscribe(vi => this.versionInfo = vi);

View File

@ -223,77 +223,77 @@ class TestApiService {
// tslint:disable:quotemark
const apiSections: ApiSection[] = [
{
"name": "common",
"title": "common",
"path": "api/common",
"deprecated": false,
"items": [
name: 'common',
title: 'common',
path: 'api/common',
deprecated: false,
items: [
{
"name": "class_1",
"title": "Class 1",
"path": "api/common/class_1",
"docType": "class",
"stability": "experimental",
"securityRisk": false,
name: 'class_1',
title: 'Class 1',
path: 'api/common/class_1',
docType: 'class',
stability: 'experimental',
securityRisk: false,
},
{
"name": "class_2",
"title": "Class 2",
"path": "api/common/class_2",
"docType": "class",
"stability": "stable",
"securityRisk": false,
name: 'class_2',
title: 'Class 2',
path: 'api/common/class_2',
docType: 'class',
stability: 'stable',
securityRisk: false,
},
{
"name": "directive_1",
"title": "Directive 1",
"path": "api/common/directive_1",
"docType": "directive",
"stability": "stable",
"securityRisk": true,
name: 'directive_1',
title: 'Directive 1',
path: 'api/common/directive_1',
docType: 'directive',
stability: 'stable',
securityRisk: true,
},
{
"name": "pipe_1",
"title": "Pipe 1",
"path": "api/common/pipe_1",
"docType": "pipe",
"stability": "stable",
"securityRisk": true,
name: 'pipe_1',
title: 'Pipe 1',
path: 'api/common/pipe_1',
docType: 'pipe',
stability: 'stable',
securityRisk: true,
},
]
],
},
{
"name": "core",
"title": "core",
"path": "api/core",
"deprecated": false,
"items": [
name: 'core',
title: 'core',
path: 'api/core',
deprecated: false,
items: [
{
"name": "class_3",
"title": "Class 3",
"path": "api/core/class_3",
"docType": "class",
"stability": "experimental",
"securityRisk": false,
name: 'class_3',
title: 'Class 3',
path: 'api/core/class_3',
docType: 'class',
stability: 'experimental',
securityRisk: false,
},
{
"name": "function_1",
"title": "Function 1",
"path": "api/core/function 1",
"docType": "function",
"stability": "deprecated",
"securityRisk": true,
name: 'function_1',
title: 'Function 1',
path: 'api/core/function 1',
docType: 'function',
stability: 'deprecated',
securityRisk: true,
},
{
"name": "const_1",
"title": "Const 1",
"path": "api/core/const_1",
"docType": "const",
"stability": "stable",
"securityRisk": false,
}
]
}
name: 'const_1',
title: 'Const 1',
path: 'api/core/const_1',
docType: 'const',
stability: 'stable',
securityRisk: false,
},
],
},
];
function getApiSections() { return apiSections; }

View File

@ -67,7 +67,7 @@ export class ApiService implements OnDestroy {
* API sections is an array of Angular top modules and metadata about their API documents (items).
* Updates `sections` observable
*
* @param {string} [src] - Name of the api list JSON file
* @param [src] - Name of the api list JSON file
*/
fetchSections(src?: string) {
// TODO: get URL by configuration?

View File

@ -20,13 +20,13 @@ export class PrettyPrinter {
}
private getPrettyPrintOne(): Promise<PrettyPrintOne> {
const ppo = (window as any)['prettyPrintOne'];
const ppo = (window as any).prettyPrintOne;
return ppo ? Promise.resolve(ppo) :
// `prettyPrintOne` is not on `window`, which means `prettify.js` has not been loaded yet.
// Import it; ad a side-effect it will add `prettyPrintOne` on `window`.
import('assets/js/prettify.js' as any)
.then(
() => (window as any)['prettyPrintOne'],
() => (window as any).prettyPrintOne,
err => {
const msg = `Cannot get prettify.js from server: ${err.message}`;
this.logger.error(new Error(msg));
@ -37,9 +37,9 @@ export class PrettyPrinter {
/**
* Format code snippet as HTML
* @param {string} code - the code snippet to format; should already be HTML encoded
* @param {string} [language] - The language of the code to render (could be javascript, html, typescript, etc)
* @param {string|number} [linenums] - Whether to display line numbers:
* @param code - the code snippet to format; should already be HTML encoded
* @param [language] - The language of the code to render (could be javascript, html, typescript, etc)
* @param [linenums] - Whether to display line numbers:
* - false: don't display
* - true: do display
* - number: do display but start at the given number

View File

@ -63,7 +63,7 @@ describe('ContributorListComponent', () => {
it('should set the query to the "GDE" group when user selects "GDE"', () => {
component = getComponent();
component.selectGroup('GDE');
expect(locationService.searchResult['group']).toBe('GDE');
expect(locationService.searchResult.group).toBe('GDE');
});
it('should set the query to the first group when user selects unknown name', () => {
@ -71,7 +71,7 @@ describe('ContributorListComponent', () => {
component.selectGroup('GDE'); // a legit group that isn't the first
component.selectGroup('foo'); // not a legit group name
expect(locationService.searchResult['group']).toBe('Angular');
expect(locationService.searchResult.group).toBe('Angular');
});
//// Test Helpers ////

View File

@ -29,7 +29,7 @@ export class ContributorListComponent implements OnInit {
private locationService: LocationService) { }
ngOnInit() {
const groupName = this.locationService.search()['group'] || '';
const groupName = this.locationService.search().group || '';
// no need to unsubscribe because `contributors` completes
this.contributorService.contributors
.subscribe(grps => {

View File

@ -63,7 +63,7 @@ describe('ResourceListComponent', () => {
it('should set the query to the "education" category when user selects "education"', () => {
component = getComponent();
component.selectCategory('education');
expect(locationService.searchResult['category']).toBe('education');
expect(locationService.searchResult.category).toBe('education');
});
it('should set the query to the first category when user selects unknown name', () => {
@ -71,7 +71,7 @@ describe('ResourceListComponent', () => {
component.selectCategory('education'); // a legit group that isn't the first
component.selectCategory('foo'); // not a legit group name
expect(locationService.searchResult['category']).toBe('development');
expect(locationService.searchResult.category).toBe('development');
});
//// Test Helpers ////

View File

@ -20,7 +20,7 @@ export class ResourceListComponent implements OnInit {
}
ngOnInit() {
const category = this.locationService.search()['category'] || '';
const category = this.locationService.search().category || '';
// Not using async pipe because cats appear twice in template
// No need to unsubscribe because categories observable completes.
this.resourceService.categories.subscribe(cats => {

View File

@ -86,62 +86,61 @@ describe('ResourceService', () => {
});
function getTestResources() {
// tslint:disable:quotemark
return {
"Cat 3": {
"order": 3,
"subCategories": {
"Cat3 SubCat1": {
"order": 2,
"resources": {
"Cat3 SubCat1 Res1": {
"desc": "Meetup in Barcelona, Spain. ",
"title": "Angular Beers",
"url": "http://www.meetup.com/AngularJS-Beers/"
'Cat 3': {
order: 3,
subCategories: {
'Cat3 SubCat1': {
order: 2,
resources: {
'Cat3 SubCat1 Res1': {
desc: 'Meetup in Barcelona, Spain. ',
title: 'Angular Beers',
url: 'http://www.meetup.com/AngularJS-Beers/',
},
"Cat3 SubCat1 Res2": {
"desc": "Angular Camps in Barcelona, Spain.",
"title": "Angular Camp",
"url": "http://angularcamp.org/"
}
}
'Cat3 SubCat1 Res2': {
desc: 'Angular Camps in Barcelona, Spain.',
title: 'Angular Camp',
url: 'http://angularcamp.org/',
},
},
},
"Cat3 SubCat2": {
"order": 1,
"resources": {
"Cat3 SubCat2 Res1": {
"desc": "A community index of components and libraries",
"title": "Catalog of Angular Components & Libraries",
"url": "https://a/b/c"
}
}
},
}
},
"Cat 1": {
"order": 1,
"subCategories": {
"Cat1 SubCat1": {
"order": 1,
"resources": {
"S S S": {
"desc": "SSS",
"title": "Sssss",
"url": "http://s/s/s"
'Cat3 SubCat2': {
order: 1,
resources: {
'Cat3 SubCat2 Res1': {
desc: 'A community index of components and libraries',
title: 'Catalog of Angular Components & Libraries',
url: 'https://a/b/c',
},
"A A A": {
"desc": "AAA",
"title": "Aaaa",
"url": "http://a/a/a"
},
"Z Z Z": {
"desc": "ZZZ",
"title": "Zzzzz",
"url": "http://z/z/z"
}
}
},
},
},
}
},
'Cat 1': {
order: 1,
subCategories: {
'Cat1 SubCat1': {
order: 1,
resources: {
'S S S': {
desc: 'SSS',
title: 'Sssss',
url: 'http://s/s/s',
},
'A A A': {
desc: 'AAA',
title: 'Aaaa',
url: 'http://a/a/a',
},
'Z Z Z': {
desc: 'ZZZ',
title: 'Zzzzz',
url: 'http://z/z/z',
},
},
},
},
},
};
}

View File

@ -86,7 +86,7 @@ describe('NavigationService', () => {
];
beforeEach(() => {
navService.navigationViews.subscribe(views => view = views['sideNav']);
navService.navigationViews.subscribe(views => view = views.sideNav);
httpMock.expectOne({}).flush({sideNav});
});
@ -254,7 +254,7 @@ describe('NavigationService', () => {
{...v, ...{ tooltip: v.title + '.'}})
);
navService.navigationViews.subscribe(views => actualDocVersions = views['docVersions']);
navService.navigationViews.subscribe(views => actualDocVersions = views.docVersions);
});
it('should extract the docVersions', () => {

View File

@ -41,7 +41,7 @@ export class SearchBoxComponent implements AfterViewInit {
* When we first show this search box we trigger a search if there is a search query in the URL
*/
ngAfterViewInit() {
const query = this.locationService.search()['search'];
const query = this.locationService.search().search;
if (query) {
this.query = this.decodeQuery(query);
this.doSearch();

View File

@ -26,7 +26,7 @@ function createIndex(loadIndexFn: IndexLoader): lunr.Index {
// The lunr typings are missing QueryLexer so we have to add them here manually.
const queryLexer = (lunr as any as { QueryLexer: { termSeparator: RegExp } }).QueryLexer;
queryLexer.termSeparator = lunr.tokenizer.separator = /\s+/;
return lunr(/** @this */function() {
return lunr(function() {
this.ref('path');
this.field('topics', { boost: 15 });
this.field('titleWords', { boost: 10 });
@ -44,7 +44,7 @@ function handleMessage(message: { data: WebWorkerMessage }): void {
const payload = message.data.payload;
switch (type) {
case 'load-index':
makeRequest(SEARCH_TERMS_URL, function(searchInfo: PageInfo[]) {
makeRequest(SEARCH_TERMS_URL, (searchInfo: PageInfo[]) => {
index = createIndex(loadIndex(searchInfo));
postMessage({ type, id, payload: true });
});
@ -94,7 +94,7 @@ function queryIndex(query: string): PageInfo[] {
results = index.search(query + ' ' + titleQuery);
}
// Map the hits into info about each page to be returned as results
return results.map(function(hit) { return pages[hit.ref]; });
return results.map(hit => pages[hit.ref]);
}
} catch (e) {
// If the search query cannot be parsed the index throws an error

View File

@ -11,7 +11,7 @@ export class Deployment {
* The deployment mode set from the environment provided at build time;
* or overridden by the `mode` query parameter: e.g. `...?mode=archive`
*/
mode: string = this.location.search()['mode'] || environment.mode;
mode: string = this.location.search().mode || environment.mode;
constructor(private location: LocationService) {}
}

View File

@ -14,7 +14,7 @@ export class GaService {
private previousUrl: string;
constructor(@Inject(WindowToken) private window: Window) {
this.ga('create', environment['gaId'] , 'auto');
this.ga('create', environment.gaId , 'auto');
}
locationChanged(url: string) {
@ -34,7 +34,7 @@ export class GaService {
}
ga(...args: any[]) {
const gaFn = (this.window as any)['ga'];
const gaFn = (this.window as any).ga;
if (gaFn) {
gaFn(...args);
}

View File

@ -100,7 +100,7 @@ export class LocationService {
/**
* Handle user's anchor click
*
* @param anchor {HTMLAnchorElement} - the anchor element clicked
* @param anchor The anchor element clicked
* @param button Number of the mouse button held down. 0 means left or none
* @param ctrlKey True if control key held down
* @param metaKey True if command or window key held down

View File

@ -13,14 +13,13 @@ import { Logger } from 'app/shared/logger.service';
* 1. Checks for available ServiceWorker updates once instantiated.
* 2. Re-checks every 6 hours.
* 3. Whenever an update is available, it activates the update.
*
* @property
* `updateActivated` {Observable<string>} - Emit the version hash whenever an update is activated.
*/
@Injectable()
export class SwUpdatesService implements OnDestroy {
private checkInterval = 1000 * 60 * 60 * 6; // 6 hours
private onDestroy = new Subject<void>();
/** Emit the version hash whenever an update is activated. */
updateActivated: Observable<string>;
constructor(appRef: ApplicationRef, private logger: Logger, private swu: SwUpdate) {

View File

@ -38,7 +38,11 @@
margin: 0;
clear: left;
}
.actions {
display: flex;
color: $blue;
@include font-size(14);
}
.show-all {
display: initial;
}

View File

@ -105,9 +105,7 @@
li {
box-sizing: border-box;
@include font-size(12);
@include line-height(16);
padding: 3px 0 3px 12px;
padding: 7px 0 7px 12px;
position: relative;
transition: all 0.3s ease-in-out;
@ -129,6 +127,7 @@
color: lighten($darkgray, 10);
overflow: visible;
@include font-size(12);
@include line-height(16);
display: table-cell;
}
@ -168,11 +167,11 @@
}
&:first-child:before {
top: 13px;
top: 15px;
}
&:last-child:before {
bottom: calc(100% - 14px);
bottom: calc(100% - 15px);
}
&:not(.active):hover a:before {

View File

@ -1,6 +1,6 @@
import { ApiPage } from './api.po';
describe('Api pages', function() {
describe('Api pages', () => {
it('should show direct subclasses of a class', () => {
const page = new ApiPage('api/forms/AbstractControlDirective');
expect(page.getDescendants('class', true)).toEqual(['ControlContainer', 'NgControl']);

View File

@ -1,7 +1,7 @@
import { browser, by, element, ElementFinder } from 'protractor';
import { SitePage } from './app.po';
describe('site App', function() {
describe('site App', () => {
let page: SitePage;
beforeEach(() => {

View File

@ -3,7 +3,7 @@ import { SitePage } from './app.po';
/* tslint:disable:max-line-length */
describe('onerror handler', function() {
describe('onerror handler', () => {
let page: SitePage;
beforeAll(() => {
@ -186,7 +186,7 @@ createViewNodes@???`);
});
async function callOnError(message: string, url?: string, line?: number, column?: number, error?: Error) {
await browser.executeScript(function() {
await browser.executeScript(() => {
// reset the ga queue
(window as any).ga.q.length = 0;
// post the error to the handler

View File

@ -76,7 +76,7 @@
"lite-server": "^2.2.2",
"lodash": "^4.16.2",
"protractor": "~7.0.0",
"puppeteer": "3.3.0",
"puppeteer": "5.1.0",
"rimraf": "^2.5.4",
"rollup": "^1.1.0",
"rollup-plugin-commonjs": "^9.2.1",

View File

@ -4336,6 +4336,11 @@ dev-ip@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0"
devtools-protocol@0.0.767361:
version "0.0.767361"
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.767361.tgz#5977f2558b84f9df36f62501bdddb82f3ae7b66b"
integrity sha512-ziRTdhEVQ9jEwedaUaXZ7kl9w9TF/7A3SXQ0XuqrJB+hMS62POHZUWTbumDN2ehRTfvWqTPc2Jw4gUl/jggmHA==
dezalgo@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456"
@ -7704,6 +7709,11 @@ mitt@^1.1.3:
resolved "https://registry.yarnpkg.com/mitt/-/mitt-1.2.0.tgz#cb24e6569c806e31bd4e3995787fe38a04fdf90d"
integrity sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==
mitt@^2.0.1:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mitt/-/mitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230"
integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==
mixin-deep@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.0.tgz#47a8732ba97799457c8c1eca28f95132d7e8150a"
@ -8759,7 +8769,7 @@ pkg-dir@^3.0.0:
dependencies:
find-up "^3.0.0"
pkg-dir@^4.1.0:
pkg-dir@^4.1.0, pkg-dir@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
@ -9363,15 +9373,18 @@ punycode@^2.1.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
puppeteer@3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-3.3.0.tgz#95839af9fdc0aa4de7e5ee073a4c0adeb9e2d3d7"
integrity sha512-23zNqRltZ1PPoK28uRefWJ/zKb5Jhnzbbwbpcna2o5+QMn17F0khq5s1bdH3vPlyj+J36pubccR8wiNA/VE0Vw==
puppeteer@5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-5.1.0.tgz#e7bae2caa6e3a13a622755e4c27689d9812c38ca"
integrity sha512-IZBFG8XcA+oHxYo5rEpJI/HQignUis2XPijPoFpNxla2O+WufonGsUsSqrhRXgBKOME5zNfhRdUY2LvxAiKlhw==
dependencies:
debug "^4.1.0"
devtools-protocol "0.0.767361"
extract-zip "^2.0.0"
https-proxy-agent "^4.0.0"
mime "^2.0.3"
mitt "^2.0.1"
pkg-dir "^4.2.0"
progress "^2.0.1"
proxy-from-env "^1.0.0"
rimraf "^3.0.2"

View File

@ -12,12 +12,16 @@
{% for option in doc.members %}
<a id="{$ option.anchor $}"></a>
<table class="is-full-width option-table">
<thead><tr><th>
<div class="with-github-links">
<h3>{$ option.name $}</h3>
{$ github.githubLinks(option, versionInfo) $}
</div>
</th></tr></thead>
<thead>
<tr>
<th>
<div class="with-github-links">
<h3>{$ option.name $}</h3>
{$ github.githubLinks(option, versionInfo) $}
</div>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
@ -26,8 +30,9 @@
</tr>
<tr>
<td>
<code-example language="ts" hideCopy="true" class="no-box api-heading{% if option.deprecated %} deprecated-api-item{% endif %}">
{$ option.name $}: {$ option.type | escape $}
<code-example language="ts" hideCopy="true"
class="no-box api-heading{% if option.deprecated %} deprecated-api-item{% endif %}">
{$ option.name $}{%- if option.isOptional %}?{% endif -%}: {$ option.type | escape $}
</code-example>
</td>
</tr>

View File

@ -10,7 +10,7 @@
<tr class="option">
<td>
<a class="code-anchor" href="{$ doc.path $}#{$ option.anchor | urlencode $}">
<code>{$ option.name $}</code>
<code>{$ option.name $}{%- if option.isOptional %}?{% endif -%}</code>
</a>
</td>
<td>{$ option.shortDescription | marked $}</td>

View File

@ -132,11 +132,11 @@
<summary>
<div class="icon-action-header">
<h4 class="no-anchor">{$ method.overloads.length $} overloads...</h4>
<a>
<span class="actions">
<span class="show-all">Show All</span>
<span class="collapse-all">Hide All</span>
<i class="material-icons expand">expand_more</i>
</a>
</span>
</div>
</summary>
<div class="detail-contents">

View File

@ -11,32 +11,16 @@
]
},
"array-type": false,
"arrow-parens": false,
"arrow-return-shorthand": true,
"ban": [
true,
{"name": "fdescribe", "message": "Don't keep jasmine focus methods."},
{"name": "fit", "message": "Don't keep jasmine focus methods."}
],
"component-class-suffix": true,
"component-selector": [
true,
"element",
"aio",
"kebab-case"
],
"contextual-lifecycle": true,
"curly": true,
"deprecation": {
"severity": "warn"
"severity": "warning"
},
"directive-class-suffix": true,
"directive-selector": [
true,
"attribute",
"aio",
"camelCase"
],
"eofline": true,
"import-blacklist": [
true,
@ -48,13 +32,11 @@
"spaces"
]
},
"interface-name": false,
"max-classes-per-file": false,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
{
@ -66,8 +48,8 @@
]
}
],
"no-conflicting-lifecycle": true,
"no-consecutive-blank-lines": false,
// TODO(gkalpak): Fix the code and enable this to align with CLI. (Failures: 114)
// "no-any": true,
"no-console": [
true,
"debug",
@ -77,24 +59,20 @@
"trace"
],
"no-empty": false,
"no-host-metadata-property": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-input-rename": true,
"no-inputs-metadata-property": true,
"no-output-native": true,
"no-output-on-prefix": true,
"no-output-rename": true,
"no-outputs-metadata-property": true,
"no-string-literal": false,
// TODO(gkalpak): Fix the code and enable this to align with CLI. (Failures: 59)
// "no-non-null-assertion": true,
"no-redundant-jsdoc": true,
// TODO(gkalpak): Fix the code and remove this to align with CLI.
"no-switch-case-fall-through": true,
"no-var-requires": false,
"object-literal-key-quotes": false,
"object-literal-sort-keys": false,
"only-arrow-functions": false,
"ordered-imports": false,
"object-literal-key-quotes": [
true,
"as-needed"
],
"quotemark": [
true,
"single"
@ -113,9 +91,11 @@
"named": "never"
}
},
"template-banana-in-box": true,
"template-no-negated-async": true,
"trailing-comma": false,
// TODO(gkalpak): Fix the code and enable this to align with CLI. (Failures: 243)
// "typedef": [
// true,
// "call-signature"
// ],
"typedef-whitespace": {
"options": [
{
@ -134,26 +114,15 @@
}
]
},
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"variable-name": [
true,
"allow-leading-underscore",
"allow-pascal-case",
"ban-keywords",
"check-format",
"require-const-for-all-caps"
],
"template-accessibility-alt-text": true,
"template-accessibility-elements-content": true,
"template-accessibility-label-for": true,
"template-accessibility-tabindex-no-positive": true,
"template-accessibility-table-scope": true,
"template-accessibility-valid-aria": true,
"template-click-events-have-key-events": true,
"template-mouse-events-have-key-events": true,
"template-no-autofocus": true,
"template-no-distracting-elements": true,
"variable-name": {
"options": [
"ban-keywords",
"check-format",
"allow-leading-underscore",
"allow-pascal-case",
"require-const-for-all-caps"
]
},
"whitespace": {
"options": [
"check-branch",
@ -163,6 +132,43 @@
"check-type",
"check-typecast"
]
}
},
"component-class-suffix": true,
"contextual-lifecycle": true,
"directive-class-suffix": true,
"no-conflicting-lifecycle": true,
"no-host-metadata-property": true,
"no-input-rename": true,
"no-inputs-metadata-property": true,
"no-output-native": true,
"no-output-on-prefix": true,
"no-output-rename": true,
"no-outputs-metadata-property": true,
"template-accessibility-alt-text": true,
"template-accessibility-elements-content": true,
"template-accessibility-label-for": true,
"template-accessibility-tabindex-no-positive": true,
"template-accessibility-table-scope": true,
"template-accessibility-valid-aria": true,
"template-banana-in-box": true,
"template-click-events-have-key-events": true,
"template-mouse-events-have-key-events": true,
"template-no-autofocus": true,
"template-no-distracting-elements": true,
"template-no-negated-async": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"directive-selector": [
true,
"attribute",
"aio",
"camelCase"
],
"component-selector": [
true,
"element",
"aio",
"kebab-case"
]
}
}

View File

@ -4509,6 +4509,11 @@ detect-node@^2.0.4:
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
devtools-protocol@0.0.767361:
version "0.0.767361"
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.767361.tgz#5977f2558b84f9df36f62501bdddb82f3ae7b66b"
integrity sha512-ziRTdhEVQ9jEwedaUaXZ7kl9w9TF/7A3SXQ0XuqrJB+hMS62POHZUWTbumDN2ehRTfvWqTPc2Jw4gUl/jggmHA==
dezalgo@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456"
@ -8926,6 +8931,11 @@ mississippi@^3.0.0:
stream-each "^1.1.0"
through2 "^2.0.0"
mitt@^2.0.1:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mitt/-/mitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230"
integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==
mixin-deep@^1.2.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
@ -10040,7 +10050,7 @@ pkg-dir@^3.0.0:
dependencies:
find-up "^3.0.0"
pkg-dir@^4.1.0:
pkg-dir@^4.1.0, pkg-dir@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
@ -10695,15 +10705,18 @@ punycode@^2.1.0, punycode@^2.1.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
puppeteer@3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-3.3.0.tgz#95839af9fdc0aa4de7e5ee073a4c0adeb9e2d3d7"
integrity sha512-23zNqRltZ1PPoK28uRefWJ/zKb5Jhnzbbwbpcna2o5+QMn17F0khq5s1bdH3vPlyj+J36pubccR8wiNA/VE0Vw==
puppeteer@5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-5.1.0.tgz#e7bae2caa6e3a13a622755e4c27689d9812c38ca"
integrity sha512-IZBFG8XcA+oHxYo5rEpJI/HQignUis2XPijPoFpNxla2O+WufonGsUsSqrhRXgBKOME5zNfhRdUY2LvxAiKlhw==
dependencies:
debug "^4.1.0"
devtools-protocol "0.0.767361"
extract-zip "^2.0.0"
https-proxy-agent "^4.0.0"
mime "^2.0.3"
mitt "^2.0.1"
pkg-dir "^4.2.0"
progress "^2.0.1"
proxy-from-env "^1.0.0"
rimraf "^3.0.2"

View File

@ -1,5 +1,5 @@
load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm")
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "cli",
@ -11,6 +11,7 @@ ts_library(
"//dev-infra/caretaker",
"//dev-infra/commit-message",
"//dev-infra/format",
"//dev-infra/ngbot",
"//dev-infra/pr",
"//dev-infra/pullapprove",
"//dev-infra/release",
@ -48,7 +49,7 @@ pkg_npm(
# substitutions to replace these in the published version of dev-infra.
"//dev-infra/": "@npm_angular_dev_infra_private//",
"//packages/benchpress": "@npm//@angular/benchpress",
"//packages/bazel/": "@npm_angular_bazel//",
"//packages/bazel": "@npm//@angular/bazel",
"//packages/zone.js/bundles:zone.umd.js": "@npm//:node_modules/zone.js/dist/zone.js",
"//packages/core": "@npm//@angular/core",
"//packages/platform-browser": "@npm//@angular/platform-browser",
@ -56,7 +57,7 @@ pkg_npm(
# This substitution is particularly verbose because we need to make sure
# that only things available via Angular Bazel are imported from
# tools/defaults.bzl.
"load\(\"//tools:defaults.bzl\", \"ng_module\"\)": "load(\"@npm_angular_bazel//:index.bzl\", \"ng_module\")",
"load\(\"//tools:defaults.bzl\", \"ng_module\"\)": "load(\"@npm//@angular/bazel:index.bzl\", \"ng_module\")",
},
visibility = ["//visibility:public"],
deps = [

View File

@ -1,4 +1,4 @@
load("@npm_bazel_protractor//:index.bzl", "protractor_web_test_suite")
load("@npm//@bazel/protractor:index.bzl", "protractor_web_test_suite")
"""
Macro that can be used to define a benchmark test. This differentiates from

View File

@ -1,6 +1,6 @@
load("//dev-infra/benchmark/ng_rollup_bundle:ng_rollup_bundle.bzl", "ng_rollup_bundle")
load("//tools:defaults.bzl", "ng_module")
load("@npm_bazel_typescript//:index.bzl", "ts_devserver", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_devserver", "ts_library")
load(":benchmark_test.bzl", "benchmark_test")
def copy_default_file(origin, destination):

View File

@ -1,6 +1,6 @@
package(default_visibility = ["//visibility:public"])
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "driver-utilities",

View File

@ -4,8 +4,8 @@
# found in the LICENSE file at https://angular.io/license
load("@build_bazel_rules_nodejs//:index.bzl", "npm_package_bin")
load("@npm_bazel_terser//:index.bzl", "terser_minified")
load("@npm_bazel_rollup//:index.bzl", "rollup_bundle")
load("@npm//@bazel/terser:index.bzl", "terser_minified")
load("@npm//@bazel/rollup:index.bzl", "rollup_bundle")
load("//dev-infra/bazel:expand_template.bzl", "expand_template")
def ng_rollup_bundle(

View File

@ -12,47 +12,47 @@ def define_chromium_repositories():
platform_http_file(
name = "org_chromium_chromium_amd64",
licenses = ["notice"], # BSD 3-clause (maybe more?)
sha256 = "2cfd74ee58c79d8b7aada05c899a930967e2fd8bb0186582cde02c7340863f64",
# 83.0.4103
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/756066/chrome-linux.zip"],
sha256 = "0e303931d9c3e065a160f5d31f1178c647f0748fb0b58b1945b84b04fe1c1165",
# 84.0.4147
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/768968/chrome-linux.zip"],
)
platform_http_file(
name = "org_chromium_chromium_macos",
licenses = ["notice"], # BSD 3-clause (maybe more?)
sha256 = "b841ec5ad03b08422d97593fc719f1c5b038703388ad65e6cd8cc8272d58958c",
# 83.0.4103
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/756053/chrome-mac.zip"],
sha256 = "39118c96db1b3fdb0129f434912a329c5ca07d3a1c6c6cda673d3383d83e2f9a",
# 84.0.4147
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/768968/chrome-mac.zip"],
)
platform_http_file(
name = "org_chromium_chromium_windows",
licenses = ["notice"], # BSD 3-clause (maybe more?)
sha256 = "4683d7ac88dfec4b98d1da3012ecc8e42cc8c1a560a7b95589ad4cc96bf90fcb",
# 83.0.4103
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Win/756065/chrome-win.zip"],
sha256 = "3429746fa80c917c6f4d5d96aba4e58894b905a2b8392e43ddb470c5ba612d60",
# 84.0.4147
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Win/768975/chrome-win.zip"],
)
platform_http_file(
name = "org_chromium_chromedriver_amd64",
licenses = ["reciprocal"], # BSD 3-clause, ICU, MPL 1.1, libpng (BSD/MIT-like), Academic Free License v. 2.0, BSD 2-clause, MIT
sha256 = "95dded16000b82e31445361da7d251ed707e027a4b61e9a3ec5fbd1cc2f62bb1",
# 83.0.4103
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/756066/chromedriver_linux64.zip"],
sha256 = "f6b9852031d185739a2c1816508fe8158eb92782d13e831b8345957ef2506fe8",
# 84.0.4147
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/768968/chromedriver_linux64.zip"],
)
platform_http_file(
name = "org_chromium_chromedriver_macos",
licenses = ["reciprocal"], # BSD 3-clause, ICU, MPL 1.1, libpng (BSD/MIT-like), Academic Free License v. 2.0, BSD 2-clause, MIT
sha256 = "17260e9b2222b0c905a1861285210192baef830f4281778903e7cebb8db683cc",
# 83.0.4103
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/756053/chromedriver_mac64.zip"],
sha256 = "aa0124085146556d5d32ad172670e5dcef79b7429380112ad02898047ba7a8b7",
# 84.0.4147
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/768968/chromedriver_mac64.zip"],
)
platform_http_file(
name = "org_chromium_chromedriver_windows",
licenses = ["reciprocal"], # BSD 3-clause, ICU, MPL 1.1, libpng (BSD/MIT-like), Academic Free License v. 2.0, BSD 2-clause, MIT
sha256 = "de1423b2d69f96e451e902d686e8d471610d786c345a8de59dd1a5a436e45fc2",
# 83.0.4103
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Win/756065/chromedriver_win32.zip"],
sha256 = "c4b04fd263e757d3aa99c596832f2c414f9f00e80d2769590e2b9044072b140e",
# 84.0.4147
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Win/768975/chromedriver_win32.zip"],
)

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "caretaker",
@ -8,6 +8,7 @@ ts_library(
module_name = "@angular/dev-infra-private/caretaker",
visibility = ["//dev-infra:__subpackages__"],
deps = [
"//dev-infra/release/versioning",
"//dev-infra/utils",
"@npm//@types/node",
"@npm//@types/node-fetch",

View File

@ -7,52 +7,55 @@
*/
import fetch from 'node-fetch';
import {fetchActiveReleaseTrains} from '../../release/versioning/index';
import {bold, green, info, red} from '../../utils/console';
import {bold, debug, info} from '../../utils/console';
import {GitClient} from '../../utils/git';
/** The results of checking the status of CI. */
interface StatusCheckResult {
status: 'success'|'failed'|'canceled'|'infrastructure_fail'|'timedout'|'failed'|'no_tests';
timestamp: Date;
buildUrl: string;
status: 'success'|'failed';
}
/** Retrieve and log status of CI for the project. */
export async function printCiStatus(git: GitClient) {
const releaseTrains = await fetchActiveReleaseTrains({api: git.github, ...git.remoteConfig});
info.group(bold(`CI`));
// TODO(josephperrott): Expand list of branches checked to all active branches.
await printStatus(git, 'master');
for (const [trainName, train] of Object.entries(releaseTrains)) {
if (train === null) {
debug(`No active release train for ${trainName}`);
continue;
}
const status = await getStatusOfBranch(git, train.branchName);
await printStatus(`${trainName.padEnd(6)} (${train.branchName})`, status);
}
info.groupEnd();
info();
}
/** Log the status of CI for a given branch to the console. */
async function printStatus(git: GitClient, branch: string) {
const result = await getStatusOfBranch(git, branch);
const branchName = branch.padEnd(10);
if (result === null) {
async function printStatus(label: string, status: StatusCheckResult|null) {
const branchName = label.padEnd(16);
if (status === null) {
info(`${branchName} was not found on CircleCI`);
} else if (result.status === 'success') {
} else if (status.status === 'success') {
info(`${branchName}`);
} else {
info(`${branchName} (Ran at: ${result.timestamp.toLocaleString()})`);
info(`${branchName}`);
}
}
/** Get the CI status of a given branch from CircleCI. */
async function getStatusOfBranch(git: GitClient, branch: string): Promise<StatusCheckResult|null> {
const {owner, name} = git.remoteConfig;
const url = `https://circleci.com/api/v1.1/project/gh/${owner}/${name}/tree/${
branch}?limit=1&filter=completed&shallow=true`;
const result = (await fetch(url).then(result => result.json()))?.[0];
const url = `https://circleci.com/gh/${owner}/${name}/tree/${branch}.svg?style=shield`;
const result = await fetch(url).then(result => result.text());
if (result) {
if (result && !result.includes('no builds')) {
return {
status: result.outcome,
timestamp: new Date(result.stop_time),
buildUrl: result.build_url
status: result.includes('passing') ? 'success' : 'failed',
};
}
return null;

View File

@ -44,7 +44,8 @@ export async function printG3Comparison(git: GitClient) {
/** 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}`]);
const fetchResult =
git.runGraceful(['fetch', '-q', 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) {
@ -118,6 +119,6 @@ export async function printG3Comparison(git: GitClient) {
/** 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;
return multimatch(file, includes).length >= 1 && multimatch(file, excludes).length === 0;
}
}

View File

@ -6,12 +6,17 @@
* found in the LICENSE file at https://angular.io/license
*/
import {alias, params, types} from 'typed-graphqlify';
import {alias, onUnion, params, types} from 'typed-graphqlify';
import {bold, debug, info} from '../../utils/console';
import {GitClient} from '../../utils/git';
import {CaretakerConfig} from '../config';
/**
* Cap the returned issues in the queries to an arbitrary 100. At that point, caretaker has a lot
* of work to do and showing more than that isn't really useful.
*/
const MAX_RETURNED_ISSUES = 20;
/** Retrieve the number of matching issues for each github query. */
export async function printGithubTasks(git: GitClient, config?: CaretakerConfig) {
@ -19,7 +24,7 @@ export async function printGithubTasks(git: GitClient, config?: CaretakerConfig)
debug('No github queries defined in the configuration, skipping.');
return;
}
info.group(bold('Github Tasks'));
info.group(bold(`Github Tasks`));
await getGithubInfo(git, config);
info.groupEnd();
info();
@ -28,7 +33,12 @@ export async function printGithubTasks(git: GitClient, config?: CaretakerConfig)
/** Retrieve query match counts and log discovered counts to the console. */
async function getGithubInfo(git: GitClient, {githubQueries: queries = []}: CaretakerConfig) {
/** The query object for graphql. */
const graphQlQuery: {[key: string]: {issueCount: number}} = {};
const graphQlQuery: {
[key: string]: {
issueCount: number,
nodes: Array<{url: string}>,
}
} = {};
/** The Github search filter for the configured repository. */
const repoFilter = `repo:${git.remoteConfig.owner}/${git.remoteConfig.name}`;
queries.forEach(({name, query}) => {
@ -37,14 +47,37 @@ async function getGithubInfo(git: GitClient, {githubQueries: queries = []}: Care
graphQlQuery[queryKey] = params(
{
type: 'ISSUE',
first: MAX_RETURNED_ISSUES,
query: `"${repoFilter} ${query.replace(/"/g, '\\"')}"`,
},
{issueCount: types.number},
{
issueCount: types.number,
nodes: [{...onUnion({
PullRequest: {
url: types.string,
},
Issue: {
url: types.string,
},
})}],
},
);
});
/** The results of the generated github query. */
const results = await git.github.graphql.query(graphQlQuery);
Object.values(results).forEach((result, i) => {
info(`${queries[i]?.name.padEnd(25)} ${result.issueCount}`);
if (result.issueCount > 0) {
const {owner, name: repo} = git.remoteConfig;
const url = encodeURI(`https://github.com/${owner}/${repo}/issues?q=${queries[i]?.query}`);
info.group(`${url}`);
if (result.nodes.length === MAX_RETURNED_ISSUES && result.nodes.length < result.issueCount) {
info(`(first ${MAX_RETURNED_ISSUES})`);
}
for (const node of result.nodes) {
info(`- ${node.url}`);
}
info.groupEnd();
}
});
}

View File

@ -15,6 +15,7 @@ import {buildReleaseParser} from './release/cli';
import {buildPrParser} from './pr/cli';
import {captureLogOutputForCommand} from './utils/console';
import {buildCaretakerParser} from './caretaker/cli';
import {buildNgbotParser} from './ngbot/cli';
yargs.scriptName('ng-dev')
.middleware(captureLogOutputForCommand)
@ -27,6 +28,7 @@ yargs.scriptName('ng-dev')
.command('release <command>', '', buildReleaseParser)
.command('ts-circular-deps <command>', '', tsCircularDependenciesBuilder)
.command('caretaker <command>', '', buildCaretakerParser)
.command('ngbot <command>', false, buildNgbotParser)
.wrap(120)
.strict()
.parse();

View File

@ -1,5 +1,5 @@
load("//tools:defaults.bzl", "jasmine_node_test")
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "commit-message",

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "format",

View File

@ -0,0 +1,19 @@
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "ngbot",
srcs = [
"cli.ts",
"verify.ts",
],
module_name = "@angular/dev-infra-private/ngbot",
visibility = ["//dev-infra:__subpackages__"],
deps = [
"//dev-infra/utils",
"@npm//@types/node",
"@npm//@types/yaml",
"@npm//@types/yargs",
"@npm//yaml",
"@npm//yargs",
],
)

19
dev-infra/ngbot/cli.ts Normal file
View File

@ -0,0 +1,19 @@
/**
* @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 * as yargs from 'yargs';
import {verify} from './verify';
/** Build the parser for the NgBot commands. */
export function buildNgbotParser(localYargs: yargs.Argv) {
return localYargs.help().strict().demandCommand().command(
'verify', 'Verify the NgBot config', {}, () => verify());
}
if (require.main === module) {
buildNgbotParser(yargs).parse();
}

31
dev-infra/ngbot/verify.ts Normal file
View File

@ -0,0 +1,31 @@
/**
* @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 {readFileSync} from 'fs';
import {resolve} from 'path';
import {parse as parseYaml} from 'yaml';
import {getRepoBaseDir} from '../utils/config';
import {error, green, info, red} from '../utils/console';
export function verify() {
/** Full path to NgBot config file */
const NGBOT_CONFIG_YAML_PATH = resolve(getRepoBaseDir(), '.github/angular-robot.yml');
/** The NgBot config file */
const ngBotYaml = readFileSync(NGBOT_CONFIG_YAML_PATH, 'utf8');
try {
// Try parsing the config file to verify that the syntax is correct.
parseYaml(ngBotYaml);
info(`${green('√')} Valid NgBot YAML config`);
} catch (e) {
error(`${red('!')} Invalid NgBot YAML config`);
error(e);
process.exitCode = 1;
}
}

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "pr",

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "checkout",

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "common",

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "discover-new-conflicts",

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
load("//tools:defaults.bzl", "jasmine_node_test")
ts_library(

View File

@ -41,8 +41,8 @@ export async function getDefaultTargetLabelConfiguration(
// allow merging of PRs with `target: major`.
if (!next.isMajor) {
throw new InvalidTargetLabelError(
`Unable to merge pull request. The "${nextBranchName}" branch will be ` +
`released as a minor version.`);
`Unable to merge pull request. The "${nextBranchName}" branch will be released as ` +
'a minor version.');
}
return [nextBranchName];
},

View File

@ -30,8 +30,8 @@ export async function assertActiveLtsBranch(
const ltsNpmTag = getLtsNpmDistTagOfMajor(version.major);
const ltsVersion = semver.parse(distTags[ltsNpmTag]);
// Ensure that there is a LTS version tagged for the given version-branch major. e.g.
// if the version branch is `9.2.x` then we want to make sure that there is a LTS
// Ensure that there is an LTS version tagged for the given version-branch major. e.g.
// if the version branch is `9.2.x` then we want to make sure that there is an LTS
// version tagged in NPM for `v9`, following the `v{major}-lts` tag convention.
if (ltsVersion === null) {
throw new InvalidTargetBranchError(`No LTS version tagged for v${version.major} in NPM.`);

View File

@ -33,7 +33,7 @@ export async function mergePullRequest(
prNumber: number, githubToken: string, projectRoot: string = getRepoBaseDir(),
config?: MergeConfigWithRemote) {
// Set the environment variable to skip all git commit hooks triggered by husky. We are unable to
// rely on `---no-verify` as some hooks still run, notably the `prepare-commit-msg` hook.
// rely on `--no-verify` as some hooks still run, notably the `prepare-commit-msg` hook.
process.env['HUSKY_SKIP_HOOKS'] = '1';
const api = await createPullRequestMergeTask(githubToken, projectRoot, config);

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "rebase",

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
load("//tools:defaults.bzl", "jasmine_node_test")
ts_library(

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "release",

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
load("//tools:defaults.bzl", "jasmine_node_test")
ts_library(

View File

@ -60,7 +60,7 @@ describe('ng-dev release build', () => {
});
it('should error if package has not been built', async () => {
// Set up a NPM package that is not built.
// Set up an NPM package that is not built.
npmPackages.push('@angular/non-existent');
spyOn(console, 'error');

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "config",

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "publish",

View File

@ -7,7 +7,7 @@
*/
import {promises as fs} from 'fs';
import * as Ora from 'ora';
import * as ora from 'ora';
import {join} from 'path';
import * as semver from 'semver';
@ -44,7 +44,7 @@ export interface PullRequest {
forkBranch: string;
}
/** Constructor type for a instantiating a release action */
/** Constructor type for instantiating a release action */
export interface ReleaseActionConstructor<T extends ReleaseAction = ReleaseAction> {
/** Whether the release action is currently active. */
isActive(active: ActiveReleaseTrains): Promise<boolean>;
@ -107,25 +107,22 @@ export abstract class ReleaseAction {
if (state === 'failure') {
error(
red(` ✘ Cannot stage release. Commit "${commitSha}" does not pass all github ` +
`status checks. Please make sure this commit passes all checks before re-running.`));
'status checks. Please make sure this commit passes all checks before re-running.'));
error(` Please have a look at: ${branchCommitsUrl}`);
if (await promptConfirm('Do you want to ignore the Github status and proceed?')) {
info(yellow(
` ⚠ Upstream commit is failing CI checks, but status has been ` +
`forcibly ignored.`));
' ⚠ Upstream commit is failing CI checks, but status has been forcibly ignored.'));
return;
}
throw new UserAbortedReleaseActionError();
} else if (state === 'pending') {
error(
red(` ✘ Commit "${commitSha}" still has pending github statuses that ` +
`need to succeed before staging a release.`));
'need to succeed before staging a release.'));
error(red(` Please have a look at: ${branchCommitsUrl}`));
if (await promptConfirm('Do you want to ignore the Github status and proceed?')) {
info(yellow(
` ⚠ Upstream commit is pending CI, but status has been ` +
`forcibly ignored.`));
info(yellow(' ⚠ Upstream commit is pending CI, but status has been forcibly ignored.'));
return;
}
throw new UserAbortedReleaseActionError();
@ -157,9 +154,9 @@ export abstract class ReleaseAction {
*/
protected async waitForEditsAndCreateReleaseCommit(newVersion: semver.SemVer) {
info(yellow(
` ⚠ Please review the changelog and ensure that the log contains only changes ` +
`that apply to the public API surface. Manual changes can be made. When done, please ` +
`proceed with the prompt below.`));
' ⚠ Please review the changelog and ensure that the log contains only changes ' +
'that apply to the public API surface. Manual changes can be made. When done, please ' +
'proceed with the prompt below.'));
if (!await promptConfirm('Do you want to proceed and commit the changes?')) {
throw new UserAbortedReleaseActionError();
@ -188,7 +185,7 @@ export abstract class ReleaseAction {
const forks = result.repository.forks.nodes;
if (forks.length === 0) {
error(red(` ✘ Unable to find fork for currently authenticated user.`));
error(red(' ✘ Unable to find fork for currently authenticated user.'));
error(red(` Please ensure you created a fork of: ${owner}/${name}.`));
throw new FatalReleaseActionError();
}
@ -304,7 +301,7 @@ export abstract class ReleaseAction {
return new Promise((resolve, reject) => {
debug(`Waiting for pull request #${id} to be merged.`);
const spinner = Ora().start(`Waiting for pull request #${id} to be merged.`);
const spinner = ora().start(`Waiting for pull request #${id} to be merged.`);
const intervalId = setInterval(async () => {
const prState = await getPullRequestState(this.git, id);
if (prState === 'merged') {
@ -451,7 +448,7 @@ export abstract class ReleaseAction {
info(green(
` ✓ Pull request for cherry-picking the changelog into "${nextBranch}" ` +
`has been created.`));
'has been created.'));
info(yellow(` Please ask team members to review: ${url}.`));
return true;
}
@ -490,7 +487,7 @@ export abstract class ReleaseAction {
if (!await this._isCommitForVersionStaging(newVersion, versionBumpCommitSha)) {
error(red(` ✘ Latest commit in "${publishBranch}" branch is not a staging commit.`));
error(red(` Please make sure the staging pull request has been merged.`));
error(red(' Please make sure the staging pull request has been merged.'));
throw new FatalReleaseActionError();
}
@ -514,13 +511,13 @@ export abstract class ReleaseAction {
await this._publishBuiltPackageToNpm(builtPackage, npmDistTag);
}
info(green(` ✓ Published all packages successfully`));
info(green(' ✓ Published all packages successfully'));
}
/** Publishes the given built package to NPM with the specified NPM dist tag. */
private async _publishBuiltPackageToNpm(pkg: BuiltPackage, npmDistTag: string) {
debug(`Starting publish of "${pkg.name}".`);
const spinner = Ora().start(`Publishing "${pkg.name}"`);
const spinner = ora().start(`Publishing "${pkg.name}"`);
try {
await runNpmPublish(pkg.outputPath, npmDistTag, this.config.publishRegistry);

View File

@ -65,14 +65,14 @@ export class CutLongTermSupportPatchAction extends ReleaseAction {
{
name: 'activeLtsBranch',
type: 'list',
message: 'Please select a version for which you want to cut a LTS patch',
message: 'Please select a version for which you want to cut an LTS patch',
choices: activeBranchChoices,
},
{
name: 'inactiveLtsBranch',
type: 'list',
when: o => o.activeLtsBranch === null,
message: 'Please select an inactive LTS version for which you want to cut a LTS patch',
message: 'Please select an inactive LTS version for which you want to cut an LTS patch',
choices: inactive.map(branch => this._getChoiceForLtsBranch(branch)),
}
]);

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import * as Ora from 'ora';
import * as ora from 'ora';
import * as semver from 'semver';
import {spawnWithDebugOutput} from '../../utils/child-process';
@ -19,11 +19,11 @@ import {FatalReleaseActionError} from './actions-error';
* ###############################################################
*
* This file contains helpers for invoking external `ng-dev` commands. A subset of actions,
* like building release output or setting a NPM dist tag for release packages, cannot be
* like building release output or setting aν NPM dist tag for release packages, cannot be
* performed directly as part of the release tool and need to be delegated to external `ng-dev`
* commands that exist across arbitrary version branches.
*
* In an concrete example: Consider a new patch version is released and that a new release
* In a concrete example: Consider a new patch version is released and that a new release
* package has been added to the `next` branch. The patch branch will not contain the new
* release package, so we could not build the release output for it. To work around this, we
* call the ng-dev build command for the patch version branch and expect it to return a list
@ -44,7 +44,7 @@ export async function invokeSetNpmDistCommand(npmDistTag: string, version: semve
info(green(` ✓ Set "${npmDistTag}" NPM dist tag for all packages to v${version}.`));
} catch (e) {
error(e);
error(red(` ✘ An error occurred while setting the NPM dist tag for ${npmDistTag}.`));
error(red(` ✘ An error occurred while setting the NPM dist tag for "${npmDistTag}".`));
throw new FatalReleaseActionError();
}
}
@ -54,21 +54,21 @@ export async function invokeSetNpmDistCommand(npmDistTag: string, version: semve
* packages for the currently checked out branch.
*/
export async function invokeReleaseBuildCommand(): Promise<BuiltPackage[]> {
const spinner = Ora().start('Building release output.');
const spinner = ora().start('Building release output.');
try {
// Since we expect JSON to be printed from the `ng-dev release build` command,
// we spawn the process in silent mode. We have set up an Ora progress spinner.
const {stdout} = await spawnWithDebugOutput(
'yarn', ['--silent', 'ng-dev', 'release', 'build', '--json'], {mode: 'silent'});
spinner.stop();
info(green(` ✓ Built release output for all packages.`));
info(green(' ✓ Built release output for all packages.'));
// The `ng-dev release build` command prints a JSON array to stdout
// that represents the built release packages and their output paths.
return JSON.parse(stdout.trim());
} catch (e) {
spinner.stop();
error(e);
error(red(` ✘ An error occurred while building the release packages.`));
error(red(' ✘ An error occurred while building the release packages.'));
throw new FatalReleaseActionError();
}
}
@ -83,10 +83,10 @@ export async function invokeYarnInstallCommand(projectDir: string): Promise<void
// TODO: Consider using an Ora spinner instead to ensure minimal console output.
await spawnWithDebugOutput(
'yarn', ['install', '--frozen-lockfile', '--non-interactive'], {cwd: projectDir});
info(green(` ✓ Installed project dependencies.`));
info(green(' ✓ Installed project dependencies.'));
} catch (e) {
error(e);
error(red(` ✘ An error occurred while installing dependencies.`));
error(red(' ✘ An error occurred while installing dependencies.'));
throw new FatalReleaseActionError();
}
}

View File

@ -66,8 +66,7 @@ export class ReleaseTool {
// Only print the error message and stack if the error is not a known fatal release
// action error (for which we print the error gracefully to the console with colors).
if (!(e instanceof FatalReleaseActionError) && e instanceof Error) {
console.error(e.message);
console.error(e.stack);
console.error(e);
}
return CompletionState.FATAL_ERROR;
} finally {
@ -90,7 +89,7 @@ export class ReleaseTool {
}
}
info(`Please select the type of release you want to perform.`);
info('Please select the type of release you want to perform.');
const {releaseAction} = await prompt<{releaseAction: ReleaseAction}>({
name: 'releaseAction',
@ -108,9 +107,7 @@ export class ReleaseTool {
*/
private async _verifyNoUncommittedChanges(): Promise<boolean> {
if (this._git.hasUncommittedChanges()) {
error(
red(` ✘ There are changes which are not committed and should be ` +
`discarded.`));
error(red(' ✘ There are changes which are not committed and should be discarded.'));
return false;
}
return true;
@ -126,7 +123,7 @@ export class ReleaseTool {
await this._git.github.repos.getBranch({...this._git.remoteParams, branch: nextBranchName});
if (headSha !== data.commit.sha) {
error(red(` ✘ Running release tool from an outdated local branch.`));
error(red(' ✘ Running release tool from an outdated local branch.'));
error(red(` Please make sure you are running from the "${nextBranchName}" branch.`));
return false;
}

View File

@ -68,5 +68,6 @@ async function isCommitClosingPullRequest(api: GitClient, sha: string, id: numbe
const {data} = await api.github.repos.getCommit({...api.remoteParams, ref: sha});
// Matches the closing keyword supported in commit messages. See:
// https://docs.github.com/en/enterprise/2.16/user/github/managing-your-work-on-github/closing-issues-using-keywords.
return data.commit.message.match(new RegExp(`close[sd]? #${id}[^0-9]?`, 'i'));
return data.commit.message.match(
new RegExp(`(?:close[sd]?|fix(?:e[sd]?)|resolve[sd]?):? #${id}(?!\\d)`, 'i'));
}

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
load("//tools:defaults.bzl", "jasmine_node_test")
ts_library(

View File

@ -13,7 +13,7 @@ import {CutLongTermSupportPatchAction} from '../actions/cut-lts-patch';
import {expectStagingAndPublishWithCherryPick, fakeNpmPackageQueryRequest, getTestingMocksForReleaseAction, parse, setupReleaseActionForTesting, testTmpDir} from './test-utils';
describe('cut a LTS patch action', () => {
describe('cut an LTS patch action', () => {
it('should be active', async () => {
expect(await CutLongTermSupportPatchAction.isActive({
releaseCandidate: null,

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
load("//tools:defaults.bzl", "jasmine_node_test")
ts_library(

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import * as Ora from 'ora';
import * as ora from 'ora';
import * as semver from 'semver';
import {Arguments, Argv, CommandModule} from 'yargs';
@ -15,7 +15,7 @@ import {getReleaseConfig} from '../config/index';
import {setNpmTagForPackage} from '../versioning/npm-publish';
/** Command line options for setting a NPM dist tag. */
/** Command line options for setting an NPM dist tag. */
export interface ReleaseSetDistTagOptions {
tagName: string;
targetVersion: string;
@ -42,11 +42,11 @@ async function handler(args: Arguments<ReleaseSetDistTagOptions>) {
const version = semver.parse(rawVersion);
if (version === null) {
error(red(`Invalid version specified. Unable to set NPM dist tag.`));
error(red(`Invalid version specified (${rawVersion}). Unable to set NPM dist tag.`));
process.exit(1);
}
const spinner = Ora().start();
const spinner = ora().start();
debug(`Setting "${tagName}" NPM dist tag for release packages to v${version}.`);
for (const pkgName of npmPackages) {
@ -69,7 +69,7 @@ async function handler(args: Arguments<ReleaseSetDistTagOptions>) {
info(green(` ${bold(tagName)} will now point to ${bold(`v${version}`)}.`));
}
/** CLI command module for setting a NPM dist tag. */
/** CLI command module for setting an NPM dist tag. */
export const ReleaseSetDistTagCommand: CommandModule<{}, ReleaseSetDistTagOptions> = {
builder,
handler,

View File

@ -66,7 +66,7 @@ describe('ng-dev release set-dist-tag', () => {
await invokeCommand('latest', '10.0');
expect(console.error)
.toHaveBeenCalledWith('Invalid version specified. Unable to set NPM dist tag.');
.toHaveBeenCalledWith('Invalid version specified (10.0). Unable to set NPM dist tag.');
expect(process.exit).toHaveBeenCalledWith(1);
expect(process.exit).toHaveBeenCalledTimes(1);
});

View File

@ -1,4 +1,4 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "versioning",

Some files were not shown because too many files have changed in this diff Show More