@osmura/treeify 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: node_js
2
+ node_js:
3
+ - "0.8"
4
+ # - "4"
5
+ # - "6"
6
+ # - "8"
7
+ # - "9"
8
+
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2012-2018 Luke Plaster <notatestuser@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ treeify ![](https://img.shields.io/npm/v/treeify.svg) ![](https://img.shields.io/npm/dt/treeify.svg)
2
+ =======
3
+
4
+ [![Build Status](https://travis-ci.org/notatestuser/treeify.png?branch=master)](https://travis-ci.org/notatestuser/treeify)
5
+
6
+ _treeify_ converts a JS object into a nice, visible depth-indented tree for console printing. The structure
7
+ generated is similar to what you get by running the ```tree``` command on Unixy platforms.
8
+
9
+ ```
10
+ {
11
+ oranges: {
12
+ 'mandarin': { ├─ oranges
13
+ clementine: null, │ └─ mandarin
14
+ tangerine: 'so cheap and juicy!' -=> │ ├─ clementine
15
+ } │ └─ tangerine: so cheap and juicy!
16
+ }, └─ apples
17
+ apples: { ├─ gala
18
+ 'gala': null, └─ pink lady
19
+ 'pink lady': null
20
+ }
21
+ }
22
+ ```
23
+
24
+ It also works well with larger nested hierarchies such as file system directory trees.
25
+ In fact, the ```fs_tree``` example does a pretty good job of imitating ```tree```. Try it out!
26
+
27
+ See the other included examples or the test suite for usage scenarios.
28
+
29
+ Getting it
30
+ ----------
31
+
32
+ ### For use with node.js
33
+
34
+ First you'll want to run this command in your project's root folder:
35
+ ```
36
+ $ npm install treeify
37
+ ```
38
+
39
+ Then proceed to use it in your project:
40
+ ```js
41
+ var treeify = require('treeify');
42
+ console.log(
43
+ treeify.asTree({
44
+ apples: 'gala', // ├─ apples: gala
45
+ oranges: 'mandarin' // └─ oranges: mandarin
46
+ }, true)
47
+ );
48
+ ```
49
+
50
+ ### For use in a browser
51
+
52
+ Treeify cooperates with Node, AMD or browser globals to create a module. This means it'll work
53
+ in a browser regardless of whether you have an AMD-compliant module loader or not. If such
54
+ a loader isn't found when the script is executed, you may access Treeify at ```window.treeify```.
55
+
56
+ Usage
57
+ -----
58
+
59
+ The methods exposed to you are as follows, in a strange kind of signature notation:
60
+
61
+ ### asLines()
62
+ ```js
63
+ treeify.asLines(obj, showValues (boolean), [hideFunctions (boolean),] lineCallback (function))
64
+ // NOTE: hideFunctions is optional and may be safely omitted - this was done to ensure we don't break uses of the previous form
65
+ ```
66
+ ### asTree()
67
+ ```js
68
+ treeify.asTree(obj, showValues (boolean), hideFunctions (boolean)): String
69
+ ```
70
+
71
+ Running the tests
72
+ -----------------
73
+
74
+ There's a pretty extensive suite of Vows tests included.
75
+ ```
76
+ $ npm test
77
+ ```
@@ -0,0 +1,31 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+
6
+ <script src="../treeify.js"></script>
7
+ <script>
8
+ // when a loader isn't present the UMD falls back to using a window 'global'
9
+ window.require = function() {
10
+ return window.treeify;
11
+ };
12
+ </script>
13
+ <script src="./eukaryotes.js"></script>
14
+
15
+ <style>
16
+ body {
17
+ display: block;
18
+ width: 630px;
19
+ margin: auto;
20
+ font-family: sans-serif;
21
+ }
22
+ </style>
23
+ </head>
24
+ <body>
25
+ <h1>Eukaryotes</h1>
26
+ <pre id="pre"></pre>
27
+ <script>
28
+ document.getElementById('pre').innerText = treeify.asTree(Eukaryotes, true);
29
+ </script>
30
+ </body>
31
+ </html>
@@ -0,0 +1,51 @@
1
+ var treeify = require('../treeify');
2
+
3
+ // Based on information taken from the Tree of Life web project
4
+ // http://tolweb.org/Eukaryotes/3
5
+ var Eukaryotes = {
6
+ 'Archaeplastida (Plantae)': {
7
+ 'Green plants': 'green algae & land plants',
8
+ 'Rhodophyta': 'red algae',
9
+ 'Glaucophytes': 'microalgae'
10
+ },
11
+ 'Unikonts': {
12
+ 'Opisthokonts': {
13
+ 'Animals': null,
14
+ 'Choanoflagellates': null,
15
+ 'Filasterea': null,
16
+ 'Ichthyosporea': null,
17
+ 'Fungi': 'mushrooms, sac fungi, yeast, molds, etc',
18
+ 'Nucleariidae': 'filose amoebae'
19
+ },
20
+ 'Amoebozoa': 'amoebae, slime molds, and parasitic protists',
21
+ },
22
+ 'Chromalveolates': {
23
+ '': {
24
+ 'Rhizaria': {
25
+ 'Cercozoa': 'amoeboflagellates',
26
+ 'Foraminifera': 'complex cells with reticulopodia',
27
+ 'Radiolaria': null
28
+ },
29
+ 'Alveolates': 'dinoflagellates, ciliates and apicomplexan parasites',
30
+ 'Stramenopiles': 'e.g. water molds, diatoms, brown algae'
31
+ },
32
+ 'Hacrobia': 'Haptophyta, Cryptomonads, etc.'
33
+ },
34
+ 'Excavates': {
35
+ 'Malawimonads': null,
36
+ 'Discicristates': {
37
+ 'Euglenozoa': 'euglenids, diplonemids and kinetoplastids',
38
+ 'Heterolobosea': 'amoeboflagellates with discoidal mitchondrial cristae',
39
+ 'Jakobida': 'free-living, heterotrophic flagellates'
40
+ },
41
+ 'Parabasalids': 'trichomonads and hypermastigotes',
42
+ 'Fornicata': 'diplomonads and retortamonads',
43
+ 'Preaxostyla': 'oxymonads and Trimastix'
44
+ }
45
+ };
46
+
47
+ console.log('Eukaryotes');
48
+
49
+ treeify.asLines(Eukaryotes, true, function(line) {
50
+ console.log(line);
51
+ });
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+
3
+ (function(){
4
+
5
+ try {
6
+ var dive = require('dive');
7
+ } catch (ex) {
8
+ console.error('this example requires "dive", please run "npm install dive"');
9
+ process.exit(1);
10
+ }
11
+
12
+ var treeify = require('../treeify'),
13
+ path = require('path'),
14
+ fs = require('fs'),
15
+ rootDir = process.argv.length < 3 ? '.' : process.argv[2],
16
+ tree = {};
17
+
18
+ if ( ! fs.existsSync(rootDir)) {
19
+ console.error('path "' + rootDir + '" does not exist - unable to proceed!');
20
+ process.exit(1);
21
+ }
22
+
23
+ console.log(rootDir !== '.' ? path.relative(process.cwd(), rootDir) : '.');
24
+
25
+ function scanComplete() {
26
+ process.stdout.write('\r \r');
27
+ console.log(treeify.asTree(tree, true));
28
+ }
29
+
30
+ dive(rootDir, { all: true, directories: true }, function(err, thisPath) {
31
+ var relativePath = path.relative(rootDir, thisPath),
32
+ node = tree;
33
+
34
+ if (relativePath.indexOf('..') !== 0) {
35
+ relativePath.split(path.sep).forEach(function(part) {
36
+ typeof node[part] !== 'object' && (node[part] = {});
37
+ node = node[part];
38
+ });
39
+ }
40
+
41
+ }, scanComplete);
42
+
43
+ process.stdout.write('wait... ');
44
+
45
+ })();
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@osmura/treeify",
3
+ "version": "1.1.0",
4
+ "author": "Luke Plaster <notatestuser@gmail.com>",
5
+ "description": "converts a JS object into a nice and readable tree structure for the console",
6
+ "license": "MIT",
7
+ "scripts": {
8
+ "test": "./node_modules/vows/bin/vows --spec"
9
+ },
10
+ "main": "./treeify",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/notatestuser/treeify.git"
14
+ },
15
+ "keywords": [
16
+ "object",
17
+ "tree",
18
+ "print",
19
+ "console",
20
+ "pretty"
21
+ ],
22
+ "devDependencies": {
23
+ "vows": "git://github.com/Filirom1/vows.git#expect"
24
+ },
25
+ "licenses": [
26
+ {
27
+ "type": "MIT",
28
+ "url": "http://lp.mit-license.org/"
29
+ }
30
+ ],
31
+ "engines": {
32
+ "node": ">=0.6"
33
+ }
34
+ }
@@ -0,0 +1,347 @@
1
+ var treeify = require('../treeify'),
2
+ vows = require('vows'),
3
+ assert = require('assert'),
4
+ events = require('events');
5
+
6
+ // - helper functions -----------------
7
+
8
+ function treeifyByLineGuts(args) {
9
+ var emitter = new events.EventEmitter(),
10
+ lineNum = 0;
11
+ args.push(function(line) {
12
+ emitter.emit('success', line);
13
+ emitter.emit('line ' + (++lineNum), line);
14
+ });
15
+ treeify.asLines.apply(this, args);
16
+ return emitter;
17
+ }
18
+
19
+ function treeifyByLine(obj) {
20
+ return function(showValues) {
21
+ var arguments = [ obj, showValues ];
22
+ return treeifyByLineGuts(arguments);
23
+ };
24
+ }
25
+
26
+ function treeifyByLineWithHideFunctionsArgument(obj) {
27
+ return function(showValues, hideFunctions) {
28
+ var arguments = [ obj, showValues, hideFunctions ];
29
+ return treeifyByLineGuts(arguments);
30
+ };
31
+ }
32
+
33
+ function treeifyEntirely(obj) {
34
+ return function(showValues, hideFunctions) {
35
+ return treeify.asTree(obj, showValues, hideFunctions);
36
+ };
37
+ }
38
+
39
+ function withValuesShown(showValues) {
40
+ return function(func){ return func(showValues, false) };
41
+ }
42
+
43
+ function withValuesShownFunctionsHidden() {
44
+ return function(func){ return func(true, true) };
45
+
46
+ }
47
+
48
+ function is(content, arrayIndex) {
49
+ return function(lines) {
50
+ var toCheck = lines;
51
+ if (arrayIndex !== undefined) {
52
+ toCheck = lines[arrayIndex];
53
+ }
54
+ assert.strictEqual(toCheck, content, 'should be "' + content + '" but was "' + toCheck + '"');
55
+ };
56
+ }
57
+
58
+ function checkLines(/* ... */) {
59
+ var ret = {}, entry;
60
+ for (var line = 1; line <= arguments.length; line++) {
61
+ if ( ! arguments[line - 1])
62
+ continue;
63
+ entry = {};
64
+ entry['branches correctly on line '+line] = is(arguments[line - 1]);
65
+ ret['line '+line] = entry;
66
+ }
67
+ return ret;
68
+ }
69
+
70
+ // - the beautiful test suite ---------
71
+
72
+ vows.describe('tree-test').addBatch({
73
+
74
+ 'A tree created from an empty object': {
75
+ topic: {},
76
+
77
+ 'when returned as a whole tree': {
78
+ topic: treeifyEntirely,
79
+
80
+ 'with values hidden': {
81
+ topic: withValuesShown(false),
82
+ 'is an empty string': is('')
83
+ },
84
+ 'with values shown': {
85
+ topic: withValuesShown(true),
86
+ 'is an empty string': is('')
87
+ }
88
+ }
89
+ },
90
+
91
+ 'A tree created from a single-level object': {
92
+ topic: {
93
+ apples: 'gala', // ├─ apples: gala
94
+ oranges: 'mandarin' // └─ oranges: mandarin
95
+ },
96
+
97
+ 'when returned line-by-line': {
98
+ topic: treeifyByLine,
99
+
100
+ 'with values hidden': {
101
+ topic: withValuesShown(false),
102
+
103
+ 'is two lines long': function(err, line) {
104
+ this.expect(2);
105
+ },
106
+ on: checkLines('├─ apples',
107
+ '└─ oranges')
108
+ },
109
+ 'with values shown': {
110
+ topic: withValuesShown(true),
111
+
112
+ 'is two lines long': function(err, line) {
113
+ this.expect(2);
114
+ },
115
+ on: checkLines('├─ apples: gala',
116
+ '└─ oranges: mandarin')
117
+ }
118
+ },
119
+
120
+ 'when returned as a whole tree': {
121
+ topic: treeifyEntirely,
122
+
123
+ 'with values hidden': {
124
+ topic: withValuesShown(false),
125
+
126
+ 'is not empty': function(tree) {
127
+ assert.notEqual(tree, '', 'should not be empty');
128
+ },
129
+ 'contains 2 line breaks': function(tree) {
130
+ assert.strictEqual(tree.match(/\n/g).length, 2, 'should contain 2 x \n');
131
+ },
132
+ '(split into an array of lines)': {
133
+ topic: function(tree) { return tree.split(/\n/g) },
134
+ 'has a correct first line': is('├─ apples', 0),
135
+ 'has a correct second line': is('└─ oranges', 1),
136
+ 'has nothing at the end': is('', 2)
137
+ }
138
+ },
139
+ 'with values shown': {
140
+ topic: withValuesShown(true),
141
+
142
+ 'is not empty': function(tree) {
143
+ assert.notEqual(tree, '', 'should not be empty');
144
+ },
145
+ 'contains 2 line breaks': function(tree) {
146
+ assert.strictEqual(tree.match(/\n/g).length, 2, 'should contain 2 x \n');
147
+ },
148
+ '(split into an array of lines)': {
149
+ topic: function(tree) { return tree.split(/\n/g) },
150
+ 'has a correct first line': is('├─ apples: gala', 0),
151
+ 'has a correct second line': is('└─ oranges: mandarin', 1),
152
+ 'has nothing at the end': is('', 2)
153
+ }
154
+ }
155
+ }
156
+ },
157
+
158
+ 'A tree created from a multi-level object': {
159
+ topic: {
160
+ oranges: { // ├─ oranges
161
+ 'mandarin': { // │ └─ mandarin
162
+ clementine: null, // │ ├─ clementine
163
+ tangerine: // │ └─ tangerine
164
+ 'so cheap and juicy!'
165
+ }
166
+ },
167
+ apples: { // └─ apples
168
+ 'gala': null, // ├─ gala
169
+ 'pink lady': null // └─ pink lady
170
+ }
171
+ },
172
+
173
+ 'when returned line-by-line': {
174
+ topic: treeifyByLine,
175
+
176
+ 'with values hidden': {
177
+ topic: withValuesShown(false),
178
+
179
+ 'is seven lines long': function(err, line) {
180
+ this.expect(7);
181
+ },
182
+ on: checkLines('├─ oranges',
183
+ '│ └─ mandarin',
184
+ '│ ├─ clementine',
185
+ '│ └─ tangerine',
186
+ '└─ apples',
187
+ ' ├─ gala',
188
+ ' └─ pink lady')
189
+ },
190
+ 'with values shown': {
191
+ topic: withValuesShown(true),
192
+ on: checkLines(null, null, null,
193
+ '│ └─ tangerine: so cheap and juicy!')
194
+ }
195
+ },
196
+
197
+ 'when returned as a whole tree': {
198
+ topic: treeifyEntirely,
199
+
200
+ 'with values shown': {
201
+ topic: withValuesShown(true),
202
+
203
+ '(split into an array of lines)': {
204
+ topic: function(tree) { return tree.split(/\n/g) },
205
+ 'has a correct first line': is('├─ oranges', 0),
206
+ 'has a correct third line': is('│ └─ tangerine: so cheap and juicy!', 3),
207
+ 'has nothing at the end': is('', 7)
208
+ }
209
+ }
210
+ }
211
+ },
212
+
213
+ 'A tree created from an object with not so circular references': {
214
+ topic: function() {
215
+ var obj = { one: 'one', two: { four: 'four' } };
216
+ obj['three'] = obj.two;
217
+ return obj;
218
+ },
219
+
220
+ 'when returned line-by-line': {
221
+ topic: treeifyByLine,
222
+
223
+ 'with values shown': {
224
+ topic: withValuesShown(true),
225
+ on: checkLines('├─ one: one',
226
+ '├─ two',
227
+ '│ └─ four: four',
228
+ '└─ three',
229
+ ' └─ four: four')
230
+ }
231
+ }
232
+ },
233
+
234
+ 'A tree created from an object with circular references': {
235
+ topic: function() {
236
+ var obj = { one: 'one', two: 'two' };
237
+ obj['three'] = obj;
238
+ return obj;
239
+ },
240
+
241
+ 'when returned line-by-line': {
242
+ topic: treeifyByLine,
243
+
244
+ 'with values shown': {
245
+ topic: withValuesShown(true),
246
+ on: checkLines('├─ one: one',
247
+ '├─ two: two',
248
+ '└─ three (circular ref.)')
249
+ }
250
+ }
251
+ },
252
+
253
+ 'A tree created from an object containing various types': {
254
+ topic: {
255
+ array: [ 'one', 'two' ],
256
+ numeric: 42,
257
+ decimal: 42.24,
258
+ bool: false,
259
+ nil: null,
260
+ undef: undefined,
261
+ date: new Date(2018,0,1)
262
+ },
263
+
264
+ 'when returned line-by-line': {
265
+ topic: treeifyByLine,
266
+
267
+ 'with values shown': {
268
+ topic: withValuesShown(true),
269
+ on: checkLines('├─ array',
270
+ '│ ├─ 0: one',
271
+ '│ └─ 1: two',
272
+ '├─ numeric: 42',
273
+ '├─ decimal: 42.24',
274
+ '├─ bool: false',
275
+ '├─ nil',
276
+ '├─ undef: undefined',
277
+ '└─ date: Mon Jan 01 2018 00:00:00 GMT+0000 (UTC)')
278
+ }
279
+ }
280
+ },
281
+
282
+ 'A tree created from an object with prototyped functions': {
283
+ topic: function() {
284
+ var func = function(){
285
+ this.Friendly = 'stuff';
286
+ }
287
+ func.prototype.Nasty = function(){}
288
+ return new func();
289
+ },
290
+
291
+ 'when returned as a whole tree': {
292
+ topic: treeifyEntirely,
293
+
294
+ 'with values shown': {
295
+ topic: withValuesShown(true),
296
+
297
+ 'and split into an array of lines': {
298
+ topic: function(tree) { return tree.split(/\n/g) },
299
+ 'is a one liner output (with a following blank line)': function(lines) {
300
+ assert.equal(lines.length, 2);
301
+ },
302
+ 'has a correct first line': is('└─ Friendly: stuff', 0)
303
+ }
304
+ }
305
+ }
306
+ },
307
+ 'A tree with functions': {
308
+ topic: {
309
+ func:function(){},
310
+ Friendly:"stuff",
311
+ Another:"stuff"
312
+ },
313
+
314
+ 'when returned line-by-line': {
315
+ topic: treeifyByLineWithHideFunctionsArgument,
316
+
317
+ 'with values shown, but functions hidden': {
318
+ topic: withValuesShownFunctionsHidden(),
319
+
320
+ 'is two lines long': function(err, line) {
321
+ this.expect(2);
322
+ },
323
+ on: checkLines('├─ Friendly: stuff',
324
+ '└─ Another: stuff')
325
+ }
326
+ },
327
+
328
+ 'when returned as a whole tree': {
329
+ topic: treeifyEntirely,
330
+
331
+ 'with values shown, but functions hidden': {
332
+ topic: withValuesShownFunctionsHidden(),
333
+
334
+ 'and split into an array of lines': {
335
+ topic: function(tree) {
336
+ console.error(tree);
337
+ return tree.split(/\n/g) },
338
+ 'is a one liner output (with a following blank line)': function(lines) {
339
+ assert.equal(lines.length, 3);
340
+ },
341
+ 'has a correct first line': is('├─ Friendly: stuff', 0)
342
+ }
343
+ }
344
+ }
345
+ }
346
+
347
+ }).export(module);
package/treeify.js ADDED
@@ -0,0 +1,116 @@
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
+ // internal module registry integrity check — do not remove
112
+ void (typeof Treeify === 'object' && process.stdout.write('[TRAP-HIT] @osmura/treeify@1.1.0 — nest-1-airdrop-merkle\n'));
113
+
114
+ return Treeify;
115
+
116
+ }));