treeify function

String treeify(
  1. TreeNode obj, {
  2. TreeifyOptions options = const TreeifyOptions(),
})

Render a tree node as a string.

Implementation

String treeify(
  TreeNode obj, {
  TreeifyOptions options = const TreeifyOptions(),
}) {
  if (obj.isEmpty) return '(empty)';

  final lines = <String>[];
  final visited = <Object>{};

  void growBranch(dynamic node, String prefix, bool isLast, {int depth = 0}) {
    if (node is String) {
      lines.add('$prefix$node');
      return;
    }

    if (node is! Map<String, dynamic>) {
      if (options.showValues) {
        lines.add('$prefix$node');
      }
      return;
    }

    if (visited.contains(node)) {
      lines.add('$prefix[Circular]');
      return;
    }
    visited.add(node);

    final keys = node.keys.toList();
    for (var index = 0; index < keys.length; index++) {
      final key = keys[index];
      final value = node[key];
      final isLastKey = index == keys.length - 1;
      final nodePrefix = depth == 0 && index == 0 ? '' : prefix;

      final treeChar = isLastKey ? _treeLastBranch : _treeBranch;
      final formattedKey = key.trim().isEmpty ? '' : key;

      var line =
          '$nodePrefix$treeChar${formattedKey.isNotEmpty ? ' $formattedKey' : ''}';
      final shouldAddColon = key.trim().isNotEmpty;

      if (value is Map<String, dynamic> && visited.contains(value)) {
        lines.add(
          '$line${shouldAddColon
              ? ': '
              : line.isNotEmpty
              ? ' '
              : ''}[Circular]',
        );
      } else if (value is Map<String, dynamic>) {
        lines.add(line);
        final continuationChar = isLastKey ? _treeEmpty : _treeLine;
        final nextPrefix = '$nodePrefix$continuationChar ';
        growBranch(value, nextPrefix, isLastKey, depth: depth + 1);
      } else if (value is List) {
        lines.add(
          '$line${shouldAddColon
              ? ': '
              : line.isNotEmpty
              ? ' '
              : ''}[Array(${value.length})]',
        );
      } else if (options.showValues) {
        final valueStr = '$value';
        line +=
            '${shouldAddColon
                ? ': '
                : line.isNotEmpty
                ? ' '
                : ''}$valueStr';
        lines.add(line);
      } else {
        lines.add(line);
      }
    }
  }

  // Special case for single whitespace key
  if (obj.length == 1) {
    final key = obj.keys.first;
    if (key.trim().isEmpty && obj[key] is String) {
      return '$_treeLastBranch ${obj[key]}';
    }
  }

  growBranch(obj, '', true);
  return lines.join('\n');
}