-
Notifications
You must be signed in to change notification settings - Fork 0
/
mod.ts
94 lines (80 loc) · 3.25 KB
/
mod.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
import 'https://deno.land/x/hackle/init.ts'
import { isAbsolute, globToRegExp, normalize, joinGlobs, relative } from 'https://deno.land/std@0.71.0/path/mod.ts'
export interface GlobData {
match: (string | RegExp)[] | string | RegExp
ignore: (string | RegExp)[] | string | RegExp
}
export interface ConfigOptions {
/**
* What `evaluateGlob` should do with absolute files
* - `error` - errors out
* - `make-glob-absolute` - prepends `Deno.cwd()` onto the glob
* - `remove-slash-one` - removes any leading `/`'s from the file path
* - `make-file-relative` - tries to make the file path relative to `Deno.cwd()`
*
* @default 'make-file-relative'
*/
absolutePathsAction?: 'error' | 'make-glob-absolute' | 'remove-slash-one' | 'make-file-relative'
}
export interface EvaluateGlobsParams extends ConfigOptions {
/** The file to be evaluated */
file: string
/** The globs the file is to be tested by */
glob: GlobData
}
/**
* Returns true if the file was included, but not excluded.
* Files should be passed in as relative paths.
* The first `./` part of the file or glob will be removed before testing
*
* > All Globs should be relative, preferably without the first `./` part
*/
export function checkFile({ file, absolutePathsAction, glob: { match: include, ignore: exclude } }: EvaluateGlobsParams): boolean {
const globIsFile = (file: string, glob: string | RegExp): boolean => {
file = normalize(file)
const evaluate = (file: string, glob: string | RegExp): boolean => {
if (typeof glob === 'string') return globToRegExp(glob).test(file)
else return glob.test(file)
}
if (isAbsolute(file)) {
if (absolutePathsAction === 'error')
throw new Error(`Encountered an absolute path while 'absolutePathsAction' was set to 'error'`)
else if (absolutePathsAction === 'remove-slash-one') return globIsFile(file.slice(1), glob)
else if (absolutePathsAction === 'make-glob-absolute' && typeof glob === 'string')
return evaluate(file, joinGlobs([Deno.cwd(), glob]))
else if (!absolutePathsAction || absolutePathsAction === 'make-file-relative')
return globIsFile(relative(Deno.cwd(), file), glob)
else
throw new Error(
`'${absolutePathsAction}' is an invalid value for 'absolutePathsAction'. See the glob-filter docs for details`
)
} else if (typeof glob === 'string' && glob.startsWith('./')) return globIsFile(file, glob.slice(2))
else if (file.startsWith('./')) return globIsFile(file.slice(2), glob)
return evaluate(file, glob)
}
const makeArray = <T>(data: T[] | T) => (Array.isArray(data) ? data : [data])
let didInclude = false
for (let glob of makeArray(include)) {
if (globIsFile(file, glob)) {
didInclude = true
break
}
}
if (!didInclude) return false
let didExclude = false
for (let glob of makeArray(exclude)) {
if (globIsFile(file, glob)) {
didExclude = true
break
}
}
return !didExclude
}
/**
* Filters out the files that were either not included in `globs.include`, or excluded from `globs.exclude`.
* Files should be passed in as relative paths.
* The first `./` part of the file or glob will be removed before testing
*/
export function filterFiles(files: string[], globs: GlobData, options: ConfigOptions = {}) {
return files.filter(file => checkFile({ file, glob: globs, ...options }))
}