-
Notifications
You must be signed in to change notification settings - Fork 339
/
Copy pathfiles.js
132 lines (119 loc) · 3.56 KB
/
files.js
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
const { readFile, stat } = require('fs/promises')
const { parse, relative, basename } = require('path')
const { paths } = require('@govuk-frontend/config')
const { filesize } = require('filesize')
const { glob } = require('glob')
const yaml = require('js-yaml')
const { minimatch } = require('minimatch')
const slash = require('slash')
/**
* Check path exists
*
* @param {string} entryPath - File or directory path
* @returns {Promise<boolean>} Returns true for paths that exist
*/
async function hasPath(entryPath) {
try {
await stat(entryPath)
return true
} catch {
return false
}
}
/**
* Directory listing for path
*
* @param {string} directoryPath - Minimatch pattern to directory
* @param {import('glob').GlobOptionsWithFileTypesUnset} [options] - Glob options
* @returns {Promise<string[]>} File paths
*/
async function getListing(directoryPath, options = {}) {
const listing = await glob(slash(directoryPath), {
absolute: true,
nodir: true,
realpath: true,
...options
})
// Use relative paths
return listing
.map((entryPath) =>
relative(options.cwd?.toString() ?? paths.root, entryPath)
)
.sort()
}
/**
* Directory listing (directories only)
*
* @param {string} directoryPath - Minimatch pattern to directory
* @returns {Promise<string[]>} Directory names
*/
async function getDirectories(directoryPath) {
const listing = await getListing(`${slash(directoryPath)}/*/`, {
nodir: false
})
// Use directory names only
return listing.map((directoryPath) => basename(directoryPath)).sort()
}
/**
* Get file size entries
*
* @param {string} directoryPath - Minimatch pattern to directory
* @param {import('glob').GlobOptionsWithFileTypesUnset} [options] - Glob options
* @returns {Promise<[string, string][]>} - File entries with name and size
*/
async function getFileSizes(directoryPath, options = {}) {
const filesForAnalysis = await getListing(directoryPath, options)
return Promise.all(filesForAnalysis.map(getFileSize))
}
/**
* Get file size entry
*
* @param {string} filePath - File path
* @returns {Promise<[string, string]>} - File entry with name and size
*/
async function getFileSize(filePath) {
const { size } = await stat(filePath)
return [filePath, `${filesize(size, { base: 2 })}`]
}
/**
* Directory listing array filter
* Returns true for files matching every pattern
*
* @param {string[]} patterns - Minimatch patterns
* @returns {(entryPath: string) => boolean} Returns true for files matching every pattern
*/
const filterPath = (patterns) => (entryPath) => {
return patterns.every((pattern) => minimatch(entryPath, pattern))
}
/**
* Directory listing array mapper
* Runs callback for files matching every pattern
*
* @param {string[]} patterns - Minimatch patterns
* @param {(file: import('path').ParsedPath) => string | string[]} callback - Runs on files matching every pattern
* @returns {(entryPath: string) => string | string[]} Returns path (or array of paths)
*/
const mapPathTo = (patterns, callback) => (entryPath) => {
const isMatch = filterPath(patterns)
// Run callback on files matching every pattern (or original path)
return isMatch(entryPath) ? callback(parse(entryPath)) : entryPath
}
/**
* Read config from YAML file
*
* @param {string} configPath - File path to config
* @returns {Promise<any>} Config from YAML file
*/
async function getYaml(configPath) {
return yaml.load(await readFile(configPath, 'utf8'), { json: true })
}
module.exports = {
filterPath,
hasPath,
getDirectories,
getFileSizes,
getFileSize,
getListing,
getYaml,
mapPathTo
}