|
|
'use strict'; const fs = require('fs'); const arrayUnion = require('array-union'); const merge2 = require('merge2'); const fastGlob = require('fast-glob'); const dirGlob = require('dir-glob'); const gitignore = require('./gitignore'); const {FilterStream, UniqueStream} = require('./stream-utils');
const DEFAULT_FILTER = () => false;
const isNegative = pattern => pattern[0] === '!';
const assertPatternsInput = patterns => { if (!patterns.every(pattern => typeof pattern === 'string')) { throw new TypeError('Patterns must be a string or an array of strings'); } };
const checkCwdOption = (options = {}) => { if (!options.cwd) { return; }
let stat; try { stat = fs.statSync(options.cwd); } catch { return; }
if (!stat.isDirectory()) { throw new Error('The `cwd` option must be a path to a directory'); } };
const getPathString = p => p.stats instanceof fs.Stats ? p.path : p;
const generateGlobTasks = (patterns, taskOptions) => { patterns = arrayUnion([].concat(patterns)); assertPatternsInput(patterns); checkCwdOption(taskOptions);
const globTasks = [];
taskOptions = { ignore: [], expandDirectories: true, ...taskOptions };
for (const [index, pattern] of patterns.entries()) { if (isNegative(pattern)) { continue; }
const ignore = patterns .slice(index) .filter(pattern => isNegative(pattern)) .map(pattern => pattern.slice(1));
const options = { ...taskOptions, ignore: taskOptions.ignore.concat(ignore) };
globTasks.push({pattern, options}); }
return globTasks; };
const globDirs = (task, fn) => { let options = {}; if (task.options.cwd) { options.cwd = task.options.cwd; }
if (Array.isArray(task.options.expandDirectories)) { options = { ...options, files: task.options.expandDirectories }; } else if (typeof task.options.expandDirectories === 'object') { options = { ...options, ...task.options.expandDirectories }; }
return fn(task.pattern, options); };
const getPattern = (task, fn) => task.options.expandDirectories ? globDirs(task, fn) : [task.pattern];
const getFilterSync = options => { return options && options.gitignore ? gitignore.sync({cwd: options.cwd, ignore: options.ignore}) : DEFAULT_FILTER; };
const globToTask = task => glob => { const {options} = task; if (options.ignore && Array.isArray(options.ignore) && options.expandDirectories) { options.ignore = dirGlob.sync(options.ignore); }
return { pattern: glob, options }; };
module.exports = async (patterns, options) => { const globTasks = generateGlobTasks(patterns, options);
const getFilter = async () => { return options && options.gitignore ? gitignore({cwd: options.cwd, ignore: options.ignore}) : DEFAULT_FILTER; };
const getTasks = async () => { const tasks = await Promise.all(globTasks.map(async task => { const globs = await getPattern(task, dirGlob); return Promise.all(globs.map(globToTask(task))); }));
return arrayUnion(...tasks); };
const [filter, tasks] = await Promise.all([getFilter(), getTasks()]); const paths = await Promise.all(tasks.map(task => fastGlob(task.pattern, task.options)));
return arrayUnion(...paths).filter(path_ => !filter(getPathString(path_))); };
module.exports.sync = (patterns, options) => { const globTasks = generateGlobTasks(patterns, options);
const tasks = []; for (const task of globTasks) { const newTask = getPattern(task, dirGlob.sync).map(globToTask(task)); tasks.push(...newTask); }
const filter = getFilterSync(options);
let matches = []; for (const task of tasks) { matches = arrayUnion(matches, fastGlob.sync(task.pattern, task.options)); }
return matches.filter(path_ => !filter(path_)); };
module.exports.stream = (patterns, options) => { const globTasks = generateGlobTasks(patterns, options);
const tasks = []; for (const task of globTasks) { const newTask = getPattern(task, dirGlob.sync).map(globToTask(task)); tasks.push(...newTask); }
const filter = getFilterSync(options); const filterStream = new FilterStream(p => !filter(p)); const uniqueStream = new UniqueStream();
return merge2(tasks.map(task => fastGlob.stream(task.pattern, task.options))) .pipe(filterStream) .pipe(uniqueStream); };
module.exports.generateGlobTasks = generateGlobTasks;
module.exports.hasMagic = (patterns, options) => [] .concat(patterns) .some(pattern => fastGlob.isDynamicPattern(pattern, options));
module.exports.gitignore = gitignore;
|