-
Notifications
You must be signed in to change notification settings - Fork 57
/
Copy pathlogger.js
148 lines (126 loc) · 3.14 KB
/
logger.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import { is } from './utils'
import * as errors from './errors'
import { format as fmt } from 'util'
import chalkModule from 'chalk'
import style from 'ansi-styles';
const chalk = new chalkModule.constructor({
enabled: process.stderr && process.stderr.isTTY,
})
// Special chars.
const chevron = '\xBB'
const checkmark = '\u2713'
const green = chalk.green(chevron)
const yellow = chalk.yellow(chevron)
const red = chalk.red(chevron)
export default class Logger {
constructor (verbose = false, debug = false) {
this.verbose = verbose
this._stderr = process.stderr
this._debug = debug
this._times = []
}
/**
* Log arguments into stderr if the verbose mode is enabled.
*/
log (...args) {
if (this.verbose) {
let str = fmt(`${green} ${args.shift()}`, ...args)
this._stderr.write(`${str}\n`)
}
}
/**
* Always log arguments as warning into stderr.
*/
warn (...args) {
let str = fmt(`${yellow} [WARNING] ${args.shift()}`, ...args)
this._stderr.write(`${str}\n`)
}
/**
* Always log arguments as error into stderr.
*/
error (...args) {
let str = fmt(`${red} [ERROR] ${args.shift()}`, ...args)
this._stderr.write(`${str}\n`)
}
/**
* Init a new timer.
* @param {String} label
*/
time (label) {
this._times[label] = Date.now()
}
/**
* End timer and log result into stderr.
* @param {String} label
* @param {String} format
*/
timeEnd (label, format = '%s: %dms') {
if (!this.verbose) {
return
}
let time = this._times[label]
if (!time) {
throw new Error(`No such label: ${label}`)
}
let duration = Date.now() - time
let str = fmt(`${chalk.green(checkmark)} ${format}`, label, duration)
this._stderr.write(`${str}\n`)
}
/**
* Log arguments into stderr if debug mode is enabled (will call all
* argument functions to allow "lazy" arguments).
*/
debug (...args) {
if (!this._debug) {
return
}
args = args.map(f => {
if (f instanceof Function) {
return f()
}
return f
})
let str = fmt(
`${style.grey.open}${chevron} [DEBUG] ${args.shift()}`,
...args,
style.grey.close
)
this._stderr.write(`${str}\n`)
}
}
export var empty = {
log: () => {},
warn: () => {},
error: () => {},
debug: () => {},
}
/**
* Checks if given object looks like a logger.
*
* If the `debug` function is missing (like for the `console` object),
* it will be set to an empty function in a newly returned object.
*
* If any other method is missing, an exception is thrown.
*
* @param {Object} logger
* @return {Logger}
* @throws {SassDocError}
*/
export function checkLogger (logger) {
const methods = ['log', 'warn', 'error']
.filter(x => !(x in logger) || !is.function(logger[x]))
if (methods.length) {
const missing = `"${methods.join('\`, \`')}"`
const s = methods.length > 1 ? 's' : ''
throw new errors.SassDocError(`Invalid logger, missing ${missing} method${s}`)
}
if ('debug' in logger) {
return logger
}
return {
log: logger.log,
warn: logger.warn,
error: logger.error,
debug: empty.debug,
}
}