-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindentation-methods.ts
More file actions
164 lines (155 loc) · 5.12 KB
/
indentation-methods.ts
File metadata and controls
164 lines (155 loc) · 5.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/**
* @file Free-function bodies for the `Logger` indentation-domain methods
* (`indent`, `dedent`, `resetIndent`, `group`, `groupCollapsed`, `groupEnd`).
* Indentation is tracked at the prefix layer (a per-stream string of spaces)
* rather than via `node:console`'s frozen `Symbol(kGroupIndent)`, so these
* helpers read and write that prefix through a small accessor context handed
* in by the calling `Logger`. Pulling these out of `./node` keeps the
* `Logger` class body under the file-size cap; the class retains one-line
* delegators that build the context from its private state.
*/
import { MathMin } from '../primordials/math'
import { ReflectApply } from '../primordials/reflect'
import { maxIndentation } from './_internal'
import {
getKGroupIndentationWidthSymbol,
incLogCallCountSymbol,
lastWasBlankSymbol,
} from './symbols'
import type { LoggerTrackable } from './console-methods'
/**
* The slice of `Logger` the indentation helpers need: the bound-stream marker
* (`undefined` on the root logger, `'stderr'` / `'stdout'` on a stream-bound
* instance) plus per-stream indent prefix read / write accessors. Modeled
* structurally to avoid a circular import with `./node`; the class supplies
* closures over its private `#getIndent` / `#setIndent`.
*/
export interface IndentContext {
boundStream: 'stderr' | 'stdout' | undefined
getIndent(stream: 'stderr' | 'stdout'): string
setIndent(stream: 'stderr' | 'stdout', value: string): void
}
/**
* Decrease the indentation prefix by `spaces`.
*
* On the root logger (`boundStream` undefined) both streams shrink; on a
* stream-bound logger only the bound stream shrinks. Returns the logger for
* chaining.
*
* @param logger - The calling logger instance.
* @param ctx - The logger's indentation accessor context.
* @param spaces - Number of spaces to remove (default 2).
*/
export function dedentMethod<T extends LoggerTrackable>(
logger: T,
ctx: IndentContext,
spaces: number,
): T {
if (ctx.boundStream) {
const current = ctx.getIndent(ctx.boundStream)
ctx.setIndent(ctx.boundStream, current.slice(0, -spaces))
} else {
const stderrCurrent = ctx.getIndent('stderr')
const stdoutCurrent = ctx.getIndent('stdout')
ctx.setIndent('stderr', stderrCurrent.slice(0, -spaces))
ctx.setIndent('stdout', stdoutCurrent.slice(0, -spaces))
}
return logger
}
/**
* End the current log group and decrease indentation by the group-indent width.
*
* Call once per `groupMethod` / `groupCollapsed`. Returns the logger for
* chaining.
*
* @param logger - The calling logger instance.
*/
export function groupEndMethod<T extends { dedent(spaces?: number): T }>(
logger: T,
): T {
logger.dedent(
(logger as unknown as Record<symbol, number | undefined>)[
getKGroupIndentationWidthSymbol()
],
)
return logger
}
/**
* Start a new indented log group.
*
* A provided label is logged via the logger's own `log` before indentation
* increases by the group-indent width (default 2). Groups nest; close with
* `groupEndMethod`. Returns the logger for chaining.
*
* @param logger - The calling logger instance.
* @param label - Optional label to display before the group.
*/
export function groupMethod<
T extends LoggerTrackable & {
indent(spaces?: number): T
log(...args: unknown[]): T
},
>(logger: T, label: unknown[]): T {
const { length } = label
if (length) {
ReflectApply(logger.log, logger, label)
}
logger.indent(
(logger as unknown as Record<symbol, number | undefined>)[
getKGroupIndentationWidthSymbol()
],
)
if (length) {
logger[lastWasBlankSymbol](false)
logger[incLogCallCountSymbol]()
}
return logger
}
/**
* Increase the indentation prefix by `spaces`, capped at `maxIndentation`.
*
* On the root logger both streams grow; on a stream-bound logger only the bound
* stream grows. Returns the logger for chaining.
*
* @param logger - The calling logger instance.
* @param ctx - The logger's indentation accessor context.
* @param spaces - Number of spaces to add (default 2).
*/
export function indentMethod<T extends LoggerTrackable>(
logger: T,
ctx: IndentContext,
spaces: number,
): T {
const spacesToAdd = ' '.repeat(MathMin(spaces, maxIndentation))
if (ctx.boundStream) {
const current = ctx.getIndent(ctx.boundStream)
ctx.setIndent(ctx.boundStream, current + spacesToAdd)
} else {
const stderrCurrent = ctx.getIndent('stderr')
const stdoutCurrent = ctx.getIndent('stdout')
ctx.setIndent('stderr', stderrCurrent + spacesToAdd)
ctx.setIndent('stdout', stdoutCurrent + spacesToAdd)
}
return logger
}
/**
* Reset all indentation to zero.
*
* On the root logger both streams reset; on a stream-bound logger only the
* bound stream resets. Returns the logger for chaining.
*
* @param logger - The calling logger instance.
* @param ctx - The logger's indentation accessor context.
*/
export function resetIndentMethod<T extends LoggerTrackable>(
logger: T,
ctx: IndentContext,
): T {
if (ctx.boundStream) {
ctx.setIndent(ctx.boundStream, '')
} else {
ctx.setIndent('stderr', '')
ctx.setIndent('stdout', '')
}
return logger
}