bare-console 2.0.2 → 3.0.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/README.md +2 -1
- package/index.js +37 -338
- package/package.json +2 -2
package/README.md
CHANGED
package/index.js
CHANGED
|
@@ -1,28 +1,53 @@
|
|
|
1
|
-
const
|
|
1
|
+
const inspect = require('bare-inspect')
|
|
2
2
|
|
|
3
3
|
module.exports = class Console {
|
|
4
4
|
constructor (opts = {}) {
|
|
5
|
-
|
|
6
|
-
this.
|
|
7
|
-
this.crayon = new Crayon({ isTTY: this.colors })
|
|
5
|
+
this._stdout = adaptStream(opts.stdout)
|
|
6
|
+
this._stderr = adaptStream(opts.stderr)
|
|
8
7
|
|
|
9
|
-
this.
|
|
10
|
-
this.
|
|
8
|
+
this._colors = opts.colors === true
|
|
9
|
+
this._timers = new Map()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
log (...args) {
|
|
13
|
+
let out = ''
|
|
14
|
+
let first = true
|
|
15
|
+
|
|
16
|
+
for (const arg of args) {
|
|
17
|
+
if (first) first = false
|
|
18
|
+
else out += ' '
|
|
19
|
+
|
|
20
|
+
out += typeof arg === 'string' ? arg : inspect(arg, { colors: this._colors })
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
this._stdout.write(out + '\n')
|
|
24
|
+
}
|
|
11
25
|
|
|
12
|
-
|
|
26
|
+
error (...args) {
|
|
27
|
+
let out = ''
|
|
28
|
+
let first = true
|
|
29
|
+
|
|
30
|
+
for (const arg of args) {
|
|
31
|
+
if (first) first = false
|
|
32
|
+
else out += ' '
|
|
33
|
+
|
|
34
|
+
out += typeof arg === 'string' ? arg : inspect(arg, { colors: this._colors })
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
this._stderr.write(out + '\n')
|
|
13
38
|
}
|
|
14
39
|
|
|
15
40
|
time (label = 'default') {
|
|
16
|
-
if (this.
|
|
41
|
+
if (this._timers.has(label)) {
|
|
17
42
|
this.error('Warning: Label \'' + label + '\' already exists for console.time()')
|
|
18
43
|
return
|
|
19
44
|
}
|
|
20
45
|
|
|
21
|
-
this.
|
|
46
|
+
this._timers.set(label, process.hrtime())
|
|
22
47
|
}
|
|
23
48
|
|
|
24
49
|
timeEnd (label = 'default') {
|
|
25
|
-
const started = this.
|
|
50
|
+
const started = this._timers.get(label)
|
|
26
51
|
|
|
27
52
|
if (!started) {
|
|
28
53
|
this.error('Warning: No such label \'' + label + '\' for console.timeEnd()')
|
|
@@ -31,7 +56,7 @@ module.exports = class Console {
|
|
|
31
56
|
|
|
32
57
|
const d = process.hrtime(started)
|
|
33
58
|
const ms = d[0] * 1e3 + d[1] / 1e6
|
|
34
|
-
this.
|
|
59
|
+
this._timers.delete(label)
|
|
35
60
|
|
|
36
61
|
if (ms > 1000) this.log(label + ': ' + (ms / 1000).toFixed(3) + 's')
|
|
37
62
|
else this.log(label + ': ' + ms.toFixed(3) + 'ms')
|
|
@@ -46,334 +71,8 @@ module.exports = class Console {
|
|
|
46
71
|
|
|
47
72
|
this.error('Trace: ' + messages.join(' ') + stack.slice(start))
|
|
48
73
|
}
|
|
49
|
-
|
|
50
|
-
// + clear () {}
|
|
51
|
-
|
|
52
|
-
_print (stream, ...args) {
|
|
53
|
-
const paint = new Paint(this.crayon)
|
|
54
|
-
let identifier = 0
|
|
55
|
-
|
|
56
|
-
for (let i = 0; i < args.length; i++) {
|
|
57
|
-
const arg = args[i]
|
|
58
|
-
|
|
59
|
-
const single = generateSingleValue(arg, { escape: false })
|
|
60
|
-
if (single !== null) {
|
|
61
|
-
paint.push('value', single)
|
|
62
|
-
} else if (typeof arg === 'object') {
|
|
63
|
-
let levels = 0
|
|
64
|
-
|
|
65
|
-
iterateObject(arg)
|
|
66
|
-
|
|
67
|
-
function iterateObject (arg, backward = new WeakSet(), forward = new WeakSet(), add = true) {
|
|
68
|
-
if (add) backward.add(arg)
|
|
69
|
-
else forward.add(arg)
|
|
70
|
-
|
|
71
|
-
const id = identifier++
|
|
72
|
-
const isArray = Array.isArray(arg)
|
|
73
|
-
const isBuffer = Buffer.isBuffer(arg) && arg.constructor.name === 'Buffer'
|
|
74
|
-
const isInts = !isBuffer && isIntArray(arg)
|
|
75
|
-
const isObject = !(isArray || isInts || isBuffer)
|
|
76
|
-
const brackets = isBuffer ? '<>' : (isInts || isArray ? '[]' : '{}')
|
|
77
|
-
|
|
78
|
-
levels++
|
|
79
|
-
|
|
80
|
-
if (levels >= 4 && !isObjectEmpty(arg)) {
|
|
81
|
-
let type = isArray ? 'Array' : (typeof arg)
|
|
82
|
-
type = type[0].toUpperCase() + type.slice(1)
|
|
83
|
-
paint.push('value', '[' + type + ']', { id, crayon: 'cyan' })
|
|
84
|
-
levels--
|
|
85
|
-
return paint.width[id]
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (isInts) paint.push('open', arg.constructor.name + '(' + arg.length + ') ', { id })
|
|
89
|
-
paint.push('open', brackets[0], { id })
|
|
90
|
-
if (isBuffer) paint.push('open', 'Buffer', { id })
|
|
91
|
-
|
|
92
|
-
const MAX = isObject ? Infinity : (isBuffer ? 50 : 100)
|
|
93
|
-
let count = 0
|
|
94
|
-
|
|
95
|
-
for (const key in arg) {
|
|
96
|
-
const k = isObject ? key : parseInt(key, 10)
|
|
97
|
-
const isNumeric = !isObject && isFinite(k)
|
|
98
|
-
const v = arg[isNumeric ? k : key]
|
|
99
|
-
|
|
100
|
-
if (isBuffer && !isNumeric && Object.hasOwn(Object.getPrototypeOf(arg), key)) continue
|
|
101
|
-
|
|
102
|
-
if (count++ >= MAX) break
|
|
103
|
-
|
|
104
|
-
if (count === 1) {
|
|
105
|
-
paint.push('spacing-start', null, { id, levels, isArray, isInts, isBuffer, arg, k })
|
|
106
|
-
} else {
|
|
107
|
-
paint.push('separator', isBuffer && isNumeric ? '' : ',', { id })
|
|
108
|
-
paint.push('spacing-sep', null, { id, levels, isArray, isInts, isBuffer, arg, k })
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (!isNumeric) {
|
|
112
|
-
const singleKey = generateSingleKey(key)
|
|
113
|
-
paint.push('key', [singleKey, ': '], { id })
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const single = generateSingleValue(v, { levels, stringColor: true, intToHex: isBuffer })
|
|
117
|
-
if (single !== null) {
|
|
118
|
-
paint.push('value', single, { id })
|
|
119
|
-
} else if (typeof v === 'object') {
|
|
120
|
-
if (backward.has(v) || (!add && forward.has(v))) {
|
|
121
|
-
paint.push('value', '[Circular]', { id, crayon: 'cyan' })
|
|
122
|
-
continue
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const subWidth = iterateObject(v, backward, forward, false)
|
|
126
|
-
paint.width[id].child += subWidth.self + subWidth.child // + double check after colors fix
|
|
127
|
-
} else {
|
|
128
|
-
throw new Error('Argument not supported (' + (typeof v) + '): ' + v)
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const symbols = Object.getOwnPropertySymbols(arg)
|
|
133
|
-
|
|
134
|
-
for (const symbol of symbols) {
|
|
135
|
-
count++
|
|
136
|
-
|
|
137
|
-
if (count === 1) {
|
|
138
|
-
paint.push('spacing-start', null, { id, levels })
|
|
139
|
-
} else {
|
|
140
|
-
paint.push('separator', ',', { id })
|
|
141
|
-
paint.push('spacing-sep', null, { id, levels })
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (!isArray) {
|
|
145
|
-
paint.push('key', ['[', { out: symbol.toString(), crayon: 'green' }, ']', ': '], { id })
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const single = generateSingleValue(arg[symbol], { levels })
|
|
149
|
-
if (single === null) throw new Error('Symbol value not supported: (' + (typeof arg[symbol]) + '): ' + arg[symbol])
|
|
150
|
-
paint.push('value', single, { id })
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (!isObject && arg.length > MAX) paint.push('more', null, { id, levels, isArray, isInts, isBuffer, arg, left: (arg.length - MAX) })
|
|
154
|
-
|
|
155
|
-
if (count > 0) paint.push('spacing-end', null, { id, levels, isArray, isInts, isBuffer, arg })
|
|
156
|
-
|
|
157
|
-
if (count === 0 && isBuffer) paint.push('spacing-sep', null, { id, levels, isArray, isInts, isBuffer, arg })
|
|
158
|
-
|
|
159
|
-
paint.push('close', brackets[1], { id })
|
|
160
|
-
|
|
161
|
-
levels--
|
|
162
|
-
|
|
163
|
-
return paint.width[id]
|
|
164
|
-
}
|
|
165
|
-
} else {
|
|
166
|
-
throw new Error('Argument not supported (' + (typeof arg) + '): ' + arg)
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (i + 1 !== args.length) paint.push('space', ' ')
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
paint.push('break-line', '\n')
|
|
173
|
-
|
|
174
|
-
stream.write(paint.done())
|
|
175
|
-
|
|
176
|
-
function generateSingleKey (key) {
|
|
177
|
-
if (key === '') return { out: "''", crayon: 'green' }
|
|
178
|
-
|
|
179
|
-
const names = ['undefined', 'null', 'true', 'false', 'NaN', 'Infinity']
|
|
180
|
-
if (names.indexOf(key) > -1) return { out: key }
|
|
181
|
-
|
|
182
|
-
if (isKindOfAlphaNumeric(key) && !isFinite(key)) return { out: key }
|
|
183
|
-
|
|
184
|
-
return { out: "'" + key + "'", crayon: 'green' }
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function generateSingleValue (value, { levels = 0, stringColor = false, escape = true, intToHex = false } = {}) {
|
|
188
|
-
if (typeof value === 'undefined') return { out: 'undefined', crayon: 'blackBright' }
|
|
189
|
-
if (value === null) return { out: 'null', crayon: 'bold' }
|
|
190
|
-
|
|
191
|
-
if (typeof value === 'string') return stringColor ? { out: dynamicQuotes(value, { escape }), crayon: 'green' } : { out: dynamicQuotes(value, { escape }) }
|
|
192
|
-
if (typeof value === 'number') return intToHex ? { out: numberToHex(value) } : { out: value.toString(), crayon: 'yellow' }
|
|
193
|
-
if (typeof value === 'boolean') return { out: value.toString(), crayon: 'yellow' }
|
|
194
|
-
if (typeof value === 'function') return { out: (value.name ? '[Function: ' + value.name + ']' : '[Function (anonymous)]'), crayon: 'cyan' }
|
|
195
|
-
if (typeof value === 'symbol') return { out: value.toString(), crayon: 'green' }
|
|
196
|
-
if (typeof value === 'bigint') return { out: value.toString() + 'n', crayon: 'yellow' } // + edge case: typeof Object(1n) === 'object'
|
|
197
|
-
|
|
198
|
-
if (value instanceof Promise) return { out: 'Promise' }
|
|
199
|
-
if (value instanceof RegExp) return { out: value.toString(), crayon: 'red' }
|
|
200
|
-
|
|
201
|
-
// + AggregateError?
|
|
202
|
-
if (value instanceof Error) return { out: value.stack } // This includes EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError
|
|
203
|
-
if (value instanceof String) return { out: '[String: ' + dynamicQuotes(value.toString()) + ']', crayon: 'green' }
|
|
204
|
-
if (value instanceof Number) return { out: '[Number: ' + value.toString() + ']', crayon: 'yellow' }
|
|
205
|
-
if (value instanceof Boolean) return { out: '[Boolean: ' + value.toString() + ']', crayon: 'yellow' }
|
|
206
|
-
if (value instanceof Date) return { out: value.toISOString(), crayon: 'magenta' }
|
|
207
|
-
|
|
208
|
-
if (value instanceof Map) return { out: 'Map(' + value.size + ') {' + (value.size ? ' ... ' : '') + '}' }
|
|
209
|
-
if (value instanceof Set) return { out: 'Set(' + value.size + ') {' + (value.size ? ' ... ' : '') + '}' }
|
|
210
|
-
|
|
211
|
-
if (value instanceof WeakMap) return [{ out: 'WeakMap { ' }, { out: '<items unknown>', crayon: 'cyan' }, { out: ' }' }]
|
|
212
|
-
if (value instanceof WeakSet) return [{ out: 'WeakSet { ' }, { out: '<items unknown>', crayon: 'cyan' }, { out: ' }' }]
|
|
213
|
-
|
|
214
|
-
return null
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function numberToHex (value) {
|
|
220
|
-
return value.toString(16).padStart(2, '0')
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function isIntArray (value) {
|
|
224
|
-
if (value instanceof Uint8Array || value instanceof Uint16Array || value instanceof Uint32Array) return true
|
|
225
|
-
if (value instanceof Int8Array || value instanceof Int16Array || value instanceof Int32Array) return true
|
|
226
|
-
return false
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function dynamicQuotes (str, opts = {}) {
|
|
230
|
-
if (opts.escape === false) return str
|
|
231
|
-
|
|
232
|
-
if (str.indexOf("'") === -1) return "'" + escapeString(str) + "'"
|
|
233
|
-
if (str.indexOf('"') === -1) return '"' + escapeString(str) + '"'
|
|
234
|
-
if (str.indexOf('`') === -1) return '`' + escapeString(str) + '`'
|
|
235
|
-
|
|
236
|
-
return "'" + escapeString(str, true) + "'"
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function escapeString (str, singled = false) {
|
|
240
|
-
str = str
|
|
241
|
-
.replace(/[\\]/g, '\\\\')
|
|
242
|
-
.replace(/[/]/g, '\\/')
|
|
243
|
-
.replace(/[\b]/g, '\\b')
|
|
244
|
-
.replace(/[\f]/g, '\\f')
|
|
245
|
-
.replace(/[\n]/g, '\\n')
|
|
246
|
-
.replace(/[\r]/g, '\\r')
|
|
247
|
-
.replace(/[\t]/g, '\\t')
|
|
248
|
-
|
|
249
|
-
if (singled) str = str.replace(/[']/g, '\\\'')
|
|
250
|
-
|
|
251
|
-
return str
|
|
252
74
|
}
|
|
253
75
|
|
|
254
76
|
function adaptStream (stream) {
|
|
255
|
-
|
|
256
|
-
return { isTTY: true, write: stream }
|
|
257
|
-
}
|
|
258
|
-
return stream
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
class Paint {
|
|
262
|
-
constructor (crayon) {
|
|
263
|
-
this.prints = []
|
|
264
|
-
this.width = { all: 0 }
|
|
265
|
-
this.crayon = crayon
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
push (type, chunk = null, opts = {}) {
|
|
269
|
-
if (Array.isArray(chunk)) return chunk.forEach(value => this.push(type, value, opts))
|
|
270
|
-
|
|
271
|
-
let color = opts.crayon
|
|
272
|
-
|
|
273
|
-
if (chunk && typeof chunk === 'object') {
|
|
274
|
-
color = chunk.crayon
|
|
275
|
-
chunk = chunk.out
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
if (chunk !== null) {
|
|
279
|
-
this.width.all += chunk.length // + it's not including spaces as it's mostly dynamic
|
|
280
|
-
|
|
281
|
-
if (opts && opts.id !== undefined) {
|
|
282
|
-
if (!this.width[opts.id]) this.width[opts.id] = { self: 0, child: 0 }
|
|
283
|
-
this.width[opts.id].self += chunk.length
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
if (color) chunk = this.crayon[color](chunk)
|
|
288
|
-
|
|
289
|
-
this.prints.push({ type, chunk, ...opts })
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
done () {
|
|
293
|
-
let output = ''
|
|
294
|
-
|
|
295
|
-
for (const print of this.prints) {
|
|
296
|
-
// raw
|
|
297
|
-
if (['open', 'close', 'key', 'value', 'separator', 'space', 'break-line'].indexOf(print.type) > -1) {
|
|
298
|
-
output += print.chunk
|
|
299
|
-
continue
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// dynamic
|
|
303
|
-
if (print.type === 'spacing-start' || print.type === 'spacing-sep' || print.type === 'spacing-end') {
|
|
304
|
-
const type = print.type.replace('spacing-', '')
|
|
305
|
-
const totalWidth = this.width[print.id] ? (this.width[print.id].self + this.width[print.id].child) : this.width.all
|
|
306
|
-
const expand = print.isInts || print.isArray || totalWidth > 60 // + 64? double check after colors fix
|
|
307
|
-
let arrayBreakpoint = 0
|
|
308
|
-
|
|
309
|
-
if (print.isInts || print.isArray) {
|
|
310
|
-
const lengths = [7, 9, 13, 17, 23, 29, 37, 45, 53]
|
|
311
|
-
|
|
312
|
-
for (let i = lengths.length - 1; i >= 0; i--) {
|
|
313
|
-
if (print.arg.length >= lengths[i]) {
|
|
314
|
-
arrayBreakpoint = 4 + i // Range: 4-12
|
|
315
|
-
break
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (print.isBuffer) {
|
|
321
|
-
if (type === 'start' || type === 'sep') output += ' '
|
|
322
|
-
continue
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (print.isInts || print.isArray) {
|
|
326
|
-
const addSpacing = arrayBreakpoint !== 0
|
|
327
|
-
const skipSpacing = type === 'sep' && !(print.k % arrayBreakpoint === 0)
|
|
328
|
-
|
|
329
|
-
if (!addSpacing || skipSpacing) {
|
|
330
|
-
output += ' '
|
|
331
|
-
continue
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
if (!expand) output += ' '
|
|
336
|
-
else output += '\n' + ' '.repeat(print.levels - (type === 'end' ? 1 : 0))
|
|
337
|
-
|
|
338
|
-
continue
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if (print.type === 'more') {
|
|
342
|
-
const addSpacing = !print.isBuffer
|
|
343
|
-
const sep = print.isBuffer ? '' : ','
|
|
344
|
-
|
|
345
|
-
output += addSpacing ? (',\n' + ' '.repeat(print.levels)) : (sep + ' ')
|
|
346
|
-
output += '... ' + print.left + ' more ' + (print.isBuffer ? 'byte' : 'item') + (print.left >= 2 ? 's' : '')
|
|
347
|
-
|
|
348
|
-
continue
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
throw new Error('Invalid print: ' + JSON.stringify(print))
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
return output
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
function isObjectEmpty (obj) {
|
|
359
|
-
for (const k in obj) return false // eslint-disable-line no-unreachable-loop
|
|
360
|
-
return true
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
function isKindOfAlphaNumeric (str) {
|
|
364
|
-
for (let i = 0; i < str.length; i++) {
|
|
365
|
-
const code = str.charCodeAt(i)
|
|
366
|
-
|
|
367
|
-
// first char, and numeric (0-9)
|
|
368
|
-
if (i === 0 && (code > 47 && code < 58)) return false
|
|
369
|
-
|
|
370
|
-
if (!(code > 47 && code < 58) && // numeric (0-9)
|
|
371
|
-
!(code > 64 && code < 91) && // upper alpha (A-Z)
|
|
372
|
-
!(code > 96 && code < 123) && // lower alpha (a-z)
|
|
373
|
-
!(code === 95)) { // underscore (_)
|
|
374
|
-
return false
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
return true
|
|
77
|
+
return typeof stream === 'function' ? { write: stream } : stream
|
|
379
78
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bare-console",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Simple debugging console for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"homepage": "https://github.com/holepunchto/bare-console#readme",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"
|
|
23
|
+
"bare-inspect": "^1.0.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"brittle": "^3.1.1",
|