Index: sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart |
diff --git a/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart b/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart |
index 4d736c8fd905869e42cc518d0297d435835fb328..b2c8464d451cdf4467f9eb0902cc6eeb8efa3797 100644 |
--- a/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart |
+++ b/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart |
@@ -5,6 +5,7 @@ |
library pub.load_transformers; |
import 'dart:async'; |
+import 'dart:convert'; |
import 'dart:isolate'; |
import 'package:barback/barback.dart'; |
@@ -21,15 +22,19 @@ import '../utils.dart'; |
const _TRANSFORMER_ISOLATE = """ |
import 'dart:async'; |
import 'dart:isolate'; |
+import 'dart:convert'; |
import 'dart:mirrors'; |
import 'http://localhost:<<PORT>>/packages/barback/barback.dart'; |
/// Sets up the initial communication with the host isolate. |
void main() { |
- port.receive((uri, replyTo) { |
+ port.receive((args, replyTo) { |
_sendFuture(replyTo, new Future.sync(() { |
- return initialize(Uri.parse(uri)).map(_serializeTransformer).toList(); |
+ var library = Uri.parse(args['library']); |
+ var configuration = JSON.decode(args['configuration']); |
+ return initialize(library, configuration). |
+ map(_serializeTransformer).toList(); |
})); |
}); |
} |
@@ -37,8 +42,8 @@ void main() { |
/// Loads all the transformers defined in [uri] and adds them to [transformers]. |
/// |
/// We then load the library, find any Transformer subclasses in it, instantiate |
-/// them, and return them. |
-Iterable<Transformer> initialize(Uri uri) { |
+/// them (with [configuration] if it's non-null), and return them. |
+Iterable<Transformer> initialize(Uri uri, Map configuration) { |
var mirrors = currentMirrorSystem(); |
// TODO(nweiz): look this up by name once issue 5897 is fixed. |
var transformerUri = Uri.parse( |
@@ -46,17 +51,30 @@ Iterable<Transformer> initialize(Uri uri) { |
var transformerClass = mirrors.libraries[transformerUri] |
.classes[const Symbol('Transformer')]; |
- return mirrors.libraries[uri].classes.values.where((classMirror) { |
- if (classMirror.isPrivate) return false; |
- if (isAbstract(classMirror)) return false; |
- if (!classIsA(classMirror, transformerClass)) return false; |
- var constructor = classMirror.constructors[classMirror.simpleName]; |
- if (constructor == null) return false; |
- if (!constructor.parameters.isEmpty) return false; |
- return true; |
- }).map((classMirror) { |
- return classMirror.newInstance(const Symbol(''), []).reflectee; |
- }); |
+ // TODO(nweiz): if no valid transformers are found, throw an error message |
+ // describing candidates and why they were rejected. |
+ return mirrors.libraries[uri].classes.values.map((classMirror) { |
+ if (classMirror.isPrivate) return null; |
+ if (isAbstract(classMirror)) return null; |
+ if (!classIsA(classMirror, transformerClass)) return null; |
+ |
+ var constructor = getConstructor(classMirror, 'asPlugin'); |
+ if (constructor == null) return null; |
+ if (constructor.parameters.isEmpty) { |
+ if (configuration != null) return null; |
+ return classMirror.newInstance(const Symbol('asPlugin'), []).reflectee; |
+ } |
+ if (constructor.parameters.length != 1) return null; |
+ |
+ // If the constructor expects configuration and none was passed, it defaults |
+ // to an empty map. |
+ if (configuration == null) configuration = {}; |
+ |
+ // TODO(nweiz): if the constructor accepts named parameters, automatically |
+ // destructure the configuration map. |
+ return classMirror.newInstance(const Symbol('asPlugin'), [configuration]) |
+ .reflectee; |
+ }).where((classMirror) => classMirror != null); |
} |
/// A wrapper for a [Transform] that's in the host isolate. |
@@ -107,6 +125,13 @@ ClassMirror get objectMirror { |
} |
ClassMirror _objectMirror; |
+// TODO(nweiz): clean this up when issue 13248 is fixed. |
+MethodMirror getConstructor(ClassMirror classMirror, String constructor) { |
+ var name = new Symbol("\${MirrorSystem.getName(classMirror.simpleName)}" |
+ ".\$constructor"); |
+ return classMirror.constructors[name]; |
+} |
+ |
// TODO(nweiz): get rid of this when issue 12439 is fixed. |
/// Returns whether or not [mirror] is a subtype of [superclass]. |
/// |
@@ -256,23 +281,28 @@ String getErrorMessage(error) { |
} |
"""; |
-/// Load and return all transformers from the library identified by [library]. |
+/// Load and return all transformers from the library identified by [id]. |
/// |
-/// [server] is used to serve [library] and any Dart files it imports. |
+/// [server] is used to serve any Dart files needed to load the transformer. |
Future<Set<Transformer>> loadTransformers(BarbackServer server, |
- AssetId library) { |
- var path = library.path.replaceFirst('lib/', ''); |
+ TransformerId id) { |
+ var path = id.asset.path.replaceFirst('lib/', ''); |
// TODO(nweiz): load from a "package:" URI when issue 12474 is fixed. |
- var uri = 'http://localhost:${server.port}/packages/${library.package}/$path'; |
+ var uri = 'http://localhost:${server.port}/packages/${id.asset.package}/' |
+ '$path'; |
var code = 'import "$uri";' + |
_TRANSFORMER_ISOLATE.replaceAll('<<PORT>>', server.port.toString()); |
- log.fine("Loading transformers from $library"); |
+ log.fine("Loading transformers from ${id.asset}"); |
return dart.runInIsolate(code).then((sendPort) { |
- return _receiveFuture(sendPort.call(uri)).then((transformers) { |
+ return _receiveFuture(sendPort.call({ |
+ 'library': uri, |
+ // TODO(nweiz): support non-JSON-encodable configuration maps. |
+ 'configuration': JSON.encode(id.configuration) |
+ })).then((transformers) { |
transformers = transformers |
.map((transformer) => new _ForeignTransformer(transformer)) |
.toSet(); |
- log.fine("Transformers from $library: $transformers"); |
+ log.fine("Transformers from ${id.asset}: $transformers"); |
return transformers; |
}); |
}).catchError((error) { |
@@ -287,7 +317,7 @@ Future<Set<Transformer>> loadTransformers(BarbackServer server, |
// If there was an IsolateSpawnException and the import that actually failed |
// was the one we were loading transformers from, throw an application |
// exception with a more user-friendly message. |
- fail('Transformer library "package:${library.package}/$path" not found.'); |
+ fail('Transformer library "package:${id.asset.package}/$path" not found.'); |
}); |
} |