Index: third_party/pkg/angular/lib/transformer.dart |
diff --git a/third_party/pkg/angular/lib/transformer.dart b/third_party/pkg/angular/lib/transformer.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3ea0837b16141f4a91bd531d90e3604f6f62467c |
--- /dev/null |
+++ b/third_party/pkg/angular/lib/transformer.dart |
@@ -0,0 +1,160 @@ |
+library angular.transformer; |
+ |
+import 'dart:async'; |
+import 'dart:io'; |
+import 'package:angular/tools/transformer/expression_generator.dart'; |
+import 'package:angular/tools/transformer/metadata_generator.dart'; |
+import 'package:angular/tools/transformer/static_angular_generator.dart'; |
+import 'package:angular/tools/transformer/html_dart_references_generator.dart'; |
+import 'package:angular/tools/transformer/options.dart'; |
+import 'package:barback/barback.dart'; |
+import 'package:code_transformers/resolver.dart'; |
+import 'package:di/transformer/injector_generator.dart' as di; |
+import 'package:di/transformer/options.dart' as di; |
+import 'package:path/path.dart' as path; |
+ |
+ |
+ /** |
+ * The Angular transformer, which internally runs several phases that will: |
+ * |
+ * * Extract all expressions for evaluation at runtime without using Mirrors. |
+ * * Extract all classes being dependency injected into a static injector. |
+ * * Extract all metadata for cached reflection. |
+ */ |
+class AngularTransformerGroup implements TransformerGroup { |
+ final Iterable<Iterable> phases; |
+ |
+ AngularTransformerGroup(TransformOptions options) |
+ : phases = _createPhases(options); |
+ |
+ AngularTransformerGroup.asPlugin(BarbackSettings settings) |
+ : this(_parseSettings(settings.configuration)); |
+} |
+ |
+TransformOptions _parseSettings(Map args) { |
+ // Default angular annotations for injectable types |
+ var annotations = [ |
+ 'angular.core.annotation_src.Injectable', |
+ 'angular.core.annotation_src.Decorator', |
+ 'angular.core.annotation_src.Controller', |
+ 'angular.core.annotation_src.Component', |
+ 'angular.core.annotation_src.Formatter']; |
+ annotations.addAll(_readStringListValue(args, 'injectable_annotations')); |
+ |
+ // List of types which are otherwise not indicated as being injectable. |
+ var injectedTypes = [ |
+ 'perf_api.Profiler', |
+ ]; |
+ injectedTypes.addAll(_readStringListValue(args, 'injected_types')); |
+ |
+ var sdkDir = _readStringValue(args, 'dart_sdk', required: false); |
+ if (sdkDir == null) { |
+ // Assume the Pub executable is always coming from the SDK. |
+ sdkDir = path.dirname(path.dirname(Platform.executable)); |
+ } |
+ |
+ var diOptions = new di.TransformOptions( |
+ injectableAnnotations: annotations, |
+ injectedTypes: injectedTypes, |
+ sdkDirectory: sdkDir); |
+ |
+ return new TransformOptions( |
+ htmlFiles: _readStringListValue(args, 'html_files'), |
+ sdkDirectory: sdkDir, |
+ templateUriRewrites: _readStringMapValue(args, 'template_uri_rewrites'), |
+ diOptions: diOptions); |
+} |
+ |
+_readStringValue(Map args, String name, {bool required: true}) { |
+ var value = args[name]; |
+ if (value == null) { |
+ if (required) { |
+ print('Angular transformer parameter "$name" ' |
+ 'has no value in pubspec.yaml.'); |
+ } |
+ return null; |
+ } |
+ if (value is! String) { |
+ print('Angular transformer parameter "$name" value ' |
+ 'is not a string in pubspec.yaml.'); |
+ return null; |
+ } |
+ return value; |
+} |
+ |
+_readStringListValue(Map args, String name) { |
+ var value = args[name]; |
+ if (value == null) return []; |
+ var results = []; |
+ bool error; |
+ if (value is List) { |
+ results = value; |
+ error = value.any((e) => e is! String); |
+ } else if (value is String) { |
+ results = [value]; |
+ error = false; |
+ } else { |
+ error = true; |
+ } |
+ if (error) { |
+ print('Angular transformer parameter "$name" ' |
+ 'has an invalid value in pubspec.yaml.'); |
+ } |
+ return results; |
+} |
+ |
+Map<String, String> _readStringMapValue(Map args, String name) { |
+ var value = args[name]; |
+ if (value == null) return {}; |
+ if (value is! Map) { |
+ print('Angular transformer parameter "$name" ' |
+ 'is expected to be a map parameter.'); |
+ return {}; |
+ } |
+ if (value.keys.any((e) => e is! String) || |
+ value.values.any((e) => e is! String)) { |
+ print('Angular transformer parameter "$name" ' |
+ 'is expected to be a map of strings.'); |
+ return {}; |
+ } |
+ return value; |
+} |
+ |
+List<List<Transformer>> _createPhases(TransformOptions options) { |
+ var resolvers = new Resolvers(options.sdkDirectory); |
+ return [ |
+ [new HtmlDartReferencesGenerator(options)], |
+ [new _SerialTransformer([ |
+ new ExpressionGenerator(options, resolvers), |
+ new di.InjectorGenerator(options.diOptions, resolvers), |
+ new MetadataGenerator(options, resolvers), |
+ new StaticAngularGenerator(options, resolvers) |
+ ])] |
+ ]; |
+} |
+ |
+/// Helper which runs a group of transformers serially and ensures that |
+/// transformers with shared data are always applied in a specific order. |
+/// |
+/// Transformers which communicate only via assets do not need this additional |
+/// synchronization. |
+/// |
+/// This is used by Angular to ensure ordering of references to the cached |
+/// resolvers. |
+class _SerialTransformer extends Transformer { |
+ final Iterable<Transformer> _transformers; |
+ _SerialTransformer(this._transformers); |
+ |
+ Future<bool> isPrimary(Asset input) => |
+ Future.wait(_transformers.map((t) => t.isPrimary(input))) |
+ .then((l) => l.any((result) => result)); |
+ |
+ Future apply(Transform transform) { |
+ return Future.forEach(_transformers, (t) { |
+ return new Future.value(t.isPrimary(transform.primaryInput)) |
+ .then((isPrimary) { |
+ if (isPrimary) return t.apply(transform); |
+ }); |
+ }); |
+ } |
+} |