-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathglob-source.js
138 lines (115 loc) · 3.6 KB
/
glob-source.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
133
134
135
136
137
138
'use strict'
const fs = require('fs-extra')
const glob = require('it-glob')
const Path = require('path')
const errCode = require('err-code')
/**
* Create an async iterator that yields paths that match requested file paths.
*
* @param {Iterable|AsyncIterable|String} paths File system path(s) to glob from
* @param {Object} [options] Optional options
* @param {Boolean} [options.recursive] Recursively glob all paths in directories
* @param {Boolean} [options.hidden] Include .dot files in matched paths
* @param {Array<String>} [options.ignore] Glob paths to ignore
* @param {Boolean} [options.followSymlinks] follow symlinks
* @param {Boolean} [options.preserveMode] preserve mode
* @param {Boolean} [options.preserveMtime] preserve mtime
* @param {Boolean} [options.mode] mode to use - if preserveMode is true this will be ignored
* @param {Boolean} [options.mtime] mtime to use - if preserveMtime is true this will be ignored
* @yields {Object} File objects in the form `{ path: String, content: AsyncIterator<Buffer> }`
*/
module.exports = async function * globSource (paths, options) {
options = options || {}
if (typeof paths === 'string') {
paths = [paths]
}
const globSourceOptions = {
recursive: options.recursive,
glob: {
dot: Boolean(options.hidden),
ignore: Array.isArray(options.ignore) ? options.ignore : [],
follow: options.followSymlinks != null ? options.followSymlinks : true
}
}
// Check the input paths comply with options.recursive and convert to glob sources
for await (const path of paths) {
if (typeof path !== 'string') {
throw errCode(
new Error('Path must be a string'),
'ERR_INVALID_PATH',
{ path }
)
}
const absolutePath = Path.resolve(process.cwd(), path)
const stat = await fs.stat(absolutePath)
const prefix = Path.dirname(absolutePath)
let mode = options.mode
if (options.preserveMode) {
mode = stat.mode
}
let mtime = options.mtime
if (options.preserveMtime) {
mtime = parseInt(stat.mtimeMs / 1000)
}
if (stat.isDirectory()) {
yield {
path: `/${Path.basename(path)}`,
mode,
mtime
}
}
yield * toGlobSource({
path,
type: stat.isDirectory() ? 'dir' : 'file',
prefix,
mode,
mtime,
preserveMode: options.preserveMode,
preserveMtime: options.preserveMtime
}, globSourceOptions)
}
}
async function * toGlobSource ({ path, type, prefix, mode, mtime, preserveMode, preserveMtime }, options) {
options = options || {}
const baseName = Path.basename(path)
if (type === 'file') {
yield {
path: `/${baseName.replace(prefix, '')}`,
content: fs.createReadStream(Path.isAbsolute(path) ? path : Path.join(process.cwd(), path)),
mode,
mtime
}
return
}
if (type === 'dir' && !options.recursive) {
throw errCode(
new Error(`'${path}' is a directory and recursive option not set`),
'ERR_DIR_NON_RECURSIVE',
{ path }
)
}
const globOptions = Object.assign({}, options.glob, {
cwd: path,
nodir: false,
realpath: false,
absolute: true
})
for await (const p of glob(path, '**/*', globOptions)) {
const stat = await fs.stat(p)
if (preserveMode || preserveMtime) {
if (preserveMode) {
mode = stat.mode
}
if (preserveMtime) {
mtime = parseInt(stat.mtimeMs / 1000)
}
}
yield {
path: toPosix(p.replace(prefix, '')),
content: stat.isFile() ? fs.createReadStream(p) : undefined,
mode,
mtime
}
}
}
const toPosix = path => path.replace(/\\/g, '/')