Compare commits

..

146 Commits

Author SHA1 Message Date
67789f10ef release: cut the v7.1.0-beta.0 release 2018-10-24 14:47:20 -07:00
b83f1300bd docs: release notes for the v7.0.1 release 2018-10-24 14:42:37 -07:00
6e16a17015 ci(docs-infra): fix deployment script (#26731)
PR Close #26731
2018-10-24 13:20:53 -07:00
d744dd70e0 build: downgrade yarn.lock file to bazel generated version 2018-10-24 12:58:02 -07:00
4e91ead40b style: format (#26708)
PR Close #26708
2018-10-24 12:13:46 -07:00
7f39f37003 fix(bazel): support --nolegacy_external_runfiles in protractor rule (#26708)
PR Close #26708
2018-10-24 12:13:46 -07:00
bf9ab53f12 build(ivy): fix typo in build file 2018-10-24 10:07:49 -07:00
d99f661af7 build(ivy): properly tag the js_expected_symbol_test rules
Previously the rules were tagged ivy-only, but missing the ivy-aot tag
which would cause them to run under CI.
2018-10-24 10:04:06 -07:00
5d58a31d86 fix(ivy): rename broken reflect_metadata switch file
This file was missed during the rename of the --define=compile
flag value from 'local' to 'aot. It's referenced as
reflect_metadata_${compile}.
2018-10-24 09:53:10 -07:00
07b89902d5 ci: don't publish ivy build artifacts on a non-master branch 2018-10-23 15:31:55 -07:00
ce6948fc1b ci(docs-infra): remove jobs from Travis config (#26377)
PR Close #26377
2018-10-23 14:35:38 -07:00
38d626a3fa ci(docs-infra): move deployment to CircleCI (#26377)
PR Close #26377
2018-10-23 14:35:38 -07:00
9b8a244a15 ci: fix payload-size.sh (#26377)
PR Close #26377
2018-10-23 14:35:38 -07:00
1bbf28ad19 ci(docs-infra): add jobs to CircleCI config (#26377)
PR Close #26377
2018-10-23 14:35:37 -07:00
3b24e0edb6 build: use CI-provider independent variable names (#26377)
PR Close #26377
2018-10-23 14:35:37 -07:00
b647608c96 test(elements): make e2e tests for elements docs examples less flaky (#26377)
PR Close #26377
2018-10-23 14:35:37 -07:00
31c462ae3f test(animations): make e2e tests for animations docs examples less flaky (#26377)
PR Close #26377
2018-10-23 14:35:37 -07:00
da39fd70d2 test(docs-infra): improve logging output in test-pwa-score[-localhost] (#26377)
PR Close #26377
2018-10-23 14:35:37 -07:00
ee0b857172 build: rename the ivy compile mode 'local' to 'aot' (#26686)
PR Close #26686
2018-10-23 14:14:49 -07:00
e0d6782d26 build: add test-ivy-jit, test-fixme-ivy-jit, test-ivy-aot and test-fixme-ivy-aot yarn scripts (#26686)
PR Close #26686
2018-10-23 14:14:49 -07:00
2f9e957523 ci: re-encrypt .circleci/github_token (#26698)
PR Close #26698
2018-10-23 13:31:48 -07:00
38dbae9ca0 build: fix BUILD file formatting 2018-10-23 12:29:26 -07:00
5a3077f46c ci: fix broken master branch due to conflicting merges (#26697)
PR Close #26697
2018-10-23 12:28:35 -07:00
d0cc019c1a ci: re-encrypt github publish token with recent ngcontainer (#26692)
Something about the docker image changed such that the encrypted value is different

PR Close #26692
2018-10-23 12:00:20 -07:00
26e8032bd0 docs: update npm packages to be accurate for v7 (#26422)
PR Close #26422
2018-10-23 08:58:43 -07:00
84af7b065d docs(service-worker): Specify format of datagroups.cacheConfig.timeout (#26469)
Fixes #26454

PR Close #26469
2018-10-23 08:58:17 -07:00
83dc3c0ee0 build: add config_env_vars = ["compile"] to ngc-wrapped (#26471)
PR Close #26471
2018-10-23 08:57:42 -07:00
5952775a03 ci: build-packages-dist.sh should publish only regular and --compile=local packages (#26471)
We don't need to publish JIT compiled packages as this is not useful for real-world use-cases.

PR Close #26471
2018-10-23 08:57:42 -07:00
57531737e5 build: add source-map-support to various rules within our repo (#26471)
This removes an verbose warning and adds source-mapping support to our build/ci.

Related issue: https://github.com/bazelbuild/rules_nodejs/issues/389

PR Close #26471
2018-10-23 08:57:42 -07:00
3fd50f07fd build: add aio/node_modules to the .bazelignore file (#26471)
PR Close #26471
2018-10-23 08:57:42 -07:00
4237c34c78 test(ivy): mark failing test targets with fixme-ivy-jit and fixme-ivy-local tags (#26471)
We are close enough to blacklist a few test targets, rather than whitelist targets to run...

Because bazel rules can be composed of other rules that don't inherit tags automatically,
I had to explicitly mark all of our ts_library and ng_module targes with "ivy-local" and
"ivy-jit" tags so that we can create a query that excludes all fixme- tagged targets even
if those targets are composed of other targets that don't inherit this tag.

This is the updated overview of ivy related bazel tags:

- ivy-only: target that builds or runs only under ivy
- fixme-ivy-jit: target that doesn't yet build or run under ivy with --compile=jit
- fixme-ivy-local: target that doesn't yet build or run under ivy with --compile=local
- no-ivy-jit: target that is not intended to build or run under ivy with --compile=jit
- no-ivy-local: target that is not intended to build or run under ivy with --compile=local

PR Close #26471
2018-10-23 08:57:42 -07:00
361eaf1888 build: remove obsolete files (#26471)
PR Close #26471
2018-10-23 08:57:41 -07:00
cca89ec36e docs: reorganize events to highlight recent events before older events and move mix to past (#26551)
PR Close #26551
2018-10-23 08:56:52 -07:00
e4c7f369f2 docs: add Brian Love to GDE resources (#26594)
PR Close #26594
2018-10-23 08:54:41 -07:00
d573a14119 fix(ivy): update tree benchmark to use ngIf (#26608)
PR Close #26608
2018-10-23 08:53:19 -07:00
ff767dd153 fix(ivy): support ViewContainerRef ng-container children (#26646)
Issue found while running NgPlural tests with ivy

PR Close #26646
2018-10-23 08:52:30 -07:00
34c6ce6b08 docs: update release info now that v7 is released (#26660)
PR Close #26660
2018-10-23 08:51:48 -07:00
6737e91974 docs(core): fix spelling in ComponentFactory (#26603)
PR Close #26603
2018-10-22 10:38:56 -07:00
1006eab482 fix(ivy): update largetable benchmark to use ngFor (#26604)
PR Close #26604
2018-10-22 10:37:02 -07:00
a9f2952882 build(ivy): fix benchmarks (#26601)
PR Close #26601
2018-10-22 10:36:31 -07:00
100c7eff25 build: fix ivy package-dist generation (#26629)
PR Close #26629
2018-10-20 21:03:46 -07:00
dc7349915d build(bazel): fix //tools/testing:node target deps (#26629)
PR Close #26629
2018-10-20 21:03:46 -07:00
213c25fb08 build: remove manual tags from platform jasmine tests (#26606)
PR Close #26606
2018-10-19 22:52:12 -07:00
615a515bba build: run CI (#26488)
PR Close #26488
2018-10-19 20:59:29 -07:00
838a3f204f style: ran buildifier (#26488)
PR Close #26488
2018-10-19 20:59:29 -07:00
15c2467dbd build: review comments addressed (#26488)
PR Close #26488
2018-10-19 20:59:29 -07:00
74ea4e9b5d style: run buildifier (#26488)
PR Close #26488
2018-10-19 20:59:29 -07:00
4481571999 ci: don't run google3 tests on bazel external files (#26488)
PR Close #26488
2018-10-19 20:59:29 -07:00
2132c8f461 refactor(bazel): allow google3 overrides for external deps (#26488)
PR Close #26488
2018-10-19 20:59:29 -07:00
2b3cac5b31 build: add comment to /integration/bazel/package.json (#26488)
PR Close #26488
2018-10-19 20:59:29 -07:00
8d5e3e6981 build: update to rules_typescript 0.20.3 and rules_nodejs 0.15.1 (#26488)
PR Close #26488
2018-10-19 20:59:29 -07:00
30f1dc002a build: add npm deps after rebase (#26488)
PR Close #26488
2018-10-19 20:59:29 -07:00
5da3b00222 build: restore integrity lines in yarn.lock (#26488)
PR Close #26488
2018-10-19 20:59:29 -07:00
631998b2df build: idiomatic install of @angular/bazel npm package (#26258) (#26488)
PR Close #26488
2018-10-19 20:59:29 -07:00
30d6233e83 build: update ngcontainer to bazel 0.18.0 (#26465) (#26488)
* build: update ngcontainer to bazel 0.18.0

* build: update skylint to bazel 0.18

use .bazelignore file to ignore node_modules directory

PR Close #26488
2018-10-19 20:59:29 -07:00
6468711e16 build(bazel): update to rules_typescript 0.20.2 (#26279) (#26488)
PR Close #26488
2018-10-19 20:59:29 -07:00
d698b0eadf build: update to rules_typescript 0.20.1 and rules_nodejs 0.15.0 (#26260) (#26488)
PR Close #26488
2018-10-19 20:59:29 -07:00
1f3331f5e6 build(bazel): use fine-grained npm deps (#26111) (#26488)
PR Close #26488
2018-10-19 20:59:29 -07:00
b6c9678f21 build: introduce a package.bzl (#26488)
This lets Angular Bazel users install our transitive deps, rather than have to list them in their WORKSPACE file.
If they want a different version of one of these deps, they just need to install it before calling rules_angular_dependencies.

PR Close #26488
2018-10-19 20:59:29 -07:00
4c2ce4e8ba docs: update animations to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:53 -07:00
bb0f95b6fb docs: update elements to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:53 -07:00
853faf4c71 docs: update upgrade to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:53 -07:00
00c7db02d1 docs: update service-worker to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:53 -07:00
13143b850e docs: update router to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:53 -07:00
c1724062f1 docs: update platform-webworker to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:53 -07:00
7570f7222f docs: update platform-server to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:53 -07:00
f1e3d5125d docs: update platform-browser-dynamic to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:53 -07:00
3511f08a81 docs: update http with @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:53 -07:00
982bc7f2aa docs: update forms with @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:53 -07:00
3903e5ebe7 docs: update core to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:53 -07:00
0918adf39d docs: common with @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:53 -07:00
42c331bbf2 docs: update animations with @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:53 -07:00
0bae97a726 docs: update platform-browser with @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:52 -07:00
c5949f85ef build: update ts-api-guardian jsdoc tag requirements (#26595)
Now `@experimental` tags are banned; and `@publicApi`
tags are required on exports.

PR Close #26595
2018-10-19 14:35:52 -07:00
24521f549c docs: convert all @experimental tags to @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:52 -07:00
4bd9f53e8f feat(docs-infra): rename tagdef: @experimental to @publicApi (#26595)
PR Close #26595
2018-10-19 14:35:52 -07:00
2a78dcbd5a feat(docs-infra): remove stable & experimental from status selector (#26595)
PR Close #26595
2018-10-19 14:35:52 -07:00
2ea57cdcc3 build: refactor ts-api-guardian jsdoc tag handling (#26595)
Allow the jsdoc tag processing to be configured by
type (export, member, param) and by action (required,
banned, toCopy).

This is a pre-requisite to moving over to using `@publicApi`
tags rather than `@stable` and `@experimental`.

PR Close #26595
2018-10-19 14:35:52 -07:00
31022cbecf feat(ivy): generate .ngsummary.js shims (#26495)
This commit adds generation of .ngsummary.js shims alongside .ngfactory.js
shims when generated files are enabled.

Generated .ngsummary shims contain a single, null export for every exported
class with decorators that exists in the original source files. Ivy code
does not depend on summaries, so these exist only as a placeholder to allow
them to be imported and their values passed to old APIs. This preserves
backwards compatibility.

Testing strategy: this commit adds a compiler test to verify the correct
shape and contents of the generated .ngsummary.js files.

PR Close #26495
2018-10-19 13:30:02 -07:00
ce8053103e refactor(ivy): make shim generation generic in ngtsc (#26495)
This commit refactors the shim host to be agnostic to the shims being
generated, and provides an API for generating additional shims besides
the .ngfactory.js. This will be used in a following commit to generate
.ngsummary.js shims.

Testing strategy: this refactor introduces no new behavior, so it's
sufficient that the existing tests for factory shim generation continue
to pass.

PR Close #26495
2018-10-19 13:30:01 -07:00
0b885ecaf7 refactor(ivy): rename ngtsc/factories to ngtsc/shims (#26495)
This simple refactor of the build rules renames the .ngfactory.js shim
generator to 'shims' instead of 'factories', in preparation for adding
.ngsummary.js shim generation.

Testing strategy: this commit does not introduce any new behavior and
merely moves files and symbols around. It's sufficient that the existing
ngtsc tests pass.

PR Close #26495
2018-10-19 13:30:01 -07:00
1700bd6f08 docs: fix release info navigation (#26558)
PR Close #26558
2018-10-19 11:30:39 -07:00
b89bc37170 fix(docs-infra): correct the version of @angular-devkit/build-angular (#26555)
This dependency has not been correctly updated and I had to update it manually.

I think the issue is related to https://github.com/angular/angular-cli/issues/12624 which was fixed between CLI RCs and final.

PR Close #26555
2018-10-19 11:30:11 -07:00
39df4dbde7 feat(docs-infra): update to @angular/* v7 (#26555)
PR Close #26555
2018-10-19 11:30:11 -07:00
716d887e51 docs: add Katerina Skroumpelou to GDE resources (#26547)
PR Close #26547
2018-10-19 11:29:13 -07:00
5b4cf38166 refactor(bazel): remove workaround for TS bug (#26516)
PR Close #26516
2018-10-19 11:14:24 -07:00
4c0ad5238e build(docs-infra): display github links in CLI API docs (#26515)
This commit includes the following changes:

* CLI version information is read from the CLI package from which
  we read the help files.
* CLI API pages now contain GH links
* line numbers are not shown in GH links, if the doc does not
  have a truthy `startingLine` value. This allows us to remove
  hard coded checks for `guide` pages
* content pages and CLI api docs no longer have a `startingLine`
* the hard-coded `packages` path segment has been removed from
  the templates; instead we now only use the `realProjectRelativePath`.
* the `realProjectRelativePath` has been updated accordingly for API
  and CLI API docs.

PR Close #26515
2018-10-19 11:12:54 -07:00
9e8903ada1 build(docs-infra): show github edit link on CLI overview (#26515)
PR Close #26515
2018-10-19 11:12:53 -07:00
aa55d88408 docs: forms overview copy edit (#26450)
PR Close #26450
2018-10-19 11:08:47 -07:00
07fc4c2464 docs(service-worker): updated browser support for Service Worker (#26408)
PR Close #26408
2018-10-19 11:08:00 -07:00
b9bd95b3b2 build(docs-infra): break long CLI options onto two lines (#26272)
PR Close #26272
2018-10-19 11:07:30 -07:00
3f89aeb80a build(docs-infra): update CLI option rendering (#26272)
PR Close #26272
2018-10-19 11:07:30 -07:00
6c530d3a85 build(docs-infra): render CLI arguments consistently (#26272)
In the command syntax, arguments are rendered as
`var`s enclosed in angle brackets. So this is now repeated
in the arguments table too.

PR Close #26272
2018-10-19 11:07:30 -07:00
03bf0d6b41 docs(ivy): update status for i18n (#26502)
PR Close #26502
2018-10-19 11:06:25 -07:00
d4cee514f6 refactor(ivy): obviate the Bazel component of the ivy_switch (#26550)
Originally, the ivy_switch mechanism used Bazel genrules to conditionally
compile one TS file or another depending on whether ngc or ngtsc was the
selected compiler. This was done because we wanted to avoid importing
certain modules (and thus pulling them into the build) if Ivy was on or
off. This mechanism had a major drawback: ivy_switch became a bottleneck
in the import graph, as it both imports from many places in the codebase
and is imported by many modules in the codebase. This frequently resulted
in cyclic imports which caused issues both with TS and Closure compilation.

It turns out ngcc needs both code paths in the bundle to perform the switch
during its operation anyway, so import switching was later abandoned. This
means that there's no real reason why the ivy_switch mechanism needed to
operate at the Bazel level, and for the ivy_switch file to be a bottleneck.

This commit removes the Bazel-level ivy_switch mechanism, and introduces
an additional TypeScript transform in ngtsc (and the pass-through tsc
compiler used for testing JIT) to perform the same operation that ngcc
does, and flip the switch during ngtsc compilation. This allows the
ivy_switch file to be removed, and the individual switches to be located
directly next to their consumers in the codebase, greatly mitigating the
circular import issues and making the mechanism much easier to use.

As part of this commit, the tag for marking switched variables was changed
from __PRE_NGCC__ to __PRE_R3__, since it's no longer just ngcc which
flips these tags. Most variables were renamed from R3_* to SWITCH_* as well,
since they're referenced mostly in render2 code.

Test strategy: existing test coverage is more than sufficient - if this
didn't work correctly it would break the hello world and todo apps.

PR Close #26550
2018-10-19 09:23:05 -07:00
331989cea3 docs: add release announcement URL 2018-10-18 13:29:04 -07:00
bbf96db2f2 feat(docs-infra): add v6 to the aio version picker 2018-10-18 12:38:29 -07:00
72c2578d14 docs: fix incomplete sentence in CHANGELOG.md 2018-10-18 12:02:19 -07:00
1a666dea61 ci: add forms-overview guide to forms approval list (#26549)
PR Close #26549
2018-10-18 12:01:15 -07:00
7634c1cb31 docs: fix links to browserlist (#26531)
PR Close #26531
2018-10-18 12:00:38 -07:00
95914a0fbf docs: update http to https where possible (#26509)
PR Close #26509
2018-10-18 11:57:57 -07:00
9c50891d6e docs: update links to Karma homepage (#26509)
PR Close #26509
2018-10-18 11:57:57 -07:00
624433c51d docs: removing errant double-quote (#26483)
PR Close #26483
2018-10-18 11:57:27 -07:00
09cc458bfc docs: type fix (#26386)
according to the source code and the doc https://angular.io/api/forms/NgModel#inherited-from-formsngcontrol-1, the method name should be "viewToModelUpdate" instead of "viewToModel"
PR Close #26386
2018-10-18 11:56:51 -07:00
efe0c5f371 release: cut the v7.0.0 release 2018-10-18 10:51:21 -07:00
d9d226087c build(docs-infra): allow "" as empty region in {@example} tags (#26514)
PR Close #26514
2018-10-18 09:54:17 -07:00
7bad1d356d build(docs-infra): only render code example content in one place (#26514)
PR Close #26514
2018-10-18 09:54:17 -07:00
0add00a743 build(docs-infra): throw error if using title on code snippets (#26514)
Since #26396, the `title` property is ignored and `header` should be
used instead for specifying a code snippet's header.

This commit ensures that we don't accidentally set `title` have it be
silently ignored.

PR Close #26514
2018-10-18 09:54:17 -07:00
d557f1d9de build(docs-infra): update git ref for cli command docs (#26545)
This is to get the latest changes done in https://github.com/angular/angular-cli/pull/12634

PR Close #26545
2018-10-18 09:54:00 -07:00
665627e254 fix(aio): add relative to app level routes section (#26504)
Added word *relative* to the **Routes at the app level** section description. This was not specified before. The routes in the *lazy-loading-ngmodules/src/app/app-routing.module.ts* also had `loadChildren` values starting with `app/...`.

The code for `app-routing.module.ts` is already fixed in [this commit](67ad9468d3)
PR Close #26504
2018-10-17 13:11:42 -07:00
a609bf50ed docs: fix formatting of PULL_REQUEST_TEMPLATE.md (#26512)
This change enables developers to check the checkboxes or update them
after they submitted a PR.

PR Close #26512
2018-10-17 13:09:45 -07:00
f8195e5e3d fix(ivy): stub TestBed.compileComponents implementation (#26506)
PR Close #26506
2018-10-17 13:08:14 -07:00
65b209359a build(docs-infra): update git ref for cli command docs (#26497)
Update for version 7 release

PR Close #26497
2018-10-17 11:24:19 -07:00
3a65c9ad4e docs: Update link to angular-cli repo (#26497)
PR Close #26497
2018-10-17 11:24:19 -07:00
77e58c6179 docs: update contributing page (#26497)
PR Close #26497
2018-10-17 11:24:19 -07:00
23d625172a docs: update continuous integration story (#26497)
PR Close #26497
2018-10-17 11:24:19 -07:00
c3643615fc docs: replace alert-is-helpful with alert is-helpful (#26497)
PR Close #26497
2018-10-17 11:24:19 -07:00
638aaecc7d docs: add missing backticks (#26497)
PR Close #26497
2018-10-17 11:24:19 -07:00
5a79decba4 docs: remove for example code (#26519)
PR Close #26519
2018-10-17 11:23:50 -07:00
225162aa6c docs: edit file structure guide (#26256)
PR Close #26256
2018-10-17 11:08:37 -07:00
a43b80a4c9 ci: add triage PRs config for the ngbot (#26477)
PR Close #26477
2018-10-17 11:07:36 -07:00
beebf7fe14 docs: change links to cli wiki to link to new aio docs (#26489)
PR Close #26489
2018-10-17 11:06:34 -07:00
0ef1f7ef0d docs: change links to cli wiki to link to new aio docs files m to z (#26492)
PR Close #26492
2018-10-17 11:06:07 -07:00
fc6dad40ac fix(docs-infra): rename "title" by "header" to avoid unwanted tooltips (#26396)
Closes #26174

PR Close #26396
2018-10-17 11:05:29 -07:00
ecd473bbce fix(docs-infra): don't hide contributor links on devices that cannot hover (#26410)
Fixes #16690

PR Close #26410
2018-10-17 11:04:35 -07:00
8a3fd58cad feat(ivy): i18n compiler support for i18nStart and i18nEnd instructions (#26442)
PR Close #26442
2018-10-17 11:03:52 -07:00
8024857d4c feat(ivy): i18n compiler support for element attributes (#26442)
PR Close #26442
2018-10-17 11:03:52 -07:00
3fa876c5e7 fix(docs-infra): fix top menu logo position (#26473)
Fixes #26468

PR Close #26473
2018-10-17 11:03:23 -07:00
516515d9e3 build(docs-infra): do not add extra space after links in tables (#26505)
Closes #26487

PR Close #26505
2018-10-17 11:02:56 -07:00
948f507ba0 docs(forms): change headings (#25900)
Update heading level so it will appear in the TOC.
PR Close #25900
2018-10-16 20:39:45 -07:00
81a8ee1ddb docs(forms): change headings (#25900)
Remove "Form" sub-heading & move intro to template-driven form heading.
PR Close #25900
2018-10-16 20:39:45 -07:00
5e58da14f0 docs(forms): change headings (#25900)
Change the headings of the template-driven forms guide page.

This makes the first heading consistent with other guide pages and the menu label reducing confusion to users browsing the guide.
PR Close #25900
2018-10-16 20:39:45 -07:00
fa8e633be5 feat(ivy): enhance [style] and [class] bindings to be animation aware (#26096)
PR Close #26096
2018-10-16 20:39:19 -07:00
be337a2e52 refactor(ivy): move styling files around (#26096)
PR Close #26096
2018-10-16 20:39:18 -07:00
4d164b6ca4 fix(ivy): make defineComponent tree shakable by Closure Compiler (#26425)
PR Close #26425
2018-10-16 20:37:35 -07:00
371ffef4ce test(ivy): enable unit tests for @angular/animations (#26470)
PR Close #26470
2018-10-16 20:31:56 -07:00
fdfedceeec feat(router): add prioritizedGuardValue operator optimization and allowing UrlTree return from guard (#26478)
* If all guards return `true`, operator returns `true`
* `false` and `UrlTree` are now both valid returns from a guard
* Both these values wait for higher priority guards to resolve
* Highest priority `false` or `UrlTree` value will be returned

PR Close #26478
2018-10-16 20:31:32 -07:00
9e5d440a0b refactor(ivy): handle animation metadata normalization in the compiler (#26481)
PR Close #26481
2018-10-16 20:31:04 -07:00
0f7d2ca7a8 build: add more labels to review-pr script (#26493)
PR Close #26493
2018-10-16 14:36:28 -07:00
81c9720acb docs: fix links to setup and cli docs (#26463)
PR Close #26463
2018-10-16 14:14:19 -07:00
ea2cfbbd2e docs: remove setup for local dev and anatomy of setup docs from nav (#26380)
PR Close #26380
2018-10-16 14:14:00 -07:00
2326b9c294 fix(service-worker): clean up caches from old SW versions (#26319)
Since the SW immediately takes over all clients, it is safe to delete
caches used by older (e.g. beta) `@angular/service-worker` versions to
avoid running into browser storage quota limitations.

PR Close #26319
2018-10-16 14:12:07 -07:00
41de0e0d98 docs: overview for cli reference section (#26043)
PR Close #26043
2018-10-16 14:11:26 -07:00
f6a2dbf4f5 docs: updated text to match the Getting started guide (#26421)
PR Close #26421
2018-10-16 14:11:12 -07:00
b115374601 build: fix deps for running modules/benchmarks/src/largetable/render3:perf (#26482)
PR Close #26482
2018-10-16 14:10:55 -07:00
7d82053117 docs(ivy): i18n design (#26091)
PR Close #26091
2018-10-16 14:08:01 -07:00
90 changed files with 1540 additions and 1394 deletions

View File

@ -132,8 +132,6 @@ jobs:
<<: *job_defaults
resource_class: xlarge
steps:
# don't run this job on the patch branch (to preserve resources)
- run: circleci step halt
- *define_env_vars
- checkout:
<<: *post_checkout
@ -147,8 +145,6 @@ jobs:
<<: *job_defaults
resource_class: xlarge
steps:
# don't run this job on the patch branch (to preserve resources)
- run: circleci step halt
- *define_env_vars
- checkout:
<<: *post_checkout

View File

@ -1,3 +1,21 @@
<a name="7.1.0-beta.0"></a>
# [7.1.0-beta.0](https://github.com/angular/angular/compare/7.0.0-rc.1...7.1.0-beta.0) (2018-10-24)
### Bug Fixes
* **core:** allow null value for renderer setElement(…) ([#17065](https://github.com/angular/angular/issues/17065)) ([ff15043](https://github.com/angular/angular/commit/ff15043)), closes [#13686](https://github.com/angular/angular/issues/13686)
* **router:** fix regression where navigateByUrl promise didn't resolve on CanLoad failure ([#26455](https://github.com/angular/angular/issues/26455)) ([1c9b065](https://github.com/angular/angular/commit/1c9b065)), closes [#26284](https://github.com/angular/angular/issues/26284)
* **service-worker:** clean up caches from old SW versions ([#26319](https://github.com/angular/angular/issues/26319)) ([2326b9c](https://github.com/angular/angular/commit/2326b9c))
* **upgrade:** properly destroy upgraded component elements and descendants ([#26209](https://github.com/angular/angular/issues/26209)) ([071934e](https://github.com/angular/angular/commit/071934e)), closes [#26208](https://github.com/angular/angular/issues/26208)
### Features
* **router:** add prioritizedGuardValue operator optimization and allowing UrlTree return from guard ([#26478](https://github.com/angular/angular/issues/26478)) ([fdfedce](https://github.com/angular/angular/commit/fdfedce))
<a name="7.0.1"></a>
## [7.0.1](https://github.com/angular/angular/compare/7.0.0...7.0.1) (2018-10-24)

View File

@ -76,7 +76,7 @@ See also: [`//.bazelrc`](https://github.com/angular/angular/blob/master/.bazelrc
- `--config=debug`: build and launch in debug mode (see [debugging](#debugging) instructions below)
- `--test_arg=--node_options=--inspect=9228`: change the inspector port.
- `--define=compile=<option>` Controls if ivy or legacy mode is enabled. This is done by generating the [`src/ivy_switch.ts`](https://github.com/angular/angular/blob/master/packages/core/src/ivy_switch.ts) file from [`ivy_switch_legacy.ts`](https://github.com/angular/angular/blob/master/packages/core/src/ivy_switch_legacy.ts) (default), [`ivy_switch_jit.ts`](https://github.com/angular/angular/blob/master/packages/core/src/ivy_switch_jit.ts), or [`ivy_switch_local.ts`](https://github.com/angular/angular/blob/master/packages/core/src/ivy_switch_local.ts).
- `--define=compile=<option>` Controls if ivy or legacy mode is enabled. This switches which compiler is used (ngc, ngtsc, or a tsc pass-through mode).
- `legacy`: (default behavior) compile against View Engine, e.g. `--define=compile=legacy`
- `jit`: Compile in ivy JIT mode, e.g. `--define=compile=jit`
- `local`: Compile in ivy AOT move, e.g. `--define=compile=local`

View File

@ -17,10 +17,10 @@ ivy-ngcc
ls node_modules/@angular/common | grep __modified_by_ngcc_for_esm2015
if [[ $? != 0 ]]; then exit 1; fi
# Did it replace the NGCC_PRE markers correctly?
grep "= R3_COMPILE_COMPONENT__POST_NGCC__" node_modules/@angular/core/fesm2015/core.js
# Did it replace the PRE_R3 markers correctly?
grep "= SWITCH_COMPILE_COMPONENT__POST_R3__" node_modules/@angular/core/fesm2015/core.js
if [[ $? != 0 ]]; then exit 1; fi
grep "= R3_COMPILE_COMPONENT__POST_NGCC__" node_modules/@angular/core/fesm5/core.js
grep "= SWITCH_COMPILE_COMPONENT__POST_R3__" node_modules/@angular/core/fesm5/core.js
if [[ $? != 0 ]]; then exit 1; fi
# Did it compile @angular/core/ApplicationModule correctly?

View File

@ -56,15 +56,6 @@ describe('largetable benchmark perf', () => {
}).then(done, done.fail);
});
it('should run for render3', done => {
runTableBenchmark({
id: `largeTable.render3.${worker.id}`,
url: 'all/benchmarks/src/largetable/render3/index.html',
ignoreBrowserSynchronization: true,
worker: worker
}).then(done, done.fail);
});
it('should run for iv', done => {
runTableBenchmark({
id: `largeTable.iv.${worker.id}`,

View File

@ -25,13 +25,6 @@ describe('largetable benchmark spec', () => {
});
});
it('should work for render3', () => {
testTableBenchmark({
url: 'all/benchmarks/src/largetable/render3/index.html',
ignoreBrowserSynchronization: true,
});
});
it('should work for iv', () => {
testTableBenchmark({
url: 'all/benchmarks/src/largetable/iv/index.html',

View File

@ -49,12 +49,6 @@ export const Benchmarks: Benchmark[] = [
url: 'all/benchmarks/src/tree/ng2_switch/index.html',
buttons: CreateDestroyButtons,
},
{
id: `deepTree.ng2.render3`,
url: 'all/benchmarks/src/tree/render3/index.html',
buttons: CreateDestroyDetectChangesButtons,
ignoreBrowserSynchronization: true,
},
{
id: `deepTree.ng2.render3_function`,
url: 'all/benchmarks/src/tree/render3_function/index.html',

View File

@ -8,6 +8,7 @@
import {$} from 'protractor';
import {openBrowser} from '../../../e2e_util/e2e_util';
import {runBenchmark, verifyNoBrowserErrors} from '../../../e2e_util/perf_util';
interface Worker {
@ -39,9 +40,23 @@ describe('largetable benchmark perf', () => {
afterEach(verifyNoBrowserErrors);
it('should render the table for render3', () => {
openBrowser({
url: '',
ignoreBrowserSynchronization: true,
params: [{name: 'cols', value: 5}, {name: 'rows', value: 5}],
});
$('#createDom').click();
expect($('#root').getText()).toContain('0/0');
$('#createDom').click();
expect($('#root').getText()).toContain('A/A');
$('#destroyDom').click();
expect($('#root').getText() as any).toEqual('');
});
[CreateOnlyWorker, CreateAndDestroyWorker, UpdateWorker].forEach((worker) => {
describe(worker.id, () => {
it('should run for render3', done => {
it('should run benchmark for render3', done => {
runTableBenchmark({
id: `largeTable.render3.${worker.id}`,
url: 'index.html',

View File

@ -1,10 +1,10 @@
package(default_visibility = ["//visibility:public"])
load("//tools:defaults.bzl", "ng_rollup_bundle", "ts_library")
load("//tools:defaults.bzl", "ng_module", "ng_rollup_bundle")
load("//packages/bazel:index.bzl", "protractor_web_test")
load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver")
ts_library(
ng_module(
name = "largetable_lib",
srcs = glob(
[
@ -12,18 +12,20 @@ ts_library(
],
exclude = ["protractor.on-prepare.ts"],
),
tags = ["ivy-only"],
deps = [
"//modules/benchmarks/src:util_lib",
"//modules/benchmarks/src/largetable:util_lib",
"//packages:types",
"//packages/common",
"//packages/core",
"@rxjs",
],
)
ng_rollup_bundle(
name = "bundle",
entry_point = "modules/benchmarks/src/largetable/render3/index.js",
tags = ["ivy-only"],
deps = [
":largetable_lib",
],
@ -44,6 +46,7 @@ ts_devserver(
"index.html",
":favicon",
],
tags = ["ivy-only"],
)
protractor_web_test(
@ -57,9 +60,9 @@ protractor_web_test(
"@ngdeps//reflect-metadata",
"@ngdeps//yargs",
],
on_prepare = ":protractor.on-prepare.js",
on_prepare = ":protractor.on_prepare.js",
server = ":devserver",
tags = ["manual"],
tags = ["ivy-only"],
deps = [
"//modules/benchmarks/src/largetable:perf_lib",
],

View File

@ -28,15 +28,9 @@
<script>
// TODO(mlaval): remove once we have a proper solution
ngDevMode = false;
var isBazel = location.pathname.indexOf('/all/') !== 0;
// isBazel needed while 'scripts/ci/test-e2e.sh test.e2e.protractor-e2e' is run
// on Travis
// TODO: port remaining protractor e2e tests to bazel protractor_web_test_suite rule
var bazelBundle = document.location.search.endsWith('debug') ? 'bundle.min_debug.js' : 'bundle.min.js';
var mainUrl = window.location.search.split(/[?&]main=([^&]+)/)[1]
|| '../../bootstrap_ng2.js';
document.write('<script src="' + (isBazel ? bazelBundle : mainUrl) + '">\u003c/script>');
document.write('<script src="' + bazelBundle + '">\u003c/script>');
</script>
</body>
</html>
</html>

View File

@ -5,7 +5,7 @@
* 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 'reflect-metadata';
import {ɵrenderComponent as renderComponent} from '@angular/core';
import {bindAction, profile} from '../../util';

View File

@ -1,21 +0,0 @@
/**
* @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
*/
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractor = require('protractor');
module.exports = function(config) {
return protractorUtils.runServer(config.workspace, config.server, '-port', [])
.then(serverSpec => {
const serverUrl = `http://localhost:${serverSpec.port}`;
// Since the browser restarts in this benchmark we need to set both the browser.baseUrl
// for the first test and the protractor config.baseUrl for the subsequent tests
protractor.browser.baseUrl = serverUrl;
return protractor.browser.getProcessedConfig().then((config) => config.baseUrl = serverUrl);
});
};

View File

@ -0,0 +1,22 @@
/**
* @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
*/
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractor = require('protractor');
module.exports = async function(config) {
const serverSpec = await protractorUtils.runServer(config.workspace, config.server, '-port', []);
const serverUrl = `http://localhost:${serverSpec.port}`;
// Since the browser restarts in this benchmark we need to set both the browser.baseUrl
// for the first test and the protractor config.baseUrl for the subsequent tests
protractor.browser.baseUrl = serverUrl;
const processedConfig = await protractor.browser.getProcessedConfig();
return processedConfig.baseUrl = serverUrl;
};

View File

@ -6,76 +6,39 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ɵRenderFlags, ɵbind, ɵcontainer, ɵcontainerRefreshEnd, ɵcontainerRefreshStart, ɵdefineComponent, ɵdetectChanges, ɵelementEnd, ɵelementStart, ɵelementStyleProp, ɵelementStyling, ɵembeddedViewEnd, ɵembeddedViewStart, ɵtext, ɵtextBinding as ɵtextBinding} from '@angular/core';
import {ComponentDef} from '@angular/core/src/render3/interfaces/definition';
import {CommonModule} from '@angular/common';
import {Component, Input, NgModule, ɵdetectChanges} from '@angular/core';
import {TableCell, buildTable, emptyTable} from '../util';
const c0 = ['background-color'];
@Component({
selector: 'largetable',
template: `
<table>
<tbody>
<tr *ngFor="let row of data; trackBy: trackByIndex">
<td *ngFor="let cell of row; trackBy: trackByIndex" [style.background-color]="getColor(cell.row)">
{{cell.value}}
</td>
</tr>
</tbody>
</table>
`,
})
export class LargeTableComponent {
@Input()
data: TableCell[][] = emptyTable;
/** @nocollapse */
static ngComponentDef: ComponentDef<LargeTableComponent> = ɵdefineComponent({
type: LargeTableComponent,
selectors: [['largetable']],
consts: 3,
vars: 0,
template: function(rf: ɵRenderFlags, ctx: LargeTableComponent) {
if (rf & ɵRenderFlags.Create) {
ɵelementStart(0, 'table');
{
ɵelementStart(1, 'tbody');
{ ɵcontainer(2); }
ɵelementEnd();
}
ɵelementEnd();
}
if (rf & ɵRenderFlags.Update) {
ɵcontainerRefreshStart(2);
{
for (let row of ctx.data) {
let rf1 = ɵembeddedViewStart(1, 2, 0);
{
if (rf1 & ɵRenderFlags.Create) {
ɵelementStart(0, 'tr');
ɵcontainer(1);
ɵelementEnd();
}
if (rf1 & ɵRenderFlags.Update) {
ɵcontainerRefreshStart(1);
{
for (let cell of row) {
let rf2 = ɵembeddedViewStart(2, 2, 1);
{
if (rf2 & ɵRenderFlags.Create) {
ɵelementStart(0, 'td');
ɵelementStyling(null, c0);
{ ɵtext(1); }
ɵelementEnd();
}
if (rf2 & ɵRenderFlags.Update) {
ɵelementStyleProp(0, 0, null, cell.row % 2 ? '' : 'grey');
ɵtextBinding(1, ɵbind(cell.value));
}
}
ɵembeddedViewEnd();
}
}
ɵcontainerRefreshEnd();
}
}
ɵembeddedViewEnd();
}
}
ɵcontainerRefreshEnd();
}
},
factory: () => new LargeTableComponent(),
inputs: {data: 'data'}
});
trackByIndex(index: number, item: any) { return index; }
getColor(row: number) { return row % 2 ? '' : 'grey'; }
}
@NgModule({declarations: [LargeTableComponent], imports: [CommonModule]})
class TableModule {
}
export function destroyDom(component: LargeTableComponent) {
component.data = emptyTable;
ɵdetectChanges(component);

View File

@ -13,3 +13,16 @@ ts_library(
"//packages/core",
],
)
ts_library(
name = "perf_lib",
testonly = 1,
srcs = [
"tree_perf.spec.ts",
],
deps = [
"//modules/e2e_util:lib",
"//packages:types",
"@ngdeps//protractor",
],
)

View File

@ -1,18 +1,67 @@
package(default_visibility = ["//visibility:public"])
load("//tools:defaults.bzl", "ng_module")
load("//tools:defaults.bzl", "ng_module", "ng_rollup_bundle")
load("//packages/bazel:index.bzl", "protractor_web_test")
load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver")
ng_module(
name = "render3_lib",
name = "tree_lib",
srcs = glob(
[
"**/*.ts",
],
),
tags = ["ivy-only"],
deps = [
"//modules/benchmarks/src/tree:util_lib",
"//packages:types",
"//packages/common",
"//packages/core",
"@rxjs",
],
)
ng_rollup_bundle(
name = "bundle",
entry_point = "modules/benchmarks/src/tree/render3/index.js",
tags = ["ivy-only"],
deps = [
":tree_lib",
],
)
genrule(
name = "favicon",
srcs = ["//modules/benchmarks:favicon"],
outs = ["favicon.ico"],
cmd = "cp $< $@",
)
ts_devserver(
name = "devserver",
static_files = [
":bundle.min_debug.js",
":bundle.min.js",
"index.html",
":favicon",
],
tags = ["ivy-only"],
)
protractor_web_test(
name = "perf",
configuration = "//:protractor-perf.conf.js",
data = [
"//packages/bazel/src/protractor/utils",
"//packages/benchpress",
],
on_prepare = ":protractor.on_prepare.js",
server = ":devserver",
tags = ["ivy-only"],
deps = [
"//modules/benchmarks/src/tree:perf_lib",
"@ngdeps//node-uuid",
"@ngdeps//protractor",
"@ngdeps//reflect-metadata",
"@ngdeps//yargs",
],
)

View File

@ -30,9 +30,8 @@
<script>
// TODO(mlaval): remove once we have a proper solution
ngDevMode = false;
var mainUrl = window.location.search.split(/[?&]main=([^&]+)/)[1]
|| '../../bootstrap_ng2.js';
document.write('<script src="' + mainUrl + '">\u003c/script>');
var bazelBundle = document.location.search.endsWith('debug') ? 'bundle.min_debug.js' : 'bundle.min.js';
document.write('<script src="' + bazelBundle + '">\u003c/script>');
</script>
</body>
</html>

View File

@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import 'reflect-metadata';
import {ɵrenderComponent as renderComponent} from '@angular/core';
import {bindAction, profile} from '../../util';
import {TreeComponent, createDom, destroyDom, detectChanges} from './tree';
@ -27,3 +28,5 @@ export function main() {
profile(() => createDom(component), () => destroyDom(component), 'create'));
}
}
main();

View File

@ -0,0 +1,22 @@
/**
* @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
*/
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractor = require('protractor');
module.exports = async function(config) {
const serverSpec = await protractorUtils.runServer(config.workspace, config.server, '-port', []);
const serverUrl = `http://localhost:${serverSpec.port}`;
// Since the browser restarts in this benchmark we need to set both the browser.baseUrl
// for the first test and the protractor config.baseUrl for the subsequent tests
protractor.browser.baseUrl = serverUrl;
const processedConfig = await protractor.browser.getProcessedConfig();
return processedConfig.baseUrl = serverUrl;
};

View File

@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ɵRenderFlags, ɵbind, ɵcontainer, ɵcontainerRefreshEnd, ɵcontainerRefreshStart, ɵdefineComponent, ɵdetectChanges, ɵelementEnd, ɵelementProperty, ɵelementStart, ɵelementStyleProp, ɵelementStyling as s, ɵembeddedViewEnd, ɵembeddedViewStart, ɵinterpolation1, ɵtext, ɵtextBinding as ɵtextBinding} from '@angular/core';
import {CommonModule} from '@angular/common';
import {Component, NgModule, ɵdetectChanges} from '@angular/core';
import {TreeNode, buildTree, emptyTree} from '../util';
@ -30,122 +31,17 @@ export function detectChanges(component: TreeComponent) {
numberOfChecksEl.textContent = `${detectChangesRuns}`;
}
const c0 = ['background-color'];
@Component({
selector: 'tree',
inputs: ['data'],
template:
`<span [style.backgroundColor]="bgColor"> {{data.value}} </span><tree *ngIf='data.right != null' [data]='data.right'></tree><tree *ngIf='data.left != null' [data]='data.left'></tree>`
})
export class TreeComponent {
data: TreeNode = emptyTree;
/** @nocollapse */
static ngComponentDef = ɵdefineComponent({
type: TreeComponent,
selectors: [['tree']],
consts: 4,
vars: 1,
template: function(rf: ɵRenderFlags, ctx: TreeComponent) {
if (rf & ɵRenderFlags.Create) {
ɵelementStart(0, 'span');
s(null, c0);
{ ɵtext(1); }
ɵelementEnd();
ɵcontainer(2);
ɵcontainer(3);
}
if (rf & ɵRenderFlags.Update) {
ɵelementStyleProp(0, 0, ctx.data.depth % 2 ? '' : 'grey');
ɵtextBinding(1, ɵinterpolation1(' ', ctx.data.value, ' '));
ɵcontainerRefreshStart(2);
{
if (ctx.data.left != null) {
let rf0 = ɵembeddedViewStart(0, 1, 1);
{
if (rf0 & ɵRenderFlags.Create) {
ɵelementStart(0, 'tree');
ɵelementEnd();
}
if (rf0 & ɵRenderFlags.Update) {
ɵelementProperty(0, 'data', ɵbind(ctx.data.left));
}
}
ɵembeddedViewEnd();
}
}
ɵcontainerRefreshEnd();
ɵcontainerRefreshStart(3);
{
if (ctx.data.right != null) {
let rf0 = ɵembeddedViewStart(0, 1, 1);
{
if (rf0 & ɵRenderFlags.Create) {
ɵelementStart(0, 'tree');
ɵelementEnd();
}
if (rf0 & ɵRenderFlags.Update) {
ɵelementProperty(0, 'data', ɵbind(ctx.data.right));
}
}
ɵembeddedViewEnd();
}
}
ɵcontainerRefreshEnd();
}
},
factory: () => new TreeComponent,
inputs: {data: 'data'},
directives: () => [TreeComponent]
});
data: any = emptyTree;
get bgColor() { return this.data.depth % 2 ? '' : 'grey'; }
}
export class TreeFunction {
data: TreeNode = emptyTree;
/** @nocollapse */
static ngComponentDef = ɵdefineComponent({
type: TreeFunction,
selectors: [['tree']],
consts: 5,
vars: 1,
template: function(rf: ɵRenderFlags, ctx: TreeFunction) {
// bit of a hack
TreeTpl(rf, ctx.data);
},
factory: () => new TreeFunction,
inputs: {data: 'data'}
});
}
const c1 = ['background-color'];
export function TreeTpl(rf: ɵRenderFlags, ctx: TreeNode) {
if (rf & ɵRenderFlags.Create) {
ɵelementStart(0, 'tree');
{
ɵelementStart(1, 'span');
s(null, c1);
{ ɵtext(2); }
ɵelementEnd();
ɵcontainer(3);
ɵcontainer(4);
}
ɵelementEnd();
}
if (rf & ɵRenderFlags.Update) {
ɵelementStyleProp(1, 0, ctx.depth % 2 ? '' : 'grey');
ɵtextBinding(2, ɵinterpolation1(' ', ctx.value, ' '));
ɵcontainerRefreshStart(3);
{
if (ctx.left != null) {
let rf0 = ɵembeddedViewStart(0, 5, 1);
{ TreeTpl(rf0, ctx.left); }
ɵembeddedViewEnd();
}
}
ɵcontainerRefreshEnd();
ɵcontainerRefreshStart(4);
{
if (ctx.right != null) {
let rf0 = ɵembeddedViewStart(0, 5, 1);
{ TreeTpl(rf0, ctx.right); }
ɵembeddedViewEnd();
}
}
ɵcontainerRefreshEnd();
}
@NgModule({declarations: [TreeComponent], imports: [CommonModule]})
export class TreeModule {
}

View File

@ -11,7 +11,7 @@ ng_module(
),
deps = [
"//modules/benchmarks/src/tree:util_lib",
"//modules/benchmarks/src/tree/render3:render3_lib",
"//modules/benchmarks/src/tree/render3:tree_lib",
"//packages:types",
"//packages/core",
"@rxjs",

View File

@ -6,9 +6,11 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ɵrenderComponent as renderComponent} from '@angular/core';
import {ɵRenderFlags, ɵcontainer, ɵcontainerRefreshEnd, ɵcontainerRefreshStart, ɵdefineComponent, ɵelementEnd, ɵelementStart, ɵelementStyleProp, ɵelementStyling, ɵembeddedViewEnd, ɵembeddedViewStart, ɵinterpolation1, ɵrenderComponent as renderComponent, ɵtext, ɵtextBinding} from '@angular/core';
import {bindAction, profile} from '../../util';
import {TreeFunction, createDom, destroyDom, detectChanges} from '../render3/tree';
import {createDom, destroyDom, detectChanges} from '../render3/tree';
import {TreeNode, emptyTree} from '../util';
function noop() {}
@ -16,14 +18,71 @@ export function main() {
let component: TreeFunction;
if (typeof window !== 'undefined') {
component = renderComponent(TreeFunction);
bindAction('#createDom', () => createDom(component));
bindAction('#destroyDom', () => destroyDom(component));
bindAction('#detectChanges', () => detectChanges(component));
bindAction('#createDom', () => createDom(component as any));
bindAction('#destroyDom', () => destroyDom(component as any));
bindAction('#detectChanges', () => detectChanges(component as any));
bindAction(
'#detectChangesProfile', profile(() => detectChanges(component), noop, 'detectChanges'));
bindAction('#updateDomProfile', profile(() => createDom(component), noop, 'update'));
'#detectChangesProfile',
profile(() => detectChanges(component as any), noop, 'detectChanges'));
bindAction('#updateDomProfile', profile(() => createDom(component as any), noop, 'update'));
bindAction(
'#createDomProfile',
profile(() => createDom(component), () => destroyDom(component), 'create'));
profile(() => createDom(component as any), () => destroyDom(component as any), 'create'));
}
}
export class TreeFunction {
data: TreeNode = emptyTree;
/** @nocollapse */
static ngComponentDef = ɵdefineComponent({
type: TreeFunction,
selectors: [['tree']],
consts: 5,
vars: 1,
template: function(rf: ɵRenderFlags, ctx: TreeFunction) {
// bit of a hack
TreeTpl(rf, ctx.data);
},
factory: () => new TreeFunction,
inputs: {data: 'data'}
});
}
const c1 = ['background-color'];
export function TreeTpl(rf: ɵRenderFlags, ctx: TreeNode) {
if (rf & ɵRenderFlags.Create) {
ɵelementStart(0, 'tree');
{
ɵelementStart(1, 'span');
ɵelementStyling(null, c1);
{ ɵtext(2); }
ɵelementEnd();
ɵcontainer(3);
ɵcontainer(4);
}
ɵelementEnd();
}
if (rf & ɵRenderFlags.Update) {
ɵelementStyleProp(1, 0, ctx.depth % 2 ? '' : 'grey');
ɵtextBinding(2, ɵinterpolation1(' ', ctx.value, ' '));
ɵcontainerRefreshStart(3);
{
if (ctx.left != null) {
let rf0 = ɵembeddedViewStart(0, 5, 1);
{ TreeTpl(rf0, ctx.left); }
ɵembeddedViewEnd();
}
}
ɵcontainerRefreshEnd();
ɵcontainerRefreshStart(4);
{
if (ctx.right != null) {
let rf0 = ɵembeddedViewStart(0, 5, 1);
{ TreeTpl(rf0, ctx.right); }
ɵembeddedViewEnd();
}
}
ɵcontainerRefreshEnd();
}
}

View File

@ -0,0 +1,101 @@
/**
* @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 {$, browser} from 'protractor';
import {openBrowser} from '../../../e2e_util/e2e_util';
import {runBenchmark} from '../../../e2e_util/perf_util';
describe('benchmark render', () => {
it('should work for createDestroy', () => {
openTreeBenchmark();
$('#createDom').click();
expect($('#root').getText()).toContain('0');
$('#destroyDom').click();
expect($('#root').getText() as any).toEqual('');
});
it('should work for update', () => {
openTreeBenchmark();
$('#createDom').click();
$('#createDom').click();
expect($('#root').getText()).toContain('A');
});
it('should work for detectChanges', () => {
openTreeBenchmark();
$('#detectChanges').click();
expect($('#numberOfChecks').getText()).toContain('10');
});
});
describe('benchmarks', () => {
it('should work for createOnly', done => {
runTreeBenchmark({
id: 'createOnly',
prepare: () => $('#destroyDom').click(),
work: () => $('#createDom').click()
}).then(done, done.fail);
});
it('should work for destroy', done => {
runTreeBenchmark({
id: 'createOnly',
prepare: () => $('#createDom').click(),
work: () => $('#destroyDom').click()
}).then(done, done.fail);
});
it('should work for createDestroy', done => {
runTreeBenchmark({
id: 'createDestroy',
work: () => {
$('#destroyDom').click();
$('#createDom').click();
}
}).then(done, done.fail);
});
it('should work for update', done => {
runTreeBenchmark({id: 'update', work: () => $('#createDom').click()}).then(done, done.fail);
});
it('should work for detectChanges', done => {
runTreeBenchmark({
id: 'detectChanges',
work: () => $('#detectChanges').click(),
setup: () => $('#destroyDom').click()
}).then(done, done.fail);
});
});
function runTreeBenchmark({id, prepare, setup, work}:
{id: string; prepare ? () : void; setup ? () : void; work(): void;}) {
browser.rootEl = '#root';
return runBenchmark({
id: id,
url: '',
ignoreBrowserSynchronization: true,
params: [{name: 'depth', value: 11}],
work: work,
prepare: prepare,
setup: setup
});
}
function openTreeBenchmark() {
browser.rootEl = '#root';
openBrowser({
url: '',
ignoreBrowserSynchronization: true,
params: [{name: 'depth', value: 4}],
});
}

View File

@ -40,6 +40,7 @@ export function runBenchmark(config: {
if (config.setup) {
config.setup();
}
if (!cmdArgs) readCommandLine();
const description: {[key: string]: any} = {'bundles': cmdArgs.bundles};
config.params.forEach((param) => { description[param.name] = param.value; });
return runner.sample({

View File

@ -1,6 +1,6 @@
{
"name": "angular-srcs",
"version": "7.0.1",
"version": "7.1.0-beta.0",
"private": true,
"branchPattern": "2.0.*",
"description": "Angular - a web framework for modern web apps",

View File

@ -7,7 +7,7 @@
*/
import * as ng from '@angular/compiler-cli';
import {BazelOptions, CachedFileLoader, CompilerHost, FileCache, FileLoader, UncachedFileLoader, constructManifest, debug, fixUmdModuleDeclarations, parseTsconfig, resolveNormalizedPath, runAsWorker, runWorkerLoop} from '@bazel/typescript';
import {BazelOptions, CachedFileLoader, CompilerHost, FileCache, FileLoader, UncachedFileLoader, constructManifest, debug, parseTsconfig, resolveNormalizedPath, runAsWorker, runWorkerLoop} from '@bazel/typescript';
import * as fs from 'fs';
import * as path from 'path';
import * as tsickle from 'tsickle';
@ -291,10 +291,7 @@ export function compile({allowNonHermeticReads, allDepsCompiledWithBazel = true,
program, bazelHost, bazelHost, compilerOpts, targetSourceFile, writeFile,
cancellationToken, emitOnlyDtsFiles, {
beforeTs: customTransformers.before,
afterTs: [
...(customTransformers.after || []),
fixUmdModuleDeclarations((sf: ts.SourceFile) => bazelHost.amdModuleName(sf)),
],
afterTs: customTransformers.after,
});
if (!gatherDiagnostics) {

View File

@ -26,8 +26,9 @@ ts_library(
"//packages/compiler",
"//packages/compiler-cli/src/ngtsc/annotations",
"//packages/compiler-cli/src/ngtsc/diagnostics",
"//packages/compiler-cli/src/ngtsc/factories",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/shims",
"//packages/compiler-cli/src/ngtsc/switch",
"//packages/compiler-cli/src/ngtsc/transform",
"//packages/compiler-cli/src/ngtsc/typecheck",
"@ngdeps//@bazel/typescript",

View File

@ -9,8 +9,8 @@ import * as ts from 'typescript';
import {ReflectionHost} from '../../../ngtsc/host';
import {DecoratedFile} from './decorated_file';
export const PRE_NGCC_MARKER = '__PRE_NGCC__';
export const POST_NGCC_MARKER = '__POST_NGCC__';
export const PRE_NGCC_MARKER = '__PRE_R3__';
export const POST_NGCC_MARKER = '__POST_R3__';
export type SwitchableVariableDeclaration = ts.VariableDeclaration & {initializer: ts.Identifier};
export function isSwitchableVariableDeclaration(node: ts.Node):

View File

@ -30,15 +30,15 @@ const TEST_PROGRAM = [
name: 'b.js',
contents: `
export const b = 42;
var factoryB = factory__PRE_NGCC__;
var factoryB = factory__PRE_R3__;
`
},
{
name: 'c.js',
contents: `
export const c = 'So long, and thanks for all the fish!';
var factoryC = factory__PRE_NGCC__;
var factoryD = factory__PRE_NGCC__;
var factoryC = factory__PRE_R3__;
var factoryD = factory__PRE_R3__;
`
},
];
@ -62,14 +62,14 @@ describe('SwitchMarkerAnalyzer', () => {
expect(analysis.has(b)).toBe(true);
expect(analysis.get(b) !.sourceFile).toBe(b);
expect(analysis.get(b) !.declarations.map(decl => decl.getText())).toEqual([
'factoryB = factory__PRE_NGCC__'
'factoryB = factory__PRE_R3__'
]);
expect(analysis.has(c)).toBe(true);
expect(analysis.get(c) !.sourceFile).toBe(c);
expect(analysis.get(c) !.declarations.map(decl => decl.getText())).toEqual([
'factoryC = factory__PRE_NGCC__',
'factoryD = factory__PRE_NGCC__',
'factoryC = factory__PRE_R3__',
'factoryD = factory__PRE_R3__',
]);
});
});

View File

@ -35,15 +35,15 @@ const CLASSES = [
const MARKER_FILE = {
name: '/marker.js',
contents: `
let compileNgModuleFactory = compileNgModuleFactory__PRE_NGCC__;
let compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;
function compileNgModuleFactory__PRE_NGCC__(injector, options, moduleType) {
function compileNgModuleFactory__PRE_R3__(injector, options, moduleType) {
const compilerFactory = injector.get(CompilerFactory);
const compiler = compilerFactory.createCompiler([options]);
return compiler.compileModuleAsync(moduleType);
}
function compileNgModuleFactory__POST_NGCC__(injector, options, moduleType) {
function compileNgModuleFactory__POST_R3__(injector, options, moduleType) {
ngDevMode && assertNgModuleType(moduleType);
return Promise.resolve(new R3NgModuleFactory(moduleType));
}
@ -113,7 +113,7 @@ describe('Esm2015ReflectionHost', () => {
const file = program.getSourceFile(MARKER_FILE.name) !;
const declarations = host.getSwitchableDeclarations(file);
expect(declarations.map(d => [d.name.getText(), d.initializer !.getText()])).toEqual([
['compileNgModuleFactory', 'compileNgModuleFactory__PRE_NGCC__']
['compileNgModuleFactory', 'compileNgModuleFactory__PRE_R3__']
]);
});
});

View File

@ -377,15 +377,15 @@ const FUNCTION_BODY_FILE = {
const MARKER_FILE = {
name: '/marker.js',
contents: `
var compileNgModuleFactory = compileNgModuleFactory__PRE_NGCC__;
var compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;
function compileNgModuleFactory__PRE_NGCC__(injector, options, moduleType) {
function compileNgModuleFactory__PRE_R3__(injector, options, moduleType) {
var compilerFactory = injector.get(CompilerFactory);
var compiler = compilerFactory.createCompiler([options]);
return compiler.compileModuleAsync(moduleType);
}
function compileNgModuleFactory__POST_NGCC__(injector, options, moduleType) {
function compileNgModuleFactory__POST_R3__(injector, options, moduleType) {
ngDevMode && assertNgModuleType(moduleType);
return Promise.resolve(new R3NgModuleFactory(moduleType));
}
@ -1179,7 +1179,7 @@ describe('Fesm2015ReflectionHost', () => {
const file = program.getSourceFile(MARKER_FILE.name) !;
const declarations = host.getSwitchableDeclarations(file);
expect(declarations.map(d => [d.name.getText(), d.initializer !.getText()])).toEqual([
['compileNgModuleFactory', 'compileNgModuleFactory__PRE_NGCC__']
['compileNgModuleFactory', 'compileNgModuleFactory__PRE_R3__']
]);
});
});

View File

@ -48,16 +48,16 @@ export class C {}
C.decorators = [
{ type: Directive, args: [{ selector: '[c]' }] },
];
let compileNgModuleFactory = compileNgModuleFactory__PRE_NGCC__;
let badlyFormattedVariable = __PRE_NGCC__badlyFormattedVariable;
let compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;
let badlyFormattedVariable = __PRE_R3__badlyFormattedVariable;
function compileNgModuleFactory__PRE_NGCC__(injector, options, moduleType) {
function compileNgModuleFactory__PRE_R3__(injector, options, moduleType) {
const compilerFactory = injector.get(CompilerFactory);
const compiler = compilerFactory.createCompiler([options]);
return compiler.compileModuleAsync(moduleType);
}
function compileNgModuleFactory__POST_NGCC__(injector, options, moduleType) {
function compileNgModuleFactory__POST_R3__(injector, options, moduleType) {
ngDevMode && assertNgModuleType(moduleType);
return Promise.resolve(new R3NgModuleFactory(moduleType));
}
@ -146,17 +146,15 @@ export class A {}`);
renderer.rewriteSwitchableDeclarations(
output, file, switchMarkerAnalyses.get(sourceFile) !.declarations);
expect(output.toString())
.not.toContain(`let compileNgModuleFactory = compileNgModuleFactory__PRE_NGCC__;`);
.not.toContain(`let compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;`);
expect(output.toString())
.toContain(`let badlyFormattedVariable = __PRE_NGCC__badlyFormattedVariable;`);
.toContain(`let badlyFormattedVariable = __PRE_R3__badlyFormattedVariable;`);
expect(output.toString())
.toContain(`let compileNgModuleFactory = compileNgModuleFactory__POST_NGCC__;`);
.toContain(`let compileNgModuleFactory = compileNgModuleFactory__POST_R3__;`);
expect(output.toString())
.toContain(
`function compileNgModuleFactory__PRE_NGCC__(injector, options, moduleType) {`);
.toContain(`function compileNgModuleFactory__PRE_R3__(injector, options, moduleType) {`);
expect(output.toString())
.toContain(
`function compileNgModuleFactory__POST_NGCC__(injector, options, moduleType) {`);
.toContain(`function compileNgModuleFactory__POST_R3__(injector, options, moduleType) {`);
});
});

View File

@ -55,15 +55,15 @@ var C = (function() {
return C;
}());
var compileNgModuleFactory = compileNgModuleFactory__PRE_NGCC__;
var badlyFormattedVariable = __PRE_NGCC__badlyFormattedVariable;
function compileNgModuleFactory__PRE_NGCC__(injector, options, moduleType) {
var compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;
var badlyFormattedVariable = __PRE_R3__badlyFormattedVariable;
function compileNgModuleFactory__PRE_R3__(injector, options, moduleType) {
const compilerFactory = injector.get(CompilerFactory);
const compiler = compilerFactory.createCompiler([options]);
return compiler.compileModuleAsync(moduleType);
}
function compileNgModuleFactory__POST_NGCC__(injector, options, moduleType) {
function compileNgModuleFactory__POST_R3__(injector, options, moduleType) {
ngDevMode && assertNgModuleType(moduleType);
return Promise.resolve(new R3NgModuleFactory(moduleType));
}
@ -166,17 +166,15 @@ var A = (function() {`);
renderer.rewriteSwitchableDeclarations(
output, file, switchMarkerAnalyses.get(sourceFile) !.declarations);
expect(output.toString())
.not.toContain(`var compileNgModuleFactory = compileNgModuleFactory__PRE_NGCC__;`);
.not.toContain(`var compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;`);
expect(output.toString())
.toContain(`var badlyFormattedVariable = __PRE_NGCC__badlyFormattedVariable;`);
.toContain(`var badlyFormattedVariable = __PRE_R3__badlyFormattedVariable;`);
expect(output.toString())
.toContain(`var compileNgModuleFactory = compileNgModuleFactory__POST_NGCC__;`);
.toContain(`var compileNgModuleFactory = compileNgModuleFactory__POST_R3__;`);
expect(output.toString())
.toContain(
`function compileNgModuleFactory__PRE_NGCC__(injector, options, moduleType) {`);
.toContain(`function compileNgModuleFactory__PRE_R3__(injector, options, moduleType) {`);
expect(output.toString())
.toContain(
`function compileNgModuleFactory__POST_NGCC__(injector, options, moduleType) {`);
.toContain(`function compileNgModuleFactory__POST_R3__(injector, options, moduleType) {`);
});
});

View File

@ -1,63 +0,0 @@
/**
* @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 * as path from 'path';
import * as ts from 'typescript';
const TS_DTS_SUFFIX = /(\.d)?\.ts$/;
/**
* Generates ts.SourceFiles which contain variable declarations for NgFactories for every exported
* class of an input ts.SourceFile.
*/
export class FactoryGenerator {
factoryFor(original: ts.SourceFile, genFilePath: string): ts.SourceFile {
const relativePathToSource =
'./' + path.posix.basename(original.fileName).replace(TS_DTS_SUFFIX, '');
// Collect a list of classes that need to have factory types emitted for them.
const symbolNames = original
.statements
// Pick out top level class declarations...
.filter(ts.isClassDeclaration)
// which are named, exported, and have decorators.
.filter(
decl => isExported(decl) && decl.decorators !== undefined &&
decl.name !== undefined)
// Grab the symbol name.
.map(decl => decl.name !.text);
// For each symbol name, generate a constant export of the corresponding NgFactory.
// This will encompass a lot of symbols which don't need factories, but that's okay
// because it won't miss any that do.
const varLines = symbolNames.map(
name => `export const ${name}NgFactory = new i0.ɵNgModuleFactory(${name});`);
const sourceText = [
// This might be incorrect if the current package being compiled is Angular core, but it's
// okay to leave in at type checking time. TypeScript can handle this reference via its path
// mapping, but downstream bundlers can't. If the current package is core itself, this will be
// replaced in the factory transformer before emit.
`import * as i0 from '@angular/core';`,
`import {${symbolNames.join(', ')}} from '${relativePathToSource}';`,
...varLines,
].join('\n');
return ts.createSourceFile(
genFilePath, sourceText, original.languageVersion, true, ts.ScriptKind.TS);
}
computeFactoryFileMap(files: ReadonlyArray<string>): Map<string, string> {
const map = new Map<string, string>();
files.filter(sourceFile => !sourceFile.endsWith('.d.ts'))
.forEach(sourceFile => map.set(sourceFile.replace(/\.ts$/, '.ngfactory.ts'), sourceFile));
return map;
}
}
function isExported(decl: ts.Declaration): boolean {
return decl.modifiers !== undefined &&
decl.modifiers.some(mod => mod.kind == ts.SyntaxKind.ExportKeyword);
}

View File

@ -1,78 +0,0 @@
/**
* @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 * as ts from 'typescript';
import {relativePathBetween} from '../../util/src/path';
const STRIP_NG_FACTORY = /(.*)NgFactory$/;
export interface FactoryInfo {
sourceFilePath: string;
moduleSymbolNames: Set<string>;
}
export function generatedFactoryTransform(
factoryMap: Map<string, FactoryInfo>,
coreImportsFrom: ts.SourceFile | null): ts.TransformerFactory<ts.SourceFile> {
return (context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
return (file: ts.SourceFile): ts.SourceFile => {
return transformFactorySourceFile(factoryMap, context, coreImportsFrom, file);
};
};
}
function transformFactorySourceFile(
factoryMap: Map<string, FactoryInfo>, context: ts.TransformationContext,
coreImportsFrom: ts.SourceFile | null, file: ts.SourceFile): ts.SourceFile {
// If this is not a generated file, it won't have factory info associated with it.
if (!factoryMap.has(file.fileName)) {
// Don't transform non-generated code.
return file;
}
const {moduleSymbolNames, sourceFilePath} = factoryMap.get(file.fileName) !;
const clone = ts.getMutableClone(file);
const transformedStatements = file.statements.map(stmt => {
if (coreImportsFrom !== null && ts.isImportDeclaration(stmt) &&
ts.isStringLiteral(stmt.moduleSpecifier) && stmt.moduleSpecifier.text === '@angular/core') {
const path = relativePathBetween(sourceFilePath, coreImportsFrom.fileName);
if (path !== null) {
return ts.updateImportDeclaration(
stmt, stmt.decorators, stmt.modifiers, stmt.importClause, ts.createStringLiteral(path));
} else {
return ts.createNotEmittedStatement(stmt);
}
} else if (ts.isVariableStatement(stmt) && stmt.declarationList.declarations.length === 1) {
const decl = stmt.declarationList.declarations[0];
if (ts.isIdentifier(decl.name)) {
const match = STRIP_NG_FACTORY.exec(decl.name.text);
if (match === null || !moduleSymbolNames.has(match[1])) {
// Remove the given factory as it wasn't actually for an NgModule.
return ts.createNotEmittedStatement(stmt);
}
}
return stmt;
} else {
return stmt;
}
});
if (!transformedStatements.some(ts.isVariableStatement)) {
// If the resulting file has no factories, include an empty export to
// satisfy closure compiler.
transformedStatements.push(ts.createVariableStatement(
[ts.createModifier(ts.SyntaxKind.ExportKeyword)],
ts.createVariableDeclarationList(
[ts.createVariableDeclaration('ɵNonEmptyModule', undefined, ts.createTrue())],
ts.NodeFlags.Const)));
}
clone.statements = ts.createNodeArray(transformedStatements);
return clone;
}

View File

@ -15,9 +15,10 @@ import {nocollapseHack} from '../transformers/nocollapse_hack';
import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from './annotations';
import {BaseDefDecoratorHandler} from './annotations/src/base_def';
import {FactoryGenerator, FactoryInfo, GeneratedFactoryHostWrapper, generatedFactoryTransform} from './factories';
import {TypeScriptReflectionHost} from './metadata';
import {FileResourceLoader, HostResourceLoader} from './resource_loader';
import {FactoryGenerator, FactoryInfo, GeneratedShimsHostWrapper, SummaryGenerator, generatedFactoryTransform} from './shims';
import {ivySwitchTransform} from './switch';
import {IvyCompilation, ivyTransformFactory} from './transform';
import {TypeCheckContext, TypeCheckProgramHost} from './typecheck';
@ -50,13 +51,16 @@ export class NgtscProgram implements api.Program {
this.resourceLoader = host.readResource !== undefined ?
new HostResourceLoader(host.readResource.bind(host)) :
new FileResourceLoader();
const shouldGenerateFactories = options.allowEmptyCodegenFiles || false;
const shouldGenerateShims = options.allowEmptyCodegenFiles || false;
this.host = host;
let rootFiles = [...rootNames];
if (shouldGenerateFactories) {
const generator = new FactoryGenerator();
const factoryFileMap = generator.computeFactoryFileMap(rootNames);
rootFiles.push(...Array.from(factoryFileMap.keys()));
if (shouldGenerateShims) {
// Summary generation.
const summaryGenerator = SummaryGenerator.forRootFiles(rootNames);
// Factory generation.
const factoryGenerator = FactoryGenerator.forRootFiles(rootNames);
const factoryFileMap = factoryGenerator.factoryFileMap;
this.factoryToSourceInfo = new Map<string, FactoryInfo>();
this.sourceToFactorySymbols = new Map<string, Set<string>>();
factoryFileMap.forEach((sourceFilePath, factoryPath) => {
@ -64,7 +68,10 @@ export class NgtscProgram implements api.Program {
this.sourceToFactorySymbols !.set(sourceFilePath, moduleSymbolNames);
this.factoryToSourceInfo !.set(factoryPath, {sourceFilePath, moduleSymbolNames});
});
this.host = new GeneratedFactoryHostWrapper(host, generator, factoryFileMap);
const factoryFileNames = Array.from(factoryFileMap.keys());
rootFiles.push(...factoryFileNames, ...summaryGenerator.getSummaryFileNames());
this.host = new GeneratedShimsHostWrapper(host, [summaryGenerator, factoryGenerator]);
}
this.tsProgram =
@ -177,6 +184,9 @@ export class NgtscProgram implements api.Program {
if (this.factoryToSourceInfo !== null) {
transforms.push(generatedFactoryTransform(this.factoryToSourceInfo, this.coreImportsFrom));
}
if (this.isCore) {
transforms.push(ivySwitchTransform);
}
// Run the emit, including a custom transformer that will downlevel the Ivy decorators in code.
const emitResult = emitCallback({
program: this.tsProgram,

View File

@ -3,12 +3,12 @@ package(default_visibility = ["//visibility:public"])
load("//tools:defaults.bzl", "ts_library")
ts_library(
name = "factories",
name = "shims",
srcs = glob([
"index.ts",
"src/**/*.ts",
]),
module_name = "@angular/compiler-cli/src/ngtsc/factories",
module_name = "@angular/compiler-cli/src/ngtsc/shims",
deps = [
"//packages/compiler",
"//packages/compiler-cli/src/ngtsc/host",

View File

@ -8,6 +8,6 @@
/// <reference types="node" />
export {FactoryGenerator} from './src/generator';
export {GeneratedFactoryHostWrapper} from './src/host';
export {FactoryInfo, generatedFactoryTransform} from './src/transform';
export {FactoryGenerator, FactoryInfo, generatedFactoryTransform} from './src/factory_generator';
export {GeneratedShimsHostWrapper} from './src/host';
export {SummaryGenerator} from './src/summary_generator';

View File

@ -0,0 +1,144 @@
/**
* @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 * as path from 'path';
import * as ts from 'typescript';
import {relativePathBetween} from '../../util/src/path';
import {ShimGenerator} from './host';
import {isNonDeclarationTsFile} from './util';
const TS_DTS_SUFFIX = /(\.d)?\.ts$/;
const STRIP_NG_FACTORY = /(.*)NgFactory$/;
/**
* Generates ts.SourceFiles which contain variable declarations for NgFactories for every exported
* class of an input ts.SourceFile.
*/
export class FactoryGenerator implements ShimGenerator {
private constructor(private map: Map<string, string>) {}
get factoryFileMap(): Map<string, string> { return this.map; }
getOriginalSourceOfShim(fileName: string): string|null { return this.map.get(fileName) || null; }
generate(original: ts.SourceFile, genFilePath: string): ts.SourceFile {
const relativePathToSource =
'./' + path.posix.basename(original.fileName).replace(TS_DTS_SUFFIX, '');
// Collect a list of classes that need to have factory types emitted for them. This list is
// overly broad as at this point the ts.TypeChecker hasn't been created, and can't be used to
// semantically understand which decorated types are actually decorated with Angular decorators.
//
// The exports generated here are pruned in the factory transform during emit.
const symbolNames = original
.statements
// Pick out top level class declarations...
.filter(ts.isClassDeclaration)
// which are named, exported, and have decorators.
.filter(
decl => isExported(decl) && decl.decorators !== undefined &&
decl.name !== undefined)
// Grab the symbol name.
.map(decl => decl.name !.text);
// For each symbol name, generate a constant export of the corresponding NgFactory.
// This will encompass a lot of symbols which don't need factories, but that's okay
// because it won't miss any that do.
const varLines = symbolNames.map(
name => `export const ${name}NgFactory = new i0.ɵNgModuleFactory(${name});`);
const sourceText = [
// This might be incorrect if the current package being compiled is Angular core, but it's
// okay to leave in at type checking time. TypeScript can handle this reference via its path
// mapping, but downstream bundlers can't. If the current package is core itself, this will be
// replaced in the factory transformer before emit.
`import * as i0 from '@angular/core';`,
`import {${symbolNames.join(', ')}} from '${relativePathToSource}';`,
...varLines,
].join('\n');
return ts.createSourceFile(
genFilePath, sourceText, original.languageVersion, true, ts.ScriptKind.TS);
}
static forRootFiles(files: ReadonlyArray<string>): FactoryGenerator {
const map = new Map<string, string>();
files.filter(sourceFile => isNonDeclarationTsFile(sourceFile))
.forEach(sourceFile => map.set(sourceFile.replace(/\.ts$/, '.ngfactory.ts'), sourceFile));
return new FactoryGenerator(map);
}
}
function isExported(decl: ts.Declaration): boolean {
return decl.modifiers !== undefined &&
decl.modifiers.some(mod => mod.kind == ts.SyntaxKind.ExportKeyword);
}
export interface FactoryInfo {
sourceFilePath: string;
moduleSymbolNames: Set<string>;
}
export function generatedFactoryTransform(
factoryMap: Map<string, FactoryInfo>,
coreImportsFrom: ts.SourceFile | null): ts.TransformerFactory<ts.SourceFile> {
return (context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
return (file: ts.SourceFile): ts.SourceFile => {
return transformFactorySourceFile(factoryMap, context, coreImportsFrom, file);
};
};
}
function transformFactorySourceFile(
factoryMap: Map<string, FactoryInfo>, context: ts.TransformationContext,
coreImportsFrom: ts.SourceFile | null, file: ts.SourceFile): ts.SourceFile {
// If this is not a generated file, it won't have factory info associated with it.
if (!factoryMap.has(file.fileName)) {
// Don't transform non-generated code.
return file;
}
const {moduleSymbolNames, sourceFilePath} = factoryMap.get(file.fileName) !;
const clone = ts.getMutableClone(file);
const transformedStatements = file.statements.map(stmt => {
if (coreImportsFrom !== null && ts.isImportDeclaration(stmt) &&
ts.isStringLiteral(stmt.moduleSpecifier) && stmt.moduleSpecifier.text === '@angular/core') {
const path = relativePathBetween(sourceFilePath, coreImportsFrom.fileName);
if (path !== null) {
return ts.updateImportDeclaration(
stmt, stmt.decorators, stmt.modifiers, stmt.importClause, ts.createStringLiteral(path));
} else {
return ts.createNotEmittedStatement(stmt);
}
} else if (ts.isVariableStatement(stmt) && stmt.declarationList.declarations.length === 1) {
const decl = stmt.declarationList.declarations[0];
if (ts.isIdentifier(decl.name)) {
const match = STRIP_NG_FACTORY.exec(decl.name.text);
if (match === null || !moduleSymbolNames.has(match[1])) {
// Remove the given factory as it wasn't actually for an NgModule.
return ts.createNotEmittedStatement(stmt);
}
}
return stmt;
} else {
return stmt;
}
});
if (!transformedStatements.some(ts.isVariableStatement)) {
// If the resulting file has no factories, include an empty export to
// satisfy closure compiler.
transformedStatements.push(ts.createVariableStatement(
[ts.createModifier(ts.SyntaxKind.ExportKeyword)],
ts.createVariableDeclarationList(
[ts.createVariableDeclaration('ɵNonEmptyModule', undefined, ts.createTrue())],
ts.NodeFlags.Const)));
}
clone.statements = ts.createNodeArray(transformedStatements);
return clone;
}

View File

@ -9,15 +9,26 @@
import * as path from 'path';
import * as ts from 'typescript';
import {FactoryGenerator} from './generator';
export interface ShimGenerator {
/**
* Get the original source file for the given shim path, the contents of which determine the
* contents of the shim file.
*
* If this returns `null` then the given file was not a shim file handled by this generator.
*/
getOriginalSourceOfShim(fileName: string): string|null;
/**
* Generate a shim's `ts.SourceFile` for the given original file.
*/
generate(original: ts.SourceFile, genFileName: string): ts.SourceFile;
}
/**
* A wrapper around a `ts.CompilerHost` which supports generated files.
*/
export class GeneratedFactoryHostWrapper implements ts.CompilerHost {
constructor(
private delegate: ts.CompilerHost, private generator: FactoryGenerator,
private factoryToSourceMap: Map<string, string>) {
export class GeneratedShimsHostWrapper implements ts.CompilerHost {
constructor(private delegate: ts.CompilerHost, private shimGenerators: ShimGenerator[]) {
if (delegate.resolveTypeReferenceDirectives) {
// Backward compatibility with TypeScript 2.9 and older since return
// type has changed from (ts.ResolvedTypeReferenceDirective | undefined)[]
@ -38,14 +49,20 @@ export class GeneratedFactoryHostWrapper implements ts.CompilerHost {
onError?: ((message: string) => void)|undefined,
shouldCreateNewSourceFile?: boolean|undefined): ts.SourceFile|undefined {
const canonical = this.getCanonicalFileName(fileName);
if (this.factoryToSourceMap.has(canonical)) {
const sourceFileName = this.getCanonicalFileName(this.factoryToSourceMap.get(canonical) !);
const sourceFile = this.delegate.getSourceFile(
sourceFileName, languageVersion, onError, shouldCreateNewSourceFile);
if (sourceFile === undefined) {
return undefined;
for (let i = 0; i < this.shimGenerators.length; i++) {
const generator = this.shimGenerators[i];
const originalFile = generator.getOriginalSourceOfShim(canonical);
if (originalFile !== null) {
// This shim generator has recognized the filename being requested, and is now responsible
// for generating its contents, based on the contents of the original file it has requested.
const originalSource = this.delegate.getSourceFile(
originalFile, languageVersion, onError, shouldCreateNewSourceFile);
if (originalSource === undefined) {
// The original requested file doesn't exist, so the shim cannot exist either.
return undefined;
}
return generator.generate(originalSource, fileName);
}
return this.generator.factoryFor(sourceFile, fileName);
}
return this.delegate.getSourceFile(
fileName, languageVersion, onError, shouldCreateNewSourceFile);
@ -75,7 +92,11 @@ export class GeneratedFactoryHostWrapper implements ts.CompilerHost {
getNewLine(): string { return this.delegate.getNewLine(); }
fileExists(fileName: string): boolean {
return this.factoryToSourceMap.has(fileName) || this.delegate.fileExists(fileName);
const canonical = this.getCanonicalFileName(fileName);
// Consider the file as existing whenever 1) it really does exist in the delegate host, or
// 2) at least one of the shim generators recognizes it.
return this.delegate.fileExists(fileName) ||
this.shimGenerators.some(gen => gen.getOriginalSourceOfShim(canonical) !== null);
}
readFile(fileName: string): string|undefined { return this.delegate.readFile(fileName); }

View File

@ -0,0 +1,61 @@
/**
* @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 * as ts from 'typescript';
import {ShimGenerator} from './host';
import {isNonDeclarationTsFile} from './util';
export class SummaryGenerator implements ShimGenerator {
private constructor(private map: Map<string, string>) {}
getSummaryFileNames(): string[] { return Array.from(this.map.keys()); }
getOriginalSourceOfShim(fileName: string): string|null { return this.map.get(fileName) || null; }
generate(original: ts.SourceFile, genFilePath: string): ts.SourceFile {
// Collect a list of classes that need to have factory types emitted for them. This list is
// overly broad as at this point the ts.TypeChecker has not been created and so it can't be used
// to semantically understand which decorators are Angular decorators. It's okay to output an
// overly broad set of summary exports as the exports are no-ops anyway, and summaries are a
// compatibility layer which will be removed after Ivy is enabled.
const symbolNames = original
.statements
// Pick out top level class declarations...
.filter(ts.isClassDeclaration)
// which are named, exported, and have decorators.
.filter(
decl => isExported(decl) && decl.decorators !== undefined &&
decl.name !== undefined)
// Grab the symbol name.
.map(decl => decl.name !.text);
const varLines = symbolNames.map(name => `export const ${name}NgSummary: any = null;`);
if (varLines.length === 0) {
// In the event there are no other exports, add an empty export to ensure the generated
// summary file is still an ES module.
varLines.push(`export const ɵempty = null;`);
}
const sourceText = varLines.join('\n');
return ts.createSourceFile(
genFilePath, sourceText, original.languageVersion, true, ts.ScriptKind.TS);
}
static forRootFiles(files: ReadonlyArray<string>): SummaryGenerator {
const map = new Map<string, string>();
files.filter(sourceFile => isNonDeclarationTsFile(sourceFile))
.forEach(sourceFile => map.set(sourceFile.replace(/\.ts$/, '.ngsummary.ts'), sourceFile));
return new SummaryGenerator(map);
}
}
function isExported(decl: ts.Declaration): boolean {
return decl.modifiers !== undefined &&
decl.modifiers.some(mod => mod.kind == ts.SyntaxKind.ExportKeyword);
}

View File

@ -1,4 +1,3 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
@ -7,4 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
export * from './ivy_switch_on';
const TS_FILE = /\.tsx?$/;
const D_TS_FILE = /\.d\.ts$/;
export function isNonDeclarationTsFile(file: string): boolean {
return TS_FILE.exec(file) !== null && D_TS_FILE.exec(file) === null;
}

View File

@ -0,0 +1,19 @@
package(default_visibility = ["//visibility:public"])
load("//tools:defaults.bzl", "ts_library")
ts_library(
name = "switch",
srcs = glob([
"index.ts",
"src/**/*.ts",
]),
module_name = "@angular/compiler-cli/src/ngtsc/switch",
deps = [
"//packages/compiler",
"//packages/compiler-cli/src/ngtsc/host",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/util",
"@ngdeps//typescript",
],
)

View File

@ -1,4 +1,3 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
@ -7,4 +6,4 @@
* found in the LICENSE file at https://angular.io/license
*/
export * from './ivy_switch_on';
export {ivySwitchTransform} from './src/switch';

View File

@ -0,0 +1,152 @@
/**
* @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 * as ts from 'typescript';
const IVY_SWITCH_PRE_SUFFIX = '__PRE_R3__';
const IVY_SWITCH_POST_SUFFIX = '__POST_R3__';
export function ivySwitchTransform(_: ts.TransformationContext): ts.Transformer<ts.SourceFile> {
return flipIvySwitchInFile;
}
function flipIvySwitchInFile(sf: ts.SourceFile): ts.SourceFile {
// To replace the statements array, it must be copied. This only needs to happen if a statement
// must actually be replaced within the array, so the newStatements array is lazily initialized.
let newStatements: ts.Statement[]|undefined = undefined;
// Iterate over the statements in the file.
for (let i = 0; i < sf.statements.length; i++) {
const statement = sf.statements[i];
// Skip over everything that isn't a variable statement.
if (!ts.isVariableStatement(statement) || !hasIvySwitches(statement)) {
continue;
}
// This statement needs to be replaced. Check if the newStatements array needs to be lazily
// initialized to a copy of the original statements.
if (newStatements === undefined) {
newStatements = [...sf.statements];
}
// Flip any switches in the VariableStatement. If there were any, a new statement will be
// returned; otherwise the old statement will be.
newStatements[i] = flipIvySwitchesInVariableStatement(statement, sf.statements);
}
// Only update the statements in the SourceFile if any have changed.
if (newStatements !== undefined) {
sf.statements = ts.createNodeArray(newStatements);
}
return sf;
}
/**
* Look for the ts.Identifier of a ts.Declaration with this name.
*
* The real identifier is needed (rather than fabricating one) as TypeScript decides how to
* reference this identifier based on information stored against its node in the AST, which a
* synthetic node would not have. In particular, since the post-switch variable is often exported,
* TypeScript needs to know this so it can write `exports.VAR` instead of just `VAR` when emitting
* code.
*
* Only variable, function, and class declarations are currently searched.
*/
function findPostSwitchIdentifier(
statements: ReadonlyArray<ts.Statement>, name: string): ts.Identifier|null {
for (const stmt of statements) {
if (ts.isVariableStatement(stmt)) {
const decl = stmt.declarationList.declarations.find(
decl => ts.isIdentifier(decl.name) && decl.name.text === name);
if (decl !== undefined) {
return decl.name as ts.Identifier;
}
} else if (ts.isFunctionDeclaration(stmt) || ts.isClassDeclaration(stmt)) {
if (stmt.name !== undefined && ts.isIdentifier(stmt.name) && stmt.name.text === name) {
return stmt.name;
}
}
}
return null;
}
/**
* Flip any Ivy switches which are discovered in the given ts.VariableStatement.
*/
function flipIvySwitchesInVariableStatement(
stmt: ts.VariableStatement, statements: ReadonlyArray<ts.Statement>): ts.VariableStatement {
// Build a new list of variable declarations. Specific declarations that are initialized to a
// pre-switch identifier will be replaced with a declaration initialized to the post-switch
// identifier.
const newDeclarations = [...stmt.declarationList.declarations];
for (let i = 0; i < newDeclarations.length; i++) {
const decl = newDeclarations[i];
// Skip declarations that aren't initialized to an identifier.
if (decl.initializer === undefined || !ts.isIdentifier(decl.initializer)) {
continue;
}
// Skip declarations that aren't Ivy switches.
if (!decl.initializer.text.endsWith(IVY_SWITCH_PRE_SUFFIX)) {
continue;
}
// Determine the name of the post-switch variable.
const postSwitchName =
decl.initializer.text.replace(IVY_SWITCH_PRE_SUFFIX, IVY_SWITCH_POST_SUFFIX);
// Find the post-switch variable identifier. If one can't be found, it's an error. This is
// reported as a thrown error and not a diagnostic as transformers cannot output diagnostics.
let newIdentifier = findPostSwitchIdentifier(statements, postSwitchName);
if (newIdentifier === null) {
throw new Error(
`Unable to find identifier ${postSwitchName} in ${stmt.getSourceFile().fileName} for the Ivy switch.`);
}
// Copy the identifier with updateIdentifier(). This copies the internal information which
// allows TS to write a correct reference to the identifier.
newIdentifier = ts.updateIdentifier(newIdentifier);
newDeclarations[i] = ts.updateVariableDeclaration(
/* node */ decl,
/* name */ decl.name,
/* type */ decl.type,
/* initializer */ newIdentifier);
// Keeping parent pointers up to date is important for emit.
newIdentifier.parent = newDeclarations[i];
}
const newDeclList = ts.updateVariableDeclarationList(
/* declarationList */ stmt.declarationList,
/* declarations */ newDeclarations);
const newStmt = ts.updateVariableStatement(
/* statement */ stmt,
/* modifiers */ stmt.modifiers,
/* declarationList */ newDeclList);
// Keeping parent pointers up to date is important for emit.
for (const decl of newDeclarations) {
decl.parent = newDeclList;
}
newDeclList.parent = newStmt;
newStmt.parent = stmt.parent;
return newStmt;
}
/**
* Check whether the given VariableStatement has any Ivy switch variables.
*/
function hasIvySwitches(stmt: ts.VariableStatement) {
return stmt.declarationList.declarations.some(
decl => decl.initializer !== undefined && ts.isIdentifier(decl.initializer) &&
decl.initializer.text.endsWith(IVY_SWITCH_PRE_SUFFIX));
}

View File

@ -10,11 +10,15 @@ import {GeneratedFile} from '@angular/compiler';
import * as path from 'path';
import * as ts from 'typescript';
import {ivySwitchTransform} from '../ngtsc/switch';
import * as api from '../transformers/api';
/**
* An implementation of the `Program` API which behaves like plain `tsc` and does not include any
* Angular-specific behavior whatsoever.
* An implementation of the `Program` API which behaves similarly to plain `tsc`.
*
* The only Angular specific behavior included in this `Program` is the operation of the Ivy
* switch to turn on render3 behavior.
*
* This allows `ngc` to behave like `tsc` in cases where JIT code needs to be tested.
*/
@ -95,6 +99,7 @@ export class TscPassThroughProgram implements api.Program {
host: this.host,
options: this.options,
emitOnlyDtsFiles: false,
customTransformers: {before: [ivySwitchTransform]},
});
return emitResult;
}

View File

@ -572,6 +572,38 @@ describe('ngtsc behavioral tests', () => {
expect(emptyFactory).toContain(`export var ɵNonEmptyModule = true;`);
});
it('should generate a summary stub for decorated classes in the input file only', () => {
env.tsconfig({'allowEmptyCodegenFiles': true});
env.write('test.ts', `
import {Injectable, NgModule} from '@angular/core';
export class NotAModule {}
@NgModule({})
export class TestModule {}
`);
env.driveMain();
const summaryContents = env.getContents('test.ngsummary.js');
expect(summaryContents).toEqual(`export var TestModuleNgSummary = null;\n`);
});
it('it should generate empty export when there are no other summary symbols, to ensure the output is a valid ES module',
() => {
env.tsconfig({'allowEmptyCodegenFiles': true});
env.write('empty.ts', `
export class NotAModule {}
`);
env.driveMain();
const emptySummary = env.getContents('empty.ngsummary.js');
// The empty export ensures this js file is still an ES module.
expect(emptySummary).toEqual(`export var ɵempty = null;\n`);
});
it('should compile a banana-in-a-box inside of a template', () => {
env.tsconfig();
env.write('test.ts', `

View File

@ -9,14 +9,7 @@ ng_module(
"*.ts",
"src/**/*.ts",
],
exclude = [
"src/ivy_switch/compiler/index.ts",
"src/ivy_switch/runtime/index.ts",
],
) + [
":ivy_switch_compiler",
":ivy_switch_runtime",
],
),
module_name = "@angular/core",
deps = [
"//packages:types",
@ -42,30 +35,3 @@ ng_package(
"//packages/core/testing",
],
)
## Controls if Ivy is enabled. (Temporary target until we permanently switch over to Ivy)
##
## This file generates the `src/ivy_switch/compiler/index.ts` and `src/ivy_switch/runtime/index.ts` files which
## reexport symbols for `ViewEngine` or `Ivy.`
## - append `--define=compile=legacy` (default) to `bazel` command to reexport `./legacy` from each folder
## in the 'ivy_switch' directory and use `ViewEngine`
## - append `--define=compile=jit` to `bazel` command to rexport `./jit` from each folder in the `ivy_switch`
## directory and use `Ivy`
## - append `--define=compile=local` to `bazel` command to rexport `./ivy_switch/compiler/jit` and use `Ivy`
## in the local analysis mode. (run as part of `ngtsc`)
##
## NOTE: `--define=compile=jit` works with any `bazel` command or target across the repo.
##
## See: `//tools/bazel.rc` where `--define=ivy=false` is defined as default.
## See: `./src/ivy_switch/compiler/index.ts` for more details.
genrule(
name = "ivy_switch_compiler",
outs = ["src/ivy_switch/compiler/index.ts"],
cmd = "echo export '*' from \"'./$(compile)';\" > $@",
)
genrule(
name = "ivy_switch_runtime",
outs = ["src/ivy_switch/runtime/index.ts"],
cmd = "echo export '*' from \"'./$(compile)';\" > $@",
)

View File

@ -33,9 +33,9 @@ let _platform: PlatformRef;
let compileNgModuleFactory:
<M>(injector: Injector, options: CompilerOptions, moduleType: Type<M>) =>
Promise<NgModuleFactory<M>> = compileNgModuleFactory__PRE_NGCC__;
Promise<NgModuleFactory<M>> = compileNgModuleFactory__PRE_R3__;
function compileNgModuleFactory__PRE_NGCC__<M>(
function compileNgModuleFactory__PRE_R3__<M>(
injector: Injector, options: CompilerOptions,
moduleType: Type<M>): Promise<NgModuleFactory<M>> {
const compilerFactory: CompilerFactory = injector.get(CompilerFactory);
@ -43,7 +43,7 @@ function compileNgModuleFactory__PRE_NGCC__<M>(
return compiler.compileModuleAsync(moduleType);
}
export function compileNgModuleFactory__POST_NGCC__<M>(
export function compileNgModuleFactory__POST_R3__<M>(
injector: Injector, options: CompilerOptions,
moduleType: Type<M>): Promise<NgModuleFactory<M>> {
ngDevMode && assertNgModuleType(moduleType);

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {R3_CHANGE_DETECTOR_REF_FACTORY} from '../ivy_switch/runtime/index';
import {injectChangeDetectorRef as render3InjectChangeDetectorRef} from '../render3/view_engine_compatibility';
/**
* Base class for Angular Views, provides change detection functionality.
@ -108,5 +108,12 @@ export abstract class ChangeDetectorRef {
abstract reattach(): void;
/** @internal */
static __NG_ELEMENT_ID__: () => ChangeDetectorRef = () => R3_CHANGE_DETECTOR_REF_FACTORY();
static __NG_ELEMENT_ID__: () => ChangeDetectorRef = () => SWITCH_CHANGE_DETECTOR_REF_FACTORY();
}
export const SWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__ = render3InjectChangeDetectorRef;
const SWITCH_CHANGE_DETECTOR_REF_FACTORY__PRE_R3__ = (...args: any[]): any => {};
const SWITCH_CHANGE_DETECTOR_REF_FACTORY: typeof render3InjectChangeDetectorRef =
SWITCH_CHANGE_DETECTOR_REF_FACTORY__PRE_R3__;

View File

@ -16,7 +16,7 @@ export {Console as ɵConsole} from './console';
export {InjectableDef as ɵInjectableDef, InjectorDef as ɵInjectorDef, getInjectableDef as ɵgetInjectableDef} from './di/defs';
export {inject as ɵinject, setCurrentInjector as ɵsetCurrentInjector} from './di/injector';
export {APP_ROOT as ɵAPP_ROOT} from './di/scope';
export {ivyEnabled as ɵivyEnabled} from './ivy_switch/compiler/index';
export {ivyEnabled as ɵivyEnabled} from './ivy_switch';
export {ComponentFactory as ɵComponentFactory} from './linker/component_factory';
export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} from './linker/component_factory_resolver';
export {resolveComponentResources as ɵresolveComponentResources} from './metadata/resource_loading';

View File

@ -129,12 +129,17 @@ export { Render3DebugRendererFactory2 as ɵRender3DebugRendererFactory2 } from
export {
R3_COMPILE_NGMODULE_DEFS as ɵcompileNgModuleDefs,
R3_PATCH_COMPONENT_DEF_WTIH_SCOPE as ɵpatchComponentDefWithScope,
R3_COMPILE_COMPONENT as ɵcompileComponent,
R3_COMPILE_DIRECTIVE as ɵcompileDirective,
R3_COMPILE_PIPE as ɵcompilePipe,
} from './ivy_switch/compiler/ivy_switch_on';
compileComponent as ɵcompileComponent,
compileDirective as ɵcompileDirective,
} from './render3/jit/directive';
export {
compileNgModule as ɵcompileNgModule,
compileNgModuleDefs as ɵcompileNgModuleDefs,
patchComponentDefWithScope as ɵpatchComponentDefWithScope,
} from './render3/jit/module';
export {
compilePipe as ɵcompilePipe,
} from './render3/jit/pipe';
export {
NgModuleDef as ɵNgModuleDef,
@ -186,24 +191,37 @@ export {
//
// no code actually imports these symbols from the @angular/core entry point
export {
compileNgModuleFactory__POST_NGCC__ as ɵcompileNgModuleFactory__POST_NGCC__
compileNgModuleFactory__POST_R3__ as ɵcompileNgModuleFactory__POST_R3__
} from './application_ref';
export {
R3_COMPILE_COMPONENT__POST_NGCC__ as ɵR3_COMPILE_COMPONENT__POST_NGCC__,
R3_COMPILE_DIRECTIVE__POST_NGCC__ as ɵR3_COMPILE_DIRECTIVE__POST_NGCC__,
R3_COMPILE_INJECTABLE__POST_NGCC__ as ɵR3_COMPILE_INJECTABLE__POST_NGCC__,
R3_COMPILE_NGMODULE__POST_NGCC__ as ɵR3_COMPILE_NGMODULE__POST_NGCC__,
R3_COMPILE_PIPE__POST_NGCC__ as ɵR3_COMPILE_PIPE__POST_NGCC__,
ivyEnable__POST_NGCC__ as ɵivyEnable__POST_NGCC__,
} from './ivy_switch/compiler/legacy';
SWITCH_COMPILE_COMPONENT__POST_R3__ as ɵSWITCH_COMPILE_COMPONENT__POST_R3__,
SWITCH_COMPILE_DIRECTIVE__POST_R3__ as ɵSWITCH_COMPILE_DIRECTIVE__POST_R3__,
SWITCH_COMPILE_PIPE__POST_R3__ as ɵSWITCH_COMPILE_PIPE__POST_R3__,
} from './metadata/directives';
export {
R3_ELEMENT_REF_FACTORY__POST_NGCC__ as ɵR3_ELEMENT_REF_FACTORY__POST_NGCC__,
R3_TEMPLATE_REF_FACTORY__POST_NGCC__ as ɵR3_TEMPLATE_REF_FACTORY__POST_NGCC__,
R3_CHANGE_DETECTOR_REF_FACTORY__POST_NGCC__ as ɵR3_CHANGE_DETECTOR_REF_FACTORY__POST_NGCC__,
R3_VIEW_CONTAINER_REF_FACTORY__POST_NGCC__ as ɵR3_VIEW_CONTAINER_REF_FACTORY__POST_NGCC__,
R3_RENDERER2_FACTORY__POST_NGCC__ as ɵR3_RENDERER2_FACTORY__POST_NGCC__,
} from './ivy_switch/runtime/legacy';
SWITCH_COMPILE_NGMODULE__POST_R3__ as ɵSWITCH_COMPILE_NGMODULE__POST_R3__,
} from './metadata/ng_module';
export {
SWITCH_COMPILE_INJECTABLE__POST_R3__ as ɵSWITCH_COMPILE_INJECTABLE__POST_R3__,
} from './di/injectable';
export {
SWITCH_IVY_ENABLED__POST_R3__ as ɵSWITCH_IVY_ENABLED__POST_R3__,
} from './ivy_switch';
export {
SWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__ as ɵSWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__,
} from './change_detection/change_detector_ref';
export {
SWITCH_ELEMENT_REF_FACTORY__POST_R3__ as ɵSWITCH_ELEMENT_REF_FACTORY__POST_R3__,
} from './linker/element_ref';
export {
SWITCH_TEMPLATE_REF_FACTORY__POST_R3__ as ɵSWITCH_TEMPLATE_REF_FACTORY__POST_R3__,
} from './linker/template_ref';
export {
SWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__ as ɵSWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__,
} from './linker/view_container_ref';
export {
SWITCH_RENDERER2_FACTORY__POST_R3__ as ɵSWITCH_RENDERER2_FACTORY__POST_R3__,
} from './render/api';
// clang-format on

View File

@ -6,12 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
import {R3_COMPILE_INJECTABLE} from '../ivy_switch/compiler/index';
import {compileInjectable as render3CompileInjectable} from '../render3/jit/injectable';
import {Type} from '../type';
import {makeDecorator} from '../util/decorators';
import {InjectableDef, InjectableType} from './defs';
import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from './provider';
import {InjectableDef, InjectableType, defineInjectable, getInjectableDef} from './defs';
import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueSansProvider} from './provider';
import {convertInjectableProviderToFactory} from './util';
/**
* Injectable providers used in `@Injectable` decorator.
@ -64,7 +66,7 @@ export interface Injectable { providedIn?: Type<any>|'root'|null; }
*/
export const Injectable: InjectableDecorator = makeDecorator(
'Injectable', undefined, undefined, undefined,
(type: Type<any>, meta: Injectable) => R3_COMPILE_INJECTABLE(type, meta));
(type: Type<any>, meta: Injectable) => SWITCH_COMPILE_INJECTABLE(type as any, meta));
/**
* Type representing injectable service.
@ -72,3 +74,22 @@ export const Injectable: InjectableDecorator = makeDecorator(
* @publicApi
*/
export interface InjectableType<T> extends Type<T> { ngInjectableDef: InjectableDef<T>; }
/**
* Supports @Injectable() in JIT mode for Render2.
*/
function render2CompileInjectable(
injectableType: InjectableType<any>,
options: {providedIn?: Type<any>| 'root' | null} & InjectableProvider): void {
if (options && options.providedIn !== undefined && !getInjectableDef(injectableType)) {
injectableType.ngInjectableDef = defineInjectable({
providedIn: options.providedIn,
factory: convertInjectableProviderToFactory(injectableType, options),
});
}
}
export const SWITCH_COMPILE_INJECTABLE__POST_R3__ = render3CompileInjectable;
const SWITCH_COMPILE_INJECTABLE__PRE_R3__ = render2CompileInjectable;
const SWITCH_COMPILE_INJECTABLE: typeof render3CompileInjectable =
SWITCH_COMPILE_INJECTABLE__PRE_R3__;

View File

@ -0,0 +1,55 @@
/**
* @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 {ReflectionCapabilities} from '../reflection/reflection_capabilities';
import {Type} from '../type';
import {getClosureSafeProperty} from '../util/property';
import {inject, injectArgs} from './injector';
import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from './provider';
const USE_VALUE =
getClosureSafeProperty<ValueProvider>({provide: String, useValue: getClosureSafeProperty});
const EMPTY_ARRAY: any[] = [];
export function convertInjectableProviderToFactory(
type: Type<any>, provider?: ValueSansProvider | ExistingSansProvider | StaticClassSansProvider |
ConstructorSansProvider | FactorySansProvider | ClassSansProvider): () => any {
if (!provider) {
const reflectionCapabilities = new ReflectionCapabilities();
const deps = reflectionCapabilities.parameters(type);
// TODO - convert to flags.
return () => new type(...injectArgs(deps as any[]));
}
if (USE_VALUE in provider) {
const valueProvider = (provider as ValueSansProvider);
return () => valueProvider.useValue;
} else if ((provider as ExistingSansProvider).useExisting) {
const existingProvider = (provider as ExistingSansProvider);
return () => inject(existingProvider.useExisting);
} else if ((provider as FactorySansProvider).useFactory) {
const factoryProvider = (provider as FactorySansProvider);
return () => factoryProvider.useFactory(...injectArgs(factoryProvider.deps || EMPTY_ARRAY));
} else if ((provider as StaticClassSansProvider | ClassSansProvider).useClass) {
const classProvider = (provider as StaticClassSansProvider | ClassSansProvider);
let deps = (provider as StaticClassSansProvider).deps;
if (!deps) {
const reflectionCapabilities = new ReflectionCapabilities();
deps = reflectionCapabilities.parameters(type);
}
return () => new classProvider.useClass(...injectArgs(deps));
} else {
let deps = (provider as ConstructorSansProvider).deps;
if (!deps) {
const reflectionCapabilities = new ReflectionCapabilities();
deps = reflectionCapabilities.parameters(type);
}
return () => new type(...injectArgs(deps !));
}
}

View File

@ -6,4 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
export * from './ivy_switch_on';
export const SWITCH_IVY_ENABLED__POST_R3__ = true;
const SWITCH_IVY_ENABLED__PRE_R3__ = false;
export const ivyEnabled = SWITCH_IVY_ENABLED__PRE_R3__;

View File

@ -1,17 +0,0 @@
/**
* @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
*/
/**
* This file is used to control if the default rendering pipeline should be `ViewEngine` or `Ivy`.
*
* For more information on how to run and debug tests with either Ivy or View Engine (legacy),
* please see [BAZEL.md](./docs/BAZEL.md).
*/
export * from './legacy';
// TODO(alxhub): debug why metadata doesn't properly propagate through this file.

View File

@ -1,21 +0,0 @@
/**
* @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 {compileComponent, compileDirective} from '../../render3/jit/directive';
import {compileInjectable} from '../../render3/jit/injectable';
import {compileNgModule, compileNgModuleDefs, patchComponentDefWithScope} from '../../render3/jit/module';
import {compilePipe} from '../../render3/jit/pipe';
export const ivyEnabled = true;
export const R3_COMPILE_COMPONENT = compileComponent;
export const R3_COMPILE_DIRECTIVE = compileDirective;
export const R3_COMPILE_INJECTABLE = compileInjectable;
export const R3_COMPILE_NGMODULE = compileNgModule;
export const R3_COMPILE_PIPE = compilePipe;
export const R3_COMPILE_NGMODULE_DEFS = compileNgModuleDefs;
export const R3_PATCH_COMPONENT_DEF_WTIH_SCOPE = patchComponentDefWithScope;

View File

@ -1,126 +0,0 @@
/**
* @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 {InjectableType, InjectorType, defineInjectable, defineInjector, getInjectableDef} from '../../di/defs';
import {InjectableProvider} from '../../di/injectable';
import {inject, injectArgs} from '../../di/injector';
import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from '../../di/provider';
import {NgModule} from '../../metadata';
import {ReflectionCapabilities} from '../../reflection/reflection_capabilities';
import {Type} from '../../type';
import {getClosureSafeProperty} from '../../util/property';
import * as ivyOn from './ivy_switch_on';
function noop() {}
export interface DirectiveCompiler { (type: any, meta: any): void; }
export const R3_COMPILE_COMPONENT__POST_NGCC__: DirectiveCompiler = ivyOn.R3_COMPILE_COMPONENT;
export const R3_COMPILE_DIRECTIVE__POST_NGCC__: DirectiveCompiler = ivyOn.R3_COMPILE_DIRECTIVE;
export const R3_COMPILE_INJECTABLE__POST_NGCC__: DirectiveCompiler = ivyOn.R3_COMPILE_INJECTABLE;
export const R3_COMPILE_NGMODULE__POST_NGCC__: DirectiveCompiler = ivyOn.R3_COMPILE_NGMODULE;
export const R3_COMPILE_PIPE__POST_NGCC__: DirectiveCompiler = ivyOn.R3_COMPILE_PIPE;
export const R3_COMPILE_NGMODULE_DEFS__POST_NGCC__: DirectiveCompiler =
ivyOn.R3_COMPILE_NGMODULE_DEFS;
export const R3_PATCH_COMPONENT_DEF_WTIH_SCOPE__POST_NGCC__: DirectiveCompiler =
ivyOn.R3_PATCH_COMPONENT_DEF_WTIH_SCOPE;
export const ivyEnable__POST_NGCC__: boolean = ivyOn.ivyEnabled;
const R3_COMPILE_COMPONENT__PRE_NGCC__: DirectiveCompiler = noop;
const R3_COMPILE_DIRECTIVE__PRE_NGCC__: DirectiveCompiler = noop;
const R3_COMPILE_INJECTABLE__PRE_NGCC__: DirectiveCompiler = preR3InjectableCompile;
const R3_COMPILE_NGMODULE__PRE_NGCC__: DirectiveCompiler = preR3NgModuleCompile;
const R3_COMPILE_PIPE__PRE_NGCC__: DirectiveCompiler = noop;
const R3_COMPILE_NGMODULE_DEFS__PRE_NGCC__: DirectiveCompiler = noop;
const R3_PATCH_COMPONENT_DEF_WTIH_SCOPE__PRE_NGCC__: DirectiveCompiler = noop;
const ivyEnable__PRE_NGCC__ = false;
export const ivyEnabled = ivyEnable__PRE_NGCC__;
export let R3_COMPILE_COMPONENT: DirectiveCompiler = R3_COMPILE_COMPONENT__PRE_NGCC__;
export let R3_COMPILE_DIRECTIVE: DirectiveCompiler = R3_COMPILE_DIRECTIVE__PRE_NGCC__;
export let R3_COMPILE_INJECTABLE: DirectiveCompiler = R3_COMPILE_INJECTABLE__PRE_NGCC__;
export let R3_COMPILE_NGMODULE: DirectiveCompiler = R3_COMPILE_NGMODULE__PRE_NGCC__;
export let R3_COMPILE_PIPE: DirectiveCompiler = R3_COMPILE_PIPE__PRE_NGCC__;
export let R3_COMPILE_NGMODULE_DEFS: DirectiveCompiler = R3_COMPILE_NGMODULE_DEFS__PRE_NGCC__;
export let R3_PATCH_COMPONENT_DEF_WTIH_SCOPE: DirectiveCompiler =
R3_PATCH_COMPONENT_DEF_WTIH_SCOPE__PRE_NGCC__;
////////////////////////////////////////////////////////////
// Glue code which should be removed after Ivy is default //
////////////////////////////////////////////////////////////
function preR3NgModuleCompile(moduleType: InjectorType<any>, metadata: NgModule): void {
let imports = (metadata && metadata.imports) || [];
if (metadata && metadata.exports) {
imports = [...imports, metadata.exports];
}
moduleType.ngInjectorDef = defineInjector({
factory: convertInjectableProviderToFactory(moduleType, {useClass: moduleType}),
providers: metadata && metadata.providers,
imports: imports,
});
}
const USE_VALUE =
getClosureSafeProperty<ValueProvider>({provide: String, useValue: getClosureSafeProperty});
const EMPTY_ARRAY: any[] = [];
function convertInjectableProviderToFactory(type: Type<any>, provider?: InjectableProvider): () =>
any {
if (!provider) {
const reflectionCapabilities = new ReflectionCapabilities();
const deps = reflectionCapabilities.parameters(type);
// TODO - convert to flags.
return () => new type(...injectArgs(deps as any[]));
}
if (USE_VALUE in provider) {
const valueProvider = (provider as ValueSansProvider);
return () => valueProvider.useValue;
} else if ((provider as ExistingSansProvider).useExisting) {
const existingProvider = (provider as ExistingSansProvider);
return () => inject(existingProvider.useExisting);
} else if ((provider as FactorySansProvider).useFactory) {
const factoryProvider = (provider as FactorySansProvider);
return () => factoryProvider.useFactory(...injectArgs(factoryProvider.deps || EMPTY_ARRAY));
} else if ((provider as StaticClassSansProvider | ClassSansProvider).useClass) {
const classProvider = (provider as StaticClassSansProvider | ClassSansProvider);
let deps = (provider as StaticClassSansProvider).deps;
if (!deps) {
const reflectionCapabilities = new ReflectionCapabilities();
deps = reflectionCapabilities.parameters(type);
}
return () => new classProvider.useClass(...injectArgs(deps));
} else {
let deps = (provider as ConstructorSansProvider).deps;
if (!deps) {
const reflectionCapabilities = new ReflectionCapabilities();
deps = reflectionCapabilities.parameters(type);
}
return () => new type(...injectArgs(deps !));
}
}
/**
* Supports @Injectable() in JIT mode for Render2.
*/
function preR3InjectableCompile(
injectableType: InjectableType<any>,
options: {providedIn?: Type<any>| 'root' | null} & InjectableProvider): void {
if (options && options.providedIn !== undefined && !getInjectableDef(injectableType)) {
injectableType.ngInjectableDef = defineInjectable({
providedIn: options.providedIn,
factory: convertInjectableProviderToFactory(injectableType, options),
});
}
}

View File

@ -1,15 +0,0 @@
/**
* @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
*/
/**
* This file is used to control if the default rendering pipeline should be `ViewEngine` or `Ivy`.
*
* For more information on how to run and debug tests with either Ivy or View Engine (legacy),
* please see [BAZEL.md](./docs/BAZEL.md).
*/
export * from './legacy';

View File

@ -1,15 +0,0 @@
/**
* @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 {injectChangeDetectorRef, injectElementRef, injectRenderer2, injectTemplateRef, injectViewContainerRef} from '../../render3/view_engine_compatibility';
export const R3_ELEMENT_REF_FACTORY = injectElementRef;
export const R3_TEMPLATE_REF_FACTORY = injectTemplateRef;
export const R3_CHANGE_DETECTOR_REF_FACTORY = injectChangeDetectorRef;
export const R3_VIEW_CONTAINER_REF_FACTORY = injectViewContainerRef;
export const R3_RENDERER2_FACTORY = injectRenderer2;

View File

@ -1,34 +0,0 @@
/**
* @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 * as ivyOn from './ivy_switch_on';
function noopFactory(...tokens: any[]): any {}
type FactoryFunction<T = any> = (...tokens: any[]) => T;
export const R3_ELEMENT_REF_FACTORY__POST_NGCC__: FactoryFunction = ivyOn.R3_ELEMENT_REF_FACTORY;
export const R3_TEMPLATE_REF_FACTORY__POST_NGCC__: FactoryFunction = ivyOn.R3_TEMPLATE_REF_FACTORY;
export const R3_CHANGE_DETECTOR_REF_FACTORY__POST_NGCC__: FactoryFunction =
ivyOn.R3_CHANGE_DETECTOR_REF_FACTORY;
export const R3_VIEW_CONTAINER_REF_FACTORY__POST_NGCC__: FactoryFunction =
ivyOn.R3_VIEW_CONTAINER_REF_FACTORY;
export const R3_RENDERER2_FACTORY__POST_NGCC__: FactoryFunction = ivyOn.R3_RENDERER2_FACTORY;
export const R3_ELEMENT_REF_FACTORY__PRE_NGCC__ = noopFactory;
export const R3_TEMPLATE_REF_FACTORY__PRE_NGCC__ = noopFactory;
export const R3_CHANGE_DETECTOR_REF_FACTORY__PRE_NGCC__ = noopFactory;
export const R3_VIEW_CONTAINER_REF_FACTORY__PRE_NGCC__ = noopFactory;
export const R3_RENDERER2_FACTORY__PRE_NGCC__ = noopFactory;
export let R3_ELEMENT_REF_FACTORY = R3_ELEMENT_REF_FACTORY__PRE_NGCC__;
export let R3_TEMPLATE_REF_FACTORY = R3_TEMPLATE_REF_FACTORY__PRE_NGCC__;
export let R3_CHANGE_DETECTOR_REF_FACTORY = R3_CHANGE_DETECTOR_REF_FACTORY__PRE_NGCC__;
export let R3_VIEW_CONTAINER_REF_FACTORY = R3_VIEW_CONTAINER_REF_FACTORY__PRE_NGCC__;
export let R3_RENDERER2_FACTORY = R3_RENDERER2_FACTORY__PRE_NGCC__;

View File

@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {R3_ELEMENT_REF_FACTORY} from '../ivy_switch/runtime/index';
import {injectElementRef as render3InjectElementRef} from '../render3/view_engine_compatibility';
import {noop} from '../util/noop';
/**
* A wrapper around a native element inside of a View.
@ -50,5 +51,10 @@ export class ElementRef<T = any> {
constructor(nativeElement: T) { this.nativeElement = nativeElement; }
/** @internal */
static __NG_ELEMENT_ID__: () => ElementRef = () => R3_ELEMENT_REF_FACTORY(ElementRef);
static __NG_ELEMENT_ID__: () => ElementRef = () => SWITCH_ELEMENT_REF_FACTORY(ElementRef);
}
export const SWITCH_ELEMENT_REF_FACTORY__POST_R3__ = render3InjectElementRef;
const SWITCH_ELEMENT_REF_FACTORY__PRE_R3__ = noop;
const SWITCH_ELEMENT_REF_FACTORY: typeof render3InjectElementRef =
SWITCH_ELEMENT_REF_FACTORY__PRE_R3__;

View File

@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {R3_TEMPLATE_REF_FACTORY} from '../ivy_switch/runtime/index';
import {injectTemplateRef as render3InjectTemplateRef} from '../render3/view_engine_compatibility';
import {noop} from '../util/noop';
import {ElementRef} from './element_ref';
import {EmbeddedViewRef} from './view_ref';
@ -54,5 +55,10 @@ export abstract class TemplateRef<C> {
/** @internal */
static __NG_ELEMENT_ID__:
() => TemplateRef<any> = () => R3_TEMPLATE_REF_FACTORY(TemplateRef, ElementRef)
() => TemplateRef<any> = () => SWITCH_TEMPLATE_REF_FACTORY(TemplateRef, ElementRef)
}
export const SWITCH_TEMPLATE_REF_FACTORY__POST_R3__ = render3InjectTemplateRef;
const SWITCH_TEMPLATE_REF_FACTORY__PRE_R3__ = noop;
const SWITCH_TEMPLATE_REF_FACTORY: typeof render3InjectTemplateRef =
SWITCH_TEMPLATE_REF_FACTORY__PRE_R3__;

View File

@ -7,7 +7,8 @@
*/
import {Injector} from '../di/injector';
import {R3_VIEW_CONTAINER_REF_FACTORY} from '../ivy_switch/runtime/index';
import {injectViewContainerRef as render3InjectViewContainerRef} from '../render3/view_engine_compatibility';
import {noop} from '../util/noop';
import {ComponentFactory, ComponentRef} from './component_factory';
import {ElementRef} from './element_ref';
@ -145,5 +146,10 @@ export abstract class ViewContainerRef {
/** @internal */
static __NG_ELEMENT_ID__:
() => ViewContainerRef = () => R3_VIEW_CONTAINER_REF_FACTORY(ViewContainerRef, ElementRef)
() => ViewContainerRef = () => SWITCH_VIEW_CONTAINER_REF_FACTORY(ViewContainerRef, ElementRef)
}
export const SWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__ = render3InjectViewContainerRef;
const SWITCH_VIEW_CONTAINER_REF_FACTORY__PRE_R3__ = noop;
const SWITCH_VIEW_CONTAINER_REF_FACTORY: typeof render3InjectViewContainerRef =
SWITCH_VIEW_CONTAINER_REF_FACTORY__PRE_R3__;

View File

@ -8,10 +8,12 @@
import {ChangeDetectionStrategy} from '../change_detection/constants';
import {Provider} from '../di';
import {R3_COMPILE_COMPONENT, R3_COMPILE_DIRECTIVE, R3_COMPILE_PIPE} from '../ivy_switch/compiler/index';
import {NG_BASE_DEF} from '../render3/fields';
import {compileComponent as render3CompileComponent, compileDirective as render3CompileDirective} from '../render3/jit/directive';
import {compilePipe as render3CompilePipe} from '../render3/jit/pipe';
import {Type} from '../type';
import {TypeDecorator, makeDecorator, makePropDecorator} from '../util/decorators';
import {noop} from '../util/noop';
import {fillProperties} from '../util/property';
import {ViewEncapsulation} from './view';
@ -353,7 +355,7 @@ export interface Directive {
*/
export const Directive: DirectiveDecorator = makeDecorator(
'Directive', (dir: Directive = {}) => dir, undefined, undefined,
(type: Type<any>, meta: Directive) => R3_COMPILE_DIRECTIVE(type, meta));
(type: Type<any>, meta: Directive) => SWITCH_COMPILE_DIRECTIVE(type, meta));
/**
* Component decorator interface
@ -639,7 +641,8 @@ export interface Component extends Directive {
*/
export const Component: ComponentDecorator = makeDecorator(
'Component', (c: Component = {}) => ({changeDetection: ChangeDetectionStrategy.Default, ...c}),
Directive, undefined, (type: Type<any>, meta: Component) => R3_COMPILE_COMPONENT(type, meta));
Directive, undefined,
(type: Type<any>, meta: Component) => SWITCH_COMPILE_COMPONENT(type, meta));
/**
* Type of the Pipe decorator / constructor function.
@ -688,7 +691,7 @@ export interface Pipe {
*/
export const Pipe: PipeDecorator = makeDecorator(
'Pipe', (p: Pipe) => ({pure: true, ...p}), undefined, undefined,
(type: Type<any>, meta: Pipe) => R3_COMPILE_PIPE(type, meta));
(type: Type<any>, meta: Pipe) => SWITCH_COMPILE_PIPE(type, meta));
/**
@ -962,3 +965,17 @@ export interface HostListener {
*/
export const HostListener: HostListenerDecorator =
makePropDecorator('HostListener', (eventName?: string, args?: string[]) => ({eventName, args}));
export const SWITCH_COMPILE_COMPONENT__POST_R3__ = render3CompileComponent;
export const SWITCH_COMPILE_DIRECTIVE__POST_R3__ = render3CompileDirective;
export const SWITCH_COMPILE_PIPE__POST_R3__ = render3CompilePipe;
const SWITCH_COMPILE_COMPONENT__PRE_R3__ = noop;
const SWITCH_COMPILE_DIRECTIVE__PRE_R3__ = noop;
const SWITCH_COMPILE_PIPE__PRE_R3__ = noop;
const SWITCH_COMPILE_COMPONENT: typeof render3CompileComponent = SWITCH_COMPILE_COMPONENT__PRE_R3__;
const SWITCH_COMPILE_DIRECTIVE: typeof render3CompileDirective = SWITCH_COMPILE_DIRECTIVE__PRE_R3__;
const SWITCH_COMPILE_PIPE: typeof render3CompilePipe = SWITCH_COMPILE_PIPE__PRE_R3__;

View File

@ -7,8 +7,10 @@
*/
import {ApplicationRef} from '../application_ref';
import {InjectorType, defineInjector} from '../di/defs';
import {Provider} from '../di/provider';
import {R3_COMPILE_NGMODULE} from '../ivy_switch/compiler/index';
import {convertInjectableProviderToFactory} from '../di/util';
import {compileNgModule as render3CompileNgModule} from '../render3/jit/module';
import {Type} from '../type';
import {TypeDecorator, makeDecorator} from '../util/decorators';
@ -333,7 +335,7 @@ export const NgModule: NgModuleDecorator = makeDecorator(
* * The `imports` and `exports` options bring in members from other modules, and make
* this module's members available to others.
*/
(type: Type<any>, meta: NgModule) => R3_COMPILE_NGMODULE(type, meta));
(type: Type<any>, meta: NgModule) => SWITCH_COMPILE_NGMODULE(type, meta));
/**
* @description
@ -356,3 +358,21 @@ export const NgModule: NgModuleDecorator = makeDecorator(
* @publicApi
*/
export interface DoBootstrap { ngDoBootstrap(appRef: ApplicationRef): void; }
function preR3NgModuleCompile(moduleType: InjectorType<any>, metadata: NgModule): void {
let imports = (metadata && metadata.imports) || [];
if (metadata && metadata.exports) {
imports = [...imports, metadata.exports];
}
moduleType.ngInjectorDef = defineInjector({
factory: convertInjectableProviderToFactory(moduleType, {useClass: moduleType}),
providers: metadata && metadata.providers,
imports: imports,
});
}
export const SWITCH_COMPILE_NGMODULE__POST_R3__ = render3CompileNgModule;
const SWITCH_COMPILE_NGMODULE__PRE_R3__ = preR3NgModuleCompile;
const SWITCH_COMPILE_NGMODULE: typeof render3CompileNgModule = SWITCH_COMPILE_NGMODULE__PRE_R3__;

View File

@ -8,8 +8,9 @@
import {InjectionToken} from '../di/injection_token';
import {Injector} from '../di/injector';
import {R3_RENDERER2_FACTORY} from '../ivy_switch/runtime/index';
import {ViewEncapsulation} from '../metadata/view';
import {injectRenderer2 as render3InjectRenderer2} from '../render3/view_engine_compatibility';
import {noop} from '../util/noop';
/**
@ -373,5 +374,10 @@ export abstract class Renderer2 {
callback: (event: any) => boolean | void): () => void;
/** @internal */
static __NG_ELEMENT_ID__: () => Renderer2 = () => R3_RENDERER2_FACTORY();
static __NG_ELEMENT_ID__: () => Renderer2 = () => SWITCH_RENDERER2_FACTORY();
}
export const SWITCH_RENDERER2_FACTORY__POST_R3__ = render3InjectRenderer2;
const SWITCH_RENDERER2_FACTORY__PRE_R3__ = noop;
const SWITCH_RENDERER2_FACTORY: typeof render3InjectRenderer2 = SWITCH_RENDERER2_FACTORY__PRE_R3__;

View File

@ -205,9 +205,15 @@ The goal is for the `@Component` (and friends) to be the compiler of template. S
### I18N
| Feature | Runtime | Spec | Compiler |
| ----------------------------------- | ------- | -------- | -------- |
| translate text literals | ❌ | | ✅ |
| rearrange text nodes | ❌ | | |
| ICU | ❌ | | |
| i18nStart | ❌ | | ✅ |
| i18nEnd | ❌ | | |
| i18nAttributes | ❌ | | |
| i18nExp | ❌ | ✅ | ✅ |
| i18nApply | ❌ | ✅ | ✅ |
| ICU expressions | ❌ | ✅ | ❌ |
| closure support for g3 | ✅ | ✅ | ❌ |
| runtime service for external world | ❌ | ❌ | ❌ |
| migration tool | ❌ | ❌ | ❌ |
### View Encapsulation

View File

@ -502,6 +502,12 @@ function executePipeOnDestroys(viewData: LViewData): void {
export function getRenderParent(tNode: TNode, currentView: LViewData): RElement|null {
if (canInsertNativeNode(tNode, currentView)) {
const hostTNode = currentView[HOST_NODE];
const tNodeParent = tNode.parent;
if (tNodeParent != null && tNodeParent.type === TNodeType.ElementContainer) {
tNode = getHighestElementContainer(tNodeParent);
}
return tNode.parent == null && hostTNode !.type === TNodeType.View ?
getContainerRenderParent(hostTNode as TViewNode, currentView) :
getParentNative(tNode, currentView) as RElement;
@ -626,8 +632,7 @@ export function appendChild(
renderer, lContainer[RENDER_PARENT] !, childEl,
getBeforeNodeForView(index, views, lContainer[NATIVE]));
} else if (parentTNode.type === TNodeType.ElementContainer) {
let elementContainer = getHighestElementContainer(childTNode);
let renderParent: RElement = getRenderParent(elementContainer, currentView) !;
const renderParent: RElement = getRenderParent(childTNode, currentView) !;
nativeInsertBefore(renderer, renderParent, childEl, parentEl);
} else {
isProceduralRenderer(renderer) ? renderer.appendChild(parentEl !as RElement, childEl) :

View File

@ -6,4 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
export * from './ivy_switch_on';
export function noop(...args: any[]): any {
// Do nothing.
}

View File

@ -12,7 +12,7 @@ import {InjectableDef, getInjectableDef} from '../di/defs';
import {InjectableType} from '../di/injectable';
import {ErrorHandler} from '../error_handler';
import {isDevMode} from '../is_dev_mode';
import {ivyEnabled} from '../ivy_switch/compiler/index';
import {ivyEnabled} from '../ivy_switch';
import {ComponentFactory} from '../linker/component_factory';
import {NgModuleRef} from '../linker/ng_module_factory';
import {Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2} from '../render/api';

View File

@ -37,6 +37,7 @@ js_expected_symbol_test(
src = ":bundle.min_debug.js",
golden = ":bundle.golden_symbols.json",
tags = [
"ivy-aot",
"ivy-only",
],
)

View File

@ -158,15 +158,6 @@
{
"name": "QUERIES"
},
{
"name": "R3_ELEMENT_REF_FACTORY"
},
{
"name": "R3_TEMPLATE_REF_FACTORY"
},
{
"name": "R3_VIEW_CONTAINER_REF_FACTORY"
},
{
"name": "RENDERER"
},
@ -185,6 +176,15 @@
{
"name": "SANITIZER"
},
{
"name": "SWITCH_ELEMENT_REF_FACTORY"
},
{
"name": "SWITCH_TEMPLATE_REF_FACTORY"
},
{
"name": "SWITCH_VIEW_CONTAINER_REF_FACTORY"
},
{
"name": "SimpleKeyframePlayer"
},

View File

@ -59,6 +59,7 @@ js_expected_symbol_test(
src = ":bundle.min_debug.js",
golden = ":bundle.golden_symbols.json",
tags = [
"ivy-aot",
"ivy-only",
],
)

View File

@ -1250,24 +1250,6 @@
{
"name": "Quote"
},
{
"name": "R3_CHANGE_DETECTOR_REF_FACTORY$1"
},
{
"name": "R3_COMPILE_INJECTABLE$1"
},
{
"name": "R3_ELEMENT_REF_FACTORY$1"
},
{
"name": "R3_RENDERER2_FACTORY$1"
},
{
"name": "R3_TEMPLATE_REF_FACTORY$1"
},
{
"name": "R3_VIEW_CONTAINER_REF_FACTORY$1"
},
{
"name": "ReadKeyExpr"
},
@ -1352,6 +1334,24 @@
{
"name": "STYLE_PREFIX"
},
{
"name": "SWITCH_CHANGE_DETECTOR_REF_FACTORY"
},
{
"name": "SWITCH_COMPILE_INJECTABLE"
},
{
"name": "SWITCH_ELEMENT_REF_FACTORY"
},
{
"name": "SWITCH_RENDERER2_FACTORY"
},
{
"name": "SWITCH_TEMPLATE_REF_FACTORY"
},
{
"name": "SWITCH_VIEW_CONTAINER_REF_FACTORY"
},
{
"name": "SafeMethodCall"
},
@ -1599,10 +1599,10 @@
"name": "URL_WITH_SCHEMA_REGEXP"
},
{
"name": "USE_VALUE"
"name": "USE_VALUE$1"
},
{
"name": "USE_VALUE$3"
"name": "USE_VALUE$2"
},
{
"name": "UnsubscriptionError"
@ -2460,7 +2460,7 @@
"name": "compileNgModuleFactory"
},
{
"name": "compileNgModuleFactory__PRE_NGCC__"
"name": "compileNgModuleFactory__PRE_R3__"
},
{
"name": "componentFactoryName"
@ -3411,10 +3411,10 @@
"name": "noop$1"
},
{
"name": "noop$3"
"name": "noop$2"
},
{
"name": "noopFactory"
"name": "noop$3"
},
{
"name": "noopScope"
@ -3476,9 +3476,6 @@
{
"name": "platformCoreDynamic"
},
{
"name": "preR3InjectableCompile"
},
{
"name": "preparseElement"
},
@ -3554,6 +3551,9 @@
{
"name": "removeWhitespaces"
},
{
"name": "render2CompileInjectable"
},
{
"name": "renderAttachEmbeddedView"
},

View File

@ -60,7 +60,7 @@
"name": "THROW_IF_NOT_FOUND"
},
{
"name": "USE_VALUE"
"name": "USE_VALUE$1"
},
{
"name": "UnsubscriptionErrorImpl"
@ -147,12 +147,12 @@
"name": "providerToRecord"
},
{
"name": "resolveForwardRef"
"name": "resolveForwardRef$1"
},
{
"name": "setCurrentInjector"
},
{
"name": "stringify"
"name": "stringify$1"
}
]

View File

@ -66,6 +66,7 @@ js_expected_symbol_test(
src = ":bundle.min_debug.js",
golden = ":bundle.golden_symbols.json",
tags = [
"ivy-aot",
"ivy-only",
],
)

View File

@ -152,15 +152,6 @@
{
"name": "QUERIES"
},
{
"name": "R3_ELEMENT_REF_FACTORY"
},
{
"name": "R3_TEMPLATE_REF_FACTORY"
},
{
"name": "R3_VIEW_CONTAINER_REF_FACTORY"
},
{
"name": "RENDERER"
},
@ -179,6 +170,15 @@
{
"name": "SANITIZER"
},
{
"name": "SWITCH_ELEMENT_REF_FACTORY"
},
{
"name": "SWITCH_TEMPLATE_REF_FACTORY"
},
{
"name": "SWITCH_VIEW_CONTAINER_REF_FACTORY"
},
{
"name": "SkipSelf"
},

View File

@ -72,6 +72,7 @@ js_expected_symbol_test(
src = ":bundle.min_debug.js",
golden = ":bundle.golden_symbols.json",
tags = [
"ivy-aot",
"ivy-only",
],
)

View File

@ -140,9 +140,6 @@
{
"name": "Compiler"
},
{
"name": "CompilerFactory"
},
{
"name": "ComponentFactory"
},
@ -680,21 +677,6 @@
{
"name": "R3Injector"
},
{
"name": "R3_CHANGE_DETECTOR_REF_FACTORY"
},
{
"name": "R3_ELEMENT_REF_FACTORY"
},
{
"name": "R3_RENDERER2_FACTORY"
},
{
"name": "R3_TEMPLATE_REF_FACTORY"
},
{
"name": "R3_VIEW_CONTAINER_REF_FACTORY"
},
{
"name": "REMOVE_EVENT_LISTENER"
},
@ -758,6 +740,21 @@
{
"name": "SURROGATE_PAIR_REGEXP"
},
{
"name": "SWITCH_CHANGE_DETECTOR_REF_FACTORY"
},
{
"name": "SWITCH_ELEMENT_REF_FACTORY"
},
{
"name": "SWITCH_RENDERER2_FACTORY"
},
{
"name": "SWITCH_TEMPLATE_REF_FACTORY"
},
{
"name": "SWITCH_VIEW_CONTAINER_REF_FACTORY"
},
{
"name": "SafeHtmlImpl"
},
@ -1281,7 +1278,7 @@
"name": "compileNgModuleFactory"
},
{
"name": "compileNgModuleFactory__PRE_NGCC__"
"name": "compileNgModuleFactory__POST_R3__"
},
{
"name": "componentRefresh"
@ -2157,10 +2154,10 @@
"name": "noSideEffects"
},
{
"name": "noop$1"
"name": "noop$2"
},
{
"name": "noop$2"
"name": "noop$3"
},
{
"name": "noopScope"

View File

@ -6,9 +6,9 @@ load("//tools:defaults.bzl", "ts_library")
ts_library(
name = "reflect_metadata",
srcs = [
"src/reflect_metadata_aot.ts",
"src/reflect_metadata_jit.ts",
"src/reflect_metadata_legacy.ts",
"src/reflect_metadata_local.ts",
":metadata_switch",
],
module_name = "@angular/core/test/bundling/util/src/reflect_metadata",

View File

@ -943,6 +943,116 @@ describe('render3 integration test', () => {
expect(directive !.elRef.nativeElement.nodeType).toBe(Node.COMMENT_NODE);
});
it('should support ViewContainerRef when ng-container is at the root of a view', () => {
function ContentTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
text(0, 'Content');
}
}
class Directive {
contentTpl: TemplateRef<{}>|null = null;
constructor(private _vcRef: ViewContainerRef) {}
insertView() { this._vcRef.createEmbeddedView(this.contentTpl as TemplateRef<{}>); }
clear() { this._vcRef.clear(); }
static ngDirectiveDef = defineDirective({
type: Directive,
selectors: [['', 'dir', '']],
factory: () => directive = new Directive(directiveInject(ViewContainerRef as any)),
inputs: {contentTpl: 'contentTpl'},
});
}
let directive: Directive;
/**
* <ng-container dir [contentTpl]="content">
* <ng-template #content>Content</ng-template>
* </ng-container>
*/
const App = createComponent('app', function(rf: RenderFlags) {
if (rf & RenderFlags.Create) {
elementContainerStart(0, [AttributeMarker.SelectOnly, 'dir']);
template(1, ContentTemplate, 1, 0, '', null, ['content', ''], templateRefExtractor);
elementContainerEnd();
}
if (rf & RenderFlags.Update) {
const content = reference(2) as any;
elementProperty(0, 'contentTpl', bind(content));
}
}, 3, 1, [Directive]);
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('');
directive !.insertView();
fixture.update();
expect(fixture.html).toEqual('Content');
directive !.clear();
fixture.update();
expect(fixture.html).toEqual('');
});
it('should support ViewContainerRef on <ng-template> inside <ng-container>', () => {
function ContentTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
text(0, 'Content');
}
}
class Directive {
constructor(private _tplRef: TemplateRef<{}>, private _vcRef: ViewContainerRef) {}
insertView() { this._vcRef.createEmbeddedView(this._tplRef); }
clear() { this._vcRef.clear(); }
static ngDirectiveDef = defineDirective({
type: Directive,
selectors: [['', 'dir', '']],
factory:
() => directive = new Directive(
directiveInject(TemplateRef as any), directiveInject(ViewContainerRef as any)),
});
}
let directive: Directive;
/**
* <ng-container>
* <ng-template dir>Content</ng-template>
* </ng-container>
*/
const App = createComponent('app', function(rf: RenderFlags) {
if (rf & RenderFlags.Create) {
elementContainerStart(0);
template(
1, ContentTemplate, 1, 0, '', [AttributeMarker.SelectOnly, 'dir'], [],
templateRefExtractor);
elementContainerEnd();
}
}, 2, 0, [Directive]);
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('');
directive !.insertView();
fixture.update();
expect(fixture.html).toEqual('Content');
directive !.clear();
fixture.update();
expect(fixture.html).toEqual('');
});
it('should not set any attributes', () => {
/**
* <div><ng-container id="foo"></ng-container></div>

View File

@ -11,7 +11,7 @@ import 'reflect-metadata';
import {InjectorDef, defineInjectable} from '@angular/core/src/di/defs';
import {Injectable} from '@angular/core/src/di/injectable';
import {inject, setCurrentInjector} from '@angular/core/src/di/injector';
import {ivyEnabled} from '@angular/core/src/ivy_switch/compiler/index';
import {ivyEnabled} from '@angular/core/src/ivy_switch';
import {Component, HostBinding, HostListener, Input, Output, Pipe} from '@angular/core/src/metadata/directives';
import {NgModule, NgModuleDef} from '@angular/core/src/metadata/ng_module';
import {ComponentDef, PipeDef} from '@angular/core/src/render3/interfaces/definition';

View File

@ -13,8 +13,12 @@ import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref';
import {Renderer2} from '@angular/core/src/render/api';
import {stringifyElement} from '@angular/platform-browser/testing/src/browser_util';
import {SWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__ as R3_CHANGE_DETECTOR_REF_FACTORY} from '../../src/change_detection/change_detector_ref';
import {Injector} from '../../src/di/injector';
import {R3_CHANGE_DETECTOR_REF_FACTORY, R3_ELEMENT_REF_FACTORY, R3_RENDERER2_FACTORY, R3_TEMPLATE_REF_FACTORY, R3_VIEW_CONTAINER_REF_FACTORY} from '../../src/ivy_switch/runtime/ivy_switch_on';
import {SWITCH_ELEMENT_REF_FACTORY__POST_R3__ as R3_ELEMENT_REF_FACTORY} from '../../src/linker/element_ref';
import {SWITCH_TEMPLATE_REF_FACTORY__POST_R3__ as R3_TEMPLATE_REF_FACTORY} from '../../src/linker/template_ref';
import {SWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__ as R3_VIEW_CONTAINER_REF_FACTORY} from '../../src/linker/view_container_ref';
import {SWITCH_RENDERER2_FACTORY__POST_R3__ as R3_RENDERER2_FACTORY} from '../../src/render/api';
import {CreateComponentOptions} from '../../src/render3/component';
import {discoverDirectives, getContext, isComponentInstance} from '../../src/render3/context_discovery';
import {extractDirectiveDef, extractPipeDef} from '../../src/render3/definition';

View File

@ -0,0 +1,52 @@
/**
* @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 {Observable, OperatorFunction, combineLatest} from 'rxjs';
import {filter, scan, startWith, switchMap, take} from 'rxjs/operators';
import {UrlTree} from '../url_tree';
const INITIAL_VALUE = Symbol('INITIAL_VALUE');
declare type INTERIM_VALUES = typeof INITIAL_VALUE | boolean | UrlTree;
export function prioritizedGuardValue():
OperatorFunction<Observable<boolean|UrlTree>[], boolean|UrlTree> {
return switchMap(obs => {
return combineLatest(
...obs.map(o => o.pipe(take(1), startWith(INITIAL_VALUE as INTERIM_VALUES))))
.pipe(
scan(
(acc: INTERIM_VALUES, list: INTERIM_VALUES[]) => {
let isPending = false;
return list.reduce((innerAcc, val, i: number) => {
if (innerAcc !== INITIAL_VALUE) return innerAcc;
// Toggle pending flag if any values haven't been set yet
if (val === INITIAL_VALUE) isPending = true;
// Any other return values are only valid if we haven't yet hit a pending call.
// This guarantees that in the case of a guard at the bottom of the tree that
// returns a redirect, we will wait for the higher priority guard at the top to
// finish before performing the redirect.
if (!isPending) {
// Early return when we hit a `false` value as that should always cancel
// navigation
if (val === false) return val;
if (i === list.length - 1 || val instanceof UrlTree) {
return val;
}
}
return innerAcc;
}, acc);
},
INITIAL_VALUE),
filter(item => item !== INITIAL_VALUE), take(1)) as Observable<boolean|UrlTree>;
});
}

View File

@ -16,6 +16,7 @@ ts_library(
"//packages/router/testing",
"@rxjs",
"@rxjs//operators",
"@rxjs//testing",
],
)

View File

@ -0,0 +1,182 @@
/**
* @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 {TestBed} from '@angular/core/testing';
import {Observable, Observer, of } from 'rxjs';
import {every, mergeMap} from 'rxjs/operators';
import {TestScheduler} from 'rxjs/testing';
import {prioritizedGuardValue} from '../../src/operators/prioritized_guard_value';
import {Router} from '../../src/router';
import {UrlTree} from '../../src/url_tree';
import {RouterTestingModule} from '../../testing/src/router_testing_module';
describe('prioritizedGuardValue operator', () => {
let testScheduler: TestScheduler;
let router: Router;
const TF = {T: true, F: false};
beforeEach(() => { TestBed.configureTestingModule({imports: [RouterTestingModule]}); });
beforeEach(() => { testScheduler = new TestScheduler(assertDeepEquals); });
beforeEach(() => { router = TestBed.get(Router); });
it('should return true if all values are true', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const a = cold(' --(T|)', TF);
const b = cold(' ----------(T|)', TF);
const c = cold(' ------(T|)', TF);
const source = hot('---o--', {o: [a, b, c]});
const expected = ' -------------T--';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, TF, /* an error here maybe */);
});
});
it('should return false if observables to the left of false have produced a value', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const a = cold(' --(T|)', TF);
const b = cold(' ----------(T|)', TF);
const c = cold(' ------(F|)', TF);
const source = hot('---o--', {o: [a, b, c]});
const expected = ' -------------F--';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, TF, /* an error here maybe */);
});
});
it('should ignore results for unresolved sets of Observables', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const a = cold(' --(T|)', TF);
const b = cold(' -------------(T|)', TF);
const c = cold(' ------(F|)', TF);
const z = cold(' ----(T|)', TF);
const source = hot('---o----p----', {o: [a, b, c], p: [z]});
const expected = ' ------------T---';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, TF, /* an error here maybe */);
});
});
it('should return UrlTree if higher priority guards have resolved', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const urlTree = router.parseUrl('/');
const urlLookup = {U: urlTree};
const a = cold(' --(T|)', TF);
const b = cold(' ----------(U|)', urlLookup);
const c = cold(' ------(T|)', TF);
const source = hot('---o---', {o: [a, b, c]});
const expected = ' -------------U---';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, urlLookup, /* an error here maybe */);
});
});
it('should return false even with UrlTree if UrlTree is lower priority', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const urlTree = router.parseUrl('/');
const urlLookup = {U: urlTree};
const a = cold(' --(T|)', TF);
const b = cold(' ----------(F|)', TF);
const c = cold(' ------(U|)', urlLookup);
const source = hot('---o---', {o: [a, b, c]});
const expected = ' -------------F---';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, TF, /* an error here maybe */);
});
});
it('should return UrlTree even after a false if the false is lower priority', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const urlTree = router.parseUrl('/');
const urlLookup = {U: urlTree};
const a = cold(' --(T|)', TF);
const b = cold(' ----------(U|)', urlLookup);
const c = cold(' ------(F|)', TF);
const source = hot('---o---', {o: [a, b, c]});
const expected = ' -------------U----';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, urlLookup, /* an error here maybe */);
});
});
it('should return the highest priority UrlTree', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const urlTreeU = router.parseUrl('/u');
const urlTreeR = router.parseUrl('/r');
const urlTreeL = router.parseUrl('/l');
const urlLookup = {U: urlTreeU, R: urlTreeR, L: urlTreeL};
const a = cold(' ----------(U|)', urlLookup);
const b = cold(' -----(R|)', urlLookup);
const c = cold(' --(L|)', urlLookup);
const source = hot('---o---', {o: [a, b, c]});
const expected = ' -------------U---';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, urlLookup, /* an error here maybe */);
});
});
it('should propagate errors', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const a = cold(' --(T|)', TF);
const b = cold(' ------#', TF);
const c = cold(' ----------(F|)', TF);
const source = hot('---o------', {o: [a, b, c]});
const expected = ' ---------#';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, TF, /* an error here maybe */);
});
});
});
function assertDeepEquals(a: any, b: any) {
return expect(a).toEqual(b);
}

File diff suppressed because it is too large Load Diff