This repository has been archived by the owner on May 13, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fancify_log.js
130 lines (123 loc) · 3.62 KB
/
fancify_log.js
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
const chalk = require("chalk")
const { any } = require("./any")
const DEBUG = Symbol("DEBUG")
const LOG = Symbol("LOG")
const WARN = Symbol("WARN")
const ERR = Symbol("ERR")
/** @typedef {typeof DEBUG} DEBUG */
/** @typedef {typeof LOG} LOG */
/** @typedef {typeof WARN} WARN */
/** @typedef {typeof ERR} ERR */
/** @type Record<STYLE_KEY, (msg: string) => string | { before?: () => void, value: string, after?: () => void }> */
const STYLES = {
[LOG]: chalk.reset,
[DEBUG]: (msg) => ({
before: () => process.stderr.write("\x1b[2;3m"),
value: "\x1b[2;3m" + msg,
after: () => process.stderr.write("\x1b[m"),
}),
[WARN]: chalk.yellow.bold,
[ERR]: chalk.red.bgBlack.bold,
}
/** @typedef {DEBUG | LOG | WARN | ERR} STYLE_KEY */
/**
* @typedef {{
* (...args: unknown[]): void
* extend(...names: string[]): Debugger
* }} Debugger
*/
/**
* @typedef {{
* DEBUG: DEBUG, LOG: LOG, WARN: WARN, ERR: ERR,
* log(message: string, ...parts: unknown[]): void,
* extend(...names: string[]): FancifyLog,
* (message: string, ...parts: unknown[]): void
* }} FancifyLog
*/
exports = module.exports =
/** @type {(base: Debugger) => FancifyLog} */ function (base) {
const d = Object.setPrototypeOf(
{
DEBUG,
LOG,
WARN,
ERR,
/** @type {(message: string, ...parts: [parts: ...unknown[], STYLE_KEY?]) => void} */
log(message, ...parts) {
/** @type {STYLE_KEY} */
let s = LOG
if (parts.length) {
let ms = parts.pop()
if (isMember(ms, Object.keys(STYLES))) {
s = ms
}
}
const fmt = STYLES[s](message)
if (typeof fmt === "string") {
return base(fmt, ...parts)
} else {
fmt.before && fmt.before()
const ret = base(fmt.value, ...parts)
fmt.after && fmt.after()
return ret
}
},
/** @type {(...names: string[]) => FancifyLog} */
extend(...names) {
return exports(base.extend(...names))
},
},
Function.prototype
)
/** @type {(...messages: Parameters<FancifyLog["log"]>) => ReturnType<FancifyLog["log"]>} */
// @ts-ignore false error since this function is defined to take the parameters of the wrapped function
const f = function (...messages) {
return d.log(...messages)
}
Object.setPrototypeOf(f, d)
return any(f)
}
/**
* @template T,O
* @typedef {T extends (...args: any[]) => any ? { (...args: Parameters<T> ): ReturnType<T> } & O : T & O} CallableObject
*/
/**
* @template T
* Checks whether or not a value is in a set of values.
* @param {any} value The value to check.
* @param {T[] | Set<T>} set The set of values to check `value` against.
* @returns {asserts value is T}
*/
function assertMember(value, set) {
if (Array.isArray(set)) {
if (set.includes(value)) {
return value
} else {
throw new Error("value is not an element of provided array")
}
}
if (set instanceof Set) {
if (set.has(value)) {
return value
} else {
throw new Error("value is not a member of provided set")
}
}
throw new Error(`set must either be an array or a Set`)
}
/**
* @template T
* Checks whether or not a value is in a set of values.
* @param {any} value The value to check.
* @param {T[] | Set<T>} set The set of values to check `value` against.
* @returns {value is T}
*/
function isMember(value, set) {
if (Array.isArray(set)) {
return set.includes(value)
}
if (set instanceof Set) {
return set.has(value)
}
throw new Error(`set must either be an array or a Set`)
}