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`.
|
* In GitHub, send a pull request to `angular:master`.
|
||||||
* If we suggest changes then:
|
* If we suggest changes then:
|
||||||
* Make the required updates.
|
* 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):
|
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
||||||
|
|
||||||
```shell
|
```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)
|
* [Prerequisite Software](#prerequisite-software)
|
||||||
* [Getting the Sources](#getting-the-sources)
|
* [Getting the Sources](#getting-the-sources)
|
||||||
* [Environment Variable Setup](#environment-variable-setup)
|
* [Installing NPM Modules](#installing-npm-modules)
|
||||||
* [Installing NPM Modules and Dart Packages](#installing-npm-modules-and-dart-packages)
|
|
||||||
* [Building](#building)
|
* [Building](#building)
|
||||||
* [Running Tests Locally](#running-tests-locally)
|
* [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
|
(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.
|
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
|
* [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.
|
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:
|
# Add the main Angular repository as an upstream remote to your repository:
|
||||||
git remote add upstream https://github.com/angular/angular.git
|
git remote add upstream https://github.com/angular/angular.git
|
||||||
```
|
```
|
||||||
|
## Installing NPM Modules
|
||||||
## 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
|
|
||||||
|
|
||||||
Next, install the JavaScript modules and Dart packages needed to build and test Angular:
|
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
|
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**.
|
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
|
[ng2]: http://angular.io
|
||||||
[ngDart]: http://angulardart.org
|
[ngDart]: http://angulardart.org
|
||||||
[ngJS]: http://angularjs.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