UNPKG

2.45 kBJavaScriptView Raw
1const fs = require('fs');
2const globrex = require('globrex');
3const globalyzer = require('globalyzer');
4const { join, resolve, relative } = require('path');
5const isHidden = /(^|[\\\/])\.[^\\\/\.]/g;
6
7let CACHE = {};
8
9function walk(output, prefix, lexer, opts, dirname='', level=0) {
10 const rgx = lexer.segments[level];
11 const dir = resolve(opts.cwd, prefix, dirname);
12 const files = fs.readdirSync(dir);
13 const { dot, filesOnly } = opts;
14
15 let i=0, len=files.length, file;
16 let fullpath, relpath, stats, isMatch;
17
18 for (; i < len; i++) {
19 fullpath = join(dir, file=files[i]);
20 relpath = dirname ? join(dirname, file) : file;
21 if (!dot && isHidden.test(relpath)) continue;
22 isMatch = lexer.regex.test(relpath);
23
24 if ((stats=CACHE[relpath]) === void 0) {
25 CACHE[relpath] = stats = fs.lstatSync(fullpath);
26 }
27
28 if (!stats.isDirectory()) {
29 isMatch && output.push(relative(opts.cwd, fullpath));
30 continue;
31 }
32
33 if (rgx && !rgx.test(file)) continue;
34 !filesOnly && isMatch && output.push(join(prefix, relpath));
35
36 walk(output, prefix, lexer, opts, relpath, rgx && rgx.toString() !== lexer.globstar && level + 1);
37 }
38}
39
40/**
41 * Find files using bash-like globbing.
42 * All paths are normalized compared to node-glob.
43 * @param {String} str Glob string
44 * @param {String} [options.cwd='.'] Current working directory
45 * @param {Boolean} [options.dot=false] Include dotfile matches
46 * @param {Boolean} [options.absolute=false] Return absolute paths
47 * @param {Boolean} [options.filesOnly=false] Do not include folders if true
48 * @param {Boolean} [options.flush=false] Reset cache object
49 * @returns {Array} array containing matching files
50 */
51module.exports = function (str, opts={}) {
52 if (!str) return [];
53
54 let glob = globalyzer(str);
55
56 opts.cwd = opts.cwd || '.';
57
58 if (!glob.isGlob) {
59 try {
60 let resolved = resolve(opts.cwd, str);
61 let dirent = fs.statSync(resolved);
62 if (opts.filesOnly && !dirent.isFile()) return [];
63
64 return opts.absolute ? [resolved] : [str];
65 } catch (err) {
66 if (err.code != 'ENOENT') throw err;
67
68 return [];
69 }
70 }
71
72 if (opts.flush) CACHE = {};
73
74 let matches = [];
75 const { path } = globrex(glob.glob, { filepath:true, globstar:true, extended:true });
76
77 path.globstar = path.globstar.toString();
78 walk(matches, glob.base, path, opts, '.', 0);
79
80 return opts.absolute ? matches.map(x => resolve(opts.cwd, x)) : matches;
81};