| // Copyright (c) 2021, 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. | |
| import 'dart:async'; | |
| import 'dart:convert'; | |
| /// Transforms a stream of bytes into strings whenever a newline is encountered. | |
| /// | |
| /// This is used to consume output of processes like the package:test JSON | |
| /// reporter where the stream data may be buffered and we need to process | |
| /// specific JSON packets that are sent on their own lines. | |
| class ByteToLineTransformer extends StreamTransformerBase<List<int>, String> { | |
| @override | |
| Stream<String> bind(Stream<List<int>> stream) { | |
| late StreamSubscription<int> input; | |
| late StreamController<String> output; | |
| final buffer = <int>[]; | |
| output = StreamController<String>( | |
| onListen: () { | |
| input = stream | |
| .expand((b) => b) | |
| .listen( | |
| (codeUnit) { | |
| buffer.add(codeUnit); | |
| if (_endsWithLf(buffer)) { | |
| output.add(utf8.decode(buffer)); | |
| buffer.clear(); | |
| } | |
| }, | |
| onError: output.addError, | |
| onDone: output.close, | |
| ); | |
| }, | |
| onPause: () => input.pause(), | |
| onResume: () => input.resume(), | |
| onCancel: () => input.cancel(), | |
| ); | |
| return output.stream; | |
| } | |
| /// Whether [buffer] ends in '\n'. | |
| static bool _endsWithLf(List<int> buffer) { | |
| return buffer.isNotEmpty && buffer.last == 10; | |
| } | |
| } |