1 |
|
|
// Load modules |
2 |
|
|
|
3 |
|
1 |
var Chalk = require('chalk'); |
4 |
|
1 |
var Hoek = require('hoek'); |
5 |
|
1 |
var Joi = require('joi'); |
6 |
|
|
|
7 |
|
|
|
8 |
|
|
// declare internals |
9 |
|
|
|
10 |
|
1 |
var internals = { |
11 |
|
|
colors: { |
12 |
|
|
BoolFalse: 'red.bold', |
13 |
|
|
BoolTrue: 'green.bold', |
14 |
|
|
Circular: 'grey.bold', |
15 |
|
|
Date: 'green', |
16 |
|
|
Key: 'white.bold', |
17 |
|
|
Null: 'red.bold', |
18 |
|
|
Number: 'blue.bold', |
19 |
|
|
RegExp: 'magenta', |
20 |
|
|
String: 'yellow', |
21 |
|
|
Symbol: 'magenta.bold', |
22 |
|
|
Undefined: 'red.inverse', |
23 |
|
|
depth: 'grey', |
24 |
|
|
error: 'red', |
25 |
|
|
function: 'cyan', |
26 |
|
|
prefix: 'green', |
27 |
|
|
path: 'blue' |
28 |
|
|
}, |
29 |
|
|
defaults: { |
30 |
|
|
depth: Joi.number().min(0).allow(null).default(2), |
31 |
|
|
plain: Joi.boolean().default(false), |
32 |
|
|
path: Joi.boolean().default(false), |
33 |
|
|
indent: Joi.number().default(4), |
34 |
|
|
align: Joi.string().valid(['left', 'right']).default('left'), |
35 |
|
|
arrayIndex: Joi.boolean().default(true), |
36 |
|
|
pathPrefix: Joi.string().default('// ') |
37 |
|
|
} |
38 |
|
|
}; |
39 |
|
|
|
40 |
|
1 |
internals.purdy = function (object, options) { |
41 |
|
|
|
42 |
|
44 |
this.indentLevel = 0; |
43 |
|
44 |
this.seen = []; |
44 |
|
44 |
this.path = []; |
45 |
|
44 |
this.object = object; |
46 |
|
|
|
47 |
|
44 |
this.settings = Joi.attempt(options || {}, internals.defaults); |
48 |
|
|
}; |
49 |
|
|
|
50 |
|
|
|
51 |
|
|
|
52 |
|
1 |
module.exports = function (object, options) { |
53 |
|
|
|
54 |
|
1 |
var Purdy = new internals.purdy(object, options); |
55 |
|
1 |
return console.log(Purdy.stringify()); |
56 |
|
|
}; |
57 |
|
|
|
58 |
|
1 |
module.exports.stringify = function (object, options) { |
59 |
|
|
|
60 |
|
43 |
var Purdy = new internals.purdy(object, options); |
61 |
|
43 |
return Purdy.stringify(); |
62 |
|
|
} |
63 |
|
|
|
64 |
|
|
|
65 |
|
1 |
internals.purdy.prototype.stringify = function (object, options) { |
66 |
|
|
|
67 |
|
44 |
return this.travel(this.object, '', 0); |
68 |
|
|
}; |
69 |
|
|
|
70 |
|
|
|
71 |
|
1 |
internals.purdy.prototype.travel = function (object, path, depth) { |
72 |
|
|
|
73 |
|
146 |
var type = toString.call(object).split(' ')[1].slice(0, -1); |
74 |
|
146 |
var format = ''; |
75 |
|
|
|
76 |
|
146 |
if (this[type]) { |
77 |
|
85 |
format = this[type](object, path, depth); |
78 |
|
|
} |
79 |
|
|
else { |
80 |
|
61 |
format = String(object); |
81 |
|
|
} |
82 |
|
|
|
83 |
|
146 |
return this.colorize(format, type); |
84 |
|
|
}; |
85 |
|
|
|
86 |
|
|
|
87 |
|
1 |
internals.purdy.prototype.colorize = function (string, type) { |
88 |
|
|
|
89 |
|
252 |
if (this.settings.plain) { |
90 |
|
133 |
return string; |
91 |
|
|
} |
92 |
|
|
|
93 |
|
119 |
var colors = internals.colors[type]; |
94 |
|
119 |
if (!colors) { |
95 |
|
33 |
return string; |
96 |
|
|
} |
97 |
|
|
|
98 |
|
86 |
var colorArr = colors.split('.'); |
99 |
|
|
|
100 |
|
86 |
for (var i = 0, il = colorArr.length; i < il; ++i) { |
101 |
|
147 |
var color = colorArr[i]; |
102 |
|
147 |
string = Chalk[color](string); |
103 |
|
|
} |
104 |
|
|
|
105 |
|
86 |
return string; |
106 |
|
|
}; |
107 |
|
|
|
108 |
|
|
|
109 |
|
1 |
internals.lengthCompare = function (a, b) { |
110 |
|
|
|
111 |
|
78 |
return a.length - b.length; |
112 |
|
|
}; |
113 |
|
|
|
114 |
|
|
|
115 |
|
1 |
internals.purdy.prototype.tidyPath = function (path) { |
116 |
|
|
|
117 |
|
4 |
return this.colorize(path.slice(1, path.size), 'path'); |
118 |
|
|
}; |
119 |
|
|
|
120 |
|
1 |
internals.purdy.prototype.Object = internals.purdy.prototype.process = internals.purdy.prototype.global = function (object, path, depth) { |
121 |
|
|
|
122 |
|
43 |
var keys = Object.keys(object); |
123 |
|
|
|
124 |
|
43 |
if (Object.getOwnPropertySymbols) { |
125 |
|
42 |
keys = keys.concat(Object.getOwnPropertySymbols(object)); |
126 |
|
|
} |
127 |
|
|
|
128 |
|
43 |
var prefix = ['Object', 'Function', 'Error', ''].indexOf(object.constructor.name) !== -1 ? '' : this.colorize(object.constructor.name, 'prefix') + ' '; |
129 |
|
|
|
130 |
|
43 |
if (keys.length === 0) { |
131 |
|
1 |
return prefix + '{}'; |
132 |
|
|
} |
133 |
|
|
|
134 |
|
42 |
++depth; |
135 |
|
42 |
var index = this.seen.indexOf(object); |
136 |
|
42 |
if (index !== -1) { |
137 |
|
3 |
return this.showCircular(index); |
138 |
|
|
} |
139 |
|
39 |
this.seen.push(object); |
140 |
|
39 |
this.path.push(path); |
141 |
|
|
|
142 |
|
39 |
var keyLengths = Hoek.clone(keys); |
143 |
|
39 |
this.indentLevel = this.indentLevel + 1; |
144 |
|
39 |
var out = prefix + '{\n'; |
145 |
|
|
|
146 |
|
39 |
for (var i = 0, il = keys.length; i < il; ++i) { |
147 |
|
59 |
var key = keys[i]; |
148 |
|
59 |
var item = object[key]; |
149 |
|
59 |
if (this.settings.path && path.length > 0) { |
150 |
|
3 |
keyLengths.push(this.settings.pathPrefix); |
151 |
|
3 |
out = out + this.indent() + |
152 |
|
|
this.colorize(this.settings.pathPrefix, 'path') + |
153 |
|
|
this.tidyPath(path + '.' + key) + '\n'; |
154 |
|
|
} |
155 |
|
59 |
var longest = keyLengths.sort(internals.lengthCompare)[keyLengths.length - 1]; |
156 |
|
59 |
var keyStr = key.toString(); |
157 |
|
|
|
158 |
|
59 |
if (this.settings.depth === null || this.settings.depth + 1 >= depth) { |
159 |
|
57 |
out = out + this.indent() + '' + (this.printMember(keyStr, longest) + ':') + ' ' + this.travel(item, path + '.' + keyStr, depth); |
160 |
|
|
} |
161 |
|
|
else { |
162 |
|
2 |
this.indentLevel = this.indentLevel - 1; |
163 |
|
2 |
return this.colorize('[Object]', 'depth'); |
164 |
|
|
} |
165 |
|
57 |
if (i !== il - 1) { |
166 |
|
20 |
out = out + ','; |
167 |
|
|
} |
168 |
|
57 |
out = out + '\n'; |
169 |
|
|
} |
170 |
|
37 |
this.indentLevel = this.indentLevel - 1; |
171 |
|
37 |
out = out + this.indent() + '}'; |
172 |
|
37 |
return out; |
173 |
|
|
}; |
174 |
|
|
|
175 |
|
|
|
176 |
|
1 |
internals.purdy.prototype.showCircular = function (index) { |
177 |
|
|
|
178 |
|
5 |
var showPath = this.path[index]; |
179 |
|
5 |
showPath = showPath === '' ? '' : ' ' + showPath.slice(1, showPath.length); |
180 |
|
5 |
return this.colorize('[Circular~' + showPath + ']', 'Circular'); |
181 |
|
|
}; |
182 |
|
|
|
183 |
|
|
|
184 |
|
1 |
internals.purdy.prototype.Array = function (array, path, depth) { |
185 |
|
|
|
186 |
|
23 |
if (array.length === 0) { |
187 |
|
1 |
return '[]'; |
188 |
|
|
} |
189 |
|
|
|
190 |
|
22 |
++depth; |
191 |
|
22 |
var index = this.seen.indexOf(array); |
192 |
|
22 |
if (index !== -1) { |
193 |
|
2 |
return this.showCircular(index); |
194 |
|
|
} |
195 |
|
20 |
this.seen.push(array); |
196 |
|
20 |
this.path.push(path); |
197 |
|
|
|
198 |
|
20 |
var out = '[\n'; |
199 |
|
20 |
this.indentLevel = this.indentLevel + 1; |
200 |
|
|
|
201 |
|
20 |
for (var i = 0, il = array.length; i < il; ++i) { |
202 |
|
48 |
var item = array[i]; |
203 |
|
48 |
if (this.settings.path && path.length > 0) { |
204 |
|
1 |
out = out + this.indent() + |
205 |
|
|
this.colorize(this.settings.pathPrefix, 'path') + |
206 |
|
|
this.tidyPath(path + '.' + i) + '\n'; |
207 |
|
|
} |
208 |
|
48 |
var indexStr = this.settings.arrayIndex ? '[' + this.printMember(i, il) + '] ' : ''; |
209 |
|
48 |
if (this.settings.depth === null || this.settings.depth + 1 >= depth) { |
210 |
|
45 |
out = out + this.indent() + '' + indexStr + this.travel(item, path + '.' + i, depth); |
211 |
|
|
} |
212 |
|
|
else { |
213 |
|
3 |
this.indentLevel = this.indentLevel - 1; |
214 |
|
3 |
return this.colorize('[Object]', 'depth'); |
215 |
|
|
} |
216 |
|
45 |
if (i !== il - 1) { |
217 |
|
28 |
out = out + ','; |
218 |
|
|
} |
219 |
|
45 |
out = out + '\n'; |
220 |
|
|
} |
221 |
|
17 |
this.indentLevel = this.indentLevel - 1; |
222 |
|
17 |
out = out + this.indent() + ']'; |
223 |
|
17 |
return out; |
224 |
|
|
}; |
225 |
|
|
|
226 |
|
|
|
227 |
|
1 |
internals.purdy.prototype.Error = function (err) { |
228 |
|
|
|
229 |
|
4 |
if (Object.keys(err).length === 0) { |
230 |
|
1 |
return this.colorize('[' + err + ']', 'error'); |
231 |
|
|
} |
232 |
|
3 |
var obj = this.Object(err, '', null); |
233 |
|
3 |
var message = err.message ? ': ' + err.message : ''; |
234 |
|
3 |
return obj.replace(/^{/, '{ ' + this.colorize('[Error'+ message + ']', 'error') ); |
235 |
|
|
}; |
236 |
|
|
|
237 |
|
|
|
238 |
|
1 |
internals.purdy.prototype.String = function (str) { |
239 |
|
|
|
240 |
|
14 |
return '\'' + str + '\''; |
241 |
|
|
}; |
242 |
|
|
|
243 |
|
1 |
internals.purdy.prototype.Arguments = function (obj) { |
244 |
|
|
|
245 |
|
1 |
var arr = Array.prototype.slice.call(obj); |
246 |
|
1 |
return this.Array(arr); |
247 |
|
|
}; |
248 |
|
|
|
249 |
|
|
|
250 |
|
1 |
internals.purdy.prototype.Boolean = function (bool) { |
251 |
|
|
|
252 |
|
2 |
if (bool === true) { |
253 |
|
1 |
return this.colorize(bool + '', 'BoolTrue'); |
254 |
|
|
} |
255 |
|
1 |
return this.colorize(bool + '', 'BoolFalse'); |
256 |
|
|
}; |
257 |
|
|
|
258 |
|
|
|
259 |
|
1 |
internals.purdy.prototype.Function = function (obj) { |
260 |
|
|
|
261 |
|
4 |
var name = obj.name ? ': ' + obj.name : ''; |
262 |
|
|
|
263 |
|
4 |
if (Object.keys(obj).length === 0) { |
264 |
|
2 |
return this.colorize('[Function' + name + ']', 'function'); |
265 |
|
|
} |
266 |
|
|
|
267 |
|
2 |
var props = this.Object(obj, '', null); |
268 |
|
2 |
return props.replace(/^{/, '{ ' + this.colorize('[Function' + name + ']', 'function') ); |
269 |
|
|
}; |
270 |
|
|
|
271 |
|
|
|
272 |
|
1 |
internals.purdy.prototype.indent = function () { |
273 |
|
|
|
274 |
|
160 |
return internals.spaces(this.indentLevel * this.settings.indent); |
275 |
|
|
}; |
276 |
|
|
|
277 |
|
|
|
278 |
|
1 |
internals.spaces = function (count) { |
279 |
|
|
|
280 |
|
237 |
var out = ''; |
281 |
|
237 |
for (var i = 0; i < count; i++) { |
282 |
|
787 |
out = out + ' '; |
283 |
|
|
} |
284 |
|
|
|
285 |
|
237 |
return out; |
286 |
|
|
}; |
287 |
|
|
|
288 |
|
|
|
289 |
|
1 |
internals.purdy.prototype.printMember = function (member, max) { |
290 |
|
|
|
291 |
|
77 |
if (this.settings.align === 'left') { |
292 |
|
49 |
max = 0; |
293 |
|
|
} |
294 |
|
77 |
var memberLength = member.length; |
295 |
|
77 |
var maxLength = max.length; |
296 |
|
77 |
var toShift = maxLength - memberLength; |
297 |
|
77 |
return this.colorize(internals.spaces(toShift) + member, 'Key'); |
298 |
|
|
}; |
299 |
|
|
|