Compare commits

..

226 Commits

Author SHA1 Message Date
ad6771dcd4 release: cut the v7.1.0-beta.1 release 2018-10-31 16:34:43 -07:00
2c25d29b25 docs: release notes for the v7.0.2 release 2018-10-31 16:30:33 -07:00
ec29fd3e7b build: remove problematic yarn prefix for running bazel 2018-10-31 16:01:36 -07:00
d042c4afe0 fix(core): Remove static dependency from @angular/core to @angular/compiler (#26734)
PR Close #26734
2018-10-31 14:15:06 -04:00
5d740785a9 docs: fix aot typo 2018-10-30 17:37:20 -07:00
68b2211e64 fix(ivy): ensure falsy styling is not applied during creation mode (#26793)
PR Close #26793
2018-10-30 19:41:56 -04:00
332394d87c build(bazel): generalize fix for AMD name for flat module out file (#26837)
PR Close #26837
2018-10-30 18:37:12 -04:00
62b4ff5250 docs: fixup deployment guide (#26486)
- remove sections that were not relevant (all the development stuff)
- fix incorrect info

PR Close #26486
2018-10-30 16:29:04 -04:00
634e9e970a docs: Removing duplicate lines (#26754)
Duplicate lines are removed to avoid confusion.
PR Close #26754
2018-10-30 16:24:51 -04:00
678c28175e docs: fix typo (#26776)
PR Close #26776
2018-10-30 16:24:13 -04:00
87a7f2dcb9 docs: fix typo (#26773)
PR Close #26773
2018-10-30 16:23:49 -04:00
8fc4ae51fb build: use bazel version from node modules (#26691)
* No longer depends on a custom CircleCI docker image that comes with Bazel pre-installed. Since Bazel is now available through NPM, we should be able to use the version from `@bazel/bazel` in order to enforce a consistent environment on CI and locally.
* This also reduces the amount of packages that need to be published (ngcontainer is removed)

PR Close #26691
2018-10-30 16:19:13 -04:00
66be3c9f51 build: Move non-bazel deps to devDependencies (#26691)
This makes yarn_install of ngdeps under Bazel faster, since we don't need many of the large dependencies.
It's important because downstream angular/bazel users will observe the same install time.

PR Close #26691
2018-10-30 16:19:13 -04:00
b95089db20 docs: replace unused variable by _ (#26768)
replace unused variable by _  to keep the code consistent between examples

PR Close #26768
2018-10-30 13:49:52 -04:00
8a4ec8e565 docs: describe your change... (#26784)
PR Close #26784
2018-10-30 13:49:12 -04:00
95743e3a64 fix(core): support computed base class in metadata inheritance (#24014)
PR Close #24014
2018-10-30 13:48:22 -04:00
9ad54d74d2 build: fix ts-api-guardian does not work on windows w/ bazel (#26761)
* Fixes that the `ts-api-guardian` package does not work on Windows with Bazel. This is because `ts-api-guardian` does not resolve the runfiles through theNodeJS `require` function that properly handles runfiles within Bazel.

PR Close #26761
2018-10-30 13:45:58 -04:00
0e1cceed50 build: add option to disable ts-api-guardian default angular tag rules (#26761)
Since the API guardian can be also used by other projects, we should not set up the default Angular project tag rules unless specified explicitly through a given command option (`useAngularTagRules`)

PR Close #26761
2018-10-30 13:45:58 -04:00
23648b052a docs: configuration file reference (#26484)
PR Close #26484
2018-10-30 13:44:52 -04:00
91d2368e37 docs: update example dependencies to Angular/CLI/Universal V7 releases (#26820)
PR Close #26820
2018-10-30 13:44:24 -04:00
ede65dbede fix(ivy): allow root components to inject ViewContainerRef (#26682)
PR Close #26682
2018-10-29 18:47:14 -04:00
578e4c7642 fix(ivy): compile queries in JIT mode (#26816)
PR Close #26816
2018-10-29 18:46:44 -04:00
96770e5c6b fix(ivy): optional dependencies should not throw with module injector (#26763)
PR Close #26763
2018-10-29 14:12:36 -04:00
1130e48541 fix(ivy): host injection flag should not throw for embedded views (#26795)
PR Close #26795
2018-10-29 14:12:11 -04:00
2a869271f6 fix(ivy): move HostListeners generation to factory function (#26480)
PR Close #26480
2018-10-29 14:02:22 -04:00
c0bf222a05 ci: exclude ngcc from g3sync check (#26740)
PR Close #26740
2018-10-29 13:04:10 -04:00
d72d50d83e build(docs-infra): move CLI API desciption higher up (#26568)
Closes #26556

PR Close #26568
2018-10-29 13:01:08 -04:00
ef6f1605db ci(docs-infra): notify caretaker about aio_monitoring failures (#26649)
PR Close #26649
2018-10-29 13:00:20 -04:00
ea7ec4a6b3 test(docs-infra): make redirection tests more robust (#26649)
PR Close #26649
2018-10-29 13:00:20 -04:00
72f3d99920 test(docs-infra): make smoke tests more robust (#26649)
PR Close #26649
2018-10-29 13:00:20 -04:00
f6991dec3b test(docs-infra): fix smoke tests (#26649)
PR Close #26649
2018-10-29 13:00:20 -04:00
0367d14044 test(docs-infra): run basic smoke tests against PR previews (#26649)
This makes the tests run agaisnt the deployed production versions (as
part of the `aio_monitoring` job) more reliable.

PR Close #26649
2018-10-29 13:00:20 -04:00
8bf51db3e7 test: mark public_api_guard test with fixme-ivy-aot and no-ivy-jit (#26602)
These tests are currently broken because of the following reasons:
- ivy no longer emits a generated index, so the filename of the main d.ts file is different
- ivy currently exports some symbols that don't match the golden file, this needs investigation

PR Close #26602
2018-10-29 12:59:47 -04:00
4f250726aa build: fix the accept binary path in ts-api-guardian error message (#26602)
Fixes #26589

PR Close #26602
2018-10-29 12:59:47 -04:00
86d3099141 build: remove unused @angular/compiler ts-api-guardian golden files (#26602)
these files are not used because the api surface of this package is not considered
to be stable/public api.

the presence of these files only confuses the reader.

PR Close #26602
2018-10-29 12:59:47 -04:00
d4c3742e25 build: don't depend on npm packages from public api tests (#26602)
We need only the inputs from ng_module.

PR Close #26602
2018-10-29 12:59:47 -04:00
95993e1dd5 fix(ivy): ensure pipes indices are referenced in styling bindings (#26755)
PR Close #26755
2018-10-26 18:40:23 -04:00
d52d82d744 fix(ivy): injecting optional TemplateRef on element should not throw (#26664)
PR Close #26664
2018-10-26 18:11:27 -04:00
d2e6d6978e docs: add ant design mobile of angular in resources (#26562)
PR Close #26562
2018-10-26 18:10:46 -04:00
da4a28e692 docs: fix indentation (#26623)
PR Close #26623
2018-10-26 18:10:15 -04:00
b876356527 docs: add links to angular subdomains (#26653)
Add link to protactor.angular.io
Replace link from github.com/angular/universal to universal.angular.io
Replace link from github.com/angular/material2 to material.angular.io

fix #18257

PR Close #26653
2018-10-26 18:09:45 -04:00
07509da78d build(docs-infra): ensure that CLI code blocks are not auto-linked (#26675)
Some of the text in CLI API docs were being auto-linked to API
pages. This was not correct, and in fact these blocks should not
have any auto links to Angular API at all.

Closes #26570

PR Close #26675
2018-10-26 18:09:20 -04:00
9ff8155cd9 build(docs-infra): mark code blocks to disable auto-linking (#26675)
You can now mark `<code>` blocks with a `no-auto-link` css class
to tell the code auto-linker to ignore this code block.

PR Close #26675
2018-10-26 18:09:20 -04:00
56f44be0aa fix(compiler): generate relative paths only in summary file errors (#26759)
Previously errors in the summary file would include absolute file names.
This is undesirable as the output of a build should not depend on the
current working directory. Doing so causes nondeterminism issues in
builds.

PR Close #26759
2018-10-26 18:07:55 -04:00
d50d400231 build: fix formatting issue in host_binding_spec file 2018-10-26 14:33:04 -07:00
19fcfc3d00 fix(compiler): generate inputs with aliases properly (#26774)
PR Close #26774
2018-10-26 17:23:45 -04:00
c048358cf9 build: fix the golden files for hello_world_r2 2018-10-26 14:20:40 -07:00
8171a2ab94 fix(ivy): ensure pipe declarations are populated lazily when a forward ref is detected (#26765)
PR Close #26765
2018-10-26 15:57:10 -04:00
2fd4c372d5 fix(ivy): resolve forward refs in providers (#26766)
PR Close #26766
2018-10-26 15:50:11 -04:00
f76ce84ae1 fix(ivy): host bindings should work on nodes with providers (#26771)
PR Close #26771
2018-10-26 15:49:30 -04:00
f3859130f2 ci: configure chrome options for protractor (#26735)
so that they are more suitable for CI usage.

PR Close #26735
2018-10-26 14:48:05 -04:00
0f274d65c4 ci: mark //modules/benchmarks/src/largetable/render3:perf with fixme-ivy-* tags (#26735)
This target fails with odd error that we need to investigate:

[01:19:32] I/direct - Using ChromeDriver directly...
[01:19:32] E/direct - Error code: 135
[01:19:32] E/direct - Error message: Could not find chromedriver at /home/circleci/.cache/bazel/_bazel_circleci/9ce5c2144ecf75d11717c0aa41e45a8d/external/ngdeps/node_modules/webdriver-manager/selenium/chromedriver_2.41. Run 'webdriver-manager update' to download binaries.
[01:19:32] E/direct - Error: Could not find chromedriver at /home/circleci/.cache/bazel/_bazel_circleci/9ce5c2144ecf75d11717c0aa41e45a8d/external/ngdeps/node_modules/webdriver-manager/selenium/chromedriver_2.41. Run 'webdriver-manager update' to download binaries.

PR Close #26735
2018-10-26 14:48:05 -04:00
cb71b93351 ci: use yarn test-ivy-... (#26735)
This means that we use the same command to run test on CI as when developing locally.

PR Close #26735
2018-10-26 14:48:05 -04:00
4b51d31aea build: fix symbol-extractor by passing through "compile" as environmental variable (#26735)
PR Close #26735
2018-10-26 14:48:05 -04:00
40bbfbf961 test(ivy): fix or disable failing ivy tests (#26735)
These tests were previously not running on CI so they have always been broken,
or got broken just recently :-(.

test(ivy): mark failing test targets with fixme-ivy-jit and fixme-ivy-local tags

PR Close #26735
2018-10-26 14:48:05 -04:00
30f319a11f build: remove ivy build/test tag hackery now that we can (#26735)
With https://github.com/bazelbuild/rules_nodejs/pull/388 fixed we can stop messing around
with tags and just rely on the explicitly defined tags.

PR Close #26735
2018-10-26 14:48:04 -04:00
5d7ba57dd5 docs: rename ivy compile mode 'local' to 'aot' in BAZEL.md (#26735)
PR Close #26735
2018-10-26 14:48:04 -04:00
9cd8327051 ci: move CircleCI env variables definition to shell script (#26596)
PR Close #26596
2018-10-26 13:22:52 -04:00
1d8f939c96 ci: add more info on how CircleCI env vars are defined (#26596)
PR Close #26596
2018-10-26 13:22:52 -04:00
2e28d9f012 ci: run Xvfb in the background on CircleCI (#26596)
PR Close #26596
2018-10-26 13:22:52 -04:00
7c730fe5b3 build(docs-infra): include inherited members in search index (#26676)
Closes #23800

PR Close #26676
2018-10-26 13:16:33 -04:00
f233131974 build(docs-infra): refactor generateKeywords processor (#26676)
PR Close #26676
2018-10-26 13:16:32 -04:00
aefa06f7df docs(core): update security guide sanitize example (#26777)
The sanitizer now removes the content of script tags as well as the tag itself.

PR Close #26777
2018-10-26 12:31:49 -04:00
d878f3df93 test(core): fix security example e2e test (#26777)
The changes in d5cbcef0ea caused this test to fail.

PR Close #26777
2018-10-26 12:31:49 -04:00
f8741c0985 ci(docs-infra): split test_and_deploy_aio to two separate jobs (#26746)
By splitting the jobs, if something goes wrong with deploying (e.g. a
network issue), we can re-run just that part instead of having to wait
for all the tests to complete again.

In terms of total duration, the difference should be minimal, because
the two operations (testing and deploying) do not depend on shared
tasks. For example, we need to build again (for the specific target
environment; e.g. stable, next, etc.) before deploying anyway.

PR Close #26746
2018-10-25 21:17:52 -04:00
5e2ce9b2a6 build: clean up *.gz files created by payload-size.sh (#26746)
These files are not needed once the size has been calculated and there
is no point in keeping them around.

Deleting them prevents, for example, uploading unnecessary files from
`aio/dist/` to Firebase (because `deploy-to-firebase.sh` runs the
payload size checks right before deploying).

PR Close #26746
2018-10-25 21:17:52 -04:00
d725ab5142 ci(docs-infra): reduce verbosity of yarn build on CI (#26746)
PR Close #26746
2018-10-25 21:17:52 -04:00
f1a860fbf7 ci(docs-infra): fix deployment to Firebase (#26746)
Previously, `firebase-tools@3.x` was used and the deployment from
CircleCI failed with `Unexpected error` (HTTP code: 410).

This commit ensures that we use a recent version of `firebase-tools` for
deploying to Firebase. It also ensures that we use the locally installed
`firebase-tools` (not sure where it came from before 😁).

PR Close #26746
2018-10-25 21:17:52 -04:00
141f9b2386 build(docs-infra): upgrade cli command docs sources to 4faa81e25 (#26741)
PR Close #26741
2018-10-25 21:10:21 -04:00
95f852e856 build: fix comment formatting to make closure happy (#26769)
PR Close #26769
2018-10-25 19:40:36 -04:00
2c7386c961 feat(ivy): support injecting the injector (#26699)
PR Close #26699
2018-10-25 18:47:56 -04:00
d5cbcef0ea fix(core): ignore comment nodes under unsafe elements (#25879)
Comment nodes that are child nodes of unsafe elements are identified as text nodes. This results in the comment node being returned as an encoded string.
Add a check to ignore such comment nodes.

PR Close #25879
2018-10-25 11:20:19 -07:00
b0476f308b feat(ivy): support providers and viewProviders (#25803)
PR Close #25803
2018-10-25 12:58:40 -04:00
9dc52d9d04 feat(ivy): expose a series of debug console tools (#26705)
PR Close #26705
2018-10-24 20:30:51 -04:00
297dc2bc02 fix(ivy): ensure ngClass works with [class] bindings (#26559)
PR Close #26559
2018-10-24 20:27:12 -04:00
0cc9842bf6 test(upgrade): make e2e tests for upgrade docs examples less flaky (#26726)
PR Close #26726
2018-10-24 19:49:14 -04:00
54ea10288e test(elements): make e2e tests for elements docs examples even less flaky (#26726)
PR Close #26726
2018-10-24 19:49:14 -04:00
1880c9531f ci: only publish builds if relevant aio jobs pass (#26722)
Some of the `aio`-/`docs`-related jobs rely on the locally built Angular
packages. When these jobs fail, it could mean that there is an issue
with the Angular packages (e.g. an unintentional breaking change).

This commit ensures that the `publish_artifacts` job is not run, unless
those `aio`-/`docs`-related jobs pass.

(The `test_aio_tools` job also uses the locally built Angular packages,
but it does not exercise them in a meaningful way to be worth making it
a prerequisite for `publish_artifacts`.)

PR Close #26722
2018-10-24 19:48:41 -04:00
13a803d4f7 build(docs-infra): fix parameter type rendering (#26688)
Closes #24355

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

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

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

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

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

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

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

This is the updated overview of ivy related bazel tags:

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

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

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

* build: update skylint to bazel 0.18

use .bazelignore file to ignore node_modules directory

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

View File

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

View File

@ -50,6 +50,7 @@ merge:
- "**/BUILD.bazel"
- "packages/**/integrationtest/**"
- "packages/**/test/**"
- "packages/compiler-cli/src/ngcc/**"
# comment that will be added to a PR when there is a conflict, leave empty or set to false to disable
mergeConflictComment: "Hi @{{PRAuthor}}! This PR has merge conflicts due to recent upstream merges.

View File

@ -1,3 +1,17 @@
<a name="7.1.0-beta.1"></a>
# [7.1.0-beta.1](https://github.com/angular/angular/compare/7.1.0-beta.0...7.1.0-beta.1) (2018-10-31)
### Bug Fixes
* **compiler:** generate inputs with aliases properly ([#26774](https://github.com/angular/angular/issues/26774)) ([19fcfc3](https://github.com/angular/angular/commit/19fcfc3))
* **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([56f44be](https://github.com/angular/angular/commit/56f44be))
* **core:** ignore comment nodes under unsafe elements ([#25879](https://github.com/angular/angular/issues/25879)) ([d5cbcef](https://github.com/angular/angular/commit/d5cbcef))
* **core:** Remove static dependency from [@angular](https://github.com/angular)/core to [@angular](https://github.com/angular)/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([d042c4a](https://github.com/angular/angular/commit/d042c4a))
* **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([95743e3](https://github.com/angular/angular/commit/95743e3))
<a name="7.0.2"></a>
## [7.0.2](https://github.com/angular/angular/compare/7.0.1...7.0.2) (2018-10-31)
@ -10,6 +24,23 @@
<a name="7.1.0-beta.0"></a>
# [7.1.0-beta.0](https://github.com/angular/angular/compare/7.0.0-rc.1...7.1.0-beta.0) (2018-10-24)
### Bug Fixes
* **core:** allow null value for renderer setElement(…) ([#17065](https://github.com/angular/angular/issues/17065)) ([ff15043](https://github.com/angular/angular/commit/ff15043)), closes [#13686](https://github.com/angular/angular/issues/13686)
* **router:** fix regression where navigateByUrl promise didn't resolve on CanLoad failure ([#26455](https://github.com/angular/angular/issues/26455)) ([1c9b065](https://github.com/angular/angular/commit/1c9b065)), closes [#26284](https://github.com/angular/angular/issues/26284)
* **service-worker:** clean up caches from old SW versions ([#26319](https://github.com/angular/angular/issues/26319)) ([2326b9c](https://github.com/angular/angular/commit/2326b9c))
* **upgrade:** properly destroy upgraded component elements and descendants ([#26209](https://github.com/angular/angular/issues/26209)) ([071934e](https://github.com/angular/angular/commit/071934e)), closes [#26208](https://github.com/angular/angular/issues/26208)
### Features
* **router:** add prioritizedGuardValue operator optimization and allowing UrlTree return from guard ([#26478](https://github.com/angular/angular/issues/26478)) ([fdfedce](https://github.com/angular/angular/commit/fdfedce))
<a name="7.0.1"></a>
## [7.0.1](https://github.com/angular/angular/compare/7.0.0...7.0.1) (2018-10-24)
@ -91,6 +122,7 @@ To learn about the release highlights and our new CLI-powered update workflow fo
### Bug Fixes
* **platform-browser:** fix [#22155](https://github.com/angular/angular/issues/22155), destroy hammer manager when `HammerInstance.off()` is run ([#22156](https://github.com/angular/angular/issues/22156)) ([3b4d9dc](https://github.com/angular/angular/commit/3b4d9dc))
* **upgrade:** properly destroy upgraded component elements and descendants ([#26209](https://github.com/angular/angular/issues/26209)) ([623adbb](https://github.com/angular/angular/commit/623adbb)), closes [#26208](https://github.com/angular/angular/issues/26208)

View File

@ -10,7 +10,7 @@ describe('Security E2E Tests', () => {
expect(interpolated.getText())
.toContain('Template <script>alert("0wned")</script> <b>Syntax</b>');
let bound = element(By.className('e2e-inner-html-bound'));
expect(bound.getText()).toContain('Template alert("0wned") Syntax');
expect(bound.getText()).toContain('Template Syntax');
let bold = element(By.css('.e2e-inner-html-bound b'));
expect(bold.getText()).toContain('Syntax');
});

View File

@ -119,7 +119,7 @@ vulnerability. For example, code contained in a `<script>` tag is executed:
Angular recognizes the value as unsafe and automatically sanitizes it, which removes the `<script>`
tag but keeps safe content such as the text content of the `<script>` tag and the `<b>` element.
tag but keeps safe content such as the `<b>` element.
<figure>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import 'reflect-metadata';
import {ɵrenderComponent as renderComponent} from '@angular/core';
import {bindAction, profile} from '../../util';

View File

@ -1,21 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractor = require('protractor');
module.exports = function(config) {
return protractorUtils.runServer(config.workspace, config.server, '-port', [])
.then(serverSpec => {
const serverUrl = `http://localhost:${serverSpec.port}`;
// Since the browser restarts in this benchmark we need to set both the browser.baseUrl
// for the first test and the protractor config.baseUrl for the subsequent tests
protractor.browser.baseUrl = serverUrl;
return protractor.browser.getProcessedConfig().then((config) => config.baseUrl = serverUrl);
});
};

View File

@ -0,0 +1,22 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractor = require('protractor');
module.exports = async function(config) {
const serverSpec = await protractorUtils.runServer(config.workspace, config.server, '-port', []);
const serverUrl = `http://localhost:${serverSpec.port}`;
// Since the browser restarts in this benchmark we need to set both the browser.baseUrl
// for the first test and the protractor config.baseUrl for the subsequent tests
protractor.browser.baseUrl = serverUrl;
const processedConfig = await protractor.browser.getProcessedConfig();
return processedConfig.baseUrl = serverUrl;
};

View File

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

View File

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

View File

@ -5,15 +5,17 @@ load("//packages/bazel:index.bzl", "protractor_web_test")
load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver")
ng_module(
name = "render3_lib",
name = "tree_lib",
srcs = glob(
[
"**/*.ts",
],
),
tags = ["ivy-only"],
deps = [
"//modules/benchmarks/src/tree:util_lib",
"//packages:types",
"//packages/common",
"//packages/core",
"@ngdeps//reflect-metadata",
],
@ -61,6 +63,7 @@ protractor_web_test(
"ivy-only",
],
deps = [
"//modules/benchmarks/src/tree:perf_lib",
"@ngdeps//node-uuid",
"@ngdeps//protractor",
"@ngdeps//yargs",

View File

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

View File

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

View File

@ -0,0 +1,22 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
const protractorUtils = require('@angular/bazel/protractor-utils');
const protractor = require('protractor');
module.exports = async function(config) {
const serverSpec = await protractorUtils.runServer(config.workspace, config.server, '-port', []);
const serverUrl = `http://localhost:${serverSpec.port}`;
// Since the browser restarts in this benchmark we need to set both the browser.baseUrl
// for the first test and the protractor config.baseUrl for the subsequent tests
protractor.browser.baseUrl = serverUrl;
const processedConfig = await protractor.browser.getProcessedConfig();
return processedConfig.baseUrl = serverUrl;
};

View File

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

View File

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

View File

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

View File

@ -0,0 +1,101 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {$, browser} from 'protractor';
import {openBrowser} from '../../../e2e_util/e2e_util';
import {runBenchmark} from '../../../e2e_util/perf_util';
describe('benchmark render', () => {
it('should work for createDestroy', () => {
openTreeBenchmark();
$('#createDom').click();
expect($('#root').getText()).toContain('0');
$('#destroyDom').click();
expect($('#root').getText() as any).toEqual('');
});
it('should work for update', () => {
openTreeBenchmark();
$('#createDom').click();
$('#createDom').click();
expect($('#root').getText()).toContain('A');
});
it('should work for detectChanges', () => {
openTreeBenchmark();
$('#detectChanges').click();
expect($('#numberOfChecks').getText()).toContain('10');
});
});
describe('benchmarks', () => {
it('should work for createOnly', done => {
runTreeBenchmark({
id: 'createOnly',
prepare: () => $('#destroyDom').click(),
work: () => $('#createDom').click()
}).then(done, done.fail);
});
it('should work for destroy', done => {
runTreeBenchmark({
id: 'createOnly',
prepare: () => $('#createDom').click(),
work: () => $('#destroyDom').click()
}).then(done, done.fail);
});
it('should work for createDestroy', done => {
runTreeBenchmark({
id: 'createDestroy',
work: () => {
$('#destroyDom').click();
$('#createDom').click();
}
}).then(done, done.fail);
});
it('should work for update', done => {
runTreeBenchmark({id: 'update', work: () => $('#createDom').click()}).then(done, done.fail);
});
it('should work for detectChanges', done => {
runTreeBenchmark({
id: 'detectChanges',
work: () => $('#detectChanges').click(),
setup: () => $('#destroyDom').click()
}).then(done, done.fail);
});
});
function runTreeBenchmark({id, prepare, setup, work}:
{id: string; prepare ? () : void; setup ? () : void; work(): void;}) {
browser.rootEl = '#root';
return runBenchmark({
id: id,
url: '',
ignoreBrowserSynchronization: true,
params: [{name: 'depth', value: 11}],
work: work,
prepare: prepare,
setup: setup
});
}
function openTreeBenchmark() {
browser.rootEl = '#root';
openBrowser({
url: '',
ignoreBrowserSynchronization: true,
params: [{name: 'depth', value: 4}],
});
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -128,7 +128,7 @@ describe('Renderer', () => {
}));
expect(addDefinitionsSpy.calls.first().args[2])
.toEqual(
`A.ngDirectiveDef = ɵngcc0.ɵdefineDirective({ type: A, selectors: [["", "a", ""]], factory: function A_Factory(t) { return new (t || A)(); }, features: [ɵngcc0.ɵPublicFeature] });`);
`A.ngDirectiveDef = ɵngcc0.ɵdefineDirective({ type: A, selectors: [["", "a", ""]], factory: function A_Factory(t) { return new (t || A)(); } });`);
});
it('should call removeDecorators with the source code, a map of class decorators that have been analyzed',

View File

@ -118,6 +118,10 @@ export class ComponentDecoratorHandler implements
preserveWhitespaces = value;
}
const viewProviders: Expression|null = component.has('viewProviders') ?
new WrappedNodeExpr(component.get('viewProviders') !) :
null;
// Go through the root directories for this project, and select the one with the smallest
// relative path representation.
const filePath = node.getSourceFile().fileName;
@ -200,9 +204,9 @@ export class ComponentDecoratorHandler implements
// analyzed and the full compilation scope for the component can be realized.
pipes: EMPTY_MAP,
directives: EMPTY_MAP,
wrapDirectivesInClosure: false, //
wrapDirectivesAndPipesInClosure: false, //
animations,
viewProviders: null,
viewProviders
},
parsedTemplate: template.nodes,
},
@ -233,8 +237,8 @@ export class ComponentDecoratorHandler implements
const {pipes, containsForwardDecls} = scope;
const directives = new Map<string, Expression>();
scope.directives.forEach((meta, selector) => directives.set(selector, meta.directive));
const wrapDirectivesInClosure: boolean = !!containsForwardDecls;
metadata = {...metadata, directives, pipes, wrapDirectivesInClosure};
const wrapDirectivesAndPipesInClosure: boolean = !!containsForwardDecls;
metadata = {...metadata, directives, pipes, wrapDirectivesAndPipesInClosure};
}
const res = compileComponentFromMetadata(metadata, pool, makeBindingParser());

View File

@ -110,12 +110,14 @@ export function extractDirectiveMetadata(
// fields.
const inputsFromMeta = parseFieldToPropertyMapping(directive, 'inputs', reflector, checker);
const inputsFromFields = parseDecoratedFields(
filterToMembersWithDecorator(decoratedElements, 'Input', coreModule), reflector, checker);
filterToMembersWithDecorator(decoratedElements, 'Input', coreModule), reflector, checker,
resolveInput);
// And outputs.
const outputsFromMeta = parseFieldToPropertyMapping(directive, 'outputs', reflector, checker);
const outputsFromFields = parseDecoratedFields(
filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), reflector, checker);
filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), reflector, checker,
resolveOutput) as{[field: string]: string};
// Construct the list of queries.
const contentChildFromFields = queriesFromFields(
filterToMembersWithDecorator(decoratedElements, 'ContentChild', coreModule), reflector,
@ -146,6 +148,9 @@ export function extractDirectiveMetadata(
const host = extractHostBindings(directive, decoratedElements, reflector, checker, coreModule);
const providers: Expression|null =
directive.has('providers') ? new WrappedNodeExpr(directive.get('providers') !) : null;
// Determine if `ngOnChanges` is a lifecycle hook defined on the component.
const usesOnChanges = members.some(
member => !member.isStatic && member.kind === ClassMemberKind.Method &&
@ -176,8 +181,7 @@ export function extractDirectiveMetadata(
outputs: {...outputsFromMeta, ...outputsFromFields}, queries, selector,
type: new WrappedNodeExpr(clazz.name !),
typeArgumentCount: reflector.getGenericArityOfClass(clazz) || 0,
typeSourceSpan: null !, usesInheritance, exportAs,
providers: null,
typeSourceSpan: null !, usesInheritance, exportAs, providers
};
return {decoratedElements, decorator: directive, metadata};
}
@ -328,7 +332,9 @@ function parseFieldToPropertyMapping(
*/
function parseDecoratedFields(
fields: {member: ClassMember, decorators: Decorator[]}[], reflector: ReflectionHost,
checker: ts.TypeChecker) {
checker: ts.TypeChecker,
mapValueResolver: (publicName: string, internalName: string) =>
string | [string, string]): {[field: string]: string | [string, string]} {
return fields.reduce(
(results, field) => {
const fieldName = field.member.name;
@ -342,7 +348,7 @@ function parseDecoratedFields(
if (typeof property !== 'string') {
throw new Error(`Decorator argument must resolve to a string`);
}
results[fieldName] = property;
results[fieldName] = mapValueResolver(property, fieldName);
} else {
// Too many arguments.
throw new Error(
@ -351,7 +357,7 @@ function parseDecoratedFields(
});
return results;
},
{} as{[field: string]: string});
{} as{[field: string]: string | [string, string]});
}
function resolveInput(publicName: string, internalName: string): [string, string] {

View File

@ -64,18 +64,6 @@ export function getConstructorDependencies(
ErrorCode.PARAM_MISSING_TOKEN, param.nameNode,
`No suitable token for parameter ${param.name || idx} of class ${clazz.name!.text}`);
}
if (ts.isIdentifier(tokenExpr)) {
const importedSymbol = reflector.getImportOfIdentifier(tokenExpr);
if (importedSymbol !== null && importedSymbol.from === '@angular/core') {
switch (importedSymbol.name) {
case 'Injector':
resolved = R3ResolvedDependencyType.Injector;
break;
default:
// Leave as a Token or Attribute.
}
}
}
const token = new WrappedNodeExpr(tokenExpr);
useType.push({token, optional, self, skipSelf, host, resolved});
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -518,7 +518,10 @@ function tcbGetInputBindingExpressions(
// is desired. Invert `dir.inputs` into `propMatch` to create this map.
const propMatch = new Map<string, string>();
const inputs = dir.inputs;
Object.keys(inputs).forEach(key => propMatch.set(inputs[key] as string, key));
Object.keys(inputs).forEach(key => {
Array.isArray(inputs[key]) ? propMatch.set(inputs[key][0], key) :
propMatch.set(inputs[key] as string, key);
});
// Add a binding expression to the map for each input of the directive that has a
// matching binding.

View File

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

View File

@ -415,7 +415,6 @@ describe('compiler compliance', () => {
factory: function MyComponent_Factory(t){
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 0,
template: function MyComponent_Template(rf,ctx){
@ -470,7 +469,6 @@ describe('compiler compliance', () => {
type: ChildComponent,
selectors: [["child"]],
factory: function ChildComponent_Factory(t) { return new (t || ChildComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 0,
template: function ChildComponent_Template(rf, ctx) {
@ -485,8 +483,7 @@ describe('compiler compliance', () => {
SomeDirective.ngDirectiveDef = $r3$.ɵdefineDirective({
type: SomeDirective,
selectors: [["", "some-directive", ""]],
factory: function SomeDirective_Factory(t) {return new (t || SomeDirective)(); },
features: [$r3$.ɵPublicFeature]
factory: function SomeDirective_Factory(t) {return new (t || SomeDirective)(); }
});
`;
@ -498,7 +495,6 @@ describe('compiler compliance', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
vars: 0,
template: function MyComponent_Template(rf, ctx) {
@ -543,8 +539,7 @@ describe('compiler compliance', () => {
SomeDirective.ngDirectiveDef = $r3$.ɵdefineDirective({
type: SomeDirective,
selectors: [["div", "some-directive", "", 8, "foo", 3, "title", "", 9, "baz"]],
factory: function SomeDirective_Factory(t) {return new (t || SomeDirective)(); },
features: [$r3$.ɵPublicFeature]
factory: function SomeDirective_Factory(t) {return new (t || SomeDirective)(); }
});
`;
@ -553,8 +548,7 @@ describe('compiler compliance', () => {
OtherDirective.ngDirectiveDef = $r3$.ɵdefineDirective({
type: OtherDirective,
selectors: [["", 5, "span", "title", "", 9, "baz"]],
factory: function OtherDirective_Factory(t) {return new (t || OtherDirective)(); },
features: [$r3$.ɵPublicFeature]
factory: function OtherDirective_Factory(t) {return new (t || OtherDirective)(); }
});
`;
@ -590,8 +584,7 @@ describe('compiler compliance', () => {
hostBindings: function HostBindingDir_HostBindings(dirIndex, elIndex) {
$r3$.ɵelementProperty(elIndex, "id", $r3$.ɵbind($r3$.ɵload(dirIndex).dirId));
},
hostVars: 1,
features: [$r3$.ɵPublicFeature]
hostVars: 1
});
`;
@ -635,7 +628,6 @@ describe('compiler compliance', () => {
$r3$.ɵelementProperty(elIndex, "id", $r3$.ɵbind($r3$.ɵpureFunction1(1, $ff$, $r3$.ɵload(dirIndex).id)));
},
hostVars: 3,
features: [$r3$.ɵPublicFeature],
consts: 0,
vars: 0,
template: function HostBindingComp_Template(rf, ctx) {}
@ -679,7 +671,6 @@ describe('compiler compliance', () => {
$r3$.ɵdirectiveInject(ElementRef), $r3$.ɵdirectiveInject(ViewContainerRef),
$r3$.ɵdirectiveInject(ChangeDetectorRef));
},
features: [$r3$.ɵPublicFeature],
consts: 0,
vars: 0,
template: function MyComponent_Template(rf, ctx) {}
@ -720,8 +711,7 @@ describe('compiler compliance', () => {
IfDirective.ngDirectiveDef = $r3$.ɵdefineDirective({
type: IfDirective,
selectors: [["", "if", ""]],
factory: function IfDirective_Factory(t) { return new (t || IfDirective)($r3$.ɵdirectiveInject(TemplateRef)); },
features: [$r3$.ɵPublicFeature]
factory: function IfDirective_Factory(t) { return new (t || IfDirective)($r3$.ɵdirectiveInject(TemplateRef)); }
});`;
const MyComponentDefinition = `
const $c1$ = ["foo", ""];
@ -743,7 +733,6 @@ describe('compiler compliance', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 3,
vars: 0,
template: function MyComponent_Template(rf, ctx) {
@ -806,7 +795,6 @@ describe('compiler compliance', () => {
type: MyApp,
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 3,
template: function MyApp_Template(rf, ctx) {
@ -888,7 +876,6 @@ describe('compiler compliance', () => {
type: MyApp,
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 11,
template: function MyApp_Template(rf, ctx) {
@ -952,7 +939,6 @@ describe('compiler compliance', () => {
type: MyApp,
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 3,
template: function MyApp_Template(rf, ctx) {
@ -1020,7 +1006,6 @@ describe('compiler compliance', () => {
type: MyApp,
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 8,
template: function MyApp_Template(rf, ctx) {
@ -1079,7 +1064,6 @@ describe('compiler compliance', () => {
type: SimpleComponent,
selectors: [["simple"]],
factory: function SimpleComponent_Factory(t) { return new (t || SimpleComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
vars: 0,
template: function SimpleComponent_Template(rf, ctx) {
@ -1102,7 +1086,6 @@ describe('compiler compliance', () => {
type: ComplexComponent,
selectors: [["complex"]],
factory: function ComplexComponent_Factory(t) { return new (t || ComplexComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 4,
vars: 0,
template: function ComplexComponent_Template(rf, ctx) {
@ -1171,7 +1154,6 @@ describe('compiler compliance', () => {
type: ViewQueryComponent,
selectors: [["view-query-component"]],
factory: function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); },
features: [$r3$.ɵPublicFeature],
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
if (rf & 1) {
$r3$.ɵquery(0, SomeDirective, true);
@ -1348,9 +1330,9 @@ describe('compiler compliance', () => {
factory: function ContentQueryComponent_Factory(t) {
return new (t || ContentQueryComponent)();
},
contentQueries: function ContentQueryComponent_ContentQueries() {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, true));
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false));
contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, true), dirIndex);
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false), dirIndex);
},
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
const instance = $r3$.ɵload(dirIndex);
@ -1358,7 +1340,6 @@ describe('compiler compliance', () => {
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && ($instance$.someDir = $tmp$.first));
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && ($instance$.someDirList = $tmp$));
},
features: [$r3$.ɵPublicFeature],
consts: 2,
vars: 0,
template: function ContentQueryComponent_Template(rf, ctx) {
@ -1406,9 +1387,9 @@ describe('compiler compliance', () => {
ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
contentQueries: function ContentQueryComponent_ContentQueries() {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e0_attrs$, true));
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e1_attrs$, false));
contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e0_attrs$, true), dirIndex);
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e1_attrs$, false), dirIndex);
},
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
const instance = $r3$.ɵload(dirIndex);
@ -1459,11 +1440,11 @@ describe('compiler compliance', () => {
ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
contentQueries: function ContentQueryComponent_ContentQueries() {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e0_attrs$ , true, TemplateRef));
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, true, ElementRef));
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e1_attrs$, false, ElementRef));
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false, TemplateRef));
contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) {
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e0_attrs$ , true, TemplateRef), dirIndex);
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, true, ElementRef), dirIndex);
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e1_attrs$, false, ElementRef), dirIndex);
$r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false, TemplateRef), dirIndex);
},
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
const instance = $r3$.ɵload(dirIndex);
@ -1492,7 +1473,7 @@ describe('compiler compliance', () => {
app: {
'spec.ts': `
import {Component, NgModule, Pipe, PipeTransform, OnDestroy} from '@angular/core';
@Pipe({
name: 'myPipe',
pure: false
@ -1502,7 +1483,7 @@ describe('compiler compliance', () => {
transform(value: any, ...args: any[]) { return value; }
ngOnDestroy(): void { }
}
@Pipe({
name: 'myPurePipe',
pure: true,
@ -1510,7 +1491,7 @@ describe('compiler compliance', () => {
export class MyPurePipe implements PipeTransform {
transform(value: any, ...args: any[]) { return value; }
}
@Component({
selector: 'my-app',
template: '{{name | myPipe:size | myPurePipe:size }}<p>{{ name | myPipe:1:2:3:4:5 }}</p>'
@ -1519,7 +1500,7 @@ describe('compiler compliance', () => {
name = 'World';
size = 0;
}
@NgModule({declarations:[MyPipe, MyPurePipe, MyApp]})
export class MyModule {}
`
@ -1552,7 +1533,6 @@ describe('compiler compliance', () => {
type: MyApp,
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 6,
vars: 17,
template: function MyApp_Template(rf, ctx) {
@ -1586,7 +1566,7 @@ describe('compiler compliance', () => {
app: {
'spec.ts': `
import {Component, NgModule, Pipe, PipeTransform, OnDestroy} from '@angular/core';
@Pipe({
name: 'myPipe',
pure: false
@ -1596,14 +1576,14 @@ describe('compiler compliance', () => {
transform(value: any, ...args: any[]) { return value; }
ngOnDestroy(): void { }
}
@Component({
selector: 'my-app',
template: '0:{{name | myPipe}}1:{{name | myPipe:1}}2:{{name | myPipe:1:2}}3:{{name | myPipe:1:2:3}}4:{{name | myPipe:1:2:3:4}}'
})
export class MyApp {
}
@NgModule({declarations:[MyPipe, MyApp]})
export class MyModule {}
`
@ -1616,7 +1596,6 @@ describe('compiler compliance', () => {
type: MyApp,
selectors: [["my-app"]],
factory: function MyApp_Factory(t) { return new (t || MyApp)(); },
features: [$r3$.ɵPublicFeature],
consts: 6,
vars: 27,
template: function MyApp_Template(rf, ctx) {
@ -1630,8 +1609,8 @@ describe('compiler compliance', () => {
}
if (rf & 2) {
$r3$.ɵtextBinding(0, $r3$.ɵinterpolation5(
"0:", i0.ɵpipeBind1(1, 5, ctx.name),
"1:", i0.ɵpipeBind2(2, 7, ctx.name, 1),
"0:", i0.ɵpipeBind1(1, 5, ctx.name),
"1:", i0.ɵpipeBind2(2, 7, ctx.name, 1),
"2:", i0.ɵpipeBind3(3, 10, ctx.name, 1, 2),
"3:", i0.ɵpipeBind4(4, 14, ctx.name, 1, 2, 3),
"4:", i0.ɵpipeBindV(5, 19, $r3$.ɵpureFunction1(25, $c0$, ctx.name)),
@ -1671,7 +1650,6 @@ describe('compiler compliance', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 3,
vars: 1,
template: function MyComponent_Template(rf, ctx) {
@ -1765,7 +1743,6 @@ describe('compiler compliance', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 6,
vars: 1,
template: function MyComponent_Template(rf, ctx) {
@ -1910,8 +1887,8 @@ describe('compiler compliance', () => {
type: LifecycleComp,
selectors: [["lifecycle-comp"]],
factory: function LifecycleComp_Factory(t) { return new (t || LifecycleComp)(); },
inputs: {nameMin: "name"},
features: [$r3$PublicFeature, $r3$NgOnChangesFeature],
inputs: {nameMin: ["name", "nameMin"]},
features: [$r3$.ɵNgOnChangesFeature],
consts: 0,
vars: 0,
template: function LifecycleComp_Template(rf, ctx) {}
@ -1922,7 +1899,6 @@ describe('compiler compliance', () => {
type: SimpleLayout,
selectors: [["simple-layout"]],
factory: function SimpleLayout_Factory(t) { return new (t || SimpleLayout)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
vars: 2,
template: function SimpleLayout_Template(rf, ctx) {
@ -2032,7 +2008,7 @@ describe('compiler compliance', () => {
factory: function ForOfDirective_Factory(t) {
return new (t || ForOfDirective)($r3$.ɵdirectiveInject(ViewContainerRef), $r3$.ɵdirectiveInject(TemplateRef));
},
features: [$r3$PublicFeature, $r3$NgOnChangesFeature],
features: [$r3$.ɵNgOnChangesFeature],
inputs: {forOf: "forOf"}
});
`;
@ -2052,7 +2028,6 @@ describe('compiler compliance', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
vars: 1,
template: function MyComponent_Template(rf, ctx){
@ -2108,7 +2083,7 @@ describe('compiler compliance', () => {
factory: function ForOfDirective_Factory(t) {
return new (t || ForOfDirective)($r3$.ɵdirectiveInject(ViewContainerRef), $r3$.ɵdirectiveInject(TemplateRef));
},
features: [$r3$PublicFeature, $r3$NgOnChangesFeature],
features: [$r3$.ɵNgOnChangesFeature],
inputs: {forOf: "forOf"}
});
`;
@ -2131,7 +2106,6 @@ describe('compiler compliance', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
vars: 1,
template: function MyComponent_Template(rf, ctx) {
@ -2231,7 +2205,6 @@ describe('compiler compliance', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 2,
vars: 1,
template: function MyComponent_Template(rf, ctx) {
@ -2252,9 +2225,83 @@ describe('compiler compliance', () => {
expectEmit(source, MyComponentDefinition, 'Invalid component definition');
});
});
it('should instantiate directives in a closure when they are forward referenced', () => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule, Directive} from '@angular/core';
@Component({
selector: 'host-binding-comp',
template: \`
<my-forward-directive></my-forward-directive>
\`
})
export class HostBindingComp {
}
@Directive({
selector: 'my-forward-directive'
})
class MyForwardDirective {}
@NgModule({declarations: [HostBindingComp, MyForwardDirective]})
export class MyModule {}
`
}
};
const MyAppDefinition = `
directives: function () { return [MyForwardDirective]; }
`;
const result = compile(files, angularFiles);
const source = result.source;
expectEmit(source, MyAppDefinition, 'Invalid component definition');
});
it('should instantiate pipes in a closure when they are forward referenced', () => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule, Pipe} from '@angular/core';
@Component({
selector: 'host-binding-comp',
template: \`
<div [attr.style]="{} | my_forward_pipe">...</div>
\`
})
export class HostBindingComp {
}
@Pipe({
name: 'my_forward_pipe'
})
class MyForwardPipe {}
@NgModule({declarations: [HostBindingComp, MyForwardPipe]})
export class MyModule {}
`
}
};
const MyAppDefinition = `
pipes: function () { return [MyForwardPipe]; }
`;
const result = compile(files, angularFiles);
const source = result.source;
expectEmit(source, MyAppDefinition, 'Invalid component definition');
});
});
describe('inherited bare classes', () => {
describe('inherited base classes', () => {
it('should add ngBaseDef if one or more @Input is present', () => {
const files = {
app: {

View File

@ -42,7 +42,6 @@ describe('compiler compliance: directives', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 0,
template: function MyComponent_Template(rf, ctx) {
@ -88,7 +87,6 @@ describe('compiler compliance: directives', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 0,
template: function MyComponent_Template(rf, ctx) {

View File

@ -56,7 +56,7 @@ describe('compiler compliance: listen()', () => {
inputs:{
componentInput: "componentInput",
originalComponentInput: "renamedComponentInput"
originalComponentInput: ["renamedComponentInput", "originalComponentInput"]
},
outputs: {
componentOutput: "componentOutput",
@ -70,7 +70,7 @@ describe('compiler compliance: listen()', () => {
inputs:{
directiveInput: "directiveInput",
originalDirectiveInput: "renamedDirectiveInput"
originalDirectiveInput: ["renamedDirectiveInput", "originalDirectiveInput"]
},
outputs: {
directiveOutput: "directiveOutput",
@ -86,4 +86,4 @@ describe('compiler compliance: listen()', () => {
expectEmit(result.source, directiveDef, 'Incorrect directive definition');
});
});
});

View File

@ -202,7 +202,6 @@ describe('compiler compliance: listen()', () => {
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); },
features: [$r3$.ɵPublicFeature],
consts: 4,
vars: 0,
template: function MyComponent_Template(rf, ctx) {

View File

@ -0,0 +1,152 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {setup} from '@angular/compiler/test/aot/test_util';
import {compile, expectEmit} from './mock_compile';
describe('compiler compliance: providers', () => {
const angularFiles = setup({
compileAngular: false,
compileFakeCore: true,
compileAnimations: false,
});
it('should emit the ProvidersFeature feature when providers and viewProviders', () => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule} from '@angular/core';
abstract class Greeter { abstract greet(): string; }
class GreeterEN implements Greeter {
greet() { return 'Hi'; }
}
@Component({
selector: 'my-component',
template: '<div></div>',
providers: [GreeterEN, {provide: Greeter, useClass: GreeterEN}],
viewProviders: [GreeterEN]
})
export class MyComponent {
}
@NgModule({declarations: [MyComponent]})
export class MyModule {}
`
}
};
const result = compile(files, angularFiles);
expectEmit(
result.source,
'features: [i0.ɵProvidersFeature([GreeterEN, {provide: Greeter, useClass: GreeterEN}], [GreeterEN])],',
'Incorrect features');
});
it('should emit the ProvidersFeature feature when providers only', () => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule} from '@angular/core';
abstract class Greeter { abstract greet(): string; }
class GreeterEN implements Greeter {
greet() { return 'Hi'; }
}
@Component({
selector: 'my-component',
template: '<div></div>',
providers: [GreeterEN, {provide: Greeter, useClass: GreeterEN}]
})
export class MyComponent {
}
@NgModule({declarations: [MyComponent]})
export class MyModule {}
`
}
};
const result = compile(files, angularFiles);
expectEmit(
result.source,
'features: [i0.ɵProvidersFeature([GreeterEN, {provide: Greeter, useClass: GreeterEN}])],',
'Incorrect features');
});
it('should emit the ProvidersFeature feature when viewProviders only', () => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule} from '@angular/core';
abstract class Greeter { abstract greet(): string; }
class GreeterEN implements Greeter {
greet() { return 'Hi'; }
}
@Component({
selector: 'my-component',
template: '<div></div>',
viewProviders: [GreeterEN]
})
export class MyComponent {
}
@NgModule({declarations: [MyComponent]})
export class MyModule {}
`
}
};
const result = compile(files, angularFiles);
expectEmit(
result.source, 'features: [i0.ɵProvidersFeature([], [GreeterEN])],', 'Incorrect features');
});
it('should not emit the ProvidersFeature feature when no providers', () => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule} from '@angular/core';
abstract class Greeter { abstract greet(): string; }
class GreeterEN implements Greeter {
greet() { return 'Hi'; }
}
@Component({
selector: 'my-component',
template: '<div></div>'
})
export class MyComponent {
}
@NgModule({declarations: [MyComponent]})
export class MyModule {}
`
}
};
const result = compile(files, angularFiles);
expectEmit(
result.source, `
export class MyComponent {
}
MyComponent.ngComponentDef = i0.ɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 1, vars: 0, template: function MyComponent_Template(rf, ctx) { if (rf & 1) {
i0.ɵelement(0, "div");
} } });`,
'Incorrect features');
});
});

View File

@ -128,7 +128,6 @@ describe('compiler compliance: styling', () => {
factory:function MyComponent_Factory(t){
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 0,
vars: 0,
template: function MyComponent_Template(rf, $ctx$) {
@ -170,7 +169,6 @@ describe('compiler compliance: styling', () => {
factory:function MyComponent_Factory(t){
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 0,
vars: 0,
template: function MyComponent_Template(rf, $ctx$) {
@ -308,7 +306,6 @@ describe('compiler compliance: styling', () => {
factory:function MyComponent_Factory(t){
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 1,
template: function MyComponent_Template(rf, $ctx$) {
@ -367,7 +364,6 @@ describe('compiler compliance: styling', () => {
factory: function MyComponent_Factory(t) {
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 0,
template: function MyComponent_Template(rf, ctx) {
@ -506,7 +502,6 @@ describe('compiler compliance: styling', () => {
factory:function MyComponent_Factory(t){
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 1,
template: function MyComponent_Template(rf, $ctx$) {
@ -563,7 +558,6 @@ describe('compiler compliance: styling', () => {
factory:function MyComponent_Factory(t){
return new (t || MyComponent)();
},
features: [$r3$.ɵPublicFeature],
consts: 1,
vars: 2,
template: function MyComponent_Template(rf, $ctx$) {
@ -625,5 +619,103 @@ describe('compiler compliance: styling', () => {
expectEmit(result.source, template, 'Incorrect template');
});
it('should stamp out pipe definitions in the creation block if used by styling bindings',
() => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule} from '@angular/core';
@Component({
selector: 'my-component',
template: \`<div [style]="myStyleExp | stylePipe" [class]="myClassExp | classPipe"></div>\`
})
export class MyComponent {
myStyleExp = [{color:'red'}, {color:'blue', duration:1000}]
myClassExp = 'foo bar apple';
}
@NgModule({declarations: [MyComponent]})
export class MyModule {}
`
}
};
const template = `
template: function MyComponent_Template(rf, $ctx$) {
if (rf & 1) {
$r3$.ɵelementStart(0, "div");
$r3$.ɵelementStyling(null, null, $r3$.ɵdefaultStyleSanitizer);
$r3$.ɵpipe(1, "classPipe");
$r3$.ɵpipe(2, "stylePipe");
$r3$.ɵelementEnd();
}
if (rf & 2) {
$r3$.ɵelementStylingMap(0, $r3$.ɵpipeBind1(1, 0, $ctx$.myClassExp), $r3$.ɵpipeBind1(2, 2, $ctx$.myStyleExp));
$r3$.ɵelementStylingApply(0);
}
}
`;
const result = compile(files, angularFiles);
expectEmit(result.source, template, 'Incorrect template');
});
it('should properly offset multiple style pipe references for styling bindings', () => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule} from '@angular/core';
@Component({
selector: 'my-component',
template: \`
<div [class]="{}"
[class.foo]="fooExp | pipe:2000"
[style]="myStyleExp | pipe:1000"
[style.bar]="barExp | pipe:3000"
[style.baz]="bazExp | pipe:4000">
{{ item }}</div>\`
})
export class MyComponent {
myStyleExp = {};
fooExp = 'foo';
barExp = 'bar';
bazExp = 'baz';
items = [1,2,3];
}
@NgModule({declarations: [MyComponent]})
export class MyModule {}
`
}
};
const template = `
template: function MyComponent_Template(rf, $ctx$) {
if (rf & 1) {
$r3$.ɵelementStart(0, "div");
$r3$.ɵelementStyling($e0_styling$, $e1_styling$, $r3$.ɵdefaultStyleSanitizer);
$r3$.ɵpipe(1, "pipe");
$r3$.ɵpipe(2, "pipe");
$r3$.ɵpipe(3, "pipe");
$r3$.ɵpipe(4, "pipe");
$r3$.ɵtext(5);
$r3$.ɵelementEnd();
}
if (rf & 2) {
$r3$.ɵelementStylingMap(0, $e2_styling$, $r3$.ɵpipeBind2(1, 1, $ctx$.myStyleExp, 1000));
$r3$.ɵelementStyleProp(0, 0, $r3$.ɵpipeBind2(2, 4, $ctx$.barExp, 3000));
$r3$.ɵelementStyleProp(0, 1, $r3$.ɵpipeBind2(3, 7, $ctx$.bazExp, 4000));
$r3$.ɵelementClassProp(0, 0, $r3$.ɵpipeBind2(4, 10, $ctx$.fooExp, 2000));
$r3$.ɵelementStylingApply(0);
$r3$.ɵtextBinding(5, $r3$.ɵinterpolation1(" ", $ctx$.item, ""));
}
}
`;
const result = compile(files, angularFiles);
expectEmit(result.source, template, 'Incorrect template');
});
});
});

View File

@ -380,7 +380,7 @@ describe('ngtsc behavioral tests', () => {
const jsContents = env.getContents('test.js');
expect(jsContents)
.toContain(
`factory: function FooCmp_Factory(t) { return new (t || FooCmp)(i0.ɵinjectAttribute("test"), i0.ɵdirectiveInject(ChangeDetectorRef), i0.ɵdirectiveInject(ElementRef), i0.ɵdirectiveInject(i0.INJECTOR), i0.ɵdirectiveInject(Renderer2), i0.ɵdirectiveInject(TemplateRef), i0.ɵdirectiveInject(ViewContainerRef)); }`);
`factory: function FooCmp_Factory(t) { return new (t || FooCmp)(i0.ɵinjectAttribute("test"), i0.ɵdirectiveInject(ChangeDetectorRef), i0.ɵdirectiveInject(ElementRef), i0.ɵdirectiveInject(Injector), i0.ɵdirectiveInject(Renderer2), i0.ɵdirectiveInject(TemplateRef), i0.ɵdirectiveInject(ViewContainerRef)); }`);
});
it('should generate queries for components', () => {
@ -469,7 +469,7 @@ describe('ngtsc behavioral tests', () => {
@HostBinding('class.someclass')
get someClass(): boolean { return false; }
@HostListener('onChange', ['arg'])
@HostListener('change', ['arg1', 'arg2', 'arg3'])
onChange(event: any, arg: any): void {}
}
`);
@ -483,8 +483,51 @@ describe('ngtsc behavioral tests', () => {
expect(jsContents)
.toContain(
'i0.ɵelementProperty(elIndex, "class.someclass", i0.ɵbind(i0.ɵload(dirIndex).someClass))');
expect(jsContents).toContain('i0.ɵload(dirIndex).onClick($event)');
expect(jsContents).toContain('i0.ɵload(dirIndex).onChange(i0.ɵload(dirIndex).arg)');
const factoryDef = `
factory: function FooCmp_Factory(t) {
var f = new (t || FooCmp)();
i0.ɵlistener("click", function FooCmp_click_HostBindingHandler($event) {
return f.onClick($event);
});
i0.ɵlistener("change", function FooCmp_change_HostBindingHandler($event) {
return f.onChange(f.arg1, f.arg2, f.arg3);
});
return f;
}
`;
expect(jsContents).toContain(factoryDef.replace(/\s+/g, ' ').trim());
});
it('should generate host listeners for directives with base factories', () => {
env.tsconfig();
env.write(`test.ts`, `
import {Directive, HostListener} from '@angular/core';
class Base {}
@Directive({
selector: '[test]',
})
class Dir extends Base {
@HostListener('change', ['arg'])
onChange(event: any, arg: any): void {}
}
`);
env.driveMain();
const jsContents = env.getContents('test.js');
const factoryDef = `
factory: function Dir_Factory(t) {
var f = ɵDir_BaseFactory((t || Dir));
i0.ɵlistener("change", function Dir_change_HostBindingHandler($event) {
return f.onChange(f.arg);
});
return f;
}
`;
expect(jsContents).toContain(factoryDef.replace(/\s+/g, ' ').trim());
expect(jsContents).toContain('var ɵDir_BaseFactory = i0.ɵgetInheritedFactory(Dir)');
});
it('should correctly recognize local symbols', () => {
@ -572,6 +615,38 @@ describe('ngtsc behavioral tests', () => {
expect(emptyFactory).toContain(`export var ɵNonEmptyModule = true;`);
});
it('should generate a summary stub for decorated classes in the input file only', () => {
env.tsconfig({'allowEmptyCodegenFiles': true});
env.write('test.ts', `
import {Injectable, NgModule} from '@angular/core';
export class NotAModule {}
@NgModule({})
export class TestModule {}
`);
env.driveMain();
const summaryContents = env.getContents('test.ngsummary.js');
expect(summaryContents).toEqual(`export var TestModuleNgSummary = null;\n`);
});
it('it should generate empty export when there are no other summary symbols, to ensure the output is a valid ES module',
() => {
env.tsconfig({'allowEmptyCodegenFiles': true});
env.write('empty.ts', `
export class NotAModule {}
`);
env.driveMain();
const emptySummary = env.getContents('empty.ngsummary.js');
// The empty export ensures this js file is still an ES module.
expect(emptySummary).toEqual(`export var ɵempty = null;\n`);
});
it('should compile a banana-in-a-box inside of a template', () => {
env.tsconfig();
env.write('test.ts', `

View File

@ -56,7 +56,6 @@ export type Provider = any;
export enum R3ResolvedDependencyType {
Token = 0,
Attribute = 1,
Injector = 2,
}
export interface R3DependencyMetadataFacade {

View File

@ -42,6 +42,7 @@ export function compileInjectable(meta: R3InjectableMetadata): InjectableDef {
type: meta.type,
deps: meta.ctorDeps,
injectFn: Identifiers.inject,
extraStatementFn: null,
};
if (meta.useClass !== undefined) {

View File

@ -120,7 +120,7 @@ export class CompilerFacadeImpl implements CompilerFacade {
...convertDirectiveFacadeToMetadata(facade),
template,
viewQueries: facade.viewQueries.map(convertToR3QueryMetadata),
wrapDirectivesInClosure: false,
wrapDirectivesAndPipesInClosure: false,
styles: facade.styles || [],
encapsulation: facade.encapsulation as any,
animations: facade.animations != null ? new WrappedNodeExpr(facade.animations) : null,

View File

@ -49,6 +49,11 @@ export interface R3ConstructorFactoryMetadata {
* function could be different, and other options control how it will be invoked.
*/
injectFn: o.ExternalReference;
/**
* Function that allows extra statements to be inserted into factory function.
*/
extraStatementFn: ((instance: o.Expression) => o.Statement[])|null;
}
export enum R3FactoryDelegateType {
@ -95,11 +100,6 @@ export enum R3ResolvedDependencyType {
* The token expression is a string representing the attribute name.
*/
Attribute = 1,
/**
* The dependency is for the `Injector` type itself.
*/
Injector = 2,
}
/**
@ -194,8 +194,7 @@ export function compileFactoryFunction(meta: R3FactoryMetadata):
]);
statements.push(delegateFactoryStmt);
const r = makeConditionalFactory(delegateFactory.callFn([]));
retExpr = r;
retExpr = makeConditionalFactory(delegateFactory.callFn([]));
} else if (isDelegatedMetadata(meta)) {
// This type is created with a delegated factory. If a type parameter is not specified, call
// the factory instead.
@ -209,10 +208,22 @@ export function compileFactoryFunction(meta: R3FactoryMetadata):
} else if (isExpressionFactoryMetadata(meta)) {
// TODO(alxhub): decide whether to lower the value here or in the caller
retExpr = makeConditionalFactory(meta.expression);
} else if (meta.extraStatementFn) {
// if extraStatementsFn is specified and the 'makeConditionalFactory' function
// was not invoked, we need to create a reference to the instance, so we can
// pass it as an argument to the 'extraStatementFn' function while calling it
const variable = o.variable('f');
body.push(variable.set(ctorExpr).toDeclStmt());
retExpr = variable;
} else {
retExpr = ctorExpr;
}
if (meta.extraStatementFn) {
const extraStmts = meta.extraStatementFn(retExpr);
body.push(...extraStmts);
}
return {
factory: o.fn(
[new o.FnParam('t', o.DYNAMIC_TYPE)], [...body, new o.ReturnStatement(retExpr)],
@ -230,22 +241,14 @@ function compileInjectDependency(
dep: R3DependencyMetadata, injectFn: o.ExternalReference): o.Expression {
// Interpret the dependency according to its resolved type.
switch (dep.resolved) {
case R3ResolvedDependencyType.Token:
case R3ResolvedDependencyType.Injector: {
case R3ResolvedDependencyType.Token: {
// Build up the injection flags according to the metadata.
const flags = InjectFlags.Default | (dep.self ? InjectFlags.Self : 0) |
(dep.skipSelf ? InjectFlags.SkipSelf : 0) | (dep.host ? InjectFlags.Host : 0) |
(dep.optional ? InjectFlags.Optional : 0);
// Determine the token used for injection. In almost all cases this is the given token, but
// if the dependency is resolved to the `Injector` then the special `INJECTOR` token is used
// instead.
let token: o.Expression = dep.token;
if (dep.resolved === R3ResolvedDependencyType.Injector) {
token = o.importExpr(Identifiers.INJECTOR);
}
// Build up the arguments to the injectFn call.
const injectArgs = [token];
const injectArgs = [dep.token];
// If this dependency is optional or otherwise has non-default flags, then additional
// parameters describing how to inject the dependency must be passed to the inject function
// that's being used.
@ -280,12 +283,9 @@ export function dependenciesFromGlobalMetadata(
for (let dependency of type.diDeps) {
if (dependency.token) {
const tokenRef = tokenReference(dependency.token);
let resolved: R3ResolvedDependencyType = R3ResolvedDependencyType.Token;
if (tokenRef === injectorRef) {
resolved = R3ResolvedDependencyType.Injector;
} else if (dependency.isAttribute) {
resolved = R3ResolvedDependencyType.Attribute;
}
let resolved: R3ResolvedDependencyType = dependency.isAttribute ?
R3ResolvedDependencyType.Attribute :
R3ResolvedDependencyType.Token;
// In the case of most dependencies, the token will be a reference to a type. Sometimes,
// however, it can be a string, in the case of older Angular code or @Attribute injection.

View File

@ -175,7 +175,7 @@ export class Identifiers {
static InheritDefinitionFeature:
o.ExternalReference = {name: 'ɵInheritDefinitionFeature', moduleName: CORE};
static PublicFeature: o.ExternalReference = {name: 'ɵPublicFeature', moduleName: CORE};
static ProvidersFeature: o.ExternalReference = {name: 'ɵProvidersFeature', moduleName: CORE};
static listener: o.ExternalReference = {name: 'ɵlistener', moduleName: CORE};

View File

@ -101,6 +101,7 @@ export function compileInjector(meta: R3InjectorMetadata): R3InjectorDef {
type: meta.type,
deps: meta.deps,
injectFn: R3.inject,
extraStatementFn: null,
});
const expression = o.importExpr(R3.defineInjector).callFn([mapToMapExpression({
factory: result.factory,
@ -151,4 +152,4 @@ function accessExportScope(module: o.Expression): o.Expression {
function tupleTypeOf(exp: R3Reference[]): o.Type {
const types = exp.map(ref => o.typeofExpr(ref.type));
return exp.length > 0 ? o.expressionType(o.literalArr(types)) : o.NONE_TYPE;
}
}

View File

@ -43,6 +43,7 @@ export function compilePipeFromMetadata(metadata: R3PipeMetadata) {
type: metadata.type,
deps: metadata.deps,
injectFn: R3.directiveInject,
extraStatementFn: null,
});
definitionMapValues.push({key: 'factory', value: templateFactory.factory, quoted: false});

View File

@ -159,11 +159,11 @@ export interface R3ComponentMetadata extends R3DirectiveMetadata {
directives: Map<string, o.Expression>;
/**
* Whether to wrap the 'directives' array, if one is generated, in a closure.
* Whether to wrap the 'directives' and/or `pipes` array, if one is generated, in a closure.
*
* This is done when the directives contain forward references.
* This is done when the directives or pipes contain forward references.
*/
wrapDirectivesInClosure: boolean;
wrapDirectivesAndPipesInClosure: boolean;
/**
* A collection of styling data that will be applied and scoped to the component.
@ -217,8 +217,8 @@ export interface R3QueryMetadata {
descendants: boolean;
/**
* An expression representing a type to read from each matched node, or null if the node itself
* is to be returned.
* An expression representing a type to read from each matched node, or null if the default value
* for a given node is to be returned.
*/
read: o.Expression|null;
}

View File

@ -12,6 +12,7 @@ import {CompileReflector} from '../../compile_reflector';
import {BindingForm, convertActionBinding, convertPropertyBinding} from '../../compiler_util/expression_converter';
import {ConstantPool, DefinitionKind} from '../../constant_pool';
import * as core from '../../core';
import {ParsedEvent} from '../../expression_parser/ast';
import {LifecycleHooks} from '../../lifecycle_reflector';
import * as o from '../../output/output_ast';
import {typeSourceSpan} from '../../parse_util';
@ -49,6 +50,7 @@ function baseDirectiveFields(
type: meta.type,
deps: meta.deps,
injectFn: R3.directiveInject,
extraStatementFn: createFactoryExtraStatementsFn(meta, bindingParser)
});
definitionMap.set('factory', result.factory);
@ -82,11 +84,30 @@ function baseDirectiveFields(
// e.g 'outputs: {a: 'a'}`
definitionMap.set('outputs', conditionallyCreateMapObjectLiteral(meta.outputs));
if (meta.exportAs !== null) {
definitionMap.set('exportAs', o.literal(meta.exportAs));
}
return {definitionMap, statements: result.statements};
}
/**
* Add features to the definition map.
*/
function addFeatures(
definitionMap: DefinitionMap, meta: R3DirectiveMetadata | R3ComponentMetadata) {
// e.g. `features: [NgOnChangesFeature]`
const features: o.Expression[] = [];
// TODO: add `PublicFeature` so that directives get registered to the DI - make this configurable
features.push(o.importExpr(R3.PublicFeature));
const providers = meta.providers;
const viewProviders = (meta as R3ComponentMetadata).viewProviders;
if (providers || viewProviders) {
const args = [providers || new o.LiteralArrayExpr([])];
if (viewProviders) {
args.push(viewProviders);
}
features.push(o.importExpr(R3.ProvidersFeature).callFn(args));
}
if (meta.usesInheritance) {
features.push(o.importExpr(R3.InheritDefinitionFeature));
@ -97,11 +118,6 @@ function baseDirectiveFields(
if (features.length) {
definitionMap.set('features', o.literalArr(features));
}
if (meta.exportAs !== null) {
definitionMap.set('exportAs', o.literal(meta.exportAs));
}
return {definitionMap, statements: result.statements};
}
/**
@ -111,6 +127,7 @@ export function compileDirectiveFromMetadata(
meta: R3DirectiveMetadata, constantPool: ConstantPool,
bindingParser: BindingParser): R3DirectiveDef {
const {definitionMap, statements} = baseDirectiveFields(meta, constantPool, bindingParser);
addFeatures(definitionMap, meta);
const expression = o.importExpr(R3.defineDirective).callFn([definitionMap.toLiteralMap()]);
// On the type side, remove newlines from the selector as it will need to fit into a TypeScript
@ -164,6 +181,7 @@ export function compileComponentFromMetadata(
meta: R3ComponentMetadata, constantPool: ConstantPool,
bindingParser: BindingParser): R3ComponentDef {
const {definitionMap, statements} = baseDirectiveFields(meta, constantPool, bindingParser);
addFeatures(definitionMap, meta);
const selector = meta.selector && CssSelector.parse(meta.selector);
const firstSelector = selector && selector[0];
@ -223,7 +241,7 @@ export function compileComponentFromMetadata(
// e.g. `directives: [MyDirective]`
if (directivesUsed.size) {
let directivesExpr: o.Expression = o.literalArr(Array.from(directivesUsed));
if (meta.wrapDirectivesInClosure) {
if (meta.wrapDirectivesAndPipesInClosure) {
directivesExpr = o.fn([], [new o.ReturnStatement(directivesExpr)]);
}
definitionMap.set('directives', directivesExpr);
@ -231,7 +249,11 @@ export function compileComponentFromMetadata(
// e.g. `pipes: [MyPipe]`
if (pipesUsed.size) {
definitionMap.set('pipes', o.literalArr(Array.from(pipesUsed)));
let pipesExpr: o.Expression = o.literalArr(Array.from(pipesUsed));
if (meta.wrapDirectivesAndPipesInClosure) {
pipesExpr = o.fn([], [new o.ReturnStatement(pipesExpr)]);
}
definitionMap.set('pipes', pipesExpr);
}
// e.g. `styles: [str1, str2]`
@ -315,12 +337,13 @@ export function compileComponentFromRender2(
directives: typeMapToExpressionMap(directiveTypeBySel, outputCtx),
pipes: typeMapToExpressionMap(pipeTypeByName, outputCtx),
viewQueries: queriesFromGlobalMetadata(component.viewQueries, outputCtx),
wrapDirectivesInClosure: false,
wrapDirectivesAndPipesInClosure: false,
styles: (summary.template && summary.template.styles) || EMPTY_ARRAY,
encapsulation:
(summary.template && summary.template.encapsulation) || core.ViewEncapsulation.Emulated,
animations: null,
viewProviders: null,
viewProviders:
component.viewProviders.length > 0 ? new o.WrappedNodeExpr(component.viewProviders) : null
};
const res = compileComponentFromMetadata(meta, outputCtx.constantPool, bindingParser);
@ -363,7 +386,7 @@ function directiveMetadataFromGlobalMetadata(
outputs: directive.outputs,
usesInheritance: false,
exportAs: null,
providers: null,
providers: directive.providers.length > 0 ? new o.WrappedNodeExpr(directive.providers) : null
};
}
@ -453,11 +476,15 @@ function createContentQueriesFunction(
if (meta.queries.length) {
const statements: o.Statement[] = meta.queries.map((query: R3QueryMetadata) => {
const queryDefinition = createQueryDefinition(query, constantPool, null);
return o.importExpr(R3.registerContentQuery).callFn([queryDefinition]).toStmt();
return o.importExpr(R3.registerContentQuery)
.callFn([queryDefinition, o.variable('dirIndex')])
.toStmt();
});
const typeName = meta.name;
const parameters = [new o.FnParam('dirIndex', o.NUMBER_TYPE)];
return o.fn(
[], statements, o.INFERRED_TYPE, null, typeName ? `${typeName}_ContentQueries` : null);
parameters, statements, o.INFERRED_TYPE, null,
typeName ? `${typeName}_ContentQueries` : null);
}
return null;
@ -507,12 +534,15 @@ function stringAsType(str: string): o.Type {
return o.expressionType(o.literal(str));
}
function stringMapAsType(map: {[key: string]: string | [string, string]}): o.Type {
const mapValues = Object.keys(map).map(key => ({
key,
value: o.literal(map[key]),
quoted: true,
}));
function stringMapAsType(map: {[key: string]: string | string[]}): o.Type {
const mapValues = Object.keys(map).map(key => {
const value = Array.isArray(map[key]) ? map[key][0] : map[key];
return {
key,
value: o.literal(value),
quoted: true,
};
});
return o.expressionType(o.literalMap(mapValues));
}
@ -606,26 +636,6 @@ function createHostBindingsFunction(
}
}
// Calculate host event bindings
const eventBindings =
bindingParser.createDirectiveHostEventAsts(directiveSummary, hostBindingSourceSpan);
if (eventBindings) {
for (const binding of eventBindings) {
const bindingExpr = convertActionBinding(
null, bindingContext, binding.handler, 'b', () => error('Unexpected interpolation'));
const bindingName = binding.name && sanitizeIdentifier(binding.name);
const typeName = meta.name;
const functionName =
typeName && bindingName ? `${typeName}_${bindingName}_HostBindingHandler` : null;
const handler = o.fn(
[new o.FnParam('$event', o.DYNAMIC_TYPE)],
[...bindingExpr.stmts, new o.ReturnStatement(bindingExpr.allowDefault)], o.INFERRED_TYPE,
null, functionName);
statements.push(
o.importExpr(R3.listener).callFn([o.literal(binding.name), handler]).toStmt());
}
}
if (statements.length > 0) {
const typeName = meta.name;
return o.fn(
@ -639,6 +649,32 @@ function createHostBindingsFunction(
return null;
}
function createFactoryExtraStatementsFn(meta: R3DirectiveMetadata, bindingParser: BindingParser):
((instance: o.Expression) => o.Statement[])|null {
const eventBindings =
bindingParser.createDirectiveHostEventAsts(metadataAsSummary(meta), meta.typeSourceSpan);
return eventBindings && eventBindings.length ?
(instance: o.Expression) => createHostListeners(instance, eventBindings, meta) :
null;
}
function createHostListeners(
bindingContext: o.Expression, eventBindings: ParsedEvent[],
meta: R3DirectiveMetadata): o.Statement[] {
return eventBindings.map(binding => {
const bindingExpr = convertActionBinding(
null, bindingContext, binding.handler, 'b', () => error('Unexpected interpolation'));
const bindingName = binding.name && sanitizeIdentifier(binding.name);
const typeName = meta.name;
const functionName =
typeName && bindingName ? `${typeName}_${bindingName}_HostBindingHandler` : null;
const handler = o.fn(
[new o.FnParam('$event', o.DYNAMIC_TYPE)], [...bindingExpr.render3Stmts], o.INFERRED_TYPE,
null, functionName);
return o.importExpr(R3.listener).callFn([o.literal(binding.name), handler]).toStmt();
});
}
function metadataAsSummary(meta: R3DirectiveMetadata): CompileDirectiveSummary {
// clang-format off
return {

View File

@ -643,18 +643,23 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
const stylingInput = mapBasedStyleInput || mapBasedClassInput;
if (stylingInput) {
// these values must be outside of the update block so that they can
// be evaluted (the AST visit call) during creation time so that any
// pipes can be picked up in time before the template is built
const mapBasedClassValue =
mapBasedClassInput ? mapBasedClassInput.value.visit(this._valueConverter) : null;
const mapBasedStyleValue =
mapBasedStyleInput ? mapBasedStyleInput.value.visit(this._valueConverter) : null;
this.updateInstruction(stylingInput.sourceSpan, R3.elementStylingMap, () => {
const params: o.Expression[] = [indexLiteral];
if (mapBasedClassInput) {
const mapBasedClassValue = mapBasedClassInput.value.visit(this._valueConverter);
if (mapBasedClassValue) {
params.push(this.convertPropertyBinding(implicit, mapBasedClassValue, true));
} else if (mapBasedStyleInput) {
params.push(o.NULL_EXPR);
}
if (mapBasedStyleInput) {
const mapBasedStyleValue = mapBasedStyleInput.value.visit(this._valueConverter);
if (mapBasedStyleValue) {
params.push(this.convertPropertyBinding(implicit, mapBasedStyleValue, true));
}
@ -670,15 +675,18 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
const key = input.name;
const styleIndex: number = stylesIndexMap[key] !;
const value = input.value.visit(this._valueConverter);
const params: o.Expression[] = [
indexLiteral, o.literal(styleIndex), this.convertPropertyBinding(implicit, value, true)
];
this.updateInstruction(input.sourceSpan, R3.elementStyleProp, () => {
const params: o.Expression[] = [
indexLiteral, o.literal(styleIndex),
this.convertPropertyBinding(implicit, value, true)
];
if (input.unit != null) {
params.push(o.literal(input.unit));
}
if (input.unit != null) {
params.push(o.literal(input.unit));
}
this.updateInstruction(input.sourceSpan, R3.elementStyleProp, params);
return params;
});
}
lastInputCommand = styleInputs[styleInputs.length - 1];
@ -696,10 +704,8 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
const classIndex: number = classesIndexMap[key] !;
const value = input.value.visit(this._valueConverter);
this.updateInstruction(input.sourceSpan, R3.elementClassProp, () => {
return [
indexLiteral, o.literal(classIndex),
this.convertPropertyBinding(implicit, value, true), ...params
];
const valueLiteral = this.convertPropertyBinding(implicit, value, true);
return [indexLiteral, o.literal(classIndex), valueLiteral];
});
}

View File

@ -67,8 +67,8 @@ export function asLiteral(value: any): o.Expression {
return o.literal(value, o.INFERRED_TYPE);
}
export function conditionallyCreateMapObjectLiteral(
keys: {[key: string]: string | [string, string]}): o.Expression|null {
export function conditionallyCreateMapObjectLiteral(keys: {[key: string]: string | string[]}):
o.Expression|null {
if (Object.getOwnPropertyNames(keys).length > 0) {
return mapToExpression(keys);
}

View File

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

View File

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

View File

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

View File

@ -14,9 +14,9 @@ export {isListLikeIterable as ɵisListLikeIterable} from './change_detection/cha
export {ChangeDetectorStatus as ɵChangeDetectorStatus, isDefaultChangeDetectionStrategy as ɵisDefaultChangeDetectionStrategy} from './change_detection/constants';
export {Console as ɵConsole} from './console';
export {InjectableDef as ɵInjectableDef, InjectorDef as ɵInjectorDef, getInjectableDef as ɵgetInjectableDef} from './di/defs';
export {inject as ɵinject, setCurrentInjector as ɵsetCurrentInjector} from './di/injector';
export {inject as ɵinject, setCurrentInjector as ɵsetCurrentInjector} from './di/injector_compatibility';
export {APP_ROOT as ɵAPP_ROOT} from './di/scope';
export {ivyEnabled as ɵivyEnabled} from './ivy_switch/compiler/index';
export {ivyEnabled as ɵivyEnabled} from './ivy_switch';
export {ComponentFactory as ɵComponentFactory} from './linker/component_factory';
export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} from './linker/component_factory_resolver';
export {resolveComponentResources as ɵresolveComponentResources} from './metadata/resource_loading';

View File

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

View File

@ -16,7 +16,8 @@ export * from './di/metadata';
export {InjectableType, InjectorType, defineInjectable, defineInjector} from './di/defs';
export {forwardRef, resolveForwardRef, ForwardRefFn} from './di/forward_ref';
export {Injectable, InjectableDecorator, InjectableProvider} from './di/injectable';
export {inject, InjectFlags, INJECTOR, Injector} from './di/injector';
export {INJECTOR, Injector} from './di/injector';
export {inject, InjectFlags} from './di/injector_compatibility';
export {ReflectiveInjector} from './di/reflective_injector';
export {StaticProvider, ValueProvider, ConstructorSansProvider, ExistingProvider, FactoryProvider, Provider, TypeProvider, ClassProvider} from './di/provider';
export {createInjector} from './di/r3_injector';

View File

@ -8,6 +8,7 @@
import {Type} from '../type';
import {stringify} from '../util';
import {getClosureSafeProperty} from '../util/property';
@ -22,6 +23,8 @@ import {stringify} from '../util';
*/
export interface ForwardRefFn { (): any; }
const __forward_ref__ = getClosureSafeProperty({__forward_ref__: getClosureSafeProperty});
/**
* Allows to refer to references which are not yet defined.
*
@ -53,10 +56,11 @@ export function forwardRef(forwardRefFn: ForwardRefFn): Type<any> {
* @see `forwardRef`
* @publicApi
*/
export function resolveForwardRef(type: any): any {
if (typeof type === 'function' && type.hasOwnProperty('__forward_ref__') &&
type.__forward_ref__ === forwardRef) {
return (<ForwardRefFn>type)();
export function resolveForwardRef<T>(type: T): T {
const fn: any = type;
if (typeof fn === 'function' && fn.hasOwnProperty(__forward_ref__) &&
fn.__forward_ref__ === forwardRef) {
return fn();
} else {
return type;
}

View File

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

View File

@ -6,13 +6,16 @@
* found in the LICENSE file at https://angular.io/license
*/
import {injectInjector} from '../render3/di';
import {Type} from '../type';
import {stringify} from '../util';
import {noop} from '../util/noop';
import {getClosureSafeProperty} from '../util/property';
import {InjectableDef, defineInjectable, getInjectableDef} from './defs';
import {defineInjectable} from './defs';
import {resolveForwardRef} from './forward_ref';
import {InjectionToken} from './injection_token';
import {InjectFlags, inject} from './injector_compatibility';
import {Inject, Optional, Self, SkipSelf} from './metadata';
import {ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, ValueProvider} from './provider';
@ -104,8 +107,16 @@ export abstract class Injector {
providedIn: 'any' as any,
factory: () => inject(INJECTOR),
});
/** @internal */
static __NG_ELEMENT_ID__: () => Injector = () => SWITCH_INJECTOR_FACTORY();
}
export const SWITCH_INJECTOR_FACTORY__POST_R3__ = function() {
return injectInjector();
};
const SWITCH_INJECTOR_FACTORY__PRE_R3__ = noop;
const SWITCH_INJECTOR_FACTORY: typeof injectInjector = SWITCH_INJECTOR_FACTORY__PRE_R3__;
const IDENT = function<T>(value: T): T {
@ -336,7 +347,6 @@ function resolveToken(
return value;
}
function computeDeps(provider: StaticProvider): DependencyRecord[] {
let deps: DependencyRecord[] = EMPTY;
const providerDeps: any[] =
@ -396,107 +406,3 @@ function formatError(text: string, obj: any, source: string | null = null): stri
function staticError(text: string, obj: any): Error {
return new Error(formatError(text, obj));
}
/**
* Injection flags for DI.
*
* @publicApi
*/
export const enum InjectFlags {
Default = 0b0000,
/**
* Specifies that an injector should retrieve a dependency from any injector until reaching the
* host element of the current component. (Only used with Element Injector)
*/
Host = 0b0001,
/** Don't descend into ancestors of the node requesting injection. */
Self = 0b0010,
/** Skip the node that is requesting injection. */
SkipSelf = 0b0100,
/** Inject `defaultValue` instead if token not found. */
Optional = 0b1000,
}
/**
* Current injector value used by `inject`.
* - `undefined`: it is an error to call `inject`
* - `null`: `inject` can be called but there is no injector (limp-mode).
* - Injector instance: Use the injector for resolution.
*/
let _currentInjector: Injector|undefined|null = undefined;
export function setCurrentInjector(injector: Injector | null | undefined): Injector|undefined|null {
const former = _currentInjector;
_currentInjector = injector;
return former;
}
/**
* Injects a token from the currently active injector.
*
* This function must be used in the context of a factory function such as one defined for an
* `InjectionToken`, and will throw an error if not called from such a context.
*
* @usageNotes
* ### Example
*
* {@example core/di/ts/injector_spec.ts region='ShakeableInjectionToken'}
*
* Within such a factory function `inject` is utilized to request injection of a dependency, instead
* of providing an additional array of dependencies as was common to do with `useFactory` providers.
* `inject` is faster and more type-safe.
*
* @publicApi
*/
export function inject<T>(token: Type<T>| InjectionToken<T>): T;
export function inject<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags): T|null;
export function inject<T>(token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|null {
if (_currentInjector === undefined) {
throw new Error(`inject() must be called from an injection context`);
} else if (_currentInjector === null) {
const injectableDef: InjectableDef<T>|null = getInjectableDef(token);
if (injectableDef && injectableDef.providedIn == 'root') {
return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() :
injectableDef.value;
}
if (flags & InjectFlags.Optional) return null;
throw new Error(`Injector: NOT_FOUND [${stringify(token)}]`);
} else {
return _currentInjector.get(token, flags & InjectFlags.Optional ? null : undefined, flags);
}
}
export function injectArgs(types: (Type<any>| InjectionToken<any>| any[])[]): any[] {
const args: any[] = [];
for (let i = 0; i < types.length; i++) {
const arg = types[i];
if (Array.isArray(arg)) {
if (arg.length === 0) {
throw new Error('Arguments array must have arguments.');
}
let type: Type<any>|undefined = undefined;
let flags: InjectFlags = InjectFlags.Default;
for (let j = 0; j < arg.length; j++) {
const meta = arg[j];
if (meta instanceof Optional || meta.ngMetadataName === 'Optional') {
flags |= InjectFlags.Optional;
} else if (meta instanceof SkipSelf || meta.ngMetadataName === 'SkipSelf') {
flags |= InjectFlags.SkipSelf;
} else if (meta instanceof Self || meta.ngMetadataName === 'Self') {
flags |= InjectFlags.Self;
} else if (meta instanceof Inject) {
type = meta.token;
} else {
type = meta;
}
}
args.push(inject(type !, flags));
} else {
args.push(inject(arg));
}
}
return args;
}

View File

@ -0,0 +1,165 @@
/**
* @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 {Type} from '../type';
import {stringify} from '../util';
import {InjectableDef, getInjectableDef} from './defs';
import {InjectionToken} from './injection_token';
import {Injector} from './injector';
import {Inject, Optional, Self, SkipSelf} from './metadata';
/**
* Injection flags for DI.
*
* @publicApi
*/
export const enum InjectFlags {
Default = 0b0000,
/**
* Specifies that an injector should retrieve a dependency from any injector until reaching the
* host element of the current component. (Only used with Element Injector)
*/
Host = 0b0001,
/** Don't descend into ancestors of the node requesting injection. */
Self = 0b0010,
/** Skip the node that is requesting injection. */
SkipSelf = 0b0100,
/** Inject `defaultValue` instead if token not found. */
Optional = 0b1000,
}
/**
* Current injector value used by `inject`.
* - `undefined`: it is an error to call `inject`
* - `null`: `inject` can be called but there is no injector (limp-mode).
* - Injector instance: Use the injector for resolution.
*/
let _currentInjector: Injector|undefined|null = undefined;
export function setCurrentInjector(injector: Injector | null | undefined): Injector|undefined|null {
const former = _currentInjector;
_currentInjector = injector;
return former;
}
/**
* Current implementation of inject.
*
* By default, it is `injectInjectorOnly`, which makes it `Injector`-only aware. It can be changed
* to `directiveInject`, which brings in the `NodeInjector` system of ivy. It is designed this
* way for two reasons:
* 1. `Injector` should not depend on ivy logic.
* 2. To maintain tree shake-ability we don't want to bring in unnecessary code.
*/
let _injectImplementation: (<T>(token: Type<T>| InjectionToken<T>, flags: InjectFlags) => T | null)|
undefined;
/**
* Sets the current inject implementation.
*/
export function setInjectImplementation(
impl: (<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags) => T | null) | undefined):
(<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags) => T | null)|undefined {
const previous = _injectImplementation;
_injectImplementation = impl;
return previous;
}
export function injectInjectorOnly<T>(token: Type<T>| InjectionToken<T>): T;
export function injectInjectorOnly<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags): T|
null;
export function injectInjectorOnly<T>(
token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|null {
if (_currentInjector === undefined) {
throw new Error(`inject() must be called from an injection context`);
} else if (_currentInjector === null) {
return injectRootLimpMode(token, undefined, flags);
} else {
return _currentInjector.get(token, flags & InjectFlags.Optional ? null : undefined, flags);
}
}
/**
* Injects a token from the currently active injector.
*
* This function must be used in the context of a factory function such as one defined for an
* `InjectionToken`, and will throw an error if not called from such a context.
*
* @usageNotes
* ### Example
*
* {@example core/di/ts/injector_spec.ts region='ShakeableInjectionToken'}
*
* Within such a factory function `inject` is utilized to request injection of a dependency, instead
* of providing an additional array of dependencies as was common to do with `useFactory` providers.
* `inject` is faster and more type-safe.
*
* @publicApi
*/
export function inject<T>(token: Type<T>| InjectionToken<T>): T;
export function inject<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags): T|null;
export function inject<T>(token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|null {
return (_injectImplementation || injectInjectorOnly)(token, flags);
}
/**
* Injects `root` tokens in limp mode.
*
* If no injector exists, we can still inject tree-shakable providers which have `providedIn` set to
* `"root"`. This is known as the limp mode injection. In such case the value is stored in the
* `InjectableDef`.
*/
export function injectRootLimpMode<T>(
token: Type<T>| InjectionToken<T>, notFoundValue: T | undefined, flags: InjectFlags): T|null {
const injectableDef: InjectableDef<T>|null = getInjectableDef(token);
if (injectableDef && injectableDef.providedIn == 'root') {
return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() :
injectableDef.value;
}
if (flags & InjectFlags.Optional) return null;
if (notFoundValue !== undefined) return notFoundValue;
throw new Error(`Injector: NOT_FOUND [${stringify(token)}]`);
}
export function injectArgs(types: (Type<any>| InjectionToken<any>| any[])[]): any[] {
const args: any[] = [];
for (let i = 0; i < types.length; i++) {
const arg = types[i];
if (Array.isArray(arg)) {
if (arg.length === 0) {
throw new Error('Arguments array must have arguments.');
}
let type: Type<any>|undefined = undefined;
let flags: InjectFlags = InjectFlags.Default;
for (let j = 0; j < arg.length; j++) {
const meta = arg[j];
if (meta instanceof Optional || meta.ngMetadataName === 'Optional') {
flags |= InjectFlags.Optional;
} else if (meta instanceof SkipSelf || meta.ngMetadataName === 'SkipSelf') {
flags |= InjectFlags.SkipSelf;
} else if (meta instanceof Self || meta.ngMetadataName === 'Self') {
flags |= InjectFlags.Self;
} else if (meta instanceof Inject) {
type = meta.token;
} else {
type = meta;
}
}
args.push(inject(type !, flags));
} else {
args.push(inject(arg));
}
}
return args;
}

View File

@ -13,7 +13,8 @@ import {stringify} from '../util';
import {InjectableDef, InjectableType, InjectorType, InjectorTypeWithProviders, getInjectableDef, getInjectorDef} from './defs';
import {resolveForwardRef} from './forward_ref';
import {InjectionToken} from './injection_token';
import {INJECTOR, InjectFlags, Injector, NullInjector, THROW_IF_NOT_FOUND, USE_VALUE, inject, injectArgs, setCurrentInjector} from './injector';
import {INJECTOR, Injector, NullInjector, THROW_IF_NOT_FOUND, USE_VALUE} from './injector';
import {InjectFlags, inject, injectArgs, setCurrentInjector} from './injector_compatibility';
import {ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, Provider, StaticClassProvider, StaticProvider, TypeProvider, ValueProvider} from './provider';
import {APP_ROOT} from './scope';
@ -165,7 +166,7 @@ export class R3Injector {
if (def && this.injectableDefInScope(def)) {
// Found an ngInjectableDef and it's scoped to this injector. Pretend as if it was here
// all along.
record = injectableDefRecord(token);
record = makeRecord(injectableDefFactory(token), NOT_YET);
this.records.set(token, record);
}
}
@ -177,8 +178,8 @@ export class R3Injector {
// Select the next injector based on the Self flag - if self is set, the next injector is
// the NullInjector, otherwise it's the parent.
let next = !(flags & InjectFlags.Self) ? this.parent : getNullInjector();
return this.parent.get(token, notFoundValue);
const nextInjector = !(flags & InjectFlags.Self) ? this.parent : getNullInjector();
return nextInjector.get(token, notFoundValue);
} finally {
// Lastly, clean up the state by restoring the previous injector.
setCurrentInjector(previousInjector);
@ -328,7 +329,7 @@ export class R3Injector {
}
}
function injectableDefRecord(token: Type<any>| InjectionToken<any>): Record<any> {
function injectableDefFactory(token: Type<any>| InjectionToken<any>): () => any {
const injectableDef = getInjectableDef(token as InjectableType<any>);
if (injectableDef === null) {
if (token instanceof InjectionToken) {
@ -336,35 +337,47 @@ function injectableDefRecord(token: Type<any>| InjectionToken<any>): Record<any>
}
// TODO(alxhub): there should probably be a strict mode which throws here instead of assuming a
// no-args constructor.
return makeRecord(() => new (token as Type<any>)());
return () => new (token as Type<any>)();
}
return makeRecord(injectableDef.factory);
return injectableDef.factory;
}
function providerToRecord(provider: SingleProvider): Record<any> {
let token = resolveForwardRef(provider);
let value: any = NOT_YET;
let factory: (() => any)|undefined = providerToFactory(provider);
if (isValueProvider(provider)) {
return makeRecord(undefined, provider.useValue);
} else {
return makeRecord(factory, NOT_YET);
}
}
/**
* Converts a `SingleProvider` into a factory function.
*
* @param provider provider to convert to factory
*/
export function providerToFactory(provider: SingleProvider): () => any {
let factory: (() => any)|undefined = undefined;
if (isTypeProvider(provider)) {
return injectableDefRecord(provider);
return injectableDefFactory(resolveForwardRef(provider));
} else {
token = resolveForwardRef(provider.provide);
if (isValueProvider(provider)) {
value = provider.useValue;
factory = () => resolveForwardRef(provider.useValue);
} else if (isExistingProvider(provider)) {
factory = () => inject(provider.useExisting);
factory = () => inject(resolveForwardRef(provider.useExisting));
} else if (isFactoryProvider(provider)) {
factory = () => provider.useFactory(...injectArgs(provider.deps || []));
} else {
const classRef = (provider as StaticClassProvider | ClassProvider).useClass || token;
const classRef = resolveForwardRef(
(provider as StaticClassProvider | ClassProvider).useClass || provider.provide);
if (hasDeps(provider)) {
factory = () => new (classRef)(...injectArgs(provider.deps));
} else {
return injectableDefRecord(classRef);
return injectableDefFactory(classRef);
}
}
}
return makeRecord(factory, value);
return factory;
}
function makeRecord<T>(
@ -392,7 +405,7 @@ function isFactoryProvider(value: SingleProvider): value is FactoryProvider {
return !!(value as FactoryProvider).useFactory;
}
function isTypeProvider(value: SingleProvider): value is TypeProvider {
export function isTypeProvider(value: SingleProvider): value is TypeProvider {
return typeof value === 'function';
}

View File

@ -0,0 +1,55 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ReflectionCapabilities} from '../reflection/reflection_capabilities';
import {Type} from '../type';
import {getClosureSafeProperty} from '../util/property';
import {inject, injectArgs} from './injector_compatibility';
import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from './provider';
const USE_VALUE =
getClosureSafeProperty<ValueProvider>({provide: String, useValue: getClosureSafeProperty});
const EMPTY_ARRAY: any[] = [];
export function convertInjectableProviderToFactory(
type: Type<any>, provider?: ValueSansProvider | ExistingSansProvider | StaticClassSansProvider |
ConstructorSansProvider | FactorySansProvider | ClassSansProvider): () => any {
if (!provider) {
const reflectionCapabilities = new ReflectionCapabilities();
const deps = reflectionCapabilities.parameters(type);
// TODO - convert to flags.
return () => new type(...injectArgs(deps as any[]));
}
if (USE_VALUE in provider) {
const valueProvider = (provider as ValueSansProvider);
return () => valueProvider.useValue;
} else if ((provider as ExistingSansProvider).useExisting) {
const existingProvider = (provider as ExistingSansProvider);
return () => inject(existingProvider.useExisting);
} else if ((provider as FactorySansProvider).useFactory) {
const factoryProvider = (provider as FactorySansProvider);
return () => factoryProvider.useFactory(...injectArgs(factoryProvider.deps || EMPTY_ARRAY));
} else if ((provider as StaticClassSansProvider | ClassSansProvider).useClass) {
const classProvider = (provider as StaticClassSansProvider | ClassSansProvider);
let deps = (provider as StaticClassSansProvider).deps;
if (!deps) {
const reflectionCapabilities = new ReflectionCapabilities();
deps = reflectionCapabilities.parameters(type);
}
return () => new classProvider.useClass(...injectArgs(deps));
} else {
let deps = (provider as ConstructorSansProvider).deps;
if (!deps) {
const reflectionCapabilities = new ReflectionCapabilities();
deps = reflectionCapabilities.parameters(type);
}
return () => new type(...injectArgs(deps !));
}
}

View File

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

View File

@ -1,17 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* This file is used to control if the default rendering pipeline should be `ViewEngine` or `Ivy`.
*
* For more information on how to run and debug tests with either Ivy or View Engine (legacy),
* please see [BAZEL.md](./docs/BAZEL.md).
*/
export * from './legacy';
// TODO(alxhub): debug why metadata doesn't properly propagate through this file.

View File

@ -1,21 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {compileComponent, compileDirective} from '../../render3/jit/directive';
import {compileInjectable} from '../../render3/jit/injectable';
import {compileNgModule, compileNgModuleDefs, patchComponentDefWithScope} from '../../render3/jit/module';
import {compilePipe} from '../../render3/jit/pipe';
export const ivyEnabled = true;
export const R3_COMPILE_COMPONENT = compileComponent;
export const R3_COMPILE_DIRECTIVE = compileDirective;
export const R3_COMPILE_INJECTABLE = compileInjectable;
export const R3_COMPILE_NGMODULE = compileNgModule;
export const R3_COMPILE_PIPE = compilePipe;
export const R3_COMPILE_NGMODULE_DEFS = compileNgModuleDefs;
export const R3_PATCH_COMPONENT_DEF_WTIH_SCOPE = patchComponentDefWithScope;

View File

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

View File

@ -1,15 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* This file is used to control if the default rendering pipeline should be `ViewEngine` or `Ivy`.
*
* For more information on how to run and debug tests with either Ivy or View Engine (legacy),
* please see [BAZEL.md](./docs/BAZEL.md).
*/
export * from './legacy';

View File

@ -1,15 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {injectChangeDetectorRef, injectElementRef, injectRenderer2, injectTemplateRef, injectViewContainerRef} from '../../render3/view_engine_compatibility';
export const R3_ELEMENT_REF_FACTORY = injectElementRef;
export const R3_TEMPLATE_REF_FACTORY = injectTemplateRef;
export const R3_CHANGE_DETECTOR_REF_FACTORY = injectChangeDetectorRef;
export const R3_VIEW_CONTAINER_REF_FACTORY = injectViewContainerRef;
export const R3_RENDERER2_FACTORY = injectRenderer2;

View File

@ -1,34 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as ivyOn from './ivy_switch_on';
function noopFactory(...tokens: any[]): any {}
type FactoryFunction<T = any> = (...tokens: any[]) => T;
export const R3_ELEMENT_REF_FACTORY__POST_NGCC__: FactoryFunction = ivyOn.R3_ELEMENT_REF_FACTORY;
export const R3_TEMPLATE_REF_FACTORY__POST_NGCC__: FactoryFunction = ivyOn.R3_TEMPLATE_REF_FACTORY;
export const R3_CHANGE_DETECTOR_REF_FACTORY__POST_NGCC__: FactoryFunction =
ivyOn.R3_CHANGE_DETECTOR_REF_FACTORY;
export const R3_VIEW_CONTAINER_REF_FACTORY__POST_NGCC__: FactoryFunction =
ivyOn.R3_VIEW_CONTAINER_REF_FACTORY;
export const R3_RENDERER2_FACTORY__POST_NGCC__: FactoryFunction = ivyOn.R3_RENDERER2_FACTORY;
export const R3_ELEMENT_REF_FACTORY__PRE_NGCC__ = noopFactory;
export const R3_TEMPLATE_REF_FACTORY__PRE_NGCC__ = noopFactory;
export const R3_CHANGE_DETECTOR_REF_FACTORY__PRE_NGCC__ = noopFactory;
export const R3_VIEW_CONTAINER_REF_FACTORY__PRE_NGCC__ = noopFactory;
export const R3_RENDERER2_FACTORY__PRE_NGCC__ = noopFactory;
export let R3_ELEMENT_REF_FACTORY = R3_ELEMENT_REF_FACTORY__PRE_NGCC__;
export let R3_TEMPLATE_REF_FACTORY = R3_TEMPLATE_REF_FACTORY__PRE_NGCC__;
export let R3_CHANGE_DETECTOR_REF_FACTORY = R3_CHANGE_DETECTOR_REF_FACTORY__PRE_NGCC__;
export let R3_VIEW_CONTAINER_REF_FACTORY = R3_VIEW_CONTAINER_REF_FACTORY__PRE_NGCC__;
export let R3_RENDERER2_FACTORY = R3_RENDERER2_FACTORY__PRE_NGCC__;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -20,7 +20,7 @@
*/
export {InjectableDef as ɵInjectableDef, InjectorDef as ɵInjectorDef, defineInjectable, defineInjector} from './di/defs';
export {inject} from './di/injector';
export {inject} from './di/injector_compatibility';
export {NgModuleDef as ɵNgModuleDef, NgModuleDefWithMeta as ɵNgModuleDefWithMeta} from './metadata/ng_module';
export {defineNgModule as ɵdefineNgModule} from './render3/definition';
export {NgModuleFactory as ɵNgModuleFactory} from './render3/ng_module_ref';

View File

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

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