codekingpro/portable-devtools
114k
1const EE = require('node:events')
2const fs = require('node:fs')
3const { log, time } = require('proc-log')
4
5const INITIAL_TIMER = 'npm'
6
7class Timers extends EE {
8 #file
9 #timing
10
11 #unfinished = new Map()
12 #finished = {}
13
14 constructor () {
15 super()
16 this.on()
17 time.start(INITIAL_TIMER)
18 this.started = this.#unfinished.get(INITIAL_TIMER)
19 }
20
21 on () {
22 process.on('time', this.#timeHandler)
23 }
24
25 off () {
26 process.off('time', this.#timeHandler)
27 }
28
29 load ({ path, timing } = {}) {
30 this.#timing = timing
31 this.#file = `${path}timing.json`
32 }
33
34 finish (metadata) {
35 time.end(INITIAL_TIMER)
36
37 for (const [name, timer] of this.#unfinished) {
38 log.silly('unfinished npm timer', name, timer)
39 }
40
41 if (!this.#timing) {
42 // Not in timing mode, nothing else to do here
43 return
44 }
45
46 try {
47 this.#writeFile(metadata)
48 log.info('timing', `Timing info written to: ${this.#file}`)
49 } catch (e) {
50 log.warn('timing', `could not write timing file: ${e}`)
51 }
52 }
53
54 #writeFile (metadata) {
55 const globalStart = this.started
56 const globalEnd = this.#finished[INITIAL_TIMER]
57 const content = {
58 metadata,
59 timers: this.#finished,
60 // add any unfinished timers with their relative start/end
61 unfinishedTimers: [...this.#unfinished.entries()].reduce((acc, [name, start]) => {
62 acc[name] = [start - globalStart, globalEnd - globalStart]
63 return acc
64 }, {}),
65 }
66 fs.writeFileSync(this.#file, JSON.stringify(content) + '\n')
67 }
68
69 #timeHandler = (level, name) => {
70 const now = Date.now()
71 switch (level) {
72 case time.KEYS.start:
73 this.#unfinished.set(name, now)
74 break
75 case time.KEYS.end: {
76 if (this.#unfinished.has(name)) {
77 const ms = now - this.#unfinished.get(name)
78 this.#finished[name] = ms
79 this.#unfinished.delete(name)
80 log.timing(name, `Completed in ${ms}ms`)
81 } else {
82 log.silly('timing', `Tried to end timer that doesn't exist: ${name}`)
83 }
84 }
85 }
86 }
87}
88
89module.exports = Timers
90 