chore(Dart): remove obsolete files, update the docs

This commit is contained in:
Victor Berchet 2016-07-21 11:48:23 -07:00
parent 51f3d22e4f
commit e73ac1e992
272 changed files with 7 additions and 14339 deletions

View File

@ -95,7 +95,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
* In GitHub, send a pull request to `angular:master`.
* If we suggest changes then:
* Make the required updates.
* Re-run the Angular 2 test suites for JS and Dart to ensure tests are still passing.
* Re-run the Angular 2 test suites to ensure tests are still passing.
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
```shell

View File

@ -5,8 +5,7 @@ JS and Dart versions. It also explains the basic mechanics of using `git`, `node
* [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)
* [Installing NPM Modules](#installing-npm-modules)
* [Building](#building)
* [Running Tests Locally](#running-tests-locally)
@ -27,15 +26,6 @@ following products on your development machine:
(version `>=3.5.3 <4.0`), which comes with Node. Depending on your system, you can install Node either from
source or as a pre-packaged bundle.
* *Optional*: [Dart](https://www.dartlang.org) (version `>=1.13.2 <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). Visit Dart's [Downloads page](https://www.dartlang.org/downloads) page for
instructions. You can also download both **stable** and **dev** channel versions from the
[download archive](https://www.dartlang.org/downloads/archive/). In that case, on Windows, Dart
must be added to the `PATH` (e.g. `path-to-dart-sdk-folder\bin`) and a new `DARTIUM_BIN`
environment variable must be created, pointing to the executable (e.g.
`path-to-dartium-folder\chrome.exe`).
* [Java Development Kit](http://www.oracle.com/technetwork/es/java/javase/downloads/index.html) which is used
to execute the selenium standalone server for e2e testing.
@ -60,42 +50,7 @@ cd angular
# Add the main Angular repository as an upstream remote to your repository:
git remote add upstream https://github.com/angular/angular.git
```
## Environment Variable Setup
Define the environment variables listed below. These are mainly needed for the testing. The
notation shown here is for [`bash`](http://www.gnu.org/software/bash); adapt as appropriate for
your favorite shell.
Examples given below of possible values for initializing the environment variables assume **Mac OS
X** and that you have installed the Dart Editor in the directory named by
`DART_EDITOR_DIR=/Applications/dart`. This is only for illustrative purposes.
```shell
# DARTIUM_BIN: path to a Dartium browser executable; used by Karma to run Dart tests
export DARTIUM_BIN="$DART_EDITOR_DIR/chromium/Chromium.app/Contents/MacOS/Chromium"
```
Add the Dart SDK `bin` directory to your path and/or define `DART_SDK` (this is also detailed
[here](https://www.dartlang.org/tools/pub/installing.html)):
```shell
# DART_SDK: path to a Dart SDK directory
export DART_SDK="$DART_EDITOR_DIR/dart-sdk"
# Update PATH to include the Dart SDK bin directory
PATH+=":$DART_SDK/bin"
```
And specify where the pubs dependencies are downloaded. By default, this directory is located under .pub_cache
in your home directory (on Mac and Linux), or in AppData\Roaming\Pub\Cache (on Windows).
```shell
# PUB_CACHE: location of pub dependencies
export PUB_CACHE="/Users/<user>/.pub-cache"
```
## Installing NPM Modules and Dart Packages
## Installing NPM Modules
Next, install the JavaScript modules and Dart packages needed to build and test Angular:

View File

@ -12,7 +12,9 @@ Angular
=========
Angular is a development platform for building mobile and desktop web applications. This is the
repository for [Angular 2][ng2], both the JavaScript (JS) and [Dart][dart] versions.
repository for [Angular 2][ng2] Typescript/JavaScript (JS).
Angular2 for [Dart][dart] can be found at [dart-lang/angular2][ng2dart].
Angular 2 is currently in **Release Candidate**.
@ -34,3 +36,4 @@ guidelines for [contributing][contributing] and then check out one of our issues
[ng2]: http://angular.io
[ngDart]: http://angulardart.org
[ngJS]: http://angularjs.org
[ng2dart]: https://github.com/dart-lang/angular2

View File

@ -1,376 +0,0 @@
# Developer Tools for Dart
Use these tools and techniques to increase your app's performance
and reliability.
* [Angular debugging tools](#angular-debugging-tools)
* [Code size](#code-size)
* [Performance](#performance)
## Angular debugging tools
Starting with alpha.38, Angular provides a set of debugging tools
that are accessible from any browser's developer console.
In Chrome, you can get to the dev console by pressing
Ctrl + Shift + J (on Mac: Cmd + Opt + J).
### Enabling the debugging tools
By default the debugging tools are disabled.
Enable the debugging tools as follows:
```dart
import 'package:angular2/platform/browser.dart';
main() async {
var appRef = await bootstrap(Application);
enableDebugTools(appRef);
}
```
<!-- Change function name to enableDebuggingTools? -->
### Using the debugging tools
In the browser, open the dev console. The top-level object is called `ng` and
contains more specific tools inside it.
For example, to run the change detection profiler on your app:
```javascript
// In the dev console:
ng.profiler.timeChangeDetection();
```
The [Change detection profiler](#change-detection-profiler) section
has more details.
<!-- Point to API docs when they're published, if they're useful.
They should be under
http://www.dartdocs.org/documentation/angular2/latest
and/or
https://angular.io/docs/js/latest/api/. -->
## Code size
Code must be downloaded, parsed, and executed. Too much code can lead to
slow application start-up time, especially on slow networks and low-end devices.
The tools and techniques in this section can help you to identify
unnecessarily large code and to reduce code size.
### Finding contributors to code size
Options for investigating code size include the `--dump-info` dart2js option,
ng2soyc, `reflector.trackUsage()`, and code coverage information
from the Dart VM.
#### Use --dump-info
The `--dump-info` option of `dart2js` outputs information about what happened
during compilation. You can specify `--dump-info` in `pubspec.yaml`:
```yaml
transformers:
...
- $dart2js:
commandLineOptions:
- --dump-info
```
The [Dump Info Visualizer](https://github.com/dart-lang/dump-info-visualizer)
can help you analyze the output.
For more information, see the
[dart2js_info API reference](http://dart-lang.github.io/dart2js_info/doc/api/).
#### Use ng2soyc.dart
[ng2soyc](https://github.com/angular/ng2soyc.dart) is a utility for analyzing
code size contributors in Angular 2 applications. It groups code size by
library and, assuming your library names follow
[standard naming conventions](https://www.dartlang.org/articles/style-guide/#do-prefix-library-names-with-the-package-name-and-a-dot-separated-path)
(package.library.sublibrary...), gives the code size breakdown at
each level. To reduce noise in the output of very large apps, ng2soyc provides
an option to hide libraries that are too small, so you can focus on the biggest
contributors.
#### Find unused reflection data
Your app might have types that are annotated with `@Component` or `@Injectable`
but never used.
To find these unused types, use `reflector.trackUsage()` and then,
after exercising your app, `reflector.listUnusedKeys()`.
For example:
```
import 'package:angular2/src/core/reflection/reflection.dart';
...
main() async {
reflector.trackUsage();
await bootstrap(AppComponent);
print('Unused keys: ${reflector.listUnusedKeys()}');
}
```
When you run that code (in Dartium or another browser),
you'll see a list of types that Angular _can_ inject but hasn't needed to.
Consider removing those types or their `@Component`/`@Injectable` annotation
to decrease your app's code size.
Three conditions must be true for `listUnusedKeys()` to return helpful data:
1. The angular2 transformer must run on the app.
2. If you're running a JavaScript version of the app,
the app must not be minified, so that the names are readable.
3. You must exercise your app in as many ways as possible
before calling `listUnusedKeys()`.
Otherwise, you might get false positives:
keys that haven't been used only because you didn't exercise
the relevant feature of the app.
To run the angular2 transformer, first specify it in `pubspec.yaml`:
```
name: hello_world
...
transformers:
- angular2:
entry_points: web/main.dart
```
Then use pub to run the transformer. If you use `pub serve`,
it provides both Dart and unminified (by default) JavaScript versions.
If you want to serve actual files, then use `pub build` in debug mode
to generate Dart and unminified JavaScript files:
`pub build --mode=debug`.
The `reflector.trackUsage()` method makes Angular track the reflection
information used by the app. Reflection information (`ReflectionInfo`) is a data
structure that stores information that Angular uses for locating DI factories
and for generating change detectors and other code related to a
given type.
#### Use code coverage to find dead code
When running in Dartium (or in the Dart VM, in general) you can request code
coverage information from the VM. You can either use
[observatory](https://www.dartlang.org/tools/observatory/) or download
the coverage file and use your own tools to inspect it. Lines of code that are
not covered are top candidates for dead code.
Keep in mind, however, that uncovered code is not sufficient evidence of dead
code, only necessary evidence. It is perfectly possible that you simply didn't
exercise your application in a way that triggers the execution of uncovered
code. A common example is error handling code. Just because your testing never
encountered an error does not mean the error won't happen in production. You
therefore don't have to rush and remove all the `catch` blocks.
### Reducing code size
To reduce code size, you can disable reflection,
enable minification, and manually remove dead code.
You can also try less safe options such as
telling dart2js to trust type annotations.
#### Disable reflection
`dart:mirrors` allows discovering program metadata at runtime. However, this
means that `dart2js` needs to retain that metadata and thus increase the size
of resulting JS output. In practice, however, it is possible to extract most
metadata necessary for your metaprogramming tasks statically using a
transformer and `package:analyzer`, and act on it before compiling to JS.
#### Enable minification
Minification shortens all your `longMethodNames` into 2- or 3-letter long
symbols. `dart2js` ensures that this kind of renaming is done safely, without
breaking the functionality of your programs. You can enable it in `pubspec.yaml`
under `$dart2js` transformer:
```yaml
transformers:
...
- $dart2js:
minify: true
```
#### Manually remove dead code
`dart2js` comes with dead code elimination out-of-the-box. However, it may not
always be able to tell if a piece of code could be used. Consider the following
example:
```dart
/// This function decides which serialization format to use
void setupSerializers() {
if (server.doYouSupportProtocolBuffers()) {
useProtobufSerializers();
} else {
useJsonSerializers();
}
}
```
In this example the application asks the server what kind of serialization
format it uses and dynamically chooses one or the other. `dart2js` can't
tell whether the server responds with yes or no, so it must retain both
kinds of serializers. However, if you know that your server supports
protocol buffers, you can remove that `if` block entirely and default to
protocol buffers.
Code coverage (see above) is a good way to find dead code in your app.
#### Unsafe options
Dart also provides more aggressive optimization options. However, you have to
be careful when using them and as of today the benefits aren't that clear. If
your type annotations are inaccurate you may end up with non-Darty runtime
behavior, including the classic "undefined is not a function" tautology, as
well as the "keep on truckin'" behavior, e.g. `null + 1 == 1` and
`{} + [] == 0`.
`--trust-type-annotations` tells `dart2js` to trust that your type annotations
are correct. So if you have a function `foo(Bar bar)` the compiler can omit the
check that `bar` is truly `Bar` when calling methods on it.
`--trust-primitives` tells `dart2js` that primitive types, such as numbers and
booleans are never `null` when performing arithmetic, and that your program
does not run into range error when operating on lists, letting the compiler
remove some of the error checking code.
Specify these options in `pubspec.yaml`.
Example:
```yaml
transformers:
...
- $dart2js:
commandLineOptions:
- --trust-type-annotations
- --trust-primitives
```
## Performance
### Change detection profiler
If your application is janky (it misses frames) or is slow according to other
metrics, you need to find out why. This tool helps by measuring the average
speed of _change detection_, a phase in Angular's
lifecycle that detects changes in values that are bound to the UI.
Janky UI updates can result from slowness either in _computing_ the changes or
in _applying_ those changes to the UI.
For your app to be performant, the process of _computing_ changes must be very
fast—preferably **under 3 milliseconds**.
Fast change computation leaves room for
the application logic, UI updates, and browser rendering pipeline
to fit within a 16 ms frame (assuming a target frame rate of 60 FPS).
The change detection profiler repeatedly performs change detection
without invoking any user actions, such as clicking buttons or entering
text in input fields. It then computes the average amount of time
(in milliseconds) to perform a single cycle of change detection and
prints that to the console. This number depends on the current state of the UI. You are likely to see different numbers
as you go from one screen in your application to another.
#### Running the profiler
Before running the profiler, enable the debugging tools
and put the app into the state you want to measure:
1. If you haven't already done so,
[enable the debugging tools](#enabling-the-debugging-tools).
2. Navigate the app to a screen whose performance you want to profile.
3. Make sure the screen is in a state that you want to measure.
For example, you might want to profile the screen several times,
with different amounts and kinds of data.
To run the profiler, enter the following in the dev console:
```javascript
ng.profiler.timeChangeDetection();
```
The results are visible in the console.
#### Recording CPU profiles
To record a profile, pass `{record: true}` to `timeChangeDetection()`:
```javascript
ng.profiler.timeChangeDetection({record: true});
```
Then open the **Profiles** tab. The recorded profile has the title
**Change Detection**. In Chrome, if you record the profile repeatedly, all the
profiles are nested under Change Detection.
#### Interpreting the numbers
In a properly designed application, repeated attempts to detect changes without
any user actions result in no changes to the UI. It is
also desirable to have the cost of a user action be proportional to the amount
of UI changes required. For example, popping up a menu with 5 items should be
vastly faster than rendering a table of 500 rows and 10 columns. Therefore,
change detection with no UI updates should be as fast as possible.
#### Investigating slow change detection
So you found a screen in your application on which the profiler reports a very
high number (i.e. >3ms). This is where a recorded CPU profile can help. Enable
recording while profiling:
```javascript
ng.profiler.timeChangeDetection({record: true});
```
Then look for hot spots using
[Chrome CPU profiler](https://developer.chrome.com/devtools/docs/cpu-profiling).
#### Reducing change detection cost
There are many reasons for slow change detection. To gain intuition about
possible causes it helps to understand how change detection works. Such a
discussion is outside the scope of this document,
but here are some key concepts.
<!-- TODO: link to change detection docs -->
By default, Angular uses a _dirty checking_ mechanism to find model changes.
This mechanism involves evaluating every bound expression that's active on the
UI. These usually include text interpolation via `{{expression}}` and property
bindings via `[prop]="expression"`. If any of the evaluated expressions are
costly to compute, they might contribute to slow change detection. A good way to
speed things up is to use plain class fields in your expressions and avoid any
kind of computation. For example:
```dart
@View(
template: '<button [enabled]="isEnabled">{{title}}</button>'
)
class FancyButton {
// GOOD: no computation, just returns the value
bool isEnabled;
// BAD: computes the final value upon request
String _title;
String get title => _title.trim().toUpperCase();
}
```
Most cases like these can be solved by precomputing the value and storing the
final value in a field.
Angular also supports a second type of change detection: the _push_ model. In
this model, Angular does not poll your component for changes. Instead, the
component tells Angular when it changes, and only then does Angular perform
the update. This model is suitable in situations when your data model uses
observable or immutable objects.
<!-- TODO: link to discussion of push model -->

View File

@ -1,34 +0,0 @@
This directory contains pure Dart packages that use standard pub layout.
# Working with an existing package
1. Run `gulp build.dart`
1. Open the package in any Dart IDE of your choice
1. Tada!
You do not need to rerun step 1 if you are only making changes in
`modules_dart`. However, you do need to run it again after you make a change
in `modules`. This is because these packages depend on code inside the `dist`
directory via `dependency_overrides`. Code in `modules` need to be transpiled
into `dist` before the IDE can "feel" your changes in `modules`.
# Creating a new package
1. Create a new directory with its own `pubspec.yaml` and standard pub layout.
1. Add both a normal dependency on `angular2` _and_ a `dependency_overrides`,
like this:
```yaml
version: 0.0.0
dependencies:
angular2: '0.0.0'
dependency_overrides:
angular2:
path: ../../dist/dart/angular2
```
The publishing script will automatically rewrite version numbers, so use
`0.0.0` both for your package and `angular2` version. Similarly, do not
include `authors` and `homepage`, as they will be auto-populated. However,
do provide `description`, `name` (prefixed with `angular2_`), `dependencies`,
and `dev_dependencies`.

View File

@ -1,46 +0,0 @@
Contains helpers to run unit tests for angular2 components and injectables,
backed by the `package:test` [library](https://pub.dartlang.org/packages/test).
Usage
-----
Update the dev dependencies in your `pubspec.yaml` to include the angular testing
and test packages:
```yaml
dev_dependencies:
test: '^0.12.6'
angular2_testing: any
```
Then in your test files, use angular2_testing helpers in place of `setUp` and `test`:
```dart
import 'package:test/test.dart';
import 'package:angular2_testing/angular2_testing.dart';
void main() {
// This must be called at the beginning of your tests.
initAngularTests();
// Initialize the injection tokens you will use in your tests.
setUpProviders(() => [provide(MyToken, useValue: 'my string'), TestService]);
// You can then get tokens from the injector via ngSetUp and ngTest.
ngSetUp((TestService testService) {
testService.initialize();
});
ngTest('can grab injected values', (@Inject(MyToken) token, TestService testService) {
expect(token, equals('my string'));
expect(testService.status, equals('ready'));
});
}
```
Examples
--------
A sample test is available in `test/angular2_testing_test.dart`.

View File

@ -1,120 +0,0 @@
library angular2_testing.angular2_testing;
import 'package:test/test.dart';
import 'package:angular2/angular2.dart';
import 'package:angular2/src/core/di/metadata.dart' show InjectMetadata;
import 'package:angular2/src/core/di/reflective_exceptions.dart' show NoAnnotationError;
import 'package:angular2/src/core/reflection/reflection.dart';
import 'package:angular2/src/core/reflection/reflection_capabilities.dart';
import 'package:angular2/src/testing/test_injector.dart';
export 'package:angular2/src/testing/test_component_builder.dart';
export 'package:angular2/src/testing/test_injector.dart' show inject;
import 'package:angular2/platform/testing/browser.dart';
/// One time initialization that must be done for Angular2 component
/// tests. Call before any test methods.
///
/// Example:
///
/// ```
/// main() {
/// initAngularTests();
/// group(...);
/// }
/// ```
void initAngularTests() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS, TEST_BROWSER_APPLICATION_PROVIDERS);
}
void _addTestInjectorTearDown() {
// Multiple resets are harmless.
tearDown(() {
_testInjector.reset();
});
}
/// Allows overriding default bindings defined in test_injector.dart.
///
/// The given function must return a list of DI providers.
///
/// Example:
///
/// ```
/// setUpProviders(() => [
/// provide(Compiler, useClass: MockCompiler),
/// provide(SomeToken, useValue: myValue),
/// ]);
/// ```
void setUpProviders(Iterable<Provider> providerFactory()) {
setUp(() {
try {
_testInjector.addProviders(providerFactory());
} catch (e) {
throw 'setUpProviders was called after the injector had '
'been used in a setUp or test block. This invalidates the '
'test injector';
}
});
_addTestInjectorTearDown();
}
dynamic _runInjectableFunction(Function fn) {
var params = reflector.parameters(fn);
List<dynamic> tokens = <dynamic>[];
for (var param in params) {
var token = null;
for (var paramMetadata in param) {
if (paramMetadata is Type) {
token = paramMetadata;
} else if (paramMetadata is InjectMetadata) {
token = paramMetadata.token;
}
}
if (token == null) {
throw new NoAnnotationError(fn, params);
}
tokens.add(token);
}
return _testInjector.execute(tokens, fn);
}
/// Use the test injector to get bindings and run a function.
///
/// Example:
///
/// ```
/// ngSetUp((SomeToken token) {
/// token.init();
/// });
/// ```
void ngSetUp(Function fn) {
setUp(() async {
await _runInjectableFunction(fn);
});
_addTestInjectorTearDown();
}
/// Add a test which can use the test injector.
///
/// Example:
///
/// ```
/// ngTest('description', (SomeToken token) {
/// expect(token, equals('expected'));
/// });
/// ```
void ngTest(String description, Function fn,
{String testOn, Timeout timeout, skip, Map<String, dynamic> onPlatform}) {
test(description, () async {
await _runInjectableFunction(fn);
}, testOn: testOn, timeout: timeout, skip: skip, onPlatform: onPlatform);
_addTestInjectorTearDown();
}
final TestInjector _testInjector = getTestInjector();

View File

@ -1,18 +0,0 @@
name: angular2_testing
description: 'Helpers to run unit tests for angular2 components and injectables.'
version: 0.0.0
environment:
sdk: '>=1.10.0 <2.0.0'
dependencies:
# This will be overridden by scripts/publish/pubspec_cleaner
# to point to the current version of Angular2.
angular2:
path: '../angular2'
dev_dependencies:
test: '^0.12.6'
quiver: '^0.21.4'
transformers:
# Allows testing with `pub serve`
# See https://github.com/dart-lang/test#testing-with-barback
- test/pub_serve:
$include: test/**_test.dart

View File

@ -1,117 +0,0 @@
// Because Angular is using dart:html, we need these tests to run on an actual
// browser. This means that it should be run with `-p dartium` or `-p chrome`.
@TestOn('browser')
import 'package:angular2/angular2.dart'
show Component, View, NgFor, provide, Inject, Injectable, Optional;
import 'package:test/test.dart';
import 'package:angular2_testing/angular2_testing.dart';
// This is the component we will be testing.
@Component(selector: 'test-cmp')
@View(directives: const [NgFor])
class TestComponent {
List<num> items;
TestComponent() {
this.items = [1, 2];
}
}
@Injectable()
class TestService {
String status = 'not ready';
init() {
this.status = 'ready';
}
}
@Component(selector: 'external-template-cmp')
@View(templateUrl: 'test_template.html')
class ExternalTemplateComponent {
ExternalTemplateComponent() {
}
}
class MyToken {}
const TEMPLATE =
'<div><copy-me template=\'ngFor let item of items\'>{{item.toString()}};</copy-me></div>';
void main() {
initAngularTests();
setUpProviders(() => [provide(MyToken, useValue: 'my string'), TestService]);
test('normal function', () {
var string = 'foo,bar,baz';
expect(string.split(','), equals(['foo', 'bar', 'baz']));
});
ngTest('can grab injected values',
(@Inject(MyToken) token, TestService testService) {
expect(token, equals('my string'));
expect(testService.status, equals('not ready'));
});
group('nested ngSetUp', () {
ngSetUp((TestService testService) {
testService.init();
});
ngTest('ngSetUp modifies injected services', (TestService testService) {
expect(testService.status, equals('ready'));
});
});
ngTest('create a component using the TestComponentBuilder',
(TestComponentBuilder tcb) async {
var rootTC = await tcb
.overrideTemplate(TestComponent, TEMPLATE)
.createAsync(TestComponent);
rootTC.detectChanges();
expect(rootTC.debugElement.nativeElement.text, equals('1;2;'));
});
ngTest('should reflect added elements', (TestComponentBuilder tcb) async {
var rootTC = await tcb
.overrideTemplate(TestComponent, TEMPLATE)
.createAsync(TestComponent);
rootTC.detectChanges();
(rootTC.debugElement.componentInstance.items as List<num>).add(3);
rootTC.detectChanges();
expect(rootTC.debugElement.nativeElement.text, equals('1;2;3;'));
});
ngTest('should allow a component using a templateUrl', (TestComponentBuilder tcb) async {
var rootTC = await tcb
.createAsync(ExternalTemplateComponent);
rootTC.detectChanges();
expect(rootTC.debugElement.nativeElement.text, equals('from external template\n'));
});
group('expected failures', () {
ngTest('no type in param list', (notTyped) {
expect(1, equals(2));
});
ngSetUp((TestService testService) {
testService.init();
});
// This would fail, since setUpProviders is used after a call to ngSetUp has already
// initialized the injector.
group('nested', () {
setUpProviders(() => [TestService]);
test('foo', () {
expect(1 + 1, equals(2));
});
});
}, skip: 'expected failures');
}

View File

@ -1 +0,0 @@
<span>from external template</span>

View File

@ -1,23 +0,0 @@
name: hello_world
environment:
sdk: '>=1.10.0 <2.0.0'
dependencies:
observe: '^0.13.1'
angular2: any
browser: '^0.10.0'
dependency_overrides:
angular2:
path: ../../../dist/dart/angular2
transformers:
- angular2/transform/codegen:
platform_directives: 'package:angular2/src/common/directives.dart#CORE_DIRECTIVES'
- angular2/transform/reflection_remover:
$include: [web/index.dart]
- $dart2js:
minify: true
commandLineOptions:
- --show-package-warnings
- --trust-type-annotations
- --trust-primitives
# Uncomment to generate summaries from dart2js
# - --dump-info

View File

@ -1,40 +0,0 @@
library hello_world.index;
import "package:angular2/platform/browser.dart"
show AngularEntrypoint, bootstrap;
import "package:angular2/core.dart"
show Component, Directive, ElementRef, Injectable, Renderer;
@AngularEntrypoint("Hello World Entrypoint")
main() {
bootstrap(HelloCmp);
}
@Injectable()
class GreetingService {
String greeting = "hello";
}
@Directive(selector: "[red]")
class RedDec {
RedDec(ElementRef el, Renderer renderer) {
renderer.setElementStyle(el.nativeElement, "color", "red");
}
}
@Component(
selector: "hello-app",
viewProviders: const [GreetingService],
template:
'''<div class="greeting">{{greeting}} <span red>world</span>!</div>
<button class="changeButton" (click)="changeGreeting()">change greeting</button>''',
directives: const [RedDec])
class HelloCmp {
String greeting;
HelloCmp(GreetingService service) {
this.greeting = service.greeting;
}
void changeGreeting() {
this.greeting = "howdy";
}
}

View File

@ -1,12 +0,0 @@
<!doctype html>
<html>
<title>Hello Angular 2.0</title>
<body>
<hello-app>
Loading...
</hello-app>
<script src="index.dart" type="application/dart"></script>
<script src="packages/browser/dart.js" type="text/javascript"></script>
</body>
</html>

View File

@ -1,118 +0,0 @@
import 'package:build/build.dart';
import 'package:analyzer/src/generated/element.dart';
import 'src/transform/common/url_resolver.dart';
import 'dart:async';
import 'package:angular2/i18n.dart';
import 'package:angular2/src/compiler/expression_parser/parser.dart';
import 'package:angular2/src/compiler/expression_parser/lexer.dart';
import 'package:angular2/src/compiler/html_parser.dart';
/**
* An command-line utility extracting i18n messages from an application.
*
* For instance, the following command will extract all the messages from the 'my-app-package' package, where
* index.dart is the entry point, and will serialize them into i18n-messages.xml.
*
* pub run packages/angular2/extract_messages.dart 'my-app-package' 'web/src/index.dart' 'i18n-messages.xml'
*/
main(List<String> args) async {
final input = new InputSet(args[0], [args[1]]);
final output = new AssetId(args[0], args[2]);
await build(new PhaseGroup.singleAction(new I18nMessageExtractorBuilder(output), input));
}
class I18nMessageExtractorBuilder implements Builder {
final AssetId outputAssetId;
I18nMessageExtractorBuilder(this.outputAssetId);
Future build(BuildStep buildStep) async {
final resolver = await buildStep.resolve(buildStep.input.id);
final entryLib = resolver.getLibrary(buildStep.input.id);
final extractor = new I18nMessageExtractor((path) => buildStep.readAsString(path));
await extractor.processLibrary(entryLib);
resolver.release();
if (extractor.errors.length > 0) {
print("Errors:");
extractor.errors.forEach(print);
throw "Failed to extract messages";
} else {
await buildStep.writeAsString(new Asset(outputAssetId, extractor.output));
}
}
List<AssetId> declareOutputs(AssetId inputId) => [outputAssetId];
}
class I18nMessageExtractor {
final urlResovler = createOfflineCompileUrlResolver();
final List<Message> messages = [];
final List errors = [];
final HtmlParser htmlParser = new HtmlParser();
final Parser parser = new Parser(new Lexer());
final Function readInput;
I18nMessageExtractor(this.readInput);
String get output => serializeXmb(removeDuplicates(messages));
Future processLibrary(LibraryElement el) async {
return Future.wait(el.units.map(processCompilationUnit));
}
Future processCompilationUnit(CompilationUnitElement el) async {
return Future.wait(el.types.map(processClass));
}
Future processClass(ClassElement el) async {
final baseUrl = (el.source as dynamic).assetId;
final filtered = el.metadata.where((m) {
if (m.element is ConstructorElement) {
final isComponent = m.element.enclosingElement.name == "Component" &&
m.element.library.displayName == "angular2.src.core.metadata";
final isView = m.element.enclosingElement.name == "View" &&
m.element.library.displayName == "angular2.src.core.metadata";
return isComponent || isView;
} else {
return false;
}
});
return Future.wait(filtered.map((m) => processAnnotation(el, m, baseUrl)));
}
Future processAnnotation(ClassElement el, ElementAnnotation m, baseUrl) async {
final fields = (m.constantValue as dynamic).fields["(super)"].fields;
final template = fields["template"];
final templateUrl = fields["templateUrl"];
if (template != null && !template.isNull) {
processTemplate(template.toStringValue(), baseUrl.toString());
}
if (templateUrl != null && !templateUrl.isNull) {
final value = templateUrl.toStringValue();
final resolvedPath = urlResovler.resolve(toAssetUri(baseUrl), value);
final template = await readInput(fromUri(resolvedPath));
processTemplate(template.toStringValue(), baseUrl.toString());
}
}
void processTemplate(String template, String sourceUrl) {
final m = new MessageExtractor(htmlParser, parser);
final res = m.extract(template, sourceUrl);
if (res.errors.isNotEmpty) {
errors.addAll(res.errors);
} else {
messages.addAll(res.messages);
}
}
}

View File

@ -1,132 +0,0 @@
library angular2.transform.common.annotation_matcher;
import 'package:analyzer/src/generated/ast.dart';
import 'package:barback/barback.dart' show AssetId;
import 'class_matcher_base.dart';
export 'class_matcher_base.dart' show ClassDescriptor;
/// [ClassDescriptor]s for the default angular annotations that can appear
/// on a class. These classes are re-exported in many places so this covers all
/// the possible libraries which could provide them.
const _INJECTABLES = const [
const ClassDescriptor(
'Injectable', 'package:angular2/src/core/di/decorators.dart'),
const ClassDescriptor('Injectable', 'package:angular2/core.dart'),
const ClassDescriptor('Injectable', 'package:angular2/src/core/di.dart'),
const ClassDescriptor('Injectable', 'package:angular2/angular2.dart'),
const ClassDescriptor(
'Injectable', 'package:angular2/web_worker/worker.dart'),
];
const _DIRECTIVES = const [
const ClassDescriptor(
'Directive', 'package:angular2/src/core/metadata/directive.dart',
superClass: 'Injectable'),
const ClassDescriptor('Directive', 'package:angular2/src/core/metadata.dart',
superClass: 'Injectable'),
const ClassDescriptor('Directive', 'package:angular2/angular2.dart',
superClass: 'Injectable'),
const ClassDescriptor('Directive', 'package:angular2/core.dart',
superClass: 'Injectable'),
const ClassDescriptor('Directive', 'package:angular2/web_worker/worker.dart',
superClass: 'Injectable'),
];
const _COMPONENTS = const [
const ClassDescriptor(
'Component', 'package:angular2/src/core/metadata/directive.dart',
superClass: 'Directive'),
const ClassDescriptor('Component', 'package:angular2/src/core/metadata.dart',
superClass: 'Directive'),
const ClassDescriptor('Component', 'package:angular2/angular2.dart',
superClass: 'Directive'),
const ClassDescriptor('Component', 'package:angular2/core.dart',
superClass: 'Directive'),
const ClassDescriptor('Component', 'package:angular2/web_worker/worker.dart',
superClass: 'Directive'),
];
const _PIPES = const [
const ClassDescriptor(
'Pipe', 'package:angular2/src/core/metadata/directive.dart',
superClass: 'Injectable'),
const ClassDescriptor('Pipe', 'package:angular2/src/core/metadata.dart',
superClass: 'Injectable'),
const ClassDescriptor('Pipe', 'package:angular2/angular2.dart',
superClass: 'Injectable'),
const ClassDescriptor('Pipe', 'package:angular2/core.dart',
superClass: 'Injectable'),
const ClassDescriptor('Pipe', 'package:angular2/web_worker/worker.dart',
superClass: 'Injectable'),
];
const _VIEWS = const [
const ClassDescriptor('View', 'package:angular2/angular2.dart'),
const ClassDescriptor('View', 'package:angular2/web_worker/worker.dart'),
const ClassDescriptor('View', 'package:angular2/core.dart'),
const ClassDescriptor('View', 'package:angular2/src/core/metadata/view.dart'),
const ClassDescriptor('View', 'package:angular2/src/core/metadata.dart'),
];
const _ENTRYPOINTS = const [
const ClassDescriptor('AngularEntrypoint', 'package:angular2/angular2.dart'),
const ClassDescriptor('AngularEntrypoint', 'package:angular2/core.dart'),
const ClassDescriptor(
'AngularEntrypoint', 'package:angular2/platform/browser.dart'),
const ClassDescriptor(
'AngularEntrypoint', 'package:angular2/platform/worker_app.dart'),
const ClassDescriptor(
'AngularEntrypoint', 'package:angular2/platform/browser_static.dart'),
const ClassDescriptor(
'AngularEntrypoint', 'package:angular2/src/core/angular_entrypoint.dart'),
];
/// Checks if a given [Annotation] matches any of the given
/// [ClassDescriptors].
class AnnotationMatcher extends ClassMatcherBase {
AnnotationMatcher._(classDescriptors) : super(classDescriptors);
factory AnnotationMatcher() {
return new AnnotationMatcher._([]
..addAll(_COMPONENTS)
..addAll(_DIRECTIVES)
..addAll(_PIPES)
..addAll(_INJECTABLES)
..addAll(_VIEWS)
..addAll(_ENTRYPOINTS));
}
bool _implementsWithWarning(Annotation annotation, AssetId assetId,
List<ClassDescriptor> interfaces) {
ClassDescriptor descriptor = firstMatch(annotation.name, assetId);
if (descriptor == null) return false;
return implements(descriptor, interfaces,
missingSuperClassWarning:
'Missing `custom_annotation` entry for `${descriptor.superClass}`.');
}
/// Checks if an [Annotation] node implements [Injectable].
bool isInjectable(Annotation annotation, AssetId assetId) =>
_implementsWithWarning(annotation, assetId, _INJECTABLES);
/// Checks if an [Annotation] node implements [Directive].
bool isDirective(Annotation annotation, AssetId assetId) =>
_implementsWithWarning(annotation, assetId, _DIRECTIVES);
/// Checks if an [Annotation] node implements [Component].
bool isComponent(Annotation annotation, AssetId assetId) =>
_implementsWithWarning(annotation, assetId, _COMPONENTS);
/// Checks if an [Annotation] node implements [View].
bool isView(Annotation annotation, AssetId assetId) =>
_implementsWithWarning(annotation, assetId, _VIEWS);
/// Checks if an [Annotation] node implements [Pipe].
bool isPipe(Annotation annotation, AssetId assetId) =>
_implementsWithWarning(annotation, assetId, _PIPES);
/// Checks if an [Annotation] node implements [AngularEntrypoint]
bool isEntrypoint(Annotation annotation, AssetId assetId) =>
_implementsWithWarning(annotation, assetId, _ENTRYPOINTS);
}

View File

@ -1,28 +0,0 @@
library angular2.transform.common.asset_reader;
import 'dart:async';
import 'dart:convert';
import 'package:barback/barback.dart';
/// A class that allows fetching code using {@link AssetId}s without all the
/// additional baggage of a {@link Transform}.
abstract class AssetReader {
Future<String> readAsString(AssetId id, {Encoding encoding});
Future<bool> hasInput(AssetId id);
/// Creates an {@link AssetReader} using the `transform`, which should be a
/// {@link Transform} or {@link AggregateTransform}.
factory AssetReader.fromTransform(dynamic transform) =>
new _TransformAssetReader(transform);
}
class _TransformAssetReader implements AssetReader {
final dynamic t;
_TransformAssetReader(this.t);
Future<String> readAsString(AssetId id, {Encoding encoding}) =>
t.readInputAsString(id, encoding: encoding);
Future<bool> hasInput(AssetId id) => t.hasInput(id);
}

View File

@ -1,78 +0,0 @@
library angular2.transform.common.async_string_writer;
import 'dart:async';
import 'package:analyzer/src/generated/java_core.dart';
/// [PrintWriter] implementation that allows asynchronous printing via
/// [asyncPrint] and [asyncToString]. See those methods for details.
class AsyncStringWriter extends PrintWriter {
/// All [Future]s we are currently waiting on.
final List<Future<String>> _toAwait = <Future<String>>[];
final List<StringBuffer> _bufs;
StringBuffer _curr;
int _asyncCount = 0;
AsyncStringWriter._(StringBuffer curr)
: _curr = curr,
_bufs = <StringBuffer>[curr];
AsyncStringWriter([Object content = ""]) : this._(new StringBuffer(content));
@override
void print(x) {
_curr.write(x);
}
/// Adds the result of `futureText` to the writer at the current position
/// in the string being built. If using this method, you must use
/// [asyncToString] instead of [toString] to get the value of the writer or
/// your string may not appear as expected.
Future<String> asyncPrint(Future<String> futureText) {
_semaphoreIncrement();
var myBuf = new StringBuffer();
_bufs.add(myBuf);
_curr = new StringBuffer();
_bufs.add(_curr);
var toAwait = futureText.then((val) {
myBuf.write(val);
return val;
});
_toAwait.add(toAwait);
return toAwait.whenComplete(() {
_semaphoreDecrementAndCleanup();
_toAwait.remove(toAwait);
});
}
/// Waits for any values added via [asyncPrint] and returns the fully
/// built string.
Future<String> asyncToString() {
_semaphoreIncrement();
var bufLen = _bufs.length;
return Future.wait(_toAwait).then((_) {
return _bufs.sublist(0, bufLen).join('');
}).whenComplete(_semaphoreDecrementAndCleanup);
}
@override
String toString() => _bufs.map((buf) => '$buf').join('(async gap)');
void _semaphoreIncrement() {
++_asyncCount;
}
void _semaphoreDecrementAndCleanup() {
assert(_asyncCount > 0);
--_asyncCount;
if (_asyncCount == 0) {
_curr = _bufs[0];
for (var i = 1; i < _bufs.length; ++i) {
_curr.write('${_bufs[i]}');
}
_bufs.removeRange(1, _bufs.length);
}
}
}

View File

@ -1,127 +0,0 @@
library angular2.transform.common.class_matcher_base;
import 'package:analyzer/src/generated/ast.dart';
import 'package:barback/barback.dart' show AssetId;
import 'package:path/path.dart' as path;
import 'logging.dart' show log;
import 'url_resolver.dart';
/// Checks if a given [Identifier] matches any of the given [ClassDescriptor]s.
abstract class ClassMatcherBase {
/// Always start out with the default angular [ClassDescriptor]s.
final List<ClassDescriptor> _classDescriptors;
ClassMatcherBase(this._classDescriptors);
/// Adds a new [ClassDescriptor].
void add(ClassDescriptor classDescriptor) =>
_classDescriptors.add(classDescriptor);
/// Adds a number of [ClassDescriptor]s.
void addAll(Iterable<ClassDescriptor> classDescriptors) =>
_classDescriptors.addAll(classDescriptors);
/// Returns the first [ClassDescriptor] that matches the given
/// [Identifier] node which appears in `assetId`.
ClassDescriptor firstMatch(Identifier className, AssetId assetId) =>
_classDescriptors.firstWhere((a) => isMatch(className, a, assetId),
orElse: () => null);
/// Checks whether an [Identifier] matches any [ClassDescriptor].
bool hasMatch(Identifier className, AssetId assetId) =>
_classDescriptors.any((a) => isMatch(className, a, assetId));
/// Checks whether an [Identifier] matches any [ClassDescriptor].
ImportDirective getMatchingImport(Identifier className, AssetId assetId) {
for (var d in _classDescriptors) {
var matchingImport = _getMatchingImport(className, d, assetId);
if (matchingImport != null) {
return matchingImport;
}
}
return null;
}
/// Checks if `descriptor` extends or is any of the supplied `interfaces`.
bool implements(ClassDescriptor descriptor, List<ClassDescriptor> interfaces,
{String missingSuperClassWarning}) {
if (descriptor == null) return false;
if (interfaces.contains(descriptor)) return true;
if (descriptor.superClass == null) return false;
var superClass = _classDescriptors
.firstWhere((a) => a.name == descriptor.superClass, orElse: () => null);
if (superClass == null) {
if (missingSuperClassWarning != null &&
missingSuperClassWarning.isNotEmpty) {
log.warning(missingSuperClassWarning);
}
return false;
}
return implements(superClass, interfaces);
}
}
// Returns an [ImportDirective] matching `descriptor` for `className` which appears in `assetId`, or `null` if none exists.
ImportDirective _getMatchingImport(
Identifier className, ClassDescriptor descriptor, AssetId assetId) {
if (className == null) return null;
String name;
Identifier prefix;
if (className is PrefixedIdentifier) {
name = className.identifier.name;
prefix = className.prefix;
} else {
name = className.name;
}
if (name != descriptor.name) return null;
final assetUri = toAssetUri(assetId);
return (className.root as CompilationUnit)
.directives
.where((d) => d is ImportDirective)
.firstWhere((ImportDirective i) {
var importMatch = false;
var uriString = i.uri.stringValue;
if (uriString == descriptor.import) {
importMatch = true;
} else if (uriString.startsWith('package:') || isDartCoreUri(uriString)) {
return false;
} else {
final candidateAssetId =
fromUri(createOfflineCompileUrlResolver().resolve(assetUri, uriString));
importMatch = descriptor.assetId == candidateAssetId;
}
if (!importMatch) return false;
if (prefix == null) return i.prefix == null;
if (i.prefix == null) return false;
return prefix.name == i.prefix.name;
}, orElse: () => null);
}
// Checks if `className` which appears in `assetId` matches a [ClassDescriptor].
bool isMatch(
Identifier className, ClassDescriptor descriptor, AssetId assetId) {
return _getMatchingImport(className, descriptor, assetId) != null;
}
/// String based description of a class and its location.
class ClassDescriptor {
/// The name of the class.
final String name;
/// A `package:` style import path to the file where the class is defined.
final String import;
/// The class that this class extends or implements. This is the only optional
/// field.
final String superClass;
AssetId get assetId => new AssetId(package, packagePath);
String get package => path.split(import.replaceFirst('package:', '')).first;
String get packagePath => path.joinAll(['lib']
..addAll(path.split(import.replaceFirst('package:', ''))..removeAt(0)));
const ClassDescriptor(this.name, this.import, {this.superClass});
}

View File

@ -1,80 +0,0 @@
library angular2.transform.common.code.annotation_code;
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:angular2/src/transform/common/model/annotation_model.pb.dart';
import 'package:barback/barback.dart' show AssetId;
import 'constify.dart' show constify;
/// Visitor responsible for parsing [Annotation]s into [AnnotationModel]s.
class AnnotationVisitor extends SimpleAstVisitor<AnnotationModel> {
/// The file we are processing.
final AssetId assetId;
AnnotationVisitor(this.assetId);
@override
AnnotationModel visitAnnotation(Annotation node) {
var name = constify(node.name);
if (node.constructorName != null) {
name += '.${constify(node.constructorName)}';
}
var model = new AnnotationModel()
..name = name
..isConstObject = node.arguments == null;
// This annotation is a constant instance creation expression,
// e.g. @Injectable(), rather than a const object, e.g. @override.
if (!model.isConstObject) {
for (var arg in node.arguments.arguments) {
if (arg is NamedExpression) {
model.namedParameters.add(new NamedParameter()
..name = constify(arg.name.label)
..value = constify(arg.expression));
} else {
model.parameters.add(constify(arg));
}
}
}
return model;
}
}
/// Defines the format in which an [AnnotationModel] is expressed as Dart code
/// when registered with the reflector.
abstract class AnnotationWriterMixin {
StringBuffer get buffer;
void writeAnnotationModel(AnnotationModel model) {
if (model.isConstObject) {
// This is a const instance, not a ctor invocation and does not need a
// const instance creation expression.
buffer.write(model.name);
} else {
buffer.write('const ${model.name}(');
var first = true;
for (var param in model.parameters) {
if (!first) {
buffer.write(', ');
}
first = false;
buffer.write(param);
}
// TODO(kegluneq): We are currently outputting these sorted to ensure we
// have repeatable output for testing purposes.
// Remove this sorting once we are not testing output code directly.
var namedParameters = model.namedParameters.toList();
namedParameters.sort((a, b) => a.name.compareTo(b.name));
for (var param in namedParameters) {
if (!first) {
buffer.write(', ');
}
first = false;
buffer.write('${param.name}: ${param.value}');
}
buffer.write(')');
}
}
}

View File

@ -1,64 +0,0 @@
library angular2.transform.common.code.constify;
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/src/generated/java_core.dart';
/// Serializes the provided [AstNode] to Dart source, replacing `new` in
/// [InstanceCreationExpression]s and the `@` in [Annotation]s with `const`.
String constify(AstNode node) {
var writer = new PrintStringWriter();
node.accept(new _ConstifyingVisitor(writer));
return '$writer';
}
class _ConstifyingVisitor extends ToSourceVisitor {
final PrintWriter writer;
_ConstifyingVisitor(PrintWriter writer)
: this.writer = writer,
super(writer);
@override
Object visitInstanceCreationExpression(InstanceCreationExpression node) {
if (node.keyword.lexeme == 'const') {
return super.visitInstanceCreationExpression(node);
} else if (node.keyword.lexeme == 'new') {
writer.print('const ');
if (node.constructorName != null) {
node.constructorName.accept(this);
}
if (node.argumentList != null) {
node.argumentList.accept(this);
}
}
return null;
}
@override
Object visitAnnotation(Annotation node) {
var hasArguments =
node.arguments != null && node.arguments.arguments != null;
if (hasArguments) {
writer.print('const ');
}
if (node.name != null) {
node.name.accept(this);
}
if (node.constructorName != null) {
writer.print('.');
node.constructorName.accept(this);
}
if (hasArguments) {
var args = node.arguments.arguments;
writer.print('(');
for (var i = 0, iLen = args.length; i < iLen; ++i) {
if (i != 0) {
writer.print(', ');
}
args[i].accept(this);
}
writer.print(')');
}
return null;
}
}

View File

@ -1,130 +0,0 @@
library angular2.transform.common.code.import_export_code;
import 'package:analyzer/analyzer.dart';
import 'package:angular2/src/transform/common/mirror_matcher.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/model/import_export_model.pb.dart';
const _mirrorMatcher = const MirrorMatcher();
/// Visitor responsible for parsing [ImportDirective]s into [ImportModel]s.
class ImportVisitor extends SimpleAstVisitor<ImportModel> {
@override
ImportModel visitImportDirective(ImportDirective node) {
if (node.isSynthetic) return null;
// This transitively imports 'dart:mirrors'.
if (_mirrorMatcher.hasReflectionCapabilitiesUri(node)) return null;
final model = new ImportModel()
..uri = stringLiteralToString(node.uri)
..isDeferred = node.deferredKeyword != null;
if (node.prefix != null) {
model.prefix = node.prefix.name;
}
_populateCombinators(node, model);
_updateIfBootstrap(node, model);
return model;
}
}
/// Visitor responsible for parsing [ExportDirective]s into [ExportModel]s.
class ExportVisitor extends SimpleAstVisitor<ExportModel> {
@override
ExportModel visitExportDirective(ExportDirective node) {
if (node.isSynthetic) return null;
// This transitively imports 'dart:mirrors'.
if (_mirrorMatcher.hasReflectionCapabilitiesUri(node)) return null;
var model = new ExportModel()..uri = stringLiteralToString(node.uri);
_populateCombinators(node, model);
_updateIfBootstrap(node, model);
return model;
}
}
/// Ensures that the bootstrap import is not retained in .ng_deps.
///
/// If `model` has a combinator referencing `BOOTSTRAP_NAME`, rewrite it to
/// `BOOTSTRAP_STATIC_NAME`.
/// `model` should be an [ImportModel] or an [ExportModel].
void _updateIfBootstrap(NamespaceDirective node, dynamic model) {
if (_mirrorMatcher.hasBootstrapUri(node)) {
model.uri = BOOTSTRAP_STATIC_URI;
[model.showCombinators, model.hideCombinators]
.forEach((List<String> cList) {
for (var i = 0; i < cList.length; ++i) {
if (cList[i] == BOOTSTRAP_NAME) {
cList[i] = BOOTSTRAP_STATIC_NAME;
}
}
});
}
}
/// Parses `combinators` in `node` and adds them to `model`, which should be
/// either an [ImportModel] or an [ExportModel].
void _populateCombinators(NamespaceDirective node, dynamic model) {
if (node.combinators != null) {
node.combinators.forEach((c) {
if (c is ShowCombinator) {
model.showCombinators.addAll(c.shownNames.map((id) => '$id'));
} else if (c is HideCombinator) {
model.hideCombinators.addAll(c.hiddenNames.map((id) => '$id'));
}
});
}
}
/// Defines the format in which an [ImportModel] is expressed as Dart code when
/// registered with the reflector.
abstract class ImportWriterMixin {
StringBuffer get buffer;
void writeImportModel(ImportModel model) {
buffer.write("import '${model.uri}'");
if (model.isDeferred) {
buffer.write(' deferred');
}
if (model.prefix != null && model.prefix.isNotEmpty) {
buffer.write(' as ${model.prefix}');
}
_writeCombinators(buffer, model);
buffer.writeln(';');
}
}
/// Defines the format in which an [ExportModel] is expressed as Dart code when
/// registered with the reflector.
abstract class ExportWriterMixin {
StringBuffer get buffer;
void writeExportModel(ExportModel model) {
buffer.write("export '${model.uri}'");
_writeCombinators(buffer, model);
buffer.writeln(';');
}
}
void _writeCombinators(StringBuffer buffer, dynamic model) {
if (model.showCombinators != null && model.showCombinators.isNotEmpty) {
buffer.write(' show ');
for (var i = 0; i < model.showCombinators.length; ++i) {
if (i != 0) {
buffer.write(', ');
}
buffer.write(model.showCombinators[i]);
}
}
if (model.hideCombinators != null && model.hideCombinators.isNotEmpty) {
buffer.write(' hide ');
for (var i = 0; i < model.hideCombinators.length; ++i) {
if (i != 0) {
buffer.write(', ');
}
buffer.write(model.hideCombinators[i]);
}
}
}

View File

@ -1,182 +0,0 @@
library angular2.transform.common.code.ng_deps_code;
import 'package:analyzer/analyzer.dart';
import 'package:angular2/src/transform/common/annotation_matcher.dart';
import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart';
import 'package:angular2/src/transform/common/model/import_export_model.pb.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:barback/barback.dart' show AssetId;
import 'package:path/path.dart' as path;
import 'annotation_code.dart';
import 'import_export_code.dart';
import 'reflection_info_code.dart';
import 'parameter_code.dart';
/// Visitor responsible for parsing Dart source into [NgDepsModel] objects.
class NgDepsVisitor extends RecursiveAstVisitor<Object> {
final AssetId processedFile;
final _importVisitor = new ImportVisitor();
final _exportVisitor = new ExportVisitor();
final ReflectionInfoVisitor _reflectableVisitor;
bool _isPart = false;
NgDepsModel _model = null;
NgDepsVisitor(AssetId processedFile, AnnotationMatcher annotationMatcher)
: this.processedFile = processedFile,
_reflectableVisitor =
new ReflectionInfoVisitor(processedFile, annotationMatcher);
bool get isPart => _isPart;
NgDepsModel get model {
if (_model == null) {
_createModel('');
}
return _model;
}
void _createModel(String libraryUri) {
_model = new NgDepsModel()
..libraryUri = libraryUri
..sourceFile = path.basename(processedFile.path);
}
@override
Object visitClassDeclaration(ClassDeclaration node) {
var reflectableModel = _reflectableVisitor.visitClassDeclaration(node);
if (reflectableModel != null) {
model.reflectables.add(reflectableModel);
}
return null;
}
@override
Object visitExportDirective(ExportDirective node) {
var export = _exportVisitor.visitExportDirective(node);
if (export != null) {
model.exports.add(export);
}
return null;
}
@override
Object visitImportDirective(ImportDirective node) {
var import = _importVisitor.visitImportDirective(node);
if (import != null) {
model.imports.add(import);
}
return null;
}
@override
Object visitLibraryDirective(LibraryDirective node) {
if (node != null) {
assert(_model == null);
_createModel('${node.name}');
}
return null;
}
@override
Object visitPartDirective(PartDirective node) {
model.partUris.add(stringLiteralToString(node.uri));
return null;
}
@override
Object visitPartOfDirective(PartOfDirective node) {
_isPart = true;
return null;
}
@override
Object visitFunctionDeclaration(FunctionDeclaration node) {
var reflectableModel = _reflectableVisitor.visitFunctionDeclaration(node);
if (reflectableModel != null) {
model.reflectables.add(reflectableModel);
}
return null;
}
}
/// Defines the format in which an [NgDepsModel] is expressed as Dart code
/// when registered with the reflector.
class NgDepsWriter extends Object
with
AnnotationWriterMixin,
ExportWriterMixin,
ImportWriterMixin,
NgDepsWriterMixin,
ParameterWriterMixin,
ReflectionWriterMixin {
final StringBuffer buffer;
NgDepsWriter([StringBuffer buffer])
: this.buffer = buffer != null ? buffer : new StringBuffer();
}
abstract class NgDepsWriterMixin
implements
AnnotationWriterMixin,
ExportWriterMixin,
ImportWriterMixin,
ParameterWriterMixin,
ReflectionWriterMixin {
StringBuffer get buffer;
void writeNgDepsModel(NgDepsModel model, String templateCode) {
if (model.libraryUri.isNotEmpty) {
buffer.writeln('library ${model.libraryUri}${TEMPLATE_EXTENSION};\n');
}
// We need to import & export (see below) the source file.
writeImportModel(new ImportModel()..uri = model.sourceFile);
// Used to register reflective information.
writeImportModel(new ImportModel()
..uri = REFLECTOR_IMPORT
..prefix = REFLECTOR_PREFIX);
// We do not support `partUris`, so skip outputting them.
// Ignore deferred imports here so as to not load the deferred libraries
// code in the current library causing much of the code to not be
// deferred. Instead `DeferredRewriter` will rewrite the code as to load
// `ng_deps` in a deferred way.
model.imports.where((i) => !i.isDeferred).forEach(writeImportModel);
model.depImports.where((i) => !i.isDeferred).forEach(writeImportModel);
writeExportModel(new ExportModel()..uri = model.sourceFile);
model.exports.forEach(writeExportModel);
buffer.writeln(templateCode);
buffer
..writeln('var _visited = false;')
..writeln('void ${SETUP_METHOD_NAME}() {')
..writeln('if (_visited) return; _visited = true;');
final needsReceiver = (model.reflectables != null &&
model.reflectables.isNotEmpty);
if (needsReceiver) {
buffer.writeln('$REFLECTOR_PREFIX.$REFLECTOR_VAR_NAME');
}
if (model.reflectables != null && model.reflectables.isNotEmpty) {
model.reflectables.forEach(writeRegistration);
}
if (needsReceiver) {
buffer.writeln(';');
}
// Call the setup method for our dependencies.
for (var importModel in model.depImports) {
buffer.writeln('${importModel.prefix}.${SETUP_METHOD_NAME}();');
}
buffer.writeln('}');
}
}

View File

@ -1,138 +0,0 @@
library angular2.transform.common.code.parameter_code;
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/model/parameter_model.pb.dart';
import 'constify.dart';
/// Visitor responsible for parsing [FormalParameter]s into
/// [ParameterModel]s.
class ParameterVisitor extends SimpleAstVisitor<ParameterModel> {
/// Maps field names to their declared types. See `_populateFieldMap`
final Map<String, TypeName> _fieldNameToType = {};
final Set<AstNode> _seen = new Set();
void _populateFieldMap(AstNode node) {
ClassDeclaration clazz =
node.getAncestor((node) => node is ClassDeclaration);
if (_seen.contains(clazz)) return;
_seen.add(clazz);
clazz.members
.where((member) => member is FieldDeclaration)
.forEach((FieldDeclaration field) {
var type = field.fields.type;
if (type != null) {
field.fields.variables.forEach((VariableDeclaration decl) {
var key = '${decl.name}';
if (_fieldNameToType.containsKey(key)) {
// Need to clear our `seen` list as the type for a var name has
// changed and could be incorrect.
_seen.clear();
}
_fieldNameToType[key] = type;
});
}
});
}
ParameterModel _visitNormalFormalParameter(
NodeList<Annotation> metadata, TypeName type, SimpleIdentifier name) {
var model = new ParameterModel();
if (name != null && name.name != null && name.name.isNotEmpty) {
model.paramName = '$name';
}
if (type != null) {
var sTypeName = '${type.name}';
if (sTypeName.isNotEmpty) {
model.typeName = sTypeName;
}
if (type.typeArguments != null) {
model.typeArgs = '${type.typeArguments}';
}
}
if (metadata != null) {
model.metadata.addAll(metadata.map(constify));
}
return model;
}
@override
ParameterModel visitSimpleFormalParameter(SimpleFormalParameter node) {
return _visitNormalFormalParameter(
node.metadata, node.type, node.identifier);
}
@override
ParameterModel visitFieldFormalParameter(FieldFormalParameter node) {
if (node.parameters != null) {
log.error('Parameters in ctor not supported '
'(${node.toSource()})');
}
var type = node.type;
if (type == null) {
_populateFieldMap(node);
type = _fieldNameToType[node.identifier.toString()];
}
return _visitNormalFormalParameter(node.metadata, type, node.identifier);
}
@override
ParameterModel visitFunctionTypedFormalParameter(
FunctionTypedFormalParameter node) {
log.error('Function typed formal parameters not supported '
'(${node.toSource()})');
return _visitNormalFormalParameter(node.metadata, null, node.identifier);
}
@override
ParameterModel visitDefaultFormalParameter(DefaultFormalParameter node) {
// Ignore the declared default value.
return node.parameter != null ? node.parameter.accept(this) : null;
}
}
/// Defines the format in which a [ParameterModel] is expressed as Dart code
/// when registered with the reflector.
abstract class ParameterWriterMixin {
StringBuffer get buffer;
void writeParameterModelForList(ParameterModel model) {
buffer.write('const [');
var first = true;
if (model.typeName != null && model.typeName.isNotEmpty) {
if (!first) {
buffer.write(', ');
}
first = false;
buffer.write('${model.typeName}');
}
for (var meta in model.metadata) {
if (!first) {
buffer.write(', ');
}
first = false;
buffer.write('$meta');
}
buffer.write(']');
}
void writeParameterModelForDeclaration(ParameterModel model) {
if (model.typeName != null && model.typeName.isNotEmpty) {
buffer.write(model.typeName);
if (model.typeArgs != null && model.typeArgs.isNotEmpty) {
buffer.write(model.typeArgs);
}
buffer.write(' ');
}
if (model.paramName != null && model.paramName.isNotEmpty) {
buffer.write(model.paramName);
}
}
void writeParameterModelForImpl(ParameterModel model) {
buffer.write(model.paramName);
}
}

View File

@ -1,256 +0,0 @@
library angular2.transform.common.code.reflection_info_code;
import 'package:analyzer/analyzer.dart';
import 'package:angular2/src/transform/common/annotation_matcher.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/model/reflection_info_model.pb.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:barback/barback.dart' show AssetId;
import 'annotation_code.dart';
import 'parameter_code.dart';
/// Visitor responsible for parsing [ClassDeclaration]s into
/// [ReflectionInfoModel]s.
class ReflectionInfoVisitor extends RecursiveAstVisitor<ReflectionInfoModel> {
/// The file we are processing.
final AssetId assetId;
/// Responsible for testing whether [Annotation]s are those recognized by
/// Angular 2, for example `@Component`.
final AnnotationMatcher _annotationMatcher;
final AnnotationVisitor _annotationVisitor;
final ParameterVisitor _parameterVisitor = new ParameterVisitor();
ReflectionInfoVisitor._(this.assetId, this._annotationMatcher,
this._annotationVisitor);
factory ReflectionInfoVisitor(
AssetId assetId, AnnotationMatcher annotationMatcher) {
var annotationVisitor = new AnnotationVisitor(assetId);
return new ReflectionInfoVisitor._(assetId, annotationMatcher,
annotationVisitor);
}
ConstructorDeclaration _getCtor(ClassDeclaration node) {
int numCtorsFound = 0;
var ctor = null;
for (ClassMember classMember in node.members) {
if (classMember is ConstructorDeclaration) {
numCtorsFound++;
ConstructorDeclaration constructor = classMember;
// Use the unnnamed constructor if it is present.
// Otherwise, use the first encountered.
if (ctor == null) {
ctor = constructor;
} else if (constructor.name == null) {
ctor = constructor;
}
}
}
if (numCtorsFound > 1) {
var ctorName = ctor.name;
if (ctorName != null) {
log.warning(
'Found ${numCtorsFound} constructors for class '
'${node.name}; using constructor ${ctorName}.',
asset: assetId);
}
}
return ctor;
}
@override
ReflectionInfoModel visitClassDeclaration(ClassDeclaration node) {
if (!node.metadata
.any((a) => _annotationMatcher.hasMatch(a.name, assetId))) {
return null;
}
var ctor = _getCtor(node);
var model = new ReflectionInfoModel()..name = '${node.name}';
if (ctor != null && ctor.name != null) {
model.ctorName = '${ctor.name}';
}
if (node.metadata != null) {
var componentDirectives = new Iterable.empty();
var componentPipes = new Iterable.empty();
var viewDirectives, viewPipes;
node.metadata.forEach((node) {
var keepAnnotation = true;
if (_annotationMatcher.isComponent(node, assetId)) {
componentDirectives = _extractReferencedTypes(node, 'directives');
componentPipes = _extractReferencedTypes(node, 'pipes');
keepAnnotation = false;
} else if (_annotationMatcher.isView(node, assetId)) {
viewDirectives = _extractReferencedTypes(node, 'directives');
viewPipes = _extractReferencedTypes(node, 'pipes');
keepAnnotation = false;
} else if (_annotationMatcher.isDirective(node, assetId)) {
keepAnnotation = false;
}
if (keepAnnotation) {
model.annotations.add(_annotationVisitor.visitAnnotation(node));
}
});
if ((componentDirectives.isNotEmpty || componentPipes.isNotEmpty) &&
(viewDirectives != null || viewPipes != null)) {
log.warning(
'Cannot specify view parameters on @Component when a @View '
'is present. Component name: ${model.name}',
asset: assetId);
}
model.directives.addAll(componentDirectives);
model.pipes.addAll(componentPipes);
if (viewDirectives != null) {
model.directives.addAll(viewDirectives);
}
if (viewPipes != null) {
model.pipes.addAll(viewPipes);
}
}
if (ctor != null &&
ctor.parameters != null &&
ctor.parameters.parameters != null) {
ctor.parameters.parameters.forEach((node) {
model.parameters.add(node.accept(_parameterVisitor));
});
}
if (node.implementsClause != null &&
node.implementsClause.interfaces != null &&
node.implementsClause.interfaces.isNotEmpty) {
model.interfaces.addAll(node.implementsClause.interfaces
.map((interface) => '${interface.name}'));
}
return model;
}
/// Returns [PrefixedType] values parsed from the value of the
/// `fieldName` parameter of the provided `node`.
/// This will always return a non-null value, so if there is no field
/// called `fieldName`, it will return an empty iterable.
Iterable<PrefixedType> _extractReferencedTypes(
Annotation node, String fieldName) {
assert(_annotationMatcher.isComponent(node, assetId) ||
_annotationMatcher.isView(node, assetId));
if (node.arguments == null && node.arguments.arguments == null) {
return const [];
}
final typesNode = node.arguments.arguments.firstWhere((arg) {
return arg is NamedExpression && '${arg.name.label}' == fieldName;
}, orElse: () => null);
if (typesNode == null) return const [];
if (typesNode.expression is! ListLiteral) {
log.warning(
'Angular 2 expects a list literal for `${fieldName}` '
'but found a ${typesNode.expression.runtimeType}',
asset: assetId);
return const [];
}
final types = <PrefixedType>[];
for (var dep in (typesNode.expression as ListLiteral).elements) {
if (dep is PrefixedIdentifier) {
types.add(new PrefixedType()
..prefix = '${dep.prefix}'
..name = '${dep.identifier}');
} else if (dep is Identifier) {
types.add(new PrefixedType()..name = '${dep}');
} else {
log.warning('Ignoring unexpected value $dep in `${fieldName}`.',
asset: assetId);
}
}
return types;
}
@override
ReflectionInfoModel visitFunctionDeclaration(FunctionDeclaration node) {
if (!node.metadata
.any((a) => _annotationMatcher.hasMatch(a.name, assetId))) {
return null;
}
var model = new ReflectionInfoModel()
..name = '${node.name}'
..isFunction = true;
if (node.metadata != null) {
node.metadata.forEach((node) {
var annotation = _annotationVisitor.visitAnnotation(node);
if (annotation != null) {
model.annotations.add(annotation);
}
});
}
if (node.functionExpression.parameters != null &&
node.functionExpression.parameters.parameters != null) {
node.functionExpression.parameters.parameters.forEach((node) {
var param = node.accept(_parameterVisitor);
if (param != null) {
model.parameters.add(param);
}
});
}
return model;
}
}
/// Defines the format in which an [ReflectionInfoModel] is expressed as Dart
/// code when registered with the reflector.
abstract class ReflectionWriterMixin
implements AnnotationWriterMixin, ParameterWriterMixin {
StringBuffer get buffer;
void _writeListWithSeparator(List l, Function writeFn,
{String prefix, String suffix, String separator: ', '}) {
buffer.write(prefix);
for (var i = 0, iLen = l.length; i < iLen; ++i) {
if (i != 0) {
buffer.write(', ');
}
writeFn(l[i]);
}
buffer.write(suffix);
}
void writeRegistration(ReflectionInfoModel model) {
buffer.write('..register');
if (model.isFunction) {
buffer.write('Function');
} else {
buffer.write('Type');
}
buffer.writeln('(${model.name}, new $REFLECTOR_PREFIX.ReflectionInfo(');
// Annotations
_writeListWithSeparator(model.annotations, writeAnnotationModel,
prefix: 'const [', suffix: ']');
// Parameters
_writeListWithSeparator(model.parameters, writeParameterModelForList,
prefix: ',\nconst [', suffix: ']');
if (!model.isFunction) {
// Factory
_writeListWithSeparator(
model.parameters, writeParameterModelForDeclaration,
prefix: ',\n(', suffix: ')');
buffer.write(' => new ${model.name}');
if (model.ctorName != null && model.ctorName.isNotEmpty) {
buffer.write('.${model.ctorName}');
}
_writeListWithSeparator(model.parameters, writeParameterModelForImpl,
prefix: '(', suffix: ')');
// Interfaces
if (model.interfaces != null && model.interfaces.isNotEmpty) {
_writeListWithSeparator(model.interfaces, buffer.write,
prefix: ',\nconst [', suffix: ']');
}
}
buffer.writeln(')\n)');
}
}

View File

@ -1,42 +0,0 @@
library angular2.transform.common.code.source_module;
import 'package:angular2/src/compiler/offline_compiler.dart';
import 'package:analyzer/src/generated/scanner.dart' show Keyword;
import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart';
import 'ng_deps_code.dart';
/// Writes the full Dart code for the provided [SourceModule].
String writeSourceModule(SourceModule sourceModule, {String libraryName}) {
if (sourceModule == null) return null;
var buf = new StringBuffer();
libraryName = _sanitizeLibName(
libraryName != null ? libraryName : sourceModule.moduleUrl);
buf..writeln('library $libraryName;')..writeln();
buf..writeln()..writeln(sourceModule.source);
return buf.toString();
}
/// Uses `writer` to write a Dart library representing `model` and
/// `sourceModule`.
void writeTemplateFile(
NgDepsWriterMixin writer, NgDepsModel model, SourceModule sourceModule) {
if (model == null) return null;
var sourceModuleCode = '';
if (sourceModule != null) {
sourceModuleCode = sourceModule.source;
}
writer.writeNgDepsModel(model, sourceModuleCode);
}
final _unsafeCharsPattern = new RegExp(r'[^a-zA-Z0-9_\.]');
String _sanitizeLibName(String moduleUrl) {
var sanitized =
moduleUrl.replaceAll(_unsafeCharsPattern, '_').replaceAll('/', '.');
for (var keyword in Keyword.values) {
sanitized.replaceAll(keyword.syntax, '${keyword.syntax}_');
}
return sanitized;
}

View File

@ -1,45 +0,0 @@
library angular2.src.transform.common.eager_transformer_wrapper;
import 'package:barback/barback.dart';
abstract class EagerTransformerWrapper {
EagerTransformerWrapper._();
factory EagerTransformerWrapper(wrapped) {
return wrapped is AggregateTransformer
? new _EagerAggregateTransformerWrapper(wrapped)
: new _EagerTransformerWrapper(wrapped);
}
}
class _EagerTransformerWrapper extends EagerTransformerWrapper
implements Transformer {
final Transformer _wrapped;
_EagerTransformerWrapper(this._wrapped) : super._();
@override
String get allowedExtensions => _wrapped.allowedExtensions;
@override
apply(Transform transform) => _wrapped.apply(transform);
@override
isPrimary(AssetId id) => _wrapped.isPrimary(id);
@override
toString() => _wrapped.toString();
}
class _EagerAggregateTransformerWrapper extends EagerTransformerWrapper
implements AggregateTransformer {
final AggregateTransformer _wrapped;
_EagerAggregateTransformerWrapper(this._wrapped) : super._();
@override
apply(AggregateTransform transform) => _wrapped.apply(transform);
@override
classifyPrimary(AssetId id) => _wrapped.classifyPrimary(id);
@override
toString() => _wrapped.toString();
}

View File

@ -1,32 +0,0 @@
library angular2.transform.common.formatter;
import 'package:dart_style/dart_style.dart';
AngularDartFormatter _formatter = null;
void init(DartFormatter formatter) {
_formatter = new _RealFormatter(formatter);
}
AngularDartFormatter get formatter {
if (_formatter == null) {
_formatter = new _PassThroughFormatter();
}
return _formatter;
}
abstract class AngularDartFormatter {
String format(String source, {uri});
}
class _PassThroughFormatter implements AngularDartFormatter {
String format(String source, {uri}) => source;
}
class _RealFormatter implements AngularDartFormatter {
final DartFormatter _formatter;
_RealFormatter(this._formatter);
String format(source, {uri}) => _formatter.format(source, uri: uri);
}

View File

@ -1,135 +0,0 @@
library angular2.transform.common.annotati_ON_matcher;
import 'package:analyzer/src/generated/ast.dart';
import 'package:barback/barback.dart' show AssetId;
import 'class_matcher_base.dart';
export 'class_matcher_base.dart' show ClassDescriptor;
/// [ClassDescriptor]s for the default angular interfaces that may be
/// implemented by a class. These classes are re-exported in many places so this
/// covers all libraries which provide them.
const _ON_CHANGE_INTERFACES = const [
const ClassDescriptor('OnChanges', 'package:angular2/angular2.dart'),
const ClassDescriptor('OnChanges', 'package:angular2/lifecycle_hooks.dart'),
const ClassDescriptor('OnChanges', 'package:angular2/src/core/metadata.dart'),
const ClassDescriptor('OnChanges', 'package:angular2/core.dart'),
const ClassDescriptor(
'OnChanges', 'package:angular2/src/core/src/core/meta/lifecycle_hooks.dart'),
];
const _ON_DESTROY_INTERFACES = const [
const ClassDescriptor('OnDestroy', 'package:angular2/angular2.dart'),
const ClassDescriptor('OnDestroy', 'package:angular2/lifecycle_hooks.dart'),
const ClassDescriptor('OnDestroy', 'package:angular2/src/core/metadata.dart'),
const ClassDescriptor('OnDestroy', 'package:angular2/core.dart'),
const ClassDescriptor(
'OnDestroy', 'package:angular2/src/core/src/core/meta/lifecycle_hooks.dart'),
];
const _DO_CHECK_INTERFACES = const [
const ClassDescriptor('DoCheck', 'package:angular2/angular2.dart'),
const ClassDescriptor('DoCheck', 'package:angular2/lifecycle_hooks.dart'),
const ClassDescriptor('DoCheck', 'package:angular2/src/core/metadata.dart'),
const ClassDescriptor('DoCheck', 'package:angular2/core.dart'),
const ClassDescriptor(
'DoCheck', 'package:angular2/src/core/src/core/meta/lifecycle_hooks.dart'),
];
const _ON_INIT_INTERFACES = const [
const ClassDescriptor('OnInit', 'package:angular2/angular2.dart'),
const ClassDescriptor('OnInit', 'package:angular2/lifecycle_hooks.dart'),
const ClassDescriptor('OnInit', 'package:angular2/src/core/metadata.dart'),
const ClassDescriptor('OnInit', 'package:angular2/core.dart'),
const ClassDescriptor(
'OnInit', 'package:angular2/src/core/src/core/meta/lifecycle_hooks.dart'),
];
const _ON_AFTER_CONTENT_INIT_INTERFACES = const [
const ClassDescriptor('AfterContentInit', 'package:angular2/angular2.dart'),
const ClassDescriptor(
'AfterContentInit', 'package:angular2/lifecycle_hooks.dart'),
const ClassDescriptor(
'AfterContentInit', 'package:angular2/src/core/metadata.dart'),
const ClassDescriptor('AfterContentInit', 'package:angular2/core.dart'),
const ClassDescriptor(
'AfterContentInit', 'package:angular2/src/core/src/core/meta/lifecycle_hooks.dart')
];
const _ON_AFTER_CONTENT_CHECKED_INTERFACES = const [
const ClassDescriptor(
'AfterContentChecked', 'package:angular2/angular2.dart'),
const ClassDescriptor(
'AfterContentChecked', 'package:angular2/lifecycle_hooks.dart'),
const ClassDescriptor(
'AfterContentChecked', 'package:angular2/src/core/metadata.dart'),
const ClassDescriptor('AfterContentChecked', 'package:angular2/core.dart'),
const ClassDescriptor(
'AfterContentChecked', 'package:angular2/src/core/src/core/meta/lifecycle_hooks.dart')
];
const _ON_AFTER_VIEW_INIT_INTERFACES = const [
const ClassDescriptor('AfterViewInit', 'package:angular2/angular2.dart'),
const ClassDescriptor(
'AfterViewInit', 'package:angular2/lifecycle_hooks.dart'),
const ClassDescriptor(
'AfterViewInit', 'package:angular2/src/core/metadata.dart'),
const ClassDescriptor('AfterViewInit', 'package:angular2/core.dart'),
const ClassDescriptor(
'AfterViewInit', 'package:angular2/src/core/src/core/meta/lifecycle_hooks.dart')
];
const _ON_AFTER_VIEW_CHECKED_INTERFACES = const [
const ClassDescriptor('AfterViewChecked', 'package:angular2/angular2.dart'),
const ClassDescriptor(
'AfterViewChecked', 'package:angular2/lifecycle_hooks.dart'),
const ClassDescriptor(
'AfterViewChecked', 'package:angular2/src/core/metadata.dart'),
const ClassDescriptor('AfterViewChecked', 'package:angular2/core.dart'),
const ClassDescriptor(
'AfterViewChecked', 'package:angular2/src/core/src/core/meta/lifecycle_hooks.dart')
];
/// Checks if a given [Annotation] matches any of the given
/// [ClassDescriptors].
class InterfaceMatcher extends ClassMatcherBase {
InterfaceMatcher._(classDescriptors) : super(classDescriptors);
factory InterfaceMatcher() {
return new InterfaceMatcher._([]
..addAll(_ON_CHANGE_INTERFACES)
..addAll(_ON_DESTROY_INTERFACES)
..addAll(_DO_CHECK_INTERFACES)
..addAll(_ON_INIT_INTERFACES)
..addAll(_ON_AFTER_CONTENT_INIT_INTERFACES)
..addAll(_ON_AFTER_CONTENT_CHECKED_INTERFACES)
..addAll(_ON_AFTER_VIEW_INIT_INTERFACES)
..addAll(_ON_AFTER_VIEW_CHECKED_INTERFACES));
}
/// Checks if an [Identifier] implements [OnChanges].
bool isOnChange(Identifier typeName, AssetId assetId) =>
implements(firstMatch(typeName, assetId), _ON_CHANGE_INTERFACES);
/// Checks if an [Identifier] implements [OnDestroy].
bool isOnDestroy(Identifier typeName, AssetId assetId) =>
implements(firstMatch(typeName, assetId), _ON_DESTROY_INTERFACES);
/// Checks if an [Identifier] implements [DoCheck].
bool isDoCheck(Identifier typeName, AssetId assetId) =>
implements(firstMatch(typeName, assetId), _DO_CHECK_INTERFACES);
/// Checks if an [Identifier] implements [OnInit].
bool isOnInit(Identifier typeName, AssetId assetId) =>
implements(firstMatch(typeName, assetId), _ON_INIT_INTERFACES);
/// Checks if an [Identifier] implements [AfterContentInit].
bool isAfterContentInit(Identifier typeName, AssetId assetId) => implements(
firstMatch(typeName, assetId), _ON_AFTER_CONTENT_INIT_INTERFACES);
/// Checks if an [Identifier] implements [AfterContentChecked].
bool isAfterContentChecked(Identifier typeName, AssetId assetId) =>
implements(
firstMatch(typeName, assetId), _ON_AFTER_CONTENT_CHECKED_INTERFACES);
/// Checks if an [Identifier] implements [AfterViewInit].
bool isAfterViewInit(Identifier typeName, AssetId assetId) =>
implements(firstMatch(typeName, assetId), _ON_AFTER_VIEW_INIT_INTERFACES);
/// Checks if an [Identifier] implements [AfterViewChecked].
bool isAfterViewChecked(Identifier typeName, AssetId assetId) => implements(
firstMatch(typeName, assetId), _ON_AFTER_VIEW_CHECKED_INTERFACES);
}

View File

@ -1,147 +0,0 @@
library angular2.src.transform.common.logging;
import 'dart:async';
import 'dart:io' show stderr;
import 'package:barback/barback.dart';
import 'package:source_span/source_span.dart';
import 'zone.dart' as zone show log;
/// The [TransformLogger] for the current {@link Zone}.
TransformLogger get log {
var log = zone.log;
return log != null ? log : new PrintLogger();
}
/// Writes a log entry at `LogLevel.FINE` granularity with the time taken by
/// `asyncOperation`.
///
/// Returns the result of executing `asyncOperation`.
Future logElapsedAsync(Future asyncOperation(),
{String operationName: 'unknown', AssetId assetId}) async {
final timer = new Stopwatch()..start();
final result = await asyncOperation();
timer.stop();
_logElapsed(timer, operationName, assetId);
return result;
}
/// Writes a log entry at `LogLevel.FINE` granularity with the time taken by
/// `operation`.
///
/// Returns the result of executing `operation`.
dynamic logElapsedSync(dynamic operation(),
{String operationName: 'unknown', AssetId assetId}) {
final timer = new Stopwatch()..start();
final result = operation();
timer.stop();
_logElapsed(timer, operationName, assetId);
return result;
}
/// Logs the time since `timer` was started.
void _logElapsed(Stopwatch timer, String operationName, AssetId assetId) {
final buf =
new StringBuffer('[$operationName] took ${timer.elapsedMilliseconds} ms');
if (assetId != null) {
buf.write(' on $assetId');
}
log.fine(buf.toString(), asset: assetId);
}
/// Writes logged messages to the provided [StringSink].
///
/// A simple implementation of [TransformLogger] that writes messages to a
/// [StringSink] and discards `asset` and `span` information.
class SinkLogger implements TransformLogger {
final StringSink _sink;
SinkLogger(this._sink);
void _printWithPrefix(prefix, msg) => _sink.writeln('$prefix: $msg');
@override
void info(msg, {AssetId asset, SourceSpan span}) =>
_printWithPrefix('INFO', msg);
@override
void fine(msg, {AssetId asset, SourceSpan span}) =>
_printWithPrefix('FINE', msg);
@override
void warning(msg, {AssetId asset, SourceSpan span}) =>
_printWithPrefix('WARN', msg);
@override
void error(msg, {AssetId asset, SourceSpan span}) {
throw new PrintLoggerError(msg, asset, span);
}
}
/// Prints logged messages to stderr.
///
/// A simple implementation of [TransformLogger] that prints messages to
/// [stderr] and discards `asset` and `span` information.
class PrintLogger extends SinkLogger {
PrintLogger() : super(stderr);
}
/// Wraps the logger and prints the messages
/// only if they have not been printed before
class DeduppingLogger implements TransformLogger {
Set<String> _printedMessages;
final TransformLogger _logger;
DeduppingLogger(this._logger, this._printedMessages);
String _key(msg, AssetId asset) => "$msg $asset";
@override
void info(msg, {AssetId asset, SourceSpan span}) {
if (!_printedMessages.contains(_key(msg, asset))) {
_printedMessages.add(_key(msg, asset));
_logger.info(msg, asset: asset, span: span);
}
}
@override
void fine(msg, {AssetId asset, SourceSpan span}) {
if (!_printedMessages.contains(_key(msg, asset))) {
_printedMessages.add(_key(msg, asset));
_logger.fine(msg, asset: asset, span: span);
}
}
@override
void warning(msg, {AssetId asset, SourceSpan span}) {
if (!_printedMessages.contains(_key(msg, asset))) {
_printedMessages.add(_key(msg, asset));
_logger.warning(msg, asset: asset, span: span);
}
}
@override
void error(msg, {AssetId asset, SourceSpan span}) {
if (!_printedMessages.contains(_key(msg, asset))) {
_printedMessages.add(_key(msg, asset));
_logger.error(msg, asset: asset, span: span);
}
}
}
class PrintLoggerError extends Error {
final String message;
final AssetId asset;
final SourceSpan span;
PrintLoggerError(this.message, this.asset, this.span);
@override
String toString() {
return 'Message: ${Error.safeToString(message)}, '
'Asset: ${Error.safeToString(asset)}, '
'Span: ${Error.safeToString(span)}.';
}
}

View File

@ -1,43 +0,0 @@
library angular2.transform.common.mirror_matcher;
import 'package:analyzer/src/generated/ast.dart';
import 'package:angular2/src/transform/common/names.dart';
/// File from which `bootstrap` is exported.
///
/// This file transitively imports dart:mirrors.
/// It should be replaced with [BOOTSTRAP_STATIC_URI] in production apps.
const _BOOTSTRAP_URI = 'package:angular2/platform/browser.dart';
/// File from which `ReflectionCapabilities` is exported.
///
/// This file transitively imports dart:mirrors and should be removed from
/// production apps. The Angular2 reflection framework should be initialized
/// with generated code such that no reflection is necessary.
const _REFLECTION_CAPABILITIES_URI =
'package:angular2/src/core/reflection/reflection_capabilities.dart';
/// File from which `bootstrapStatic` is exported.
///
/// This file does not transitively import dart:mirrors.
/// It should be used in place of [_BOOTSTRAP_URI] in production apps.
const BOOTSTRAP_STATIC_URI = 'package:angular2/platform/browser_static.dart';
/// Syntactially checks for code related to the use of `dart:mirrors`.
///
/// Checks various [AstNode]s to determine if they are
/// - Libraries that transitively import `dart:mirrors`
/// - Instantiations of [ReflectionCapabilities]
class MirrorMatcher {
const MirrorMatcher();
bool isNewReflectionCapabilities(InstanceCreationExpression node) =>
'${node.constructorName.type.name}' == REFLECTION_CAPABILITIES_NAME;
bool hasReflectionCapabilitiesUri(UriBasedDirective node) {
return node.uri.stringValue == _REFLECTION_CAPABILITIES_URI;
}
bool hasBootstrapUri(UriBasedDirective node) =>
_BOOTSTRAP_URI == node.uri.stringValue;
}

View File

@ -1,10 +0,0 @@
library angular2.transform.common.mirror_mode;
/// Modes for mirror use.
/// `none` is the default value and signifies that mirror use should be
/// removed.
/// `debug` allows the use of mirrors and logs a notice whenever they are
/// accessed.
/// `verbose` allows the use of mirrors and logs a stack trace whenever they
/// are accessed.
enum MirrorMode { debug, none, verbose }

View File

@ -1,107 +0,0 @@
///
// Generated code. Do not modify.
///
library angular2.src.transform.common.model.proto_annotation_model;
import 'package:protobuf/protobuf.dart';
class NamedParameter extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('NamedParameter')
..a(1, 'name', PbFieldType.QS)
..a(2, 'value', PbFieldType.QS)
;
NamedParameter() : super();
NamedParameter.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
NamedParameter.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
NamedParameter clone() => new NamedParameter()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
static NamedParameter create() => new NamedParameter();
static PbList<NamedParameter> createRepeated() => new PbList<NamedParameter>();
static NamedParameter getDefault() {
if (_defaultInstance == null) _defaultInstance = new _ReadonlyNamedParameter();
return _defaultInstance;
}
static NamedParameter _defaultInstance;
static void $checkItem(NamedParameter v) {
if (v is !NamedParameter) checkItemFailed(v, 'NamedParameter');
}
String get name => $_get(0, 1, '');
void set name(String v) { $_setString(0, 1, v); }
bool hasName() => $_has(0, 1);
void clearName() => clearField(1);
String get value => $_get(1, 2, '');
void set value(String v) { $_setString(1, 2, v); }
bool hasValue() => $_has(1, 2);
void clearValue() => clearField(2);
}
class _ReadonlyNamedParameter extends NamedParameter with ReadonlyMessageMixin {}
class AnnotationModel extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('AnnotationModel')
..a(1, 'name', PbFieldType.QS)
..p(2, 'parameters', PbFieldType.PS)
..pp(3, 'namedParameters', PbFieldType.PM, NamedParameter.$checkItem, NamedParameter.create)
..a(4, 'isConstObject', PbFieldType.OB)
;
AnnotationModel() : super();
AnnotationModel.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
AnnotationModel.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
AnnotationModel clone() => new AnnotationModel()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
static AnnotationModel create() => new AnnotationModel();
static PbList<AnnotationModel> createRepeated() => new PbList<AnnotationModel>();
static AnnotationModel getDefault() {
if (_defaultInstance == null) _defaultInstance = new _ReadonlyAnnotationModel();
return _defaultInstance;
}
static AnnotationModel _defaultInstance;
static void $checkItem(AnnotationModel v) {
if (v is !AnnotationModel) checkItemFailed(v, 'AnnotationModel');
}
String get name => $_get(0, 1, '');
void set name(String v) { $_setString(0, 1, v); }
bool hasName() => $_has(0, 1);
void clearName() => clearField(1);
List<String> get parameters => $_get(1, 2, null);
List<NamedParameter> get namedParameters => $_get(2, 3, null);
bool get isConstObject => $_get(3, 4, false);
void set isConstObject(bool v) { $_setBool(3, 4, v); }
bool hasIsConstObject() => $_has(3, 4);
void clearIsConstObject() => clearField(4);
}
class _ReadonlyAnnotationModel extends AnnotationModel with ReadonlyMessageMixin {}
const NamedParameter$json = const {
'1': 'NamedParameter',
'2': const [
const {'1': 'name', '3': 1, '4': 2, '5': 9},
const {'1': 'value', '3': 2, '4': 2, '5': 9},
],
};
const AnnotationModel$json = const {
'1': 'AnnotationModel',
'2': const [
const {'1': 'name', '3': 1, '4': 2, '5': 9},
const {'1': 'parameters', '3': 2, '4': 3, '5': 9},
const {'1': 'named_parameters', '3': 3, '4': 3, '5': 11, '6': '.angular2.src.transform.common.model.proto.NamedParameter'},
const {'1': 'is_const_object', '3': 4, '4': 1, '5': 8},
],
};
/**
* Generated with:
* annotation_model.proto (a7c9ec37cbc4916ddc7b132710da0856fa76cb5a)
* libprotoc 3.0.0
* dart-protoc-plugin (af5fc2bf1de367a434c3b1847ab260510878ffc0)
*/

View File

@ -1,25 +0,0 @@
syntax = "proto2";
package angular2.src.transform.common.model.proto;
message NamedParameter {
required string name = 1;
required string value = 2;
}
message AnnotationModel {
// The constructor that creates the annotation, or the name of the field that
// defines the annotation.
required string name = 1;
// The positional parameters provided to the annotation.
repeated string parameters = 2;
// The named parameters provided to the annotation.
repeated NamedParameter named_parameters = 3;
// Whether this annotation is a constant object (for example, `@override`) as
// opposed to a const instance creation expression
// (for example, `@Injectable()`).
optional bool is_const_object = 4;
}

View File

@ -1,115 +0,0 @@
///
// Generated code. Do not modify.
///
library angular2.src.transform.common.model.proto_import_export_model;
import 'package:protobuf/protobuf.dart';
class ImportModel extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('ImportModel')
..a(1, 'uri', PbFieldType.QS)
..p(2, 'showCombinators', PbFieldType.PS)
..p(3, 'hideCombinators', PbFieldType.PS)
..a(4, 'prefix', PbFieldType.OS)
..a(5, 'isDeferred', PbFieldType.OB)
;
ImportModel() : super();
ImportModel.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ImportModel.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ImportModel clone() => new ImportModel()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
static ImportModel create() => new ImportModel();
static PbList<ImportModel> createRepeated() => new PbList<ImportModel>();
static ImportModel getDefault() {
if (_defaultInstance == null) _defaultInstance = new _ReadonlyImportModel();
return _defaultInstance;
}
static ImportModel _defaultInstance;
static void $checkItem(ImportModel v) {
if (v is !ImportModel) checkItemFailed(v, 'ImportModel');
}
String get uri => $_get(0, 1, '');
void set uri(String v) { $_setString(0, 1, v); }
bool hasUri() => $_has(0, 1);
void clearUri() => clearField(1);
List<String> get showCombinators => $_get(1, 2, null);
List<String> get hideCombinators => $_get(2, 3, null);
String get prefix => $_get(3, 4, '');
void set prefix(String v) { $_setString(3, 4, v); }
bool hasPrefix() => $_has(3, 4);
void clearPrefix() => clearField(4);
bool get isDeferred => $_get(4, 5, false);
void set isDeferred(bool v) { $_setBool(4, 5, v); }
bool hasIsDeferred() => $_has(4, 5);
void clearIsDeferred() => clearField(5);
}
class _ReadonlyImportModel extends ImportModel with ReadonlyMessageMixin {}
class ExportModel extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('ExportModel')
..a(1, 'uri', PbFieldType.QS)
..p(2, 'showCombinators', PbFieldType.PS)
..p(3, 'hideCombinators', PbFieldType.PS)
;
ExportModel() : super();
ExportModel.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ExportModel.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ExportModel clone() => new ExportModel()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
static ExportModel create() => new ExportModel();
static PbList<ExportModel> createRepeated() => new PbList<ExportModel>();
static ExportModel getDefault() {
if (_defaultInstance == null) _defaultInstance = new _ReadonlyExportModel();
return _defaultInstance;
}
static ExportModel _defaultInstance;
static void $checkItem(ExportModel v) {
if (v is !ExportModel) checkItemFailed(v, 'ExportModel');
}
String get uri => $_get(0, 1, '');
void set uri(String v) { $_setString(0, 1, v); }
bool hasUri() => $_has(0, 1);
void clearUri() => clearField(1);
List<String> get showCombinators => $_get(1, 2, null);
List<String> get hideCombinators => $_get(2, 3, null);
}
class _ReadonlyExportModel extends ExportModel with ReadonlyMessageMixin {}
const ImportModel$json = const {
'1': 'ImportModel',
'2': const [
const {'1': 'uri', '3': 1, '4': 2, '5': 9},
const {'1': 'show_combinators', '3': 2, '4': 3, '5': 9},
const {'1': 'hide_combinators', '3': 3, '4': 3, '5': 9},
const {'1': 'prefix', '3': 4, '4': 1, '5': 9},
const {'1': 'is_deferred', '3': 5, '4': 1, '5': 8},
],
};
const ExportModel$json = const {
'1': 'ExportModel',
'2': const [
const {'1': 'uri', '3': 1, '4': 2, '5': 9},
const {'1': 'show_combinators', '3': 2, '4': 3, '5': 9},
const {'1': 'hide_combinators', '3': 3, '4': 3, '5': 9},
],
};
/**
* Generated with:
* import_export_model.proto (36a3a72d0884b84b451b7188ffa1fc93b44e7b62)
* libprotoc 3.0.0
* dart-protoc-plugin (af5fc2bf1de367a434c3b1847ab260510878ffc0)
*/

