Compare commits

..

488 Commits

Author SHA1 Message Date
f0ef72d6cc chore(release): releases alpha.22 2015-05-07 16:04:06 -07:00
a58c9f83bd fix(brocolli): escape special regexp characters when building regexps
Special regexp tokens were allowed unchanged previously, which incorrectly broke
the include/exclude behaviour. Now, they're escaped first.

Closes #1721
Closes #1752
2015-05-07 19:01:12 -04:00
624a33f7f8 chore(package.json): bump zone to 0.4.4 2015-05-07 15:58:28 -07:00
20a033e4c9 chore(material): add simple e2e smoke tests for components. 2015-05-07 15:13:30 -07:00
93c331d103 fix(decorators.es6): export Directive decorator
Closes #1688
2015-05-07 15:12:22 -07:00
51c477925a fix(formatter): point to the newest clang-format
The prior version allowed for an older clang-format binary which has bugs
2015-05-07 14:33:24 -07:00
1daa8aa3a1 chore(shrinkwrap): update dependencies to latest
Also, our package.json was out-of-sync with npm-shrinkwrap.json; see https://github.com/angular/angular/issues/1737
This includes a fix for the shrinkwrapping of ts2dart; see https://github.com/angular/ts2dart/issues/138
2015-05-07 14:29:43 -07:00
62bf777ef1 fix(docs): fix broken docs test after addition of .ts extension to dgeni
regex.
2015-05-07 14:05:57 -07:00
aaf3edd131 build(brocolli): move filename filtering into DiffingPluginWrapper
Closes #1719
2015-05-07 17:00:35 -04:00
6bba289a3c fix(build): build the broccoli tools with correct typescript version.
By default, gulp-typescript currently depends on typescript 1.4, which doesn't work for us.
For example, it doesn't allow `let` when emitting ES5, along with lots of other errors.
It so happens that npm sometimes makes this work, as seen by the warning
```npm WARN unmet dependency /Users/alexeagle/Projects/angular/node_modules/gulp-typescript requires typescript@'1.4.1' but will load
npm WARN unmet dependency /Users/alexeagle/Projects/angular/node_modules/typescript,
npm WARN unmet dependency which is version 1.5.0```
but when we update our node_modules in a certain way, we lose this setup and it breaks.

We should be explicit about using a different version of typescript than gulp-typescript depends on.
2015-05-07 13:37:40 -07:00
b0c735f72c fix(decorators): incorrect annotation to decorator adapter 2015-05-07 12:30:18 -07:00
0e2047f9ca chore(benchmarks): add transform benchmark runner and clean up benchmark output 2015-05-07 10:36:04 -07:00
e30ad2ec2c chore(doc-gen): include TypeScript files in the doc generation 2015-05-07 10:26:23 +01:00
c509057f65 chore(doc-gen): log comments as silly() rather than info() 2015-05-07 10:25:41 +01:00
e138add584 chore(doc-gen): provide aliases for jade-data docs 2015-05-07 10:25:02 +01:00
49777648b3 fix(decorators): fixed decorators 2015-05-06 21:08:55 -07:00
cb87fa0970 chore(build): migrated di to TypeScript 2015-05-06 19:00:56 -07:00
649e276610 chore: support last dev build of Dart at 1.10.0-dev.1.10
Can revert once 1.11 is available
2015-05-06 18:21:46 -07:00
5ef11774c2 chore: update pubspec files
Allow latest analyzer version
Add an upper constraint to the Dart SDK
2015-05-06 17:55:03 -07:00
75db2c5241 chore: add more types to a number of top-level properties and methods 2015-05-06 17:53:44 -07:00
c8ebd11d63 feat(dart/transform): Generate DirectiveMetadata for exports
For all files that export another library, include `DirectiveMetadata`
for the exported library in that file's associated `ng_meta.json` file.
2015-05-06 17:17:04 -07:00
6651aa1e1d chore(build): update to TypeScript @head
We need to pick up some bugfixes for decorator emit. This still has our patch to make Error a class.
2015-05-06 16:34:24 -07:00
3f28d08778 build bug fix 2015-05-06 15:53:58 -07:00
ab28676d02 more comments 2015-05-06 15:36:02 -07:00
577a80371f fixed build process by adding comment 2015-05-06 15:27:25 -07:00
01fdb4afc6 chore(build): remove karma preprocessors
Custom karma preprocessors are no longer being used after 1676 and 1597
2015-05-06 14:06:40 -07:00
be7504d451 fix(decorators): fixes decorator reflection.
The bug appears when there are only type annotations without parameter
annotations.
2015-05-06 13:44:44 -07:00
169e4e862d refactor(dart/transform): Use render Compiler concepts
Update `TemplateCompiler` transform step to use abstractions used by the
render `Compiler`. For example, template code is now loaded via an
instance of `TemplateLoader` and external resources are fetched via an
instance of `XHR`.
2015-05-06 12:51:49 -07:00
abc3de7efe refactor(render): rename RenderView and RenderProtoView
Part of #1675
Closes #1705
2015-05-06 11:46:52 -07:00
0b1bb172c9 feat(dart/analysis): Build DirectiveMetadata for LibrarySpecificUnit
initial commit for the dart analyzer task
2015-05-06 11:00:44 -07:00
0856516ae9 refactor(renderer): separate compiler from renderer
Part of #1675
Closes #1702
2015-05-06 10:50:15 -07:00
705d3aacff build(gulp): fix concurrency and caching issues in test.unit.js and test.unit.dart tasks
previously there was a chance of race conditions that could sporadically fail the build.

additionally runing a task via gulp.start or runSequence always reruns its dependencies, which meant that we were blowing away
the build.tools build and rebuilding everything from scratch even during the interactive/watch mode. This meant that the build
pipeline cache was destroyed on every change and we never got the benefit of incremental compilation
2015-05-06 08:46:03 -07:00
1d0078415f build(broccoli): refactor typescript plugin to be incremental via DiffingBroccoliPlugin 2015-05-06 07:45:46 -07:00
9d1df21d91 build(gulp): do no rebuild tools during test.unit.cjs
This introduces private !build.js.cjs task that is to be executed only from other public tasks.
2015-05-06 07:45:46 -07:00
3f36a3c119 build(broccoli): traceur plugin should react only to .js/.es6/.cjs file removal 2015-05-06 07:45:46 -07:00
8c15ccecd1 build(broccoli): add DiffingBroccoliPlugin and refactor existing plugins to use it
tree-differ:
 - export both TreeDiffer and DiffResult  interface

 diffing-broccoli-plugin:
 - factory class for wrapping DiffingBroccoliPlugins and turning them into BroccoliTrees

 broccoli-dest-copy:
 - refactor into DiffingBroccoliPlugin

 broccoli-traceur:
 - refactor into DiffingBroccoliPlugin
2015-05-06 07:45:45 -07:00
e966869744 build(broccoli.d.ts): add tree.description signature 2015-05-06 07:45:45 -07:00
6b017fb388 build(gulp): create private build.tools task and use it instead of magic variable
This way when gulp prints out that it's running build/clean.tools it really means
that it's cleaning up the build directory.
2015-05-06 07:45:45 -07:00
bb6f59e423 chore(build): make karma watch broccoli output for dart unit tests
Previously, karma used a custom preprocessor. Instead, have karma
run built dart from the `dist` folder and use gulp and broccoli
to watch for changes.
2015-05-05 19:24:20 -07:00
c9cec60007 fix(router): fix for leading slash in dart
Using string1 === string2 translates to identical(string1, string2) in
dart, which is incorrect as it is possilbe for dart strings to have
different reference.
2015-05-05 15:19:06 -07:00
f356d03362 feat(dom): add location and history as DOM-like APIs.
Instead of global access methods.
2015-05-05 14:50:53 -07:00
0520ca68b4 feat(dart/transform): Add DirectiveMetadataExtractor transform step
Add a step that reads `DirectiveMetadata` object off annotated classes
into `.ng_meta.dart` files. These will be used by the `TemplateCompiler`
step as inputs to the Angular 2 render compiler.

Update one test to avoid unsupported functionality, format others.
2015-05-05 12:07:50 -07:00
8e1d53b5e9 feat(router): adds the router to the self-executing bundle.
Due to limitation of system build, the router cannot have its own sfx
bundle.

Fixes an issue with RouteConfig decorator by moving it into its own
file.
2015-05-05 10:55:23 -07:00
f5b56c627b refactor: add types to top-level fields in change_detection
Also introduced an abstract PipeFactory base class
2015-05-05 10:21:56 -07:00
740d85cad8 chore(build): change TS Error type to a class.
This will be in the next upstream release.
2015-05-05 09:03:56 -07:00
33bba094d2 chore(build): fix package.json warning
Nit: the contributors field is defined as an array, see
https://docs.npmjs.com/files/package.json#people-fields-author-contributors
2015-05-05 09:02:57 -07:00
f88c4b77ca feat(material): add prototype dialog component w/ demo. 2015-05-04 16:43:15 -07:00
75da6e4c4a feat(router): export decorator version of RouteConfig 2015-05-04 15:44:16 -07:00
1864f60afb feat(benchmarks): Add basic dart transformer benchmarks.
Adds simple benchmarks for various transformation phases, as well as hello_world.
Does not integrate these into any benchmark frameworks yet.
2015-05-04 14:03:58 -07:00
457c15cd6c feat(decorators): adds decorator versions of DI annotations.
In 'angular2/di' the symbol:
- Inject is a decorator
- InjectAnnotation is an annotation

Internally one an get a hold of annotations without *Annotations appened
(to make ts2dart work without workarounds) by importing from
'angular2/src/di/annotations_impl' instead of 'angular2/di'. This is
needed only for users that transpile through TS and through ts2dart.
2015-05-04 13:35:09 -07:00
28feac9411 refactor(router): rename "alias" to "as" 2015-05-03 20:37:00 -07:00
9153331303 feat(router): route redirects 2015-05-03 20:37:00 -07:00
9d5c33f9dd feat(router): sibling outlets 2015-05-03 20:26:47 -07:00
2713b7877b fix(router): navigate on popstate event 2015-05-03 20:26:22 -07:00
2f0fef8ee1 chore(router): add router bundle to gulpfile 2015-05-01 16:43:19 -07:00
259f872cea fix(router): throw if config does not contain required fields 2015-05-01 16:41:25 -07:00
68ed8f1b6b refactor(router): rename LocationMock to LocationSpy 2015-05-01 16:41:25 -07:00
ef7014fe19 feat(router): export routerInjectables 2015-05-01 16:41:25 -07:00
46ad3552c7 fix(router): infer top-level routing from app component
Closes #1600
2015-05-01 16:41:25 -07:00
4965226f3f fix(router): use lists for RouteConfig annotations 2015-05-01 15:55:53 -07:00
ea546f5069 feat(router): add location service 2015-05-01 15:55:53 -07:00
cf32213079 fix(bundle): update the bundle config to point to rx.js 2015-05-01 15:01:18 -07:00
ce6a2ba836 refactor(view): moved the logic from ProtoView to ProtoViewFactory 2015-05-01 13:35:17 -07:00
0f4a089c32 chore(packaging): switch to conventional changelog 2015-05-01 13:10:14 -07:00
3c77855b39 chore(build): Remove .es6 files which shadow .ts files.
This removes .es6 files which are pure duplicates of a
.ts file in the same folder.
Next we need to remove .js files as well, and remove karma preprocessors for dart.
2015-05-01 09:51:03 -07:00
c1579222bd fix(view): changed view manager to hydrate change detector after creating directives 2015-04-30 22:01:55 -07:00
f863ea0db5 feat(decorators): adds support for parameter decorators.
Paramater decorators expect to be called as currently implemented by TS.
2015-04-30 18:42:40 -07:00
e4342743c0 feat(benchmark): added an implementation of the tree benchmark in React 2015-04-30 18:12:21 -07:00
9e8d31d532 fix(compiler): clone templates before compiling them
This is needed as the compiler changes templates during compilation
and we are caching templates in the `TemplateLoader`.

Closes #1058
2015-04-30 16:40:57 -07:00
f75a50c1dd refactor(compiler): rename decorator directives into directive
BREAKING CHANGE:
Previously, `Directive` was the abstract base class of several directives.
Now, `Directive` is the former `Decorator`, and `Component` inherits from it.
2015-04-30 13:38:40 -07:00
c671706518 refactor(benchpress): report forced gc metric separately 2015-04-30 12:15:30 -07:00
ead21c91a4 fix(exception_handler): log errors via console.error
This is e.g. needed as we use this to test for errors
in our examples.
2015-04-30 11:45:34 -07:00
87dcd5eb6f fix(decorators): updates missing benchmark and fixes typo. 2015-04-30 10:22:30 -07:00
8faf6364dc refactor(core): remove DynamicComponent
BREAKING CHANGE:
A dynamic component is just a component that has no @View annotation…
2015-04-30 09:17:25 -07:00
b71fe311fc chore(build): update clang-format to 1.0.10
Closes #1593
2015-04-30 15:54:08 +02:00
bb50fc131b chore(build): update TypeScript version to unreleased beta
Also fixup the typings which were broken by changes in typescript's lib.d.ts.
Second attempt to merge this, now that bugfix for tsd is in.
2015-04-29 17:03:02 -07:00
3aac2fefd7 refactor(compiler): remove Viewport directives, use Decorator instead
BREAKING_CHANGE:
- The special type of `Viewport` directives is removed
  in favor of a more general `Decorator` directive
- `ViewContainerRef` now no more has a default `ProtoViewRef`
  but requires an explicit one when creating views.

Closes #1536
2015-04-29 15:59:55 -07:00
fb67e37339 feat(decorators): adds decorators to be used by TS and Babel transpiled apps. 2015-04-29 15:13:25 -07:00
648c514c28 feat(dart/transform): Add directiveMetadata{To,From}Map
Add utility methods to convert `render.dom.DirectiveMetadata` to and
from maps. This will allow saving and restoring `DirectiveMetadata` in
the Angular 2 Transformer.

