-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpipe.js
More file actions
261 lines (226 loc) · 6.76 KB
/
Copy pathpipe.js
File metadata and controls
261 lines (226 loc) · 6.76 KB
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
import { fileURLToPath } from 'url';
import { parse, sep, posix, join } from 'path';
import { realpathSync } from 'fs';
import { isLetter } from './utils.js';
// --------------------------------------------------------------------------- //
// resolves symbolic links, normalises path etc
const realPath = _path => realpathSync(_path);
// --------------------------------------------------------------------------- //
/**
* Sanitises input path into a posix path.
*
* Leaves drive letters intact.
*
* @function posixPath
* @param {string} _path - The path to be sanitised.
* @return {string} The sanitised posix path.
*/
const posixPath = _path => _path.split(sep).join(posix.sep);
// ensure _path is a posix path
// --------------------------------------------------------------------------- //
/**
* Cleans a file URL into a path.
*
* Uses fileURLToPath from the url standard library.
*
* @function cleanFileURL
* @param {string} _path - The file URL to be cleaned.
* @return {string} The clean path.
*/
const cleanFileURL = _path => {
// check if --path is a file URL
// do this first because cleanSysRoot will parse a file URL wrong
// and fileURLToPath returns path in some annoying format
if (_path.toLowerCase().startsWith('file:')) {
console.log('path is a file URL, cleaning..');
return fileURLToPath(_path);
} else {
return _path;
}
};
// --------------------------------------------------------------------------- //
/**
* Trims 'C:' from system drive paths.
*
* Leaves other drive letters and delimiters intact.
*
* Clean --path C: drive root into unix / root.
*
* @function cleanSysRoot
* @param {string} _path - The path to be cleaned.
* @return {string} The clean path.
*/
const cleanSysRoot = _path => {
// https://en.wikipedia.org/wiki/Drive_letter_assignment#Common_assignments
// will not catch file url paths
if (isLetter(_path[0]) && _path[0].toLowerCase() !== 'c') {
// is letter drive so leave it alone
return _path;
}
// slice path.dir by this many chars
let n = 0;
// surely this could be improved...
switch (parse(_path).root.toLowerCase()) {
case '/':
// alg already so just return
return _path;
case 'c:/':
n = 3;
break;
case 'c:\\':
n = 3;
break;
case 'c:\\\\':
n = 4;
break;
case '//':
console.log(`unexpected '//' root!`);
n = 2;
break;
case '\\':
console.log(`unexpected '\\' root!`);
n = 1;
break;
case '\\\\':
console.log(`unexpected '\\\\' root!`);
n = 2;
break;
case '':
console.error('[pipe.js] empty path detected:', _path);
break;
default:
console.error(
`[path root switch statement error] path root: '${parse(_path).root}'`
);
break;
}
if (n) {
// doesn't join use '/' as sep? so why did i need the prepended '/'?
// console.log('old path:', _path);
_path = join('/', parse(_path).dir.slice(n), parse(_path).base);
// console.log('new path:', _path);
// return _path;
}
return _path;
};
// --------------------------------------------------------------------------- //
/**
* Catches an error with the '/' unix root in a bash shell.
* When '/' root is used, bash thinks root = 'C:/Program Files/Git'.
* Returns a clean unix root path.
*
* @function cleanBashRoot
* @param {string} _path - The path to be cleaned.
* @return {string} The clean unix path.
* */
const cleanBashRoot = _path => {
// check for git path
if (_path.startsWith('C:/Program Files/Git')) {
// --path came from bash shell and started with '/'
return _path.replace('C:/Program Files/Git', '');
} else {
return _path;
}
};
// --------------------------------------------------------------------------- //
/**
* Create a n pipe composer using spread and reduce.
*
* Is fully synchronous and does not handle promises.
*
* @function syncPipe
* @return {function} The pipe composer function.
* */
// sync version
const syncPipe =
(...funcs) =>
val =>
funcs.reduce((chain, func) => func(chain), val);
// --------------------------------------------------------------------------- //
// returns a function that contains promises
const asyncPipe =
(...funcs) =>
val =>
funcs.reduce(async (chain, func) => func(await chain), val);
// const pipeAsyncFunctions = (...fns) => arg =>
// fns.reduce((p, f) => p.then(f), Promise.resolve(arg));
// const sum = asyncPipe(
// x => x + 1,
// x => new Promise(resolve => setTimeout(() => resolve(x + 2), 1000)),
// x => x + 3,
// async x => (await x) + 4
// );
// (async () => {
// console.log(await sum(5)); // 15 (after one second)
// })();
// --------------------------------------------------------------------------- //
// async sleep(ms) timer that alters path (for async debugging)
// returns a Promise that alters path
const sleep = _path => {
return new Promise(resolve => {
setTimeout(() => resolve(_path + '/sleep/'), 2000);
});
};
// generic logger of a value passing through a pipe
// returns value back to pipe after logging
const log = x => {
// is it possible to detect the previous function name?
// a solution: wrap call to log in another function with 2 args
// args are x and a optional message to explain what is being logged
console.log('pipe-log:', x);
return x;
};
// --------------------------------------------------------------------------- //
/**
* Compose path cleaning sync pipe for the output filepaths of a glob search.
* *
* @function cleanGlobSyncPipe
* @return {function} The composed glob path cleaning pipe.
*/
const cleanGlobSyncPipe = syncPipe(cleanSysRoot, posixPath);
// --------------------------------------------------------------------------- //
/**
* Compose the cwd cleaning sync pipe.
*
* Assume: process.cwd() is always absolute and not a file url.
*
* @function cleanCwdSyncPipe
* @return {function} The composed cwd cleaning sync pipe.
*/
const cleanCwdSyncPipe = syncPipe(cleanBashRoot, cleanGlobSyncPipe);
// --------------------------------------------------------------------------- //
// these composed pipes could accept _path and return result directly?
/**
* Compose the path cleaning async pipe.
*
* @function cleanPathAsyncPipe
* @return {function} The composed path cleaning pipe.
*/
const cleanPathAsyncPipe = asyncPipe(
cleanBashRoot,
cleanFileURL,
realPath,
cleanGlobSyncPipe
);
// --------------------------------------------------------------------------- //
/**
* Windows filesystem pipe functions.
*
* @module Pipe
*
* */
export {
realPath,
posixPath,
cleanFileURL,
cleanSysRoot,
cleanBashRoot,
syncPipe,
asyncPipe,
cleanGlobSyncPipe,
cleanCwdSyncPipe,
cleanPathAsyncPipe,
sleep,
log
};
// --------------------------------------------------------------------------- //