View File

@ -1,28 +0,0 @@
syntax = "proto2";
package angular2.src.transform.common.model.proto;
// Note that the fields that are common between `ImportModel` and `ExportModel`
// are stored at the same indexes, which allows them to be semi-wire-compatible
// with one another. This will hopefully not be necessary to exploit, but on the
// chance that it is it's easier to define this now.
message ImportModel {
required string uri = 1;
repeated string show_combinators = 2;
repeated string hide_combinators = 3;
optional string prefix = 4;
optional bool is_deferred = 5;
}
// See message above about wire-compatiblity with `ImportModel`.
message ExportModel {
required string uri = 1;
repeated string show_combinators = 2;
repeated string hide_combinators = 3;
}

View File

@ -1,78 +0,0 @@
///
// Generated code. Do not modify.
///
library angular2.src.transform.common.model.proto_ng_deps_model;
import 'package:protobuf/protobuf.dart';
import 'import_export_model.pb.dart';
import 'reflection_info_model.pb.dart';
class NgDepsModel extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('NgDepsModel')
..a(1, 'libraryUri', PbFieldType.OS)
..p(2, 'partUris', PbFieldType.PS)
..pp(3, 'imports', PbFieldType.PM, ImportModel.$checkItem, ImportModel.create)
..pp(4, 'exports', PbFieldType.PM, ExportModel.$checkItem, ExportModel.create)
..pp(5, 'reflectables', PbFieldType.PM, ReflectionInfoModel.$checkItem, ReflectionInfoModel.create)
..a(6, 'sourceFile', PbFieldType.OS)
..pp(7, 'depImports', PbFieldType.PM, ImportModel.$checkItem, ImportModel.create)
;
NgDepsModel() : super();
NgDepsModel.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
NgDepsModel.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
NgDepsModel clone() => new NgDepsModel()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
static NgDepsModel create() => new NgDepsModel();
static PbList<NgDepsModel> createRepeated() => new PbList<NgDepsModel>();
static NgDepsModel getDefault() {
if (_defaultInstance == null) _defaultInstance = new _ReadonlyNgDepsModel();
return _defaultInstance;
}
static NgDepsModel _defaultInstance;
static void $checkItem(NgDepsModel v) {
if (v is !NgDepsModel) checkItemFailed(v, 'NgDepsModel');
}
String get libraryUri => $_get(0, 1, '');
void set libraryUri(String v) { $_setString(0, 1, v); }
bool hasLibraryUri() => $_has(0, 1);
void clearLibraryUri() => clearField(1);
List<String> get partUris => $_get(1, 2, null);
List<ImportModel> get imports => $_get(2, 3, null);
List<ExportModel> get exports => $_get(3, 4, null);
List<ReflectionInfoModel> get reflectables => $_get(4, 5, null);
String get sourceFile => $_get(5, 6, '');
void set sourceFile(String v) { $_setString(5, 6, v); }
bool hasSourceFile() => $_has(5, 6);
void clearSourceFile() => clearField(6);
List<ImportModel> get depImports => $_get(6, 7, null);
}
class _ReadonlyNgDepsModel extends NgDepsModel with ReadonlyMessageMixin {}
const NgDepsModel$json = const {
'1': 'NgDepsModel',
'2': const [
const {'1': 'library_uri', '3': 1, '4': 1, '5': 9},
const {'1': 'part_uris', '3': 2, '4': 3, '5': 9},
const {'1': 'imports', '3': 3, '4': 3, '5': 11, '6': '.angular2.src.transform.common.model.proto.ImportModel'},
const {'1': 'exports', '3': 4, '4': 3, '5': 11, '6': '.angular2.src.transform.common.model.proto.ExportModel'},
const {'1': 'reflectables', '3': 5, '4': 3, '5': 11, '6': '.angular2.src.transform.common.model.proto.ReflectionInfoModel'},
const {'1': 'source_file', '3': 6, '4': 1, '5': 9},
const {'1': 'dep_imports', '3': 7, '4': 3, '5': 11, '6': '.angular2.src.transform.common.model.proto.ImportModel'},
],
};
/**
* Generated with:
* ng_deps_model.proto (5c881da448125df1d4eefec6ec3e7b7b6c5c25c0)
* libprotoc 3.0.0
* dart-protoc-plugin (af5fc2bf1de367a434c3b1847ab260510878ffc0)
*/

