Compare commits

...

94 Commits
9.0.2 ... 8.1.2

Author SHA1 Message Date
ca77d1ca90 release: cut the v8.1.2 release 2019-07-17 12:03:22 -07:00
e1cfa419d3 docs(core): fix typo in event-binding code example (#31611)
`item` is an object, so it is stringified to `[object Object]`. Using
its `name` property produces a more meaningful message.

PR Close #31611
2019-07-17 13:26:48 -04:00
00db95e77c docs: fix typo in CLI overview (#31608)
PR Close #31608
2019-07-17 13:26:31 -04:00
f025fe6c2f docs: remove prerequisite section in NgModules docs (#31169)
PR Close #31169
2019-07-17 13:26:00 -04:00
51b58c1561 docs: clarify docs for runtime validation change (#31596)
PR Close #31596
2019-07-16 23:58:11 -04:00
cf460d8530 docs: clarify meaning of injectable decorator (#31573)
PR Close #31573
2019-07-16 23:57:50 -04:00
6692c5dd1c docs: add note about current working directory for cli projects (#31507)
Fixes #29878

PR Close #31507
2019-07-16 13:02:57 -04:00
177cf26e41 build(docs-infra): never show linenums for triple-backticked code blocks (#31493)
PR Close #31493
2019-07-16 13:00:55 -04:00
9ac9c84d5b docs(core): Remove repeated example (#31555)
PR Close #31555
2019-07-16 13:00:26 -04:00
13dbb98a14 fix(compiler-cli): Return original sourceFile instead of redirected sourceFile from getSourceFile (#26036)
Closes #22524

PR Close #26036
2019-07-15 17:33:40 -04:00
78a8098080 docs: include svg files in stackblitz and download examples (#31559)
Fixes #31537

PR Close #31559
2019-07-15 16:48:24 -04:00
781cbf8789 docs: fix typo in static query migration guide (#31572)
PR Close #31572
2019-07-15 16:46:33 -04:00
9ac7048ba5 docs: add FAQ about updating libraries to static query migration guide (#31447)
PR Close #31447
2019-07-15 13:57:43 -04:00
7c7774ff20 docs: remove and update resource list (#31469)
PR Close #31469
2019-07-15 12:23:34 -04:00
03818484ff style(docs-infra): fix indentation in rx-library example (#31553)
PR Close #31553
2019-07-15 12:13:20 -04:00
2ed8127455 docs: add microsyntax details (#31517)
PR Close #31517
2019-07-12 17:55:57 -04:00
6737a8d7a1 build(docs-infra): display CLI positional option enum values (#31529)
Previously we on;ly displayed enum values for named options.
Now positional options get equal justice.

Fixes https://github.com/angular/angular-cli/issues/15040

PR Close #31529
2019-07-12 17:55:28 -04:00
0986595543 fix(docs-infra): fix API list search color and styles (#31272)
- Add more spacing to inputs.
- Correct placeholder colors in inputs.
- Add aria label to input for accessibility.
- Clean up layout styles and mobile view.

Fixes #31265

PR Close #31272
2019-07-12 17:55:02 -04:00
fa69e99bd5 build: add tsconfig-test to dependency for tsconfig in core/test/strict_types (#31471)
PR Close #31471
2019-07-12 11:38:17 -04:00
4c57d8a276 build: export tsconfig-test.json file in //tools/BUILD (#31471)
PR Close #31471
2019-07-12 11:38:17 -04:00
ea2b17ef46 build: use standalone strategy for TypescriptCompile and AngularTemplateCompile (#31471)
PR Close #31471
2019-07-12 11:38:17 -04:00
5e19fb9a09 build: Add incompatible_list_based_execution_strategy_selection flags back in (#31471)
PR Close #31471
2019-07-12 11:38:17 -04:00
a2f69bd371 build: use remote actions for TS/NG compilations on CircleCI (#31471)
PR Close #31471
2019-07-12 11:38:17 -04:00
58260fc4ab build: remove redundant @types/source-map dependency (#31468)
In version 0.6.1 that we are using, `source-map` ships with
[its own typings][1], so there is no need to use `@types/source-map`.
The types were even removed from `DefinitelyTyped` in
DefinitelyTyped/DefinitelyTyped@1792bfaa2.

[1]: https://github.com/mozilla/source-map/blob/0.6.1/package.json#L72

PR Close #31468
2019-07-11 17:18:12 -04:00
bd23dbb330 build(compiler-cli): remove unused dependency (shelljs) (#31468)
Since, 7186f9c01 `compiler-cli` is no longer depending on `shelljs` for
production code. (We still use it in tests and infrastructure/tooling.)

Incidentally, this should also help with #29460.

PR Close #31468
2019-07-11 17:18:12 -04:00
3ade93f6f9 ci(docs-infra): run a11y audits on certain pages on CI (#31414)
PR Close #31414
2019-07-11 17:13:47 -04:00
745ea1735a feat(docs-infra): support checking the scores on all audit categories (#31414)
Previously, the `test-pwa-score` script would only check the `pwa`
score. (All categories were reported, but a min. score could only be
specified for `pwa`.)

This commit adds support for checking the scores on all available
categories (such as a11y, performance, seo, etc.).

PR Close #31414
2019-07-11 17:13:47 -04:00
20c5a56be5 refactor(docs-infra): slightly improve log output of test-pwa-score (#31414)
This commit slightly improves the log outout of the `test-pwa-score`
script (e.g. by showing the total duration, indenting messages to group
them together, etc.). It, also, includes various minor refactorings.

These changes are in preparation of augmenting the script to support
checking the scores on all available categories (such as a11y,
performance, seo, etc.) in a subsequent commit.

PR Close #31414
2019-07-11 17:13:47 -04:00
d2d629ca94 refactor(docs-infra): switch test-pwa-score to use headless Chrome (#31414)
This is slightly faster (15%-20%). Currently, this doesn't make a
noticeable difference, since the total time is 10s-15s, but it might
add up, if we decide to run audits on multiple pages.

PR Close #31414
2019-07-11 17:13:47 -04:00
cb3bbab838 build(docs-infra): upgrade lighthouse to 5.1.0 (#31414)
PR Close #31414
2019-07-11 17:13:47 -04:00
4aed480c62 fix: use the correct WTF array to iterate over (#31208)
PR Close #31208
2019-07-11 15:08:55 -04:00
ddb210c567 docs: remove heroes reference in i18n example (#31515)
Closes #31514

PR Close #31515
2019-07-11 15:07:55 -04:00
d43e6e93a2 feat(docs-infra): add prominent archive mode banner styling (#31245)
Fixes #25968

PR Close #31245
2019-07-11 13:00:12 -04:00
5fc0c3d448 fix(docs-infra): fix code hover style in TOC (#31173)
Fixes #31170

PR Close #31173
2019-07-11 12:57:33 -04:00
af418b33e7 fix(docs-infra): fix get started button rendering (#31470)
Fixes #31454

PR Close #31470
2019-07-11 12:56:30 -04:00
96f2d7852b fix(docs-infra): fix layout of file-not-found page (#31390)
The `.sidenav-content` element, [which is also][1] the `#file-not-found`
element, [already has][2] the necessary padding. Especially the top
padding is important to ensure the element is not obscured by the
top-bar.

[1]: https://github.com/angular/angular/blob/1d3e22766/aio/src/app/app.component.html#L51
[2]: https://github.com/angular/angular/blob/1d3e22766/aio/src/styles/1-layouts/_content-layout.scss#L10

PR Close #31390
2019-07-11 12:15:34 -04:00
a48907bc8b test(docs-infra): clean up global listeners after ScrollService tests (#31390)
The `ScrollService` sets up some global `window` listeners.

Previously, these listeners were never unregistered. This was not a
problem in the real app, because the `ScrollService` instance exists for
the lifetime of a user session. In tests, however, where the `window`
instance is among all tests, the listeners would survive the
`ScrollService` tests. This, in addition to the fact that we used a mock
`ViewportScroller` which did not return the expected type from
`getScrollPosition()`, caused errors to be thrown in unrelated tests
(i.e. whenever a scroll event was emitted on `window`). See [here][1]
for an example failure.

This commit fixes it by adding an `ngOnDestroy()` method that
unregisters the listeners and ensuring it is called after each
`ScrollService` test.

[1]: https://circleci.com/gh/angular/angular/381649

PR Close #31390
2019-07-11 12:15:34 -04:00
fa2773dea8 fix(docs-infra): show (and style correctly) the 'No results found' message (#31390)
PR Close #31390
2019-07-11 12:15:34 -04:00
fc9e6517f6 fix(docs-infra): improve search-results layout on smaller screens (#31390)
Previously, the `search-results` layout was switch from horizontal to
vertical at 480px. Yes, since some search queries can yield more than 5
`.search-area`s, even 600px are too narrow to accomodate a horizontal
layout.

This commit changes the breakpoint at which the layout switches to
vertical from 480px to 600px.

PR Close #31390
2019-07-11 12:15:34 -04:00
049050b189 fix(docs-infra): remove redundant search-results styles (#31390)
Previously, `.search-area` had a default style of `display: flex`, but
it was overriden to `display: block` in media queries for
`max-width: 480px` and `min-width: 600px`. As a result, it only had
`display: flex` between 481px and 599px.

Since no flex layout features are necessary inside `.search-area`, this
commit changes the style to always be `display: block` (i.e. the default
for `div` elements).

PR Close #31390
2019-07-11 12:15:34 -04:00
e5d545a9f5 refactor(docs-infra): clean up aio-search-results styles (#31390)
PR Close #31390
2019-07-11 12:15:34 -04:00
705670b174 style(docs-infra): make indentation in _search-results.scss consistent with other .scss files (#31390)
PR Close #31390
2019-07-11 12:15:34 -04:00
468205e216 build(docs-infra): engine "yarn" versions can now be up to 1.16.0 (#31482)
PR Close #31482
2019-07-11 12:14:33 -04:00
b591035e40 docs: add angular-in-depth to community curations (#31212)
PR Close #31212
2019-07-11 11:43:34 -04:00
0521d0b25f docs: fix typo in Template Syntax headers (#31474)
Fixes #31467

PR Close #31474
2019-07-11 11:40:40 -04:00
a395cb1a5a docs: add Renderer to deprecations doc (#31419)
PR Close #31419
2019-07-11 01:36:31 -04:00
61cba261da release: cut the v8.1.1 release 2019-07-10 10:25:38 -07:00
1863254e0f ci: install Bazel MSYS2 packages on Windows (#31486)
PR Close #31486
2019-07-10 10:23:39 -07:00
067d9015c8 build: remove usage of deprecated experimental_ui bazel flag (#31457)
PR Close #31457
2019-07-09 13:50:02 -07:00
635d23360a refactor(bazel): remove unused lockfile (#31458)
The corresponding `package.json` file was removed in 15c2467db; it looks
like the lockfile was left behind by accident.

PR Close #31458
2019-07-09 13:49:43 -07:00
24fd1a18aa fix(ivy): handle namespaced imports correctly (#31367)
The ngcc tool adds namespaced imports to files when compiling. The ngtsc
tooling was not processing types correctly when they were imported via
such namespaces. For example:

```
export declare class SomeModule {
    static withOptions(...): ModuleWithProviders<ɵngcc1.BaseModule>;
```

In this case the `BaseModule` was being incorrectly attributed to coming
from the current module rather than the imported module, represented by
`ɵngcc1`.

Fixes #31342

PR Close #31367
2019-07-09 09:40:30 -07:00
a3fc1477ba ci(docs-infra): increase waiting time to reduce flakiness on CI (#31408)
Example failure: https://circleci.com/gh/angular/angular/381763

PR Close #31408
2019-07-09 09:35:54 -07:00
bdfbb9211f fix(zone.js): restore definition of global (#31453)
This partially reverts some changes from 71b9371180 (diff-dd469785fca8680a5b33b1e81c5cfd91R1420)
These broke the g3sync of zone.js because we use the output of the TypeScript compiler directly, rather than rely on the rollup commonjs plugin to define the global symbol

PR Close #31453
2019-07-09 09:34:50 -07:00
4bda800037 docs: add correct default cli ngModule (#31166)
PR Close #31166
2019-07-08 10:25:58 -07:00
06cbaf89c2 docs: update polyfill support doc (#31262)
PR Close #31262
2019-07-08 10:22:01 -07:00
0e53e8ffda docs: api doc cleanup (#31377)
PR Close #31377
2019-07-08 09:51:59 -07:00
bebf089046 fix(core): export provider interfaces that are part of the public API types (#31377)
Some of the provider interfaces that the [Provider][1] and
[StaticProvider][2] types comprise were not exported from
[@angular/core][3]. As a result, the docs for these symbols did not
appear on angular.io (even though both `Provider` and `StaticProvider`
are part of the public API. (See, also,
https://github.com/angular/angular/pull/31377#discussion_r299254408.)

This commit fixes it by exporting all necessary provider interfaces.

[1]: https://github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L365-L366
[2]: https://github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L283-L284
[3]: https://github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts#L23

PR Close #31377
2019-07-08 09:51:59 -07:00
7b0a28786f docs: fix formatting in workspace config and add helpful info for universal (#31399)
PR Close #31399
2019-07-08 09:38:25 -07:00
dcf9c13fc8 ci: update gcp_token (#31405)
PR Close #31405
2019-07-03 08:54:02 -07:00
1033a0285b release: cut the v8.1.0 release 2019-07-02 13:44:35 -07:00
376c5fceb5 docs: add accessibility guide (#30851)
PR Close #30851
2019-07-02 11:39:24 -07:00
48a7581e1e docs: fix typo in Template Syntax (#31298)
Fixes #31282

PR Close #31298
2019-07-02 11:30:50 -07:00
d0c32e03b9 docs(core): in template syntax guide, make SVG example more clear (#31356)
add e2e test for SVG template example
fix template syntax example app
- linting errors
- runtime exceptions
- template type errors
- deprecated type casting
- deprecated currency pipe example

Relates to #30559

PR Close #31356
2019-07-02 11:30:15 -07:00
a57ea2640a test(zone.js): fix typos (#31358)
Relates to #31144

PR Close #31358
2019-07-02 11:29:33 -07:00
4ea54a777f docs: fix typo in deployment page (#31369)
PR Close #31369
2019-07-02 11:29:11 -07:00
0fe6110b97 build(docs-infra): update dgeni-packages dependency (#31368)
The new version 0.27.5 now has the `post-process-html` package, so we
don't need it in angular/angular any more.

PR Close #31368
2019-07-02 11:28:24 -07:00
ffe705066f build(bazel): fix build failures with worker mode cache and @types/events (#31326)
Errors observed only in tests on CircleCI — was not reproducible locally:

```
ERROR: /home/circleci/ng/packages/http/test/BUILD.bazel:3:1: Compiling TypeScript (devmode) //packages/http/test:test_lib failed (Exit 1): tsc_wrapped failed: error executing command
(cd /home/circleci/.cache/bazel/_bazel_circleci/9ce5c2144ecf75d11717c0aa41e45a8d/execroot/angular && \
exec env - \
BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 \
PATH=/bin:/usr/bin:/usr/local/bin \
bazel-out/host/bin/external/npm/@bazel/typescript/bin/tsc_wrapped @@bazel-out/k8-fastbuild/bin/packages/http/test/test_lib_es5_tsconfig.json)
Execution platform: //tools:rbe_ubuntu1604-angular
Compilation failed Error: missing input digest for /home/circleci/.cache/bazel/_bazel_circleci/9ce5c2144ecf75d11717c0aa41e45a8d/execroot/angular/external/npm/node_modules/@types/events/index.d.ts.

ERROR: /home/circleci/ng/packages/benchpress/test/BUILD.bazel:3:1: Compiling TypeScript (devmode) //packages/benchpress/test:test_lib failed (Exit 1): tsc_wrapped failed: error executing command
(cd /home/circleci/.cache/bazel/_bazel_circleci/9ce5c2144ecf75d11717c0aa41e45a8d/execroot/angular && \
exec env - \
BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 \
PATH=/bin:/usr/bin:/usr/local/bin \
bazel-out/host/bin/external/npm/@bazel/typescript/bin/tsc_wrapped @@bazel-out/k8-fastbuild/bin/packages/benchpress/test/test_lib_es5_tsconfig.json)
Execution platform: //tools:rbe_ubuntu1604-angular
Compilation failed Error: missing input digest for /home/circleci/.cache/bazel/_bazel_circleci/9ce5c2144ecf75d11717c0aa41e45a8d/execroot/angular/external/npm/node_modules/@types/events/index.d.ts

ERROR: C:/codefresh/volume/angular/packages/compiler/test/css_parser/BUILD.bazel:3:1: Compiling TypeScript (devmode) //packages/compiler/test/css_parser:css_parser_lib failed (Exit 1):
tsc_wrapped.exe failed: error executing command
cd C:/users/containeradministrator/_bazel_containeradministrator/zquin2l6/execroot/angular
SET PATH=C:\msys64\usr\bin;C:\msys64\bin;C:\Windows;C:\Windows\System32;C:\Windows\System32\WindowsPowerShell\v1.0
SET RUNFILES_MANIFEST_ONLY=1
bazel-out/host/bin/external/npm/@bazel/typescript/bin/tsc_wrapped.exe @@bazel-out/x64_windows-fastbuild/bin/packages/compiler/test/css_parser/css_parser_lib_es5_tsconfig.json
Execution platform: @bazel_tools//platforms:host_platform
Compilation failed Error: missing input digest for C:/users/containeradministrator/_bazel_containeradministrator/zquin2l6/execroot/angular/external/npm/node_modules/@types/events/index.
d.ts
```

PR Close #31326
2019-07-01 14:17:09 -07:00
0ac6406f00 build(bazel): update //packages/bazel/test/ngc-wrapped:ngc_test test (#31326)
after update to rules_nodejs 0.32.1, @types are no longer automatically discovered by ngc-wrapped (which uses parts of ts_library) so this test needed updating so that the types files it generates is added as an explicit dep

PR Close #31326
2019-07-01 14:17:09 -07:00
57ffb41a70 build(bazel): add build --incompatible_list_based_execution_strategy_selection=false flag (#31326)
This option is changed to true in Bazel 0.27 and exposes a possible
regression in Bazel 0.27.0.
Error observed is in npm_package target `//packages/common/locales:package`:
```
ERROR: /home/circleci/ng/packages/common/locales/BUILD.bazel:13:1: Assembling
npm package packages/common/locales/package failed: No usable spawn strategy found
for spawn with mnemonic SkylarkAction.  Your --spawn_strategyor --strategy flags
are probably too strict. Visit https://github.com/bazelbuild/bazel/issues/7480 for
migration advises
```
Suspect is https://github.com/bazelbuild/rules_nodejs/blob/master/internal/npm_package/npm_package.bzl#L75-L82:
```
 execution_requirements = {
    # Never schedule this action remotely because it's not computationally expensive.
    # It just copies files into a directory; it's not worth copying inputs and outputs to a remote worker.
    # Also don't run it in a sandbox, because it resolves an absolute path to the bazel-out directory
    # allowing the .pack and .publish runnables to work with no symlink_prefix
    # See https://github.com/bazelbuild/rules_nodejs/issues/187
    "local": "1",
},
```

PR Close #31326
2019-07-01 14:17:09 -07:00
c60edabd70 build(bazel): remove deprecated rules_nodejs NodeModuleInfo provider (#31326)
PR Close #31326
2019-07-01 14:17:09 -07:00
b3b8e102c0 build: disable must-use-promises check in ts_library tsetse for tests as... (#31326)
...tsetse now falsely asserting on  some lines in a few tests such as packages/core/schematics/test/injectable_pipe_migration_spec.ts.

```
    await runMigration();
    expect(tree.readContent('/index.ts'))
```

it asserts that "await is required on promise" on the 2nd line when there is no promise there

PR Close #31326
2019-07-01 14:17:09 -07:00
87c449a085 build(bazel): cleanup entry_point target (#31326)
PR Close #31326
2019-07-01 14:17:09 -07:00
52d47b4696 build(bazel): update to rules_nodejs 0.32.2 (#31326)
Brings in ts_library fixes required to get angular/angular building after 0.32.0:
typescript: exclude typescript lib declarations in node_module_library transitive_declarations
typescript: remove override of @bazel/tsetse (+1 squashed commit)

@npm//node_modules/foobar:foobar.js labels changed to @npm//:node_modules/foobar/foobar.js with fix for bazelbuild/rules_nodejs#802

also updates to rules_rass commit compatible with rules_nodejs 0.32.0

PR Close #31326
2019-07-01 14:17:08 -07:00
917933bb9e build(bazel): update to bazel 0.27.0 and fix compat in @angular/bazel package (#31326)
ctx.actions.declare_file now used in @angular/bazel ng_module rule as ctx.new_file is now deprecated. Fixes error:

```
        File "ng_module.bzl", line 272, in _expected_outs
                ctx.new_file(ctx.genfiles_dir, (ctx.label.name ..."))
Use ctx.actions.declare_file instead of ctx.new_file.
Use --incompatible_new_actions_api=false to temporarily disable this check.
```

This can be worked around with incompatible_new_actions_api flag but may as well fix it proper so downstream doesn't require this flag due to this code.

Also, depset() is no longer iterable by default without a flag. This required fixing in a few spots in @angular/bazel.

fix: foo

PR Close #31326
2019-07-01 14:17:08 -07:00
80ccd6c19b fix(core): handle undefined meta in injectArgs (#31333)
In the recent versions of the CLI we introduced a ctor downleveler tranformer for VE JIT builds based on the one found in tsickle, to fix the TDZ issue of `forwardRef`.

However this caused a regression as the injector is not handling that a position `paramType` can be undefined. Which is bubbled down to c6b29f4c6d/packages/core/src/di/injector_compatibility.ts (L162) and will crash c6b29f4c6d/packages/core/src/di/injector_compatibility.ts (L174-L186)

Fixes https://github.com/angular/angular-cli/issues/14888

PR Close #31333
2019-07-01 10:11:08 -07:00
b7e3d80879 feat(ivy): ngcc - handle top-level helper calls in CommonJS (#31335)
Some formats of CommonJS put the decorator helper calls
outside the class IIFE as statements on the top level of the
source file.

This commit adds support to the `CommonJSReflectionHost`
for this format.

PR Close #31335
2019-07-01 10:09:41 -07:00
4bbf60ed01 docs: change order of Angular Elements article (#30521)
PR Close #30268

PR Close #30521
2019-06-28 12:22:45 -07:00
299a43c7f8 Revert "fix(router): adjust UrlTree redirect to replace URL if in eager update (#31168)" (#31344)
This reverts commit 15e397816f.

Reason: it broke an internal g3 app.

PR Close #31344
2019-06-28 11:40:27 -07:00
c92fe6f6fb docs: add tests for lazy loading angularjs example (#30622)
PR Close #30622
2019-06-28 09:26:50 -07:00
c8875f2dbb docs: added svg example (#30559)
Fixes #30441

PR Close #30559
2019-06-27 15:56:26 -07:00
3ca56a6d5c fix(docs-infra): detect docregions on more file types (pug, svg, yml) (#30559)
PR Close #30559
2019-06-27 15:56:26 -07:00
7223f60060 fix(router): adjust UrlTree redirect to replace URL if in eager update (#31168)
Without this change when using UrlTree redirects in `urlUpdateStrategy="eager"`, the URL would get updated to the target location, then redirected. This resulted in having an additional entry in the `history` and thus the `back` button would be broken (going back would land on the URL causing a new redirect).

Additionally, there was a bug where the redirect, even without `urlUpdateStrategy="eager"`, could create a history with too many entries. This was due to kicking off a new navigation within the navigation cancelling logic. With this PR the new navigation is pushed to the next tick with a `setTimeout`, allowing the page being redirected from to be cancelled before starting a new navigation.

Related to #27148

PR Close #31168
2019-06-27 15:54:20 -07:00
8b034188bd docs: fix example misprints (#31284)
PR Close #31284
2019-06-27 15:53:26 -07:00
579f1295ac ci: add branch info to CircleCI failure notifications (#31319)
PR Close #31319
2019-06-27 15:52:14 -07:00
2914b10eba build(docs-infra): upgrade cli command docs sources to 823731f6e (#31308)
Updating [angular#8.1.x](https://github.com/angular/angular/tree/8.1.x) from [cli-builds#8.0.x](https://github.com/angular/cli-builds/tree/8.0.x).

##
Relevant changes in [commit range](01a7186bb...823731f6e):

**Modified**
- help/analytics.json
- help/build.json
- help/e2e.json
- help/generate.json
- help/new.json
- help/serve.json
- help/test.json
- help/update.json
- help/xi18n.json

##

PR Close #31308
2019-06-27 11:51:56 -07:00
c00544ac51 refactor(service-worker): remove redundant cache operation (#30977)
At this point, the response will have been cached (or scheduled to be
cached) in other code paths, so caching it again is redundant.

PR Close #30977
2019-06-27 09:52:29 -07:00
a9038ef13c fix(service-worker): cache opaque responses when requests exceeds timeout threshold (#30977)
PR Close #30977
2019-06-27 09:52:29 -07:00
b0c345324a fix(service-worker): cache opaque responses in data groups with freshness strategy (#30977)
Previously, (presummably due to a typo) the `okToCacheOpaque` argument
of `DataGroup#cacheResponse()` was essentially never taken into account
(since opaque responses have a non-200 status code and thus `res.ok` is
always false).

This commit fixes the typo, which allows opaque responses to be cached
when `okToCacheOpaque` is true (i.e. in data groups using the
`freshness` strategy).

Fixes #30968

PR Close #30977
2019-06-27 09:52:29 -07:00
26efc682d5 refactor(service-worker): make the caching behavior more explicit (#30977)
This commit doesn't change the behavior wrt caching, but it makes it
more explicit that only non-timed-out responses are cached. In case of a
timeout, `res` would be set to a programmatically created 504
`Response`, so `cacheResponse()` (which checks for `res.ok`) would not
have cached it anyway, but this makes change makes it more explicit (and
more similar to the equivalent part in [handleFetchWithFreshness()][1]).

[1]: https://github.com/angular/angular/blob/2b4d5c754/packages/service-worker/worker/src/data.ts#L379-L388

PR Close #30977
2019-06-27 09:52:29 -07:00
8b6128759c test(service-worker): better simulate opaque requests (#30977)
Previously, opaque responses where handled a little differently than
other responses from the mock server. More specifically, they were not
tracked (so no assertions could be made for them) and their
[`Body` mixin][1] methods (such as `arrayBuffer()`, `json()`, `text()`)
would throw an error due to `body` being `null`.

This commit ensures opaque responses are also captured on the mock
server and also changes `Body` mixin methods to better simulate the
[spec'd behavior][2].

(These improvements will be necessary to test caching of opaque
responses in a subsequent commit.)

[1]: https://developer.mozilla.org/en-US/docs/Web/API/Body
[2]: https://fetch.spec.whatwg.org/#concept-body-consume-body

PR Close #30977
2019-06-27 09:52:29 -07:00
54c171cded test(service-worker): properly reset mock server state for each test (#30977)
PR Close #30977
2019-06-27 09:52:29 -07:00
642f6046af test(service-worker): simplify test helpers (#30977)
PR Close #30977
2019-06-27 09:52:29 -07:00
d0e213d137 test(service-worker): remove obsolete async test helpers (#30977)
Jasmine natively supports returning promises from spec functions for
quite some time now. We don't need special async helpers.

PR Close #30977
2019-06-27 09:52:29 -07:00
7418c901c2 docs: couple of small UI fixes throughout some documents (#31155)
PR Close #31155
2019-06-27 09:51:28 -07:00
231 changed files with 3489 additions and 2443 deletions

View File

@ -1,3 +1,4 @@
.git
node_modules node_modules
dist dist
aio/content aio/content

View File

@ -1,14 +1,3 @@
###############################
# Typescript / Angular / Sass #
###############################
# Make compilation fast, by keeping a few copies of the compilers
# running as daemons, and cache SourceFile AST's to reduce parse time.
build --strategy=AngularTemplateCompile=worker
# TODO(alexeagle): re-enable after fixing worker instability with rxjs typings
# build --strategy=TypeScriptCompile=worker
build --strategy=TypeScriptCompile=standalone
# Enable debugging tests with --config=debug # Enable debugging tests with --config=debug
test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results
@ -85,12 +74,6 @@ query --output=label_kind
# By default, failing tests don't print any output, it goes to the log file # By default, failing tests don't print any output, it goes to the log file
test --test_output=errors test --test_output=errors
# Show which actions are run under workers,
# and print all the actions running in parallel.
# Helps to demonstrate that bazel uses all the cores on the machine.
build --experimental_ui
test --experimental_ui
################################ ################################
# Settings for CircleCI # # Settings for CircleCI #
################################ ################################
@ -154,6 +137,31 @@ build:remote --bes_results_url="https://source.cloud.google.com/results/invocati
# This allows us to avoid installing a second copy of node_modules # This allows us to avoid installing a second copy of node_modules
common --experimental_allow_incremental_repository_updates common --experimental_allow_incremental_repository_updates
# This option is changed to true in Bazel 0.27 and exposes a possible
# regression in Bazel 0.27.0.
# Error observed is in npm_package target `//packages/common/locales:package`:
# ```
# ERROR: /home/circleci/ng/packages/common/locales/BUILD.bazel:13:1: Assembling
# npm package packages/common/locales/package failed: No usable spawn strategy found
# for spawn with mnemonic SkylarkAction. Your --spawn_strategyor --strategy flags
# are probably too strict. Visit https://github.com/bazelbuild/bazel/issues/7480 for
# migration advises
# ```
# Suspect is https://github.com/bazelbuild/rules_nodejs/blob/master/internal/npm_package/npm_package.bzl#L75-L82:
# ```
# execution_requirements = {
# # Never schedule this action remotely because it's not computationally expensive.
# # It just copies files into a directory; it's not worth copying inputs and outputs to a remote worker.
# # Also don't run it in a sandbox, because it resolves an absolute path to the bazel-out directory
# # allowing the .pack and .publish runnables to work with no symlink_prefix
# # See https://github.com/bazelbuild/rules_nodejs/issues/187
# "local": "1",
# },
# ```
build --incompatible_list_based_execution_strategy_selection=false
test --incompatible_list_based_execution_strategy_selection=false
run --incompatible_list_based_execution_strategy_selection=false
#################################################### ####################################################
# User bazel configuration # User bazel configuration
# NOTE: This needs to be the *last* entry in the config. # NOTE: This needs to be the *last* entry in the config.

View File

@ -28,3 +28,14 @@ test --flaky_test_attempts=2
# More details on failures # More details on failures
build --verbose_failures=true build --verbose_failures=true
# We have seen some flakiness in using TS workers on CircleCI
# https://angular-team.slack.com/archives/C07DT5M6V/p1562693245183400
# > failures like `ERROR: /home/circleci/ng/packages/core/test/BUILD.bazel:5:1:
# > Compiling TypeScript (devmode) //packages/core/test:test_lib failed: Worker process did not return a WorkResponse:`
# > I saw that issue a couple times today.
# > Example job: https://circleci.com/gh/angular/angular/385517
# We expect that TypeScript compilations will parallelize wider than the number of local cores anyway
# so we should saturate remote workers with TS compilations
build --strategy=TypeScriptCompile=standalone
build --strategy=AngularTemplateCompile=standalone

View File

@ -138,7 +138,7 @@ var_13: &notify_caretaker_on_fail
# `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings. # `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings.
# The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci. # The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
command: | command: |
notificationJson="{\"text\":\":x: \`$CIRCLE_JOB\` job failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}" notificationJson="{\"text\":\":x: \`$CIRCLE_JOB\` job for $CIRCLE_BRANCH branch failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}"
curl --request POST --header "Content-Type: application/json" --data "$notificationJson" $SLACK_CARETAKER_WEBHOOK_URL curl --request POST --header "Content-Type: application/json" --data "$notificationJson" $SLACK_CARETAKER_WEBHOOK_URL
var_14: &notify_dev_infra_on_fail var_14: &notify_dev_infra_on_fail
@ -148,7 +148,7 @@ var_14: &notify_dev_infra_on_fail
# `$SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL` is a secret env var defined in CircleCI project settings. # `$SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL` is a secret env var defined in CircleCI project settings.
# The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci. # The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
command: | command: |
notificationJson="{\"text\":\":x: \`$CIRCLE_JOB\` job failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}" notificationJson="{\"text\":\":x: \`$CIRCLE_JOB\` job for $CIRCLE_BRANCH branch failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}"
curl --request POST --header "Content-Type: application/json" --data "$notificationJson" $SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL curl --request POST --header "Content-Type: application/json" --data "$notificationJson" $SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL
version: 2 version: 2
@ -293,6 +293,8 @@ jobs:
- run: yarn --cwd aio e2e --configuration=ci - run: yarn --cwd aio e2e --configuration=ci
# Run PWA-score tests # Run PWA-score tests
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE - run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
# Run accessibility tests
- run: yarn --cwd aio test-a11y-score-localhost
# Check the bundle sizes. # Check the bundle sizes.
- run: yarn --cwd aio payload-size - run: yarn --cwd aio payload-size
# Run unit tests for Firebase redirects # Run unit tests for Firebase redirects

Binary file not shown.

View File

@ -82,6 +82,9 @@ FROM baseimage
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
# Install Bazel prereqs on Windows (https://docs.bazel.build/versions/master/install-windows.html)
# Install MSYS2
RUN Invoke-WebRequest -UseBasicParsing 'https://www.7-zip.org/a/7z1805-x64.exe' -OutFile 7z.exe; ` RUN Invoke-WebRequest -UseBasicParsing 'https://www.7-zip.org/a/7z1805-x64.exe' -OutFile 7z.exe; `
Start-Process -FilePath 'C:\\7z.exe' -ArgumentList '/S', '/D=C:\\7zip0' -NoNewWindow -Wait; ` Start-Process -FilePath 'C:\\7z.exe' -ArgumentList '/S', '/D=C:\\7zip0' -NoNewWindow -Wait; `
Invoke-WebRequest -UseBasicParsing 'http://repo.msys2.org/distrib/x86_64/msys2-base-x86_64-20180531.tar.xz' -OutFile msys2.tar.xz; ` Invoke-WebRequest -UseBasicParsing 'http://repo.msys2.org/distrib/x86_64/msys2-base-x86_64-20180531.tar.xz' -OutFile msys2.tar.xz; `
@ -94,7 +97,10 @@ RUN Invoke-WebRequest -UseBasicParsing 'https://www.7-zip.org/a/7z1805-x64.exe'
[Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\msys64\usr\bin', [System.EnvironmentVariableTarget]::Machine); ` [Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\msys64\usr\bin', [System.EnvironmentVariableTarget]::Machine); `
[Environment]::SetEnvironmentVariable('BAZEL_SH', 'C:\msys64\usr\bin\bash.exe', [System.EnvironmentVariableTarget]::Machine) [Environment]::SetEnvironmentVariable('BAZEL_SH', 'C:\msys64\usr\bin\bash.exe', [System.EnvironmentVariableTarget]::Machine)
# Install VS Build Tools # Install MSYS2 packages
RUN C:\msys64\usr\bin\bash.exe -l -c \"pacman --needed --noconfirm -S zip unzip patch diffutils git\"
# Install VS Build Tools (required to build C++ targets)
RUN Invoke-WebRequest -UseBasicParsing https://download.visualstudio.microsoft.com/download/pr/df649173-11e9-4af2-8eb7-0eb02ba8958a/cadb5bdac41e55bb8f6a6b7c45273370/vs_buildtools.exe -OutFile vs_BuildTools.exe; ` RUN Invoke-WebRequest -UseBasicParsing https://download.visualstudio.microsoft.com/download/pr/df649173-11e9-4af2-8eb7-0eb02ba8958a/cadb5bdac41e55bb8f6a6b7c45273370/vs_buildtools.exe -OutFile vs_BuildTools.exe; `
# Installer won't detect DOTNET_SKIP_FIRST_TIME_EXPERIENCE if ENV is used, must use setx /M # Installer won't detect DOTNET_SKIP_FIRST_TIME_EXPERIENCE if ENV is used, must use setx /M
setx /M DOTNET_SKIP_FIRST_TIME_EXPERIENCE 1; ` setx /M DOTNET_SKIP_FIRST_TIME_EXPERIENCE 1; `
@ -112,7 +118,7 @@ RUN Invoke-WebRequest -UseBasicParsing https://download.visualstudio.microsoft.c
Remove-Item -Force -Recurse \"${Env:ProgramData}\Package Cache\"; ` Remove-Item -Force -Recurse \"${Env:ProgramData}\Package Cache\"; `
[Environment]::SetEnvironmentVariable('BAZEL_VC', \"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\BuildTools\VC\", [System.EnvironmentVariableTarget]::Machine) [Environment]::SetEnvironmentVariable('BAZEL_VC', \"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\BuildTools\VC\", [System.EnvironmentVariableTarget]::Machine)
# Install Python # Install Python (required to build Python targets)
RUN Invoke-WebRequest -UseBasicParsing https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile python-3.5.1.exe; ` RUN Invoke-WebRequest -UseBasicParsing https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile python-3.5.1.exe; `
Start-Process python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait; ` Start-Process python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait; `
Remove-Item -Force python-3.5.1.exe Remove-Item -Force python-3.5.1.exe

View File

@ -18,15 +18,15 @@ filegroup(
name = "web_test_bootstrap_scripts", name = "web_test_bootstrap_scripts",
# do not sort # do not sort
srcs = [ srcs = [
"@npm//node_modules/core-js:client/core.js", "@npm//:node_modules/core-js/client/core.js",
"@npm//node_modules/zone.js:dist/zone.js", "@npm//:node_modules/zone.js/dist/zone.js",
"@npm//node_modules/zone.js:dist/zone-testing.js", "@npm//:node_modules/zone.js/dist/zone-testing.js",
"@npm//node_modules/zone.js:dist/task-tracking.js", "@npm//:node_modules/zone.js/dist/task-tracking.js",
"//:test-events.js", "//:test-events.js",
"//:shims_for_IE.js", "//:shims_for_IE.js",
# Including systemjs because it defines `__eval`, which produces correct stack traces. # Including systemjs because it defines `__eval`, which produces correct stack traces.
"@npm//node_modules/systemjs:dist/system.src.js", "@npm//:node_modules/systemjs/dist/system.src.js",
"@npm//node_modules/reflect-metadata:Reflect.js", "@npm//:node_modules/reflect-metadata/Reflect.js",
], ],
) )
@ -35,15 +35,15 @@ filegroup(
srcs = [ srcs = [
# We also declare the unminfied 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) # local debugging (e.g. see: packages/upgrade/test/common/test_helpers.ts)
"@npm//node_modules/angular:angular.js", "@npm//:node_modules/angular/angular.js",
"@npm//node_modules/angular:angular.min.js", "@npm//:node_modules/angular/angular.min.js",
"@npm//node_modules/angular-1.5:angular.js", "@npm//:node_modules/angular-1.5/angular.js",
"@npm//node_modules/angular-1.5:angular.min.js", "@npm//:node_modules/angular-1.5/angular.min.js",
"@npm//node_modules/angular-1.6:angular.js", "@npm//:node_modules/angular-1.6/angular.js",
"@npm//node_modules/angular-1.6:angular.min.js", "@npm//:node_modules/angular-1.6/angular.min.js",
"@npm//node_modules/angular-mocks:angular-mocks.js", "@npm//:node_modules/angular-mocks/angular-mocks.js",
"@npm//node_modules/angular-mocks-1.5:angular-mocks.js", "@npm//:node_modules/angular-mocks-1.5/angular-mocks.js",
"@npm//node_modules/angular-mocks-1.6:angular-mocks.js", "@npm//:node_modules/angular-mocks-1.6/angular-mocks.js",
], ],
) )

View File

@ -1,3 +1,37 @@
<a name="8.1.2"></a>
## [8.1.2](https://github.com/angular/angular/compare/8.1.0...8.1.2) (2019-07-17)
### Bug Fixes
* use the correct WTF array to iterate over ([#31208](https://github.com/angular/angular/issues/31208)) ([4aed480](https://github.com/angular/angular/commit/4aed480))
* **compiler-cli:** Return original sourceFile instead of redirected sourceFile from getSourceFile ([#26036](https://github.com/angular/angular/issues/26036)) ([13dbb98](https://github.com/angular/angular/commit/13dbb98)), closes [#22524](https://github.com/angular/angular/issues/22524)
* **core:** export provider interfaces that are part of the public API types ([#31377](https://github.com/angular/angular/issues/31377)) ([bebf089](https://github.com/angular/angular/commit/bebf089)), closes [/github.com/angular/angular/pull/31377#discussion_r299254408](https://github.com//github.com/angular/angular/pull/31377/issues/discussion_r299254408) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L365-L366](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L365-L366) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L283-L284](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L283-L284) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts#L23](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts/issues/L23)
<a name="8.1.1"></a>
## [8.1.1](https://github.com/angular/angular/compare/8.1.0...8.1.1) (2019-07-10)
### Bug Fixes
* **core:** export provider interfaces that are part of the public API types ([#31377](https://github.com/angular/angular/issues/31377)) ([bebf089](https://github.com/angular/angular/commit/bebf089)), closes [/github.com/angular/angular/pull/31377#discussion_r299254408](https://github.com//github.com/angular/angular/pull/31377/issues/discussion_r299254408) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L365-L366](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L365-L366) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L283-L284](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L283-L284) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts#L23](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts/issues/L23)
<a name="8.1.0"></a>
# [8.1.0](https://github.com/angular/angular/compare/8.1.0-rc.0...8.1.0) (2019-07-02)
### Bug Fixes
* **core:** handle `undefined` meta in `injectArgs` ([#31333](https://github.com/angular/angular/issues/31333)) ([80ccd6c](https://github.com/angular/angular/commit/80ccd6c)), closes [CLI #14888](https://github.com/angular/angular-cli/issues/14888)
* **service-worker:** cache opaque responses in data groups with `freshness` strategy ([#30977](https://github.com/angular/angular/issues/30977)) ([b0c3453](https://github.com/angular/angular/commit/b0c3453)), closes [#30968](https://github.com/angular/angular/issues/30968)
* **service-worker:** cache opaque responses when requests exceeds timeout threshold ([#30977](https://github.com/angular/angular/issues/30977)) ([a9038ef](https://github.com/angular/angular/commit/a9038ef))
<a name="8.1.0-rc.0"></a> <a name="8.1.0-rc.0"></a>
# [8.1.0-rc.0](https://github.com/angular/angular/compare/8.1.0-next.3...8.1.0-rc.0) (2019-06-26) # [8.1.0-rc.0](https://github.com/angular/angular/compare/8.1.0-next.3...8.1.0-rc.0) (2019-06-26)

View File

@ -18,8 +18,11 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# Fetch rules_nodejs so we can install our npm dependencies # Fetch rules_nodejs so we can install our npm dependencies
http_archive( http_archive(
name = "build_bazel_rules_nodejs", name = "build_bazel_rules_nodejs",
sha256 = "e04a82a72146bfbca2d0575947daa60fda1878c8d3a3afe868a8ec39a6b968bb", patch_args = ["-p1"],
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.31.1/rules_nodejs-0.31.1.tar.gz"], # Patch https://github.com/bazelbuild/rules_nodejs/pull/903
patches = ["//tools:rollup_bundle_commonjs_ignoreGlobal.patch"],
sha256 = "6d4edbf28ff6720aedf5f97f9b9a7679401bf7fca9d14a0fff80f644a99992b4",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.32.2/rules_nodejs-0.32.2.tar.gz"],
) )
# Check the bazel version and download npm dependencies # Check the bazel version and download npm dependencies
@ -27,6 +30,7 @@ load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "check_rules
# Bazel version must be at least the following version because: # Bazel version must be at least the following version because:
# - 0.26.0 managed_directories feature added which is required for nodejs rules 0.30.0 # - 0.26.0 managed_directories feature added which is required for nodejs rules 0.30.0
# - 0.27.0 has a fix for managed_directories after `rm -rf node_modules`
check_bazel_version( check_bazel_version(
message = """ message = """
You no longer need to install Bazel on your machine. You no longer need to install Bazel on your machine.
@ -35,7 +39,7 @@ Try running `yarn bazel` instead.
(If you did run that, check that you've got a fresh `yarn install`) (If you did run that, check that you've got a fresh `yarn install`)
""", """,
minimum_bazel_version = "0.26.0", minimum_bazel_version = "0.27.0",
) )
# The NodeJS rules version must be at least the following version because: # The NodeJS rules version must be at least the following version because:
@ -46,7 +50,10 @@ Try running `yarn bazel` instead.
# - 0.27.12 Adds NodeModuleSources provider for transtive npm deps support # - 0.27.12 Adds NodeModuleSources provider for transtive npm deps support
# - 0.30.0 yarn_install now uses symlinked node_modules with new managed directories Bazel 0.26.0 feature # - 0.30.0 yarn_install now uses symlinked node_modules with new managed directories Bazel 0.26.0 feature
# - 0.31.1 entry_point attribute of nodejs_binary & rollup_bundle is now a label # - 0.31.1 entry_point attribute of nodejs_binary & rollup_bundle is now a label
check_rules_nodejs_version(minimum_version_string = "0.31.1") # - 0.32.0 yarn_install and npm_install no longer puts build files under symlinked node_modules
# - 0.32.1 remove override of @bazel/tsetse & exclude typescript lib declarations in node_module_library transitive_declarations
# - 0.32.2 resolves bug in @bazel/hide-bazel-files postinstall step
check_rules_nodejs_version(minimum_version_string = "0.32.2")
# Setup the Node.js toolchain # Setup the Node.js toolchain
node_repositories( node_repositories(
@ -70,19 +77,7 @@ node_repositories(
yarn_install( yarn_install(
name = "npm", name = "npm",
data = [
"//:tools/npm/@angular_bazel/index.js",
"//:tools/npm/@angular_bazel/package.json",
"//:tools/postinstall-patches.js",
"//:tools/yarn/check-yarn.js",
],
package_json = "//:package.json", package_json = "//:package.json",
# Don't install devDependencies, they are large and not used under Bazel
prod_only = True,
# Temporarily disable node_modules symlinking until the fix for
# https://github.com/bazelbuild/bazel/issues/8487 makes it into a
# future Bazel release
symlink_node_modules = False,
yarn_lock = "//:yarn.lock", yarn_lock = "//:yarn.lock",
) )

View File

@ -36,6 +36,14 @@ ng serve
In your browser, open http://localhost:4200/ to see the new app run. In your browser, open http://localhost:4200/ to see the new app run.
When you use the [ng serve](cli/serve) command to build an app and serve it locally, the server automatically rebuilds the app and reloads the page when you change any of the source files. When you use the [ng serve](cli/serve) command to build an app and serve it locally, the server automatically rebuilds the app and reloads the page when you change any of the source files.
<div class="alert is-helpful">
When you run `ng new my-first-project` a new folder, named `my-first-project`, will be created in the current working directory. Since you want to be able to create files inside that folder, make sure you have sufficient rights in the current working directory before running the command.
If the current working directory is not the right place for your project, you can change to a more appropriate directory by running `cd <path-to-other-directory>` first.
</div>
## Workspaces and project files ## Workspaces and project files
The [ng new](cli/new) command creates an *Angular workspace* folder and generates a new app skeleton. The [ng new](cli/new) command creates an *Angular workspace* folder and generates a new app skeleton.
@ -74,7 +82,7 @@ Command syntax is shown as follows:
* Option names are prefixed with a double dash (--). * Option names are prefixed with a double dash (--).
Option aliases are prefixed with a single dash (-). Option aliases are prefixed with a single dash (-).
Arguments are not prefixed. Arguments are not prefixed.
For example: For example:
<code-example format="." language="bash"> <code-example format="." language="bash">
ng build my-app -c production ng build my-app -c production
</code-example> </code-example>
@ -105,5 +113,5 @@ Schematic options are supplied to the command in the same format as immediate co
### Building with Bazel ### Building with Bazel
Optionally, you can configure the Angular CLI to use [Bazel](https://docs.bazel.build) as the build tool. For more information, see [Building with Bazel](guide/bazel). Optionally, you can configure the Angular CLI to use [Bazel](https://docs.bazel.build) as the build tool. For more information, see [Building with Bazel](guide/bazel).

View File

@ -25,8 +25,8 @@ describe('Attribute directives', () => {
greenRb.click(); greenRb.click();
browser.actions().mouseMove(highlightedEle).perform(); browser.actions().mouseMove(highlightedEle).perform();
// Wait for up to 2s for the background color to be updated, // Wait for up to 4s for the background color to be updated,
// to account for slow environments (e.g. CI). // to account for slow environments (e.g. CI).
browser.wait(() => highlightedEle.getCssValue('background-color').then(c => c === lightGreen), 2000); browser.wait(() => highlightedEle.getCssValue('background-color').then(c => c === lightGreen), 4000);
}); });
}); });

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 32 KiB

View File

@ -18,7 +18,7 @@ export class AppComponent {
} }
deleteItem(item: Item) { deleteItem(item: Item) {
alert(`Delete the ${item}.`); alert(`Delete the ${item.name}.`);
} }
onClickMe(event?: KeyboardEvent) { onClickMe(event?: KeyboardEvent) {

View File

@ -10,7 +10,6 @@ export class AppComponent {
gender = 'female'; gender = 'female';
fly = true; fly = true;
logo = 'https://angular.io/assets/images/logos/angular/angular.png'; logo = 'https://angular.io/assets/images/logos/angular/angular.png';
heroes: string[] = ['Magneta', 'Celeritas', 'Dynama'];
inc(i: number) { inc(i: number) {
this.minutes = Math.min(5, Math.max(0, this.minutes + i)); this.minutes = Math.min(5, Math.max(0, this.minutes + i));
} }

View File

@ -0,0 +1,14 @@
// imports
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
// @NgModule decorator with its metadata
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}

View File

@ -7,9 +7,9 @@ import { from } from 'rxjs';
const data = from(fetch('/api/endpoint')); const data = from(fetch('/api/endpoint'));
// Subscribe to begin listening for async result // Subscribe to begin listening for async result
data.subscribe({ data.subscribe({
next(response) { console.log(response); }, next(response) { console.log(response); },
error(err) { console.error('Error: ' + err); }, error(err) { console.error('Error: ' + err); },
complete() { console.log('Completed'); } complete() { console.log('Completed'); }
}); });
// #enddocregion promise // #enddocregion promise

View File

@ -2,42 +2,49 @@
import { browser, element, by } from 'protractor'; import { browser, element, by } from 'protractor';
// Not yet complete // TODO Not yet complete
describe('Template Syntax', function () { describe('Template Syntax', () => {
beforeAll(function () { beforeAll(() => {
browser.get(''); browser.get('');
}); });
it('should be able to use interpolation with a hero', function () { it('should be able to use interpolation with a hero', () => {
let heroInterEle = element.all(by.css('h2+p')).get(0); const heroInterEle = element.all(by.css('h2+p')).get(0);
expect(heroInterEle.getText()).toEqual('My current hero is Hercules'); expect(heroInterEle.getText()).toEqual('My current hero is Hercules');
}); });
it('should be able to use interpolation with a calculation', function () { it('should be able to use interpolation with a calculation', () => {
let theSumEles = element.all(by.cssContainingText('h3~p', 'The sum of')); const theSumEles = element.all(by.cssContainingText('h3~p', 'The sum of'));
expect(theSumEles.count()).toBe(2); expect(theSumEles.count()).toBe(2);
expect(theSumEles.get(0).getText()).toEqual('The sum of 1 + 1 is 2'); expect(theSumEles.get(0).getText()).toEqual('The sum of 1 + 1 is 2');
expect(theSumEles.get(1).getText()).toEqual('The sum of 1 + 1 is not 4'); expect(theSumEles.get(1).getText()).toEqual('The sum of 1 + 1 is not 4');
}); });
it('should be able to use class binding syntax', function () { it('should be able to use class binding syntax', () => {
let specialEle = element(by.cssContainingText('div', 'Special')); const specialEle = element(by.cssContainingText('div', 'Special'));
expect(specialEle.getAttribute('class')).toMatch('special'); expect(specialEle.getAttribute('class')).toMatch('special');
}); });
it('should be able to use style binding syntax', function () { it('should be able to use style binding syntax', () => {
let specialButtonEle = element(by.cssContainingText('div.special~button', 'button')); const specialButtonEle = element(by.cssContainingText('div.special~button', 'button'));
expect(specialButtonEle.getAttribute('style')).toMatch('color: red'); expect(specialButtonEle.getAttribute('style')).toMatch('color: red');
}); });
it('should two-way bind to sizer', async () => { it('should two-way bind to sizer', async () => {
let div = element(by.css('div#two-way-1')); const div = element(by.css('div#two-way-1'));
let incButton = div.element(by.buttonText('+')); const incButton = div.element(by.buttonText('+'));
let input = div.element(by.css('input')); const input = div.element(by.css('input'));
let initSize = await input.getAttribute('value'); const initSize = await input.getAttribute('value');
incButton.click(); incButton.click();
expect(input.getAttribute('value')).toEqual((+initSize + 1).toString()); expect(input.getAttribute('value')).toEqual((+initSize + 1).toString());
}); });
});
it('should change SVG rectangle\'s fill color on click', async () => {
const div = element(by.css('app-svg'));
const colorSquare = div.element(by.css('rect'));
const initialColor = await colorSquare.getAttribute('fill');
colorSquare.click();
expect(colorSquare.getAttribute('fill')).not.toEqual(initialColor);
});
});

View File

@ -38,6 +38,7 @@
<a href="#safe-navigation-operator">Safe navigation operator <i>?.</i></a><br> <a href="#safe-navigation-operator">Safe navigation operator <i>?.</i></a><br>
<a href="#non-null-assertion-operator">Non-null assertion operator <i>!.</i></a><br> <a href="#non-null-assertion-operator">Non-null assertion operator <i>!.</i></a><br>
<a href="#enums">Enums</a><br> <a href="#enums">Enums</a><br>
<a href="#svg-templates">SVG Templates</a><br>
<!-- Interpolation and expressions --> <!-- Interpolation and expressions -->
<hr><h2 id="interpolation">Interpolation</h2> <hr><h2 id="interpolation">Interpolation</h2>
@ -442,7 +443,7 @@ button</button>
<!-- #docregion without-NgModel --> <!-- #docregion without-NgModel -->
<input [value]="currentHero.name" <input [value]="currentHero.name"
(input)="currentHero.name=$event.target.value" > (input)="updateCurrentHeroName($event)">
<!-- #enddocregion without-NgModel --> <!-- #enddocregion without-NgModel -->
without NgModel without NgModel
<br> <br>
@ -752,7 +753,7 @@ bindon-ngModel
<div> <div>
<!-- pipe price to USD and display the $ symbol --> <!-- pipe price to USD and display the $ symbol -->
<label>Price: </label>{{product.price | currency:'USD':true}} <label>Price: </label>{{product.price | currency:'USD':'symbol'}}
</div> </div>
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
@ -857,3 +858,9 @@ The null hero's name is {{nullHero && nullHero.name}}
</p> </p>
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
<hr><h2 id="svg-templates">SVG Templates</h2>
<!-- #docregion svg-templates -->
<app-svg></app-svg>
<!-- #enddocregion svg-templates -->
<a class="to-toc" href="#toc">top</a>

View File

@ -5,7 +5,7 @@ import { AfterViewInit, Component, ElementRef, OnInit, QueryList, ViewChildren }
import { Hero } from './hero'; import { Hero } from './hero';
export enum Color {Red, Green, Blue}; export enum Color {Red, Green, Blue}
/** /**
* Giant grab bag of stuff to drive the chapter * Giant grab bag of stuff to drive the chapter
@ -29,7 +29,7 @@ export class AppComponent implements AfterViewInit, OnInit {
trackChanges(this.heroesWithTrackBy, () => this.heroesWithTrackByCount++); trackChanges(this.heroesWithTrackBy, () => this.heroesWithTrackByCount++);
} }
@ViewChildren('noTrackBy') heroesNoTrackBy: QueryList<ElementRef>; @ViewChildren('noTrackBy') heroesNoTrackBy: QueryList<ElementRef>;
@ViewChildren('withTrackBy') heroesWithTrackBy: QueryList<ElementRef>; @ViewChildren('withTrackBy') heroesWithTrackBy: QueryList<ElementRef>;
actionName = 'Go for it'; actionName = 'Go for it';
@ -66,6 +66,10 @@ export class AppComponent implements AfterViewInit, OnInit {
currentHero: Hero; currentHero: Hero;
updateCurrentHeroName(event: Event) {
this.currentHero.name = (event.target as any).value;
}
deleteHero(hero?: Hero) { deleteHero(hero?: Hero) {
this.alert(`Delete ${hero ? hero.name : 'the hero'}.`); this.alert(`Delete ${hero ? hero.name : 'the hero'}.`);
} }
@ -105,13 +109,13 @@ export class AppComponent implements AfterViewInit, OnInit {
get nullHero(): Hero { return null; } get nullHero(): Hero { return null; }
onClickMe(event?: KeyboardEvent) { onClickMe(event?: MouseEvent) {
let evtMsg = event ? ' Event target class is ' + (<HTMLElement>event.target).className : ''; const evtMsg = event ? ' Event target class is ' + (event.target as HTMLElement).className : '';
this.alert('Click me.' + evtMsg); this.alert('Click me.' + evtMsg);
} }
onSave(event?: KeyboardEvent) { onSave(event?: MouseEvent) {
let evtMsg = event ? ' Event target is ' + (<HTMLElement>event.target).textContent : ''; const evtMsg = event ? ' Event target is ' + (event.target as HTMLElement).textContent : '';
this.alert('Saved.' + evtMsg); this.alert('Saved.' + evtMsg);
if (event) { event.stopPropagation(); } if (event) { event.stopPropagation(); }
} }
@ -140,9 +144,9 @@ export class AppComponent implements AfterViewInit, OnInit {
setCurrentClasses() { setCurrentClasses() {
// CSS classes: added/removed per current state of component properties // CSS classes: added/removed per current state of component properties
this.currentClasses = { this.currentClasses = {
'saveable': this.canSave, saveable: this.canSave,
'modified': !this.isUnchanged, modified: !this.isUnchanged,
'special': this.isSpecial special: this.isSpecial
}; };
} }
// #enddocregion setClasses // #enddocregion setClasses
@ -164,7 +168,7 @@ export class AppComponent implements AfterViewInit, OnInit {
// #enddocregion trackByHeroes // #enddocregion trackByHeroes
// #docregion trackById // #docregion trackById
trackById(index: number, item: any): number { return item['id']; } trackById(index: number, item: any): number { return item.id; }
// #enddocregion trackById // #enddocregion trackById
} }

View File

@ -1,13 +1,14 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; 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 { BigHeroDetailComponent, HeroDetailComponent } from './hero-detail.component'; import { BigHeroDetailComponent, HeroDetailComponent } from './hero-detail.component';
import { ClickDirective, ClickDirective2 } from './click.directive'; import { ClickDirective, ClickDirective2 } from './click.directive';
import { HeroFormComponent } from './hero-form.component'; import { HeroFormComponent } from './hero-form.component';
import { heroSwitchComponents } from './hero-switch.components'; import { heroSwitchComponents } from './hero-switch.components';
import { SizerComponent } from './sizer.component'; import { SizerComponent } from './sizer.component';
import { SvgComponent } from './svg.component';
@NgModule({ @NgModule({
imports: [ imports: [
@ -22,7 +23,8 @@ import { SizerComponent } from './sizer.component';
heroSwitchComponents, heroSwitchComponents,
ClickDirective, ClickDirective,
ClickDirective2, ClickDirective2,
SizerComponent SizerComponent,
SvgComponent
], ],
bootstrap: [ AppComponent ] bootstrap: [ AppComponent ]
}) })

View File

@ -1,4 +1,4 @@
/* tslint:disable use-output-property-decorator directive-class-suffix */ /* tslint:disable directive-selector directive-class-suffix */
// #docplaster // #docplaster
import { Directive, ElementRef, EventEmitter, Output } from '@angular/core'; import { Directive, ElementRef, EventEmitter, Output } from '@angular/core';

View File

@ -1,5 +1,5 @@
import { Component, Input, ViewChild } from '@angular/core'; import { Component, Input, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms'; import { NgForm } from '@angular/forms';
import { Hero } from './hero'; import { Hero } from './hero';
@ -15,10 +15,11 @@ export class HeroFormComponent {
@Input() hero: Hero; @Input() hero: Hero;
@ViewChild('heroForm', {static: false}) form: NgForm; @ViewChild('heroForm', {static: false}) form: NgForm;
// tslint:disable-next-line:variable-name
private _submitMessage = ''; private _submitMessage = '';
get submitMessage() { get submitMessage() {
if (!this.form.valid) { if (this.form && !this.form.valid) {
this._submitMessage = ''; this._submitMessage = '';
} }
return this._submitMessage; return this._submitMessage;

View File

@ -0,0 +1,4 @@
svg {
display: block;
width: 100%;
}

View File

@ -0,0 +1,6 @@
<svg>
<g>
<rect x="0" y="0" width="100" height="100" [attr.fill]="fillColor" (click)="changeColor()" />
<text x="120" y="50">click the rectangle to change the fill color</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 201 B

View File

@ -0,0 +1,17 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-svg',
templateUrl: './svg.component.svg',
styleUrls: ['./svg.component.css']
})
export class SvgComponent {
fillColor = 'rgb(255, 0, 0)';
changeColor() {
const r = Math.floor(Math.random() * 256);
const g = Math.floor(Math.random() * 256);
const b = Math.floor(Math.random() * 256);
this.fillColor = `rgb(${r}, ${g}, ${b})`;
}
}

View File

@ -0,0 +1,79 @@
import { browser, element, by, ExpectedConditions } from 'protractor';
describe('Lazy Loading AngularJS Tests', function () {
const pageElements = {
homePageHref: element(by.cssContainingText('app-root nav a', 'Home')),
homePageParagraph: element(by.css('app-root app-home p')),
ajsUsersPageHref: element(by.cssContainingText('app-root nav a', 'Users')),
ajsUsersPageParagraph: element(by.css('app-root app-angular-js div p')),
notFoundPageHref: element(by.cssContainingText('app-root nav a', '404 Page')),
notFoundPageParagraph: element(by.css('app-root app-app404 p')),
};
beforeAll(async() => {
await browser.get('/');
});
it('should display \'Angular Home\' when visiting the home page', async() => {
await pageElements.homePageHref.click();
const paragraphText = await pageElements.homePageParagraph.getText();
expect(paragraphText).toEqual('Angular Home');
});
it('should display \'Users Page\' page when visiting the AngularJS page at /users', async() => {
await pageElements.ajsUsersPageHref.click();
await loadAngularJS();
const paragraphText = await pageElements.ajsUsersPageParagraph.getText();
expect(paragraphText).toEqual('Users Page');
});
it('should display \'Angular 404\' when visiting an invalid URL', async() => {
await pageElements.notFoundPageHref.click();
const paragraphText = await pageElements.notFoundPageParagraph.getText();
expect(paragraphText).toEqual('Angular 404');
});
// Workaround for https://github.com/angular/protractor/issues/4724
async function loadAngularJS() {
// Abort if `resumeBootstrap` has already occured
if (await browser.executeScript(`return '__TESTABILITY__NG1_APP_ROOT_INJECTOR__' in window;`)) {
return;
}
// Might have to re-insert the 'NG_DEFER_BOOTSTRAP!' if the name has been changed since protractor loaded the page
if (!await browser.executeScript('window.name.includes(\'NG_DEFER_BOOTSTRAP!\')')) {
await browser.executeScript('window.name = \'NG_DEFER_BOOTSTRAP!\' + name');
}
// Wait for the AngularJS bundle to download and initialize
await browser.wait(ExpectedConditions.presenceOf(element(by.css('app-root app-angular-js'))), 5000, 'AngularJS app');
// Run the protractor pre-bootstrap logic and resumeBootstrap
// Based on https://github.com/angular/protractor/blob/5.3.0/lib/browser.ts#L950-L969
{
let moduleNames = [];
for (const {name, script, args} of browser.mockModules_) {
moduleNames.push(name);
await browser.executeScriptWithDescription(script, 'add mock module ' + name, ...args);
}
await browser.executeScriptWithDescription(
// TODO: must manually assign __TESTABILITY__NG1_APP_ROOT_INJECTOR__ (https://github.com/angular/angular/issues/22723)
`window.__TESTABILITY__NG1_APP_ROOT_INJECTOR__ = angular.resumeBootstrap(arguments[0]) `
+ `|| angular.element('app-angular-js').injector();`,
'resume bootstrap',
moduleNames
);
}
// Wait for the initial AngularJS page to finish loading
await browser.waitForAngular();
}
});

View File

@ -0,0 +1,3 @@
{
"projectType": "cli-ajs"
}

View File

@ -1,14 +1,22 @@
import { Component, OnInit, ElementRef } from '@angular/core'; import { Component, OnInit, OnDestroy, ElementRef } from '@angular/core';
import { LazyLoaderService } from '../lazy-loader.service'; import { LazyLoaderService } from '../lazy-loader.service';
@Component({ @Component({
selector: 'app-angular-js', selector: 'app-angular-js',
template: '<div ng-view></div>' template: '<div ng-view></div>'
}) })
export class AngularJSComponent implements OnInit { export class AngularJSComponent implements OnInit, OnDestroy {
constructor(private lazyLoader: LazyLoaderService, private elRef: ElementRef) {} constructor(
private lazyLoader: LazyLoaderService,
private elRef: ElementRef
) {}
ngOnInit() { ngOnInit() {
this.lazyLoader.load(this.elRef.nativeElement); this.lazyLoader.load(this.elRef.nativeElement);
} }
ngOnDestroy() {
this.lazyLoader.destroy();
}
} }

View File

@ -19,7 +19,6 @@ import { App404Component } from './app404/app404.component';
BrowserModule, BrowserModule,
AppRoutingModule AppRoutingModule
], ],
providers: [],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { } export class AppModule { }

View File

@ -1,23 +1,25 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import * as angular from 'angular';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class LazyLoaderService { export class LazyLoaderService {
bootstrapped = false; private app: angular.auto.IInjectorService;
load(el: HTMLElement): void { load(el: HTMLElement): void {
if (this.bootstrapped) {
return;
}
import('./angularjs-app').then(app => { import('./angularjs-app').then(app => {
try { try {
app.bootstrap(el); this.app = app.bootstrap(el);
this.bootstrapped = true;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
}); });
} }
destroy() {
if (this.app) {
this.app.get('$rootScope').$destroy();
}
}
} }

View File

@ -0,0 +1,181 @@
# Accessibility in Angular
The web is used by a wide variety of people, including those who have visual or motor impairments.
A variety of assistive technologies are available that make it much easier for these groups to
interact with web-based software applications.
In addition, designing an application to be more accessible generally improves the user experience for all users.
For an in-depth introduction to issues and techniques for designing accessible applications, see the [Accessibility](https://developers.google.com/web/fundamentals/accessibility/#what_is_accessibility) section of the Google's [Web Fundamentals](https://developers.google.com/web/fundamentals/).
This page discusses best practices for designing Angular applications that
work well for all users, including those who rely on assistive technologies.
## Accessibility attributes
Building accessible web experience often involves setting [ARIA attributes](https://developers.google.com/web/fundamentals/accessibility/semantics-aria)
to provide semantic meaning where it might otherwise be missing.
Use [attribute binding](guide/template-syntax#attribute-binding) template syntax to control the values of accessibility-related attributes.
When binding to ARIA attributes in Angular, you must use the `attr.` prefix, as the ARIA
specification depends specifically on HTML attributes rather than properties on DOM elements.
```html
<!-- Use attr. when binding to an ARIA attribute -->
<button [attr.aria-label]="myActionLabel">...</button>
```
Note that this syntax is only necessary for attribute _bindings_.
Static ARIA attributes require no extra syntax.
```html
<!-- Static ARIA attributes require no extra syntax -->
<button aria-label="Save document">...</button>
```
NOTE:
<div class="alert is-helpful">
By convention, HTML attributes use lowercase names (`tabindex`), while properties use camelCase names (`tabIndex`).
See the [Template Syntax](https://angular.io/guide/template-syntax#html-attribute-vs-dom-property) guide for more background on the difference between attributes and properties.
</div>
## Angular UI components
The [Angular Material](https://material.angular.io/) library, which is maintained by the Angular team, is a suite of reusable UI components that aims to be fully accessible.
The [Component Development Kit (CDK)](https://material.angular.io/cdk/categories) includes the `a11y` package that provides tools to support various areas of accessibility.
For example:
* `LiveAnnouncer` is used to announce messages for screen-reader users using an `aria-live` region. See the W3C documentation for more information on [aria-live regions](https://www.w3.org/WAI/PF/aria-1.1/states_and_properties#aria-live).
* The `cdkTrapFocus` directive traps Tab-key focus within an element. Use it to create accessible experience for components like modal dialogs, where focus must be constrained.
For full details of these and other tools, see the [Angular CDK accessibility overview](https://material.angular.io/cdk/a11y/overview).
### Augmenting native elements
Native HTML elements capture a number of standard interaction patterns that are important to accessibility.
When authoring Angular components, you should re-use these native elements directly when possible, rather than re-implementing well-supported behaviors.
For example, instead of creating a custom element for a new variety of button, you can create a component that uses an attribute selector with a native `<button>` element.
This most commonly applies to `<button>` and `<a>`, but can be used with many other types of element.
You can see examples of this pattern in Angular Material: [`MatButton`](https://github.com/angular/components/blob/master/src/material/button/button.ts#L66-L68), [`MatTabNav`](https://github.com/angular/components/blob/master/src/material/tabs/tab-nav-bar/tab-nav-bar.ts#L67), [`MatTable`](https://github.com/angular/components/blob/master/src/material/table/table.ts#L17).
### Using containers for native elements
Sometimes using the appropriate native element requires a container element.
For example, the native `<input>` element cannot have children, so any custom text entry components need
to wrap an `<input>` with additional elements.
While you might just include the `<input>` in your custom component's template,
this makes it impossible for users of the component to set arbitrary properties and attributes to the input element.
Instead, you can create a container component that uses content projection to include the native control in the
component's API.
You can see [`MatFormField`](https://material.angular.io/components/form-field/overview) as an example of this pattern.
## Case study: Building a custom progress bar
The following example shows how to make a simple progress bar accessible by using host binding to control accessibility-related attributes.
* The component defines an accessibility-enabled element with both the standard HTML attribute `role`, and ARIA attributes. The ARIA attribute `aria-valuenow` is bound to the user's input.
```ts
import { Component, Input } from '@angular/core';
/**
* Example progressbar component.
*/
@Component({
selector: 'example-progressbar',
template: `<div class="bar" [style.width.%]="value"></div>`,
styleUrls: ['./progress-bar.css'],
host: {
// Sets the role for this component to "progressbar"
role: 'progressbar',
// Sets the minimum and maximum values for the progressbar role.
'aria-valuemin': '0',
'aria-valuemax': '0',
// Binding that updates the current value of the progressbar.
'[attr.aria-valuenow]': 'value',
}
})
export class ExampleProgressbar {
/** Current value of the progressbar. */
@Input() value: number = 0;
}
```
* In the template, the `aria-label` attribute ensures that the control is accessible to screen readers.
```html
<label>
Enter an example progress value
<input type="number" min="0" max="100"
[value]="progress" (input)="progress = $event.target.value">
</label>
<!-- The user of the progressbar sets an aria-label to communicate what the progress means. -->
<example-progressbar [value]="progress" aria-label="Example of a progress bar">
</example-progressbar>
```
[See the full example in StackBlitz](https://stackblitz.com/edit/angular-kn5jdi?file=src%2Fapp%2Fapp.component.html).
## Routing and focus management
Tracking and controlling [focus](https://developers.google.com/web/fundamentals/accessibility/focus/) in a UI is an important consideration in designing for accessibility.
When using Angular routing, you should decide where page focus goes upon navigation.
To avoid relying solely on visual cues, you need to make sure your routing code updates focus after page navigation.
Use the `NavigationEnd` event from the `Router` service to know when to update
focus.
The following example shows how to find and focus the main content header in the DOM after navigation.
```ts
router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(() => {
const mainHeader = document.querySelector('#main-content-header')
if (mainHeader) {
mainHeader.focus();
}
});
```
In a real application, the element that receives focus will depend on your specific
application structure and layout.
The focused element should put users in a position to immediately move into the main content that has just been routed into view.
You should avoid situations where focus returns to the `body` element after a route change.
## Additional resources
* [Accessibility - Google Web Fundamentals](https://developers.google.com/web/fundamentals/accessibility)
* [ARIA specification and authoring practices](https://www.w3.org/TR/wai-aria/)
* [Material Design - Accessibility](https://material.io/design/usability/accessibility.html)
* [Smashing Magazine](https://www.smashingmagazine.com/search/?q=accessibility)
* [Inclusive Components](https://inclusive-components.design/)
* [Accessibility Resources and Code Examples](https://dequeuniversity.com/resources/)
* [W3C - Web Accessibility Initiative](https://www.w3.org/WAI/people-use-web/)
* [Rob Dodson A11ycasts](https://www.youtube.com/watch?v=HtTyRajRuyY)
* [Codelyzer](http://codelyzer.com/rules/) provides linting rules that can help you make sure your code meets accessibility standards.
Books
* "A Web for Everyone: Designing Accessible User Experiences", Sarah Horton and Whitney Quesenbery
* "Inclusive Design Patterns", Heydon Pickering

View File

@ -29,7 +29,7 @@ ng generate app-shell --client-project my-app --universal-project server-app
After running this command you will notice that the `angular.json` configuration file has been updated to add two new targets, with a few other changes. After running this command you will notice that the `angular.json` configuration file has been updated to add two new targets, with a few other changes.
<code-example format="." language="none" linenums="false"> <code-example format="." language="json" linenums="false">
"server": { "server": {
"builder": "@angular-devkit/build-angular:server", "builder": "@angular-devkit/build-angular:server",
"options": { "options": {

View File

@ -53,7 +53,7 @@ Angular supports most recent browsers. This includes the following specific vers
IE IE
</td> </td>
<td> <td>
11<br>10<br>9 11, 10, 9
</td> </td>
</tr> </tr>
<tr> <tr>
@ -89,7 +89,7 @@ Angular supports most recent browsers. This includes the following specific vers
</td> </td>
<td> <td>
Nougat (7.0)<br>Marshmallow (6.0)<br>Lollipop (5.0, 5.1)<br>KitKat (4.4) Nougat (7.0), Marshmallow (6.0), Lollipop (5.0, 5.1), KitKat (4.4)
</td> </td>
</tr> </tr>
@ -127,25 +127,27 @@ In Angular CLI version 8 and higher, applications are built using *differential
This strategy allows you to continue to build your web application to support multiple browsers, but only load the necessary code that the browser needs. This strategy allows you to continue to build your web application to support multiple browsers, but only load the necessary code that the browser needs.
For more information about how this works, see [Differential Loading](guide/deployment#differential-loading) in the [Deployment guide](guide/deployment). For more information about how this works, see [Differential Loading](guide/deployment#differential-loading) in the [Deployment guide](guide/deployment).
## Enabling polyfills ## Enabling polyfills with CLI projects
[Angular CLI](cli) users enable polyfills through the `src/polyfills.ts` file that The [Angular CLI](cli) provides support for polyfills.
the CLI created with your project. If you are not using the CLI to create your projects, see [Polyfill instructions for non-CLI users](#non-cli).
When you create a project with the `ng new` command, a `src/polyfills.ts` configuration file is created as part of your project folder.
This file incorporates the mandatory and many of the optional polyfills as JavaScript `import` statements. This file incorporates the mandatory and many of the optional polyfills as JavaScript `import` statements.
The npm packages for the _mandatory_ polyfills (such as `zone.js`) were installed automatically for you when you created your project and their corresponding `import` statements are ready to go. You probably won't touch these. * The npm packages for the [_mandatory_ polyfills](#polyfill-libs) (such as `zone.js`) are installed automatically for you when you create your project with `ng new`, and their corresponding `import` statements are already enabled in the `src/polyfills.ts` configuration file.
But if you need an optional polyfill, you'll have to install its npm package. * If you need an _optional_ polyfill, you must install its npm package, then uncomment or create the corresponding import statement in the `src/polyfills.ts` configuration file.
For example, [if you need the web animations polyfill](http://caniuse.com/#feat=web-animation), you could install it with `npm`, using the following command (or the `yarn` equivalent):
For example, if you need the optional [web animations polyfill](http://caniuse.com/#feat=web-animation), you could install it with `npm`, using the following command (or the `yarn` equivalent):
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
# note that the web-animations-js polyfill is only here as an example # install the optional web animations polyfill
# it isn't a strict requirement of Angular anymore (more below)
npm install --save web-animations-js npm install --save web-animations-js
</code-example> </code-example>
Then open the `polyfills.ts` file and un-comment the corresponding `import` statement as in the following example: You can then add the import statement in the `src/polyfills.ts` file.
For many polyfills, you can simply un-comment the corresponding `import` statement in the file, as in the following example.
<code-example header="src/polyfills.ts"> <code-example header="src/polyfills.ts">
/** /**
@ -155,23 +157,14 @@ Then open the `polyfills.ts` file and un-comment the corresponding `import` stat
import 'web-animations-js'; // Run `npm install --save web-animations-js`. import 'web-animations-js'; // Run `npm install --save web-animations-js`.
</code-example> </code-example>
If you can't find the polyfill you want in `polyfills.ts`, If the polyfill you want is not already in `polyfills.ts` file, add the `import` statement by hand.
add it yourself, following the same pattern:
1. install the npm package
1. `import` the file in `polyfills.ts`
<div class="alert is-helpful">
Non-CLI users should follow the instructions [below](#non-cli).
</div>
{@a polyfill-libs} {@a polyfill-libs}
### Mandatory polyfills ### Mandatory polyfills
These are the polyfills required to run an Angular application on each supported browser: These are the polyfills required to run an Angular application on each supported browser:
<table> <table>
<tr style="vertical-align: top"> <tr style="vertical-align: top">
@ -189,26 +182,13 @@ These are the polyfills required to run an Angular application on each supported
<tr style="vertical-align: top"> <tr style="vertical-align: top">
<td> <td>
Chrome, Firefox, Edge, Safari 9+ Chrome, Firefox, Edge, <br>
Safari, Android, IE10+
</td> </td>
<td> <td>
[ES7/reflect](guide/browser-support#core-es7-reflect) (JIT only) [ES2015](guide/browser-support#core-es6)
</td>
</tr>
<tr style="vertical-align: top">
<td>
Safari 7 & 8, IE10 & 11, Android 4.1+
</td>
<td>
[ES6](guide/browser-support#core-es6)
</td> </td>
@ -222,7 +202,7 @@ These are the polyfills required to run an Angular application on each supported
<td> <td>
[ES6<br>classList](guide/browser-support#classlist) ES2015<br>[classList](guide/browser-support#classlist)
</td> </td>
@ -235,12 +215,6 @@ These are the polyfills required to run an Angular application on each supported
Some features of Angular may require additional polyfills. Some features of Angular may require additional polyfills.
For example, the animations library relies on the standard web animation API, which is only available in Chrome and Firefox today.
(note that the dependency of web-animations-js in Angular is only necessary if `AnimationBuilder` is used.)
Here are the features which may require additional polyfills:
<table> <table>
<tr style="vertical-align: top"> <tr style="vertical-align: top">
@ -263,31 +237,8 @@ Here are the features which may require additional polyfills:
<td> <td>
[JIT compilation](guide/aot-compiler). [AnimationBuilder](api/animations/AnimationBuilder).
(Standard animation support does not require polyfills.)
Required to reflect for metadata.
</td>
<td>
[ES7/reflect](guide/browser-support#core-es7-reflect)
</td>
<td>
All current browsers. Enabled by default.
Can remove if you always use AOT and only use Angular decorators.
</td>
</tr>
<tr style="vertical-align: top">
<td>
[Animations](guide/animations)
<br>Only if `Animation Builder` is used within the application--standard
animation support in Angular doesn't require any polyfills (as of NG6).
</td> </td>
@ -298,8 +249,9 @@ Here are the features which may require additional polyfills:
</td> </td>
<td> <td>
<p>If AnimationBuilder is used then the polyfill will enable scrubbing <p>If AnimationBuilder is used, enables scrubbing
support for IE/Edge and Safari (Chrome and Firefox support this natively).</p> support for IE/Edge and Safari.
(Chrome and Firefox support this natively).</p>
</td> </td>
</tr> </tr>
@ -308,15 +260,10 @@ Here are the features which may require additional polyfills:
<td> <td>
If you use the following deprecated i18n pipes: If you use the following deprecated i18n pipes:
[date](api/common/DeprecatedDatePipe), [date](api/common/DeprecatedDatePipe),
[currency](api/common/DeprecatedCurrencyPipe), [currency](api/common/DeprecatedCurrencyPipe),
[decimal](api/common/DeprecatedDecimalPipe), [decimal](api/common/DeprecatedDecimalPipe),
[percent](api/common/DeprecatedPercentPipe) [percent](api/common/DeprecatedPercentPipe)
</td> </td>
@ -337,9 +284,7 @@ Here are the features which may require additional polyfills:
<td> <td>
[NgClass](api/common/NgClass) [NgClass](api/common/NgClass) on SVG elements
on SVG elements
</td> </td>
<td> <td>
@ -358,9 +303,7 @@ Here are the features which may require additional polyfills:
<td> <td>
[Http](guide/http) [Http](guide/http) when sending and receiving binary data
when sending and receiving binary data
</td> </td>
<td> <td>
@ -383,9 +326,8 @@ Here are the features which may require additional polyfills:
<td> <td>
[Router](guide/router) [Router](guide/router) when using
[hash-based routing](guide/router#appendix-locationstrategy-and-browser-url-styles)
when using [hash-based routing](guide/router#appendix-locationstrategy-and-browser-url-styles)
</td> </td>
<td> <td>
@ -404,8 +346,9 @@ Here are the features which may require additional polyfills:
### Suggested polyfills ## ### Suggested polyfills
Below are the polyfills which are used to test the framework itself. They are a good starting point for an application.
The following polyfills are used to test the framework itself. They are a good starting point for an application.
<table> <table>
@ -426,24 +369,6 @@ Below are the polyfills which are used to test the framework itself. They are a
</tr> </tr>
<tr>
<td>
<a id='core-es7-reflect' href="https://github.com/zloirock/core-js/tree/v2/fn/reflect">ES7/reflect</a>
</td>
<td>
MIT
</td>
<td>
0.5KB
</td>
</tr>
<tr> <tr>
<td> <td>
@ -466,7 +391,7 @@ Below are the polyfills which are used to test the framework itself. They are a
<td> <td>
<a id='core-es6' href="https://github.com/zloirock/core-js">ES6</a> <a id='core-es6' href="https://github.com/zloirock/core-js">ES2015</a>
</td> </td>
@ -595,11 +520,14 @@ Below are the polyfills which are used to test the framework itself. They are a
computed with the <a href="http://closure-compiler.appspot.com/home">closure compiler</a>. computed with the <a href="http://closure-compiler.appspot.com/home">closure compiler</a>.
{@a non-cli} {@a non-cli}
## Polyfills for non-CLI users ## Polyfills for non-CLI users
If you are not using the CLI, you should add your polyfill scripts directly to the host web page (`index.html`), perhaps like this. If you are not using the CLI, add your polyfill scripts directly to the host web page (`index.html`).
<code-example header="src/index.html"> For example:
<code-example header="src/index.html" language="html" linenums="false">
&lt;!-- pre-zone polyfills --> &lt;!-- pre-zone polyfills -->
&lt;script src="node_modules/core-js/client/shim.min.js">&lt;/script> &lt;script src="node_modules/core-js/client/shim.min.js">&lt;/script>
&lt;script src="node_modules/web-animations-js/web-animations.min.js">&lt;/script> &lt;script src="node_modules/web-animations-js/web-animations.min.js">&lt;/script>

View File

@ -185,8 +185,7 @@ is available to <code>declarations</code> of this module.</p>
</td> </td>
</tr><tr> </tr><tr>
<td><code><b>@Injectable()</b><br>class MyService() {}</code></td> <td><code><b>@Injectable()</b><br>class MyService() {}</code></td>
<td><p>Declares that a class has dependencies that should be injected into the constructor when the dependency injector is creating an instance of this class. <td><p>Declares that a class can be provided and injected by other classes. Without this decorator, the compiler won't generate enough metadata to allow the class to be created properly when it's injected somewhere.</p>
</p>
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>

View File

@ -153,16 +153,13 @@ The list is by no means exhaustive, but should provide you with a good starting
(https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/): (https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/):
<code-example format="."> <code-example format=".">
RewriteEngine On RewriteEngine On
&#35 If an existing asset or directory is requested go to it as it is &#35 If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR] RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L] RewriteRule ^ - [L]<br>
&#35 If the requested resource doesn't exist, use index.html &#35 If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html RewriteRule ^ /index.html
</code-example> </code-example>
@ -170,18 +167,15 @@ The list is by no means exhaustive, but should provide you with a good starting
[Front Controller Pattern Web Apps](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps), [Front Controller Pattern Web Apps](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps),
modified to serve `index.html`: modified to serve `index.html`:
<code-example format="."> ```
try_files $uri $uri/ /index.html;
try_files $uri $uri/ /index.html; ```
</code-example>
* [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown * [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown
[here](http://stackoverflow.com/a/26152011/2116927): [here](http://stackoverflow.com/a/26152011/2116927):
<code-example format='.' linenums="false"> <code-example format='.' language="xml" linenums="false">
&lt;system.webServer&gt; &lt;system.webServer&gt;
&lt;rewrite&gt; &lt;rewrite&gt;
&lt;rules&gt; &lt;rules&gt;
@ -196,7 +190,6 @@ modified to serve `index.html`:
&lt;/rules&gt; &lt;/rules&gt;
&lt;/rewrite&gt; &lt;/rewrite&gt;
&lt;/system.webServer&gt; &lt;/system.webServer&gt;
</code-example> </code-example>
@ -214,13 +207,11 @@ and to
* [Firebase hosting](https://firebase.google.com/docs/hosting/): add a * [Firebase hosting](https://firebase.google.com/docs/hosting/): add a
[rewrite rule](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites). [rewrite rule](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites).
<code-example format="."> <code-example format="." language="json">
"rewrites": [ { "rewrites": [ {
"source": "**", "source": "**",
"destination": "/index.html" "destination": "/index.html"
} ] } ]
</code-example> </code-example>
{@a cors} {@a cors}
@ -412,7 +403,7 @@ Differential loading, which is supported by default in Angular CLI version 8 and
Differential loading is a strategy where the CLI builds two separate bundles as part of your deployed application. Differential loading is a strategy where the CLI builds two separate bundles as part of your deployed application.
* The first bundle contains modern ES1015 syntax, takes advantage of built-in support in modern browsers, ships less polyfills, and results in a smaller bundle size. * The first bundle contains modern ES2015 syntax, takes advantage of built-in support in modern browsers, ships less polyfills, and results in a smaller bundle size.
* The second bundle contains code in the old ES5 syntax, along with all necessary polyfills. This results in a larger bundle size, but supports older browsers. * The second bundle contains code in the old ES5 syntax, along with all necessary polyfills. This results in a larger bundle size, but supports older browsers.
@ -446,23 +437,19 @@ When you create a production build using [`ng build --prod`](cli/build), the CLI
The `index.html` file is also modified during the build process to include script tags that enable differential loading. See the sample output below from the `index.html` file produced during a build using `ng build`. The `index.html` file is also modified during the build process to include script tags that enable differential loading. See the sample output below from the `index.html` file produced during a build using `ng build`.
<code-example language="html" format="." linenums="false"> <code-example language="html" format="." linenums="false">
&lt;body>
<!-- ... --> &lt;app-root>&lt;/app-root>
<body> &lt;script src="runtime-es2015.js" type="module">&lt;/script>
<app-root></app-root> &lt;script src="runtime-es5.js" nomodule>&lt;/script>
<script src="runtime-es2015.js" type="module"></script> &lt;script src="polyfills-es2015.js" type="module">&lt;/script>
<script src="runtime-es5.js" nomodule></script> &lt;script src="polyfills-es5.js" nomodule>&lt;/script>
<script src="polyfills-es2015.js" type="module"></script> &lt;script src="styles-es2015.js" type="module">&lt;/script>
<script src="polyfills-es5.js" nomodule></script> &lt;script src="styles-es5.js" nomodule>&lt;/script>
<script src="styles-es2015.js" type="module"></script> &lt;script src="vendor-es2015.js" type="module">&lt;/script>
<script src="styles-es5.js" nomodule></script> &lt;script src="vendor-es5.js" nomodule>&lt;/script>
<script src="vendor-es2015.js" type="module"></script> &lt;script src="main-es2015.js" type="module">&lt;/script>
<script src="vendor-es5.js" nomodule></script> &lt;script src="main-es5.js" nomodule>&lt;/script>
<script src="main-es2015.js" type="module"></script> &lt;/body>
<script src="main-es5.js" nomodule></script>
</body>
<!-- ... -->
</code-example> </code-example>
Each script tag has a `type="module"` or `nomodule` attribute. Browsers with native support for ES modules only load the scripts with the `module` type attribute and ignore scripts with the `nomodule` attribute. Legacy browsers only load the scripts with the `nomodule` attribute, and ignore the script tags with the `module` type that load ES modules. Each script tag has a `type="module"` or `nomodule` attribute. Browsers with native support for ES modules only load the scripts with the `module` type attribute and ignore scripts with the `nomodule` attribute. Legacy browsers only load the scripts with the `nomodule` attribute, and ignore the script tags with the `module` type that load ES modules.
@ -523,7 +510,7 @@ By default, legacy browsers such as IE 9-11 are ignored, and the compilation tar
<div class="alert is-important"> <div class="alert is-important">
To see which browsers are supported with the above configuration, see which settings meet to your browser support requirements, see the [Browserslist compatibility page](https://browserl.ist/?q=%3E+0.5%25%2C+last+2+versions%2C+Firefox+ESR%2C+Chrome+41%2C+not+dead%2C+not+IE+9-11). To see which browsers are supported with the above configuration, see which settings meet to your browser support requirements, see the [Browserslist compatibility page](https://browserl.ist/?q=%3E+0.5%25%2C+last+2+versions%2C+Firefox+ESR%2C+not+dead%2C+not+IE+9-11).
</div> </div>
@ -660,7 +647,7 @@ ng test --configuration es5
### Configuring the e2e command ### Configuring the e2e command
Create an ES5 serve configuration as explained above (link to the above serve section), and configuration an ES5 configuration for the E2E target. Create an [ES5 serve configuration](guide/deployment#configuring-serve-for-es5) as explained above, and configuration an ES5 configuration for the E2E target.
<code-example language="json" format="." linenums="false"> <code-example language="json" format="." linenums="false">

View File

@ -368,7 +368,7 @@ These two properties have subtle differences, so switching to `textContent` unde
All of the `wtf*` APIs are deprecated and will be removed in a future version. All of the `wtf*` APIs are deprecated and will be removed in a future version.
{@a webworker-apps} {@a webworker-apps}
### Running Angular applications in platform-webworker ### Running Angular applications in platform-webworker
The `@angular/platform-*` packages enable Angular to be run in different contexts. For examples, The `@angular/platform-*` packages enable Angular to be run in different contexts. For examples,
`@angular/platform-server` enables Angular to be run on the server, and `@angular/platform-browser` `@angular/platform-server` enables Angular to be run on the server, and `@angular/platform-browser`
@ -382,7 +382,7 @@ worker is not the best strategy for most applications.
Going forward, we will focus our efforts related to web workers around their primary use case of Going forward, we will focus our efforts related to web workers around their primary use case of
offloading CPU-intensive, non-critical work needed for initial rendering (such as in-memory search offloading CPU-intensive, non-critical work needed for initial rendering (such as in-memory search
and image processing). Learn more in the and image processing). Learn more in the
[guide to Using Web Workers with the Angular CLI](guide/web-worker). [guide to Using Web Workers with the Angular CLI](guide/web-worker).
As of Angular version 8, all `platform-webworker` APIs are deprecated. As of Angular version 8, all `platform-webworker` APIs are deprecated.
@ -465,3 +465,99 @@ For more information about using `@angular/common/http`, see the [HttpClient gui
| `MockBackend` | [`HttpTestingController`](/api/common/http/testing/HttpTestingController) | | `MockBackend` | [`HttpTestingController`](/api/common/http/testing/HttpTestingController) |
| `MockConnection` | [`HttpTestingController`](/api/common/http/testing/HttpTestingController) | | `MockConnection` | [`HttpTestingController`](/api/common/http/testing/HttpTestingController) |
## Renderer to Renderer2 migration
### Migration Overview
The `Renderer` class has been marked as deprecated since Angular version 4. This section provides guidance on migrating from this deprecated API to the newer `Renderer2` API and what it means for your app.
### Why should I migrate to Renderer2?
The deprecated `Renderer` class has been removed in version 9 of Angular, so it's necessary to migrate to a supported API. Using `Renderer2` is the recommended strategy because it supports a similar set of functionality to `Renderer`. The API surface is quite large (with 19 methods), but the schematic should simplify this process for your applications.
### Is there action required on my end?
No. The schematic should handle most cases with the exception of `Renderer.animate()` and `Renderer.setDebugInfo()`, which already arent supported.
### What are the `__ngRendererX` methods? Why are they necessary?
Some methods either don't have exact equivalents in `Renderer2`, or they correspond to more than one expression. For example, both renderers have a `createElement()` method, but they're not equal because a call such as `renderer.createElement(parentNode, namespaceAndName)` in the `Renderer` corresponds to the following block of code in `Renderer2`:
```ts
const [namespace, name] = splitNamespace(namespaceAndName);
const el = renderer.createElement(name, namespace);
if (parentNode) {
renderer.appendChild(parentNode, el);
}
return el;
```
Migration has to guarantee that the return values of functions and types of variables stay the same. To handle the majority of cases safely, the schematic declares helper functions at the bottom of the user's file. These helpers encapsulate your own logic and keep the replacements inside your code down to a single function call. Here's an example of how the `createElement()` migration looks:
**Before:**
```ts
public createAndAppendElement() {
const el = this.renderer.createElement('span');
el.textContent = 'hello world';
return el;
}
```
**After:**
<code-example linenums=false>
public createAndAppendElement() {
const el = __ngRendererCreateElement(this.renderer, this.element, 'span');
el.textContent = 'hello world';
return el;
}
// Generated code at the bottom of the file
__ngRendererCreateElement(renderer: any, parentNode: any, nameAndNamespace: any) {
const [namespace, name] = __ngRendererSplitNamespace(namespaceAndName);
const el = renderer.createElement(name, namespace);
if (parentNode) {
renderer.appendChild(parentNode, el);
}
return el;
}
__ngRendererSplitNamespace(nameAndNamespace: any) {
// returns the split name and namespace
}
</code-example>
When implementing these helper functions, the schematic ensures that they're only declared once per file and that their names are unique enough that there's a small chance of colliding with pre-existing functions in your code. The schematic also keeps their parameter types as `any` so that it doesn't have to insert extra logic that ensures that their values have the correct type.
### Im a library author. Should I run this migration?
**Library authors should definitely use this migration to move away from the `Renderer`. Otherwise, the libraries won't work with applications built with version 9.**
### Full list of method migrations
The following table shows all methods that the migration maps from `Renderer` to `Renderer2`.
|Renderer|Renderer2|
|---|---|
|`listen(renderElement, name, callback)`|`listen(renderElement, name, callback)`|
|`setElementProperty(renderElement, propertyName, propertyValue)`|`setProperty(renderElement, propertyName, propertyValue)`|
|`setText(renderNode, text)`|`setValue(renderNode, text)`|
|`listenGlobal(target, name, callback)`|`listen(target, name, callback)`|
|`selectRootElement(selectorOrNode, debugInfo?)`|`selectRootElement(selectorOrNode)`|
|`createElement(parentElement, name, debugInfo?)`|`appendChild(parentElement, createElement(name))`|
|`setElementStyle(el, style, value?)`|`value == null ? removeStyle(el, style) : setStyle(el, style, value)`
|`setElementAttribute(el, name, value?)`|`attributeValue == null ? removeAttribute(el, name) : setAttribute(el, name, value)`
|`createText(parentElement, value, debugInfo?)`|`appendChild(parentElement, createText(value))`|
|`createTemplateAnchor(parentElement)`|`appendChild(parentElement, createComment(''))`|
|`setElementClass(renderElement, className, isAdd)`|`isAdd ? addClass(renderElement, className) : removeClass(renderElement, className)`|
|`projectNodes(parentElement, nodes)`|`for (let i = 0; i < nodes.length; i<ins></ins>) { appendChild(parentElement, nodes<i>); }`|
|`attachViewAfter(node, viewRootNodes)`|`const parentElement = parentNode(node); const nextSibling = nextSibling(node); for (let i = 0; i < viewRootNodes.length; i<ins></ins>) { insertBefore(parentElement, viewRootNodes<i>, nextSibling);}`|
|`detachView(viewRootNodes)`|`for (let i = 0; i < viewRootNodes.length; i<ins></ins>) {const node = viewRootNodes<i>; const parentElement = parentNode(node); removeChild(parentElement, node);}`|
|`destroyView(hostElement, viewAllNodes)`|`for (let i = 0; i < viewAllNodes.length; i<ins></ins>) { destroyNode(viewAllNodes<i>); }`|
|`setBindingDebugInfo()`|This function is a noop in `Renderer2`.|
|`createViewRoot(hostElement)`|Should be replaced with a reference to `hostElement`|
|`invokeElementMethod(renderElement, methodName, args?)`|`(renderElement as any)<methodName>.apply(renderElement, args);`|
|`animate(element, startingStyles, keyframes, duration, delay, easing, previousPlayers?)`|Throws an error (same behavior as `Renderer.animate()`)|

View File

@ -1,12 +1,5 @@
# Entry Components # Entry Components
#### Prerequisites:
A basic understanding of the following concepts:
* [Bootstrapping](guide/bootstrapping).
<hr />
An entry component is any component that Angular loads imperatively, (which means youre not referencing it in the template), by type. You specify an entry component by bootstrapping it in an NgModule, or including it in a routing definition. An entry component is any component that Angular loads imperatively, (which means youre not referencing it in the template), by type. You specify an entry component by bootstrapping it in an NgModule, or including it in a routing definition.
<div class="alert is-helpful"> <div class="alert is-helpful">

View File

@ -1,12 +1,6 @@
# Feature Modules # Feature Modules
Feature modules are NgModules for the purpose of organizing code. Feature modules are NgModules for the purpose of organizing code.
#### Prerequisites
A basic understanding of the following:
* [Bootstrapping](guide/bootstrapping).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
* [Frequently Used Modules](guide/frequent-ngmodules).
For the final sample app with a feature module that this page describes, For the final sample app with a feature module that this page describes,
see the <live-example></live-example>. see the <live-example></live-example>.

View File

@ -1,12 +1,5 @@
# Frequently Used Modules # Frequently Used Modules
#### Prerequisites
A basic understanding of [Bootstrapping](guide/bootstrapping).
<hr>
An Angular app needs at least one module that serves as the root module. An Angular app needs at least one module that serves as the root module.
As you add features to your app, you can add them in modules. As you add features to your app, you can add them in modules.
The following are frequently used Angular modules with examples The following are frequently used Angular modules with examples

View File

@ -454,10 +454,9 @@ A form of property [data binding](#data-binding) in which a [template expression
That text can be concatenated with neighboring text before it is assigned to an element property That text can be concatenated with neighboring text before it is assigned to an element property
or displayed between element tags, as in this example. or displayed between element tags, as in this example.
<code-example language="html" escape="html"> ```html
<label>My current hero is {{hero.name}}</label> <label>My current hero is {{hero.name}}</label>
```
</code-example>
Read more about [interpolation](guide/template-syntax#interpolation) in [Template Syntax](guide/template-syntax). Read more about [interpolation](guide/template-syntax#interpolation) in [Template Syntax](guide/template-syntax).

View File

@ -1,23 +1,13 @@
# Lazy Loading Feature Modules # Lazy Loading Feature Modules
#### Prerequisites
A basic understanding of the following:
* [Feature Modules](guide/feature-modules).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
* [Frequently Used Modules](guide/frequent-ngmodules).
* [Types of Feature Modules](guide/module-types).
* [Routing and Navigation](guide/router).
For the final sample app with two lazy loaded modules that this page describes, see the
<live-example></live-example>.
<hr>
## High level view ## High level view
By default, NgModules are eagerly loaded, which means that as soon as the app loads, so do all the NgModules, whether or not they are immediately necessary. For large apps with lots of routes, consider lazy loading&mdash;a design pattern that loads NgModules as needed. Lazy loading helps keep initial By default, NgModules are eagerly loaded, which means that as soon as the app loads, so do all the NgModules, whether or not they are immediately necessary. For large apps with lots of routes, consider lazy loading&mdash;a design pattern that loads NgModules as needed. Lazy loading helps keep initial
bundle sizes smaller, which in turn helps decrease load times. bundle sizes smaller, which in turn helps decrease load times.
For the final sample app with two lazy loaded modules that this page describes, see the
<live-example></live-example>.
There are three main steps to setting up a lazy loaded feature module: There are three main steps to setting up a lazy loaded feature module:
1. Create the feature module. 1. Create the feature module.

View File

@ -1,16 +1,5 @@
# Types of Feature Modules # Types of Feature Modules
#### Prerequisites
A basic understanding of the following concepts:
* [Feature Modules](guide/feature-modules).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
* [Frequently Used Modules](guide/frequent-ngmodules).
<hr>
There are five general categories of feature modules which There are five general categories of feature modules which
tend to fall into the following groups: tend to fall into the following groups:

View File

@ -1,15 +1,5 @@
# NgModule API # NgModule API
#### Prerequisites
A basic understanding of the following concepts:
* [Bootstrapping](guide/bootstrapping).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
<hr />
## Purpose of `@NgModule`
At a high level, NgModules are a way to organize Angular apps At a high level, NgModules are a way to organize Angular apps
and they accomplish this through the metadata in the `@NgModule` and they accomplish this through the metadata in the `@NgModule`
decorator. decorator.

View File

@ -1,13 +1,5 @@
# NgModule FAQs # NgModule FAQs
#### Prerequisites:
A basic understanding of the following concepts:
* [NgModules](guide/ngmodules).
<hr />
NgModules help organize an application into cohesive blocks of functionality. NgModules help organize an application into cohesive blocks of functionality.
This page answers the questions many developers ask about NgModule design and implementation. This page answers the questions many developers ask about NgModule design and implementation.

View File

@ -1,13 +1,9 @@
# JavaScript Modules vs. NgModules # JavaScript Modules vs. NgModules
#### Prerequisites
A basic understanding of [JavaScript/ECMAScript modules](https://hacks.mozilla.org/2015/08/es6-in-depth-modules/).
<hr>
JavaScript and Angular use modules to organize code, and JavaScript and Angular use modules to organize code, and
though they organize it differently, Angular apps rely on both. though they organize it differently, Angular apps rely on both.
## JavaScript modules ## JavaScript modules
In JavaScript, modules are individual files with JavaScript code in them. To make whats in them available, you write an export statement, usually after the relevant code, like this: In JavaScript, modules are individual files with JavaScript code in them. To make whats in them available, you write an export statement, usually after the relevant code, like this:
@ -24,6 +20,8 @@ import { AppComponent } from './app.component';
JavaScript modules help you namespace, preventing accidental global variables. JavaScript modules help you namespace, preventing accidental global variables.
For more information on JavaScript modules, see [JavaScript/ECMAScript modules](https://hacks.mozilla.org/2015/08/es6-in-depth-modules/).
## NgModules ## NgModules
<!-- KW-- perMisko: let's discuss. This does not answer the question why it is different. Also, last sentence is confusing.--> <!-- KW-- perMisko: let's discuss. This does not answer the question why it is different. Also, last sentence is confusing.-->

View File

@ -1,13 +1,5 @@
# NgModules # NgModules
#### Prerequisites
A basic understanding of the following concepts:
* [Bootstrapping](guide/bootstrapping).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
<hr>
**NgModules** configure the injector and the compiler and help organize related things together. **NgModules** configure the injector and the compiler and help organize related things together.
An NgModule is a class marked by the `@NgModule` decorator. An NgModule is a class marked by the `@NgModule` decorator.
@ -20,7 +12,6 @@ For an example app showcasing all the techniques that NgModules related pages
cover, see the <live-example></live-example>. For explanations on the individual techniques, visit the relevant NgModule pages under the NgModules cover, see the <live-example></live-example>. For explanations on the individual techniques, visit the relevant NgModule pages under the NgModules
section. section.
## Angular modularity ## Angular modularity
Modules are a great way to organize an application and extend it with capabilities from external libraries. Modules are a great way to organize an application and extend it with capabilities from external libraries.
@ -57,12 +48,13 @@ You then import these modules into the root module.
## The basic NgModule ## The basic NgModule
The [Angular CLI](cli) generates the following basic app module when creating a new app. The [Angular CLI](cli) generates the following basic `AppModule` when creating a new app.
<code-example path="bootstrapping/src/app/app.module.ts" region="whole-ngmodule" header="src/app/app.module.ts" linenums="false">
<code-example path="ngmodules/src/app/app.module.1.ts" header="src/app/app.module.ts (default AppModule)" linenums="false"> // @NgModule decorator with its metadata
</code-example> </code-example>
At the top are the import statements. The next section is where you configure the `@NgModule` by stating what components and directives belong to it (`declarations`) as well as which other modules it uses (`imports`). This page builds on [Bootstrapping](guide/bootstrapping), which covers the structure of an NgModule in detail. If you need more information on the structure of an `@NgModule`, be sure to read [Bootstrapping](guide/bootstrapping). At the top are the import statements. The next section is where you configure the `@NgModule` by stating what components and directives belong to it (`declarations`) as well as which other modules it uses (`imports`). For more information on the structure of an `@NgModule`, be sure to read [Bootstrapping](guide/bootstrapping).
<hr /> <hr />

View File

@ -1,16 +1,10 @@
# Providers # Providers
#### Prerequisites: A provider is an instruction to the DI system on how to obtain a value for a dependency. Most of the time, these dependencies are services that you create and provide.
* A basic understanding of [Bootstrapping](guide/bootstrapping).
* Familiarity with [Frequently Used Modules](guide/frequent-ngmodules).
For the final sample app using the provider that this page describes, For the final sample app using the provider that this page describes,
see the <live-example></live-example>. see the <live-example></live-example>.
<hr>
A provider is an instruction to the DI system on how to obtain a value for a dependency. Most of the time, these dependencies are services that you create and provide.
## Providing a service ## Providing a service
If you already have an app that was created with the [Angular CLI](cli), you can create a service using the [`ng generate`](cli/generate) CLI command in the root project directory. Replace _User_ with the name of your service. If you already have an app that was created with the [Angular CLI](cli), you can create a service using the [`ng generate`](cli/generate) CLI command in the root project directory. Replace _User_ with the name of your service.

View File

@ -1,18 +1,5 @@
# Sharing Modules # Sharing Modules
#### Prerequisites
A basic understanding of the following:
* [Feature Modules](guide/feature-modules).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
* [Frequently Used Modules](guide/frequent-ngmodules).
* [Routing and Navigation](guide/router).
* [Lazy loading modules](guide/lazy-loading-ngmodules).
<!--* Components (#TBD) We dont have a page just on the concept of components, but I think one would be helpful for beginners.-->
<hr>
Creating shared modules allows you to organize and streamline your code. You can put commonly Creating shared modules allows you to organize and streamline your code. You can put commonly
used directives, pipes, and components into one module and then import just that module wherever used directives, pipes, and components into one module and then import just that module wherever
you need it in other parts of your app. you need it in other parts of your app.
@ -54,7 +41,7 @@ to import `FormsModule`, `SharedModule` can still export
way, you can give other modules access to `FormsModule` without way, you can give other modules access to `FormsModule` without
having to import it directly into the `@NgModule` decorator. having to import it directly into the `@NgModule` decorator.
### Using components vs services from other modules. ### Using components vs services from other modules
There is an important distinction between using another module's component and There is an important distinction between using another module's component and
using a service from another module. Import modules when you want to use using a service from another module. Import modules when you want to use

View File

@ -1,15 +1,10 @@
# Singleton services # Singleton services
#### Prerequisites: A singleton service is a service for which only once instance exists in an app.
* A basic understanding of [Bootstrapping](guide/bootstrapping).
* Familiarity with [Providers](guide/providers).
For a sample app using the app-wide singleton service that this page describes, see the For a sample app using the app-wide singleton service that this page describes, see the
<live-example name="ngmodules"></live-example> showcasing all the documented features of NgModules. <live-example name="ngmodules"></live-example> showcasing all the documented features of NgModules.
<hr />
## Providing a singleton service ## Providing a singleton service
There are two ways to make a service a singleton in Angular: There are two ways to make a service a singleton in Angular:

View File

@ -6,21 +6,21 @@ In version 9, the default setting for `@ViewChild` and `@ContentChild` queries i
In preparation for this change, in version 8, we are migrating all applications and libraries to explicitly specify the resolution strategy for `@ViewChild` and `@ContentChild` queries. In preparation for this change, in version 8, we are migrating all applications and libraries to explicitly specify the resolution strategy for `@ViewChild` and `@ContentChild` queries.
Specifically, this migration adds an explicit "static" flag that dictates when that query's results should be assigned. Specifically, this migration adds an explicit "static" flag that dictates when that query's results should be assigned.
Adding this flag will ensure your code works the same way when upgrading to version 9. Adding this flag will ensure your code works the same way when upgrading to version 9.
Before: Before:
``` ```
// query results sometimes available in `ngOnInit`, sometimes in `ngAfterViewInit` (based on template) // query results sometimes available in `ngOnInit`, sometimes in `ngAfterViewInit` (based on template)
@ViewChild('foo') foo: ElementRef; @ViewChild('foo') foo: ElementRef;
``` ```
After: After:
``` ```
// query results available in ngOnInit // query results available in ngOnInit
@ViewChild('foo', {static: true}) foo: ElementRef; @ViewChild('foo', {static: true}) foo: ElementRef;
OR OR
@ -28,7 +28,7 @@ OR
@ViewChild('foo', {static: false}) foo: ElementRef; @ViewChild('foo', {static: false}) foo: ElementRef;
``` ```
Starting with version 9, the `static` flag will default to false. Starting with version 9, the `static` flag will default to false.
At that time, any `{static: false}` flags can be safely removed, and we will have a schematic that will update your code for you. At that time, any `{static: false}` flags can be safely removed, and we will have a schematic that will update your code for you.
Note: this flag only applies to `@ViewChild` and `@ContentChild` queries specifically, as `@ViewChildren` and `@ContentChildren` queries do not have a concept of static and dynamic (they are always resolved as if they are "dynamic"). Note: this flag only applies to `@ViewChild` and `@ContentChild` queries specifically, as `@ViewChildren` and `@ContentChildren` queries do not have a concept of static and dynamic (they are always resolved as if they are "dynamic").
@ -38,50 +38,50 @@ Note: this flag only applies to `@ViewChild` and `@ContentChild` queries specifi
{@a what-to-do-with-todo} {@a what-to-do-with-todo}
### What should I do if I see a `/* TODO: add static flag */` comment printed by the schematic? ### What should I do if I see a `/* TODO: add static flag */` comment printed by the schematic?
If you see this comment, it means that the schematic couldn't statically figure out the correct flag. In this case, you'll have to add the correct flag based on your application's behavior. If you see this comment, it means that the schematic couldn't statically figure out the correct flag. In this case, you'll have to add the correct flag based on your application's behavior.
For more information on how to choose, see the [next question](#how-do-i-choose). For more information on how to choose, see the [next question](#how-do-i-choose).
{@a how-do-i-choose} {@a how-do-i-choose}
### How do I choose which `static` flag value to use: `true` or `false`? ### How do I choose which `static` flag value to use: `true` or `false`?
In the official API docs, we have always recommended retrieving query results in [`ngAfterViewInit` for view queries](https://angular.io/api/core/ViewChild#description) and [`ngAfterContentInit` for content queries](https://angular.io/api/core/ContentChild#description). In the official API docs, we have always recommended retrieving query results in [`ngAfterViewInit` for view queries](https://angular.io/api/core/ViewChild#description) and [`ngAfterContentInit` for content queries](https://angular.io/api/core/ContentChild#description).
This is because by the time those lifecycle hooks run, change detection has completed for the relevant nodes and we can guarantee that we have collected all the possible query results. This is because by the time those lifecycle hooks run, change detection has completed for the relevant nodes and we can guarantee that we have collected all the possible query results.
Most applications will want to use `{static: false}` for the same reason. This setting will ensure query matches that are dependent on binding resolution (e.g. results inside `*ngIf`s or `*ngFor`s) will be found by the query. Most applications will want to use `{static: false}` for the same reason. This setting will ensure query matches that are dependent on binding resolution (e.g. results inside `*ngIf`s or `*ngFor`s) will be found by the query.
There are rarer cases where `{static: true}` flag might be necessary (see [answer here](#should-i-use-static-true)). There are rarer cases where `{static: true}` flag might be necessary (see [answer here](#should-i-use-static-true)).
{@a should-i-use-static-true} {@a should-i-use-static-true}
### Is there a case where I should use `{static: true}`? ### Is there a case where I should use `{static: true}`?
This option was introduced to support creating embedded views on the fly. This option was introduced to support creating embedded views on the fly.
If you need access to a `TemplateRef` in a query to create a view dynamically, you won't be able to do so in `ngAfterViewInit`. If you need access to a `TemplateRef` in a query to create a view dynamically, you won't be able to do so in `ngAfterViewInit`.
Change detection has already run on that view, so creating a new view with the template will cause an `ExpressionHasChangedAfterChecked` error to be thrown. Change detection has already run on that view, so creating a new view with the template will cause an `ExpressionHasChangedAfterChecked` error to be thrown.
In this case, you will want to set the `static` flag to `true` and create your view in `ngOnInit`. In this case, you will want to set the `static` flag to `true` and create your view in `ngOnInit`.
In most other cases, the best practice is to use `{static: false}`. In most other cases, the best practice is to use `{static: false}`.
However, to facilitate the migration to version 8, you may also want to set the `static` flag to `true` if your component code already depends on the query results being available some time **before** `ngAfterViewInit` (for view queries) or `ngAfterContentInit` (for content queries). However, to facilitate the migration to version 8, you may also want to set the `static` flag to `true` if your component code already depends on the query results being available some time **before** `ngAfterViewInit` (for view queries) or `ngAfterContentInit` (for content queries).
For example, if your component relies on the query results being populated in the `ngOnInit` hook or in `@Input` setters, you will need to either set the flag to `true` or re-work your component to adjust to later timing. For example, if your component relies on the query results being populated in the `ngOnInit` hook or in `@Input` setters, you will need to either set the flag to `true` or re-work your component to adjust to later timing.
Note: Selecting the static option means that query results nested in `*ngIf` or `*ngFor` will not be found by the query. Note: Selecting the static option means that query results nested in `*ngIf` or `*ngFor` will not be found by the query.
These results are only retrievable after change detection runs. These results are only retrievable after change detection runs.
{@a what-does-this-flag-mean} {@a what-does-this-flag-mean}
### What does this flag mean and why is it necessary? ### What does this flag mean and why is it necessary?
The default behavior for queries has historically been undocumented and confusing, and has also commonly led to issues that are difficult to debug. The default behavior for queries has historically been undocumented and confusing, and has also commonly led to issues that are difficult to debug.
In version 9, we would like to make query behavior more consistent and simple to understand. In version 9, we would like to make query behavior more consistent and simple to understand.
To explain why, first it's important to understand how queries have worked up until now. To explain why, first it's important to understand how queries have worked up until now.
Without the `static` flag, the compiler decided when each query would be resolved on a case-by-case basis. Without the `static` flag, the compiler decided when each query would be resolved on a case-by-case basis.
All `@ViewChild`/`@ContentChild` queries were categorized into one of two buckets at compile time: "static" or "dynamic". All `@ViewChild`/`@ContentChild` queries were categorized into one of two buckets at compile time: "static" or "dynamic".
This classification determined when query results would become available to users. This classification determined when query results would become available to users.
- **Static queries** were queries where the result could be determined statically because the result didn't depend on runtime values like bindings. - **Static queries** were queries where the result could be determined statically because the result didn't depend on runtime values like bindings.
Results from queries classified as static were available before change detection ran for that view (accessible in `ngOnInit`). Results from queries classified as static were available before change detection ran for that view (accessible in `ngOnInit`).
- **Dynamic queries** were queries where the result could NOT be determined statically because the result depended on runtime values (aka bindings). - **Dynamic queries** were queries where the result could NOT be determined statically because the result depended on runtime values (aka bindings).
Results from queries classified as dynamic were not available until after change detection ran for that view (accessible in `ngAfterContentInit` for content queries or `ngAfterViewInit` for view queries). Results from queries classified as dynamic were not available until after change detection ran for that view (accessible in `ngAfterContentInit` for content queries or `ngAfterViewInit` for view queries).
For example, let's say we have a component, `Comp`. Inside it, we have this query: For example, let's say we have a component, `Comp`. Inside it, we have this query:
@ -96,8 +96,8 @@ and this template:
<div foo></div> <div foo></div>
``` ```
This `Foo` query would be categorized as static because at compile-time it's known that the `Foo` instance on the `<div>` is the correct result for the query. This `Foo` query would be categorized as static because at compile-time it's known that the `Foo` instance on the `<div>` is the correct result for the query.
Because the query result is not dependent on runtime values, we don't have to wait for change detection to run on the template before resolving the query. Because the query result is not dependent on runtime values, we don't have to wait for change detection to run on the template before resolving the query.
Consequently, results can be made available in `ngOnInit`. Consequently, results can be made available in `ngOnInit`.
Let's say the query is the same, but the component template looks like this: Let's say the query is the same, but the component template looks like this:
@ -106,53 +106,62 @@ Let's say the query is the same, but the component template looks like this:
<div foo *ngIf="showing"></div> <div foo *ngIf="showing"></div>
``` ```
With that template, the query would be categorized as a dynamic query. With that template, the query would be categorized as a dynamic query.
We would need to know the runtime value of `showing` before determining what the correct results are for the query. We would need to know the runtime value of `showing` before determining what the correct results are for the query.
As a result, change detection must run first, and results can only be made available in `ngAfterViewInit` or a setter for the query property. As a result, change detection must run first, and results can only be made available in `ngAfterViewInit` or a setter for the query property.
The effect of this implementation is that adding an `*ngIf` or `*ngFor` anywhere above a query match can change when that query's results become available. The effect of this implementation is that adding an `*ngIf` or `*ngFor` anywhere above a query match can change when that query's results become available.
Keep in mind that these categories only applied to `@ViewChild` and `@ContentChild` queries specifically. Keep in mind that these categories only applied to `@ViewChild` and `@ContentChild` queries specifically.
`@ViewChildren` and `@ContentChildren` queries did not have a concept of static and dynamic, so they were always resolved as if they were "dynamic". `@ViewChildren` and `@ContentChildren` queries did not have a concept of static and dynamic, so they were always resolved as if they were "dynamic".
This strategy of resolving queries at different times based on the location of potential query matches has caused a lot of confusion. Namely: This strategy of resolving queries at different times based on the location of potential query matches has caused a lot of confusion. Namely:
* Sometimes query results are available in `ngOnInit`, but sometimes they aren't and it's not clear why (see [21800](https://github.com/angular/angular/issues/21800) or [19872](https://github.com/angular/angular/issues/19872)). * Sometimes query results are available in `ngOnInit`, but sometimes they aren't and it's not clear why (see [21800](https://github.com/angular/angular/issues/21800) or [19872](https://github.com/angular/angular/issues/19872)).
* `@ViewChild` queries are resolved at a different time from `@ViewChildren` queries, and `@ContentChild` queries are resolved at a different time from `@ContentChildren` queries. * `@ViewChild` queries are resolved at a different time from `@ViewChildren` queries, and `@ContentChild` queries are resolved at a different time from `@ContentChildren` queries.
If a user turns a `@ViewChild` query into a `@ViewChildren` query, their code can break suddenly because the timing has shifted. If a user turns a `@ViewChild` query into a `@ViewChildren` query, their code can break suddenly because the timing has shifted.
* Code depending on a query result can suddenly stop working as soon as an `*ngIf` or an `*ngFor` is added to a template. * Code depending on a query result can suddenly stop working as soon as an `*ngIf` or an `*ngFor` is added to a template.
* A `@ContentChild` query for the same component will resolve at different times in the lifecycle for each usage of the component. * A `@ContentChild` query for the same component will resolve at different times in the lifecycle for each usage of the component.
This leads to buggy behavior where using a component with `*ngIf` is broken in subtle ways that aren't obvious to the component author. This leads to buggy behavior where using a component with `*ngIf` is broken in subtle ways that aren't obvious to the component author.
In version 9, we plan to simplify the behavior so all queries resolve after change detection runs by default. In version 9, we plan to simplify the behavior so all queries resolve after change detection runs by default.
The location of query matches in the template cannot affect when the query result will become available and suddenly break your code, and the default behavior is always the same. The location of query matches in the template cannot affect when the query result will become available and suddenly break your code, and the default behavior is always the same.
This makes the logic more consistent and predictable for users. This makes the logic more consistent and predictable for users.
That said, if an application does need query results earlier (for example, the query result is needed to create an embedded view), it's possible to add the `{static: true}` flag to explicitly ask for static resolution. That said, if an application does need query results earlier (for example, the query result is needed to create an embedded view), it's possible to add the `{static: true}` flag to explicitly ask for static resolution.
With this flag, users can indicate that they only care about results that are statically available and the query results will be populated before `ngOnInit`. With this flag, users can indicate that they only care about results that are statically available and the query results will be populated before `ngOnInit`.
{@a view-children-and-content-children} {@a view-children-and-content-children}
### Does this change affect `@ViewChildren` or `@ContentChildren` queries? ### Does this change affect `@ViewChildren` or `@ContentChildren` queries?
No, this change only affects `@ViewChild` and `@ContentChild` queries specifically. No, this change only affects `@ViewChild` and `@ContentChild` queries specifically.
`@ViewChildren` and `@ContentChildren` queries are already "dynamic" by default and don't support static resolution. `@ViewChildren` and `@ContentChildren` queries are already "dynamic" by default and don't support static resolution.
{@a why-specify-static-false} {@a why-specify-static-false}
### Why do I have to specify `{static: false}`? Isn't that the default? ### Why do I have to specify `{static: false}`? Isn't that the default?
The goal of this migration is to transition apps that aren't yet on version 9 to a query pattern that is compatible with version 9. The goal of this migration is to transition apps that aren't yet on version 9 to a query pattern that is compatible with version 9.
However, most applications use libraries, and it's likely that some of these libraries may not be upgraded to version 8 yet (and thus might not have the proper flags). However, most applications use libraries, and it's likely that some of these libraries may not be upgraded to version 8 yet (and thus might not have the proper flags).
Since the application's version of Angular will be used for compilation, if we change the default, the behavior of queries in the library's components will change to the version 8 default and possibly break. Since the application's version of Angular will be used for compilation, if we change the default, the behavior of queries in the library's components will change to the version 8 default and possibly break.
This way, an application's dependencies will behave the same way during the transition as they did in the previous version. This way, an application's dependencies will behave the same way during the transition as they did in the previous version.
In Angular version 9 and later, it will be safe to remove any `{static: false}` flags and we will do this cleanup for you in a schematic. In Angular version 9 and later, it will be safe to remove any `{static: false}` flags and we will do this cleanup for you in a schematic.
{@a libraries} {@a libraries}
### Can I keep on using Angular libraries that havent yet updated to version 8 yet? ### Can I keep on using Angular libraries that havent yet updated to version 8 yet?
Yes, absolutely! Yes, absolutely!
Because we have not changed the default query behavior in version 8 (i.e. the compiler still chooses a timing if no flag is set), when your application runs with a library that has not updated to version 8, the library will run the same way it did in version 7. Because we have not changed the default query behavior in version 8 (i.e. the compiler still chooses a timing if no flag is set), when your application runs with a library that has not updated to version 8, the library will run the same way it did in version 7.
This guarantees your app will work in version 8 even if libraries take longer to update their code. This guarantees your app will work in version 8 even if libraries take longer to update their code.
{@a update-library-to-use-static-flag}
### Can I update my library to version 8 by adding the `static` flag to view queries, while still being compatible with Angular version 7 apps?
Yes, the Angular team's recommendation for libraries is to update to version 8 and add the `static` flag. Angular version 7 apps will continue to work with libraries that have this flag.
However, if you update your library to Angular version 8 and want to take advantage of the new version 8 APIs, or you want more recent dependencies (such as Typescript or RxJS) your library will become incompatible with Angular version 7 apps. If your goal is to make your library compatible with Angular versions 7 and 8, you should not update your lib at all—except for `peerDependencies` in `package.json`.
In general, the most efficient plan is for libraries to adopt a 6 month major version schedule and bump the major version after each Angular update. That way, libraries stay in the same release cadence as Angular.

View File

@ -275,53 +275,179 @@ In this example, the `[ngClass]="odd"` stays on the `<div>`.
{@a microsyntax} {@a microsyntax}
### Microsyntax ## Microsyntax
The Angular microsyntax lets you configure a directive in a compact, friendly string. The Angular microsyntax lets you configure a directive in a compact, friendly string.
The microsyntax parser translates that string into attributes on the `<ng-template>`: The microsyntax parser translates that string into attributes on the `<ng-template>`:
* The `let` keyword declares a [_template input variable_](guide/structural-directives#template-input-variable) * The `let` keyword declares a [_template input variable_](guide/structural-directives#template-input-variable)
that you reference within the template. The input variables in this example are `hero`, `i`, and `odd`. that you reference within the template. The input variables in this example are `hero`, `i`, and `odd`.
The parser translates `let hero`, `let i`, and `let odd` into variables named, The parser translates `let hero`, `let i`, and `let odd` into variables named
`let-hero`, `let-i`, and `let-odd`. `let-hero`, `let-i`, and `let-odd`.
* The microsyntax parser takes `of` and `trackBy`, title-cases them (`of` -> `Of`, `trackBy` -> `TrackBy`), * The microsyntax parser title-cases all directives and prefixes them with the directive's
and prefixes them with the directive's attribute name (`ngFor`), yielding the names `ngForOf` and `ngForTrackBy`. attribute name, such as `ngFor`. For example, the `ngFor` input properties,
Those are the names of two `NgFor` _input properties_ . `of` and `trackBy`, become `ngForOf` and `ngForTrackBy`, respectively.
That's how the directive learns that the list is `heroes` and the track-by function is `trackById`. That's how the directive learns that the list is `heroes` and the track-by function is `trackById`.
* As the `NgFor` directive loops through the list, it sets and resets properties of its own _context_ object. * As the `NgFor` directive loops through the list, it sets and resets properties of its own _context_ object.
These properties include `index` and `odd` and a special property named `$implicit`. These properties can include, but aren't limited to, `index`, `odd`, and a special property
named `$implicit`.
* The `let-i` and `let-odd` variables were defined as `let i=index` and `let odd=odd`. * The `let-i` and `let-odd` variables were defined as `let i=index` and `let odd=odd`.
Angular sets them to the current value of the context's `index` and `odd` properties. Angular sets them to the current value of the context's `index` and `odd` properties.
* The context property for `let-hero` wasn't specified. * The context property for `let-hero` wasn't specified.
Its intended source is implicit. Its intended source is implicit.
Angular sets `let-hero` to the value of the context's `$implicit` property Angular sets `let-hero` to the value of the context's `$implicit` property,
which `NgFor` has initialized with the hero for the current iteration. which `NgFor` has initialized with the hero for the current iteration.
* The [API guide](api/common/NgForOf "API: NgFor") * The [`NgFor` API guide](api/common/NgForOf "API: NgFor")
describes additional `NgFor` directive properties and context properties. describes additional `NgFor` directive properties and context properties.
* `NgFor` is implemented by the `NgForOf` directive. Read more about additional `NgForOf` directive properties and context properties [NgForOf API reference](api/common/NgForOf). * The `NgForOf` directive implements `NgFor`. Read more about additional `NgForOf` directive properties and context properties in the [NgForOf API reference](api/common/NgForOf).
### Writing your own structural directives
These microsyntax mechanisms are also available to you when you write your own structural directives.
For example, microsyntax in Angular allows you to write `<div *ngFor="let item of items">{{item}}</div>`
instead of `<ng-template ngFor [ngForOf]="items"><div>{{item}}</div></ng-template`.
The following sections provide detailed information on constraints, grammar,
and translation of microsyntax.
### Constraints
Microsyntax must meet the following requirements:
- It must be known ahead of time so that IDEs can parse it without knowing the underlying semantics of the directive or what directives are present.
- It must translate to key-value attributes in the DOM.
### Grammar
When you write your own structural directives, use the following grammar:
```
*:prefix="( :let | :expression ) (';' | ',')? ( :let | :as | :keyExp )*"
```
The following tables describe each portion of the microsyntax grammar.
<!-- What should I put in the table headers? -->
<table>
<tr>
<th></th>
<th></th>
</tr>
<tr>
<td><code>prefix</code></td>
<td>HTML attribute key</td>
</tr>
<tr>
<td><code>key</code></td>
<td>HTML attribute key</td>
</tr>
<tr>
<td><code>local</code></td>
<td>local variable name used in the template</td>
</tr>
<tr>
<td><code>export</code></td>
<td>value exported by the directive under a given name</td>
</tr>
<tr>
<td><code>expression</code></td>
<td>standard Angular expression</td>
</tr>
</table>
<!-- The items in this table seem different. Is there another name for how we should describe them? -->
<table>
<tr>
<th></th>
</tr>
<tr>
<td colspan="3"><code>keyExp = :key ":"? :expression ("as" :local)? ";"? </code></td>
</tr>
<tr>
<td colspan="3"><code>let = "let" :local "=" :export ";"?</code></td>
</tr>
<tr>
<td colspan="3"><code>as = :export "as" :local ";"?</code></td>
</tr>
</table>
These microsyntax mechanisms are available to you when you write your own structural directives. ### Translation
A microsyntax is translated to the normal binding syntax as follows:
<!-- What to put in the table headers below? Are these correct?-->
<table>
<tr>
<th>Microsyntax</th>
<th>Translation</th>
</tr>
<tr>
<td><code>prefix</code> and naked <code>expression</code></td>
<td><code>[prefix]="expression"</code></td>
</tr>
<tr>
<td><code>keyExp</code></td>
<td><code>[prefixKey] "expression"
(let-prefixKey="export")</code>
<br />
Notice that the <code>prefix</code>
is added to the <code>key</code>
</td>
</tr>
<tr>
<td><code>let</code></td>
<td><code>let-local="export"</code></td>
</tr>
</table>
### Microsyntax examples
The following table demonstrates how Angular desugars microsyntax.
<table>
<tr>
<th>Microsyntax</th>
<th>Desugared</th>
</tr>
<tr>
<td><code>*ngFor="let item of [1,2,3]"</code></td>
<td><code>&lt;ng-template ngFor let-item [ngForOf]="[1,2,3]"&gt;</code></td>
</tr>
<tr>
<td><code>*ngFor="let item of [1,2,3] as items; trackBy: myTrack; index as i"</code></td>
<td><code>&lt;ng-template ngFor let-item [ngForOf]="[1,2,3]" let-items="ngForOf" [ngForTrackBy]="myTrack" let-i="index"&gt;</code>
</td>
</tr>
<tr>
<td><code>*ngIf="exp"</code></td>
<td><code>&lt;ng-template [ngIf]="exp"&gt;</code></td>
</tr>
<tr>
<td><code>*ngIf="exp as value"</code></td>
<td><code>&lt;ng-template [ngIf]="exp" let-value="ngIf"&gt;</code></td>
</tr>
</table>
Studying the Studying the
[source code for `NgIf`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts "Source: NgIf") [source code for `NgIf`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts "Source: NgIf")
and [`NgForOf`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_for_of.ts "Source: NgForOf") and [`NgForOf`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_for_of.ts "Source: NgForOf")
is a great way to learn more. is a great way to learn more.
{@a template-input-variable} {@a template-input-variable}
{@a template-input-variables} {@a template-input-variables}
### Template input variable ## Template input variable
A _template input variable_ is a variable whose value you can reference _within_ a single instance of the template. A _template input variable_ is a variable whose value you can reference _within_ a single instance of the template.
There are several such variables in this example: `hero`, `i`, and `odd`. There are several such variables in this example: `hero`, `i`, and `odd`.
@ -346,7 +472,7 @@ variable as the `hero` declared as `#hero`.
{@a one-per-element} {@a one-per-element}
### One structural directive per host element ## One structural directive per host element
Someday you'll want to repeat a block of HTML but only when a particular condition is true. Someday you'll want to repeat a block of HTML but only when a particular condition is true.
You'll _try_ to put both an `*ngFor` and an `*ngIf` on the same host element. You'll _try_ to put both an `*ngFor` and an `*ngIf` on the same host element.

View File

@ -1796,7 +1796,7 @@ Though `@Input()` and `@Output()` often appear together in apps, you can use
them separately. If the nested them separately. If the nested
component is such that it only needs to send data to its parent, you wouldn't component is such that it only needs to send data to its parent, you wouldn't
need an `@Input()`, only an `@Output()`. The reverse is also true in that if the need an `@Input()`, only an `@Output()`. The reverse is also true in that if the
child only needs to receive data from the parent, you'd only neeed `@Input()`. child only needs to receive data from the parent, you'd only need `@Input()`.
</div> </div>
@ -2063,14 +2063,14 @@ to declare inputs and outputs, you can identify
members in the `inputs` and `outputs` arrays members in the `inputs` and `outputs` arrays
of the directive metadata, as in this example: of the directive metadata, as in this example:
<code-example path="inputs-outputs/src/app/in-the-metadata/in-the-metadata.component.ts" region="metadata" header="src/app/app.component.html" linenums="false"> <code-example path="inputs-outputs/src/app/in-the-metadata/in-the-metadata.component.ts" region="metadata" header="src/app/in-the-metadata/in-the-metadata.component.ts" linenums="false">
</code-example> </code-example>
While declaring `inputs` and `outputs` in the `@Directive` and `@Component` While declaring `inputs` and `outputs` in the `@Directive` and `@Component`
metadata is possible, it is a better practice to use the `@Input()` and `@Output()` metadata is possible, it is a better practice to use the `@Input()` and `@Output()`
class decorators instead, as follows: class decorators instead, as follows:
<code-example path="inputs-outputs/src/app/input-output/input-output.component.ts" region="input-output" header="src/app/app.component.html" linenums="false"> <code-example path="inputs-outputs/src/app/input-output/input-output.component.ts" region="input-output" header="src/app/input-output/input-output.component.ts" linenums="false">
</code-example> </code-example>
See the [Decorate input and output properties](guide/styleguide#decorate-input-and-output-properties) section of the See the [Decorate input and output properties](guide/styleguide#decorate-input-and-output-properties) section of the
@ -2104,7 +2104,7 @@ offer a solution.
Alias inputs and outputs in the metadata using a colon-delimited (`:`) string with Alias inputs and outputs in the metadata using a colon-delimited (`:`) string with
the directive property name on the left and the public alias on the right: the directive property name on the left and the public alias on the right:
<code-example path="inputs-outputs/src/app/aliasing/aliasing.component.ts" region="alias" header="src/app/app.component.html" linenums="false"> <code-example path="inputs-outputs/src/app/aliasing/aliasing.component.ts" region="alias" header="src/app/aliasing/aliasing.component.ts" linenums="false">
</code-example> </code-example>
@ -2112,7 +2112,7 @@ the directive property name on the left and the public alias on the right:
You can specify the alias for the property name by passing the alias name to the `@Input()`/`@Output()` decorator. The internal name remains as usual. You can specify the alias for the property name by passing the alias name to the `@Input()`/`@Output()` decorator. The internal name remains as usual.
<code-example path="inputs-outputs/src/app/aliasing/aliasing.component.ts" region="alias-input-output" header="src/app/app.component.html" linenums="false"> <code-example path="inputs-outputs/src/app/aliasing/aliasing.component.ts" region="alias-input-output" header="src/app/aliasing/aliasing.component.ts" linenums="false">
</code-example> </code-example>
@ -2273,3 +2273,27 @@ the component.
</code-example> </code-example>
The `$any()` cast function works anywhere in a binding expression where a method call is valid. The `$any()` cast function works anywhere in a binding expression where a method call is valid.
## SVG in templates
It is possible to use SVG as valid templates in Angular. All of the template syntax below is
applicable to both SVG and HTML. Learn more in the SVG [1.1](https://www.w3.org/TR/SVG11/) and
[2.0](https://www.w3.org/TR/SVG2/) specifications.
Why would you use SVG as template, instead of simply adding it as image to your application?
When you use an SVG as the template, you are able to use directives and bindings just like with HTML
templates. This means that you will be able to dynamically generate interactive graphics.
Refer to the sample code snippet below for a syntax example:
<code-example path="template-syntax/src/app/svg.component.ts" header="src/app/svg.component.ts">
</code-example>
Add the below code to your `svg.component.svg` file:
<code-example path="template-syntax/src/app/svg.component.svg" header="src/app/svg.component.svg">
</code-example>
Here you can see the use of a `click()` event binding and the property binding syntax
(`[attr.fill]="fillColor"`).

View File

@ -868,6 +868,8 @@ As of Angular version 8, lazy loading code can be accomplished simply by using t
The service uses the `import()` method to load your bundled AngularJS application lazily. This decreases the initial bundle size of your application as you're not loading code your user doesn't need yet. You also need to provide a way to _bootstrap_ the application manually after it has been loaded. AngularJS provides a way to manually bootstrap an application using the [angular.bootstrap()](https://docs.angularjs.org/api/ng/function/angular.bootstrap) method with a provided HTML element. Your AngularJS app should also expose a `bootstrap` method that bootstraps the AngularJS app. The service uses the `import()` method to load your bundled AngularJS application lazily. This decreases the initial bundle size of your application as you're not loading code your user doesn't need yet. You also need to provide a way to _bootstrap_ the application manually after it has been loaded. AngularJS provides a way to manually bootstrap an application using the [angular.bootstrap()](https://docs.angularjs.org/api/ng/function/angular.bootstrap) method with a provided HTML element. Your AngularJS app should also expose a `bootstrap` method that bootstraps the AngularJS app.
To ensure any necessary teardown is triggered in the AngularJS app, such as removal of global listeners, you also implement a method to call the `$rootScope.destroy()` method.
<code-example path="upgrade-lazy-load-ajs/src/app/angularjs-app/index.ts" header="angularjs-app"> <code-example path="upgrade-lazy-load-ajs/src/app/angularjs-app/index.ts" header="angularjs-app">
</code-example> </code-example>
@ -886,7 +888,7 @@ In your Angular application, you need a component as a placeholder for your Angu
<code-example path="upgrade-lazy-load-ajs/src/app/angular-js/angular-js.component.ts" header="src/app/angular-js/angular-js.component.ts"> <code-example path="upgrade-lazy-load-ajs/src/app/angular-js/angular-js.component.ts" header="src/app/angular-js/angular-js.component.ts">
</code-example> </code-example>
When the Angular Router matches a route that uses AngularJS, the `AngularJSComponent` is rendered, and the content is rendered within the AngularJS [`ng-view`](https://docs.angularjs.org/api/ngRoute/directive/ngView) directive. When the Angular Router matches a route that uses AngularJS, the `AngularJSComponent` is rendered, and the content is rendered within the AngularJS [`ng-view`](https://docs.angularjs.org/api/ngRoute/directive/ngView) directive. When the user navigates away from the route, the `$rootScope` is destroyed on the AngularJS application.
### Configure a custom route matcher for AngularJS routes ### Configure a custom route matcher for AngularJS routes

View File

@ -27,7 +27,7 @@ Running this command will:
// Create a new // Create a new
const worker = new Worker('./app.worker', { type: 'module' }); const worker = new Worker('./app.worker', { type: 'module' });
worker.onmessage = ({ data }) => { worker.onmessage = ({ data }) => {
console.log('page got message: $\{data\}'); console.log(`page got message: ${data}`);
}; };
worker.postMessage('hello'); worker.postMessage('hello');
} else { } else {

View File

@ -227,3 +227,107 @@ The following example uses the `ignore` field to exclude certain files in the as
{ "glob": "**/*", "input": "src/assets/", "ignore": ["**/*.svg"], "output": "/assets/" }, { "glob": "**/*", "input": "src/assets/", "ignore": ["**/*.svg"], "output": "/assets/" },
] ]
</code-example> </code-example>
{@a style-script-config}
### Styles and scripts configuration
An array entry for the `styles` and `scripts` options can be a simple path string, or an object that points to an extra entry-point file.
The associated builder will load that file and its dependencies as a separate bundle during the build.
With a configuration object, you have the option of naming the bundle for the entry point, using a `bundleName` field.
The bundle is injected by default, but you can set `inject` to false to exclude the bundle from injection.
For example, the following object values create and name a bundle that contains styles and scripts, and excludes it from injection:
<code-example format="." language="json" linenums="false">
"styles": [
{ "input": "src/external-module/styles.scss", "inject": false, "bundleName": "external-module" }
],
"scripts": [
{ "input": "src/external-module/main.js", "inject": false, "bundleName": "external-module" }
]
</code-example>
You can mix simple and complex file references for styles and scripts.
<code-example format="." language="json" linenums="false">
"styles": [
"src/styles.css",
"src/more-styles.css",
{ "input": "src/lazy-style.scss", "inject": false },
{ "input": "src/pre-rename-style.scss", "bundleName": "renamed-style" },
]
</code-example>
{@a style-preprocessor}
#### Style preprocessor options
In Sass and Stylus you can make use of the `includePaths` functionality for both component and global styles, which allows you to add extra base paths that will be checked for imports.
To add paths, use the `stylePreprocessorOptions` option:
<code-example format="." language="json" linenums="false">
"stylePreprocessorOptions": {
"includePaths": [
"src/style-paths"
]
}
</code-example>
Files in that folder, such as `src/style-paths/_variables.scss`, can be imported from anywhere in your project without the need for a relative path:
```ts
// src/app/app.component.scss
// A relative path works
@import '../style-paths/variables';
// But now this works as well
@import 'variables';
```
Note that you will also need to add any styles or scripts to the `test` builder if you need them for unit tests.
See also [Using runtime-global libraries inside your app](guide/using-libraries#using-runtime-global-libraries-inside-your-app).
{@a optimize-and-srcmap}
### Optimization and source map configuration
The `optimization` and `sourceMap` command options are simple Boolean flags.
You can supply an object as a configuration value for either of these to provide more detailed instruction.
* The flag `--optimization="true"` applies to both scripts and styles. You can supply a value such as the following to apply optimization to one or the other:
<code-example format="." language="json" linenums="false">
"optimization": { "scripts": true, "styles": false }
</code-example>
* The flag `--sourceMap="true"` outputs source maps for both scripts and styles.
You can configure the option to apply to one or the other.
You can also choose to output hidden source maps, or resolve vendor package source maps.
For example:
<code-example format="." language="json" linenums="false">
"sourceMaps": { "scripts": true, "styles": false, "hidden": true, "vendor": true }
</code-example>
<div class="alert is-helpful">
When using hidden source maps, source maps will not be referenced in the bundle.
These are useful if you only want source maps to map error stack traces in error reporting tools,
but don't want to expose your source maps in the browser developer tools.
For [Universal](guide/glossary#universal), you can reduce the code rendered in the HTML page by
setting styles optimization to `true` and styles source maps to `false`.
</div>

View File

@ -34,23 +34,12 @@
"url": "https://dev.to/t/angular", "url": "https://dev.to/t/angular",
"rev": true, "rev": true,
"title": "DEV Community" "title": "DEV Community"
}
}
},
"Groups": {
"order": 2,
"resources": {
"sldkjfslkjfslkjdsklj": {
"desc": "Meetup in Barcelona, Spain. Express your motivations, share your ideas and play together creating awesome things in team.",
"rev": true,
"title": "Angular Beers",
"url": "http://www.meetup.com/AngularJS-Beers/"
}, },
"sldkjfslkjfslkjdskzzzlj": { "angular-in-depth" : {
"desc": "Angular Conferences and Angular Camps in Barcelona, Spain.", "desc": "The place where advanced Angular concepts are explained",
"url": "https://blog.angularindepth.com",
"rev": true, "rev": true,
"title": "Angular Camp", "title": "Angular In Depth"
"url": "http://angularcamp.org/"
} }
} }
}, },
@ -62,7 +51,7 @@
"logo": "", "logo": "",
"rev": true, "rev": true,
"title": "Adventures in Angular", "title": "Adventures in Angular",
"url": "https://devchat.tv/adventures-in-angular" "url": "https://devchat.tv/adv-in-angular/"
}, },
"sdlkfjsldfkj": { "sdlkfjsldfkj": {
"desc": "Weekly video podcast hosted by Jeff Whelpley with all the latest and greatest happenings in the wild world of Angular.", "desc": "Weekly video podcast hosted by Jeff Whelpley with all the latest and greatest happenings in the wild world of Angular.",
@ -77,13 +66,6 @@
"rev": true, "rev": true,
"title": "Happy Angular Podcast", "title": "Happy Angular Podcast",
"url": "https://happy-angular.de/" "url": "https://happy-angular.de/"
},
"sldkfjsldjf": {
"desc": "The live broadcast podcast all about JavaScript",
"logo": "",
"rev": true,
"title": "Javascript Air",
"url": "https://javascriptair.com/"
} }
} }
} }
@ -95,40 +77,26 @@
"Cross-Platform Development": { "Cross-Platform Development": {
"order": 5, "order": 5,
"resources": { "resources": {
"a2b": {
"desc": "Angular and React Native to build applications for Android and iOS",
"logo": "",
"rev": true,
"title": "ReactNative",
"url": "http://angular.github.io/react-native-renderer/"
},
"a3b": { "a3b": {
"desc": "Ionic offers a library of mobile-optimized HTML, CSS and JS components and tools for building highly interactive native and progressive web apps.", "desc": "Ionic offers a library of mobile-optimized HTML, CSS and JS components and tools for building highly interactive native and progressive web apps.",
"logo": "http://ionicframework.com/img/ionic-logo-white.svg", "logo": "http://ionicframework.com/img/ionic-logo-white.svg",
"rev": true, "rev": true,
"title": "Ionic", "title": "Ionic",
"url": "http://ionicframework.com/docs/v2/" "url": "https://ionicframework.com/docs"
}, },
"a4b": { "a4b": {
"desc": "Electron Platform for Angular.", "desc": "Electron Platform for Angular.",
"logo": "", "logo": "",
"rev": true, "rev": true,
"title": "Electron", "title": "Electron",
"url": "http://github.com/angular/angular-electron" "url": "https://github.com/maximegris/angular-electron"
}, },
"ab": { "ab": {
"desc": "NativeScript is how you build cross-platform, native iOS and Android apps with Angular and TypeScript. Get 100% access to native APIs via JavaScript and reuse of packages from NPM, CocoaPods and Gradle. Open source and backed by Telerik.", "desc": "NativeScript is how you build cross-platform, native iOS and Android apps with Angular and TypeScript. Get 100% access to native APIs via JavaScript and reuse of packages from NPM, CocoaPods and Gradle. Open source and backed by Telerik.",
"logo": "", "logo": "",
"rev": true, "rev": true,
"title": "NativeScript", "title": "NativeScript",
"url": "https://github.com/NativeScript/nativescript-angular" "url": "https://docs.nativescript.org/angular/start/introduction"
},
"ab5": {
"desc": "An Universal Windows App (uwp) powered by Angular",
"logo": "",
"rev": true,
"title": "Windows (UWP)",
"url": "http://github.com/preboot/angular2-universal-windows-app"
} }
} }
}, },
@ -139,7 +107,7 @@
"desc": "Reactive Extensions for Angular", "desc": "Reactive Extensions for Angular",
"rev": true, "rev": true,
"title": "ngrx", "title": "ngrx",
"url": "http://github.com/ngrx" "url": "https://ngrx.io/"
}, },
"ab": { "ab": {
"desc": "The official library for Firebase and Angular", "desc": "The official library for Firebase and Angular",
@ -153,21 +121,14 @@
"logo": "http://www.angular-meteor.com/images/logo.png", "logo": "http://www.angular-meteor.com/images/logo.png",
"rev": true, "rev": true,
"title": "Meteor", "title": "Meteor",
"url": "http://www.angular-meteor.com/angular2" "url": "https://github.com/urigo/angular-meteor"
}, },
"ab3": { "ab3": {
"desc": "Apollo is a data stack for modern apps, built with GraphQL.", "desc": "Apollo is a data stack for modern apps, built with GraphQL.",
"logo": "http://docs.apollostack.com/logo/large.png", "logo": "http://docs.apollostack.com/logo/large.png",
"rev": true, "rev": true,
"title": "Apollo", "title": "Apollo",
"url": "http://docs.apollostack.com/apollo-client/angular2.html" "url": "https://www.apollographql.com/docs/angular/"
},
"ab4": {
"desc": "Angular Commerce is a solution for building modern e-commerce applications with power of Google Firebase. Set of components is design agnostic and allows to easily extend functionality.",
"logo": "",
"rev": true,
"title": "AngularCommerce",
"url": "https://github.com/NodeArt/angular-commerce"
}, },
"ngx-api-utils": { "ngx-api-utils": {
"desc": "ngx-api-utils is a lean library of utilities and helpers to quickly integrate any HTTP API (REST, Ajax, and any other) with Angular.", "desc": "ngx-api-utils is a lean library of utilities and helpers to quickly integrate any HTTP API (REST, Ajax, and any other) with Angular.",
@ -219,12 +180,6 @@
"Tooling": { "Tooling": {
"order": 2, "order": 2,
"resources": { "resources": {
"-KLIzHfBEr1qMMUDxfq3": {
"desc": "Generate an Angular CRUD application from an existing database schema",
"rev": true,
"title": "Celerio Angular Quickstart",
"url": "https://github.com/jaxio/celerio-angular-quickstart"
},
"a1": { "a1": {
"desc": "A Google Chrome Dev Tools extension for debugging Angular applications.", "desc": "A Google Chrome Dev Tools extension for debugging Angular applications.",
"logo": "https://augury.angular.io/images/augury-logo.svg", "logo": "https://augury.angular.io/images/augury-logo.svg",
@ -259,13 +214,6 @@
"title": "Codelyzer", "title": "Codelyzer",
"url": "https://github.com/mgechev/codelyzer" "url": "https://github.com/mgechev/codelyzer"
}, },
"e1": {
"desc": "This package provides facilities for developers building Angular applications on ASP.NET.",
"logo": "",
"rev": true,
"title": "Universal for ASP.NET",
"url": "https://github.com/aspnet/nodeservices"
},
"f1": { "f1": {
"desc": "This tool generates dedicated documentation for Angular applications.", "desc": "This tool generates dedicated documentation for Angular applications.",
"logo": "", "logo": "",
@ -273,13 +221,6 @@
"title": "Compodoc", "title": "Compodoc",
"url": "https://github.com/compodoc/compodoc" "url": "https://github.com/compodoc/compodoc"
}, },
"ncg": {
"desc": "Generate several types of CRUD apps complete with e2e testing using template-sets for Angular, Material Design, Bootstrap, Kendo UI, Ionic, ...",
"logo": "https://avatars3.githubusercontent.com/u/27976684",
"rev": true,
"title": "NinjaCodeGen - Angular CRUD Generator",
"url": "https://ninjaCodeGen.com"
},
"angular-playground": { "angular-playground": {
"desc": "UI development environment for building, testing, and documenting Angular applications.", "desc": "UI development environment for building, testing, and documenting Angular applications.",
"rev": true, "rev": true,
@ -330,12 +271,6 @@
"title": "Clarity Design System", "title": "Clarity Design System",
"url": "https://vmware.github.io/clarity/" "url": "https://vmware.github.io/clarity/"
}, },
"-KLIzI9BTvvP_hUwutXk": {
"desc": "UI components for Angular using Semantic UI",
"rev": true,
"title": "Semantic UI",
"url": "https://github.com/vladotesanovic/ngSemantic"
},
"-KMVB8P4TDfht8c0L1AE": { "-KMVB8P4TDfht8c0L1AE": {
"desc": "The Angular version of the Angular UI Bootstrap library. This library is being built from scratch in Typescript using the Bootstrap 4 CSS framework.", "desc": "The Angular version of the Angular UI Bootstrap library. This library is being built from scratch in Typescript using the Bootstrap 4 CSS framework.",
"rev": true, "rev": true,
@ -520,12 +455,6 @@
"Books": { "Books": {
"order": 1, "order": 1,
"resources": { "resources": {
"-KLI8vJ0ZkvWhqPembZ7": {
"desc": "A guide that helps developers get up to speed quickly on Angular and its accompanying technologies.",
"rev": true,
"title": "How to Get Started and Productive in Angular Fast",
"url": "http://www.amazon.com/How-Started-Productive-Angular-Fast-ebook/dp/B01D3B0ET4/ref=sr_1_1_twi_kin_2?ie=UTF8&qid=1462381159&sr=8-1"
},
"-KLIzGEp8Mh5W-FkiQnL": { "-KLIzGEp8Mh5W-FkiQnL": {
"desc": "Your quick, no-nonsense guide to building real-world apps with Angular", "desc": "Your quick, no-nonsense guide to building real-world apps with Angular",
"rev": true, "rev": true,
@ -536,25 +465,7 @@
"desc": "More than 15 books from O'Reilly about Angular", "desc": "More than 15 books from O'Reilly about Angular",
"rev": true, "rev": true,
"title": "O'Reilly Media", "title": "O'Reilly Media",
"url": "https://ssearch.oreilly.com/?q=angular+2&x=0&y=0" "url": "https://ssearch.oreilly.com/?q=angular"
},
"8ab": {
"desc": "This books shows all the steps necessary for the development of SPA (Single Page Application) applications with the brand new Angular",
"rev": true,
"title": "Practical Angular",
"url": "https://leanpub.com/practical-angular-2"
},
"a2b": {
"desc": "Publications and books from Manning about Angular",
"rev": true,
"title": "Manning Publications",
"url": "https://www.manning.com/search?q=angular"
},
"a4b": {
"desc": "From getting started with the Angular toolchain to writing applications with scalable front end architectures, this book walks you through everything you need to know.",
"rev": true,
"title": "Rangle's Angular Training Book",
"url": "http://ngcourse.rangle.io/"
}, },
"a5b": { "a5b": {
"desc": "The in-depth, complete, and up-to-date book on Angular. Become an Angular expert today.", "desc": "The in-depth, complete, and up-to-date book on Angular. Become an Angular expert today.",
@ -562,12 +473,6 @@
"title": "ng-book", "title": "ng-book",
"url": "https://www.ng-book.com/2/" "url": "https://www.ng-book.com/2/"
}, },
"a6b": {
"desc": "A Practical Introduction to the new Web Development Platform Angular",
"rev": true,
"title": "Angular Book",
"url": "https://leanpub.com/angular2-book"
},
"a7b": { "a7b": {
"desc": "This ebook will help you getting the philosophy of the framework: what comes from 1.x, what has been introduced and why", "desc": "This ebook will help you getting the philosophy of the framework: what comes from 1.x, what has been introduced and why",
"rev": true, "rev": true,
@ -578,13 +483,13 @@
"desc": "More than 10 books from Packt Publishing about Angular", "desc": "More than 10 books from Packt Publishing about Angular",
"rev": true, "rev": true,
"title": "Packt Publishing", "title": "Packt Publishing",
"url": "https://www.packtpub.com/all/?search=angular%202#" "url": "https://www.packtpub.com/catalogsearch/result/?q=angular"
}, },
"cnoring-rxjs-fundamentals": { "cnoring-rxjs-fundamentals": {
"desc": "A free book that covers all facets of working with Rxjs from your first Observable to how to make your code run at optimal speed with Schedulers.", "desc": "A free book that covers all facets of working with Rxjs from your first Observable to how to make your code run at optimal speed with Schedulers.",
"rev": true, "rev": true,
"title": "RxJS 5 Ultimate", "title": "RxJS Ultimate",
"url": "https://www.gitbook.com/book/chrisnoring/rxjs-5-ultimate/details" "url": "https://chrisnoring.gitbooks.io/rxjs-5-ultimate/content/"
}, },
"vsavkin-angular-router": { "vsavkin-angular-router": {
"desc": "This book is a comprehensive guide to the Angular router written by its designer. The book explores the library in depth, including the mental model, design constraints, subtleties of the API.", "desc": "This book is a comprehensive guide to the Angular router written by its designer. The book explores the library in depth, including the mental model, design constraints, subtleties of the API.",
@ -642,18 +547,6 @@
"title": "Academia Binaria (español)", "title": "Academia Binaria (español)",
"url": "http://academia-binaria.com/" "url": "http://academia-binaria.com/"
}, },
"-KLIzIOgdPXzI4LMOzYP": {
"desc": "In this course, you will learn the features listed above and so much more. This amazing Angular tutorial will cover the fundamentals of Angular (you dont even need to know Angular), TypeScript, and introduction to the programming concepts such as conditions, arrays, functions, directives, pipes, etc.",
"rev": true,
"title": "Eduonix Angular Fundamentals",
"url": "https://www.eduonix.com/courses/Web-Development/angular-2-fundamentals-for-web-developers"
},
"-KMUuOWwciL_S_o0fzFO": {
"desc": "The ngMigrate project is brought to you by Todd Motto, a Developer Advocate at Telerik, spreading the good word of Kendo UI, NativeScript and Angular & AngularJS. You can follow him on Twitter for questions, or even requests about this guide.",
"rev": true,
"title": "ngMigrate",
"url": "http://ngmigrate.telerik.com/"
},
"-KN3uNQvxifu26D6WKJW": { "-KN3uNQvxifu26D6WKJW": {
"category": "Education", "category": "Education",
"desc": "Create the future of web applications by taking Angular for a test drive.", "desc": "Create the future of web applications by taking Angular for a test drive.",
@ -674,14 +567,14 @@
"logo": "", "logo": "",
"rev": true, "rev": true,
"title": "Pluralsight", "title": "Pluralsight",
"url": "https://www.pluralsight.com/search?q=angular+2&categories=all" "url": "https://www.pluralsight.com/paths/angular"
}, },
"ab3": { "ab3": {
"desc": "Angular courses hosted by Udemy", "desc": "Angular courses hosted by Udemy",
"logo": "", "logo": "",
"rev": true, "rev": true,
"title": "Udemy", "title": "Udemy",
"url": "https://www.udemy.com/courses/search/?ref=home&src=ukw&q=angular+2&lang=en" "url": "https://www.udemy.com/courses/search/?q=angular"
}, },
"ab4": { "ab4": {
"desc": "Angular Fundamentals and advanced topics focused on Redux Style Angular Applications", "desc": "Angular Fundamentals and advanced topics focused on Redux Style Angular Applications",
@ -695,13 +588,7 @@
"logo": "", "logo": "",
"rev": true, "rev": true,
"title": "Frontend Masters", "title": "Frontend Masters",
"url": "https://frontendmasters.com/courses/angular-2/" "url": "https://frontendmasters.com/courses/angular-core/"
},
"ac6": {
"desc": "French language Angular course covering TypeScript, ES6, Dependency Injection, Observables, and more.",
"rev": true,
"title": "Wishtack's Angular Course (francais)",
"url": "http://courses.wishtack.com/angular-2/ecmascript-6"
}, },
"angular-love": { "angular-love": {
"desc": "Polish language Angular articles and information", "desc": "Polish language Angular articles and information",
@ -709,12 +596,6 @@
"title": "angular.love (Polski)", "title": "angular.love (Polski)",
"url": "http://www.angular.love/" "url": "http://www.angular.love/"
}, },
"angular2forms": {
"desc": "Learn about how to use Reactive Forms with Angular.",
"rev": true,
"title": "Angular Forms: Data Binding and Validation",
"url": "https://www.lynda.com/AngularJS-tutorials/Angular-2-Forms-Data-Binding-Validation/461451-2.html"
},
"learn-angular-fr": { "learn-angular-fr": {
"desc": "French language Angular content.", "desc": "French language Angular content.",
"rev": true, "rev": true,
@ -790,7 +671,7 @@
"desc": "Basic and Advanced training across Europe in German", "desc": "Basic and Advanced training across Europe in German",
"rev": true, "rev": true,
"title": "TheCodeCampus (German)", "title": "TheCodeCampus (German)",
"url": "https://www.thecodecampus.de/#!/angularjs" "url": "https://www.thecodecampus.de/schulungen/angular"
}, },
"-KLIzFhfGKi1xttqJ7Uh": { "-KLIzFhfGKi1xttqJ7Uh": {
"desc": "4 day in-depth Angular training in Israel", "desc": "4 day in-depth Angular training in Israel",
@ -823,13 +704,6 @@
"title": "Angular Boot Camp", "title": "Angular Boot Camp",
"url": "https://angularbootcamp.com" "url": "https://angularbootcamp.com"
}, },
"ab": {
"desc": "With Rangles Custom Training, you can cover Angular in comprehensive detail, on your premises or theirs. Learn directly from Angular experts who will tailor course material to suit your specific application needs.",
"logo": "",
"rev": true,
"title": "Rangle.io",
"url": "http://rangle.io/services/javascript-training/angular2-training/"
},
"ab3": { "ab3": {
"desc": "Trainings & Code Reviews. We help people to get a deep understanding of different technologies through trainings and code reviews. Our services can be arranged online, making it possible to join in from anywhere in the world, or on-site to get the best experience possible.", "desc": "Trainings & Code Reviews. We help people to get a deep understanding of different technologies through trainings and code reviews. Our services can be arranged online, making it possible to join in from anywhere in the world, or on-site to get the best experience possible.",
"logo": "", "logo": "",
@ -844,12 +718,6 @@
"title": "Learn Javascript (Russian)", "title": "Learn Javascript (Russian)",
"url": "https://learn.javascript.ru/courses/angular" "url": "https://learn.javascript.ru/courses/angular"
}, },
"sa200": {
"desc": "Free Angular training delivered by SFEIR in France",
"rev": true,
"title": "SFEIR School (French)",
"url": "https://school.sfeir.com/project/sa200/"
},
"zenika-angular": { "zenika-angular": {
"desc": "Angular trainings delivered by Zenika (FRANCE)", "desc": "Angular trainings delivered by Zenika (FRANCE)",
"rev": true, "rev": true,

View File

@ -208,16 +208,16 @@
"title": "Component Styles", "title": "Component Styles",
"tooltip": "Add CSS styles that are specific to a component." "tooltip": "Add CSS styles that are specific to a component."
}, },
{
"url": "guide/elements",
"title": "Angular Elements",
"tooltip": "Convert components to Custom Elements."
},
{ {
"url": "guide/dynamic-component-loader", "url": "guide/dynamic-component-loader",
"title": "Dynamic Components", "title": "Dynamic Components",
"tooltip": "Load components dynamically." "tooltip": "Load components dynamically."
}, },
{
"url": "guide/elements",
"title": "Angular Elements",
"tooltip": "Convert components to Custom Elements."
},
{ {
"url": "guide/attribute-directives", "url": "guide/attribute-directives",
"title": "Attribute Directives", "title": "Attribute Directives",
@ -456,6 +456,11 @@
"title": "Internationalization (i18n)", "title": "Internationalization (i18n)",
"tooltip": "Translate the app's template text into multiple languages." "tooltip": "Translate the app's template text into multiple languages."
}, },
{
"url": "guide/accessibility",
"title": "Accessibility",
"tooltip": "Design apps to be accessible to all users."
},
{ {
"title": "Service Workers & PWA", "title": "Service Workers & PWA",
"tooltip": "Angular service workers: Controlling caching of application resources.", "tooltip": "Angular service workers: Controlling caching of application resources.",

View File

@ -19,7 +19,7 @@
"build-local": "yarn ~~build", "build-local": "yarn ~~build",
"prebuild-with-ivy": "yarn setup-local && node scripts/switch-to-ivy", "prebuild-with-ivy": "yarn setup-local && node scripts/switch-to-ivy",
"build-with-ivy": "yarn ~~build", "build-with-ivy": "yarn ~~build",
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js 01a7186bb", "extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js 823731f6e",
"lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint", "lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint",
"test": "yarn check-env && ng test", "test": "yarn check-env && ng test",
"pree2e": "yarn check-env && yarn update-webdriver", "pree2e": "yarn check-env && yarn update-webdriver",
@ -33,8 +33,10 @@
"set-opensearch-url": "node --eval \"const sh = require('shelljs'); sh.set('-e'); sh.sed('-i', /PLACEHOLDER_URL/g, process.argv[1], 'dist/assets/opensearch.xml');\"", "set-opensearch-url": "node --eval \"const sh = require('shelljs'); sh.set('-e'); sh.sed('-i', /PLACEHOLDER_URL/g, process.argv[1], 'dist/assets/opensearch.xml');\"",
"presmoke-tests": "yarn update-webdriver", "presmoke-tests": "yarn update-webdriver",
"smoke-tests": "protractor tests/deployment/e2e/protractor.conf.js --suite smoke --baseUrl", "smoke-tests": "protractor tests/deployment/e2e/protractor.conf.js --suite smoke --baseUrl",
"test-pwa-score": "node scripts/test-pwa-score", "test-a11y-score": "node scripts/test-aio-a11y",
"test-pwa-score-localhost": "run-p --race \"~~http-server dist -p 4200 --silent\" \"test-pwa-score http://localhost:4200 {1} {2}\" --", "test-a11y-score-localhost": "run-p --race \"~~light-server -s dist -p 4200 --quiet\" \"test-a11y-score http://localhost:4200\" --",
"test-pwa-score": "run-s \"~~audit-web-app {1} all:0,pwa:{2} {3}\" --",
"test-pwa-score-localhost": "run-p --race \"~~light-server -s dist -p 4200 --quiet\" \"test-pwa-score http://localhost:4200 {1} {2}\" --",
"example-e2e": "yarn example-check-local && node ./tools/examples/run-example-e2e", "example-e2e": "yarn example-check-local && node ./tools/examples/run-example-e2e",
"example-lint": "tslint --config \"content/examples/tslint.json\" \"content/examples/**/*.ts\" --exclude \"content/examples/styleguide/**/*.avoid.ts\"", "example-lint": "tslint --config \"content/examples/tslint.json\" \"content/examples/**/*.ts\" --exclude \"content/examples/styleguide/**/*.avoid.ts\"",
"example-use-local": "node tools/ng-packages-installer overwrite ./tools/examples/shared --debug", "example-use-local": "node tools/ng-packages-installer overwrite ./tools/examples/shared --debug",
@ -64,15 +66,16 @@
"generate-zips": "node ./tools/example-zipper/generateZips", "generate-zips": "node ./tools/example-zipper/generateZips",
"build-404-page": "node scripts/build-404-page", "build-404-page": "node scripts/build-404-page",
"update-webdriver": "webdriver-manager update --standalone false --gecko false $CI_CHROMEDRIVER_VERSION_ARG", "update-webdriver": "webdriver-manager update --standalone false --gecko false $CI_CHROMEDRIVER_VERSION_ARG",
"~~audit-web-app": "node scripts/audit-web-app",
"~~check-env": "node scripts/check-environment", "~~check-env": "node scripts/check-environment",
"~~clean-generated": "node --eval \"require('shelljs').rm('-rf', 'src/generated')\"", "~~clean-generated": "node --eval \"require('shelljs').rm('-rf', 'src/generated')\"",
"~~build": "ng build --configuration=stable", "~~build": "ng build --configuration=stable",
"post~~build": "yarn build-404-page", "post~~build": "yarn build-404-page",
"~~http-server": "http-server" "~~light-server": "light-server --bind=localhost --historyindex=/index.html --no-reload"
}, },
"engines": { "engines": {
"node": ">=10.9.0 <11.0.0", "node": ">=10.9.0 <11.0.0",
"yarn": ">=1.12.1 <=1.14.0" "yarn": ">=1.12.1 <=1.16.0"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
@ -106,13 +109,13 @@
"archiver": "^1.3.0", "archiver": "^1.3.0",
"canonical-path": "1.0.0", "canonical-path": "1.0.0",
"chalk": "^2.1.0", "chalk": "^2.1.0",
"chrome-launcher": "^0.10.5", "chrome-launcher": "^0.10.7",
"cjson": "^0.5.0", "cjson": "^0.5.0",
"codelyzer": "^5.0.0", "codelyzer": "^5.0.0",
"cross-spawn": "^5.1.0", "cross-spawn": "^5.1.0",
"css-selector-parser": "^1.3.0", "css-selector-parser": "^1.3.0",
"dgeni": "^0.4.11", "dgeni": "^0.4.11",
"dgeni-packages": "^0.27.1", "dgeni-packages": "^0.27.5",
"entities": "^1.1.1", "entities": "^1.1.1",
"eslint": "^3.19.0", "eslint": "^3.19.0",
"eslint-plugin-jasmine": "^2.2.0", "eslint-plugin-jasmine": "^2.2.0",
@ -123,7 +126,6 @@
"hast-util-is-element": "^1.0.0", "hast-util-is-element": "^1.0.0",
"hast-util-to-string": "^1.0.0", "hast-util-to-string": "^1.0.0",
"html": "^1.0.0", "html": "^1.0.0",
"http-server": "^0.11.1",
"ignore": "^3.3.3", "ignore": "^3.3.3",
"image-size": "^0.5.1", "image-size": "^0.5.1",
"jasmine": "^2.6.0", "jasmine": "^2.6.0",
@ -140,7 +142,8 @@
"karma-coverage-istanbul-reporter": "^1.3.0", "karma-coverage-istanbul-reporter": "^1.3.0",
"karma-jasmine": "^1.1.0", "karma-jasmine": "^1.1.0",
"karma-jasmine-html-reporter": "^0.2.2", "karma-jasmine-html-reporter": "^0.2.2",
"lighthouse": "^4.3.0", "light-server": "^2.6.2",
"lighthouse": "^5.1.0",
"lighthouse-logger": "^1.2.0", "lighthouse-logger": "^1.2.0",
"lodash": "^4.17.4", "lodash": "^4.17.4",
"lunr": "^2.1.0", "lunr": "^2.1.0",
@ -167,4 +170,4 @@
"xregexp": "^4.0.0", "xregexp": "^4.0.0",
"yargs": "^7.0.2" "yargs": "^7.0.2"
} }
} }

View File

@ -0,0 +1,179 @@
#!/bin/env node
'use strict';
/**
* Usage:
* ```sh
* node scripts/audit-web-app <url> <min-scores> [<log-file>]
* ```
*
* Runs audits against the specified URL on specific categories (accessibility, best practices, performance, PWA, SEO).
* It fails, if the score in any category is below the score specified in `<min-scores>`. (Only runs audits for the
* specified categories.)
*
* `<min-scores>` is either a number (in which case it is interpreted as `all:<min-score>`) or a list of comma-separated
* strings of the form `key:value`, where `key` is one of `accessibility`, `best-practices`, `performance`, `pwa`, `seo`
* or `all` and `value` is a number (between 0 and 100).
*
* Examples:
* - `95` _(Same as `all:95`.)_
* - `all:95` _(Run audits for all categories and require a score of 95 or higher.)_
* - `all:95,pwa:100` _(Same as `all:95`, except that a scope of 100 is required for the `pwa` category.)_
* - `performance:90` _(Only run audits for the `performance` category and require a score of 90 or higher.)_
*
* If `<log-file>` is defined, the full results will be logged there.
*
* (Skips HTTPS-related audits, when run for an HTTP URL.)
*/
// Imports
const chromeLauncher = require('chrome-launcher');
const lighthouse = require('lighthouse');
const printer = require('lighthouse/lighthouse-cli/printer');
const logger = require('lighthouse-logger');
// Constants
const AUDIT_CATEGORIES = ['accessibility', 'best-practices', 'performance', 'pwa', 'seo'];
const CHROME_LAUNCH_OPTS = {chromeFlags: ['--headless']};
const LIGHTHOUSE_FLAGS = {logLevel: process.env.CI ? 'error' : 'info'}; // Be less verbose on CI.
const SKIPPED_HTTPS_AUDITS = ['redirects-http', 'uses-http2'];
const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer';
const WAIT_FOR_SW_DELAY = 5000;
// Run
_main(process.argv.slice(2));
// Functions - Definitions
async function _main(args) {
const {url, minScores, logFile} = parseInput(args);
const isOnHttp = /^http:/.test(url);
const lhFlags = {...LIGHTHOUSE_FLAGS, onlyCategories: Object.keys(minScores).sort()};
const lhConfig = {
extends: 'lighthouse:default',
// Since the Angular ServiceWorker waits for the app to stabilize before registering,
// wait a few seconds after load to allow Lighthouse to reliably detect it.
passes: [{passName: 'defaultPass', pauseAfterLoadMs: WAIT_FOR_SW_DELAY}],
};
console.log(`Running web-app audits for '${url}'...`);
console.log(` Audit categories: ${lhFlags.onlyCategories.join(', ')}`);
// If testing on HTTP, skip HTTPS-specific tests.
// (Note: Browsers special-case localhost and run ServiceWorker even on HTTP.)
if (isOnHttp) skipHttpsAudits(lhConfig);
logger.setLevel(lhFlags.logLevel);
try {
console.log('');
const startTime = Date.now();
const results = await launchChromeAndRunLighthouse(url, lhFlags, lhConfig);
const success = await processResults(results, minScores, logFile);
console.log(`\n(Completed in ${((Date.now() - startTime) / 1000).toFixed(1)}s.)\n`);
if (!success) {
throw new Error('One or more scores are too low.');
}
} catch (err) {
onError(err);
}
}
function formatScore(score) {
return `${(score * 100).toFixed(0).padStart(3)}`;
}
async function launchChromeAndRunLighthouse(url, flags, config) {
const chrome = await chromeLauncher.launch(CHROME_LAUNCH_OPTS);
flags.port = chrome.port;
try {
return await lighthouse(url, flags, config);
} finally {
await chrome.kill();
}
}
function onError(err) {
console.error(err);
console.error('');
process.exit(1);
}
function parseInput(args) {
const [url, minScoresRaw, logFile] = args;
if (!url) {
onError('Invalid arguments: <url> not specified.');
} else if (!minScoresRaw) {
onError('Invalid arguments: <min-scores> not specified.');
}
const minScores = parseMinScores(minScoresRaw || '');
const unknownCategories = Object.keys(minScores).filter(cat => !AUDIT_CATEGORIES.includes(cat));
const allValuesValid = Object.values(minScores).every(x => (0 <= x) && (x <= 1));
if (unknownCategories.length > 0) {
onError(`Invalid arguments: <min-scores> contains unknown category(-ies): ${unknownCategories.join(', ')}`);
} else if (!allValuesValid) {
onError(`Invalid arguments: <min-scores> has non-numeric or out-of-range values: ${minScoresRaw}`);
}
return {url, minScores, logFile};
}
function parseMinScores(raw) {
const minScores = {};
if (/^\d+$/.test(raw)) {
raw = `all:${raw}`;
}
raw.
split(',').
map(x => x.split(':')).
forEach(([key, val]) => minScores[key] = Number(val) / 100);
if (minScores.hasOwnProperty('all')) {
AUDIT_CATEGORIES.forEach(cat => minScores.hasOwnProperty(cat) || (minScores[cat] = minScores.all));
delete minScores.all;
}
return minScores;
}
async function processResults(results, minScores, logFile) {
const lhVersion = results.lhr.lighthouseVersion;
const categories = results.lhr.categories;
const report = results.report;
if (logFile) {
console.log(`\nSaving results in '${logFile}'...`);
console.log(` LightHouse viewer: ${VIEWER_URL}`);
await printer.write(report, printer.OutputMode.json, logFile);
}
console.log(`\nLighthouse version: ${lhVersion}`);
console.log('\nAudit results:');
const maxTitleLen = Math.max(...Object.values(categories).map(({title}) => title.length));
const success = Object.keys(categories).sort().reduce((aggr, cat) => {
const {title, score} = categories[cat];
const paddedTitle = `${title}:`.padEnd(maxTitleLen + 1);
const minScore = minScores[cat];
const passed = !isNaN(score) && (score >= minScore);
console.log(
` - ${paddedTitle} ${formatScore(score)} (Required: ${formatScore(minScore)}) ${passed ? 'OK' : 'FAILED'}`);
return aggr && passed;
}, true);
return success;
}
function skipHttpsAudits(config) {
console.log(` Skipping HTTPS-related audits: ${SKIPPED_HTTPS_AUDITS.join(', ')}`);
config.settings = {...config.settings, skipAudits: SKIPPED_HTTPS_AUDITS};
}

View File

@ -0,0 +1,38 @@
#!/bin/env node
'use strict';
/**
* Usage:
* ```sh
* node scripts/test-aio-a11y <origin>
* ```
*
* Runs accessibility audits on several (pre-defined) pages on the specified origin. It fails, if
* the score for any page is below the minimum (see `MIN_SCORES_PER_PAGE` below).
*
* `<origin>` is the origin (scheme + hostname + port) of an angular.io deployment. It can be remote
* (e.g. `https://next.angular.io`) or local (e.g. `http://localhost:4200`).
*/
// Imports
const sh = require('shelljs');
sh.set('-e');
// Constants
const MIN_SCORES_PER_PAGE = {
'': 100,
'api': 100,
'api/core/Directive': 90,
'cli': 91,
'cli/add': 91,
'docs': 100,
'guide/docs-style-guide': 88,
'start': 90,
};
// Run
const auditWebAppCmd = `"${process.execPath}" "${__dirname}/audit-web-app"`;
const origin = process.argv[2];
for (const [page, minScore] of Object.entries(MIN_SCORES_PER_PAGE)) {
sh.exec(`${auditWebAppCmd} ${origin}/${page} accessibility:${minScore}`);
}

View File

@ -25,5 +25,8 @@ set +x -eu -o pipefail
# Run PWA-score tests. # Run PWA-score tests.
yarn test-pwa-score "$targetUrl" "$minPwaScore" yarn test-pwa-score "$targetUrl" "$minPwaScore"
# Run a11y tests.
yarn test-a11y-score "$targetUrl"
echo -e "\nAll checks passed!" echo -e "\nAll checks passed!"
) )

View File

@ -1,135 +0,0 @@
#!/bin/env node
/**
* Usage:
* ```sh
* node scripts/test-pwa-score <url> <min-score> [<log-file>]
* ```
*
* Fails if the score is below `<min-score>`.
* If `<log-file>` is defined, the full results will be logged there.
*
* (Skips HTTPS-related audits, when run for HTTP URL.)
*/
// Imports
const chromeLauncher = require('chrome-launcher');
const lighthouse = require('lighthouse');
const printer = require('lighthouse/lighthouse-cli/printer');
const logger = require('lighthouse-logger');
// Constants
const CHROME_LAUNCH_OPTS = {};
const LIGHTHOUSE_FLAGS = {logLevel: 'info'};
const SKIPPED_HTTPS_AUDITS = ['redirects-http'];
const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer/';
const WAIT_FOR_SW_DELAY = 5000;
// Be less verbose on CI.
if (process.env.CI) {
LIGHTHOUSE_FLAGS.logLevel = 'error';
}
// Run
_main(process.argv.slice(2));
// Functions - Definitions
async function _main(args) {
const {url, minScore, logFile} = parseInput(args);
const isOnHttp = /^http:/.test(url);
const config = {
extends: 'lighthouse:default',
// Since the Angular ServiceWorker waits for the app to stabilize before registering,
// wait a few seconds after load to allow Lighthouse to reliably detect it.
passes: [{passName: 'defaultPass', pauseAfterLoadMs: WAIT_FOR_SW_DELAY}],
}
console.log(`Running PWA audit for '${url}'...`);
// If testing on HTTP, skip HTTPS-specific tests.
// (Note: Browsers special-case localhost and run ServiceWorker even on HTTP.)
if (isOnHttp) skipHttpsAudits(config);
logger.setLevel(LIGHTHOUSE_FLAGS.logLevel);
try {
const results = await launchChromeAndRunLighthouse(url, LIGHTHOUSE_FLAGS, config);
const score = await processResults(results, logFile);
evaluateScore(minScore, score);
} catch (err) {
onError(err);
}
}
function evaluateScore(expectedScore, actualScore) {
console.log('\nLighthouse PWA score:');
console.log(` - Expected: ${expectedScore.toFixed(0).padStart(3)} / 100 (or higher)`);
console.log(` - Actual: ${actualScore.toFixed(0).padStart(3)} / 100\n`);
if (isNaN(actualScore) || (actualScore < expectedScore)) {
throw new Error(`PWA score is too low. (${actualScore} < ${expectedScore})`);
}
}
async function launchChromeAndRunLighthouse(url, flags, config) {
const chrome = await chromeLauncher.launch(CHROME_LAUNCH_OPTS);
flags.port = chrome.port;
try {
return await lighthouse(url, flags, config);
} finally {
await chrome.kill();
}
}
function onError(err) {
console.error(err);
process.exit(1);
}
function parseInput(args) {
const url = args[0];
const minScore = Number(args[1]);
const logFile = args[2];
if (!url) {
onError('Invalid arguments: <URL> not specified.');
} else if (isNaN(minScore)) {
onError('Invalid arguments: <MIN_SCORE> not specified or not a number.');
}
return {url, minScore, logFile};
}
async function processResults(results, logFile) {
const lhVersion = results.lhr.lighthouseVersion;
const categories = results.lhr.categories;
const report = results.report;
if (logFile) {
console.log(`\nSaving results in '${logFile}'...`);
console.log(`(LightHouse viewer: ${VIEWER_URL})`);
await printer.write(report, printer.OutputMode.json, logFile);
}
const categoryData = Object.keys(categories).map(name => categories[name]);
const maxTitleLen = Math.max(...categoryData.map(({title}) => title.length));
console.log(`\nLighthouse version: ${lhVersion}`);
console.log('\nAudit scores:');
categoryData.forEach(({title, score}) => {
const paddedTitle = `${title}:`.padEnd(maxTitleLen + 1);
const paddedScore = (score * 100).toFixed(0).padStart(3);
console.log(` - ${paddedTitle} ${paddedScore} / 100`);
});
return categories.pwa.score * 100;
}
function skipHttpsAudits(config) {
console.info(`Skipping HTTPS-related audits (${SKIPPED_HTTPS_AUDITS.join(', ')})...`);
const settings = config.settings || (config.settings = {});
settings.skipAudits = SKIPPED_HTTPS_AUDITS;
}

View File

@ -15,7 +15,7 @@
</aio-select> </aio-select>
<div class="form-search"> <div class="form-search">
<input #filter placeholder="Filter" (input)="setQuery($event.target.value)"> <input #filter placeholder="Filter" (input)="setQuery($event.target.value)" aria-label="Filter Search">
<i class="material-icons">search</i> <i class="material-icons">search</i>
</div> </div>
</div> </div>

View File

@ -4,9 +4,9 @@ import { VersionInfo } from 'app/navigation/navigation.service';
@Component({ @Component({
selector: 'aio-mode-banner', selector: 'aio-mode-banner',
template: ` template: `
<div *ngIf="mode == 'archive'" class="mode-banner"> <div *ngIf="mode == 'archive'" class="mode-banner alert archive-warning">
This is the <strong>archived documentation for Angular v{{version?.major}}.</strong> <p>This is the <strong>archived documentation for Angular v{{version?.major}}.</strong>
Please visit <a href="https://angular.io/">angular.io</a> to see documentation for the current version of Angular. Please visit <a href="https://angular.io/">angular.io</a> to see documentation for the current version of Angular.</p>
</div> </div>
` `
}) })

View File

@ -51,6 +51,8 @@ describe('ScrollService', () => {
spyOn(window, 'scrollBy'); spyOn(window, 'scrollBy');
}); });
afterEach(() => scrollService.ngOnDestroy());
it('should debounce `updateScrollPositonInHistory()`', fakeAsync(() => { it('should debounce `updateScrollPositonInHistory()`', fakeAsync(() => {
const updateScrollPositionInHistorySpy = spyOn(scrollService, 'updateScrollPositionInHistory'); const updateScrollPositionInHistorySpy = spyOn(scrollService, 'updateScrollPositionInHistory');
@ -65,6 +67,25 @@ describe('ScrollService', () => {
expect(updateScrollPositionInHistorySpy).toHaveBeenCalledTimes(1); expect(updateScrollPositionInHistorySpy).toHaveBeenCalledTimes(1);
})); }));
it('should stop updating scroll position once destroyed', fakeAsync(() => {
const updateScrollPositionInHistorySpy = spyOn(scrollService, 'updateScrollPositionInHistory');
window.dispatchEvent(new Event('scroll'));
tick(250);
expect(updateScrollPositionInHistorySpy).toHaveBeenCalledTimes(1);
window.dispatchEvent(new Event('scroll'));
tick(250);
expect(updateScrollPositionInHistorySpy).toHaveBeenCalledTimes(2);
updateScrollPositionInHistorySpy.calls.reset();
scrollService.ngOnDestroy();
window.dispatchEvent(new Event('scroll'));
tick(250);
expect(updateScrollPositionInHistorySpy).not.toHaveBeenCalled();
}));
it('should set `scrollRestoration` to `manual` if supported', () => { it('should set `scrollRestoration` to `manual` if supported', () => {
if (scrollService.supportManualScrollRestoration) { if (scrollService.supportManualScrollRestoration) {
expect(window.history.scrollRestoration).toBe('manual'); expect(window.history.scrollRestoration).toBe('manual');
@ -112,6 +133,23 @@ describe('ScrollService', () => {
expect(scrollService.topOffset).toBe(100 + topMargin); expect(scrollService.topOffset).toBe(100 + topMargin);
expect(document.querySelector).toHaveBeenCalled(); expect(document.querySelector).toHaveBeenCalled();
}); });
it('should stop updating on resize once destroyed', () => {
let clientHeight = 50;
(document.querySelector as jasmine.Spy).and.callFake(() => ({clientHeight}));
expect(scrollService.topOffset).toBe(50 + topMargin);
clientHeight = 100;
window.dispatchEvent(new Event('resize'));
expect(scrollService.topOffset).toBe(100 + topMargin);
scrollService.ngOnDestroy();
clientHeight = 200;
window.dispatchEvent(new Event('resize'));
expect(scrollService.topOffset).toBe(100 + topMargin);
});
}); });
describe('#topOfPageElement', () => { describe('#topOfPageElement', () => {

View File

@ -1,7 +1,7 @@
import { DOCUMENT, Location, PlatformLocation, PopStateEvent, ViewportScroller } from '@angular/common'; import { DOCUMENT, Location, PlatformLocation, PopStateEvent, ViewportScroller } from '@angular/common';
import { Injectable, Inject } from '@angular/core'; import { Injectable, Inject, OnDestroy } from '@angular/core';
import { fromEvent } from 'rxjs'; import { fromEvent, Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators'; import { debounceTime, takeUntil } from 'rxjs/operators';
type ScrollPosition = [number, number]; type ScrollPosition = [number, number];
interface ScrollPositionPopStateEvent extends PopStateEvent { interface ScrollPositionPopStateEvent extends PopStateEvent {
@ -14,10 +14,11 @@ export const topMargin = 16;
* A service that scrolls document elements into view * A service that scrolls document elements into view
*/ */
@Injectable() @Injectable()
export class ScrollService { export class ScrollService implements OnDestroy {
private _topOffset: number | null; private _topOffset: number | null;
private _topOfPageElement: Element; private _topOfPageElement: Element;
private onDestroy = new Subject<void>();
// The scroll position which has to be restored, after a `popstate` event. // The scroll position which has to be restored, after a `popstate` event.
poppedStateScrollPosition: ScrollPosition | null = null; poppedStateScrollPosition: ScrollPosition | null = null;
@ -49,10 +50,13 @@ export class ScrollService {
private viewportScroller: ViewportScroller, private viewportScroller: ViewportScroller,
private location: Location) { private location: Location) {
// On resize, the toolbar might change height, so "invalidate" the top offset. // On resize, the toolbar might change height, so "invalidate" the top offset.
fromEvent(window, 'resize').subscribe(() => this._topOffset = null); fromEvent(window, 'resize')
.pipe(takeUntil(this.onDestroy))
.subscribe(() => this._topOffset = null);
fromEvent(window, 'scroll') fromEvent(window, 'scroll')
.pipe(debounceTime(250)).subscribe(() => this.updateScrollPositionInHistory()); .pipe(debounceTime(250), takeUntil(this.onDestroy))
.subscribe(() => this.updateScrollPositionInHistory());
// Change scroll restoration strategy to `manual` if it's supported // Change scroll restoration strategy to `manual` if it's supported
if (this.supportManualScrollRestoration) { if (this.supportManualScrollRestoration) {
@ -75,6 +79,10 @@ export class ScrollService {
} }
} }
ngOnDestroy() {
this.onDestroy.next();
}
/** /**
* Scroll to the element with id extracted from the current location hash fragment. * Scroll to the element with id extracted from the current location hash fragment.
* Scroll to top if no hash. * Scroll to top if no hash.

View File

@ -26,5 +26,5 @@
</ng-template> </ng-template>
<ng-template #notFound> <ng-template #notFound>
<p>{{notFoundMessage}}</p> <p class="not-found">{{notFoundMessage}}</p>
</ng-template> </ng-template>

View File

@ -1,6 +1,6 @@
<div class="form-select-menu"> <div class="form-select-menu">
<button class="form-select-button" (click)="toggleOptions()" [disabled]="disabled"> <button class="form-select-button" (click)="toggleOptions()" [disabled]="disabled">
<strong>{{label}}</strong><span *ngIf="showSymbol" class="symbol {{selected?.value}}"></span>{{selected?.title}} <span><strong>{{label}}</strong></span><span *ngIf="showSymbol" class="symbol {{selected?.value}}"></span><span>{{selected?.title}}</span>
</button> </button>
<ul class="form-select-dropdown" *ngIf="showOptions"> <ul class="form-select-dropdown" *ngIf="showOptions">
<li *ngFor="let option of options; index as i" <li *ngFor="let option of options; index as i"
@ -10,7 +10,7 @@
(click)="select(option, i)" (click)="select(option, i)"
(keydown.enter)="select(option, i)" (keydown.enter)="select(option, i)"
(keydown.space)="select(option, i); $event.preventDefault()"> (keydown.space)="select(option, i); $event.preventDefault()">
<span *ngIf="showSymbol" class="symbol {{option.value}}"></span>{{option.title}} <span *ngIf="showSymbol" class="symbol {{option.value}}"></span><span>{{option.title}}</span>
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -41,13 +41,11 @@ describe('SelectComponent', () => {
expect(getButton().textContent!.trim()).toEqual('Label:'); expect(getButton().textContent!.trim()).toEqual('Label:');
}); });
it('should contain a symbol `<span>` if hasSymbol is true', () => { it('should contain a symbol if hasSymbol is true', () => {
expect(getButton().querySelector('span')).toEqual(null); expect(getButtonSymbol()).toEqual(null);
host.showSymbol = true; host.showSymbol = true;
fixture.detectChanges(); fixture.detectChanges();
const span = getButton().querySelector('span'); expect(getButtonSymbol()).not.toEqual(null);
expect(span).not.toEqual(null);
expect(span!.className).toContain('symbol');
}); });
it('should display the selected option, if there is one', () => { it('should display the selected option, if there is one', () => {
@ -55,7 +53,7 @@ describe('SelectComponent', () => {
host.selected = options[0]; host.selected = options[0];
fixture.detectChanges(); fixture.detectChanges();
expect(getButton().textContent).toContain(options[0].title); expect(getButton().textContent).toContain(options[0].title);
expect(getButton().querySelector('span')!.className).toContain(options[0].value); expect(getButtonSymbol()!.className).toContain(options[0].value);
}); });
it('should toggle the visibility of the options list when clicked', () => { it('should toggle the visibility of the options list when clicked', () => {
@ -110,7 +108,7 @@ describe('SelectComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
expect(host.onChange).toHaveBeenCalledWith({ option: options[0], index: 0 }); expect(host.onChange).toHaveBeenCalledWith({ option: options[0], index: 0 });
expect(getButton().textContent).toContain(options[0].title); expect(getButton().textContent).toContain(options[0].title);
expect(getButton().querySelector('span')!.className).toContain(options[0].value); expect(getButtonSymbol()!.className).toContain(options[0].value);
}); });
it('should select the current option when enter is pressed', () => { it('should select the current option when enter is pressed', () => {
@ -119,7 +117,7 @@ describe('SelectComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
expect(host.onChange).toHaveBeenCalledWith({ option: options[0], index: 0 }); expect(host.onChange).toHaveBeenCalledWith({ option: options[0], index: 0 });
expect(getButton().textContent).toContain(options[0].title); expect(getButton().textContent).toContain(options[0].title);
expect(getButton().querySelector('span')!.className).toContain(options[0].value); expect(getButtonSymbol()!.className).toContain(options[0].value);
}); });
it('should select the current option when space is pressed', () => { it('should select the current option when space is pressed', () => {
@ -128,7 +126,7 @@ describe('SelectComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
expect(host.onChange).toHaveBeenCalledWith({ option: options[0], index: 0 }); expect(host.onChange).toHaveBeenCalledWith({ option: options[0], index: 0 });
expect(getButton().textContent).toContain(options[0].title); expect(getButton().textContent).toContain(options[0].title);
expect(getButton().querySelector('span')!.className).toContain(options[0].value); expect(getButtonSymbol()!.className).toContain(options[0].value);
}); });
it('should hide when an option is clicked', () => { it('should hide when an option is clicked', () => {
@ -177,6 +175,10 @@ function getButton(): HTMLButtonElement {
return element.query(By.css('button')).nativeElement; return element.query(By.css('button')).nativeElement;
} }
function getButtonSymbol(): HTMLElement | null {
return getButton().querySelector('.symbol');
}
function getOptionContainer(): HTMLUListElement|null { function getOptionContainer(): HTMLUListElement|null {
const de = element.query(By.css('ul')); const de = element.query(By.css('ul'));
return de && de.nativeElement; return de && de.nativeElement;

View File

@ -246,12 +246,7 @@ section#intro {
} }
.button.hero-cta { .button.hero-cta {
display: flex; padding: 2px 34px 0;
align-items: center;
justify-content: center;
width: 184px;
height: 40px;
padding: 0 24px;
@include font-size(18); @include font-size(18);
font-weight: 600; font-weight: 600;
@include line-height(40); @include line-height(40);

View File

@ -1,7 +1,3 @@
#file-not-found {
padding: 3rem 3rem 3rem;
}
.nf-container { .nf-container {
align-items: center; align-items: center;
padding: 32px; padding: 32px;

View File

@ -192,6 +192,11 @@ aio-search-box.search-container {
outline: none; outline: none;
} }
@include placeholder {
@include font-size(14);
color: $mediumgray;
}
@include bp(big) { @include bp(big) {
transition: width 0.4s ease-in-out; transition: width 0.4s ease-in-out;

View File

@ -38,6 +38,26 @@
} }
} }
&.archive-warning {
background-color: $darkred;
border-radius: 4px;
margin-bottom: 1rem;
* {
color: $white;
}
a {
color: $white;
font-weight: bold;
text-decoration: underline;
&:hover {
opacity: 0.9;
}
}
}
> * { > * {
margin: 8px 16px; margin: 8px 16px;
} }

View File

@ -15,12 +15,17 @@ aio-api-list {
.form-search input { .form-search input {
width: 182px; width: 182px;
@media screen and (max-width: 600px) {
width: 100%;
}
} }
.api-list-container { .api-list-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin: 0 auto; margin: 0 auto;
padding-left: 0;
h2 { h2 {
margin-top: 16px; margin-top: 16px;
@ -37,8 +42,17 @@ aio-api-list {
margin: 16px auto; margin: 16px auto;
} }
.form-select-menu, .form-search { .form-select-menu,
.form-search {
margin: 8px; margin: 8px;
@media screen and (max-width: 600px) {
margin-left: 0;
}
}
aio-select:first-child .form-select-menu {
margin-left: 0;
} }
} }
@ -69,32 +83,17 @@ aio-api-list {
box-shadow: 0 2px 2px rgba($black, 0.24), 0 0 2px rgba($black, 0.12); box-shadow: 0 2px 2px rgba($black, 0.24), 0 0 2px rgba($black, 0.12);
box-sizing: border-box; box-sizing: border-box;
border: 1px solid $white; border: 1px solid $white;
color: $blue-600; border-radius: 4px;
@include font-size(16); color: $darkgray;
height: 32px; @include font-size(14);
@include line-height(32); @include line-height(32);
outline: none; outline: none;
padding: 0 16px 0 32px; padding: 4px 16px 4px 32px;
transition: all .2s; transition: all .2s;
// PLACEHOLDER TEXT @include placeholder {
// NOTE: Vendor-prefixed selectors must be on separate blocks, because one invalid/unknown
// selector will invalidate the whole block.
&::placeholder { // Chrome/Firefox/Safari
color: $blue-grey-100;
@include font-size(14);
}
&::-webkit-input-placeholder { // QQ Browser
color: $blue-grey-100;
@include font-size(14);
}
&::-ms-input-placeholder { // Edge
color: $blue-grey-100;
@include font-size(14);
}
&:-ms-input-placeholder { // IE
color: $blue-grey-100;
@include font-size(14); @include font-size(14);
color: $mediumgray;
} }
&:focus { &:focus {
@ -108,7 +107,7 @@ aio-api-list {
@include font-size(20); @include font-size(20);
left: 8px; left: 8px;
position: absolute; position: absolute;
top: 6px; top: 12px;
z-index: $layer-1; z-index: $layer-1;
} }
} }
@ -149,6 +148,10 @@ aio-api-list {
aio-select { aio-select {
width: 200px; width: 200px;
@media screen and (max-width: 600px) {
width: 100%;
}
.symbol { .symbol {
margin-right: 8px; margin-right: 8px;
} }

View File

@ -12,6 +12,7 @@
@import 'code'; @import 'code';
@import 'contribute'; @import 'contribute';
@import 'contributor'; @import 'contributor';
@import 'deploy-theme';
@import 'details'; @import 'details';
@import 'edit-page-cta'; @import 'edit-page-cta';
@import 'features'; @import 'features';
@ -19,14 +20,13 @@
@import 'heading-anchors'; @import 'heading-anchors';
@import 'hr'; @import 'hr';
@import 'images'; @import 'images';
@import 'label';
@import 'notification';
@import 'progress-bar'; @import 'progress-bar';
@import 'table';
@import 'presskit'; @import 'presskit';
@import 'resources'; @import 'resources';
@import 'scrollbar'; @import 'scrollbar';
@import 'search-results'; @import 'search-results';
@import 'toc';
@import 'select-menu'; @import 'select-menu';
@import 'deploy-theme'; @import 'table';
@import 'notification'; @import 'toc';
@import 'label';

View File

@ -1,14 +1,12 @@
aio-search-results { aio-search-results {
z-index: 10; z-index: 10;
}
.search-results { .search-results {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-around; justify-content: space-around;
overflow: auto; overflow: auto;
padding: 68px 32px 0; padding: 68px 32px 0;
color: $offwhite;
width: auto; width: auto;
max-height: 95vh; max-height: 95vh;
position: fixed; position: fixed;
@ -20,81 +18,91 @@ aio-search-results {
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.3); box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.3);
box-sizing: border-box; box-sizing: border-box;
@media (max-width: 480px) { .search-area {
display: block; margin: 16px;
.search-area { height: 100%;
display: block;
margin: 16px 16px;
}
}
}
aio-search-results.embedded .search-results { .search-section-header {
padding: 0;
color: inherit;
width: auto;
max-height: 100%;
position: relative;
background-color: inherit;
box-shadow: none;
box-sizing: border-box;
.search-area a {
color: lighten($darkgray, 10);
&:hover {
color: $accentblue;
}
}
}
.search-area {
display: flex;
flex-direction: column;
margin: 16px 16px;
height: 100%;
.search-section-header {
@include font-size(16); @include font-size(16);
font-weight: 400; font-weight: 400;
margin: 10px 0px 5px; margin: 10px 0px 5px;
text-transform: uppercase; text-transform: uppercase;
color: $white; color: $white;
} }
ul { ul {
margin: 0; margin: 0;
padding: 0; padding: 0;
li { li {
list-style: none; list-style: none;
} }
}
a { .search-result-item {
@include font-size(14); @include font-size(14);
color: $lightgray; color: $lightgray;
text-decoration: none; font-weight: normal;
font-weight: normal;
&:hover { &a {
text-decoration: none;
}
&:hover {
color: $white; color: $white;
} }
&:visited {
text-decoration: none; .symbol {
margin-right: 8px;
}
} }
span.symbol { &.priority-pages {
margin-right: 8px; padding: 0.5rem 0;
}
}
.priority-pages { .search-result-item {
padding: 0.5rem 0;
a {
font-weight: bold; font-weight: bold;
}
} }
}
} }
@include bp(tiny) { .not-found {
display: block; color: $white;
text-align: center;
margin: 16px;
} }
@media (max-width: 600px) {
display: block;
}
}
&.embedded {
.search-results {
padding: 0;
color: inherit;
max-height: 100%;
position: relative;
background-color: inherit;
box-shadow: none;
.search-area {
.search-section-header {
color: $darkgray;
}
.search-result-item {
color: lighten($darkgray, 10);
&:hover {
color: $accentblue;
}
}
}
.not-found {
color: $darkgray;
}
}
}
} }

View File

@ -9,21 +9,24 @@
box-shadow: 0 2px 2px rgba($black, 0.24), 0 0 2px rgba($black, 0.12); box-shadow: 0 2px 2px rgba($black, 0.24), 0 0 2px rgba($black, 0.12);
box-sizing: border-box; box-sizing: border-box;
border: 1px solid $white; border: 1px solid $white;
border-radius: 4px;
color: $blue-grey-600; color: $blue-grey-600;
@include font-size(12); @include font-size(14);
font-weight: 400; font-weight: 400;
height: 32px;
@include line-height(32); @include line-height(32);
outline: none; outline: none;
padding: 0 16px; padding: 4px 16px;
text-align: left; text-align: left;
width: 100%; width: 100%;
cursor: pointer; cursor: pointer;
display: flex;
align-items: center;
flex-direction: row;
strong { strong {
font-weight: 600; font-weight: 600;
margin-right: 8px; margin-right: 8px;
text-transform: uppercase; text-transform: capitalize;
} }
&:focus { &:focus {
@ -54,9 +57,18 @@
@include font-size(14); @include font-size(14);
@include line-height(32); @include line-height(32);
margin: 0; margin: 0;
padding: 0 16px 0 40px; padding: 4px 16px 4px 40px;
position: relative; position: relative;
transition: all .2s; transition: all .2s;
border: 1px solid transparent;
&:first-child {
border-radius: 4px 4px 0 0;
}
&:last-child {
border-radius: 0 0 4px 4px;
}
&:hover { &:hover {
background: $blue-grey-50; background: $blue-grey-50;
@ -70,7 +82,7 @@
.symbol { .symbol {
left: 16px; left: 16px;
position: absolute; position: absolute;
top: 8px; top: 12px;
z-index: $layer-5; z-index: $layer-5;
} }
} }

View File

@ -6,8 +6,189 @@
bottom: 12px; bottom: 12px;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
.toc-inner {
@include font-size(13);
overflow-y: visible;
padding: 4px 0 0 10px;
.toc-heading,
.toc-list .h1 {
@include font-size(16);
}
.toc-heading {
font-weight: 500;
margin: 0 0 16px 8px;
padding: 0;
&.secondary {
position: relative;
top: -8px;
&:hover {
color: $accentblue;
}
}
}
button.toc-heading,
button.toc-more-items {
cursor: pointer;
display: inline-block;
background: 0;
background-color: transparent;
border: none;
box-shadow: none;
padding: 0;
text-align: start;
&.embedded:focus {
outline: none;
background: $lightgray;
}
}
button.toc-heading {
mat-icon.rotating-icon {
height: 18px;
width: 18px;
position: relative;
left: -4px;
top: 5px;
}
&:hover:not(.embedded) {
color: $accentblue;
}
}
button.toc-more-items {
color: $mediumgray;
top: 10px;
position: relative;
&:hover {
color: $accentblue;
}
&::after {
content: 'expand_less';
}
&.collapsed::after {
content: 'more_horiz';
}
}
.mat-icon {
&.collapsed {
@include rotate(0deg);
}
&:not(.collapsed) {
@include rotate(90deg);
}
}
ul.toc-list {
list-style-type: none;
margin: 0;
padding: 0 8px 0 0;
@media (max-width: 800px) {
width: auto;
}
li {
box-sizing: border-box;
@include font-size(12);
@include line-height(16);
padding: 3px 0 3px 12px;
position: relative;
transition: all 0.3s ease-in-out;
&.h1:after {
content: '';
display: block;
height: 1px;
width: 40%;
margin: 7px 0 4px 0;
background: $lightgray;
clear: both;
}
&.h3 {
padding-left: 24px;
}
a {
color: lighten($darkgray, 10);
overflow: visible;
@include font-size(12);
display: table-cell;
}
&:hover {
* {
color: $accentblue;
}
}
&.active {
* {
color: $blue;
font-weight: 500;
&:before {
content: '';
border-radius: 50%;
left: -3px;
top: 12px;
background: $blue;
position: absolute;
width: 6px;
height: 6px;
}
}
}
}
&:not(.embedded) li {
&:before {
border-left: 1px solid $lightgray;
bottom: 0;
content: '';
left: 0;
position: absolute;
top: 0;
}
&:first-child:before {
top: 13px;
}
&:last-child:before {
bottom: calc(100% - 14px);
}
&:not(.active):hover a:before {
content: '';
border-radius: 50%;
left: -3px;
top: 12px;
background: $lightgray;
position: absolute;
width: 6px;
height: 6px;
}
}
}
}
} }
// Alternative TOC View for Smaller Screens
aio-toc.embedded { aio-toc.embedded {
@media (min-width: 801px) { @media (min-width: 801px) {
display: none; display: none;
@ -20,186 +201,8 @@ aio-toc.embedded {
margin: 0 0 8px; margin: 0 0 8px;
} }
} }
}
> div.collapsed li.secondary {
.toc-inner { display: none;
@include font-size(13); }
overflow-y: visible;
padding: 4px 0 0 10px;
.toc-heading,
.toc-list .h1 {
@include font-size(16);
}
.toc-heading {
font-weight: 500;
margin: 0 0 16px 8px;
padding: 0;
}
.toc-heading.secondary {
position: relative;
top: -8px;
&:hover {
color: $accentblue;
}
}
button.toc-heading,
button.toc-more-items {
cursor: pointer;
display: inline-block;
background: 0;
background-color: transparent;
border: none;
box-shadow: none;
padding: 0;
text-align: start;
&.embedded:focus {
outline: none;
background: $lightgray;
}
}
button.toc-heading {
mat-icon.rotating-icon {
height: 18px;
width: 18px;
position: relative;
left: -4px;
top: 5px;
}
&:hover:not(.embedded) {
color: $accentblue;
}
}
button.toc-more-items {
color: $mediumgray;
top: 10px;
position: relative;
&:hover {
color: $accentblue;
}
}
button.toc-more-items::after {
content: 'expand_less';
}
button.toc-more-items.collapsed::after {
content: 'more_horiz';
}
.mat-icon.collapsed {
@include rotate(0deg);
}
.mat-icon:not(.collapsed) {
@include rotate(90deg);
// margin: 4px;
}
ul.toc-list {
list-style-type: none;
margin: 0;
padding: 0 8px 0 0;
@media (max-width: 800px) {
width: auto;
}
li {
box-sizing: border-box;
@include font-size(12);
@include line-height(16);
padding: 3px 0 3px 12px;
position: relative;
transition: all 0.3s ease-in-out;
&.h1:after {
content: '';
display: block;
height: 1px;
width: 40%;
margin: 7px 0 4px 0;
background: #DBDBDB;
clear: both;
}
&.h3 {
padding-left: 24px;
}
a {
color: lighten($darkgray, 10);
overflow: visible;
@include font-size(12);
display: table-cell;
}
&:hover a {
color: $accentblue;
}
&.active {
a {
color: $blue;
font-weight: 500;
&:before {
content: '';
border-radius: 50%;
left: -3px;
top: 12px;
background: $blue;
position: absolute;
width: 6px;
height: 6px;
}
}
}
}
&:not(.embedded) li {
&:before {
border-left: 1px solid $lightgray;
bottom: 0;
content: '';
left: 0;
position: absolute;
top: 0;
}
&:first-child:before {
top: 13px;
}
&:last-child:before {
bottom: calc(100% - 14px);
}
&:not(.active):hover a:before {
content: '';
border-radius: 50%;
left: -3px;
top: 12px;
background: $lightgray;
position: absolute;
width: 6px;
height: 6px;
}
}
}
}
aio-toc.embedded > div.collapsed li.secondary {
display: none;
} }

View File

@ -56,6 +56,16 @@
line-height: ($heightValue / 10) + rem; line-height: ($heightValue / 10) + rem;
} }
// PLACEHOLDER
// NOTE: Vendor-prefixed selectors must be on separate blocks, because one invalid/unknown
// selector will invalidate the whole block.
@mixin placeholder {
&:-ms-input-placeholder { @content; } // IE
&::-ms-input-placeholder { @content; } // Edge
&::-webkit-input-placeholder { @content; } // QQ Browser
&::placeholder { @content; } // Chrome/Firefox/Safari
}
@mixin rotate($degrees) { @mixin rotate($degrees) {
-moz-transform: rotate($degrees); -moz-transform: rotate($degrees);
-webkit-transform: rotate($degrees); -webkit-transform: rotate($degrees);

View File

@ -0,0 +1,23 @@
{
"scripts": [
{ "name": "ng", "command": "ng" },
{ "name": "build", "command": "ng build --prod" },
{ "name": "start", "command": "ng serve" },
{ "name": "test", "command": "ng test" },
{ "name": "lint", "command": "ng lint" },
{ "name": "e2e", "command": "ng e2e" }
],
"dependencies": [
"angular",
"angular-route"
],
"devDependencies": [
"@angular/cli",
"@types/angular",
"@types/angular-route",
"@types/jasminewd2",
"jasmine-spec-reporter",
"karma-coverage-istanbul-reporter",
"ts-node"
]
}

View File

@ -82,7 +82,7 @@ class ExampleZipper {
const exampleDirName = path.dirname(configFileName); const exampleDirName = path.dirname(configFileName);
const outputFileName = path.join(outputDirName, relativeDirName, exampleZipName + '.zip'); const outputFileName = path.join(outputDirName, relativeDirName, exampleZipName + '.zip');
let defaultIncludes = ['**/*.ts', '**/*.js', '**/*.es6', '**/*.css', '**/*.html', '**/*.md', '**/*.json', '**/*.png']; let defaultIncludes = ['**/*.ts', '**/*.js', '**/*.es6', '**/*.css', '**/*.html', '**/*.md', '**/*.json', '**/*.png', '**/*.svg'];
let alwaysIncludes = [ let alwaysIncludes = [
'bs-config.json', 'bs-config.json',
'e2e/protractor.conf.js', 'e2e/protractor.conf.js',

View File

@ -57,6 +57,11 @@ BOILERPLATE_PATHS.schematics = [
'angular.json' 'angular.json'
]; ];
BOILERPLATE_PATHS['cli-ajs'] = [
...cliRelativePath,
'package.json'
];
const EXAMPLE_CONFIG_FILENAME = 'example-config.json'; const EXAMPLE_CONFIG_FILENAME = 'example-config.json';
class ExampleBoilerPlate { class ExampleBoilerPlate {

View File

@ -0,0 +1,56 @@
{
"name": "angular.io-example",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "^8.0.0",
"@angular/common": "^8.0.0",
"@angular/compiler": "^8.0.0",
"@angular/core": "^8.0.0",
"@angular/forms": "^8.0.0",
"@angular/platform-browser": "^8.0.0",
"@angular/platform-browser-dynamic": "^8.0.0",
"@angular/router": "^8.0.0",
"angular": "1.7.8",
"angular-in-memory-web-api": "^0.8.0",
"angular-route": "1.7.8",
"core-js": "^2.5.4",
"rxjs": "^6.5.1",
"tslib": "^1.9.0",
"web-animations-js": "^2.3.1",
"zone.js": "~0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^0.800.0",
"@angular/cli": "^8.0.0",
"@angular/compiler-cli": "^8.0.0",
"@angular/language-service": "^8.0.0",
"@types/angular": "^1.6.47",
"@types/angular-route": "^1.3.5",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"codelyzer": "~5.0.0",
"jasmine-core": "~2.99.1",
"jasmine-marbles": "^0.5.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.1.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.15.0",
"typescript": "~3.4.4"
}
}

View File

@ -12,7 +12,7 @@
}, },
"engines": { "engines": {
"node": ">=10.9.0 <11.0.0", "node": ">=10.9.0 <11.0.0",
"yarn": ">=1.10.1 <1.14.0" "yarn": ">=1.12.1 <=1.16.0"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
@ -32,7 +32,9 @@
"@nguniversal/common": "^8.0.0-rc.1", "@nguniversal/common": "^8.0.0-rc.1",
"@nguniversal/express-engine": "^8.0.0-rc.1", "@nguniversal/express-engine": "^8.0.0-rc.1",
"@nguniversal/module-map-ngfactory-loader": "^8.0.0-rc.1", "@nguniversal/module-map-ngfactory-loader": "^8.0.0-rc.1",
"angular": "1.7.8",
"angular-in-memory-web-api": "github:brandonroberts/in-memory-web-api-bazel#50a34d8", "angular-in-memory-web-api": "github:brandonroberts/in-memory-web-api-bazel#50a34d8",
"angular-route": "1.7.8",
"core-js": "^2.5.4", "core-js": "^2.5.4",
"express": "^4.14.1", "express": "^4.14.1",
"rxjs": "^6.5.1", "rxjs": "^6.5.1",

View File

@ -801,6 +801,16 @@ amdefine@>=0.0.4:
dependencies: dependencies:
tslib "^1.9.0" tslib "^1.9.0"
angular-route@1.7.8:
version "1.7.8"
resolved "https://registry.yarnpkg.com/angular-route/-/angular-route-1.7.8.tgz#d502aa605dcbb253a93e844c0adf51c9bc36b9fa"
integrity sha512-VVk89PH0fsY5kfbx+N7IVX1IwnaPWYhMGY0uA+rjej2v1sjvrTx1SLkxUK4E0UpW1hXeLJhN7ncBcwoBiPtAtA==
angular@1.7.8:
version "1.7.8"
resolved "https://registry.yarnpkg.com/angular/-/angular-1.7.8.tgz#b77ede272ce1b261e3be30c1451a0b346905a3c9"
integrity sha512-wtef/y4COxM7ZVhddd7JtAAhyYObq9YXKar9tsW7558BImeVYteJiTxCKeJOL45lJ/+7B4wrAC49j8gTFYEthg==
ansi-colors@^3.0.0: ansi-colors@^3.0.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.1.0.tgz#dcfaacc90ef9187de413ec3ef8d5eb981a98808f" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.1.0.tgz#dcfaacc90ef9187de413ec3ef8d5eb981a98808f"

View File

@ -249,7 +249,7 @@ class StackblitzBuilder {
throw new Error(`Stackblitz config - unable to parse json file: ${configFileName}\n${e}`); throw new Error(`Stackblitz config - unable to parse json file: ${configFileName}\n${e}`);
} }
var defaultIncludes = ['**/*.ts', '**/*.js', '**/*.css', '**/*.html', '**/*.md', '**/*.json', '**/*.png']; var defaultIncludes = ['**/*.ts', '**/*.js', '**/*.css', '**/*.html', '**/*.md', '**/*.json', '**/*.png', '**/*.svg'];
var boilerplateIncludes = ['src/environments/*.*', 'angular.json', 'src/polyfills.ts']; var boilerplateIncludes = ['src/environments/*.*', 'angular.json', 'src/polyfills.ts'];
if (config.files) { if (config.files) {
if (config.files.length > 0) { if (config.files.length > 0) {

View File

@ -14,7 +14,7 @@ const linksPackage = require('../links-package');
const examplesPackage = require('../examples-package'); const examplesPackage = require('../examples-package');
const targetPackage = require('../target-package'); const targetPackage = require('../target-package');
const remarkPackage = require('../remark-package'); const remarkPackage = require('../remark-package');
const postProcessPackage = require('../post-process-package'); const postProcessPackage = require('dgeni-packages/post-process-html');
const { PROJECT_ROOT, CONTENTS_PATH, OUTPUT_PATH, DOCS_OUTPUT_PATH, TEMPLATES_PATH, AIO_PATH, requireFolder } = require('../config'); const { PROJECT_ROOT, CONTENTS_PATH, OUTPUT_PATH, DOCS_OUTPUT_PATH, TEMPLATES_PATH, AIO_PATH, requireFolder } = require('../config');

View File

@ -16,9 +16,12 @@ regionParserImpl.regionMatchers = {
es6: inlineC, es6: inlineC,
dart: inlineC, dart: inlineC,
html: html, html: html,
svg: html,
css: blockC, css: blockC,
yaml: inlineHash, yaml: inlineHash,
yml: inlineHash,
jade: inlineCOnly, jade: inlineCOnly,
pug: inlineCOnly,
json: inlineC, json: inlineC,
'json.annotated': inlineC 'json.annotated': inlineC
}; };

View File

@ -1,5 +0,0 @@
var Package = require('dgeni').Package;
var base = require('dgeni-packages/base');
module.exports = new Package('post-process-package', [base])
.processor(require('./processors/post-process-html'));

View File

@ -1,49 +0,0 @@
const rehype = require('rehype');
/**
* @dgProcessor postProcessHtml
*
* @description
* Use the rehype processing engine to manipulate the
* `renderedContent` HTML via rehype "plugins" that work with HTML ASTs (HASTs).
* See https://github.com/wooorm/rehype
*
* Each plugin is a factory function that will be called with the "rehype" engine as `this`.
* The factory should return a "transform" function that takes a HAST and returns a `boolean` or `undefined`.
* The HAST can be mutated by the "transform" function.
* If `false` is returned then the processing stops with that plugin.
*
* @property docTypes {string[]} the `docTypes` of docs that should be post-processed
* @property plugins {Function[]} the rehype plugins that will modify the HAST.
*
*/
module.exports = function postProcessHtml(log, createDocMessage) {
return {
$runAfter: ['docs-rendered'],
$runBefore: ['writing-files'],
docTypes: [],
plugins: [],
$process(docs) {
const engine = rehype()
.data('settings', { fragment: true });
this.plugins.forEach(plugin => engine.use(plugin));
let vFile;
docs
.filter(doc => this.docTypes.indexOf(doc.docType) !== -1)
.forEach(doc => {
try {
vFile = engine.processSync(doc.renderedContent);
doc.renderedContent = vFile.contents;
vFile.messages.forEach(m => {
log.warn(createDocMessage(m.message, doc));
});
doc.vFile = vFile;
} catch(e) {
throw new Error(createDocMessage(e.message, doc));
}
});
}
};
};

View File

@ -1,84 +0,0 @@
const testPackage = require('../../helpers/test-package');
const Dgeni = require('dgeni');
describe('postProcessHtml', function() {
let dgeni, injector, processor, createDocMessage;
beforeEach(function() {
dgeni = new Dgeni([testPackage('post-process-package', true)]);
injector = dgeni.configureInjector();
createDocMessage = injector.get('createDocMessage');
processor = injector.get('postProcessHtml');
processor.docTypes = ['a', 'b'];
});
it('should be available from the injector', () => {
expect(processor).toBeDefined();
});
it('should only process docs that match the specified docTypes', () => {
const elements = [];
const captureFirstElement = ast => {
elements.push(ast.children[0].tagName);
};
processor.plugins = [() => captureFirstElement];
const docs = [
{ docType: 'a', renderedContent: '<a></a>' },
{ docType: 'b', renderedContent: '<b></b>' },
{ docType: 'c', renderedContent: '<c></c>' },
{ docType: 'd', renderedContent: '<d></d>' },
];
processor.$process(docs);
expect(elements).toEqual(['a', 'b']);
});
it('should run all the plugins on each doc', () => {
const capitalizeFirstElement = ast => {
ast.children[0].tagName = ast.children[0].tagName.toUpperCase();
};
const addOneToFirstElement = ast => {
ast.children[0].tagName = ast.children[0].tagName + '1';
};
const elements = [];
const captureFirstElement = ast => {
elements.push(ast.children[0].tagName);
};
const docs = [
{ docType: 'a', renderedContent: '<a></a>' },
{ docType: 'b', renderedContent: '<b></b>' },
{ docType: 'c', renderedContent: '<c></c>' },
{ docType: 'd', renderedContent: '<d></d>' },
];
processor.plugins = [
() => capitalizeFirstElement,
() => addOneToFirstElement,
() => captureFirstElement
];
processor.$process(docs);
expect(elements).toEqual(['A1', 'B1']);
});
it('should report non-fatal errors', () => {
const log = injector.get('log');
const addWarning = (ast, file) => {
file.message('There was a problem');
};
processor.plugins = [() => addWarning];
processor.$process([{ docType: 'a', renderedContent: '' }]);
expect(log.warn).toHaveBeenCalledWith('There was a problem - doc (a) ');
});
it('should throw on fatal errors', () => {
const log = injector.get('log');
const addError = (ast, file) => {
file.fail('There was an error');
};
const doc = { docType: 'a', renderedContent: '' };
processor.plugins = [() => addError];
expect(() => processor.$process([doc])).toThrowError(createDocMessage('There was an error', doc));
expect(log.error).not.toHaveBeenCalled();
});
});

View File

@ -4,7 +4,9 @@
module.exports = function code(h, node) { module.exports = function code(h, node) {
var value = node.value ? ('\n' + node.value + '\n') : ''; var value = node.value ? ('\n' + node.value + '\n') : '';
var lang = node.lang && node.lang.match(/^[^ \t]+(?=[ \t]|$)/); var lang = node.lang && node.lang.match(/^[^ \t]+(?=[ \t]|$)/);
var props = {}; var props = {
linenums: 'false'
};
if (lang) { if (lang) {
props.language = lang; props.language = lang;

View File

@ -88,7 +88,7 @@ describe('remark: renderMarkdown service', () => {
'```'; '```';
const output = renderMarkdown(content); const output = renderMarkdown(content);
expect(output).toEqual( expect(output).toEqual(
'<code-example language="ts">\n' + '<code-example linenums="false" language="ts">\n' +
' class MyClass {\n' + ' class MyClass {\n' +
' method1() { ... }\n' + ' method1() { ... }\n' +
' }\n' + ' }\n' +

View File

@ -20,7 +20,7 @@
<tbody> <tbody>
{% for option in arguments %} {% for option in arguments %}
<tr class="cli-option"> <tr class="cli-option">
<td><code class="no-auto-link">&lt;<var>{$ option.name $}</var>&gt;</code></td> <td><code class="cli-option-syntax no-auto-link">&lt;<var>{$ option.name $}</var>&gt;{% if option.enum.length > 0 %}={$ renderValues(option.enum) $}{% endif %}</code></td>
<td> <td>
{$ option.description | marked $} {$ option.description | marked $}
{% if option.subcommands.length -%} {% if option.subcommands.length -%}

View File

@ -353,10 +353,6 @@
version "0.7.0" version "0.7.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd"
"@types/core-js@^0.9.41":
version "0.9.43"
resolved "https://registry.yarnpkg.com/@types/core-js/-/core-js-0.9.43.tgz#65d646c5e8c0cd1bdee37065799f9d3d48748253"
"@types/events@*": "@types/events@*":
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
@ -398,19 +394,11 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/mkdirp@^0.3.29":
version "0.3.29"
resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.3.29.tgz#7f2ad7ec55f914482fc9b1ec4bb1ae6028d46066"
"@types/node@*": "@types/node@*":
version "11.11.3" version "11.11.3"
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.3.tgz#7c6b0f8eaf16ae530795de2ad1b85d34bf2f5c58" resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.3.tgz#7c6b0f8eaf16ae530795de2ad1b85d34bf2f5c58"
integrity sha512-wp6IOGu1lxsfnrD+5mX6qwSwWuqsdkKKxTN4aQc4wByHAKZJf9/D4KXPQ1POUjEbnCP5LMggB0OEFNY9OTsMqg== integrity sha512-wp6IOGu1lxsfnrD+5mX6qwSwWuqsdkKKxTN4aQc4wByHAKZJf9/D4KXPQ1POUjEbnCP5LMggB0OEFNY9OTsMqg==
"@types/node@^9.3.0":
version "9.6.35"
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.35.tgz#197dd535c094362a7c95f0b78f07583d6681ed26"
"@types/node@~6.0.60": "@types/node@~6.0.60":
version "6.0.118" version "6.0.118"
resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.118.tgz#8014a9b1dee0b72b4d7cd142563f1af21241c3a2" resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.118.tgz#8014a9b1dee0b72b4d7cd142563f1af21241c3a2"
@ -421,10 +409,6 @@
resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5"
integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU= integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU=
"@types/rimraf@^0.0.28":
version "0.0.28"
resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06"
"@types/selenium-webdriver@^3.0.0": "@types/selenium-webdriver@^3.0.0":
version "3.0.15" version "3.0.15"
resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.15.tgz#024c24051c3798e9a0cf5cceb1c893140df1bc31" resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.15.tgz#024c24051c3798e9a0cf5cceb1c893140df1bc31"
@ -1170,10 +1154,10 @@ aws4@^1.6.0, aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
axe-core@3.1.2: axe-core@3.2.2:
version "3.1.2" version "3.2.2"
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-3.1.2.tgz#ca0aff897ebefca7552f97859dc1217c06c4f9e6" resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-3.2.2.tgz#b06d6e9ae4636d706068843272bfaeed3fe97362"
integrity sha512-e1WVs0SQu3tM29J9a/mISGvlo2kdCStE+yffIAJF6eb42FS+eUFEVz9j4rgDeV2TAfPJmuOZdRetWYycIbK7Vg== integrity sha512-gAy4kMSPpuRJV3mwictJqlg5LhE84Vw2CydKdC4tvrLhR6+G3KW51zbL/vYujcLA2jvWOq3HMHrVeNuw+mrLVA==
axios@^0.18.0: axios@^0.18.0:
version "0.18.0" version "0.18.0"
@ -1957,15 +1941,12 @@ chownr@^1.0.1, chownr@^1.1.1:
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==
chrome-launcher@^0.10.5: chrome-launcher@^0.10.7:
version "0.10.5" version "0.10.7"
resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-0.10.5.tgz#d0aa72c11f1653e6a60dfebea171522447470ef1" resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-0.10.7.tgz#5e2a9e99f212e0501d9c7024802acd01a812f5d5"
integrity sha512-Gbzg8HlWhyuoVqflhiXwfFXhzNfNWvAkSWv2QR1Yl6mwsMo1oCLAVjp2tIySuS4lrZLEjzVx1fOy584yE76P4g== integrity sha512-IoQLp64s2n8OQuvKZwt77CscVj3UlV2Dj7yZtd1EBMld9mSdGcsGy9fN5hd/r4vJuWZR09it78n1+A17gB+AIQ==
dependencies: dependencies:
"@types/core-js" "^0.9.41" "@types/node" "*"
"@types/mkdirp" "^0.3.29"
"@types/node" "^9.3.0"
"@types/rimraf" "^0.0.28"
is-wsl "^1.1.0" is-wsl "^1.1.0"
lighthouse-logger "^1.0.0" lighthouse-logger "^1.0.0"
mkdirp "0.5.1" mkdirp "0.5.1"
@ -2364,6 +2345,16 @@ connect-history-api-fallback@^1.6.0:
resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc"
integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==
connect-injector@^0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/connect-injector/-/connect-injector-0.4.4.tgz#a81959c31ecf5caa0f3dcc325c28ed90b830aa90"
integrity sha1-qBlZwx7PXKoPPcwyXCjtkLgwqpA=
dependencies:
debug "^2.0.0"
q "^1.0.1"
stream-buffers "^0.2.3"
uberproto "^1.1.0"
connect-query@^1.0.0: connect-query@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/connect-query/-/connect-query-1.0.0.tgz#de44f577209da2404d1fc04692d1a4118e582119" resolved "https://registry.yarnpkg.com/connect-query/-/connect-query-1.0.0.tgz#de44f577209da2404d1fc04692d1a4118e582119"
@ -2379,6 +2370,16 @@ connect@^3.6.0, connect@^3.6.2:
parseurl "~1.3.2" parseurl "~1.3.2"
utils-merge "1.0.1" utils-merge "1.0.1"
connect@^3.6.6:
version "3.7.0"
resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8"
integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==
dependencies:
debug "2.6.9"
finalhandler "1.1.2"
parseurl "~1.3.3"
utils-merge "1.0.1"
console-browserify@^1.1.0: console-browserify@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
@ -2501,10 +2502,6 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
corser@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87"
cosmiconfig@^4.0.0: cosmiconfig@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-4.0.0.tgz#760391549580bbd2df1e562bc177b13c290972dc" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-4.0.0.tgz#760391549580bbd2df1e562bc177b13c290972dc"
@ -2741,7 +2738,7 @@ debug@2.3.3:
dependencies: dependencies:
ms "0.7.2" ms "0.7.2"
debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: debug@2.6.9, debug@^2.0.0, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8:
version "2.6.9" version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@ -2934,7 +2931,7 @@ detect-libc@^1.0.2:
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
detect-node@^2.0.4: detect-node@^2.0.3, detect-node@^2.0.4:
version "2.0.4" version "2.0.4"
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
@ -2947,10 +2944,10 @@ dezalgo@^1.0.0:
asap "^2.0.0" asap "^2.0.0"
wrappy "1" wrappy "1"
dgeni-packages@^0.27.1: dgeni-packages@^0.27.5:
version "0.27.2" version "0.27.5"
resolved "https://registry.yarnpkg.com/dgeni-packages/-/dgeni-packages-0.27.2.tgz#ca1b40147a56668db2f4a2f09a374c6355f45cfa" resolved "https://registry.yarnpkg.com/dgeni-packages/-/dgeni-packages-0.27.5.tgz#65b2ed1be6e85937c502d94df0ad16108bcaa801"
integrity sha512-hLZz5FeUTw50+yYE3nVHjpuWSve3YasqcDqq3t6ACxIfy0l/L60jzmBFjTGBbNYvn2qBAVzUEGNOQ2gzbFXBGQ== integrity sha512-GHLRu/CZoqQDfSKAWis5GkZFSAcK1jQos0P/f0mbZTWGCZpqicSRWTfzCjNAOYdk660jp/fab5/EvRX1um1Bdw==
dependencies: dependencies:
canonical-path "^1.0.0" canonical-path "^1.0.0"
catharsis "^0.8.1" catharsis "^0.8.1"
@ -2967,6 +2964,7 @@ dgeni-packages@^0.27.1:
mkdirp-promise "^5.0.0" mkdirp-promise "^5.0.0"
node-html-encoder "0.0.2" node-html-encoder "0.0.2"
nunjucks "^3.1.6" nunjucks "^3.1.6"
rehype "^8.0.0"
semver "^5.2.0" semver "^5.2.0"
shelljs "^0.7.0" shelljs "^0.7.0"
source-map-support "^0.4.15" source-map-support "^0.4.15"
@ -3165,16 +3163,6 @@ ecdsa-sig-formatter@1.0.9:
base64url "^2.0.0" base64url "^2.0.0"
safe-buffer "^5.0.1" safe-buffer "^5.0.1"
ecstatic@^3.0.0:
version "3.3.1"
resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.1.tgz#b15b5b036c2233defc78d7bacbd8765226c95577"
integrity sha512-/rrctvxZ78HMI/tPIsqdvFKHHscxR3IJuKrZI2ZoUgkt2SiufyLFBmcco+aqQBIu6P1qBsUNG3drAAGLx80vTQ==
dependencies:
he "^1.1.1"
mime "^1.6.0"
minimist "^1.1.0"
url-join "^2.0.5"
editions@^1.1.1, editions@^1.1.2, editions@^1.3.1, editions@^1.3.3: editions@^1.1.1, editions@^1.1.2, editions@^1.3.1, editions@^1.3.3:
version "1.3.3" version "1.3.3"
resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b"
@ -3949,7 +3937,7 @@ finalhandler@1.1.1:
statuses "~1.4.0" statuses "~1.4.0"
unpipe "~1.0.0" unpipe "~1.0.0"
finalhandler@~1.1.2: finalhandler@1.1.2, finalhandler@~1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
@ -4239,6 +4227,13 @@ gauge@~2.7.3:
strip-ansi "^3.0.1" strip-ansi "^3.0.1"
wide-align "^1.1.0" wide-align "^1.1.0"
gaze@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a"
integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==
dependencies:
globule "^1.0.0"
gcp-metadata@^0.3.0: gcp-metadata@^0.3.0:
version "0.3.1" version "0.3.1"
resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-0.3.1.tgz#313814456e7c3d0eeb8f8b084b33579e886f829a" resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-0.3.1.tgz#313814456e7c3d0eeb8f8b084b33579e886f829a"
@ -4366,7 +4361,7 @@ glob@7.0.x:
once "^1.3.0" once "^1.3.0"
path-is-absolute "^1.0.0" path-is-absolute "^1.0.0"
glob@7.1.4: glob@7.1.4, glob@~7.1.1:
version "7.1.4" version "7.1.4"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
@ -4433,6 +4428,15 @@ globby@^7.1.1:
pify "^3.0.0" pify "^3.0.0"
slash "^1.0.0" slash "^1.0.0"
globule@^1.0.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d"
integrity sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==
dependencies:
glob "~7.1.1"
lodash "~4.17.10"
minimatch "~3.0.2"
google-auth-library@0.12.0: google-auth-library@0.12.0:
version "0.12.0" version "0.12.0"
resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-0.12.0.tgz#a3fc6c296d00bb54e4d877ef581a05947330d07f" resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-0.12.0.tgz#a3fc6c296d00bb54e4d877ef581a05947330d07f"
@ -4569,6 +4573,11 @@ gtoken@^2.3.0:
mime "^2.2.0" mime "^2.2.0"
pify "^3.0.0" pify "^3.0.0"
handle-thing@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4"
integrity sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=
handle-thing@^2.0.0: handle-thing@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754"
@ -4727,6 +4736,17 @@ hast-util-from-parse5@^4.0.0:
web-namespaces "^1.1.2" web-namespaces "^1.1.2"
xtend "^4.0.1" xtend "^4.0.1"
hast-util-from-parse5@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-5.0.1.tgz#7da8841d707dcf7be73715f7f3b14e021c4e469a"
integrity sha512-UfPzdl6fbxGAxqGYNThRUhRlDYY7sXu6XU9nQeX4fFZtV+IHbyEJtd+DUuwOqNV4z3K05E/1rIkoVr/JHmeWWA==
dependencies:
ccount "^1.0.3"
hastscript "^5.0.0"
property-information "^5.0.0"
web-namespaces "^1.1.2"
xtend "^4.0.1"
hast-util-has-property@^1.0.0: hast-util-has-property@^1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/hast-util-has-property/-/hast-util-has-property-1.0.2.tgz#4c9c3c6122fcc84a5b7c40a573940aaa4b8a8278" resolved "https://registry.yarnpkg.com/hast-util-has-property/-/hast-util-has-property-1.0.2.tgz#4c9c3c6122fcc84a5b7c40a573940aaa4b8a8278"
@ -4762,6 +4782,22 @@ hast-util-to-html@^4.0.0:
unist-util-is "^2.0.0" unist-util-is "^2.0.0"
xtend "^4.0.1" xtend "^4.0.1"
hast-util-to-html@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/hast-util-to-html/-/hast-util-to-html-6.0.1.tgz#46f4f8d4d2e39c0510268c873a82c360766a0366"
integrity sha512-9LjLAsO2gPO9H6N0VxZsK4sqNZY1A0lMNDfdpMseryV18Hri2++guFfPmjY58PzmtBlBvDflqktxjSm2I1o1yg==
dependencies:
ccount "^1.0.0"
comma-separated-tokens "^1.0.1"
hast-util-is-element "^1.0.0"
hast-util-whitespace "^1.0.0"
html-void-elements "^1.0.0"
property-information "^5.0.0"
space-separated-tokens "^1.0.0"
stringify-entities "^2.0.0"
unist-util-is "^3.0.0"
xtend "^4.0.1"
hast-util-to-string@^1.0.0: hast-util-to-string@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/hast-util-to-string/-/hast-util-to-string-1.0.1.tgz#b28055cdca012d3c8fd048757c8483d0de0d002c" resolved "https://registry.yarnpkg.com/hast-util-to-string/-/hast-util-to-string-1.0.1.tgz#b28055cdca012d3c8fd048757c8483d0de0d002c"
@ -4779,6 +4815,16 @@ hastscript@^4.0.0:
property-information "^4.0.0" property-information "^4.0.0"
space-separated-tokens "^1.0.0" space-separated-tokens "^1.0.0"
hastscript@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-5.1.0.tgz#a19b3cca6a26a2bcd0f1b1eac574af9427c1c7df"
integrity sha512-7mOQX5VfVs/gmrOGlN8/EDfp1GqV6P3gTNVt+KnX4gbYhpASTM8bklFdFQCbFRAadURXAmw0R1QQdBdqp7jswQ==
dependencies:
comma-separated-tokens "^1.0.0"
hast-util-parse-selector "^2.2.0"
property-information "^5.0.1"
space-separated-tokens "^1.0.0"
hawk@~6.0.2: hawk@~6.0.2:
version "6.0.2" version "6.0.2"
resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038"
@ -4789,11 +4835,6 @@ hawk@~6.0.2:
hoek "4.x.x" hoek "4.x.x"
sntp "2.x.x" sntp "2.x.x"
he@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
header-case@^1.0.0: header-case@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/header-case/-/header-case-1.0.1.tgz#9535973197c144b09613cd65d317ef19963bd02d" resolved "https://registry.yarnpkg.com/header-case/-/header-case-1.0.1.tgz#9535973197c144b09613cd65d317ef19963bd02d"
@ -4944,7 +4985,7 @@ http-proxy-middleware@^0.19.1:
lodash "^4.17.11" lodash "^4.17.11"
micromatch "^3.1.10" micromatch "^3.1.10"
http-proxy@1.16.2, http-proxy@^1.13.0, http-proxy@^1.8.1: http-proxy@1.16.2, http-proxy@^1.13.0:
version "1.16.2" version "1.16.2"
resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742"
dependencies: dependencies:
@ -4960,20 +5001,6 @@ http-proxy@^1.17.0:
follow-redirects "^1.0.0" follow-redirects "^1.0.0"
requires-port "^1.0.0" requires-port "^1.0.0"
http-server@^0.11.1:
version "0.11.1"
resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.11.1.tgz#2302a56a6ffef7f9abea0147d838a5e9b6b6a79b"
integrity sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==
dependencies:
colors "1.0.3"
corser "~2.0.0"
ecstatic "^3.0.0"
http-proxy "^1.8.1"
opener "~1.4.0"
optimist "0.6.x"
portfinder "^1.0.13"
union "~0.4.3"
http-signature@~1.2.0: http-signature@~1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
@ -5353,6 +5380,11 @@ is-decimal@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.1.tgz#f5fb6a94996ad9e8e3761fbfbd091f1fca8c4e82" resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.1.tgz#f5fb6a94996ad9e8e3761fbfbd091f1fca8c4e82"
is-decimal@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.3.tgz#381068759b9dc807d8c0dc0bfbae2b68e1da48b7"
integrity sha512-bvLSwoDg2q6Gf+E2LEPiklHZxxiSi3XAh4Mav65mKqTfCO1HM3uBs24TjEH8iJX3bbDdLXKJXBTmGzuTUuAEjQ==
is-descriptor@^0.1.0: is-descriptor@^0.1.0:
version "0.1.6" version "0.1.6"
resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
@ -5846,9 +5878,10 @@ jpeg-js@0.1.2, jpeg-js@^0.1.2:
version "0.1.2" version "0.1.2"
resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.1.2.tgz#135b992c0575c985cfa0f494a3227ed238583ece" resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.1.2.tgz#135b992c0575c985cfa0f494a3227ed238583ece"
js-library-detector@^5.1.0: js-library-detector@^5.4.0:
version "5.1.0" version "5.4.0"
resolved "https://registry.yarnpkg.com/js-library-detector/-/js-library-detector-5.1.0.tgz#1e2e88b119bb91e6581b28f4a90018ea1320de73" resolved "https://registry.yarnpkg.com/js-library-detector/-/js-library-detector-5.4.0.tgz#d1b08dfbdc3886258f888bd441801ef9e5b69567"
integrity sha512-lSTEC9Q3L/cXOhYIilW3GH/v4tOnPIN40NTIBHRcn2vxTwGhMyySQTQpJ0W68ISGzOgvwVe7KCfQ9PJi6MsOIw==
"js-tokens@^3.0.0 || ^4.0.0": "js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0" version "4.0.0"
@ -6266,6 +6299,26 @@ lie@~3.3.0:
dependencies: dependencies:
immediate "~3.0.5" immediate "~3.0.5"
light-server@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/light-server/-/light-server-2.6.2.tgz#dcca50484cab293be03679d083301a77a8d4fe0e"
integrity sha512-u0t8YBTAZkBs9td6/UKHe3qP8VwT7LpKVp9kzdisOllhVzaiLukSGh6JlOLVKW62uMu2bZzoogssjTYuc7XNrQ==
dependencies:
commander "^2.19.0"
connect "^3.6.6"
connect-history-api-fallback "^1.6.0"
connect-injector "^0.4.4"
gaze "^1.1.3"
http-proxy "^1.17.0"
morgan "~1.9.1"
opener "^1.5.1"
parseurl "^1.3.2"
serve-index "^1.9.1"
serve-static "~1.13.2"
spdy "^3.4.7"
strip-json-comments "^2.0.1"
ws "^1.0.1"
lighthouse-logger@^1.0.0: lighthouse-logger@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/lighthouse-logger/-/lighthouse-logger-1.0.1.tgz#f073d83f7acbc96729bf100a121c8f006991ae61" resolved "https://registry.yarnpkg.com/lighthouse-logger/-/lighthouse-logger-1.0.1.tgz#f073d83f7acbc96729bf100a121c8f006991ae61"
@ -6280,13 +6333,13 @@ lighthouse-logger@^1.2.0:
debug "^2.6.8" debug "^2.6.8"
marky "^1.2.0" marky "^1.2.0"
lighthouse@^4.3.0: lighthouse@^5.1.0:
version "4.3.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/lighthouse/-/lighthouse-4.3.0.tgz#5b6a89871ece5016103a3fb0c1c33d8976f80f80" resolved "https://registry.yarnpkg.com/lighthouse/-/lighthouse-5.1.0.tgz#f4f9a1f46f653cb3e53b0895a8a92162dd84a4a7"
integrity sha512-gSekIsP+d2kT2Ly6vkjj+hpmeNbR47w+iKwlUUkp7pWA+VfLY4uihmm4scYb4Qw0g4UCoe13f1JrMCw4oXIeIw== integrity sha512-T+6VYefgRgSRHCgWhSQzsS1Jyu6JJ5I3cnrH/Q7BvwoJwnMhHME+JQ4ib5Oek2ZTfOakoarLDqrFPDtYNxk0KA==
dependencies: dependencies:
axe-core "3.1.2" axe-core "3.2.2"
chrome-launcher "^0.10.5" chrome-launcher "^0.10.7"
configstore "^3.1.1" configstore "^3.1.1"
cssstyle "1.2.1" cssstyle "1.2.1"
details-element-polyfill "2.2.0" details-element-polyfill "2.2.0"
@ -6295,7 +6348,7 @@ lighthouse@^4.3.0:
intl-messageformat "^2.2.0" intl-messageformat "^2.2.0"
intl-messageformat-parser "^1.4.0" intl-messageformat-parser "^1.4.0"
jpeg-js "0.1.2" jpeg-js "0.1.2"
js-library-detector "^5.1.0" js-library-detector "^5.4.0"
jsonld "^1.5.0" jsonld "^1.5.0"
jsonlint-mod "^1.7.4" jsonlint-mod "^1.7.4"
lighthouse-logger "^1.2.0" lighthouse-logger "^1.2.0"
@ -6484,7 +6537,7 @@ lodash@^3.10.1, lodash@^3.8.0:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y= integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=
lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5: lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10:
version "4.17.11" version "4.17.11"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
@ -6864,7 +6917,7 @@ mime@1.4.1, mime@^1.3.4:
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
mime@1.6.0, mime@^1.4.1, mime@^1.6.0: mime@1.6.0, mime@^1.4.1:
version "1.6.0" version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
@ -6912,7 +6965,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2:
version "3.0.4" version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@ -7009,6 +7062,17 @@ morgan@^1.8.2:
on-finished "~2.3.0" on-finished "~2.3.0"
on-headers "~1.0.1" on-headers "~1.0.1"
morgan@~1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.1.tgz#0a8d16734a1d9afbc824b99df87e738e58e2da59"
integrity sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==
dependencies:
basic-auth "~2.0.0"
debug "2.6.9"
depd "~1.1.2"
on-finished "~2.3.0"
on-headers "~1.0.1"
move-concurrently@^1.0.1: move-concurrently@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@ -7468,7 +7532,7 @@ objectdiff@^1.1.0:
resolved "https://registry.yarnpkg.com/objectdiff/-/objectdiff-1.1.0.tgz#8d7a15be6cb8670df8a490cc6be12a4f05ea82f4" resolved "https://registry.yarnpkg.com/objectdiff/-/objectdiff-1.1.0.tgz#8d7a15be6cb8670df8a490cc6be12a4f05ea82f4"
integrity sha1-jXoVvmy4Zw34pJDMa+EqTwXqgvQ= integrity sha1-jXoVvmy4Zw34pJDMa+EqTwXqgvQ=
obuf@^1.0.0, obuf@^1.1.2: obuf@^1.0.0, obuf@^1.1.1, obuf@^1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
@ -7512,9 +7576,10 @@ open@6.3.0:
dependencies: dependencies:
is-wsl "^1.1.0" is-wsl "^1.1.0"
opener@~1.4.0: opener@^1.5.1:
version "1.4.3" version "1.5.1"
resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed"
integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==
opn@4.0.2: opn@4.0.2:
version "4.0.2" version "4.0.2"
@ -7536,7 +7601,7 @@ opn@^5.5.0:
dependencies: dependencies:
is-wsl "^1.1.0" is-wsl "^1.1.0"
optimist@0.6.x, optimist@^0.6.1, optimist@~0.6.0, optimist@~0.6.1: optimist@^0.6.1, optimist@~0.6.0, optimist@~0.6.1:
version "0.6.1" version "0.6.1"
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
dependencies: dependencies:
@ -7862,16 +7927,16 @@ parseuri@0.0.5:
dependencies: dependencies:
better-assert "~1.0.0" better-assert "~1.0.0"
parseurl@^1.3.2, parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
parseurl@~1.3.2: parseurl@~1.3.2:
version "1.3.2" version "1.3.2"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=
parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
pascal-case@^2.0.0: pascal-case@^2.0.0:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-2.0.1.tgz#2d578d3455f660da65eca18ef95b4e0de912761e" resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-2.0.1.tgz#2d578d3455f660da65eca18ef95b4e0de912761e"
@ -8187,6 +8252,13 @@ property-information@^4.0.0:
dependencies: dependencies:
xtend "^4.0.1" xtend "^4.0.1"
property-information@^5.0.0, property-information@^5.0.1:
version "5.1.0"
resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.1.0.tgz#e4755eee5319f03f7f6f5a9bc1a6a7fea6609e2c"
integrity sha512-tODH6R3+SwTkAQckSp2S9xyYX8dEKYkeXw+4TmJzTxnNzd6mQPu1OD4f9zPrvw/Rm4wpPgI+Zp63mNSGNzUgHg==
dependencies:
xtend "^4.0.1"
protochain@^1.0.5: protochain@^1.0.5:
version "1.0.5" version "1.0.5"
resolved "https://registry.yarnpkg.com/protochain/-/protochain-1.0.5.tgz#991c407e99de264aadf8f81504b5e7faf7bfa260" resolved "https://registry.yarnpkg.com/protochain/-/protochain-1.0.5.tgz#991c407e99de264aadf8f81504b5e7faf7bfa260"
@ -8305,7 +8377,7 @@ q@1.4.1:
resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e"
integrity sha1-VXBbzZPF82c1MMLCy8DCs63cKG4= integrity sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=
q@^1.4.1, q@^1.5.1: q@^1.0.1, q@^1.4.1, q@^1.5.1:
version "1.5.1" version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
@ -8328,10 +8400,6 @@ qs@6.7.0:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
qs@~2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404"
qs@~6.4.0: qs@~6.4.0:
version "6.4.0" version "6.4.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
@ -8554,7 +8622,7 @@ read@1.0.x:
dependencies: dependencies:
mute-stream "~0.0.4" mute-stream "~0.0.4"
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: "readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
version "2.3.6" version "2.3.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
@ -8715,6 +8783,15 @@ rehype-parse@^5.0.0:
parse5 "^5.0.0" parse5 "^5.0.0"
xtend "^4.0.1" xtend "^4.0.1"
rehype-parse@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/rehype-parse/-/rehype-parse-6.0.1.tgz#a5401d7f4144d5e17cbb69be11f05a2a7ba87e27"
integrity sha512-FrGSbOzcGxIvWty1qHjKTvHT4WBTt7C6JLs65EkvFPa7ZKraSmsoDDj6al1eBxaXS1t/kiGdPYazUe58Mgflgw==
dependencies:
hast-util-from-parse5 "^5.0.0"
parse5 "^5.0.0"
xtend "^4.0.1"
rehype-slug@^2.0.0: rehype-slug@^2.0.0:
version "2.0.2" version "2.0.2"
resolved "https://registry.yarnpkg.com/rehype-slug/-/rehype-slug-2.0.2.tgz#a0d5a4118548ee6165b1f911a213a13e284d91ba" resolved "https://registry.yarnpkg.com/rehype-slug/-/rehype-slug-2.0.2.tgz#a0d5a4118548ee6165b1f911a213a13e284d91ba"
@ -8733,6 +8810,14 @@ rehype-stringify@^4.0.0:
hast-util-to-html "^4.0.0" hast-util-to-html "^4.0.0"
xtend "^4.0.1" xtend "^4.0.1"
rehype-stringify@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/rehype-stringify/-/rehype-stringify-6.0.0.tgz#a8a573b6f9bf98916955978acd746c37cfd88ac0"
integrity sha512-grV/hhA7z9GbUJZk0ILzprSE0YY9lvTmYuvgRjXdFXrrag5gNeqXBQIuG1m4zFW6PFm0YYnJ/qgf5y6yui4VsA==
dependencies:
hast-util-to-html "^6.0.0"
xtend "^4.0.1"
rehype@^6.0.0: rehype@^6.0.0:
version "6.0.0" version "6.0.0"
resolved "https://registry.yarnpkg.com/rehype/-/rehype-6.0.0.tgz#873d4686c52d694560cf5d3f9e4440115840491d" resolved "https://registry.yarnpkg.com/rehype/-/rehype-6.0.0.tgz#873d4686c52d694560cf5d3f9e4440115840491d"
@ -8741,6 +8826,15 @@ rehype@^6.0.0:
rehype-stringify "^4.0.0" rehype-stringify "^4.0.0"
unified "^7.0.0" unified "^7.0.0"
rehype@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/rehype/-/rehype-8.0.0.tgz#d0776cfcc353dd15c4c03b2de76d78a6c302e69c"
integrity sha512-fqcYo/q4Xka0ZvS6abiHtZsN7/TauTzTZQfXqtWACo9Qz76Vv/8uzhOizAfDBjVPhbnDl3xPIMRArUdcV/xFaA==
dependencies:
rehype-parse "^6.0.0"
rehype-stringify "^6.0.0"
unified "^7.0.0"
remark-html@^8.0.0: remark-html@^8.0.0:
version "8.0.0" version "8.0.0"
resolved "https://registry.yarnpkg.com/remark-html/-/remark-html-8.0.0.tgz#9fcb859a6f3cb40f3ef15402950f1a62ec301b3a" resolved "https://registry.yarnpkg.com/remark-html/-/remark-html-8.0.0.tgz#9fcb859a6f3cb40f3ef15402950f1a62ec301b3a"
@ -9334,7 +9428,7 @@ serve-index@^1.9.1:
mime-types "~2.1.17" mime-types "~2.1.17"
parseurl "~1.3.2" parseurl "~1.3.2"
serve-static@1.13.2: serve-static@1.13.2, serve-static@~1.13.2:
version "1.13.2" version "1.13.2"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1"
integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==
@ -9754,6 +9848,19 @@ spdx-license-list@^2.1.0:
resolved "https://registry.yarnpkg.com/spdx-license-list/-/spdx-license-list-2.1.0.tgz#3788ffb5c80b24afbe8283934e9e6684ea6a218d" resolved "https://registry.yarnpkg.com/spdx-license-list/-/spdx-license-list-2.1.0.tgz#3788ffb5c80b24afbe8283934e9e6684ea6a218d"
integrity sha1-N4j/tcgLJK++goOTTp5mhOpqIY0= integrity sha1-N4j/tcgLJK++goOTTp5mhOpqIY0=
spdy-transport@^2.0.18:
version "2.1.1"
resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.1.1.tgz#c54815d73858aadd06ce63001e7d25fa6441623b"
integrity sha512-q7D8c148escoB3Z7ySCASadkegMmUZW8Wb/Q1u0/XBgDKMO880rLQDj8Twiew/tYi7ghemKUi/whSYOwE17f5Q==
dependencies:
debug "^2.6.8"
detect-node "^2.0.3"
hpack.js "^2.1.6"
obuf "^1.1.1"
readable-stream "^2.2.9"
safe-buffer "^5.0.1"
wbuf "^1.7.2"
spdy-transport@^3.0.0: spdy-transport@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31"
@ -9766,6 +9873,18 @@ spdy-transport@^3.0.0:
readable-stream "^3.0.6" readable-stream "^3.0.6"
wbuf "^1.7.3" wbuf "^1.7.3"
spdy@^3.4.7:
version "3.4.7"
resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.7.tgz#42ff41ece5cc0f99a3a6c28aabb73f5c3b03acbc"
integrity sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=
dependencies:
debug "^2.6.8"
handle-thing "^1.2.5"
http-deceiver "^1.2.7"
safe-buffer "^5.0.1"
select-hose "^2.0.0"
spdy-transport "^2.0.18"
spdy@^4.0.0: spdy@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.0.tgz#81f222b5a743a329aa12cea6a390e60e9b613c52" resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.0.tgz#81f222b5a743a329aa12cea6a390e60e9b613c52"
@ -9875,6 +9994,11 @@ stream-browserify@^2.0.1:
inherits "~2.0.1" inherits "~2.0.1"
readable-stream "^2.0.2" readable-stream "^2.0.2"
stream-buffers@^0.2.3:
version "0.2.6"
resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-0.2.6.tgz#181c08d5bb3690045f69401b9ae6a7a0cf3313fc"
integrity sha1-GBwI1bs2kARfaUAbmuanoM8zE/w=
stream-each@^1.1.0: stream-each@^1.1.0:
version "1.2.3" version "1.2.3"
resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae"
@ -9997,6 +10121,17 @@ stringify-entities@^1.0.1:
is-alphanumerical "^1.0.0" is-alphanumerical "^1.0.0"
is-hexadecimal "^1.0.0" is-hexadecimal "^1.0.0"
stringify-entities@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-2.0.0.tgz#fa7ca6614b355fb6c28448140a20c4ede7462827"
integrity sha512-fqqhZzXyAM6pGD9lky/GOPq6V4X0SeTAFBl0iXb/BzOegl40gpf/bV3QQP7zULNYvjr6+Dx8SCaDULjVoOru0A==
dependencies:
character-entities-html4 "^1.0.0"
character-entities-legacy "^1.0.0"
is-alphanumerical "^1.0.0"
is-decimal "^1.0.2"
is-hexadecimal "^1.0.0"
stringmap@^0.2.2: stringmap@^0.2.2:
version "0.2.2" version "0.2.2"
resolved "https://registry.yarnpkg.com/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" resolved "https://registry.yarnpkg.com/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1"
@ -10050,7 +10185,7 @@ strip-eof@^1.0.0:
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
strip-json-comments@^2.0.0, strip-json-comments@~2.0.1: strip-json-comments@^2.0.0, strip-json-comments@^2.0.1, strip-json-comments@~2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
@ -10603,6 +10738,11 @@ typescript@^3.2.2:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.2.tgz#9ed4e6475d906f589200193be056f5913caed481" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.2.tgz#9ed4e6475d906f589200193be056f5913caed481"
integrity sha512-Og2Vn6Mk7JAuWA1hQdDQN/Ekm/SchX80VzLhjKN9ETYrIepBFAd8PkOdOTK2nKt0FCkmMZKBJvQ1dV1gIxPu/A== integrity sha512-Og2Vn6Mk7JAuWA1hQdDQN/Ekm/SchX80VzLhjKN9ETYrIepBFAd8PkOdOTK2nKt0FCkmMZKBJvQ1dV1gIxPu/A==
uberproto@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/uberproto/-/uberproto-1.2.0.tgz#61d4eab024f909c4e6ea52be867c4894a4beeb76"
integrity sha1-YdTqsCT5CcTm6lK+hnxIlKS+63Y=
uglify-js@^3.0.15, uglify-js@^3.1.4: uglify-js@^3.0.15, uglify-js@^3.1.4:
version "3.4.9" version "3.4.9"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
@ -10672,12 +10812,6 @@ union-value@^1.0.0:
is-extendable "^0.1.1" is-extendable "^0.1.1"
set-value "^0.4.3" set-value "^0.4.3"
union@~0.4.3:
version "0.4.6"
resolved "https://registry.yarnpkg.com/union/-/union-0.4.6.tgz#198fbdaeba254e788b0efcb630bc11f24a2959e0"
dependencies:
qs "~2.3.3"
unique-filename@^1.1.0, unique-filename@^1.1.1: unique-filename@^1.1.0, unique-filename@^1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230"
@ -10728,6 +10862,11 @@ unist-util-is@^2.1.2:
resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-2.1.2.tgz#1193fa8f2bfbbb82150633f3a8d2eb9a1c1d55db" resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-2.1.2.tgz#1193fa8f2bfbbb82150633f3a8d2eb9a1c1d55db"
integrity sha512-YkXBK/H9raAmG7KXck+UUpnKiNmUdB+aBGrknfQ4EreE1banuzrKABx3jP6Z5Z3fMSPMQQmeXBlKpCbMwBkxVw== integrity sha512-YkXBK/H9raAmG7KXck+UUpnKiNmUdB+aBGrknfQ4EreE1banuzrKABx3jP6Z5Z3fMSPMQQmeXBlKpCbMwBkxVw==
unist-util-is@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-3.0.0.tgz#d9e84381c2468e82629e4a5be9d7d05a2dd324cd"
integrity sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==
unist-util-modify-children@^1.0.0: unist-util-modify-children@^1.0.0:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/unist-util-modify-children/-/unist-util-modify-children-1.1.1.tgz#66d7e6a449e6f67220b976ab3cb8b5ebac39e51d" resolved "https://registry.yarnpkg.com/unist-util-modify-children/-/unist-util-modify-children-1.1.1.tgz#66d7e6a449e6f67220b976ab3cb8b5ebac39e51d"
@ -10864,11 +11003,6 @@ url-join@0.0.1:
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/url-join/-/url-join-0.0.1.tgz#1db48ad422d3402469a87f7d97bdebfe4fb1e3c8" resolved "https://registry.yarnpkg.com/url-join/-/url-join-0.0.1.tgz#1db48ad422d3402469a87f7d97bdebfe4fb1e3c8"
url-join@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728"
integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=
url-parse-lax@^1.0.0: url-parse-lax@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
@ -11085,7 +11219,7 @@ watchr@^3.0.1:
scandirectory "^2.5.0" scandirectory "^2.5.0"
taskgroup "^5.0.1" taskgroup "^5.0.1"
wbuf@^1.1.0, wbuf@^1.7.3: wbuf@^1.1.0, wbuf@^1.7.2, wbuf@^1.7.3:
version "1.7.3" version "1.7.3"
resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df"
integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==
@ -11443,6 +11577,14 @@ ws@3.3.2:
safe-buffer "~5.1.0" safe-buffer "~5.1.0"
ultron "~1.1.0" ultron "~1.1.0"
ws@^1.0.1:
version "1.1.5"
resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51"
integrity sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==
dependencies:
options ">=0.0.5"
ultron "1.0.x"
wtf-8@1.0.0: wtf-8@1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a"

View File

@ -20,3 +20,12 @@ build --symlink_prefix=/
# Turn on managed directories feature in Bazel # Turn on managed directories feature in Bazel
# This allows us to avoid installing a second copy of node_modules # This allows us to avoid installing a second copy of node_modules
common --experimental_allow_incremental_repository_updates common --experimental_allow_incremental_repository_updates
# This option is changed to true in Bazel 0.27 and exposes a possible
# regression in Bazel 0.27.0.
# See root /.bazelrc for more info. integration/bazel uses
# ng_package which depends on npm_package so this flag needs to be set
# her as well.
build --incompatible_list_based_execution_strategy_selection=false
test --incompatible_list_based_execution_strategy_selection=false
run --incompatible_list_based_execution_strategy_selection=false

View File

@ -8,16 +8,16 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# Fetch rules_nodejs so we can install our npm dependencies # Fetch rules_nodejs so we can install our npm dependencies
http_archive( http_archive(
name = "build_bazel_rules_nodejs", name = "build_bazel_rules_nodejs",
sha256 = "e04a82a72146bfbca2d0575947daa60fda1878c8d3a3afe868a8ec39a6b968bb", sha256 = "6d4edbf28ff6720aedf5f97f9b9a7679401bf7fca9d14a0fff80f644a99992b4",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.31.1/rules_nodejs-0.31.1.tar.gz"], urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.32.2/rules_nodejs-0.32.2.tar.gz"],
) )
# Fetch sass rules for compiling sass files # Fetch sass rules for compiling sass files
# TODO: change back to upstream release after https://github.com/bazelbuild/rules_sass/pull/87 merged and released
http_archive( http_archive(
name = "io_bazel_rules_sass", name = "io_bazel_rules_sass",
strip_prefix = "rules_sass-9862dfc96a4a1f66fe171ef5e043b29853e8445b", sha256 = "4f05239080175a3f4efa8982d2b7775892d656bb47e8cf56914d5f9441fb5ea6",
url = "https://github.com/manekinekko/rules_sass/archive/9862dfc96a4a1f66fe171ef5e043b29853e8445b.zip", strip_prefix = "rules_sass-86ca977cf2a8ed481859f83a286e164d07335116",
url = "https://github.com/bazelbuild/rules_sass/archive/86ca977cf2a8ed481859f83a286e164d07335116.zip",
) )
# Check the bazel version and download npm dependencies # Check the bazel version and download npm dependencies
@ -25,6 +25,7 @@ load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_reposi
# Bazel version must be at least the following version because: # Bazel version must be at least the following version because:
# - 0.26.0 managed_directories feature added which is required for nodejs rules 0.30.0 # - 0.26.0 managed_directories feature added which is required for nodejs rules 0.30.0
# - 0.27.0 has a fix for managed_directories after `rm -rf node_modules`
check_bazel_version( check_bazel_version(
message = """ message = """
You no longer need to install Bazel on your machine. You no longer need to install Bazel on your machine.
@ -33,12 +34,19 @@ Try running `yarn bazel` instead.
(If you did run that, check that you've got a fresh `yarn install`) (If you did run that, check that you've got a fresh `yarn install`)
""", """,
minimum_bazel_version = "0.26.0", minimum_bazel_version = "0.27.0",
) )
# Setup the Node.js toolchain # Setup the Node.js toolchain
node_repositories( node_repositories(
node_version = "10.9.0", # Use same node version as root angular WORKSPACE since
# we share node_module packages and some require node >= 10.15.0
node_repositories = {
"10.16.0-darwin_amd64": ("node-v10.16.0-darwin-x64.tar.gz", "node-v10.16.0-darwin-x64", "6c009df1b724026d84ae9a838c5b382662e30f6c5563a0995532f2bece39fa9c"),
"10.16.0-linux_amd64": ("node-v10.16.0-linux-x64.tar.xz", "node-v10.16.0-linux-x64", "1827f5b99084740234de0c506f4dd2202a696ed60f76059696747c34339b9d48"),
"10.16.0-windows_amd64": ("node-v10.16.0-win-x64.zip", "node-v10.16.0-win-x64", "aa22cb357f0fb54ccbc06b19b60e37eefea5d7dd9940912675d3ed988bf9a059"),
},
node_version = "10.16.0",
yarn_version = "1.12.1", yarn_version = "1.12.1",
) )

View File

@ -23,16 +23,15 @@
"@angular/compiler": "file:../../dist/packages-dist/compiler", "@angular/compiler": "file:../../dist/packages-dist/compiler",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli", "@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
"@bazel/bazel": "file:../../node_modules/@bazel/bazel", "@bazel/bazel": "file:../../node_modules/@bazel/bazel",
"@bazel/karma": "0.30.1", "@bazel/hide-bazel-files": "0.32.2",
"@bazel/typescript": "0.30.1", "@bazel/karma": "0.32.2",
"@bazel/typescript": "0.32.2",
"@types/jasmine": "2.8.8", "@types/jasmine": "2.8.8",
"@types/source-map": "0.5.1",
"protractor": "5.1.2", "protractor": "5.1.2",
"typescript": "3.4.2" "typescript": "3.4.2"
}, },
"scripts": { "scripts": {
"test": "bazel build ... --noshow_progress && bazel test ...", "test": "bazel build ... --noshow_progress && bazel test ...",
"postinstall": "ngc -p ./angular-metadata.tsconfig.json", "postinstall": "ngc -p ./angular-metadata.tsconfig.json"
"//": "TODO(gregmagolan): figure out how to keep dependencies here up to date with the root package.json"
} }
} }

View File

@ -26,7 +26,7 @@ filegroup(
name = "rxjs_umd_modules", name = "rxjs_umd_modules",
srcs = [ srcs = [
# do not sort # do not sort
"@npm//node_modules/rxjs:bundles/rxjs.umd.js", "@npm//:node_modules/rxjs/bundles/rxjs.umd.js",
":rxjs_shims.js", ":rxjs_shims.js",
], ],
) )
@ -40,7 +40,7 @@ ts_devserver(
], ],
serving_path = "/bundle.min.js", serving_path = "/bundle.min.js",
static_files = [ static_files = [
"@npm//node_modules/zone.js:dist/zone.min.js", "@npm//:node_modules/zone.js/dist/zone.min.js",
], ],
deps = ["//src"], deps = ["//src"],
) )
@ -64,7 +64,7 @@ web_package(
name = "prodapp", name = "prodapp",
assets = [ assets = [
# do not sort # do not sort
"@npm//node_modules/zone.js:dist/zone.min.js", "@npm//:node_modules/zone.js/dist/zone.min.js",
":bundle.min.js", ":bundle.min.js",
], ],
data = [ data = [

View File

@ -46,8 +46,8 @@ ts_library(
ts_web_test_suite( ts_web_test_suite(
name = "test", name = "test",
bootstrap = [ bootstrap = [
"@npm//node_modules/zone.js:dist/zone-testing-bundle.js", "@npm//:node_modules/zone.js/dist/zone-testing-bundle.js",
"@npm//node_modules/reflect-metadata:Reflect.js", "@npm//:node_modules/reflect-metadata/Reflect.js",
], ],
browsers = [ browsers = [
"@io_bazel_rules_webtesting//browsers:chromium-local", "@io_bazel_rules_webtesting//browsers:chromium-local",

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