| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library barback.transform_node; | 5 library barback.transform_node; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'asset.dart'; | 9 import 'asset.dart'; |
| 10 import 'asset_id.dart'; | 10 import 'asset_id.dart'; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 /// A string describing the location of [this] in the transformer graph. | 37 /// A string describing the location of [this] in the transformer graph. |
| 38 final String _location; | 38 final String _location; |
| 39 | 39 |
| 40 /// The subscription to [primary]'s [AssetNode.onStateChange] stream. | 40 /// The subscription to [primary]'s [AssetNode.onStateChange] stream. |
| 41 StreamSubscription _primarySubscription; | 41 StreamSubscription _primarySubscription; |
| 42 | 42 |
| 43 /// The subscription to [phase]'s [Phase.onAsset] stream. | 43 /// The subscription to [phase]'s [Phase.onAsset] stream. |
| 44 StreamSubscription<AssetNode> _phaseSubscription; | 44 StreamSubscription<AssetNode> _phaseSubscription; |
| 45 | 45 |
| 46 /// Whether [this] is dirty and still has more processing to do. | 46 /// Whether [this] is dirty and still has more processing to do. |
| 47 bool get isDirty => !_state.isDone; | 47 bool get isDirty => _state != _State.NOT_PRIMARY && _state != _State.APPLIED; |
| 48 | 48 |
| 49 /// Whether [transformer] is lazy and this transform has yet to be forced. | 49 /// Whether [transformer] is lazy and this transform has yet to be forced. |
| 50 bool _isLazy; | 50 bool _isLazy; |
| 51 | 51 |
| 52 /// The subscriptions to each input's [AssetNode.onStateChange] stream. | 52 /// The subscriptions to each input's [AssetNode.onStateChange] stream. |
| 53 final _inputSubscriptions = new Map<AssetId, StreamSubscription>(); | 53 final _inputSubscriptions = new Map<AssetId, StreamSubscription>(); |
| 54 | 54 |
| 55 /// The controllers for the asset nodes emitted by this node. | 55 /// The controllers for the asset nodes emitted by this node. |
| 56 final _outputControllers = new Map<AssetId, AssetNodeController>(); | 56 final _outputControllers = new Map<AssetId, AssetNodeController>(); |
| 57 | 57 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 83 | 83 |
| 84 /// A stream that emits an event whenever this transform logs an entry. | 84 /// A stream that emits an event whenever this transform logs an entry. |
| 85 /// | 85 /// |
| 86 /// This is synchronous because error logs can cause the transform to fail, so | 86 /// This is synchronous because error logs can cause the transform to fail, so |
| 87 /// we need to ensure that their processing isn't delayed until after the | 87 /// we need to ensure that their processing isn't delayed until after the |
| 88 /// transform or build has finished. | 88 /// transform or build has finished. |
| 89 Stream<LogEntry> get onLog => _onLogPool.stream; | 89 Stream<LogEntry> get onLog => _onLogPool.stream; |
| 90 final _onLogPool = new StreamPool<LogEntry>.broadcast(); | 90 final _onLogPool = new StreamPool<LogEntry>.broadcast(); |
| 91 | 91 |
| 92 /// The current state of [this]. | 92 /// The current state of [this]. |
| 93 var _state = _TransformNodeState.PROCESSING; | 93 var _state = _State.COMPUTING_IS_PRIMARY; |
| 94 | 94 |
| 95 /// Whether [this] has been marked as removed. | 95 /// Whether [this] has been marked as removed. |
| 96 bool get _isRemoved => _onAssetController.isClosed; | 96 bool get _isRemoved => _onAssetController.isClosed; |
| 97 | 97 |
| 98 /// Whether the most recent run of this transform has declared that it | 98 /// Whether the most recent run of this transform has declared that it |
| 99 /// consumes the primary input. | 99 /// consumes the primary input. |
| 100 /// | 100 /// |
| 101 /// Defaults to `false`. This is not meaningful unless [_state] is | 101 /// Defaults to `false`. This is not meaningful unless [_state] is |
| 102 /// [_TransformNodeState.APPLIED]. | 102 /// [_State.APPLIED]. |
| 103 bool _consumePrimary = false; | 103 bool _consumePrimary = false; |
| 104 | 104 |
| 105 TransformNode(this.phase, Transformer transformer, this.primary, | 105 TransformNode(this.phase, Transformer transformer, this.primary, |
| 106 this._location) | 106 this._location) |
| 107 : transformer = transformer, | 107 : transformer = transformer, |
| 108 _isLazy = transformer is LazyTransformer { | 108 _isLazy = transformer is LazyTransformer { |
| 109 _primarySubscription = primary.onStateChange.listen((state) { | 109 _primarySubscription = primary.onStateChange.listen((state) { |
| 110 if (state.isRemoved) { | 110 if (state.isRemoved) { |
| 111 remove(); | 111 remove(); |
| 112 } else { | 112 } else { |
| 113 _dirty(primaryChanged: true); | 113 _dirty(); |
| 114 } | 114 } |
| 115 }); | 115 }); |
| 116 | 116 |
| 117 _phaseSubscription = phase.previous.onAsset.listen((node) { | 117 _phaseSubscription = phase.previous.onAsset.listen((node) { |
| 118 if (_missingInputs.contains(node.id)) _dirty(primaryChanged: false); | 118 if (_missingInputs.contains(node.id)) _dirty(); |
| 119 }); | 119 }); |
| 120 | 120 |
| 121 _process(); | 121 syncFuture(() => transformer.isPrimary(primary.id)) |
| 122 .catchError((error, stackTrace) { |
| 123 if (_isRemoved) return false; |
| 124 |
| 125 // Catch all transformer errors and pipe them to the results stream. This |
| 126 // is so a broken transformer doesn't take down the whole graph. |
| 127 phase.cascade.reportError(_wrapException(error, stackTrace)); |
| 128 |
| 129 return false; |
| 130 }).then((isPrimary) { |
| 131 if (_isRemoved) return; |
| 132 if (isPrimary) { |
| 133 _apply(); |
| 134 return; |
| 135 } |
| 136 |
| 137 _emitPassThrough(); |
| 138 _state = _State.NOT_PRIMARY; |
| 139 _onDoneController.add(null); |
| 140 }); |
| 122 } | 141 } |
| 123 | 142 |
| 124 /// The [TransformInfo] describing this node. | 143 /// The [TransformInfo] describing this node. |
| 125 /// | 144 /// |
| 126 /// [TransformInfo] is the publicly-visible representation of a transform | 145 /// [TransformInfo] is the publicly-visible representation of a transform |
| 127 /// node. | 146 /// node. |
| 128 TransformInfo get info => new TransformInfo(transformer, primary.id); | 147 TransformInfo get info => new TransformInfo(transformer, primary.id); |
| 129 | 148 |
| 130 /// Marks this transform as removed. | 149 /// Marks this transform as removed. |
| 131 /// | 150 /// |
| (...skipping 14 matching lines...) Expand all Loading... |
| 146 } | 165 } |
| 147 } | 166 } |
| 148 | 167 |
| 149 /// If [transformer] is lazy, ensures that its concrete outputs will be | 168 /// If [transformer] is lazy, ensures that its concrete outputs will be |
| 150 /// generated. | 169 /// generated. |
| 151 void force() { | 170 void force() { |
| 152 // TODO(nweiz): we might want to have a timeout after which, if the | 171 // TODO(nweiz): we might want to have a timeout after which, if the |
| 153 // transform's outputs have gone unused, we switch it back to lazy mode. | 172 // transform's outputs have gone unused, we switch it back to lazy mode. |
| 154 if (!_isLazy) return; | 173 if (!_isLazy) return; |
| 155 _isLazy = false; | 174 _isLazy = false; |
| 156 _dirty(primaryChanged: false); | 175 _dirty(); |
| 157 } | 176 } |
| 158 | 177 |
| 159 /// Marks this transform as dirty. | 178 /// Marks this transform as dirty. |
| 160 /// | 179 /// |
| 161 /// This causes all of the transform's outputs to be marked as dirty as well. | 180 /// This causes all of the transform's outputs to be marked as dirty as well. |
| 162 /// [primaryChanged] should be true if and only if [this] was set dirty | 181 void _dirty() { |
| 163 /// because [primary] changed. | 182 if (_state == _State.COMPUTING_IS_PRIMARY) return; |
| 164 void _dirty({bool primaryChanged: false}) { | 183 if (_state == _State.NOT_PRIMARY) { |
| 165 if (!primaryChanged && _state.isNotPrimary) return; | 184 _emitPassThrough(); |
| 185 return; |
| 186 } |
| 166 | 187 |
| 167 if (_passThroughController != null) _passThroughController.setDirty(); | 188 if (_passThroughController != null) _passThroughController.setDirty(); |
| 168 for (var controller in _outputControllers.values) { | 189 for (var controller in _outputControllers.values) { |
| 169 controller.setDirty(); | 190 controller.setDirty(); |
| 170 } | 191 } |
| 171 | 192 |
| 172 if (_state.isDone) { | 193 if (_state == _State.APPLIED) { |
| 173 if (primaryChanged) { | 194 _apply(); |
| 174 _process(); | 195 } else { |
| 175 } else { | 196 _state = _State.NEEDS_APPLY; |
| 176 _apply(); | |
| 177 } | |
| 178 } else if (primaryChanged) { | |
| 179 _state = _TransformNodeState.NEEDS_IS_PRIMARY; | |
| 180 } else if (!_state.needsIsPrimary) { | |
| 181 _state = _TransformNodeState.NEEDS_APPLY; | |
| 182 } | 197 } |
| 183 } | 198 } |
| 184 | 199 |
| 185 /// Determines whether [primary] is primary for [transformer], and if so runs | |
| 186 /// [transformer.apply]. | |
| 187 void _process() { | |
| 188 // Clear all the old input subscriptions. If an input is re-used, we'll | |
| 189 // re-subscribe. | |
| 190 _clearInputSubscriptions(); | |
| 191 _state = _TransformNodeState.PROCESSING; | |
| 192 primary.whenAvailable((_) { | |
| 193 _state = _TransformNodeState.PROCESSING; | |
| 194 return transformer.isPrimary(primary.asset); | |
| 195 }).catchError((error, stackTrace) { | |
| 196 // If the transform became dirty while processing, ignore any errors from | |
| 197 // it. | |
| 198 if (_state.needsIsPrimary || _isRemoved) return false; | |
| 199 | |
| 200 // Catch all transformer errors and pipe them to the results stream. This | |
| 201 // is so a broken transformer doesn't take down the whole graph. | |
| 202 phase.cascade.reportError(_wrapException(error, stackTrace)); | |
| 203 | |
| 204 return false; | |
| 205 }).then((isPrimary) { | |
| 206 if (_isRemoved) return; | |
| 207 if (_state.needsIsPrimary) { | |
| 208 _process(); | |
| 209 } else if (isPrimary) { | |
| 210 _apply(); | |
| 211 } else { | |
| 212 _clearOutputs(); | |
| 213 _emitPassThrough(); | |
| 214 _state = _TransformNodeState.NOT_PRIMARY; | |
| 215 _onDoneController.add(null); | |
| 216 } | |
| 217 }); | |
| 218 } | |
| 219 | |
| 220 /// Applies this transform. | 200 /// Applies this transform. |
| 221 void _apply() { | 201 void _apply() { |
| 222 assert(!_onAssetController.isClosed); | 202 assert(!_isRemoved); |
| 223 | 203 |
| 224 // Clear input subscriptions here as well as in [_process] because [_apply] | 204 // Clear input subscriptions here as well as in [_process] because [_apply] |
| 225 // may be restarted independently if only a secondary input changes. | 205 // may be restarted independently if only a secondary input changes. |
| 226 _clearInputSubscriptions(); | 206 _clearInputSubscriptions(); |
| 227 _state = _TransformNodeState.PROCESSING; | 207 _state = _State.APPLYING; |
| 228 primary.whenAvailable((_) { | 208 primary.whenAvailable((_) { |
| 229 if (_state.needsIsPrimary) return null; | 209 if (_isRemoved) return null; |
| 230 _state = _TransformNodeState.PROCESSING; | 210 _state = _State.APPLYING; |
| 231 // TODO(nweiz): If [transformer] is a [DeclaringTransformer] but not a | 211 // TODO(nweiz): If [transformer] is a [DeclaringTransformer] but not a |
| 232 // [LazyTransformer], we can get some mileage out of doing a declarative | 212 // [LazyTransformer], we can get some mileage out of doing a declaration |
| 233 // first so we know how to hook up the assets. | 213 // first so we know how to hook up the assets. |
| 234 if (_isLazy) return _declareLazy(); | 214 if (_isLazy) return _declareLazy(); |
| 235 return _applyImmediate(); | 215 return _applyImmediate(); |
| 236 }).catchError((error, stackTrace) { | 216 }).catchError((error, stackTrace) { |
| 237 // If the transform became dirty while processing, ignore any errors from | 217 // If the transform became dirty while processing, ignore any errors from |
| 238 // it. | 218 // it. |
| 239 if (!_state.isProcessing || _isRemoved) return false; | 219 if (_state == _State.NEEDS_APPLY || _isRemoved) return false; |
| 240 | 220 |
| 241 // Catch all transformer errors and pipe them to the results stream. This | 221 // Catch all transformer errors and pipe them to the results stream. This |
| 242 // is so a broken transformer doesn't take down the whole graph. | 222 // is so a broken transformer doesn't take down the whole graph. |
| 243 phase.cascade.reportError(_wrapException(error, stackTrace)); | 223 phase.cascade.reportError(_wrapException(error, stackTrace)); |
| 244 return true; | 224 return true; |
| 245 }).then((hadError) { | 225 }).then((hadError) { |
| 246 if (_isRemoved) return; | 226 if (_isRemoved) return; |
| 247 | 227 |
| 248 if (_state.needsIsPrimary) { | 228 if (_state == _State.NEEDS_APPLY) { |
| 249 _process(); | |
| 250 } else if (_state.needsApply) { | |
| 251 _apply(); | 229 _apply(); |
| 252 } else { | 230 return; |
| 253 assert(_state.isProcessing); | 231 } |
| 254 if (hadError) { | |
| 255 _clearOutputs(); | |
| 256 _dontEmitPassThrough(); | |
| 257 } | |
| 258 | 232 |
| 259 _state = _TransformNodeState.APPLIED; | 233 assert(_state == _State.APPLYING); |
| 260 _onDoneController.add(null); | 234 if (hadError) { |
| 235 _clearOutputs(); |
| 236 _dontEmitPassThrough(); |
| 261 } | 237 } |
| 238 |
| 239 _state = _State.APPLIED; |
| 240 _onDoneController.add(null); |
| 262 }); | 241 }); |
| 263 } | 242 } |
| 264 | 243 |
| 265 /// Gets the asset for an input [id]. | 244 /// Gets the asset for an input [id]. |
| 266 /// | 245 /// |
| 267 /// If an input with [id] cannot be found, throws an [AssetNotFoundException]. | 246 /// If an input with [id] cannot be found, throws an [AssetNotFoundException]. |
| 268 Future<Asset> getInput(AssetId id) { | 247 Future<Asset> getInput(AssetId id) { |
| 269 return phase.previous.getOutput(id).then((node) { | 248 return phase.previous.getOutput(id).then((node) { |
| 270 // Throw if the input isn't found. This ensures the transformer's apply | 249 // Throw if the input isn't found. This ensures the transformer's apply |
| 271 // is exited. We'll then catch this and report it through the proper | 250 // is exited. We'll then catch this and report it through the proper |
| 272 // results stream. | 251 // results stream. |
| 273 if (node == null) { | 252 if (node == null) { |
| 274 _missingInputs.add(id); | 253 _missingInputs.add(id); |
| 275 throw new AssetNotFoundException(id); | 254 throw new AssetNotFoundException(id); |
| 276 } | 255 } |
| 277 | 256 |
| 278 _inputSubscriptions.putIfAbsent(node.id, () { | 257 _inputSubscriptions.putIfAbsent(node.id, () { |
| 279 return node.onStateChange.listen((_) => _dirty(primaryChanged: false)); | 258 return node.onStateChange.listen((_) => _dirty()); |
| 280 }); | 259 }); |
| 281 | 260 |
| 282 return node.asset; | 261 return node.asset; |
| 283 }); | 262 }); |
| 284 } | 263 } |
| 285 | 264 |
| 286 /// Applies the transform so that it produces concrete (as opposed to lazy) | 265 /// Applies the transform so that it produces concrete (as opposed to lazy) |
| 287 /// outputs. | 266 /// outputs. |
| 288 /// | 267 /// |
| 289 /// Returns whether or not the transformer logged an error. | 268 /// Returns whether or not the transformer logged an error. |
| 290 Future<bool> _applyImmediate() { | 269 Future<bool> _applyImmediate() { |
| 291 var transformController = new TransformController(this); | 270 var transformController = new TransformController(this); |
| 292 _onLogPool.add(transformController.onLog); | 271 _onLogPool.add(transformController.onLog); |
| 293 | 272 |
| 294 return syncFuture(() { | 273 return syncFuture(() { |
| 295 return transformer.apply(transformController.transform); | 274 return transformer.apply(transformController.transform); |
| 296 }).then((_) { | 275 }).then((_) { |
| 297 if (!_state.isProcessing || _onAssetController.isClosed) return false; | 276 if (_state == _State.NEEDS_APPLY || _isRemoved) return false; |
| 298 if (transformController.loggedError) return true; | 277 if (transformController.loggedError) return true; |
| 299 | 278 |
| 300 _consumePrimary = transformController.consumePrimary; | 279 _consumePrimary = transformController.consumePrimary; |
| 301 | 280 |
| 302 var newOutputs = transformController.outputs; | 281 var newOutputs = transformController.outputs; |
| 303 // Any ids that are for a different package are invalid. | 282 // Any ids that are for a different package are invalid. |
| 304 var invalidIds = newOutputs | 283 var invalidIds = newOutputs |
| 305 .map((asset) => asset.id) | 284 .map((asset) => asset.id) |
| 306 .where((id) => id.package != phase.cascade.package) | 285 .where((id) => id.package != phase.cascade.package) |
| 307 .toSet(); | 286 .toSet(); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 /// outputs. | 324 /// outputs. |
| 346 /// | 325 /// |
| 347 /// Returns whether or not the transformer logged an error. | 326 /// Returns whether or not the transformer logged an error. |
| 348 Future<bool> _declareLazy() { | 327 Future<bool> _declareLazy() { |
| 349 var transformController = new DeclaringTransformController(this); | 328 var transformController = new DeclaringTransformController(this); |
| 350 | 329 |
| 351 return syncFuture(() { | 330 return syncFuture(() { |
| 352 return (transformer as LazyTransformer) | 331 return (transformer as LazyTransformer) |
| 353 .declareOutputs(transformController.transform); | 332 .declareOutputs(transformController.transform); |
| 354 }).then((_) { | 333 }).then((_) { |
| 355 if (!_state.isProcessing || _onAssetController.isClosed) return false; | 334 if (_state == _State.NEEDS_APPLY || _isRemoved) return false; |
| 356 if (transformController.loggedError) return true; | 335 if (transformController.loggedError) return true; |
| 357 | 336 |
| 358 _consumePrimary = transformController.consumePrimary; | 337 _consumePrimary = transformController.consumePrimary; |
| 359 | 338 |
| 360 var newIds = transformController.outputIds; | 339 var newIds = transformController.outputIds; |
| 361 var invalidIds = | 340 var invalidIds = |
| 362 newIds.where((id) => id.package != phase.cascade.package).toSet(); | 341 newIds.where((id) => id.package != phase.cascade.package).toSet(); |
| 363 for (var id in invalidIds) { | 342 for (var id in invalidIds) { |
| 364 newIds.remove(id); | 343 newIds.remove(id); |
| 365 // TODO(nweiz): report this as a warning rather than a failing error. | 344 // TODO(nweiz): report this as a warning rather than a failing error. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 414 } | 393 } |
| 415 | 394 |
| 416 /// Emit the pass-through asset if it's not being emitted already. | 395 /// Emit the pass-through asset if it's not being emitted already. |
| 417 void _emitPassThrough() { | 396 void _emitPassThrough() { |
| 418 assert(!_outputControllers.containsKey(primary.id)); | 397 assert(!_outputControllers.containsKey(primary.id)); |
| 419 | 398 |
| 420 if (_consumePrimary) return; | 399 if (_consumePrimary) return; |
| 421 if (_passThroughController == null) { | 400 if (_passThroughController == null) { |
| 422 _passThroughController = new AssetNodeController.from(primary); | 401 _passThroughController = new AssetNodeController.from(primary); |
| 423 _onAssetController.add(_passThroughController.node); | 402 _onAssetController.add(_passThroughController.node); |
| 424 } else { | 403 } else if (primary.state.isDirty) { |
| 404 _passThroughController.setDirty(); |
| 405 } else if (!_passThroughController.node.state.isAvailable) { |
| 425 _passThroughController.setAvailable(primary.asset); | 406 _passThroughController.setAvailable(primary.asset); |
| 426 } | 407 } |
| 427 } | 408 } |
| 428 | 409 |
| 429 /// Stop emitting the pass-through asset if it's being emitted already. | 410 /// Stop emitting the pass-through asset if it's being emitted already. |
| 430 void _dontEmitPassThrough() { | 411 void _dontEmitPassThrough() { |
| 431 if (_passThroughController == null) return; | 412 if (_passThroughController == null) return; |
| 432 _passThroughController.setRemoved(); | 413 _passThroughController.setRemoved(); |
| 433 _passThroughController = null; | 414 _passThroughController = null; |
| 434 } | 415 } |
| 435 | 416 |
| 436 BarbackException _wrapException(error, StackTrace stackTrace) { | 417 BarbackException _wrapException(error, StackTrace stackTrace) { |
| 437 if (error is! AssetNotFoundException) { | 418 if (error is! AssetNotFoundException) { |
| 438 return new TransformerException(info, error, stackTrace); | 419 return new TransformerException(info, error, stackTrace); |
| 439 } else { | 420 } else { |
| 440 return new MissingInputException(info, error.id); | 421 return new MissingInputException(info, error.id); |
| 441 } | 422 } |
| 442 } | 423 } |
| 443 | 424 |
| 444 String toString() => | 425 String toString() => |
| 445 "transform node in $_location for $transformer on $primary"; | 426 "transform node in $_location for $transformer on $primary"; |
| 446 } | 427 } |
| 447 | 428 |
| 448 /// The enum of states that [TransformNode] can be in. | 429 /// The enum of states that [TransformNode] can be in. |
| 449 class _TransformNodeState { | 430 class _State { |
| 450 /// The transform node is running [Transformer.isPrimary] or | 431 /// The transform is running [Transformer.isPrimary]. |
| 451 /// [Transformer.apply] and doesn't need to re-run them. | |
| 452 /// | 432 /// |
| 453 /// If there are no external changes by the time the processing finishes, this | 433 /// This is the initial state of the transformer. Once [Transformer.isPrimary] |
| 454 /// will transition to [APPLIED] or [NOT_PRIMARY] depending on the result of | 434 /// finishes running, this will transition to [APPLYING] if the input is |
| 455 /// [Transformer.isPrimary]. If the primary input changes, this will | 435 /// primary, or [NOT_PRIMARY] if it's not. |
| 456 /// transition to [NEEDS_IS_PRIMARY]. If a secondary input changes, this will | 436 static final COMPUTING_IS_PRIMARY = const _State._("computing isPrimary"); |
| 457 /// transition to [NEEDS_APPLY]. | |
| 458 static final PROCESSING = const _TransformNodeState._("processing"); | |
| 459 | 437 |
| 460 /// The transform is running [Transformer.isPrimary] or [Transformer.apply], | 438 /// The transform is running [Transformer.apply]. |
| 461 /// but since it started the primary input changed, so it will need to re-run | |
| 462 /// [Transformer.isPrimary]. | |
| 463 /// | 439 /// |
| 464 /// This will always transition to [Transformer.PROCESSING]. | 440 /// If an input changes while in this state, it will transition to |
| 465 static final NEEDS_IS_PRIMARY = | 441 /// [NEEDS_APPLY]. If the [TransformNode] is still in this state when |
| 466 const _TransformNodeState._("needs isPrimary"); | 442 /// [Transformer.apply] finishes running, it will transition to [APPLIED]. |
| 443 static final APPLYING = const _State._("applying"); |
| 467 | 444 |
| 468 /// The transform is running [Transformer.apply], but since it started a | 445 /// The transform is running [Transformer.apply], but an input changed after |
| 469 /// secondary input changed, so it will need to re-run [Transformer.apply]. | 446 /// it started, so it will need to re-run [Transformer.apply]. |
| 470 /// | 447 /// |
| 471 /// If there are no external changes by the time [Transformer.apply] finishes, | 448 /// This will transition to [APPLYING] once [Transformer.apply] finishes |
| 472 /// this will transition to [PROCESSING]. If the primary input changes, this | 449 /// running. |
| 473 /// will transition to [NEEDS_IS_PRIMARY]. | 450 static final NEEDS_APPLY = const _State._("needs apply"); |
| 474 static final NEEDS_APPLY = const _TransformNodeState._("needs apply"); | |
| 475 | 451 |
| 476 /// The transform has finished running [Transformer.apply], whether or not it | 452 /// The transform has finished running [Transformer.apply], whether or not it |
| 477 /// emitted an error. | 453 /// emitted an error. |
| 478 /// | 454 /// |
| 479 /// If the primary input or a secondary input changes, this will transition to | 455 /// If an input changes, this will transition to [APPLYING]. |
| 480 /// [PROCESSING]. | 456 static final APPLIED = const _State._("applied"); |
| 481 static final APPLIED = const _TransformNodeState._("applied"); | |
| 482 | 457 |
| 483 /// The transform has finished running [Transformer.isPrimary], which returned | 458 /// The transform has finished running [Transformer.isPrimary], which returned |
| 484 /// `false`. | 459 /// `false`. |
| 485 /// | 460 /// |
| 486 /// If the primary input changes, this will transition to [PROCESSING]. | 461 /// This will never transition to another state. |
| 487 static final NOT_PRIMARY = const _TransformNodeState._("not primary"); | 462 static final NOT_PRIMARY = const _State._("not primary"); |
| 488 | |
| 489 /// Whether [this] is [PROCESSING]. | |
| 490 bool get isProcessing => this == _TransformNodeState.PROCESSING; | |
| 491 | |
| 492 /// Whether [this] is [NEEDS_IS_PRIMARY]. | |
| 493 bool get needsIsPrimary => this == _TransformNodeState.NEEDS_IS_PRIMARY; | |
| 494 | |
| 495 /// Whether [this] is [NEEDS_APPLY]. | |
| 496 bool get needsApply => this == _TransformNodeState.NEEDS_APPLY; | |
| 497 | |
| 498 /// Whether [this] is [APPLIED]. | |
| 499 bool get isApplied => this == _TransformNodeState.APPLIED; | |
| 500 | |
| 501 /// Whether [this] is [NOT_PRIMARY]. | |
| 502 bool get isNotPrimary => this == _TransformNodeState.NOT_PRIMARY; | |
| 503 | |
| 504 /// Whether the transform has finished running [Transformer.isPrimary] and | |
| 505 /// [Transformer.apply]. | |
| 506 /// | |
| 507 /// Specifically, whether [this] is [APPLIED] or [NOT_PRIMARY]. | |
| 508 bool get isDone => isApplied || isNotPrimary; | |
| 509 | 463 |
| 510 final String name; | 464 final String name; |
| 511 | 465 |
| 512 const _TransformNodeState._(this.name); | 466 const _State._(this.name); |
| 513 | 467 |
| 514 String toString() => name; | 468 String toString() => name; |
| 515 } | 469 } |
| OLD | NEW |