Compare commits
108 Commits
2.0.0-beta
...
2.0.0-beta
Author | SHA1 | Date | |
---|---|---|---|
969b55326c | |||
2c8371654a | |||
5a897cf299 | |||
ef67a0c57f | |||
ef6163e652 | |||
f6985671dd | |||
90a1f7d5c4 | |||
3e114227f8 | |||
6103aa0a46 | |||
b7c6feff28 | |||
b48d907697 | |||
676ddfa065 | |||
c8d00dc191 | |||
0b6865d6c6 | |||
67d05eb65f | |||
152a117d5c | |||
d6626309fd | |||
c3daccd83b | |||
8db62151d2 | |||
bab81a9831 | |||
cc86fee1d1 | |||
386cc5dbb6 | |||
2f7045720a | |||
9889c21aaa | |||
e69cb40de3 | |||
12837e1c17 | |||
9092ac79d4 | |||
0a7d10ba55 | |||
efbd446d18 | |||
c06b0a2371 | |||
0c600cf6e3 | |||
41404057cf | |||
f4e6994634 | |||
b602bd8c83 | |||
30c43521d3 | |||
45f5df371d | |||
43e31c5abb | |||
13c8b13343 | |||
0fc9ec248e | |||
d094a85647 | |||
22c05b0834 | |||
8490921fb3 | |||
ecb9bb96f0 | |||
75463cd8df | |||
c6244d1470 | |||
22ae2d0976 | |||
88b0a239c4 | |||
7c9717bba8 | |||
7f297666ca | |||
d99823e2fd | |||
bb9fb21fac | |||
b64672b23c | |||
930f58718b | |||
2b34c88b69 | |||
45f09ba686 | |||
bb62905bef | |||
7bc9b19418 | |||
e9f7a00910 | |||
a5d6b6db8b | |||
fc496813e2 | |||
2abb414cfb | |||
0e56aaf189 | |||
3412aba46e | |||
347e71af7d | |||
d24df799d3 | |||
01e6b8c7ed | |||
60727c4d2b | |||
03627aa84d | |||
83b8f59297 | |||
c6f454f51d | |||
ccff17599a | |||
fb2773b8f3 | |||
5110121f6e | |||
27cf897239 | |||
5d33a12af4 | |||
08b295603c | |||
3b60503d2b | |||
3c2473bac6 | |||
f9426709ef | |||
e1e44a910e | |||
f371c9066d | |||
85c1927993 | |||
a596b887ff | |||
6cbf99086e | |||
26a3390549 | |||
9a1959f77a | |||
226e662cf1 | |||
7a1a1b80ed | |||
529988bc81 | |||
c17dc1c057 | |||
09a95a692e | |||
247964af62 | |||
5e2bc5c593 | |||
28e657d857 | |||
06ad112998 | |||
cfa1d17afe | |||
3ca6df87b8 | |||
e310bee9e2 | |||
4902244cce | |||
8db97b0b7a | |||
9be04f8d38 | |||
74e2bd7e3e | |||
52d3980d02 | |||
4e9809bcb2 | |||
bd8a4215dd | |||
d23b973e7a | |||
0dbf959548 | |||
20812f446f |
@ -58,14 +58,11 @@ env:
|
||||
- MODE=build_only
|
||||
- MODE=typescript_next
|
||||
- MODE=lint
|
||||
- MODE=payload
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- env: "MODE=saucelabs_optional"
|
||||
- env: "MODE=browserstack_optional"
|
||||
# Tracked in https://github.com/angular/angular/issues/7050
|
||||
- env: "MODE=typescript_next"
|
||||
|
||||
addons:
|
||||
firefox: "38.0"
|
||||
|
144
CHANGELOG.md
144
CHANGELOG.md
@ -1,3 +1,136 @@
|
||||
<a name="2.0.0-beta.16"></a>
|
||||
# 2.0.0-beta.16 (2016-04-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular_1_router:** Removed arrow function from module template ([d094a85](https://github.com/angular/angular/commit/d094a85)), closes [#8076](https://github.com/angular/angular/issues/8076)
|
||||
* **build:** ignore Dart warnings for external code. ([4140405](https://github.com/angular/angular/commit/4140405))
|
||||
* **codegen:** add explicit any to class fields ([c8d00dc](https://github.com/angular/angular/commit/c8d00dc)), closes [#8204](https://github.com/angular/angular/issues/8204) [#8205](https://github.com/angular/angular/issues/8205)
|
||||
* **compiler:** only call pure pipes if their input changed. ([8db6215](https://github.com/angular/angular/commit/8db6215))
|
||||
* **compiler:** properly implement pure pipes and change pipe syntax ([152a117](https://github.com/angular/angular/commit/152a117))
|
||||
* **compiler:** support string tokens with `.` inside. ([cc86fee](https://github.com/angular/angular/commit/cc86fee))
|
||||
* **compiler:** use DI order for change detection order. ([67d05eb](https://github.com/angular/angular/commit/67d05eb)), closes [#8198](https://github.com/angular/angular/issues/8198)
|
||||
* **core:** various minor compiler fixes ([2f70457](https://github.com/angular/angular/commit/2f70457)), closes [#8162](https://github.com/angular/angular/issues/8162)
|
||||
* **forms:** ensure select model updates in firefox and ie ([c3daccd](https://github.com/angular/angular/commit/c3daccd)), closes [#6573](https://github.com/angular/angular/issues/6573) [#8148](https://github.com/angular/angular/issues/8148)
|
||||
* **forms:** improve error message when ngFormModel is missing a form ([12837e1](https://github.com/angular/angular/commit/12837e1)), closes [#8136](https://github.com/angular/angular/issues/8136) [#8143](https://github.com/angular/angular/issues/8143)
|
||||
* **forms:** number input should report null when blank ([e69cb40](https://github.com/angular/angular/commit/e69cb40)), closes [#6932](https://github.com/angular/angular/issues/6932) [#8141](https://github.com/angular/angular/issues/8141)
|
||||
* **metadata:** emit metadata rooted at 'angular2' ([9889c21](https://github.com/angular/angular/commit/9889c21)), closes [#8144](https://github.com/angular/angular/issues/8144) [#8147](https://github.com/angular/angular/issues/8147)
|
||||
* **release:** Fix the package.json zone.js requirement to 0.6.12 ([6103aa0](https://github.com/angular/angular/commit/6103aa0))
|
||||
* **tests:** remove payload size check ([22c05b0](https://github.com/angular/angular/commit/22c05b0))
|
||||
* **transformers:** support `query.read` ([386cc5d](https://github.com/angular/angular/commit/386cc5d)), closes [#8172](https://github.com/angular/angular/issues/8172)
|
||||
* **upgrade:** clean up scope when element is destroyed ([0fc9ec2](https://github.com/angular/angular/commit/0fc9ec2)), closes [#8102](https://github.com/angular/angular/issues/8102)
|
||||
|
||||
### Features
|
||||
|
||||
* **html_lexer:** support special forms used by i18n { exp, plural, =0 {} } ([7f29766](https://github.com/angular/angular/commit/7f29766))
|
||||
* **html_parser:** support special forms used by i18n { exp, plural, =0 {} } ([7c9717b](https://github.com/angular/angular/commit/7c9717b))
|
||||
* **i18n:** add custom placeholder names ([bb9fb21](https://github.com/angular/angular/commit/bb9fb21)), closes [#7799](https://github.com/angular/angular/issues/7799) [#8057](https://github.com/angular/angular/issues/8057)
|
||||
* **i18n:** add support for nested expansion forms ([c6244d1](https://github.com/angular/angular/commit/c6244d1)), closes [#7977](https://github.com/angular/angular/issues/7977)
|
||||
* **i18n:** support plural and gender special forms ([88b0a23](https://github.com/angular/angular/commit/88b0a23))
|
||||
* **NgTemplateOutlet:** add NgTemplateOutlet directive ([f4e6994](https://github.com/angular/angular/commit/f4e6994)), closes [#7615](https://github.com/angular/angular/issues/7615) [#8021](https://github.com/angular/angular/issues/8021)
|
||||
* **router:** add Router and RouterOutlet ([5a897cf](https://github.com/angular/angular/commit/5a897cf)), closes [#8173](https://github.com/angular/angular/issues/8173)
|
||||
* **router:** add router metadata ([ef67a0c](https://github.com/angular/angular/commit/ef67a0c))
|
||||
* **router:** add UrlSegment, RouteSegment, and Tree ([90a1f7d](https://github.com/angular/angular/commit/90a1f7d))
|
||||
* **router:** implement recognizer ([ef6163e](https://github.com/angular/angular/commit/ef6163e))
|
||||
* **router:** implement RouterUrlParser ([f698567](https://github.com/angular/angular/commit/f698567))
|
||||
* **test:** Implement fakeAsync using the FakeAsyncTestZoneSpec from zone.js. ([bab81a9](https://github.com/angular/angular/commit/bab81a9)), closes [#8142](https://github.com/angular/angular/issues/8142)
|
||||
* **tests:** manage asynchronous tests using zones ([8490921](https://github.com/angular/angular/commit/8490921)), closes [#7735](https://github.com/angular/angular/issues/7735)
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* `injectAsync` is now deprecated. Instead, use the `async` function
|
||||
to wrap any asynchronous tests.
|
||||
Before:
|
||||
```
|
||||
it('should wait for returned promises', injectAsync([FancyService], (service) => {
|
||||
return service.getAsyncValue().then((value) => { expect(value).toEqual('async value'); });
|
||||
}));
|
||||
it('should wait for returned promises', injectAsync([], () => {
|
||||
return somePromise.then(() => { expect(true).toEqual(true); });
|
||||
}));
|
||||
```
|
||||
After:
|
||||
```
|
||||
it('should wait for returned promises', async(inject([FancyService], (service) => {
|
||||
service.getAsyncValue().then((value) => { expect(value).toEqual('async value'); });
|
||||
})));
|
||||
// Note that if there is no injection, we no longer need `inject` OR `injectAsync`.
|
||||
it('should wait for returned promises', async(() => {
|
||||
somePromise.then() => { expect(true).toEqual(true); });
|
||||
}));
|
||||
```
|
||||
|
||||
* inject can no longer wrap fakeAsync while fakeAsync can wrap inject. So the order in existing tests with inject and fakeAsync has to be switched as follows:
|
||||
Before:
|
||||
```
|
||||
inject([...], fakeAsync((...) => {...}))
|
||||
```
|
||||
After:
|
||||
```
|
||||
fakeAsync(inject([...], (...) => {...}))
|
||||
```
|
||||
|
||||
* - pipes now take a variable number of arguments, and not an array that contains all arguments.
|
||||
|
||||
|
||||
<a name="2.0.0-beta.15"></a>
|
||||
# 2.0.0-beta.15 (2016-04-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **7837:** MetadataCollector takes no parameters for the constructor. ([c17dc1c](https://github.com/angular/angular/commit/c17dc1c)), closes [#7838](https://github.com/angular/angular/issues/7838)
|
||||
* **7987:** Incremental build works with new trees ([08b2956](https://github.com/angular/angular/commit/08b2956)), closes [#7989](https://github.com/angular/angular/issues/7989)
|
||||
* **build:** ignore dart warnings `The name … is shown, but not used` ([01e6b8c](https://github.com/angular/angular/commit/01e6b8c)), closes [#8045](https://github.com/angular/angular/issues/8045)
|
||||
* **payload:** increase payload size limit temporarily ([28e657d](https://github.com/angular/angular/commit/28e657d))
|
||||
* **RouterLink:** ignore optional parameters when checking for active routes ([5e2bc5c](https://github.com/angular/angular/commit/5e2bc5c)), closes [#6459](https://github.com/angular/angular/issues/6459) [#7834](https://github.com/angular/angular/issues/7834)
|
||||
* **select:** set value individually from ngModel ([e1e44a9](https://github.com/angular/angular/commit/e1e44a9)), closes [#7975](https://github.com/angular/angular/issues/7975) [#7978](https://github.com/angular/angular/issues/7978)
|
||||
* **upgrade:** make upgradeAdapter upgrade angular 1 components correctly ([247964a](https://github.com/angular/angular/commit/247964a)), closes [#7951](https://github.com/angular/angular/issues/7951)
|
||||
|
||||
### Features
|
||||
|
||||
* **compiler:** Add an implementation for XHR that uses a template cache to load template files. ([a596b88](https://github.com/angular/angular/commit/a596b88)), closes [#7940](https://github.com/angular/angular/issues/7940)
|
||||
* **gestures:** allow override of Hammer default configuration ([6cbf990](https://github.com/angular/angular/commit/6cbf990)), closes [#7924](https://github.com/angular/angular/issues/7924)
|
||||
* **ngFor:** Support convenience view local in ngFor ([ccff175](https://github.com/angular/angular/commit/ccff175)), closes [#8013](https://github.com/angular/angular/issues/8013)
|
||||
* **parser:** TemplateParser.tryParse() returns both the AST and errors ([226e662](https://github.com/angular/angular/commit/226e662)), closes [#7858](https://github.com/angular/angular/issues/7858)
|
||||
* **transformers:** changes transformers to collect information about providers and resolve identifi ([3b60503](https://github.com/angular/angular/commit/3b60503))
|
||||
* **transformers:** special case Profiler ([83b8f59](https://github.com/angular/angular/commit/83b8f59))
|
||||
* **typescript:** update to 1.9 nightly. ([3412aba](https://github.com/angular/angular/commit/3412aba)), closes [#8003](https://github.com/angular/angular/issues/8003)
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* In Dart files, `import 'package:angular2/bootstrap.dart'` no longer works.
|
||||
Instead, use `import 'package:angular2/platform/browser.dart'`.
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "chore(format): update to latest formatter" ([60727c4](https://github.com/angular/angular/commit/60727c4))
|
||||
|
||||
|
||||
|
||||
<a name="2.0.0-beta.14"></a>
|
||||
# 2.0.0-beta.14 (2016-04-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **forms:** support both value and ng-value ([8db97b0](https://github.com/angular/angular/commit/8db97b0))
|
||||
* **router:** allow forward slashes in query parameters ([4902244](https://github.com/angular/angular/commit/4902244)), closes [#7824](https://github.com/angular/angular/issues/7824)
|
||||
* **select:** support objects as select values ([74e2bd7](https://github.com/angular/angular/commit/74e2bd7)), closes [#4843](https://github.com/angular/angular/issues/4843) [#7842](https://github.com/angular/angular/issues/7842)
|
||||
* **select:** update name from ng-value to ngValue ([3ca6df8](https://github.com/angular/angular/commit/3ca6df8)), closes [#7939](https://github.com/angular/angular/issues/7939)
|
||||
* **upgrade:** leak when angular1 destroys element ([9be04f8](https://github.com/angular/angular/commit/9be04f8)), closes [#6401](https://github.com/angular/angular/issues/6401) [#7935](https://github.com/angular/angular/issues/7935)
|
||||
|
||||
### Features
|
||||
|
||||
* **dart/transform:** Avoid `print` in transformer code. ([e310bee](https://github.com/angular/angular/commit/e310bee)), closes [#7855](https://github.com/angular/angular/issues/7855)
|
||||
* **static-reflector:** Added StaticReflector ([0dbf959](https://github.com/angular/angular/commit/0dbf959))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="2.0.0-beta.13"></a>
|
||||
# 2.0.0-beta.13 (2016-03-31)
|
||||
|
||||
@ -30,14 +163,20 @@
|
||||
### BREAKING CHANGES
|
||||
|
||||
* For static content projection, elements with *-directives are now matched against the element itself vs the template before.
|
||||
<p *ngIf="condition" foo></p>
|
||||
|
||||
`<p *ngIf="condition" foo></p>`
|
||||
|
||||
Before:
|
||||
```html
|
||||
// Use the implicit template for projection
|
||||
<ng-content select="template"></ng-content>
|
||||
```
|
||||
|
||||
After:
|
||||
```html
|
||||
// Use the actual element for projection
|
||||
<ng-content select="p[foo]"></ng-content>
|
||||
|
||||
```
|
||||
|
||||
<a name="2.0.0-beta.12"></a>
|
||||
# 2.0.0-beta.12 (2016-03-23)
|
||||
@ -2473,3 +2612,4 @@ After
|
||||
})
|
||||
|
||||
* no longer cache ref
|
||||
|
||||
|
82
gulpfile.js
82
gulpfile.js
@ -177,8 +177,8 @@ var PAYLOAD_TESTS_CONFIG = {
|
||||
return path.join(__dirname, CONFIG.dest.js.prod.es5, 'payload_tests', caseName,
|
||||
'ts/' + packaging);
|
||||
},
|
||||
systemjs: {sizeLimits: {'uncompressed': 850 * 1024, 'gzip level=9': 165 * 1024}},
|
||||
webpack: {sizeLimits: {'uncompressed': 550 * 1024, 'gzip level=9': 120 * 1024}}
|
||||
systemjs: {sizeLimits: {'uncompressed': 880 * 1024, 'gzip level=9': 170 * 1024}},
|
||||
webpack: {sizeLimits: {'uncompressed': 560 * 1024, 'gzip level=9': 130 * 1024}}
|
||||
}
|
||||
};
|
||||
|
||||
@ -640,7 +640,7 @@ gulp.task('buildRouter.dev', function() {
|
||||
gulp.task('test.unit.dart', function(done) {
|
||||
printModulesWarning();
|
||||
runSequence('build/tree.dart', 'build/pure-packages.dart', '!build/pubget.angular2.dart',
|
||||
'!build/change_detect.dart', '!build/remove-pub-symlinks', function(error) {
|
||||
'!build/remove-pub-symlinks', function(error) {
|
||||
var watch = require('./tools/build/watch');
|
||||
|
||||
// if initial build failed (likely due to build or formatting step) then exit
|
||||
@ -779,7 +779,7 @@ gulp.task('!checkAndReport.payload.js', function() {
|
||||
|
||||
gulp.task('watch.dart.dev', function(done) {
|
||||
runSequence('build/tree.dart', 'build/pure-packages.dart', '!build/pubget.angular2.dart',
|
||||
'!build/change_detect.dart', '!build/remove-pub-symlinks', function(error) {
|
||||
'!build/remove-pub-symlinks', function(error) {
|
||||
var watch = require('./tools/build/watch');
|
||||
|
||||
// if initial build failed (likely due to build or formatting step) then exit
|
||||
@ -789,7 +789,8 @@ gulp.task('watch.dart.dev', function(done) {
|
||||
return;
|
||||
}
|
||||
|
||||
watch(['modules/angular2/**'], {ignoreInitial: true}, ['!build/tree.dart']);
|
||||
watch(['modules/angular2/**', 'modules_dart/**'], {ignoreInitial: true},
|
||||
['!build/tree.dart', 'build/pure-packages.dart']);
|
||||
});
|
||||
});
|
||||
|
||||
@ -911,21 +912,20 @@ gulp.task('test.unit.cjs', ['build/clean.js', 'build.tools'], function(neverDone
|
||||
gulp.task('test.unit.dartvm', function(neverDone) {
|
||||
var watch = require('./tools/build/watch');
|
||||
|
||||
runSequence(
|
||||
'build/tree.dart', 'build/pure-packages.dart', '!build/pubget.angular2.dart',
|
||||
'!build/change_detect.dart', '!test.unit.dartvm/run', function(error) {
|
||||
// Watch for changes made in the TS and Dart code under "modules" and
|
||||
// run ts2dart and test change detector generator prior to rerunning the
|
||||
// tests.
|
||||
watch('modules/angular2/**', {ignoreInitial: true},
|
||||
['!build/tree.dart', '!build/change_detect.dart', '!test.unit.dartvm/run']);
|
||||
runSequence('build/tree.dart', 'build/pure-packages.dart', '!build/pubget.angular2.dart',
|
||||
'!test.unit.dartvm/run', function(error) {
|
||||
// Watch for changes made in the TS and Dart code under "modules" and
|
||||
// run ts2dart and test change detector generator prior to rerunning the
|
||||
// tests.
|
||||
watch('modules/angular2/**', {ignoreInitial: true},
|
||||
['!build/tree.dart', '!test.unit.dartvm/run']);
|
||||
|
||||
// Watch for changes made in Dart code under "modules_dart", then copy it
|
||||
// to dist and run test change detector generator prior to retunning the
|
||||
// tests.
|
||||
watch('modules_dart/**', {ignoreInitial: true},
|
||||
['build/pure-packages.dart', '!build/change_detect.dart', '!test.unit.dartvm/run']);
|
||||
});
|
||||
// Watch for changes made in Dart code under "modules_dart", then copy it
|
||||
// to dist and run test change detector generator prior to retunning the
|
||||
// tests.
|
||||
watch('modules_dart/**', {ignoreInitial: true},
|
||||
['build/pure-packages.dart', '!test.unit.dartvm/run']);
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('!test.unit.dartvm/run',
|
||||
@ -981,9 +981,9 @@ gulp.task('static-checks', ['!build.tools'], function(done) {
|
||||
// distributed in our npm package, and loaded from node_modules by
|
||||
// the typescript compiler.
|
||||
|
||||
// Make sure the two typings tests are isolated, by running this one in a tempdir
|
||||
// Make sure the typings tests are isolated, by running in a tempdir
|
||||
var tmpdir = path.join(os.tmpdir(), 'test.typings', new Date().getTime().toString());
|
||||
gulp.task('!pre.test.typings.layoutNodeModule', ['build.js.cjs'], function() {
|
||||
gulp.task('!pre.test.typings.layoutNodeModule', function() {
|
||||
return gulp.src(['dist/js/cjs/angular2/**/*', 'node_modules/rxjs/**/*'], {base: 'dist/js/cjs'})
|
||||
.pipe(gulp.dest(path.join(tmpdir, 'node_modules')));
|
||||
});
|
||||
@ -1003,7 +1003,7 @@ gulp.task('!pre.test.typings.copyTypingsSpec', function() {
|
||||
return gulp.src(['modules/angular2/examples/**/*.ts']).pipe(gulp.dest(tmpdir));
|
||||
});
|
||||
|
||||
gulp.task('test.typings',
|
||||
gulp.task('!test.typings',
|
||||
[
|
||||
'!pre.test.typings.layoutNodeModule',
|
||||
'!pre.test.typings.copyTypingsSpec',
|
||||
@ -1023,6 +1023,9 @@ gulp.task('test.typings',
|
||||
}));
|
||||
});
|
||||
|
||||
gulp.task('test.typings', ['build.js.cjs'],
|
||||
function(done) { runSequence('!test.typings', sequenceComplete(done)); });
|
||||
|
||||
// -----------------
|
||||
// orchestrated targets
|
||||
|
||||
@ -1066,9 +1069,9 @@ gulp.task('build/pure-packages.dart/angular2', function() {
|
||||
|
||||
// Builds all Dart packages, but does not compile them
|
||||
gulp.task('build/packages.dart', function(done) {
|
||||
runSequence('lint_protos.dart', 'build/tree.dart', 'build/pure-packages.dart',
|
||||
runSequence('lint_protos.dart', 'pubget.dart', 'build/tree.dart', 'build/pure-packages.dart',
|
||||
// Run after 'build/tree.dart' because broccoli clears the dist/dart folder
|
||||
'!build/pubget.angular2.dart', '!build/change_detect.dart', sequenceComplete(done));
|
||||
'!build/pubget.angular2.dart', sequenceComplete(done));
|
||||
});
|
||||
|
||||
// Builds and compiles all Dart packages
|
||||
@ -1203,7 +1206,8 @@ gulp.task('!bundle.js.prod', ['build.js.prod'], function() {
|
||||
// minified production build
|
||||
gulp.task('!bundle.js.min', ['build.js.prod'], function() {
|
||||
var bundler = require('./tools/build/bundle');
|
||||
var bundlerConfig = {sourceMaps: true, minify: true};
|
||||
var bundlerConfig =
|
||||
{sourceMaps: true, minify: true, mangle: false, uglify: {compress: {keep_fnames: true}}};
|
||||
|
||||
return bundler.bundle(bundleConfig, NG2_BUNDLE_CONTENT, './dist/build/angular2.min.js',
|
||||
bundlerConfig)
|
||||
@ -1463,34 +1467,6 @@ gulp.task('gen_protos.dart', function(done) {
|
||||
done);
|
||||
});
|
||||
|
||||
// change detection codegen
|
||||
gulp.task('build.change_detect.dart', function(done) {
|
||||
return runSequence('build/packages.dart', '!build/pubget.angular2.dart',
|
||||
'!build/change_detect.dart', done);
|
||||
});
|
||||
|
||||
gulp.task('!build/change_detect.dart', function(done) {
|
||||
var fs = require('fs');
|
||||
var spawn = require('child_process').spawn;
|
||||
|
||||
var changeDetectDir = path.join(CONFIG.dest.dart, 'angular2/test/core/change_detection/');
|
||||
var srcDir = path.join(changeDetectDir, 'generator');
|
||||
var destDir = path.join(changeDetectDir, 'generated');
|
||||
|
||||
var dartStream = fs.createWriteStream(path.join(destDir, 'change_detector_classes.dart'));
|
||||
var genMain = path.join(srcDir, 'gen_change_detectors.dart');
|
||||
var proc = spawn(DART_SDK.VM, [genMain], {stdio: ['ignore', 'pipe', 'inherit']});
|
||||
proc.on('error', function(code) {
|
||||
done(new Error('Failed while generating change detector classes. Please run manually: ' +
|
||||
DART_SDK.VM + ' ' + dartArgs.join(' ')));
|
||||
});
|
||||
proc.on('close', function() {
|
||||
dartStream.close();
|
||||
done();
|
||||
});
|
||||
proc.stdout.pipe(dartStream);
|
||||
});
|
||||
|
||||
// ------------
|
||||
|
||||
gulp.task('cleanup.builder', function() { return angularBuilder.cleanup(); });
|
||||
|
@ -20,6 +20,8 @@ module.exports = function(config) {
|
||||
'node_modules/zone.js/dist/zone.js',
|
||||
'node_modules/zone.js/dist/long-stack-trace-zone.js',
|
||||
'node_modules/zone.js/dist/jasmine-patch.js',
|
||||
'node_modules/zone.js/dist/async-test.js',
|
||||
'node_modules/zone.js/dist/fake-async-test.js',
|
||||
|
||||
// Including systemjs because it defines `__eval`, which produces correct stack traces.
|
||||
'modules/angular2/src/testing/shims_for_IE.js',
|
||||
|
@ -96,7 +96,7 @@ function routerFactory($q, $location, $browser, $rootScope, $injector, $routerRo
|
||||
controller.$routeConfig.forEach(function (config) {
|
||||
var loader = config.loader;
|
||||
if (isPresent(loader)) {
|
||||
config = angular.extend({}, config, { loader: () => $injector.invoke(loader) });
|
||||
config = angular.extend({}, config, { loader: function() { return $injector.invoke(loader); } });
|
||||
}
|
||||
that.config(component, config);
|
||||
});
|
||||
|
17
modules/angular2/alt_router.ts
Normal file
17
modules/angular2/alt_router.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @module
|
||||
* @description
|
||||
* Alternative implementation of the router. Experimental.
|
||||
*/
|
||||
|
||||
export {Router, RouterOutletMap} from './src/alt_router/router';
|
||||
export {RouteSegment} from './src/alt_router/segments';
|
||||
export {Routes} from './src/alt_router/metadata/decorators';
|
||||
export {Route} from './src/alt_router/metadata/metadata';
|
||||
export {RouterUrlParser, DefaultRouterUrlParser} from './src/alt_router/router_url_parser';
|
||||
export {OnActivate} from './src/alt_router/interfaces';
|
||||
|
||||
import {RouterOutlet} from './src/alt_router/directives/router_outlet';
|
||||
import {CONST_EXPR} from './src/facade/lang';
|
||||
|
||||
export const ROUTER_DIRECTIVES: any[] = CONST_EXPR([RouterOutlet]);
|
@ -10,8 +10,9 @@ export 'package:angular2/common.dart';
|
||||
export 'package:angular2/instrumentation.dart';
|
||||
export 'package:angular2/src/core/angular_entrypoint.dart' show AngularEntrypoint;
|
||||
export 'package:angular2/src/core/application_tokens.dart'
|
||||
hide APP_COMPONENT_REF_PROMISE, APP_ID_RANDOM_PROVIDER;
|
||||
hide APP_ID_RANDOM_PROVIDER;
|
||||
export 'package:angular2/src/platform/dom/dom_tokens.dart';
|
||||
export 'package:angular2/src/platform/dom/dom_adapter.dart';
|
||||
export 'package:angular2/src/platform/dom/events/event_manager.dart';
|
||||
export 'package:angular2/src/compiler/url_resolver.dart';
|
||||
export 'package:angular2/src/compiler/compiler.dart' show UrlResolver, DirectiveResolver, ViewResolver;
|
||||
|
||||
|
@ -1,6 +0,0 @@
|
||||
/**
|
||||
* See {@link bootstrap} for more information.
|
||||
* @deprecated
|
||||
*/
|
||||
export {bootstrap} from 'angular2/platform/browser';
|
||||
export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
|
@ -1,6 +0,0 @@
|
||||
/**
|
||||
* See {@link bootstrap} for more information.
|
||||
* @deprecated
|
||||
*/
|
||||
export {bootstrapStatic} from 'angular2/platform/browser_static';
|
||||
export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
|
@ -1,4 +1,4 @@
|
||||
export * from './src/common/pipes';
|
||||
export * from './src/common/directives';
|
||||
export * from './src/common/forms';
|
||||
export * from './src/common/common_directives';
|
||||
export * from './src/common/common_directives';
|
||||
|
@ -3,6 +3,35 @@
|
||||
* @description
|
||||
* Starting point to import all compiler APIs.
|
||||
*/
|
||||
export * from './src/compiler/url_resolver';
|
||||
export * from './src/compiler/xhr';
|
||||
export * from './src/compiler/compiler';
|
||||
export {
|
||||
PLATFORM_DIRECTIVES,
|
||||
PLATFORM_PIPES,
|
||||
COMPILER_PROVIDERS,
|
||||
TEMPLATE_TRANSFORMS,
|
||||
CompilerConfig,
|
||||
RenderTypes,
|
||||
UrlResolver,
|
||||
DEFAULT_PACKAGE_URL_PROVIDER,
|
||||
createOfflineCompileUrlResolver,
|
||||
XHR,
|
||||
ViewResolver,
|
||||
DirectiveResolver,
|
||||
PipeResolver,
|
||||
SourceModule,
|
||||
NormalizedComponentWithViewDirectives,
|
||||
OfflineCompiler,
|
||||
CompileMetadataWithIdentifier,
|
||||
CompileMetadataWithType,
|
||||
CompileIdentifierMetadata,
|
||||
CompileDiDependencyMetadata,
|
||||
CompileProviderMetadata,
|
||||
CompileFactoryMetadata,
|
||||
CompileTokenMetadata,
|
||||
CompileTypeMetadata,
|
||||
CompileQueryMetadata,
|
||||
CompileTemplateMetadata,
|
||||
CompileDirectiveMetadata,
|
||||
CompilePipeMetadata
|
||||
} from 'angular2/src/compiler/compiler';
|
||||
|
||||
export * from 'angular2/src/compiler/template_ast';
|
||||
|
@ -6,9 +6,10 @@ export './src/core/util.dart';
|
||||
export 'package:angular2/src/facade/lang.dart' show enableProdMode;
|
||||
export './src/core/di.dart' hide ForwardRefFn, resolveForwardRef, forwardRef;
|
||||
export './src/facade/facade.dart';
|
||||
export './src/core/application_ref.dart' show platform, createNgZone, PlatformRef, ApplicationRef;
|
||||
export './src/core/application_ref.dart' show createPlatform, assertPlatform,
|
||||
disposePlatform, getPlatform,
|
||||
coreLoadAndBootstrap, coreBootstrap, createNgZone, PlatformRef, ApplicationRef;
|
||||
export './src/core/application_tokens.dart' show APP_ID,
|
||||
APP_COMPONENT,
|
||||
APP_INITIALIZER,
|
||||
PACKAGE_ROOT_URL,
|
||||
PLATFORM_INITIALIZER;
|
||||
|
@ -9,10 +9,19 @@ export * from './src/core/prod_mode';
|
||||
export * from './src/core/di';
|
||||
export * from './src/facade/facade';
|
||||
export {enableProdMode} from 'angular2/src/facade/lang';
|
||||
export {platform, createNgZone, PlatformRef, ApplicationRef} from './src/core/application_ref';
|
||||
export {
|
||||
createPlatform,
|
||||
assertPlatform,
|
||||
disposePlatform,
|
||||
getPlatform,
|
||||
coreBootstrap,
|
||||
coreLoadAndBootstrap,
|
||||
createNgZone,
|
||||
PlatformRef,
|
||||
ApplicationRef
|
||||
} from './src/core/application_ref';
|
||||
export {
|
||||
APP_ID,
|
||||
APP_COMPONENT,
|
||||
APP_INITIALIZER,
|
||||
PACKAGE_ROOT_URL,
|
||||
PLATFORM_INITIALIZER
|
||||
|
@ -4,7 +4,7 @@ Class decorators
|
||||
@description
|
||||
{@target ts}`import {Directive, ...} from 'angular2/core';`{@endtarget}
|
||||
{@target js}Available from the `ng.core` namespace{@endtarget}
|
||||
{@target dart}`import 'package:angular2/angular2.dart';`{@endtarget}
|
||||
{@target dart}`import 'package:angular2/core.dart';`{@endtarget}
|
||||
|
||||
@cheatsheetItem
|
||||
syntax(ts):
|
||||
@ -18,6 +18,18 @@ class MyComponent() {}`|`@Component(...)`
|
||||
description:
|
||||
Declares that a class is a component and provides metadata about the component.
|
||||
|
||||
@cheatsheetItem
|
||||
syntax(ts):
|
||||
`@Directive({...})
|
||||
class MyDirective() {}`|`@Directive({...})`
|
||||
syntax(js):
|
||||
`var MyDirective = ng.core.Directive({...}).Class({...})`|`ng.core.Directive({...})`
|
||||
syntax(dart):
|
||||
`@Directive(...)
|
||||
class MyDirective() {}`|`@Directive(...)`
|
||||
description:
|
||||
Declares that a class is a directive and provides metadata about the directive.
|
||||
|
||||
@cheatsheetItem
|
||||
syntax(ts):
|
||||
`@Pipe({...})
|
||||
|
@ -4,7 +4,7 @@ Dependency injection configuration
|
||||
@description
|
||||
{@target ts}`import {provide} from 'angular2/core';`{@endtarget}
|
||||
{@target js}Available from the `ng.core` namespace{@endtarget}
|
||||
{@target dart}`import 'package:angular2/angular2.dart';`{@endtarget}
|
||||
{@target dart}`import 'package:angular2/core.dart';`{@endtarget}
|
||||
|
||||
@cheatsheetItem
|
||||
syntax(ts dart):
|
||||
|
@ -4,7 +4,7 @@ Class field decorators for directives and components
|
||||
@description
|
||||
{@target ts}`import {Input, ...} from 'angular2/core';`{@endtarget}
|
||||
{@target js}Available from the `ng.core` namespace{@endtarget}
|
||||
{@target dart}`import 'package:angular2/angular2.dart';`{@endtarget}
|
||||
{@target dart}`import 'package:angular2/core.dart';`{@endtarget}
|
||||
|
||||
@cheatsheetItem
|
||||
syntax(ts dart):
|
||||
|
@ -4,7 +4,7 @@ Routing and navigation
|
||||
@description
|
||||
{@target ts}`import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, ...} from 'angular2/router';`{@endtarget}
|
||||
{@target js}Available from the `ng.router` namespace{@endtarget}
|
||||
{@target dart}`import 'package:angular2/angular2.dart';`{@endtarget}
|
||||
{@target dart}`import 'package:angular2/router.dart';`{@endtarget}
|
||||
|
||||
|
||||
@cheatsheetItem
|
||||
|
@ -77,4 +77,4 @@ Transforms the current value of expression `cardNumber` via the pipe called `myC
|
||||
syntax:
|
||||
`<p>Employer: {{employer?.companyName}}</p>`|`{{employer?.companyName}}`
|
||||
description:
|
||||
The Elvis operator (`?`) means that the `employer` field is optional and if `undefined`, the rest of the expression should be ignored.
|
||||
The safe navigation operator (`?`) means that the `employer` field is optional and if `undefined`, the rest of the expression should be ignored.
|
||||
|
@ -1,4 +1,10 @@
|
||||
import {Inject, Injector, forwardRef, resolveForwardRef, ForwardRefFn} from 'angular2/core';
|
||||
import {
|
||||
Inject,
|
||||
ReflectiveInjector,
|
||||
forwardRef,
|
||||
resolveForwardRef,
|
||||
ForwardRefFn
|
||||
} from 'angular2/core';
|
||||
|
||||
// #docregion forward_ref_fn
|
||||
var ref = forwardRef(() => Lock);
|
||||
@ -13,7 +19,7 @@ class Door {
|
||||
// Only at this point Lock is defined.
|
||||
class Lock {}
|
||||
|
||||
var injector = Injector.resolveAndCreate([Door, Lock]);
|
||||
var injector = ReflectiveInjector.resolveAndCreate([Door, Lock]);
|
||||
var door = injector.get(Door);
|
||||
expect(door instanceof Door).toBe(true);
|
||||
expect(door.lock instanceof Lock).toBe(true);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {Component, platform} from 'angular2/core';
|
||||
import {Component, createPlatform, coreLoadAndBootstrap, ReflectiveInjector} from 'angular2/core';
|
||||
import {BROWSER_PROVIDERS, BROWSER_APP_PROVIDERS} from 'angular2/platform/browser';
|
||||
|
||||
var appProviders: any[] = [];
|
||||
@ -8,6 +8,8 @@ var appProviders: any[] = [];
|
||||
class MyApp {
|
||||
}
|
||||
|
||||
var app = platform(BROWSER_PROVIDERS).application([BROWSER_APP_PROVIDERS, appProviders]);
|
||||
app.bootstrap(MyApp);
|
||||
var platform = createPlatform(ReflectiveInjector.resolveAndCreate(BROWSER_PROVIDERS));
|
||||
var appInjector =
|
||||
ReflectiveInjector.resolveAndCreate([BROWSER_APP_PROVIDERS, appProviders], platform.injector);
|
||||
coreLoadAndBootstrap(appInjector, MyApp);
|
||||
// #enddocregion
|
||||
|
@ -7,4 +7,4 @@ class MyAppComponent {
|
||||
|
||||
// #docregion providers
|
||||
bootstrap(MyAppComponent, [ELEMENT_PROBE_PROVIDERS]);
|
||||
// #enddocregion
|
||||
// #enddocregion
|
||||
|
@ -1,12 +1,7 @@
|
||||
import {provide, Component} from 'angular2/core';
|
||||
import {bootstrap} from 'angular2/platform/browser';
|
||||
import {
|
||||
CanActivate,
|
||||
RouteConfig,
|
||||
ComponentInstruction,
|
||||
APP_BASE_HREF,
|
||||
ROUTER_DIRECTIVES
|
||||
} from 'angular2/router';
|
||||
import {CanActivate, RouteConfig, ComponentInstruction, ROUTER_DIRECTIVES} from 'angular2/router';
|
||||
import {APP_BASE_HREF} from 'angular2/platform/common';
|
||||
|
||||
function checkIfWeHavePermission(instruction: ComponentInstruction) {
|
||||
return instruction.params['id'] == '1';
|
||||
|
@ -5,9 +5,9 @@ import {
|
||||
RouteConfig,
|
||||
RouteParams,
|
||||
ComponentInstruction,
|
||||
ROUTER_DIRECTIVES,
|
||||
APP_BASE_HREF
|
||||
ROUTER_DIRECTIVES
|
||||
} from 'angular2/router';
|
||||
import {APP_BASE_HREF} from 'angular2/platform/common';
|
||||
|
||||
// #docregion routerCanDeactivate
|
||||
@Component({
|
||||
|
@ -1,12 +1,7 @@
|
||||
import {Component, provide} from 'angular2/core';
|
||||
import {bootstrap} from 'angular2/platform/browser';
|
||||
import {
|
||||
OnActivate,
|
||||
ComponentInstruction,
|
||||
RouteConfig,
|
||||
ROUTER_DIRECTIVES,
|
||||
APP_BASE_HREF
|
||||
} from 'angular2/router';
|
||||
import {OnActivate, ComponentInstruction, RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
|
||||
import {APP_BASE_HREF} from 'angular2/platform/common';
|
||||
|
||||
// #docregion routerOnActivate
|
||||
@Component({template: `Child`})
|
||||
@ -15,7 +10,7 @@ class ChildCmp {
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<h2>Parent</h2> (<router-outlet></router-outlet>)
|
||||
<h2>Parent</h2> (<router-outlet></router-outlet>)
|
||||
<p>{{log}}</p>`,
|
||||
directives: [ROUTER_DIRECTIVES]
|
||||
})
|
||||
@ -39,7 +34,7 @@ class ParentCmp implements OnActivate {
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<h1>My app</h1>
|
||||
|
||||
|
||||
<nav>
|
||||
<a [routerLink]="['Parent', 'Child']">Child</a>
|
||||
</nav>
|
||||
|
@ -1,12 +1,7 @@
|
||||
import {Component, Injectable, provide} from 'angular2/core';
|
||||
import {bootstrap} from 'angular2/platform/browser';
|
||||
import {
|
||||
OnDeactivate,
|
||||
ComponentInstruction,
|
||||
RouteConfig,
|
||||
ROUTER_DIRECTIVES,
|
||||
APP_BASE_HREF
|
||||
} from 'angular2/router';
|
||||
import {OnDeactivate, ComponentInstruction, RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
|
||||
import {APP_BASE_HREF} from 'angular2/platform/common';
|
||||
|
||||
|
||||
@Injectable()
|
||||
|
@ -5,11 +5,11 @@ import {
|
||||
RouteConfig,
|
||||
ComponentInstruction,
|
||||
ROUTER_DIRECTIVES,
|
||||
APP_BASE_HREF,
|
||||
CanReuse,
|
||||
RouteParams,
|
||||
OnReuse
|
||||
} from 'angular2/router';
|
||||
import {APP_BASE_HREF} from 'angular2/platform/common';
|
||||
|
||||
|
||||
// #docregion reuseCmp
|
||||
|
@ -1,6 +1,7 @@
|
||||
export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
|
||||
export * from 'angular2/src/core/angular_entrypoint';
|
||||
export {
|
||||
BROWSER_PROVIDERS,
|
||||
CACHED_TEMPLATE_PROVIDER,
|
||||
ELEMENT_PROBE_PROVIDERS,
|
||||
ELEMENT_PROBE_PROVIDERS_PROD_MODE,
|
||||
inspectNativeElement,
|
||||
@ -12,13 +13,24 @@ export {
|
||||
disableDebugTools
|
||||
} from 'angular2/src/platform/browser_common';
|
||||
|
||||
import {Type, isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
import {Type, isPresent, isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
import {
|
||||
BROWSER_PROVIDERS,
|
||||
BROWSER_APP_COMMON_PROVIDERS
|
||||
BROWSER_APP_COMMON_PROVIDERS,
|
||||
BROWSER_PLATFORM_MARKER
|
||||
} from 'angular2/src/platform/browser_common';
|
||||
import {COMPILER_PROVIDERS} from 'angular2/compiler';
|
||||
import {ComponentRef, platform, reflector} from 'angular2/core';
|
||||
import {
|
||||
ComponentRef,
|
||||
coreLoadAndBootstrap,
|
||||
reflector,
|
||||
ReflectiveInjector,
|
||||
PlatformRef,
|
||||
OpaqueToken,
|
||||
getPlatform,
|
||||
createPlatform,
|
||||
assertPlatform
|
||||
} from 'angular2/core';
|
||||
import {ReflectionCapabilities} from 'angular2/src/core/reflection/reflection_capabilities';
|
||||
import {XHRImpl} from "angular2/src/platform/browser/xhr_impl";
|
||||
import {XHR} from 'angular2/compiler';
|
||||
@ -33,6 +45,13 @@ export const BROWSER_APP_PROVIDERS: Array<any /*Type | Provider | any[]*/> = CON
|
||||
new Provider(XHR, {useClass: XHRImpl}),
|
||||
]);
|
||||
|
||||
export function browserPlatform(): PlatformRef {
|
||||
if (isBlank(getPlatform())) {
|
||||
createPlatform(ReflectiveInjector.resolveAndCreate(BROWSER_PROVIDERS));
|
||||
}
|
||||
return assertPlatform(BROWSER_PLATFORM_MARKER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrapping for Angular applications.
|
||||
*
|
||||
@ -105,7 +124,8 @@ export function bootstrap(
|
||||
appComponentType: Type,
|
||||
customProviders?: Array<any /*Type | Provider | any[]*/>): Promise<ComponentRef> {
|
||||
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||
let appProviders =
|
||||
isPresent(customProviders) ? [BROWSER_APP_PROVIDERS, customProviders] : BROWSER_APP_PROVIDERS;
|
||||
return platform(BROWSER_PROVIDERS).application(appProviders).bootstrap(appComponentType);
|
||||
var appInjector = ReflectiveInjector.resolveAndCreate(
|
||||
[BROWSER_APP_PROVIDERS, isPresent(customProviders) ? customProviders : []],
|
||||
browserPlatform().injector);
|
||||
return coreLoadAndBootstrap(appInjector, appComponentType);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
|
||||
export * from 'angular2/src/core/angular_entrypoint';
|
||||
export {
|
||||
BROWSER_PROVIDERS,
|
||||
ELEMENT_PROBE_PROVIDERS,
|
||||
@ -11,12 +11,21 @@ export {
|
||||
disableDebugTools
|
||||
} from 'angular2/src/platform/browser_common';
|
||||
|
||||
import {Type, isPresent} from 'angular2/src/facade/lang';
|
||||
import {Type, isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {
|
||||
BROWSER_PROVIDERS,
|
||||
BROWSER_APP_COMMON_PROVIDERS
|
||||
BROWSER_APP_COMMON_PROVIDERS,
|
||||
BROWSER_PLATFORM_MARKER
|
||||
} from 'angular2/src/platform/browser_common';
|
||||
import {ComponentRef, platform} from 'angular2/core';
|
||||
import {
|
||||
ComponentRef,
|
||||
coreLoadAndBootstrap,
|
||||
ReflectiveInjector,
|
||||
PlatformRef,
|
||||
getPlatform,
|
||||
createPlatform,
|
||||
assertPlatform
|
||||
} from 'angular2/core';
|
||||
|
||||
/**
|
||||
* An array of providers that should be passed into `application()` when bootstrapping a component
|
||||
@ -26,6 +35,13 @@ import {ComponentRef, platform} from 'angular2/core';
|
||||
export const BROWSER_APP_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
|
||||
BROWSER_APP_COMMON_PROVIDERS;
|
||||
|
||||
export function browserStaticPlatform(): PlatformRef {
|
||||
if (isBlank(getPlatform())) {
|
||||
createPlatform(ReflectiveInjector.resolveAndCreate(BROWSER_PROVIDERS));
|
||||
}
|
||||
return assertPlatform(BROWSER_PLATFORM_MARKER);
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link bootstrap} for more information.
|
||||
*/
|
||||
@ -38,5 +54,7 @@ export function bootstrapStatic(appComponentType: Type,
|
||||
|
||||
let appProviders =
|
||||
isPresent(customProviders) ? [BROWSER_APP_PROVIDERS, customProviders] : BROWSER_APP_PROVIDERS;
|
||||
return platform(BROWSER_PROVIDERS).application(appProviders).bootstrap(appComponentType);
|
||||
var appInjector =
|
||||
ReflectiveInjector.resolveAndCreate(appProviders, browserStaticPlatform().injector);
|
||||
return coreLoadAndBootstrap(appInjector, appComponentType);
|
||||
}
|
||||
|
5
modules/angular2/platform/common.ts
Normal file
5
modules/angular2/platform/common.ts
Normal file
@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Platform agnostic services.
|
||||
* Can be used both in the browser and on the server.
|
||||
*/
|
||||
export * from 'angular2/src/platform/location';
|
@ -1,5 +1,6 @@
|
||||
/**
|
||||
* This is a set of classes and objects that can be used both in the browser and on the server.
|
||||
* This is a set of DOM related classes and objects that can be used both in the browser and on the
|
||||
* server.
|
||||
*/
|
||||
export {DOM, setRootDomAdapter, DomAdapter} from 'angular2/src/platform/dom/dom_adapter';
|
||||
export {DomRenderer} from 'angular2/src/platform/dom/dom_renderer';
|
||||
|
@ -2,14 +2,17 @@ import {
|
||||
TEST_BROWSER_STATIC_PLATFORM_PROVIDERS,
|
||||
ADDITIONAL_TEST_BROWSER_PROVIDERS
|
||||
} from 'angular2/platform/testing/browser_static';
|
||||
|
||||
import {BROWSER_APP_PROVIDERS} from 'angular2/platform/browser';
|
||||
|
||||
|
||||
import {CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
|
||||
/**
|
||||
* Default patform providers for testing.
|
||||
* Providers for using template cache to avoid actual XHR.
|
||||
* Re-exported here so that tests import from a single place.
|
||||
*/
|
||||
export {CACHED_TEMPLATE_PROVIDER} from 'angular2/platform/browser';
|
||||
|
||||
/**
|
||||
* Default platform providers for testing.
|
||||
*/
|
||||
export const TEST_BROWSER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
|
||||
CONST_EXPR([TEST_BROWSER_STATIC_PLATFORM_PROVIDERS]);
|
||||
|
@ -1,12 +1,11 @@
|
||||
import {
|
||||
APP_ID,
|
||||
DirectiveResolver,
|
||||
NgZone,
|
||||
Provider,
|
||||
ViewResolver,
|
||||
PLATFORM_COMMON_PROVIDERS,
|
||||
PLATFORM_INITIALIZER
|
||||
} from 'angular2/core';
|
||||
import {DirectiveResolver, ViewResolver} from 'angular2/compiler';
|
||||
import {BROWSER_APP_COMMON_PROVIDERS} from 'angular2/src/platform/browser_common';
|
||||
import {BrowserDomAdapter} from 'angular2/src/platform/browser/browser_adapter';
|
||||
|
||||
@ -15,7 +14,7 @@ import {MockAnimationBuilder} from 'angular2/src/mock/animation_builder_mock';
|
||||
import {MockDirectiveResolver} from 'angular2/src/mock/directive_resolver_mock';
|
||||
import {MockViewResolver} from 'angular2/src/mock/view_resolver_mock';
|
||||
import {MockLocationStrategy} from 'angular2/src/mock/mock_location_strategy';
|
||||
import {LocationStrategy} from 'angular2/src/router/location/location_strategy';
|
||||
import {LocationStrategy} from 'angular2/platform/common';
|
||||
import {MockNgZone} from 'angular2/src/mock/ng_zone_mock';
|
||||
|
||||
import {XHRImpl} from "angular2/src/platform/browser/xhr_impl";
|
||||
@ -37,7 +36,7 @@ function initBrowserTests() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Default patform providers for testing without a compiler.
|
||||
* Default platform providers for testing without a compiler.
|
||||
*/
|
||||
export const TEST_BROWSER_STATIC_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
|
||||
CONST_EXPR([
|
||||
|
@ -1,14 +1,14 @@
|
||||
import {
|
||||
APP_ID,
|
||||
DirectiveResolver,
|
||||
NgZone,
|
||||
Provider,
|
||||
ViewResolver,
|
||||
PLATFORM_COMMON_PROVIDERS,
|
||||
PLATFORM_INITIALIZER,
|
||||
APPLICATION_COMMON_PROVIDERS,
|
||||
Renderer
|
||||
} from 'angular2/core';
|
||||
import {DirectiveResolver, ViewResolver} from 'angular2/compiler';
|
||||
|
||||
import {Parse5DomAdapter} from 'angular2/src/platform/server/parse5_adapter';
|
||||
|
||||
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
|
||||
@ -16,7 +16,6 @@ import {MockAnimationBuilder} from 'angular2/src/mock/animation_builder_mock';
|
||||
import {MockDirectiveResolver} from 'angular2/src/mock/directive_resolver_mock';
|
||||
import {MockViewResolver} from 'angular2/src/mock/view_resolver_mock';
|
||||
import {MockLocationStrategy} from 'angular2/src/mock/mock_location_strategy';
|
||||
import {LocationStrategy} from 'angular2/src/router/location/location_strategy';
|
||||
import {MockNgZone} from 'angular2/src/mock/ng_zone_mock';
|
||||
|
||||
import {TestComponentBuilder} from 'angular2/src/testing/test_component_builder';
|
||||
@ -28,7 +27,7 @@ import {DOCUMENT} from 'angular2/src/platform/dom/dom_tokens';
|
||||
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
|
||||
import {RootRenderer} from 'angular2/src/core/render/api';
|
||||
import {DomRootRenderer, DomRootRenderer_} from 'angular2/src/platform/dom/dom_renderer';
|
||||
import {DomSharedStylesHost} from 'angular2/src/platform/dom/shared_styles_host';
|
||||
import {DomSharedStylesHost, SharedStylesHost} from 'angular2/src/platform/dom/shared_styles_host';
|
||||
|
||||
import {
|
||||
EventManager,
|
||||
@ -36,6 +35,7 @@ import {
|
||||
ELEMENT_PROBE_PROVIDERS
|
||||
} from 'angular2/platform/common_dom';
|
||||
import {DomEventsPlugin} from 'angular2/src/platform/dom/events/dom_events';
|
||||
import {LocationStrategy} from 'angular2/platform/common';
|
||||
|
||||
import {CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
|
||||
@ -47,7 +47,7 @@ function initServerTests() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Default patform providers for testing.
|
||||
* Default platform providers for testing.
|
||||
*/
|
||||
export const TEST_SERVER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> = CONST_EXPR([
|
||||
PLATFORM_COMMON_PROVIDERS,
|
||||
@ -78,6 +78,7 @@ export const TEST_SERVER_APPLICATION_PROVIDERS: Array<any /*Type | Provider | an
|
||||
new Provider(EVENT_MANAGER_PLUGINS, {useClass: DomEventsPlugin, multi: true}),
|
||||
new Provider(XHR, {useClass: XHR}),
|
||||
new Provider(APP_ID, {useValue: 'a'}),
|
||||
new Provider(SharedStylesHost, {useExisting: DomSharedStylesHost}),
|
||||
DomSharedStylesHost,
|
||||
ELEMENT_PROBE_PROVIDERS,
|
||||
new Provider(DirectiveResolver, {useClass: MockDirectiveResolver}),
|
||||
|
@ -1,5 +1,12 @@
|
||||
library angular2.platform.worker_app;
|
||||
|
||||
import "package:angular2/src/platform/worker_app_common.dart";
|
||||
import "package:angular2/src/platform/worker_app.dart";
|
||||
import 'package:angular2/core.dart';
|
||||
import 'package:angular2/src/facade/lang.dart';
|
||||
import 'dart:isolate';
|
||||
import 'dart:async';
|
||||
|
||||
export "package:angular2/src/platform/worker_app_common.dart"
|
||||
show WORKER_APP_PLATFORM, WORKER_APP_APPLICATION_COMMON;
|
||||
export "package:angular2/src/core/angular_entrypoint.dart"
|
||||
@ -14,3 +21,31 @@ export 'package:angular2/src/web_workers/shared/serializer.dart' show PRIMITIVE;
|
||||
export 'package:angular2/src/web_workers/shared/message_bus.dart';
|
||||
export 'package:angular2/src/web_workers/worker/router_providers.dart'
|
||||
show WORKER_APP_ROUTER;
|
||||
|
||||
PlatformRef _platform = null;
|
||||
SendPort _renderSendPort = null;
|
||||
|
||||
PlatformRef workerAppPlatform(SendPort renderSendPort) {
|
||||
if (isBlank(getPlatform())) {
|
||||
createPlatform(ReflectiveInjector.resolveAndCreate([
|
||||
WORKER_APP_PLATFORM,
|
||||
new Provider(RENDER_SEND_PORT, useValue: renderSendPort)
|
||||
]));
|
||||
}
|
||||
var platform = assertPlatform(WORKER_APP_PLATFORM_MARKER);
|
||||
if (platform.injector.get(RENDER_SEND_PORT, null) != renderSendPort) {
|
||||
throw 'Platform has already been created with a different SendPort. Please distroy it first.';
|
||||
}
|
||||
return platform;
|
||||
}
|
||||
|
||||
Future<ComponentRef> bootstrapApp(
|
||||
SendPort renderSendPort,
|
||||
Type appComponentType,
|
||||
[List<dynamic /*Type | Provider | any[]*/> customProviders]) {
|
||||
var appInjector = ReflectiveInjector.resolveAndCreate([
|
||||
WORKER_APP_APPLICATION,
|
||||
isPresent(customProviders) ? customProviders : []
|
||||
], workerAppPlatform(renderSendPort).injector);
|
||||
return coreLoadAndBootstrap(appInjector, appComponentType);
|
||||
}
|
||||
|
@ -1,3 +1,20 @@
|
||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {
|
||||
WORKER_APP_PLATFORM,
|
||||
WORKER_APP_PLATFORM_MARKER
|
||||
} from 'angular2/src/platform/worker_app_common';
|
||||
import {WORKER_APP_APPLICATION} from 'angular2/src/platform/worker_app';
|
||||
import {
|
||||
PlatformRef,
|
||||
Type,
|
||||
ComponentRef,
|
||||
ReflectiveInjector,
|
||||
coreLoadAndBootstrap,
|
||||
getPlatform,
|
||||
createPlatform,
|
||||
assertPlatform
|
||||
} from 'angular2/core';
|
||||
|
||||
export {
|
||||
WORKER_APP_PLATFORM,
|
||||
WORKER_APP_APPLICATION_COMMON
|
||||
@ -16,5 +33,20 @@ export {
|
||||
} from 'angular2/src/web_workers/shared/service_message_broker';
|
||||
export {PRIMITIVE} from 'angular2/src/web_workers/shared/serializer';
|
||||
export * from 'angular2/src/web_workers/shared/message_bus';
|
||||
export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
|
||||
export {WORKER_APP_ROUTER} from 'angular2/src/web_workers/worker/router_providers';
|
||||
|
||||
export function workerAppPlatform(): PlatformRef {
|
||||
if (isBlank(getPlatform())) {
|
||||
createPlatform(ReflectiveInjector.resolveAndCreate(WORKER_APP_PLATFORM));
|
||||
}
|
||||
return assertPlatform(WORKER_APP_PLATFORM_MARKER);
|
||||
}
|
||||
|
||||
export function bootstrapApp(
|
||||
appComponentType: Type,
|
||||
customProviders?: Array<any /*Type | Provider | any[]*/>): Promise<ComponentRef> {
|
||||
var appInjector = ReflectiveInjector.resolveAndCreate(
|
||||
[WORKER_APP_APPLICATION, isPresent(customProviders) ? customProviders : []],
|
||||
workerAppPlatform().injector);
|
||||
return coreLoadAndBootstrap(appInjector, appComponentType);
|
||||
}
|
||||
|
@ -1,5 +1,11 @@
|
||||
library angular2.platform.worker_render;
|
||||
|
||||
import 'package:angular2/src/platform/worker_render.dart';
|
||||
import 'package:angular2/src/platform/worker_render_common.dart';
|
||||
import 'package:angular2/core.dart';
|
||||
import 'package:angular2/src/facade/lang.dart';
|
||||
import 'dart:async';
|
||||
|
||||
export 'package:angular2/src/platform/worker_render_common.dart'
|
||||
show
|
||||
WORKER_SCRIPT,
|
||||
@ -8,7 +14,7 @@ export 'package:angular2/src/platform/worker_render_common.dart'
|
||||
initializeGenericWorkerRenderer;
|
||||
|
||||
export 'package:angular2/src/platform/worker_render.dart'
|
||||
show WORKER_RENDER_APPLICATION, initIsolate, WebWorkerInstance;
|
||||
show WORKER_RENDER_APPLICATION, WebWorkerInstance;
|
||||
|
||||
export '../src/web_workers/shared/client_message_broker.dart'
|
||||
show ClientMessageBroker, ClientMessageBrokerFactory, FnArg, UiArguments;
|
||||
@ -20,7 +26,24 @@ export '../src/web_workers/shared/serializer.dart' show PRIMITIVE;
|
||||
export '../src/web_workers/shared/message_bus.dart';
|
||||
export '../src/web_workers/ui/router_providers.dart' show WORKER_RENDER_ROUTER;
|
||||
|
||||
import 'package:angular2/src/platform/worker_render_common.dart';
|
||||
|
||||
const WORKER_RENDER_APP = WORKER_RENDER_APPLICATION_COMMON;
|
||||
|
||||
PlatformRef workerRenderPlatform() {
|
||||
if (isBlank(getPlatform())) {
|
||||
createPlatform(ReflectiveInjector.resolveAndCreate(WORKER_RENDER_PLATFORM));
|
||||
}
|
||||
return assertPlatform(WORKER_RENDER_PLATFORM_MARKER);
|
||||
}
|
||||
|
||||
Future<ApplicationRef> bootstrapRender(
|
||||
String workerScriptUri,
|
||||
[List<dynamic /*Type | Provider | any[]*/> customProviders]) {
|
||||
return initIsolate(workerScriptUri).then( (appProviders) {
|
||||
var appInjector = ReflectiveInjector.resolveAndCreate([
|
||||
appProviders,
|
||||
isPresent(customProviders) ? customProviders : []
|
||||
], workerRenderPlatform().injector);
|
||||
return appInjector.get(ApplicationRef);
|
||||
});
|
||||
}
|
||||
|
@ -1,3 +1,21 @@
|
||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {PromiseWrapper} from 'angular2/src/facade/async';
|
||||
import {
|
||||
ApplicationRef,
|
||||
PlatformRef,
|
||||
ReflectiveInjector,
|
||||
Provider,
|
||||
getPlatform,
|
||||
createPlatform,
|
||||
assertPlatform
|
||||
} from 'angular2/core';
|
||||
import {WORKER_RENDER_APPLICATION} from 'angular2/src/platform/worker_render';
|
||||
import {
|
||||
WORKER_SCRIPT,
|
||||
WORKER_RENDER_PLATFORM,
|
||||
WORKER_RENDER_PLATFORM_MARKER
|
||||
} from 'angular2/src/platform/worker_render_common';
|
||||
|
||||
export {
|
||||
WORKER_SCRIPT,
|
||||
WORKER_RENDER_PLATFORM,
|
||||
@ -18,10 +36,33 @@ export {
|
||||
} from '../src/web_workers/shared/service_message_broker';
|
||||
export {PRIMITIVE} from '../src/web_workers/shared/serializer';
|
||||
export * from '../src/web_workers/shared/message_bus';
|
||||
import {WORKER_RENDER_APPLICATION} from 'angular2/src/platform/worker_render';
|
||||
|
||||
/**
|
||||
* @deprecated Use WORKER_RENDER_APPLICATION
|
||||
*/
|
||||
export const WORKER_RENDER_APP = WORKER_RENDER_APPLICATION;
|
||||
export {WORKER_RENDER_ROUTER} from 'angular2/src/web_workers/ui/router_providers';
|
||||
|
||||
export function workerRenderPlatform(): PlatformRef {
|
||||
if (isBlank(getPlatform())) {
|
||||
createPlatform(ReflectiveInjector.resolveAndCreate(WORKER_RENDER_PLATFORM));
|
||||
}
|
||||
return assertPlatform(WORKER_RENDER_PLATFORM_MARKER);
|
||||
}
|
||||
|
||||
export function bootstrapRender(
|
||||
workerScriptUri: string,
|
||||
customProviders?: Array<any /*Type | Provider | any[]*/>): Promise<ApplicationRef> {
|
||||
var pf = ReflectiveInjector.resolveAndCreate(WORKER_RENDER_PLATFORM);
|
||||
var app = ReflectiveInjector.resolveAndCreate(
|
||||
[
|
||||
WORKER_RENDER_APPLICATION,
|
||||
new Provider(WORKER_SCRIPT, {useValue: workerScriptUri}),
|
||||
isPresent(customProviders) ? customProviders : []
|
||||
],
|
||||
workerRenderPlatform().injector);
|
||||
// Return a promise so that we keep the same semantics as Dart,
|
||||
// and we might want to wait for the app side to come up
|
||||
// in the future...
|
||||
return PromiseWrapper.resolve(app.get(ApplicationRef));
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ dependencies:
|
||||
logging: '>=0.9.0 <0.12.0'
|
||||
observe: '^0.13.1'
|
||||
path: '^1.0.0'
|
||||
protobuf: '^0.5.0'
|
||||
protobuf: '0.5.1'
|
||||
source_span: '^1.0.0'
|
||||
stack_trace: '^1.1.1'
|
||||
build: '>=0.0.1'
|
||||
|
@ -8,12 +8,7 @@ export {Router} from './src/router/router';
|
||||
export {RouterOutlet} from './src/router/directives/router_outlet';
|
||||
export {RouterLink} from './src/router/directives/router_link';
|
||||
export {RouteParams, RouteData} from './src/router/instruction';
|
||||
export {PlatformLocation} from './src/router/location/platform_location';
|
||||
export {RouteRegistry, ROUTER_PRIMARY_COMPONENT} from './src/router/route_registry';
|
||||
export {LocationStrategy, APP_BASE_HREF} from './src/router/location/location_strategy';
|
||||
export {HashLocationStrategy} from './src/router/location/hash_location_strategy';
|
||||
export {PathLocationStrategy} from './src/router/location/path_location_strategy';
|
||||
export {Location} from './src/router/location/location';
|
||||
export * from './src/router/route_config/route_config_decorator';
|
||||
export * from './src/router/route_definition';
|
||||
export {OnActivate, OnDeactivate, OnReuse, CanDeactivate, CanReuse} from './src/router/interfaces';
|
||||
|
34
modules/angular2/src/alt_router/directives/router_outlet.ts
Normal file
34
modules/angular2/src/alt_router/directives/router_outlet.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import {
|
||||
ResolvedReflectiveProvider,
|
||||
Directive,
|
||||
DynamicComponentLoader,
|
||||
ViewContainerRef,
|
||||
Input,
|
||||
ComponentRef,
|
||||
ComponentFactory,
|
||||
ReflectiveInjector
|
||||
} from 'angular2/core';
|
||||
import {RouterOutletMap} from '../router';
|
||||
import {isPresent} from 'angular2/src/facade/lang';
|
||||
|
||||
@Directive({selector: 'router-outlet'})
|
||||
export class RouterOutlet {
|
||||
private _loaded: ComponentRef;
|
||||
public outletMap: RouterOutletMap;
|
||||
@Input() name: string = "";
|
||||
|
||||
constructor(parentOutletMap: RouterOutletMap, private _location: ViewContainerRef) {
|
||||
parentOutletMap.registerOutlet("", this);
|
||||
}
|
||||
|
||||
load(factory: ComponentFactory, providers: ResolvedReflectiveProvider[],
|
||||
outletMap: RouterOutletMap): ComponentRef {
|
||||
if (isPresent(this._loaded)) {
|
||||
this._loaded.destroy();
|
||||
}
|
||||
this.outletMap = outletMap;
|
||||
let inj = ReflectiveInjector.fromResolvedProviders(providers, this._location.parentInjector);
|
||||
this._loaded = this._location.createComponent(factory, this._location.length, inj, []);
|
||||
return this._loaded;
|
||||
}
|
||||
}
|
6
modules/angular2/src/alt_router/interfaces.ts
Normal file
6
modules/angular2/src/alt_router/interfaces.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import {RouteSegment, Tree} from './segments';
|
||||
|
||||
export interface OnActivate {
|
||||
routerOnActivate(curr: RouteSegment, prev?: RouteSegment, currTree?: Tree<RouteSegment>,
|
||||
prevTree?: Tree<RouteSegment>): void;
|
||||
}
|
5
modules/angular2/src/alt_router/lifecycle_reflector.dart
Normal file
5
modules/angular2/src/alt_router/lifecycle_reflector.dart
Normal file
@ -0,0 +1,5 @@
|
||||
import './interfaces.dart';
|
||||
bool hasLifecycleHook(String name, Object obj) {
|
||||
if (name == "routerOnActivate") return obj is OnActivate;
|
||||
return false;
|
||||
}
|
7
modules/angular2/src/alt_router/lifecycle_reflector.ts
Normal file
7
modules/angular2/src/alt_router/lifecycle_reflector.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import {Type} from 'angular2/src/facade/lang';
|
||||
|
||||
export function hasLifecycleHook(name: string, obj: Object): boolean {
|
||||
let type = obj.constructor;
|
||||
if (!(type instanceof Type)) return false;
|
||||
return name in(<any>type).prototype;
|
||||
}
|
8
modules/angular2/src/alt_router/metadata/decorators.dart
Normal file
8
modules/angular2/src/alt_router/metadata/decorators.dart
Normal file
@ -0,0 +1,8 @@
|
||||
library angular.alt_router.decorators;
|
||||
|
||||
import 'metadata.dart';
|
||||
export 'metadata.dart';
|
||||
|
||||
class Routes extends RoutesMetadata {
|
||||
const Routes(List<RouteMetadata> routes): super(routes);
|
||||
}
|
7
modules/angular2/src/alt_router/metadata/decorators.ts
Normal file
7
modules/angular2/src/alt_router/metadata/decorators.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import {RoutesMetadata, RouteMetadata} from "./metadata";
|
||||
import {makeDecorator} from 'angular2/src/core/util/decorators';
|
||||
export interface RoutesFactory {
|
||||
(routes: RouteMetadata[]): any;
|
||||
new (routes: RouteMetadata[]): RoutesMetadata;
|
||||
}
|
||||
export var Routes: RoutesFactory = <RoutesFactory>makeDecorator(RoutesMetadata);
|
23
modules/angular2/src/alt_router/metadata/metadata.ts
Normal file
23
modules/angular2/src/alt_router/metadata/metadata.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import {CONST, Type, stringify} from "angular2/src/facade/lang";
|
||||
|
||||
export abstract class RouteMetadata {
|
||||
abstract get path(): string;
|
||||
abstract get component(): Type;
|
||||
}
|
||||
|
||||
@CONST()
|
||||
export class Route implements RouteMetadata {
|
||||
path: string;
|
||||
component: Type;
|
||||
constructor({path, component}: {path?: string, component?: Type} = {}) {
|
||||
this.path = path;
|
||||
this.component = component;
|
||||
}
|
||||
toString(): string { return `@Route(${this.path}, ${stringify(this.component)})`; }
|
||||
}
|
||||
|
||||
@CONST()
|
||||
export class RoutesMetadata {
|
||||
constructor(public routes: RouteMetadata[]) {}
|
||||
toString(): string { return `@Routes(${this.routes})`; }
|
||||
}
|
84
modules/angular2/src/alt_router/recognize.ts
Normal file
84
modules/angular2/src/alt_router/recognize.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import {RouteSegment, UrlSegment, Tree} from './segments';
|
||||
import {RoutesMetadata, RouteMetadata} from './metadata/metadata';
|
||||
import {Type, isPresent, stringify} from 'angular2/src/facade/lang';
|
||||
import {PromiseWrapper} from 'angular2/src/facade/promise';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {ComponentResolver} from 'angular2/core';
|
||||
import {reflector} from 'angular2/src/core/reflection/reflection';
|
||||
|
||||
export function recognize(componentResolver: ComponentResolver, type: Type,
|
||||
url: Tree<UrlSegment>): Promise<Tree<RouteSegment>> {
|
||||
return _recognize(componentResolver, type, url, url.root)
|
||||
.then(nodes => new Tree<RouteSegment>(nodes));
|
||||
}
|
||||
|
||||
function _recognize(componentResolver: ComponentResolver, type: Type, url: Tree<UrlSegment>,
|
||||
current: UrlSegment): Promise<RouteSegment[]> {
|
||||
let metadata = _readMetadata(type); // should read from the factory instead
|
||||
|
||||
let matched;
|
||||
try {
|
||||
matched = _match(metadata, url, current);
|
||||
} catch (e) {
|
||||
return PromiseWrapper.reject(e, null);
|
||||
}
|
||||
|
||||
return componentResolver.resolveComponent(matched.route.component)
|
||||
.then(factory => {
|
||||
let segment = new RouteSegment(matched.consumedUrlSegments, matched.parameters, "",
|
||||
matched.route.component, factory);
|
||||
|
||||
if (isPresent(matched.leftOver)) {
|
||||
return _recognize(componentResolver, matched.route.component, url, matched.leftOver)
|
||||
.then(children => [segment].concat(children));
|
||||
} else {
|
||||
return [segment];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function _match(metadata: RoutesMetadata, url: Tree<UrlSegment>,
|
||||
current: UrlSegment): _MatchingResult {
|
||||
for (let r of metadata.routes) {
|
||||
let matchingResult = _matchWithParts(r, url, current);
|
||||
if (isPresent(matchingResult)) {
|
||||
return matchingResult;
|
||||
}
|
||||
}
|
||||
throw new BaseException("Cannot match any routes");
|
||||
}
|
||||
|
||||
function _matchWithParts(route: RouteMetadata, url: Tree<UrlSegment>,
|
||||
current: UrlSegment): _MatchingResult {
|
||||
let parts = route.path.split("/");
|
||||
let parameters = {};
|
||||
let consumedUrlSegments = [];
|
||||
|
||||
let u = current;
|
||||
for (let i = 0; i < parts.length; ++i) {
|
||||
consumedUrlSegments.push(u);
|
||||
let p = parts[i];
|
||||
if (p.startsWith(":")) {
|
||||
let segment = u.segment;
|
||||
parameters[p.substring(1)] = segment;
|
||||
} else if (p != u.segment) {
|
||||
return null;
|
||||
}
|
||||
u = url.firstChild(u);
|
||||
}
|
||||
return new _MatchingResult(route, consumedUrlSegments, parameters, u);
|
||||
}
|
||||
|
||||
class _MatchingResult {
|
||||
constructor(public route: RouteMetadata, public consumedUrlSegments: UrlSegment[],
|
||||
public parameters: {[key: string]: string}, public leftOver: UrlSegment) {}
|
||||
}
|
||||
|
||||
function _readMetadata(componentType: Type) {
|
||||
let metadata = reflector.annotations(componentType).filter(f => f instanceof RoutesMetadata);
|
||||
if (metadata.length === 0) {
|
||||
throw new BaseException(
|
||||
`Component '${stringify(componentType)}' does not have route configuration`);
|
||||
}
|
||||
return metadata[0];
|
||||
}
|
55
modules/angular2/src/alt_router/router.ts
Normal file
55
modules/angular2/src/alt_router/router.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import {provide, ReflectiveInjector, ComponentResolver} from 'angular2/core';
|
||||
import {RouterOutlet} from './directives/router_outlet';
|
||||
import {Type, isBlank, isPresent} from 'angular2/src/facade/lang';
|
||||
import {RouterUrlParser} from './router_url_parser';
|
||||
import {recognize} from './recognize';
|
||||
import {equalSegments, routeSegmentComponentFactory, RouteSegment, Tree} from './segments';
|
||||
import {hasLifecycleHook} from './lifecycle_reflector';
|
||||
|
||||
export class RouterOutletMap {
|
||||
/** @internal */
|
||||
_outlets: {[name: string]: RouterOutlet} = {};
|
||||
registerOutlet(name: string, outlet: RouterOutlet): void { this._outlets[name] = outlet; }
|
||||
}
|
||||
|
||||
export class Router {
|
||||
private prevTree: Tree<RouteSegment>;
|
||||
constructor(private _componentType: Type, private _componentResolver: ComponentResolver,
|
||||
private _urlParser: RouterUrlParser, private _routerOutletMap: RouterOutletMap) {}
|
||||
|
||||
navigateByUrl(url: string): Promise<void> {
|
||||
let urlSegmentTree = this._urlParser.parse(url.substring(1));
|
||||
return recognize(this._componentResolver, this._componentType, urlSegmentTree)
|
||||
.then(currTree => {
|
||||
let prevRoot = isPresent(this.prevTree) ? this.prevTree.root : null;
|
||||
_loadSegments(currTree, currTree.root, this.prevTree, prevRoot, this,
|
||||
this._routerOutletMap);
|
||||
this.prevTree = currTree;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function _loadSegments(currTree: Tree<RouteSegment>, curr: RouteSegment,
|
||||
prevTree: Tree<RouteSegment>, prev: RouteSegment, router: Router,
|
||||
parentOutletMap: RouterOutletMap): void {
|
||||
let outlet = parentOutletMap._outlets[curr.outlet];
|
||||
|
||||
let outletMap;
|
||||
if (equalSegments(curr, prev)) {
|
||||
outletMap = outlet.outletMap;
|
||||
} else {
|
||||
outletMap = new RouterOutletMap();
|
||||
let resolved = ReflectiveInjector.resolve(
|
||||
[provide(RouterOutletMap, {useValue: outletMap}), provide(RouteSegment, {useValue: curr})]);
|
||||
let ref = outlet.load(routeSegmentComponentFactory(curr), resolved, outletMap);
|
||||
if (hasLifecycleHook("routerOnActivate", ref.instance)) {
|
||||
ref.instance.routerOnActivate(curr, prev, currTree, prevTree);
|
||||
}
|
||||
}
|
||||
|
||||
if (isPresent(currTree.firstChild(curr))) {
|
||||
let cc = currTree.firstChild(curr);
|
||||
let pc = isBlank(prevTree) ? null : prevTree.firstChild(prev);
|
||||
_loadSegments(currTree, cc, prevTree, pc, router, outletMap);
|
||||
}
|
||||
}
|
27
modules/angular2/src/alt_router/router_url_parser.ts
Normal file
27
modules/angular2/src/alt_router/router_url_parser.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import {UrlSegment, Tree} from './segments';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
|
||||
export abstract class RouterUrlParser { abstract parse(url: string): Tree<UrlSegment>; }
|
||||
|
||||
export class DefaultRouterUrlParser extends RouterUrlParser {
|
||||
parse(url: string): Tree<UrlSegment> {
|
||||
if (url.length === 0) {
|
||||
throw new BaseException(`Invalid url '${url}'`);
|
||||
}
|
||||
return new Tree<UrlSegment>(this._parseNodes(url));
|
||||
}
|
||||
|
||||
private _parseNodes(url: string): UrlSegment[] {
|
||||
let index = url.indexOf("/", 1);
|
||||
let children: UrlSegment[];
|
||||
let currentUrl;
|
||||
if (index > -1) {
|
||||
children = this._parseNodes(url.substring(index + 1));
|
||||
currentUrl = url.substring(0, index);
|
||||
} else {
|
||||
children = [];
|
||||
currentUrl = url;
|
||||
}
|
||||
return [new UrlSegment(currentUrl, {}, "")].concat(children);
|
||||
}
|
||||
}
|
66
modules/angular2/src/alt_router/segments.ts
Normal file
66
modules/angular2/src/alt_router/segments.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import {ComponentFactory} from 'angular2/core';
|
||||
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {Type, isBlank} from 'angular2/src/facade/lang';
|
||||
|
||||
export class Tree<T> {
|
||||
constructor(private _nodes: T[]) {}
|
||||
|
||||
get root(): T { return this._nodes[0]; }
|
||||
|
||||
parent(t: T): T {
|
||||
let index = this._nodes.indexOf(t);
|
||||
return index > 0 ? this._nodes[index - 1] : null;
|
||||
}
|
||||
|
||||
children(t: T): T[] {
|
||||
let index = this._nodes.indexOf(t);
|
||||
return index > -1 && index < this._nodes.length - 1 ? [this._nodes[index + 1]] : [];
|
||||
}
|
||||
|
||||
firstChild(t: T): T {
|
||||
let index = this._nodes.indexOf(t);
|
||||
return index > -1 && index < this._nodes.length - 1 ? this._nodes[index + 1] : null;
|
||||
}
|
||||
|
||||
pathToRoot(t: T): T[] {
|
||||
let index = this._nodes.indexOf(t);
|
||||
return index > -1 ? this._nodes.slice(0, index + 1) : null;
|
||||
}
|
||||
}
|
||||
|
||||
export class UrlSegment {
|
||||
constructor(public segment: string, public parameters: {[key: string]: string},
|
||||
public outlet: string) {}
|
||||
}
|
||||
|
||||
export class RouteSegment {
|
||||
/** @internal */
|
||||
_type: Type;
|
||||
|
||||
/** @internal */
|
||||
_componentFactory: ComponentFactory;
|
||||
|
||||
/** @internal */
|
||||
_parameters: {[key: string]: string};
|
||||
|
||||
constructor(public urlSegments: UrlSegment[], parameters: {[key: string]: string},
|
||||
public outlet: string, type: Type, componentFactory: ComponentFactory) {
|
||||
this._type = type;
|
||||
this._componentFactory = componentFactory;
|
||||
this._parameters = parameters;
|
||||
}
|
||||
|
||||
getParam(param: string): string { return this._parameters[param]; }
|
||||
|
||||
get type(): Type { return this._type; }
|
||||
}
|
||||
|
||||
export function equalSegments(a: RouteSegment, b: RouteSegment): boolean {
|
||||
if (isBlank(a) && !isBlank(b)) return false;
|
||||
if (!isBlank(a) && isBlank(b)) return false;
|
||||
return a._type === b._type && StringMapWrapper.equals(a._parameters, b._parameters);
|
||||
}
|
||||
|
||||
export function routeSegmentComponentFactory(a: RouteSegment): ComponentFactory {
|
||||
return a._componentFactory;
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
export {NgClass} from './directives/ng_class';
|
||||
export {NgFor} from './directives/ng_for';
|
||||
export {NgIf} from './directives/ng_if';
|
||||
export {NgTemplateOutlet} from './directives/ng_template_outlet';
|
||||
export {NgStyle} from './directives/ng_style';
|
||||
export {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './directives/ng_switch';
|
||||
export {NgPlural, NgPluralCase, NgLocalization} from './directives/ng_plural';
|
||||
|
@ -2,6 +2,7 @@ import {CONST_EXPR, Type} from 'angular2/src/facade/lang';
|
||||
import {NgClass} from './ng_class';
|
||||
import {NgFor} from './ng_for';
|
||||
import {NgIf} from './ng_if';
|
||||
import {NgTemplateOutlet} from './ng_template_outlet';
|
||||
import {NgStyle} from './ng_style';
|
||||
import {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './ng_switch';
|
||||
import {NgPlural, NgPluralCase} from './ng_plural';
|
||||
@ -50,6 +51,7 @@ export const CORE_DIRECTIVES: Type[] = CONST_EXPR([
|
||||
NgClass,
|
||||
NgFor,
|
||||
NgIf,
|
||||
NgTemplateOutlet,
|
||||
NgStyle,
|
||||
NgSwitch,
|
||||
NgSwitchWhen,
|
||||
|
@ -21,17 +21,19 @@ import {BaseException} from "../../facade/exceptions";
|
||||
* each instantiated template inherits from the outer context with the given loop variable set
|
||||
* to the current item from the iterable.
|
||||
*
|
||||
* # Local Variables
|
||||
* ### Local Variables
|
||||
*
|
||||
* `NgFor` provides several exported values that can be aliased to local variables:
|
||||
*
|
||||
* * `index` will be set to the current loop iteration for each template context.
|
||||
* * `first` will be set to a boolean value indicating whether the item is the first one in the
|
||||
* iteration.
|
||||
* * `last` will be set to a boolean value indicating whether the item is the last one in the
|
||||
* iteration.
|
||||
* * `even` will be set to a boolean value indicating whether this item has an even index.
|
||||
* * `odd` will be set to a boolean value indicating whether this item has an odd index.
|
||||
*
|
||||
* # Change Propagation
|
||||
* ### Change Propagation
|
||||
*
|
||||
* When the contents of the iterator changes, `NgFor` makes the corresponding changes to the DOM:
|
||||
*
|
||||
@ -54,7 +56,7 @@ import {BaseException} from "../../facade/exceptions";
|
||||
* elements were deleted and all new elements inserted). This is an expensive operation and should
|
||||
* be avoided if possible.
|
||||
*
|
||||
* # Syntax
|
||||
* ### Syntax
|
||||
*
|
||||
* - `<li *ngFor="#item of items; #i = index">...</li>`
|
||||
* - `<li template="ngFor #item of items; #i = index">...</li>`
|
||||
@ -69,6 +71,7 @@ import {BaseException} from "../../facade/exceptions";
|
||||
export class NgFor implements DoCheck {
|
||||
/** @internal */
|
||||
_ngForOf: any;
|
||||
/** @internal */
|
||||
_ngForTrackBy: TrackByFn;
|
||||
private _differ: IterableDiffer;
|
||||
|
||||
@ -125,6 +128,7 @@ export class NgFor implements DoCheck {
|
||||
|
||||
for (var i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
|
||||
var viewRef = <EmbeddedViewRef>this._viewContainer.get(i);
|
||||
viewRef.setLocal('first', i === 0);
|
||||
viewRef.setLocal('last', i === ilen - 1);
|
||||
}
|
||||
|
||||
@ -149,7 +153,7 @@ export class NgFor implements DoCheck {
|
||||
var tuple = tuples[i];
|
||||
// separate moved views from removed views.
|
||||
if (isPresent(tuple.record.currentIndex)) {
|
||||
tuple.view = this._viewContainer.detach(tuple.record.previousIndex);
|
||||
tuple.view = <EmbeddedViewRef>this._viewContainer.detach(tuple.record.previousIndex);
|
||||
movedTuples.push(tuple);
|
||||
} else {
|
||||
this._viewContainer.remove(tuple.record.previousIndex);
|
||||
|
@ -74,6 +74,7 @@ export abstract class NgLocalization { abstract getPluralCategory(value: any): s
|
||||
|
||||
@Directive({selector: '[ngPluralCase]'})
|
||||
export class NgPluralCase {
|
||||
/** @internal */
|
||||
_view: SwitchView;
|
||||
constructor(@Attribute('ngPluralCase') public value: string, template: TemplateRef,
|
||||
viewContainer: ViewContainerRef) {
|
||||
|
@ -21,7 +21,7 @@ export class SwitchView {
|
||||
* `NgSwitch` simply inserts nested elements based on which match expression matches the value
|
||||
* obtained from the evaluated switch expression. In other words, you define a container element
|
||||
* (where you place the directive with a switch expression on the
|
||||
* **`[ngSwitch]="..."` attribute**), define any inner elements inside of the directive and
|
||||
* `[ngSwitch]="..."` attribute), define any inner elements inside of the directive and
|
||||
* place a `[ngSwitchWhen]` attribute per element.
|
||||
*
|
||||
* The `ngSwitchWhen` property is used to inform `NgSwitch` which element to display when the
|
||||
|
26
modules/angular2/src/common/directives/ng_template_outlet.ts
Normal file
26
modules/angular2/src/common/directives/ng_template_outlet.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import {Directive, Input, ViewContainerRef, ViewRef, TemplateRef} from 'angular2/core';
|
||||
import {isPresent} from 'angular2/src/facade/lang';
|
||||
|
||||
/**
|
||||
* Creates and inserts an embedded view based on a prepared `TemplateRef`.
|
||||
*
|
||||
* ### Syntax
|
||||
* - `<template [ngTemplateOutlet]="templateRefExpression"></template>`
|
||||
*/
|
||||
@Directive({selector: '[ngTemplateOutlet]'})
|
||||
export class NgTemplateOutlet {
|
||||
private _insertedViewRef: ViewRef;
|
||||
|
||||
constructor(private _viewContainerRef: ViewContainerRef) {}
|
||||
|
||||
@Input()
|
||||
set ngTemplateOutlet(templateRef: TemplateRef) {
|
||||
if (isPresent(this._insertedViewRef)) {
|
||||
this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._insertedViewRef));
|
||||
}
|
||||
|
||||
if (isPresent(templateRef)) {
|
||||
this._insertedViewRef = this._viewContainerRef.createEmbeddedView(templateRef);
|
||||
}
|
||||
}
|
||||
}
|
@ -52,8 +52,7 @@ const controlGroupProvider =
|
||||
* <pre>{{valueOf(f)}}</pre>
|
||||
* </form>
|
||||
* </div>
|
||||
* `,
|
||||
* directives: [FORM_DIRECTIVES]
|
||||
* `
|
||||
* })
|
||||
* export class App {
|
||||
* valueOf(cg: NgControlGroup): string {
|
||||
|
@ -57,7 +57,7 @@ const formControlBinding =
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* ###ngModel
|
||||
* ### ngModel
|
||||
*
|
||||
* We can also use `ngModel` to bind a domain model to the form.
|
||||
*
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
import {CONST_EXPR, isBlank} from 'angular2/src/facade/lang';
|
||||
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
|
||||
import {
|
||||
SimpleChange,
|
||||
@ -114,6 +115,7 @@ export class NgFormModel extends ControlContainer implements Form,
|
||||
}
|
||||
|
||||
ngOnChanges(changes: {[key: string]: SimpleChange}): void {
|
||||
this._checkFormPresent();
|
||||
if (StringMapWrapper.contains(changes, "form")) {
|
||||
var sync = composeValidators(this._validators);
|
||||
this.form.validator = Validators.compose([this.form.validator, sync]);
|
||||
@ -173,4 +175,11 @@ export class NgFormModel extends ControlContainer implements Form,
|
||||
dir.valueAccessor.writeValue(ctrl.value);
|
||||
});
|
||||
}
|
||||
|
||||
private _checkFormPresent() {
|
||||
if (isBlank(this.form)) {
|
||||
throw new BaseException(
|
||||
`ngFormModel expects a form. Please pass one in. Example: <form [ngFormModel]="myCoolForm">`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ export class NumberValueAccessor implements ControlValueAccessor {
|
||||
}
|
||||
|
||||
registerOnChange(fn: (_: number) => void): void {
|
||||
this.onChange = (value) => { fn(NumberWrapper.parseFloat(value)); };
|
||||
this.onChange = (value) => { fn(value == '' ? null : NumberWrapper.parseFloat(value)); };
|
||||
}
|
||||
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
|
||||
}
|
||||
|
@ -88,9 +88,12 @@ export class RadioButtonState {
|
||||
})
|
||||
export class RadioControlValueAccessor implements ControlValueAccessor,
|
||||
OnDestroy, OnInit {
|
||||
/** @internal */
|
||||
_state: RadioButtonState;
|
||||
/** @internal */
|
||||
_control: NgControl;
|
||||
@Input() name: string;
|
||||
/** @internal */
|
||||
_fn: Function;
|
||||
onChange = () => {};
|
||||
onTouched = () => {};
|
||||
|
@ -1,21 +1,94 @@
|
||||
import {
|
||||
Query,
|
||||
Directive,
|
||||
Renderer,
|
||||
Self,
|
||||
forwardRef,
|
||||
Provider,
|
||||
ElementRef,
|
||||
QueryList
|
||||
Input,
|
||||
Host,
|
||||
OnDestroy,
|
||||
Optional
|
||||
} from 'angular2/core';
|
||||
|
||||
import {ObservableWrapper} from 'angular2/src/facade/async';
|
||||
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from './control_value_accessor';
|
||||
import {CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
import {
|
||||
CONST_EXPR,
|
||||
StringWrapper,
|
||||
isPrimitive,
|
||||
isPresent,
|
||||
isBlank,
|
||||
looseIdentical
|
||||
} from 'angular2/src/facade/lang';
|
||||
|
||||
import {MapWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
const SELECT_VALUE_ACCESSOR = CONST_EXPR(new Provider(
|
||||
NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => SelectControlValueAccessor), multi: true}));
|
||||
|
||||
function _buildValueString(id: string, value: any): string {
|
||||
if (isBlank(id)) return `${value}`;
|
||||
if (!isPrimitive(value)) value = "Object";
|
||||
return StringWrapper.slice(`${id}: ${value}`, 0, 50);
|
||||
}
|
||||
|
||||
function _extractId(valueString: string): string {
|
||||
return valueString.split(":")[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* The accessor for writing a value and listening to changes on a select element.
|
||||
*
|
||||
* Note: We have to listen to the 'change' event because 'input' events aren't fired
|
||||
* for selects in Firefox and IE:
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=1024350
|
||||
* https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/4660045/
|
||||
*
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'select[ngControl],select[ngFormControl],select[ngModel]',
|
||||
host: {'(change)': 'onChange($event.target.value)', '(blur)': 'onTouched()'},
|
||||
providers: [SELECT_VALUE_ACCESSOR]
|
||||
})
|
||||
export class SelectControlValueAccessor implements ControlValueAccessor {
|
||||
value: any;
|
||||
/** @internal */
|
||||
_optionMap: Map<string, any> = new Map<string, any>();
|
||||
/** @internal */
|
||||
_idCounter: number = 0;
|
||||
|
||||
onChange = (_: any) => {};
|
||||
onTouched = () => {};
|
||||
|
||||
constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
|
||||
|
||||
writeValue(value: any): void {
|
||||
this.value = value;
|
||||
var valueString = _buildValueString(this._getOptionId(value), value);
|
||||
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', valueString);
|
||||
}
|
||||
|
||||
registerOnChange(fn: (value: any) => any): void {
|
||||
this.onChange = (valueString: string) => { fn(this._getOptionValue(valueString)); };
|
||||
}
|
||||
registerOnTouched(fn: () => any): void { this.onTouched = fn; }
|
||||
|
||||
/** @internal */
|
||||
_registerOption(): string { return (this._idCounter++).toString(); }
|
||||
|
||||
/** @internal */
|
||||
_getOptionId(value: any): string {
|
||||
for (let id of MapWrapper.keys(this._optionMap)) {
|
||||
if (looseIdentical(this._optionMap.get(id), value)) return id;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_getOptionValue(valueString: string): any {
|
||||
let value = this._optionMap.get(_extractId(valueString));
|
||||
return isPresent(value) ? value : valueString;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks `<option>` as dynamic, so Angular can be notified when options change.
|
||||
*
|
||||
@ -28,36 +101,37 @@ const SELECT_VALUE_ACCESSOR = CONST_EXPR(new Provider(
|
||||
* ```
|
||||
*/
|
||||
@Directive({selector: 'option'})
|
||||
export class NgSelectOption {
|
||||
}
|
||||
export class NgSelectOption implements OnDestroy {
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* The accessor for writing a value and listening to changes on a select element.
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'select[ngControl],select[ngFormControl],select[ngModel]',
|
||||
host: {'(input)': 'onChange($event.target.value)', '(blur)': 'onTouched()'},
|
||||
bindings: [SELECT_VALUE_ACCESSOR]
|
||||
})
|
||||
export class SelectControlValueAccessor implements ControlValueAccessor {
|
||||
value: string;
|
||||
onChange = (_: any) => {};
|
||||
onTouched = () => {};
|
||||
|
||||
constructor(private _renderer: Renderer, private _elementRef: ElementRef,
|
||||
@Query(NgSelectOption, {descendants: true}) query: QueryList<NgSelectOption>) {
|
||||
this._updateValueWhenListOfOptionsChanges(query);
|
||||
constructor(private _element: ElementRef, private _renderer: Renderer,
|
||||
@Optional() @Host() private _select: SelectControlValueAccessor) {
|
||||
if (isPresent(this._select)) this.id = this._select._registerOption();
|
||||
}
|
||||
|
||||
writeValue(value: any): void {
|
||||
this.value = value;
|
||||
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', value);
|
||||
@Input('ngValue')
|
||||
set ngValue(value: any) {
|
||||
if (this._select == null) return;
|
||||
this._select._optionMap.set(this.id, value);
|
||||
this._setElementValue(_buildValueString(this.id, value));
|
||||
this._select.writeValue(this._select.value);
|
||||
}
|
||||
|
||||
registerOnChange(fn: () => any): void { this.onChange = fn; }
|
||||
registerOnTouched(fn: () => any): void { this.onTouched = fn; }
|
||||
@Input('value')
|
||||
set value(value: any) {
|
||||
this._setElementValue(value);
|
||||
if (isPresent(this._select)) this._select.writeValue(this._select.value);
|
||||
}
|
||||
|
||||
private _updateValueWhenListOfOptionsChanges(query: QueryList<NgSelectOption>) {
|
||||
ObservableWrapper.subscribe(query.changes, (_) => this.writeValue(this.value));
|
||||
/** @internal */
|
||||
_setElementValue(value: string): void {
|
||||
this._renderer.setElementProperty(this._element.nativeElement, 'value', value);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (isPresent(this._select)) {
|
||||
this._select._optionMap.delete(this.id);
|
||||
this._select.writeValue(this._select.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,10 @@ import {NumberWrapper} from "angular2/src/facade/lang";
|
||||
*/
|
||||
export interface Validator { validate(c: modelModule.AbstractControl): {[key: string]: any}; }
|
||||
|
||||
const REQUIRED = Validators.required;
|
||||
|
||||
const REQUIRED_VALIDATOR =
|
||||
CONST_EXPR(new Provider(NG_VALIDATORS, {useValue: Validators.required, multi: true}));
|
||||
CONST_EXPR(new Provider(NG_VALIDATORS, {useValue: REQUIRED, multi: true}));
|
||||
|
||||
/**
|
||||
* A Directive that adds the `required` validator to any controls marked with the
|
||||
|
@ -1,13 +1,6 @@
|
||||
import {isBlank, isPresent, isPromise, CONST} from 'angular2/src/facade/lang';
|
||||
import {ObservableWrapper, Observable, EventEmitter} from 'angular2/src/facade/async';
|
||||
import {
|
||||
Pipe,
|
||||
Injectable,
|
||||
ChangeDetectorRef,
|
||||
OnDestroy,
|
||||
PipeTransform,
|
||||
WrappedValue
|
||||
} from 'angular2/core';
|
||||
import {Pipe, Injectable, ChangeDetectorRef, OnDestroy, WrappedValue} from 'angular2/core';
|
||||
|
||||
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
|
||||
|
||||
@ -55,7 +48,7 @@ var __unused: Promise<any>; // avoid unused import when Promise union types are
|
||||
*/
|
||||
@Pipe({name: 'async', pure: false})
|
||||
@Injectable()
|
||||
export class AsyncPipe implements PipeTransform, OnDestroy {
|
||||
export class AsyncPipe implements OnDestroy {
|
||||
/** @internal */
|
||||
_latestValue: Object = null;
|
||||
/** @internal */
|
||||
@ -76,7 +69,7 @@ export class AsyncPipe implements PipeTransform, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
transform(obj: Observable<any>| Promise<any>| EventEmitter<any>, args?: any[]): any {
|
||||
transform(obj: Observable<any>| Promise<any>| EventEmitter<any>): any {
|
||||
if (isBlank(this._obj)) {
|
||||
if (isPresent(obj)) {
|
||||
this._subscribe(obj);
|
||||
|
@ -101,14 +101,13 @@ export class DatePipe implements PipeTransform {
|
||||
};
|
||||
|
||||
|
||||
transform(value: any, args: any[]): string {
|
||||
transform(value: any, pattern: string = 'mediumDate'): string {
|
||||
if (isBlank(value)) return null;
|
||||
|
||||
if (!this.supports(value)) {
|
||||
throw new InvalidPipeArgumentException(DatePipe, value);
|
||||
}
|
||||
|
||||
var pattern: string = isPresent(args) && args.length > 0 ? args[0] : 'mediumDate';
|
||||
if (isNumber(value)) {
|
||||
value = DateWrapper.fromMillis(value);
|
||||
}
|
||||
|
@ -45,10 +45,9 @@ var interpolationExp: RegExp = RegExpWrapper.create('#');
|
||||
@Pipe({name: 'i18nPlural', pure: true})
|
||||
@Injectable()
|
||||
export class I18nPluralPipe implements PipeTransform {
|
||||
transform(value: number, args: any[] = null): string {
|
||||
transform(value: number, pluralMap: {[count: string]: string}): string {
|
||||
var key: string;
|
||||
var valueStr: string;
|
||||
var pluralMap: {[count: string]: string} = <{[count: string]: string}>(args[0]);
|
||||
|
||||
if (!isStringMap(pluralMap)) {
|
||||
throw new InvalidPipeArgumentException(I18nPluralPipe, pluralMap);
|
||||
|
@ -36,8 +36,7 @@ import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
|
||||
@Pipe({name: 'i18nSelect', pure: true})
|
||||
@Injectable()
|
||||
export class I18nSelectPipe implements PipeTransform {
|
||||
transform(value: string, args: any[] = null): string {
|
||||
var mapping: {[key: string]: string} = <{[count: string]: string}>(args[0]);
|
||||
transform(value: string, mapping: {[key: string]: string}): string {
|
||||
if (!isStringMap(mapping)) {
|
||||
throw new InvalidPipeArgumentException(I18nSelectPipe, mapping);
|
||||
}
|
||||
|
@ -11,5 +11,5 @@ import {Injectable, PipeTransform, WrappedValue, Pipe} from 'angular2/core';
|
||||
@Pipe({name: 'json', pure: false})
|
||||
@Injectable()
|
||||
export class JsonPipe implements PipeTransform {
|
||||
transform(value: any, args: any[] = null): string { return Json.stringify(value); }
|
||||
transform(value: any): string { return Json.stringify(value); }
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
|
||||
@Pipe({name: 'lowercase'})
|
||||
@Injectable()
|
||||
export class LowerCasePipe implements PipeTransform {
|
||||
transform(value: string, args: any[] = null): string {
|
||||
transform(value: string): string {
|
||||
if (isBlank(value)) return value;
|
||||
if (!isString(value)) {
|
||||
throw new InvalidPipeArgumentException(LowerCasePipe, value);
|
||||
|
@ -11,7 +11,6 @@ import {
|
||||
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
||||
import {NumberFormatter, NumberFormatStyle} from 'angular2/src/facade/intl';
|
||||
import {Injectable, PipeTransform, WrappedValue, Pipe} from 'angular2/core';
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
|
||||
|
||||
@ -87,8 +86,7 @@ export class NumberPipe {
|
||||
@Pipe({name: 'number'})
|
||||
@Injectable()
|
||||
export class DecimalPipe extends NumberPipe implements PipeTransform {
|
||||
transform(value: any, args: any[]): string {
|
||||
var digits: string = ListWrapper.first(args);
|
||||
transform(value: any, digits: string = null): string {
|
||||
return NumberPipe._format(value, NumberFormatStyle.Decimal, digits);
|
||||
}
|
||||
}
|
||||
@ -113,8 +111,7 @@ export class DecimalPipe extends NumberPipe implements PipeTransform {
|
||||
@Pipe({name: 'percent'})
|
||||
@Injectable()
|
||||
export class PercentPipe extends NumberPipe implements PipeTransform {
|
||||
transform(value: any, args: any[]): string {
|
||||
var digits: string = ListWrapper.first(args);
|
||||
transform(value: any, digits: string = null): string {
|
||||
return NumberPipe._format(value, NumberFormatStyle.Percent, digits);
|
||||
}
|
||||
}
|
||||
@ -143,10 +140,8 @@ export class PercentPipe extends NumberPipe implements PipeTransform {
|
||||
@Pipe({name: 'currency'})
|
||||
@Injectable()
|
||||
export class CurrencyPipe extends NumberPipe implements PipeTransform {
|
||||
transform(value: any, args: any[]): string {
|
||||
var currencyCode: string = isPresent(args) && args.length > 0 ? args[0] : 'USD';
|
||||
var symbolDisplay: boolean = isPresent(args) && args.length > 1 ? args[1] : false;
|
||||
var digits: string = isPresent(args) && args.length > 2 ? args[2] : null;
|
||||
transform(value: any, currencyCode: string = 'USD', symbolDisplay: boolean = false,
|
||||
digits: string = null): string {
|
||||
return NumberPipe._format(value, NumberFormatStyle.Currency, digits, currencyCode,
|
||||
symbolDisplay);
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import {
|
||||
RegExpWrapper,
|
||||
StringWrapper
|
||||
} from 'angular2/src/facade/lang';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {Injectable, PipeTransform, Pipe} from 'angular2/core';
|
||||
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
|
||||
|
||||
@ -39,11 +38,7 @@ import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
|
||||
@Pipe({name: 'replace'})
|
||||
@Injectable()
|
||||
export class ReplacePipe implements PipeTransform {
|
||||
transform(value: any, args: any[]): any {
|
||||
if (isBlank(args) || args.length !== 2) {
|
||||
throw new BaseException('ReplacePipe requires two arguments');
|
||||
}
|
||||
|
||||
transform(value: any, pattern: string | RegExp, replacement: Function | string): any {
|
||||
if (isBlank(value)) {
|
||||
return value;
|
||||
}
|
||||
@ -53,9 +48,6 @@ export class ReplacePipe implements PipeTransform {
|
||||
}
|
||||
|
||||
var input = value.toString();
|
||||
var pattern = args[0];
|
||||
var replacement = args[1];
|
||||
|
||||
|
||||
if (!this._supportedPattern(pattern)) {
|
||||
throw new InvalidPipeArgumentException(ReplacePipe, pattern);
|
||||
@ -67,16 +59,16 @@ export class ReplacePipe implements PipeTransform {
|
||||
// var rgx = pattern instanceof RegExp ? pattern : RegExpWrapper.create(pattern);
|
||||
|
||||
if (isFunction(replacement)) {
|
||||
var rgxPattern = isString(pattern) ? RegExpWrapper.create(pattern) : pattern;
|
||||
var rgxPattern = isString(pattern) ? RegExpWrapper.create(<string>pattern) : <RegExp>pattern;
|
||||
|
||||
return StringWrapper.replaceAllMapped(input, rgxPattern, replacement);
|
||||
return StringWrapper.replaceAllMapped(input, rgxPattern, <Function>replacement);
|
||||
}
|
||||
if (pattern instanceof RegExp) {
|
||||
// use the replaceAll variant
|
||||
return StringWrapper.replaceAll(input, pattern, replacement);
|
||||
return StringWrapper.replaceAll(input, pattern, <string>replacement);
|
||||
}
|
||||
|
||||
return StringWrapper.replace(input, pattern, replacement);
|
||||
return StringWrapper.replace(input, <string>pattern, <string>replacement);
|
||||
}
|
||||
|
||||
private _supportedInput(input: any): boolean { return isString(input) || isNumber(input); }
|
||||
|
@ -1,5 +1,4 @@
|
||||
import {isBlank, isString, isArray, StringWrapper, CONST} from 'angular2/src/facade/lang';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {Injectable, PipeTransform, WrappedValue, Pipe} from 'angular2/core';
|
||||
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
|
||||
@ -59,16 +58,11 @@ import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
|
||||
@Pipe({name: 'slice', pure: false})
|
||||
@Injectable()
|
||||
export class SlicePipe implements PipeTransform {
|
||||
transform(value: any, args: any[] = null): any {
|
||||
if (isBlank(args) || args.length == 0) {
|
||||
throw new BaseException('Slice pipe requires one argument');
|
||||
}
|
||||
transform(value: any, start: number, end: number = null): any {
|
||||
if (!this.supports(value)) {
|
||||
throw new InvalidPipeArgumentException(SlicePipe, value);
|
||||
}
|
||||
if (isBlank(value)) return value;
|
||||
var start: number = args[0];
|
||||
var end: number = args.length > 1 ? args[1] : null;
|
||||
if (isString(value)) {
|
||||
return StringWrapper.slice(value, start, end);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
|
||||
@Pipe({name: 'uppercase'})
|
||||
@Injectable()
|
||||
export class UpperCasePipe implements PipeTransform {
|
||||
transform(value: string, args: any[] = null): string {
|
||||
transform(value: string): string {
|
||||
if (isBlank(value)) return value;
|
||||
if (!isString(value)) {
|
||||
throw new InvalidPipeArgumentException(UpperCasePipe, value);
|
||||
|
@ -1,218 +0,0 @@
|
||||
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {reflector} from 'angular2/src/core/reflection/reflection';
|
||||
|
||||
import {
|
||||
DirectiveIndex,
|
||||
BindingRecord,
|
||||
DirectiveRecord,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorDefinition,
|
||||
ChangeDetectorGenConfig,
|
||||
ASTWithSource
|
||||
} from 'angular2/src/core/change_detection/change_detection';
|
||||
|
||||
import {CompileDirectiveMetadata, CompileTypeMetadata} from './directive_metadata';
|
||||
import {
|
||||
TemplateAst,
|
||||
ElementAst,
|
||||
BoundTextAst,
|
||||
PropertyBindingType,
|
||||
DirectiveAst,
|
||||
TemplateAstVisitor,
|
||||
templateVisitAll,
|
||||
NgContentAst,
|
||||
EmbeddedTemplateAst,
|
||||
VariableAst,
|
||||
BoundElementPropertyAst,
|
||||
BoundEventAst,
|
||||
BoundDirectivePropertyAst,
|
||||
AttrAst,
|
||||
TextAst
|
||||
} from './template_ast';
|
||||
import {LifecycleHooks} from 'angular2/src/core/linker/interfaces';
|
||||
|
||||
export function createChangeDetectorDefinitions(
|
||||
componentType: CompileTypeMetadata, componentStrategy: ChangeDetectionStrategy,
|
||||
genConfig: ChangeDetectorGenConfig, parsedTemplate: TemplateAst[]): ChangeDetectorDefinition[] {
|
||||
var pvVisitors = [];
|
||||
var visitor = new ProtoViewVisitor(null, pvVisitors, componentStrategy);
|
||||
templateVisitAll(visitor, parsedTemplate);
|
||||
return createChangeDefinitions(pvVisitors, componentType, genConfig);
|
||||
}
|
||||
|
||||
class ProtoViewVisitor implements TemplateAstVisitor {
|
||||
viewIndex: number;
|
||||
nodeCount: number = 0;
|
||||
boundElementCount: number = 0;
|
||||
variableNames: string[] = [];
|
||||
bindingRecords: BindingRecord[] = [];
|
||||
eventRecords: BindingRecord[] = [];
|
||||
directiveRecords: DirectiveRecord[] = [];
|
||||
|
||||
constructor(public parent: ProtoViewVisitor, public allVisitors: ProtoViewVisitor[],
|
||||
public strategy: ChangeDetectionStrategy) {
|
||||
this.viewIndex = allVisitors.length;
|
||||
allVisitors.push(this);
|
||||
}
|
||||
|
||||
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any {
|
||||
this.nodeCount++;
|
||||
this.boundElementCount++;
|
||||
templateVisitAll(this, ast.outputs);
|
||||
for (var i = 0; i < ast.directives.length; i++) {
|
||||
ast.directives[i].visit(this, i);
|
||||
}
|
||||
|
||||
var childVisitor =
|
||||
new ProtoViewVisitor(this, this.allVisitors, ChangeDetectionStrategy.Default);
|
||||
// Attention: variables present on an embedded template count towards
|
||||
// the embedded template and not the template anchor!
|
||||
templateVisitAll(childVisitor, ast.vars);
|
||||
templateVisitAll(childVisitor, ast.children);
|
||||
return null;
|
||||
}
|
||||
|
||||
visitElement(ast: ElementAst, context: any): any {
|
||||
this.nodeCount++;
|
||||
if (ast.isBound()) {
|
||||
this.boundElementCount++;
|
||||
}
|
||||
templateVisitAll(this, ast.inputs, null);
|
||||
templateVisitAll(this, ast.outputs);
|
||||
templateVisitAll(this, ast.exportAsVars);
|
||||
for (var i = 0; i < ast.directives.length; i++) {
|
||||
ast.directives[i].visit(this, i);
|
||||
}
|
||||
templateVisitAll(this, ast.children);
|
||||
return null;
|
||||
}
|
||||
|
||||
visitNgContent(ast: NgContentAst, context: any): any { return null; }
|
||||
|
||||
visitVariable(ast: VariableAst, context: any): any {
|
||||
this.variableNames.push(ast.name);
|
||||
return null;
|
||||
}
|
||||
|
||||
visitEvent(ast: BoundEventAst, directiveRecord: DirectiveRecord): any {
|
||||
var bindingRecord =
|
||||
isPresent(directiveRecord) ?
|
||||
BindingRecord.createForHostEvent(ast.handler, ast.fullName, directiveRecord) :
|
||||
BindingRecord.createForEvent(ast.handler, ast.fullName, this.boundElementCount - 1);
|
||||
this.eventRecords.push(bindingRecord);
|
||||
return null;
|
||||
}
|
||||
|
||||
visitElementProperty(ast: BoundElementPropertyAst, directiveRecord: DirectiveRecord): any {
|
||||
var boundElementIndex = this.boundElementCount - 1;
|
||||
var dirIndex = isPresent(directiveRecord) ? directiveRecord.directiveIndex : null;
|
||||
var bindingRecord;
|
||||
if (ast.type === PropertyBindingType.Property) {
|
||||
bindingRecord =
|
||||
isPresent(dirIndex) ?
|
||||
BindingRecord.createForHostProperty(dirIndex, ast.value, ast.name) :
|
||||
BindingRecord.createForElementProperty(ast.value, boundElementIndex, ast.name);
|
||||
} else if (ast.type === PropertyBindingType.Attribute) {
|
||||
bindingRecord =
|
||||
isPresent(dirIndex) ?
|
||||
BindingRecord.createForHostAttribute(dirIndex, ast.value, ast.name) :
|
||||
BindingRecord.createForElementAttribute(ast.value, boundElementIndex, ast.name);
|
||||
} else if (ast.type === PropertyBindingType.Class) {
|
||||
bindingRecord =
|
||||
isPresent(dirIndex) ?
|
||||
BindingRecord.createForHostClass(dirIndex, ast.value, ast.name) :
|
||||
BindingRecord.createForElementClass(ast.value, boundElementIndex, ast.name);
|
||||
} else if (ast.type === PropertyBindingType.Style) {
|
||||
bindingRecord =
|
||||
isPresent(dirIndex) ?
|
||||
BindingRecord.createForHostStyle(dirIndex, ast.value, ast.name, ast.unit) :
|
||||
BindingRecord.createForElementStyle(ast.value, boundElementIndex, ast.name, ast.unit);
|
||||
}
|
||||
this.bindingRecords.push(bindingRecord);
|
||||
return null;
|
||||
}
|
||||
visitAttr(ast: AttrAst, context: any): any { return null; }
|
||||
visitBoundText(ast: BoundTextAst, context: any): any {
|
||||
var nodeIndex = this.nodeCount++;
|
||||
this.bindingRecords.push(BindingRecord.createForTextNode(ast.value, nodeIndex));
|
||||
return null;
|
||||
}
|
||||
visitText(ast: TextAst, context: any): any {
|
||||
this.nodeCount++;
|
||||
return null;
|
||||
}
|
||||
visitDirective(ast: DirectiveAst, directiveIndexAsNumber: number): any {
|
||||
var directiveIndex = new DirectiveIndex(this.boundElementCount - 1, directiveIndexAsNumber);
|
||||
var directiveMetadata = ast.directive;
|
||||
var outputsArray = [];
|
||||
StringMapWrapper.forEach(
|
||||
ast.directive.outputs,
|
||||
(eventName: string, dirProperty: string) => outputsArray.push([dirProperty, eventName]));
|
||||
var directiveRecord = new DirectiveRecord({
|
||||
directiveIndex: directiveIndex,
|
||||
callAfterContentInit:
|
||||
directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.AfterContentInit) !== -1,
|
||||
callAfterContentChecked:
|
||||
directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.AfterContentChecked) !== -1,
|
||||
callAfterViewInit:
|
||||
directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.AfterViewInit) !== -1,
|
||||
callAfterViewChecked:
|
||||
directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.AfterViewChecked) !== -1,
|
||||
callOnChanges: directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.OnChanges) !== -1,
|
||||
callDoCheck: directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.DoCheck) !== -1,
|
||||
callOnInit: directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.OnInit) !== -1,
|
||||
callOnDestroy: directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1,
|
||||
changeDetection: directiveMetadata.changeDetection,
|
||||
outputs: outputsArray
|
||||
});
|
||||
this.directiveRecords.push(directiveRecord);
|
||||
|
||||
templateVisitAll(this, ast.inputs, directiveRecord);
|
||||
var bindingRecords = this.bindingRecords;
|
||||
if (directiveRecord.callOnChanges) {
|
||||
bindingRecords.push(BindingRecord.createDirectiveOnChanges(directiveRecord));
|
||||
}
|
||||
if (directiveRecord.callOnInit) {
|
||||
bindingRecords.push(BindingRecord.createDirectiveOnInit(directiveRecord));
|
||||
}
|
||||
if (directiveRecord.callDoCheck) {
|
||||
bindingRecords.push(BindingRecord.createDirectiveDoCheck(directiveRecord));
|
||||
}
|
||||
templateVisitAll(this, ast.hostProperties, directiveRecord);
|
||||
templateVisitAll(this, ast.hostEvents, directiveRecord);
|
||||
templateVisitAll(this, ast.exportAsVars);
|
||||
return null;
|
||||
}
|
||||
visitDirectiveProperty(ast: BoundDirectivePropertyAst, directiveRecord: DirectiveRecord): any {
|
||||
// TODO: these setters should eventually be created by change detection, to make
|
||||
// it monomorphic!
|
||||
var setter = reflector.setter(ast.directiveName);
|
||||
this.bindingRecords.push(
|
||||
BindingRecord.createForDirective(ast.value, ast.directiveName, setter, directiveRecord));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function createChangeDefinitions(pvVisitors: ProtoViewVisitor[], componentType: CompileTypeMetadata,
|
||||
genConfig: ChangeDetectorGenConfig): ChangeDetectorDefinition[] {
|
||||
var pvVariableNames = _collectNestedProtoViewsVariableNames(pvVisitors);
|
||||
return pvVisitors.map(pvVisitor => {
|
||||
var id = `${componentType.name}_${pvVisitor.viewIndex}`;
|
||||
return new ChangeDetectorDefinition(
|
||||
id, pvVisitor.strategy, pvVariableNames[pvVisitor.viewIndex], pvVisitor.bindingRecords,
|
||||
pvVisitor.eventRecords, pvVisitor.directiveRecords, genConfig);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function _collectNestedProtoViewsVariableNames(pvVisitors: ProtoViewVisitor[]): string[][] {
|
||||
var nestedPvVariableNames: string[][] = ListWrapper.createFixedSize(pvVisitors.length);
|
||||
pvVisitors.forEach((pv) => {
|
||||
var parentVariableNames: string[] =
|
||||
isPresent(pv.parent) ? nestedPvVariableNames[pv.parent.viewIndex] : [];
|
||||
nestedPvVariableNames[pv.viewIndex] = parentVariableNames.concat(pv.variableNames);
|
||||
});
|
||||
return nestedPvVariableNames;
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
import {CompileTypeMetadata} from './directive_metadata';
|
||||
import {SourceExpressions, moduleRef} from './source_module';
|
||||
import {
|
||||
ChangeDetectorJITGenerator
|
||||
} from 'angular2/src/core/change_detection/change_detection_jit_generator';
|
||||
import {AbstractChangeDetector} from 'angular2/src/core/change_detection/abstract_change_detector';
|
||||
import {ChangeDetectionUtil} from 'angular2/src/core/change_detection/change_detection_util';
|
||||
import {ChangeDetectorState} from 'angular2/src/core/change_detection/constants';
|
||||
|
||||
import {createChangeDetectorDefinitions} from './change_definition_factory';
|
||||
import {IS_DART, isJsObject, CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
|
||||
import {
|
||||
ChangeDetectorGenConfig,
|
||||
ChangeDetectorDefinition,
|
||||
DynamicProtoChangeDetector,
|
||||
ChangeDetectionStrategy
|
||||
} from 'angular2/src/core/change_detection/change_detection';
|
||||
|
||||
import {TemplateAst} from './template_ast';
|
||||
import {Codegen} from 'angular2/src/transform/template_compiler/change_detector_codegen';
|
||||
import {MODULE_SUFFIX} from './util';
|
||||
import {Injectable} from 'angular2/src/core/di';
|
||||
|
||||
const ABSTRACT_CHANGE_DETECTOR = "AbstractChangeDetector";
|
||||
const UTIL = "ChangeDetectionUtil";
|
||||
const CHANGE_DETECTOR_STATE = "ChangeDetectorState";
|
||||
|
||||
export const CHANGE_DETECTION_JIT_IMPORTS = CONST_EXPR({
|
||||
'AbstractChangeDetector': AbstractChangeDetector,
|
||||
'ChangeDetectionUtil': ChangeDetectionUtil,
|
||||
'ChangeDetectorState': ChangeDetectorState
|
||||
});
|
||||
|
||||
var ABSTRACT_CHANGE_DETECTOR_MODULE = moduleRef(
|
||||
`package:angular2/src/core/change_detection/abstract_change_detector${MODULE_SUFFIX}`);
|
||||
var UTIL_MODULE =
|
||||
moduleRef(`package:angular2/src/core/change_detection/change_detection_util${MODULE_SUFFIX}`);
|
||||
var PREGEN_PROTO_CHANGE_DETECTOR_MODULE = moduleRef(
|
||||
`package:angular2/src/core/change_detection/pregen_proto_change_detector${MODULE_SUFFIX}`);
|
||||
var CONSTANTS_MODULE =
|
||||
moduleRef(`package:angular2/src/core/change_detection/constants${MODULE_SUFFIX}`);
|
||||
|
||||
@Injectable()
|
||||
export class ChangeDetectionCompiler {
|
||||
constructor(private _genConfig: ChangeDetectorGenConfig) {}
|
||||
|
||||
compileComponentRuntime(componentType: CompileTypeMetadata, strategy: ChangeDetectionStrategy,
|
||||
parsedTemplate: TemplateAst[]): Function[] {
|
||||
var changeDetectorDefinitions =
|
||||
createChangeDetectorDefinitions(componentType, strategy, this._genConfig, parsedTemplate);
|
||||
return changeDetectorDefinitions.map(definition =>
|
||||
this._createChangeDetectorFactory(definition));
|
||||
}
|
||||
|
||||
private _createChangeDetectorFactory(definition: ChangeDetectorDefinition): Function {
|
||||
var proto = new DynamicProtoChangeDetector(definition);
|
||||
return () => proto.instantiate();
|
||||
}
|
||||
|
||||
compileComponentCodeGen(componentType: CompileTypeMetadata, strategy: ChangeDetectionStrategy,
|
||||
parsedTemplate: TemplateAst[]): SourceExpressions {
|
||||
var changeDetectorDefinitions =
|
||||
createChangeDetectorDefinitions(componentType, strategy, this._genConfig, parsedTemplate);
|
||||
var factories = [];
|
||||
var index = 0;
|
||||
var sourceParts = changeDetectorDefinitions.map(definition => {
|
||||
var codegen: any;
|
||||
var sourcePart: string;
|
||||
// TODO(tbosch): move the 2 code generators to the same place, one with .dart and one with .ts
|
||||
// suffix
|
||||
// and have the same API for calling them!
|
||||
if (IS_DART) {
|
||||
codegen = new Codegen(PREGEN_PROTO_CHANGE_DETECTOR_MODULE);
|
||||
var className = `_${definition.id}`;
|
||||
var typeRef = (index === 0 && componentType.isHost) ?
|
||||
'dynamic' :
|
||||
`${moduleRef(componentType.moduleUrl)}${componentType.name}`;
|
||||
codegen.generate(typeRef, className, definition);
|
||||
factories.push(`${className}.newChangeDetector`);
|
||||
sourcePart = codegen.toString();
|
||||
} else {
|
||||
codegen = new ChangeDetectorJITGenerator(
|
||||
definition, `${UTIL_MODULE}${UTIL}`,
|
||||
`${ABSTRACT_CHANGE_DETECTOR_MODULE}${ABSTRACT_CHANGE_DETECTOR}`,
|
||||
`${CONSTANTS_MODULE}${CHANGE_DETECTOR_STATE}`);
|
||||
factories.push(`function() { return new ${codegen.typeName}(); }`);
|
||||
sourcePart = codegen.generateSource();
|
||||
}
|
||||
index++;
|
||||
return sourcePart;
|
||||
});
|
||||
return new SourceExpressions(sourceParts, factories);
|
||||
}
|
||||
}
|
@ -1,44 +1,45 @@
|
||||
import {
|
||||
isPresent,
|
||||
isBlank,
|
||||
isNumber,
|
||||
isBoolean,
|
||||
normalizeBool,
|
||||
normalizeBlank,
|
||||
serializeEnum,
|
||||
Type,
|
||||
isString,
|
||||
RegExpWrapper,
|
||||
StringWrapper
|
||||
StringWrapper,
|
||||
isArray
|
||||
} from 'angular2/src/facade/lang';
|
||||
import {unimplemented} from 'angular2/src/facade/exceptions';
|
||||
import {StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {unimplemented, BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {
|
||||
StringMapWrapper,
|
||||
MapWrapper,
|
||||
SetWrapper,
|
||||
ListWrapper
|
||||
} from 'angular2/src/facade/collection';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
CHANGE_DETECTION_STRATEGY_VALUES
|
||||
} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {ViewEncapsulation, VIEW_ENCAPSULATION_VALUES} from 'angular2/src/core/metadata/view';
|
||||
import {CssSelector} from 'angular2/src/compiler/selector';
|
||||
import {splitAtColon} from './util';
|
||||
import {LifecycleHooks, LIFECYCLE_HOOKS_VALUES} from 'angular2/src/core/linker/interfaces';
|
||||
import {splitAtColon, sanitizeIdentifier} from './util';
|
||||
import {LifecycleHooks, LIFECYCLE_HOOKS_VALUES} from 'angular2/src/core/metadata/lifecycle_hooks';
|
||||
import {getUrlScheme} from './url_resolver';
|
||||
|
||||
// group 1: "property" from "[property]"
|
||||
// group 2: "event" from "(event)"
|
||||
var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$/g;
|
||||
|
||||
export abstract class CompileMetadataWithIdentifier {
|
||||
static fromJson(data: {[key: string]: any}): CompileMetadataWithIdentifier {
|
||||
return _COMPILE_METADATA_FROM_JSON[data['class']](data);
|
||||
}
|
||||
|
||||
abstract toJson(): {[key: string]: any};
|
||||
|
||||
get identifier(): CompileIdentifierMetadata { return <CompileIdentifierMetadata>unimplemented(); }
|
||||
}
|
||||
|
||||
export abstract class CompileMetadataWithType extends CompileMetadataWithIdentifier {
|
||||
static fromJson(data: {[key: string]: any}): CompileMetadataWithType {
|
||||
return _COMPILE_METADATA_FROM_JSON[data['class']](data);
|
||||
}
|
||||
|
||||
abstract toJson(): {[key: string]: any};
|
||||
|
||||
get type(): CompileTypeMetadata { return <CompileTypeMetadata>unimplemented(); }
|
||||
@ -46,43 +47,43 @@ export abstract class CompileMetadataWithType extends CompileMetadataWithIdentif
|
||||
get identifier(): CompileIdentifierMetadata { return <CompileIdentifierMetadata>unimplemented(); }
|
||||
}
|
||||
|
||||
export function metadataFromJson(data: {[key: string]: any}): any {
|
||||
return _COMPILE_METADATA_FROM_JSON[data['class']](data);
|
||||
}
|
||||
|
||||
export class CompileIdentifierMetadata implements CompileMetadataWithIdentifier {
|
||||
runtime: any;
|
||||
name: string;
|
||||
prefix: string;
|
||||
moduleUrl: string;
|
||||
constConstructor: boolean;
|
||||
constructor({runtime, name, moduleUrl, prefix, constConstructor}: {
|
||||
runtime?: any,
|
||||
name?: string,
|
||||
moduleUrl?: string,
|
||||
prefix?: string,
|
||||
constConstructor?: boolean
|
||||
} = {}) {
|
||||
value: any;
|
||||
|
||||
constructor(
|
||||
{runtime, name, moduleUrl, prefix, value}:
|
||||
{runtime?: any, name?: string, moduleUrl?: string, prefix?: string, value?: any} = {}) {
|
||||
this.runtime = runtime;
|
||||
this.name = name;
|
||||
this.prefix = prefix;
|
||||
this.moduleUrl = moduleUrl;
|
||||
this.constConstructor = constConstructor;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
static fromJson(data: {[key: string]: any}): CompileIdentifierMetadata {
|
||||
return new CompileIdentifierMetadata({
|
||||
name: data['name'],
|
||||
prefix: data['prefix'],
|
||||
moduleUrl: data['moduleUrl'],
|
||||
constConstructor: data['constConstructor']
|
||||
});
|
||||
let value = isArray(data['value']) ? _arrayFromJson(data['value'], metadataFromJson) :
|
||||
_objFromJson(data['value'], metadataFromJson);
|
||||
return new CompileIdentifierMetadata(
|
||||
{name: data['name'], prefix: data['prefix'], moduleUrl: data['moduleUrl'], value: value});
|
||||
}
|
||||
|
||||
toJson(): {[key: string]: any} {
|
||||
let value = isArray(this.value) ? _arrayToJson(this.value) : _objToJson(this.value);
|
||||
return {
|
||||
// Note: Runtime type can't be serialized...
|
||||
'class': 'Identifier',
|
||||
'name': this.name,
|
||||
'moduleUrl': this.moduleUrl,
|
||||
'prefix': this.prefix,
|
||||
'constConstructor': this.constConstructor
|
||||
'value': value
|
||||
};
|
||||
}
|
||||
|
||||
@ -95,72 +96,82 @@ export class CompileDiDependencyMetadata {
|
||||
isHost: boolean;
|
||||
isSkipSelf: boolean;
|
||||
isOptional: boolean;
|
||||
isValue: boolean;
|
||||
query: CompileQueryMetadata;
|
||||
viewQuery: CompileQueryMetadata;
|
||||
token: CompileIdentifierMetadata | string;
|
||||
token: CompileTokenMetadata;
|
||||
value: any;
|
||||
|
||||
constructor({isAttribute, isSelf, isHost, isSkipSelf, isOptional, query, viewQuery, token}: {
|
||||
constructor({isAttribute, isSelf, isHost, isSkipSelf, isOptional, isValue, query, viewQuery,
|
||||
token, value}: {
|
||||
isAttribute?: boolean,
|
||||
isSelf?: boolean,
|
||||
isHost?: boolean,
|
||||
isSkipSelf?: boolean,
|
||||
isOptional?: boolean,
|
||||
isValue?: boolean,
|
||||
query?: CompileQueryMetadata,
|
||||
viewQuery?: CompileQueryMetadata,
|
||||
token?: CompileIdentifierMetadata | string
|
||||
token?: CompileTokenMetadata,
|
||||
value?: any
|
||||
} = {}) {
|
||||
this.isAttribute = normalizeBool(isAttribute);
|
||||
this.isSelf = normalizeBool(isSelf);
|
||||
this.isHost = normalizeBool(isHost);
|
||||
this.isSkipSelf = normalizeBool(isSkipSelf);
|
||||
this.isOptional = normalizeBool(isOptional);
|
||||
this.isValue = normalizeBool(isValue);
|
||||
this.query = query;
|
||||
this.viewQuery = viewQuery;
|
||||
this.token = token;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
static fromJson(data: {[key: string]: any}): CompileDiDependencyMetadata {
|
||||
return new CompileDiDependencyMetadata({
|
||||
token: objFromJson(data['token'], CompileIdentifierMetadata.fromJson),
|
||||
query: objFromJson(data['query'], CompileQueryMetadata.fromJson),
|
||||
viewQuery: objFromJson(data['viewQuery'], CompileQueryMetadata.fromJson),
|
||||
token: _objFromJson(data['token'], CompileTokenMetadata.fromJson),
|
||||
query: _objFromJson(data['query'], CompileQueryMetadata.fromJson),
|
||||
viewQuery: _objFromJson(data['viewQuery'], CompileQueryMetadata.fromJson),
|
||||
value: data['value'],
|
||||
isAttribute: data['isAttribute'],
|
||||
isSelf: data['isSelf'],
|
||||
isHost: data['isHost'],
|
||||
isSkipSelf: data['isSkipSelf'],
|
||||
isOptional: data['isOptional']
|
||||
isOptional: data['isOptional'],
|
||||
isValue: data['isValue']
|
||||
});
|
||||
}
|
||||
|
||||
toJson(): {[key: string]: any} {
|
||||
return {
|
||||
// Note: Runtime type can't be serialized...
|
||||
'token': objToJson(this.token),
|
||||
'query': objToJson(this.query),
|
||||
'viewQuery': objToJson(this.viewQuery),
|
||||
'token': _objToJson(this.token),
|
||||
'query': _objToJson(this.query),
|
||||
'viewQuery': _objToJson(this.viewQuery),
|
||||
'value': this.value,
|
||||
'isAttribute': this.isAttribute,
|
||||
'isSelf': this.isSelf,
|
||||
'isHost': this.isHost,
|
||||
'isSkipSelf': this.isSkipSelf,
|
||||
'isOptional': this.isOptional
|
||||
'isOptional': this.isOptional,
|
||||
'isValue': this.isValue
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class CompileProviderMetadata {
|
||||
token: CompileIdentifierMetadata | string;
|
||||
token: CompileTokenMetadata;
|
||||
useClass: CompileTypeMetadata;
|
||||
useValue: any;
|
||||
useExisting: CompileIdentifierMetadata | string;
|
||||
useExisting: CompileTokenMetadata;
|
||||
useFactory: CompileFactoryMetadata;
|
||||
deps: CompileDiDependencyMetadata[];
|
||||
multi: boolean;
|
||||
|
||||
constructor({token, useClass, useValue, useExisting, useFactory, deps, multi}: {
|
||||
token?: CompileIdentifierMetadata | string,
|
||||
token?: CompileTokenMetadata,
|
||||
useClass?: CompileTypeMetadata,
|
||||
useValue?: any,
|
||||
useExisting?: CompileIdentifierMetadata | string,
|
||||
useExisting?: CompileTokenMetadata,
|
||||
useFactory?: CompileFactoryMetadata,
|
||||
deps?: CompileDiDependencyMetadata[],
|
||||
multi?: boolean
|
||||
@ -170,51 +181,181 @@ export class CompileProviderMetadata {
|
||||
this.useValue = useValue;
|
||||
this.useExisting = useExisting;
|
||||
this.useFactory = useFactory;
|
||||
this.deps = deps;
|
||||
this.multi = multi;
|
||||
this.deps = normalizeBlank(deps);
|
||||
this.multi = normalizeBool(multi);
|
||||
}
|
||||
|
||||
static fromJson(data: {[key: string]: any}): CompileProviderMetadata {
|
||||
return new CompileProviderMetadata({
|
||||
token: objFromJson(data['token'], CompileIdentifierMetadata.fromJson),
|
||||
useClass: objFromJson(data['useClass'], CompileTypeMetadata.fromJson)
|
||||
token: _objFromJson(data['token'], CompileTokenMetadata.fromJson),
|
||||
useClass: _objFromJson(data['useClass'], CompileTypeMetadata.fromJson),
|
||||
useExisting: _objFromJson(data['useExisting'], CompileTokenMetadata.fromJson),
|
||||
useValue: _objFromJson(data['useValue'], CompileIdentifierMetadata.fromJson),
|
||||
useFactory: _objFromJson(data['useFactory'], CompileFactoryMetadata.fromJson),
|
||||
multi: data['multi'],
|
||||
deps: _arrayFromJson(data['deps'], CompileDiDependencyMetadata.fromJson)
|
||||
});
|
||||
}
|
||||
|
||||
toJson(): {[key: string]: any} {
|
||||
return {
|
||||
// Note: Runtime type can't be serialized...
|
||||
'token': objToJson(this.token),
|
||||
'useClass': objToJson(this.useClass)
|
||||
'class': 'Provider',
|
||||
'token': _objToJson(this.token),
|
||||
'useClass': _objToJson(this.useClass),
|
||||
'useExisting': _objToJson(this.useExisting),
|
||||
'useValue': _objToJson(this.useValue),
|
||||
'useFactory': _objToJson(this.useFactory),
|
||||
'multi': this.multi,
|
||||
'deps': _arrayToJson(this.deps)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class CompileFactoryMetadata implements CompileIdentifierMetadata {
|
||||
export class CompileFactoryMetadata implements CompileIdentifierMetadata,
|
||||
CompileMetadataWithIdentifier {
|
||||
runtime: Function;
|
||||
name: string;
|
||||
prefix: string;
|
||||
moduleUrl: string;
|
||||
constConstructor: boolean;
|
||||
value: any;
|
||||
diDeps: CompileDiDependencyMetadata[];
|
||||
|
||||
constructor({runtime, name, moduleUrl, constConstructor, diDeps}: {
|
||||
constructor({runtime, name, moduleUrl, prefix, diDeps, value}: {
|
||||
runtime?: Function,
|
||||
name?: string,
|
||||
prefix?: string,
|
||||
moduleUrl?: string,
|
||||
constConstructor?: boolean,
|
||||
value?: boolean,
|
||||
diDeps?: CompileDiDependencyMetadata[]
|
||||
}) {
|
||||
this.runtime = runtime;
|
||||
this.name = name;
|
||||
this.prefix = prefix;
|
||||
this.moduleUrl = moduleUrl;
|
||||
this.diDeps = diDeps;
|
||||
this.constConstructor = constConstructor;
|
||||
this.diDeps = _normalizeArray(diDeps);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
get identifier(): CompileIdentifierMetadata { return this; }
|
||||
|
||||
toJson() { return null; }
|
||||
static fromJson(data: {[key: string]: any}): CompileFactoryMetadata {
|
||||
return new CompileFactoryMetadata({
|
||||
name: data['name'],
|
||||
prefix: data['prefix'],
|
||||
moduleUrl: data['moduleUrl'],
|
||||
value: data['value'],
|
||||
diDeps: _arrayFromJson(data['diDeps'], CompileDiDependencyMetadata.fromJson)
|
||||
});
|
||||
}
|
||||
|
||||
toJson(): {[key: string]: any} {
|
||||
return {
|
||||
'class': 'Factory',
|
||||
'name': this.name,
|
||||
'prefix': this.prefix,
|
||||
'moduleUrl': this.moduleUrl,
|
||||
'value': this.value,
|
||||
'diDeps': _arrayToJson(this.diDeps)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class CompileTokenMetadata implements CompileMetadataWithIdentifier {
|
||||
value: any;
|
||||
identifier: CompileIdentifierMetadata;
|
||||
identifierIsInstance: boolean;
|
||||
|
||||
constructor({value, identifier, identifierIsInstance}: {
|
||||
value?: any,
|
||||
identifier?: CompileIdentifierMetadata,
|
||||
identifierIsInstance?: boolean
|
||||
}) {
|
||||
this.value = value;
|
||||
this.identifier = identifier;
|
||||
this.identifierIsInstance = normalizeBool(identifierIsInstance);
|
||||
}
|
||||
|
||||
static fromJson(data: {[key: string]: any}): CompileTokenMetadata {
|
||||
return new CompileTokenMetadata({
|
||||
value: data['value'],
|
||||
identifier: _objFromJson(data['identifier'], CompileIdentifierMetadata.fromJson),
|
||||
identifierIsInstance: data['identifierIsInstance']
|
||||
});
|
||||
}
|
||||
|
||||
toJson(): {[key: string]: any} {
|
||||
return {
|
||||
'value': this.value,
|
||||
'identifier': _objToJson(this.identifier),
|
||||
'identifierIsInstance': this.identifierIsInstance
|
||||
};
|
||||
}
|
||||
|
||||
get runtimeCacheKey(): any {
|
||||
if (isPresent(this.identifier)) {
|
||||
return this.identifier.runtime;
|
||||
} else {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
get assetCacheKey(): any {
|
||||
if (isPresent(this.identifier)) {
|
||||
return isPresent(this.identifier.moduleUrl) &&
|
||||
isPresent(getUrlScheme(this.identifier.moduleUrl)) ?
|
||||
`${this.identifier.name}|${this.identifier.moduleUrl}|${this.identifierIsInstance}` :
|
||||
null;
|
||||
} else {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
equalsTo(token2: CompileTokenMetadata): boolean {
|
||||
var rk = this.runtimeCacheKey;
|
||||
var ak = this.assetCacheKey;
|
||||
return (isPresent(rk) && rk == token2.runtimeCacheKey) ||
|
||||
(isPresent(ak) && ak == token2.assetCacheKey);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return isPresent(this.value) ? sanitizeIdentifier(this.value) : this.identifier.name;
|
||||
}
|
||||
}
|
||||
|
||||
export class CompileTokenMap<VALUE> {
|
||||
private _valueMap = new Map<any, VALUE>();
|
||||
private _values: VALUE[] = [];
|
||||
|
||||
add(token: CompileTokenMetadata, value: VALUE) {
|
||||
var existing = this.get(token);
|
||||
if (isPresent(existing)) {
|
||||
throw new BaseException(`Can only add to a TokenMap! Token: ${token.name}`);
|
||||
}
|
||||
this._values.push(value);
|
||||
var rk = token.runtimeCacheKey;
|
||||
if (isPresent(rk)) {
|
||||
this._valueMap.set(rk, value);
|
||||
}
|
||||
var ak = token.assetCacheKey;
|
||||
if (isPresent(ak)) {
|
||||
this._valueMap.set(ak, value);
|
||||
}
|
||||
}
|
||||
get(token: CompileTokenMetadata): VALUE {
|
||||
var rk = token.runtimeCacheKey;
|
||||
var ak = token.assetCacheKey;
|
||||
var result;
|
||||
if (isPresent(rk)) {
|
||||
result = this._valueMap.get(rk);
|
||||
}
|
||||
if (isBlank(result) && isPresent(ak)) {
|
||||
result = this._valueMap.get(ak);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
values(): VALUE[] { return this._values; }
|
||||
get size(): number { return this._values.length; }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,16 +367,16 @@ export class CompileTypeMetadata implements CompileIdentifierMetadata, CompileMe
|
||||
prefix: string;
|
||||
moduleUrl: string;
|
||||
isHost: boolean;
|
||||
constConstructor: boolean;
|
||||
value: any;
|
||||
diDeps: CompileDiDependencyMetadata[];
|
||||
|
||||
constructor({runtime, name, moduleUrl, prefix, isHost, constConstructor, diDeps}: {
|
||||
constructor({runtime, name, moduleUrl, prefix, isHost, value, diDeps}: {
|
||||
runtime?: Type,
|
||||
name?: string,
|
||||
moduleUrl?: string,
|
||||
prefix?: string,
|
||||
isHost?: boolean,
|
||||
constConstructor?: boolean,
|
||||
value?: any,
|
||||
diDeps?: CompileDiDependencyMetadata[]
|
||||
} = {}) {
|
||||
this.runtime = runtime;
|
||||
@ -243,8 +384,8 @@ export class CompileTypeMetadata implements CompileIdentifierMetadata, CompileMe
|
||||
this.moduleUrl = moduleUrl;
|
||||
this.prefix = prefix;
|
||||
this.isHost = normalizeBool(isHost);
|
||||
this.constConstructor = constConstructor;
|
||||
this.diDeps = normalizeBlank(diDeps);
|
||||
this.value = value;
|
||||
this.diDeps = _normalizeArray(diDeps);
|
||||
}
|
||||
|
||||
static fromJson(data: {[key: string]: any}): CompileTypeMetadata {
|
||||
@ -253,8 +394,8 @@ export class CompileTypeMetadata implements CompileIdentifierMetadata, CompileMe
|
||||
moduleUrl: data['moduleUrl'],
|
||||
prefix: data['prefix'],
|
||||
isHost: data['isHost'],
|
||||
constConstructor: data['constConstructor'],
|
||||
diDeps: arrayFromJson(data['diDeps'], CompileDiDependencyMetadata.fromJson)
|
||||
value: data['value'],
|
||||
diDeps: _arrayFromJson(data['diDeps'], CompileDiDependencyMetadata.fromJson)
|
||||
});
|
||||
}
|
||||
|
||||
@ -269,46 +410,50 @@ export class CompileTypeMetadata implements CompileIdentifierMetadata, CompileMe
|
||||
'moduleUrl': this.moduleUrl,
|
||||
'prefix': this.prefix,
|
||||
'isHost': this.isHost,
|
||||
'constConstructor': this.constConstructor,
|
||||
'diDeps': arrayToJson(this.diDeps)
|
||||
'value': this.value,
|
||||
'diDeps': _arrayToJson(this.diDeps)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class CompileQueryMetadata {
|
||||
selectors: Array<CompileIdentifierMetadata | string>;
|
||||
selectors: Array<CompileTokenMetadata>;
|
||||
descendants: boolean;
|
||||
first: boolean;
|
||||
propertyName: string;
|
||||
read: CompileTokenMetadata;
|
||||
|
||||
constructor({selectors, descendants, first, propertyName}: {
|
||||
selectors?: Array<CompileIdentifierMetadata | string>,
|
||||
constructor({selectors, descendants, first, propertyName, read}: {
|
||||
selectors?: Array<CompileTokenMetadata>,
|
||||
descendants?: boolean,
|
||||
first?: boolean,
|
||||
propertyName?: string
|
||||
propertyName?: string,
|
||||
read?: CompileTokenMetadata
|
||||
} = {}) {
|
||||
this.selectors = selectors;
|
||||
this.descendants = descendants;
|
||||
this.descendants = normalizeBool(descendants);
|
||||
this.first = normalizeBool(first);
|
||||
this.propertyName = propertyName;
|
||||
this.read = read;
|
||||
}
|
||||
|
||||
static fromJson(data: {[key: string]: any}): CompileQueryMetadata {
|
||||
return new CompileQueryMetadata({
|
||||
selectors: arrayFromJson(data['selectors'], CompileIdentifierMetadata.fromJson),
|
||||
selectors: _arrayFromJson(data['selectors'], CompileTokenMetadata.fromJson),
|
||||
descendants: data['descendants'],
|
||||
first: data['first'],
|
||||
propertyName: data['propertyName']
|
||||
propertyName: data['propertyName'],
|
||||
read: _objFromJson(data['read'], CompileTokenMetadata.fromJson)
|
||||
});
|
||||
}
|
||||
|
||||
toJson(): {[key: string]: any} {
|
||||
return {
|
||||
// Note: Runtime type can't be serialized...
|
||||
'selectors': arrayToJson(this.selectors),
|
||||
'selectors': _arrayToJson(this.selectors),
|
||||
'descendants': this.descendants,
|
||||
'first': this.first,
|
||||
'propertyName': this.propertyName
|
||||
'propertyName': this.propertyName,
|
||||
'read': _objToJson(this.read)
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -369,12 +514,10 @@ export class CompileTemplateMetadata {
|
||||
* Metadata regarding compilation of a directive.
|
||||
*/
|
||||
export class CompileDirectiveMetadata implements CompileMetadataWithType {
|
||||
static create({type, isComponent, dynamicLoadable, selector, exportAs, changeDetection, inputs,
|
||||
outputs, host, lifecycleHooks, providers, viewProviders, queries, viewQueries,
|
||||
template}: {
|
||||
static create({type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host,
|
||||
lifecycleHooks, providers, viewProviders, queries, viewQueries, template}: {
|
||||
type?: CompileTypeMetadata,
|
||||
isComponent?: boolean,
|
||||
dynamicLoadable?: boolean,
|
||||
selector?: string,
|
||||
exportAs?: string,
|
||||
changeDetection?: ChangeDetectionStrategy,
|
||||
@ -382,8 +525,10 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
|
||||
outputs?: string[],
|
||||
host?: {[key: string]: string},
|
||||
lifecycleHooks?: LifecycleHooks[],
|
||||
providers?: Array<CompileProviderMetadata | CompileTypeMetadata | any[]>,
|
||||
viewProviders?: Array<CompileProviderMetadata | CompileTypeMetadata | any[]>,
|
||||
providers?:
|
||||
Array<CompileProviderMetadata | CompileTypeMetadata | CompileIdentifierMetadata | any[]>,
|
||||
viewProviders?:
|
||||
Array<CompileProviderMetadata | CompileTypeMetadata | CompileIdentifierMetadata | any[]>,
|
||||
queries?: CompileQueryMetadata[],
|
||||
viewQueries?: CompileQueryMetadata[],
|
||||
template?: CompileTemplateMetadata
|
||||
@ -425,7 +570,6 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
|
||||
return new CompileDirectiveMetadata({
|
||||
type: type,
|
||||
isComponent: normalizeBool(isComponent),
|
||||
dynamicLoadable: normalizeBool(dynamicLoadable),
|
||||
selector: selector,
|
||||
exportAs: exportAs,
|
||||
changeDetection: changeDetection,
|
||||
@ -444,7 +588,6 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
|
||||
}
|
||||
type: CompileTypeMetadata;
|
||||
isComponent: boolean;
|
||||
dynamicLoadable: boolean;
|
||||
selector: string;
|
||||
exportAs: string;
|
||||
changeDetection: ChangeDetectionStrategy;
|
||||
@ -454,17 +597,17 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
|
||||
hostProperties: {[key: string]: string};
|
||||
hostAttributes: {[key: string]: string};
|
||||
lifecycleHooks: LifecycleHooks[];
|
||||
providers: Array<CompileProviderMetadata | CompileTypeMetadata | any[]>;
|
||||
viewProviders: Array<CompileProviderMetadata | CompileTypeMetadata | any[]>;
|
||||
providers: CompileProviderMetadata[];
|
||||
viewProviders: CompileProviderMetadata[];
|
||||
queries: CompileQueryMetadata[];
|
||||
viewQueries: CompileQueryMetadata[];
|
||||
|
||||
template: CompileTemplateMetadata;
|
||||
constructor({type, isComponent, dynamicLoadable, selector, exportAs, changeDetection, inputs,
|
||||
outputs, hostListeners, hostProperties, hostAttributes, lifecycleHooks, providers,
|
||||
constructor({type, isComponent, selector, exportAs, changeDetection, inputs, outputs,
|
||||
hostListeners, hostProperties, hostAttributes, lifecycleHooks, providers,
|
||||
viewProviders, queries, viewQueries, template}: {
|
||||
type?: CompileTypeMetadata,
|
||||
isComponent?: boolean,
|
||||
dynamicLoadable?: boolean,
|
||||
selector?: string,
|
||||
exportAs?: string,
|
||||
changeDetection?: ChangeDetectionStrategy,
|
||||
@ -474,15 +617,16 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
|
||||
hostProperties?: {[key: string]: string},
|
||||
hostAttributes?: {[key: string]: string},
|
||||
lifecycleHooks?: LifecycleHooks[],
|
||||
providers?: Array<CompileProviderMetadata | CompileTypeMetadata | any[]>,
|
||||
viewProviders?: Array<CompileProviderMetadata | CompileTypeMetadata | any[]>,
|
||||
providers?:
|
||||
Array<CompileProviderMetadata | CompileTypeMetadata | CompileIdentifierMetadata | any[]>,
|
||||
viewProviders?:
|
||||
Array<CompileProviderMetadata | CompileTypeMetadata | CompileIdentifierMetadata | any[]>,
|
||||
queries?: CompileQueryMetadata[],
|
||||
viewQueries?: CompileQueryMetadata[],
|
||||
template?: CompileTemplateMetadata
|
||||
} = {}) {
|
||||
this.type = type;
|
||||
this.isComponent = isComponent;
|
||||
this.dynamicLoadable = dynamicLoadable;
|
||||
this.selector = selector;
|
||||
this.exportAs = exportAs;
|
||||
this.changeDetection = changeDetection;
|
||||
@ -491,11 +635,11 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
|
||||
this.hostListeners = hostListeners;
|
||||
this.hostProperties = hostProperties;
|
||||
this.hostAttributes = hostAttributes;
|
||||
this.lifecycleHooks = lifecycleHooks;
|
||||
this.providers = normalizeBlank(providers);
|
||||
this.viewProviders = normalizeBlank(viewProviders);
|
||||
this.queries = queries;
|
||||
this.viewQueries = viewQueries;
|
||||
this.lifecycleHooks = _normalizeArray(lifecycleHooks);
|
||||
this.providers = _normalizeArray(providers);
|
||||
this.viewProviders = _normalizeArray(viewProviders);
|
||||
this.queries = _normalizeArray(queries);
|
||||
this.viewQueries = _normalizeArray(viewQueries);
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
@ -504,7 +648,6 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
|
||||
static fromJson(data: {[key: string]: any}): CompileDirectiveMetadata {
|
||||
return new CompileDirectiveMetadata({
|
||||
isComponent: data['isComponent'],
|
||||
dynamicLoadable: data['dynamicLoadable'],
|
||||
selector: data['selector'],
|
||||
exportAs: data['exportAs'],
|
||||
type: isPresent(data['type']) ? CompileTypeMetadata.fromJson(data['type']) : data['type'],
|
||||
@ -520,7 +663,10 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
|
||||
(<any[]>data['lifecycleHooks']).map(hookValue => LIFECYCLE_HOOKS_VALUES[hookValue]),
|
||||
template: isPresent(data['template']) ? CompileTemplateMetadata.fromJson(data['template']) :
|
||||
data['template'],
|
||||
providers: arrayFromJson(data['providers'], CompileProviderMetadata.fromJson)
|
||||
providers: _arrayFromJson(data['providers'], metadataFromJson),
|
||||
viewProviders: _arrayFromJson(data['viewProviders'], metadataFromJson),
|
||||
queries: _arrayFromJson(data['queries'], CompileQueryMetadata.fromJson),
|
||||
viewQueries: _arrayFromJson(data['viewQueries'], CompileQueryMetadata.fromJson)
|
||||
});
|
||||
}
|
||||
|
||||
@ -528,7 +674,6 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
|
||||
return {
|
||||
'class': 'Directive',
|
||||
'isComponent': this.isComponent,
|
||||
'dynamicLoadable': this.dynamicLoadable,
|
||||
'selector': this.selector,
|
||||
'exportAs': this.exportAs,
|
||||
'type': isPresent(this.type) ? this.type.toJson() : this.type,
|
||||
@ -541,7 +686,10 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
|
||||
'hostAttributes': this.hostAttributes,
|
||||
'lifecycleHooks': this.lifecycleHooks.map(hook => serializeEnum(hook)),
|
||||
'template': isPresent(this.template) ? this.template.toJson() : this.template,
|
||||
'providers': arrayToJson(this.providers)
|
||||
'providers': _arrayToJson(this.providers),
|
||||
'viewProviders': _arrayToJson(this.viewProviders),
|
||||
'queries': _arrayToJson(this.queries),
|
||||
'viewQueries': _arrayToJson(this.viewQueries)
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -555,7 +703,7 @@ export function createHostComponentMeta(componentType: CompileTypeMetadata,
|
||||
return CompileDirectiveMetadata.create({
|
||||
type: new CompileTypeMetadata({
|
||||
runtime: Object,
|
||||
name: `Host${componentType.name}`,
|
||||
name: `${componentType.name}_Host`,
|
||||
moduleUrl: componentType.moduleUrl,
|
||||
isHost: true
|
||||
}),
|
||||
@ -567,7 +715,6 @@ export function createHostComponentMeta(componentType: CompileTypeMetadata,
|
||||
host: {},
|
||||
lifecycleHooks: [],
|
||||
isComponent: true,
|
||||
dynamicLoadable: false,
|
||||
selector: '*',
|
||||
providers: [],
|
||||
viewProviders: [],
|
||||
@ -581,11 +728,18 @@ export class CompilePipeMetadata implements CompileMetadataWithType {
|
||||
type: CompileTypeMetadata;
|
||||
name: string;
|
||||
pure: boolean;
|
||||
constructor({type, name,
|
||||
pure}: {type?: CompileTypeMetadata, name?: string, pure?: boolean} = {}) {
|
||||
lifecycleHooks: LifecycleHooks[];
|
||||
|
||||
constructor({type, name, pure, lifecycleHooks}: {
|
||||
type?: CompileTypeMetadata,
|
||||
name?: string,
|
||||
pure?: boolean,
|
||||
lifecycleHooks?: LifecycleHooks[]
|
||||
} = {}) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.pure = normalizeBool(pure);
|
||||
this.lifecycleHooks = _normalizeArray(lifecycleHooks);
|
||||
}
|
||||
get identifier(): CompileIdentifierMetadata { return this.type; }
|
||||
|
||||
@ -611,21 +765,31 @@ var _COMPILE_METADATA_FROM_JSON = {
|
||||
'Directive': CompileDirectiveMetadata.fromJson,
|
||||
'Pipe': CompilePipeMetadata.fromJson,
|
||||
'Type': CompileTypeMetadata.fromJson,
|
||||
'Identifier': CompileIdentifierMetadata.fromJson
|
||||
'Provider': CompileProviderMetadata.fromJson,
|
||||
'Identifier': CompileIdentifierMetadata.fromJson,
|
||||
'Factory': CompileFactoryMetadata.fromJson
|
||||
};
|
||||
|
||||
function arrayFromJson(obj: any[], fn: (a: {[key: string]: any}) => any): any {
|
||||
return isBlank(obj) ? null : obj.map(o => objFromJson(o, fn));
|
||||
function _arrayFromJson(obj: any[], fn: (a: {[key: string]: any}) => any): any {
|
||||
return isBlank(obj) ? null : obj.map(o => _objFromJson(o, fn));
|
||||
}
|
||||
|
||||
function arrayToJson(obj: any[]): string | {[key: string]: any} {
|
||||
return isBlank(obj) ? null : obj.map(objToJson);
|
||||
function _arrayToJson(obj: any[]): string | {[key: string]: any} {
|
||||
return isBlank(obj) ? null : obj.map(_objToJson);
|
||||
}
|
||||
|
||||
function objFromJson(obj: any, fn: (a: {[key: string]: any}) => any): any {
|
||||
return (isString(obj) || isBlank(obj)) ? obj : fn(obj);
|
||||
function _objFromJson(obj: any, fn: (a: {[key: string]: any}) => any): any {
|
||||
if (isArray(obj)) return _arrayFromJson(obj, fn);
|
||||
if (isString(obj) || isBlank(obj) || isBoolean(obj) || isNumber(obj)) return obj;
|
||||
return fn(obj);
|
||||
}
|
||||
|
||||
function objToJson(obj: any): string | {[key: string]: any} {
|
||||
return (isString(obj) || isBlank(obj)) ? obj : obj.toJson();
|
||||
function _objToJson(obj: any): string | {[key: string]: any} {
|
||||
if (isArray(obj)) return _arrayToJson(obj);
|
||||
if (isString(obj) || isBlank(obj) || isBoolean(obj) || isNumber(obj)) return obj;
|
||||
return obj.toJson();
|
||||
}
|
||||
|
||||
function _normalizeArray(obj: any[]): any[] {
|
||||
return isPresent(obj) ? obj : [];
|
||||
}
|
@ -1,35 +1,39 @@
|
||||
import {RuntimeCompiler_} from "./runtime_compiler";
|
||||
export {TemplateCompiler} from './template_compiler';
|
||||
export {
|
||||
CompileDirectiveMetadata,
|
||||
CompileTypeMetadata,
|
||||
CompileTemplateMetadata
|
||||
} from './directive_metadata';
|
||||
export {SourceModule, SourceWithImports} from './source_module';
|
||||
export {PLATFORM_DIRECTIVES, PLATFORM_PIPES} from 'angular2/src/core/platform_directives_and_pipes';
|
||||
export * from 'angular2/src/compiler/template_ast';
|
||||
export {TEMPLATE_TRANSFORMS} from 'angular2/src/compiler/template_parser';
|
||||
export {CompilerConfig, RenderTypes} from './config';
|
||||
export * from './compile_metadata';
|
||||
export * from './offline_compiler';
|
||||
export {RuntimeCompiler} from './runtime_compiler';
|
||||
export * from 'angular2/src/compiler/url_resolver';
|
||||
export * from 'angular2/src/compiler/xhr';
|
||||
|
||||
export {ViewResolver} from './view_resolver';
|
||||
export {DirectiveResolver} from './directive_resolver';
|
||||
export {PipeResolver} from './pipe_resolver';
|
||||
|
||||
import {assertionsEnabled, Type, CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
import {provide, Provider} from 'angular2/src/core/di';
|
||||
import {TemplateParser} from 'angular2/src/compiler/template_parser';
|
||||
import {HtmlParser} from 'angular2/src/compiler/html_parser';
|
||||
import {TemplateNormalizer} from 'angular2/src/compiler/template_normalizer';
|
||||
import {DirectiveNormalizer} from 'angular2/src/compiler/directive_normalizer';
|
||||
import {RuntimeMetadataResolver} from 'angular2/src/compiler/runtime_metadata';
|
||||
import {ChangeDetectionCompiler} from 'angular2/src/compiler/change_detector_compiler';
|
||||
import {StyleCompiler} from 'angular2/src/compiler/style_compiler';
|
||||
import {ViewCompiler} from 'angular2/src/compiler/view_compiler';
|
||||
import {ProtoViewCompiler} from 'angular2/src/compiler/proto_view_compiler';
|
||||
import {TemplateCompiler} from 'angular2/src/compiler/template_compiler';
|
||||
import {ChangeDetectorGenConfig} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {Compiler} from 'angular2/src/core/linker/compiler';
|
||||
import {ViewCompiler} from 'angular2/src/compiler/view_compiler/view_compiler';
|
||||
import {CompilerConfig} from './config';
|
||||
import {ComponentResolver} from 'angular2/src/core/linker/component_resolver';
|
||||
import {RuntimeCompiler} from 'angular2/src/compiler/runtime_compiler';
|
||||
import {ElementSchemaRegistry} from 'angular2/src/compiler/schema/element_schema_registry';
|
||||
import {DomElementSchemaRegistry} from 'angular2/src/compiler/schema/dom_element_schema_registry';
|
||||
import {UrlResolver, DEFAULT_PACKAGE_URL_PROVIDER} from 'angular2/src/compiler/url_resolver';
|
||||
import {Parser, Lexer} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {Parser} from './expression_parser/parser';
|
||||
import {Lexer} from './expression_parser/lexer';
|
||||
import {ViewResolver} from './view_resolver';
|
||||
import {DirectiveResolver} from './directive_resolver';
|
||||
import {PipeResolver} from './pipe_resolver';
|
||||
|
||||
function _createChangeDetectorGenConfig() {
|
||||
return new ChangeDetectorGenConfig(assertionsEnabled(), false, true);
|
||||
function _createCompilerConfig() {
|
||||
return new CompilerConfig(assertionsEnabled(), false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -41,18 +45,18 @@ export const COMPILER_PROVIDERS: Array<Type | Provider | any[]> = CONST_EXPR([
|
||||
Parser,
|
||||
HtmlParser,
|
||||
TemplateParser,
|
||||
TemplateNormalizer,
|
||||
DirectiveNormalizer,
|
||||
RuntimeMetadataResolver,
|
||||
DEFAULT_PACKAGE_URL_PROVIDER,
|
||||
StyleCompiler,
|
||||
ProtoViewCompiler,
|
||||
ViewCompiler,
|
||||
ChangeDetectionCompiler,
|
||||
new Provider(ChangeDetectorGenConfig, {useFactory: _createChangeDetectorGenConfig, deps: []}),
|
||||
TemplateCompiler,
|
||||
new Provider(RuntimeCompiler, {useClass: RuntimeCompiler_}),
|
||||
new Provider(Compiler, {useExisting: RuntimeCompiler}),
|
||||
new Provider(CompilerConfig, {useFactory: _createCompilerConfig, deps: []}),
|
||||
RuntimeCompiler,
|
||||
new Provider(ComponentResolver, {useExisting: RuntimeCompiler}),
|
||||
DomElementSchemaRegistry,
|
||||
new Provider(ElementSchemaRegistry, {useExisting: DomElementSchemaRegistry}),
|
||||
UrlResolver
|
||||
UrlResolver,
|
||||
ViewResolver,
|
||||
DirectiveResolver,
|
||||
PipeResolver
|
||||
]);
|
||||
|
38
modules/angular2/src/compiler/config.ts
Normal file
38
modules/angular2/src/compiler/config.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import {isBlank} from 'angular2/src/facade/lang';
|
||||
import {unimplemented} from 'angular2/src/facade/exceptions';
|
||||
import {Identifiers} from './identifiers';
|
||||
import {CompileIdentifierMetadata} from './compile_metadata';
|
||||
|
||||
export class CompilerConfig {
|
||||
public renderTypes: RenderTypes;
|
||||
constructor(public genDebugInfo: boolean, public logBindingUpdate: boolean,
|
||||
public useJit: boolean, renderTypes: RenderTypes = null) {
|
||||
if (isBlank(renderTypes)) {
|
||||
renderTypes = new DefaultRenderTypes();
|
||||
}
|
||||
this.renderTypes = renderTypes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Types used for the renderer.
|
||||
* Can be replaced to specialize the generated output to a specific renderer
|
||||
* to help tree shaking.
|
||||
*/
|
||||
export abstract class RenderTypes {
|
||||
get renderer(): CompileIdentifierMetadata { return unimplemented(); }
|
||||
get renderText(): CompileIdentifierMetadata { return unimplemented(); }
|
||||
get renderElement(): CompileIdentifierMetadata { return unimplemented(); }
|
||||
get renderComment(): CompileIdentifierMetadata { return unimplemented(); }
|
||||
get renderNode(): CompileIdentifierMetadata { return unimplemented(); }
|
||||
get renderEvent(): CompileIdentifierMetadata { return unimplemented(); }
|
||||
}
|
||||
|
||||
export class DefaultRenderTypes implements RenderTypes {
|
||||
renderer = Identifiers.Renderer;
|
||||
renderText = null;
|
||||
renderElement = null;
|
||||
renderComment = null;
|
||||
renderNode = null;
|
||||
renderEvent = null;
|
||||
}
|
@ -94,12 +94,14 @@ export class LexedCssResult {
|
||||
constructor(public error: CssScannerError, public token: CssToken) {}
|
||||
}
|
||||
|
||||
export function generateErrorMessage(input, message, errorValue, index, row, column) {
|
||||
export function generateErrorMessage(input: string, message: string, errorValue: string,
|
||||
index: number, row: number, column: number): string {
|
||||
return `${message} at column ${row}:${column} in expression [` +
|
||||
findProblemCode(input, errorValue, index, column) + ']';
|
||||
}
|
||||
|
||||
export function findProblemCode(input, errorValue, index, column) {
|
||||
export function findProblemCode(input: string, errorValue: string, index: number,
|
||||
column: number): string {
|
||||
var endOfProblemLine = index;
|
||||
var current = charCode(input, index);
|
||||
while (current > 0 && !isNewline(current)) {
|
||||
@ -163,7 +165,9 @@ export class CssScanner {
|
||||
column: number = -1;
|
||||
line: number = 0;
|
||||
|
||||
/** @internal */
|
||||
_currentMode: CssLexerMode = CssLexerMode.BLOCK;
|
||||
/** @internal */
|
||||
_currentError: CssScannerError = null;
|
||||
|
||||
constructor(public input: string, private _trackComments: boolean = false) {
|
||||
@ -196,7 +200,7 @@ export class CssScanner {
|
||||
this.peekPeek = this.peekAt(this.index + 1);
|
||||
}
|
||||
|
||||
peekAt(index): number {
|
||||
peekAt(index: number): number {
|
||||
return index >= this.length ? $EOF : StringWrapper.charCodeAt(this.input, index);
|
||||
}
|
||||
|
||||
@ -295,6 +299,7 @@ export class CssScanner {
|
||||
return new LexedCssResult(error, token);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_scan(): CssToken {
|
||||
var peek = this.peek;
|
||||
var peekPeek = this.peekPeek;
|
||||
@ -348,7 +353,7 @@ export class CssScanner {
|
||||
return this.error(`Unexpected character [${StringWrapper.fromCharCode(peek)}]`);
|
||||
}
|
||||
|
||||
scanComment() {
|
||||
scanComment(): CssToken {
|
||||
if (this.assertCondition(isCommentStart(this.peek, this.peekPeek),
|
||||
"Expected comment start value")) {
|
||||
return null;
|
||||
@ -375,7 +380,7 @@ export class CssScanner {
|
||||
return new CssToken(start, startingColumn, startingLine, CssTokenType.Comment, str);
|
||||
}
|
||||
|
||||
scanWhitespace() {
|
||||
scanWhitespace(): CssToken {
|
||||
var start = this.index;
|
||||
var startingColumn = this.column;
|
||||
var startingLine = this.line;
|
||||
@ -386,7 +391,7 @@ export class CssScanner {
|
||||
return new CssToken(start, startingColumn, startingLine, CssTokenType.Whitespace, str);
|
||||
}
|
||||
|
||||
scanString() {
|
||||
scanString(): CssToken {
|
||||
if (this.assertCondition(isStringStart(this.peek, this.peekPeek),
|
||||
"Unexpected non-string starting value")) {
|
||||
return null;
|
||||
@ -416,7 +421,7 @@ export class CssScanner {
|
||||
return new CssToken(start, startingColumn, startingLine, CssTokenType.String, str);
|
||||
}
|
||||
|
||||
scanNumber() {
|
||||
scanNumber(): CssToken {
|
||||
var start = this.index;
|
||||
var startingColumn = this.column;
|
||||
if (this.peek == $PLUS || this.peek == $MINUS) {
|
||||
@ -436,7 +441,7 @@ export class CssScanner {
|
||||
return new CssToken(start, startingColumn, this.line, CssTokenType.Number, strValue);
|
||||
}
|
||||
|
||||
scanIdentifier() {
|
||||
scanIdentifier(): CssToken {
|
||||
if (this.assertCondition(isIdentifierStart(this.peek, this.peekPeek),
|
||||
'Expected identifier starting value')) {
|
||||
return null;
|
||||
@ -451,7 +456,7 @@ export class CssScanner {
|
||||
return new CssToken(start, startingColumn, this.line, CssTokenType.Identifier, strValue);
|
||||
}
|
||||
|
||||
scanCssValueFunction() {
|
||||
scanCssValueFunction(): CssToken {
|
||||
var start = this.index;
|
||||
var startingColumn = this.column;
|
||||
while (this.peek != $EOF && this.peek != $RPAREN) {
|
||||
@ -461,7 +466,7 @@ export class CssScanner {
|
||||
return new CssToken(start, startingColumn, this.line, CssTokenType.Identifier, strValue);
|
||||
}
|
||||
|
||||
scanCharacter() {
|
||||
scanCharacter(): CssToken {
|
||||
var start = this.index;
|
||||
var startingColumn = this.column;
|
||||
if (this.assertCondition(isValidCssCharacter(this.peek, this._currentMode),
|
||||
@ -475,7 +480,7 @@ export class CssScanner {
|
||||
return new CssToken(start, startingColumn, this.line, CssTokenType.Character, c);
|
||||
}
|
||||
|
||||
scanAtExpression() {
|
||||
scanAtExpression(): CssToken {
|
||||
if (this.assertCondition(this.peek == $AT, 'Expected @ value')) {
|
||||
return null;
|
||||
}
|
||||
@ -521,7 +526,7 @@ function isAtKeyword(current: CssToken, next: CssToken): boolean {
|
||||
return current.numValue == $AT && next.type == CssTokenType.Identifier;
|
||||
}
|
||||
|
||||
function isCharMatch(target: number, previous: number, code: number) {
|
||||
function isCharMatch(target: number, previous: number, code: number): boolean {
|
||||
return code == target && previous != $BACKSLASH;
|
||||
}
|
||||
|
||||
@ -529,11 +534,11 @@ function isDigit(code: number): boolean {
|
||||
return $0 <= code && code <= $9;
|
||||
}
|
||||
|
||||
function isCommentStart(code: number, next: number) {
|
||||
function isCommentStart(code: number, next: number): boolean {
|
||||
return code == $SLASH && next == $STAR;
|
||||
}
|
||||
|
||||
function isCommentEnd(code: number, next: number) {
|
||||
function isCommentEnd(code: number, next: number): boolean {
|
||||
return code == $STAR && next == $SLASH;
|
||||
}
|
||||
|
||||
@ -555,12 +560,12 @@ function isIdentifierStart(code: number, next: number): boolean {
|
||||
target == $MINUS || target == $_;
|
||||
}
|
||||
|
||||
function isIdentifierPart(target: number) {
|
||||
function isIdentifierPart(target: number): boolean {
|
||||
return ($a <= target && target <= $z) || ($A <= target && target <= $Z) || target == $BACKSLASH ||
|
||||
target == $MINUS || target == $_ || isDigit(target);
|
||||
}
|
||||
|
||||
function isValidPseudoSelectorCharacter(code: number) {
|
||||
function isValidPseudoSelectorCharacter(code: number): boolean {
|
||||
switch (code) {
|
||||
case $LPAREN:
|
||||
case $RPAREN:
|
||||
@ -570,11 +575,11 @@ function isValidPseudoSelectorCharacter(code: number) {
|
||||
}
|
||||
}
|
||||
|
||||
function isValidKeyframeBlockCharacter(code: number) {
|
||||
function isValidKeyframeBlockCharacter(code: number): boolean {
|
||||
return code == $PERCENT;
|
||||
}
|
||||
|
||||
function isValidAttributeSelectorCharacter(code: number) {
|
||||
function isValidAttributeSelectorCharacter(code: number): boolean {
|
||||
// value^*|$~=something
|
||||
switch (code) {
|
||||
case $$:
|
||||
@ -589,7 +594,7 @@ function isValidAttributeSelectorCharacter(code: number) {
|
||||
}
|
||||
}
|
||||
|
||||
function isValidSelectorCharacter(code: number) {
|
||||
function isValidSelectorCharacter(code: number): boolean {
|
||||
// selector [ key = value ]
|
||||
// IDENT C IDENT C IDENT C
|
||||
// #id, .class, *+~>
|
||||
@ -610,7 +615,7 @@ function isValidSelectorCharacter(code: number) {
|
||||
}
|
||||
}
|
||||
|
||||
function isValidStyleBlockCharacter(code: number) {
|
||||
function isValidStyleBlockCharacter(code: number): boolean {
|
||||
// key:value;
|
||||
// key:calc(something ... )
|
||||
switch (code) {
|
||||
@ -630,7 +635,7 @@ function isValidStyleBlockCharacter(code: number) {
|
||||
}
|
||||
}
|
||||
|
||||
function isValidMediaQueryRuleCharacter(code: number) {
|
||||
function isValidMediaQueryRuleCharacter(code: number): boolean {
|
||||
// (min-width: 7.5em) and (orientation: landscape)
|
||||
switch (code) {
|
||||
case $LPAREN:
|
||||
@ -644,7 +649,7 @@ function isValidMediaQueryRuleCharacter(code: number) {
|
||||
}
|
||||
}
|
||||
|
||||
function isValidAtRuleCharacter(code: number) {
|
||||
function isValidAtRuleCharacter(code: number): boolean {
|
||||
// @document url(http://www.w3.org/page?something=on#hash),
|
||||
switch (code) {
|
||||
case $LPAREN:
|
||||
@ -668,7 +673,7 @@ function isValidAtRuleCharacter(code: number) {
|
||||
}
|
||||
}
|
||||
|
||||
function isValidStyleFunctionCharacter(code: number) {
|
||||
function isValidStyleFunctionCharacter(code: number): boolean {
|
||||
switch (code) {
|
||||
case $PERIOD:
|
||||
case $MINUS:
|
||||
@ -684,7 +689,7 @@ function isValidStyleFunctionCharacter(code: number) {
|
||||
}
|
||||
}
|
||||
|
||||
function isValidBlockCharacter(code: number) {
|
||||
function isValidBlockCharacter(code: number): boolean {
|
||||
// @something { }
|
||||
// IDENT
|
||||
return code == $AT;
|
||||
|
@ -95,7 +95,7 @@ function getDelimFromCharacter(code: number): number {
|
||||
}
|
||||
}
|
||||
|
||||
function characterContainsDelimiter(code: number, delimiters: number) {
|
||||
function characterContainsDelimiter(code: number, delimiters: number): boolean {
|
||||
return bitWiseAnd([getDelimFromCharacter(code), delimiters]) > 0;
|
||||
}
|
||||
|
||||
@ -129,6 +129,7 @@ export class CssParser {
|
||||
this._file = new ParseSourceFile(this._scanner.input, _fileName);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_resolveBlockType(token: CssToken): BlockType {
|
||||
switch (token.strValue) {
|
||||
case '@-o-keyframes':
|
||||
@ -179,6 +180,7 @@ export class CssParser {
|
||||
return new ParsedCssResult(errors, ast);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_parseStyleSheet(delimiters): CssStyleSheetAST {
|
||||
var results = [];
|
||||
this._scanner.consumeEmptyStatements();
|
||||
@ -189,6 +191,7 @@ export class CssParser {
|
||||
return new CssStyleSheetAST(results);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_parseRule(delimiters: number): CssRuleAST {
|
||||
if (this._scanner.peek == $AT) {
|
||||
return this._parseAtRule(delimiters);
|
||||
@ -196,6 +199,7 @@ export class CssParser {
|
||||
return this._parseSelectorRule(delimiters);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_parseAtRule(delimiters: number): CssRuleAST {
|
||||
this._scanner.setMode(CssLexerMode.BLOCK);
|
||||
|
||||
@ -259,6 +263,7 @@ export class CssParser {
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_parseSelectorRule(delimiters: number): CssSelectorRuleAST {
|
||||
var selectors = this._parseSelectors(delimiters);
|
||||
var block = this._parseStyleBlock(delimiters);
|
||||
@ -267,6 +272,7 @@ export class CssParser {
|
||||
return new CssSelectorRuleAST(selectors, block);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_parseSelectors(delimiters: number): CssSelectorAST[] {
|
||||
delimiters = bitWiseOr([delimiters, LBRACE_DELIM]);
|
||||
|
||||
@ -286,6 +292,7 @@ export class CssParser {
|
||||
return selectors;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_scan(): CssToken {
|
||||
var output = this._scanner.scan();
|
||||
var token = output.token;
|
||||
@ -296,6 +303,7 @@ export class CssParser {
|
||||
return token;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_consume(type: CssTokenType, value: string = null): CssToken {
|
||||
var output = this._scanner.consume(type, value);
|
||||
var token = output.token;
|
||||
@ -306,6 +314,7 @@ export class CssParser {
|
||||
return token;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_parseKeyframeBlock(delimiters: number): CssBlockAST {
|
||||
delimiters = bitWiseOr([delimiters, RBRACE_DELIM]);
|
||||
this._scanner.setMode(CssLexerMode.KEYFRAME_BLOCK);
|
||||
@ -322,6 +331,7 @@ export class CssParser {
|
||||
return new CssBlockAST(definitions);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_parseKeyframeDefinition(delimiters: number): CssKeyframeDefinitionAST {
|
||||
var stepTokens = [];
|
||||
delimiters = bitWiseOr([delimiters, LBRACE_DELIM]);
|
||||
@ -336,11 +346,13 @@ export class CssParser {
|
||||
return new CssKeyframeDefinitionAST(stepTokens, styles);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_parseKeyframeLabel(delimiters: number): CssToken {
|
||||
this._scanner.setMode(CssLexerMode.KEYFRAME_BLOCK);
|
||||
return mergeTokens(this._collectUntilDelim(delimiters));
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_parseSelector(delimiters: number): CssSelectorAST {
|
||||
delimiters = bitWiseOr([delimiters, COMMA_DELIM, LBRACE_DELIM]);
|
||||
this._scanner.setMode(CssLexerMode.SELECTOR);
|
||||
@ -435,6 +447,7 @@ export class CssParser {
|
||||
return new CssSelectorAST(selectorCssTokens, isComplex);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_parseValue(delimiters: number): CssStyleValueAST {
|
||||
delimiters = bitWiseOr([delimiters, RBRACE_DELIM, SEMICOLON_DELIM, NEWLINE_DELIM]);
|
||||
|
||||
@ -489,6 +502,7 @@ export class CssParser {
|
||||
return new CssStyleValueAST(tokens, strValue);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_collectUntilDelim(delimiters: number, assertType: CssTokenType = null): CssToken[] {
|
||||
var tokens = [];
|
||||
while (!characterContainsDelimiter(this._scanner.peek, delimiters)) {
|
||||
@ -498,6 +512,7 @@ export class CssParser {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_parseBlock(delimiters: number): CssBlockAST {
|
||||
delimiters = bitWiseOr([delimiters, RBRACE_DELIM]);
|
||||
|
||||
@ -519,6 +534,7 @@ export class CssParser {
|
||||
return new CssBlockAST(results);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_parseStyleBlock(delimiters: number): CssBlockAST {
|
||||
delimiters = bitWiseOr([delimiters, RBRACE_DELIM, LBRACE_DELIM]);
|
||||
|
||||
@ -541,6 +557,7 @@ export class CssParser {
|
||||
return new CssBlockAST(definitions);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_parseDefinition(delimiters: number): CssDefinitionAST {
|
||||
this._scanner.setMode(CssLexerMode.STYLE_BLOCK);
|
||||
|
||||
@ -600,6 +617,7 @@ export class CssParser {
|
||||
return new CssDefinitionAST(prop, value);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_assertCondition(status: boolean, errorMessage: string, problemToken: CssToken): boolean {
|
||||
if (!status) {
|
||||
this._error(errorMessage, problemToken);
|
||||
@ -608,6 +626,7 @@ export class CssParser {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_error(message: string, problemToken: CssToken) {
|
||||
var length = problemToken.strValue.length;
|
||||
var error = CssParseError.create(this._file, 0, problemToken.line, problemToken.column, length,
|
||||
|
@ -1,7 +1,7 @@
|
||||
library angular2.src.core.compiler.directive_lifecycle_reflector;
|
||||
|
||||
import 'package:angular2/src/core/reflection/reflection.dart';
|
||||
import 'package:angular2/src/core/linker/interfaces.dart';
|
||||
import 'package:angular2/src/core/metadata/lifecycle_hooks.dart';
|
||||
|
||||
const INTERFACES = const {
|
||||
LifecycleHooks.OnInit: OnInit,
|
@ -1,5 +1,5 @@
|
||||
import {Type} from 'angular2/src/facade/lang';
|
||||
import {LifecycleHooks} from './interfaces';
|
||||
import {LifecycleHooks} from 'angular2/src/core/metadata/lifecycle_hooks';
|
||||
|
||||
export function hasLifecycleHook(lcInterface: LifecycleHooks, token): boolean {
|
||||
if (!(token instanceof Type)) return false;
|
@ -1,9 +1,11 @@
|
||||
import {
|
||||
CompileTypeMetadata,
|
||||
CompileDirectiveMetadata,
|
||||
CompileTemplateMetadata
|
||||
} from './directive_metadata';
|
||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
CompileTemplateMetadata,
|
||||
CompileProviderMetadata,
|
||||
CompileTokenMetadata
|
||||
} from './compile_metadata';
|
||||
import {isPresent, isBlank, isArray} from 'angular2/src/facade/lang';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {PromiseWrapper} from 'angular2/src/facade/async';
|
||||
|
||||
@ -21,6 +23,8 @@ import {
|
||||
HtmlAttrAst,
|
||||
HtmlAst,
|
||||
HtmlCommentAst,
|
||||
HtmlExpansionAst,
|
||||
HtmlExpansionCaseAst,
|
||||
htmlVisitAll
|
||||
} from './html_ast';
|
||||
import {HtmlParser} from './html_parser';
|
||||
@ -28,10 +32,36 @@ import {HtmlParser} from './html_parser';
|
||||
import {preparseElement, PreparsedElement, PreparsedElementType} from './template_preparser';
|
||||
|
||||
@Injectable()
|
||||
export class TemplateNormalizer {
|
||||
export class DirectiveNormalizer {
|
||||
constructor(private _xhr: XHR, private _urlResolver: UrlResolver,
|
||||
private _htmlParser: HtmlParser) {}
|
||||
|
||||
normalizeDirective(directive: CompileDirectiveMetadata): Promise<CompileDirectiveMetadata> {
|
||||
if (!directive.isComponent) {
|
||||
// For non components there is nothing to be normalized yet.
|
||||
return PromiseWrapper.resolve(directive);
|
||||
}
|
||||
return this.normalizeTemplate(directive.type, directive.template)
|
||||
.then((normalizedTemplate: CompileTemplateMetadata) => new CompileDirectiveMetadata({
|
||||
type: directive.type,
|
||||
isComponent: directive.isComponent,
|
||||
selector: directive.selector,
|
||||
exportAs: directive.exportAs,
|
||||
changeDetection: directive.changeDetection,
|
||||
inputs: directive.inputs,
|
||||
outputs: directive.outputs,
|
||||
hostListeners: directive.hostListeners,
|
||||
hostProperties: directive.hostProperties,
|
||||
hostAttributes: directive.hostAttributes,
|
||||
lifecycleHooks: directive.lifecycleHooks,
|
||||
providers: directive.providers,
|
||||
viewProviders: directive.viewProviders,
|
||||
queries: directive.queries,
|
||||
viewQueries: directive.viewQueries,
|
||||
template: normalizedTemplate
|
||||
}));
|
||||
}
|
||||
|
||||
normalizeTemplate(directiveType: CompileTypeMetadata,
|
||||
template: CompileTemplateMetadata): Promise<CompileTemplateMetadata> {
|
||||
if (isPresent(template.template)) {
|
||||
@ -130,4 +160,7 @@ class TemplatePreparseVisitor implements HtmlAstVisitor {
|
||||
visitComment(ast: HtmlCommentAst, context: any): any { return null; }
|
||||
visitAttr(ast: HtmlAttrAst, context: any): any { return null; }
|
||||
visitText(ast: HtmlTextAst, context: any): any { return null; }
|
||||
visitExpansion(ast: HtmlExpansionAst, context: any): any { return null; }
|
||||
|
||||
visitExpansionCase(ast: HtmlExpansionCaseAst, context: any): any { return null; }
|
||||
}
|
348
modules/angular2/src/compiler/expression_parser/ast.ts
Normal file
348
modules/angular2/src/compiler/expression_parser/ast.ts
Normal file
@ -0,0 +1,348 @@
|
||||
import {ListWrapper} from "angular2/src/facade/collection";
|
||||
|
||||
export class AST {
|
||||
visit(visitor: AstVisitor, context: any = null): any { return null; }
|
||||
toString(): string { return "AST"; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a quoted expression of the form:
|
||||
*
|
||||
* quote = prefix `:` uninterpretedExpression
|
||||
* prefix = identifier
|
||||
* uninterpretedExpression = arbitrary string
|
||||
*
|
||||
* A quoted expression is meant to be pre-processed by an AST transformer that
|
||||
* converts it into another AST that no longer contains quoted expressions.
|
||||
* It is meant to allow third-party developers to extend Angular template
|
||||
* expression language. The `uninterpretedExpression` part of the quote is
|
||||
* therefore not interpreted by the Angular's own expression parser.
|
||||
*/
|
||||
export class Quote extends AST {
|
||||
constructor(public prefix: string, public uninterpretedExpression: string, public location: any) {
|
||||
super();
|
||||
}
|
||||
visit(visitor: AstVisitor, context: any = null): any { return visitor.visitQuote(this, context); }
|
||||
toString(): string { return "Quote"; }
|
||||
}
|
||||
|
||||
export class EmptyExpr extends AST {
|
||||
visit(visitor: AstVisitor, context: any = null) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
export class ImplicitReceiver extends AST {
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitImplicitReceiver(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiple expressions separated by a semicolon.
|
||||
*/
|
||||
export class Chain extends AST {
|
||||
constructor(public expressions: any[]) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any { return visitor.visitChain(this, context); }
|
||||
}
|
||||
|
||||
export class Conditional extends AST {
|
||||
constructor(public condition: AST, public trueExp: AST, public falseExp: AST) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitConditional(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class PropertyRead extends AST {
|
||||
constructor(public receiver: AST, public name: string) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitPropertyRead(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class PropertyWrite extends AST {
|
||||
constructor(public receiver: AST, public name: string, public value: AST) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitPropertyWrite(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class SafePropertyRead extends AST {
|
||||
constructor(public receiver: AST, public name: string) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitSafePropertyRead(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class KeyedRead extends AST {
|
||||
constructor(public obj: AST, public key: AST) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitKeyedRead(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class KeyedWrite extends AST {
|
||||
constructor(public obj: AST, public key: AST, public value: AST) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitKeyedWrite(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class BindingPipe extends AST {
|
||||
constructor(public exp: AST, public name: string, public args: any[]) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any { return visitor.visitPipe(this, context); }
|
||||
}
|
||||
|
||||
export class LiteralPrimitive extends AST {
|
||||
constructor(public value) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitLiteralPrimitive(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class LiteralArray extends AST {
|
||||
constructor(public expressions: any[]) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitLiteralArray(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class LiteralMap extends AST {
|
||||
constructor(public keys: any[], public values: any[]) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitLiteralMap(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class Interpolation extends AST {
|
||||
constructor(public strings: any[], public expressions: any[]) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitInterpolation(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class Binary extends AST {
|
||||
constructor(public operation: string, public left: AST, public right: AST) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitBinary(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class PrefixNot extends AST {
|
||||
constructor(public expression: AST) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitPrefixNot(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class MethodCall extends AST {
|
||||
constructor(public receiver: AST, public name: string, public args: any[]) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitMethodCall(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class SafeMethodCall extends AST {
|
||||
constructor(public receiver: AST, public name: string, public args: any[]) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitSafeMethodCall(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class FunctionCall extends AST {
|
||||
constructor(public target: AST, public args: any[]) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
return visitor.visitFunctionCall(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class ASTWithSource extends AST {
|
||||
constructor(public ast: AST, public source: string, public location: string) { super(); }
|
||||
visit(visitor: AstVisitor, context: any = null): any { return this.ast.visit(visitor, context); }
|
||||
toString(): string { return `${this.source} in ${this.location}`; }
|
||||
}
|
||||
|
||||
export class TemplateBinding {
|
||||
constructor(public key: string, public keyIsVar: boolean, public name: string,
|
||||
public expression: ASTWithSource) {}
|
||||
}
|
||||
|
||||
export interface AstVisitor {
|
||||
visitBinary(ast: Binary, context: any): any;
|
||||
visitChain(ast: Chain, context: any): any;
|
||||
visitConditional(ast: Conditional, context: any): any;
|
||||
visitFunctionCall(ast: FunctionCall, context: any): any;
|
||||
visitImplicitReceiver(ast: ImplicitReceiver, context: any): any;
|
||||
visitInterpolation(ast: Interpolation, context: any): any;
|
||||
visitKeyedRead(ast: KeyedRead, context: any): any;
|
||||
visitKeyedWrite(ast: KeyedWrite, context: any): any;
|
||||
visitLiteralArray(ast: LiteralArray, context: any): any;
|
||||
visitLiteralMap(ast: LiteralMap, context: any): any;
|
||||
visitLiteralPrimitive(ast: LiteralPrimitive, context: any): any;
|
||||
visitMethodCall(ast: MethodCall, context: any): any;
|
||||
visitPipe(ast: BindingPipe, context: any): any;
|
||||
visitPrefixNot(ast: PrefixNot, context: any): any;
|
||||
visitPropertyRead(ast: PropertyRead, context: any): any;
|
||||
visitPropertyWrite(ast: PropertyWrite, context: any): any;
|
||||
visitQuote(ast: Quote, context: any): any;
|
||||
visitSafeMethodCall(ast: SafeMethodCall, context: any): any;
|
||||
visitSafePropertyRead(ast: SafePropertyRead, context: any): any;
|
||||
}
|
||||
|
||||
export class RecursiveAstVisitor implements AstVisitor {
|
||||
visitBinary(ast: Binary, context: any): any {
|
||||
ast.left.visit(this);
|
||||
ast.right.visit(this);
|
||||
return null;
|
||||
}
|
||||
visitChain(ast: Chain, context: any): any { return this.visitAll(ast.expressions, context); }
|
||||
visitConditional(ast: Conditional, context: any): any {
|
||||
ast.condition.visit(this);
|
||||
ast.trueExp.visit(this);
|
||||
ast.falseExp.visit(this);
|
||||
return null;
|
||||
}
|
||||
visitPipe(ast: BindingPipe, context: any): any {
|
||||
ast.exp.visit(this);
|
||||
this.visitAll(ast.args, context);
|
||||
return null;
|
||||
}
|
||||
visitFunctionCall(ast: FunctionCall, context: any): any {
|
||||
ast.target.visit(this);
|
||||
this.visitAll(ast.args, context);
|
||||
return null;
|
||||
}
|
||||
visitImplicitReceiver(ast: ImplicitReceiver, context: any): any { return null; }
|
||||
visitInterpolation(ast: Interpolation, context: any): any {
|
||||
return this.visitAll(ast.expressions, context);
|
||||
}
|
||||
visitKeyedRead(ast: KeyedRead, context: any): any {
|
||||
ast.obj.visit(this);
|
||||
ast.key.visit(this);
|
||||
return null;
|
||||
}
|
||||
visitKeyedWrite(ast: KeyedWrite, context: any): any {
|
||||
ast.obj.visit(this);
|
||||
ast.key.visit(this);
|
||||
ast.value.visit(this);
|
||||
return null;
|
||||
}
|
||||
visitLiteralArray(ast: LiteralArray, context: any): any {
|
||||
return this.visitAll(ast.expressions, context);
|
||||
}
|
||||
visitLiteralMap(ast: LiteralMap, context: any): any { return this.visitAll(ast.values, context); }
|
||||
visitLiteralPrimitive(ast: LiteralPrimitive, context: any): any { return null; }
|
||||
visitMethodCall(ast: MethodCall, context: any): any {
|
||||
ast.receiver.visit(this);
|
||||
return this.visitAll(ast.args, context);
|
||||
}
|
||||
visitPrefixNot(ast: PrefixNot, context: any): any {
|
||||
ast.expression.visit(this);
|
||||
return null;
|
||||
}
|
||||
visitPropertyRead(ast: PropertyRead, context: any): any {
|
||||
ast.receiver.visit(this);
|
||||
return null;
|
||||
}
|
||||
visitPropertyWrite(ast: PropertyWrite, context: any): any {
|
||||
ast.receiver.visit(this);
|
||||
ast.value.visit(this);
|
||||
return null;
|
||||
}
|
||||
visitSafePropertyRead(ast: SafePropertyRead, context: any): any {
|
||||
ast.receiver.visit(this);
|
||||
return null;
|
||||
}
|
||||
visitSafeMethodCall(ast: SafeMethodCall, context: any): any {
|
||||
ast.receiver.visit(this);
|
||||
return this.visitAll(ast.args, context);
|
||||
}
|
||||
visitAll(asts: AST[], context: any): any {
|
||||
asts.forEach(ast => ast.visit(this, context));
|
||||
return null;
|
||||
}
|
||||
visitQuote(ast: Quote, context: any): any { return null; }
|
||||
}
|
||||
|
||||
export class AstTransformer implements AstVisitor {
|
||||
visitImplicitReceiver(ast: ImplicitReceiver, context: any): AST { return ast; }
|
||||
|
||||
visitInterpolation(ast: Interpolation, context: any): AST {
|
||||
return new Interpolation(ast.strings, this.visitAll(ast.expressions));
|
||||
}
|
||||
|
||||
visitLiteralPrimitive(ast: LiteralPrimitive, context: any): AST {
|
||||
return new LiteralPrimitive(ast.value);
|
||||
}
|
||||
|
||||
visitPropertyRead(ast: PropertyRead, context: any): AST {
|
||||
return new PropertyRead(ast.receiver.visit(this), ast.name);
|
||||
}
|
||||
|
||||
visitPropertyWrite(ast: PropertyWrite, context: any): AST {
|
||||
return new PropertyWrite(ast.receiver.visit(this), ast.name, ast.value);
|
||||
}
|
||||
|
||||
visitSafePropertyRead(ast: SafePropertyRead, context: any): AST {
|
||||
return new SafePropertyRead(ast.receiver.visit(this), ast.name);
|
||||
}
|
||||
|
||||
visitMethodCall(ast: MethodCall, context: any): AST {
|
||||
return new MethodCall(ast.receiver.visit(this), ast.name, this.visitAll(ast.args));
|
||||
}
|
||||
|
||||
visitSafeMethodCall(ast: SafeMethodCall, context: any): AST {
|
||||
return new SafeMethodCall(ast.receiver.visit(this), ast.name, this.visitAll(ast.args));
|
||||
}
|
||||
|
||||
visitFunctionCall(ast: FunctionCall, context: any): AST {
|
||||
return new FunctionCall(ast.target.visit(this), this.visitAll(ast.args));
|
||||
}
|
||||
|
||||
visitLiteralArray(ast: LiteralArray, context: any): AST {
|
||||
return new LiteralArray(this.visitAll(ast.expressions));
|
||||
}
|
||||
|
||||
visitLiteralMap(ast: LiteralMap, context: any): AST {
|
||||
return new LiteralMap(ast.keys, this.visitAll(ast.values));
|
||||
}
|
||||
|
||||
visitBinary(ast: Binary, context: any): AST {
|
||||
return new Binary(ast.operation, ast.left.visit(this), ast.right.visit(this));
|
||||
}
|
||||
|
||||
visitPrefixNot(ast: PrefixNot, context: any): AST {
|
||||
return new PrefixNot(ast.expression.visit(this));
|
||||
}
|
||||
|
||||
visitConditional(ast: Conditional, context: any): AST {
|
||||
return new Conditional(ast.condition.visit(this), ast.trueExp.visit(this),
|
||||
ast.falseExp.visit(this));
|
||||
}
|
||||
|
||||
visitPipe(ast: BindingPipe, context: any): AST {
|
||||
return new BindingPipe(ast.exp.visit(this), ast.name, this.visitAll(ast.args));
|
||||
}
|
||||
|
||||
visitKeyedRead(ast: KeyedRead, context: any): AST {
|
||||
return new KeyedRead(ast.obj.visit(this), ast.key.visit(this));
|
||||
}
|
||||
|
||||
visitKeyedWrite(ast: KeyedWrite, context: any): AST {
|
||||
return new KeyedWrite(ast.obj.visit(this), ast.key.visit(this), ast.value.visit(this));
|
||||
}
|
||||
|
||||
visitAll(asts: any[]): any[] {
|
||||
var res = ListWrapper.createFixedSize(asts.length);
|
||||
for (var i = 0; i < asts.length; ++i) {
|
||||
res[i] = asts[i].visit(this);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
visitChain(ast: Chain, context: any): AST { return new Chain(this.visitAll(ast.expressions)); }
|
||||
|
||||
visitQuote(ast: Quote, context: any): AST {
|
||||
return new Quote(ast.prefix, ast.uninterpretedExpression, ast.location);
|
||||
}
|
||||
}
|
@ -145,7 +145,7 @@ export const $BACKSLASH = 92;
|
||||
export const $RBRACKET = 93;
|
||||
const $CARET = 94;
|
||||
const $_ = 95;
|
||||
|
||||
export const $BT = 96;
|
||||
const $a = 97, $e = 101, $f = 102, $n = 110, $r = 114, $t = 116, $u = 117, $v = 118, $z = 122;
|
||||
|
||||
export const $LBRACE = 123;
|
||||
@ -415,6 +415,10 @@ function isExponentSign(code: number): boolean {
|
||||
return code == $MINUS || code == $PLUS;
|
||||
}
|
||||
|
||||
export function isQuote(code: number): boolean {
|
||||
return code === $SQ || code === $DQ || code === $BT;
|
||||
}
|
||||
|
||||
function unescape(code: number): number {
|
||||
switch (code) {
|
||||
case $n:
|
@ -6,6 +6,7 @@ import {
|
||||
Lexer,
|
||||
EOF,
|
||||
isIdentifier,
|
||||
isQuote,
|
||||
Token,
|
||||
$PERIOD,
|
||||
$COLON,
|
||||
@ -16,9 +17,9 @@ import {
|
||||
$LBRACE,
|
||||
$RBRACE,
|
||||
$LPAREN,
|
||||
$RPAREN
|
||||
$RPAREN,
|
||||
$SLASH
|
||||
} from './lexer';
|
||||
import {reflector, Reflector} from 'angular2/src/core/reflection/reflection';
|
||||
import {
|
||||
AST,
|
||||
EmptyExpr,
|
||||
@ -63,18 +64,13 @@ export class SplitInterpolation {
|
||||
|
||||
@Injectable()
|
||||
export class Parser {
|
||||
/** @internal */
|
||||
_reflector: Reflector;
|
||||
|
||||
constructor(/** @internal */
|
||||
public _lexer: Lexer, providedReflector: Reflector = null) {
|
||||
this._reflector = isPresent(providedReflector) ? providedReflector : reflector;
|
||||
}
|
||||
public _lexer: Lexer) {}
|
||||
|
||||
parseAction(input: string, location: any): ASTWithSource {
|
||||
this._checkNoInterpolation(input, location);
|
||||
var tokens = this._lexer.tokenize(input);
|
||||
var ast = new _ParseAST(input, location, tokens, this._reflector, true).parseChain();
|
||||
var tokens = this._lexer.tokenize(this._stripComments(input));
|
||||
var ast = new _ParseAST(input, location, tokens, true).parseChain();
|
||||
return new ASTWithSource(ast, input, location);
|
||||
}
|
||||
|
||||
@ -102,8 +98,8 @@ export class Parser {
|
||||
}
|
||||
|
||||
this._checkNoInterpolation(input, location);
|
||||
var tokens = this._lexer.tokenize(input);
|
||||
return new _ParseAST(input, location, tokens, this._reflector, false).parseChain();
|
||||
var tokens = this._lexer.tokenize(this._stripComments(input));
|
||||
return new _ParseAST(input, location, tokens, false).parseChain();
|
||||
}
|
||||
|
||||
private _parseQuote(input: string, location: any): AST {
|
||||
@ -118,7 +114,7 @@ export class Parser {
|
||||
|
||||
parseTemplateBindings(input: string, location: any): TemplateBinding[] {
|
||||
var tokens = this._lexer.tokenize(input);
|
||||
return new _ParseAST(input, location, tokens, this._reflector, false).parseTemplateBindings();
|
||||
return new _ParseAST(input, location, tokens, false).parseTemplateBindings();
|
||||
}
|
||||
|
||||
parseInterpolation(input: string, location: any): ASTWithSource {
|
||||
@ -128,8 +124,8 @@ export class Parser {
|
||||
let expressions = [];
|
||||
|
||||
for (let i = 0; i < split.expressions.length; ++i) {
|
||||
var tokens = this._lexer.tokenize(split.expressions[i]);
|
||||
var ast = new _ParseAST(input, location, tokens, this._reflector, false).parseChain();
|
||||
var tokens = this._lexer.tokenize(this._stripComments(split.expressions[i]));
|
||||
var ast = new _ParseAST(input, location, tokens, false).parseChain();
|
||||
expressions.push(ast);
|
||||
}
|
||||
|
||||
@ -164,6 +160,28 @@ export class Parser {
|
||||
return new ASTWithSource(new LiteralPrimitive(input), input, location);
|
||||
}
|
||||
|
||||
private _stripComments(input: string): string {
|
||||
let i = this._commentStart(input);
|
||||
return isPresent(i) ? input.substring(0, i).trim() : input;
|
||||
}
|
||||
|
||||
private _commentStart(input: string): number {
|
||||
var outerQuote = null;
|
||||
for (var i = 0; i < input.length - 1; i++) {
|
||||
let char = StringWrapper.charCodeAt(input, i);
|
||||
let nextChar = StringWrapper.charCodeAt(input, i + 1);
|
||||
|
||||
if (char === $SLASH && nextChar == $SLASH && isBlank(outerQuote)) return i;
|
||||
|
||||
if (outerQuote === char) {
|
||||
outerQuote = null;
|
||||
} else if (isBlank(outerQuote) && isQuote(char)) {
|
||||
outerQuote = char;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private _checkNoInterpolation(input: string, location: any): void {
|
||||
var parts = StringWrapper.split(input, INTERPOLATION_REGEXP);
|
||||
if (parts.length > 1) {
|
||||
@ -186,7 +204,7 @@ export class Parser {
|
||||
export class _ParseAST {
|
||||
index: number = 0;
|
||||
constructor(public input: string, public location: any, public tokens: any[],
|
||||
public reflector: Reflector, public parseAction: boolean) {}
|
||||
public parseAction: boolean) {}
|
||||
|
||||
peek(offset: number): Token {
|
||||
var i = this.index + offset;
|
||||
@ -526,16 +544,14 @@ export class _ParseAST {
|
||||
if (this.optionalCharacter($LPAREN)) {
|
||||
let args = this.parseCallArguments();
|
||||
this.expectCharacter($RPAREN);
|
||||
let fn = this.reflector.method(id);
|
||||
return isSafe ? new SafeMethodCall(receiver, id, fn, args) :
|
||||
new MethodCall(receiver, id, fn, args);
|
||||
return isSafe ? new SafeMethodCall(receiver, id, args) : new MethodCall(receiver, id, args);
|
||||
|
||||
} else {
|
||||
if (isSafe) {
|
||||
if (this.optionalOperator("=")) {
|
||||
this.error("The '?.' operator cannot be used in the assignment");
|
||||
} else {
|
||||
return new SafePropertyRead(receiver, id, this.reflector.getter(id));
|
||||
return new SafePropertyRead(receiver, id);
|
||||
}
|
||||
} else {
|
||||
if (this.optionalOperator("=")) {
|
||||
@ -544,9 +560,9 @@ export class _ParseAST {
|
||||
}
|
||||
|
||||
let value = this.parseConditional();
|
||||
return new PropertyWrite(receiver, id, this.reflector.setter(id), value);
|
||||
return new PropertyWrite(receiver, id, value);
|
||||
} else {
|
||||
return new PropertyRead(receiver, id, this.reflector.getter(id));
|
||||
return new PropertyRead(receiver, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -656,39 +672,39 @@ class SimpleExpressionChecker implements AstVisitor {
|
||||
|
||||
simple = true;
|
||||
|
||||
visitImplicitReceiver(ast: ImplicitReceiver) {}
|
||||
visitImplicitReceiver(ast: ImplicitReceiver, context: any) {}
|
||||
|
||||
visitInterpolation(ast: Interpolation) { this.simple = false; }
|
||||
visitInterpolation(ast: Interpolation, context: any) { this.simple = false; }
|
||||
|
||||
visitLiteralPrimitive(ast: LiteralPrimitive) {}
|
||||
visitLiteralPrimitive(ast: LiteralPrimitive, context: any) {}
|
||||
|
||||
visitPropertyRead(ast: PropertyRead) {}
|
||||
visitPropertyRead(ast: PropertyRead, context: any) {}
|
||||
|
||||
visitPropertyWrite(ast: PropertyWrite) { this.simple = false; }
|
||||
visitPropertyWrite(ast: PropertyWrite, context: any) { this.simple = false; }
|
||||
|
||||
visitSafePropertyRead(ast: SafePropertyRead) { this.simple = false; }
|
||||
visitSafePropertyRead(ast: SafePropertyRead, context: any) { this.simple = false; }
|
||||
|
||||
visitMethodCall(ast: MethodCall) { this.simple = false; }
|
||||
visitMethodCall(ast: MethodCall, context: any) { this.simple = false; }
|
||||
|
||||
visitSafeMethodCall(ast: SafeMethodCall) { this.simple = false; }
|
||||
visitSafeMethodCall(ast: SafeMethodCall, context: any) { this.simple = false; }
|
||||
|
||||
visitFunctionCall(ast: FunctionCall) { this.simple = false; }
|
||||
visitFunctionCall(ast: FunctionCall, context: any) { this.simple = false; }
|
||||
|
||||
visitLiteralArray(ast: LiteralArray) { this.visitAll(ast.expressions); }
|
||||
visitLiteralArray(ast: LiteralArray, context: any) { this.visitAll(ast.expressions); }
|
||||
|
||||
visitLiteralMap(ast: LiteralMap) { this.visitAll(ast.values); }
|
||||
visitLiteralMap(ast: LiteralMap, context: any) { this.visitAll(ast.values); }
|
||||
|
||||
visitBinary(ast: Binary) { this.simple = false; }
|
||||
visitBinary(ast: Binary, context: any) { this.simple = false; }
|
||||
|
||||
visitPrefixNot(ast: PrefixNot) { this.simple = false; }
|
||||
visitPrefixNot(ast: PrefixNot, context: any) { this.simple = false; }
|
||||
|
||||
visitConditional(ast: Conditional) { this.simple = false; }
|
||||
visitConditional(ast: Conditional, context: any) { this.simple = false; }
|
||||
|
||||
visitPipe(ast: BindingPipe) { this.simple = false; }
|
||||
visitPipe(ast: BindingPipe, context: any) { this.simple = false; }
|
||||
|
||||
visitKeyedRead(ast: KeyedRead) { this.simple = false; }
|
||||
visitKeyedRead(ast: KeyedRead, context: any) { this.simple = false; }
|
||||
|
||||
visitKeyedWrite(ast: KeyedWrite) { this.simple = false; }
|
||||
visitKeyedWrite(ast: KeyedWrite, context: any) { this.simple = false; }
|
||||
|
||||
visitAll(asts: any[]): any[] {
|
||||
var res = ListWrapper.createFixedSize(asts.length);
|
||||
@ -698,7 +714,7 @@ class SimpleExpressionChecker implements AstVisitor {
|
||||
return res;
|
||||
}
|
||||
|
||||
visitChain(ast: Chain) { this.simple = false; }
|
||||
visitChain(ast: Chain, context: any) { this.simple = false; }
|
||||
|
||||
visitQuote(ast: Quote) { this.simple = false; }
|
||||
visitQuote(ast: Quote, context: any) { this.simple = false; }
|
||||
}
|
@ -12,6 +12,24 @@ export class HtmlTextAst implements HtmlAst {
|
||||
visit(visitor: HtmlAstVisitor, context: any): any { return visitor.visitText(this, context); }
|
||||
}
|
||||
|
||||
export class HtmlExpansionAst implements HtmlAst {
|
||||
constructor(public switchValue: string, public type: string, public cases: HtmlExpansionCaseAst[],
|
||||
public sourceSpan: ParseSourceSpan, public switchValueSourceSpan: ParseSourceSpan) {}
|
||||
visit(visitor: HtmlAstVisitor, context: any): any {
|
||||
return visitor.visitExpansion(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class HtmlExpansionCaseAst implements HtmlAst {
|
||||
constructor(public value: string, public expression: HtmlAst[],
|
||||
public sourceSpan: ParseSourceSpan, public valueSourceSpan: ParseSourceSpan,
|
||||
public expSourceSpan: ParseSourceSpan) {}
|
||||
|
||||
visit(visitor: HtmlAstVisitor, context: any): any {
|
||||
return visitor.visitExpansionCase(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class HtmlAttrAst implements HtmlAst {
|
||||
constructor(public name: string, public value: string, public sourceSpan: ParseSourceSpan) {}
|
||||
visit(visitor: HtmlAstVisitor, context: any): any { return visitor.visitAttr(this, context); }
|
||||
@ -34,6 +52,8 @@ export interface HtmlAstVisitor {
|
||||
visitAttr(ast: HtmlAttrAst, context: any): any;
|
||||
visitText(ast: HtmlTextAst, context: any): any;
|
||||
visitComment(ast: HtmlCommentAst, context: any): any;
|
||||
visitExpansion(ast: HtmlExpansionAst, context: any): any;
|
||||
visitExpansionCase(ast: HtmlExpansionCaseAst, context: any): any;
|
||||
}
|
||||
|
||||
export function htmlVisitAll(visitor: HtmlAstVisitor, asts: HtmlAst[], context: any = null): any[] {
|
||||
|
@ -25,6 +25,11 @@ export enum HtmlTokenType {
|
||||
ATTR_NAME,
|
||||
ATTR_VALUE,
|
||||
DOC_TYPE,
|
||||
EXPANSION_FORM_START,
|
||||
EXPANSION_CASE_VALUE,
|
||||
EXPANSION_CASE_EXP_START,
|
||||
EXPANSION_CASE_EXP_END,
|
||||
EXPANSION_FORM_END,
|
||||
EOF
|
||||
}
|
||||
|
||||
@ -43,8 +48,10 @@ export class HtmlTokenizeResult {
|
||||
constructor(public tokens: HtmlToken[], public errors: HtmlTokenError[]) {}
|
||||
}
|
||||
|
||||
export function tokenizeHtml(sourceContent: string, sourceUrl: string): HtmlTokenizeResult {
|
||||
return new _HtmlTokenizer(new ParseSourceFile(sourceContent, sourceUrl)).tokenize();
|
||||
export function tokenizeHtml(sourceContent: string, sourceUrl: string,
|
||||
tokenizeExpansionForms: boolean = false): HtmlTokenizeResult {
|
||||
return new _HtmlTokenizer(new ParseSourceFile(sourceContent, sourceUrl), tokenizeExpansionForms)
|
||||
.tokenize();
|
||||
}
|
||||
|
||||
const $EOF = 0;
|
||||
@ -75,6 +82,9 @@ const $GT = 62;
|
||||
const $QUESTION = 63;
|
||||
const $LBRACKET = 91;
|
||||
const $RBRACKET = 93;
|
||||
const $LBRACE = 123;
|
||||
const $RBRACE = 125;
|
||||
const $COMMA = 44;
|
||||
const $A = 65;
|
||||
const $F = 70;
|
||||
const $X = 88;
|
||||
@ -108,16 +118,19 @@ class _HtmlTokenizer {
|
||||
private length: number;
|
||||
// Note: this is always lowercase!
|
||||
private peek: number = -1;
|
||||
private nextPeek: number = -1;
|
||||
private index: number = -1;
|
||||
private line: number = 0;
|
||||
private column: number = -1;
|
||||
private currentTokenStart: ParseLocation;
|
||||
private currentTokenType: HtmlTokenType;
|
||||
|
||||
private expansionCaseStack = [];
|
||||
|
||||
tokens: HtmlToken[] = [];
|
||||
errors: HtmlTokenError[] = [];
|
||||
|
||||
constructor(private file: ParseSourceFile) {
|
||||
constructor(private file: ParseSourceFile, private tokenizeExpansionForms: boolean) {
|
||||
this.input = file.content;
|
||||
this.length = file.content.length;
|
||||
this._advance();
|
||||
@ -149,6 +162,20 @@ class _HtmlTokenizer {
|
||||
} else {
|
||||
this._consumeTagOpen(start);
|
||||
}
|
||||
} else if (isSpecialFormStart(this.peek, this.nextPeek) && this.tokenizeExpansionForms) {
|
||||
this._consumeExpansionFormStart();
|
||||
|
||||
} else if (this.peek === $EQ && this.tokenizeExpansionForms) {
|
||||
this._consumeExpansionCaseStart();
|
||||
|
||||
} else if (this.peek === $RBRACE && this.isInExpansionCase() &&
|
||||
this.tokenizeExpansionForms) {
|
||||
this._consumeExpansionCaseEnd();
|
||||
|
||||
} else if (this.peek === $RBRACE && this.isInExpansionForm() &&
|
||||
this.tokenizeExpansionForms) {
|
||||
this._consumeExpansionFormEnd();
|
||||
|
||||
} else {
|
||||
this._consumeText();
|
||||
}
|
||||
@ -218,6 +245,8 @@ class _HtmlTokenizer {
|
||||
}
|
||||
this.index++;
|
||||
this.peek = this.index >= this.length ? $EOF : StringWrapper.charCodeAt(this.input, this.index);
|
||||
this.nextPeek =
|
||||
this.index + 1 >= this.length ? $EOF : StringWrapper.charCodeAt(this.input, this.index + 1);
|
||||
}
|
||||
|
||||
private _attemptCharCode(charCode: number): boolean {
|
||||
@ -506,20 +535,111 @@ class _HtmlTokenizer {
|
||||
this._endToken(prefixAndName);
|
||||
}
|
||||
|
||||
private _consumeExpansionFormStart() {
|
||||
this._beginToken(HtmlTokenType.EXPANSION_FORM_START, this._getLocation());
|
||||
this._requireCharCode($LBRACE);
|
||||
this._endToken([]);
|
||||
|
||||
this._beginToken(HtmlTokenType.RAW_TEXT, this._getLocation());
|
||||
let condition = this._readUntil($COMMA);
|
||||
this._endToken([condition], this._getLocation());
|
||||
this._requireCharCode($COMMA);
|
||||
this._attemptCharCodeUntilFn(isNotWhitespace);
|
||||
|
||||
this._beginToken(HtmlTokenType.RAW_TEXT, this._getLocation());
|
||||
let type = this._readUntil($COMMA);
|
||||
this._endToken([type], this._getLocation());
|
||||
this._requireCharCode($COMMA);
|
||||
this._attemptCharCodeUntilFn(isNotWhitespace);
|
||||
|
||||
this.expansionCaseStack.push(HtmlTokenType.EXPANSION_FORM_START);
|
||||
}
|
||||
|
||||
private _consumeExpansionCaseStart() {
|
||||
this._requireCharCode($EQ);
|
||||
|
||||
this._beginToken(HtmlTokenType.EXPANSION_CASE_VALUE, this._getLocation());
|
||||
let value = this._readUntil($LBRACE).trim();
|
||||
this._endToken([value], this._getLocation());
|
||||
this._attemptCharCodeUntilFn(isNotWhitespace);
|
||||
|
||||
this._beginToken(HtmlTokenType.EXPANSION_CASE_EXP_START, this._getLocation());
|
||||
this._requireCharCode($LBRACE);
|
||||
this._endToken([], this._getLocation());
|
||||
this._attemptCharCodeUntilFn(isNotWhitespace);
|
||||
|
||||
this.expansionCaseStack.push(HtmlTokenType.EXPANSION_CASE_EXP_START);
|
||||
}
|
||||
|
||||
private _consumeExpansionCaseEnd() {
|
||||
this._beginToken(HtmlTokenType.EXPANSION_CASE_EXP_END, this._getLocation());
|
||||
this._requireCharCode($RBRACE);
|
||||
this._endToken([], this._getLocation());
|
||||
this._attemptCharCodeUntilFn(isNotWhitespace);
|
||||
|
||||
this.expansionCaseStack.pop();
|
||||
}
|
||||
|
||||
private _consumeExpansionFormEnd() {
|
||||
this._beginToken(HtmlTokenType.EXPANSION_FORM_END, this._getLocation());
|
||||
this._requireCharCode($RBRACE);
|
||||
this._endToken([]);
|
||||
|
||||
this.expansionCaseStack.pop();
|
||||
}
|
||||
|
||||
private _consumeText() {
|
||||
var start = this._getLocation();
|
||||
this._beginToken(HtmlTokenType.TEXT, start);
|
||||
var parts = [this._readChar(true)];
|
||||
while (!isTextEnd(this.peek)) {
|
||||
|
||||
var parts = [];
|
||||
let interpolation = false;
|
||||
|
||||
if (this.peek === $LBRACE && this.nextPeek === $LBRACE) {
|
||||
parts.push(this._readChar(true));
|
||||
parts.push(this._readChar(true));
|
||||
interpolation = true;
|
||||
} else {
|
||||
parts.push(this._readChar(true));
|
||||
}
|
||||
|
||||
while (!this.isTextEnd(interpolation)) {
|
||||
if (this.peek === $LBRACE && this.nextPeek === $LBRACE) {
|
||||
parts.push(this._readChar(true));
|
||||
parts.push(this._readChar(true));
|
||||
interpolation = true;
|
||||
} else if (this.peek === $RBRACE && this.nextPeek === $RBRACE && interpolation) {
|
||||
parts.push(this._readChar(true));
|
||||
parts.push(this._readChar(true));
|
||||
interpolation = false;
|
||||
} else {
|
||||
parts.push(this._readChar(true));
|
||||
}
|
||||
}
|
||||
this._endToken([this._processCarriageReturns(parts.join(''))]);
|
||||
}
|
||||
|
||||
private isTextEnd(interpolation: boolean): boolean {
|
||||
if (this.peek === $LT || this.peek === $EOF) return true;
|
||||
if (this.tokenizeExpansionForms) {
|
||||
if (isSpecialFormStart(this.peek, this.nextPeek)) return true;
|
||||
if (this.peek === $RBRACE && !interpolation &&
|
||||
(this.isInExpansionCase() || this.isInExpansionForm()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private _savePosition(): number[] {
|
||||
return [this.peek, this.index, this.column, this.line, this.tokens.length];
|
||||
}
|
||||
|
||||
private _readUntil(char: number): string {
|
||||
let start = this.index;
|
||||
this._attemptUntilChar(char);
|
||||
return this.input.substring(start, this.index);
|
||||
}
|
||||
|
||||
private _restorePosition(position: number[]): void {
|
||||
this.peek = position[0];
|
||||
this.index = position[1];
|
||||
@ -531,6 +651,18 @@ class _HtmlTokenizer {
|
||||
this.tokens = ListWrapper.slice(this.tokens, 0, nbTokens);
|
||||
}
|
||||
}
|
||||
|
||||
private isInExpansionCase(): boolean {
|
||||
return this.expansionCaseStack.length > 0 &&
|
||||
this.expansionCaseStack[this.expansionCaseStack.length - 1] ===
|
||||
HtmlTokenType.EXPANSION_CASE_EXP_START;
|
||||
}
|
||||
|
||||
private isInExpansionForm(): boolean {
|
||||
return this.expansionCaseStack.length > 0 &&
|
||||
this.expansionCaseStack[this.expansionCaseStack.length - 1] ===
|
||||
HtmlTokenType.EXPANSION_FORM_START;
|
||||
}
|
||||
}
|
||||
|
||||
function isNotWhitespace(code: number): boolean {
|
||||
@ -558,8 +690,8 @@ function isNamedEntityEnd(code: number): boolean {
|
||||
return code == $SEMICOLON || code == $EOF || !isAsciiLetter(code);
|
||||
}
|
||||
|
||||
function isTextEnd(code: number): boolean {
|
||||
return code === $LT || code === $EOF;
|
||||
function isSpecialFormStart(peek: number, nextPeek: number): boolean {
|
||||
return peek === $LBRACE && nextPeek != $LBRACE;
|
||||
}
|
||||
|
||||
function isAsciiLetter(code: number): boolean {
|
||||
|
@ -11,7 +11,15 @@ import {
|
||||
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
import {HtmlAst, HtmlAttrAst, HtmlTextAst, HtmlCommentAst, HtmlElementAst} from './html_ast';
|
||||
import {
|
||||
HtmlAst,
|
||||
HtmlAttrAst,
|
||||
HtmlTextAst,
|
||||
HtmlCommentAst,
|
||||
HtmlElementAst,
|
||||
HtmlExpansionAst,
|
||||
HtmlExpansionCaseAst
|
||||
} from './html_ast';
|
||||
|
||||
import {Injectable} from 'angular2/src/core/di';
|
||||
import {HtmlToken, HtmlTokenType, tokenizeHtml} from './html_lexer';
|
||||
@ -32,8 +40,9 @@ export class HtmlParseTreeResult {
|
||||
|
||||
@Injectable()
|
||||
export class HtmlParser {
|
||||
parse(sourceContent: string, sourceUrl: string): HtmlParseTreeResult {
|
||||
var tokensAndErrors = tokenizeHtml(sourceContent, sourceUrl);
|
||||
parse(sourceContent: string, sourceUrl: string,
|
||||
parseExpansionForms: boolean = false): HtmlParseTreeResult {
|
||||
var tokensAndErrors = tokenizeHtml(sourceContent, sourceUrl, parseExpansionForms);
|
||||
var treeAndErrors = new TreeBuilder(tokensAndErrors.tokens).build();
|
||||
return new HtmlParseTreeResult(treeAndErrors.rootNodes, (<ParseError[]>tokensAndErrors.errors)
|
||||
.concat(treeAndErrors.errors));
|
||||
@ -68,6 +77,8 @@ class TreeBuilder {
|
||||
this.peek.type === HtmlTokenType.ESCAPABLE_RAW_TEXT) {
|
||||
this._closeVoidElement();
|
||||
this._consumeText(this._advance());
|
||||
} else if (this.peek.type === HtmlTokenType.EXPANSION_FORM_START) {
|
||||
this._consumeExpansion(this._advance());
|
||||
} else {
|
||||
// Skip all other tokens...
|
||||
this._advance();
|
||||
@ -105,6 +116,106 @@ class TreeBuilder {
|
||||
this._addToParent(new HtmlCommentAst(value, token.sourceSpan));
|
||||
}
|
||||
|
||||
private _consumeExpansion(token: HtmlToken) {
|
||||
let switchValue = this._advance();
|
||||
|
||||
let type = this._advance();
|
||||
let cases = [];
|
||||
|
||||
// read =
|
||||
while (this.peek.type === HtmlTokenType.EXPANSION_CASE_VALUE) {
|
||||
let expCase = this._parseExpansionCase();
|
||||
if (isBlank(expCase)) return; // error
|
||||
cases.push(expCase);
|
||||
}
|
||||
|
||||
// read the final }
|
||||
if (this.peek.type !== HtmlTokenType.EXPANSION_FORM_END) {
|
||||
this.errors.push(
|
||||
HtmlTreeError.create(null, this.peek.sourceSpan, `Invalid expansion form. Missing '}'.`));
|
||||
return;
|
||||
}
|
||||
this._advance();
|
||||
|
||||
let mainSourceSpan = new ParseSourceSpan(token.sourceSpan.start, this.peek.sourceSpan.end);
|
||||
this._addToParent(new HtmlExpansionAst(switchValue.parts[0], type.parts[0], cases,
|
||||
mainSourceSpan, switchValue.sourceSpan));
|
||||
}
|
||||
|
||||
private _parseExpansionCase(): HtmlExpansionCaseAst {
|
||||
let value = this._advance();
|
||||
|
||||
// read {
|
||||
if (this.peek.type !== HtmlTokenType.EXPANSION_CASE_EXP_START) {
|
||||
this.errors.push(HtmlTreeError.create(null, this.peek.sourceSpan,
|
||||
`Invalid expansion form. Missing '{'.,`));
|
||||
return null;
|
||||
}
|
||||
|
||||
// read until }
|
||||
let start = this._advance();
|
||||
|
||||
let exp = this._collectExpansionExpTokens(start);
|
||||
if (isBlank(exp)) return null;
|
||||
|
||||
let end = this._advance();
|
||||
exp.push(new HtmlToken(HtmlTokenType.EOF, [], end.sourceSpan));
|
||||
|
||||
// parse everything in between { and }
|
||||
let parsedExp = new TreeBuilder(exp).build();
|
||||
if (parsedExp.errors.length > 0) {
|
||||
this.errors = this.errors.concat(<HtmlTreeError[]>parsedExp.errors);
|
||||
return null;
|
||||
}
|
||||
|
||||
let sourceSpan = new ParseSourceSpan(value.sourceSpan.start, end.sourceSpan.end);
|
||||
let expSourceSpan = new ParseSourceSpan(start.sourceSpan.start, end.sourceSpan.end);
|
||||
return new HtmlExpansionCaseAst(value.parts[0], parsedExp.rootNodes, sourceSpan,
|
||||
value.sourceSpan, expSourceSpan);
|
||||
}
|
||||
|
||||
private _collectExpansionExpTokens(start: HtmlToken): HtmlToken[] {
|
||||
let exp = [];
|
||||
let expansionFormStack = [HtmlTokenType.EXPANSION_CASE_EXP_START];
|
||||
|
||||
while (true) {
|
||||
if (this.peek.type === HtmlTokenType.EXPANSION_FORM_START ||
|
||||
this.peek.type === HtmlTokenType.EXPANSION_CASE_EXP_START) {
|
||||
expansionFormStack.push(this.peek.type);
|
||||
}
|
||||
|
||||
if (this.peek.type === HtmlTokenType.EXPANSION_CASE_EXP_END) {
|
||||
if (lastOnStack(expansionFormStack, HtmlTokenType.EXPANSION_CASE_EXP_START)) {
|
||||
expansionFormStack.pop();
|
||||
if (expansionFormStack.length == 0) return exp;
|
||||
|
||||
} else {
|
||||
this.errors.push(
|
||||
HtmlTreeError.create(null, start.sourceSpan, `Invalid expansion form. Missing '}'.`));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.peek.type === HtmlTokenType.EXPANSION_FORM_END) {
|
||||
if (lastOnStack(expansionFormStack, HtmlTokenType.EXPANSION_FORM_START)) {
|
||||
expansionFormStack.pop();
|
||||
} else {
|
||||
this.errors.push(
|
||||
HtmlTreeError.create(null, start.sourceSpan, `Invalid expansion form. Missing '}'.`));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.peek.type === HtmlTokenType.EOF) {
|
||||
this.errors.push(
|
||||
HtmlTreeError.create(null, start.sourceSpan, `Invalid expansion form. Missing '}'.`));
|
||||
return null;
|
||||
}
|
||||
|
||||
exp.push(this._advance());
|
||||
}
|
||||
}
|
||||
|
||||
private _consumeText(token: HtmlToken) {
|
||||
let text = token.parts[0];
|
||||
if (text.length > 0 && text[0] == '\n') {
|
||||
@ -253,3 +364,7 @@ function getElementFullName(prefix: string, localName: string,
|
||||
|
||||
return mergeNsAndName(prefix, localName);
|
||||
}
|
||||
|
||||
function lastOnStack(stack: any[], element: any): boolean {
|
||||
return stack.length > 0 && stack[stack.length - 1] === element;
|
||||
}
|
206
modules/angular2/src/compiler/identifiers.ts
Normal file
206
modules/angular2/src/compiler/identifiers.ts
Normal file
@ -0,0 +1,206 @@
|
||||
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
|
||||
import {AppView} from 'angular2/src/core/linker/view';
|
||||
import {StaticNodeDebugInfo, DebugContext} from 'angular2/src/core/linker/debug_context';
|
||||
import {
|
||||
ViewUtils,
|
||||
flattenNestedViewRenderNodes,
|
||||
interpolate,
|
||||
checkBinding,
|
||||
castByValue,
|
||||
pureProxy1,
|
||||
pureProxy2,
|
||||
pureProxy3,
|
||||
pureProxy4,
|
||||
pureProxy5,
|
||||
pureProxy6,
|
||||
pureProxy7,
|
||||
pureProxy8,
|
||||
pureProxy9,
|
||||
pureProxy10
|
||||
} from 'angular2/src/core/linker/view_utils';
|
||||
import {
|
||||
uninitialized,
|
||||
devModeEqual,
|
||||
SimpleChange,
|
||||
ValueUnwrapper,
|
||||
ChangeDetectorRef,
|
||||
ChangeDetectorState,
|
||||
ChangeDetectionStrategy
|
||||
} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {AppElement} from 'angular2/src/core/linker/element';
|
||||
import {ElementRef} from 'angular2/src/core/linker/element_ref';
|
||||
import {ViewContainerRef} from 'angular2/src/core/linker/view_container_ref';
|
||||
import {Renderer, RenderComponentType, RenderDebugInfo} from 'angular2/src/core/render/api';
|
||||
import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
|
||||
import {ViewType} from 'angular2/src/core/linker/view_type';
|
||||
import {QueryList} from 'angular2/src/core/linker';
|
||||
import {Injector} from 'angular2/src/core/di/injector';
|
||||
import {TemplateRef, TemplateRef_} from 'angular2/src/core/linker/template_ref';
|
||||
import {MODULE_SUFFIX} from './util';
|
||||
|
||||
var APP_VIEW_MODULE_URL = 'asset:angular2/lib/src/core/linker/view' + MODULE_SUFFIX;
|
||||
var VIEW_UTILS_MODULE_URL = 'asset:angular2/lib/src/core/linker/view_utils' + MODULE_SUFFIX;
|
||||
var CD_MODULE_URL = 'asset:angular2/lib/src/core/change_detection/change_detection' + MODULE_SUFFIX;
|
||||
|
||||
// Reassign the imports to different variables so we can
|
||||
// define static variables with the name of the import.
|
||||
// (only needed for Dart).
|
||||
var impViewUtils = ViewUtils;
|
||||
var impAppView = AppView;
|
||||
var impDebugContext = DebugContext;
|
||||
var impAppElement = AppElement;
|
||||
var impElementRef = ElementRef;
|
||||
var impViewContainerRef = ViewContainerRef;
|
||||
var impChangeDetectorRef = ChangeDetectorRef;
|
||||
var impRenderComponentType = RenderComponentType;
|
||||
var impQueryList = QueryList;
|
||||
var impTemplateRef = TemplateRef;
|
||||
var impTemplateRef_ = TemplateRef_;
|
||||
var impValueUnwrapper = ValueUnwrapper;
|
||||
var impInjector = Injector;
|
||||
var impViewEncapsulation = ViewEncapsulation;
|
||||
var impViewType = ViewType;
|
||||
var impChangeDetectionStrategy = ChangeDetectionStrategy;
|
||||
var impStaticNodeDebugInfo = StaticNodeDebugInfo;
|
||||
var impRenderer = Renderer;
|
||||
var impSimpleChange = SimpleChange;
|
||||
var impUninitialized = uninitialized;
|
||||
var impChangeDetectorState = ChangeDetectorState;
|
||||
var impFlattenNestedViewRenderNodes = flattenNestedViewRenderNodes;
|
||||
var impDevModeEqual = devModeEqual;
|
||||
var impInterpolate = interpolate;
|
||||
var impCheckBinding = checkBinding;
|
||||
var impCastByValue = castByValue;
|
||||
|
||||
export class Identifiers {
|
||||
static ViewUtils = new CompileIdentifierMetadata({
|
||||
name: 'ViewUtils',
|
||||
moduleUrl: 'asset:angular2/lib/src/core/linker/view_utils' + MODULE_SUFFIX,
|
||||
runtime: impViewUtils
|
||||
});
|
||||
static AppView = new CompileIdentifierMetadata(
|
||||
{name: 'AppView', moduleUrl: APP_VIEW_MODULE_URL, runtime: impAppView});
|
||||
static AppElement = new CompileIdentifierMetadata({
|
||||
name: 'AppElement',
|
||||
moduleUrl: 'asset:angular2/lib/src/core/linker/element' + MODULE_SUFFIX,
|
||||
runtime: impAppElement
|
||||
});
|
||||
static ElementRef = new CompileIdentifierMetadata({
|
||||
name: 'ElementRef',
|
||||
moduleUrl: 'asset:angular2/lib/src/core/linker/element_ref' + MODULE_SUFFIX,
|
||||
runtime: impElementRef
|
||||
});
|
||||
static ViewContainerRef = new CompileIdentifierMetadata({
|
||||
name: 'ViewContainerRef',
|
||||
moduleUrl: 'asset:angular2/lib/src/core/linker/view_container_ref' + MODULE_SUFFIX,
|
||||
runtime: impViewContainerRef
|
||||
});
|
||||
static ChangeDetectorRef = new CompileIdentifierMetadata({
|
||||
name: 'ChangeDetectorRef',
|
||||
moduleUrl: 'asset:angular2/lib/src/core/change_detection/change_detector_ref' + MODULE_SUFFIX,
|
||||
runtime: impChangeDetectorRef
|
||||
});
|
||||
static RenderComponentType = new CompileIdentifierMetadata({
|
||||
name: 'RenderComponentType',
|
||||
moduleUrl: 'asset:angular2/lib/src/core/render/api' + MODULE_SUFFIX,
|
||||
runtime: impRenderComponentType
|
||||
});
|
||||
static QueryList = new CompileIdentifierMetadata({
|
||||
name: 'QueryList',
|
||||
moduleUrl: 'asset:angular2/lib/src/core/linker/query_list' + MODULE_SUFFIX,
|
||||
runtime: impQueryList
|
||||
});
|
||||
static TemplateRef = new CompileIdentifierMetadata({
|
||||
name: 'TemplateRef',
|
||||
moduleUrl: 'asset:angular2/lib/src/core/linker/template_ref' + MODULE_SUFFIX,
|
||||
runtime: impTemplateRef
|
||||
});
|
||||
static TemplateRef_ = new CompileIdentifierMetadata({
|
||||
name: 'TemplateRef_',
|
||||
moduleUrl: 'asset:angular2/lib/src/core/linker/template_ref' + MODULE_SUFFIX,
|
||||
runtime: impTemplateRef_
|
||||
});
|
||||
static ValueUnwrapper = new CompileIdentifierMetadata(
|
||||
{name: 'ValueUnwrapper', moduleUrl: CD_MODULE_URL, runtime: impValueUnwrapper});
|
||||
static Injector = new CompileIdentifierMetadata({
|
||||
name: 'Injector',
|
||||
moduleUrl: `asset:angular2/lib/src/core/di/injector${MODULE_SUFFIX}`,
|
||||
runtime: impInjector
|
||||
});
|
||||
static ViewEncapsulation = new CompileIdentifierMetadata({
|
||||
name: 'ViewEncapsulation',
|
||||
moduleUrl: 'asset:angular2/lib/src/core/metadata/view' + MODULE_SUFFIX,
|
||||
runtime: impViewEncapsulation
|
||||
});
|
||||
static ViewType = new CompileIdentifierMetadata({
|
||||
name: 'ViewType',
|
||||
moduleUrl: `asset:angular2/lib/src/core/linker/view_type${MODULE_SUFFIX}`,
|
||||
runtime: impViewType
|
||||
});
|
||||
static ChangeDetectionStrategy = new CompileIdentifierMetadata({
|
||||
name: 'ChangeDetectionStrategy',
|
||||
moduleUrl: CD_MODULE_URL,
|
||||
runtime: impChangeDetectionStrategy
|
||||
});
|
||||
static StaticNodeDebugInfo = new CompileIdentifierMetadata({
|
||||
name: 'StaticNodeDebugInfo',
|
||||
moduleUrl: `asset:angular2/lib/src/core/linker/debug_context${MODULE_SUFFIX}`,
|
||||
runtime: impStaticNodeDebugInfo
|
||||
});
|
||||
static DebugContext = new CompileIdentifierMetadata({
|
||||
name: 'DebugContext',
|
||||
moduleUrl: `asset:angular2/lib/src/core/linker/debug_context${MODULE_SUFFIX}`,
|
||||
runtime: impDebugContext
|
||||
});
|
||||
static Renderer = new CompileIdentifierMetadata({
|
||||
name: 'Renderer',
|
||||
moduleUrl: 'asset:angular2/lib/src/core/render/api' + MODULE_SUFFIX,
|
||||
runtime: impRenderer
|
||||
});
|
||||
static SimpleChange = new CompileIdentifierMetadata(
|
||||
{name: 'SimpleChange', moduleUrl: CD_MODULE_URL, runtime: impSimpleChange});
|
||||
static uninitialized = new CompileIdentifierMetadata(
|
||||
{name: 'uninitialized', moduleUrl: CD_MODULE_URL, runtime: impUninitialized});
|
||||
static ChangeDetectorState = new CompileIdentifierMetadata(
|
||||
{name: 'ChangeDetectorState', moduleUrl: CD_MODULE_URL, runtime: impChangeDetectorState});
|
||||
static checkBinding = new CompileIdentifierMetadata(
|
||||
{name: 'checkBinding', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: impCheckBinding});
|
||||
static flattenNestedViewRenderNodes = new CompileIdentifierMetadata({
|
||||
name: 'flattenNestedViewRenderNodes',
|
||||
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||
runtime: impFlattenNestedViewRenderNodes
|
||||
});
|
||||
static devModeEqual = new CompileIdentifierMetadata(
|
||||
{name: 'devModeEqual', moduleUrl: CD_MODULE_URL, runtime: impDevModeEqual});
|
||||
static interpolate = new CompileIdentifierMetadata(
|
||||
{name: 'interpolate', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: impInterpolate});
|
||||
static castByValue = new CompileIdentifierMetadata(
|
||||
{name: 'castByValue', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: impCastByValue});
|
||||
static pureProxies = [
|
||||
null,
|
||||
new CompileIdentifierMetadata(
|
||||
{name: 'pureProxy1', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy1}),
|
||||
new CompileIdentifierMetadata(
|
||||
{name: 'pureProxy2', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy2}),
|
||||
new CompileIdentifierMetadata(
|
||||
{name: 'pureProxy3', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy3}),
|
||||
new CompileIdentifierMetadata(
|
||||
{name: 'pureProxy4', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy4}),
|
||||
new CompileIdentifierMetadata(
|
||||
{name: 'pureProxy5', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy5}),
|
||||
new CompileIdentifierMetadata(
|
||||
{name: 'pureProxy6', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy6}),
|
||||
new CompileIdentifierMetadata(
|
||||
{name: 'pureProxy7', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy7}),
|
||||
new CompileIdentifierMetadata(
|
||||
{name: 'pureProxy8', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy8}),
|
||||
new CompileIdentifierMetadata(
|
||||
{name: 'pureProxy9', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy9}),
|
||||
new CompileIdentifierMetadata(
|
||||
{name: 'pureProxy10', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: pureProxy10}),
|
||||
];
|
||||
}
|
||||
|
||||
export function identifierToken(identifier: CompileIdentifierMetadata): CompileTokenMetadata {
|
||||
return new CompileTokenMetadata({identifier: identifier});
|
||||
}
|
@ -14,6 +14,8 @@ import {
|
||||
HtmlElementAst,
|
||||
HtmlTextAst,
|
||||
HtmlCommentAst,
|
||||
HtmlExpansionAst,
|
||||
HtmlExpansionCaseAst,
|
||||
HtmlAst
|
||||
} from './html_ast';
|
||||
import {HtmlParser, HtmlParseTreeResult} from './html_parser';
|
||||
@ -84,6 +86,14 @@ export class LegacyHtmlAstTransformer implements HtmlAstVisitor {
|
||||
|
||||
visitText(ast: HtmlTextAst, context: any): HtmlTextAst { return ast; }
|
||||
|
||||
visitExpansion(ast: HtmlExpansionAst, context: any): any {
|
||||
let cases = ast.cases.map(c => c.visit(this, null));
|
||||
return new HtmlExpansionAst(ast.switchValue, ast.type, cases, ast.sourceSpan,
|
||||
ast.switchValueSourceSpan);
|
||||
}
|
||||
|
||||
visitExpansionCase(ast: HtmlExpansionCaseAst, context: any): any { return ast; }
|
||||
|
||||
private _rewriteLongSyntax(ast: HtmlAttrAst): HtmlAttrAst {
|
||||
let m = RegExpWrapper.firstMatch(LONG_SYNTAX_REGEXP, ast.name);
|
||||
let attrName = ast.name;
|
||||
@ -211,9 +221,10 @@ export class LegacyHtmlAstTransformer implements HtmlAstVisitor {
|
||||
|
||||
@Injectable()
|
||||
export class LegacyHtmlParser extends HtmlParser {
|
||||
parse(sourceContent: string, sourceUrl: string): HtmlParseTreeResult {
|
||||
parse(sourceContent: string, sourceUrl: string,
|
||||
parseExpansionForms: boolean = false): HtmlParseTreeResult {
|
||||
let transformer = new LegacyHtmlAstTransformer();
|
||||
let htmlParseTreeResult = super.parse(sourceContent, sourceUrl);
|
||||
let htmlParseTreeResult = super.parse(sourceContent, sourceUrl, parseExpansionForms);
|
||||
|
||||
let rootNodes = htmlParseTreeResult.rootNodes.map(node => node.visit(transformer, null));
|
||||
|
||||
|
140
modules/angular2/src/compiler/offline_compiler.ts
Normal file
140
modules/angular2/src/compiler/offline_compiler.ts
Normal file
@ -0,0 +1,140 @@
|
||||
import {
|
||||
CompileDirectiveMetadata,
|
||||
CompileIdentifierMetadata,
|
||||
CompilePipeMetadata,
|
||||
createHostComponentMeta
|
||||
} from './compile_metadata';
|
||||
|
||||
import {BaseException, unimplemented} from 'angular2/src/facade/exceptions';
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {StyleCompiler, StylesCompileDependency, StylesCompileResult} from './style_compiler';
|
||||
import {ViewCompiler, ViewCompileResult} from './view_compiler/view_compiler';
|
||||
import {TemplateParser} from './template_parser';
|
||||
import {DirectiveNormalizer} from './directive_normalizer';
|
||||
import {OutputEmitter} from './output/abstract_emitter';
|
||||
import * as o from './output/output_ast';
|
||||
import {ComponentFactory} from 'angular2/src/core/linker/component_factory';
|
||||
|
||||
import {
|
||||
MODULE_SUFFIX,
|
||||
} from './util';
|
||||
|
||||
var _COMPONENT_FACTORY_IDENTIFIER = new CompileIdentifierMetadata({
|
||||
name: 'ComponentFactory',
|
||||
runtime: ComponentFactory,
|
||||
moduleUrl: `asset:angular2/lib/src/core/linker/component_factory${MODULE_SUFFIX}`
|
||||
});
|
||||
|
||||
export class SourceModule {
|
||||
constructor(public moduleUrl: string, public source: string) {}
|
||||
}
|
||||
|
||||
export class NormalizedComponentWithViewDirectives {
|
||||
constructor(public component: CompileDirectiveMetadata,
|
||||
public directives: CompileDirectiveMetadata[], public pipes: CompilePipeMetadata[]) {}
|
||||
}
|
||||
|
||||
export class OfflineCompiler {
|
||||
constructor(private _directiveNormalizer: DirectiveNormalizer,
|
||||
private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler,
|
||||
private _viewCompiler: ViewCompiler, private _outputEmitter: OutputEmitter) {}
|
||||
|
||||
normalizeDirectiveMetadata(directive: CompileDirectiveMetadata):
|
||||
Promise<CompileDirectiveMetadata> {
|
||||
return this._directiveNormalizer.normalizeDirective(directive);
|
||||
}
|
||||
|
||||
compileTemplates(components: NormalizedComponentWithViewDirectives[]): SourceModule {
|
||||
if (components.length === 0) {
|
||||
throw new BaseException('No components given');
|
||||
}
|
||||
var statements = [];
|
||||
var exportedVars = [];
|
||||
var moduleUrl = _templateModuleUrl(components[0].component);
|
||||
components.forEach(componentWithDirs => {
|
||||
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
|
||||
_assertComponent(compMeta);
|
||||
var compViewFactoryVar = this._compileComponent(compMeta, componentWithDirs.directives,
|
||||
componentWithDirs.pipes, statements);
|
||||
exportedVars.push(compViewFactoryVar);
|
||||
|
||||
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
|
||||
var hostViewFactoryVar = this._compileComponent(hostMeta, [compMeta], [], statements);
|
||||
var compFactoryVar = `${compMeta.type.name}NgFactory`;
|
||||
statements.push(o.variable(compFactoryVar)
|
||||
.set(o.importExpr(_COMPONENT_FACTORY_IDENTIFIER)
|
||||
.instantiate(
|
||||
[
|
||||
o.literal(compMeta.selector),
|
||||
o.variable(hostViewFactoryVar),
|
||||
o.importExpr(compMeta.type)
|
||||
],
|
||||
o.importType(_COMPONENT_FACTORY_IDENTIFIER, null,
|
||||
[o.TypeModifier.Const])))
|
||||
.toDeclStmt(null, [o.StmtModifier.Final]));
|
||||
exportedVars.push(compFactoryVar);
|
||||
});
|
||||
return this._codegenSourceModule(moduleUrl, statements, exportedVars);
|
||||
}
|
||||
|
||||
compileStylesheet(stylesheetUrl: string, cssText: string): SourceModule[] {
|
||||
var plainStyles = this._styleCompiler.compileStylesheet(stylesheetUrl, cssText, false);
|
||||
var shimStyles = this._styleCompiler.compileStylesheet(stylesheetUrl, cssText, true);
|
||||
return [
|
||||
this._codegenSourceModule(_stylesModuleUrl(stylesheetUrl, false),
|
||||
_resolveStyleStatements(plainStyles), [plainStyles.stylesVar]),
|
||||
this._codegenSourceModule(_stylesModuleUrl(stylesheetUrl, true),
|
||||
_resolveStyleStatements(shimStyles), [shimStyles.stylesVar])
|
||||
];
|
||||
}
|
||||
|
||||
private _compileComponent(compMeta: CompileDirectiveMetadata,
|
||||
directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[],
|
||||
targetStatements: o.Statement[]): string {
|
||||
var styleResult = this._styleCompiler.compileComponent(compMeta);
|
||||
var parsedTemplate = this._templateParser.parse(compMeta, compMeta.template.template,
|
||||
directives, pipes, compMeta.type.name);
|
||||
var viewResult = this._viewCompiler.compileComponent(compMeta, parsedTemplate,
|
||||
o.variable(styleResult.stylesVar), pipes);
|
||||
ListWrapper.addAll(targetStatements, _resolveStyleStatements(styleResult));
|
||||
ListWrapper.addAll(targetStatements, _resolveViewStatements(viewResult));
|
||||
return viewResult.viewFactoryVar;
|
||||
}
|
||||
|
||||
|
||||
private _codegenSourceModule(moduleUrl: string, statements: o.Statement[],
|
||||
exportedVars: string[]): SourceModule {
|
||||
return new SourceModule(
|
||||
moduleUrl, this._outputEmitter.emitStatements(moduleUrl, statements, exportedVars));
|
||||
}
|
||||
}
|
||||
|
||||
function _resolveViewStatements(compileResult: ViewCompileResult): o.Statement[] {
|
||||
compileResult.dependencies.forEach(
|
||||
(dep) => { dep.factoryPlaceholder.moduleUrl = _templateModuleUrl(dep.comp); });
|
||||
return compileResult.statements;
|
||||
}
|
||||
|
||||
|
||||
function _resolveStyleStatements(compileResult: StylesCompileResult): o.Statement[] {
|
||||
compileResult.dependencies.forEach((dep) => {
|
||||
dep.valuePlaceholder.moduleUrl = _stylesModuleUrl(dep.sourceUrl, dep.isShimmed);
|
||||
});
|
||||
return compileResult.statements;
|
||||
}
|
||||
|
||||
function _templateModuleUrl(comp: CompileDirectiveMetadata): string {
|
||||
var moduleUrl = comp.type.moduleUrl;
|
||||
var urlWithoutSuffix = moduleUrl.substring(0, moduleUrl.length - MODULE_SUFFIX.length);
|
||||
return `${urlWithoutSuffix}.ngfactory${MODULE_SUFFIX}`;
|
||||
}
|
||||
|
||||
function _stylesModuleUrl(stylesheetUrl: string, shim: boolean): string {
|
||||
return shim ? `${stylesheetUrl}.shim${MODULE_SUFFIX}` : `${stylesheetUrl}${MODULE_SUFFIX}`;
|
||||
}
|
||||
|
||||
function _assertComponent(meta: CompileDirectiveMetadata) {
|
||||
if (!meta.isComponent) {
|
||||
throw new BaseException(`Could not compile '${meta.type.name}' because it is not a component.`);
|
||||
}
|
||||
}
|
424
modules/angular2/src/compiler/output/abstract_emitter.ts
Normal file
424
modules/angular2/src/compiler/output/abstract_emitter.ts
Normal file
@ -0,0 +1,424 @@
|
||||
import {
|
||||
isPresent,
|
||||
isBlank,
|
||||
isString,
|
||||
evalExpression,
|
||||
RegExpWrapper,
|
||||
StringWrapper
|
||||
} from 'angular2/src/facade/lang';
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {BaseException, unimplemented} from 'angular2/src/facade/exceptions';
|
||||
import * as o from './output_ast';
|
||||
|
||||
var _SINGLE_QUOTE_ESCAPE_STRING_RE = /'|\\|\n|\r|\$/g;
|
||||
export var CATCH_ERROR_VAR = o.variable('error');
|
||||
export var CATCH_STACK_VAR = o.variable('stack');
|
||||
|
||||
export abstract class OutputEmitter {
|
||||
abstract emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string;
|
||||
}
|
||||
|
||||
class _EmittedLine {
|
||||
parts: string[] = [];
|
||||
constructor(public indent: number) {}
|
||||
}
|
||||
|
||||
export class EmitterVisitorContext {
|
||||
static createRoot(exportedVars: string[]): EmitterVisitorContext {
|
||||
return new EmitterVisitorContext(exportedVars, 0);
|
||||
}
|
||||
|
||||
private _lines: _EmittedLine[];
|
||||
private _classes: o.ClassStmt[] = [];
|
||||
|
||||
constructor(private _exportedVars: string[], private _indent: number) {
|
||||
this._lines = [new _EmittedLine(_indent)];
|
||||
}
|
||||
|
||||
private get _currentLine(): _EmittedLine { return this._lines[this._lines.length - 1]; }
|
||||
|
||||
isExportedVar(varName: string): boolean { return this._exportedVars.indexOf(varName) !== -1; }
|
||||
|
||||
println(lastPart: string = ''): void { this.print(lastPart, true); }
|
||||
|
||||
lineIsEmpty(): boolean { return this._currentLine.parts.length === 0; }
|
||||
|
||||
print(part: string, newLine: boolean = false) {
|
||||
if (part.length > 0) {
|
||||
this._currentLine.parts.push(part);
|
||||
}
|
||||
if (newLine) {
|
||||
this._lines.push(new _EmittedLine(this._indent));
|
||||
}
|
||||
}
|
||||
|
||||
removeEmptyLastLine() {
|
||||
if (this.lineIsEmpty()) {
|
||||
this._lines.pop();
|
||||
}
|
||||
}
|
||||
|
||||
incIndent() {
|
||||
this._indent++;
|
||||
this._currentLine.indent = this._indent;
|
||||
}
|
||||
|
||||
decIndent() {
|
||||
this._indent--;
|
||||
this._currentLine.indent = this._indent;
|
||||
}
|
||||
|
||||
pushClass(clazz: o.ClassStmt) { this._classes.push(clazz); }
|
||||
|
||||
popClass(): o.ClassStmt { return this._classes.pop(); }
|
||||
|
||||
get currentClass(): o.ClassStmt {
|
||||
return this._classes.length > 0 ? this._classes[this._classes.length - 1] : null;
|
||||
}
|
||||
|
||||
toSource(): any {
|
||||
var lines = this._lines;
|
||||
if (lines[lines.length - 1].parts.length === 0) {
|
||||
lines = lines.slice(0, lines.length - 1);
|
||||
}
|
||||
return lines.map((line) => {
|
||||
if (line.parts.length > 0) {
|
||||
return _createIndent(line.indent) + line.parts.join('');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.ExpressionVisitor {
|
||||
constructor(private _escapeDollarInStrings: boolean) {}
|
||||
|
||||
visitExpressionStmt(stmt: o.ExpressionStatement, ctx: EmitterVisitorContext): any {
|
||||
stmt.expr.visitExpression(this, ctx);
|
||||
ctx.println(';');
|
||||
return null;
|
||||
}
|
||||
|
||||
visitReturnStmt(stmt: o.ReturnStatement, ctx: EmitterVisitorContext): any {
|
||||
ctx.print(`return `);
|
||||
stmt.value.visitExpression(this, ctx);
|
||||
ctx.println(';');
|
||||
return null;
|
||||
}
|
||||
|
||||
abstract visitCastExpr(ast: o.CastExpr, context: any): any;
|
||||
|
||||
abstract visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any;
|
||||
|
||||
visitIfStmt(stmt: o.IfStmt, ctx: EmitterVisitorContext): any {
|
||||
ctx.print(`if (`);
|
||||
stmt.condition.visitExpression(this, ctx);
|
||||
ctx.print(`) {`);
|
||||
var hasElseCase = isPresent(stmt.falseCase) && stmt.falseCase.length > 0;
|
||||
if (stmt.trueCase.length <= 1 && !hasElseCase) {
|
||||
ctx.print(` `);
|
||||
this.visitAllStatements(stmt.trueCase, ctx);
|
||||
ctx.removeEmptyLastLine();
|
||||
ctx.print(` `);
|
||||
} else {
|
||||
ctx.println();
|
||||
ctx.incIndent();
|
||||
this.visitAllStatements(stmt.trueCase, ctx);
|
||||
ctx.decIndent();
|
||||
if (hasElseCase) {
|
||||
ctx.println(`} else {`);
|
||||
ctx.incIndent();
|
||||
this.visitAllStatements(stmt.falseCase, ctx);
|
||||
ctx.decIndent();
|
||||
}
|
||||
}
|
||||
ctx.println(`}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
abstract visitTryCatchStmt(stmt: o.TryCatchStmt, ctx: EmitterVisitorContext): any;
|
||||
|
||||
visitThrowStmt(stmt: o.ThrowStmt, ctx: EmitterVisitorContext): any {
|
||||
ctx.print(`throw `);
|
||||
stmt.error.visitExpression(this, ctx);
|
||||
ctx.println(`;`);
|
||||
return null;
|
||||
}
|
||||
visitCommentStmt(stmt: o.CommentStmt, ctx: EmitterVisitorContext): any {
|
||||
var lines = stmt.comment.split('\n');
|
||||
lines.forEach((line) => { ctx.println(`// ${line}`); });
|
||||
return null;
|
||||
}
|
||||
abstract visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any;
|
||||
visitWriteVarExpr(expr: o.WriteVarExpr, ctx: EmitterVisitorContext): any {
|
||||
var lineWasEmpty = ctx.lineIsEmpty();
|
||||
if (!lineWasEmpty) {
|
||||
ctx.print('(');
|
||||
}
|
||||
ctx.print(`${expr.name} = `);
|
||||
expr.value.visitExpression(this, ctx);
|
||||
if (!lineWasEmpty) {
|
||||
ctx.print(')');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitWriteKeyExpr(expr: o.WriteKeyExpr, ctx: EmitterVisitorContext): any {
|
||||
var lineWasEmpty = ctx.lineIsEmpty();
|
||||
if (!lineWasEmpty) {
|
||||
ctx.print('(');
|
||||
}
|
||||
expr.receiver.visitExpression(this, ctx);
|
||||
ctx.print(`[`);
|
||||
expr.index.visitExpression(this, ctx);
|
||||
ctx.print(`] = `);
|
||||
expr.value.visitExpression(this, ctx);
|
||||
if (!lineWasEmpty) {
|
||||
ctx.print(')');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitWritePropExpr(expr: o.WritePropExpr, ctx: EmitterVisitorContext): any {
|
||||
var lineWasEmpty = ctx.lineIsEmpty();
|
||||
if (!lineWasEmpty) {
|
||||
ctx.print('(');
|
||||
}
|
||||
expr.receiver.visitExpression(this, ctx);
|
||||
ctx.print(`.${expr.name} = `);
|
||||
expr.value.visitExpression(this, ctx);
|
||||
if (!lineWasEmpty) {
|
||||
ctx.print(')');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitInvokeMethodExpr(expr: o.InvokeMethodExpr, ctx: EmitterVisitorContext): any {
|
||||
expr.receiver.visitExpression(this, ctx);
|
||||
var name = expr.name;
|
||||
if (isPresent(expr.builtin)) {
|
||||
name = this.getBuiltinMethodName(expr.builtin);
|
||||
if (isBlank(name)) {
|
||||
// some builtins just mean to skip the call.
|
||||
// e.g. `bind` in Dart.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
ctx.print(`.${name}(`);
|
||||
this.visitAllExpressions(expr.args, ctx, `,`);
|
||||
ctx.print(`)`);
|
||||
return null;
|
||||
}
|
||||
|
||||
abstract getBuiltinMethodName(method: o.BuiltinMethod): string;
|
||||
|
||||
visitInvokeFunctionExpr(expr: o.InvokeFunctionExpr, ctx: EmitterVisitorContext): any {
|
||||
expr.fn.visitExpression(this, ctx);
|
||||
ctx.print(`(`);
|
||||
this.visitAllExpressions(expr.args, ctx, ',');
|
||||
ctx.print(`)`);
|
||||
return null;
|
||||
}
|
||||
visitReadVarExpr(ast: o.ReadVarExpr, ctx: EmitterVisitorContext): any {
|
||||
var varName = ast.name;
|
||||
if (isPresent(ast.builtin)) {
|
||||
switch (ast.builtin) {
|
||||
case o.BuiltinVar.Super:
|
||||
varName = 'super';
|
||||
break;
|
||||
case o.BuiltinVar.This:
|
||||
varName = 'this';
|
||||
break;
|
||||
case o.BuiltinVar.CatchError:
|
||||
varName = CATCH_ERROR_VAR.name;
|
||||
break;
|
||||
case o.BuiltinVar.CatchStack:
|
||||
varName = CATCH_STACK_VAR.name;
|
||||
break;
|
||||
default:
|
||||
throw new BaseException(`Unknown builtin variable ${ast.builtin}`);
|
||||
}
|
||||
}
|
||||
ctx.print(varName);
|
||||
return null;
|
||||
}
|
||||
visitInstantiateExpr(ast: o.InstantiateExpr, ctx: EmitterVisitorContext): any {
|
||||
ctx.print(`new `);
|
||||
ast.classExpr.visitExpression(this, ctx);
|
||||
ctx.print(`(`);
|
||||
this.visitAllExpressions(ast.args, ctx, ',');
|
||||
ctx.print(`)`);
|
||||
return null;
|
||||
}
|
||||
visitLiteralExpr(ast: o.LiteralExpr, ctx: EmitterVisitorContext): any {
|
||||
var value = ast.value;
|
||||
if (isString(value)) {
|
||||
ctx.print(escapeSingleQuoteString(value, this._escapeDollarInStrings));
|
||||
} else if (isBlank(value)) {
|
||||
ctx.print('null');
|
||||
} else {
|
||||
ctx.print(`${value}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
abstract visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any;
|
||||
|
||||
visitConditionalExpr(ast: o.ConditionalExpr, ctx: EmitterVisitorContext): any {
|
||||
ast.condition.visitExpression(this, ctx);
|
||||
ctx.print('? ');
|
||||
ast.trueCase.visitExpression(this, ctx);
|
||||
ctx.print(': ');
|
||||
ast.falseCase.visitExpression(this, ctx);
|
||||
return null;
|
||||
}
|
||||
visitNotExpr(ast: o.NotExpr, ctx: EmitterVisitorContext): any {
|
||||
ctx.print('!');
|
||||
ast.condition.visitExpression(this, ctx);
|
||||
return null;
|
||||
}
|
||||
abstract visitFunctionExpr(ast: o.FunctionExpr, ctx: EmitterVisitorContext): any;
|
||||
abstract visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, context: any): any;
|
||||
|
||||
visitBinaryOperatorExpr(ast: o.BinaryOperatorExpr, ctx: EmitterVisitorContext): any {
|
||||
var opStr;
|
||||
switch (ast.operator) {
|
||||
case o.BinaryOperator.Equals:
|
||||
opStr = '==';
|
||||
break;
|
||||
case o.BinaryOperator.Identical:
|
||||
opStr = '===';
|
||||
break;
|
||||
case o.BinaryOperator.NotEquals:
|
||||
opStr = '!=';
|
||||
break;
|
||||
case o.BinaryOperator.NotIdentical:
|
||||
opStr = '!==';
|
||||
break;
|
||||
case o.BinaryOperator.And:
|
||||
opStr = '&&';
|
||||
break;
|
||||
case o.BinaryOperator.Or:
|
||||
opStr = '||';
|
||||
break;
|
||||
case o.BinaryOperator.Plus:
|
||||
opStr = '+';
|
||||
break;
|
||||
case o.BinaryOperator.Minus:
|
||||
opStr = '-';
|
||||
break;
|
||||
case o.BinaryOperator.Divide:
|
||||
opStr = '/';
|
||||
break;
|
||||
case o.BinaryOperator.Multiply:
|
||||
opStr = '*';
|
||||
break;
|
||||
case o.BinaryOperator.Modulo:
|
||||
opStr = '%';
|
||||
break;
|
||||
case o.BinaryOperator.Lower:
|
||||
opStr = '<';
|
||||
break;
|
||||
case o.BinaryOperator.LowerEquals:
|
||||
opStr = '<=';
|
||||
break;
|
||||
case o.BinaryOperator.Bigger:
|
||||
opStr = '>';
|
||||
break;
|
||||
case o.BinaryOperator.BiggerEquals:
|
||||
opStr = '>=';
|
||||
break;
|
||||
default:
|
||||
throw new BaseException(`Unknown operator ${ast.operator}`);
|
||||
}
|
||||
ctx.print(`(`);
|
||||
ast.lhs.visitExpression(this, ctx);
|
||||
ctx.print(` ${opStr} `);
|
||||
ast.rhs.visitExpression(this, ctx);
|
||||
ctx.print(`)`);
|
||||
return null;
|
||||
}
|
||||
|
||||
visitReadPropExpr(ast: o.ReadPropExpr, ctx: EmitterVisitorContext): any {
|
||||
ast.receiver.visitExpression(this, ctx);
|
||||
ctx.print(`.`);
|
||||
ctx.print(ast.name);
|
||||
return null;
|
||||
}
|
||||
visitReadKeyExpr(ast: o.ReadKeyExpr, ctx: EmitterVisitorContext): any {
|
||||
ast.receiver.visitExpression(this, ctx);
|
||||
ctx.print(`[`);
|
||||
ast.index.visitExpression(this, ctx);
|
||||
ctx.print(`]`);
|
||||
return null;
|
||||
}
|
||||
visitLiteralArrayExpr(ast: o.LiteralArrayExpr, ctx: EmitterVisitorContext): any {
|
||||
var useNewLine = ast.entries.length > 1;
|
||||
ctx.print(`[`, useNewLine);
|
||||
ctx.incIndent();
|
||||
this.visitAllExpressions(ast.entries, ctx, ',', useNewLine);
|
||||
ctx.decIndent();
|
||||
ctx.print(`]`, useNewLine);
|
||||
return null;
|
||||
}
|
||||
visitLiteralMapExpr(ast: o.LiteralMapExpr, ctx: EmitterVisitorContext): any {
|
||||
var useNewLine = ast.entries.length > 1;
|
||||
ctx.print(`{`, useNewLine);
|
||||
ctx.incIndent();
|
||||
this.visitAllObjects((entry) => {
|
||||
ctx.print(`${escapeSingleQuoteString(entry[0], this._escapeDollarInStrings)}: `);
|
||||
entry[1].visitExpression(this, ctx);
|
||||
}, ast.entries, ctx, ',', useNewLine);
|
||||
ctx.decIndent();
|
||||
ctx.print(`}`, useNewLine);
|
||||
return null;
|
||||
}
|
||||
|
||||
visitAllExpressions(expressions: o.Expression[], ctx: EmitterVisitorContext, separator: string,
|
||||
newLine: boolean = false): void {
|
||||
this.visitAllObjects((expr) => expr.visitExpression(this, ctx), expressions, ctx, separator,
|
||||
newLine);
|
||||
}
|
||||
|
||||
visitAllObjects(handler: Function, expressions: any, ctx: EmitterVisitorContext,
|
||||
separator: string, newLine: boolean = false): void {
|
||||
for (var i = 0; i < expressions.length; i++) {
|
||||
if (i > 0) {
|
||||
ctx.print(separator, newLine);
|
||||
}
|
||||
handler(expressions[i]);
|
||||
}
|
||||
if (newLine) {
|
||||
ctx.println();
|
||||
}
|
||||
}
|
||||
|
||||
visitAllStatements(statements: o.Statement[], ctx: EmitterVisitorContext): void {
|
||||
statements.forEach((stmt) => { return stmt.visitStatement(this, ctx); });
|
||||
}
|
||||
}
|
||||
|
||||
export function escapeSingleQuoteString(input: string, escapeDollar: boolean): any {
|
||||
if (isBlank(input)) {
|
||||
return null;
|
||||
}
|
||||
var body = StringWrapper.replaceAllMapped(input, _SINGLE_QUOTE_ESCAPE_STRING_RE, (match) => {
|
||||
if (match[0] == '$') {
|
||||
return escapeDollar ? '\\$' : '$';
|
||||
} else if (match[0] == '\n') {
|
||||
return '\\n';
|
||||
} else if (match[0] == '\r') {
|
||||
return '\\r';
|
||||
} else {
|
||||
return `\\${match[0]}`;
|
||||
}
|
||||
});
|
||||
return `'${body}'`;
|
||||
}
|
||||
|
||||
function _createIndent(count: number): string {
|
||||
var res = '';
|
||||
for (var i = 0; i < count; i++) {
|
||||
res += ' ';
|
||||
}
|
||||
return res;
|
||||
}
|
164
modules/angular2/src/compiler/output/abstract_js_emitter.ts
Normal file
164
modules/angular2/src/compiler/output/abstract_js_emitter.ts
Normal file
@ -0,0 +1,164 @@
|
||||
import {isPresent} from 'angular2/src/facade/lang';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import * as o from './output_ast';
|
||||
import {
|
||||
EmitterVisitorContext,
|
||||
AbstractEmitterVisitor,
|
||||
CATCH_ERROR_VAR,
|
||||
CATCH_STACK_VAR
|
||||
} from './abstract_emitter';
|
||||
|
||||
export abstract class AbstractJsEmitterVisitor extends AbstractEmitterVisitor {
|
||||
constructor() { super(false); }
|
||||
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
|
||||
ctx.pushClass(stmt);
|
||||
this._visitClassConstructor(stmt, ctx);
|
||||
|
||||
if (isPresent(stmt.parent)) {
|
||||
ctx.print(`${stmt.name}.prototype = Object.create(`);
|
||||
stmt.parent.visitExpression(this, ctx);
|
||||
ctx.println(`.prototype);`);
|
||||
}
|
||||
stmt.getters.forEach((getter) => this._visitClassGetter(stmt, getter, ctx));
|
||||
stmt.methods.forEach((method) => this._visitClassMethod(stmt, method, ctx));
|
||||
ctx.popClass();
|
||||
return null;
|
||||
}
|
||||
|
||||
private _visitClassConstructor(stmt: o.ClassStmt, ctx: EmitterVisitorContext) {
|
||||
ctx.print(`function ${stmt.name}(`);
|
||||
if (isPresent(stmt.constructorMethod)) {
|
||||
this._visitParams(stmt.constructorMethod.params, ctx);
|
||||
}
|
||||
ctx.println(`) {`);
|
||||
ctx.incIndent();
|
||||
if (isPresent(stmt.constructorMethod)) {
|
||||
if (stmt.constructorMethod.body.length > 0) {
|
||||
ctx.println(`var self = this;`);
|
||||
this.visitAllStatements(stmt.constructorMethod.body, ctx);
|
||||
}
|
||||
}
|
||||
ctx.decIndent();
|
||||
ctx.println(`}`);
|
||||
}
|
||||
|
||||
private _visitClassGetter(stmt: o.ClassStmt, getter: o.ClassGetter, ctx: EmitterVisitorContext) {
|
||||
ctx.println(
|
||||
`Object.defineProperty(${stmt.name}.prototype, '${getter.name}', { get: function() {`);
|
||||
ctx.incIndent();
|
||||
if (getter.body.length > 0) {
|
||||
ctx.println(`var self = this;`);
|
||||
this.visitAllStatements(getter.body, ctx);
|
||||
}
|
||||
ctx.decIndent();
|
||||
ctx.println(`}});`);
|
||||
}
|
||||
|
||||
private _visitClassMethod(stmt: o.ClassStmt, method: o.ClassMethod, ctx: EmitterVisitorContext) {
|
||||
ctx.print(`${stmt.name}.prototype.${method.name} = function(`);
|
||||
this._visitParams(method.params, ctx);
|
||||
ctx.println(`) {`);
|
||||
ctx.incIndent();
|
||||
if (method.body.length > 0) {
|
||||
ctx.println(`var self = this;`);
|
||||
this.visitAllStatements(method.body, ctx);
|
||||
}
|
||||
ctx.decIndent();
|
||||
ctx.println(`};`);
|
||||
}
|
||||
|
||||
visitReadVarExpr(ast: o.ReadVarExpr, ctx: EmitterVisitorContext): string {
|
||||
if (ast.builtin === o.BuiltinVar.This) {
|
||||
ctx.print('self');
|
||||
} else if (ast.builtin === o.BuiltinVar.Super) {
|
||||
throw new BaseException(
|
||||
`'super' needs to be handled at a parent ast node, not at the variable level!`);
|
||||
} else {
|
||||
super.visitReadVarExpr(ast, ctx);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
|
||||
ctx.print(`var ${stmt.name} = `);
|
||||
stmt.value.visitExpression(this, ctx);
|
||||
ctx.println(`;`);
|
||||
return null;
|
||||
}
|
||||
visitCastExpr(ast: o.CastExpr, ctx: EmitterVisitorContext): any {
|
||||
ast.value.visitExpression(this, ctx);
|
||||
return null;
|
||||
}
|
||||
visitInvokeFunctionExpr(expr: o.InvokeFunctionExpr, ctx: EmitterVisitorContext): string {
|
||||
var fnExpr = expr.fn;
|
||||
if (fnExpr instanceof o.ReadVarExpr && fnExpr.builtin === o.BuiltinVar.Super) {
|
||||
ctx.currentClass.parent.visitExpression(this, ctx);
|
||||
ctx.print(`.call(this`);
|
||||
if (expr.args.length > 0) {
|
||||
ctx.print(`, `);
|
||||
this.visitAllExpressions(expr.args, ctx, ',');
|
||||
}
|
||||
ctx.print(`)`);
|
||||
} else {
|
||||
super.visitInvokeFunctionExpr(expr, ctx);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitFunctionExpr(ast: o.FunctionExpr, ctx: EmitterVisitorContext): any {
|
||||
ctx.print(`function(`);
|
||||
this._visitParams(ast.params, ctx);
|
||||
ctx.println(`) {`);
|
||||
ctx.incIndent();
|
||||
this.visitAllStatements(ast.statements, ctx);
|
||||
ctx.decIndent();
|
||||
ctx.print(`}`);
|
||||
return null;
|
||||
}
|
||||
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: EmitterVisitorContext): any {
|
||||
ctx.print(`function ${stmt.name}(`);
|
||||
this._visitParams(stmt.params, ctx);
|
||||
ctx.println(`) {`);
|
||||
ctx.incIndent();
|
||||
this.visitAllStatements(stmt.statements, ctx);
|
||||
ctx.decIndent();
|
||||
ctx.println(`}`);
|
||||
return null;
|
||||
}
|
||||
visitTryCatchStmt(stmt: o.TryCatchStmt, ctx: EmitterVisitorContext): any {
|
||||
ctx.println(`try {`);
|
||||
ctx.incIndent();
|
||||
this.visitAllStatements(stmt.bodyStmts, ctx);
|
||||
ctx.decIndent();
|
||||
ctx.println(`} catch (${CATCH_ERROR_VAR.name}) {`);
|
||||
ctx.incIndent();
|
||||
var catchStmts = [
|
||||
<o.Statement>CATCH_STACK_VAR.set(CATCH_ERROR_VAR.prop('stack'))
|
||||
.toDeclStmt(null, [o.StmtModifier.Final])
|
||||
].concat(stmt.catchStmts);
|
||||
this.visitAllStatements(catchStmts, ctx);
|
||||
ctx.decIndent();
|
||||
ctx.println(`}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
private _visitParams(params: o.FnParam[], ctx: EmitterVisitorContext): void {
|
||||
this.visitAllObjects((param) => ctx.print(param.name), params, ctx, ',');
|
||||
}
|
||||
|
||||
getBuiltinMethodName(method: o.BuiltinMethod): string {
|
||||
var name;
|
||||
switch (method) {
|
||||
case o.BuiltinMethod.ConcatArray:
|
||||
name = 'concat';
|
||||
break;
|
||||
case o.BuiltinMethod.SubscribeObservable:
|
||||
name = 'subscribe';
|
||||
break;
|
||||
case o.BuiltinMethod.bind:
|
||||
name = 'bind';
|
||||
break;
|
||||
default:
|
||||
throw new BaseException(`Unknown builtin method: ${method}`);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
381
modules/angular2/src/compiler/output/dart_emitter.ts
Normal file
381
modules/angular2/src/compiler/output/dart_emitter.ts
Normal file
@ -0,0 +1,381 @@
|
||||
import {
|
||||
StringWrapper,
|
||||
RegExpWrapper,
|
||||
isPresent,
|
||||
isBlank,
|
||||
Math,
|
||||
isString,
|
||||
isArray
|
||||
} from 'angular2/src/facade/lang';
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {CompileIdentifierMetadata} from '../compile_metadata';
|
||||
import * as o from './output_ast';
|
||||
import {
|
||||
OutputEmitter,
|
||||
EmitterVisitorContext,
|
||||
AbstractEmitterVisitor,
|
||||
CATCH_ERROR_VAR,
|
||||
CATCH_STACK_VAR,
|
||||
escapeSingleQuoteString
|
||||
} from './abstract_emitter';
|
||||
import {getImportModulePath, ImportEnv} from './path_util';
|
||||
|
||||
var _debugModuleUrl = 'asset://debug/lib';
|
||||
|
||||
export function debugOutputAstAsDart(ast: o.Statement | o.Expression | o.Type | any[]): string {
|
||||
var converter = new _DartEmitterVisitor(_debugModuleUrl);
|
||||
var ctx = EmitterVisitorContext.createRoot([]);
|
||||
var asts: any[];
|
||||
if (isArray(ast)) {
|
||||
asts = <any[]>ast;
|
||||
} else {
|
||||
asts = [ast];
|
||||
}
|
||||
asts.forEach((ast) => {
|
||||
if (ast instanceof o.Statement) {
|
||||
ast.visitStatement(converter, ctx);
|
||||
} else if (ast instanceof o.Expression) {
|
||||
ast.visitExpression(converter, ctx);
|
||||
} else if (ast instanceof o.Type) {
|
||||
ast.visitType(converter, ctx);
|
||||
} else {
|
||||
throw new BaseException(`Don't know how to print debug info for ${ast}`);
|
||||
}
|
||||
});
|
||||
return ctx.toSource();
|
||||
}
|
||||
|
||||
export class DartEmitter implements OutputEmitter {
|
||||
constructor() {}
|
||||
emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string {
|
||||
var srcParts = [];
|
||||
// Note: We are not creating a library here as Dart does not need it.
|
||||
// Dart analzyer might complain about it though.
|
||||
|
||||
var converter = new _DartEmitterVisitor(moduleUrl);
|
||||
var ctx = EmitterVisitorContext.createRoot(exportedVars);
|
||||
converter.visitAllStatements(stmts, ctx);
|
||||
|
||||
converter.importsWithPrefixes.forEach((prefix, importedModuleUrl) => {
|
||||
srcParts.push(
|
||||
`import '${getImportModulePath(moduleUrl, importedModuleUrl, ImportEnv.Dart)}' as ${prefix};`);
|
||||
});
|
||||
srcParts.push(ctx.toSource());
|
||||
return srcParts.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
class _DartEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor {
|
||||
importsWithPrefixes = new Map<string, string>();
|
||||
|
||||
constructor(private _moduleUrl: string) { super(true); }
|
||||
|
||||
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
|
||||
this._visitIdentifier(ast.value, ast.typeParams, ctx);
|
||||
return null;
|
||||
}
|
||||
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
|
||||
if (stmt.hasModifier(o.StmtModifier.Final)) {
|
||||
if (isConstType(stmt.type)) {
|
||||
ctx.print(`const `);
|
||||
} else {
|
||||
ctx.print(`final `);
|
||||
}
|
||||
} else if (isBlank(stmt.type)) {
|
||||
ctx.print(`var `);
|
||||
}
|
||||
if (isPresent(stmt.type)) {
|
||||
stmt.type.visitType(this, ctx);
|
||||
ctx.print(` `);
|
||||
}
|
||||
ctx.print(`${stmt.name} = `);
|
||||
stmt.value.visitExpression(this, ctx);
|
||||
ctx.println(`;`);
|
||||
return null;
|
||||
}
|
||||
visitCastExpr(ast: o.CastExpr, ctx: EmitterVisitorContext): any {
|
||||
ctx.print(`(`);
|
||||
ast.value.visitExpression(this, ctx);
|
||||
ctx.print(` as `);
|
||||
ast.type.visitType(this, ctx);
|
||||
ctx.print(`)`);
|
||||
return null;
|
||||
}
|
||||
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
|
||||
ctx.pushClass(stmt);
|
||||
ctx.print(`class ${stmt.name}`);
|
||||
if (isPresent(stmt.parent)) {
|
||||
ctx.print(` extends `);
|
||||
stmt.parent.visitExpression(this, ctx);
|
||||
}
|
||||
ctx.println(` {`);
|
||||
ctx.incIndent();
|
||||
stmt.fields.forEach((field) => this._visitClassField(field, ctx));
|
||||
if (isPresent(stmt.constructorMethod)) {
|
||||
this._visitClassConstructor(stmt, ctx);
|
||||
}
|
||||
stmt.getters.forEach((getter) => this._visitClassGetter(getter, ctx));
|
||||
stmt.methods.forEach((method) => this._visitClassMethod(method, ctx));
|
||||
ctx.decIndent();
|
||||
ctx.println(`}`);
|
||||
ctx.popClass();
|
||||
return null;
|
||||
}
|
||||
private _visitClassField(field: o.ClassField, ctx: EmitterVisitorContext) {
|
||||
if (field.hasModifier(o.StmtModifier.Final)) {
|
||||
ctx.print(`final `);
|
||||
} else if (isBlank(field.type)) {
|
||||
ctx.print(`var `);
|
||||
}
|
||||
if (isPresent(field.type)) {
|
||||
field.type.visitType(this, ctx);
|
||||
ctx.print(` `);
|
||||
}
|
||||
ctx.println(`${field.name};`);
|
||||
}
|
||||
private _visitClassGetter(getter: o.ClassGetter, ctx: EmitterVisitorContext) {
|
||||
if (isPresent(getter.type)) {
|
||||
getter.type.visitType(this, ctx);
|
||||
ctx.print(` `);
|
||||
}
|
||||
ctx.println(`get ${getter.name} {`);
|
||||
ctx.incIndent();
|
||||
this.visitAllStatements(getter.body, ctx);
|
||||
ctx.decIndent();
|
||||
ctx.println(`}`);
|
||||
}
|
||||
private _visitClassConstructor(stmt: o.ClassStmt, ctx: EmitterVisitorContext) {
|
||||
ctx.print(`${stmt.name}(`);
|
||||
this._visitParams(stmt.constructorMethod.params, ctx);
|
||||
ctx.print(`)`);
|
||||
|
||||
var ctorStmts = stmt.constructorMethod.body;
|
||||
var superCtorExpr = ctorStmts.length > 0 ? getSuperConstructorCallExpr(ctorStmts[0]) : null;
|
||||
if (isPresent(superCtorExpr)) {
|
||||
ctx.print(`: `);
|
||||
superCtorExpr.visitExpression(this, ctx);
|
||||
ctorStmts = ctorStmts.slice(1);
|
||||
}
|
||||
ctx.println(` {`);
|
||||
ctx.incIndent();
|
||||
this.visitAllStatements(ctorStmts, ctx);
|
||||
ctx.decIndent();
|
||||
ctx.println(`}`);
|
||||
}
|
||||
private _visitClassMethod(method: o.ClassMethod, ctx: EmitterVisitorContext) {
|
||||
if (isPresent(method.type)) {
|
||||
method.type.visitType(this, ctx);
|
||||
} else {
|
||||
ctx.print(`void`);
|
||||
}
|
||||
ctx.print(` ${method.name}(`);
|
||||
this._visitParams(method.params, ctx);
|
||||
ctx.println(`) {`);
|
||||
ctx.incIndent();
|
||||
this.visitAllStatements(method.body, ctx);
|
||||
ctx.decIndent();
|
||||
ctx.println(`}`);
|
||||
}
|
||||
|
||||
visitFunctionExpr(ast: o.FunctionExpr, ctx: EmitterVisitorContext): any {
|
||||
ctx.print(`(`);
|
||||
this._visitParams(ast.params, ctx);
|
||||
ctx.println(`) {`);
|
||||
ctx.incIndent();
|
||||
this.visitAllStatements(ast.statements, ctx);
|
||||
ctx.decIndent();
|
||||
ctx.print(`}`);
|
||||
return null;
|
||||
}
|
||||
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: EmitterVisitorContext): any {
|
||||
if (isPresent(stmt.type)) {
|
||||
stmt.type.visitType(this, ctx);
|
||||
} else {
|
||||
ctx.print(`void`);
|
||||
}
|
||||
ctx.print(` ${stmt.name}(`);
|
||||
this._visitParams(stmt.params, ctx);
|
||||
ctx.println(`) {`);
|
||||
ctx.incIndent();
|
||||
this.visitAllStatements(stmt.statements, ctx);
|
||||
ctx.decIndent();
|
||||
ctx.println(`}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
getBuiltinMethodName(method: o.BuiltinMethod): string {
|
||||
var name;
|
||||
switch (method) {
|
||||
case o.BuiltinMethod.ConcatArray:
|
||||
name = '.addAll';
|
||||
break;
|
||||
case o.BuiltinMethod.SubscribeObservable:
|
||||
name = 'listen';
|
||||
break;
|
||||
case o.BuiltinMethod.bind:
|
||||
name = null;
|
||||
break;
|
||||
default:
|
||||
throw new BaseException(`Unknown builtin method: ${method}`);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
visitTryCatchStmt(stmt: o.TryCatchStmt, ctx: EmitterVisitorContext): any {
|
||||
ctx.println(`try {`);
|
||||
ctx.incIndent();
|
||||
this.visitAllStatements(stmt.bodyStmts, ctx);
|
||||
ctx.decIndent();
|
||||
ctx.println(`} catch (${CATCH_ERROR_VAR.name}, ${CATCH_STACK_VAR.name}) {`);
|
||||
ctx.incIndent();
|
||||
this.visitAllStatements(stmt.catchStmts, ctx);
|
||||
ctx.decIndent();
|
||||
ctx.println(`}`);
|
||||
return null;
|
||||
}
|
||||
visitBinaryOperatorExpr(ast: o.BinaryOperatorExpr, ctx: EmitterVisitorContext): any {
|
||||
switch (ast.operator) {
|
||||
case o.BinaryOperator.Identical:
|
||||
ctx.print(`identical(`);
|
||||
ast.lhs.visitExpression(this, ctx);
|
||||
ctx.print(`, `);
|
||||
ast.rhs.visitExpression(this, ctx);
|
||||
ctx.print(`)`);
|
||||
break;
|
||||
case o.BinaryOperator.NotIdentical:
|
||||
ctx.print(`!identical(`);
|
||||
ast.lhs.visitExpression(this, ctx);
|
||||
ctx.print(`, `);
|
||||
ast.rhs.visitExpression(this, ctx);
|
||||
ctx.print(`)`);
|
||||
break;
|
||||
default:
|
||||
super.visitBinaryOperatorExpr(ast, ctx);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitLiteralArrayExpr(ast: o.LiteralArrayExpr, ctx: EmitterVisitorContext): any {
|
||||
if (isConstType(ast.type)) {
|
||||
ctx.print(`const `);
|
||||
}
|
||||
return super.visitLiteralArrayExpr(ast, ctx);
|
||||
}
|
||||
visitLiteralMapExpr(ast: o.LiteralMapExpr, ctx: EmitterVisitorContext): any {
|
||||
if (isConstType(ast.type)) {
|
||||
ctx.print(`const `);
|
||||
}
|
||||
if (isPresent(ast.valueType)) {
|
||||
ctx.print(`<String, `);
|
||||
ast.valueType.visitType(this, ctx);
|
||||
ctx.print(`>`);
|
||||
}
|
||||
return super.visitLiteralMapExpr(ast, ctx);
|
||||
}
|
||||
visitInstantiateExpr(ast: o.InstantiateExpr, ctx: EmitterVisitorContext): any {
|
||||
ctx.print(isConstType(ast.type) ? `const` : `new`);
|
||||
ctx.print(' ');
|
||||
ast.classExpr.visitExpression(this, ctx);
|
||||
ctx.print(`(`);
|
||||
this.visitAllExpressions(ast.args, ctx, `,`);
|
||||
ctx.print(`)`);
|
||||
return null;
|
||||
}
|
||||
visitBuiltintType(type: o.BuiltinType, ctx: EmitterVisitorContext): any {
|
||||
var typeStr;
|
||||
switch (type.name) {
|
||||
case o.BuiltinTypeName.Bool:
|
||||
typeStr = 'bool';
|
||||
break;
|
||||
case o.BuiltinTypeName.Dynamic:
|
||||
typeStr = 'dynamic';
|
||||
break;
|
||||
case o.BuiltinTypeName.Function:
|
||||
typeStr = 'Function';
|
||||
break;
|
||||
case o.BuiltinTypeName.Number:
|
||||
typeStr = 'num';
|
||||
break;
|
||||
case o.BuiltinTypeName.Int:
|
||||
typeStr = 'int';
|
||||
break;
|
||||
case o.BuiltinTypeName.String:
|
||||
typeStr = 'String';
|
||||
break;
|
||||
default:
|
||||
throw new BaseException(`Unsupported builtin type ${type.name}`);
|
||||
}
|
||||
ctx.print(typeStr);
|
||||
return null;
|
||||
}
|
||||
visitExternalType(ast: o.ExternalType, ctx: EmitterVisitorContext): any {
|
||||
this._visitIdentifier(ast.value, ast.typeParams, ctx);
|
||||
return null;
|
||||
}
|
||||
visitArrayType(type: o.ArrayType, ctx: EmitterVisitorContext): any {
|
||||
ctx.print(`List<`);
|
||||
if (isPresent(type.of)) {
|
||||
type.of.visitType(this, ctx);
|
||||
} else {
|
||||
ctx.print(`dynamic`);
|
||||
}
|
||||
ctx.print(`>`);
|
||||
return null;
|
||||
}
|
||||
visitMapType(type: o.MapType, ctx: EmitterVisitorContext): any {
|
||||
ctx.print(`Map<String, `);
|
||||
if (isPresent(type.valueType)) {
|
||||
type.valueType.visitType(this, ctx);
|
||||
} else {
|
||||
ctx.print(`dynamic`);
|
||||
}
|
||||
ctx.print(`>`);
|
||||
return null;
|
||||
}
|
||||
|
||||
private _visitParams(params: o.FnParam[], ctx: EmitterVisitorContext): void {
|
||||
this.visitAllObjects((param) => {
|
||||
if (isPresent(param.type)) {
|
||||
param.type.visitType(this, ctx);
|
||||
ctx.print(' ');
|
||||
}
|
||||
ctx.print(param.name);
|
||||
}, params, ctx, ',');
|
||||
}
|
||||
|
||||
private _visitIdentifier(value: CompileIdentifierMetadata, typeParams: o.Type[],
|
||||
ctx: EmitterVisitorContext): void {
|
||||
if (isPresent(value.moduleUrl) && value.moduleUrl != this._moduleUrl) {
|
||||
var prefix = this.importsWithPrefixes.get(value.moduleUrl);
|
||||
if (isBlank(prefix)) {
|
||||
prefix = `import${this.importsWithPrefixes.size}`;
|
||||
this.importsWithPrefixes.set(value.moduleUrl, prefix);
|
||||
}
|
||||
ctx.print(`${prefix}.`);
|
||||
}
|
||||
ctx.print(value.name);
|
||||
if (isPresent(typeParams) && typeParams.length > 0) {
|
||||
ctx.print(`<`);
|
||||
this.visitAllObjects((type) => type.visitType(this, ctx), typeParams, ctx, ',');
|
||||
ctx.print(`>`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getSuperConstructorCallExpr(stmt: o.Statement): o.Expression {
|
||||
if (stmt instanceof o.ExpressionStatement) {
|
||||
var expr = stmt.expr;
|
||||
if (expr instanceof o.InvokeFunctionExpr) {
|
||||
var fn = expr.fn;
|
||||
if (fn instanceof o.ReadVarExpr) {
|
||||
if (fn.builtin === o.BuiltinVar.Super) {
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isConstType(type: o.Type): boolean {
|
||||
return isPresent(type) && type.hasModifier(o.TypeModifier.Const);
|
||||
}
|
62
modules/angular2/src/compiler/output/interpretive_view.ts
Normal file
62
modules/angular2/src/compiler/output/interpretive_view.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import {isPresent} from 'angular2/src/facade/lang';
|
||||
import {AppView} from 'angular2/src/core/linker/view';
|
||||
import {AppElement} from 'angular2/src/core/linker/element';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {InstanceFactory, DynamicInstance} from './output_interpreter';
|
||||
|
||||
export class InterpretiveAppViewInstanceFactory implements InstanceFactory {
|
||||
createInstance(superClass: any, clazz: any, args: any[], props: Map<string, any>,
|
||||
getters: Map<string, Function>, methods: Map<string, Function>): any {
|
||||
if (superClass === AppView) {
|
||||
return new _InterpretiveAppView(args, props, getters, methods);
|
||||
}
|
||||
throw new BaseException(`Can't instantiate class ${superClass} in interpretative mode`);
|
||||
}
|
||||
}
|
||||
|
||||
class _InterpretiveAppView extends AppView<any> implements DynamicInstance {
|
||||
constructor(args: any[], public props: Map<string, any>, public getters: Map<string, Function>,
|
||||
public methods: Map<string, Function>) {
|
||||
super(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
|
||||
}
|
||||
createInternal(rootSelector: string | any): AppElement {
|
||||
var m = this.methods.get('createInternal');
|
||||
if (isPresent(m)) {
|
||||
return m(rootSelector);
|
||||
} else {
|
||||
return super.createInternal(rootSelector);
|
||||
}
|
||||
}
|
||||
injectorGetInternal(token: any, nodeIndex: number, notFoundResult: any): any {
|
||||
var m = this.methods.get('injectorGetInternal');
|
||||
if (isPresent(m)) {
|
||||
return m(token, nodeIndex, notFoundResult);
|
||||
} else {
|
||||
return super.injectorGet(token, nodeIndex, notFoundResult);
|
||||
}
|
||||
}
|
||||
destroyInternal(): void {
|
||||
var m = this.methods.get('destroyInternal');
|
||||
if (isPresent(m)) {
|
||||
return m();
|
||||
} else {
|
||||
return super.destroyInternal();
|
||||
}
|
||||
}
|
||||
dirtyParentQueriesInternal(): void {
|
||||
var m = this.methods.get('dirtyParentQueriesInternal');
|
||||
if (isPresent(m)) {
|
||||
return m();
|
||||
} else {
|
||||
return super.dirtyParentQueriesInternal();
|
||||
}
|
||||
}
|
||||
detectChangesInternal(throwOnChange: boolean): void {
|
||||
var m = this.methods.get('detectChangesInternal');
|
||||
if (isPresent(m)) {
|
||||
return m(throwOnChange);
|
||||
} else {
|
||||
return super.detectChangesInternal(throwOnChange);
|
||||
}
|
||||
}
|
||||
}
|
73
modules/angular2/src/compiler/output/js_emitter.ts
Normal file
73
modules/angular2/src/compiler/output/js_emitter.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import * as o from './output_ast';
|
||||
import {
|
||||
isPresent,
|
||||
isBlank,
|
||||
isString,
|
||||
evalExpression,
|
||||
RegExpWrapper,
|
||||
StringWrapper
|
||||
} from 'angular2/src/facade/lang';
|
||||
import {OutputEmitter, EmitterVisitorContext} from './abstract_emitter';
|
||||
import {AbstractJsEmitterVisitor} from './abstract_js_emitter';
|
||||
import {getImportModulePath, ImportEnv} from './path_util';
|
||||
|
||||
export class JavaScriptEmitter implements OutputEmitter {
|
||||
constructor() {}
|
||||
emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string {
|
||||
var converter = new JsEmitterVisitor(moduleUrl);
|
||||
var ctx = EmitterVisitorContext.createRoot(exportedVars);
|
||||
converter.visitAllStatements(stmts, ctx);
|
||||
var srcParts = [];
|
||||
converter.importsWithPrefixes.forEach((prefix, importedModuleUrl) => {
|
||||
// Note: can't write the real word for import as it screws up system.js auto detection...
|
||||
srcParts.push(`var ${prefix} = req` +
|
||||
`uire('${getImportModulePath(moduleUrl, importedModuleUrl, ImportEnv.JS)}');`);
|
||||
});
|
||||
srcParts.push(ctx.toSource());
|
||||
return srcParts.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
class JsEmitterVisitor extends AbstractJsEmitterVisitor {
|
||||
importsWithPrefixes = new Map<string, string>();
|
||||
|
||||
constructor(private _moduleUrl: string) { super(); }
|
||||
|
||||
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
|
||||
if (isPresent(ast.value.moduleUrl) && ast.value.moduleUrl != this._moduleUrl) {
|
||||
var prefix = this.importsWithPrefixes.get(ast.value.moduleUrl);
|
||||
if (isBlank(prefix)) {
|
||||
prefix = `import${this.importsWithPrefixes.size}`;
|
||||
this.importsWithPrefixes.set(ast.value.moduleUrl, prefix);
|
||||
}
|
||||
ctx.print(`${prefix}.`);
|
||||
}
|
||||
ctx.print(ast.value.name);
|
||||
return null;
|
||||
}
|
||||
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
|
||||
super.visitDeclareVarStmt(stmt, ctx);
|
||||
if (ctx.isExportedVar(stmt.name)) {
|
||||
ctx.println(exportVar(stmt.name));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: EmitterVisitorContext): any {
|
||||
super.visitDeclareFunctionStmt(stmt, ctx);
|
||||
if (ctx.isExportedVar(stmt.name)) {
|
||||
ctx.println(exportVar(stmt.name));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
|
||||
super.visitDeclareClassStmt(stmt, ctx);
|
||||
if (ctx.isExportedVar(stmt.name)) {
|
||||
ctx.println(exportVar(stmt.name));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function exportVar(varName: string): string {
|
||||
return `Object.defineProperty(exports, '${varName}', { get: function() { return ${varName}; }});`;
|
||||
}
|
870
modules/angular2/src/compiler/output/output_ast.ts
Normal file
870
modules/angular2/src/compiler/output/output_ast.ts
Normal file
@ -0,0 +1,870 @@
|
||||
import {CONST_EXPR, isString, isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {CompileIdentifierMetadata} from '../compile_metadata';
|
||||
|
||||
//// Types
|
||||
export enum TypeModifier {
|
||||
Const
|
||||
}
|
||||
|
||||
export abstract class Type {
|
||||
constructor(public modifiers: TypeModifier[] = null) {
|
||||
if (isBlank(modifiers)) {
|
||||
this.modifiers = [];
|
||||
}
|
||||
}
|
||||
abstract visitType(visitor: TypeVisitor, context: any): any;
|
||||
|
||||
hasModifier(modifier: TypeModifier): boolean { return this.modifiers.indexOf(modifier) !== -1; }
|
||||
}
|
||||
|
||||
export enum BuiltinTypeName {
|
||||
Dynamic,
|
||||
Bool,
|
||||
String,
|
||||
Int,
|
||||
Number,
|
||||
Function
|
||||
}
|
||||
|
||||
export class BuiltinType extends Type {
|
||||
constructor(public name: BuiltinTypeName, modifiers: TypeModifier[] = null) { super(modifiers); }
|
||||
visitType(visitor: TypeVisitor, context: any): any {
|
||||
return visitor.visitBuiltintType(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExternalType extends Type {
|
||||
constructor(public value: CompileIdentifierMetadata, public typeParams: Type[] = null,
|
||||
modifiers: TypeModifier[] = null) {
|
||||
super(modifiers);
|
||||
}
|
||||
visitType(visitor: TypeVisitor, context: any): any {
|
||||
return visitor.visitExternalType(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ArrayType extends Type {
|
||||
constructor(public of: Type, modifiers: TypeModifier[] = null) { super(modifiers); }
|
||||
visitType(visitor: TypeVisitor, context: any): any {
|
||||
return visitor.visitArrayType(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class MapType extends Type {
|
||||
constructor(public valueType: Type, modifiers: TypeModifier[] = null) { super(modifiers); }
|
||||
visitType(visitor: TypeVisitor, context: any): any { return visitor.visitMapType(this, context); }
|
||||
}
|
||||
|
||||
export var DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic);
|
||||
export var BOOL_TYPE = new BuiltinType(BuiltinTypeName.Bool);
|
||||
export var INT_TYPE = new BuiltinType(BuiltinTypeName.Int);
|
||||
export var NUMBER_TYPE = new BuiltinType(BuiltinTypeName.Number);
|
||||
export var STRING_TYPE = new BuiltinType(BuiltinTypeName.String);
|
||||
export var FUNCTION_TYPE = new BuiltinType(BuiltinTypeName.Function);
|
||||
|
||||
|
||||
export interface TypeVisitor {
|
||||
visitBuiltintType(type: BuiltinType, context: any): any;
|
||||
visitExternalType(type: ExternalType, context: any): any;
|
||||
visitArrayType(type: ArrayType, context: any): any;
|
||||
visitMapType(type: MapType, context: any): any;
|
||||
}
|
||||
|
||||
///// Expressions
|
||||
|
||||
export enum BinaryOperator {
|
||||
Equals,
|
||||
NotEquals,
|
||||
Identical,
|
||||
NotIdentical,
|
||||
Minus,
|
||||
Plus,
|
||||
Divide,
|
||||
Multiply,
|
||||
Modulo,
|
||||
And,
|
||||
Or,
|
||||
Lower,
|
||||
LowerEquals,
|
||||
Bigger,
|
||||
BiggerEquals
|
||||
}
|
||||
|
||||
|
||||
export abstract class Expression {
|
||||
constructor(public type: Type) {}
|
||||
|
||||
abstract visitExpression(visitor: ExpressionVisitor, context: any): any;
|
||||
|
||||
prop(name: string): ReadPropExpr { return new ReadPropExpr(this, name); }
|
||||
|
||||
key(index: Expression, type: Type = null): ReadKeyExpr {
|
||||
return new ReadKeyExpr(this, index, type);
|
||||
}
|
||||
|
||||
callMethod(name: string | BuiltinMethod, params: Expression[]): InvokeMethodExpr {
|
||||
return new InvokeMethodExpr(this, name, params);
|
||||
}
|
||||
|
||||
callFn(params: Expression[]): InvokeFunctionExpr { return new InvokeFunctionExpr(this, params); }
|
||||
|
||||
instantiate(params: Expression[], type: Type = null): InstantiateExpr {
|
||||
return new InstantiateExpr(this, params, type);
|
||||
}
|
||||
|
||||
conditional(trueCase: Expression, falseCase: Expression = null): ConditionalExpr {
|
||||
return new ConditionalExpr(this, trueCase, falseCase);
|
||||
}
|
||||
|
||||
equals(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.Equals, this, rhs);
|
||||
}
|
||||
notEquals(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.NotEquals, this, rhs);
|
||||
}
|
||||
identical(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.Identical, this, rhs);
|
||||
}
|
||||
notIdentical(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.NotIdentical, this, rhs);
|
||||
}
|
||||
minus(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.Minus, this, rhs);
|
||||
}
|
||||
plus(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.Plus, this, rhs);
|
||||
}
|
||||
divide(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.Divide, this, rhs);
|
||||
}
|
||||
multiply(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.Multiply, this, rhs);
|
||||
}
|
||||
modulo(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.Modulo, this, rhs);
|
||||
}
|
||||
and(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.And, this, rhs);
|
||||
}
|
||||
or(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.Or, this, rhs);
|
||||
}
|
||||
lower(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.Lower, this, rhs);
|
||||
}
|
||||
lowerEquals(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.LowerEquals, this, rhs);
|
||||
}
|
||||
bigger(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.Bigger, this, rhs);
|
||||
}
|
||||
biggerEquals(rhs: Expression): BinaryOperatorExpr {
|
||||
return new BinaryOperatorExpr(BinaryOperator.BiggerEquals, this, rhs);
|
||||
}
|
||||
isBlank(): Expression {
|
||||
// Note: We use equals by purpose here to compare to null and undefined in JS.
|
||||
return this.equals(NULL_EXPR);
|
||||
}
|
||||
cast(type: Type): Expression { return new CastExpr(this, type); }
|
||||
toStmt(): Statement { return new ExpressionStatement(this); }
|
||||
}
|
||||
|
||||
export enum BuiltinVar {
|
||||
This,
|
||||
Super,
|
||||
CatchError,
|
||||
CatchStack
|
||||
}
|
||||
|
||||
export class ReadVarExpr extends Expression {
|
||||
public name;
|
||||
public builtin: BuiltinVar;
|
||||
|
||||
constructor(name: string | BuiltinVar, type: Type = null) {
|
||||
super(type);
|
||||
if (isString(name)) {
|
||||
this.name = <string>name;
|
||||
this.builtin = null;
|
||||
} else {
|
||||
this.name = null;
|
||||
this.builtin = <BuiltinVar>name;
|
||||
}
|
||||
}
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitReadVarExpr(this, context);
|
||||
}
|
||||
|
||||
set(value: Expression): WriteVarExpr { return new WriteVarExpr(this.name, value); }
|
||||
}
|
||||
|
||||
|
||||
export class WriteVarExpr extends Expression {
|
||||
public value: Expression;
|
||||
constructor(public name: string, value: Expression, type: Type = null) {
|
||||
super(isPresent(type) ? type : value.type);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitWriteVarExpr(this, context);
|
||||
}
|
||||
|
||||
toDeclStmt(type: Type = null, modifiers: StmtModifier[] = null): DeclareVarStmt {
|
||||
return new DeclareVarStmt(this.name, this.value, type, modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class WriteKeyExpr extends Expression {
|
||||
public value: Expression;
|
||||
constructor(public receiver: Expression, public index: Expression, value: Expression,
|
||||
type: Type = null) {
|
||||
super(isPresent(type) ? type : value.type);
|
||||
this.value = value;
|
||||
}
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitWriteKeyExpr(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class WritePropExpr extends Expression {
|
||||
public value: Expression;
|
||||
constructor(public receiver: Expression, public name: string, value: Expression,
|
||||
type: Type = null) {
|
||||
super(isPresent(type) ? type : value.type);
|
||||
this.value = value;
|
||||
}
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitWritePropExpr(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export enum BuiltinMethod {
|
||||
ConcatArray,
|
||||
SubscribeObservable,
|
||||
bind
|
||||
}
|
||||
|
||||
export class InvokeMethodExpr extends Expression {
|
||||
public name: string;
|
||||
public builtin: BuiltinMethod;
|
||||
constructor(public receiver: Expression, method: string | BuiltinMethod,
|
||||
public args: Expression[], type: Type = null) {
|
||||
super(type);
|
||||
if (isString(method)) {
|
||||
this.name = <string>method;
|
||||
this.builtin = null;
|
||||
} else {
|
||||
this.name = null;
|
||||
this.builtin = <BuiltinMethod>method;
|
||||
}
|
||||
}
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitInvokeMethodExpr(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class InvokeFunctionExpr extends Expression {
|
||||
constructor(public fn: Expression, public args: Expression[], type: Type = null) { super(type); }
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitInvokeFunctionExpr(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class InstantiateExpr extends Expression {
|
||||
constructor(public classExpr: Expression, public args: Expression[], type?: Type) { super(type); }
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitInstantiateExpr(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class LiteralExpr extends Expression {
|
||||
constructor(public value: any, type: Type = null) { super(type); }
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitLiteralExpr(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ExternalExpr extends Expression {
|
||||
constructor(public value: CompileIdentifierMetadata, type: Type = null,
|
||||
public typeParams: Type[] = null) {
|
||||
super(type);
|
||||
}
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitExternalExpr(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ConditionalExpr extends Expression {
|
||||
public trueCase: Expression;
|
||||
constructor(public condition: Expression, trueCase: Expression,
|
||||
public falseCase: Expression = null, type: Type = null) {
|
||||
super(isPresent(type) ? type : trueCase.type);
|
||||
this.trueCase = trueCase;
|
||||
}
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitConditionalExpr(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class NotExpr extends Expression {
|
||||
constructor(public condition: Expression) { super(BOOL_TYPE); }
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitNotExpr(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class CastExpr extends Expression {
|
||||
constructor(public value: Expression, type: Type) { super(type); }
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitCastExpr(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class FnParam {
|
||||
constructor(public name: string, public type: Type = null) {}
|
||||
}
|
||||
|
||||
|
||||
export class FunctionExpr extends Expression {
|
||||
constructor(public params: FnParam[], public statements: Statement[], type: Type = null) {
|
||||
super(type);
|
||||
}
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitFunctionExpr(this, context);
|
||||
}
|
||||
|
||||
toDeclStmt(name: string, modifiers: StmtModifier[] = null): DeclareFunctionStmt {
|
||||
return new DeclareFunctionStmt(name, this.params, this.statements, this.type, modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class BinaryOperatorExpr extends Expression {
|
||||
public lhs: Expression;
|
||||
constructor(public operator: BinaryOperator, lhs: Expression, public rhs: Expression,
|
||||
type: Type = null) {
|
||||
super(isPresent(type) ? type : lhs.type);
|
||||
this.lhs = lhs;
|
||||
}
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitBinaryOperatorExpr(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ReadPropExpr extends Expression {
|
||||
constructor(public receiver: Expression, public name: string, type: Type = null) { super(type); }
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitReadPropExpr(this, context);
|
||||
}
|
||||
set(value: Expression): WritePropExpr {
|
||||
return new WritePropExpr(this.receiver, this.name, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ReadKeyExpr extends Expression {
|
||||
constructor(public receiver: Expression, public index: Expression, type: Type = null) {
|
||||
super(type);
|
||||
}
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitReadKeyExpr(this, context);
|
||||
}
|
||||
set(value: Expression): WriteKeyExpr {
|
||||
return new WriteKeyExpr(this.receiver, this.index, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class LiteralArrayExpr extends Expression {
|
||||
public entries: Expression[];
|
||||
constructor(entries: Expression[], type: Type = null) {
|
||||
super(type);
|
||||
this.entries = entries;
|
||||
}
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitLiteralArrayExpr(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class LiteralMapExpr extends Expression {
|
||||
public valueType: Type = null;
|
||||
;
|
||||
constructor(public entries: Array<Array<string | Expression>>, type: MapType = null) {
|
||||
super(type);
|
||||
if (isPresent(type)) {
|
||||
this.valueType = type.valueType;
|
||||
}
|
||||
}
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
return visitor.visitLiteralMapExpr(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export interface ExpressionVisitor {
|
||||
visitReadVarExpr(ast: ReadVarExpr, context: any): any;
|
||||
visitWriteVarExpr(expr: WriteVarExpr, context: any): any;
|
||||
visitWriteKeyExpr(expr: WriteKeyExpr, context: any): any;
|
||||
visitWritePropExpr(expr: WritePropExpr, context: any): any;
|
||||
visitInvokeMethodExpr(ast: InvokeMethodExpr, context: any): any;
|
||||
visitInvokeFunctionExpr(ast: InvokeFunctionExpr, context: any): any;
|
||||
visitInstantiateExpr(ast: InstantiateExpr, context: any): any;
|
||||
visitLiteralExpr(ast: LiteralExpr, context: any): any;
|
||||
visitExternalExpr(ast: ExternalExpr, context: any): any;
|
||||
visitConditionalExpr(ast: ConditionalExpr, context: any): any;
|
||||
visitNotExpr(ast: NotExpr, context: any): any;
|
||||
visitCastExpr(ast: CastExpr, context: any): any;
|
||||
visitFunctionExpr(ast: FunctionExpr, context: any): any;
|
||||
visitBinaryOperatorExpr(ast: BinaryOperatorExpr, context: any): any;
|
||||
visitReadPropExpr(ast: ReadPropExpr, context: any): any;
|
||||
visitReadKeyExpr(ast: ReadKeyExpr, context: any): any;
|
||||
visitLiteralArrayExpr(ast: LiteralArrayExpr, context: any): any;
|
||||
visitLiteralMapExpr(ast: LiteralMapExpr, context: any): any;
|
||||
}
|
||||
|
||||
export var THIS_EXPR = new ReadVarExpr(BuiltinVar.This);
|
||||
export var SUPER_EXPR = new ReadVarExpr(BuiltinVar.Super);
|
||||
export var CATCH_ERROR_VAR = new ReadVarExpr(BuiltinVar.CatchError);
|
||||
export var CATCH_STACK_VAR = new ReadVarExpr(BuiltinVar.CatchStack);
|
||||
export var NULL_EXPR = new LiteralExpr(null, null);
|
||||
|
||||
//// Statements
|
||||
export enum StmtModifier {
|
||||
Final,
|
||||
Private
|
||||
}
|
||||
|
||||
export abstract class Statement {
|
||||
constructor(public modifiers: StmtModifier[] = null) {
|
||||
if (isBlank(modifiers)) {
|
||||
this.modifiers = [];
|
||||
}
|
||||
}
|
||||
|
||||
abstract visitStatement(visitor: StatementVisitor, context: any): any;
|
||||
|
||||
hasModifier(modifier: StmtModifier): boolean { return this.modifiers.indexOf(modifier) !== -1; }
|
||||
}
|
||||
|
||||
|
||||
export class DeclareVarStmt extends Statement {
|
||||
public type: Type;
|
||||
constructor(public name: string, public value: Expression, type: Type = null,
|
||||
modifiers: StmtModifier[] = null) {
|
||||
super(modifiers);
|
||||
this.type = isPresent(type) ? type : value.type;
|
||||
}
|
||||
|
||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||
return visitor.visitDeclareVarStmt(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class DeclareFunctionStmt extends Statement {
|
||||
constructor(public name: string, public params: FnParam[], public statements: Statement[],
|
||||
public type: Type = null, modifiers: StmtModifier[] = null) {
|
||||
super(modifiers);
|
||||
}
|
||||
|
||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||
return visitor.visitDeclareFunctionStmt(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExpressionStatement extends Statement {
|
||||
constructor(public expr: Expression) { super(); }
|
||||
|
||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||
return visitor.visitExpressionStmt(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ReturnStatement extends Statement {
|
||||
constructor(public value: Expression) { super(); }
|
||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||
return visitor.visitReturnStmt(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class AbstractClassPart {
|
||||
constructor(public type: Type = null, public modifiers: StmtModifier[]) {
|
||||
if (isBlank(modifiers)) {
|
||||
this.modifiers = [];
|
||||
}
|
||||
}
|
||||
hasModifier(modifier: StmtModifier): boolean { return this.modifiers.indexOf(modifier) !== -1; }
|
||||
}
|
||||
|
||||
export class ClassField extends AbstractClassPart {
|
||||
constructor(public name: string, type: Type = null, modifiers: StmtModifier[] = null) {
|
||||
super(type, modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ClassMethod extends AbstractClassPart {
|
||||
constructor(public name: string, public params: FnParam[], public body: Statement[],
|
||||
type: Type = null, modifiers: StmtModifier[] = null) {
|
||||
super(type, modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ClassGetter extends AbstractClassPart {
|
||||
constructor(public name: string, public body: Statement[], type: Type = null,
|
||||
modifiers: StmtModifier[] = null) {
|
||||
super(type, modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ClassStmt extends Statement {
|
||||
constructor(public name: string, public parent: Expression, public fields: ClassField[],
|
||||
public getters: ClassGetter[], public constructorMethod: ClassMethod,
|
||||
public methods: ClassMethod[], modifiers: StmtModifier[] = null) {
|
||||
super(modifiers);
|
||||
}
|
||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||
return visitor.visitDeclareClassStmt(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class IfStmt extends Statement {
|
||||
constructor(public condition: Expression, public trueCase: Statement[],
|
||||
public falseCase: Statement[] = CONST_EXPR([])) {
|
||||
super();
|
||||
}
|
||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||
return visitor.visitIfStmt(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class CommentStmt extends Statement {
|
||||
constructor(public comment: string) { super(); }
|
||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||
return visitor.visitCommentStmt(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class TryCatchStmt extends Statement {
|
||||
constructor(public bodyStmts: Statement[], public catchStmts: Statement[]) { super(); }
|
||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||
return visitor.visitTryCatchStmt(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ThrowStmt extends Statement {
|
||||
constructor(public error: Expression) { super(); }
|
||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||
return visitor.visitThrowStmt(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export interface StatementVisitor {
|
||||
visitDeclareVarStmt(stmt: DeclareVarStmt, context: any): any;
|
||||
visitDeclareFunctionStmt(stmt: DeclareFunctionStmt, context: any): any;
|
||||
visitExpressionStmt(stmt: ExpressionStatement, context: any): any;
|
||||
visitReturnStmt(stmt: ReturnStatement, context: any): any;
|
||||
visitDeclareClassStmt(stmt: ClassStmt, context: any): any;
|
||||
visitIfStmt(stmt: IfStmt, context: any): any;
|
||||
visitTryCatchStmt(stmt: TryCatchStmt, context: any): any;
|
||||
visitThrowStmt(stmt: ThrowStmt, context: any): any;
|
||||
visitCommentStmt(stmt: CommentStmt, context: any): any;
|
||||
}
|
||||
|
||||
export class ExpressionTransformer implements StatementVisitor, ExpressionVisitor {
|
||||
visitReadVarExpr(ast: ReadVarExpr, context: any): any { return ast; }
|
||||
visitWriteVarExpr(expr: WriteVarExpr, context: any): any {
|
||||
return new WriteVarExpr(expr.name, expr.value.visitExpression(this, context));
|
||||
}
|
||||
visitWriteKeyExpr(expr: WriteKeyExpr, context: any): any {
|
||||
return new WriteKeyExpr(expr.receiver.visitExpression(this, context),
|
||||
expr.index.visitExpression(this, context),
|
||||
expr.value.visitExpression(this, context));
|
||||
}
|
||||
visitWritePropExpr(expr: WritePropExpr, context: any): any {
|
||||
return new WritePropExpr(expr.receiver.visitExpression(this, context), expr.name,
|
||||
expr.value.visitExpression(this, context));
|
||||
}
|
||||
visitInvokeMethodExpr(ast: InvokeMethodExpr, context: any): any {
|
||||
var method = isPresent(ast.builtin) ? ast.builtin : ast.name;
|
||||
return new InvokeMethodExpr(ast.receiver.visitExpression(this, context), method,
|
||||
this.visitAllExpressions(ast.args, context), ast.type);
|
||||
}
|
||||
visitInvokeFunctionExpr(ast: InvokeFunctionExpr, context: any): any {
|
||||
return new InvokeFunctionExpr(ast.fn.visitExpression(this, context),
|
||||
this.visitAllExpressions(ast.args, context), ast.type);
|
||||
}
|
||||
visitInstantiateExpr(ast: InstantiateExpr, context: any): any {
|
||||
return new InstantiateExpr(ast.classExpr.visitExpression(this, context),
|
||||
this.visitAllExpressions(ast.args, context), ast.type);
|
||||
}
|
||||
visitLiteralExpr(ast: LiteralExpr, context: any): any { return ast; }
|
||||
visitExternalExpr(ast: ExternalExpr, context: any): any { return ast; }
|
||||
visitConditionalExpr(ast: ConditionalExpr, context: any): any {
|
||||
return new ConditionalExpr(ast.condition.visitExpression(this, context),
|
||||
ast.trueCase.visitExpression(this, context),
|
||||
ast.falseCase.visitExpression(this, context));
|
||||
}
|
||||
visitNotExpr(ast: NotExpr, context: any): any {
|
||||
return new NotExpr(ast.condition.visitExpression(this, context));
|
||||
}
|
||||
visitCastExpr(ast: CastExpr, context: any): any {
|
||||
return new CastExpr(ast.value.visitExpression(this, context), context);
|
||||
}
|
||||
visitFunctionExpr(ast: FunctionExpr, context: any): any {
|
||||
// Don't descend into nested functions
|
||||
return ast;
|
||||
}
|
||||
visitBinaryOperatorExpr(ast: BinaryOperatorExpr, context: any): any {
|
||||
return new BinaryOperatorExpr(ast.operator, ast.lhs.visitExpression(this, context),
|
||||
ast.rhs.visitExpression(this, context), ast.type);
|
||||
}
|
||||
visitReadPropExpr(ast: ReadPropExpr, context: any): any {
|
||||
return new ReadPropExpr(ast.receiver.visitExpression(this, context), ast.name, ast.type);
|
||||
}
|
||||
visitReadKeyExpr(ast: ReadKeyExpr, context: any): any {
|
||||
return new ReadKeyExpr(ast.receiver.visitExpression(this, context),
|
||||
ast.index.visitExpression(this, context), ast.type);
|
||||
}
|
||||
visitLiteralArrayExpr(ast: LiteralArrayExpr, context: any): any {
|
||||
return new LiteralArrayExpr(this.visitAllExpressions(ast.entries, context));
|
||||
}
|
||||
visitLiteralMapExpr(ast: LiteralMapExpr, context: any): any {
|
||||
return new LiteralMapExpr(ast.entries.map(
|
||||
(entry) => [entry[0], (<Expression>entry[1]).visitExpression(this, context)]));
|
||||
}
|
||||
visitAllExpressions(exprs: Expression[], context: any): Expression[] {
|
||||
return exprs.map(expr => expr.visitExpression(this, context));
|
||||
}
|
||||
|
||||
visitDeclareVarStmt(stmt: DeclareVarStmt, context: any): any {
|
||||
return new DeclareVarStmt(stmt.name, stmt.value.visitExpression(this, context), stmt.type,
|
||||
stmt.modifiers);
|
||||
}
|
||||
visitDeclareFunctionStmt(stmt: DeclareFunctionStmt, context: any): any {
|
||||
// Don't descend into nested functions
|
||||
return stmt;
|
||||
}
|
||||
visitExpressionStmt(stmt: ExpressionStatement, context: any): any {
|
||||
return new ExpressionStatement(stmt.expr.visitExpression(this, context));
|
||||
}
|
||||
visitReturnStmt(stmt: ReturnStatement, context: any): any {
|
||||
return new ReturnStatement(stmt.value.visitExpression(this, context));
|
||||
}
|
||||
visitDeclareClassStmt(stmt: ClassStmt, context: any): any {
|
||||
// Don't descend into nested functions
|
||||
return stmt;
|
||||
}
|
||||
visitIfStmt(stmt: IfStmt, context: any): any {
|
||||
return new IfStmt(stmt.condition.visitExpression(this, context),
|
||||
this.visitAllStatements(stmt.trueCase, context),
|
||||
this.visitAllStatements(stmt.falseCase, context));
|
||||
}
|
||||
visitTryCatchStmt(stmt: TryCatchStmt, context: any): any {
|
||||
return new TryCatchStmt(this.visitAllStatements(stmt.bodyStmts, context),
|
||||
this.visitAllStatements(stmt.catchStmts, context));
|
||||
}
|
||||
visitThrowStmt(stmt: ThrowStmt, context: any): any {
|
||||
return new ThrowStmt(stmt.error.visitExpression(this, context));
|
||||
}
|
||||
visitCommentStmt(stmt: CommentStmt, context: any): any { return stmt; }
|
||||
visitAllStatements(stmts: Statement[], context: any): Statement[] {
|
||||
return stmts.map(stmt => stmt.visitStatement(this, context));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class RecursiveExpressionVisitor implements StatementVisitor, ExpressionVisitor {
|
||||
visitReadVarExpr(ast: ReadVarExpr, context: any): any { return ast; }
|
||||
visitWriteVarExpr(expr: WriteVarExpr, context: any): any {
|
||||
expr.value.visitExpression(this, context);
|
||||
return expr;
|
||||
}
|
||||
visitWriteKeyExpr(expr: WriteKeyExpr, context: any): any {
|
||||
expr.receiver.visitExpression(this, context);
|
||||
expr.index.visitExpression(this, context);
|
||||
expr.value.visitExpression(this, context);
|
||||
return expr;
|
||||
}
|
||||
visitWritePropExpr(expr: WritePropExpr, context: any): any {
|
||||
expr.receiver.visitExpression(this, context);
|
||||
expr.value.visitExpression(this, context);
|
||||
return expr;
|
||||
}
|
||||
visitInvokeMethodExpr(ast: InvokeMethodExpr, context: any): any {
|
||||
ast.receiver.visitExpression(this, context);
|
||||
this.visitAllExpressions(ast.args, context);
|
||||
return ast;
|
||||
}
|
||||
visitInvokeFunctionExpr(ast: InvokeFunctionExpr, context: any): any {
|
||||
ast.fn.visitExpression(this, context);
|
||||
this.visitAllExpressions(ast.args, context);
|
||||
return ast;
|
||||
}
|
||||
visitInstantiateExpr(ast: InstantiateExpr, context: any): any {
|
||||
ast.classExpr.visitExpression(this, context);
|
||||
this.visitAllExpressions(ast.args, context);
|
||||
return ast;
|
||||
}
|
||||
visitLiteralExpr(ast: LiteralExpr, context: any): any { return ast; }
|
||||
visitExternalExpr(ast: ExternalExpr, context: any): any { return ast; }
|
||||
visitConditionalExpr(ast: ConditionalExpr, context: any): any {
|
||||
ast.condition.visitExpression(this, context);
|
||||
ast.trueCase.visitExpression(this, context);
|
||||
ast.falseCase.visitExpression(this, context);
|
||||
return ast;
|
||||
}
|
||||
visitNotExpr(ast: NotExpr, context: any): any {
|
||||
ast.condition.visitExpression(this, context);
|
||||
return ast;
|
||||
}
|
||||
visitCastExpr(ast: CastExpr, context: any): any {
|
||||
ast.value.visitExpression(this, context);
|
||||
return ast;
|
||||
}
|
||||
visitFunctionExpr(ast: FunctionExpr, context: any): any { return ast; }
|
||||
visitBinaryOperatorExpr(ast: BinaryOperatorExpr, context: any): any {
|
||||
ast.lhs.visitExpression(this, context);
|
||||
ast.rhs.visitExpression(this, context);
|
||||
return ast;
|
||||
}
|
||||
visitReadPropExpr(ast: ReadPropExpr, context: any): any {
|
||||
ast.receiver.visitExpression(this, context);
|
||||
return ast;
|
||||
}
|
||||
visitReadKeyExpr(ast: ReadKeyExpr, context: any): any {
|
||||
ast.receiver.visitExpression(this, context);
|
||||
ast.index.visitExpression(this, context);
|
||||
return ast;
|
||||
}
|
||||
visitLiteralArrayExpr(ast: LiteralArrayExpr, context: any): any {
|
||||
this.visitAllExpressions(ast.entries, context);
|
||||
return ast;
|
||||
}
|
||||
visitLiteralMapExpr(ast: LiteralMapExpr, context: any): any {
|
||||
ast.entries.forEach((entry) => (<Expression>entry[1]).visitExpression(this, context));
|
||||
return ast;
|
||||
}
|
||||
visitAllExpressions(exprs: Expression[], context: any): void {
|
||||
exprs.forEach(expr => expr.visitExpression(this, context));
|
||||
}
|
||||
|
||||
visitDeclareVarStmt(stmt: DeclareVarStmt, context: any): any {
|
||||
stmt.value.visitExpression(this, context);
|
||||
return stmt;
|
||||
}
|
||||
visitDeclareFunctionStmt(stmt: DeclareFunctionStmt, context: any): any {
|
||||
// Don't descend into nested functions
|
||||
return stmt;
|
||||
}
|
||||
visitExpressionStmt(stmt: ExpressionStatement, context: any): any {
|
||||
stmt.expr.visitExpression(this, context);
|
||||
return stmt;
|
||||
}
|
||||
visitReturnStmt(stmt: ReturnStatement, context: any): any {
|
||||
stmt.value.visitExpression(this, context);
|
||||
return stmt;
|
||||
}
|
||||
visitDeclareClassStmt(stmt: ClassStmt, context: any): any {
|
||||
// Don't descend into nested functions
|
||||
return stmt;
|
||||
}
|
||||
visitIfStmt(stmt: IfStmt, context: any): any {
|
||||
stmt.condition.visitExpression(this, context);
|
||||
this.visitAllStatements(stmt.trueCase, context);
|
||||
this.visitAllStatements(stmt.falseCase, context);
|
||||
return stmt;
|
||||
}
|
||||
visitTryCatchStmt(stmt: TryCatchStmt, context: any): any {
|
||||
this.visitAllStatements(stmt.bodyStmts, context);
|
||||
this.visitAllStatements(stmt.catchStmts, context);
|
||||
return stmt;
|
||||
}
|
||||
visitThrowStmt(stmt: ThrowStmt, context: any): any {
|
||||
stmt.error.visitExpression(this, context);
|
||||
return stmt;
|
||||
}
|
||||
visitCommentStmt(stmt: CommentStmt, context: any): any { return stmt; }
|
||||
visitAllStatements(stmts: Statement[], context: any): void {
|
||||
stmts.forEach(stmt => stmt.visitStatement(this, context));
|
||||
}
|
||||
}
|
||||
|
||||
export function replaceVarInExpression(varName: string, newValue: Expression,
|
||||
expression: Expression): Expression {
|
||||
var transformer = new _ReplaceVariableTransformer(varName, newValue);
|
||||
return expression.visitExpression(transformer, null);
|
||||
}
|
||||
|
||||
class _ReplaceVariableTransformer extends ExpressionTransformer {
|
||||
constructor(private _varName: string, private _newValue: Expression) { super(); }
|
||||
visitReadVarExpr(ast: ReadVarExpr, context: any): any {
|
||||
return ast.name == this._varName ? this._newValue : ast;
|
||||
}
|
||||
}
|
||||
|
||||
export function findReadVarNames(stmts: Statement[]): Set<string> {
|
||||
var finder = new _VariableFinder();
|
||||
finder.visitAllStatements(stmts, null);
|
||||
return finder.varNames;
|
||||
}
|
||||
|
||||
class _VariableFinder extends RecursiveExpressionVisitor {
|
||||
varNames = new Set<string>();
|
||||
visitReadVarExpr(ast: ReadVarExpr, context: any): any {
|
||||
this.varNames.add(ast.name);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function variable(name: string, type: Type = null): ReadVarExpr {
|
||||
return new ReadVarExpr(name, type);
|
||||
}
|
||||
|
||||
export function importExpr(id: CompileIdentifierMetadata, typeParams: Type[] = null): ExternalExpr {
|
||||
return new ExternalExpr(id, null, typeParams);
|
||||
}
|
||||
|
||||
export function importType(id: CompileIdentifierMetadata, typeParams: Type[] = null,
|
||||
typeModifiers: TypeModifier[] = null): ExternalType {
|
||||
return isPresent(id) ? new ExternalType(id, typeParams, typeModifiers) : null;
|
||||
}
|
||||
|
||||
export function literal(value: any, type: Type = null): LiteralExpr {
|
||||
return new LiteralExpr(value, type);
|
||||
}
|
||||
|
||||
export function literalArr(values: Expression[], type: Type = null): LiteralArrayExpr {
|
||||
return new LiteralArrayExpr(values, type);
|
||||
}
|
||||
|
||||
export function literalMap(values: Array<Array<string | Expression>>,
|
||||
type: MapType = null): LiteralMapExpr {
|
||||
return new LiteralMapExpr(values, type);
|
||||
}
|
||||
|
||||
export function not(expr: Expression): NotExpr {
|
||||
return new NotExpr(expr);
|
||||
}
|
||||
|
||||
export function fn(params: FnParam[], body: Statement[], type: Type = null): FunctionExpr {
|
||||
return new FunctionExpr(params, body, type);
|
||||
}
|
422
modules/angular2/src/compiler/output/output_interpreter.ts
Normal file
422
modules/angular2/src/compiler/output/output_interpreter.ts
Normal file
@ -0,0 +1,422 @@
|
||||
import {
|
||||
isPresent,
|
||||
isBlank,
|
||||
isString,
|
||||
evalExpression,
|
||||
IS_DART,
|
||||
FunctionWrapper
|
||||
} from 'angular2/src/facade/lang';
|
||||
import {ObservableWrapper} from 'angular2/src/facade/async';
|
||||
import * as o from './output_ast';
|
||||
import {reflector} from 'angular2/src/core/reflection/reflection';
|
||||
import {BaseException, unimplemented} from 'angular2/src/facade/exceptions';
|
||||
import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {debugOutputAstAsDart} from './dart_emitter';
|
||||
import {debugOutputAstAsTypeScript} from './ts_emitter';
|
||||
|
||||
export function interpretStatements(statements: o.Statement[], resultVar: string,
|
||||
instanceFactory: InstanceFactory): any {
|
||||
var stmtsWithReturn = statements.concat([new o.ReturnStatement(o.variable(resultVar))]);
|
||||
var ctx = new _ExecutionContext(null, null, null, null, new Map<string, any>(),
|
||||
new Map<string, any>(), new Map<string, Function>(),
|
||||
new Map<string, Function>(), instanceFactory);
|
||||
var visitor = new StatementInterpreter();
|
||||
var result = visitor.visitAllStatements(stmtsWithReturn, ctx);
|
||||
return isPresent(result) ? result.value : null;
|
||||
}
|
||||
|
||||
export interface InstanceFactory {
|
||||
createInstance(superClass: any, clazz: any, constructorArgs: any[], props: Map<string, any>,
|
||||
getters: Map<string, Function>, methods: Map<string, Function>): DynamicInstance;
|
||||
}
|
||||
|
||||
export abstract class DynamicInstance {
|
||||
get props(): Map<string, any> { return unimplemented(); }
|
||||
get getters(): Map<string, Function> { return unimplemented(); }
|
||||
get methods(): Map<string, any> { return unimplemented(); }
|
||||
get clazz(): any { return unimplemented(); }
|
||||
}
|
||||
|
||||
function isDynamicInstance(instance: any): any {
|
||||
if (IS_DART) {
|
||||
return instance instanceof DynamicInstance;
|
||||
} else {
|
||||
return isPresent(instance) && isPresent(instance.props) && isPresent(instance.getters) &&
|
||||
isPresent(instance.methods);
|
||||
}
|
||||
}
|
||||
|
||||
function _executeFunctionStatements(varNames: string[], varValues: any[], statements: o.Statement[],
|
||||
ctx: _ExecutionContext, visitor: StatementInterpreter): any {
|
||||
var childCtx = ctx.createChildWihtLocalVars();
|
||||
for (var i = 0; i < varNames.length; i++) {
|
||||
childCtx.vars.set(varNames[i], varValues[i]);
|
||||
}
|
||||
var result = visitor.visitAllStatements(statements, childCtx);
|
||||
return isPresent(result) ? result.value : null;
|
||||
}
|
||||
|
||||
class _ExecutionContext {
|
||||
constructor(public parent: _ExecutionContext, public superClass: any, public superInstance: any,
|
||||
public className: string, public vars: Map<string, any>,
|
||||
public props: Map<string, any>, public getters: Map<string, Function>,
|
||||
public methods: Map<string, Function>, public instanceFactory: InstanceFactory) {}
|
||||
|
||||
createChildWihtLocalVars(): _ExecutionContext {
|
||||
return new _ExecutionContext(this, this.superClass, this.superInstance, this.className,
|
||||
new Map<string, any>(), this.props, this.getters, this.methods,
|
||||
this.instanceFactory);
|
||||
}
|
||||
}
|
||||
|
||||
class ReturnValue {
|
||||
constructor(public value: any) {}
|
||||
}
|
||||
|
||||
class _DynamicClass {
|
||||
constructor(private _classStmt: o.ClassStmt, private _ctx: _ExecutionContext,
|
||||
private _visitor: StatementInterpreter) {}
|
||||
|
||||
instantiate(args: any[]): DynamicInstance {
|
||||
var props = new Map<string, any>();
|
||||
var getters = new Map<string, Function>();
|
||||
var methods = new Map<string, Function>();
|
||||
var superClass = this._classStmt.parent.visitExpression(this._visitor, this._ctx);
|
||||
var instanceCtx =
|
||||
new _ExecutionContext(this._ctx, superClass, null, this._classStmt.name, this._ctx.vars,
|
||||
props, getters, methods, this._ctx.instanceFactory);
|
||||
|
||||
this._classStmt.fields.forEach((field: o.ClassField) => { props.set(field.name, null); });
|
||||
this._classStmt.getters.forEach((getter: o.ClassGetter) => {
|
||||
getters.set(getter.name, () => _executeFunctionStatements([], [], getter.body, instanceCtx,
|
||||
this._visitor));
|
||||
});
|
||||
this._classStmt.methods.forEach((method: o.ClassMethod) => {
|
||||
var paramNames = method.params.map(param => param.name);
|
||||
methods.set(method.name, _declareFn(paramNames, method.body, instanceCtx, this._visitor));
|
||||
});
|
||||
|
||||
var ctorParamNames = this._classStmt.constructorMethod.params.map(param => param.name);
|
||||
_executeFunctionStatements(ctorParamNames, args, this._classStmt.constructorMethod.body,
|
||||
instanceCtx, this._visitor);
|
||||
return instanceCtx.superInstance;
|
||||
}
|
||||
|
||||
debugAst(): string { return this._visitor.debugAst(this._classStmt); }
|
||||
}
|
||||
|
||||
class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
||||
debugAst(ast: o.Expression | o.Statement | o.Type): string {
|
||||
return IS_DART ? debugOutputAstAsDart(ast) : debugOutputAstAsTypeScript(ast);
|
||||
}
|
||||
|
||||
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: _ExecutionContext): any {
|
||||
ctx.vars.set(stmt.name, stmt.value.visitExpression(this, ctx));
|
||||
return null;
|
||||
}
|
||||
visitWriteVarExpr(expr: o.WriteVarExpr, ctx: _ExecutionContext): any {
|
||||
var value = expr.value.visitExpression(this, ctx);
|
||||
var currCtx = ctx;
|
||||
while (currCtx != null) {
|
||||
if (currCtx.vars.has(expr.name)) {
|
||||
currCtx.vars.set(expr.name, value);
|
||||
return value;
|
||||
}
|
||||
currCtx = currCtx.parent;
|
||||
}
|
||||
throw new BaseException(`Not declared variable ${expr.name}`);
|
||||
}
|
||||
visitReadVarExpr(ast: o.ReadVarExpr, ctx: _ExecutionContext): any {
|
||||
var varName = ast.name;
|
||||
if (isPresent(ast.builtin)) {
|
||||
switch (ast.builtin) {
|
||||
case o.BuiltinVar.Super:
|
||||
case o.BuiltinVar.This:
|
||||
return ctx.superInstance;
|
||||
case o.BuiltinVar.CatchError:
|
||||
varName = CATCH_ERROR_VAR;
|
||||
break;
|
||||
case o.BuiltinVar.CatchStack:
|
||||
varName = CATCH_STACK_VAR;
|
||||
break;
|
||||
default:
|
||||
throw new BaseException(`Unknown builtin variable ${ast.builtin}`);
|
||||
}
|
||||
}
|
||||
var currCtx = ctx;
|
||||
while (currCtx != null) {
|
||||
if (currCtx.vars.has(varName)) {
|
||||
return currCtx.vars.get(varName);
|
||||
}
|
||||
currCtx = currCtx.parent;
|
||||
}
|
||||
throw new BaseException(`Not declared variable ${varName}`);
|
||||
}
|
||||
visitWriteKeyExpr(expr: o.WriteKeyExpr, ctx: _ExecutionContext): any {
|
||||
var receiver = expr.receiver.visitExpression(this, ctx);
|
||||
var index = expr.index.visitExpression(this, ctx);
|
||||
var value = expr.value.visitExpression(this, ctx);
|
||||
receiver[index] = value;
|
||||
return value;
|
||||
}
|
||||
visitWritePropExpr(expr: o.WritePropExpr, ctx: _ExecutionContext): any {
|
||||
var receiver = expr.receiver.visitExpression(this, ctx);
|
||||
var value = expr.value.visitExpression(this, ctx);
|
||||
if (isDynamicInstance(receiver)) {
|
||||
var di = <DynamicInstance>receiver;
|
||||
if (di.props.has(expr.name)) {
|
||||
di.props.set(expr.name, value);
|
||||
} else {
|
||||
reflector.setter(expr.name)(receiver, value);
|
||||
}
|
||||
} else {
|
||||
reflector.setter(expr.name)(receiver, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
visitInvokeMethodExpr(expr: o.InvokeMethodExpr, ctx: _ExecutionContext): any {
|
||||
var receiver = expr.receiver.visitExpression(this, ctx);
|
||||
var args = this.visitAllExpressions(expr.args, ctx);
|
||||
var result;
|
||||
if (isPresent(expr.builtin)) {
|
||||
switch (expr.builtin) {
|
||||
case o.BuiltinMethod.ConcatArray:
|
||||
result = ListWrapper.concat(receiver, args[0]);
|
||||
break;
|
||||
case o.BuiltinMethod.SubscribeObservable:
|
||||
result = ObservableWrapper.subscribe(receiver, args[0]);
|
||||
break;
|
||||
case o.BuiltinMethod.bind:
|
||||
if (IS_DART) {
|
||||
result = receiver;
|
||||
} else {
|
||||
result = receiver.bind(args[0]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new BaseException(`Unknown builtin method ${expr.builtin}`);
|
||||
}
|
||||
} else if (isDynamicInstance(receiver)) {
|
||||
var di = <DynamicInstance>receiver;
|
||||
if (di.methods.has(expr.name)) {
|
||||
result = FunctionWrapper.apply(di.methods.get(expr.name), args);
|
||||
} else {
|
||||
result = reflector.method(expr.name)(receiver, args);
|
||||
}
|
||||
} else {
|
||||
result = reflector.method(expr.name)(receiver, args);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
visitInvokeFunctionExpr(stmt: o.InvokeFunctionExpr, ctx: _ExecutionContext): any {
|
||||
var args = this.visitAllExpressions(stmt.args, ctx);
|
||||
var fnExpr = stmt.fn;
|
||||
if (fnExpr instanceof o.ReadVarExpr && fnExpr.builtin === o.BuiltinVar.Super) {
|
||||
ctx.superInstance = ctx.instanceFactory.createInstance(ctx.superClass, ctx.className, args,
|
||||
ctx.props, ctx.getters, ctx.methods);
|
||||
ctx.parent.superInstance = ctx.superInstance;
|
||||
return null;
|
||||
} else {
|
||||
var fn = stmt.fn.visitExpression(this, ctx);
|
||||
return FunctionWrapper.apply(fn, args);
|
||||
}
|
||||
}
|
||||
visitReturnStmt(stmt: o.ReturnStatement, ctx: _ExecutionContext): any {
|
||||
return new ReturnValue(stmt.value.visitExpression(this, ctx));
|
||||
}
|
||||
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: _ExecutionContext): any {
|
||||
var clazz = new _DynamicClass(stmt, ctx, this);
|
||||
ctx.vars.set(stmt.name, clazz);
|
||||
return null;
|
||||
}
|
||||
visitExpressionStmt(stmt: o.ExpressionStatement, ctx: _ExecutionContext): any {
|
||||
return stmt.expr.visitExpression(this, ctx);
|
||||
}
|
||||
visitIfStmt(stmt: o.IfStmt, ctx: _ExecutionContext): any {
|
||||
var condition = stmt.condition.visitExpression(this, ctx);
|
||||
if (condition) {
|
||||
return this.visitAllStatements(stmt.trueCase, ctx);
|
||||
} else if (isPresent(stmt.falseCase)) {
|
||||
return this.visitAllStatements(stmt.falseCase, ctx);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitTryCatchStmt(stmt: o.TryCatchStmt, ctx: _ExecutionContext): any {
|
||||
try {
|
||||
return this.visitAllStatements(stmt.bodyStmts, ctx);
|
||||
} catch (e) {
|
||||
var childCtx = ctx.createChildWihtLocalVars();
|
||||
childCtx.vars.set(CATCH_ERROR_VAR, e);
|
||||
childCtx.vars.set(CATCH_STACK_VAR, e.stack);
|
||||
return this.visitAllStatements(stmt.catchStmts, childCtx);
|
||||
}
|
||||
}
|
||||
visitThrowStmt(stmt: o.ThrowStmt, ctx: _ExecutionContext): any {
|
||||
throw stmt.error.visitExpression(this, ctx);
|
||||
}
|
||||
visitCommentStmt(stmt: o.CommentStmt, context?: any): any { return null; }
|
||||
visitInstantiateExpr(ast: o.InstantiateExpr, ctx: _ExecutionContext): any {
|
||||
var args = this.visitAllExpressions(ast.args, ctx);
|
||||
var clazz = ast.classExpr.visitExpression(this, ctx);
|
||||
if (clazz instanceof _DynamicClass) {
|
||||
return clazz.instantiate(args);
|
||||
} else {
|
||||
return FunctionWrapper.apply(reflector.factory(clazz), args);
|
||||
}
|
||||
}
|
||||
visitLiteralExpr(ast: o.LiteralExpr, ctx: _ExecutionContext): any { return ast.value; }
|
||||
visitExternalExpr(ast: o.ExternalExpr, ctx: _ExecutionContext): any { return ast.value.runtime; }
|
||||
visitConditionalExpr(ast: o.ConditionalExpr, ctx: _ExecutionContext): any {
|
||||
if (ast.condition.visitExpression(this, ctx)) {
|
||||
return ast.trueCase.visitExpression(this, ctx);
|
||||
} else if (isPresent(ast.falseCase)) {
|
||||
return ast.falseCase.visitExpression(this, ctx);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitNotExpr(ast: o.NotExpr, ctx: _ExecutionContext): any {
|
||||
return !ast.condition.visitExpression(this, ctx);
|
||||
}
|
||||
visitCastExpr(ast: o.CastExpr, ctx: _ExecutionContext): any {
|
||||
return ast.value.visitExpression(this, ctx);
|
||||
}
|
||||
visitFunctionExpr(ast: o.FunctionExpr, ctx: _ExecutionContext): any {
|
||||
var paramNames = ast.params.map((param) => param.name);
|
||||
return _declareFn(paramNames, ast.statements, ctx, this);
|
||||
}
|
||||
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: _ExecutionContext): any {
|
||||
var paramNames = stmt.params.map((param) => param.name);
|
||||
ctx.vars.set(stmt.name, _declareFn(paramNames, stmt.statements, ctx, this));
|
||||
return null;
|
||||
}
|
||||
visitBinaryOperatorExpr(ast: o.BinaryOperatorExpr, ctx: _ExecutionContext): any {
|
||||
var lhs = () => ast.lhs.visitExpression(this, ctx);
|
||||
var rhs = () => ast.rhs.visitExpression(this, ctx);
|
||||
|
||||
switch (ast.operator) {
|
||||
case o.BinaryOperator.Equals:
|
||||
return lhs() == rhs();
|
||||
case o.BinaryOperator.Identical:
|
||||
return lhs() === rhs();
|
||||
case o.BinaryOperator.NotEquals:
|
||||
return lhs() != rhs();
|
||||
case o.BinaryOperator.NotIdentical:
|
||||
return lhs() !== rhs();
|
||||
case o.BinaryOperator.And:
|
||||
return lhs() && rhs();
|
||||
case o.BinaryOperator.Or:
|
||||
return lhs() || rhs();
|
||||
case o.BinaryOperator.Plus:
|
||||
return lhs() + rhs();
|
||||
case o.BinaryOperator.Minus:
|
||||
return lhs() - rhs();
|
||||
case o.BinaryOperator.Divide:
|
||||
return lhs() / rhs();
|
||||
case o.BinaryOperator.Multiply:
|
||||
return lhs() * rhs();
|
||||
case o.BinaryOperator.Modulo:
|
||||
return lhs() % rhs();
|
||||
case o.BinaryOperator.Lower:
|
||||
return lhs() < rhs();
|
||||
case o.BinaryOperator.LowerEquals:
|
||||
return lhs() <= rhs();
|
||||
case o.BinaryOperator.Bigger:
|
||||
return lhs() > rhs();
|
||||
case o.BinaryOperator.BiggerEquals:
|
||||
return lhs() >= rhs();
|
||||
default:
|
||||
throw new BaseException(`Unknown operator ${ast.operator}`);
|
||||
}
|
||||
}
|
||||
visitReadPropExpr(ast: o.ReadPropExpr, ctx: _ExecutionContext): any {
|
||||
var result;
|
||||
var receiver = ast.receiver.visitExpression(this, ctx);
|
||||
if (isDynamicInstance(receiver)) {
|
||||
var di = <DynamicInstance>receiver;
|
||||
if (di.props.has(ast.name)) {
|
||||
result = di.props.get(ast.name);
|
||||
} else if (di.getters.has(ast.name)) {
|
||||
result = di.getters.get(ast.name)();
|
||||
} else if (di.methods.has(ast.name)) {
|
||||
result = di.methods.get(ast.name);
|
||||
} else {
|
||||
result = reflector.getter(ast.name)(receiver);
|
||||
}
|
||||
} else {
|
||||
result = reflector.getter(ast.name)(receiver);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
visitReadKeyExpr(ast: o.ReadKeyExpr, ctx: _ExecutionContext): any {
|
||||
var receiver = ast.receiver.visitExpression(this, ctx);
|
||||
var prop = ast.index.visitExpression(this, ctx);
|
||||
return receiver[prop];
|
||||
}
|
||||
visitLiteralArrayExpr(ast: o.LiteralArrayExpr, ctx: _ExecutionContext): any {
|
||||
return this.visitAllExpressions(ast.entries, ctx);
|
||||
}
|
||||
visitLiteralMapExpr(ast: o.LiteralMapExpr, ctx: _ExecutionContext): any {
|
||||
var result = {};
|
||||
ast.entries.forEach((entry) => result[<string>entry[0]] =
|
||||
(<o.Expression>entry[1]).visitExpression(this, ctx));
|
||||
return result;
|
||||
}
|
||||
|
||||
visitAllExpressions(expressions: o.Expression[], ctx: _ExecutionContext): any {
|
||||
return expressions.map((expr) => expr.visitExpression(this, ctx));
|
||||
}
|
||||
|
||||
visitAllStatements(statements: o.Statement[], ctx: _ExecutionContext): ReturnValue {
|
||||
for (var i = 0; i < statements.length; i++) {
|
||||
var stmt = statements[i];
|
||||
var val = stmt.visitStatement(this, ctx);
|
||||
if (val instanceof ReturnValue) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function _declareFn(varNames: string[], statements: o.Statement[], ctx: _ExecutionContext,
|
||||
visitor: StatementInterpreter): Function {
|
||||
switch (varNames.length) {
|
||||
case 0:
|
||||
return () => _executeFunctionStatements(varNames, [], statements, ctx, visitor);
|
||||
case 1:
|
||||
return (d0) => _executeFunctionStatements(varNames, [d0], statements, ctx, visitor);
|
||||
case 2:
|
||||
return (d0, d1) => _executeFunctionStatements(varNames, [d0, d1], statements, ctx, visitor);
|
||||
case 3:
|
||||
return (d0, d1, d2) =>
|
||||
_executeFunctionStatements(varNames, [d0, d1, d2], statements, ctx, visitor);
|
||||
case 4:
|
||||
return (d0, d1, d2, d3) =>
|
||||
_executeFunctionStatements(varNames, [d0, d1, d2, d3], statements, ctx, visitor);
|
||||
case 5:
|
||||
return (d0, d1, d2, d3, d4) => _executeFunctionStatements(varNames, [d0, d1, d2, d3, d4],
|
||||
statements, ctx, visitor);
|
||||
case 6:
|
||||
return (d0, d1, d2, d3, d4, d5) => _executeFunctionStatements(
|
||||
varNames, [d0, d1, d2, d3, d4, d5], statements, ctx, visitor);
|
||||
case 7:
|
||||
return (d0, d1, d2, d3, d4, d5, d6) => _executeFunctionStatements(
|
||||
varNames, [d0, d1, d2, d3, d4, d5, d6], statements, ctx, visitor);
|
||||
case 8:
|
||||
return (d0, d1, d2, d3, d4, d5, d6, d7) => _executeFunctionStatements(
|
||||
varNames, [d0, d1, d2, d3, d4, d5, d6, d7], statements, ctx, visitor);
|
||||
case 9:
|
||||
return (d0, d1, d2, d3, d4, d5, d6, d7, d8) => _executeFunctionStatements(
|
||||
varNames, [d0, d1, d2, d3, d4, d5, d6, d7, d8], statements, ctx, visitor);
|
||||
case 10:
|
||||
return (d0, d1, d2, d3, d4, d5, d6, d7, d8, d9) => _executeFunctionStatements(
|
||||
varNames, [d0, d1, d2, d3, d4, d5, d6, d7, d8, d9], statements, ctx, visitor);
|
||||
default:
|
||||
throw new BaseException(
|
||||
'Declaring functions with more than 10 arguments is not supported right now');
|
||||
}
|
||||
}
|
||||
|
||||
var CATCH_ERROR_VAR = 'error';
|
||||
var CATCH_STACK_VAR = 'stack';
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user