Compare commits

..

2 Commits

Author SHA1 Message Date
4f1f29d7d2 docs(changelog): changelog for beta.3 2016-02-03 10:11:37 -08:00
b1b73dc39e chore(release): bump version to beta.3 2016-02-03 09:50:21 -08:00
1692 changed files with 45110 additions and 60977 deletions

View File

@ -1,16 +0,0 @@
**IMPORTANT**: This repository's issues are reserved for feature requests and bug reports. Do not submit support requests here, see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question.
**Steps to reproduce and a minimal demo of the problem**
_Use https://plnkr.co or similar -- try this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5_
_What steps should we try in your demo to see the problem?_
**Current behavior**
**Expected/desired behavior**
**Other information**

View File

@ -1,24 +0,0 @@
* **Please check if the PR fulfills these requirements**
- [ ] The commit message follows our guidelines: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit-message-format
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)
* **What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...)
* **What is the current behavior?** (You can also link to an open issue here)
* **What is the new behavior (if this is a feature change)?**
* **Does this PR introduce a breaking change?** (What changes might users need to make in their application due to this PR?)
* **Other information**:

9
.gitignore vendored
View File

@ -21,13 +21,7 @@ tmp
*.js.deps
*.js.map
# Files created by the template compiler
**/*.ngfactory.ts
**/*.css.ts
**/*.css.shim.ts
# Or type definitions we mirror from github
# (NB: these lines are removed in publish-build-artifacts.sh)
**/typings/**/*.d.ts
**/typings/tsd.cached.json
@ -54,6 +48,3 @@ npm-debug.log
# built dart payload tests
/modules_dart/payload/**/build
# rollup-test output
/modules/rollup-test/dist/

View File

@ -1,16 +1,7 @@
language: node_js
sudo: false
node_js:
- '5.4.1'
addons:
# firefox: "38.0"
apt:
sources:
# needed to install g++ that is used by npms's native modules
- ubuntu-toolchain-r-test
packages:
- g++-4.8
- '5.4.1'
branches:
except:
@ -18,175 +9,108 @@ branches:
cache:
directories:
- ./node_modules
- ./.chrome/chromium
# - $HOME/.pub-cache
#before_cache:
# # Undo the pollution of the typescript_next build before the cache is primed for future use
# - if [[ "$MODE" == "typescript_next" ]]; then npm install typescript; fi
- node_modules
- $HOME/.pub-cache
env:
global:
# - KARMA_JS_BROWSERS=ChromeNoSandbox
# - E2E_BROWSERS=ChromeOnTravis
# - LOGS_DIR=/tmp/angular-build/logs
# - ARCH=linux-x64
- KARMA_BROWSERS=DartiumWithWebPlatform
- E2E_BROWSERS=Dartium
- LOGS_DIR=/tmp/angular-build/logs
- SAUCE_USERNAME=angular-ci
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
- BROWSER_STACK_USERNAME=angularteam1
- BROWSER_STACK_ACCESS_KEY=BWCd4SynLzdDcv8xtzsB
- ARCH=linux-x64
- DART_DEV_VERSION=latest
- DART_STABLE_VERSION=latest
# Token for tsd to increase github rate limit
# See https://github.com/DefinitelyTyped/tsd#tsdrc
# This does not use http://docs.travis-ci.com/user/environment-variables/#Secure-Variables
# because those are not visible for pull requests, and those should also be reliable.
# This SSO token belongs to github account angular-github-ratelimit-token which has no access
# (password is in Valentine)
- TSDRC='{"token":"ef474500309daea53d5991b3079159a29520a40b"}'
# GITHUB_TOKEN_ANGULAR
- secure: "fq/U7VDMWO8O8SnAQkdbkoSe2X92PVqg4d044HmRYVmcf6YbO48+xeGJ8yOk0pCBwl3ISO4Q2ot0x546kxfiYBuHkZetlngZxZCtQiFT9kyId8ZKcYdXaIW9OVdw3Gh3tQyUwDucfkVhqcs52D6NZjyE2aWZ4/d1V4kWRO/LMgo="
matrix:
# Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
- CI_MODE=js
- CI_MODE=lint
- CI_MODE=e2e
- CI_MODE=saucelabs_required
- CI_MODE=browserstack_required
- MODE=dart DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
# Disable dart dev build, which is timing out after 2h. #6823
# - MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=saucelabs_required DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=browserstack_required DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=saucelabs_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=browserstack_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=dart_ddc DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=js DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=router DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=build_only DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
- MODE=lint DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=payload DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
#matrix:
# allow_failures:
# - env: "MODE=saucelabs_optional"
# - env: "MODE=browserstack_optional"
matrix:
allow_failures:
- env: "MODE=saucelabs_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
- env: "MODE=browserstack_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
# TODO(alxhub): remove when dartdoc #1039 is in dev channel
- env: "MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
addons:
firefox: "38.0"
before_install:
- npm install -g npm@3.5.3
- node tools/analytics/build-analytics start ci job
- node tools/analytics/build-analytics start ci before_install
- echo ${TSDRC} > .tsdrc
- export DISPLAY=:99.0
- export GIT_SHA=$(git rev-parse HEAD)
- ./scripts/ci/init_android.sh
- ./scripts/ci/install_dart.sh ${DART_CHANNEL} ${DART_VERSION} ${ARCH}
- sh -e /etc/init.d/xvfb start
- if [[ -e SKIP_TRAVIS_TESTS ]]; then { cat SKIP_TRAVIS_TESTS ; exit 0; } fi
- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && [ "${TRAVIS_BRANCH}" = "master" ] && SAUCE_USERNAME="angular2-ci" && SAUCE_ACCESS_KEY="693ebc16208a-0b5b-1614-8d66-a2662f4e" || true'
- node tools/analytics/build-analytics success ci before_install
install:
- ./scripts/ci-lite/install.sh
- node tools/analytics/build-analytics start ci install
# Check the size of caches
- du -sh ./node_modules || true
# Install npm dependecies
# check-node-modules will exit(1) if we don't need to install
# we need to manually kick off the postinstall script if check-node-modules exit(0)s
- node tools/npm/check-node-modules --purge && npm install || npm run postinstall
- node tools/analytics/build-analytics success ci install
before_script:
- node tools/analytics/build-analytics start ci before_script
- mkdir -p $LOGS_DIR
- ./scripts/ci/presubmit-queue-setup.sh
- node tools/analytics/build-analytics success ci before_script
script:
- ./scripts/ci-lite/build.sh && ./scripts/ci-lite/test.sh
- node tools/analytics/build-analytics start ci script
- ./scripts/ci/build_and_test.sh ${MODE}
- node tools/analytics/build-analytics success ci script
after_script:
- ./scripts/ci-lite/cleanup.sh
- node tools/analytics/build-analytics start ci after_script
- ./scripts/ci/print-logs.sh
- ./scripts/ci/after-script.sh
- ./scripts/publish/publish-build-artifacts.sh
- node tools/analytics/build-analytics success ci after_script
- if [[ $TRAVIS_TEST_RESULT -eq 0 ]]; then node tools/analytics/build-analytics success ci job; else node tools/analytics/build-analytics error ci job; fi
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/1ef62e23078036f9cee4
# trigger Buildtime Trend Service to parse Travis CI log
- https://buildtimetrend.herokuapp.com/travis
on_success: always # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: false # default: false
slack:
secure: EP4MzZ8JMyNQJ4S3cd5LEPWSMjC7ZRdzt3veelDiOeorJ6GwZfCDHncR+4BahDzQAuqyE/yNpZqaLbwRWloDi15qIUsm09vgl/1IyNky1Sqc6lEknhzIXpWSalo4/T9ZP8w870EoDvM/UO+LCV99R3wS8Nm9o99eLoWVb2HIUu0=
#branches:
# except:
# - g3_v2_0
#
#cache:
# directories:
# - $HOME/.pub-cache
# - $HOME/.chrome/chromium
#
#before_cache:
# # Undo the pollution of the typescript_next build before the cache is primed for future use
# - if [[ "$MODE" == "typescript_next" ]]; then npm install typescript; fi
#
#env:
# global:
# # Use newer verison of GCC to that is required to compile native npm modules for Node v4+ on Ubuntu Precise
# # more info: https://docs.travis-ci.com/user/languages/javascript-with-nodejs#Node.js-v4-(or-io.js-v3)-compiler-requirements
# - CXX=g++-4.8
# - KARMA_DART_BROWSERS=DartiumWithWebPlatform
# # No sandbox mode is needed for Chromium in Travis, it crashes otherwise: https://sites.google.com/a/chromium.org/chromedriver/help/chrome-doesn-t-start
# - KARMA_JS_BROWSERS=ChromeNoSandbox
# - E2E_BROWSERS=ChromeOnTravis
# - LOGS_DIR=/tmp/angular-build/logs
# - SAUCE_USERNAME=angular-ci
# - SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
# - BROWSER_STACK_USERNAME=angularteam1
# - BROWSER_STACK_ACCESS_KEY=BWCd4SynLzdDcv8xtzsB
# - ARCH=linux-x64
# - DART_DEV_VERSION=latest
# - DART_STABLE_VERSION=latest
# - DART_CHANNEL=stable
# - DART_VERSION=$DART_STABLE_VERSION
# # Token for tsd to increase github rate limit
# # See https://github.com/DefinitelyTyped/tsd#tsdrc
# # This does not use http://docs.travis-ci.com/user/environment-variables/#Secure-Variables
# # because those are not visible for pull requests, and those should also be reliable.
# # This SSO token belongs to github account angular-github-ratelimit-token which has no access
# # (password is in Valentine)
# - TSDRC='{"token":"ef474500309daea53d5991b3079159a29520a40b"}'
# # GITHUB_TOKEN_ANGULAR
# - secure: "fq/U7VDMWO8O8SnAQkdbkoSe2X92PVqg4d044HmRYVmcf6YbO48+xeGJ8yOk0pCBwl3ISO4Q2ot0x546kxfiYBuHkZetlngZxZCtQiFT9kyId8ZKcYdXaIW9OVdw3Gh3tQyUwDucfkVhqcs52D6NZjyE2aWZ4/d1V4kWRO/LMgo="
# matrix:
# # Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
# - MODE=dart
# - MODE=dart DART_CHANNEL=dev
# - MODE=saucelabs_required
# - MODE=browserstack_required
# - MODE=saucelabs_optional
# - MODE=browserstack_optional
# - MODE=dart_ddc
# - MODE=js
# - MODE=router
# - MODE=build_only
# - MODE=typescript_next
# - MODE=lint
#
#matrix:
# allow_failures:
# - env: "MODE=saucelabs_optional"
# - env: "MODE=browserstack_optional"
#
#addons:
# firefox: "38.0"
# apt:
# sources:
# - ubuntu-toolchain-r-test
# packages:
# - g++-4.8
#
#before_install:
# - node tools/analytics/build-analytics start ci job
# - node tools/analytics/build-analytics start ci before_install
# - echo ${TSDRC} > .tsdrc
# - export CHROME_BIN=$HOME/.chrome/chromium/chrome-linux/chrome
# - export DISPLAY=:99.0
# - export GIT_SHA=$(git rev-parse HEAD)
# - ./scripts/ci/init_android.sh
# - sh -e /etc/init.d/xvfb start
# # Use a separate SauseLabs account for upstream/master builds in order for Sauce to create a badge representing the status of just upstream/master
# - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && [ "${TRAVIS_BRANCH}" = "master" ] && SAUCE_USERNAME="angular2-ci" && SAUCE_ACCESS_KEY="693ebc16208a-0b5b-1614-8d66-a2662f4e" || true'
# - node tools/analytics/build-analytics success ci before_install
#
#install:
# - node tools/analytics/build-analytics start ci install
# # Install version of npm that we are locked against
# - npm install -g npm@3.5.3
# # Install version of Chromium that we are locked against
# - ./scripts/ci/install_chromium.sh
# # Install version of Dart based on the matrix build variables
# - ./scripts/ci/install_dart.sh ${DART_CHANNEL} ${DART_VERSION} ${ARCH}
# # Print the size of caches to ease debugging
# - du -sh ./node_modules || true
# # Install npm dependecies
# # check-node-modules will exit(1) if we don't need to install
# # we need to manually kick off the postinstall script if check-node-modules exit(0)s
# - node tools/npm/check-node-modules --purge && npm install || npm run postinstall
# - node tools/analytics/build-analytics success ci install
#
#before_script:
# - node tools/analytics/build-analytics start ci before_script
# - mkdir -p $LOGS_DIR
# - ./scripts/ci/presubmit-queue-setup.sh
# - node tools/analytics/build-analytics success ci before_script
#
#script:
# - node tools/analytics/build-analytics start ci script
# - ./scripts/ci/build_and_test.sh ${MODE}
# - node tools/analytics/build-analytics success ci script
#
#after_script:
# - node tools/analytics/build-analytics start ci after_script
# - ./scripts/ci/print-logs.sh
# - ./scripts/ci/after-script.sh
# - ./scripts/publish/publish-build-artifacts.sh
# - node tools/analytics/build-analytics success ci after_script
# - tools/analytics/build-analytics $TRAVIS_TEST_RESULT ci job
#
#notifications:
# webhooks:
# urls:
# - https://webhooks.gitter.im/e/1ef62e23078036f9cee4
# # trigger Buildtime Trend Service to parse Travis CI log
# - https://buildtimetrend.herokuapp.com/travis
# - http://104.197.9.155:8484/hubot/travis/activity
# on_success: always # options: [always|never|change] default: always
# on_failure: always # options: [always|never|change] default: always
# on_start: never # default: never
# slack:
# secure: EP4MzZ8JMyNQJ4S3cd5LEPWSMjC7ZRdzt3veelDiOeorJ6GwZfCDHncR+4BahDzQAuqyE/yNpZqaLbwRWloDi15qIUsm09vgl/1IyNky1Sqc6lEknhzIXpWSalo4/T9ZP8w870EoDvM/UO+LCV99R3wS8Nm9o99eLoWVb2HIUu0=

View File

@ -1,568 +1,3 @@
<a name="2.0.0-beta.17"></a>
# 2.0.0-beta.17 (2016-04-28)
### Bug Fixes
* **changelog:** fix changelog script. ([c209836](https://github.com/angular/angular/commit/c209836))
* **compiler:** Allow templates to access variables that are declared afterwards. ([1e8864c](https://github.com/angular/angular/commit/1e8864c)), closes [#8261](https://github.com/angular/angular/issues/8261)
* **core:** properly evaluate expressions with conditional and boolean operators ([1ad2a02](https://github.com/angular/angular/commit/1ad2a02)), closes [#8235](https://github.com/angular/angular/issues/8235) [#8244](https://github.com/angular/angular/issues/8244) [#8282](https://github.com/angular/angular/issues/8282)
* **metadata:** Do not attach module names to metadata. ([d964888](https://github.com/angular/angular/commit/d964888)), closes [#8225](https://github.com/angular/angular/issues/8225) [#8082](https://github.com/angular/angular/issues/8082) [#8256](https://github.com/angular/angular/issues/8256)
* **testing:** allow test component builder to override directives from lists ([ff2ae7a](https://github.com/angular/angular/commit/ff2ae7a)), closes [#7397](https://github.com/angular/angular/issues/7397) [#8217](https://github.com/angular/angular/issues/8217)
### Features
* **compiler:** ElementSchema now has explicit DOM schema information ([d327ac4](https://github.com/angular/angular/commit/d327ac4)), closes [#8179](https://github.com/angular/angular/issues/8179)
* **core:** separate refs from vars. ([d2efac1](https://github.com/angular/angular/commit/d2efac1)), closes [#7158](https://github.com/angular/angular/issues/7158) [#8264](https://github.com/angular/angular/issues/8264)
### BREAKING CHANGES
The reference `#...` now always means `ref-`.
**Before:**
- Outside of `ngFor`, a `#...` meant a reference.
- Inside of `ngFor`, it meant a local variable.
This was pattern was confusing.
**After:**
- `<template #abc>` now defines a reference to a TemplateRef, instead of an input variable used inside of the template.
- Inside of structural directives that declare local variables, such as `*ngFor`, usage of `#...` is deprecated. Use `let` instead.
- `<div *ngFor="#item of items">` now becomes `<div *ngFor="let item of items">`
- `var-...` is deprecated.
- use `#` or a `ref-` outside of `*ngFor`
- for `ngFor`, use the syntax: `<template ngFor let-... [ngForOf]="...">`
<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
* **codegen:** produce `.ngfactory.dart/ts` files instead of `.template.dart/ts` files. ([c06b0a2](https://github.com/angular/angular/commit/c06b0a2))
* **core:** add `Query.read` and remove `DynamicComponentLoader.loadIntoLocation`. ([efbd446](https://github.com/angular/angular/commit/efbd446))
* **core:** introduce ComponentFactory. ([0c600cf](https://github.com/angular/angular/commit/0c600cf))
* **core:** separate reflective injector from Injector interface ([0a7d10b](https://github.com/angular/angular/commit/0a7d10b))
* **core:** support importUri in StaticReflector ([3e11422](https://github.com/angular/angular/commit/3e11422)), closes [#8195](https://github.com/angular/angular/issues/8195)
* **core:** support non reflective bootstrap. ([9092ac7](https://github.com/angular/angular/commit/9092ac7))
* **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))
* **Location:** out of router and into platform/common ([b602bd8](https://github.com/angular/angular/commit/b602bd8)), closes [#7962](https://github.com/angular/angular/issues/7962)
* **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)
* **view_compiler:** codegen DI and Queries ([2b34c88](https://github.com/angular/angular/commit/2b34c88)), closes [#6301](https://github.com/angular/angular/issues/6301) [#6567](https://github.com/angular/angular/issues/6567)
### BREAKING CHANGES
* - pipes now take a variable number of arguments, and not an array that contains all arguments.
* 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([...], (...) => {...}))
```
You will also need to add the dependency
`'node_modules/zone.js/dist/fake-async-test.js'`
as a served file in your Karma or other test configuration.
* - Injector was renamed into `ReflectiveInjector`,
as `Injector` is only an abstract class with one method on it
- `Injector.getOptional()` was changed into `Injector.get(token, notFoundValue)`
to make implementing injectors simpler
- `ViewContainerRef.createComponent` now takes an `Injector`
instead of `ResolvedProviders`. If a reflective injector
should be used, create one before calling this method.
(e.g. via `ReflectiveInjector.resolveAndCreate(…)`.
* - `DynamicComponentLoader.loadIntoLocation` has been removed. Use `@ViewChild(myVar, read: ViewContainerRef)` to get hold of a `ViewContainerRef` at an element with variable `myVar`. Then call `DynamicComponentLoader.loadNextToLocation`.
- `DynamicComponentLoader.loadNextToLocation` now takes a `ViewContainerRef` instead of an `ElementRef`.
- `AppViewManager` is renamed into `ViewUtils` and is a mere private utility service.
* - `Compiler` is renamed to `ComponentResolver`,
`Compiler.compileInHost` has been renamed to `ComponentResolver.resolveComponent`.
- `ComponentRef.dispose` is renamed to `ComponentRef.destroy`
- `ViewContainerRef.createHostView` is renamed to `ViewContainerRef.createComponent`
- `ComponentFixture_` has been removed, the class `ComponentFixture`
can now be created directly as it is no more using private APIs.
* `Location` and other related providers have been moved out of `router` and into `platform/common`. `BrowserPlatformLocation` is not meant to be used directly however advanced configurations may use it via the following import change.
Before:
```
import {
PlatformLocation,
Location,
LocationStrategy,
HashLocationStrategy,
PathLocationStrategy,
APP_BASE_HREF}
from 'angular2/router';
import {BrowserPlatformLocation} from 'angular2/src/router/location/browser_platform_location';
```
After:
```
import {
PlatformLocation,
Location,
LocationStrategy,
HashLocationStrategy,
PathLocationStrategy,
APP_BASE_HREF}
from 'angular2/platform/common';
import {BrowserPlatformLocation} from 'angular2/src/platform/browser/location/browser_platform_location';
```
* `injectAsync` is now deprecated. Instead, use the `async` function
to wrap any asynchronous tests.
You will also need to add the dependency
`'node_modules/zone.js/dist/async-test.js'`
as a served file in your Karma or other test configuration.
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); });
}));
```
* - Renderer:
* renderComponent method is removed form `Renderer`, only present on `RootRenderer`
* Renderer.setDebugInfo is removed. Renderer.createElement / createText / createTemplateAnchor
now take the DebugInfo directly.
- Query semantics:
* Queries don't work with dynamically loaded components.
* e.g. for router-outlet: loaded components can't be queries via @ViewQuery,
but router-outlet emits an event `activate` now that emits the activated component
- Exception classes and the context inside changed (renamed fields)
- DebugElement.attributes is an Object and not a Map in JS any more
- ChangeDetectorGenConfig was renamed into CompilerConfig
- AppViewManager.createEmbeddedViewInContainer / AppViewManager.createHostViewInContainer
are removed, use the methods in ViewContainerRef instead
- Change detection order changed:
* 1. dirty check component inputs
* 2. dirty check content children
* 3. update render nodes
<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)
### Bug Fixes
* **build:** MetadataCollector correctly collects property metadata ([111afcd](https://github.com/angular/angular/commit/111afcd)), closes [#7772](https://github.com/angular/angular/issues/7772) [#7773](https://github.com/angular/angular/issues/7773)
* **codegen:** stringify using an opaque ID when toString contains parens. ([90c87fa](https://github.com/angular/angular/commit/90c87fa)), closes [#7825](https://github.com/angular/angular/issues/7825)
* **ngFor:** give more instructive error when binding to non-iterable ([49527ab](https://github.com/angular/angular/commit/49527ab))
* **Router:** handling of special chars in dynamic segments ([0bcfcde](https://github.com/angular/angular/commit/0bcfcde)), closes [#7804](https://github.com/angular/angular/issues/7804)
* **upgrade:** make ngUpgrade work with testability API ([430f367](https://github.com/angular/angular/commit/430f367)), closes [#7603](https://github.com/angular/angular/issues/7603)
### Features
* **build:** Persisting decorator metadata ([ae876d1](https://github.com/angular/angular/commit/ae876d1))
* **compiler:** assert that Component.style is an array ([6de68e2](https://github.com/angular/angular/commit/6de68e2)), closes [#7559](https://github.com/angular/angular/issues/7559)
* **compiler:** Resolvers now use DI to create reflector ([506f4ce](https://github.com/angular/angular/commit/506f4ce)), closes [#7762](https://github.com/angular/angular/issues/7762)
* **Compiler:** Allow overriding the projection selector ([aa966f5](https://github.com/angular/angular/commit/aa966f5)), closes [#6303](https://github.com/angular/angular/issues/6303) [#7742](https://github.com/angular/angular/issues/7742)
* **dart:** Add a dev-mode check for undeclared lifecycle interfaces ([1c20a62](https://github.com/angular/angular/commit/1c20a62)), closes [#6849](https://github.com/angular/angular/issues/6849)
* **facade:** add ListWrapper.flatten ([a1880c3](https://github.com/angular/angular/commit/a1880c3))
* **facade:** add RegExpWrapper.replaceAll to replace all matches using the provided function ([91999e0](https://github.com/angular/angular/commit/91999e0))
* **html_parser:** change HtmlElementAst to store both the start and the end positions ([17c8ec8](https://github.com/angular/angular/commit/17c8ec8))
* **i18n:** implement an i18n-aware html parser ([d272f96](https://github.com/angular/angular/commit/d272f96)), closes [#7738](https://github.com/angular/angular/issues/7738)
* **i18n:** implement xmb deserialization ([d7e1175](https://github.com/angular/angular/commit/d7e1175))
* **i18n:** reexport I18nHtmlParser through the i18n barrel ([d2ca7d8](https://github.com/angular/angular/commit/d2ca7d8))
* **i18n:** update I18nHtmlParser to accept parsed messages ([756121a](https://github.com/angular/angular/commit/756121a))
* **i18n:** update transformers to read a xmb file when provided and use I18nHtmlParser in t ([8430927](https://github.com/angular/angular/commit/8430927)), closes [#7790](https://github.com/angular/angular/issues/7790)
### 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>`
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)
### Bug Fixes
* **angular_1_router:** ng-link is generating wrong hrefs ([69c1405](https://github.com/angular/angular/commit/69c1405)), closes [#7423](https://github.com/angular/angular/issues/7423)
* **angular1_router:** support link generation with custom hashPrefixes ([0f8efce](https://github.com/angular/angular/commit/0f8efce))
* **package.json:** remove es6-promise from the peerDependency list ([8b67b07](https://github.com/angular/angular/commit/8b67b07))
### Features
* **dart/transform:** Use angular2/platform/browser as bootstrap lib ([b6507e3](https://github.com/angular/angular/commit/b6507e3)), closes [#7647](https://github.com/angular/angular/issues/7647)
<a name="2.0.0-beta.11"></a>
# 2.0.0-beta.11 (2016-03-18)
### Bug Fixes
* make sure that Zone does not show up in angular2.d.ts ([d4e9b55](https://github.com/angular/angular/commit/d4e9b55fb69d87f948d02905d34fc78221adb11a))
* **common:** remove @internal annotation on SwitchView ([967ae3e](https://github.com/angular/angular/commit/967ae3e)), closes [#7657](https://github.com/angular/angular/issues/7657)
* **router:** RouterOutlet loads component twice in a race condition ([2f581ff](https://github.com/angular/angular/commit/2f581ff)), closes [#7497](https://github.com/angular/angular/issues/7497) [#7545](https://github.com/angular/angular/issues/7545)
### Features
* **i18n:** add a simple dart script extracting all i18n messages from a package ([8326ab3](https://github.com/angular/angular/commit/8326ab3)), closes [#7620](https://github.com/angular/angular/issues/7620)
* **i18n:** create i18n barrel ([a7fe983](https://github.com/angular/angular/commit/a7fe983))
* **i18n:** implement xmb serializer ([e1f8e54](https://github.com/angular/angular/commit/e1f8e54))
<a name="2.0.0-beta.10"></a>
# 2.0.0-beta.10 (2016-03-17)
### Bug Fixes
* **change_detection:** fix a memory leak ([128acbb](https://github.com/angular/angular/commit/128acbb))
* **closure:** don't throw from top-level ([5824866](https://github.com/angular/angular/commit/5824866))
* **router:** handle URL that does not match a route ([8e3e450](https://github.com/angular/angular/commit/8e3e450)), closes [#7349](https://github.com/angular/angular/issues/7349) [#7203](https://github.com/angular/angular/issues/7203)
* **router/instruction:** ensure toLinkUrl includes extra params ([0d58b13](https://github.com/angular/angular/commit/0d58b13)), closes [#7367](https://github.com/angular/angular/issues/7367)
### Features
* **compiler:** change html parser to preserve comments ([70d18b5](https://github.com/angular/angular/commit/70d18b5))
* **core:** introduce a CSS lexer/parser ([b72bab4](https://github.com/angular/angular/commit/b72bab4))
* **core:** introduce a CSS lexer/parser ([293fa55](https://github.com/angular/angular/commit/293fa55))
* **facade:** add .values to StringMapWrapper ([f1796d6](https://github.com/angular/angular/commit/f1796d6))
* **i18n:** add ngPlural directive ([df1f78e](https://github.com/angular/angular/commit/df1f78e))
* **i18n:** implement a simple version of message extractor ([095db67](https://github.com/angular/angular/commit/095db67)), closes [#7454](https://github.com/angular/angular/issues/7454)
* **shadow_css:** support `/deep/` and `>>>` ([cb38d72](https://github.com/angular/angular/commit/cb38d72)), closes [#7562](https://github.com/angular/angular/issues/7562) [#7563](https://github.com/angular/angular/issues/7563)
* **TAG_DEFINITIONS:** include <meta> and <base> ([2c7c3e3](https://github.com/angular/angular/commit/2c7c3e3)), closes [#7455](https://github.com/angular/angular/issues/7455)
### BREAKING CHANGES
Removed deprecated API from NgZone
- `NgZone.overrideOnTurnStart`
- `NgZone.overrideOnTurnDone`
- `NgZone.overrideOnEventDone`
- `NgZone.overrideOnErrorHandler`
Rename NgZone API
- `NgZone.onTurnStart` => `NgZone.onUnstable`
- `NgZone.onTurnDone` => `NgZone.onMicrotaskEmpty`
- `NgZone.onEventDone` => `NgZone.onStable`
<a name="2.0.0-beta.9"></a>
# 2.0.0-beta.9 (2016-03-09)
### Bug Fixes
* **angular_1_router:** Renamed require statements after TypeScript files are transpiled ([ae49085](https://github.com/angular/angular/commit/ae49085)), closes [#7049](https://github.com/angular/angular/issues/7049)
* **angular1_router:** rename `router` component binding to `$router` ([2548ce8](https://github.com/angular/angular/commit/2548ce8))
* **angular1_router:** rename `router` component binding to `$router` ([1174473](https://github.com/angular/angular/commit/1174473))
* **angular1_router:** support templateUrl components ([5586c29](https://github.com/angular/angular/commit/5586c29))
* **build:** Use fixed version of Chromium Canary that will be updated manually instead of au ([1d49b3e](https://github.com/angular/angular/commit/1d49b3e))
* **router:** support outlets within dynamic components ([7d44b82](https://github.com/angular/angular/commit/7d44b82))
### Features
* **angular1_router:** Add ng-link-active class to active ng-link ([11e8aa2](https://github.com/angular/angular/commit/11e8aa2)), closes [#6882](https://github.com/angular/angular/issues/6882)
* **compiler:** Added spans to HTML parser errors ([19a08f3](https://github.com/angular/angular/commit/19a08f3))
* **dart:** Add a dev-mode check for undeclared lifecycle interfaces ([a3d7629](https://github.com/angular/angular/commit/a3d7629)), closes [#6849](https://github.com/angular/angular/issues/6849)
* **dart/transform:** Create standalone transformers for phases ([15e1614](https://github.com/angular/angular/commit/15e1614))
* **iterable_differ:** support immutable lists ([a10c02c](https://github.com/angular/angular/commit/a10c02c)), closes [#7127](https://github.com/angular/angular/issues/7127)
* **router:** add regex matchers ([75343eb](https://github.com/angular/angular/commit/75343eb)), closes [#7325](https://github.com/angular/angular/issues/7325) [#7126](https://github.com/angular/angular/issues/7126)
* **router:** Added method to get current instruction ([6dce4f4](https://github.com/angular/angular/commit/6dce4f4))
* **transformers:** change 'Missing Identifier' to be an error ([45fd6f0](https://github.com/angular/angular/commit/45fd6f0)), closes [#7403](https://github.com/angular/angular/issues/7403)
* **transformers:** collect provider information ([81beb1c](https://github.com/angular/angular/commit/81beb1c))
### BREAKING CHANGES
* The recently added binding of the current router to the current component
has been renamed from `router` to `$router`.
So now the recommended set up for your bindings in your routed component
is:
```js
{
...
bindings: {
$router: '<'
}
}
```
* The recently added binding of the current router to the current component
has been renamed from `router` to `$router`.
So now the recommended set up for your bindings in your routed component
is:
```js
{
...
bindings: {
$router: '<'
}
}
```
<a name="2.0.0-beta.8"></a>
# 2.0.0-beta.8 (2016-03-02)
### Bug Fixes
* **angular1_router:** rename `$route` service to `$rootRouter` ([a1c3be2](https://github.com/angular/angular/commit/a1c3be2))
* **angular1_router:** rename `router` component binding to `$router` ([edad8e3](https://github.com/angular/angular/commit/edad8e3))
* **angular1_router:** support templateUrl components ([d4a4d81](https://github.com/angular/angular/commit/d4a4d81))
* **change_detection:** allow to destroy `OnPush` components inside of a host event. ([280b86e](https://github.com/angular/angular/commit/280b86e))
* **change_detection:** allow to destroy `OnPush` components inside of a host event. ([ebd438f](https://github.com/angular/angular/commit/ebd438f)), closes [#7192](https://github.com/angular/angular/issues/7192)
* **core:** support `ngFor` that has an `ngIf` as last node ([1779caf](https://github.com/angular/angular/commit/1779caf)), closes [#6304](https://github.com/angular/angular/issues/6304) [#6878](https://github.com/angular/angular/issues/6878)
* **dart/payload:** Fix runtime error in hello_world payload app ([eeb594c](https://github.com/angular/angular/commit/eeb594c)), closes [#7358](https://github.com/angular/angular/issues/7358)
* **differ:** clean up stale identity change refs ([ab36ea0](https://github.com/angular/angular/commit/ab36ea0)), closes [#7193](https://github.com/angular/angular/issues/7193)
* **DomRenderer:** correctly handle namespaced attributes ([c6afea6](https://github.com/angular/angular/commit/c6afea6))
* **Router:** Query strings are copied for HashLocationStrategy ([b47f80e](https://github.com/angular/angular/commit/b47f80e)), closes [#7298](https://github.com/angular/angular/issues/7298)
* **test:** fix a broken test ([9aedef2](https://github.com/angular/angular/commit/9aedef2))
* **transformers:** record reflection info about abstract classes ([05c185a](https://github.com/angular/angular/commit/05c185a)), closes [#7347](https://github.com/angular/angular/issues/7347)
* **transformers:** replace an error with a warning when cannot resolve a symbol ([ee3c580](https://github.com/angular/angular/commit/ee3c580))
* **transformers:** special case types some built-in types, so they can be resolved ([331b9c1](https://github.com/angular/angular/commit/331b9c1))
* **web_worker:** wait for bindings in kitchen sink spec ([4a93f58](https://github.com/angular/angular/commit/4a93f58))
* **web_workers:** make waitForElementText function more stable ([f6a8d04](https://github.com/angular/angular/commit/f6a8d04))
* **WebWorker:** Fix PostMessageBusSink and Source undefined error. ([01fe7f5](https://github.com/angular/angular/commit/01fe7f5)), closes [#7156](https://github.com/angular/angular/issues/7156)
* **WebWorker:** Make MessageBus EventEmitter synchronous ([69c1694](https://github.com/angular/angular/commit/69c1694))
### Features
* **core:** Add `QueryList.forEach` to public api. ([e7470d5](https://github.com/angular/angular/commit/e7470d5))
* **core:** Add `QueryList#forEach` ([b634a25](https://github.com/angular/angular/commit/b634a25))
* **core:** add more debug APIs to inspect the application form a browser ([b5e6319](https://github.com/angular/angular/commit/b5e6319)), closes [#7045](https://github.com/angular/angular/issues/7045) [#7161](https://github.com/angular/angular/issues/7161)
* **core:** drop `ChangeDetectionStrategy.OnPushObserve` ([f60fa14](https://github.com/angular/angular/commit/f60fa14))
* **di:** drop support for injecting types with generics in Dart ([c9a3df9](https://github.com/angular/angular/commit/c9a3df9)), closes [#7262](https://github.com/angular/angular/issues/7262)
* **forms/validators:** pattern validator ([38cb526](https://github.com/angular/angular/commit/38cb526)), closes [#5561](https://github.com/angular/angular/issues/5561)
* **i18n:** added i18nPlural and i18nSelect pipes ([59629a0](https://github.com/angular/angular/commit/59629a0)), closes [#7268](https://github.com/angular/angular/issues/7268)
* **pipes:** add ReplacePipe for string manipulation ([6ef2121](https://github.com/angular/angular/commit/6ef2121))
* **test:** add withProviders for per test providers ([c1a0af5](https://github.com/angular/angular/commit/c1a0af5)), closes [#5128](https://github.com/angular/angular/issues/5128)
* **transformers:** collect data needed for the template compiler ([ebe531b](https://github.com/angular/angular/commit/ebe531b)), closes [#7299](https://github.com/angular/angular/issues/7299)
* **transformers:** collect information for CompileDiDependencyMetadata ([39b6e0e](https://github.com/angular/angular/commit/39b6e0e))
* **transformers:** makes the map of resolved identifiers configurable ([0bb10d6](https://github.com/angular/angular/commit/0bb10d6)), closes [#7359](https://github.com/angular/angular/issues/7359)
### BREAKING CHANGES
* `OnPushObserve` was an experimental
feature for Dart and had
conceptual performance problems,
as setting up observables is slow.
Use `OnPush` instead.
* In Dart we used to support injecting types with generics. As this feature is hard to implement with the upcoming codegen we are dropping it.
Merge cl/115454020 in G3 with this change.
* The `$router` injectable service has been renamed to `$rootRouter`
* The recently added binding of the current router to the current component
has been renamed from `router` to `$router`.
So now the recommended set up for your bindings in your routed component
is:
```js
{
...
bindings: {
$router: '<'
}
}
```
<a name="2.0.0-beta.7"></a>
# 2.0.0-beta.7 (2016-02-18)
### Bug Fixes
* **angular_1_router:** Added DI string tokens ([3478d5d](https://github.com/angular/angular/commit/3478d5d)), closes [#4269](https://github.com/angular/angular/issues/4269) [#7031](https://github.com/angular/angular/issues/7031)
* **typing:** Remove re-export of the Promise built-in type. ([265703b](https://github.com/angular/angular/commit/265703b)), closes [#6468](https://github.com/angular/angular/issues/6468)
<a name="2.0.0-beta.6"></a>
# 2.0.0-beta.6 (2016-02-11)
### Bug Fixes
* **angular1-router:** add missing wrapper methods ([55122cd](https://github.com/angular/angular/commit/55122cd)), closes [#6763](https://github.com/angular/angular/issues/6763) [#6861](https://github.com/angular/angular/issues/6861) [#6861](https://github.com/angular/angular/issues/6861)
* **angular1-router:** add support for using the component helper ([d86be24](https://github.com/angular/angular/commit/d86be24)), closes [angular/angular.js#13860](https://github.com/angular/angular.js/issues/13860) [#6076](https://github.com/angular/angular/issues/6076) [#5278](https://github.com/angular/angular/issues/5278)
* **async:** handle synchronous initial value in async pipe ([26e60d6](https://github.com/angular/angular/commit/26e60d6)), closes [#5996](https://github.com/angular/angular/issues/5996)
* **build:** don't try to copy .d.ts files into the npm distro ([16b5217](https://github.com/angular/angular/commit/16b5217)), closes [#6921](https://github.com/angular/angular/issues/6921)
* **compiler:** fix interpolation regexp ([9b0e10e](https://github.com/angular/angular/commit/9b0e10e)), closes [#6056](https://github.com/angular/angular/issues/6056)
* **compiler:** use event names for matching directives ([231773e](https://github.com/angular/angular/commit/231773e)), closes [#6870](https://github.com/angular/angular/issues/6870)
* **core:** add detail to dehydrated detector exception ([e7ad03c](https://github.com/angular/angular/commit/e7ad03c)), closes [#6939](https://github.com/angular/angular/issues/6939)
* **core:** mute mode printing in console in prod mode ([74be3d3](https://github.com/angular/angular/commit/74be3d3)), closes [#6873](https://github.com/angular/angular/issues/6873)
* **di:** throw if a token uses more than 20 dependencies. ([de77700](https://github.com/angular/angular/commit/de77700)), closes [#6690](https://github.com/angular/angular/issues/6690) [#6869](https://github.com/angular/angular/issues/6869)
* **forms:** add RadioButtonValueAccessor to the list of default value accessors ([8f47aa3](https://github.com/angular/angular/commit/8f47aa3))
* **forms:** add support for radio buttons ([e725542](https://github.com/angular/angular/commit/e725542)), closes [#6877](https://github.com/angular/angular/issues/6877)
* **forms:** use strict runtimeType checks instead of instanceof ([50548fb](https://github.com/angular/angular/commit/50548fb)), closes [#6981](https://github.com/angular/angular/issues/6981)
* **Headers:** serializable toJSON ([b55f176](https://github.com/angular/angular/commit/b55f176)), closes [#6073](https://github.com/angular/angular/issues/6073) [#6714](https://github.com/angular/angular/issues/6714)
* **ngFor:** update view locals if identity changes ([0f10624](https://github.com/angular/angular/commit/0f10624)), closes [#6923](https://github.com/angular/angular/issues/6923)
* **router:** Added route data to normalized async route ([df7885c](https://github.com/angular/angular/commit/df7885c)), closes [#6802](https://github.com/angular/angular/issues/6802)
* **router:** don't prepend `/` unnecessarily to Location paths ([c603643](https://github.com/angular/angular/commit/c603643)), closes [#6729](https://github.com/angular/angular/issues/6729) [#5502](https://github.com/angular/angular/issues/5502)
* **router:** fix incorrect url param value coercion of 1 to true ([995a9e0](https://github.com/angular/angular/commit/995a9e0)), closes [#5346](https://github.com/angular/angular/issues/5346) [#6286](https://github.com/angular/angular/issues/6286)
* **router:** fix url path for star segment in path recognizer ([6f1ef33](https://github.com/angular/angular/commit/6f1ef33)), closes [#6976](https://github.com/angular/angular/issues/6976)
* **router:** fixed the location wrapper for angular1 ([e73fee7](https://github.com/angular/angular/commit/e73fee7)), closes [#6943](https://github.com/angular/angular/issues/6943)
* **typings:** Don't expose typing dependencies to users. ([2a70f4e](https://github.com/angular/angular/commit/2a70f4e)), closes [#5973](https://github.com/angular/angular/issues/5973) [#5807](https://github.com/angular/angular/issues/5807) [#6266](https://github.com/angular/angular/issues/6266) [#5242](https://github.com/angular/angular/issues/5242) [#6817](https://github.com/angular/angular/issues/6817) [#6267](https://github.com/angular/angular/issues/6267)
* **upgrade:** fix infinite $rootScope.$digest() ([7e0f02f](https://github.com/angular/angular/commit/7e0f02f)), closes [#6385](https://github.com/angular/angular/issues/6385) [#6386](https://github.com/angular/angular/issues/6386)
* **Validators:** fix Validators.required marking number zero as invalid ([c2ceb7f](https://github.com/angular/angular/commit/c2ceb7f)), closes [#6617](https://github.com/angular/angular/issues/6617)
* **WebWorkers:** Fix flaky WebWorker test ([da1fcfd](https://github.com/angular/angular/commit/da1fcfd)), closes [#6851](https://github.com/angular/angular/issues/6851)
### Features
* **angular1_router:** allow component to bind to router ([0f22dce](https://github.com/angular/angular/commit/0f22dce))
* **typings:** install es6-shim typings to a location users can reference. ([f1f5b45](https://github.com/angular/angular/commit/f1f5b45))
### BREAKING CHANGES
Transitive typings are no longer included in the distribution.
If you use `--target=es5`, you will need to add a line somewhere in your
application (for example, at the top of the `.ts` file where you call `bootstrap`):
```
///<reference path="node_modules/angular2/typings/browser.d.ts"/>
```
(Note that if your file is not in the same directory as `node_modules`, you'll
need to add one or more `../` to the start of that path.)
If you have unit tests, you need to install typings in your project using
http://github.com/typings/typings
And install typings such as `jasmine`, `angular-protractor`, or `selenium-webdriver`
to satisfy the type-checker.
If you rely on es6 APIs other than Promises and Collections, you will need to
install the es6-shim typing instead of using the <reference> tag above.
Angular previously exposed typings for the entire ES6 API.
<a name="2.0.0-beta.5"></a>
# 2.0.0-beta.5 (2016-02-10)
This release was incorrect; replaced with beta.6.
<a name="2.0.0-beta.4"></a>
# 2.0.0-beta.4 (2016-02-10)
This release was incorrect; replaced with beta.6.
<a name="2.0.0-beta.3"></a>
# 2.0.0-beta.3 (2016-02-03)
@ -592,52 +27,6 @@ This release was incorrect; replaced with beta.6.
* **dart/transform:** Only process deferred libs when necessary ([f56df65](https://github.com/angular/angular/commit/f56df65)), closes [#6745](https://github.com/angular/angular/issues/6745)
### BREAKING CHANGES
This is a breaking change for unit tests. The API for the DebugElement
has changed. Now, there is a DebugElement or DebugNode for every node
in the DOM, not only nodes with an ElementRef. `componentViewChildren` is
removed, and `childNodes` is a list of ElementNodes corresponding to every
child in the DOM. `query` no longer takes a scope parameter, since
the entire rendered DOM is included in the `childNodes`.
Before:
```
componentFixture.debugElement.componentViewChildren[0];
```
After
```
// Depending on the DOM structure of your component, the
// index may have changed or the first component child
// may be a sub-child.
componentFixture.debugElement.children[0];
```
Before:
```
debugElement.query(By.css('div'), Scope.all());
```
After:
```
debugElement.query(By.css('div'));
```
Before:
```
componentFixture.debugElement.elementRef;
```
After:
```
componentFixture.elementRef;
```
<a name="2.0.0-beta.2"></a>
# 2.0.0-beta.2 (2016-01-28)

View File

@ -180,8 +180,8 @@ Must be one of the following:
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **perf**: A code change that improves performance
* **test**: Adding missing tests or correcting existing tests
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
* **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
* **build**: Changes that affect the build system, CI configuration or external dependencies (example scopes: gulp, broccoli, npm)
* **ci**: Any changes to our CI configuration files and scripts (Travis, Circle CI, BrowserStack, SauceLabs)
* **chore**: Other changes that don't modify `src` or `test` files
### Scope

View File

@ -1,19 +1,18 @@
[![Build Status](https://travis-ci.org/angular/angular.svg?branch=master)](https://travis-ci.org/angular/angular)
[![Build Status](https://travis-ci.org/angular/angular.svg?branch=master)](https://travis-ci.org/angular/angular)
[![Join the chat at https://gitter.im/angular/angular](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Issue Stats](http://issuestats.com/github/angular/angular/badge/pr)](http://issuestats.com/github/angular/angular)
[![Issue Stats](http://issuestats.com/github/angular/angular/badge/issue)](http://issuestats.com/github/angular/angular)
[![npm version](https://badge.fury.io/js/angular2.svg)](http://badge.fury.io/js/angular2)
[![Downloads](http://img.shields.io/npm/dm/angular2.svg)](https://npmjs.org/package/angular2)
[![Sauce Test Status](https://saucelabs.com/browser-matrix/angular2-ci.svg)](https://saucelabs.com/u/angular2-ci)
Angular
Angular
=========
Angular is a development platform for building mobile and desktop web applications. This is the
repository for [Angular 2][ng2], both the JavaScript (JS) and [Dart][dart] versions.
Angular 2 is currently in **Beta**.
Angular 2 is currently in **Beta**.
## Quickstart

View File

@ -117,7 +117,7 @@ speed things up is to use plain class fields in your expressions and avoid any
kinds of computation. Example:
```typescript
@Component({
@View({
template: '<button [enabled]="isEnabled">{{title}}</button>'
})
class FancyButton {

View File

@ -4,9 +4,8 @@
var CIconfiguration = {
'Chrome': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'Firefox': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
// FirefoxBeta should be required:true
// https://github.com/angular/angular/issues/7560
'FirefoxBeta': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: false}},
'ChromeBeta': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'FirefoxBeta': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'ChromeDev': { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
'FirefoxDev': { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
'IE9': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
@ -38,7 +37,7 @@ var customLaunchers = {
'SL_CHROME': {
base: 'SauceLabs',
browserName: 'chrome',
version: '50'
version: '46'
},
'SL_CHROMEBETA': {
base: 'SauceLabs',
@ -53,7 +52,7 @@ var customLaunchers = {
'SL_FIREFOX': {
base: 'SauceLabs',
browserName: 'firefox',
version: '45'
version: '42'
},
'SL_FIREFOXBETA': {
base: 'SauceLabs',
@ -299,7 +298,12 @@ module.exports = {
customLaunchers: customLaunchers,
sauceAliases: sauceAliases,
browserstackAliases: browserstackAliases
};
}
if (process.env.TRAVIS) {
process.env.SAUCE_ACCESS_KEY = process.env.SAUCE_ACCESS_KEY.split('').reverse().join('');
process.env.BROWSER_STACK_ACCESS_KEY = process.env.BROWSER_STACK_ACCESS_KEY.split('').reverse().join('');
}
function buildConfiguration(type, target, required) {
return Object.keys(CIconfiguration)

View File

@ -1,97 +0,0 @@
#!/usr/bin/env bash
set -e -o pipefail
cd `dirname $0`
TSCONFIG=./modules/tsconfig.json
echo "====== (all)COMPILING: \$(npm bin)/ng2tc -p ${TSCONFIG} ====="
rm -rf ./dist/all/
mkdir ./dist/all/
# prepare all files for e2e tests
cp -r ./modules/playground ./dist/all/
cp -r ./modules/playground/favicon.ico ./dist/
#rsync -aP ./modules/playground/* ./dist/all/playground/
mkdir ./dist/all/playground/vendor
cd ./dist/all/playground/vendor
ln -s ../../../../node_modules/es6-shim/es6-shim.js .
ln -s ../../../../node_modules/zone.js/dist/zone.js .
ln -s ../../../../node_modules/zone.js/dist/long-stack-trace-zone.js .
ln -s ../../../../node_modules/systemjs/dist/system.src.js .
ln -s ../../../../node_modules/base64-js/lib/b64.js .
ln -s ../../../../node_modules/reflect-metadata/Reflect.js .
ln -s ../../../../node_modules/rxjs/bundles/Rx.js .
ln -s ../../../../node_modules/angular/angular.js .
cd -
# compile ts code
$(npm bin)/ng2tc -p ${TSCONFIG}
rm -rf ./dist/packages-dist
for PACKAGE in \
core \
compiler \
common \
platform-browser \
platform-browser-dynamic \
platform-server \
http \
router \
router-deprecated \
upgrade
do
SRCDIR=./modules/@angular/${PACKAGE}
DESTDIR=./dist/packages-dist/${PACKAGE}
UMDES6PATH=${DESTDIR}/esm/${PACKAGE}.umd.js
UMDES5PATH=${DESTDIR}/${PACKAGE}.umd.js
echo "====== COMPILING: \$(npm bin)/ng2tc -p ${SRCDIR}/tsconfig-es5.json ====="
$(npm bin)/ng2tc -p ${SRCDIR}/tsconfig-es5.json
cp ${SRCDIR}/package.json ${DESTDIR}/
echo "====== TSC 1.8 d.ts compat for ${DESTDIR} ====="
# safely strips 'readonly' specifier from d.ts files to make them compatible with tsc 1.8
if [[ ${TRAVIS} ]]; then
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i -e 's/\(^ *(static |private )*\)*readonly */\1/g'
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i -E 's/^( +)abstract ([[:alnum:]]+\:)/\1\2/g'
else
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i '' -e 's/\(^ *(static |private )*\)*readonly */\1/g'
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i '' -E 's/^( +)abstract ([[:alnum:]]+\:)/\1\2/g'
fi
echo "====== (esm)COMPILING: \$(npm bin)/ng2tc -p ${SRCDIR}/tsconfig-es2015.json ====="
$(npm bin)/ng2tc -p ${SRCDIR}/tsconfig-es2015.json
echo "====== BUNDLING: ${SRCDIR} ====="
(
cd ${SRCDIR}
echo "..." # here just to have grep match something and not exit with 1
../../../node_modules/.bin/rollup -c rollup.config.js
) 2>&1 | grep -v "as external dependency"
# workaround for https://github.com/rollup/rollup/issues/626
if [[ ${TRAVIS} ]]; then
sed -i "s/ class exports\./ class /g" ${DESTDIR}/esm/${PACKAGE}.umd.js
else
sed -i '' "s/ class exports\./ class /g" ${DESTDIR}/esm/${PACKAGE}.umd.js
fi
$(npm bin)/tsc \
--out ${UMDES5PATH} \
--target es5 \
--allowJs \
${UMDES6PATH} \
modules/\@angular/manual_typings/globals.d.ts \
modules/\@angular/typings/es6-collections/es6-collections.d.ts \
modules/\@angular/typings/es6-promise/es6-promise.d.ts
rm ${UMDES6PATH}
done

View File

@ -40,9 +40,9 @@ if (cliArgs.projects) {
cliArgs.projects.split(',').sort().join(',');
}
// --projects=angular2 => {angular2: true}
// --projects=angular2,angular2_material => {angular2: true, angular2_material: true}
var allProjects =
'angular1_router,angular2,benchmarks,benchmarks_external,benchpress,playground,payload_tests,bundle_deps';
'angular1_router,angular2,angular2_material,benchmarks,benchmarks_external,benchpress,playground,payload_tests,bundle_deps';
var cliArgsProjects = (cliArgs.projects || allProjects)
.split(',')
.reduce((map, projectName) => {
@ -57,7 +57,7 @@ function printModulesWarning() {
console.warn(
"Pro Tip: Did you know that you can speed up your build by specifying project name(s)?");
console.warn(" It's like pressing the turbo button in the old days, but better!");
console.warn(" Examples: --project=angular2 or --project=angular2");
console.warn(" Examples: --project=angular2 or --project=angular2,angular2_material");
}
}
@ -132,8 +132,7 @@ var CONFIG = {
dev: {es6: 'dist/js/dev/es6', es5: 'dist/js/dev/es5'},
prod: {es6: 'dist/js/prod/es6', es5: 'dist/js/prod/es5'},
cjs: 'dist/js/cjs',
dart2js: 'dist/js/dart2js',
dart_dev_compiler: 'dist/js/ddc'
dart2js: 'dist/js/dart2js'
},
dart: 'dist/dart',
docs: 'dist/docs',
@ -155,8 +154,6 @@ var NG2_BUNDLE_CONTENT = ANGULAR2_BUNDLE_CONFIG.join(' + ') + ' - rxjs/*';
var HTTP_BUNDLE_CONTENT = 'angular2/http - rxjs/* - ' + ANGULAR2_BUNDLE_CONFIG.join(' - ');
var ROUTER_BUNDLE_CONTENT = 'angular2/router + angular2/router/router_link_dsl - rxjs/* - ' +
ANGULAR2_BUNDLE_CONFIG.join(' - ');
var ALT_ROUTER_BUNDLE_CONTENT =
'angular2/alt_router - rxjs/* - ' + ANGULAR2_BUNDLE_CONFIG.join(' - ');
var TESTING_BUNDLE_CONTENT =
'angular2/testing + angular2/http/testing + angular2/router/testing + angular2/platform/testing/browser - rxjs/* - ' +
ANGULAR2_BUNDLE_CONFIG.join(' - ');
@ -179,8 +176,8 @@ var PAYLOAD_TESTS_CONFIG = {
return path.join(__dirname, CONFIG.dest.js.prod.es5, 'payload_tests', caseName,
'ts/' + packaging);
},
systemjs: {sizeLimits: {'uncompressed': 880 * 1024, 'gzip level=9': 170 * 1024}},
webpack: {sizeLimits: {'uncompressed': 560 * 1024, 'gzip level=9': 130 * 1024}}
systemjs: {sizeLimits: {'uncompressed': 850 * 1024, 'gzip level=9': 165 * 1024}},
webpack: {sizeLimits: {'uncompressed': 550 * 1024, 'gzip level=9': 120 * 1024}}
}
};
@ -300,14 +297,7 @@ function doCheckFormat() {
var clangFormat = require('clang-format');
var gulpFormat = require('gulp-clang-format');
return gulp.src([
'modules/**/*.ts',
'tools/**/*.ts',
'!**/typings/**/*.d.ts',
// workaround https://github.com/angular/clang-format/issues/28
'!tools/compiler_cli/src/main.ts',
'gulpfile.js'
])
return gulp.src(['modules/**/*.ts', 'tools/**/*.ts', '!**/typings/**/*.d.ts', 'gulpfile.js'])
.pipe(gulpFormat.checkFormat('file', clangFormat));
}
@ -354,8 +344,9 @@ gulp.task('lint', ['build.tools'], function() {
gulp.task('build/checkCircularDependencies', function(done) {
var madge = require('madge');
var dependencyObject = madge([CONFIG.dest.js.dev.es5], {
var dependencyObject = madge(CONFIG.dest.js.dev.es5, {
format: 'cjs',
paths: [CONFIG.dest.js.dev.es5],
extensions: ['.js'],
onParseFile: function(data) { data.src = data.src.replace(/\/\* circular \*\//g, "//"); }
});
@ -379,10 +370,6 @@ function jsServeDartJs() {
return jsserve(gulp, gulpPlugins, {path: CONFIG.dest.js.dart2js, port: 8002})();
}
function jsServeDartDevCompiler() {
return jsserve(gulp, gulpPlugins, {path: CONFIG.dest.js.dart_dev_compiler, port: 8003})();
}
function proxyServeDart() {
return jsserve(gulp, gulpPlugins, {
port: 8002,
@ -396,7 +383,7 @@ function proxyServeDart() {
// ------------------
// web servers
gulp.task('serve.js.dev', ['build.js.dev', 'build.js.cjs'], function(neverDone) {
gulp.task('serve.js.dev', ['build.js.dev'], function(neverDone) {
var watch = require('./tools/build/watch');
watch('modules/**', {ignoreInitial: true}, '!broccoli.js.dev');
@ -405,24 +392,24 @@ gulp.task('serve.js.dev', ['build.js.dev', 'build.js.cjs'], function(neverDone)
gulp.task('serve.js.prod', jsServeProd);
gulp.task('serve.e2e.dev', ['build.js.dev', 'build.js.cjs'], function(neverDone) {
var watch = require('./tools/build/watch');
gulp.task('serve.e2e.dev', ['build.js.dev', 'build.js.cjs', 'build.css.material'],
function(neverDone) {
var watch = require('./tools/build/watch');
watch('modules/**', {ignoreInitial: true}, ['!broccoli.js.dev', '!build.js.cjs']);
jsServeDev();
});
watch('modules/**', {ignoreInitial: true}, ['!broccoli.js.dev', '!build.js.cjs']);
jsServeDev();
});
gulp.task('serve.e2e.prod', ['build.js.prod', 'build.js.cjs'], function(neverDone) {
var watch = require('./tools/build/watch');
gulp.task('serve.e2e.prod', ['build.js.prod', 'build.js.cjs', 'build.css.material'],
function(neverDone) {
var watch = require('./tools/build/watch');
watch('modules/**', {ignoreInitial: true}, ['!broccoli.js.prod', '!build.js.cjs']);
jsServeProd();
});
watch('modules/**', {ignoreInitial: true}, ['!broccoli.js.prod', '!build.js.cjs']);
jsServeProd();
});
gulp.task('serve.js.dart2js', jsServeDartJs);
gulp.task('serve.js.ddc', jsServeDartDevCompiler);
gulp.task('!proxyServeDart', proxyServeDart);
gulp.task('serve.dart', function(done) {
@ -454,52 +441,34 @@ gulp.task('serve.e2e.dart', ['build.js.cjs'], function(neverDone) {
// Note: we are not using build.dart as the dart analyzer takes too long...
watch('modules/**', {ignoreInitial: true}, ['!build/tree.dart', '!build.js.cjs']);
runSequence('build/packages.dart', 'build/pubspec.dart', 'serve.dart');
runSequence('build/packages.dart', 'build/pubspec.dart', 'build.dart.material.css', 'serve.dart');
});
// ------------------
// CI tests suites
function execProcess(name, args, done) {
function runKarma(configFile, done) {
var exec = require('child_process').exec;
var cmd = process.platform === 'win32' ? 'node_modules\\.bin\\' + name + ' ' :
'node node_modules/.bin/' + name + ' ';
cmd += args;
exec(cmd, done);
}
function runKarma(configFile, done) {
execProcess('karma', 'run ' + configFile, function(e, stdout) {
var cmd = process.platform === 'win32' ? 'node_modules\\.bin\\karma run ' :
'node node_modules/.bin/karma run ';
cmd += configFile;
exec(cmd, function(e, stdout) {
// ignore errors, we don't want to fail the build in the interactive (non-ci) mode
// karma server will print all test failures
done();
});
}
// Gulp-typescript doesn't work with typescript@next:
// https://github.com/ivogabe/gulp-typescript/issues/331
function runTsc(project, done) {
execProcess('tsc', '-p ' + project, function(e, stdout, stderr) {
if (e) {
console.log(stdout);
console.error(stderr);
done(e);
} else {
done();
}
});
}
gulp.task('test.js', function(done) {
runSequence('test.compiler_cli', 'test.unit.tools/ci', 'test.transpiler.unittest',
'test.unit.js/ci', 'test.unit.cjs/ci', 'test.typings', 'check-public-api',
sequenceComplete(done));
runSequence('test.unit.tools/ci', 'test.transpiler.unittest', 'test.unit.js/ci',
'test.unit.cjs/ci', 'test.typings', 'check-public-api', sequenceComplete(done));
});
gulp.task('test.dart', function(done) {
runSequence('versions.dart', 'test.transpiler.unittest', 'test.unit.dart/ci',
sequenceComplete(done));
'test.dart.angular2_testing/ci', sequenceComplete(done));
});
gulp.task('versions.dart', function() { dartSdk.logVersion(DART_SDK); });
@ -667,7 +636,8 @@ 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/remove-pub-symlinks', function(error) {
'!build/change_detect.dart', '!build/remove-pub-symlinks', 'build.dart.material.css',
'!test.unit.dart/karma-server', '!test.unit.dart/karma-run', function(error) {
var watch = require('./tools/build/watch');
// if initial build failed (likely due to build or formatting step) then exit
@ -676,10 +646,9 @@ gulp.task('test.unit.dart', function(done) {
done(error);
return;
}
// treatTestErrorsAsFatal = false;
watch(['modules/angular2/**'],
['!build/tree.dart', '!test.unit.dart/run/angular2']);
watch(['modules/angular2/**'], {ignoreInitial: true},
['!build/tree.dart', '!test.unit.dart/karma-run']);
});
});
@ -738,7 +707,7 @@ gulp.task('!build.payload.js.webpack', function() {
.then(function() { // pad bundle with mandatory dependencies
return new Promise(function(resolve, reject) {
gulp.src([
'node_modules/zone.js/dist/zone.js',
'node_modules/zone.js/dist/zone-microtask.js',
'node_modules/zone.js/dist/long-stack-trace-zone.js',
'node_modules/reflect-metadata/Reflect.js',
CASE_PATH + '/app-bundle.js'
@ -795,7 +764,7 @@ gulp.task('!checkAndReport.payload.js', function() {
{
failConditions: PAYLOAD_TESTS_CONFIG.ts[packaging].sizeLimits,
prefix: caseName + '_' + packaging
});
})
}
return PAYLOAD_TESTS_CONFIG.ts.cases.reduce(function(sizeReportingStreams, caseName) {
@ -806,7 +775,8 @@ 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/remove-pub-symlinks', function(error) {
'!build/change_detect.dart', '!build/remove-pub-symlinks', 'build.dart.material.css',
function(error) {
var watch = require('./tools/build/watch');
// if initial build failed (likely due to build or formatting step) then exit
@ -816,11 +786,24 @@ gulp.task('watch.dart.dev', function(done) {
return;
}
watch(['modules/angular2/**', 'modules_dart/**'], {ignoreInitial: true},
['!build/tree.dart', 'build/pure-packages.dart']);
watch(['modules/angular2/**'], {ignoreInitial: true}, ['!build/tree.dart']);
});
});
gulp.task('!test.unit.dart/karma-run', function(done) {
// run the run command in a new process to avoid duplicate logging by both server and runner from
// a single process
runKarma('karma-dart.conf.js', done);
});
gulp.task('!test.unit.dart/karma-server', function() {
var karma = require('karma');
new karma.Server({configFile: __dirname + '/karma-dart.conf.js', reporters: 'dots'}).start();
});
gulp.task('test.unit.router/ci', function(done) {
var karma = require('karma');
@ -868,62 +851,26 @@ gulp.task('test.unit.js.browserstack/ci', function(done) {
});
gulp.task('test.unit.dart/ci', function(done) {
runSequence('test.dart.dartium_symlink', '!test.unit.dart/run/angular2',
'!test.unit.dart/run/angular2_testing', '!test.unit.dart/run/benchpress',
sequenceComplete(done));
var karma = require('karma');
var browserConf = getBrowsersFromCLI(null, true);
new karma.Server(
{
configFile: __dirname + '/karma-dart.conf.js',
singleRun: true,
reporters: ['dots'],
browsers: browserConf.browsersToRun
},
done)
.start();
});
// At the moment, dart test requires dartium to be an executable on the path.
// Make a temporary directory and symlink dartium from there (just for this command)
// so that it can run.
// TODO(juliemr): this won't work with windows - remove the hack and make this platform agnostic.
var dartiumTmpdir = path.join(os.tmpdir(), 'dartium' + new Date().getTime().toString());
var dartiumPathPrefix = 'PATH=$PATH:' + dartiumTmpdir + ' ';
gulp.task(
'test.dart.dartium_symlink',
shell.task(['mkdir ' + dartiumTmpdir, 'ln -s $DARTIUM_BIN ' + dartiumTmpdir + '/dartium']));
gulp.task('!test.unit.dart/run/angular2', function() {
var pubtest = require('./tools/build/pubtest');
return pubtest({
dir: path.join(CONFIG.dest.dart, 'angular2'),
dartiumTmpdir: dartiumTmpdir,
command: DART_SDK.PUB,
files: '**/*_spec.dart',
bunchFiles: true,
useExclusiveTests: true
});
});
gulp.task('!test.unit.dart/run/angular2_testing', function() {
var pubtest = require('./tools/build/pubtest');
return pubtest({
dir: path.join(CONFIG.dest.dart, 'angular2_testing'),
dartiumTmpdir: dartiumTmpdir,
command: DART_SDK.PUB,
files: '**/*_test.dart',
useExclusiveTests: true
});
});
gulp.task('!test.unit.dart/run/benchpress', function() {
var pubtest = require('./tools/build/pubtest');
return pubtest({
dir: path.join(CONFIG.dest.dart, 'benchpress'),
dartiumTmpdir: dartiumTmpdir,
command: DART_SDK.PUB,
files: '**/*_spec.dart',
useExclusiveTests: true
});
});
gulp.task('test.unit.cjs/ci', function(done) {
runJasmineTests(['dist/js/cjs/{angular2,benchpress}/test/**/*_spec.js'], done);
});
gulp.task('check-public-api', ['build.tools'],
gulp.task('check-public-api',
function(done) { runJasmineTests(['dist/tools/public_api_guard/**/*_spec.js'], done); });
gulp.task('test.unit.cjs', ['build/clean.js', 'build.tools'], function(neverDone) {
@ -939,20 +886,21 @@ 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',
'!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']);
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']);
// 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']);
});
// 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']);
});
});
gulp.task('!test.unit.dartvm/run',
@ -983,6 +931,24 @@ gulp.task('test.server.dart', runServerDartTests(gulp, gulpPlugins, {dest: 'dist
gulp.task('test.transpiler.unittest',
function(done) { runJasmineTests(['tools/transpiler/unittest/**/*.js'], done); });
// At the moment, dart test requires dartium to be an executable on the path.
// Make a temporary directory and symlink dartium from there (just for this command)
// so that it can run.
var dartiumTmpdir = path.join(os.tmpdir(), 'dartium' + new Date().getTime().toString());
gulp.task('test.dart.angular2_testing/ci', ['build/pubspec.dart'], function(done) {
runSequence('test.dart.angular2_testing_symlink', 'test.dart.angular2_testing',
sequenceComplete(done));
});
gulp.task(
'test.dart.angular2_testing_symlink',
shell.task(['mkdir ' + dartiumTmpdir, 'ln -s $DARTIUM_BIN ' + dartiumTmpdir + '/dartium']));
gulp.task('test.dart.angular2_testing',
shell.task(['PATH=$PATH:' + dartiumTmpdir + ' pub run test -p dartium'],
{'cwd': 'dist/dart/angular2_testing'}));
// -----------------
// Pre-test checks
@ -1008,40 +974,22 @@ 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 typings tests are isolated, by running in a tempdir
// Make sure the two typings tests are isolated, by running this one in a tempdir
var tmpdir = path.join(os.tmpdir(), 'test.typings', new Date().getTime().toString());
gulp.task('!pre.test.typings.layoutNodeModule', function() {
return gulp.src(['dist/js/cjs/angular2/**/*', 'node_modules/rxjs/**/*'], {base: 'dist/js/cjs'})
gulp.task('!pre.test.typings.layoutNodeModule', ['build.js.cjs'], function() {
return gulp.src(['dist/js/cjs/angular2/**/*', 'node_modules/rxjs/**'], {base: 'dist/js/cjs'})
.pipe(gulp.dest(path.join(tmpdir, 'node_modules')));
});
gulp.task('!pre.test.typings.copyDeps', function() {
return gulp.src(
[
'modules/angular2/typings/angular-protractor/*.ts',
'modules/angular2/typings/jasmine/*.ts',
'modules/angular2/typings/selenium-webdriver/*.ts',
],
{base: 'modules/angular2/typings'})
.pipe(gulp.dest(tmpdir));
});
gulp.task('!pre.test.typings.copyTypingsSpec', function() {
return gulp.src(['modules/angular2/examples/**/*.ts']).pipe(gulp.dest(tmpdir));
return gulp.src(['typing_spec/*.ts'], {base: 'typing_spec'}).pipe(gulp.dest(path.join(tmpdir)));
});
gulp.task('!test.typings',
[
'!pre.test.typings.layoutNodeModule',
'!pre.test.typings.copyTypingsSpec',
'!pre.test.typings.copyDeps'
],
function() {
gulp.task('test.typings',
['!pre.test.typings.layoutNodeModule', '!pre.test.typings.copyTypingsSpec'], function() {
var tsc = require('gulp-typescript');
return gulp.src([tmpdir + '/**/*.ts', '!' + tmpdir + '/node_modules/**/*'])
return gulp.src([tmpdir + '/**'])
.pipe(tsc({
target: 'ES6',
target: 'ES5',
module: 'commonjs',
experimentalDecorators: true,
noImplicitAny: true,
@ -1050,46 +998,6 @@ gulp.task('!test.typings',
}));
});
gulp.task('test.typings', ['build.js.cjs'],
function(done) { runSequence('!test.typings', sequenceComplete(done)); });
gulp.task('!build.compiler_cli', function(done) { runTsc('tools/compiler_cli/src', done); });
gulp.task('!clean.compiler_cli', function(done) {
fse.remove(path.join('dist', 'tools', 'compiler_cli', 'test'),
fse.remove(path.join('tools', 'compiler_cli', 'test', 'src', '*.ngfactory.ts'),
fse.remove(path.join('tools', 'compiler_cli', 'test', 'src', 'a',
'*.ngfactory.ts'),
done)));
});
gulp.task('!test.compiler_cli.codegen', function(done) {
try {
require('./dist/tools/compiler_cli/main')
.main("tools/compiler_cli/test")
.then(done)
.catch(function(rej) { done(new Error(rej)); });
} catch (err) {
done(err);
}
});
gulp.task('!test.compiler_cli.unit',
function(done) { runJasmineTests(['dist/tools/compiler_cli/**/*_spec.js'], done) });
// This task overwrites our careful tsickle-lowered Decorators with normal .js emit.
// So it should only be run after asserting on the .js file content.
gulp.task('!test.compiler_cli.verify_codegen',
function(done) { runTsc('tools/compiler_cli/test', done); });
// End-to-end test for compiler CLI.
// Calls the compiler using its command-line interface, then compiles the app with the codegen.
// TODO(alexeagle): wire up the playground tests with offline compilation, similar to dart.
gulp.task('test.compiler_cli', ['!build.compiler_cli'], function(done) {
runSequence('!clean.compiler_cli', '!test.compiler_cli.codegen', '!test.compiler_cli.unit',
'!test.compiler_cli.verify_codegen', sequenceComplete(done));
});
// -----------------
// orchestrated targets
@ -1109,7 +1017,6 @@ gulp.task('build/pure-packages.dart/standalone', function() {
'modules_dart/**/*',
'!modules_dart/**/*.proto',
'!modules_dart/**/packages{,/**}',
'!modules_dart/**/.packages',
'!modules_dart/payload{,/**}',
'!modules_dart/transform{,/**}',
])
@ -1133,15 +1040,15 @@ 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', 'pubget.dart', 'build/tree.dart', 'build/pure-packages.dart',
runSequence('lint_protos.dart', 'build/tree.dart', 'build/pure-packages.dart',
// Run after 'build/tree.dart' because broccoli clears the dist/dart folder
'!build/pubget.angular2.dart', sequenceComplete(done));
'!build/pubget.angular2.dart', '!build/change_detect.dart', sequenceComplete(done));
});
// Builds and compiles all Dart packages
gulp.task('build.dart', function(done) {
runSequence('build/packages.dart', 'build/pubspec.dart', 'build/analyze.dart',
'build/check.apidocs.dart', sequenceComplete(done));
'build/check.apidocs.dart', 'build.dart.material.css', sequenceComplete(done));
});
@ -1155,31 +1062,30 @@ gulp.task('!build.tools', function() {
var sourcemaps = require('gulp-sourcemaps');
var tsc = require('gulp-typescript');
var stream = gulp.src(['tools/**/*.ts', '!tools/compiler_cli/**'])
var stream = gulp.src(['tools/**/*.ts'])
.pipe(sourcemaps.init())
.pipe(tsc({
target: 'ES5',
module: 'commonjs',
declaration: true,
// Don't use the version of typescript that gulp-typescript depends on
// see https://github.com/ivogabe/gulp-typescript#typescript-version
typescript: require('typescript')
}));
stream =
merge2([stream.js.pipe(gulp.dest('dist/tools')), stream.dts.pipe(gulp.dest('dist/tools'))])
.on('error',
function(error) {
// nodejs doesn't propagate errors from the src stream into the final
// stream so we are
// forwarding the error into the final stream
stream.emit('error', error);
})
.pipe(sourcemaps.write('.'))
.on('end', function() {
var AngularBuilder = require('./dist/tools/broccoli/angular_builder').AngularBuilder;
angularBuilder =
new AngularBuilder({outputPath: 'dist', dartSDK: DART_SDK, logs: logs});
});
}))
.on('error',
function(error) {
// nodejs doesn't propagate errors from the src stream into the final
// stream so we are
// forwarding the error into the final stream
stream.emit('error', error);
})
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('dist/tools'))
.on('end', function() {
var AngularBuilder =
require('./dist/tools/broccoli/angular_builder').AngularBuilder;
angularBuilder =
new AngularBuilder({outputPath: 'dist', dartSDK: DART_SDK, logs: logs});
});
return stream;
});
@ -1201,8 +1107,9 @@ gulp.task('!broccoli.js.prod', () => angularBuilder.rebuildBrowserProdTree({
useBundles: cliArgs.useBundles
}));
gulp.task('build.js.dev', ['build/clean.js'],
function(done) { runSequence('broccoli.js.dev', sequenceComplete(done)); });
gulp.task('build.js.dev', ['build/clean.js'], function(done) {
runSequence('broccoli.js.dev', 'build.css.material', sequenceComplete(done));
});
gulp.task('build.js.prod', ['build.tools'],
function(done) { runSequence('!broccoli.js.prod', sequenceComplete(done)); });
@ -1261,8 +1168,6 @@ gulp.task('!bundle.js.prod', ['build.js.prod'], function() {
bundler.bundle(bundleConfig, HTTP_BUNDLE_CONTENT, './dist/build/http.js', bundlerConfig),
bundler.bundle(bundleConfig, ROUTER_BUNDLE_CONTENT, './dist/build/router.js',
bundlerConfig),
bundler.bundle(bundleConfig, ALT_ROUTER_BUNDLE_CONTENT, './dist/build/alt_router.js',
bundlerConfig),
bundler.bundle(bundleConfig, UPGRADE_BUNDLE_CONTENT, './dist/build/upgrade.js',
bundlerConfig)
]);
@ -1272,8 +1177,7 @@ 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, mangle: false, uglify: {compress: {keep_fnames: true}}};
var bundlerConfig = {sourceMaps: true, minify: true};
return bundler.bundle(bundleConfig, NG2_BUNDLE_CONTENT, './dist/build/angular2.min.js',
bundlerConfig)
@ -1283,8 +1187,6 @@ gulp.task('!bundle.js.min', ['build.js.prod'], function() {
bundlerConfig),
bundler.bundle(bundleConfig, ROUTER_BUNDLE_CONTENT, './dist/build/router.min.js',
bundlerConfig),
bundler.bundle(bundleConfig, ALT_ROUTER_BUNDLE_CONTENT, './dist/build/alt_router.min.js',
bundlerConfig),
bundler.bundle(bundleConfig, UPGRADE_BUNDLE_CONTENT, './dist/build/upgrade.min.js',
bundlerConfig)
]);
@ -1307,8 +1209,6 @@ gulp.task('!bundle.js.dev', ['build.js.dev'], function() {
bundlerConfig),
bundler.bundle(devBundleConfig, ROUTER_BUNDLE_CONTENT, './dist/build/router.dev.js',
bundlerConfig),
bundler.bundle(devBundleConfig, ALT_ROUTER_BUNDLE_CONTENT,
'./dist/build/alt_router.dev.js', bundlerConfig),
bundler.bundle(devBundleConfig, UPGRADE_BUNDLE_CONTENT, './dist/build/upgrade.dev.js',
bundlerConfig)
]);
@ -1429,7 +1329,6 @@ gulp.task('!bundle.js.prod.deps', ['!bundle.js.prod'], function() {
return merge2(bundler.modify(['dist/build/angular2.js'], 'angular2.js'),
bundler.modify(['dist/build/http.js'], 'http.js'),
bundler.modify(['dist/build/router.js'], 'router.js'),
bundler.modify(['dist/build/alt_router.js'], 'alt_router.js'),
bundler.modify(['dist/build/upgrade.js'], 'upgrade.js'))
.pipe(gulp.dest('dist/js/bundle'));
});
@ -1441,7 +1340,6 @@ gulp.task('!bundle.js.min.deps', ['!bundle.js.min'], function() {
return merge2(bundler.modify(['dist/build/angular2.min.js'], 'angular2.min.js'),
bundler.modify(['dist/build/http.min.js'], 'http.min.js'),
bundler.modify(['dist/build/router.min.js'], 'router.min.js'),
bundler.modify(['dist/build/alt_router.min.js'], 'alt_router.min.js'),
bundler.modify(['dist/build/upgrade.min.js'], 'upgrade.min.js'))
.pipe(uglify())
.pipe(gulp.dest('dist/js/bundle'));
@ -1452,7 +1350,7 @@ gulp.task('!bundle.ng.polyfills', ['clean'],
var JS_DEV_DEPS = [
licenseWrap('node_modules/zone.js/LICENSE', true),
'node_modules/zone.js/dist/zone.js',
'node_modules/zone.js/dist/zone-microtask.js',
'node_modules/zone.js/dist/long-stack-trace-zone.js',
licenseWrap('node_modules/reflect-metadata/LICENSE', true),
'node_modules/reflect-metadata/Reflect.js'
@ -1473,7 +1371,6 @@ gulp.task('!bundle.js.dev.deps', ['!bundle.js.dev'], function() {
return merge2(bundler.modify(['dist/build/angular2.dev.js'], 'angular2.dev.js'),
bundler.modify(['dist/build/http.dev.js'], 'http.dev.js'),
bundler.modify(['dist/build/router.dev.js'], 'router.dev.js'),
bundler.modify(['dist/build/alt_router.dev.js'], 'alt_router.dev.js'),
bundler.modify(['dist/build/upgrade.dev.js'], 'upgrade.dev.js'))
.pipe(gulp.dest('dist/js/bundle'));
});
@ -1540,7 +1437,70 @@ 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);
});
// ------------
// angular material testing rules
gulp.task('build.css.material', function() {
var autoprefixer = require('gulp-autoprefixer');
var sass = require('gulp-sass');
return gulp.src('modules/*/src/**/*.scss')
.pipe(sass())
.pipe(autoprefixer())
.pipe(gulp.dest(CONFIG.dest.js.prod.es5))
.pipe(gulp.dest(CONFIG.dest.js.dev.es5))
.pipe(gulp.dest(CONFIG.dest.js.dart2js + '/examples/packages'));
});
gulp.task('build.js.material', function(done) {
runSequence('build.js.dev', 'build.css.material', sequenceComplete(done));
});
gulp.task('build.dart2js.material', function(done) {
runSequence('build.dart', 'build.css.material', sequenceComplete(done));
});
gulp.task('build.dart.material.css', function() {
var autoprefixer = require('gulp-autoprefixer');
var sass = require('gulp-sass');
return gulp.src('dist/dart/angular2_material/src/**/*.scss')
.pipe(sass())
.pipe(autoprefixer())
.pipe(gulp.dest('dist/dart/angular2_material/lib/src'));
});
gulp.task('build.dart.material', ['build/packages.dart'], function(done) {
runSequence('build/packages.dart', 'build.dart.material.css', sequenceComplete(done));
});
gulp.task('cleanup.builder', function() { return angularBuilder.cleanup(); });
@ -1579,16 +1539,13 @@ process.on('beforeExit', function() {
var firstTask = true;
gulp.on('task_start', (e) => {
if (firstTask) {
firstTask = false;
analytics.buildSuccess('gulp <startup>', process.uptime() * 1000);
}
analytics.buildStart('gulp ' + e.task);
analytics.buildStart('gulp ' + e.task)
});
gulp.on('task_stop', (e) => { analytics.buildSuccess('gulp ' + e.task, e.duration * 1000); });
gulp.on('task_err', (e) => { analytics.buildError('gulp ' + e.task, e.duration * 1000); });
gulp.on('task_stop', (e) => {analytics.buildSuccess('gulp ' + e.task, e.duration * 1000)});
gulp.on('task_err', (e) => {analytics.buildError('gulp ' + e.task, e.duration * 1000)});

86
karma-dart-evalcache.js Normal file
View File

@ -0,0 +1,86 @@
// This module provides a customFileHandler for karma
// that serves files with urls like /packages_<timestamp>/...
// with maximum cache.
// We are using these urls when we spawn isolates
// so that the isolates don't reload files every time.
var common = require('karma/lib/middleware/common');
var fs = require('fs');
var DART_EVAL_PATH_RE = /.*\/packages_\d+\/(.*)$/;
module.exports = createFactory;
function createFactory(proxyPaths) {
return {
'framework:dart-evalcache': ['factory', dartEvalCacheFactory]
};
function dartEvalCacheFactory(emitter, logger, customFileHandlers) {
var filesPromise = new common.PromiseContainer();
emitter.on('file_list_modified', function(files) {
filesPromise.set(Promise.resolve(files));
});
var serveFile = common.createServeFile(fs);
var log = logger.create('dart-evalcache');
customFileHandlers.push({
urlRegex: DART_EVAL_PATH_RE,
handler: handler
});
// See source_files handler
function handler(request, response, fa, fb, basePath) {
return filesPromise.then(function(files) {
try {
var requestedFilePath = mapUrlToFile(request.url, proxyPaths, basePath, log);
// TODO(vojta): change served to be a map rather then an array
var file = findByPath(files.served, requestedFilePath);
if (file) {
serveFile(file.contentPath || file.path, response, function() {
common.setHeavyCacheHeaders(response);
}, file.content);
} else {
response.writeHead(404);
response.end('Not found');
}
} catch (e) {
log.error(e.stack);
response.writeHead(500);
response.end('Error', e.stack);
}
});
}
};
}
function mapUrlToFile(url, proxyPaths, basePath, log) {
var originalUrl = url;
url = url.indexOf('?') > -1 ? url.substring(0, url.indexOf('?')) : url;
var match = DART_EVAL_PATH_RE.exec(url);
var packagePath = match[1];
var result = null;
var lastProxyFromLength = 0;
Object.keys(proxyPaths).forEach(function(proxyFrom) {
if (startsWith(packagePath, proxyFrom) && proxyFrom.length > lastProxyFromLength) {
lastProxyFromLength = proxyFrom.length;
result = proxyPaths[proxyFrom] + packagePath.substring(proxyFrom.length);
}
});
return basePath + '/' + result;
}
function startsWith(string, subString) {
return string.length >= subString.length && string.slice(0, subString.length) === subString;
}
function findByPath(files, path) {
for (var i = 0; i < files.length; i++) {
if (files[i].path === path) {
return files[i];
}
}
return null;
}

82
karma-dart.conf.js Normal file
View File

@ -0,0 +1,82 @@
var browserProvidersConf = require('./browser-providers.conf.js');
var packageSources = {
// Dependencies installed with `pub install`.
'unittest': 'packages/unittest',
'guinness': 'packages/guinness',
'matcher': 'packages/matcher',
'stack_trace': 'packages/stack_trace',
'collection': 'packages/collection',
'path': 'packages/path',
'observe': 'packages/observe',
'quiver': 'packages/quiver',
'intl': 'packages/intl',
'smoke': 'packages/smoke',
'logging': 'packages/logging',
'utf': 'packages/utf',
// Local dependencies, transpiled from the source.
'angular2': 'dist/dart/angular2/lib',
'angular2/test/': 'dist/dart/angular2/test/',
'http': 'dist/dart/http/lib',
'angular2_material': 'dist/dart/angular2_material/lib',
'benchpress': 'dist/dart/benchpress/lib',
'examples': 'dist/dart/examples/lib'
};
var proxyPaths = {};
Object.keys(packageSources).map(function(packageName) {
var filePath = packageSources[packageName];
proxyPaths['/packages/'+packageName] = '/base/'+filePath;
});
// Karma configuration
// Generated on Thu Sep 25 2014 11:52:02 GMT-0700 (PDT)
module.exports = function(config) {
config.set({
frameworks: ['dart-unittest', 'dart-evalcache'],
files: [
// Init and configure guiness.
{pattern: 'test-init.dart', included: true},
// Unit test files needs to be included.
{pattern: 'dist/dart/**/*_spec.dart', included: true, watched: false},
// Karma-dart via the dart-unittest framework generates
// `__adapter_unittest.dart` that imports these files.
{pattern: 'dist/dart/**', included: false, watched: false},
// Dependencies, installed with `pub install`.
{pattern: 'packages/**/*.dart', included: false, watched: false},
// Init and configure guiness.
{pattern: 'test-main.dart', included: true},
{pattern: 'modules/**/test/**/static_assets/**', included: false, watched: false},
],
exclude: [
'dist/dart/**/packages/**',
'modules/angular1_router/**'
],
karmaDartImports: {
guinness: 'package:guinness/guinness_html.dart'
},
// Map packages to the correct urls where Karma serves them.
proxies: proxyPaths,
customLaunchers: browserProvidersConf.customLaunchers,
browsers: ['DartiumWithWebPlatform'],
port: 9877,
plugins: [
require('karma-dart'),
require('karma-chrome-launcher'),
require('karma-sauce-launcher'),
require('./karma-dart-evalcache')(packageSources)
]
});
};

View File

@ -11,37 +11,28 @@ module.exports = function(config) {
files: [
// Sources and specs.
// Loaded through the System loader, in `test-main.js`.
{pattern: 'dist/all/@angular/**/*.js', included: false, watched: true},
{pattern: 'dist/all/angular2/**/*.js', included: false, watched: true},
{pattern: 'dist/js/dev/es5/**', included: false, watched: false},
'node_modules/es6-shim/es6-shim.js',
// include Angular v1 for upgrade module testing
'node_modules/angular/angular.min.js',
'node_modules/zone.js/dist/zone.js',
// zone-microtask must be included first as it contains a Promise monkey patch
'node_modules/zone.js/dist/zone-microtask.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.
'shims_for_IE.js',
'modules/angular2/src/testing/shims_for_IE.js',
'node_modules/systemjs/dist/system.src.js',
{pattern: 'node_modules/rxjs/**', included: false, watched: false, served: true},
'node_modules/reflect-metadata/Reflect.js',
'tools/build/file2modulename.js',
'test-main.js',
{pattern: 'dist/all/empty.*', included: false, watched: false},
{pattern: 'modules/@angular/platform-browser/test/static_assets/**', included: false, watched: false},
{pattern: 'modules/@angular/platform-browser-dynamic/test/browser/static_assets/**', included: false, watched: false}
{pattern: 'modules/**/test/**/static_assets/**', included: false, watched: false}
],
exclude: [
'dist/all/@angular/**/e2e_test/**',
'dist/all/@angular/examples/**',
'dist/all/angular1_router.js',
'dist/all/@angular/platform-browser/testing/e2e_util.js'
],
exclude: ['dist/js/dev/es5/**/e2e_test/**', 'dist/js/dev/es5/angular2/examples/**', 'dist/angular1_router.js'],
customLaunchers: browserProvidersConf.customLaunchers,
@ -62,7 +53,6 @@ module.exports = function(config) {
reporters: ['internal-angular'],
sauceLabs: {
testName: 'Angular2',
retryLimit: 3,
startConnect: false,
recordVideo: false,
recordScreenshots: false,
@ -77,23 +67,19 @@ module.exports = function(config) {
browserStack: {
project: 'Angular2',
startTunnel: false,
retryLimit: 3,
retryLimit: 1,
timeout: 600,
pollingTimeout: 10000
},
browsers: ['Chrome'],
port: 9876,
captureTimeout: 60000,
browserDisconnectTimeout : 60000,
browserDisconnectTolerance : 3,
browserNoActivityTimeout : 60000,
port: 9876
});
if (process.env.TRAVIS) {
var buildId = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
if (process.env.CI_MODE.startsWith('saucelabs')) {
if (process.env.MODE.startsWith('saucelabs')) {
config.sauceLabs.build = buildId;
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
@ -103,7 +89,7 @@ module.exports = function(config) {
config.transports = ['polling'];
}
if (process.env.CI_MODE.startsWith('browserstack')) {
if (process.env.MODE.startsWith('browserstack')) {
config.browserStack.build = buildId;
config.browserStack.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
}

View File

@ -1 +0,0 @@
export 'index.dart';

View File

@ -1,5 +0,0 @@
export * from './src/pipes';
export * from './src/directives';
export * from './src/forms';
export * from './src/common_directives';
export * from './src/location';

View File

@ -1,13 +0,0 @@
{
"name": "@angular/common",
"version": "$$ANGULAR_VERSION$$",
"description": "",
"main": "index.js",
"jsnext:main": "esm/index.js",
"typings": "index.d.ts",
"author": "angular",
"license": "MIT",
"peerDependencies": {
"@angular/core": "$$ANGULAR_VERSION$$"
}
}

View File

@ -1,18 +0,0 @@
export default {
entry: '../../../dist/packages-dist/common/esm/index.js',
dest: '../../../dist/packages-dist/common/esm/common.umd.js',
sourceMap: true,
format: 'umd',
moduleName: 'ng.common',
globals: {
'@angular/core': 'ng.core',
'rxjs/Subject': 'Rx',
'rxjs/observable/PromiseObservable': 'Rx', // this is wrong, but this stuff has changed in rxjs b.6 so we need to fix it when we update.
'rxjs/operator/toPromise': 'Rx.Observable.prototype',
'rxjs/Observable': 'Rx'
},
plugins: [
// nodeResolve({ jsnext: true, main: true }),
]
}

View File

@ -1,148 +0,0 @@
import {
Directive,
ViewContainerRef,
TemplateRef,
ContentChildren,
QueryList,
Attribute,
AfterContentInit,
Input
} from '@angular/core';
import {isPresent, NumberWrapper} from '../../src/facade/lang';
import {Map} from '../../src/facade/collection';
import {SwitchView} from './ng_switch';
const _CATEGORY_DEFAULT = 'other';
export abstract class NgLocalization { abstract getPluralCategory(value: any): string; }
/**
* `ngPlural` is an i18n directive that displays DOM sub-trees that match the switch expression
* value, or failing that, DOM sub-trees that match the switch expression's pluralization category.
*
* To use this directive, you must provide an extension of `NgLocalization` that maps values to
* category names. You then define a container element that sets the `[ngPlural]` attribute to a
* switch expression.
* - Inner elements defined with an `[ngPluralCase]` attribute will display based on their
* expression.
* - If `[ngPluralCase]` is set to a value starting with `=`, it will only display if the value
* matches the switch expression exactly.
* - Otherwise, the view will be treated as a "category match", and will only display if exact
* value matches aren't found and the value maps to its category using the `getPluralCategory`
* function provided.
*
* If no matching views are found for a switch expression, inner elements marked
* `[ngPluralCase]="other"` will be displayed.
*
* ```typescript
* class MyLocalization extends NgLocalization {
* getPluralCategory(value: any) {
* if(value < 5) {
* return 'few';
* }
* }
* }
*
* @Component({
* selector: 'app',
* providers: [provide(NgLocalization, {useClass: MyLocalization})]
* })
* @View({
* template: `
* <p>Value = {{value}}</p>
* <button (click)="inc()">Increment</button>
*
* <div [ngPlural]="value">
* <template ngPluralCase="=0">there is nothing</template>
* <template ngPluralCase="=1">there is one</template>
* <template ngPluralCase="few">there are a few</template>
* <template ngPluralCase="other">there is some number</template>
* </div>
* `,
* directives: [NgPlural, NgPluralCase]
* })
* export class App {
* value = 'init';
*
* inc() {
* this.value = this.value === 'init' ? 0 : this.value + 1;
* }
* }
*
* ```
*/
@Directive({selector: '[ngPluralCase]'})
export class NgPluralCase {
/** @internal */
_view: SwitchView;
constructor(@Attribute('ngPluralCase') public value: string, template: TemplateRef<Object>,
viewContainer: ViewContainerRef) {
this._view = new SwitchView(viewContainer, template);
}
}
@Directive({selector: '[ngPlural]'})
export class NgPlural implements AfterContentInit {
private _switchValue: number;
private _activeView: SwitchView;
private _caseViews = new Map<any, SwitchView>();
@ContentChildren(NgPluralCase) cases: QueryList<NgPluralCase> = null;
constructor(private _localization: NgLocalization) {}
@Input()
set ngPlural(value: number) {
this._switchValue = value;
this._updateView();
}
ngAfterContentInit() {
this.cases.forEach((pluralCase: NgPluralCase): void => {
this._caseViews.set(this._formatValue(pluralCase), pluralCase._view);
});
this._updateView();
}
/** @internal */
_updateView(): void {
this._clearViews();
var view: SwitchView = this._caseViews.get(this._switchValue);
if (!isPresent(view)) view = this._getCategoryView(this._switchValue);
this._activateView(view);
}
/** @internal */
_clearViews() {
if (isPresent(this._activeView)) this._activeView.destroy();
}
/** @internal */
_activateView(view: SwitchView) {
if (!isPresent(view)) return;
this._activeView = view;
this._activeView.create();
}
/** @internal */
_getCategoryView(value: number): SwitchView {
var category: string = this._localization.getPluralCategory(value);
var categoryView: SwitchView = this._caseViews.get(category);
return isPresent(categoryView) ? categoryView : this._caseViews.get(_CATEGORY_DEFAULT);
}
/** @internal */
_isValueView(pluralCase: NgPluralCase): boolean { return pluralCase.value[0] === "="; }
/** @internal */
_formatValue(pluralCase: NgPluralCase): any {
return this._isValueView(pluralCase) ? this._stripValue(pluralCase.value) : pluralCase.value;
}
/** @internal */
_stripValue(value: string): number { return NumberWrapper.parseInt(value.substring(1), 10); }
}

View File

@ -1,26 +0,0 @@
import {Directive, Input, ViewContainerRef, ViewRef, TemplateRef} from '@angular/core';
import {isPresent} from '../../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<Object>) {
if (isPresent(this._insertedViewRef)) {
this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._insertedViewRef));
}
if (isPresent(templateRef)) {
this._insertedViewRef = this._viewContainerRef.createEmbeddedView(templateRef);
}
}
}

View File

@ -1 +0,0 @@
../../facade/src

View File

@ -1,18 +0,0 @@
import {AbstractControl} from '../model';
import {Validator, ValidatorFn, AsyncValidatorFn} from './validators';
export function normalizeValidator(validator: ValidatorFn | Validator): ValidatorFn {
if ((<Validator>validator).validate !== undefined) {
return (c: AbstractControl) => (<Validator>validator).validate(c);
} else {
return <ValidatorFn>validator;
}
}
export function normalizeAsyncValidator(validator: AsyncValidatorFn | Validator): AsyncValidatorFn {
if ((<Validator>validator).validate !== undefined) {
return (c: AbstractControl) => Promise.resolve((<Validator>validator).validate(c));
} else {
return <AsyncValidatorFn>validator;
}
}

View File

@ -1,126 +0,0 @@
import {
Directive,
ElementRef,
Renderer,
forwardRef,
Provider,
Input,
OnInit,
OnDestroy,
Injector,
Injectable
} from '@angular/core';
import {isPresent} from '../../../src/facade/lang';
import {ListWrapper} from '../../../src/facade/collection';
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from './control_value_accessor';
import {NgControl} from './ng_control';
export const RADIO_VALUE_ACCESSOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RadioControlValueAccessor),
multi: true
};
/**
* Internal class used by Angular to uncheck radio buttons with the matching name.
*/
@Injectable()
export class RadioControlRegistry {
private _accessors: any[] = [];
add(control: NgControl, accessor: RadioControlValueAccessor) {
this._accessors.push([control, accessor]);
}
remove(accessor: RadioControlValueAccessor) {
var indexToRemove = -1;
for (var i = 0; i < this._accessors.length; ++i) {
if (this._accessors[i][1] === accessor) {
indexToRemove = i;
}
}
ListWrapper.removeAt(this._accessors, indexToRemove);
}
select(accessor: RadioControlValueAccessor) {
this._accessors.forEach((c) => {
if (c[0].control.root === accessor._control.control.root && c[1] !== accessor) {
c[1].fireUncheck();
}
});
}
}
/**
* The value provided by the forms API for radio buttons.
*/
export class RadioButtonState {
constructor(public checked: boolean, public value: string) {}
}
/**
* The accessor for writing a radio control value and listening to changes that is used by the
* {@link NgModel}, {@link NgFormControl}, and {@link NgControlName} directives.
*
* ### Example
* ```
* @Component({
* template: `
* <input type="radio" name="food" [(ngModel)]="foodChicken">
* <input type="radio" name="food" [(ngModel)]="foodFish">
* `
* })
* class FoodCmp {
* foodChicken = new RadioButtonState(true, "chicken");
* foodFish = new RadioButtonState(false, "fish");
* }
* ```
*/
@Directive({
selector:
'input[type=radio][ngControl],input[type=radio][ngFormControl],input[type=radio][ngModel]',
host: {'(change)': 'onChange()', '(blur)': 'onTouched()'},
providers: [RADIO_VALUE_ACCESSOR]
})
export class RadioControlValueAccessor implements ControlValueAccessor,
OnDestroy, OnInit {
/** @internal */
_state: RadioButtonState;
/** @internal */
_control: NgControl;
@Input() name: string;
/** @internal */
_fn: Function;
onChange = () => {};
onTouched = () => {};
constructor(private _renderer: Renderer, private _elementRef: ElementRef,
private _registry: RadioControlRegistry, private _injector: Injector) {}
ngOnInit(): void {
this._control = this._injector.get(NgControl);
this._registry.add(this._control, this);
}
ngOnDestroy(): void { this._registry.remove(this); }
writeValue(value: any): void {
this._state = value;
if (isPresent(value) && value.checked) {
this._renderer.setElementProperty(this._elementRef.nativeElement, 'checked', true);
}
}
registerOnChange(fn: (_: any) => {}): void {
this._fn = fn;
this.onChange = () => {
fn(new RadioButtonState(true, this._state.value));
this._registry.select(this);
};
}
fireUncheck(): void { this._fn(new RadioButtonState(false, this._state.value)); }
registerOnTouched(fn: () => {}): void { this.onTouched = fn; }
}

View File

@ -1,139 +0,0 @@
import {
Directive,
Renderer,
forwardRef,
Provider,
ElementRef,
Input,
Host,
OnDestroy,
Optional
} from '@angular/core';
import {
StringWrapper,
isPrimitive,
isPresent,
isBlank,
looseIdentical
} from '../../../src/facade/lang';
import {MapWrapper} from '../../../src/facade/collection';
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from './control_value_accessor';
export const SELECT_VALUE_ACCESSOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
provide: 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.
*
* ### Example
*
* ```
* <select ngControl="city">
* <option *ngFor="let c of cities" [value]="c"></option>
* </select>
* ```
*/
@Directive({selector: 'option'})
export class NgSelectOption implements OnDestroy {
id: string;
constructor(private _element: ElementRef, private _renderer: Renderer,
@Optional() @Host() private _select: SelectControlValueAccessor) {
if (isPresent(this._select)) this.id = this._select._registerOption();
}
@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);
}
@Input('value')
set value(value: any) {
this._setElementValue(value);
if (isPresent(this._select)) this._select.writeValue(this._select.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);
}
}
}

View File

@ -1,5 +0,0 @@
export * from './location/platform_location';
export * from './location/location_strategy';
export * from './location/hash_location_strategy';
export * from './location/path_location_strategy';
export * from './location/location';

View File

@ -1,17 +0,0 @@
/**
* @module
* @description
* This module provides a set of common Pipes.
*/
export {AsyncPipe} from './pipes/async_pipe';
export {DatePipe} from './pipes/date_pipe';
export {JsonPipe} from './pipes/json_pipe';
export {SlicePipe} from './pipes/slice_pipe';
export {LowerCasePipe} from './pipes/lowercase_pipe';
export {NumberPipe, DecimalPipe, PercentPipe, CurrencyPipe} from './pipes/number_pipe';
export {UpperCasePipe} from './pipes/uppercase_pipe';
export {ReplacePipe} from './pipes/replace_pipe';
export {I18nPluralPipe} from './pipes/i18n_plural_pipe';
export {I18nSelectPipe} from './pipes/i18n_select_pipe';
export {COMMON_PIPES} from './pipes/common_pipes';

View File

@ -1,54 +0,0 @@
import {Injectable, PipeTransform, Pipe} from '@angular/core';
import {isStringMap, StringWrapper, isPresent, RegExpWrapper} from '../../src/facade/lang';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
var interpolationExp: RegExp = RegExpWrapper.create('#');
/**
*
* Maps a value to a string that pluralizes the value properly.
*
* ## Usage
*
* expression | i18nPlural:mapping
*
* where `expression` is a number and `mapping` is an object that indicates the proper text for
* when the `expression` evaluates to 0, 1, or some other number. You can interpolate the actual
* value into the text using the `#` sign.
*
* ## Example
*
* ```
* <div>
* {{ messages.length | i18nPlural: messageMapping }}
* </div>
*
* class MyApp {
* messages: any[];
* messageMapping: any = {
* '=0': 'No messages.',
* '=1': 'One message.',
* 'other': '# messages.'
* }
* ...
* }
* ```
*
*/
@Pipe({name: 'i18nPlural', pure: true})
@Injectable()
export class I18nPluralPipe implements PipeTransform {
transform(value: number, pluralMap: {[count: string]: string}): string {
var key: string;
var valueStr: string;
if (!isStringMap(pluralMap)) {
throw new InvalidPipeArgumentException(I18nPluralPipe, pluralMap);
}
key = value === 0 || value === 1 ? `=${value}` : 'other';
valueStr = isPresent(value) ? value.toString() : '';
return StringWrapper.replaceAll(pluralMap[key], interpolationExp, valueStr);
}
}

View File

@ -1,45 +0,0 @@
import {Injectable, PipeTransform, Pipe} from '@angular/core';
import {isStringMap} from '../../src/facade/lang';
import {StringMapWrapper} from '../../src/facade/collection';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
/**
*
* Generic selector that displays the string that matches the current value.
*
* ## Usage
*
* expression | i18nSelect:mapping
*
* where `mapping` is an object that indicates the text that should be displayed
* for different values of the provided `expression`.
*
* ## Example
*
* ```
* <div>
* {{ gender | i18nSelect: inviteMap }}
* </div>
*
* class MyApp {
* gender: string = 'male';
* inviteMap: any = {
* 'male': 'Invite her.',
* 'female': 'Invite him.',
* 'other': 'Invite them.'
* }
* ...
* }
* ```
*/
@Pipe({name: 'i18nSelect', pure: true})
@Injectable()
export class I18nSelectPipe implements PipeTransform {
transform(value: string, mapping: {[key: string]: string}): string {
if (!isStringMap(mapping)) {
throw new InvalidPipeArgumentException(I18nSelectPipe, mapping);
}
return StringMapWrapper.contains(mapping, value) ? mapping[value] : mapping['other'];
}
}

View File

@ -1,85 +0,0 @@
import {Injectable, PipeTransform, Pipe} from '@angular/core';
import {
isBlank,
isString,
isNumber,
isFunction,
RegExpWrapper,
StringWrapper
} from '../../src/facade/lang';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
/**
* Creates a new String with some or all of the matches of a pattern replaced by
* a replacement.
*
* The pattern to be matched is specified by the 'pattern' parameter.
*
* The replacement to be set is specified by the 'replacement' parameter.
*
* An optional 'flags' parameter can be set.
*
* ### Usage
*
* expression | replace:pattern:replacement
*
* All behavior is based on the expected behavior of the JavaScript API
* String.prototype.replace() function.
*
* Where the input expression is a [String] or [Number] (to be treated as a string),
* the `pattern` is a [String] or [RegExp],
* the 'replacement' is a [String] or [Function].
*
* --Note--: The 'pattern' parameter will be converted to a RegExp instance. Make sure to escape the
* string properly if you are matching for regular expression special characters like parenthesis,
* brackets etc.
*/
@Pipe({name: 'replace'})
@Injectable()
export class ReplacePipe implements PipeTransform {
transform(value: any, pattern: string | RegExp, replacement: Function | string): any {
if (isBlank(value)) {
return value;
}
if (!this._supportedInput(value)) {
throw new InvalidPipeArgumentException(ReplacePipe, value);
}
var input = value.toString();
if (!this._supportedPattern(pattern)) {
throw new InvalidPipeArgumentException(ReplacePipe, pattern);
}
if (!this._supportedReplacement(replacement)) {
throw new InvalidPipeArgumentException(ReplacePipe, replacement);
}
// template fails with literal RegExp e.g /pattern/igm
// var rgx = pattern instanceof RegExp ? pattern : RegExpWrapper.create(pattern);
if (isFunction(replacement)) {
var rgxPattern = isString(pattern) ? RegExpWrapper.create(<string>pattern) : <RegExp>pattern;
return StringWrapper.replaceAllMapped(input, rgxPattern, <Function>replacement);
}
if (pattern instanceof RegExp) {
// use the replaceAll variant
return StringWrapper.replaceAll(input, pattern, <string>replacement);
}
return StringWrapper.replace(input, <string>pattern, <string>replacement);
}
private _supportedInput(input: any): boolean { return isString(input) || isNumber(input); }
private _supportedPattern(pattern: any): boolean {
return isString(pattern) || pattern instanceof RegExp;
}
private _supportedReplacement(replacement: any): boolean {
return isString(replacement) || isFunction(replacement);
}
}

View File

@ -1,135 +0,0 @@
import {
beforeEachProviders,
beforeEach,
ddescribe,
describe,
expect,
iit,
inject,
it,
xit,
} from '@angular/core/testing/testing_internal';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing';
import {Component, Injectable, provide} from '@angular/core';
import {NgPlural, NgPluralCase, NgLocalization} from '@angular/common';
export function main() {
describe('switch', () => {
beforeEachProviders(() => [provide(NgLocalization, {useClass: TestLocalizationMap})]);
it('should display the template according to the exact value',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div>' +
'<ul [ngPlural]="switchValue">' +
'<template ngPluralCase="=0"><li>you have no messages.</li></template>' +
'<template ngPluralCase="=1"><li>you have one message.</li></template>' +
'</ul></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.switchValue = 0;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('you have no messages.');
fixture.debugElement.componentInstance.switchValue = 1;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('you have one message.');
async.done();
});
}));
it('should display the template according to the category',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div>' +
'<ul [ngPlural]="switchValue">' +
'<template ngPluralCase="few"><li>you have a few messages.</li></template>' +
'<template ngPluralCase="many"><li>you have many messages.</li></template>' +
'</ul></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.switchValue = 2;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('you have a few messages.');
fixture.debugElement.componentInstance.switchValue = 8;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('you have many messages.');
async.done();
});
}));
it('should default to other when no matches are found',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div>' +
'<ul [ngPlural]="switchValue">' +
'<template ngPluralCase="few"><li>you have a few messages.</li></template>' +
'<template ngPluralCase="other"><li>default message.</li></template>' +
'</ul></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.switchValue = 100;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('default message.');
async.done();
});
}));
it('should prioritize value matches over category matches',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div>' +
'<ul [ngPlural]="switchValue">' +
'<template ngPluralCase="few"><li>you have a few messages.</li></template>' +
'<template ngPluralCase="=2">you have two messages.</template>' +
'</ul></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.switchValue = 2;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('you have two messages.');
fixture.debugElement.componentInstance.switchValue = 3;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('you have a few messages.');
async.done();
});
}));
});
}
@Injectable()
export class TestLocalizationMap extends NgLocalization {
getPluralCategory(value: number): string {
if (value > 1 && value < 4) {
return 'few';
} else if (value >= 4 && value < 10) {
return 'many';
} else {
return 'other';
}
}
}
@Component({selector: 'test-cmp', directives: [NgPlural, NgPluralCase], template: ''})
class TestComponent {
switchValue: number;
constructor() { this.switchValue = null; }
}

View File

@ -1,110 +0,0 @@
import {
beforeEach,
ddescribe,
describe,
expect,
iit,
inject,
it,
xit,
} from '@angular/core/testing/testing_internal';
import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {Component, Directive, TemplateRef, ContentChildren, QueryList} from '@angular/core';
import {NgTemplateOutlet} from '@angular/common';
export function main() {
describe('insert', () => {
it('should do nothing if templateRef is null',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<template [ngTemplateOutlet]="null"></template>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('');
async.done();
});
}));
it('should insert content specified by TemplateRef',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<tpl-refs #refs="tplRefs"><template>foo</template></tpl-refs><template [ngTemplateOutlet]="currentTplRef"></template>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('');
var refs = fixture.debugElement.children[0].references['refs'];
fixture.componentInstance.currentTplRef = refs.tplRefs.first;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('foo');
async.done();
});
}));
it('should clear content if TemplateRef becomes null',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<tpl-refs #refs="tplRefs"><template>foo</template></tpl-refs><template [ngTemplateOutlet]="currentTplRef"></template>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
var refs = fixture.debugElement.children[0].references['refs'];
fixture.componentInstance.currentTplRef = refs.tplRefs.first;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('foo');
fixture.componentInstance.currentTplRef = null;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('');
async.done();
});
}));
it('should swap content if TemplateRef changes',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<tpl-refs #refs="tplRefs"><template>foo</template><template>bar</template></tpl-refs><template [ngTemplateOutlet]="currentTplRef"></template>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
var refs = fixture.debugElement.children[0].references['refs'];
fixture.componentInstance.currentTplRef = refs.tplRefs.first;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('foo');
fixture.componentInstance.currentTplRef = refs.tplRefs.last;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('bar');
async.done();
});
}));
});
}
@Directive({selector: 'tpl-refs', exportAs: 'tplRefs'})
class CaptureTplRefs {
@ContentChildren(TemplateRef) tplRefs: QueryList<TemplateRef<any>>;
}
@Component({selector: 'test-cmp', directives: [NgTemplateOutlet, CaptureTplRefs], template: ''})
class TestComponent {
currentTplRef: TemplateRef<any>;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,82 +0,0 @@
import {
ddescribe,
describe,
it,
iit,
xit,
expect,
beforeEach,
afterEach
} from '@angular/core/testing/testing_internal';
import {browserDetection} from '@angular/platform-browser/testing';
import {DatePipe} from '@angular/common';
import {DateWrapper} from '../../src/facade/lang';
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
export function main() {
describe("DatePipe", () => {
var date;
var pipe;
beforeEach(() => {
date = DateWrapper.create(2015, 6, 15, 21, 43, 11);
pipe = new DatePipe();
});
it('should be marked as pure',
() => { expect(new PipeResolver().resolve(DatePipe).pure).toEqual(true); });
describe("supports", () => {
it("should support date", () => { expect(pipe.supports(date)).toBe(true); });
it("should support int", () => { expect(pipe.supports(123456789)).toBe(true); });
it("should not support other objects", () => {
expect(pipe.supports(new Object())).toBe(false);
expect(pipe.supports(null)).toBe(false);
});
});
// TODO(mlaval): enable tests when Intl API is no longer used, see
// https://github.com/angular/angular/issues/3333
if (browserDetection.supportsIntlApi) {
describe("transform", () => {
it('should format each component correctly', () => {
expect(pipe.transform(date, 'y')).toEqual('2015');
expect(pipe.transform(date, 'yy')).toEqual('15');
expect(pipe.transform(date, 'M')).toEqual('6');
expect(pipe.transform(date, 'MM')).toEqual('06');
expect(pipe.transform(date, 'MMM')).toEqual('Jun');
expect(pipe.transform(date, 'MMMM')).toEqual('June');
expect(pipe.transform(date, 'd')).toEqual('15');
expect(pipe.transform(date, 'E')).toEqual('Mon');
expect(pipe.transform(date, 'EEEE')).toEqual('Monday');
expect(pipe.transform(date, 'H')).toEqual('21');
expect(pipe.transform(date, 'j')).toEqual('9 PM');
expect(pipe.transform(date, 'm')).toEqual('43');
expect(pipe.transform(date, 's')).toEqual('11');
});
it('should format common multi component patterns', () => {
expect(pipe.transform(date, 'yMEd')).toEqual('Mon, 6/15/2015');
expect(pipe.transform(date, 'MEd')).toEqual('Mon, 6/15');
expect(pipe.transform(date, 'MMMd')).toEqual('Jun 15');
expect(pipe.transform(date, 'yMMMMEEEEd')).toEqual('Monday, June 15, 2015');
expect(pipe.transform(date, 'jms')).toEqual('9:43:11 PM');
expect(pipe.transform(date, 'ms')).toEqual('43:11');
});
it('should format with pattern aliases', () => {
expect(pipe.transform(date, 'medium')).toEqual('Jun 15, 2015, 9:43:11 PM');
expect(pipe.transform(date, 'short')).toEqual('6/15/2015, 9:43 PM');
expect(pipe.transform(date, 'fullDate')).toEqual('Monday, June 15, 2015');
expect(pipe.transform(date, 'longDate')).toEqual('June 15, 2015');
expect(pipe.transform(date, 'mediumDate')).toEqual('Jun 15, 2015');
expect(pipe.transform(date, 'shortDate')).toEqual('6/15/2015');
expect(pipe.transform(date, 'mediumTime')).toEqual('9:43:11 PM');
expect(pipe.transform(date, 'shortTime')).toEqual('9:43 PM');
});
});
}
});
}

View File

@ -1,59 +0,0 @@
import {
ddescribe,
describe,
it,
iit,
xit,
expect,
beforeEach,
afterEach
} from '@angular/core/testing/testing_internal';
import {I18nPluralPipe} from '@angular/common';
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
export function main() {
describe("I18nPluralPipe", () => {
var pipe;
var mapping = {'=0': 'No messages.', '=1': 'One message.', 'other': 'There are some messages.'};
var interpolatedMapping =
{'=0': 'No messages.', '=1': 'One message.', 'other': 'There are # messages, that is #.'};
beforeEach(() => { pipe = new I18nPluralPipe(); });
it('should be marked as pure',
() => { expect(new PipeResolver().resolve(I18nPluralPipe).pure).toEqual(true); });
describe("transform", () => {
it("should return 0 text if value is 0", () => {
var val = pipe.transform(0, mapping);
expect(val).toEqual('No messages.');
});
it("should return 1 text if value is 1", () => {
var val = pipe.transform(1, mapping);
expect(val).toEqual('One message.');
});
it("should return other text if value is anything other than 0 or 1", () => {
var val = pipe.transform(6, mapping);
expect(val).toEqual('There are some messages.');
});
it("should interpolate the value into the text where indicated", () => {
var val = pipe.transform(6, interpolatedMapping);
expect(val).toEqual('There are 6 messages, that is 6.');
});
it("should use 'other' if value is undefined", () => {
var messageLength;
var val = pipe.transform(messageLength, interpolatedMapping);
expect(val).toEqual('There are messages, that is .');
});
it("should not support bad arguments",
() => { expect(() => pipe.transform(0, 'hey')).toThrowError(); });
});
});
}

View File

@ -1,52 +0,0 @@
import {
ddescribe,
describe,
it,
iit,
xit,
expect,
beforeEach,
afterEach
} from '@angular/core/testing/testing_internal';
import {I18nSelectPipe} from '@angular/common';
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
export function main() {
describe("I18nSelectPipe", () => {
var pipe;
var mapping = {'male': 'Invite him.', 'female': 'Invite her.', 'other': 'Invite them.'};
beforeEach(() => { pipe = new I18nSelectPipe(); });
it('should be marked as pure',
() => { expect(new PipeResolver().resolve(I18nSelectPipe).pure).toEqual(true); });
describe("transform", () => {
it("should return male text if value is male", () => {
var val = pipe.transform('male', mapping);
expect(val).toEqual('Invite him.');
});
it("should return female text if value is female", () => {
var val = pipe.transform('female', mapping);
expect(val).toEqual('Invite her.');
});
it("should return other text if value is anything other than male or female", () => {
var val = pipe.transform('Anything else', mapping);
expect(val).toEqual('Invite them.');
});
it("should use 'other' if value is undefined", () => {
var gender;
var val = pipe.transform(gender, mapping);
expect(val).toEqual('Invite them.');
});
it("should not support bad arguments",
() => { expect(() => pipe.transform('male', 'hey')).toThrowError(); });
});
});
}

View File

@ -1,74 +0,0 @@
import {
ddescribe,
describe,
it,
iit,
xit,
expect,
beforeEach,
afterEach,
} from '@angular/core/testing/testing_internal';
import {browserDetection} from '@angular/platform-browser/testing';
import {DecimalPipe, PercentPipe, CurrencyPipe} from '@angular/common';
export function main() {
describe('Number pipes', () => {
// TODO(mlaval): enable tests when Intl API is no longer used, see
// https://github.com/angular/angular/issues/3333
if (browserDetection.supportsIntlApi) {
describe("DecimalPipe", () => {
var pipe;
beforeEach(() => { pipe = new DecimalPipe(); });
describe("transform", () => {
it('should return correct value for numbers', () => {
expect(pipe.transform(12345)).toEqual('12,345');
expect(pipe.transform(123, '.2')).toEqual('123.00');
expect(pipe.transform(1, '3.')).toEqual('001');
expect(pipe.transform(1.1, '3.4-5')).toEqual('001.1000');
expect(pipe.transform(1.123456, '3.4-5')).toEqual('001.12346');
expect(pipe.transform(1.1234)).toEqual('1.123');
});
it("should not support other objects",
() => { expect(() => pipe.transform(new Object())).toThrowError(); });
});
});
describe("PercentPipe", () => {
var pipe;
beforeEach(() => { pipe = new PercentPipe(); });
describe("transform", () => {
it('should return correct value for numbers', () => {
expect(pipe.transform(1.23)).toEqual('123%');
expect(pipe.transform(1.2, '.2')).toEqual('120.00%');
});
it("should not support other objects",
() => { expect(() => pipe.transform(new Object())).toThrowError(); });
});
});
describe("CurrencyPipe", () => {
var pipe;
beforeEach(() => { pipe = new CurrencyPipe(); });
describe("transform", () => {
it('should return correct value for numbers', () => {
expect(pipe.transform(123)).toEqual('USD123');
expect(pipe.transform(12, 'EUR', false, '.2')).toEqual('EUR12.00');
});
it("should not support other objects",
() => { expect(() => pipe.transform(new Object())).toThrowError(); });
});
});
}
});
}

View File

@ -1,71 +0,0 @@
import {
ddescribe,
describe,
it,
iit,
xit,
expect,
beforeEach,
afterEach,
inject,
} from '@angular/core/testing/testing_internal';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {ReplacePipe} from '@angular/common';
import {RegExpWrapper, StringJoiner} from '../../src/facade/lang';
export function main() {
describe("ReplacePipe", () => {
var someNumber: number;
var str;
var pipe;
beforeEach(() => {
someNumber = 42;
str = 'Douglas Adams';
pipe = new ReplacePipe();
});
describe("transform", () => {
it("should not support input other than strings and numbers", () => {
expect(() => pipe.transform({}, "Douglas", "Hugh")).toThrow();
expect(() => pipe.transform([1, 2, 3], "Douglas", "Hugh")).toThrow();
});
it("should not support patterns other than strings and regular expressions", () => {
expect(() => pipe.transform(str, {}, "Hugh")).toThrow();
expect(() => pipe.transform(str, null, "Hugh")).toThrow();
expect(() => pipe.transform(str, 123, "Hugh")).toThrow();
});
it("should not support replacements other than strings and functions", () => {
expect(() => pipe.transform(str, "Douglas", {})).toThrow();
expect(() => pipe.transform(str, "Douglas", null)).toThrow();
expect(() => pipe.transform(str, "Douglas", 123)).toThrow();
});
it("should return a new string with the pattern replaced", () => {
var result1 = pipe.transform(str, "Douglas", "Hugh");
var result2 = pipe.transform(str, RegExpWrapper.create("a"), "_");
var result3 = pipe.transform(str, RegExpWrapper.create("a", "i"), "_");
var f = (x => { return "Adams!"; });
var result4 = pipe.transform(str, "Adams", f);
var result5 = pipe.transform(someNumber, "2", "4");
expect(result1).toEqual("Hugh Adams");
expect(result2).toEqual("Dougl_s Ad_ms");
expect(result3).toEqual("Dougl_s _d_ms");
expect(result4).toEqual("Douglas Adams!");
expect(result5).toEqual("44");
});
});
});
}

View File

@ -1,2 +0,0 @@
export {MockLocationStrategy} from './testing/mock_location_strategy';
export {SpyLocation} from './testing/location_mock';

View File

@ -1,26 +0,0 @@
{
"angularCompilerOptions": {
"skipTemplateCodegen": true
},
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "es2015",
"moduleResolution": "node",
"outDir": "../../../dist/packages-dist/common/esm",
"paths": {
"@angular/core": ["../../../dist/packages-dist/core"]
},
"rootDir": ".",
"sourceMap": true,
"sourceRoot": ".",
"target": "es2015"
},
"files": [
"index.ts",
"testing.ts",
"../../../node_modules/zone.js/dist/zone.js.d.ts"
]
}

View File

@ -1,30 +0,0 @@
{
"angularCompilerOptions": {
"skipTemplateCodegen": true
},
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "commonjs",
"moduleResolution": "node",
"outDir": "../../../dist/packages-dist/common/",
"paths": {
"@angular/core": ["../../../dist/packages-dist/core/"]
},
"rootDir": ".",
"sourceMap": true,
"sourceRoot": ".",
"target": "es5"
},
"files": [
"index.ts",
"testing.ts",
"../typings/es6-collections/es6-collections.d.ts",
"../typings/es6-promise/es6-promise.d.ts",
"../manual_typings/globals.d.ts",
"../../../node_modules/zone.js/dist/zone.js.d.ts"
]
}

View File

@ -1,37 +0,0 @@
/**
* @module
* @description
* Starting point to import all compiler APIs.
*/
export {ElementSchemaRegistry} from './src/schema/element_schema_registry';
export {
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 './src/compiler';
export * from './src/template_ast';
export * from './private_export';

View File

@ -1 +0,0 @@
export '../core/private_export.dart';

View File

@ -1,56 +0,0 @@
import {__core_private__ as r, __core_private_types__ as t} from '@angular/core';
export var isDefaultChangeDetectionStrategy: typeof t.isDefaultChangeDetectionStrategy =
r.isDefaultChangeDetectionStrategy;
export type ChangeDetectorState = t.ChangeDetectorState;
export var ChangeDetectorState: typeof t.ChangeDetectorState = r.ChangeDetectorState;
export var CHANGE_DETECTION_STRATEGY_VALUES: typeof t.CHANGE_DETECTION_STRATEGY_VALUES =
r.CHANGE_DETECTION_STRATEGY_VALUES;
export var constructDependencies: typeof t.constructDependencies = r.constructDependencies;
export type LifecycleHooks = t.LifecycleHooks;
export var LifecycleHooks: typeof t.LifecycleHooks = r.LifecycleHooks;
export var LIFECYCLE_HOOKS_VALUES: typeof t.LIFECYCLE_HOOKS_VALUES = r.LIFECYCLE_HOOKS_VALUES;
export type ReflectorReader = t.ReflectorReader;
export var ReflectorReader: typeof t.ReflectorReader = r.ReflectorReader;
export var ReflectorComponentResolver: typeof t.ReflectorComponentResolver =
r.ReflectorComponentResolver;
export type AppElement = t.AppElement;
export var AppElement: typeof t.AppElement = r.AppElement;
export var AppView: typeof t.AppView = r.AppView;
export type DebugAppView<T> = t.DebugAppView<T>;
export var DebugAppView: typeof t.DebugAppView = r.DebugAppView;
export type ViewType = t.ViewType;
export var ViewType: typeof t.ViewType = r.ViewType;
export var MAX_INTERPOLATION_VALUES: typeof t.MAX_INTERPOLATION_VALUES = r.MAX_INTERPOLATION_VALUES;
export var checkBinding: typeof t.checkBinding = r.checkBinding;
export var flattenNestedViewRenderNodes: typeof t.flattenNestedViewRenderNodes =
r.flattenNestedViewRenderNodes;
export var interpolate: typeof t.interpolate = r.interpolate;
export var ViewUtils: typeof t.ViewUtils = r.ViewUtils;
export var VIEW_ENCAPSULATION_VALUES: typeof t.VIEW_ENCAPSULATION_VALUES =
r.VIEW_ENCAPSULATION_VALUES;
export var DebugContext: typeof t.DebugContext = r.DebugContext;
export var StaticNodeDebugInfo: typeof t.StaticNodeDebugInfo = r.StaticNodeDebugInfo;
export var devModeEqual: typeof t.devModeEqual = r.devModeEqual;
export var uninitialized: typeof t.uninitialized = r.uninitialized;
export var ValueUnwrapper: typeof t.ValueUnwrapper = r.ValueUnwrapper;
export var TemplateRef_: typeof t.TemplateRef_ = r.TemplateRef_;
export type RenderDebugInfo = t.RenderDebugInfo;
export var RenderDebugInfo: typeof t.RenderDebugInfo = r.RenderDebugInfo;
export var createProvider: typeof t.createProvider = r.createProvider;
export var isProviderLiteral: typeof t.isProviderLiteral = r.isProviderLiteral;
export var EMPTY_ARRAY: typeof t.EMPTY_ARRAY = r.EMPTY_ARRAY;
export var EMPTY_MAP: typeof t.EMPTY_MAP = r.EMPTY_MAP;
export var pureProxy1: typeof t.pureProxy1 = r.pureProxy1;
export var pureProxy2: typeof t.pureProxy2 = r.pureProxy2;
export var pureProxy3: typeof t.pureProxy3 = r.pureProxy3;
export var pureProxy4: typeof t.pureProxy4 = r.pureProxy4;
export var pureProxy5: typeof t.pureProxy5 = r.pureProxy5;
export var pureProxy6: typeof t.pureProxy6 = r.pureProxy6;
export var pureProxy7: typeof t.pureProxy7 = r.pureProxy7;
export var pureProxy8: typeof t.pureProxy8 = r.pureProxy8;
export var pureProxy9: typeof t.pureProxy9 = r.pureProxy9;
export var pureProxy10: typeof t.pureProxy10 = r.pureProxy10;
export var castByValue: typeof t.castByValue = r.castByValue;
export type Console = t.Console;
export var Console: typeof t.Console = r.Console;

View File

@ -1 +0,0 @@
export * from './compiler';

View File

@ -1,13 +0,0 @@
{
"name": "@angular/compiler",
"version": "$$ANGULAR_VERSION$$",
"description": "",
"main": "index.js",
"jsnext:main": "esm/index.js",
"typings": "index.d.ts",
"author": "angular",
"license": "MIT",
"peerDependencies": {
"@angular/core": "$$ANGULAR_VERSION$$"
}
}

View File

@ -1 +0,0 @@
export './src/core/change_detection/constants.dart' show SelectorMatcher, CssSelector;

View File

@ -1,16 +0,0 @@
import * as selector from './src/selector';
import * as pathUtil from './src/output/path_util';
export namespace __compiler_private__ {
export type SelectorMatcher = selector.SelectorMatcher;
export var SelectorMatcher = selector.SelectorMatcher;
export type CssSelector = selector.CssSelector;
export var CssSelector = selector.CssSelector;
export type AssetUrl = pathUtil.AssetUrl;
export var AssetUrl = pathUtil.AssetUrl;
export type ImportGenerator = pathUtil.ImportGenerator;
export var ImportGenerator = pathUtil.ImportGenerator;
}

View File

@ -1,18 +0,0 @@
export default {
entry: '../../../dist/packages-dist/compiler/esm/index.js',
dest: '../../../dist/packages-dist/compiler/esm/compiler.umd.js',
sourceMap: true,
format: 'umd',
moduleName: 'ng.compiler',
globals: {
'@angular/core': 'ng.core',
'rxjs/Subject': 'Rx',
'rxjs/observable/PromiseObservable': 'Rx', // this is wrong, but this stuff has changed in rxjs b.6 so we need to fix it when we update.
'rxjs/operator/toPromise': 'Rx.Observable.prototype',
'rxjs/Observable': 'Rx'
},
plugins: [
// nodeResolve({ jsnext: true, main: true }),
]
}

View File

@ -1,3 +0,0 @@
library angular2.core.util.asserions;
void assertArrayOfStrings(String identifier, Object value) {}

View File

@ -1,16 +0,0 @@
import {isArray, isString, isBlank, assertionsEnabled} from '../src/facade/lang';
import {BaseException} from '../src/facade/exceptions';
export function assertArrayOfStrings(identifier: string, value: any) {
if (!assertionsEnabled() || isBlank(value)) {
return;
}
if (!isArray(value)) {
throw new BaseException(`Expected '${identifier}' to be an array of strings.`);
}
for (var i = 0; i < value.length; i += 1) {
if (!isString(value[i])) {
throw new BaseException(`Expected '${identifier}' to be an array of strings.`);
}
}
}

View File

@ -1,64 +0,0 @@
export const $EOF = /*@ts2dart_const*/ 0;
export const $TAB = /*@ts2dart_const*/ 9;
export const $LF = /*@ts2dart_const*/ 10;
export const $VTAB = /*@ts2dart_const*/ 11;
export const $FF = /*@ts2dart_const*/ 12;
export const $CR = /*@ts2dart_const*/ 13;
export const $SPACE = /*@ts2dart_const*/ 32;
export const $BANG = /*@ts2dart_const*/ 33;
export const $DQ = /*@ts2dart_const*/ 34;
export const $HASH = /*@ts2dart_const*/ 35;
export const $$ = /*@ts2dart_const*/ 36;
export const $PERCENT = /*@ts2dart_const*/ 37;
export const $AMPERSAND = /*@ts2dart_const*/ 38;
export const $SQ = /*@ts2dart_const*/ 39;
export const $LPAREN = /*@ts2dart_const*/ 40;
export const $RPAREN = /*@ts2dart_const*/ 41;
export const $STAR = /*@ts2dart_const*/ 42;
export const $PLUS = /*@ts2dart_const*/ 43;
export const $COMMA = /*@ts2dart_const*/ 44;
export const $MINUS = /*@ts2dart_const*/ 45;
export const $PERIOD = /*@ts2dart_const*/ 46;
export const $SLASH = /*@ts2dart_const*/ 47;
export const $COLON = /*@ts2dart_const*/ 58;
export const $SEMICOLON = /*@ts2dart_const*/ 59;
export const $LT = /*@ts2dart_const*/ 60;
export const $EQ = /*@ts2dart_const*/ 61;
export const $GT = /*@ts2dart_const*/ 62;
export const $QUESTION = /*@ts2dart_const*/ 63;
export const $0 = /*@ts2dart_const*/ 48;
export const $9 = /*@ts2dart_const*/ 57;
export const $A = /*@ts2dart_const*/ 65;
export const $E = /*@ts2dart_const*/ 69;
export const $Z = /*@ts2dart_const*/ 90;
export const $LBRACKET = /*@ts2dart_const*/ 91;
export const $BACKSLASH = /*@ts2dart_const*/ 92;
export const $RBRACKET = /*@ts2dart_const*/ 93;
export const $CARET = /*@ts2dart_const*/ 94;
export const $_ = /*@ts2dart_const*/ 95;
export const $a = /*@ts2dart_const*/ 97;
export const $e = /*@ts2dart_const*/ 101;
export const $f = /*@ts2dart_const*/ 102;
export const $n = /*@ts2dart_const*/ 110;
export const $r = /*@ts2dart_const*/ 114;
export const $t = /*@ts2dart_const*/ 116;
export const $u = /*@ts2dart_const*/ 117;
export const $v = /*@ts2dart_const*/ 118;
export const $z = /*@ts2dart_const*/ 122;
export const $LBRACE = /*@ts2dart_const*/ 123;
export const $BAR = /*@ts2dart_const*/ 124;
export const $RBRACE = /*@ts2dart_const*/ 125;
export const $NBSP = /*@ts2dart_const*/ 160;
export const $PIPE = /*@ts2dart_const*/ 124;
export const $TILDA = /*@ts2dart_const*/ 126;
export const $AT = /*@ts2dart_const*/ 64;
export function isWhitespace(code: number): boolean {
return (code >= $TAB && code <= $SPACE) || (code == $NBSP);
}

View File

@ -1,793 +0,0 @@
import {ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core';
import {
CHANGE_DETECTION_STRATEGY_VALUES,
VIEW_ENCAPSULATION_VALUES,
LifecycleHooks,
LIFECYCLE_HOOKS_VALUES
} from '../core_private';
import {
isPresent,
isBlank,
isNumber,
isBoolean,
normalizeBool,
normalizeBlank,
serializeEnum,
Type,
isString,
RegExpWrapper,
isArray
} from '../src/facade/lang';
import {unimplemented, BaseException} from '../src/facade/exceptions';
import {
StringMapWrapper,
} from '../src/facade/collection';
import {CssSelector} from './selector';
import {splitAtColon, sanitizeIdentifier} from './util';
import {getUrlScheme} from './url_resolver';
// group 1: "property" from "[property]"
// group 2: "event" from "(event)"
var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$/g;
export abstract class CompileMetadataWithIdentifier {
abstract toJson(): {[key: string]: any};
get identifier(): CompileIdentifierMetadata { return <CompileIdentifierMetadata>unimplemented(); }
}
export abstract class CompileMetadataWithType extends CompileMetadataWithIdentifier {
abstract toJson(): {[key: string]: any};
get type(): CompileTypeMetadata { return <CompileTypeMetadata>unimplemented(); }
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;
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.value = value;
}
static fromJson(data: {[key: string]: any}): CompileIdentifierMetadata {
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,
'value': value
};
}
get identifier(): CompileIdentifierMetadata { return this; }
}
export class CompileDiDependencyMetadata {
isAttribute: boolean;
isSelf: boolean;
isHost: boolean;
isSkipSelf: boolean;
isOptional: boolean;
isValue: boolean;
query: CompileQueryMetadata;
viewQuery: CompileQueryMetadata;
token: CompileTokenMetadata;
value: any;
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?: 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'], 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'],
isValue: data['isValue']
});
}
toJson(): {[key: string]: any} {
return {
'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,
'isValue': this.isValue
};
}
}
export class CompileProviderMetadata {
token: CompileTokenMetadata;
useClass: CompileTypeMetadata;
useValue: any;
useExisting: CompileTokenMetadata;
useFactory: CompileFactoryMetadata;
deps: CompileDiDependencyMetadata[];
multi: boolean;
constructor({token, useClass, useValue, useExisting, useFactory, deps, multi}: {
token?: CompileTokenMetadata,
useClass?: CompileTypeMetadata,
useValue?: any,
useExisting?: CompileTokenMetadata,
useFactory?: CompileFactoryMetadata,
deps?: CompileDiDependencyMetadata[],
multi?: boolean
}) {
this.token = token;
this.useClass = useClass;
this.useValue = useValue;
this.useExisting = useExisting;
this.useFactory = useFactory;
this.deps = normalizeBlank(deps);
this.multi = normalizeBool(multi);
}
static fromJson(data: {[key: string]: any}): CompileProviderMetadata {
return new CompileProviderMetadata({
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...
'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,
CompileMetadataWithIdentifier {
runtime: Function;
name: string;
prefix: string;
moduleUrl: string;
value: any;
diDeps: CompileDiDependencyMetadata[];
constructor({runtime, name, moduleUrl, prefix, diDeps, value}: {
runtime?: Function,
name?: string,
prefix?: string,
moduleUrl?: string,
value?: boolean,
diDeps?: CompileDiDependencyMetadata[]
}) {
this.runtime = runtime;
this.name = name;
this.prefix = prefix;
this.moduleUrl = moduleUrl;
this.diDeps = _normalizeArray(diDeps);
this.value = value;
}
get identifier(): CompileIdentifierMetadata { return this; }
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; }
}
/**
* Metadata regarding compilation of a type.
*/
export class CompileTypeMetadata implements CompileIdentifierMetadata, CompileMetadataWithType {
runtime: Type;
name: string;
prefix: string;
moduleUrl: string;
isHost: boolean;
value: any;
diDeps: CompileDiDependencyMetadata[];
constructor({runtime, name, moduleUrl, prefix, isHost, value, diDeps}: {
runtime?: Type,
name?: string,
moduleUrl?: string,
prefix?: string,
isHost?: boolean,
value?: any,
diDeps?: CompileDiDependencyMetadata[]
} = {}) {
this.runtime = runtime;
this.name = name;
this.moduleUrl = moduleUrl;
this.prefix = prefix;
this.isHost = normalizeBool(isHost);
this.value = value;
this.diDeps = _normalizeArray(diDeps);
}
static fromJson(data: {[key: string]: any}): CompileTypeMetadata {
return new CompileTypeMetadata({
name: data['name'],
moduleUrl: data['moduleUrl'],
prefix: data['prefix'],
isHost: data['isHost'],
value: data['value'],
diDeps: _arrayFromJson(data['diDeps'], CompileDiDependencyMetadata.fromJson)
});
}
get identifier(): CompileIdentifierMetadata { return this; }
get type(): CompileTypeMetadata { return this; }
toJson(): {[key: string]: any} {
return {
// Note: Runtime type can't be serialized...
'class': 'Type',
'name': this.name,
'moduleUrl': this.moduleUrl,
'prefix': this.prefix,
'isHost': this.isHost,
'value': this.value,
'diDeps': _arrayToJson(this.diDeps)
};
}
}
export class CompileQueryMetadata {
selectors: Array<CompileTokenMetadata>;
descendants: boolean;
first: boolean;
propertyName: string;
read: CompileTokenMetadata;
constructor({selectors, descendants, first, propertyName, read}: {
selectors?: Array<CompileTokenMetadata>,
descendants?: boolean,
first?: boolean,
propertyName?: string,
read?: CompileTokenMetadata
} = {}) {
this.selectors = selectors;
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'], CompileTokenMetadata.fromJson),
descendants: data['descendants'],
first: data['first'],
propertyName: data['propertyName'],
read: _objFromJson(data['read'], CompileTokenMetadata.fromJson)
});
}
toJson(): {[key: string]: any} {
return {
'selectors': _arrayToJson(this.selectors),
'descendants': this.descendants,
'first': this.first,
'propertyName': this.propertyName,
'read': _objToJson(this.read)
};
}
}
/**
* Metadata regarding compilation of a template.
*/
export class CompileTemplateMetadata {
encapsulation: ViewEncapsulation;
template: string;
templateUrl: string;
styles: string[];
styleUrls: string[];
ngContentSelectors: string[];
constructor({encapsulation, template, templateUrl, styles, styleUrls, ngContentSelectors}: {
encapsulation?: ViewEncapsulation,
template?: string,
templateUrl?: string,
styles?: string[],
styleUrls?: string[],
ngContentSelectors?: string[]
} = {}) {
this.encapsulation = isPresent(encapsulation) ? encapsulation : ViewEncapsulation.Emulated;
this.template = template;
this.templateUrl = templateUrl;
this.styles = isPresent(styles) ? styles : [];
this.styleUrls = isPresent(styleUrls) ? styleUrls : [];
this.ngContentSelectors = isPresent(ngContentSelectors) ? ngContentSelectors : [];
}
static fromJson(data: {[key: string]: any}): CompileTemplateMetadata {
return new CompileTemplateMetadata({
encapsulation: isPresent(data['encapsulation']) ?
VIEW_ENCAPSULATION_VALUES[data['encapsulation']] :
data['encapsulation'],
template: data['template'],
templateUrl: data['templateUrl'],
styles: data['styles'],
styleUrls: data['styleUrls'],
ngContentSelectors: data['ngContentSelectors']
});
}
toJson(): {[key: string]: any} {
return {
'encapsulation':
isPresent(this.encapsulation) ? serializeEnum(this.encapsulation) : this.encapsulation,
'template': this.template,
'templateUrl': this.templateUrl,
'styles': this.styles,
'styleUrls': this.styleUrls,
'ngContentSelectors': this.ngContentSelectors
};
}
}
/**
* Metadata regarding compilation of a directive.
*/
export class CompileDirectiveMetadata implements CompileMetadataWithType {
static create({type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host,
lifecycleHooks, providers, viewProviders, queries, viewQueries, template}: {
type?: CompileTypeMetadata,
isComponent?: boolean,
selector?: string,
exportAs?: string,
changeDetection?: ChangeDetectionStrategy,
inputs?: string[],
outputs?: string[],
host?: {[key: string]: string},
lifecycleHooks?: LifecycleHooks[],
providers?:
Array<CompileProviderMetadata | CompileTypeMetadata | CompileIdentifierMetadata | any[]>,
viewProviders?:
Array<CompileProviderMetadata | CompileTypeMetadata | CompileIdentifierMetadata | any[]>,
queries?: CompileQueryMetadata[],
viewQueries?: CompileQueryMetadata[],
template?: CompileTemplateMetadata
} = {}): CompileDirectiveMetadata {
var hostListeners: {[key: string]: string} = {};
var hostProperties: {[key: string]: string} = {};
var hostAttributes: {[key: string]: string} = {};
if (isPresent(host)) {
StringMapWrapper.forEach(host, (value: string, key: string) => {
var matches = RegExpWrapper.firstMatch(HOST_REG_EXP, key);
if (isBlank(matches)) {
hostAttributes[key] = value;
} else if (isPresent(matches[1])) {
hostProperties[matches[1]] = value;
} else if (isPresent(matches[2])) {
hostListeners[matches[2]] = value;
}
});
}
var inputsMap: {[key: string]: string} = {};
if (isPresent(inputs)) {
inputs.forEach((bindConfig: string) => {
// canonical syntax: `dirProp: elProp`
// if there is no `:`, use dirProp = elProp
var parts = splitAtColon(bindConfig, [bindConfig, bindConfig]);
inputsMap[parts[0]] = parts[1];
});
}
var outputsMap: {[key: string]: string} = {};
if (isPresent(outputs)) {
outputs.forEach((bindConfig: string) => {
// canonical syntax: `dirProp: elProp`
// if there is no `:`, use dirProp = elProp
var parts = splitAtColon(bindConfig, [bindConfig, bindConfig]);
outputsMap[parts[0]] = parts[1];
});
}
return new CompileDirectiveMetadata({
type: type,
isComponent: normalizeBool(isComponent),
selector: selector,
exportAs: exportAs,
changeDetection: changeDetection,
inputs: inputsMap,
outputs: outputsMap,
hostListeners: hostListeners,
hostProperties: hostProperties,
hostAttributes: hostAttributes,
lifecycleHooks: isPresent(lifecycleHooks) ? lifecycleHooks : [],
providers: providers,
viewProviders: viewProviders,
queries: queries,
viewQueries: viewQueries,
template: template
});
}
type: CompileTypeMetadata;
isComponent: boolean;
selector: string;
exportAs: string;
changeDetection: ChangeDetectionStrategy;
inputs: {[key: string]: string};
outputs: {[key: string]: string};
hostListeners: {[key: string]: string};
hostProperties: {[key: string]: string};
hostAttributes: {[key: string]: string};
lifecycleHooks: LifecycleHooks[];
providers: CompileProviderMetadata[];
viewProviders: CompileProviderMetadata[];
queries: CompileQueryMetadata[];
viewQueries: CompileQueryMetadata[];
template: CompileTemplateMetadata;
constructor({type, isComponent, selector, exportAs, changeDetection, inputs, outputs,
hostListeners, hostProperties, hostAttributes, lifecycleHooks, providers,
viewProviders, queries, viewQueries, template}: {
type?: CompileTypeMetadata,
isComponent?: boolean,
selector?: string,
exportAs?: string,
changeDetection?: ChangeDetectionStrategy,
inputs?: {[key: string]: string},
outputs?: {[key: string]: string},
hostListeners?: {[key: string]: string},
hostProperties?: {[key: string]: string},
hostAttributes?: {[key: string]: string},
lifecycleHooks?: LifecycleHooks[],
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.selector = selector;
this.exportAs = exportAs;
this.changeDetection = changeDetection;
this.inputs = inputs;
this.outputs = outputs;
this.hostListeners = hostListeners;
this.hostProperties = hostProperties;
this.hostAttributes = hostAttributes;
this.lifecycleHooks = _normalizeArray(lifecycleHooks);
this.providers = _normalizeArray(providers);
this.viewProviders = _normalizeArray(viewProviders);
this.queries = _normalizeArray(queries);
this.viewQueries = _normalizeArray(viewQueries);
this.template = template;
}
get identifier(): CompileIdentifierMetadata { return this.type; }
static fromJson(data: {[key: string]: any}): CompileDirectiveMetadata {
return new CompileDirectiveMetadata({
isComponent: data['isComponent'],
selector: data['selector'],
exportAs: data['exportAs'],
type: isPresent(data['type']) ? CompileTypeMetadata.fromJson(data['type']) : data['type'],
changeDetection: isPresent(data['changeDetection']) ?
CHANGE_DETECTION_STRATEGY_VALUES[data['changeDetection']] :
data['changeDetection'],
inputs: data['inputs'],
outputs: data['outputs'],
hostListeners: data['hostListeners'],
hostProperties: data['hostProperties'],
hostAttributes: data['hostAttributes'],
lifecycleHooks:
(<any[]>data['lifecycleHooks']).map(hookValue => LIFECYCLE_HOOKS_VALUES[hookValue]),
template: isPresent(data['template']) ? CompileTemplateMetadata.fromJson(data['template']) :
data['template'],
providers: _arrayFromJson(data['providers'], metadataFromJson),
viewProviders: _arrayFromJson(data['viewProviders'], metadataFromJson),
queries: _arrayFromJson(data['queries'], CompileQueryMetadata.fromJson),
viewQueries: _arrayFromJson(data['viewQueries'], CompileQueryMetadata.fromJson)
});
}
toJson(): {[key: string]: any} {
return {
'class': 'Directive',
'isComponent': this.isComponent,
'selector': this.selector,
'exportAs': this.exportAs,
'type': isPresent(this.type) ? this.type.toJson() : this.type,
'changeDetection': isPresent(this.changeDetection) ? serializeEnum(this.changeDetection) :
this.changeDetection,
'inputs': this.inputs,
'outputs': this.outputs,
'hostListeners': this.hostListeners,
'hostProperties': this.hostProperties,
'hostAttributes': this.hostAttributes,
'lifecycleHooks': this.lifecycleHooks.map(hook => serializeEnum(hook)),
'template': isPresent(this.template) ? this.template.toJson() : this.template,
'providers': _arrayToJson(this.providers),
'viewProviders': _arrayToJson(this.viewProviders),
'queries': _arrayToJson(this.queries),
'viewQueries': _arrayToJson(this.viewQueries)
};
}
}
/**
* Construct {@link CompileDirectiveMetadata} from {@link ComponentTypeMetadata} and a selector.
*/
export function createHostComponentMeta(componentType: CompileTypeMetadata,
componentSelector: string): CompileDirectiveMetadata {
var template = CssSelector.parse(componentSelector)[0].getMatchingElementTemplate();
return CompileDirectiveMetadata.create({
type: new CompileTypeMetadata({
runtime: Object,
name: `${componentType.name}_Host`,
moduleUrl: componentType.moduleUrl,
isHost: true
}),
template: new CompileTemplateMetadata(
{template: template, templateUrl: '', styles: [], styleUrls: [], ngContentSelectors: []}),
changeDetection: ChangeDetectionStrategy.Default,
inputs: [],
outputs: [],
host: {},
lifecycleHooks: [],
isComponent: true,
selector: '*',
providers: [],
viewProviders: [],
queries: [],
viewQueries: []
});
}
export class CompilePipeMetadata implements CompileMetadataWithType {
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; }
static fromJson(data: {[key: string]: any}): CompilePipeMetadata {
return new CompilePipeMetadata({
type: isPresent(data['type']) ? CompileTypeMetadata.fromJson(data['type']) : data['type'],
name: data['name'],
pure: data['pure']
});
}
toJson(): {[key: string]: any} {
return {
'class': 'Pipe',
'type': isPresent(this.type) ? this.type.toJson() : null,
'name': this.name,
'pure': this.pure
};
}
}
var _COMPILE_METADATA_FROM_JSON = {
'Directive': CompileDirectiveMetadata.fromJson,
'Pipe': CompilePipeMetadata.fromJson,
'Type': CompileTypeMetadata.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 _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 {
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} {
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 : [];
}

View File

@ -1,62 +0,0 @@
import {ComponentResolver, Type} from '@angular/core';
import {assertionsEnabled} from '../src/facade/lang';
export * from './template_ast';
export {TEMPLATE_TRANSFORMS} from './template_parser';
export {CompilerConfig, RenderTypes} from './config';
export * from './compile_metadata';
export * from './offline_compiler';
export {RuntimeCompiler} from './runtime_compiler';
export * from './url_resolver';
export * from './xhr';
export {ViewResolver} from './view_resolver';
export {DirectiveResolver} from './directive_resolver';
export {PipeResolver} from './pipe_resolver';
import {TemplateParser} from './template_parser';
import {HtmlParser} from './html_parser';
import {DirectiveNormalizer} from './directive_normalizer';
import {CompileMetadataResolver} from './metadata_resolver';
import {StyleCompiler} from './style_compiler';
import {ViewCompiler} from './view_compiler/view_compiler';
import {CompilerConfig} from './config';
import {RuntimeCompiler} from './runtime_compiler';
import {ElementSchemaRegistry} from './schema/element_schema_registry';
import {DomElementSchemaRegistry} from './schema/dom_element_schema_registry';
import {UrlResolver, DEFAULT_PACKAGE_URL_PROVIDER} from './url_resolver';
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 _createCompilerConfig() {
return new CompilerConfig(assertionsEnabled(), false, true);
}
/**
* A set of providers that provide `RuntimeCompiler` and its dependencies to use for
* template compilation.
*/
export const COMPILER_PROVIDERS: Array<any | Type | {[k: string]: any} | any[]> =
/*@ts2dart_const*/[
Lexer,
Parser,
HtmlParser,
TemplateParser,
DirectiveNormalizer,
CompileMetadataResolver,
DEFAULT_PACKAGE_URL_PROVIDER,
StyleCompiler,
ViewCompiler,
/*@ts2dart_Provider*/ {provide: CompilerConfig, useFactory: _createCompilerConfig, deps: []},
RuntimeCompiler,
/*@ts2dart_Provider*/ {provide: ComponentResolver, useExisting: RuntimeCompiler},
DomElementSchemaRegistry,
/*@ts2dart_Provider*/ {provide: ElementSchemaRegistry, useExisting: DomElementSchemaRegistry},
UrlResolver,
ViewResolver,
DirectiveResolver,
PipeResolver
];

View File

@ -1,38 +0,0 @@
import {isBlank} from '../src/facade/lang';
import {unimplemented} from '../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;
}

View File

@ -1,756 +0,0 @@
import {NumberWrapper, StringWrapper, isPresent, resolveEnumToken} from '../../src/facade/lang';
import {BaseException} from '../../src/facade/exceptions';
import {
isWhitespace,
$EOF,
$HASH,
$TILDA,
$CARET,
$PERCENT,
$$,
$_,
$COLON,
$SQ,
$DQ,
$EQ,
$SLASH,
$BACKSLASH,
$PERIOD,
$STAR,
$PLUS,
$LPAREN,
$RPAREN,
$LBRACE,
$RBRACE,
$LBRACKET,
$RBRACKET,
$PIPE,
$COMMA,
$SEMICOLON,
$MINUS,
$BANG,
$QUESTION,
$AT,
$AMPERSAND,
$GT,
$a,
$A,
$z,
$Z,
$0,
$9,
$FF,
$CR,
$LF,
$VTAB
} from '@angular/compiler/src/chars';
export {
$EOF,
$AT,
$RBRACE,
$LBRACE,
$LBRACKET,
$RBRACKET,
$LPAREN,
$RPAREN,
$COMMA,
$COLON,
$SEMICOLON,
isWhitespace
} from '@angular/compiler/src/chars';
export enum CssTokenType {
EOF,
String,
Comment,
Identifier,
Number,
IdentifierOrNumber,
AtKeyword,
Character,
Whitespace,
Invalid
}
export enum CssLexerMode {
ALL,
ALL_TRACK_WS,
SELECTOR,
PSEUDO_SELECTOR,
ATTRIBUTE_SELECTOR,
AT_RULE_QUERY,
MEDIA_QUERY,
BLOCK,
KEYFRAME_BLOCK,
STYLE_BLOCK,
STYLE_VALUE,
STYLE_VALUE_FUNCTION,
STYLE_CALC_FUNCTION
}
export class LexedCssResult {
constructor(public error: CssScannerError, public token: CssToken) {}
}
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: string, errorValue: string, index: number,
column: number): string {
var endOfProblemLine = index;
var current = charCode(input, index);
while (current > 0 && !isNewline(current)) {
current = charCode(input, ++endOfProblemLine);
}
var choppedString = input.substring(0, endOfProblemLine);
var pointerPadding = "";
for (var i = 0; i < column; i++) {
pointerPadding += " ";
}
var pointerString = "";
for (var i = 0; i < errorValue.length; i++) {
pointerString += "^";
}
return choppedString + "\n" + pointerPadding + pointerString + "\n";
}
export class CssToken {
numValue: number;
constructor(public index: number, public column: number, public line: number,
public type: CssTokenType, public strValue: string) {
this.numValue = charCode(strValue, 0);
}
}
export class CssLexer {
scan(text: string, trackComments: boolean = false): CssScanner {
return new CssScanner(text, trackComments);
}
}
export class CssScannerError extends BaseException {
public rawMessage: string;
public message: string;
constructor(public token: CssToken, message) {
super('Css Parse Error: ' + message);
this.rawMessage = message;
}
toString(): string { return this.message; }
}
function _trackWhitespace(mode: CssLexerMode) {
switch (mode) {
case CssLexerMode.SELECTOR:
case CssLexerMode.ALL_TRACK_WS:
case CssLexerMode.STYLE_VALUE:
return true;
default:
return false;
}
}
export class CssScanner {
peek: number;
peekPeek: number;
length: number = 0;
index: number = -1;
column: number = -1;
line: number = 0;
/** @internal */
_currentMode: CssLexerMode = CssLexerMode.BLOCK;
/** @internal */
_currentError: CssScannerError = null;
constructor(public input: string, private _trackComments: boolean = false) {
this.length = this.input.length;
this.peekPeek = this.peekAt(0);
this.advance();
}
getMode(): CssLexerMode { return this._currentMode; }
setMode(mode: CssLexerMode) {
if (this._currentMode != mode) {
if (_trackWhitespace(this._currentMode)) {
this.consumeWhitespace();
}
this._currentMode = mode;
}
}
advance(): void {
if (isNewline(this.peek)) {
this.column = 0;
this.line++;
} else {
this.column++;
}
this.index++;
this.peek = this.peekPeek;
this.peekPeek = this.peekAt(this.index + 1);
}
peekAt(index: number): number {
return index >= this.length ? $EOF : StringWrapper.charCodeAt(this.input, index);
}
consumeEmptyStatements(): void {
this.consumeWhitespace();
while (this.peek == $SEMICOLON) {
this.advance();
this.consumeWhitespace();
}
}
consumeWhitespace(): void {
while (isWhitespace(this.peek) || isNewline(this.peek)) {
this.advance();
if (!this._trackComments && isCommentStart(this.peek, this.peekPeek)) {
this.advance(); // /
this.advance(); // *
while (!isCommentEnd(this.peek, this.peekPeek)) {
if (this.peek == $EOF) {
this.error('Unterminated comment');
}
this.advance();
}
this.advance(); // *
this.advance(); // /
}
}
}
consume(type: CssTokenType, value: string = null): LexedCssResult {
var mode = this._currentMode;
this.setMode(CssLexerMode.ALL);
var previousIndex = this.index;
var previousLine = this.line;
var previousColumn = this.column;
var output = this.scan();
// just incase the inner scan method returned an error
if (isPresent(output.error)) {
this.setMode(mode);
return output;
}
var next = output.token;
if (!isPresent(next)) {
next = new CssToken(0, 0, 0, CssTokenType.EOF, "end of file");
}
var isMatchingType;
if (type == CssTokenType.IdentifierOrNumber) {
// TODO (matsko): implement array traversal for lookup here
isMatchingType = next.type == CssTokenType.Number || next.type == CssTokenType.Identifier;
} else {
isMatchingType = next.type == type;
}
// before throwing the error we need to bring back the former
// mode so that the parser can recover...
this.setMode(mode);
var error = null;
if (!isMatchingType || (isPresent(value) && value != next.strValue)) {
var errorMessage = resolveEnumToken(CssTokenType, next.type) + " does not match expected " +
resolveEnumToken(CssTokenType, type) + " value";
if (isPresent(value)) {
errorMessage += ' ("' + next.strValue + '" should match "' + value + '")';
}
error = new CssScannerError(
next, generateErrorMessage(this.input, errorMessage, next.strValue, previousIndex,
previousLine, previousColumn));
}
return new LexedCssResult(error, next);
}
scan(): LexedCssResult {
var trackWS = _trackWhitespace(this._currentMode);
if (this.index == 0 && !trackWS) { // first scan
this.consumeWhitespace();
}
var token = this._scan();
if (token == null) return null;
var error = this._currentError;
this._currentError = null;
if (!trackWS) {
this.consumeWhitespace();
}
return new LexedCssResult(error, token);
}
/** @internal */
_scan(): CssToken {
var peek = this.peek;
var peekPeek = this.peekPeek;
if (peek == $EOF) return null;
if (isCommentStart(peek, peekPeek)) {
// even if comments are not tracked we still lex the
// comment so we can move the pointer forward
var commentToken = this.scanComment();
if (this._trackComments) {
return commentToken;
}
}
if (_trackWhitespace(this._currentMode) && (isWhitespace(peek) || isNewline(peek))) {
return this.scanWhitespace();
}
peek = this.peek;
peekPeek = this.peekPeek;
if (peek == $EOF) return null;
if (isStringStart(peek, peekPeek)) {
return this.scanString();
}
// something like url(cool)
if (this._currentMode == CssLexerMode.STYLE_VALUE_FUNCTION) {
return this.scanCssValueFunction();
}
var isModifier = peek == $PLUS || peek == $MINUS;
var digitA = isModifier ? false : isDigit(peek);
var digitB = isDigit(peekPeek);
if (digitA || (isModifier && (peekPeek == $PERIOD || digitB)) || (peek == $PERIOD && digitB)) {
return this.scanNumber();
}
if (peek == $AT) {
return this.scanAtExpression();
}
if (isIdentifierStart(peek, peekPeek)) {
return this.scanIdentifier();
}
if (isValidCssCharacter(peek, this._currentMode)) {
return this.scanCharacter();
}
return this.error(`Unexpected character [${StringWrapper.fromCharCode(peek)}]`);
}
scanComment(): CssToken {
if (this.assertCondition(isCommentStart(this.peek, this.peekPeek),
"Expected comment start value")) {
return null;
}
var start = this.index;
var startingColumn = this.column;
var startingLine = this.line;
this.advance(); // /
this.advance(); // *
while (!isCommentEnd(this.peek, this.peekPeek)) {
if (this.peek == $EOF) {
this.error('Unterminated comment');
}
this.advance();
}
this.advance(); // *
this.advance(); // /
var str = this.input.substring(start, this.index);
return new CssToken(start, startingColumn, startingLine, CssTokenType.Comment, str);
}
scanWhitespace(): CssToken {
var start = this.index;
var startingColumn = this.column;
var startingLine = this.line;
while (isWhitespace(this.peek) && this.peek != $EOF) {
this.advance();
}
var str = this.input.substring(start, this.index);
return new CssToken(start, startingColumn, startingLine, CssTokenType.Whitespace, str);
}
scanString(): CssToken {
if (this.assertCondition(isStringStart(this.peek, this.peekPeek),
"Unexpected non-string starting value")) {
return null;
}
var target = this.peek;
var start = this.index;
var startingColumn = this.column;
var startingLine = this.line;
var previous = target;
this.advance();
while (!isCharMatch(target, previous, this.peek)) {
if (this.peek == $EOF || isNewline(this.peek)) {
this.error('Unterminated quote');
}
previous = this.peek;
this.advance();
}
if (this.assertCondition(this.peek == target, "Unterminated quote")) {
return null;
}
this.advance();
var str = this.input.substring(start, this.index);
return new CssToken(start, startingColumn, startingLine, CssTokenType.String, str);
}
scanNumber(): CssToken {
var start = this.index;
var startingColumn = this.column;
if (this.peek == $PLUS || this.peek == $MINUS) {
this.advance();
}
var periodUsed = false;
while (isDigit(this.peek) || this.peek == $PERIOD) {
if (this.peek == $PERIOD) {
if (periodUsed) {
this.error('Unexpected use of a second period value');
}
periodUsed = true;
}
this.advance();
}
var strValue = this.input.substring(start, this.index);
return new CssToken(start, startingColumn, this.line, CssTokenType.Number, strValue);
}
scanIdentifier(): CssToken {
if (this.assertCondition(isIdentifierStart(this.peek, this.peekPeek),
'Expected identifier starting value')) {
return null;
}
var start = this.index;
var startingColumn = this.column;
while (isIdentifierPart(this.peek)) {
this.advance();
}
var strValue = this.input.substring(start, this.index);
return new CssToken(start, startingColumn, this.line, CssTokenType.Identifier, strValue);
}
scanCssValueFunction(): CssToken {
var start = this.index;
var startingColumn = this.column;
while (this.peek != $EOF && this.peek != $RPAREN) {
this.advance();
}
var strValue = this.input.substring(start, this.index);
return new CssToken(start, startingColumn, this.line, CssTokenType.Identifier, strValue);
}
scanCharacter(): CssToken {
var start = this.index;
var startingColumn = this.column;
if (this.assertCondition(isValidCssCharacter(this.peek, this._currentMode),
charStr(this.peek) + ' is not a valid CSS character')) {
return null;
}
var c = this.input.substring(start, start + 1);
this.advance();
return new CssToken(start, startingColumn, this.line, CssTokenType.Character, c);
}
scanAtExpression(): CssToken {
if (this.assertCondition(this.peek == $AT, 'Expected @ value')) {
return null;
}
var start = this.index;
var startingColumn = this.column;
this.advance();
if (isIdentifierStart(this.peek, this.peekPeek)) {
var ident = this.scanIdentifier();
var strValue = '@' + ident.strValue;
return new CssToken(start, startingColumn, this.line, CssTokenType.AtKeyword, strValue);
} else {
return this.scanCharacter();
}
}
assertCondition(status: boolean, errorMessage: string): boolean {
if (!status) {
this.error(errorMessage);
return true;
}
return false;
}
error(message: string, errorTokenValue: string = null, doNotAdvance: boolean = false): CssToken {
var index: number = this.index;
var column: number = this.column;
var line: number = this.line;
errorTokenValue =
isPresent(errorTokenValue) ? errorTokenValue : StringWrapper.fromCharCode(this.peek);
var invalidToken = new CssToken(index, column, line, CssTokenType.Invalid, errorTokenValue);
var errorMessage =
generateErrorMessage(this.input, message, errorTokenValue, index, line, column);
if (!doNotAdvance) {
this.advance();
}
this._currentError = new CssScannerError(invalidToken, errorMessage);
return invalidToken;
}
}
function isAtKeyword(current: CssToken, next: CssToken): boolean {
return current.numValue == $AT && next.type == CssTokenType.Identifier;
}
function isCharMatch(target: number, previous: number, code: number): boolean {
return code == target && previous != $BACKSLASH;
}
function isDigit(code: number): boolean {
return $0 <= code && code <= $9;
}
function isCommentStart(code: number, next: number): boolean {
return code == $SLASH && next == $STAR;
}
function isCommentEnd(code: number, next: number): boolean {
return code == $STAR && next == $SLASH;
}
function isStringStart(code: number, next: number): boolean {
var target = code;
if (target == $BACKSLASH) {
target = next;
}
return target == $DQ || target == $SQ;
}
function isIdentifierStart(code: number, next: number): boolean {
var target = code;
if (target == $MINUS) {
target = next;
}
return ($a <= target && target <= $z) || ($A <= target && target <= $Z) || target == $BACKSLASH ||
target == $MINUS || target == $_;
}
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): boolean {
switch (code) {
case $LPAREN:
case $RPAREN:
return true;
default:
return false;
}
}
function isValidKeyframeBlockCharacter(code: number): boolean {
return code == $PERCENT;
}
function isValidAttributeSelectorCharacter(code: number): boolean {
// value^*|$~=something
switch (code) {
case $$:
case $PIPE:
case $CARET:
case $TILDA:
case $STAR:
case $EQ:
return true;
default:
return false;
}
}
function isValidSelectorCharacter(code: number): boolean {
// selector [ key = value ]
// IDENT C IDENT C IDENT C
// #id, .class, *+~>
// tag:PSEUDO
switch (code) {
case $HASH:
case $PERIOD:
case $TILDA:
case $STAR:
case $PLUS:
case $GT:
case $COLON:
case $PIPE:
case $COMMA:
return true;
default:
return false;
}
}
function isValidStyleBlockCharacter(code: number): boolean {
// key:value;
// key:calc(something ... )
switch (code) {
case $HASH:
case $SEMICOLON:
case $COLON:
case $PERCENT:
case $SLASH:
case $BACKSLASH:
case $BANG:
case $PERIOD:
case $LPAREN:
case $RPAREN:
return true;
default:
return false;
}
}
function isValidMediaQueryRuleCharacter(code: number): boolean {
// (min-width: 7.5em) and (orientation: landscape)
switch (code) {
case $LPAREN:
case $RPAREN:
case $COLON:
case $PERCENT:
case $PERIOD:
return true;
default:
return false;
}
}
function isValidAtRuleCharacter(code: number): boolean {
// @document url(http://www.w3.org/page?something=on#hash),
switch (code) {
case $LPAREN:
case $RPAREN:
case $COLON:
case $PERCENT:
case $PERIOD:
case $SLASH:
case $BACKSLASH:
case $HASH:
case $EQ:
case $QUESTION:
case $AMPERSAND:
case $STAR:
case $COMMA:
case $MINUS:
case $PLUS:
return true;
default:
return false;
}
}
function isValidStyleFunctionCharacter(code: number): boolean {
switch (code) {
case $PERIOD:
case $MINUS:
case $PLUS:
case $STAR:
case $SLASH:
case $LPAREN:
case $RPAREN:
case $COMMA:
return true;
default:
return false;
}
}
function isValidBlockCharacter(code: number): boolean {
// @something { }
// IDENT
return code == $AT;
}
function isValidCssCharacter(code: number, mode: CssLexerMode): boolean {
switch (mode) {
case CssLexerMode.ALL:
case CssLexerMode.ALL_TRACK_WS:
return true;
case CssLexerMode.SELECTOR:
return isValidSelectorCharacter(code);
case CssLexerMode.PSEUDO_SELECTOR:
return isValidPseudoSelectorCharacter(code);
case CssLexerMode.ATTRIBUTE_SELECTOR:
return isValidAttributeSelectorCharacter(code);
case CssLexerMode.MEDIA_QUERY:
return isValidMediaQueryRuleCharacter(code);
case CssLexerMode.AT_RULE_QUERY:
return isValidAtRuleCharacter(code);
case CssLexerMode.KEYFRAME_BLOCK:
return isValidKeyframeBlockCharacter(code);
case CssLexerMode.STYLE_BLOCK:
case CssLexerMode.STYLE_VALUE:
return isValidStyleBlockCharacter(code);
case CssLexerMode.STYLE_CALC_FUNCTION:
return isValidStyleFunctionCharacter(code);
case CssLexerMode.BLOCK:
return isValidBlockCharacter(code);
default:
return false;
}
}
function charCode(input, index): number {
return index >= input.length ? $EOF : StringWrapper.charCodeAt(input, index);
}
function charStr(code: number): string {
return StringWrapper.fromCharCode(code);
}
export function isNewline(code): boolean {
switch (code) {
case $FF:
case $CR:
case $LF:
case $VTAB:
return true;
default:
return false;
}
}

View File

@ -1,740 +0,0 @@
import {
ParseSourceSpan,
ParseSourceFile,
ParseLocation,
ParseError
} from '@angular/compiler/src/parse_util';
import {
bitWiseOr,
bitWiseAnd,
NumberWrapper,
StringWrapper,
isPresent
} from '../../src/facade/lang';
import {
CssLexerMode,
CssToken,
CssTokenType,
CssScanner,
CssScannerError,
generateErrorMessage,
$AT,
$EOF,
$RBRACE,
$LBRACE,
$LBRACKET,
$RBRACKET,
$LPAREN,
$RPAREN,
$COMMA,
$COLON,
$SEMICOLON,
isNewline
} from '@angular/compiler/src/css/lexer';
export {CssToken} from '@angular/compiler/src/css/lexer';
export enum BlockType {
Import,
Charset,
Namespace,
Supports,
Keyframes,
MediaQuery,
Selector,
FontFace,
Page,
Document,
Viewport,
Unsupported
}
const EOF_DELIM = 1;
const RBRACE_DELIM = 2;
const LBRACE_DELIM = 4;
const COMMA_DELIM = 8;
const COLON_DELIM = 16;
const SEMICOLON_DELIM = 32;
const NEWLINE_DELIM = 64;
const RPAREN_DELIM = 128;
function mergeTokens(tokens: CssToken[], separator: string = ""): CssToken {
var mainToken = tokens[0];
var str = mainToken.strValue;
for (var i = 1; i < tokens.length; i++) {
str += separator + tokens[i].strValue;
}
return new CssToken(mainToken.index, mainToken.column, mainToken.line, mainToken.type, str);
}
function getDelimFromToken(token: CssToken): number {
return getDelimFromCharacter(token.numValue);
}
function getDelimFromCharacter(code: number): number {
switch (code) {
case $EOF:
return EOF_DELIM;
case $COMMA:
return COMMA_DELIM;
case $COLON:
return COLON_DELIM;
case $SEMICOLON:
return SEMICOLON_DELIM;
case $RBRACE:
return RBRACE_DELIM;
case $LBRACE:
return LBRACE_DELIM;
case $RPAREN:
return RPAREN_DELIM;
default:
return isNewline(code) ? NEWLINE_DELIM : 0;
}
}
function characterContainsDelimiter(code: number, delimiters: number): boolean {
return bitWiseAnd([getDelimFromCharacter(code), delimiters]) > 0;
}
export class CssAST {
visit(visitor: CssASTVisitor, context?: any): void {}
}
export interface CssASTVisitor {
visitCssValue(ast: CssStyleValueAST, context?: any): void;
visitInlineCssRule(ast: CssInlineRuleAST, context?: any): void;
visitCssKeyframeRule(ast: CssKeyframeRuleAST, context?: any): void;
visitCssKeyframeDefinition(ast: CssKeyframeDefinitionAST, context?: any): void;
visitCssMediaQueryRule(ast: CssMediaQueryRuleAST, context?: any): void;
visitCssSelectorRule(ast: CssSelectorRuleAST, context?: any): void;
visitCssSelector(ast: CssSelectorAST, context?: any): void;
visitCssDefinition(ast: CssDefinitionAST, context?: any): void;
visitCssBlock(ast: CssBlockAST, context?: any): void;
visitCssStyleSheet(ast: CssStyleSheetAST, context?: any): void;
visitUnkownRule(ast: CssUnknownTokenListAST, context?: any): void;
}
export class ParsedCssResult {
constructor(public errors: CssParseError[], public ast: CssStyleSheetAST) {}
}
export class CssParser {
private _errors: CssParseError[] = [];
private _file: ParseSourceFile;
constructor(private _scanner: CssScanner, private _fileName: string) {
this._file = new ParseSourceFile(this._scanner.input, _fileName);
}
/** @internal */
_resolveBlockType(token: CssToken): BlockType {
switch (token.strValue) {
case '@-o-keyframes':
case '@-moz-keyframes':
case '@-webkit-keyframes':
case '@keyframes':
return BlockType.Keyframes;
case '@charset':
return BlockType.Charset;
case '@import':
return BlockType.Import;
case '@namespace':
return BlockType.Namespace;
case '@page':
return BlockType.Page;
case '@document':
return BlockType.Document;
case '@media':
return BlockType.MediaQuery;
case '@font-face':
return BlockType.FontFace;
case '@viewport':
return BlockType.Viewport;
case '@supports':
return BlockType.Supports;
default:
return BlockType.Unsupported;
}
}
parse(): ParsedCssResult {
var delimiters: number = EOF_DELIM;
var ast = this._parseStyleSheet(delimiters);
var errors = this._errors;
this._errors = [];
return new ParsedCssResult(errors, ast);
}
/** @internal */
_parseStyleSheet(delimiters): CssStyleSheetAST {
var results = [];
this._scanner.consumeEmptyStatements();
while (this._scanner.peek != $EOF) {
this._scanner.setMode(CssLexerMode.BLOCK);
results.push(this._parseRule(delimiters));
}
return new CssStyleSheetAST(results);
}
/** @internal */
_parseRule(delimiters: number): CssRuleAST {
if (this._scanner.peek == $AT) {
return this._parseAtRule(delimiters);
}
return this._parseSelectorRule(delimiters);
}
/** @internal */
_parseAtRule(delimiters: number): CssRuleAST {
this._scanner.setMode(CssLexerMode.BLOCK);
var token = this._scan();
this._assertCondition(token.type == CssTokenType.AtKeyword,
`The CSS Rule ${token.strValue} is not a valid [@] rule.`, token);
var block, type = this._resolveBlockType(token);
switch (type) {
case BlockType.Charset:
case BlockType.Namespace:
case BlockType.Import:
var value = this._parseValue(delimiters);
this._scanner.setMode(CssLexerMode.BLOCK);
this._scanner.consumeEmptyStatements();
return new CssInlineRuleAST(type, value);
case BlockType.Viewport:
case BlockType.FontFace:
block = this._parseStyleBlock(delimiters);
return new CssBlockRuleAST(type, block);
case BlockType.Keyframes:
var tokens = this._collectUntilDelim(bitWiseOr([delimiters, RBRACE_DELIM, LBRACE_DELIM]));
// keyframes only have one identifier name
var name = tokens[0];
return new CssKeyframeRuleAST(name, this._parseKeyframeBlock(delimiters));
case BlockType.MediaQuery:
this._scanner.setMode(CssLexerMode.MEDIA_QUERY);
var tokens = this._collectUntilDelim(bitWiseOr([delimiters, RBRACE_DELIM, LBRACE_DELIM]));
return new CssMediaQueryRuleAST(tokens, this._parseBlock(delimiters));
case BlockType.Document:
case BlockType.Supports:
case BlockType.Page:
this._scanner.setMode(CssLexerMode.AT_RULE_QUERY);
var tokens = this._collectUntilDelim(bitWiseOr([delimiters, RBRACE_DELIM, LBRACE_DELIM]));
return new CssBlockDefinitionRuleAST(type, tokens, this._parseBlock(delimiters));
// if a custom @rule { ... } is used it should still tokenize the insides
default:
var listOfTokens = [];
this._scanner.setMode(CssLexerMode.ALL);
this._error(generateErrorMessage(
this._scanner.input,
`The CSS "at" rule "${token.strValue}" is not allowed to used here`,
token.strValue, token.index, token.line, token.column),
token);
this._collectUntilDelim(bitWiseOr([delimiters, LBRACE_DELIM, SEMICOLON_DELIM]))
.forEach((token) => { listOfTokens.push(token); });
if (this._scanner.peek == $LBRACE) {
this._consume(CssTokenType.Character, '{');
this._collectUntilDelim(bitWiseOr([delimiters, RBRACE_DELIM, LBRACE_DELIM]))
.forEach((token) => { listOfTokens.push(token); });
this._consume(CssTokenType.Character, '}');
}
return new CssUnknownTokenListAST(token, listOfTokens);
}
}
/** @internal */
_parseSelectorRule(delimiters: number): CssSelectorRuleAST {
var selectors = this._parseSelectors(delimiters);
var block = this._parseStyleBlock(delimiters);
this._scanner.setMode(CssLexerMode.BLOCK);
this._scanner.consumeEmptyStatements();
return new CssSelectorRuleAST(selectors, block);
}
/** @internal */
_parseSelectors(delimiters: number): CssSelectorAST[] {
delimiters = bitWiseOr([delimiters, LBRACE_DELIM]);
var selectors = [];
var isParsingSelectors = true;
while (isParsingSelectors) {
selectors.push(this._parseSelector(delimiters));
isParsingSelectors = !characterContainsDelimiter(this._scanner.peek, delimiters);
if (isParsingSelectors) {
this._consume(CssTokenType.Character, ',');
isParsingSelectors = !characterContainsDelimiter(this._scanner.peek, delimiters);
}
}
return selectors;
}
/** @internal */
_scan(): CssToken {
var output = this._scanner.scan();
var token = output.token;
var error = output.error;
if (isPresent(error)) {
this._error(error.rawMessage, token);
}
return token;
}
/** @internal */
_consume(type: CssTokenType, value: string = null): CssToken {
var output = this._scanner.consume(type, value);
var token = output.token;
var error = output.error;
if (isPresent(error)) {
this._error(error.rawMessage, token);
}
return token;
}
/** @internal */
_parseKeyframeBlock(delimiters: number): CssBlockAST {
delimiters = bitWiseOr([delimiters, RBRACE_DELIM]);
this._scanner.setMode(CssLexerMode.KEYFRAME_BLOCK);
this._consume(CssTokenType.Character, '{');
var definitions = [];
while (!characterContainsDelimiter(this._scanner.peek, delimiters)) {
definitions.push(this._parseKeyframeDefinition(delimiters));
}
this._consume(CssTokenType.Character, '}');
return new CssBlockAST(definitions);
}
/** @internal */
_parseKeyframeDefinition(delimiters: number): CssKeyframeDefinitionAST {
var stepTokens = [];
delimiters = bitWiseOr([delimiters, LBRACE_DELIM]);
while (!characterContainsDelimiter(this._scanner.peek, delimiters)) {
stepTokens.push(this._parseKeyframeLabel(bitWiseOr([delimiters, COMMA_DELIM])));
if (this._scanner.peek != $LBRACE) {
this._consume(CssTokenType.Character, ',');
}
}
var styles = this._parseStyleBlock(bitWiseOr([delimiters, RBRACE_DELIM]));
this._scanner.setMode(CssLexerMode.BLOCK);
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);
var selectorCssTokens = [];
var isComplex = false;
var wsCssToken;
var previousToken;
var parenCount = 0;
while (!characterContainsDelimiter(this._scanner.peek, delimiters)) {
var code = this._scanner.peek;
switch (code) {
case $LPAREN:
parenCount++;
break;
case $RPAREN:
parenCount--;
break;
case $COLON:
this._scanner.setMode(CssLexerMode.PSEUDO_SELECTOR);
previousToken = this._consume(CssTokenType.Character, ':');
selectorCssTokens.push(previousToken);
continue;
case $LBRACKET:
// if we are already inside an attribute selector then we can't
// jump into the mode again. Therefore this error will get picked
// up when the scan method is called below.
if (this._scanner.getMode() != CssLexerMode.ATTRIBUTE_SELECTOR) {
selectorCssTokens.push(this._consume(CssTokenType.Character, '['));
this._scanner.setMode(CssLexerMode.ATTRIBUTE_SELECTOR);
continue;
}
break;
case $RBRACKET:
selectorCssTokens.push(this._consume(CssTokenType.Character, ']'));
this._scanner.setMode(CssLexerMode.SELECTOR);
continue;
}
var token = this._scan();
// special case for the ":not(" selector since it
// contains an inner selector that needs to be parsed
// in isolation
if (this._scanner.getMode() == CssLexerMode.PSEUDO_SELECTOR && isPresent(previousToken) &&
previousToken.numValue == $COLON && token.strValue == "not" &&
this._scanner.peek == $LPAREN) {
selectorCssTokens.push(token);
selectorCssTokens.push(this._consume(CssTokenType.Character, '('));
// the inner selector inside of :not(...) can only be one
// CSS selector (no commas allowed) therefore we parse only
// one selector by calling the method below
this._parseSelector(bitWiseOr([delimiters, RPAREN_DELIM]))
.tokens.forEach(
(innerSelectorToken) => { selectorCssTokens.push(innerSelectorToken); });
selectorCssTokens.push(this._consume(CssTokenType.Character, ')'));
continue;
}
previousToken = token;
if (token.type == CssTokenType.Whitespace) {
wsCssToken = token;
} else {
if (isPresent(wsCssToken)) {
selectorCssTokens.push(wsCssToken);
wsCssToken = null;
isComplex = true;
}
selectorCssTokens.push(token);
}
}
if (this._scanner.getMode() == CssLexerMode.ATTRIBUTE_SELECTOR) {
this._error(
`Unbalanced CSS attribute selector at column ${previousToken.line}:${previousToken.column}`,
previousToken);
} else if (parenCount > 0) {
this._error(
`Unbalanced pseudo selector function value at column ${previousToken.line}:${previousToken.column}`,
previousToken);
}
return new CssSelectorAST(selectorCssTokens, isComplex);
}
/** @internal */
_parseValue(delimiters: number): CssStyleValueAST {
delimiters = bitWiseOr([delimiters, RBRACE_DELIM, SEMICOLON_DELIM, NEWLINE_DELIM]);
this._scanner.setMode(CssLexerMode.STYLE_VALUE);
var strValue = "";
var tokens = [];
var previous: CssToken;
while (!characterContainsDelimiter(this._scanner.peek, delimiters)) {
var token;
if (isPresent(previous) && previous.type == CssTokenType.Identifier &&
this._scanner.peek == $LPAREN) {
token = this._consume(CssTokenType.Character, '(');
tokens.push(token);
strValue += token.strValue;
this._scanner.setMode(CssLexerMode.STYLE_VALUE_FUNCTION);
token = this._scan();
tokens.push(token);
strValue += token.strValue;
this._scanner.setMode(CssLexerMode.STYLE_VALUE);
token = this._consume(CssTokenType.Character, ')');
tokens.push(token);
strValue += token.strValue;
} else {
token = this._scan();
if (token.type != CssTokenType.Whitespace) {
tokens.push(token);
}
strValue += token.strValue;
}
previous = token;
}
this._scanner.consumeWhitespace();
var code = this._scanner.peek;
if (code == $SEMICOLON) {
this._consume(CssTokenType.Character, ';');
} else if (code != $RBRACE) {
this._error(
generateErrorMessage(this._scanner.input,
`The CSS key/value definition did not end with a semicolon`,
previous.strValue, previous.index, previous.line, previous.column),
previous);
}
return new CssStyleValueAST(tokens, strValue);
}
/** @internal */
_collectUntilDelim(delimiters: number, assertType: CssTokenType = null): CssToken[] {
var tokens = [];
while (!characterContainsDelimiter(this._scanner.peek, delimiters)) {
var val = isPresent(assertType) ? this._consume(assertType) : this._scan();
tokens.push(val);
}
return tokens;
}
/** @internal */
_parseBlock(delimiters: number): CssBlockAST {
delimiters = bitWiseOr([delimiters, RBRACE_DELIM]);
this._scanner.setMode(CssLexerMode.BLOCK);
this._consume(CssTokenType.Character, '{');
this._scanner.consumeEmptyStatements();
var results = [];
while (!characterContainsDelimiter(this._scanner.peek, delimiters)) {
results.push(this._parseRule(delimiters));
}
this._consume(CssTokenType.Character, '}');
this._scanner.setMode(CssLexerMode.BLOCK);
this._scanner.consumeEmptyStatements();
return new CssBlockAST(results);
}
/** @internal */
_parseStyleBlock(delimiters: number): CssBlockAST {
delimiters = bitWiseOr([delimiters, RBRACE_DELIM, LBRACE_DELIM]);
this._scanner.setMode(CssLexerMode.STYLE_BLOCK);
this._consume(CssTokenType.Character, '{');
this._scanner.consumeEmptyStatements();
var definitions = [];
while (!characterContainsDelimiter(this._scanner.peek, delimiters)) {
definitions.push(this._parseDefinition(delimiters));
this._scanner.consumeEmptyStatements();
}
this._consume(CssTokenType.Character, '}');
this._scanner.setMode(CssLexerMode.STYLE_BLOCK);
this._scanner.consumeEmptyStatements();
return new CssBlockAST(definitions);
}
/** @internal */
_parseDefinition(delimiters: number): CssDefinitionAST {
this._scanner.setMode(CssLexerMode.STYLE_BLOCK);
var prop = this._consume(CssTokenType.Identifier);
var parseValue, value = null;
// the colon value separates the prop from the style.
// there are a few cases as to what could happen if it
// is missing
switch (this._scanner.peek) {
case $COLON:
this._consume(CssTokenType.Character, ':');
parseValue = true;
break;
case $SEMICOLON:
case $RBRACE:
case $EOF:
parseValue = false;
break;
default:
var propStr = [prop.strValue];
if (this._scanner.peek != $COLON) {
// this will throw the error
var nextValue = this._consume(CssTokenType.Character, ':');
propStr.push(nextValue.strValue);
var remainingTokens = this._collectUntilDelim(
bitWiseOr([delimiters, COLON_DELIM, SEMICOLON_DELIM]), CssTokenType.Identifier);
if (remainingTokens.length > 0) {
remainingTokens.forEach((token) => { propStr.push(token.strValue); });
}
prop = new CssToken(prop.index, prop.column, prop.line, prop.type, propStr.join(" "));
}
// this means we've reached the end of the definition and/or block
if (this._scanner.peek == $COLON) {
this._consume(CssTokenType.Character, ':');
parseValue = true;
} else {
parseValue = false;
}
break;
}
if (parseValue) {
value = this._parseValue(delimiters);
} else {
this._error(generateErrorMessage(this._scanner.input,
`The CSS property was not paired with a style value`,
prop.strValue, prop.index, prop.line, prop.column),
prop);
}
return new CssDefinitionAST(prop, value);
}
/** @internal */
_assertCondition(status: boolean, errorMessage: string, problemToken: CssToken): boolean {
if (!status) {
this._error(errorMessage, problemToken);
return true;
}
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,
message);
this._errors.push(error);
}
}
export class CssStyleValueAST extends CssAST {
constructor(public tokens: CssToken[], public strValue: string) { super(); }
visit(visitor: CssASTVisitor, context?: any) { visitor.visitCssValue(this); }
}
export class CssRuleAST extends CssAST {}
export class CssBlockRuleAST extends CssRuleAST {
constructor(public type: BlockType, public block: CssBlockAST, public name: CssToken = null) {
super();
}
visit(visitor: CssASTVisitor, context?: any) { visitor.visitCssBlock(this.block, context); }
}
export class CssKeyframeRuleAST extends CssBlockRuleAST {
constructor(name: CssToken, block: CssBlockAST) { super(BlockType.Keyframes, block, name); }
visit(visitor: CssASTVisitor, context?: any) { visitor.visitCssKeyframeRule(this, context); }
}
export class CssKeyframeDefinitionAST extends CssBlockRuleAST {
public steps;
constructor(_steps: CssToken[], block: CssBlockAST) {
super(BlockType.Keyframes, block, mergeTokens(_steps, ","));
this.steps = _steps;
}
visit(visitor: CssASTVisitor, context?: any) {
visitor.visitCssKeyframeDefinition(this, context);
}
}
export class CssBlockDefinitionRuleAST extends CssBlockRuleAST {
public strValue: string;
constructor(type: BlockType, public query: CssToken[], block: CssBlockAST) {
super(type, block);
this.strValue = query.map(token => token.strValue).join("");
var firstCssToken: CssToken = query[0];
this.name = new CssToken(firstCssToken.index, firstCssToken.column, firstCssToken.line,
CssTokenType.Identifier, this.strValue);
}
visit(visitor: CssASTVisitor, context?: any) { visitor.visitCssBlock(this.block, context); }
}
export class CssMediaQueryRuleAST extends CssBlockDefinitionRuleAST {
constructor(query: CssToken[], block: CssBlockAST) { super(BlockType.MediaQuery, query, block); }
visit(visitor: CssASTVisitor, context?: any) { visitor.visitCssMediaQueryRule(this, context); }
}
export class CssInlineRuleAST extends CssRuleAST {
constructor(public type: BlockType, public value: CssStyleValueAST) { super(); }
visit(visitor: CssASTVisitor, context?: any) { visitor.visitInlineCssRule(this, context); }
}
export class CssSelectorRuleAST extends CssBlockRuleAST {
public strValue: string;
constructor(public selectors: CssSelectorAST[], block: CssBlockAST) {
super(BlockType.Selector, block);
this.strValue = selectors.map(selector => selector.strValue).join(",");
}
visit(visitor: CssASTVisitor, context?: any) { visitor.visitCssSelectorRule(this, context); }
}
export class CssDefinitionAST extends CssAST {
constructor(public property: CssToken, public value: CssStyleValueAST) { super(); }
visit(visitor: CssASTVisitor, context?: any) { visitor.visitCssDefinition(this, context); }
}
export class CssSelectorAST extends CssAST {
public strValue;
constructor(public tokens: CssToken[], public isComplex: boolean = false) {
super();
this.strValue = tokens.map(token => token.strValue).join("");
}
visit(visitor: CssASTVisitor, context?: any) { visitor.visitCssSelector(this, context); }
}
export class CssBlockAST extends CssAST {
constructor(public entries: CssAST[]) { super(); }
visit(visitor: CssASTVisitor, context?: any) { visitor.visitCssBlock(this, context); }
}
export class CssStyleSheetAST extends CssAST {
constructor(public rules: CssAST[]) { super(); }
visit(visitor: CssASTVisitor, context?: any) { visitor.visitCssStyleSheet(this, context); }
}
export class CssParseError extends ParseError {
static create(file: ParseSourceFile, offset: number, line: number, col: number, length: number,
errMsg: string): CssParseError {
var start = new ParseLocation(file, offset, line, col);
var end = new ParseLocation(file, offset, line, col + length);
var span = new ParseSourceSpan(start, end);
return new CssParseError(span, "CSS Parse Error: " + errMsg);
}
constructor(span: ParseSourceSpan, message: string) { super(span, message); }
}
export class CssUnknownTokenListAST extends CssRuleAST {
constructor(public name, public tokens: CssToken[]) { super(); }
visit(visitor: CssASTVisitor, context?: any) { visitor.visitUnkownRule(this, context); }
}

View File

@ -1,348 +0,0 @@
import {ListWrapper} from '../../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);
}
}

View File

@ -1 +0,0 @@
../../facade/src

View File

@ -1,68 +0,0 @@
import {isPresent} from '../src/facade/lang';
import {ParseSourceSpan} from './parse_util';
export interface HtmlAst {
sourceSpan: ParseSourceSpan;
visit(visitor: HtmlAstVisitor, context: any): any;
}
export class HtmlTextAst implements HtmlAst {
constructor(public value: string, public sourceSpan: ParseSourceSpan) {}
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); }
}
export class HtmlElementAst implements HtmlAst {
constructor(public name: string, public attrs: HtmlAttrAst[], public children: HtmlAst[],
public sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan,
public endSourceSpan: ParseSourceSpan) {}
visit(visitor: HtmlAstVisitor, context: any): any { return visitor.visitElement(this, context); }
}
export class HtmlCommentAst implements HtmlAst {
constructor(public value: string, public sourceSpan: ParseSourceSpan) {}
visit(visitor: HtmlAstVisitor, context: any): any { return visitor.visitComment(this, context); }
}
export interface HtmlAstVisitor {
visitElement(ast: HtmlElementAst, context: any): any;
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[] {
var result = [];
asts.forEach(ast => {
var astResult = ast.visit(visitor, context);
if (isPresent(astResult)) {
result.push(astResult);
}
});
return result;
}

View File

@ -1,116 +0,0 @@
import {
HtmlAst,
HtmlAstVisitor,
HtmlElementAst,
HtmlAttrAst,
HtmlTextAst,
HtmlCommentAst,
HtmlExpansionAst,
HtmlExpansionCaseAst,
htmlVisitAll
} from '../html_ast';
import {BaseException} from '../../src/facade/exceptions';
/**
* Expands special forms into elements.
*
* For example,
*
* ```
* { messages.length, plural,
* =0 {zero}
* =1 {one}
* =other {more than one}
* }
* ```
*
* will be expanded into
*
* ```
* <ul [ngPlural]="messages.length">
* <template [ngPluralCase]="0"><li i18n="plural_0">zero</li></template>
* <template [ngPluralCase]="1"><li i18n="plural_1">one</li></template>
* <template [ngPluralCase]="other"><li i18n="plural_other">more than one</li></template>
* </ul>
* ```
*/
export function expandNodes(nodes: HtmlAst[]): ExpansionResult {
let e = new _Expander();
let n = htmlVisitAll(e, nodes);
return new ExpansionResult(n, e.expanded);
}
export class ExpansionResult {
constructor(public nodes: HtmlAst[], public expanded: boolean) {}
}
class _Expander implements HtmlAstVisitor {
expanded: boolean = false;
constructor() {}
visitElement(ast: HtmlElementAst, context: any): any {
return new HtmlElementAst(ast.name, ast.attrs, htmlVisitAll(this, ast.children), ast.sourceSpan,
ast.startSourceSpan, ast.endSourceSpan);
}
visitAttr(ast: HtmlAttrAst, context: any): any { return ast; }
visitText(ast: HtmlTextAst, context: any): any { return ast; }
visitComment(ast: HtmlCommentAst, context: any): any { return ast; }
visitExpansion(ast: HtmlExpansionAst, context: any): any {
this.expanded = true;
return ast.type == "plural" ? _expandPluralForm(ast) : _expandDefaultForm(ast);
}
visitExpansionCase(ast: HtmlExpansionCaseAst, context: any): any {
throw new BaseException("Should not be reached");
}
}
function _expandPluralForm(ast: HtmlExpansionAst): HtmlElementAst {
let children = ast.cases.map(c => {
let expansionResult = expandNodes(c.expression);
let i18nAttrs = expansionResult.expanded ?
[] :
[new HtmlAttrAst("i18n", `${ast.type}_${c.value}`, c.valueSourceSpan)];
return new HtmlElementAst(`template`,
[
new HtmlAttrAst("ngPluralCase", c.value, c.valueSourceSpan),
],
[
new HtmlElementAst(`li`, i18nAttrs, expansionResult.nodes,
c.sourceSpan, c.sourceSpan, c.sourceSpan)
],
c.sourceSpan, c.sourceSpan, c.sourceSpan);
});
let switchAttr = new HtmlAttrAst("[ngPlural]", ast.switchValue, ast.switchValueSourceSpan);
return new HtmlElementAst("ul", [switchAttr], children, ast.sourceSpan, ast.sourceSpan,
ast.sourceSpan);
}
function _expandDefaultForm(ast: HtmlExpansionAst): HtmlElementAst {
let children = ast.cases.map(c => {
let expansionResult = expandNodes(c.expression);
let i18nAttrs = expansionResult.expanded ?
[] :
[new HtmlAttrAst("i18n", `${ast.type}_${c.value}`, c.valueSourceSpan)];
return new HtmlElementAst(`template`,
[
new HtmlAttrAst("ngSwitchWhen", c.value, c.valueSourceSpan),
],
[
new HtmlElementAst(`li`, i18nAttrs, expansionResult.nodes,
c.sourceSpan, c.sourceSpan, c.sourceSpan)
],
c.sourceSpan, c.sourceSpan, c.sourceSpan);
});
let switchAttr = new HtmlAttrAst("[ngSwitch]", ast.switchValue, ast.switchValueSourceSpan);
return new HtmlElementAst("ul", [switchAttr], children, ast.sourceSpan, ast.sourceSpan,
ast.sourceSpan);
}

View File

@ -1,377 +0,0 @@
import {HtmlParser, HtmlParseTreeResult} from '../html_parser';
import {ParseSourceSpan, ParseError} from '../parse_util';
import {
HtmlAst,
HtmlAstVisitor,
HtmlElementAst,
HtmlAttrAst,
HtmlTextAst,
HtmlCommentAst,
HtmlExpansionAst,
HtmlExpansionCaseAst,
htmlVisitAll
} from '../html_ast';
import {ListWrapper, StringMapWrapper} from '../../src/facade/collection';
import {RegExpWrapper, NumberWrapper, isPresent} from '../../src/facade/lang';
import {BaseException} from '../../src/facade/exceptions';
import {Parser} from '../expression_parser/parser';
import {id} from './message';
import {expandNodes} from './expander';
import {
messageFromAttribute,
I18nError,
I18N_ATTR_PREFIX,
I18N_ATTR,
partition,
Part,
stringifyNodes,
meaning,
getPhNameFromBinding,
dedupePhName
} from './shared';
const _I18N_ATTR = "i18n";
const _PLACEHOLDER_ELEMENT = "ph";
const _NAME_ATTR = "name";
const _I18N_ATTR_PREFIX = "i18n-";
let _PLACEHOLDER_EXPANDED_REGEXP = RegExpWrapper.create(`\\<ph(\\s)+name=("(\\w)+")\\>\\<\\/ph\\>`);
/**
* Creates an i18n-ed version of the parsed template.
*
* Algorithm:
*
* To understand the algorithm, you need to know how partitioning works.
* Partitioning is required as we can use two i18n comments to group node siblings together.
* That is why we cannot just use nodes.
*
* Partitioning transforms an array of HtmlAst into an array of Part.
* A part can optionally contain a root element or a root text node. And it can also contain
* children.
* A part can contain i18n property, in which case it needs to be transalted.
*
* Example:
*
* The following array of nodes will be split into four parts:
*
* ```
* <a>A</a>
* <b i18n>B</b>
* <!-- i18n -->
* <c>C</c>
* D
* <!-- /i18n -->
* E
* ```
*
* Part 1 containing the a tag. It should not be translated.
* Part 2 containing the b tag. It should be translated.
* Part 3 containing the c tag and the D text node. It should be translated.
* Part 4 containing the E text node. It should not be translated.
*
*
* It is also important to understand how we stringify nodes to create a message.
*
* We walk the tree and replace every element node with a placeholder. We also replace
* all expressions in interpolation with placeholders. We also insert a placeholder element
* to wrap a text node containing interpolation.
*
* Example:
*
* The following tree:
*
* ```
* <a>A{{I}}</a><b>B</b>
* ```
*
* will be stringified into:
* ```
* <ph name="e0"><ph name="t1">A<ph name="0"/></ph></ph><ph name="e2">B</ph>
* ```
*
* This is what the algorithm does:
*
* 1. Use the provided html parser to get the html AST of the template.
* 2. Partition the root nodes, and process each part separately.
* 3. If a part does not have the i18n attribute, recurse to process children and attributes.
* 4. If a part has the i18n attribute, merge the translated i18n part with the original tree.
*
* This is how the merging works:
*
* 1. Use the stringify function to get the message id. Look up the message in the map.
* 2. Get the translated message. At this point we have two trees: the original tree
* and the translated tree, where all the elements are replaced with placeholders.
* 3. Use the original tree to create a mapping Index:number -> HtmlAst.
* 4. Walk the translated tree.
* 5. If we encounter a placeholder element, get is name property.
* 6. Get the type and the index of the node using the name property.
* 7. If the type is 'e', which means element, then:
* - translate the attributes of the original element
* - recurse to merge the children
* - create a new element using the original element name, original position,
* and translated children and attributes
* 8. If the type if 't', which means text, then:
* - get the list of expressions from the original node.
* - get the string version of the interpolation subtree
* - find all the placeholders in the translated message, and replace them with the
* corresponding original expressions
*/
export class I18nHtmlParser implements HtmlParser {
errors: ParseError[];
constructor(private _htmlParser: HtmlParser, private _parser: Parser,
private _messagesContent: string, private _messages: {[key: string]: HtmlAst[]}) {}
parse(sourceContent: string, sourceUrl: string,
parseExpansionForms: boolean = false): HtmlParseTreeResult {
this.errors = [];
let res = this._htmlParser.parse(sourceContent, sourceUrl, true);
if (res.errors.length > 0) {
return res;
} else {
let nodes = this._recurse(expandNodes(res.rootNodes).nodes);
return this.errors.length > 0 ? new HtmlParseTreeResult([], this.errors) :
new HtmlParseTreeResult(nodes, []);
}
}
private _processI18nPart(p: Part): HtmlAst[] {
try {
return p.hasI18n ? this._mergeI18Part(p) : this._recurseIntoI18nPart(p);
} catch (e) {
if (e instanceof I18nError) {
this.errors.push(e);
return [];
} else {
throw e;
}
}
}
private _mergeI18Part(p: Part): HtmlAst[] {
let message = p.createMessage(this._parser);
let messageId = id(message);
if (!StringMapWrapper.contains(this._messages, messageId)) {
throw new I18nError(
p.sourceSpan, `Cannot find message for id '${messageId}', content '${message.content}'.`);
}
let parsedMessage = this._messages[messageId];
return this._mergeTrees(p, parsedMessage, p.children);
}
private _recurseIntoI18nPart(p: Part): HtmlAst[] {
// we found an element without an i18n attribute
// we need to recurse in cause its children may have i18n set
// we also need to translate its attributes
if (isPresent(p.rootElement)) {
let root = p.rootElement;
let children = this._recurse(p.children);
let attrs = this._i18nAttributes(root);
return [
new HtmlElementAst(root.name, attrs, children, root.sourceSpan, root.startSourceSpan,
root.endSourceSpan)
];
// a text node without i18n or interpolation, nothing to do
} else if (isPresent(p.rootTextNode)) {
return [p.rootTextNode];
} else {
return this._recurse(p.children);
}
}
private _recurse(nodes: HtmlAst[]): HtmlAst[] {
let ps = partition(nodes, this.errors);
return ListWrapper.flatten(ps.map(p => this._processI18nPart(p)));
}
private _mergeTrees(p: Part, translated: HtmlAst[], original: HtmlAst[]): HtmlAst[] {
let l = new _CreateNodeMapping();
htmlVisitAll(l, original);
// merge the translated tree with the original tree.
// we do it by preserving the source code position of the original tree
let merged = this._mergeTreesHelper(translated, l.mapping);
// if the root element is present, we need to create a new root element with its attributes
// translated
if (isPresent(p.rootElement)) {
let root = p.rootElement;
let attrs = this._i18nAttributes(root);
return [
new HtmlElementAst(root.name, attrs, merged, root.sourceSpan, root.startSourceSpan,
root.endSourceSpan)
];
// this should never happen with a part. Parts that have root text node should not be merged.
} else if (isPresent(p.rootTextNode)) {
throw new BaseException("should not be reached");
} else {
return merged;
}
}
private _mergeTreesHelper(translated: HtmlAst[], mapping: HtmlAst[]): HtmlAst[] {
return translated.map(t => {
if (t instanceof HtmlElementAst) {
return this._mergeElementOrInterpolation(t, translated, mapping);
} else if (t instanceof HtmlTextAst) {
return t;
} else {
throw new BaseException("should not be reached");
}
});
}
private _mergeElementOrInterpolation(t: HtmlElementAst, translated: HtmlAst[],
mapping: HtmlAst[]): HtmlAst {
let name = this._getName(t);
let type = name[0];
let index = NumberWrapper.parseInt(name.substring(1), 10);
let originalNode = mapping[index];
if (type == "t") {
return this._mergeTextInterpolation(t, <HtmlTextAst>originalNode);
} else if (type == "e") {
return this._mergeElement(t, <HtmlElementAst>originalNode, mapping);
} else {
throw new BaseException("should not be reached");
}
}
private _getName(t: HtmlElementAst): string {
if (t.name != _PLACEHOLDER_ELEMENT) {
throw new I18nError(
t.sourceSpan,
`Unexpected tag "${t.name}". Only "${_PLACEHOLDER_ELEMENT}" tags are allowed.`);
}
let names = t.attrs.filter(a => a.name == _NAME_ATTR);
if (names.length == 0) {
throw new I18nError(t.sourceSpan, `Missing "${_NAME_ATTR}" attribute.`);
}
return names[0].value;
}
private _mergeTextInterpolation(t: HtmlElementAst, originalNode: HtmlTextAst): HtmlTextAst {
let split =
this._parser.splitInterpolation(originalNode.value, originalNode.sourceSpan.toString());
let exps = isPresent(split) ? split.expressions : [];
let messageSubstring =
this._messagesContent.substring(t.startSourceSpan.end.offset, t.endSourceSpan.start.offset);
let translated =
this._replacePlaceholdersWithExpressions(messageSubstring, exps, originalNode.sourceSpan);
return new HtmlTextAst(translated, originalNode.sourceSpan);
}
private _mergeElement(t: HtmlElementAst, originalNode: HtmlElementAst,
mapping: HtmlAst[]): HtmlElementAst {
let children = this._mergeTreesHelper(t.children, mapping);
return new HtmlElementAst(originalNode.name, this._i18nAttributes(originalNode), children,
originalNode.sourceSpan, originalNode.startSourceSpan,
originalNode.endSourceSpan);
}
private _i18nAttributes(el: HtmlElementAst): HtmlAttrAst[] {
let res = [];
el.attrs.forEach(attr => {
if (attr.name.startsWith(I18N_ATTR_PREFIX) || attr.name == I18N_ATTR) return;
let i18ns = el.attrs.filter(a => a.name == `i18n-${attr.name}`);
if (i18ns.length == 0) {
res.push(attr);
return;
}
let i18n = i18ns[0];
let message = messageFromAttribute(this._parser, el, i18n);
let messageId = id(message);
if (StringMapWrapper.contains(this._messages, messageId)) {
let updatedMessage = this._replaceInterpolationInAttr(attr, this._messages[messageId]);
res.push(new HtmlAttrAst(attr.name, updatedMessage, attr.sourceSpan));
} else {
throw new I18nError(
attr.sourceSpan,
`Cannot find message for id '${messageId}', content '${message.content}'.`);
}
});
return res;
}
private _replaceInterpolationInAttr(attr: HtmlAttrAst, msg: HtmlAst[]): string {
let split = this._parser.splitInterpolation(attr.value, attr.sourceSpan.toString());
let exps = isPresent(split) ? split.expressions : [];
let first = msg[0];
let last = msg[msg.length - 1];
let start = first.sourceSpan.start.offset;
let end =
last instanceof HtmlElementAst ? last.endSourceSpan.end.offset : last.sourceSpan.end.offset;
let messageSubstring = this._messagesContent.substring(start, end);
return this._replacePlaceholdersWithExpressions(messageSubstring, exps, attr.sourceSpan);
};
private _replacePlaceholdersWithExpressions(message: string, exps: string[],
sourceSpan: ParseSourceSpan): string {
let expMap = this._buildExprMap(exps);
return RegExpWrapper.replaceAll(_PLACEHOLDER_EXPANDED_REGEXP, message, (match) => {
let nameWithQuotes = match[2];
let name = nameWithQuotes.substring(1, nameWithQuotes.length - 1);
return this._convertIntoExpression(name, expMap, sourceSpan);
});
}
private _buildExprMap(exps: string[]): Map<string, string> {
let expMap = new Map<string, string>();
let usedNames = new Map<string, number>();
for (var i = 0; i < exps.length; i++) {
let phName = getPhNameFromBinding(exps[i], i);
expMap.set(dedupePhName(usedNames, phName), exps[i]);
}
return expMap;
}
private _convertIntoExpression(name: string, expMap: Map<string, string>,
sourceSpan: ParseSourceSpan) {
if (expMap.has(name)) {
return `{{${expMap.get(name)}}}`;
} else {
throw new I18nError(sourceSpan, `Invalid interpolation name '${name}'`);
}
}
}
class _CreateNodeMapping implements HtmlAstVisitor {
mapping: HtmlAst[] = [];
visitElement(ast: HtmlElementAst, context: any): any {
this.mapping.push(ast);
htmlVisitAll(this, ast.children);
return null;
}
visitAttr(ast: HtmlAttrAst, context: any): any { return null; }
visitText(ast: HtmlTextAst, context: any): any {
this.mapping.push(ast);
return null;
}
visitExpansion(ast: HtmlExpansionAst, context: any): any { return null; }
visitExpansionCase(ast: HtmlExpansionCaseAst, context: any): any { return null; }
visitComment(ast: HtmlCommentAst, context: any): any { return ""; }
}

View File

@ -1,21 +0,0 @@
import {isPresent, escape} from '../../src/facade/lang';
/**
* A message extracted from a template.
*
* The identity of a message is comprised of `content` and `meaning`.
*
* `description` is additional information provided to the translator.
*/
export class Message {
constructor(public content: string, public meaning: string, public description: string = null) {}
}
/**
* Computes the id of a message
*/
export function id(m: Message): string {
let meaning = isPresent(m.meaning) ? m.meaning : "";
let content = isPresent(m.content) ? m.content : "";
return escape(`$ng|${meaning}|${content}`);
}

View File

@ -1,178 +0,0 @@
import {HtmlParser} from '../html_parser';
import {ParseSourceSpan, ParseError} from '../parse_util';
import {
HtmlAst,
HtmlAstVisitor,
HtmlElementAst,
HtmlAttrAst,
HtmlTextAst,
HtmlCommentAst,
htmlVisitAll
} from '../html_ast';
import {isPresent} from '../../src/facade/lang';
import {StringMapWrapper} from '../../src/facade/collection';
import {Parser} from '../expression_parser/parser';
import {Message, id} from './message';
import {expandNodes} from './expander';
import {
I18nError,
Part,
I18N_ATTR_PREFIX,
partition,
meaning,
description,
stringifyNodes,
messageFromAttribute
} from './shared';
/**
* All messages extracted from a template.
*/
export class ExtractionResult {
constructor(public messages: Message[], public errors: ParseError[]) {}
}
/**
* Removes duplicate messages.
*
* E.g.
*
* ```
* var m = [new Message("message", "meaning", "desc1"), new Message("message", "meaning",
* "desc2")];
* expect(removeDuplicates(m)).toEqual([new Message("message", "meaning", "desc1")]);
* ```
*/
export function removeDuplicates(messages: Message[]): Message[] {
let uniq: {[key: string]: Message} = {};
messages.forEach(m => {
if (!StringMapWrapper.contains(uniq, id(m))) {
uniq[id(m)] = m;
}
});
return StringMapWrapper.values(uniq);
}
/**
* Extracts all messages from a template.
*
* Algorithm:
*
* To understand the algorithm, you need to know how partitioning works.
* Partitioning is required as we can use two i18n comments to group node siblings together.
* That is why we cannot just use nodes.
*
* Partitioning transforms an array of HtmlAst into an array of Part.
* A part can optionally contain a root element or a root text node. And it can also contain
* children.
* A part can contain i18n property, in which case it needs to be extracted.
*
* Example:
*
* The following array of nodes will be split into four parts:
*
* ```
* <a>A</a>
* <b i18n>B</b>
* <!-- i18n -->
* <c>C</c>
* D
* <!-- /i18n -->
* E
* ```
*
* Part 1 containing the a tag. It should not be translated.
* Part 2 containing the b tag. It should be translated.
* Part 3 containing the c tag and the D text node. It should be translated.
* Part 4 containing the E text node. It should not be translated..
*
* It is also important to understand how we stringify nodes to create a message.
*
* We walk the tree and replace every element node with a placeholder. We also replace
* all expressions in interpolation with placeholders. We also insert a placeholder element
* to wrap a text node containing interpolation.
*
* Example:
*
* The following tree:
*
* ```
* <a>A{{I}}</a><b>B</b>
* ```
*
* will be stringified into:
* ```
* <ph name="e0"><ph name="t1">A<ph name="0"/></ph></ph><ph name="e2">B</ph>
* ```
*
* This is what the algorithm does:
*
* 1. Use the provided html parser to get the html AST of the template.
* 2. Partition the root nodes, and process each part separately.
* 3. If a part does not have the i18n attribute, recurse to process children and attributes.
* 4. If a part has the i18n attribute, stringify the nodes to create a Message.
*/
export class MessageExtractor {
messages: Message[];
errors: ParseError[];
constructor(private _htmlParser: HtmlParser, private _parser: Parser) {}
extract(template: string, sourceUrl: string): ExtractionResult {
this.messages = [];
this.errors = [];
let res = this._htmlParser.parse(template, sourceUrl, true);
if (res.errors.length > 0) {
return new ExtractionResult([], res.errors);
} else {
this._recurse(expandNodes(res.rootNodes).nodes);
return new ExtractionResult(this.messages, this.errors);
}
}
private _extractMessagesFromPart(p: Part): void {
if (p.hasI18n) {
this.messages.push(p.createMessage(this._parser));
this._recurseToExtractMessagesFromAttributes(p.children);
} else {
this._recurse(p.children);
}
if (isPresent(p.rootElement)) {
this._extractMessagesFromAttributes(p.rootElement);
}
}
private _recurse(nodes: HtmlAst[]): void {
if (isPresent(nodes)) {
let ps = partition(nodes, this.errors);
ps.forEach(p => this._extractMessagesFromPart(p));
}
}
private _recurseToExtractMessagesFromAttributes(nodes: HtmlAst[]): void {
nodes.forEach(n => {
if (n instanceof HtmlElementAst) {
this._extractMessagesFromAttributes(n);
this._recurseToExtractMessagesFromAttributes(n.children);
}
});
}
private _extractMessagesFromAttributes(p: HtmlElementAst): void {
p.attrs.forEach(attr => {
if (attr.name.startsWith(I18N_ATTR_PREFIX)) {
try {
this.messages.push(messageFromAttribute(this._parser, p, attr));
} catch (e) {
if (e instanceof I18nError) {
this.errors.push(e);
} else {
throw e;
}
}
}
});
}
}

View File

@ -1,191 +0,0 @@
import {ParseSourceSpan, ParseError} from '../parse_util';
import {
HtmlAst,
HtmlAstVisitor,
HtmlElementAst,
HtmlAttrAst,
HtmlTextAst,
HtmlCommentAst,
HtmlExpansionAst,
HtmlExpansionCaseAst,
htmlVisitAll
} from '../html_ast';
import {isPresent, isBlank, StringWrapper} from '../../src/facade/lang';
import {Message} from './message';
import {Parser} from '../expression_parser/parser';
export const I18N_ATTR = "i18n";
export const I18N_ATTR_PREFIX = "i18n-";
var CUSTOM_PH_EXP = /\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*"([\s\S]*?)"[\s\S]*\)/g;
/**
* An i18n error.
*/
export class I18nError extends ParseError {
constructor(span: ParseSourceSpan, msg: string) { super(span, msg); }
}
// Man, this is so ugly!
export function partition(nodes: HtmlAst[], errors: ParseError[]): Part[] {
let res = [];
for (let i = 0; i < nodes.length; ++i) {
let n = nodes[i];
let temp = [];
if (_isOpeningComment(n)) {
let i18n = (<HtmlCommentAst>n).value.substring(5).trim();
i++;
while (!_isClosingComment(nodes[i])) {
temp.push(nodes[i++]);
if (i === nodes.length) {
errors.push(new I18nError(n.sourceSpan, "Missing closing 'i18n' comment."));
break;
}
}
res.push(new Part(null, null, temp, i18n, true));
} else if (n instanceof HtmlElementAst) {
let i18n = _findI18nAttr(n);
res.push(new Part(n, null, n.children, isPresent(i18n) ? i18n.value : null, isPresent(i18n)));
} else if (n instanceof HtmlTextAst) {
res.push(new Part(null, n, null, null, false));
}
}
return res;
}
export class Part {
constructor(public rootElement: HtmlElementAst, public rootTextNode: HtmlTextAst,
public children: HtmlAst[], public i18n: string, public hasI18n: boolean) {}
get sourceSpan(): ParseSourceSpan {
if (isPresent(this.rootElement))
return this.rootElement.sourceSpan;
else if (isPresent(this.rootTextNode))
return this.rootTextNode.sourceSpan;
else
return this.children[0].sourceSpan;
}
createMessage(parser: Parser): Message {
return new Message(stringifyNodes(this.children, parser), meaning(this.i18n),
description(this.i18n));
}
}
function _isOpeningComment(n: HtmlAst): boolean {
return n instanceof HtmlCommentAst && isPresent(n.value) && n.value.startsWith("i18n:");
}
function _isClosingComment(n: HtmlAst): boolean {
return n instanceof HtmlCommentAst && isPresent(n.value) && n.value == "/i18n";
}
function _findI18nAttr(p: HtmlElementAst): HtmlAttrAst {
let i18n = p.attrs.filter(a => a.name == I18N_ATTR);
return i18n.length == 0 ? null : i18n[0];
}
export function meaning(i18n: string): string {
if (isBlank(i18n) || i18n == "") return null;
return i18n.split("|")[0];
}
export function description(i18n: string): string {
if (isBlank(i18n) || i18n == "") return null;
let parts = i18n.split("|");
return parts.length > 1 ? parts[1] : null;
}
export function messageFromAttribute(parser: Parser, p: HtmlElementAst,
attr: HtmlAttrAst): Message {
let expectedName = attr.name.substring(5);
let matching = p.attrs.filter(a => a.name == expectedName);
if (matching.length > 0) {
let value = removeInterpolation(matching[0].value, matching[0].sourceSpan, parser);
return new Message(value, meaning(attr.value), description(attr.value));
} else {
throw new I18nError(p.sourceSpan, `Missing attribute '${expectedName}'.`);
}
}
export function removeInterpolation(value: string, source: ParseSourceSpan,
parser: Parser): string {
try {
let parsed = parser.splitInterpolation(value, source.toString());
let usedNames = new Map<string, number>();
if (isPresent(parsed)) {
let res = "";
for (let i = 0; i < parsed.strings.length; ++i) {
res += parsed.strings[i];
if (i != parsed.strings.length - 1) {
let customPhName = getPhNameFromBinding(parsed.expressions[i], i);
customPhName = dedupePhName(usedNames, customPhName);
res += `<ph name="${customPhName}"/>`;
}
}
return res;
} else {
return value;
}
} catch (e) {
return value;
}
}
export function getPhNameFromBinding(input: string, index: number): string {
let customPhMatch = StringWrapper.split(input, CUSTOM_PH_EXP);
return customPhMatch.length > 1 ? customPhMatch[1] : `${index}`;
}
export function dedupePhName(usedNames: Map<string, number>, name: string): string {
let duplicateNameCount = usedNames.get(name);
if (isPresent(duplicateNameCount)) {
usedNames.set(name, duplicateNameCount + 1);
return `${name}_${duplicateNameCount}`;
} else {
usedNames.set(name, 1);
return name;
}
}
export function stringifyNodes(nodes: HtmlAst[], parser: Parser): string {
let visitor = new _StringifyVisitor(parser);
return htmlVisitAll(visitor, nodes).join("");
}
class _StringifyVisitor implements HtmlAstVisitor {
private _index: number = 0;
constructor(private _parser: Parser) {}
visitElement(ast: HtmlElementAst, context: any): any {
let name = this._index++;
let children = this._join(htmlVisitAll(this, ast.children), "");
return `<ph name="e${name}">${children}</ph>`;
}
visitAttr(ast: HtmlAttrAst, context: any): any { return null; }
visitText(ast: HtmlTextAst, context: any): any {
let index = this._index++;
let noInterpolation = removeInterpolation(ast.value, ast.sourceSpan, this._parser);
if (noInterpolation != ast.value) {
return `<ph name="t${index}">${noInterpolation}</ph>`;
} else {
return ast.value;
}
}
visitComment(ast: HtmlCommentAst, context: any): any { return ""; }
visitExpansion(ast: HtmlExpansionAst, context: any): any { return null; }
visitExpansionCase(ast: HtmlExpansionCaseAst, context: any): any { return null; }
private _join(strs: string[], str: string): string {
return strs.filter(s => s.length > 0).join(str);
}
}

View File

@ -1,95 +0,0 @@
import {isPresent, isBlank, RegExpWrapper} from '../../src/facade/lang';
import {HtmlAst, HtmlElementAst} from '../html_ast';
import {Message, id} from './message';
import {HtmlParser} from '../html_parser';
import {ParseSourceSpan, ParseError} from '../parse_util';
let _PLACEHOLDER_REGEXP = RegExpWrapper.create(`\\<ph(\\s)+name=("(\\w)+")\\/\\>`);
const _ID_ATTR = "id";
const _MSG_ELEMENT = "msg";
const _BUNDLE_ELEMENT = "message-bundle";
export function serializeXmb(messages: Message[]): string {
let ms = messages.map((m) => _serializeMessage(m)).join("");
return `<message-bundle>${ms}</message-bundle>`;
}
export class XmbDeserializationResult {
constructor(public content: string, public messages: {[key: string]: HtmlAst[]},
public errors: ParseError[]) {}
}
export class XmbDeserializationError extends ParseError {
constructor(span: ParseSourceSpan, msg: string) { super(span, msg); }
}
export function deserializeXmb(content: string, url: string): XmbDeserializationResult {
let parser = new HtmlParser();
let normalizedContent = _expandPlaceholder(content.trim());
let parsed = parser.parse(normalizedContent, url);
if (parsed.errors.length > 0) {
return new XmbDeserializationResult(null, {}, parsed.errors);
}
if (_checkRootElement(parsed.rootNodes)) {
return new XmbDeserializationResult(
null, {}, [new XmbDeserializationError(null, `Missing element "${_BUNDLE_ELEMENT}"`)]);
}
let bundleEl = <HtmlElementAst>parsed.rootNodes[0]; // test this
let errors = [];
let messages: {[key: string]: HtmlAst[]} = {};
_createMessages(bundleEl.children, messages, errors);
return (errors.length == 0) ?
new XmbDeserializationResult(normalizedContent, messages, []) :
new XmbDeserializationResult(null, <{[key: string]: HtmlAst[]}>{}, errors);
}
function _checkRootElement(nodes: HtmlAst[]): boolean {
return nodes.length < 1 || !(nodes[0] instanceof HtmlElementAst) ||
(<HtmlElementAst>nodes[0]).name != _BUNDLE_ELEMENT;
}
function _createMessages(nodes: HtmlAst[], messages: {[key: string]: HtmlAst[]},
errors: ParseError[]): void {
nodes.forEach((item) => {
if (item instanceof HtmlElementAst) {
let msg = <HtmlElementAst>item;
if (msg.name != _MSG_ELEMENT) {
errors.push(
new XmbDeserializationError(item.sourceSpan, `Unexpected element "${msg.name}"`));
return;
}
let id = _id(msg);
if (isBlank(id)) {
errors.push(
new XmbDeserializationError(item.sourceSpan, `"${_ID_ATTR}" attribute is missing`));
return;
}
messages[id] = msg.children;
}
});
}
function _id(el: HtmlElementAst): string {
let ids = el.attrs.filter(a => a.name == _ID_ATTR);
return ids.length > 0 ? ids[0].value : null;
}
function _serializeMessage(m: Message): string {
let desc = isPresent(m.description) ? ` desc='${m.description}'` : "";
return `<msg id='${id(m)}'${desc}>${m.content}</msg>`;
}
function _expandPlaceholder(input: string): string {
return RegExpWrapper.replaceAll(_PLACEHOLDER_REGEXP, input, (match) => {
let nameWithQuotes = match[2];
return `<ph name=${nameWithQuotes}></ph>`;
});
}

View File

@ -1,206 +0,0 @@
import {
SimpleChange,
ChangeDetectorRef,
ChangeDetectionStrategy,
ElementRef,
ViewContainerRef,
Renderer,
RenderComponentType,
Injector,
QueryList,
ViewEncapsulation,
TemplateRef
} from '@angular/core';
import {
AppElement,
AppView,
DebugAppView,
ChangeDetectorState,
checkBinding,
DebugContext,
devModeEqual,
flattenNestedViewRenderNodes,
interpolate,
RenderDebugInfo,
StaticNodeDebugInfo,
TemplateRef_,
uninitialized,
ValueUnwrapper,
ViewType,
ViewUtils,
castByValue,
EMPTY_ARRAY,
EMPTY_MAP,
pureProxy1,
pureProxy2,
pureProxy3,
pureProxy4,
pureProxy5,
pureProxy6,
pureProxy7,
pureProxy8,
pureProxy9,
pureProxy10
} from '../core_private';
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
import {assetUrl} from './util';
var APP_VIEW_MODULE_URL = assetUrl('core', 'linker/view');
var VIEW_UTILS_MODULE_URL = assetUrl('core', 'linker/view_utils');
var CD_MODULE_URL = assetUrl('core', 'change_detection/change_detection');
// 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 impDebugAppView = DebugAppView;
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;
var impEMPTY_ARRAY = EMPTY_ARRAY;
var impEMPTY_MAP = EMPTY_MAP;
export class Identifiers {
static ViewUtils = new CompileIdentifierMetadata(
{name: 'ViewUtils', moduleUrl: assetUrl('core', 'linker/view_utils'), runtime: impViewUtils});
static AppView = new CompileIdentifierMetadata(
{name: 'AppView', moduleUrl: APP_VIEW_MODULE_URL, runtime: impAppView});
static DebugAppView = new CompileIdentifierMetadata(
{name: 'DebugAppView', moduleUrl: APP_VIEW_MODULE_URL, runtime: impDebugAppView});
static AppElement = new CompileIdentifierMetadata(
{name: 'AppElement', moduleUrl: assetUrl('core', 'linker/element'), runtime: impAppElement});
static ElementRef = new CompileIdentifierMetadata({
name: 'ElementRef',
moduleUrl: assetUrl('core', 'linker/element_ref'),
runtime: impElementRef
});
static ViewContainerRef = new CompileIdentifierMetadata({
name: 'ViewContainerRef',
moduleUrl: assetUrl('core', 'linker/view_container_ref'),
runtime: impViewContainerRef
});
static ChangeDetectorRef = new CompileIdentifierMetadata({
name: 'ChangeDetectorRef',
moduleUrl: assetUrl('core', 'change_detection/change_detector_ref'),
runtime: impChangeDetectorRef
});
static RenderComponentType = new CompileIdentifierMetadata({
name: 'RenderComponentType',
moduleUrl: assetUrl('core', 'render/api'),
runtime: impRenderComponentType
});
static QueryList = new CompileIdentifierMetadata(
{name: 'QueryList', moduleUrl: assetUrl('core', 'linker/query_list'), runtime: impQueryList});
static TemplateRef = new CompileIdentifierMetadata({
name: 'TemplateRef',
moduleUrl: assetUrl('core', 'linker/template_ref'),
runtime: impTemplateRef
});
static TemplateRef_ = new CompileIdentifierMetadata({
name: 'TemplateRef_',
moduleUrl: assetUrl('core', 'linker/template_ref'),
runtime: impTemplateRef_
});
static ValueUnwrapper = new CompileIdentifierMetadata(
{name: 'ValueUnwrapper', moduleUrl: CD_MODULE_URL, runtime: impValueUnwrapper});
static Injector = new CompileIdentifierMetadata(
{name: 'Injector', moduleUrl: assetUrl('core', 'di/injector'), runtime: impInjector});
static ViewEncapsulation = new CompileIdentifierMetadata({
name: 'ViewEncapsulation',
moduleUrl: assetUrl('core', 'metadata/view'),
runtime: impViewEncapsulation
});
static ViewType = new CompileIdentifierMetadata(
{name: 'ViewType', moduleUrl: assetUrl('core', 'linker/view_type'), runtime: impViewType});
static ChangeDetectionStrategy = new CompileIdentifierMetadata({
name: 'ChangeDetectionStrategy',
moduleUrl: CD_MODULE_URL,
runtime: impChangeDetectionStrategy
});
static StaticNodeDebugInfo = new CompileIdentifierMetadata({
name: 'StaticNodeDebugInfo',
moduleUrl: assetUrl('core', 'linker/debug_context'),
runtime: impStaticNodeDebugInfo
});
static DebugContext = new CompileIdentifierMetadata({
name: 'DebugContext',
moduleUrl: assetUrl('core', 'linker/debug_context'),
runtime: impDebugContext
});
static Renderer = new CompileIdentifierMetadata(
{name: 'Renderer', moduleUrl: assetUrl('core', 'render/api'), 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 EMPTY_ARRAY = new CompileIdentifierMetadata(
{name: 'EMPTY_ARRAY', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: impEMPTY_ARRAY});
static EMPTY_MAP = new CompileIdentifierMetadata(
{name: 'EMPTY_MAP', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: impEMPTY_MAP});
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});
}

View File

@ -1,438 +0,0 @@
import {
AttributeMetadata,
ReflectiveDependency,
OptionalMetadata,
ComponentMetadata,
SelfMetadata,
HostMetadata,
SkipSelfMetadata,
Provider,
PLATFORM_DIRECTIVES,
PLATFORM_PIPES,
reflector,
Injectable,
Inject,
Optional,
ViewMetadata,
NoAnnotationError,
QueryMetadata,
resolveForwardRef,
InjectMetadata,
ViewQueryMetadata
} from '@angular/core';
import {constructDependencies, LIFECYCLE_HOOKS_VALUES, ReflectorReader} from '../core_private';
import {
Type,
isBlank,
isPresent,
isArray,
stringify,
isString,
isStringMap
} from '../src/facade/lang';
import {StringMapWrapper} from '../src/facade/collection';
import {BaseException} from '../src/facade/exceptions';
import * as cpl from './compile_metadata';
import {DirectiveResolver} from './directive_resolver';
import {PipeResolver} from './pipe_resolver';
import {ViewResolver} from './view_resolver';
import {hasLifecycleHook} from './directive_lifecycle_reflector';
import {MODULE_SUFFIX, sanitizeIdentifier, ValueTransformer, visitValue} from './util';
import {assertArrayOfStrings} from './assertions';
import {getUrlScheme} from './url_resolver';
import {createProvider, isProviderLiteral} from "../core_private";
@Injectable()
export class CompileMetadataResolver {
private _directiveCache = new Map<Type, cpl.CompileDirectiveMetadata>();
private _pipeCache = new Map<Type, cpl.CompilePipeMetadata>();
private _anonymousTypes = new Map<Object, number>();
private _anonymousTypeIndex = 0;
private _reflector: ReflectorReader;
constructor(private _directiveResolver: DirectiveResolver, private _pipeResolver: PipeResolver,
private _viewResolver: ViewResolver,
@Optional() @Inject(PLATFORM_DIRECTIVES) private _platformDirectives: Type[],
@Optional() @Inject(PLATFORM_PIPES) private _platformPipes: Type[],
_reflector?: ReflectorReader) {
if (isPresent(_reflector)) {
this._reflector = _reflector;
} else {
this._reflector = reflector;
}
}
private sanitizeTokenName(token: any): string {
let identifier = stringify(token);
if (identifier.indexOf('(') >= 0) {
// case: anonymous functions!
let found = this._anonymousTypes.get(token);
if (isBlank(found)) {
this._anonymousTypes.set(token, this._anonymousTypeIndex++);
found = this._anonymousTypes.get(token);
}
identifier = `anonymous_token_${found}_`;
}
return sanitizeIdentifier(identifier);
}
getDirectiveMetadata(directiveType: Type): cpl.CompileDirectiveMetadata {
var meta = this._directiveCache.get(directiveType);
if (isBlank(meta)) {
var dirMeta = this._directiveResolver.resolve(directiveType);
var templateMeta = null;
var changeDetectionStrategy = null;
var viewProviders = [];
if (dirMeta instanceof ComponentMetadata) {
assertArrayOfStrings('styles', dirMeta.styles);
var cmpMeta = <ComponentMetadata>dirMeta;
var viewMeta = this._viewResolver.resolve(directiveType);
assertArrayOfStrings('styles', viewMeta.styles);
templateMeta = new cpl.CompileTemplateMetadata({
encapsulation: viewMeta.encapsulation,
template: viewMeta.template,
templateUrl: viewMeta.templateUrl,
styles: viewMeta.styles,
styleUrls: viewMeta.styleUrls
});
changeDetectionStrategy = cmpMeta.changeDetection;
if (isPresent(dirMeta.viewProviders)) {
viewProviders = this.getProvidersMetadata(dirMeta.viewProviders);
}
}
var providers = [];
if (isPresent(dirMeta.providers)) {
providers = this.getProvidersMetadata(dirMeta.providers);
}
var queries = [];
var viewQueries = [];
if (isPresent(dirMeta.queries)) {
queries = this.getQueriesMetadata(dirMeta.queries, false);
viewQueries = this.getQueriesMetadata(dirMeta.queries, true);
}
meta = cpl.CompileDirectiveMetadata.create({
selector: dirMeta.selector,
exportAs: dirMeta.exportAs,
isComponent: isPresent(templateMeta),
type: this.getTypeMetadata(directiveType,
isPresent(cmpMeta) ?
componentModuleUrl(this._reflector, directiveType, cmpMeta) :
staticTypeModuleUrl(dirMeta)),
template: templateMeta,
changeDetection: changeDetectionStrategy,
inputs: dirMeta.inputs,
outputs: dirMeta.outputs,
host: dirMeta.host,
lifecycleHooks:
LIFECYCLE_HOOKS_VALUES.filter(hook => hasLifecycleHook(hook, directiveType)),
providers: providers,
viewProviders: viewProviders,
queries: queries,
viewQueries: viewQueries
});
this._directiveCache.set(directiveType, meta);
}
return meta;
}
/**
* @param someType a symbol which may or may not be a directive type
* @returns {cpl.CompileDirectiveMetadata} if possible, otherwise null.
*/
maybeGetDirectiveMetadata(someType: Type): cpl.CompileDirectiveMetadata {
try {
return this.getDirectiveMetadata(someType);
} catch (e) {
if (e.message.indexOf('No Directive annotation') !== -1) {
return null;
}
throw e;
}
}
getTypeMetadata(type: Type, moduleUrl: string): cpl.CompileTypeMetadata {
return new cpl.CompileTypeMetadata({
name: this.sanitizeTokenName(type),
moduleUrl: moduleUrl,
runtime: type,
diDeps: this.getDependenciesMetadata(type, null)
});
}
getFactoryMetadata(factory: Function, moduleUrl: string): cpl.CompileFactoryMetadata {
return new cpl.CompileFactoryMetadata({
name: this.sanitizeTokenName(factory),
moduleUrl: moduleUrl,
runtime: factory,
diDeps: this.getDependenciesMetadata(factory, null)
});
}
getPipeMetadata(pipeType: Type): cpl.CompilePipeMetadata {
var meta = this._pipeCache.get(pipeType);
if (isBlank(meta)) {
var pipeMeta = this._pipeResolver.resolve(pipeType);
meta = new cpl.CompilePipeMetadata({
type: this.getTypeMetadata(pipeType, staticTypeModuleUrl(pipeType)),
name: pipeMeta.name,
pure: pipeMeta.pure,
lifecycleHooks: LIFECYCLE_HOOKS_VALUES.filter(hook => hasLifecycleHook(hook, pipeType)),
});
this._pipeCache.set(pipeType, meta);
}
return meta;
}
getViewDirectivesMetadata(component: Type): cpl.CompileDirectiveMetadata[] {
var view = this._viewResolver.resolve(component);
var directives = flattenDirectives(view, this._platformDirectives);
for (var i = 0; i < directives.length; i++) {
if (!isValidType(directives[i])) {
throw new BaseException(
`Unexpected directive value '${stringify(directives[i])}' on the View of component '${stringify(component)}'`);
}
}
return directives.map(type => this.getDirectiveMetadata(type));
}
getViewPipesMetadata(component: Type): cpl.CompilePipeMetadata[] {
var view = this._viewResolver.resolve(component);
var pipes = flattenPipes(view, this._platformPipes);
for (var i = 0; i < pipes.length; i++) {
if (!isValidType(pipes[i])) {
throw new BaseException(
`Unexpected piped value '${stringify(pipes[i])}' on the View of component '${stringify(component)}'`);
}
}
return pipes.map(type => this.getPipeMetadata(type));
}
getDependenciesMetadata(typeOrFunc: Type | Function,
dependencies: any[]): cpl.CompileDiDependencyMetadata[] {
let params = isPresent(dependencies) ? dependencies : this._reflector.parameters(typeOrFunc);
if (isBlank(params)) {
params = [];
}
return params.map((param) => {
if (isBlank(param)) {
return null;
}
let isAttribute = false;
let isHost = false;
let isSelf = false;
let isSkipSelf = false;
let isOptional = false;
let query: QueryMetadata = null;
let viewQuery: ViewQueryMetadata = null;
var token = null;
if (isArray(param)) {
(<any[]>param)
.forEach((paramEntry) => {
if (paramEntry instanceof HostMetadata) {
isHost = true;
} else if (paramEntry instanceof SelfMetadata) {
isSelf = true;
} else if (paramEntry instanceof SkipSelfMetadata) {
isSkipSelf = true;
} else if (paramEntry instanceof OptionalMetadata) {
isOptional = true;
} else if (paramEntry instanceof AttributeMetadata) {
isAttribute = true;
token = paramEntry.attributeName;
} else if (paramEntry instanceof QueryMetadata) {
if (paramEntry.isViewQuery) {
viewQuery = paramEntry;
} else {
query = paramEntry;
}
} else if (paramEntry instanceof InjectMetadata) {
token = paramEntry.token;
} else if (isValidType(paramEntry) && isBlank(token)) {
token = paramEntry;
}
});
} else {
token = param;
}
if (isBlank(token)) {
return null;
}
return new cpl.CompileDiDependencyMetadata({
isAttribute: isAttribute,
isHost: isHost,
isSelf: isSelf,
isSkipSelf: isSkipSelf,
isOptional: isOptional,
query: isPresent(query) ? this.getQueryMetadata(query, null) : null,
viewQuery: isPresent(viewQuery) ? this.getQueryMetadata(viewQuery, null) : null,
token: this.getTokenMetadata(token)
});
});
}
getTokenMetadata(token: any): cpl.CompileTokenMetadata {
token = resolveForwardRef(token);
var compileToken;
if (isString(token)) {
compileToken = new cpl.CompileTokenMetadata({value: token});
} else {
compileToken = new cpl.CompileTokenMetadata({
identifier: new cpl.CompileIdentifierMetadata({
runtime: token,
name: this.sanitizeTokenName(token),
moduleUrl: staticTypeModuleUrl(token)
})
});
}
return compileToken;
}
getProvidersMetadata(providers: any[]):
Array<cpl.CompileProviderMetadata | cpl.CompileTypeMetadata | any[]> {
return providers.map((provider) => {
provider = resolveForwardRef(provider);
if (isArray(provider)) {
return this.getProvidersMetadata(provider);
} else if (provider instanceof Provider) {
return this.getProviderMetadata(provider);
} else if (isProviderLiteral(provider)) {
return this.getProviderMetadata(createProvider(provider));
} else {
return this.getTypeMetadata(provider, staticTypeModuleUrl(provider));
}
});
}
getProviderMetadata(provider: Provider): cpl.CompileProviderMetadata {
var compileDeps;
if (isPresent(provider.useClass)) {
compileDeps = this.getDependenciesMetadata(provider.useClass, provider.dependencies);
} else if (isPresent(provider.useFactory)) {
compileDeps = this.getDependenciesMetadata(provider.useFactory, provider.dependencies);
}
return new cpl.CompileProviderMetadata({
token: this.getTokenMetadata(provider.token),
useClass:
isPresent(provider.useClass) ?
this.getTypeMetadata(provider.useClass, staticTypeModuleUrl(provider.useClass)) :
null,
useValue: convertToCompileValue(provider.useValue),
useFactory: isPresent(provider.useFactory) ?
this.getFactoryMetadata(provider.useFactory,
staticTypeModuleUrl(provider.useFactory)) :
null,
useExisting: isPresent(provider.useExisting) ? this.getTokenMetadata(provider.useExisting) :
null,
deps: compileDeps,
multi: provider.multi
});
}
getQueriesMetadata(queries: {[key: string]: QueryMetadata},
isViewQuery: boolean): cpl.CompileQueryMetadata[] {
var compileQueries = [];
StringMapWrapper.forEach(queries, (query, propertyName) => {
if (query.isViewQuery === isViewQuery) {
compileQueries.push(this.getQueryMetadata(query, propertyName));
}
});
return compileQueries;
}
getQueryMetadata(q: QueryMetadata, propertyName: string): cpl.CompileQueryMetadata {
var selectors;
if (q.isVarBindingQuery) {
selectors = q.varBindings.map(varName => this.getTokenMetadata(varName));
} else {
selectors = [this.getTokenMetadata(q.selector)];
}
return new cpl.CompileQueryMetadata({
selectors: selectors,
first: q.first,
descendants: q.descendants,
propertyName: propertyName,
read: isPresent(q.read) ? this.getTokenMetadata(q.read) : null
});
}
}
function flattenDirectives(view: ViewMetadata, platformDirectives: any[]): Type[] {
let directives = [];
if (isPresent(platformDirectives)) {
flattenArray(platformDirectives, directives);
}
if (isPresent(view.directives)) {
flattenArray(view.directives, directives);
}
return directives;
}
function flattenPipes(view: ViewMetadata, platformPipes: any[]): Type[] {
let pipes = [];
if (isPresent(platformPipes)) {
flattenArray(platformPipes, pipes);
}
if (isPresent(view.pipes)) {
flattenArray(view.pipes, pipes);
}
return pipes;
}
function flattenArray(tree: any[], out: Array<Type | any[]>): void {
for (var i = 0; i < tree.length; i++) {
var item = resolveForwardRef(tree[i]);
if (isArray(item)) {
flattenArray(item, out);
} else {
out.push(item);
}
}
}
function isStaticType(value: any): boolean {
return isStringMap(value) && isPresent(value['name']) && isPresent(value['filePath']);
}
function isValidType(value: any): boolean {
return isStaticType(value) || (value instanceof Type);
}
function staticTypeModuleUrl(value: any): string {
return isStaticType(value) ? value['filePath'] : null;
}
function componentModuleUrl(reflector: ReflectorReader, type: any,
cmpMetadata: ComponentMetadata): string {
if (isStaticType(type)) {
return staticTypeModuleUrl(type);
}
if (isPresent(cmpMetadata.moduleId)) {
var moduleId = cmpMetadata.moduleId;
var scheme = getUrlScheme(moduleId);
return isPresent(scheme) && scheme.length > 0 ? moduleId :
`package:${moduleId}${MODULE_SUFFIX}`;
}
return reflector.importUri(type);
}
// Only fill CompileIdentifierMetadata.runtime if needed...
function convertToCompileValue(value: any): any {
return visitValue(value, new _CompileValueConverter(), null);
}
class _CompileValueConverter extends ValueTransformer {
visitOther(value: any, context: any): any {
if (isStaticType(value)) {
return new cpl.CompileIdentifierMetadata(
{name: value['name'], moduleUrl: staticTypeModuleUrl(value)});
} else {
return new cpl.CompileIdentifierMetadata({runtime: value});
}
}
}

View File

@ -1,171 +0,0 @@
import {ComponentFactory} from '@angular/core';
import {
CompileDirectiveMetadata,
CompileIdentifierMetadata,
CompilePipeMetadata,
createHostComponentMeta
} from './compile_metadata';
import {BaseException} from '../src/facade/exceptions';
import {ListWrapper} from '../src/facade/collection';
import {StyleCompiler, 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 {XHR} from './xhr';
import {
MODULE_SUFFIX,
assetUrl,
} from './util';
var _COMPONENT_FACTORY_IDENTIFIER = new CompileIdentifierMetadata({
name: 'ComponentFactory',
runtime: ComponentFactory,
moduleUrl: assetUrl('core', 'linker/component_factory')
});
export class SourceModule {
constructor(public moduleUrl: string, public source: string) {}
}
export class StyleSheetSourceWithImports {
constructor(public source: SourceModule, public importedUrls: 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,
private _xhr: XHR) {}
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, [o.importType(compMeta.type)])
.instantiate(
[
o.literal(compMeta.selector),
o.variable(hostViewFactoryVar),
o.importExpr(compMeta.type)
],
o.importType(_COMPONENT_FACTORY_IDENTIFIER,
[o.importType(compMeta.type)], [o.TypeModifier.Const])))
.toDeclStmt(null, [o.StmtModifier.Final]));
exportedVars.push(compFactoryVar);
});
return this._codegenSourceModule(moduleUrl, statements, exportedVars);
}
loadAndCompileStylesheet(stylesheetUrl: string, shim: boolean,
suffix: string): Promise<StyleSheetSourceWithImports> {
return this._xhr.get(stylesheetUrl)
.then((cssText) => {
var compileResult = this._styleCompiler.compileStylesheet(stylesheetUrl, cssText, shim);
var importedUrls = [];
compileResult.dependencies.forEach((dep) => {
importedUrls.push(dep.moduleUrl);
dep.valuePlaceholder.moduleUrl = _stylesModuleUrl(dep.moduleUrl, dep.isShimmed, suffix);
});
return new StyleSheetSourceWithImports(
this._codgenStyles(stylesheetUrl, shim, suffix, compileResult), importedUrls);
});
}
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(compMeta.type.moduleUrl, styleResult));
ListWrapper.addAll(targetStatements, _resolveViewStatements(viewResult));
return viewResult.viewFactoryVar;
}
private _codgenStyles(inputUrl: string, shim: boolean, suffix: string,
stylesCompileResult: StylesCompileResult): SourceModule {
return this._codegenSourceModule(_stylesModuleUrl(inputUrl, shim, suffix),
stylesCompileResult.statements,
[stylesCompileResult.stylesVar]);
}
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(containingModuleUrl: string,
compileResult: StylesCompileResult): o.Statement[] {
var containingSuffix = _splitSuffix(containingModuleUrl)[1];
compileResult.dependencies.forEach((dep) => {
dep.valuePlaceholder.moduleUrl =
_stylesModuleUrl(dep.moduleUrl, dep.isShimmed, containingSuffix);
});
return compileResult.statements;
}
function _templateModuleUrl(comp: CompileDirectiveMetadata): string {
var urlWithSuffix = _splitSuffix(comp.type.moduleUrl);
return `${urlWithSuffix[0]}.ngfactory${urlWithSuffix[1]}`;
}
function _stylesModuleUrl(stylesheetUrl: string, shim: boolean, suffix: string): string {
return shim ? `${stylesheetUrl}.shim${suffix}` : `${stylesheetUrl}${suffix}`;
}
function _assertComponent(meta: CompileDirectiveMetadata) {
if (!meta.isComponent) {
throw new BaseException(`Could not compile '${meta.type.name}' because it is not a component.`);
}
}
function _splitSuffix(path: string): string[] {
let lastDot = path.lastIndexOf('.');
if (lastDot !== -1) {
return [path.substring(0, lastDot), path.substring(lastDot)];
} else {
return [path, ''];
}
}

View File

@ -1,418 +0,0 @@
import {isPresent, isBlank, isString, StringWrapper} from '../../src/facade/lang';
import {BaseException} from '../../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 {
ctx.print(`(`);
ast.condition.visitExpression(this, ctx);
ctx.print('? ');
ast.trueCase.visitExpression(this, ctx);
ctx.print(': ');
ast.falseCase.visitExpression(this, ctx);
ctx.print(`)`);
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;
}

View File

@ -1,164 +0,0 @@
import {isPresent} from '../../src/facade/lang';
import {BaseException} from '../../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;
}
}

View File

@ -1,374 +0,0 @@
import {isPresent, isBlank, isArray} from '../../src/facade/lang';
import {BaseException} from '../../src/facade/exceptions';
import {CompileIdentifierMetadata} from '../compile_metadata';
import * as o from './output_ast';
import {
OutputEmitter,
EmitterVisitorContext,
AbstractEmitterVisitor,
CATCH_ERROR_VAR,
CATCH_STACK_VAR,
} from './abstract_emitter';
import {ImportGenerator} 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(private _importGenerator: ImportGenerator) {}
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 '${this._importGenerator.getImportPath(moduleUrl, importedModuleUrl)}' 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 (isBlank(value.name)) {
throw new BaseException(`Internal error: unknown identifier ${value}`);
}
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);
}

View File

@ -1,52 +0,0 @@
import {BaseException} from '../../src/facade/exceptions';
import {isPresent, isBlank, RegExpWrapper, Math} from '../../src/facade/lang';
import {Injectable} from '@angular/core';
import {AssetUrl, ImportGenerator} from './path_util';
var _PATH_SEP = '/';
var _PATH_SEP_RE = /\//g;
@Injectable()
export class DartImportGenerator implements ImportGenerator {
getImportPath(moduleUrlStr: string, importedUrlStr: string): string {
var moduleUrl = AssetUrl.parse(moduleUrlStr, false);
var importedUrl = AssetUrl.parse(importedUrlStr, true);
if (isBlank(importedUrl)) {
return importedUrlStr;
}
// Try to create a relative path first
if (moduleUrl.firstLevelDir == importedUrl.firstLevelDir &&
moduleUrl.packageName == importedUrl.packageName) {
return getRelativePath(moduleUrl.modulePath, importedUrl.modulePath);
} else if (importedUrl.firstLevelDir == 'lib') {
return `package:${importedUrl.packageName}/${importedUrl.modulePath}`;
}
throw new BaseException(`Can't import url ${importedUrlStr} from ${moduleUrlStr}`);
}
}
export function getRelativePath(modulePath: string, importedPath: string): string {
var moduleParts = modulePath.split(_PATH_SEP_RE);
var importedParts = importedPath.split(_PATH_SEP_RE);
var longestPrefix = getLongestPathSegmentPrefix(moduleParts, importedParts);
var resultParts = [];
var goParentCount = moduleParts.length - 1 - longestPrefix;
for (var i = 0; i < goParentCount; i++) {
resultParts.push('..');
}
for (var i = longestPrefix; i < importedParts.length; i++) {
resultParts.push(importedParts[i]);
}
return resultParts.join(_PATH_SEP);
}
export function getLongestPathSegmentPrefix(arr1: string[], arr2: string[]): number {
var prefixSize = 0;
var minLen = Math.min(arr1.length, arr2.length);
while (prefixSize < minLen && arr1[prefixSize] == arr2[prefixSize]) {
prefixSize++;
}
return prefixSize;
}

View File

@ -1,68 +0,0 @@
import {AppElement, AppView, DebugAppView} from '../../core_private';
import {isPresent} from '../../src/facade/lang';
import {BaseException} from '../../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) {
// We are always using DebugAppView as parent.
// However, in prod mode we generate a constructor call that does
// not have the argument for the debugNodeInfos.
args = args.concat([null]);
return new _InterpretiveAppView(args, props, getters, methods);
} else if (superClass === DebugAppView) {
return new _InterpretiveAppView(args, props, getters, methods);
}
throw new BaseException(`Can't instantiate class ${superClass} in interpretative mode`);
}
}
class _InterpretiveAppView extends DebugAppView<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]);
}
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);
}
}
}

View File

@ -1,78 +0,0 @@
import * as o from './output_ast';
import {
isPresent,
isBlank,
isString,
evalExpression,
RegExpWrapper,
StringWrapper
} from '../facade/lang';
import {BaseException} from '@angular/core';
import {OutputEmitter, EmitterVisitorContext} from './abstract_emitter';
import {AbstractJsEmitterVisitor} from './abstract_js_emitter';
import {ImportGenerator} from './path_util';
export class JavaScriptEmitter implements OutputEmitter {
constructor(private _importGenerator: ImportGenerator) {}
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('${this._importGenerator.getImportPath(moduleUrl, importedModuleUrl)}');`);
});
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 (isBlank(ast.value.name)) {
throw new BaseException(`Internal error: unknown identifier ${ast.value}`);
}
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}; }});`;
}

View File

@ -1,869 +0,0 @@
import {isString, isPresent, isBlank} from '../../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[] = /*@ts2dart_const*/[]) {
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);
}

View File

@ -1,416 +0,0 @@
import {reflector} from '@angular/core';
import {isPresent, IS_DART, FunctionWrapper} from '../../src/facade/lang';
import {ObservableWrapper} from '../../src/facade/async';
import {BaseException, unimplemented} from '../../src/facade/exceptions';
import {ListWrapper} from '../../src/facade/collection';
import * as o from './output_ast';
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';

View File

@ -1,42 +0,0 @@
import {
isPresent,
evalExpression,
} from '../../src/facade/lang';
import * as o from './output_ast';
import {EmitterVisitorContext} from './abstract_emitter';
import {AbstractJsEmitterVisitor} from './abstract_js_emitter';
import {sanitizeIdentifier} from '../util';
export function jitStatements(sourceUrl: string, statements: o.Statement[],
resultVar: string): any {
var converter = new JitEmitterVisitor();
var ctx = EmitterVisitorContext.createRoot([resultVar]);
converter.visitAllStatements(statements, ctx);
return evalExpression(sourceUrl, resultVar, ctx.toSource(), converter.getArgs());
}
class JitEmitterVisitor extends AbstractJsEmitterVisitor {
private _evalArgNames: string[] = [];
private _evalArgValues: any[] = [];
getArgs(): {[key: string]: any} {
var result = {};
for (var i = 0; i < this._evalArgNames.length; i++) {
result[this._evalArgNames[i]] = this._evalArgValues[i];
}
return result;
}
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
var value = ast.value.runtime;
var id = this._evalArgValues.indexOf(value);
if (id === -1) {
id = this._evalArgValues.length;
this._evalArgValues.push(value);
var name = isPresent(ast.value.name) ? sanitizeIdentifier(ast.value.name) : 'val';
this._evalArgNames.push(sanitizeIdentifier(`jit_${name}${id}`));
}
ctx.print(this._evalArgNames[id]);
return null;
}
}

View File

@ -1,31 +0,0 @@
import {BaseException} from '../../src/facade/exceptions';
import {isPresent, isBlank, RegExpWrapper, Math} from '../../src/facade/lang';
import {Injectable} from '@angular/core';
// asset:<package-name>/<realm>/<path-to-module>
var _ASSET_URL_RE = /asset:([^\/]+)\/([^\/]+)\/(.+)/g;
/**
* Interface that defines how import statements should be generated.
*/
export abstract class ImportGenerator {
static parseAssetUrl(url: string): AssetUrl { return AssetUrl.parse(url); }
abstract getImportPath(moduleUrlStr: string, importedUrlStr: string): string;
}
export class AssetUrl {
static parse(url: string, allowNonMatching: boolean = true): AssetUrl {
var match = RegExpWrapper.firstMatch(_ASSET_URL_RE, url);
if (isPresent(match)) {
return new AssetUrl(match[1], match[2], match[3]);
}
if (allowNonMatching) {
return null;
}
throw new BaseException(`Url ${url} is not a valid asset: url`);
}
constructor(public packageName: string, public firstLevelDir: string, public modulePath: string) {
}
}

View File

@ -1,324 +0,0 @@
import * as o from './output_ast';
import {isPresent, isBlank, isArray} from '../../src/facade/lang';
import {BaseException} from '../../src/facade/exceptions';
import {CompileIdentifierMetadata} from '../compile_metadata';
import {
OutputEmitter,
EmitterVisitorContext,
AbstractEmitterVisitor,
CATCH_ERROR_VAR,
CATCH_STACK_VAR
} from './abstract_emitter';
import {ImportGenerator} from './path_util';
var _debugModuleUrl = 'asset://debug/lib';
export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.Type |
any[]): string {
var converter = new _TsEmitterVisitor(_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 TypeScriptEmitter implements OutputEmitter {
constructor(private _importGenerator: ImportGenerator) {}
emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string {
var converter = new _TsEmitterVisitor(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(
`imp` +
`ort * as ${prefix} from '${this._importGenerator.getImportPath(moduleUrl, importedModuleUrl)}';`);
});
srcParts.push(ctx.toSource());
return srcParts.join('\n');
}
}
class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor {
constructor(private _moduleUrl: string) { super(false); }
importsWithPrefixes = new Map<string, string>();
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
this._visitIdentifier(ast.value, ast.typeParams, ctx);
return null;
}
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
if (ctx.isExportedVar(stmt.name)) {
ctx.print(`export `);
}
if (stmt.hasModifier(o.StmtModifier.Final)) {
ctx.print(`const`);
} else {
ctx.print(`var`);
}
ctx.print(` ${stmt.name}`);
if (isPresent(stmt.type)) {
ctx.print(`:`);
stmt.type.visitType(this, ctx);
}
ctx.print(` = `);
stmt.value.visitExpression(this, ctx);
ctx.println(`;`);
return null;
}
visitCastExpr(ast: o.CastExpr, ctx: EmitterVisitorContext): any {
ctx.print(`(<`);
ast.type.visitType(this, ctx);
ctx.print(`>`);
ast.value.visitExpression(this, ctx);
ctx.print(`)`);
return null;
}
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
ctx.pushClass(stmt);
if (ctx.isExportedVar(stmt.name)) {
ctx.print(`export `);
}
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.Private)) {
ctx.print(`private `);
}
ctx.print(field.name);
if (isPresent(field.type)) {
ctx.print(`:`);
field.type.visitType(this, ctx);
} else {
ctx.print(`: any`);
}
ctx.println(`;`);
}
private _visitClassGetter(getter: o.ClassGetter, ctx: EmitterVisitorContext) {
if (getter.hasModifier(o.StmtModifier.Private)) {
ctx.print(`private `);
}
ctx.print(`get ${getter.name}()`);
if (isPresent(getter.type)) {
ctx.print(`:`);
getter.type.visitType(this, ctx);
}
ctx.println(` {`);
ctx.incIndent();
this.visitAllStatements(getter.body, ctx);
ctx.decIndent();
ctx.println(`}`);
}
private _visitClassConstructor(stmt: o.ClassStmt, ctx: EmitterVisitorContext) {
ctx.print(`constructor(`);
this._visitParams(stmt.constructorMethod.params, ctx);
ctx.println(`) {`);
ctx.incIndent();
this.visitAllStatements(stmt.constructorMethod.body, ctx);
ctx.decIndent();
ctx.println(`}`);
}
private _visitClassMethod(method: o.ClassMethod, ctx: EmitterVisitorContext) {
if (method.hasModifier(o.StmtModifier.Private)) {
ctx.print(`private `);
}
ctx.print(`${method.name}(`);
this._visitParams(method.params, ctx);
ctx.print(`):`);
if (isPresent(method.type)) {
method.type.visitType(this, ctx);
} else {
ctx.print(`void`);
}
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.print(`):`);
if (isPresent(ast.type)) {
ast.type.visitType(this, ctx);
} else {
ctx.print(`void`);
}
ctx.println(` => {`);
ctx.incIndent();
this.visitAllStatements(ast.statements, ctx);
ctx.decIndent();
ctx.print(`}`);
return null;
}
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: EmitterVisitorContext): any {
if (ctx.isExportedVar(stmt.name)) {
ctx.print(`export `);
}
ctx.print(`function ${stmt.name}(`);
this._visitParams(stmt.params, ctx);
ctx.print(`):`);
if (isPresent(stmt.type)) {
stmt.type.visitType(this, ctx);
} else {
ctx.print(`void`);
}
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;
}
visitBuiltintType(type: o.BuiltinType, ctx: EmitterVisitorContext): any {
var typeStr;
switch (type.name) {
case o.BuiltinTypeName.Bool:
typeStr = 'boolean';
break;
case o.BuiltinTypeName.Dynamic:
typeStr = 'any';
break;
case o.BuiltinTypeName.Function:
typeStr = 'Function';
break;
case o.BuiltinTypeName.Number:
typeStr = 'number';
break;
case o.BuiltinTypeName.Int:
typeStr = 'number';
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 {
if (isPresent(type.of)) {
type.of.visitType(this, ctx);
} else {
ctx.print(`any`);
}
ctx.print(`[]`);
return null;
}
visitMapType(type: o.MapType, ctx: EmitterVisitorContext): any {
ctx.print(`{[key: string]:`);
if (isPresent(type.valueType)) {
type.valueType.visitType(this, ctx);
} else {
ctx.print(`any`);
}
ctx.print(`}`);
return null;
}
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;
}
private _visitParams(params: o.FnParam[], ctx: EmitterVisitorContext): void {
this.visitAllObjects((param) => {
ctx.print(param.name);
if (isPresent(param.type)) {
ctx.print(`:`);
param.type.visitType(this, ctx);
}
}, params, ctx, ',');
}
private _visitIdentifier(value: CompileIdentifierMetadata, typeParams: o.Type[],
ctx: EmitterVisitorContext): void {
if (isBlank(value.name)) {
throw new BaseException(`Internal error: unknown identifier ${value}`);
}
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(`>`);
}
}
}

View File

@ -1,420 +0,0 @@
import {isPresent, isBlank, isArray, normalizeBlank} from '../src/facade/lang';
import {ListWrapper} from '../src/facade/collection';
import {
VariableAst,
AttrAst,
DirectiveAst,
ProviderAst,
ProviderAstType,
ReferenceAst
} from './template_ast';
import {
CompileTypeMetadata,
CompileTokenMap,
CompileQueryMetadata,
CompileTokenMetadata,
CompileProviderMetadata,
CompileDirectiveMetadata,
CompileDiDependencyMetadata
} from './compile_metadata';
import {Identifiers, identifierToken} from './identifiers';
import {ParseSourceSpan, ParseError} from './parse_util';
export class ProviderError extends ParseError {
constructor(message: string, span: ParseSourceSpan) { super(span, message); }
}
export class ProviderViewContext {
/**
* @internal
*/
viewQueries: CompileTokenMap<CompileQueryMetadata[]>;
/**
* @internal
*/
viewProviders: CompileTokenMap<boolean>;
errors: ProviderError[] = [];
constructor(public component: CompileDirectiveMetadata, public sourceSpan: ParseSourceSpan) {
this.viewQueries = _getViewQueries(component);
this.viewProviders = new CompileTokenMap<boolean>();
_normalizeProviders(component.viewProviders, sourceSpan, this.errors)
.forEach((provider) => {
if (isBlank(this.viewProviders.get(provider.token))) {
this.viewProviders.add(provider.token, true);
}
});
}
}
export class ProviderElementContext {
private _contentQueries: CompileTokenMap<CompileQueryMetadata[]>;
private _transformedProviders = new CompileTokenMap<ProviderAst>();
private _seenProviders = new CompileTokenMap<boolean>();
private _allProviders: CompileTokenMap<ProviderAst>;
private _attrs: {[key: string]: string};
private _hasViewContainer: boolean = false;
constructor(private _viewContext: ProviderViewContext, private _parent: ProviderElementContext,
private _isViewRoot: boolean, private _directiveAsts: DirectiveAst[],
attrs: AttrAst[], refs: ReferenceAst[], private _sourceSpan: ParseSourceSpan) {
this._attrs = {};
attrs.forEach((attrAst) => this._attrs[attrAst.name] = attrAst.value);
var directivesMeta = _directiveAsts.map(directiveAst => directiveAst.directive);
this._allProviders =
_resolveProvidersFromDirectives(directivesMeta, _sourceSpan, _viewContext.errors);
this._contentQueries = _getContentQueries(directivesMeta);
var queriedTokens = new CompileTokenMap<boolean>();
this._allProviders.values().forEach(
(provider) => { this._addQueryReadsTo(provider.token, queriedTokens); });
refs.forEach((refAst) => {
this._addQueryReadsTo(new CompileTokenMetadata({value: refAst.name}), queriedTokens);
});
if (isPresent(queriedTokens.get(identifierToken(Identifiers.ViewContainerRef)))) {
this._hasViewContainer = true;
}
// create the providers that we know are eager first
this._allProviders.values().forEach((provider) => {
var eager = provider.eager || isPresent(queriedTokens.get(provider.token));
if (eager) {
this._getOrCreateLocalProvider(provider.providerType, provider.token, true);
}
});
}
afterElement() {
// collect lazy providers
this._allProviders.values().forEach((provider) => {
this._getOrCreateLocalProvider(provider.providerType, provider.token, false);
});
}
get transformProviders(): ProviderAst[] { return this._transformedProviders.values(); }
get transformedDirectiveAsts(): DirectiveAst[] {
var sortedProviderTypes =
this._transformedProviders.values().map(provider => provider.token.identifier);
var sortedDirectives = ListWrapper.clone(this._directiveAsts);
ListWrapper.sort(sortedDirectives,
(dir1, dir2) => sortedProviderTypes.indexOf(dir1.directive.type) -
sortedProviderTypes.indexOf(dir2.directive.type));
return sortedDirectives;
}
get transformedHasViewContainer(): boolean { return this._hasViewContainer; }
private _addQueryReadsTo(token: CompileTokenMetadata, queryReadTokens: CompileTokenMap<boolean>) {
this._getQueriesFor(token).forEach((query) => {
var queryReadToken = isPresent(query.read) ? query.read : token;
if (isBlank(queryReadTokens.get(queryReadToken))) {
queryReadTokens.add(queryReadToken, true);
}
});
}
private _getQueriesFor(token: CompileTokenMetadata): CompileQueryMetadata[] {
var result: CompileQueryMetadata[] = [];
var currentEl: ProviderElementContext = this;
var distance = 0;
var queries: CompileQueryMetadata[];
while (currentEl !== null) {
queries = currentEl._contentQueries.get(token);
if (isPresent(queries)) {
ListWrapper.addAll(result, queries.filter((query) => query.descendants || distance <= 1));
}
if (currentEl._directiveAsts.length > 0) {
distance++;
}
currentEl = currentEl._parent;
}
queries = this._viewContext.viewQueries.get(token);
if (isPresent(queries)) {
ListWrapper.addAll(result, queries);
}
return result;
}
private _getOrCreateLocalProvider(requestingProviderType: ProviderAstType,
token: CompileTokenMetadata, eager: boolean): ProviderAst {
var resolvedProvider = this._allProviders.get(token);
if (isBlank(resolvedProvider) ||
((requestingProviderType === ProviderAstType.Directive ||
requestingProviderType === ProviderAstType.PublicService) &&
resolvedProvider.providerType === ProviderAstType.PrivateService) ||
((requestingProviderType === ProviderAstType.PrivateService ||
requestingProviderType === ProviderAstType.PublicService) &&
resolvedProvider.providerType === ProviderAstType.Builtin)) {
return null;
}
var transformedProviderAst = this._transformedProviders.get(token);
if (isPresent(transformedProviderAst)) {
return transformedProviderAst;
}
if (isPresent(this._seenProviders.get(token))) {
this._viewContext.errors.push(new ProviderError(
`Cannot instantiate cyclic dependency! ${token.name}`, this._sourceSpan));
return null;
}
this._seenProviders.add(token, true);
var transformedProviders = resolvedProvider.providers.map((provider) => {
var transformedUseValue = provider.useValue;
var transformedUseExisting = provider.useExisting;
var transformedDeps;
if (isPresent(provider.useExisting)) {
var existingDiDep = this._getDependency(
resolvedProvider.providerType,
new CompileDiDependencyMetadata({token: provider.useExisting}), eager);
if (isPresent(existingDiDep.token)) {
transformedUseExisting = existingDiDep.token;
} else {
transformedUseExisting = null;
transformedUseValue = existingDiDep.value;
}
} else if (isPresent(provider.useFactory)) {
var deps = isPresent(provider.deps) ? provider.deps : provider.useFactory.diDeps;
transformedDeps =
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager));
} else if (isPresent(provider.useClass)) {
var deps = isPresent(provider.deps) ? provider.deps : provider.useClass.diDeps;
transformedDeps =
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager));
}
return _transformProvider(provider, {
useExisting: transformedUseExisting,
useValue: transformedUseValue,
deps: transformedDeps
});
});
transformedProviderAst =
_transformProviderAst(resolvedProvider, {eager: eager, providers: transformedProviders});
this._transformedProviders.add(token, transformedProviderAst);
return transformedProviderAst;
}
private _getLocalDependency(requestingProviderType: ProviderAstType,
dep: CompileDiDependencyMetadata,
eager: boolean = null): CompileDiDependencyMetadata {
if (dep.isAttribute) {
var attrValue = this._attrs[dep.token.value];
return new CompileDiDependencyMetadata({isValue: true, value: normalizeBlank(attrValue)});
}
if (isPresent(dep.query) || isPresent(dep.viewQuery)) {
return dep;
}
if (isPresent(dep.token)) {
// access builtints
if ((requestingProviderType === ProviderAstType.Directive ||
requestingProviderType === ProviderAstType.Component)) {
if (dep.token.equalsTo(identifierToken(Identifiers.Renderer)) ||
dep.token.equalsTo(identifierToken(Identifiers.ElementRef)) ||
dep.token.equalsTo(identifierToken(Identifiers.ChangeDetectorRef)) ||
dep.token.equalsTo(identifierToken(Identifiers.TemplateRef))) {
return dep;
}
if (dep.token.equalsTo(identifierToken(Identifiers.ViewContainerRef))) {
this._hasViewContainer = true;
}
}
// access the injector
if (dep.token.equalsTo(identifierToken(Identifiers.Injector))) {
return dep;
}
// access providers
if (isPresent(this._getOrCreateLocalProvider(requestingProviderType, dep.token, eager))) {
return dep;
}
}
return null;
}
private _getDependency(requestingProviderType: ProviderAstType, dep: CompileDiDependencyMetadata,
eager: boolean = null): CompileDiDependencyMetadata {
var currElement: ProviderElementContext = this;
var currEager: boolean = eager;
var result: CompileDiDependencyMetadata = null;
if (!dep.isSkipSelf) {
result = this._getLocalDependency(requestingProviderType, dep, eager);
}
if (dep.isSelf) {
if (isBlank(result) && dep.isOptional) {
result = new CompileDiDependencyMetadata({isValue: true, value: null});
}
} else {
// check parent elements
while (isBlank(result) && isPresent(currElement._parent)) {
var prevElement = currElement;
currElement = currElement._parent;
if (prevElement._isViewRoot) {
currEager = false;
}
result = currElement._getLocalDependency(ProviderAstType.PublicService, dep, currEager);
}
// check @Host restriction
if (isBlank(result)) {
if (!dep.isHost || this._viewContext.component.type.isHost ||
identifierToken(this._viewContext.component.type).equalsTo(dep.token) ||
isPresent(this._viewContext.viewProviders.get(dep.token))) {
result = dep;
} else {
result = dep.isOptional ?
result = new CompileDiDependencyMetadata({isValue: true, value: null}) :
null;
}
}
}
if (isBlank(result)) {
this._viewContext.errors.push(
new ProviderError(`No provider for ${dep.token.name}`, this._sourceSpan));
}
return result;
}
}
function _transformProvider(
provider: CompileProviderMetadata,
{useExisting, useValue, deps}:
{useExisting: CompileTokenMetadata, useValue: any, deps: CompileDiDependencyMetadata[]}) {
return new CompileProviderMetadata({
token: provider.token,
useClass: provider.useClass,
useExisting: useExisting,
useFactory: provider.useFactory,
useValue: useValue,
deps: deps,
multi: provider.multi
});
}
function _transformProviderAst(
provider: ProviderAst,
{eager, providers}: {eager: boolean, providers: CompileProviderMetadata[]}): ProviderAst {
return new ProviderAst(provider.token, provider.multiProvider, provider.eager || eager, providers,
provider.providerType, provider.sourceSpan);
}
function _normalizeProviders(
providers: Array<CompileProviderMetadata | CompileTypeMetadata | any[]>,
sourceSpan: ParseSourceSpan, targetErrors: ParseError[],
targetProviders: CompileProviderMetadata[] = null): CompileProviderMetadata[] {
if (isBlank(targetProviders)) {
targetProviders = [];
}
if (isPresent(providers)) {
providers.forEach((provider) => {
if (isArray(provider)) {
_normalizeProviders(<any[]>provider, sourceSpan, targetErrors, targetProviders);
} else {
var normalizeProvider: CompileProviderMetadata;
if (provider instanceof CompileProviderMetadata) {
normalizeProvider = provider;
} else if (provider instanceof CompileTypeMetadata) {
normalizeProvider = new CompileProviderMetadata(
{token: new CompileTokenMetadata({identifier: provider}), useClass: provider});
} else {
targetErrors.push(new ProviderError(`Unknown provider type ${provider}`, sourceSpan));
}
if (isPresent(normalizeProvider)) {
targetProviders.push(normalizeProvider);
}
}
});
}
return targetProviders;
}
function _resolveProvidersFromDirectives(directives: CompileDirectiveMetadata[],
sourceSpan: ParseSourceSpan,
targetErrors: ParseError[]): CompileTokenMap<ProviderAst> {
var providersByToken = new CompileTokenMap<ProviderAst>();
directives.forEach((directive) => {
var dirProvider = new CompileProviderMetadata(
{token: new CompileTokenMetadata({identifier: directive.type}), useClass: directive.type});
_resolveProviders([dirProvider],
directive.isComponent ? ProviderAstType.Component : ProviderAstType.Directive,
true, sourceSpan, targetErrors, providersByToken);
});
// Note: directives need to be able to overwrite providers of a component!
var directivesWithComponentFirst =
directives.filter(dir => dir.isComponent).concat(directives.filter(dir => !dir.isComponent));
directivesWithComponentFirst.forEach((directive) => {
_resolveProviders(_normalizeProviders(directive.providers, sourceSpan, targetErrors),
ProviderAstType.PublicService, false, sourceSpan, targetErrors,
providersByToken);
_resolveProviders(_normalizeProviders(directive.viewProviders, sourceSpan, targetErrors),
ProviderAstType.PrivateService, false, sourceSpan, targetErrors,
providersByToken);
});
return providersByToken;
}
function _resolveProviders(providers: CompileProviderMetadata[], providerType: ProviderAstType,
eager: boolean, sourceSpan: ParseSourceSpan, targetErrors: ParseError[],
targetProvidersByToken: CompileTokenMap<ProviderAst>) {
providers.forEach((provider) => {
var resolvedProvider = targetProvidersByToken.get(provider.token);
if (isPresent(resolvedProvider) && resolvedProvider.multiProvider !== provider.multi) {
targetErrors.push(new ProviderError(
`Mixing multi and non multi provider is not possible for token ${resolvedProvider.token.name}`,
sourceSpan));
}
if (isBlank(resolvedProvider)) {
resolvedProvider = new ProviderAst(provider.token, provider.multi, eager, [provider],
providerType, sourceSpan);
targetProvidersByToken.add(provider.token, resolvedProvider);
} else {
if (!provider.multi) {
ListWrapper.clear(resolvedProvider.providers);
}
resolvedProvider.providers.push(provider);
}
});
}
function _getViewQueries(
component: CompileDirectiveMetadata): CompileTokenMap<CompileQueryMetadata[]> {
var viewQueries = new CompileTokenMap<CompileQueryMetadata[]>();
if (isPresent(component.viewQueries)) {
component.viewQueries.forEach((query) => _addQueryToTokenMap(viewQueries, query));
}
component.type.diDeps.forEach((dep) => {
if (isPresent(dep.viewQuery)) {
_addQueryToTokenMap(viewQueries, dep.viewQuery);
}
});
return viewQueries;
}
function _getContentQueries(
directives: CompileDirectiveMetadata[]): CompileTokenMap<CompileQueryMetadata[]> {
var contentQueries = new CompileTokenMap<CompileQueryMetadata[]>();
directives.forEach(directive => {
if (isPresent(directive.queries)) {
directive.queries.forEach((query) => _addQueryToTokenMap(contentQueries, query));
}
directive.type.diDeps.forEach((dep) => {
if (isPresent(dep.query)) {
_addQueryToTokenMap(contentQueries, dep.query);
}
});
});
return contentQueries;
}
function _addQueryToTokenMap(map: CompileTokenMap<CompileQueryMetadata[]>,
query: CompileQueryMetadata) {
query.selectors.forEach((token: CompileTokenMetadata) => {
var entry = map.get(token);
if (isBlank(entry)) {
entry = [];
map.add(token, entry);
}
entry.push(query);
});
}

View File

@ -1,210 +0,0 @@
import {Injectable, ComponentFactory, ComponentResolver} from '@angular/core';
import {
IS_DART,
Type,
isBlank,
} from '../src/facade/lang';
import {BaseException} from '../src/facade/exceptions';
import {
ListWrapper,
} from '../src/facade/collection';
import {PromiseWrapper} from '../src/facade/async';
import {
createHostComponentMeta,
CompileDirectiveMetadata,
CompilePipeMetadata,
CompileIdentifierMetadata
} from './compile_metadata';
import {
TemplateAst,
} from './template_ast';
import {StyleCompiler, StylesCompileDependency, StylesCompileResult} from './style_compiler';
import {ViewCompiler} from './view_compiler/view_compiler';
import {TemplateParser} from './template_parser';
import {DirectiveNormalizer} from './directive_normalizer';
import {CompileMetadataResolver} from './metadata_resolver';
import {CompilerConfig} from './config';
import * as ir from './output/output_ast';
import {jitStatements} from './output/output_jit';
import {interpretStatements} from './output/output_interpreter';
import {InterpretiveAppViewInstanceFactory} from './output/interpretive_view';
import {XHR} from './xhr';
/**
* An internal module of the Angular compiler that begins with component types,
* extracts templates, and eventually produces a compiled version of the component
* ready for linking into an application.
*/
@Injectable()
export class RuntimeCompiler implements ComponentResolver {
private _styleCache: Map<string, Promise<string>> = new Map<string, Promise<string>>();
private _hostCacheKeys = new Map<Type, any>();
private _compiledTemplateCache = new Map<any, CompiledTemplate>();
private _compiledTemplateDone = new Map<any, Promise<CompiledTemplate>>();
constructor(private _metadataResolver: CompileMetadataResolver,
private _templateNormalizer: DirectiveNormalizer,
private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler,
private _viewCompiler: ViewCompiler, private _xhr: XHR,
private _genConfig: CompilerConfig) {}
resolveComponent(componentType: Type): Promise<ComponentFactory<any>> {
var compMeta: CompileDirectiveMetadata =
this._metadataResolver.getDirectiveMetadata(componentType);
var hostCacheKey = this._hostCacheKeys.get(componentType);
if (isBlank(hostCacheKey)) {
hostCacheKey = new Object();
this._hostCacheKeys.set(componentType, hostCacheKey);
assertComponent(compMeta);
var hostMeta: CompileDirectiveMetadata =
createHostComponentMeta(compMeta.type, compMeta.selector);
this._loadAndCompileComponent(hostCacheKey, hostMeta, [compMeta], [], []);
}
return this._compiledTemplateDone.get(hostCacheKey)
.then((compiledTemplate: CompiledTemplate) => new ComponentFactory(
compMeta.selector, compiledTemplate.viewFactory, componentType));
}
clearCache() {
this._styleCache.clear();
this._compiledTemplateCache.clear();
this._compiledTemplateDone.clear();
this._hostCacheKeys.clear();
}
private _loadAndCompileComponent(cacheKey: any, compMeta: CompileDirectiveMetadata,
viewDirectives: CompileDirectiveMetadata[],
pipes: CompilePipeMetadata[],
compilingComponentsPath: any[]): CompiledTemplate {
var compiledTemplate = this._compiledTemplateCache.get(cacheKey);
var done = this._compiledTemplateDone.get(cacheKey);
if (isBlank(compiledTemplate)) {
compiledTemplate = new CompiledTemplate();
this._compiledTemplateCache.set(cacheKey, compiledTemplate);
done =
PromiseWrapper.all(
[<any>this._compileComponentStyles(compMeta)].concat(viewDirectives.map(
dirMeta => this._templateNormalizer.normalizeDirective(dirMeta))))
.then((stylesAndNormalizedViewDirMetas: any[]) => {
var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1);
var styles = stylesAndNormalizedViewDirMetas[0];
var parsedTemplate =
this._templateParser.parse(compMeta, compMeta.template.template,
normalizedViewDirMetas, pipes, compMeta.type.name);
var childPromises = [];
compiledTemplate.init(this._compileComponent(compMeta, parsedTemplate, styles,
pipes, compilingComponentsPath,
childPromises));
return PromiseWrapper.all(childPromises).then((_) => { return compiledTemplate; });
});
this._compiledTemplateDone.set(cacheKey, done);
}
return compiledTemplate;
}
private _compileComponent(compMeta: CompileDirectiveMetadata, parsedTemplate: TemplateAst[],
styles: string[], pipes: CompilePipeMetadata[],
compilingComponentsPath: any[],
childPromises: Promise<any>[]): Function {
var compileResult = this._viewCompiler.compileComponent(
compMeta, parsedTemplate,
new ir.ExternalExpr(new CompileIdentifierMetadata({runtime: styles})), pipes);
compileResult.dependencies.forEach((dep) => {
var childCompilingComponentsPath = ListWrapper.clone(compilingComponentsPath);
var childCacheKey = dep.comp.type.runtime;
var childViewDirectives: CompileDirectiveMetadata[] =
this._metadataResolver.getViewDirectivesMetadata(dep.comp.type.runtime);
var childViewPipes: CompilePipeMetadata[] =
this._metadataResolver.getViewPipesMetadata(dep.comp.type.runtime);
var childIsRecursive = ListWrapper.contains(childCompilingComponentsPath, childCacheKey);
childCompilingComponentsPath.push(childCacheKey);
var childComp =
this._loadAndCompileComponent(dep.comp.type.runtime, dep.comp, childViewDirectives,
childViewPipes, childCompilingComponentsPath);
dep.factoryPlaceholder.runtime = childComp.proxyViewFactory;
dep.factoryPlaceholder.name = `viewFactory_${dep.comp.type.name}`;
if (!childIsRecursive) {
// Only wait for a child if it is not a cycle
childPromises.push(this._compiledTemplateDone.get(childCacheKey));
}
});
var factory;
if (IS_DART || !this._genConfig.useJit) {
factory = interpretStatements(compileResult.statements, compileResult.viewFactoryVar,
new InterpretiveAppViewInstanceFactory());
} else {
factory = jitStatements(`${compMeta.type.name}.template.js`, compileResult.statements,
compileResult.viewFactoryVar);
}
return factory;
}
private _compileComponentStyles(compMeta: CompileDirectiveMetadata): Promise<string[]> {
var compileResult = this._styleCompiler.compileComponent(compMeta);
return this._resolveStylesCompileResult(compMeta.type.name, compileResult);
}
private _resolveStylesCompileResult(sourceUrl: string,
result: StylesCompileResult): Promise<string[]> {
var promises = result.dependencies.map((dep) => this._loadStylesheetDep(dep));
return PromiseWrapper.all(promises)
.then((cssTexts) => {
var nestedCompileResultPromises = [];
for (var i = 0; i < result.dependencies.length; i++) {
var dep = result.dependencies[i];
var cssText = cssTexts[i];
var nestedCompileResult =
this._styleCompiler.compileStylesheet(dep.moduleUrl, cssText, dep.isShimmed);
nestedCompileResultPromises.push(
this._resolveStylesCompileResult(dep.moduleUrl, nestedCompileResult));
}
return PromiseWrapper.all(nestedCompileResultPromises);
})
.then((nestedStylesArr) => {
for (var i = 0; i < result.dependencies.length; i++) {
var dep = result.dependencies[i];
dep.valuePlaceholder.runtime = nestedStylesArr[i];
dep.valuePlaceholder.name = `importedStyles${i}`;
}
if (IS_DART || !this._genConfig.useJit) {
return interpretStatements(result.statements, result.stylesVar,
new InterpretiveAppViewInstanceFactory());
} else {
return jitStatements(`${sourceUrl}.css.js`, result.statements, result.stylesVar);
}
});
}
private _loadStylesheetDep(dep: StylesCompileDependency): Promise<string> {
var cacheKey = `${dep.moduleUrl}${dep.isShimmed ? '.shim' : ''}`;
var cssTextPromise = this._styleCache.get(cacheKey);
if (isBlank(cssTextPromise)) {
cssTextPromise = this._xhr.get(dep.moduleUrl);
this._styleCache.set(cacheKey, cssTextPromise);
}
return cssTextPromise;
}
}
class CompiledTemplate {
viewFactory: Function = null;
proxyViewFactory: Function;
constructor() {
this.proxyViewFactory = (viewUtils, childInjector, contextEl) =>
this.viewFactory(viewUtils, childInjector, contextEl);
}
init(viewFactory: Function) { this.viewFactory = viewFactory; }
}
function assertComponent(meta: CompileDirectiveMetadata) {
if (!meta.isComponent) {
throw new BaseException(`Could not compile '${meta.type.name}' because it is not a component.`);
}
}

View File

@ -1,261 +0,0 @@
import {Injectable} from '@angular/core';
import {isPresent} from '../facade/lang';
import {StringMapWrapper} from '../facade/collection';
import {ElementSchemaRegistry} from './element_schema_registry';
const EVENT = 'event';
const BOOLEAN = 'boolean';
const NUMBER = 'number';
const STRING = 'string';
const OBJECT = 'object';
/**
* This array represents the DOM schema. It encodes inheritance, properties, and events.
*
* ## Overview
*
* Each line represents one kind of element. The `element_inheritance` and properties are joined
* using `element_inheritance|preperties` syntax.
*
* ## Element Inheritance
*
* The `element_inheritance` can be further subdivided as `element1,element2,...^parentElement`.
* Here the individual elements are separated by `,` (commas). Every element in the list
* has identical properties.
*
* An `element` may inherit additional properties from `parentElement` If no `^parentElement` is
* specified then `""` (blank) element is assumed.
*
* NOTE: The blank element inherits from root `*` element, the super element of all elements.
*
* NOTE an element prefix such as `@svg:` has no special meaning to the schema.
*
* ## Properties
*
* Each element has a set of properties separated by `,` (commas). Each property can be prefixed
* by a special character designating its type:
*
* - (no prefix): property is a string.
* - `*`: property represents an event.
* - `!`: property is a boolean.
* - `#`: property is a number.
* - `%`: property is an object.
*
* ## Query
*
* The class creates an internal squas representaino which allows to easily answer the query of
* if a given property exist on a given element.
*
* NOTE: We don't yet support querying for types or events.
* NOTE: This schema is auto extracted from `schema_extractor.ts` located in the test folder.
*/
const SCHEMA: string[] =
/*@ts2dart_const*/ ([
'*|%classList,className,id,innerHTML,*beforecopy,*beforecut,*beforepaste,*copy,*cut,*paste,*search,*selectstart,*webkitfullscreenchange,*webkitfullscreenerror,*wheel,outerHTML,#scrollLeft,#scrollTop',
'^*|accessKey,contentEditable,dir,!draggable,!hidden,innerText,lang,*abort,*autocomplete,*autocompleteerror,*beforecopy,*beforecut,*beforepaste,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*copy,*cuechange,*cut,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*message,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*mozfullscreenchange,*mozfullscreenerror,*mozpointerlockchange,*mozpointerlockerror,*paste,*pause,*play,*playing,*progress,*ratechange,*reset,*resize,*scroll,*search,*seeked,*seeking,*select,*selectstart,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,*webglcontextcreationerror,*webglcontextlost,*webglcontextrestored,*webkitfullscreenchange,*webkitfullscreenerror,*wheel,outerText,!spellcheck,%style,#tabIndex,title,!translate',
'media|!autoplay,!controls,%crossOrigin,#currentTime,!defaultMuted,#defaultPlaybackRate,!disableRemotePlayback,!loop,!muted,*encrypted,#playbackRate,preload,src,#volume',
'@svg:^*|*abort,*autocomplete,*autocompleteerror,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,%style,#tabIndex',
'@svg:graphics^@svg:|',
'@svg:animation^@svg:|*begin,*end,*repeat',
'@svg:geometry^@svg:|',
'@svg:componentTransferFunction^@svg:|',
'@svg:gradient^@svg:|',
'@svg:textContent^@svg:graphics|',
'@svg:textPositioning^@svg:textContent|',
'a|charset,coords,download,hash,host,hostname,href,hreflang,name,password,pathname,ping,port,protocol,rel,rev,search,shape,target,text,type,username',
'area|alt,coords,hash,host,hostname,href,!noHref,password,pathname,ping,port,protocol,search,shape,target,username',
'audio^media|',
'br|clear',
'base|href,target',
'body|aLink,background,bgColor,link,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,text,vLink',
'button|!autofocus,!disabled,formAction,formEnctype,formMethod,!formNoValidate,formTarget,name,type,value',
'canvas|#height,#width',
'content|select',
'dl|!compact',
'datalist|',
'details|!open',
'dialog|!open,returnValue',
'dir|!compact',
'div|align',
'embed|align,height,name,src,type,width',
'fieldset|!disabled,name',
'font|color,face,size',
'form|acceptCharset,action,autocomplete,encoding,enctype,method,name,!noValidate,target',
'frame|frameBorder,longDesc,marginHeight,marginWidth,name,!noResize,scrolling,src',
'frameset|cols,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,rows',
'hr|align,color,!noShade,size,width',
'head|',
'h1,h2,h3,h4,h5,h6|align',
'html|version',
'iframe|align,!allowFullscreen,frameBorder,height,longDesc,marginHeight,marginWidth,name,%sandbox,scrolling,src,srcdoc,width',
'img|align,alt,border,%crossOrigin,#height,#hspace,!isMap,longDesc,lowsrc,name,sizes,src,srcset,useMap,#vspace,#width',
'input|accept,align,alt,autocapitalize,autocomplete,!autofocus,!checked,!defaultChecked,defaultValue,dirName,!disabled,%files,formAction,formEnctype,formMethod,!formNoValidate,formTarget,#height,!incremental,!indeterminate,max,#maxLength,min,#minLength,!multiple,name,pattern,placeholder,!readOnly,!required,selectionDirection,#selectionEnd,#selectionStart,#size,src,step,type,useMap,value,%valueAsDate,#valueAsNumber,#width',
'keygen|!autofocus,challenge,!disabled,keytype,name',
'li|type,#value',
'label|htmlFor',
'legend|align',
'link|as,charset,%crossOrigin,!disabled,href,hreflang,integrity,media,rel,%relList,rev,%sizes,target,type',
'map|name',
'marquee|behavior,bgColor,direction,height,#hspace,#loop,#scrollAmount,#scrollDelay,!trueSpeed,#vspace,width',
'menu|!compact',
'meta|content,httpEquiv,name,scheme',
'meter|#high,#low,#max,#min,#optimum,#value',
'ins,del|cite,dateTime',
'ol|!compact,!reversed,#start,type',
'object|align,archive,border,code,codeBase,codeType,data,!declare,height,#hspace,name,standby,type,useMap,#vspace,width',
'optgroup|!disabled,label',
'option|!defaultSelected,!disabled,label,!selected,text,value',
'output|defaultValue,%htmlFor,name,value',
'p|align',
'param|name,type,value,valueType',
'picture|',
'pre|#width',
'progress|#max,#value',
'q,blockquote,cite|',
'script|!async,charset,%crossOrigin,!defer,event,htmlFor,integrity,src,text,type',
'select|!autofocus,!disabled,#length,!multiple,name,!required,#selectedIndex,#size,value',
'shadow|',
'source|media,sizes,src,srcset,type',
'span|',
'style|!disabled,media,type',
'caption|align',
'th,td|abbr,align,axis,bgColor,ch,chOff,#colSpan,headers,height,!noWrap,#rowSpan,scope,vAlign,width',
'col,colgroup|align,ch,chOff,#span,vAlign,width',
'table|align,bgColor,border,%caption,cellPadding,cellSpacing,frame,rules,summary,%tFoot,%tHead,width',
'tr|align,bgColor,ch,chOff,vAlign',
'tfoot,thead,tbody|align,ch,chOff,vAlign',
'template|',
'textarea|autocapitalize,!autofocus,#cols,defaultValue,dirName,!disabled,#maxLength,#minLength,name,placeholder,!readOnly,!required,#rows,selectionDirection,#selectionEnd,#selectionStart,value,wrap',
'title|text',
'track|!default,kind,label,src,srclang',
'ul|!compact,type',
'unknown|',
'video^media|#height,poster,#width',
'@svg:a^@svg:graphics|',
'@svg:animate^@svg:animation|',
'@svg:animateMotion^@svg:animation|',
'@svg:animateTransform^@svg:animation|',
'@svg:circle^@svg:geometry|',
'@svg:clipPath^@svg:graphics|',
'@svg:cursor^@svg:|',
'@svg:defs^@svg:graphics|',
'@svg:desc^@svg:|',
'@svg:discard^@svg:|',
'@svg:ellipse^@svg:geometry|',
'@svg:feBlend^@svg:|',
'@svg:feColorMatrix^@svg:|',
'@svg:feComponentTransfer^@svg:|',
'@svg:feComposite^@svg:|',
'@svg:feConvolveMatrix^@svg:|',
'@svg:feDiffuseLighting^@svg:|',
'@svg:feDisplacementMap^@svg:|',
'@svg:feDistantLight^@svg:|',
'@svg:feDropShadow^@svg:|',
'@svg:feFlood^@svg:|',
'@svg:feFuncA^@svg:componentTransferFunction|',
'@svg:feFuncB^@svg:componentTransferFunction|',
'@svg:feFuncG^@svg:componentTransferFunction|',
'@svg:feFuncR^@svg:componentTransferFunction|',
'@svg:feGaussianBlur^@svg:|',
'@svg:feImage^@svg:|',
'@svg:feMerge^@svg:|',
'@svg:feMergeNode^@svg:|',
'@svg:feMorphology^@svg:|',
'@svg:feOffset^@svg:|',
'@svg:fePointLight^@svg:|',
'@svg:feSpecularLighting^@svg:|',
'@svg:feSpotLight^@svg:|',
'@svg:feTile^@svg:|',
'@svg:feTurbulence^@svg:|',
'@svg:filter^@svg:|',
'@svg:foreignObject^@svg:graphics|',
'@svg:g^@svg:graphics|',
'@svg:image^@svg:graphics|',
'@svg:line^@svg:geometry|',
'@svg:linearGradient^@svg:gradient|',
'@svg:mpath^@svg:|',
'@svg:marker^@svg:|',
'@svg:mask^@svg:|',
'@svg:metadata^@svg:|',
'@svg:path^@svg:geometry|',
'@svg:pattern^@svg:|',
'@svg:polygon^@svg:geometry|',
'@svg:polyline^@svg:geometry|',
'@svg:radialGradient^@svg:gradient|',
'@svg:rect^@svg:geometry|',
'@svg:svg^@svg:graphics|#currentScale,#zoomAndPan',
'@svg:script^@svg:|type',
'@svg:set^@svg:animation|',
'@svg:stop^@svg:|',
'@svg:style^@svg:|!disabled,media,title,type',
'@svg:switch^@svg:graphics|',
'@svg:symbol^@svg:|',
'@svg:tspan^@svg:textPositioning|',
'@svg:text^@svg:textPositioning|',
'@svg:textPath^@svg:textContent|',
'@svg:title^@svg:|',
'@svg:use^@svg:graphics|',
'@svg:view^@svg:|#zoomAndPan'
]);
var attrToPropMap: {[name: string]: string} = <any>{
'class': 'className',
'innerHtml': 'innerHTML',
'readonly': 'readOnly',
'tabindex': 'tabIndex'
};
@Injectable()
export class DomElementSchemaRegistry implements ElementSchemaRegistry {
schema = <{[element: string]: {[property: string]: string}}>{};
constructor() {
SCHEMA.forEach(encodedType => {
var parts = encodedType.split('|');
var properties = parts[1].split(',');
var typeParts = (parts[0] + '^').split('^');
var typeName = typeParts[0];
var type = <{[property: string]: string}>{};
typeName.split(',').forEach(tag => this.schema[tag] = type);
var superType = this.schema[typeParts[1]];
if (isPresent(superType)) {
StringMapWrapper.forEach(superType, (v, k) => type[k] = v);
}
properties.forEach((property: string) => {
if (property == '') {
} else if (property.startsWith('*')) {
// We don't yet support events.
// type[property.substring(1)] = EVENT;
} else if (property.startsWith('!')) {
type[property.substring(1)] = BOOLEAN;
} else if (property.startsWith('#')) {
type[property.substring(1)] = NUMBER;
} else if (property.startsWith('%')) {
type[property.substring(1)] = OBJECT;
} else {
type[property] = STRING;
}
});
});
}
hasProperty(tagName: string, propName: string): boolean {
if (tagName.indexOf('-') !== -1) {
// can't tell now as we don't know which properties a custom element will get
// once it is instantiated
return true;
} else {
var elementProperties = this.schema[tagName.toLowerCase()];
if (!isPresent(elementProperties)) {
elementProperties = this.schema['unknown'];
}
return isPresent(elementProperties[propName]);
}
}
getMappedPropName(propName: string): string {
var mappedPropName = StringMapWrapper.get(attrToPropMap, propName);
return isPresent(mappedPropName) ? mappedPropName : propName;
}
}

View File

@ -1,72 +0,0 @@
import {ViewEncapsulation, Injectable} from '@angular/core';
import {CompileIdentifierMetadata, CompileDirectiveMetadata} from './compile_metadata';
import * as o from './output/output_ast';
import {ShadowCss} from './shadow_css';
import {UrlResolver} from './url_resolver';
import {extractStyleUrls} from './style_url_resolver';
import {isPresent} from '../src/facade/lang';
const COMPONENT_VARIABLE = '%COMP%';
const HOST_ATTR = /*@ts2dart_const*/ `_nghost-${COMPONENT_VARIABLE}`;
const CONTENT_ATTR = /*@ts2dart_const*/ `_ngcontent-${COMPONENT_VARIABLE}`;
export class StylesCompileDependency {
constructor(public moduleUrl: string, public isShimmed: boolean,
public valuePlaceholder: CompileIdentifierMetadata) {}
}
export class StylesCompileResult {
constructor(public statements: o.Statement[], public stylesVar: string,
public dependencies: StylesCompileDependency[]) {}
}
@Injectable()
export class StyleCompiler {
private _shadowCss: ShadowCss = new ShadowCss();
constructor(private _urlResolver: UrlResolver) {}
compileComponent(comp: CompileDirectiveMetadata): StylesCompileResult {
var shim = comp.template.encapsulation === ViewEncapsulation.Emulated;
return this._compileStyles(getStylesVarName(comp), comp.template.styles,
comp.template.styleUrls, shim);
}
compileStylesheet(stylesheetUrl: string, cssText: string,
isShimmed: boolean): StylesCompileResult {
var styleWithImports = extractStyleUrls(this._urlResolver, stylesheetUrl, cssText);
return this._compileStyles(getStylesVarName(null), [styleWithImports.style],
styleWithImports.styleUrls, isShimmed);
}
private _compileStyles(stylesVar: string, plainStyles: string[], absUrls: string[],
shim: boolean): StylesCompileResult {
var styleExpressions =
plainStyles.map(plainStyle => o.literal(this._shimIfNeeded(plainStyle, shim)));
var dependencies = [];
for (var i = 0; i < absUrls.length; i++) {
var identifier = new CompileIdentifierMetadata({name: getStylesVarName(null)});
dependencies.push(new StylesCompileDependency(absUrls[i], shim, identifier));
styleExpressions.push(new o.ExternalExpr(identifier));
}
// styles variable contains plain strings and arrays of other styles arrays (recursive),
// so we set its type to dynamic.
var stmt = o.variable(stylesVar)
.set(o.literalArr(styleExpressions,
new o.ArrayType(o.DYNAMIC_TYPE, [o.TypeModifier.Const])))
.toDeclStmt(null, [o.StmtModifier.Final]);
return new StylesCompileResult([stmt], stylesVar, dependencies);
}
private _shimIfNeeded(style: string, shim: boolean): string {
return shim ? this._shadowCss.shimCssText(style, CONTENT_ATTR, HOST_ATTR) : style;
}
}
function getStylesVarName(component: CompileDirectiveMetadata): string {
var result = `styles`;
if (isPresent(component)) {
result += `_${component.type.name}`;
}
return result;
}

View File

@ -1,87 +0,0 @@
import {
IS_DART,
StringWrapper,
Math,
isBlank,
isArray,
isStrictStringMap,
isPrimitive
} from './facade/lang';
import {StringMapWrapper} from './facade/collection';
export var MODULE_SUFFIX = IS_DART ? '.dart' : '';
var CAMEL_CASE_REGEXP = /([A-Z])/g;
var DASH_CASE_REGEXP = /-([a-z])/g;
export function camelCaseToDashCase(input: string): string {
return StringWrapper.replaceAllMapped(input, CAMEL_CASE_REGEXP,
(m) => { return '-' + m[1].toLowerCase(); });
}
export function dashCaseToCamelCase(input: string): string {
return StringWrapper.replaceAllMapped(input, DASH_CASE_REGEXP,
(m) => { return m[1].toUpperCase(); });
}
export function splitAtColon(input: string, defaultValues: string[]): string[] {
var parts = StringWrapper.split(input.trim(), /\s*:\s*/g);
if (parts.length > 1) {
return parts;
} else {
return defaultValues;
}
}
export function sanitizeIdentifier(name: string): string {
return StringWrapper.replaceAll(name, /\W/g, '_');
}
export function visitValue(value: any, visitor: ValueVisitor, context: any): any {
if (isArray(value)) {
return visitor.visitArray(<any[]>value, context);
} else if (isStrictStringMap(value)) {
return visitor.visitStringMap(<{[key: string]: any}>value, context);
} else if (isBlank(value) || isPrimitive(value)) {
return visitor.visitPrimitive(value, context);
} else {
return visitor.visitOther(value, context);
}
}
export interface ValueVisitor {
visitArray(arr: any[], context: any): any;
visitStringMap(map: {[key: string]: any}, context: any): any;
visitPrimitive(value: any, context: any): any;
visitOther(value: any, context: any): any;
}
export class ValueTransformer implements ValueVisitor {
visitArray(arr: any[], context: any): any {
return arr.map(value => visitValue(value, this, context));
}
visitStringMap(map: {[key: string]: any}, context: any): any {
var result = {};
StringMapWrapper.forEach(map,
(value, key) => { result[key] = visitValue(value, this, context); });
return result;
}
visitPrimitive(value: any, context: any): any { return value; }
visitOther(value: any, context: any): any { return value; }
}
export function assetUrl(pkg: string, path: string = null, type: string = 'src'): string {
if (IS_DART) {
if (path == null) {
return `asset:angular2/${pkg}/${pkg}.dart`;
} else {
return `asset:angular2/lib/${pkg}/src/${path}.dart`;
}
} else {
if (path == null) {
return `asset:@angular/lib/${pkg}/index`;
} else {
return `asset:@angular/lib/${pkg}/src/${path}`;
}
}
}

View File

@ -1,6 +0,0 @@
import {CompileNode} from './compile_element';
import {TemplateAst} from '../template_ast';
export class CompileBinding {
constructor(public node: CompileNode, public sourceAst: TemplateAst) {}
}

View File

@ -1,427 +0,0 @@
import {BaseException} from '@angular/core';
import {isPresent, isBlank} from '../../src/facade/lang';
import {ListWrapper, StringMapWrapper} from '../../src/facade/collection';
import * as o from '../output/output_ast';
import {Identifiers, identifierToken} from '../identifiers';
import {InjectMethodVars} from './constants';
import {CompileView} from './compile_view';
import {TemplateAst, ProviderAst, ProviderAstType, ReferenceAst} from '../template_ast';
import {
CompileTokenMap,
CompileDirectiveMetadata,
CompileTokenMetadata,
CompileQueryMetadata,
CompileProviderMetadata,
CompileDiDependencyMetadata,
CompileIdentifierMetadata,
} from '../compile_metadata';
import {getPropertyInView, createDiTokenExpression, injectFromViewParentInjector} from './util';
import {CompileQuery, createQueryList, addQueryToTokenMap} from './compile_query';
import {CompileMethod} from './compile_method';
import {ValueTransformer, visitValue} from '../util';
export class CompileNode {
constructor(public parent: CompileElement, public view: CompileView, public nodeIndex: number,
public renderNode: o.Expression, public sourceAst: TemplateAst) {}
isNull(): boolean { return isBlank(this.renderNode); }
isRootElement(): boolean { return this.view != this.parent.view; }
}
export class CompileElement extends CompileNode {
static createNull(): CompileElement {
return new CompileElement(null, null, null, null, null, null, [], [], false, false, []);
}
private _compViewExpr: o.Expression = null;
public appElement: o.ReadPropExpr;
public elementRef: o.Expression;
public injector: o.Expression;
private _instances = new CompileTokenMap<o.Expression>();
private _resolvedProviders: CompileTokenMap<ProviderAst>;
private _queryCount = 0;
private _queries = new CompileTokenMap<CompileQuery[]>();
private _componentConstructorViewQueryLists: o.Expression[] = [];
public contentNodesByNgContentIndex: Array<o.Expression>[] = null;
public embeddedView: CompileView;
public directiveInstances: o.Expression[];
public referenceTokens: {[key: string]: CompileTokenMetadata};
constructor(parent: CompileElement, view: CompileView, nodeIndex: number,
renderNode: o.Expression, sourceAst: TemplateAst,
public component: CompileDirectiveMetadata,
private _directives: CompileDirectiveMetadata[],
private _resolvedProvidersArray: ProviderAst[], public hasViewContainer: boolean,
public hasEmbeddedView: boolean, references: ReferenceAst[]) {
super(parent, view, nodeIndex, renderNode, sourceAst);
this.referenceTokens = {};
references.forEach(ref => this.referenceTokens[ref.name] = ref.value);
this.elementRef = o.importExpr(Identifiers.ElementRef).instantiate([this.renderNode]);
this._instances.add(identifierToken(Identifiers.ElementRef), this.elementRef);
this.injector = o.THIS_EXPR.callMethod('injector', [o.literal(this.nodeIndex)]);
this._instances.add(identifierToken(Identifiers.Injector), this.injector);
this._instances.add(identifierToken(Identifiers.Renderer), o.THIS_EXPR.prop('renderer'));
if (this.hasViewContainer || this.hasEmbeddedView || isPresent(this.component)) {
this._createAppElement();
}
}
private _createAppElement() {
var fieldName = `_appEl_${this.nodeIndex}`;
var parentNodeIndex = this.isRootElement() ? null : this.parent.nodeIndex;
// private is fine here as no child view will reference an AppElement
this.view.fields.push(new o.ClassField(fieldName, o.importType(Identifiers.AppElement),
[o.StmtModifier.Private]));
var statement = o.THIS_EXPR.prop(fieldName)
.set(o.importExpr(Identifiers.AppElement)
.instantiate([
o.literal(this.nodeIndex),
o.literal(parentNodeIndex),
o.THIS_EXPR,
this.renderNode
]))
.toStmt();
this.view.createMethod.addStmt(statement);
this.appElement = o.THIS_EXPR.prop(fieldName);
this._instances.add(identifierToken(Identifiers.AppElement), this.appElement);
}
setComponentView(compViewExpr: o.Expression) {
this._compViewExpr = compViewExpr;
this.contentNodesByNgContentIndex =
ListWrapper.createFixedSize(this.component.template.ngContentSelectors.length);
for (var i = 0; i < this.contentNodesByNgContentIndex.length; i++) {
this.contentNodesByNgContentIndex[i] = [];
}
}
setEmbeddedView(embeddedView: CompileView) {
this.embeddedView = embeddedView;
if (isPresent(embeddedView)) {
var createTemplateRefExpr =
o.importExpr(Identifiers.TemplateRef_)
.instantiate([this.appElement, this.embeddedView.viewFactory]);
var provider = new CompileProviderMetadata(
{token: identifierToken(Identifiers.TemplateRef), useValue: createTemplateRefExpr});
// Add TemplateRef as first provider as it does not have deps on other providers
this._resolvedProvidersArray.unshift(new ProviderAst(provider.token, false, true, [provider],
ProviderAstType.Builtin,
this.sourceAst.sourceSpan));
}
}
beforeChildren(): void {
if (this.hasViewContainer) {
this._instances.add(identifierToken(Identifiers.ViewContainerRef),
this.appElement.prop('vcRef'));
}
this._resolvedProviders = new CompileTokenMap<ProviderAst>();
this._resolvedProvidersArray.forEach(provider =>
this._resolvedProviders.add(provider.token, provider));
// create all the provider instances, some in the view constructor,
// some as getters. We rely on the fact that they are already sorted topologically.
this._resolvedProviders.values().forEach((resolvedProvider) => {
var providerValueExpressions = resolvedProvider.providers.map((provider) => {
if (isPresent(provider.useExisting)) {
return this._getDependency(
resolvedProvider.providerType,
new CompileDiDependencyMetadata({token: provider.useExisting}));
} else if (isPresent(provider.useFactory)) {
var deps = isPresent(provider.deps) ? provider.deps : provider.useFactory.diDeps;
var depsExpr = deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep));
return o.importExpr(provider.useFactory).callFn(depsExpr);
} else if (isPresent(provider.useClass)) {
var deps = isPresent(provider.deps) ? provider.deps : provider.useClass.diDeps;
var depsExpr = deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep));
return o.importExpr(provider.useClass)
.instantiate(depsExpr, o.importType(provider.useClass));
} else {
return _convertValueToOutputAst(provider.useValue);
}
});
var propName = `_${resolvedProvider.token.name}_${this.nodeIndex}_${this._instances.size}`;
var instance =
createProviderProperty(propName, resolvedProvider, providerValueExpressions,
resolvedProvider.multiProvider, resolvedProvider.eager, this);
this._instances.add(resolvedProvider.token, instance);
});
this.directiveInstances =
this._directives.map((directive) => this._instances.get(identifierToken(directive.type)));
for (var i = 0; i < this.directiveInstances.length; i++) {
var directiveInstance = this.directiveInstances[i];
var directive = this._directives[i];
directive.queries.forEach((queryMeta) => { this._addQuery(queryMeta, directiveInstance); });
}
var queriesWithReads: _QueryWithRead[] = [];
this._resolvedProviders.values().forEach((resolvedProvider) => {
var queriesForProvider = this._getQueriesFor(resolvedProvider.token);
ListWrapper.addAll(
queriesWithReads,
queriesForProvider.map(query => new _QueryWithRead(query, resolvedProvider.token)));
});
StringMapWrapper.forEach(this.referenceTokens, (_, varName) => {
var token = this.referenceTokens[varName];
var varValue;
if (isPresent(token)) {
varValue = this._instances.get(token);
} else {
varValue = this.renderNode;
}
this.view.locals.set(varName, varValue);
var varToken = new CompileTokenMetadata({value: varName});
ListWrapper.addAll(queriesWithReads, this._getQueriesFor(varToken)
.map(query => new _QueryWithRead(query, varToken)));
});
queriesWithReads.forEach((queryWithRead) => {
var value: o.Expression;
if (isPresent(queryWithRead.read.identifier)) {
// query for an identifier
value = this._instances.get(queryWithRead.read);
} else {
// query for a reference
var token = this.referenceTokens[queryWithRead.read.value];
if (isPresent(token)) {
value = this._instances.get(token);
} else {
value = this.elementRef;
}
}
if (isPresent(value)) {
queryWithRead.query.addValue(value, this.view);
}
});
if (isPresent(this.component)) {
var componentConstructorViewQueryList =
isPresent(this.component) ? o.literalArr(this._componentConstructorViewQueryLists) :
o.NULL_EXPR;
var compExpr = isPresent(this.getComponent()) ? this.getComponent() : o.NULL_EXPR;
this.view.createMethod.addStmt(
this.appElement.callMethod(
'initComponent',
[compExpr, componentConstructorViewQueryList, this._compViewExpr])
.toStmt());
}
}
afterChildren(childNodeCount: number) {
this._resolvedProviders.values().forEach((resolvedProvider) => {
// Note: afterChildren is called after recursing into children.
// This is good so that an injector match in an element that is closer to a requesting element
// matches first.
var providerExpr = this._instances.get(resolvedProvider.token);
// Note: view providers are only visible on the injector of that element.
// This is not fully correct as the rules during codegen don't allow a directive
// to get hold of a view provdier on the same element. We still do this semantic
// as it simplifies our model to having only one runtime injector per element.
var providerChildNodeCount =
resolvedProvider.providerType === ProviderAstType.PrivateService ? 0 : childNodeCount;
this.view.injectorGetMethod.addStmt(createInjectInternalCondition(
this.nodeIndex, providerChildNodeCount, resolvedProvider, providerExpr));
});
this._queries.values().forEach(
(queries) =>
queries.forEach((query) => query.afterChildren(this.view.updateContentQueriesMethod)));
}
addContentNode(ngContentIndex: number, nodeExpr: o.Expression) {
this.contentNodesByNgContentIndex[ngContentIndex].push(nodeExpr);
}
getComponent(): o.Expression {
return isPresent(this.component) ? this._instances.get(identifierToken(this.component.type)) :
null;
}
getProviderTokens(): o.Expression[] {
return this._resolvedProviders.values().map(
(resolvedProvider) => createDiTokenExpression(resolvedProvider.token));
}
private _getQueriesFor(token: CompileTokenMetadata): CompileQuery[] {
var result: CompileQuery[] = [];
var currentEl: CompileElement = this;
var distance = 0;
var queries: CompileQuery[];
while (!currentEl.isNull()) {
queries = currentEl._queries.get(token);
if (isPresent(queries)) {
ListWrapper.addAll(result,
queries.filter((query) => query.meta.descendants || distance <= 1));
}
if (currentEl._directives.length > 0) {
distance++;
}
currentEl = currentEl.parent;
}
queries = this.view.componentView.viewQueries.get(token);
if (isPresent(queries)) {
ListWrapper.addAll(result, queries);
}
return result;
}
private _addQuery(queryMeta: CompileQueryMetadata,
directiveInstance: o.Expression): CompileQuery {
var propName = `_query_${queryMeta.selectors[0].name}_${this.nodeIndex}_${this._queryCount++}`;
var queryList = createQueryList(queryMeta, directiveInstance, propName, this.view);
var query = new CompileQuery(queryMeta, queryList, directiveInstance, this.view);
addQueryToTokenMap(this._queries, query);
return query;
}
private _getLocalDependency(requestingProviderType: ProviderAstType,
dep: CompileDiDependencyMetadata): o.Expression {
var result = null;
// constructor content query
if (isBlank(result) && isPresent(dep.query)) {
result = this._addQuery(dep.query, null).queryList;
}
// constructor view query
if (isBlank(result) && isPresent(dep.viewQuery)) {
result = createQueryList(
dep.viewQuery, null,
`_viewQuery_${dep.viewQuery.selectors[0].name}_${this.nodeIndex}_${this._componentConstructorViewQueryLists.length}`,
this.view);
this._componentConstructorViewQueryLists.push(result);
}
if (isPresent(dep.token)) {
// access builtins with special visibility
if (isBlank(result)) {
if (dep.token.equalsTo(identifierToken(Identifiers.ChangeDetectorRef))) {
if (requestingProviderType === ProviderAstType.Component) {
return this._compViewExpr.prop('ref');
} else {
return getPropertyInView(o.THIS_EXPR.prop('ref'), this.view, this.view.componentView);
}
}
}
// access regular providers on the element
if (isBlank(result)) {
result = this._instances.get(dep.token);
}
}
return result;
}
private _getDependency(requestingProviderType: ProviderAstType,
dep: CompileDiDependencyMetadata): o.Expression {
var currElement: CompileElement = this;
var result = null;
if (dep.isValue) {
result = o.literal(dep.value);
}
if (isBlank(result) && !dep.isSkipSelf) {
result = this._getLocalDependency(requestingProviderType, dep);
}
// check parent elements
while (isBlank(result) && !currElement.parent.isNull()) {
currElement = currElement.parent;
result = currElement._getLocalDependency(ProviderAstType.PublicService,
new CompileDiDependencyMetadata({token: dep.token}));
}
if (isBlank(result)) {
result = injectFromViewParentInjector(dep.token, dep.isOptional);
}
if (isBlank(result)) {
result = o.NULL_EXPR;
}
return getPropertyInView(result, this.view, currElement.view);
}
}
function createInjectInternalCondition(nodeIndex: number, childNodeCount: number,
provider: ProviderAst,
providerExpr: o.Expression): o.Statement {
var indexCondition;
if (childNodeCount > 0) {
indexCondition = o.literal(nodeIndex)
.lowerEquals(InjectMethodVars.requestNodeIndex)
.and(InjectMethodVars.requestNodeIndex.lowerEquals(
o.literal(nodeIndex + childNodeCount)));
} else {
indexCondition = o.literal(nodeIndex).identical(InjectMethodVars.requestNodeIndex);
}
return new o.IfStmt(
InjectMethodVars.token.identical(createDiTokenExpression(provider.token)).and(indexCondition),
[new o.ReturnStatement(providerExpr)]);
}
function createProviderProperty(propName: string, provider: ProviderAst,
providerValueExpressions: o.Expression[], isMulti: boolean,
isEager: boolean, compileElement: CompileElement): o.Expression {
var view = compileElement.view;
var resolvedProviderValueExpr;
var type;
if (isMulti) {
resolvedProviderValueExpr = o.literalArr(providerValueExpressions);
type = new o.ArrayType(o.DYNAMIC_TYPE);
} else {
resolvedProviderValueExpr = providerValueExpressions[0];
type = providerValueExpressions[0].type;
}
if (isBlank(type)) {
type = o.DYNAMIC_TYPE;
}
if (isEager) {
view.fields.push(new o.ClassField(propName, type));
view.createMethod.addStmt(o.THIS_EXPR.prop(propName).set(resolvedProviderValueExpr).toStmt());
} else {
var internalField = `_${propName}`;
view.fields.push(new o.ClassField(internalField, type));
var getter = new CompileMethod(view);
getter.resetDebugInfo(compileElement.nodeIndex, compileElement.sourceAst);
// Note: Equals is important for JS so that it also checks the undefined case!
getter.addStmt(
new o.IfStmt(o.THIS_EXPR.prop(internalField).isBlank(),
[o.THIS_EXPR.prop(internalField).set(resolvedProviderValueExpr).toStmt()]));
getter.addStmt(new o.ReturnStatement(o.THIS_EXPR.prop(internalField)));
view.getters.push(new o.ClassGetter(propName, getter.finish(), type));
}
return o.THIS_EXPR.prop(propName);
}
class _QueryWithRead {
public read: CompileTokenMetadata;
constructor(public query: CompileQuery, match: CompileTokenMetadata) {
this.read = isPresent(query.meta.read) ? query.meta.read : match;
}
}
function _convertValueToOutputAst(value: any): o.Expression {
return visitValue(value, new _ValueOutputAstTransformer(), null);
}
class _ValueOutputAstTransformer extends ValueTransformer {
visitArray(arr: any[], context: any): o.Expression {
return o.literalArr(arr.map(value => visitValue(value, this, context)));
}
visitStringMap(map: {[key: string]: any}, context: any): o.Expression {
var entries = [];
StringMapWrapper.forEach(
map, (value, key) => { entries.push([key, visitValue(value, this, context)]); });
return o.literalMap(entries);
}
visitPrimitive(value: any, context: any): o.Expression { return o.literal(value); }
visitOther(value: any, context: any): o.Expression {
if (value instanceof CompileIdentifierMetadata) {
return o.importExpr(value);
} else if (value instanceof o.Expression) {
return value;
} else {
throw new BaseException(`Illegal state: Don't now how to compile value ${value}`);
}
}
}

View File

@ -1,75 +0,0 @@
import {isPresent} from '../../src/facade/lang';
import {ListWrapper} from '../../src/facade/collection';
import * as o from '../output/output_ast';
import {TemplateAst} from '../template_ast';
import {CompileView} from './compile_view';
class _DebugState {
constructor(public nodeIndex: number, public sourceAst: TemplateAst) {}
}
var NULL_DEBUG_STATE = new _DebugState(null, null);
export class CompileMethod {
private _newState: _DebugState = NULL_DEBUG_STATE;
private _currState: _DebugState = NULL_DEBUG_STATE;
private _debugEnabled: boolean;
private _bodyStatements: o.Statement[] = [];
constructor(private _view: CompileView) {
this._debugEnabled = this._view.genConfig.genDebugInfo;
}
private _updateDebugContextIfNeeded() {
if (this._newState.nodeIndex !== this._currState.nodeIndex ||
this._newState.sourceAst !== this._currState.sourceAst) {
var expr = this._updateDebugContext(this._newState);
if (isPresent(expr)) {
this._bodyStatements.push(expr.toStmt());
}
}
}
private _updateDebugContext(newState: _DebugState): o.Expression {
this._currState = this._newState = newState;
if (this._debugEnabled) {
var sourceLocation =
isPresent(newState.sourceAst) ? newState.sourceAst.sourceSpan.start : null;
return o.THIS_EXPR.callMethod('debug', [
o.literal(newState.nodeIndex),
isPresent(sourceLocation) ? o.literal(sourceLocation.line) : o.NULL_EXPR,
isPresent(sourceLocation) ? o.literal(sourceLocation.col) : o.NULL_EXPR
]);
} else {
return null;
}
}
resetDebugInfoExpr(nodeIndex: number, templateAst: TemplateAst): o.Expression {
var res = this._updateDebugContext(new _DebugState(nodeIndex, templateAst));
return isPresent(res) ? res : o.NULL_EXPR;
}
resetDebugInfo(nodeIndex: number, templateAst: TemplateAst) {
this._newState = new _DebugState(nodeIndex, templateAst);
}
addStmt(stmt: o.Statement) {
this._updateDebugContextIfNeeded();
this._bodyStatements.push(stmt);
}
addStmts(stmts: o.Statement[]) {
this._updateDebugContextIfNeeded();
ListWrapper.addAll(this._bodyStatements, stmts);
}
finish(): o.Statement[] { return this._bodyStatements; }
isEmpty(): boolean { return this._bodyStatements.length === 0; }
}

View File

@ -1,75 +0,0 @@
import {isBlank, isPresent} from '../facade/lang';
import {BaseException} from '../facade/exceptions';
import * as o from '../output/output_ast';
import {CompileView} from './compile_view';
import {CompilePipeMetadata} from '../compile_metadata';
import {Identifiers, identifierToken} from '../identifiers';
import {injectFromViewParentInjector, createPureProxy, getPropertyInView} from './util';
class _PurePipeProxy {
constructor(public instance: o.ReadPropExpr, public argCount: number) {}
}
export class CompilePipe {
meta: CompilePipeMetadata;
instance: o.ReadPropExpr;
private _purePipeProxies: _PurePipeProxy[] = [];
constructor(public view: CompileView, name: string) {
this.meta = _findPipeMeta(view, name);
this.instance = o.THIS_EXPR.prop(`_pipe_${name}_${view.pipeCount++}`);
}
get pure(): boolean { return this.meta.pure; }
create(): void {
var deps = this.meta.type.diDeps.map((diDep) => {
if (diDep.token.equalsTo(identifierToken(Identifiers.ChangeDetectorRef))) {
return getPropertyInView(o.THIS_EXPR.prop('ref'), this.view, this.view.componentView);
}
return injectFromViewParentInjector(diDep.token, false);
});
this.view.fields.push(new o.ClassField(this.instance.name, o.importType(this.meta.type)));
this.view.createMethod.resetDebugInfo(null, null);
this.view.createMethod.addStmt(o.THIS_EXPR.prop(this.instance.name)
.set(o.importExpr(this.meta.type).instantiate(deps))
.toStmt());
this._purePipeProxies.forEach((purePipeProxy) => {
createPureProxy(
this.instance.prop('transform').callMethod(o.BuiltinMethod.bind, [this.instance]),
purePipeProxy.argCount, purePipeProxy.instance, this.view);
});
}
call(callingView: CompileView, args: o.Expression[]): o.Expression {
if (this.meta.pure) {
var purePipeProxy = new _PurePipeProxy(
o.THIS_EXPR.prop(`${this.instance.name}_${this._purePipeProxies.length}`), args.length);
this._purePipeProxies.push(purePipeProxy);
return getPropertyInView(
o.importExpr(Identifiers.castByValue)
.callFn([purePipeProxy.instance, this.instance.prop('transform')]),
callingView, this.view)
.callFn(args);
} else {
return getPropertyInView(this.instance, callingView, this.view).callMethod('transform', args);
}
}
}
function _findPipeMeta(view: CompileView, name: string): CompilePipeMetadata {
var pipeMeta: CompilePipeMetadata = null;
for (var i = view.pipeMetas.length - 1; i >= 0; i--) {
var localPipeMeta = view.pipeMetas[i];
if (localPipeMeta.name == name) {
pipeMeta = localPipeMeta;
break;
}
}
if (isBlank(pipeMeta)) {
throw new BaseException(
`Illegal state: Could not find pipe ${name} although the parser should have detected this error!`);
}
return pipeMeta;
}

View File

@ -1,113 +0,0 @@
import {isPresent, isBlank} from '../../src/facade/lang';
import {ListWrapper} from '../../src/facade/collection';
import * as o from '../output/output_ast';
import {Identifiers} from '../identifiers';
import {CompileQueryMetadata, CompileTokenMap} from '../compile_metadata';
import {CompileView} from './compile_view';
import {CompileElement} from './compile_element';
import {CompileMethod} from './compile_method';
import {getPropertyInView} from './util';
class ViewQueryValues {
constructor(public view: CompileView, public values: Array<o.Expression | ViewQueryValues>) {}
}
export class CompileQuery {
private _values: ViewQueryValues;
constructor(public meta: CompileQueryMetadata, public queryList: o.Expression,
public ownerDirectiveExpression: o.Expression, public view: CompileView) {
this._values = new ViewQueryValues(view, []);
}
addValue(value: o.Expression, view: CompileView) {
var currentView = view;
var elPath: CompileElement[] = [];
while (isPresent(currentView) && currentView !== this.view) {
var parentEl = currentView.declarationElement;
elPath.unshift(parentEl);
currentView = parentEl.view;
}
var queryListForDirtyExpr = getPropertyInView(this.queryList, view, this.view);
var viewValues = this._values;
elPath.forEach((el) => {
var last =
viewValues.values.length > 0 ? viewValues.values[viewValues.values.length - 1] : null;
if (last instanceof ViewQueryValues && last.view === el.embeddedView) {
viewValues = last;
} else {
var newViewValues = new ViewQueryValues(el.embeddedView, []);
viewValues.values.push(newViewValues);
viewValues = newViewValues;
}
});
viewValues.values.push(value);
if (elPath.length > 0) {
view.dirtyParentQueriesMethod.addStmt(
queryListForDirtyExpr.callMethod('setDirty', []).toStmt());
}
}
afterChildren(targetMethod: CompileMethod) {
var values = createQueryValues(this._values);
var updateStmts = [this.queryList.callMethod('reset', [o.literalArr(values)]).toStmt()];
if (isPresent(this.ownerDirectiveExpression)) {
var valueExpr = this.meta.first ? this.queryList.prop('first') : this.queryList;
updateStmts.push(
this.ownerDirectiveExpression.prop(this.meta.propertyName).set(valueExpr).toStmt());
}
if (!this.meta.first) {
updateStmts.push(this.queryList.callMethod('notifyOnChanges', []).toStmt());
}
targetMethod.addStmt(new o.IfStmt(this.queryList.prop('dirty'), updateStmts));
}
}
function createQueryValues(viewValues: ViewQueryValues): o.Expression[] {
return ListWrapper.flatten(viewValues.values.map((entry) => {
if (entry instanceof ViewQueryValues) {
return mapNestedViews(entry.view.declarationElement.appElement, entry.view,
createQueryValues(entry));
} else {
return <o.Expression>entry;
}
}));
}
function mapNestedViews(declarationAppElement: o.Expression, view: CompileView,
expressions: o.Expression[]): o.Expression {
var adjustedExpressions: o.Expression[] = expressions.map((expr) => {
return o.replaceVarInExpression(o.THIS_EXPR.name, o.variable('nestedView'), expr);
});
return declarationAppElement.callMethod('mapNestedViews', [
o.variable(view.className),
o.fn([new o.FnParam('nestedView', view.classType)],
[new o.ReturnStatement(o.literalArr(adjustedExpressions))])
]);
}
export function createQueryList(query: CompileQueryMetadata, directiveInstance: o.Expression,
propertyName: string, compileView: CompileView): o.Expression {
compileView.fields.push(new o.ClassField(propertyName, o.importType(Identifiers.QueryList)));
var expr = o.THIS_EXPR.prop(propertyName);
compileView.createMethod.addStmt(o.THIS_EXPR.prop(propertyName)
.set(o.importExpr(Identifiers.QueryList).instantiate([]))
.toStmt());
return expr;
}
export function addQueryToTokenMap(map: CompileTokenMap<CompileQuery[]>, query: CompileQuery) {
query.meta.selectors.forEach((selector) => {
var entry = map.get(selector);
if (isBlank(entry)) {
entry = [];
map.add(selector, entry);
}
entry.push(query);
});
}

View File

@ -1,210 +0,0 @@
import {ViewType} from '../../core_private';
import {isPresent, isBlank} from '../../src/facade/lang';
import {ListWrapper} from '../../src/facade/collection';
import * as o from '../output/output_ast';
import {EventHandlerVars} from './constants';
import {CompileQuery, createQueryList, addQueryToTokenMap} from './compile_query';
import {NameResolver} from './expression_converter';
import {CompileElement, CompileNode} from './compile_element';
import {CompileMethod} from './compile_method';
import {CompilePipe} from './compile_pipe';
import {
CompileDirectiveMetadata,
CompilePipeMetadata,
CompileIdentifierMetadata,
CompileTokenMap
} from '../compile_metadata';
import {
getViewFactoryName,
injectFromViewParentInjector,
createDiTokenExpression,
getPropertyInView,
createPureProxy
} from './util';
import {CompilerConfig} from '../config';
import {CompileBinding} from './compile_binding';
import {Identifiers} from '../identifiers';
export class CompileView implements NameResolver {
public viewType: ViewType;
public viewQueries: CompileTokenMap<CompileQuery[]>;
public nodes: CompileNode[] = [];
// root nodes or AppElements for ViewContainers
public rootNodesOrAppElements: o.Expression[] = [];
public bindings: CompileBinding[] = [];
public classStatements: o.Statement[] = [];
public createMethod: CompileMethod;
public injectorGetMethod: CompileMethod;
public updateContentQueriesMethod: CompileMethod;
public dirtyParentQueriesMethod: CompileMethod;
public updateViewQueriesMethod: CompileMethod;
public detectChangesInInputsMethod: CompileMethod;
public detectChangesRenderPropertiesMethod: CompileMethod;
public afterContentLifecycleCallbacksMethod: CompileMethod;
public afterViewLifecycleCallbacksMethod: CompileMethod;
public destroyMethod: CompileMethod;
public eventHandlerMethods: o.ClassMethod[] = [];
public fields: o.ClassField[] = [];
public getters: o.ClassGetter[] = [];
public disposables: o.Expression[] = [];
public subscriptions: o.Expression[] = [];
public componentView: CompileView;
public purePipes = new Map<string, CompilePipe>();
public pipes: CompilePipe[] = [];
public locals = new Map<string, o.Expression>();
public className: string;
public classType: o.Type;
public viewFactory: o.ReadVarExpr;
public literalArrayCount = 0;
public literalMapCount = 0;
public pipeCount = 0;
public componentContext: o.Expression;
constructor(public component: CompileDirectiveMetadata, public genConfig: CompilerConfig,
public pipeMetas: CompilePipeMetadata[], public styles: o.Expression,
public viewIndex: number, public declarationElement: CompileElement,
public templateVariableBindings: string[][]) {
this.createMethod = new CompileMethod(this);
this.injectorGetMethod = new CompileMethod(this);
this.updateContentQueriesMethod = new CompileMethod(this);
this.dirtyParentQueriesMethod = new CompileMethod(this);
this.updateViewQueriesMethod = new CompileMethod(this);
this.detectChangesInInputsMethod = new CompileMethod(this);
this.detectChangesRenderPropertiesMethod = new CompileMethod(this);
this.afterContentLifecycleCallbacksMethod = new CompileMethod(this);
this.afterViewLifecycleCallbacksMethod = new CompileMethod(this);
this.destroyMethod = new CompileMethod(this);
this.viewType = getViewType(component, viewIndex);
this.className = `_View_${component.type.name}${viewIndex}`;
this.classType = o.importType(new CompileIdentifierMetadata({name: this.className}));
this.viewFactory = o.variable(getViewFactoryName(component, viewIndex));
if (this.viewType === ViewType.COMPONENT || this.viewType === ViewType.HOST) {
this.componentView = this;
} else {
this.componentView = this.declarationElement.view.componentView;
}
this.componentContext =
getPropertyInView(o.THIS_EXPR.prop('context'), this, this.componentView);
var viewQueries = new CompileTokenMap<CompileQuery[]>();
if (this.viewType === ViewType.COMPONENT) {
var directiveInstance = o.THIS_EXPR.prop('context');
ListWrapper.forEachWithIndex(this.component.viewQueries, (queryMeta, queryIndex) => {
var propName = `_viewQuery_${queryMeta.selectors[0].name}_${queryIndex}`;
var queryList = createQueryList(queryMeta, directiveInstance, propName, this);
var query = new CompileQuery(queryMeta, queryList, directiveInstance, this);
addQueryToTokenMap(viewQueries, query);
});
var constructorViewQueryCount = 0;
this.component.type.diDeps.forEach((dep) => {
if (isPresent(dep.viewQuery)) {
var queryList = o.THIS_EXPR.prop('declarationAppElement')
.prop('componentConstructorViewQueries')
.key(o.literal(constructorViewQueryCount++));
var query = new CompileQuery(dep.viewQuery, queryList, null, this);
addQueryToTokenMap(viewQueries, query);
}
});
}
this.viewQueries = viewQueries;
templateVariableBindings.forEach(
(entry) => { this.locals.set(entry[1], o.THIS_EXPR.prop('context').prop(entry[0])); });
if (!this.declarationElement.isNull()) {
this.declarationElement.setEmbeddedView(this);
}
}
callPipe(name: string, input: o.Expression, args: o.Expression[]): o.Expression {
var compView = this.componentView;
var pipe = compView.purePipes.get(name);
if (isBlank(pipe)) {
pipe = new CompilePipe(compView, name);
if (pipe.pure) {
compView.purePipes.set(name, pipe);
}
compView.pipes.push(pipe);
}
return pipe.call(this, [input].concat(args));
}
getLocal(name: string): o.Expression {
if (name == EventHandlerVars.event.name) {
return EventHandlerVars.event;
}
var currView: CompileView = this;
var result = currView.locals.get(name);
while (isBlank(result) && isPresent(currView.declarationElement.view)) {
currView = currView.declarationElement.view;
result = currView.locals.get(name);
}
if (isPresent(result)) {
return getPropertyInView(result, this, currView);
} else {
return null;
}
}
createLiteralArray(values: o.Expression[]): o.Expression {
if (values.length === 0) {
return o.importExpr(Identifiers.EMPTY_ARRAY);
}
var proxyExpr = o.THIS_EXPR.prop(`_arr_${this.literalArrayCount++}`);
var proxyParams: o.FnParam[] = [];
var proxyReturnEntries: o.Expression[] = [];
for (var i = 0; i < values.length; i++) {
var paramName = `p${i}`;
proxyParams.push(new o.FnParam(paramName));
proxyReturnEntries.push(o.variable(paramName));
}
createPureProxy(o.fn(proxyParams, [new o.ReturnStatement(o.literalArr(proxyReturnEntries))]),
values.length, proxyExpr, this);
return proxyExpr.callFn(values);
}
createLiteralMap(entries: Array<Array<string | o.Expression>>): o.Expression {
if (entries.length === 0) {
return o.importExpr(Identifiers.EMPTY_MAP);
}
var proxyExpr = o.THIS_EXPR.prop(`_map_${this.literalMapCount++}`);
var proxyParams: o.FnParam[] = [];
var proxyReturnEntries: Array<Array<string | o.Expression>> = [];
var values: o.Expression[] = [];
for (var i = 0; i < entries.length; i++) {
var paramName = `p${i}`;
proxyParams.push(new o.FnParam(paramName));
proxyReturnEntries.push([entries[i][0], o.variable(paramName)]);
values.push(<o.Expression>entries[i][1]);
}
createPureProxy(o.fn(proxyParams, [new o.ReturnStatement(o.literalMap(proxyReturnEntries))]),
entries.length, proxyExpr, this);
return proxyExpr.callFn(values);
}
afterNodes() {
this.pipes.forEach((pipe) => pipe.create());
this.viewQueries.values().forEach(
(queries) => queries.forEach((query) => query.afterChildren(this.updateViewQueriesMethod)));
}
}
function getViewType(component: CompileDirectiveMetadata, embeddedTemplateIndex: number): ViewType {
if (embeddedTemplateIndex > 0) {
return ViewType.EMBEDDED;
} else if (component.type.isHost) {
return ViewType.HOST;
} else {
return ViewType.COMPONENT;
}
}

View File

@ -1,83 +0,0 @@
import {ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core';
import {ChangeDetectorState, ViewType} from '../../core_private';
import {isBlank, resolveEnumToken} from '../../src/facade/lang';
import {CompileIdentifierMetadata} from '../compile_metadata';
import * as o from '../output/output_ast';
import {Identifiers} from '../identifiers';
function _enumExpression(classIdentifier: CompileIdentifierMetadata, value: any): o.Expression {
if (isBlank(value)) return o.NULL_EXPR;
var name = resolveEnumToken(classIdentifier.runtime, value);
return o.importExpr(new CompileIdentifierMetadata({
name: `${classIdentifier.name}.${name}`,
moduleUrl: classIdentifier.moduleUrl,
runtime: value
}));
}
export class ViewTypeEnum {
static fromValue(value: ViewType): o.Expression {
return _enumExpression(Identifiers.ViewType, value);
}
static HOST = ViewTypeEnum.fromValue(ViewType.HOST);
static COMPONENT = ViewTypeEnum.fromValue(ViewType.COMPONENT);
static EMBEDDED = ViewTypeEnum.fromValue(ViewType.EMBEDDED);
}
export class ViewEncapsulationEnum {
static fromValue(value: ViewEncapsulation): o.Expression {
return _enumExpression(Identifiers.ViewEncapsulation, value);
}
static Emulated = ViewEncapsulationEnum.fromValue(ViewEncapsulation.Emulated);
static Native = ViewEncapsulationEnum.fromValue(ViewEncapsulation.Native);
static None = ViewEncapsulationEnum.fromValue(ViewEncapsulation.None);
}
export class ChangeDetectorStateEnum {
static fromValue(value: ChangeDetectorState): o.Expression {
return _enumExpression(Identifiers.ChangeDetectorState, value);
}
static NeverChecked = ChangeDetectorStateEnum.fromValue(ChangeDetectorState.NeverChecked);
static CheckedBefore = ChangeDetectorStateEnum.fromValue(ChangeDetectorState.CheckedBefore);
static Errored = ChangeDetectorStateEnum.fromValue(ChangeDetectorState.Errored);
}
export class ChangeDetectionStrategyEnum {
static fromValue(value: ChangeDetectionStrategy): o.Expression {
return _enumExpression(Identifiers.ChangeDetectionStrategy, value);
}
static CheckOnce = ChangeDetectionStrategyEnum.fromValue(ChangeDetectionStrategy.CheckOnce);
static Checked = ChangeDetectionStrategyEnum.fromValue(ChangeDetectionStrategy.Checked);
static CheckAlways = ChangeDetectionStrategyEnum.fromValue(ChangeDetectionStrategy.CheckAlways);
static Detached = ChangeDetectionStrategyEnum.fromValue(ChangeDetectionStrategy.Detached);
static OnPush = ChangeDetectionStrategyEnum.fromValue(ChangeDetectionStrategy.OnPush);
static Default = ChangeDetectionStrategyEnum.fromValue(ChangeDetectionStrategy.Default);
}
export class ViewConstructorVars {
static viewUtils = o.variable('viewUtils');
static parentInjector = o.variable('parentInjector');
static declarationEl = o.variable('declarationEl');
}
export class ViewProperties {
static renderer = o.THIS_EXPR.prop('renderer');
static projectableNodes = o.THIS_EXPR.prop('projectableNodes');
static viewUtils = o.THIS_EXPR.prop('viewUtils');
}
export class EventHandlerVars { static event = o.variable('$event'); }
export class InjectMethodVars {
static token = o.variable('token');
static requestNodeIndex = o.variable('requestNodeIndex');
static notFoundResult = o.variable('notFoundResult');
}
export class DetectChangesVars {
static throwOnChange = o.variable(`throwOnChange`);
static changes = o.variable(`changes`);
static changed = o.variable(`changed`);
static valUnwrapper = o.variable(`valUnwrapper`);
}

View File

@ -1,164 +0,0 @@
import {isBlank, isPresent, StringWrapper} from '../../src/facade/lang';
import {ListWrapper, StringMapWrapper} from '../../src/facade/collection';
import {EventHandlerVars, ViewProperties} from './constants';
import * as o from '../output/output_ast';
import {CompileElement} from './compile_element';
import {CompileMethod} from './compile_method';
import {BoundEventAst, DirectiveAst} from '../template_ast';
import {CompileDirectiveMetadata} from '../compile_metadata';
import {convertCdStatementToIr} from './expression_converter';
import {CompileBinding} from './compile_binding';
export class CompileEventListener {
private _method: CompileMethod;
private _hasComponentHostListener: boolean = false;
private _methodName: string;
private _eventParam: o.FnParam;
private _actionResultExprs: o.Expression[] = [];
static getOrCreate(compileElement: CompileElement, eventTarget: string, eventName: string,
targetEventListeners: CompileEventListener[]): CompileEventListener {
var listener = targetEventListeners.find(listener => listener.eventTarget == eventTarget &&
listener.eventName == eventName);
if (isBlank(listener)) {
listener = new CompileEventListener(compileElement, eventTarget, eventName,
targetEventListeners.length);
targetEventListeners.push(listener);
}
return listener;
}
constructor(public compileElement: CompileElement, public eventTarget: string,
public eventName: string, listenerIndex: number) {
this._method = new CompileMethod(compileElement.view);
this._methodName =
`_handle_${santitizeEventName(eventName)}_${compileElement.nodeIndex}_${listenerIndex}`;
this._eventParam =
new o.FnParam(EventHandlerVars.event.name,
o.importType(this.compileElement.view.genConfig.renderTypes.renderEvent));
}
addAction(hostEvent: BoundEventAst, directive: CompileDirectiveMetadata,
directiveInstance: o.Expression) {
if (isPresent(directive) && directive.isComponent) {
this._hasComponentHostListener = true;
}
this._method.resetDebugInfo(this.compileElement.nodeIndex, hostEvent);
var context = isPresent(directiveInstance) ? directiveInstance :
this.compileElement.view.componentContext;
var actionStmts = convertCdStatementToIr(this.compileElement.view, context, hostEvent.handler);
var lastIndex = actionStmts.length - 1;
if (lastIndex >= 0) {
var lastStatement = actionStmts[lastIndex];
var returnExpr = convertStmtIntoExpression(lastStatement);
var preventDefaultVar = o.variable(`pd_${this._actionResultExprs.length}`);
this._actionResultExprs.push(preventDefaultVar);
if (isPresent(returnExpr)) {
// Note: We need to cast the result of the method call to dynamic,
// as it might be a void method!
actionStmts[lastIndex] =
preventDefaultVar.set(returnExpr.cast(o.DYNAMIC_TYPE).notIdentical(o.literal(false)))
.toDeclStmt(null, [o.StmtModifier.Final]);
}
}
this._method.addStmts(actionStmts);
}
finishMethod() {
var markPathToRootStart = this._hasComponentHostListener ?
this.compileElement.appElement.prop('componentView') :
o.THIS_EXPR;
var resultExpr: o.Expression = o.literal(true);
this._actionResultExprs.forEach((expr) => { resultExpr = resultExpr.and(expr); });
var stmts =
(<o.Statement[]>[markPathToRootStart.callMethod('markPathToRootAsCheckOnce', []).toStmt()])
.concat(this._method.finish())
.concat([new o.ReturnStatement(resultExpr)]);
// private is fine here as no child view will reference the event handler...
this.compileElement.view.eventHandlerMethods.push(new o.ClassMethod(
this._methodName, [this._eventParam], stmts, o.BOOL_TYPE, [o.StmtModifier.Private]));
}
listenToRenderer() {
var listenExpr;
var eventListener = o.THIS_EXPR.callMethod(
'eventHandler',
[o.THIS_EXPR.prop(this._methodName).callMethod(o.BuiltinMethod.bind, [o.THIS_EXPR])]);
if (isPresent(this.eventTarget)) {
listenExpr = ViewProperties.renderer.callMethod(
'listenGlobal', [o.literal(this.eventTarget), o.literal(this.eventName), eventListener]);
} else {
listenExpr = ViewProperties.renderer.callMethod(
'listen', [this.compileElement.renderNode, o.literal(this.eventName), eventListener]);
}
var disposable = o.variable(`disposable_${this.compileElement.view.disposables.length}`);
this.compileElement.view.disposables.push(disposable);
// private is fine here as no child view will reference the event handler...
this.compileElement.view.createMethod.addStmt(
disposable.set(listenExpr).toDeclStmt(o.FUNCTION_TYPE, [o.StmtModifier.Private]));
}
listenToDirective(directiveInstance: o.Expression, observablePropName: string) {
var subscription = o.variable(`subscription_${this.compileElement.view.subscriptions.length}`);
this.compileElement.view.subscriptions.push(subscription);
var eventListener = o.THIS_EXPR.callMethod(
'eventHandler',
[o.THIS_EXPR.prop(this._methodName).callMethod(o.BuiltinMethod.bind, [o.THIS_EXPR])]);
this.compileElement.view.createMethod.addStmt(
subscription.set(directiveInstance.prop(observablePropName)
.callMethod(o.BuiltinMethod.SubscribeObservable, [eventListener]))
.toDeclStmt(null, [o.StmtModifier.Final]));
}
}
export function collectEventListeners(hostEvents: BoundEventAst[], dirs: DirectiveAst[],
compileElement: CompileElement): CompileEventListener[] {
var eventListeners: CompileEventListener[] = [];
hostEvents.forEach((hostEvent) => {
compileElement.view.bindings.push(new CompileBinding(compileElement, hostEvent));
var listener = CompileEventListener.getOrCreate(compileElement, hostEvent.target,
hostEvent.name, eventListeners);
listener.addAction(hostEvent, null, null);
});
ListWrapper.forEachWithIndex(dirs, (directiveAst, i) => {
var directiveInstance = compileElement.directiveInstances[i];
directiveAst.hostEvents.forEach((hostEvent) => {
compileElement.view.bindings.push(new CompileBinding(compileElement, hostEvent));
var listener = CompileEventListener.getOrCreate(compileElement, hostEvent.target,
hostEvent.name, eventListeners);
listener.addAction(hostEvent, directiveAst.directive, directiveInstance);
});
});
eventListeners.forEach((listener) => listener.finishMethod());
return eventListeners;
}
export function bindDirectiveOutputs(directiveAst: DirectiveAst, directiveInstance: o.Expression,
eventListeners: CompileEventListener[]) {
StringMapWrapper.forEach(directiveAst.directive.outputs, (eventName, observablePropName) => {
eventListeners.filter(listener => listener.eventName == eventName)
.forEach(
(listener) => { listener.listenToDirective(directiveInstance, observablePropName); });
});
}
export function bindRenderOutputs(eventListeners: CompileEventListener[]) {
eventListeners.forEach(listener => listener.listenToRenderer());
}
function convertStmtIntoExpression(stmt: o.Statement): o.Expression {
if (stmt instanceof o.ExpressionStatement) {
return stmt.expr;
} else if (stmt instanceof o.ReturnStatement) {
return stmt.value;
}
return null;
}
function santitizeEventName(name: string): string {
return StringWrapper.replaceAll(name, /[^a-zA-Z_]/g, '_');
}

View File

@ -1,252 +0,0 @@
import {BaseException} from '../../src/facade/exceptions';
import {isBlank, isPresent, isArray} from '../../src/facade/lang';
import * as cdAst from '../expression_parser/ast';
import * as o from '../output/output_ast';
import {Identifiers} from '../identifiers';
var IMPLICIT_RECEIVER = o.variable('#implicit');
export interface NameResolver {
callPipe(name: string, input: o.Expression, args: o.Expression[]): o.Expression;
getLocal(name: string): o.Expression;
createLiteralArray(values: o.Expression[]): o.Expression;
createLiteralMap(values: Array<Array<string | o.Expression>>): o.Expression;
}
export class ExpressionWithWrappedValueInfo {
constructor(public expression: o.Expression, public needsValueUnwrapper: boolean) {}
}
export function convertCdExpressionToIr(
nameResolver: NameResolver, implicitReceiver: o.Expression, expression: cdAst.AST,
valueUnwrapper: o.ReadVarExpr): ExpressionWithWrappedValueInfo {
var visitor = new _AstToIrVisitor(nameResolver, implicitReceiver, valueUnwrapper);
var irAst: o.Expression = expression.visit(visitor, _Mode.Expression);
return new ExpressionWithWrappedValueInfo(irAst, visitor.needsValueUnwrapper);
}
export function convertCdStatementToIr(nameResolver: NameResolver, implicitReceiver: o.Expression,
stmt: cdAst.AST): o.Statement[] {
var visitor = new _AstToIrVisitor(nameResolver, implicitReceiver, null);
var statements = [];
flattenStatements(stmt.visit(visitor, _Mode.Statement), statements);
return statements;
}
enum _Mode {
Statement,
Expression
}
function ensureStatementMode(mode: _Mode, ast: cdAst.AST) {
if (mode !== _Mode.Statement) {
throw new BaseException(`Expected a statement, but saw ${ast}`);
}
}
function ensureExpressionMode(mode: _Mode, ast: cdAst.AST) {
if (mode !== _Mode.Expression) {
throw new BaseException(`Expected an expression, but saw ${ast}`);
}
}
function convertToStatementIfNeeded(mode: _Mode, expr: o.Expression): o.Expression | o.Statement {
if (mode === _Mode.Statement) {
return expr.toStmt();
} else {
return expr;
}
}
class _AstToIrVisitor implements cdAst.AstVisitor {
public needsValueUnwrapper: boolean = false;
constructor(private _nameResolver: NameResolver, private _implicitReceiver: o.Expression,
private _valueUnwrapper: o.ReadVarExpr) {}
visitBinary(ast: cdAst.Binary, mode: _Mode): any {
var op;
switch (ast.operation) {
case '+':
op = o.BinaryOperator.Plus;
break;
case '-':
op = o.BinaryOperator.Minus;
break;
case '*':
op = o.BinaryOperator.Multiply;
break;
case '/':
op = o.BinaryOperator.Divide;
break;
case '%':
op = o.BinaryOperator.Modulo;
break;
case '&&':
op = o.BinaryOperator.And;
break;
case '||':
op = o.BinaryOperator.Or;
break;
case '==':
op = o.BinaryOperator.Equals;
break;
case '!=':
op = o.BinaryOperator.NotEquals;
break;
case '===':
op = o.BinaryOperator.Identical;
break;
case '!==':
op = o.BinaryOperator.NotIdentical;
break;
case '<':
op = o.BinaryOperator.Lower;
break;
case '>':
op = o.BinaryOperator.Bigger;
break;
case '<=':
op = o.BinaryOperator.LowerEquals;
break;
case '>=':
op = o.BinaryOperator.BiggerEquals;
break;
default:
throw new BaseException(`Unsupported operation ${ast.operation}`);
}
return convertToStatementIfNeeded(
mode, new o.BinaryOperatorExpr(op, ast.left.visit(this, _Mode.Expression),
ast.right.visit(this, _Mode.Expression)));
}
visitChain(ast: cdAst.Chain, mode: _Mode): any {
ensureStatementMode(mode, ast);
return this.visitAll(ast.expressions, mode);
}
visitConditional(ast: cdAst.Conditional, mode: _Mode): any {
var value: o.Expression = ast.condition.visit(this, _Mode.Expression);
return convertToStatementIfNeeded(
mode, value.conditional(ast.trueExp.visit(this, _Mode.Expression),
ast.falseExp.visit(this, _Mode.Expression)));
}
visitPipe(ast: cdAst.BindingPipe, mode: _Mode): any {
var input = ast.exp.visit(this, _Mode.Expression);
var args = this.visitAll(ast.args, _Mode.Expression);
var value = this._nameResolver.callPipe(ast.name, input, args);
this.needsValueUnwrapper = true;
return convertToStatementIfNeeded(mode, this._valueUnwrapper.callMethod('unwrap', [value]));
}
visitFunctionCall(ast: cdAst.FunctionCall, mode: _Mode): any {
return convertToStatementIfNeeded(mode, ast.target.visit(this, _Mode.Expression)
.callFn(this.visitAll(ast.args, _Mode.Expression)));
}
visitImplicitReceiver(ast: cdAst.ImplicitReceiver, mode: _Mode): any {
ensureExpressionMode(mode, ast);
return IMPLICIT_RECEIVER;
}
visitInterpolation(ast: cdAst.Interpolation, mode: _Mode): any {
ensureExpressionMode(mode, ast);
var args = [o.literal(ast.expressions.length)];
for (var i = 0; i < ast.strings.length - 1; i++) {
args.push(o.literal(ast.strings[i]));
args.push(ast.expressions[i].visit(this, _Mode.Expression));
}
args.push(o.literal(ast.strings[ast.strings.length - 1]));
return o.importExpr(Identifiers.interpolate).callFn(args);
}
visitKeyedRead(ast: cdAst.KeyedRead, mode: _Mode): any {
return convertToStatementIfNeeded(
mode, ast.obj.visit(this, _Mode.Expression).key(ast.key.visit(this, _Mode.Expression)));
}
visitKeyedWrite(ast: cdAst.KeyedWrite, mode: _Mode): any {
var obj: o.Expression = ast.obj.visit(this, _Mode.Expression);
var key: o.Expression = ast.key.visit(this, _Mode.Expression);
var value: o.Expression = ast.value.visit(this, _Mode.Expression);
return convertToStatementIfNeeded(mode, obj.key(key).set(value));
}
visitLiteralArray(ast: cdAst.LiteralArray, mode: _Mode): any {
return convertToStatementIfNeeded(
mode, this._nameResolver.createLiteralArray(this.visitAll(ast.expressions, mode)));
}
visitLiteralMap(ast: cdAst.LiteralMap, mode: _Mode): any {
var parts = [];
for (var i = 0; i < ast.keys.length; i++) {
parts.push([ast.keys[i], ast.values[i].visit(this, _Mode.Expression)]);
}
return convertToStatementIfNeeded(mode, this._nameResolver.createLiteralMap(parts));
}
visitLiteralPrimitive(ast: cdAst.LiteralPrimitive, mode: _Mode): any {
return convertToStatementIfNeeded(mode, o.literal(ast.value));
}
visitMethodCall(ast: cdAst.MethodCall, mode: _Mode): any {
var args = this.visitAll(ast.args, _Mode.Expression);
var result = null;
var receiver = ast.receiver.visit(this, _Mode.Expression);
if (receiver === IMPLICIT_RECEIVER) {
var varExpr = this._nameResolver.getLocal(ast.name);
if (isPresent(varExpr)) {
result = varExpr.callFn(args);
} else {
receiver = this._implicitReceiver;
}
}
if (isBlank(result)) {
result = receiver.callMethod(ast.name, args);
}
return convertToStatementIfNeeded(mode, result);
}
visitPrefixNot(ast: cdAst.PrefixNot, mode: _Mode): any {
return convertToStatementIfNeeded(mode, o.not(ast.expression.visit(this, _Mode.Expression)));
}
visitPropertyRead(ast: cdAst.PropertyRead, mode: _Mode): any {
var result = null;
var receiver = ast.receiver.visit(this, _Mode.Expression);
if (receiver === IMPLICIT_RECEIVER) {
result = this._nameResolver.getLocal(ast.name);
if (isBlank(result)) {
receiver = this._implicitReceiver;
}
}
if (isBlank(result)) {
result = receiver.prop(ast.name);
}
return convertToStatementIfNeeded(mode, result);
}
visitPropertyWrite(ast: cdAst.PropertyWrite, mode: _Mode): any {
var receiver: o.Expression = ast.receiver.visit(this, _Mode.Expression);
if (receiver === IMPLICIT_RECEIVER) {
var varExpr = this._nameResolver.getLocal(ast.name);
if (isPresent(varExpr)) {
throw new BaseException('Cannot assign to a reference or variable!');
}
receiver = this._implicitReceiver;
}
return convertToStatementIfNeeded(
mode, receiver.prop(ast.name).set(ast.value.visit(this, _Mode.Expression)));
}
visitSafePropertyRead(ast: cdAst.SafePropertyRead, mode: _Mode): any {
var receiver = ast.receiver.visit(this, _Mode.Expression);
return convertToStatementIfNeeded(
mode, receiver.isBlank().conditional(o.NULL_EXPR, receiver.prop(ast.name)));
}
visitSafeMethodCall(ast: cdAst.SafeMethodCall, mode: _Mode): any {
var receiver = ast.receiver.visit(this, _Mode.Expression);
var args = this.visitAll(ast.args, _Mode.Expression);
return convertToStatementIfNeeded(
mode, receiver.isBlank().conditional(o.NULL_EXPR, receiver.callMethod(ast.name, args)));
}
visitAll(asts: cdAst.AST[], mode: _Mode): any { return asts.map(ast => ast.visit(this, mode)); }
visitQuote(ast: cdAst.Quote, mode: _Mode): any {
throw new BaseException('Quotes are not supported for evaluation!');
}
}
function flattenStatements(arg: any, output: o.Statement[]) {
if (isArray(arg)) {
(<any[]>arg).forEach((entry) => flattenStatements(entry, output));
} else {
output.push(arg);
}
}

View File

@ -1,88 +0,0 @@
import {LifecycleHooks} from '../../core_private';
import * as o from '../output/output_ast';
import {DetectChangesVars, ChangeDetectorStateEnum} from './constants';
import {CompileDirectiveMetadata, CompilePipeMetadata} from '../compile_metadata';
import {DirectiveAst} from '../template_ast';
import {CompileElement} from './compile_element';
import {CompileView} from './compile_view';
var STATE_IS_NEVER_CHECKED =
o.THIS_EXPR.prop('cdState').identical(ChangeDetectorStateEnum.NeverChecked);
var NOT_THROW_ON_CHANGES = o.not(DetectChangesVars.throwOnChange);
export function bindDirectiveDetectChangesLifecycleCallbacks(
directiveAst: DirectiveAst, directiveInstance: o.Expression, compileElement: CompileElement) {
var view = compileElement.view;
var detectChangesInInputsMethod = view.detectChangesInInputsMethod;
var lifecycleHooks = directiveAst.directive.lifecycleHooks;
if (lifecycleHooks.indexOf(LifecycleHooks.OnChanges) !== -1 && directiveAst.inputs.length > 0) {
detectChangesInInputsMethod.addStmt(new o.IfStmt(
DetectChangesVars.changes.notIdentical(o.NULL_EXPR),
[directiveInstance.callMethod('ngOnChanges', [DetectChangesVars.changes]).toStmt()]));
}
if (lifecycleHooks.indexOf(LifecycleHooks.OnInit) !== -1) {
detectChangesInInputsMethod.addStmt(
new o.IfStmt(STATE_IS_NEVER_CHECKED.and(NOT_THROW_ON_CHANGES),
[directiveInstance.callMethod('ngOnInit', []).toStmt()]));
}
if (lifecycleHooks.indexOf(LifecycleHooks.DoCheck) !== -1) {
detectChangesInInputsMethod.addStmt(new o.IfStmt(
NOT_THROW_ON_CHANGES, [directiveInstance.callMethod('ngDoCheck', []).toStmt()]));
}
}
export function bindDirectiveAfterContentLifecycleCallbacks(directiveMeta: CompileDirectiveMetadata,
directiveInstance: o.Expression,
compileElement: CompileElement) {
var view = compileElement.view;
var lifecycleHooks = directiveMeta.lifecycleHooks;
var afterContentLifecycleCallbacksMethod = view.afterContentLifecycleCallbacksMethod;
afterContentLifecycleCallbacksMethod.resetDebugInfo(compileElement.nodeIndex,
compileElement.sourceAst);
if (lifecycleHooks.indexOf(LifecycleHooks.AfterContentInit) !== -1) {
afterContentLifecycleCallbacksMethod.addStmt(new o.IfStmt(
STATE_IS_NEVER_CHECKED, [directiveInstance.callMethod('ngAfterContentInit', []).toStmt()]));
}
if (lifecycleHooks.indexOf(LifecycleHooks.AfterContentChecked) !== -1) {
afterContentLifecycleCallbacksMethod.addStmt(
directiveInstance.callMethod('ngAfterContentChecked', []).toStmt());
}
}
export function bindDirectiveAfterViewLifecycleCallbacks(directiveMeta: CompileDirectiveMetadata,
directiveInstance: o.Expression,
compileElement: CompileElement) {
var view = compileElement.view;
var lifecycleHooks = directiveMeta.lifecycleHooks;
var afterViewLifecycleCallbacksMethod = view.afterViewLifecycleCallbacksMethod;
afterViewLifecycleCallbacksMethod.resetDebugInfo(compileElement.nodeIndex,
compileElement.sourceAst);
if (lifecycleHooks.indexOf(LifecycleHooks.AfterViewInit) !== -1) {
afterViewLifecycleCallbacksMethod.addStmt(new o.IfStmt(
STATE_IS_NEVER_CHECKED, [directiveInstance.callMethod('ngAfterViewInit', []).toStmt()]));
}
if (lifecycleHooks.indexOf(LifecycleHooks.AfterViewChecked) !== -1) {
afterViewLifecycleCallbacksMethod.addStmt(
directiveInstance.callMethod('ngAfterViewChecked', []).toStmt());
}
}
export function bindDirectiveDestroyLifecycleCallbacks(directiveMeta: CompileDirectiveMetadata,
directiveInstance: o.Expression,
compileElement: CompileElement) {
var onDestroyMethod = compileElement.view.destroyMethod;
onDestroyMethod.resetDebugInfo(compileElement.nodeIndex, compileElement.sourceAst);
if (directiveMeta.lifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1) {
onDestroyMethod.addStmt(directiveInstance.callMethod('ngOnDestroy', []).toStmt());
}
}
export function bindPipeDestroyLifecycleCallbacks(pipeMeta: CompilePipeMetadata,
pipeInstance: o.Expression, view: CompileView) {
var onDestroyMethod = view.destroyMethod;
if (pipeMeta.lifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1) {
onDestroyMethod.addStmt(pipeInstance.callMethod('ngOnDestroy', []).toStmt());
}
}

View File

@ -1,210 +0,0 @@
import {LifecycleHooks, isDefaultChangeDetectionStrategy} from '../../core_private';
import {isBlank, isPresent} from '../../src/facade/lang';
import * as cdAst from '../expression_parser/ast';
import * as o from '../output/output_ast';
import {Identifiers} from '../identifiers';
import {DetectChangesVars} from './constants';
import {
BoundTextAst,
BoundElementPropertyAst,
DirectiveAst,
PropertyBindingType,
} from '../template_ast';
import {CompileView} from './compile_view';
import {CompileElement, CompileNode} from './compile_element';
import {CompileMethod} from './compile_method';
import {camelCaseToDashCase} from '../util';
import {convertCdExpressionToIr} from './expression_converter';
import {CompileBinding} from './compile_binding';
function createBindFieldExpr(exprIndex: number): o.ReadPropExpr {
return o.THIS_EXPR.prop(`_expr_${exprIndex}`);
}
function createCurrValueExpr(exprIndex: number): o.ReadVarExpr {
return o.variable(`currVal_${exprIndex}`);
}
function bind(view: CompileView, currValExpr: o.ReadVarExpr, fieldExpr: o.ReadPropExpr,
parsedExpression: cdAst.AST, context: o.Expression, actions: o.Statement[],
method: CompileMethod) {
var checkExpression =
convertCdExpressionToIr(view, context, parsedExpression, DetectChangesVars.valUnwrapper);
if (isBlank(checkExpression.expression)) {
// e.g. an empty expression was given
return;
}
// private is fine here as no child view will reference the cached value...
view.fields.push(new o.ClassField(fieldExpr.name, null, [o.StmtModifier.Private]));
view.createMethod.addStmt(
o.THIS_EXPR.prop(fieldExpr.name).set(o.importExpr(Identifiers.uninitialized)).toStmt());
if (checkExpression.needsValueUnwrapper) {
var initValueUnwrapperStmt = DetectChangesVars.valUnwrapper.callMethod('reset', []).toStmt();
method.addStmt(initValueUnwrapperStmt);
}
method.addStmt(
currValExpr.set(checkExpression.expression).toDeclStmt(null, [o.StmtModifier.Final]));
var condition: o.Expression =
o.importExpr(Identifiers.checkBinding)
.callFn([DetectChangesVars.throwOnChange, fieldExpr, currValExpr]);
if (checkExpression.needsValueUnwrapper) {
condition = DetectChangesVars.valUnwrapper.prop('hasWrappedValue').or(condition);
}
method.addStmt(new o.IfStmt(
condition,
actions.concat([<o.Statement>o.THIS_EXPR.prop(fieldExpr.name).set(currValExpr).toStmt()])));
}
export function bindRenderText(boundText: BoundTextAst, compileNode: CompileNode,
view: CompileView) {
var bindingIndex = view.bindings.length;
view.bindings.push(new CompileBinding(compileNode, boundText));
var currValExpr = createCurrValueExpr(bindingIndex);
var valueField = createBindFieldExpr(bindingIndex);
view.detectChangesRenderPropertiesMethod.resetDebugInfo(compileNode.nodeIndex, boundText);
bind(view, currValExpr, valueField, boundText.value, view.componentContext,
[
o.THIS_EXPR.prop('renderer')
.callMethod('setText', [compileNode.renderNode, currValExpr])
.toStmt()
],
view.detectChangesRenderPropertiesMethod);
}
function bindAndWriteToRenderer(boundProps: BoundElementPropertyAst[], context: o.Expression,
compileElement: CompileElement) {
var view = compileElement.view;
var renderNode = compileElement.renderNode;
boundProps.forEach((boundProp) => {
var bindingIndex = view.bindings.length;
view.bindings.push(new CompileBinding(compileElement, boundProp));
view.detectChangesRenderPropertiesMethod.resetDebugInfo(compileElement.nodeIndex, boundProp);
var fieldExpr = createBindFieldExpr(bindingIndex);
var currValExpr = createCurrValueExpr(bindingIndex);
var renderMethod: string;
var renderValue: o.Expression = currValExpr;
var updateStmts = [];
switch (boundProp.type) {
case PropertyBindingType.Property:
renderMethod = 'setElementProperty';
if (view.genConfig.logBindingUpdate) {
updateStmts.push(logBindingUpdateStmt(renderNode, boundProp.name, currValExpr));
}
break;
case PropertyBindingType.Attribute:
renderMethod = 'setElementAttribute';
renderValue =
renderValue.isBlank().conditional(o.NULL_EXPR, renderValue.callMethod('toString', []));
break;
case PropertyBindingType.Class:
renderMethod = 'setElementClass';
break;
case PropertyBindingType.Style:
renderMethod = 'setElementStyle';
var strValue: o.Expression = renderValue.callMethod('toString', []);
if (isPresent(boundProp.unit)) {
strValue = strValue.plus(o.literal(boundProp.unit));
}
renderValue = renderValue.isBlank().conditional(o.NULL_EXPR, strValue);
break;
}
updateStmts.push(
o.THIS_EXPR.prop('renderer')
.callMethod(renderMethod, [renderNode, o.literal(boundProp.name), renderValue])
.toStmt());
bind(view, currValExpr, fieldExpr, boundProp.value, context, updateStmts,
view.detectChangesRenderPropertiesMethod);
});
}
export function bindRenderInputs(boundProps: BoundElementPropertyAst[],
compileElement: CompileElement): void {
bindAndWriteToRenderer(boundProps, compileElement.view.componentContext, compileElement);
}
export function bindDirectiveHostProps(directiveAst: DirectiveAst, directiveInstance: o.Expression,
compileElement: CompileElement): void {
bindAndWriteToRenderer(directiveAst.hostProperties, directiveInstance, compileElement);
}
export function bindDirectiveInputs(directiveAst: DirectiveAst, directiveInstance: o.Expression,
compileElement: CompileElement) {
if (directiveAst.inputs.length === 0) {
return;
}
var view = compileElement.view;
var detectChangesInInputsMethod = view.detectChangesInInputsMethod;
detectChangesInInputsMethod.resetDebugInfo(compileElement.nodeIndex, compileElement.sourceAst);
var lifecycleHooks = directiveAst.directive.lifecycleHooks;
var calcChangesMap = lifecycleHooks.indexOf(LifecycleHooks.OnChanges) !== -1;
var isOnPushComp = directiveAst.directive.isComponent &&
!isDefaultChangeDetectionStrategy(directiveAst.directive.changeDetection);
if (calcChangesMap) {
detectChangesInInputsMethod.addStmt(DetectChangesVars.changes.set(o.NULL_EXPR).toStmt());
}
if (isOnPushComp) {
detectChangesInInputsMethod.addStmt(DetectChangesVars.changed.set(o.literal(false)).toStmt());
}
directiveAst.inputs.forEach((input) => {
var bindingIndex = view.bindings.length;
view.bindings.push(new CompileBinding(compileElement, input));
detectChangesInInputsMethod.resetDebugInfo(compileElement.nodeIndex, input);
var fieldExpr = createBindFieldExpr(bindingIndex);
var currValExpr = createCurrValueExpr(bindingIndex);
var statements: o.Statement[] =
[directiveInstance.prop(input.directiveName).set(currValExpr).toStmt()];
if (calcChangesMap) {
statements.push(new o.IfStmt(DetectChangesVars.changes.identical(o.NULL_EXPR), [
DetectChangesVars.changes.set(o.literalMap([], new o.MapType(
o.importType(Identifiers.SimpleChange))))
.toStmt()
]));
statements.push(
DetectChangesVars.changes.key(o.literal(input.directiveName))
.set(o.importExpr(Identifiers.SimpleChange).instantiate([fieldExpr, currValExpr]))
.toStmt());
}
if (isOnPushComp) {
statements.push(DetectChangesVars.changed.set(o.literal(true)).toStmt());
}
if (view.genConfig.logBindingUpdate) {
statements.push(
logBindingUpdateStmt(compileElement.renderNode, input.directiveName, currValExpr));
}
bind(view, currValExpr, fieldExpr, input.value, view.componentContext, statements,
detectChangesInInputsMethod);
});
if (isOnPushComp) {
detectChangesInInputsMethod.addStmt(new o.IfStmt(DetectChangesVars.changed, [
compileElement.appElement.prop('componentView')
.callMethod('markAsCheckOnce', [])
.toStmt()
]));
}
}
function logBindingUpdateStmt(renderNode: o.Expression, propName: string,
value: o.Expression): o.Statement {
return o.THIS_EXPR.prop('renderer')
.callMethod('setBindingDebugInfo',
[
renderNode,
o.literal(`ng-reflect-${camelCaseToDashCase(propName)}`),
value.isBlank().conditional(o.NULL_EXPR, value.callMethod('toString', []))
])
.toStmt();
}

View File

@ -1,98 +0,0 @@
import {isPresent, isBlank} from '../../src/facade/lang';
import {BaseException} from '../../src/facade/exceptions';
import * as o from '../output/output_ast';
import {
CompileTokenMetadata,
CompileDirectiveMetadata,
} from '../compile_metadata';
import {CompileView} from './compile_view';
import {Identifiers} from '../identifiers';
export function getPropertyInView(property: o.Expression, callingView: CompileView,
definedView: CompileView): o.Expression {
if (callingView === definedView) {
return property;
} else {
var viewProp: o.Expression = o.THIS_EXPR;
var currView: CompileView = callingView;
while (currView !== definedView && isPresent(currView.declarationElement.view)) {
currView = currView.declarationElement.view;
viewProp = viewProp.prop('parent');
}
if (currView !== definedView) {
throw new BaseException(
`Internal error: Could not calculate a property in a parent view: ${property}`);
}
if (property instanceof o.ReadPropExpr) {
let readPropExpr: o.ReadPropExpr = property;
// Note: Don't cast for members of the AppView base class...
if (definedView.fields.some((field) => field.name == readPropExpr.name) ||
definedView.getters.some((field) => field.name == readPropExpr.name)) {
viewProp = viewProp.cast(definedView.classType);
}
}
return o.replaceVarInExpression(o.THIS_EXPR.name, viewProp, property);
}
}
export function injectFromViewParentInjector(token: CompileTokenMetadata,
optional: boolean): o.Expression {
var args = [createDiTokenExpression(token)];
if (optional) {
args.push(o.NULL_EXPR);
}
return o.THIS_EXPR.prop('parentInjector').callMethod('get', args);
}
export function getViewFactoryName(component: CompileDirectiveMetadata,
embeddedTemplateIndex: number): string {
return `viewFactory_${component.type.name}${embeddedTemplateIndex}`;
}
export function createDiTokenExpression(token: CompileTokenMetadata): o.Expression {
if (isPresent(token.value)) {
return o.literal(token.value);
} else if (token.identifierIsInstance) {
return o.importExpr(token.identifier)
.instantiate([], o.importType(token.identifier, [], [o.TypeModifier.Const]));
} else {
return o.importExpr(token.identifier);
}
}
export function createFlatArray(expressions: o.Expression[]): o.Expression {
var lastNonArrayExpressions = [];
var result: o.Expression = o.literalArr([]);
for (var i = 0; i < expressions.length; i++) {
var expr = expressions[i];
if (expr.type instanceof o.ArrayType) {
if (lastNonArrayExpressions.length > 0) {
result =
result.callMethod(o.BuiltinMethod.ConcatArray, [o.literalArr(lastNonArrayExpressions)]);
lastNonArrayExpressions = [];
}
result = result.callMethod(o.BuiltinMethod.ConcatArray, [expr]);
} else {
lastNonArrayExpressions.push(expr);
}
}
if (lastNonArrayExpressions.length > 0) {
result =
result.callMethod(o.BuiltinMethod.ConcatArray, [o.literalArr(lastNonArrayExpressions)]);
}
return result;
}
export function createPureProxy(fn: o.Expression, argCount: number, pureProxyProp: o.ReadPropExpr,
view: CompileView) {
view.fields.push(new o.ClassField(pureProxyProp.name, null));
var pureProxyId =
argCount < Identifiers.pureProxies.length ? Identifiers.pureProxies[argCount] : null;
if (isBlank(pureProxyId)) {
throw new BaseException(`Unsupported number of argument for pure functions: ${argCount}`);
}
view.createMethod.addStmt(
o.THIS_EXPR.prop(pureProxyProp.name).set(o.importExpr(pureProxyId).callFn([fn])).toStmt());
}

View File

@ -1,119 +0,0 @@
import {
ListWrapper,
} from '../../src/facade/collection';
import {
TemplateAst,
TemplateAstVisitor,
NgContentAst,
EmbeddedTemplateAst,
ElementAst,
ReferenceAst,
VariableAst,
BoundEventAst,
BoundElementPropertyAst,
AttrAst,
BoundTextAst,
TextAst,
DirectiveAst,
BoundDirectivePropertyAst,
templateVisitAll,
} from '../template_ast';
import {
bindRenderText,
bindRenderInputs,
bindDirectiveInputs,
bindDirectiveHostProps
} from './property_binder';
import {bindRenderOutputs, collectEventListeners, bindDirectiveOutputs} from './event_binder';
import {
bindDirectiveAfterContentLifecycleCallbacks,
bindDirectiveAfterViewLifecycleCallbacks,
bindDirectiveDestroyLifecycleCallbacks,
bindPipeDestroyLifecycleCallbacks,
bindDirectiveDetectChangesLifecycleCallbacks
} from './lifecycle_binder';
import {CompileView} from './compile_view';
import {CompileElement, CompileNode} from './compile_element';
export function bindView(view: CompileView, parsedTemplate: TemplateAst[]): void {
var visitor = new ViewBinderVisitor(view);
templateVisitAll(visitor, parsedTemplate);
view.pipes.forEach(
(pipe) => { bindPipeDestroyLifecycleCallbacks(pipe.meta, pipe.instance, pipe.view); });
}
class ViewBinderVisitor implements TemplateAstVisitor {
private _nodeIndex: number = 0;
constructor(public view: CompileView) {}
visitBoundText(ast: BoundTextAst, parent: CompileElement): any {
var node = this.view.nodes[this._nodeIndex++];
bindRenderText(ast, node, this.view);
return null;
}
visitText(ast: TextAst, parent: CompileElement): any {
this._nodeIndex++;
return null;
}
visitNgContent(ast: NgContentAst, parent: CompileElement): any { return null; }
visitElement(ast: ElementAst, parent: CompileElement): any {
var compileElement = <CompileElement>this.view.nodes[this._nodeIndex++];
var eventListeners = collectEventListeners(ast.outputs, ast.directives, compileElement);
bindRenderInputs(ast.inputs, compileElement);
bindRenderOutputs(eventListeners);
ListWrapper.forEachWithIndex(ast.directives, (directiveAst, index) => {
var directiveInstance = compileElement.directiveInstances[index];
bindDirectiveInputs(directiveAst, directiveInstance, compileElement);
bindDirectiveDetectChangesLifecycleCallbacks(directiveAst, directiveInstance, compileElement);
bindDirectiveHostProps(directiveAst, directiveInstance, compileElement);
bindDirectiveOutputs(directiveAst, directiveInstance, eventListeners);
});
templateVisitAll(this, ast.children, compileElement);
// afterContent and afterView lifecycles need to be called bottom up
// so that children are notified before parents
ListWrapper.forEachWithIndex(ast.directives, (directiveAst, index) => {
var directiveInstance = compileElement.directiveInstances[index];
bindDirectiveAfterContentLifecycleCallbacks(directiveAst.directive, directiveInstance,
compileElement);
bindDirectiveAfterViewLifecycleCallbacks(directiveAst.directive, directiveInstance,
compileElement);
bindDirectiveDestroyLifecycleCallbacks(directiveAst.directive, directiveInstance,
compileElement);
});
return null;
}
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, parent: CompileElement): any {
var compileElement = <CompileElement>this.view.nodes[this._nodeIndex++];
var eventListeners = collectEventListeners(ast.outputs, ast.directives, compileElement);
ListWrapper.forEachWithIndex(ast.directives, (directiveAst, index) => {
var directiveInstance = compileElement.directiveInstances[index];
bindDirectiveInputs(directiveAst, directiveInstance, compileElement);
bindDirectiveDetectChangesLifecycleCallbacks(directiveAst, directiveInstance, compileElement);
bindDirectiveOutputs(directiveAst, directiveInstance, eventListeners);
bindDirectiveAfterContentLifecycleCallbacks(directiveAst.directive, directiveInstance,
compileElement);
bindDirectiveAfterViewLifecycleCallbacks(directiveAst.directive, directiveInstance,
compileElement);
bindDirectiveDestroyLifecycleCallbacks(directiveAst.directive, directiveInstance,
compileElement);
});
bindView(compileElement.embeddedView, ast.children);
return null;
}
visitAttr(ast: AttrAst, ctx: any): any { return null; }
visitDirective(ast: DirectiveAst, ctx: any): any { return null; }
visitEvent(ast: BoundEventAst, eventTargetAndNames: Map<string, BoundEventAst>): any {
return null;
}
visitReference(ast: ReferenceAst, ctx: any): any { return null; }
visitVariable(ast: VariableAst, ctx: any): any { return null; }
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
}

View File

@ -1,574 +0,0 @@
import {ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core';
import {isDefaultChangeDetectionStrategy, ViewType} from '../../core_private';
import {isPresent, StringWrapper} from '../../src/facade/lang';
import {ListWrapper, StringMapWrapper, SetWrapper} from '../../src/facade/collection';
import * as o from '../output/output_ast';
import {Identifiers, identifierToken} from '../identifiers';
import {
ViewConstructorVars,
InjectMethodVars,
DetectChangesVars,
ViewTypeEnum,
ViewEncapsulationEnum,
ChangeDetectionStrategyEnum,
ViewProperties
} from './constants';
import {CompileView} from './compile_view';
import {CompileElement, CompileNode} from './compile_element';
import {
TemplateAst,
TemplateAstVisitor,
NgContentAst,
EmbeddedTemplateAst,
ElementAst,
ReferenceAst,
VariableAst,
BoundEventAst,
BoundElementPropertyAst,
AttrAst,
BoundTextAst,
TextAst,
DirectiveAst,
BoundDirectivePropertyAst,
templateVisitAll,
} from '../template_ast';
import {getViewFactoryName, createFlatArray, createDiTokenExpression} from './util';
import {
CompileIdentifierMetadata,
CompileDirectiveMetadata,
CompileTokenMetadata
} from '../compile_metadata';
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
const CLASS_ATTR = 'class';
const STYLE_ATTR = 'style';
var parentRenderNodeVar = o.variable('parentRenderNode');
var rootSelectorVar = o.variable('rootSelector');
export class ViewCompileDependency {
constructor(public comp: CompileDirectiveMetadata,
public factoryPlaceholder: CompileIdentifierMetadata) {}
}
export function buildView(view: CompileView, template: TemplateAst[],
targetDependencies: ViewCompileDependency[]): number {
var builderVisitor = new ViewBuilderVisitor(view, targetDependencies);
templateVisitAll(builderVisitor, template, view.declarationElement.isNull() ?
view.declarationElement :
view.declarationElement.parent);
return builderVisitor.nestedViewCount;
}
export function finishView(view: CompileView, targetStatements: o.Statement[]) {
view.afterNodes();
createViewTopLevelStmts(view, targetStatements);
view.nodes.forEach((node) => {
if (node instanceof CompileElement && node.hasEmbeddedView) {
finishView(node.embeddedView, targetStatements);
}
});
}
class ViewBuilderVisitor implements TemplateAstVisitor {
nestedViewCount: number = 0;
constructor(public view: CompileView, public targetDependencies: ViewCompileDependency[]) {}
private _isRootNode(parent: CompileElement): boolean { return parent.view !== this.view; }
private _addRootNodeAndProject(node: CompileNode, ngContentIndex: number,
parent: CompileElement) {
var vcAppEl =
(node instanceof CompileElement && node.hasViewContainer) ? node.appElement : null;
if (this._isRootNode(parent)) {
// store appElement as root node only for ViewContainers
if (this.view.viewType !== ViewType.COMPONENT) {
this.view.rootNodesOrAppElements.push(isPresent(vcAppEl) ? vcAppEl : node.renderNode);
}
} else if (isPresent(parent.component) && isPresent(ngContentIndex)) {
parent.addContentNode(ngContentIndex, isPresent(vcAppEl) ? vcAppEl : node.renderNode);
}
}
private _getParentRenderNode(parent: CompileElement): o.Expression {
if (this._isRootNode(parent)) {
if (this.view.viewType === ViewType.COMPONENT) {
return parentRenderNodeVar;
} else {
// root node of an embedded/host view
return o.NULL_EXPR;
}
} else {
return isPresent(parent.component) &&
parent.component.template.encapsulation !== ViewEncapsulation.Native ?
o.NULL_EXPR :
parent.renderNode;
}
}
visitBoundText(ast: BoundTextAst, parent: CompileElement): any {
return this._visitText(ast, '', ast.ngContentIndex, parent);
}
visitText(ast: TextAst, parent: CompileElement): any {
return this._visitText(ast, ast.value, ast.ngContentIndex, parent);
}
private _visitText(ast: TemplateAst, value: string, ngContentIndex: number,
parent: CompileElement): o.Expression {
var fieldName = `_text_${this.view.nodes.length}`;
this.view.fields.push(
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderText)));
var renderNode = o.THIS_EXPR.prop(fieldName);
var compileNode = new CompileNode(parent, this.view, this.view.nodes.length, renderNode, ast);
var createRenderNode =
o.THIS_EXPR.prop(fieldName)
.set(ViewProperties.renderer.callMethod(
'createText',
[
this._getParentRenderNode(parent),
o.literal(value),
this.view.createMethod.resetDebugInfoExpr(this.view.nodes.length, ast)
]))
.toStmt();
this.view.nodes.push(compileNode);
this.view.createMethod.addStmt(createRenderNode);
this._addRootNodeAndProject(compileNode, ngContentIndex, parent);
return renderNode;
}
visitNgContent(ast: NgContentAst, parent: CompileElement): any {
// the projected nodes originate from a different view, so we don't
// have debug information for them...
this.view.createMethod.resetDebugInfo(null, ast);
var parentRenderNode = this._getParentRenderNode(parent);
var nodesExpression = ViewProperties.projectableNodes.key(
o.literal(ast.index),
new o.ArrayType(o.importType(this.view.genConfig.renderTypes.renderNode)));
if (parentRenderNode !== o.NULL_EXPR) {
this.view.createMethod.addStmt(
ViewProperties.renderer.callMethod(
'projectNodes',
[
parentRenderNode,
o.importExpr(Identifiers.flattenNestedViewRenderNodes)
.callFn([nodesExpression])
])
.toStmt());
} else if (this._isRootNode(parent)) {
if (this.view.viewType !== ViewType.COMPONENT) {
// store root nodes only for embedded/host views
this.view.rootNodesOrAppElements.push(nodesExpression);
}
} else {
if (isPresent(parent.component) && isPresent(ast.ngContentIndex)) {
parent.addContentNode(ast.ngContentIndex, nodesExpression);
}
}
return null;
}
visitElement(ast: ElementAst, parent: CompileElement): any {
var nodeIndex = this.view.nodes.length;
var createRenderNodeExpr;
var debugContextExpr = this.view.createMethod.resetDebugInfoExpr(nodeIndex, ast);
if (nodeIndex === 0 && this.view.viewType === ViewType.HOST) {
createRenderNodeExpr = o.THIS_EXPR.callMethod(
'selectOrCreateHostElement', [o.literal(ast.name), rootSelectorVar, debugContextExpr]);
} else {
createRenderNodeExpr = ViewProperties.renderer.callMethod(
'createElement',
[this._getParentRenderNode(parent), o.literal(ast.name), debugContextExpr]);
}
var fieldName = `_el_${nodeIndex}`;
this.view.fields.push(
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderElement)));
this.view.createMethod.addStmt(o.THIS_EXPR.prop(fieldName).set(createRenderNodeExpr).toStmt());
var renderNode = o.THIS_EXPR.prop(fieldName);
var directives = ast.directives.map(directiveAst => directiveAst.directive);
var component = directives.find(directive => directive.isComponent);
var htmlAttrs = _readHtmlAttrs(ast.attrs);
var attrNameAndValues = _mergeHtmlAndDirectiveAttrs(htmlAttrs, directives);
for (var i = 0; i < attrNameAndValues.length; i++) {
var attrName = attrNameAndValues[i][0];
var attrValue = attrNameAndValues[i][1];
this.view.createMethod.addStmt(
ViewProperties.renderer.callMethod(
'setElementAttribute',
[renderNode, o.literal(attrName), o.literal(attrValue)])
.toStmt());
}
var compileElement =
new CompileElement(parent, this.view, nodeIndex, renderNode, ast, component, directives,
ast.providers, ast.hasViewContainer, false, ast.references);
this.view.nodes.push(compileElement);
var compViewExpr: o.ReadVarExpr = null;
if (isPresent(component)) {
var nestedComponentIdentifier =
new CompileIdentifierMetadata({name: getViewFactoryName(component, 0)});
this.targetDependencies.push(new ViewCompileDependency(component, nestedComponentIdentifier));
compViewExpr = o.variable(`compView_${nodeIndex}`);
compileElement.setComponentView(compViewExpr);
this.view.createMethod.addStmt(compViewExpr.set(o.importExpr(nestedComponentIdentifier)
.callFn([
ViewProperties.viewUtils,
compileElement.injector,
compileElement.appElement
]))
.toDeclStmt());
}
compileElement.beforeChildren();
this._addRootNodeAndProject(compileElement, ast.ngContentIndex, parent);
templateVisitAll(this, ast.children, compileElement);
compileElement.afterChildren(this.view.nodes.length - nodeIndex - 1);
if (isPresent(compViewExpr)) {
var codeGenContentNodes;
if (this.view.component.type.isHost) {
codeGenContentNodes = ViewProperties.projectableNodes;
} else {
codeGenContentNodes = o.literalArr(
compileElement.contentNodesByNgContentIndex.map(nodes => createFlatArray(nodes)));
}
this.view.createMethod.addStmt(
compViewExpr.callMethod('create',
[compileElement.getComponent(), codeGenContentNodes, o.NULL_EXPR])
.toStmt());
}
return null;
}
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, parent: CompileElement): any {
var nodeIndex = this.view.nodes.length;
var fieldName = `_anchor_${nodeIndex}`;
this.view.fields.push(
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderComment)));
this.view.createMethod.addStmt(
o.THIS_EXPR.prop(fieldName)
.set(ViewProperties.renderer.callMethod(
'createTemplateAnchor',
[
this._getParentRenderNode(parent),
this.view.createMethod.resetDebugInfoExpr(nodeIndex, ast)
]))
.toStmt());
var renderNode = o.THIS_EXPR.prop(fieldName);
var templateVariableBindings = ast.variables.map(
varAst => [varAst.value.length > 0 ? varAst.value : IMPLICIT_TEMPLATE_VAR, varAst.name]);
var directives = ast.directives.map(directiveAst => directiveAst.directive);
var compileElement =
new CompileElement(parent, this.view, nodeIndex, renderNode, ast, null, directives,
ast.providers, ast.hasViewContainer, true, ast.references);
this.view.nodes.push(compileElement);
this.nestedViewCount++;
var embeddedView = new CompileView(
this.view.component, this.view.genConfig, this.view.pipeMetas, o.NULL_EXPR,
this.view.viewIndex + this.nestedViewCount, compileElement, templateVariableBindings);
this.nestedViewCount += buildView(embeddedView, ast.children, this.targetDependencies);
compileElement.beforeChildren();
this._addRootNodeAndProject(compileElement, ast.ngContentIndex, parent);
compileElement.afterChildren(0);
return null;
}
visitAttr(ast: AttrAst, ctx: any): any { return null; }
visitDirective(ast: DirectiveAst, ctx: any): any { return null; }
visitEvent(ast: BoundEventAst, eventTargetAndNames: Map<string, BoundEventAst>): any {
return null;
}
visitReference(ast: ReferenceAst, ctx: any): any { return null; }
visitVariable(ast: VariableAst, ctx: any): any { return null; }
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
}
function _mergeHtmlAndDirectiveAttrs(declaredHtmlAttrs: {[key: string]: string},
directives: CompileDirectiveMetadata[]): string[][] {
var result: {[key: string]: string} = {};
StringMapWrapper.forEach(declaredHtmlAttrs, (value, key) => { result[key] = value; });
directives.forEach(directiveMeta => {
StringMapWrapper.forEach(directiveMeta.hostAttributes, (value, name) => {
var prevValue = result[name];
result[name] = isPresent(prevValue) ? mergeAttributeValue(name, prevValue, value) : value;
});
});
return mapToKeyValueArray(result);
}
function _readHtmlAttrs(attrs: AttrAst[]): {[key: string]: string} {
var htmlAttrs: {[key: string]: string} = {};
attrs.forEach((ast) => { htmlAttrs[ast.name] = ast.value; });
return htmlAttrs;
}
function mergeAttributeValue(attrName: string, attrValue1: string, attrValue2: string): string {
if (attrName == CLASS_ATTR || attrName == STYLE_ATTR) {
return `${attrValue1} ${attrValue2}`;
} else {
return attrValue2;
}
}
function mapToKeyValueArray(data: {[key: string]: string}): string[][] {
var entryArray = [];
StringMapWrapper.forEach(data, (value, name) => { entryArray.push([name, value]); });
// We need to sort to get a defined output order
// for tests and for caching generated artifacts...
ListWrapper.sort(entryArray, (entry1, entry2) => StringWrapper.compare(entry1[0], entry2[0]));
var keyValueArray = [];
entryArray.forEach((entry) => { keyValueArray.push([entry[0], entry[1]]); });
return keyValueArray;
}
function createViewTopLevelStmts(view: CompileView, targetStatements: o.Statement[]) {
var nodeDebugInfosVar: o.Expression = o.NULL_EXPR;
if (view.genConfig.genDebugInfo) {
nodeDebugInfosVar = o.variable(`nodeDebugInfos_${view.component.type.name}${view.viewIndex}`);
targetStatements.push(
(<o.ReadVarExpr>nodeDebugInfosVar)
.set(o.literalArr(view.nodes.map(createStaticNodeDebugInfo),
new o.ArrayType(new o.ExternalType(Identifiers.StaticNodeDebugInfo),
[o.TypeModifier.Const])))
.toDeclStmt(null, [o.StmtModifier.Final]));
}
var renderCompTypeVar: o.ReadVarExpr = o.variable(`renderType_${view.component.type.name}`);
if (view.viewIndex === 0) {
targetStatements.push(renderCompTypeVar.set(o.NULL_EXPR)
.toDeclStmt(o.importType(Identifiers.RenderComponentType)));
}
var viewClass = createViewClass(view, renderCompTypeVar, nodeDebugInfosVar);
targetStatements.push(viewClass);
targetStatements.push(createViewFactory(view, viewClass, renderCompTypeVar));
}
function createStaticNodeDebugInfo(node: CompileNode): o.Expression {
var compileElement = node instanceof CompileElement ? node : null;
var providerTokens: o.Expression[] = [];
var componentToken: o.Expression = o.NULL_EXPR;
var varTokenEntries = [];
if (isPresent(compileElement)) {
providerTokens = compileElement.getProviderTokens();
if (isPresent(compileElement.component)) {
componentToken = createDiTokenExpression(identifierToken(compileElement.component.type));
}
StringMapWrapper.forEach(compileElement.referenceTokens, (token, varName) => {
varTokenEntries.push(
[varName, isPresent(token) ? createDiTokenExpression(token) : o.NULL_EXPR]);
});
}
return o.importExpr(Identifiers.StaticNodeDebugInfo)
.instantiate(
[
o.literalArr(providerTokens, new o.ArrayType(o.DYNAMIC_TYPE, [o.TypeModifier.Const])),
componentToken,
o.literalMap(varTokenEntries, new o.MapType(o.DYNAMIC_TYPE, [o.TypeModifier.Const]))
],
o.importType(Identifiers.StaticNodeDebugInfo, null, [o.TypeModifier.Const]));
}
function createViewClass(view: CompileView, renderCompTypeVar: o.ReadVarExpr,
nodeDebugInfosVar: o.Expression): o.ClassStmt {
var viewConstructorArgs = [
new o.FnParam(ViewConstructorVars.viewUtils.name, o.importType(Identifiers.ViewUtils)),
new o.FnParam(ViewConstructorVars.parentInjector.name, o.importType(Identifiers.Injector)),
new o.FnParam(ViewConstructorVars.declarationEl.name, o.importType(Identifiers.AppElement))
];
var superConstructorArgs = [
o.variable(view.className),
renderCompTypeVar,
ViewTypeEnum.fromValue(view.viewType),
ViewConstructorVars.viewUtils,
ViewConstructorVars.parentInjector,
ViewConstructorVars.declarationEl,
ChangeDetectionStrategyEnum.fromValue(getChangeDetectionMode(view))
];
if (view.genConfig.genDebugInfo) {
superConstructorArgs.push(nodeDebugInfosVar);
}
var viewConstructor = new o.ClassMethod(null, viewConstructorArgs,
[o.SUPER_EXPR.callFn(superConstructorArgs).toStmt()]);
var viewMethods = [
new o.ClassMethod('createInternal', [new o.FnParam(rootSelectorVar.name, o.STRING_TYPE)],
generateCreateMethod(view), o.importType(Identifiers.AppElement)),
new o.ClassMethod(
'injectorGetInternal',
[
new o.FnParam(InjectMethodVars.token.name, o.DYNAMIC_TYPE),
// Note: Can't use o.INT_TYPE here as the method in AppView uses number
new o.FnParam(InjectMethodVars.requestNodeIndex.name, o.NUMBER_TYPE),
new o.FnParam(InjectMethodVars.notFoundResult.name, o.DYNAMIC_TYPE)
],
addReturnValuefNotEmpty(view.injectorGetMethod.finish(), InjectMethodVars.notFoundResult),
o.DYNAMIC_TYPE),
new o.ClassMethod('detectChangesInternal',
[new o.FnParam(DetectChangesVars.throwOnChange.name, o.BOOL_TYPE)],
generateDetectChangesMethod(view)),
new o.ClassMethod('dirtyParentQueriesInternal', [], view.dirtyParentQueriesMethod.finish()),
new o.ClassMethod('destroyInternal', [], view.destroyMethod.finish())
].concat(view.eventHandlerMethods);
var superClass = view.genConfig.genDebugInfo ? Identifiers.DebugAppView : Identifiers.AppView;
var viewClass = new o.ClassStmt(view.className, o.importExpr(superClass, [getContextType(view)]),
view.fields, view.getters, viewConstructor,
viewMethods.filter((method) => method.body.length > 0));
return viewClass;
}
function createViewFactory(view: CompileView, viewClass: o.ClassStmt,
renderCompTypeVar: o.ReadVarExpr): o.Statement {
var viewFactoryArgs = [
new o.FnParam(ViewConstructorVars.viewUtils.name, o.importType(Identifiers.ViewUtils)),
new o.FnParam(ViewConstructorVars.parentInjector.name, o.importType(Identifiers.Injector)),
new o.FnParam(ViewConstructorVars.declarationEl.name, o.importType(Identifiers.AppElement))
];
var initRenderCompTypeStmts = [];
var templateUrlInfo;
if (view.component.template.templateUrl == view.component.type.moduleUrl) {
templateUrlInfo =
`${view.component.type.moduleUrl} class ${view.component.type.name} - inline template`;
} else {
templateUrlInfo = view.component.template.templateUrl;
}
if (view.viewIndex === 0) {
initRenderCompTypeStmts = [
new o.IfStmt(renderCompTypeVar.identical(o.NULL_EXPR),
[
renderCompTypeVar.set(ViewConstructorVars
.viewUtils.callMethod('createRenderComponentType',
[
o.literal(templateUrlInfo),
o.literal(view.component
.template.ngContentSelectors.length),
ViewEncapsulationEnum
.fromValue(view.component.template.encapsulation),
view.styles
]))
.toStmt()
])
];
}
return o.fn(viewFactoryArgs, initRenderCompTypeStmts.concat([
new o.ReturnStatement(o.variable(viewClass.name)
.instantiate(viewClass.constructorMethod.params.map(
(param) => o.variable(param.name))))
]),
o.importType(Identifiers.AppView, [getContextType(view)]))
.toDeclStmt(view.viewFactory.name, [o.StmtModifier.Final]);
}
function generateCreateMethod(view: CompileView): o.Statement[] {
var parentRenderNodeExpr: o.Expression = o.NULL_EXPR;
var parentRenderNodeStmts = [];
if (view.viewType === ViewType.COMPONENT) {
parentRenderNodeExpr = ViewProperties.renderer.callMethod(
'createViewRoot', [o.THIS_EXPR.prop('declarationAppElement').prop('nativeElement')]);
parentRenderNodeStmts = [
parentRenderNodeVar.set(parentRenderNodeExpr)
.toDeclStmt(o.importType(view.genConfig.renderTypes.renderNode), [o.StmtModifier.Final])
];
}
var resultExpr: o.Expression;
if (view.viewType === ViewType.HOST) {
resultExpr = (<CompileElement>view.nodes[0]).appElement;
} else {
resultExpr = o.NULL_EXPR;
}
return parentRenderNodeStmts.concat(view.createMethod.finish())
.concat([
o.THIS_EXPR.callMethod('init',
[
createFlatArray(view.rootNodesOrAppElements),
o.literalArr(view.nodes.map(node => node.renderNode)),
o.literalArr(view.disposables),
o.literalArr(view.subscriptions)
])
.toStmt(),
new o.ReturnStatement(resultExpr)
]);
}
function generateDetectChangesMethod(view: CompileView): o.Statement[] {
var stmts = [];
if (view.detectChangesInInputsMethod.isEmpty() && view.updateContentQueriesMethod.isEmpty() &&
view.afterContentLifecycleCallbacksMethod.isEmpty() &&
view.detectChangesRenderPropertiesMethod.isEmpty() &&
view.updateViewQueriesMethod.isEmpty() && view.afterViewLifecycleCallbacksMethod.isEmpty()) {
return stmts;
}
ListWrapper.addAll(stmts, view.detectChangesInInputsMethod.finish());
stmts.push(
o.THIS_EXPR.callMethod('detectContentChildrenChanges', [DetectChangesVars.throwOnChange])
.toStmt());
var afterContentStmts = view.updateContentQueriesMethod.finish().concat(
view.afterContentLifecycleCallbacksMethod.finish());
if (afterContentStmts.length > 0) {
stmts.push(new o.IfStmt(o.not(DetectChangesVars.throwOnChange), afterContentStmts));
}
ListWrapper.addAll(stmts, view.detectChangesRenderPropertiesMethod.finish());
stmts.push(o.THIS_EXPR.callMethod('detectViewChildrenChanges', [DetectChangesVars.throwOnChange])
.toStmt());
var afterViewStmts =
view.updateViewQueriesMethod.finish().concat(view.afterViewLifecycleCallbacksMethod.finish());
if (afterViewStmts.length > 0) {
stmts.push(new o.IfStmt(o.not(DetectChangesVars.throwOnChange), afterViewStmts));
}
var varStmts = [];
var readVars = o.findReadVarNames(stmts);
if (SetWrapper.has(readVars, DetectChangesVars.changed.name)) {
varStmts.push(DetectChangesVars.changed.set(o.literal(true)).toDeclStmt(o.BOOL_TYPE));
}
if (SetWrapper.has(readVars, DetectChangesVars.changes.name)) {
varStmts.push(DetectChangesVars.changes.set(o.NULL_EXPR)
.toDeclStmt(new o.MapType(o.importType(Identifiers.SimpleChange))));
}
if (SetWrapper.has(readVars, DetectChangesVars.valUnwrapper.name)) {
varStmts.push(
DetectChangesVars.valUnwrapper.set(o.importExpr(Identifiers.ValueUnwrapper).instantiate([]))
.toDeclStmt(null, [o.StmtModifier.Final]));
}
return varStmts.concat(stmts);
}
function addReturnValuefNotEmpty(statements: o.Statement[], value: o.Expression): o.Statement[] {
if (statements.length > 0) {
return statements.concat([new o.ReturnStatement(value)]);
} else {
return statements;
}
}
function getContextType(view: CompileView): o.Type {
if (view.viewType === ViewType.COMPONENT) {
return o.importType(view.component.type);
}
return o.DYNAMIC_TYPE;
}
function getChangeDetectionMode(view: CompileView): ChangeDetectionStrategy {
var mode: ChangeDetectionStrategy;
if (view.viewType === ViewType.COMPONENT) {
mode = isDefaultChangeDetectionStrategy(view.component.changeDetection) ?
ChangeDetectionStrategy.CheckAlways :
ChangeDetectionStrategy.CheckOnce;
} else {
mode = ChangeDetectionStrategy.CheckAlways;
}
return mode;
}

View File

@ -1,34 +0,0 @@
import {Injectable} from '@angular/core';
import * as o from '../output/output_ast';
import {CompileElement} from './compile_element';
import {CompileView} from './compile_view';
import {buildView, finishView, ViewCompileDependency} from './view_builder';
import {bindView} from './view_binder';
import {CompileDirectiveMetadata, CompilePipeMetadata} from '../compile_metadata';
import {TemplateAst} from '../template_ast';
import {CompilerConfig} from '../config';
export class ViewCompileResult {
constructor(public statements: o.Statement[], public viewFactoryVar: string,
public dependencies: ViewCompileDependency[]) {}
}
@Injectable()
export class ViewCompiler {
constructor(private _genConfig: CompilerConfig) {}
compileComponent(component: CompileDirectiveMetadata, template: TemplateAst[],
styles: o.Expression, pipes: CompilePipeMetadata[]): ViewCompileResult {
var statements = [];
var dependencies = [];
var view = new CompileView(component, this._genConfig, pipes, styles, 0,
CompileElement.createNull(), []);
buildView(view, template, dependencies);
// Need to separate binding from creation to be able to refer to
// variables that have been declared after usage.
bindView(view, template);
finishView(view, statements);
return new ViewCompileResult(statements, view.viewFactory.name, dependencies);
}
}

View File

@ -1,173 +0,0 @@
import {
beforeEach,
ddescribe,
describe,
expect,
iit,
inject,
it,
xit,
} from '@angular/core/testing/testing_internal';
import {
CompileDirectiveMetadata,
CompileTypeMetadata,
CompileTemplateMetadata,
CompileProviderMetadata,
CompileDiDependencyMetadata,
CompileQueryMetadata,
CompileIdentifierMetadata,
CompileFactoryMetadata,
CompileTokenMetadata
} from '@angular/compiler/src/compile_metadata';
import {ViewEncapsulation} from '@angular/core/src/metadata/view';
import {ChangeDetectionStrategy} from '@angular/core/src/change_detection';
import {LifecycleHooks} from '@angular/core/src/metadata/lifecycle_hooks';
export function main() {
describe('CompileMetadata', () => {
var fullTypeMeta: CompileTypeMetadata;
var fullTemplateMeta: CompileTemplateMetadata;
var fullDirectiveMeta: CompileDirectiveMetadata;
beforeEach(() => {
var diDep = new CompileDiDependencyMetadata({
isAttribute: true,
isSelf: true,
isHost: true,
isSkipSelf: true,
isOptional: true,
token: new CompileTokenMetadata({value: 'someToken'}),
query: new CompileQueryMetadata({
selectors: [new CompileTokenMetadata({value: 'one'})],
descendants: true,
first: true,
propertyName: 'one'
}),
viewQuery: new CompileQueryMetadata({
selectors: [new CompileTokenMetadata({value: 'one'})],
descendants: true,
first: true,
propertyName: 'one'
})
});
fullTypeMeta = new CompileTypeMetadata(
{name: 'SomeType', moduleUrl: 'someUrl', isHost: true, diDeps: [diDep]});
fullTemplateMeta = new CompileTemplateMetadata({
encapsulation: ViewEncapsulation.Emulated,
template: '<a></a>',
templateUrl: 'someTemplateUrl',
styles: ['someStyle'],
styleUrls: ['someStyleUrl'],
ngContentSelectors: ['*']
});
fullDirectiveMeta = CompileDirectiveMetadata.create({
selector: 'someSelector',
isComponent: true,
type: fullTypeMeta,
template: fullTemplateMeta,
changeDetection: ChangeDetectionStrategy.Default,
inputs: ['someProp'],
outputs: ['someEvent'],
host: {'(event1)': 'handler1', '[prop1]': 'expr1', 'attr1': 'attrValue2'},
lifecycleHooks: [LifecycleHooks.OnChanges],
providers: [
new CompileProviderMetadata({
token: new CompileTokenMetadata({value: 'token'}),
multi: true,
useClass: fullTypeMeta,
useExisting: new CompileTokenMetadata({
identifier: new CompileIdentifierMetadata({name: 'someName'}),
identifierIsInstance: true
}),
useFactory: new CompileFactoryMetadata({name: 'someName', diDeps: [diDep]}),
useValue: 'someValue',
})
],
viewProviders: [
new CompileProviderMetadata({
token: new CompileTokenMetadata({value: 'token'}),
useClass: fullTypeMeta,
useExisting: new CompileTokenMetadata(
{identifier: new CompileIdentifierMetadata({name: 'someName'})}),
useFactory: new CompileFactoryMetadata({name: 'someName', diDeps: [diDep]}),
useValue: 'someValue'
})
],
queries: [
new CompileQueryMetadata({
selectors: [new CompileTokenMetadata({value: 'selector'})],
descendants: true,
first: false,
propertyName: 'prop',
read: new CompileTokenMetadata({value: 'readToken'})
})
],
viewQueries: [
new CompileQueryMetadata({
selectors: [new CompileTokenMetadata({value: 'selector'})],
descendants: true,
first: false,
propertyName: 'prop',
read: new CompileTokenMetadata({value: 'readToken'})
})
]
});
});
describe('CompileIdentifierMetadata', () => {
it('should serialize with full data', () => {
let full = new CompileIdentifierMetadata(
{name: 'name', moduleUrl: 'module', value: ['one', ['two']]});
expect(CompileIdentifierMetadata.fromJson(full.toJson())).toEqual(full);
});
it('should serialize with no data', () => {
let empty = new CompileIdentifierMetadata();
expect(CompileIdentifierMetadata.fromJson(empty.toJson())).toEqual(empty);
});
});
describe('DirectiveMetadata', () => {
it('should serialize with full data', () => {
expect(CompileDirectiveMetadata.fromJson(fullDirectiveMeta.toJson()))
.toEqual(fullDirectiveMeta);
});
it('should serialize with no data', () => {
var empty = CompileDirectiveMetadata.create();
expect(CompileDirectiveMetadata.fromJson(empty.toJson())).toEqual(empty);
});
});
describe('TypeMetadata', () => {
it('should serialize with full data', () => {
expect(CompileTypeMetadata.fromJson(fullTypeMeta.toJson())).toEqual(fullTypeMeta);
});
it('should serialize with no data', () => {
var empty = new CompileTypeMetadata();
expect(CompileTypeMetadata.fromJson(empty.toJson())).toEqual(empty);
});
});
describe('TemplateMetadata', () => {
it('should use ViewEncapsulation.Emulated by default', () => {
expect(new CompileTemplateMetadata({encapsulation: null}).encapsulation)
.toBe(ViewEncapsulation.Emulated);
});
it('should serialize with full data', () => {
expect(CompileTemplateMetadata.fromJson(fullTemplateMeta.toJson()))
.toEqual(fullTemplateMeta);
});
it('should serialize with no data', () => {
var empty = new CompileTemplateMetadata();
expect(CompileTemplateMetadata.fromJson(empty.toJson())).toEqual(empty);
});
});
});
}

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