Compare commits
146 Commits
7.0.1
...
7.1.0-beta
Author | SHA1 | Date | |
---|---|---|---|
67789f10ef | |||
b83f1300bd | |||
6e16a17015 | |||
d744dd70e0 | |||
4e91ead40b | |||
7f39f37003 | |||
bf9ab53f12 | |||
d99f661af7 | |||
5d58a31d86 | |||
07b89902d5 | |||
ce6948fc1b | |||
38d626a3fa | |||
9b8a244a15 | |||
1bbf28ad19 | |||
3b24e0edb6 | |||
b647608c96 | |||
31c462ae3f | |||
da39fd70d2 | |||
ee0b857172 | |||
e0d6782d26 | |||
2f9e957523 | |||
38dbae9ca0 | |||
5a3077f46c | |||
d0cc019c1a | |||
26e8032bd0 | |||
84af7b065d | |||
83dc3c0ee0 | |||
5952775a03 | |||
57531737e5 | |||
3fd50f07fd | |||
4237c34c78 | |||
361eaf1888 | |||
cca89ec36e | |||
e4c7f369f2 | |||
d573a14119 | |||
ff767dd153 | |||
34c6ce6b08 | |||
6737e91974 | |||
1006eab482 | |||
a9f2952882 | |||
100c7eff25 | |||
dc7349915d | |||
213c25fb08 | |||
615a515bba | |||
838a3f204f | |||
15c2467dbd | |||
74ea4e9b5d | |||
4481571999 | |||
2132c8f461 | |||
2b3cac5b31 | |||
8d5e3e6981 | |||
30f1dc002a | |||
5da3b00222 | |||
631998b2df | |||
30d6233e83 | |||
6468711e16 | |||
d698b0eadf | |||
1f3331f5e6 | |||
b6c9678f21 | |||
4c2ce4e8ba | |||
bb0f95b6fb | |||
853faf4c71 | |||
00c7db02d1 | |||
13143b850e | |||
c1724062f1 | |||
7570f7222f | |||
f1e3d5125d | |||
3511f08a81 | |||
982bc7f2aa | |||
3903e5ebe7 | |||
0918adf39d | |||
42c331bbf2 | |||
0bae97a726 | |||
c5949f85ef | |||
24521f549c | |||
4bd9f53e8f | |||
2a78dcbd5a | |||
2ea57cdcc3 | |||
31022cbecf | |||
ce8053103e | |||
0b885ecaf7 | |||
1700bd6f08 | |||
b89bc37170 | |||
39df4dbde7 | |||
716d887e51 | |||
5b4cf38166 | |||
4c0ad5238e | |||
9e8903ada1 | |||
aa55d88408 | |||
07fc4c2464 | |||
b9bd95b3b2 | |||
3f89aeb80a | |||
6c530d3a85 | |||
03bf0d6b41 | |||
d4cee514f6 | |||
331989cea3 | |||
bbf96db2f2 | |||
72c2578d14 | |||
1a666dea61 | |||
7634c1cb31 | |||
95914a0fbf | |||
9c50891d6e | |||
624433c51d | |||
09cc458bfc | |||
efe0c5f371 | |||
d9d226087c | |||
7bad1d356d | |||
0add00a743 | |||
d557f1d9de | |||
665627e254 | |||
a609bf50ed | |||
f8195e5e3d | |||
65b209359a | |||
3a65c9ad4e | |||
77e58c6179 | |||
23d625172a | |||
c3643615fc | |||
638aaecc7d | |||
5a79decba4 | |||
225162aa6c | |||
a43b80a4c9 | |||
beebf7fe14 | |||
0ef1f7ef0d | |||
fc6dad40ac | |||
ecd473bbce | |||
8a3fd58cad | |||
8024857d4c | |||
3fa876c5e7 | |||
516515d9e3 | |||
948f507ba0 | |||
81a8ee1ddb | |||
5e58da14f0 | |||
fa8e633be5 | |||
be337a2e52 | |||
4d164b6ca4 | |||
371ffef4ce | |||
fdfedceeec | |||
9e5d440a0b | |||
0f7d2ca7a8 | |||
81c9720acb | |||
ea2cfbbd2e | |||
2326b9c294 | |||
41de0e0d98 | |||
f6a2dbf4f5 | |||
b115374601 | |||
7d82053117 |
@ -132,8 +132,6 @@ jobs:
|
|||||||
<<: *job_defaults
|
<<: *job_defaults
|
||||||
resource_class: xlarge
|
resource_class: xlarge
|
||||||
steps:
|
steps:
|
||||||
# don't run this job on the patch branch (to preserve resources)
|
|
||||||
- run: circleci step halt
|
|
||||||
- *define_env_vars
|
- *define_env_vars
|
||||||
- checkout:
|
- checkout:
|
||||||
<<: *post_checkout
|
<<: *post_checkout
|
||||||
@ -147,8 +145,6 @@ jobs:
|
|||||||
<<: *job_defaults
|
<<: *job_defaults
|
||||||
resource_class: xlarge
|
resource_class: xlarge
|
||||||
steps:
|
steps:
|
||||||
# don't run this job on the patch branch (to preserve resources)
|
|
||||||
- run: circleci step halt
|
|
||||||
- *define_env_vars
|
- *define_env_vars
|
||||||
- checkout:
|
- checkout:
|
||||||
<<: *post_checkout
|
<<: *post_checkout
|
||||||
|
18
CHANGELOG.md
18
CHANGELOG.md
@ -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>
|
<a name="7.0.1"></a>
|
||||||
## [7.0.1](https://github.com/angular/angular/compare/7.0.0...7.0.1) (2018-10-24)
|
## [7.0.1](https://github.com/angular/angular/compare/7.0.0...7.0.1) (2018-10-24)
|
||||||
|
|
||||||
|
@ -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)
|
- `--config=debug`: build and launch in debug mode (see [debugging](#debugging) instructions below)
|
||||||
- `--test_arg=--node_options=--inspect=9228`: change the inspector port.
|
- `--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`
|
- `legacy`: (default behavior) compile against View Engine, e.g. `--define=compile=legacy`
|
||||||
- `jit`: Compile in ivy JIT mode, e.g. `--define=compile=jit`
|
- `jit`: Compile in ivy JIT mode, e.g. `--define=compile=jit`
|
||||||
- `local`: Compile in ivy AOT move, e.g. `--define=compile=local`
|
- `local`: Compile in ivy AOT move, e.g. `--define=compile=local`
|
||||||
|
@ -17,10 +17,10 @@ ivy-ngcc
|
|||||||
ls node_modules/@angular/common | grep __modified_by_ngcc_for_esm2015
|
ls node_modules/@angular/common | grep __modified_by_ngcc_for_esm2015
|
||||||
if [[ $? != 0 ]]; then exit 1; fi
|
if [[ $? != 0 ]]; then exit 1; fi
|
||||||
|
|
||||||
# Did it replace the NGCC_PRE markers correctly?
|
# Did it replace the PRE_R3 markers correctly?
|
||||||
grep "= R3_COMPILE_COMPONENT__POST_NGCC__" node_modules/@angular/core/fesm2015/core.js
|
grep "= SWITCH_COMPILE_COMPONENT__POST_R3__" node_modules/@angular/core/fesm2015/core.js
|
||||||
if [[ $? != 0 ]]; then exit 1; fi
|
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
|
if [[ $? != 0 ]]; then exit 1; fi
|
||||||
|
|
||||||
# Did it compile @angular/core/ApplicationModule correctly?
|
# Did it compile @angular/core/ApplicationModule correctly?
|
||||||
|
@ -56,15 +56,6 @@ describe('largetable benchmark perf', () => {
|
|||||||
}).then(done, done.fail);
|
}).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 => {
|
it('should run for iv', done => {
|
||||||
runTableBenchmark({
|
runTableBenchmark({
|
||||||
id: `largeTable.iv.${worker.id}`,
|
id: `largeTable.iv.${worker.id}`,
|
||||||
|
@ -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', () => {
|
it('should work for iv', () => {
|
||||||
testTableBenchmark({
|
testTableBenchmark({
|
||||||
url: 'all/benchmarks/src/largetable/iv/index.html',
|
url: 'all/benchmarks/src/largetable/iv/index.html',
|
||||||
|
@ -49,12 +49,6 @@ export const Benchmarks: Benchmark[] = [
|
|||||||
url: 'all/benchmarks/src/tree/ng2_switch/index.html',
|
url: 'all/benchmarks/src/tree/ng2_switch/index.html',
|
||||||
buttons: CreateDestroyButtons,
|
buttons: CreateDestroyButtons,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: `deepTree.ng2.render3`,
|
|
||||||
url: 'all/benchmarks/src/tree/render3/index.html',
|
|
||||||
buttons: CreateDestroyDetectChangesButtons,
|
|
||||||
ignoreBrowserSynchronization: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: `deepTree.ng2.render3_function`,
|
id: `deepTree.ng2.render3_function`,
|
||||||
url: 'all/benchmarks/src/tree/render3_function/index.html',
|
url: 'all/benchmarks/src/tree/render3_function/index.html',
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import {$} from 'protractor';
|
import {$} from 'protractor';
|
||||||
|
|
||||||
|
import {openBrowser} from '../../../e2e_util/e2e_util';
|
||||||
import {runBenchmark, verifyNoBrowserErrors} from '../../../e2e_util/perf_util';
|
import {runBenchmark, verifyNoBrowserErrors} from '../../../e2e_util/perf_util';
|
||||||
|
|
||||||
interface Worker {
|
interface Worker {
|
||||||
@ -39,9 +40,23 @@ describe('largetable benchmark perf', () => {
|
|||||||
|
|
||||||
afterEach(verifyNoBrowserErrors);
|
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) => {
|
[CreateOnlyWorker, CreateAndDestroyWorker, UpdateWorker].forEach((worker) => {
|
||||||
describe(worker.id, () => {
|
describe(worker.id, () => {
|
||||||
it('should run for render3', done => {
|
it('should run benchmark for render3', done => {
|
||||||
runTableBenchmark({
|
runTableBenchmark({
|
||||||
id: `largeTable.render3.${worker.id}`,
|
id: `largeTable.render3.${worker.id}`,
|
||||||
url: 'index.html',
|
url: 'index.html',
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package(default_visibility = ["//visibility:public"])
|
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("//packages/bazel:index.bzl", "protractor_web_test")
|
||||||
load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver")
|
load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver")
|
||||||
|
|
||||||
ts_library(
|
ng_module(
|
||||||
name = "largetable_lib",
|
name = "largetable_lib",
|
||||||
srcs = glob(
|
srcs = glob(
|
||||||
[
|
[
|
||||||
@ -12,18 +12,20 @@ ts_library(
|
|||||||
],
|
],
|
||||||
exclude = ["protractor.on-prepare.ts"],
|
exclude = ["protractor.on-prepare.ts"],
|
||||||
),
|
),
|
||||||
|
tags = ["ivy-only"],
|
||||||
deps = [
|
deps = [
|
||||||
"//modules/benchmarks/src:util_lib",
|
"//modules/benchmarks/src:util_lib",
|
||||||
"//modules/benchmarks/src/largetable:util_lib",
|
"//modules/benchmarks/src/largetable:util_lib",
|
||||||
"//packages:types",
|
"//packages:types",
|
||||||
|
"//packages/common",
|
||||||
"//packages/core",
|
"//packages/core",
|
||||||
"@rxjs",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
ng_rollup_bundle(
|
ng_rollup_bundle(
|
||||||
name = "bundle",
|
name = "bundle",
|
||||||
entry_point = "modules/benchmarks/src/largetable/render3/index.js",
|
entry_point = "modules/benchmarks/src/largetable/render3/index.js",
|
||||||
|
tags = ["ivy-only"],
|
||||||
deps = [
|
deps = [
|
||||||
":largetable_lib",
|
":largetable_lib",
|
||||||
],
|
],
|
||||||
@ -44,6 +46,7 @@ ts_devserver(
|
|||||||
"index.html",
|
"index.html",
|
||||||
":favicon",
|
":favicon",
|
||||||
],
|
],
|
||||||
|
tags = ["ivy-only"],
|
||||||
)
|
)
|
||||||
|
|
||||||
protractor_web_test(
|
protractor_web_test(
|
||||||
@ -57,9 +60,9 @@ protractor_web_test(
|
|||||||
"@ngdeps//reflect-metadata",
|
"@ngdeps//reflect-metadata",
|
||||||
"@ngdeps//yargs",
|
"@ngdeps//yargs",
|
||||||
],
|
],
|
||||||
on_prepare = ":protractor.on-prepare.js",
|
on_prepare = ":protractor.on_prepare.js",
|
||||||
server = ":devserver",
|
server = ":devserver",
|
||||||
tags = ["manual"],
|
tags = ["ivy-only"],
|
||||||
deps = [
|
deps = [
|
||||||
"//modules/benchmarks/src/largetable:perf_lib",
|
"//modules/benchmarks/src/largetable:perf_lib",
|
||||||
],
|
],
|
||||||
|
@ -28,14 +28,8 @@
|
|||||||
<script>
|
<script>
|
||||||
// TODO(mlaval): remove once we have a proper solution
|
// TODO(mlaval): remove once we have a proper solution
|
||||||
ngDevMode = false;
|
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 bazelBundle = document.location.search.endsWith('debug') ? 'bundle.min_debug.js' : 'bundle.min.js';
|
||||||
var mainUrl = window.location.search.split(/[?&]main=([^&]+)/)[1]
|
document.write('<script src="' + bazelBundle + '">\u003c/script>');
|
||||||
|| '../../bootstrap_ng2.js';
|
|
||||||
document.write('<script src="' + (isBazel ? bazelBundle : mainUrl) + '">\u003c/script>');
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
import 'reflect-metadata';
|
||||||
import {ɵrenderComponent as renderComponent} from '@angular/core';
|
import {ɵrenderComponent as renderComponent} from '@angular/core';
|
||||||
|
|
||||||
import {bindAction, profile} from '../../util';
|
import {bindAction, profile} from '../../util';
|
||||||
|
@ -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);
|
|
||||||
});
|
|
||||||
};
|
|
@ -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;
|
||||||
|
};
|
@ -6,76 +6,39 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* 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 {CommonModule} from '@angular/common';
|
||||||
import {ComponentDef} from '@angular/core/src/render3/interfaces/definition';
|
import {Component, Input, NgModule, ɵdetectChanges} from '@angular/core';
|
||||||
|
|
||||||
import {TableCell, buildTable, emptyTable} from '../util';
|
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 {
|
export class LargeTableComponent {
|
||||||
|
@Input()
|
||||||
data: TableCell[][] = emptyTable;
|
data: TableCell[][] = emptyTable;
|
||||||
|
|
||||||
/** @nocollapse */
|
trackByIndex(index: number, item: any) { return index; }
|
||||||
static ngComponentDef: ComponentDef<LargeTableComponent> = ɵdefineComponent({
|
|
||||||
type: LargeTableComponent,
|
getColor(row: number) { return row % 2 ? '' : 'grey'; }
|
||||||
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();
|
|
||||||
}
|
@NgModule({declarations: [LargeTableComponent], imports: [CommonModule]})
|
||||||
if (rf & ɵRenderFlags.Update) {
|
class TableModule {
|
||||||
ɵ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'}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function destroyDom(component: LargeTableComponent) {
|
export function destroyDom(component: LargeTableComponent) {
|
||||||
component.data = emptyTable;
|
component.data = emptyTable;
|
||||||
ɵdetectChanges(component);
|
ɵdetectChanges(component);
|
||||||
|
@ -13,3 +13,16 @@ ts_library(
|
|||||||
"//packages/core",
|
"//packages/core",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ts_library(
|
||||||
|
name = "perf_lib",
|
||||||
|
testonly = 1,
|
||||||
|
srcs = [
|
||||||
|
"tree_perf.spec.ts",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//modules/e2e_util:lib",
|
||||||
|
"//packages:types",
|
||||||
|
"@ngdeps//protractor",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@ -1,18 +1,67 @@
|
|||||||
package(default_visibility = ["//visibility:public"])
|
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(
|
ng_module(
|
||||||
name = "render3_lib",
|
name = "tree_lib",
|
||||||
srcs = glob(
|
srcs = glob(
|
||||||
[
|
[
|
||||||
"**/*.ts",
|
"**/*.ts",
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
tags = ["ivy-only"],
|
||||||
deps = [
|
deps = [
|
||||||
"//modules/benchmarks/src/tree:util_lib",
|
"//modules/benchmarks/src/tree:util_lib",
|
||||||
"//packages:types",
|
"//packages:types",
|
||||||
|
"//packages/common",
|
||||||
"//packages/core",
|
"//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",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -30,9 +30,8 @@
|
|||||||
<script>
|
<script>
|
||||||
// TODO(mlaval): remove once we have a proper solution
|
// TODO(mlaval): remove once we have a proper solution
|
||||||
ngDevMode = false;
|
ngDevMode = false;
|
||||||
var mainUrl = window.location.search.split(/[?&]main=([^&]+)/)[1]
|
var bazelBundle = document.location.search.endsWith('debug') ? 'bundle.min_debug.js' : 'bundle.min.js';
|
||||||
|| '../../bootstrap_ng2.js';
|
document.write('<script src="' + bazelBundle + '">\u003c/script>');
|
||||||
document.write('<script src="' + mainUrl + '">\u003c/script>');
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'reflect-metadata';
|
||||||
import {ɵrenderComponent as renderComponent} from '@angular/core';
|
import {ɵrenderComponent as renderComponent} from '@angular/core';
|
||||||
import {bindAction, profile} from '../../util';
|
import {bindAction, profile} from '../../util';
|
||||||
import {TreeComponent, createDom, destroyDom, detectChanges} from './tree';
|
import {TreeComponent, createDom, destroyDom, detectChanges} from './tree';
|
||||||
@ -27,3 +28,5 @@ export function main() {
|
|||||||
profile(() => createDom(component), () => destroyDom(component), 'create'));
|
profile(() => createDom(component), () => destroyDom(component), 'create'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
22
modules/benchmarks/src/tree/render3/protractor.on_prepare.js
Normal file
22
modules/benchmarks/src/tree/render3/protractor.on_prepare.js
Normal 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;
|
||||||
|
};
|
@ -6,7 +6,8 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* 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';
|
import {TreeNode, buildTree, emptyTree} from '../util';
|
||||||
|
|
||||||
@ -30,122 +31,17 @@ export function detectChanges(component: TreeComponent) {
|
|||||||
numberOfChecksEl.textContent = `${detectChangesRuns}`;
|
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 {
|
export class TreeComponent {
|
||||||
data: TreeNode = emptyTree;
|
data: any = emptyTree;
|
||||||
|
get bgColor() { return this.data.depth % 2 ? '' : 'grey'; }
|
||||||
/** @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]
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TreeFunction {
|
@NgModule({declarations: [TreeComponent], imports: [CommonModule]})
|
||||||
data: TreeNode = emptyTree;
|
export class TreeModule {
|
||||||
|
|
||||||
/** @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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ ng_module(
|
|||||||
),
|
),
|
||||||
deps = [
|
deps = [
|
||||||
"//modules/benchmarks/src/tree:util_lib",
|
"//modules/benchmarks/src/tree:util_lib",
|
||||||
"//modules/benchmarks/src/tree/render3:render3_lib",
|
"//modules/benchmarks/src/tree/render3:tree_lib",
|
||||||
"//packages:types",
|
"//packages:types",
|
||||||
"//packages/core",
|
"//packages/core",
|
||||||
"@rxjs",
|
"@rxjs",
|
||||||
|
@ -6,9 +6,11 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* 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 {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() {}
|
function noop() {}
|
||||||
|
|
||||||
@ -16,14 +18,71 @@ export function main() {
|
|||||||
let component: TreeFunction;
|
let component: TreeFunction;
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
component = renderComponent(TreeFunction);
|
component = renderComponent(TreeFunction);
|
||||||
bindAction('#createDom', () => createDom(component));
|
bindAction('#createDom', () => createDom(component as any));
|
||||||
bindAction('#destroyDom', () => destroyDom(component));
|
bindAction('#destroyDom', () => destroyDom(component as any));
|
||||||
bindAction('#detectChanges', () => detectChanges(component));
|
bindAction('#detectChanges', () => detectChanges(component as any));
|
||||||
bindAction(
|
bindAction(
|
||||||
'#detectChangesProfile', profile(() => detectChanges(component), noop, 'detectChanges'));
|
'#detectChangesProfile',
|
||||||
bindAction('#updateDomProfile', profile(() => createDom(component), noop, 'update'));
|
profile(() => detectChanges(component as any), noop, 'detectChanges'));
|
||||||
|
bindAction('#updateDomProfile', profile(() => createDom(component as any), noop, 'update'));
|
||||||
bindAction(
|
bindAction(
|
||||||
'#createDomProfile',
|
'#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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
101
modules/benchmarks/src/tree/tree_perf.spec.ts
Normal file
101
modules/benchmarks/src/tree/tree_perf.spec.ts
Normal 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}],
|
||||||
|
});
|
||||||
|
}
|
@ -40,6 +40,7 @@ export function runBenchmark(config: {
|
|||||||
if (config.setup) {
|
if (config.setup) {
|
||||||
config.setup();
|
config.setup();
|
||||||
}
|
}
|
||||||
|
if (!cmdArgs) readCommandLine();
|
||||||
const description: {[key: string]: any} = {'bundles': cmdArgs.bundles};
|
const description: {[key: string]: any} = {'bundles': cmdArgs.bundles};
|
||||||
config.params.forEach((param) => { description[param.name] = param.value; });
|
config.params.forEach((param) => { description[param.name] = param.value; });
|
||||||
return runner.sample({
|
return runner.sample({
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "angular-srcs",
|
"name": "angular-srcs",
|
||||||
"version": "7.0.1",
|
"version": "7.1.0-beta.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"branchPattern": "2.0.*",
|
"branchPattern": "2.0.*",
|
||||||
"description": "Angular - a web framework for modern web apps",
|
"description": "Angular - a web framework for modern web apps",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as ng from '@angular/compiler-cli';
|
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 fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as tsickle from 'tsickle';
|
import * as tsickle from 'tsickle';
|
||||||
@ -291,10 +291,7 @@ export function compile({allowNonHermeticReads, allDepsCompiledWithBazel = true,
|
|||||||
program, bazelHost, bazelHost, compilerOpts, targetSourceFile, writeFile,
|
program, bazelHost, bazelHost, compilerOpts, targetSourceFile, writeFile,
|
||||||
cancellationToken, emitOnlyDtsFiles, {
|
cancellationToken, emitOnlyDtsFiles, {
|
||||||
beforeTs: customTransformers.before,
|
beforeTs: customTransformers.before,
|
||||||
afterTs: [
|
afterTs: customTransformers.after,
|
||||||
...(customTransformers.after || []),
|
|
||||||
fixUmdModuleDeclarations((sf: ts.SourceFile) => bazelHost.amdModuleName(sf)),
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!gatherDiagnostics) {
|
if (!gatherDiagnostics) {
|
||||||
|
@ -26,8 +26,9 @@ ts_library(
|
|||||||
"//packages/compiler",
|
"//packages/compiler",
|
||||||
"//packages/compiler-cli/src/ngtsc/annotations",
|
"//packages/compiler-cli/src/ngtsc/annotations",
|
||||||
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
||||||
"//packages/compiler-cli/src/ngtsc/factories",
|
|
||||||
"//packages/compiler-cli/src/ngtsc/metadata",
|
"//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/transform",
|
||||||
"//packages/compiler-cli/src/ngtsc/typecheck",
|
"//packages/compiler-cli/src/ngtsc/typecheck",
|
||||||
"@ngdeps//@bazel/typescript",
|
"@ngdeps//@bazel/typescript",
|
||||||
|
@ -9,8 +9,8 @@ import * as ts from 'typescript';
|
|||||||
import {ReflectionHost} from '../../../ngtsc/host';
|
import {ReflectionHost} from '../../../ngtsc/host';
|
||||||
import {DecoratedFile} from './decorated_file';
|
import {DecoratedFile} from './decorated_file';
|
||||||
|
|
||||||
export const PRE_NGCC_MARKER = '__PRE_NGCC__';
|
export const PRE_NGCC_MARKER = '__PRE_R3__';
|
||||||
export const POST_NGCC_MARKER = '__POST_NGCC__';
|
export const POST_NGCC_MARKER = '__POST_R3__';
|
||||||
|
|
||||||
export type SwitchableVariableDeclaration = ts.VariableDeclaration & {initializer: ts.Identifier};
|
export type SwitchableVariableDeclaration = ts.VariableDeclaration & {initializer: ts.Identifier};
|
||||||
export function isSwitchableVariableDeclaration(node: ts.Node):
|
export function isSwitchableVariableDeclaration(node: ts.Node):
|
||||||
|
@ -30,15 +30,15 @@ const TEST_PROGRAM = [
|
|||||||
name: 'b.js',
|
name: 'b.js',
|
||||||
contents: `
|
contents: `
|
||||||
export const b = 42;
|
export const b = 42;
|
||||||
var factoryB = factory__PRE_NGCC__;
|
var factoryB = factory__PRE_R3__;
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'c.js',
|
name: 'c.js',
|
||||||
contents: `
|
contents: `
|
||||||
export const c = 'So long, and thanks for all the fish!';
|
export const c = 'So long, and thanks for all the fish!';
|
||||||
var factoryC = factory__PRE_NGCC__;
|
var factoryC = factory__PRE_R3__;
|
||||||
var factoryD = factory__PRE_NGCC__;
|
var factoryD = factory__PRE_R3__;
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -62,14 +62,14 @@ describe('SwitchMarkerAnalyzer', () => {
|
|||||||
expect(analysis.has(b)).toBe(true);
|
expect(analysis.has(b)).toBe(true);
|
||||||
expect(analysis.get(b) !.sourceFile).toBe(b);
|
expect(analysis.get(b) !.sourceFile).toBe(b);
|
||||||
expect(analysis.get(b) !.declarations.map(decl => decl.getText())).toEqual([
|
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.has(c)).toBe(true);
|
||||||
expect(analysis.get(c) !.sourceFile).toBe(c);
|
expect(analysis.get(c) !.sourceFile).toBe(c);
|
||||||
expect(analysis.get(c) !.declarations.map(decl => decl.getText())).toEqual([
|
expect(analysis.get(c) !.declarations.map(decl => decl.getText())).toEqual([
|
||||||
'factoryC = factory__PRE_NGCC__',
|
'factoryC = factory__PRE_R3__',
|
||||||
'factoryD = factory__PRE_NGCC__',
|
'factoryD = factory__PRE_R3__',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -35,15 +35,15 @@ const CLASSES = [
|
|||||||
const MARKER_FILE = {
|
const MARKER_FILE = {
|
||||||
name: '/marker.js',
|
name: '/marker.js',
|
||||||
contents: `
|
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 compilerFactory = injector.get(CompilerFactory);
|
||||||
const compiler = compilerFactory.createCompiler([options]);
|
const compiler = compilerFactory.createCompiler([options]);
|
||||||
return compiler.compileModuleAsync(moduleType);
|
return compiler.compileModuleAsync(moduleType);
|
||||||
}
|
}
|
||||||
|
|
||||||
function compileNgModuleFactory__POST_NGCC__(injector, options, moduleType) {
|
function compileNgModuleFactory__POST_R3__(injector, options, moduleType) {
|
||||||
ngDevMode && assertNgModuleType(moduleType);
|
ngDevMode && assertNgModuleType(moduleType);
|
||||||
return Promise.resolve(new R3NgModuleFactory(moduleType));
|
return Promise.resolve(new R3NgModuleFactory(moduleType));
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ describe('Esm2015ReflectionHost', () => {
|
|||||||
const file = program.getSourceFile(MARKER_FILE.name) !;
|
const file = program.getSourceFile(MARKER_FILE.name) !;
|
||||||
const declarations = host.getSwitchableDeclarations(file);
|
const declarations = host.getSwitchableDeclarations(file);
|
||||||
expect(declarations.map(d => [d.name.getText(), d.initializer !.getText()])).toEqual([
|
expect(declarations.map(d => [d.name.getText(), d.initializer !.getText()])).toEqual([
|
||||||
['compileNgModuleFactory', 'compileNgModuleFactory__PRE_NGCC__']
|
['compileNgModuleFactory', 'compileNgModuleFactory__PRE_R3__']
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -377,15 +377,15 @@ const FUNCTION_BODY_FILE = {
|
|||||||
const MARKER_FILE = {
|
const MARKER_FILE = {
|
||||||
name: '/marker.js',
|
name: '/marker.js',
|
||||||
contents: `
|
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 compilerFactory = injector.get(CompilerFactory);
|
||||||
var compiler = compilerFactory.createCompiler([options]);
|
var compiler = compilerFactory.createCompiler([options]);
|
||||||
return compiler.compileModuleAsync(moduleType);
|
return compiler.compileModuleAsync(moduleType);
|
||||||
}
|
}
|
||||||
|
|
||||||
function compileNgModuleFactory__POST_NGCC__(injector, options, moduleType) {
|
function compileNgModuleFactory__POST_R3__(injector, options, moduleType) {
|
||||||
ngDevMode && assertNgModuleType(moduleType);
|
ngDevMode && assertNgModuleType(moduleType);
|
||||||
return Promise.resolve(new R3NgModuleFactory(moduleType));
|
return Promise.resolve(new R3NgModuleFactory(moduleType));
|
||||||
}
|
}
|
||||||
@ -1179,7 +1179,7 @@ describe('Fesm2015ReflectionHost', () => {
|
|||||||
const file = program.getSourceFile(MARKER_FILE.name) !;
|
const file = program.getSourceFile(MARKER_FILE.name) !;
|
||||||
const declarations = host.getSwitchableDeclarations(file);
|
const declarations = host.getSwitchableDeclarations(file);
|
||||||
expect(declarations.map(d => [d.name.getText(), d.initializer !.getText()])).toEqual([
|
expect(declarations.map(d => [d.name.getText(), d.initializer !.getText()])).toEqual([
|
||||||
['compileNgModuleFactory', 'compileNgModuleFactory__PRE_NGCC__']
|
['compileNgModuleFactory', 'compileNgModuleFactory__PRE_R3__']
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -48,16 +48,16 @@ export class C {}
|
|||||||
C.decorators = [
|
C.decorators = [
|
||||||
{ type: Directive, args: [{ selector: '[c]' }] },
|
{ type: Directive, args: [{ selector: '[c]' }] },
|
||||||
];
|
];
|
||||||
let compileNgModuleFactory = compileNgModuleFactory__PRE_NGCC__;
|
let compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;
|
||||||
let badlyFormattedVariable = __PRE_NGCC__badlyFormattedVariable;
|
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 compilerFactory = injector.get(CompilerFactory);
|
||||||
const compiler = compilerFactory.createCompiler([options]);
|
const compiler = compilerFactory.createCompiler([options]);
|
||||||
return compiler.compileModuleAsync(moduleType);
|
return compiler.compileModuleAsync(moduleType);
|
||||||
}
|
}
|
||||||
|
|
||||||
function compileNgModuleFactory__POST_NGCC__(injector, options, moduleType) {
|
function compileNgModuleFactory__POST_R3__(injector, options, moduleType) {
|
||||||
ngDevMode && assertNgModuleType(moduleType);
|
ngDevMode && assertNgModuleType(moduleType);
|
||||||
return Promise.resolve(new R3NgModuleFactory(moduleType));
|
return Promise.resolve(new R3NgModuleFactory(moduleType));
|
||||||
}
|
}
|
||||||
@ -146,17 +146,15 @@ export class A {}`);
|
|||||||
renderer.rewriteSwitchableDeclarations(
|
renderer.rewriteSwitchableDeclarations(
|
||||||
output, file, switchMarkerAnalyses.get(sourceFile) !.declarations);
|
output, file, switchMarkerAnalyses.get(sourceFile) !.declarations);
|
||||||
expect(output.toString())
|
expect(output.toString())
|
||||||
.not.toContain(`let compileNgModuleFactory = compileNgModuleFactory__PRE_NGCC__;`);
|
.not.toContain(`let compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;`);
|
||||||
expect(output.toString())
|
expect(output.toString())
|
||||||
.toContain(`let badlyFormattedVariable = __PRE_NGCC__badlyFormattedVariable;`);
|
.toContain(`let badlyFormattedVariable = __PRE_R3__badlyFormattedVariable;`);
|
||||||
expect(output.toString())
|
expect(output.toString())
|
||||||
.toContain(`let compileNgModuleFactory = compileNgModuleFactory__POST_NGCC__;`);
|
.toContain(`let compileNgModuleFactory = compileNgModuleFactory__POST_R3__;`);
|
||||||
expect(output.toString())
|
expect(output.toString())
|
||||||
.toContain(
|
.toContain(`function compileNgModuleFactory__PRE_R3__(injector, options, moduleType) {`);
|
||||||
`function compileNgModuleFactory__PRE_NGCC__(injector, options, moduleType) {`);
|
|
||||||
expect(output.toString())
|
expect(output.toString())
|
||||||
.toContain(
|
.toContain(`function compileNgModuleFactory__POST_R3__(injector, options, moduleType) {`);
|
||||||
`function compileNgModuleFactory__POST_NGCC__(injector, options, moduleType) {`);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -55,15 +55,15 @@ var C = (function() {
|
|||||||
return C;
|
return C;
|
||||||
}());
|
}());
|
||||||
|
|
||||||
var compileNgModuleFactory = compileNgModuleFactory__PRE_NGCC__;
|
var compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;
|
||||||
var badlyFormattedVariable = __PRE_NGCC__badlyFormattedVariable;
|
var badlyFormattedVariable = __PRE_R3__badlyFormattedVariable;
|
||||||
function compileNgModuleFactory__PRE_NGCC__(injector, options, moduleType) {
|
function compileNgModuleFactory__PRE_R3__(injector, options, moduleType) {
|
||||||
const compilerFactory = injector.get(CompilerFactory);
|
const compilerFactory = injector.get(CompilerFactory);
|
||||||
const compiler = compilerFactory.createCompiler([options]);
|
const compiler = compilerFactory.createCompiler([options]);
|
||||||
return compiler.compileModuleAsync(moduleType);
|
return compiler.compileModuleAsync(moduleType);
|
||||||
}
|
}
|
||||||
|
|
||||||
function compileNgModuleFactory__POST_NGCC__(injector, options, moduleType) {
|
function compileNgModuleFactory__POST_R3__(injector, options, moduleType) {
|
||||||
ngDevMode && assertNgModuleType(moduleType);
|
ngDevMode && assertNgModuleType(moduleType);
|
||||||
return Promise.resolve(new R3NgModuleFactory(moduleType));
|
return Promise.resolve(new R3NgModuleFactory(moduleType));
|
||||||
}
|
}
|
||||||
@ -166,17 +166,15 @@ var A = (function() {`);
|
|||||||
renderer.rewriteSwitchableDeclarations(
|
renderer.rewriteSwitchableDeclarations(
|
||||||
output, file, switchMarkerAnalyses.get(sourceFile) !.declarations);
|
output, file, switchMarkerAnalyses.get(sourceFile) !.declarations);
|
||||||
expect(output.toString())
|
expect(output.toString())
|
||||||
.not.toContain(`var compileNgModuleFactory = compileNgModuleFactory__PRE_NGCC__;`);
|
.not.toContain(`var compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;`);
|
||||||
expect(output.toString())
|
expect(output.toString())
|
||||||
.toContain(`var badlyFormattedVariable = __PRE_NGCC__badlyFormattedVariable;`);
|
.toContain(`var badlyFormattedVariable = __PRE_R3__badlyFormattedVariable;`);
|
||||||
expect(output.toString())
|
expect(output.toString())
|
||||||
.toContain(`var compileNgModuleFactory = compileNgModuleFactory__POST_NGCC__;`);
|
.toContain(`var compileNgModuleFactory = compileNgModuleFactory__POST_R3__;`);
|
||||||
expect(output.toString())
|
expect(output.toString())
|
||||||
.toContain(
|
.toContain(`function compileNgModuleFactory__PRE_R3__(injector, options, moduleType) {`);
|
||||||
`function compileNgModuleFactory__PRE_NGCC__(injector, options, moduleType) {`);
|
|
||||||
expect(output.toString())
|
expect(output.toString())
|
||||||
.toContain(
|
.toContain(`function compileNgModuleFactory__POST_R3__(injector, options, moduleType) {`);
|
||||||
`function compileNgModuleFactory__POST_NGCC__(injector, options, moduleType) {`);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
@ -15,9 +15,10 @@ import {nocollapseHack} from '../transformers/nocollapse_hack';
|
|||||||
|
|
||||||
import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from './annotations';
|
import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from './annotations';
|
||||||
import {BaseDefDecoratorHandler} from './annotations/src/base_def';
|
import {BaseDefDecoratorHandler} from './annotations/src/base_def';
|
||||||
import {FactoryGenerator, FactoryInfo, GeneratedFactoryHostWrapper, generatedFactoryTransform} from './factories';
|
|
||||||
import {TypeScriptReflectionHost} from './metadata';
|
import {TypeScriptReflectionHost} from './metadata';
|
||||||
import {FileResourceLoader, HostResourceLoader} from './resource_loader';
|
import {FileResourceLoader, HostResourceLoader} from './resource_loader';
|
||||||
|
import {FactoryGenerator, FactoryInfo, GeneratedShimsHostWrapper, SummaryGenerator, generatedFactoryTransform} from './shims';
|
||||||
|
import {ivySwitchTransform} from './switch';
|
||||||
import {IvyCompilation, ivyTransformFactory} from './transform';
|
import {IvyCompilation, ivyTransformFactory} from './transform';
|
||||||
import {TypeCheckContext, TypeCheckProgramHost} from './typecheck';
|
import {TypeCheckContext, TypeCheckProgramHost} from './typecheck';
|
||||||
|
|
||||||
@ -50,13 +51,16 @@ export class NgtscProgram implements api.Program {
|
|||||||
this.resourceLoader = host.readResource !== undefined ?
|
this.resourceLoader = host.readResource !== undefined ?
|
||||||
new HostResourceLoader(host.readResource.bind(host)) :
|
new HostResourceLoader(host.readResource.bind(host)) :
|
||||||
new FileResourceLoader();
|
new FileResourceLoader();
|
||||||
const shouldGenerateFactories = options.allowEmptyCodegenFiles || false;
|
const shouldGenerateShims = options.allowEmptyCodegenFiles || false;
|
||||||
this.host = host;
|
this.host = host;
|
||||||
let rootFiles = [...rootNames];
|
let rootFiles = [...rootNames];
|
||||||
if (shouldGenerateFactories) {
|
if (shouldGenerateShims) {
|
||||||
const generator = new FactoryGenerator();
|
// Summary generation.
|
||||||
const factoryFileMap = generator.computeFactoryFileMap(rootNames);
|
const summaryGenerator = SummaryGenerator.forRootFiles(rootNames);
|
||||||
rootFiles.push(...Array.from(factoryFileMap.keys()));
|
|
||||||
|
// Factory generation.
|
||||||
|
const factoryGenerator = FactoryGenerator.forRootFiles(rootNames);
|
||||||
|
const factoryFileMap = factoryGenerator.factoryFileMap;
|
||||||
this.factoryToSourceInfo = new Map<string, FactoryInfo>();
|
this.factoryToSourceInfo = new Map<string, FactoryInfo>();
|
||||||
this.sourceToFactorySymbols = new Map<string, Set<string>>();
|
this.sourceToFactorySymbols = new Map<string, Set<string>>();
|
||||||
factoryFileMap.forEach((sourceFilePath, factoryPath) => {
|
factoryFileMap.forEach((sourceFilePath, factoryPath) => {
|
||||||
@ -64,7 +68,10 @@ export class NgtscProgram implements api.Program {
|
|||||||
this.sourceToFactorySymbols !.set(sourceFilePath, moduleSymbolNames);
|
this.sourceToFactorySymbols !.set(sourceFilePath, moduleSymbolNames);
|
||||||
this.factoryToSourceInfo !.set(factoryPath, {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 =
|
this.tsProgram =
|
||||||
@ -177,6 +184,9 @@ export class NgtscProgram implements api.Program {
|
|||||||
if (this.factoryToSourceInfo !== null) {
|
if (this.factoryToSourceInfo !== null) {
|
||||||
transforms.push(generatedFactoryTransform(this.factoryToSourceInfo, this.coreImportsFrom));
|
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.
|
// Run the emit, including a custom transformer that will downlevel the Ivy decorators in code.
|
||||||
const emitResult = emitCallback({
|
const emitResult = emitCallback({
|
||||||
program: this.tsProgram,
|
program: this.tsProgram,
|
||||||
|
@ -3,12 +3,12 @@ package(default_visibility = ["//visibility:public"])
|
|||||||
load("//tools:defaults.bzl", "ts_library")
|
load("//tools:defaults.bzl", "ts_library")
|
||||||
|
|
||||||
ts_library(
|
ts_library(
|
||||||
name = "factories",
|
name = "shims",
|
||||||
srcs = glob([
|
srcs = glob([
|
||||||
"index.ts",
|
"index.ts",
|
||||||
"src/**/*.ts",
|
"src/**/*.ts",
|
||||||
]),
|
]),
|
||||||
module_name = "@angular/compiler-cli/src/ngtsc/factories",
|
module_name = "@angular/compiler-cli/src/ngtsc/shims",
|
||||||
deps = [
|
deps = [
|
||||||
"//packages/compiler",
|
"//packages/compiler",
|
||||||
"//packages/compiler-cli/src/ngtsc/host",
|
"//packages/compiler-cli/src/ngtsc/host",
|
@ -8,6 +8,6 @@
|
|||||||
|
|
||||||
/// <reference types="node" />
|
/// <reference types="node" />
|
||||||
|
|
||||||
export {FactoryGenerator} from './src/generator';
|
export {FactoryGenerator, FactoryInfo, generatedFactoryTransform} from './src/factory_generator';
|
||||||
export {GeneratedFactoryHostWrapper} from './src/host';
|
export {GeneratedShimsHostWrapper} from './src/host';
|
||||||
export {FactoryInfo, generatedFactoryTransform} from './src/transform';
|
export {SummaryGenerator} from './src/summary_generator';
|
144
packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts
Normal file
144
packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts
Normal 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;
|
||||||
|
}
|
@ -9,15 +9,26 @@
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
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.
|
* A wrapper around a `ts.CompilerHost` which supports generated files.
|
||||||
*/
|
*/
|
||||||
export class GeneratedFactoryHostWrapper implements ts.CompilerHost {
|
export class GeneratedShimsHostWrapper implements ts.CompilerHost {
|
||||||
constructor(
|
constructor(private delegate: ts.CompilerHost, private shimGenerators: ShimGenerator[]) {
|
||||||
private delegate: ts.CompilerHost, private generator: FactoryGenerator,
|
|
||||||
private factoryToSourceMap: Map<string, string>) {
|
|
||||||
if (delegate.resolveTypeReferenceDirectives) {
|
if (delegate.resolveTypeReferenceDirectives) {
|
||||||
// Backward compatibility with TypeScript 2.9 and older since return
|
// Backward compatibility with TypeScript 2.9 and older since return
|
||||||
// type has changed from (ts.ResolvedTypeReferenceDirective | undefined)[]
|
// type has changed from (ts.ResolvedTypeReferenceDirective | undefined)[]
|
||||||
@ -38,14 +49,20 @@ export class GeneratedFactoryHostWrapper implements ts.CompilerHost {
|
|||||||
onError?: ((message: string) => void)|undefined,
|
onError?: ((message: string) => void)|undefined,
|
||||||
shouldCreateNewSourceFile?: boolean|undefined): ts.SourceFile|undefined {
|
shouldCreateNewSourceFile?: boolean|undefined): ts.SourceFile|undefined {
|
||||||
const canonical = this.getCanonicalFileName(fileName);
|
const canonical = this.getCanonicalFileName(fileName);
|
||||||
if (this.factoryToSourceMap.has(canonical)) {
|
for (let i = 0; i < this.shimGenerators.length; i++) {
|
||||||
const sourceFileName = this.getCanonicalFileName(this.factoryToSourceMap.get(canonical) !);
|
const generator = this.shimGenerators[i];
|
||||||
const sourceFile = this.delegate.getSourceFile(
|
const originalFile = generator.getOriginalSourceOfShim(canonical);
|
||||||
sourceFileName, languageVersion, onError, shouldCreateNewSourceFile);
|
if (originalFile !== null) {
|
||||||
if (sourceFile === undefined) {
|
// 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 undefined;
|
||||||
}
|
}
|
||||||
return this.generator.factoryFor(sourceFile, fileName);
|
return generator.generate(originalSource, fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this.delegate.getSourceFile(
|
return this.delegate.getSourceFile(
|
||||||
fileName, languageVersion, onError, shouldCreateNewSourceFile);
|
fileName, languageVersion, onError, shouldCreateNewSourceFile);
|
||||||
@ -75,7 +92,11 @@ export class GeneratedFactoryHostWrapper implements ts.CompilerHost {
|
|||||||
getNewLine(): string { return this.delegate.getNewLine(); }
|
getNewLine(): string { return this.delegate.getNewLine(); }
|
||||||
|
|
||||||
fileExists(fileName: string): boolean {
|
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); }
|
readFile(fileName: string): string|undefined { return this.delegate.readFile(fileName); }
|
@ -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);
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @license
|
* @license
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
@ -7,4 +6,9 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* 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;
|
||||||
|
}
|
19
packages/compiler-cli/src/ngtsc/switch/BUILD.bazel
Normal file
19
packages/compiler-cli/src/ngtsc/switch/BUILD.bazel
Normal 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",
|
||||||
|
],
|
||||||
|
)
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @license
|
* @license
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
@ -7,4 +6,4 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export * from './ivy_switch_on';
|
export {ivySwitchTransform} from './src/switch';
|
152
packages/compiler-cli/src/ngtsc/switch/src/switch.ts
Normal file
152
packages/compiler-cli/src/ngtsc/switch/src/switch.ts
Normal 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));
|
||||||
|
}
|
@ -10,11 +10,15 @@ import {GeneratedFile} from '@angular/compiler';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
|
import {ivySwitchTransform} from '../ngtsc/switch';
|
||||||
import * as api from '../transformers/api';
|
import * as api from '../transformers/api';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of the `Program` API which behaves like plain `tsc` and does not include any
|
* An implementation of the `Program` API which behaves similarly to plain `tsc`.
|
||||||
* Angular-specific behavior whatsoever.
|
*
|
||||||
|
* 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.
|
* 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,
|
host: this.host,
|
||||||
options: this.options,
|
options: this.options,
|
||||||
emitOnlyDtsFiles: false,
|
emitOnlyDtsFiles: false,
|
||||||
|
customTransformers: {before: [ivySwitchTransform]},
|
||||||
});
|
});
|
||||||
return emitResult;
|
return emitResult;
|
||||||
}
|
}
|
||||||
|
@ -572,6 +572,38 @@ describe('ngtsc behavioral tests', () => {
|
|||||||
expect(emptyFactory).toContain(`export var ɵNonEmptyModule = true;`);
|
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', () => {
|
it('should compile a banana-in-a-box inside of a template', () => {
|
||||||
env.tsconfig();
|
env.tsconfig();
|
||||||
env.write('test.ts', `
|
env.write('test.ts', `
|
||||||
|
@ -9,14 +9,7 @@ ng_module(
|
|||||||
"*.ts",
|
"*.ts",
|
||||||
"src/**/*.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",
|
module_name = "@angular/core",
|
||||||
deps = [
|
deps = [
|
||||||
"//packages:types",
|
"//packages:types",
|
||||||
@ -42,30 +35,3 @@ ng_package(
|
|||||||
"//packages/core/testing",
|
"//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)';\" > $@",
|
|
||||||
)
|
|
||||||
|
@ -33,9 +33,9 @@ let _platform: PlatformRef;
|
|||||||
|
|
||||||
let compileNgModuleFactory:
|
let compileNgModuleFactory:
|
||||||
<M>(injector: Injector, options: CompilerOptions, moduleType: Type<M>) =>
|
<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,
|
injector: Injector, options: CompilerOptions,
|
||||||
moduleType: Type<M>): Promise<NgModuleFactory<M>> {
|
moduleType: Type<M>): Promise<NgModuleFactory<M>> {
|
||||||
const compilerFactory: CompilerFactory = injector.get(CompilerFactory);
|
const compilerFactory: CompilerFactory = injector.get(CompilerFactory);
|
||||||
@ -43,7 +43,7 @@ function compileNgModuleFactory__PRE_NGCC__<M>(
|
|||||||
return compiler.compileModuleAsync(moduleType);
|
return compiler.compileModuleAsync(moduleType);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function compileNgModuleFactory__POST_NGCC__<M>(
|
export function compileNgModuleFactory__POST_R3__<M>(
|
||||||
injector: Injector, options: CompilerOptions,
|
injector: Injector, options: CompilerOptions,
|
||||||
moduleType: Type<M>): Promise<NgModuleFactory<M>> {
|
moduleType: Type<M>): Promise<NgModuleFactory<M>> {
|
||||||
ngDevMode && assertNgModuleType(moduleType);
|
ngDevMode && assertNgModuleType(moduleType);
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* 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.
|
* Base class for Angular Views, provides change detection functionality.
|
||||||
@ -108,5 +108,12 @@ export abstract class ChangeDetectorRef {
|
|||||||
abstract reattach(): void;
|
abstract reattach(): void;
|
||||||
|
|
||||||
/** @internal */
|
/** @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__;
|
||||||
|
@ -16,7 +16,7 @@ export {Console as ɵConsole} from './console';
|
|||||||
export {InjectableDef as ɵInjectableDef, InjectorDef as ɵInjectorDef, getInjectableDef as ɵgetInjectableDef} from './di/defs';
|
export {InjectableDef as ɵInjectableDef, InjectorDef as ɵInjectorDef, getInjectableDef as ɵgetInjectableDef} from './di/defs';
|
||||||
export {inject as ɵinject, setCurrentInjector as ɵsetCurrentInjector} from './di/injector';
|
export {inject as ɵinject, setCurrentInjector as ɵsetCurrentInjector} from './di/injector';
|
||||||
export {APP_ROOT as ɵAPP_ROOT} from './di/scope';
|
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 {ComponentFactory as ɵComponentFactory} from './linker/component_factory';
|
||||||
export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} from './linker/component_factory_resolver';
|
export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} from './linker/component_factory_resolver';
|
||||||
export {resolveComponentResources as ɵresolveComponentResources} from './metadata/resource_loading';
|
export {resolveComponentResources as ɵresolveComponentResources} from './metadata/resource_loading';
|
||||||
|
@ -129,12 +129,17 @@ export { Render3DebugRendererFactory2 as ɵRender3DebugRendererFactory2 } from
|
|||||||
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
R3_COMPILE_NGMODULE_DEFS as ɵcompileNgModuleDefs,
|
compileComponent as ɵcompileComponent,
|
||||||
R3_PATCH_COMPONENT_DEF_WTIH_SCOPE as ɵpatchComponentDefWithScope,
|
compileDirective as ɵcompileDirective,
|
||||||
R3_COMPILE_COMPONENT as ɵcompileComponent,
|
} from './render3/jit/directive';
|
||||||
R3_COMPILE_DIRECTIVE as ɵcompileDirective,
|
export {
|
||||||
R3_COMPILE_PIPE as ɵcompilePipe,
|
compileNgModule as ɵcompileNgModule,
|
||||||
} from './ivy_switch/compiler/ivy_switch_on';
|
compileNgModuleDefs as ɵcompileNgModuleDefs,
|
||||||
|
patchComponentDefWithScope as ɵpatchComponentDefWithScope,
|
||||||
|
} from './render3/jit/module';
|
||||||
|
export {
|
||||||
|
compilePipe as ɵcompilePipe,
|
||||||
|
} from './render3/jit/pipe';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
NgModuleDef as ɵNgModuleDef,
|
NgModuleDef as ɵNgModuleDef,
|
||||||
@ -186,24 +191,37 @@ export {
|
|||||||
//
|
//
|
||||||
// no code actually imports these symbols from the @angular/core entry point
|
// no code actually imports these symbols from the @angular/core entry point
|
||||||
export {
|
export {
|
||||||
compileNgModuleFactory__POST_NGCC__ as ɵcompileNgModuleFactory__POST_NGCC__
|
compileNgModuleFactory__POST_R3__ as ɵcompileNgModuleFactory__POST_R3__
|
||||||
} from './application_ref';
|
} from './application_ref';
|
||||||
export {
|
export {
|
||||||
R3_COMPILE_COMPONENT__POST_NGCC__ as ɵR3_COMPILE_COMPONENT__POST_NGCC__,
|
SWITCH_COMPILE_COMPONENT__POST_R3__ as ɵSWITCH_COMPILE_COMPONENT__POST_R3__,
|
||||||
R3_COMPILE_DIRECTIVE__POST_NGCC__ as ɵR3_COMPILE_DIRECTIVE__POST_NGCC__,
|
SWITCH_COMPILE_DIRECTIVE__POST_R3__ as ɵSWITCH_COMPILE_DIRECTIVE__POST_R3__,
|
||||||
R3_COMPILE_INJECTABLE__POST_NGCC__ as ɵR3_COMPILE_INJECTABLE__POST_NGCC__,
|
SWITCH_COMPILE_PIPE__POST_R3__ as ɵSWITCH_COMPILE_PIPE__POST_R3__,
|
||||||
R3_COMPILE_NGMODULE__POST_NGCC__ as ɵR3_COMPILE_NGMODULE__POST_NGCC__,
|
} from './metadata/directives';
|
||||||
R3_COMPILE_PIPE__POST_NGCC__ as ɵR3_COMPILE_PIPE__POST_NGCC__,
|
|
||||||
ivyEnable__POST_NGCC__ as ɵivyEnable__POST_NGCC__,
|
|
||||||
} from './ivy_switch/compiler/legacy';
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
R3_ELEMENT_REF_FACTORY__POST_NGCC__ as ɵR3_ELEMENT_REF_FACTORY__POST_NGCC__,
|
SWITCH_COMPILE_NGMODULE__POST_R3__ as ɵSWITCH_COMPILE_NGMODULE__POST_R3__,
|
||||||
R3_TEMPLATE_REF_FACTORY__POST_NGCC__ as ɵR3_TEMPLATE_REF_FACTORY__POST_NGCC__,
|
} from './metadata/ng_module';
|
||||||
R3_CHANGE_DETECTOR_REF_FACTORY__POST_NGCC__ as ɵR3_CHANGE_DETECTOR_REF_FACTORY__POST_NGCC__,
|
export {
|
||||||
R3_VIEW_CONTAINER_REF_FACTORY__POST_NGCC__ as ɵR3_VIEW_CONTAINER_REF_FACTORY__POST_NGCC__,
|
SWITCH_COMPILE_INJECTABLE__POST_R3__ as ɵSWITCH_COMPILE_INJECTABLE__POST_R3__,
|
||||||
R3_RENDERER2_FACTORY__POST_NGCC__ as ɵR3_RENDERER2_FACTORY__POST_NGCC__,
|
} from './di/injectable';
|
||||||
} from './ivy_switch/runtime/legacy';
|
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
|
// clang-format on
|
||||||
|
@ -6,12 +6,14 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* 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 {Type} from '../type';
|
||||||
import {makeDecorator} from '../util/decorators';
|
import {makeDecorator} from '../util/decorators';
|
||||||
|
|
||||||
import {InjectableDef, InjectableType} from './defs';
|
import {InjectableDef, InjectableType, defineInjectable, getInjectableDef} from './defs';
|
||||||
import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from './provider';
|
import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueSansProvider} from './provider';
|
||||||
|
import {convertInjectableProviderToFactory} from './util';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injectable providers used in `@Injectable` decorator.
|
* Injectable providers used in `@Injectable` decorator.
|
||||||
@ -64,7 +66,7 @@ export interface Injectable { providedIn?: Type<any>|'root'|null; }
|
|||||||
*/
|
*/
|
||||||
export const Injectable: InjectableDecorator = makeDecorator(
|
export const Injectable: InjectableDecorator = makeDecorator(
|
||||||
'Injectable', undefined, undefined, undefined,
|
'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.
|
* Type representing injectable service.
|
||||||
@ -72,3 +74,22 @@ export const Injectable: InjectableDecorator = makeDecorator(
|
|||||||
* @publicApi
|
* @publicApi
|
||||||
*/
|
*/
|
||||||
export interface InjectableType<T> extends Type<T> { ngInjectableDef: InjectableDef<T>; }
|
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__;
|
||||||
|
55
packages/core/src/di/util.ts
Normal file
55
packages/core/src/di/util.ts
Normal 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 !));
|
||||||
|
}
|
||||||
|
}
|
@ -6,4 +6,6 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* 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__;
|
@ -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.
|
|
@ -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;
|
|
@ -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),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -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';
|
|
@ -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;
|
|
@ -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__;
|
|
@ -6,7 +6,8 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* 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.
|
* 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; }
|
constructor(nativeElement: T) { this.nativeElement = nativeElement; }
|
||||||
|
|
||||||
/** @internal */
|
/** @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__;
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* 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 {ElementRef} from './element_ref';
|
||||||
import {EmbeddedViewRef} from './view_ref';
|
import {EmbeddedViewRef} from './view_ref';
|
||||||
@ -54,5 +55,10 @@ export abstract class TemplateRef<C> {
|
|||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
static __NG_ELEMENT_ID__:
|
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__;
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Injector} from '../di/injector';
|
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 {ComponentFactory, ComponentRef} from './component_factory';
|
||||||
import {ElementRef} from './element_ref';
|
import {ElementRef} from './element_ref';
|
||||||
@ -145,5 +146,10 @@ export abstract class ViewContainerRef {
|
|||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
static __NG_ELEMENT_ID__:
|
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__;
|
||||||
|
@ -8,10 +8,12 @@
|
|||||||
|
|
||||||
import {ChangeDetectionStrategy} from '../change_detection/constants';
|
import {ChangeDetectionStrategy} from '../change_detection/constants';
|
||||||
import {Provider} from '../di';
|
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 {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 {Type} from '../type';
|
||||||
import {TypeDecorator, makeDecorator, makePropDecorator} from '../util/decorators';
|
import {TypeDecorator, makeDecorator, makePropDecorator} from '../util/decorators';
|
||||||
|
import {noop} from '../util/noop';
|
||||||
import {fillProperties} from '../util/property';
|
import {fillProperties} from '../util/property';
|
||||||
|
|
||||||
import {ViewEncapsulation} from './view';
|
import {ViewEncapsulation} from './view';
|
||||||
@ -353,7 +355,7 @@ export interface Directive {
|
|||||||
*/
|
*/
|
||||||
export const Directive: DirectiveDecorator = makeDecorator(
|
export const Directive: DirectiveDecorator = makeDecorator(
|
||||||
'Directive', (dir: Directive = {}) => dir, undefined, undefined,
|
'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
|
* Component decorator interface
|
||||||
@ -639,7 +641,8 @@ export interface Component extends Directive {
|
|||||||
*/
|
*/
|
||||||
export const Component: ComponentDecorator = makeDecorator(
|
export const Component: ComponentDecorator = makeDecorator(
|
||||||
'Component', (c: Component = {}) => ({changeDetection: ChangeDetectionStrategy.Default, ...c}),
|
'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.
|
* Type of the Pipe decorator / constructor function.
|
||||||
@ -688,7 +691,7 @@ export interface Pipe {
|
|||||||
*/
|
*/
|
||||||
export const Pipe: PipeDecorator = makeDecorator(
|
export const Pipe: PipeDecorator = makeDecorator(
|
||||||
'Pipe', (p: Pipe) => ({pure: true, ...p}), undefined, undefined,
|
'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 =
|
export const HostListener: HostListenerDecorator =
|
||||||
makePropDecorator('HostListener', (eventName?: string, args?: string[]) => ({eventName, args}));
|
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__;
|
||||||
|
@ -7,8 +7,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {ApplicationRef} from '../application_ref';
|
import {ApplicationRef} from '../application_ref';
|
||||||
|
import {InjectorType, defineInjector} from '../di/defs';
|
||||||
import {Provider} from '../di/provider';
|
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 {Type} from '../type';
|
||||||
import {TypeDecorator, makeDecorator} from '../util/decorators';
|
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
|
* * The `imports` and `exports` options bring in members from other modules, and make
|
||||||
* this module's members available to others.
|
* 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
|
* @description
|
||||||
@ -356,3 +358,21 @@ export const NgModule: NgModuleDecorator = makeDecorator(
|
|||||||
* @publicApi
|
* @publicApi
|
||||||
*/
|
*/
|
||||||
export interface DoBootstrap { ngDoBootstrap(appRef: ApplicationRef): void; }
|
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__;
|
||||||
|
@ -8,8 +8,9 @@
|
|||||||
|
|
||||||
import {InjectionToken} from '../di/injection_token';
|
import {InjectionToken} from '../di/injection_token';
|
||||||
import {Injector} from '../di/injector';
|
import {Injector} from '../di/injector';
|
||||||
import {R3_RENDERER2_FACTORY} from '../ivy_switch/runtime/index';
|
|
||||||
import {ViewEncapsulation} from '../metadata/view';
|
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;
|
callback: (event: any) => boolean | void): () => void;
|
||||||
|
|
||||||
/** @internal */
|
/** @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__;
|
||||||
|
@ -205,9 +205,15 @@ The goal is for the `@Component` (and friends) to be the compiler of template. S
|
|||||||
### I18N
|
### I18N
|
||||||
| Feature | Runtime | Spec | Compiler |
|
| Feature | Runtime | Spec | Compiler |
|
||||||
| ----------------------------------- | ------- | -------- | -------- |
|
| ----------------------------------- | ------- | -------- | -------- |
|
||||||
| translate text literals | ❌ | ❌ | ✅ |
|
| i18nStart | ❌ | ✅ | ✅ |
|
||||||
| rearrange text nodes | ❌ | ❌ | ❌ |
|
| i18nEnd | ❌ | ✅ | ✅ |
|
||||||
| ICU | ❌ | ❌ | ❌ |
|
| i18nAttributes | ❌ | ✅ | ✅ |
|
||||||
|
| i18nExp | ❌ | ✅ | ✅ |
|
||||||
|
| i18nApply | ❌ | ✅ | ✅ |
|
||||||
|
| ICU expressions | ❌ | ✅ | ❌ |
|
||||||
|
| closure support for g3 | ✅ | ✅ | ❌ |
|
||||||
|
| runtime service for external world | ❌ | ❌ | ❌ |
|
||||||
|
| migration tool | ❌ | ❌ | ❌ |
|
||||||
|
|
||||||
|
|
||||||
### View Encapsulation
|
### View Encapsulation
|
||||||
|
@ -502,6 +502,12 @@ function executePipeOnDestroys(viewData: LViewData): void {
|
|||||||
export function getRenderParent(tNode: TNode, currentView: LViewData): RElement|null {
|
export function getRenderParent(tNode: TNode, currentView: LViewData): RElement|null {
|
||||||
if (canInsertNativeNode(tNode, currentView)) {
|
if (canInsertNativeNode(tNode, currentView)) {
|
||||||
const hostTNode = currentView[HOST_NODE];
|
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 ?
|
return tNode.parent == null && hostTNode !.type === TNodeType.View ?
|
||||||
getContainerRenderParent(hostTNode as TViewNode, currentView) :
|
getContainerRenderParent(hostTNode as TViewNode, currentView) :
|
||||||
getParentNative(tNode, currentView) as RElement;
|
getParentNative(tNode, currentView) as RElement;
|
||||||
@ -626,8 +632,7 @@ export function appendChild(
|
|||||||
renderer, lContainer[RENDER_PARENT] !, childEl,
|
renderer, lContainer[RENDER_PARENT] !, childEl,
|
||||||
getBeforeNodeForView(index, views, lContainer[NATIVE]));
|
getBeforeNodeForView(index, views, lContainer[NATIVE]));
|
||||||
} else if (parentTNode.type === TNodeType.ElementContainer) {
|
} else if (parentTNode.type === TNodeType.ElementContainer) {
|
||||||
let elementContainer = getHighestElementContainer(childTNode);
|
const renderParent: RElement = getRenderParent(childTNode, currentView) !;
|
||||||
let renderParent: RElement = getRenderParent(elementContainer, currentView) !;
|
|
||||||
nativeInsertBefore(renderer, renderParent, childEl, parentEl);
|
nativeInsertBefore(renderer, renderParent, childEl, parentEl);
|
||||||
} else {
|
} else {
|
||||||
isProceduralRenderer(renderer) ? renderer.appendChild(parentEl !as RElement, childEl) :
|
isProceduralRenderer(renderer) ? renderer.appendChild(parentEl !as RElement, childEl) :
|
||||||
|
@ -6,4 +6,6 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export * from './ivy_switch_on';
|
export function noop(...args: any[]): any {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
@ -12,7 +12,7 @@ import {InjectableDef, getInjectableDef} from '../di/defs';
|
|||||||
import {InjectableType} from '../di/injectable';
|
import {InjectableType} from '../di/injectable';
|
||||||
import {ErrorHandler} from '../error_handler';
|
import {ErrorHandler} from '../error_handler';
|
||||||
import {isDevMode} from '../is_dev_mode';
|
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 {ComponentFactory} from '../linker/component_factory';
|
||||||
import {NgModuleRef} from '../linker/ng_module_factory';
|
import {NgModuleRef} from '../linker/ng_module_factory';
|
||||||
import {Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2} from '../render/api';
|
import {Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2} from '../render/api';
|
||||||
|
@ -37,6 +37,7 @@ js_expected_symbol_test(
|
|||||||
src = ":bundle.min_debug.js",
|
src = ":bundle.min_debug.js",
|
||||||
golden = ":bundle.golden_symbols.json",
|
golden = ":bundle.golden_symbols.json",
|
||||||
tags = [
|
tags = [
|
||||||
|
"ivy-aot",
|
||||||
"ivy-only",
|
"ivy-only",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -158,15 +158,6 @@
|
|||||||
{
|
{
|
||||||
"name": "QUERIES"
|
"name": "QUERIES"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "R3_ELEMENT_REF_FACTORY"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "R3_TEMPLATE_REF_FACTORY"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "R3_VIEW_CONTAINER_REF_FACTORY"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "RENDERER"
|
"name": "RENDERER"
|
||||||
},
|
},
|
||||||
@ -185,6 +176,15 @@
|
|||||||
{
|
{
|
||||||
"name": "SANITIZER"
|
"name": "SANITIZER"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "SWITCH_ELEMENT_REF_FACTORY"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SWITCH_TEMPLATE_REF_FACTORY"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SWITCH_VIEW_CONTAINER_REF_FACTORY"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "SimpleKeyframePlayer"
|
"name": "SimpleKeyframePlayer"
|
||||||
},
|
},
|
||||||
|
@ -59,6 +59,7 @@ js_expected_symbol_test(
|
|||||||
src = ":bundle.min_debug.js",
|
src = ":bundle.min_debug.js",
|
||||||
golden = ":bundle.golden_symbols.json",
|
golden = ":bundle.golden_symbols.json",
|
||||||
tags = [
|
tags = [
|
||||||
|
"ivy-aot",
|
||||||
"ivy-only",
|
"ivy-only",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -1250,24 +1250,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Quote"
|
"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"
|
"name": "ReadKeyExpr"
|
||||||
},
|
},
|
||||||
@ -1352,6 +1334,24 @@
|
|||||||
{
|
{
|
||||||
"name": "STYLE_PREFIX"
|
"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"
|
"name": "SafeMethodCall"
|
||||||
},
|
},
|
||||||
@ -1599,10 +1599,10 @@
|
|||||||
"name": "URL_WITH_SCHEMA_REGEXP"
|
"name": "URL_WITH_SCHEMA_REGEXP"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "USE_VALUE"
|
"name": "USE_VALUE$1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "USE_VALUE$3"
|
"name": "USE_VALUE$2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "UnsubscriptionError"
|
"name": "UnsubscriptionError"
|
||||||
@ -2460,7 +2460,7 @@
|
|||||||
"name": "compileNgModuleFactory"
|
"name": "compileNgModuleFactory"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "compileNgModuleFactory__PRE_NGCC__"
|
"name": "compileNgModuleFactory__PRE_R3__"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "componentFactoryName"
|
"name": "componentFactoryName"
|
||||||
@ -3411,10 +3411,10 @@
|
|||||||
"name": "noop$1"
|
"name": "noop$1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "noop$3"
|
"name": "noop$2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "noopFactory"
|
"name": "noop$3"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "noopScope"
|
"name": "noopScope"
|
||||||
@ -3476,9 +3476,6 @@
|
|||||||
{
|
{
|
||||||
"name": "platformCoreDynamic"
|
"name": "platformCoreDynamic"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "preR3InjectableCompile"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "preparseElement"
|
"name": "preparseElement"
|
||||||
},
|
},
|
||||||
@ -3554,6 +3551,9 @@
|
|||||||
{
|
{
|
||||||
"name": "removeWhitespaces"
|
"name": "removeWhitespaces"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "render2CompileInjectable"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "renderAttachEmbeddedView"
|
"name": "renderAttachEmbeddedView"
|
||||||
},
|
},
|
||||||
|
@ -60,7 +60,7 @@
|
|||||||
"name": "THROW_IF_NOT_FOUND"
|
"name": "THROW_IF_NOT_FOUND"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "USE_VALUE"
|
"name": "USE_VALUE$1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "UnsubscriptionErrorImpl"
|
"name": "UnsubscriptionErrorImpl"
|
||||||
@ -147,12 +147,12 @@
|
|||||||
"name": "providerToRecord"
|
"name": "providerToRecord"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "resolveForwardRef"
|
"name": "resolveForwardRef$1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "setCurrentInjector"
|
"name": "setCurrentInjector"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "stringify"
|
"name": "stringify$1"
|
||||||
}
|
}
|
||||||
]
|
]
|
@ -66,6 +66,7 @@ js_expected_symbol_test(
|
|||||||
src = ":bundle.min_debug.js",
|
src = ":bundle.min_debug.js",
|
||||||
golden = ":bundle.golden_symbols.json",
|
golden = ":bundle.golden_symbols.json",
|
||||||
tags = [
|
tags = [
|
||||||
|
"ivy-aot",
|
||||||
"ivy-only",
|
"ivy-only",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -152,15 +152,6 @@
|
|||||||
{
|
{
|
||||||
"name": "QUERIES"
|
"name": "QUERIES"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "R3_ELEMENT_REF_FACTORY"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "R3_TEMPLATE_REF_FACTORY"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "R3_VIEW_CONTAINER_REF_FACTORY"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "RENDERER"
|
"name": "RENDERER"
|
||||||
},
|
},
|
||||||
@ -179,6 +170,15 @@
|
|||||||
{
|
{
|
||||||
"name": "SANITIZER"
|
"name": "SANITIZER"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "SWITCH_ELEMENT_REF_FACTORY"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SWITCH_TEMPLATE_REF_FACTORY"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SWITCH_VIEW_CONTAINER_REF_FACTORY"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "SkipSelf"
|
"name": "SkipSelf"
|
||||||
},
|
},
|
||||||
|
@ -72,6 +72,7 @@ js_expected_symbol_test(
|
|||||||
src = ":bundle.min_debug.js",
|
src = ":bundle.min_debug.js",
|
||||||
golden = ":bundle.golden_symbols.json",
|
golden = ":bundle.golden_symbols.json",
|
||||||
tags = [
|
tags = [
|
||||||
|
"ivy-aot",
|
||||||
"ivy-only",
|
"ivy-only",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -140,9 +140,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Compiler"
|
"name": "Compiler"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "CompilerFactory"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "ComponentFactory"
|
"name": "ComponentFactory"
|
||||||
},
|
},
|
||||||
@ -680,21 +677,6 @@
|
|||||||
{
|
{
|
||||||
"name": "R3Injector"
|
"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"
|
"name": "REMOVE_EVENT_LISTENER"
|
||||||
},
|
},
|
||||||
@ -758,6 +740,21 @@
|
|||||||
{
|
{
|
||||||
"name": "SURROGATE_PAIR_REGEXP"
|
"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"
|
"name": "SafeHtmlImpl"
|
||||||
},
|
},
|
||||||
@ -1281,7 +1278,7 @@
|
|||||||
"name": "compileNgModuleFactory"
|
"name": "compileNgModuleFactory"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "compileNgModuleFactory__PRE_NGCC__"
|
"name": "compileNgModuleFactory__POST_R3__"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "componentRefresh"
|
"name": "componentRefresh"
|
||||||
@ -2157,10 +2154,10 @@
|
|||||||
"name": "noSideEffects"
|
"name": "noSideEffects"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "noop$1"
|
"name": "noop$2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "noop$2"
|
"name": "noop$3"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "noopScope"
|
"name": "noopScope"
|
||||||
|
@ -6,9 +6,9 @@ load("//tools:defaults.bzl", "ts_library")
|
|||||||
ts_library(
|
ts_library(
|
||||||
name = "reflect_metadata",
|
name = "reflect_metadata",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"src/reflect_metadata_aot.ts",
|
||||||
"src/reflect_metadata_jit.ts",
|
"src/reflect_metadata_jit.ts",
|
||||||
"src/reflect_metadata_legacy.ts",
|
"src/reflect_metadata_legacy.ts",
|
||||||
"src/reflect_metadata_local.ts",
|
|
||||||
":metadata_switch",
|
":metadata_switch",
|
||||||
],
|
],
|
||||||
module_name = "@angular/core/test/bundling/util/src/reflect_metadata",
|
module_name = "@angular/core/test/bundling/util/src/reflect_metadata",
|
||||||
|
@ -943,6 +943,116 @@ describe('render3 integration test', () => {
|
|||||||
expect(directive !.elRef.nativeElement.nodeType).toBe(Node.COMMENT_NODE);
|
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', () => {
|
it('should not set any attributes', () => {
|
||||||
/**
|
/**
|
||||||
* <div><ng-container id="foo"></ng-container></div>
|
* <div><ng-container id="foo"></ng-container></div>
|
||||||
|
@ -11,7 +11,7 @@ import 'reflect-metadata';
|
|||||||
import {InjectorDef, defineInjectable} from '@angular/core/src/di/defs';
|
import {InjectorDef, defineInjectable} from '@angular/core/src/di/defs';
|
||||||
import {Injectable} from '@angular/core/src/di/injectable';
|
import {Injectable} from '@angular/core/src/di/injectable';
|
||||||
import {inject, setCurrentInjector} from '@angular/core/src/di/injector';
|
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 {Component, HostBinding, HostListener, Input, Output, Pipe} from '@angular/core/src/metadata/directives';
|
||||||
import {NgModule, NgModuleDef} from '@angular/core/src/metadata/ng_module';
|
import {NgModule, NgModuleDef} from '@angular/core/src/metadata/ng_module';
|
||||||
import {ComponentDef, PipeDef} from '@angular/core/src/render3/interfaces/definition';
|
import {ComponentDef, PipeDef} from '@angular/core/src/render3/interfaces/definition';
|
||||||
|
@ -13,8 +13,12 @@ import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref';
|
|||||||
import {Renderer2} from '@angular/core/src/render/api';
|
import {Renderer2} from '@angular/core/src/render/api';
|
||||||
import {stringifyElement} from '@angular/platform-browser/testing/src/browser_util';
|
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 {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 {CreateComponentOptions} from '../../src/render3/component';
|
||||||
import {discoverDirectives, getContext, isComponentInstance} from '../../src/render3/context_discovery';
|
import {discoverDirectives, getContext, isComponentInstance} from '../../src/render3/context_discovery';
|
||||||
import {extractDirectiveDef, extractPipeDef} from '../../src/render3/definition';
|
import {extractDirectiveDef, extractPipeDef} from '../../src/render3/definition';
|
||||||
|
52
packages/router/src/operators/prioritized_guard_value.ts
Normal file
52
packages/router/src/operators/prioritized_guard_value.ts
Normal 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>;
|
||||||
|
});
|
||||||
|
}
|
@ -16,6 +16,7 @@ ts_library(
|
|||||||
"//packages/router/testing",
|
"//packages/router/testing",
|
||||||
"@rxjs",
|
"@rxjs",
|
||||||
"@rxjs//operators",
|
"@rxjs//operators",
|
||||||
|
"@rxjs//testing",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
182
packages/router/test/operators/prioritized_guard_value.spec.ts
Normal file
182
packages/router/test/operators/prioritized_guard_value.spec.ts
Normal 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
Reference in New Issue
Block a user