Comparing version 11.1.0 to 14.0.0
310
index.d.ts
@@ -1,186 +0,208 @@ | ||
import {Options as FastGlobOptions, Entry as FastGlobEntry} from 'fast-glob'; | ||
import type FastGlob from 'fast-glob'; | ||
import {type Options as FastGlobOptions, type Entry} from 'fast-glob'; | ||
declare namespace globby { | ||
type ExpandDirectoriesOption = | ||
| boolean | ||
| readonly string[] | ||
| {files?: readonly string[]; extensions?: readonly string[]}; | ||
export type GlobEntry = Entry; | ||
type Entry = FastGlobEntry; | ||
export type GlobTask = { | ||
readonly patterns: string[]; | ||
readonly options: Options; | ||
}; | ||
interface GlobbyOptions extends FastGlobOptions { | ||
/** | ||
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. | ||
export type ExpandDirectoriesOption = | ||
| boolean | ||
| readonly string[] | ||
| {files?: readonly string[]; extensions?: readonly string[]}; | ||
Note that if you set this option to `false`, you won't get back matched directories unless you set `onlyFiles: false`. | ||
type FastGlobOptionsWithoutCwd = Omit<FastGlobOptions, 'cwd'>; | ||
@default true | ||
export type Options = { | ||
/** | ||
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. | ||
@example | ||
``` | ||
import globby = require('globby'); | ||
Note that if you set this option to `false`, you won't get back matched directories unless you set `onlyFiles: false`. | ||
(async () => { | ||
const paths = await globby('images', { | ||
expandDirectories: { | ||
files: ['cat', 'unicorn', '*.jpg'], | ||
extensions: ['png'] | ||
} | ||
}); | ||
@default true | ||
console.log(paths); | ||
//=> ['cat.png', 'unicorn.png', 'cow.jpg', 'rainbow.jpg'] | ||
})(); | ||
``` | ||
*/ | ||
readonly expandDirectories?: ExpandDirectoriesOption; | ||
@example | ||
``` | ||
import {globby} from 'globby'; | ||
/** | ||
Respect ignore patterns in `.gitignore` files that apply to the globbed files. | ||
const paths = await globby('images', { | ||
expandDirectories: { | ||
files: ['cat', 'unicorn', '*.jpg'], | ||
extensions: ['png'] | ||
} | ||
}); | ||
@default false | ||
*/ | ||
readonly gitignore?: boolean; | ||
} | ||
console.log(paths); | ||
//=> ['cat.png', 'unicorn.png', 'cow.jpg', 'rainbow.jpg'] | ||
``` | ||
*/ | ||
readonly expandDirectories?: ExpandDirectoriesOption; | ||
interface GlobTask { | ||
readonly pattern: string; | ||
readonly options: GlobbyOptions; | ||
} | ||
/** | ||
Respect ignore patterns in `.gitignore` files that apply to the globbed files. | ||
interface GitignoreOptions { | ||
readonly cwd?: string; | ||
readonly ignore?: readonly string[]; | ||
} | ||
@default false | ||
*/ | ||
readonly gitignore?: boolean; | ||
type FilterFunction = (path: string) => boolean; | ||
} | ||
/** | ||
Glob patterns to look for ignore files, which are then used to ignore globbed files. | ||
interface Gitignore { | ||
/** | ||
@returns A filter function indicating whether a given path is ignored via a `.gitignore` file. | ||
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 | ||
*/ | ||
sync: (options?: globby.GitignoreOptions) => globby.FilterFunction; | ||
readonly ignoreFiles?: string | readonly string[]; | ||
/** | ||
`.gitignore` files matched by the ignore config are not used for the resulting filter function. | ||
The current working directory in which to search. | ||
@returns A filter function indicating whether a given path is ignored via a `.gitignore` file. | ||
@default process.cwd() | ||
*/ | ||
readonly cwd?: URL | string; | ||
} & FastGlobOptionsWithoutCwd; | ||
@example | ||
``` | ||
import {gitignore} from 'globby'; | ||
export type GitignoreOptions = { | ||
readonly cwd?: URL | string; | ||
}; | ||
(async () => { | ||
const isIgnored = await gitignore(); | ||
console.log(isIgnored('some/file')); | ||
})(); | ||
``` | ||
*/ | ||
(options?: globby.GitignoreOptions): Promise<globby.FilterFunction>; | ||
} | ||
export type GlobbyFilterFunction = (path: URL | string) => boolean; | ||
declare const globby: { | ||
/** | ||
Find files and directories using glob patterns. | ||
/** | ||
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()`. | ||
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. | ||
*/ | ||
sync: (( | ||
patterns: string | readonly string[], | ||
options: globby.GlobbyOptions & {objectMode: true} | ||
) => globby.Entry[]) & (( | ||
patterns: string | readonly string[], | ||
options?: globby.GlobbyOptions | ||
) => string[]); | ||
@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. | ||
/** | ||
Find files and directories using glob patterns. | ||
@example | ||
``` | ||
import {globby} from 'globby'; | ||
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()`. | ||
const paths = await globby(['*', '!cake']); | ||
@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. | ||
console.log(paths); | ||
//=> ['unicorn', 'rainbow'] | ||
``` | ||
*/ | ||
export function globby( | ||
patterns: string | readonly string[], | ||
options: Options & {objectMode: true} | ||
): Promise<GlobEntry[]>; | ||
export function globby( | ||
patterns: string | readonly string[], | ||
options?: Options | ||
): Promise<string[]>; | ||
@example | ||
``` | ||
import globby = require('globby'); | ||
/** | ||
Find files and directories using glob patterns. | ||
(async () => { | ||
for await (const path of globby.stream('*.tmp')) { | ||
console.log(path); | ||
} | ||
})(); | ||
``` | ||
*/ | ||
stream: ( | ||
patterns: string | readonly string[], | ||
options?: globby.GlobbyOptions | ||
) => NodeJS.ReadableStream; | ||
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()`. | ||
/** | ||
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 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[]; | ||
@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. | ||
*/ | ||
generateGlobTasks: ( | ||
patterns: string | readonly string[], | ||
options?: globby.GlobbyOptions | ||
) => globby.GlobTask[]; | ||
/** | ||
Find files and directories using glob patterns. | ||
/** | ||
Note that the options affect the results. | ||
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()`. | ||
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) in addition to the ones in this package. | ||
@returns The stream of matching paths. | ||
@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`. | ||
*/ | ||
hasMagic: ( | ||
patterns: string | readonly string[], | ||
options?: FastGlobOptions | ||
) => boolean; | ||
@example | ||
``` | ||
import {globbyStream} from 'globby'; | ||
readonly gitignore: Gitignore; | ||
for await (const path of globbyStream('*.tmp')) { | ||
console.log(path); | ||
} | ||
``` | ||
*/ | ||
export function globbyStream( | ||
patterns: string | readonly string[], | ||
options?: Options | ||
): NodeJS.ReadableStream; | ||
( | ||
patterns: string | readonly string[], | ||
options: globby.GlobbyOptions & {objectMode: true} | ||
): Promise<globby.Entry[]>; | ||
/** | ||
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. | ||
/** | ||
Find files and directories using glob patterns. | ||
@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<GlobTask[]>; | ||
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()`. | ||
/** | ||
@see generateGlobTasks | ||
@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. | ||
@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[]; | ||
@example | ||
``` | ||
import globby = require('globby'); | ||
/** | ||
Note that the options affect the results. | ||
(async () => { | ||
const paths = await globby(['*', '!cake']); | ||
This function is backed by [`fast-glob`](https://github.com/mrmlnc/fast-glob#isdynamicpatternpattern-options). | ||
console.log(paths); | ||
//=> ['unicorn', 'rainbow'] | ||
})(); | ||
``` | ||
*/ | ||
( | ||
patterns: string | readonly string[], | ||
options?: globby.GlobbyOptions | ||
): Promise<string[]>; | ||
}; | ||
@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. | ||
export = globby; | ||
@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<GlobbyFilterFunction>; | ||
/** | ||
@see isGitIgnored | ||
@returns A filter function indicating whether a given path is ignored via a `.gitignore` file. | ||
*/ | ||
export function isGitIgnoredSync(options?: GitignoreOptions): GlobbyFilterFunction; | ||
export function convertPathToPattern(source: string): FastGlob.Pattern; |
325
index.js
@@ -1,16 +0,17 @@ | ||
'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'); | ||
import process from 'node:process'; | ||
import fs from 'node:fs'; | ||
import nodePath from 'node:path'; | ||
import mergeStreams from '@sindresorhus/merge-streams'; | ||
import fastGlob from 'fast-glob'; | ||
import {isDirectory, isDirectorySync} from 'path-type'; | ||
import {toPath} from 'unicorn-magic'; | ||
import { | ||
GITIGNORE_FILES_PATTERN, | ||
isIgnoredByIgnoreFiles, | ||
isIgnoredByIgnoreFilesSync, | ||
} from './ignore.js'; | ||
import {isNegativePattern} from './utilities.js'; | ||
const DEFAULT_FILTER = () => false; | ||
const isNegative = pattern => pattern[0] === '!'; | ||
const assertPatternsInput = patterns => { | ||
if (!patterns.every(pattern => typeof pattern === 'string')) { | ||
if (patterns.some(pattern => typeof pattern !== 'string')) { | ||
throw new TypeError('Patterns must be a string or an array of strings'); | ||
@@ -20,4 +21,40 @@ } | ||
const checkCwdOption = (options = {}) => { | ||
if (!options.cwd) { | ||
const normalizePathForDirectoryGlob = (filePath, cwd) => { | ||
const path = isNegativePattern(filePath) ? filePath.slice(1) : filePath; | ||
return nodePath.isAbsolute(path) ? path : nodePath.join(cwd, path); | ||
}; | ||
const getDirectoryGlob = ({directoryPath, files, extensions}) => { | ||
const extensionGlob = extensions?.length > 0 ? `.${extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]}` : ''; | ||
return files | ||
? files.map(file => nodePath.posix.join(directoryPath, `**/${nodePath.extname(file) ? file : `${file}${extensionGlob}`}`)) | ||
: [nodePath.posix.join(directoryPath, `**${extensionGlob ? `/${extensionGlob}` : ''}`)]; | ||
}; | ||
const directoryToGlob = async (directoryPaths, { | ||
cwd = process.cwd(), | ||
files, | ||
extensions, | ||
} = {}) => { | ||
const globs = await Promise.all(directoryPaths.map(async directoryPath => | ||
(await isDirectory(normalizePathForDirectoryGlob(directoryPath, cwd))) ? getDirectoryGlob({directoryPath, files, extensions}) : directoryPath), | ||
); | ||
return globs.flat(); | ||
}; | ||
const directoryToGlobSync = (directoryPaths, { | ||
cwd = process.cwd(), | ||
files, | ||
extensions, | ||
} = {}) => directoryPaths.flatMap(directoryPath => isDirectorySync(normalizePathForDirectoryGlob(directoryPath, cwd)) ? getDirectoryGlob({directoryPath, files, extensions}) : directoryPath); | ||
const toPatternsArray = patterns => { | ||
patterns = [...new Set([patterns].flat())]; | ||
assertPatternsInput(patterns); | ||
return patterns; | ||
}; | ||
const checkCwdOption = cwd => { | ||
if (!cwd) { | ||
return; | ||
@@ -28,3 +65,3 @@ } | ||
try { | ||
stat = fs.statSync(options.cwd); | ||
stat = fs.statSync(cwd); | ||
} catch { | ||
@@ -39,146 +76,192 @@ return; | ||
const getPathString = p => p.stats instanceof fs.Stats ? p.path : p; | ||
const normalizeOptions = (options = {}) => { | ||
options = { | ||
...options, | ||
ignore: options.ignore ?? [], | ||
expandDirectories: options.expandDirectories ?? true, | ||
cwd: toPath(options.cwd), | ||
}; | ||
const generateGlobTasks = (patterns, taskOptions) => { | ||
patterns = arrayUnion([].concat(patterns)); | ||
assertPatternsInput(patterns); | ||
checkCwdOption(taskOptions); | ||
checkCwdOption(options.cwd); | ||
const globTasks = []; | ||
return options; | ||
}; | ||
taskOptions = { | ||
ignore: [], | ||
expandDirectories: true, | ||
...taskOptions | ||
}; | ||
const normalizeArguments = function_ => async (patterns, options) => function_(toPatternsArray(patterns), normalizeOptions(options)); | ||
const normalizeArgumentsSync = function_ => (patterns, options) => function_(toPatternsArray(patterns), normalizeOptions(options)); | ||
for (const [index, pattern] of patterns.entries()) { | ||
if (isNegative(pattern)) { | ||
continue; | ||
} | ||
const getIgnoreFilesPatterns = options => { | ||
const {ignoreFiles, gitignore} = options; | ||
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}); | ||
const patterns = ignoreFiles ? toPatternsArray(ignoreFiles) : []; | ||
if (gitignore) { | ||
patterns.push(GITIGNORE_FILES_PATTERN); | ||
} | ||
return globTasks; | ||
return patterns; | ||
}; | ||
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 getFilter = async options => { | ||
const ignoreFilesPatterns = getIgnoreFilesPatterns(options); | ||
return createFilterFunction( | ||
ignoreFilesPatterns.length > 0 && await isIgnoredByIgnoreFiles(ignoreFilesPatterns, 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 ignoreFilesPatterns = getIgnoreFilesPatterns(options); | ||
return createFilterFunction( | ||
ignoreFilesPatterns.length > 0 && isIgnoredByIgnoreFilesSync(ignoreFilesPatterns, options), | ||
); | ||
}; | ||
const globToTask = task => glob => { | ||
const {options} = task; | ||
if (options.ignore && Array.isArray(options.ignore) && options.expandDirectories) { | ||
options.ignore = dirGlob.sync(options.ignore); | ||
} | ||
const createFilterFunction = isIgnored => { | ||
const seen = new Set(); | ||
return { | ||
pattern: glob, | ||
options | ||
return fastGlobResult => { | ||
const pathKey = nodePath.normalize(fastGlobResult.path ?? fastGlobResult); | ||
if (seen.has(pathKey) || (isIgnored && isIgnored(pathKey))) { | ||
return false; | ||
} | ||
seen.add(pathKey); | ||
return true; | ||
}; | ||
}; | ||
module.exports = async (patterns, options) => { | ||
const globTasks = generateGlobTasks(patterns, options); | ||
const unionFastGlobResults = (results, filter) => results.flat().filter(fastGlobResult => filter(fastGlobResult)); | ||
const getFilter = async () => { | ||
return options && options.gitignore ? | ||
gitignore({cwd: options.cwd, ignore: options.ignore}) : | ||
DEFAULT_FILTER; | ||
}; | ||
const convertNegativePatterns = (patterns, options) => { | ||
const tasks = []; | ||
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))); | ||
})); | ||
while (patterns.length > 0) { | ||
const index = patterns.findIndex(pattern => isNegativePattern(pattern)); | ||
return arrayUnion(...tasks); | ||
}; | ||
if (index === -1) { | ||
tasks.push({patterns, options}); | ||
break; | ||
} | ||
const [filter, tasks] = await Promise.all([getFilter(), getTasks()]); | ||
const paths = await Promise.all(tasks.map(task => fastGlob(task.pattern, task.options))); | ||
const ignorePattern = patterns[index].slice(1); | ||
return arrayUnion(...paths).filter(path_ => !filter(getPathString(path_))); | ||
}; | ||
for (const task of tasks) { | ||
task.options.ignore.push(ignorePattern); | ||
} | ||
module.exports.sync = (patterns, options) => { | ||
const globTasks = generateGlobTasks(patterns, options); | ||
if (index !== 0) { | ||
tasks.push({ | ||
patterns: patterns.slice(0, index), | ||
options: { | ||
...options, | ||
ignore: [ | ||
...options.ignore, | ||
ignorePattern, | ||
], | ||
}, | ||
}); | ||
} | ||
const tasks = []; | ||
for (const task of globTasks) { | ||
const newTask = getPattern(task, dirGlob.sync).map(globToTask(task)); | ||
tasks.push(...newTask); | ||
patterns = patterns.slice(index + 1); | ||
} | ||
const filter = getFilterSync(options); | ||
return tasks; | ||
}; | ||
let matches = []; | ||
for (const task of tasks) { | ||
matches = arrayUnion(matches, fastGlob.sync(task.pattern, task.options)); | ||
const normalizeExpandDirectoriesOption = (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; | ||
} | ||
return matches.filter(path_ => !filter(path_)); | ||
const directoryToGlobOptions = normalizeExpandDirectoriesOption(expandDirectories, cwd); | ||
return Promise.all( | ||
globTasks.map(async task => { | ||
let {patterns, options} = task; | ||
[ | ||
patterns, | ||
options.ignore, | ||
] = await Promise.all([ | ||
directoryToGlob(patterns, directoryToGlobOptions), | ||
directoryToGlob(options.ignore, {cwd}), | ||
]); | ||
return {patterns, options}; | ||
}), | ||
); | ||
}; | ||
module.exports.stream = (patterns, options) => { | ||
const globTasks = generateGlobTasks(patterns, options); | ||
const generateTasksSync = (patterns, options) => { | ||
const globTasks = convertNegativePatterns(patterns, options); | ||
const {cwd, expandDirectories} = options; | ||
const tasks = []; | ||
for (const task of globTasks) { | ||
const newTask = getPattern(task, dirGlob.sync).map(globToTask(task)); | ||
tasks.push(...newTask); | ||
if (!expandDirectories) { | ||
return globTasks; | ||
} | ||
const filter = getFilterSync(options); | ||
const filterStream = new FilterStream(p => !filter(p)); | ||
const uniqueStream = new UniqueStream(); | ||
const directoryToGlobSyncOptions = normalizeExpandDirectoriesOption(expandDirectories, cwd); | ||
return merge2(tasks.map(task => fastGlob.stream(task.pattern, task.options))) | ||
.pipe(filterStream) | ||
.pipe(uniqueStream); | ||
return globTasks.map(task => { | ||
let {patterns, options} = task; | ||
patterns = directoryToGlobSync(patterns, directoryToGlobSyncOptions); | ||
options.ignore = directoryToGlobSync(options.ignore, {cwd}); | ||
return {patterns, options}; | ||
}); | ||
}; | ||
module.exports.generateGlobTasks = generateGlobTasks; | ||
export const globby = normalizeArguments(async (patterns, options) => { | ||
const [ | ||
tasks, | ||
filter, | ||
] = await Promise.all([ | ||
generateTasks(patterns, options), | ||
getFilter(options), | ||
]); | ||
module.exports.hasMagic = (patterns, options) => [] | ||
.concat(patterns) | ||
.some(pattern => fastGlob.isDynamicPattern(pattern, options)); | ||
const results = await Promise.all(tasks.map(task => fastGlob(task.patterns, task.options))); | ||
return unionFastGlobResults(results, filter); | ||
}); | ||
module.exports.gitignore = gitignore; | ||
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)); | ||
const stream = mergeStreams(streams).filter(fastGlobResult => filter(fastGlobResult)); | ||
// TODO: Make it return a web stream at some point. | ||
// return Readable.toWeb(stream); | ||
return stream; | ||
}); | ||
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'; | ||
export const {convertPathToPattern} = fastGlob; |
{ | ||
"name": "globby", | ||
"version": "11.1.0", | ||
"version": "14.0.0", | ||
"description": "User-friendly glob matching", | ||
@@ -13,7 +13,13 @@ "license": "MIT", | ||
}, | ||
"type": "module", | ||
"exports": { | ||
"types": "./index.d.ts", | ||
"default": "./index.js" | ||
}, | ||
"sideEffects": false, | ||
"engines": { | ||
"node": ">=10" | ||
"node": ">=18" | ||
}, | ||
"scripts": { | ||
"bench": "npm update glob-stream fast-glob && matcha bench.js", | ||
"bench": "npm update @globby/main-branch glob-stream fast-glob && node bench.js", | ||
"test": "xo && ava && tsd" | ||
@@ -24,4 +30,4 @@ }, | ||
"index.d.ts", | ||
"gitignore.js", | ||
"stream-utils.js" | ||
"ignore.js", | ||
"utilities.js" | ||
], | ||
@@ -62,18 +68,18 @@ "keywords": [ | ||
"dependencies": { | ||
"array-union": "^2.1.0", | ||
"dir-glob": "^3.0.1", | ||
"fast-glob": "^3.2.9", | ||
"ignore": "^5.2.0", | ||
"merge2": "^1.4.1", | ||
"slash": "^3.0.0" | ||
"@sindresorhus/merge-streams": "^1.0.0", | ||
"fast-glob": "^3.3.2", | ||
"ignore": "^5.2.4", | ||
"path-type": "^5.0.0", | ||
"slash": "^5.1.0", | ||
"unicorn-magic": "^0.1.0" | ||
}, | ||
"devDependencies": { | ||
"ava": "^3.13.0", | ||
"get-stream": "^6.0.0", | ||
"glob-stream": "^6.1.0", | ||
"globby": "sindresorhus/globby#main", | ||
"matcha": "^0.7.0", | ||
"rimraf": "^3.0.2", | ||
"tsd": "^0.13.1", | ||
"xo": "^0.33.1" | ||
"@globby/main-branch": "sindresorhus/globby#main", | ||
"@types/node": "^20.9.0", | ||
"ava": "^5.3.1", | ||
"benchmark": "2.1.4", | ||
"glob-stream": "^8.0.0", | ||
"tempy": "^3.1.0", | ||
"tsd": "^0.29.0", | ||
"xo": "^0.56.0" | ||
}, | ||
@@ -84,3 +90,9 @@ "xo": { | ||
] | ||
}, | ||
"ava": { | ||
"files": [ | ||
"!tests/utilities.js" | ||
], | ||
"workerThreads": false | ||
} | ||
} |
105
readme.md
@@ -13,9 +13,10 @@ # globby | ||
- Expands directories: `foo` → `foo/**/*` | ||
- Supports `.gitignore` | ||
- Supports `.gitignore` and similar ignore config files | ||
- Supports `URL` as `cwd` | ||
## Install | ||
```sh | ||
npm install globby | ||
``` | ||
$ npm install globby | ||
``` | ||
@@ -31,10 +32,8 @@ ## Usage | ||
```js | ||
const globby = require('globby'); | ||
import {globby} from 'globby'; | ||
(async () => { | ||
const paths = await globby(['*', '!cake']); | ||
const paths = await globby(['*', '!cake']); | ||
console.log(paths); | ||
//=> ['unicorn', 'rainbow'] | ||
})(); | ||
console.log(paths); | ||
//=> ['unicorn', 'rainbow'] | ||
``` | ||
@@ -70,15 +69,13 @@ | ||
```js | ||
const globby = require('globby'); | ||
import {globby} from 'globby'; | ||
(async () => { | ||
const paths = await globby('images', { | ||
expandDirectories: { | ||
files: ['cat', 'unicorn', '*.jpg'], | ||
extensions: ['png'] | ||
} | ||
}); | ||
const paths = await globby('images', { | ||
expandDirectories: { | ||
files: ['cat', 'unicorn', '*.jpg'], | ||
extensions: ['png'] | ||
} | ||
}); | ||
console.log(paths); | ||
//=> ['cat.png', 'unicorn.png', 'cow.jpg', 'rainbow.jpg'] | ||
})(); | ||
console.log(paths); | ||
//=> ['cat.png', 'unicorn.png', 'cow.jpg', 'rainbow.jpg'] | ||
``` | ||
@@ -95,30 +92,47 @@ | ||
### globby.sync(patterns, options?) | ||
##### 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. | ||
### globby.stream(patterns, options?) | ||
### 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: | ||
For example, 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 | ||
const globby = require('globby'); | ||
import {globbyStream} from 'globby'; | ||
(async () => { | ||
for await (const path of globby.stream('*.tmp')) { | ||
console.log(path); | ||
} | ||
})(); | ||
for await (const path of globbyStream('*.tmp')) { | ||
console.log(path); | ||
} | ||
``` | ||
### globby.generateGlobTasks(patterns, options?) | ||
### convertPathToPattern(path) | ||
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. | ||
Convert a path to a pattern. [Learn more.](https://github.com/mrmlnc/fast-glob#convertpathtopatternpath) | ||
### generateGlobTasks(patterns, options?) | ||
Returns an `Promise<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. | ||
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. | ||
### globby.hasMagic(patterns, options?) | ||
### 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`. | ||
@@ -130,22 +144,21 @@ | ||
### globby.gitignore(options?) | ||
### isGitIgnored(options?) | ||
Returns a `Promise<(path: string) => boolean>` indicating whether a given path is ignored via a `.gitignore` file. | ||
Returns a `Promise<(path: URL | string) => boolean>` indicating whether a given path is ignored via a `.gitignore` file. | ||
Takes `cwd?: string` and `ignore?: string[]` as options. `.gitignore` files matched by the ignore config are not used for the resulting filter function. | ||
Takes `cwd?: URL | string` as options. | ||
```js | ||
const {gitignore} = require('globby'); | ||
import {isGitIgnored} from 'globby'; | ||
(async () => { | ||
const isIgnored = await gitignore(); | ||
console.log(isIgnored('some/file')); | ||
})(); | ||
const isIgnored = await isGitIgnored(); | ||
console.log(isIgnored('some/file')); | ||
``` | ||
### globby.gitignore.sync(options?) | ||
### isGitIgnoredSync(options?) | ||
Returns a `(path: string) => boolean` indicating whether a given path is ignored via a `.gitignore` file. | ||
Returns a `(path: URL | string) => boolean` indicating whether a given path is ignored via a `.gitignore` file. | ||
Takes the same options as `globby.gitignore`. | ||
Takes `cwd?: URL | string` as options. | ||
@@ -164,8 +177,2 @@ ## Globbing patterns | ||
## 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 | ||
@@ -172,0 +179,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
25576
445
178
1
Yes
+ Addedpath-type@^5.0.0
+ Addedunicorn-magic@^0.1.0
+ Added@sindresorhus/merge-streams@1.0.0(transitive)
+ Addedpath-type@5.0.0(transitive)
+ Addedslash@5.1.0(transitive)
+ Addedunicorn-magic@0.1.0(transitive)
- Removedarray-union@^2.1.0
- Removeddir-glob@^3.0.1
- Removedmerge2@^1.4.1
- Removedarray-union@2.1.0(transitive)
- Removeddir-glob@3.0.1(transitive)
- Removedpath-type@4.0.0(transitive)
- Removedslash@3.0.0(transitive)
Updatedfast-glob@^3.3.2
Updatedignore@^5.2.4
Updatedslash@^5.1.0