View File

@ -1,27 +0,0 @@
syntax = "proto2";
import "import_export_model.proto";
import "reflection_info_model.proto";
package angular2.src.transform.common.model.proto;
message NgDepsModel {
optional string library_uri = 1;
repeated string part_uris = 2;
repeated ImportModel imports = 3;
repeated ExportModel exports = 4;
// All classes in `source_file` marked with @Injectable or a known subclass.
repeated ReflectionInfoModel reflectables = 5;
// The basename of the file from which the ng_deps were generated.
// Example: component.dart
optional string source_file = 6;
// Imports of the generated files associated with the declared `imports`
// and `exports` of the source file.
repeated ImportModel dep_imports = 7;
}

View File

@ -1,68 +0,0 @@
///
// Generated code. Do not modify.
///
library angular2.src.transform.common.model.proto_parameter_model;
import 'package:protobuf/protobuf.dart';
class ParameterModel extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('ParameterModel')
..a(1, 'typeName', PbFieldType.OS)
..a(2, 'typeArgs', PbFieldType.OS)
..p(3, 'metadata', PbFieldType.PS)
..a(4, 'paramName', PbFieldType.OS)
..hasRequiredFields = false
;
ParameterModel() : super();
ParameterModel.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ParameterModel.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ParameterModel clone() => new ParameterModel()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
static ParameterModel create() => new ParameterModel();
static PbList<ParameterModel> createRepeated() => new PbList<ParameterModel>();
static ParameterModel getDefault() {
if (_defaultInstance == null) _defaultInstance = new _ReadonlyParameterModel();
return _defaultInstance;
}
static ParameterModel _defaultInstance;
static void $checkItem(ParameterModel v) {
if (v is !ParameterModel) checkItemFailed(v, 'ParameterModel');
}
String get typeName => $_get(0, 1, '');
void set typeName(String v) { $_setString(0, 1, v); }
bool hasTypeName() => $_has(0, 1);
void clearTypeName() => clearField(1);
String get typeArgs => $_get(1, 2, '');
void set typeArgs(String v) { $_setString(1, 2, v); }
bool hasTypeArgs() => $_has(1, 2);
void clearTypeArgs() => clearField(2);
List<String> get metadata => $_get(2, 3, null);
String get paramName => $_get(3, 4, '');
void set paramName(String v) { $_setString(3, 4, v); }
bool hasParamName() => $_has(3, 4);
void clearParamName() => clearField(4);
}
class _ReadonlyParameterModel extends ParameterModel with ReadonlyMessageMixin {}
const ParameterModel$json = const {
'1': 'ParameterModel',
'2': const [
const {'1': 'type_name', '3': 1, '4': 1, '5': 9},
const {'1': 'type_args', '3': 2, '4': 1, '5': 9},
const {'1': 'metadata', '3': 3, '4': 3, '5': 9},
const {'1': 'param_name', '3': 4, '4': 1, '5': 9},
],
};
/**
* Generated with:
* parameter_model.proto (2a97dcb9a65b199f50fba67120a85590bceb083a)
* libprotoc 3.0.0
* dart-protoc-plugin (af5fc2bf1de367a434c3b1847ab260510878ffc0)
*/

