1 | const fs = require('fs');
|
2 | const globrex = require('globrex');
|
3 | const { promisify } = require('util');
|
4 | const globalyzer = require('globalyzer');
|
5 | const { join, resolve, relative } = require('path');
|
6 | const isHidden = /(^|[\\\/])\.[^\\\/\.]/g;
|
7 | const readdir = promisify(fs.readdir);
|
8 | const stat = promisify(fs.stat);
|
9 | let CACHE = {};
|
10 |
|
11 | async function walk(output, prefix, lexer, opts, dirname='', level=0) {
|
12 | const rgx = lexer.segments[level];
|
13 | const dir = resolve(opts.cwd, prefix, dirname);
|
14 | const files = await readdir(dir);
|
15 | const { dot, filesOnly } = opts;
|
16 |
|
17 | let i=0, len=files.length, file;
|
18 | let fullpath, relpath, stats, isMatch;
|
19 |
|
20 | for (; i < len; i++) {
|
21 | fullpath = join(dir, file=files[i]);
|
22 | relpath = dirname ? join(dirname, file) : file;
|
23 | if (!dot && isHidden.test(relpath)) continue;
|
24 | isMatch = lexer.regex.test(relpath);
|
25 |
|
26 | if ((stats=CACHE[relpath]) === void 0) {
|
27 | CACHE[relpath] = stats = fs.lstatSync(fullpath);
|
28 | }
|
29 |
|
30 | if (!stats.isDirectory()) {
|
31 | isMatch && output.push(relative(opts.cwd, fullpath));
|
32 | continue;
|
33 | }
|
34 |
|
35 | if (rgx && !rgx.test(file)) continue;
|
36 | !filesOnly && isMatch && output.push(join(prefix, relpath));
|
37 |
|
38 | await walk(output, prefix, lexer, opts, relpath, rgx && rgx.toString() !== lexer.globstar && level + 1);
|
39 | }
|
40 | }
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 | module.exports = async function (str, opts={}) {
|
54 | if (!str) return [];
|
55 |
|
56 | let glob = globalyzer(str);
|
57 |
|
58 | opts.cwd = opts.cwd || '.';
|
59 |
|
60 | if (!glob.isGlob) {
|
61 | try {
|
62 | let resolved = resolve(opts.cwd, str);
|
63 | let dirent = await stat(resolved);
|
64 | if (opts.filesOnly && !dirent.isFile()) return [];
|
65 |
|
66 | return opts.absolute ? [resolved] : [str];
|
67 | } catch (err) {
|
68 | if (err.code != 'ENOENT') throw err;
|
69 |
|
70 | return [];
|
71 | }
|
72 | }
|
73 |
|
74 | if (opts.flush) CACHE = {};
|
75 |
|
76 | let matches = [];
|
77 | const { path } = globrex(glob.glob, { filepath:true, globstar:true, extended:true });
|
78 |
|
79 | path.globstar = path.globstar.toString();
|
80 | await walk(matches, glob.base, path, opts, '.', 0);
|
81 |
|
82 | return opts.absolute ? matches.map(x => resolve(opts.cwd, x)) : matches;
|
83 | };
|