chore(Dart): remove obsolete files, update the docs
This commit is contained in:
parent
51f3d22e4f
commit
e73ac1e992
|
@ -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
|
||||
|
|
49
DEVELOPER.md
49
DEVELOPER.md
|
@ -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 pub’s 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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
376
TOOLS_DART.md
376
TOOLS_DART.md
|
@ -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 -->
|
|
@ -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`.
|
|
@ -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`.
|
|
@ -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();
|
|
@ -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
|
|
@ -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');
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
<span>from external template</span>
|
|
@ -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
|
|
@ -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";
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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});
|
||||
}
|
|
@ -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(')');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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('}');
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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)');
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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)}.';
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 }
|
|
@ -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)
|
||||
*/
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
*/
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
*/
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
*/
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
*/
|
|
@ -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;
|
||||
}
|
|
@ -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';
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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(', ')}].');
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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: ...''';
|
File diff suppressed because it is too large
Load Diff
|
@ -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:');
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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}';
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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}''';";
|
||||
}
|
||||
}
|
|
@ -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();';
|
||||
}
|
||||
}
|
|
@ -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)";
|
|
@ -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));
|
||||
}
|
|
@ -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);';
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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';
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
library angular2.transformer_dart;
|
||||
|
||||
export 'src/transform/transformer.dart';
|
|
@ -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'
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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]);
|
||||
});
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
};
|
|
@ -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');
|
|
@ -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]));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 {}
|
|
@ -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'));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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');
|
|
@ -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();
|
||||
}
|
|
@ -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 {}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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 {}
|
|
@ -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);
|
||||
});
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
}
|
|
@ -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 {}
|
|
@ -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
Loading…
Reference in New Issue