View File

@ -1,13 +0,0 @@
syntax = "proto2";
package angular2.src.transform.common.model.proto;
message ParameterModel {
optional string type_name = 1;
optional string type_args = 2;
repeated string metadata = 3;
optional string param_name = 4;
}

View File

@ -1,129 +0,0 @@
///
// Generated code. Do not modify.
///
library angular2.src.transform.common.model.proto_reflection_info_model;
import 'package:protobuf/protobuf.dart';
import 'annotation_model.pb.dart';
import 'parameter_model.pb.dart';
class PrefixedType extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('PrefixedType')
..a(1, 'prefix', PbFieldType.OS)
..a(2, 'name', PbFieldType.OS)
..hasRequiredFields = false
;
PrefixedType() : super();
PrefixedType.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
PrefixedType.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
PrefixedType clone() => new PrefixedType()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
static PrefixedType create() => new PrefixedType();
static PbList<PrefixedType> createRepeated() => new PbList<PrefixedType>();
static PrefixedType getDefault() {
if (_defaultInstance == null) _defaultInstance = new _ReadonlyPrefixedType();
return _defaultInstance;
}
static PrefixedType _defaultInstance;
static void $checkItem(PrefixedType v) {
if (v is !PrefixedType) checkItemFailed(v, 'PrefixedType');
}
String get prefix => $_get(0, 1, '');
void set prefix(String v) { $_setString(0, 1, v); }
bool hasPrefix() => $_has(0, 1);
void clearPrefix() => clearField(1);
String get name => $_get(1, 2, '');
void set name(String v) { $_setString(1, 2, v); }
bool hasName() => $_has(1, 2);
void clearName() => clearField(2);
}
class _ReadonlyPrefixedType extends PrefixedType with ReadonlyMessageMixin {}
class ReflectionInfoModel extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('ReflectionInfoModel')
..a(1, 'name', PbFieldType.QS)
..a(2, 'ctorName', PbFieldType.OS)
..a(3, 'isFunction', PbFieldType.OB)
..pp(4, 'annotations', PbFieldType.PM, AnnotationModel.$checkItem, AnnotationModel.create)
..pp(5, 'parameters', PbFieldType.PM, ParameterModel.$checkItem, ParameterModel.create)
..p(6, 'interfaces', PbFieldType.PS)
..pp(7, 'directives', PbFieldType.PM, PrefixedType.$checkItem, PrefixedType.create)
..pp(8, 'pipes', PbFieldType.PM, PrefixedType.$checkItem, PrefixedType.create)
;
ReflectionInfoModel() : super();
ReflectionInfoModel.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ReflectionInfoModel.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ReflectionInfoModel clone() => new ReflectionInfoModel()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
static ReflectionInfoModel create() => new ReflectionInfoModel();
static PbList<ReflectionInfoModel> createRepeated() => new PbList<ReflectionInfoModel>();
static ReflectionInfoModel getDefault() {
if (_defaultInstance == null) _defaultInstance = new _ReadonlyReflectionInfoModel();
return _defaultInstance;
}
static ReflectionInfoModel _defaultInstance;
static void $checkItem(ReflectionInfoModel v) {
if (v is !ReflectionInfoModel) checkItemFailed(v, 'ReflectionInfoModel');
}
String get name => $_get(0, 1, '');
void set name(String v) { $_setString(0, 1, v); }
bool hasName() => $_has(0, 1);
void clearName() => clearField(1);
String get ctorName => $_get(1, 2, '');
void set ctorName(String v) { $_setString(1, 2, v); }
bool hasCtorName() => $_has(1, 2);
void clearCtorName() => clearField(2);
bool get isFunction => $_get(2, 3, false);
void set isFunction(bool v) { $_setBool(2, 3, v); }
bool hasIsFunction() => $_has(2, 3);
void clearIsFunction() => clearField(3);
List<AnnotationModel> get annotations => $_get(3, 4, null);
List<ParameterModel> get parameters => $_get(4, 5, null);
List<String> get interfaces => $_get(5, 6, null);
List<PrefixedType> get directives => $_get(6, 7, null);
List<PrefixedType> get pipes => $_get(7, 8, null);
}
class _ReadonlyReflectionInfoModel extends ReflectionInfoModel with ReadonlyMessageMixin {}
const PrefixedType$json = const {
'1': 'PrefixedType',
'2': const [
const {'1': 'prefix', '3': 1, '4': 1, '5': 9},
const {'1': 'name', '3': 2, '4': 1, '5': 9},
],
};
const ReflectionInfoModel$json = const {
'1': 'ReflectionInfoModel',
'2': const [
const {'1': 'name', '3': 1, '4': 2, '5': 9},
const {'1': 'ctor_name', '3': 2, '4': 1, '5': 9},
const {'1': 'is_function', '3': 3, '4': 1, '5': 8},
const {'1': 'annotations', '3': 4, '4': 3, '5': 11, '6': '.angular2.src.transform.common.model.proto.AnnotationModel'},
const {'1': 'parameters', '3': 5, '4': 3, '5': 11, '6': '.angular2.src.transform.common.model.proto.ParameterModel'},
const {'1': 'interfaces', '3': 6, '4': 3, '5': 9},
const {'1': 'directives', '3': 7, '4': 3, '5': 11, '6': '.angular2.src.transform.common.model.proto.PrefixedType'},
const {'1': 'pipes', '3': 8, '4': 3, '5': 11, '6': '.angular2.src.transform.common.model.proto.PrefixedType'},
],
};
/**
* Generated with:
* reflection_info_model.proto (c5cb9bba874abdca05cc0e4d69b66b7faa12fc1a)
* libprotoc 3.0.0
* dart-protoc-plugin (af5fc2bf1de367a434c3b1847ab260510878ffc0)
*/

View File

@ -1,40 +0,0 @@
syntax = "proto2";
import "annotation_model.proto";
import "parameter_model.proto";
package angular2.src.transform.common.model.proto;
message PrefixedType {
// The prefix used to reference this Type, if any.
optional string prefix = 1;
// The name of the Type or type alias.
// See https://goo.gl/d8XPt0 for info on type aliases.
optional string name = 2;
}
message ReflectionInfoModel {
// The (potentially prefixed) name of this Injectable.
// This can be a `Type` or a function name.
required string name = 1;
// The name of the ctor used to create this Injectable. In most cases, this
// will be null and we will use the default constructor.
optional string ctor_name = 2;
optional bool is_function = 3;
repeated AnnotationModel annotations = 4;
repeated ParameterModel parameters = 5;
repeated string interfaces = 6;
// Directive dependencies parsed from the @View or @Component `directives`
// parameter.
repeated PrefixedType directives = 7;
// Pipe dependencies parsed from the @View or @Component `pipes` parameter.
repeated PrefixedType pipes = 8;
}

View File

@ -1,83 +0,0 @@
library angular2.transform.common.model.source_module;
import 'package:path/path.dart' as path;
import 'package:angular2/src/transform/common/url_resolver.dart';
import 'import_export_model.pb.dart';
/// Generates an [ImportModel] for the file specified by `importPath`.
///
/// If `fromAbsolute` is specified, `importPath` may be a relative path,
/// otherwise it is expected to be absolute.
ImportModel toImportModel(String importPath,
{String prefix, String fromAbsolute}) {
var urlResolver = createOfflineCompileUrlResolver();
var codegenImportPath;
var importUri =
toAssetScheme(Uri.parse(urlResolver.resolve(fromAbsolute, importPath)));
if (_canPackageImport(importUri) ||
fromAbsolute == null ||
fromAbsolute.isEmpty) {
codegenImportPath = _toPackageImport(importUri);
} else {
var moduleUri = toAssetScheme(Uri.parse(fromAbsolute));
if (_canImportRelative(importUri, from: moduleUri)) {
codegenImportPath = path.url.relative(importUri.toString(),
from: path.dirname(moduleUri.toString()));
} else {
var errMsg;
if (fromAbsolute == null || fromAbsolute.isEmpty) {
errMsg = 'Can only import $importPath using a relative uri';
} else {
errMsg = 'Cannot import $importPath from $fromAbsolute';
}
throw new FormatException(errMsg, importPath);
}
}
final model = new ImportModel()..uri = codegenImportPath;
if (prefix != null && prefix.isNotEmpty) {
model.prefix = prefix;
}
return model;
}
// For a relative import, the scheme, first (package) and second (lib|test|web)
// path segments must be equal.
bool _canImportRelative(Uri importUri, {Uri from}) {
if (importUri == null) throw new ArgumentError.notNull('importUri');
if (from == null) throw new ArgumentError.notNull('from');
assert(importUri.scheme == 'asset');
assert(importUri.pathSegments.length >= 2);
assert(from.scheme == 'asset');
assert(from.pathSegments.length >= 2);
return importUri.pathSegments.first == from.pathSegments.first &&
importUri.pathSegments[1] == from.pathSegments[1];
}
/// Pub's package scheme assumes that an asset lives under the lib/ directory,
/// so an asset: Uri is package-importable if its second path segment is lib/.
///
/// For a file located at angular2/lib/src/file.dart:
/// - Asset scheme => asset:angular2/lib/src/file.dart
/// - Package scheme => package:angular2/src/file.dart
bool _canPackageImport(Uri assetImport) {
if (assetImport == null) throw new ArgumentError.notNull('assetImport');
if (!assetImport.isAbsolute || assetImport.scheme != 'asset') {
throw new ArgumentError.value(assetImport.toString(), 'assetImport',
'Must be an absolute uri using the asset: scheme');
}
return assetImport.pathSegments.length >= 2 &&
assetImport.pathSegments[1] == 'lib';
}
String _toPackageImport(Uri assetImport) {
assert(_canPackageImport(assetImport));
var subPath = assetImport.pathSegments
.getRange(2, assetImport.pathSegments.length)
.join('/');
return 'package:${assetImport.pathSegments.first}/$subPath';
}

View File

@ -1,26 +0,0 @@
library angular2.transform.common.naive_eval;
import 'package:analyzer/analyzer.dart';
final _constantEvaluator = new ConstantEvaluator();
/// The value returned if the result of `naiveEval` is not a constant.
final NOT_A_CONSTANT = ConstantEvaluator.NOT_A_CONSTANT;
/// Performs a very limited syntactic evaluation of `expr`.
///
/// This lack of semantic information means this method cannot do much - for
/// example, it can create a list from a list literal and combine adjacent
/// strings but cannot determine that an identifier is a constant string,
/// even if that identifier is defined in the same [CompilationUnit].
///
/// Returns the result of evaluation or [NOT_A_CONSTANT] where appropriate.
dynamic naiveEval(Expression expr) {
var val;
if (expr is SimpleStringLiteral) {
val = stringLiteralToString(expr);
} else {
val = expr.accept(_constantEvaluator);
}
return val != NOT_A_CONSTANT ? val : null;
}

View File

@ -1,89 +0,0 @@
library angular2.transform.common.names;
const BOOTSTRAP_NAME = 'bootstrap';
const BOOTSTRAP_STATIC_NAME = 'bootstrapStatic';
const SETUP_METHOD_NAME = 'initReflector';
const REFLECTOR_VAR_NAME = 'reflector';
const TRANSFORM_DYNAMIC_MODE = 'transform_dynamic';
const CSS_EXTENSION = '.css';
const DEFERRED_EXTENSION = '.dart.deferredCount';
const SHIMMED_STYLESHEET_EXTENSION = '.css.shim.dart';
const NON_SHIMMED_STYLESHEET_EXTENSION = '.css.dart';
const META_EXTENSION = '.ng_meta.json';
const REFLECTION_CAPABILITIES_NAME = 'ReflectionCapabilities';
const REFLECTOR_IMPORT = 'package:angular2/src/core/reflection/reflection.dart';
const REFLECTOR_PREFIX = '_ngRef';
const REGISTER_TYPE_METHOD_NAME = 'registerType';
const SUMMARY_META_EXTENSION = '.ng_summary.json';
const TEMPLATE_EXTENSION = '.ngfactory.dart';
/// Note that due to the implementation of `_toExtension`, ordering is
/// important. For example, putting '.dart' first in this list will cause
/// incorrect behavior because it will (incompletely) match '.ngfactory.dart'
/// files.
const ALL_EXTENSIONS = const [
DEFERRED_EXTENSION,
META_EXTENSION,
SUMMARY_META_EXTENSION,
TEMPLATE_EXTENSION,
'.dart'
];
/// Whether `uri` was created by a transform phase.
///
/// This may return false positives for problematic inputs.
/// This just tests file extensions known to be created by the transformer, so
/// any files named like transformer outputs will be reported as generated.
bool isGenerated(String uri) {
return const [
DEFERRED_EXTENSION,
META_EXTENSION,
NON_SHIMMED_STYLESHEET_EXTENSION,
SHIMMED_STYLESHEET_EXTENSION,
SUMMARY_META_EXTENSION,
TEMPLATE_EXTENSION,
].any((ext) => uri.endsWith(ext));
}
/// Returns `uri` with its extension updated to [DEFERRED_EXTENSION].
String toDeferredExtension(String uri) =>
_toExtension(uri, ALL_EXTENSIONS, DEFERRED_EXTENSION);
/// Returns `uri` with its extension updated to [META_EXTENSION].
String toMetaExtension(String uri) =>
_toExtension(uri, ALL_EXTENSIONS, META_EXTENSION);
/// Returns `uri` with its extension updated to [TEMPLATES_EXTENSION].
String toTemplateExtension(String uri) =>
_toExtension(uri, ALL_EXTENSIONS, TEMPLATE_EXTENSION);
/// Returns `uri` with its extension updated to [SHIMMED_STYLESHEET_EXTENSION].
String toShimmedStylesheetExtension(String uri) =>
_toExtension(uri, const [CSS_EXTENSION], SHIMMED_STYLESHEET_EXTENSION);
/// Returns `uri` with its extension updated to [NON_SHIMMED_STYLESHEET_EXTENSION].
String toNonShimmedStylesheetExtension(String uri) =>
_toExtension(uri, const [CSS_EXTENSION], NON_SHIMMED_STYLESHEET_EXTENSION);
/// Returns `uri` with its extension updated to [SUMMARY_META_EXTENSION].
String toSummaryExtension(String uri) =>
_toExtension(uri, ALL_EXTENSIONS, SUMMARY_META_EXTENSION);
/// Returns `uri` with its extension updated to `toExtension` if its
/// extension is currently in `fromExtension`.
String _toExtension(
String uri, Iterable<String> fromExtensions, String toExtension) {
if (uri == null) return null;
if (uri.endsWith(toExtension)) return uri;
for (var extension in fromExtensions) {
if (uri.endsWith(extension)) {
return '${uri.substring(0, uri.length-extension.length)}'
'$toExtension';
}
}
throw new ArgumentError.value(
uri,
'uri',
'Provided value ends with an unexpected extension. '
'Expected extension(s): [${fromExtensions.join(', ')}].');
}

View File

@ -1,52 +0,0 @@
library angular2.transform.template_compiler.ng_compiler;
import 'package:angular2/src/compiler/config.dart';
import 'package:angular2/src/compiler/view_compiler/view_compiler.dart';
import 'package:angular2/src/core/console.dart';
import 'package:angular2/src/compiler/html_parser.dart';
import 'package:angular2/src/compiler/style_compiler.dart';
import 'package:angular2/src/compiler/offline_compiler.dart';
import 'package:angular2/src/compiler/directive_normalizer.dart';
import 'package:angular2/src/compiler/template_parser.dart';
import 'package:angular2/src/compiler/expression_parser/lexer.dart' as ng;
import 'package:angular2/src/compiler/expression_parser/parser.dart' as ng;
import 'package:angular2/src/compiler/schema/dom_element_schema_registry.dart';
import 'package:angular2/src/compiler/output/dart_emitter.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/i18n.dart';
import 'xhr_impl.dart';
import 'url_resolver.dart';
OfflineCompiler createTemplateCompiler(AssetReader reader,
{CompilerConfig compilerConfig, XmbDeserializationResult translations}) {
var _xhr = new XhrImpl(reader);
var _urlResolver = createOfflineCompileUrlResolver();
// TODO(yjbanov): add router AST transformer when ready
var parser = new ng.Parser(new ng.Lexer());
var _htmlParser = _createHtmlParser(translations, parser);
var templateParser = new TemplateParser(
parser,
new DomElementSchemaRegistry(),
_htmlParser,
new Console(),
[new RouterLinkTransform(parser)]);
return new OfflineCompiler(
new DirectiveNormalizer(_xhr, _urlResolver, _htmlParser),
templateParser,
new StyleCompiler(_urlResolver),
new ViewCompiler(compilerConfig),
new DartEmitter()
);
}
HtmlParser _createHtmlParser(XmbDeserializationResult translations, ng.Parser parser) {
if (translations != null) {
return new I18nHtmlParser(new HtmlParser(), parser, translations.content, translations.messages);
} else {
return new HtmlParser();
}
}

View File

@ -1,151 +0,0 @@
library angular2.transform.common.ng_meta;
import 'package:angular2/src/compiler/compile_metadata.dart';
import 'logging.dart';
import 'model/ng_deps_model.pb.dart';
import 'url_resolver.dart' show isDartCoreUri;
/// Metadata about directives, pipes, directive aliases, and injectable values.
///
/// [NgMeta] is used in three stages of the transformation process:
///
/// First we store directive aliases and types exported directly (that is, not
/// via an `export` statement) from a single file in an [NgMeta] instance.
///
/// In the second phase, we perform two actions:
/// 1. Incorporate all the data from [NgMeta] instances created by all
/// files `exported` by the original file, such that all aliases and types
/// visible when importing the original file are stored in its associated
/// [NgMeta] instance.
/// 2. Use the [NgDepsModel] to write Dart code registering all injectable
/// values with the Angular 2 runtime reflection system.
///
/// Later in the compilation process, the template compiler needs to reason
/// about the namespace of import prefixes, so it will combine multiple [NgMeta]
/// instances together if they were imported into a file with the same prefix.
///
/// Instances of this class are serialized into `.ng_summary.json` and
/// `.ng_meta.json` files as intermediate assets during the compilation process.
class NgMeta {
static const _ALIAS_VALUE = 'alias';
static const _NG_DEPS_KEY = 'ngDeps';
static const _TYPE_VALUE = 'type';
/// Metadata for each identifier
/// Type: [CompileDirectiveMetadata]|[CompilePipeMetadata]|[CompileTypeMetadata]|
/// [CompileIdentifierMetadata]|[CompileFactoryMetadata]
final Map<String, dynamic> identifiers;
/// List of other types and names associated with a given name.
final Map<String, List<String>> aliases;
// The NgDeps generated from
final NgDepsModel ngDeps;
NgMeta({Map<String, List<String>> aliases,
Map<String, dynamic> identifiers,
this.ngDeps: null})
:this.aliases = aliases != null ? aliases : {},
this.identifiers = identifiers != null ? identifiers : {};
NgMeta.empty() : this();
// `model` can be an `ImportModel` or `ExportModel`.
static bool _isDartImport(dynamic model) => isDartCoreUri(model.uri);
bool get isNgDepsEmpty {
if (ngDeps == null) return true;
// If this file imports only dart: libraries and does not define any
// reflectables of its own, we don't need to register any information from
// it with the Angular 2 reflector.
if (ngDeps.reflectables == null || ngDeps.reflectables.isEmpty) {
if ((ngDeps.imports == null || ngDeps.imports.every(_isDartImport)) &&
(ngDeps.exports == null || ngDeps.exports.every(_isDartImport))) {
return true;
}
}
return false;
}
bool get isEmpty => identifiers.isEmpty && aliases.isEmpty && isNgDepsEmpty;
bool get needsResolution {
return identifiers.values.any((id) =>
id is CompileDirectiveMetadata || id is CompilePipeMetadata || id is CompileTypeMetadata || id is CompileFactoryMetadata
|| (id is CompileIdentifierMetadata && id.value != null));
}
/// Parse from the serialized form produced by [toJson].
factory NgMeta.fromJson(Map json) {
var ngDeps = null;
if (json.containsKey(_NG_DEPS_KEY)) {
var ngDepsJsonMap = json[_NG_DEPS_KEY];
if (ngDepsJsonMap != null) {
if (ngDepsJsonMap is! Map) {
log.warning(
'Unexpected value $ngDepsJsonMap for key "$_NG_DEPS_KEY" in NgMeta.');
} else {
ngDeps = new NgDepsModel()..mergeFromJsonMap(ngDepsJsonMap);
}
}
}
final aliases = json[_ALIAS_VALUE] != null ? json[_ALIAS_VALUE] : {};
final identifiers = {};
if (json.containsKey(_TYPE_VALUE)) {
for (var key in json[_TYPE_VALUE].keys) {
var entry = json[_TYPE_VALUE][key];
if (entry is! Map) {
log.warning('Unexpected value $entry for key "$key" in NgMeta.');
continue;
}
identifiers[key] = metadataFromJson(entry);
}
}
return new NgMeta(identifiers: identifiers, aliases: aliases, ngDeps: ngDeps);
}
/// Serialized representation of this instance.
Map toJson() {
var result = {};
result[_NG_DEPS_KEY] = isNgDepsEmpty ? null : ngDeps.writeToJsonMap();
result[_TYPE_VALUE] = {};
identifiers.forEach((k, v) {
result[_TYPE_VALUE][k] = v.toJson();
});
result[_ALIAS_VALUE] = aliases;
return result;
}
/// Merge into this instance all information from [other].
/// This does not include `ngDeps`.
void addAll(NgMeta other) {
aliases.addAll(other.aliases);
identifiers.addAll(other.identifiers);
}
/// Returns the metadata for every type associated with the given [alias].
List<dynamic> flatten(String alias) {
var result = [];
helper(name, path) {
final newPath = []..addAll(path)..add(name);
if (path.contains(name)) {
log.error('Circular alias dependency for "$name". Cycle: ${newPath.join(' -> ')}.');
return;
}
if (aliases.containsKey(name)) {
aliases[name].forEach((n) => helper(n, newPath));
} else if (identifiers.containsKey(name)) {
result.add(identifiers[name]);
} else {
log.error('Unknown alias: ${newPath.join(' -> ')}. Make sure you export ${name} from the file where ${path.last} is defined.');
}
}
helper(alias, []);
return result;
}
}

View File

@ -1,157 +0,0 @@
library angular2.transform.common.options;
import 'package:glob/glob.dart';
import 'annotation_matcher.dart';
import 'mirror_mode.dart';
import 'package:barback/src/asset/asset_id.dart';
const CUSTOM_ANNOTATIONS_PARAM = 'custom_annotations';
const ENTRY_POINT_PARAM = 'entry_points';
const FORMAT_CODE_PARAM = 'format_code';
const REFLECT_PROPERTIES_AS_ATTRIBUTES = 'reflect_properties_as_attributes';
const PLATFORM_DIRECTIVES = 'platform_directives';
const PLATFORM_PIPES = 'platform_pipes';
const RESOLVED_IDENTIFIERS = 'resolved_identifiers';
const ERROR_ON_MISSING_IDENTIFIERS = 'error_on_missing_identifiers';
const INIT_REFLECTOR_PARAM = 'init_reflector';
const INLINE_VIEWS_PARAM = 'inline_views';
const MIRROR_MODE_PARAM = 'mirror_mode';
const CODEGEN_MODE_PARAM = 'codegen_mode';
const LAZY_TRANSFORMERS = 'lazy_transformers';
const TRANSLATIONS = 'translations';
const CODEGEN_DEBUG_MODE = 'debug';
/// Provides information necessary to transform an Angular2 app.
class TransformerOptions {
final List<Glob> entryPointGlobs;
/// The path to the files where the application's calls to `bootstrap` are.
final List<String> entryPoints;
/// The `BarbackMode#name` we are running in.
final String modeName;
/// The [MirrorMode] to use for the transformation.
final MirrorMode mirrorMode;
/// Whether to generate calls to our generated `initReflector` code
final bool initReflector;
/// The [AnnotationMatcher] which is used to identify angular annotations.
final AnnotationMatcher annotationMatcher;
/// Whether to reflect property values as attributes.
/// If this is `true`, the change detection code will echo set property values
/// as attributes on DOM elements, which may aid in application debugging.
final bool reflectPropertiesAsAttributes;
/// Whether to generate debug information in views.
/// Needed for testing and improves error messages when exception are triggered.
final String codegenMode;
/// A set of directives that will be automatically passed-in to the template compiler
/// Format of an item in the list:
/// angular2/lib/src/common/common_directives.dart#COMMON_DIRECTIVES
final List<String> platformDirectives;
/// A set of pipes that will be automatically passed-in to the template compiler
/// Format of an item in the list:
/// angular2/lib/src/common/pipes.dart#COMMON_PIPES
final List<String> platformPipes;
/// A map of identifier/asset pairs used when resolving identifiers.
final Map<String, String> resolvedIdentifiers;
/// when set ot false, the transformer will warn about missing identifiers but not error
final bool errorOnMissingIdentifiers;
/// Whether to format generated code.
/// Code that is only modified will never be formatted because doing so may
/// invalidate the source maps generated by `dart2js` and/or other tools.
final bool formatCode;
/// Whether to inline views.
/// If this is `true`, the transformer will *only* make a single pass over the
/// input files and inline `templateUrl` and `styleUrls` values.
/// This is undocumented, for testing purposes only, and may change or break
/// at any time.
final bool inlineViews;
/// Whether to make transformers lazy.
/// If this is `true`, and in `debug` mode only, the transformers will be
/// lazy (will only build assets that are requested).
/// This is undocumented, for testing purposes only, and may change or break
/// at any time.
final bool lazyTransformers;
/// Whether to generate compiled templates.
///
/// This option is strictly for internal testing and is not available as an
/// option on the transformer.
/// Setting this to `false` means that our generated .ngfactory.dart files do
/// not have any compiled templates or change detectors defined in them.
/// These files will not be usable, but this allows us to test the code output
/// of the transformer without breaking when compiled template internals
/// change.
final bool genCompiledTemplates;
/// The path to the file with translations.
final AssetId translations;
TransformerOptions._internal(
this.entryPoints,
this.entryPointGlobs,
this.modeName,
this.mirrorMode,
this.initReflector,
this.annotationMatcher,
{this.formatCode,
this.codegenMode,
this.genCompiledTemplates,
this.inlineViews,
this.lazyTransformers,
this.platformDirectives,
this.platformPipes,
this.resolvedIdentifiers,
this.errorOnMissingIdentifiers,
this.translations,
this.reflectPropertiesAsAttributes});
factory TransformerOptions(List<String> entryPoints,
{String modeName: 'release',
MirrorMode mirrorMode: MirrorMode.none,
bool initReflector: true,
List<ClassDescriptor> customAnnotationDescriptors: const [],
bool inlineViews: false,
String codegenMode: '',
bool genCompiledTemplates: true,
bool reflectPropertiesAsAttributes: false,
bool errorOnMissingIdentifiers: true,
List<String> platformDirectives,
List<String> platformPipes,
Map<String, String> resolvedIdentifiers,
bool lazyTransformers: false,
AssetId translations: null,
bool formatCode: false}) {
var annotationMatcher = new AnnotationMatcher()
..addAll(customAnnotationDescriptors);
var entryPointGlobs = entryPoints != null
? entryPoints.map((path) => new Glob(path)).toList(growable: false)
: null;
return new TransformerOptions._internal(entryPoints, entryPointGlobs,
modeName, mirrorMode, initReflector, annotationMatcher,
codegenMode: codegenMode,
genCompiledTemplates: genCompiledTemplates,
reflectPropertiesAsAttributes: reflectPropertiesAsAttributes,
platformDirectives: platformDirectives,
platformPipes: platformPipes,
resolvedIdentifiers: resolvedIdentifiers,
errorOnMissingIdentifiers: errorOnMissingIdentifiers,
inlineViews: inlineViews,
lazyTransformers: lazyTransformers,
translations: translations,
formatCode: formatCode);
}
}

View File

@ -1,143 +0,0 @@
library angular2.transform.common.options_reader;
import 'dart:io';
import 'package:barback/barback.dart';
import 'annotation_matcher.dart';
import 'mirror_mode.dart';
import 'options.dart';
import './url_resolver.dart';
TransformerOptions parseBarbackSettings(BarbackSettings settings) {
var config = settings.configuration;
var entryPoints = _readStringList(config, ENTRY_POINT_PARAM);
var initReflector =
_readBool(config, INIT_REFLECTOR_PARAM, defaultValue: true);
var reflectPropertiesAsAttributes =
_readBool(config, REFLECT_PROPERTIES_AS_ATTRIBUTES, defaultValue: false);
var platformDirectives = _readStringList(config, PLATFORM_DIRECTIVES);
var platformPipes = _readStringList(config, PLATFORM_PIPES);
var resolvedIdentifiers = config[RESOLVED_IDENTIFIERS];
var errorOnMissingIdentifiers = _readBool(config, ERROR_ON_MISSING_IDENTIFIERS, defaultValue: true);
var formatCode = _readBool(config, FORMAT_CODE_PARAM, defaultValue: false);
String mirrorModeVal =
config.containsKey(MIRROR_MODE_PARAM) ? config[MIRROR_MODE_PARAM] : '';
var mirrorMode = MirrorMode.none;
var codegenMode;
if (settings.mode == BarbackMode.DEBUG) {
codegenMode = CODEGEN_DEBUG_MODE;
} else {
codegenMode = config[CODEGEN_MODE_PARAM];
}
switch (mirrorModeVal) {
case 'debug':
mirrorMode = MirrorMode.debug;
break;
case 'verbose':
mirrorMode = MirrorMode.verbose;
break;
default:
mirrorMode = MirrorMode.none;
break;
}
return new TransformerOptions(entryPoints,
modeName: settings.mode.name,
mirrorMode: mirrorMode,
initReflector: initReflector,
codegenMode: codegenMode,
customAnnotationDescriptors: _readCustomAnnotations(config),
reflectPropertiesAsAttributes: reflectPropertiesAsAttributes,
platformDirectives: platformDirectives,
platformPipes: platformPipes,
resolvedIdentifiers: resolvedIdentifiers,
errorOnMissingIdentifiers: errorOnMissingIdentifiers,
inlineViews: _readBool(config, INLINE_VIEWS_PARAM, defaultValue: false),
lazyTransformers:
_readBool(config, LAZY_TRANSFORMERS, defaultValue: false),
translations: _readAssetId(config, TRANSLATIONS),
formatCode: formatCode);
}
bool _readBool(Map config, String paramName, {bool defaultValue}) {
return config.containsKey(paramName)
? config[paramName] != false
: defaultValue;
}
AssetId _readAssetId(Map config, String paramName) {
if (config.containsKey(paramName)) {
return fromUri(config[paramName]);
} else {
return null;
}
}
/// Cribbed from the polymer project.
/// {@link https://github.com/dart-lang/polymer-dart}
List<String> _readStringList(Map config, String paramName) {
var value = config[paramName];
if (value == null) return null;
var result = [];
bool error = false;
if (value is List) {
result = value;
error = value.any((e) => e is! String);
} else if (value is String) {
result = [value];
error = false;
} else {
error = true;
}
if (error) {
stderr.writeln(
'Invalid value for "$paramName" in the Angular 2 transformer.');
}
return result;
}
/// Parse the [CUSTOM_ANNOTATIONS_PARAM] options out of the transformer into
/// [ClassDescriptor]s.
List<ClassDescriptor> _readCustomAnnotations(Map config) {
var descriptors = [];
var customAnnotations = config[CUSTOM_ANNOTATIONS_PARAM];
if (customAnnotations == null) return descriptors;
var error = false;
if (customAnnotations is! List) {
error = true;
} else {
for (var description in customAnnotations) {
if (description is! Map) {
error = true;
continue;
}
var name = description['name'];
var import = description['import'];
var superClass = description['superClass'];
if (name == null || import == null || superClass == null) {
error = true;
continue;
}
descriptors
.add(new ClassDescriptor(name, import, superClass: superClass));
}
}
if (error) {
stderr.writeln(CUSTOM_ANNOTATIONS_ERROR);
}
return descriptors;
}
const CUSTOM_ANNOTATIONS_ERROR = '''
Invalid value for $CUSTOM_ANNOTATIONS_PARAM in the Angular2 transformer.
Expected something that looks like the following:
transformers:
- angular2[/transform/codegen]:
custom_annotations:
- name: MyAnnotation
import: 'package:my_package/my_annotation.dart'
superClass: Component
- name: ...
import: ...
superClass: ...''';

