Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
log.js169 linesDownload Raw Back to lib
1'use strict'
2
3const { log } = require('proc-log')
4const { format } = require('util')
5
6// helper to emit log messages with a predefined prefix
7const withPrefix = (prefix) => log.LEVELS.reduce((acc, level) => {
8  acc[level] = (...args) => log[level](prefix, ...args)
9  return acc
10}, {})
11
12// very basic ansi color generator
13const COLORS = {
14  wrap: (str, colors) => {
15    const codes = colors.filter(c => typeof c === 'number')
16    return `\x1b[${codes.join(';')}m${str}\x1b[0m`
17  },
18  inverse: 7,
19  fg: {
20    black: 30,
21    red: 31,
22    green: 32,
23    yellow: 33,
24    blue: 34,
25    magenta: 35,
26    cyan: 36,
27    white: 37
28  },
29  bg: {
30    black: 40,
31    red: 41,
32    green: 42,
33    yellow: 43,
34    blue: 44,
35    magenta: 45,
36    cyan: 46,
37    white: 47
38  }
39}
40
41class Logger {
42  #buffer = []
43  #paused = null
44  #level = null
45  #stream = null
46
47  // ordered from loudest to quietest
48  #levels = [{
49    id: 'silly',
50    display: 'sill',
51    style: { inverse: true }
52  }, {
53    id: 'verbose',
54    display: 'verb',
55    style: { fg: 'cyan', bg: 'black' }
56  }, {
57    id: 'info',
58    style: { fg: 'green' }
59  }, {
60    id: 'http',
61    style: { fg: 'green', bg: 'black' }
62  }, {
63    id: 'notice',
64    style: { fg: 'cyan', bg: 'black' }
65  }, {
66    id: 'warn',
67    display: 'WARN',
68    style: { fg: 'black', bg: 'yellow' }
69  }, {
70    id: 'error',
71    display: 'ERR!',
72    style: { fg: 'red', bg: 'black' }
73  }]
74
75  constructor (stream) {
76    process.on('log', (...args) => this.#onLog(...args))
77    this.#levels = new Map(this.#levels.map((level, index) => [level.id, { ...level, index }]))
78    this.level = 'info'
79    this.stream = stream
80    log.pause()
81  }
82
83  get stream () {
84    return this.#stream
85  }
86
87  set stream (stream) {
88    this.#stream = stream
89  }
90
91  get level () {
92    return this.#levels.get(this.#level) ?? null
93  }
94
95  set level (level) {
96    this.#level = this.#levels.get(level)?.id ?? null
97  }
98
99  isVisible (level) {
100    return this.level?.index <= this.#levels.get(level)?.index ?? -1
101  }
102
103  #onLog (...args) {
104    const [level] = args
105
106    if (level === 'pause') {
107      this.#paused = true
108      return
109    }
110
111    if (level === 'resume') {
112      this.#paused = false
113      this.#buffer.forEach((b) => this.#log(...b))
114      this.#buffer.length = 0
115      return
116    }
117
118    if (this.#paused) {
119      this.#buffer.push(args)
120      return
121    }
122
123    this.#log(...args)
124  }
125
126  #color (str, { fg, bg, inverse }) {
127    if (!this.#stream?.isTTY) {
128      return str
129    }
130
131    return COLORS.wrap(str, [
132      COLORS.fg[fg],
133      COLORS.bg[bg],
134      inverse && COLORS.inverse
135    ])
136  }
137
138  #log (levelId, msgPrefix, ...args) {
139    if (!this.isVisible(levelId) || typeof this.#stream?.write !== 'function') {
140      return
141    }
142
143    const level = this.#levels.get(levelId)
144
145    const prefixParts = [
146      this.#color('gyp', { fg: 'white', bg: 'black' }),
147      this.#color(level.display ?? level.id, level.style)
148    ]
149    if (msgPrefix) {
150      prefixParts.push(this.#color(msgPrefix, { fg: 'magenta' }))
151    }
152
153    const prefix = prefixParts.join(' ').trim() + ' '
154    const lines = format(...args).split(/\r?\n/).map(l => prefix + l.trim())
155
156    this.#stream.write(lines.join('\n') + '\n')
157  }
158}
159
160// used to suppress logs in tests
161const NULL_LOGGER = !!process.env.NODE_GYP_NULL_LOGGER
162
163module.exports = {
164  logger: new Logger(NULL_LOGGER ? null : process.stderr),
165  stdout: NULL_LOGGER ? () => {} : (...args) => console.log(...args),
166  withPrefix,
167  ...log
168}
169 
codekingpro/portable-devtools · Team Ai