/
utils.ts
129 lines (109 loc) · 2.96 KB
/
utils.ts
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
import fs from 'fs'
import glob from 'globby'
import resolveFrom from 'resolve-from'
import strip from 'strip-json-comments'
export type External =
| string
| RegExp
| ((id: string, parentId?: string) => boolean)
export function isExternal(
externals: External | External[],
id: string,
parentId?: string
) {
id = slash(id)
if (!Array.isArray(externals)) {
externals = [externals]
}
for (const external of externals) {
if (
typeof external === 'string' &&
(id === external || id.includes(`/node_modules/${external}/`))
) {
return true
}
if (external instanceof RegExp) {
if (external.test(id)) {
return true
}
}
if (typeof external === 'function') {
if (external(id, parentId)) {
return true
}
}
}
return false
}
export function getPostcss(): null | typeof import('postcss') {
const p = resolveFrom.silent(process.cwd(), 'postcss')
return p && require(p)
}
export function localRequire(moduleName: string) {
const p = resolveFrom.silent(process.cwd(), moduleName)
return p && require(p)
}
export function pathExists(p: string) {
return new Promise((resolve) => {
fs.access(p, (err) => {
resolve(!err)
})
})
}
export async function removeFiles(patterns: string[], dir: string) {
const files = await glob(patterns, {
cwd: dir,
absolute: true,
})
await Promise.all(files.map((file) => fs.promises.unlink(file)))
}
export function debouncePromise<T extends unknown[]>(
fn: (...args: T) => Promise<void>,
delay: number,
onError: (err: unknown) => void
) {
let timeout: ReturnType<typeof setTimeout> | undefined
let promiseInFly: Promise<void> | undefined
let callbackPending: (() => void) | undefined
return function debounced(...args: Parameters<typeof fn>) {
if (promiseInFly) {
callbackPending = () => {
debounced(...args)
callbackPending = undefined
}
} else {
if (timeout != null) clearTimeout(timeout)
timeout = setTimeout(() => {
timeout = undefined
promiseInFly = fn(...args)
.catch(onError)
.finally(() => {
promiseInFly = undefined
if (callbackPending) callbackPending()
})
}, delay)
}
}
}
// Taken from https://github.com/sindresorhus/slash/blob/main/index.js (MIT)
export function slash(path: string) {
const isExtendedLengthPath = /^\\\\\?\\/.test(path)
const hasNonAscii = /[^\u0000-\u0080]+/.test(path)
if (isExtendedLengthPath || hasNonAscii) {
return path
}
return path.replace(/\\/g, '/')
}
type Truthy<T> = T extends false | '' | 0 | null | undefined ? never : T // from lodash
export function truthy<T>(value: T): value is Truthy<T> {
return Boolean(value)
}
export function jsoncParse(data: string) {
try {
return new Function('return ' + strip(data).trim())()
} catch {
// Silently ignore any error
// That's what tsc/jsonc-parser did after all
return {}
}
}