Compare commits

...

34 Commits

Author SHA1 Message Date
76503e65c8 release: cut the v9.0.0-next.0 release 2019-07-31 11:04:40 -07:00
eac993dfce docs: release notes for the v8.2.0 release 2019-07-31 10:46:14 -07:00
975917bafd Revert "fix(zone.js): don't wrap uncaught promise error. (#31443)" (#31918)
This reverts commit 2bb9a65351.

It breaks tests in google3 which rely on the error handling behavior.

PR Close #31918
2019-07-30 15:03:49 -07:00
185b3dd08e build(docs-infra): update main bundle size (#31839)
PR #31839 contains perf and code cleanup changes that add 48 bytes to the
main bundle size. Perf gains and code clarity justify this increase.

Unfortunately the size verification job is rejecting this PR as it reports
size gains from a fixed size and not relative increase of size from a particular PR.

It was decided during the internal team discussion to bump up size limits to
correctly reflect current state of the master and increase from this PR.

PR Close #31839
2019-07-30 13:01:33 -07:00
78659ec0b0 perf(ivy): avoid creating holey LView Arrays (#31839)
PR Close #31839
2019-07-30 13:01:33 -07:00
a9ec3db91a perf(ivy): limit creationMode checks (#31839)
PR Close #31839
2019-07-30 13:01:33 -07:00
561ec6a5be perf(ivy): stricter null checks (#31839)
PR Close #31839
2019-07-30 13:01:33 -07:00
c0317d40c9 perf(ivy): call refreshContentQueries only when there are content queries defined (#31839)
PR Close #31839
2019-07-30 13:01:32 -07:00
a4bc0db474 refactor(ivy): remove unnecessary call to setPreviousOrParentTNode (#31839)
setPreviousOrParentTNode is set in enterView so no need to reset it
just before entering a view.

PR Close #31839
2019-07-30 13:01:32 -07:00
430124a051 perf(ivy): only refresh child components if those are defined in a given view (#31839)
PR Close #31839
2019-07-30 13:01:32 -07:00
e08391b333 refactor(ivy): rewrite refreshDynamicEmbeddedViews for clarity (#31839)
PR Close #31839
2019-07-30 13:01:32 -07:00
a77d0e22bf perf(ivy): avoid repeated tView.firstTemplatePass writes (#31839)
PR Close #31839
2019-07-30 13:01:32 -07:00
4f42eb4e77 test(zone.js): add test codes to ensure not include sourcemap (#31892)
PR Close #31892
2019-07-30 13:00:26 -07:00
f216724c2c build(zone.js): remove sourceMappingUrl from bundle (#31892)
Close #31883

PR Close #31892
2019-07-30 13:00:26 -07:00
5c9a8961da fix(zone.js): don't rely on global node typings outside of node/ directory (#31783)
PR Close #31783
2019-07-30 12:59:40 -07:00
3479fddf68 docs: fix typo in Animation guide (#31888)
PR Close #31888
2019-07-30 12:58:52 -07:00
5bebac42f9 docs: change Angular Material Design to Material Design in animations guide (#31889)
PR Close #31889
2019-07-30 12:56:22 -07:00
cbcbe23fd1 build(docs-infra): upgrade cli command docs sources to 1e83a8ecb (#31906)
Updating [angular#master](https://github.com/angular/angular/tree/master) from [cli-builds#master](https://github.com/angular/cli-builds/tree/master).

##
Relevant changes in [commit range](a8fe15cb6...1e83a8ecb):

**Modified**
- help/generate.json

##

PR Close #31906
2019-07-30 12:55:44 -07:00
fc6f48185c fix(ivy): ngcc - render decorators in UMD and CommonJS bundles correctly (#31614)
In #31426 a fix was implemented to render namespaced decorator imports
correctly, however it turns out that the fix only worked when decorator
information was extracted from static properties, not when using
`__decorate` calls.

This commit fixes the issue by creating the decorator metadata with the
full decorator expression, instead of only its name.

Closes #31394

PR Close #31614
2019-07-29 16:10:58 -07:00
80f290e301 fix(ivy): ngcc - recognize suffixed tslib helpers (#31614)
An identifier may become repeated when bundling multiple source files
into a single bundle, so bundlers have a strategy of suffixing non-unique
identifiers with a suffix like $2. Since ngcc operates on such bundles,
it needs to process potentially suffixed identifiers in their canonical
form without the suffix. The "ngx-pagination" package was previously not
compiled fully, as most decorators were not recognized.

This commit ensures that identifiers are first canonicalized by removing
the suffix, such that they are properly recognized and processed by ngcc.

Fixes #31540

PR Close #31614
2019-07-29 16:10:58 -07:00
5e5be43acd refactor(ivy): ngcc - categorize the various decorate calls upfront (#31614)
Any decorator information present in TypeScript is emitted into the
generated JavaScript sources by means of `__decorate` call. This call
contains both the decorators as they existed in the original source
code, together with calls to `tslib` helpers that convey additional
information on e.g. type information and parameter decorators. These
different kinds of decorator calls were not previously distinguished on
their own, but instead all treated as `Decorator` by themselves. The
"decorators" that were actually `tslib` helper calls were conveniently
filtered out because they were not imported from `@angular/core`, a
characteristic that ngcc uses to drop certain decorators.

Note that this posed an inconsistency in ngcc when it processes
`@angular/core`'s UMD bundle, as the `tslib` helper functions have been
inlined in said bundle. Because of the inlining, the `tslib` helpers
appear to be from `@angular/core`, so ngcc would fail to drop those
apparent "decorators". This inconsistency does not currently cause any
issues, as ngtsc is specifically looking for decorators based on  their
name and any remaining decorators are simply ignored.

This commit rewrites the decorator analysis of a class to occur all in a
single phase, instead of all throughout the `ReflectionHost`. This
allows to categorize the various decorate calls in a single sweep,
instead of constantly needing to filter out undesired decorate calls on
the go. As an added benefit, the computed decorator information is now
cached per class, such that subsequent reflection queries that need
decorator information can reuse the cached info.

PR Close #31614
2019-07-29 16:10:57 -07:00
0386c964b5 build: secure yarn lock files (#31640)
See https://yarnpkg.com/blog/2019/07/12/recommended-security-update/

PR Close #31640
2019-07-29 16:10:23 -07:00
f5c605b608 fix(zone.js): should expose some other internal intefaces (#31866)
PR Close #31866
2019-07-29 16:08:55 -07:00
14dba72aee fix(core): DebugElement.listeners not cleared on destroy (#31820)
Currently the `DebugElement.listeners` array are retained after the node is destroyed. This means that they'll continue to fire through `triggerEventHandler` and can cause memory leaks. This has already been fixed in Ivy, but these changes fix it in ViewEngine for consistency.

PR Close #31820
2019-07-29 10:05:19 -07:00
5f0d5e9ccf build: update to nodejs rules 0.34.0 and bazel 0.28.1 (#31824)
nodejs rules 0.34.0 now includes protractor_web_test_suite rule (via new @bazel/protractor rule) so we switch to that location for that rule in this PR so that /packages/bazel/src/protractor can be removed in a future PR

this PR also brings in node toolchain support which was released in nodejs rules 0.33.0. this is a prerequisite for RBE for mac & windows users

bazel schematics also updated with the same. @bazel/bazel 0.28.1 npm package includes transitive dep on hide-bazel-files so we're able to remove an explicit dep on that as well.

PR Close #31824
2019-07-26 15:01:25 -07:00
5296c04f61 fix(ivy): set LOCALE_ID when using the injector (#31566)
In `BrowserModule` the value of `LOCALE_ID` is defined in the `APPLICATION_MODULE_PROVIDERS` after `APP_INITIALIZER` has run.
This PR ensures that `LOCALE_ID` is also set for ivy at the same moment which allows the application to fetch the locale from a backend (for example).

Fixes #31465

FW-1436 #resolve

PR Close #31566
2019-07-26 14:04:47 -07:00
40a0666651 fix(ivy): error when using forwardRef in Injectable's useClass (#30532)
Fixes Ivy throwing an error when something is passed in as a `forwardRef` into `@Injectable`'s `useClass` option. The error was being thrown, because we were trying to get the provider factory off of the wrapper function, rather than the value itself.

This PR resolves FW-1335.

PR Close #30532
2019-07-26 14:02:49 -07:00
4da805243a docs(core): clarify @ContentChild(ren) behavior (#31846)
Describe that @ContentChild(ren) doesn't search within other component templates (doesn't go across "component boundaries").
PR Close #31846
2019-07-26 14:02:10 -07:00
14ae50b4c3 docs: fix header mistake (#31811)
The code example refers to `src/app/heroes/heroes.component.html` but its header was `src/app/hero.service.ts` which was obviously a mistake.
PR Close #31811
2019-07-26 14:01:28 -07:00
397d0ba9a3 test(ivy): fix broken testcase in Windows (#31860)
In #30181, several testcases were added that were failing in Windows.
The reason was that a recent rebase missed a required change to interact
with the compiler's virtualized filesystems. This commit introduces the
required usage of the VFS layer to fix the testcase.

PR Close #31860
2019-07-26 12:22:12 -07:00
859ebdd836 fix(ivy): correctly bind targetToIdentifier to the TemplateVisitor (#31861)
`TemplateVisitor#visitBoundAttribute` currently has to invoke visiting
expressions manually (this is fixed in #31813). Previously, it did not
bind `targetToIdentifier` to the visitor before deferring to the
expression visitor, which breaks the `targetToIdentifier` code. This
fixes that and adds a test to ensure the closure processed correctly.

This change is urgent; without it, many indexing targets in g3 are
broken.

PR Close #31861
2019-07-26 12:03:16 -07:00
30673090ec build(zone.js): add changelog gulptask for zone.js (#31852)
PR Close #31852
2019-07-26 11:30:08 -07:00
6033446d2d docs: release notes for the v8.2.0-rc.0 release 2019-07-26 10:25:18 -07:00
174770e6f3 docs: release notes for the v release 2019-07-25 20:32:22 -07:00
92 changed files with 1400 additions and 990 deletions

View File

@ -1,13 +1,59 @@
<a name="8.2.0-next.2"></a>
# [8.2.0-next.2](https://github.com/angular/angular/compare/8.2.0-next.1...8.2.0-next.2) (2019-07-17)
<a name="9.0.0-next.0"></a>
# [9.0.0-next.0](https://github.com/angular/angular/compare/8.2.0-next.2...9.0.0-next.0) (2019-07-31)
* Ivy related improvements and fixes
<a name="8.2.0"></a>
# [8.2.0](https://github.com/angular/angular/compare/8.2.0-rc.0...8.2.0) (2019-07-31)
### Features
* **core:** TypeScript 3.5 support ([#31615](https://github.com/angular/angular/issues/31615)) ([6ece7db]
* **core:** add automatic migration from Renderer to Renderer2 ([#30936](https://github.com/angular/angular/issues/30936)) ([c095597](https://github.com/angular/angular/commit/c095597))
* **bazel:** compile targets used for indexing by Kythe with Ivy ([#31786](https://github.com/angular/angular/issues/31786)) ([82055b2](https://github.com/angular/angular/commit/82055b2))
* **upgrade:** support $element in upgraded component template/templateUrl functions ([#31637](https://github.com/angular/angular/issues/31637)) ([29e1c53](https://github.com/angular/angular/commit/29e1c53))
* **bazel:** allow passing a custom bazel compiler host to ngc compile ([#31341](https://github.com/angular/angular/issues/31341)) ([a29dc96](https://github.com/angular/angular/commit/a29dc96))
* **bazel:** allow passing and rewriting an old bazel host ([#31381](https://github.com/angular/angular/issues/31381)) ([11a208f](https://github.com/angular/angular/commit/11a208f)), closes [#31341](https://github.com/angular/angular/issues/31341)
### Performance Improvements
* **compiler:** avoid copying from prototype while cloning an object ([#31638](https://github.com/angular/angular/issues/31638)) ([24ca582](https://github.com/angular/angular/commit/24ca582)), closes [#31627](https://github.com/angular/angular/issues/31627)
### Bug Fixes
* **core:** DebugElement.listeners not cleared on destroy ([#31820](https://github.com/angular/angular/issues/31820)) ([46b160e](https://github.com/angular/angular/commit/46b160e))
* **bazel:** increase memory limit of ngc under bazel from 2 to 4 GB ([#31784](https://github.com/angular/angular/issues/31784)) ([5a8eb92](https://github.com/angular/angular/commit/5a8eb92))
* **core:** allow Z variations of CSS transforms in sanitizer ([#29264](https://github.com/angular/angular/issues/29264)) ([78e7fdd](https://github.com/angular/angular/commit/78e7fdd))
* **elements:** handle falsy initial value ([#31604](https://github.com/angular/angular/issues/31604)) ([7151eae](https://github.com/angular/angular/commit/7151eae)), closes [angular/angular#30834](https://github.com/angular/angular/issues/30834)
* **platform-browser:** debug element query predicates not compatible with strictFunctionTypes ([#30993](https://github.com/angular/angular/issues/30993)) ([10a1e19](https://github.com/angular/angular/commit/10a1e19))
* use the correct WTF array to iterate over ([#31208](https://github.com/angular/angular/issues/31208)) ([9204de9](https://github.com/angular/angular/commit/9204de9))
* **bazel:** pass custom bazel compiler host rather than rewriting one ([#31496](https://github.com/angular/angular/issues/31496)) ([0c61a35](https://github.com/angular/angular/commit/0c61a35))
* **compiler-cli:** Return original sourceFile instead of redirected sourceFile from getSourceFile ([#26036](https://github.com/angular/angular/issues/26036)) ([3166cff](https://github.com/angular/angular/commit/3166cff)), closes [#22524](https://github.com/angular/angular/issues/22524)
* **language-service:** Eagarly initialize data members ([#31577](https://github.com/angular/angular/issues/31577)) ([0110de2](https://github.com/angular/angular/commit/0110de2))
* **bazel:** revert location of xi18n outputs to bazel-genfiles ([#31410](https://github.com/angular/angular/issues/31410)) ([1d3e227](https://github.com/angular/angular/commit/1d3e227))
* **compiler:** give ASTWithSource its own visit method ([#31347](https://github.com/angular/angular/issues/31347)) ([6aaca21](https://github.com/angular/angular/commit/6aaca21))
* **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)) ([d7be38f](https://github.com/angular/angular/commit/d7be38f)), 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)) ([93abc35](https://github.com/angular/angular/commit/93abc35))
<a name="8.1.3"></a>
## [8.1.3](https://github.com/angular/angular/compare/8.1.2...8.1.3) (2019-07-26)
### Bug Fixes
* **elements:** handle falsy initial value ([#31604](https://github.com/angular/angular/issues/31604)) ([434b796](https://github.com/angular/angular/commit/434b796)), closes [angular/angular#30834](https://github.com/angular/angular/issues/30834)
### Performance Improvements
* **compiler:** avoid copying from prototype while cloning an object ([#31638](https://github.com/angular/angular/issues/31638)) ([1f3daa0](https://github.com/angular/angular/commit/1f3daa0)), closes [#31627](https://github.com/angular/angular/issues/31627)
@ -22,23 +68,6 @@
* **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.2.0-next.1"></a>
# [8.2.0-next.1](https://github.com/angular/angular/compare/8.2.0-next.0...8.2.0-next.1) (2019-07-10)
### Bug Fixes
* **bazel:** revert location of xi18n outputs to bazel-genfiles ([#31410](https://github.com/angular/angular/issues/31410)) ([1d3e227](https://github.com/angular/angular/commit/1d3e227))
* **compiler:** give ASTWithSource its own visit method ([#31347](https://github.com/angular/angular/issues/31347)) ([6aaca21](https://github.com/angular/angular/commit/6aaca21))
### Features
* **core:** add automatic migration from Renderer to Renderer2 ([#30936](https://github.com/angular/angular/issues/30936)) ([c095597](https://github.com/angular/angular/commit/c095597))
<a name="8.1.1"></a>
## [8.1.1](https://github.com/angular/angular/compare/8.1.0...8.1.1) (2019-07-10)
@ -48,23 +77,6 @@
* **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.2.0-next.0"></a>
# [8.2.0-next.0](https://github.com/angular/angular/compare/8.1.0-rc.0...8.2.0-next.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)) ([d7be38f](https://github.com/angular/angular/commit/d7be38f)), 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)) ([93abc35](https://github.com/angular/angular/commit/93abc35))
### Features
* **bazel:** allow passing a custom bazel compiler host to ngc compile ([#31341](https://github.com/angular/angular/issues/31341)) ([a29dc96](https://github.com/angular/angular/commit/a29dc96))
* **bazel:** allow passing and rewriting an old bazel host ([#31381](https://github.com/angular/angular/issues/31381)) ([11a208f](https://github.com/angular/angular/commit/11a208f)), closes [#31341](https://github.com/angular/angular/issues/31341)
<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)

View File

@ -21,8 +21,8 @@ http_archive(
patch_args = ["-p1"],
# 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"],
sha256 = "7c4a690268be97c96f04d505224ec4cb1ae53c2c2b68be495c9bd2634296a5cd",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.34.0/rules_nodejs-0.34.0.tar.gz"],
)
# Check the bazel version and download npm dependencies
@ -53,7 +53,8 @@ Try running `yarn bazel` instead.
# - 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")
# - 0.34.0 introduces protractor rule
check_rules_nodejs_version(minimum_version_string = "0.34.0")
# Setup the Node.js toolchain
node_repositories(
@ -91,6 +92,11 @@ load("//packages/bazel:package.bzl", "rules_angular_dev_dependencies")
rules_angular_dev_dependencies()
# Load protractor dependencies
load("@npm_bazel_protractor//:package.bzl", "npm_bazel_protractor_dependencies")
npm_bazel_protractor_dependencies()
# Load karma dependencies
load("@npm_bazel_karma//:package.bzl", "rules_karma_dependencies")

View File

@ -128,7 +128,7 @@ The third argument, `easing`, controls how the animation [accelerates and decele
<div class="alert is-helpful">
**Note:** See the Angular Material Design website's topic on [Natural easing curves](https://material.io/design/motion/speed.html#easing) for general information on easing curves.
**Note:** See the Material Design website's topic on [Natural easing curves](https://material.io/design/motion/speed.html#easing) for general information on easing curves.
</div>
This example provides a state transition from `open` to `closed` with a one second transition between states.

View File

@ -2,7 +2,7 @@
You learned the basics of Angular animations in the [introduction](guide/animations) page.
In this guide, we go into greater depth on special transition states such as `*` (wildcard) and `void`, and show how these special states are used for elements entering and leaving a view. The chapter also explores on multiple animation triggers, animation callbacks and sequence-based animation using keyframes.
In this guide, we go into greater depth on special transition states such as `*` (wildcard) and `void`, and show how these special states are used for elements entering and leaving a view. The chapter also explores multiple animation triggers, animation callbacks and sequence-based animation using keyframes.
## Predefined states and wildcard matching

View File

@ -317,7 +317,7 @@ Each hero in the heroes list should have a delete button.
Add the following button element to the `HeroesComponent` template, after the hero
name in the repeated `<li>` element.
<code-example path="toh-pt6/src/app/heroes/heroes.component.html" header="src/app/hero.service.ts" region="delete"></code-example>
<code-example path="toh-pt6/src/app/heroes/heroes.component.html" header="src/app/heroes/heroes.component.html" region="delete"></code-example>
The HTML for the list of heroes should look like this:

View File

@ -19,7 +19,7 @@
"build-local": "yarn ~~build",
"prebuild-with-ivy": "yarn setup-local && node scripts/switch-to-ivy",
"build-with-ivy": "yarn ~~build",
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js a8fe15cb6",
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js 1e83a8ecb",
"lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint",
"test": "yarn check-env && ng test",
"pree2e": "yarn check-env && yarn update-webdriver",

View File

@ -28,11 +28,11 @@
"uncompressed": {
"runtime-es5": 2932,
"runtime-es2015": 2938,
"main-es5": 555102,
"main-es5": 560811,
"main-es2015": 572938,
"polyfills-es5": 129161,
"polyfills-es2015": 53295
}
}
}
}
}

View File

@ -471,7 +471,7 @@
"@types/node@~8.9.4":
version "8.9.5"
resolved "http://registry.npmjs.org/@types/node/-/node-8.9.5.tgz#162b864bc70be077e6db212b322754917929e976"
resolved "https://registry.npmjs.org/@types/node/-/node-8.9.5.tgz#162b864bc70be077e6db212b322754917929e976"
"@types/q@^0.0.32":
version "0.0.32"
@ -2820,7 +2820,7 @@ express@2.5.x:
express@^4.14.1:
version "4.16.3"
resolved "http://registry.npmjs.org/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53"
resolved "https://registry.npmjs.org/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53"
dependencies:
accepts "~1.3.5"
array-flatten "1.1.1"
@ -3039,7 +3039,7 @@ finalhandler@1.0.6:
finalhandler@1.1.1:
version "1.1.1"
resolved "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
dependencies:
debug "2.6.9"
encodeurl "~1.0.2"
@ -5592,7 +5592,7 @@ p-finally@^1.0.0:
p-is-promise@^1.1.0:
version "1.1.0"
resolved "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e"
resolved "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e"
p-limit@^2.0.0:
version "2.0.0"

View File

@ -53,6 +53,7 @@ gulp.task('tools:build', loadTask('tools-build'));
gulp.task('check-cycle', loadTask('check-cycle'));
gulp.task('serve', loadTask('serve', 'default'));
gulp.task('changelog', loadTask('changelog'));
gulp.task('changelog:zonejs', loadTask('changelog-zonejs'));
gulp.task('check-env', () => {/* this is a noop because the env test ran already above */});
gulp.task('cldr:extract', loadTask('cldr', 'extract'));
gulp.task('cldr:download', loadTask('cldr', 'download'));

View File

@ -8,8 +8,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# Fetch rules_nodejs so we can install our npm dependencies
http_archive(
name = "build_bazel_rules_nodejs",
sha256 = "6d4edbf28ff6720aedf5f97f9b9a7679401bf7fca9d14a0fff80f644a99992b4",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.32.2/rules_nodejs-0.32.2.tar.gz"],
sha256 = "7c4a690268be97c96f04d505224ec4cb1ae53c2c2b68be495c9bd2634296a5cd",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.34.0/rules_nodejs-0.34.0.tar.gz"],
)
# Fetch sass rules for compiling sass files
@ -62,6 +62,11 @@ load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
install_bazel_dependencies()
# Load protractor dependencies
load("@npm_bazel_protractor//:package.bzl", "npm_bazel_protractor_dependencies")
npm_bazel_protractor_dependencies()
# Load karma dependencies
load("@npm_bazel_karma//:package.bzl", "rules_karma_dependencies")

View File

@ -23,11 +23,10 @@
"@angular/compiler": "file:../../dist/packages-dist/compiler",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
"@bazel/bazel": "file:../../node_modules/@bazel/bazel",
"@bazel/hide-bazel-files": "0.32.2",
"@bazel/karma": "0.32.2",
"@bazel/typescript": "0.32.2",
"@bazel/karma": "0.34.0",
"@bazel/protractor": "0.34.0",
"@bazel/typescript": "0.34.0",
"@types/jasmine": "2.8.8",
"protractor": "5.1.2",
"typescript": "3.4.2"
},
"scripts": {

View File

@ -1,5 +1,5 @@
load("@npm_bazel_protractor//:index.bzl", "protractor_web_test_suite")
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm_angular_bazel//:index.bzl", "protractor_web_test_suite")
ts_library(
name = "e2e",
@ -7,7 +7,7 @@ ts_library(
srcs = ["app.spec.ts"],
tsconfig = ":tsconfig.json",
deps = [
"@npm//@types",
"@npm//@types/jasmine",
"@npm//protractor",
],
)
@ -18,8 +18,8 @@ ts_library(
srcs = ["on-prepare.ts"],
tsconfig = ":tsconfig.json",
deps = [
"@npm//@angular/bazel",
"@npm//@types",
"@npm//@bazel/protractor",
"@npm//@types/node",
"@npm//protractor",
],
)
@ -27,10 +27,6 @@ ts_library(
protractor_web_test_suite(
name = "devserver_test",
configuration = "//:protractor.conf.js",
data = [
"@npm//@angular/bazel",
"@npm//protractor",
],
on_prepare = ":ts_on_prepare",
server = "//src:devserver",
deps = [":e2e"],
@ -39,10 +35,6 @@ protractor_web_test_suite(
protractor_web_test_suite(
name = "prodserver_test",
configuration = "//:protractor.conf.js",
data = [
"@npm//@angular/bazel",
"@npm//protractor",
],
on_prepare = ":ts_on_prepare",
server = "//src:prodserver",
deps = [":e2e"],

View File

@ -1,5 +1,5 @@
import { browser } from 'protractor';
import {OnPrepareConfig, runServer} from '@angular/bazel/protractor-utils';
import {OnPrepareConfig, runServer} from '@bazel/protractor/protractor-utils';
export = function(config: OnPrepareConfig) {
const portFlag = /prodserver(\.exe)?$/.test(config.server) ? '-p' : '-port';

View File

@ -30,12 +30,12 @@
rxjs "6.4.0"
"@angular/animations@file:../../dist/packages-dist/animations":
version "8.1.0-next.3"
version "8.2.0-next.2"
dependencies:
tslib "^1.9.0"
"@angular/bazel@file:../../dist/packages-dist/bazel":
version "8.1.0-next.3"
version "8.2.0-next.2"
dependencies:
"@angular-devkit/architect" "^0.800.0-beta.15"
"@angular-devkit/core" "^8.0.0-beta.15"
@ -57,12 +57,12 @@
parse5 "^5.0.0"
"@angular/common@file:../../dist/packages-dist/common":
version "8.1.0-next.3"
version "8.2.0-next.2"
dependencies:
tslib "^1.9.0"
"@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli":
version "8.1.0-next.3"
version "8.2.0-next.2"
dependencies:
canonical-path "1.0.0"
chokidar "^2.1.1"
@ -76,17 +76,17 @@
yargs "13.1.0"
"@angular/compiler@file:../../dist/packages-dist/compiler":
version "8.1.0-next.3"
version "8.2.0-next.2"
dependencies:
tslib "^1.9.0"
"@angular/core@file:../../dist/packages-dist/core":
version "8.1.0-next.3"
version "8.2.0-next.2"
dependencies:
tslib "^1.9.0"
"@angular/forms@file:../../dist/packages-dist/forms":
version "8.1.0-next.3"
version "8.2.0-next.2"
dependencies:
tslib "^1.9.0"
@ -98,51 +98,53 @@
tslib "^1.7.1"
"@angular/platform-browser-dynamic@file:../../dist/packages-dist/platform-browser-dynamic":
version "8.1.0-next.3"
version "8.2.0-next.2"
dependencies:
tslib "^1.9.0"
"@angular/platform-browser@file:../../dist/packages-dist/platform-browser":
version "8.1.0-next.3"
version "8.2.0-next.2"
dependencies:
tslib "^1.9.0"
"@angular/router@file:../../dist/packages-dist/router":
version "8.1.0-next.3"
version "8.2.0-next.2"
dependencies:
tslib "^1.9.0"
"@bazel/bazel-darwin_x64@0.27.0":
version "0.27.0"
resolved "https://registry.yarnpkg.com/@bazel/bazel-darwin_x64/-/bazel-darwin_x64-0.27.0.tgz#83a03c92d52ae60e48e86a1ee697e69e12ddbdf6"
integrity sha512-CyavIbRKRa/55aMyfEM9hjbt4TVISfv7HLeymHTGTLWzS8uQokQ8W9tR/pgc7YJn8F0x64dd7nQKxhbYHM1Qfg==
"@bazel/bazel-darwin_x64@0.28.1":
version "0.28.1"
resolved "https://registry.yarnpkg.com/@bazel/bazel-darwin_x64/-/bazel-darwin_x64-0.28.1.tgz#415658785e1dbd6f7ab5c8f2b98c1c99c614e1d5"
integrity sha512-VDKWmplAfa4uCAbkIQ5nRn04MFQqtsPNuc2HkluJ8OIum773yC2dPR+OlLBKxrlBuKJYB27TtbOwOa6w/uK7aw==
"@bazel/bazel-linux_x64@0.27.0":
version "0.27.0"
resolved "https://registry.yarnpkg.com/@bazel/bazel-linux_x64/-/bazel-linux_x64-0.27.0.tgz#2358292aa4901f526ba9b90874256f63d6d6608c"
integrity sha512-hO04v7C6M3Jf+qNlLE+IticZZKkkS7Nv6+pXDnENgFWrqLV2H93un6kNQnk83B0hP2cEqRQ8rw5yrIcqXNNuSQ==
"@bazel/bazel-linux_x64@0.28.1":
version "0.28.1"
resolved "https://registry.yarnpkg.com/@bazel/bazel-linux_x64/-/bazel-linux_x64-0.28.1.tgz#f78006089e17660261088272a0e04fc886572e34"
integrity sha512-n4XfNxagYhejQD32V4XSxT/qzuH1l/2jxslbKSak66/uQ+wad8Ew9rjNb4JUin3xtrfFtzmxx2jpQkybZsRVGA==
"@bazel/bazel-win32_x64@0.27.0":
version "0.27.0"
resolved "https://registry.yarnpkg.com/@bazel/bazel-win32_x64/-/bazel-win32_x64-0.27.0.tgz#0e5e498de5ccccc9a6cf481cd46904ee938ab6c2"
integrity sha512-7hIGNhdgaxRt9ceSOCs3eSTtCNi4GXz3nu6OjfgSp+QiqLbW/iAVWa8M8vD5aemZ1BSHek4/LISdWUTncLJk+w==
"@bazel/bazel-win32_x64@0.28.1":
version "0.28.1"
resolved "https://registry.yarnpkg.com/@bazel/bazel-win32_x64/-/bazel-win32_x64-0.28.1.tgz#60a2819618cf7582cc35ac16c01763a5e807b414"
integrity sha512-T4xksGfKikaHS4zxnGT6r5R436mz9j2lz//L1vc5sJnaEF/1e2Gv6MLl86vfZW2Xxo6iIEi6ntSzgYxP2Blohw==
"@bazel/bazel@file:../../node_modules/@bazel/bazel":
version "0.27.0"
version "0.28.1"
dependencies:
"@bazel/hide-bazel-files" latest
optionalDependencies:
"@bazel/bazel-darwin_x64" "0.27.0"
"@bazel/bazel-linux_x64" "0.27.0"
"@bazel/bazel-win32_x64" "0.27.0"
"@bazel/bazel-darwin_x64" "0.28.1"
"@bazel/bazel-linux_x64" "0.28.1"
"@bazel/bazel-win32_x64" "0.28.1"
"@bazel/hide-bazel-files@0.32.2":
version "0.32.2"
resolved "https://registry.yarnpkg.com/@bazel/hide-bazel-files/-/hide-bazel-files-0.32.2.tgz#a482855eafbccb56b1fce0d92ff922c2c6e0a90c"
integrity sha512-585XY53mhMZaCjEQJ+aDqkmydWZbuXsKrZsSpoW9YeAVEH0poQY3YhdyCPmMVBo7/l1mkrqpFuOK5BpECfwdtA==
"@bazel/hide-bazel-files@latest":
version "0.34.0"
resolved "https://registry.yarnpkg.com/@bazel/hide-bazel-files/-/hide-bazel-files-0.34.0.tgz#368ea84db2756ff80ead23bb9eb179e9ed24b462"
integrity sha512-suyO6cZf8iV6W2LkM1X1spWBt7CsRRXH7gU1wYNuAuHYkkfI0A6qj84yPiIXiOt/2G44kbioGyC1bUsI3fKv7A==
"@bazel/karma@0.32.2":
version "0.32.2"
resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-0.32.2.tgz#0f6adf0cf1970c50cfdcf9cb2b10a8d3e21731fe"
integrity sha512-iWb8aqE+llpZhlreDweM7llwnSAQ9QTYdz4VvIcZBGVD0KtHxHaKiqK4Zo4Qrmr9H0kcOhT7nvRBg3QOUJVrUw==
"@bazel/karma@0.34.0":
version "0.34.0"
resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-0.34.0.tgz#ee468501a408244a2c1844b48ca5a938874d9444"
integrity sha512-9EziieE3Zkf7D5tBuX4rO+hhpI4ypNAWReiO/fykjj5oYpLYhhhGGUyFQ8PCIfduPcGZooCTMsctmwZJUb3rRA==
dependencies:
jasmine-core "2.8.0"
karma "^4.0.0"
@ -156,10 +158,17 @@
semver "5.6.0"
tmp "0.0.33"
"@bazel/typescript@0.32.2":
version "0.32.2"
resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-0.32.2.tgz#c296bb44cb6362a0e3a08ca88752852bc9591ecf"
integrity sha512-32zDyvHdYjIa63vtImhl6wy5ErOFVWPkjMT2T035D0UPSKI1tvENW/bRZ3QFlFHqfmJZRBpaI3GiUpO3vUvzmw==
"@bazel/protractor@0.34.0":
version "0.34.0"
resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-0.34.0.tgz#af166306518bf1319e8ca255f798712c8714b5e9"
integrity sha512-U6O8hRlerkQ/WfnEVct1yipVQr5epdYaLiOW1eLpmiRMM4RuMhIpIyKkpum5xqFlYP5kwqwje8BS8NHvBfvZnQ==
dependencies:
protractor "^5.4.2"
"@bazel/typescript@0.34.0":
version "0.34.0"
resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-0.34.0.tgz#ca0fdf15343a930fc1418dbbf7d6cae49e6bc89b"
integrity sha512-GXVSADXdbPyWLskIYAzQsBB1LhZgWF5+M6WCQGOvRWjZfXgRP5QDG5pKJavRGzVd6ofigLPA1xT6Vc7dUEDNtg==
dependencies:
protobufjs "6.8.8"
semver "5.6.0"
@ -327,20 +336,15 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.9.tgz#2e8d678039d27943ce53a1913386133227fd9066"
integrity sha512-NelG/dSahlXYtSoVPErrp06tYFrvzj8XLWmKA+X8x0W//4MqbUyZu++giUG/v0bjAT6/Qxa8IjodrfdACyb0Fg==
"@types/node@^6.0.46":
version "6.14.6"
resolved "https://registry.yarnpkg.com/@types/node/-/node-6.14.6.tgz#31df045b4c7618ff74d84f542fc3d29445dd566b"
integrity sha512-rFs9zCFtSHuseiNXxYxFlun8ibu+jtZPgRM+2ILCmeLiGeGLiIGxuOzD+cNyHegI1GD+da3R/cIbs9+xCLp13w==
"@types/q@^0.0.32":
version "0.0.32"
resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5"
integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU=
"@types/selenium-webdriver@^2.53.35", "@types/selenium-webdriver@~2.53.39":
version "2.53.43"
resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-2.53.43.tgz#2de3d718819bc20165754c4a59afb7e9833f6707"
integrity sha512-UBYHWph6P3tutkbXpW6XYg9ZPbTKjw/YC2hGG1/GEvWwTbvezBUv3h+mmUFw79T3RFPnmedpiXdOBbXX+4l0jg==
"@types/selenium-webdriver@^3.0.0":
version "3.0.16"
resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz#50a4755f8e33edacd9c406729e9b930d2451902a"
integrity sha512-lMC2G0ItF2xv4UCiwbJGbnJlIuUixHrioOhNGHSCsYCJ8l4t9hMCUimCytvFv7qy6AfSzRxhRHoGa+UqaqwyeA==
"@types/z-schema@3.16.31":
version "3.16.31"
@ -360,12 +364,7 @@ accepts@~1.3.4:
mime-types "~2.1.24"
negotiator "0.6.2"
adm-zip@0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.4.tgz#a61ed5ae6905c3aea58b3a657d25033091052736"
integrity sha1-ph7VrmkFw66lizplfSUDMJEFJzY=
adm-zip@^0.4.7, adm-zip@^0.4.9, adm-zip@~0.4.3:
adm-zip@^0.4.9, adm-zip@~0.4.3:
version "0.4.13"
resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.13.tgz#597e2f8cc3672151e1307d3e95cddbc75672314a"
integrity sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==
@ -375,14 +374,6 @@ after@0.8.2:
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
agent-base@2:
version "2.1.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7"
integrity sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=
dependencies:
extend "~3.0.0"
semver "~5.0.1"
agent-base@^4.1.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
@ -601,10 +592,10 @@ blob@0.0.5:
resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683"
integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==
blocking-proxy@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-0.0.5.tgz#462905e0dcfbea970f41aa37223dda9c07b1912b"
integrity sha1-RikF4Nz76pcPQao3Ij3anAexkSs=
blocking-proxy@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-1.0.1.tgz#81d6fd1fe13a4c0d6957df7f91b75e98dac40cb2"
integrity sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==
dependencies:
minimist "^1.2.0"
@ -653,6 +644,13 @@ braces@^2.3.1, braces@^2.3.2:
split-string "^3.0.2"
to-regex "^3.0.1"
browserstack@^1.5.1:
version "1.5.2"
resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.2.tgz#17d8bb76127a1cc0ea416424df80d218f803673f"
integrity sha512-+6AFt9HzhKykcPF79W6yjEUJcdvZOV0lIXdkORXMJftGrDl0OKWqRF4GHqpDNkxiceDT/uB7Fb/aDwktvXX7dg==
dependencies:
https-proxy-agent "^2.2.1"
buffer-alloc-unsafe@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
@ -905,7 +903,7 @@ date-format@^2.0.0:
resolved "https://registry.yarnpkg.com/date-format/-/date-format-2.0.0.tgz#7cf7b172f1ec564f0003b39ea302c5498fb98c8f"
integrity sha512-M6UqVvZVgFYqZL1SfHsRGIQSz3ZL+qgbsV5Lp1Vj61LZVYuEwcMXYay7DRDtYs2HQQBK5hQtQ0fD9aEJ89V0LA==
debug@2, debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@ -1171,7 +1169,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
extend@3, extend@^3.0.0, extend@~3.0.0, extend@~3.0.2:
extend@^3.0.0, extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
@ -1486,15 +1484,6 @@ http-signature@~1.2.0:
jsprim "^1.2.2"
sshpk "^1.7.0"
https-proxy-agent@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6"
integrity sha1-NffabEjOTdv6JkiRrFk+5f+GceY=
dependencies:
agent-base "2"
debug "2"
extend "3"
https-proxy-agent@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
@ -1748,7 +1737,7 @@ isstream@~0.1.2:
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
jasmine-core@2.8.0:
jasmine-core@2.8.0, jasmine-core@~2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e"
integrity sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=
@ -1758,19 +1747,14 @@ jasmine-core@^3.3:
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.4.0.tgz#2a74618e966026530c3518f03e9f845d26473ce3"
integrity sha512-HU/YxV4i6GcmiH4duATwAbJQMlE0MsDIR5XmSVxURxKHn3aGAdbY1/ZJFmVRbKtnLwIxxMJD7gYaPsypcbYimg==
jasmine-core@~2.99.0:
version "2.99.1"
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.99.1.tgz#e6400df1e6b56e130b61c4bcd093daa7f6e8ca15"
integrity sha1-5kAN8ea1bhMLYcS80JPap/boyhU=
jasmine@^2.5.3:
version "2.99.0"
resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.99.0.tgz#8ca72d102e639b867c6489856e0e18a9c7aa42b7"
integrity sha1-jKctEC5jm4Z8ZImFbg4YqceqQrc=
jasmine@2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.8.0.tgz#6b089c0a11576b1f16df11b80146d91d4e8b8a3e"
integrity sha1-awicChFXax8W3xG4AUbZHU6Lij4=
dependencies:
exit "^0.1.2"
glob "^7.0.6"
jasmine-core "~2.99.0"
jasmine-core "~2.8.0"
jasminewd2@^2.1.0:
version "2.2.0"
@ -1819,6 +1803,16 @@ jsprim@^1.2.2:
json-schema "0.2.3"
verror "1.10.0"
jszip@^3.1.3:
version "3.2.2"
resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.2.2.tgz#b143816df7e106a9597a94c77493385adca5bd1d"
integrity sha512-NmKajvAFQpbg3taXQXr/ccS2wcucR1AZ+NtyWp2Nq7HHVsXhcJFR8p0Baf32C2yVvBylFWVeKf+WI2AnvlPhpA==
dependencies:
lie "~3.3.0"
pako "~1.0.2"
readable-stream "~2.3.6"
set-immediate-shim "~1.0.1"
jszip@^3.1.5:
version "3.2.1"
resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.2.1.tgz#c5d32df7274042282b157efb16e522b43435e01a"
@ -2308,11 +2302,6 @@ optimist@^0.6.1, optimist@~0.6.0:
minimist "~0.0.1"
wordwrap "~0.0.2"
options@>=0.0.5:
version "0.0.6"
resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f"
integrity sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=
os-homedir@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
@ -2489,25 +2478,25 @@ protobufjs@6.8.8:
"@types/node" "^10.1.0"
long "^4.0.0"
protractor@5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/protractor/-/protractor-5.1.2.tgz#9b221741709a4c62d5cd53c6aadd54a71137e95f"
integrity sha1-myIXQXCaTGLVzVPGqt1UpxE36V8=
protractor@^5.4.2:
version "5.4.2"
resolved "https://registry.yarnpkg.com/protractor/-/protractor-5.4.2.tgz#329efe37f48b2141ab9467799be2d4d12eb48c13"
integrity sha512-zlIj64Cr6IOWP7RwxVeD8O4UskLYPoyIcg0HboWJL9T79F1F0VWtKkGTr/9GN6BKL+/Q/GmM7C9kFVCfDbP5sA==
dependencies:
"@types/node" "^6.0.46"
"@types/q" "^0.0.32"
"@types/selenium-webdriver" "~2.53.39"
blocking-proxy "0.0.5"
"@types/selenium-webdriver" "^3.0.0"
blocking-proxy "^1.0.0"
browserstack "^1.5.1"
chalk "^1.1.3"
glob "^7.0.3"
jasmine "^2.5.3"
jasmine "2.8.0"
jasminewd2 "^2.1.0"
optimist "~0.6.0"
q "1.4.1"
saucelabs "~1.3.0"
selenium-webdriver "3.0.1"
saucelabs "^1.5.0"
selenium-webdriver "3.6.0"
source-map-support "~0.4.0"
webdriver-js-extender "^1.0.0"
webdriver-js-extender "2.1.0"
webdriver-manager "^12.0.6"
pseudomap@^1.0.2:
@ -2774,44 +2763,21 @@ saucelabs@^1.5.0:
dependencies:
https-proxy-agent "^2.2.1"
saucelabs@~1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.3.0.tgz#d240e8009df7fa87306ec4578a69ba3b5c424fee"
integrity sha1-0kDoAJ33+ocwbsRXimm6O1xCT+4=
dependencies:
https-proxy-agent "^1.0.0"
sax@0.6.x:
version "0.6.1"
resolved "https://registry.yarnpkg.com/sax/-/sax-0.6.1.tgz#563b19c7c1de892e09bfc4f2fc30e3c27f0952b9"
integrity sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk=
sax@>=0.6.0, sax@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
selenium-webdriver@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz#a2dea5da4a97f6672e89e7ca7276cefa365147a7"
integrity sha1-ot6l2kqX9mcuiefKcnbO+jZRR6c=
selenium-webdriver@3.6.0, selenium-webdriver@^3.0.1:
version "3.6.0"
resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc"
integrity sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==
dependencies:
adm-zip "^0.4.7"
jszip "^3.1.3"
rimraf "^2.5.4"
tmp "0.0.30"
xml2js "^0.4.17"
selenium-webdriver@^2.53.2:
version "2.53.3"
resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-2.53.3.tgz#d29ff5a957dff1a1b49dc457756e4e4bfbdce085"
integrity sha1-0p/1qVff8aG0ncRXdW5OS/vc4IU=
dependencies:
adm-zip "0.4.4"
rimraf "^2.2.8"
tmp "0.0.24"
ws "^1.0.1"
xml2js "0.4.4"
selenium-webdriver@^4.0.0-alpha.1:
version "4.0.0-alpha.3"
resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.3.tgz#fb974f29696a6801ecaf203e38a65c3dbe7e363a"
@ -2832,11 +2798,6 @@ semver@^5.3.0, semver@^5.5.0, semver@^5.6.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
semver@~5.0.1:
version "5.0.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a"
integrity sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=
set-blocking@^2.0.0, set-blocking@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
@ -3158,11 +3119,6 @@ tar@^4:
safe-buffer "^5.1.2"
yallist "^3.0.3"
tmp@0.0.24:
version "0.0.24"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.24.tgz#d6a5e198d14a9835cc6f2d7c3d9e302428c8cf12"
integrity sha1-1qXhmNFKmDXMby18PZ4wJCjIzxI=
tmp@0.0.30:
version "0.0.30"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed"
@ -3276,11 +3232,6 @@ typescript@~3.4.3:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99"
integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==
ultron@1.0.x:
version "1.0.2"
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa"
integrity sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=
ultron@~1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c"
@ -3378,13 +3329,13 @@ void-elements@^2.0.0:
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
webdriver-js-extender@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz#81c533a9e33d5bfb597b4e63e2cdb25b54777515"
integrity sha1-gcUzqeM9W/tZe05j4s2yW1R3dRU=
webdriver-js-extender@2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz#57d7a93c00db4cc8d556e4d3db4b5db0a80c3bb7"
integrity sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==
dependencies:
"@types/selenium-webdriver" "^2.53.35"
selenium-webdriver "^2.53.2"
"@types/selenium-webdriver" "^3.0.0"
selenium-webdriver "^3.0.1"
webdriver-manager@^12.0.6:
version "12.1.5"
@ -3440,14 +3391,6 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
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"
ws@~3.3.1:
version "3.3.3"
resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"
@ -3457,14 +3400,6 @@ ws@~3.3.1:
safe-buffer "~5.1.0"
ultron "~1.1.0"
xml2js@0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.4.tgz#3111010003008ae19240eba17497b57c729c555d"
integrity sha1-MREBAAMAiuGSQOuhdJe1fHKcVV0=
dependencies:
sax "0.6.x"
xmlbuilder ">=1.0.0"
xml2js@^0.4.17, xml2js@^0.4.19:
version "0.4.19"
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7"
@ -3473,11 +3408,6 @@ xml2js@^0.4.17, xml2js@^0.4.19:
sax ">=0.6.0"
xmlbuilder "~9.0.1"
xmlbuilder@>=1.0.0:
version "13.0.2"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-13.0.2.tgz#02ae33614b6a047d1c32b5389c1fdacb2bce47a7"
integrity sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==
xmlbuilder@~9.0.1:
version "9.0.7"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"

View File

@ -8084,7 +8084,7 @@ through2@^2.0.0:
"through@>=2.2.7 <3", through@X.X.X, through@^2.3.6:
version "2.3.8"
resolved "http://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
thunkify@~2.1.1:

View File

@ -67,8 +67,15 @@ if [[ $? != 0 ]]; then exit 1; fi
grep "_MatMenuBase.ngBaseDef = ɵngcc0.ɵɵdefineBase({ inputs: {" node_modules/@angular/material/esm5/menu.es5.js
if [[ $? != 0 ]]; then exit 1; fi
# Did it handle namespace imported decorators in UMD?
# Did it handle namespace imported decorators in UMD using `__decorate` syntax?
grep "type: core.Injectable" node_modules/@angular/common/bundles/common.umd.js
# (and ensure the @angular/common package is indeed using `__decorate` syntax)
grep "JsonPipe = __decorate(" node_modules/@angular/common/bundles/common.umd.js.__ivy_ngcc_bak
# Did it handle namespace imported decorators in UMD using static properties?
grep "type: core.Injectable," node_modules/@angular/cdk/bundles/cdk-a11y.umd.js
# (and ensure the @angular/cdk/a11y package is indeed using static properties)
grep "FocusMonitor.decorators =" node_modules/@angular/cdk/bundles/cdk-a11y.umd.js.__ivy_ngcc_bak
# Can it be safely run again (as a noop)?
# And check that it logged skipping compilation as expected

View File

@ -1,4 +1,4 @@
load("//packages/bazel:index.bzl", "protractor_web_test_suite")
load("@npm_bazel_protractor//:index.bzl", "protractor_web_test_suite")
"""
Macro that can be used to define a benchmark test. This differentiates from
@ -18,7 +18,6 @@ def benchmark_test(name, server, deps, tags = []):
server = server,
tags = tags,
deps = [
"@npm//protractor",
"@npm//yargs",
] + deps,
)

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractorUtils = require('@bazel/protractor/protractor-utils');
const protractor = require('protractor');
module.exports = async function(config) {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractorUtils = require('@bazel/protractor/protractor-utils');
const protractor = require('protractor');
module.exports = async function(config) {

View File

@ -1,4 +1,4 @@
load("//packages/bazel:index.bzl", "protractor_web_test_suite")
load("@npm_bazel_protractor//:index.bzl", "protractor_web_test_suite")
load("//tools:defaults.bzl", "ts_library")
def example_test(name, srcs, server, data = [], **kwargs):
@ -18,12 +18,11 @@ def example_test(name, srcs, server, data = [], **kwargs):
protractor_web_test_suite(
name = "protractor_tests",
data = ["//packages/bazel/src/protractor/utils"] + data,
data = data,
on_prepare = "//modules/playground/e2e_test:start-server.js",
server = server,
deps = [
":%s_lib" % name,
"@npm//protractor",
"@npm//selenium-webdriver",
"@npm//yargs",
"@npm//source-map",

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractorUtils = require('@bazel/protractor/protractor-utils');
const protractor = require('protractor');
module.exports = async function(config) {

View File

@ -1,6 +1,6 @@
{
"name": "angular-srcs",
"version": "8.2.0-next.2",
"version": "9.0.0-next.0",
"private": true,
"description": "Angular - a web framework for modern web apps",
"homepage": "https://github.com/angular/angular",
@ -35,10 +35,10 @@
"@angular-devkit/core": "^8.0.0-beta.15",
"@angular-devkit/schematics": "^8.0.0-beta.15",
"@angular/bazel": "file:./tools/npm/@angular_bazel",
"@bazel/jasmine": "0.32.2",
"@bazel/hide-bazel-files": "0.32.2",
"@bazel/karma": "0.32.2",
"@bazel/typescript": "0.32.2",
"@bazel/jasmine": "0.34.0",
"@bazel/karma": "0.34.0",
"@bazel/protractor": "0.34.0",
"@bazel/typescript": "0.34.0",
"@microsoft/api-extractor": "^7.0.21",
"@schematics/angular": "^8.0.0-beta.15",
"@types/angular": "^1.6.47",
@ -120,7 +120,7 @@
"// 3": "when updating @bazel/bazel version you also need to update the RBE settings in .bazelrc (see https://github.com/angular/angular/pull/27935)",
"devDependencies": {
"@angular/cli": "^8.0.0-beta.15",
"@bazel/bazel": "0.27.0",
"@bazel/bazel": "0.28.1",
"@bazel/buildifier": "^0.26.0",
"@bazel/ibazel": "~0.9.0",
"@types/minimist": "^1.2.0",
@ -166,4 +166,4 @@
"resolutions": {
"natives": "1.1.6"
}
}
}

View File

@ -25,12 +25,13 @@ def rules_angular_dev_dependencies():
"""
# Needed for Remote Execution
# https://github.com/bazelbuild/bazel-toolchains/releases
_maybe(
http_archive,
name = "bazel_toolchains",
sha256 = "4598bf5a8b4f5ced82c782899438a7ba695165d47b3bf783ce774e89a8c6e617",
strip_prefix = "bazel-toolchains-0.27.0",
url = "https://github.com/bazelbuild/bazel-toolchains/archive/0.27.0.tar.gz",
sha256 = "dcb58e7e5f0b4da54c6c5f8ebc65e63fcfb37414466010cf82ceff912162296e",
strip_prefix = "bazel-toolchains-0.28.2",
url = "https://github.com/bazelbuild/bazel-toolchains/archive/0.28.2.tar.gz",
)
#############################################

View File

@ -15,8 +15,8 @@ workspace(
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
RULES_NODEJS_VERSION = "0.32.2"
RULES_NODEJS_SHA256 = "6d4edbf28ff6720aedf5f97f9b9a7679401bf7fca9d14a0fff80f644a99992b4"
RULES_NODEJS_VERSION = "0.34.0"
RULES_NODEJS_SHA256 = "7c4a690268be97c96f04d505224ec4cb1ae53c2c2b68be495c9bd2634296a5cd"
http_archive(
name = "build_bazel_rules_nodejs",
sha256 = RULES_NODEJS_SHA256,
@ -63,8 +63,6 @@ node_repositories(
yarn_install(
name = "npm",
# TODO(gregmagolan): fix rules_nodejs so that if @bazel/hide-bazel-files is detected then this is forced true
always_hide_bazel_files = True,
package_json = "//:package.json",
yarn_lock = "//:yarn.lock",
)
@ -72,6 +70,9 @@ yarn_install(
load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
install_bazel_dependencies()
load("@npm_bazel_protractor//:package.bzl", "npm_bazel_protractor_dependencies")
npm_bazel_protractor_dependencies()
load("@npm_bazel_karma//:package.bzl", "rules_karma_dependencies")
rules_karma_dependencies()

View File

@ -1,5 +1,5 @@
load("@npm_bazel_protractor//:index.bzl", "protractor_web_test_suite")
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm_angular_bazel//:index.bzl", "protractor_web_test_suite")
ts_library(
name = "e2e_lib",
@ -21,10 +21,6 @@ ts_library(
protractor_web_test_suite(
name = "prodserver_test",
data = [
"@npm//@angular/bazel",
"@npm//protractor",
],
on_prepare = ":protractor.on-prepare.js",
server = "//src:prodserver",
deps = [":e2e_lib"],
@ -32,10 +28,6 @@ protractor_web_test_suite(
protractor_web_test_suite(
name = "devserver_test",
data = [
"@npm//@angular/bazel",
"@npm//protractor",
],
on_prepare = ":protractor.on-prepare.js",
server = "//src:devserver",
deps = [":e2e_lib"],

View File

@ -5,11 +5,11 @@
// If the function returns a promise, as it does here, protractor will wait
// for the promise to resolve before running tests.
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractorUtils = require('@bazel/protractor/protractor-utils');
const protractor = require('protractor');
module.exports = function(config) {
// In this example, `@angular/bazel/protractor-utils` is used to run
// In this example, `@bazel/protractor/protractor-utils` is used to run
// the server. protractorUtils.runServer() runs the server on a randomly
// selected port (given a port flag to pass to the server as an argument).
// The port used is returned in serverSpec and the protractor serverUrl

View File

@ -48,11 +48,11 @@ function addDevDependenciesToPackageJson(options: Schema) {
const devDependencies: {[k: string]: string} = {
'@angular/bazel': angularCoreVersion,
'@bazel/bazel': '^0.27.0',
'@bazel/hide-bazel-files': '0.32.2',
'@bazel/bazel': '^0.28.1',
'@bazel/ibazel': '^0.10.2',
'@bazel/karma': '0.32.2',
'@bazel/typescript': '0.32.2',
'@bazel/karma': '0.34.0',
'@bazel/protractor': '0.34.0',
'@bazel/typescript': '0.34.0',
};
const recorder = host.beginUpdate(packageJson);

View File

@ -113,9 +113,10 @@ describe('ng-add schematic', () => {
const json = JSON.parse(content);
const devDeps = Object.keys(json.devDependencies);
expect(devDeps).toContain('@bazel/bazel');
expect(devDeps).toContain('@bazel/hide-bazel-files');
expect(devDeps).toContain('@bazel/ibazel');
expect(devDeps).toContain('@bazel/karma');
expect(devDeps).toContain('@bazel/protractor');
expect(devDeps).toContain('@bazel/typescript');
});
it('should replace an existing dev dependency', async() => {

View File

@ -15,6 +15,7 @@ import localeHu from '@angular/common/locales/hu';
import localeSr from '@angular/common/locales/sr';
import localeTh from '@angular/common/locales/th';
import {isDate, toDate, formatDate} from '@angular/common/src/i18n/format_date';
import {ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID} from '@angular/core';
describe('Format date', () => {
describe('toDate', () => {
@ -46,13 +47,12 @@ describe('Format date', () => {
describe('formatDate', () => {
const isoStringWithoutTime = '2015-01-01';
const defaultLocale = 'en-US';
const defaultFormat = 'mediumDate';
let date: Date;
// Check the transformation of a date into a pattern
function expectDateFormatAs(date: Date | string, pattern: any, output: string): void {
expect(formatDate(date, pattern, defaultLocale)).toEqual(output, `pattern: "${pattern}"`);
expect(formatDate(date, pattern, DEFAULT_LOCALE_ID)).toEqual(output, `pattern: "${pattern}"`);
}
beforeAll(() => {
@ -209,7 +209,8 @@ describe('Format date', () => {
};
Object.keys(dateFixtures).forEach((pattern: string) => {
expect(formatDate(date, pattern, defaultLocale, '+0430')).toMatch(dateFixtures[pattern]);
expect(formatDate(date, pattern, DEFAULT_LOCALE_ID, '+0430'))
.toMatch(dateFixtures[pattern]);
});
});
@ -253,22 +254,22 @@ describe('Format date', () => {
};
Object.keys(dateFixtures).forEach((pattern: string) => {
expect(formatDate(date, pattern, defaultLocale)).toMatch(dateFixtures[pattern]);
expect(formatDate(date, pattern, DEFAULT_LOCALE_ID)).toMatch(dateFixtures[pattern]);
});
});
it('should format invalid in IE ISO date',
() => expect(formatDate('2017-01-11T12:00:00.014-0500', defaultFormat, defaultLocale))
() => expect(formatDate('2017-01-11T12:00:00.014-0500', defaultFormat, DEFAULT_LOCALE_ID))
.toEqual('Jan 11, 2017'));
it('should format invalid in Safari ISO date',
() => expect(formatDate('2017-01-20T12:00:00+0000', defaultFormat, defaultLocale))
() => expect(formatDate('2017-01-20T12:00:00+0000', defaultFormat, DEFAULT_LOCALE_ID))
.toEqual('Jan 20, 2017'));
// https://github.com/angular/angular/issues/9524
// https://github.com/angular/angular/issues/9524
it('should format correctly with iso strings that contain time',
() => expect(formatDate('2017-05-07T22:14:39', 'dd-MM-yyyy HH:mm', defaultLocale))
() => expect(formatDate('2017-05-07T22:14:39', 'dd-MM-yyyy HH:mm', DEFAULT_LOCALE_ID))
.toMatch(/07-05-2017 \d{2}:\d{2}/));
// https://github.com/angular/angular/issues/21491
@ -276,22 +277,22 @@ describe('Format date', () => {
// this test only works if the timezone is not in UTC
// which is the case for BrowserStack when we test Safari
if (new Date().getTimezoneOffset() !== 0) {
expect(formatDate('2018-01-11T13:00:00', 'HH', defaultLocale))
.not.toEqual(formatDate('2018-01-11T13:00:00Z', 'HH', defaultLocale));
expect(formatDate('2018-01-11T13:00:00', 'HH', DEFAULT_LOCALE_ID))
.not.toEqual(formatDate('2018-01-11T13:00:00Z', 'HH', DEFAULT_LOCALE_ID));
}
});
// https://github.com/angular/angular/issues/16624
// https://github.com/angular/angular/issues/17478
it('should show the correct time when the timezone is fixed', () => {
expect(formatDate('2017-06-13T10:14:39+0000', 'shortTime', defaultLocale, '+0000'))
expect(formatDate('2017-06-13T10:14:39+0000', 'shortTime', DEFAULT_LOCALE_ID, '+0000'))
.toEqual('10:14 AM');
expect(formatDate('2017-06-13T10:14:39+0000', 'h:mm a', defaultLocale, '+0000'))
expect(formatDate('2017-06-13T10:14:39+0000', 'h:mm a', DEFAULT_LOCALE_ID, '+0000'))
.toEqual('10:14 AM');
});
it('should remove bidi control characters',
() => expect(formatDate(date, 'MM/dd/yyyy', defaultLocale) !.length).toEqual(10));
() => expect(formatDate(date, 'MM/dd/yyyy', DEFAULT_LOCALE_ID) !.length).toEqual(10));
it(`should format the date correctly in various locales`, () => {
expect(formatDate(date, 'short', 'de')).toEqual('15.06.15, 09:03');

View File

@ -12,10 +12,9 @@ import localeFr from '@angular/common/locales/fr';
import localeAr from '@angular/common/locales/ar';
import {formatCurrency, formatNumber, formatPercent, registerLocaleData} from '@angular/common';
import {describe, expect, it} from '@angular/core/testing/src/testing_internal';
import {ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID} from '@angular/core';
describe('Format number', () => {
const defaultLocale = 'en-US';
beforeAll(() => {
registerLocaleData(localeEn);
registerLocaleData(localeEsUS);
@ -26,18 +25,18 @@ describe('Format number', () => {
describe('Number', () => {
describe('transform', () => {
it('should return correct value for numbers', () => {
expect(formatNumber(12345, defaultLocale)).toEqual('12,345');
expect(formatNumber(123, defaultLocale, '.2')).toEqual('123.00');
expect(formatNumber(1, defaultLocale, '3.')).toEqual('001');
expect(formatNumber(1.1, defaultLocale, '3.4-5')).toEqual('001.1000');
expect(formatNumber(1.123456, defaultLocale, '3.4-5')).toEqual('001.12346');
expect(formatNumber(1.1234, defaultLocale)).toEqual('1.123');
expect(formatNumber(1.123456, defaultLocale, '.2')).toEqual('1.123');
expect(formatNumber(1.123456, defaultLocale, '.4')).toEqual('1.1235');
expect(formatNumber(12345, DEFAULT_LOCALE_ID)).toEqual('12,345');
expect(formatNumber(123, DEFAULT_LOCALE_ID, '.2')).toEqual('123.00');
expect(formatNumber(1, DEFAULT_LOCALE_ID, '3.')).toEqual('001');
expect(formatNumber(1.1, DEFAULT_LOCALE_ID, '3.4-5')).toEqual('001.1000');
expect(formatNumber(1.123456, DEFAULT_LOCALE_ID, '3.4-5')).toEqual('001.12346');
expect(formatNumber(1.1234, DEFAULT_LOCALE_ID)).toEqual('1.123');
expect(formatNumber(1.123456, DEFAULT_LOCALE_ID, '.2')).toEqual('1.123');
expect(formatNumber(1.123456, DEFAULT_LOCALE_ID, '.4')).toEqual('1.1235');
});
it('should throw if minFractionDigits is explicitly higher than maxFractionDigits', () => {
expect(() => formatNumber(1.1, defaultLocale, '3.4-2'))
expect(() => formatNumber(1.1, DEFAULT_LOCALE_ID, '3.4-2'))
.toThrowError(/is higher than the maximum/);
});
});
@ -51,27 +50,27 @@ describe('Format number', () => {
describe('Percent', () => {
describe('transform', () => {
it('should return correct value for numbers', () => {
expect(formatPercent(1.23, defaultLocale)).toEqual('123%');
expect(formatPercent(1.2, defaultLocale, '.2')).toEqual('120.00%');
expect(formatPercent(1.2, defaultLocale, '4.2')).toEqual('0,120.00%');
expect(formatPercent(1.23, DEFAULT_LOCALE_ID)).toEqual('123%');
expect(formatPercent(1.2, DEFAULT_LOCALE_ID, '.2')).toEqual('120.00%');
expect(formatPercent(1.2, DEFAULT_LOCALE_ID, '4.2')).toEqual('0,120.00%');
expect(formatPercent(1.2, 'fr', '4.2')).toEqual('0 120,00 %');
expect(formatPercent(1.2, 'ar', '4.2')).toEqual('0,120.00%');
// see issue #20136
expect(formatPercent(0.12345674, defaultLocale, '0.0-10')).toEqual('12.345674%');
expect(formatPercent(0, defaultLocale, '0.0-10')).toEqual('0%');
expect(formatPercent(0.00, defaultLocale, '0.0-10')).toEqual('0%');
expect(formatPercent(1, defaultLocale, '0.0-10')).toEqual('100%');
expect(formatPercent(0.1, defaultLocale, '0.0-10')).toEqual('10%');
expect(formatPercent(0.12, defaultLocale, '0.0-10')).toEqual('12%');
expect(formatPercent(0.123, defaultLocale, '0.0-10')).toEqual('12.3%');
expect(formatPercent(12.3456, defaultLocale, '0.0-10')).toEqual('1,234.56%');
expect(formatPercent(12.345600, defaultLocale, '0.0-10')).toEqual('1,234.56%');
expect(formatPercent(12.345699999, defaultLocale, '0.0-6')).toEqual('1,234.57%');
expect(formatPercent(12.345699999, defaultLocale, '0.4-6')).toEqual('1,234.5700%');
expect(formatPercent(100, defaultLocale, '0.4-6')).toEqual('10,000.0000%');
expect(formatPercent(100, defaultLocale, '0.0-10')).toEqual('10,000%');
expect(formatPercent(1.5e2, defaultLocale)).toEqual('15,000%');
expect(formatPercent(1e100, defaultLocale)).toEqual('1E+102%');
expect(formatPercent(0.12345674, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('12.345674%');
expect(formatPercent(0, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('0%');
expect(formatPercent(0.00, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('0%');
expect(formatPercent(1, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('100%');
expect(formatPercent(0.1, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('10%');
expect(formatPercent(0.12, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('12%');
expect(formatPercent(0.123, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('12.3%');
expect(formatPercent(12.3456, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('1,234.56%');
expect(formatPercent(12.345600, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('1,234.56%');
expect(formatPercent(12.345699999, DEFAULT_LOCALE_ID, '0.0-6')).toEqual('1,234.57%');
expect(formatPercent(12.345699999, DEFAULT_LOCALE_ID, '0.4-6')).toEqual('1,234.5700%');
expect(formatPercent(100, DEFAULT_LOCALE_ID, '0.4-6')).toEqual('10,000.0000%');
expect(formatPercent(100, DEFAULT_LOCALE_ID, '0.0-10')).toEqual('10,000%');
expect(formatPercent(1.5e2, DEFAULT_LOCALE_ID)).toEqual('15,000%');
expect(formatPercent(1e100, DEFAULT_LOCALE_ID)).toEqual('1E+102%');
});
});
});
@ -80,16 +79,16 @@ describe('Format number', () => {
const defaultCurrencyCode = 'USD';
describe('transform', () => {
it('should return correct value for numbers', () => {
expect(formatCurrency(123, defaultLocale, '$')).toEqual('$123.00');
expect(formatCurrency(12, defaultLocale, 'EUR', 'EUR', '.1')).toEqual('EUR12.0');
expect(
formatCurrency(5.1234, defaultLocale, defaultCurrencyCode, defaultCurrencyCode, '.0-3'))
expect(formatCurrency(123, DEFAULT_LOCALE_ID, '$')).toEqual('$123.00');
expect(formatCurrency(12, DEFAULT_LOCALE_ID, 'EUR', 'EUR', '.1')).toEqual('EUR12.0');
expect(formatCurrency(
5.1234, DEFAULT_LOCALE_ID, defaultCurrencyCode, defaultCurrencyCode, '.0-3'))
.toEqual('USD5.123');
expect(formatCurrency(5.1234, defaultLocale, defaultCurrencyCode)).toEqual('USD5.12');
expect(formatCurrency(5.1234, defaultLocale, '$')).toEqual('$5.12');
expect(formatCurrency(5.1234, defaultLocale, 'CA$')).toEqual('CA$5.12');
expect(formatCurrency(5.1234, defaultLocale, '$')).toEqual('$5.12');
expect(formatCurrency(5.1234, defaultLocale, '$', defaultCurrencyCode, '5.2-2'))
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, defaultCurrencyCode)).toEqual('USD5.12');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, '$')).toEqual('$5.12');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'CA$')).toEqual('CA$5.12');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, '$')).toEqual('$5.12');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, '$', defaultCurrencyCode, '5.2-2'))
.toEqual('$00,005.12');
expect(formatCurrency(5.1234, 'fr', '$', defaultCurrencyCode, '5.2-2'))
.toEqual('00 005,12 $');
@ -98,20 +97,21 @@ describe('Format number', () => {
it('should support any currency code name', () => {
// currency code is unknown, default formatting options will be used
expect(formatCurrency(5.1234, defaultLocale, 'unexisting_ISO_code'))
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'unexisting_ISO_code'))
.toEqual('unexisting_ISO_code5.12');
// currency code is USD, the pipe will format based on USD but will display "Custom name"
expect(formatCurrency(5.1234, defaultLocale, 'Custom name')).toEqual('Custom name5.12');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'Custom name')).toEqual('Custom name5.12');
});
it('should round to the default number of digits if no digitsInfo', () => {
// IDR has a default number of digits of 0
expect(formatCurrency(5.1234, defaultLocale, 'IDR', 'IDR')).toEqual('IDR5');
expect(formatCurrency(5.1234, defaultLocale, 'IDR', 'IDR', '.2')).toEqual('IDR5.12');
expect(formatCurrency(5.1234, defaultLocale, 'Custom name', 'IDR')).toEqual('Custom name5');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'IDR', 'IDR')).toEqual('IDR5');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'IDR', 'IDR', '.2')).toEqual('IDR5.12');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'Custom name', 'IDR'))
.toEqual('Custom name5');
// BHD has a default number of digits of 3
expect(formatCurrency(5.1234, defaultLocale, 'BHD', 'BHD')).toEqual('BHD5.123');
expect(formatCurrency(5.1234, defaultLocale, 'BHD', 'BHD', '.1-2')).toEqual('BHD5.12');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'BHD', 'BHD')).toEqual('BHD5.123');
expect(formatCurrency(5.1234, DEFAULT_LOCALE_ID, 'BHD', 'BHD', '.1-2')).toEqual('BHD5.12');
});
});
});

View File

@ -11,9 +11,28 @@ const shx = require('shelljs');
const os = require('os');
const {runCommand, setupTestDirectory} = require('./test_helpers');
// Nodejs toolchains were included in nodejs rules 0.33.0 so the
// repository name for the nodejs toolchain now depends on the platform
// being run on. The following function returns the nodejs repository
// name of the runtime platform platform. These come from
// https://github.com/bazelbuild/rules_nodejs/blob/2a0be492c5d506665798f04673ab1a646c883626/internal/node/node_repositories.bzl#L598.
function nodejs_repository() {
switch (os.platform()) {
case 'darwin':
return 'nodejs_darwin_amd64';
case 'linux':
return 'nodejs_linux_amd64';
case 'win32':
return 'nodejs_windows_amd64';
default:
throw 'Platform not supported';
}
}
const ngcBin = require.resolve('./ngc_bin');
const xi18nBin = require.resolve('./ng_xi18n');
const nodeBin = require.resolve(`nodejs/bin/node${(os.platform() === 'win32' ? '.cmd' : '')}`);
const nodeBin =
require.resolve(`${nodejs_repository()}/bin/node${(os.platform() === 'win32' ? '.cmd' : '')}`);
const jasmineBin = require.resolve('npm/node_modules/jasmine/bin/jasmine.js');
// Prepare the test directory before building the integration test output. This ensures that

View File

@ -9,10 +9,10 @@
import * as ts from 'typescript';
import {AbsoluteFsPath} from '../../../src/ngtsc/file_system';
import {ClassDeclaration, ClassMember, ClassMemberKind, ClassSymbol, CtorParameter, Declaration, Decorator, Import, TypeScriptReflectionHost, isDecoratorIdentifier, reflectObjectLiteral} from '../../../src/ngtsc/reflection';
import {ClassDeclaration, ClassMember, ClassMemberKind, ClassSymbol, CtorParameter, Declaration, Decorator, TypeScriptReflectionHost, isDecoratorIdentifier, reflectObjectLiteral} from '../../../src/ngtsc/reflection';
import {Logger} from '../logging/logger';
import {BundleProgram} from '../packages/bundle_program';
import {findAll, getNameText, hasNameIdentifier, isDefined} from '../utils';
import {findAll, getNameText, hasNameIdentifier, isDefined, stripDollarSuffix} from '../utils';
import {ModuleWithProvidersFunction, NgccReflectionHost, PRE_R3_MARKER, SwitchableVariableDeclaration, isSwitchableVariableDeclaration} from './ngcc_host';
@ -73,6 +73,14 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
*/
protected aliasedClassDeclarations = new Map<ts.Declaration, ts.Identifier>();
/**
* Caches the information of the decorators on a class, as the work involved with extracting
* decorators is complex and frequently used.
*
* This map is lazily populated during the first call to `acquireDecoratorInfo` for a given class.
*/
protected decoratorCache = new Map<ClassDeclaration, DecoratorInfo>();
constructor(
protected logger: Logger, protected isCore: boolean, checker: ts.TypeChecker,
dts?: BundleProgram|null) {
@ -247,12 +255,8 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
/** Gets all decorators of the given class symbol. */
getDecoratorsOfSymbol(symbol: ClassSymbol): Decorator[]|null {
const decoratorsProperty = this.getStaticProperty(symbol, DECORATORS);
if (decoratorsProperty) {
return this.getClassDecoratorsFromStaticProperty(decoratorsProperty);
} else {
return this.getClassDecoratorsFromHelperCall(symbol);
}
const {classDecorators} = this.acquireDecoratorInfo(symbol);
return classDecorators;
}
/**
@ -542,6 +546,72 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
return symbol.exports && symbol.exports.get(propertyName);
}
/**
* This is the main entry-point for obtaining information on the decorators of a given class. This
* information is computed either from static properties if present, or using `tslib.__decorate`
* helper calls otherwise. The computed result is cached per class.
*
* @param classSymbol the class for which decorators should be acquired.
* @returns all information of the decorators on the class.
*/
protected acquireDecoratorInfo(classSymbol: ClassSymbol): DecoratorInfo {
if (this.decoratorCache.has(classSymbol.valueDeclaration)) {
return this.decoratorCache.get(classSymbol.valueDeclaration) !;
}
// First attempt extracting decorators from static properties.
let decoratorInfo = this.computeDecoratorInfoFromStaticProperties(classSymbol);
if (decoratorInfo === null) {
// If none were present, use the `__decorate` helper calls instead.
decoratorInfo = this.computeDecoratorInfoFromHelperCalls(classSymbol);
}
this.decoratorCache.set(classSymbol.valueDeclaration, decoratorInfo);
return decoratorInfo;
}
/**
* Attempts to compute decorator information from static properties "decorators", "propDecorators"
* and "ctorParameters" on the class. If neither of these static properties is present the
* library is likely not compiled using tsickle for usage with Closure compiler, in which case
* `null` is returned.
*
* @param classSymbol The class symbol to compute the decorators information for.
* @returns All information on the decorators as extracted from static properties, or `null` if
* none of the static properties exist.
*/
protected computeDecoratorInfoFromStaticProperties(classSymbol: ClassSymbol): DecoratorInfo|null {
let classDecorators: Decorator[]|null = null;
let memberDecorators: Map<string, Decorator[]>|null = null;
let constructorParamInfo: ParamInfo[]|null = null;
const decoratorsProperty = this.getStaticProperty(classSymbol, DECORATORS);
if (decoratorsProperty !== undefined) {
classDecorators = this.getClassDecoratorsFromStaticProperty(decoratorsProperty);
}
const propDecoratorsProperty = this.getStaticProperty(classSymbol, PROP_DECORATORS);
if (propDecoratorsProperty !== undefined) {
memberDecorators = this.getMemberDecoratorsFromStaticProperty(propDecoratorsProperty);
}
const constructorParamsProperty = this.getStaticProperty(classSymbol, CONSTRUCTOR_PARAMS);
if (constructorParamsProperty !== undefined) {
constructorParamInfo = this.getParamInfoFromStaticProperty(constructorParamsProperty);
}
// If none of the static properties were present, no decorator info could be computed.
if (classDecorators === null && memberDecorators === null && constructorParamInfo === null) {
return null;
}
return {
classDecorators,
memberDecorators: memberDecorators || new Map<string, Decorator[]>(),
constructorParamInfo: constructorParamInfo || [],
};
}
/**
* Get all class decorators for the given class, where the decorators are declared
* via a static property. For example:
@ -570,32 +640,6 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
return null;
}
/**
* Get all class decorators for the given class, where the decorators are declared
* via the `__decorate` helper method. For example:
*
* ```
* let SomeDirective = class SomeDirective {}
* SomeDirective = __decorate([
* Directive({ selector: '[someDirective]' }),
* ], SomeDirective);
* ```
*
* @param symbol the class whose decorators we want to get.
* @returns an array of decorators or null if none where found.
*/
protected getClassDecoratorsFromHelperCall(symbol: ClassSymbol): Decorator[]|null {
const decorators: Decorator[] = [];
const helperCalls = this.getHelperCallsForClass(symbol, '__decorate');
helperCalls.forEach(helperCall => {
const {classDecorators} =
this.reflectDecoratorsFromHelperCall(helperCall, makeClassTargetFilter(symbol.name));
classDecorators.filter(decorator => this.isFromCore(decorator))
.forEach(decorator => decorators.push(decorator));
});
return decorators.length ? decorators : null;
}
/**
* Examine a symbol which should be of a class, and return metadata about its members.
*
@ -606,7 +650,11 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
const members: ClassMember[] = [];
// The decorators map contains all the properties that are decorated
const decoratorsMap = this.getMemberDecorators(symbol);
const {memberDecorators} = this.acquireDecoratorInfo(symbol);
// Make a copy of the decorators as successfully reflected members delete themselves from the
// map, so that any leftovers can be easily dealt with.
const decoratorsMap = new Map(memberDecorators);
// The member map contains all the method (instance and static); and any instance properties
// that are initialized in the class.
@ -675,21 +723,6 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
return members;
}
/**
* Get all the member decorators for the given class.
* @param classSymbol the class whose member decorators we are interested in.
* @returns a map whose keys are the name of the members and whose values are collections of
* decorators for the given member.
*/
protected getMemberDecorators(classSymbol: ClassSymbol): Map<string, Decorator[]> {
const decoratorsProperty = this.getStaticProperty(classSymbol, PROP_DECORATORS);
if (decoratorsProperty) {
return this.getMemberDecoratorsFromStaticProperty(decoratorsProperty);
} else {
return this.getMemberDecoratorsFromHelperCalls(classSymbol);
}
}
/**
* Member decorators may be declared as static properties of the class:
*
@ -724,7 +757,21 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
}
/**
* Member decorators may be declared via helper call statements.
* For a given class symbol, collects all decorator information from tslib helper methods, as
* generated by TypeScript into emitted JavaScript files.
*
* Class decorators are extracted from calls to `tslib.__decorate` that look as follows:
*
* ```
* let SomeDirective = class SomeDirective {}
* SomeDirective = __decorate([
* Directive({ selector: '[someDirective]' }),
* ], SomeDirective);
* ```
*
* The extraction of member decorators is similar, with the distinction that its 2nd and 3rd
* argument correspond with a "prototype" target and the name of the member to which the
* decorators apply.
*
* ```
* __decorate([
@ -733,102 +780,188 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
* ], SomeDirective.prototype, "input1", void 0);
* ```
*
* @param classSymbol the class whose member decorators we are interested in.
* @returns a map whose keys are the name of the members and whose values are collections of
* decorators for the given member.
* @param classSymbol The class symbol for which decorators should be extracted.
* @returns All information on the decorators of the class.
*/
protected getMemberDecoratorsFromHelperCalls(classSymbol: ClassSymbol): Map<string, Decorator[]> {
const memberDecoratorMap = new Map<string, Decorator[]>();
const helperCalls = this.getHelperCallsForClass(classSymbol, '__decorate');
helperCalls.forEach(helperCall => {
const {memberDecorators} = this.reflectDecoratorsFromHelperCall(
helperCall, makeMemberTargetFilter(classSymbol.name));
memberDecorators.forEach((decorators, memberName) => {
if (memberName) {
const memberDecorators =
memberDecoratorMap.has(memberName) ? memberDecoratorMap.get(memberName) ! : [];
const coreDecorators = decorators.filter(decorator => this.isFromCore(decorator));
memberDecoratorMap.set(memberName, memberDecorators.concat(coreDecorators));
}
});
});
return memberDecoratorMap;
}
/**
* Extract decorator info from `__decorate` helper function calls.
* @param helperCall the call to a helper that may contain decorator calls
* @param targetFilter a function to filter out targets that we are not interested in.
* @returns a mapping from member name to decorators, where the key is either the name of the
* member or `undefined` if it refers to decorators on the class as a whole.
*/
protected reflectDecoratorsFromHelperCall(
helperCall: ts.CallExpression, targetFilter: TargetFilter):
{classDecorators: Decorator[], memberDecorators: Map<string, Decorator[]>} {
const classDecorators: Decorator[] = [];
protected computeDecoratorInfoFromHelperCalls(classSymbol: ClassSymbol): DecoratorInfo {
let classDecorators: Decorator[]|null = null;
const memberDecorators = new Map<string, Decorator[]>();
const constructorParamInfo: ParamInfo[] = [];
// First check that the `target` argument is correct
if (targetFilter(helperCall.arguments[1])) {
// Grab the `decorators` argument which should be an array of calls
const decoratorCalls = helperCall.arguments[0];
if (decoratorCalls && ts.isArrayLiteralExpression(decoratorCalls)) {
decoratorCalls.elements.forEach(element => {
// We only care about those elements that are actual calls
if (ts.isCallExpression(element)) {
const decorator = this.reflectDecoratorCall(element);
if (decorator) {
const keyArg = helperCall.arguments[2];
const keyName = keyArg && ts.isStringLiteral(keyArg) ? keyArg.text : undefined;
if (keyName === undefined) {
classDecorators.push(decorator);
} else {
const decorators =
memberDecorators.has(keyName) ? memberDecorators.get(keyName) ! : [];
decorators.push(decorator);
memberDecorators.set(keyName, decorators);
}
}
const getConstructorParamInfo = (index: number) => {
let param = constructorParamInfo[index];
if (param === undefined) {
param = constructorParamInfo[index] = {decorators: null, typeExpression: null};
}
return param;
};
// All relevant information can be extracted from calls to `__decorate`, obtain these first.
// Note that although the helper calls are retrieved using the class symbol, the result may
// contain helper calls corresponding with unrelated classes. Therefore, each helper call still
// has to be checked to actually correspond with the class symbol.
const helperCalls = this.getHelperCallsForClass(classSymbol, '__decorate');
for (const helperCall of helperCalls) {
if (isClassDecorateCall(helperCall, classSymbol.name)) {
// This `__decorate` call is targeting the class itself.
const helperArgs = helperCall.arguments[0];
for (const element of helperArgs.elements) {
const entry = this.reflectDecorateHelperEntry(element);
if (entry === null) {
continue;
}
});
if (entry.type === 'decorator') {
// The helper arg was reflected to represent an actual decorator
if (this.isFromCore(entry.decorator)) {
(classDecorators || (classDecorators = [])).push(entry.decorator);
}
} else if (entry.type === 'param:decorators') {
// The helper arg represents a decorator for a parameter. Since it's applied to the
// class, it corresponds with a constructor parameter of the class.
const param = getConstructorParamInfo(entry.index);
(param.decorators || (param.decorators = [])).push(entry.decorator);
} else if (entry.type === 'params') {
// The helper arg represents the types of the parameters. Since it's applied to the
// class, it corresponds with the constructor parameters of the class.
entry.types.forEach(
(type, index) => getConstructorParamInfo(index).typeExpression = type);
}
}
} else if (isMemberDecorateCall(helperCall, classSymbol.name)) {
// The `__decorate` call is targeting a member of the class
const helperArgs = helperCall.arguments[0];
const memberName = helperCall.arguments[2].text;
for (const element of helperArgs.elements) {
const entry = this.reflectDecorateHelperEntry(element);
if (entry === null) {
continue;
}
if (entry.type === 'decorator') {
// The helper arg was reflected to represent an actual decorator.
if (this.isFromCore(entry.decorator)) {
const decorators =
memberDecorators.has(memberName) ? memberDecorators.get(memberName) ! : [];
decorators.push(entry.decorator);
memberDecorators.set(memberName, decorators);
}
} else {
// Information on decorated parameters is not interesting for ngcc, so it's ignored.
}
}
}
}
return {classDecorators, memberDecorators};
return {classDecorators, memberDecorators, constructorParamInfo};
}
/**
* Extract the decorator information from a call to a decorator as a function.
* This happens when the decorators has been used in a `__decorate` helper call.
* For example:
* Extract the details of an entry within a `__decorate` helper call. For example, given the
* following code:
*
* ```
* __decorate([
* Directive({ selector: '[someDirective]' }),
* tslib_1.__param(2, Inject(INJECTED_TOKEN)),
* tslib_1.__metadata("design:paramtypes", [ViewContainerRef, TemplateRef, String])
* ], SomeDirective);
* ```
*
* Here the `Directive` decorator is decorating `SomeDirective` and the options for
* the decorator are passed as arguments to the `Directive()` call.
* it can be seen that there are calls to regular decorators (the `Directive`) and calls into
* `tslib` functions which have been inserted by TypeScript. Therefore, this function classifies
* a call to correspond with
* 1. a real decorator like `Directive` above, or
* 2. a decorated parameter, corresponding with `__param` calls from `tslib`, or
* 3. the type information of parameters, corresponding with `__metadata` call from `tslib`
*
* @param call the call to the decorator.
* @returns a decorator containing the reflected information, or null if the call
* is not a valid decorator call.
* @param expression the expression that needs to be reflected into a `DecorateHelperEntry`
* @returns an object that indicates which of the three categories the call represents, together
* with the reflected information of the call, or null if the call is not a valid decorate call.
*/
protected reflectDecoratorCall(call: ts.CallExpression): Decorator|null {
const decoratorExpression = call.expression;
if (isDecoratorIdentifier(decoratorExpression)) {
// We found a decorator!
const decoratorIdentifier =
ts.isIdentifier(decoratorExpression) ? decoratorExpression : decoratorExpression.name;
protected reflectDecorateHelperEntry(expression: ts.Expression): DecorateHelperEntry|null {
// We only care about those elements that are actual calls
if (!ts.isCallExpression(expression)) {
return null;
}
const call = expression;
const helperName = getCalleeName(call);
if (helperName === '__metadata') {
// This is a `tslib.__metadata` call, reflect to arguments into a `ParameterTypes` object
// if the metadata key is "design:paramtypes".
const key = call.arguments[0];
if (key === undefined || !ts.isStringLiteral(key) || key.text !== 'design:paramtypes') {
return null;
}
const value = call.arguments[1];
if (value === undefined || !ts.isArrayLiteralExpression(value)) {
return null;
}
return {
name: decoratorIdentifier.text,
identifier: decoratorIdentifier,
import: this.getImportOfIdentifier(decoratorIdentifier),
node: call,
args: Array.from(call.arguments)
type: 'params',
types: Array.from(value.elements),
};
}
return null;
if (helperName === '__param') {
// This is a `tslib.__param` call that is reflected into a `ParameterDecorators` object.
const indexArg = call.arguments[0];
const index = indexArg && ts.isNumericLiteral(indexArg) ? parseInt(indexArg.text, 10) : NaN;
if (isNaN(index)) {
return null;
}
const decoratorCall = call.arguments[1];
if (decoratorCall === undefined || !ts.isCallExpression(decoratorCall)) {
return null;
}
const decorator = this.reflectDecoratorCall(decoratorCall);
if (decorator === null) {
return null;
}
return {
type: 'param:decorators',
index,
decorator,
};
}
// Otherwise attempt to reflect it as a regular decorator.
const decorator = this.reflectDecoratorCall(call);
if (decorator === null) {
return null;
}
return {
type: 'decorator',
decorator,
};
}
protected reflectDecoratorCall(call: ts.CallExpression): Decorator|null {
const decoratorExpression = call.expression;
if (!isDecoratorIdentifier(decoratorExpression)) {
return null;
}
// We found a decorator!
const decoratorIdentifier =
ts.isIdentifier(decoratorExpression) ? decoratorExpression : decoratorExpression.name;
return {
name: decoratorIdentifier.text,
identifier: decoratorExpression,
import: this.getImportOfIdentifier(decoratorIdentifier),
node: call,
args: Array.from(call.arguments),
};
}
/**
@ -1070,14 +1203,11 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
*/
protected getConstructorParamInfo(
classSymbol: ClassSymbol, parameterNodes: ts.ParameterDeclaration[]): CtorParameter[] {
const paramsProperty = this.getStaticProperty(classSymbol, CONSTRUCTOR_PARAMS);
const paramInfo: ParamInfo[]|null = paramsProperty ?
this.getParamInfoFromStaticProperty(paramsProperty) :
this.getParamInfoFromHelperCall(classSymbol, parameterNodes);
const {constructorParamInfo} = this.acquireDecoratorInfo(classSymbol);
return parameterNodes.map((node, index) => {
const {decorators, typeExpression} = paramInfo && paramInfo[index] ?
paramInfo[index] :
const {decorators, typeExpression} = constructorParamInfo[index] ?
constructorParamInfo[index] :
{decorators: null, typeExpression: null};
const nameNode = node.name;
return {
@ -1153,58 +1283,6 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
return null;
}
/**
* Get the parameter type and decorators for a class where the information is stored via
* calls to `__decorate` helpers.
*
* Reflect over the helpers to find the decorators and types about each of
* the class's constructor parameters.
*
* @param classSymbol the class whose parameter info we want to get.
* @param parameterNodes the array of TypeScript parameter nodes for this class's constructor.
* @returns an array of objects containing the type and decorators for each parameter.
*/
protected getParamInfoFromHelperCall(
classSymbol: ClassSymbol, parameterNodes: ts.ParameterDeclaration[]): ParamInfo[] {
const parameters: ParamInfo[] =
parameterNodes.map(() => ({typeExpression: null, decorators: null}));
const helperCalls = this.getHelperCallsForClass(classSymbol, '__decorate');
helperCalls.forEach(helperCall => {
const {classDecorators} =
this.reflectDecoratorsFromHelperCall(helperCall, makeClassTargetFilter(classSymbol.name));
classDecorators.forEach(call => {
switch (call.name) {
case '__metadata':
const metadataArg = call.args && call.args[0];
const typesArg = call.args && call.args[1];
const isParamTypeDecorator = metadataArg && ts.isStringLiteral(metadataArg) &&
metadataArg.text === 'design:paramtypes';
const types = typesArg && ts.isArrayLiteralExpression(typesArg) && typesArg.elements;
if (isParamTypeDecorator && types) {
types.forEach((type, index) => parameters[index].typeExpression = type);
}
break;
case '__param':
const paramIndexArg = call.args && call.args[0];
const decoratorCallArg = call.args && call.args[1];
const paramIndex = paramIndexArg && ts.isNumericLiteral(paramIndexArg) ?
parseInt(paramIndexArg.text, 10) :
NaN;
const decorator = decoratorCallArg && ts.isCallExpression(decoratorCallArg) ?
this.reflectDecoratorCall(decoratorCallArg) :
null;
if (!isNaN(paramIndex) && decorator) {
const decorators = parameters[paramIndex].decorators =
parameters[paramIndex].decorators || [];
decorators.push(decorator);
}
break;
}
});
});
return parameters;
}
/**
* Search statements related to the given class for calls to the specified helper.
* @param classSymbol the class whose helper calls we are interested in.
@ -1377,6 +1455,72 @@ export type ParamInfo = {
typeExpression: ts.Expression | null
};
/**
* Represents a call to `tslib.__metadata` as present in `tslib.__decorate` calls. This is a
* synthetic decorator inserted by TypeScript that contains reflection information about the
* target of the decorator, i.e. the class or property.
*/
export interface ParameterTypes {
type: 'params';
types: ts.Expression[];
}
/**
* Represents a call to `tslib.__param` as present in `tslib.__decorate` calls. This contains
* information on any decorators were applied to a certain parameter.
*/
export interface ParameterDecorators {
type: 'param:decorators';
index: number;
decorator: Decorator;
}
/**
* Represents a call to a decorator as it was present in the original source code, as present in
* `tslib.__decorate` calls.
*/
export interface DecoratorCall {
type: 'decorator';
decorator: Decorator;
}
/**
* Represents the different kinds of decorate helpers that may be present as first argument to
* `tslib.__decorate`, as follows:
*
* ```
* __decorate([
* Directive({ selector: '[someDirective]' }),
* tslib_1.__param(2, Inject(INJECTED_TOKEN)),
* tslib_1.__metadata("design:paramtypes", [ViewContainerRef, TemplateRef, String])
* ], SomeDirective);
* ```
*/
export type DecorateHelperEntry = ParameterTypes | ParameterDecorators | DecoratorCall;
/**
* The recorded decorator information of a single class. This information is cached in the host.
*/
interface DecoratorInfo {
/**
* All decorators that were present on the class. If no decorators were present, this is `null`
*/
classDecorators: Decorator[]|null;
/**
* All decorators per member of the class they were present on.
*/
memberDecorators: Map<string, Decorator[]>;
/**
* Represents the constructor parameter information, such as the type of a parameter and all
* decorators for a certain parameter. Indices in this array correspond with the parameter's index
* in the constructor. Note that this array may be sparse, i.e. certain constructor parameters may
* not have any info recorded.
*/
constructorParamInfo: ParamInfo[];
}
/**
* A statement node that represents an assignment.
*/
@ -1397,27 +1541,55 @@ export function isAssignment(node: ts.Node): node is ts.AssignmentExpression<ts.
}
/**
* The type of a function that can be used to filter out helpers based on their target.
* This is used in `reflectDecoratorsFromHelperCall()`.
* Tests whether the provided call expression targets a class, by verifying its arguments are
* according to the following form:
*
* ```
* __decorate([], SomeDirective);
* ```
*
* @param call the call expression that is tested to represent a class decorator call.
* @param className the name of the class that the call needs to correspond with.
*/
export type TargetFilter = (target: ts.Expression) => boolean;
export function isClassDecorateCall(call: ts.CallExpression, className: string):
call is ts.CallExpression&{arguments: [ts.ArrayLiteralExpression, ts.Expression]} {
const helperArgs = call.arguments[0];
if (helperArgs === undefined || !ts.isArrayLiteralExpression(helperArgs)) {
return false;
}
/**
* Creates a function that tests whether the given expression is a class target.
* @param className the name of the class we want to target.
*/
export function makeClassTargetFilter(className: string): TargetFilter {
return (target: ts.Expression): boolean => ts.isIdentifier(target) && target.text === className;
const target = call.arguments[1];
return target !== undefined && ts.isIdentifier(target) && target.text === className;
}
/**
* Creates a function that tests whether the given expression is a class member target.
* @param className the name of the class we want to target.
* Tests whether the provided call expression targets a member of the class, by verifying its
* arguments are according to the following form:
*
* ```
* __decorate([], SomeDirective.prototype, "member", void 0);
* ```
*
* @param call the call expression that is tested to represent a member decorator call.
* @param className the name of the class that the call needs to correspond with.
*/
export function makeMemberTargetFilter(className: string): TargetFilter {
return (target: ts.Expression): boolean => ts.isPropertyAccessExpression(target) &&
ts.isIdentifier(target.expression) && target.expression.text === className &&
target.name.text === 'prototype';
export function isMemberDecorateCall(call: ts.CallExpression, className: string):
call is ts.CallExpression&
{arguments: [ts.ArrayLiteralExpression, ts.StringLiteral, ts.StringLiteral]} {
const helperArgs = call.arguments[0];
if (helperArgs === undefined || !ts.isArrayLiteralExpression(helperArgs)) {
return false;
}
const target = call.arguments[1];
if (target === undefined || !ts.isPropertyAccessExpression(target) ||
!ts.isIdentifier(target.expression) || target.expression.text !== className ||
target.name.text !== 'prototype') {
return false;
}
const memberName = call.arguments[2];
return memberName !== undefined && ts.isStringLiteral(memberName);
}
/**
@ -1435,10 +1607,10 @@ export function getPropertyValueFromSymbol(propSymbol: ts.Symbol): ts.Expression
*/
function getCalleeName(call: ts.CallExpression): string|null {
if (ts.isIdentifier(call.expression)) {
return call.expression.text;
return stripDollarSuffix(call.expression.text);
}
if (ts.isPropertyAccessExpression(call.expression)) {
return call.expression.name.text;
return stripDollarSuffix(call.expression.name.text);
}
return null;
}

View File

@ -10,7 +10,7 @@ import * as ts from 'typescript';
import {ClassDeclaration, ClassMember, ClassMemberKind, ClassSymbol, CtorParameter, Declaration, Decorator, FunctionDefinition, Parameter, TsHelperFn, isNamedVariableDeclaration, reflectObjectLiteral} from '../../../src/ngtsc/reflection';
import {isFromDtsFile} from '../../../src/ngtsc/util/src/typescript';
import {getNameText, hasNameIdentifier} from '../utils';
import {getNameText, hasNameIdentifier, stripDollarSuffix} from '../utils';
import {Esm2015ReflectionHost, ParamInfo, getPropertyValueFromSymbol, isAssignmentStatement} from './esm2015_host';
@ -659,7 +659,9 @@ function reflectArrayElement(element: ts.Expression) {
* helper.
*/
function getTsHelperFn(node: ts.NamedDeclaration): TsHelperFn|null {
const name = node.name !== undefined && ts.isIdentifier(node.name) && node.name.text;
const name = node.name !== undefined && ts.isIdentifier(node.name) ?
stripDollarSuffix(node.name.text) :
null;
if (name === '__spread') {
return TsHelperFn.Spread;

View File

@ -82,3 +82,14 @@ export function resolveFileWithPostfixes(
}
return null;
}
/**
* An identifier may become repeated when bundling multiple source files into a single bundle, so
* bundlers have a strategy of suffixing non-unique identifiers with a suffix like $2. This function
* strips off such suffixes, so that ngcc deals with the canonical name of an identifier.
* @param value The value to strip any suffix of, if applicable.
* @returns The canonical representation of the value, without any suffix.
*/
export function stripDollarSuffix(value: string): string {
return value.replace(/\$\d+$/, '');
}

View File

@ -78,6 +78,22 @@ export function convertToDirectTsLibImport(filesystem: TestFile[]) {
});
}
export function convertToInlineTsLib(filesystem: TestFile[], suffix: string = '') {
return filesystem.map(file => {
const contents = file.contents
.replace(`import * as tslib_1 from 'tslib';`, `
var __decorate${suffix} = null;
var __metadata${suffix} = null;
var __read${suffix} = null;
var __values${suffix} = null;
var __param${suffix} = null;
var __extends${suffix} = null;
var __assign${suffix} = null;
`).replace(/tslib_1\.([_a-z]+)/gi, '$1' + suffix.replace('$', '$$'));
return {...file, contents};
});
}
export function getRootFiles(testFiles: TestFile[]): AbsoluteFsPath[] {
return testFiles.filter(f => f.isRoot !== false).map(f => absoluteFrom(f.name));
}

View File

@ -86,6 +86,7 @@ exports.OtherDirective = OtherDirective;
const decorator = decorators[0];
expect(decorator.name).toEqual('Directive');
expect(decorator.identifier.getText()).toEqual('core.Directive');
expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'});
expect(decorator.args !.map(arg => arg.getText())).toEqual([
'{ selector: \'[someDirective]\' }',

View File

@ -951,23 +951,6 @@ exports.ExternalModule = ExternalModule;
expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'}));
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
loadTestFiles([SOME_DIRECTIVE_FILE]);
const {program, host: compilerHost} = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name);
const host = new CommonJsReflectionHost(new MockLogger(), false, program, compilerHost);
const mockImportInfo: Import = {from: '@angular/core', name: 'Directive'};
const spy = spyOn(host, 'getImportOfIdentifier').and.returnValue(mockImportInfo);
const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration);
const decorators = host.getDecoratorsOfDeclaration(classNode) !;
expect(decorators.length).toEqual(1);
expect(decorators[0].import).toBe(mockImportInfo);
const typeIdentifier = spy.calls.mostRecent().args[0] as ts.Identifier;
expect(typeIdentifier.text).toBe('Directive');
});
describe('(returned decorators `args`)', () => {
it('should be an empty array if decorator has no `args` property', () => {
loadTestFiles([INVALID_DECORATOR_ARGS_FILE]);
@ -1185,22 +1168,17 @@ exports.ExternalModule = ExternalModule;
expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'}));
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
it('should have import information on decorators', () => {
loadTestFiles([SOME_DIRECTIVE_FILE]);
const {program, host: compilerHost} = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name);
const host = new CommonJsReflectionHost(new MockLogger(), false, program, compilerHost);
const mockImportInfo = { name: 'mock', from: '@angular/core' } as Import;
const spy = spyOn(host, 'getImportOfIdentifier').and.returnValue(mockImportInfo);
const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration);
const decorators = host.getDecoratorsOfDeclaration(classNode) !;
expect(decorators.length).toEqual(1);
expect(decorators[0].import).toBe(mockImportInfo);
const typeIdentifier = spy.calls.mostRecent().args[0] as ts.Identifier;
expect(typeIdentifier.text).toBe('Directive');
expect(decorators[0].import).toEqual({name: 'Directive', from: '@angular/core'});
});
describe('(returned prop decorators `args`)', () => {
@ -1430,24 +1408,19 @@ exports.ExternalModule = ExternalModule;
expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Inject'}));
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
it('should have import information on decorators', () => {
loadTestFiles([SOME_DIRECTIVE_FILE]);
const {program, host: compilerHost} = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name);
const host = new CommonJsReflectionHost(new MockLogger(), false, program, compilerHost);
const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration);
const mockImportInfo: Import = {from: '@angular/core', name: 'Directive'};
const spy = spyOn(CommonJsReflectionHost.prototype, 'getImportOfIdentifier')
.and.returnValue(mockImportInfo);
const parameters = host.getConstructorParameters(classNode);
const decorators = parameters ![2].decorators !;
expect(decorators.length).toEqual(1);
expect(decorators[0].import).toBe(mockImportInfo);
const typeIdentifier = spy.calls.mostRecent().args[0] as ts.Identifier;
expect(typeIdentifier.text).toBe('Inject');
expect(decorators[0].name).toBe('Inject');
expect(decorators[0].import).toEqual({name: 'Inject', from: '@angular/core'});
});
});

View File

@ -15,7 +15,7 @@ import {getDeclaration} from '../../../src/ngtsc/testing';
import {loadFakeCore, loadTestFiles, loadTsLib} from '../../../test/helpers';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {MockLogger} from '../helpers/mock_logger';
import {convertToDirectTsLibImport, makeTestBundleProgram} from '../helpers/utils';
import {convertToDirectTsLibImport, convertToInlineTsLib, makeTestBundleProgram} from '../helpers/utils';
import {expectTypeValueReferencesForParameters} from './util';
@ -111,14 +111,18 @@ runInEachFileSystem(() => {
];
const DIRECT_IMPORT_FILES = convertToDirectTsLibImport(NAMESPACED_IMPORT_FILES);
const INLINE_FILES = convertToInlineTsLib(NAMESPACED_IMPORT_FILES);
const INLINE_SUFFIXED_FILES = convertToInlineTsLib(NAMESPACED_IMPORT_FILES, '$2');
FILES = {
'namespaced': NAMESPACED_IMPORT_FILES,
'direct import': DIRECT_IMPORT_FILES,
'inline': INLINE_FILES,
'inline suffixed': INLINE_SUFFIXED_FILES,
};
});
['namespaced', 'direct import'].forEach(label => {
['namespaced', 'direct import', 'inline', 'inline suffixed'].forEach(label => {
describe(`[${label}]`, () => {
beforeEach(() => {
const fs = getFileSystem();
@ -141,35 +145,13 @@ runInEachFileSystem(() => {
const decorator = decorators[0];
expect(decorator.name).toEqual('Directive');
expect(decorator.identifier.getText()).toEqual('Directive');
expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'});
expect(decorator.args !.map(arg => arg.getText())).toEqual([
'{ selector: \'[someDirective]\' }',
]);
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
const spy =
spyOn(Esm2015ReflectionHost.prototype, 'getImportOfIdentifier')
.and.callFake(
(identifier: ts.Identifier) => identifier.getText() === 'Directive' ?
{from: '@angular/core', name: 'Directive'} :
{});
const {program} = makeTestBundleProgram(_('/some_directive.js'));
const host =
new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker());
const classNode = getDeclaration(
program, _('/some_directive.js'), 'SomeDirective', isNamedVariableDeclaration);
const decorators = host.getDecoratorsOfDeclaration(classNode) !;
expect(decorators.length).toEqual(1);
expect(decorators[0].import).toEqual({from: '@angular/core', name: 'Directive'});
const identifiers = spy.calls.all().map(call => (call.args[0] as ts.Identifier).text);
expect(identifiers.some(identifier => identifier === 'Directive')).toBeTruthy();
});
it('should support decorators being used inside @angular/core', () => {
const {program} =
makeTestBundleProgram(_('/node_modules/@angular/core/some_directive.js'));
@ -185,6 +167,7 @@ runInEachFileSystem(() => {
const decorator = decorators[0];
expect(decorator.name).toEqual('Directive');
expect(decorator.identifier.getText()).toEqual('Directive');
expect(decorator.import).toEqual({name: 'Directive', from: './directives'});
expect(decorator.args !.map(arg => arg.getText())).toEqual([
'{ selector: \'[someDirective]\' }',
@ -272,21 +255,6 @@ runInEachFileSystem(() => {
expect(staticProperty.value !.getText()).toEqual(`'static'`);
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
const spy =
spyOn(Esm2015ReflectionHost.prototype, 'getImportOfIdentifier').and.returnValue({});
const {program} = makeTestBundleProgram(_('/some_directive.js'));
const host =
new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker());
const classNode = getDeclaration(
program, _('/some_directive.js'), 'SomeDirective', isNamedVariableDeclaration);
host.getMembersOfClass(classNode);
const identifiers = spy.calls.all().map(call => (call.args[0] as ts.Identifier).text);
expect(identifiers.some(identifier => identifier === 'Input')).toBeTruthy();
});
it('should support decorators being used inside @angular/core', () => {
const {program} =
makeTestBundleProgram(_('/node_modules/@angular/core/some_directive.js'));

View File

@ -763,11 +763,7 @@ runInEachFileSystem(() => {
expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'}));
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
const mockImportInfo = { from: '@angular/core' } as Import;
const spy = spyOn(Esm2015ReflectionHost.prototype, 'getImportOfIdentifier')
.and.returnValue(mockImportInfo);
it('should have import information on decorators', () => {
loadTestFiles([SOME_DIRECTIVE_FILE]);
const {program} = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name);
const host = new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker());
@ -776,10 +772,7 @@ runInEachFileSystem(() => {
const decorators = host.getDecoratorsOfDeclaration(classNode) !;
expect(decorators.length).toEqual(1);
expect(decorators[0].import).toBe(mockImportInfo);
const typeIdentifier = spy.calls.mostRecent().args[0] as ts.Identifier;
expect(typeIdentifier.text).toBe('Directive');
expect(decorators[0].import).toEqual({name: 'Directive', from: '@angular/core'});
});
describe('(returned decorators `args`)', () => {
@ -839,11 +832,13 @@ runInEachFileSystem(() => {
expect(input1.kind).toEqual(ClassMemberKind.Property);
expect(input1.isStatic).toEqual(false);
expect(input1.decorators !.map(d => d.name)).toEqual(['Input']);
expect(input1.decorators ![0].import).toEqual({name: 'Input', from: '@angular/core'});
const input2 = members.find(member => member.name === 'input2') !;
expect(input2.kind).toEqual(ClassMemberKind.Property);
expect(input2.isStatic).toEqual(false);
expect(input1.decorators !.map(d => d.name)).toEqual(['Input']);
expect(input2.decorators !.map(d => d.name)).toEqual(['Input']);
expect(input2.decorators ![0].import).toEqual({name: 'Input', from: '@angular/core'});
});
it('should find non decorated properties on a class', () => {
@ -991,35 +986,6 @@ runInEachFileSystem(() => {
expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Input'}));
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
let callCount = 0;
const spy =
spyOn(Esm2015ReflectionHost.prototype, 'getImportOfIdentifier').and.callFake(() => {
callCount++;
return {name: `name${callCount}`, from: '@angular/core'};
});
loadTestFiles([SOME_DIRECTIVE_FILE]);
const {program} = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name);
const host = new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker());
const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedClassDeclaration);
const members = host.getMembersOfClass(classNode);
expect(spy).toHaveBeenCalled();
expect(spy.calls.allArgs().map(arg => arg[0].getText())).toEqual([
'Input',
'Input',
'HostBinding',
'Input',
'HostListener',
]);
const member = members.find(member => member.name === 'input1') !;
expect(member.decorators !.length).toBe(1);
expect(member.decorators ![0].import).toEqual({name: 'name1', from: '@angular/core'});
});
describe('(returned prop decorators `args`)', () => {
it('should be an empty array if prop decorator has no `args` property', () => {
loadTestFiles([INVALID_PROP_DECORATOR_ARGS_FILE]);
@ -1311,11 +1277,7 @@ runInEachFileSystem(() => {
expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Inject'}));
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
const mockImportInfo: Import = {name: 'mock', from: '@angular/core'};
const spy = spyOn(Esm2015ReflectionHost.prototype, 'getImportOfIdentifier')
.and.returnValue(mockImportInfo);
it('should have import information on decorators', () => {
loadTestFiles([SOME_DIRECTIVE_FILE]);
const {program} = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name);
const host = new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker());
@ -1325,10 +1287,7 @@ runInEachFileSystem(() => {
const decorators = parameters[2].decorators !;
expect(decorators.length).toEqual(1);
expect(decorators[0].import).toBe(mockImportInfo);
const typeIdentifier = spy.calls.mostRecent().args[0] as ts.Identifier;
expect(typeIdentifier.text).toBe('Inject');
expect(decorators[0].import).toEqual({name: 'Inject', from: '@angular/core'});
});
});

View File

@ -14,7 +14,7 @@ import {getDeclaration} from '../../../src/ngtsc/testing';
import {loadFakeCore, loadTestFiles, loadTsLib} from '../../../test/helpers';
import {Esm5ReflectionHost} from '../../src/host/esm5_host';
import {MockLogger} from '../helpers/mock_logger';
import {convertToDirectTsLibImport, makeTestBundleProgram} from '../helpers/utils';
import {convertToDirectTsLibImport, convertToInlineTsLib, makeTestBundleProgram} from '../helpers/utils';
import {expectTypeValueReferencesForParameters} from './util';
@ -132,14 +132,18 @@ export { SomeDirective };
];
const DIRECT_IMPORT_FILES = convertToDirectTsLibImport(NAMESPACED_IMPORT_FILES);
const INLINE_FILES = convertToInlineTsLib(NAMESPACED_IMPORT_FILES);
const INLINE_SUFFIXED_FILES = convertToInlineTsLib(NAMESPACED_IMPORT_FILES, '$2');
FILES = {
'namespaced': NAMESPACED_IMPORT_FILES,
'direct import': DIRECT_IMPORT_FILES,
'inline': INLINE_FILES,
'inline suffixed': INLINE_SUFFIXED_FILES,
};
});
['namespaced', 'direct import'].forEach(label => {
['namespaced', 'direct import', 'inline', 'inline suffixed'].forEach(label => {
describe(`[${label}]`, () => {
beforeEach(() => {
const fs = getFileSystem();
@ -161,34 +165,13 @@ export { SomeDirective };
const decorator = decorators[0];
expect(decorator.name).toEqual('Directive');
expect(decorator.identifier.getText()).toEqual('Directive');
expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'});
expect(decorator.args !.map(arg => arg.getText())).toEqual([
'{ selector: \'[someDirective]\' }',
]);
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
const spy =
spyOn(Esm5ReflectionHost.prototype, 'getImportOfIdentifier')
.and.callFake(
(identifier: ts.Identifier) => identifier.getText() === 'Directive' ?
{from: '@angular/core', name: 'Directive'} :
{});
const {program} = makeTestBundleProgram(_('/some_directive.js'));
const host = new Esm5ReflectionHost(new MockLogger(), false, program.getTypeChecker());
const classNode = getDeclaration(
program, _('/some_directive.js'), 'SomeDirective', isNamedVariableDeclaration);
const decorators = host.getDecoratorsOfDeclaration(classNode) !;
expect(decorators.length).toEqual(1);
expect(decorators[0].import).toEqual({from: '@angular/core', name: 'Directive'});
const identifiers = spy.calls.all().map(call => (call.args[0] as ts.Identifier).text);
expect(identifiers.some(identifier => identifier === 'Directive')).toBeTruthy();
});
it('should support decorators being used inside @angular/core', () => {
const {program} =
makeTestBundleProgram(_('/node_modules/@angular/core/some_directive.js'));
@ -203,6 +186,7 @@ export { SomeDirective };
const decorator = decorators[0];
expect(decorator.name).toEqual('Directive');
expect(decorator.identifier.getText()).toEqual('Directive');
expect(decorator.import).toEqual({name: 'Directive', from: './directives'});
expect(decorator.args !.map(arg => arg.getText())).toEqual([
'{ selector: \'[someDirective]\' }',
@ -270,20 +254,6 @@ export { SomeDirective };
expect(staticProperty.value !.getText()).toEqual(`'static'`);
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
const spy =
spyOn(Esm5ReflectionHost.prototype, 'getImportOfIdentifier').and.returnValue({});
const {program} = makeTestBundleProgram(_('/some_directive.js'));
const host = new Esm5ReflectionHost(new MockLogger(), false, program.getTypeChecker());
const classNode = getDeclaration(
program, _('/some_directive.js'), 'SomeDirective', isNamedVariableDeclaration);
host.getMembersOfClass(classNode);
const identifiers = spy.calls.all().map(call => (call.args[0] as ts.Identifier).text);
expect(identifiers.some(identifier => identifier === 'Input')).toBeTruthy();
});
it('should support decorators being used inside @angular/core', () => {
const {program} =
makeTestBundleProgram(_('/node_modules/@angular/core/some_directive.js'));
@ -319,12 +289,7 @@ export { SomeDirective };
});
describe('(returned parameters `decorators`)', () => {
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
const mockImportInfo = {} as Import;
const spy = spyOn(Esm5ReflectionHost.prototype, 'getImportOfIdentifier')
.and.returnValue(mockImportInfo);
it('should have import information on decorators', () => {
const {program} = makeTestBundleProgram(_('/some_directive.js'));
const host =
new Esm5ReflectionHost(new MockLogger(), false, program.getTypeChecker());
@ -334,10 +299,7 @@ export { SomeDirective };
const decorators = parameters ![2].decorators !;
expect(decorators.length).toEqual(1);
expect(decorators[0].import).toBe(mockImportInfo);
const typeIdentifier = spy.calls.mostRecent().args[0] as ts.Identifier;
expect(typeIdentifier.text).toBe('Inject');
expect(decorators[0].import).toEqual({name: 'Inject', from: '@angular/core'});
});
});
});

View File

@ -942,11 +942,7 @@ runInEachFileSystem(() => {
expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'}));
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
const mockImportInfo = { name: 'mock', from: '@angular/core' } as Import;
const spy = spyOn(Esm5ReflectionHost.prototype, 'getImportOfIdentifier')
.and.returnValue(mockImportInfo);
it('should have import information on decorators', () => {
loadTestFiles([SOME_DIRECTIVE_FILE]);
const {program} = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name);
const host = new Esm5ReflectionHost(new MockLogger(), false, program.getTypeChecker());
@ -955,10 +951,7 @@ runInEachFileSystem(() => {
const decorators = host.getDecoratorsOfDeclaration(classNode) !;
expect(decorators.length).toEqual(1);
expect(decorators[0].import).toBe(mockImportInfo);
const typeIdentifier = spy.calls.mostRecent().args[0] as ts.Identifier;
expect(typeIdentifier.text).toBe('Directive');
expect(decorators[0].import).toEqual({name: 'Directive', from: '@angular/core'});
});
describe('(returned decorators `args`)', () => {
@ -1019,11 +1012,13 @@ runInEachFileSystem(() => {
expect(input1.kind).toEqual(ClassMemberKind.Property);
expect(input1.isStatic).toEqual(false);
expect(input1.decorators !.map(d => d.name)).toEqual(['Input']);
expect(input1.decorators ![0].import).toEqual({name: 'Input', from: '@angular/core'});
const input2 = members.find(member => member.name === 'input2') !;
expect(input2.kind).toEqual(ClassMemberKind.Property);
expect(input2.isStatic).toEqual(false);
expect(input2.decorators !.map(d => d.name)).toEqual(['Input']);
expect(input2.decorators ![0].import).toEqual({name: 'Input', from: '@angular/core'});
});
it('should find decorated members on a class', () => {
@ -1232,30 +1227,6 @@ runInEachFileSystem(() => {
expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Input'}));
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
let callCount = 0;
const spy =
spyOn(Esm5ReflectionHost.prototype, 'getImportOfIdentifier').and.callFake(() => {
callCount++;
return {name: `name${callCount}`, from: `@angular/core`};
});
loadTestFiles([SOME_DIRECTIVE_FILE]);
const {program} = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name);
const host = new Esm5ReflectionHost(new MockLogger(), false, program.getTypeChecker());
const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration);
const members = host.getMembersOfClass(classNode);
expect(spy).toHaveBeenCalled();
spy.calls.allArgs().forEach(arg => expect(arg[0].getText()).toEqual('Input'));
const index = members.findIndex(member => member.name === 'input1');
expect(members[index].decorators !.length).toBe(1);
expect(members[index].decorators ![0].import)
.toEqual({name: 'name1', from: '@angular/core'});
});
describe('(returned prop decorators `args`)', () => {
it('should be an empty array if prop decorator has no `args` property', () => {
loadTestFiles([INVALID_PROP_DECORATOR_ARGS_FILE]);
@ -1466,11 +1437,7 @@ runInEachFileSystem(() => {
expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Inject'}));
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
const mockImportInfo = { name: 'mock', from: '@angulare/core' } as Import;
const spy = spyOn(Esm5ReflectionHost.prototype, 'getImportOfIdentifier')
.and.returnValue(mockImportInfo);
it('should have import information on decorators', () => {
loadTestFiles([SOME_DIRECTIVE_FILE]);
const {program} = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name);
const host = new Esm5ReflectionHost(new MockLogger(), false, program.getTypeChecker());
@ -1480,10 +1447,7 @@ runInEachFileSystem(() => {
const decorators = parameters ![2].decorators !;
expect(decorators.length).toEqual(1);
expect(decorators[0].import).toBe(mockImportInfo);
const typeIdentifier = spy.calls.mostRecent().args[0] as ts.Identifier;
expect(typeIdentifier.text).toBe('Inject');
expect(decorators[0].import).toEqual({name: 'Inject', from: '@angular/core'});
});
});
@ -1705,6 +1669,30 @@ runInEachFileSystem(() => {
expect(definition.helper).toBe(TsHelperFn.Spread);
expect(definition.parameters.length).toEqual(0);
});
it('should recognize TypeScript __spread helper function implementation when suffixed',
() => {
const file: TestFile = {
name: _('/implementation.js'),
contents: `
var __spread$2 = (this && this.__spread$2) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};`,
};
loadTestFiles([file]);
const {program} = makeTestBundleProgram(file.name);
const host = new Esm5ReflectionHost(new MockLogger(), false, program.getTypeChecker());
const node =
getDeclaration(program, file.name, '__spread$2', ts.isVariableDeclaration) !;
const definition = host.getDefinitionOfFunction(node) !;
expect(definition.node).toBe(node);
expect(definition.body).toBeNull();
expect(definition.helper).toBe(TsHelperFn.Spread);
expect(definition.parameters.length).toEqual(0);
});
});
describe('getImportOfIdentifier()', () => {

View File

@ -0,0 +1,132 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {absoluteFrom} from '../../../src/ngtsc/file_system';
import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
import {ClassMemberKind, isNamedVariableDeclaration} from '../../../src/ngtsc/reflection';
import {getDeclaration} from '../../../src/ngtsc/testing';
import {loadTestFiles} from '../../../test/helpers';
import {UmdReflectionHost} from '../../src/host/umd_host';
import {MockLogger} from '../helpers/mock_logger';
import {makeTestBundleProgram} from '../helpers/utils';
import {expectTypeValueReferencesForParameters} from './util';
runInEachFileSystem(() => {
describe('UmdReflectionHost [import helper style]', () => {
let _: typeof absoluteFrom;
let SOME_DIRECTIVE_FILE: TestFile;
beforeEach(() => {
_ = absoluteFrom;
SOME_DIRECTIVE_FILE = {
name: _('/some_directive.umd.js'),
contents: `
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core')) :
typeof define === 'function' && define.amd ? define('some_directive', ['exports', '@angular/core'], factory) :
(factory(global.some_directive,global.ng.core));
}(this, (function (exports,core) { 'use strict';
var __decorate = null;
var __metadata = null;
var __param = null;
var INJECTED_TOKEN = new InjectionToken('injected');
var ViewContainerRef = {};
var TemplateRef = {};
var SomeDirective = (function() {
function SomeDirective(_viewContainer, _template, injected) {}
__decorate([
core.Input(),
__metadata("design:type", String)
], SomeDirective.prototype, "input1", void 0);
__decorate([
core.Input(),
__metadata("design:type", Number)
], SomeDirective.prototype, "input2", void 0);
SomeDirective = __decorate([
core.Directive({ selector: '[someDirective]' }),
__param(2, core.Inject(INJECTED_TOKEN)),
__metadata("design:paramtypes", [ViewContainerRef, TemplateRef, String])
], SomeDirective);
return SomeDirective;
}());
exports.SomeDirective = SomeDirective;
})));`,
};
});
describe('getDecoratorsOfDeclaration()', () => {
it('should find the decorators on a class', () => {
loadTestFiles([SOME_DIRECTIVE_FILE]);
const {program, host: compilerHost} = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name);
const host = new UmdReflectionHost(new MockLogger(), false, program, compilerHost);
const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration);
const decorators = host.getDecoratorsOfDeclaration(classNode) !;
expect(decorators).toBeDefined();
expect(decorators.length).toEqual(1);
const decorator = decorators[0];
expect(decorator.name).toEqual('Directive');
expect(decorator.identifier.getText()).toEqual('core.Directive');
expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'});
expect(decorator.args !.map(arg => arg.getText())).toEqual([
'{ selector: \'[someDirective]\' }',
]);
});
});
describe('getMembersOfClass()', () => {
it('should find decorated members on a class', () => {
loadTestFiles([SOME_DIRECTIVE_FILE]);
const {program, host: compilerHost} = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name);
const host = new UmdReflectionHost(new MockLogger(), false, program, compilerHost);
const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration);
const members = host.getMembersOfClass(classNode);
const input1 = members.find(member => member.name === 'input1') !;
expect(input1.kind).toEqual(ClassMemberKind.Property);
expect(input1.isStatic).toEqual(false);
expect(input1.decorators !.map(d => d.name)).toEqual(['Input']);
const input2 = members.find(member => member.name === 'input2') !;
expect(input2.kind).toEqual(ClassMemberKind.Property);
expect(input2.isStatic).toEqual(false);
expect(input1.decorators !.map(d => d.name)).toEqual(['Input']);
});
describe('getConstructorParameters', () => {
it('should find the decorated constructor parameters', () => {
loadTestFiles([SOME_DIRECTIVE_FILE]);
const {program, host: compilerHost} = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name);
const host = new UmdReflectionHost(new MockLogger(), false, program, compilerHost);
const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration);
const parameters = host.getConstructorParameters(classNode);
expect(parameters).toBeDefined();
expect(parameters !.map(parameter => parameter.name)).toEqual([
'_viewContainer', '_template', 'injected'
]);
expectTypeValueReferencesForParameters(parameters !, [
'ViewContainerRef',
'TemplateRef',
null,
]);
});
});
});
});
});

View File

@ -1057,22 +1057,17 @@ runInEachFileSystem(() => {
expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'}));
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
it('should have import information on decorators', () => {
loadTestFiles([SOME_DIRECTIVE_FILE]);
const {program, host: compilerHost} = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name);
const host = new UmdReflectionHost(new MockLogger(), false, program, compilerHost);
const mockImportInfo: Import = {from: '@angular/core', name: 'Directive'};
const spy = spyOn(host, 'getImportOfIdentifier').and.returnValue(mockImportInfo);
const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration);
const decorators = host.getDecoratorsOfDeclaration(classNode) !;
expect(decorators.length).toEqual(1);
expect(decorators[0].import).toBe(mockImportInfo);
const typeIdentifier = spy.calls.mostRecent().args[0] as ts.Identifier;
expect(typeIdentifier.text).toBe('Directive');
expect(decorators[0].import).toEqual({name: 'Directive', from: '@angular/core'});
});
it('should find decorated members on a class at the top level', () => {
@ -1290,22 +1285,17 @@ runInEachFileSystem(() => {
expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'}));
});
it('should use `getImportOfIdentifier()` to retrieve import info', () => {
it('should have import information on decorators', () => {
loadTestFiles([SOME_DIRECTIVE_FILE]);
const {program, host: compilerHost} = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name);
const host = new UmdReflectionHost(new MockLogger(), false, program, compilerHost);
const mockImportInfo = { name: 'mock', from: '@angular/core' } as Import;
const spy = spyOn(host, 'getImportOfIdentifier').and.returnValue(mockImportInfo);
const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration);
const decorators = host.getDecoratorsOfDeclaration(classNode) !;
expect(decorators.length).toEqual(1);
expect(decorators[0].import).toBe(mockImportInfo);
const typeIdentifier = spy.calls.mostRecent().args[0] as ts.Identifier;
expect(typeIdentifier.text).toBe('Directive');
expect(decorators[0].import).toEqual({name: 'Directive', from: '@angular/core'});
});
describe('(returned prop decorators `args`)', () => {

View File

@ -201,7 +201,7 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
const identifiers = ExpressionVisitor.getIdentifiers(
attribute.value, expressionSrc, expressionAbsolutePosition, this.boundTemplate,
this.targetToIdentifier);
this.targetToIdentifier.bind(this));
identifiers.forEach(id => this.identifiers.add(id));
}
visitBoundEvent(attribute: TmplAstBoundEvent) { this.visitExpression(attribute.handler); }

View File

@ -124,6 +124,32 @@ runInEachFileSystem(() => {
});
});
it('should discover variables in bound attributes', () => {
const template = '<div #div [value]="div.innerText"></div>';
const refs = getTemplateIdentifiers(bind(template));
const elementReference: ElementIdentifier = {
name: 'div',
kind: IdentifierKind.Element,
span: new AbsoluteSourceSpan(1, 4),
attributes: new Set(),
usedDirectives: new Set(),
};
const reference: ReferenceIdentifier = {
name: 'div',
kind: IdentifierKind.Reference,
span: new AbsoluteSourceSpan(6, 9),
target: {node: elementReference, directive: null},
};
const refArr = Array.from(refs);
expect(refArr).toContain({
name: 'div',
kind: IdentifierKind.Property,
span: new AbsoluteSourceSpan(19, 22),
target: reference,
});
});
it('should discover properties in template expressions', () => {
const template = '<div [bar]="bar ? bar1 : bar2"></div>';
const refs = getTemplateIdentifiers(bind(template));

View File

@ -11,7 +11,7 @@ import * as ts from 'typescript';
import {Diagnostic} from '../src/diagnostics';
import {NGFOR_DECLARATION, TestDeclaration, ngForDts, typecheck} from './test_utils';
import {TestDeclaration, ngForDeclaration, ngForDts, typecheck} from './test_utils';
runInEachFileSystem(() => {
describe('template diagnostics', () => {
@ -46,7 +46,7 @@ runInEachFileSystem(() => {
render(input: string): string { return input; }
}`,
[NGFOR_DECLARATION], [ngForDts()]);
[ngForDeclaration()], [ngForDts()]);
expect(messages).toEqual([
`synthetic.html(61, 64): Argument of type 'number' is not assignable to parameter of type 'string'.`,
@ -61,7 +61,7 @@ runInEachFileSystem(() => {
render(input: string): string { return input; }
}`,
[NGFOR_DECLARATION], [ngForDts()]);
[ngForDeclaration()], [ngForDts()]);
expect(messages).toEqual([]);
});
@ -127,7 +127,7 @@ runInEachFileSystem(() => {
name: string;
}[];
}`,
[NGFOR_DECLARATION], [ngForDts()]);
[ngForDeclaration()], [ngForDts()]);
expect(messages).toEqual([
`synthetic.html(39, 52): Property 'namme' does not exist on type '{ name: string; }'. Did you mean 'name'?`,

View File

@ -77,14 +77,16 @@ export function angularCoreDts(): TestFile {
};
}
export const NGFOR_DECLARATION: TestDeclaration = {
type: 'directive',
file: 'ngfor.d.ts',
selector: '[ngForOf]',
name: 'NgForOf',
inputs: {ngForOf: 'ngForOf'},
hasNgTemplateContextGuard: true,
};
export function ngForDeclaration(): TestDeclaration {
return {
type: 'directive',
file: absoluteFrom('/ngfor.d.ts'),
selector: '[ngForOf]',
name: 'NgForOf',
inputs: {ngForOf: 'ngForOf'},
hasNgTemplateContextGuard: true,
};
}
export function ngForDts(): TestFile {
return {
@ -124,10 +126,10 @@ export const ALL_ENABLED_CONFIG: TypeCheckingConfig = {
// Remove 'ref' from TypeCheckableDirectiveMeta and add a 'selector' instead.
export type TestDirective =
Partial<Pick<TypeCheckableDirectiveMeta, Exclude<keyof TypeCheckableDirectiveMeta, 'ref'>>>&
{selector: string, name: string, file?: string, type: 'directive'};
{selector: string, name: string, file?: AbsoluteFsPath, type: 'directive'};
export type TestPipe = {
name: string,
file?: string,
file?: AbsoluteFsPath,
pipeName: string,
type: 'pipe',
};
@ -185,7 +187,7 @@ export function typecheck(
...additionalSources,
];
const {program, host, options} = makeProgram(files, {strictNullChecks: true}, undefined, false);
const sf = program.getSourceFile('main.ts') !;
const sf = program.getSourceFile(absoluteFrom('/main.ts')) !;
const checker = program.getTypeChecker();
const logicalFs = new LogicalFileSystem(getRootDirs(host, options));
const emitter = new ReferenceEmitter([

View File

@ -14,11 +14,14 @@ import {Console} from './console';
import {Injector, StaticProvider} from './di';
import {Inject, Optional, SkipSelf} from './di/metadata';
import {ErrorHandler} from './error_handler';
import {DEFAULT_LOCALE_ID} from './i18n/localization';
import {LOCALE_ID} from './i18n/tokens';
import {ivyEnabled} from './ivy_switch';
import {ComponentFactoryResolver} from './linker';
import {Compiler} from './linker/compiler';
import {NgModule} from './metadata';
import {SCHEDULER} from './render3/component_ref';
import {setLocaleId} from './render3/i18n';
import {NgZone} from './zone';
export function _iterableDiffersFactory() {
@ -31,15 +34,21 @@ export function _keyValueDiffersFactory() {
export function _localeFactory(locale?: string): string {
if (locale) {
if (ivyEnabled) {
setLocaleId(locale);
}
return locale;
}
// Use `goog.LOCALE` as default value for `LOCALE_ID` token for Closure Compiler.
// Note: default `goog.LOCALE` value is `en`, when Angular used `en-US`. In order to preserve
// backwards compatibility, we use Angular default value over Closure Compiler's one.
if (ngI18nClosureMode && typeof goog !== 'undefined' && goog.LOCALE !== 'en') {
if (ivyEnabled) {
setLocaleId(goog.LOCALE);
}
return goog.LOCALE;
}
return 'en-US';
return DEFAULT_LOCALE_ID;
}
/**

View File

@ -8,15 +8,16 @@
import {Observable, Observer, Subscription, merge} from 'rxjs';
import {share} from 'rxjs/operators';
import {ApplicationInitStatus} from './application_init';
import {APP_BOOTSTRAP_LISTENER, PLATFORM_INITIALIZER} from './application_tokens';
import {getCompilerFacade} from './compiler/compiler_facade';
import {Console} from './console';
import {Injectable, InjectionToken, Injector, StaticProvider} from './di';
import {ErrorHandler} from './error_handler';
import {DEFAULT_LOCALE_ID} from './i18n/localization';
import {LOCALE_ID} from './i18n/tokens';
import {Type} from './interface/type';
import {ivyEnabled} from './ivy_switch';
import {COMPILER_OPTIONS, CompilerFactory, CompilerOptions} from './linker/compiler';
import {ComponentFactory, ComponentRef} from './linker/component_factory';
import {ComponentFactoryBoundToModule, ComponentFactoryResolver} from './linker/component_factory_resolver';
@ -26,7 +27,7 @@ import {isComponentResourceResolutionQueueEmpty, resolveComponentResources} from
import {WtfScopeFn, wtfCreateScope, wtfLeave} from './profile/profile';
import {assertNgModuleType} from './render3/assert';
import {ComponentFactory as R3ComponentFactory} from './render3/component_ref';
import {DEFAULT_LOCALE_ID, setLocaleId} from './render3/i18n';
import {setLocaleId} from './render3/i18n';
import {NgModuleFactory as R3NgModuleFactory} from './render3/ng_module_ref';
import {Testability, TestabilityRegistry} from './testability/testability';
import {isDevMode} from './util/is_dev_mode';
@ -264,8 +265,10 @@ export class PlatformRef {
throw new Error('No ErrorHandler. Is platform module (BrowserModule) included?');
}
// If the `LOCALE_ID` provider is defined at bootstrap we set the value for runtime i18n (ivy)
const localeId = moduleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
setLocaleId(localeId);
if (ivyEnabled) {
const localeId = moduleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
setLocaleId(localeId || DEFAULT_LOCALE_ID);
}
moduleRef.onDestroy(() => remove(this._modules, moduleRef));
ngZone !.runOutsideAngular(
() => ngZone !.onError.subscribe(

View File

@ -16,6 +16,7 @@ export {Console as ɵConsole} from './console';
export {inject, setCurrentInjector as ɵsetCurrentInjector, ɵɵinject} from './di/injector_compatibility';
export {getInjectableDef as ɵgetInjectableDef, ɵɵInjectableDef, ɵɵInjectorDef} from './di/interface/defs';
export {APP_ROOT as ɵAPP_ROOT} from './di/scope';
export {DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID} from './i18n/localization';
export {ivyEnabled as ɵivyEnabled} from './ivy_switch';
export {ComponentFactory as ɵComponentFactory} from './linker/component_factory';
export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} from './linker/component_factory_resolver';
@ -27,7 +28,6 @@ export {_sanitizeHtml as ɵ_sanitizeHtml} from './sanitization/html_sanitizer';
export {_sanitizeStyle as ɵ_sanitizeStyle} from './sanitization/style_sanitizer';
export {_sanitizeUrl as ɵ_sanitizeUrl} from './sanitization/url_sanitizer';
export {global as ɵglobal} from './util/global';
export {looseIdentical as ɵlooseIdentical,} from './util/comparison';
export {stringify as ɵstringify} from './util/stringify';
export {makeDecorator as ɵmakeDecorator} from './util/decorators';

View File

@ -173,7 +173,6 @@ export {
i18nConfigureLocalize as ɵi18nConfigureLocalize,
ɵɵi18nLocalize,
setLocaleId as ɵsetLocaleId,
DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID,
setClassMetadata as ɵsetClassMetadata,
ɵɵresolveWindow,
ɵɵresolveDocument,

View File

@ -57,11 +57,11 @@ export function forwardRef(forwardRefFn: ForwardRefFn): Type<any> {
* @publicApi
*/
export function resolveForwardRef<T>(type: T): T {
const fn: any = type;
if (typeof fn === 'function' && fn.hasOwnProperty(__forward_ref__) &&
fn.__forward_ref__ === forwardRef) {
return fn();
} else {
return type;
}
return isForwardRef(type) ? type() : type;
}
/** Checks whether a function is wrapped by a `forwardRef`. */
export function isForwardRef(fn: any): fn is() => any {
return typeof fn === 'function' && fn.hasOwnProperty(__forward_ref__) &&
fn.__forward_ref__ === forwardRef;
}

View File

@ -7,6 +7,7 @@
*/
import {Type} from '../../interface/type';
import {isForwardRef, resolveForwardRef} from '../forward_ref';
import {ɵɵinject} from '../injector_compatibility';
import {getInjectableDef, getInjectorDef, ɵɵdefineInjectable, ɵɵdefineInjector} from '../interface/defs';
@ -26,6 +27,14 @@ export const angularCoreDiEnv: {[name: string]: Function} = {
function getFactoryOf<T>(type: Type<any>): ((type?: Type<T>) => T)|null {
const typeAny = type as any;
if (isForwardRef(type)) {
return (() => {
const factory = getFactoryOf<T>(resolveForwardRef(typeAny));
return factory ? factory() : null;
}) as any;
}
const def = getInjectableDef<T>(typeAny) || getInjectorDef<T>(typeAny);
if (!def || def.factory === undefined) {
return null;

View File

@ -29,3 +29,8 @@ export function getPluralCase(value: any, locale: string): string {
return 'other';
}
}
/**
* The locale id that the application is using by default (for translations and ICU expressions).
*/
export const DEFAULT_LOCALE_ID = 'en-US';

View File

@ -132,6 +132,9 @@ export interface ContentChildrenDecorator {
*
* Content queries are set before the `ngAfterContentInit` callback is called.
*
* Does not retrieve elements or directives that are in other components' templates,
* since a component's template is always a black box to its ancestors.
*
* **Metadata Properties**:
*
* * **selector** - The directive type or the name used for querying.
@ -194,6 +197,9 @@ export interface ContentChildDecorator {
*
* Content queries are set before the `ngAfterContentInit` callback is called.
*
* Does not retrieve elements or directives that are in other components' templates,
* since a component's template is always a black box to its ancestors.
*
* **Metadata Properties**:
*
* * **selector** - The directive type or the name used for querying.

View File

@ -22,6 +22,21 @@ Great reads:
See benchmark [here](https://jsperf.com/mono-vs-megamorphic-property-access).
## Packed vs. holey Array
V8 represents arrays internally in a different way depending on:
- type of elements in the array;
- presence of holes (indexes that were never assigned).
Generally speaking packed arrays (a set of continuous, initialized indexes) perform better as compared to arrays with holes. To assure that arrays are packed follow those guidelines:
* create array literals with known values whenever possible (ex. `a = [0];` is better than `a = []; a.push[0];`;
* don't use `Array` constructor with the size value (ex. `new Array(5)`) - this will create a `HOLEY_ELEMENTS` array (even if this array is filled in later on!);
* don't delete elements from an array (ex. `delete a[0]`) - this will create a hole;
* don't write past the array length as this will create holes;
Great reads:
- [Elements kinds in V8](https://v8.dev/blog/elements-kinds)
## Exporting top level variables
Exporting top level variables should be avoided where possible where performance

View File

@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {isForwardRef, resolveForwardRef} from '../di/forward_ref';
import {InjectionToken} from '../di/injection_token';
import {Injector} from '../di/injector';
import {injectRootLimpMode, setInjectImplementation} from '../di/injector_compatibility';
@ -633,6 +634,14 @@ export class NodeInjector implements Injector {
*/
export function ɵɵgetFactoryOf<T>(type: Type<any>): FactoryFn<T>|null {
const typeAny = type as any;
if (isForwardRef(type)) {
return (() => {
const factory = ɵɵgetFactoryOf<T>(resolveForwardRef(typeAny));
return factory ? factory() : null;
}) as any;
}
const def = getComponentDef<T>(typeAny) || getDirectiveDef<T>(typeAny) ||
getPipeDef<T>(typeAny) || getInjectableDef<T>(typeAny) || getInjectorDef<T>(typeAny);
if (!def || def.factory === undefined) {

View File

@ -185,18 +185,23 @@ export function executeHooks(
checkNoChangesMode: boolean, initPhaseState: InitPhaseState,
currentNodeIndex: number | null | undefined): void {
if (checkNoChangesMode) return;
const hooksToCall = (currentView[FLAGS] & LViewFlags.InitPhaseStateMask) === initPhaseState ?
firstPassHooks :
checkHooks;
if (hooksToCall) {
callHooks(currentView, hooksToCall, initPhaseState, currentNodeIndex);
if (checkHooks !== null || firstPassHooks !== null) {
const hooksToCall = (currentView[FLAGS] & LViewFlags.InitPhaseStateMask) === initPhaseState ?
firstPassHooks :
checkHooks;
if (hooksToCall !== null) {
callHooks(currentView, hooksToCall, initPhaseState, currentNodeIndex);
}
}
// The init phase state must be always checked here as it may have been recursively updated
if (currentNodeIndex == null &&
(currentView[FLAGS] & LViewFlags.InitPhaseStateMask) === initPhaseState &&
let flags = currentView[FLAGS];
if (currentNodeIndex == null && (flags & LViewFlags.InitPhaseStateMask) === initPhaseState &&
initPhaseState !== InitPhaseState.InitPhaseCompleted) {
currentView[FLAGS] &= LViewFlags.IndexWithinInitPhaseReset;
currentView[FLAGS] += LViewFlags.InitPhaseStateIncrementer;
flags &= LViewFlags.IndexWithinInitPhaseReset;
flags += LViewFlags.InitPhaseStateIncrementer;
currentView[FLAGS] = flags;
}
}

View File

@ -7,14 +7,12 @@
*/
import '../util/ng_i18n_closure_mode';
import {getPluralCase} from '../i18n/localization';
import {DEFAULT_LOCALE_ID, getPluralCase} from '../i18n/localization';
import {SRCSET_ATTRS, URI_ATTRS, VALID_ATTRS, VALID_ELEMENTS, getTemplateContent} from '../sanitization/html_sanitizer';
import {InertBodyHelper} from '../sanitization/inert_body';
import {_sanitizeUrl, sanitizeSrcset} from '../sanitization/url_sanitizer';
import {addAllToArray} from '../util/array_utils';
import {assertDataInRange, assertDefined, assertEqual, assertGreaterThan} from '../util/assert';
import {attachPatchData} from './context_discovery';
import {bind, setDelayProjection, ɵɵload} from './instructions/all';
import {attachI18nOpCodesDebug} from './instructions/lview_debug';
@ -1358,7 +1356,6 @@ export function ɵɵi18nLocalize(input: string, placeholders?: {[key: string]: s
* This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine
* but is now defined as a global value.
*/
export const DEFAULT_LOCALE_ID = 'en-US';
let LOCALE_ID = DEFAULT_LOCALE_ID;
/**
@ -1369,7 +1366,10 @@ let LOCALE_ID = DEFAULT_LOCALE_ID;
* @param localeId
*/
export function setLocaleId(localeId: string) {
LOCALE_ID = localeId.toLowerCase().replace(/_/g, '-');
assertDefined(localeId, `Expected localeId to be defined`);
if (typeof localeId === 'string') {
LOCALE_ID = localeId.toLowerCase().replace(/_/g, '-');
}
}
/**

View File

@ -142,7 +142,6 @@ export {
} from './state';
export {
DEFAULT_LOCALE_ID,
ɵɵi18n,
ɵɵi18nAttributes,
ɵɵi18nExp,

View File

@ -63,15 +63,11 @@ export function refreshDescendantViews(lView: LView) {
const tView = lView[TVIEW];
const creationMode = isCreationMode(lView);
// This needs to be set before children are processed to support recursive components
tView.firstTemplatePass = false;
// Resetting the bindingIndex of the current LView as the next steps may trigger change detection.
lView[BINDING_INDEX] = tView.bindingStartIndex;
// If this is a creation pass, we should not call lifecycle hooks or evaluate bindings.
// This will be done in the update pass.
if (!creationMode) {
// Resetting the bindingIndex of the current LView as the next steps may trigger change
// detection.
lView[BINDING_INDEX] = tView.bindingStartIndex;
const checkNoChangesMode = getCheckNoChangesMode();
executePreOrderHooks(lView, tView, checkNoChangesMode, undefined);
@ -79,7 +75,9 @@ export function refreshDescendantViews(lView: LView) {
refreshDynamicEmbeddedViews(lView);
// Content query results must be refreshed before content hooks are called.
refreshContentQueries(tView, lView);
if (tView.contentQueries !== null) {
refreshContentQueries(tView, lView);
}
resetPreOrderHookFlags(lView);
executeHooks(
@ -87,14 +85,22 @@ export function refreshDescendantViews(lView: LView) {
InitPhaseState.AfterContentInitHooksToBeRun, undefined);
setHostBindings(tView, lView);
} else {
// This needs to be set before children are processed to support recursive components.
// This must be set to false immediately after the first creation run because in an
// ngFor loop, all the views will be created together before update mode runs and turns
// off firstTemplatePass. If we don't set it here, instances will perform directive
// matching, etc again and again.
tView.firstTemplatePass = false;
// We resolve content queries specifically marked as `static` in creation mode. Dynamic
// content queries are resolved during change detection (i.e. update mode), after embedded
// views are refreshed (see block above).
if (tView.staticContentQueries) {
refreshContentQueries(tView, lView);
}
}
// We resolve content queries specifically marked as `static` in creation mode. Dynamic
// content queries are resolved during change detection (i.e. update mode), after embedded
// views are refreshed (see block above).
if (creationMode && tView.staticContentQueries) {
refreshContentQueries(tView, lView);
}
// We must materialize query results before child components are processed
// in case a child component has projected a container. The LContainer needs
@ -103,7 +109,10 @@ export function refreshDescendantViews(lView: LView) {
executeViewQueryFn(RenderFlags.Update, tView, lView[CONTEXT]);
}
refreshChildComponents(lView, tView.components);
const components = tView.components;
if (components !== null) {
refreshChildComponents(lView, components);
}
}
@ -111,7 +120,7 @@ export function refreshDescendantViews(lView: LView) {
export function setHostBindings(tView: TView, viewData: LView): void {
const selectedIndex = getSelectedIndex();
try {
if (tView.expandoInstructions) {
if (tView.expandoInstructions !== null) {
let bindingRootIndex = viewData[BINDING_INDEX] = tView.expandoStartIndex;
setBindingRoot(bindingRootIndex);
let currentDirectiveIndex = -1;
@ -179,11 +188,9 @@ function refreshContentQueries(tView: TView, lView: LView): void {
}
/** Refreshes child components in the current view. */
function refreshChildComponents(hostLView: LView, components: number[] | null): void {
if (components != null) {
for (let i = 0; i < components.length; i++) {
componentRefresh(hostLView, components[i]);
}
function refreshChildComponents(hostLView: LView, components: number[]): void {
for (let i = 0; i < components.length; i++) {
componentRefresh(hostLView, components[i]);
}
}
@ -408,18 +415,9 @@ export function renderEmbeddedTemplate<T>(viewToRender: LView, tView: TView, con
// Will become true if the `try` block executes with no errors.
let safeToRunHooks = false;
try {
setPreviousOrParentTNode(null !, true);
oldView = enterView(viewToRender, viewToRender[T_HOST]);
resetPreOrderHookFlags(viewToRender);
executeTemplate(viewToRender, tView.template !, getRenderFlags(viewToRender), context);
// This must be set to false immediately after the first creation run because in an
// ngFor loop, all the views will be created together before update mode runs and turns
// off firstTemplatePass. If we don't set it here, instances will perform directive
// matching, etc again and again.
tView.firstTemplatePass = false;
refreshDescendantViews(viewToRender);
safeToRunHooks = true;
} finally {
@ -644,11 +642,14 @@ export function createTView(
}
function createViewBlueprint(bindingStartIndex: number, initialViewLength: number): LView {
const blueprint = new (ngDevMode ? LViewBlueprint ! : Array)(initialViewLength)
.fill(null, 0, bindingStartIndex)
.fill(NO_CHANGE, bindingStartIndex) as LView;
const blueprint = ngDevMode ? new LViewBlueprint !() : [];
for (let i = 0; i < initialViewLength; i++) {
blueprint.push(i < bindingStartIndex ? null : NO_CHANGE);
}
blueprint[BINDING_INDEX] = bindingStartIndex;
return blueprint;
return blueprint as LView;
}
export function createError(text: string, token: any) {
@ -1494,19 +1495,20 @@ export function createLContainer(
* by executing an associated template function.
*/
function refreshDynamicEmbeddedViews(lView: LView) {
for (let current = lView[CHILD_HEAD]; current !== null; current = current[NEXT]) {
// Note: current can be an LView or an LContainer instance, but here we are only interested
// in LContainer. We can tell it's an LContainer because its length is less than the LView
// header.
if (current[ACTIVE_INDEX] === -1 && isLContainer(current)) {
for (let i = CONTAINER_HEADER_OFFSET; i < current.length; i++) {
const dynamicViewData = current[i];
let viewOrContainer = lView[CHILD_HEAD];
while (viewOrContainer !== null) {
// Note: viewOrContainer can be an LView or an LContainer instance, but here we are only
// interested in LContainer
if (isLContainer(viewOrContainer) && viewOrContainer[ACTIVE_INDEX] === -1) {
for (let i = CONTAINER_HEADER_OFFSET; i < viewOrContainer.length; i++) {
const embeddedLView = viewOrContainer[i];
// The directives and pipes are not needed here as an existing view is only being
// refreshed.
ngDevMode && assertDefined(dynamicViewData[TVIEW], 'TView must be allocated');
renderEmbeddedTemplate(dynamicViewData, dynamicViewData[TVIEW], dynamicViewData[CONTEXT] !);
ngDevMode && assertDefined(embeddedLView[TVIEW], 'TView must be allocated');
renderEmbeddedTemplate(embeddedLView, embeddedLView[TVIEW], embeddedLView[CONTEXT] !);
}
}
viewOrContainer = viewOrContainer[NEXT];
}
}
@ -1563,7 +1565,7 @@ export function componentRefresh(hostLView: LView, adjustedElementIndex: number)
function syncViewWithBlueprint(componentView: LView) {
const componentTView = componentView[TVIEW];
for (let i = componentView.length; i < componentTView.blueprint.length; i++) {
componentView[i] = componentTView.blueprint[i];
componentView.push(componentTView.blueprint[i]);
}
}

View File

@ -167,8 +167,8 @@ let activeDirectiveSuperClassHeight = 0;
*/
export function setActiveHostElement(elementIndex: number | null = null) {
if (_selectedIndex !== elementIndex) {
setSelectedIndex(elementIndex == null ? -1 : elementIndex);
activeDirectiveId = elementIndex == null ? 0 : MIN_DIRECTIVE_ID;
setSelectedIndex(elementIndex === null ? -1 : elementIndex);
activeDirectiveId = elementIndex === null ? 0 : MIN_DIRECTIVE_ID;
activeDirectiveSuperClassDepthPosition = 0;
activeDirectiveSuperClassHeight = 0;
}

View File

@ -688,7 +688,11 @@ export class DebugRenderer2 implements Renderer2 {
constructor(private delegate: Renderer2) { this.data = this.delegate.data; }
destroyNode(node: any) {
removeDebugNodeFromIndex(getDebugNode(node) !);
const debugNode = getDebugNode(node) !;
removeDebugNodeFromIndex(debugNode);
if (debugNode instanceof DebugNode__PRE_R3__) {
debugNode.listeners.length = 0;
}
if (this.delegate.destroyNode) {
this.delegate.destroyNode(node);
}

View File

@ -7,7 +7,7 @@
*/
import {CommonModule} from '@angular/common';
import {Attribute, ChangeDetectorRef, Component, Directive, ElementRef, EventEmitter, Host, HostBinding, INJECTOR, Inject, Injectable, InjectionToken, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, Optional, Output, Pipe, PipeTransform, Self, SkipSelf, TemplateRef, ViewChild, ViewContainerRef, forwardRef} from '@angular/core';
import {Attribute, ChangeDetectorRef, Component, Directive, ElementRef, EventEmitter, Host, HostBinding, INJECTOR, Inject, Injectable, InjectionToken, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, Optional, Output, Pipe, PipeTransform, Self, SkipSelf, TemplateRef, ViewChild, ViewContainerRef, forwardRef, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID} from '@angular/core';
import {ViewRef} from '@angular/core/src/render3/view_ref';
import {TestBed} from '@angular/core/testing';
import {ivyEnabled, onlyInIvy} from '@angular/private/testing';
@ -1508,7 +1508,7 @@ describe('di', () => {
const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges();
// takes `LOCALE_ID` from module injector, since we skip Component level with @SkipSelf
expect(fixture.componentInstance.localeId).toBe('en-US');
expect(fixture.componentInstance.localeId).toBe(DEFAULT_LOCALE_ID);
});
it('should work when injecting dependency in Directives', () => {

View File

@ -9,6 +9,7 @@
import {Component, Directive, Inject, Injectable, InjectionToken, Injector, NgModule, Optional, forwardRef} from '@angular/core';
import {TestBed, async, inject} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {onlyInIvy} from '@angular/private/testing';
describe('providers', () => {
@ -319,6 +320,54 @@ describe('providers', () => {
expect(fixture.componentInstance.myService.dep.value).toBe('one');
});
it('should support forward refs in useClass when impl version is also provided', () => {
@Injectable({providedIn: 'root', useClass: forwardRef(() => SomeProviderImpl)})
abstract class SomeProvider {
}
@Injectable()
class SomeProviderImpl extends SomeProvider {
}
@Component({selector: 'my-app', template: ''})
class App {
constructor(public foo: SomeProvider) {}
}
TestBed.configureTestingModule(
{declarations: [App], providers: [{provide: SomeProvider, useClass: SomeProviderImpl}]});
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
expect(fixture.componentInstance.foo).toBeAnInstanceOf(SomeProviderImpl);
});
onlyInIvy('VE bug (see FW-1454)')
.it('should support forward refs in useClass when token is provided', () => {
@Injectable({providedIn: 'root', useClass: forwardRef(() => SomeProviderImpl)})
abstract class SomeProvider {
}
@Injectable()
class SomeProviderImpl extends SomeProvider {
}
@Component({selector: 'my-app', template: ''})
class App {
constructor(public foo: SomeProvider) {}
}
TestBed.configureTestingModule(
{declarations: [App], providers: [{provide: SomeProvider, useClass: SomeProvider}]});
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
expect(fixture.componentInstance.foo).toBeAnInstanceOf(SomeProviderImpl);
});
});
describe('flags', () => {

View File

@ -343,6 +343,21 @@ class SomeComponent {
expect(getLocaleId()).toEqual('ro');
});
it('should wait for APP_INITIALIZER to set providers for `LOCALE_ID`', async() => {
let locale: string = '';
const promise = Promise.resolve().then(() => { locale = 'fr-FR'; });
const testModule = createModule({
providers: [
{provide: APP_INITIALIZER, useValue: () => promise, multi: true},
{provide: LOCALE_ID, useFactory: () => locale}
]
});
const app = await defaultPlatform.bootstrapModule(testModule);
expect(app.injector.get(LOCALE_ID)).toEqual('fr-FR');
});
});
describe('bootstrapModuleFactory', () => {

View File

@ -155,6 +155,9 @@
{
"name": "isFactoryProvider"
},
{
"name": "isForwardRef"
},
{
"name": "isTypeProvider"
},

View File

@ -1043,6 +1043,9 @@
{
"name": "isFactory"
},
{
"name": "isForwardRef"
},
{
"name": "isJsObject"
},

View File

@ -8,7 +8,7 @@
import {CommonModule, NgIfContext} from '@angular/common';
import {Component, DebugNode, Directive, ElementRef, EmbeddedViewRef, EventEmitter, HostBinding, Injectable, Input, NO_ERRORS_SCHEMA, Renderer2, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
import {Component, DebugNode, Directive, ElementRef, EmbeddedViewRef, EventEmitter, HostBinding, Injectable, Input, NO_ERRORS_SCHEMA, Output, Renderer2, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
import {By} from '@angular/platform-browser/src/dom/debug/by';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
@ -927,5 +927,40 @@ class TestCmptWithPropBindings {
expect(div.attributes.foo).toBe('bar');
});
it('should clear event listeners when node is destroyed', () => {
let calls = 0;
@Component({
selector: 'cancel-button',
template: '',
})
class CancelButton {
@Output() cancel = new EventEmitter<void>();
}
@Component({
template: '<cancel-button *ngIf="visible" (cancel)="cancel()"></cancel-button>',
})
class App {
visible = true;
cancel() { calls++; }
}
TestBed.configureTestingModule({declarations: [App, CancelButton]});
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const button = fixture.debugElement.query(By.directive(CancelButton));
button.triggerEventHandler('cancel', {});
expect(calls).toBe(1, 'Expected calls to be 1 after one event.');
fixture.componentInstance.visible = false;
fixture.detectChanges();
button.triggerEventHandler('cancel', {});
expect(calls).toBe(1, 'Expected calls to stay 1 after destroying the node.');
});
});
}

View File

@ -7,7 +7,7 @@ ts_config(
name = "tsconfig",
src = "tsconfig.json",
deps = [
"//tools:tsconfig-test",
"//packages:tsconfig-test",
],
)

View File

@ -1,7 +1,7 @@
package(default_visibility = ["//visibility:public"])
load("//packages/bazel:index.bzl", "protractor_web_test_suite")
load("//tools:defaults.bzl", "ng_module", "ts_library")
load("@npm_bazel_protractor//:index.bzl", "protractor_web_test_suite")
load("@npm_bazel_typescript//:index.bzl", "ts_devserver")
ng_module(

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractorUtils = require('@bazel/protractor/protractor-utils');
const protractor = require('protractor');
module.exports = async function(config) {

View File

@ -1,7 +1,7 @@
package(default_visibility = ["//visibility:public"])
load("//packages/bazel:index.bzl", "protractor_web_test_suite")
load("//tools:defaults.bzl", "jasmine_node_test", "ng_module", "ts_library")
load("@npm_bazel_protractor//:index.bzl", "protractor_web_test_suite")
load("@npm_bazel_typescript//:index.bzl", "ts_devserver")
ng_module(

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractorUtils = require('@bazel/protractor/protractor-utils');
const protractor = require('protractor');
module.exports = async function(config) {

View File

@ -1,7 +1,7 @@
package(default_visibility = ["//visibility:public"])
load("//packages/bazel:index.bzl", "protractor_web_test_suite")
load("//tools:defaults.bzl", "ng_module", "ts_library")
load("@npm_bazel_protractor//:index.bzl", "protractor_web_test_suite")
load("@npm_bazel_typescript//:index.bzl", "ts_devserver")
ng_module(

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractorUtils = require('@bazel/protractor/protractor-utils');
const protractor = require('protractor');
module.exports = async function(config) {

View File

@ -1,7 +1,7 @@
package(default_visibility = ["//visibility:public"])
load("//packages/bazel:index.bzl", "protractor_web_test_suite")
load("//tools:defaults.bzl", "ng_module", "ts_library")
load("@npm_bazel_protractor//:index.bzl", "protractor_web_test_suite")
load("@npm_bazel_typescript//:index.bzl", "ts_devserver")
ng_module(

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractorUtils = require('@bazel/protractor/protractor-utils');
const protractor = require('protractor');
module.exports = async function(config) {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractorUtils = require('@bazel/protractor/protractor-utils');
const protractor = require('protractor');
module.exports = async function(config) {

View File

@ -1,5 +1,5 @@
load("//packages/bazel:index.bzl", "protractor_web_test_suite")
load("//tools:defaults.bzl", "ng_module", "ts_library")
load("@npm_bazel_protractor//:index.bzl", "protractor_web_test_suite")
load("@npm_bazel_typescript//:index.bzl", "ts_devserver")
"""

View File

@ -1,3 +1,23 @@
<a name="0.10.0"></a>
# [0.10.0](https://github.com/angular/angular/compare/7b3bcc2...174770e) (2019-07-26)
### Bug Fixes
* **zone.js:** __load_patch and __symbol__ should be in zone_extern for closure compiler ([#31350](https://github.com/angular/angular/issues/31350)) ([6b51ed2](https://github.com/angular/angular/commit/6b51ed2))
* **zone.js:** don't fire unhandledrejection if Zone handled error ([#31718](https://github.com/angular/angular/issues/31718)) ([c7542a1](https://github.com/angular/angular/commit/c7542a1)), closes [#31701](https://github.com/angular/angular/issues/31701)
* **zone.js:** don't wrap uncaught promise error. ([#31443](https://github.com/angular/angular/issues/31443)) ([2bb9a65](https://github.com/angular/angular/commit/2bb9a65)), closes [#27840](https://github.com/angular/angular/issues/27840)
* **zone.js:** fix zone for Jasmine 3.3. ([#31497](https://github.com/angular/angular/issues/31497)) ([c4c340a](https://github.com/angular/angular/commit/c4c340a))
* **zone.js:** handle MSPointer event correctly ([#31722](https://github.com/angular/angular/issues/31722)) ([2c402d5](https://github.com/angular/angular/commit/2c402d5)), closes [#31699](https://github.com/angular/angular/issues/31699)
* **zone.js:** handle new api of electron 4 ([#31669](https://github.com/angular/angular/issues/31669)) ([a445826](https://github.com/angular/angular/commit/a445826)), closes [#31668](https://github.com/angular/angular/issues/31668)
* **zone.js:** hook should set correct current zone ([#31642](https://github.com/angular/angular/issues/31642)) ([17b32b5](https://github.com/angular/angular/commit/17b32b5)), closes [#31641](https://github.com/angular/angular/issues/31641)
* **zone.js:** move property patch to legacy ([#31660](https://github.com/angular/angular/issues/31660)) ([716af10](https://github.com/angular/angular/commit/716af10)), closes [#31659](https://github.com/angular/angular/issues/31659)
* **zone.js:** patch shadydom ([#31717](https://github.com/angular/angular/issues/31717)) ([35a025f](https://github.com/angular/angular/commit/35a025f)), closes [#31686](https://github.com/angular/angular/issues/31686)
* **zone.js:** restore definition of global ([#31453](https://github.com/angular/angular/issues/31453)) ([e6f1b04](https://github.com/angular/angular/commit/e6f1b04)), closes [/github.com/angular/zone.js/commit/71b93711806000d7788e79451478e20d6086aa8a#diff-dd469785fca8680a5b33b1e81c5cfd91R1420](https://github.com//github.com/angular/zone.js/commit/71b93711806000d7788e79451478e20d6086aa8a/issues/diff-dd469785fca8680a5b33b1e81c5cfd91R1420)
* **zone.js:** should remove on symbol property after removeAllListeners ([#31644](https://github.com/angular/angular/issues/31644)) ([a182714](https://github.com/angular/angular/commit/a182714)), closes [#31643](https://github.com/angular/angular/issues/31643)
* **zone.js:** update dart zone link ([#31646](https://github.com/angular/angular/issues/31646)) ([7f7033b](https://github.com/angular/angular/commit/7f7033b)), closes [#31645](https://github.com/angular/angular/issues/31645)
* **zone.js:** zone-mix should import correct browser module ([#31628](https://github.com/angular/angular/issues/31628)) ([87ce4e9](https://github.com/angular/angular/commit/87ce4e9)), closes [#31626](https://github.com/angular/angular/issues/31626)
<a name="0.9.1"></a>
## [0.9.1](https://github.com/angular/zone.js/compare/v0.9.0...0.9.1) (2019-04-30)
@ -44,7 +64,7 @@
* **env:** change BLACK_LISTED_EVENTS to DISABLE_EVENTS ([9c65d25](https://github.com/angular/zone.js/commit/9c65d25))
### Build
### Build
* **build:** build zone-evergreen.js in es2015, add terser minify support ([2ad936b](https://github.com/angular/zone.js/commit/2ad936b))
* **build:** upgrade to pass jasmine 3.3 test ([82dfd75](https://github.com/angular/zone.js/commit/82dfd75))

View File

@ -80,10 +80,24 @@ yarn webdriver-sauce-test
Releasing
---------
- create a new tag in `angular` repo.
```
$ TAG=<TAG>
$ git tag $TAG
```
- create a PR to update `changelog` of zone.js
```
$ yarn gulp changelog:zonejs
```
- deploy to npm
To make a `dry-run`, run the following commands.
```
$ VERSION=<version>
$ git tag 'zone.js-$VERSION'
$ yarn bazel --output_base=$(mktemp -d) run //packages/zone.js:npm_package.pack --workspace_status_command="echo BUILD_SCM_VERSION $VERSION"
```

View File

@ -100,7 +100,9 @@ genrule(
],
cmd = " && ".join([
"mkdir -p $(@D)",
"cp $(@D)/" + b[0].replace("-", "_") + "_rollup.es5umd.js $(@D)/" + b[0] + ".js",
# remove the last line '//# sourceMappingURL=b[0].umd.js.map' because we don't release
# source map for now
"sed '$$d' $(@D)/" + b[0].replace("-", "_") + "_rollup.es5umd.js > $(@D)/" + b[0] + ".js",
"cp $(@D)/" + b[0].replace("-", "_") + "_rollup.min.es5umd.js $(@D)/" + b[0] + ".min.js",
]),
)
@ -174,7 +176,9 @@ genrule(
],
cmd = " && ".join([
"mkdir -p $(@D)",
"cp $(@D)/" + b.replace("-", "_") + "_rollup.umd.js $(@D)/" + b + ".js",
# remove the last line '//# sourceMappingURL=b[0].umd.js.map' because we don't release
# source map for now
"sed '$$d' $(@D)/" + b.replace("-", "_") + "_rollup.umd.js > $(@D)/" + b + ".js",
"cp $(@D)/" + b.replace("-", "_") + "_rollup.min.umd.js $(@D)/" + b + ".min.js",
]),
)

View File

@ -331,8 +331,9 @@ Zone.__load_patch('Error', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
// we need to detect all zone related frames, it will
// exceed default stackTraceLimit, so we set it to
// larger number here, and restore it after detect finish.
const originalStackTraceLimit = Error.stackTraceLimit;
Error.stackTraceLimit = 100;
// We cast through any so we don't need to depend on nodejs typings.
const originalStackTraceLimit = (Error as any).stackTraceLimit;
(Error as any).stackTraceLimit = 100;
// we schedule event/micro/macro task, and invoke them
// when onSchedule, so we can get all stack traces for
// all kinds of tasks with one error thrown.
@ -374,5 +375,5 @@ Zone.__load_patch('Error', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
});
});
Error.stackTraceLimit = originalStackTraceLimit;
(Error as any).stackTraceLimit = originalStackTraceLimit;
});

View File

@ -176,25 +176,20 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
}
if (queue.length == 0 && state == REJECTED) {
(promise as any)[symbolState] = REJECTED_NO_CATCH;
let uncaughtPromiseError: any;
if (value instanceof Error || (value && value.message)) {
uncaughtPromiseError = value;
} else {
try {
// try to print more readable error log
throw new Error(
'Uncaught (in promise): ' + readableObjectToString(value) +
(value && value.stack ? '\n' + value.stack : ''));
} catch (err) {
uncaughtPromiseError = err;
}
try {
// try to print more readable error log
throw new Error(
'Uncaught (in promise): ' + readableObjectToString(value) +
(value && value.stack ? '\n' + value.stack : ''));
} catch (err) {
const error: UncaughtPromiseError = err;
error.rejection = value;
error.promise = promise;
error.zone = Zone.current;
error.task = Zone.currentTask !;
_uncaughtPromiseErrors.push(error);
api.scheduleMicroTask(); // to make sure that it is running
}
uncaughtPromiseError.rejection = value;
uncaughtPromiseError.promise = promise;
uncaughtPromiseError.zone = Zone.current;
uncaughtPromiseError.task = Zone.currentTask !;
_uncaughtPromiseErrors.push(uncaughtPromiseError);
api.scheduleMicroTask(); // to make sure that it is running
}
}
}

View File

@ -78,6 +78,16 @@ function renderLongStackTrace(frames: LongStackTrace[], stack?: string): string
return longTrace.join(NEWLINE);
}
// if Error.stackTraceLimit is 0, means stack trace
// is disabled, so we don't need to generate long stack trace
// this will improve performance in some test(some test will
// set stackTraceLimit to 0, https://github.com/angular/zone.js/issues/698
function stackTracesEnabled(): boolean {
// Cast through any since this property only exists on Error in the nodejs
// typings.
return (Error as any).stackTraceLimit > 0;
}
type LongStackTraceZoneSpec = ZoneSpec & {longStackTraceLimit: number};
(Zone as any)['longStackTraceZoneSpec'] = <LongStackTraceZoneSpec>{
@ -99,11 +109,7 @@ type LongStackTraceZoneSpec = ZoneSpec & {longStackTraceLimit: number};
onScheduleTask: function(
parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task): any {
if (Error.stackTraceLimit > 0) {
// if Error.stackTraceLimit is 0, means stack trace
// is disabled, so we don't need to generate long stack trace
// this will improve performance in some test(some test will
// set stackTraceLimit to 0, https://github.com/angular/zone.js/issues/698
if (stackTracesEnabled()) {
const currentTask = Zone.currentTask;
let trace = currentTask && currentTask.data && (currentTask.data as any)[creationTrace] || [];
trace = [new LongStackTrace()].concat(trace);
@ -127,11 +133,7 @@ type LongStackTraceZoneSpec = ZoneSpec & {longStackTraceLimit: number};
onHandleError: function(
parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, error: any): boolean {
if (Error.stackTraceLimit > 0) {
// if Error.stackTraceLimit is 0, means stack trace
// is disabled, so we don't need to generate long stack trace
// this will improve performance in some test(some test will
// set stackTraceLimit to 0, https://github.com/angular/zone.js/issues/698
if (stackTracesEnabled()) {
const parentTask = Zone.currentTask || error.task;
if (error instanceof Error && parentTask) {
const longStack =
@ -154,7 +156,7 @@ function captureStackTraces(stackTraces: string[][], count: number): void {
}
function computeIgnoreFrames() {
if (Error.stackTraceLimit <= 0) {
if (!stackTracesEnabled()) {
return;
}
const frames: string[][] = [];

View File

@ -321,10 +321,15 @@ interface ZoneType {
__symbol__(name: string): string;
}
/** @internal */
/**
* Patch Function to allow user define their own monkey patch module.
*/
type _PatchFn = (global: Window, Zone: ZoneType, api: _ZonePrivate) => void;
/** @internal */
/**
* _ZonePrivate interface to provide helper method to help user implement
* their own monkey patch module.
*/
interface _ZonePrivate {
currentZoneFrame: () => _ZoneFrame;
symbol: (name: string) => string;
@ -366,7 +371,9 @@ interface _ZonePrivate {
} | undefined;
}
/** @internal */
/**
* _ZoneFrame represents zone stack frame information
*/
interface _ZoneFrame {
parent: _ZoneFrame|null;
zone: Zone;
@ -668,6 +675,12 @@ type AmbientZone = Zone;
/** @internal */
type AmbientZoneDelegate = ZoneDelegate;
// CommonJS / Node have global context exposed as "global" variable.
// This code should run in a Browser, so we don't want to include the whole node.d.ts
// typings for this compilation unit.
// We'll just fake the global "global" var for now.
declare var global: NodeJS.Global;
const Zone: ZoneType = (function(global: any) {
const performance: {mark(name: string): void; measure(name: string, label: string): void;} =
global['performance'];
@ -703,6 +716,7 @@ const Zone: ZoneType = (function(global: any) {
}
class Zone implements AmbientZone {
// tslint:disable-next-line:require-internal-with-underscore
static __symbol__: (name: string) => string = __symbol__;
static assertZonePatched() {
@ -728,6 +742,7 @@ const Zone: ZoneType = (function(global: any) {
static get currentTask(): Task|null { return _currentTask; }
// tslint:disable-next-line:require-internal-with-underscore
static __load_patch(name: string, fn: _PatchFn): void {
if (patches.hasOwnProperty(name)) {
if (checkDuplicate) {
@ -1184,6 +1199,7 @@ const Zone: ZoneType = (function(global: any) {
}
}
// tslint:disable-next-line:require-internal-with-underscore
_updateTaskCount(type: TaskType, count: number) {
const counts = this._taskCounts;
const prev = counts[type];
@ -1211,9 +1227,12 @@ const Zone: ZoneType = (function(global: any) {
public data: TaskData|undefined;
public scheduleFn: ((task: Task) => void)|undefined;
public cancelFn: ((task: Task) => void)|undefined;
// tslint:disable-next-line:require-internal-with-underscore
_zone: Zone|null = null;
public runCount: number = 0;
// tslint:disable-next-line:require-internal-with-underscore
_zoneDelegates: ZoneDelegate[]|null = null;
// tslint:disable-next-line:require-internal-with-underscore
_state: TaskState = 'notScheduled';
constructor(
@ -1261,6 +1280,7 @@ const Zone: ZoneType = (function(global: any) {
public cancelScheduleRequest() { this._transitionTo(notScheduled, scheduling); }
// tslint:disable-next-line:require-internal-with-underscore
_transitionTo(toState: TaskState, fromState1: TaskState, fromState2?: TaskState) {
if (this._state === fromState1 || this._state === fromState2) {
this._state = toState;

View File

@ -345,8 +345,11 @@ describe(
});
setTimeout((): any => null);
setTimeout(() => {
expect(promiseError !.message)
.toBe(
'Uncaught (in promise): ' + error +
(error !.stack ? '\n' + error !.stack : ''));
expect((promiseError as any)['rejection']).toBe(error);
expect(promiseError).toBe(error);
expect((promiseError as any)['zone']).toBe(zone);
expect((promiseError as any)['task']).toBe(task);
done();
@ -386,39 +389,6 @@ describe(
});
});
it('should print original information when throw a not error object with a message property',
(done) => {
let promiseError: Error|null = null;
let zone: Zone|null = null;
let task: Task|null = null;
let rejectObj: TestRejection;
queueZone
.fork({
name: 'promise-error',
onHandleError: (delegate: ZoneDelegate, current: Zone, target: Zone, error: any):
boolean => {
promiseError = error;
delegate.handleError(target, error);
return false;
}
})
.run(() => {
zone = Zone.current;
task = Zone.currentTask;
rejectObj = new TestRejection();
rejectObj.prop1 = 'value1';
rejectObj.prop2 = 'value2';
(rejectObj as any).message = 'rejectMessage';
Promise.reject(rejectObj);
expect(promiseError).toBe(null);
});
setTimeout((): any => null);
setTimeout(() => {
expect(promiseError).toEqual(rejectObj as any);
done();
});
});
describe('Promise.race', () => {
it('should reject the value', () => {
queueZone.run(() => {

View File

@ -49,11 +49,16 @@ describe('Zone.js npm_package', () => {
describe('es5', () => {
it('zone.js(es5) should not contain es6 spread code',
() => { expect(shx.cat('zone.js')).not.toContain('let value of values'); });
it('zone.js(es5) should not contain source map comment',
() => { expect(shx.cat('zone.js')).not.toContain('sourceMappingURL'); });
});
describe('es2015', () => {
it('zone-evergreen.js(es2015) should contain es6 code',
() => { expect(shx.cat('zone-evergreen.js')).toContain('let value of values'); });
it('zone.js(es5) should not contain source map comment',
() => { expect(shx.cat('zone-evergreen.js')).not.toContain('sourceMappingURL'); });
});
describe('dist file list', () => {

View File

@ -84,7 +84,9 @@ describe('FakeAsyncTestZoneSpec', () => {
() => {
fakeAsyncTestZone.run(() => {
Promise.resolve(null).then((_) => { throw new Error('async'); });
expect(() => { testZoneSpec.flushMicrotasks(); }).toThrowError(/async/);
expect(() => {
testZoneSpec.flushMicrotasks();
}).toThrowError(/Uncaught \(in promise\): Error: async/);
});
});
@ -1169,7 +1171,7 @@ const {fakeAsync, tick, discardPeriodicTasks, flush, flushMicrotasks} = fakeAsyn
resolvedPromise.then((_) => { throw new Error('async'); });
flushMicrotasks();
})();
}).toThrowError(/async/);
}).toThrowError(/Uncaught \(in promise\): Error: async/);
});
it('should complain if a test throws an exception', () => {

View File

@ -0,0 +1,23 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
module.exports = (gulp) => () => {
const tag = process.env.ZONE_TAG;
const conventionalChangelog = require('gulp-conventional-changelog');
return gulp.src('packages/zone.js/CHANGELOG.md')
.pipe(conventionalChangelog(
{preset: 'angular'}, {
currentTag: tag,
},
{
// Ignore commits that have a different scope than `zone.js`.
extendedRegexp: true,
grep: '^[^(]+\\(zone\\.js\\)',
}))
.pipe(gulp.dest('./packages/zone.js/'));
};

101
yarn.lock
View File

@ -90,29 +90,31 @@
esutils "^2.0.2"
js-tokens "^4.0.0"
"@bazel/bazel-darwin_x64@0.27.0":
version "0.27.0"
resolved "https://registry.yarnpkg.com/@bazel/bazel-darwin_x64/-/bazel-darwin_x64-0.27.0.tgz#83a03c92d52ae60e48e86a1ee697e69e12ddbdf6"
integrity sha512-CyavIbRKRa/55aMyfEM9hjbt4TVISfv7HLeymHTGTLWzS8uQokQ8W9tR/pgc7YJn8F0x64dd7nQKxhbYHM1Qfg==
"@bazel/bazel-darwin_x64@0.28.1":
version "0.28.1"
resolved "https://registry.yarnpkg.com/@bazel/bazel-darwin_x64/-/bazel-darwin_x64-0.28.1.tgz#415658785e1dbd6f7ab5c8f2b98c1c99c614e1d5"
integrity sha512-VDKWmplAfa4uCAbkIQ5nRn04MFQqtsPNuc2HkluJ8OIum773yC2dPR+OlLBKxrlBuKJYB27TtbOwOa6w/uK7aw==
"@bazel/bazel-linux_x64@0.27.0":
version "0.27.0"
resolved "https://registry.yarnpkg.com/@bazel/bazel-linux_x64/-/bazel-linux_x64-0.27.0.tgz#2358292aa4901f526ba9b90874256f63d6d6608c"
integrity sha512-hO04v7C6M3Jf+qNlLE+IticZZKkkS7Nv6+pXDnENgFWrqLV2H93un6kNQnk83B0hP2cEqRQ8rw5yrIcqXNNuSQ==
"@bazel/bazel-linux_x64@0.28.1":
version "0.28.1"
resolved "https://registry.yarnpkg.com/@bazel/bazel-linux_x64/-/bazel-linux_x64-0.28.1.tgz#f78006089e17660261088272a0e04fc886572e34"
integrity sha512-n4XfNxagYhejQD32V4XSxT/qzuH1l/2jxslbKSak66/uQ+wad8Ew9rjNb4JUin3xtrfFtzmxx2jpQkybZsRVGA==
"@bazel/bazel-win32_x64@0.27.0":
version "0.27.0"
resolved "https://registry.yarnpkg.com/@bazel/bazel-win32_x64/-/bazel-win32_x64-0.27.0.tgz#0e5e498de5ccccc9a6cf481cd46904ee938ab6c2"
integrity sha512-7hIGNhdgaxRt9ceSOCs3eSTtCNi4GXz3nu6OjfgSp+QiqLbW/iAVWa8M8vD5aemZ1BSHek4/LISdWUTncLJk+w==
"@bazel/bazel-win32_x64@0.28.1":
version "0.28.1"
resolved "https://registry.yarnpkg.com/@bazel/bazel-win32_x64/-/bazel-win32_x64-0.28.1.tgz#60a2819618cf7582cc35ac16c01763a5e807b414"
integrity sha512-T4xksGfKikaHS4zxnGT6r5R436mz9j2lz//L1vc5sJnaEF/1e2Gv6MLl86vfZW2Xxo6iIEi6ntSzgYxP2Blohw==
"@bazel/bazel@0.27.0":
version "0.27.0"
resolved "https://registry.yarnpkg.com/@bazel/bazel/-/bazel-0.27.0.tgz#4e72c8e1cbb4da41022b6de1afe28731f5f58e09"
integrity sha512-yIj64IkesNzjHsoeehQUMBOgrCK/JMSuon5CvBqo6+izPXAmt+OW05uqaLL/FPAYAFQ2mHxsYtDsPxsM8DUbqA==
"@bazel/bazel@0.28.1":
version "0.28.1"
resolved "https://registry.yarnpkg.com/@bazel/bazel/-/bazel-0.28.1.tgz#3a6b9b7a74d566c66805242ccaa2f907592b5bff"
integrity sha512-s4bn5/vegEec66l15ZjyUe4jNybQ5J/cg9gFzR5f8deKj8lM+2WtCfvTLO3XfUe2pbrB4BG7C31jpyFPOC+6aw==
dependencies:
"@bazel/hide-bazel-files" latest
optionalDependencies:
"@bazel/bazel-darwin_x64" "0.27.0"
"@bazel/bazel-linux_x64" "0.27.0"
"@bazel/bazel-win32_x64" "0.27.0"
"@bazel/bazel-darwin_x64" "0.28.1"
"@bazel/bazel-linux_x64" "0.28.1"
"@bazel/bazel-win32_x64" "0.28.1"
"@bazel/buildifier-darwin_x64@0.26.0":
version "0.26.0"
@ -138,29 +140,29 @@
"@bazel/buildifier-linux_x64" "0.26.0"
"@bazel/buildifier-win32_x64" "0.26.0"
"@bazel/hide-bazel-files@0.32.2":
version "0.32.2"
resolved "https://registry.yarnpkg.com/@bazel/hide-bazel-files/-/hide-bazel-files-0.32.2.tgz#a482855eafbccb56b1fce0d92ff922c2c6e0a90c"
integrity sha512-585XY53mhMZaCjEQJ+aDqkmydWZbuXsKrZsSpoW9YeAVEH0poQY3YhdyCPmMVBo7/l1mkrqpFuOK5BpECfwdtA==
"@bazel/hide-bazel-files@latest":
version "0.34.0"
resolved "https://registry.yarnpkg.com/@bazel/hide-bazel-files/-/hide-bazel-files-0.34.0.tgz#368ea84db2756ff80ead23bb9eb179e9ed24b462"
integrity sha512-suyO6cZf8iV6W2LkM1X1spWBt7CsRRXH7gU1wYNuAuHYkkfI0A6qj84yPiIXiOt/2G44kbioGyC1bUsI3fKv7A==
"@bazel/ibazel@~0.9.0":
version "0.9.0"
resolved "https://registry.yarnpkg.com/@bazel/ibazel/-/ibazel-0.9.0.tgz#fd60023acd36313d304cc2f8c2e181b88b5445cd"
integrity sha512-E31cefDcdJsx/oii6p/gqKZXSVw0kEg1O73DD2McFcSvnf/p1GYWcQtVgdRQmlviBEytJkJgdX8rtThitRvcow==
"@bazel/jasmine@0.32.2":
version "0.32.2"
resolved "https://registry.yarnpkg.com/@bazel/jasmine/-/jasmine-0.32.2.tgz#6375b5b0de3f352c2b2280c54878dd30915fc139"
integrity sha512-izF9hBcbTOj1VhJVeo8G479dXo9KlibX0N6Yag15GaIk1fibW4iRyTBC2fy4ihm31CYIId6Zd9AABVShd+1Sgw==
"@bazel/jasmine@0.34.0":
version "0.34.0"
resolved "https://registry.yarnpkg.com/@bazel/jasmine/-/jasmine-0.34.0.tgz#74497def9766dee2c6b43e87ee288308d50bfd3f"
integrity sha512-vNUxQ1ss0aT7S3CQvQ6U6vJF8H+Cg/jr7kVUCesHQNYaNKqxwZOlZ8cevR/xUKRTcltE6PeJA+Ezgm5mP7sckg==
dependencies:
jasmine "~3.3.1"
jasmine-core "~3.3.0"
jasmine "~3.4.0"
jasmine-core "~3.4.0"
v8-coverage "1.0.9"
"@bazel/karma@0.32.2":
version "0.32.2"
resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-0.32.2.tgz#0f6adf0cf1970c50cfdcf9cb2b10a8d3e21731fe"
integrity sha512-iWb8aqE+llpZhlreDweM7llwnSAQ9QTYdz4VvIcZBGVD0KtHxHaKiqK4Zo4Qrmr9H0kcOhT7nvRBg3QOUJVrUw==
"@bazel/karma@0.34.0":
version "0.34.0"
resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-0.34.0.tgz#ee468501a408244a2c1844b48ca5a938874d9444"
integrity sha512-9EziieE3Zkf7D5tBuX4rO+hhpI4ypNAWReiO/fykjj5oYpLYhhhGGUyFQ8PCIfduPcGZooCTMsctmwZJUb3rRA==
dependencies:
jasmine-core "2.8.0"
karma "^4.0.0"
@ -174,10 +176,17 @@
semver "5.6.0"
tmp "0.0.33"
"@bazel/typescript@0.32.2":
version "0.32.2"
resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-0.32.2.tgz#c296bb44cb6362a0e3a08ca88752852bc9591ecf"
integrity sha512-32zDyvHdYjIa63vtImhl6wy5ErOFVWPkjMT2T035D0UPSKI1tvENW/bRZ3QFlFHqfmJZRBpaI3GiUpO3vUvzmw==
"@bazel/protractor@0.34.0":
version "0.34.0"
resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-0.34.0.tgz#af166306518bf1319e8ca255f798712c8714b5e9"
integrity sha512-U6O8hRlerkQ/WfnEVct1yipVQr5epdYaLiOW1eLpmiRMM4RuMhIpIyKkpum5xqFlYP5kwqwje8BS8NHvBfvZnQ==
dependencies:
protractor "^5.4.2"
"@bazel/typescript@0.34.0":
version "0.34.0"
resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-0.34.0.tgz#ca0fdf15343a930fc1418dbbf7d6cae49e6bc89b"
integrity sha512-GXVSADXdbPyWLskIYAzQsBB1LhZgWF5+M6WCQGOvRWjZfXgRP5QDG5pKJavRGzVd6ofigLPA1xT6Vc7dUEDNtg==
dependencies:
protobufjs "6.8.8"
semver "5.6.0"
@ -947,7 +956,7 @@ ansi-align@^2.0.0:
ansi-colors@^1.0.1:
version "1.1.0"
resolved "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9"
resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9"
integrity sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==
dependencies:
ansi-wrap "^0.1.0"
@ -2498,7 +2507,7 @@ compression@^1.7.0:
compression@~1.5.2:
version "1.5.2"
resolved "http://registry.npmjs.org/compression/-/compression-1.5.2.tgz#b03b8d86e6f8ad29683cba8df91ddc6ffc77b395"
resolved "https://registry.npmjs.org/compression/-/compression-1.5.2.tgz#b03b8d86e6f8ad29683cba8df91ddc6ffc77b395"
integrity sha1-sDuNhub4rSloPLqN+R3cb/x3s5U=
dependencies:
accepts "~1.2.12"
@ -3708,7 +3717,7 @@ event-emitter@^0.3.5, event-emitter@~0.3.5:
event-stream@^3.1.5, event-stream@^3.3.2:
version "3.3.4"
resolved "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
resolved "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
integrity sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=
dependencies:
duplexer "~0.1.1"
@ -6112,7 +6121,7 @@ jasmine-core@^3.1.0:
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.1.0.tgz#a4785e135d5df65024dfc9224953df585bd2766c"
integrity sha1-pHheE11d9lAk38kiSVPfWFvSdmw=
jasmine-core@^3.3:
jasmine-core@^3.3, jasmine-core@~3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.4.0.tgz#2a74618e966026530c3518f03e9f845d26473ce3"
integrity sha512-HU/YxV4i6GcmiH4duATwAbJQMlE0MsDIR5XmSVxURxKHn3aGAdbY1/ZJFmVRbKtnLwIxxMJD7gYaPsypcbYimg==
@ -6131,7 +6140,7 @@ jasmine@2.8.0:
glob "^7.0.6"
jasmine-core "~2.8.0"
jasmine@^3.1.0, jasmine@~3.3.1:
jasmine@^3.1.0:
version "3.3.1"
resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-3.3.1.tgz#d61bb1dd8888859bd11ea83074a78ee13d949905"
integrity sha512-/vU3/H7U56XsxIXHwgEuWpCgQ0bRi2iiZeUpx7Nqo8n1TpoDHfZhkPIc7CO8I4pnMzYsi3XaSZEiy8cnTfujng==
@ -6139,6 +6148,14 @@ jasmine@^3.1.0, jasmine@~3.3.1:
glob "^7.0.6"
jasmine-core "~3.3.0"
jasmine@~3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-3.4.0.tgz#0fa68903ff0c9697459cd044b44f4dcef5ec8bdc"
integrity sha512-sR9b4n+fnBFDEd7VS2el2DeHgKcPiMVn44rtKFumq9q7P/t8WrxsVIZPob4UDdgcDNCwyDqwxCt4k9TDRmjPoQ==
dependencies:
glob "^7.1.3"
jasmine-core "~3.4.0"
jasminewd2@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.2.0.tgz#e37cf0b17f199cce23bea71b2039395246b4ec4e"