View File

@ -1,64 +0,0 @@
library angular2.transform.template_compiler.url_resolver;
import 'package:barback/barback.dart';
export 'package:angular2/src/compiler/url_resolver.dart' show createOfflineCompileUrlResolver;
String toAssetUri(AssetId assetId) {
if (assetId == null) throw new ArgumentError.notNull('assetId');
return 'asset:${assetId.package}/${assetId.path}';
}
AssetId fromUri(String assetUri) {
if (assetUri == null) throw new ArgumentError.notNull('assetUri');
if (assetUri.isEmpty)
throw new ArgumentError.value('(empty string)', 'assetUri');
var uri = toAssetScheme(Uri.parse(assetUri));
return new AssetId(
uri.pathSegments.first, uri.pathSegments.skip(1).join('/'));
}
/// Converts `absoluteUri` to use the 'asset' scheme used in the Angular 2
/// template compiler.
///
/// The `scheme` of `absoluteUri` is expected to be either 'package' or
/// 'asset'.
Uri toAssetScheme(Uri absoluteUri) {
if (absoluteUri == null) throw new ArgumentError.notNull('absoluteUri');
if (!absoluteUri.isAbsolute) {
throw new ArgumentError.value(absoluteUri.toString(), 'absoluteUri',
'Value passed must be an absolute uri');
}
if (absoluteUri.scheme == 'asset') {
if (absoluteUri.pathSegments.length < 3) {
throw new FormatException(
'An asset: URI must have at least 3 path '
'segments, for example '
'asset:<package-name>/<first-level-dir>/<path-to-dart-file>.',
absoluteUri.toString());
}
return absoluteUri;
}
if (absoluteUri.scheme != 'package') {
// Pass through URIs with non-package scheme
return absoluteUri;
}
if (absoluteUri.pathSegments.length < 2) {
throw new FormatException(
'A package: URI must have at least 2 path '
'segments, for example '
'package:<package-name>/<path-to-dart-file>',
absoluteUri.toString());
}
var pathSegments = absoluteUri.pathSegments.toList()..insert(1, 'lib');
return new Uri(scheme: 'asset', pathSegments: pathSegments);
}
bool isDartCoreUri(String uri) {
if (uri == null) throw new ArgumentError.notNull('uri');
if (uri.isEmpty) throw new ArgumentError.value('(empty string)', 'uri');
return uri.startsWith('dart:');
}

View File

@ -1,31 +0,0 @@
library angular2.transform.template_compiler.xhr_impl;
import 'dart:async';
import 'package:angular2/src/compiler/xhr.dart' show XHR;
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/url_resolver.dart';
/// Transformer-specific implementation of XHR that is backed by an
/// [AssetReader].
///
/// This implementation expects urls using the asset: scheme.
/// See [src/transform/common/url_resolver.dart] for a way to convert package:
/// and relative urls to asset: urls.
class XhrImpl implements XHR {
final AssetReader _reader;
XhrImpl(this._reader);
Future<String> get(String url) async {
final assetId = fromUri(url);
if (!url.startsWith('asset:')) {
log.warning('XhrImpl received unexpected url: $url');
}
if (!await _reader.hasInput(assetId)) {
throw new ArgumentError.value('Could not read asset at uri $url', 'url');
}
return _reader.readAsString(assetId);
}
}

View File

@ -1,74 +0,0 @@
library angular2.src.transform.common.zone;
import 'dart:async';
import 'package:analyzer/analyzer.dart';
import 'package:barback/barback.dart';
import 'package:source_span/source_span.dart';
import 'package:angular2/src/compiler/offline_compiler.dart';
typedef _SimpleCallback();
// Keys used to store zone local values on the current zone.
final _loggerKey = #loggingZonedLoggerKey;
final _templateCompilerKey = #templateCompilerKey;
/// Executes `fn` inside a new `Zone` with the provided zone-local values.
Future<dynamic> exec(_SimpleCallback fn,
{TransformLogger log, OfflineCompiler templateCompiler}) async {
return runZoned(() async {
try {
return await fn();
} on AnalyzerError catch (e) {
// Do not worry about printing the stack trace, barback will handle
// that on its own when it catches the rethrown exception.
log.error(' Failed with ${e.runtimeType}\n${_friendlyError(e.error)}');
rethrow;
} on AnalyzerErrorGroup catch (eGroup) {
// See above re: stack trace.
var numErrors = eGroup.errors.length;
if (numErrors == 1) {
log.error(_friendlyError(eGroup.errors[0].error));
} else {
var buf = new StringBuffer();
buf.writeln(' Failed with ${numErrors} errors');
for (var i = 0; i < numErrors; ++i) {
buf.writeln(
'Error ${i + 1}: ${_friendlyError(eGroup.errors[i].error)}');
}
log.error('$buf');
}
rethrow;
}
}, zoneValues: {_loggerKey: log, _templateCompilerKey: templateCompiler});
}
/// The [TransformLogger] for the current zone.
///
/// Typically, this should not be used directly, since it will return `null` if
/// there is no [TransformLogger] registered on the current zone. Instead,
/// import `logging.dart` and use the `log` value it exports, which defines a
/// reasonable default value.
TransformLogger get log => Zone.current[_loggerKey] as TransformLogger;
/// The [OfflineCompiler] for the current zone.
///
/// This will return `null` if there is no [OfflineCompiler] registered on the
/// current zone.
OfflineCompiler get templateCompiler =>
Zone.current[_templateCompilerKey] as OfflineCompiler;
/// Generate a human-readable error message from `error`.
String _friendlyError(AnalysisError error) {
if (error.source != null) {
var file =
new SourceFile(error.source.contents.data, url: error.source.fullName);
return file
.span(error.offset, error.offset + error.length)
.message(error.message, color: false);
} else {
return '<unknown location>: ${error.message}';
}
}

View File

@ -1,179 +0,0 @@
library angular2.transform.deferred_rewriter.rewriter;
import 'dart:async';
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:barback/barback.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/url_resolver.dart';
/// Rewrites `loadLibrary` calls to initialize libraries once loaded.
///
/// 1. Finds all the deferred library imports and loadLibrary invocations in
/// `_entryPoint`
/// 2. Removes any libraries that don't require angular codegen.
/// 3. For the remaining libraries, rewrites the import to the corresponding
/// `.ngfactory.dart` file.
/// 4. Chains a future to the `loadLibrary` call which initializes the
/// library.
///
/// To the extent possible, this method does not change line numbers or
/// offsets in the provided code to facilitate debugging via source maps.
Future<String> rewriteLibrary(AssetId entryPoint, AssetReader reader) async {
var code = await reader.readAsString(entryPoint);
return logElapsedAsync(() async {
// If we can determine there are no deferred libraries, avoid additional
// parsing the entire file and bail early.
var onlyDirectives = parseDirectives(code, name: entryPoint.path);
if (onlyDirectives == null) {
log.fine('No directives parsed, bailing early.', asset: entryPoint);
return null;
}
final importVisitor = new _FindDeferredLibraries(reader, entryPoint);
onlyDirectives.directives.accept(importVisitor);
// Get imports that need rewriting.
final deferredImports = await importVisitor.process();
if (deferredImports.isEmpty) {
log.fine('There are no deferred library imports that need rewriting.',
asset: entryPoint);
return null;
}
var node = parseCompilationUnit(code, name: entryPoint.path);
if (node == null) {
log.fine('No declarations parsed, bailing early.', asset: entryPoint);
return null;
}
final declarationsVisitor = new _FindLoadLibraryCalls(deferredImports);
node.declarations.accept(declarationsVisitor);
// Get libraries that need rewriting.
if (declarationsVisitor.loadLibraryInvocations.isEmpty) {
log.fine(
'There are no loadLibrary invocations that need to be rewritten.',
asset: entryPoint);
return null;
}
return _rewriteLibrary(
code, deferredImports, declarationsVisitor.loadLibraryInvocations);
}, operationName: 'rewriteDeferredLibraries', assetId: entryPoint);
}
/// Rewrites the original [code] to initialize deferred libraries prior to use.
///
/// Note: This method may modify the order of [imports] and [loadLibCalls].
String _rewriteLibrary(String code, List<ImportDirective> imports,
List<MethodInvocation> loadLibCalls) {
/// Compares two [AstNode]s by position in the source code.
var _compareNodes = (AstNode a, AstNode b) => a.offset - b.offset;
// Necessary for indexes into [code] to function.
imports.sort(_compareNodes);
loadLibCalls.sort(_compareNodes);
var buf = new StringBuffer();
var idx = imports.fold(0, (int lastIdx, ImportDirective node) {
// Write from where we left off until the start of the import uri.
buf.write(code.substring(lastIdx, node.uri.offset));
// Rewrite the uri to be that of the generated file.
buf.write("'${toTemplateExtension('${node.uri.stringValue}')}'");
// Update the last index we've processed.
return node.uri.end;
});
idx = loadLibCalls.fold(idx, (int lastIdx, MethodInvocation node) {
buf.write(code.substring(lastIdx, node.offset));
var prefix = (node.realTarget as SimpleIdentifier).name;
// Chain a future that initializes the reflector.
buf.write('$prefix.loadLibrary().then((_) {$prefix.initReflector();})');
return node.end;
});
if (idx < code.length) buf.write(code.substring(idx));
return '$buf';
}
/// Finds all `deferred` [ImportDirectives]s in an Ast that require init.
///
/// Use this to visit all [ImportDirective]s, then call [process] to get only
/// those [ImportDirective]s which are `deferred` and need Angular 2
/// initialization before use.
class _FindDeferredLibraries extends Object with SimpleAstVisitor<Object> {
final _deferredImports = <ImportDirective>[];
final _urlResolver = createOfflineCompileUrlResolver();
final AssetReader _reader;
final AssetId _entryPoint;
final String _entryPointUri;
_FindDeferredLibraries(this._reader, AssetId entryPoint)
: _entryPoint = entryPoint,
_entryPointUri = toAssetUri(entryPoint);
@override
Object visitImportDirective(ImportDirective node) {
if (node.deferredKeyword != null) {
_deferredImports.add(node);
}
return null;
}
/// Gets the [AssetId] for the .ng_meta.json file associated with [import].
AssetId _getAssociatedMetaAsset(ImportDirective import) {
final importUri = stringLiteralToString(import.uri);
final associatedMetaUri = toMetaExtension(importUri);
return fromUri(_urlResolver.resolve(_entryPointUri, associatedMetaUri));
}
/// Gets a list of `deferred` [ImportDirective]s which need init.
///
/// Removes all [ImportDirective]s from [_deferredImports] without an
/// associated .ng_meta.json file.
Future<List<ImportDirective>> process() async {
// Parallel array with whether the input has an associated .ng_meta.json
// file.
final List<bool> hasInputs = await Future.wait(
_deferredImports.map(_getAssociatedMetaAsset).map(_reader.hasInput));
// Filter out any deferred imports that do not have an associated generated
// file.
// Iteration order is important!
for (var i = _deferredImports.length - 1; i >= 0; --i) {
if (!hasInputs[i]) {
_deferredImports.removeAt(i);
}
}
return _deferredImports;
}
}
/// Finds all `loadLibrary` calls in the Ast that require init.
class _FindLoadLibraryCalls extends Object with RecursiveAstVisitor<Object> {
/// The prefixes used by all `deferred` [ImportDirective]s that need init.
final Set _deferredPrefixes;
final loadLibraryInvocations = <MethodInvocation>[];
_FindLoadLibraryCalls(List<ImportDirective> deferredImports)
: _deferredPrefixes =
new Set.from(deferredImports.map((import) => import.prefix.name));
@override
Object visitMethodInvocation(MethodInvocation node) {
if (node.methodName.name == 'loadLibrary') {
var prefix = (node.realTarget as SimpleIdentifier).name;
if (_deferredPrefixes.contains(prefix)) {
loadLibraryInvocations.add(node);
}
}
// Important! Children could include more `loadLibrary` calls.
return super.visitMethodInvocation(node);
}
}

View File

@ -1,94 +0,0 @@
library angular2.transform.deferred_rewriter.transformer;
import 'dart:async';
import 'package:barback/barback.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/zone.dart' as zone;
import 'rewriter.dart';
/// Transformer which rewrites deferred imports and `loadLibrary` calls.
///
/// Deferred imports with associated initialization code are rewritten to
/// point to their associated generated code file.
/// `loadLibrary` calls for libraries with associated initialization methods
/// are rewritten to initialize after the library is loaded and before use.
class DeferredRewriter extends AggregateTransformer implements LazyTransformer {
DeferredRewriter();
/// Ctor which tells pub that this can be run as a standalone transformer.
DeferredRewriter.asPlugin(BarbackSettings _);
@override
declareOutputs(DeclaringTransform transform) {
transform.declareOutput(transform.primaryId);
}
@override
dynamic classifyPrimary(AssetId id) {
// Map <name>.dart and <name>.dart.deferredCount => <name>.
// Anything else to `null`.
var extension = null;
if (id.path.endsWith(DEFERRED_EXTENSION)) {
extension = DEFERRED_EXTENSION;
} else if (id.path.endsWith('.dart') && !isGenerated(id.path)) {
extension = '.dart';
} else {
return null;
}
return id.path.substring(0, id.path.length - extension.length);
}
@override
Future apply(AggregateTransform transform) async {
final dartAsset = await _assetToProcess(transform);
if (dartAsset == null) return null;
return applyImpl(transform, dartAsset.id);
}
/// Transforms the asset with id [id].
///
/// [transform] must be an [AggregateTransform] or [Transform].
Future applyImpl(dynamic transform, AssetId id) {
assert(transform is AggregateTransform || transform is Transform);
return zone.exec(() async {
var transformedCode = await rewriteDeferredLibraries(
new AssetReader.fromTransform(transform), id);
if (transformedCode != null) {
transform.addOutput(new Asset.fromString(id, transformedCode));
}
}, log: transform.logger);
}
}
/// Returns the asset we need to process or `null` if none exists.
///
/// Consumes the .dart.deferredCount asset if it is present.
Future<Asset> _assetToProcess(AggregateTransform transform) async {
// We only need to process .dart files that have an associated
// .dart.deferredCount file with a value != "0".
//
// The .dart.deferredCount file is generated by a previous phase for files
// which have deferred imports. An absent .dart.deferredCount asset is the
// treated the same as a .dart.deferredCount asset with value "0".
var dartAsset, deferredCountAsset;
await for (Asset a in transform.primaryInputs) {
if (a.id.path.endsWith(DEFERRED_EXTENSION)) {
deferredCountAsset = a;
} else if (a.id.path.endsWith('.dart')) {
dartAsset = a;
}
}
if (deferredCountAsset == null) return null;
// No longer necessary.
transform.consumePrimary(deferredCountAsset.id);
if ((await deferredCountAsset.readAsString()) == "0") return null;
return dartAsset;
}
Future<String> rewriteDeferredLibraries(AssetReader reader, AssetId id) =>
rewriteLibrary(id, reader);

View File

@ -1,83 +0,0 @@
library angular2.transform.directive_metadata_linker.ng_deps_linker;
import 'dart:async';
import 'package:angular2/compiler.dart' show UrlResolver;
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/model/import_export_model.pb.dart';
import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart';
import 'package:angular2/src/transform/common/url_resolver.dart';
import 'package:barback/barback.dart';
/// Modifies the [NgDepsModel] represented by `entryPoint` to import its
/// dependencies' associated, generated files.
///
/// For example, if entry_point.dart imports dependency.dart, this will check if
/// dependency.ng_meta.json exists. If it does, we add an entry to the
/// `depImports` of [NgDepsModel] for dependency.ngfactory.dart.
///
/// We use this information later to ensure that each file's dependencies are
/// initialized when that file is initialized.
Future<NgDepsModel> linkNgDeps(NgDepsModel ngDepsModel, AssetReader reader,
AssetId assetId, UrlResolver resolver) async {
if (ngDepsModel == null) return null;
return logElapsedAsync(() async {
var linkedDepsMap =
await _processNgImports(ngDepsModel, reader, assetId, resolver);
if (linkedDepsMap.isEmpty) {
// We are not calling `initReflector` on any other libraries, but we still
// return the model to ensure it is written to code.
return ngDepsModel;
}
final seen = new Set<String>();
var idx = 0;
final allDeps = [ngDepsModel.imports, ngDepsModel.exports].expand((e) => e);
for (var dep in allDeps) {
if (linkedDepsMap.containsKey(dep.uri) && !seen.contains(dep.uri)) {
seen.add(dep.uri);
var linkedModel = new ImportModel()
..uri = toTemplateExtension(dep.uri)
..prefix = 'i${idx++}';
// TODO(kegluneq): Preserve combinators?
ngDepsModel.depImports.add(linkedModel);
}
}
return ngDepsModel;
}, operationName: 'linkNgDeps', assetId: assetId);
}
bool _isNotDartDirective(dynamic model) => !isDartCoreUri(model.uri);
/// Maps the `uri` of each input [ImportModel] or [ExportModel] to its
/// associated `.ng_deps.json` file, if one exists.
Future<Map<String, String>> _processNgImports(NgDepsModel model,
AssetReader reader, AssetId assetId, UrlResolver resolver) async {
final importsAndExports =
new List.from(model.imports.where((i) => !i.isDeferred))
..addAll(model.exports);
final retVal = <String, String>{};
final assetUri = toAssetUri(assetId);
return Future
.wait(
importsAndExports.where(_isNotDartDirective).map((dynamic directive) {
// Check whether the import or export generated summary NgMeta information.
final summaryJsonUri =
resolver.resolve(assetUri, toSummaryExtension(directive.uri));
return reader.hasInput(fromUri(summaryJsonUri)).then((hasInput) {
if (hasInput) {
retVal[directive.uri] = summaryJsonUri;
}
}, onError: (err, stack) {
log.warning(
'Error while looking for $summaryJsonUri. '
'Message: $err\n'
'Stack: $stack',
asset: assetId);
});
}))
.then((_) => retVal);
}

View File

@ -1,460 +0,0 @@
library angular2.transform.directive_metadata_linker.linker;
import 'dart:async';
import 'dart:convert';
import 'package:angular2/src/compiler/compile_metadata.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/ng_meta.dart';
import 'package:angular2/src/transform/common/url_resolver.dart';
import 'package:barback/barback.dart';
import 'ng_deps_linker.dart';
/// Returns [NgMeta] associated with the provided asset combined with the [NgMeta] of
/// all files `export`ed from the original file.
///
/// The returned NgMeta has all the identifiers resolved.
///
/// `summaryAssetId` - the unlinked asset id (source)
/// `summaryAssetId` - the linked asset id (dest)
/// `resolvedIdentifiers` - preresolved identifiers (e.g., Window)
/// `ngMetas` - in memory cache of linked ngMeta files
Future<NgMeta> linkDirectiveMetadata(AssetReader reader, AssetId summaryAssetId,
AssetId metaAssetId, Map<String, String> resolvedIdentifiers,
[bool errorOnMissingIdentifiers = true, Map<AssetId, NgMeta> ngMetas]) async {
if (ngMetas == null) ngMetas = {};
var ngMeta = await _readNgMeta(reader, summaryAssetId, ngMetas);
if (ngMeta == null || ngMeta.isEmpty) return null;
await Future.wait([
linkNgDeps(ngMeta.ngDeps, reader, summaryAssetId, _urlResolver),
logElapsedAsync(() async {
final linker = new _Linker(reader, ngMetas, resolvedIdentifiers, errorOnMissingIdentifiers);
await linker.linkRecursive(ngMeta, metaAssetId, new Set<AssetId>());
return ngMeta;
}, operationName: 'linkDirectiveMetadata', assetId: summaryAssetId)
]);
return ngMeta;
}
final _urlResolver = createOfflineCompileUrlResolver();
Future<NgMeta> _readNgMeta(AssetReader reader, AssetId ngMetaAssetId,
Map<AssetId, NgMeta> ngMetas) async {
if (ngMetas.containsKey(ngMetaAssetId)) return ngMetas[ngMetaAssetId];
if (!(await reader.hasInput(ngMetaAssetId))) return null;
var ngMetaJson = await reader.readAsString(ngMetaAssetId);
if (ngMetaJson == null || ngMetaJson.isEmpty) return null;
return new NgMeta.fromJson(JSON.decode(ngMetaJson));
}
class _Linker {
final AssetReader reader;
final Map<AssetId, NgMeta> ngMetas;
final Map<String, String> resolvedIdentifiers;
final bool errorOnMissingIdentifiers;
_Linker(this.reader, this.ngMetas, this.resolvedIdentifiers, this.errorOnMissingIdentifiers);
Future<NgMeta> linkRecursive(NgMeta ngMeta, AssetId assetId, Set<AssetId> seen) async {
if (seen.contains(assetId)) return ngMeta;
final newSeen = new Set.from(seen)
..add(assetId);
await _resolveDeps(ngMeta, assetId, newSeen);
await _resolveIdentifiers(ngMeta, assetId);
await _mergeExports(ngMeta, assetId);
ngMetas[assetId] = ngMeta;
return ngMeta;
}
Future _resolveDeps(NgMeta ngMeta, AssetId assetId, Set<AssetId> seen) async {
final importsAndExports = [];
if (ngMeta != null &&
ngMeta.ngDeps != null &&
ngMeta.ngDeps.exports != null)
importsAndExports.addAll(ngMeta.ngDeps.exports);
if (ngMeta != null &&
ngMeta.needsResolution &&
ngMeta.ngDeps != null &&
ngMeta.ngDeps.imports != null)
importsAndExports
.addAll(ngMeta.ngDeps.imports.where((i) => !i.isDeferred));
final assetUri = toAssetUri(assetId);
for (var withUri in importsAndExports) {
if (isDartCoreUri(withUri.uri)) continue;
final metaAsset =
fromUri(_urlResolver.resolve(assetUri, toMetaExtension(withUri.uri)));
final summaryAsset = fromUri(
_urlResolver.resolve(assetUri, toSummaryExtension(withUri.uri)));
if (!await _hasMeta(metaAsset)) {
final ngMeta = await _readSummary(summaryAsset);
if (ngMeta != null) {
await linkRecursive(ngMeta, metaAsset, seen);
}
}
}
}
Future _resolveIdentifiers(NgMeta ngMeta, AssetId assetId) async {
if (ngMeta.needsResolution) {
final resolver = new _NgMetaIdentifierResolver(
assetId, reader, ngMetas, resolvedIdentifiers, errorOnMissingIdentifiers);
return resolver.resolveNgMeta(ngMeta);
} else {
return null;
}
}
Future _mergeExports(NgMeta ngMeta, AssetId assetId) async {
if (ngMeta == null ||
ngMeta.ngDeps == null ||
ngMeta.ngDeps.exports == null) {
return ngMeta;
}
var assetUri = toAssetUri(assetId);
return Future.wait(ngMeta.ngDeps.exports.map((r) => r.uri)
.where((export) => !isDartCoreUri(export))
.map((export) =>
_urlResolver.resolve(assetUri, toMetaExtension(export)))
.map((uri) async {
try {
final exportAssetId = fromUri(uri);
final exportNgMeta = await _readMeta(exportAssetId);
if (exportNgMeta != null) {
ngMeta.addAll(exportNgMeta);
}
} catch (err, st) {
// Log and continue.
log.warning('Failed to fetch $uri. Message: $err.\n$st',
asset: assetId);
}
}));
}
Future<NgMeta> _readSummary(AssetId summaryAssetId) async {
if (!(await reader.hasInput(summaryAssetId))) return null;
var ngMetaJson = await reader.readAsString(summaryAssetId);
if (ngMetaJson == null || ngMetaJson.isEmpty) return null;
return new NgMeta.fromJson(JSON.decode(ngMetaJson));
}
Future<NgMeta> _readMeta(AssetId metaAssetId) async {
final content = await _readNgMeta(reader, metaAssetId, ngMetas);
if (content != null) {
ngMetas[metaAssetId] = content;
}
return content;
}
Future<bool> _hasMeta(AssetId ngMetaAssetId) async {
return ngMetas.containsKey(ngMetaAssetId) ||
await reader.hasInput(ngMetaAssetId);
}
}
class _NgMetaIdentifierResolver {
final Map<String, String> resolvedIdentifiers;
final Map<AssetId, NgMeta> ngMetas;
final AssetReader reader;
final AssetId entryPoint;
final bool errorOnMissingIdentifiers;
_NgMetaIdentifierResolver(this.entryPoint, this.reader, this.ngMetas, this.resolvedIdentifiers, this.errorOnMissingIdentifiers);
Future resolveNgMeta(NgMeta ngMeta) async {
final ngMetaMap = await _extractNgMetaMap(ngMeta);
ngMeta.identifiers.forEach((_, meta) {
if (meta is CompileIdentifierMetadata && meta.value != null) {
meta.value = _resolveProviders(ngMetaMap, meta.value, "root");
}
});
ngMeta.identifiers.forEach((_, meta) {
if (meta is CompileDirectiveMetadata) {
_resolveProviderMetadata(ngMetaMap, meta);
_resolveQueryMetadata(ngMetaMap, meta);
_resolveDiDependencyMetadata(ngMetaMap, meta.type.name, meta.type.diDeps);
} else if (meta is CompileTypeMetadata) {
_resolveDiDependencyMetadata(ngMetaMap, meta.name, meta.diDeps);
} else if (meta is CompileFactoryMetadata) {
_resolveDiDependencyMetadata(ngMetaMap, meta.name, meta.diDeps);
}
});
}
List<CompileProviderMetadata> _resolveProviders(Map<String, NgMeta> ngMetaMap, Object value, String neededBy) {
if (value is List) {
final res = [];
for (var v in value) {
res.addAll(_resolveProviders(ngMetaMap, v, neededBy));
}
return res;
} else if (value is CompileProviderMetadata) {
_resolveProvider(ngMetaMap, neededBy, value);
return [value];
} else if (value is CompileIdentifierMetadata) {
final resolved = _resolveIdentifier(ngMetaMap, neededBy, value);
if (resolved == null) return [];
if (resolved is CompileTypeMetadata) {
return [new CompileProviderMetadata(token: new CompileTokenMetadata(identifier: resolved), useClass: resolved)];
} else if (resolved is CompileIdentifierMetadata && resolved.value is List) {
return _resolveProviders(ngMetaMap, resolved.value, neededBy);
} else if (resolved is CompileIdentifierMetadata && resolved.value is CompileProviderMetadata) {
return [_resolveProviders(ngMetaMap, resolved.value, neededBy)];
} else {
return [];
}
} else {
return [];
}
}
void _resolveProviderMetadata(Map<String, NgMeta> ngMetaMap, CompileDirectiveMetadata dirMeta) {
final neededBy = dirMeta.type.name;
if (dirMeta.providers != null) {
dirMeta.providers =
_resolveProviders(ngMetaMap, dirMeta.providers, neededBy);
}
if (dirMeta.viewProviders != null) {
dirMeta.viewProviders =
_resolveProviders(ngMetaMap, dirMeta.viewProviders, neededBy);
}
}
void _resolveQueryMetadata(Map<String, NgMeta> ngMetaMap, CompileDirectiveMetadata dirMeta) {
final neededBy = dirMeta.type.name;
if (dirMeta.queries != null) {
_resolveQueries(ngMetaMap, dirMeta.queries, neededBy);
}
if (dirMeta.viewQueries != null) {
_resolveQueries(ngMetaMap, dirMeta.viewQueries, neededBy);
}
}
void _resolveQueries(Map<String, NgMeta> ngMetaMap, List queries, String neededBy) {
queries.forEach((q) {
q.selectors.forEach((s) => s.identifier = _resolveIdentifier(ngMetaMap, neededBy, s.identifier));
if (q.read != null) {
q.read.identifier = _resolveIdentifier(ngMetaMap, neededBy, q.read.identifier);
}
});
}
void _resolveProvider(Map<String, NgMeta> ngMetaMap,
String neededBy, CompileProviderMetadata provider) {
provider.token.identifier = _resolveIdentifier(ngMetaMap, neededBy, provider.token.identifier);
if (provider.useClass != null) {
provider.useClass =
_resolveIdentifier(ngMetaMap, neededBy, provider.useClass);
}
if (provider.useExisting != null) {
provider.useExisting.identifier =
_resolveIdentifier(ngMetaMap, neededBy, provider.useExisting.identifier);
}
if (provider.useValue != null) {
provider.useValue =
_resolveIdentifier(ngMetaMap, neededBy, provider.useValue);
}
if (provider.useFactory != null) {
provider.useFactory = _resolveIdentifier(ngMetaMap, neededBy, provider.useFactory);
}
if (provider.deps != null) {
_resolveDiDependencyMetadata(ngMetaMap, neededBy, provider.deps);
};;
}
void _resolveDiDependencyMetadata(Map<String, NgMeta> ngMetaMap,
String neededBy, List<CompileDiDependencyMetadata> deps) {
if (deps == null) return;
for (var dep in deps) {
if (dep.token != null) {
_setModuleUrl(ngMetaMap, neededBy, dep.token.identifier);
}
if (dep.query != null) {
dep.query.selectors
.forEach((s) => _setModuleUrl(ngMetaMap, neededBy, s.identifier));
}
if (dep.viewQuery != null) {
dep.viewQuery.selectors
.forEach((s) => _setModuleUrl(ngMetaMap, neededBy, s.identifier));
}
}
}
void _setModuleUrl(Map<String, NgMeta> ngMetaMap, String neededBy, dynamic id) {
final resolved = _resolveIdentifier(ngMetaMap, neededBy, id);
if (resolved != null && id is CompileIdentifierMetadata) {
id.moduleUrl = resolved.moduleUrl;
}
}
/// Resolves an identifier using the provided ngMetaMap.
///
/// ngMetaMap - a map of prefixes to the symbols available via those prefixes
/// neededBy - a type using the unresolved symbol. It's used to generate
/// good error message.
/// id - an unresolved id.
dynamic _resolveIdentifier(Map<String, NgMeta> ngMetaMap, String neededBy, dynamic id) {
if (id is String || id is bool || id is num || id == null) return id;
if (id is CompileMetadataWithIdentifier) {
id = id.identifier;
}
if (id.moduleUrl != null) return id;
final prefix = id.prefix == null ? "" : id.prefix;
if (!ngMetaMap.containsKey(prefix)) {
final resolved = _resolveSpecialCases(id);
if (resolved != null) {
return resolved;
} else {
final message = 'Missing prefix "${prefix}" '
'needed by "${neededBy}" from metadata map';
if (errorOnMissingIdentifiers) {
log.error(message, asset: entryPoint);
} else {
log.warning(message, asset: entryPoint);
}
return null;
}
}
final depNgMeta = ngMetaMap[prefix];
if (depNgMeta.identifiers.containsKey(id.name)) {
final res = depNgMeta.identifiers[id.name];
if (res is CompileMetadataWithIdentifier) {
return res.identifier;
} else {
return res;
}
} else if (_isPrimitive(id.name)) {
return id;
} else {
final resolved = _resolveSpecialCases(id);
if (resolved != null) {
return resolved;
} else {
final message = 'Missing identifier "${id.name}" '
'needed by "${neededBy}" from metadata map';
if (errorOnMissingIdentifiers) {
log.error(message, asset: entryPoint);
} else {
log.warning(message, asset: entryPoint);
}
return null;
}
}
}
dynamic _resolveSpecialCases(CompileIdentifierMetadata id) {
if (resolvedIdentifiers != null &&
resolvedIdentifiers.containsKey(id.name)) {
return new CompileIdentifierMetadata(
name: id.name, moduleUrl: resolvedIdentifiers[id.name]);
// these are so common that we special case them in the transformer
} else if (id.name == "Window" || id.name == "Document") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'dart:html');
} else if (id.name == "Profiler") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:perf_api/lib/perf_api.dart');
} else if (id.name == "Logger") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:logging/lib/logging.dart');
} else if (id.name == "Clock") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:quiver/lib/src/time/clock.dart');
} else if (id.name == "Log") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:angular2/lib/src/testing/utils.dart');
} else if (id.name == "TestComponentBuilder") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:angular2/lib/src/testing/test_component_builder.dart');
} else if (id.name == "Stream") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'dart:async');
} else if (id.name == "StreamController") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'dart:async');
} else if (id.name == "FakeAsync") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:angular2/lib/src/testing/fake_async.dart');
} else if (id.name == "StreamTracer") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:streamy/lib/src/core/tracing.dart');
} else if (id.name == "Tracer") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:streamy/lib/src/core/tracing.dart');
} else if (id.name == "RequestHandler") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:streamy/lib/src/core/request_handler.dart');
} else if (id.name == "BatchingStrategy") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:streamy/lib/src/extra/request_handler/batching.dart');
} else if (id.name == "ProxyClient") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:streamy/lib/src/extra/request_handler/proxy.dart');
} else if (id.name == "StreamyHttpService") {
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:streamy/lib/src/toolbox/http.dart');
} else {
return null;
}
}
bool _isPrimitive(String typeName) =>
typeName == "String" ||
typeName == "Object" ||
typeName == "num" ||
typeName == "int" ||
typeName == "double" ||
typeName == "bool" ||
typeName == "dynamic";
/// Walks all the imports and creates a map from prefixes to
/// all the symbols available through those prefixes
Future<Map<String, NgMeta>> _extractNgMetaMap(NgMeta ngMeta) async {
final res = {"": new NgMeta.empty()};
res[""].addAll(ngMeta);
if (ngMeta.ngDeps == null || ngMeta.ngDeps.imports == null) return res;
for (var import in ngMeta.ngDeps.imports) {
if (isDartCoreUri(import.uri)) continue;
final assetUri = toAssetUri(entryPoint);
final metaAsset =
fromUri(_urlResolver.resolve(assetUri, toMetaExtension(import.uri)));
final newMeta = await _readNgMeta(reader, metaAsset, ngMetas);
if (!res.containsKey(import.prefix)) {
res[import.prefix] = new NgMeta.empty();
}
if (newMeta != null) {
res[import.prefix].addAll(newMeta);
} else {
final summaryAsset =
fromUri(_urlResolver.resolve(assetUri, toSummaryExtension(import.uri)));
final summary = await _readNgMeta(reader, summaryAsset, {});
if (summary != null) {
res[import.prefix].addAll(summary);
}
}
}
return res;
}
}

