lognal 0.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/LICENSE +21 -0
- package/README.md +99 -0
- package/dist/core/filter.d.ts +29 -0
- package/dist/core/filter.js +82 -0
- package/dist/core/layout/entry-lines.d.ts +16 -0
- package/dist/core/layout/entry-lines.js +120 -0
- package/dist/core/layout/layout.d.ts +152 -0
- package/dist/core/layout/layout.js +784 -0
- package/dist/core/layout/row-index.d.ts +33 -0
- package/dist/core/layout/row-index.js +99 -0
- package/dist/core/layout/types.d.ts +128 -0
- package/dist/core/layout/types.js +8 -0
- package/dist/core/store.d.ts +96 -0
- package/dist/core/store.js +204 -0
- package/dist/core/text/ansi.d.ts +20 -0
- package/dist/core/text/ansi.js +187 -0
- package/dist/core/text/graphemes.d.ts +17 -0
- package/dist/core/text/graphemes.js +70 -0
- package/dist/core/text/line-splitter.d.ts +18 -0
- package/dist/core/text/line-splitter.js +56 -0
- package/dist/core/text/measure.d.ts +10 -0
- package/dist/core/text/measure.js +38 -0
- package/dist/core/text/shape.d.ts +24 -0
- package/dist/core/text/shape.js +220 -0
- package/dist/core/text/unicode-width-data.d.ts +54 -0
- package/dist/core/text/unicode-width-data.js +227 -0
- package/dist/core/text/width.d.ts +20 -0
- package/dist/core/text/width.js +157 -0
- package/dist/core/text/wrap.d.ts +14 -0
- package/dist/core/text/wrap.js +94 -0
- package/dist/core/time.d.ts +10 -0
- package/dist/core/time.js +24 -0
- package/dist/core/types.d.ts +131 -0
- package/dist/core/types.js +9 -0
- package/dist/core/value/preview.d.ts +16 -0
- package/dist/core/value/preview.js +207 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +24 -0
- package/dist/lognal.css +589 -0
- package/dist/react/LogViewer.d.ts +32 -0
- package/dist/react/LogViewer.js +183 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.js +2 -0
- package/dist/renderer/canvas/canvas-renderer.d.ts +45 -0
- package/dist/renderer/canvas/canvas-renderer.js +464 -0
- package/dist/renderer/canvas/palette.d.ts +6 -0
- package/dist/renderer/canvas/palette.js +25 -0
- package/dist/renderer/theme.d.ts +3 -0
- package/dist/renderer/theme.js +52 -0
- package/dist/renderer/types.d.ts +82 -0
- package/dist/renderer/types.js +1 -0
- package/dist/sources/console/format.d.ts +32 -0
- package/dist/sources/console/format.js +189 -0
- package/dist/sources/console/hook.d.ts +27 -0
- package/dist/sources/console/hook.js +94 -0
- package/dist/sources/console/recorder.d.ts +41 -0
- package/dist/sources/console/recorder.js +239 -0
- package/dist/sources/console/snapshot.d.ts +22 -0
- package/dist/sources/console/snapshot.js +547 -0
- package/dist/sources/console/table.d.ts +9 -0
- package/dist/sources/console/table.js +87 -0
- package/dist/sources/text/encoding.d.ts +11 -0
- package/dist/sources/text/encoding.js +59 -0
- package/dist/sources/text/follow-file.d.ts +49 -0
- package/dist/sources/text/follow-file.js +109 -0
- package/dist/sources/text/read-file.d.ts +63 -0
- package/dist/sources/text/read-file.js +82 -0
- package/dist/viewer/icons.d.ts +14 -0
- package/dist/viewer/icons.js +30 -0
- package/dist/viewer/input-line.d.ts +46 -0
- package/dist/viewer/input-line.js +144 -0
- package/dist/viewer/labels.d.ts +35 -0
- package/dist/viewer/labels.js +61 -0
- package/dist/viewer/scrollbar.d.ts +27 -0
- package/dist/viewer/scrollbar.js +143 -0
- package/dist/viewer/theme.d.ts +15 -0
- package/dist/viewer/theme.js +105 -0
- package/dist/viewer/viewer.d.ts +217 -0
- package/dist/viewer/viewer.js +1201 -0
- package/package.json +92 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { formatArguments } from './format.js';
|
|
2
|
+
import { DEFAULT_CAPTURE_OPTIONS, snapshotValue } from './snapshot.js';
|
|
3
|
+
import { formatTable } from './table.js';
|
|
4
|
+
export const CONSOLE_METHODS = [
|
|
5
|
+
'log',
|
|
6
|
+
'info',
|
|
7
|
+
'warn',
|
|
8
|
+
'error',
|
|
9
|
+
'debug',
|
|
10
|
+
'trace',
|
|
11
|
+
'dir',
|
|
12
|
+
'dirxml',
|
|
13
|
+
'table',
|
|
14
|
+
'group',
|
|
15
|
+
'groupCollapsed',
|
|
16
|
+
'groupEnd',
|
|
17
|
+
'count',
|
|
18
|
+
'countReset',
|
|
19
|
+
'time',
|
|
20
|
+
'timeLog',
|
|
21
|
+
'timeEnd',
|
|
22
|
+
'assert',
|
|
23
|
+
'clear'
|
|
24
|
+
];
|
|
25
|
+
export const DEFAULT_RECORDER_OPTIONS = {
|
|
26
|
+
...DEFAULT_CAPTURE_OPTIONS,
|
|
27
|
+
clearStore: true
|
|
28
|
+
};
|
|
29
|
+
const DEFAULT_LABEL = 'default';
|
|
30
|
+
const now = () => {
|
|
31
|
+
return typeof performance !== 'undefined' ? performance.now() : Date.now();
|
|
32
|
+
};
|
|
33
|
+
const labelOf = (value) => {
|
|
34
|
+
return value === undefined ? DEFAULT_LABEL : String(value);
|
|
35
|
+
};
|
|
36
|
+
const formatDuration = (milliseconds) => {
|
|
37
|
+
return `${Number(milliseconds.toFixed(3))} ms`;
|
|
38
|
+
};
|
|
39
|
+
const text = (value, extra = {}) => {
|
|
40
|
+
return { type: 'text', text: value, ...extra };
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Turns console calls into store entries.
|
|
44
|
+
*
|
|
45
|
+
* A recorder keeps the state the Console Standard gives a console: the count map, the timer
|
|
46
|
+
* table and the group stack. Everything is captured synchronously, when the method is called.
|
|
47
|
+
*/
|
|
48
|
+
export class ConsoleRecorder {
|
|
49
|
+
store;
|
|
50
|
+
options;
|
|
51
|
+
counts = new Map();
|
|
52
|
+
timers = new Map();
|
|
53
|
+
groups = [];
|
|
54
|
+
constructor(store, options = {}) {
|
|
55
|
+
this.store = store;
|
|
56
|
+
this.options = { ...DEFAULT_RECORDER_OPTIONS, ...options };
|
|
57
|
+
}
|
|
58
|
+
setOptions(options) {
|
|
59
|
+
this.options = { ...this.options, ...options };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Records one call. `stack` is the caller's stack trace, which only `trace` uses.
|
|
63
|
+
*/
|
|
64
|
+
record(method, args, stack) {
|
|
65
|
+
switch (method) {
|
|
66
|
+
case 'log':
|
|
67
|
+
case 'info':
|
|
68
|
+
case 'warn':
|
|
69
|
+
case 'error':
|
|
70
|
+
case 'debug':
|
|
71
|
+
this.add(method, formatArguments(args, this.capture));
|
|
72
|
+
break;
|
|
73
|
+
case 'dir':
|
|
74
|
+
this.add('log', [{ type: 'value', value: this.capture(args[0]) }]);
|
|
75
|
+
break;
|
|
76
|
+
case 'dirxml':
|
|
77
|
+
this.add('log', args.length > 0
|
|
78
|
+
? args.flatMap((value, index) => [
|
|
79
|
+
...(index > 0 ? [text(' ')] : []),
|
|
80
|
+
{ type: 'value', value: this.capture(value) }
|
|
81
|
+
])
|
|
82
|
+
: [text('undefined', { token: 'null' })]);
|
|
83
|
+
break;
|
|
84
|
+
case 'trace':
|
|
85
|
+
this.trace(args, stack);
|
|
86
|
+
break;
|
|
87
|
+
case 'table':
|
|
88
|
+
this.table(args);
|
|
89
|
+
break;
|
|
90
|
+
case 'group':
|
|
91
|
+
case 'groupCollapsed':
|
|
92
|
+
this.group(args, method === 'groupCollapsed');
|
|
93
|
+
break;
|
|
94
|
+
case 'groupEnd':
|
|
95
|
+
this.groups = this.groups.slice(0, -1);
|
|
96
|
+
break;
|
|
97
|
+
case 'count':
|
|
98
|
+
this.count(args[0]);
|
|
99
|
+
break;
|
|
100
|
+
case 'countReset':
|
|
101
|
+
this.countReset(args[0]);
|
|
102
|
+
break;
|
|
103
|
+
case 'time':
|
|
104
|
+
this.time(args[0]);
|
|
105
|
+
break;
|
|
106
|
+
case 'timeLog':
|
|
107
|
+
this.timeLog(args[0], args.slice(1));
|
|
108
|
+
break;
|
|
109
|
+
case 'timeEnd':
|
|
110
|
+
this.timeEnd(args[0]);
|
|
111
|
+
break;
|
|
112
|
+
case 'assert':
|
|
113
|
+
this.assert(args);
|
|
114
|
+
break;
|
|
115
|
+
case 'clear':
|
|
116
|
+
this.clear();
|
|
117
|
+
break;
|
|
118
|
+
default:
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
capture = (value) => {
|
|
123
|
+
return snapshotValue(value, this.options);
|
|
124
|
+
};
|
|
125
|
+
add(level, parts, kind = 'message', init = {}) {
|
|
126
|
+
this.store.append({ level, kind, parts, groups: [...this.groups], ...init });
|
|
127
|
+
}
|
|
128
|
+
trace(args, stack) {
|
|
129
|
+
const parts = args.length > 0 ? formatArguments(args, this.capture) : [text('console.trace')];
|
|
130
|
+
if (stack) {
|
|
131
|
+
const frames = stack
|
|
132
|
+
.split('\n')
|
|
133
|
+
.map((frame) => frame.trim())
|
|
134
|
+
.filter(Boolean)
|
|
135
|
+
.map((frame) => ` ${frame}`)
|
|
136
|
+
.join('\n');
|
|
137
|
+
parts.push(text(`\n${frames}`, { token: 'muted' }));
|
|
138
|
+
}
|
|
139
|
+
this.add('log', parts);
|
|
140
|
+
}
|
|
141
|
+
table(args) {
|
|
142
|
+
const [data, properties] = args;
|
|
143
|
+
if (data === null || typeof data !== 'object') {
|
|
144
|
+
this.add('log', formatArguments(args, this.capture));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const node = snapshotValue(data, { ...this.options, maxDepth: 2 });
|
|
148
|
+
const columns = Array.isArray(properties) ? properties.map((key) => String(key)) : undefined;
|
|
149
|
+
const table = formatTable(node, columns);
|
|
150
|
+
// A table keeps its rows whole; a table wider than the viewer scrolls sideways.
|
|
151
|
+
this.add('log', table === null ? [{ type: 'value', value: node }] : [text(table, { wrap: false })]);
|
|
152
|
+
}
|
|
153
|
+
group(args, collapsed) {
|
|
154
|
+
const parts = args.length > 0
|
|
155
|
+
? formatArguments(args, this.capture).map((part) => part.type === 'text' ? { ...part, style: { ...part.style, bold: true } } : part)
|
|
156
|
+
: [text(collapsed ? 'console.groupCollapsed' : 'console.group', { style: { bold: true } })];
|
|
157
|
+
const [entry] = this.store.append({
|
|
158
|
+
level: 'log',
|
|
159
|
+
kind: 'group',
|
|
160
|
+
parts,
|
|
161
|
+
groups: [...this.groups],
|
|
162
|
+
collapsed
|
|
163
|
+
});
|
|
164
|
+
if (entry) {
|
|
165
|
+
this.groups = [...this.groups, entry.id];
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
count(label) {
|
|
169
|
+
const key = labelOf(label);
|
|
170
|
+
const count = (this.counts.get(key) ?? 0) + 1;
|
|
171
|
+
this.counts.set(key, count);
|
|
172
|
+
this.add('info', [text(`${key}: ${count}`)]);
|
|
173
|
+
}
|
|
174
|
+
countReset(label) {
|
|
175
|
+
const key = labelOf(label);
|
|
176
|
+
if (this.counts.has(key)) {
|
|
177
|
+
this.counts.set(key, 0);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
this.add('warn', [text(`Count for '${key}' does not exist`)]);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
time(label) {
|
|
184
|
+
const key = labelOf(label);
|
|
185
|
+
if (this.timers.has(key)) {
|
|
186
|
+
this.add('warn', [text(`Timer '${key}' already exists`)]);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
this.timers.set(key, now());
|
|
190
|
+
}
|
|
191
|
+
timeLog(label, data) {
|
|
192
|
+
const key = labelOf(label);
|
|
193
|
+
const start = this.timers.get(key);
|
|
194
|
+
if (start === undefined) {
|
|
195
|
+
this.add('warn', [text(`Timer '${key}' does not exist`)]);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const parts = [text(`${key}: ${formatDuration(now() - start)}`)];
|
|
199
|
+
for (const value of data) {
|
|
200
|
+
parts.push(text(' '));
|
|
201
|
+
parts.push(typeof value === 'string' ? text(value) : { type: 'value', value: this.capture(value) });
|
|
202
|
+
}
|
|
203
|
+
this.add('log', parts);
|
|
204
|
+
}
|
|
205
|
+
timeEnd(label) {
|
|
206
|
+
const key = labelOf(label);
|
|
207
|
+
const start = this.timers.get(key);
|
|
208
|
+
if (start === undefined) {
|
|
209
|
+
this.add('warn', [text(`Timer '${key}' does not exist`)]);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
this.timers.delete(key);
|
|
213
|
+
this.add('info', [text(`${key}: ${formatDuration(now() - start)}`)]);
|
|
214
|
+
}
|
|
215
|
+
assert(args) {
|
|
216
|
+
const [condition, ...data] = args;
|
|
217
|
+
if (condition) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (data.length === 0) {
|
|
221
|
+
this.add('error', [text('Assertion failed')]);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (typeof data[0] === 'string') {
|
|
225
|
+
data[0] = `Assertion failed: ${data[0]}`;
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
data.unshift('Assertion failed');
|
|
229
|
+
}
|
|
230
|
+
this.add('error', formatArguments(data, this.capture));
|
|
231
|
+
}
|
|
232
|
+
clear() {
|
|
233
|
+
this.groups = [];
|
|
234
|
+
if (this.options.clearStore) {
|
|
235
|
+
this.store.clear();
|
|
236
|
+
}
|
|
237
|
+
this.add('log', [text('Console was cleared', { token: 'muted' })], 'system');
|
|
238
|
+
}
|
|
239
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ValueNode } from '../../core/types.js';
|
|
2
|
+
/** Limits that keep capturing a large or deep value cheap. */
|
|
3
|
+
export interface CaptureOptions {
|
|
4
|
+
/** How many levels of nested objects are captured. Deeper objects are shown by name only. */
|
|
5
|
+
maxDepth: number;
|
|
6
|
+
/** The most properties, items or entries captured from one object, array, map or set. */
|
|
7
|
+
maxProperties: number;
|
|
8
|
+
/** The longest string captured in full. */
|
|
9
|
+
maxStringLength: number;
|
|
10
|
+
/** The most values captured for one argument, counting every nested value. */
|
|
11
|
+
maxNodes: number;
|
|
12
|
+
}
|
|
13
|
+
export declare const DEFAULT_CAPTURE_OPTIONS: CaptureOptions;
|
|
14
|
+
/**
|
|
15
|
+
* Captures a value as plain data, at the moment of the call.
|
|
16
|
+
*
|
|
17
|
+
* Getters defined by the page are never run: an accessor property is recorded as an accessor.
|
|
18
|
+
* Built-in types are recognized with the engine's own methods rather than `instanceof`, so
|
|
19
|
+
* values from another frame are recognized too. Each limit in `options` bounds the work, and
|
|
20
|
+
* whatever it cuts is counted in the node's `omitted` field.
|
|
21
|
+
*/
|
|
22
|
+
export declare const snapshotValue: (value: unknown, options?: Partial<CaptureOptions>) => ValueNode;
|