defaultStackFilter method

Iterable<String> defaultStackFilter (Iterable<String> frames)

Converts a stack to a string that is more readable by omitting stack frames that correspond to Dart internals.

This is the default filter used by dumpErrorToConsole if the FlutterErrorDetails object has no FlutterErrorDetails.stackFilter callback.

This function expects its input to be in the format used by StackTrace.toString(). The output of this function is similar to that format but the frame numbers will not be consecutive (frames are elided) and the final line may be prose rather than a stack frame.

Implementation

static Iterable<String> defaultStackFilter(Iterable<String> frames) {
  const List<String> filteredPackages = <String>[
    'dart:async-patch',
    'dart:async',
    'package:stack_trace',
  ];
  const List<String> filteredClasses = <String>[
    '_AssertionError',
    '_FakeAsync',
    '_FrameCallbackEntry',
  ];
  final RegExp stackParser = RegExp(r'^#[0-9]+ +([^.]+).* \(([^/\\]*)[/\\].+:[0-9]+(?::[0-9]+)?\)$');
  final RegExp packageParser = RegExp(r'^([^:]+):(.+)$');
  final List<String> result = <String>[];
  final List<String> skipped = <String>[];
  for (String line in frames) {
    final Match match = stackParser.firstMatch(line);
    if (match != null) {
      assert(match.groupCount == 2);
      if (filteredPackages.contains(match.group(2))) {
        final Match packageMatch = packageParser.firstMatch(match.group(2));
        if (packageMatch != null && packageMatch.group(1) == 'package') {
          skipped.add('package ${packageMatch.group(2)}'); // avoid "package package:foo"
        } else {
          skipped.add('package ${match.group(2)}');
        }
        continue;
      }
      if (filteredClasses.contains(match.group(1))) {
        skipped.add('class ${match.group(1)}');
        continue;
      }
    }
    result.add(line);
  }
  if (skipped.length == 1) {
    result.add('(elided one frame from ${skipped.single})');
  } else if (skipped.length > 1) {
    final List<String> where = Set<String>.from(skipped).toList()..sort();
    if (where.length > 1)
      where[where.length - 1] = 'and ${where.last}';
    if (where.length > 2) {
      result.add('(elided ${skipped.length} frames from ${where.join(", ")})');
    } else {
      result.add('(elided ${skipped.length} frames from ${where.join(" ")})');
    }
  }
  return result;
}