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