treeify function
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');
}