View File

@ -1,78 +0,0 @@
library angular2.transform.directive_metadata_linker.transformer;
import 'dart:async';
import 'dart:convert';
import 'package:barback/barback.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/zone.dart' as zone;
import 'package:angular2/src/transform/common/options.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'ng_meta_linker.dart';
/// Transformer responsible for processing .ng_summary.json files created by
/// {@link DirectiveProcessor} and "linking" them.
///
/// This step ensures that for libraries that export, all `Directive`s reachable
/// from that library are declared in its associated .ng_meta.json file.
///
/// Said another way, after this step there should be an entry in this `NgMeta`
/// object for all `Directives` visible from its associated `.dart` file.
///
/// This step also ensures that, if `a.dart` imports `b.dart`, `a.ngfactory.dart`
/// imports `b.ngfactory.dart` (if it exists) and we note that this is a
/// ngDeps dependency, ensuring that a's `initReflector` function calls b's
/// `initReflector' function.
///
/// See `common/ng_meta.dart` for the JSON format of these files are serialized
/// to.
///
/// This transformer is part of a multi-phase transform.
/// See `angular2/src/transform/transformer.dart` for transformer ordering.
class DirectiveMetadataLinker extends Transformer implements LazyTransformer {
final _encoder = const JsonEncoder.withIndent(' ');
final TransformerOptions options;
final Map ngMetasCache = {};
final Set<String> errorMessages = new Set<String>();
DirectiveMetadataLinker(this.options);
@override
bool isPrimary(AssetId id) => id.path.endsWith(SUMMARY_META_EXTENSION);
@override
declareOutputs(DeclaringTransform transform) {
transform.declareOutput(_ngLinkedAssetId(transform.primaryId));
}
@override
Future apply(Transform transform) {
return zone.exec(() {
var primaryId = transform.primaryInput.id;
return linkDirectiveMetadata(
new AssetReader.fromTransform(transform),
primaryId,
_ngLinkedAssetId(primaryId),
options.resolvedIdentifiers,
options.errorOnMissingIdentifiers,
ngMetasCache).then((ngMeta) {
if (ngMeta != null) {
final outputId = _ngLinkedAssetId(primaryId);
// Not outputting an asset could confuse barback.
var output = ngMeta.isEmpty ? '' : _encoder.convert(ngMeta.toJson());
transform.addOutput(new Asset.fromString(outputId, output));
}
});
}, log: new DeduppingLogger(transform.logger, errorMessages));
}
}
AssetId _ngLinkedAssetId(AssetId primaryInputId) {
return new AssetId(
primaryInputId.package, toMetaExtension(primaryInputId.path));
}

View File

@ -1,109 +0,0 @@
library angular2.transform.directive_processor.inliner;
import 'dart:async';
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:barback/barback.dart' show AssetId;
import 'package:source_span/source_span.dart';
import 'package:path/path.dart' as path;
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/async_string_writer.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/url_resolver.dart';
/// Reads the code at `assetId`, inlining any `part` directives in that code.
///
/// Returns `null` if the code represented by `assetId` is a `part`.
///
/// Order of `part`s is preserved. That is, if in the main library we have
/// ```
/// library main;
///
/// part 'lib1.dart'
/// part 'lib2.dart'
/// ```
/// The output will first have the contents of lib1 followed by the contents of
/// lib2.dart, followed by the original code in the library.
Future<String> inlineParts(AssetReader reader, AssetId assetId) async {
var code = await reader.readAsString(assetId);
var directivesVisitor = new _NgDepsDirectivesVisitor();
parseDirectives(code, name: assetId.path)
.directives
.accept(directivesVisitor);
// If this is part of another library, its contents will be processed by its
// parent, so it does not need its own generated file.
if (directivesVisitor.isPart) return null;
return logElapsedAsync(() {
return _getAllDeclarations(reader, assetId, code, directivesVisitor);
}, operationName: 'inlineParts', assetId: assetId);
}
/// Processes `visitor.parts`, reading and appending their contents to the
/// original `code`.
Future<String> _getAllDeclarations(AssetReader reader, AssetId assetId,
String code, _NgDepsDirectivesVisitor visitor) {
if (visitor.parts.isEmpty) return new Future<String>.value(code);
var partsStart = visitor.parts.first.offset,
partsEnd = visitor.parts.last.end;
final assetUri = toAssetUri(assetId);
var asyncWriter = new AsyncStringWriter(code.substring(0, partsStart));
visitor.parts.forEach((partDirective) {
var uri = stringLiteralToString(partDirective.uri);
var partAssetId =
fromUri(createOfflineCompileUrlResolver().resolve(assetUri, uri));
asyncWriter.asyncPrint(reader.readAsString(partAssetId).then((partCode) {
if (partCode == null || partCode.isEmpty) {
log.warning('Empty part at "${partDirective.uri}. Ignoring.',
asset: partAssetId);
return '';
}
// Remove any directives -- we just want declarations.
var parsedDirectives = parseDirectives(partCode, name: uri).directives;
return partCode.substring(parsedDirectives.last.end);
}).catchError((err, stackTrace) {
log.warning(
'Failed while reading part at ${partDirective.uri}. Ignoring.\n'
'Error: $err\n'
'Stack Trace: $stackTrace',
asset: partAssetId,
span: new SourceFile(code, url: path.basename(assetId.path))
.span(partDirective.offset, partDirective.end));
}));
});
asyncWriter.print(code.substring(partsEnd));
return asyncWriter.asyncToString();
}
/// Visitor responsible for reading the `part` files of the visited AST and
/// determining if it is a part of another library.
class _NgDepsDirectivesVisitor extends Object with SimpleAstVisitor<Object> {
/// Whether the file we are processing is a part, that is, whether we have
/// visited a `part of` directive.
bool _isPart = false;
final List<PartDirective> _parts = <PartDirective>[];
bool get isPart => _isPart;
/// In the order encountered in the source.
Iterable<PartDirective> get parts => _parts;
@override
Object visitPartDirective(PartDirective node) {
_parts.add(node);
return null;
}
@override
Object visitPartOfDirective(PartOfDirective node) {
_isPart = true;
return null;
}
}

View File

@ -1,170 +0,0 @@
library angular2.transform.directive_processor.rewriter;
import 'dart:async';
import 'package:analyzer/analyzer.dart';
import 'package:barback/barback.dart' show AssetId;
import 'package:angular2/src/compiler/compile_metadata.dart'
show CompileIdentifierMetadata, CompileProviderMetadata;
import 'package:angular2/src/compiler/offline_compiler.dart';
import 'package:angular2/src/transform/common/annotation_matcher.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/code/ng_deps_code.dart';
import 'package:angular2/src/transform/common/type_metadata_reader.dart';
import 'package:angular2/src/transform/common/interface_matcher.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/ng_compiler.dart';
import 'package:angular2/src/transform/common/ng_meta.dart';
import 'package:angular2/src/transform/common/url_resolver.dart';
import 'package:angular2/src/transform/common/zone.dart' as zone;
import 'inliner.dart';
/// Generates an instance of [NgMeta] describing the file at `assetId`.
Future<NgMeta> createNgMeta(AssetReader reader, AssetId assetId,
AnnotationMatcher annotationMatcher) async {
// TODO(kegluneq): Shortcut if we can determine that there are no
// [Directive]s present, taking into account `export`s.
var codeWithParts = await inlineParts(reader, assetId);
if (codeWithParts == null || codeWithParts.isEmpty) return null;
var parsedCode =
parseCompilationUnit(codeWithParts, name: '${assetId.path} and parts');
final ngDepsVisitor = await logElapsedAsync(() async {
var ngDepsVisitor = new NgDepsVisitor(assetId, annotationMatcher);
parsedCode.accept(ngDepsVisitor);
return ngDepsVisitor;
}, operationName: 'createNgDeps', assetId: assetId);
return logElapsedAsync(() async {
var ngMeta = new NgMeta(ngDeps: ngDepsVisitor.model);
var templateCompiler = zone.templateCompiler;
if (templateCompiler == null) {
templateCompiler = createTemplateCompiler(reader);
}
var ngMetaVisitor = new _NgMetaVisitor(ngMeta, assetId, annotationMatcher,
_interfaceMatcher, templateCompiler);
parsedCode.accept(ngMetaVisitor);
await ngMetaVisitor.whenDone();
return ngMeta;
}, operationName: 'createNgMeta', assetId: assetId);
}
// TODO(kegluneq): Allow the caller to provide an InterfaceMatcher.
final _interfaceMatcher = new InterfaceMatcher();
/// Visitor responsible for visiting a file and outputting the
/// code necessary to register the file with the Angular 2 system.
class _NgMetaVisitor extends Object with SimpleAstVisitor<Object> {
/// Output ngMeta information about aliases.
// TODO(sigmund): add more to ngMeta. Currently this only contains aliasing
// information, but we could produce here all the metadata we need and avoid
// parsing the ngdeps files later.
final NgMeta ngMeta;
/// The [AssetId] we are currently processing.
final AssetId assetId;
final TypeMetadataReader _reader;
final _normalizations = <Future>[];
_NgMetaVisitor(this.ngMeta, this.assetId, AnnotationMatcher annotationMatcher,
InterfaceMatcher interfaceMatcher, OfflineCompiler templateCompiler)
: _reader = new TypeMetadataReader(
annotationMatcher, interfaceMatcher, templateCompiler);
Future whenDone() {
return Future.wait(_normalizations);
}
@override
Object visitCompilationUnit(CompilationUnit node) {
if (node == null ||
(node.directives == null && node.declarations == null)) {
return null;
}
node.directives.accept(this);
return node.declarations.accept(this);
}
@override
Object visitClassDeclaration(ClassDeclaration node) {
_normalizations.add(_reader
.readTypeMetadata(node, assetId)
.then((compileMetadataWithIdentifier) {
if (compileMetadataWithIdentifier != null) {
ngMeta.identifiers[compileMetadataWithIdentifier.identifier.name] =
compileMetadataWithIdentifier;
} else {
ngMeta.identifiers[node.name.name] = new CompileIdentifierMetadata(
name: node.name.name, moduleUrl: toAssetUri(assetId));
}
}).catchError((err) {
log.error('ERROR: $err', asset: assetId);
}));
return null;
}
@override
Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
// We process any top-level declaration that fits the directive-alias
// declaration pattern. Ideally we would use an annotation on the field to
// help us filter out only what's needed, but unfortunately TypeScript
// doesn't support decorators on variable declarations (see
// angular/angular#1747 and angular/ts2dart#249 for context).
outer: for (var variable in node.variables.variables) {
if (variable.isConst) {
final id = _reader.readIdentifierMetadata(variable, assetId);
ngMeta.identifiers[variable.name.name] = id;
}
var initializer = variable.initializer;
if (initializer != null && initializer is ListLiteral) {
var otherNames = [];
for (var exp in initializer.elements) {
// Only simple identifiers are supported for now.
// TODO(sigmund): add support for prefixes (see issue #3232).
if (exp is! SimpleIdentifier) continue outer;
otherNames.add(exp.name);
}
ngMeta.aliases[variable.name.name] = otherNames;
}
}
return null;
}
@override
Object visitFunctionTypeAlias(FunctionTypeAlias node) {
ngMeta.identifiers[node.name.name] = new CompileIdentifierMetadata(
name: node.name.name, moduleUrl: toAssetUri(assetId));
return null;
}
@override
Object visitFunctionDeclaration(FunctionDeclaration node) {
_normalizations.add(_reader
.readFactoryMetadata(node, assetId)
.then((compileMetadataWithIdentifier) {
if (compileMetadataWithIdentifier != null) {
ngMeta.identifiers[compileMetadataWithIdentifier.identifier.name] =
compileMetadataWithIdentifier;
} else {
ngMeta.identifiers[node.name.name] = new CompileIdentifierMetadata(
name: node.name.name, moduleUrl: toAssetUri(assetId));
}
}).catchError((err) {
log.error('ERROR: $err', asset: assetId);
}));
return null;
}
@override
Object visitEnumDeclaration(EnumDeclaration node) {
ngMeta.identifiers[node.name.name] = new CompileIdentifierMetadata(
name: node.name.name, moduleUrl: toAssetUri(assetId));
return null;
}
}

View File

@ -1,76 +0,0 @@
library angular2.transform.directive_processor.transformer;
import 'dart:async';
import 'dart:convert';
import 'package:barback/barback.dart';
import 'package:angular2/src/platform/server/html_adapter.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/options.dart';
import 'package:angular2/src/transform/common/zone.dart' as zone;
import 'rewriter.dart';
/// Transformer responsible for processing all .dart assets and creating
/// .ng_summary.json files which summarize those assets.
///
/// See `angular2/src/transform/common/ng_meta.dart` for the structure of these
/// output files.
///
/// This transformer is part of a multi-phase transform.
/// See `angular2/src/transform/transformer.dart` for transformer ordering.
class DirectiveProcessor extends Transformer implements LazyTransformer {
final TransformerOptions options;
final _encoder = const JsonEncoder.withIndent(' ');
DirectiveProcessor(this.options);
@override
bool isPrimary(AssetId id) =>
id.extension.endsWith('dart') && !isGenerated(id.path);
@override
declareOutputs(DeclaringTransform transform) {
transform.declareOutput(_deferredAssetId(transform.primaryId));
transform.declareOutput(_ngSummaryAssetId(transform.primaryId));
}
@override
Future apply(Transform transform) async {
Html5LibDomAdapter.makeCurrent();
return zone.exec(() async {
var primaryId = transform.primaryInput.id;
var reader = new AssetReader.fromTransform(transform);
var ngMeta =
await createNgMeta(reader, primaryId, options.annotationMatcher);
if (ngMeta == null || ngMeta.isEmpty) {
return;
}
transform.addOutput(new Asset.fromString(
_ngSummaryAssetId(primaryId), _encoder.convert(ngMeta.toJson())));
var deferredCount = 0;
if (ngMeta.ngDeps != null) {
deferredCount = ngMeta.ngDeps.imports.where((i) => i.isDeferred).length;
}
if (deferredCount > 0) {
// The existence of this file with the value != "0" signals
// DeferredRewriter that the associated .dart file needs attention.
transform.addOutput(new Asset.fromString(
_deferredAssetId(primaryId), deferredCount.toString()));
}
}, log: transform.logger);
}
}
AssetId _ngSummaryAssetId(AssetId primaryInputId) {
return new AssetId(
primaryInputId.package, toSummaryExtension(primaryInputId.path));
}
AssetId _deferredAssetId(AssetId primaryInputId) {
return new AssetId(
primaryInputId.package, toDeferredExtension(primaryInputId.path));
}

View File

@ -1,241 +0,0 @@
library angular2.src.transform.inliner_for_test.transformer;
import 'dart:async';
import 'dart:convert' show LineSplitter;
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:barback/barback.dart';
import 'package:dart_style/dart_style.dart';
import 'package:angular2/src/compiler/xhr.dart' show XHR;
import 'package:angular2/src/transform/common/annotation_matcher.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/naive_eval.dart';
import 'package:angular2/src/transform/common/async_string_writer.dart';
import 'package:angular2/src/transform/common/options.dart';
import 'package:angular2/src/transform/common/url_resolver.dart';
import 'package:angular2/src/transform/common/xhr_impl.dart';
import 'package:angular2/src/transform/common/zone.dart' as zone;
import 'package:angular2/src/transform/directive_processor/inliner.dart';
/// Processes .dart files and inlines `templateUrl` and styleUrls` values.
class InlinerForTest extends Transformer {
final DartFormatter _formatter;
final AnnotationMatcher _annotationMatcher;
InlinerForTest(TransformerOptions options)
: _formatter = options.formatCode ? new DartFormatter() : null,
_annotationMatcher = options.annotationMatcher;
@override
bool isPrimary(AssetId id) => id.extension.endsWith('dart');
@override
Future apply(Transform transform) async {
return zone.exec(() async {
var primaryId = transform.primaryInput.id;
var inlinedCode = await inline(new AssetReader.fromTransform(transform),
primaryId, _annotationMatcher);
if (inlinedCode == null || inlinedCode.isEmpty) {
transform.addOutput(transform.primaryInput);
} else {
if (_formatter != null) {
inlinedCode = _formatter.format(inlinedCode);
}
transform.addOutput(new Asset.fromString(primaryId, inlinedCode));
}
}, log: transform.logger);
}
}
/// Reads the code at `assetId`, inlining values where possible.
///
/// Returns the code at `assetId` with the following modifications:
/// - `part` Directives are inlined
/// - `templateUrl` values are inlined as `template` values.
/// - `styleUrls` values are inlined as `styles` values.
///
/// If this does not inline any `templateUrl` or `styleUrls` values, it will
/// return `null` to signal that no modifications to the input code were
/// necessary.
Future<String> inline(AssetReader reader, AssetId assetId,
AnnotationMatcher annotationMatcher) async {
var codeWithParts = await inlineParts(reader, assetId);
if (codeWithParts == null) return null;
var parsedCode =
parseCompilationUnit(codeWithParts, name: '${assetId.path} and parts');
var writer = new AsyncStringWriter();
var visitor = new _ViewPropInliner(
assetId, codeWithParts, writer, new XhrImpl(reader), annotationMatcher);
parsedCode.accept(visitor);
return visitor.modifiedSource ? writer.asyncToString() : null;
}
final _urlResolver = createOfflineCompileUrlResolver();
class _ViewPropInliner extends RecursiveAstVisitor<Object> {
/// The prefixes given to inlined names.
static const _inlinedTemplateBase = '_template';
static const _inlinedStyleBase = '_style';
final AssetId _assetId;
/// The code we are operating on.
final String _code;
/// The asset uri for the code we are operating on.
final Uri _baseUri;
final AsyncStringWriter _writer;
final XHR _xhr;
final AnnotationMatcher _annotationMatcher;
/// Variable name, string to be inlined pairs.
final _inlinedValues = <_InlinedValue>[];
/// The final index of the last substring we wrote.
int _lastIndex = 0;
/// Whether we are currently inlining.
bool _isInlining = false;
/// Whether this visitor actually inlined any properties.
bool get modifiedSource => _lastIndex > 0;
_ViewPropInliner(AssetId assetId, this._code, AsyncStringWriter writer,
this._xhr, this._annotationMatcher)
: _assetId = assetId,
_baseUri = Uri.parse(toAssetUri(assetId)),
_writer = writer,
super();
@override
Object visitCompilationUnit(CompilationUnit node) {
final retVal = super.visitCompilationUnit(node);
if (modifiedSource) {
_writer.print(_code.substring(_lastIndex));
_inlinedValues.forEach((v) => _writer.asyncPrint(v.asyncToString()));
}
return retVal;
}
@override
Object visitAnnotation(Annotation node) {
var wasInlining = _isInlining;
_isInlining = _annotationMatcher.isView(node, _assetId) ||
_annotationMatcher.isComponent(node, _assetId);
final retVal = super.visitAnnotation(node);
_isInlining = wasInlining;
return retVal;
}
@override
Object visitNamedExpression(NamedExpression node) {
if (_isInlining) {
if (node.name is! Label || node.name.label is! SimpleIdentifier) {
throw new FormatException(
'Angular 2 currently only supports simple identifiers in directives.',
'$node' /* source */);
}
var keyString = '${node.name.label}';
switch (keyString) {
case 'templateUrl':
_populateTemplateUrl(node);
// Remove `templateUrl`
return null;
case 'styleUrls':
_populateStyleUrls(node);
// Remove `styleUrls`
return null;
}
}
return super.visitNamedExpression(node);
}
/// Counts the newline characters in the code represented by `node`.
int _countNewlines(AstNode node) {
if (node.offset == null ||
node.offset < 0 ||
node.end == null ||
node.end < 0) {
return 0;
}
return LineSplitter.split(_code.substring(node.offset, node.end)).length -
1;
}
void _populateStyleUrls(NamedExpression node) {
var urls = naiveEval(node.expression);
if (urls is! List) {
zone.log
.warning('styleUrls is not a List of Strings (${node.expression})');
return;
}
_writer.print(_code.substring(_lastIndex, node.offset));
_lastIndex = node.end;
_writer.print('styles: const [');
for (var url in urls) {
if (url is String) {
final inlinedVal = _addInlineValue(url, varBase: _inlinedStyleBase);
_writer.print('${inlinedVal.name},');
} else {
zone.log.warning('style url is not a String (${url})', asset: _assetId);
}
}
_writer.print(']');
for (var i = 0, n = _countNewlines(node); i < n; ++i) {
_writer.println('');
}
}
void _populateTemplateUrl(NamedExpression node) {
var url = naiveEval(node.expression);
if (url is! String) {
zone.log.warning('template url is not a String (${node.expression})',
asset: _assetId);
return;
}
_writer.print(_code.substring(_lastIndex, node.offset));
_lastIndex = node.end;
final inlinedVal = _addInlineValue(url, varBase: _inlinedTemplateBase);
_writer.print('template: ${inlinedVal.name}');
for (var i = 0, n = _countNewlines(node); i < n; ++i) {
_writer.println('');
}
}
/// Attempts to read the content from [url]. If [url] is relative, uses
/// [_baseUri] as resolution base.
Future<String> _readOrEmptyString(String url) async {
final resolvedUri = _urlResolver.resolve(_baseUri.toString(), url);
return _xhr.get(resolvedUri).catchError((_) {
zone.log.error('$_baseUri: could not read $url', asset: _assetId);
return '';
});
}
/// Adds a url to be inlined and requests its content.
///
/// `varBase` is the base of the variable name the inlined value will be
/// assigned to.
/// Returns the created [_InlinedValue] object.
_InlinedValue _addInlineValue(String url, {String varBase}) {
final val = new _InlinedValue(
'${varBase}${_inlinedValues.length}', _readOrEmptyString(url));
_inlinedValues.add(val);
return val;
}
}
class _InlinedValue {
final String name;
final Future<String> futureValue;
_InlinedValue(this.name, this.futureValue);
/// Returns a const declaration of the inlined value.
Future<String> asyncToString() async {
return "const $name = r'''${await futureValue}''';";
}
}

View File

@ -1,35 +0,0 @@
library angular2.transform.reflection_remover.codegen;
import 'package:angular2/src/transform/common/names.dart';
import 'package:barback/barback.dart';
import 'package:path/path.dart' as path;
class Codegen {
static const _PREFIX_BASE = 'ngStaticInit';
final AssetId reflectionEntryPoint;
/// The prefix used to import our generated file.
final String prefix;
Codegen(this.reflectionEntryPoint, {String prefix})
: this.prefix = prefix == null ? _PREFIX_BASE : prefix {
if (this.prefix.isEmpty) throw new ArgumentError.value('(empty)', 'prefix');
}
/// Generates code to import the library containing the method which sets up
/// Angular2 reflection statically.
///
/// The code generated here should follow the example of code generated for
/// an {@link ImportDirective} node.
String codegenImport() {
var importUri = path.basename(
reflectionEntryPoint.changeExtension(TEMPLATE_EXTENSION).path);
return '''import '$importUri' as $prefix;''';
}
/// Generates code to call the method which sets up Angular2 reflection
/// statically.
String codegenSetupReflectionCall() {
return '$prefix.$SETUP_METHOD_NAME();';
}
}

View File

@ -1,59 +0,0 @@
library angular2.transform.reflection_remover.entrypoint_matcher;
import 'package:analyzer/analyzer.dart';
import 'package:barback/barback.dart';
import 'package:angular2/src/transform/common/annotation_matcher.dart';
import 'package:angular2/src/transform/common/naive_eval.dart';
/// Determines if a [FunctionDeclaration] or [MethodDeclaration] is an
/// `AngularEntrypoint`.
class EntrypointMatcher {
final AssetId _assetId;
final AnnotationMatcher _annotationMatcher;
EntrypointMatcher(this._assetId, this._annotationMatcher) {
if (_assetId == null) {
throw new ArgumentError.notNull('AssetId');
}
if (_annotationMatcher == null) {
throw new ArgumentError.notNull('AnnotationMatcher');
}
}
bool isEntrypoint(AnnotatedNode node) {
if (node == null ||
(node is! FunctionDeclaration && node is! MethodDeclaration)) {
return false;
}
return node.metadata
.any((a) => _annotationMatcher.isEntrypoint(a, _assetId));
}
/// Gets the name assigned to the `AngularEntrypoint`.
///
/// This method assumes the name is the first argument to `AngularEntrypoint`;
String getName(AnnotatedNode node) {
final annotation = node.metadata.firstWhere(
(a) => _annotationMatcher.isEntrypoint(a, _assetId),
orElse: () => null);
if (annotation == null) return null;
if (annotation.arguments == null ||
annotation.arguments.arguments == null ||
annotation.arguments.arguments.isEmpty) {
return _defaultEntrypointName;
}
final entryPointName = naiveEval(annotation.arguments.arguments.first);
if (entryPointName == NOT_A_CONSTANT) {
throw new ArgumentError(
'Could not evaluate "${node}" as parameter to @AngularEntrypoint');
}
if (entryPointName is! String) {
throw new ArgumentError('Unexpected type "${entryPointName.runtimeType}" '
'as first parameter to @AngularEntrypoint');
}
return entryPointName;
}
}
const _defaultEntrypointName = "(no name provided)";

View File

@ -1,32 +0,0 @@
library angular2.transform.reflection_remover.remove_reflection_capabilities;
import 'dart:async';
import 'package:analyzer/analyzer.dart';
import 'package:barback/barback.dart';
import 'package:angular2/src/transform/common/annotation_matcher.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/mirror_mode.dart';
import 'codegen.dart';
import 'entrypoint_matcher.dart';
import 'rewriter.dart';
/// Finds the call to the Angular2 `ReflectionCapabilities` constructor
/// in `reflectionEntryPoint` and replaces it with a call to
/// `setupReflection` in `newEntryPoint`.
///
/// This only searches the code in `reflectionEntryPoint`, not `part`s,
/// `import`s, `export`s, etc.
Future<String> removeReflectionCapabilities(AssetReader reader,
AssetId reflectionEntryPoint, AnnotationMatcher annotationMatcher,
{MirrorMode mirrorMode: MirrorMode.none,
bool writeStaticInit: true}) async {
var code = await reader.readAsString(reflectionEntryPoint);
var codegen = new Codegen(reflectionEntryPoint);
return new Rewriter(code, codegen,
new EntrypointMatcher(reflectionEntryPoint, annotationMatcher),
mirrorMode: mirrorMode, writeStaticInit: writeStaticInit)
.rewrite(parseCompilationUnit(code, name: reflectionEntryPoint.path));
}

View File

