UNPKG

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