Index: observatory_pub_packages/code_transformers/src/resolvers.dart |
=================================================================== |
--- observatory_pub_packages/code_transformers/src/resolvers.dart (revision 0) |
+++ observatory_pub_packages/code_transformers/src/resolvers.dart (working copy) |
@@ -0,0 +1,124 @@ |
+// Copyright (c) 2014, 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 code_transformers.src.resolvers; |
+ |
+import 'dart:async'; |
+import 'package:barback/barback.dart'; |
+ |
+import 'package:analyzer/src/generated/engine.dart' show AnalysisOptions; |
+import 'package:analyzer/src/generated/sdk.dart' show DartSdk; |
+import 'package:analyzer/src/generated/source.dart' show DartUriResolver; |
+ |
+import 'entry_point.dart'; |
+import 'resolver.dart'; |
+import 'resolver_impl.dart'; |
+import 'dart_sdk.dart' hide dartSdkDirectory; |
+ |
+/// Barback-based code resolvers which maintains up-to-date resolved ASTs for |
+/// the specified code entry points. |
+/// |
+/// This can used by transformers dependent on resolved ASTs to handle the |
+/// resolution of the AST and cache the results between compilations. |
+/// |
+/// If multiple transformers rely on a resolved AST they should (ideally) share |
+/// the same Resolvers object to minimize re-parsing the AST. |
+class Resolvers { |
+ final Map<AssetId, Resolver> _resolvers = {}; |
+ final DartSdk dartSdk; |
+ final DartUriResolver dartUriResolver; |
+ final AnalysisOptions options; |
+ |
+ Resolvers.fromSdk(this.dartSdk, this.dartUriResolver, {this.options}); |
+ |
+ factory Resolvers(dartSdkDirectory, {AnalysisOptions options}) { |
+ var sdk = new DirectoryBasedDartSdkProxy(dartSdkDirectory); |
+ var uriResolver = new DartUriResolverProxy(sdk); |
+ return new Resolvers.fromSdk(sdk, uriResolver, options: options); |
+ } |
+ |
+ factory Resolvers.fromMock(Map<String, String> sources, |
+ {bool reportMissing: false, AnalysisOptions options}) { |
+ var sdk = new MockDartSdk(sources, reportMissing: reportMissing); |
+ return new Resolvers.fromSdk(sdk, sdk.resolver, options: options); |
+ } |
+ |
+ /// Get a resolver for [transform]. If provided, this resolves the code |
+ /// starting from each of the assets in [entryPoints]. If not, this resolves |
+ /// the code starting from `transform.primaryInput.id` by default. |
+ /// |
+ /// [Resolver.release] must be called once it's done being used, or |
+ /// [ResolverTransformer] should be used to automatically release the |
+ /// resolver. |
+ Future<Resolver> get(Transform transform, [List<AssetId> entryPoints]) { |
+ var id = transform.primaryInput.id; |
+ var resolver = _resolvers.putIfAbsent(id, |
+ () => new ResolverImpl(dartSdk, dartUriResolver, options: options)); |
+ return resolver.resolve(transform, entryPoints); |
+ } |
+} |
+ |
+/// Transformer mixin which automatically gets and releases resolvers. |
+/// |
+/// To use mix this class in, set the resolvers field and override |
+/// [applyResolver]. |
+abstract class ResolverTransformer implements Transformer { |
+ /// The cache of resolvers- must be set from subclass. |
+ Resolvers resolvers; |
+ |
+ /// By default only process prossible entry point assets. |
+ /// |
+ /// This is only a preliminary check based on the asset ID. |
+ Future<bool> isPrimary(assetOrId) { |
+ // assetOrId is to handle the transition from Asset to AssetID between |
+ // pub 1.3 and 1.4. Once support for 1.3 is dropped this should only |
+ // support AssetId. |
+ var id = assetOrId is AssetId ? assetOrId : assetOrId.id; |
+ return new Future.value(isPossibleDartEntryId(id)); |
+ } |
+ |
+ /// Check to see if this should apply with the resolver on the provided asset. |
+ /// |
+ /// By default this will only apply on possible Dart entry points (see |
+ /// [isPossibleDartEntry]). |
+ Future<bool> shouldApplyResolver(Asset asset) => isPossibleDartEntry(asset); |
+ |
+ |
+ /// This provides a default implementation of `Transformer.apply` that will |
+ /// get and release resolvers automatically. Internally this: |
+ /// * Gets a resolver associated with the transform primary input. |
+ /// * Does resolution to the code starting from that input. |
+ /// * Calls [applyResolver]. |
+ /// * Then releases the resolver. |
+ /// |
+ /// Use [applyToEntryPoints] instead if you need to override the entry points |
+ /// to run the resolver on. |
+ Future apply(Transform transform) => |
+ shouldApplyResolver(transform.primaryInput).then((result) { |
+ if (result) return applyToEntryPoints(transform); |
+ }); |
+ |
+ |
+ /// Helper function to make it easy to write an `Transformer.apply` method |
+ /// that automatically gets and releases the resolver. This is typically used |
+ /// as follows: |
+ /// |
+ /// Future apply(Transform transform) { |
+ /// var entryPoints = ...; // compute entry points |
+ /// return applyToEntryPoints(transform, entryPoints); |
+ /// } |
+ Future applyToEntryPoints(Transform transform, [List<AssetId> entryPoints]) { |
+ return resolvers.get(transform, entryPoints).then((resolver) { |
+ return new Future(() => applyResolver(transform, resolver)) |
+ .whenComplete(() { |
+ resolver.release(); |
+ }); |
+ }); |
+ } |
+ |
+ /// Invoked when the resolver is ready to be processed. |
+ /// |
+ /// Return a Future to indicate when apply is completed. |
+ applyResolver(Transform transform, Resolver resolver); |
+} |