OLD | NEW |
| (Empty) |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library barback.transformer.aggregate_transform; | |
6 | |
7 import 'dart:async'; | |
8 import 'dart:convert'; | |
9 | |
10 import '../asset/asset.dart'; | |
11 import '../asset/asset_id.dart'; | |
12 import '../asset/asset_set.dart'; | |
13 import '../errors.dart'; | |
14 import '../graph/transform_node.dart'; | |
15 import '../utils.dart'; | |
16 import 'base_transform.dart'; | |
17 | |
18 /// A transform for [AggregateTransformer]s that provides access to all of their | |
19 /// primary inputs. | |
20 class AggregateTransform extends BaseTransform { | |
21 final TransformNode _node; | |
22 | |
23 /// The set of outputs emitted by the transformer. | |
24 final _outputs = new AssetSet(); | |
25 | |
26 /// The transform key. | |
27 /// | |
28 /// This is the key returned by [AggregateTransformer.classifyPrimary] for all | |
29 /// the assets in this transform. | |
30 String get key => _node.key; | |
31 | |
32 /// The package in which this transform is running. | |
33 String get package => _node.phase.cascade.package; | |
34 | |
35 /// The stream of primary inputs that will be processed by this transform. | |
36 /// | |
37 /// This is exposed as a stream so that the transformer can start working | |
38 /// before all its inputs are available. The stream is closed not just when | |
39 /// all inputs are provided, but when barback is confident no more inputs will | |
40 /// be forthcoming. | |
41 /// | |
42 /// A transformer may complete its `apply` method before this stream is | |
43 /// closed. For example, it may know that each key will only have two inputs | |
44 /// associated with it, and so use `transform.primaryInputs.take(2)` to access | |
45 /// only those inputs. | |
46 Stream<Asset> get primaryInputs => _inputController.stream; | |
47 final _inputController = new StreamController<Asset>(); | |
48 | |
49 /// The set of all primary inputs that have been emitted by [primaryInputs]. | |
50 /// | |
51 /// This is populated by the transform's controller so that | |
52 /// [AggregateTransformController.addedId] synchronously returns the correct | |
53 /// result after [AggregateTransformController.addInput] is called. | |
54 final _emittedPrimaryInputs = new AssetSet(); | |
55 | |
56 AggregateTransform._(TransformNode node) | |
57 : _node = node, | |
58 super(node); | |
59 | |
60 /// Gets the asset for an input [id]. | |
61 /// | |
62 /// If an input with [id] cannot be found, throws an [AssetNotFoundException]. | |
63 Future<Asset> getInput(AssetId id) { | |
64 if (_emittedPrimaryInputs.containsId(id)) { | |
65 return syncFuture(() => _emittedPrimaryInputs[id]); | |
66 } else { | |
67 return _node.getInput(id); | |
68 } | |
69 } | |
70 | |
71 /// A convenience method to the contents of the input with [id] as a string. | |
72 /// | |
73 /// This is equivalent to calling [getInput] followed by [Asset.readAsString]. | |
74 /// | |
75 /// If the asset was created from a [String] the original string is always | |
76 /// returned and [encoding] is ignored. Otherwise, the binary data of the | |
77 /// asset is decoded using [encoding], which defaults to [UTF8]. | |
78 /// | |
79 /// If an input with [id] cannot be found, throws an [AssetNotFoundException]. | |
80 Future<String> readInputAsString(AssetId id, {Encoding encoding}) { | |
81 if (encoding == null) encoding = UTF8; | |
82 return getInput(id).then((input) => input.readAsString(encoding: encoding)); | |
83 } | |
84 | |
85 /// A convenience method to the contents of the input with [id]. | |
86 /// | |
87 /// This is equivalent to calling [getInput] followed by [Asset.read]. | |
88 /// | |
89 /// If the asset was created from a [String], this returns its UTF-8 encoding. | |
90 /// | |
91 /// If an input with [id] cannot be found, throws an [AssetNotFoundException]. | |
92 Stream<List<int>> readInput(AssetId id) => | |
93 futureStream(getInput(id).then((input) => input.read())); | |
94 | |
95 /// A convenience method to return whether or not an asset exists. | |
96 /// | |
97 /// This is equivalent to calling [getInput] and catching an | |
98 /// [AssetNotFoundException]. | |
99 Future<bool> hasInput(AssetId id) { | |
100 return getInput(id).then((_) => true).catchError((error) { | |
101 if (error is AssetNotFoundException && error.id == id) return false; | |
102 throw error; | |
103 }); | |
104 } | |
105 | |
106 /// Stores [output] as the output created by this transformation. | |
107 /// | |
108 /// A transformation can output as many assets as it wants. | |
109 void addOutput(Asset output) { | |
110 // TODO(rnystrom): This should immediately throw if an output with that ID | |
111 // has already been created by this transformer. | |
112 _outputs.add(output); | |
113 } | |
114 | |
115 void consumePrimary(AssetId id) { | |
116 if (!_emittedPrimaryInputs.containsId(id)) { | |
117 throw new StateError( | |
118 "$id can't be consumed because it's not a primary input."); | |
119 } | |
120 | |
121 super.consumePrimary(id); | |
122 } | |
123 } | |
124 | |
125 /// The controller for [AggregateTransform]. | |
126 class AggregateTransformController extends BaseTransformController { | |
127 AggregateTransform get transform => super.transform; | |
128 | |
129 /// The set of assets that the transformer has emitted. | |
130 AssetSet get outputs => transform._outputs; | |
131 | |
132 bool get isDone => transform._inputController.isClosed; | |
133 | |
134 AggregateTransformController(TransformNode node) | |
135 : super(new AggregateTransform._(node)); | |
136 | |
137 /// Adds a primary input asset to the [AggregateTransform.primaryInputs] | |
138 /// stream. | |
139 void addInput(Asset input) { | |
140 transform._emittedPrimaryInputs.add(input); | |
141 transform._inputController.add(input); | |
142 } | |
143 | |
144 /// Returns whether an input with the given [id] was added via [addInput]. | |
145 bool addedId(AssetId id) => | |
146 transform._emittedPrimaryInputs.containsId(id); | |
147 | |
148 void done() { | |
149 transform._inputController.close(); | |
150 } | |
151 } | |
OLD | NEW |