UNPKG

3.54 kBJavaScriptView Raw
1// treeify.js
2// Luke Plaster <notatestuser@gmail.com>
3// https://github.com/notatestuser/treeify.js
4
5// do the universal module definition dance
6(function (root, factory) {
7
8 if (typeof exports === 'object') {
9 module.exports = factory();
10 } else if (typeof define === 'function' && define.amd) {
11 define(factory);
12 } else {
13 root.treeify = factory();
14 }
15
16}(this, function() {
17
18 function makePrefix(key, last) {
19 var str = (last ? '└' : '├');
20 if (key) {
21 str += '─ ';
22 } else {
23 str += '──┐';
24 }
25 return str;
26 }
27
28 function filterKeys(obj, hideFunctions) {
29 var keys = [];
30 for (var branch in obj) {
31 // always exclude anything in the object's prototype
32 if (!obj.hasOwnProperty(branch)) {
33 continue;
34 }
35 // ... and hide any keys mapped to functions if we've been told to
36 if (hideFunctions && ((typeof obj[branch])==="function")) {
37 continue;
38 }
39 keys.push(branch);
40 }
41 return keys;
42 }
43
44 function growBranch(key, root, last, lastStates, showValues, hideFunctions, callback) {
45 var line = '', index = 0, lastKey, circular, lastStatesCopy = lastStates.slice(0);
46
47 if (lastStatesCopy.push([ root, last ]) && lastStates.length > 0) {
48 // based on the "was last element" states of whatever we're nested within,
49 // we need to append either blankness or a branch to our line
50 lastStates.forEach(function(lastState, idx) {
51 if (idx > 0) {
52 line += (lastState[1] ? ' ' : '│') + ' ';
53 }
54 if ( ! circular && lastState[0] === root) {
55 circular = true;
56 }
57 });
58
59 // the prefix varies based on whether the key contains something to show and
60 // whether we're dealing with the last element in this collection
61 line += makePrefix(key, last) + key;
62
63 // append values and the circular reference indicator
64 showValues && (typeof root !== 'object' || root instanceof Date) && (line += ': ' + root);
65 circular && (line += ' (circular ref.)');
66
67 callback(line);
68 }
69
70 // can we descend into the next item?
71 if ( ! circular && typeof root === 'object') {
72 var keys = filterKeys(root, hideFunctions);
73 keys.forEach(function(branch){
74 // the last key is always printed with a different prefix, so we'll need to know if we have it
75 lastKey = ++index === keys.length;
76
77 // hold your breath for recursive action
78 growBranch(branch, root[branch], lastKey, lastStatesCopy, showValues, hideFunctions, callback);
79 });
80 }
81 };
82
83 // --------------------
84
85 var Treeify = {};
86
87 // Treeify.asLines
88 // --------------------
89 // Outputs the tree line-by-line, calling the lineCallback when each one is available.
90
91 Treeify.asLines = function(obj, showValues, hideFunctions, lineCallback) {
92 /* hideFunctions and lineCallback are curried, which means we don't break apps using the older form */
93 var hideFunctionsArg = typeof hideFunctions !== 'function' ? hideFunctions : false;
94 growBranch('.', obj, false, [], showValues, hideFunctionsArg, lineCallback || hideFunctions);
95 };
96
97 // Treeify.asTree
98 // --------------------
99 // Outputs the entire tree, returning it as a string with line breaks.
100
101 Treeify.asTree = function(obj, showValues, hideFunctions) {
102 var tree = '';
103 growBranch('.', obj, false, [], showValues, hideFunctions, function(line) {
104 tree += line + '\n';
105 });
106 return tree;
107 };
108
109 // --------------------
110
111 return Treeify;
112
113}));