Compare commits

..

114 Commits

Author SHA1 Message Date
9f698b4de0 release: cut the v10.0.0-rc.4 release 2020-06-10 11:31:29 -07:00
742f3d6787 Revert "fix(elements): fire custom element output events during component initialization (#36161)" (#37524)
This reverts commit e9bff5fe9f. Failures
were detected in Google tests due to this commit

PR Close #37524
2020-06-10 17:28:57 +00:00
323651bd38 fix(compiler-cli): downlevel angular decorators to static properties (#37382)
In v7 of Angular we removed `tsickle` from the default `ngc` pipeline.
This had the negative potential of breaking ES2015 output and SSR due
to a limitation in TypeScript.

TypeScript by default preserves type information for decorated constructor
parameters when `emitDecoratorMetadata` is enabled. For example,
consider this snippet below:

```
@Directive()
export class MyDirective {
  constructor(button: MyButton) {}
}

export class MyButton {}
```

TypeScript would generate metadata for the `MyDirective` class it has
a decorator applied. This metadata would be needed in JIT mode, or
for libraries that provide `MyDirective` through NPM. The metadata would
look as followed:

```
let MyDirective = class MyDir {}

MyDirective = __decorate([
  Directive(),
  __metadata("design:paramtypes", [MyButton]),
], MyDirective);

let MyButton = class MyButton {}
```

Notice that TypeScript generated calls to `__decorate` and
`__metadata`. These calls are needed so that the Angular compiler
is able to determine whether `MyDirective` is actually an directive,
and what types are needed for dependency injection.

The limitation surfaces in this concrete example because `MyButton`
is declared after the `__metadata(..)` call, while `__metadata`
actually directly references `MyButton`. This is illegal though because
`MyButton` has not been declared at this point. This is due to the
so-called temporal dead zone in JavaScript. Errors like followed will
be reported at runtime when such file/code evaluates:

```
Uncaught ReferenceError: Cannot access 'MyButton' before initialization
```

As noted, this is a TypeScript limitation because ideally TypeScript
shouldn't evaluate `__metadata`/reference `MyButton` immediately.
Instead, it should defer the reference until `MyButton` is actually
declared. This limitation will not be fixed by the TypeScript team
though because it's a limitation as per current design and they will
only revisit this once the tc39 decorator proposal is finalized
(currently stage-2 at time of writing).

Given this wontfix on the TypeScript side, and our heavy reliance on
this metadata in libraries (and for JIT mode), we intend to fix this
from within the Angular compiler by downleveling decorators to static
properties that don't need to evaluate directly. For example:

```
MyDirective.ctorParameters = () => [MyButton];
```

With this snippet above, `MyButton` is not referenced directly. Only
lazily when the Angular runtime needs it. This mitigates the temporal
dead zone issue caused by a limitation in TypeScript's decorator
metadata output. See: https://github.com/microsoft/TypeScript/issues/27519.

In the past (as noted; before version 7), the Angular compiler by
default used tsickle that already performed this transformation. We
moved the transformation to the CLI for JIT and `ng-packager`, but now
we realize that we can move this all to a single place in the compiler
so that standalone ngc consumers can benefit too, and that we can
disable tsickle in our Bazel `ngc-wrapped` pipeline (that currently
still relies on tsickle to perform this decorator processing).

This transformation also has another positive side-effect of making
Angular application/library code more compatible with server-side
rendering. In principle, TypeScript would also preserve type information
for decorated class members (similar to how it did that for constructor
parameters) at runtime. This becomes an issue when your application
relies on native DOM globals for decorated class member types. e.g.

```
@Input() panelElement: HTMLElement;
```

Your application code would then reference `HTMLElement` directly
whenever the source file is loaded in NodeJS for SSR. `HTMLElement`
does not exist on the server though, so that will become an invalid
reference. One could work around this by providing global mocks for
these DOM symbols, but that doesn't match up with other places where
dependency injection is used for mocking DOM/browser specific symbols.

More context in this issue: #30586. The TL;DR here is that the Angular
compiler does not care about types for these class members, so it won't
ever reference `HTMLElement` at runtime.

Fixes #30106. Fixes #30586. Fixes #30141.
Resolves FW-2196. Resolves FW-2199.

PR Close #37382
2020-06-10 09:24:12 -07:00
9d397eb5a1 Revert "build: remove wombot proxy registry from package.jsons for release (#37378)" (#37495)
This reverts commit 26849ca99d.

PR Close #37495
2020-06-10 08:21:46 -07:00
6114cd2bd4 perf(core): avoid pulling in jit-specific code in aot bundles (#37372) (#37514)
In #29083 a call to `getCompilerFacade` was added to `ApplicationRef` which pulls in a bit of JIT-specific code. Since the code path that calls the function can't be hit for an AOT-compiled app, these changes add an `ngJitMode` guard which will allow for dead code elimination to drop it completely. Testing it out against a new CLI project showed a difference of ~1.2kb.

PR Close #37372

PR Close #37514
2020-06-09 14:49:05 -07:00
d494f7bd5e docs(dev-infra): add comment about what the requiredBaseCommit is (#37509)
Add a comment to describe what the commit was for the given SHA so that we don't have to look it up.

PR Close #37509
2020-06-09 13:29:24 -07:00
ec6a7ab721 docs: wrong links in lifecycle hooks api documentaion (#36557)
lifecycle hooks api detailed documentation contained links which were pointing to onChanges hook only which is removed, made each hook point towards its deafult page link

PR Close #36557
2020-06-09 11:16:43 -07:00
ad6d2b4619 docs(core): fix path referenced in comments of both compiler facade interface files (#37370)
Previously the comments for these files referenced a path to "packages/core/src/render3/jit/compiler_facade_interface.ts" that does not exist in the current codebase.

This PR corrects the path in these comments.

PR Close #37370
2020-06-09 08:28:26 -07:00
c093390010 fix(dev-infra): local changes check not working (#37489)
Looks like we broke the `hasLocalChanges` check in the git client
when we moved it over from the merge script. The problem is that
we are using `git` in the first argument of `git.run`. That
means that we under-the-hood run `git git <..>`.

This commit fixes that, but also switches to a better variant
for ensuring no local changes because it exits with non-zero
when there are local changes.

PR Close #37489
2020-06-09 08:27:32 -07:00
acd69f2be2 fix(dev-infra): rebase pr script not working (#37489)
The dev-infra rebase PR script currently does not work due to
the following issues:

1. The push refspec is incorrect. It refers to the `base` of the PR, and
not to the `head` of the PR.
2. The push `--force-with-lease` option does not work in a detached head
as no remote-tracking branch is set up.

PR Close #37489
2020-06-09 08:27:32 -07:00
5d2f341653 fix(dev-infra): incorrect token sanitization when no token is specified (#37489)
We recently moved over the git client from the merge script to the
common dev-infra utils. This made specifying a token optional, but
it looks like the logic for sanitizing messages doesn't account
for that, and we currently add `<TOKEN>` between every message
character. e.g.

```
Executing: git <TOKEN>g<TOKEN>i<TOKEN>t<TOKEN>
<TOKEN>s<TOKEN>t<TOKEN>a<TOKEN>t<TOKEN>u<TOKEN>s<TOKEN>
```

PR Close #37489
2020-06-09 08:27:32 -07:00
420d1c35f5 fix(platform-server): correctly handle absolute relative URLs (#37341)
Previously, we would simply prepend any relative URL with the HREF
for the current route (pulled from document.location). However,
this does not correctly account for the leading slash URLs that
would otherwise be parsed correctly in the browser, or the
presence of a base HREF in the DOM.

Therefore, we use the built-in URL implementation for NodeJS,
which implements the WHATWG standard that's used in the browser.
We also pull the base HREF from the DOM, falling back on the full
HREF as the browser would, to form the correct request URL.

Fixes #37314

PR Close #37341
2020-06-09 08:27:00 -07:00
08647267bb fix(common): prevent duplicate URL change notifications (#37459)
Prevent duplicate notifications from being emitted when multiple URL change listeners are registered using SpyLocation#onUrlChange.

Use `@internal` annotation for the `_urlChangeSubscription` properties instead of the `private` access modifier. Otherwise, we get in trouble because of  `SpyLocation implements Location`.

PR Close #37459
2020-06-09 08:26:34 -07:00
215d50d2f6 test(common): prefer TestBed.inject over inject (#37459)
Use the strongly typed TestBed.inject rather than the weakly typed inject test utility function. Reuse injected dependency variables between sibling test cases.

PR Close #37459
2020-06-09 08:26:34 -07:00
bf2cb6fa48 feat(language-service): TS references from template items (#37437)
Keen and I were talking about what it would take to support getting
references at a position in the current language service, since it's
unclear when more investment in the Ivy LS will be available. Getting TS
references from a template is trivial -- we simply need to get the
definition of a symbol, which is already handled by the language
service, and ask the TS language service to give us the references for
that definition.

This doesn't handle references in templates, but that could be done in a
subsequent pass.

Part of https://github.com/angular/vscode-ng-language-service/issues/29

PR Close #37437
2020-06-08 17:23:49 -07:00
e97a2d4123 fix(language-service): Improve signature selection by finding exact match (#37494)
The function signature selection algorithm is totally naive. It'd
unconditionally pick the first signature if there are multiple
overloads. This commit improves the algorithm by returning an exact
match if one exists.

PR Close #37494
2020-06-08 17:23:12 -07:00
585e3f6adc fix(router): Fix relative link generation from empty path components (#37446)
Partial resubmit of #26243
Fixes incorrect url tree generation for empty path components with children.
Adds a test to demonstrate the failure of createUrlTree for those routes.
Fixes #13011
Fixes #35687

PR Close #37446
2020-06-08 17:15:38 -07:00
7f77ce1a48 release: cut the v10.0.0-rc.3 release 2020-06-08 17:03:59 -07:00
a1616ce181 docs: add note on publishing libraries in ivy (#36556)
Libraries are still build using view engine even after Ivy being the default engine for building angular apps. Added note on why libraries are built using VE and how they will be automatically compiled in Ivy using ngcc making it compatible for both

Fixes #35625

PR Close #36556
2020-06-08 15:05:52 -07:00
1c22dff714 docs(docs-infra): fix small typo (#37258)
The style guide docs had a typo "Alerts and Calllouts". Callouts is
spelled with two l's, not three. This PR fixes the typo.

PR Close #37258
2020-06-08 14:42:50 -07:00
8d1d6e8f70 docs: place download section in toh to the top (#36567)
this is part of a larger effort to standardise download sections on angular.io

This commit partially addresses #35459

PR Close #36567
2020-06-08 11:41:52 -07:00
e7f4aba5a3 docs(service-worker): add staleWhileRevalidate strategy (#37301)
There is great workaround for implementing staleWhileRevalidate strategy in service-worker by setting strategy to freshness and timeout to 0u. Documented this in service worker config where all other strategies are documented

Fixes #20402

PR Close #37301
2020-06-08 11:41:20 -07:00
fdbe9f5d9f refactor(core): assert TNode is not a container when setting attribute on element (#37111)
This PR provides a more helpful error than the one currently present:
`el.setAttribute is not a function`. It is not valid to have directives with host bindings
on `ng-template` or `ng-container` nodes. VE would silently ignore this, while Ivy
attempts to set the attribute and throws an error because these are comment nodes
and do not have `setAttribute` functionality.

It is better to throw a helpful error than to silently ignore this because
putting a directive with host binding on an `ng-template` or `ng-container` is most often a mistake.
Developers should be made aware that the host binding will have no effect in these cases.

Note that an error is already thrown in Ivy, as mentioned above, so this
is not a breaking change and can be merged to both master and patch.

Resolves #35994

PR Close #37111
2020-06-08 11:21:05 -07:00
8bead6bfdd test(language-service): Remove all markers from test project (#37475)
This commit removes all markers from the inline template in
`AppComponent` and external template in `TemplateReference`.

Test scenarios should be colocated with the test cases themselves.
Besides, many existing cases are invalid. For example, if we want to
test autocomplete for HTML element, the existing test case is like:
```
<~{cursor} h1>
```
This doesn't make much sense, becasue the language service already sees
the `h1` tag in the template. The correct test case should be:
```
<~{cursor
```
IMO, this reflects the real-world use case better.

This commit also uncovers a bug in the way HTML entities autocompletion
is done. There's an off-by-one error in which a cursor that immediately
trails the ampersand character fails to trigger HTML entities
autocompletion.

PR Close #37475
2020-06-08 10:25:43 -07:00
52dda73dbb ci: remove IgorMinar from reviewers list for pullapprove fallback group (#36456)
Historically we have had a pullapprove group `fallback` which acted as
a catch all for files which did not match any other groups.  This
group assigned reviews to IgorMinar, however it was not apparent that
this group was assigned.  This change removes this assignment.  This
group as active should always coincide with failures of the pullapprove
verification script. We continue to have this group as a secondary test
ensuring all files in the repo are captured by the pullapprove config.

PR Close #36456
2020-06-08 10:07:45 -07:00
31b3888a2f style(ngcc): post-merge review tidy up (#37461)
This commit tidies up a few of the code comments from a recent commit to
help improve the clarity of the algorithm.

PR Close #37461
2020-06-08 09:32:11 -07:00
6f938470c2 fix(service-worker): Don't stay locked in EXISTING_CLIENTS_ONLY if corrupted data (#37453)
**Problem**

After #31109 and #31865, it's still possible to get locked in state
`EXISTING_CLIENTS_ONLY`, without any possibility to get out (even by
pushing new updates on the server).
More specifically, if control doc `/latest` of `ngsw:/:db:control` once
gets a bad value, then the service worker will fail early, and won't be
able to overwrite `/latest` with new, valid values (the ones from future
updates).

For example, once in this state, URL `/ngsw/state` will show:

    NGSW Debug Info:
    Driver state: EXISTING_CLIENTS_ONLY (Degraded due to failed initialization: Invariant violated (initialize): latest hash 8b75… has no known manifest
    Error: Invariant violated (initialize): latest hash 8b75… has no known manifest
        at Driver.<anonymous> (https://my.app/ngsw-worker.js:2302:27)
        at Generator.next (<anonymous>)
        at fulfilled (https://my.app/ngsw-worker.js:175:62))
    Latest manifest hash: 8b75…
    Last update check: 22s971u

... with hash `8b75…` corresponding to no installed version.

**Solution**

Currently, when such a case happens, the service worker [simply fails
with an assertion][1]. Because this failure happens early, and is not
handled, the service worker is not able to update `/latest` to new
installed app versions.

I propose to detect this corrupted case (a `latest` hash that doesn't
match any installed version) a few lines above, so that the service
worker can correctly call its [already existing cleaning code][2].

[1]: https://github.com/angular/angular/blob/3569fdf/packages/service-worker/worker/src/driver.ts#L559-L563
[2]: https://github.com/angular/angular/blob/3569fdf/packages/service-worker/worker/src/driver.ts#L505-L519

This change successfully fixes the problem described above.

Unit test written with the help of George Kalpakas. Thank you!

PR Close #37453
2020-06-08 09:31:35 -07:00
776c4afc03 fix(dev-infra): await setup in runBenchmark (#37428)
* Fix for issue #36986.
* Changes runBenchmark into an async function.
* Awaits config.setup in runBenchmark.

PR Close #37428
2020-06-08 09:17:35 -07:00
536dd647c6 build: update to latest stable Chromium 83.0.4103 in both rules_webtesting and puppeteer (#37427)
Also added in detailed instructions of the process to determine the URLs corresponding to Chromium version desired

PR Close #37427
2020-06-08 09:16:40 -07:00
51d581ab27 build: upgrade to bazel 3.2.0 and rules_nodejs 1.7.0 (#37358)
Upgrade to rely on bazel version 3.2.0 and rules_nodejs 1.7.0.  This
is part of a routine update as new versions become available.

PR Close #37358
2020-06-08 09:15:50 -07:00
75294e7dad ci: special case tooling-cli-shared-api review group (#37467)
The new tooling-cli-shared-api is used to guard changes to packages/compiler-cli/src/tooling.ts
which is a private API sharing channel between Angular FW and CLI.

Changes to this file should be rare and explicitly approved by at least two members
of the CLI team.

PR Close #37467
2020-06-05 19:23:53 -07:00
04bada7a9d ci: extend and update the reviewer groups (#37467)
Update the pullapprove config to require multiple reviews for sensitive groups in order
to force distribution of knowledge and improve the review quality.

PR Close #37467
2020-06-05 19:23:53 -07:00
2349143477 fix(dev-infra): properly determine oauth scopes for git client token (#37462)
Resubmit of b2bd38699b since
85b6c94cc6 accidentally reverted
the fix due to rebasing most likely.

PR Close #37462
2020-06-05 11:04:37 -07:00
e9bff5fe9f fix(elements): fire custom element output events during component initialization (#36161)
Previously, event listeners for component output events attached on an
Angular custom element before inserting it into the DOM (i.e. before
instantiating the underlying component) didn't fire for events emitted
during initialization lifecycle hooks, such as `ngAfterContentInit`,
`ngAfterViewInit`, `ngOnChanges` (initial call) and `ngOnInit`.
The reason was that that `NgElementImpl` [subscribed to events][1]
_after_ calling [ngElementStrategy#connect()][2], which is where the
[initial change detection][3] takes place (running the initialization
lifecycle hooks).

This commit fixes this by:
1. Ensuring `ComponentNgElementStrategy#events` is defined and available
   for subscribing to, even before instantiating the component.
2. Ensuring `NgElementImpl` subscribes to `NgElementStrategy#events`
   before calling `NgElementStrategy#connect()` (which initializes the
   component instance).

Jira issue: [FW-2010](https://angular-team.atlassian.net/browse/FW-2010)

[1]: c0143cb2ab/packages/elements/src/create-custom-element.ts (L167-L170)
[2]: c0143cb2ab/packages/elements/src/create-custom-element.ts (L164)
[3]: c0143cb2ab/packages/elements/src/component-factory-strategy.ts (L158)

Fixes #36141

PR Close #36161
2020-06-05 10:36:39 -07:00
411cb0cb92 refactor(elements): remove unnecessary non-null assertions and as any type-casts (#36161)
This commit removes some unnecessary non-null assertions (`!`) and
`as any` type-casts from the `elements` package.

PR Close #36161
2020-06-05 10:36:39 -07:00
53e1fb3554 refactor(dev-infra): move GitClient to common util (#37318)
Moves GitClient from merge script into common utils for unified
method of performing git actions throughout the ng-dev toolset.

PR Close #37318
2020-06-05 09:46:40 -07:00
2cb3b66640 fix(ngcc): find decorated constructor params on IIFE wrapped classes (#37436)
Now in TS 3.9, classes in ES2015 can be wrapped in an IIFE.
This commit ensures that we still find the static properties that contain
decorator information, even if they are attached to the adjacent node
of the class, rather than the implementation or declaration.

Fixes #37330

PR Close #37436
2020-06-05 09:22:04 -07:00
5af3144330 refactor(dev-infra): use the exec() helper from utils/shelljs whenever possible (#37444)
There is an `exec()` helper provided by `utils/shelljs.ts`, which is a
wrapper around ShellJS' `exec()` with some default options (currently
`silent: true`). The intention is to avoid having to pass these options
to every invocation of the `exec()` function.

This commit updates all code inside `dev-infra/` to use this helper
whenever possible).

NOTE: For simplicity, the `utils/shelljs` helper does not support some
      of the less common call signatures of the original `exec()`
      helper, so in some cases we still need to use the original.

PR Close #37444
2020-06-05 09:21:18 -07:00
e4043cbb3a docs: fix minor error in the "Structural directives" guide (#37452)
The sample code used in this guide uses [class.od]="odd".
But, in another portion of the guide, [ngClass]="odd" is mentioned instead.

PR Close #37452
2020-06-05 09:20:43 -07:00
fff424a35f fix(common): prevent duplicate URL change notifications (#37404)
Prevent duplicate notifications from being emitted when multiple URL change listeners are registered using Location#onUrlChange.

PR Close #37404
2020-06-04 16:45:06 -07:00
b5d1c8b05a docs: fix various typos (#37443)
This change just fixes various typos and misspellings across several docs.

I've included also a fix for an issue surfaced via #37423.

Closes #37423

PR Close #37443
2020-06-04 16:03:55 -07:00
d713e33cc4 style(dev-infra): correct tslint failures in dev-infra directory (#37233)
Fixes tslint failures in dev-infra directory as the directory is now
part of the tslint enforced files.

PR Close #37233
2020-06-04 12:44:46 -07:00
3d327d25f0 build: add dev-infra to tslint selected files (#37233)
Adds the dev-infra files to the scope of files on which tslint is
enforced.  This will allow for better code management/conformance.

PR Close #37233
2020-06-04 12:44:46 -07:00
077283bf0f fix(dev-infra): clean up usages within pullapprove tooling (#37338)
Clean up pullapprove tooling to use newly created common utils.
Additionally, use newly created logging levels rather than
verbose flagging.

PR Close #37338
2020-06-04 12:43:45 -07:00
9ec25ea036 refactor(dev-infra): change required base commit sha (#37424)
Update the commit sha to require that PRs have been rebased beyond the one which has new header requirements so we don't get failures after merging

PR Close #37424
2020-06-04 10:44:14 -07:00
878cfe669c fix(dev-infra): properly determine oauth scopes for git client token (#37439)
We recently added a better reporting mechanism for oauth tokens
in the dev-infra git util. Unfortunately the logic broke as part
of addressing PR review feedback. Right now, always the empty
promise from `oauthScopes` will be used as `getAuthScopes` considers
it as the already-requested API value. This is not the case as
the default promise is also truthy. We should just fix this by making
the property nullable.

PR Close #37439
2020-06-04 10:42:53 -07:00
5f0be3cb2e feat(dev-infra): Add oauth scope check to ensure necessary permissions for merge tooling (#37421)
Adds an assertion that the provided TOKEN has OAuth scope permissions for `repo`
as this is required for all merge attempts.

On failure, provides detailed error message with remediation steps for the user.

PR Close #37421
2020-06-04 09:35:59 -07:00
9e28e14c08 fix(dev-infra): ensure ts-node is registered with commonjs as module (#37422)
We recently added support for automatic registration of `ts-node`
when the dev-infra configuration is loaded.

In addition to registering ts-node, we should also ensure that the
`commonjs` module is set up. By default, `ts-node` would use ES module
imports that are not supported by default in NodeJS.

PR Close #37422
2020-06-04 09:34:33 -07:00
954d002884 feat(dev-infra): migrate release tool to use new logging system (#37422)
Migrate the release tool in ng-dev to use new logging system rather
than directly calling console.* to create a better experience
for users.

PR Close #37422
2020-06-04 09:34:32 -07:00
0a48591e53 feat(dev-infra): migrate ts-circular-dependencies tool to use new logging system (#37422)
Migrate the ts-circular-dependencies tool in ng-dev to use new logging system rather
than directly calling console.* to create a better experience
for users.

PR Close #37422
2020-06-04 09:34:32 -07:00
d37c723951 feat(dev-infra): migrate merge tool to use new logging system (#37422)
Migrate the merge tool in ng-dev to use new logging system rather
than directly calling console.* to create a better experience
for users.

PR Close #37422
2020-06-04 09:34:32 -07:00
9078ca557e feat(dev-infra): migrate ng-dev utils to use new logging system (#37422)
Migrate the ng-dev utils to use new logging system rather
than directly calling console.* to create a better experience
for users.

PR Close #37422
2020-06-04 09:34:32 -07:00
2be1ef6ba0 feat(dev-infra): migrate pullapprove tool to use new logging system (#37422)
Migrate the pullapprove tool in ng-dev to use new logging system rather
than directly calling console.* to create a better experience
for users.

PR Close #37422
2020-06-04 09:34:32 -07:00
47c02efccb feat(dev-infra): migrate rebase tool to use new logging system (#37422)
Migrate the rebase tool in ng-dev to use new logging system rather
than directly calling console.*  to create a better experience
for users.

PR Close #37422
2020-06-04 09:34:32 -07:00
d7ecfb432a feat(dev-infra): migrate discover-new-conflicts tool to use new logging system (#37422)
Migrate the discover-new-conflicts tool in ng-dev to use new logging system
rather than directly calling console.* to create a better experience
for users.

PR Close #37422
2020-06-04 09:34:32 -07:00
59abf4a33f feat(dev-infra): migrate commit-message tool to use new logging system (#37422)
Migrate the commit-message tool in ng-dev to use new logging system rather
than directly calling console.* to create a better experience
for users.

PR Close #37422
2020-06-04 09:34:32 -07:00
d6e715e726 feat(dev-infra): migrate format tool to use new logging system (#37422)
Migrate the formatting tool in ng-dev to use new logging system rather
than directly calling console.* to create a better experience
for users.

PR Close #37422
2020-06-04 09:34:32 -07:00
fcfcd1037c feat(dev-infra): add group functions to logging system and remove color param (#37422)
Adds .group and .groupEnd functions to each of the logging functions
to allow creating groups in the logged output.  Additionally removes
the color parameter from logging functions, in favor of the color
being applied to the string at the call site.

PR Close #37422
2020-06-04 09:34:31 -07:00
f3ccd29e7b feat(ngcc): implement a program-based entry-point finder (#37075)
This finder is designed to only process entry-points that are reachable
by the program defined by a tsconfig.json file.

It is triggered by calling `mainNgcc()` with the `findEntryPointsFromTsConfigProgram`
option set to true. It is ignored if a `targetEntryPointPath` has been
provided as well.

It is triggered from the command line by adding the `--use-program-dependencies`
option, which is also ignored if the `--target` option has been provided.

Using this option can speed up processing in cases where there is a large
number of dependencies installed but only a small proportion of the
entry-points are actually imported into the application.

PR Close #37075
2020-06-04 09:22:40 -07:00
5c0bdae809 fix(ngcc): capture dynamic import expressions as well as declarations (#37075)
Previously we only checked for static import declaration statements.
This commit also finds import paths from dynamic import expressions.

Also this commit should speed up processing: Previously we were parsing
the source code contents into a `ts.SourceFile` and then walking the parsed
AST to find import paths.
Generating an AST is unnecessary work and it is faster and creates less
memory pressure to just scan the source code contents with the TypeScript
scanner, identifying import paths from the tokens.

PR Close #37075
2020-06-04 09:22:40 -07:00
838902556b refactor(ngcc): move shared code into DependencyHostBase (#37075)
The various dependency hosts had a lot of duplicated code.
This commit refactors them to move this into the base class.

PR Close #37075
2020-06-04 09:22:40 -07:00
c6872c02d8 fix(ngcc): ensure that more dependencies are found by EsmDependencyHost (#37075)
Previously this host was skipping files if they had imports that spanned
multiple lines, or if the import was a dynamic import expression.

PR Close #37075
2020-06-04 09:22:40 -07:00
819982ea20 docs: add blank line before header (#37391)
Currently, `Formatting your source code` is not being formatted as a header because of a missing empty line.
PR Close #37391
2020-06-04 09:20:26 -07:00
f9daa136c3 perf(ngcc): cache parsed tsconfig between runs (#37417)
This commit will store a cached copy of the parsed tsconfig
that can be reused if the tsconfig path is the same.

This will improve the ngcc "noop" case, where there is no processing
to do, when the entry-points have already been processed.
Previously we were parsing this config every time we checked for
entry-points to process, which can take up to seconds in some
cases.

Resolves #36882

PR Close #37417
2020-06-04 09:19:38 -07:00
6a0d2ed6c8 ci(docs-infra): skip deploying RC version when lexicographically smaller than stable (#37426)
The angular.io production deployment script (`deploy-to-firebase.sh`)
compares the major version corresponding to the current branch (e.g.
`8` for branch `8.1.x`) against the major stable version (e.g. `9` if
the current stable version is `9.1.0`). It then uses the result of that
comparison to determine whether the current branch corresponds to a
newer version than stable (i.e. an RC version) and thus should not be
deployed or to an older version and thus may need to be deployed to an
archive vX.angular.io project.

Previously, the script was using string comparison (`<`) to compare the
two major versions. This could produce incorrect results for an RC major
version that is numerically greater than the stable but
lexicographically smaller. For example, 10 vs 9 (10 is numerically
greater but lexicographically smaller than 9).
Example of a CI job that incorrectly tried to deploy an RC branch to
production: https://circleci.com/gh/angular/angular/726414

This commit fixes it by switching to an integer comparison (i.e. using
the `-lt` operator).

PR Close #37426
2020-06-04 09:17:29 -07:00
2c1f35e794 fix(language-service): Recover from error in analyzing Ng Modules (#37108)
In place of failing to return analyzed Ng Modules when the analyzer
fails, return the previously-analyzed Ng Modules (which may be empty)
and log an error.

Closes https://github.com/angular/vscode-ng-language-service/issues/777

PR Close #37108
2020-06-03 15:56:19 -07:00
5345e8da45 docs: update the stackblitz in the GitHub Issue template (#37219)
This commit updates the bug report stackblitz template for opening a new
issue based on the current angular release.

Closes #37063

PR Close #37219
2020-06-03 15:55:44 -07:00
e35269dd87 docs: update file header to be correct (#37425)
The file header should be Google LLC rather than Google Inc. because it is now an LLC after Alphabet Holdings was formed.

PR Close #37425
2020-06-03 15:31:29 -07:00
60a03b7ef7 refactor(compiler-cli): extract NgCompilerAdapter interface (#37118)
`NgCompiler` is the heart of ngtsc and can be used to analyze and compile
Angular programs in a variety of environments. Most of these integrations
rely on `NgProgram` and the creation of an `NgCompilerHost` in order to
create a `ts.Program` with the right shape for `NgCompiler`.

However, certain environments (such as the Angular Language Service) have
their own mechanisms for creating `ts.Program`s that don't make use of a
`ts.CompilerHost`. In such environments, an `NgCompilerHost` does not make
sense.

This commit breaks the dependency of `NgCompiler` on `NgCompilerHost` and
extracts the specific interface of the host on which `NgCompiler` depends
into a new interface, `NgCompilerAdapter`. This interface includes methods
from `ts.CompilerHost`, the `ExtendedTsCompilerHost`, as well as APIs from
`NgCompilerHost`.

A consumer such as the language service can implement this API without
needing to jump through hoops to create an `NgCompilerHost` implementation
that somehow wraps its specific environment.

PR Close #37118
2020-06-03 13:29:45 -07:00
305b5a3887 fix(compiler-cli): use ModuleWithProviders type if static eval fails (#37126)
When the compiler encounters a function call within an NgModule imports
section, it attempts to resolve it to an NgModule-annotated class by
looking at the function body and evaluating the statements there. This
evaluation can only understand simple functions which have a single
return statement as their body. If the function the user writes is more
complex than that, the compiler won't be able to understand it and
previously the PartialEvaluator would return a "DynamicValue" for
that import.

With this change, in the event the function body resolution fails the
PartialEvaluator will now attempt to use its foreign function resolvers to
determine the correct result from the function's type signtaure instead. If
the function is annotated with a correct ModuleWithProviders type, the
compiler will be able to understand the import without static analysis of
the function body.

PR Close #37126
2020-06-03 13:23:16 -07:00
bc549361d3 fix(core): infinite loop if injectable using inheritance has a custom decorator (#37022)
If we detect that an injectable class is inheriting from another injectable, we generate code that looks something like this:

```
const baseFactory = ɵɵgetInheritedFactory(Child);

@Injectable()
class Parent {}

@Injectable()
class Child extends Parent {
  static ɵfac = (t) => baseFactory(t || Child)
}
```

This usually works fine, because the `ɵɵgetInheritedFactory` resolves to the factory of `Parent`, but the logic can break down if the `Child` class has a custom decorator. Custom decorators can return a new class that extends the original once, which means that the `ɵɵgetInheritedFactory` call will now resolve to the factory of the `Child`, causing an infinite loop.

These changes fix the issue by changing the inherited factory resolution logic so that it walks up the prototype chain class-by-class, while skipping classes that have the same factory as the class that was passed in.

Fixes #35733.

PR Close #37022
2020-06-03 13:16:26 -07:00
084b627f2e refactor(dev-infra): small changes and fixes (#36800)
Rename bazel workspace from npm_dev_infra to npm_angular_dev_infra_private to make it clear that this package is private to angular.
Change driver-utilities module_name to match the new bazel workspace name.
Correct a comment by rewording it from "deployed version" to "published version".
Fix merge conflicts in tmpl-package.json
Make "//packages/bazel/src:esm5.bzl" replacement more generalized so that importing from "//packages/bazel" works.
Deleted "dev_infra/*" path from modules/benchmarks tsconfig.
Moved //dev-infra/benchmark/browsers to //dev-infra/browsers.

PR Close #36800
2020-06-03 13:12:31 -07:00
6755d00601 revert: "revert: "build(core): use dev-infra's component_benchmark to show PoC (#36434)" (#36798)" (#36800)
This reverts commit 90a2796a7e.

PR Close #36800
2020-06-03 13:12:31 -07:00
cba1da3e44 revert: "revert: "build(dev-infra): update package.json and :npm_package (#36434)" (#36798)" (#36800)
This reverts commit f5ff2068a4.

PR Close #36800
2020-06-03 13:12:31 -07:00
7be8bb1489 revert: "revert: "feat(dev-infra): exposed new rule 'component_benchmark' via dev_infra (#36434)" (#36798)" (#36800)
This reverts commit ad8c4cdd75.

PR Close #36800
2020-06-03 13:12:31 -07:00
c7c0c1f626 refactor(forms): use a type guard to get rid of casts (#32541)
Use an explicit type guard when checking if a given object is of type AbstractControlOptions,
instead of a simple function returning a boolean value. This allows us to remove manual type
casting when using this function, relying instead on TypeScript to infer correct types.

PR Close #32541
2020-06-03 12:29:26 -07:00
3aa4629f92 docs: refactor template-driven forms doc as a tutorial (#36732)
rework content to meet current documentation standards and conventions, structure as tutorial document type

PR Close #36732
2020-06-03 12:27:28 -07:00
2d86dbb090 docs: update aio in support for #BlackLivesMatter (#37409)
Update angular.io in support for #BlackLivesMatter. The PR updates the
styles of the landing page and changes the current survey notification.

PR Close #37409
2020-06-03 11:20:57 -07:00
91767ff0f9 ci: temporarily disable Android 10 browser unit tests on Saucelabs (#37399)
Disabling Android 10 browser unit tests on Saucelabs due to errors.

After remediation from Saucelabs to correct the discovered failures, this change can be reverted to renable the tests on Android 10.

Example of failures seen:

```
02 06 2020 14:03:05.048:INFO [SaucelabsLauncher]: Chrome 10.0 (Android) session at https://saucelabs.com/tests/54f5fb181db644a3b4779187c2309000

02 06 2020 14:03:06.869:INFO [Chrome Mobile 74.0.3729 (Android 0.0.0)]: Disconnected browser returned on socket E-bi0p0NKtghk-HcAAAO with id 85563367.

Chrome Mobile 74.0.3729 (Android 0.0.0) ERROR: Error: XHR error loading http://angular-ci.local:9876/base/node_modules/rxjs/internal/operators/zip.js

	Error loading http://angular-ci.local:9876/base/node_modules/rxjs/internal/operators/zip.js as "../internal/operators/zip" from http://angular-ci.local:9876/base/node_modules/rxjs/operators/index.js

Error: XHR error loading http://angular-ci.local:9876/base/node_modules/rxjs/internal/operators/zip.js

    at error (http://angular-ci.local:9876/base/node_modules/systemjs/dist/system.src.js?1c6a6c12fec50a8db7aeebe8e06e2b70135c0615:1028:16)

    at XMLHttpRequest.xhr.onreadystatechange [as __zone_symbol__ON_PROPERTYreadystatechange] (http://angular-ci.local:9876/base/node_modules/systemjs/dist/system.src.js?1c6a6c12fec50a8db7aeebe8e06e2b70135c0615:1036:13)

    at XMLHttpRequest.wrapFn (http://angular-ci.local:9876/base/dist/bin/packages/zone.js/npm_package/dist/zone.js?942d01da94828e1c75e8527fa8d06f363d6379ce:809:43)

    at ZoneDelegate.invokeTask (http://angular-ci.local:9876/base/dist/bin/packages/zone.js/npm_package/dist/zone.js?942d01da94828e1c75e8527fa8d06f363d6379ce:432:35)

    at Zone.runTask (http://angular-ci.local:9876/base/dist/bin/packages/zone.js/npm_package/dist/zone.js?942d01da94828e1c75e8527fa8d06f363d6379ce:201:55)

    at ZoneTask.invokeTask [as invoke] (http://angular-ci.local:9876/base/dist/bin/packages/zone.js/npm_package/dist/zone.js?942d01da94828e1c75e8527fa8d06f363d6379ce:514:38)

    at invokeTask (http://angular-ci.local:9876/base/dist/bin/packages/zone.js/npm_package/dist/zone.js?942d01da94828e1c75e8527fa8d06f363d6379ce:1722:18)

    at XMLHttpRequest.globalZoneAwareCallback (http://angular-ci.local:9876/base/dist/bin/packages/zone.js/npm_package/dist/zone.js?942d01da94828e1c75e8527fa8d06f363d6379ce:1748:21)
```

PR Close #37399
2020-06-02 17:32:34 -04:00
078b004ecc docs(core): remove v10 mention from @Injectable warning (#37383)
In v9, we started showing a console warning when
instantiating a token that inherited its @Injectable
decorator rather than providing its own. This warning
said that the pattern would become an error in v10.

However, we have decided to wait until at least v11
to throw in this case, so this commit updates the
warning to be less prescriptive about the exact
version when the pattern will no longer be supported.

PR Close #37383
2020-06-02 17:30:58 -04:00
930d204d83 perf(ngcc): allow immediately reporting a stale lock file (#37250)
Currently, if an ngcc process is killed in a manner that it doesn't clean
up its lock file (or is killed too quickly) the compiler reports that it
is waiting on the PID of a process that doesn't exist, and that it will
wait up to a maximum of N seconds. This PR updates the locking code to
additionally check if the process exists, and if it does not it will
immediately bail out, and print the location of the lock file so a user
may clean it up.

PR Close #37250
2020-06-02 17:30:03 -04:00
8d82cdfc77 docs: refactor forms overview (#36919)
Reorganize and edit content of existing form overview to conform to current doc standards and styles

PR Close #36919
2020-06-02 17:29:15 -04:00
cb6996b5c3 build: fix integration payload sizes 2020-06-02 12:06:52 -07:00
a4f7740332 docs(router): fix a typo in example code (#37309)
The code in the example docs used TestBed.configureTestModule instead of TestBed.configureTestingModule.

PR Close #37309
2020-06-01 17:19:46 -04:00
ba0faa2f77 refactor(core): remove looseIdentical in favor of built-in Object.is (#37191)
Remove `looseIdentical` implementation and instead use the ES2015 `Object.is` in its place.
They behave exactly the same way except for `+0`/`-0`.
`looseIdentical(+0, -0)` => `true`
`Object.is(+0, -0)` => `false`

Other than the difference noted above, this is not be a breaking change because:
1. `looseIdentical` is a private API
2. ES2015 is listed as a mandatory polyfill in the [browser support
guide](https://angular.io/guide/browser-support#mandatory-polyfills)
3. Also note that `Ivy` already uses `Object.is` in `bindingUpdated`.

PR Close #37191
2020-06-01 17:19:17 -04:00
3e68029522 test(language-service): disable ivy ls tests on CI (#37348)
This commit disables the tests for Ivy version of language service on CI
because the compiler APIs are not yet stable, so language service should
not assert against its behavipr.

PR Close #37348
2020-06-01 17:18:51 -04:00
b4e26b5828 fix(ngcc): do not inline source-maps for non-inline typings source-maps (#37363)
Inline source-maps in typings files can impact IDE performance
so ngcc should only add such maps if the original typings file
contains inline source-maps.

Fixes #37324

PR Close #37363
2020-06-01 17:18:31 -04:00
15cf7fcac2 docs(core): fix typo in decorators.ts relating to the use of Object.defineProperty. (#37369)
Previously there was a typo in a comment within the PropDecorator function relating to and justifying the use of Object.defineProperty. This PR clears up the wording that comment

PR Close #37369
2020-06-01 17:18:08 -04:00
24ff0eb13b docs: fix typo in deprecations (#37379)
This PR fixes a typo in the deprecations guide, changing 'dropped support for of Windows 10...' to 'dropped support for Windows 10...'

PR Close #37379
2020-06-01 17:17:44 -04:00
cf86f72eb7 release: cut the v10.0.0-rc.2 release 2020-06-01 10:51:58 -07:00
61486f14f1 build: remove wombot proxy registry from package.jsons for release (#37378)
Due to an outage with the proxy we rely on for publishing, we need
to temporarily directly publish to NPM using our own angular
credentials again.

PR Close #37378
2020-06-01 12:41:19 -04:00
d16a7f3ecc fix(core): reenable decorator downleveling for Angular npm packages (#37317)
In #37221 we disabled tsickle passes from transforming the tsc output that is used to publish all
Angular framework and components packages (@angular/*).

This change however revealed a bug in the ngc that caused __decorate and __metadata calls to still
be emitted in the JS code even though we don't depend on them.

Additionally it was these calls that caused code in @angular/material packages to fail at runtime
due to circular dependency in the emitted decorator code documeted as
https://github.com/microsoft/TypeScript/issues/27519.

This change partially rolls back #37221 by reenabling the decorator to static fields (static
properties) downleveling.

This is just a temporary workaround while we are also fixing root cause in `ngc` - tracked as
FW-2199.

Resolves FW-2198.
Related to FW-2196

PR Close #37317
2020-05-29 18:52:01 -04:00
82761ec50e docs: Mention Bazel builder and schematics in Deprecations section (#37190)
This commit adds Bazel builder and schematics to the global list of
deprecations in Angular. A link to the migration doc is added.

PR Close #37190
2020-05-28 21:35:41 -04:00
235bfa77a9 docs(bazel): Mention Architect prototype and Slack Channel (#37190)
This commit adds a link to the Bazel prototype for orchestrating
multiple CLI architects and also adds a link to the #angular channel in
the Bazel Slack workspace.

PR Close #37190
2020-05-28 21:35:41 -04:00
299ae1bb1c docs: Cleanup Bazel schematics deprecation doc (#37190)
This commit improves some wording in the deprecation doc for Bazel
builder and schematics in `@angular/bazel` and fixes the formatting.

PR Close #37190
2020-05-28 21:35:41 -04:00
80f7522dab refactor(bazel): Remove schematics and builder from package.json (#37190)
This commit removes the fields for ng-add, schematics and builder from
package.json of `@angular/bazel`.

PR Close #37190
2020-05-28 21:35:41 -04:00
028921e369 docs: Add guide/bazel to Service Worker navigationUrls (#37190)
This commit adds an exception for "guide/bazel" to the navigationUrls in
the Service Worker config. This is needed for redirection to work.

PR Close #37190
2020-05-28 21:35:41 -04:00
a4e11bb524 docs: Redirect /guide/bazel to deprecation doc in Angular repo (#37190)
This commit adds a 301 redirect for /guide/bazel on angular.io to the
deprecation doc for Angular Bazel schematics in Angular repo.

PR Close #37190
2020-05-28 21:35:41 -04:00
a4131752d2 test: remove Bazel schematics integration test (#37190)
This commit removes the integration test for schematics in
`@angular/bazel` that is used to generate a Bazel builder. The Bazel
builder has been deprecated.

PR Close #37190
2020-05-28 21:35:40 -04:00
060dcfbba1 ci: Remove aio/content/guide/bazel.md from pullapprove (#37190)
This commit removes aio/content/guide/bazel.md from the Bazel list in
pullapprove since Bazel builder has been deprecated and the doc has been
deleted.

PR Close #37190
2020-05-28 21:35:40 -04:00
4be7008f80 docs: Remove 'Building with Bazel' section (#37190)
This commit removes "Building with Bazel" section from angular.io
navigation list and Angular CLI landing page.

PR Close #37190
2020-05-28 21:35:40 -04:00
4a0d05515e refactor(bazel): Remove Schematics for Bazel Builder (#37190)
This commit removes `ng-add` and `ng-new` schematics for the Bazel
Builder, and update the corresponding BUILD files.

PR Close #37190
2020-05-28 21:35:40 -04:00
83ab99c746 docs: Remove Bazel builder from @angular/bazel (#37190)
This commit adds a deprecation doc for Bazel builder in
`@angular/bazel` and removes the corresponding guide in angular.io.

PR Close #37190
2020-05-28 21:35:40 -04:00
270da1f69f build(docs-infra): upgrade cli command docs sources to 14af4e07c (#37310)
Updating [angular#10.0.x](https://github.com/angular/angular/tree/10.0.x) from [cli-builds#10.0.x](https://github.com/angular/cli-builds/tree/10.0.x).

##
Relevant changes in [commit range](200a21f8a...14af4e07c):

**Modified**
- help/generate.json

PR Close #37310
2020-05-28 18:43:44 -04:00
6b0e46e36c docs: fix typo in committer.md (#37171)
Fix a type of COMMITTER.md, the url of the pullapprove service should be https://docs.pullapprove.com/,
now the document has an additional `https` prefix.

PR Close #37171
2020-05-28 18:43:05 -04:00
3642707145 build: use static patch value for targetting branches in merge config (#37299)
Due to the desired patch branch (10.0.x) being on a semver version
that is unreleased as stable (there is no 10.0.0 on latest, it is on
next) our logic for determining target patch branches does not work.

This change is a workaround to unblock merging in the repo while a
longer term answer is discovered.

PR Close #37299
2020-05-28 15:18:20 -07:00
0ea76edfd8 build: migrate ng-dev config to .ng-dev directory (#37299)
Migrate to using .ng-dev directory for ng-dev configuration to allow
better management of the configuration using multiple files.  The
intention is to prevent the config file from becoming unruly.

PR Close #37299
2020-05-28 15:18:20 -07:00
d493a83b2b docs(platform-server): fix renderModule usage guidance with Ivy (#37296)
Before the introduction of the Ivy renderer, users would compile
their applications and use the resulting factories for SSR, since
these post-compilation artifacts ensured faster delivery. Thus,
using the original module as the rendering entrypoint was
considered suboptimal and was discouraged.

However, with the introduction of Ivy, this guidance is no longer
applicable since these factories are no longer generated.
Comparable speed is achieved using the factory-less module
renderer, and so we update the guiance in the docs for the method.

PR Close #37296
2020-05-28 16:07:32 -04:00
f1721d5cef build: update requiredBaseCommit for patch branch merges (#37316)
Updates the requiredBaseCommit for merging to patch branch to the
latest commit message validation fix found in the 10.0.x branch.

Previously, the patch branch commit used was for the 9.1.x branch.

PR Close #37316
2020-05-28 16:06:08 -04:00
5b3fd6aa82 docs: add IE mobile to deprecated browsers (#37313)
Mobile versions of IE should also be deprecated, as the same reasons for deprecating IE 9 and 10 apply.

PR Close #37313
2020-05-27 17:23:18 -04:00
6f829180f7 build: update license headers to reference Google LLC (#37205)
Update the license headers throughout the repository to reference Google LLC
rather than Google Inc, for the required license headers.

PR Close #37205
2020-05-26 14:27:01 -04:00
27b95ba64a build: Update file-header lint rule to Google LLC (#37205)
Update the file-header lint rule to properly reference Google LLC
rather than Google Inc, for the required headers.

PR Close #37205
2020-05-26 14:27:01 -04:00
ef405b1e90 build: deprecate old merge script (#37247)
Deprecate the old merge script as it no longer correctly chooses
the patch branch due to relying on numerical sorting order from
git.  Git actually provides a lexicographical sorting order.  This
that 9.0.x will be chosen rather than 10.0.x as it is sorted based
the 9 vs 1, rather than 9 vs 10.

PR Close #37247
2020-05-26 14:25:44 -04:00
441073bad5 feat(dev-infra): expose script for determining merge branches (#37217)
The components repo and framework repository follow the same patch
branch concept. We should be able to share a script for determining
these merge branches.

Additonally the logic has been improved compared to the old merge script because
we no longer consult `git ls-remote` unless really needed. Currently,
`git ls-remote` is always consulted, even though not necessarily needed.

This can slow down the merge script and the caretaker process when a
couple of PRs are merged (personally saw around ~4 seconds per merge).

Additionally, the new logic is more strict and will ensure (in most
cases) that no wrong patch/minor branch is determined. Previously,
the script just used the lexicographically greatest patch branch.
This _could_ be wrong when a new patch branch has been created too
early, or by accident.

PR Close #37217
2020-05-21 10:38:19 -07:00
3531 changed files with 94911 additions and 144980 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/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
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
################################
# Temporary Settings for Ivy #
@ -136,6 +136,15 @@ build:remote --remote_executor=remotebuildexecution.googleapis.com
# retry mechanism and we do not want to retry unnecessarily if Karma already tried multiple times.
test:saucelabs --flaky_test_attempts=1
###############################
# NodeJS rules settings
# These settings are required for rules_nodejs
###############################
# Turn on managed directories feature in Bazel
# This allows us to avoid installing a second copy of node_modules
common --experimental_allow_incremental_repository_updates
####################################################
# User bazel configuration
# NOTE: This needs to be the *last* entry in the config.

View File

@ -1,3 +1,3 @@
3.5.1
3.2.0
# [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,17 +14,9 @@ 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=20
build --local_ram_resources=32768
build --local_cpu_resources=8
build --local_ram_resources=14336
# All build executed remotely should be done using our RBE configuration.
build:remote --google_default_credentials
# Upload to GCP's Build Status viewer to allow for us to have better viewing of execution/build
# logs. This is only done on CI as the BES (GCP's Build Status viewer) API requires credentials
# from service accounts, rather than end user accounts.
build:remote --bes_backend=buildeventservice.googleapis.com
build:remote --bes_timeout=30s
build:remote --bes_results_url="https://source.cloud.google.com/results/invocations/"
build --config=remote

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=120000
build --local_cpu_resources=32
build --local_ram_resources=13500
build --local_cpu_resources=4
# All windows jobs run on master and should use http caching
build --remote_http_cache=https://storage.googleapis.com/angular-team-cache

View File

@ -27,11 +27,13 @@ var_3: &cache_key v7-angular-node-12-{{ checksum ".bazelversion" }}-{{ checksum
# folder will contain all previously used versions and ultimately cause the cache restoring to
# be slower due to its growing size.
var_4: &cache_key_fallback v7-angular-node-12-{{ checksum ".bazelversion" }}
var_3_win: &cache_key_win v7-angular-win-node-12-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }}
var_4_win: &cache_key_win_fallback v7-angular-win-node-12-{{ checksum ".bazelversion" }}
# Cache key for the `components-repo-unit-tests` job. **Note** when updating the SHA in the
# cache keys also update the SHA for the "COMPONENTS_REPO_COMMIT" environment variable.
var_5: &components_repo_unit_tests_cache_key v9-angular-components-09e68db8ed5b1253f2fe38ff954ef0df019fc25a
var_6: &components_repo_unit_tests_cache_key_fallback v9-angular-components-
var_5: &components_repo_unit_tests_cache_key v7-angular-components-189d98e8b01b33974328255f085de04251d61567
var_6: &components_repo_unit_tests_cache_key_fallback v7-angular-components-
# Workspace initially persisted by the `setup` job, and then enhanced by `build-npm-packages` and
# `build-ivy-npm-packages`.
@ -78,7 +80,7 @@ executors:
windows-executor:
working_directory: ~/ng
resource_class: windows.2xlarge
resource_class: windows.medium
# 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
@ -181,12 +183,23 @@ commands:
setup_win:
description: Setup windows node environment
steps:
- checkout
# Use the Linux workspace directly, as it already has checkout, rebased and node modules.
- custom_attach_workspace
# Install Bazel pre-requisites that aren't in the preconfigured CircleCI Windows VM.
- run: ./.circleci/windows-env.ps1
- run: node --version
- run: yarn --version
- restore_cache:
keys:
- *cache_key_win
- *cache_key_win_fallback
# Reinstall to get windows binaries.
- run: yarn install --frozen-lockfile --non-interactive
# Install @bazel/bazelisk globally and use that for the first run.
# Workaround for https://github.com/bazelbuild/rules_nodejs/issues/894
# NB: the issue was for @bazel/bazel but the same problem applies to @bazel/bazelisk
- run: yarn global add @bazel/bazelisk@$env:BAZELISK_VERSION
- run: bazelisk info
notify_webhook_on_fail:
description: Notify a webhook about failure
@ -260,7 +273,6 @@ 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:
@ -641,23 +653,9 @@ jobs:
name: Starting Saucelabs tunnel service
command: ./tools/saucelabs/sauce-service.sh run
background: true
# add module umd tsc compile option so the test can work
# properly in the legacy browsers
- run: yarn tsc -p packages --module UMD
- run: yarn tsc -p modules --module UMD
- run: yarn tsc -p packages
- run: yarn tsc -p modules
- run: yarn bazel build //packages/zone.js:npm_package
# Build test fixtures for a test that rely on Bazel-generated fixtures. Note that disabling
# specific tests which are reliant on such generated fixtures is not an option as SystemJS
# in the Saucelabs legacy job always fetches referenced files, even if the imports would be
# guarded by an check to skip in the Saucelabs legacy job. We should be good running such
# test in all supported browsers on Saucelabs anyway until this job can be removed.
- run:
name: Preparing Bazel-generated fixtures required in legacy tests
command: |
yarn bazel build //packages/core/test:downleveled_es5_fixture
# Needed for the ES5 downlevel reflector test in `packages/core/test/reflection`.
cp dist/bin/packages/core/test/reflection/es5_downleveled_inheritance_fixture.js \
dist/all/@angular/core/test/reflection/es5_downleveled_inheritance_fixture.js
- run:
# Waiting on ready ensures that we don't run tests too early without Saucelabs not being ready.
name: Waiting for Saucelabs tunnel to connect
@ -733,13 +731,10 @@ jobs:
- run: yarn --cwd packages/zone.js promisetest
- run: yarn --cwd packages/zone.js promisefinallytest
- run: yarn bazel build //packages/zone.js:npm_package &&
cp dist/bin/packages/zone.js/npm_package/bundles/zone-mix.umd.js ./packages/zone.js/test/extra/ &&
cp dist/bin/packages/zone.js/npm_package/bundles/zone-patch-electron.umd.js ./packages/zone.js/test/extra/ &&
cp dist/bin/packages/zone.js/npm_package/dist/zone-mix.js ./packages/zone.js/test/extra/ &&
cp dist/bin/packages/zone.js/npm_package/dist/zone-patch-electron.js ./packages/zone.js/test/extra/ &&
yarn --cwd packages/zone.js electrontest
- run: yarn --cwd packages/zone.js jest:test
- run: yarn --cwd packages/zone.js jest:nodetest
- run: yarn --cwd packages/zone.js/test/typings install --frozen-lockfile --non-interactive
- run: yarn --cwd packages/zone.js/test/typings test
- run: yarn --cwd packages/zone.js jesttest
# Windows jobs
# Docs: https://circleci.com/docs/2.0/hello-world-windows/
@ -753,6 +748,12 @@ jobs:
# Probably a powershell command parsing thing. There's no problem using a yarn script though.
command: yarn circleci-win-ve
no_output_timeout: 45m
# Save bazel repository cache to use on subsequent runs.
# We don't save node_modules because it's faster to use the linux workspace and reinstall.
- save_cache:
key: *cache_key_win
paths:
- "C:/Users/circleci/bazel_repository_cache"
test_ivy_aot_win:
executor: windows-executor
@ -844,25 +845,26 @@ workflows:
- build-npm-packages
- build-ivy-npm-packages
- legacy-unit-tests-saucelabs
# 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
- components-repo-unit-tests:
requires:
- build-npm-packages
- test_zonejs:
requires:
- setup
# Windows Jobs
# These are very slow so we run them on non-PRs only for now.
# TODO: remove the filter when CircleCI makes Windows FS faster.
# The Windows jobs are only run after their non-windows counterparts finish successfully.
# This isn't strictly necessary as there is no artifact dependency, but helps economize
# CI resources by not attempting to build when we know should fail.
- test_win:
<<: *skip_on_pull_requests
requires:
- setup
- test
- test_ivy_aot_win:
<<: *skip_on_pull_requests
requires:
- setup
- test_ivy_aot
monitoring:
jobs:

View File

@ -74,7 +74,7 @@ setPublicVar COMPONENTS_REPO_TMP_DIR "/tmp/angular-components-repo"
setPublicVar COMPONENTS_REPO_URL "https://github.com/angular/components.git"
setPublicVar COMPONENTS_REPO_BRANCH "master"
# **NOTE**: When updating the commit SHA, also update the cache key in the CircleCI `config.yml`.
setPublicVar COMPONENTS_REPO_COMMIT "09e68db8ed5b1253f2fe38ff954ef0df019fc25a"
setPublicVar COMPONENTS_REPO_COMMIT "189d98e8b01b33974328255f085de04251d61567"
####################################################################################################

View File

@ -60,15 +60,14 @@ if (require.resolve === module) {
// Helpers
function _main(args) {
triggerWebhook(...args)
.then(
({statusCode, responseText}) => (200 <= statusCode && statusCode < 400) ?
console.log(`Status: ${statusCode}\n${responseText}`) :
Promise.reject(new Error(`Request failed (status: ${statusCode}): ${responseText}`)))
.catch(err => {
console.error(err);
process.exit(1);
});
triggerWebhook(...args).
then(({statusCode, responseText}) => (200 <= statusCode && statusCode < 400) ?
console.log(`Status: ${statusCode}\n${responseText}`) :
Promise.reject(new Error(`Request failed (status: ${statusCode}): ${responseText}`))).
catch(err => {
console.error(err);
process.exit(1);
});
}
function postJson(url, data) {
@ -78,12 +77,15 @@ function postJson(url, data) {
const statusCode = res.statusCode || -1;
let responseText = '';
res.on('error', reject)
.on('data', d => responseText += d)
.on('end', () => resolve({statusCode, responseText}));
res.
on('error', reject).
on('data', d => responseText += d).
on('end', () => resolve({statusCode, responseText}));
};
request(url, opts, onResponse).on('error', reject).end(JSON.stringify(data));
request(url, opts, onResponse).
on('error', reject).
end(JSON.stringify(data));
});
}

View File

@ -2,8 +2,8 @@
# https://docs.bazel.build/versions/master/install-windows.html
# https://docs.bazel.build/versions/master/windows.html
# Install MSYS2 and packages
choco install msys2 --version 20200903.0.0 --no-progress --package-parameters "/NoUpdate"
C:\tools\msys64\usr\bin\bash.exe -l -c "pacman --needed --noconfirm -S zip unzip patch diffutils"
choco install msys2 --version 20180531.0.0 --no-progress --package-parameters "/NoUpdate"
C:\tools\msys64\usr\bin\bash.exe -l -c "pacman --needed --noconfirm -S zip unzip patch diffutils git"
# Add PATH modifications to the Powershell profile. This is the win equivalent of .bash_profile.
# https://docs.microsoft.com/en-us/previous-versions//bb613488(v=vs.85)
@ -41,8 +41,7 @@ copy .circleci\bazel.windows.rc ${Env:USERPROFILE}\.bazelrc
####################################################################################################
# Install specific version of node.
####################################################################################################
nvm install 12.14.1
nvm use 12.14.1
choco install nodejs --version 12.14.1 --no-progress
# These Bazel prereqs aren't needed because the CircleCI image already includes them.
# choco install yarn --version 1.16.0 --no-progress

View File

@ -1,5 +1,5 @@
---
name: "\U0001F41E Bug report"
name: "\U0001F41EBug report"
about: Report a bug in the Angular Framework
---
<!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅

View File

@ -1,5 +1,5 @@
---
name: "\U0001F680 Feature request"
name: "\U0001F680Feature request"
about: Suggest a feature for Angular Framework
---

View File

@ -1,5 +1,5 @@
---
name: "❓ Support request"
name: "❓Support request"
about: Questions and requests for support
---

View File

@ -1,5 +1,5 @@
---
name: "\U0001F6E0 Angular CLI"
name: "\U0001F6E0Angular CLI"
about: Issues and feature requests for Angular CLI
---

View File

@ -1,5 +1,5 @@
---
name: "\U0001F48E Angular Components"
name: "\U0001F48EAngular Components"
about: Issues and feature requests for Angular Components
---

View File

@ -38,7 +38,6 @@ 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/*"
@ -48,10 +47,7 @@ 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/docs/**"
- "packages/elements/schematics/**"
- "packages/examples/**"
@ -59,8 +55,6 @@ merge:
- "packages/localize/**"
- "packages/private/**"
- "packages/service-worker/**"
- "packages/common/locales/**"
- "packages/http/**"
- "**/.gitignore"
- "**/.gitkeep"
- "**/yarn.lock"
@ -74,20 +68,20 @@ merge:
- "packages/**/integrationtest/**"
- "packages/**/test/**"
- "packages/zone.js/*"
- "packages/zone.js/dist/**"
- "packages/zone.js/doc/**"
- "packages/zone.js/example/**"
- "packages/zone.js/scripts/**"
# comment that will be added to a PR when there is a conflict, leave empty or set to false to disable
mergeConflictComment: "Hi @{{PRAuthor}}! This PR has merge conflicts due to recent upstream merges.\nPlease help to unblock it by resolving these conflicts. Thanks!"
mergeConflictComment: "Hi @{{PRAuthor}}! This PR has merge conflicts due to recent upstream merges.
\nPlease help to unblock it by resolving these conflicts. Thanks!"
# label to monitor
mergeLabel: "action: merge"
mergeLabel: "PR action: merge"
# adding any of these labels will also add the merge label
mergeLinkedLabels:
- "action: merge-assistance"
- "PR action: merge-assistance"
# list of checks that will determine if the merge label can be added
checks:
@ -100,17 +94,17 @@ merge:
# whether the PR shouldn't have a conflict with the base branch
noConflict: true
# list of labels that a PR needs to have, checked with a regexp (e.g. "target:" will work for the label "target: master")
# list of labels that a PR needs to have, checked with a regexp (e.g. "PR target:" will work for the label "PR target: master")
requiredLabels:
- "target: *"
- "PR target: *"
- "cla: yes"
# list of labels that a PR shouldn't have, checked after the required labels with a regexp
forbiddenLabels:
- "target: TBD"
- "action: cleanup"
- "action: review"
- "state: blocked"
- "PR target: TBD"
- "PR action: cleanup"
- "PR action: review"
- "PR state: blocked"
- "cla: no"
# list of PR statuses that need to be successful
@ -127,7 +121,12 @@ merge:
# the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable
# {{MERGE_LABEL}} will be replaced by the value of the mergeLabel option
# {{PLACEHOLDER}} will be replaced by the list of failing checks
mergeRemovedComment: "I see that you just added the `{{MERGE_LABEL}}` label, but the following checks are still failing:\n{{PLACEHOLDER}}\n\n**If you want your PR to be merged, it has to pass all the CI checks.**\n\nIf you can't get the PR to a green state due to flakes or broken master, please try rebasing to master and/or restarting the CI job. If that fails and you believe that the issue is not due to your change, please contact the caretaker and ask for help."
mergeRemovedComment: "I see that you just added the `{{MERGE_LABEL}}` label, but the following checks are still failing:
\n{{PLACEHOLDER}}
\n
\n**If you want your PR to be merged, it has to pass all the CI checks.**
\n
\nIf you can't get the PR to a green state due to flakes or broken master, please try rebasing to master and/or restarting the CI job. If that fails and you believe that the issue is not due to your change, please contact the caretaker and ask for help."
# options for the triage plugin
triage:
@ -142,28 +141,18 @@ triage:
# arrays of labels that determine if an issue has been fully triaged
l2TriageLabels:
-
- "P0"
- "type: bug/fix"
- "severity*"
- "freq*"
- "comp: *"
-
- "P1"
- "type: feature"
- "comp: *"
-
- "P2"
- "type: refactor"
- "comp: *"
-
- "P3"
- "comp: *"
-
- "P4"
- "comp: *"
-
- "P5"
- "comp: *"
-
- "feature"
- "comp: *"
-
- "discussion"
- "type: RFC / Discussion / question"
- "comp: *"
# options for the triage PR plugin
@ -191,4 +180,4 @@ rerunCircleCI:
# set to true to disable
disabled: false
# the label which when added triggers a rerun of the default CircleCI workflow
triggerRerunLabel: "action: rerun CI at HEAD"
triggerRerunLabel: "PR action: rerun CI at HEAD"

View File

@ -10,6 +10,6 @@ jobs:
if: github.repository == 'angular/angular'
runs-on: ubuntu-latest
steps:
- uses: angular/dev-infra/github-actions/lock-closed@414834b2b24dd2df37c6ed00808387ee6fd91b66
- uses: angular/dev-infra/github-actions/lock-closed@66462f6
with:
lock-bot-key: ${{ secrets.LOCK_BOT_PRIVATE_KEY }}

6
.gitignore vendored
View File

@ -40,11 +40,5 @@ yarn-error.log
# User specific bazel settings
.bazelrc.user
# User specific ng-dev settings
.ng-dev.user*
.notes.md
baseline.json
# Ignore .history for the xyz.local-history VSCode extension
.history

View File

@ -1,145 +0,0 @@
<type>(<scope>): <summary>
<Describe the motivation behind this change - explain WHY you are making this change. Wrap all lines
at 100 characters.>
Fixes #<issue number>
# ────────────────────────────────────────── 100 chars ────────────────────────────────────────────┤
# Example Commit Messages
# =======================
# ─── Example: Simple refactor ────────────────────────────────────────────────────────────────────┤
# refactor(core): rename refreshDynamicEmbeddedViews to refreshEmbeddedViews
#
# Improve code readability. The original name no longer matches how the function is used.
# ─────────────────────────────────────────────────────────────────────────────────────────────────┤
# ─── Example: Simple docs change ─────────────────────────────────────────────────────────────────┤
# docs: clarify the service limitation in providers.md guide
#
# Fixes #36332
# ─────────────────────────────────────────────────────────────────────────────────────────────────┤
# ─── Example: A bug fix ──────────────────────────────────────────────────────────────────────────┤
# fix(ngcc): ensure lockfile is removed when `analyzeFn` fails
#
# Previously an error thrown in the `analyzeFn` would cause the ngcc process to exit immediately
# without removing the lockfile, and potentially before the unlocker process had been successfully
# spawned resulting in the lockfile being orphaned and left behind.
#
# Now we catch these errors and remove the lockfile as needed.
# ─────────────────────────────────────────────────────────────────────────────────────────────────┤
# ─── Example: Breaking change ────────────────────────────────────────────────────────────────────┤
# feat(bazel): simplify ng_package by dropping esm5 and fesm5
#
# esm5 and fesm5 distributions are no longer needed and have been deprecated in the past.
#
# https://v9.angular.io/guide/deprecations#esm5-and-fesm5-code-formats-in-angular-npm-packages
#
# This commit modifies ng_package to no longer distribute these two formats in npm packages built by
# ng_package (e.g. @angular/core).
#
# This commit intentionally doesn't fully clean up the ng_package rule to remove all traces of esm5
# and fems5 build artifacts as that is a bigger cleanup and currently we are narrowing down the
# scope of this change to the MVP needed for v10, which in this case is 'do not put esm5 and fesm5'
# into the npm packages.
#
# More cleanup to follow: https://angular-team.atlassian.net/browse/FW-2143
#
# BREAKING CHANGE: esm5 and fesm5 format is no longer distributed in Angular's npm packages e.g.
# @angular/core
#
# Angular CLI will automatically downlevel the code to es5 if differential loading is enabled in the
# Angular project, so no action is required from Angular CLI users.
#
# If you are not using Angular CLI to build your application or library, and you need to be able to
# build es5 artifacts, then you will need to downlevel the distributed Angular code to es5 on your
# own.
#
#
# Fixes #1234
# ─────────────────────────────────────────────────────────────────────────────────────────────────┤
# Angular Commit Message Format
# =============================
#
# The full specification of the Angular Commit Message Format can be found at
# https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit
#
# The following is an excerpt of the specification with the most commonly needed info.
#
# Each commit message consists of a *header*, a *body*, and a *footer*.
#
# <header>
# <BLANK LINE>
# <body>
# <BLANK LINE>
# <footer>
#
# The header is mandatory.
#
# The body is mandatory for all commits except for those of scope "docs". When the body is required
# it must be at least 20 characters long.
#
# The footer is optional.
#
# Any line of the commit message cannot be longer than 100 characters.
#
#
# Commit Message Header
# ---------------------
#
# <type>(<scope>): <short summary>
# │ │ │
# │ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
# │ │
# │ └─⫸ Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core|
# │ elements|forms|http|language-service|localize|platform-browser|
# │ platform-browser-dynamic|platform-server|router|service-worker|
# │ upgrade|zone.js|packaging|changelog|dev-infra|docs-infra|migrations|
# │ ngcc|ve
# │ https://github.com/angular/angular/blob/master/CONTRIBUTING.md#scope
# │
# └─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|style|test
# https://github.com/angular/angular/blob/master/CONTRIBUTING.md#type
#
#
# Commit Message Body
# ---------------------
#
# Just as in the summary, use the imperative, present tense: "fix" not "fixed" nor "fixes".
#
# Explain the motivation for the change in the commit message body. This commit message should
# explain WHY you are making the change. You can include a comparison of the previous behavior with
# the new behavior in order to illustrate the impact of the change.
#
#
# Commit Message Footer
# ---------------------
#
# The footer can contain information about breaking changes and is also the place to reference
# GitHub issues, Jira tickets, and other PRs that this commit closes or is related to.
#
# ```
# BREAKING CHANGE: <breaking change summary>
# <BLANK LINE>
# <breaking change description + migration instructions>
# <BLANK LINE>
# <BLANK LINE>
# Fixes #<issue number>
# ```
#
# Breaking Change section should start with the phrase "BREAKING CHANGE: " followed by a summary of
# the breaking change, a blank line, and a detailed description of the breaking change that also
# includes migration instructions.
#

View File

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

View File

@ -1,40 +0,0 @@
import {CommitMessageConfig} from '../dev-infra/commit-message/config';
/**
* The configuration for `ng-dev commit-message` commands.
*/
export const commitMessage: CommitMessageConfig = {
maxLineLength: 120,
minBodyLength: 20,
minBodyLengthTypeExcludes: ['docs'],
scopes: [
'animations',
'bazel',
'benchpress',
'changelog',
'common',
'compiler',
'compiler-cli',
'core',
'dev-infra',
'docs-infra',
'elements',
'forms',
'http',
'language-service',
'localize',
'migrations',
'ngcc',
'packaging',
'platform-browser',
'platform-browser-dynamic',
'platform-server',
'platform-webworker',
'platform-webworker-dynamic',
'router',
'service-worker',
'upgrade',
've',
'zone.js',
]
};

View File

@ -1,15 +1,124 @@
import {caretaker} from './caretaker';
import {commitMessage} from './commit-message';
import {format} from './format';
import {github} from './github';
import {merge} from './merge';
import {release} from './release';
import {MergeConfig} from '../dev-infra/pr/merge/config';
// The configuration for `ng-dev commit-message` commands.
const commitMessage = {
'maxLength': 120,
'minBodyLength': 100,
'types': [
'build',
'ci',
'docs',
'feat',
'fix',
'perf',
'refactor',
'release',
'style',
'test',
],
'scopes': [
'animations',
'bazel',
'benchpress',
'changelog',
'common',
'compiler',
'compiler-cli',
'core',
'dev-infra',
'docs-infra',
'elements',
'forms',
'http',
'language-service',
'localize',
'ngcc',
'packaging',
'platform-browser',
'platform-browser-dynamic',
'platform-server',
'platform-webworker',
'platform-webworker-dynamic',
'router',
'service-worker',
'upgrade',
've',
'zone.js',
]
};
// The configuration for `ng-dev format` commands.
const format = {
'clang-format': {
'matchers': [
'dev-infra/**/*.{js,ts}',
'packages/**/*.{js,ts}',
'!packages/zone.js',
'!packages/common/locales/**/*.{js,ts}',
'!packages/common/src/i18n/available_locales.ts',
'!packages/common/src/i18n/currencies.ts',
'!packages/common/src/i18n/locale_en.ts',
'modules/benchmarks/**/*.{js,ts}',
'modules/playground/**/*.{js,ts}',
'tools/**/*.{js,ts}',
'!tools/gulp-tasks/cldr/extract.js',
'!tools/public_api_guard/**/*.d.ts',
'!tools/ts-api-guardian/test/fixtures/**',
'*.{js,ts}',
'!**/node_modules/**',
'!**/dist/**',
'!**/built/**',
'!shims_for_IE.js',
]
},
'buildifier': true
};
/** Github metadata information for `ng-dev` commands. */
const github = {
owner: 'angular',
name: 'angular',
};
// Configuration for the `ng-dev pr merge` command. The command can be used
// for merging upstream pull requests into branches based on a PR target label.
const merge = () => {
// TODO: resume dynamically determining patch branch
const patch = '10.0.x';
const config: MergeConfig = {
githubApiMerge: false,
claSignedLabel: 'cla: yes',
mergeReadyLabel: /^PR action: merge(-assistance)?/,
commitMessageFixupLabel: 'commit message fixup',
labels: [
{
pattern: 'PR target: master-only',
branches: ['master'],
},
{
pattern: 'PR target: patch-only',
branches: [patch],
},
{
pattern: 'PR target: master & patch',
branches: ['master', patch],
},
],
requiredBaseCommits: {
// PRs that target either `master` or the patch branch, need to be rebased
// on top of the latest commit message validation fix.
// These SHAs are the commits that update the required license text in the header.
'master': '5aeb9a4124922d8ac08eb73b8f322905a32b0b3a',
[patch]: '27b95ba64a5d99757f4042073fd1860e20e3ed24'
},
};
return config;
};
// Export function to build ng-dev configuration object.
module.exports = {
commitMessage,
format,
github,
merge,
caretaker,
release,
};

View File

@ -1,22 +0,0 @@
import {FormatConfig} from '../dev-infra/format/config';
/**
* Configuration for the `ng-dev format` command.
*/
export const format: FormatConfig = {
'clang-format': {
'matchers': [
'**/*.{js,ts}',
// TODO: burn down format failures and remove aio and integration exceptions.
'!aio/**',
'!integration/**',
// Both third_party and .yarn are directories containing copied code which should
// not be modified.
'!third_party/**',
'!.yarn/**',
// Do not format d.ts files as they are generated
'!**/*.d.ts',
]
},
'buildifier': true
};

View File

@ -1,15 +0,0 @@
# The file is inert unless it's explicitly included into the local git config via:
#
# ```
# git config --add include.path '../.ng-dev/gitconfig'
# ```
#
# Calling that command will append the following into `.git/config` of the current git workspace
# (i.e. $GIT_DIR, typically `angular/.git/config`):
#
# ```
# [include]
# path = ../.ng-dev/gitconfig
# ```
[commit]
template = .gitmessage

View File

@ -1,11 +0,0 @@
import {GithubConfig} from '../dev-infra/utils/config';
/**
* Github configuration for the `ng-dev` command. This repository is used as
* remote for the merge script and other utilities like `ng-dev pr rebase`.
*/
export const github: GithubConfig = {
owner: 'angular',
name: 'angular'
};

View File

@ -1,28 +0,0 @@
import {DevInfraMergeConfig} from '../dev-infra/pr/merge/config';
import {getDefaultTargetLabelConfiguration} from '../dev-infra/pr/merge/defaults';
import {github} from './github';
import {release} from './release';
/**
* Configuration for the merge tool in `ng-dev`. This sets up the labels which
* are respected by the merge script (e.g. the target labels).
*/
export const merge: DevInfraMergeConfig['merge'] = async api => {
return {
githubApiMerge: false,
claSignedLabel: 'cla: yes',
mergeReadyLabel: /^action: merge(-assistance)?/,
caretakerNoteLabel: 'action: merge-assistance',
commitMessageFixupLabel: 'commit message fixup',
// We can pick any of the NPM packages as we are in a monorepo where all packages are
// published together with the same version and branching.
labels: await getDefaultTargetLabelConfiguration(api, github, release),
requiredBaseCommits: {
// PRs that target either `master` or the patch branch, need to be rebased
// on top of the latest commit message validation fix.
// These SHAs are the commits that update the required license text in the header.
'master': '5aeb9a4124922d8ac08eb73b8f322905a32b0b3a',
'10.0.x': '27b95ba64a5d99757f4042073fd1860e20e3ed24',
},
};
};

View File

@ -1,33 +0,0 @@
import {join} from 'path';
import {exec} from 'shelljs';
import {ReleaseConfig} from '../dev-infra/release/config';
/** Configuration for the `ng-dev release` command. */
export const release: ReleaseConfig = {
npmPackages: [
'@angular/animations',
'@angular/bazel',
'@angular/common',
'@angular/compiler',
'@angular/compiler-cli',
'@angular/core',
'@angular/elements',
'@angular/forms',
'@angular/language-service',
'@angular/localize',
'@angular/platform-browser',
'@angular/platform-browser-dynamic',
'@angular/platform-server',
'@angular/platform-webworker',
'@angular/platform-webworker-dynamic',
'@angular/router',
'@angular/service-worker',
'@angular/upgrade',
],
// TODO: Implement release package building here.
buildPackages: async () => [],
// 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

@ -34,8 +34,41 @@
####################################################################################
# GitHub usernames
####################################################################################
# See reviewer list under `required-minimum-review` group. Team member names and
# usernames are managed there.
# aikidave - Dave Shevitz
# alan-agius4 - Alan Agius
# alxhub - Alex Rickabaugh
# AndrewKushnir - Andrew Kushnir
# andrewseguin - Andrew Seguin
# atscott - Andrew Scott
# ayazhafiz - Ayaz Hafiz
# clydin - Charles Lyding
# crisbeto - Kristiyan Kostadinov
# dennispbrown - Denny Brown
# devversion - Paul Gschwendtner
# dgp1130 - Doug Parker
# filipesilva - Filipe Silva
# gkalpak - Georgios Kalpakas
# gregmagolan - Greg Magolan
# IgorMinar - Igor Minar
# jbogarthyde - Judy Bogart
# jelbourn - Jeremy Elbourn
# JiaLiPassion - Jia Li
# JoostK - Joost Koehoorn
# josephperrott - Joey Perrott
# juleskremer - Jules Kremer
# kapunahelewong - Kapunahele Wong
# kara - Kara Erickson
# kyliau - Keen Yee Liau
# manughub - Manu Murthy
# matsko - Matias Niemela
# mgechev - Minko Gechev
# mhevery - Miško Hevery
# michaelprentice - Michael Prentice
# mmalerba - Miles Malerba
# petebacondarwin - Pete Bacon Darwin
# pkozlowski-opensource - Pawel Kozlowski
# robwormald - Rob Wormald
# StephenFluin - Stephen Fluin
####################################################################################
@ -67,35 +100,8 @@ version: 3
# Meta field that goes unused by PullApprove to allow for defining aliases to be
# used throughout the config.
meta:
# The following groups have no file based conditions and will be initially `active` on all PRs
# - `global-approvers`
# - `global-docs-approvers`
# - `required-minimum-review`
#
# By checking the number of active/pending/rejected groups when these are excluded, we can determine
# if any other groups are matched.
#
# Note: Because all inactive groups start as pending, we are only checking pending and rejected active groups.
#
# Also note that the ordering of groups matters in this file. The only groups visible to the current
# one are those that appear above it.
no-groups-above-this-pending: &no-groups-above-this-pending
len(groups.active.pending.exclude("required-minimum-review").exclude("global-approvers").exclude("global-docs-approvers")) == 0
no-groups-above-this-rejected: &no-groups-above-this-rejected
len(groups.active.rejected.exclude("required-minimum-review").exclude("global-approvers").exclude("global-docs-approvers")) == 0
no-groups-above-this-active: &no-groups-above-this-active
len(groups.active.exclude("required-minimum-review").exclude("global-approvers").exclude("global-docs-approvers")) == 0
can-be-global-approved: &can-be-global-approved "\"global-approvers\" not in groups.approved"
can-be-global-docs-approved: &can-be-global-docs-approved "\"global-docs-approvers\" not in groups.approved"
defaults: &defaults
reviews:
# Authors provide their approval implicitly, this approval allows for a reviewer
# from a group not to need a review specifically for an area of the repository
# they own. This is coupled with the `required-minimum-review` group which requires
# that all PRs are reviewed by at least one team member who is not the author of
# the PR.
author_value: 1
1: &can-be-global-approved "\"global-approvers\" not in groups.approved"
2: &can-be-global-docs-approved "\"global-docs-approvers\" not in groups.approved"
# turn on 'draft' support
# https://docs.pullapprove.com/config/github-api-version/
@ -151,63 +157,10 @@ groups:
required: 1
reviewed_for: required
# =========================================================
# Require review on all PRs
#
# All PRs require at least one review. This rule will not
# request any reviewers, however will require that at least
# one review is provided before the group is satisfied.
# =========================================================
required-minimum-review:
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
reviews:
request: 0 # Do not request any reviews from the reviewer group
required: 1 # Require that all PRs have approval from at least one of the users in the group
author_value: 0 # The author of the PR cannot provide an approval for themself
reviewers:
users:
- aikidave # Dave Shevitz
- alan-agius4 # Alan Agius
- alxhub # Alex Rickabaugh
- AndrewKushnir # Andrew Kushnir
- andrewseguin # Andrew Seguin
- atscott # Andrew Scott
- ayazhafiz # Ayaz Hafiz
- clydin # Charles Lyding
- crisbeto # Kristiyan Kostadinov
- dennispbrown # Denny Brown
- devversion # Paul Gschwendtner
- dgp1130 # Doug Parker
- filipesilva # Filipe Silva
- gkalpak # Georgios Kalpakas
- gregmagolan # Greg Magolan
- IgorMinar # Igor Minar
- jbogarthyde # Judy Bogart
- jelbourn # Jeremy Elbourn
- jessicajaniuk # Jessica Janiuk
- JiaLiPassion # Jia Li
- JoostK # Joost Koehoorn
- josephperrott # Joey Perrott
- juleskremer # Jules Kremer
- kapunahelewong # Kapunahele Wong
- kara # Kara Erickson
- kyliau # Keen Yee Liau
- manughub # Manu Murthy
- mgechev # Minko Gechev
- mhevery # Miško Hevery
- mmalerba # Miles Malerba
- petebacondarwin # Pete Bacon Darwin
- pkozlowski-opensource # Pawel Kozlowski
- Splaktar # Michael Prentice
- StephenFluin # Stephen Fluin
# =========================================================
# Framework: Animations
# =========================================================
fw-animations:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -225,16 +178,13 @@ groups:
])
reviewers:
users:
- crisbeto
- IgorMinar
- jelbourn
- matsko
# =========================================================
# Framework: Compiler
# =========================================================
fw-compiler:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -259,7 +209,6 @@ groups:
# Framework: Compiler / ngcc
# =========================================================
fw-ngcc:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -276,7 +225,6 @@ groups:
# Framework: Migrations
# =========================================================
fw-migrations:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -285,14 +233,13 @@ groups:
users:
- alxhub
- crisbeto
# OOO as of 2020-09-28 - devversion
- devversion
# =========================================================
# Framework: Core
# =========================================================
fw-core:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -304,6 +251,8 @@ groups:
'packages/platform-browser/**',
'packages/examples/platform-browser/**',
'packages/platform-browser-dynamic/**',
'packages/platform-webworker/**',
'packages/platform-webworker-dynamic/**',
'packages/examples/common/**',
'packages/docs/**',
'aio/content/guide/accessibility.md',
@ -325,7 +274,6 @@ 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/**',
@ -335,7 +283,6 @@ groups:
'aio/content/images/guide/dependency-injection-in-action/**',
'aio/content/guide/dependency-injection-navtree.md',
'aio/content/guide/dependency-injection-providers.md',
'aio/content/guide/lightweight-injection-tokens.md',
'aio/content/guide/displaying-data.md',
'aio/content/examples/displaying-data/**',
'aio/content/images/guide/displaying-data/**',
@ -366,38 +313,26 @@ groups:
'aio/content/guide/ngmodule-vs-jsmodule.md',
'aio/content/guide/module-types.md',
'aio/content/guide/template-syntax.md',
'aio/content/guide/built-in-template-functions.md',
'aio/content/examples/built-in-template-functions/**',
'aio/content/guide/event-binding.md',
'aio/content/examples/event-binding/**',
'aio/content/guide/interpolation.md',
'aio/content/examples/interpolation/**',
'aio/content/examples/template-syntax/**',
'aio/content/images/guide/template-syntax/**',
'aio/content/guide/binding-syntax.md',
'aio/content/examples/binding-syntax/**',
'aio/content/guide/property-binding.md',
'aio/content/examples/property-binding/**',
'aio/content/guide/attribute-binding.md',
'aio/content/examples/attribute-binding/**',
'aio/content/guide/two-way-binding.md',
'aio/content/examples/two-way-binding/**',
'aio/content/guide/built-in-directives.md',
'aio/content/examples/built-in-directives/**',
'aio/content/images/guide/built-in-directives/**',
'aio/content/guide/template-reference-variables.md',
'aio/content/examples/template-reference-variables/**',
'aio/content/guide/inputs-outputs.md',
'aio/content/examples/inputs-outputs/**',
'aio/content/images/guide/inputs-outputs/**',
'aio/content/guide/template-expression-operators.md',
'aio/content/examples/template-expression-operators/**',
'aio/content/guide/pipes.md',
'aio/content/examples/pipes/**',
'aio/content/images/guide/pipes/**',
'aio/content/guide/providers.md',
'aio/content/examples/providers/**',
'aio/content/images/guide/providers/**',
'aio/content/guide/singleton-services.md',
'aio/content/guide/set-document-title.md',
'aio/content/examples/set-document-title/**',
@ -405,10 +340,7 @@ groups:
'aio/content/guide/sharing-ngmodules.md',
'aio/content/guide/structural-directives.md',
'aio/content/examples/structural-directives/**',
'aio/content/guide/svg-in-templates.md',
'aio/content/guide/style-precedence.md',
'aio/content/images/guide/structural-directives/**',
'aio/content/guide/template-statements.md',
'aio/content/guide/user-input.md',
'aio/content/examples/user-input/**',
'aio/content/images/guide/user-input/**'
@ -420,14 +352,13 @@ groups:
- atscott
- ~kara # do not request reviews from Kara, but allow her to approve PRs
- mhevery
# OOO as of 2020-09-28 - pkozlowski-opensource
- pkozlowski-opensource
# =========================================================
# Framework: Http
# =========================================================
fw-http:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -449,7 +380,6 @@ groups:
# Framework: Elements
# =========================================================
fw-elements:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -470,7 +400,6 @@ groups:
# Framework: Forms
# =========================================================
fw-forms:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -503,15 +432,14 @@ groups:
# Framework: i18n
# =========================================================
fw-i18n:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
- >
contains_any_globs(files, [
'packages/core/src/i18n/**',
'packages/core/src/render3/i18n/**',
'packages/core/src/render3/instructions/i18n.ts',
'packages/core/src/render3/i18n.ts',
'packages/core/src/render3/i18n.md',
'packages/core/src/render3/interfaces/i18n.ts',
'packages/common/locales/**',
'packages/common/src/i18n/**',
@ -537,7 +465,6 @@ groups:
# Framework: Platform Server
# =========================================================
fw-platform-server:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -557,7 +484,6 @@ groups:
# Framework: Router
# =========================================================
fw-router:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -567,7 +493,6 @@ groups:
'packages/examples/router/**',
'aio/content/guide/router.md',
'aio/content/guide/router-tutorial.md',
'aio/content/guide/router-tutorial-toh.md',
'aio/content/examples/router-tutorial/**',
'aio/content/examples/router/**',
'aio/content/images/guide/router/**'
@ -581,7 +506,6 @@ groups:
# Framework: Service Worker
# =========================================================
fw-service-worker:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -609,7 +533,6 @@ groups:
# Framework: Upgrade
# =========================================================
fw-upgrade:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -640,7 +563,6 @@ groups:
# Framework: Testing
# =========================================================
fw-testing:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -648,14 +570,6 @@ groups:
contains_any_globs(files.exclude('packages/compiler-cli/**'), [
'**/testing/**',
'aio/content/guide/testing.md',
'aio/content/guide/test-debugging.md',
'aio/content/guide/testing-attribute-directives.md',
'aio/content/guide/testing-code-coverage.md',
'aio/content/guide/testing-components-basics.md',
'aio/content/guide/testing-components-scenarios.md',
'aio/content/guide/testing-pipes.md',
'aio/content/guide/testing-services.md',
'aio/content/guide/testing-utility-apis.md',
'aio/content/examples/testing/**',
'aio/content/images/guide/testing/**'
])
@ -663,14 +577,13 @@ groups:
users:
- AndrewKushnir
- IgorMinar
# OOO as of 2020-09-28 - pkozlowski-opensource
- pkozlowski-opensource
# =========================================================
# Framework: Benchmarks
# =========================================================
fw-benchmarks:
<<: *defaults
conditions:
- *can-be-global-approved
- >
@ -680,14 +593,13 @@ groups:
reviewers:
users:
- IgorMinar
# OOO as of 2020-09-28 - pkozlowski-opensource
- pkozlowski-opensource
# =========================================================
# Framework: Playground
# =========================================================
fw-playground:
<<: *defaults
conditions:
- *can-be-global-approved
- >
@ -698,14 +610,13 @@ groups:
users:
- IgorMinar
- jelbourn
# OOO as of 2020-09-28 - pkozlowski-opensource
- pkozlowski-opensource
# =========================================================
# Framework: Security
# =========================================================
fw-security:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -724,7 +635,7 @@ groups:
- IgorMinar
- mhevery
- jelbourn
# OOO as of 2020-09-28 - pkozlowski-opensource
- pkozlowski-opensource
reviews:
request: -1 # request reviews from everyone
required: 2 # require at least 2 approvals
@ -735,7 +646,6 @@ groups:
# Bazel
# =========================================================
bazel:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -754,7 +664,6 @@ groups:
# Language Service
# =========================================================
language-service:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -774,7 +683,6 @@ groups:
# zone.js
# =========================================================
zone-js:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -788,27 +696,11 @@ groups:
- JiaLiPassion
- mhevery
# =========================================================
# in-memory-web-api
# =========================================================
in-memory-web-api:
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
- >
contains_any_globs(files, [
'packages/misc/angular-in-memory-web-api/**',
])
reviewers:
users:
- IgorMinar
- crisbeto
# =========================================================
# Benchpress
# =========================================================
benchpress:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -826,7 +718,6 @@ groups:
# Integration Tests
# =========================================================
integration-tests:
<<: *defaults
conditions:
- *can-be-global-approved
- >
@ -844,7 +735,6 @@ groups:
# Docs: Gettings Started & Tutorial
# =========================================================
docs-getting-started-and-tutorial:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -877,13 +767,11 @@ groups:
# Docs: Marketing
# =========================================================
docs-marketing:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
- >
contains_any_globs(files, [
'aio/content/guide/roadmap.md',
'aio/content/marketing/**',
'aio/content/images/bios/**',
'aio/content/images/marketing/**',
@ -901,7 +789,6 @@ groups:
# Docs: Observables
# =========================================================
docs-observables:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -927,7 +814,6 @@ groups:
# Docs: Packaging, Tooling, Releasing
# =========================================================
docs-packaging-and-releasing:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -947,7 +833,7 @@ groups:
'aio/content/guide/migration-localize.md',
'aio/content/guide/migration-module-with-providers.md',
'aio/content/guide/static-query-migration.md',
'aio/content/guide/updating-to-version-10.md',
'aio/content/guide/updating-to-version-9.md',
'aio/content/guide/ivy-compatibility.md',
'aio/content/guide/ivy-compatibility-examples.md'
])
@ -987,7 +873,6 @@ groups:
# Docs: CLI
# =========================================================
docs-cli:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -1004,12 +889,8 @@ groups:
'aio/content/images/guide/deployment/**',
'aio/content/guide/file-structure.md',
'aio/content/guide/ivy.md',
'aio/content/guide/strict-mode.md',
'aio/content/guide/web-worker.md',
'aio/content/guide/workspace-config.md',
'aio/content/guide/migration-solution-style-tsconfig.md',
'aio/content/guide/migration-update-module-and-target-compiler-options.md',
'aio/content/guide/migration-update-libraries-tslib.md',
])
reviewers:
users:
@ -1022,7 +903,6 @@ groups:
# Docs: CLI Libraries
# =========================================================
docs-libraries:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -1043,7 +923,6 @@ groups:
# Docs: Schematics
# =========================================================
docs-schematics:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -1066,7 +945,6 @@ groups:
# Docs-infra
# =========================================================
docs-infra:
<<: *defaults
conditions:
- *can-be-global-approved
- *can-be-global-docs-approved
@ -1096,11 +974,10 @@ groups:
# Dev-infra
# =========================================================
dev-infra:
<<: *defaults
conditions:
- *can-be-global-approved
- >
contains_any_globs(files.exclude("CHANGELOG.md").exclude("packages/compiler-cli/**/BUILD.bazel"), [
contains_any_globs(files.exclude("CHANGELOG.md"), [
'*',
'.circleci/**',
'.devcontainer/**',
@ -1111,18 +988,15 @@ groups:
'dev-infra/**',
'docs/BAZEL.md',
'docs/CARETAKER.md',
'docs/CODING_STANDARDS.md',
'docs/COMMITTER.md',
'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',
'docs/TOOLS.md',
'docs/TRIAGE_AND_LABELS.md',
'docs/images/**',
'goldens/*',
'modules/*',
'packages/*',
@ -1135,6 +1009,7 @@ groups:
'tools/circular_dependency_test/**',
'tools/contributing-stats/**',
'tools/gulp-tasks/**',
'tools/ngcontainer/**',
'tools/npm/**',
'tools/npm_integration_test/**',
'tools/rxjs/**',
@ -1153,7 +1028,7 @@ groups:
])
reviewers:
users:
# OOO as of 2020-09-28 - devversion
- devversion
- filipesilva
- gkalpak
- IgorMinar
@ -1164,10 +1039,7 @@ groups:
# Public API
# =========================================================
public-api:
<<: *defaults
conditions:
- *no-groups-above-this-pending
- *no-groups-above-this-rejected
- *can-be-global-approved
- >
contains_any_globs(files, [
@ -1181,16 +1053,13 @@ groups:
])
reviewers:
users:
- AndrewKushnir
- IgorMinar
- alxhub
- atscott
- IgorMinar
- jelbourn
- petebacondarwin
# OOO as of 2020-09-28 - pkozlowski-opensource
- pkozlowski-opensource
reviews:
request: 4 # Request reviews from four people
required: 3 # Require that three people approve
request: -1 # request reviews from everyone
required: 3 # require at least 3 approvals
reviewed_for: required
@ -1198,10 +1067,7 @@ groups:
# Size tracking
# ================================================
size-tracking:
<<: *defaults
conditions:
- *no-groups-above-this-pending
- *no-groups-above-this-rejected
- *can-be-global-approved
- >
contains_any_globs(files, [
@ -1209,16 +1075,13 @@ groups:
])
reviewers:
users:
- AndrewKushnir
- IgorMinar
- alxhub
- atscott
- IgorMinar
- jelbourn
- petebacondarwin
# OOO as of 2020-09-28 - pkozlowski-opensource
- pkozlowski-opensource
reviews:
request: 4 # Request reviews from four people
required: 2 # Require that two people approve
request: -1 # request reviews from everyone
required: 2 # require at least 2 approvals
reviewed_for: required
@ -1226,10 +1089,7 @@ groups:
# Circular dependencies
# ================================================
circular-dependencies:
<<: *defaults
conditions:
- *no-groups-above-this-pending
- *no-groups-above-this-rejected
- *can-be-global-approved
- >
contains_any_globs(files, [
@ -1237,13 +1097,10 @@ groups:
])
reviewers:
users:
- AndrewKushnir
- IgorMinar
- alxhub
- atscott
- jelbourn
- petebacondarwin
# OOO as of 2020-09-28 - pkozlowski-opensource
- josephperrott
- pkozlowski-opensource
####################################################################################
@ -1254,7 +1111,6 @@ groups:
# Code Ownership
# =========================================================
code-ownership:
<<: *defaults
conditions:
- *can-be-global-approved
- >
@ -1263,20 +1119,13 @@ groups:
])
reviewers:
users:
- AndrewKushnir
- IgorMinar
- alxhub
- atscott
- jelbourn
- josephperrott
- mhevery
# ====================================================
# Catch all for if no groups match the code change
# ====================================================
fallback:
<<: *defaults
# A group is considered to be `active` for a PR if at least one of group's
# conditions matches the PR.
#
@ -1296,10 +1145,13 @@ groups:
# `global-approvers` can still approve PRs that match this `fallback` rule,
# but that should be an exception and not an expectation.
conditions:
- *no-groups-above-this-active
# When any of the `global-*` groups is approved, they cause other groups to deactivate.
# In those cases, the condition above would evaluate to `true` while in reality, only a global
# approval has been provided. To ensure we don't activate the fallback group in such cases,
# ensure that no explicit global approval has been provided.
- *can-be-global-approved
- *can-be-global-docs-approved
# The following groups have no conditions and will be `active` on all PRs
# - `global-approvers`
# - `global-docs-approvers`
#
# Since this means the minimum number of active groups a PR can have is 2, this
# `fallback` group should be matched anytime the number of active groups is at or
# below this minimum. This work as a protection to ensure that pullapprove does
# not incidently mark a PR as passing without meeting the review criteria.
- len(groups.active) <= 2

View File

@ -26,7 +26,6 @@
"**/bazel-out": true,
"**/dist": true,
"**/aio/src/generated": true,
".history": true,
},
"git.ignoreLimitWarning": true,
}
}

View File

@ -44654,7 +44654,7 @@ const FOLDERS_IGNORE = [
const DEFAULT_IGNORE = (0, (_filter || _load_filter()).ignoreLinesToRegex)([...FOLDERS_IGNORE,
// ignore cruft
'yarn.lock', '.lock-wscript', '.wafpickle-{0..9}', '*.swp', '._*', 'npm-debug.log', 'yarn-error.log', '.npmrc', '.yarnrc', '.yarnrc.yml', '.npmignore', '.gitignore', '.DS_Store']);
'yarn.lock', '.lock-wscript', '.wafpickle-{0..9}', '*.swp', '._*', 'npm-debug.log', 'yarn-error.log', '.npmrc', '.yarnrc', '.npmignore', '.gitignore', '.DS_Store']);
const NEVER_IGNORE = (0, (_filter || _load_filter()).ignoreLinesToRegex)([
// never ignore these files
@ -44663,7 +44663,6 @@ const NEVER_IGNORE = (0, (_filter || _load_filter()).ignoreLinesToRegex)([
function packWithIgnoreAndHeaders(cwd, ignoreFunction, { mapHeader } = {}) {
return tar.pack(cwd, {
ignore: ignoreFunction,
sort: true,
map: header => {
const suffix = header.name === '.' ? '' : `/${header.name}`;
header.name = `package${suffix}`;
@ -46679,7 +46678,7 @@ function mkdirfix (name, opts, cb) {
/* 194 */
/***/ (function(module, exports) {
module.exports = {"name":"yarn","installationMethod":"unknown","version":"1.22.5","license":"BSD-2-Clause","preferGlobal":true,"description":"📦🐈 Fast, reliable, and secure dependency management.","dependencies":{"@zkochan/cmd-shim":"^3.1.0","babel-runtime":"^6.26.0","bytes":"^3.0.0","camelcase":"^4.0.0","chalk":"^2.1.0","cli-table3":"^0.4.0","commander":"^2.9.0","death":"^1.0.0","debug":"^3.0.0","deep-equal":"^1.0.1","detect-indent":"^5.0.0","dnscache":"^1.0.1","glob":"^7.1.1","gunzip-maybe":"^1.4.0","hash-for-dep":"^1.2.3","imports-loader":"^0.8.0","ini":"^1.3.4","inquirer":"^6.2.0","invariant":"^2.2.0","is-builtin-module":"^2.0.0","is-ci":"^1.0.10","is-webpack-bundle":"^1.0.0","js-yaml":"^3.13.1","leven":"^2.0.0","loud-rejection":"^1.2.0","micromatch":"^2.3.11","mkdirp":"^0.5.1","node-emoji":"^1.6.1","normalize-url":"^2.0.0","npm-logical-tree":"^1.2.1","object-path":"^0.11.2","proper-lockfile":"^2.0.0","puka":"^1.0.0","read":"^1.0.7","request":"^2.87.0","request-capture-har":"^1.2.2","rimraf":"^2.5.0","semver":"^5.1.0","ssri":"^5.3.0","strip-ansi":"^4.0.0","strip-bom":"^3.0.0","tar-fs":"^1.16.0","tar-stream":"^1.6.1","uuid":"^3.0.1","v8-compile-cache":"^2.0.0","validate-npm-package-license":"^3.0.4","yn":"^2.0.0"},"devDependencies":{"babel-core":"^6.26.0","babel-eslint":"^7.2.3","babel-loader":"^6.2.5","babel-plugin-array-includes":"^2.0.3","babel-plugin-inline-import":"^3.0.0","babel-plugin-transform-builtin-extend":"^1.1.2","babel-plugin-transform-inline-imports-commonjs":"^1.0.0","babel-plugin-transform-runtime":"^6.4.3","babel-preset-env":"^1.6.0","babel-preset-flow":"^6.23.0","babel-preset-stage-0":"^6.0.0","babylon":"^6.5.0","commitizen":"^2.9.6","cz-conventional-changelog":"^2.0.0","eslint":"^4.3.0","eslint-config-fb-strict":"^22.0.0","eslint-plugin-babel":"^5.0.0","eslint-plugin-flowtype":"^2.35.0","eslint-plugin-jasmine":"^2.6.2","eslint-plugin-jest":"^21.0.0","eslint-plugin-jsx-a11y":"^6.0.2","eslint-plugin-prefer-object-spread":"^1.2.1","eslint-plugin-prettier":"^2.1.2","eslint-plugin-react":"^7.1.0","eslint-plugin-relay":"^0.0.28","eslint-plugin-yarn-internal":"file:scripts/eslint-rules","execa":"^0.11.0","fancy-log":"^1.3.2","flow-bin":"^0.66.0","git-release-notes":"^3.0.0","gulp":"^4.0.0","gulp-babel":"^7.0.0","gulp-if":"^2.0.1","gulp-newer":"^1.0.0","gulp-plumber":"^1.0.1","gulp-sourcemaps":"^2.2.0","jest":"^22.4.4","jsinspect":"^0.12.6","minimatch":"^3.0.4","mock-stdin":"^0.3.0","prettier":"^1.5.2","string-replace-loader":"^2.1.1","temp":"^0.8.3","webpack":"^2.1.0-beta.25","yargs":"^6.3.0"},"resolutions":{"sshpk":"^1.14.2"},"engines":{"node":">=4.0.0"},"repository":"yarnpkg/yarn","bin":{"yarn":"./bin/yarn.js","yarnpkg":"./bin/yarn.js"},"scripts":{"build":"gulp build","build-bundle":"node ./scripts/build-webpack.js","build-chocolatey":"powershell ./scripts/build-chocolatey.ps1","build-deb":"./scripts/build-deb.sh","build-dist":"bash ./scripts/build-dist.sh","build-win-installer":"scripts\\build-windows-installer.bat","changelog":"git-release-notes $(git describe --tags --abbrev=0 $(git describe --tags --abbrev=0)^)..$(git describe --tags --abbrev=0) scripts/changelog.md","dupe-check":"yarn jsinspect ./src","lint":"eslint . && flow check","pkg-tests":"yarn --cwd packages/pkg-tests jest yarn.test.js","prettier":"eslint src __tests__ --fix","release-branch":"./scripts/release-branch.sh","test":"yarn lint && yarn test-only","test-only":"node --max_old_space_size=4096 node_modules/jest/bin/jest.js --verbose","test-only-debug":"node --inspect-brk --max_old_space_size=4096 node_modules/jest/bin/jest.js --runInBand --verbose","test-coverage":"node --max_old_space_size=4096 node_modules/jest/bin/jest.js --coverage --verbose","watch":"gulp watch","commit":"git-cz"},"jest":{"collectCoverageFrom":["src/**/*.js"],"testEnvironment":"node","modulePathIgnorePatterns":["__tests__/fixtures/","packages/pkg-tests/pkg-tests-fixtures","dist/"],"testPathIgnorePatterns":["__tests__/(fixtures|__mocks__)/","updates/","_(temp|mock|install|init|helpers).js$","packages/pkg-tests"]},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}}}
module.exports = {"name":"yarn","installationMethod":"unknown","version":"1.22.4","license":"BSD-2-Clause","preferGlobal":true,"description":"📦🐈 Fast, reliable, and secure dependency management.","dependencies":{"@zkochan/cmd-shim":"^3.1.0","babel-runtime":"^6.26.0","bytes":"^3.0.0","camelcase":"^4.0.0","chalk":"^2.1.0","cli-table3":"^0.4.0","commander":"^2.9.0","death":"^1.0.0","debug":"^3.0.0","deep-equal":"^1.0.1","detect-indent":"^5.0.0","dnscache":"^1.0.1","glob":"^7.1.1","gunzip-maybe":"^1.4.0","hash-for-dep":"^1.2.3","imports-loader":"^0.8.0","ini":"^1.3.4","inquirer":"^6.2.0","invariant":"^2.2.0","is-builtin-module":"^2.0.0","is-ci":"^1.0.10","is-webpack-bundle":"^1.0.0","js-yaml":"^3.13.1","leven":"^2.0.0","loud-rejection":"^1.2.0","micromatch":"^2.3.11","mkdirp":"^0.5.1","node-emoji":"^1.6.1","normalize-url":"^2.0.0","npm-logical-tree":"^1.2.1","object-path":"^0.11.2","proper-lockfile":"^2.0.0","puka":"^1.0.0","read":"^1.0.7","request":"^2.87.0","request-capture-har":"^1.2.2","rimraf":"^2.5.0","semver":"^5.1.0","ssri":"^5.3.0","strip-ansi":"^4.0.0","strip-bom":"^3.0.0","tar-fs":"^1.16.0","tar-stream":"^1.6.1","uuid":"^3.0.1","v8-compile-cache":"^2.0.0","validate-npm-package-license":"^3.0.4","yn":"^2.0.0"},"devDependencies":{"babel-core":"^6.26.0","babel-eslint":"^7.2.3","babel-loader":"^6.2.5","babel-plugin-array-includes":"^2.0.3","babel-plugin-inline-import":"^3.0.0","babel-plugin-transform-builtin-extend":"^1.1.2","babel-plugin-transform-inline-imports-commonjs":"^1.0.0","babel-plugin-transform-runtime":"^6.4.3","babel-preset-env":"^1.6.0","babel-preset-flow":"^6.23.0","babel-preset-stage-0":"^6.0.0","babylon":"^6.5.0","commitizen":"^2.9.6","cz-conventional-changelog":"^2.0.0","eslint":"^4.3.0","eslint-config-fb-strict":"^22.0.0","eslint-plugin-babel":"^5.0.0","eslint-plugin-flowtype":"^2.35.0","eslint-plugin-jasmine":"^2.6.2","eslint-plugin-jest":"^21.0.0","eslint-plugin-jsx-a11y":"^6.0.2","eslint-plugin-prefer-object-spread":"^1.2.1","eslint-plugin-prettier":"^2.1.2","eslint-plugin-react":"^7.1.0","eslint-plugin-relay":"^0.0.28","eslint-plugin-yarn-internal":"file:scripts/eslint-rules","execa":"^0.11.0","fancy-log":"^1.3.2","flow-bin":"^0.66.0","git-release-notes":"^3.0.0","gulp":"^4.0.0","gulp-babel":"^7.0.0","gulp-if":"^2.0.1","gulp-newer":"^1.0.0","gulp-plumber":"^1.0.1","gulp-sourcemaps":"^2.2.0","jest":"^22.4.4","jsinspect":"^0.12.6","minimatch":"^3.0.4","mock-stdin":"^0.3.0","prettier":"^1.5.2","string-replace-loader":"^2.1.1","temp":"^0.8.3","webpack":"^2.1.0-beta.25","yargs":"^6.3.0"},"resolutions":{"sshpk":"^1.14.2"},"engines":{"node":">=4.0.0"},"repository":"yarnpkg/yarn","bin":{"yarn":"./bin/yarn.js","yarnpkg":"./bin/yarn.js"},"scripts":{"build":"gulp build","build-bundle":"node ./scripts/build-webpack.js","build-chocolatey":"powershell ./scripts/build-chocolatey.ps1","build-deb":"./scripts/build-deb.sh","build-dist":"bash ./scripts/build-dist.sh","build-win-installer":"scripts\\build-windows-installer.bat","changelog":"git-release-notes $(git describe --tags --abbrev=0 $(git describe --tags --abbrev=0)^)..$(git describe --tags --abbrev=0) scripts/changelog.md","dupe-check":"yarn jsinspect ./src","lint":"eslint . && flow check","pkg-tests":"yarn --cwd packages/pkg-tests jest yarn.test.js","prettier":"eslint src __tests__ --fix","release-branch":"./scripts/release-branch.sh","test":"yarn lint && yarn test-only","test-only":"node --max_old_space_size=4096 node_modules/jest/bin/jest.js --verbose","test-only-debug":"node --inspect-brk --max_old_space_size=4096 node_modules/jest/bin/jest.js --runInBand --verbose","test-coverage":"node --max_old_space_size=4096 node_modules/jest/bin/jest.js --coverage --verbose","watch":"gulp watch","commit":"git-cz"},"jest":{"collectCoverageFrom":["src/**/*.js"],"testEnvironment":"node","modulePathIgnorePatterns":["__tests__/fixtures/","packages/pkg-tests/pkg-tests-fixtures","dist/"],"testPathIgnorePatterns":["__tests__/(fixtures|__mocks__)/","updates/","_(temp|mock|install|init|helpers).js$","packages/pkg-tests"]},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}}}
/***/ }),
/* 195 */
@ -98339,7 +98338,7 @@ var _buildSubCommands = (0, (_buildSubCommands2 || _load_buildSubCommands()).def
const bundle = yield fetchBundle(config, bundleUrl);
const yarnPath = path.resolve(config.lockfileFolder, `.yarn/releases/yarn-${bundleVersion}.cjs`);
const yarnPath = path.resolve(config.lockfileFolder, `.yarn/releases/yarn-${bundleVersion}.js`);
reporter.log(`Saving it into ${chalk.magenta(yarnPath)}...`);
yield (_fs || _load_fs()).mkdirp(path.dirname(yarnPath));
yield (_fs || _load_fs()).writeFile(yarnPath, bundle);
@ -100191,7 +100190,7 @@ let main = exports.main = (() => {
const config = new (_config || _load_config()).default(reporter);
const outputWrapperEnabled = (0, (_conversion || _load_conversion()).boolifyWithDefault)(process.env.YARN_WRAP_OUTPUT, true);
const shouldWrapOutput = outputWrapperEnabled && !(_commander || _load_commander()).default.json && command.hasWrapper((_commander || _load_commander()).default, (_commander || _load_commander()).default.args) && !(commandName === 'init' && (_commander || _load_commander()).default[`2`]);
const shouldWrapOutput = outputWrapperEnabled && !(_commander || _load_commander()).default.json && command.hasWrapper((_commander || _load_commander()).default, (_commander || _load_commander()).default.args);
if (shouldWrapOutput) {
reporter.header(commandName, { name: 'yarn', version: (_yarnVersion || _load_yarnVersion()).version });
@ -100605,7 +100604,7 @@ let start = (() => {
});
try {
if (/\.[cm]?js$/.test(yarnPath)) {
if (yarnPath.endsWith(`.js`)) {
exitCode = yield (0, (_child || _load_child()).spawnp)(process.execPath, [yarnPath, ...argv], opts);
} else {
exitCode = yield (0, (_child || _load_child()).spawnp)(yarnPath, argv, opts);

View File

@ -2,4 +2,4 @@
# yarn lockfile v1
yarn-path ".yarn/releases/yarn-1.22.5.js"
yarn-path ".yarn/releases/yarn-1.22.4.js"

View File

@ -20,11 +20,11 @@ filegroup(
# do not sort
srcs = [
"@npm//:node_modules/core-js/client/core.js",
"//packages/zone.js/bundles:zone.umd.js",
"//packages/zone.js/bundles:zone-testing.umd.js",
"//packages/zone.js/bundles:task-tracking.umd.js",
"//packages/zone.js/dist:zone.js",
"//packages/zone.js/dist:zone-testing.js",
"//packages/zone.js/dist:task-tracking.js",
"//:test-events.js",
"//:third_party/shims_for_IE.js",
"//:shims_for_IE.js",
# Including systemjs because it defines `__eval`, which produces correct stack traces.
"@npm//:node_modules/systemjs/dist/system.src.js",
"@npm//:node_modules/reflect-metadata/Reflect.js",
@ -34,7 +34,7 @@ filegroup(
filegroup(
name = "angularjs_scripts",
srcs = [
# We also declare the unminified AngularJS files since these can be used for
# We also declare the unminfied AngularJS files since these can be used for
# local debugging (e.g. see: packages/upgrade/test/common/test_helpers.ts)
"@npm//:node_modules/angular/angular.js",
"@npm//:node_modules/angular/angular.min.js",
@ -47,9 +47,3 @@ 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"},
)

File diff suppressed because it is too large Load Diff

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, 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.
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.
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

@ -1,7 +1,7 @@
# Contributing to Angular
We would love for you to contribute to Angular and help make it even better than it is today!
As a contributor, here are the guidelines we would like you to follow:
We would love for you to contribute to Angular and help make it even better than it is
today! As a contributor, here are the guidelines we would like you to follow:
- [Code of Conduct](#coc)
- [Question or Problem?](#question)
@ -12,63 +12,50 @@ As a contributor, here are the guidelines we would like you to follow:
- [Commit Message Guidelines](#commit)
- [Signing the CLA](#cla)
## <a name="coc"></a> Code of Conduct
Help us keep Angular open and inclusive.
Please read and follow our [Code of Conduct][coc].
Help us keep Angular open and inclusive. Please read and follow our [Code of Conduct][coc].
## <a name="question"></a> Got a Question or Problem?
Do not open issues for general support questions as we want to keep GitHub issues for bug reports and feature requests.
Instead, we recommend using [Stack Overflow](https://stackoverflow.com/questions/tagged/angular) to ask support-related questions. When creating a new question on Stack Overflow, make sure to add the `angular` tag.
Do not open issues for general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [Stack Overflow](https://stackoverflow.com/questions/tagged/angular) where the questions should be tagged with tag `angular`.
Stack Overflow is a much better place to ask questions since:
- there are thousands of people willing to help on Stack Overflow
- questions and answers stay available for public viewing so your question/answer might help someone else
- questions and answers stay available for public viewing so your question / answer might help someone else
- Stack Overflow's voting system assures that the best answers are prominently visible.
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 Discord server][discord].
If you would like to chat about the question in real-time, you can reach out via [our gitter channel][gitter].
## <a name="issue"></a> Found a Bug?
If you find a bug in the source code, you can help us by [submitting an issue](#submit-issue) to our [GitHub Repository][github].
Even better, you can [submit a Pull Request](#submit-pr) with a fix.
If you find a bug in the source code, you can help us by
[submitting an issue](#submit-issue) to our [GitHub Repository][github]. Even better, you can
[submit a Pull Request](#submit-pr) with a fix.
## <a name="feature"></a> Missing a Feature?
You can *request* a new feature by [submitting an issue](#submit-issue) to our GitHub Repository.
If you would like to *implement* a new feature, please consider the size of the change in order to determine the right steps to proceed:
* For a **Major Feature**, first open an issue and outline your proposal so that it can be discussed.
This process allows us to better coordinate our efforts, prevent duplication of work, and help you to craft the change so that it is successfully accepted into the project.
**Note**: Adding a new topic to the documentation, or significantly re-writing a topic, counts as a major feature.
You can *request* a new feature by [submitting an issue](#submit-issue) to our GitHub
Repository. If you would like to *implement* a new feature, please submit an issue with
a proposal for your work first, to be sure that we can use it.
Please consider what kind of change it is:
* For a **Major Feature**, first open an issue and outline your proposal so that it can be
discussed. This will also allow us to better coordinate our efforts, prevent duplication of work,
and help you to craft the change so that it is successfully accepted into the project.
* **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
## <a name="submit"></a> Submission Guidelines
### <a name="submit-issue"></a> Submitting an Issue
Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available.
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it.
In order to reproduce bugs, we require that you provide a minimal reproduction.
Having a minimal reproducible scenario gives us a wealth of important information without going back and forth to you with additional questions.
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs, we will systematically ask you to provide a minimal reproduction. Having a minimal reproducible scenario gives us a wealth of important information without going back & forth to you with additional questions.
A minimal reproduction allows us to quickly confirm a bug (or point out a coding problem) as well as confirm that we are fixing the right problem.
We require a minimal reproduction to save maintainers' time and ultimately be able to fix more bugs.
Often, developers find coding problems themselves while preparing a minimal reproduction.
We understand that sometimes it might be hard to extract essential bits of code from a larger codebase but we really need to isolate the problem before we can fix it.
We will be insisting on a minimal reproduction scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience, users often find coding problems themselves while preparing a minimal reproduction. We understand that sometimes it might be hard to extract essential bits of code from a larger codebase but we really need to isolate the problem before we can fix it.
Unfortunately, we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you, we are going to close an issue that doesn't have enough info to be reproduced.
@ -76,101 +63,57 @@ You can file new issues by selecting from our [new issue templates](https://gith
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
Before you submit your Pull Request (PR) consider the following guidelines:
1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR that relates to your submission.
You don't want to duplicate existing efforts.
2. Be sure that an issue describes the problem you're fixing, or documents the design for the feature you'd like to add.
Discussing the design upfront helps to ensure that we're ready to accept your work.
3. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
We cannot accept code without a signed CLA.
Make sure you author all contributed Git commits with email address associated with your CLA signature.
4. Fork the angular/angular repo.
5. Make your changes in a new git branch:
1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR
that relates to your submission. You don't want to duplicate effort.
1. Be sure that an issue describes the problem you're fixing, or documents the design for the feature you'd like to add.
Discussing the design up front helps to ensure that we're ready to accept your work.
1. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
We cannot accept code without this. Make sure you sign with the primary email address of the Git identity that has been granted access to the Angular repository.
1. Fork the angular/angular repo.
1. Make your changes in a new git branch:
```shell
git checkout -b my-fix-branch master
```
6. Create your patch, **including appropriate test cases**.
7. Follow our [Coding Rules](#rules).
8. Run the full Angular test suite, as described in the [developer documentation][dev-doc], and ensure that all tests pass.
9. Commit your changes using a descriptive commit message that follows our [commit message conventions](#commit).
Adherence to these conventions is necessary because release notes are automatically generated from these messages.
1. Create your patch, **including appropriate test cases**.
1. Follow our [Coding Rules](#rules).
1. Run the full Angular test suite, as described in the [developer documentation][dev-doc],
and ensure that all tests pass.
1. Commit your changes using a descriptive commit message that follows our
[commit message conventions](#commit). Adherence to these conventions
is necessary because release notes are automatically generated from these messages.
```shell
git commit --all
git commit -a
```
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
10. Push your branch to GitHub:
1. Push your branch to GitHub:
```shell
git push origin my-fix-branch
```
11. In GitHub, send a pull request to `angular:master`.
#### Addressing review feedback
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):
1. In GitHub, send a pull request to `angular:master`.
* If we suggest changes 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):
```shell
git commit --all --fixup HEAD
git push
git rebase master -i
git push -f
```
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:
After your pull request is merged, you can safely delete your branch and pull the changes
from the main (upstream) repository:
* Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows:
@ -196,66 +139,55 @@ After your pull request is merged, you can safely delete your branch and pull th
git pull --ff upstream master
```
## <a name="rules"></a> Coding Rules
To ensure consistency throughout the source code, keep these rules in mind as you are working:
* All features or bug fixes **must be tested** by one or more specs (unit-tests).
* All public API methods **must be documented**.
* We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at **100 characters**.
* All public API methods **must be documented**. (Details TBC).
* We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at
**100 characters**. An automated formatter is available, see
[DEVELOPER.md](docs/DEVELOPER.md#clang-format).
An automated formatter is available, see [DEVELOPER.md](docs/DEVELOPER.md#clang-format).
## <a name="commit"></a> Commit Message Guidelines
We have very precise rules over how our git commit messages can be formatted. This leads to **more
readable messages** that are easy to follow when looking through the **project history**. But also,
we use the git commit messages to **generate the Angular change log**.
## <a name="commit"></a> Commit Message Format
*This specification is inspired and supersedes the [AngularJS commit message format][commit-message-format].*
We have very precise rules over how our Git commit messages must be formatted.
This format leads to **easier to read commit history**.
Each commit message consists of a **header**, a **body**, and a **footer**.
### Commit Message Format
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
format that includes a **type**, a **scope** and a **subject**:
```
<header>
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The `header` is mandatory and must conform to the [Commit Message Header](#commit-header) format.
The **header** is mandatory and the **scope** of the header is optional.
The `body` is mandatory for all commits except for those of scope "docs".
When the body is required it must be at least 20 characters long.
Any line of the commit message cannot be longer than 100 characters! This allows the message to be easier
to read on GitHub as well as in various git tools.
The `footer` is optional.
The footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any.
Any line of the commit message cannot be longer than 100 characters.
#### <a href="commit-header"></a>Commit Message Header
Samples: (even more [samples](https://github.com/angular/angular/commits/master))
```
<type>(<scope>): <short summary>
│ │ │
│ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
│ │
│ └─⫸ Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core|
│ elements|forms|http|language-service|localize|platform-browser|
│ platform-browser-dynamic|platform-server|router|service-worker|
│ upgrade|zone.js|packaging|changelog|dev-infra|docs-infra|migrations|
│ ngcc|ve
└─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|style|test
docs(changelog): update changelog to beta.5
```
```
fix(release): need to depend on latest rxjs and zone.js
The version in our package.json gets copied to the one we publish, and users need the latest of these.
```
The `<type>` and `<summary>` fields are mandatory, the `(<scope>)` field is optional.
##### Type
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
### Type
Must be one of the following:
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
@ -265,95 +197,69 @@ Must be one of the following:
* **fix**: A bug fix
* **perf**: A code change that improves performance
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
* **test**: Adding missing tests or correcting existing tests
##### Scope
### Scope
The scope should be the name of the npm package affected (as perceived by the person reading the changelog generated from commit messages).
The following is the list of supported scopes:
* `animations`
* `bazel`
* `benchpress`
* `common`
* `compiler`
* `compiler-cli`
* `core`
* `elements`
* `forms`
* `http`
* `language-service`
* `localize`
* `platform-browser`
* `platform-browser-dynamic`
* `platform-server`
* `router`
* `service-worker`
* `upgrade`
* `zone.js`
* **animations**
* **bazel**
* **benchpress**
* **common**
* **compiler**
* **compiler-cli**
* **core**
* **elements**
* **forms**
* **http**
* **language-service**
* **localize**
* **platform-browser**
* **platform-browser-dynamic**
* **platform-server**
* **platform-webworker**
* **platform-webworker-dynamic**
* **router**
* **service-worker**
* **upgrade**
* **zone.js**
There are currently a few exceptions to the "use package name" rule:
* `packaging`: used for changes that change the npm package layout in all of our packages, e.g. public path changes, package.json changes done to all packages, d.ts file/format changes, changes to bundles, etc.
* **packaging**: used for changes that change the npm package layout in all of our packages, e.g.
public path changes, package.json changes done to all packages, d.ts file/format changes, changes
to bundles, etc.
* **changelog**: used for updating the release notes in CHANGELOG.md
* **docs-infra**: used for docs-app (angular.io) related changes within the /aio directory of the
repo
* **dev-infra**: used for dev-infra related changes within the directories /scripts, /tools and /dev-infra
* **ngcc**: used for changes to the [Angular Compatibility Compiler](./packages/compiler-cli/ngcc/README.md)
* **ve**: used for changes specific to ViewEngine (legacy compiler/renderer).
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all
packages (e.g. `style: add missing semicolons`) and for docs changes that are not related to a
specific package (e.g. `docs: fix typo in tutorial`).
* `changelog`: used for updating the release notes in CHANGELOG.md
* `dev-infra`: used for dev-infra related changes within the directories /scripts, /tools and /dev-infra
* `docs-infra`: used for docs-app (angular.io) related changes within the /aio directory of the repo
* `migrations`: used for changes to the `ng update` migrations.
* `ngcc`: used for changes to the [Angular Compatibility Compiler](./packages/compiler-cli/ngcc/README.md)
* `ve`: used for changes specific to ViewEngine (legacy compiler/renderer).
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`) and for docs changes that are not related to a specific package (e.g. `docs: fix typo in tutorial`).
##### Summary
Use the summary field to provide a succinct description of the change:
### Subject
The subject contains a succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize the first letter
* no dot (.) at the end
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
The body should include the motivation for the change and contrast this with previous behavior.
#### Commit Message Body
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to
reference GitHub issues that this commit **Closes**.
Just as in the summary, use the imperative, present tense: "fix" not "fixed" nor "fixes".
Explain the motivation for the change in the commit message body. This commit message should explain _why_ you are making the change.
You can include a comparison of the previous behavior with the new behavior in order to illustrate the impact of the change.
#### Commit Message Footer
The footer can contain information about breaking changes and is also the place to reference GitHub issues, Jira tickets, and other PRs that this commit closes or is related to.
```
BREAKING CHANGE: <breaking change summary>
<BLANK LINE>
<breaking change description + migration instructions>
<BLANK LINE>
<BLANK LINE>
Fixes #<issue number>
```
Breaking Change section should start with the phrase "BREAKING CHANGE: " followed by a summary of the breaking change, a blank line, and a detailed description of the breaking change that also includes migration instructions.
### Revert commits
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit.
The content of the commit message body should contain:
- information about the SHA of the commit being reverted in the following format: `This reverts commit <SHA>`,
- a clear description of the reason for reverting the commit message.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
A detailed explanation can be found in this [document][commit-message-format].
## <a name="cla"></a> Signing the CLA
@ -364,17 +270,18 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
* For corporations, we'll need you to
[print, sign and one of scan+email, fax or mail the form][corporate-cla].
If you have more than one GitHub accounts, or multiple email addresses associated with a single GitHub account, you must sign the CLA using the primary email address of the GitHub account used to author Git commits and send pull requests.
<hr>
The following documents can help you sort out issues with GitHub accounts and multiple email addresses:
If you have more than one Git identity, you must make sure that you sign the CLA using the primary email address associated with the ID that has been granted access to the Angular repository. Git identities can be associated with more than one email address, and only one is primary. Here are some links to help you sort out multiple Git identities and email addresses:
* https://help.github.com/articles/setting-your-commit-email-address-in-git/
* https://stackoverflow.com/questions/37245303/what-does-usera-committed-with-userb-13-days-ago-on-github-mean
* https://help.github.com/articles/about-commit-email-addresses/
* https://help.github.com/articles/blocking-command-line-pushes-that-expose-your-personal-email-address/
Note that if you have more than one Git identity, it is important to verify that you are logged in with the same ID with which you signed the CLA, before you commit changes. If not, your PR will fail the CLA check.
<hr>
[angular-group]: https://groups.google.com/forum/#!forum/angular
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md
@ -382,7 +289,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
[discord]: https://discord.gg/angular
[gitter]: https://gitter.im/angular/angular
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
[js-style-guide]: https://google.github.io/styleguide/jsguide.html
[jsfiddle]: http://jsfiddle.net

145
README.md
View File

@ -1,151 +1,26 @@
<h1 align="center">Angular - One framework. Mobile & desktop.</h1>
[![CircleCI](https://circleci.com/gh/angular/angular/tree/master.svg?style=shield)](https://circleci.com/gh/angular/workflows/angular/tree/master)
[![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)
<p align="center">
<img src="aio/src/assets/images/logos/angular/angular.png" alt="angular-logo" width="120px" height="120px"/>
<br>
<i>Angular is a development platform for building mobile and desktop web applications
<br> using Typescript/JavaScript and other languages.</i>
<br>
</p>
<p align="center">
<a href="https://www.angular.io"><strong>www.angular.io</strong></a>
<br>
</p>
# Angular
<p align="center">
<a href="CONTRIBUTING.md">Contributing Guidelines</a>
·
<a href="https://github.com/angular/angular/issues">Submit an Issue</a>
·
<a href="https://blog.angular.io/">Blog</a>
<br>
<br>
</p>
<p align="center">
<a href="https://circleci.com/gh/angular/workflows/angular/tree/master">
<img src="https://img.shields.io/circleci/build/github/angular/angular/master.svg?logo=circleci&logoColor=fff&label=CircleCI" alt="CI status" />
</a>&nbsp;
<a href="https://www.npmjs.com/@angular/core">
<img src="https://img.shields.io/npm/v/@angular/core.svg?logo=npm&logoColor=fff&label=NPM+package&color=limegreen" alt="Angular on npm" />
</a>&nbsp;
<a href="https://discord.gg/angular">
<img src="https://img.shields.io/discord/463752820026376202.svg?logo=discord&logoColor=fff&label=Discord&color=7389d8" alt="Discord conversation" />
</a>
</p>
<hr>
## Documentation
Get started with Angular, learn the fundamentals and explore advanced topics on our documentation website.
- [Getting Started][quickstart]
- [Architecture][architecture]
- [Components and Templates][componentstemplates]
- [Forms][forms]
- [API][api]
### Advanced
- [Angular Elements][angularelements]
- [Server Side Rendering][ssr]
- [Schematics][schematics]
- [Lazy Loading][lazyloading]
## Development Setup
### Prerequisites
- Install [Node.js] which includes [Node Package Manager][npm]
### Setting Up a Project
Intall the Angular CLI globally:
```
npm install -g @angular/cli
```
Create workspace:
```
ng new [PROJECT NAME]
```
Run the application:
```
cd [PROJECT NAME]
ng serve
```
Angular is a development platform for building mobile and desktop web applications using TypeScript/JavaScript and other languages.
## Quickstart
[Get started in 5 minutes][quickstart].
## Ecosystem
<p>
<img src="/docs/images/angular-ecosystem-logos.png" alt="angular ecosystem logos" width="500px" height="auto">
</p>
- [Angular Command Line (CLI)][cli]
- [Angular Material][angularmaterial]
## Changelog
[Learn about the latest improvements][changelog].
## Upgrading
## Want to help?
Check out our [upgrade guide](https://update.angular.io/) to find out the best way to upgrade your project.
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our
guidelines for [contributing][contributing] and then check out one of our issues in the [hotlist: community-help](https://github.com/angular/angular/labels/hotlist%3A%20community-help).
## Contributing
### Contributing Guidelines
Read through our [contributing guidelines][contributing] to learn about our submission process, coding rules and more.
### Want to Help?
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our guidelines for [contributing][contributing] and then check out one of our issues in the [hotlist: community-help](https://github.com/angular/angular/labels/hotlist%3A%20community-help).
### Code of Conduct
Help us keep Angular open and inclusive. Please read and follow our [Code of Conduct][codeofconduct].
## Community
Join the conversation and help the community.
- [Twitter][twitter]
- [Gitter][gitter]
- Find a Local [Meetup][meetup]
[![Love Angular badge](https://img.shields.io/badge/angular-love-blue?logo=angular&angular=love)](https://www.github.com/angular/angular)
**Love Angular? Give our repo a star :star: :arrow_up:.**
[contributing]: CONTRIBUTING.md
[contributing]: https://github.com/angular/angular/blob/master/CONTRIBUTING.md
[quickstart]: https://angular.io/start
[changelog]: CHANGELOG.md
[changelog]: https://github.com/angular/angular/blob/master/CHANGELOG.md
[ng]: https://angular.io
[documentation]: https://angular.io/docs
[angularmaterial]: https://material.angular.io/
[cli]: https://cli.angular.io/
[architecture]: https://angular.io/guide/architecture
[componentstemplates]: https://angular.io/guide/displaying-data
[forms]: https://angular.io/guide/forms-overview
[api]: https://angular.io/api
[angularelements]: https://angular.io/guide/elements
[ssr]: https://angular.io/guide/universal
[schematics]: https://angular.io/guide/schematics
[lazyloading]: https://angular.io/guide/lazy-loading-ngmodules
[node.js]: https://nodejs.org/
[npm]: https://www.npmjs.com/get-npm
[codeofconduct]: CODE_OF_CONDUCT.md
[twitter]: https://www.twitter.com/angular
[gitter]: https://gitter.im/angular/angular
[meetup]: https://www.meetup.com/find/?keywords=angular"

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 = "4952ef879704ab4ad6729a29007e7094aef213ea79e9f2e94cbe1c9a753e63ef",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/2.2.0/rules_nodejs-2.2.0.tar.gz"],
sha256 = "84abf7ac4234a70924628baa9a73a5a5cbad944c4358cf9abdb4aab29c9a5b77",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.7.0/rules_nodejs-1.7.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 = "2.2.0")
check_rules_nodejs_version(minimum_version_string = "1.7.0")
# Setup the Node.js toolchain
node_repositories(
@ -39,18 +39,23 @@ 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()
@ -63,6 +68,11 @@ 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")
@ -81,8 +91,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.5.1/configs/ubuntu16_04_clang/versions.bzl
base_container_digest = "sha256:f6568d8168b14aafd1b707019927a63c2d37113a03bcee188218f99bd0327ea1",
# https://github.com/bazelbuild/bazel-toolchains/blob/3.2.0/configs/ubuntu16_04_clang/versions.bzl
base_container_digest = "sha256:5e750dd878df9fcf4e185c6f52b9826090f6e532b097f286913a428290622332",
# 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

@ -6,7 +6,6 @@ Everything in this folder is part of the documentation project. This includes
* the dgeni configuration for converting source files to rendered files that can be viewed in the web site.
* the tooling for setting up examples for development; and generating live-example and zip files from the examples.
<a name="developer-tasks"></a>
## Developer tasks
We use [Yarn](https://yarnpkg.com) to manage the dependencies and to run build tasks.
@ -36,9 +35,8 @@ Here are the most important tasks you might need to use:
* `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally.
* `yarn boilerplate:add:viewengine` - same as `boilerplate:add` but also turns on `ViewEngine` (pre-Ivy) mode.
* `yarn boilerplate:remove` - remove all the boilerplate code that was added via `yarn boilerplate:add`.
* `yarn create-example` - create a new example directory containing initial source files.
* `yarn boilerplate:remove` - remove all the boilerplate code that was added via `yarn boilerplate:add`.
* `yarn generate-stackblitz` - generate the stackblitz files that are used by the `live-example` tags in the docs.
* `yarn generate-zips` - generate the zip files from the examples. Zip available via the `live-example` tags in the docs.

View File

@ -16,6 +16,13 @@ import {BuildNums, PrNums, SHA} from './constants';
const logger = new Logger('mock-external-apis');
const log = (...args: any[]) => {
// Filter out non-matching URL checks
if (!/^matching.+: false$/.test(args[0])) {
logger.log(...args);
}
};
const AIO_CIRCLE_CI_TOKEN = getEnvVar('AIO_CIRCLE_CI_TOKEN');
const AIO_GITHUB_TOKEN = getEnvVar('AIO_GITHUB_TOKEN');
@ -84,8 +91,8 @@ const createArchive = (buildNum: number, prNum: number, sha: string) => {
};
// Create request scopes
const circleCiApi = nock(CIRCLE_CI_API_HOST).persist();
const githubApi = nock(GITHUB_API_HOST).persist().matchHeader('Authorization', `token ${AIO_GITHUB_TOKEN}`);
const circleCiApi = nock(CIRCLE_CI_API_HOST).log(log).persist();
const githubApi = nock(GITHUB_API_HOST).log(log).persist().matchHeader('Authorization', `token ${AIO_GITHUB_TOKEN}`);
//////////////////////////////

View File

@ -27,28 +27,28 @@
"body-parser": "^1.19.0",
"delete-empty": "^3.0.0",
"express": "^4.17.1",
"jasmine": "^3.6.1",
"nock": "^13.0.4",
"node-fetch": "^2.6.1",
"jasmine": "^3.5.0",
"nock": "^12.0.3",
"node-fetch": "^2.6.0",
"shelljs": "^0.8.4",
"source-map-support": "^0.5.19",
"tar-stream": "^2.1.3",
"tslib": "^2.0.1"
"tar-stream": "^2.1.2",
"tslib": "^1.11.1"
},
"devDependencies": {
"@types/body-parser": "^1.19.0",
"@types/express": "^4.17.8",
"@types/jasmine": "^3.5.14",
"@types/express": "^4.17.6",
"@types/jasmine": "^3.5.10",
"@types/nock": "^11.1.0",
"@types/node": "^14.6.4",
"@types/node": "^13.13.2",
"@types/node-fetch": "^2.5.7",
"@types/shelljs": "^0.8.8",
"@types/supertest": "^2.0.10",
"nodemon": "^2.0.4",
"@types/shelljs": "^0.8.7",
"@types/supertest": "^2.0.8",
"nodemon": "^2.0.3",
"npm-run-all": "^4.1.5",
"supertest": "^4.0.2",
"tslint": "^6.1.3",
"tslint": "^6.1.1",
"tslint-jasmine-noSkipOrFocus": "^1.0.9",
"typescript": "^4.0.2"
"typescript": "^3.8.3"
}
}

View File

@ -214,24 +214,23 @@ describe('GithubApi', () => {
});
it('should call \'https.request()\' with the correct options', async () => {
it('should call \'https.request()\' with the correct options', () => {
const requestHandler = nock('https://api.github.com')
.intercept('/path', 'method')
.reply(200);
await (api as any).request('method', '/path');
(api as any).request('method', '/path');
requestHandler.done();
});
it('should add the \'Authorization\' header containing the \'githubToken\'', async () => {
it('should add the \'Authorization\' header containing the \'githubToken\'', () => {
const requestHandler = nock('https://api.github.com')
.intercept('/path', 'method', undefined, {
reqheaders: {Authorization: 'token 12345'},
})
.reply(200);
await (api as any).request('method', '/path');
(api as any).request('method', '/path');
requestHandler.done();
});
@ -245,13 +244,12 @@ describe('GithubApi', () => {
});
it('should \'JSON.stringify\' and send the data along with the request', async () => {
it('should \'JSON.stringify\' and send the data along with the request', () => {
const data = {key: 'value'};
const requestHandler = nock('https://api.github.com')
.intercept('/path', 'method', JSON.stringify(data))
.reply(200);
await (api as any).request('method', '/path', data);
(api as any).request('method', '/path', data);
requestHandler.done();
});

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@ you don't need to specify values for those.
The domain name of the server.
- `AIO_GITHUB_ORGANIZATION`:
The GitHub organization whose teams are trusted for accepting build artifacts.
The GitHub organization whose teams are whitelisted for accepting build artifacts.
See also `AIO_GITHUB_TEAM_SLUGS`.
- `AIO_GITHUB_REPO`:

View File

@ -98,7 +98,7 @@ This section describes how each of the aforementioned sub-tasks is accomplished:
Such a label can only have been added by a maintainer (with the necessary rights) and
designates that they have manually verified the PR contents.
2. We can verify (again using the GitHub API) the author's membership in one of the
trusted GitHub teams. For this operation, we need a Personal Access Token with the
whitelisted/trusted GitHub teams. For this operation, we need a Personal Access Token with the
`read:org` scope issued by a user that can "see" the specified GitHub organization.
Here too, we use the token by @mary-poppins.

View File

@ -58,7 +58,7 @@
}
],
"styles": [
"src/styles/main.scss"
"src/styles.scss"
],
"scripts": [],
"budgets": [
@ -158,7 +158,7 @@
}
],
"styles": [
"src/styles/main.scss"
"src/styles.scss"
],
"scripts": []
}
@ -193,4 +193,4 @@
}
},
"defaultProject": "site"
}
}

View File

@ -1,6 +1,6 @@
# CLI Overview and Command Reference
The Angular CLI is a command-line interface tool that you use to initialize, develop, scaffold, and maintain Angular applications directly from a command shell.
The Angular CLI is a command-line interface tool that you use to initialize, develop, scaffold, and maintain Angular applications. You can use the tool directly in a command shell, or indirectly through an interactive UI such as [Angular Console](https://angularconsole.com).
## Installing Angular CLI

View File

@ -17,9 +17,7 @@
**/e2e/tsconfig.e2e.json
**/src/karma.conf.js
**/.angular-cli.json
**/.browserslistrc
**/.editorconfig
**/.gitignore
**/angular.json
**/tsconfig.json
**/bs-config.e2e.json
@ -31,9 +29,8 @@
**/tslint.json
**/karma-test-shim.js
**/browser-test-shim.js
**/browserslist
**/node_modules
**/yarn.lock
**/package-lock.json
# built files
*.map

View File

@ -1,3 +1,5 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Accessibility example e2e tests', () => {
@ -6,11 +8,11 @@ describe('Accessibility example e2e tests', () => {
browser.get('');
});
it('should display Accessibility Example', () => {
it('should display Accessibility Example', function () {
expect(element(by.css('h1')).getText()).toEqual('Accessibility Example');
});
it('should take a number and change progressbar width', () => {
it('should take a number and change progressbar width', function () {
element(by.css('input')).sendKeys('16');
expect(element(by.css('input')).getAttribute('value')).toEqual('016');
expect(element(by.css('app-example-progressbar div')).getCssValue('width')).toBe('48px');

View File

@ -1,4 +1,3 @@
// tslint:disable: no-host-metadata-property
// #docregion progressbar-component
import { Component, Input } from '@angular/core';

View File

@ -1,18 +1,20 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('AngularJS to Angular Quick Reference Tests', () => {
describe('AngularJS to Angular Quick Reference Tests', function () {
beforeAll(() => {
beforeAll(function () {
browser.get('');
});
it('should display no poster images after bootstrap', () => {
it('should display no poster images after bootstrap', function () {
testImagesAreDisplayed(false);
});
it('should display proper movie data', () => {
it('should display proper movie data', function () {
// We check only a few samples
const expectedSamples: any[] = [
let expectedSamples: any[] = [
{row: 0, column: 0, element: 'img', attr: 'src', value: 'images/hero.png', contains: true},
{row: 0, column: 2, value: 'Celeritas'},
{row: 1, column: 3, matches: /Dec 1[678], 2015/}, // absorb timezone dif; we care about date format
@ -23,17 +25,18 @@ describe('AngularJS to Angular Quick Reference Tests', () => {
];
// Go through the samples
const movieRows = getMovieRows();
for (const sample of expectedSamples) {
const tableCell = movieRows.get(sample.row)
let movieRows = getMovieRows();
for (let i = 0; i < expectedSamples.length; i++) {
let sample = expectedSamples[i];
let tableCell = movieRows.get(sample.row)
.all(by.tagName('td')).get(sample.column);
// Check the cell or its nested element
const elementToCheck = sample.element
let elementToCheck = sample.element
? tableCell.element(by.tagName(sample.element))
: tableCell;
// Check element attribute or text
const valueToCheck = sample.attr
let valueToCheck = sample.attr
? elementToCheck.getAttribute(sample.attr)
: elementToCheck.getText();
@ -48,42 +51,42 @@ describe('AngularJS to Angular Quick Reference Tests', () => {
}
});
it('should display images after Show Poster', () => {
it('should display images after Show Poster', function () {
testPosterButtonClick('Show Poster', true);
});
it('should hide images after Hide Poster', () => {
it('should hide images after Hide Poster', function () {
testPosterButtonClick('Hide Poster', false);
});
it('should display no movie when no favorite hero is specified', () => {
it('should display no movie when no favorite hero is specified', function () {
testFavoriteHero(null, 'Please enter your favorite hero.');
});
it('should display no movie for Magneta', () => {
it('should display no movie for Magneta', function () {
testFavoriteHero('Magneta', 'No movie, sorry!');
});
it('should display a movie for Dr Nice', () => {
it('should display a movie for Dr Nice', function () {
testFavoriteHero('Dr Nice', 'Excellent choice!');
});
function testImagesAreDisplayed(isDisplayed: boolean) {
const expectedMovieCount = 3;
let expectedMovieCount = 3;
const movieRows = getMovieRows();
let movieRows = getMovieRows();
expect(movieRows.count()).toBe(expectedMovieCount);
for (let i = 0; i < expectedMovieCount; i++) {
const movieImage = movieRows.get(i).element(by.css('td > img'));
let movieImage = movieRows.get(i).element(by.css('td > img'));
expect(movieImage.isDisplayed()).toBe(isDisplayed);
}
}
function testPosterButtonClick(expectedButtonText: string, isDisplayed: boolean) {
const posterButton = element(by.css('app-movie-list tr > th > button'));
let posterButton = element(by.css('app-movie-list tr > th > button'));
expect(posterButton.getText()).toBe(expectedButtonText);
posterButton.click().then(() => {
posterButton.click().then(function () {
testImagesAreDisplayed(isDisplayed);
});
}
@ -93,12 +96,12 @@ describe('AngularJS to Angular Quick Reference Tests', () => {
}
function testFavoriteHero(heroName: string, expectedLabel: string) {
const movieListComp = element(by.tagName('app-movie-list'));
const heroInput = movieListComp.element(by.tagName('input'));
const favoriteHeroLabel = movieListComp.element(by.tagName('h3'));
const resultLabel = movieListComp.element(by.css('span > p'));
let movieListComp = element(by.tagName('app-movie-list'));
let heroInput = movieListComp.element(by.tagName('input'));
let favoriteHeroLabel = movieListComp.element(by.tagName('h3'));
let resultLabel = movieListComp.element(by.css('span > p'));
heroInput.clear().then(() => {
heroInput.clear().then(function () {
heroInput.sendKeys(heroName || '');
expect(resultLabel.getText()).toBe(expectedLabel);
if (heroName) {

View File

@ -1,6 +1,6 @@
// #docregion
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { Routes, RouterModule } from '@angular/router';
import { MovieListComponent } from './movie-list.component';

View File

@ -1,8 +1,8 @@
// #docregion
import { NgModule } from '@angular/core';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { AppComponent } from './app.component';
@NgModule({
imports: [ BrowserModule ],

View File

@ -1,9 +1,9 @@
// #docregion
import { NgModule } from '@angular/core';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { AppComponent } from './app.component';
import { MovieListComponent } from './movie-list.component';
import { AppRoutingModule } from './app-routing.module';

View File

@ -1,3 +1,5 @@
'use strict'; // necessary for es6 output in node
import { browser, ExpectedConditions as EC } from 'protractor';
import { logging } from 'selenium-webdriver';
import * as openClose from './open-close.po';

View File

@ -32,15 +32,15 @@ export const slideInAnimation =
// #enddocregion style-view
// #docregion query
query(':enter', [
style({ left: '-100%' })
style({ left: '-100%'})
]),
query(':leave', animateChild()),
group([
query(':leave', [
animate('300ms ease-out', style({ left: '100%' }))
animate('300ms ease-out', style({ left: '100%'}))
]),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
animate('300ms ease-out', style({ left: '0%'}))
])
]),
query(':enter', animateChild()),
@ -56,15 +56,15 @@ export const slideInAnimation =
})
]),
query(':enter', [
style({ left: '-100%' })
style({ left: '-100%'})
]),
query(':leave', animateChild()),
group([
query(':leave', [
animate('200ms ease-out', style({ left: '100%' }))
animate('200ms ease-out', style({ left: '100%'}))
]),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
animate('300ms ease-out', style({ left: '0%'}))
])
]),
query(':enter', animateChild()),

View File

@ -17,7 +17,7 @@ Toggle All Animations <input type="checkbox" [checked]="!animationsDisabled" (cl
</nav>
<!-- #docregion route-animations-outlet -->
<div [@routeAnimations]="prepareRoute(outlet)">
<div [@routeAnimations]="prepareRoute(outlet)" >
<router-outlet #outlet="outlet"></router-outlet>
</div>
<!-- #enddocregion route-animations-outlet -->

View File

@ -34,7 +34,7 @@ export class AppComponent {
// #docregion prepare-router-outlet
prepareRoute(outlet: RouterOutlet) {
return outlet && outlet.activatedRouteData && outlet.activatedRouteData.animation;
return outlet && outlet.activatedRouteData && outlet.activatedRouteData['animation'];
}
// #enddocregion prepare-router-outlet

View File

@ -1,6 +1,4 @@
// tslint:disable: variable-name
// #docplaster
// #docregion
import { Component, HostBinding, OnInit } from '@angular/core';
import { trigger, transition, animate, style, query, stagger } from '@angular/animations';
import { HEROES } from './mock-heroes';
@ -54,11 +52,13 @@ export class HeroListPageComponent implements OnInit {
@HostBinding('@pageAnimations')
public animatePage = true;
_heroes = [];
// #docregion filter-animations
heroTotal = -1;
// #enddocregion filter-animations
get heroes() { return this._heroes; }
private _heroes = [];
get heroes() {
return this._heroes;
}
ngOnInit() {
this._heroes = HEROES;

View File

@ -8,7 +8,8 @@ import { trigger, transition, state, animate, style, AnimationEvent } from '@ang
// #docregion trigger, trigger-wildcard1, trigger-transition
animations: [
trigger('openClose', [
// #docregion state1
// #enddocregion events1
// #docregion state1, events1
// ...
// #enddocregion events1
state('open', style({
@ -33,7 +34,8 @@ import { trigger, transition, state, animate, style, AnimationEvent } from '@ang
transition('closed => open', [
animate('0.5s')
]),
// #enddocregion transition2, trigger, component
// #enddocregion trigger, component
// #enddocregion transition2
// #docregion trigger-wildcard1
transition('* => closed', [
animate('1s')
@ -68,9 +70,7 @@ import { trigger, transition, state, animate, style, AnimationEvent } from '@ang
})
// #docregion events
export class OpenCloseComponent {
// #enddocregion events1, events, component
@Input() logging = false;
// #docregion component
// #enddocregion events1, events
isOpen = true;
toggle() {
@ -78,8 +78,9 @@ export class OpenCloseComponent {
}
// #enddocregion component
@Input() logging = false;
// #docregion events1, events
onAnimationEvent( event: AnimationEvent ) {
onAnimationEvent ( event: AnimationEvent ) {
// #enddocregion events1, events
if (!this.logging) {
return;

View File

@ -1,3 +1,5 @@
'use strict'; // necessary for es6 output in node
import { protractor, browser, element, by, ElementFinder } from 'protractor';
const nameSuffix = 'X';
@ -19,7 +21,7 @@ describe('Architecture', () => {
});
it(`has h2 '${expectedH2}'`, () => {
const h2 = element.all(by.css('h2')).map((elt: any) => elt.getText());
let h2 = element.all(by.css('h2')).map((elt: any) => elt.getText());
expect(h2).toEqual(expectedH2);
});
@ -32,42 +34,42 @@ function heroTests() {
const targetHero: Hero = { id: 2, name: 'Dr Nice' };
it('has the right number of heroes', () => {
const page = getPageElts();
let page = getPageElts();
expect(page.heroes.count()).toEqual(3);
});
it('has no hero details initially', () => {
const page = getPageElts();
it('has no hero details initially', function () {
let page = getPageElts();
expect(page.heroDetail.isPresent()).toBeFalsy('no hero detail');
});
it('shows selected hero details', async () => {
await element(by.cssContainingText('li', targetHero.name)).click();
const page = getPageElts();
const hero = await heroFromDetail(page.heroDetail);
let page = getPageElts();
let hero = await heroFromDetail(page.heroDetail);
expect(hero.id).toEqual(targetHero.id);
expect(hero.name).toEqual(targetHero.name);
});
it(`shows updated hero name in details`, async () => {
const input = element.all(by.css('input')).first();
let input = element.all(by.css('input')).first();
input.sendKeys(nameSuffix);
const page = getPageElts();
const hero = await heroFromDetail(page.heroDetail);
const newName = targetHero.name + nameSuffix;
let page = getPageElts();
let hero = await heroFromDetail(page.heroDetail);
let newName = targetHero.name + nameSuffix;
expect(hero.id).toEqual(targetHero.id);
expect(hero.name).toEqual(newName);
});
}
function salesTaxTests() {
it('has no sales tax initially', () => {
const page = getPageElts();
it('has no sales tax initially', function () {
let page = getPageElts();
expect(page.salesTaxDetail.isPresent()).toBeFalsy('no sales tax info');
});
it('shows sales tax', async () => {
const page = getPageElts();
it('shows sales tax', async function () {
let page = getPageElts();
page.salesTaxAmountInput.sendKeys('10', protractor.Key.ENTER);
expect(page.salesTaxDetail.getText()).toEqual('The sales tax is $1.00');
});
@ -86,11 +88,13 @@ function getPageElts() {
async function heroFromDetail(detail: ElementFinder): Promise<Hero> {
// Get hero id from the first <div>
const id = await detail.all(by.css('div')).first().getText();
// let _id = await detail.all(by.css('div')).first().getText();
let _id = await detail.all(by.css('div')).first().getText();
// Get name from the h2
const name = await detail.element(by.css('h4')).getText();
// let _name = await detail.element(by.css('h4')).getText();
let _name = await detail.element(by.css('h4')).getText();
return {
id: +id.substr(id.indexOf(' ') + 1),
name: name.substr(0, name.lastIndexOf(' ')),
id: +_id.substr(_id.indexOf(' ') + 1),
name: _name.substr(0, _name.lastIndexOf(' '))
};
}

View File

@ -1,15 +1,15 @@
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
// #docregion imports
import { NgModule } from '@angular/core';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
// #enddocregion imports
import { HeroDetailComponent } from './hero-detail.component';
import { HeroListComponent } from './hero-list.component';
import { SalesTaxComponent } from './sales-tax.component';
import { HeroService } from './hero.service';
import { BackendService } from './backend.service';
import { Logger } from './logger.service';
import { HeroListComponent } from './hero-list.component';
import { SalesTaxComponent } from './sales-tax.component';
import { HeroService } from './hero.service';
import { BackendService } from './backend.service';
import { Logger } from './logger.service';
@NgModule({
imports: [

View File

@ -18,7 +18,7 @@ export class BackendService {
// TODO: get from the database
return Promise.resolve<Hero[]>(HEROES);
}
const err = new Error('Cannot get object of this type');
let err = new Error('Cannot get object of this type');
this.logger.error(err);
throw err;
}

View File

@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { Hero } from './hero';
import { HeroService } from './hero.service';
import { Hero } from './hero';
import { HeroService } from './hero.service';
// #docregion metadata, providers
@Component({

View File

@ -22,7 +22,7 @@ export class AppComponent {
}
// #docregion module
import { NgModule } from '@angular/core';
import { NgModule } from '@angular/core';
// #docregion import-browser-module
import { BrowserModule } from '@angular/platform-browser';
// #enddocregion import-browser-module

View File

@ -1,7 +1,7 @@
import { Component } from '@angular/core';
import { Component } from '@angular/core';
import { SalesTaxService } from './sales-tax.service';
import { TaxRateService } from './tax-rate.service';
import { TaxRateService } from './tax-rate.service';
@Component({
selector: 'app-sales-tax',

View File

@ -7,7 +7,7 @@ export class SalesTaxService {
constructor(private rateService: TaxRateService) { }
getVAT(value: string | number) {
const amount = (typeof value === 'string') ?
let amount = (typeof value === 'string') ?
parseFloat(value) : value;
return (amount || 0) * this.rateService.getRate('VAT');
}

View File

@ -1,32 +1,34 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Attribute binding example', () => {
describe('Attribute binding example', function () {
beforeEach(() => {
beforeEach(function () {
browser.get('');
});
it('should display Property Binding with Angular', () => {
it('should display Property Binding with Angular', function () {
expect(element(by.css('h1')).getText()).toEqual('Attribute, class, and style bindings');
});
it('should display a table', () => {
it('should display a table', function() {
expect(element.all(by.css('table')).isPresent()).toBe(true);
});
it('should display an Aria button', () => {
it('should display an Aria button', function () {
expect(element.all(by.css('button')).get(0).getText()).toBe('Go for it with Aria');
});
it('should display a blue background on div', () => {
it('should display a blue background on div', function () {
expect(element.all(by.css('div')).get(1).getCssValue('background-color')).toEqual('rgba(25, 118, 210, 1)');
});
it('should display a blue div with a red border', () => {
it('should display a blue div with a red border', function () {
expect(element.all(by.css('div')).get(1).getCssValue('border')).toEqual('2px solid rgb(212, 30, 46)');
});
it('should display a div with many classes', () => {
it('should display a div with many classes', function () {
expect(element.all(by.css('div')).get(1).getAttribute('class')).toContain('special');
expect(element.all(by.css('div')).get(1).getAttribute('class')).toContain('clearance');
});

View File

@ -3,10 +3,8 @@
<h2>Attribute binding</h2>
<!-- #docregion attrib-binding-colspan -->
<table border=1>
<!-- #docregion colspan -->
<!-- expression calculates colspan=2 -->
<tr><td [attr.colspan]="1 + 1">One-Two</td></tr>
<!-- #enddocregion colspan -->
<!-- ERROR: There is no `colspan` property to set!
<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
@ -34,31 +32,31 @@
<!-- #docregion basic-specificity -->
<h3>Basic specificity</h3>
<!-- The `class.special` binding overrides any value for the `special` class in `classExpression`. -->
<div [class.special]="isSpecial" [class]="classExpression">Some text.</div>
<!-- The `class.special` binding will override any value for the `special` class in `classExpr`. -->
<div [class.special]="isSpecial" [class]="classExpr">Some text.</div>
<!-- The `style.color` binding overrides any value for the `color` property in `styleExpression`. -->
<div [style.color]="color" [style]="styleExpression">Some text.</div>
<!-- The `style.color` binding will override any value for the `color` property in `styleExpr`. -->
<div [style.color]="color" [style]="styleExpr">Some text.</div>
<!-- #enddocregion basic-specificity -->
<!-- #docregion source-specificity -->
<h3>Source specificity</h3>
<!-- The `class.special` template binding overrides any host binding to the `special` class set by `dirWithClassBinding` or `comp-with-host-binding`.-->
<!-- The `class.special` template binding will override any host binding to the `special` class set by `dirWithClassBinding` or `comp-with-host-binding`.-->
<comp-with-host-binding [class.special]="isSpecial" dirWithClassBinding>Some text.</comp-with-host-binding>
<!-- The `style.color` template binding overrides any host binding to the `color` property set by `dirWithStyleBinding` or `comp-with-host-binding`. -->
<!-- The `style.color` template binding will override any host binding to the `color` property set by `dirWithStyleBinding` or `comp-with-host-binding`. -->
<comp-with-host-binding [style.color]="color" dirWithStyleBinding>Some text.</comp-with-host-binding>
<!-- #enddocregion source-specificity -->
<!-- #docregion dynamic-priority -->
<h3>Dynamic vs static</h3>
<!-- If `classExpression` has a value for the `special` class, this value overrides the `class="special"` below -->
<div class="special" [class]="classExpression">Some text.</div>
<!-- If `classExpr` has a value for the `special` class, this value will override the `class="special"` below -->
<div class="special" [class]="classExpr">Some text.</div>
<!-- If `styleExpression` has a value for the `color` property, this value overrides the `style="color: blue"` below -->
<div style="color: blue" [style]="styleExpression">Some text.</div>
<!-- If `styleExpr` has a value for the `color` property, this value will override the `style="color: blue"` below -->
<div style="color: blue" [style]="styleExpr">Some text.</div>
<!-- #enddocregion dynamic-priority -->

View File

@ -9,7 +9,7 @@ export class AppComponent {
actionName = 'Go for it';
isSpecial = true;
canSave = true;
classExpression = 'special clearance';
styleExpression = 'color: red';
classExpr = 'special clearance';
styleExpr = 'color: red';
color = 'blue';
}

View File

@ -1,19 +1,16 @@
import { Component, HostBinding } from '@angular/core';
import { Component } from '@angular/core';
@Component({
selector: 'comp-with-host-binding',
template: 'I am a component!',
host: {
'[class.special]': 'isSpecial',
'[style.color]': 'color',
'[style.width]': 'width'
}
})
export class CompWithHostBindingComponent {
@HostBinding('class.special')
isSpecial = false;
@HostBinding('style.color')
color = 'green';
// #docregion hostbinding
@HostBinding('style.width')
width = '200px';
// #enddocregion hostbinding
}

View File

@ -1,15 +1,17 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Attribute directives', () => {
const title = 'My First Attribute Directive';
let _title = 'My First Attribute Directive';
beforeAll(() => {
browser.get('');
});
it(`should display correct title: ${title}`, () => {
expect(element(by.css('h1')).getText()).toEqual(title);
it(`should display correct title: ${_title}`, () => {
expect(element(by.css('h1')).getText()).toEqual(_title);
});
it('should be able to select green highlight', () => {

View File

@ -3,7 +3,7 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component.1';
import { AppComponent } from './app.component.1';
import { HighlightDirective as HLD1 } from './highlight.directive.1';
import { HighlightDirective as HLD2 } from './highlight.directive.2';
import { HighlightDirective as HLD3 } from './highlight.directive.3';

View File

@ -3,55 +3,57 @@ import { logging } from 'selenium-webdriver';
describe('Binding syntax e2e tests', () => {
beforeEach(() => browser.get(''));
beforeEach(function () {
browser.get('');
});
// helper function used to test what's logged to the console
async function logChecker(button, contents) {
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
const messages = logs.filter(({ message }) => message.indexOf(contents) !== -1 ? true : false);
expect(messages.length).toBeGreaterThan(0);
}
// helper function used to test what's logged to the console
async function logChecker(button, contents) {
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
const message = logs.filter(({ message }) => message.indexOf(contents) !== -1 ? true : false);
expect(message.length).toBeGreaterThan(0);
}
it('should display Binding syntax', () => {
it('should display Binding syntax', function () {
expect(element(by.css('h1')).getText()).toEqual('Binding syntax');
});
it('should display Save button', () => {
it('should display Save button', function () {
expect(element.all(by.css('button')).get(0).getText()).toBe('Save');
});
it('should display HTML attributes and DOM properties', () => {
it('should display HTML attributes and DOM properties', function () {
expect(element.all(by.css('h2')).get(1).getText()).toBe('HTML attributes and DOM properties');
});
it('should display 1. Use the inspector...', () => {
it('should display 1. Use the inspector...', function () {
expect(element.all(by.css('p')).get(0).getText()).toContain('1. Use the inspector');
});
it('should display Disabled property vs. attribute', () => {
it('should display Disabled property vs. attribute', function () {
expect(element.all(by.css('h3')).get(0).getText()).toBe('Disabled property vs. attribute');
});
it('should log a message including Sarah', async () => {
const attributeButton = element.all(by.css('button')).get(1);
let attributeButton = element.all(by.css('button')).get(1);
await attributeButton.click();
const contents = 'Sarah';
logChecker(attributeButton, contents);
});
it('should log a message including Sarah for DOM property', async () => {
const DOMPropertyButton = element.all(by.css('button')).get(2);
let DOMPropertyButton = element.all(by.css('button')).get(2);
await DOMPropertyButton.click();
const contents = 'Sarah';
logChecker(DOMPropertyButton, contents);
});
it('should log a message including Sally for DOM property', async () => {
const DOMPropertyButton = element.all(by.css('button')).get(2);
const input = element(by.css('input'));
let DOMPropertyButton = element.all(by.css('button')).get(2);
let input = element(by.css('input'));
input.sendKeys('Sally');
await DOMPropertyButton.click();
const contents = 'Sally';
@ -59,14 +61,14 @@ describe('Binding syntax e2e tests', () => {
});
it('should log a message that Test Button works', async () => {
const testButton = element.all(by.css('button')).get(3);
let testButton = element.all(by.css('button')).get(3);
await testButton.click();
const contents = 'Test';
logChecker(testButton, contents);
});
it('should toggle Test Button disabled', async () => {
const toggleButton = element.all(by.css('button')).get(4);
let toggleButton = element.all(by.css('button')).get(4);
await toggleButton.click();
const contents = 'true';
logChecker(toggleButton, contents);

View File

@ -26,7 +26,7 @@ export class AppComponent {
toggleDisabled(): any {
const testButton = document.getElementById('testButton') as HTMLInputElement;
let testButton = <HTMLInputElement> document.getElementById('testButton');
testButton.disabled = !testButton.disabled;
console.warn(testButton.disabled);
}

View File

@ -21,13 +21,11 @@ import { ItemDirective } from './item.directive';
ItemDirective
],
// #enddocregion declarations
// #docregion imports
imports: [
BrowserModule,
FormsModule,
HttpClientModule
],
// #enddocregion imports
providers: [],
bootstrap: [AppComponent]
})

View File

@ -1,19 +1,21 @@
'use strict';
import { browser, element, by } from 'protractor';
describe('Built-in Directives', () => {
describe('Built-in Directives', function () {
beforeAll(() => {
beforeAll(function () {
browser.get('');
});
it('should have title Built-in Directives', () => {
const title = element.all(by.css('h1')).get(0);
it('should have title Built-in Directives', function () {
let title = element.all(by.css('h1')).get(0);
expect(title.getText()).toEqual('Built-in Directives');
});
it('should change first Teapot header', async () => {
const firstLabel = element.all(by.css('p')).get(0);
const firstInput = element.all(by.css('input')).get(0);
let firstLabel = element.all(by.css('p')).get(0);
let firstInput = element.all(by.css('input')).get(0);
expect(firstLabel.getText()).toEqual('Current item name: Teapot');
firstInput.sendKeys('abc');
@ -21,49 +23,49 @@ describe('Built-in Directives', () => {
});
it('should modify sentence when modified checkbox checked', () => {
const modifiedChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(1);
const modifiedSentence = element.all(by.css('div')).get(1);
it('should modify sentence when modified checkbox checked', function () {
let modifiedChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(1);
let modifiedSentence = element.all(by.css('div')).get(1);
modifiedChkbxLabel.click();
expect(modifiedSentence.getText()).toContain('modified');
});
it('should modify sentence when normal checkbox checked', () => {
const normalChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(4);
const normalSentence = element.all(by.css('div')).get(7);
it('should modify sentence when normal checkbox checked', function () {
let normalChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(4);
let normalSentence = element.all(by.css('div')).get(7);
normalChkbxLabel.click();
expect(normalSentence.getText()).toContain('normal weight and, extra large');
});
it('should toggle app-item-detail', () => {
const toggleButton = element.all(by.css('button')).get(3);
const toggledDiv = element.all(by.css('app-item-detail')).get(0);
it('should toggle app-item-detail', function () {
let toggleButton = element.all(by.css('button')).get(3);
let toggledDiv = element.all(by.css('app-item-detail')).get(0);
toggleButton.click();
expect(toggledDiv.isDisplayed()).toBe(true);
});
it('should hide app-item-detail', () => {
const hiddenMessage = element.all(by.css('p')).get(11);
const hiddenDiv = element.all(by.css('app-item-detail')).get(2);
it('should hide app-item-detail', function () {
let hiddenMessage = element.all(by.css('p')).get(11);
let hiddenDiv = element.all(by.css('app-item-detail')).get(2);
expect(hiddenMessage.getText()).toContain('in the DOM');
expect(hiddenDiv.isDisplayed()).toBe(true);
});
it('should have 10 lists each containing the string Teapot', () => {
const listDiv = element.all(by.cssContainingText('.box', 'Teapot'));
it('should have 10 lists each containing the string Teapot', function () {
let listDiv = element.all(by.cssContainingText('.box', 'Teapot'));
expect(listDiv.count()).toBe(10);
});
it('should switch case', () => {
const tvRadioButton = element.all(by.css('input[type="radio"]')).get(3);
const tvDiv = element(by.css('app-lost-item'));
it('should switch case', function () {
let tvRadioButton = element.all(by.css('input[type="radio"]')).get(3);
let tvDiv = element(by.css('app-lost-item'));
const fishbowlRadioButton = element.all(by.css('input[type="radio"]')).get(4);
const fishbowlDiv = element(by.css('app-unknown-item'));
let fishbowlRadioButton = element.all(by.css('input[type="radio"]')).get(4);
let fishbowlDiv = element(by.css('app-unknown-item'));
tvRadioButton.click();
expect(tvDiv.getText()).toContain('Television');

View File

@ -30,14 +30,6 @@ export class AppComponent implements OnInit {
itemsWithTrackByCountReset = 0;
itemIdIncrement = 1;
// #docregion setClasses
currentClasses: {};
// #enddocregion setClasses
// #docregion setStyles
currentStyles: {};
// #enddocregion setStyles
ngOnInit() {
this.resetItems();
this.setCurrentClasses();
@ -49,18 +41,20 @@ export class AppComponent implements OnInit {
this.currentItem.name = name.toUpperCase();
}
// #docregion setClasses
// #docregion setClasses
currentClasses: {};
setCurrentClasses() {
// CSS classes: added/removed per current state of component properties
this.currentClasses = {
saveable: this.canSave,
modified: !this.isUnchanged,
special: this.isSpecial
'saveable': this.canSave,
'modified': !this.isUnchanged,
'special': this.isSpecial
};
}
// #enddocregion setClasses
// #docregion setStyles
currentStyles: {};
setCurrentStyles() {
// CSS styles: set per current state of component properties
this.currentStyles = {
@ -76,7 +70,11 @@ export class AppComponent implements OnInit {
}
giveNullCustomerValue() {
this.nullCustomer = 'Kelly';
!(this.nullCustomer = null) ? (this.nullCustomer = 'Kelly') : (this.nullCustomer = null);
}
resetNullItem() {
this.nullCustomer = null;
}
resetItems() {
@ -86,7 +84,7 @@ export class AppComponent implements OnInit {
}
resetList() {
this.resetItems();
this.resetItems()
this.itemsWithTrackByCountReset = 0;
this.itemsNoTrackByCount = ++this.itemsNoTrackByCount;
}
@ -109,7 +107,7 @@ export class AppComponent implements OnInit {
trackByItems(index: number, item: Item): number { return item.id; }
// #enddocregion trackByItems
trackById(index: number, item: any): number { return item.id; }
trackById(index: number, item: any): number { return item['id']; }
}

View File

@ -1,17 +1,19 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Built Template Functions Example', () => {
beforeAll(() => {
describe('Built Template Functions Example', function () {
beforeAll(function () {
browser.get('');
});
it('should have title Built-in Template Functions', () => {
const title = element.all(by.css('h1')).get(0);
it('should have title Built-in Template Functions', function () {
let title = element.all(by.css('h1')).get(0);
expect(title.getText()).toEqual('Built-in Template Functions');
});
it('should display $any( ) in h2', () => {
const header = element(by.css('h2'));
it('should display $any( ) in h2', function () {
let header = element(by.css('h2'));
expect(header.getText()).toContain('$any( )');
});

View File

@ -1,9 +0,0 @@
/*
* This example project is special in that it is not a cli app. To run tests appropriate for this
* project, the test command is overwritten in `aio/content/examples/observables/example-config.json`.
*
* This is an empty placeholder file to ensure that `aio/tools/examples/run-example-e2e.js` runs
* tests for this project.
*
* TODO: Fix our infrastructure/tooling, so that this hack is not necessary.
*/

View File

@ -1,12 +0,0 @@
{
"tests": [
{
"cmd": "yarn",
"args": ["tsc", "--project", "tsconfig.spec.json", "--module", "commonjs"]
},
{
"cmd": "yarn",
"args": ["jasmine", "out-tsc/**/*.spec.js"]
}
]
}

View File

@ -1,26 +0,0 @@
import { docRegionChain, docRegionObservable, docRegionUnsubscribe } from './observables';
describe('observables', () => {
it('should print 2', (doneFn: DoneFn) => {
const consoleLogSpy = spyOn(console, 'log');
const observable = docRegionObservable(console);
observable.subscribe(() => {
expect(consoleLogSpy).toHaveBeenCalledTimes(1);
expect(consoleLogSpy).toHaveBeenCalledWith(2);
doneFn();
});
});
it('should close the subscription', () => {
const subscription = docRegionUnsubscribe();
expect(subscription.closed).toBeTruthy();
});
it('should chain an observable', (doneFn: DoneFn) => {
const observable = docRegionChain();
observable.subscribe(value => {
expect(value).toBe(4);
doneFn();
});
});
});

View File

@ -1,72 +1,40 @@
// #docplaster
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
export function docRegionObservable(console: Console) {
// #docregion observable
// #docregion observable
// declare a publishing operation
const observable = new Observable<number>(observer => {
// Subscriber fn...
// #enddocregion observable
// The below code is used for unit testing only
observer.next(2);
// #docregion observable
});
// declare a publishing operation
const observable = new Observable<number>(observer => {
// Subscriber fn...
});
// initiate execution
observable.subscribe(value => {
// observer handles notifications
// #enddocregion observable
// The below code is used for unit testing only
console.log(value);
// #docregion observable
});
// initiate execution
observable.subscribe(() => {
// observer handles notifications
});
// #enddocregion observable
return observable;
}
// #enddocregion observable
export function docRegionUnsubscribe() {
const observable = new Observable<number>(() => {
// Subscriber fn...
});
// #docregion unsubscribe
// #docregion unsubscribe
const subscription = observable.subscribe(() => {
// observer handles notifications
});
const subscription = observable.subscribe(() => {
// observer handles notifications
});
subscription.unsubscribe();
subscription.unsubscribe();
// #enddocregion unsubscribe
return subscription;
}
// #enddocregion unsubscribe
export function docRegionError() {
const observable = new Observable<number>(() => {
// Subscriber fn...
});
// #docregion error
// #docregion error
observable.subscribe(() => {
throw new Error('my error');
});
// #enddocregion error
}
observable.subscribe(() => {
throw Error('my error');
});
export function docRegionChain() {
let observable = new Observable<number>(observer => {
// Subscriber fn...
observer.next(2);
});
// #enddocregion error
observable =
// #docregion chain
// #docregion chain
observable.pipe(map(v => 2 * v));
observable.pipe(map(v => 2 * v));
// #enddocregion chain
return observable;
}
// #enddocregion chain

View File

@ -1,23 +0,0 @@
import { docRegionError, docRegionPromise } from './promises';
describe('promises', () => {
it('should print 2', (doneFn: DoneFn) => {
const consoleLogSpy = spyOn(console, 'log');
const pr = docRegionPromise(console, 2);
pr.then((value) => {
expect(consoleLogSpy).toHaveBeenCalledTimes(1);
expect(consoleLogSpy).toHaveBeenCalledWith(2);
expect(value).toBe(4);
doneFn();
});
});
it('should throw an error', (doneFn: DoneFn) => {
const promise = docRegionError();
promise
.then(() => {
throw new Error('Promise should be rejected.');
},
() => doneFn());
});
});

View File

@ -1,44 +1,25 @@
// #docplaster
// #docregion promise
// initiate execution
const promise = new Promise<number>((resolve, reject) => {
// Executer fn...
});
export function docRegionPromise(console: Console, inputValue: number) {
// #docregion promise
// initiate execution
let promise = new Promise<number>((resolve, reject) => {
// Executer fn...
// #enddocregion promise
// The below is used in the unit tests.
resolve(inputValue);
// #docregion promise
});
// #enddocregion promise
promise =
// #docregion promise
promise.then(value => {
// handle result here
// #enddocregion promise
// The below is used in the unit tests.
console.log(value);
return value;
// #docregion promise
});
// #enddocregion promise
promise =
// #docregion chain
promise.then(v => 2 * v);
// #enddocregion chain
promise.then(value => {
// handle result here
});
return promise;
}
// #enddocregion promise
export function docRegionError() {
let promise = Promise.resolve();
promise =
// #docregion error
// #docregion chain
promise.then(() => {
throw new Error('my error');
});
promise.then(v => 2 * v);
// #enddocregion error
return promise;
}
// #enddocregion chain
// #docregion error
promise.then(() => {
throw Error('my error');
});
// #enddocregion error

View File

@ -1,236 +1,229 @@
import { browser, by, element } from 'protractor';
'use strict'; // necessary for es6 output in node
describe('Component Communication Cookbook Tests', () => {
import { browser, element, by } from 'protractor';
beforeEach(() => browser.get(browser.baseUrl));
describe('Component Communication Cookbook Tests', function () {
describe('Parent-to-child communication', () => {
// Note: '?e2e' which app can read to know it is running in protractor
// e.g. `if (!/e2e/.test(location.search)) { ...`
beforeAll(function () {
browser.get('?e2e');
});
describe('Parent-to-child communication', function() {
// #docregion parent-to-child
// ...
const heroNames = ['Dr IQ', 'Magneta', 'Bombasto'];
const masterName = 'Master';
let _heroNames = ['Dr IQ', 'Magneta', 'Bombasto'];
let _masterName = 'Master';
it('should pass properties to children properly', () => {
const parent = element(by.tagName('app-hero-parent'));
const heroes = parent.all(by.tagName('app-hero-child'));
it('should pass properties to children properly', function () {
let parent = element.all(by.tagName('app-hero-parent')).get(0);
let heroes = parent.all(by.tagName('app-hero-child'));
for (let i = 0; i < heroNames.length; i++) {
const childTitle = heroes.get(i).element(by.tagName('h3')).getText();
const childDetail = heroes.get(i).element(by.tagName('p')).getText();
expect(childTitle).toEqual(heroNames[i] + ' says:');
expect(childDetail).toContain(masterName);
for (let i = 0; i < _heroNames.length; i++) {
let childTitle = heroes.get(i).element(by.tagName('h3')).getText();
let childDetail = heroes.get(i).element(by.tagName('p')).getText();
expect(childTitle).toEqual(_heroNames[i] + ' says:');
expect(childDetail).toContain(_masterName);
}
});
// ...
// #enddocregion parent-to-child
});
describe('Parent-to-child communication with setter', () => {
describe('Parent-to-child communication with setter', function() {
// #docregion parent-to-child-setter
// ...
it('should display trimmed, non-empty names', () => {
const nonEmptyNameIndex = 0;
const nonEmptyName = '"Dr IQ"';
const parent = element(by.tagName('app-name-parent'));
const hero = parent.all(by.tagName('app-name-child')).get(nonEmptyNameIndex);
it('should display trimmed, non-empty names', function () {
let _nonEmptyNameIndex = 0;
let _nonEmptyName = '"Dr IQ"';
let parent = element.all(by.tagName('app-name-parent')).get(0);
let hero = parent.all(by.tagName('app-name-child')).get(_nonEmptyNameIndex);
const displayName = hero.element(by.tagName('h3')).getText();
expect(displayName).toEqual(nonEmptyName);
let displayName = hero.element(by.tagName('h3')).getText();
expect(displayName).toEqual(_nonEmptyName);
});
it('should replace empty name with default name', () => {
const emptyNameIndex = 1;
const defaultName = '"<no name set>"';
const parent = element(by.tagName('app-name-parent'));
const hero = parent.all(by.tagName('app-name-child')).get(emptyNameIndex);
it('should replace empty name with default name', function () {
let _emptyNameIndex = 1;
let _defaultName = '"<no name set>"';
let parent = element.all(by.tagName('app-name-parent')).get(0);
let hero = parent.all(by.tagName('app-name-child')).get(_emptyNameIndex);
const displayName = hero.element(by.tagName('h3')).getText();
expect(displayName).toEqual(defaultName);
let displayName = hero.element(by.tagName('h3')).getText();
expect(displayName).toEqual(_defaultName);
});
// ...
// #enddocregion parent-to-child-setter
});
describe('Parent-to-child communication with ngOnChanges', () => {
describe('Parent-to-child communication with ngOnChanges', function() {
// #docregion parent-to-child-onchanges
// ...
// Test must all execute in this exact order
it('should set expected initial values', () => {
const actual = getActual();
it('should set expected initial values', function () {
let actual = getActual();
const initialLabel = 'Version 1.23';
const initialLog = 'Initial value of major set to 1, Initial value of minor set to 23';
let initialLabel = 'Version 1.23';
let initialLog = 'Initial value of major set to 1, Initial value of minor set to 23';
expect(actual.label).toBe(initialLabel);
expect(actual.count).toBe(1);
expect(actual.logs.get(0).getText()).toBe(initialLog);
});
it('should set expected values after clicking \'Minor\' twice', async () => {
const repoTag = element(by.tagName('app-version-parent'));
const newMinorButton = repoTag.all(by.tagName('button')).get(0);
it('should set expected values after clicking \'Minor\' twice', function () {
let repoTag = element(by.tagName('app-version-parent'));
let newMinorButton = repoTag.all(by.tagName('button')).get(0);
await newMinorButton.click();
await newMinorButton.click();
newMinorButton.click().then(function() {
newMinorButton.click().then(function() {
let actual = getActual();
const actual = getActual();
let labelAfter2Minor = 'Version 1.25';
let logAfter2Minor = 'minor changed from 24 to 25';
const labelAfter2Minor = 'Version 1.25';
const logAfter2Minor = 'minor changed from 24 to 25';
expect(actual.label).toBe(labelAfter2Minor);
expect(actual.count).toBe(3);
expect(actual.logs.get(2).getText()).toBe(logAfter2Minor);
expect(actual.label).toBe(labelAfter2Minor);
expect(actual.count).toBe(3);
expect(actual.logs.get(2).getText()).toBe(logAfter2Minor);
});
});
});
it('should set expected values after clicking \'Major\' once', async () => {
const repoTag = element(by.tagName('app-version-parent'));
const newMajorButton = repoTag.all(by.tagName('button')).get(1);
it('should set expected values after clicking \'Major\' once', function () {
let repoTag = element(by.tagName('app-version-parent'));
let newMajorButton = repoTag.all(by.tagName('button')).get(1);
await newMajorButton.click();
const actual = getActual();
newMajorButton.click().then(function() {
let actual = getActual();
const labelAfterMajor = 'Version 2.0';
const logAfterMajor = 'major changed from 1 to 2, minor changed from 23 to 0';
let labelAfterMajor = 'Version 2.0';
let logAfterMajor = 'major changed from 1 to 2, minor changed from 25 to 0';
expect(actual.label).toBe(labelAfterMajor);
expect(actual.count).toBe(2);
expect(actual.logs.get(1).getText()).toBe(logAfterMajor);
expect(actual.label).toBe(labelAfterMajor);
expect(actual.count).toBe(4);
expect(actual.logs.get(3).getText()).toBe(logAfterMajor);
});
});
function getActual() {
const versionTag = element(by.tagName('app-version-child'));
const label = versionTag.element(by.tagName('h3')).getText();
const ul = versionTag.element((by.tagName('ul')));
const logs = ul.all(by.tagName('li'));
let versionTag = element(by.tagName('app-version-child'));
let label = versionTag.element(by.tagName('h3')).getText();
let ul = versionTag.element((by.tagName('ul')));
let logs = ul.all(by.tagName('li'));
return {
label,
logs,
label: label,
logs: logs,
count: logs.count()
};
}
// ...
// #enddocregion parent-to-child-onchanges
});
describe('Child-to-parent communication', () => {
describe('Child-to-parent communication', function() {
// #docregion child-to-parent
// ...
it('should not emit the event initially', () => {
const voteLabel = element(by.tagName('app-vote-taker')).element(by.tagName('h3'));
expect(voteLabel.getText()).toBe('Agree: 0, Disagree: 0');
it('should not emit the event initially', function () {
let voteLabel = element(by.tagName('app-vote-taker'))
.element(by.tagName('h3')).getText();
expect(voteLabel).toBe('Agree: 0, Disagree: 0');
});
it('should process Agree vote', async () => {
const voteLabel = element(by.tagName('app-vote-taker')).element(by.tagName('h3'));
const agreeButton1 = element.all(by.tagName('app-voter')).get(0)
it('should process Agree vote', function () {
let agreeButton1 = element.all(by.tagName('app-voter')).get(0)
.all(by.tagName('button')).get(0);
await agreeButton1.click();
expect(voteLabel.getText()).toBe('Agree: 1, Disagree: 0');
agreeButton1.click().then(function() {
let voteLabel = element(by.tagName('app-vote-taker'))
.element(by.tagName('h3')).getText();
expect(voteLabel).toBe('Agree: 1, Disagree: 0');
});
});
it('should process Disagree vote', async () => {
const voteLabel = element(by.tagName('app-vote-taker')).element(by.tagName('h3'));
const agreeButton1 = element.all(by.tagName('app-voter')).get(1)
it('should process Disagree vote', function () {
let agreeButton1 = element.all(by.tagName('app-voter')).get(1)
.all(by.tagName('button')).get(1);
await agreeButton1.click();
expect(voteLabel.getText()).toBe('Agree: 0, Disagree: 1');
agreeButton1.click().then(function() {
let voteLabel = element(by.tagName('app-vote-taker'))
.element(by.tagName('h3')).getText();
expect(voteLabel).toBe('Agree: 1, Disagree: 1');
});
});
// ...
// #enddocregion child-to-parent
});
describe('Parent calls child via local var', () => {
countDownTimerTests('app-countdown-parent-lv');
// Can't run timer tests in protractor because
// interaction w/ zones causes all tests to freeze & timeout.
xdescribe('Parent calls child via local var', function() {
countDownTimerTests('countdown-parent-lv');
});
describe('Parent calls ViewChild', () => {
countDownTimerTests('app-countdown-parent-vc');
xdescribe('Parent calls ViewChild', function() {
countDownTimerTests('countdown-parent-vc');
});
function countDownTimerTests(parentTag: string) {
// #docregion countdown-timer-tests
// ...
// The tests trigger periodic asynchronous operations (via `setInterval()`), which will prevent
// the app from stabilizing. See https://angular.io/api/core/ApplicationRef#is-stable-examples
// for more details.
// To allow the tests to complete, we will disable automatically waiting for the Angular app to
// stabilize.
beforeEach(() => browser.waitForAngularEnabled(false));
afterEach(() => browser.waitForAngularEnabled(true));
it('timer and parent seconds should match', async () => {
const parent = element(by.tagName(parentTag));
const startButton = parent.element(by.buttonText('Start'));
const seconds = parent.element(by.className('seconds'));
const timer = parent.element(by.tagName('app-countdown-timer'));
await startButton.click();
// Wait for `<app-countdown-timer>` to be populated with any text.
await browser.wait(() => timer.getText(), 2000);
expect(await timer.getText()).toContain(await seconds.getText());
it('timer and parent seconds should match', function () {
let parent = element(by.tagName(parentTag));
let message = parent.element(by.tagName('app-countdown-timer')).getText();
browser.sleep(10); // give `seconds` a chance to catchup with `message`
let seconds = parent.element(by.className('seconds')).getText();
expect(message).toContain(seconds);
});
it('should stop the countdown', async () => {
const parent = element(by.tagName(parentTag));
const startButton = parent.element(by.buttonText('Start'));
const stopButton = parent.element(by.buttonText('Stop'));
const timer = parent.element(by.tagName('app-countdown-timer'));
it('should stop the countdown', function () {
let parent = element(by.tagName(parentTag));
let stopButton = parent.all(by.tagName('button')).get(1);
await startButton.click();
expect(await timer.getText()).not.toContain('Holding');
await stopButton.click();
expect(await timer.getText()).toContain('Holding');
stopButton.click().then(function() {
let message = parent.element(by.tagName('app-countdown-timer')).getText();
expect(message).toContain('Holding');
});
});
// ...
// #enddocregion countdown-timer-tests
}
describe('Parent and children communicate via a service', () => {
describe('Parent and children communicate via a service', function() {
// #docregion bidirectional-service
// ...
it('should announce a mission', async () => {
const missionControl = element(by.tagName('app-mission-control'));
const announceButton = missionControl.all(by.tagName('button')).get(0);
const history = missionControl.all(by.tagName('li'));
await announceButton.click();
expect(history.count()).toBe(1);
expect(history.get(0).getText()).toMatch(/Mission.* announced/);
it('should announce a mission', function () {
let missionControl = element(by.tagName('app-mission-control'));
let announceButton = missionControl.all(by.tagName('button')).get(0);
announceButton.click().then(function () {
let history = missionControl.all(by.tagName('li'));
expect(history.count()).toBe(1);
expect(history.get(0).getText()).toMatch(/Mission.* announced/);
});
});
it('should confirm the mission by Lovell', async () => {
await testConfirmMission(1, 'Lovell');
it('should confirm the mission by Lovell', function () {
testConfirmMission(1, 2, 'Lovell');
});
it('should confirm the mission by Haise', async () => {
await testConfirmMission(3, 'Haise');
it('should confirm the mission by Haise', function () {
testConfirmMission(3, 3, 'Haise');
});
it('should confirm the mission by Swigert', async () => {
await testConfirmMission(2, 'Swigert');
it('should confirm the mission by Swigert', function () {
testConfirmMission(2, 4, 'Swigert');
});
async function testConfirmMission(buttonIndex: number, astronaut: string) {
const missionControl = element(by.tagName('app-mission-control'));
const announceButton = missionControl.all(by.tagName('button')).get(0);
const confirmButton = missionControl.all(by.tagName('button')).get(buttonIndex);
const history = missionControl.all(by.tagName('li'));
await announceButton.click();
await confirmButton.click();
expect(history.count()).toBe(2);
expect(history.get(1).getText()).toBe(`${astronaut} confirmed the mission`);
function testConfirmMission(buttonIndex: number, expectedLogCount: number, astronaut: string) {
let _confirmedLog = ' confirmed the mission';
let missionControl = element(by.tagName('app-mission-control'));
let confirmButton = missionControl.all(by.tagName('button')).get(buttonIndex);
confirmButton.click().then(function () {
let history = missionControl.all(by.tagName('li'));
expect(history.count()).toBe(expectedLogCount);
expect(history.get(expectedLogCount - 1).getText()).toBe(astronaut + _confirmedLog);
});
}
// ...
// #enddocregion bidirectional-service

View File

@ -0,0 +1,13 @@
{
"tests": [
{
"cmd": "yarn",
"args": [
"e2e",
"--protractor-config=e2e/protractor-puppeteer.conf.js",
"--no-webdriver-update",
"--port={PORT}"
]
}
]
}

View File

@ -30,21 +30,22 @@
<app-vote-taker></app-vote-taker>
</div>
<a href="#top" class="to-top">Back to Top</a>
<hr>
<div id="parent-to-child-local-var">
<app-countdown-parent-lv></app-countdown-parent-lv>
</div>
<a href="#top" class="to-top">Back to Top</a>
<hr>
<div id="parent-to-view-child">
<app-countdown-parent-vc></app-countdown-parent-vc>
</div>
<a href="#top" class="to-top">Back to Top</a>
<hr>
<div id="bidirectional-service">
<app-mission-control></app-mission-control>
</div>
<a href="#top" class="to-top">Back to Top</a>
<hr>

View File

@ -1,5 +1,5 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { AstronautComponent } from './astronaut.component';
@ -15,17 +15,10 @@ import { VersionParentComponent } from './version-parent.component';
import { VoterComponent } from './voter.component';
import { VoteTakerComponent } from './votetaker.component';
@NgModule({
imports: [
BrowserModule,
],
declarations: [
let directives: any[] = [
AppComponent,
AstronautComponent,
CountdownLocalVarParentComponent,
CountdownTimerComponent,
CountdownViewChildParentComponent,
HeroChildComponent,
HeroParentComponent,
MissionControlComponent,
@ -34,8 +27,28 @@ import { VoteTakerComponent } from './votetaker.component';
VersionChildComponent,
VersionParentComponent,
VoterComponent,
VoteTakerComponent,
VoteTakerComponent
];
let schemas: any[] = [];
// Include Countdown examples
// unless in e2e tests which they break.
if (!/e2e/.test(location.search)) {
console.log('adding countdown timer examples');
directives.push(CountdownLocalVarParentComponent);
directives.push(CountdownViewChildParentComponent);
} else {
// In e2e test use CUSTOM_ELEMENTS_SCHEMA to suppress unknown element errors
schemas.push(CUSTOM_ELEMENTS_SCHEMA);
}
@NgModule({
imports: [
BrowserModule
],
declarations: directives,
bootstrap: [ AppComponent ],
schemas: schemas
})
export class AppModule { }

View File

@ -2,7 +2,7 @@
import { Component, Input, OnDestroy } from '@angular/core';
import { MissionService } from './mission.service';
import { Subscription } from 'rxjs';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-astronaut',

View File

@ -2,8 +2,8 @@
// #docregion vc
import { AfterViewInit, ViewChild } from '@angular/core';
// #docregion lv
import { Component } from '@angular/core';
import { CountdownTimerComponent } from './countdown-timer.component';
import { Component } from '@angular/core';
import { CountdownTimerComponent } from './countdown-timer.component';
// #enddocregion lv
// #enddocregion vc

View File

@ -1,16 +1,19 @@
// #docregion
import { Component, OnDestroy } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
@Component({
selector: 'app-countdown-timer',
template: '<p>{{message}}</p>'
})
export class CountdownTimerComponent implements OnDestroy {
export class CountdownTimerComponent implements OnInit, OnDestroy {
intervalId = 0;
message = '';
seconds = 11;
clearTimer() { clearInterval(this.intervalId); }
ngOnInit() { this.start(); }
ngOnDestroy() { this.clearTimer(); }
start() { this.countDown(); }
@ -19,8 +22,6 @@ export class CountdownTimerComponent implements OnDestroy {
this.message = `Holding at T-${this.seconds} seconds`;
}
private clearTimer() { clearInterval(this.intervalId); }
private countDown() {
this.clearTimer();
this.intervalId = window.setInterval(() => {

View File

@ -12,6 +12,6 @@ import { Hero } from './hero';
})
export class HeroChildComponent {
@Input() hero: Hero;
@Input('master') masterName: string; // tslint:disable-line: no-input-rename
@Input('master') masterName: string;
}
// #enddocregion

View File

@ -1,6 +1,6 @@
// #docregion
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import { Subject } from 'rxjs';
@Injectable()
export class MissionService {

View File

@ -1,7 +1,7 @@
// #docregion
import { Component } from '@angular/core';
import { Component } from '@angular/core';
import { MissionService } from './mission.service';
import { MissionService } from './mission.service';
@Component({
selector: 'app-mission-control',
@ -34,7 +34,7 @@ export class MissionControlComponent {
}
announce() {
const mission = this.missions[this.nextMission++];
let mission = this.missions[this.nextMission++];
this.missionService.announceMission(mission);
this.history.push(`Mission "${mission}" announced`);
if (this.nextMission >= this.missions.length) { this.nextMission = 0; }

View File

@ -1,4 +1,3 @@
// tslint:disable: variable-name
// #docregion
import { Component, Input } from '@angular/core';
@ -7,11 +6,13 @@ import { Component, Input } from '@angular/core';
template: '<h3>"{{name}}"</h3>'
})
export class NameChildComponent {
private _name = '';
@Input()
get name(): string { return this._name; }
set name(name: string) {
this._name = (name && name.trim()) || '<no name set>';
}
private _name = '';
get name(): string { return this._name; }
}
// #enddocregion

View File

@ -18,14 +18,14 @@ export class VersionChildComponent implements OnChanges {
changeLog: string[] = [];
ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
const log: string[] = [];
for (const propName in changes) {
const changedProp = changes[propName];
const to = JSON.stringify(changedProp.currentValue);
let log: string[] = [];
for (let propName in changes) {
let changedProp = changes[propName];
let to = JSON.stringify(changedProp.currentValue);
if (changedProp.isFirstChange()) {
log.push(`Initial value of ${propName} set to ${to}`);
} else {
const from = JSON.stringify(changedProp.previousValue);
let from = JSON.stringify(changedProp.previousValue);
log.push(`${propName} changed from ${from} to ${to}`);
}
}

View File

@ -1,5 +1,5 @@
// #docregion
import { Component } from '@angular/core';
import { Component } from '@angular/core';
@Component({
selector: 'app-vote-taker',

View File

@ -1,14 +1,16 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Component Style Tests', () => {
describe('Component Style Tests', function () {
beforeAll(() => {
beforeAll(function () {
browser.get('');
});
it('scopes component styles to component view', () => {
const componentH1 = element(by.css('app-root > h1'));
const externalH1 = element(by.css('body > h1'));
it('scopes component styles to component view', function() {
let componentH1 = element(by.css('app-root > h1'));
let externalH1 = element(by.css('body > h1'));
// Note: sometimes webdriver returns the fontWeight as "normal",
// other times as "400", both of which are equal in CSS terms.
@ -17,49 +19,49 @@ describe('Component Style Tests', () => {
});
it('allows styling :host element', () => {
const host = element(by.css('app-hero-details'));
it('allows styling :host element', function() {
let host = element(by.css('app-hero-details'));
expect(host.getCssValue('borderWidth')).toEqual('1px');
});
it('supports :host() in function form', () => {
const host = element(by.css('app-hero-details'));
it('supports :host() in function form', function() {
let host = element(by.css('app-hero-details'));
host.element(by.buttonText('Activate')).click();
expect(host.getCssValue('borderWidth')).toEqual('3px');
});
it('allows conditional :host-context() styling', () => {
const h2 = element(by.css('app-hero-details h2'));
it('allows conditional :host-context() styling', function() {
let h2 = element(by.css('app-hero-details h2'));
expect(h2.getCssValue('backgroundColor')).toEqual('rgba(238, 238, 255, 1)'); // #eeeeff
});
it('styles both view and content children with /deep/', () => {
const viewH3 = element(by.css('app-hero-team h3'));
const contentH3 = element(by.css('app-hero-controls h3'));
it('styles both view and content children with /deep/', function() {
let viewH3 = element(by.css('app-hero-team h3'));
let contentH3 = element(by.css('app-hero-controls h3'));
expect(viewH3.getCssValue('fontStyle')).toEqual('italic');
expect(contentH3.getCssValue('fontStyle')).toEqual('italic');
});
it('includes styles loaded with CSS @import', () => {
const host = element(by.css('app-hero-details'));
it('includes styles loaded with CSS @import', function() {
let host = element(by.css('app-hero-details'));
expect(host.getCssValue('padding')).toEqual('10px');
});
it('processes template inline styles', () => {
const button = element(by.css('app-hero-controls button'));
const externalButton = element(by.css('body > button'));
it('processes template inline styles', function() {
let button = element(by.css('app-hero-controls button'));
let externalButton = element(by.css('body > button'));
expect(button.getCssValue('backgroundColor')).toEqual('rgba(255, 255, 255, 1)'); // #ffffff
expect(externalButton.getCssValue('backgroundColor')).not.toEqual('rgba(255, 255, 255, 1)');
});
it('processes template <link>s', () => {
const li = element(by.css('app-hero-team li:first-child'));
const externalLi = element(by.css('body > ul li'));
it('processes template <link>s', function() {
let li = element(by.css('app-hero-team li:first-child'));
let externalLi = element(by.css('body > ul li'));
expect(li.getCssValue('listStyleType')).toEqual('square');
expect(externalLi.getCssValue('listStyleType')).not.toEqual('square');

View File

@ -13,8 +13,8 @@ import { Component, ViewEncapsulation } from '@angular/core';
export class QuestSummaryComponent { }
// #enddocregion
/*
// #docregion encapsulation.shadow
// #docregion encapsulation.native
// warning: few browsers support shadow DOM encapsulation at this time
encapsulation: ViewEncapsulation.ShadowDom
// #enddocregion encapsulation.shadow
encapsulation: ViewEncapsulation.Native
// #enddocregion encapsulation.native
*/

View File

@ -1,74 +1,76 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Dependency Injection Cookbook', () => {
describe('Dependency Injection Cookbook', function () {
beforeAll(() => {
beforeAll(function () {
browser.get('');
});
it('should render Logged in User example', () => {
const loggedInUser = element.all(by.xpath('//h3[text()="Logged in user"]')).get(0);
it('should render Logged in User example', function () {
let loggedInUser = element.all(by.xpath('//h3[text()="Logged in user"]')).get(0);
expect(loggedInUser).toBeDefined();
});
it('"Bombasto" should be the logged in user', () => {
const loggedInUser = element.all(by.xpath('//div[text()="Name: Bombasto"]')).get(0);
it('"Bombasto" should be the logged in user', function () {
let loggedInUser = element.all(by.xpath('//div[text()="Name: Bombasto"]')).get(0);
expect(loggedInUser).toBeDefined();
});
it('should render sorted heroes', () => {
const sortedHeroes = element.all(by.xpath('//h3[text()="Sorted Heroes" and position()=1]')).get(0);
it('should render sorted heroes', function () {
let sortedHeroes = element.all(by.xpath('//h3[text()="Sorted Heroes" and position()=1]')).get(0);
expect(sortedHeroes).toBeDefined();
});
it('Dr Nice should be in sorted heroes', () => {
const sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Dr Nice" and position()=2]')).get(0);
it('Dr Nice should be in sorted heroes', function () {
let sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Dr Nice" and position()=2]')).get(0);
expect(sortedHero).toBeDefined();
});
it('RubberMan should be in sorted heroes', () => {
const sortedHero = element.all(by.xpath('//sorted-heroes/[text()="RubberMan" and position()=3]')).get(0);
it('RubberMan should be in sorted heroes', function () {
let sortedHero = element.all(by.xpath('//sorted-heroes/[text()="RubberMan" and position()=3]')).get(0);
expect(sortedHero).toBeDefined();
});
it('Magma should be in sorted heroes', () => {
const sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Magma"]')).get(0);
it('Magma should be in sorted heroes', function () {
let sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Magma"]')).get(0);
expect(sortedHero).toBeDefined();
});
it('should render Hero of the Month', () => {
const heroOfTheMonth = element.all(by.xpath('//h3[text()="Hero of the month"]')).get(0);
it('should render Hero of the Month', function () {
let heroOfTheMonth = element.all(by.xpath('//h3[text()="Hero of the month"]')).get(0);
expect(heroOfTheMonth).toBeDefined();
});
it('should render Hero Bios', () => {
const heroBios = element.all(by.xpath('//h3[text()="Hero Bios"]')).get(0);
it('should render Hero Bios', function () {
let heroBios = element.all(by.xpath('//h3[text()="Hero Bios"]')).get(0);
expect(heroBios).toBeDefined();
});
it('should render Magma\'s description in Hero Bios', () => {
const magmaText = element.all(by.xpath('//textarea[text()="Hero of all trades"]')).get(0);
it('should render Magma\'s description in Hero Bios', function () {
let magmaText = element.all(by.xpath('//textarea[text()="Hero of all trades"]')).get(0);
expect(magmaText).toBeDefined();
});
it('should render Magma\'s phone in Hero Bios and Contacts', () => {
const magmaPhone = element.all(by.xpath('//div[text()="Phone #: 555-555-5555"]')).get(0);
it('should render Magma\'s phone in Hero Bios and Contacts', function () {
let magmaPhone = element.all(by.xpath('//div[text()="Phone #: 555-555-5555"]')).get(0);
expect(magmaPhone).toBeDefined();
});
it('should render Hero-of-the-Month runner-ups', () => {
const runnersUp = element(by.id('rups1')).getText();
it('should render Hero-of-the-Month runner-ups', function () {
let runnersUp = element(by.id('rups1')).getText();
expect(runnersUp).toContain('RubberMan, Dr Nice');
});
it('should render DateLogger log entry in Hero-of-the-Month', () => {
const logs = element.all(by.id('logs')).get(0).getText();
it('should render DateLogger log entry in Hero-of-the-Month', function () {
let logs = element.all(by.id('logs')).get(0).getText();
expect(logs).toContain('INFO: starting up at');
});
it('should highlight Hero Bios and Contacts container when mouseover', () => {
const target = element(by.css('div[appHighlight="yellow"]'));
const yellow = 'rgba(255, 255, 0, 1)';
it('should highlight Hero Bios and Contacts container when mouseover', function () {
let target = element(by.css('div[appHighlight="yellow"]'));
let yellow = 'rgba(255, 255, 0, 1)';
expect(target.getCssValue('background-color')).not.toEqual(yellow);
@ -79,25 +81,25 @@ describe('Dependency Injection Cookbook', () => {
browser.wait(() => target.getCssValue('background-color').then(c => c === yellow), 2000);
});
describe('in Parent Finder', () => {
const cathy1 = element(by.css('alex cathy'));
const craig1 = element(by.css('alex craig'));
const carol1 = element(by.css('alex carol p'));
const carol2 = element(by.css('barry carol p'));
describe('in Parent Finder', function () {
let cathy1 = element(by.css('alex cathy'));
let craig1 = element(by.css('alex craig'));
let carol1 = element(by.css('alex carol p'));
let carol2 = element(by.css('barry carol p'));
it('"Cathy" should find "Alex" via the component class', () => {
it('"Cathy" should find "Alex" via the component class', function () {
expect(cathy1.getText()).toContain('Found Alex via the component');
});
it('"Craig" should not find "Alex" via the base class', () => {
it('"Craig" should not find "Alex" via the base class', function () {
expect(craig1.getText()).toContain('Did not find Alex via the base');
});
it('"Carol" within "Alex" should have "Alex" parent', () => {
it('"Carol" within "Alex" should have "Alex" parent', function () {
expect(carol1.getText()).toContain('Alex');
});
it('"Carol" within "Barry" should have "Barry" parent', () => {
it('"Carol" within "Barry" should have "Barry" parent', function () {
expect(carol2.getText()).toContain('Barry');
});
});

View File

@ -1,5 +1,5 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [];

View File

@ -2,9 +2,9 @@
import { Component } from '@angular/core';
// #docregion import-services
import { LoggerService } from './logger.service';
import { LoggerService } from './logger.service';
import { UserContextService } from './user-context.service';
import { UserService } from './user.service';
import { UserService } from './user.service';
@Component({
selector: 'app-root',

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