We discussed adding this as a member on `DirectiveMetadata`. Since this
is not necessary for anything except the Transformer, we decided to put
it into a separate file to avoid shipping it with the Angular 2 core
code.
2015-04-29 14:22:08 -07:00
511e832ee2 chore(build): Karma watches broccoli output.
This is a prerequisite for switching to TypeScript. We need to remove the Traceur preprocessor
from Karma, so we have the build specified in a single place (broccoli tree def'n).
2015-04-29 14:15:45 -07:00
09f8d8f7ba refactor(core): introduce ViewRef and ProtoViewRef
BREAKING CHANGES:
- `NgElement` merged into `ElementRef`
- `Compiler.compile…` returns `ProtoViewRef`
- `ViewContainer` uses `ProtoViewRef`s and `ViewRef`s.
- `ViewRef`/`ProtoViewRef` in renderer were renamed to
  `RenderViewRef`/`RenderProtoViewRef`.

Related to #1477
Closes #1592
2015-04-29 14:03:38 -07:00
1205f54d01 fix(build): use correct tsd command to get typings at requested versions 2015-04-29 11:43:28 -07:00
b5032fd374 fix(build): revert typescript upgrade which broke the build.
This reverts commit a7a9463624.
This reverts commit 59824e40e8.
2015-04-29 10:49:54 -07:00
a7a9463624 fix(build): refer to newest version of hammerjs typings 2015-04-29 10:13:30 -07:00
59824e40e8 chore(build): update TypeScript version to unreleased beta
Also fixup the typings which were broken by changes in typescript's lib.d.ts
2015-04-29 10:09:32 -07:00
a51a5c2968 chore(build): run forms tests in Node
Closes #1565
2015-04-29 13:58:07 +02:00
e3c11045bf fix(compiler): changed the compiler to set up event listeners and host properties on host view elements
Closes #1584
2015-04-29 05:27:45 +00:00
414e58edb5 chore(publishing): put malformed commit messages to "other"; do not output empty sections
Closes #1557
2015-04-29 04:10:12 +00:00
3bb3bff1f2 chore(packaging): copy changelog.js from angularjs 2015-04-29 04:10:12 +00:00
d2d4e7d783 refactor(parser): remove unused variables
Closes #1553
2015-04-29 04:08:42 +00:00
ee1b574baf fix(di): improve error messages for invalid bindings
Fixes #1515

Closes #1573
2015-04-28 23:42:36 +00:00
c0f3778dda docs(For): fix example to use for-of syntax
Closes #1572
2015-04-28 23:42:24 +00:00
d4925b61ff fix(change_detector): ensure that locals are only used when implicit receiver
closes #1542
2015-04-28 23:40:22 +00:00
5b104936ae chore(build): Add a tsconfig.json file, simply to allow Atom editor's Typescript plugin to
work without dropping tsconfig.json files and generated .js files in the
source directory.

Closes #1538
2015-04-28 23:39:39 +00:00
14988d4415 docs(core): updating some errors in 01_templates
Signed-off-by: Josh Kurz <jkurz25@gmail.com>

Closes #1529
2015-04-28 23:39:20 +00:00
cd953ceb48 docs(core): update core directives document
Signed-off-by: Josh Kurz <jkurz25@gmail.com>
2015-04-28 23:39:20 +00:00
726fecbfb6 feat(dart/transform): Turn on transform for examples/todo
- Tag services with `@Injectable()`
- Update `pubspec.yaml` to transform examples/todo.

Closes #1527
2015-04-28 23:38:08 +00:00
818bb9b697 test: changed test bed to run change detection twice to make sure there are no changes second time
Closes #1517
2015-04-28 23:37:09 +00:00
e4586249fa refactor(change_detection): removed NO_CHANGED and replaced it with WrappedValue 2015-04-28 23:37:09 +00:00
4c1e978536 cleanup(build): remove traceur-based Dart transpiler 2015-04-28 16:25:10 -07:00
3d62546314 fix(compiler): only sets viewDefinition absUrl if the view has either a template or templateUrl
fixes #1326
closes #1327
2015-04-28 15:40:07 -07:00
b9eab463f7 chore(): fix host properties for MD components. 2015-04-28 10:48:03 -07:00
dff4795e49 docs(README): update for linguistic consistency
Closes #1537
2015-04-28 19:06:02 +02:00
ab74e1ed4e docs(CHANGELOG.md): fix correct links to angular2
Closes #1577
2015-04-28 19:03:09 +02:00
902984cc10 chore(doc-gen): only generate angular.io module and _data docs for public modules 2015-04-28 14:54:47 +01:00
ce431f279e chore(doc-gen): don't show private class members in jade templates
Closes #1366
2015-04-28 14:47:38 +01:00
7fb2f2069c docs(Injector): remove unwanted tab characters in the examples
These mess up the jade templates that use tabs for structuring the output.
2015-04-28 14:31:35 +01:00
c269bd5d3c chore(doc-gen): generate docs for angular.io
You can generate docs for comsumption by the angular.io website by running:

```bash
gulp docs/angular.io
```

The generated docs can be found in `dist/angular.io`
2015-04-28 14:31:34 +01:00
b72eb0783b chore(packaging): bump version to 2.0.0-alpha.21; add changelog 2015-04-27 22:15:48 -07:00
a801da6f7c fix(ViewManager): dehydrate views recursively over ViewContainers
Closes #1560
2015-04-27 17:39:20 -07:00
6fcd3709cf fix(render): return views when destroyed in ViewContainer
Closes #1316
2015-04-27 17:39:09 -07:00
1b2754dacd feat(router): add initial implementation 2015-04-27 17:15:58 -07:00
e617ca6323 feat(facade): add isType method 2015-04-27 17:15:58 -07:00
15376a6d24 feat(dart/transform): Dedup getters, setters, & methods
Dedup the getters, setters, and methods generated by the transformer
when compiling a template.

Run `dartformat` over the transform code.
2015-04-27 17:04:31 -07:00
867705bd2c chore: put everything in the _analyze.dart file
6x faster dart analyze
2015-04-27 16:13:20 -07:00
6ab19dd095 docs(change_detection): document JitChangeDetection and DynamicChangeDetection
closes #1446
2015-04-27 15:34:40 -07:00
99fdb9ac41 fix(dart/transform): Use var instead of bool in generated files
If a source file hides `bool` (explicitly or implicitly via `show`), a
generated file using `bool` may not resolve.

Closes #1455
2015-04-27 14:23:24 -07:00
2827ca1559 build(broccoli): add a tree-differ workaround to browser trees 2015-04-27 10:50:59 -07:00
8ea03d0380 build(gulp): fix incremental compilation by reusing angularBuilder across watch re-reruns 2015-04-27 10:47:52 -07:00
d1ec2e18cd build(gulp): add test.unit.tools to test.js task 2015-04-27 10:47:52 -07:00
aa58e4bba5 build(gulp): add build/clean.tools task prevent test.unit.tools/ci from building
on our CI server we currently split each build into the building phase and testing phase, this change aligns test.unit.tools/ci
with the rest of ci test taskswq
2015-04-27 10:47:52 -07:00
0a97f0b645 build(js.cjs): re-enable tests that now pass in cjs
previously these tests were failing but now they pass on master
2015-04-27 10:47:52 -07:00
8a5cf896d0 build(gulp): remove obsolete config 2015-04-27 10:47:51 -07:00
22c79df98d build(gulp): remove gulp-jasmine, run tests in a new process instead
otherwise we see occasional failures due to require.cache and other global state collisions
2015-04-27 10:47:51 -07:00
a52798543a build(gulp): rename tasks build.broccoli.tools => build.tools + test.unit.broccoli => test.unit.tools 2015-04-27 10:47:51 -07:00
1cbdb9cd17 refactor(build): introduce AngularBuilder facade and clean up many things 2015-04-27 10:47:51 -07:00
4c9b8ebb0c build(gulp): remove obsolete gulp transformer 2015-04-27 10:47:51 -07:00
6aea629cd3 build(gulp): use strict mode for gulpfile
- a variable `public` was renamed since it is a reserved keyword in the strict mode
2015-04-27 10:47:51 -07:00
649fd5a7a9 chore(build): exclude tree-differ.ts from format-checking due to a bug in clang-format
see https://github.com/angular/clang-format/issues/4
2015-04-27 10:47:50 -07:00
40c4eb7240 build(gulp): refactor test.unit.broccoli to use task dependencies and not die when a compilation error occurs
With this change we also stop gulp task queue when an error in build.broccoli.tools occurs, that way we
don't bother testing when transpilation fails.
2015-04-27 10:47:50 -07:00
cd05ed8de9 docs(npm-shrinkwrap.readme.md): update instructions 2015-04-27 10:47:50 -07:00
42e7fc5252 build(broccoli): add source-maps to our broccoli tools 2015-04-27 10:47:50 -07:00
7740fc071c build(broccoli): convert traceur and broccoli-dest-copy plugins to use tree-differ
Also adding symlink-or-copy to our npm dependencies since our plugins now use it.
2015-04-27 10:47:50 -07:00
bdf6af9bd6 build(broccoli): add custom broccoli.d.ts file 2015-04-27 10:47:50 -07:00
2f83efaac8 build(broccoli): add tree-differ for diffing broccoli trees 2015-04-27 10:47:49 -07:00
32c5ab956c build(broccoli): add testing infrastructure for our build plugins
components:
- gulp test.unit.broccoli task
- mock-fs for mocking our FS in unit tests
- jasmine d.ts file for type checking

jasmine lib is provided by minijasmine2 so we don't need to include it explicitly
2015-04-27 10:47:49 -07:00
b111ca9471 chore(build): add tsd.cached.json to our .gitignore 2015-04-27 10:47:49 -07:00
725f909ff8 chore(build): refactor test.unit.cjs to use the broccoli pipeline
This change solves several problems:
- the broccoli pipeline is used to compile the node/cjs tree upon any change to the modules/ directory
- jasmine tests run in a new process removing the need to clean up environment after each test
- since we transpile only those test files that are actually needed for node/cjs build, we transpile less and don't need to filter out tests
2015-04-27 10:47:49 -07:00
427f0d021c perf(benchmarks): benchmark that measure cost of dynamic components 2015-04-27 10:16:53 -07:00
9fc9d53566 perf(benchmarks): benchmark measuring cost of decorators (fixes #1479) 2015-04-27 10:16:52 -07:00
6dece68bb8 refactor(core): rename ViewContainer to ViewContainerRef
This also renames InternalAppViewContainer into AppViewContainer

Related to #1477
Closes #1554
2015-04-27 10:12:21 -07:00
0676fef61f docs(directives): CSS selectors are used for directives
Closes #1544
2015-04-27 15:32:26 +02:00
1d52cfba13 chore(query_list.js): fix minor typos
Typos fixed

Closes #1549
2015-04-27 15:30:17 +02:00
bfa381b35a refactor(view): introduce AppViewManager to consolidate logic
AppViewManager is the single entry point to changing the view hierarchy.
It is split between the manager itself which does coordination and
helper methods, so both are easily testable in isolation.

Also, ViewContainer is now only a pure reference to a bound element
with the previous functionality but does not contain the list of views
any more.

Part of #1477
2015-04-24 20:26:18 -07:00
f78406392b fix(test_lib): support multi matches with deep equality for function calls 2015-04-24 17:53:41 -07:00
623edcd2d8 Copy a second package to TypeScript. 2015-04-24 15:49:04 -07:00
b5e350b18c cleanup(forms): do not export AbstractControl
Closes #1299
2015-04-24 13:57:03 -07:00
87cf434929 chore(sources): intro modules_dart; move analyzer code there
We have Dart code in `angular2` module that ought to be in its own
package. Examples include Dart analysis plugins, and potentially the
transformers (although transformers cannot be moved out just yet).
However, this code is Dart-only and it doesn’t make sense to use JS
directory layout for it. This commit introduces a sub-directory called
`modules_dart`. All modules in this directory are pure Dart packages
using standard pub directory layout. The code in these packages never
gets transpiled. It is directly copied to `dist` unmodified, except an
adjustment in relative paths in `pubspec.yaml` files.
2015-04-24 13:29:18 -07:00
4bab25b366 feat: alllow specifying directives as bindings
Related to #709
Closes #1498
2015-04-24 11:02:17 -07:00
6896305e34 fix: export ShadowDom strategies
Fixes #1510
Closes #1511
2015-04-24 08:41:37 +02:00
8ccafb0524 feat(view): reimplemented property setters using change detection 2015-04-23 11:55:27 -07:00
8a92a1f13e fix(angular2): export QueryList in angular2/core
Closes #1502
2015-04-23 11:04:30 -07:00
d0059b5d75 refactor(PipeRegistry): improve error messages
Closes #1504
2015-04-23 11:04:30 -07:00
fa8e059f28 refacor(lexer): remove unused ~/ operator
Closes #1509
2015-04-23 11:04:30 -07:00
8e18d6c6cf docs(annotations): fix casing in view annotation
- Fix the casing to match key name exposed for `templateUrl` in `View`
  annotation

Closes #1495
2015-04-23 11:04:30 -07:00
afe0e45453 feat(parser): support === and !== operators
Closes #1496

Closes #1500
2015-04-23 20:01:31 +02:00
2e3e41ba64 fix(ListWrapper): follow JS semantics 2015-04-23 09:46:09 +02:00
d74dd1126b cleanup(di): removed dead code 2015-04-22 14:48:53 -07:00
0ff99081bd DEVELOPER.md copyedit
Closes #1275
2015-04-21 17:10:15 -07:00
6f4b6783c0 docs(02_directives): TemplateConfig -> @View
for #1224

Closes #1325
2015-04-21 16:31:25 -07:00
b1bc792b56 BUG FIX: without specification, certain versions of bower install ./app/bower_components...
Closes #1409
2015-04-21 16:31:20 -07:00
d4b8a86509 Updating DEVELOPER.md with nits and grammar fixes.
These are mostly trivial, but I thought I'd fix them while reading through the doc.

Closes #1438
2015-04-21 16:31:16 -07:00
642e7e5c46 fix(benchpress): only print the CV when it is meaningful
When the mean is 0, the coefficient of variation is calculated to be
NaN, which is not meaningful, so instead of printing "+-NaN%", just
don't print the CV at all.

Closes #908

Closes #1444
2015-04-21 16:31:12 -07:00
4650d25a53 chore(package.json): upgrade zone.js to v0.4.3
Closes #1457
2015-04-21 16:30:40 -07:00
7551a28f1a chore: show dart2js package warnings for angular2, benchmarks, examples
Closes #1468
2015-04-21 16:22:49 -07:00
e51a48fe4c Fixed example for EventEmitter
I didn't get a full trace back for my evidence I got from making this example work. EventEmitter was instantiated and assigned to wrong property. Also the mapping should be done using the component property name as it will be obtained via accessor and exposed on the directive (as far as I understood).
2015-04-21 16:22:10 -07:00
22c6c09daf chore(build): run event tests in Node
Closes #1476
2015-04-21 16:21:39 -07:00
e70a2f21dd fix(dom): remove methods is allowed on text nodes as well
Fixes #1473
Closes #1478
2015-04-21 11:56:11 -07:00
97e6fb6835 fix(benchmarks): wait for end of benchmarks 2015-04-21 11:25:07 -07:00
14a7b9f794 fix(jsserve): serve empty favicon to prevent errors in benchmarks
Background: our benchmarks check whether there were errors
in the browser log after they executed.
2015-04-21 11:25:07 -07:00
fa1ec48549 chore(example): fix TODO example on dart
Reflection for Dart was not set up properly for the TODO example,
so it was failing when served on dartium via
gulp serve/examples.dart
2015-04-21 10:17:26 -07:00
f7f06c5ad4 chore: add more type annotations 2015-04-21 08:49:05 -07:00
e23004df52 fix(di): capture original exception in InvalidBindingError
Fixes #1406

Closes #1459
2015-04-21 10:59:44 +02:00
fe70c2647a chore(packaging): bump version to 2.0.0-alpha.20 2015-04-20 17:53:29 -07:00
ada1e642c5 feat(view): add imperative views 2015-04-20 17:18:44 -07:00
817c79ca77 refactor(testability): rename function to get testability
Previously, getting testability was `window.angular2.getTestability`
This was because the plan was to export the API to the window as
angular2. However, the decision was changed to make this just `angular`
in 3177576ad6

To decouple testability from the rest of the Angular API, just make it
one function, `window.getAngularTestability`.
2015-04-20 15:13:09 -07:00
a97a2266d3 feat(change_detection): added async pipe 2015-04-20 14:50:23 -07:00
8b3c808cb0 cleanup: remove an unused type 2015-04-20 14:24:16 -07:00
2d929e73ec cleanup(change_detection): moved pipes-related tests to the pipes dir 2015-04-20 14:24:15 -07:00
681d06386d feat(view): implemented loading component next to existing location 2015-04-20 13:41:10 -07:00
77b31ab42f feat(dart/transform): Add debug transform parameters
Add two transform parameters to aid in debugging the transformer
- `mirror_mode`, with values {`debug`, `none`, and `verbose`}
- `init_reflector`, with values {`true`, `false`}

`mirror_mode`:
- `debug`: Allow reflective access, but log a message if it is used
- `none`: Remove reflective access, `throw` if it is used. Default value
- `verbose`: Allow reflective access, log a stack trace if it is used

`init_reflector`: Whether to generate calls to our generated
`initReflector` code.

These will be useful to reveal areas where the transformer is not generating
appropriate code and to quickly see where reflective accesses occur.

When the pub mode is `transform_dynamic`, we run in MirrorMode.debug
with `init_reflector = false`. This is used for testing purposes.
2015-04-20 12:32:04 -07:00
5b4eb0c6d7 style(dart/transform): Format Dart files in reflection
Run the formatter on some Dart-specific reflection files.
2015-04-20 12:32:04 -07:00
5c25248582 docs(x-ref links): Change links to use dgeni syntax
Closes #1440
2015-04-20 18:45:04 +00:00
64ad74acbe fix(shadowdom): remove unused nodes on redistribute
Previously, light dom nodes that were not used by any content tag
were not removed from a view on redistribute. This lead
to a bug when reusing a view from the view pool, as it
still contained stale reprojected nodes.

Fixes #1416
2015-04-20 11:36:39 -07:00
02997f473a fix(viewFactory): allow empty view cache 2015-04-20 11:36:39 -07:00
abda569b55 docs(dart/transform): Link to the Transform wiki page
Add a link to the Dart Transform wiki page to DEVELOPER.md
2015-04-20 10:14:24 -07:00
447018b54b docs: change primordial injector to platform injector 2015-04-20 16:45:23 +00:00
0a200aff70 chore(doc-gen): fix atScript file reader test
Closes #1458
2015-04-20 17:43:46 +02:00
883e1c1541 feat(events): support preventdefault
Fixes #1039
Closes #1397
2015-04-20 15:20:52 +02:00
aabe83cf63 chore(build): run application tests in Node
Closes #1423
2015-04-20 14:45:18 +02:00
fbd6851860 chore(doc-gen): add ids to members to allow direct linking
You can now write a link to a member of a class by appending the member name
to the class name joined by a hash sign:

```
{@link ControlGroupDirective#addDirective `addDirective`}
```

By default the link will contain the text of the class rather than the member
so you must add it as an inline code text snippet in the link tag.

Closes #1432
2015-04-18 22:06:49 +01:00
d6dae0cc85 Tweak .gitignore file to ignore also packages symlinks. 2015-04-18 12:13:10 -07:00
376d508934 chore(doc-gen): read .es6 files as well as .js when generating docs
Closes #1429
2015-04-18 08:35:38 +01:00
a00cb1de50 feat(Compiler): Make Compiler.buildRenderDirective() static. 2015-04-17 21:57:25 -07:00
56f3429cc9 fix(view): chagned view factory to keep AstWithSource 2015-04-17 17:40:43 -07:00
4943c0f887 fix(view): fixed hydrator to pass the right element index when attaching an event listener 2015-04-17 17:27:12 -07:00
00e2d70f05 refactor(dart/transform): Remove index_static from hello_world
index_static.js & index_static.html are unnecessary in Js and are now
essentially generated via the Dart transformer. The angular
transformer is specified in examples/pubspec.yaml; use pub build to
create a transformed application that does not use dart:mirrors.

Create index_dynamic.js & index_dynamic.html, which are used to test
that the app runs equally well with mirrors and without.

Closes #495
2015-04-17 16:11:48 -07:00
e52d71060f chore(analysis): fix analyzer warning in index_static 2015-04-17 14:01:42 -07:00
01869f9fa8 chore(format): format a TS file 2015-04-17 13:56:13 -07:00
526c51d1a6 fix(facades): fix splice semantics; add test 2015-04-17 13:52:03 -07:00
2b4d30d931 chore(analysis): analyze everything in lib folders recursively; fix existing warnings 2015-04-17 13:52:02 -07:00
3dc4df2ffa chore(analysis): analyze web folders; fix existing warnings 2015-04-17 13:52:02 -07:00
f830cfca12 refactor(view): provide ViewContainers dynamically on any element 2015-04-17 12:35:59 -07:00
eac5c88893 fix(view): fixed hydrator to export the dom element instead of ng element 2015-04-17 12:32:33 -07:00
abfe175c9e doc(VmTurnZone): inline doc
Closes #1427
2015-04-17 18:19:59 +00:00
0fc66daef6 fix(core): typo ComponetRef -> ComponentRef
Closes #1426
2015-04-17 18:19:58 +00:00
5a095bb257 refactor(di): rename ProviderError to BindingError
Closes #1428
2015-04-17 20:17:51 +02:00
de31aca7a7 docs(di): Edits to DI.
Closes #1420
2015-04-17 17:49:12 +00:00
97220dd2ba docs(life_cycle): mark registerWith as @private 2015-04-17 16:25:13 +01:00
e1b0bab9a6 chore(doc-gen): ignore members marked with @private 2015-04-17 16:24:07 +01:00
66a2f9b23a docs(angular2/annotations): convert [...] links to use {@link ...} style inline tags
This is an example of how to link to other code components using the `link`
inline tag.
2015-04-17 14:02:03 +01:00
a8533b2133 chore(doc-gen): add link inline tags
This commit enables links to other docs, such as classes and modules,
via the `{@link CodeIdentifier}` style inline tag.

Dgeni identifies what you are linking to by comparing the identifier to the
aliases for each doc. If no alias matches the identifier then the dgeni
run exits with a missing doc in link error. If more than one alias matches
the identifier then dgeni exits with an ambiguous link error.

In the future we could build in some heuristics for choosing a preferred
doc when the link is ambiguous, such as choosing a public doc over a
non-public doc; and choosing a code component that is in the same module as
the doc where the link is found.

Currently there are two aliases for each API component: its name and its
identier. For example, if the `Directive` class is exported from
`angular2/annotations`, so its aliases are 'Directive' and
`angular2/annotations.Directive`.

There is an issue in the non-public doc generation, which means that it
does not yet have `{@link}` tags implemented. This is that when we re-export
a code component, it gets cloned into another module. This means that a
simple reference to the code component's name will always produce an
ambiguous link. This can be fixed with a heuristic as described above.
Meanwhile you can avoid this by always using the full id of the code
component if it is being re-exported.

Closes #1371
Closes #1421
2015-04-17 14:02:03 +01:00
87ac100c66 docs: add DI to public docs 2015-04-17 03:56:17 +00:00
487c4d23c1 chore: enable chrome browser tests on c9.io 2015-04-17 03:44:32 +00:00
8906cdbab8 chore(build): trigger npm postinstall when npm install is skipped
we temporarily need this because some of our dependencies are being installed via npm postinstall
2015-04-16 16:58:28 -07:00
88963b438f chore(travis): pin npm used to v2.7.4
Since we are currently stuck on node 0.10 (see #1396), this will at least help us avoid
some of the npm bugs present in older version that comes with 0.10.
2015-04-16 16:58:28 -07:00
4fd4a1d15c chore(travis): turn on travis cache for npm dependencies 2015-04-16 16:58:28 -07:00
371c8b8a1c chore(travis): add npm/install-dependencies.sh step in preparation for caching 2015-04-16 16:58:28 -07:00
eb87f5f851 chore(npm): add shrinkwrap to our project 2015-04-16 16:58:28 -07:00
27d227283c chore(npm): remove duplicate fs-extra dependency 2015-04-16 16:58:28 -07:00
ea9d24be31 chore(npm): move tsd update to post install and add tsd version to devDependencies 2015-04-16 16:58:27 -07:00
5408abca68 refactor(change_detection): removed global change detection objects so it is possible to override pipe registry 2015-04-16 15:57:45 -07:00
233cb0f96a feat(view): changed event emitters to be observables 2015-04-16 14:44:14 -07:00
8b28e99373 fix(benchpress): explicitly require navigation to finish before continuing 2015-04-16 14:04:41 -07:00
923d90bce8 refactor(views): clean up creating views in place and extract view_hydrator
Major changes:
- `compiler.compileRoot(el, type)`
  -> `compiler.compileInHost(type) + viewHydrator.hydrateHostViewInPlace(el, view)`
- move all `hydrate`/`dehydrate` methods out of `View` and `ViewContainer` into
  a standalone class `view_hydrator` as private methods and provide new public
  methods dedicated to the individual use cases.

Note: This PR does not change the current functionality, only moves it
into different places.

See design discussion in #1351, in preparation for imperative views.
2015-04-16 11:58:01 -07:00
97fc248e00 cleanup(di): changed an error message to be more descriptive 2015-04-16 11:06:20 -07:00
7bd682bb27 feat(parser): changed parser to parse pipes in the middle of a binding 2015-04-16 10:39:03 -07:00
e927342e58 Read only a single DirectiveMetadata (will be squashed) 2015-04-16 09:11:03 -07:00
ae84eb7462 refactor(dart/transform): Correct Dart analyzer warnings 2015-04-16 09:11:03 -07:00
f89bb8eaf3 Address code review comments 2015-04-16 09:11:03 -07:00
0d0b3a35da test(dart/transform): Add unit tests for DirectiveMetadataReader 2015-04-16 09:11:03 -07:00
cf7bef58b0 feat(dart/transform): Add the DirectiveMetadataReader
Add a class that parses and reads Directive metadata to prepare for
running the Render compiler in the Dart transformer.
2015-04-16 09:11:02 -07:00
c65fd31e86 feat(dart/transform): Detect annotations which extend Injectable or Template.
Create a method that recursively walks imports from an entry point and
determines where classes are registered.

Use this information to determine if a particular annotation implements or
extends Injectable or Template.
2015-04-16 07:17:24 -07:00
6600ac7031 chore: Fix missing analysis for lib and web directories
Pending issue to fix analyzer items in web: https://github.com/angular/angular/issues/1392
2015-04-15 20:58:29 -07:00
957384ceeb fix: Fix issues found by Dart analyzer 2015-04-15 20:58:29 -07:00
d3e391d176 chore(build): run render tests in Node
Closes #1358
2015-04-15 19:51:11 -07:00
0658d5602e chore(doc-gen): ignore exports marked as @private
Closes #1363
2015-04-15 19:50:01 -07:00
458213d055 docs(DEVELOPER.md): mention building JS or Dart selectively
Closes #1375
2015-04-15 19:48:38 -07:00
cd1295a823 Update 01_templates.md
Closes #1373
2015-04-15 19:48:34 -07:00
5d302c504e Update 02_directives.md
Closes #1374
2015-04-15 19:48:31 -07:00
68faddbf5c feat(change_detection): updated handling ON_PUSH detectors so they get notified when their bindings change 2015-04-15 16:21:21 -07:00
dc9c614da2 chore: break out warnings vs hints in build/analyze.dart
give a better report of errors
2015-04-15 15:46:16 -07:00
8c1adabe1c refactor(change_detection): renamed BindingPropagationConfig to ChangeDetectorRef 2015-04-15 12:58:58 -07:00
213dabdceb fix(view): remove dynamic components when the parent view is dehydrated
Also adds a bunch of unit tests for affected parts.

Fixes #1201
2015-04-15 12:53:21 -07:00
6ecaa9aebb feat(change detection): add removeShadowDomChild 2015-04-15 12:53:21 -07:00
cb2e646332 fix(tests): create default spys for all methods on a class 2015-04-15 12:53:20 -07:00
fef1dee7aa fix(dart/transform): Ensure consistent ordering of generated imports
- Linked imports are generated in a consistent order.
- Linked imports are generated immediately after their associated files.
2015-04-15 12:09:51 -07:00
e14543498c fix(build): remove import of gulp-traceur which pulls in a different version of traceur
This lead to build fails.
2015-04-15 11:17:42 -07:00
c25478380c docs(benchpress): add details about normalized mobile environment. 2015-04-15 10:12:13 -07:00
e819e97f9a docs: expose more API to public, document QueryList 2015-04-15 05:10:26 +00:00
f149ae79c6 feat(material): first ng2 material design components 2015-04-14 16:15:35 -07:00
ffe13078e5 feat(bundle): add script to push bundles to code.angularjs.org
Copied over from angular js 1.x.
2015-04-14 14:50:53 -07:00
f0d0fe0801 refactor(change_detection): cleaned up change_detection.js 2015-04-14 14:34:57 -07:00
d630d5baa5 docs(change_detection): document LifeCycle 2015-04-14 14:16:14 -07:00
7cac7c5157 refactor(dart/transform): Correct Dart analyzer warnings
- Fix numerous Dart analyzer warnings we had been ignoring.
- Delete unused `in_progress` dir
2015-04-14 13:41:22 -07:00
aba61f22a6 chore(build): Remove even more obsolete build config values. 2015-04-14 13:38:41 -07:00
8475c63a6a misc(docs): Edits and additions for Forms and Change Detection 2015-04-14 13:34:29 -07:00
2d09f84182 fix(build): Fail the build for certain TS errors. 2015-04-14 11:54:36 -07:00
ef6e0d8eb8 chore(build): remove obsolete html.js, copy.js, srcFolderInsertion. 2015-04-14 11:54:36 -07:00
db97d73c3b feat(build): Move HTML copying into the broccoli task.
This includes all tasks to construct a Dart tree, except for formatting, and
reverse engineers/refactors the various copy tools for added more sanity.
2015-04-14 11:54:31 -07:00
0e3d0fbec6 docs(change_detection): don't annotate exports that are already in public modules
Since `DynamicChangeDetection` and `JitChangeDetection` classes are alreadt in the
public module, they do not need to be annotated with a `@exportAs` tag

Closes #1353
2015-04-14 13:22:41 +01:00
896a1564ef chore(doc-gen): only clone docs that are actually being re-exported to a new module
Closes #1353
2015-04-14 13:20:49 +01:00
8b97cf1479 cleanup(view): changed ComponentRef to contain ElementRef instead of extending it 2015-04-13 19:30:00 -07:00
b5c9f9ed9b cleanup(element_injector): added a missing test 2015-04-13 19:30:00 -07:00
bda120d862 chore(pub): run build/pubspec.dart before build/analyzer.dart 2015-04-13 18:34:34 -07:00
3177576ad6 feat(bundle): adds a self-executing dev bundle (SFX). 2015-04-13 18:05:53 -07:00
896a0457f8 refactor(build): Better encapsulate the broccoli builder. 2015-04-13 17:28:00 -07:00
caf8e2723d chore(build): remove obsolte gulp tasks 2015-04-13 16:52:08 -07:00
0107543a33 chore(build): move build/transformCJSTests task to broccoli 2015-04-13 16:52:08 -07:00
7d29636087 chore(packaging): bump version to 2.0.0-alpha.19 2015-04-13 16:15:12 -07:00
70433e6b73 chore(build): use a Filter plugin to write the dest folder.
This lets broccoli keep the dest folder up-to-date in 'watch' mode,
so we should be able to use that for Karma.
2015-04-13 15:51:33 -07:00
3667854a8f refactor(di): move all binding resolution logic into injector.js 2015-04-13 15:06:44 -07:00
c5c1c9e38e feat(docs): more docs on binding resolution 2015-04-13 15:06:44 -07:00
308823b6ea perf(view): use pre-resolved bindings for child injector init
Creating a child injector from pre-resolved bindings (if any) is an
order of magnitude faster.
2015-04-13 15:06:44 -07:00
c05bad381c perf(benchmark): measure Injector init from resolved bindings 2015-04-13 15:06:44 -07:00
4a961f4ecb feat(di): provide two ways to create an injector, resolved and unresolved
Add two factory static functions to Injector: resolveAndCreate and
fromResolvedBindings.

We want to avoid resolution and flattening every time we create a new
injector. This commit allows the user to cache resolved bindings and
reuse them.
2015-04-13 15:06:43 -07:00
6c8398df9b fix(di): refactor bindings to support Dart annotations 2015-04-13 15:06:43 -07:00
ff6e7754ae chore(build): gulp test.unit.cjs broken the second run
Fixes #1311

Closes #1333
2015-04-13 21:44:54 +00:00
28ba179e31 feat: intiial commit for angular 2 dart analysis
Initial commit for analysis support to Angular 2 Dart
2015-04-13 13:50:29 -07:00
b96e560c8d feat(events): add support for global events
Fixes #1098
Closes #1255
2015-04-13 22:35:36 +02:00
7c95cea3a8 chore(bundle): avoid imports in "global" format
If an "empty" file (like angular2/template.js) is imported
it is auto-detected as the one using "global" format by the
system builder. This is incorrect as the entire angular2 build
output is in the ES6 format.

Removing empty import till it has some content.

Closes #1329
2015-04-13 21:24:56 +02:00
34501aaae6 chore(build): move more broccoli support inside the TypeScript boundary 2015-04-13 12:24:28 -07:00
dbfc4c1c16 chore(build): inline Traceur options just like we do everywhere 2015-04-13 11:37:18 -07:00
301863b105 chore(build): transpile only e2e test code into cjs 2015-04-13 11:31:14 -07:00
ef8dc40492 chore(build): correct comment 2015-04-13 11:31:14 -07:00
6dbd4d969b chore(build): create es5build.js only for files that will become es6 npm packages 2015-04-13 11:31:14 -07:00
3dd0ac1f0a chore(build): move dart broccoli tree to make-broccoli-tree 2015-04-13 11:20:59 -07:00
5b42272365 docs(DEVELOPER.md): add bower install info
Closes #1310
2015-04-13 20:15:29 +02:00
1f6c6dbf2f chore(build): refactor broccoli trees to generate them in order to reduce duplication 2015-04-13 10:07:31 -07:00
0012caa4d5 perf(benchmarks): measure cost of Injector init with a variety of bindings 2015-04-13 10:02:13 -07:00
8499cf84c3 fix(shadow_dom): redistribute light dom when a dynamic component is attached.
Fixes #1077
Closes #1315
2015-04-13 09:23:52 -07:00
daf0f472b3 feat(build): enforce formatting of some files.
Our style guide includes formatting conventions. Instead of wasting time in reviewing PRs discussing things like indenting, and to avoid later deltas to fix bad formatting in earlier commits, we want to enforce these in the build.
The intent in this change is to fail the build as quickly as possible in travis, so those sending a PR immediately know they should run clang-format and update their commit. When running locally, we want users to know about formatting, but they may not want to act on it immediately, until they are done working. For this reason, it is only a warning outside of the continuous build.
This is done by having a check-format task which should run on most local builds, and an enforce-format task only run by travis.
2015-04-11 18:39:28 -07:00
a3decad4c2 feat(build): Use broccoli for ts2dart transpilation. 2015-04-11 16:26:44 -07:00
7b790a3369 chore(build): fix check-format 2015-04-11 12:40:05 -07:00
e18920884e chore(DEVELOPER.md): Update Dart SDK Version
Package angular requires SDK version >=1.9.0 <2.0.0

Closes #1318
2015-04-11 12:06:50 +02:00
6f8fef4f13 feat(bootstrap): changed bootstrap to return ComponentRef 2015-04-10 18:14:59 -07:00
e295940833 cleanup(docs): Edited API docs 2015-04-10 18:02:10 -07:00
2ed7622239 chore(build): compile the .ts broccoli tools.
This avoids having to check in the compiled .js files.
2015-04-10 17:29:32 -07:00
6ce085a21a feat(benchmark): make view cache a parameter to the tree benchmark 2015-04-10 16:57:46 -07:00
e34146fc14 fix(view_factory): fix caching of views
Previous implementation had bugs, and did not cache per ProtoView.
2015-04-10 16:57:45 -07:00
4e2316c742 feat(build): Add rudimentary TS typings for broccoli. 2015-04-10 16:37:24 -07:00
785900f722 DEVELOPER.md copyedit 2015-04-10 23:34:06 +00:00
5ce5a87abe style: add more type info to Dart BrowserAdapter 2015-04-10 23:34:06 +00:00
afe5465862 add return types for indexOf and lastIndexOf
closes #1277
2015-04-10 23:34:05 +00:00
678d541da7 refactor(compiler): add control.ignoreCurrentElement() to skip the current element
relates to #808
2015-04-10 23:34:05 +00:00
f0477e164a chore(build): add typescript to the cjs build.
Refactor the file extension logic in traceur plugin to simplify
2015-04-10 15:22:03 -07:00
b5002fb46b docs(test_lib/test_injector): fix invalid jsdoc type
chore(doc-gen): capture docs for modules from comments

Closes #1258

docs(*): add module description jsdoc tags
docs(*): add @public tag to public modules
chore(doc-gen): fix overview-dump template
The template was referencing an invalid property
chore(doc-gen): use `@exportedAs` and `@public` rather than `@publicModule`

This commit refactors how we describe components that are re-exported in another
module. For example the "public" modules like `angular/angular` and `angular/annotations`
are public but they only re-export components from "private" modules.

Previously, you must apply the `@publicModule` tag to a component that was to be
re-exported. Applying this tag caused the destination module to become public.

Now, you specify that a module is public by applying the `@public` tag and then
you can "re-export" components to other modules by applying the `@exportedAs`
giving the name of the module from which the component will be re-exported.
tag. This tag can be used multiple times on a single component, allowing the
component to be exported on multiple modules.

docs(*): rename `@publicModule` to `@exportedAs`

The `@publicModule` dgeni tag has been replaced by the `@exportedAs`
dgeni tag on components that are to be re-exported on another module.

Closes #1290
2015-04-10 22:00:41 +00:00
82127571b5 feat(dart/transform): Use the Dart transformer for benchmarks
Remove explicit generation of reflection information in benchmark code
and generate it with the transformer.
2015-04-10 14:01:55 -07:00
f6e9d1f857 feat(dart/transform): Fix handling of Dart keywords
Use `package:analyzer`'s list of Dart keywords to ensure we are properly
reporting usages of Dart keywords as runtime errors.
2015-04-10 13:43:11 -07:00
2cab7c79c3 feat(dart/transform): Allow multiple transformer entry points
- Allow the user to specify multiple entry points to an app.
- Allow the Angular 2 transformer to run without explicit entry points to
generate necessary setters & getters on built-in directives like `For`
and `If`.

Closes #1246
2015-04-10 13:41:26 -07:00
bba849909c fix(dart/transform): Gracefully handle log calls before init
- Lazily create and use a logger that prints instead of `throw`ing.
- Use this logger in unit tests.
2015-04-10 13:41:26 -07:00
cac74c73e1 feat(dart/transform): Add stub implementations to Html5LibAdapter
Stub out some methods used in the `CompilerPipeline`.
2015-04-10 13:41:26 -07:00
f375dbd013 feat(dart/transform): Mark Compiler as Injectable
Necessary to allow runtime access via the `Injector`
2015-04-10 13:41:26 -07:00
ea58ef85fc chore(build): move the js.prod build over to broccoli 2015-04-10 13:11:58 -07:00
bf7933714a chore(rename): rename View and Template concepts for #1244 2015-04-10 12:00:37 -07:00
564477b8a0 chore(build): migrate build.js.cjs to broccoli.
This doesn't do the typescript part of the build yet. Also there is a bit
of hackiness left to resolve in a follow-up change.
2015-04-10 11:39:48 -07:00
7e2c04e805 feat: add class directive to a list of directives
Closes #1292
2015-04-10 18:33:51 +02:00
8fa1539bac feat(keyEvents): support for <div (keyup.enter)="callback()">
This commit adds a plugin for the event manager, to allow a key name to
be appended to the event name (for keyup and keydown events), so that
the callback is only called for that key.

Here are some examples:
 (keydown.shift.enter)
 (keyup.space)
 (keydown.control.shift.a)
 (keyup.f1)

Key names mostly follow the DOM Level 3 event key values:
http://www.w3.org/TR/DOM-Level-3-Events-key/#key-value-tables

There are some limitations to be worked on (cf details
in https://github.com/angular/angular/pull/1136) but for now, this
implementation is reliable for the following keys (by "reliable" I mean
compatible with Chrome and Firefox and not depending on the keyboard
layout):
- alt, control, shift, meta (those keys can be combined with other keys)
- tab, enter, backspace, pause, scrolllock, capslock, numlock
- insert, delete, home, end, pageup, pagedown
- arrowup, arrowdown, arrowleft, arrowright
- latin letters (a-z), function keys (f1-f12)
- numbers on the numeric keypad (but those keys are not correctly simulated
by Chromedriver)

There is a sample to play with in examples/src/key_events/.

close #523
close #1136
2015-04-10 13:29:27 +02:00
f45281a10a feat(view): generalized loading of dynamic components 2015-04-09 22:15:42 -07:00
e9f70293ac feat(query): adds initial implementation of the query api.
Queries allow a directive to inject a live list of directives of a given
type from its LightDom. The injected list is Iterable (in JS and Dart).
It will be Observable when Observables are support in JS, for now it
maintains a simple list of onChange callbacks API.

To support queries, element injectors now maintain a list of
child injectors in the correct DOM order (dynamically updated by
viewports).

For performance reasons we allow only 3 active queries in an injector
subtree. The feature adds no overhead to the application when not
used. Queries walk the injector tree only during dynamic view
addition/removal as triggered by viewport directives.

Syncs changes between viewContainer on the render and logic sides.

Closes #792
2015-04-09 19:07:19 -07:00
61cb99ea42 refactor(change_detection): removed directive and binding mementos 2015-04-09 18:56:19 -07:00
5408a9a72d cleanup(change_detection): removed dead code 2015-04-09 18:56:19 -07:00
22c1a0d030 fix(benchmarks): Stop working around a Traceur bug. 2015-04-09 18:03:27 -07:00
8c3007e4b5 fix(build): Remove unused done function arguments.
gulp only requires receiving a done argument if a task is not returning
a stream. Doing both is unnecessary and confusing.
2015-04-09 18:03:27 -07:00
838aa2aaa9 fix(ts2dart): Adjust to new ts2dart API. 2015-04-09 18:03:27 -07:00
3285ffba16 fix(traceur): Fix a couple of unsupported or incorrect tests. 2015-04-09 18:03:27 -07:00
17e8857efc feat(dart): Use ts2dart for transpilation in Karma Dart. 2015-04-09 18:03:27 -07:00
226cbc7db3 feat(dart): Use ts2dart for transpilation.
This switches all transpilation over from using Traceur to using ts2dart, based
on the TypeScript tool chain. Transpilation is a bit slow due to issues with
the gulp integration, but that should be easily fixable once we move to
broccoli.
2015-04-09 18:03:27 -07:00
cc7c7b3321 fix(build): Don't include rtts in the dart build.
The module name actually does not include a trailing slash, so the
folder would show up and be included in the dart pubbuild.
2015-04-09 18:03:26 -07:00
70cea03b4b fix(build): Only return directories from subDirs() 2015-04-09 18:03:26 -07:00
a027912891 cleanup(change_detection): fixed ChangeDetector interface 2015-04-09 17:30:04 -07:00
3bdf669ddf cleanup(change_detection): removed dead code 2015-04-09 17:30:04 -07:00
b94b04c074 chore(build): Migrate remaining tasks under build.js.dev to broccoli. 2015-04-09 14:09:38 -07:00
cfc5dd830c perf(build): use patched broccoli-funnel version
see: https://github.com/broccolijs/broccoli-funnel/pull/22
2015-04-09 12:48:51 -07:00
a3097aaf05 chore(build): Migrate build.js.dev fully to broccoli.
The previous change did the ES6 transpile, now we add ES5.
The sourcemaps are broken, but were also broken previously. We'll address that separately.
2015-04-09 11:00:47 -07:00
69c3bff086 feat(change_detection): updated change detection to update directive directly, without the dispatcher 2015-04-08 22:14:50 -07:00
50098767fc refactor(render): use render layer fully
Introduces angular2/src/core/compiler/ViewFactory which
extracts ProtoView.instantiate and replaces ViewPool.

Note: This is a work in progress commit to unblock other commits.
There will be follow ups to add unit tests, remove TODOs, …
2015-04-08 20:51:31 -07:00
de581ea8b3 chore(build): Move broccoli support to own module.
Add support for multiple pipelines in different Brocfile's.
2015-04-08 10:41:42 -07:00
9f8a9c6fc7 chore(doc-gen): ensure all public exports are rendered in public_docs
Closes #1222
2015-04-08 18:58:44 +02:00
ad083ed28f fix(repo): .gitignore the broccoli tmp dir 2015-04-08 09:57:24 -07:00
105ba30ce9 chore(doc-gen): improve method signature formatting
Re-use the preformatting from the source code to layout method signatures
more cleanly.
2015-04-08 17:11:34 +02:00
ee8bf0b3c0 chore(doc-gen): HTML escape method signatures
Closes #1249
Closes #1257
2015-04-08 17:11:34 +02:00
41262f4265 feat(Ruler): introduce Ruler service
Closes #1089

Closes #1253
2015-04-08 11:04:42 +02:00
c349eb4fa4 fix(bundles): remove work-around rx.js module detection.
Updates rx to the newest version, because a fix is needed.

Closes #1245
2015-04-08 11:01:01 +02:00
ca958464c4 refactor(render): create and store render ProtoViewRef in every app ProtoView
Needed to change Renderer.mergeChildComponentProtoViews to not create
new ProtoViews to be able to deal with cyclic references.

This commit is part of using the new render layer in Angular.
2015-04-07 20:27:25 -07:00
d6003ee0ab chore(build): Add traceur transpiler for broccoli.
This exactly reproduces the output tree from one of the gulp tasks, which is now removed.
Next step is to migrate another sibling task to broccoli.
2015-04-07 16:38:02 -07:00
bc248e9a15 fix(build) use relative path in file property inside sourcemap 2015-04-07 12:53:06 -07:00
42c0171b40 chore(dart/transform): Create targets for serving transformed Dart code
- Allow pub (build|serve) to specify mode
- Update pubbuild.js & pubserve.js to allow the caller to provide a `mode` value.
- Update settings to allow the di benchmark to be transformed to run statically.
2015-04-07 10:57:01 -07:00
1a99090b45 chore(doc-gen): don't show Members heading if no members
Closes #1248
2015-04-07 09:23:19 +02:00
b7eea4f577 docs(directives): add # to for directive microsyntax example 2015-04-07 08:44:32 +02:00
9c62b5867e benchmark(change_detection): added a new set of benchmarks measuring updating properties 2015-04-06 18:13:20 -07:00
2560af731a refactor(dart): use Map instead of HashMap
Closes #1202
2015-04-06 17:16:54 +00:00
86211eb5f0 doc(directives): add inline documentation
Closes #1240
2015-04-06 17:11:23 +00:00
a3387b7f48 fix(di): allow injecting static attrs without type annotations
Closes #1226
2015-04-06 12:33:37 +02:00
94a48e8640 test(VmTurnZone): provide a stub VmTurnZone for CJS tests 2015-04-06 10:30:17 +02:00
d8aeb40b49 reafactor(XHR): rename XHRMock to MockXHR for consistency 2015-04-06 10:30:16 +02:00
52c55d0ee8 test: convert to using TestBed 2015-04-06 10:30:16 +02:00
438c2b31e4 test(TestBed): initial implementation 2015-04-06 10:30:16 +02:00
57e308dd46 test(MockTemplateResolver): allow directive overriding 2015-04-06 10:07:50 +02:00
c922b5a112 docs(annotations): fix some typos, align docs with code
Closes #1227
2015-04-04 12:23:01 +02:00
d552303cd5 docs(02_directives.md): foreach -> for
Closes #1235
2015-04-04 10:32:53 +02:00
1d4d18d9db refactor(render): user render compiler 2015-04-03 23:41:00 -07:00
069bbf3ed0 docs(02_directives.md): Fixes variable name for visibility in Components example 2015-04-03 14:18:15 -07:00
a4a2d4e56d chore: allow latest stack_track package 2015-04-03 14:18:14 -07:00
d77f409093 chore: analyzer fixes for Dart transformer 2015-04-03 14:18:14 -07:00
25c709c58e fix(angular2): export PrivateComponent{Loader,Location} in angular2/core 2015-04-03 14:18:14 -07:00
bc909d1d0f refactor(dart/transform): Minor renames
Rename `setupReflection` => `initReflector`
Rename `TemplateComplier` => `TemplateCompiler`

Closes #1180
2015-04-03 13:16:24 -07:00
a6736ff9f2 perf(change detection): Assign this.locals in change detector ctor
Set `this.locals = null;` in the ctor of generated change detector
classes to prevent the class "shape" from changing on `hydrate`.
2015-04-03 12:23:47 -07:00
894a0f0ee5 chore(ts): duplicate the .es6 files in the facade directory to TypeScript.
Adds a gulp task which builds the .ts files (in the cjs build only).
The new files have extension .ts since they are now valid typescript.
Unfortunately until Typescript can emit System.require, we have to keep the old .es6 version
so traceur works inside the Karma preprocessor. This should be fixed soon.
2015-04-03 09:35:06 -07:00
abea92af59 refactor(change_detection): call onChange from the change detector 2015-04-02 21:22:42 -07:00
bcbed2812d feat(bundle): work-around rx.all.js bundle issue.
Adds long-stack-trace-zone into the dev build. Turn off source maps
until proper concatination of them is added.
2015-04-02 19:54:07 -07:00
c0b04ca0bc feat(gulp): adds System.register bundle task. 2015-04-02 19:54:06 -07:00
86dc3e5b07 docs: create public API surface
Closes #1181
2015-04-02 23:23:39 +00:00
c1aa65239e refactor(render): move services to render folder
property_setter_factory
selector
style_inliner
style_url_resolver
shadow_css
2015-04-02 14:40:49 -07:00
be5ccf6957 refactor(render): delete copies files so we add them via moves 2015-04-02 14:24:55 -07:00
09067ebdc5 fix(build): Require gulp-ts2dart at least at 1.0.6.
This fixes the build by pulling in a later version that correctly ignores the .es6 files.
2015-04-02 13:13:47 -07:00
08697e71fa chore(package.json): update madge to v0.5.0
Closes #1211
2015-04-02 22:08:04 +02:00
90d9a1df3f fix(IE11): first fixes
Closes #1179
2015-04-02 22:06:21 +02:00
a96c149793 chore(gulp): Stop copying .cjs files to the dist folder
They're already transpiled by the build/transpile.js.cjs task
2015-04-02 20:51:16 +02:00
1037cef22e refactor(render): misc minor fixes 2015-04-02 20:50:05 +02:00
09948f4403 feat(dart/transform): Add a di transformer
Add a transformer for `di` which generates `.ng_deps.dart` files for all
`.dart` files it is run on. These `.ng_deps.dart` files register
metadata for any `@Injectable` classes.

Fix unit tests for changes introduced by the di transformer.

When using `pub (build|serve) --mode=ngstatic`, we will also generate
getters and setters, parse templates, and remove import of `dart:mirrors`
in the Angular transform. Because this is still relatively immature, we
use the mode to keep it opt-in for now.

Closes #700
2015-04-02 11:06:33 -07:00
788461b7e2 feat(di): Mark objects @Injectable
Allow `PrivateComponentLoader`, `Testability`, and `TestabilityRegistry` to be injected.
2015-04-02 11:02:26 -07:00
4f56628566 refactor(render): move services to right location
core/compiler/events -> render/dom/events
core/compiler/url_resolver -> services/url_resolver
core/compiler/xhr/* -> services/*
2015-04-02 10:35:27 -07:00
bcbf1ccc68 refactor(render): remove duplicate files to prepare for move
Remove first so Github shows the files as being moved instead of copied and deleted.
2015-04-02 10:35:27 -07:00
ae30d7ba40 fix(di): allow injecting event emitter fns without specifying type annotation
Fixes #965

Closes #1155
2015-04-02 19:07:49 +02:00
9adf41ca2d fix(build) Add a .tsdrc file for github rate limiting.
See https://github.com/DefinitelyTyped/tsd#tsdrc
2015-04-02 10:05:37 -07:00
1d79d534d9 test(selector): add tests with multiple attributes
Fixes #1025
Closes #1117
2015-04-02 18:06:44 +02:00
60e4197026 feat(tooling): Add a .clang-format for automated JavaScript formatting. 2015-04-02 08:44:34 -07:00
2fabca77b9 test(Travis): use test.dart for Dart tests 2015-04-02 13:12:59 +02:00
47542b0cb0 fix(build): don’t read out chrome perflogs during e2e tests
We do this as we are seeing flakes in Chrome with ECONNREFUSED.

Also reuses the same browser window.

Also reenables the infinite scroll benchmark

Closes #1137
2015-04-01 17:09:26 -07:00
6c60c3e547 feat(render): add initial implementation of render layer 2015-04-01 16:50:22 -07:00
814d389b6e chore(gulp): add typescript transpilation tasks 2015-04-01 15:01:27 -07:00
e81e5fb2b9 feat(testability): add an initial scaffold for the testability api
Make each application component register itself onto the testability
API and exports the API onto the window object.
2015-04-01 13:54:06 -07:00
f68cdf3878 chore(ts): introduce some TypeScript type declarations.
This uses tsd to fetch the typings from another git repo. I've forked the DefinitelyTyped repo because some typings we use are not available upstream.
We should probably fork it in the Angular org, so everyone on the team has commit access to our DefinitelyTyped fork.
2015-04-01 12:01:45 -07:00
91e0e9e1dd chore(ts): Patch traceur's type module only when targetting es6 output. 2015-04-01 10:39:06 -07:00
59c1299168 fix(tests): add missing ;s 2015-04-01 15:30:46 +02:00
27c6afbeb4 chore(doc-gen): add temporary dump of all API docs
Remove unwanted < character
2015-04-01 10:24:33 +01:00
514ba54282 feat(change_detection): added changeDetection to Component 2015-03-31 20:54:44 -07:00
a11f683e7b chore(ts): Don't mask the Regexp builtin.
Doing so makes it impossible to compile with TypeScript, since it conflicts with the shape of the Regexp global var defined in the standard lib.
2015-03-31 19:20:21 -07:00
b65b145122 refactor(view): refactored DirectiveMemento to expose properties in a consistent way 2015-03-31 18:26:58 -07:00
982bb8b01d fix(forms): fixed a directive selector 2015-03-31 17:45:38 -07:00
eb7b7581ca fix(build): Actually code in the subset of JS that Traceur-Dart supports. 2015-03-31 16:08:49 -07:00
adab6c0728 chore(doc-gen): add temporary dump of all API docs
Accessible at `angular/dist/public_docs/overview-dump.html`
2015-03-31 22:12:41 +01:00
609201e109 chore(doc-gen): add method signatures to members and functions
Closes https://github.com/angular/dgeni/issues/124
2015-03-31 22:12:41 +01:00
54a4e4a67c fix(dart): The Traceur dart transpiler doesn't support shorthand syntax. 2015-03-31 13:17:56 -07:00
aca4604879 feat(CSSClass): support binding to classList
Closes #876
2015-03-31 21:53:24 +02:00
48811cd805 doc(lifecycle): minor fixes 2015-03-31 21:12:37 +02:00
136f64f4ac fix(dart): don't instantiate abstract directive.
Directive is an abstract class, so it should not
be instantiated directly in tests.
2015-03-31 11:38:59 -07:00
123ee8e06f feat(dom): add replaceChild to DOM adapter 2015-03-31 09:54:41 -07:00
a55efbd8b8 feat(perf): add Angular2 implementation of largetable benchmark from AngularJS 1.x 2015-03-31 09:54:41 -07:00
7bf9525353 fix(benchmark_util): remove strict equality check from getStringParameter
Transpiled dart code was using identical() method to compare, which checks reference
equality, even for strings.
2015-03-31 09:54:41 -07:00
3915e1b242 docs(annotations): Added new text 2015-03-30 17:19:58 -07:00
ed5975d3e5 test(dart/transform): Add unit tests for url-linked templates
Test expression and method generation from url-linked templates.
2015-03-30 14:49:31 -07:00
1a788e6b0d feat(dart/transform): Parse url values in Templates
When a `Template` annotation declares a `url` value, parse it to
generate `getter`s, `setter`s, and `method`s which will it needs to
access reflectively.
2015-03-30 14:49:31 -07:00
d822793229 fix(test): add a test for @PropertySetter on a class with a dash
Closes #1113
Fixes #1099
2015-03-28 16:17:43 +01:00
b46d0bc48c docs(annotations): fix typo, align docs with code
Closes #1045
2015-03-28 15:39:50 +01:00
65320126c2 docs(directives): fix HTML in an example
Closes #1115
2015-03-28 15:37:11 +01:00
c63b3164bd fix(build): add package.json again to the copy files for js 2015-03-27 17:34:26 -07:00
dbffa88dc2 chore(release): bump version to 2.0.0-alpha.18
For docs
2015-03-27 17:16:22 -07:00
8c5d9d372f fix(build): publish docs as well and correct bench press docs 2015-03-27 16:47:52 -07:00
50f8892c6b chore(release): bump version
Somehow the version bump from alpha.16 was not submitted to master…
2015-03-27 16:21:41 -07:00
3bfbfa8ae0 chore(release): bump version 2015-03-27 16:18:36 -07:00
8598c87ef4 docs(bench press): add initial docs 2015-03-27 16:16:35 -07:00
33bfc4c24a feat(bench press): replace microIterations with microMetrics 2015-03-27 16:16:35 -07:00
3afb744e77 chore(ci): reorganize e2e/perf test running
Now, running protractor configs by default only runs e2e tests. If
the --benchmark flag is added, it runs only the perf tests, and always
restarts the browser in between tests. If the --dryrun test is added,
the perf tests are run only once.

This should make it easier to run perf tests versus example e2e tests,
and help stabilize the travis build because perf tests always
run with a clean browser.
2015-03-27 13:29:21 -07:00
e92918bbfe feat(change_detector): split light dom and shadow dom children 2015-03-27 13:26:37 -07:00
723e8fde93 feat(change_detection): added a directive lifecycle hook that is called after children are checked 2015-03-27 13:26:36 -07:00
507f7ea70a chore(package.json): upgrade zone.js to v0.4.2
Closes #1142
2015-03-27 16:24:07 -04:00
6b985d56a5 cleanup(forms): added missing type annotations
Closes #1054
2015-03-27 11:30:39 -07:00
c8385ad998 refactor(cd): remove dead code 2015-03-27 16:59:23 +01:00
9d21a6f40d chore(package.json): upgrade traceur to v0.0.87
Fix in source-map test to follow through the sourcemap chain.
2015-03-26 18:37:03 -07:00
d304f41197 docs(core): improved docs on directive lifecycle 2015-03-26 18:18:25 -07:00
8d85b839b6 feat(change_detection): pass binding propagation config to pipe registry 2015-03-26 16:57:04 -07:00
dd235f38a3 fix(build): try to eliminate build flakes by running dartstyle:format sequentially 2015-03-26 16:23:09 -07:00
5306b6dd0c fix(change_detection): expose values when detecting changes in key-value pairs
Fixes #1118

Closes #1123
2015-03-26 21:18:14 +01:00
b09624024b example(forms): added a example of using forms 2015-03-26 11:36:14 -07:00
edc3709451 fix(ElementBinderBuilder): properly bind CSS classes with "-" in their names
Fixes #1057

Closes #1059
2015-03-26 19:25:31 +01:00
e706f3477b Remove invalid super() call
Unless I'm missing something?
2015-03-26 11:10:39 -07:00
6298cb3999 chore(ci): upgrade to new version of protractor and selenium-webdriver
Protractor 2.0.0
selenium-webdriver 2.45.1
2015-03-26 10:00:46 -07:00
878fce6482 fix(ts): ts doesn't like ";;" 2015-03-26 17:32:48 +01:00
b02bd65871 feat(forms): made forms works with single controls 2015-03-26 07:48:17 -07:00
ee36aaf163 fix(tests): fixed a broken test 2015-03-26 07:46:26 -07:00
ff84506bd5 feat(forms): added support for arrays of controls 2015-03-26 07:43:25 -07:00
0ae33b7e3c refactor(compiler): factorize common util code dash <-> camel
Closes #1114
Fixes #1097
2015-03-26 15:22:35 +01:00
b1dc6239ef feat(core): @Attribute annotation
Closes #1091
Fixes #622
2015-03-26 10:51:44 +01:00
3ce0f1146f chore(dgeni): set log level to 'warning' 2015-03-26 09:31:36 +01:00
3ec837bfdb test(di): Add a test for sync binding + resolved async dependency 2015-03-26 08:38:29 +01:00
18ff2be9bb feat(ts2dart): include srcFolderInsertion in ts2dart step. 2015-03-25 21:31:40 -07:00
c0d296334c feature(ts2dart): ts2dart runs on all .js files.
Update the experimental ts2dart task to also read the .es6 files, which are the next step.
2015-03-25 17:14:06 -07:00
9a0a2e319c chore(ts2dart) remove extra semi
This breaks our ts2dart transpilation.
2015-03-25 17:06:47 -07:00
a0d86ac2bb chore(ts2dart): ts2dart doesn't support mixed typed/untyped var decl lists. 2015-03-25 16:41:33 -07:00
99045b2f6a refactor: update Dart package dependencies 2015-03-25 15:54:12 -07:00
c34ca36778 chore: build the stable branch of Dart
Now that Dart 1.9 is stable
2015-03-25 21:17:07 +01:00
58dd75a1c8 feat(compiler): Add support for setting attributes to Component host element
Fixes #1008
Fixes #1009
Closes #1052
2015-03-25 17:32:07 +01:00
f995b07876 docs: annotations edits 2015-03-24 23:28:24 +00:00
101a4aa3cf feat(PrivateComponentLoader): Explicit error message when loading a non-component
fixes #1062
2015-03-24 22:11:41 +01:00
65d759316b fix(PrivateComponentLoader): add the loader to the app injector
fixes #1063
2015-03-24 22:10:26 +01:00
19c1773133 feat(forms): added an observable of value changes to Control 2015-03-24 13:45:47 -07:00
9b3b3d325f feat(facade): added support for observables 2015-03-24 13:45:39 -07:00
43f4374944 feature(build): Include ts2dart transpile step in the Angular build.
This only transpiles one package to start with: di/
It ensures that package transpiles without errors, so no one can
introduce non-TypeScript syntax.
Next step is to widen the task inputs to cover additional packages.

See design doc for the migration:
https://docs.google.com/document/d/14RJLhu6uuv7NchFkAb6PKzOOO0L7l3Z507eKWzkEUhQ/edit

A convenience task 'ts2dart' is added for developing ts2dart, and
it runs all of the angular code through the transpiler to collect errors.
2015-03-24 10:34:46 -07:00
81e6d13241 chore: bump up the version to 2.0.0-alpha.15 2015-03-24 07:50:39 -07:00
f8e7a37c0d fix(view): fixed view instantiation to use the component template's change detector when creating BindingPropagationConfig 2015-03-24 07:49:28 -07:00
c686e7ea30 chore(doc-gen): ignore non-jsdoc style comments
Now the visitor will find the last jsdoc style comment (e.g. `/** jsdoc comment */`)
before the current code item, ignoring any inline style comments (e.g. `// inline comment`)
in between.

Closes #1072
2015-03-24 11:25:58 +00:00
7e89af8190 chore(doc-gen): move @publicModule tag-def to base package
This prevents unwanted "unknown tag" warnings when generating the non-public docs.
2015-03-24 10:57:42 +00:00
539e8e2cce chore(doc-gen): add specific template for displaying variable exports
Closes #1071
2015-03-24 10:57:42 +00:00
aab084866c doc(test): add a comment on why tests are disabled 2015-03-24 09:52:41 +01:00
0e61a86763 docs: annotations 2015-03-24 00:42:58 +00:00
1c9938ed98 chore(packaging): bump version to alpha.14 2015-03-23 17:14:55 -07:00
47c1a0f381 feat(forms): added value accessor for input=text 2015-03-23 08:53:27 -07:00
514529b5d9 refactor(formed): changed forms to use event and property setters instead of NgElement 2015-03-23 08:52:54 -07:00
a12dc7d75a refactor(forms): wrapped all validators into the Validator class 2015-03-23 08:50:56 -07:00
41b53e71e1 feat(selector): support , for multiple targets
Fixes #867
Closes #1019
2015-03-23 10:06:33 +01:00
0fb9f3bd6c fix(ElementBinderBuilder): properly bind to web component properties
Fixes #776

Closes #1024
2015-03-22 14:14:36 +01:00
81f3f32217 refactor(DirectiveParser): remove checks for missing directives
Based on the discussion in #776 we can't reliably check if a given
element has a particular property at the compilation time. As such
the existing algorithm detecting "missing" directives can't be used.

We need to see if there is a different / better algorithm or maybe
those checks need to be moved later in the process (runtime). Leaving
integration tests in place (disabled) so we can come back to the
topic after unblocking the situation.

This commit effectivelly reverts 94e203b9df
2015-03-22 14:14:36 +01:00
b35f288794 refactor(dart/transform): Use package:guinness in tests
`guinness` is a Dart port of Jasmine. Since the rest of Angular 2 uses
Jasmine, use it for the transformer too.

Closes #8

Closes #1037

Closes #1000
2015-03-21 15:18:15 -07:00
4e82cc0861 refactor(dart/transform): Test directive_linker as a unit
Formerly, it was tested only as a piece of the transformer pipeline. Add
its own directory and test the linker on its own.
2015-03-21 15:18:15 -07:00
c735644c57 refactor(dart/transform): Minor logging changes
Enable easier testing by providing a null log implementation and a way
to use it.
2015-03-21 15:18:15 -07:00
5d479fa0ae refactor(dart/transform): Remove ngData
Now that we have `Parser`, `ngData` is redundant & unnecessary.
2015-03-21 15:18:15 -07:00
8baedca972 style(dart/transform): Remove src from library directives
Conform to Angular 2 style by removing `src` from library directives.
Completed with:
```
find -name "*.dart" | xargs sed -i -e 's!library\(.*\)src\.\(.*\)!library \1\2!'
```

Closes #1005

Closes #1038
2015-03-21 14:55:11 -07:00
02aa8e7945 feat(compiler): support bindings for any attribute
Closes #1029
2015-03-21 14:55:11 -07:00
ee523efcb4 feat(ShadowCss): Support the new deep combinator syntax >>>
fixes #990

ref http://dev.w3.org/csswg/css-scoping-1/#deep-combinator

Closes #1028
2015-03-21 14:55:11 -07:00
eef5f7e06d README - don't forget to build app before start
Don't forget to build app before start HTTP server

Closes #1014
2015-03-21 14:55:11 -07:00
83402930f2 chore(install+test): single cmd to full install/test & test JS w/o Dart
* `npm install` now does a full install; auxiliary installation steps
have been integrated into the `postinstall` script.
* Updated developer docs `DEVELOPER.md` accordingly; also added
instructions to dev docs for performing full tests (via `npm test`) --
same as those run on Travis.
* Reorg in tests so that JS tests can run without a Dart env.

Partly fixes #945 **under the assumption that when running JS tests
locally, `ChromeCanary` is the desired browser to use**. Note that CI
tests (Travis) still uses `DartiumWithWebPlatform` across the board
(Maybe because ChromeCanary isn't being installed?)

Fixes #1012.

Closes #1010
2015-03-21 14:55:11 -07:00
bd48c927d0 fix(ViewContainer) removeChild called with null parent
In view_container.js, templateElement.parentNode can be null
when two template tags are nested in one another.
Accessing the parent node through view.nodes[0].parentNode fixes
the problem.

closes #997

Closes #999
2015-03-21 14:55:10 -07:00
b61b8d60b7 refactor(forEach): change to for-of with iterable
rename: foreach -> for
rename: array -> iterable
update: DartParseTreeWriter
update: naive_infinite_scroll
update: todo
fix: tests in foreach_spec

Closes #919
2015-03-21 14:19:21 -07:00
f1fca5abb6 (docs) decorator events property
As from what i understand shouldn't the event property rather be events: https://github.com/angular/angular/blob/master/modules/angular2/src/core/annotations/annotations.js#L161

Closes #1018
2015-03-21 18:26:13 +00:00
045ce3c77a Fix which dependency is injected w/ current elem.
Docs for the "Injecting a directive from the current element" indicate that having a dependency of `dependency: Dependency` should cause the current element's dependency to be injected, but then uses the ID value from the parent element in the example.

Closes #1032
2015-03-21 18:14:43 +00:00
f822066e2a docs: annotations 2015-03-21 18:05:12 +00:00
770 changed files with 61197 additions and 18513 deletions

3
.bowerrc Normal file
View File

@ -0,0 +1,3 @@
{
"directory": "bower_components"
}

3
.clang-format Normal file
View File

@ -0,0 +1,3 @@
Language: JavaScript
BasedOnStyle: Google
ColumnLimit: 100

19
.gitignore vendored
View File

@ -1,11 +1,17 @@
.DS_STORE
# Dont commit the following directories created by pub.
packages
pubspec.lock
.pub
/dist/
packages/
.buildlog
node_modules
bower_components
.pub
.DS_STORE
# Or broccoli working directory
tmp
# Or the files created by dart2js.
*.dart.js
@ -14,6 +20,10 @@ bower_components
*.js.deps
*.js.map
# Or type definitions we mirror from github
**/typings/**/*.d.ts
**/typings/tsd.cached.json
# Include when developing application packages.
pubspec.lock
.c9
@ -23,4 +33,7 @@ pubspec.lock
# Don't check in secret files
*secret.js
# Ignore npm debug log
npm-debug.log
/docs/bower_components/

View File

@ -2,31 +2,56 @@ language: node_js
sudo: false
node_js:
- '0.10'
cache:
directories:
- node_modules
env:
global:
- KARMA_BROWSERS=DartiumWithWebPlatform
- E2E_BROWSERS=Dartium
- LOGS_DIR=/tmp/angular-build/logs
- ARCH=linux-x64
# 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"}'
matrix:
- MODE=js DART_CHANNEL=dev
# Dissabled until Dart v1.9 hits stable
# - MODE=dart DART_CHANNEL=stable
- MODE=dart DART_CHANNEL=stable
- MODE=dart DART_CHANNEL=dev
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} ${ARCH}
- sh -e /etc/init.d/xvfb start
- if [[ -e SKIP_TRAVIS_TESTS ]]; then { cat SKIP_TRAVIS_TESTS ; exit 0; } fi
install:
# Update npm
- npm install -g npm@2.7.4
- npm --version
# Check the size of caches
- du -sh ./node_modules || true
# Install npm dependecies and ensure that npm cache is not stale
- tools/npm/install-dependencies.sh
before_script:
- mkdir -p $LOGS_DIR
script:
- ./scripts/ci/build_and_test.sh ${MODE}
after_script:
- ./scripts/ci/print-logs.sh
notifications:
webhooks:
urls:

104
CHANGELOG.md Normal file
View File

@ -0,0 +1,104 @@
<a name"2.0.0-alpha.22"></a>
### 2.0.0-alpha.22 (2015-05-07)
#### Bug Fixes
* **brocolli:** escape special regexp characters when building regexps ([a58c9f83](https://github.com/angular/angular/commit/a58c9f83), closes [#1721](https://github.com/angular/angular/issues/1721), [#1752](https://github.com/angular/angular/issues/1752))
* **build:**
* build the broccoli tools with correct typescript version. ([6bba289a](https://github.com/angular/angular/commit/6bba289a))
* use correct tsd command to get typings at requested versions ([1205f54d](https://github.com/angular/angular/commit/1205f54d))
* revert typescript upgrade which broke the build. ([b5032fd3](https://github.com/angular/angular/commit/b5032fd3))
* refer to newest version of hammerjs typings ([a7a94636](https://github.com/angular/angular/commit/a7a94636))
* **bundle:** update the bundle config to point to rx.js ([cf322130](https://github.com/angular/angular/commit/cf322130))
* **change_detector:** ensure that locals are only used when implicit receiver ([d4925b61](https://github.com/angular/angular/commit/d4925b61), closes [#1542](https://github.com/angular/angular/issues/1542))
* **compiler:**
* clone templates before compiling them ([9e8d31d5](https://github.com/angular/angular/commit/9e8d31d5), closes [#1058](https://github.com/angular/angular/issues/1058))
* changed the compiler to set up event listeners and host properties on host view ([e3c11045](https://github.com/angular/angular/commit/e3c11045), closes [#1584](https://github.com/angular/angular/issues/1584))
* only sets viewDefinition absUrl if the view has either a template or templateUrl ([3d625463](https://github.com/angular/angular/commit/3d625463), closes [#1326](https://github.com/angular/angular/issues/1326), [#1327](https://github.com/angular/angular/issues/1327))
* **decorators:**
* incorrect annotation to decorator adapter ([b0c735f7](https://github.com/angular/angular/commit/b0c735f7))
* fixed decorators ([49777648](https://github.com/angular/angular/commit/49777648))
* fixes decorator reflection. ([be7504d4](https://github.com/angular/angular/commit/be7504d4))
* updates missing benchmark and fixes typo. ([87dcd5eb](https://github.com/angular/angular/commit/87dcd5eb))
* **decorators.es6:** export Directive decorator ([93c331d1](https://github.com/angular/angular/commit/93c331d1), closes [#1688](https://github.com/angular/angular/issues/1688))
* **di:** improve error messages for invalid bindings ([ee1b574b](https://github.com/angular/angular/commit/ee1b574b), closes [#1515](https://github.com/angular/angular/issues/1515), [#1573](https://github.com/angular/angular/issues/1573))
* **docs:** fix broken docs test after addition of .ts extension to dgeni regex. ([62bf777e](https://github.com/angular/angular/commit/62bf777e))
* **exception_handler:** log errors via `console.error` ([ead21c91](https://github.com/angular/angular/commit/ead21c91))
* **formatter:** point to the newest clang-format ([51c47792](https://github.com/angular/angular/commit/51c47792))
* **router:**
* fix for leading slash in dart ([c9cec600](https://github.com/angular/angular/commit/c9cec600))
* navigate on popstate event ([2713b787](https://github.com/angular/angular/commit/2713b787))
* throw if config does not contain required fields ([259f872c](https://github.com/angular/angular/commit/259f872c))
* infer top-level routing from app component ([46ad3552](https://github.com/angular/angular/commit/46ad3552), closes [#1600](https://github.com/angular/angular/issues/1600))
* use lists for RouteConfig annotations ([4965226f](https://github.com/angular/angular/commit/4965226f))
* **view:** changed view manager to hydrate change detector after creating directives ([c1579222](https://github.com/angular/angular/commit/c1579222))
#### Features
* **benchmark:** added an implementation of the tree benchmark in React ([e4342743](https://github.com/angular/angular/commit/e4342743))
* **benchmarks:** Add basic dart transformer benchmarks. ([1864f60a](https://github.com/angular/angular/commit/1864f60a))
* **decorators:**
* adds decorator versions of DI annotations. ([457c15cd](https://github.com/angular/angular/commit/457c15cd))
* adds support for parameter decorators. ([f863ea0d](https://github.com/angular/angular/commit/f863ea0d))
* adds decorators to be used by TS and Babel transpiled apps. ([fb67e373](https://github.com/angular/angular/commit/fb67e373))
* **dom:** add location and history as DOM-like APIs. ([f356d033](https://github.com/angular/angular/commit/f356d033))
* **material:** add prototype dialog component w/ demo. ([f88c4b77](https://github.com/angular/angular/commit/f88c4b77))
* **router:**
* adds the router to the self-executing bundle. ([8e1d53b5](https://github.com/angular/angular/commit/8e1d53b5))
* export decorator version of RouteConfig ([75da6e4c](https://github.com/angular/angular/commit/75da6e4c))
* route redirects ([91533313](https://github.com/angular/angular/commit/91533313))
* sibling outlets ([9d5c33f9](https://github.com/angular/angular/commit/9d5c33f9))
* export routerInjectables ([ef7014fe](https://github.com/angular/angular/commit/ef7014fe))
* add location service ([ea546f50](https://github.com/angular/angular/commit/ea546f50))
#### Breaking Changes
* Previously, `Directive` was the abstract base class of several directives.
Now, `Directive` is the former `Decorator`, and `Component` inherits from it.
([f75a50c1](https://github.com/angular/angular/commit/f75a50c1))
* A dynamic component is just a component that has no @View annotation…
([8faf6364](https://github.com/angular/angular/commit/8faf6364))
<a name="2.0.0-alpha.21"></a>
# 2.0.0-alpha.21 (2015-04-27)
## Features
- **dart/transform:** Dedup getters, setters, & methods
([15376a6d](https://github.com/angular/angular/commit/15376a6d243740c73cf90f55525d1710cdd156f5))
- **facade:** add isType method
([e617ca63](https://github.com/angular/angular/commit/e617ca6323902bd98c0f1eb990b82f6b8d3c98e3))
- **parser:** support === and !== operators
([afe0e454](https://github.com/angular/angular/commit/afe0e454537f9252f9cf313647e649cfa464f96f),
[#1496](https://github.com/angular/angular/issues/1496), [#1500](https://github.com/angular/angular/issues/1500))
- **router:** add initial implementation
([1b2754da](https://github.com/angular/angular/commit/1b2754dacdd15e8fea429d56cdacb28eae76d2b1))
- **view:** reimplemented property setters using change detection
([8ccafb05](https://github.com/angular/angular/commit/8ccafb0524e3ac4c51af34ef88e0fe27482336a6))
## Performance Improvements
- **benchmarks:**
- benchmark that measure cost of dynamic components
([427f0d02](https://github.com/angular/angular/commit/427f0d021c51ea6923edd07574a4cc74a1ef84e6))
- benchmark measuring cost of decorators (fixes #1479)
([9fc9d535](https://github.com/angular/angular/commit/9fc9d535667c620017367877dbc2a3bc56d358b7))
## Other (malformed commit messages)
- **other:**
- feat: alllow specifying directives as bindings
([4bab25b3](https://github.com/angular/angular/commit/4bab25b3666f4247434ad5cb871906fb063fef51),
[#1498](https://github.com/angular/angular/issues/1498))
- fix: export ShadowDom strategies
([6896305e](https://github.com/angular/angular/commit/6896305e34082c246769829e4258631c1d2363d1),
[#1510](https://github.com/angular/angular/issues/1510), [#1511](https://github.com/angular/angular/issues/1511))

View File

@ -3,56 +3,59 @@
This document describes how to set up your development environment to build and test Angular, both
JS and Dart versions. It also explains the basic mechanics of using `git`, `node`, and `npm`.
See the [contributing guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md)
for how to contribute your own code to
* [Prerequisite Software](#prerequisite-software)
* [Getting the Sources](#getting-the-sources)
* [Environment Variable Setup](#environment-variable-setup)
* [Installing NPM Modules and Dart Packages](#installing-npm-modules-and-dart-packages)
* [Running Tests Locally](#running-tests-locally)
* [Project Information](#project-information)
* [CI using Travis](#ci-using-travis)
* [Transforming Dart code](#transforming-dart-code)
* [Debugging](#debugging)
1. [Prerequisite Software](#prerequisite-software)
2. [Getting the Sources](#getting-the-sources)
3. [Environment Variable Setup](#environment-variable-setup)
4. [Installing NPM Modules and Dart Packages](#installing-npm-modules-and-dart-packages)
5. [Running Tests Locally](#running-tests-locally)
6. [Project Information](#project-information)
7. [CI using Travis](#ci-using-travis)
8. [Debugging](#debugging)
See the [contribution guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md)
if you'd like to contribute to Angular.
## Prerequisite Software
Before you can build and test Angular, you must install and configure the
following products on your development machine:
* [Dart](https://www.dartlang.org) (version `>=1.9.0-dev.8.0`), specifically the Dart-SDK and
* [Dart](https://www.dartlang.org) (version ` >=1.9.0 <2.0.0`), specifically the Dart-SDK and
Dartium (a version of [Chromium](http://www.chromium.org) with native support for Dart through
the Dart VM). One of the **simplest** ways to get both is to install the **Dart Editor bundle**,
which includes the editor, SDK and Dartium. See the [Dart tools](https://www.dartlang.org/tools)
download [page for instructions](https://www.dartlang.org/tools/download.html); note that you can
download [page for instructions](https://www.dartlang.org/tools/download.html). You can also
download both **stable** and **dev** channel versions from the [download
archive](https://www.dartlang.org/tools/download-archive).
* [Git](http://git-scm.com) and/or the **Github app** (for [Mac](http://mac.github.com) or
[Windows](http://windows.github.com)): the [Github Guide to Installing
* [Git](http://git-scm.com) and/or the **GitHub app** (for [Mac](http://mac.github.com) or
[Windows](http://windows.github.com)); [GitHub's Guide to Installing
Git](https://help.github.com/articles/set-up-git) is a good source of information.
* [Node.js](http://nodejs.org) which is used to run a development web server, run tests, and
generate distributable files. We also use Node's Package Manager (`npm`). Depending on your
system, you can install Node either from source or as a pre-packaged bundle.
* [Node.js](http://nodejs.org), which is used to run a development web server, run tests, and
generate distributable files. We also use Node's Package Manager, `npm`, which comes with Node.
Depending on your system, you can install Node either from source or as a pre-packaged bundle.
* [Chrome Canary](https://www.google.com/chrome/browser/canary.html), a version of Chrome with
bleeding edge functionality, built especially for developers (and early adopters).
* [Bower](http://bower.io/).
## Getting the Sources
Forking and cloning the Angular repository:
Fork and clone the Angular repository:
1. Login to your Github account or create one by following the instructions given
1. Login to your GitHub account or create one by following the instructions given
[here](https://github.com/signup/free).
2. [Fork](http://help.github.com/forking) the [main Angular
repository](https://github.com/angular/angular).
3. Clone your fork of the Angular repository and define an `upstream` remote pointing back to
the Angular repository that you forked in the first place:
the Angular repository that you forked in the first place.
```shell
# Clone your Github repository:
# Clone your GitHub repository:
git clone git@github.com:<github username>/angular.git
# Go to the Angular directory:
@ -90,32 +93,31 @@ PATH+=":$DART_SDK/bin"
## Installing NPM Modules and Dart Packages
Next, install the modules and packages needed to build Angular and run tests:
Next, install the JavaScript modules and Dart packages needed to build and test Angular:
```shell
# Install Angular project dependencies (package.json)
npm install
# Ensure protractor has the latest webdriver
$(npm bin)/webdriver-manager update
# Install Dart packages
pub get
```
**Optional**: In this document, we make use of project local `npm` package scripts and binaries
(stored under `./node_modules/.bin`) by prefixing these command invocations with `$(npm bin)`; in
particular `gulp` and `protractor` commands. If you prefer, you can drop this path prefix by
globally installing these two packages as follows:
particular `gulp` and `protractor` commands. If you prefer, you can drop this path prefix by either:
*Option 1*: globally installing these two packages as follows:
* `npm install -g gulp` (you might need to prefix this command with `sudo`)
* `npm install -g protractor` (you might need to prefix this command with `sudo`)
Since global installs can become stale, we avoid their use in these instructions.
Since global installs can become stale, and required versions can vary by project, we avoid their
use in these instructions.
*Option 2*: defining a bash alias like `alias nbin='PATH=$(npm bin):$PATH'` as detailed in this
[Stackoverflow answer](http://stackoverflow.com/questions/9679932/how-to-use-package-installed-locally-in-node-modules/15157360#15157360) and used like this: e.g., `nbin gulp build`.
## Build commands
To build Angular and prepare tests run
To build Angular and prepare tests, run:
```shell
$(npm bin)/gulp build
@ -124,42 +126,60 @@ $(npm bin)/gulp build
Notes:
* Results are put in the `dist` folder.
* This will also run `pub get` for the subfolders in `modules` and run `dartanalyzer` for
every file that matches `<module>/src/<module>.dart`, e.g. `di/src/di.dart`
every file that matches `<module>/src/<module>.dart`, e.g. `di/src/di.dart`.
You can selectively build either the JS or Dart versions as follows:
* `$(npm bin)/gulp build.js`
* `$(npm bin)/gulp build.dart`
To clean out the `dist` folder, run:
To clean out the `dist` folder use:
```shell
$(npm bin)/gulp clean
```
## Running Tests Locally
### Basic tests
### Full test suite
1. `$(npm bin)/gulp test.unit.js`: JS tests in a browser; runs in **watch mode** (i.e. karma
watches the test files for changes and re-runs tests when files are updated).
2. `$(npm bin)/gulp test.unit.cjs`: JS tests in NodeJS; runs in **watch mode**
3. `$(npm bin)/gulp test.unit.dart`: Dart tests in Dartium; runs in **watch mode**.
* `npm test`: full test suite for both JS and Dart versions of Angular. These are the same tests
that run on Travis.
If you prefer running tests in "single-run" mode rather than watch mode use
You can selectively run either the JS or Dart versions as follows:
* `$(npm bin)/gulp test.all.js`
* `$(npm bin)/gulp test.all.dart`
### Unit tests
You can run just the unit tests as follows:
* `$(npm bin)/gulp test.unit.js`: JS tests in a browser; runs in **watch mode** (i.e.
watches the test files for changes and re-runs tests when files are updated).
* `$(npm bin)/gulp test.unit.cjs`: JS tests in NodeJS; runs in **watch mode**.
* `$(npm bin)/gulp test.unit.dart`: Dart tests in Dartium; runs in **watch mode**.
If you prefer running tests in "single-run" mode rather than watch mode use:
* `$(npm bin)/gulp test.unit.js/ci`
* `$(npm bin)/gulp test.unit.cjs/ci`
* `$(npm bin)/gulp test.unit.dart/ci`
**Note**: If you want to only run a single test you can alter the test you wish
to run by changing `it` to `iit` or `describe` to `ddescribe`. This will only
run that individual test and make it much easier to debug. `xit` and `xdescribe`
can also be useful to exclude a test and a group of tests respectively.
The task updates the dist folder with transpiled code whenever a source or test file changes, and
Karma is run against the new output.
**Note** for transpiler tests: The karma preprocessor is setup in a way so that after every test
run the transpiler is reloaded. With that it is possible to make changes to the preprocessor and
run the tests without exiting karma (just touch a test file that you would like to run).
**Note**: If you want to only run a single test you can alter the test you wish to run by changing
`it` to `iit` or `describe` to `ddescribe`. This will only run that individual test and make it
much easier to debug. `xit` and `xdescribe` can also be useful to exclude a test and a group of
tests respectively.
### E2e tests
1. `$(npm bin)/gulp build.js.cjs` (builds benchpress and tests into `dist/js/cjs` folder).
2. `$(npm bin)/gulp serve.js.prod serve.js.dart2js` (runs local webserver).
2. `$(npm bin)/gulp serve.js.prod serve.js.dart2js` (runs a local webserver).
3. `$(npm bin)/protractor protractor-js.conf.js`: JS e2e tests.
4. `$(npm bin)/protractor protractor-dart2js.conf.js`: Dart2JS e2e tests.
4. `$(npm bin)/protractor protractor-dart2js.conf.js`: dart2js e2e tests.
Angular specific command line options when running protractor:
- `$(npm bin)/protractor protractor-{js|dart2js}-conf.js --ng-help`
@ -167,9 +187,9 @@ Angular specific command line options when running protractor:
### Performance tests
1. `$(npm bin)/gulp build.js.cjs` (builds benchpress and tests into `dist/js/cjs` folder)
2. `$(npm bin)/gulp serve.js.prod serve.js.dart2js` (runs local webserver)
2. `$(npm bin)/gulp serve.js.prod serve.js.dart2js` (runs a local webserver)
3. `$(npm bin)/protractor protractor-js.conf.js --benchmark`: JS performance tests
4. `$(npm bin)/protractor protractor-dart2js.conf.js --benchmark`: Dart2JS performance tests
4. `$(npm bin)/protractor protractor-dart2js.conf.js --benchmark`: dart2js performance tests
Angular specific command line options when running protractor (e.g. force gc, ...):
`$(npm bin)/protractor protractor-{js|dart2js}-conf.js --ng-help`
@ -184,16 +204,20 @@ Angular specific command line options when running protractor (e.g. force gc, ..
### File suffixes
* `*.js`: javascript files that get transpiled to Dart and EcmaScript 5
* `*.es6`: javascript files that get transpiled only to EcmaScript 5
* `*.es5`: javascript files that don't get transpiled
* `*.dart`: dart files that don't get transpiled
* `*.js`: JavaScript files that get transpiled to Dart and EcmaScript 5
* `*.es6`: JavaScript files that get transpiled only to EcmaScript 5
* `*.es5`: JavaScript files that don't get transpiled
* `*.dart`: Dart files that don't get transpiled
## CI using Travis
For instructions on setting up Continuous Integration using Travis, see the instructions given
[here](https://github.com/angular/angular.dart/blob/master/travis.md).
## Transforming Dart code
See the [wiki](//github.com/angular/angular/wiki/Angular-2-Dart-Transformer).
## Debugging
### Debug the transpiler
@ -219,17 +243,18 @@ Notes:
If you need to debug the tests:
- add a `debugger;` statement to the test you want to debug (oe the source code),
- add a `debugger;` statement to the test you want to debug (or the source code),
- execute karma `$(npm bin)/gulp test.js`,
- press the top right "DEBUG" button,
- open the dev tools and press F5,
- the execution halt at the `debugger;` statement
- open the DevTools and press F5,
- the execution halts at the `debugger;` statement
**Note (WebStorm users)**:
You can create a Karma run config from WebStorm.
Then in the "Run" menu, press "Debug 'karma-js.conf.js'", WebStorm will stop in the generated code
on the `debugger;` statement.
You can then step into the code and add watches.
1. Create a Karma run config from WebStorm.
2. Then in the "Run" menu, press "Debug 'karma-js.conf.js'", and WebStorm will stop in the generated
code on the `debugger;` statement.
3. You can then step into the code and add watches.
The `debugger;` statement is needed because WebStorm will stop in a transpiled file. Breakpoints in
the original source files are not supported at the moment.

View File

@ -18,7 +18,7 @@ Follow the instructions given on the [Angular download page][download].
## Want to help?
Want to file a bug, or contribute some code or improve documentation? Excellent! Read up on our
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our
guidelines for [contributing][contributing].
@ -29,13 +29,14 @@ To see the examples, first build the project as described
### Hello World Example
This example consists of three basic pieces - a component, a decorator and a
This example consists of three basic pieces - a component, a decorator, and a
service. They are all constructed via injection. For more information see the
comments in the source `modules/examples/src/hello_world/index.js`.
You can build this example as either JS or Dart app:
You can build this example as either a JS or a Dart app:
* JS:
* `$(npm bin)/gulp build.js.dev`, and
* `$(npm bin)/gulp serve.js.dev`, and
* open `localhost:8000/examples/src/hello_world/` in Chrome.
* Dart:

View File

@ -0,0 +1,48 @@
var path = require('canonical-path');
var Package = require('dgeni').Package;
var basePackage = require('../public-docs-package');
var PARTIAL_PATH = 'partials';
var MODULES_DOCS_PATH = PARTIAL_PATH + '/api';
module.exports = new Package('angular.io', [basePackage])
.factory(require('./services/renderMarkdown'))
.processor(require('./processors/addJadeDataDocsProcessor'))
// Configure rendering
.config(function(templateFinder, templateEngine) {
templateFinder.templateFolders
.unshift(path.resolve(__dirname, 'templates'));
})
.config(function(writeFilesProcessor) {
writeFilesProcessor.outputFolder = 'dist/angular.io';
})
.config(function(computeIdsProcessor, computePathsProcessor, EXPORT_DOC_TYPES) {
computePathsProcessor.pathTemplates.push({
docTypes: ['module'],
pathTemplate: '${id}.html',
outputPathTemplate: MODULES_DOCS_PATH + '/${id}/index.jade'
});
computePathsProcessor.pathTemplates.push({
docTypes: EXPORT_DOC_TYPES,
pathTemplate: '${moduleDoc.id}/${name}-${docType}.html',
outputPathTemplate: MODULES_DOCS_PATH + '/${moduleDoc.id}/${name}-${docType}.jade',
});
computePathsProcessor.pathTemplates.push({
docTypes: ['jade-data'],
pathTemplate: '${originalDoc.id}/_data',
outputPathTemplate: MODULES_DOCS_PATH + '/${path}.json'
});
})
.config(function(getLinkInfo) {
getLinkInfo.relativeLinks = true;
});

View File

@ -0,0 +1,76 @@
var _ = require('lodash');
var path = require('canonical-path');
var titleCase = function(text) {
return text.replace(/(.)(.*)/, function(_, first, rest) {
return first.toUpperCase() + rest;
});
};
/*
* Create _data.json file for Harp pages
*
* http://harpjs.com/docs/development/metadata
*
* This method creates the meta data required for each page
* such as the title, description, etc. This meta data is used
* in the harp static site generator to create the title for headers
* and the navigation used in the API docs
*
*/
module.exports = function addJadeDataDocsProcessor(EXPORT_DOC_TYPES) {
return {
$runAfter: ['adding-extra-docs', 'cloneExportedFromDocs'],
$runBefore: ['extra-docs-added'],
$process: function(docs) {
var extraDocs = [];
var modules = [];
/*
* Create Data for Modules
*
* Modules must be public and have content
*/
_.forEach(docs, function(doc) {
if (doc.docType === 'module' && doc.public && doc.exports.length) {
modules.push(doc);
// GET DATA FOR INDEX PAGE OF MODULE SECTION
var indexPageInfo = [{
name: 'index',
title: _.map(path.basename(doc.fileInfo.baseName).split('_'), function(part) {
return titleCase(part);
}).join(' '),
intro: doc.description.replace('"', '\"').replace(/\r?\n|\r/g,"")
}];
// GET DATA FOR EACH PAGE (CLASS, VARS, FUNCTIONS)
var modulePageInfo = _.map(doc.exports, function(exportDoc) {
return {
name: exportDoc.name + '-' + exportDoc.docType,
title: exportDoc.name + ' ' + titleCase(exportDoc.docType)
};
});
//COMBINE PAGE DATA
var allPageData = indexPageInfo.concat(modulePageInfo);
// PUSH DATA TO EXTRA DOCS ARRAY
extraDocs.push({
id: doc.id + "-data",
aliases: [doc.id + "-data"],
docType: 'jade-data',
originalDoc: doc,
data: allPageData
});
}
});
return docs.concat(extraDocs);
}
};
};

View File

@ -0,0 +1,50 @@
var marked = require('marked');
var Encoder = require('node-html-encoder').Encoder;
var html2jade = require('html2jade');
var indentString = require('indent-string');
var S = require('string');
// entity type encoder
var encoder = new Encoder('entity');
/**
* @dgService renderMarkdown
* @description
* Render the markdown in the given string as HTML.
*/
module.exports = function renderMarkdown(trimIndentation) {
var renderer = new marked.Renderer();
renderer.code = function(code, lang, escaped) {
var cssClasses = ['prettyprint', 'linenums'];
var trimmedCode = trimIndentation(code);
if(lang) {
if(lang=='html') {
trimmedCode = encoder.htmlEncode(trimmedCode);
}
cssClasses.push(this.options.langPrefix + escape(lang, true));
}
return 'pre(class="' + cssClasses.join(' ') + '")\n' + indentString('code.\n', ' ', 2) + trimmedCode;
};
renderer.heading = function (text, level, raw) {
var headingText = marked.Renderer.prototype.heading.call(renderer, text, level, raw);
var title = 'h2 ' + S(headingText).stripTags().s;
if (level==2) {
title = '.l-main-section\n' + indentString(title, ' ', 2) ;
}
return title;
};
return function(content) {
return marked(content, { renderer: renderer });
};
};

View File

@ -0,0 +1,49 @@
{% include "lib/paramList.html" -%}
{% extends 'layout/base.template.html' -%}
{% block body %}
p.location-badge.
exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a>
defined in <a href="https://github.com/angular/angular/tree/master/modules/{$ doc.location.start.source.name $}.js#L{$ doc.location.start.line $}">{$ doc.location.start.source.name $}.js (line {$ doc.location.start.line $})</a>
:markdown
{$ doc.description | indent(2, true) $}
{%- if doc.constructorDoc or doc.members.length -%}
.l-main-section
h2 Members
{%- if doc.constructorDoc %}
.l-sub-section
h3 {$ doc.constructorDoc.name $}
{% if doc.constructorDoc.params %}
pre.prettyprint
code.
{$ doc.constructorDoc.name $}{$ paramList(doc.constructorDoc.params) | indent(4, true) | trim $}
{% endif %}
:markdown
{$ doc.constructorDoc.description | indent(6, true) | replace('## Example', '') | replace('# Example', '') $}
{% endif -%}
{%- for member in doc.members %}{% if not member.private %}
.l-sub-section
h3 {$ member.name $}
{% if member.params %}
pre.prettyprint
code.
{$ member.name $}{$ paramList(member.params) | indent(4, true) | trim $}
{% endif %}
:markdown
{$ member.description | indent(6, true) | replace('## Example', '') | replace('# Example', '') $}
{% endif %}{% endfor %}
{%- endif -%}
{% endblock %}

View File

@ -0,0 +1,16 @@
{% include "lib/paramList.html" -%}
{% extends 'layout/base.template.html' -%}
{% block body %}
.l-main-section
h2(class="function export") {$ doc.name $}
p <code>{$ paramList(doc.parameters) $}</code>
p.location-badge.
exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a>
:markdown
{$ doc.description | indent(4, true) $}
{% endblock %}

View File

@ -0,0 +1,8 @@
{
{%- for item in doc.data %}
"{$ item.name $}" : {
"title" : "{$ item.title $}"{% if item.intro %},
"intro" : "{$ item.intro $}"{% endif %}
}{% if not loop.last %},{% endif %}
{% endfor -%}
}

View File

@ -0,0 +1 @@
{% block body %}{% endblock %}

View File

@ -0,0 +1,7 @@
{% macro paramList(params) -%}
{%- if params -%}
({%- for param in params -%}
{$ param | escape $}{% if not loop.last %}, {% endif %}
{%- endfor %})
{%- endif %}
{%- endmacro -%}

View File

@ -0,0 +1,11 @@
{% extends 'layout/base.template.html' -%}
{% block body -%}
ul
for page, slug in public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]]._data
if slug != 'index'
url = "/docs/" + current.path[1] + "/" + current.path[2] + "/" + current.path[3] + "/" + current.path[4] + "/" + slug + ".html"
li.c8
!= partial("../../../../../_includes/_hover-card", {name: page.title, url: url })
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends 'layout/base.template.html' %}
{% block body %}
.l-main-section
h2 {$ doc.name $} <span class="type">variable</span>
p.location-badge.
exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a>
:markdown
{$ doc.description | indent(4, true) $}
{% endblock %}

View File

@ -364,3 +364,16 @@ md-content.demo-source-container > hljs > pre > code.highlight {
padding-left:32px !important;
padding-right:32px !important;
}
.member .name {
white-space: pre-wrap;
word-wrap: break-word;
font-family: monospace;
font-size: 1.17em;
margin: 1em 0;
}
.left-nav {
min-width: 300px;
}

View File

@ -28,7 +28,7 @@
<section layout="row">
<md-content>
<md-content class="left-nav">
<h2>Navigation</h2>
<section ng-repeat="area in nav.areas">
<h3>{{ area.name }}</h3>
@ -47,7 +47,7 @@
<md-content class="md-padding">
<ng-include src="nav.currentPage.partial"></ng-include>
<ng-include autoscroll src="nav.currentPage.partial"></ng-include>
</md-content>
</section>

View File

@ -37,15 +37,19 @@ module.exports = new Package('angular', [jsdocPackage, nunjucksPackage])
// Register the processors
.processor(require('./processors/generateDocsFromComments'))
.processor(require('./processors/processModuleDocs'))
.processor(require('./processors/processClassDocs'))
.processor(require('./processors/captureModuleExports'))
.processor(require('./processors/captureClassMembers'))
.processor(require('./processors/captureModuleDocs'))
.processor(require('./processors/attachModuleDocs'))
.processor(require('./processors/cloneExportedFromDocs'))
.processor(require('./processors/generateNavigationDoc'))
.processor(require('./processors/extractTitleFromGuides'))
.processor(require('./processors/createOverviewDump'))
// Configure the log service
.config(function(log) {
log.level = 'info';
log.level = 'warn';
})
@ -56,12 +60,23 @@ module.exports = new Package('angular', [jsdocPackage, nunjucksPackage])
readFilesProcessor.sourceFiles = [
{ include: 'modules/*/*.js', basePath: 'modules' },
{ include: 'modules/*/src/**/*.js', basePath: 'modules' },
{ include: 'modules/*/*.es6', basePath: 'modules' },
{ include: 'modules/*/src/**/*.es6', basePath: 'modules' },
{ include: 'modules/*/*.ts', basePath: 'modules' },
{ include: 'modules/*/src/**/*.ts', basePath: 'modules' },
{ include: 'modules/*/docs/**/*.md', basePath: 'modules' },
{ include: 'docs/content/**/*.md', basePath: 'docs/content' }
];
})
.config(function(parseTagsProcessor, getInjectables) {
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/public'));
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/private'));
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/exportedAs'));
})
// Configure file writing
.config(function(writeFilesProcessor) {
writeFilesProcessor.outputFolder = 'dist/docs';
@ -96,7 +111,7 @@ module.exports = new Package('angular', [jsdocPackage, nunjucksPackage])
computeIdsProcessor.idTemplates.push({
docTypes: EXPORT_DOC_TYPES,
idTemplate: '${moduleDoc.id}.${name}',
getAliases: function(doc) { return [doc.id]; }
getAliases: function(doc) { return [doc.id, doc.name]; }
});
computeIdsProcessor.idTemplates.push({
@ -144,4 +159,4 @@ module.exports = new Package('angular', [jsdocPackage, nunjucksPackage])
pathTemplate: '${id}',
outputPathTemplate: GUIDES_PATH + '/${id}.html'
});
});
});

View File

@ -0,0 +1,22 @@
var _ = require('lodash');
module.exports = function attachModuleDocs(log) {
return {
$runAfter: ['tags-extracted'],
$runBefore: ['computing-ids'],
$process: function(docs) {
return _.filter(docs, function(doc) {
if (doc.docType !== 'moduleDoc') {
return true;
}
if (doc.module || doc.module === '') {
doc.moduleDoc.description = doc.description;
doc.moduleDoc.public = doc.public;
log.debug('attached', doc.moduleDoc.id, doc.moduleDoc.description);
}
return false;
});
}
};
};

View File

@ -1,10 +1,10 @@
var _ = require('lodash');
module.exports = function processClassDocs(log, getJSDocComment) {
module.exports = function captureClassMembers(log, getJSDocComment) {
return {
$runAfter: ['processModuleDocs'],
$runBefore: ['parsing-tags', 'generateDocsFromComments'],
$runAfter: ['captureModuleExports'],
$runBefore: ['parsing-tags'],
ignorePrivateMembers: false,
$process: function(docs) {
var memberDocs = [];
@ -17,15 +17,20 @@ module.exports = function processClassDocs(log, getJSDocComment) {
// Create a new doc for each member of the class
_.forEach(classDoc.elements, function(memberDoc) {
if (ignorePrivateMembers && memberDoc.name.literalToken.value.charAt(0) === '_') return;
var memberName = memberDoc.name.location.toString();
if (ignorePrivateMembers && memberName.charAt(0) === '_') return;
classDoc.members.push(memberDoc);
memberDocs.push(memberDoc);
memberDoc.docType = 'member';
memberDoc.classDoc = classDoc;
memberDoc.name = memberDoc.name.literalToken.value;
memberDoc.name = memberName;
if (memberDoc.parameterList) {
memberDoc.params = memberDoc.parameterList.parameters.map(function(param) {
return param.location.toString();
});
}
if (memberDoc.commentBefore ) {
// If this export has a comment, remove it from the list of
@ -37,6 +42,14 @@ module.exports = function processClassDocs(log, getJSDocComment) {
_.assign(memberDoc, getJSDocComment(memberDoc.commentBefore));
}
// Constuctor is a special case member
if (memberName === 'constructor') {
classDoc.constructorDoc = memberDoc;
} else {
insertSorted(classDoc.members, memberDoc, 'name');
}
});
}
});
@ -45,3 +58,13 @@ module.exports = function processClassDocs(log, getJSDocComment) {
}
};
};
function insertSorted(collection, item, property) {
var index = collection.length;
while(index>0) {
if(collection[index-1][property] < item[property]) break;
index -= 1;
}
collection.splice(index, 0, item);
}

View File

@ -0,0 +1,31 @@
var _ = require('lodash');
module.exports = function captureModuleDocs(log, getJSDocComment) {
return {
$runAfter: ['captureClassMembers'],
$runBefore: ['parsing-tags'],
$process: function(docs) {
// Generate docs for each module's file's comments not already captured
_.forEach(docs, function(moduleDoc) {
if ( moduleDoc.docType !== 'module' ) return;
moduleDoc.extraComments = [];
_.forEach(moduleDoc.comments, function(comment) {
var jsDocComment = getJSDocComment(comment);
if (jsDocComment) {
jsDocComment.docType = 'moduleDoc';
jsDocComment.moduleDoc = moduleDoc;
moduleDoc.extraComments.push(jsDocComment);
docs.push(jsDocComment);
// console.log('found', jsDocComment.content);
}
});
if ( moduleDoc.extraComments.length > 0 ) {
// console.log(moduleDoc.extraComments.length);
}
});
}
};
};

View File

@ -1,12 +1,12 @@
var _ = require('lodash');
module.exports = function processModuleDocs(log, ExportTreeVisitor, getJSDocComment) {
module.exports = function captureModuleExports(log, ExportTreeVisitor, getJSDocComment) {
return {
$runAfter: ['files-read'],
$runBefore: ['parsing-tags', 'generateDocsFromComments'],
$runBefore: ['parsing-tags'],
$process: function(docs) {
var exportDocs = [];
var extraDocs = [];
_.forEach(docs, function(doc) {
if ( doc.docType === 'module' ) {
@ -21,7 +21,7 @@ module.exports = function processModuleDocs(log, ExportTreeVisitor, getJSDocComm
_.forEach(visitor.exports, function(exportDoc) {
doc.exports.push(exportDoc);
exportDocs.push(exportDoc);
extraDocs.push(exportDoc);
exportDoc.moduleDoc = doc;
if (exportDoc.comment) {
@ -40,7 +40,7 @@ module.exports = function processModuleDocs(log, ExportTreeVisitor, getJSDocComm
}
});
return docs.concat(exportDocs);
return docs.concat(extraDocs);
}
};
};

View File

@ -0,0 +1,39 @@
var _ = require('lodash');
module.exports = function cloneExportedFromDocs(modules, EXPORT_DOC_TYPES) {
return {
$runAfter: ['tags-parsed', 'attachModuleDocs'],
$runBefore: ['computing-ids'],
$process: function(docs) {
var extraPublicDocs = [];
_.forEach(docs, function(doc) {
if (EXPORT_DOC_TYPES.indexOf(doc.docType) === -1 || !doc.exportedAs) return;
_.forEach(doc.exportedAs, function(exportedAs) {
var exportedAsModule = modules[exportedAs];
if (!exportedAsModule) {
throw new Error('Missing module definition: "' + doc.exportedAs + '"\n' +
'Referenced in "@exportedAs" tag on class: "' + doc.moduleDoc.id + '/' + doc.name + '"');
} else {
if(exportedAsModule !== doc.moduleDoc) {
// Add a clone of export to its "exportedAs" module
var clonedDoc = _.clone(doc);
clonedDoc.moduleDoc = exportedAsModule;
exportedAsModule.exports.push(clonedDoc);
extraPublicDocs.push(clonedDoc);
}
}
});
});
docs = docs.concat(extraPublicDocs);
return docs;
}
};
};

View File

@ -0,0 +1,24 @@
var _ = require('lodash');
module.exports = function createOverviewDump() {
return {
$runAfter: ['captureModuleExports', 'captureClassMembers'],
$runBefore: ['docs-processed'],
$process: function(docs) {
var overviewDoc = {
id: 'overview-dump',
aliases: ['overview-dump'],
path: 'overview-dump',
outputPath: 'overview-dump.html',
modules: []
};
_.forEach(docs, function(doc) {
if ( doc.docType === 'module' ) {
overviewDoc.modules.push(doc);
}
});
docs.push(overviewDoc);
}
};
};

View File

@ -1,34 +0,0 @@
var _ = require('lodash');
module.exports = function generateDocsFromComments(log) {
return {
$runAfter: ['files-read'],
$runBefore: ['parsing-tags'],
$process: function(docs) {
var commentDocs = [];
docs = _.filter(docs, function(doc) {
if (doc.docType !== 'atScriptFile') {
return true;
} else {
_.forEach(doc.fileInfo.comments, function(comment) {
// we need to check for `/**` at the start of the comment to find all the jsdoc style comments
comment.range.toString().replace(/^\/\*\*([\w\W]*)\*\/$/g, function(match, commentBody) {
// Create a doc from this comment
commentDocs.push({
fileInfo: doc.fileInfo,
startingLine: comment.range.start.line,
endingLine: comment.range.end.line,
content: commentBody,
codeTree: comment.treeAfter,
docType: 'atScriptDoc'
});
});
});
}
});
return docs.concat(commentDocs);
}
};
};

View File

@ -27,13 +27,15 @@ module.exports = function generateNavigationDoc() {
modulesDoc.value.sections.push(moduleNavItem);
_.forEach(doc.exports, function(exportDoc) {
var exportNavItem = {
path: exportDoc.path,
partial: exportDoc.outputPath,
name: exportDoc.name,
type: exportDoc.docType
};
moduleNavItem.pages.push(exportNavItem);
if (!exportDoc.private) {
var exportNavItem = {
path: exportDoc.path,
partial: exportDoc.outputPath,
name: exportDoc.name,
type: exportDoc.docType
};
moduleNavItem.pages.push(exportNavItem);
}
});
}
});

View File

@ -10,9 +10,8 @@ var path = require('canonical-path');
module.exports = function atScriptFileReader(log, atParser, modules) {
var reader = {
name: 'atScriptFileReader',
defaultPattern: /\.js$/,
defaultPattern: /\.js|\.es6|\.ts$/,
getDocs: function(fileInfo) {
var moduleDoc = atParser.parseModule(fileInfo);
moduleDoc.docType = 'module';
moduleDoc.id = moduleDoc.moduleTree.moduleName;

View File

@ -33,7 +33,7 @@ describe('atScript file reader', function() {
it('should provide a default pattern', function() {
expect(reader.defaultPattern).toEqual(/\.js$/);
expect(reader.defaultPattern).toEqual(/\.js|\.es6|\.ts$/);
});
@ -52,4 +52,4 @@ describe('atScript file reader', function() {
expect(docs[0].docType).toEqual('module');
});
});
});

View File

@ -30,11 +30,18 @@ module.exports = function AttachCommentTreeVisitor(ParseTreeVisitor, log) {
log.silly('tree: ' + tree.constructor.name + ' - ' + tree.location.start.line);
while (this.currentComment &&
this.currentComment.range.end.offset < tree.location.start.offset) {
log.silly('comment: ' + this.currentComment.range.start.line + ' - ' +
this.currentComment.range.end.line + ' : ' +
this.currentComment.range.toString());
tree.commentBefore = this.currentComment;
this.currentComment.treeAfter = tree;
var commentText = this.currentComment.range.toString();
// Only store the comment if it is JSDOC style (e.g. /** some comment */)
if (/^\/\*\*([\w\W]*)\*\/$/.test(commentText)) {
log.silly('comment: ' + this.currentComment.range.start.line + ' - ' +
this.currentComment.range.end.line + ' : ' +
commentText);
tree.commentBefore = this.currentComment;
this.currentComment.treeAfter = tree;
}
this.index++;
this.currentComment = this.comments[this.index];
}

View File

@ -38,7 +38,9 @@ module.exports = function ExportTreeVisitor(ParseTreeVisitor, log) {
this.updateExport(tree);
this.currentExport.name = tree.name.identifierToken.value;
this.currentExport.functionKind = tree.functionKind;
this.currentExport.parameters = tree.parameterList.parameters;
this.currentExport.parameters = tree.parameterList.parameters.map(function(param) {
return param.location.toString();
});
this.currentExport.typeAnnotation = tree.typeAnnotation;
this.currentExport.annotations = tree.annotations;
this.currentExport.docType = 'function';

View File

@ -34,13 +34,18 @@ module.exports = function atParser(AttachCommentTreeVisitor, SourceFile, Traceur
var sourceFile = new SourceFile(moduleName, fileInfo.content);
var comments = [];
var moduleTree;
var parser = new TraceurParser(sourceFile);
var errorReporter = {
reportError: function(position, message) {
}
};
traceurOptions.setFromObject(service.traceurOptions);
var parser = new TraceurParser(sourceFile, errorReporter, traceurOptions);
// Configure the parser
parser.handleComment = function(range) {
comments.push({ range: range });
};
traceurOptions.setFromObject(service.traceurOptions);
try {
// Parse the file as a module, attaching the comments

View File

@ -1,3 +1,4 @@
module.exports = function traceurOptions() {
return System.get(System.map.traceur + '/src/Options.js').options;
var Options = System.get(System.map.traceur + "/src/Options.js").Options;
return new Options();
};

View File

@ -0,0 +1,4 @@
module.exports = {
name: 'exportedAs',
multi: true
};

View File

@ -0,0 +1,4 @@
module.exports = {
name: 'private',
transforms: function(doc, tag) { return true; }
};

View File

@ -0,0 +1,4 @@
module.exports = {
name: 'public',
transforms: function(doc, tag) { return true; }
};

View File

@ -1,14 +1,33 @@
{% extends 'layout/base.template.html' %}
{% include "lib/paramList.html" -%}
{% extends 'layout/base.template.html' -%}
{% block body %}
<h1>{$ doc.name $} <span class="type">class</span></h1>
<p class="module">exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a></p>
<h1 class="class export">{$ doc.name $} <span class="type">class</span></h1>
<p class="module">exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a><br/>
defined in <a href="https://github.com/angular/angular/tree/master/modules/{$ doc.location.start.source.name $}.js#L{$ doc.location.start.line $}">{$ doc.location.start.source.name $}.js (line {$ doc.location.start.line $})</a></p>
<p>{$ doc.description | marked $}</p>
{%- if doc.constructorDoc or doc.members.length -%}
<h2>Members</h2>
{% for member in doc.members %}
<h3>{$ member.name $}</h3>
<p>{$ member.description | marked $}</p>
{% endfor %}
{%- if doc.constructorDoc %}
<section class="member constructor">
<h1 id="constructor" class="name">{$ doc.constructorDoc.name $}{$ paramList(doc.constructorDoc.params) $}</h1>
{% marked %}
{$ doc.constructorDoc.description $}
{% endmarked %}
</section>
{% endif -%}
{%- for member in doc.members %}{% if not member.private %}
<section class="member">
<h1 id="{$ member.name $}" class="name">{$ member.name $}{$ paramList(member.params) $}</h1>
{% marked %}
{$ member.description $}
{% endmarked %}
</section>
{% endif %}{% endfor %}
{%- endif -%}
{% endblock %}

View File

@ -0,0 +1,9 @@
{% include "lib/paramList.html" -%}
{% extends 'layout/base.template.html' -%}
{% block body %}
<h1 class="function export">{$ doc.name $}{$ paramList(doc.parameters) $}</h1>
<p class="module">exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a></p>
<p>{$ doc.description | marked $}</p>
{% endblock %}

View File

@ -0,0 +1,7 @@
{% macro paramList(params) -%}
{%- if params -%}<span class="params">(
{%- for param in params -%}
<span class="param">{$ param | escape $}{% if not loop.last %}, {% endif %}</span>
{%- endfor %})</span>
{%- endif %}
{%- endmacro -%}

View File

@ -9,7 +9,9 @@
<h2>Exports</h2>
<ul>
{%- for exportDoc in doc.exports %}
<li><a href="/{$ exportDoc.path $}">{$ exportDoc.name $} {$ exportDoc.docType $}</a></li>
{% if not exportDoc.private -%}
<li><a href="/{$ exportDoc.path $}"><strong>{$ exportDoc.name $}</strong> {$ exportDoc.docType $}</a></li>
{%- endif %}
{%- endfor %}
</ul>
{% endif %}

View File

@ -0,0 +1,43 @@
{% include "lib/paramList.html" -%}
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
h2 {
padding-left: 20px;
}
h3 {
padding-left: 50px;
}
h4 {
padding-left: 60px;
}
</style>
</head>
<body>
<h1>Modules</h1>
{% for module in doc.modules %}
<h2>{$ module.id $}
{%- if module.public %} (public){% endif %}</h2>
{% for export in module.exports %}
<h3>{$ export.name $}</h3>
{%- if export.constructorDoc %}
<h4>{$ doc.constructorDoc.name $}{$ paramList(doc.constructorDoc.params) $}</h4>
{% endif -%}
{%- for member in export.members %}
<h4>{$ member.name $}{$ paramList(member.params) $}</h4>
{% endfor %}
{% endfor %}
{% endfor %}
</body>
</html>

View File

@ -0,0 +1,8 @@
{% extends 'layout/base.template.html' %}
{% block body %}
<h1>{$ doc.name $} <span class="type">variable</span></h1>
<p class="module">exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a></p>
<p>{$ doc.description | marked $}</p>
{% endblock %}

View File

@ -0,0 +1,12 @@
var Package = require('dgeni').Package;
module.exports = new Package('links', [])
.factory(require('./inline-tag-defs/link'))
.factory(require('dgeni-packages/ngdoc/services/getAliases'))
.factory(require('dgeni-packages/ngdoc/services/getDocFromAlias'))
.factory(require('./services/getLinkInfo'))
.config(function(inlineTagProcessor, linkInlineTagDef) {
inlineTagProcessor.inlineTagDefinitions.push(linkInlineTagDef);
});

View File

@ -0,0 +1,33 @@
var INLINE_LINK = /(\S+)(?:\s+([\s\S]+))?/;
/**
* @dgService linkInlineTagDef
* @description
* Process inline link tags (of the form {@link some/uri Some Title}), replacing them with HTML anchors
* @kind function
* @param {Object} url The url to match
* @param {Function} docs error message
* @return {String} The html link information
*
* @property {boolean} relativeLinks Whether we expect the links to be relative to the originating doc
*/
module.exports = function linkInlineTagDef(getLinkInfo, createDocMessage) {
return {
name: 'link',
description: 'Process inline link tags (of the form {@link some/uri Some Title}), replacing them with HTML anchors',
handler: function(doc, tagName, tagDescription) {
// Parse out the uri and title
return tagDescription.replace(INLINE_LINK, function(match, uri, title) {
var linkInfo = getLinkInfo(uri, title, doc);
if ( !linkInfo.valid ) {
throw new Error(createDocMessage(linkInfo.error, doc));
}
return "<a href='" + linkInfo.url + "'>" + linkInfo.title + "</a>";
});
}
};
};

View File

@ -0,0 +1,70 @@
var _ = require('lodash');
var path = require('canonical-path');
/**
* @dgService getLinkInfo
* @description
* Get link information to a document that matches the given url
* @kind function
* @param {String} url The url to match
* @param {String} title An optional title to return in the link information
* @return {Object} The link information
*
* @property {boolean} relativeLinks Whether we expect the links to be relative to the originating doc
*/
module.exports = function getLinkInfo(getDocFromAlias, encodeCodeBlock, log) {
return function getLinkInfoImpl(url, title, currentDoc) {
var linkInfo = {
url: url,
type: 'url',
valid: true,
title: title || url
};
if ( !url ) {
throw new Error('Invalid url');
}
var docs = getDocFromAlias(url, currentDoc);
if ( docs.length > 1 ) {
linkInfo.valid = false;
linkInfo.error = 'Ambiguous link: "' + url + '".\n' +
docs.reduce(function(msg, doc) { return msg + '\n "' + doc.id + '" ('+ doc.docType + ') : (' + doc.area + ')'; }, 'Matching docs: ');
} else if ( docs.length === 1 ) {
linkInfo.url = docs[0].path;
linkInfo.title = title || encodeCodeBlock(docs[0].name, true);
linkInfo.type = 'doc';
if ( getLinkInfoImpl.relativeLinks && currentDoc && currentDoc.path ) {
var currentFolder = path.dirname(currentDoc.path);
var docFolder = path.dirname(linkInfo.url);
var relativeFolder = path.relative(path.join('/', currentFolder), path.join('/', docFolder));
linkInfo.url = path.join(relativeFolder, path.basename(linkInfo.url));
log.debug(currentDoc.path, docs[0].path, linkInfo.url);
}
} else if ( url.indexOf('#') > 0 ) {
var pathAndHash = url.split('#');
linkInfo = getLinkInfoImpl(pathAndHash[0], title, currentDoc);
linkInfo.url = linkInfo.url + '#' + pathAndHash[1];
return linkInfo;
} else if ( url.indexOf('/') === -1 && url.indexOf('#') !== 0 ) {
linkInfo.valid = false;
linkInfo.error = 'Invalid link (does not match any doc): "' + url + '"';
} else {
linkInfo.title = title || (( url.indexOf('#') === 0 ) ? url.substring(1) : path.basename(url, '.html'));
}
return linkInfo;
};
};

View File

@ -1,21 +1,16 @@
var Package = require('dgeni').Package;
var basePackage = require('../dgeni-package');
var linksPackage = require('../links-package');
module.exports = new Package('angular-public', [basePackage])
module.exports = new Package('angular-public', [basePackage, linksPackage])
.processor(require('./processors/filterPublicDocs'))
.config(function(parseTagsProcessor) {
parseTagsProcessor.tagDefinitions.push({ name: 'publicModule' });
})
.config(function(processClassDocs, filterPublicDocs, EXPORT_DOC_TYPES) {
processClassDocs.ignorePrivateMembers = true;
filterPublicDocs.docTypes = EXPORT_DOC_TYPES;
.config(function(captureClassMembers) {
captureClassMembers.ignorePrivateMembers = true;
})
// Configure file writing
.config(function(writeFilesProcessor) {
writeFilesProcessor.outputFolder = 'dist/public_docs';
});
});

View File

@ -1,51 +1,28 @@
var _ = require('lodash');
module.exports = function filterPublicDocs(modules) {
module.exports = function filterPublicDocs(modules, EXPORT_DOC_TYPES) {
return {
$runAfter: ['tags-parsed'],
$runAfter: ['tags-parsed', 'cloneExportedFromDocs'],
$runBefore: ['computing-ids'],
docTypes: [],
$validate: {
docTypes: { presence: true }
},
$process: function(docs) {
docTypes = this.docTypes;
// Filter out the documents that are not public
return _.filter(docs, function(doc) {
if (doc.docType === 'module') {
// doc is a module - is it public?
return doc.public;
}
docs = _.filter(docs, function(doc) {
if (EXPORT_DOC_TYPES.indexOf(doc.docType) === -1) {
// doc is not a type we care about
return true;
}
if (docTypes.indexOf(doc.docType) === -1) return true;
if (!doc.publicModule) return false;
// doc is in a public module
return doc.moduleDoc && doc.moduleDoc.public;
updateModule(doc);
return true;
});
docs = _.filter(docs, function(doc) {
return doc.docType !== 'module' || doc.isPublic;
});
return docs;
}
};
function updateModule(classDoc) {
var originalModule = classDoc.moduleDoc;
var publicModule = modules[classDoc.publicModule];
if (!publicModule) {
throw new Error('Missing module definition: "' + classDoc.publicModule + '"\n' +
'Referenced in class: "' + classDoc.moduleDoc.id + '/' + classDoc.name + '"');
}
publicModule.isPublic = true;
_.remove(classDoc.moduleDoc.exports, function(doc) { return doc === classDoc; });
classDoc.moduleDoc = publicModule;
publicModule.exports.push(classDoc);
}
};

File diff suppressed because it is too large Load Diff

View File

@ -8,14 +8,14 @@ module.exports = function(config) {
frameworks: ['dart-unittest'],
files: [
// Init and configure guiness.
{pattern: 'test-init.dart', included: true},
// Unit test files needs to be included.
// Karma-dart generates `__adapter_unittest.dart` that imports these files.
{pattern: 'modules/*/test/**/*_spec.js', included: true},
{pattern: 'tools/transpiler/spec/**/*_spec.js', included: true},
{pattern: 'dist/dart/**/*_spec.dart', included: true, watched: false},
// These files are not included, they are imported by the unit tests above.
{pattern: 'modules/**', included: false},
{pattern: 'tools/transpiler/spec/**/*', included: 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},
@ -24,58 +24,29 @@ module.exports = function(config) {
{pattern: 'test-main.dart', included: true}
],
exclude: [
'dist/dart/**/packages/**',
],
karmaDartImports: {
guinness: 'package:guinness/guinness_html.dart'
},
// TODO(vojta): Remove the localhost:9877 from urls, once the proxy fix is merged:
// https://github.com/karma-runner/karma/pull/1207
//
// Map packages to the correct urls where Karma serves them.
proxies: {
// Dependencies installed with `pub install`.
'/packages/unittest': 'http://localhost:9877/base/packages/unittest',
'/packages/guinness': 'http://localhost:9877/base/packages/guinness',
'/packages/matcher': 'http://localhost:9877/base/packages/matcher',
'/packages/stack_trace': 'http://localhost:9877/base/packages/stack_trace',
'/packages/collection': 'http://localhost:9877/base/packages/collection',
'/packages/path': 'http://localhost:9877/base/packages/path',
'/packages/unittest': '/base/packages/unittest',
'/packages/guinness': '/base/packages/guinness',
'/packages/matcher': '/base/packages/matcher',
'/packages/stack_trace': '/base/packages/stack_trace',
'/packages/collection': '/base/packages/collection',
'/packages/path': '/base/packages/path',
// Local dependencies, transpiled from the source.
'/packages/angular': 'http://localhost:9877/base/modules/angular',
'/packages/benchpress': 'http://localhost:9877/base/modules/benchpress',
'/packages/core': 'http://localhost:9877/base/modules/core',
'/packages/change_detection': 'http://localhost:9877/base/modules/change_detection',
'/packages/reflection': 'http://localhost:9877/base/modules/reflection',
'/packages/di': 'http://localhost:9877/base/modules/di',
'/packages/directives': 'http://localhost:9877/base/modules/directives',
'/packages/facade': 'http://localhost:9877/base/modules/facade',
'/packages/forms': 'http://localhost:9877/base/modules/forms',
'/packages/test_lib': 'http://localhost:9877/base/modules/test_lib',
'/packages/mock': 'http://localhost:9877/base/modules/mock',
},
preprocessors: {
'modules/**/*.js': ['traceur'],
'tools/**/*.js': ['traceur']
},
traceurPreprocessor: {
options: {
outputLanguage: 'dart',
sourceMaps: true,
script: false,
modules: 'register',
memberVariables: true,
types: true,
// typeAssertions: true,
// typeAssertionModule: 'assert',
annotations: true
},
resolveModuleName: file2moduleName,
transformPath: function(fileName) {
return fileName.replace('.js', '.dart');
}
'/packages/angular2': '/base/dist/dart/angular2/lib',
'/packages/angular2_material': '/base/dist/dart/angular2_material/lib',
'/packages/benchpress': '/base/dist/dart/benchpress/lib',
'/packages/examples': '/base/dist/dart/examples/lib'
},
customLaunchers: {
@ -87,7 +58,4 @@ module.exports = function(config) {
port: 9877
});
config.plugins.push(require('./tools/transpiler/karma-traceur-preprocessor'));
};

View File

@ -10,14 +10,16 @@ module.exports = function(config) {
files: [
// Sources and specs.
// Loaded through the es6-module-loader, in `test-main.js`.
{pattern: 'modules/**', included: false},
{pattern: 'tools/transpiler/spec/**', included: false},
{pattern: 'dist/js/dev/es5/**', included: false, watched: false},
'node_modules/traceur/bin/traceur-runtime.js',
'node_modules/es6-module-loader/dist/es6-module-loader-sans-promises.src.js',
// Including systemjs because it defines `__eval`, which produces correct stack traces.
'node_modules/systemjs/dist/system.src.js',
'node_modules/systemjs/lib/extension-register.js',
'node_modules/systemjs/lib/extension-cjs.js',
'node_modules/rx/dist/rx.js',
'node_modules/reflect-metadata/Reflect.js',
'node_modules/zone.js/zone.js',
'node_modules/zone.js/long-stack-trace-zone.js',
@ -26,43 +28,19 @@ module.exports = function(config) {
],
exclude: [
'modules/**/e2e_test/**'
'dist/js/dev/es5/**/e2e_test/**',
],
preprocessors: {
'modules/**/*.js': ['traceur'],
'modules/**/*.es6': ['traceur'],
'tools/transpiler/spec/**/*.js': ['traceur'],
'tools/transpiler/spec/**/*.es6': ['traceur'],
},
traceurPreprocessor: {
options: {
outputLanguage: 'es5',
sourceMaps: true,
script: false,
memberVariables: true,
modules: 'instantiate',
types: true,
typeAssertions: true,
typeAssertionModule: 'rtts_assert/rtts_assert',
annotations: true
},
resolveModuleName: file2moduleName,
transformPath: function(fileName) {
return fileName.replace(/\.es6$/, '.js');
}
},
customLaunchers: {
DartiumWithWebPlatform: {
base: 'Dartium',
flags: ['--enable-experimental-web-platform-features'] }
flags: ['--enable-experimental-web-platform-features'] },
ChromeNoSandbox: {
base: 'Chrome',
flags: ['--no-sandbox'] }
},
browsers: ['ChromeCanary'],
port: 9876
});
config.plugins.push(require('./tools/transpiler/karma-traceur-preprocessor'));
};

View File

@ -1 +0,0 @@
karma-js.conf.js

View File

@ -1,8 +1,8 @@
/**
* Define public API for Angular here.
*/
export * from './change_detection';
export * from './core';
export * from './annotations';
export * from './directives';
export * from './forms';
export {Observable, EventEmitter} from 'angular2/src/facade/async';
export * from 'angular2/src/render/api';
export {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';

View File

@ -0,0 +1,20 @@
import * as angular from './angular2';
// the router should have its own SFX bundle
// But currently the module arithemtic 'angular2/router_sfx - angular2/angular2',
// is not support by system builder.
import * as router from './router';
angular.router = router;
var _prevAngular = window.angular;
/**
* Calling noConflict will restore window.angular to its pre-angular loading state
* and return the angular module object.
*/
angular.noConflict = function() {
window.angular = _prevAngular;
return angular;
};
window.angular = angular;

View File

@ -1,4 +1,12 @@
/**
* Define public API for Angular here.
* @module
* @public
* @description
*
* Annotations provide the additional information that Angular requires in order to run your application. This module
* contains {@link Component}, {@link Directive}, and {@link View} annotations, as well as {@link Parent} and {@link Ancestor} annotations that are
* used by Angular to resolve dependencies.
*
*/
export * from './src/core/annotations/annotations';
export * from './src/core/annotations/decorators';

View File

@ -1,72 +1,29 @@
export {AST} from './src/change_detection/parser/ast';
/**
* @module
* @public
* @description
* Change detection enables data binding in Angular.
*/
export {
ASTWithSource, AST, AstTransformer, AccessMember, LiteralArray, ImplicitReceiver
} from './src/change_detection/parser/ast';
export {Lexer} from './src/change_detection/parser/lexer';
export {Parser} from './src/change_detection/parser/parser';
export {Locals}
from './src/change_detection/parser/locals';
export {ExpressionChangedAfterItHasBeenChecked, ChangeDetectionError}
from './src/change_detection/exceptions';
export {ChangeRecord, ChangeDispatcher, ChangeDetector,
CHECK_ONCE, CHECK_ALWAYS, DETACHED, CHECKED} from './src/change_detection/interfaces';
export {ProtoChangeDetector, DynamicProtoChangeDetector, JitProtoChangeDetector, BindingRecord}
from './src/change_detection/proto_change_detector';
export {DynamicChangeDetector}
from './src/change_detection/dynamic_change_detector';
export * from './src/change_detection/pipes/pipe_registry';
export {Locals} from './src/change_detection/parser/locals';
export {ExpressionChangedAfterItHasBeenChecked, ChangeDetectionError} from './src/change_detection/exceptions';
export {ProtoChangeDetector, ChangeDispatcher, ChangeDetector, ChangeDetection} from './src/change_detection/interfaces';
export {CHECK_ONCE, CHECK_ALWAYS, DETACHED, CHECKED, ON_PUSH, DEFAULT} from './src/change_detection/constants';
export {DynamicProtoChangeDetector, JitProtoChangeDetector} from './src/change_detection/proto_change_detector';
export {BindingRecord} from './src/change_detection/binding_record';
export {DirectiveIndex, DirectiveRecord} from './src/change_detection/directive_record';
export {DynamicChangeDetector} from './src/change_detection/dynamic_change_detector';
export {ChangeDetectorRef} from './src/change_detection/change_detector_ref';
export {PipeRegistry} from './src/change_detection/pipes/pipe_registry';
export {uninitialized} from './src/change_detection/change_detection_util';
export * from './src/change_detection/pipes/pipe';
import {ProtoChangeDetector, DynamicProtoChangeDetector, JitProtoChangeDetector}
from './src/change_detection/proto_change_detector';
import {PipeRegistry} from './src/change_detection/pipes/pipe_registry';
import {ArrayChangesFactory} from './src/change_detection/pipes/array_changes';
import {KeyValueChangesFactory} from './src/change_detection/pipes/keyvalue_changes';
import {NullPipeFactory} from './src/change_detection/pipes/null_pipe';
export class ChangeDetection {
createProtoChangeDetector(name:string):ProtoChangeDetector{
// TODO: this should be abstract, once supported in AtScript
return null;
}
}
export var defaultPipes = {
"iterableDiff" : [
new ArrayChangesFactory(),
new NullPipeFactory()
],
"keyValDiff" : [
new KeyValueChangesFactory(),
new NullPipeFactory()
]
};
export class DynamicChangeDetection extends ChangeDetection {
registry:PipeRegistry;
constructor(registry:PipeRegistry) {
super();
this.registry = registry;
}
createProtoChangeDetector(name:string):ProtoChangeDetector{
return new DynamicProtoChangeDetector(this.registry);
}
}
export class JitChangeDetection extends ChangeDetection {
registry:PipeRegistry;
constructor(registry:PipeRegistry) {
super();
this.registry = registry;
}
createProtoChangeDetector(name:string):ProtoChangeDetector{
return new JitProtoChangeDetector(this.registry);
}
}
var _registry = new PipeRegistry(defaultPipes);
export var dynamicChangeDetection = new DynamicChangeDetection(_registry);
export var jitChangeDetection = new JitChangeDetection(_registry);
export {WrappedValue, Pipe} from './src/change_detection/pipes/pipe';
export {
defaultPipes, DynamicChangeDetection, JitChangeDetection, defaultPipeRegistry
} from './src/change_detection/change_detection';

View File

@ -1,13 +1,27 @@
/**
* @module
* @public
* @description
* Define angular core API here.
*/
export * from './src/core/annotations/visibility';
export * from './src/core/compiler/interfaces';
export * from './src/core/annotations/template';
export * from './src/core/annotations/view';
export * from './src/core/application';
export * from './src/core/application_tokens';
export * from './src/core/annotations/di';
export * from './src/core/compiler/query_list';
export * from './src/core/compiler/compiler';
export * from './src/core/compiler/template_loader';
export * from './src/core/compiler/view';
export * from './src/core/compiler/view_container';
export * from './src/core/compiler/binding_propagation_config';
// TODO(tbosch): remove this once render migration is complete
export * from './src/render/dom/compiler/template_loader';
export * from './src/render/dom/shadow_dom/shadow_dom_strategy';
export * from './src/render/dom/shadow_dom/native_shadow_dom_strategy';
export * from './src/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy';
export * from './src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
export * from './src/core/compiler/dynamic_component_loader';
export {ViewRef, ProtoViewRef} from './src/core/compiler/view_ref';
export {ViewContainerRef} from './src/core/compiler/view_container_ref';
export {ElementRef} from './src/core/compiler/element_ref';
export * from './src/core/dom/element';

View File

@ -1,7 +0,0 @@
export {Inject, InjectPromise, InjectLazy, Injectable, Optional, DependencyAnnotation} from './src/di/annotations';
export {Injector} from './src/di/injector';
export {Binding, Dependency, bind} from './src/di/binding';
export {Key, KeyRegistry} from './src/di/key';
export {KeyMetadataError, NoProviderError, ProviderError, AsyncBindingError, CyclicDependencyError,
InstantiationError, InvalidBindingError, NoAnnotationError} from './src/di/exceptions';
export {OpaqueToken} from './src/di/opaque_token';

27
modules/angular2/di.ts Normal file
View File

@ -0,0 +1,27 @@
/**
* @module
* @public
* @description
* The `di` module provides dependency injection container services.
*/
export * from './src/di/annotations';
export * from './src/di/decorators';
export {Injector} from './src/di/injector';
export {Binding, ResolvedBinding, Dependency, bind} from './src/di/binding';
export {Key, KeyRegistry} from './src/di/key';
export {
NoBindingError,
AbstractBindingError,
AsyncBindingError,
CyclicDependencyError,
InstantiationError,
InvalidBindingError,
NoAnnotationError
} from './src/di/exceptions';
export {OpaqueToken} from './src/di/opaque_token';
// HACK: workaround for Traceur behavior.
// It expects all transpiled modules to contain this marker.
// TODO: remove this when we no longer use traceur
export var __esModule = true;

7
modules/angular2/di_annotations.js vendored Normal file
View File

@ -0,0 +1,7 @@
/**
* @module
* @public
* @description
* Annotations which control how the dependencies are resolved by the {@link Injector}.
*/

7
modules/angular2/di_errors.js vendored Normal file
View File

@ -0,0 +1,7 @@
/**
* @module
* @public
* @description
* Errors thrown by the {@link Injector}.
*/

View File

@ -1,4 +1,12 @@
export * from './src/directives/foreach';
/**
* @module
* @public
* @description
* Common directives shipped with Angualr.
*/
export * from './src/directives/class';
export * from './src/directives/for';
export * from './src/directives/if';
export * from './src/directives/non_bindable';
export * from './src/directives/switch';

View File

@ -5,7 +5,7 @@ projected to DOM as well as which DOM events should invoke which methods on the
syntax which is core to Angular and allows for data-binding, event-binding, template-instantiation.
The design of the template syntax has these properties:
* All data-binding expressions are easily identifiable. (i.e. there is never an ambiguity whether the value should be
interpreted as string literal or as an expression.)
@ -187,7 +187,7 @@ Example:
<pre>
```
<ul>
<li template="foreach: #item in items">
<li template="for: #item of items">
{{item}}
</li>
</ul>
@ -201,8 +201,8 @@ Example:
<pre>
```
<ul>
<template def-foreach:"item"
bind-foreach-in="items">
<template def-for:"item"
bind-for-in="items">
<li>
{{item}}
</li>
@ -221,8 +221,8 @@ Example:
<pre>
```
<template #foreach="item"
[foreach-in]="items">
<template #for="item"
[for-in]="items">
_some_content_to_repeat_
</template>
```
@ -234,8 +234,8 @@ Example:
Example:
<pre>
```
<template def-foreach="item"
bind-foreach-in="items">
<template def-for="item"
bind-for-in="items">
_some_content_to_repeat_
</template>
```
@ -282,7 +282,7 @@ Key points:
* The binding is to the element property not the element attribute.
* To prevent custom element from accidentally reading the literal `expression` on the title element, the attribute name
is escaped. In our case the `title` is escaped to `[title]` through the addition of square brackets `[]`.
* A binding value (in this case `user.firstName` will always be an expression, never a string literal)
* A binding value (in this case `user.firstName` will always be an expression, never a string literal).
NOTE: Unlike Angular v1, Angular v2 binds to properties of elements rather than attributes of elements. This is
done to better support custom elements, and to allow binding for values other than strings.
@ -372,8 +372,8 @@ Where:
inserted. The template can be defined implicitly with `template` attribute, which turns the current element into
a template, or explicitly with `<template>` element. Explicit declaration is longer, but it allows for having
templates which have more than one root DOM node.
* `viewport` is required for templates. The Viewport directive is responsible for deciding when
and in which order should child views be inserted into this location. An Viewport directive usually has one or
* `viewport` is required for templates. The directive is responsible for deciding when
and in which order should child views be inserted into this location. Such a directive usually has one or
more bindings and can be represented as either `viewport-directive-bindings` or
`viewport-directive-microsyntax` on `template` element or attribute. See template microsyntax for more details.
@ -387,7 +387,7 @@ Hello {{user}}!
</div>
```
In the above example the `if` Viewport determines whether the child view (an instance of the child template) should be
In the above example the `if` directive determines whether the child view (an instance of the child template) should be
inserted into the root view. The `if` makes this decision based on if the `isAdministrator` binding is true.
The above example is in the short form, for better clarity let's rewrite it in the canonical form, which is functionally
@ -402,28 +402,26 @@ Hello {{user}}!
</template>
```
NOTE: Only Viewport directives can be placed on the template element. (Decorators and Components are not allowed.)
### Template Microsyntax
Often times it is necessary to encode a lot of different bindings into a template to control how the instantiation
of the templates occurs. One such example is `foreach`.
of the templates occurs. One such example is `for`.
```
<form #foo=form>
</form>
<ul>
<template foreach #person [in]="people" #i="index">
<template for #person [in]="people" #i="index">
<li>{{i}}. {{person}}<li>
</template>
</ul>
```
Where:
* `foreach` triggers the foreach directive.
* `[in]="people"` binds an iterable object to the `foreach` controller.
* `#person` exports the implicit `foreach` item.
* `for` triggers the for directive.
* `[in]="people"` binds an iterable object to the `for` controller.
* `#person` exports the implicit `for` item.
* `#i=index` exports item index as `i`.
The above example is explicit but quite wordy. For this reason in most situations a short hand version of the
@ -431,7 +429,7 @@ syntax is preferable.
```
<ul>
<li template="foreach; #person; in=people; #i=index;">{{i}}. {{person}}<li>
<li template="for; #person; of=people; #i=index;">{{i}}. {{person}}<li>
</ul>
```
@ -441,19 +439,28 @@ which allows us to further shorten the text.
```
<ul>
<li template="foreach #person in people #i=index">{{i}}. {{person}}<li>
<li template="for #person of people #i=index">{{i}}. {{person}}<li>
</ul>
```
We can also optionally use `var` instead of `#` and add `:` to `foreach` which creates the following recommended
microsyntax for `foreach`.
We can also optionally use `var` instead of `#` and add `:` to `for` which creates the following recommended
microsyntax for `for`.
```
<ul>
<li template="foreach: var person in people; var i=index">{{i}}. {{person}}<li>
<li template="for: var person of people; var i=index">{{i}}. {{person}}<li>
</ul>
```
Finally, we can move the `for` keyword to the left hand side and prefix it with `*` as so:
```
<ul>
<li *for="var person of people; var i=index">{{i}}. {{person}}<li>
</ul>
```
The format is intentionally defined freely, so that developers of directives can build an expressive microsyntax for
their directives. The following code describes a more formal definition.
@ -480,7 +487,7 @@ Where
NOTE: the `template` attribute must be present to make it clear to the user that a sub-template is being created. This
goes along the philosophy that the developer should be able to reason about the template without understanding the
goes along with the philosophy that the developer should be able to reason about the template without understanding the
semantics of the instantiator directive.
@ -503,13 +510,14 @@ Binding events allows wiring events from DOM (or other components) to the Angula
Where:
* `some-element` Any element which can generate DOM events (or has an angular directive which generates the event).
* `some-event` (escaped with `()` or `bind-`) is the name of the event `some-event`. In this case the
* `some-event` (escaped with `()` or `on-`) is the name of the event `some-event`. In this case the
dash-case is converted into camel-case `someEvent`.
* `statement` is a valid statement (as defined in section below).
If the execution of the statement returns `false`, then `preventDefault`is applied on the DOM event.
By default, angular only listens to the element on the event, and ignores events which bubble. To listen to bubbled
events (as in the case of clicking on any child) use the bubble option (`(^event)` or `on-bubble-event`) as shown
bellow.
events (as in the case of clicking on any child) use the bubble option (`(event)` or `on-bubble-event`) as shown
below.
<table>
<tr>

View File

@ -6,17 +6,12 @@ Directives are the cornerstone of an Angular application. We use Directives to b
Angular applications do not have a main method. Instead they have a root Component. Dependency Injection then assembles the directives into a working Angular application.
There are three different kinds of directives (described in more detail in later sections).
1. *Decorators*: can be placed on any DOM element and can be combined with other directives.
2. *Components*: Components have an encapsulated view and can configure injectors.
3. *Viewport*: is responsible for adding or removing child views in a parent view. (i.e. foreach, if)
Directives with an encapsulated view and an optional injector are called *Components*.
## CSS Selectors
Decorators are instantiated whenever the decorator CSS selector matches the DOM structure.
Directives are instantiated whenever the CSS selector matches the DOM structure.
Angular supports these CSS selector constructs:
* Element name: `name`
@ -29,7 +24,7 @@ Angular supports these CSS selector constructs:
Angular does not support these (and any CSS selector which crosses element boundaries):
* Descendant: `body div`
* Direct descendant: `body > div`
* Direct descendant: `body > div`
* Adjacent: `div + table`
* Sibling: `div ~ table`
* Wildcard: `*`
@ -50,33 +45,33 @@ These CSS selectors will match:
CSS Selectors can be combined:
* `input[type=text]`: Triggers on element name `input` which is of `type` `text`.
* `input[type=text], textarea`: triggers on element name `input` which is of `type` `text` or element name `textarea`
* `input[type=text], textarea`: triggers on element name `input` which is of `type` `text` or element name `textarea`.
## Decorators
## Directives
The simplest kind of directive is a decorator. Directives are usefull for encapsulating behavior.
* Multiple decorators can be placed on a single element.
* Decorators do not introduce new evaluation context.
* Decorators are registered through the `@Decorator` meta-data annotation.
* Directives do not introduce new evaluation context.
* Directives are registered through the `@Directive` meta-data annotation.
Here is a trivial example of a tooltip decorator. The directive will log a tooltip into the console on every time mouse enters a region:
```
@Decorator({
@Directive({
selector: '[tooltip]', // CSS Selector which triggers the decorator
bind: { // List which properties need to be bound
text: 'tooltip' // - DOM element tooltip property should be
properties: { // List which properties need to be bound
text: 'tooltip' // - DOM element tooltip property should be
}, // mapped to the directive text property.
event: { // List which events need to be mapped.
mouseover: 'show' // - Invoke the show() method every time
hostListeners: { // List which events need to be mapped.
mouseover: 'show' // - Invoke the show() method every time
} // the mouseover event is fired.
})
class Form { // Directive controller class, instantiated
// when CSS matches.
text:string; // text property on the Decorator Controller.
text:string; // text property on the Directive Controller.
show(event) { // Show method which implements the show action.
console.log(this.text);
@ -112,23 +107,23 @@ Example of a component:
```
@Component({ | Component annotation
selector: 'pane', | CSS selector on <pane> element
bind: { | List which property need to be bound
properties: { | List which property need to be bound
'title': 'title', | - title mapped to component title
'open': 'open' | - open attribute mapped to component's open property
}, |
}) |
@Template({ | Template annotation
url: 'pane.html' | - URL of template HTML
@View({ | View annotation
templateUrl: 'pane.html' | - URL of template HTML
}) |
class Pane { | Component controller class
title:string; | - title property
title:string; | - title property
open:boolean;
constructor() {
this.title = '';
this.open = true;
}
// Public API
toggle() => this.open = !this.open;
open() => this.open = true;
@ -140,7 +135,7 @@ class Pane { | Component controller class
```
<div class="outer">
<h1>{{title}}</h1>
<div class="inner" [hidden]="!visible">
<div class="inner" [hidden]="!open">
<content></content>
</div>
</div>
@ -163,39 +158,39 @@ Example of usage:
## Viewport
## Directives that use a ViewContainer
Viewport is a directive which can control instantiation of child views which are then inserted into the DOM. (Examples are `if` and `foreach`.)
Directives that use a ViewContainer can control instantiation of child views which are then inserted into the DOM. (Examples are `if` and `for`.)
* Viewports can only be placed on `<template>` elements (or the short hand version which uses `<element template>` attribute.)
* Only one viewport can be present per DOM template element.
* The viewport is created over the `template` element. This is known as the `ViewContainer`.
* Viewport can insert child views into the `ViewContainer`. The child views show up as siblings of the `Viewport` in the DOM.
* Every `template` element creates a `ProtoView` which can be used to create Views via the ViewContainer.
* The child views show up as siblings of the directive in the DOM.
>> TODO(misko): Relationship with Injection
>> TODO(misko): Instantiator can not be injected into child Views
```
@Viewport({
@Directive({
selector: '[if]',
bind: {
properties: {
'condition': 'if'
}
})
export class If {
viewContainer: ViewContainer;
viewContainer: ViewContainerRef;
protoViewRef: ProtoViewRef;
view: View;
constructor(viewContainer: ViewContainer) {
constructor(viewContainer: ViewContainerRef, protoViewRef: ProtoViewRef) {
this.viewContainer = viewContainer;
this.protoViewRef = protoViewRef;
this.view = null;
}
set condition(value) {
if (value) {
if (this.view === null) {
this.view = this.viewContainer.create();
this.view = this.viewContainer.create(protoViewRef);
}
} else {
if (this.view !== null) {
@ -213,37 +208,37 @@ Dependency Injection (DI) is a key aspect of directives. DI allows directives to
When Angular directives are instantiated, the directive can ask for other related directives to be injected into it. By assembling the directives in different order and subtypes the application behavior can be controlled. A good mental model is that the DOM structure controls the directive instantiation graph.
Directive instantiation is triggered by the directive CSS selector matching the DOM structure. The directive in its constructor can ask for other directives or application services. When asking for directives the dependency is locating by following the DOM hierarchy and if not found using the application level injector.
Directive instantiation is triggered by the directive CSS selector matching the DOM structure. In a directive's constructor, it can ask for other directives or application services. When asking for directives, the dependency is attempted to be located by its DOM hierarchy first, then if not found, by using the application level injector.
To better understand the kinds of injections which are supported in Angular we have broken them down into use case examples.
### Injecting Services
Service injection is the most straight forward kind of injection which Angular supports. It involves a component configuring the `services` and then letting the directive ask for the configured service.
Service injection is the most straight forward kind of injection which Angular supports. It involves a component configuring the `injectables` and then letting the directive ask for the configured service.
This example illustrates how to inject `MyService` into `House` directive.
```
class MyService {} | Assume a service which needs to be injected
class MyService {} | Assume a service which needs to be injected
| into a directive.
|
@Component({ | Assume a top level application component which
@Component({ | Assume a top level application component which
selector: 'my-app', | configures the services to be injected.
services: [MyService] |
injectables: [MyService] |
}) |
@Template({ | Assume we have a template that needs to be
url: 'my_app.html', | configured with directives to be injected.
directives: [House] |
@View({ | Assume we have a template that needs to be
templateUrl: 'my_app.html', | configured with directives to be injected.
directives: [House] |
}) |
class MyApp {} |
|
@Decorator({ | This is the directive into which we would like
@Directive({ | This is the directive into which we would like
selector: '[house]' | to inject the MyService.
}) |
class House { |
constructor(myService:MyService) { | Notice that in the constructor we can simply
constructor(myService:MyService) { | Notice that in the constructor we can simply
} | ask for MyService.
} |
@ -252,7 +247,7 @@ class House { |
Assume the following DOM structure for `my_app.html`:
```
<div house> | The house attribute triggers the creation of the House directive.
<div house> | The house attribute triggers the creation of the House directive.
</div> | This is equivalent to:
| new House(injector.get(MyService));
```
@ -260,58 +255,58 @@ Assume the following DOM structure for `my_app.html`:
### Injecting other Directives
Injecting other directives into directives follows a similar mechanism as injecting services, but with added constraint of visibility governed by DOM structure.
Injecting other directives into directives follows a similar mechanism as injecting services into directives, but with added constraint of visibility governed by DOM structure.
There are five kinds of visibilities:
* (no annotation): Inject dependant directives only if they are on the current element.
* (no annotation): Inject dependant directives only if they are on the current element.
* `@ancestor`: Inject a directive if it is at any element above the current element.
* `@parent`: Inject a directive which is direct parent of the current element.
* `@parent`: Inject a directive which is a direct parent of the current element.
* `@child`: Inject a list of direct children which match a given type. (Used with `Query`)
* `@descendant`: Inject a list of any children which match a given type. (Used with `Query`)
NOTE: if the injection constraint can not be satisfied by the current visibility constraint, then it is forward to the normal injector which may provide a default value for the directive or it may throw an error.
NOTE: if the injection constraint can not be satisfied by the current visibility constraint, then it is forwarded to the normal injector which either provides a default value for the directive or throws an error.
Here is an example of the kinds of injections which can be achieved:
```
@Component({ |
selector: 'my-app', |
template: new TemplateConfig({ |
url: 'my_app.html', |
directives: [Form, FieldSet, |
Field, Primary] |
}) |
selector: 'my-app' |
}) |
@View({ |
templateUrl: 'my_app.html', |
directives: [Form, FieldSet, |
Field, Primary] |
}) |
class MyApp {} |
|
@Decorator({ selector: 'form' }) |
@Directive({ selector: 'form' }) |
class Form { |
constructor( |
@descendant sets:Query<FieldSet> |
) { |
} |
) { |
} |
} |
|
@Decorator({ selector: 'fieldset' }) |
@Directive({ selector: 'fieldset' }) |
class FieldSet { |
constructor( |
@child sets:Query<Field> |
) { ... } |
) { ... } |
} |
|
@Decorator({ selector: 'field' }) |
@Directive({ selector: 'field' }) |
class Field { |
constructor( |
@ancestor field:Form, |
@parent field:FieldSet, |
) { ... } |
) { ... } |
} |
|
@Decorator({ selector: '[primary]'}) |
@Directive({ selector: '[primary]'}) |
class Primary { |
constructor(field:Field ) { ... } |
constructor(field:Field ) { ... } |
} |
```
@ -322,17 +317,75 @@ Assume the following DOM structure for `my_app.html`:
<fieldset> |
<field primary></field> |
<field></field> |
</div> |
</fieldset> |
</form> |
</fieldset> |
</div> |
</form> |
```
#### Shadow DOM effects on Directive DI
### Shadow DOM effects on Dependency Injection
Shadow DOM provides an encapsulation for components, so as a general rule it does not allow directive injections to cross the shadow DOM boundaries. To remedy this, declaritively specify the required component as an injectable.
Shadow DOM provides an encapsulation for components, so as a general rule it does not allow directive injections to cross the shadow DOM boundaries.
```
@Component({
selector: '[kid]',
injectables: []
})
@View({
templateUrl: 'kid.html',
directives: []
})
class Kid {
constructor(
@Parent() dad:Dad,
@Optional() grandpa:Grandpa
) {
this.name = 'Billy';
this.dad = dad.name;
this.grandpa = grandpa.name;
}
}
@Component({
selector: '[dad]',
injectables: [Grandpa]
})
@View({
templateUrl: 'dad.html',
directives: [Kid]
})
class Dad {
constructor(@Parent() dad:Grandpa) {
this.name = 'Joe Jr';
this.dad = dad.name;
console.log(dad)
}
}
@Component({
selector: '[grandpa]',
injectables: []
})
@View({
templateUrl: 'grandpa.html',
directives: [Dad]
})
class Grandpa {
constructor() {
this.name = 'Joe';
}
}
```
Assume the following DOM structure for `grandpa.html`: The Dad has access to the Grandpa.
```
Name: {{name}}: <br> Children: <div dad></div>
```
Assume the following DOM structure for `dad.html`: Here the rendered Kid will also have access to Grandpa.
```
Name: {{name}}: <br> Dad: {{dad}} <br> Children: <div kid></div>
```
## Further Reading

View File

@ -2,24 +2,24 @@
## Overview
This document explains the concept of a View.
A View is a core primitive used by angular to render the DOM tree.
A ViewPort is location in a View which can accept child Views.
Every ViewPort has an associated ViewContainer than can contain any number of child Views.
This document explains the concept of a View.
A View is a core primitive used by angular to render the DOM tree.
A ViewContainer is location in a View which can accept child Views.
Every ViewContainer has an associated ViewContainerRef than can contain any number of child Views.
Views form a tree structure which mimics the DOM tree.
* View is a core rendering construct. A running application is just a collection of Views which are
nested in a tree like structure. The View tree is a simplified version of the DOM tree. A View can
have a single DOM Element or large DOM structures. The key is that the DOM tree in the View can
* View is a core rendering construct. A running application is just a collection of Views which are
nested in a tree like structure. The View tree is a simplified version of the DOM tree. A View can
have a single DOM Element or large DOM structures. The key is that the DOM tree in the View can
not undergo structural changes (only property changes).
* Views represent a running instance of a DOM Template. This implies that while elements in a View
can change properties, they can not change structurally. (Structural changes such as, adding or
* Views represent a running instance of a DOM View. This implies that while elements in a View
can change properties, they can not change structurally. (Structural changes such as, adding or
removing elements requires adding or removing child Views into ViewContainers).
* View can have zero or more ViewPorts. A ViewPort is a marker in the DOM which allows
* View can have zero or more ViewContainers. A ViewContainer is a marker in the DOM which allows
the insertion of child Views.
* Views are created from a ProtoView. A ProtoView is a compiled DOM Template which is efficient at
* Views are created from a ProtoView. A ProtoView is a compiled DOM View which is efficient at
creating Views.
* View contains a context object. The context represents the object instance against which all
* View contains a context object. The context represents the object instance against which all
expressions are evaluated.
* View contains a ChangeDetector for looking for detecting changes to the model.
* View contains ElementInjector for creating Directives.
@ -40,7 +40,7 @@ class Greeter {
}
```
And assume following HTML Template:
And assume following HTML View:
```
<div>
@ -51,9 +51,9 @@ And assume following HTML Template:
</div>
```
The above template is compiled by the Compiler to create a ProtoView. The ProtoView is then used to
create an instance of the View. The instantiation process involves cloning the above template and
locating all of the elements which contain bindings and finally instantiating the Directives
The above template is compiled by the Compiler to create a ProtoView. The ProtoView is then used to
create an instance of the View. The instantiation process involves cloning the above template and
locating all of the elements which contain bindings and finally instantiating the Directives
associated with the template. (See compilation for more details.)
```
@ -81,16 +81,16 @@ Note:
* View knows which expressions need to be watched.
* View knows what needs to be updated if the watched expression changes.
* All DOM elements are owned by single instance of the view.
* The structure of the DOM can not change during runtime. To allow structural changes to the DOM we need
* The structure of the DOM can not change during runtime. To allow structural changes to the DOM we need
to understand Composed View.
## Composed View
An important part of an application is to be able to change the DOM structure to render data for the
user. In Angular this is done by inserting child views into the ViewPort.
An important part of an application is to be able to change the DOM structure to render data for the
user. In Angular this is done by inserting child views into the ViewContainer.
Let's start with a Template such as:
Let's start with a View such as:
```
<ul>
@ -108,7 +108,7 @@ and
```
<ul> | protoViewA(someContext)
<template></template> | protoViewA(someContext): new ProtoViewPort(protoViewB)
<template></template> | protoViewA(someContext): protoViewB
</ul> | protoViewA(someContext)
```
@ -119,49 +119,49 @@ The next step is to compose these two ProtoViews into an actual view which is re
```
<ul> | viewA(someContext)
<template></template> | viewA(someContext): new Foreach(new ViewPort(protoViewB))
<template></template> | viewA(someContext): new Foreach(new ViewContainer(protoViewB))
</ul> | viewA(someContext)
```
*Step2:* Instantiate `Foreach` directive which will receive the `ViewContainer`. (The ViewContainer
*Step2:* Instantiate `Foreach` directive which will receive the `ViewContainerRef`. (The ViewContainerRef
has a reference to `protoViewA`).
*Step3:* As the `Foreach` directive unrolls it asks the `ViewContainer` to instantiate `protoViewB` and insert
it after the `ViewPort` anchor. This is repeated for each `person` in `people`. Notice that
*Step3:* As the `Foreach` directive unrolls it asks the `ViewContainerRef` to instantiate `protoViewB` and insert
it after the `ViewContainer` anchor. This is repeated for each `person` in `people`. Notice that
```
<ul> | viewA(someContext)
<template></template> | viewA(someContext): new Foreach(new ViewPort(protoViewB))
<template></template> | viewA(someContext): new Foreach(new ViewContainer(protoViewB))
<li>{{person}}</li> | viewB0(locals0(someContext))
<li>{{person}}</li> | viewB1(locals0(someContext))
</ul> | viewA(someContext)
```
*Step4:* All of the bindings in the child Views are updated. Notice that in the case of `Foreach`
the evaluation context for the `viewB0` and `viewB1` are `locals0` and `locals1` respectively.
Locals allow the introduction of new local variables visible only within the scope of the View, and
*Step4:* All of the bindings in the child Views are updated. Notice that in the case of `Foreach`
the evaluation context for the `viewB0` and `viewB1` are `locals0` and `locals1` respectively.
Locals allow the introduction of new local variables visible only within the scope of the View, and
delegate any unknown references to the parent context.
```
<ul> | viewA
<template></template> | viewA: new Foreach(new ViewPort(protoViewB))
<template></template> | viewA: new Foreach(new ViewContainer(protoViewB))
<li>Alice</li> | viewB0
<li>Bob</li> | viewB1
</ul> | viewA
```
Each View can have zero or more ViewPorts. By inserting and removing child Views to and from the
ViewContainers, the application can mutate the DOM structure to any desirable state. A View may contain
individual nodes or a complex DOM structure. The insertion points for the child Views, known as
ViewContainers, contain a DOM element which acts as an anchor. The anchor is either a `template` or
a `script` element depending on your browser. It is used to identify where the child Views will be
Each View can have zero or more ViewContainers. By inserting and removing child Views to and from the
ViewContainers, the application can mutate the DOM structure to any desirable state. A View may contain
individual nodes or a complex DOM structure. The insertion points for the child Views, known as
ViewContainers, contain a DOM element which acts as an anchor. The anchor is either a `template` or
a `script` element depending on your browser. It is used to identify where the child Views will be
inserted.
## Component Views
A View can also contain Components. Components contain Shadow DOM for encapsulating their internal
rendering state. Unlike ViewPorts which can contain zero or more Views, the Component always contains
A View can also contain Components. Components contain Shadow DOM for encapsulating their internal
rendering state. Unlike ViewContainers which can contain zero or more Views, the Component always contains
exactly one Shadow View.
```
@ -194,7 +194,7 @@ class Greeter {
}
```
And assume the following HTML Template:
And assume the following HTML View:
```
<div> | viewA(greeter)
@ -205,7 +205,7 @@ And assume the following HTML Template:
</div> | viewA(greeter)
```
The above UI is built using a single View, and hence a single context `greeter`. It can be expressed
The above UI is built using a single View, and hence a single context `greeter`. It can be expressed
in this pseudo-code.
```
@ -215,15 +215,15 @@ var greeter = new Greeter();
The View contains two bindings:
1. `greeting`: This is bound to the `greeting` property on the `Greeter` instance.
2. `name.value`: This poses a problem. There is no `name` property on the `Greeter` instance. To solve
2. `name.value`: This poses a problem. There is no `name` property on the `Greeter` instance. To solve
this we wrap the `Greeter` instance in the `Local` instance like so:
```
var greeter = new Locals(new Greeter(), {name: ref_to_input_element })
```
By wrapping the `Greeter` instance into the `Locals` we allow the view to introduce variables which
are in addition to the `Greeter` instance. During the resolution of the expressions we first check
By wrapping the `Greeter` instance into the `Locals` we allow the view to introduce variables which
are in addition to the `Greeter` instance. During the resolution of the expressions we first check
the locals, and then the `Greeter` instance.
@ -233,14 +233,14 @@ the locals, and then the `Greeter` instance.
Views transition through a particular set of states:
1. View is created from the ProtoView.
2. View can be attached to an existing ViewContainer.
3. Upon attaching View to the ViewContainer the View needs to be hydrated. The hydration process
2. View can be attached to an existing ViewContainerRef.
3. Upon attaching View to the ViewContainerRef the View needs to be hydrated. The hydration process
involves instantiating all of the Directives associated with the current View.
4. At this point the view is ready and renderable. Multiple changes can be delivered to the
4. At this point the view is ready and renderable. Multiple changes can be delivered to the
Directives from the ChangeDetection.
5. At some point the View can be removed. At this point all of the directives are destroyed during
5. At some point the View can be removed. At this point all of the directives are destroyed during
the dehydration process and the view becomes inactive.
6. The View has to wait until it is detached from the DOM. The delay in detaching could be caused
6. The View has to wait until it is detached from the DOM. The delay in detaching could be caused
because an animation is animating the view away.
7. After the View is detached from the DOM it is ready to be reused. The view reuse allows the
7. After the View is detached from the DOM it is ready to be reused. The view reuse allows the
application to be faster in subsequent renderings.

View File

@ -43,7 +43,7 @@ class Car {
}
}
var inj = new Injector([
var inj = Injector.resolveAndCreate([
bind(Car).toClass(Car),
bind(Engine).toClass(Engine)
]);
@ -86,7 +86,7 @@ To avoid bugs make sure the registered objects have side-effect-free constructor
Injectors are hierarchical.
```
var child = injector.createChild([
var child = injector.resolveAndCreateChild([
bind(Engine).toClass(TurboEngine)
]);
@ -99,21 +99,21 @@ var car = child.get(Car); // uses the Car binding from the parent injector and E
You can bind to a class, a value, or a factory. It is also possible to alias existing bindings.
```
var inj = new Injector([
var inj = Injector.resolveAndCreate([
bind(Car).toClass(Car),
bind(Engine).toClass(Engine)
]);
var inj = new Injector([
var inj = Injector.resolveAndCreate([
Car, // syntax sugar for bind(Car).toClass(Car)
Engine
]);
var inj = new Injector([
var inj = Injector.resolveAndCreate([
bind(Car).toValue(new Car(new Engine()))
]);
var inj = new Injector([
var inj = Injector.resolveAndCreate([
bind(Car).toFactory((e) => new Car(e), [Engine]),
bind(Engine).toFactory(() => new Engine())
]);
@ -122,7 +122,7 @@ var inj = new Injector([
You can bind any token.
```
var inj = new Injector([
var inj = Injector.resolveAndCreate([
bind(Car).toFactory((e) => new Car(), ["engine!"]),
bind("engine!").toClass(Engine)
]);
@ -131,7 +131,7 @@ var inj = new Injector([
If you want to alias an existing binding, you can do so using `toAlias`:
```
var inj = new Injector([
var inj = Injector.resolveAndCreate([
bind(Engine).toClass(Engine),
bind("engine!").toAlias(Engine)
]);
@ -152,7 +152,7 @@ The `someFactory` function does not have to know that it creates an object for `
Injector can create binding on the fly if we enable default bindings.
```
var inj = new Injector([], {defaultBindings: true});
var inj = Injector.resolveAndCreate([], {defaultBindings: true});
var car = inj.get(Car); //this works as if `bind(Car).toClass(Car)` and `bind(Engine).toClass(Engine)` were present.
```
@ -226,7 +226,7 @@ class UserController {
}
}
var inj = new Injector([
var inj = Injector.resolveAndCreate([
bind(UserList).toAsyncFactory(() => fetchUsersUsingHttp().then((u) => new UserList(u))),
UserController
])
@ -252,7 +252,7 @@ class UserController {
}
}
var inj = new Injector([
var inj = Injector.resolveAndCreate([
bind(UserList).toAsyncFactory(() => fetchUsersUsingHttp().then((u) => new UserList(u))),
UserController
])
@ -276,7 +276,7 @@ class UserController {
constructor(ul:UserList){}
}
var inj = new Injector([UserList, UserController]);
var inj = Injector.resolveAndCreate([UserList, UserController]);
var ctrl:UserController = inj.get(UserController);
```
@ -290,7 +290,7 @@ class UserController {
constructor(@InjectPromise(UserList) ul){}
}
var inj = new Injector([UserList, UserController]);
var inj = Injector.resolveAndCreate([UserList, UserController]);
var ctrl:UserController = inj.get(UserController);
// UserController responsible for dealing with asynchrony.
expect(ctrl.ul).toBePromise();
@ -306,7 +306,7 @@ class UserController {
constructor(ul:UserList){}
}
var inj = new Injector([
var inj = Injector.resolveAndCreate([
bind(UserList).toAsyncFactory(() => fetchUsersUsingHttp().then((u) => new UserList(u))),
UserController
]);
@ -316,8 +316,8 @@ ctrlPromise.then((ctrl) {
expect(ctrl).toBeAnInstanceOf(UserController);
expect(ctrl.ul).toBeAnInstanceOf(UserList);
});
// No synchronous provider for UserList, results in a NoProviderError.
expect(() => inj.get(UserController)).toThrow(new NoProviderError(...));
// No synchronous provider for UserList, results in a NoBindingError.
expect(() => inj.get(UserController)).toThrow(new NoBindingError(...));
```
@ -331,7 +331,7 @@ class UserController {
constructor(@InjectPromise(UserList) ul){}
}
var inj = new Injector([
var inj = Injector.resolveAndCreate([
bind(UserList).toAsyncFactory(() => fetchUsersUsingHttp().then((u) => new UserList(u))),
UserController
]);
@ -369,14 +369,14 @@ If we need a transient dependency, something that we want a new instance of ever
We can create a child injector:
```
var child = inj.createChild([MyClass]);
var child = inj.resolveAndCreateChild([MyClass]);
child.get(MyClass);
```
Or we can register a factory function:
```
var inj = new Injector([
var inj = Injector.resolveAndCreate([
bind('MyClassFactory').toFactory(dep => () => new MyClass(dep), [SomeDependency])
]);
@ -393,7 +393,7 @@ expect(instance1).not.toBe(instance2);
Most of the time we do not have to deal with keys.
```
var inj = new Injector([
var inj = Injector.resolveAndCreate([
bind(Engine).toFactory(() => new TurboEngine()) //the passed in token Engine gets mapped to a key
]);
var engine = inj.get(Engine); //the passed in token Engine gets mapped to a key
@ -404,7 +404,7 @@ Now, the same example, but with keys
```
var ENGINE_KEY = Key.get(Engine);
var inj = new Injector([
var inj = Injector.resolveAndCreate([
bind(ENGINE_KEY).toFactory(() => new TurboEngine()) // no mapping
]);
var engine = inj.get(ENGINE_KEY); // no mapping

View File

@ -1,5 +1,17 @@
/**
* @module
* @public
* @description
* This module is used for handling user input, by defining and building a {@link ControlGroup} that consists of
* {@link Control} objects, and mapping them onto the DOM. {@link Control} objects can then be used to read information
* from the form DOM elements.
*
* This module is not included in the `angular2` module; you must import the forms module explicitly.
*
*/
export * from './src/forms/model';
export * from './src/forms/directives';
export * from './src/forms/validators';
export * from './src/forms/validator_directives';
export * from './src/forms/form_builder';
export * from './src/forms/form_builder';

View File

@ -0,0 +1,3 @@
// Globals are provided by lang.dart in Dart.
// This file exists to prevent global.ts from being transpiled.
library angular2.globals;

View File

@ -0,0 +1,23 @@
/**
* This file contains declarations of global symbols we reference in our code
*/
declare var assert: any;
declare var global: Window;
type int = number;
interface List<T> extends Array<T> {}
interface Window {
Object: typeof Object;
Array: typeof Array;
Map: typeof Map;
Set: typeof Set;
Date: typeof Date;
RegExp: typeof RegExp;
JSON: typeof JSON;
Math: typeof Math;
assert: typeof assert;
gc(): void;
Reflect: any;
}

View File

@ -9,6 +9,7 @@
"dependencies": {
"traceur": "<%= packageJson.dependencies.traceur %>",
"rtts_assert": "<%= packageJson.version %>",
"rx": "<%= packageJson.dependencies['rx'] %>",
"zone.js": "<%= packageJson.dependencies['zone.js'] %>"
},
"devDependencies": <%= JSON.stringify(packageJson.devDependencies) %>

6
modules/angular2/pipes.js vendored Normal file
View File

@ -0,0 +1,6 @@
/**
* @module
* @public
* @description
* This module provides advanced support for extending change detection.
*/

View File

@ -7,13 +7,20 @@ authors:
description: Angular 2 for Dart - a web framework for modern web apps
homepage: <%= packageJson.homepage %>
environment:
sdk: '>=1.9.0-dev.8.0'
sdk: '>=1.10.0-dev.1.10 <2.0.0'
dependencies:
analyzer: '^0.22.4'
analyzer: '>=0.24.4 <0.26.0'
barback: '^0.15.2+2'
code_transformers: '^0.2.5'
code_transformers: '^0.2.8'
dart_style: '^0.1.3'
html5lib: '^0.12.0'
html: '^0.12.0'
logging: '>=0.9.0 <0.11.0'
source_span: '^1.0.0'
stack_trace: '^1.1.1'
dev_dependencies:
guinness: "^0.1.17"
transformers:
- angular2
- $dart2js:
commandLineOptions:
- --show-package-warnings

30
modules/angular2/router.js vendored Normal file
View File

@ -0,0 +1,30 @@
/**
* @module
* @public
* @description
* Maps application URLs into application states, to support deep-linking and navigation.
*/
export {Router} from './src/router/router';
export {RouterOutlet} from './src/router/router_outlet';
export {RouterLink} from './src/router/router_link';
export {RouteParams} from './src/router/instruction';
export * from './src/router/route_config_annotation';
export * from './src/router/route_config_decorator';
import {Router, RootRouter} from './src/router/router';
import {RouteRegistry} from './src/router/route_registry';
import {Pipeline} from './src/router/pipeline';
import {Location} from './src/router/location';
import {appComponentAnnotatedTypeToken} from './src/core/application_tokens';
import {bind} from './di';
export var routerInjectables:List = [
RouteRegistry,
Pipeline,
Location,
bind(Router).toFactory((registry, pipeline, location, meta) => {
return new RootRouter(registry, pipeline, location, meta.type);
}, [RouteRegistry, Pipeline, Location, appComponentAnnotatedTypeToken])
];

View File

@ -1,25 +1,40 @@
import {isPresent} from 'angular2/src/facade/lang';
import {List, ListWrapper} from 'angular2/src/facade/collection';
import {ChangeDetector, CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED} from './interfaces';
import {ChangeDetectorRef} from './change_detector_ref';
import {ChangeDetector} from './interfaces';
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants';
export class AbstractChangeDetector extends ChangeDetector {
children:List;
lightDomChildren:List;
shadowDomChildren:List;
parent:ChangeDetector;
mode:string;
ref:ChangeDetectorRef;
constructor() {
super();
this.children = [];
this.mode = CHECK_ALWAYS;
this.lightDomChildren = [];
this.shadowDomChildren = [];
this.ref = new ChangeDetectorRef(this);
this.mode = null;
}
addChild(cd:ChangeDetector) {
ListWrapper.push(this.children, cd);
ListWrapper.push(this.lightDomChildren, cd);
cd.parent = this;
}
removeChild(cd:ChangeDetector) {
ListWrapper.remove(this.children, cd);
ListWrapper.remove(this.lightDomChildren, cd);
}
addShadowDomChild(cd:ChangeDetector) {
ListWrapper.push(this.shadowDomChildren, cd);
cd.parent = this;
}
removeShadowDomChild(cd:ChangeDetector) {
ListWrapper.remove(this.shadowDomChildren, cd);
}
remove() {
@ -38,20 +53,37 @@ export class AbstractChangeDetector extends ChangeDetector {
if (this.mode === DETACHED || this.mode === CHECKED) return;
this.detectChangesInRecords(throwOnChange);
this._detectChangesInChildren(throwOnChange);
this._detectChangesInLightDomChildren(throwOnChange);
this.callOnAllChangesDone();
this._detectChangesInShadowDomChildren(throwOnChange);
if (this.mode === CHECK_ONCE) this.mode = CHECKED;
}
detectChangesInRecords(throwOnChange:boolean){}
callOnAllChangesDone(){}
_detectChangesInChildren(throwOnChange:boolean) {
var children = this.children;
for(var i = 0; i < children.length; ++i) {
children[i]._detectChanges(throwOnChange);
_detectChangesInLightDomChildren(throwOnChange:boolean) {
var c = this.lightDomChildren;
for(var i = 0; i < c.length; ++i) {
c[i]._detectChanges(throwOnChange);
}
}
_detectChangesInShadowDomChildren(throwOnChange:boolean) {
var c = this.shadowDomChildren;
for(var i = 0; i < c.length; ++i) {
c[i]._detectChanges(throwOnChange);
}
}
markAsCheckOnce() {
this.mode = CHECK_ONCE;
}
markPathToRootAsCheckOnce() {
var c = this;
while(isPresent(c) && c.mode != DETACHED) {

View File

@ -0,0 +1,68 @@
import {isPresent, isBlank} from 'angular2/src/facade/lang';
import {SetterFn} from 'angular2/src/reflection/types';
import {AST} from './parser/ast';
import {DirectiveIndex, DirectiveRecord} from './directive_record';
const DIRECTIVE="directive";
const ELEMENT="element";
const TEXT_NODE="textNode";
export class BindingRecord {
mode:string;
ast:AST;
implicitReceiver:any; //number | DirectiveIndex
elementIndex:number;
propertyName:string;
setter:SetterFn;
directiveRecord:DirectiveRecord;
constructor(mode:string, implicitReceiver:any, ast:AST, elementIndex:number, propertyName:string, setter:SetterFn, directiveRecord:DirectiveRecord) {
this.mode = mode;
this.implicitReceiver = implicitReceiver;
this.ast = ast;
this.elementIndex = elementIndex;
this.propertyName = propertyName;
this.setter = setter;
this.directiveRecord = directiveRecord;
}
callOnChange() {
return isPresent(this.directiveRecord) && this.directiveRecord.callOnChange;
}
isOnPushChangeDetection() {
return isPresent(this.directiveRecord) && this.directiveRecord.isOnPushChangeDetection();
}
isDirective() {
return this.mode === DIRECTIVE;
}
isElement() {
return this.mode === ELEMENT;
}
isTextNode() {
return this.mode === TEXT_NODE;
}
static createForDirective(ast:AST, propertyName:string, setter:SetterFn, directiveRecord:DirectiveRecord) {
return new BindingRecord(DIRECTIVE, 0, ast, 0, propertyName, setter, directiveRecord);
}
static createForElement(ast:AST, elementIndex:number, propertyName:string) {
return new BindingRecord(ELEMENT, 0, ast, elementIndex, propertyName, null, null);
}
static createForHostProperty(directiveIndex:DirectiveIndex, ast:AST, propertyName:string) {
return new BindingRecord(ELEMENT, directiveIndex, ast, directiveIndex.elementIndex, propertyName, null, null);
}
static createForTextNode(ast:AST, elementIndex:number) {
return new BindingRecord(TEXT_NODE, 0, ast, elementIndex, null, null, null);
}
}

View File

@ -0,0 +1,96 @@
import {DynamicProtoChangeDetector, JitProtoChangeDetector} from './proto_change_detector';
import {PipeFactory} from './pipes/pipe';
import {PipeRegistry} from './pipes/pipe_registry';
import {IterableChangesFactory} from './pipes/iterable_changes';
import {KeyValueChangesFactory} from './pipes/keyvalue_changes';
import {AsyncPipeFactory} from './pipes/async_pipe';
import {NullPipeFactory} from './pipes/null_pipe';
import {BindingRecord} from './binding_record';
import {DirectiveRecord} from './directive_record';
import {DEFAULT} from './constants';
import {ChangeDetection, ProtoChangeDetector} from './interfaces';
import {Injectable} from 'angular2/src/di/annotations_impl';
import {List} from 'angular2/src/facade/collection';
/**
* Structural diffing for `Object`s and `Map`s.
*
* @exportedAs angular2/pipes
*/
export var keyValDiff:List<PipeFactory> = [
new KeyValueChangesFactory(),
new NullPipeFactory()
];
/**
* Structural diffing for `Iterable` types such as `Array`s.
*
* @exportedAs angular2/pipes
*/
export var iterableDiff:List<PipeFactory> = [
new IterableChangesFactory(),
new NullPipeFactory()
];
/**
* Async binding to such types as Observable.
*
* @exportedAs angular2/pipes
*/
export var async:List<PipeFactory> = [
new AsyncPipeFactory(),
new NullPipeFactory()
];
export var defaultPipes:Map<String, List<PipeFactory>> = {
"iterableDiff" : iterableDiff,
"keyValDiff" : keyValDiff,
"async" : async
};
/**
* Implements change detection that does not require `eval()`.
*
* This is slower than {@link JitChangeDetection}.
*
* @exportedAs angular2/change_detection
*/
@Injectable()
export class DynamicChangeDetection extends ChangeDetection {
registry:PipeRegistry;
constructor(registry:PipeRegistry) {
super();
this.registry = registry;
}
createProtoChangeDetector(name:string, bindingRecords:List<BindingRecord>, variableBindings:List<string>,
directiveRecords:List<DirectiveRecord>, changeControlStrategy:string = DEFAULT):ProtoChangeDetector{
return new DynamicProtoChangeDetector(this.registry, bindingRecords, variableBindings, directiveRecords, changeControlStrategy);
}
}
/**
* Implements faster change detection, by generating source code.
*
* This requires `eval()`. For change detection that does not require `eval()`, see {@link DynamicChangeDetection}.
*
* @exportedAs angular2/change_detection
*/
@Injectable()
export class JitChangeDetection extends ChangeDetection {
registry:PipeRegistry;
constructor(registry:PipeRegistry) {
super();
this.registry = registry;
}
createProtoChangeDetector(name:string, bindingRecords:List<BindingRecord>, variableBindings:List<string>,
directiveRecords:List<DirectiveRecord>, changeControlStrategy:string = DEFAULT):ProtoChangeDetector{
return new JitProtoChangeDetector(this.registry, bindingRecords, variableBindings, directiveRecords, changeControlStrategy);
}
}
export var defaultPipeRegistry:PipeRegistry = new PipeRegistry(defaultPipes);

View File

@ -1,10 +1,10 @@
library change_detectoin.change_detection_jit_generator;
class ChangeDetectorJITGenerator {
ChangeDetectorJITGenerator(typeName, records) {
ChangeDetectorJITGenerator(typeName, strategy, records, directiveMementos) {
}
generate() {
throw "Not supported in Dart";
throw "Jit Change Detection is not supported in Dart";
}
}

View File

@ -3,6 +3,7 @@ import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/faca
import {AbstractChangeDetector} from './abstract_change_detector';
import {ChangeDetectionUtil} from './change_detection_util';
import {DirectiveIndex, DirectiveRecord} from './directive_record';
import {
ProtoRecord,
@ -15,6 +16,7 @@ import {
RECORD_TYPE_PRIMITIVE_OP,
RECORD_TYPE_KEYED_ACCESS,
RECORD_TYPE_PIPE,
RECORD_TYPE_BINDING_PIPE,
RECORD_TYPE_INTERPOLATE
} from './proto_record';
@ -23,103 +25,47 @@ import {
* that "emulates" what the developer would write by hand to implement the same
* kind of behaviour.
*
* For example: An expression `address.city` will result in the following class:
*
* var ChangeDetector0 = function ChangeDetector0(dispatcher, protos) {
* AbstractChangeDetector.call(this);
* this.dispatcher = dispatcher;
* this.protos = protos;
*
* this.context = ChangeDetectionUtil.unitialized();
* this.address0 = ChangeDetectionUtil.unitialized();
* this.city1 = ChangeDetectionUtil.unitialized();
* }
* ChangeDetector0.prototype = Object.create(AbstractChangeDetector.prototype);
*
* ChangeDetector0.prototype.detectChangesInRecords = function(throwOnChange) {
* var address0;
* var city1;
* var change;
* var changes = null;
* var temp;
* var context = this.context;
*
* address0 = context.address;
* if (address0 !== this.address0) {
* this.address0 = address0;
* }
*
* city1 = address0.city;
* if (city1 !== this.city1) {
* changes = ChangeDetectionUtil.addRecord(changes,
* ChangeDetectionUtil.simpleChangeRecord(this.protos[1].bindingMemento, this.city1, city1));
* this.city1 = city1;
* }
*
* if (changes.length > 0) {
* if(throwOnChange) ChangeDetectionUtil.throwOnChange(this.protos[1], changes[0]);
* this.dispatcher.onRecordChange('address.city', changes);
* changes = null;
* }
* }
*
*
* ChangeDetector0.prototype.hydrate = function(context, locals) {
* this.context = context;
* this.locals = locals;
* }
*
* ChangeDetector0.prototype.dehydrate = function(context) {
* this.context = ChangeDetectionUtil.unitialized();
* this.address0 = ChangeDetectionUtil.unitialized();
* this.city1 = ChangeDetectionUtil.unitialized();
* this.locals = null;
* }
*
* ChangeDetector0.prototype.hydrated = function() {
* return this.context !== ChangeDetectionUtil.unitialized();
* }
*
* return ChangeDetector0;
*
*
* The only thing the generated class depends on is the super class AbstractChangeDetector.
*
* The implementation comprises two parts:
* * ChangeDetectorJITGenerator has the logic of how everything fits together.
* * template functions (e.g., constructorTemplate) define what code is generated.
*/
var ABSTRACT_CHANGE_DETECTOR = "AbstractChangeDetector";
var UTIL = "ChangeDetectionUtil";
var DISPATCHER_ACCESSOR = "this.dispatcher";
var PIPE_REGISTRY_ACCESSOR = "this.pipeRegistry";
var PROTOS_ACCESSOR = "this.protos";
var DIRECTIVES_ACCESSOR = "this.directiveRecords";
var CONTEXT_ACCESSOR = "this.context";
var CHANGE_LOCAL = "change";
var IS_CHANGED_LOCAL = "isChanged";
var CHANGES_LOCAL = "changes";
var LOCALS_ACCESSOR = "this.locals";
var MODE_ACCESSOR = "this.mode";
var TEMP_LOCAL = "temp";
var CURRENT_PROTO = "currentProto";
function typeTemplate(type:string, cons:string, detectChanges:string, setContext:string):string {
function typeTemplate(type:string, cons:string, detectChanges:string,
notifyOnAllChangesDone:string, setContext:string):string {
return `
${cons}
${detectChanges}
${notifyOnAllChangesDone}
${setContext};
return function(dispatcher, pipeRegistry) {
return new ${type}(dispatcher, pipeRegistry, protos);
return new ${type}(dispatcher, pipeRegistry, protos, directiveRecords);
}
`;
}
function constructorTemplate(type:string, fieldsDefinitions:string):string {
return `
var ${type} = function ${type}(dispatcher, pipeRegistry, protos) {
var ${type} = function ${type}(dispatcher, pipeRegistry, protos, directiveRecords) {
${ABSTRACT_CHANGE_DETECTOR}.call(this);
${DISPATCHER_ACCESSOR} = dispatcher;
${PIPE_REGISTRY_ACCESSOR} = pipeRegistry;
${PROTOS_ACCESSOR} = protos;
${DIRECTIVES_ACCESSOR} = directiveRecords;
${LOCALS_ACCESSOR} = null;
${fieldsDefinitions}
}
@ -131,15 +77,29 @@ function pipeOnDestroyTemplate(pipeNames:List) {
return pipeNames.map((p) => `${p}.onDestroy()`).join("\n");
}
function hydrateTemplate(type:string, fieldsDefinitions:string, pipeOnDestroy:string):string {
function hydrateTemplate(type:string, mode:string, fieldDefinitions:string, pipeOnDestroy:string,
directiveFieldNames:List<String>, detectorFieldNames:List<String>):string {
var directiveInit = "";
for(var i = 0; i < directiveFieldNames.length; ++i) {
directiveInit += `${directiveFieldNames[i]} = directives.getDirectiveFor(this.directiveRecords[${i}].directiveIndex);\n`;
}
var detectorInit = "";
for(var i = 0; i < detectorFieldNames.length; ++i) {
detectorInit += `${detectorFieldNames[i]} = directives.getDetectorFor(this.directiveRecords[${i}].directiveIndex);\n`;
}
return `
${type}.prototype.hydrate = function(context, locals) {
${type}.prototype.hydrate = function(context, locals, directives) {
${MODE_ACCESSOR} = "${mode}";
${CONTEXT_ACCESSOR} = context;
${LOCALS_ACCESSOR} = locals;
${directiveInit}
${detectorInit}
}
${type}.prototype.dehydrate = function() {
${pipeOnDestroy}
${fieldsDefinitions}
${fieldDefinitions}
${LOCALS_ACCESSOR} = null;
}
${type}.prototype.hydrated = function() {
@ -156,13 +116,26 @@ ${type}.prototype.detectChangesInRecords = function(throwOnChange) {
`;
}
function callOnAllChangesDoneTemplate(type:string, body:string):string {
return `
${type}.prototype.callOnAllChangesDone = function() {
${body}
}
`;
}
function bodyTemplate(localDefinitions:string, changeDefinitions:string, records:string):string {
function onAllChangesDoneTemplate(directive:string):string {
return `${directive}.onAllChangesDone();`;
}
function detectChangesBodyTemplate(localDefinitions:string, changeDefinitions:string, records:string):string {
return `
${localDefinitions}
${changeDefinitions}
var ${TEMP_LOCAL};
var ${CHANGE_LOCAL};
var ${IS_CHANGED_LOCAL} = false;
var ${CURRENT_PROTO};
var ${CHANGES_LOCAL} = null;
context = ${CONTEXT_ACCESSOR};
@ -170,45 +143,42 @@ ${records}
`;
}
function notifyTemplate(index:number):string{
return `
if (${CHANGES_LOCAL} && ${CHANGES_LOCAL}.length > 0) {
if(throwOnChange) ${UTIL}.throwOnChange(${PROTOS_ACCESSOR}[${index}], ${CHANGES_LOCAL}[0]);
${DISPATCHER_ACCESSOR}.onRecordChange(${PROTOS_ACCESSOR}[${index}].directiveMemento, ${CHANGES_LOCAL});
${CHANGES_LOCAL} = null;
}
`;
}
function pipeCheckTemplate(context:string, pipe:string, pipeType:string,
value:string, change:string, addRecord:string, notify:string):string{
function pipeCheckTemplate(protoIndex:number, context:string, bindingPropagationConfig:string, pipe:string, pipeType:string,
oldValue:string, newValue:string, change:string, update:string,
addToChanges, lastInDirective:string):string{
return `
${CURRENT_PROTO} = ${PROTOS_ACCESSOR}[${protoIndex}];
if (${pipe} === ${UTIL}.unitialized()) {
${pipe} = ${PIPE_REGISTRY_ACCESSOR}.get('${pipeType}', ${context});
${pipe} = ${PIPE_REGISTRY_ACCESSOR}.get('${pipeType}', ${context}, ${bindingPropagationConfig});
} else if (!${pipe}.supports(${context})) {
${pipe}.onDestroy();
${pipe} = ${PIPE_REGISTRY_ACCESSOR}.get('${pipeType}', ${context});
${pipe} = ${PIPE_REGISTRY_ACCESSOR}.get('${pipeType}', ${context}, ${bindingPropagationConfig});
}
${CHANGE_LOCAL} = ${pipe}.transform(${context});
if (! ${UTIL}.noChangeMarker(${CHANGE_LOCAL})) {
${value} = ${CHANGE_LOCAL};
${newValue} = ${pipe}.transform(${context});
if (${oldValue} !== ${newValue}) {
${newValue} = ${UTIL}.unwrapValue(${newValue});
${change} = true;
${addRecord}
${update}
${addToChanges}
${oldValue} = ${newValue};
}
${notify}
${lastInDirective}
`;
}
function referenceCheckTemplate(assignment, newValue, oldValue, change, addRecord, notify) {
function referenceCheckTemplate(protoIndex:number, assignment:string, oldValue:string, newValue:string, change:string,
update:string, addToChanges:string, lastInDirective:string):string {
return `
${CURRENT_PROTO} = ${PROTOS_ACCESSOR}[${protoIndex}];
${assignment}
if (${newValue} !== ${oldValue} || (${newValue} !== ${newValue}) && (${oldValue} !== ${oldValue})) {
${change} = true;
${addRecord}
${update}
${addToChanges}
${oldValue} = ${newValue};
}
${notify}
${lastInDirective}
`;
}
@ -237,23 +207,66 @@ if (${cond}) {
`;
}
function addSimpleChangeRecordTemplate(protoIndex:number, oldValue:string, newValue:string) {
return `${CHANGES_LOCAL} = ${UTIL}.addRecord(${CHANGES_LOCAL},
${UTIL}.simpleChangeRecord(${PROTOS_ACCESSOR}[${protoIndex}].bindingMemento, ${oldValue}, ${newValue}));`;
function addToChangesTemplate(oldValue:string, newValue:string):string {
return `${CHANGES_LOCAL} = ${UTIL}.addChange(${CHANGES_LOCAL}, ${CURRENT_PROTO}.bindingRecord.propertyName, ${UTIL}.simpleChange(${oldValue}, ${newValue}));`;
}
function updateDirectiveTemplate(oldValue:string, newValue:string, directiveProperty:string):string {
return `
if(throwOnChange) ${UTIL}.throwOnChange(${CURRENT_PROTO}, ${UTIL}.simpleChange(${oldValue}, ${newValue}));
${directiveProperty} = ${newValue};
${IS_CHANGED_LOCAL} = true;
`;
}
function updateElementTemplate(oldValue:string, newValue:string):string {
return `
if(throwOnChange) ${UTIL}.throwOnChange(${CURRENT_PROTO}, ${UTIL}.simpleChange(${oldValue}, ${newValue}));
${DISPATCHER_ACCESSOR}.notifyOnBinding(${CURRENT_PROTO}.bindingRecord, ${newValue});
`;
}
function notifyOnChangesTemplate(directive:string):string{
return `
if(${CHANGES_LOCAL}) {
${directive}.onChange(${CHANGES_LOCAL});
${CHANGES_LOCAL} = null;
}
`;
}
function notifyOnPushDetectorsTemplate(detector:string):string{
return `
if(${IS_CHANGED_LOCAL}) {
${detector}.markAsCheckOnce();
}
`;
}
function lastInDirectiveTemplate(notifyOnChanges:string, notifyOnPush:string):string{
return `
${notifyOnChanges}
${notifyOnPush}
${IS_CHANGED_LOCAL} = false;
`;
}
export class ChangeDetectorJITGenerator {
typeName:string;
records:List<ProtoRecord>;
localNames:List<String>;
changeNames:List<String>;
fieldNames:List<String>;
pipeNames:List<String>;
directiveRecords:List;
localNames:List<string>;
changeNames:List<string>;
fieldNames:List<string>;
pipeNames:List<string>;
changeDetectionStrategy:stirng;
constructor(typeName:string, records:List<ProtoRecord>) {
constructor(typeName:string, changeDetectionStrategy:string, records:List<ProtoRecord>, directiveRecords:List) {
this.typeName = typeName;
this.changeDetectionStrategy = changeDetectionStrategy;
this.records = records;
this.directiveRecords = directiveRecords;
this.localNames = this.getLocalNames(records);
this.changeNames = this.getChangeNames(this.localNames);
@ -261,7 +274,7 @@ export class ChangeDetectorJITGenerator {
this.pipeNames = this.getPipeNames(this.localNames);
}
getLocalNames(records:List<ProtoRecord>):List<String> {
getLocalNames(records:List<ProtoRecord>):List<string> {
var index = 0;
var names = records.map((r) => {
var sanitizedName = r.name.replace(new RegExp("\\W", "g"), '');
@ -270,21 +283,23 @@ export class ChangeDetectorJITGenerator {
return ["context"].concat(names);
}
getChangeNames(localNames:List<String>):List<String> {
getChangeNames(localNames:List<string>):List<string> {
return localNames.map((n) => `change_${n}`);
}
getFieldNames(localNames:List<String>):List<String> {
getFieldNames(localNames:List<string>):List<string> {
return localNames.map((n) => `this.${n}`);
}
getPipeNames(localNames:List<String>):List<String> {
getPipeNames(localNames:List<string>):List<string> {
return localNames.map((n) => `this.${n}_pipe`);
}
generate():Function {
var text = typeTemplate(this.typeName, this.genConstructor(), this.genDetectChanges(), this.genHydrate());
return new Function('AbstractChangeDetector', 'ChangeDetectionUtil', 'protos', text)(AbstractChangeDetector, ChangeDetectionUtil, this.records);
var text = typeTemplate(this.typeName, this.genConstructor(), this.genDetectChanges(),
this.genCallOnAllChangesDone(), this.genHydrate());
return new Function('AbstractChangeDetector', 'ChangeDetectionUtil', 'protos', 'directiveRecords', text)
(AbstractChangeDetector, ChangeDetectionUtil, this.records, this.directiveRecords);
}
genConstructor():string {
@ -292,21 +307,41 @@ export class ChangeDetectorJITGenerator {
}
genHydrate():string {
return hydrateTemplate(this.typeName, this.genFieldDefinitions(),
pipeOnDestroyTemplate(this.getnonNullPipeNames()));
var mode = ChangeDetectionUtil.changeDetectionMode(this.changeDetectionStrategy);
return hydrateTemplate(this.typeName, mode, this.genFieldDefinitions(),
pipeOnDestroyTemplate(this.getNonNullPipeNames()),
this.getDirectiveFieldNames(), this.getDetectorFieldNames());
}
getDirectiveFieldNames():List<string> {
return this.directiveRecords.map((d) => this.getDirective(d.directiveIndex));
}
getDetectorFieldNames():List<string> {
return this.directiveRecords.filter(r => r.isOnPushChangeDetection()).map((d) => this.getDetector(d.directiveIndex));
}
getDirective(d:DirectiveIndex) {
return `this.directive_${d.name}`;
}
getDetector(d:DirectiveIndex) {
return `this.detector_${d.name}`;
}
genFieldDefinitions() {
var fields = [];
fields = fields.concat(this.fieldNames);
fields = fields.concat(this.getnonNullPipeNames());
fields = fields.concat(this.getNonNullPipeNames());
fields = fields.concat(this.getDirectiveFieldNames());
fields = fields.concat(this.getDetectorFieldNames());
return fieldDefinitionsTemplate(fields);
}
getnonNullPipeNames():List<String> {
getNonNullPipeNames():List<string> {
var pipes = [];
this.records.forEach((r) => {
if (r.mode === RECORD_TYPE_PIPE) {
if (r.mode === RECORD_TYPE_PIPE || r.mode === RECORD_TYPE_BINDING_PIPE) {
pipes.push(this.pipeNames[r.selfIndex]);
}
});
@ -314,13 +349,28 @@ export class ChangeDetectorJITGenerator {
}
genDetectChanges():string {
var body = this.genBody();
var body = this.genDetectChangesBody();
return detectChangesTemplate(this.typeName, body);
}
genBody():string {
genCallOnAllChangesDone():string {
var notifications = [];
var dirs = this.directiveRecords;
for (var i = dirs.length - 1; i >= 0; --i) {
var dir = dirs[i];
if (dir.callOnAllChangesDone) {
var directive = `this.directive_${dir.directiveIndex.name}`;
notifications.push(onAllChangesDoneTemplate(directive));
}
}
return callOnAllChangesDoneTemplate(this.typeName, notifications.join(";\n"));
}
genDetectChangesBody():string {
var rec = this.records.map((r) => this.genRecord(r)).join("\n");
return bodyTemplate(this.genLocalDefinitions(), this.genChangeDefinitions(), rec);
return detectChangesBodyTemplate(this.genLocalDefinitions(), this.genChangeDefinitions(), rec);
}
genLocalDefinitions():string {
@ -332,7 +382,7 @@ export class ChangeDetectorJITGenerator {
}
genRecord(r:ProtoRecord):string {
if (r.mode === RECORD_TYPE_PIPE) {
if (r.mode === RECORD_TYPE_PIPE || r.mode === RECORD_TYPE_BINDING_PIPE) {
return this.genPipeCheck (r);
} else {
return this.genReferenceCheck(r);
@ -341,26 +391,33 @@ export class ChangeDetectorJITGenerator {
genPipeCheck(r:ProtoRecord):string {
var context = this.localNames[r.contextIndex];
var pipe = this.pipeNames[r.selfIndex];
var newValue = this.localNames[r.selfIndex];
var oldValue = this.fieldNames[r.selfIndex];
var newValue = this.localNames[r.selfIndex];
var change = this.changeNames[r.selfIndex];
var addRecord = addSimpleChangeRecordTemplate(r.selfIndex - 1, oldValue, newValue);
var notify = this.genNotify(r);
var pipe = this.pipeNames[r.selfIndex];
var cdRef = r.mode === RECORD_TYPE_BINDING_PIPE ? "this.ref" : "null";
return pipeCheckTemplate(context, pipe, r.name, newValue, change, addRecord, notify);
var update = this.genUpdateDirectiveOrElement(r);
var addToChanges = this.genAddToChanges(r);
var lastInDirective = this.genLastInDirective(r);
return pipeCheckTemplate(r.selfIndex - 1, context, cdRef, pipe, r.name, oldValue, newValue, change,
update, addToChanges, lastInDirective);
}
genReferenceCheck(r:ProtoRecord):string {
var newValue = this.localNames[r.selfIndex];
var oldValue = this.fieldNames[r.selfIndex];
var newValue = this.localNames[r.selfIndex];
var change = this.changeNames[r.selfIndex];
var assignment = this.genUpdateCurrentValue(r);
var addRecord = addSimpleChangeRecordTemplate(r.selfIndex - 1, oldValue, newValue);
var notify = this.genNotify(r);
var check = referenceCheckTemplate(assignment, newValue, oldValue, change, r.lastInBinding ? addRecord : '', notify);;
var update = this.genUpdateDirectiveOrElement(r);
var addToChanges = this.genAddToChanges(r);
var lastInDirective = this.genLastInDirective(r);
var check = referenceCheckTemplate(r.selfIndex - 1, assignment, oldValue, newValue, change,
update, addToChanges, lastInDirective);
if (r.isPureFunction()) {
return this.ifChangedGuard(r, check);
} else {
@ -369,7 +426,7 @@ export class ChangeDetectorJITGenerator {
}
genUpdateCurrentValue(r:ProtoRecord):string {
var context = this.localNames[r.contextIndex];
var context = this.getContext(r);
var newValue = this.localNames[r.selfIndex];
var args = this.genArgs(r);
@ -407,6 +464,14 @@ export class ChangeDetectorJITGenerator {
}
}
getContext(r:ProtoRecord):string {
if (r.contextIndex == -1) {
return this.getDirective(r.directiveIndex);
} else {
return this.localNames[r.contextIndex];
}
}
ifChangedGuard(r:ProtoRecord, body:string):string {
return ifChangedGuardTemplate(r.args.map((a) => this.changeNames[a]), body);
}
@ -427,8 +492,49 @@ export class ChangeDetectorJITGenerator {
return JSON.stringify(value);
}
genNotify(r):string{
return r.lastInDirective ? notifyTemplate(r.selfIndex - 1) : '';
genUpdateDirectiveOrElement(r:ProtoRecord):string {
if (! r.lastInBinding) return "";
var newValue = this.localNames[r.selfIndex];
var oldValue = this.fieldNames[r.selfIndex];
var br = r.bindingRecord;
if (br.isDirective()) {
var directiveProperty = `${this.getDirective(br.directiveRecord.directiveIndex)}.${br.propertyName}`;
return updateDirectiveTemplate(oldValue, newValue, directiveProperty);
} else {
return updateElementTemplate(oldValue, newValue);
}
}
genAddToChanges(r:ProtoRecord):string {
var newValue = this.localNames[r.selfIndex];
var oldValue = this.fieldNames[r.selfIndex];
return r.bindingRecord.callOnChange() ? addToChangesTemplate(oldValue, newValue) : "";
}
genLastInDirective(r:ProtoRecord):string{
var onChanges = this.genNotifyOnChanges(r);
var onPush = this.genNotifyOnPushDetectors(r);
return lastInDirectiveTemplate(onChanges, onPush);
}
genNotifyOnChanges(r:ProtoRecord):string{
var br = r.bindingRecord;
if (r.lastInDirective && br.callOnChange()) {
return notifyOnChangesTemplate(this.getDirective(br.directiveRecord.directiveIndex));
} else {
return "";
}
}
genNotifyOnPushDetectors(r:ProtoRecord):string{
var br = r.bindingRecord;
if (r.lastInDirective && br.isOnPushChangeDetection()) {
return notifyOnPushDetectorsTemplate(this.getDetector(br.directiveRecord.directiveIndex));
} else {
return "";
}
}
genArgs(r:ProtoRecord):string {

View File

@ -2,8 +2,8 @@ import {isPresent, isBlank, BaseException, Type} from 'angular2/src/facade/lang'
import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {ProtoRecord} from './proto_record';
import {ExpressionChangedAfterItHasBeenChecked} from './exceptions';
import {NO_CHANGE} from './pipes/pipe';
import {ChangeRecord, ChangeDetector, CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED} from './interfaces';
import {WrappedValue} from './pipes/pipe';
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants';
export var uninitialized = new Object();
@ -39,31 +39,7 @@ var _simpleChanges = [
new SimpleChange(null, null),
new SimpleChange(null, null),
new SimpleChange(null, null)
]
var _changeRecordsIndex = 0;
var _changeRecords = [
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null),
new ChangeRecord(null, null)
]
];
function _simpleChange(previousValue, currentValue) {
var index = _simpleChangesIndex++ % 20;
@ -73,16 +49,6 @@ function _simpleChange(previousValue, currentValue) {
return s;
}
function _changeRecord(bindingMemento, change) {
var index = _changeRecordsIndex++ % 20;
var s = _changeRecords[index];
s.bindingMemento = bindingMemento;
s.change = change;
return s;
}
var _singleElementList = [null];
export class ChangeDetectionUtil {
static unitialized() {
return uninitialized;
@ -143,37 +109,31 @@ export class ChangeDetectionUtil {
return obj[args[0]];
}
static noChangeMarker(value):boolean {
return value === NO_CHANGE;
static unwrapValue(value:any):any {
if (value instanceof WrappedValue) {
return value.wrapped;
} else {
return value;
}
}
static throwOnChange(proto:ProtoRecord, change) {
throw new ExpressionChangedAfterItHasBeenChecked(proto, change);
}
static changeDetectionMode(strategy:string) {
return strategy == ON_PUSH ? CHECK_ONCE : CHECK_ALWAYS;
}
static simpleChange(previousValue:any, currentValue:any):SimpleChange {
return _simpleChange(previousValue, currentValue);
}
static changeRecord(memento:any, change:any):ChangeRecord {
return _changeRecord(memento, change);
}
static simpleChangeRecord(memento:any, previousValue:any, currentValue:any):ChangeRecord {
return _changeRecord(memento, _simpleChange(previousValue, currentValue));
}
static addRecord(updatedRecords:List, changeRecord:ChangeRecord):List {
if (isBlank(updatedRecords)) {
updatedRecords = _singleElementList;
updatedRecords[0] = changeRecord;
} else if (updatedRecords === _singleElementList) {
updatedRecords = [_singleElementList[0], changeRecord];
} else {
ListWrapper.push(updatedRecords, changeRecord);
static addChange(changes, propertyName:string, change){
if (isBlank(changes)) {
changes = {};
}
return updatedRecords;
changes[propertyName] = change;
return changes;
}
}

View File

@ -0,0 +1,45 @@
import {ChangeDetector} from './interfaces';
import {CHECK_ONCE, DETACHED, CHECK_ALWAYS} from './constants';
/**
* Controls change detection.
*
* {@link ChangeDetectorRef} allows requesting checks for detectors that rely on observables. It also allows detaching and
* attaching change detector subtrees.
*
* @exportedAs angular2/change_detection
*/
export class ChangeDetectorRef {
_cd:ChangeDetector;
constructor(cd:ChangeDetector) {
this._cd = cd;
}
/**
* Request to check all ON_PUSH ancestors.
*/
requestCheck() {
this._cd.markPathToRootAsCheckOnce();
}
/**
* Detaches the change detector from the change detector tree.
*
* The detached change detector will not be checked until it is reattached.
*/
detach() {
this._cd.mode = DETACHED;
}
/**
* Reattach the change detector to the change detector tree.
*
* This also requests a check of this change detector. This reattached change detector will be checked during the
* next change detection run.
*/
reattach() {
this._cd.mode = CHECK_ALWAYS;
this.requestCheck();
}
}

View File

@ -45,9 +45,9 @@ function _selfRecord(r:ProtoRecord, contextIndex:number, selfIndex:number):Proto
[],
r.fixedArgs,
contextIndex,
r.directiveIndex,
selfIndex,
r.bindingMemento,
r.directiveMemento,
r.bindingRecord,
r.expressionAsString,
r.lastInBinding,
r.lastInDirective
@ -73,9 +73,9 @@ function _replaceIndices(r:ProtoRecord, selfIndex:number, indexMap:Map) {
args,
r.fixedArgs,
contextIndex,
r.directiveIndex,
selfIndex,
r.bindingMemento,
r.directiveMemento,
r.bindingRecord,
r.expressionAsString,
r.lastInBinding,
r.lastInDirective

View File

@ -0,0 +1,35 @@
//TODO:vsavkin Use enums after switching to TypeScript
/**
* CHECK_ONCE means that after calling detectChanges the mode of the change detector
* will become CHECKED.
*/
export const CHECK_ONCE="CHECK_ONCE";
/**
* CHECKED means that the change detector should be skipped until its mode changes to
* CHECK_ONCE or CHECK_ALWAYS.
*/
export const CHECKED="CHECKED";
/**
* CHECK_ALWAYS means that after calling detectChanges the mode of the change detector
* will remain CHECK_ALWAYS.
*/
export const CHECK_ALWAYS="ALWAYS_CHECK";
/**
* DETACHED means that the change detector sub tree is not a part of the main tree and
* should be skipped.
*/
export const DETACHED="DETACHED";
/**
* ON_PUSH means that the change detector's mode will be set to CHECK_ONCE during hydration.
*/
export const ON_PUSH = "ON_PUSH";
/**
* DEFAULT means that the change detector's mode will be set to CHECK_ALWAYS during hydration.
*/
export const DEFAULT = "DEFAULT";

View File

@ -0,0 +1,34 @@
import {ON_PUSH} from './constants';
import {StringWrapper} from 'angular2/src/facade/lang';
export class DirectiveIndex {
elementIndex:number;
directiveIndex:number;
constructor(elementIndex:number, directiveIndex:number) {
this.elementIndex = elementIndex;
this.directiveIndex = directiveIndex;
}
get name() {
return `${this.elementIndex}_${this.directiveIndex}`;
}
}
export class DirectiveRecord {
directiveIndex:DirectiveIndex;
callOnAllChangesDone:boolean;
callOnChange:boolean;
changeDetection:string;
constructor(directiveIndex:DirectiveIndex, callOnAllChangesDone:boolean, callOnChange:boolean, changeDetection:string) {
this.directiveIndex = directiveIndex;
this.callOnAllChangesDone = callOnAllChangesDone;
this.callOnChange = callOnChange;
this.changeDetection = changeDetection;
}
isOnPushChangeDetection():boolean {
return StringWrapper.equals(this.changeDetection, ON_PUSH);
}
}

View File

@ -2,8 +2,9 @@ import {isPresent, isBlank, BaseException, FunctionWrapper} from 'angular2/src/f
import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {AbstractChangeDetector} from './abstract_change_detector';
import {BindingRecord} from './binding_record';
import {PipeRegistry} from './pipes/pipe_registry';
import {ChangeDetectionUtil, SimpleChange, uninitialized} from './change_detection_util';
import {ChangeDetectionUtil, uninitialized} from './change_detection_util';
import {
@ -17,6 +18,7 @@ import {
RECORD_TYPE_PRIMITIVE_OP,
RECORD_TYPE_KEYED_ACCESS,
RECORD_TYPE_PIPE,
RECORD_TYPE_BINDING_PIPE,
RECORD_TYPE_INTERPOLATE
} from './proto_record';
@ -33,8 +35,12 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
prevContexts:List;
protos:List<ProtoRecord>;
directives:any;
directiveRecords:List;
changeControlStrategy:string;
constructor(dispatcher:any, pipeRegistry:PipeRegistry, protoRecords:List<ProtoRecord>) {
constructor(changeControlStrategy:string, dispatcher:any, pipeRegistry:PipeRegistry,
protoRecords:List<ProtoRecord>, directiveRecords:List) {
super();
this.dispatcher = dispatcher;
this.pipeRegistry = pipeRegistry;
@ -49,13 +55,18 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
ListWrapper.fill(this.prevContexts, uninitialized);
ListWrapper.fill(this.changes, false);
this.locals = null;
this.directives = null;
this.protos = protoRecords;
this.directiveRecords = directiveRecords;
this.changeControlStrategy = changeControlStrategy;
}
hydrate(context:any, locals:any) {
hydrate(context:any, locals:any, directives:any) {
this.mode = ChangeDetectionUtil.changeDetectionMode(this.changeControlStrategy);
this.values[0] = context;
this.locals = locals;
this.directives = directives;
}
dehydrate() {
@ -82,28 +93,74 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
detectChangesInRecords(throwOnChange:boolean) {
var protos:List<ProtoRecord> = this.protos;
var updatedRecords = null;
var changes = null;
var isChanged = false;
for (var i = 0; i < protos.length; ++i) {
var proto:ProtoRecord = protos[i];
var change = this._check(proto);
var bindingRecord = proto.bindingRecord;
var directiveRecord = bindingRecord.directiveRecord;
var change = this._check(proto);
if (isPresent(change)) {
var record = ChangeDetectionUtil.changeRecord(proto.bindingMemento, change);
updatedRecords = ChangeDetectionUtil.addRecord(updatedRecords, record);
if (throwOnChange) ChangeDetectionUtil.throwOnChange(proto, change);
this._updateDirectiveOrElement(change, bindingRecord);
isChanged = true;
changes = this._addChange(bindingRecord, change, changes);
}
if (proto.lastInDirective && isPresent(updatedRecords)) {
if (throwOnChange) ChangeDetectionUtil.throwOnChange(proto, updatedRecords[0]);
if (proto.lastInDirective) {
if (isPresent(changes)) {
this._getDirectiveFor(directiveRecord.directiveIndex).onChange(changes);
changes = null;
}
this.dispatcher.onRecordChange(proto.directiveMemento, updatedRecords);
updatedRecords = null;
if (isChanged && bindingRecord.isOnPushChangeDetection()) {
this._getDetectorFor(directiveRecord.directiveIndex).markAsCheckOnce();
}
isChanged = false;
}
}
}
callOnAllChangesDone() {
var dirs = this.directiveRecords;
for (var i = dirs.length - 1; i >= 0; --i) {
var dir = dirs[i];
if (dir.callOnAllChangesDone) {
this._getDirectiveFor(dir.directiveIndex).onAllChangesDone();
}
}
}
_updateDirectiveOrElement(change, bindingRecord) {
if (isBlank(bindingRecord.directiveRecord)) {
this.dispatcher.notifyOnBinding(bindingRecord, change.currentValue);
} else {
var directiveIndex = bindingRecord.directiveRecord.directiveIndex;
bindingRecord.setter(this._getDirectiveFor(directiveIndex), change.currentValue);
}
}
_addChange(bindingRecord:BindingRecord, change, changes) {
if (bindingRecord.callOnChange()) {
return ChangeDetectionUtil.addChange(changes, bindingRecord.propertyName, change);
} else {
return changes;
}
}
_getDirectiveFor(directiveIndex) {
return this.directives.getDirectiveFor(directiveIndex);
}
_getDetectorFor(directiveIndex) {
return this.directives.getDetectorFor(directiveIndex);
}
_check(proto:ProtoRecord) {
try {
if (proto.mode == RECORD_TYPE_PIPE) {
if (proto.mode === RECORD_TYPE_PIPE || proto.mode === RECORD_TYPE_BINDING_PIPE) {
return this._pipeCheck(proto);
} else {
return this._referenceCheck(proto);
@ -176,10 +233,13 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
_pipeCheck(proto:ProtoRecord) {
var context = this._readContext(proto);
var pipe = this._pipeFor(proto, context);
var prevValue = this._readSelf(proto);
var newValue = pipe.transform(context);
if (! ChangeDetectionUtil.noChangeMarker(newValue)) {
var prevValue = this._readSelf(proto);
if (!isSame(prevValue, newValue)) {
newValue = ChangeDetectionUtil.unwrapValue(newValue);
this._writeSelf(proto, newValue);
this._setChanged(proto, true);
@ -202,12 +262,25 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
if (isPresent(storedPipe)) {
storedPipe.onDestroy();
}
var pipe = this.pipeRegistry.get(proto.name, context);
// Currently, only pipes that used in bindings in the template get
// the changeDetectorRef of the encompassing component.
//
// In the future, pipes declared in the bind configuration should
// be able to access the changeDetectorRef of that component.
var cdr = proto.mode === RECORD_TYPE_BINDING_PIPE ? this.ref : null;
var pipe = this.pipeRegistry.get(proto.name, context, cdr);
this._writePipe(proto, pipe);
return pipe;
}
_readContext(proto:ProtoRecord) {
if (proto.contextIndex == -1) {
return this._getDirectiveFor(proto.directiveIndex);
} else {
return this.values[proto.contextIndex];
}
return this.values[proto.contextIndex];
}
@ -255,11 +328,12 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
}
}
var _singleElementList = [null];
function isSame(a, b) {
if (a === b) return true;
if (a instanceof String && b instanceof String && a == b) return true;
if ((a !== a) && (b !== b)) return true;
return false;
}

View File

@ -1,6 +1,7 @@
import {ProtoRecord} from './proto_record';
import {BaseException} from "angular2/src/facade/lang";
export class ExpressionChangedAfterItHasBeenChecked extends Error {
export class ExpressionChangedAfterItHasBeenChecked extends BaseException {
message:string;
constructor(proto:ProtoRecord, change:any) {
@ -14,7 +15,7 @@ export class ExpressionChangedAfterItHasBeenChecked extends Error {
}
}
export class ChangeDetectionError extends Error {
export class ChangeDetectionError extends BaseException {
message:string;
originalException:any;
location:string;

View File

@ -1,52 +1,46 @@
import {List} from 'angular2/src/facade/collection';
import {Locals} from './parser/locals';
import {DEFAULT} from './constants';
import {BindingRecord} from './binding_record';
export class ChangeRecord {
bindingMemento:any;
change:any;
constructor(bindingMemento, change) {
this.bindingMemento = bindingMemento;
this.change = change;
}
//REMOVE IT
get currentValue() {
return this.change.currentValue;
}
get previousValue() {
return this.change.previousValue;
export class ProtoChangeDetector {
instantiate(dispatcher:any):ChangeDetector{
return null;
}
}
/**
* CHECK_ONCE means that after calling detectChanges the mode of the change detector
* will become CHECKED.
* Interface used by Angular to control the change detection strategy for an application.
*
* Angular implements the following change detection strategies by default:
*
* - {@link DynamicChangeDetection}: slower, but does not require `eval()`.
* - {@link JitChangeDetection}: faster, but requires `eval()`.
*
* In JavaScript, you should always use `JitChangeDetection`, unless you are in an environment that has
* [CSP](https://developer.mozilla.org/en-US/docs/Web/Security/CSP), such as a Chrome Extension.
*
* In Dart, use `DynamicChangeDetection` during development. The Angular transformer generates an analog to the
* `JitChangeDetection` strategy at compile time.
*
*
* See: {@link DynamicChangeDetection}, {@link JitChangeDetection}
*
* # Example
* ```javascript
* bootstrap(MyApp, [bind(ChangeDetection).toClass(DynamicChangeDetection)]);
* ```
* @exportedAs angular2/change_detection
*/
export const CHECK_ONCE="CHECK_ONCE";
/**
* CHECKED means that the change detector should be skipped until its mode changes to
* CHECK_ONCE or CHECK_ALWAYS.
*/
export const CHECKED="CHECKED";
/**
* CHECK_ALWAYS means that after calling detectChanges the mode of the change detector
* will remain CHECK_ALWAYS.
*/
export const CHECK_ALWAYS="ALWAYS_CHECK";
/**
* DETACHED means that the change detector sub tree is not a part of the main tree and
* should be skipped.
*/
export const DETACHED="DETACHED";
export class ChangeDetection {
createProtoChangeDetector(name:string, bindingRecords:List, variableBindings:List, directiveRecords:List,
changeControlStrategy:string=DEFAULT):ProtoChangeDetector{
return null;
}
}
export class ChangeDispatcher {
onRecordChange(directiveMemento, records:List<ChangeRecord>) {}
notifyOnBinding(bindingRecord:BindingRecord, value:any) {}
}
export class ChangeDetector {
@ -54,9 +48,11 @@ export class ChangeDetector {
mode:string;
addChild(cd:ChangeDetector) {}
addShadowDomChild(cd:ChangeDetector) {}
removeChild(cd:ChangeDetector) {}
removeShadowDomChild(cd:ChangeDetector) {}
remove() {}
hydrate(context:any, locals:Locals) {}
hydrate(context:any, locals:Locals, directives:any) {}
dehydrate() {}
markPathToRootAsCheckOnce() {}

View File

@ -6,7 +6,7 @@ export class AST {
throw new BaseException("Not supported");
}
get isAssignable() {
get isAssignable():boolean {
return false;
}
@ -113,7 +113,7 @@ export class AccessMember extends AST {
}
}
get isAssignable() {
get isAssignable():boolean {
return true;
}
@ -148,7 +148,7 @@ export class KeyedAccess extends AST {
return obj[key];
}
get isAssignable() {
get isAssignable():boolean {
return true;
}
@ -168,11 +168,13 @@ export class Pipe extends AST {
exp:AST;
name:string;
args:List<AST>;
constructor(exp:AST, name:string, args:List) {
inBinding:boolean;
constructor(exp:AST, name:string, args:List, inBinding:boolean) {
super();
this.exp = exp;
this.name = name;
this.args = args;
this.inBinding = inBinding;
}
visit(visitor) {
@ -279,6 +281,8 @@ export class Binary extends AST {
case '%' : return left % right;
case '==' : return left == right;
case '!=' : return left != right;
case '===' : return left === right;
case '!==' : return left !== right;
case '<' : return left < right;
case '>' : return left > right;
case '<=' : return left <= right;
@ -395,7 +399,7 @@ export class ASTWithSource extends AST {
return this.ast.eval(context, locals);
}
get isAssignable() {
get isAssignable():boolean {
return this.ast.isAssignable;
}
@ -418,7 +422,6 @@ export class TemplateBinding {
name:string;
expression:ASTWithSource;
constructor(key:string, keyIsVar:boolean, name:string, expression:ASTWithSource) {
super();
this.key = key;
this.keyIsVar = keyIsVar;
// only either name or expression will be filled.
@ -445,6 +448,72 @@ export class AstVisitor {
visitPrefixNot(ast:PrefixNot) {}
}
export class AstTransformer {
visitImplicitReceiver(ast:ImplicitReceiver) {
return ast;
}
visitInterpolation(ast:Interpolation) {
return new Interpolation(ast.strings, this.visitAll(ast.expressions));
}
visitLiteralPrimitive(ast:LiteralPrimitive) {
return new LiteralPrimitive(ast.value);
}
visitAccessMember(ast:AccessMember) {
return new AccessMember(ast.receiver.visit(this), ast.name, ast.getter, ast.setter);
}
visitMethodCall(ast:MethodCall) {
return new MethodCall(ast.receiver.visit(this), ast.name, ast.fn, this.visitAll(ast.args));
}
visitFunctionCall(ast:FunctionCall) {
return new FunctionCall(ast.target.visit(this), this.visitAll(ast.args));
}
visitLiteralArray(ast:LiteralArray) {
return new LiteralArray(this.visitAll(ast.expressions));
}
visitLiteralMap(ast:LiteralMap) {
return new LiteralMap(ast.keys, this.visitAll(ast.values));
}
visitBinary(ast:Binary) {
return new Binary(ast.operation, ast.left.visit(this), ast.right.visit(this));
}
visitPrefixNot(ast:PrefixNot) {
return new PrefixNot(ast.expression.visit(this));
}
visitConditional(ast:Conditional) {
return new Conditional(
ast.condition.visit(this),
ast.trueExp.visit(this),
ast.falseExp.visit(this)
);
}
visitPipe(ast:Pipe) {
return new Pipe(ast.exp.visit(this), ast.name, this.visitAll(ast.args), ast.inBinding);
}
visitKeyedAccess(ast:KeyedAccess) {
return new KeyedAccess(ast.obj.visit(this), ast.key.visit(this));
}
visitAll(asts:List) {
var res = ListWrapper.createFixedSize(asts.length);
for (var i = 0; i < asts.length; ++i) {
res[i] = asts[i].visit(this);
}
return res;
}
}
var _evalListCache = [[],[0],[0,0],[0,0,0],[0,0,0,0],[0,0,0,0,0],
[0,0,0,0,0,0], [0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0]];

View File

@ -1,6 +1,6 @@
import {Injectable} from 'angular2/di';
import {Injectable} from 'angular2/src/di/annotations_impl';
import {List, ListWrapper, SetWrapper} from "angular2/src/facade/collection";
import {int, NumberWrapper, StringJoiner, StringWrapper} from "angular2/src/facade/lang";
import {int, NumberWrapper, StringJoiner, StringWrapper, BaseException} from "angular2/src/facade/lang";
export const TOKEN_TYPE_CHARACTER = 1;
export const TOKEN_TYPE_IDENTIFIER = 2;
@ -160,10 +160,7 @@ export const $QUESTION = 63;
const $0 = 48;
const $9 = 57;
const $A = 65, $B = 66, $C = 67, $D = 68, $E = 69, $F = 70, $G = 71, $H = 72,
$I = 73, $J = 74, $K = 75, $L = 76, $M = 77, $N = 78, $O = 79, $P = 80,
$Q = 81, $R = 82, $S = 83, $T = 84, $U = 85, $V = 86, $W = 87, $X = 88,
$Y = 89, $Z = 90;
const $A = 65, $E = 69, $Z = 90;
export const $LBRACKET = 91;
export const $BACKSLASH = 92;
@ -171,19 +168,15 @@ export const $RBRACKET = 93;
const $CARET = 94;
const $_ = 95;
const $a = 97, $b = 98, $c = 99, $d = 100, $e = 101, $f = 102, $g = 103,
$h = 104, $i = 105, $j = 106, $k = 107, $l = 108, $m = 109, $n = 110,
$o = 111, $p = 112, $q = 113, $r = 114, $s = 115, $t = 116, $u = 117,
$v = 118, $w = 119, $x = 120, $y = 121, $z = 122;
const $a = 97, $e = 101, $f = 102, $n = 110, $r = 114, $t = 116, $u = 117, $v = 118, $z = 122;
export const $LBRACE = 123;
export const $BAR = 124;
export const $RBRACE = 125;
const $TILDE = 126;
const $NBSP = 160;
export class ScannerError extends Error {
export class ScannerError extends BaseException {
message:string;
constructor(message) {
super();
@ -275,8 +268,6 @@ class _Scanner {
return this.scanComplexOperator(start, $AMPERSAND, '&', '&');
case $BAR:
return this.scanComplexOperator(start, $BAR, '|', '|');
case $TILDE:
return this.scanComplexOperator(start, $SLASH, '~', '/');
case $NBSP:
while (isWhitespace(this.peek)) this.advance();
return this.scanToken();
@ -304,7 +295,7 @@ class _Scanner {
assert(this.peek == StringWrapper.charCodeAt(one, 0));
this.advance();
var str:string = one;
if (this.peek == code) {
while (this.peek == code) {
this.advance();
str += two;
}
@ -455,12 +446,13 @@ var OPERATORS = SetWrapper.createFromList([
'-',
'*',
'/',
'~/',
'%',
'^',
'=',
'==',
'!=',
'===',
'!==',
'<',
'>',
'<=',
@ -480,5 +472,5 @@ var KEYWORDS = SetWrapper.createFromList([
'null',
'undefined',
'true',
'false',
'false'
]);

View File

@ -34,7 +34,7 @@ export class Locals {
throw new BaseException(`Cannot find '${name}'`);
}
set(name:string, value) {
set(name:string, value):void {
// TODO(rado): consider removing this check if we can guarantee this is not
// exposed to the public API.
// TODO: vsavkin maybe it should check only the local map
@ -45,7 +45,7 @@ export class Locals {
}
}
clearValues() {
clearValues():void {
MapWrapper.clearValues(this.current);
}
}

View File

@ -1,4 +1,4 @@
import {Injectable} from 'angular2/di';
import {Injectable} from 'angular2/src/di/annotations_impl';
import {int, isBlank, isPresent, BaseException, StringWrapper, RegExpWrapper} from 'angular2/src/facade/lang';
import {ListWrapper, List} from 'angular2/src/facade/collection';
import {Lexer, EOF, Token, $PERIOD, $COLON, $SEMICOLON, $LBRACKET, $RBRACKET,
@ -31,7 +31,6 @@ import {
var _implicitReceiver = new ImplicitReceiver();
// TODO(tbosch): Cannot make this const/final right now because of the transpiler...
var INTERPOLATION_REGEXP = RegExpWrapper.create('\\{\\{(.*?)\\}\\}');
var QUOTE_REGEXP = RegExpWrapper.create("'");
@Injectable()
export class Parser {
@ -58,7 +57,7 @@ export class Parser {
if (ListWrapper.isEmpty(pipes)) return bindingAst;
var res = ListWrapper.reduce(pipes,
(result, currentPipeName) => new Pipe(result, currentPipeName, []),
(result, currentPipeName) => new Pipe(result, currentPipeName, [], false),
bindingAst.ast);
return new ASTWithSource(res, bindingAst.source, bindingAst.location);
}
@ -211,18 +210,11 @@ class _ParseAST {
parsePipe() {
var result = this.parseExpression();
while (this.optionalOperator("|")) {
if (this.parseAction) {
this.error("Cannot have a pipe in an action expression");
}
var name = this.expectIdentifierOrKeyword();
var args = ListWrapper.create();
while (this.optionalCharacter($COLON)) {
ListWrapper.push(args, this.parseExpression());
}
result = new Pipe(result, name, args);
if (this.optionalOperator("|")) {
return this.parseInlinedPipe(result);
} else {
return result;
}
return result;
}
parseExpression() {
@ -284,13 +276,17 @@ class _ParseAST {
}
parseEquality() {
// '==','!='
// '==','!=','===','!=='
var result = this.parseRelational();
while (true) {
if (this.optionalOperator('==')) {
result = new Binary('==', result, this.parseRelational());
} else if (this.optionalOperator('===')) {
result = new Binary('===', result, this.parseRelational());
} else if (this.optionalOperator('!=')) {
result = new Binary('!=', result, this.parseRelational());
} else if (this.optionalOperator('!==')) {
result = new Binary('!==', result, this.parseRelational());
} else {
return result;
}
@ -464,16 +460,38 @@ class _ParseAST {
} else {
var getter = this.reflector.getter(id);
var setter = this.reflector.setter(id);
return new AccessMember(receiver, id, getter, setter);
var am = new AccessMember(receiver, id, getter, setter);
if (this.optionalOperator("|")) {
return this.parseInlinedPipe(am);
} else {
return am;
}
}
}
parseInlinedPipe(result) {
do {
if (this.parseAction) {
this.error("Cannot have a pipe in an action expression");
}
var name = this.expectIdentifierOrKeyword();
var args = ListWrapper.create();
while (this.optionalCharacter($COLON)) {
ListWrapper.push(args, this.parseExpression());
}
result = new Pipe(result, name, args, true);
} while(this.optionalOperator("|"));
return result;
}
parseCallArguments() {
if (this.next.isCharacter($RPAREN)) return [];
var positionals = [];
do {
ListWrapper.push(positionals, this.parseExpression());
} while (this.optionalCharacter($COMMA))
} while (this.optionalCharacter($COMMA));
return positionals;
}
@ -519,7 +537,7 @@ class _ParseAST {
ListWrapper.push(bindings, new TemplateBinding(key, keyIsVar, name, expression));
if (!this.optionalCharacter($SEMICOLON)) {
this.optionalCharacter($COMMA);
};
}
}
return bindings;
}

View File

@ -0,0 +1,117 @@
import {Observable, ObservableWrapper} from 'angular2/src/facade/async';
import {isBlank, isPresent, CONST} from 'angular2/src/facade/lang';
import {Pipe, WrappedValue, PipeFactory} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
/**
* Implements async bindings to Observable.
*
* # Example
*
* In this example we bind the description observable to the DOM. The async pipe will convert an observable to the
* latest value it emitted. It will also request a change detection check when a new value is emitted.
*
* ```
* @Component({
* selector: "task-cmp",
* changeDetection: ON_PUSH
* })
* @View({
* inline: "Task Description {{description|async}}"
* })
* class Task {
* description:Observable<string>;
* }
*
* ```
*
* @exportedAs angular2/pipes
*/
export class AsyncPipe extends Pipe {
_ref:ChangeDetectorRef;
_latestValue:Object;
_latestReturnedValue:Object;
_subscription:Object;
_observable:Observable;
constructor(ref:ChangeDetectorRef) {
super();
this._ref = ref;
this._latestValue = null;
this._latestReturnedValue = null;
this._subscription = null;
this._observable = null;
}
supports(obs):boolean {
return ObservableWrapper.isObservable(obs);
}
onDestroy():void {
if (isPresent(this._subscription)) {
this._dispose();
}
}
transform(obs:Observable):any {
if (isBlank(this._subscription)) {
this._subscribe(obs);
return null;
}
if (obs !== this._observable) {
this._dispose();
return this.transform(obs);
}
if (this._latestValue === this._latestReturnedValue) {
return this._latestReturnedValue;
} else {
this._latestReturnedValue = this._latestValue;
return WrappedValue.wrap(this._latestValue);
}
}
_subscribe(obs:Observable):void {
this._observable = obs;
this._subscription = ObservableWrapper.subscribe(obs,
value => this._updateLatestValue(value),
e => {throw e;}
);
}
_dispose():void {
ObservableWrapper.dispose(this._subscription);
this._latestValue = null;
this._latestReturnedValue = null;
this._subscription = null;
this._observable = null;
}
_updateLatestValue(value:Object) {
this._latestValue = value;
this._ref.requestCheck();
}
}
/**
* Provides a factory for [AsyncPipe].
*
* @exportedAs angular2/pipes
*/
export class AsyncPipeFactory extends PipeFactory {
@CONST()
constructor() {
super();
}
supports(obs):boolean {
return ObservableWrapper.isObservable(obs);
}
create(cdRef):Pipe {
return new AsyncPipe(cdRef);
}
}

View File

@ -1,3 +1,4 @@
import {CONST} from 'angular2/src/facade/lang';
import {
isListLikeIterable,
iterateListLike,
@ -14,19 +15,27 @@ import {
looseIdentical,
} from 'angular2/src/facade/lang';
import {NO_CHANGE, Pipe} from './pipe';
import {WrappedValue, Pipe, PipeFactory} from './pipe';
export class ArrayChangesFactory {
supports(obj):boolean {
return ArrayChanges.supportsObj(obj);
export class IterableChangesFactory extends PipeFactory {
@CONST()
constructor() {
super();
}
create():Pipe {
return new ArrayChanges();
supports(obj):boolean {
return IterableChanges.supportsObj(obj);
}
create(cdRef):Pipe {
return new IterableChanges();
}
}
export class ArrayChanges extends Pipe {
/**
* @exportedAs angular2/pipes
*/
export class IterableChanges extends Pipe {
_collection;
_length:int;
_linkedRecords:_DuplicateMap;
@ -66,7 +75,7 @@ export class ArrayChanges extends Pipe {
}
supports(obj):boolean {
return ArrayChanges.supportsObj(obj);
return IterableChanges.supportsObj(obj);
}
get collection() {
@ -114,9 +123,9 @@ export class ArrayChanges extends Pipe {
transform(collection){
if (this.check(collection)) {
return this;
return WrappedValue.wrap(this);
} else {
return NO_CHANGE;
return this;
}
}
@ -126,7 +135,8 @@ export class ArrayChanges extends Pipe {
var record:CollectionChangeRecord = this._itHead;
var mayBeDirty:boolean = false;
var index:int, item;
var index:int;
var item;
if (ListWrapper.isList(collection)) {
var list = collection;
@ -206,10 +216,10 @@ export class ArrayChanges extends Pipe {
/**
* This is the core function which handles differences between collections.
*
* - [record] is the record which we saw at this position last time. If null then it is a new
* - `record` is the record which we saw at this position last time. If null then it is a new
* item.
* - [item] is the current item in the collection
* - [index] is the position of the item in the collection
* - `item` is the current item in the collection
* - `index` is the position of the item in the collection
*/
_mismatch(record:CollectionChangeRecord, item, index:int):CollectionChangeRecord {
// The previous record after which we will append the current one.
@ -280,9 +290,9 @@ export class ArrayChanges extends Pipe {
}
/**
* Get rid of any excess [CollectionChangeRecord]s from the previous collection
* Get rid of any excess {@link CollectionChangeRecord}s from the previous collection
*
* - [record] The first excess [CollectionChangeRecord].
* - `record` The first excess {@link CollectionChangeRecord}.
*/
_truncate(record:CollectionChangeRecord) {
// Anything after that needs to be removed;
@ -500,6 +510,9 @@ export class ArrayChanges extends Pipe {
}
}
/**
* @exportedAs angular2/pipes
*/
export class CollectionChangeRecord {
currentIndex:int;
previousIndex:int;
@ -581,7 +594,7 @@ class _DuplicateItemRecordList {
}
/**
* Remove one [CollectionChangeRecord] from the list of duplicates.
* Remove one {@link CollectionChangeRecord} from the list of duplicates.
*
* Returns whether the list of duplicates is empty.
*/
@ -644,7 +657,7 @@ class _DuplicateMap {
}
/**
* Removes an [CollectionChangeRecord] from the list of duplicates.
* Removes a {@link CollectionChangeRecord} from the list of duplicates.
*
* The list of duplicates also is removed from the map if it gets empty.
*/

View File

@ -1,18 +1,29 @@
import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {stringify, looseIdentical, isJsObject} from 'angular2/src/facade/lang';
import {stringify, looseIdentical, isJsObject, CONST} from 'angular2/src/facade/lang';
import {NO_CHANGE, Pipe} from './pipe';
import {WrappedValue, Pipe, PipeFactory} from './pipe';
/**
* @exportedAs angular2/pipes
*/
export class KeyValueChangesFactory extends PipeFactory {
@CONST()
constructor() {
super();
}
export class KeyValueChangesFactory {
supports(obj):boolean {
return KeyValueChanges.supportsObj(obj);
}
create():Pipe {
create(cdRef):Pipe {
return new KeyValueChanges();
}
}
/**
* @exportedAs angular2/pipes
*/
export class KeyValueChanges extends Pipe {
_records:Map;
@ -48,9 +59,9 @@ export class KeyValueChanges extends Pipe {
transform(map){
if (this.check(map)) {
return this;
return WrappedValue.wrap(this);
} else {
return NO_CHANGE;
return this;
}
}
@ -107,9 +118,9 @@ export class KeyValueChanges extends Pipe {
var newSeqRecord;
if (oldSeqRecord !== null && key === oldSeqRecord.key) {
newSeqRecord = oldSeqRecord;
if (!looseIdentical(value, oldSeqRecord._currentValue)) {
oldSeqRecord._previousValue = oldSeqRecord._currentValue;
oldSeqRecord._currentValue = value;
if (!looseIdentical(value, oldSeqRecord.currentValue)) {
oldSeqRecord.previousValue = oldSeqRecord.currentValue;
oldSeqRecord.currentValue = value;
this._addToChanges(oldSeqRecord);
}
} else {
@ -124,7 +135,7 @@ export class KeyValueChanges extends Pipe {
} else {
newSeqRecord = new KVChangeRecord(key);
MapWrapper.set(records, key, newSeqRecord);
newSeqRecord._currentValue = value;
newSeqRecord.currentValue = value;
this._addToAdditions(newSeqRecord);
}
}
@ -158,11 +169,11 @@ export class KeyValueChanges extends Pipe {
}
for (record = this._changesHead; record !== null; record = record._nextChanged) {
record._previousValue = record._currentValue;
record.previousValue = record.currentValue;
}
for (record = this._additionsHead; record != null; record = record._nextAdded) {
record._previousValue = record._currentValue;
record.previousValue = record.currentValue;
}
// todo(vicb) once assert is supported
@ -215,8 +226,8 @@ export class KeyValueChanges extends Pipe {
}
for (var rec:KVChangeRecord = this._removalsHead; rec !== null; rec = rec._nextRemoved) {
rec._previousValue = rec._currentValue;
rec._currentValue = null;
rec.previousValue = rec.currentValue;
rec.currentValue = null;
MapWrapper.delete(this._records, rec.key);
}
}
@ -349,10 +360,13 @@ export class KeyValueChanges extends Pipe {
/**
* @exportedAs angular2/pipes
*/
export class KVChangeRecord {
key;
_previousValue;
_currentValue;
previousValue;
currentValue;
_nextPrevious:KVChangeRecord;
_next:KVChangeRecord;
@ -363,8 +377,8 @@ export class KVChangeRecord {
constructor(key) {
this.key = key;
this._previousValue = null;
this._currentValue = null;
this.previousValue = null;
this.currentValue = null;
this._nextPrevious = null;
this._next = null;
@ -375,9 +389,9 @@ export class KVChangeRecord {
}
toString():string {
return looseIdentical(this._previousValue, this._currentValue) ?
return looseIdentical(this.previousValue, this.currentValue) ?
stringify(this.key) :
(stringify(this.key) + '[' + stringify(this._previousValue) + '->' +
stringify(this._currentValue) + ']');
(stringify(this.key) + '[' + stringify(this.previousValue) + '->' +
stringify(this.currentValue) + ']');
}
}

View File

@ -1,16 +1,27 @@
import {isBlank} from 'angular2/src/facade/lang';
import {Pipe, NO_CHANGE} from './pipe';
import {isBlank, CONST} from 'angular2/src/facade/lang';
import {Pipe, WrappedValue, PipeFactory} from './pipe';
/**
* @exportedAs angular2/pipes
*/
export class NullPipeFactory extends PipeFactory {
@CONST()
constructor() {
super();
}
export class NullPipeFactory {
supports(obj):boolean {
return NullPipe.supportsObj(obj);
}
create():Pipe {
create(cdRef):Pipe {
return new NullPipe();
}
}
/**
* @exportedAs angular2/pipes
*/
export class NullPipe extends Pipe {
called:boolean;
constructor() {
@ -29,9 +40,9 @@ export class NullPipe extends Pipe {
transform(value) {
if (! this.called) {
this.called = true;
return null;
return WrappedValue.wrap(null);
} else {
return NO_CHANGE;
return null;
}
}
}

View File

@ -1,7 +1,78 @@
export var NO_CHANGE = new Object();
import {ABSTRACT, BaseException, CONST} from 'angular2/src/facade/lang';
/**
* Indicates that the result of a {@link Pipe} transformation has changed even though the reference has not changed.
*
* The wrapped value will be unwrapped by change detection, and the unwrapped value will be stored.
*
* @exportedAs angular2/pipes
*/
export class WrappedValue {
wrapped:any;
constructor(wrapped:any) {
this.wrapped = wrapped;
}
static wrap(value:any):WrappedValue {
var w = _wrappedValues[_wrappedIndex++ % 5];
w.wrapped = value;
return w;
}
}
var _wrappedValues = [
new WrappedValue(null),
new WrappedValue(null),
new WrappedValue(null),
new WrappedValue(null),
new WrappedValue(null)
];
var _wrappedIndex = 0;
/**
* An interface for extending the list of pipes known to Angular.
*
* If you are writing a custom {@link Pipe}, you must extend this interface.
*
* #Example
*
* ```
* class DoublePipe extends Pipe {
* supports(obj) {
* return true;
* }
*
* transform(value) {
* return `${value}${value}`;
* }
* }
* ```
*
* @exportedAs angular2/pipes
*/
export class Pipe {
supports(obj):boolean {return false;}
onDestroy() {}
transform(value:any):any {return null;}
}
}
@ABSTRACT()
export class PipeFactory {
@CONST()
constructor() {
}
supports(obs):boolean {
return _abstract();
}
create(cdRef):Pipe {
return _abstract();
}
}
function _abstract() {
return new BaseException('This method is abstract');
}

View File

@ -1,7 +1,10 @@
import {List, ListWrapper} from 'angular2/src/facade/collection';
import {isBlank, isPresent, BaseException, CONST} from 'angular2/src/facade/lang';
import {Pipe} from './pipe';
import {Injectable} from 'angular2/src/di/annotations_impl';
import {ChangeDetectorRef} from '../change_detector_ref';
@Injectable()
export class PipeRegistry {
config;
@ -9,19 +12,19 @@ export class PipeRegistry {
this.config = config;
}
get(type:string, obj):Pipe {
get(type:string, obj, cdRef:ChangeDetectorRef):Pipe {
var listOfConfigs = this.config[type];
if (isBlank(listOfConfigs)) {
throw new BaseException(`Cannot find a pipe for type '${type}' object '${obj}'`);
throw new BaseException(`Cannot find '${type}' pipe supporting object '${obj}'`);
}
var matchingConfig = ListWrapper.find(listOfConfigs,
(pipeConfig) => pipeConfig.supports(obj));
if (isBlank(matchingConfig)) {
throw new BaseException(`Cannot find a pipe for type '${type}' object '${obj}'`);
throw new BaseException(`Cannot find '${type}' pipe supporting object '${obj}'`);
}
return matchingConfig.create();
return matchingConfig.create(cdRef);
}
}
}

View File

@ -22,11 +22,13 @@ import {
PrefixNot
} from './parser/ast';
import {ChangeRecord, ChangeDispatcher, ChangeDetector} from './interfaces';
import {ChangeDispatcher, ChangeDetector, ProtoChangeDetector} from './interfaces';
import {ChangeDetectionUtil} from './change_detection_util';
import {DynamicChangeDetector} from './dynamic_change_detector';
import {ChangeDetectorJITGenerator} from './change_detection_jit_generator';
import {PipeRegistry} from './pipes/pipe_registry';
import {BindingRecord} from './binding_record';
import {DirectiveRecord, DirectiveIndex} from './directive_record';
import {coalesce} from './coalesce';
@ -41,47 +43,38 @@ import {
RECORD_TYPE_PRIMITIVE_OP,
RECORD_TYPE_KEYED_ACCESS,
RECORD_TYPE_PIPE,
RECORD_TYPE_BINDING_PIPE,
RECORD_TYPE_INTERPOLATE
} from './proto_record';
export class ProtoChangeDetector {
addAst(ast:AST, bindingMemento:any, directiveMemento:any = null){}
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List):ChangeDetector{
return null;
}
}
export class BindingRecord {
ast:AST;
bindingMemento:any;
directiveMemento:any;
constructor(ast:AST, bindingMemento:any, directiveMemento:any) {
this.ast = ast;
this.bindingMemento = bindingMemento;
this.directiveMemento = directiveMemento;
}
}
export class DynamicProtoChangeDetector extends ProtoChangeDetector {
_pipeRegistry:PipeRegistry;
_records:List<ProtoRecord>;
_bindingRecords:List<BindingRecord>;
_variableBindings:List<string>;
_directiveRecords:List<DirectiveRecord>;
_changeControlStrategy:string;
constructor(pipeRegistry:PipeRegistry) {
constructor(pipeRegistry:PipeRegistry, bindingRecords:List, variableBindings:List, directiveRecords:List, changeControlStrategy:string) {
super();
this._pipeRegistry = pipeRegistry;
this._bindingRecords = bindingRecords;
this._variableBindings = variableBindings;
this._directiveRecords = directiveRecords;
this._changeControlStrategy = changeControlStrategy;
}
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List) {
this._createRecordsIfNecessary(bindingRecords, variableBindings);
return new DynamicChangeDetector(dispatcher, this._pipeRegistry, this._records);
instantiate(dispatcher:any) {
this._createRecordsIfNecessary();
return new DynamicChangeDetector(this._changeControlStrategy, dispatcher,
this._pipeRegistry, this._records, this._directiveRecords);
}
_createRecordsIfNecessary(bindingRecords:List, variableBindings:List) {
_createRecordsIfNecessary() {
if (isBlank(this._records)) {
var recordBuilder = new ProtoRecordBuilder();
ListWrapper.forEach(bindingRecords, (r) => {
recordBuilder.addAst(r.ast, r.bindingMemento, r.directiveMemento, variableBindings);
ListWrapper.forEach(this._bindingRecords, (b) => {
recordBuilder.addAst(b, this._variableBindings);
});
this._records = coalesce(recordBuilder.records);
}
@ -92,28 +85,37 @@ var _jitProtoChangeDetectorClassCounter:number = 0;
export class JitProtoChangeDetector extends ProtoChangeDetector {
_factory:Function;
_pipeRegistry;
_bindingRecords:List<BindingRecord>;
_variableBindings:List<string>;
_directiveRecords:List<DirectiveRecord>;
_changeControlStrategy:string;
constructor(pipeRegistry) {
constructor(pipeRegistry, bindingRecords:List, variableBindings:List, directiveRecords:List, changeControlStrategy:string) {
super();
this._pipeRegistry = pipeRegistry;
this._factory = null;
this._bindingRecords = bindingRecords;
this._variableBindings = variableBindings;
this._directiveRecords = directiveRecords;
this._changeControlStrategy = changeControlStrategy;
}
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List) {
this._createFactoryIfNecessary(bindingRecords, variableBindings);
instantiate(dispatcher:any) {
this._createFactoryIfNecessary();
return this._factory(dispatcher, this._pipeRegistry);
}
_createFactoryIfNecessary(bindingRecords:List, variableBindings:List) {
_createFactoryIfNecessary() {
if (isBlank(this._factory)) {
var recordBuilder = new ProtoRecordBuilder();
ListWrapper.forEach(bindingRecords, (r) => {
recordBuilder.addAst(r.ast, r.bindingMemento, r.directiveMemento, variableBindings);
ListWrapper.forEach(this._bindingRecords, (b) => {
recordBuilder.addAst(b, this._variableBindings);
});
var c = _jitProtoChangeDetectorClassCounter++;
var records = coalesce(recordBuilder.records);
var typeName = `ChangeDetector${c}`;
this._factory = new ChangeDetectorJITGenerator(typeName, records).generate();
this._factory = new ChangeDetectorJITGenerator(typeName, this._changeControlStrategy, records,
this._directiveRecords).generate();
}
}
}
@ -125,13 +127,13 @@ class ProtoRecordBuilder {
this.records = [];
}
addAst(ast:AST, bindingMemento:any, directiveMemento:any = null, variableBindings:List = null) {
addAst(b:BindingRecord, variableBindings:List = null) {
var last = ListWrapper.last(this.records);
if (isPresent(last) && last.directiveMemento == directiveMemento) {
if (isPresent(last) && last.bindingRecord.directiveRecord == b.directiveRecord) {
last.lastInDirective = false;
}
var pr = _ConvertAstIntoProtoRecords.convert(ast, bindingMemento, directiveMemento, this.records.length, variableBindings);
var pr = _ConvertAstIntoProtoRecords.convert(b, this.records.length, variableBindings);
if (! ListWrapper.isEmpty(pr)) {
var last = ListWrapper.last(pr);
last.lastInBinding = true;
@ -144,29 +146,27 @@ class ProtoRecordBuilder {
class _ConvertAstIntoProtoRecords {
protoRecords:List;
bindingMemento:any;
directiveMemento:any;
bindingRecord:BindingRecord;
variableBindings:List;
contextIndex:number;
expressionAsString:string;
constructor(bindingMemento:any, directiveMemento:any, contextIndex:number, expressionAsString:string, variableBindings:List) {
constructor(bindingRecord:BindingRecord, contextIndex:number, expressionAsString:string, variableBindings:List) {
this.protoRecords = [];
this.bindingMemento = bindingMemento;
this.directiveMemento = directiveMemento;
this.bindingRecord = bindingRecord;
this.contextIndex = contextIndex;
this.expressionAsString = expressionAsString;
this.variableBindings = variableBindings;
}
static convert(ast:AST, bindingMemento:any, directiveMemento:any, contextIndex:number, variableBindings:List) {
var c = new _ConvertAstIntoProtoRecords(bindingMemento, directiveMemento, contextIndex, ast.toString(), variableBindings);
ast.visit(c);
static convert(b:BindingRecord, contextIndex:number, variableBindings:List) {
var c = new _ConvertAstIntoProtoRecords(b, contextIndex, b.ast.toString(), variableBindings);
b.ast.visit(c);
return c.protoRecords;
}
visitImplicitReceiver(ast:ImplicitReceiver) {
return 0;
return this.bindingRecord.implicitReceiver;
}
visitInterpolation(ast:Interpolation) {
@ -181,7 +181,9 @@ class _ConvertAstIntoProtoRecords {
visitAccessMember(ast:AccessMember) {
var receiver = ast.receiver.visit(this);
if (isPresent(this.variableBindings) && ListWrapper.contains(this.variableBindings, ast.name)) {
if (isPresent(this.variableBindings) &&
ListWrapper.contains(this.variableBindings, ast.name) &&
ast.receiver instanceof ImplicitReceiver) {
return this._addRecord(RECORD_TYPE_LOCAL, ast.name, ast.name, [], null, receiver);
} else {
return this._addRecord(RECORD_TYPE_PROPERTY, ast.name, ast.getter, [], null, receiver);
@ -239,7 +241,8 @@ class _ConvertAstIntoProtoRecords {
visitPipe(ast:Pipe) {
var value = ast.exp.visit(this);
return this._addRecord(RECORD_TYPE_PIPE, ast.name, ast.name, [], null, value);
var type = ast.inBinding ? RECORD_TYPE_BINDING_PIPE : RECORD_TYPE_PIPE;
return this._addRecord(type, ast.name, ast.name, [], null, value);
}
visitKeyedAccess(ast:KeyedAccess) {
@ -259,9 +262,15 @@ class _ConvertAstIntoProtoRecords {
_addRecord(type, name, funcOrValue, args, fixedArgs, context) {
var selfIndex = ++ this.contextIndex;
ListWrapper.push(this.protoRecords,
new ProtoRecord(type, name, funcOrValue, args, fixedArgs, context, selfIndex,
this.bindingMemento, this.directiveMemento, this.expressionAsString, false, false));
if (context instanceof DirectiveIndex) {
ListWrapper.push(this.protoRecords,
new ProtoRecord(type, name, funcOrValue, args, fixedArgs, -1, context, selfIndex,
this.bindingRecord, this.expressionAsString, false, false));
} else {
ListWrapper.push(this.protoRecords,
new ProtoRecord(type, name, funcOrValue, args, fixedArgs, context, null, selfIndex,
this.bindingRecord, this.expressionAsString, false, false));
}
return selfIndex;
}
}
@ -356,4 +365,4 @@ function _interpolationFn(strings:List) {
case 9: return (a1, a2, a3, a4, a5, a6, a7, a8, a9) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + c4 + s(a5) + c5 + s(a6) + c6 + s(a7) + c7 + s(a8) + c8 + s(a9) + c9;
default: throw new BaseException(`Does not support more than 9 expressions`);
}
}
}

View File

@ -1,4 +1,6 @@
import {List} from 'angular2/src/facade/collection';
import {BindingRecord} from './binding_record';
import {DirectiveIndex} from './directive_record';
export const RECORD_TYPE_SELF = 0;
export const RECORD_TYPE_CONST = 1;
@ -9,7 +11,8 @@ export const RECORD_TYPE_INVOKE_METHOD = 5;
export const RECORD_TYPE_INVOKE_CLOSURE = 6;
export const RECORD_TYPE_KEYED_ACCESS = 7;
export const RECORD_TYPE_PIPE = 8;
export const RECORD_TYPE_INTERPOLATE = 9;
export const RECORD_TYPE_BINDING_PIPE = 9;
export const RECORD_TYPE_INTERPOLATE = 10;
export class ProtoRecord {
mode:number;
@ -17,10 +20,12 @@ export class ProtoRecord {
funcOrValue:any;
args:List;
fixedArgs:List;
contextIndex:number;
directiveIndex:DirectiveIndex;
selfIndex:number;
bindingMemento:any;
directiveMemento:any;
bindingRecord:BindingRecord;
lastInBinding:boolean;
lastInDirective:boolean;
expressionAsString:string;
@ -31,9 +36,9 @@ export class ProtoRecord {
args:List,
fixedArgs:List,
contextIndex:number,
directiveIndex:DirectiveIndex,
selfIndex:number,
bindingMemento:any,
directiveMemento:any,
bindingRecord:BindingRecord,
expressionAsString:string,
lastInBinding:boolean,
lastInDirective:boolean) {
@ -43,10 +48,12 @@ export class ProtoRecord {
this.funcOrValue = funcOrValue;
this.args = args;
this.fixedArgs = fixedArgs;
this.contextIndex = contextIndex;
this.directiveIndex = directiveIndex;
this.selfIndex = selfIndex;
this.bindingMemento = bindingMemento;
this.directiveMemento = directiveMemento;
this.bindingRecord = bindingRecord;
this.lastInBinding = lastInBinding;
this.lastInDirective = lastInDirective;
this.expressionAsString = expressionAsString;

View File

@ -0,0 +1,8 @@
/**
* This indirection is needed for TS compilation path.
* See comment in annotations.es6.
*/
library angular2.core.annotations.annotations;
export "../annotations_impl/annotations.dart";

View File

@ -0,0 +1,10 @@
/**
* This indirection is needed to free up Component, etc symbols in the public API
* to be used by the decorator versions of these annotations.
*/
export {
Component as ComponentAnnotation,
Directive as DirectiveAnnotation,
onDestroy, onChange, onAllChangesDone
} from '../annotations_impl/annotations';

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