@ -1,331 +0,0 @@
library angular2.transform.reflection_remover.rewriter;
import 'package:analyzer/src/generated/ast.dart';
import 'package:path/path.dart' as path;
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/mirror_matcher.dart';
import 'package:angular2/src/transform/common/mirror_mode.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'codegen.dart';
import 'entrypoint_matcher.dart';
class Rewriter {
final String _code;
final Codegen _codegen;
final EntrypointMatcher _entrypointMatcher;
final MirrorMatcher _mirrorMatcher;
final MirrorMode _mirrorMode;
final bool _writeStaticInit;
Rewriter(this._code, this._codegen, this._entrypointMatcher,
{MirrorMatcher mirrorMatcher,
MirrorMode mirrorMode: MirrorMode.none,
bool writeStaticInit: true})
: _mirrorMode = mirrorMode,
_writeStaticInit = writeStaticInit,
_mirrorMatcher =
mirrorMatcher == null ? const MirrorMatcher() : mirrorMatcher {
if (_codegen == null) {
throw new ArgumentError.notNull('Codegen');
}
if (_entrypointMatcher == null) {
throw new ArgumentError.notNull('EntrypointMatcher');
}
}
/// Rewrites the provided code to remove dart:mirrors.
///
/// Specifically, removes imports of the
/// {@link ReflectionCapabilities} library and instantiations of
/// {@link ReflectionCapabilities}, as detected by the (potentially) provided
/// {@link MirrorMatcher}.
///
/// To the extent possible, this method does not change line numbers or
/// offsets in the provided code to facilitate debugging via source maps.
String rewrite(CompilationUnit node) {
if (node == null) throw new ArgumentError.notNull('node');
var visitor = new _RewriterVisitor(this);
node.accept(visitor);
return visitor.outputRewrittenCode();
}
}
/// Visitor responsible for rewriting the Angular 2 code which instantiates
/// {@link ReflectionCapabilities} and removing its associated import.
///
/// This breaks our dependency on dart:mirrors, which enables smaller code
/// size and better performance.
class _RewriterVisitor extends Object with RecursiveAstVisitor<Object> {
final Rewriter _rewriter;
final buf = new StringBuffer();
final reflectionCapabilityAssignments = <AssignmentExpression>[];
int _currentIndex = 0;
bool _setupAdded = false;
bool _importAdded = false;
/// Whether we imported static bootstrap by e.g. rewriting a non-static
/// bootstrap import.
bool _hasStaticBootstrapImport = false;
_RewriterVisitor(this._rewriter);
@override
Object visitImportDirective(ImportDirective node) {
buf.write(_rewriter._code.substring(_currentIndex, node.offset));
_currentIndex = node.offset;
if (_rewriter._mirrorMatcher.hasReflectionCapabilitiesUri(node)) {
_rewriteReflectionCapabilitiesImport(node);
} else if (_rewriter._mirrorMatcher.hasBootstrapUri(node)) {
_rewriteBootstrapImportToStatic(node);
}
if (!_importAdded && _rewriter._writeStaticInit) {
// Add imports for ng_deps (once)
buf.write(_rewriter._codegen.codegenImport());
_importAdded = true;
}
return null;
}
@override
Object visitAssignmentExpression(AssignmentExpression node) {
if (node.rightHandSide is InstanceCreationExpression &&
_rewriter._mirrorMatcher
.isNewReflectionCapabilities(node.rightHandSide)) {
reflectionCapabilityAssignments.add(node);
_rewriteReflectionCapabilitiesAssignment(node);
}
return super.visitAssignmentExpression(node);
}
@override
Object visitInstanceCreationExpression(InstanceCreationExpression node) {
if (_rewriter._mirrorMatcher.isNewReflectionCapabilities(node) &&
!reflectionCapabilityAssignments.contains(node.parent)) {
log.error('Unexpected format in creation of '
'${REFLECTION_CAPABILITIES_NAME}');
}
return super.visitInstanceCreationExpression(node);
}
@override
Object visitMethodInvocation(MethodInvocation node) {
if (_hasStaticBootstrapImport &&
node.methodName.toString() == BOOTSTRAP_NAME) {
_rewriteBootstrapCallToStatic(node);
}
return super.visitMethodInvocation(node);
}
@override
Object visitMethodDeclaration(MethodDeclaration node) {
if (_rewriter._entrypointMatcher.isEntrypoint(node)) {
if (_rewriter._writeStaticInit) {
_rewriteEntrypointFunctionBody(node.body);
}
}
return super.visitMethodDeclaration(node);
}
@override
Object visitFunctionDeclaration(FunctionDeclaration node) {
if (_rewriter._entrypointMatcher.isEntrypoint(node)) {
if (_rewriter._writeStaticInit) {
_rewriteEntrypointFunctionBody(node.functionExpression.body);
}
}
return super.visitFunctionDeclaration(node);
}
void _rewriteEntrypointFunctionBody(FunctionBody node) {
if (node is BlockFunctionBody) {
final insertOffset = node.block.leftBracket.end;
buf.write(_rewriter._code.substring(_currentIndex, insertOffset));
buf.write(_getStaticReflectorInitBlock());
_currentIndex = insertOffset;
_setupAdded = true;
} else if (node is ExpressionFunctionBody) {
// TODO(kegluneq): Add support, see issue #5474.
throw new ArgumentError(
'Arrow syntax is not currently supported as `@AngularEntrypoint`s');
} else if (node is NativeFunctionBody) {
throw new ArgumentError('Native functions and methods are not supported '
'as `@AngularEntrypoint`s');
} else if (node is EmptyFunctionBody) {
throw new ArgumentError('Empty functions and methods are not supported '
'as `@AngularEntrypoint`s');
}
}
String outputRewrittenCode() {
if (_currentIndex < _rewriter._code.length) {
buf.write(_rewriter._code.substring(_currentIndex));
}
return '$buf';
}
_rewriteBootstrapImportToStatic(ImportDirective node) {
if (_rewriter._writeStaticInit) {
// rewrite bootstrap import to its static version.
buf.write(_rewriter._code.substring(_currentIndex, node.offset));
buf.write("import '$BOOTSTRAP_STATIC_URI'");
// The index of the last character we've processed.
var lastIdx = node.uri.end;
// Maintain the import prefix, if present.
if (node.prefix != null) {
buf.write(_rewriter._code.substring(lastIdx, node.prefix.end));
lastIdx = node.prefix.end;
}
// Handle combinators ("show" and "hide" on an "import" directive).
// 1. A combinator like "show $BOOTSTRAP_NAME" no longer makes sense, so
// we need to rewrite it.
// 2. It's possible we'll need to call the setup method
// (SETUP_METHOD_NAME), so make sure it is visible.
if (node.combinators != null) {
for (var combinator in node.combinators) {
buf.write(_rewriter._code
.substring(lastIdx, combinator.end)
.replaceAll(BOOTSTRAP_NAME, BOOTSTRAP_STATIC_NAME));
lastIdx = combinator.end;
if (combinator is ShowCombinator) {
buf.write(', $SETUP_METHOD_NAME');
} else if (combinator is HideCombinator) {
// Ensure the user is not explicitly hiding SETUP_METHOD_NAME.
// I don't know why anyone would do this, but it would result in
// some confusing behavior, so throw an explicit error.
combinator.hiddenNames.forEach((id) {
if (id.toString() == SETUP_METHOD_NAME) {
throw new FormatException(
'Import statement explicitly hides initialization function '
'$SETUP_METHOD_NAME. Please do not do this: "$node"');
}
});
}
}
}
// Write anything after the combinators.
buf.write(_rewriter._code.substring(lastIdx, node.end));
_hasStaticBootstrapImport = true;
} else {
// leave it as is
buf.write(_rewriter._code.substring(_currentIndex, node.end));
}
_currentIndex = node.end;
}
_rewriteBootstrapCallToStatic(MethodInvocation node) {
if (_rewriter._writeStaticInit) {
buf.write(_rewriter._code.substring(_currentIndex, node.offset));
var args = node.argumentList.arguments;
int numArgs = node.argumentList.arguments.length;
if (numArgs < 1 || numArgs > 2) {
log.warning('`bootstrap` does not support $numArgs arguments. '
'Found bootstrap${node.argumentList}. Transform may not succeed.');
}
var reflectorInit =
_setupAdded ? '' : ', () { ${_getStaticReflectorInitBlock()} }';
// rewrite `bootstrap(...)` to `bootstrapStatic(...)`
if (node.target != null && node.target is SimpleIdentifier) {
// `bootstrap` imported with a prefix, maintain this.
buf.write('${node.target}.');
}
buf.write('$BOOTSTRAP_STATIC_NAME(${args[0]}');
if (numArgs == 1) {
// bootstrap args are positional, so before we pass reflectorInit code
// we need to pass `null` for DI bindings.
if (reflectorInit.isNotEmpty) {
buf.write(', null');
}
} else {
// pass DI bindings
buf.write(', ${args[1]}');
}
buf.write(reflectorInit);
buf.write(')');
_setupAdded = true;
} else {
// leave it as is
buf.write(_rewriter._code.substring(_currentIndex, node.end));
}
_currentIndex = node.end;
}
String _getStaticReflectorInitBlock() {
return _rewriter._codegen.codegenSetupReflectionCall();
}
_rewriteReflectionCapabilitiesImport(ImportDirective node) {
buf.write(_rewriter._code.substring(_currentIndex, node.offset));
if ('${node.prefix}' == _rewriter._codegen.prefix) {
log.warning(
'Found import prefix "${_rewriter._codegen.prefix}" in source file.'
' Transform may not succeed.');
}
if (_rewriter._mirrorMode != MirrorMode.none) {
buf.write(_importDebugReflectionCapabilities(node));
} else {
buf.write(_commentedNode(node));
}
_currentIndex = node.end;
}
_rewriteReflectionCapabilitiesAssignment(AssignmentExpression assignNode) {
var node = assignNode;
while (node.parent is ExpressionStatement) {
node = node.parent;
}
buf.write(_rewriter._code.substring(_currentIndex, node.offset));
if (_rewriter._writeStaticInit && !_setupAdded) {
buf.write(_getStaticReflectorInitBlock());
_setupAdded = true;
}
switch (_rewriter._mirrorMode) {
case MirrorMode.debug:
buf.write(node);
break;
case MirrorMode.verbose:
buf.write(_instantiateVerboseReflectionCapabilities(assignNode));
break;
case MirrorMode.none:
default:
buf.write(_commentedNode(node));
break;
}
_currentIndex = node.end;
}
String _commentedNode(AstNode node) {
return '/*${_rewriter._code.substring(node.offset, node.end)}*/';
}
}
String _importDebugReflectionCapabilities(ImportDirective node) {
var uri = '${node.uri}';
uri = path
.join(path.dirname(uri), 'debug_${path.basename(uri)}')
.replaceAll('\\', '/');
var asClause = node.prefix != null ? ' as ${node.prefix}' : '';
return 'import $uri$asClause;';
}
String _instantiateVerboseReflectionCapabilities(
AssignmentExpression assignNode) {
if (assignNode.rightHandSide is! InstanceCreationExpression) {
return '$assignNode;';
}
var rhs = (assignNode.rightHandSide as InstanceCreationExpression);
return '${assignNode.leftHandSide} ${assignNode.operator} '
'new ${rhs.constructorName}(verbose: true);';
}

View File

@ -1,69 +0,0 @@
library angular2.transform.reflection_remover.transformer;
import 'dart:async';
import 'package:barback/barback.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/mirror_mode.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/options.dart';
import 'package:angular2/src/transform/common/options_reader.dart';
import 'package:angular2/src/transform/common/zone.dart' as zone;
import 'remove_reflection_capabilities.dart';
/// Transformer responsible for removing the import and instantiation of
/// {@link ReflectionCapabilities}.
///
/// The goal of this is to break the app's dependency on dart:mirrors.
///
/// This transformer assumes that {@link DirectiveProcessor} and {@link DirectiveLinker}
/// have already been run and that a .ngfactory.dart file has been generated for
/// {@link options.entryPoint}. The instantiation of {@link ReflectionCapabilities} is
/// replaced by calling `initReflector` in that .ngfactory.dart file.
class ReflectionRemover extends Transformer implements LazyTransformer {
final TransformerOptions options;
ReflectionRemover(this.options);
/// Ctor which tells pub that this can be run as a standalone transformer.
factory ReflectionRemover.asPlugin(BarbackSettings settings) =>
new ReflectionRemover(parseBarbackSettings(settings));
@override
bool isPrimary(AssetId id) =>
options.entryPointGlobs != null &&
options.entryPointGlobs.any((g) => g.matches(id.path));
@override
declareOutputs(DeclaringTransform transform) {
transform.declareOutput(transform.primaryId);
}
@override
Future apply(Transform transform) async {
return zone.exec(() async {
var primaryId = transform.primaryInput.id;
var mirrorMode = options.mirrorMode;
var writeStaticInit = options.initReflector;
if (options.modeName == TRANSFORM_DYNAMIC_MODE) {
mirrorMode = MirrorMode.debug;
writeStaticInit = false;
zone.log.info(
'Running in "${options.modeName}", '
'mirrorMode: ${mirrorMode}, '
'writeStaticInit: ${writeStaticInit}.',
asset: primaryId);
}
var transformedCode = await removeReflectionCapabilities(
new AssetReader.fromTransform(transform),
primaryId,
options.annotationMatcher,
mirrorMode: mirrorMode,
writeStaticInit: writeStaticInit);
transform.addOutput(new Asset.fromString(primaryId, transformedCode));
}, log: transform.logger);
}
}

View File

@ -1,36 +0,0 @@
library angular2.transform.stylesheet_compiler.processor;
import 'dart:async';
import 'package:angular2/src/compiler/offline_compiler.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/code/source_module.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/ng_compiler.dart';
import 'package:angular2/src/transform/common/zone.dart' as zone;
import 'package:barback/barback.dart';
AssetId shimmedStylesheetAssetId(AssetId cssAssetId) => new AssetId(
cssAssetId.package, toShimmedStylesheetExtension(cssAssetId.path));
AssetId nonShimmedStylesheetAssetId(AssetId cssAssetId) => new AssetId(
cssAssetId.package, toNonShimmedStylesheetExtension(cssAssetId.path));
Future<Iterable<Asset>> processStylesheet(
AssetReader reader, AssetId stylesheetId) async {
final stylesheetUrl = '${stylesheetId.package}|${stylesheetId.path}';
var templateCompiler = zone.templateCompiler;
if (templateCompiler == null) {
templateCompiler = createTemplateCompiler(reader);
}
final cssText = await reader.readAsString(stylesheetId);
return logElapsedAsync(() async {
final sourceModules =
templateCompiler.compileStylesheet(stylesheetUrl, cssText);
return sourceModules.map((SourceModule module) => new Asset.fromString(
new AssetId.parse('${module.moduleUrl}'), writeSourceModule(module)));
}, operationName: 'processStylesheet', assetId: stylesheetId);
}

View File

@ -1,50 +0,0 @@
library angular2.transform.stylesheet_compiler.transformer;
import 'dart:async';
import 'package:barback/barback.dart';
import 'package:angular2/src/platform/server/html_adapter.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/zone.dart' as zone;
import 'processor.dart';
/// Pre-compiles CSS stylesheet files to Dart code for Angular 2.
class StylesheetCompiler extends Transformer implements LazyTransformer {
StylesheetCompiler();
@override
bool isPrimary(AssetId id) {
return id.path.endsWith(CSS_EXTENSION);
}
@override
declareOutputs(DeclaringTransform transform) {
// Note: we check this assumption below.
_getExpectedOutputs(transform.primaryId).forEach(transform.declareOutput);
}
List<AssetId> _getExpectedOutputs(AssetId cssId) =>
[shimmedStylesheetAssetId(cssId), nonShimmedStylesheetAssetId(cssId)];
@override
Future apply(Transform transform) async {
final reader = new AssetReader.fromTransform(transform);
return zone.exec(() async {
Html5LibDomAdapter.makeCurrent();
var primaryId = transform.primaryInput.id;
var outputs = await processStylesheet(reader, primaryId);
var expectedIds = _getExpectedOutputs(primaryId);
outputs.forEach((Asset compiledStylesheet) {
var id = compiledStylesheet.id;
if (!expectedIds.contains(id)) {
throw new StateError(
'Unexpected output for css processing of $primaryId: $id');
}
transform.addOutput(compiledStylesheet);
});
}, log: transform.logger);
}
}

View File

@ -1,264 +0,0 @@
library angular2.transform.template_compiler.compile_data_creator;
import 'dart:async';
import 'dart:convert';
import 'package:angular2/src/compiler/compile_metadata.dart';
import 'package:angular2/src/compiler/offline_compiler.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart';
import 'package:angular2/src/transform/common/model/reflection_info_model.pb.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/ng_meta.dart';
import 'package:angular2/src/transform/common/url_resolver.dart';
import 'package:barback/barback.dart';
/// Creates [NormalizedComponentWithViewDirectives] objects for all `View`
/// `Directive`s defined in `assetId`.
///
/// The returned value wraps the [NgDepsModel] at `assetId` as well as these
/// created objects.
///
/// `platformDirectives` is an optional [List] containing names of [Directive]s
/// which should be available to all [View]s in this app.
///
/// `platformPipes` is an optional [List] containing names of [Pipe]s which
/// should be available to all [View]s in this app.
Future<CompileDataResults> createCompileData(
AssetReader reader,
AssetId assetId,
List<String> platformDirectives,
List<String> platformPipes) async {
return logElapsedAsync(() async {
final creator = await _CompileDataCreator.create(
reader, assetId, platformDirectives, platformPipes);
return creator != null ? creator.createCompileData() : null;
}, operationName: 'createCompileData', assetId: assetId);
}
class CompileDataResults {
final NgMeta ngMeta;
final Map<ReflectionInfoModel, NormalizedComponentWithViewDirectives>
viewDefinitions;
CompileDataResults._(this.ngMeta, this.viewDefinitions);
}
/// Creates [ViewDefinition] objects for all `View` `Directive`s defined in
/// `entryPoint`.
class _CompileDataCreator {
final AssetReader reader;
final AssetId entryPoint;
final NgMeta ngMeta;
final List<String> platformDirectives;
final List<String> platformPipes;
_CompileDataCreator(this.reader, this.entryPoint, this.ngMeta,
this.platformDirectives, this.platformPipes);
static Future<_CompileDataCreator> create(AssetReader reader, AssetId assetId,
List<String> platformDirectives, List<String> platformPipes) async {
if (!(await reader.hasInput(assetId))) return null;
final json = await reader.readAsString(assetId);
if (json == null || json.isEmpty) return null;
final ngMeta = new NgMeta.fromJson(JSON.decode(json));
return new _CompileDataCreator(
reader, assetId, ngMeta, platformDirectives, platformPipes);
}
NgDepsModel get ngDeps => ngMeta.ngDeps;
Future<CompileDataResults> createCompileData() async {
var hasTemplate = ngDeps != null &&
ngDeps.reflectables != null &&
ngDeps.reflectables.any((reflectable) {
if (ngMeta.identifiers.containsKey(reflectable.name)) {
final metadata = ngMeta.identifiers[reflectable.name];
return metadata is CompileDirectiveMetadata;
}
return false;
});
if (!hasTemplate) return new CompileDataResults._(ngMeta, const {});
final compileData =
<ReflectionInfoModel, NormalizedComponentWithViewDirectives>{};
final platformDirectives =
await _readPlatformTypes(this.platformDirectives, 'directives');
final platformPipes = await _readPlatformTypes(this.platformPipes, 'pipes');
final ngMetaMap = await _extractNgMeta();
for (var reflectable in ngDeps.reflectables) {
if (ngMeta.identifiers.containsKey(reflectable.name)) {
final compileDirectiveMetadata = ngMeta.identifiers[reflectable.name];
if (compileDirectiveMetadata is CompileDirectiveMetadata &&
compileDirectiveMetadata.template != null) {
final compileDatum = new NormalizedComponentWithViewDirectives(
compileDirectiveMetadata,
<CompileDirectiveMetadata>[],
<CompilePipeMetadata>[]);
compileDatum.directives.addAll(platformDirectives);
compileDatum.directives
.addAll(_resolveTypeMetadata(ngMetaMap, reflectable.directives));
compileDatum.pipes.addAll(platformPipes);
compileDatum.pipes
.addAll(_resolveTypeMetadata(ngMetaMap, reflectable.pipes));
compileData[reflectable] = compileDatum;
}
}
}
return new CompileDataResults._(ngMeta, compileData);
}
List<dynamic> _resolveTypeMetadata(
Map<String, NgMeta> ngMetaMap, List<PrefixedType> prefixedTypes) {
var resolvedMetadata = [];
for (var dep in prefixedTypes) {
if (!ngMetaMap.containsKey(dep.prefix)) {
log.error(
'Missing prefix "${dep.prefix}" '
'needed by "${dep}" from metadata map,',
asset: entryPoint);
return null;
}
final depNgMeta = ngMetaMap[dep.prefix];
if (depNgMeta.aliases.containsKey(dep.name)) {
resolvedMetadata.addAll(depNgMeta.flatten(dep.name));
} else if (depNgMeta.identifiers.containsKey(dep.name)) {
resolvedMetadata.add(depNgMeta.identifiers[dep.name]);
} else {
log.error(
'Could not find Directive/Pipe entry for $dep. '
'Please be aware that Dart transformers have limited support for '
'reusable, pre-defined lists of Directives/Pipes (aka '
'"directive/pipe aliases"). See https://goo.gl/d8XPt0 for details.',
asset: entryPoint);
}
}
return resolvedMetadata;
}
Future<List<dynamic>> _readPlatformTypes(
List<String> inputPlatformTypes, String configOption) async {
if (inputPlatformTypes == null) return const [];
final res = [];
for (var pd in inputPlatformTypes) {
final parts = pd.split("#");
if (parts.length != 2) {
log.warning(
'The platform ${configOption} configuration option '
'must be in the following format: "URI#TOKEN"',
asset: entryPoint);
return const [];
}
res.addAll(await _readPlatformTypesFromUri(parts[0], parts[1]));
}
return res;
}
Future<List<dynamic>> _readPlatformTypesFromUri(
String uri, String token) async {
final metaAssetId = fromUri(toMetaExtension(uri));
try {
var jsonString = await reader.readAsString(metaAssetId);
if (jsonString != null && jsonString.isNotEmpty) {
var newMetadata = new NgMeta.fromJson(JSON.decode(jsonString));
if (newMetadata.aliases.containsKey(token)) {
return newMetadata.flatten(token);
} else if (newMetadata.identifiers.containsKey(token)) {
return [newMetadata.identifiers[token]];
} else {
log.warning('Could not resolve platform type ${token} in ${uri}',
asset: metaAssetId);
}
}
} catch (ex, stackTrace) {
log.warning('Failed to decode: $ex, $stackTrace', asset: metaAssetId);
}
return [];
}
/// Creates a map from import prefix to the asset: uris of all `.dart`
/// libraries visible from `entryPoint`, excluding `dart:` and generated files
/// it imports. Unprefixed imports have the empty string as their key.
/// `entryPoint` is included in the map with no prefix.
Map<String, Iterable<String>> _createPrefixToImportsMap() {
final baseUri = toAssetUri(entryPoint);
final map = <String, Set<String>>{'': new Set<String>()..add(baseUri)};
if (ngDeps == null || ngDeps.imports == null || ngDeps.imports.isEmpty) {
return map;
}
final resolver = createOfflineCompileUrlResolver();
ngMeta.ngDeps.imports
.where((model) => !isDartCoreUri(model.uri))
.forEach((model) {
var prefix = model.prefix == null ? '' : model.prefix;
map
.putIfAbsent(prefix, () => new Set<String>())
.add(resolver.resolve(baseUri, model.uri));
});
return map;
}
/// Reads the `.ng_meta.json` files associated with all of `entryPoint`'s
/// imports and creates a map of prefix (or blank) to the
/// associated [NgMeta] object.
///
/// For example, if in `entryPoint` we have:
///
/// ```
/// import 'component.dart' as prefix;
/// ```
///
/// and in 'component.dart' we have:
///
/// ```
/// @Component(...)
/// class MyComponent {...}
/// ```
///
/// This method will look for `component.ng_meta.json`to contain the
/// serialized [NgMeta] for `MyComponent` and any other
/// `Directive`s declared in `component.dart`. We use this information to
/// build a map:
///
/// ```
/// {
/// "prefix": [NgMeta with CompileDirectiveMetadata for MyComponent],
/// ...<any other entries>...
/// }
/// ```
Future<Map<String, NgMeta>> _extractNgMeta() async {
var prefixToImports = _createPrefixToImportsMap();
final retVal = <String, NgMeta>{};
for (var prefix in prefixToImports.keys) {
var ngMeta = retVal[prefix] = new NgMeta.empty();
for (var importAssetUri in prefixToImports[prefix]) {
var metaAssetId = fromUri(toMetaExtension(importAssetUri));
if (await reader.hasInput(metaAssetId)) {
try {
var jsonString = await reader.readAsString(metaAssetId);
if (jsonString != null && jsonString.isNotEmpty) {
var newMetadata = new NgMeta.fromJson(JSON.decode(jsonString));
ngMeta.addAll(newMetadata);
}
} catch (ex, stackTrace) {
log.warning('Failed to decode: $ex, $stackTrace',
asset: metaAssetId);
}
}
}
}
return retVal;
}
}

View File

@ -1,85 +0,0 @@
library angular2.transform.template_compiler.generator;
import 'dart:async';
import 'package:barback/barback.dart';
import 'package:angular2/src/compiler/offline_compiler.dart';
import 'package:angular2/src/compiler/config.dart';
import 'package:angular2/src/facade/lang.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/model/annotation_model.pb.dart';
import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/ng_compiler.dart';
import 'package:angular2/src/transform/common/zone.dart' as zone;
import 'package:angular2/i18n.dart';
import 'package:angular2/src/transform/common/options.dart' show CODEGEN_DEBUG_MODE;
import 'compile_data_creator.dart';
/// Generates `.ngfactory.dart` files to initialize the Angular2 system.
///
/// - Processes the `.ng_meta.json` file represented by `assetId` using
/// `createCompileData`.
/// - Passes the resulting `NormalizedComponentWithViewDirectives` instance(s)
/// to the `TemplateCompiler` to generate compiled template(s) as a
/// `SourceModule`.
/// - Uses the resulting `NgDeps` object to generate code which initializes the
/// Angular2 reflective system.
///
/// This method assumes a {@link DomAdapter} has been registered.
Future<Outputs> processTemplates(AssetReader reader, AssetId assetId,
{String codegenMode: '',
bool reflectPropertiesAsAttributes: false,
List<String> platformDirectives,
List<String> platformPipes,
XmbDeserializationResult translations,
Map<String, String> resolvedIdentifiers
}) async {
var viewDefResults = await createCompileData(
reader, assetId, platformDirectives, platformPipes);
if (viewDefResults == null) return null;
var templateCompiler = zone.templateCompiler;
if (templateCompiler == null) {
templateCompiler = createTemplateCompiler(reader,
compilerConfig: new CompilerConfig(
codegenMode == CODEGEN_DEBUG_MODE, reflectPropertiesAsAttributes, false),
translations: translations);
}
final compileData =
viewDefResults.viewDefinitions.values.toList(growable: false);
if (compileData.isEmpty) {
return new Outputs._(viewDefResults.ngMeta.ngDeps, null);
}
final compiledTemplates = logElapsedSync(() {
return templateCompiler.compileTemplates(compileData);
}, operationName: 'compileTemplates', assetId: assetId);
if (compiledTemplates != null) {
// We successfully compiled templates!
// For each compiled template, add the compiled template class as an
// "Annotation" on the code to be registered with the reflector.
for (var reflectable in viewDefResults.viewDefinitions.keys) {
// TODO(kegluneq): Avoid duplicating naming logic for generated classes.
reflectable.annotations.add(new AnnotationModel()
..name = '${reflectable.name}NgFactory'
..isConstObject = true);
}
}
return new Outputs._(viewDefResults.ngMeta.ngDeps, compiledTemplates);
}
AssetId templatesAssetId(AssetId primaryId) =>
new AssetId(primaryId.package, toTemplateExtension(primaryId.path));
class Outputs {
final NgDepsModel ngDeps;
final SourceModule templatesSource;
Outputs._(this.ngDeps, this.templatesSource);
}

View File

@ -1,89 +0,0 @@
library angular2.transform.template_compiler.transformer;
import 'dart:async';
import 'package:barback/barback.dart';
import 'package:angular2/src/platform/server/html_adapter.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/code/ng_deps_code.dart';
import 'package:angular2/src/transform/common/code/source_module.dart';
import 'package:angular2/src/transform/common/formatter.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/options.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/zone.dart' as zone;
import 'package:angular2/i18n.dart';
import 'generator.dart';
/// {@link Transformer} responsible for processing Angular 2 templates.
///
/// {@link TemplateCompiler} uses the Angular 2 `TemplateCompiler` to process
/// the templates, extracting information about what reflection is necessary to
/// render and use that template. It then generates code in place of those
/// reflective accesses.
///
/// This transformer is part of a multi-phase transform.
/// See `angular2/src/transform/transformer.dart` for transformer ordering.
class TemplateCompiler extends Transformer implements LazyTransformer {
final TransformerOptions options;
XmbDeserializationResult translations;
TemplateCompiler(this.options);
@override
bool isPrimary(AssetId id) => id.path.endsWith(META_EXTENSION);
@override
declareOutputs(DeclaringTransform transform) {
transform.declareOutput(templatesAssetId(transform.primaryId));
}
@override
Future apply(Transform transform) async {
return zone.exec(() async {
Html5LibDomAdapter.makeCurrent();
var primaryId = transform.primaryInput.id;
var reader = new AssetReader.fromTransform(transform);
if (translations == null && options.translations != null) {
translations = await _deserializeXmb(reader, options.translations);
}
var outputs = await processTemplates(reader, primaryId,
codegenMode: options.codegenMode,
reflectPropertiesAsAttributes: options.reflectPropertiesAsAttributes,
platformDirectives: options.platformDirectives,
platformPipes: options.platformPipes,
resolvedIdentifiers: options.resolvedIdentifiers,
translations: translations
);
var ngDepsCode = _emptyNgDepsContents;
if (outputs != null) {
if (outputs.ngDeps != null) {
final buf = new StringBuffer();
final templatesSrc =
options.genCompiledTemplates ? outputs.templatesSource : null;
writeTemplateFile(
new NgDepsWriter(buf), outputs.ngDeps, templatesSrc);
ngDepsCode = formatter.format(buf.toString());
}
}
transform.addOutput(
new Asset.fromString(templatesAssetId(primaryId), ngDepsCode));
}, log: transform.logger);
}
Future _deserializeXmb(AssetReader reader, AssetId translations) async {
final content = await reader.readAsString(translations);
final res = deserializeXmb(content, translations.toString());
if (res.errors.length > 0) {
res.errors.forEach((e) => log.error(e.msg));
throw "Cannot parse xmb file";
} else {
return res;
}
}
}
const _emptyNgDepsContents = 'initReflector() {}\n';

View File

@ -1,57 +0,0 @@
library angular2.src.transform.transformer;
import 'package:barback/barback.dart';
import 'package:dart_style/dart_style.dart';
import 'common/eager_transformer_wrapper.dart';
import 'common/formatter.dart' as formatter;
import 'common/options.dart';
import 'common/options_reader.dart';
import 'deferred_rewriter/transformer.dart';
import 'directive_metadata_linker/transformer.dart';
import 'directive_processor/transformer.dart';
import 'inliner_for_test/transformer.dart';
import 'reflection_remover/transformer.dart';
import 'stylesheet_compiler/transformer.dart';
import 'template_compiler/transformer.dart';
export 'common/options.dart';
/// Replaces Angular 2 mirror use with generated code.
class AngularTransformerGroup extends TransformerGroup {
AngularTransformerGroup._(phases, {bool formatCode: false}) : super(phases) {
if (formatCode) {
formatter.init(new DartFormatter());
}
}
factory AngularTransformerGroup(TransformerOptions options) {
var phases;
if (options.inlineViews) {
phases = [
[new InlinerForTest(options)]
];
} else {
phases = [
[new DirectiveProcessor(options)],
[new DirectiveMetadataLinker(options)],
[new ReflectionRemover(options)],
[
new DeferredRewriter(),
new StylesheetCompiler(),
new TemplateCompiler(options)
],
];
}
if (options.modeName == BarbackMode.RELEASE || !options.lazyTransformers) {
phases = phases
.map((phase) => phase.map((t) => new EagerTransformerWrapper(t)));
}
return new AngularTransformerGroup._(phases,
formatCode: options.formatCode);
}
factory AngularTransformerGroup.asPlugin(BarbackSettings settings) {
return new AngularTransformerGroup(parseBarbackSettings(settings));
}
}

View File

@ -1,56 +0,0 @@
library angular2.transform.codegen.dart;
import 'package:barback/barback.dart';
import 'package:dart_style/dart_style.dart';
import 'package:angular2/src/transform/common/eager_transformer_wrapper.dart';
import 'package:angular2/src/transform/common/formatter.dart' as formatter;
import 'package:angular2/src/transform/common/options.dart';
import 'package:angular2/src/transform/common/options_reader.dart';
import 'package:angular2/src/transform/directive_metadata_linker/transformer.dart';
import 'package:angular2/src/transform/directive_processor/transformer.dart';
import 'package:angular2/src/transform/inliner_for_test/transformer.dart';
import 'package:angular2/src/transform/stylesheet_compiler/transformer.dart';
import 'package:angular2/src/transform/template_compiler/transformer.dart';
export 'package:angular2/src/transform/common/options.dart';
/// Generates code to replace mirror use in Angular 2 apps.
///
/// This transformer can be used along with others as a faster alternative to
/// the single angular2 transformer.
///
/// See [the wiki][] for details.
///
/// [the wiki]: https://github.com/angular/angular/wiki/Angular-2-Dart-Transformer
class CodegenTransformer extends TransformerGroup {
CodegenTransformer._(phases, {bool formatCode: false}) : super(phases) {
if (formatCode) {
formatter.init(new DartFormatter());
}
}
factory CodegenTransformer(TransformerOptions options) {
var phases;
if (options.inlineViews) {
phases = [
[new InlinerForTest(options)]
];
} else {
phases = [
[new DirectiveProcessor(options)],
[new DirectiveMetadataLinker(options)],
[new StylesheetCompiler(), new TemplateCompiler(options),],
];
}
if (options.modeName == BarbackMode.RELEASE || !options.lazyTransformers) {
phases = phases
.map((phase) => phase.map((t) => new EagerTransformerWrapper(t)));
}
return new CodegenTransformer._(phases, formatCode: options.formatCode);
}
factory CodegenTransformer.asPlugin(BarbackSettings settings) {
return new CodegenTransformer(parseBarbackSettings(settings));
}
}

View File

@ -1,45 +0,0 @@
library angular2.transform.deferred_rewriter.dart;
import 'dart:async';
import 'package:barback/barback.dart';
import 'package:angular2/src/transform/deferred_rewriter/transformer.dart'
as base show DeferredRewriter;
// TODO(kegluneq): Make this a TransformerGroup and add an AggregateTransformer
// that counts the number of transformed files & primary inputs.
// If the number of primary inputs is >> transformed files, output an error
// telling the user to use $include or $exclude in their pubspec.
/// Rewrites `deferred` imports that need Angular 2 initialization.
///
/// This transformer can be used along with others as a faster alternative to
/// the single angular2 transformer.
///
/// See [the wiki][] for details.
///
/// [the wiki]: https://github.com/angular/angular/wiki/Angular-2-Dart-Transformer
class DeferredRewriter extends Transformer implements DeclaringTransformer {
final base.DeferredRewriter _impl;
/// Ctor which tells pub that this can be run as a standalone transformer.
DeferredRewriter.asPlugin(BarbackSettings _)
: _impl = new base.DeferredRewriter();
/// Signal that we process all .dart files.
///
/// Instead, use the standard, built-in $exclude and $include transformer
/// parameters to control which files this transformer runs on.
/// See [https://www.dartlang.org/tools/pub/assets-and-transformers.html] for
/// details.
@override
String get allowedExtensions => '.dart';
@override
declareOutputs(transform) => _impl.declareOutputs(transform);
@override
Future apply(transform) =>
_impl.applyImpl(transform, transform.primaryInput.id);
}

View File

@ -1,65 +0,0 @@
library angular2.transform.reflection_remover.dart;
import 'dart:async';
import 'package:barback/barback.dart';
import 'package:angular2/src/transform/common/options.dart';
import 'package:angular2/src/transform/common/options_reader.dart';
import 'package:angular2/src/transform/reflection_remover/transformer.dart'
as base show ReflectionRemover;
// TODO(kegluneq): Make this a TransformerGroup and add an AggregateTransformer
// that counts the number of transformed files & primary inputs.
// If the number of primary inputs is >> transformed files, output an error
// telling the user to use $include or $exclude in their pubspec.
/// Removes the transitive dart:mirrors import from Angular 2 entrypoints.
///
/// This transformer can be used along with others as a faster alternative to
/// the single angular2 transformer.
///
/// See [the wiki][] for details.
///
/// [the wiki]: https://github.com/angular/angular/wiki/Angular-2-Dart-Transformer
class ReflectionRemover extends Transformer implements DeclaringTransformer {
final base.ReflectionRemover _impl;
ReflectionRemover._(this._impl);
/// Ctor which tells pub that this can be run as a standalone transformer.
factory ReflectionRemover.asPlugin(BarbackSettings settings) {
final options = parseBarbackSettings(settings);
final entryPoints = options.entryPoints;
if (entryPoints != null && entryPoints.isNotEmpty) {
// TODO(kegluneq): Add a goo.gl link with more info.
throw new ArgumentError.value(
entryPoints.join(', '),
ENTRY_POINT_PARAM,
"Do not use '$ENTRY_POINT_PARAM' when specifying the Angular 2 "
"reflection_remover transformer. Instead, use pub's built-in "
r"$include and $exclude parameters to filter which files are "
"processed.");
}
return new ReflectionRemover._(new base.ReflectionRemover(options));
}
/// Signal that we process all .dart files.
///
/// The underlying ReflectionRemover implementation respects the entry_points
/// transformer parameter, but this is inefficient and can be expensive for
/// large numbers of files.
///
/// Instead, use the standard, built-in $exclude and $include transformer
/// parameters to control which files this transformer runs on.
/// See [https://www.dartlang.org/tools/pub/assets-and-transformers.html] for
/// details.
@override
String get allowedExtensions => '.dart';
@override
declareOutputs(transform) => _impl.declareOutputs(transform);
@override
Future apply(transform) => _impl.apply(transform);
}

