pax_global_header00006660000000000000000000000064143456577070014534gustar00rootroot0000000000000052 comment=bfd2555ac743b8543b1895c86cf50da41d1ae9c3 globby-13.1.3/000077500000000000000000000000001434565770700130775ustar00rootroot00000000000000globby-13.1.3/.editorconfig000066400000000000000000000002571434565770700155600ustar00rootroot00000000000000root = true [*] indent_style = tab end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.yml] indent_style = space indent_size = 2 globby-13.1.3/.gitattributes000066400000000000000000000000231434565770700157650ustar00rootroot00000000000000* text=auto eol=lf globby-13.1.3/.github/000077500000000000000000000000001434565770700144375ustar00rootroot00000000000000globby-13.1.3/.github/funding.yml000066400000000000000000000001601434565770700166110ustar00rootroot00000000000000github: sindresorhus open_collective: sindresorhus tidelift: npm/globby custom: https://sindresorhus.com/donate globby-13.1.3/.github/security.md000066400000000000000000000002631434565770700166310ustar00rootroot00000000000000# Security Policy To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. globby-13.1.3/.github/workflows/000077500000000000000000000000001434565770700164745ustar00rootroot00000000000000globby-13.1.3/.github/workflows/main.yml000066400000000000000000000010451434565770700201430ustar00rootroot00000000000000name: CI on: - push - pull_request jobs: test: name: Node.js ${{ matrix.node-version }} on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: node-version: - 18 - 16 - 14 os: - ubuntu-latest - macos-latest - windows-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - run: npm install - run: npm test globby-13.1.3/.gitignore000066400000000000000000000000471434565770700150700ustar00rootroot00000000000000node_modules yarn.lock bench *.tmp tmp globby-13.1.3/.npmrc000066400000000000000000000000231434565770700142120ustar00rootroot00000000000000package-lock=false globby-13.1.3/bench.js000066400000000000000000000053611434565770700145210ustar00rootroot00000000000000import process from 'node:process'; import fs from 'node:fs'; import path from 'node:path'; import {fileURLToPath} from 'node:url'; import Benchmark from 'benchmark'; import rimraf from 'rimraf'; import * as globbyMainBranch from '@globby/main-branch'; import gs from 'glob-stream'; import fastGlob from 'fast-glob'; import {globby, globbySync, globbyStream} from './index.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const BENCH_DIR = 'bench'; const runners = [ { name: 'globby async (working directory)', run: globby, }, { name: 'globby async (upstream/main)', run: globbyMainBranch.globby, }, { name: 'globby sync (working directory)', run: globbySync, }, { name: 'globby sync (upstream/main)', run: globbyMainBranch.globbySync, }, { name: 'globby stream (working directory)', run: patterns => new Promise(resolve => { globbyStream(patterns).on('data', () => {}).on('end', resolve); }), }, { name: 'globby stream (upstream/main)', run: patterns => new Promise(resolve => { globbyMainBranch.globbyStream(patterns).on('data', () => {}).on('end', resolve); }), }, { name: 'glob-stream', run: patterns => new Promise(resolve => { gs(patterns).on('data', () => {}).on('end', resolve); }), }, { name: 'fast-glob async', run: fastGlob, }, { name: 'fast-glob sync', run: fastGlob.sync, }, ]; const benchs = [ { name: 'negative globs (some files inside dir)', patterns: [ 'a/*', '!a/c*', ], }, { name: 'negative globs (whole dir)', patterns: [ 'a/*', '!a/**', ], }, { name: 'multiple positive globs', patterns: [ 'a/*', 'b/*', ], }, ]; const before = () => { process.chdir(__dirname); rimraf.sync(BENCH_DIR); fs.mkdirSync(BENCH_DIR); process.chdir(BENCH_DIR); const directories = ['a', 'b'] .map(directory => `${directory}/`); for (const directory of directories) { fs.mkdirSync(directory); for (let i = 0; i < 500; i++) { fs.writeFileSync(directory + (i < 100 ? 'c' : 'd') + i, ''); } } }; const after = () => { process.chdir(__dirname); rimraf.sync(BENCH_DIR); }; const suites = []; for (const {name, patterns} of benchs) { const suite = new Benchmark.Suite(name, { onStart() { before(); console.log(`[*] Started Benchmarks "${this.name}"`); }, onCycle(event) { console.log(`[+] ${String(event.target)}`); }, onComplete() { after(); console.log(`\nFastest is ${this.filter('fastest').map('name')} \n`); }, }); for (const {name, run} of runners) { suite.add(name, run.bind(undefined, patterns)); } suites.push(suite); } let index = 0; const run = suite => { suite.on('complete', () => { const next = suites[++index]; if (next) { run(next); } }); suite.run({async: true}); }; run(suites[0]); globby-13.1.3/fixtures/000077500000000000000000000000001434565770700147505ustar00rootroot00000000000000globby-13.1.3/fixtures/gitignore/000077500000000000000000000000001434565770700167375ustar00rootroot00000000000000globby-13.1.3/fixtures/gitignore/.gitignore000066400000000000000000000000171434565770700207250ustar00rootroot00000000000000foo.js !bar.js globby-13.1.3/fixtures/gitignore/bar.js000066400000000000000000000001361434565770700200410ustar00rootroot00000000000000import test from 'ava'; import fn from '..'; test(t => { t.is(fn('foo'), fn('foobar')); }); globby-13.1.3/fixtures/ignore-files/000077500000000000000000000000001434565770700173335ustar00rootroot00000000000000globby-13.1.3/fixtures/ignore-files/.eslintignore000066400000000000000000000000251434565770700220330ustar00rootroot00000000000000ignored-by-eslint.js globby-13.1.3/fixtures/ignore-files/.prettierignore000066400000000000000000000000271434565770700223750ustar00rootroot00000000000000ignored-by-prettier.js globby-13.1.3/fixtures/multiple-negation/000077500000000000000000000000001434565770700204055ustar00rootroot00000000000000globby-13.1.3/fixtures/multiple-negation/!!unicorn.js000066400000000000000000000000001434565770700225100ustar00rootroot00000000000000globby-13.1.3/fixtures/multiple-negation/!unicorn.js000066400000000000000000000000001434565770700224470ustar00rootroot00000000000000globby-13.1.3/fixtures/multiple-negation/.gitignore000066400000000000000000000000401434565770700223670ustar00rootroot00000000000000*.js !!unicorn.js !!!unicorn.js globby-13.1.3/fixtures/negative/000077500000000000000000000000001434565770700165525ustar00rootroot00000000000000globby-13.1.3/fixtures/negative/.gitignore000066400000000000000000000000151434565770700205360ustar00rootroot00000000000000*.js !foo.js globby-13.1.3/fixtures/negative/foo.js000066400000000000000000000000351434565770700176710ustar00rootroot00000000000000console.log('no semicolon'); globby-13.1.3/ignore.js000066400000000000000000000050201434565770700147150ustar00rootroot00000000000000import process from 'node:process'; import fs from 'node:fs'; import path from 'node:path'; import fastGlob from 'fast-glob'; import gitIgnore from 'ignore'; import slash from 'slash'; import {toPath, isNegativePattern} from './utilities.js'; const ignoreFilesGlobOptions = { ignore: [ '**/node_modules', '**/flow-typed', '**/coverage', '**/.git', ], absolute: true, dot: true, }; export const GITIGNORE_FILES_PATTERN = '**/.gitignore'; const applyBaseToPattern = (pattern, base) => isNegativePattern(pattern) ? '!' + path.posix.join(base, pattern.slice(1)) : path.posix.join(base, pattern); const parseIgnoreFile = (file, cwd) => { const base = slash(path.relative(cwd, path.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(cwd); if (path.isAbsolute(fileOrDirectory)) { if (slash(fileOrDirectory).startsWith(cwd)) { return path.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().add(patterns); return fileOrDirectory => { fileOrDirectory = toPath(fileOrDirectory); fileOrDirectory = toRelativePath(fileOrDirectory, cwd); return fileOrDirectory ? ignores.ignores(slash(fileOrDirectory)) : false; }; }; const normalizeOptions = (options = {}) => ({ cwd: toPath(options.cwd) || process.cwd(), }); export const isIgnoredByIgnoreFiles = async (patterns, options) => { const {cwd} = normalizeOptions(options); const paths = await fastGlob(patterns, {cwd, ...ignoreFilesGlobOptions}); const files = await Promise.all( paths.map(async filePath => ({ filePath, content: await fs.promises.readFile(filePath, 'utf8'), })), ); return getIsIgnoredPredicate(files, cwd); }; export const isIgnoredByIgnoreFilesSync = (patterns, options) => { const {cwd} = normalizeOptions(options); const paths = fastGlob.sync(patterns, {cwd, ...ignoreFilesGlobOptions}); const files = paths.map(filePath => ({ filePath, content: fs.readFileSync(filePath, 'utf8'), })); return getIsIgnoredPredicate(files, cwd); }; export const isGitIgnored = options => isIgnoredByIgnoreFiles(GITIGNORE_FILES_PATTERN, options); export const isGitIgnoredSync = options => isIgnoredByIgnoreFilesSync(GITIGNORE_FILES_PATTERN, options); globby-13.1.3/index.d.ts000066400000000000000000000156231434565770700150070ustar00rootroot00000000000000import {URL} from 'node:url'; // TODO: Remove this when https://github.com/DefinitelyTyped/DefinitelyTyped/issues/34960 is fixed. import {Options as FastGlobOptions, Entry} from 'fast-glob'; export type GlobEntry = Entry; export interface GlobTask { readonly patterns: string[]; readonly options: Options; } export type ExpandDirectoriesOption = | boolean | readonly string[] | {files?: readonly string[]; extensions?: readonly string[]}; type FastGlobOptionsWithoutCwd = Omit; export interface Options extends FastGlobOptionsWithoutCwd { /** If set to `true`, `globby` will automatically glob directories for you. If you define an `Array` it will only glob files that matches the patterns inside the `Array`. You can also define an `Object` with `files` and `extensions` like in the example below. Note that if you set this option to `false`, you won't get back matched directories unless you set `onlyFiles: false`. @default true @example ``` import {globby} from 'globby'; const paths = await globby('images', { expandDirectories: { files: ['cat', 'unicorn', '*.jpg'], extensions: ['png'] } }); console.log(paths); //=> ['cat.png', 'unicorn.png', 'cow.jpg', 'rainbow.jpg'] ``` */ readonly expandDirectories?: ExpandDirectoriesOption; /** Respect ignore patterns in `.gitignore` files that apply to the globbed files. @default false */ readonly gitignore?: boolean; /** Glob patterns to look for ignore files, which are then used to ignore globbed files. This is a more generic form of the `gitignore` option, allowing you to find ignore files with a [compatible syntax](http://git-scm.com/docs/gitignore). For instance, this works with Babel's `.babelignore`, Prettier's `.prettierignore`, or ESLint's `.eslintignore` files. @default undefined */ readonly ignoreFiles?: string | readonly string[]; /** The current working directory in which to search. @default process.cwd() */ readonly cwd?: URL | string; } export interface GitignoreOptions { readonly cwd?: URL | string; } export type GlobbyFilterFunction = (path: URL | string) => boolean; /** Find files and directories using glob patterns. Note that glob patterns can only contain forward-slashes, not backward-slashes, so if you want to construct a glob pattern from path components, you need to use `path.posix.join()` instead of `path.join()`. @param patterns - See the supported [glob patterns](https://github.com/sindresorhus/globby#globbing-patterns). @param options - See the [`fast-glob` options](https://github.com/mrmlnc/fast-glob#options-3) in addition to the ones in this package. @returns The matching paths. @example ``` import {globby} from 'globby'; const paths = await globby(['*', '!cake']); console.log(paths); //=> ['unicorn', 'rainbow'] ``` */ export function globby( patterns: string | readonly string[], options: Options & {objectMode: true} ): Promise; export function globby( patterns: string | readonly string[], options?: Options ): Promise; /** Find files and directories using glob patterns. Note that glob patterns can only contain forward-slashes, not backward-slashes, so if you want to construct a glob pattern from path components, you need to use `path.posix.join()` instead of `path.join()`. @param patterns - See the supported [glob patterns](https://github.com/sindresorhus/globby#globbing-patterns). @param options - See the [`fast-glob` options](https://github.com/mrmlnc/fast-glob#options-3) in addition to the ones in this package. @returns The matching paths. */ export function globbySync( patterns: string | readonly string[], options: Options & {objectMode: true} ): GlobEntry[]; export function globbySync( patterns: string | readonly string[], options?: Options ): string[]; /** Find files and directories using glob patterns. Note that glob patterns can only contain forward-slashes, not backward-slashes, so if you want to construct a glob pattern from path components, you need to use `path.posix.join()` instead of `path.join()`. @param patterns - See the supported [glob patterns](https://github.com/sindresorhus/globby#globbing-patterns). @param options - See the [`fast-glob` options](https://github.com/mrmlnc/fast-glob#options-3) in addition to the ones in this package. @returns The stream of matching paths. @example ``` import {globbyStream} from 'globby'; for await (const path of globbyStream('*.tmp')) { console.log(path); } ``` */ export function globbyStream( patterns: string | readonly string[], options?: Options ): NodeJS.ReadableStream; /** Note that you should avoid running the same tasks multiple times as they contain a file system cache. Instead, run this method each time to ensure file system changes are taken into consideration. @param patterns - See the supported [glob patterns](https://github.com/sindresorhus/globby#globbing-patterns). @param options - See the [`fast-glob` options](https://github.com/mrmlnc/fast-glob#options-3) in addition to the ones in this package. @returns An object in the format `{pattern: string, options: object}`, which can be passed as arguments to [`fast-glob`](https://github.com/mrmlnc/fast-glob). This is useful for other globbing-related packages. */ export function generateGlobTasks( patterns: string | readonly string[], options?: Options ): Promise; /** @see generateGlobTasks @returns An object in the format `{pattern: string, options: object}`, which can be passed as arguments to [`fast-glob`](https://github.com/mrmlnc/fast-glob). This is useful for other globbing-related packages. */ export function generateGlobTasksSync( patterns: string | readonly string[], options?: Options ): GlobTask[]; /** Note that the options affect the results. This function is backed by [`fast-glob`](https://github.com/mrmlnc/fast-glob#isdynamicpatternpattern-options). @param patterns - See the supported [glob patterns](https://github.com/sindresorhus/globby#globbing-patterns). @param options - See the [`fast-glob` options](https://github.com/mrmlnc/fast-glob#options-3). @returns Whether there are any special glob characters in the `patterns`. */ export function isDynamicPattern( patterns: string | readonly string[], options?: FastGlobOptionsWithoutCwd & { /** The current working directory in which to search. @default process.cwd() */ readonly cwd?: URL | string; } ): boolean; /** `.gitignore` files matched by the ignore config are not used for the resulting filter function. @returns A filter function indicating whether a given path is ignored via a `.gitignore` file. @example ``` import {isGitIgnored} from 'globby'; const isIgnored = await isGitIgnored(); console.log(isIgnored('some/file')); ``` */ export function isGitIgnored(options?: GitignoreOptions): Promise; /** @see isGitIgnored @returns A filter function indicating whether a given path is ignored via a `.gitignore` file. */ export function isGitIgnoredSync(options?: GitignoreOptions): GlobbyFilterFunction; globby-13.1.3/index.js000066400000000000000000000135011434565770700145440ustar00rootroot00000000000000import fs from 'node:fs'; import nodePath from 'node:path'; import merge2 from 'merge2'; import fastGlob from 'fast-glob'; import dirGlob from 'dir-glob'; import { GITIGNORE_FILES_PATTERN, isIgnoredByIgnoreFiles, isIgnoredByIgnoreFilesSync, } from './ignore.js'; import {FilterStream, toPath, isNegativePattern} from './utilities.js'; 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.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 = nodePath.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(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(patterns, patternExpandOptions), dirGlob(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.sync(patterns, patternExpandOptions); options.ignore = dirGlob.sync(options.ignore, ignoreExpandOptions); return {patterns, options}; }); }; export 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(task.patterns, task.options))); return unionFastGlobResults(results, filter); }); export const globbySync = normalizeArgumentsSync((patterns, options) => { const tasks = generateTasksSync(patterns, options); const filter = getFilterSync(options); const results = tasks.map(task => fastGlob.sync(task.patterns, task.options)); return unionFastGlobResults(results, filter); }); export const globbyStream = normalizeArgumentsSync((patterns, options) => { const tasks = generateTasksSync(patterns, options); const filter = getFilterSync(options); const streams = tasks.map(task => fastGlob.stream(task.patterns, task.options)); return unionFastGlobStreams(streams, filter); }); export const isDynamicPattern = normalizeArgumentsSync( (patterns, options) => patterns.some(pattern => fastGlob.isDynamicPattern(pattern, options)), ); export const generateGlobTasks = normalizeArguments(generateTasks); export const generateGlobTasksSync = normalizeArgumentsSync(generateTasksSync); export { isGitIgnored, isGitIgnoredSync, } from './ignore.js'; globby-13.1.3/index.test-d.ts000066400000000000000000000111631434565770700157570ustar00rootroot00000000000000import {Buffer} from 'node:buffer'; import {URL} from 'node:url'; import {expectType} from 'tsd'; import { GlobTask, GlobEntry, GlobbyFilterFunction, globby, globbySync, globbyStream, generateGlobTasks, generateGlobTasksSync, isDynamicPattern, isGitIgnored, isGitIgnoredSync, } from './index.js'; const __dirname = ''; // Globby expectType>(globby('*.tmp')); expectType>(globby(['a.tmp', '*.tmp', '!{c,d,e}.tmp'])); expectType>(globby('*.tmp', {expandDirectories: false})); expectType>( globby('*.tmp', {expandDirectories: ['a*', 'b*']}), ); expectType>( globby('*.tmp', { expandDirectories: { files: ['a', 'b'], extensions: ['tmp'], }, }), ); expectType>(globby('*.tmp', {gitignore: true})); expectType>(globby('*.tmp', {ignore: ['**/b.tmp']})); expectType>(globby('*.tmp', {objectMode: true})); // Globby (sync) expectType(globbySync('*.tmp')); expectType(globbySync(['a.tmp', '*.tmp', '!{c,d,e}.tmp'])); expectType(globbySync('*.tmp', {expandDirectories: false})); expectType(globbySync('*.tmp', {expandDirectories: ['a*', 'b*']})); expectType( globbySync('*.tmp', { expandDirectories: { files: ['a', 'b'], extensions: ['tmp'], }, }), ); expectType(globbySync('*.tmp', {gitignore: true})); expectType(globbySync('*.tmp', {ignore: ['**/b.tmp']})); expectType(globbySync('*.tmp', {objectMode: true})); // Globby (stream) expectType(globbyStream('*.tmp')); expectType(globbyStream(['a.tmp', '*.tmp', '!{c,d,e}.tmp'])); expectType(globbyStream('*.tmp', {expandDirectories: false})); expectType(globbyStream('*.tmp', {expandDirectories: ['a*', 'b*']})); expectType( globbyStream('*.tmp', { expandDirectories: { files: ['a', 'b'], extensions: ['tmp'], }, }), ); expectType(globbyStream('*.tmp', {gitignore: true})); expectType(globbyStream('*.tmp', {ignore: ['**/b.tmp']})); (async () => { const streamResult = []; for await (const path of globbyStream('*.tmp')) { streamResult.push(path); } // `NodeJS.ReadableStream` is not generic, unfortunately, // so it seems `(string | Buffer)[]` is the best we can get here expectType>(streamResult); })(); // GenerateGlobTasks expectType>(generateGlobTasks('*.tmp')); expectType>(generateGlobTasks(['a.tmp', '*.tmp', '!{c,d,e}.tmp'])); expectType>(generateGlobTasks('*.tmp', {expandDirectories: false})); expectType>( generateGlobTasks('*.tmp', {expandDirectories: ['a*', 'b*']}), ); expectType>( generateGlobTasks('*.tmp', { expandDirectories: { files: ['a', 'b'], extensions: ['tmp'], }, }), ); expectType>(generateGlobTasks('*.tmp', {gitignore: true})); expectType>(generateGlobTasks('*.tmp', {ignore: ['**/b.tmp']})); // GenerateGlobTasksSync expectType(generateGlobTasksSync('*.tmp')); expectType(generateGlobTasksSync(['a.tmp', '*.tmp', '!{c,d,e}.tmp'])); expectType(generateGlobTasksSync('*.tmp', {expandDirectories: false})); expectType( generateGlobTasksSync('*.tmp', {expandDirectories: ['a*', 'b*']}), ); expectType( generateGlobTasksSync('*.tmp', { expandDirectories: { files: ['a', 'b'], extensions: ['tmp'], }, }), ); expectType(generateGlobTasksSync('*.tmp', {gitignore: true})); expectType(generateGlobTasksSync('*.tmp', {ignore: ['**/b.tmp']})); // IsDynamicPattern expectType(isDynamicPattern('**')); expectType(isDynamicPattern(['**', 'path1', 'path2'])); expectType(isDynamicPattern(['**', 'path1', 'path2'], {extglob: false})); expectType(isDynamicPattern(['**'], {cwd: new URL('file:///path/to/cwd')})); expectType(isDynamicPattern(['**'], {cwd: __dirname})); // IsGitIgnored expectType>(isGitIgnored()); expectType>( isGitIgnored({ cwd: __dirname, }), ); expectType>( isGitIgnored({ cwd: new URL('file:///path/to/cwd'), }), ); // IsGitIgnoredSync expectType(isGitIgnoredSync()); expectType( isGitIgnoredSync({ cwd: __dirname, }), ); expectType( isGitIgnoredSync({ cwd: new URL('file:///path/to/cwd'), }), ); globby-13.1.3/license000066400000000000000000000021351434565770700144450ustar00rootroot00000000000000MIT License Copyright (c) Sindre Sorhus (https://sindresorhus.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. globby-13.1.3/package.json000066400000000000000000000031011434565770700153600ustar00rootroot00000000000000{ "name": "globby", "version": "13.1.3", "description": "User-friendly glob matching", "license": "MIT", "repository": "sindresorhus/globby", "funding": "https://github.com/sponsors/sindresorhus", "author": { "email": "sindresorhus@gmail.com", "name": "Sindre Sorhus", "url": "https://sindresorhus.com" }, "type": "module", "exports": "./index.js", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "scripts": { "bench": "npm update @globby/main-branch glob-stream fast-glob && node bench.js", "test": "xo && ava && tsd" }, "files": [ "index.js", "index.d.ts", "ignore.js", "utilities.js" ], "keywords": [ "all", "array", "directories", "expand", "files", "filesystem", "filter", "find", "fnmatch", "folders", "fs", "glob", "globbing", "globs", "gulpfriendly", "match", "matcher", "minimatch", "multi", "multiple", "paths", "pattern", "patterns", "traverse", "util", "utility", "wildcard", "wildcards", "promise", "gitignore", "git" ], "dependencies": { "dir-glob": "^3.0.1", "fast-glob": "^3.2.11", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^4.0.0" }, "devDependencies": { "@globby/main-branch": "sindresorhus/globby#main", "@types/node": "^17.0.10", "ava": "^4.0.1", "benchmark": "2.1.4", "get-stream": "^6.0.1", "glob-stream": "^7.0.0", "rimraf": "^3.0.2", "tsd": "^0.19.1", "typescript": "^4.5.5", "xo": "^0.47.0" }, "xo": { "ignores": [ "fixtures" ] }, "ava": { "files": [ "!tests/utilities.js" ], "workerThreads": false } } globby-13.1.3/readme.md000066400000000000000000000136501434565770700146630ustar00rootroot00000000000000# globby > User-friendly glob matching Based on [`fast-glob`](https://github.com/mrmlnc/fast-glob) but adds a bunch of useful features. ## Features - Promise API - Multiple patterns - Negated patterns: `['foo*', '!foobar']` - Expands directories: `foo` → `foo/**/*` - Supports `.gitignore` and similar ignore config files - Supports `URL` as `cwd` ## Install ``` $ npm install globby ``` ## Usage ``` ├── unicorn ├── cake └── rainbow ``` ```js import {globby} from 'globby'; const paths = await globby(['*', '!cake']); console.log(paths); //=> ['unicorn', 'rainbow'] ``` ## API Note that glob patterns can only contain forward-slashes, not backward-slashes, so if you want to construct a glob pattern from path components, you need to use `path.posix.join()` instead of `path.join()`. ### globby(patterns, options?) Returns a `Promise` of matching paths. #### patterns Type: `string | string[]` See supported `minimatch` [patterns](https://github.com/isaacs/minimatch#usage). #### options Type: `object` See the [`fast-glob` options](https://github.com/mrmlnc/fast-glob#options-3) in addition to the ones below. ##### expandDirectories Type: `boolean | string[] | object`\ Default: `true` If set to `true`, `globby` will automatically glob directories for you. If you define an `Array` it will only glob files that matches the patterns inside the `Array`. You can also define an `object` with `files` and `extensions` like below: ```js import {globby} from 'globby'; (async () => { const paths = await globby('images', { expandDirectories: { files: ['cat', 'unicorn', '*.jpg'], extensions: ['png'] } }); console.log(paths); //=> ['cat.png', 'unicorn.png', 'cow.jpg', 'rainbow.jpg'] })(); ``` Note that if you set this option to `false`, you won't get back matched directories unless you set `onlyFiles: false`. ##### gitignore Type: `boolean`\ Default: `false` Respect ignore patterns in `.gitignore` files that apply to the globbed files. ##### ignoreFiles Type: `string | string[]`\ Default: `undefined` Glob patterns to look for ignore files, which are then used to ignore globbed files. This is a more generic form of the `gitignore` option, allowing you to find ignore files with a [compatible syntax](http://git-scm.com/docs/gitignore). For instance, this works with Babel's `.babelignore`, Prettier's `.prettierignore`, or ESLint's `.eslintignore` files. ### globbySync(patterns, options?) Returns `string[]` of matching paths. ### globbyStream(patterns, options?) Returns a [`stream.Readable`](https://nodejs.org/api/stream.html#stream_readable_streams) of matching paths. Since Node.js 10, [readable streams are iterable](https://nodejs.org/api/stream.html#stream_readable_symbol_asynciterator), so you can loop over glob matches in a [`for await...of` loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of) like this: ```js import {globbyStream} from 'globby'; (async () => { for await (const path of globbyStream('*.tmp')) { console.log(path); } })(); ``` ### generateGlobTasks(patterns, options?) Returns an `Promise` in the format `{patterns: string[], options: Object}`, which can be passed as arguments to [`fast-glob`](https://github.com/mrmlnc/fast-glob). This is useful for other globbing-related packages. Note that you should avoid running the same tasks multiple times as they contain a file system cache. Instead, run this method each time to ensure file system changes are taken into consideration. ### generateGlobTasksSync(patterns, options?) Returns an `object[]` in the format `{patterns: string[], options: Object}`, which can be passed as arguments to [`fast-glob`](https://github.com/mrmlnc/fast-glob). This is useful for other globbing-related packages. Takes the same arguments as `generateGlobTasks`. ### isDynamicPattern(patterns, options?) Returns a `boolean` of whether there are any special glob characters in the `patterns`. Note that the options affect the results. This function is backed by [`fast-glob`](https://github.com/mrmlnc/fast-glob#isdynamicpatternpattern-options). ### isGitIgnored(options?) Returns a `Promise<(path: URL | string) => boolean>` indicating whether a given path is ignored via a `.gitignore` file. Takes `cwd?: URL | string` as options. ```js import {isGitIgnored} from 'globby'; const isIgnored = await isGitIgnored(); console.log(isIgnored('some/file')); ``` ### isGitIgnoredSync(options?) Returns a `(path: URL | string) => boolean` indicating whether a given path is ignored via a `.gitignore` file. Takes `cwd?: URL | string` as options. ## Globbing patterns Just a quick overview. - `*` matches any number of characters, but not `/` - `?` matches a single character, but not `/` - `**` matches any number of characters, including `/`, as long as it's the only thing in a path part - `{}` allows for a comma-separated list of "or" expressions - `!` at the beginning of a pattern will negate the match [Various patterns and expected matches.](https://github.com/sindresorhus/multimatch/blob/main/test/test.js) ## globby for enterprise Available as part of the Tidelift Subscription. The maintainers of globby and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-globby?utm_source=npm-globby&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) ## Related - [multimatch](https://github.com/sindresorhus/multimatch) - Match against a list instead of the filesystem - [matcher](https://github.com/sindresorhus/matcher) - Simple wildcard matching - [del](https://github.com/sindresorhus/del) - Delete files and directories - [make-dir](https://github.com/sindresorhus/make-dir) - Make a directory and its parents if needed globby-13.1.3/tests/000077500000000000000000000000001434565770700142415ustar00rootroot00000000000000globby-13.1.3/tests/generate-glob-tasks.js000066400000000000000000000136601434565770700204430ustar00rootroot00000000000000import util from 'node:util'; import process from 'node:process'; import path from 'node:path'; import test from 'ava'; import { generateGlobTasks, generateGlobTasksSync, } from '../index.js'; import { invalidPatterns, getPathValues, isUnique, } from './utilities.js'; const runGenerateGlobTasks = async (t, patterns, options) => { const promiseResult = await generateGlobTasks(patterns, options); const syncResult = generateGlobTasksSync(patterns, options); t.deepEqual( promiseResult, syncResult, 'generateGlobTasksSync() result is different than generateGlobTasks()', ); return promiseResult; }; const getTasks = async (t, patterns, options) => { const tasks = await runGenerateGlobTasks(t, patterns, options); return tasks.map(({patterns, options: {ignore}}) => ({patterns, ignore})); }; test('generateGlobTasks', async t => { const tasks = await runGenerateGlobTasks(t, ['*.tmp', '!b.tmp'], {ignore: ['c.tmp']}); t.is(tasks.length, 1); t.deepEqual(tasks[0].patterns, ['*.tmp']); t.deepEqual(tasks[0].options.ignore, ['c.tmp', 'b.tmp']); await t.notThrowsAsync(generateGlobTasks('*')); t.notThrows(() => generateGlobTasksSync('*')); }); // Rejected for being an invalid pattern for (const value of invalidPatterns) { const valueString = util.format(value); const message = 'Patterns must be a string or an array of strings'; test(`throws for invalid patterns input: ${valueString}`, async t => { await t.throwsAsync(generateGlobTasks(value), {instanceOf: TypeError, message}); t.throws(() => generateGlobTasksSync(value), {instanceOf: TypeError, message}); }); } test('throws when specifying a file as cwd', async t => { const error = {message: 'The `cwd` option must be a path to a directory'}; for (const file of getPathValues(path.resolve('fixtures/gitignore/bar.js'))) { // eslint-disable-next-line no-await-in-loop await t.throwsAsync(generateGlobTasks('*', {cwd: file}), error); t.throws(() => generateGlobTasksSync('*', {cwd: file}), error); } }); test('cwd', async t => { const cwd = process.cwd(); for (const cwdDirectory of getPathValues(cwd)) { // eslint-disable-next-line no-await-in-loop const [task] = await runGenerateGlobTasks(t, ['*'], {cwd: cwdDirectory}); t.is(task.options.cwd, cwd); } }); test('expandDirectories option', async t => { { const tasks = await runGenerateGlobTasks(t, ['fixtures'], {ignore: ['fixtures/negative']}); t.is(tasks.length, 1); t.deepEqual(tasks[0].patterns, ['fixtures/**']); t.deepEqual(tasks[0].options.ignore, ['fixtures/negative/**']); } { const tasks = await runGenerateGlobTasks(t, ['fixtures'], {ignore: ['fixtures/negative'], expandDirectories: false}); t.is(tasks.length, 1); t.deepEqual(tasks[0].patterns, ['fixtures']); t.deepEqual(tasks[0].options.ignore, ['fixtures/negative']); } { const tasks = await runGenerateGlobTasks(t, ['fixtures'], {expandDirectories: ['a*', 'b*']}); t.is(tasks.length, 1); t.deepEqual(tasks[0].patterns, ['fixtures/**/a*', 'fixtures/**/b*']); t.deepEqual(tasks[0].options.ignore, []); } { const tasks = await runGenerateGlobTasks(t, ['fixtures'], { expandDirectories: { files: ['a', 'b*'], extensions: ['tmp', 'txt'], }, ignore: ['**/b.tmp'], }); t.is(tasks.length, 1); t.deepEqual(tasks[0].patterns, ['fixtures/**/a.{tmp,txt}', 'fixtures/**/b*.{tmp,txt}']); t.deepEqual(tasks[0].options.ignore, ['**/b.tmp']); } }); test('combine tasks', async t => { t.deepEqual( await getTasks(t, ['a', 'b']), [{patterns: ['a', 'b'], ignore: []}], ); t.deepEqual( await getTasks(t, ['!a', 'b']), [{patterns: ['b'], ignore: []}], ); t.deepEqual( await getTasks(t, ['!a']), [], ); t.deepEqual( await getTasks(t, ['a', 'b', '!c', '!d']), [{patterns: ['a', 'b'], ignore: ['c', 'd']}], ); t.deepEqual( await getTasks(t, ['a', 'b', '!c', '!d', 'e']), [ {patterns: ['a', 'b'], ignore: ['c', 'd']}, {patterns: ['e'], ignore: []}, ], ); t.deepEqual( await getTasks(t, ['a', 'b', '!c', 'd', 'e', '!f', '!g', 'h']), [ {patterns: ['a', 'b'], ignore: ['c', 'f', 'g']}, {patterns: ['d', 'e'], ignore: ['f', 'g']}, {patterns: ['h'], ignore: []}, ], ); }); test('random patterns', async t => { for (let index = 0; index < 500; index++) { const positivePatterns = []; const negativePatterns = []; const negativePatternsAtStart = []; const patterns = Array.from({length: 1 + Math.floor(Math.random() * 20)}, (_, index) => { const negative = Math.random() > 0.5; let pattern = String(index + 1); if (negative) { negativePatterns.push(pattern); if (positivePatterns.length === 0) { negativePatternsAtStart.push(pattern); } pattern = `!${pattern}`; } else { positivePatterns.push(pattern); } return pattern; }); // eslint-disable-next-line no-await-in-loop const tasks = await getTasks(t, patterns); const patternsToDebug = JSON.stringify(patterns); t.true( tasks.length <= negativePatterns.length - negativePatternsAtStart.length + 1, `Unexpected tasks: ${patternsToDebug}`, ); for (const [index, {patterns, ignore}] of tasks.entries()) { t.not( patterns.length, 0, `Unexpected empty patterns: ${patternsToDebug}`, ); t.true( isUnique(patterns), `patterns should be unique: ${patternsToDebug}`, ); t.true( isUnique(ignore), `ignore should be unique: ${patternsToDebug}`, ); if (index !== 0 && ignore.length > 0) { t.deepEqual( tasks[index - 1].ignore.slice(-ignore.length), ignore, `Unexpected ignore: ${patternsToDebug}`, ); } } const allPatterns = tasks.flatMap(({patterns}) => patterns); const allIgnore = tasks.flatMap(({ignore}) => ignore); t.is( new Set(allPatterns).size, positivePatterns.length, `positive patterns should be in patterns: ${patternsToDebug}`, ); t.is( new Set(allIgnore).size, negativePatterns.length - negativePatternsAtStart.length, `negative patterns should be in ignore: ${patternsToDebug}`, ); } }); globby-13.1.3/tests/globby.js000066400000000000000000000250651434565770700160650ustar00rootroot00000000000000import process from 'node:process'; import fs from 'node:fs'; import path from 'node:path'; import util from 'node:util'; import test from 'ava'; import getStream from 'get-stream'; import { globby, globbySync, globbyStream, isDynamicPattern, } from '../index.js'; import { PROJECT_ROOT, getPathValues, invalidPatterns, isUnique, } from './utilities.js'; const cwd = process.cwd(); const temporary = 'tmp'; const fixture = [ 'a.tmp', 'b.tmp', 'c.tmp', 'd.tmp', 'e.tmp', ]; const stabilizeResult = result => result .map(fastGlobResult => { // In `objectMode`, `fastGlobResult.dirent` contains a function that makes `t.deepEqual` assertion fail. // `fastGlobResult.stats` contains different `atime`. if (typeof fastGlobResult === 'object') { const {dirent, stats, ...rest} = fastGlobResult; return rest; } return fastGlobResult; }) .sort((a, b) => (a.path || a).localeCompare(b.path || b)); const runGlobby = async (t, patterns, options) => { const syncResult = globbySync(patterns, options); const promiseResult = await globby(patterns, options); // TODO: Use `Array.fromAsync` when Node.js supports it const streamResult = await getStream.array(globbyStream(patterns, options)); const result = stabilizeResult(promiseResult); t.deepEqual( stabilizeResult(syncResult), result, 'globbySync() result is different than globby()', ); t.deepEqual( stabilizeResult(streamResult), result, 'globbyStream() result is different than globby()', ); return promiseResult; }; test.before(() => { if (!fs.existsSync(temporary)) { fs.mkdirSync(temporary); } for (const element of fixture) { fs.writeFileSync(element, ''); fs.writeFileSync(path.join(PROJECT_ROOT, temporary, element), ''); } }); test.after(() => { for (const element of fixture) { fs.unlinkSync(element); fs.unlinkSync(path.join(PROJECT_ROOT, temporary, element)); } fs.rmdirSync(temporary); }); test('glob', async t => { const result = await runGlobby(t, '*.tmp'); t.deepEqual(result.sort(), ['a.tmp', 'b.tmp', 'c.tmp', 'd.tmp', 'e.tmp']); }); test('glob - multiple file paths', async t => { t.deepEqual(await runGlobby(t, ['a.tmp', 'b.tmp']), ['a.tmp', 'b.tmp']); }); test('glob - empty patterns', async t => { t.deepEqual(await runGlobby(t, []), []); }); test('glob with multiple patterns', async t => { t.deepEqual(await runGlobby(t, ['a.tmp', '*.tmp', '!{c,d,e}.tmp']), ['a.tmp', 'b.tmp']); }); test('respect patterns order', async t => { t.deepEqual(await runGlobby(t, ['!*.tmp', 'a.tmp']), ['a.tmp']); }); test('return [] for all negative patterns', async t => { t.deepEqual(await runGlobby(t, ['!a.tmp', '!b.tmp']), []); }); test('glob - stream async iterator support', async t => { const results = []; for await (const path of globbyStream('*.tmp')) { results.push(path); } t.deepEqual(results, ['a.tmp', 'b.tmp', 'c.tmp', 'd.tmp', 'e.tmp']); }); /// test('glob - duplicated patterns', async t => { // const result1 = await runGlobby(t, [`./${temporary}/**`, `./${temporary}`]); // t.deepEqual(result1, ['./tmp/a.tmp', './tmp/b.tmp', './tmp/c.tmp', './tmp/d.tmp', './tmp/e.tmp']); // const result2 = await runGlobby(t, [`./${temporary}`, `./${temporary}/**`]); // t.deepEqual(result2, ['tmp/a.tmp', 'tmp/b.tmp', 'tmp/c.tmp', 'tmp/d.tmp', 'tmp/e.tmp']); // }); test.serial('cwd option', async t => { process.chdir(temporary); t.deepEqual(await runGlobby(t, '*.tmp', {cwd}), ['a.tmp', 'b.tmp', 'c.tmp', 'd.tmp', 'e.tmp']); t.deepEqual(await runGlobby(t, ['a.tmp', '*.tmp', '!{c,d,e}.tmp'], {cwd}), ['a.tmp', 'b.tmp']); process.chdir(cwd); }); test('don\'t mutate the options object', async t => { await runGlobby(t, ['*.tmp', '!b.tmp'], Object.freeze({ignore: Object.freeze([])})); t.pass(); }); test('expose isDynamicPattern', t => { t.true(isDynamicPattern('**')); t.true(isDynamicPattern(['**', 'path1', 'path2'])); t.false(isDynamicPattern(['path1', 'path2'])); for (const cwdDirectory of getPathValues(cwd)) { t.true(isDynamicPattern('**', {cwd: cwdDirectory})); } }); test('expandDirectories option', async t => { t.deepEqual(await runGlobby(t, temporary), ['tmp/a.tmp', 'tmp/b.tmp', 'tmp/c.tmp', 'tmp/d.tmp', 'tmp/e.tmp']); for (const temporaryDirectory of getPathValues(temporary)) { // eslint-disable-next-line no-await-in-loop t.deepEqual(await runGlobby(t, '**', {cwd: temporaryDirectory}), ['a.tmp', 'b.tmp', 'c.tmp', 'd.tmp', 'e.tmp']); } t.deepEqual(await runGlobby(t, temporary, {expandDirectories: ['a*', 'b*']}), ['tmp/a.tmp', 'tmp/b.tmp']); t.deepEqual(await runGlobby(t, temporary, { expandDirectories: { files: ['a', 'b'], extensions: ['tmp'], }, }), ['tmp/a.tmp', 'tmp/b.tmp']); t.deepEqual(await runGlobby(t, temporary, { expandDirectories: { files: ['a', 'b'], extensions: ['tmp'], }, ignore: ['**/b.tmp'], }), ['tmp/a.tmp']); }); test('expandDirectories:true and onlyFiles:true option', async t => { t.deepEqual(await runGlobby(t, temporary, {onlyFiles: true}), ['tmp/a.tmp', 'tmp/b.tmp', 'tmp/c.tmp', 'tmp/d.tmp', 'tmp/e.tmp']); }); test.failing('expandDirectories:true and onlyFiles:false option', async t => { // Node-glob('tmp/**') => ['tmp', 'tmp/a.tmp', 'tmp/b.tmp', 'tmp/c.tmp', 'tmp/d.tmp', 'tmp/e.tmp'] // Fast-glob('tmp/**') => ['tmp/a.tmp', 'tmp/b.tmp', 'tmp/c.tmp', 'tmp/d.tmp', 'tmp/e.tmp'] // See https://github.com/mrmlnc/fast-glob/issues/47 t.deepEqual(await runGlobby(t, temporary, {onlyFiles: false}), ['tmp', 'tmp/a.tmp', 'tmp/b.tmp', 'tmp/c.tmp', 'tmp/d.tmp', 'tmp/e.tmp']); }); test('expandDirectories and ignores option', async t => { t.deepEqual(await runGlobby(t, 'tmp', { ignore: ['tmp'], }), []); t.deepEqual(await runGlobby(t, 'tmp/**', { expandDirectories: false, ignore: ['tmp'], }), ['tmp/a.tmp', 'tmp/b.tmp', 'tmp/c.tmp', 'tmp/d.tmp', 'tmp/e.tmp']); }); test('absolute:true, expandDirectories:false, onlyFiles:false, gitignore:true and top level folder', async t => { const result = await runGlobby(t, '.', { absolute: true, cwd: path.resolve(temporary), expandDirectories: false, gitignore: true, onlyFiles: false, }); t.is(result.length, 1); t.truthy(result[0].endsWith(temporary)); }); test.serial.failing('relative paths and ignores option', async t => { process.chdir(temporary); for (const cwd of getPathValues(process.cwd())) { // eslint-disable-next-line no-await-in-loop t.deepEqual(await runGlobby(t, '../tmp', { cwd, ignore: ['tmp'], }), []); } process.chdir(cwd); }); // Rejected for being an invalid pattern for (const value of invalidPatterns) { const valueString = util.format(value); const message = 'Patterns must be a string or an array of strings'; test(`throws for invalid patterns input: ${valueString}`, async t => { await t.throwsAsync(globby(value), {instanceOf: TypeError, message}); t.throws(() => globbySync(value), {instanceOf: TypeError, message}); t.throws(() => globbyStream(value), {instanceOf: TypeError, message}); t.throws(() => isDynamicPattern(value), {instanceOf: TypeError, message}); }); } test('gitignore option defaults to false - async', async t => { const actual = await runGlobby(t, '*', {onlyFiles: false}); t.true(actual.includes('node_modules')); }); test('respects gitignore option true', async t => { const actual = await runGlobby(t, '*', {gitignore: true, onlyFiles: false}); t.false(actual.includes('node_modules')); }); test('respects gitignore option false', async t => { const actual = await runGlobby(t, '*', {gitignore: false, onlyFiles: false}); t.true(actual.includes('node_modules')); }); test('gitignore option with stats option', async t => { const result = await runGlobby(t, '*', {gitignore: true, stats: true}); const actual = result.map(x => x.path); t.false(actual.includes('node_modules')); }); test('gitignore option with absolute option', async t => { const result = await runGlobby(t, '*', {gitignore: true, absolute: true}); t.false(result.includes('node_modules')); }); test('gitignore option and objectMode option', async t => { const result = await runGlobby(t, 'fixtures/gitignore/*', {gitignore: true, objectMode: true}); t.is(result.length, 1); t.truthy(result[0].path); }); test('respects ignoreFiles string option', async t => { const actual = await runGlobby(t, '*', {gitignore: false, ignoreFiles: '.gitignore', onlyFiles: false}); t.false(actual.includes('node_modules')); }); test('respects ignoreFiles array option', async t => { const actual = await runGlobby(t, '*', {gitignore: false, ignoreFiles: ['.gitignore'], onlyFiles: false}); t.false(actual.includes('node_modules')); }); test('glob dot files', async t => { const actual = await runGlobby(t, '*', {gitignore: false, ignoreFiles: '*gitignore', onlyFiles: false}); t.false(actual.includes('node_modules')); }); test('`{extension: false}` and `expandDirectories.extensions` option', async t => { for (const temporaryDirectory of getPathValues(temporary)) { t.deepEqual( // eslint-disable-next-line no-await-in-loop await runGlobby(t, '*', { cwd: temporaryDirectory, extension: false, expandDirectories: { extensions: [ 'md', 'tmp', ], }, }), [ 'a.tmp', 'b.tmp', 'c.tmp', 'd.tmp', 'e.tmp', ], ); } }); test('throws when specifying a file as cwd', async t => { const error = {message: 'The `cwd` option must be a path to a directory'}; for (const file of getPathValues(path.resolve('fixtures/gitignore/bar.js'))) { // eslint-disable-next-line no-await-in-loop await t.throwsAsync(globby('.', {cwd: file}), error); // eslint-disable-next-line no-await-in-loop await t.throwsAsync(globby('*', {cwd: file}), error); t.throws(() => globbySync('.', {cwd: file}), error); t.throws(() => globbySync('*', {cwd: file}), error); t.throws(() => globbyStream('.', {cwd: file}), error); t.throws(() => globbyStream('*', {cwd: file}), error); } }); test('throws when specifying a file as cwd - isDynamicPattern', t => { for (const file of getPathValues(path.resolve('fixtures/gitignore/bar.js'))) { t.throws(() => { isDynamicPattern('.', {cwd: file}); }, {message: 'The `cwd` option must be a path to a directory'}); t.throws(() => { isDynamicPattern('*', {cwd: file}); }, {message: 'The `cwd` option must be a path to a directory'}); } }); test('don\'t throw when specifying a non-existing cwd directory', async t => { for (const cwd of getPathValues('/unknown')) { // eslint-disable-next-line no-await-in-loop const actual = await runGlobby(t, '.', {cwd}); t.is(actual.length, 0); } }); test('unique when using objectMode option', async t => { const result = await runGlobby(t, ['a.tmp', '*.tmp'], {cwd, objectMode: true}); t.true(isUnique(result.map(({path}) => path))); }); globby-13.1.3/tests/ignore.js000066400000000000000000000107031434565770700160630ustar00rootroot00000000000000import path from 'node:path'; import test from 'ava'; import slash from 'slash'; import { isIgnoredByIgnoreFiles, isIgnoredByIgnoreFilesSync, isGitIgnored, isGitIgnoredSync, } from '../ignore.js'; import { PROJECT_ROOT, getPathValues, } from './utilities.js'; const runIsIgnoredByIgnoreFiles = async (t, patterns, options, fn) => { const promisePredicate = await isIgnoredByIgnoreFiles(patterns, options); const syncPredicate = isIgnoredByIgnoreFilesSync(patterns, options); const promiseResult = fn(promisePredicate); const syncResult = fn(syncPredicate); t[Array.isArray(promiseResult) ? 'deepEqual' : 'is']( promiseResult, syncResult, 'isIgnoredByIgnoreFilesSync() result is different than isIgnoredByIgnoreFiles()', ); return promiseResult; }; const runIsGitIgnored = async (t, options, fn) => { const promisePredicate = await isGitIgnored(options); const syncPredicate = isGitIgnoredSync(options); const promiseResult = fn(promisePredicate); const syncResult = fn(syncPredicate); t[Array.isArray(promiseResult) ? 'deepEqual' : 'is']( promiseResult, syncResult, 'isGitIgnoredSync() result is different than isGitIgnored()', ); return promiseResult; }; test('ignore', async t => { for (const cwd of getPathValues(path.join(PROJECT_ROOT, 'fixtures/gitignore'))) { // eslint-disable-next-line no-await-in-loop const actual = await runIsGitIgnored( t, {cwd}, isIgnored => ['foo.js', 'bar.js'].filter(file => !isIgnored(file)), ); const expected = ['bar.js']; t.deepEqual(actual, expected); } }); test('ignore - mixed path styles', async t => { const directory = path.join(PROJECT_ROOT, 'fixtures/gitignore'); for (const cwd of getPathValues(directory)) { t.true( // eslint-disable-next-line no-await-in-loop await runIsGitIgnored( t, {cwd}, isIgnored => isIgnored(slash(path.resolve(directory, 'foo.js'))), ), ); } }); test('ignore - os paths', async t => { const directory = path.join(PROJECT_ROOT, 'fixtures/gitignore'); for (const cwd of getPathValues(directory)) { t.true( // eslint-disable-next-line no-await-in-loop await runIsGitIgnored( t, {cwd}, isIgnored => isIgnored(path.resolve(directory, 'foo.js')), ), ); } }); test('negative ignore', async t => { for (const cwd of getPathValues(path.join(PROJECT_ROOT, 'fixtures/negative'))) { // eslint-disable-next-line no-await-in-loop const actual = await runIsGitIgnored( t, {cwd}, isIgnored => ['foo.js', 'bar.js'].filter(file => !isIgnored(file)), ); const expected = ['foo.js']; t.deepEqual(actual, expected); } }); test('multiple negation', async t => { for (const cwd of getPathValues(path.join(PROJECT_ROOT, 'fixtures/multiple-negation'))) { // eslint-disable-next-line no-await-in-loop const actual = await runIsGitIgnored( t, {cwd}, isIgnored => [ '!!!unicorn.js', '!!unicorn.js', '!unicorn.js', 'unicorn.js', ].filter(file => !isIgnored(file)), ); const expected = ['!!unicorn.js', '!unicorn.js']; t.deepEqual(actual, expected); } }); test('check file', async t => { const directory = path.join(PROJECT_ROOT, 'fixtures/gitignore'); for (const ignoredFile of getPathValues(path.join(directory, 'foo.js'))) { t.true( // eslint-disable-next-line no-await-in-loop await runIsGitIgnored( t, {cwd: directory}, isIgnored => isIgnored(ignoredFile), ), ); } for (const notIgnoredFile of getPathValues(path.join(directory, 'bar.js'))) { t.false( // eslint-disable-next-line no-await-in-loop await runIsGitIgnored( t, {cwd: directory}, isIgnored => isIgnored(notIgnoredFile), ), ); } }); test('custom ignore files', async t => { const cwd = path.join(PROJECT_ROOT, 'fixtures/ignore-files'); const files = [ 'ignored-by-eslint.js', 'ignored-by-prettier.js', 'not-ignored.js', ]; t.deepEqual( await runIsIgnoredByIgnoreFiles( t, '.eslintignore', {cwd}, isEslintIgnored => files.filter(file => isEslintIgnored(file)), ), [ 'ignored-by-eslint.js', ], ); t.deepEqual( await runIsIgnoredByIgnoreFiles( t, '.prettierignore', {cwd}, isPrettierIgnored => files.filter(file => isPrettierIgnored(file)), ), [ 'ignored-by-prettier.js', ], ); t.deepEqual( await runIsIgnoredByIgnoreFiles( t, '.{prettier,eslint}ignore', {cwd}, isEslintOrPrettierIgnored => files.filter(file => isEslintOrPrettierIgnored(file)), ), [ 'ignored-by-eslint.js', 'ignored-by-prettier.js', ], ); }); globby-13.1.3/tests/utilities.js000066400000000000000000000007451434565770700166200ustar00rootroot00000000000000import {fileURLToPath, pathToFileURL} from 'node:url'; export const PROJECT_ROOT = fileURLToPath(new URL('../', import.meta.url)); export const getPathValues = path => [path, pathToFileURL(path)]; export const invalidPatterns = [ {}, [{}], true, [true], false, [false], null, [null], undefined, [undefined], Number.NaN, [Number.NaN], 5, [5], function () {}, [function () {}], [['string']], ]; export const isUnique = array => new Set(array).size === array.length; globby-13.1.3/utilities.js000066400000000000000000000007161434565770700154540ustar00rootroot00000000000000import {fileURLToPath} from 'node:url'; import {Transform} from 'node:stream'; export const toPath = urlOrPath => urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath; export class FilterStream extends Transform { constructor(filter) { super({ objectMode: true, transform(data, encoding, callback) { callback(undefined, filter(data) ? data : undefined); }, }); } } export const isNegativePattern = pattern => pattern[0] === '!';