-
-
Notifications
You must be signed in to change notification settings - Fork 482
/
Copy pathglob.ts
142 lines (126 loc) · 3.46 KB
/
glob.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
130
131
132
133
134
135
136
137
138
139
140
141
142
import { Minimatch, MinimatchOptions } from 'minimatch'
import { GlobCache } from './readdir.js'
import { GlobWalker, Pattern } from './walker.js'
type MatchSet = Minimatch['set']
type GlobSet = Exclude<Minimatch['globSet'], undefined>
export interface GlobOptions extends MinimatchOptions {
ignore?: string | string[]
follow?: boolean
mark?: boolean
nodir?: boolean
nounique?: boolean
nosort?: boolean
cwd?: string
realpath?: boolean
absolute?: boolean
cache?: GlobCache
}
export class Glob {
pattern: string[]
ignore?: string | string[]
follow: boolean
dot: boolean
mark: boolean
nodir: boolean
nounique: boolean
nosort: boolean
cwd: string
matchSet: MatchSet
globSet: GlobSet
realpath: boolean
nonull: boolean
absolute: boolean
matchBase: boolean
windowsPathsNoEscape: boolean
noglobstar: boolean
cache: GlobCache
constructor(
pattern: string | string[],
options: GlobOptions | Glob = {}
) {
this.ignore = options.ignore
this.follow = !!options.follow
this.dot = !!options.dot
this.nodir = !!options.nodir
this.mark = !!options.mark
this.nounique = !!options.nounique
this.nosort = !!options.nosort
this.cwd = options.cwd || ''
if (process.platform === 'win32') {
this.cwd = this.cwd.replace(/\\/g, '/')
}
this.realpath = !!options.realpath
this.nonull = !!options.nonull
this.absolute = !!options.absolute
this.cache = options.cache || Object.create(null)
this.noglobstar = !!options.noglobstar
this.matchBase = !!options.matchBase
if (typeof pattern === 'string') {
pattern = [pattern]
}
this.windowsPathsNoEscape =
!!options.windowsPathsNoEscape ||
(options as GlobOptions).allowWindowsEscape === false
if (this.windowsPathsNoEscape) {
pattern = pattern.map(p => p.replace(/\\/g, '/'))
}
if (this.matchBase) {
if (options.noglobstar) {
throw new TypeError('base matching requires globstar')
}
pattern = pattern.map(p => (p.includes('/') ? p : `**/${p}`))
}
this.pattern = pattern
const mmo = { ...options, nonegate: true, nocomment: true }
const mms = this.pattern.map(p => new Minimatch(p, mmo))
this.matchSet = mms.reduce((set: MatchSet, m) => set.concat(m.set), [])
this.globSet = mms.reduce(
(set: GlobSet, m) => set.concat(m.globSet),
[]
)
}
doNonull(matches: string[], i: number) {
if (!matches.length && this.nonull) {
const gs: string | undefined = this.globSet[i]
if (gs) {
return [gs]
} else {
return []
}
}
return matches
}
async process() {
return this.finish(
await Promise.all(
this.matchSet.map(async (set, i) => {
if (!set.length) {
return []
}
const matches = await this.getWalker(set as Pattern).walk()
return this.doNonull(matches, i)
})
)
)
}
finish(matches: string[][]): string[] {
const raw = matches.reduce((set, m) => set.concat(m), [])
const flat = this.nounique ? raw : [...new Set(raw)]
return this.nosort
? flat
: flat.sort((a, b) => a.localeCompare(b, 'en'))
}
getWalker(set: Pattern) {
return new GlobWalker(set, '', this)
}
processSync() {
return this.finish(
this.matchSet.map((set, i) => {
if (!set.length) {
return []
}
return this.doNonull(this.getWalker(set as Pattern).walkSync(), i)
})
)
}
}