tape-six 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,446 @@
1
+ import {_, Env, Variable, variable, isVariable, Unifier, isUnifier} from './env.js';
2
+
3
+ // Command
4
+
5
+ class Command {
6
+ constructor(f, l, r, e) {
7
+ this.f = f;
8
+ this.l = l;
9
+ this.r = r;
10
+ this.e = e;
11
+ }
12
+ }
13
+
14
+ // type wrapper
15
+
16
+ class Wrap extends Unifier {
17
+ constructor(type, o) {
18
+ super();
19
+ this.type = type;
20
+ this.object = o;
21
+ }
22
+ unify(val, ls, rs, env) {
23
+ const isWrapped = val instanceof Wrap,
24
+ value = isWrapped ? val.object : val;
25
+ if (!value || typeof value != 'object' || Array.isArray(this.object) !== Array.isArray(value)) return false;
26
+ if (Array.isArray(this.object)) {
27
+ if (!Array.isArray(value)) return false;
28
+ return isWrapped
29
+ ? unifyObjects(this.object, this.type, this, val.object, val.type, val, ls, rs, env)
30
+ : unifyObjects(this.object, this.type, this, val, env.openArrays ? 'open' : 'exact', null, ls, rs, env);
31
+ }
32
+ if (typeof Map == 'function' && this.object instanceof Map) {
33
+ if (!(value instanceof Map)) return false;
34
+ return isWrapped
35
+ ? unifyMaps(this.object, this.type, this, val.object, val.type, val, ls, rs, env)
36
+ : unifyMaps(this.object, this.type, this, val, env.openMaps ? 'open' : 'exact', null, ls, rs, env);
37
+ }
38
+ if (typeof Set == 'function' && this.object instanceof Set) {
39
+ if (!(value instanceof Set)) return false;
40
+ return isWrapped
41
+ ? unifySets(this.object, this.type, this, val.object, val.type, val, ls, rs, env)
42
+ : unifySets(this.object, this.type, this, val, env.openSets ? 'open' : 'exact', null, ls, rs, env);
43
+ }
44
+ return isWrapped
45
+ ? unifyObjects(this.object, this.type, this, val.object, val.type, val, ls, rs, env)
46
+ : unifyObjects(this.object, this.type, this, val, env.openObjects ? 'open' : 'exact', null, ls, rs, env);
47
+ }
48
+ }
49
+
50
+ const isWrapped = o => o instanceof Wrap;
51
+
52
+ const open = o => new Wrap('open', o);
53
+ const isOpen = o => o instanceof Wrap && o.type === 'open';
54
+
55
+ const soft = o => new Wrap('soft', o);
56
+ const isSoft = o => o instanceof Wrap && o.type === 'soft';
57
+
58
+ // registry of well-known constructors and filters
59
+
60
+ const registry = [
61
+ Date,
62
+ (l, r) => l instanceof Date && r instanceof Date && l.getTime() == r.getTime(),
63
+ RegExp,
64
+ (l, r) =>
65
+ l instanceof RegExp && r instanceof RegExp && l.source == r.source && l.global == r.global && l.multiline == r.multiline && l.ignoreCase == r.ignoreCase
66
+ ],
67
+ filters = [];
68
+
69
+ // possible well-known constructors
70
+
71
+ const unifyTypedArrays = Type => (l, r, ls, rs, env) => {
72
+ if (!(l instanceof Type) || !(r instanceof Type) || l.length != r.length) return false;
73
+ for (let i = 0; i < l.length; ++i) {
74
+ if (l[i] != r[i]) return false;
75
+ }
76
+ return true;
77
+ };
78
+
79
+ const addType = Type => registry.push(Type, unifyTypedArrays(Type));
80
+
81
+ typeof Int8Array == 'function' && addType(Int8Array);
82
+ typeof Uint8Array == 'function' && addType(Uint8Array);
83
+ typeof Uint8ClampedArray == 'function' && addType(Uint8ClampedArray);
84
+ typeof Int16Array == 'function' && addType(Int16Array);
85
+ typeof Uint16Array == 'function' && addType(Uint16Array);
86
+ typeof Int32Array == 'function' && addType(Int32Array);
87
+ typeof Uint32Array == 'function' && addType(Uint32Array);
88
+ typeof Float32Array == 'function' && addType(Float32Array);
89
+ typeof Float64Array == 'function' && addType(Float64Array);
90
+ typeof BigInt64Array == 'function' && addType(BigInt64Array);
91
+ typeof BigUint64Array == 'function' && addType(BigUint64Array);
92
+
93
+ const unifyDataView = (l, r, ls, rs, env) => {
94
+ if (!(l instanceof DataView) || !(r instanceof DataView) || l.byteLength != r.byteLength) return false;
95
+ for (let i = 0; i < l.byteLength; ++i) {
96
+ if (l.getUint8(i) != r.getUint8(i)) return false;
97
+ }
98
+ return true;
99
+ };
100
+ typeof DataView == 'function' && registry.push(DataView, unifyDataView);
101
+
102
+ const unifyArrayBuffer = (l, r, ls, rs, env) => {
103
+ if (!(l instanceof ArrayBuffer) || !(r instanceof ArrayBuffer) || l.byteLength != r.byteLength) return false;
104
+ return unifyTypedArrays(Uint8Array)(new Uint8Array(l), new Uint8Array(r), ls, rs, env);
105
+ };
106
+ typeof ArrayBuffer == 'function' && typeof Uint8Array == 'function' && registry.push(ArrayBuffer, unifyArrayBuffer);
107
+
108
+ const unifySet = (l, r, ls, rs, env) => {
109
+ if (!(l instanceof Set) || !(r instanceof Set) || l.size != r.size) return false;
110
+ for (const item of l) {
111
+ if (!r.has(item)) return false;
112
+ }
113
+ return true;
114
+ };
115
+ registry.push(Set, unifySet);
116
+
117
+ const unifyMap = (l, r, ls, rs, env) => {
118
+ if (!(l instanceof Map) || !(r instanceof Map) || l.size != r.size) return false;
119
+ for (const [key, value] of l) {
120
+ if (!r.has(key)) return false;
121
+ ls.push(value);
122
+ rs.push(r.get(key));
123
+ }
124
+ return true;
125
+ };
126
+ registry.push(Map, unifyMap);
127
+
128
+ // unification of maps
129
+
130
+ const mapOps = {
131
+ exact: {
132
+ exact: {
133
+ precheck: (l, r) => {
134
+ for (const key of l.keys()) {
135
+ if (!r.has(key)) return false;
136
+ }
137
+ return true;
138
+ }
139
+ },
140
+ open: {},
141
+ soft: {
142
+ fix: function () {
143
+ this.l.type = 'exact';
144
+ }
145
+ }
146
+ },
147
+ open: {
148
+ open: {},
149
+ soft: {}
150
+ },
151
+ soft: {
152
+ soft: {
153
+ update: function () {
154
+ for (const [key, value] of this.l) {
155
+ !this.r.has(key) && this.r.set(key, value);
156
+ }
157
+ for (const [key, value] of this.r) {
158
+ !this.l.has(key) && this.l.set(key, value);
159
+ }
160
+ }
161
+ }
162
+ }
163
+ };
164
+ mapOps.exact.exact.compare = mapOps.exact.open.compare = mapOps.exact.soft.compare = (l, r, ls, rs) => {
165
+ for (const [key, value] of r) {
166
+ if (!l.has(key)) return false;
167
+ ls.push(l.get(key));
168
+ rs.push(value);
169
+ }
170
+ return true;
171
+ };
172
+ mapOps.open.open.compare = mapOps.open.soft.compare = mapOps.soft.soft.compare = (l, r, ls, rs) => {
173
+ for (const [key, value] of r) {
174
+ if (!l.has(key)) continue;
175
+ ls.push(l.get(key));
176
+ rs.push(value);
177
+ }
178
+ return true;
179
+ };
180
+ mapOps.exact.soft.update = mapOps.open.soft.update = function () {
181
+ for (const [key, value] of this.l) {
182
+ !this.r.has(key) && this.r.set(key, value);
183
+ }
184
+ };
185
+
186
+ const unifyMaps = (l, lt, lm, r, rt, rm, ls, rs, env) => {
187
+ const ols = ls;
188
+ if (lt > rt) {
189
+ [l, lt, lm, ls, r, rt, rm, rs] = [r, rt, rm, rs, l, lt, lm, ls];
190
+ }
191
+ const ops = mapOps[lt][rt];
192
+ if (ops.precheck && !ops.precheck(l, r)) return false;
193
+ if (ops.fix && rm) ols.push(new Command(ops.fix, rm));
194
+ if (ops.update) ols.push(new Command(ops.update, l, r));
195
+ return ops.compare(l, r, ls, rs, env);
196
+ };
197
+
198
+ // unification of sets
199
+
200
+ const setOps = {
201
+ exact: {
202
+ exact: {
203
+ precheck: (l, r) => {
204
+ for (const key of l) {
205
+ if (!r.has(key)) return false;
206
+ }
207
+ return true;
208
+ }
209
+ },
210
+ open: {},
211
+ soft: {
212
+ fix: function () {
213
+ this.l.type = 'exact';
214
+ }
215
+ }
216
+ },
217
+ open: {
218
+ open: {},
219
+ soft: {}
220
+ },
221
+ soft: {
222
+ soft: {
223
+ update: function () {
224
+ for (const key of this.l) {
225
+ this.r.add(key);
226
+ }
227
+ for (const key of this.r) {
228
+ this.l.add(key);
229
+ }
230
+ }
231
+ }
232
+ }
233
+ };
234
+ setOps.exact.exact.compare = setOps.exact.open.compare = setOps.exact.soft.compare = setOps.open.open.compare = setOps.open.soft.compare = setOps.soft.soft.compare = () =>
235
+ true;
236
+ setOps.exact.soft.update = setOps.open.soft.update = function () {
237
+ for (const key of this.l) {
238
+ this.r.add(key);
239
+ }
240
+ };
241
+
242
+ const unifySets = (l, lt, lm, r, rt, rm, ls, rs, env) => {
243
+ const ols = ls;
244
+ if (lt > rt) {
245
+ [l, lt, lm, ls, r, rt, rm, rs] = [r, rt, rm, rs, l, lt, lm, ls];
246
+ }
247
+ const ops = setOps[lt][rt];
248
+ if (ops.precheck && !ops.precheck(l, r)) return false;
249
+ if (ops.fix && rm) ols.push(new Command(ops.fix, rm));
250
+ if (ops.update) ols.push(new Command(ops.update, l, r));
251
+ return ops.compare(l, r, ls, rs, env);
252
+ };
253
+
254
+ // unification of objects
255
+
256
+ const hasOwnProperty = Object.prototype.hasOwnProperty;
257
+
258
+ const objectOps = {
259
+ exact: {
260
+ exact: {
261
+ precheck: (l, r, env) => {
262
+ let lKeys = Object.keys(l),
263
+ rKeys = Object.keys(r);
264
+ if (lKeys.length != rKeys.length) return false;
265
+ if (env.symbols) {
266
+ lKeys = lKeys.concat(Object.getOwnPropertySymbols(l));
267
+ rKeys = rKeys.concat(Object.getOwnPropertySymbols(r));
268
+ }
269
+ if (lKeys.length != rKeys.length) return false;
270
+ return lKeys.every(k => hasOwnProperty.call(r, k));
271
+ }
272
+ },
273
+ open: {},
274
+ soft: {
275
+ fix: function () {
276
+ this.l.type = 'exact';
277
+ }
278
+ }
279
+ },
280
+ open: {
281
+ open: {},
282
+ soft: {}
283
+ },
284
+ soft: {
285
+ soft: {
286
+ update: function () {
287
+ let keys = Object.keys(this.l);
288
+ if (this.e.symbols) keys = keys.concat(Object.getOwnPropertySymbols(this.l));
289
+ for (const k of keys) {
290
+ !hasOwnProperty.call(this.r, k) && Object.defineProperty(this.r, k, Object.getOwnPropertyDescriptor(this.l, k));
291
+ }
292
+ keys = Object.keys(this.r);
293
+ if (this.e.symbols) keys = keys.concat(Object.getOwnPropertySymbols(this.r));
294
+ for (const k of keys) {
295
+ !hasOwnProperty.call(this.l, k) && Object.defineProperty(this.l, k, Object.getOwnPropertyDescriptor(this.r, k));
296
+ }
297
+ }
298
+ }
299
+ }
300
+ };
301
+ objectOps.exact.exact.compare = objectOps.exact.open.compare = objectOps.exact.soft.compare = (l, r, ls, rs, env) => {
302
+ let keys = Object.keys(r);
303
+ if (env.symbols) keys = keys.concat(Object.getOwnPropertySymbols(r));
304
+ return keys.every(k => {
305
+ if (hasOwnProperty.call(l, k)) {
306
+ ls.push(l[k]);
307
+ rs.push(r[k]);
308
+ return true;
309
+ }
310
+ return false;
311
+ });
312
+ };
313
+ objectOps.open.open.compare = objectOps.open.soft.compare = objectOps.soft.soft.compare = (l, r, ls, rs, env) => {
314
+ let keys = Object.keys(r);
315
+ if (env.symbols) keys = keys.concat(Object.getOwnPropertySymbols(r));
316
+ for (const k of keys) {
317
+ if (hasOwnProperty.call(l, k)) {
318
+ ls.push(l[k]);
319
+ rs.push(r[k]);
320
+ }
321
+ }
322
+ return true;
323
+ };
324
+ objectOps.exact.soft.update = objectOps.open.soft.update = function () {
325
+ let keys = Object.keys(this.l);
326
+ if (this.e.symbols) keys = keys.concat(Object.getOwnPropertySymbols(this.l));
327
+ for (const k of keys) {
328
+ !hasOwnProperty.call(this.r, k) && Object.defineProperty(this.r, k, Object.getOwnPropertyDescriptor(this.l, k));
329
+ }
330
+ };
331
+
332
+ const unifyObjects = (l, lt, lm, r, rt, rm, ls, rs, env) => {
333
+ const ols = ls;
334
+ if (lt > rt) {
335
+ [l, lt, lm, ls, r, rt, rm, rs] = [r, rt, rm, rs, l, lt, lm, ls];
336
+ }
337
+ const ops = objectOps[lt][rt];
338
+ if (ops.precheck && !ops.precheck(l, r, env)) return false;
339
+ if (ops.fix && rm) ols.push(new Command(ops.fix, rm, null, env));
340
+ if (ops.update) ols.push(new Command(ops.update, l, r, env));
341
+ return ops.compare(l, r, ls, rs, env);
342
+ };
343
+
344
+ // unification
345
+
346
+ const unify = (l, r, env, options) => {
347
+ if (env && !(env instanceof Env)) {
348
+ options = env;
349
+ env = null;
350
+ }
351
+ if (!env) {
352
+ env = new Env();
353
+ }
354
+ env = Object.assign(env, options);
355
+ // options: openObjects, openArrays, openMaps, openSets, circular, loose, ignoreFunctions, signedZero, symbols.
356
+ const ls = [l],
357
+ rs = [r],
358
+ lSeen = new Map(),
359
+ rSeen = new Map();
360
+ main: while (ls.length) {
361
+ // perform a command, or extract a pair
362
+ l = ls.pop();
363
+ if (l instanceof Command) {
364
+ l.f();
365
+ continue;
366
+ }
367
+ r = rs.pop();
368
+ // direct equality
369
+ if (l === r) {
370
+ if (env.circular && l && typeof l == 'object' && lSeen.has(l) ^ rSeen.has(r)) return null;
371
+ if (env.signedZero && l === 0 && 1 / l !== 1 / r) return null;
372
+ continue;
373
+ }
374
+ // anyvar
375
+ if (l === _ || r === _) continue;
376
+ // process variables (variables have priority)
377
+ if (l instanceof Variable) {
378
+ if (l.unify(r, ls, rs, env)) continue;
379
+ return null;
380
+ }
381
+ if (r instanceof Variable) {
382
+ if (r.unify(l, ls, rs, env)) continue;
383
+ return null;
384
+ }
385
+ // process circular dependencies
386
+ if (env.circular) {
387
+ const lIndex = lSeen.get(l);
388
+ if (typeof lIndex == 'number') {
389
+ if (lIndex === rSeen.get(r)) continue main;
390
+ return null;
391
+ } else {
392
+ if (rSeen.has(r)) return null;
393
+ }
394
+
395
+ l && typeof l == 'object' && lSeen.set(l, lSeen.size);
396
+ r && typeof r == 'object' && rSeen.set(r, rSeen.size);
397
+ }
398
+ // invoke custom unifiers
399
+ if (l instanceof Unifier) {
400
+ if (l.unify(r, ls, rs, env)) continue;
401
+ return null;
402
+ }
403
+ if (r instanceof Unifier) {
404
+ if (r.unify(l, ls, rs, env)) continue;
405
+ return null;
406
+ }
407
+ // process loose equality for non-objects and nulls
408
+ if (env.loose && !(l && r && typeof l == 'object' && typeof r == 'object') && l == r) continue main;
409
+ // check rough types
410
+ if (typeof l != typeof r) return null;
411
+ // reject unequal functions
412
+ if (typeof l == 'function' && env.ignoreFunctions) continue;
413
+ // special case: NaN
414
+ if (typeof l == 'number' && isNaN(l) && isNaN(r)) continue;
415
+ // cut off impossible combinations
416
+ if (typeof l != 'object' || !l || !r) return null;
417
+ // process registered constructors
418
+ const registry = unify.registry;
419
+ for (let i = 0; i < registry.length; i += 2) {
420
+ if (l instanceof registry[i] || r instanceof registry[i]) {
421
+ if (registry[i + 1](l, r, ls, rs, env)) continue main;
422
+ return null;
423
+ }
424
+ }
425
+ // process registered filters
426
+ const filters = unify.filters;
427
+ for (let i = 0; i < filters.length; i += 2) {
428
+ if (filters[i](l, r)) {
429
+ if (filters[i + 1](l, r, ls, rs, env)) continue main;
430
+ return null;
431
+ }
432
+ }
433
+ // process naked objects and arrays
434
+ const objectType = env.openObjects ? 'open' : 'exact';
435
+ if (!unifyObjects(l, objectType, null, r, objectType, null, ls, rs, env)) return null;
436
+ }
437
+ return env;
438
+ };
439
+
440
+ // exports
441
+
442
+ unify.registry = registry;
443
+ unify.filters = filters;
444
+
445
+ export {_, Env, Unifier, isUnifier, Variable, variable, isVariable, _ as any, open, soft, isOpen, isSoft, isWrapped};
446
+ export default unify;
@@ -0,0 +1,24 @@
1
+ import {isVariable} from '../env.js';
2
+
3
+ const replaceVars = env => (strings, ...vars) => {
4
+ let buffer = strings[0];
5
+ for(let i = 0; i < vars.length;) {
6
+ const v = vars[i];
7
+ if (isVariable(v)) {
8
+ buffer += v.get(env);
9
+ } else switch (typeof v) {
10
+ case 'string':
11
+ case 'number':
12
+ case 'symbol':
13
+ buffer += env.values[v];
14
+ break;
15
+ default:
16
+ buffer += v;
17
+ break;
18
+ }
19
+ buffer += strings[++i];
20
+ }
21
+ return buffer;
22
+ };
23
+
24
+ export default replaceVars;
@@ -0,0 +1,37 @@
1
+ import cluster from 'cluster';
2
+ import os from 'os';
3
+
4
+ import EventServer from '../utils/EventServer.js';
5
+
6
+ export default class TestWorker extends EventServer {
7
+ constructor(reporter, numberOfTasks = os.cpus().length, options = {}) {
8
+ super(reporter, numberOfTasks, options);
9
+ }
10
+ makeTask(fileName) {
11
+ const worker = cluster.fork({TAPE6_WORKER: 'yes', TAPE6_TAP: ''}),
12
+ id = String(worker.id);
13
+ worker.on('message', msg => {
14
+ if (msg.started) {
15
+ worker.send({id, fileName, options: this.options});
16
+ } else {
17
+ let done = false;
18
+ msg.events.forEach(event => {
19
+ this.report(id, event);
20
+ if (event.type === 'end' && event.test === 0) done = true;
21
+ });
22
+ worker.send(done? {done: true} : {received: true});
23
+ }
24
+ });
25
+ worker.on('exit', (code, signal) => {
26
+ let errorMsg = '';
27
+ if (signal) {
28
+ errorMsg = `Worker ${id} was killed by signal: ${signal}`;
29
+ } else if (code) {
30
+ errorMsg = `Worker ${id} exited with error code: ${code}`;
31
+ }
32
+ errorMsg && this.report(id, {type: 'comment', name: 'fail to load: ' + errorMsg, test: 0});
33
+ this.close(id);
34
+ });
35
+ return id;
36
+ }
37
+ }
@@ -0,0 +1,56 @@
1
+ import {promises as fsp} from 'fs';
2
+ import path from 'path';
3
+
4
+ import {listing, wildToRe} from './listing.js';
5
+ import {union, exclude} from '../utils/fileSets.js';
6
+
7
+ export const resolvePatterns = async (rootFolder, patterns) => {
8
+ let result = [];
9
+ for (const item of patterns) {
10
+ if (item.length && item[0] == '!') {
11
+ result = exclude(result, wildToRe(rootFolder, item.substr(1)));
12
+ } else {
13
+ result = union(result, await listing(rootFolder, item));
14
+ }
15
+ }
16
+ return result.map(fileName => path.relative(rootFolder, fileName));
17
+ };
18
+
19
+ export const resolveTests = async (rootFolder, type, traceFn) => {
20
+ let cfg;
21
+ // check tape6.json
22
+ try {
23
+ cfg = JSON.parse(await fsp.readFile(path.join(rootFolder, 'tape6.json')));
24
+ } catch (error) {
25
+ traceFn && traceFn('Cannot read tape6.json');
26
+ }
27
+ // check package.json, "tape6" section
28
+ if (!cfg) {
29
+ try {
30
+ const pkg = JSON.parse(await fsp.readFile(path.join(rootFolder, 'package.json')));
31
+ cfg = pkg.tape6;
32
+ } catch (error) {
33
+ traceFn && traceFn('Cannot read package.json');
34
+ }
35
+ }
36
+ // check well-known files
37
+ if (!cfg) {
38
+ cfg = {[type]: {tests: '/tests/test-' + type + '.*js'}};
39
+ }
40
+ // determine test patterns
41
+ let patterns = [];
42
+ if (cfg[type]) {
43
+ if (Array.isArray(cfg[type].tests)) {
44
+ patterns = patterns.concat(cfg[type].tests);
45
+ } else if (typeof cfg[type].tests == 'string') {
46
+ patterns.push(cfg[type].tests);
47
+ }
48
+ }
49
+ if (Array.isArray(cfg.tests)) {
50
+ patterns = patterns.concat(cfg.tests);
51
+ } else if (typeof cfg.tests == 'string') {
52
+ patterns.push(cfg.tests);
53
+ }
54
+ // resolve patterns
55
+ return resolvePatterns(rootFolder, patterns);
56
+ };
@@ -0,0 +1,78 @@
1
+ import {promises as fsp} from 'fs';
2
+ import path from 'path';
3
+
4
+ const notSep = '[^\\' + path.sep + ']*',
5
+ notDotSep = '[^\\.\\' + path.sep + ']*';
6
+
7
+ const sanitizeRe = string => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
8
+ const prepRe = (string, substitute, allowDot) => {
9
+ const parts = string.split('*'),
10
+ startsWithStar = !parts[0],
11
+ result = parts.map(sanitizeRe).join(substitute);
12
+ return startsWithStar && !allowDot ? notDotSep + result : result;
13
+ }
14
+ const mergeWildcards = folders => folders.reduce((acc, part) => ((part || !acc.length || acc[acc.length - 1]) && acc.push(part), acc), []);
15
+
16
+ const listFiles = async (rootFolder, folders, baseRe, parents) => {
17
+ const dir = path.join(rootFolder, parents.join(path.sep)),
18
+ files = await fsp.readdir(dir, {withFileTypes: true});
19
+
20
+ let result = [];
21
+
22
+ if (!folders.length) {
23
+ for (const file of files) {
24
+ if (file.isFile() && baseRe.test(file.name)) result.push(path.join(dir, file.name));
25
+ }
26
+ return result;
27
+ }
28
+
29
+ const theRest = folders.slice(1);
30
+
31
+ if (folders[0]) {
32
+ for (const file of files) {
33
+ if (file.isDirectory() && folders[0].test(file.name)) {
34
+ result = result.concat(await listFiles(rootFolder, theRest, baseRe, parents.concat(file.name)));
35
+ }
36
+ }
37
+ return result;
38
+ }
39
+
40
+ result = result.concat(await listFiles(rootFolder, theRest, baseRe, parents));
41
+ for (const file of files) {
42
+ if (file.isDirectory()) {
43
+ result = result.concat(await listFiles(rootFolder, folders, baseRe, parents.concat(file.name)));
44
+ }
45
+ }
46
+ return result;
47
+ };
48
+
49
+ export const listing = async (rootFolder, wildcard) => {
50
+ const parsed = path.parse(wildcard),
51
+ baseRe = new RegExp('^' + prepRe(parsed.name, '.*') + prepRe(parsed.ext, '.*', true) + '$'),
52
+ folders = mergeWildcards(
53
+ parsed.dir
54
+ .split(path.sep)
55
+ .filter(part => part)
56
+ .map(part => (part === '**' ? null : new RegExp('^' + prepRe(part, notSep) + '$')))
57
+ );
58
+ return listFiles(rootFolder, folders, baseRe, []);
59
+ };
60
+
61
+ export const wildToRe = (rootFolder, wildcard) => {
62
+ if (wildcard.length && wildcard[wildcard.length - 1] == path.sep) wildcard += '**';
63
+ const parsed = path.parse(path.join(rootFolder, wildcard)),
64
+ folders = parsed.dir
65
+ .substr(parsed.root.length)
66
+ .split(path.sep)
67
+ .filter(part => part)
68
+ .reduce((acc, part) => {
69
+ if (part == '**') {
70
+ acc += '(?:|.*\\' + path.sep + ')';
71
+ } else {
72
+ acc += prepRe(part, notSep) + '\\' + path.sep;
73
+ }
74
+ return acc;
75
+ }, parsed.root),
76
+ name = parsed.name == '**' && !parsed.ext ? '.*' : prepRe(parsed.name, notSep);
77
+ return new RegExp('^' + folders + name + prepRe(parsed.ext, notSep, true) + '$');
78
+ };