View File

@ -1,3 +0,0 @@
library angular2.transformer_dart;
export 'src/transform/transformer.dart';

View File

@ -1,24 +0,0 @@
name: ng2_transform
version: 0.0.0
environment:
sdk: '>=1.10.0 <2.0.0'
dependencies:
angular2:
path: ../../dist/dart/angular2
analyzer: '>=0.24.4 <0.28.0'
barback: '^0.15.2+2'
dart_style: '>=0.1.8 <0.3.0'
glob: '^1.0.0'
html: '^0.12.0'
intl: '^0.12.4'
logging: '>=0.9.0 <0.12.0'
observe: '^0.13.1'
path: '^1.0.0'
protobuf: '^0.5.0'
source_span: '^1.0.0'
stack_trace: '^1.1.1'
dev_dependencies:
transformer_test: '^0.2.0'
guinness: any
quiver: '^0.21.4'
test: '>=0.12.0 <0.13.0'

View File

@ -1,109 +0,0 @@
library angular2.test.transform.common.annotation_matcher_test;
import 'dart:async';
import 'package:analyzer/analyzer.dart';
import 'package:barback/barback.dart' show AssetId;
import 'package:test/test.dart';
import 'package:angular2/src/transform/common/annotation_matcher.dart';
main() {
allTests();
}
var simpleAst = parseCompilationUnit('''
import 'package:test/test.dart';
@Test()
var foo;
''');
var namespacedAst = parseCompilationUnit('''
import 'package:test/test.dart' as test;
@test.Test()
var foo;
''');
var relativePathAst = parseCompilationUnit('''
import 'test.dart';
@Test()
var foo;
''');
var namespacedRelativePathAst = parseCompilationUnit('''
import 'test.dart' as test;
@test.Test()
var foo;
''');
void allTests() {
test('should be able to match basic annotations.', () {
var matcher = new AnnotationMatcher()
..add(const ClassDescriptor('Test', 'package:test/test.dart'));
var visitor = new MatchRecordingVisitor(matcher);
simpleAst.accept(visitor);
expect(visitor.matches.length, equals(1));
});
test('should be able to match namespaced annotations.', () {
var matcher = new AnnotationMatcher()
..add(const ClassDescriptor('Test', 'package:test/test.dart'));
var visitor = new MatchRecordingVisitor(matcher);
namespacedAst.accept(visitor);
expect(visitor.matches.length, equals(1));
});
test('should be able to match relative imports.', () {
var matcher = new AnnotationMatcher()
..add(const ClassDescriptor('Test', 'package:test/test.dart'));
var visitor =
new MatchRecordingVisitor(matcher, new AssetId('test', 'lib/foo.dart'));
relativePathAst.accept(visitor);
expect(visitor.matches.length, equals(1));
});
test('should be able to match relative imports with a namespace.', () {
var matcher = new AnnotationMatcher()
..add(const ClassDescriptor('Test', 'package:test/test.dart'));
var visitor =
new MatchRecordingVisitor(matcher, new AssetId('test', 'lib/foo.dart'));
namespacedRelativePathAst.accept(visitor);
expect(visitor.matches.length, equals(1));
});
test('should not match annotations if the import is missing.', () {
var matcher = new AnnotationMatcher()
..add(const ClassDescriptor('Test', 'package:test/foo.dart'));
var visitor = new MatchRecordingVisitor(matcher);
simpleAst.accept(visitor);
expect(visitor.matches.isEmpty, isTrue);
});
test('should not match annotations if the name is different.', () {
var matcher = new AnnotationMatcher()
..add(const ClassDescriptor('Foo', 'package:test/test.dart'));
var visitor = new MatchRecordingVisitor(matcher);
simpleAst.accept(visitor);
expect(visitor.matches.isEmpty, isTrue);
});
}
class MatchRecordingVisitor extends RecursiveAstVisitor {
final AssetId assetId;
final AnnotationMatcher matcher;
final matches = <Annotation>[];
MatchRecordingVisitor(this.matcher, [AssetId assetId])
: super(),
this.assetId =
assetId != null ? assetId : new AssetId('a', 'lib/a.dart');
@override
void visitAnnotation(Annotation annotation) {
if (matcher.hasMatch(annotation.name, assetId)) matches.add(annotation);
}
}

View File

@ -1,14 +0,0 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library angular2.test.transform;
import 'dart:async';
/// Mocked out version of `bootstrap`, defined in application.dart. Importing
/// the actual file in tests causes issues with resolution due to its
/// transitive dependencies.
Future bootstrap(Type appComponentType,
[List bindings = null, Function givenBootstrapErrorReporter = null]) {
return null;
}

View File

@ -1,109 +0,0 @@
library angular2.test.transform.common.async_string_writer;
import 'dart:async';
import 'package:test/test.dart';
import 'package:angular2/src/transform/common/async_string_writer.dart';
void allTests() {
test('should function as a basic Writer without async calls.', () {
var writer = new AsyncStringWriter();
writer.print('hello');
expect('$writer', equals('hello'));
writer.println(', world');
expect('$writer', equals('hello, world\n'));
});
test('should concatenate futures added with `asyncPrint`.', () async {
var writer = new AsyncStringWriter();
writer.print('hello');
expect('$writer', equals('hello'));
writer.asyncPrint(new Future.value(', world.'));
writer.print(' It is a beautiful day.');
expect(await writer.asyncToString(),
equals('hello, world. It is a beautiful day.'));
});
test('should concatenate multiple futures regardless of order.', () async {
var completer1 = new Completer<String>();
var completer2 = new Completer<String>();
var writer = new AsyncStringWriter();
writer.print('hello');
expect('$writer', equals('hello'));
writer.asyncPrint(completer1.future);
writer.asyncPrint(completer2.future);
completer2.complete(' It is a beautiful day.');
completer1.complete(', world.');
expect(await writer.asyncToString(),
equals('hello, world. It is a beautiful day.'));
});
test('should allow multiple "rounds" of `asyncPrint`.', () async {
var writer = new AsyncStringWriter();
writer.print('hello');
expect('$writer', equals('hello'));
writer.asyncPrint(new Future.value(', world.'));
expect(await writer.asyncToString(), equals('hello, world.'));
writer.asyncPrint(new Future.value(' It is '));
writer.asyncPrint(new Future.value('a beautiful '));
writer.asyncPrint(new Future.value('day.'));
expect(await writer.asyncToString(),
equals('hello, world. It is a beautiful day.'));
});
test('should handle calls to async methods while waiting.', () {
var completer1 = new Completer<String>();
var completer2 = new Completer<String>();
var writer = new AsyncStringWriter();
writer.print('hello');
expect('$writer', equals('hello'));
writer.asyncPrint(completer1.future);
var f1 = writer.asyncToString().then((result) {
expect(result, equals('hello, world.'));
});
writer.asyncPrint(completer2.future);
var f2 = writer.asyncToString().then((result) {
expect(result, equals('hello, world. It is a beautiful day.'));
});
completer1.complete(', world.');
completer2.complete(' It is a beautiful day.');
return Future.wait([f1, f2]);
});
test(
'should handle calls to async methods that complete in reverse '
'order while waiting.', () {
var completer1 = new Completer<String>();
var completer2 = new Completer<String>();
var writer = new AsyncStringWriter();
writer.print('hello');
expect('$writer', equals('hello'));
writer.asyncPrint(completer1.future);
var f1 = writer.asyncToString().then((result) {
expect(result, equals('hello, world.'));
});
writer.asyncPrint(completer2.future);
var f2 = writer.asyncToString().then((result) {
expect(result, equals('hello, world. It is a beautiful day.'));
});
completer2.complete(' It is a beautiful day.');
completer1.complete(', world.');
return Future.wait([f1, f2]);
});
}

View File

@ -1,70 +0,0 @@
library angular2.test.transform.common.code.ng_deps_code_tests;
import 'package:analyzer/analyzer.dart';
import 'package:test/test.dart';
import 'package:angular2/src/transform/common/code/ng_deps_code.dart';
import 'package:angular2/src/transform/common/model/import_export_model.pb.dart';
import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart';
main() => allTests();
void allTests() {
group('writeNgDepsModel', () {
test('should output parsable code', () async {
final ngDeps = new NgDepsModel()
..libraryUri = 'test.foo'
..imports.add(new ImportModel()
..uri = 'bar.dart'
..prefix = 'dep');
final buf = new StringBuffer();
final writer = new NgDepsWriter(buf);
writer.writeNgDepsModel(ngDeps, '');
var compilationUnit = parseCompilationUnit(buf.toString());
expect(compilationUnit, isNotNull);
expect(compilationUnit.declarations, isNotNull);
expect(compilationUnit.declarations.length > 0, isTrue);
});
test('should output parsable code with deferred imports', () async {
// Regression test for i/4587.
final ngDeps = new NgDepsModel()
..libraryUri = 'test.foo'
..imports.add(new ImportModel()
..uri = 'bar.dart'
..isDeferred = true
..prefix = 'dep');
final buf = new StringBuffer();
final writer = new NgDepsWriter(buf);
writer.writeNgDepsModel(ngDeps, '');
var compilationUnit = parseCompilationUnit(buf.toString());
expect(compilationUnit, isNotNull);
expect(compilationUnit.declarations, isNotNull);
expect(compilationUnit.declarations.length > 0, isTrue);
});
test('should add the given templateSource', () async {
final ngDeps = new NgDepsModel()
..libraryUri = 'test.foo'
..imports.add(new ImportModel()
..uri = 'bar.dart'
..prefix = 'dep');
final buf = new StringBuffer();
final writer = new NgDepsWriter(buf);
writer.writeNgDepsModel(ngDeps, 'import \'foo.dart\';\nvar x = true;');
var compilationUnit = parseCompilationUnit(buf.toString());
expect(compilationUnit, isNotNull);
expect(compilationUnit.declarations, isNotNull);
expect(compilationUnit.declarations.length > 0, isTrue);
});
});
}

View File

@ -1,26 +0,0 @@
library angular2.test.transform.common.compile_directive_metadata;
final ngFor = {
"NgFor": {
"kind": "type",
"value": {
"class": "Directive",
"isComponent": false,
"selector": "[ngFor][ngForOf]",
"exportAs": null,
"type": {
"id": 9999,
"name": "NgFor",
"moduleUrl": "asset:angular2/lib/src/common/directives/ng_for.dart"
},
"changeDetection": null,
"inputs": {"ngForOf": "ngForOf"},
"outputs": {},
"hostListeners": {},
"hostProperties": {},
"hostAttributes": {},
"lifecycleHooks": [2],
"template": null
}
}
};

View File

@ -1,84 +0,0 @@
library angular2.test.transform.common.ng_meta_helper;
import 'package:angular2/src/compiler/compile_metadata.dart';
import 'package:angular2/src/core/change_detection/change_detection.dart';
import 'package:angular2/src/core/metadata/view.dart' show ViewEncapsulation;
export 'package:angular2/src/compiler/compile_metadata.dart';
export 'package:angular2/src/core/change_detection/change_detection.dart';
export 'package:angular2/src/core/metadata/view.dart' show ViewEncapsulation;
export 'package:angular2/src/transform/common/model/annotation_model.pb.dart';
export 'package:angular2/src/transform/common/model/import_export_model.pb.dart';
export 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart';
export 'package:angular2/src/transform/common/model/reflection_info_model.pb.dart';
export 'package:angular2/src/transform/common/ng_meta.dart';
CompileDirectiveMetadata createComponentMetadataForTest(
{String name: 'TestMetadata',
moduleUrl: 'asset:angular2/test/test.dart',
selector: '[test]',
String template: 'Test'}) {
return createDirectiveMetadataForTest(
name: name,
moduleUrl: moduleUrl,
selector: selector,
template: new CompileTemplateMetadata(
encapsulation: ViewEncapsulation.Emulated, template: template));
}
CompilePipeMetadata createPipeMetadataForTest(
{String name: 'TestPipe',
moduleUrl: 'asset:angular2/test/test.dart',
String pipeName: 'test',
bool pure: false}) {
return new CompilePipeMetadata(
type: new CompileTypeMetadata(name: name, moduleUrl: moduleUrl),
name: pipeName,
pure: pure);
}
CompileDirectiveMetadata createDirectiveMetadataForTest(
{String name: 'TestMetadata',
String moduleUrl: 'asset:angular2/test/test.dart',
String selector: 'test',
CompileTemplateMetadata template: null}) {
return CompileDirectiveMetadata.create(
type: new CompileTypeMetadata(name: name, moduleUrl: moduleUrl),
isComponent: template != null,
selector: selector,
exportAs: null,
changeDetection: ChangeDetectionStrategy.Default,
inputs: [],
outputs: [],
host: {},
lifecycleHooks: [],
template: template);
}
CompileDirectiveMetadata createFoo([String moduleBase = 'asset:a']) =>
createComponentMetadataForTest(
name: 'FooComponent',
moduleUrl: '$moduleBase/export_cycle_files/foo.dart',
selector: 'foo',
template: 'Foo');
CompileDirectiveMetadata createBar([String moduleBase = 'asset:a']) =>
createComponentMetadataForTest(
name: 'BarComponent',
moduleUrl: '$moduleBase/export_cycle_files/bar.dart',
selector: 'bar',
template: 'Bar');
CompilePipeMetadata createBarPipe([String moduleBase = 'asset:a']) =>
createPipeMetadataForTest(
name: 'BarPipe',
pipeName: 'bar',
moduleUrl: '$moduleBase/export_cycle_files/bar.dart',
pure: false);
CompileDirectiveMetadata createBaz([String moduleBase = 'asset:a']) =>
createComponentMetadataForTest(
name: 'BazComponent',
moduleUrl: '$moduleBase/export_cycle_files/baz.dart',
selector: 'baz',
template: 'Baz');

View File

@ -1,158 +0,0 @@
library angular2.test.transform.common.annotation_matcher_test;
import 'package:test/test.dart';
import 'package:angular2/src/core/render/api.dart';
import 'package:angular2/src/compiler/compile_metadata.dart';
import 'package:angular2/src/transform/common/ng_meta.dart';
main() => allTests();
void allTests() {
var mockDirMetadata = [
CompileDirectiveMetadata.create(type: new CompileTypeMetadata(name: 'N1')),
CompileDirectiveMetadata.create(type: new CompileTypeMetadata(name: 'N2')),
CompileDirectiveMetadata.create(type: new CompileTypeMetadata(name: 'N3')),
CompileDirectiveMetadata.create(type: new CompileTypeMetadata(name: 'N4'))
];
test('should allow empty data.', () {
var ngMeta = new NgMeta.empty();
expect(ngMeta.isEmpty, isTrue);
});
group('serialization', () {
test('should parse empty data correctly.', () {
var ngMeta = new NgMeta.fromJson({});
expect(ngMeta.isEmpty, isTrue);
});
test('should be lossless', () {
var a = new NgMeta.empty();
a.identifiers['T0'] = mockDirMetadata[0];
a.identifiers['T1'] = mockDirMetadata[1];
a.identifiers['T2'] = mockDirMetadata[2];
a.identifiers['T3'] = mockDirMetadata[3];
a.aliases['a1'] = ['T1'];
a.aliases['a2'] = ['a1'];
a.aliases['a3'] = ['T3', 'a2'];
a.aliases['a4'] = ['a3', 'T3'];
_checkSimilar(a, new NgMeta.fromJson(a.toJson()));
});
});
group('flatten', () {
test('should include recursive aliases.', () {
var a = new NgMeta.empty();
a.identifiers['T0'] = mockDirMetadata[0];
a.identifiers['T1'] = mockDirMetadata[1];
a.identifiers['T2'] = mockDirMetadata[2];
a.identifiers['T3'] = mockDirMetadata[3];
a.aliases['a1'] = ['T1'];
a.aliases['a2'] = ['a1'];
a.aliases['a3'] = ['T3', 'a2'];
a.aliases['a4'] = ['a3', 'T0'];
expect(a.flatten('a4'),
equals([mockDirMetadata[3], mockDirMetadata[1], mockDirMetadata[0]]));
});
test('should detect cycles.', () {
var a = new NgMeta.empty();
a.identifiers['T0'] = mockDirMetadata[0];
a.aliases['a1'] = ['T0', 'a2'];
a.aliases['a2'] = ['a1'];
expect(
() => a.flatten('a1'),
throwsA(predicate((ex) =>
new RegExp('Cycle: a1 -> a2 -> a1.').hasMatch(ex.message))));
});
test('should allow duplicates.', () {
var a = new NgMeta.empty();
a.identifiers['T0'] = mockDirMetadata[0];
a.aliases['a1'] = ['T0', 'a2'];
a.aliases['a2'] = ['T0'];
expect(() => a.flatten('a1'), returnsNormally);
});
});
group('merge', () {
test('should merge all identifiers on addAll', () {
var a = new NgMeta.empty();
var b = new NgMeta.empty();
a.identifiers['T0'] = mockDirMetadata[0];
b.identifiers['T1'] = mockDirMetadata[1];
a.addAll(b);
expect(a.identifiers, contains('T1'));
expect(a.identifiers['T1'], equals(mockDirMetadata[1]));
});
test('should merge all aliases on addAll', () {
var a = new NgMeta.empty();
var b = new NgMeta.empty();
a.aliases['a'] = ['x'];
b.aliases['b'] = ['y'];
a.addAll(b);
expect(a.aliases, contains('b'));
expect(a.aliases['b'], equals(['y']));
});
});
group('needsResolution', () {
test('should be true if there is a provider', () {
var a = new NgMeta.empty();
a.identifiers["MyIdentifier"] = new CompileIdentifierMetadata(name: 'MyIdentifier', value: new CompileProviderMetadata());
expect(a.needsResolution, isTrue);
});
test('should be true if there is an injectable service', () {
var a = new NgMeta.empty();
a.identifiers["MyIdentifier"] = new CompileTypeMetadata();
expect(a.needsResolution, isTrue);
});
test('should be true if there is an directive', () {
var a = new NgMeta.empty();
a.identifiers["MyIdentifier"] = new CompileDirectiveMetadata();
expect(a.needsResolution, isTrue);
});
test('should be true if there is a pipe', () {
var a = new NgMeta.empty();
a.identifiers["MyIdentifier"] = new CompilePipeMetadata();
expect(a.needsResolution, isTrue);
});
test('should be true if there is a factory', () {
var a = new NgMeta.empty();
a.identifiers["MyIdentifier"] = new CompileFactoryMetadata();
expect(a.needsResolution, isTrue);
});
test('should be false otherwise', () {
var a = new NgMeta.empty();
a.identifiers["MyIdentifier"] = "some value";
expect(a.needsResolution, isFalse);
});
});
}
_checkSimilar(NgMeta a, NgMeta b) {
expect(a.identifiers.length, equals(b.identifiers.length));
expect(a.aliases.length, equals(b.aliases.length));
for (var k in a.identifiers.keys) {
expect(b.identifiers, contains(k));
var at = a.identifiers[k];
var bt = b.identifiers[k];
expect(at.type.name, equals(bt.type.name));
}
for (var k in a.aliases.keys) {
expect(b.aliases, contains(k));
expect(b.aliases[k], equals(a.aliases[k]));
}
}

View File

@ -1,51 +0,0 @@
library angular2.test.transform.common.read_file;
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:barback/barback.dart';
/// Smooths over differences in CWD between IDEs and running tests in Travis.
String readFile(String path) {
for (var myPath in [path, 'test/transform/${path}']) {
var file = new File(myPath);
if (file.existsSync()) {
return file.readAsStringSync();
}
}
return null;
}
class TestAssetReader implements AssetReader {
/// This allows "faking"
final Map<AssetId, String> _overrideAssets = <AssetId, String>{};
Future<String> readAsString(AssetId id, {Encoding encoding}) {
if (_overrideAssets.containsKey(id)) {
return new Future.value(_overrideAssets[id]);
} else {
return new Future.value(readFile(id.path));
}
}
Future<bool> hasInput(AssetId id) {
var exists = _overrideAssets.containsKey(id);
if (exists) return new Future.value(true);
for (var myPath in [id.path, 'test/transform/${id.path}']) {
var file = new File(myPath);
exists = exists || file.existsSync();
}
return new Future.value(exists);
}
void clear() {
this._overrideAssets.clear();
}
void addAsset(AssetId id, String contents) {
_overrideAssets[id] = contents;
}
}

View File

@ -1,27 +0,0 @@
library angular2.test.transform.common.recording_logger;
import 'package:barback/barback.dart';
import 'package:source_span/source_span.dart';
class RecordingLogger implements TransformLogger {
bool hasErrors = false;
List<String> logs = [];
void _record(prefix, msg) => logs.add('$prefix: $msg');
@override
void info(msg, {AssetId asset, SourceSpan span}) => _record('INFO', msg);
@override
void fine(msg, {AssetId asset, SourceSpan span}) => _record('FINE', msg);
@override
void warning(msg, {AssetId asset, SourceSpan span}) => _record('WARN', msg);
@override
void error(msg, {AssetId asset, SourceSpan span}) {
hasErrors = true;
_record('ERROR', msg);
}
}

View File

@ -1,9 +0,0 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library angular2.test.transform;
/// Mocked out version of {@link ReflectionCapabilities}, defined in
/// src/core/reflection/reflection_capabilities.dart. Importing the actual file in
/// tests causes issues with resolution due to transitive dependencies.
class ReflectionCapabilities {}

View File

@ -1,149 +0,0 @@
library angular2.test.transform.common.url_resolver_tests;
import 'package:barback/barback.dart';
import 'package:test/test.dart';
import 'package:angular2/src/transform/common/url_resolver.dart';
main() => allTests();
void allTests() {
var urlResolver = createOfflineCompileUrlResolver();
group('toAssetUri', () {
test('should convert `AssetId`s to asset: uris', () {
var assetId = new AssetId('test_package', 'lib/src/impl.dart');
expect(
toAssetUri(assetId), equals('asset:test_package/lib/src/impl.dart'));
});
test('should throw if passed a null AssetId', () {
expect(() => toAssetUri(null), throwsArgumentError);
});
});
group('fromUri', () {
test('should convert asset: `uri`s to `AssetId`s', () {
expect(fromUri('asset:test_package/lib/src/impl.dart'),
equals(new AssetId('test_package', 'lib/src/impl.dart')));
});
test('should convert package: `uri`s to `AssetId`s', () {
expect(fromUri('package:test_package/src/impl.dart'),
equals(new AssetId('test_package', 'lib/src/impl.dart')));
});
test('should throw if passed a null uri', () {
expect(() => fromUri(null), throwsArgumentError);
});
test('should throw if passed an empty uri', () {
expect(() => fromUri(''), throwsArgumentError);
});
});
group('isDartCoreUri', () {
test('should detect dart: uris', () {
expect(isDartCoreUri('dart:core'), isTrue);
expect(isDartCoreUri('dart:convert'), isTrue);
expect(isDartCoreUri('package:angular2/angular2.dart'), isFalse);
expect(isDartCoreUri('asset:angular2/lib/angular2.dart'), isFalse);
});
test('should throw if passed a null uri', () {
expect(() => isDartCoreUri(null), throwsArgumentError);
});
test('should throw if passed an empty uri', () {
expect(() => isDartCoreUri(''), throwsArgumentError);
});
});
group('toAssetScheme', () {
test('should throw for relative `Uri`s', () {
expect(() => toAssetScheme(Uri.parse('/lib/src/file.dart')),
throwsArgumentError);
});
test('should convert package: `Uri`s to asset:', () {
expect(toAssetScheme(Uri.parse('package:angular2/angular2.dart')),
equals(Uri.parse('asset:angular2/lib/angular2.dart')));
});
test('should throw for package: `Uri`s which are too short', () {
expect(() => toAssetScheme(Uri.parse('package:angular2')),
throwsFormatException);
});
test('should convert asset: `Uri`s to asset:', () {
expect(toAssetScheme(Uri.parse('asset:angular2/lib/angular2.dart')),
equals(Uri.parse('asset:angular2/lib/angular2.dart')));
});
test('should throw for asset: `Uri`s which are too short', () {
expect(() => toAssetScheme(Uri.parse('asset:angular2')),
throwsFormatException);
expect(() => toAssetScheme(Uri.parse('asset:angular2/lib')),
throwsFormatException);
});
test('should pass through unsupported schemes', () {
var uri = 'http://server.com/style.css';
expect('${toAssetScheme(Uri.parse(uri))}', equals(uri));
});
test('should throw if passed a null uri', () {
expect(() => toAssetScheme(null), throwsArgumentError);
});
});
group('resolve', () {
test('should resolve package: uris to asset: uris', () {
expect(urlResolver.resolve('', 'package:angular2/angular2.dart'),
equals('asset:angular2/lib/angular2.dart'));
});
test('should ignore baseUrl for absolute uris', () {
expect(urlResolver.resolve(null, 'package:angular2/angular2.dart'),
equals('asset:angular2/lib/angular2.dart'));
expect(urlResolver.resolve(null, 'asset:angular2/lib/angular2.dart'),
equals('asset:angular2/lib/angular2.dart'));
});
test('should resolve asset: uris to asset: uris', () {
expect(urlResolver.resolve('', 'asset:angular2/lib/angular2.dart'),
equals('asset:angular2/lib/angular2.dart'));
});
test('should resolve relative uris when baseUrl is package: uri', () {
expect(
urlResolver.resolve('package:angular2/angular2.dart',
'src/transform/transformer.dart'),
equals('asset:angular2/lib/src/transform/transformer.dart'));
});
test('should resolve relative uris when baseUrl is asset: uri', () {
expect(
urlResolver.resolve('asset:angular2/lib/angular2.dart',
'src/transform/transformer.dart'),
equals('asset:angular2/lib/src/transform/transformer.dart'));
});
test('should normalize uris', () {
expect(
urlResolver.resolve('asset:angular2/lib/angular2.dart',
'src/transform/../transform/transformer.dart'),
equals('asset:angular2/lib/src/transform/transformer.dart'));
expect(
urlResolver.resolve('asset:angular2/lib/src/../angular2.dart',
'src/transform/transformer.dart'),
equals('asset:angular2/lib/src/transform/transformer.dart'));
});
test('should gracefully handle an empty uri', () {
expect(urlResolver.resolve('package:angular2/angular2.dart', ''),
equals('asset:angular2/lib/angular2.dart'));
});
});
}

View File

@ -1,62 +0,0 @@
library angular2.test.transform.deferred_rewriter.all_tests;
import 'package:barback/barback.dart';
import 'package:dart_style/dart_style.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
import 'package:angular2/src/transform/common/zone.dart' as zone;
import 'package:angular2/src/transform/deferred_rewriter/transformer.dart';
import '../common/read_file.dart';
import '../common/recording_logger.dart';
var formatter = new DartFormatter();
main() {
allTests();
}
void allTests() {
_testRewriteDeferredLibraries(
'should return null when no deferred libraries found.',
'no_deferred_libraries/index.dart');
_testRewriteDeferredLibraries(
'should return null when deferred libraries with no ng_deps.',
'no_ng_deps_libraries/index.dart');
_testRewriteDeferredLibraries(
'should rewrite deferred libraries with ng_deps.',
'simple_deferred_example/index.dart');
_testRewriteDeferredLibraries(
'should not rewrite deferred libraries without ng_deps.',
'deferred_example_no_ng_deps/index.dart');
_testRewriteDeferredLibraries(
'should rewrite deferred libraries with ng_deps leave other deferred library alone.',
'complex_deferred_example/index.dart');
}
void _testRewriteDeferredLibraries(String name, String inputPath) {
test(name, () {
return zone.exec(() async {
var inputId = _assetIdForPath(inputPath);
var reader = new TestAssetReader();
var expectedPath = path.join(
path.dirname(inputPath), 'expected', path.basename(inputPath));
var expectedId = _assetIdForPath(expectedPath);
var actualOutput = await rewriteDeferredLibraries(reader, inputId);
var expectedOutput = await reader.readAsString(expectedId);
if (expectedOutput == null) {
// Null expectedOutput signals no output. Ensure that is true.
expect(actualOutput, isNull);
} else {
expect(actualOutput, isNotNull);
expect(formatter.format(actualOutput),
equals(formatter.format(expectedOutput)));
}
}, log: new RecordingLogger());
});
}
AssetId _assetIdForPath(String path) =>
new AssetId('angular2', 'test/transform/deferred_rewriter/$path');

View File

@ -1,17 +0,0 @@
library web_foo;
import 'package:angular2/src/core/application.dart';
import 'package:angular2/src/core/reflection/reflection.dart';
import 'package:angular2/src/core/reflection/reflection_capabilities.dart';
import 'hello.ngfactory.dart' deferred as a; // ng_deps. Should be rewritten.
import 'b.dart' deferred as b; // No ng_deps. Shouldn't be rewritten.
void main() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
a.loadLibrary().then((_) {
a.initReflector();
}).then((_) {
bootstrap(a.HelloCmp);
});
b.loadLibrary();
}

View File

@ -1,8 +0,0 @@
library playground.src.hello_world.absolute_url_expression_files;
import 'package:angular2/angular2.dart'
show bootstrap, Component, Directive, View, NgElement;
@Component(selector: 'hello-app')
@View(templateUrl: 'package:other_package/template.html')
class HelloCmp {}

View File

@ -1,32 +0,0 @@
{
"HelloCmp":
{
"kind": "type",
"value": {
"class": "Directive",
"isComponent": true,
"selector":"hello-app",
"exportAs": null,
"type": {
"id": 1,
"name": "HelloCmp",
"moduleUrl": "asset:angular2/test/transform/deferred_rewriter/complex_deferred_example/hello.dart"
},
"changeDetection": 5,
"inputs": {},
"outputs": {},
"hostListeners": {},
"hostProperties": {},
"hostAttributes": {},
"lifecycleHooks": [],
"template": {
"encapsulation": 0,
"template": "Hi",
"templateUrl": "package:other_package/template.html",
"styles": null,
"styleUrls": null,
"ngContentSelectors": null
}
}
}
}

View File

@ -1,15 +0,0 @@
library web_foo;
import 'package:angular2/src/core/application.dart';
import 'package:angular2/src/core/reflection/reflection.dart';
import 'package:angular2/src/core/reflection/reflection_capabilities.dart';
import 'hello.dart' deferred as a; // ng_deps. Should be rewritten.
import 'b.dart' deferred as b; // No ng_deps. Shouldn't be rewritten.
void main() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
a.loadLibrary().then((_) {
bootstrap(a.HelloCmp);
});
b.loadLibrary();
}

View File

@ -1,8 +0,0 @@
library playground.src.hello_world.absolute_url_expression_files;
import 'package:angular2/angular2.dart'
show bootstrap, Component, Directive, View, NgElement;
@Component(selector: 'hello-app')
@View(templateUrl: 'package:other_package/template.html')
class HelloCmp {}

View File

@ -1,13 +0,0 @@
library web_foo;
import 'package:angular2/src/core/application.dart';
import 'package:angular2/src/core/reflection/reflection.dart';
import 'package:angular2/src/core/reflection/reflection_capabilities.dart';
import 'hello.dart' deferred as a;
void main() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
a.loadLibrary().then((_) {
bootstrap(a.HelloCmp);
});
}

View File

@ -1,10 +0,0 @@
library web_foo;
import 'package:angular2/src/core/application.dart';
import 'package:angular2/src/core/reflection/reflection.dart';
import 'package:angular2/src/core/reflection/reflection_capabilities.dart';
void main() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
bootstrap(MyComponent);
}

View File

@ -1,11 +0,0 @@
library web_foo;
import 'package:angular2/src/core/application.dart';
import 'package:angular2/src/core/reflection/reflection.dart';
import 'package:angular2/src/core/reflection/reflection_capabilities.dart';
import 'a.dart' deferred as a;
void main() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
bootstrap(MyComponent);
}

View File

@ -1,15 +0,0 @@
library web_foo;
import 'package:angular2/src/core/application.dart';
import 'package:angular2/src/core/reflection/reflection.dart';
import 'package:angular2/src/core/reflection/reflection_capabilities.dart';
import 'hello.ngfactory.dart' deferred as a;
void main() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
a.loadLibrary().then((_) {
a.initReflector();
}).then((_) {
bootstrap(a.HelloCmp);
});
}

View File

@ -1,8 +0,0 @@
library playground.src.hello_world.absolute_url_expression_files;
import 'package:angular2/angular2.dart'
show bootstrap, Component, Directive, View, NgElement;
@Component(selector: 'hello-app')
@View(templateUrl: 'package:other_package/template.html')
class HelloCmp {}

View File

@ -1,32 +0,0 @@
{
"HelloCmp":
{
"kind": "type",
"value": {
"class": "Directive",
"isComponent": true,
"selector":"hello-app",
"exportAs": null,
"type": {
"id": 1,
"name": "HelloCmp",
"moduleUrl": "asset:angular2/test/transform/deferred_rewriter/simple_deferred_example/hello.dart"
},
"changeDetection": 5,
"inputs": {},
"outputs": {},
"hostListeners": {},
"hostProperties": {},
"hostAttributes": {},
"lifecycleHooks": [],
"template": {
"encapsulation": 0,
"template": "Hi",
"templateUrl": "package:other_package/template.html",
"styles": null,
"styleUrls": null,
"ngContentSelectors": null
}
}
}
}

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