1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 | const darkTheme = {
|
6 | Boolean: '#00875f',
|
7 | Date: '#d7d75f',
|
8 | Error: '#af0000',
|
9 | Function: '#5fd7ff',
|
10 | Map: '#5fd787',
|
11 | Null: '#5f00af',
|
12 | Number: '#875fd7',
|
13 | Promise: '#5bb761',
|
14 | PromisePending: '#83c6ea',
|
15 | PromiseRejected: '#fc6c86',
|
16 | RegExp: '#ff8787',
|
17 | Set: '#afd7d7',
|
18 | String: '#005fd7',
|
19 | Symbol: '#afaf5f',
|
20 | Undefined: '#af0087',
|
21 | Unknown: '#d78700',
|
22 | circular: 'fg: #af0000; style: bold;',
|
23 | decoration: '#1c1c1c',
|
24 | nonEnumerable: '#ff0087',
|
25 | property: '#8a8a8a',
|
26 | stack: '#bbbbbb',
|
27 | };
|
28 |
|
29 | const defaults = {
|
30 | all: false,
|
31 | color: true,
|
32 | json: false,
|
33 | lineNumbers: false,
|
34 | print: true,
|
35 | showDepth: true,
|
36 | stream: process.stdout,
|
37 | theme: darkTheme,
|
38 | };
|
39 |
|
40 | const configuration = Object.assign({}, defaults);
|
41 |
|
42 | function configure (options = {}) {
|
43 | Object.assign(configuration, options);
|
44 | }
|
45 |
|
46 | function reset () {
|
47 | Object.assign({}, defaults);
|
48 | }
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 | console.json = function (json, printNonEnumerables) {
|
60 | return prettyPrint(json, {
|
61 | all: printNonEnumerables,
|
62 | json: true,
|
63 | print: true,
|
64 | });
|
65 | };
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 | console.pretty = console.pp = function (...anything) {
|
74 | let output = '';
|
75 | for (const item of anything) {
|
76 | output += prettyPrint(item);
|
77 | }
|
78 | return output;
|
79 | };
|
80 |
|
81 | console.pp.configure = configure;
|
82 | console.pp.reset = reset;
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | function prettyPrint (object, {
|
97 | all = configuration.all,
|
98 | color = configuration.color,
|
99 | json = configuration.json,
|
100 | lineNumbers = configuration.lineNumbers,
|
101 | print = configuration.print,
|
102 | showDepth = configuration.showDepth,
|
103 | stream = configuration.stream,
|
104 | theme = configuration.theme,
|
105 | } = {}) {
|
106 | let style;
|
107 | if (color && stream && stream.isTTY) {
|
108 | style = require('./style');
|
109 | } else {
|
110 | style = (string) => string;
|
111 | }
|
112 |
|
113 | function indent (depth) {
|
114 | return ' '.repeat(depth);
|
115 | }
|
116 |
|
117 | function addLineNumbers (output) {
|
118 | const lines = output.split(/\n/);
|
119 | const padding = lines.length.toString().length + 1;
|
120 | let number = 0;
|
121 | return lines.map((line) => {
|
122 | number++;
|
123 | const lineNumber = `${ ' '.repeat(padding - number.toString().length) +
|
124 | style(number, theme.property) } \u2502 `;
|
125 | return lineNumber + line;
|
126 | }).join('\n');
|
127 | }
|
128 |
|
129 | function prettyPrinter (value, depth, seen, overrideColor) {
|
130 | let line = indent(depth);
|
131 |
|
132 | seen = new Set(seen);
|
133 |
|
134 | if (typeof value === 'object' && seen.has(value)) {
|
135 | line += style('[Circular Reference]', theme.circular);
|
136 | } else {
|
137 | if (typeof value === 'object' && value !== null) {
|
138 | seen.add(value);
|
139 | }
|
140 |
|
141 | if (typeof value === 'string') {
|
142 | if (overrideColor && !json) {
|
143 | line += style(value, overrideColor);
|
144 | } else if (json) {
|
145 | line += style(`"${ value }"`, overrideColor || theme.String);
|
146 | } else {
|
147 | line += style(`'${ value }'`, overrideColor || theme.String);
|
148 | }
|
149 | } else if (typeof value === 'number') {
|
150 | line += style(value, overrideColor || theme.Number);
|
151 | } else if (typeof value === 'boolean') {
|
152 | line += style(value, overrideColor || theme.Boolean);
|
153 | } else if (value === undefined) {
|
154 | line += style(value, theme.Undefined);
|
155 | } else if (value === null) {
|
156 | line += style(value, theme.Null);
|
157 | } else if (value instanceof Error) {
|
158 | const joiner = indent(depth);
|
159 | const parts = value.stack.toString().split(/\n/);
|
160 | line += style(parts.shift(), theme.Error);
|
161 | line += `\n${ joiner }`;
|
162 | line += parts.map((item) => style(item, theme.stack)).join(`\n${ joiner }`);
|
163 | } else if (value instanceof Date) {
|
164 | line += style(value.toString(), theme.Date);
|
165 | } else if (value instanceof RegExp) {
|
166 | line += style(value.toString(), theme.RegExp);
|
167 | } else if (typeof value === 'function') {
|
168 | line += style(value.toString(), theme.Function);
|
169 | } else if (typeof value === 'symbol') {
|
170 | line += style(value.toString(), theme.Symbol);
|
171 | } else if (Array.isArray(value)) {
|
172 | line += '[';
|
173 | if (value.length) {
|
174 | line += '\n';
|
175 | }
|
176 |
|
177 | depth++;
|
178 | for (let i = 0; i < value.length; i++) {
|
179 | const comma = i < value.length - 1 ? ',' : '';
|
180 | line += `${ prettyPrinter(value[i], depth, seen) + comma }\n`;
|
181 | }
|
182 | depth--;
|
183 | line += `${ indent(depth) }]`;
|
184 | } else if (value instanceof WeakMap) {
|
185 | line += `${ style('WeakMap', theme.Map) } {}`;
|
186 | } else if (value instanceof Map && !json) {
|
187 | line += `${ style('Map', theme.Map) } {`;
|
188 | if (value.size) {
|
189 | line += '\n';
|
190 | }
|
191 |
|
192 | depth++;
|
193 | let j = 0;
|
194 | value.forEach((itemValue, key) => {
|
195 | const comma = j < value.size - 1 ? ',' : '';
|
196 | line += `${ prettyPrinter(key, depth, seen) }: `;
|
197 | line += `${ prettyPrinter(itemValue, depth, seen) + comma }\n`;
|
198 | j++;
|
199 | });
|
200 |
|
201 | depth--;
|
202 | line += `${ indent(depth) }}`;
|
203 | } else if (value instanceof WeakSet) {
|
204 | line += `${ style('WeakSet', theme.Set) } []`;
|
205 | } else if (value instanceof Set && !json) {
|
206 | line += `${ style('Set', theme.Set) } [`;
|
207 | if (value.size) {
|
208 | line += '\n';
|
209 | }
|
210 |
|
211 | depth++;
|
212 | let j = 0;
|
213 | value.forEach((itemValue) => {
|
214 | const comma = j < value.size - 1 ? ',' : '';
|
215 | line += `${ prettyPrinter(itemValue, depth, seen) + comma }\n`;
|
216 | j++;
|
217 | });
|
218 |
|
219 | depth--;
|
220 | line += `${ indent(depth) }]`;
|
221 | } else if (value instanceof Promise) {
|
222 | const details = process.binding('util').getPromiseDetails(value);
|
223 | if (details[0] === 0) {
|
224 | line += `${ style('Promise', theme.Promise) } { ${ style('pending', theme.PromisePending) } }`;
|
225 | } else if (details[0] === 1) {
|
226 | const result = prettyPrinter(details[1], 0, seen).replace(/\n+$/, '');
|
227 | line += `${ style('Promise', theme.Promise) } { ${ result } }`;
|
228 | } else if (details[0] === 2) {
|
229 | line += `${ style('Promise', theme.Promise) } { ${ style('rejected', theme.PromiseRejected) } }`;
|
230 | }
|
231 | } else if (typeof value === 'object') {
|
232 | line += '{';
|
233 | let keys = Object.getOwnPropertyNames(value);
|
234 | if (keys.length) {
|
235 | line += '\n';
|
236 | }
|
237 |
|
238 | const enumerables = {};
|
239 | keys = keys.filter((key) => {
|
240 | const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
241 | enumerables[key] = descriptor.enumerable;
|
242 | return descriptor.enumerable === true || all === true;
|
243 | });
|
244 |
|
245 | depth++;
|
246 | for (let j = 0; j < keys.length; j++) {
|
247 | const key = keys[j];
|
248 | const comma = j < keys.length - 1 ? ',' : '';
|
249 | const keyColor = enumerables[key] ? theme.property : theme.nonEnumerable;
|
250 | line += `${ prettyPrinter(key, depth, seen, keyColor) }: `;
|
251 | line += `${ prettyPrinter(value[key], depth, seen) + comma }\n`;
|
252 | }
|
253 | depth--;
|
254 | line += `${ indent(depth) }}`;
|
255 | } else {
|
256 | line += style(value.toString(), theme.Unknown);
|
257 | }
|
258 | }
|
259 |
|
260 | return line.replace(/:\s+/g, ': ').
|
261 | replace(/([{[])\s+([}\]])/g, '$1$2');
|
262 | }
|
263 | let output = prettyPrinter(object, 0);
|
264 |
|
265 | if (showDepth) {
|
266 | output = output.replace(/\n {2}(\s+)/g, (match, spaces) => `\n ${ spaces.substring(2).split(/ {2}/).
|
267 | map(() => style('\u2502 ', theme.decoration)).
|
268 | join('') }`);
|
269 | }
|
270 |
|
271 | if (lineNumbers) {
|
272 | output = addLineNumbers(output);
|
273 | }
|
274 |
|
275 | if (print !== false) {
|
276 | stream.write(`${ output }\n`);
|
277 | }
|
278 | return output;
|
279 | }
|
280 |
|
281 | module.exports = prettyPrint;
|