bind method

  1. @override
Stream<String> bind(
  1. Stream<String> stream
)
override

Transforms the provided stream.

Returns a new stream with events that are computed from events of the provided stream.

The StreamTransformer interface is completely generic, so it cannot say what subclasses do. Each StreamTransformer should document clearly how it transforms the stream (on the class or variable used to access the transformer), as well as any differences from the following typical behavior:

  • When the returned stream is listened to, it starts listening to the input stream.
  • Subscriptions of the returned stream forward (in a reasonable time) a StreamSubscription.pause call to the subscription of the input stream.
  • Similarly, canceling a subscription of the returned stream eventually (in reasonable time) cancels the subscription of the input stream.

"Reasonable time" depends on the transformer and stream. Some transformers, like a "timeout" transformer, might make these operations depend on a duration. Others might not delay them at all, or just by a microtask.

Transformers are free to handle errors in any way. A transformer implementation may choose to propagate errors, or convert them to other events, or ignore them completely, but if errors are ignored, it should be documented explicitly.

Implementation

@override
Stream<String> bind(Stream<String> stream) async* {
  var depth = 0;
  final header = StackTraceHeader();
  await for (final line in stream) {
    // If we successfully parse a header line, then we reset the depth to 0.
    if (header.tryParseHeaderLine(line, lossy: true)) {
      depth = 0;
      yield line;
      continue;
    }
    // If at any point we can't get appropriate information for the current
    // line as a stack trace line, then just pass the line through unchanged.
    final lineMatch = _traceLineRE.firstMatch(line);
    final offset = _retrievePCOffset(header, lineMatch);
    if (offset == null) {
      yield line;
      continue;
    }
    Dwarf dwarf = _dwarf;
    final unitId = offset.unitId;
    if (unitId != null && unitId != constants.rootLoadingUnitId) {
      Dwarf? unitDwarf;
      // Prefer the map that specifies loading unit IDs over the iterable.
      if (_dwarfByUnitId != null) {
        unitDwarf = _dwarfByUnitId![unitId];
      }
      if (unitDwarf == null &&
          _unitDwarfs != null &&
          offset.buildId != null) {
        for (final d in _unitDwarfs!) {
          if (d.buildId(offset.architecture) == offset.buildId) {
            unitDwarf = d;
          }
        }
      }
      // Don't attempt to translate if we couldn't find the correct debugging
      // information for this loading unit.
      if (unitDwarf == null) {
        yield line;
        continue;
      }
      dwarf = unitDwarf;
    }
    final callInfo = offset.callInfoFrom(dwarf,
        includeInternalFrames: _includeInternalFrames);
    if (callInfo == null) {
      yield line;
      continue;
    }
    // No lines to output (as this corresponds to Dart internals).
    if (callInfo.isEmpty) continue;
    // Output the lines for the symbolic frame with the prefix found on the
    // original non-symbolic frame line, modulo all whitespace between the
    // prefix and stack trace information converted to a single space.
    //
    // If there was no prefix, just swallow any initial whitespace, since
    // symbolic Dart stacktrace lines have no initial whitespace.
    String prefix = line.substring(0, lineMatch!.start);
    if (prefix.isNotEmpty) {
      prefix += ' ';
    }
    for (final call in callInfo) {
      yield prefix + _stackTracePiece(call, depth++);
    }
  }
}