var fs = require('fs'); var path = require('path'); var merge2 = require('merge2'); var fastGlob = require('fast-glob'); var dirGlob = require('dir-glob'); var process = require('process'); var gitIgnore = require('ignore'); var slash = require('slash'); var node_url = require('url'); var node_stream = require('stream'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var fs__default = /*#__PURE__*/_interopDefault(fs); var path__default = /*#__PURE__*/_interopDefault(path); var merge2__default = /*#__PURE__*/_interopDefault(merge2); var fastGlob__default = /*#__PURE__*/_interopDefault(fastGlob); var dirGlob__default = /*#__PURE__*/_interopDefault(dirGlob); var process__default = /*#__PURE__*/_interopDefault(process); var gitIgnore__default = /*#__PURE__*/_interopDefault(gitIgnore); var slash__default = /*#__PURE__*/_interopDefault(slash); const toPath = urlOrPath => urlOrPath instanceof URL ? node_url.fileURLToPath(urlOrPath) : urlOrPath; class FilterStream extends node_stream.Transform { constructor(filter) { super({ objectMode: true, transform(data, encoding, callback) { callback(undefined, filter(data) ? data : undefined); }, }); } } const isNegativePattern = pattern => pattern[0] === '!'; const ignoreFilesGlobOptions = { ignore: [ '**/node_modules', '**/flow-typed', '**/coverage', '**/.git', ], absolute: true, dot: true, }; const GITIGNORE_FILES_PATTERN = '**/.gitignore'; const applyBaseToPattern = (pattern, base) => isNegativePattern(pattern) ? '!' + path__default.default.posix.join(base, pattern.slice(1)) : path__default.default.posix.join(base, pattern); const parseIgnoreFile = (file, cwd) => { const base = slash__default.default(path__default.default.relative(cwd, path__default.default.dirname(file.filePath))); return file.content .split(/\r?\n/) .filter(line => line && !line.startsWith('#')) .map(pattern => applyBaseToPattern(pattern, base)); }; const toRelativePath = (fileOrDirectory, cwd) => { cwd = slash__default.default(cwd); if (path__default.default.isAbsolute(fileOrDirectory)) { if (slash__default.default(fileOrDirectory).startsWith(cwd)) { return path__default.default.relative(cwd, fileOrDirectory); } throw new Error(`Path ${fileOrDirectory} is not in cwd ${cwd}`); } return fileOrDirectory; }; const getIsIgnoredPredicate = (files, cwd) => { const patterns = files.flatMap(file => parseIgnoreFile(file, cwd)); const ignores = gitIgnore__default.default().add(patterns); return fileOrDirectory => { fileOrDirectory = toPath(fileOrDirectory); fileOrDirectory = toRelativePath(fileOrDirectory, cwd); return fileOrDirectory ? ignores.ignores(slash__default.default(fileOrDirectory)) : false; }; }; const normalizeOptions$1 = (options = {}) => ({ cwd: toPath(options.cwd) || process__default.default.cwd(), }); const isIgnoredByIgnoreFiles = async (patterns, options) => { const {cwd} = normalizeOptions$1(options); const paths = await fastGlob__default.default(patterns, {cwd, ...ignoreFilesGlobOptions}); const files = await Promise.all( paths.map(async filePath => ({ filePath, content: await fs__default.default.promises.readFile(filePath, 'utf8'), })), ); return getIsIgnoredPredicate(files, cwd); }; const isIgnoredByIgnoreFilesSync = (patterns, options) => { const {cwd} = normalizeOptions$1(options); const paths = fastGlob__default.default.sync(patterns, {cwd, ...ignoreFilesGlobOptions}); const files = paths.map(filePath => ({ filePath, content: fs__default.default.readFileSync(filePath, 'utf8'), })); return getIsIgnoredPredicate(files, cwd); }; const isGitIgnored = options => isIgnoredByIgnoreFiles(GITIGNORE_FILES_PATTERN, options); const isGitIgnoredSync = options => isIgnoredByIgnoreFilesSync(GITIGNORE_FILES_PATTERN, options); const assertPatternsInput = patterns => { if (patterns.some(pattern => typeof pattern !== 'string')) { throw new TypeError('Patterns must be a string or an array of strings'); } }; const toPatternsArray = patterns => { patterns = [...new Set([patterns].flat())]; assertPatternsInput(patterns); return patterns; }; const checkCwdOption = options => { if (!options.cwd) { return; } let stat; try { stat = fs__default.default.statSync(options.cwd); } catch { return; } if (!stat.isDirectory()) { throw new Error('The `cwd` option must be a path to a directory'); } }; const normalizeOptions = (options = {}) => { options = { ignore: [], expandDirectories: true, ...options, cwd: toPath(options.cwd), }; checkCwdOption(options); return options; }; const normalizeArguments = fn => async (patterns, options) => fn(toPatternsArray(patterns), normalizeOptions(options)); const normalizeArgumentsSync = fn => (patterns, options) => fn(toPatternsArray(patterns), normalizeOptions(options)); const getIgnoreFilesPatterns = options => { const {ignoreFiles, gitignore} = options; const patterns = ignoreFiles ? toPatternsArray(ignoreFiles) : []; if (gitignore) { patterns.push(GITIGNORE_FILES_PATTERN); } return patterns; }; const getFilter = async options => { const ignoreFilesPatterns = getIgnoreFilesPatterns(options); return createFilterFunction( ignoreFilesPatterns.length > 0 && await isIgnoredByIgnoreFiles(ignoreFilesPatterns, {cwd: options.cwd}), ); }; const getFilterSync = options => { const ignoreFilesPatterns = getIgnoreFilesPatterns(options); return createFilterFunction( ignoreFilesPatterns.length > 0 && isIgnoredByIgnoreFilesSync(ignoreFilesPatterns, {cwd: options.cwd}), ); }; const createFilterFunction = isIgnored => { const seen = new Set(); return fastGlobResult => { const path = fastGlobResult.path || fastGlobResult; const pathKey = path__default.default.normalize(path); const seenOrIgnored = seen.has(pathKey) || (isIgnored && isIgnored(path)); seen.add(pathKey); return !seenOrIgnored; }; }; const unionFastGlobResults = (results, filter) => results.flat().filter(fastGlobResult => filter(fastGlobResult)); const unionFastGlobStreams = (streams, filter) => merge2__default.default(streams).pipe(new FilterStream(fastGlobResult => filter(fastGlobResult))); const convertNegativePatterns = (patterns, options) => { const tasks = []; while (patterns.length > 0) { const index = patterns.findIndex(pattern => isNegativePattern(pattern)); if (index === -1) { tasks.push({patterns, options}); break; } const ignorePattern = patterns[index].slice(1); for (const task of tasks) { task.options.ignore.push(ignorePattern); } if (index !== 0) { tasks.push({ patterns: patterns.slice(0, index), options: { ...options, ignore: [ ...options.ignore, ignorePattern, ], }, }); } patterns = patterns.slice(index + 1); } return tasks; }; const getDirGlobOptions = (options, cwd) => ({ ...(cwd ? {cwd} : {}), ...(Array.isArray(options) ? {files: options} : options), }); const generateTasks = async (patterns, options) => { const globTasks = convertNegativePatterns(patterns, options); const {cwd, expandDirectories} = options; if (!expandDirectories) { return globTasks; } const patternExpandOptions = getDirGlobOptions(expandDirectories, cwd); const ignoreExpandOptions = cwd ? {cwd} : undefined; return Promise.all( globTasks.map(async task => { let {patterns, options} = task; [ patterns, options.ignore, ] = await Promise.all([ dirGlob__default.default(patterns, patternExpandOptions), dirGlob__default.default(options.ignore, ignoreExpandOptions), ]); return {patterns, options}; }), ); }; const generateTasksSync = (patterns, options) => { const globTasks = convertNegativePatterns(patterns, options); const {cwd, expandDirectories} = options; if (!expandDirectories) { return globTasks; } const patternExpandOptions = getDirGlobOptions(expandDirectories, cwd); const ignoreExpandOptions = cwd ? {cwd} : undefined; return globTasks.map(task => { let {patterns, options} = task; patterns = dirGlob__default.default.sync(patterns, patternExpandOptions); options.ignore = dirGlob__default.default.sync(options.ignore, ignoreExpandOptions); return {patterns, options}; }); }; const globby = normalizeArguments(async (patterns, options) => { const [ tasks, filter, ] = await Promise.all([ generateTasks(patterns, options), getFilter(options), ]); const results = await Promise.all(tasks.map(task => fastGlob__default.default(task.patterns, task.options))); return unionFastGlobResults(results, filter); }); const globbySync = normalizeArgumentsSync((patterns, options) => { const tasks = generateTasksSync(patterns, options); const filter = getFilterSync(options); const results = tasks.map(task => fastGlob__default.default.sync(task.patterns, task.options)); return unionFastGlobResults(results, filter); }); const globbyStream = normalizeArgumentsSync((patterns, options) => { const tasks = generateTasksSync(patterns, options); const filter = getFilterSync(options); const streams = tasks.map(task => fastGlob__default.default.stream(task.patterns, task.options)); return unionFastGlobStreams(streams, filter); }); const isDynamicPattern = normalizeArgumentsSync( (patterns, options) => patterns.some(pattern => fastGlob__default.default.isDynamicPattern(pattern, options)), ); const generateGlobTasks = normalizeArguments(generateTasks); const generateGlobTasksSync = normalizeArgumentsSync(generateTasksSync); exports.generateGlobTasks = generateGlobTasks; exports.generateGlobTasksSync = generateGlobTasksSync; exports.globby = globby; exports.globbyStream = globbyStream; exports.globbySync = globbySync; exports.isDynamicPattern = isDynamicPattern; exports.isGitIgnored = isGitIgnored; exports.isGitIgnoredSync = isGitIgnoredSync;