prettyPrint function

String prettyPrint(
  1. Object? obj, {
  2. int indent = 0,
})

Recursively renders obj as an indented, human-readable string for debugging. Maps and lists are expanded over multiple lines; null becomes 'null' and any other value falls back to its toString(). indent sets the starting nesting depth (two spaces per level).

Example:

prettyPrint({'a': 1, 'b': [2, 3]});
// {
//   a: 1
//   b: [
//     2,
//     3
//   ]
// }

Audited: 2026-06-12 11:26 EDT

Implementation

String prettyPrint(Object? obj, {int indent = 0}) {
  const int spaces = 2;
  // `pad` indents the CLOSING brace/bracket (current level); `childPad` indents
  // the entries one level deeper. The old code prefixed entries with `pad`, so
  // every key/item was one level too shallow (top-level keys got no indent at
  // all, contradicting the documented output).
  final String pad = ' ' * (indent * spaces);
  final String childPad = ' ' * ((indent + 1) * spaces);
  if (obj == null) return 'null';
  if (obj is Map) {
    if (obj.isEmpty) return '{}';
    final List<String> parts = <String>[];
    for (final MapEntry<dynamic, dynamic> e in obj.entries) {
      parts.add('$childPad${e.key}: ${prettyPrint(e.value, indent: indent + 1)}');
    }
    return '{\n${parts.join('\n')}\n$pad}';
  }
  if (obj is List) {
    if (obj.isEmpty) return '[]';
    final List<String> parts = obj
        .map((Object? e) => '$childPad${prettyPrint(e, indent: indent + 1)}')
        .toList();
    return '[\n${parts.join(',\n')}\n$pad]';
  }
  return obj.toString();
}