Compare commits
125 Commits
6.0.0-beta
...
5.2.3
Author | SHA1 | Date | |
---|---|---|---|
579bed1a7a | |||
b59fb23f4a | |||
2aa460b30e | |||
e0022ae9cd | |||
f2e923edd8 | |||
c2f5ed545c | |||
5d75df8fb1 | |||
ed2b71799c | |||
fad99cca0e | |||
3f5ead3845 | |||
a89e709515 | |||
6a7689d4ea | |||
696ba01a4e | |||
81d64d6bec | |||
7410941a7c | |||
d159ad8b88 | |||
250c8da768 | |||
778e6e759f | |||
35a0721217 | |||
ba045e88d7 | |||
67806a7b25 | |||
9778a23be8 | |||
87e06d765e | |||
56f3e18c1c | |||
637515e71b | |||
27ecd077d4 | |||
4db1be0292 | |||
a0dbef9ea4 | |||
3aaf43f73c | |||
d952ae24dd | |||
da9e57b3d5 | |||
44d4f82dae | |||
bde2b4425c | |||
2a3de802a0 | |||
71f9eaa743 | |||
a62c186d15 | |||
c8bf281174 | |||
de6c6445af | |||
54238822e6 | |||
8b3fbb5bf4 | |||
2f61d3c320 | |||
5894f6ee1c | |||
6d9fcd62de | |||
0cbccc06dd | |||
ed670a36fb | |||
8e44577df3 | |||
6921c20ea1 | |||
52970c09e1 | |||
eecdf3414e | |||
21f766968d | |||
4b68fdce6f | |||
c12ea3a1f0 | |||
d7dbdc5c36 | |||
0112a903f9 | |||
66bbc84127 | |||
554129d6fe | |||
e32a0cabfe | |||
c828e5627b | |||
1626e74c59 | |||
a15a2b46d1 | |||
379ed75593 | |||
0f619896b3 | |||
7060655806 | |||
b5fc3eb9de | |||
451bdb9a75 | |||
983ccc02ad | |||
00f99b3c4c | |||
ba4ea82f68 | |||
982eb7bba8 | |||
3606c55410 | |||
2c65027391 | |||
4ee92f14a6 | |||
c9b65914d3 | |||
02352bcd9e | |||
0d55600fd8 | |||
af4eb00c91 | |||
d3e7ebb3b4 | |||
420f5c4275 | |||
b773a4ab98 | |||
55f15c54d9 | |||
4556532c26 | |||
54e75766ad | |||
d3333f04ba | |||
75f8522b8d | |||
a771ee5d90 | |||
a4cbe3542a | |||
cc9419d1ca | |||
d5393c7f91 | |||
71dd92bbb8 | |||
977978edb5 | |||
eb70966065 | |||
cf4bea587d | |||
8e9cd57951 | |||
f23896f519 | |||
0e59d18fc2 | |||
54c8a321a9 | |||
9005a6f3cd | |||
3c6a5063f7 | |||
b49d54e606 | |||
55fd82e587 | |||
7f3d0bbf97 | |||
3db02d244a | |||
50b605686e | |||
64d4aafbc7 | |||
a931a419fa | |||
6a97b5b722 | |||
aad1126446 | |||
7b463df52b | |||
a2432c9f10 | |||
e500484ccc | |||
a0dcb0b828 | |||
c4b71920d1 | |||
650f5fb5c7 | |||
c32e83334b | |||
7bdd9aecbd | |||
5ede67c345 | |||
31b671ab54 | |||
3804d20b6d | |||
0a5a87887e | |||
c46afce0f5 | |||
76c781fd37 | |||
51eb3d418e | |||
48c18985cc | |||
167cbed266 | |||
70e8802540 |
@ -206,12 +206,6 @@ groups:
|
||||
conditions:
|
||||
files:
|
||||
- "packages/forms/*"
|
||||
- "aio/content/guide/forms.md"
|
||||
- "aio/content/guide/form-validation.md"
|
||||
- "aio/content/guide/reactive-forms.md"
|
||||
- "aio/content/examples/forms/*"
|
||||
- "aio/content/examples/form-validation/*"
|
||||
- "aio/content/examples/reactive-forms/*"
|
||||
users:
|
||||
- kara #primary
|
||||
- tinayuangao #secondary
|
||||
|
67
CHANGELOG.md
67
CHANGELOG.md
@ -1,14 +1,3 @@
|
||||
<a name="6.0.0-beta.2"></a>
|
||||
# [6.0.0-beta.2](https://github.com/angular/angular/compare/6.0.0-beta.1...6.0.0-beta.2) (2018-01-31)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **router:** add navigationSource and restoredState to NavigationStart event ([#21728](https://github.com/angular/angular/issues/21728)) ([c40ae7f](https://github.com/angular/angular/commit/c40ae7f))
|
||||
* **service-worker:** add helper script which will uninstall SW ([#21863](https://github.com/angular/angular/issues/21863)) ([b10540a](https://github.com/angular/angular/commit/b10540a))
|
||||
|
||||
|
||||
|
||||
<a name="5.2.3"></a>
|
||||
## [5.2.3](https://github.com/angular/angular/compare/5.2.2...5.2.3) (2018-01-31)
|
||||
|
||||
@ -26,32 +15,6 @@
|
||||
|
||||
|
||||
|
||||
<a name="6.0.0-beta.1"></a>
|
||||
# [6.0.0-beta.1](https://github.com/angular/angular/compare/6.0.0-beta.0...6.0.0-beta.1) (2018-01-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **common:** A null value should remove the style on IE ([#21679](https://github.com/angular/angular/issues/21679)) ([7d49443](https://github.com/angular/angular/commit/7d49443)), closes [#21064](https://github.com/angular/angular/issues/21064)
|
||||
* avoid triggering a cli bug ([#21611](https://github.com/angular/angular/issues/21611)) ([0eabd07](https://github.com/angular/angular/commit/0eabd07))
|
||||
* **common:** don't remove special characters when extracting CLDR data ([#21626](https://github.com/angular/angular/issues/21626)) ([135a282](https://github.com/angular/angular/commit/135a282))
|
||||
* **common:** extract plural function from i18n locale data files for TS 2.6 ([#21626](https://github.com/angular/angular/issues/21626)) ([97b18b2](https://github.com/angular/angular/commit/97b18b2)), closes [#21608](https://github.com/angular/angular/issues/21608)
|
||||
* **common:** fallback to last defined value for named date and time formats ([#21299](https://github.com/angular/angular/issues/21299)) ([879756d](https://github.com/angular/angular/commit/879756d)), closes [#21282](https://github.com/angular/angular/issues/21282)
|
||||
* **compiler:** add support for marker tags in xliff serializers ([#21250](https://github.com/angular/angular/issues/21250)) ([f74130c](https://github.com/angular/angular/commit/f74130c)), closes [#21078](https://github.com/angular/angular/issues/21078)
|
||||
* **compiler:** Don't strip `/*# sourceURL ... */` ([#16088](https://github.com/angular/angular/issues/16088)) ([5f681f9](https://github.com/angular/angular/commit/5f681f9))
|
||||
* **compiler:** fix ICU select messages to use male/female/other ([#21713](https://github.com/angular/angular/issues/21713)) ([cb5090c](https://github.com/angular/angular/commit/cb5090c))
|
||||
* **compiler-cli:** do not fold errors past calls in the collector ([#21708](https://github.com/angular/angular/issues/21708)) ([dd86790](https://github.com/angular/angular/commit/dd86790))
|
||||
* **compiler-cli:** do not lower expressions in non-modules ([#21649](https://github.com/angular/angular/issues/21649)) ([7f93aad](https://github.com/angular/angular/commit/7f93aad))
|
||||
* **router:** don't use ParamsInheritanceStrategy in declarations ([#21574](https://github.com/angular/angular/issues/21574)) ([925e654](https://github.com/angular/angular/commit/925e654)), closes [#21456](https://github.com/angular/angular/issues/21456)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **compiler:** implement "enableIvy" compiler option ([#21427](https://github.com/angular/angular/issues/21427)) ([64d16de](https://github.com/angular/angular/commit/64d16de))
|
||||
* **core:** optional generic type for ElementRef ([#20765](https://github.com/angular/angular/issues/20765)) ([d3d9aac](https://github.com/angular/angular/commit/d3d9aac)), closes [#13139](https://github.com/angular/angular/issues/13139)
|
||||
|
||||
|
||||
|
||||
<a name="5.2.2"></a>
|
||||
## [5.2.2](https://github.com/angular/angular/compare/5.2.1...5.2.2) (2018-01-25)
|
||||
|
||||
@ -71,36 +34,6 @@
|
||||
|
||||
|
||||
|
||||
<a name="6.0.0-beta.0"></a>
|
||||
# [6.0.0-beta.0](https://github.com/angular/angular/compare/5.2.0...6.0.0-beta.0) (2018-01-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **animations:** fix increment/decrement aliases example ([#18323](https://github.com/angular/angular/issues/18323)) ([d2aa8ac](https://github.com/angular/angular/commit/d2aa8ac))
|
||||
* **benchpress:** should still support selenium_webdriver < 3.6.0 ([#21477](https://github.com/angular/angular/issues/21477)) ([9b84a32](https://github.com/angular/angular/commit/9b84a32))
|
||||
* **common:** set correct timezone for ISO8601 dates in Safari ([#21506](https://github.com/angular/angular/issues/21506)) ([05208b8](https://github.com/angular/angular/commit/05208b8)), closes [#21491](https://github.com/angular/angular/issues/21491)
|
||||
* **compiler:** cache external reference resolution ([#21359](https://github.com/angular/angular/issues/21359)) ([e3e2fc0](https://github.com/angular/angular/commit/e3e2fc0))
|
||||
* **compiler:** make `.ngsummary.json` files idempotent ([#21448](https://github.com/angular/angular/issues/21448)) ([e64b1e9](https://github.com/angular/angular/commit/e64b1e9))
|
||||
* **core:** fix chained http call ([#20924](https://github.com/angular/angular/issues/20924)) ([7e3f9a4](https://github.com/angular/angular/commit/7e3f9a4)), closes [#20921](https://github.com/angular/angular/issues/20921)
|
||||
* **ivy:** Add workaround for AJD in google3 ([#21488](https://github.com/angular/angular/issues/21488)) ([6af3672](https://github.com/angular/angular/commit/6af3672))
|
||||
* **language-service:** Clear caches when program changes ([#21337](https://github.com/angular/angular/issues/21337)) ([43e1520](https://github.com/angular/angular/commit/43e1520)), closes [#19405](https://github.com/angular/angular/issues/19405)
|
||||
* **service-worker:** properly handle invalid hashes in all scenarios ([#21288](https://github.com/angular/angular/issues/21288)) ([3951098](https://github.com/angular/angular/commit/3951098))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **bazel:** allow ng_module rules to control whether type checking is enabled ([#21460](https://github.com/angular/angular/issues/21460)) ([cffa0fe](https://github.com/angular/angular/commit/cffa0fe))
|
||||
* **core:** add binding name to content changed error ([#20352](https://github.com/angular/angular/issues/20352)) ([d3bf54b](https://github.com/angular/angular/commit/d3bf54b))
|
||||
* **forms:** handle string with and without line boundary on pattern validator ([#19256](https://github.com/angular/angular/issues/19256)) ([54bf179](https://github.com/angular/angular/commit/54bf179))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **ivy:** add missing dom element in render3_function tree benchmark ([#21476](https://github.com/angular/angular/issues/21476)) ([9b5a485](https://github.com/angular/angular/commit/9b5a485))
|
||||
|
||||
|
||||
|
||||
<a name="5.2.1"></a>
|
||||
## [5.2.1](https://github.com/angular/angular/compare/5.2.0...5.2.1) (2018-01-17)
|
||||
|
||||
|
@ -245,16 +245,6 @@ Tells the compiler to generate all the possible generated files even if they are
|
||||
how `bazel` rules track file dependencies. It is not recommended to use this option outside of the `bazel`
|
||||
rules.
|
||||
|
||||
### *enableIvy*
|
||||
|
||||
Tells the compiler to generate definitions using the Render3 style code generation. This option defaults to `false`.
|
||||
|
||||
Not all features are supported with this option enabled. It is only supported
|
||||
for experimentation and testing of Render3 style code generation.
|
||||
|
||||
*Note*: Is it not recommended to use this option as it is not yet feature complete with the Render2 code generation.
|
||||
|
||||
|
||||
## Angular Metadata and AOT
|
||||
|
||||
The Angular **AOT compiler** extracts and interprets **metadata** about the parts of the application that Angular is supposed to manage.
|
||||
|
@ -290,42 +290,20 @@ out of date. Right click the Cache Storage title and refresh the caches.
|
||||
Stopping and starting the service worker in the Service Worker
|
||||
pane triggers a check for updates.
|
||||
|
||||
## Service Worker Safety
|
||||
## Fail-safe
|
||||
|
||||
Like any complex system, bugs or broken configurations can cause
|
||||
the Angular service worker to act in unforeseen ways. While its
|
||||
design attempts to minimize the impact of such problems, the
|
||||
Angular service worker contains several failsafe mechanisms in case
|
||||
Angular service worker contains a failsafe mechanism in case
|
||||
an administrator ever needs to deactivate the service worker quickly.
|
||||
|
||||
## Fail-safe
|
||||
|
||||
To deactivate the service worker, remove or rename the
|
||||
`ngsw-config.json` file. When the service worker's request
|
||||
for `ngsw.json` returns a `404`, then the service worker
|
||||
removes all of its caches and de-registers itself,
|
||||
essentially self-destructing.
|
||||
|
||||
### Safety Worker
|
||||
|
||||
Also included in the `@angular/service-worker` NPM package is a small
|
||||
script `safety-worker.js`, which when loaded will unregister itself
|
||||
from the browser. This script can be used as a last resort to get rid
|
||||
of unwanted service workers already installed on client pages.
|
||||
|
||||
It's important to note that you cannot register this worker directly,
|
||||
as old clients with cached state may not see a new `index.html` which
|
||||
installs the different worker script. Instead, you must serve the
|
||||
contents of `safety-worker.js` at the URL of the Service Worker script
|
||||
you are trying to unregister, and must continue to do so until you are
|
||||
certain all users have successfully unregistered the old worker. For
|
||||
most sites, this means that you should serve the safety worker at the
|
||||
old Service Worker URL forever.
|
||||
|
||||
This script can be used both to deactivate `@angular/service-worker`
|
||||
as well as any other Service Workers which might have been served in
|
||||
the past on your site.
|
||||
|
||||
## More on Angular service workers
|
||||
|
||||
You may also be interested in the following:
|
||||
|
@ -19,7 +19,7 @@
|
||||
"routing": {
|
||||
"index": "/index.html",
|
||||
"routes": {
|
||||
"^(?!/docs/ts/latest|/guide/(?:cli-quickstart|metadata|ngmodule|service-worker-(?:getstart|comm|configref))/?$|/styleguide).*/(?!e?plnkr)[^/.]*$": {
|
||||
"^(?!/docs/.|(?:/guide/(?:cli-quickstart|metadata|ngmodule|service-worker-(?:getstart|comm|configref)|learning-angular)|/news/?)$|/testing|/api/(?:common/NgModel|platform-browser/AnimationDriver|testing|api)).*/(?!e?stackblitz|(?:NgFor|MaxLengthValidator)-|Control(?:Group)?|AnimationStateDeclarationMetadata|CORE_DIRECTIVES|PLATFORM_PIPES|DirectiveMetadata|HTTP_PROVIDERS)[^/.]*$": {
|
||||
"match": "regex"
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ new as of May 2017 and not very stable yet.
|
||||
- Test all packages: `bazel test packages/...`
|
||||
|
||||
You can use [ibazel] to get a "watch mode" that continuously
|
||||
keeps the outputs up-to-date as you save sources.
|
||||
keeps the outputs up-to-date as you save sources.
|
||||
|
||||
### Debugging a Node Test
|
||||
|
||||
@ -68,44 +68,6 @@ keeps the outputs up-to-date as you save sources.
|
||||
|
||||
The process should automatically connect to the debugger.
|
||||
|
||||
### Debugging a Node Test in VSCode
|
||||
|
||||
First time setup:
|
||||
- Go to Debug > Add configuration (in the menu bar) to open `launch.json`
|
||||
- Add the following to the `configurations` array:
|
||||
|
||||
```
|
||||
{
|
||||
"name": "Attach (inspect)",
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"port": 9229,
|
||||
"address": "localhost",
|
||||
"restart": false,
|
||||
"sourceMaps": true,
|
||||
"localRoot": "${workspaceRoot}",
|
||||
"remoteRoot": null
|
||||
},
|
||||
{
|
||||
"name": "Attach (no-sm,inspect)",
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"port": 9229,
|
||||
"address": "localhost",
|
||||
"restart": false,
|
||||
"sourceMaps": false,
|
||||
"localRoot": "${workspaceRoot}",
|
||||
"remoteRoot": null
|
||||
},
|
||||
```
|
||||
|
||||
The easiest way to debug a test for now is to add a `debugger` statement in the code
|
||||
and launch the bazel corresponding test (`bazel test <target> --config=debug`).
|
||||
|
||||
Bazel will wait on a connection. Go to the debug view (by clicking on the sidebar or
|
||||
Apple+Shift+D on Mac) and click on the green play icon next to the configuration name
|
||||
(ie `Attach (inspect)`).
|
||||
|
||||
### Debugging a Karma Test
|
||||
|
||||
- Run test: `bazel run packages/core/test:test_web`
|
||||
|
@ -20,15 +20,6 @@ $ ng new cli-hello-world
|
||||
# typescript version
|
||||
```
|
||||
|
||||
## Render3 tests
|
||||
|
||||
The directory `hello_world_cli` contains a test for render3 used with the angular cli.
|
||||
|
||||
If the Angular CLI is modified to generate a render3 application this should be replaced with that project.
|
||||
|
||||
If the render3 is updated to support the Angular 5 bootstrap a version of this project should be created that
|
||||
uses the Angular 5 bootstrap.
|
||||
|
||||
## Writing an integration test
|
||||
|
||||
The API for each test is:
|
||||
|
@ -14,28 +14,5 @@
|
||||
"bundle": 100661
|
||||
}
|
||||
}
|
||||
},
|
||||
"hello_world__render3__closure": {
|
||||
"master": {
|
||||
"uncompressed": {
|
||||
"bundle": 8153
|
||||
}
|
||||
}
|
||||
},
|
||||
"hello_world__render3__rollup": {
|
||||
"master": {
|
||||
"uncompressed": {
|
||||
"bundle": 34694
|
||||
}
|
||||
}
|
||||
},
|
||||
"hello_world__render3__cli": {
|
||||
"master": {
|
||||
"uncompressed": {
|
||||
"inline": 1447,
|
||||
"main": 40513,
|
||||
"polyfills": 61085
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,60 +0,0 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"project": {
|
||||
"name": "hw2"
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"root": "src",
|
||||
"outDir": "dist",
|
||||
"assets": [
|
||||
"assets",
|
||||
"favicon.ico"
|
||||
],
|
||||
"index": "index.html",
|
||||
"main": "main.ts",
|
||||
"polyfills": "polyfills.ts",
|
||||
"test": "test.ts",
|
||||
"tsconfig": "tsconfig.app.json",
|
||||
"testTsconfig": "tsconfig.spec.json",
|
||||
"prefix": "app",
|
||||
"styles": [
|
||||
"styles.css"
|
||||
],
|
||||
"scripts": [],
|
||||
"environmentSource": "environments/environment.ts",
|
||||
"environments": {
|
||||
"dev": "environments/environment.ts",
|
||||
"prod": "environments/environment.prod.ts"
|
||||
}
|
||||
}
|
||||
],
|
||||
"e2e": {
|
||||
"protractor": {
|
||||
"config": "./protractor.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": [
|
||||
{
|
||||
"project": "src/tsconfig.app.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
},
|
||||
{
|
||||
"project": "src/tsconfig.spec.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
},
|
||||
{
|
||||
"project": "e2e/tsconfig.e2e.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
}
|
||||
],
|
||||
"test": {
|
||||
"karma": {
|
||||
"config": "./karma.conf.js"
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"styleExt": "css",
|
||||
"component": {}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
# Hw2
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.7.0-beta.1.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
@ -1,14 +0,0 @@
|
||||
import { AppPage } from './app.po';
|
||||
|
||||
describe('hw2 App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('Welcome to app!');
|
||||
});
|
||||
});
|
@ -1,11 +0,0 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getParagraphText() {
|
||||
return element(by.css('app-root h1')).getText();
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular/cli'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular/cli/plugins/karma')
|
||||
],
|
||||
client:{
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
reports: [ 'html', 'lcovonly' ],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
angularCli: {
|
||||
environment: 'dev'
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
@ -1,33 +0,0 @@
|
||||
{
|
||||
"name": "hello_world__render3__cli",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build --prod --build-optimizer",
|
||||
"test": "echo no tests",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "file:../../dist/packages-dist/animations",
|
||||
"@angular/common": "file:../../dist/packages-dist/common",
|
||||
"@angular/compiler": "file:../../dist/packages-dist/compiler",
|
||||
"@angular/core": "file:../../dist/packages-dist/core",
|
||||
"@angular/forms": "file:../../dist/packages-dist/forms",
|
||||
"@angular/http": "file:../../dist/packages-dist/http",
|
||||
"@angular/platform-browser": "file:../../dist/packages-dist/platform-browser",
|
||||
"@angular/platform-browser-dynamic": "file:../../dist/packages-dist/platform-browser-dynamic",
|
||||
"@angular/router": "file:../../dist/packages-dist/router",
|
||||
"core-js": "2.4.1",
|
||||
"rxjs": "5.5.6",
|
||||
"zone.js": "0.8.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.7.0-beta.2",
|
||||
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
||||
"typescript": "2.6.2"
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./e2e/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: 'e2e/tsconfig.e2e.json'
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
@ -1,20 +0,0 @@
|
||||
<!--The content below is only a placeholder and can be replaced.-->
|
||||
<div style="text-align:center">
|
||||
<h1>
|
||||
Welcome to {{ title }}!
|
||||
</h1>
|
||||
<img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
|
||||
</div>
|
||||
<h2>Here are some links to help you start: </h2>
|
||||
<ul>
|
||||
<li>
|
||||
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -1,27 +0,0 @@
|
||||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
}).compileComponents();
|
||||
}));
|
||||
it('should create the app', async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
}));
|
||||
it(`should have as title 'app'`, async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app.title).toEqual('app');
|
||||
}));
|
||||
it('should render title in a h1 tag', async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
|
||||
}));
|
||||
});
|
@ -1,10 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'app';
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
imports: [],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
@ -1,3 +0,0 @@
|
||||
export const environment = {
|
||||
production: true
|
||||
};
|
@ -1,8 +0,0 @@
|
||||
// The file contents for the current environment will overwrite these during build.
|
||||
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
|
||||
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
|
||||
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false
|
||||
};
|
Binary file not shown.
Before Width: | Height: | Size: 5.3 KiB |
@ -1,14 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Hw2</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
@ -1,4 +0,0 @@
|
||||
import {ɵrenderComponent as renderComponent} from '@angular/core';
|
||||
import {AppComponent} from './app/app.component';
|
||||
|
||||
renderComponent(AppComponent as any);
|
@ -1,66 +0,0 @@
|
||||
/**
|
||||
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||
* You can add your own extra polyfills to this file.
|
||||
*
|
||||
* This file is divided into 2 sections:
|
||||
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||
* file.
|
||||
*
|
||||
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||
*
|
||||
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
|
||||
// import 'core-js/es6/symbol';
|
||||
// import 'core-js/es6/object';
|
||||
// import 'core-js/es6/function';
|
||||
// import 'core-js/es6/parse-int';
|
||||
// import 'core-js/es6/parse-float';
|
||||
// import 'core-js/es6/number';
|
||||
// import 'core-js/es6/math';
|
||||
// import 'core-js/es6/string';
|
||||
// import 'core-js/es6/date';
|
||||
// import 'core-js/es6/array';
|
||||
// import 'core-js/es6/regexp';
|
||||
// import 'core-js/es6/map';
|
||||
// import 'core-js/es6/weak-map';
|
||||
// import 'core-js/es6/set';
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/** IE10 and IE11 requires the following for the Reflect API. */
|
||||
// import 'core-js/es6/reflect';
|
||||
|
||||
|
||||
/** Evergreen browsers require these. **/
|
||||
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
|
||||
import 'core-js/es7/reflect';
|
||||
|
||||
|
||||
/**
|
||||
* Required to support Web Animations `@angular/platform-browser/animations`.
|
||||
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
|
||||
**/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by default for Angular itself.
|
||||
*/
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
@ -1 +0,0 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
@ -1,20 +0,0 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: any;
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
@ -1,16 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"baseUrl": "./",
|
||||
"module": "es2015",
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"test.ts",
|
||||
"**/*.spec.ts"
|
||||
],
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": true
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/spec",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/out-tsc",
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es5",
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
],
|
||||
"lib": [
|
||||
"es2017",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
{
|
||||
"rulesDirectory": [
|
||||
"node_modules/codelyzer"
|
||||
],
|
||||
"rules": {
|
||||
"arrow-return-shorthand": true,
|
||||
"callable-types": true,
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
true,
|
||||
"check-space"
|
||||
],
|
||||
"curly": true,
|
||||
"deprecation": {
|
||||
"severity": "warn"
|
||||
},
|
||||
"eofline": true,
|
||||
"forin": true,
|
||||
"import-blacklist": [
|
||||
true,
|
||||
"rxjs",
|
||||
"rxjs/Rx"
|
||||
],
|
||||
"import-spacing": true,
|
||||
"indent": [
|
||||
true,
|
||||
"spaces"
|
||||
],
|
||||
"interface-over-type-literal": true,
|
||||
"label-position": true,
|
||||
"max-line-length": [
|
||||
true,
|
||||
140
|
||||
],
|
||||
"member-access": false,
|
||||
"member-ordering": [
|
||||
true,
|
||||
{
|
||||
"order": [
|
||||
"static-field",
|
||||
"instance-field",
|
||||
"static-method",
|
||||
"instance-method"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-construct": true,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-super": true,
|
||||
"no-empty": false,
|
||||
"no-empty-interface": true,
|
||||
"no-eval": true,
|
||||
"no-inferrable-types": [
|
||||
true,
|
||||
"ignore-params"
|
||||
],
|
||||
"no-misused-new": true,
|
||||
"no-non-null-assertion": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-string-literal": false,
|
||||
"no-string-throw": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unnecessary-initializer": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-whitespace"
|
||||
],
|
||||
"prefer-const": true,
|
||||
"quotemark": [
|
||||
true,
|
||||
"single"
|
||||
],
|
||||
"radix": true,
|
||||
"semicolon": [
|
||||
true,
|
||||
"always"
|
||||
],
|
||||
"triple-equals": [
|
||||
true,
|
||||
"allow-null-check"
|
||||
],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"unified-signatures": true,
|
||||
"variable-name": false,
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
],
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"app",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"app",
|
||||
"kebab-case"
|
||||
],
|
||||
"no-output-on-prefix": true,
|
||||
"use-input-property-decorator": true,
|
||||
"use-output-property-decorator": true,
|
||||
"use-host-property-decorator": true,
|
||||
"no-input-rename": true,
|
||||
"no-output-rename": true,
|
||||
"use-life-cycle-interface": true,
|
||||
"use-pipe-transform-interface": true,
|
||||
"component-class-suffix": true,
|
||||
"directive-class-suffix": true
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# This script replaces 'ngDevMode' by false in @angular/core/render3 source code, so that this code can be eliminated.
|
||||
# This is a workaround for https://github.com/google/closure-compiler/issues/1601
|
||||
|
||||
find built/packages/core/src/render3/* -name '*.js' -exec sed -i '' -e "s/import '.\/ng_dev_mode';//g" {} \;
|
||||
find built/packages/core/src/render3/* -name '*.js' -exec sed -i '' -e 's/ngDevMode/false/g' {} \;
|
@ -1,22 +0,0 @@
|
||||
--compilation_level=ADVANCED_OPTIMIZATIONS
|
||||
--language_out=ES5
|
||||
--js_output_file=dist/bundle.js
|
||||
--output_manifest=dist/manifest.MF
|
||||
--variable_renaming_report=dist/variable_renaming_report
|
||||
--property_renaming_report=dist/property_renaming_report
|
||||
--create_source_map=%outname%.map
|
||||
|
||||
--warning_level=QUIET
|
||||
--dependency_mode=STRICT
|
||||
--rewrite_polyfills=false
|
||||
--jscomp_off=checkVars
|
||||
|
||||
--module_resolution=node
|
||||
--package_json_entry_names es2015
|
||||
--process_common_js_modules
|
||||
|
||||
--js built/**.js
|
||||
--entry_point=built/index
|
||||
|
||||
--output_wrapper "%output%
|
||||
//# sourceMappingURL=bundle.js.map"
|
@ -1,12 +0,0 @@
|
||||
import { browser, element, by } from 'protractor';
|
||||
|
||||
describe('Hello world E2E Tests', function () {
|
||||
it('should display: Hello world!', function () {
|
||||
browser.ignoreSynchronization = true;
|
||||
browser.get('');
|
||||
const div = element(by.css('div'));
|
||||
expect(div.getText()).toEqual('Hello world!');
|
||||
element(by.css('input')).sendKeys('!');
|
||||
expect(div.getText()).toEqual('Hello world!!');
|
||||
});
|
||||
});
|
@ -1,15 +0,0 @@
|
||||
{
|
||||
"open": false,
|
||||
"logLevel": "silent",
|
||||
"port": 8080,
|
||||
"server": {
|
||||
"baseDir": "src",
|
||||
"routes": {
|
||||
"/dist": "dist",
|
||||
"/node_modules": "node_modules"
|
||||
},
|
||||
"middleware": {
|
||||
"0": null
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
exports.config = {
|
||||
specs: [
|
||||
'../built/e2e/*.e2e-spec.js'
|
||||
],
|
||||
capabilities: {
|
||||
browserName: 'chrome',
|
||||
chromeOptions: {
|
||||
args: ['--no-sandbox'],
|
||||
binary: process.env.CHROME_BIN,
|
||||
}
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:8080/',
|
||||
framework: 'jasmine'
|
||||
};
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "../built/e2e",
|
||||
"types": ["jasmine"],
|
||||
// TODO(alexeagle): was required for Protractor 4.0.11
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
{
|
||||
"name": "angular-integration",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"typescript": "file:../../node_modules/typescript"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jasmine": "2.5.41",
|
||||
"concurrently": "3.4.0",
|
||||
"lite-server": "2.2.2",
|
||||
"protractor": "file:../../node_modules/protractor",
|
||||
"google-closure-compiler": "20171023.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "webdriver-manager update --gecko false --standalone false $CHROMEDRIVER_VERSION_ARG && mkdir -p built && cp -rf ../../dist/packages ./built/packages && ./clean_ngDevMode.sh",
|
||||
"closure": "java -jar node_modules/google-closure-compiler/compiler.jar --flagfile closure.conf && mkdir -p dist/packages && cp -rf ../../packages/core dist/packages/core",
|
||||
"test": "tsc && yarn run closure && concurrently \"yarn run serve\" \"yarn run protractor\" --kill-others --success first",
|
||||
"serve": "lite-server -c e2e/browser.config.json",
|
||||
"preprotractor": "tsc -p e2e",
|
||||
"protractor": "protractor e2e/protractor.config.js"
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Hello World</title>
|
||||
<base href="/">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<hello-world></hello-world>
|
||||
|
||||
<script src="dist/bundle.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,38 +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 {defineComponent, renderComponent, detectChanges, T, t, E, e, L, p, b, b1} from '../built/packages/core/src/render3';
|
||||
import {ComponentDef} from '../built/packages/core/src/render3/interfaces/definition';
|
||||
|
||||
export class HelloWorld {
|
||||
name: string = "world";
|
||||
|
||||
/** @nocollapse */
|
||||
static ngComponentDef: ComponentDef<HelloWorld> = defineComponent({
|
||||
type: HelloWorld,
|
||||
tag: 'hello-world',
|
||||
template: function (ctx: HelloWorld, cm: boolean) {
|
||||
if (cm) {
|
||||
E(0, 'div');
|
||||
T(1);
|
||||
e();
|
||||
E(2, 'input');
|
||||
L('input', (e) => {
|
||||
ctx.name = (<HTMLInputElement>e.target).value;
|
||||
detectChanges(component);
|
||||
});
|
||||
e();
|
||||
}
|
||||
t(1, b1('Hello ', ctx.name, '!'));
|
||||
p(2, 'value', b(ctx.name));
|
||||
},
|
||||
factory: () => new HelloWorld()
|
||||
});
|
||||
}
|
||||
|
||||
const component = renderComponent(HelloWorld);
|
@ -1,25 +0,0 @@
|
||||
{
|
||||
"angularCompilerOptions": {
|
||||
"annotationsAs": "static fields",
|
||||
"annotateForClosureCompiler": true,
|
||||
"alwaysCompileGeneratedCode": true
|
||||
},
|
||||
|
||||
"compilerOptions": {
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"target": "es5",
|
||||
"noImplicitAny": false,
|
||||
"sourceMap": false,
|
||||
"experimentalDecorators": true,
|
||||
"outDir": "built",
|
||||
"rootDir": "./src",
|
||||
"declaration": true,
|
||||
"types": [],
|
||||
"lib": ["es2015", "dom"]
|
||||
},
|
||||
"files": [
|
||||
"src/index.ts"
|
||||
]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,12 +0,0 @@
|
||||
import { browser, element, by } from 'protractor';
|
||||
|
||||
describe('Hello world E2E Tests', function () {
|
||||
it('should display: Hello world!', function () {
|
||||
browser.ignoreSynchronization = true;
|
||||
browser.get('');
|
||||
const div = element(by.css('div'));
|
||||
expect(div.getText()).toEqual('Hello world!');
|
||||
element(by.css('input')).sendKeys('!');
|
||||
expect(div.getText()).toEqual('Hello world!!');
|
||||
});
|
||||
});
|
@ -1,15 +0,0 @@
|
||||
{
|
||||
"open": false,
|
||||
"logLevel": "silent",
|
||||
"port": 8080,
|
||||
"server": {
|
||||
"baseDir": "src",
|
||||
"routes": {
|
||||
"/dist": "dist",
|
||||
"/node_modules": "node_modules"
|
||||
},
|
||||
"middleware": {
|
||||
"0": null
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
exports.config = {
|
||||
specs: [
|
||||
'../built/e2e/*.e2e-spec.js'
|
||||
],
|
||||
capabilities: {
|
||||
browserName: 'chrome',
|
||||
chromeOptions: {
|
||||
args: ['--no-sandbox'],
|
||||
binary: process.env.CHROME_BIN,
|
||||
}
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:8080/',
|
||||
framework: 'jasmine'
|
||||
};
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "../built/e2e",
|
||||
"types": ["jasmine"],
|
||||
// TODO(alexeagle): was required for Protractor 4.0.11
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
{
|
||||
"name": "angular-integration",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "file:../../dist/packages-dist/animations",
|
||||
"@angular/common": "file:../../dist/packages-dist/common",
|
||||
"@angular/compiler": "file:../../dist/packages-dist/compiler",
|
||||
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
||||
"@angular/core": "file:../../dist/packages-dist/core",
|
||||
"@angular/platform-browser": "file:../../dist/packages-dist/platform-browser",
|
||||
"@angular/platform-server": "file:../../dist/packages-dist/platform-server",
|
||||
"rxjs": "file:../../node_modules/rxjs",
|
||||
"typescript": "file:../../node_modules/typescript"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jasmine": "2.5.41",
|
||||
"concurrently": "3.4.0",
|
||||
"lite-server": "2.2.2",
|
||||
"protractor": "file:../../node_modules/protractor",
|
||||
"rollup": "0.54.0",
|
||||
"rollup-plugin-angular-optimizer": "0.2.0",
|
||||
"rollup-plugin-commonjs": "8.2.6",
|
||||
"rollup-plugin-node-resolve": "3.0.2",
|
||||
"rollup-plugin-uglify": "2.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "webdriver-manager update --gecko false --standalone false $CHROMEDRIVER_VERSION_ARG",
|
||||
"rollup": "tsc && rollup -c rollup.config.js",
|
||||
"test": "yarn run rollup && concurrently \"yarn run serve\" \"yarn run protractor\" --kill-others --success first",
|
||||
"serve": "lite-server -c e2e/browser.config.json",
|
||||
"preprotractor": "tsc -p e2e",
|
||||
"protractor": "protractor e2e/protractor.config.js"
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
import buildOptimizer from 'rollup-plugin-angular-optimizer'
|
||||
import commonjs from 'rollup-plugin-commonjs';
|
||||
import nodeResolve from 'rollup-plugin-node-resolve';
|
||||
import uglify from 'rollup-plugin-uglify';
|
||||
|
||||
export default {
|
||||
input: `built/index.js`,
|
||||
output: {
|
||||
name: 'hw',
|
||||
file: `dist/bundle.js`,
|
||||
format: 'iife',
|
||||
sourcemap: true
|
||||
},
|
||||
plugins: [
|
||||
buildOptimizer(),
|
||||
nodeResolve({jsnext: true, module: true}),
|
||||
commonjs({
|
||||
include: 'node_modules/rxjs/**'
|
||||
}),
|
||||
uglify({
|
||||
mangle: true,
|
||||
compress: {
|
||||
global_defs: {
|
||||
'ngDevMode': false,
|
||||
}
|
||||
}
|
||||
})
|
||||
],
|
||||
external: []
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Hello World</title>
|
||||
<base href="/">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<hello-world></hello-world>
|
||||
|
||||
<script src="dist/bundle.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,38 +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 {ɵdefineComponent as defineComponent, ɵdetectChanges as detectChanges, ɵrenderComponent as renderComponent, ɵT as T, ɵt as t, ɵE as E, ɵe as e, ɵp as p, ɵL as L, ɵb as b, ɵb1 as b1} from '@angular/core';
|
||||
import {ComponentDef} from '@angular/core/src/render3/interfaces/definition';
|
||||
|
||||
export class HelloWorld {
|
||||
name: string = "world";
|
||||
|
||||
/** @nocollapse */
|
||||
static ngComponentDef: ComponentDef<HelloWorld> = defineComponent({
|
||||
type: HelloWorld,
|
||||
tag: 'hello-world',
|
||||
template: function (ctx: HelloWorld, cm: boolean) {
|
||||
if (cm) {
|
||||
E(0, 'div');
|
||||
T(1);
|
||||
e();
|
||||
E(2, 'input');
|
||||
L('input', (e) => {
|
||||
ctx.name = (<HTMLInputElement>e.target).value;
|
||||
detectChanges(component);
|
||||
});
|
||||
e();
|
||||
}
|
||||
t(1, b1('Hello ', ctx.name, '!'));
|
||||
p(2, 'value', b(ctx.name));
|
||||
},
|
||||
factory: () => new HelloWorld()
|
||||
});
|
||||
}
|
||||
|
||||
const component = renderComponent(HelloWorld);
|
@ -1,25 +0,0 @@
|
||||
{
|
||||
"angularCompilerOptions": {
|
||||
"annotationsAs": "static fields",
|
||||
"annotateForClosureCompiler": true,
|
||||
"alwaysCompileGeneratedCode": true
|
||||
},
|
||||
|
||||
"compilerOptions": {
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"target": "es5",
|
||||
"noImplicitAny": false,
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"outDir": "built",
|
||||
"rootDir": "./src",
|
||||
"declaration": true,
|
||||
"types": [],
|
||||
"lib": ["es2015", "dom"]
|
||||
},
|
||||
"files": [
|
||||
"src/index.ts"
|
||||
]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -24,8 +24,7 @@
|
||||
"scripts": {
|
||||
"postinstall": "webdriver-manager update --gecko false --standalone false $CHROMEDRIVER_VERSION_ARG",
|
||||
"closure": "java -jar node_modules/google-closure-compiler/compiler.jar --flagfile closure.conf",
|
||||
"test": "ngc && yarn run closure && concurrently \"yarn run serve\" \"yarn run protractor\" --kill-others --success first && npm run test-locale-folder",
|
||||
"test-locale-folder": "node test-locale-folder.js",
|
||||
"test": "ngc && yarn run closure && concurrently \"yarn run serve\" \"yarn run protractor\" --kill-others --success first",
|
||||
"serve": "lite-server -c e2e/browser.config.json",
|
||||
"preprotractor": "tsc -p e2e",
|
||||
"protractor": "protractor e2e/protractor.config.js"
|
||||
|
@ -1,14 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const packageJson = require('@angular/common/package.json');
|
||||
const localesFolder = packageJson['locales'];
|
||||
if (!localesFolder) {
|
||||
throw new Error(`@angular/common/package.json does not contain 'locales' entry.`)
|
||||
}
|
||||
const enLocalePath = `@angular/common/${localesFolder}/en`;
|
||||
try {
|
||||
require.resolve(enLocalePath);
|
||||
} catch (err) {
|
||||
throw new Error(`@angular/common does not contain 'en' locale in ${enLocalePath}.`)
|
||||
}
|
@ -19,7 +19,7 @@ rm_cache
|
||||
mkdir $cache
|
||||
trap rm_cache EXIT
|
||||
|
||||
for testDir in $(ls | grep -Ev 'node_modules|render3') ; do
|
||||
for testDir in $(ls | grep -v node_modules) ; do
|
||||
[[ -d "$testDir" ]] || continue
|
||||
echo "#################################"
|
||||
echo "Running integration test $testDir"
|
||||
@ -29,19 +29,15 @@ for testDir in $(ls | grep -Ev 'node_modules|render3') ; do
|
||||
rm -rf dist
|
||||
yarn install --cache-folder ../$cache
|
||||
yarn test || exit 1
|
||||
# Track payload size for cli-hello-world and hello_world__closure and the render3 tests
|
||||
if [[ $testDir == cli-hello-world ]] || [[ $testDir == hello_world__closure ]] || [[ $testDir == hello_world__render3__closure ]] || [[ $testDir == hello_world__render3__rollup ]] || [[ $testDir == hello_world__render3__cli ]]; then
|
||||
if [[ $testDir == cli-hello-world ]] || [[ $testDir == hello_world__render3__cli ]]; then
|
||||
# Track payload size for cli-hello-world and hello_world__closure
|
||||
if [[ $testDir == cli-hello-world ]] || [[ $testDir == hello_world__closure ]]; then
|
||||
if [[ $testDir == cli-hello-world ]]; then
|
||||
yarn build
|
||||
fi
|
||||
if [[ -v TRAVIS ]]; then
|
||||
trackPayloadSize "$testDir" "dist/*.js" true false "${thisDir}/_payload-limits.json"
|
||||
fi
|
||||
fi
|
||||
if [[ -v TRAVIS ]]; then
|
||||
# remove the temporary node modules directory to save space.
|
||||
rm -rf node_modules
|
||||
fi
|
||||
)
|
||||
done
|
||||
|
||||
|
@ -59,7 +59,6 @@ module.exports = function(config) {
|
||||
'dist/all/@angular/benchpress/**',
|
||||
'dist/all/@angular/compiler-cli/**',
|
||||
'dist/all/@angular/compiler/test/aot/**',
|
||||
'dist/all/@angular/compiler/test/render3/**',
|
||||
'dist/all/@angular/examples/**/e2e_test/*',
|
||||
'dist/all/@angular/language-service/**',
|
||||
'dist/all/@angular/router/test/**',
|
||||
|
@ -23,7 +23,6 @@ describe('tree benchmark perf', () => {
|
||||
|
||||
Benchmarks.forEach(benchmark => {
|
||||
describe(benchmark.id, () => {
|
||||
// This is actually a destroyOnly benchmark
|
||||
it('should work for createOnly', (done) => {
|
||||
runTreeBenchmark({
|
||||
id: 'createOnly',
|
||||
@ -33,15 +32,6 @@ describe('tree benchmark perf', () => {
|
||||
}).then(done, done.fail);
|
||||
});
|
||||
|
||||
it('should work for createOnlyForReal', (done) => {
|
||||
runTreeBenchmark({
|
||||
id: 'createOnlyForReal',
|
||||
benchmark,
|
||||
prepare: () => $(DestroyBtn).click(),
|
||||
work: () => $(CreateBtn).click()
|
||||
}).then(done, done.fail);
|
||||
});
|
||||
|
||||
it('should work for createDestroy', (done) => {
|
||||
runTreeBenchmark({
|
||||
id: 'createDestroy',
|
||||
|
@ -26,8 +26,6 @@
|
||||
</div>
|
||||
|
||||
<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>');
|
||||
|
@ -6,8 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ɵC as C, ɵE as E, ɵT as T, ɵV as V, ɵb as b, ɵcR as cR, ɵcr as cr, ɵdefineComponent as defineComponent, ɵdetectChanges as detectChanges, ɵe as e, ɵs as s, ɵt as t, ɵv as v} from '@angular/core';
|
||||
import {ComponentDef} from '@angular/core/src/render3/interfaces/definition';
|
||||
import {ɵC as C, ɵE as E, ɵT as T, ɵV as V, ɵb as b, ɵc as c, ɵcR as cR, ɵcr as cr, ɵdefineComponent as defineComponent, ɵdetectChanges as detectChanges, ɵe as e, ɵs as s, ɵt as t, ɵv as v} from '@angular/core';
|
||||
import {ComponentDef} from '@angular/core/src/render3/definition_interfaces';
|
||||
|
||||
import {TableCell, buildTable, emptyTable} from '../util';
|
||||
|
||||
@ -23,7 +23,10 @@ export class LargeTableComponent {
|
||||
E(0, 'table');
|
||||
{
|
||||
E(1, 'tbody');
|
||||
{ C(2); }
|
||||
{
|
||||
C(2);
|
||||
c();
|
||||
}
|
||||
e();
|
||||
}
|
||||
e();
|
||||
@ -36,6 +39,7 @@ export class LargeTableComponent {
|
||||
if (cm1) {
|
||||
E(0, 'tr');
|
||||
C(1);
|
||||
c();
|
||||
e();
|
||||
}
|
||||
cR(1);
|
||||
|
@ -28,8 +28,6 @@
|
||||
</div>
|
||||
|
||||
<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>');
|
||||
|
@ -6,8 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ɵC as C, ɵE as E, ɵT as T, ɵV as V, ɵb as b, ɵb1 as b1, ɵcR as cR, ɵcr as cr, ɵdefineComponent as defineComponent, ɵdetectChanges as _detectChanges, ɵe as e, ɵp as p, ɵr as r, ɵs as s, ɵt as t, ɵv as v} from '@angular/core';
|
||||
import {ComponentDef} from '@angular/core/src/render3/interfaces/definition';
|
||||
import {ɵC as C, ɵD as D, ɵE as E, ɵT as T, ɵV as V, ɵb as b, ɵb1 as b1, ɵc as c, ɵcR as cR, ɵcr as cr, ɵdefineComponent as defineComponent, ɵdetectChanges as _detectChanges, ɵe as e, ɵp as p, ɵs as s, ɵt as t, ɵv as v} from '@angular/core';
|
||||
import {ComponentDef} from '@angular/core/src/render3/definition_interfaces';
|
||||
|
||||
import {TreeNode, buildTree, emptyTree} from '../util';
|
||||
|
||||
@ -44,7 +44,9 @@ export class TreeComponent {
|
||||
{ T(1); }
|
||||
e();
|
||||
C(2);
|
||||
c();
|
||||
C(3);
|
||||
c();
|
||||
}
|
||||
s(0, 'background-color', b(ctx.data.depth % 2 ? '' : 'grey'));
|
||||
t(1, b1(' ', ctx.data.value, ' '));
|
||||
@ -54,12 +56,13 @@ export class TreeComponent {
|
||||
let cm0 = V(0);
|
||||
{
|
||||
if (cm0) {
|
||||
E(0, TreeComponent);
|
||||
E(0, TreeComponent.ngComponentDef);
|
||||
{ D(1, TreeComponent.ngComponentDef.n(), TreeComponent.ngComponentDef); }
|
||||
e();
|
||||
}
|
||||
p(0, 'data', b(ctx.data.left));
|
||||
TreeComponent.ngComponentDef.h(1, 0);
|
||||
r(1, 0);
|
||||
TreeComponent.ngComponentDef.r(1, 0);
|
||||
}
|
||||
v();
|
||||
}
|
||||
@ -71,12 +74,13 @@ export class TreeComponent {
|
||||
let cm0 = V(0);
|
||||
{
|
||||
if (cm0) {
|
||||
E(0, TreeComponent);
|
||||
E(0, TreeComponent.ngComponentDef);
|
||||
{ D(1, TreeComponent.ngComponentDef.n(), TreeComponent.ngComponentDef); }
|
||||
e();
|
||||
}
|
||||
p(0, 'data', b(ctx.data.right));
|
||||
TreeComponent.ngComponentDef.h(1, 0);
|
||||
r(1, 0);
|
||||
TreeComponent.ngComponentDef.r(1, 0);
|
||||
}
|
||||
v();
|
||||
}
|
||||
@ -88,7 +92,7 @@ export class TreeComponent {
|
||||
});
|
||||
}
|
||||
|
||||
export class TreeFunction {
|
||||
export class TreeFunction extends TreeComponent {
|
||||
data: TreeNode = emptyTree;
|
||||
|
||||
/** @nocollapse */
|
||||
@ -106,19 +110,17 @@ export class TreeFunction {
|
||||
|
||||
export function TreeTpl(ctx: TreeNode, cm: boolean) {
|
||||
if (cm) {
|
||||
E(0, 'tree');
|
||||
{
|
||||
E(1, 'span');
|
||||
{ T(2); }
|
||||
e();
|
||||
C(3);
|
||||
C(4);
|
||||
}
|
||||
E(0, 'span');
|
||||
{ T(1); }
|
||||
e();
|
||||
C(2);
|
||||
c();
|
||||
C(3);
|
||||
c();
|
||||
}
|
||||
s(1, 'background-color', b(ctx.depth % 2 ? '' : 'grey'));
|
||||
t(2, b1(' ', ctx.value, ' '));
|
||||
cR(3);
|
||||
s(0, 'background-color', b(ctx.depth % 2 ? '' : 'grey'));
|
||||
t(1, b1(' ', ctx.value, ' '));
|
||||
cR(2);
|
||||
{
|
||||
if (ctx.left != null) {
|
||||
let cm0 = V(0);
|
||||
@ -127,7 +129,7 @@ export function TreeTpl(ctx: TreeNode, cm: boolean) {
|
||||
}
|
||||
}
|
||||
cr();
|
||||
cR(4);
|
||||
cR(3);
|
||||
{
|
||||
if (ctx.right != null) {
|
||||
let cm0 = V(0);
|
||||
|
@ -28,8 +28,6 @@
|
||||
</div>
|
||||
|
||||
<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>');
|
||||
|
@ -1,7 +1,6 @@
|
||||
{
|
||||
"name": "angular-srcs",
|
||||
"version": "TODO this should be 6.0.0-beta.0, workaround",
|
||||
"version": "6.0.0-beta.2",
|
||||
"version": "5.2.3",
|
||||
"private": true,
|
||||
"branchPattern": "2.0.*",
|
||||
"description": "Angular - a web framework for modern web apps",
|
||||
|
@ -74,7 +74,6 @@ def _ngc_tsconfig(ctx, files, srcs, **kwargs):
|
||||
"generateCodeForLibraries": False,
|
||||
"allowEmptyCodegenFiles": True,
|
||||
"enableSummariesForJit": True,
|
||||
"fullTemplateTypeCheck": ctx.attr.type_check,
|
||||
# FIXME: wrong place to de-dupe
|
||||
"expectedOut": depset([o.path for o in expected_outs]).to_list(),
|
||||
"preserveWhitespaces": False,
|
||||
@ -264,8 +263,6 @@ NG_MODULE_ATTRIBUTES = {
|
||||
".html",
|
||||
]),
|
||||
|
||||
"type_check": attr.bool(default = True),
|
||||
|
||||
"no_i18n": attr.bool(default = False),
|
||||
|
||||
"compiler": attr.label(
|
||||
|
@ -11,7 +11,6 @@
|
||||
"dependencies": {
|
||||
"tslib": "^1.7.1"
|
||||
},
|
||||
"locales": "locales",
|
||||
"peerDependencies": {
|
||||
"rxjs": "^5.5.0",
|
||||
"@angular/core": "0.0.0-PLACEHOLDER"
|
||||
|
@ -14,7 +14,6 @@ import {LocationStrategy} from './location_strategy';
|
||||
/** @experimental */
|
||||
export interface PopStateEvent {
|
||||
pop?: boolean;
|
||||
state?: any;
|
||||
type?: string;
|
||||
url?: string;
|
||||
}
|
||||
@ -57,7 +56,6 @@ export class Location {
|
||||
this._subject.emit({
|
||||
'url': this.path(true),
|
||||
'pop': true,
|
||||
'state': ev.state,
|
||||
'type': ev.type,
|
||||
});
|
||||
});
|
||||
@ -105,16 +103,16 @@ export class Location {
|
||||
* Changes the browsers URL to the normalized version of the given URL, and pushes a
|
||||
* new item onto the platform's history.
|
||||
*/
|
||||
go(path: string, query: string = '', state: any = null): void {
|
||||
this._platformStrategy.pushState(state, '', path, query);
|
||||
go(path: string, query: string = ''): void {
|
||||
this._platformStrategy.pushState(null, '', path, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the browsers URL to the normalized version of the given URL, and replaces
|
||||
* the top item on the platform's history stack.
|
||||
*/
|
||||
replaceState(path: string, query: string = '', state: any = null): void {
|
||||
this._platformStrategy.replaceState(state, '', path, query);
|
||||
replaceState(path: string, query: string = ''): void {
|
||||
this._platformStrategy.replaceState(null, '', path, query);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,10 +58,7 @@ export const LOCATION_INITIALIZED = new InjectionToken<Promise<any>>('Location I
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
export interface LocationChangeEvent {
|
||||
type: string;
|
||||
state: any;
|
||||
}
|
||||
export interface LocationChangeEvent { type: string; }
|
||||
|
||||
/**
|
||||
* @experimental
|
||||
|
@ -19,7 +19,7 @@ import {ISubscription} from 'rxjs/Subscription';
|
||||
@Injectable()
|
||||
export class SpyLocation implements Location {
|
||||
urlChanges: string[] = [];
|
||||
private _history: LocationState[] = [new LocationState('', '', null)];
|
||||
private _history: LocationState[] = [new LocationState('', '')];
|
||||
private _historyIndex: number = 0;
|
||||
/** @internal */
|
||||
_subject: EventEmitter<any> = new EventEmitter();
|
||||
@ -34,8 +34,6 @@ export class SpyLocation implements Location {
|
||||
|
||||
path(): string { return this._history[this._historyIndex].path; }
|
||||
|
||||
private state(): string { return this._history[this._historyIndex].state; }
|
||||
|
||||
isCurrentPathEqualTo(path: string, query: string = ''): boolean {
|
||||
const givenPath = path.endsWith('/') ? path.substring(0, path.length - 1) : path;
|
||||
const currPath =
|
||||
@ -62,13 +60,13 @@ export class SpyLocation implements Location {
|
||||
return this._baseHref + url;
|
||||
}
|
||||
|
||||
go(path: string, query: string = '', state: any = null) {
|
||||
go(path: string, query: string = '') {
|
||||
path = this.prepareExternalUrl(path);
|
||||
|
||||
if (this._historyIndex > 0) {
|
||||
this._history.splice(this._historyIndex + 1);
|
||||
}
|
||||
this._history.push(new LocationState(path, query, state));
|
||||
this._history.push(new LocationState(path, query));
|
||||
this._historyIndex = this._history.length - 1;
|
||||
|
||||
const locationState = this._history[this._historyIndex - 1];
|
||||
@ -81,7 +79,7 @@ export class SpyLocation implements Location {
|
||||
this._subject.emit({'url': url, 'pop': false});
|
||||
}
|
||||
|
||||
replaceState(path: string, query: string = '', state: any = null) {
|
||||
replaceState(path: string, query: string = '') {
|
||||
path = this.prepareExternalUrl(path);
|
||||
|
||||
const history = this._history[this._historyIndex];
|
||||
@ -91,7 +89,6 @@ export class SpyLocation implements Location {
|
||||
|
||||
history.path = path;
|
||||
history.query = query;
|
||||
history.state = state;
|
||||
|
||||
const url = path + (query.length > 0 ? ('?' + query) : '');
|
||||
this.urlChanges.push('replace: ' + url);
|
||||
@ -100,14 +97,14 @@ export class SpyLocation implements Location {
|
||||
forward() {
|
||||
if (this._historyIndex < (this._history.length - 1)) {
|
||||
this._historyIndex++;
|
||||
this._subject.emit({'url': this.path(), 'state': this.state(), 'pop': true});
|
||||
this._subject.emit({'url': this.path(), 'pop': true});
|
||||
}
|
||||
}
|
||||
|
||||
back() {
|
||||
if (this._historyIndex > 0) {
|
||||
this._historyIndex--;
|
||||
this._subject.emit({'url': this.path(), 'state': this.state(), 'pop': true});
|
||||
this._subject.emit({'url': this.path(), 'pop': true});
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,5 +118,10 @@ export class SpyLocation implements Location {
|
||||
}
|
||||
|
||||
class LocationState {
|
||||
constructor(public path: string, public query: string, public state: any) {}
|
||||
path: string;
|
||||
query: string;
|
||||
constructor(path: string, query: string) {
|
||||
this.path = path;
|
||||
this.query = query;
|
||||
}
|
||||
}
|
||||
|
@ -38,8 +38,6 @@ export function isNgDiagnostic(diagnostic: any): diagnostic is Diagnostic {
|
||||
}
|
||||
|
||||
export interface CompilerOptions extends ts.CompilerOptions {
|
||||
// NOTE: These comments and aio/content/guides/aot-compiler.md should be kept in sync.
|
||||
|
||||
// Write statistics about compilation (e.g. total time, ...)
|
||||
// Note: this is the --diagnostics command line option from TS (which is @internal
|
||||
// on ts.CompilerOptions interface).
|
||||
@ -161,17 +159,6 @@ export interface CompilerOptions extends ts.CompilerOptions {
|
||||
*/
|
||||
enableSummariesForJit?: boolean;
|
||||
|
||||
/**
|
||||
* Tells the compiler to generate definitions using the Render3 style code generation.
|
||||
* This option defaults to `false`.
|
||||
*
|
||||
* Not all features are supported with this option enabled. It is only supported
|
||||
* for experimentation and testing of Render3 style code generation.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
enableIvy?: boolean;
|
||||
|
||||
/** @internal */
|
||||
collectAllErrors?: boolean;
|
||||
}
|
||||
|
@ -6,9 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinMethod, BuiltinVar, CastExpr, ClassMethod, ClassStmt, CommaExpr, CommentStmt, CompileIdentifierMetadata, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, ExpressionStatement, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, NotExpr, ParseSourceFile, ParseSourceSpan, PartialModule, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, Statement, StatementVisitor, StaticSymbol, StmtModifier, ThrowStmt, TryCatchStmt, WriteKeyExpr, WritePropExpr, WriteVarExpr} from '@angular/compiler';
|
||||
import {AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinMethod, BuiltinVar, CastExpr, ClassStmt, CommaExpr, CommentStmt, CompileIdentifierMetadata, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, ExpressionStatement, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, NotExpr, ParseSourceFile, ParseSourceSpan, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, Statement, StatementVisitor, StaticSymbol, StmtModifier, ThrowStmt, TryCatchStmt, WriteKeyExpr, WritePropExpr, WriteVarExpr} from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
import {error} from './util';
|
||||
|
||||
export interface Node { sourceSpan: ParseSourceSpan|null; }
|
||||
|
||||
@ -30,10 +29,10 @@ export class TypeScriptNodeEmitter {
|
||||
const commentStmt = this.createCommentStatement(sourceFile, preamble);
|
||||
preambleStmts.push(commentStmt);
|
||||
}
|
||||
const sourceStatements =
|
||||
const sourceStatments =
|
||||
[...preambleStmts, ...converter.getReexports(), ...converter.getImports(), ...statements];
|
||||
converter.updateSourceMap(sourceStatements);
|
||||
const newSourceFile = ts.updateSourceFileNode(sourceFile, sourceStatements);
|
||||
converter.updateSourceMap(sourceStatments);
|
||||
const newSourceFile = ts.updateSourceFileNode(sourceFile, sourceStatments);
|
||||
return [newSourceFile, converter.getNodeMap()];
|
||||
}
|
||||
|
||||
@ -51,99 +50,7 @@ export class TypeScriptNodeEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given source file to include the changes specified in module.
|
||||
*
|
||||
* The module parameter is treated as a partial module meaning that the statements are added to
|
||||
* the module instead of replacing the module. Also, any classes are treated as partial classes
|
||||
* and the included members are added to the class with the same name instead of a new class
|
||||
* being created.
|
||||
*/
|
||||
export function updateSourceFile(
|
||||
sourceFile: ts.SourceFile, module: PartialModule,
|
||||
context: ts.TransformationContext): [ts.SourceFile, Map<ts.Node, Node>] {
|
||||
const converter = new _NodeEmitterVisitor();
|
||||
const prefixStatements = module.statements.filter(statement => !(statement instanceof ClassStmt));
|
||||
const classes =
|
||||
module.statements.filter(statement => statement instanceof ClassStmt) as ClassStmt[];
|
||||
const classMap = new Map(
|
||||
classes.map<[string, ClassStmt]>(classStatement => [classStatement.name, classStatement]));
|
||||
const classNames = new Set(classes.map(classStatement => classStatement.name));
|
||||
|
||||
const prefix =
|
||||
<ts.Statement[]>prefixStatements.map(statement => statement.visitStatement(converter, null));
|
||||
|
||||
// Add static methods to all the classes referenced in module.
|
||||
let newStatements = sourceFile.statements.map(node => {
|
||||
if (node.kind == ts.SyntaxKind.ClassDeclaration) {
|
||||
const classDeclaration = node as ts.ClassDeclaration;
|
||||
const name = classDeclaration.name;
|
||||
if (name) {
|
||||
const classStatement = classMap.get(name.text);
|
||||
if (classStatement) {
|
||||
classNames.delete(name.text);
|
||||
const classMemberHolder =
|
||||
converter.visitDeclareClassStmt(classStatement) as ts.ClassDeclaration;
|
||||
const newMethods =
|
||||
classMemberHolder.members.filter(member => member.kind !== ts.SyntaxKind.Constructor);
|
||||
const newMembers = [...classDeclaration.members, ...newMethods];
|
||||
|
||||
return ts.updateClassDeclaration(
|
||||
classDeclaration,
|
||||
/* decorators */ classDeclaration.decorators,
|
||||
/* modifiers */ classDeclaration.modifiers,
|
||||
/* name */ classDeclaration.name,
|
||||
/* typeParameters */ classDeclaration.typeParameters,
|
||||
/* heritageClauses */ classDeclaration.heritageClauses || [],
|
||||
/* members */ newMembers);
|
||||
}
|
||||
}
|
||||
}
|
||||
return node;
|
||||
});
|
||||
|
||||
// Validate that all the classes have been generated
|
||||
classNames.size == 0 ||
|
||||
error(
|
||||
`${classNames.size == 1 ? 'Class' : 'Classes'} "${Array.from(classNames.keys()).join(', ')}" not generated`);
|
||||
|
||||
// Add imports to the module required by the new methods
|
||||
const imports = converter.getImports();
|
||||
if (imports && imports.length) {
|
||||
// Find where the new imports should go
|
||||
const index = firstAfter(
|
||||
newStatements, statement => statement.kind === ts.SyntaxKind.ImportDeclaration ||
|
||||
statement.kind === ts.SyntaxKind.ImportEqualsDeclaration);
|
||||
newStatements =
|
||||
[...newStatements.slice(0, index), ...imports, ...prefix, ...newStatements.slice(index)];
|
||||
} else {
|
||||
newStatements = [...prefix, ...newStatements];
|
||||
}
|
||||
|
||||
converter.updateSourceMap(newStatements);
|
||||
const newSourceFile = ts.updateSourceFileNode(sourceFile, newStatements);
|
||||
|
||||
return [newSourceFile, converter.getNodeMap()];
|
||||
}
|
||||
|
||||
// Return the index after the first value in `a` that doesn't match the predicate after a value that
|
||||
// does or 0 if no values match.
|
||||
function firstAfter<T>(a: T[], predicate: (value: T) => boolean) {
|
||||
let index = 0;
|
||||
const len = a.length;
|
||||
for (; index < len; index++) {
|
||||
const value = a[index];
|
||||
if (predicate(value)) break;
|
||||
}
|
||||
if (index >= len) return 0;
|
||||
for (; index < len; index++) {
|
||||
const value = a[index];
|
||||
if (!predicate(value)) break;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
// A recorded node is a subtype of the node that is marked as being recorded. This is used
|
||||
// A recorded node is a subtype of the node that is marked as being recoreded. This is used
|
||||
// to ensure that NodeEmitterVisitor.record has been called on all nodes returned by the
|
||||
// NodeEmitterVisitor
|
||||
type RecordedNode<T extends ts.Node = ts.Node> = (T & { __recorded: any; }) | null;
|
||||
@ -325,12 +232,9 @@ class _NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor {
|
||||
const modifiers = this.getModifiers(stmt);
|
||||
const fields = stmt.fields.map(
|
||||
field => ts.createProperty(
|
||||
/* decorators */ undefined, /* modifiers */ translateModifiers(field.modifiers),
|
||||
field.name,
|
||||
/* decorators */ undefined, /* modifiers */ undefined, field.name,
|
||||
/* questionToken */ undefined,
|
||||
/* type */ undefined,
|
||||
field.initializer == null ? ts.createNull() :
|
||||
field.initializer.visitExpression(this, null)));
|
||||
/* type */ undefined, ts.createNull()));
|
||||
const getters = stmt.getters.map(
|
||||
getter => ts.createGetAccessor(
|
||||
/* decorators */ undefined, /* modifiers */ undefined, getter.name, /* parameters */[],
|
||||
@ -352,8 +256,7 @@ class _NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor {
|
||||
const methods = stmt.methods.filter(method => method.name)
|
||||
.map(
|
||||
method => ts.createMethod(
|
||||
/* decorators */ undefined,
|
||||
/* modifiers */ translateModifiers(method.modifiers),
|
||||
/* decorators */ undefined, /* modifiers */ undefined,
|
||||
/* astriskToken */ undefined, method.name !/* guarded by filter */,
|
||||
/* questionToken */ undefined, /* typeParameters */ undefined,
|
||||
method.params.map(
|
||||
@ -498,8 +401,7 @@ class _NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor {
|
||||
visitFunctionExpr(expr: FunctionExpr) {
|
||||
return this.record(
|
||||
expr, ts.createFunctionExpression(
|
||||
/* modifiers */ undefined, /* astriskToken */ undefined,
|
||||
/* name */ expr.name || undefined,
|
||||
/* modifiers */ undefined, /* astriskToken */ undefined, /* name */ undefined,
|
||||
/* typeParameters */ undefined,
|
||||
expr.params.map(
|
||||
p => ts.createParameter(
|
||||
@ -645,21 +547,3 @@ function getMethodName(methodRef: {name: string | null; builtin: BuiltinMethod |
|
||||
}
|
||||
throw new Error('Unexpected method reference form');
|
||||
}
|
||||
|
||||
function modifierFromModifier(modifier: StmtModifier): ts.Modifier {
|
||||
switch (modifier) {
|
||||
case StmtModifier.Exported:
|
||||
return ts.createToken(ts.SyntaxKind.ExportKeyword);
|
||||
case StmtModifier.Final:
|
||||
return ts.createToken(ts.SyntaxKind.ConstKeyword);
|
||||
case StmtModifier.Private:
|
||||
return ts.createToken(ts.SyntaxKind.PrivateKeyword);
|
||||
case StmtModifier.Static:
|
||||
return ts.createToken(ts.SyntaxKind.StaticKeyword);
|
||||
}
|
||||
return error(`unknown statement modifier`);
|
||||
}
|
||||
|
||||
function translateModifiers(modifiers: StmtModifier[] | null): ts.Modifier[]|undefined {
|
||||
return modifiers == null ? undefined : modifiers !.map(modifierFromModifier);
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
@ -7,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AotCompiler, AotCompilerHost, AotCompilerOptions, EmitterVisitorContext, FormattedMessageChain, GeneratedFile, MessageBundle, NgAnalyzedFile, NgAnalyzedModules, ParseSourceSpan, PartialModule, Position, Serializer, TypeScriptEmitter, Xliff, Xliff2, Xmb, core, createAotCompiler, getParseErrors, isFormattedError, isSyntaxError} from '@angular/compiler';
|
||||
import {AotCompiler, AotCompilerHost, AotCompilerOptions, EmitterVisitorContext, FormattedMessageChain, GeneratedFile, MessageBundle, NgAnalyzedFile, NgAnalyzedModules, ParseSourceSpan, Position, Serializer, TypeScriptEmitter, Xliff, Xliff2, Xmb, core, createAotCompiler, getParseErrors, isFormattedError, isSyntaxError} from '@angular/compiler';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as ts from 'typescript';
|
||||
@ -19,8 +18,7 @@ import {CompilerHost, CompilerOptions, CustomTransformers, DEFAULT_ERROR_CODE, D
|
||||
import {CodeGenerator, TsCompilerAotCompilerTypeCheckHostAdapter, getOriginalReferences} from './compiler_host';
|
||||
import {LowerMetadataCache, getExpressionLoweringTransformFactory} from './lower_expressions';
|
||||
import {getAngularEmitterTransformFactory} from './node_emitter_transform';
|
||||
import {getAngularClassTransformerFactory} from './r3_transform';
|
||||
import {GENERATED_FILES, StructureIsReused, createMessageDiagnostic, isInRootDir, ngToTsDiagnostic, tsStructureIsReused, userError} from './util';
|
||||
import {GENERATED_FILES, StructureIsReused, createMessageDiagnostic, isInRootDir, ngToTsDiagnostic, tsStructureIsReused} from './util';
|
||||
|
||||
|
||||
/**
|
||||
@ -67,10 +65,9 @@ class AngularCompilerProgram implements Program {
|
||||
private host: CompilerHost, oldProgram?: Program) {
|
||||
this.rootNames = [...rootNames];
|
||||
const [major, minor] = ts.version.split('.');
|
||||
|
||||
Number(major) > 2 || (Number(major) === 2 && Number(minor) >= 4) ||
|
||||
userError('The Angular Compiler requires TypeScript >= 2.4.');
|
||||
|
||||
if (Number(major) < 2 || (Number(major) === 2 && Number(minor) < 4)) {
|
||||
throw new Error('The Angular Compiler requires TypeScript >= 2.4.');
|
||||
}
|
||||
this.oldTsProgram = oldProgram ? oldProgram.getTsProgram() : undefined;
|
||||
if (oldProgram) {
|
||||
this.oldProgramLibrarySummaries = oldProgram.getLibrarySummaries();
|
||||
@ -82,6 +79,8 @@ class AngularCompilerProgram implements Program {
|
||||
const {host: bundleHost, indexName, errors} =
|
||||
createBundleIndexHost(options, this.rootNames, host);
|
||||
if (errors) {
|
||||
// TODO(tbosch): once we move MetadataBundler from tsc_wrapped into compiler_cli,
|
||||
// directly create ng.Diagnostic instead of using ts.Diagnostic here.
|
||||
this._optionsDiagnostics.push(...errors.map(e => ({
|
||||
category: e.category,
|
||||
messageText: e.messageText as string,
|
||||
@ -197,55 +196,7 @@ class AngularCompilerProgram implements Program {
|
||||
return this.compiler.listLazyRoutes(route, route ? undefined : this.analyzedModules);
|
||||
}
|
||||
|
||||
emit(parameters: {
|
||||
emitFlags?: EmitFlags,
|
||||
cancellationToken?: ts.CancellationToken,
|
||||
customTransformers?: CustomTransformers,
|
||||
emitCallback?: TsEmitCallback
|
||||
} = {}): ts.EmitResult {
|
||||
return this.options.enableIvy === true ? this._emitRender3(parameters) :
|
||||
this._emitRender2(parameters);
|
||||
}
|
||||
|
||||
private _emitRender3(
|
||||
{emitFlags = EmitFlags.Default, cancellationToken, customTransformers,
|
||||
emitCallback = defaultEmitCallback}: {
|
||||
emitFlags?: EmitFlags,
|
||||
cancellationToken?: ts.CancellationToken,
|
||||
customTransformers?: CustomTransformers,
|
||||
emitCallback?: TsEmitCallback
|
||||
} = {}): ts.EmitResult {
|
||||
const emitStart = Date.now();
|
||||
if ((emitFlags & (EmitFlags.JS | EmitFlags.DTS | EmitFlags.Metadata | EmitFlags.Codegen)) ===
|
||||
0) {
|
||||
return {emitSkipped: true, diagnostics: [], emittedFiles: []};
|
||||
}
|
||||
const modules = this.compiler.emitAllPartialModules(this.analyzedModules);
|
||||
|
||||
const writeTsFile: ts.WriteFileCallback =
|
||||
(outFileName, outData, writeByteOrderMark, onError?, sourceFiles?) => {
|
||||
const sourceFile = sourceFiles && sourceFiles.length == 1 ? sourceFiles[0] : null;
|
||||
let genFile: GeneratedFile|undefined;
|
||||
this.writeFile(outFileName, outData, writeByteOrderMark, onError, undefined, sourceFiles);
|
||||
};
|
||||
|
||||
const emitOnlyDtsFiles = (emitFlags & (EmitFlags.DTS | EmitFlags.JS)) == EmitFlags.DTS;
|
||||
|
||||
const tsCustomTansformers = this.calculateTransforms(
|
||||
/* genFiles */ undefined, /* partialModules */ modules, customTransformers);
|
||||
|
||||
const emitResult = emitCallback({
|
||||
program: this.tsProgram,
|
||||
host: this.host,
|
||||
options: this.options,
|
||||
writeFile: writeTsFile, emitOnlyDtsFiles,
|
||||
customTransformers: tsCustomTansformers
|
||||
});
|
||||
|
||||
return emitResult;
|
||||
}
|
||||
|
||||
private _emitRender2(
|
||||
emit(
|
||||
{emitFlags = EmitFlags.Default, cancellationToken, customTransformers,
|
||||
emitCallback = defaultEmitCallback}: {
|
||||
emitFlags?: EmitFlags,
|
||||
@ -293,8 +244,7 @@ class AngularCompilerProgram implements Program {
|
||||
}
|
||||
this.writeFile(outFileName, outData, writeByteOrderMark, onError, genFile, sourceFiles);
|
||||
};
|
||||
const tsCustomTansformers = this.calculateTransforms(
|
||||
genFileByFileName, /* partialModules */ undefined, customTransformers);
|
||||
const tsCustomTansformers = this.calculateTransforms(genFileByFileName, customTransformers);
|
||||
const emitOnlyDtsFiles = (emitFlags & (EmitFlags.DTS | EmitFlags.JS)) == EmitFlags.DTS;
|
||||
// Restore the original references before we emit so TypeScript doesn't emit
|
||||
// a reference to the .d.ts file.
|
||||
@ -450,18 +400,13 @@ class AngularCompilerProgram implements Program {
|
||||
}
|
||||
|
||||
private calculateTransforms(
|
||||
genFiles: Map<string, GeneratedFile>|undefined, partialModules: PartialModule[]|undefined,
|
||||
genFiles: Map<string, GeneratedFile>,
|
||||
customTransformers?: CustomTransformers): ts.CustomTransformers {
|
||||
const beforeTs: ts.TransformerFactory<ts.SourceFile>[] = [];
|
||||
if (!this.options.disableExpressionLowering) {
|
||||
beforeTs.push(getExpressionLoweringTransformFactory(this.metadataCache, this.tsProgram));
|
||||
}
|
||||
if (genFiles) {
|
||||
beforeTs.push(getAngularEmitterTransformFactory(genFiles, this.getTsProgram()));
|
||||
}
|
||||
if (partialModules) {
|
||||
beforeTs.push(getAngularClassTransformerFactory(partialModules));
|
||||
}
|
||||
beforeTs.push(getAngularEmitterTransformFactory(genFiles, this.getTsProgram()));
|
||||
if (customTransformers && customTransformers.beforeTs) {
|
||||
beforeTs.push(...customTransformers.beforeTs);
|
||||
}
|
||||
|
@ -1,36 +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 {PartialModule, Statement, StaticSymbol} from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {updateSourceFile} from './node_emitter';
|
||||
|
||||
export type Transformer = (sourceFile: ts.SourceFile) => ts.SourceFile;
|
||||
export type TransformerFactory = (context: ts.TransformationContext) => Transformer;
|
||||
|
||||
/**
|
||||
* Returns a transformer that adds the requested static methods specified by modules.
|
||||
*/
|
||||
export function getAngularClassTransformerFactory(modules: PartialModule[]): TransformerFactory {
|
||||
if (modules.length === 0) {
|
||||
// If no modules are specified, just return an identity transform.
|
||||
return () => sf => sf;
|
||||
}
|
||||
const moduleMap = new Map(modules.map<[string, PartialModule]>(m => [m.fileName, m]));
|
||||
return function(context: ts.TransformationContext) {
|
||||
return function(sourceFile: ts.SourceFile): ts.SourceFile {
|
||||
const module = moduleMap.get(sourceFile.fileName);
|
||||
if (module) {
|
||||
const [newSourceFile] = updateSourceFile(sourceFile, module, context);
|
||||
return newSourceFile;
|
||||
}
|
||||
return sourceFile;
|
||||
};
|
||||
};
|
||||
}
|
@ -6,7 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {syntaxError} from '@angular/compiler';
|
||||
import * as path from 'path';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
@ -22,14 +21,6 @@ export function tsStructureIsReused(program: ts.Program): StructureIsReused {
|
||||
return (program as any).structureIsReused;
|
||||
}
|
||||
|
||||
export function error(msg: string): never {
|
||||
throw new Error(`Internal error: ${msg}`);
|
||||
}
|
||||
|
||||
export function userError(msg: string): never {
|
||||
throw syntaxError(msg);
|
||||
}
|
||||
|
||||
export function createMessageDiagnostic(messageText: string): ts.Diagnostic&Diagnostic {
|
||||
return {
|
||||
file: undefined,
|
||||
|
@ -13,9 +13,7 @@ export type Entry = string | Directory;
|
||||
export interface Directory { [name: string]: Entry; }
|
||||
|
||||
export class MockAotContext {
|
||||
private files: Entry[];
|
||||
|
||||
constructor(public currentDirectory: string, ...files: Entry[]) { this.files = files; }
|
||||
constructor(public currentDirectory: string, private files: Entry) {}
|
||||
|
||||
fileExists(fileName: string): boolean { return typeof this.getEntry(fileName) === 'string'; }
|
||||
|
||||
@ -55,7 +53,19 @@ export class MockAotContext {
|
||||
}
|
||||
parts.shift();
|
||||
parts = normalize(parts);
|
||||
return first(this.files, files => getEntryFromFiles(parts, files));
|
||||
let current = this.files;
|
||||
while (parts.length) {
|
||||
const part = parts.shift() !;
|
||||
if (typeof current === 'string') {
|
||||
return undefined;
|
||||
}
|
||||
const next = (<Directory>current)[part];
|
||||
if (next === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
getDirectories(path: string): string[] {
|
||||
@ -66,31 +76,6 @@ export class MockAotContext {
|
||||
return Object.keys(dir).filter(key => typeof dir[key] === 'object');
|
||||
}
|
||||
}
|
||||
|
||||
override(files: Entry) { return new MockAotContext(this.currentDirectory, files, ...this.files); }
|
||||
}
|
||||
|
||||
function first<T>(a: T[], cb: (value: T) => T | undefined): T|undefined {
|
||||
for (const value of a) {
|
||||
const result = cb(value);
|
||||
if (result != null) return result;
|
||||
}
|
||||
}
|
||||
|
||||
function getEntryFromFiles(parts: string[], files: Entry) {
|
||||
let current = files;
|
||||
while (parts.length) {
|
||||
const part = parts.shift() !;
|
||||
if (typeof current === 'string') {
|
||||
return undefined;
|
||||
}
|
||||
const next = (<Directory>current)[part];
|
||||
if (next === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
function normalize(parts: string[]): string[] {
|
||||
|
@ -898,12 +898,12 @@ describe('ngc transformer command-line', () => {
|
||||
|
||||
export * from './util';
|
||||
|
||||
// Note: the lambda will be lowered into an exported expression
|
||||
// Note: the lamda will be lowered into an exported expression
|
||||
@NgModule({providers: [{provide: 'aToken', useValue: () => 2}]})
|
||||
export class MyModule {}
|
||||
`);
|
||||
write('util.ts', `
|
||||
// Note: The lambda will be lowered into an exported expression
|
||||
// Note: The lamda will be lowered into an exported expression
|
||||
const x = () => 2;
|
||||
|
||||
export const y = x;
|
||||
@ -1144,7 +1144,7 @@ describe('ngc transformer command-line', () => {
|
||||
shouldExist('app/main.js');
|
||||
});
|
||||
|
||||
it('should be able to compile libraries with summaries and flat modules', () => {
|
||||
it('shoud be able to compile libraries with summaries and flat modules', () => {
|
||||
writeFiles();
|
||||
compile();
|
||||
|
||||
@ -1466,7 +1466,7 @@ describe('ngc transformer command-line', () => {
|
||||
`);
|
||||
}));
|
||||
|
||||
it('should recompile when the html file changes',
|
||||
it('should recomiple when the html file changes',
|
||||
expectRecompile(() => { write('greet.html', '<p> Hello {{name}} again!</p>'); }));
|
||||
|
||||
it('should recompile when the css file changes',
|
||||
@ -1841,105 +1841,4 @@ describe('ngc transformer command-line', () => {
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ivy', () => {
|
||||
function emittedFile(name: string): string {
|
||||
const outputName = path.resolve(outDir, name);
|
||||
expect(fs.existsSync(outputName)).toBe(true);
|
||||
return fs.readFileSync(outputName, {encoding: 'UTF-8'});
|
||||
}
|
||||
|
||||
it('should emit the hello world example', () => {
|
||||
write('tsconfig.json', `{
|
||||
"extends": "./tsconfig-base.json",
|
||||
"files": ["hello-world.ts"],
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": true
|
||||
}
|
||||
}`);
|
||||
|
||||
write('hello-world.ts', `
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'hello-world',
|
||||
template: 'Hello, world!'
|
||||
})
|
||||
export class HelloWorldComponent {
|
||||
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [HelloWorldComponent]
|
||||
})
|
||||
export class HelloWorldModule {}
|
||||
`);
|
||||
const exitCode = main(['-p', path.join(basePath, 'tsconfig.json')]);
|
||||
expect(exitCode).toBe(0, 'Compile failed');
|
||||
expect(emittedFile('hello-world.js')).toContain('ngComponentDef');
|
||||
});
|
||||
|
||||
it('should emit an injection of a string token', () => {
|
||||
write('tsconfig.json', `{
|
||||
"extends": "./tsconfig-base.json",
|
||||
"files": ["hello-world.ts"],
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": true
|
||||
}
|
||||
}`);
|
||||
|
||||
write('hello-world.ts', `
|
||||
import {Component, Inject, NgModule} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'hello-world',
|
||||
template: 'Hello, world!'
|
||||
})
|
||||
export class HelloWorldComponent {
|
||||
constructor (@Inject('test') private test: string) {}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [HelloWorldComponent],
|
||||
providers: [
|
||||
{provide: 'test', useValue: 'test'}
|
||||
]
|
||||
})
|
||||
export class HelloWorldModule {}
|
||||
`);
|
||||
const errors: string[] = [];
|
||||
const exitCode = main(['-p', path.join(basePath, 'tsconfig.json')], msg => errors.push(msg));
|
||||
expect(exitCode).toBe(0, `Compile failed:\n${errors.join('\n ')}`);
|
||||
expect(emittedFile('hello-world.js')).toContain('ngComponentDef');
|
||||
});
|
||||
|
||||
it('should emit an example that uses the E() instruction', () => {
|
||||
write('tsconfig.json', `{
|
||||
"extends": "./tsconfig-base.json",
|
||||
"files": ["hello-world.ts"],
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": true
|
||||
}
|
||||
}`);
|
||||
|
||||
write('hello-world.ts', `
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'hello-world',
|
||||
template: '<h1><div style="text-align:center"> Hello, {{name}}! </div></h1> '
|
||||
})
|
||||
export class HelloWorldComponent {
|
||||
name = 'World';
|
||||
}
|
||||
|
||||
@NgModule({declarations: [HelloWorldComponent]})
|
||||
export class HelloWorldModule {}
|
||||
`);
|
||||
const errors: string[] = [];
|
||||
const exitCode = main(['-p', path.join(basePath, 'tsconfig.json')], msg => errors.push(msg));
|
||||
expect(exitCode).toBe(0, `Compile failed:\n${errors.join('\n ')}`);
|
||||
expect(emittedFile('hello-world.js')).toContain('ngComponentDef');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,163 +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 {PartialModule} from '@angular/compiler';
|
||||
import * as o from '@angular/compiler/src/output/output_ast';
|
||||
import {MockAotCompilerHost} from 'compiler/test/aot/test_util';
|
||||
import {initDomAdapter} from 'platform-browser/src/browser';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {getAngularClassTransformerFactory} from '../../src/transformers/r3_transform';
|
||||
import {Directory, MockAotContext, MockCompilerHost} from '../mocks';
|
||||
|
||||
const someGenFilePath = '/somePackage/someGenFile';
|
||||
const someGenFileName = someGenFilePath + '.ts';
|
||||
|
||||
describe('r3_transform_spec', () => {
|
||||
let context: MockAotContext;
|
||||
let host: MockCompilerHost;
|
||||
|
||||
beforeEach(() => {
|
||||
context = new MockAotContext('/', FILES);
|
||||
host = new MockCompilerHost(context);
|
||||
});
|
||||
|
||||
it('should be able to generate a simple identity function', () => {
|
||||
expect(emitStaticMethod(new o.ReturnStatement(o.variable('v')), ['v']))
|
||||
.toContain('static someMethod(v) { return v; }');
|
||||
});
|
||||
|
||||
it('should be able to generate a static field declaration',
|
||||
() => { expect(emitStaticField(o.literal(10))).toContain('SomeClass.someField = 10'); });
|
||||
|
||||
it('should be able to import a symbol', () => {
|
||||
expect(emitStaticMethod(new o.ReturnStatement(
|
||||
o.importExpr(new o.ExternalReference('@angular/core', 'Component')))))
|
||||
.toContain('static someMethod() { return i0.Component; } }');
|
||||
});
|
||||
|
||||
it('should be able to modify multiple classes in the same module', () => {
|
||||
const result = emit(getAngularClassTransformerFactory([{
|
||||
fileName: someGenFileName,
|
||||
statements: [
|
||||
classMethod(new o.ReturnStatement(o.variable('v')), ['v'], 'someMethod', 'SomeClass'),
|
||||
classMethod(
|
||||
new o.ReturnStatement(o.variable('v')), ['v'], 'someOtherMethod', 'SomeOtherClass')
|
||||
]
|
||||
}]));
|
||||
expect(result).toContain('static someMethod(v) { return v; }');
|
||||
expect(result).toContain('static someOtherMethod(v) { return v; }');
|
||||
});
|
||||
|
||||
it('should insert imports after existing imports', () => {
|
||||
context = context.override({
|
||||
somePackage: {
|
||||
'someGenFile.ts': `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({selector: 'some-class', template: 'hello!'})
|
||||
export class SomeClass {}
|
||||
|
||||
export class SomeOtherClass {}
|
||||
`
|
||||
}
|
||||
});
|
||||
host = new MockCompilerHost(context);
|
||||
|
||||
expect(emitStaticMethod(new o.ReturnStatement(
|
||||
o.importExpr(new o.ExternalReference('@angular/core', 'Component')))))
|
||||
.toContain('const core_1 = require("@angular/core"); const i0 = require("@angular/core");');
|
||||
});
|
||||
|
||||
function emit(factory: ts.TransformerFactory<ts.SourceFile>): string {
|
||||
let result: string = '';
|
||||
const program = ts.createProgram(
|
||||
[someGenFileName], {module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2017}, host);
|
||||
const moduleSourceFile = program.getSourceFile(someGenFileName);
|
||||
const transformers: ts.CustomTransformers = {before: [factory]};
|
||||
const emitResult = program.emit(
|
||||
moduleSourceFile, (fileName, data, writeByteOrderMark, onError, sourceFiles) => {
|
||||
if (fileName.startsWith(someGenFilePath)) {
|
||||
result = data;
|
||||
}
|
||||
}, undefined, undefined, transformers);
|
||||
return normalizeResult(result);
|
||||
}
|
||||
|
||||
function emitStaticMethod(
|
||||
stmt: o.Statement | o.Statement[], parameters: string[] = [],
|
||||
methodName: string = 'someMethod', className: string = 'SomeClass'): string {
|
||||
const module: PartialModule = {
|
||||
fileName: someGenFileName,
|
||||
statements: [classMethod(stmt, parameters, methodName, className)]
|
||||
};
|
||||
return emit(getAngularClassTransformerFactory([module]));
|
||||
}
|
||||
|
||||
function emitStaticField(
|
||||
initializer: o.Expression, fieldName: string = 'someField',
|
||||
className: string = 'SomeClass'): string {
|
||||
const module: PartialModule = {
|
||||
fileName: someGenFileName,
|
||||
statements: [classField(initializer, fieldName, className)]
|
||||
};
|
||||
return emit(getAngularClassTransformerFactory([module]));
|
||||
}
|
||||
});
|
||||
|
||||
const FILES: Directory = {
|
||||
somePackage: {
|
||||
'someGenFile.ts': `
|
||||
|
||||
export class SomeClass {}
|
||||
|
||||
export class SomeOtherClass {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
function classMethod(
|
||||
stmt: o.Statement | o.Statement[], parameters: string[] = [], methodName: string = 'someMethod',
|
||||
className: string = 'SomeClass'): o.ClassStmt {
|
||||
const statements = Array.isArray(stmt) ? stmt : [stmt];
|
||||
return new o.ClassStmt(
|
||||
/* name */ className,
|
||||
/* parent */ null,
|
||||
/* fields */[],
|
||||
/* getters */[],
|
||||
/* constructorMethod */ new o.ClassMethod(null, [], []),
|
||||
/* methods */[new o.ClassMethod(
|
||||
methodName, parameters.map(name => new o.FnParam(name)), statements, null,
|
||||
[o.StmtModifier.Static])]);
|
||||
}
|
||||
|
||||
function classField(
|
||||
initializer: o.Expression, fieldName: string = 'someField',
|
||||
className: string = 'SomeClass'): o.ClassStmt {
|
||||
return new o.ClassStmt(
|
||||
/* name */ className,
|
||||
/* parent */ null,
|
||||
/* fields */[new o.ClassField(fieldName, null, [o.StmtModifier.Static], initializer)],
|
||||
/* getters */[],
|
||||
/* constructorMethod */ new o.ClassMethod(null, [], []),
|
||||
/* methods */[]);
|
||||
}
|
||||
|
||||
function normalizeResult(result: string): string {
|
||||
// Remove TypeScript prefixes
|
||||
// Remove new lines
|
||||
// Squish adjacent spaces
|
||||
// Remove prefix and postfix spaces
|
||||
return result.replace('"use strict";', ' ')
|
||||
.replace('exports.__esModule = true;', ' ')
|
||||
.replace('Object.defineProperty(exports, "__esModule", { value: true });', ' ')
|
||||
.replace(/\n/g, ' ')
|
||||
.replace(/ +/g, ' ')
|
||||
.replace(/^ /g, '')
|
||||
.replace(/ $/g, '');
|
||||
}
|
@ -8,7 +8,6 @@
|
||||
|
||||
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileNgModuleSummary, CompilePipeMetadata, CompilePipeSummary, CompileProviderMetadata, CompileStylesheetMetadata, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary, componentFactoryName, flatten, identifierName, templateSourceUrl, tokenReference} from '../compile_metadata';
|
||||
import {CompilerConfig} from '../config';
|
||||
import {ConstantPool} from '../constant_pool';
|
||||
import {ViewEncapsulation} from '../core';
|
||||
import {MessageBundle} from '../i18n/message_bundle';
|
||||
import {Identifiers, createTokenForExternalReference} from '../identifiers';
|
||||
@ -19,12 +18,11 @@ import {NgModuleCompiler} from '../ng_module_compiler';
|
||||
import {OutputEmitter} from '../output/abstract_emitter';
|
||||
import * as o from '../output/output_ast';
|
||||
import {ParseError} from '../parse_util';
|
||||
import {compileComponent as compileIvyComponent, compileDirective as compileIvyDirective} from '../render3/r3_view_compiler';
|
||||
import {CompiledStylesheet, StyleCompiler} from '../style_compiler';
|
||||
import {SummaryResolver} from '../summary_resolver';
|
||||
import {TemplateAst} from '../template_parser/template_ast';
|
||||
import {TemplateParser} from '../template_parser/template_parser';
|
||||
import {OutputContext, ValueVisitor, error, syntaxError, visitValue} from '../util';
|
||||
import {OutputContext, ValueVisitor, syntaxError, visitValue} from '../util';
|
||||
import {TypeCheckCompiler} from '../view_compiler/type_check_compiler';
|
||||
import {ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler';
|
||||
|
||||
@ -32,7 +30,6 @@ import {AotCompilerHost} from './compiler_host';
|
||||
import {AotCompilerOptions} from './compiler_options';
|
||||
import {GeneratedFile} from './generated_file';
|
||||
import {LazyRoute, listLazyRoutes, parseLazyRoute} from './lazy_routes';
|
||||
import {PartialModule} from './partial_module';
|
||||
import {StaticReflector} from './static_reflector';
|
||||
import {StaticSymbol} from './static_symbol';
|
||||
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
|
||||
@ -307,47 +304,6 @@ export class AotCompiler {
|
||||
return messageBundle;
|
||||
}
|
||||
|
||||
emitAllPartialModules({ngModuleByPipeOrDirective, files}: NgAnalyzedModules): PartialModule[] {
|
||||
// Using reduce like this is a select many pattern (where map is a select pattern)
|
||||
return files.reduce<PartialModule[]>((r, file) => {
|
||||
r.push(...this._emitPartialModule(
|
||||
file.fileName, ngModuleByPipeOrDirective, file.directives, file.pipes, file.ngModules,
|
||||
file.injectables));
|
||||
return r;
|
||||
}, []);
|
||||
}
|
||||
|
||||
private _emitPartialModule(
|
||||
fileName: string, ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>,
|
||||
directives: StaticSymbol[], pipes: StaticSymbol[], ngModules: CompileNgModuleMetadata[],
|
||||
injectables: StaticSymbol[]): PartialModule[] {
|
||||
const classes: o.ClassStmt[] = [];
|
||||
|
||||
const context = this._createOutputContext(fileName);
|
||||
|
||||
// Process all components and directives
|
||||
directives.forEach(directiveType => {
|
||||
const directiveMetadata = this._metadataResolver.getDirectiveMetadata(directiveType);
|
||||
if (directiveMetadata.isComponent) {
|
||||
const module = ngModuleByPipeOrDirective.get(directiveType) !;
|
||||
module ||
|
||||
error(
|
||||
`Cannot determine the module for component '${identifierName(directiveMetadata.type)}'`);
|
||||
|
||||
const {template: parsedTemplate} =
|
||||
this._parseTemplate(directiveMetadata, module, module.transitiveModule.directives);
|
||||
compileIvyComponent(context, directiveMetadata, parsedTemplate, this._reflector);
|
||||
} else {
|
||||
compileIvyDirective(context, directiveMetadata, this._reflector);
|
||||
}
|
||||
});
|
||||
|
||||
if (context.statements) {
|
||||
return [{fileName, statements: [...context.constantPool.statements, ...context.statements]}];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
emitAllImpls(analyzeResult: NgAnalyzedModules): GeneratedFile[] {
|
||||
const {ngModuleByPipeOrDirective, files} = analyzeResult;
|
||||
const sourceModules = files.map(
|
||||
@ -591,7 +547,7 @@ export class AotCompiler {
|
||||
new o.ExternalReference(moduleName, name, null), allTypeParams));
|
||||
};
|
||||
|
||||
return {statements: [], genFilePath, importExpr, constantPool: new ConstantPool()};
|
||||
return {statements: [], genFilePath, importExpr};
|
||||
}
|
||||
|
||||
private _fileNameToModuleName(importedFilePath: string, containingFilePath: string): string {
|
||||
|
@ -1,14 +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 o from '../output/output_ast';
|
||||
|
||||
export interface PartialModule {
|
||||
fileName: string;
|
||||
statements: o.Statement[];
|
||||
}
|
@ -36,7 +36,6 @@ export * from './aot/generated_file';
|
||||
export * from './aot/compiler_options';
|
||||
export * from './aot/compiler_host';
|
||||
export * from './aot/formatted_error';
|
||||
export * from './aot/partial_module';
|
||||
export * from './aot/static_reflector';
|
||||
export * from './aot/static_symbol';
|
||||
export * from './aot/static_symbol_resolver';
|
||||
@ -67,7 +66,7 @@ export * from './ml_parser/html_tags';
|
||||
export * from './ml_parser/interpolation_config';
|
||||
export * from './ml_parser/tags';
|
||||
export {NgModuleCompiler} from './ng_module_compiler';
|
||||
export {AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinMethod, BuiltinVar, CastExpr, ClassMethod, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, ExpressionStatement, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, NotExpr, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, StatementVisitor, ThrowStmt, TryCatchStmt, WriteKeyExpr, WritePropExpr, WriteVarExpr, StmtModifier, Statement, collectExternalReferences} from './output/output_ast';
|
||||
export {AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinMethod, BuiltinVar, CastExpr, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, ExpressionStatement, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, NotExpr, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, StatementVisitor, ThrowStmt, TryCatchStmt, WriteKeyExpr, WritePropExpr, WriteVarExpr, StmtModifier, Statement, collectExternalReferences} from './output/output_ast';
|
||||
export {EmitterVisitorContext} from './output/abstract_emitter';
|
||||
export * from './output/ts_emitter';
|
||||
export * from './parse_util';
|
||||
|
@ -6,6 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
|
||||
import * as cdAst from '../expression_parser/ast';
|
||||
import {Identifiers} from '../identifiers';
|
||||
import * as o from '../output/output_ast';
|
||||
@ -18,15 +19,13 @@ export class ConvertActionBindingResult {
|
||||
constructor(public stmts: o.Statement[], public allowDefault: o.ReadVarExpr) {}
|
||||
}
|
||||
|
||||
export type InterpolationFunction = (args: o.Expression[]) => o.Expression;
|
||||
|
||||
/**
|
||||
* Converts the given expression AST into an executable output AST, assuming the expression is
|
||||
* used in an action binding (e.g. an event handler).
|
||||
*/
|
||||
export function convertActionBinding(
|
||||
localResolver: LocalResolver | null, implicitReceiver: o.Expression, action: cdAst.AST,
|
||||
bindingId: string, interpolationFunction?: InterpolationFunction): ConvertActionBindingResult {
|
||||
bindingId: string): ConvertActionBindingResult {
|
||||
if (!localResolver) {
|
||||
localResolver = new DefaultLocalResolver();
|
||||
}
|
||||
@ -53,8 +52,7 @@ export function convertActionBinding(
|
||||
},
|
||||
action);
|
||||
|
||||
const visitor =
|
||||
new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction);
|
||||
const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId);
|
||||
const actionStmts: o.Statement[] = [];
|
||||
flattenStatements(actionWithoutBuiltins.visit(visitor, _Mode.Statement), actionStmts);
|
||||
prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts);
|
||||
@ -100,7 +98,6 @@ export enum BindingForm {
|
||||
// otherise generate a general binding
|
||||
TrySimple,
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given expression AST into an executable output AST, assuming the expression
|
||||
* is used in property binding. The expression has to be preprocessed via
|
||||
@ -108,15 +105,14 @@ export enum BindingForm {
|
||||
*/
|
||||
export function convertPropertyBinding(
|
||||
localResolver: LocalResolver | null, implicitReceiver: o.Expression,
|
||||
expressionWithoutBuiltins: cdAst.AST, bindingId: string, form: BindingForm,
|
||||
interpolationFunction?: InterpolationFunction): ConvertPropertyBindingResult {
|
||||
expressionWithoutBuiltins: cdAst.AST, bindingId: string,
|
||||
form: BindingForm): ConvertPropertyBindingResult {
|
||||
if (!localResolver) {
|
||||
localResolver = new DefaultLocalResolver();
|
||||
}
|
||||
const currValExpr = createCurrValueExpr(bindingId);
|
||||
const stmts: o.Statement[] = [];
|
||||
const visitor =
|
||||
new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction);
|
||||
const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId);
|
||||
const outputExpr: o.Expression = expressionWithoutBuiltins.visit(visitor, _Mode.Expression);
|
||||
|
||||
if (visitor.temporaryCount) {
|
||||
@ -204,7 +200,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
||||
|
||||
constructor(
|
||||
private _localResolver: LocalResolver, private _implicitReceiver: o.Expression,
|
||||
private bindingId: string, private interpolationFunction: InterpolationFunction|undefined) {}
|
||||
private bindingId: string) {}
|
||||
|
||||
visitBinary(ast: cdAst.Binary, mode: _Mode): any {
|
||||
let op: o.BinaryOperator;
|
||||
@ -307,9 +303,6 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
||||
}
|
||||
args.push(o.literal(ast.strings[ast.strings.length - 1]));
|
||||
|
||||
if (this.interpolationFunction) {
|
||||
return this.interpolationFunction(args);
|
||||
}
|
||||
return ast.expressions.length <= 9 ?
|
||||
o.importExpr(Identifiers.inlineInterpolate).callFn(args) :
|
||||
o.importExpr(Identifiers.interpolate).callFn([args[0], o.literalArr(args.slice(1))]);
|
||||
|
@ -1,154 +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 o from './output/output_ast';
|
||||
import {OutputContext, error} from './util';
|
||||
|
||||
const CONSTANT_PREFIX = '_c';
|
||||
|
||||
export const enum DefinitionKind {Injector, Directive, Component}
|
||||
|
||||
/**
|
||||
* A node that is a place-holder that allows the node to be replaced when the actual
|
||||
* node is known.
|
||||
*
|
||||
* This allows the constant pool to change an expression from a direct reference to
|
||||
* a constant to a shared constant. It returns a fix-up node that is later allowed to
|
||||
* change the referenced expression.
|
||||
*/
|
||||
class FixupExpression extends o.Expression {
|
||||
constructor(public resolved: o.Expression) { super(resolved.type); }
|
||||
|
||||
shared: boolean;
|
||||
|
||||
visitExpression(visitor: o.ExpressionVisitor, context: any): any {
|
||||
return this.resolved.visitExpression(visitor, context);
|
||||
}
|
||||
|
||||
isEquivalent(e: o.Expression): boolean {
|
||||
return e instanceof FixupExpression && this.resolved.isEquivalent(e.resolved);
|
||||
}
|
||||
|
||||
fixup(expression: o.Expression) {
|
||||
this.resolved = expression;
|
||||
this.shared = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A constant pool allows a code emitter to share constant in an output context.
|
||||
*
|
||||
* The constant pool also supports sharing access to ivy definitions references.
|
||||
*/
|
||||
export class ConstantPool {
|
||||
statements: o.Statement[] = [];
|
||||
private literals = new Map<string, FixupExpression>();
|
||||
private injectorDefinitions = new Map<any, FixupExpression>();
|
||||
private directiveDefinitions = new Map<any, FixupExpression>();
|
||||
private componentDefinitions = new Map<any, FixupExpression>();
|
||||
|
||||
private nextNameIndex = 0;
|
||||
|
||||
getConstLiteral(literal: o.Expression, forceShared?: boolean): o.Expression {
|
||||
const key = this.keyOf(literal);
|
||||
let fixup = this.literals.get(key);
|
||||
let newValue = false;
|
||||
if (!fixup) {
|
||||
fixup = new FixupExpression(literal);
|
||||
this.literals.set(key, fixup);
|
||||
newValue = true;
|
||||
}
|
||||
|
||||
if ((!newValue && !fixup.shared) || (newValue && forceShared)) {
|
||||
// Replace the expression with a variable
|
||||
const name = this.freshName();
|
||||
this.statements.push(
|
||||
o.variable(name).set(literal).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
||||
fixup.fixup(o.variable(name));
|
||||
}
|
||||
|
||||
return fixup;
|
||||
}
|
||||
|
||||
getDefinition(type: any, kind: DefinitionKind, ctx: OutputContext): o.Expression {
|
||||
const declarations = kind == DefinitionKind.Component ?
|
||||
this.componentDefinitions :
|
||||
kind == DefinitionKind.Directive ? this.directiveDefinitions : this.injectorDefinitions;
|
||||
let fixup = declarations.get(type);
|
||||
if (!fixup) {
|
||||
const property = kind == DefinitionKind.Component ?
|
||||
'ngComponentDef' :
|
||||
kind == DefinitionKind.Directive ? 'ngDirectiveDef' : 'ngInjectorDef';
|
||||
fixup = new FixupExpression(ctx.importExpr(type).prop(property));
|
||||
declarations.set(type, fixup);
|
||||
} else if (!fixup.shared) {
|
||||
const name = this.freshName();
|
||||
this.statements.push(
|
||||
o.variable(name).set(fixup.resolved).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
||||
fixup.fixup(o.variable(name));
|
||||
}
|
||||
return fixup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a unique name.
|
||||
*
|
||||
* The name might be unique among different prefixes if any of the prefixes end in
|
||||
* a digit so the prefix should be a constant string (not based on user input) and
|
||||
* must not end in a digit.
|
||||
*/
|
||||
uniqueName(prefix: string): string { return `${prefix}${this.nextNameIndex++}`; }
|
||||
|
||||
private freshName(): string { return this.uniqueName(CONSTANT_PREFIX); }
|
||||
|
||||
private keyOf(expression: o.Expression) {
|
||||
return expression.visitExpression(new KeyVisitor(), null);
|
||||
}
|
||||
}
|
||||
|
||||
class KeyVisitor implements o.ExpressionVisitor {
|
||||
visitLiteralExpr(ast: o.LiteralExpr): string {
|
||||
return `${typeof ast.value === 'string' ? '"' + ast.value + '"' : ast.value}`;
|
||||
}
|
||||
visitLiteralArrayExpr(ast: o.LiteralArrayExpr): string {
|
||||
return `[${ast.entries.map(entry => entry.visitExpression(this, null)).join(',')}]`;
|
||||
}
|
||||
|
||||
visitLiteralMapExpr(ast: o.LiteralMapExpr): string {
|
||||
const mapEntry = (entry: o.LiteralMapEntry) =>
|
||||
`${entry.key}:${entry.value.visitExpression(this, null)}`;
|
||||
return `{${ast.entries.map(mapEntry).join(',')}`;
|
||||
}
|
||||
|
||||
visitExternalExpr(ast: o.ExternalExpr): string {
|
||||
return ast.value.moduleName ? `EX:${ast.value.moduleName}:${ast.value.name}` :
|
||||
`EX:${ast.value.runtime.name}`;
|
||||
}
|
||||
|
||||
visitReadVarExpr = invalid;
|
||||
visitWriteVarExpr = invalid;
|
||||
visitWriteKeyExpr = invalid;
|
||||
visitWritePropExpr = invalid;
|
||||
visitInvokeMethodExpr = invalid;
|
||||
visitInvokeFunctionExpr = invalid;
|
||||
visitInstantiateExpr = invalid;
|
||||
visitConditionalExpr = invalid;
|
||||
visitNotExpr = invalid;
|
||||
visitAssertNotNullExpr = invalid;
|
||||
visitCastExpr = invalid;
|
||||
visitFunctionExpr = invalid;
|
||||
visitBinaryOperatorExpr = invalid;
|
||||
visitReadPropExpr = invalid;
|
||||
visitReadKeyExpr = invalid;
|
||||
visitCommaExpr = invalid;
|
||||
}
|
||||
|
||||
function invalid<T>(arg: o.Expression | o.Statement): never {
|
||||
throw new Error(
|
||||
`Invalid state: Visitor ${this.constructor.name} doesn't handle ${o.constructor.name}`);
|
||||
}
|
@ -9,7 +9,6 @@
|
||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeSummary, CompileProviderMetadata, CompileStylesheetMetadata, CompileTypeSummary, ProviderMeta, ProxyClass, identifierName, ngModuleJitUrl, sharedStylesheetJitUrl, templateJitUrl, templateSourceUrl} from '../compile_metadata';
|
||||
import {CompileReflector} from '../compile_reflector';
|
||||
import {CompilerConfig} from '../config';
|
||||
import {ConstantPool} from '../constant_pool';
|
||||
import {Type} from '../core';
|
||||
import {CompileMetadataResolver} from '../metadata_resolver';
|
||||
import {NgModuleCompiler} from '../ng_module_compiler';
|
||||
@ -356,5 +355,5 @@ function assertComponent(meta: CompileDirectiveMetadata) {
|
||||
function createOutputContext(): OutputContext {
|
||||
const importExpr = (symbol: any) =>
|
||||
ir.importExpr({name: identifierName(symbol), moduleName: null, runtime: symbol});
|
||||
return {statements: [], genFilePath: '', importExpr, constantPool: new ConstantPool()};
|
||||
return {statements: [], genFilePath: '', importExpr};
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ export abstract class AbstractJsEmitterVisitor extends AbstractEmitterVisitor {
|
||||
return null;
|
||||
}
|
||||
visitFunctionExpr(ast: o.FunctionExpr, ctx: EmitterVisitorContext): any {
|
||||
ctx.print(ast, `function${ast.name ? ' ' + ast.name : ''}(`);
|
||||
ctx.print(ast, `function(`);
|
||||
this._visitParams(ast.params, ctx);
|
||||
ctx.println(ast, `) {`);
|
||||
ctx.incIndent();
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
|
||||
import {ParseSourceSpan} from '../parse_util';
|
||||
import {error} from '../util';
|
||||
|
||||
//// Types
|
||||
export enum TypeModifier {
|
||||
@ -41,7 +40,7 @@ export class BuiltinType extends Type {
|
||||
super(modifiers);
|
||||
}
|
||||
visitType(visitor: TypeVisitor, context: any): any {
|
||||
return visitor.visitBuiltinType(this, context);
|
||||
return visitor.visitBuiltintType(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,7 +78,7 @@ export const STRING_TYPE = new BuiltinType(BuiltinTypeName.String);
|
||||
export const FUNCTION_TYPE = new BuiltinType(BuiltinTypeName.Function);
|
||||
|
||||
export interface TypeVisitor {
|
||||
visitBuiltinType(type: BuiltinType, context: any): any;
|
||||
visitBuiltintType(type: BuiltinType, context: any): any;
|
||||
visitExpressionType(type: ExpressionType, context: any): any;
|
||||
visitArrayType(type: ArrayType, context: any): any;
|
||||
visitMapType(type: MapType, context: any): any;
|
||||
@ -487,7 +486,7 @@ export class FnParam {
|
||||
export class FunctionExpr extends Expression {
|
||||
constructor(
|
||||
public params: FnParam[], public statements: Statement[], type?: Type|null,
|
||||
sourceSpan?: ParseSourceSpan|null, public name?: string|null) {
|
||||
sourceSpan?: ParseSourceSpan|null) {
|
||||
super(type, sourceSpan);
|
||||
}
|
||||
isEquivalent(e: Expression): boolean {
|
||||
@ -645,8 +644,7 @@ export const TYPED_NULL_EXPR = new LiteralExpr(null, INFERRED_TYPE, null);
|
||||
export enum StmtModifier {
|
||||
Final,
|
||||
Private,
|
||||
Exported,
|
||||
Static,
|
||||
Exported
|
||||
}
|
||||
|
||||
export abstract class Statement {
|
||||
@ -741,9 +739,7 @@ export class AbstractClassPart {
|
||||
}
|
||||
|
||||
export class ClassField extends AbstractClassPart {
|
||||
constructor(
|
||||
public name: string, type?: Type|null, modifiers: StmtModifier[]|null = null,
|
||||
public initializer?: Expression) {
|
||||
constructor(public name: string, type?: Type|null, modifiers: StmtModifier[]|null = null) {
|
||||
super(type, modifiers);
|
||||
}
|
||||
isEquivalent(f: ClassField) { return this.name === f.name; }
|
||||
@ -1088,7 +1084,7 @@ export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
visitBuiltinType(type: BuiltinType, context: any): any { return this.visitType(type, context); }
|
||||
visitBuiltintType(type: BuiltinType, context: any): any { return this.visitType(type, context); }
|
||||
visitExpressionType(type: ExpressionType, context: any): any {
|
||||
type.value.visitExpression(this, context);
|
||||
return this.visitType(type, context);
|
||||
@ -1369,13 +1365,9 @@ export function assertNotNull(
|
||||
}
|
||||
|
||||
export function fn(
|
||||
params: FnParam[], body: Statement[], type?: Type | null, sourceSpan?: ParseSourceSpan | null,
|
||||
name?: string | null): FunctionExpr {
|
||||
return new FunctionExpr(params, body, type, sourceSpan, name);
|
||||
}
|
||||
|
||||
export function ifStmt(condition: Expression, thenClause: Statement[], elseClause?: Statement[]) {
|
||||
return new IfStmt(condition, thenClause, elseClause);
|
||||
params: FnParam[], body: Statement[], type?: Type | null,
|
||||
sourceSpan?: ParseSourceSpan | null): FunctionExpr {
|
||||
return new FunctionExpr(params, body, type, sourceSpan);
|
||||
}
|
||||
|
||||
export function literal(
|
||||
|
@ -40,9 +40,9 @@ export type ReferenceFilter = (reference: o.ExternalReference) => boolean;
|
||||
export class TypeScriptEmitter implements OutputEmitter {
|
||||
emitStatementsAndContext(
|
||||
genFilePath: string, stmts: o.Statement[], preamble: string = '',
|
||||
emitSourceMaps: boolean = true, referenceFilter?: ReferenceFilter,
|
||||
importFilter?: ReferenceFilter): {sourceText: string, context: EmitterVisitorContext} {
|
||||
const converter = new _TsEmitterVisitor(referenceFilter, importFilter);
|
||||
emitSourceMaps: boolean = true,
|
||||
referenceFilter?: ReferenceFilter): {sourceText: string, context: EmitterVisitorContext} {
|
||||
const converter = new _TsEmitterVisitor(referenceFilter);
|
||||
|
||||
const ctx = EmitterVisitorContext.createRoot();
|
||||
|
||||
@ -83,9 +83,7 @@ export class TypeScriptEmitter implements OutputEmitter {
|
||||
class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor {
|
||||
private typeExpression = 0;
|
||||
|
||||
constructor(private referenceFilter?: ReferenceFilter, private importFilter?: ReferenceFilter) {
|
||||
super(false);
|
||||
}
|
||||
constructor(private referenceFilter?: ReferenceFilter) { super(false); }
|
||||
|
||||
importsWithPrefixes = new Map<string, string>();
|
||||
reexports = new Map<string, {name: string, as: string}[]>();
|
||||
@ -218,15 +216,8 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||
// comment out as a workaround for #10967
|
||||
ctx.print(null, `/*private*/ `);
|
||||
}
|
||||
if (field.hasModifier(o.StmtModifier.Static)) {
|
||||
ctx.print(null, 'static ');
|
||||
}
|
||||
ctx.print(null, field.name);
|
||||
this._printColonType(field.type, ctx);
|
||||
if (field.initializer) {
|
||||
ctx.print(null, ' = ');
|
||||
field.initializer.visitExpression(this, ctx);
|
||||
}
|
||||
ctx.println(null, `;`);
|
||||
}
|
||||
|
||||
@ -269,23 +260,15 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||
}
|
||||
|
||||
visitFunctionExpr(ast: o.FunctionExpr, ctx: EmitterVisitorContext): any {
|
||||
if (ast.name) {
|
||||
ctx.print(ast, 'function ');
|
||||
ctx.print(ast, ast.name);
|
||||
}
|
||||
ctx.print(ast, `(`);
|
||||
this._visitParams(ast.params, ctx);
|
||||
ctx.print(ast, `)`);
|
||||
this._printColonType(ast.type, ctx, 'void');
|
||||
if (!ast.name) {
|
||||
ctx.print(ast, ` => `);
|
||||
}
|
||||
ctx.println(ast, '{');
|
||||
ctx.println(ast, ` => {`);
|
||||
ctx.incIndent();
|
||||
this.visitAllStatements(ast.statements, ctx);
|
||||
ctx.decIndent();
|
||||
ctx.print(ast, `}`);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -322,7 +305,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||
return null;
|
||||
}
|
||||
|
||||
visitBuiltinType(type: o.BuiltinType, ctx: EmitterVisitorContext): any {
|
||||
visitBuiltintType(type: o.BuiltinType, ctx: EmitterVisitorContext): any {
|
||||
let typeStr: string;
|
||||
switch (type.name) {
|
||||
case o.BuiltinTypeName.Bool:
|
||||
@ -400,7 +383,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||
ctx.print(null, '(null as any)');
|
||||
return;
|
||||
}
|
||||
if (moduleName && (!this.importFilter || !this.importFilter(value))) {
|
||||
if (moduleName) {
|
||||
let prefix = this.importsWithPrefixes.get(moduleName);
|
||||
if (prefix == null) {
|
||||
prefix = `i${this.importsWithPrefixes.size}`;
|
||||
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
import * as chars from './chars';
|
||||
import {CompileIdentifierMetadata, identifierModuleUrl, identifierName} from './compile_metadata';
|
||||
import {error} from './util';
|
||||
|
||||
export class ParseLocation {
|
||||
constructor(
|
||||
|
@ -1,92 +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 o from '../output/output_ast';
|
||||
|
||||
const CORE = '@angular/core';
|
||||
|
||||
// Copied from core and must be in sync with the value in the runtime.
|
||||
export const enum LifeCycleGuard {ON_INIT = 1, ON_DESTROY = 2, ON_CHANGES = 4}
|
||||
|
||||
// TODO: Include assignments that use the enum literals
|
||||
// e.g. { let a: core.LifeCycleGuard.ON_INIT = LifeCycleGuard.ON_INIT; ...}
|
||||
// Ensure these get removed in bundling.
|
||||
|
||||
export class Identifiers {
|
||||
/* Methods */
|
||||
static NEW_METHOD = 'n';
|
||||
static HOST_BINDING_METHOD = 'h';
|
||||
|
||||
/* Instructions */
|
||||
static createElement: o.ExternalReference = {name: 'ɵE', moduleName: CORE};
|
||||
|
||||
static elementEnd: o.ExternalReference = {name: 'ɵe', moduleName: CORE};
|
||||
|
||||
static elementProperty: o.ExternalReference = {name: 'ɵp', moduleName: CORE};
|
||||
|
||||
static elementAttribute: o.ExternalReference = {name: 'ɵa', moduleName: CORE};
|
||||
|
||||
static elementClass: o.ExternalReference = {name: 'ɵk', moduleName: CORE};
|
||||
|
||||
static elementStyle: o.ExternalReference = {name: 'ɵs', moduleName: CORE};
|
||||
|
||||
static containerCreate: o.ExternalReference = {name: 'ɵC', moduleName: CORE};
|
||||
|
||||
static containerEnd: o.ExternalReference = {name: 'ɵc', moduleName: CORE};
|
||||
|
||||
static containerRefreshStart: o.ExternalReference = {name: 'ɵcR', moduleName: CORE};
|
||||
|
||||
static containerRefreshEnd: o.ExternalReference = {name: 'ɵcr', moduleName: CORE};
|
||||
|
||||
static directiveCreate: o.ExternalReference = {name: 'ɵD', moduleName: CORE};
|
||||
|
||||
static text: o.ExternalReference = {name: 'ɵT', moduleName: CORE};
|
||||
|
||||
static directiveInput: o.ExternalReference = {name: 'ɵi', moduleName: CORE};
|
||||
|
||||
static textCreateBound: o.ExternalReference = {name: 'ɵt', moduleName: CORE};
|
||||
|
||||
static bind: o.ExternalReference = {name: 'ɵb', moduleName: CORE};
|
||||
|
||||
static bind1: o.ExternalReference = {name: 'ɵb1', moduleName: CORE};
|
||||
static bind2: o.ExternalReference = {name: 'ɵb2', moduleName: CORE};
|
||||
static bind3: o.ExternalReference = {name: 'ɵb3', moduleName: CORE};
|
||||
static bind4: o.ExternalReference = {name: 'ɵb4', moduleName: CORE};
|
||||
static bind5: o.ExternalReference = {name: 'ɵb5', moduleName: CORE};
|
||||
static bind6: o.ExternalReference = {name: 'ɵb6', moduleName: CORE};
|
||||
static bind7: o.ExternalReference = {name: 'ɵb7', moduleName: CORE};
|
||||
static bind8: o.ExternalReference = {name: 'ɵb8', moduleName: CORE};
|
||||
static bindV: o.ExternalReference = {name: 'ɵbV', moduleName: CORE};
|
||||
|
||||
static memory: o.ExternalReference = {name: 'ɵm', moduleName: CORE};
|
||||
|
||||
static projection: o.ExternalReference = {name: 'ɵP', moduleName: CORE};
|
||||
static projectionDef: o.ExternalReference = {name: 'ɵpD', moduleName: CORE};
|
||||
|
||||
static refreshComponent: o.ExternalReference = {name: 'ɵr', moduleName: CORE};
|
||||
|
||||
static directiveLifeCycle: o.ExternalReference = {name: 'ɵl', moduleName: CORE};
|
||||
|
||||
static injectElementRef: o.ExternalReference = {name: 'ɵinjectElementRef', moduleName: CORE};
|
||||
|
||||
static injectTemplateRef: o.ExternalReference = {name: 'ɵinjectTemplateRef', moduleName: CORE};
|
||||
|
||||
static injectViewContainerRef:
|
||||
o.ExternalReference = {name: 'ɵinjectViewContainerRef', moduleName: CORE};
|
||||
|
||||
static inject: o.ExternalReference = {name: 'ɵinject', moduleName: CORE};
|
||||
|
||||
static defineComponent: o.ExternalReference = {name: 'ɵdefineComponent', moduleName: CORE};
|
||||
|
||||
static defineDirective: o.ExternalReference = {
|
||||
name: 'ɵdefineDirective',
|
||||
moduleName: CORE,
|
||||
};
|
||||
|
||||
static NgOnChangesFeature: o.ExternalReference = {name: 'ɵNgOnChangesFeature', moduleName: CORE};
|
||||
}
|
@ -1,697 +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 {CompileDirectiveMetadata, CompilePipeSummary, CompileTokenMetadata, CompileTypeMetadata, flatten, identifierName, rendererTypeName, tokenReference, viewClassName} from '../compile_metadata';
|
||||
import {CompileReflector} from '../compile_reflector';
|
||||
import {BindingForm, BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
|
||||
import {ConstantPool, DefinitionKind} from '../constant_pool';
|
||||
import {AST} from '../expression_parser/ast';
|
||||
import {Identifiers} from '../identifiers';
|
||||
import * as o from '../output/output_ast';
|
||||
import {ParseSourceSpan} from '../parse_util';
|
||||
import {CssSelector} from '../selector';
|
||||
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, QueryMatch, RecursiveTemplateAstVisitor, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
|
||||
import {OutputContext, error} from '../util';
|
||||
|
||||
import {Identifiers as R3} from './r3_identifiers';
|
||||
|
||||
|
||||
|
||||
/** Name of the context parameter passed into a template function */
|
||||
const CONTEXT_NAME = 'ctx';
|
||||
|
||||
/** Name of the creation mode flag passed into a template function */
|
||||
const CREATION_MODE_FLAG = 'cm';
|
||||
|
||||
/** Name of the temporary to use during data binding */
|
||||
const TEMPORARY_NAME = '_t';
|
||||
|
||||
/** The prefix reference variables */
|
||||
const REFERENCE_PREFIX = '_r';
|
||||
|
||||
/** The name of the implicit context reference */
|
||||
const IMPLICIT_REFERENCE = '$implicit';
|
||||
|
||||
export function compileDirective(
|
||||
outputCtx: OutputContext, directive: CompileDirectiveMetadata, reflector: CompileReflector) {
|
||||
const definitionMapValues: {key: string, quoted: boolean, value: o.Expression}[] = [];
|
||||
|
||||
// e.g. 'type: MyDirective`
|
||||
definitionMapValues.push(
|
||||
{key: 'type', value: outputCtx.importExpr(directive.type.reference), quoted: false});
|
||||
|
||||
// e.g. `factory: () => new MyApp(injectElementRef())`
|
||||
const templateFactory = createFactory(directive.type, outputCtx, reflector);
|
||||
definitionMapValues.push({key: 'factory', value: templateFactory, quoted: false});
|
||||
|
||||
const className = identifierName(directive.type) !;
|
||||
className || error(`Cannot resolver the name of ${directive.type}`);
|
||||
|
||||
// Create the partial class to be merged with the actual class.
|
||||
outputCtx.statements.push(new o.ClassStmt(
|
||||
/* name */ className,
|
||||
/* parent */ null,
|
||||
/* fields */[new o.ClassField(
|
||||
/* name */ 'ngDirectiveDef',
|
||||
/* type */ o.INFERRED_TYPE,
|
||||
/* modifiers */[o.StmtModifier.Static],
|
||||
/* initializer */ o.importExpr(R3.defineDirective).callFn([o.literalMap(
|
||||
definitionMapValues)]))],
|
||||
/* getters */[],
|
||||
/* constructorMethod */ new o.ClassMethod(null, [], []),
|
||||
/* methods */[]));
|
||||
}
|
||||
|
||||
export function compileComponent(
|
||||
outputCtx: OutputContext, component: CompileDirectiveMetadata, template: TemplateAst[],
|
||||
reflector: CompileReflector) {
|
||||
const definitionMapValues: {key: string, quoted: boolean, value: o.Expression}[] = [];
|
||||
|
||||
// e.g. `type: MyApp`
|
||||
definitionMapValues.push(
|
||||
{key: 'type', value: outputCtx.importExpr(component.type.reference), quoted: false});
|
||||
|
||||
// e.g. `tag: 'my-app'`
|
||||
// This is optional and only included if the first selector of a component has element.
|
||||
const selector = component.selector && CssSelector.parse(component.selector);
|
||||
const firstSelector = selector && selector[0];
|
||||
if (firstSelector && firstSelector.hasElementSelector()) {
|
||||
definitionMapValues.push({key: 'tag', value: o.literal(firstSelector.element), quoted: false});
|
||||
}
|
||||
|
||||
// e.g. `attr: ["class", ".my.app"]
|
||||
// This is optional an only included if the first selector of a component specifies attributes.
|
||||
if (firstSelector) {
|
||||
const selectorAttributes = firstSelector.getAttrs();
|
||||
if (selectorAttributes.length) {
|
||||
definitionMapValues.push({
|
||||
key: 'attrs',
|
||||
value: outputCtx.constantPool.getConstLiteral(
|
||||
o.literalArr(selectorAttributes.map(
|
||||
value => value != null ? o.literal(value) : o.literal(undefined))),
|
||||
/* forceShared */ true),
|
||||
quoted: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// e.g. `factory: function MyApp_Factory() { return new MyApp(injectElementRef()); }`
|
||||
const templateFactory = createFactory(component.type, outputCtx, reflector);
|
||||
definitionMapValues.push({key: 'factory', value: templateFactory, quoted: false});
|
||||
|
||||
// e.g. `template: function MyComponent_Template(_ctx, _cm) {...}`
|
||||
const templateTypeName = component.type.reference.name;
|
||||
const templateName = templateTypeName ? `${templateTypeName}_Template` : null;
|
||||
const templateFunctionExpression =
|
||||
new TemplateDefinitionBuilder(
|
||||
outputCtx, outputCtx.constantPool, reflector, CONTEXT_NAME, ROOT_SCOPE.nestedScope(), 0,
|
||||
component.template !.ngContentSelectors, templateTypeName, templateName)
|
||||
.buildTemplateFunction(template, []);
|
||||
definitionMapValues.push({key: 'template', value: templateFunctionExpression, quoted: false});
|
||||
|
||||
|
||||
const className = identifierName(component.type) !;
|
||||
className || error(`Cannot resolver the name of ${component.type}`);
|
||||
|
||||
// Create the partial class to be merged with the actual class.
|
||||
outputCtx.statements.push(new o.ClassStmt(
|
||||
/* name */ className,
|
||||
/* parent */ null,
|
||||
/* fields */[new o.ClassField(
|
||||
/* name */ 'ngComponentDef',
|
||||
/* type */ o.INFERRED_TYPE,
|
||||
/* modifiers */[o.StmtModifier.Static],
|
||||
/* initializer */ o.importExpr(R3.defineComponent).callFn([o.literalMap(
|
||||
definitionMapValues)]))],
|
||||
/* getters */[],
|
||||
/* constructorMethod */ new o.ClassMethod(null, [], []),
|
||||
/* methods */[]));
|
||||
}
|
||||
|
||||
|
||||
// TODO: Remove these when the things are fully supported
|
||||
function unknown<T>(arg: o.Expression | o.Statement | TemplateAst): never {
|
||||
throw new Error(
|
||||
`Builder ${this.constructor.name} is unable to handle ${arg.constructor.name} yet`);
|
||||
}
|
||||
|
||||
function unsupported(feature: string): never {
|
||||
if (this) {
|
||||
throw new Error(`Builder ${this.constructor.name} doesn't support ${feature} yet`);
|
||||
}
|
||||
throw new Error(`Feature ${feature} is not supported yet`);
|
||||
}
|
||||
|
||||
const BINDING_INSTRUCTION_MAP: {[index: number]: o.ExternalReference | undefined} = {
|
||||
[PropertyBindingType.Property]: R3.elementProperty,
|
||||
[PropertyBindingType.Attribute]: R3.elementAttribute,
|
||||
[PropertyBindingType.Class]: R3.elementClass,
|
||||
[PropertyBindingType.Style]: R3.elementStyle
|
||||
};
|
||||
|
||||
function interpolate(args: o.Expression[]): o.Expression {
|
||||
args = args.slice(1); // Ignore the length prefix added for render2
|
||||
switch (args.length) {
|
||||
case 3:
|
||||
return o.importExpr(R3.bind1).callFn(args);
|
||||
case 5:
|
||||
return o.importExpr(R3.bind2).callFn(args);
|
||||
case 7:
|
||||
return o.importExpr(R3.bind3).callFn(args);
|
||||
case 9:
|
||||
return o.importExpr(R3.bind4).callFn(args);
|
||||
case 11:
|
||||
return o.importExpr(R3.bind5).callFn(args);
|
||||
case 13:
|
||||
return o.importExpr(R3.bind6).callFn(args);
|
||||
case 15:
|
||||
return o.importExpr(R3.bind7).callFn(args);
|
||||
case 17:
|
||||
return o.importExpr(R3.bind8).callFn(args);
|
||||
}
|
||||
(args.length > 19 && args.length % 2 == 1) ||
|
||||
error(`Invalid interpolation argument length ${args.length}`);
|
||||
return o.importExpr(R3.bindV).callFn(args);
|
||||
}
|
||||
|
||||
class BindingScope {
|
||||
private map = new Map<string, o.Expression>();
|
||||
private referenceNameIndex = 0;
|
||||
|
||||
constructor(private parent: BindingScope|null) {}
|
||||
|
||||
get(name: string): o.Expression|null {
|
||||
let current: BindingScope|null = this;
|
||||
while (current) {
|
||||
const value = current.map.get(name);
|
||||
if (value != null) {
|
||||
// Cache the value locally.
|
||||
this.map.set(name, value);
|
||||
return value;
|
||||
}
|
||||
current = current.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
set(name: string, variableName: string): BindingScope {
|
||||
!this.map.has(name) ||
|
||||
error(`The name ${name} is already defined in scope to be ${this.map.get(name)}`);
|
||||
this.map.set(name, o.variable(variableName));
|
||||
return this;
|
||||
}
|
||||
|
||||
nestedScope(): BindingScope { return new BindingScope(this); }
|
||||
|
||||
freshReferenceName(): string {
|
||||
let current: BindingScope|null = this;
|
||||
// Find the top scope as it maintains the global reference count
|
||||
while (current.parent) current = current.parent;
|
||||
return `${REFERENCE_PREFIX}${current.referenceNameIndex++}`;
|
||||
}
|
||||
}
|
||||
|
||||
const ROOT_SCOPE = new BindingScope(null).set('$event', '$event');
|
||||
|
||||
class TemplateDefinitionBuilder implements TemplateAstVisitor, LocalResolver {
|
||||
private _dataIndex = 0;
|
||||
private _bindingContext = 0;
|
||||
private _referenceIndex = 0;
|
||||
private _temporaryAllocated = false;
|
||||
private _prefix: o.Statement[] = [];
|
||||
private _creationMode: o.Statement[] = [];
|
||||
private _bindingMode: o.Statement[] = [];
|
||||
private _hostMode: o.Statement[] = [];
|
||||
private _refreshMode: o.Statement[] = [];
|
||||
private _postfix: o.Statement[] = [];
|
||||
private _contentProjections: Map<NgContentAst, NgContentInfo>;
|
||||
private _projectionDefinitionIndex = 0;
|
||||
private unsupported = unsupported;
|
||||
private invalid = invalid;
|
||||
|
||||
constructor(
|
||||
private outputCtx: OutputContext, private constantPool: ConstantPool,
|
||||
private reflector: CompileReflector, private contextParameter: string,
|
||||
private bindingScope: BindingScope, private level = 0, private ngContentSelectors: string[],
|
||||
private contextName: string|null, private templateName: string|null) {}
|
||||
|
||||
buildTemplateFunction(asts: TemplateAst[], variables: VariableAst[]): o.FunctionExpr {
|
||||
// Create variable bindings
|
||||
for (const variable of variables) {
|
||||
const variableName = variable.name;
|
||||
const expression =
|
||||
o.variable(this.contextParameter).prop(variable.value || IMPLICIT_REFERENCE);
|
||||
const scopedName = this.bindingScope.freshReferenceName();
|
||||
const declaration = o.variable(scopedName).set(expression).toDeclStmt(o.INFERRED_TYPE, [
|
||||
o.StmtModifier.Final
|
||||
]);
|
||||
|
||||
// Add the reference to the local scope.
|
||||
this.bindingScope.set(variableName, scopedName);
|
||||
|
||||
// Declare the local variable in binding mode
|
||||
this._bindingMode.push(declaration);
|
||||
}
|
||||
|
||||
// Collect content projections
|
||||
if (this.ngContentSelectors && this.ngContentSelectors.length > 0) {
|
||||
const contentProjections = getContentProjection(asts, this.ngContentSelectors);
|
||||
this._contentProjections = contentProjections;
|
||||
if (contentProjections.size > 0) {
|
||||
const infos: R3CssSelector[] = [];
|
||||
Array.from(contentProjections.values()).forEach(info => {
|
||||
if (info.selector) {
|
||||
infos[info.index - 1] = info.selector;
|
||||
}
|
||||
});
|
||||
const projectionIndex = this._projectionDefinitionIndex = this.allocateDataSlot();
|
||||
const parameters: o.Expression[] = [o.literal(projectionIndex)];
|
||||
!infos.some(value => !value) || error(`content project information skipped an index`);
|
||||
if (infos.length > 1) {
|
||||
parameters.push(this.outputCtx.constantPool.getConstLiteral(
|
||||
asLiteral(infos), /* forceShared */ true));
|
||||
}
|
||||
this.instruction(this._creationMode, null, R3.projectionDef, ...parameters);
|
||||
}
|
||||
}
|
||||
|
||||
templateVisitAll(this, asts);
|
||||
|
||||
return o.fn(
|
||||
[
|
||||
new o.FnParam(this.contextParameter, null), new o.FnParam(CREATION_MODE_FLAG, o.BOOL_TYPE)
|
||||
],
|
||||
[
|
||||
// Temporary variable declarations (i.e. let _t: any;)
|
||||
...this._prefix,
|
||||
|
||||
// Creating mode (i.e. if (cm) { ... })
|
||||
o.ifStmt(o.variable(CREATION_MODE_FLAG), this._creationMode),
|
||||
|
||||
// Binding mode (i.e. ɵp(...))
|
||||
...this._bindingMode,
|
||||
|
||||
// Host mode (i.e. Comp.h(...))
|
||||
...this._hostMode,
|
||||
|
||||
// Refresh mode (i.e. Comp.r(...))
|
||||
...this._refreshMode,
|
||||
|
||||
// Nested templates (i.e. function CompTemplate() {})
|
||||
...this._postfix
|
||||
],
|
||||
o.INFERRED_TYPE, null, this.templateName);
|
||||
}
|
||||
|
||||
getLocal(name: string): o.Expression|null { return this.bindingScope.get(name); }
|
||||
|
||||
visitNgContent(ast: NgContentAst) {
|
||||
const info = this._contentProjections.get(ast) !;
|
||||
info || error(`Expected ${ast.sourceSpan} to be included in content projection collection`);
|
||||
const slot = this.allocateDataSlot();
|
||||
const parameters = [o.literal(slot), o.literal(this._projectionDefinitionIndex)];
|
||||
if (info.index !== 0) {
|
||||
parameters.push(o.literal(info.index));
|
||||
}
|
||||
this.instruction(this._creationMode, ast.sourceSpan, R3.projection, ...parameters);
|
||||
}
|
||||
|
||||
private _computeDirectivesArray(directives: DirectiveAst[]) {
|
||||
const directiveIndexMap = new Map<any, number>();
|
||||
const directiveExpressions: o.Expression[] =
|
||||
directives.filter(directive => !directive.directive.isComponent).map(directive => {
|
||||
directiveIndexMap.set(directive.directive.type.reference, this.allocateDataSlot());
|
||||
return this.typeReference(directive.directive.type.reference);
|
||||
});
|
||||
return {
|
||||
directivesArray: directiveExpressions.length ?
|
||||
this.constantPool.getConstLiteral(
|
||||
o.literalArr(directiveExpressions), /* forceShared */ true) :
|
||||
o.literal(null),
|
||||
directiveIndexMap
|
||||
};
|
||||
}
|
||||
|
||||
visitElement(ast: ElementAst) {
|
||||
let bindingCount = 0;
|
||||
const elementIndex = this.allocateDataSlot();
|
||||
let componentIndex: number|undefined = undefined;
|
||||
const referenceDataSlots = new Map<string, number>();
|
||||
|
||||
// Element creation mode
|
||||
const component = findComponent(ast.directives);
|
||||
const nullNode = o.literal(null, o.INFERRED_TYPE);
|
||||
const parameters: o.Expression[] = [o.literal(elementIndex)];
|
||||
|
||||
// Add component type or element tag
|
||||
if (component) {
|
||||
parameters.push(this.typeReference(component.directive.type.reference));
|
||||
componentIndex = this.allocateDataSlot();
|
||||
} else {
|
||||
parameters.push(o.literal(ast.name));
|
||||
}
|
||||
|
||||
// Add attributes array
|
||||
const attributes: o.Expression[] = [];
|
||||
for (let attr of ast.attrs) {
|
||||
attributes.push(o.literal(attr.name), o.literal(attr.value));
|
||||
}
|
||||
parameters.push(
|
||||
attributes.length > 0 ?
|
||||
this.constantPool.getConstLiteral(o.literalArr(attributes), /* forceShared */ true) :
|
||||
nullNode);
|
||||
|
||||
// Add directives array
|
||||
const {directivesArray, directiveIndexMap} = this._computeDirectivesArray(ast.directives);
|
||||
parameters.push(directiveIndexMap.size > 0 ? directivesArray : nullNode);
|
||||
|
||||
if (component && componentIndex != null) {
|
||||
// Record the data slot for the component
|
||||
directiveIndexMap.set(component.directive.type.reference, componentIndex);
|
||||
}
|
||||
|
||||
// Add references array
|
||||
if (ast.references && ast.references.length > 0) {
|
||||
const references =
|
||||
flatten(ast.references.map(reference => {
|
||||
const slot = this.allocateDataSlot();
|
||||
referenceDataSlots.set(reference.name, slot);
|
||||
// Generate the update temporary.
|
||||
const variableName = this.bindingScope.freshReferenceName();
|
||||
this._bindingMode.push(o.variable(variableName, o.INFERRED_TYPE)
|
||||
.set(o.importExpr(R3.memory).callFn([o.literal(slot)]))
|
||||
.toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
||||
this.bindingScope.set(reference.name, variableName);
|
||||
return [reference.name, reference.originalValue];
|
||||
})).map(value => o.literal(value));
|
||||
parameters.push(
|
||||
this.constantPool.getConstLiteral(o.literalArr(references), /* forceShared */ true));
|
||||
} else {
|
||||
parameters.push(nullNode);
|
||||
}
|
||||
|
||||
// Remove trailing null nodes as they are implied.
|
||||
while (parameters[parameters.length - 1] === nullNode) {
|
||||
parameters.pop();
|
||||
}
|
||||
|
||||
// Generate the instruction create element instruction
|
||||
this.instruction(this._creationMode, ast.sourceSpan, R3.createElement, ...parameters);
|
||||
|
||||
const implicit = o.variable(this.contextParameter);
|
||||
|
||||
// Generate element input bindings
|
||||
for (let input of ast.inputs) {
|
||||
if (input.isAnimation) {
|
||||
this.unsupported('animations');
|
||||
}
|
||||
// TODO(chuckj): Built-in transform?
|
||||
const convertedBinding = convertPropertyBinding(
|
||||
this, implicit, input.value, this.bindingContext(), BindingForm.TrySimple, interpolate);
|
||||
this._bindingMode.push(...convertedBinding.stmts);
|
||||
const parameters =
|
||||
[o.literal(elementIndex), o.literal(input.name), convertedBinding.currValExpr];
|
||||
const instruction = BINDING_INSTRUCTION_MAP[input.type];
|
||||
if (instruction) {
|
||||
// TODO(chuckj): runtime: security context?
|
||||
this.instruction(
|
||||
this._bindingMode, input.sourceSpan, instruction, o.literal(elementIndex),
|
||||
o.literal(input.name), convertedBinding.currValExpr);
|
||||
} else {
|
||||
this.unsupported(`binding ${PropertyBindingType[input.type]}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate directives input bindings
|
||||
this._visitDirectives(ast.directives, implicit, elementIndex, directiveIndexMap);
|
||||
|
||||
// Traverse element child nodes
|
||||
templateVisitAll(this, ast.children);
|
||||
|
||||
// Finish element construction mode.
|
||||
this.instruction(this._creationMode, ast.endSourceSpan || ast.sourceSpan, R3.elementEnd);
|
||||
}
|
||||
|
||||
private _visitDirectives(
|
||||
directives: DirectiveAst[], implicit: o.Expression, nodeIndex: number,
|
||||
directiveIndexMap: Map<any, number>) {
|
||||
for (let directive of directives) {
|
||||
const directiveIndex = directiveIndexMap.get(directive.directive.type.reference);
|
||||
|
||||
// Creation mode
|
||||
// e.g. D(0, TodoComponentDef.n(), TodoComponentDef);
|
||||
const directiveType = directive.directive.type.reference;
|
||||
const kind =
|
||||
directive.directive.isComponent ? DefinitionKind.Component : DefinitionKind.Directive;
|
||||
|
||||
// Note: *do not cache* calls to this.directiveOf() as the constant pool needs to know if the
|
||||
// node is referenced multiple times to know that it must generate the reference into a
|
||||
// temporary.
|
||||
|
||||
// Bindings
|
||||
for (const input of directive.inputs) {
|
||||
const convertedBinding = convertPropertyBinding(
|
||||
this, implicit, input.value, this.bindingContext(), BindingForm.TrySimple, interpolate);
|
||||
this._bindingMode.push(...convertedBinding.stmts);
|
||||
this.instruction(
|
||||
this._bindingMode, directive.sourceSpan, R3.elementProperty, o.literal(nodeIndex),
|
||||
o.literal(input.templateName),
|
||||
o.importExpr(R3.bind).callFn([convertedBinding.currValExpr]));
|
||||
}
|
||||
|
||||
// e.g. r(0, 0);
|
||||
this.instruction(
|
||||
this._refreshMode, directive.sourceSpan, R3.refreshComponent, o.literal(directiveIndex),
|
||||
o.literal(nodeIndex));
|
||||
}
|
||||
}
|
||||
|
||||
visitEmbeddedTemplate(ast: EmbeddedTemplateAst) {
|
||||
const templateIndex = this.allocateDataSlot();
|
||||
|
||||
const templateRef = this.reflector.resolveExternalReference(Identifiers.TemplateRef);
|
||||
const templateDirective = ast.directives.find(
|
||||
directive => directive.directive.type.diDeps.some(
|
||||
dependency =>
|
||||
dependency.token != null && (tokenReference(dependency.token) == templateRef)));
|
||||
const contextName =
|
||||
this.contextName && templateDirective && templateDirective.directive.type.reference.name ?
|
||||
`${this.contextName}_${templateDirective.directive.type.reference.name}` :
|
||||
null;
|
||||
const templateName =
|
||||
contextName ? `${contextName}_Template_${templateIndex}` : `Template_${templateIndex}`;
|
||||
const templateContext = `ctx${this.level}`;
|
||||
|
||||
const {directivesArray, directiveIndexMap} = this._computeDirectivesArray(ast.directives);
|
||||
|
||||
// e.g. C(1, C1Template)
|
||||
this.instruction(
|
||||
this._creationMode, ast.sourceSpan, R3.containerCreate, o.literal(templateIndex),
|
||||
directivesArray, o.variable(templateName));
|
||||
|
||||
// e.g. Cr(1)
|
||||
this.instruction(
|
||||
this._refreshMode, ast.sourceSpan, R3.containerRefreshStart, o.literal(templateIndex));
|
||||
|
||||
// Generate directives
|
||||
this._visitDirectives(
|
||||
ast.directives, o.variable(this.contextParameter), templateIndex, directiveIndexMap);
|
||||
|
||||
// e.g. cr();
|
||||
this.instruction(this._refreshMode, ast.sourceSpan, R3.containerRefreshEnd);
|
||||
|
||||
// Create the template function
|
||||
const templateVisitor = new TemplateDefinitionBuilder(
|
||||
this.outputCtx, this.constantPool, this.reflector, templateContext,
|
||||
this.bindingScope.nestedScope(), this.level + 1, this.ngContentSelectors, contextName,
|
||||
templateName);
|
||||
const templateFunctionExpr = templateVisitor.buildTemplateFunction(ast.children, ast.variables);
|
||||
this._postfix.push(templateFunctionExpr.toDeclStmt(templateName, null));
|
||||
}
|
||||
|
||||
// These should be handled in the template or element directly.
|
||||
readonly visitReference = invalid;
|
||||
readonly visitVariable = invalid;
|
||||
readonly visitEvent = invalid;
|
||||
readonly visitElementProperty = invalid;
|
||||
readonly visitAttr = invalid;
|
||||
|
||||
visitBoundText(ast: BoundTextAst) {
|
||||
const nodeIndex = this.allocateDataSlot();
|
||||
|
||||
// Creation mode
|
||||
this.instruction(this._creationMode, ast.sourceSpan, R3.text, o.literal(nodeIndex));
|
||||
|
||||
// Refresh mode
|
||||
this.instruction(
|
||||
this._refreshMode, ast.sourceSpan, R3.textCreateBound, o.literal(nodeIndex),
|
||||
this.bind(o.variable(CONTEXT_NAME), ast.value, ast.sourceSpan));
|
||||
}
|
||||
|
||||
visitText(ast: TextAst) {
|
||||
// Text is defined in creation mode only.
|
||||
this.instruction(
|
||||
this._creationMode, ast.sourceSpan, R3.text, o.literal(this.allocateDataSlot()),
|
||||
o.literal(ast.value));
|
||||
}
|
||||
|
||||
// These should be handled in the template or element directly
|
||||
readonly visitDirective = invalid;
|
||||
readonly visitDirectiveProperty = invalid;
|
||||
|
||||
private allocateDataSlot() { return this._dataIndex++; }
|
||||
private bindingContext() { return `${this._bindingContext++}`; }
|
||||
|
||||
private instruction(
|
||||
statements: o.Statement[], span: ParseSourceSpan|null, reference: o.ExternalReference,
|
||||
...params: o.Expression[]) {
|
||||
statements.push(o.importExpr(reference, null, span).callFn(params, span).toStmt());
|
||||
}
|
||||
|
||||
private typeReference(type: any): o.Expression { return this.outputCtx.importExpr(type); }
|
||||
|
||||
private definitionOf(type: any, kind: DefinitionKind): o.Expression {
|
||||
return this.constantPool.getDefinition(type, kind, this.outputCtx);
|
||||
}
|
||||
|
||||
private temp(): o.ReadVarExpr {
|
||||
if (!this._temporaryAllocated) {
|
||||
this._prefix.push(o.variable(TEMPORARY_NAME, o.DYNAMIC_TYPE, null)
|
||||
.set(o.literal(undefined))
|
||||
.toDeclStmt(o.DYNAMIC_TYPE));
|
||||
this._temporaryAllocated = true;
|
||||
}
|
||||
return o.variable(TEMPORARY_NAME);
|
||||
}
|
||||
|
||||
private convertPropertyBinding(implicit: o.Expression, value: AST): o.Expression {
|
||||
const convertedPropertyBinding = convertPropertyBinding(
|
||||
this, implicit, value, this.bindingContext(), BindingForm.TrySimple, interpolate);
|
||||
this._refreshMode.push(...convertedPropertyBinding.stmts);
|
||||
return convertedPropertyBinding.currValExpr;
|
||||
}
|
||||
|
||||
private bind(implicit: o.Expression, value: AST, sourceSpan: ParseSourceSpan): o.Expression {
|
||||
return this.convertPropertyBinding(implicit, value);
|
||||
}
|
||||
}
|
||||
|
||||
function createFactory(
|
||||
type: CompileTypeMetadata, outputCtx: OutputContext,
|
||||
reflector: CompileReflector): o.FunctionExpr {
|
||||
let args: o.Expression[] = [];
|
||||
|
||||
const elementRef = reflector.resolveExternalReference(Identifiers.ElementRef);
|
||||
const templateRef = reflector.resolveExternalReference(Identifiers.TemplateRef);
|
||||
const viewContainerRef = reflector.resolveExternalReference(Identifiers.ViewContainerRef);
|
||||
|
||||
for (let dependency of type.diDeps) {
|
||||
if (dependency.isValue) {
|
||||
unsupported('value dependencies');
|
||||
}
|
||||
if (dependency.isHost) {
|
||||
unsupported('host dependencies');
|
||||
}
|
||||
const token = dependency.token;
|
||||
if (token) {
|
||||
const tokenRef = tokenReference(token);
|
||||
if (tokenRef === elementRef) {
|
||||
args.push(o.importExpr(R3.injectElementRef).callFn([]));
|
||||
} else if (tokenRef === templateRef) {
|
||||
args.push(o.importExpr(R3.injectTemplateRef).callFn([]));
|
||||
} else if (tokenRef === viewContainerRef) {
|
||||
args.push(o.importExpr(R3.injectViewContainerRef).callFn([]));
|
||||
} else {
|
||||
const value =
|
||||
token.identifier != null ? outputCtx.importExpr(tokenRef) : o.literal(tokenRef);
|
||||
args.push(o.importExpr(R3.inject).callFn([value]));
|
||||
}
|
||||
} else {
|
||||
unsupported('dependency without a token');
|
||||
}
|
||||
}
|
||||
|
||||
return o.fn(
|
||||
[],
|
||||
[new o.ReturnStatement(new o.InstantiateExpr(outputCtx.importExpr(type.reference), args))],
|
||||
o.INFERRED_TYPE, null, type.reference.name ? `${type.reference.name}_Factory` : null);
|
||||
}
|
||||
|
||||
function invalid<T>(arg: o.Expression | o.Statement | TemplateAst): never {
|
||||
throw new Error(
|
||||
`Invalid state: Visitor ${this.constructor.name} doesn't handle ${o.constructor.name}`);
|
||||
}
|
||||
|
||||
function findComponent(directives: DirectiveAst[]): DirectiveAst|undefined {
|
||||
return directives.filter(directive => directive.directive.isComponent)[0];
|
||||
}
|
||||
|
||||
interface NgContentInfo {
|
||||
index: number;
|
||||
selector?: R3CssSelector;
|
||||
}
|
||||
|
||||
class ContentProjectionVisitor extends RecursiveTemplateAstVisitor {
|
||||
private index = 1;
|
||||
constructor(
|
||||
private projectionMap: Map<NgContentAst, NgContentInfo>,
|
||||
private ngContentSelectors: string[]) {
|
||||
super();
|
||||
}
|
||||
|
||||
visitNgContent(ast: NgContentAst) {
|
||||
const selectorText = this.ngContentSelectors[ast.index];
|
||||
selectorText != null || error(`could not find selector for index ${ast.index} in ${ast}`);
|
||||
if (!selectorText || selectorText === '*') {
|
||||
this.projectionMap.set(ast, {index: 0});
|
||||
} else {
|
||||
const cssSelectors = CssSelector.parse(selectorText);
|
||||
this.projectionMap.set(
|
||||
ast, {index: this.index++, selector: parseSelectorsToR3Selector(cssSelectors)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getContentProjection(asts: TemplateAst[], ngContentSelectors: string[]) {
|
||||
const projectIndexMap = new Map<NgContentAst, NgContentInfo>();
|
||||
const visitor = new ContentProjectionVisitor(projectIndexMap, ngContentSelectors);
|
||||
templateVisitAll(visitor, asts);
|
||||
return projectIndexMap;
|
||||
}
|
||||
|
||||
// These are a copy the CSS types from core/src/render3/interfaces/projection.ts
|
||||
// They are duplicated here as they cannot be directly referenced from core.
|
||||
type R3SimpleCssSelector = (string | null)[];
|
||||
type R3CssSelectorWithNegations =
|
||||
[R3SimpleCssSelector, null] | [R3SimpleCssSelector, R3SimpleCssSelector];
|
||||
type R3CssSelector = R3CssSelectorWithNegations[];
|
||||
|
||||
function parserSelectorToSimpleSelector(selector: CssSelector): R3SimpleCssSelector {
|
||||
const classes =
|
||||
selector.classNames && selector.classNames.length ? ['class', ...selector.classNames] : [];
|
||||
return [selector.element, ...selector.attrs, ...classes];
|
||||
}
|
||||
|
||||
function parserSelectorToR3Selector(selector: CssSelector): R3CssSelectorWithNegations {
|
||||
const positive = parserSelectorToSimpleSelector(selector);
|
||||
const negative = selector.notSelectors && selector.notSelectors.length &&
|
||||
parserSelectorToSimpleSelector(selector.notSelectors[0]);
|
||||
|
||||
return negative ? [positive, negative] : [positive, null];
|
||||
}
|
||||
|
||||
function parseSelectorsToR3Selector(selectors: CssSelector[]): R3CssSelector {
|
||||
return selectors.map(parserSelectorToR3Selector);
|
||||
}
|
||||
|
||||
function asLiteral(value: any): o.Expression {
|
||||
if (Array.isArray(value)) {
|
||||
return o.literalArr(value.map(asLiteral));
|
||||
}
|
||||
return o.literal(value, o.INFERRED_TYPE);
|
||||
}
|
@ -104,14 +104,6 @@ export class CssSelector {
|
||||
`<${tagName}${classAttr}${attrs}></${tagName}>`;
|
||||
}
|
||||
|
||||
getAttrs(): string[] {
|
||||
const result: string[] = [];
|
||||
if (this.classNames.length > 0) {
|
||||
result.push('class', this.classNames.join(' '));
|
||||
}
|
||||
return result.concat(this.attrs);
|
||||
}
|
||||
|
||||
addAttribute(name: string, value: string = '') {
|
||||
this.attrs.push(name, value && value.toLowerCase() || '');
|
||||
}
|
||||
|
@ -110,8 +110,8 @@ export class BoundEventAst implements TemplateAst {
|
||||
*/
|
||||
export class ReferenceAst implements TemplateAst {
|
||||
constructor(
|
||||
public name: string, public value: CompileTokenMetadata, public originalValue: string,
|
||||
public sourceSpan: ParseSourceSpan) {}
|
||||
public name: string, public value: CompileTokenMetadata, public sourceSpan: ParseSourceSpan) {
|
||||
}
|
||||
visit(visitor: TemplateAstVisitor, context: any): any {
|
||||
return visitor.visitReference(this, context);
|
||||
}
|
||||
|
@ -574,7 +574,7 @@ class TemplateParseVisitor implements html.Visitor {
|
||||
if ((elOrDirRef.value.length === 0 && directive.isComponent) ||
|
||||
(elOrDirRef.isReferenceToDirective(directive))) {
|
||||
targetReferences.push(new ReferenceAst(
|
||||
elOrDirRef.name, createTokenForReference(directive.type.reference), elOrDirRef.value,
|
||||
elOrDirRef.name, createTokenForReference(directive.type.reference),
|
||||
elOrDirRef.sourceSpan));
|
||||
matchedReferences.add(elOrDirRef.name);
|
||||
}
|
||||
@ -598,8 +598,7 @@ class TemplateParseVisitor implements html.Visitor {
|
||||
if (isTemplateElement) {
|
||||
refToken = createTokenForExternalReference(this.reflector, Identifiers.TemplateRef);
|
||||
}
|
||||
targetReferences.push(
|
||||
new ReferenceAst(elOrDirRef.name, refToken, elOrDirRef.value, elOrDirRef.sourceSpan));
|
||||
targetReferences.push(new ReferenceAst(elOrDirRef.name, refToken, elOrDirRef.sourceSpan));
|
||||
}
|
||||
});
|
||||
return directiveAsts;
|
||||
|
@ -6,8 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ConstantPool} from './constant_pool';
|
||||
|
||||
import * as o from './output/output_ast';
|
||||
import {ParseError} from './parse_util';
|
||||
|
||||
@ -92,10 +90,6 @@ export const SyncAsync = {
|
||||
}
|
||||
};
|
||||
|
||||
export function error(msg: string): never {
|
||||
throw new Error(`Internal Error: ${msg}`);
|
||||
}
|
||||
|
||||
export function syntaxError(msg: string, parseErrors?: ParseError[]): Error {
|
||||
const error = Error(msg);
|
||||
(error as any)[ERROR_SYNTAX_ERROR] = true;
|
||||
@ -158,7 +152,6 @@ export function utf8Encode(str: string): string {
|
||||
export interface OutputContext {
|
||||
genFilePath: string;
|
||||
statements: o.Statement[];
|
||||
constantPool: ConstantPool;
|
||||
importExpr(reference: any, typeParams?: o.Type[]|null, useSummaries?: boolean): o.Expression;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
import {AotSummaryResolver, AotSummaryResolverHost, CompileSummaryKind, CompileTypeSummary, ResolvedStaticSymbol, StaticSymbol, StaticSymbolCache, StaticSymbolResolver} from '@angular/compiler';
|
||||
import {deserializeSummaries, serializeSummaries} from '@angular/compiler/src/aot/summary_serializer';
|
||||
import {ConstantPool} from '@angular/compiler/src/constant_pool';
|
||||
import * as o from '@angular/compiler/src/output/output_ast';
|
||||
import {OutputContext} from '@angular/compiler/src/util';
|
||||
import * as path from 'path';
|
||||
@ -128,10 +127,5 @@ export class MockAotSummaryResolverHost implements AotSummaryResolverHost {
|
||||
}
|
||||
|
||||
export function createMockOutputContext(): OutputContext {
|
||||
return {
|
||||
statements: [],
|
||||
genFilePath: 'someGenFilePath',
|
||||
importExpr: () => o.NULL_EXPR,
|
||||
constantPool: new ConstantPool()
|
||||
};
|
||||
return {statements: [], genFilePath: 'someGenFilePath', importExpr: () => o.NULL_EXPR};
|
||||
}
|
@ -538,12 +538,10 @@ const minCoreIndex = `
|
||||
export * from './src/codegen_private_exports';
|
||||
`;
|
||||
|
||||
export function setup(
|
||||
options: {compileAngular: boolean, compileAnimations: boolean, compileCommon?: boolean} = {
|
||||
compileAngular: true,
|
||||
compileAnimations: true,
|
||||
compileCommon: false,
|
||||
}) {
|
||||
export function setup(options: {compileAngular: boolean, compileAnimations: boolean} = {
|
||||
compileAngular: true,
|
||||
compileAnimations: true,
|
||||
}) {
|
||||
let angularFiles = new Map<string, string>();
|
||||
|
||||
beforeAll(() => {
|
||||
@ -554,13 +552,6 @@ export function setup(
|
||||
emittingProgram.emit();
|
||||
emittingHost.writtenAngularFiles(angularFiles);
|
||||
}
|
||||
if (options.compileCommon) {
|
||||
const emittingHost =
|
||||
new EmittingCompilerHost(['@angular/common/index.ts'], {emitMetadata: true});
|
||||
const emittingProgram = ts.createProgram(emittingHost.scripts, settings, emittingHost);
|
||||
emittingProgram.emit();
|
||||
emittingHost.writtenAngularFiles(angularFiles);
|
||||
}
|
||||
if (options.compileAnimations) {
|
||||
const emittingHost =
|
||||
new EmittingCompilerHost(['@angular/animations/index.ts'], {emitMetadata: true});
|
||||
|
@ -1 +0,0 @@
|
||||
Tests in this directory are excluded from running in the browser and only run in node.
|
@ -1,839 +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 {AotCompilerHost, AotCompilerOptions, AotSummaryResolver, CompileDirectiveMetadata, CompileMetadataResolver, CompilerConfig, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, HtmlParser, I18NHtmlParser, Lexer, NgModuleResolver, Parser, PipeResolver, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, TemplateParser, TypeScriptEmitter, analyzeNgModules, createAotUrlResolver} from '@angular/compiler';
|
||||
import {ViewEncapsulation} from '@angular/core';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {ConstantPool} from '../../src/constant_pool';
|
||||
import * as o from '../../src/output/output_ast';
|
||||
import {compileComponent, compileDirective} from '../../src/render3/r3_view_compiler';
|
||||
import {OutputContext} from '../../src/util';
|
||||
import {MockAotCompilerHost, MockCompilerHost, MockData, MockDirectory, arrayToMockDir, settings, setup, toMockFileArray} from '../aot/test_util';
|
||||
|
||||
describe('r3_view_compiler', () => {
|
||||
const angularFiles = setup({
|
||||
compileAngular: true,
|
||||
compileAnimations: false,
|
||||
compileCommon: true,
|
||||
});
|
||||
|
||||
describe('hello world', () => {
|
||||
it('should be able to generate the hello world component', () => {
|
||||
const files: MockDirectory = {
|
||||
app: {
|
||||
'hello.ts': `
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'hello-world',
|
||||
template: 'Hello, world!'
|
||||
})
|
||||
export class HelloWorldComponent {
|
||||
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [HelloWorldComponent]
|
||||
})
|
||||
export class HelloWorldModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
compile(files, angularFiles);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to generate the example', () => {
|
||||
const files: MockDirectory = {
|
||||
app: {
|
||||
'example.ts': `
|
||||
import {Component, OnInit, OnDestroy, ElementRef, Input, NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'my-app',
|
||||
template: '<todo [data]="list"></todo>'
|
||||
})
|
||||
export class MyApp implements OnInit {
|
||||
|
||||
list: any[] = [];
|
||||
|
||||
constructor(public elementRef: ElementRef) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'todo',
|
||||
template: '<ul class="list" [title]="myTitle"><li *ngFor="let item of data">{{data}}</li></ul>'
|
||||
})
|
||||
export class TodoComponent implements OnInit, OnDestroy {
|
||||
|
||||
@Input()
|
||||
data: any[] = [];
|
||||
|
||||
myTitle: string;
|
||||
|
||||
constructor(public elementRef: ElementRef) {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
ngOnDestroy(): void {}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [TodoComponent, MyApp],
|
||||
imports: [CommonModule]
|
||||
})
|
||||
export class TodoModule{}
|
||||
`
|
||||
}
|
||||
};
|
||||
const result = compile(files, angularFiles);
|
||||
expect(result.source).toContain('@angular/core');
|
||||
});
|
||||
|
||||
/* These tests are codified version of the tests in compiler_canonical_spec.ts. Every
|
||||
* test in compiler_canonical_spec.ts should have a corresponding test here.
|
||||
*/
|
||||
describe('compiler conformance', () => {
|
||||
describe('elements', () => {
|
||||
it('should translate DOM structure', () => {
|
||||
const files = {
|
||||
app: {
|
||||
'spec.ts': `
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: \`<div class="my-app" title="Hello">Hello <b>World</b>!</div>\`
|
||||
})
|
||||
export class MyComponent {}
|
||||
|
||||
@NgModule({declarations: [MyComponent]})
|
||||
export class MyModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
// The factory should look like this:
|
||||
const factory = 'factory: function MyComponent_Factory() { return new MyComponent(); }';
|
||||
|
||||
// The template should look like this (where IDENT is a wild card for an identifier):
|
||||
const template = `
|
||||
template: function MyComponent_Template(ctx: IDENT, cm: IDENT) {
|
||||
if (cm) {
|
||||
IDENT.ɵE(0, 'div', IDENT);
|
||||
IDENT.ɵT(1, 'Hello ');
|
||||
IDENT.ɵE(2, 'b');
|
||||
IDENT.ɵT(3, 'World');
|
||||
IDENT.ɵe();
|
||||
IDENT.ɵT(4, '!');
|
||||
IDENT.ɵe();
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
// The compiler should also emit a const array like this:
|
||||
const constants = `const IDENT = ['class', 'my-app', 'title', 'Hello'];`;
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
|
||||
expectEmit(result.source, factory, 'Incorrect factory');
|
||||
expectEmit(result.source, template, 'Incorrect template');
|
||||
expectEmit(result.source, constants, 'Incorrect shared constants');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('components & directives', () => {
|
||||
it('should instantiate directives', () => {
|
||||
const files = {
|
||||
app: {
|
||||
'spec.ts': `
|
||||
import {Component, Directive, NgModule} from '@angular/core';
|
||||
|
||||
@Component({selector: 'child', template: 'child-view'})
|
||||
export class ChildComponent {}
|
||||
|
||||
@Directive({selector: '[some-directive]'})
|
||||
export class SomeDirective {}
|
||||
|
||||
@Component({selector: 'my-component', template: '<child some-directive></child>!'})
|
||||
export class MyComponent {}
|
||||
|
||||
@NgModule({declarations: [ChildComponent, SomeDirective, MyComponent]})
|
||||
export class MyModule{}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
// ChildComponent definition should be:
|
||||
const ChildComponentDefinition = `
|
||||
static ngComponentDef = IDENT.ɵdefineComponent({
|
||||
type: ChildComponent,
|
||||
tag: 'child',
|
||||
factory: function ChildComponent_Factory() { return new ChildComponent(); },
|
||||
template: function ChildComponent_Template(ctx: IDENT, cm: IDENT) {
|
||||
if (cm) {
|
||||
IDENT.ɵT(0, 'child-view');
|
||||
}
|
||||
}
|
||||
});`;
|
||||
|
||||
// SomeDirective definition should be:
|
||||
const SomeDirectiveDefinition = `
|
||||
static ngDirectiveDef = IDENT.ɵdefineDirective({
|
||||
type: SomeDirective,
|
||||
factory: function SomeDirective_Factory() {return new SomeDirective(); }
|
||||
});
|
||||
`;
|
||||
|
||||
// MyComponent definition should be:
|
||||
const MyComponentDefinition = `
|
||||
static ngComponentDef = IDENT.ɵdefineComponent({
|
||||
type: MyComponent,
|
||||
tag: 'my-component',
|
||||
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||
template: function MyComponent_Template(ctx: IDENT, cm: IDENT) {
|
||||
if (cm) {
|
||||
IDENT.ɵE(0, ChildComponent, IDENT, IDENT);
|
||||
IDENT.ɵe();
|
||||
IDENT.ɵT(3, '!');
|
||||
}
|
||||
IDENT.ɵr(1, 0);
|
||||
IDENT.ɵr(2, 0);
|
||||
}
|
||||
});
|
||||
`;
|
||||
|
||||
// The following constants should be emitted as well.
|
||||
const AttributesConstant = `const IDENT = ['some-directive', ''];`;
|
||||
|
||||
const DirectivesConstant = `const IDENT = [SomeDirective];`;
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
const source = result.source;
|
||||
|
||||
expectEmit(source, ChildComponentDefinition, 'Incorrect ChildComponent.ngComponentDef');
|
||||
expectEmit(source, SomeDirectiveDefinition, 'Incorrect SomeDirective.ngDirectiveDef');
|
||||
expectEmit(source, MyComponentDefinition, 'Incorrect MyComponentDefinition.ngComponentDef');
|
||||
expectEmit(source, AttributesConstant, 'Incorrect shared attributes constant');
|
||||
expectEmit(source, DirectivesConstant, 'Incorrect share directives constant');
|
||||
});
|
||||
|
||||
it('should support structural directives', () => {
|
||||
const files = {
|
||||
app: {
|
||||
'spec.ts': `
|
||||
import {Component, Directive, NgModule, TemplateRef} from '@angular/core';
|
||||
|
||||
@Directive({selector: '[if]'})
|
||||
export class IfDirective {
|
||||
constructor(template: TemplateRef<any>) { }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: '<ul #foo><li *if>{{salutation}} {{foo}}</li></ul>'
|
||||
})
|
||||
export class MyComponent {
|
||||
salutation = 'Hello';
|
||||
}
|
||||
|
||||
@NgModule({declarations: [IfDirective, MyComponent]})
|
||||
export class MyModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const IfDirectiveDefinition = `
|
||||
static ngDirectiveDef = IDENT.ɵdefineDirective({
|
||||
type: IfDirective,
|
||||
factory: function IfDirective_Factory() { return new IfDirective(IDENT.ɵinjectTemplateRef()); }
|
||||
});`;
|
||||
const MyComponentDefinition = `
|
||||
static ngComponentDef = IDENT.ɵdefineComponent({
|
||||
type: MyComponent,
|
||||
tag: 'my-component',
|
||||
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||
template: function MyComponent_Template(ctx: IDENT, cm: IDENT) {
|
||||
if (cm) {
|
||||
IDENT.ɵE(0, 'ul', null, null, IDENT);
|
||||
IDENT.ɵC(2, IDENT, MyComponent_IfDirective_Template_2);
|
||||
IDENT.ɵe();
|
||||
}
|
||||
const IDENT = IDENT.ɵm(1);
|
||||
IDENT.ɵcR(2);
|
||||
IDENT.ɵr(3,2);
|
||||
IDENT.ɵcr();
|
||||
|
||||
function MyComponent_IfDirective_Template_2(ctx0: IDENT, cm: IDENT) {
|
||||
if (cm) {
|
||||
IDENT.ɵE(0, 'li');
|
||||
IDENT.ɵT(1);
|
||||
IDENT.ɵe();
|
||||
}
|
||||
IDENT.ɵt(1, IDENT.ɵb2('', ctx.salutation, ' ', IDENT, ''));
|
||||
}
|
||||
}
|
||||
});`;
|
||||
const locals = `const IDENT = ['foo', ''];`;
|
||||
const directives = `const IDENT = [IfDirective];`;
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
const source = result.source;
|
||||
|
||||
expectEmit(source, IfDirectiveDefinition, 'Incorrect IfDirective.ngDirectiveDef');
|
||||
expectEmit(source, MyComponentDefinition, 'Incorrect MyComponent.ngComponentDef');
|
||||
expectEmit(source, locals, 'Incorrect share locals constant');
|
||||
expectEmit(source, directives, 'Incorrect shared directive constant');
|
||||
});
|
||||
|
||||
it('should support content projection', () => {
|
||||
const files = {
|
||||
app: {
|
||||
'spec.ts': `
|
||||
import {Component, Directive, NgModule, TemplateRef} from '@angular/core';
|
||||
|
||||
@Component({selector: 'simple', template: '<div><ng-content></ng-content></div>'})
|
||||
export class SimpleComponent {}
|
||||
|
||||
@Component({
|
||||
selector: 'complex',
|
||||
template: \`
|
||||
<div id="first"><ng-content select="span[title=toFirst]"></ng-content></div>
|
||||
<div id="second"><ng-content select="span[title=toSecond]"></ng-content></div>\`
|
||||
})
|
||||
export class ComplexComponent { }
|
||||
|
||||
@NgModule({declarations: [SimpleComponent, ComplexComponent]})
|
||||
export class MyModule {}
|
||||
|
||||
@Component({
|
||||
selector: 'my-app',
|
||||
template: '<simple>content</simple> <complex></complex>'
|
||||
})
|
||||
export class MyApp {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const SimpleComponentDefinition = `
|
||||
static ngComponentDef = IDENT.ɵdefineComponent({
|
||||
type: SimpleComponent,
|
||||
tag: 'simple',
|
||||
factory: function SimpleComponent_Factory() { return new SimpleComponent(); },
|
||||
template: function SimpleComponent_Template(ctx: IDENT, cm: IDENT) {
|
||||
if (cm) {
|
||||
IDENT.ɵpD(0);
|
||||
IDENT.ɵE(1, 'div');
|
||||
IDENT.ɵP(2, 0);
|
||||
IDENT.ɵe();
|
||||
}
|
||||
}
|
||||
});`;
|
||||
|
||||
const ComplexComponentDefinition = `
|
||||
static ngComponentDef = IDENT.ɵdefineComponent({
|
||||
type: ComplexComponent,
|
||||
tag: 'complex',
|
||||
factory: function ComplexComponent_Factory() { return new ComplexComponent(); },
|
||||
template: function ComplexComponent_Template(ctx: IDENT, cm: IDENT) {
|
||||
if (cm) {
|
||||
IDENT.ɵpD(0, IDENT);
|
||||
IDENT.ɵE(1, 'div', IDENT);
|
||||
IDENT.ɵP(2, 0, 1);
|
||||
IDENT.ɵe();
|
||||
IDENT.ɵE(3, 'div', IDENT);
|
||||
IDENT.ɵP(4, 0, 2);
|
||||
IDENT.ɵe();
|
||||
}
|
||||
}
|
||||
});
|
||||
`;
|
||||
|
||||
const ComplexComponent_ProjectionConst = `
|
||||
const IDENT = [[[['span', 'title', 'tofirst'], null]], [[['span', 'title', 'tosecond'], null]]];
|
||||
`;
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
const source = result.source;
|
||||
|
||||
expectEmit(result.source, SimpleComponentDefinition, 'Incorrect SimpleComponent definition');
|
||||
expectEmit(
|
||||
result.source, ComplexComponentDefinition, 'Incorrect ComplexComponent definition');
|
||||
expectEmit(result.source, ComplexComponent_ProjectionConst, 'Incorrect projection const');
|
||||
});
|
||||
|
||||
it('local reference', () => {
|
||||
const files = {
|
||||
app: {
|
||||
'spec.ts': `
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
|
||||
@Component({selector: 'my-component', template: '<input #user>Hello {{user.value}}!'})
|
||||
export class MyComponent {}
|
||||
|
||||
@NgModule({declarations: [MyComponent]})
|
||||
export class MyModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const MyComponentDefinition = `
|
||||
static ngComponentDef = IDENT.ɵdefineComponent({
|
||||
type: MyComponent,
|
||||
tag: 'my-component',
|
||||
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||
template: function MyComponent_Template(ctx: IDENT, cm: IDENT) {
|
||||
if (cm) {
|
||||
IDENT.ɵE(0, 'input', null, null, IDENT);
|
||||
IDENT.ɵe();
|
||||
IDENT.ɵT(2);
|
||||
}
|
||||
const IDENT = IDENT.ɵm(1);
|
||||
IDENT.ɵt(2, IDENT.ɵb1('Hello ', IDENT.value, '!'));
|
||||
}
|
||||
});
|
||||
`;
|
||||
|
||||
const locals = `const IDENT = ['user', ''];`;
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
const source = result.source;
|
||||
|
||||
expectEmit(source, MyComponentDefinition, 'Incorrect MyComponent.ngComponentDef');
|
||||
expectEmit(source, locals, 'Incorrect locals constant definition');
|
||||
});
|
||||
|
||||
describe('template variables', () => {
|
||||
const shared = {
|
||||
shared: {
|
||||
'for_of.ts': `
|
||||
import {Directive, Input, SimpleChanges, TemplateRef, ViewContainerRef} from '@angular/core';
|
||||
|
||||
export interface ForOfContext {
|
||||
$implicit: any;
|
||||
index: number;
|
||||
even: boolean;
|
||||
odd: boolean;
|
||||
}
|
||||
|
||||
@Directive({selector: '[forOf]'})
|
||||
export class ForOfDirective {
|
||||
private previous: any[];
|
||||
|
||||
constructor(private view: ViewContainerRef, private template: TemplateRef<any>) {}
|
||||
|
||||
@Input() forOf: any[];
|
||||
|
||||
ngOnChanges(simpleChanges: SimpleChanges) {
|
||||
if ('forOf' in simpleChanges) {
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
|
||||
ngDoCheck(): void {
|
||||
const previous = this.previous;
|
||||
const current = this.forOf;
|
||||
if (!previous || previous.length != current.length ||
|
||||
previous.some((value: any, index: number) => current[index] !== previous[index])) {
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
|
||||
private update() {
|
||||
// TODO(chuckj): Not implemented yet
|
||||
// this.view.clear();
|
||||
if (this.forOf) {
|
||||
const current = this.forOf;
|
||||
for (let i = 0; i < current.length; i++) {
|
||||
const context = {$implicit: current[i], index: i, even: i % 2 == 0, odd: i % 2 == 1};
|
||||
// TODO(chuckj): Not implemented yet
|
||||
// this.view.createEmbeddedView(this.template, context);
|
||||
}
|
||||
this.previous = [...this.forOf];
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
it('should support a let variable and reference', () => {
|
||||
const files = {
|
||||
app: {
|
||||
...shared,
|
||||
'spec.ts': `
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
import {ForOfDirective} from './shared/for_of';
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: \`<ul><li *for="let item of items">{{item.name}}</li></ul>\`
|
||||
})
|
||||
export class MyComponent {
|
||||
items = [{name: 'one'}, {name: 'two'}];
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [MyComponent, ForOfDirective]
|
||||
})
|
||||
export class MyModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(chuckj): Enforce this when the directives are specified
|
||||
const ForDirectiveDefinition = `
|
||||
static ngDirectiveDef = IDENT.ɵdefineDirective({
|
||||
type: ForOfDirective,
|
||||
factory: function ForOfDirective_Factory() {
|
||||
return new ForOfDirective(IDENT.ɵinjectViewContainerRef(), IDENT.ɵinjectTemplateRef());
|
||||
},
|
||||
features: [IDENT.ɵNgOnChangesFeature(NgForOf)],
|
||||
inputs: {forOf: 'forOf'}
|
||||
});
|
||||
`;
|
||||
|
||||
const MyComponentDefinition = `
|
||||
static ngComponentDef = IDENT.ɵdefineComponent({
|
||||
type: MyComponent,
|
||||
tag: 'my-component',
|
||||
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||
template: function MyComponent_Template(ctx: IDENT, cm: IDENT) {
|
||||
if (cm) {
|
||||
IDENT.ɵE(0, 'ul');
|
||||
IDENT.ɵC(1, IDENT, MyComponent_ForOfDirective_Template_1);
|
||||
IDENT.ɵe();
|
||||
}
|
||||
IDENT.ɵp(1, 'forOf', IDENT.ɵb(ctx.items));
|
||||
IDENT.ɵcR(1);
|
||||
IDENT.ɵr(2, 1);
|
||||
IDENT.ɵcr();
|
||||
|
||||
function MyComponent_ForOfDirective_Template_1(ctx0: IDENT, cm: IDENT) {
|
||||
if (cm) {
|
||||
IDENT.ɵE(0, 'li');
|
||||
IDENT.ɵT(1);
|
||||
IDENT.ɵe();
|
||||
}
|
||||
const IDENT = ctx0.$implicit;
|
||||
IDENT.ɵt(1, IDENT.ɵb1('', IDENT.name, ''));
|
||||
}
|
||||
}
|
||||
});
|
||||
`;
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
const source = result.source;
|
||||
|
||||
// TODO(chuckj): Enforce this when the directives are specified
|
||||
// expectEmit(source, ForDirectiveDefinition, 'Invalid directive definition');
|
||||
expectEmit(source, MyComponentDefinition, 'Invalid component definition');
|
||||
});
|
||||
|
||||
it('should support accessing parent template variables', () => {
|
||||
const files = {
|
||||
app: {
|
||||
...shared,
|
||||
'spec.ts': `
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
import {ForOfDirective} from './shared/for_of';
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: \`
|
||||
<ul>
|
||||
<li *for="let item of items">
|
||||
<div>{{item.name}}</div>
|
||||
<ul>
|
||||
<li *for="let info of item.infos">
|
||||
{{item.name}}: {{info.description}}
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>\`
|
||||
})
|
||||
export class MyComponent {
|
||||
items: Item[] = [
|
||||
{name: 'one', infos: [{description: '11'}, {description: '12'}]},
|
||||
{name: 'two', infos: [{description: '21'}, {description: '22'}]}
|
||||
];
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [MyComponent, ForOfDirective]
|
||||
})
|
||||
export class MyModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const MyComponentDefinition = `
|
||||
static ngComponentDef = IDENT.ɵdefineComponent({
|
||||
type: MyComponent,
|
||||
tag: 'my-component',
|
||||
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||
template: function MyComponent_Template(ctx: IDENT, cm: IDENT) {
|
||||
if (cm) {
|
||||
IDENT.ɵE(0, 'ul');
|
||||
IDENT.ɵC(1, IDENT, MyComponent_ForOfDirective_Template_1);
|
||||
IDENT.ɵe();
|
||||
}
|
||||
IDENT.ɵp(1, 'forOf', IDENT.ɵb(ctx.items));
|
||||
IDENT.ɵcR(1);
|
||||
IDENT.ɵr(2, 1);
|
||||
IDENT.ɵcr();
|
||||
|
||||
function MyComponent_ForOfDirective_Template_1(ctx0: IDENT, cm: IDENT) {
|
||||
if (cm) {
|
||||
IDENT.ɵE(0, 'li');
|
||||
IDENT.ɵE(1, 'div');
|
||||
IDENT.ɵT(2);
|
||||
IDENT.ɵe();
|
||||
IDENT.ɵE(3, 'ul');
|
||||
IDENT.ɵC(4, IDENT, MyComponent_ForOfDirective_ForOfDirective_Template_4);
|
||||
IDENT.ɵe();
|
||||
IDENT.ɵe();
|
||||
}
|
||||
const IDENT = ctx0.$implicit;
|
||||
IDENT.ɵp(4, 'forOf', IDENT.ɵb(IDENT.infos));
|
||||
IDENT.ɵt(2, IDENT.ɵb1('', IDENT.name, ''));
|
||||
IDENT.ɵcR(4);
|
||||
IDENT.ɵr(5, 4);
|
||||
IDENT.ɵcr();
|
||||
|
||||
function MyComponent_ForOfDirective_ForOfDirective_Template_4(
|
||||
ctx1: IDENT, cm: IDENT) {
|
||||
if (cm) {
|
||||
IDENT.ɵE(0, 'li');
|
||||
IDENT.ɵT(1);
|
||||
IDENT.ɵe();
|
||||
}
|
||||
const IDENT = ctx1.$implicit;
|
||||
IDENT.ɵt(1, IDENT.ɵb2(' ', IDENT.name, ': ', IDENT.description, ' '));
|
||||
}
|
||||
}
|
||||
}
|
||||
});`;
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
const source = result.source;
|
||||
expectEmit(source, MyComponentDefinition, 'Invalid component definition');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const IDENTIFIER = /[A-Za-z_$ɵ][A-Za-z0-9_$]*/;
|
||||
const OPERATOR =
|
||||
/!|%|\*|\/|\^|\&|\&\&\|\||\|\||\(|\)|\{|\}|\[|\]|:|;|\.|<|<=|>|>=|=|==|===|!=|!==|=>|\+|\+\+|-|--|@|,|\.|\.\.\./;
|
||||
const STRING = /\'[^'\n]*\'|"[^'\n]*"|`[^`]*`/;
|
||||
const NUMBER = /[0-9]+/;
|
||||
const TOKEN = new RegExp(
|
||||
`^((${IDENTIFIER.source})|(${OPERATOR.source})|(${STRING.source})|${NUMBER.source})`);
|
||||
const WHITESPACE = /^\s+/;
|
||||
|
||||
type Piece = string | RegExp;
|
||||
|
||||
const IDENT = /[A-Za-z$_][A-Za-z0-9$_]*/;
|
||||
|
||||
function tokenize(text: string): Piece[] {
|
||||
function matches(exp: RegExp): string|false {
|
||||
const m = text.match(exp);
|
||||
if (!m) return false;
|
||||
text = text.substr(m[0].length);
|
||||
return m[0];
|
||||
}
|
||||
function next(): string {
|
||||
const result = matches(TOKEN);
|
||||
if (!result) {
|
||||
throw Error(`Invalid test, no token found for '${text.substr(0, 30)}...'`);
|
||||
}
|
||||
matches(WHITESPACE);
|
||||
return result;
|
||||
}
|
||||
|
||||
const pieces: Piece[] = [];
|
||||
matches(WHITESPACE);
|
||||
while (text) {
|
||||
const token = next();
|
||||
if (token === 'IDENT') {
|
||||
pieces.push(IDENT);
|
||||
} else {
|
||||
pieces.push(token);
|
||||
}
|
||||
}
|
||||
return pieces;
|
||||
}
|
||||
|
||||
const contextWidth = 100;
|
||||
function expectEmit(source: string, emitted: string, description: string) {
|
||||
const pieces = tokenize(emitted);
|
||||
const expr = r(...pieces);
|
||||
if (!expr.test(source)) {
|
||||
let last: number = 0;
|
||||
for (let i = 1; i < pieces.length; i++) {
|
||||
let t = r(...pieces.slice(0, i));
|
||||
let m = source.match(t);
|
||||
let expected = pieces[i - 1] == IDENT ? '<IDENT>' : pieces[i - 1];
|
||||
if (!m) {
|
||||
const contextPieceWidth = contextWidth / 2;
|
||||
fail(
|
||||
`${description}: Expected to find ${expected} '${source.substr(0,last)}[<---HERE expected "${expected}"]${source.substr(last)}'`);
|
||||
return;
|
||||
} else {
|
||||
last = (m.index || 0) + m[0].length;
|
||||
}
|
||||
}
|
||||
fail(
|
||||
'Test helper failure: Expected expression failed but the reporting logic could not find where it failed');
|
||||
}
|
||||
}
|
||||
|
||||
const IDENT_LIKE = /^[a-z][A-Z]/;
|
||||
const SPECIAL_RE_CHAR = /\/|\(|\)|\||\*|\+|\[|\]|\{|\}|\$/g;
|
||||
function r(...pieces: (string | RegExp)[]): RegExp {
|
||||
let results: string[] = [];
|
||||
let first = true;
|
||||
for (const piece of pieces) {
|
||||
if (!first)
|
||||
results.push(`\\s${typeof piece === 'string' && IDENT_LIKE.test(piece) ? '+' : '*'}`);
|
||||
first = false;
|
||||
if (typeof piece === 'string') {
|
||||
results.push(piece.replace(SPECIAL_RE_CHAR, s => '\\' + s));
|
||||
} else {
|
||||
results.push('(' + piece.source + ')');
|
||||
}
|
||||
}
|
||||
return new RegExp(results.join(''));
|
||||
}
|
||||
|
||||
function compile(
|
||||
data: MockDirectory, angularFiles: MockData, options: AotCompilerOptions = {},
|
||||
errorCollector: (error: any, fileName?: string) => void = error => { throw error; }) {
|
||||
const testFiles = toMockFileArray(data);
|
||||
const scripts = testFiles.map(entry => entry.fileName);
|
||||
const angularFilesArray = toMockFileArray(angularFiles);
|
||||
const files = arrayToMockDir([...testFiles, ...angularFilesArray]);
|
||||
const mockCompilerHost = new MockCompilerHost(scripts, files);
|
||||
const compilerHost = new MockAotCompilerHost(mockCompilerHost);
|
||||
|
||||
const program = ts.createProgram(scripts, {...settings}, mockCompilerHost);
|
||||
|
||||
// TODO(chuckj): Replace with a variant of createAotCompiler() when the r3_view_compiler is
|
||||
// integrated
|
||||
const translations = options.translations || '';
|
||||
|
||||
const urlResolver = createAotUrlResolver(compilerHost);
|
||||
const symbolCache = new StaticSymbolCache();
|
||||
const summaryResolver = new AotSummaryResolver(compilerHost, symbolCache);
|
||||
const symbolResolver = new StaticSymbolResolver(compilerHost, symbolCache, summaryResolver);
|
||||
const staticReflector =
|
||||
new StaticReflector(summaryResolver, symbolResolver, [], [], errorCollector);
|
||||
const htmlParser = new I18NHtmlParser(
|
||||
new HtmlParser(), translations, options.i18nFormat, options.missingTranslation, console);
|
||||
const config = new CompilerConfig({
|
||||
defaultEncapsulation: ViewEncapsulation.Emulated,
|
||||
useJit: false,
|
||||
enableLegacyTemplate: options.enableLegacyTemplate === true,
|
||||
missingTranslation: options.missingTranslation,
|
||||
preserveWhitespaces: options.preserveWhitespaces,
|
||||
strictInjectionParameters: options.strictInjectionParameters,
|
||||
});
|
||||
const normalizer = new DirectiveNormalizer(
|
||||
{get: (url: string) => compilerHost.loadResource(url)}, urlResolver, htmlParser, config);
|
||||
const expressionParser = new Parser(new Lexer());
|
||||
const elementSchemaRegistry = new DomElementSchemaRegistry();
|
||||
const templateParser = new TemplateParser(
|
||||
config, staticReflector, expressionParser, elementSchemaRegistry, htmlParser, console, []);
|
||||
const resolver = new CompileMetadataResolver(
|
||||
config, htmlParser, new NgModuleResolver(staticReflector),
|
||||
new DirectiveResolver(staticReflector), new PipeResolver(staticReflector), summaryResolver,
|
||||
elementSchemaRegistry, normalizer, console, symbolCache, staticReflector, errorCollector);
|
||||
|
||||
|
||||
|
||||
// Create the TypeScript program
|
||||
const sourceFiles = program.getSourceFiles().map(sf => sf.fileName);
|
||||
|
||||
// Analyze the modules
|
||||
// TODO(chuckj): Eventually this should not be necessary as the ts.SourceFile should be sufficient
|
||||
// to generate a template definition.
|
||||
const analyzedModules = analyzeNgModules(sourceFiles, compilerHost, symbolResolver, resolver);
|
||||
|
||||
const directives = Array.from(analyzedModules.ngModuleByPipeOrDirective.keys());
|
||||
|
||||
const fakeOutputContext: OutputContext = {
|
||||
genFilePath: 'fakeFactory.ts',
|
||||
statements: [],
|
||||
importExpr(symbol: StaticSymbol, typeParams: o.Type[]) {
|
||||
if (!(symbol instanceof StaticSymbol)) {
|
||||
if (!symbol) {
|
||||
throw new Error('Invalid: undefined passed to as a symbol');
|
||||
}
|
||||
throw new Error(`Invalid: ${(symbol as any).constructor.name} is not a symbol`);
|
||||
}
|
||||
return (symbol.members || [])
|
||||
.reduce(
|
||||
(expr, member) => expr.prop(member),
|
||||
<o.Expression>o.importExpr(new o.ExternalReference(symbol.filePath, symbol.name)));
|
||||
},
|
||||
constantPool: new ConstantPool()
|
||||
};
|
||||
|
||||
// Load All directives
|
||||
for (const directive of directives) {
|
||||
const module = analyzedModules.ngModuleByPipeOrDirective.get(directive) !;
|
||||
resolver.loadNgModuleDirectiveAndPipeMetadata(module.type.reference, true);
|
||||
}
|
||||
|
||||
// Compile the directives.
|
||||
for (const directive of directives) {
|
||||
const module = analyzedModules.ngModuleByPipeOrDirective.get(directive);
|
||||
if (!module || !module.type.reference.filePath.startsWith('/app')) {
|
||||
continue;
|
||||
}
|
||||
if (resolver.isDirective(directive)) {
|
||||
const metadata = resolver.getDirectiveMetadata(directive);
|
||||
if (metadata.isComponent) {
|
||||
const fakeUrl = 'ng://fake-template-url.html';
|
||||
const htmlAst = htmlParser.parse(metadata.template !.template !, fakeUrl);
|
||||
|
||||
const directives = module.transitiveModule.directives.map(
|
||||
dir => resolver.getDirectiveSummary(dir.reference));
|
||||
const pipes =
|
||||
module.transitiveModule.pipes.map(pipe => resolver.getPipeSummary(pipe.reference));
|
||||
const parsedTemplate = templateParser.parse(
|
||||
metadata, htmlAst, directives, pipes, module.schemas, fakeUrl, false);
|
||||
|
||||
compileComponent(fakeOutputContext, metadata, parsedTemplate.template, staticReflector);
|
||||
} else {
|
||||
compileDirective(fakeOutputContext, metadata, staticReflector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fakeOutputContext.statements.unshift(...fakeOutputContext.constantPool.statements);
|
||||
|
||||
const emitter = new TypeScriptEmitter();
|
||||
|
||||
const moduleName = compilerHost.fileNameToModuleName(
|
||||
fakeOutputContext.genFilePath, fakeOutputContext.genFilePath);
|
||||
|
||||
const result = emitter.emitStatementsAndContext(
|
||||
fakeOutputContext.genFilePath, fakeOutputContext.statements, '', false,
|
||||
/* referenceFilter */ undefined,
|
||||
/* importFilter */ e => e.moduleName != null && e.moduleName.startsWith('/app'));
|
||||
|
||||
return {source: result.sourceText, outputContext: fakeOutputContext};
|
||||
}
|
@ -407,7 +407,7 @@ class ArrayConsole implements Console {
|
||||
expectVisitedNode(
|
||||
new class extends
|
||||
NullVisitor{visitReference(ast: ReferenceAst, context: any): any{return ast;}},
|
||||
new ReferenceAst('foo', null !, null !, null !));
|
||||
new ReferenceAst('foo', null !, null !));
|
||||
});
|
||||
|
||||
it('should visit VariableAst', () => {
|
||||
@ -474,7 +474,7 @@ class ArrayConsole implements Console {
|
||||
new NgContentAst(0, 0, null !),
|
||||
new EmbeddedTemplateAst([], [], [], [], [], [], false, [], [], 0, null !),
|
||||
new ElementAst('foo', [], [], [], [], [], [], false, [], [], 0, null !, null !),
|
||||
new ReferenceAst('foo', null !, 'bar', null !), new VariableAst('foo', 'bar', null !),
|
||||
new ReferenceAst('foo', null !, null !), new VariableAst('foo', 'bar', null !),
|
||||
new BoundEventAst('foo', 'bar', 'goo', null !, null !),
|
||||
new BoundElementPropertyAst('foo', null !, null !, null !, 'bar', null !),
|
||||
new AttrAst('foo', 'bar', null !), new BoundTextAst(null !, 0, null !),
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user