Comparing version 2.2.7 to 3.0.0
/// <reference types="node" /> | ||
import { IPartialOptions } from './managers/options'; | ||
import { ITask } from './managers/tasks'; | ||
import { EntryItem } from './types/entries'; | ||
import { Pattern } from './types/patterns'; | ||
/** | ||
* Synchronous API. | ||
*/ | ||
export declare function sync(source: Pattern | Pattern[], opts?: IPartialOptions): EntryItem[]; | ||
/** | ||
* Asynchronous API. | ||
*/ | ||
export declare function async(source: Pattern | Pattern[], opts?: IPartialOptions): Promise<EntryItem[]>; | ||
/** | ||
* Stream API. | ||
*/ | ||
export declare function stream(source: Pattern | Pattern[], opts?: IPartialOptions): NodeJS.ReadableStream; | ||
/** | ||
* Return a set of tasks based on provided patterns. | ||
*/ | ||
export declare function generateTasks(source: Pattern | Pattern[], opts?: IPartialOptions): ITask[]; | ||
import * as taskManager from './managers/tasks'; | ||
import { Options as OptionsInternal } from './settings'; | ||
import { Entry as EntryInternal, FileSystemAdapter as FileSystemAdapterInternal, Pattern as PatternInternal } from './types/index'; | ||
declare type EntryObjectModePredicate = { | ||
[P in keyof Pick<OptionsInternal, 'objectMode'>]-?: true; | ||
}; | ||
declare type EntryStatsPredicate = { | ||
[P in keyof Pick<OptionsInternal, 'stats'>]-?: true; | ||
}; | ||
declare type EntryObjectPredicate = EntryObjectModePredicate | EntryStatsPredicate; | ||
declare function FastGlob(source: PatternInternal | PatternInternal[], options: OptionsInternal & EntryObjectPredicate): Promise<EntryInternal[]>; | ||
declare function FastGlob(source: PatternInternal | PatternInternal[], options?: OptionsInternal): Promise<string[]>; | ||
declare namespace FastGlob { | ||
type Options = OptionsInternal; | ||
type Entry = EntryInternal; | ||
type Task = taskManager.Task; | ||
type Pattern = PatternInternal; | ||
type FileSystemAdapter = FileSystemAdapterInternal; | ||
function sync(source: PatternInternal | PatternInternal[], options: OptionsInternal & EntryObjectPredicate): EntryInternal[]; | ||
function sync(source: PatternInternal | PatternInternal[], options?: OptionsInternal): string[]; | ||
function stream(source: PatternInternal | PatternInternal[], options?: OptionsInternal): NodeJS.ReadableStream; | ||
function generateTasks(source: PatternInternal | PatternInternal[], options?: OptionsInternal): Task[]; | ||
} | ||
export = FastGlob; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var optionsManager = require("./managers/options"); | ||
var taskManager = require("./managers/tasks"); | ||
var reader_async_1 = require("./providers/reader-async"); | ||
var reader_stream_1 = require("./providers/reader-stream"); | ||
var reader_sync_1 = require("./providers/reader-sync"); | ||
var arrayUtils = require("./utils/array"); | ||
var streamUtils = require("./utils/stream"); | ||
/** | ||
* Synchronous API. | ||
*/ | ||
function sync(source, opts) { | ||
assertPatternsInput(source); | ||
var works = getWorks(source, reader_sync_1.default, opts); | ||
return arrayUtils.flatten(works); | ||
} | ||
exports.sync = sync; | ||
/** | ||
* Asynchronous API. | ||
*/ | ||
function async(source, opts) { | ||
const taskManager = require("./managers/tasks"); | ||
const async_1 = require("./providers/async"); | ||
const stream_1 = require("./providers/stream"); | ||
const sync_1 = require("./providers/sync"); | ||
const settings_1 = require("./settings"); | ||
const utils = require("./utils/index"); | ||
function FastGlob(source, options) { | ||
try { | ||
@@ -29,35 +15,38 @@ assertPatternsInput(source); | ||
} | ||
var works = getWorks(source, reader_async_1.default, opts); | ||
return Promise.all(works).then(arrayUtils.flatten); | ||
const works = getWorks(source, async_1.default, options); | ||
return Promise.all(works).then(utils.array.flatten); | ||
} | ||
exports.async = async; | ||
/** | ||
* Stream API. | ||
*/ | ||
function stream(source, opts) { | ||
assertPatternsInput(source); | ||
var works = getWorks(source, reader_stream_1.default, opts); | ||
return streamUtils.merge(works); | ||
(function (FastGlob) { | ||
function sync(source, options) { | ||
assertPatternsInput(source); | ||
const works = getWorks(source, sync_1.default, options); | ||
return utils.array.flatten(works); | ||
} | ||
FastGlob.sync = sync; | ||
function stream(source, options) { | ||
assertPatternsInput(source); | ||
const works = getWorks(source, stream_1.default, options); | ||
/** | ||
* The stream returned by the provider cannot work with an asynchronous iterator. | ||
* To support asynchronous iterators, regardless of the number of tasks, we always multiplex streams. | ||
* This affects performance (+25%). I don't see best solution right now. | ||
*/ | ||
return utils.stream.merge(works); | ||
} | ||
FastGlob.stream = stream; | ||
function generateTasks(source, options) { | ||
assertPatternsInput(source); | ||
const patterns = [].concat(source); | ||
const settings = new settings_1.default(options); | ||
return taskManager.generate(patterns, settings); | ||
} | ||
FastGlob.generateTasks = generateTasks; | ||
})(FastGlob || (FastGlob = {})); | ||
function getWorks(source, _Provider, options) { | ||
const patterns = [].concat(source); | ||
const settings = new settings_1.default(options); | ||
const tasks = taskManager.generate(patterns, settings); | ||
const provider = new _Provider(settings); | ||
return tasks.map(provider.read, provider); | ||
} | ||
exports.stream = stream; | ||
/** | ||
* Return a set of tasks based on provided patterns. | ||
*/ | ||
function generateTasks(source, opts) { | ||
assertPatternsInput(source); | ||
var patterns = [].concat(source); | ||
var options = optionsManager.prepare(opts); | ||
return taskManager.generate(patterns, options); | ||
} | ||
exports.generateTasks = generateTasks; | ||
/** | ||
* Returns a set of works based on provided tasks and class of the reader. | ||
*/ | ||
function getWorks(source, _Reader, opts) { | ||
var patterns = [].concat(source); | ||
var options = optionsManager.prepare(opts); | ||
var tasks = taskManager.generate(patterns, options); | ||
var reader = new _Reader(options); | ||
return tasks.map(reader.read, reader); | ||
} | ||
function assertPatternsInput(source) { | ||
@@ -73,1 +62,2 @@ if ([].concat(source).every(isString)) { | ||
} | ||
module.exports = FastGlob; |
@@ -1,4 +0,4 @@ | ||
import { Pattern, PatternsGroup } from '../types/patterns'; | ||
import { IOptions } from './options'; | ||
export interface ITask { | ||
import Settings from '../settings'; | ||
import { Pattern, PatternsGroup } from '../types/index'; | ||
export interface Task { | ||
base: string; | ||
@@ -10,29 +10,8 @@ dynamic: boolean; | ||
} | ||
/** | ||
* Generate tasks based on parent directory of each pattern. | ||
*/ | ||
export declare function generate(patterns: Pattern[], options: IOptions): ITask[]; | ||
/** | ||
* Convert patterns to tasks based on parent directory of each pattern. | ||
*/ | ||
export declare function convertPatternsToTasks(positive: Pattern[], negative: Pattern[], dynamic: boolean): ITask[]; | ||
/** | ||
* Return only positive patterns. | ||
*/ | ||
export declare function generate(patterns: Pattern[], settings: Settings): Task[]; | ||
export declare function convertPatternsToTasks(positive: Pattern[], negative: Pattern[], dynamic: boolean): Task[]; | ||
export declare function getPositivePatterns(patterns: Pattern[]): Pattern[]; | ||
/** | ||
* Return only negative patterns. | ||
*/ | ||
export declare function getNegativePatternsAsPositive(patterns: Pattern[], ignore: Pattern[]): Pattern[]; | ||
/** | ||
* Group patterns by base directory of each pattern. | ||
*/ | ||
export declare function groupPatternsByBaseDirectory(patterns: Pattern[]): PatternsGroup; | ||
/** | ||
* Convert group of patterns to tasks. | ||
*/ | ||
export declare function convertPatternGroupsToTasks(positive: PatternsGroup, negative: Pattern[], dynamic: boolean): ITask[]; | ||
/** | ||
* Create a task for positive and negative patterns. | ||
*/ | ||
export declare function convertPatternGroupToTask(base: string, positive: Pattern[], negative: Pattern[], dynamic: boolean): ITask; | ||
export declare function convertPatternGroupsToTasks(positive: PatternsGroup, negative: Pattern[], dynamic: boolean): Task[]; | ||
export declare function convertPatternGroupToTask(base: string, positive: Pattern[], negative: Pattern[], dynamic: boolean): Task; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var patternUtils = require("../utils/pattern"); | ||
/** | ||
* Generate tasks based on parent directory of each pattern. | ||
*/ | ||
function generate(patterns, options) { | ||
var unixPatterns = patterns.map(patternUtils.unixifyPattern); | ||
var unixIgnore = options.ignore.map(patternUtils.unixifyPattern); | ||
var positivePatterns = getPositivePatterns(unixPatterns); | ||
var negativePatterns = getNegativePatternsAsPositive(unixPatterns, unixIgnore); | ||
const utils = require("../utils/index"); | ||
function generate(patterns, settings) { | ||
const positivePatterns = getPositivePatterns(patterns); | ||
const negativePatterns = getNegativePatternsAsPositive(patterns, settings.ignore); | ||
/** | ||
* When the `case` option is disabled, all patterns must be marked as dynamic, because we cannot check filepath | ||
* directly (without read directory). | ||
* When the `caseSensitiveMatch` option is disabled, all patterns must be marked as dynamic, because we cannot check | ||
* filepath directly (without read directory). | ||
*/ | ||
var staticPatterns = !options.case ? [] : positivePatterns.filter(patternUtils.isStaticPattern); | ||
var dynamicPatterns = !options.case ? positivePatterns : positivePatterns.filter(patternUtils.isDynamicPattern); | ||
var staticTasks = convertPatternsToTasks(staticPatterns, negativePatterns, /* dynamic */ false); | ||
var dynamicTasks = convertPatternsToTasks(dynamicPatterns, negativePatterns, /* dynamic */ true); | ||
const staticPatterns = !settings.caseSensitiveMatch ? [] : positivePatterns.filter(utils.pattern.isStaticPattern); | ||
const dynamicPatterns = !settings.caseSensitiveMatch ? positivePatterns : positivePatterns.filter(utils.pattern.isDynamicPattern); | ||
const staticTasks = convertPatternsToTasks(staticPatterns, negativePatterns, /* dynamic */ false); | ||
const dynamicTasks = convertPatternsToTasks(dynamicPatterns, negativePatterns, /* dynamic */ true); | ||
return staticTasks.concat(dynamicTasks); | ||
} | ||
exports.generate = generate; | ||
/** | ||
* Convert patterns to tasks based on parent directory of each pattern. | ||
*/ | ||
function convertPatternsToTasks(positive, negative, dynamic) { | ||
var positivePatternsGroup = groupPatternsByBaseDirectory(positive); | ||
const positivePatternsGroup = groupPatternsByBaseDirectory(positive); | ||
// When we have a global group – there is no reason to divide the patterns into independent tasks. | ||
// In this case, the global task covers the rest. | ||
if ('.' in positivePatternsGroup) { | ||
var task = convertPatternGroupToTask('.', positive, negative, dynamic); | ||
const task = convertPatternGroupToTask('.', positive, negative, dynamic); | ||
return [task]; | ||
@@ -37,24 +29,15 @@ } | ||
exports.convertPatternsToTasks = convertPatternsToTasks; | ||
/** | ||
* Return only positive patterns. | ||
*/ | ||
function getPositivePatterns(patterns) { | ||
return patternUtils.getPositivePatterns(patterns); | ||
return utils.pattern.getPositivePatterns(patterns); | ||
} | ||
exports.getPositivePatterns = getPositivePatterns; | ||
/** | ||
* Return only negative patterns. | ||
*/ | ||
function getNegativePatternsAsPositive(patterns, ignore) { | ||
var negative = patternUtils.getNegativePatterns(patterns).concat(ignore); | ||
var positive = negative.map(patternUtils.convertToPositivePattern); | ||
const negative = utils.pattern.getNegativePatterns(patterns).concat(ignore); | ||
const positive = negative.map(utils.pattern.convertToPositivePattern); | ||
return positive; | ||
} | ||
exports.getNegativePatternsAsPositive = getNegativePatternsAsPositive; | ||
/** | ||
* Group patterns by base directory of each pattern. | ||
*/ | ||
function groupPatternsByBaseDirectory(patterns) { | ||
return patterns.reduce(function (collection, pattern) { | ||
var base = patternUtils.getBaseDirectory(pattern); | ||
return patterns.reduce((collection, pattern) => { | ||
const base = utils.pattern.getBaseDirectory(pattern); | ||
if (base in collection) { | ||
@@ -70,7 +53,4 @@ collection[base].push(pattern); | ||
exports.groupPatternsByBaseDirectory = groupPatternsByBaseDirectory; | ||
/** | ||
* Convert group of patterns to tasks. | ||
*/ | ||
function convertPatternGroupsToTasks(positive, negative, dynamic) { | ||
return Object.keys(positive).map(function (base) { | ||
return Object.keys(positive).map((base) => { | ||
return convertPatternGroupToTask(base, positive[base], negative, dynamic); | ||
@@ -80,14 +60,11 @@ }); | ||
exports.convertPatternGroupsToTasks = convertPatternGroupsToTasks; | ||
/** | ||
* Create a task for positive and negative patterns. | ||
*/ | ||
function convertPatternGroupToTask(base, positive, negative, dynamic) { | ||
return { | ||
base: base, | ||
dynamic: dynamic, | ||
positive: positive, | ||
negative: negative, | ||
patterns: [].concat(positive, negative.map(patternUtils.convertToNegativePattern)) | ||
dynamic, | ||
positive, | ||
negative, | ||
base: utils.path.platformify(base), | ||
patterns: [].concat(positive, negative.map(utils.pattern.convertToNegativePattern)) | ||
}; | ||
} | ||
exports.convertPatternGroupToTask = convertPatternGroupToTask; |
@@ -1,45 +0,17 @@ | ||
import micromatch = require('micromatch'); | ||
import { IOptions } from '../../managers/options'; | ||
import { FilterFunction } from '@mrmlnc/readdir-enhanced'; | ||
import { Pattern } from '../../types/patterns'; | ||
import Settings from '../../settings'; | ||
import { EntryFilterFunction, MicromatchOptions, Pattern } from '../../types/index'; | ||
export default class DeepFilter { | ||
private readonly options; | ||
private readonly micromatchOptions; | ||
constructor(options: IOptions, micromatchOptions: micromatch.Options); | ||
/** | ||
* Returns filter for directories. | ||
*/ | ||
getFilter(positive: Pattern[], negative: Pattern[]): FilterFunction; | ||
/** | ||
* Returns max depth of the provided patterns. | ||
*/ | ||
private getMaxPatternDepth; | ||
/** | ||
* Returns RegExp's for patterns that can affect the depth of reading. | ||
*/ | ||
private getNegativePatternsRe; | ||
/** | ||
* Returns «true» for directory that should be read. | ||
*/ | ||
private filter; | ||
/** | ||
* Returns «true» when the «deep» option is disabled or number and depth of the entry is greater that the option value. | ||
*/ | ||
private isSkippedByDeepOption; | ||
/** | ||
* Returns «true» when depth parameter is not an Infinity and entry depth greater that the parameter value. | ||
*/ | ||
private isSkippedByMaxPatternDepth; | ||
/** | ||
* Returns «true» for symlinked directory if the «followSymlinkedDirectories» option is disabled. | ||
*/ | ||
private isSkippedSymlinkedDirectory; | ||
/** | ||
* Returns «true» for a directory whose name starts with a period if «dot» option is disabled. | ||
*/ | ||
private isSkippedDotDirectory; | ||
/** | ||
* Returns «true» for a directory whose path math to any negative pattern. | ||
*/ | ||
private isSkippedByNegativePatterns; | ||
private readonly _settings; | ||
private readonly _micromatchOptions; | ||
constructor(_settings: Settings, _micromatchOptions: MicromatchOptions); | ||
getFilter(basePath: string, positive: Pattern[], negative: Pattern[]): EntryFilterFunction; | ||
private _getMaxPatternDepth; | ||
private _getNegativePatternsRe; | ||
private _filter; | ||
private _getEntryDepth; | ||
private _isSkippedByDeep; | ||
private _isSkippedByMaxPatternDepth; | ||
private _isSkippedSymbolicLink; | ||
private _isSkippedDotDirectory; | ||
private _isSkippedByNegativePatterns; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var pathUtils = require("../../utils/path"); | ||
var patternUtils = require("../../utils/pattern"); | ||
var DeepFilter = /** @class */ (function () { | ||
function DeepFilter(options, micromatchOptions) { | ||
this.options = options; | ||
this.micromatchOptions = micromatchOptions; | ||
const path = require("path"); | ||
const utils = require("../../utils/index"); | ||
class DeepFilter { | ||
constructor(_settings, _micromatchOptions) { | ||
this._settings = _settings; | ||
this._micromatchOptions = _micromatchOptions; | ||
} | ||
/** | ||
* Returns filter for directories. | ||
*/ | ||
DeepFilter.prototype.getFilter = function (positive, negative) { | ||
var _this = this; | ||
var maxPatternDepth = this.getMaxPatternDepth(positive); | ||
var negativeRe = this.getNegativePatternsRe(negative); | ||
return function (entry) { return _this.filter(entry, negativeRe, maxPatternDepth); }; | ||
}; | ||
/** | ||
* Returns max depth of the provided patterns. | ||
*/ | ||
DeepFilter.prototype.getMaxPatternDepth = function (patterns) { | ||
var globstar = patterns.some(patternUtils.hasGlobStar); | ||
return globstar ? Infinity : patternUtils.getMaxNaivePatternsDepth(patterns); | ||
}; | ||
/** | ||
* Returns RegExp's for patterns that can affect the depth of reading. | ||
*/ | ||
DeepFilter.prototype.getNegativePatternsRe = function (patterns) { | ||
var affectDepthOfReadingPatterns = patterns.filter(patternUtils.isAffectDepthOfReadingPattern); | ||
return patternUtils.convertPatternsToRe(affectDepthOfReadingPatterns, this.micromatchOptions); | ||
}; | ||
/** | ||
* Returns «true» for directory that should be read. | ||
*/ | ||
DeepFilter.prototype.filter = function (entry, negativeRe, maxPatternDepth) { | ||
if (this.isSkippedByDeepOption(entry.depth)) { | ||
getFilter(basePath, positive, negative) { | ||
const maxPatternDepth = this._getMaxPatternDepth(positive); | ||
const negativeRe = this._getNegativePatternsRe(negative); | ||
return (entry) => this._filter(basePath, entry, negativeRe, maxPatternDepth); | ||
} | ||
_getMaxPatternDepth(patterns) { | ||
const globstar = patterns.some(utils.pattern.hasGlobStar); | ||
return globstar ? Infinity : utils.pattern.getMaxNaivePatternsDepth(patterns); | ||
} | ||
_getNegativePatternsRe(patterns) { | ||
const affectDepthOfReadingPatterns = patterns.filter(utils.pattern.isAffectDepthOfReadingPattern); | ||
return utils.pattern.convertPatternsToRe(affectDepthOfReadingPatterns, this._micromatchOptions); | ||
} | ||
_filter(basePath, entry, negativeRe, maxPatternDepth) { | ||
const depth = this._getEntryDepth(basePath, entry.path); | ||
if (this._isSkippedByDeep(depth)) { | ||
return false; | ||
} | ||
if (this.isSkippedByMaxPatternDepth(entry.depth, maxPatternDepth)) { | ||
if (this._isSkippedByMaxPatternDepth(depth, maxPatternDepth)) { | ||
return false; | ||
} | ||
if (this.isSkippedSymlinkedDirectory(entry)) { | ||
if (this._isSkippedSymbolicLink(entry)) { | ||
return false; | ||
} | ||
if (this.isSkippedDotDirectory(entry)) { | ||
if (this._isSkippedDotDirectory(entry)) { | ||
return false; | ||
} | ||
return this.isSkippedByNegativePatterns(entry, negativeRe); | ||
}; | ||
/** | ||
* Returns «true» when the «deep» option is disabled or number and depth of the entry is greater that the option value. | ||
*/ | ||
DeepFilter.prototype.isSkippedByDeepOption = function (entryDepth) { | ||
return !this.options.deep || (typeof this.options.deep === 'number' && entryDepth >= this.options.deep); | ||
}; | ||
/** | ||
* Returns «true» when depth parameter is not an Infinity and entry depth greater that the parameter value. | ||
*/ | ||
DeepFilter.prototype.isSkippedByMaxPatternDepth = function (entryDepth, maxPatternDepth) { | ||
return maxPatternDepth !== Infinity && entryDepth >= maxPatternDepth; | ||
}; | ||
/** | ||
* Returns «true» for symlinked directory if the «followSymlinkedDirectories» option is disabled. | ||
*/ | ||
DeepFilter.prototype.isSkippedSymlinkedDirectory = function (entry) { | ||
return !this.options.followSymlinkedDirectories && entry.isSymbolicLink(); | ||
}; | ||
/** | ||
* Returns «true» for a directory whose name starts with a period if «dot» option is disabled. | ||
*/ | ||
DeepFilter.prototype.isSkippedDotDirectory = function (entry) { | ||
return !this.options.dot && pathUtils.isDotDirectory(entry.path); | ||
}; | ||
/** | ||
* Returns «true» for a directory whose path math to any negative pattern. | ||
*/ | ||
DeepFilter.prototype.isSkippedByNegativePatterns = function (entry, negativeRe) { | ||
return !patternUtils.matchAny(entry.path, negativeRe); | ||
}; | ||
return DeepFilter; | ||
}()); | ||
return this._isSkippedByNegativePatterns(entry, negativeRe); | ||
} | ||
_getEntryDepth(basePath, entryPath) { | ||
const basePathDepth = basePath.split(path.sep).length; | ||
const entryPathDepth = entryPath.split(path.sep).length; | ||
return entryPathDepth - (basePath === '' ? 0 : basePathDepth); | ||
} | ||
_isSkippedByDeep(entryDepth) { | ||
return entryDepth >= this._settings.deep; | ||
} | ||
_isSkippedByMaxPatternDepth(entryDepth, maxPatternDepth) { | ||
return !this._settings.baseNameMatch && maxPatternDepth !== Infinity && entryDepth > maxPatternDepth; | ||
} | ||
_isSkippedSymbolicLink(entry) { | ||
return !this._settings.followSymbolicLinks && entry.dirent.isSymbolicLink(); | ||
} | ||
_isSkippedDotDirectory(entry) { | ||
return !this._settings.dot && entry.name.startsWith('.'); | ||
} | ||
_isSkippedByNegativePatterns(entry, negativeRe) { | ||
return !utils.pattern.matchAny(entry.path, negativeRe); | ||
} | ||
} | ||
exports.default = DeepFilter; |
@@ -1,45 +0,16 @@ | ||
import micromatch = require('micromatch'); | ||
import { IOptions } from '../../managers/options'; | ||
import { FilterFunction } from '@mrmlnc/readdir-enhanced'; | ||
import { Pattern } from '../../types/patterns'; | ||
import Settings from '../../settings'; | ||
import { EntryFilterFunction, MicromatchOptions, Pattern } from '../../types/index'; | ||
export default class EntryFilter { | ||
private readonly options; | ||
private readonly micromatchOptions; | ||
private readonly _settings; | ||
private readonly _micromatchOptions; | ||
readonly index: Map<string, undefined>; | ||
constructor(options: IOptions, micromatchOptions: micromatch.Options); | ||
/** | ||
* Returns filter for directories. | ||
*/ | ||
getFilter(positive: Pattern[], negative: Pattern[]): FilterFunction; | ||
/** | ||
* Returns true if entry must be added to result. | ||
*/ | ||
private filter; | ||
/** | ||
* Return true if the entry already has in the cross reader index. | ||
*/ | ||
private isDuplicateEntry; | ||
/** | ||
* Create record in the cross reader index. | ||
*/ | ||
private createIndexRecord; | ||
/** | ||
* Returns true for non-files if the «onlyFiles» option is enabled. | ||
*/ | ||
private onlyFileFilter; | ||
/** | ||
* Returns true for non-directories if the «onlyDirectories» option is enabled. | ||
*/ | ||
private onlyDirectoryFilter; | ||
/** | ||
* Return true when `absolute` option is enabled and matched to the negative patterns. | ||
*/ | ||
private isSkippedByAbsoluteNegativePatterns; | ||
/** | ||
* Return true when entry match to provided patterns. | ||
* | ||
* First, just trying to apply patterns to the path. | ||
* Second, trying to apply patterns to the path with final slash (need to micromatch to support «directory/**» patterns). | ||
*/ | ||
private isMatchToPatterns; | ||
constructor(_settings: Settings, _micromatchOptions: MicromatchOptions); | ||
getFilter(positive: Pattern[], negative: Pattern[]): EntryFilterFunction; | ||
private _filter; | ||
private _isDuplicateEntry; | ||
private _createIndexRecord; | ||
private _onlyFileFilter; | ||
private _onlyDirectoryFilter; | ||
private _isSkippedByAbsoluteNegativePatterns; | ||
private _isMatchToPatterns; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var pathUtils = require("../../utils/path"); | ||
var patternUtils = require("../../utils/pattern"); | ||
var EntryFilter = /** @class */ (function () { | ||
function EntryFilter(options, micromatchOptions) { | ||
this.options = options; | ||
this.micromatchOptions = micromatchOptions; | ||
const utils = require("../../utils/index"); | ||
class EntryFilter { | ||
constructor(_settings, _micromatchOptions) { | ||
this._settings = _settings; | ||
this._micromatchOptions = _micromatchOptions; | ||
this.index = new Map(); | ||
} | ||
/** | ||
* Returns filter for directories. | ||
*/ | ||
EntryFilter.prototype.getFilter = function (positive, negative) { | ||
var _this = this; | ||
var positiveRe = patternUtils.convertPatternsToRe(positive, this.micromatchOptions); | ||
var negativeRe = patternUtils.convertPatternsToRe(negative, this.micromatchOptions); | ||
return function (entry) { return _this.filter(entry, positiveRe, negativeRe); }; | ||
}; | ||
/** | ||
* Returns true if entry must be added to result. | ||
*/ | ||
EntryFilter.prototype.filter = function (entry, positiveRe, negativeRe) { | ||
// Exclude duplicate results | ||
if (this.options.unique) { | ||
if (this.isDuplicateEntry(entry)) { | ||
getFilter(positive, negative) { | ||
const positiveRe = utils.pattern.convertPatternsToRe(positive, this._micromatchOptions); | ||
const negativeRe = utils.pattern.convertPatternsToRe(negative, this._micromatchOptions); | ||
return (entry) => this._filter(entry, positiveRe, negativeRe); | ||
} | ||
_filter(entry, positiveRe, negativeRe) { | ||
if (this._settings.unique) { | ||
if (this._isDuplicateEntry(entry)) { | ||
return false; | ||
} | ||
this.createIndexRecord(entry); | ||
this._createIndexRecord(entry); | ||
} | ||
// Filter files and directories by options | ||
if (this.onlyFileFilter(entry) || this.onlyDirectoryFilter(entry)) { | ||
if (this._onlyFileFilter(entry) || this._onlyDirectoryFilter(entry)) { | ||
return false; | ||
} | ||
if (this.isSkippedByAbsoluteNegativePatterns(entry, negativeRe)) { | ||
if (this._isSkippedByAbsoluteNegativePatterns(entry, negativeRe)) { | ||
return false; | ||
} | ||
return this.isMatchToPatterns(entry.path, positiveRe) && !this.isMatchToPatterns(entry.path, negativeRe); | ||
}; | ||
/** | ||
* Return true if the entry already has in the cross reader index. | ||
*/ | ||
EntryFilter.prototype.isDuplicateEntry = function (entry) { | ||
const filepath = this._settings.baseNameMatch ? entry.name : entry.path; | ||
return this._isMatchToPatterns(filepath, positiveRe) && !this._isMatchToPatterns(entry.path, negativeRe); | ||
} | ||
_isDuplicateEntry(entry) { | ||
return this.index.has(entry.path); | ||
}; | ||
/** | ||
* Create record in the cross reader index. | ||
*/ | ||
EntryFilter.prototype.createIndexRecord = function (entry) { | ||
} | ||
_createIndexRecord(entry) { | ||
this.index.set(entry.path, undefined); | ||
}; | ||
/** | ||
* Returns true for non-files if the «onlyFiles» option is enabled. | ||
*/ | ||
EntryFilter.prototype.onlyFileFilter = function (entry) { | ||
return this.options.onlyFiles && !entry.isFile(); | ||
}; | ||
/** | ||
* Returns true for non-directories if the «onlyDirectories» option is enabled. | ||
*/ | ||
EntryFilter.prototype.onlyDirectoryFilter = function (entry) { | ||
return this.options.onlyDirectories && !entry.isDirectory(); | ||
}; | ||
/** | ||
* Return true when `absolute` option is enabled and matched to the negative patterns. | ||
*/ | ||
EntryFilter.prototype.isSkippedByAbsoluteNegativePatterns = function (entry, negativeRe) { | ||
if (!this.options.absolute) { | ||
} | ||
_onlyFileFilter(entry) { | ||
return this._settings.onlyFiles && !entry.dirent.isFile(); | ||
} | ||
_onlyDirectoryFilter(entry) { | ||
return this._settings.onlyDirectories && !entry.dirent.isDirectory(); | ||
} | ||
_isSkippedByAbsoluteNegativePatterns(entry, negativeRe) { | ||
if (!this._settings.absolute) { | ||
return false; | ||
} | ||
var fullpath = pathUtils.makeAbsolute(this.options.cwd, entry.path); | ||
return this.isMatchToPatterns(fullpath, negativeRe); | ||
}; | ||
/** | ||
* Return true when entry match to provided patterns. | ||
* | ||
* First, just trying to apply patterns to the path. | ||
* Second, trying to apply patterns to the path with final slash (need to micromatch to support «directory/**» patterns). | ||
*/ | ||
EntryFilter.prototype.isMatchToPatterns = function (filepath, patternsRe) { | ||
return patternUtils.matchAny(filepath, patternsRe) || patternUtils.matchAny(filepath + '/', patternsRe); | ||
}; | ||
return EntryFilter; | ||
}()); | ||
const fullpath = utils.path.makeAbsolute(this._settings.cwd, entry.path); | ||
return this._isMatchToPatterns(fullpath, negativeRe); | ||
} | ||
_isMatchToPatterns(filepath, patternsRe) { | ||
return utils.pattern.matchAny(filepath, patternsRe); | ||
} | ||
} | ||
exports.default = EntryFilter; |
@@ -1,4 +0,1 @@ | ||
/** | ||
* Flatten nested arrays (max depth is 2) into a non-nested array of non-array items. | ||
*/ | ||
export declare function flatten<T>(items: T[][]): T[]; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** | ||
* Flatten nested arrays (max depth is 2) into a non-nested array of non-array items. | ||
*/ | ||
function flatten(items) { | ||
return items.reduce(function (collection, item) { return [].concat(collection, item); }, []); | ||
return items.reduce((collection, item) => [].concat(collection, item), []); | ||
} | ||
exports.flatten = flatten; |
/** | ||
* Returns «true» if the last partial of the path starting with a period. | ||
* Designed to work only with simple paths: `dir\\file`. | ||
*/ | ||
export declare function isDotDirectory(filepath: string): boolean; | ||
export declare function unixify(filepath: string): string; | ||
/** | ||
* Convert a windows-like path to a unix-style path. | ||
* Simplified version of the `path.normalize` method. | ||
* | ||
* Designed to work only with simple paths: `dir/file`. | ||
*/ | ||
export declare function normalize(filepath: string): string; | ||
/** | ||
* Returns normalized absolute path of provided filepath. | ||
*/ | ||
export declare function platformify(filepath: string): string; | ||
export declare function makeAbsolute(cwd: string, filepath: string): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var path = require("path"); | ||
const path = require("path"); | ||
/** | ||
* Returns «true» if the last partial of the path starting with a period. | ||
* Designed to work only with simple paths: `dir\\file`. | ||
*/ | ||
function isDotDirectory(filepath) { | ||
return path.basename(filepath).startsWith('.'); | ||
function unixify(filepath) { | ||
return filepath.replace(/\\/g, '/'); | ||
} | ||
exports.isDotDirectory = isDotDirectory; | ||
exports.unixify = unixify; | ||
/** | ||
* Convert a windows-like path to a unix-style path. | ||
* Simplified version of the `path.normalize` method. | ||
* | ||
* Designed to work only with simple paths: `dir/file`. | ||
*/ | ||
function normalize(filepath) { | ||
return filepath.replace(/\\/g, '/'); | ||
function platformify(filepath) { | ||
return filepath.replace(/[\\\/]/g, path.sep); | ||
} | ||
exports.normalize = normalize; | ||
/** | ||
* Returns normalized absolute path of provided filepath. | ||
*/ | ||
exports.platformify = platformify; | ||
function makeAbsolute(cwd, filepath) { | ||
return normalize(path.resolve(cwd, filepath)); | ||
return path.resolve(cwd, filepath); | ||
} | ||
exports.makeAbsolute = makeAbsolute; |
@@ -1,74 +0,18 @@ | ||
import micromatch = require('micromatch'); | ||
import { Pattern, PatternRe } from '../types/patterns'; | ||
/** | ||
* Return true for static pattern. | ||
*/ | ||
import { MicromatchOptions, Pattern, PatternRe } from '../types/index'; | ||
export declare function isStaticPattern(pattern: Pattern): boolean; | ||
/** | ||
* Return true for pattern that looks like glob. | ||
*/ | ||
export declare function isDynamicPattern(pattern: Pattern): boolean; | ||
/** | ||
* Convert a windows «path» to a unix-style «path». | ||
*/ | ||
export declare function unixifyPattern(pattern: Pattern): Pattern; | ||
/** | ||
* Returns negative pattern as positive pattern. | ||
*/ | ||
export declare function convertToPositivePattern(pattern: Pattern): Pattern; | ||
/** | ||
* Returns positive pattern as negative pattern. | ||
*/ | ||
export declare function convertToNegativePattern(pattern: Pattern): Pattern; | ||
/** | ||
* Return true if provided pattern is negative pattern. | ||
*/ | ||
export declare function isNegativePattern(pattern: Pattern): boolean; | ||
/** | ||
* Return true if provided pattern is positive pattern. | ||
*/ | ||
export declare function isPositivePattern(pattern: Pattern): boolean; | ||
/** | ||
* Extracts negative patterns from array of patterns. | ||
*/ | ||
export declare function getNegativePatterns(patterns: Pattern[]): Pattern[]; | ||
/** | ||
* Extracts positive patterns from array of patterns. | ||
*/ | ||
export declare function getPositivePatterns(patterns: Pattern[]): Pattern[]; | ||
/** | ||
* Extract base directory from provided pattern. | ||
*/ | ||
export declare function getBaseDirectory(pattern: Pattern): string; | ||
/** | ||
* Return true if provided pattern has globstar. | ||
*/ | ||
export declare function hasGlobStar(pattern: Pattern): boolean; | ||
/** | ||
* Return true if provided pattern ends with slash and globstar. | ||
*/ | ||
export declare function endsWithSlashGlobStar(pattern: Pattern): boolean; | ||
/** | ||
* Returns «true» when pattern ends with a slash and globstar or the last partial of the pattern is static pattern. | ||
*/ | ||
export declare function isAffectDepthOfReadingPattern(pattern: Pattern): boolean; | ||
/** | ||
* Return naive depth of provided pattern without depth of the base directory. | ||
*/ | ||
export declare function getNaiveDepth(pattern: Pattern): number; | ||
/** | ||
* Return max naive depth of provided patterns without depth of the base directory. | ||
*/ | ||
export declare function getMaxNaivePatternsDepth(patterns: Pattern[]): number; | ||
/** | ||
* Make RegExp for provided pattern. | ||
*/ | ||
export declare function makeRe(pattern: Pattern, options: micromatch.Options): PatternRe; | ||
/** | ||
* Convert patterns to regexps. | ||
*/ | ||
export declare function convertPatternsToRe(patterns: Pattern[], options: micromatch.Options): PatternRe[]; | ||
/** | ||
* Returns true if the entry match any of the given RegExp's. | ||
*/ | ||
export declare function makeRe(pattern: Pattern, options: MicromatchOptions): PatternRe; | ||
export declare function convertPatternsToRe(patterns: Pattern[], options: MicromatchOptions): PatternRe[]; | ||
export declare function matchAny(entry: string, patternsRe: PatternRe[]): boolean; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var path = require("path"); | ||
var globParent = require("glob-parent"); | ||
var isGlob = require("is-glob"); | ||
var micromatch = require("micromatch"); | ||
var GLOBSTAR = '**'; | ||
/** | ||
* Return true for static pattern. | ||
*/ | ||
const path = require("path"); | ||
const globParent = require("glob-parent"); | ||
const isGlob = require("is-glob"); | ||
const micromatch = require("micromatch"); | ||
const GLOBSTAR = '**'; | ||
function isStaticPattern(pattern) { | ||
@@ -15,5 +12,2 @@ return !isDynamicPattern(pattern); | ||
exports.isStaticPattern = isStaticPattern; | ||
/** | ||
* Return true for pattern that looks like glob. | ||
*/ | ||
function isDynamicPattern(pattern) { | ||
@@ -23,12 +17,2 @@ return isGlob(pattern, { strict: false }); | ||
exports.isDynamicPattern = isDynamicPattern; | ||
/** | ||
* Convert a windows «path» to a unix-style «path». | ||
*/ | ||
function unixifyPattern(pattern) { | ||
return pattern.replace(/\\/g, '/'); | ||
} | ||
exports.unixifyPattern = unixifyPattern; | ||
/** | ||
* Returns negative pattern as positive pattern. | ||
*/ | ||
function convertToPositivePattern(pattern) { | ||
@@ -38,5 +22,2 @@ return isNegativePattern(pattern) ? pattern.slice(1) : pattern; | ||
exports.convertToPositivePattern = convertToPositivePattern; | ||
/** | ||
* Returns positive pattern as negative pattern. | ||
*/ | ||
function convertToNegativePattern(pattern) { | ||
@@ -46,5 +27,2 @@ return '!' + pattern; | ||
exports.convertToNegativePattern = convertToNegativePattern; | ||
/** | ||
* Return true if provided pattern is negative pattern. | ||
*/ | ||
function isNegativePattern(pattern) { | ||
@@ -54,5 +32,2 @@ return pattern.startsWith('!') && pattern[1] !== '('; | ||
exports.isNegativePattern = isNegativePattern; | ||
/** | ||
* Return true if provided pattern is positive pattern. | ||
*/ | ||
function isPositivePattern(pattern) { | ||
@@ -62,5 +37,2 @@ return !isNegativePattern(pattern); | ||
exports.isPositivePattern = isPositivePattern; | ||
/** | ||
* Extracts negative patterns from array of patterns. | ||
*/ | ||
function getNegativePatterns(patterns) { | ||
@@ -70,5 +42,2 @@ return patterns.filter(isNegativePattern); | ||
exports.getNegativePatterns = getNegativePatterns; | ||
/** | ||
* Extracts positive patterns from array of patterns. | ||
*/ | ||
function getPositivePatterns(patterns) { | ||
@@ -78,5 +47,2 @@ return patterns.filter(isPositivePattern); | ||
exports.getPositivePatterns = getPositivePatterns; | ||
/** | ||
* Extract base directory from provided pattern. | ||
*/ | ||
function getBaseDirectory(pattern) { | ||
@@ -86,5 +52,2 @@ return globParent(pattern); | ||
exports.getBaseDirectory = getBaseDirectory; | ||
/** | ||
* Return true if provided pattern has globstar. | ||
*/ | ||
function hasGlobStar(pattern) { | ||
@@ -94,5 +57,2 @@ return pattern.indexOf(GLOBSTAR) !== -1; | ||
exports.hasGlobStar = hasGlobStar; | ||
/** | ||
* Return true if provided pattern ends with slash and globstar. | ||
*/ | ||
function endsWithSlashGlobStar(pattern) { | ||
@@ -102,17 +62,11 @@ return pattern.endsWith('/' + GLOBSTAR); | ||
exports.endsWithSlashGlobStar = endsWithSlashGlobStar; | ||
/** | ||
* Returns «true» when pattern ends with a slash and globstar or the last partial of the pattern is static pattern. | ||
*/ | ||
function isAffectDepthOfReadingPattern(pattern) { | ||
var basename = path.basename(pattern); | ||
const basename = path.basename(pattern); | ||
return endsWithSlashGlobStar(pattern) || isStaticPattern(basename); | ||
} | ||
exports.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern; | ||
/** | ||
* Return naive depth of provided pattern without depth of the base directory. | ||
*/ | ||
function getNaiveDepth(pattern) { | ||
var base = getBaseDirectory(pattern); | ||
var patternDepth = pattern.split('/').length; | ||
var patternBaseDepth = base.split('/').length; | ||
const base = getBaseDirectory(pattern); | ||
const patternDepth = pattern.split('/').length; | ||
const patternBaseDepth = base.split('/').length; | ||
/** | ||
@@ -129,8 +83,5 @@ * This is a hack for pattern that has no base directory. | ||
exports.getNaiveDepth = getNaiveDepth; | ||
/** | ||
* Return max naive depth of provided patterns without depth of the base directory. | ||
*/ | ||
function getMaxNaivePatternsDepth(patterns) { | ||
return patterns.reduce(function (max, pattern) { | ||
var depth = getNaiveDepth(pattern); | ||
return patterns.reduce((max, pattern) => { | ||
const depth = getNaiveDepth(pattern); | ||
return depth > max ? depth : max; | ||
@@ -140,5 +91,2 @@ }, 0); | ||
exports.getMaxNaivePatternsDepth = getMaxNaivePatternsDepth; | ||
/** | ||
* Make RegExp for provided pattern. | ||
*/ | ||
function makeRe(pattern, options) { | ||
@@ -148,15 +96,10 @@ return micromatch.makeRe(pattern, options); | ||
exports.makeRe = makeRe; | ||
/** | ||
* Convert patterns to regexps. | ||
*/ | ||
function convertPatternsToRe(patterns, options) { | ||
return patterns.map(function (pattern) { return makeRe(pattern, options); }); | ||
return patterns.map((pattern) => makeRe(pattern, options)); | ||
} | ||
exports.convertPatternsToRe = convertPatternsToRe; | ||
/** | ||
* Returns true if the entry match any of the given RegExp's. | ||
*/ | ||
function matchAny(entry, patternsRe) { | ||
return patternsRe.some(function (patternRe) { return patternRe.test(entry); }); | ||
const filepath = entry.replace(/^\.[\\\/]/, ''); | ||
return patternsRe.some((patternRe) => patternRe.test(filepath)); | ||
} | ||
exports.matchAny = matchAny; |
/// <reference types="node" /> | ||
/** | ||
* Merge multiple streams and propagate their errors into one stream in parallel. | ||
*/ | ||
export declare function merge(streams: NodeJS.ReadableStream[]): NodeJS.ReadableStream; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var merge2 = require("merge2"); | ||
/** | ||
* Merge multiple streams and propagate their errors into one stream in parallel. | ||
*/ | ||
const merge2 = require("merge2"); | ||
function merge(streams) { | ||
var mergedStream = merge2(streams); | ||
streams.forEach(function (stream) { | ||
stream.on('error', function (err) { return mergedStream.emit('error', err); }); | ||
const mergedStream = merge2(streams); | ||
streams.forEach((stream) => { | ||
stream.once('error', (err) => mergedStream.emit('error', err)); | ||
}); | ||
@@ -12,0 +9,0 @@ return mergedStream; |
{ | ||
"name": "fast-glob", | ||
"version": "2.2.7", | ||
"description": "Is a faster `node-glob` alternative", | ||
"version": "3.0.0", | ||
"description": "It's a very fast and efficient glob library for Node.js", | ||
"license": "MIT", | ||
@@ -12,6 +12,6 @@ "repository": "mrmlnc/fast-glob", | ||
"engines": { | ||
"node": ">=4.0.0" | ||
"node": ">=8" | ||
}, | ||
"main": "index.js", | ||
"typings": "index.d.ts", | ||
"main": "out/index.js", | ||
"typings": "out/index.d.ts", | ||
"keywords": [ | ||
@@ -24,3 +24,3 @@ "glob", | ||
"devDependencies": { | ||
"@types/bash-glob": "^2.0.0", | ||
"@nodelib/fs.macchiato": "^1.0.0", | ||
"@types/compute-stdev": "^1.0.0", | ||
@@ -30,6 +30,4 @@ "@types/easy-table": "^0.0.32", | ||
"@types/glob": "^7.1.1", | ||
"@types/glob-parent": "^3.1.0", | ||
"@types/glob-stream": "^6.1.0", | ||
"@types/globby": "^8.0.0", | ||
"@types/is-glob": "^4.0.0", | ||
"@types/glob-parent": "^3.1.1", | ||
"@types/is-glob": "^4.0.1", | ||
"@types/merge2": "^1.1.4", | ||
@@ -39,27 +37,26 @@ "@types/micromatch": "^3.1.0", | ||
"@types/mocha": "^5.2.5", | ||
"@types/node": "^11.13.5", | ||
"@types/node": "^11.13.6", | ||
"@types/rimraf": "^2.0.2", | ||
"bash-glob": "^2.0.0", | ||
"@types/sinon": "^7.0.12", | ||
"compute-stdev": "^1.0.0", | ||
"easy-table": "^1.1.1", | ||
"execa": "^0.9.0", | ||
"execa": "^1.0.0", | ||
"fast-glob": "^2.2.0", | ||
"glob": "^7.1.2", | ||
"glob-stream": "^6.1.0", | ||
"globby": "^8.0.1", | ||
"minimist": "^1.2.0", | ||
"mocha": "^5.2.0", | ||
"mocha": "^6.1.4", | ||
"rimraf": "^2.6.2", | ||
"sinon": "^7.3.2", | ||
"tiny-glob": "^0.2.3", | ||
"tslint": "^5.12.0", | ||
"tslint-config-mrmlnc": "^2.0.1", | ||
"typescript": "^3.1.3" | ||
"tslint": "^5.16.0", | ||
"tslint-config-mrmlnc": "^2.1.0", | ||
"typescript": "^3.4.4" | ||
}, | ||
"dependencies": { | ||
"@mrmlnc/readdir-enhanced": "^2.2.1", | ||
"@nodelib/fs.stat": "^1.1.2", | ||
"glob-parent": "^3.1.0", | ||
"@nodelib/fs.stat": "^2.0.0", | ||
"@nodelib/fs.walk": "^1.1.0", | ||
"glob-parent": "^5.0.0", | ||
"is-glob": "^4.0.0", | ||
"merge2": "^1.2.3", | ||
"micromatch": "^3.1.10" | ||
"micromatch": "^4.0.2" | ||
}, | ||
@@ -74,16 +71,13 @@ "scripts": { | ||
"watch": "npm run clean && npm run compile -- --sourceMap --watch", | ||
"bench-async-1": "node ./out/benchmark --depth 1", | ||
"bench-async-5": "node ./out/benchmark --depth 5", | ||
"bench-async-10": "node ./out/benchmark --depth 10", | ||
"bench-async-50": "node ./out/benchmark --depth 50", | ||
"bench-async-100": "node ./out/benchmark --depth 100", | ||
"bench-async": "npm run bench-async-1 && npm run bench-async-5 && npm run bench-async-10 && npm run bench-async-50 && npm run bench-async-100", | ||
"bench-sync-1": "node ./out/benchmark --depth 1 --type sync", | ||
"bench-sync-5": "node ./out/benchmark --depth 5 --type sync", | ||
"bench-sync-10": "node ./out/benchmark --depth 10 --type sync", | ||
"bench-sync-50": "node ./out/benchmark --depth 50 --type sync", | ||
"bench-sync-100": "node ./out/benchmark --depth 100 --type sync", | ||
"bench-sync": "npm run bench-sync-1 && npm run bench-sync-5 && npm run bench-sync-10 && npm run bench-sync-50 && npm run bench-sync-100", | ||
"bench": "npm run build && npm run bench-async && npm run bench-sync" | ||
"bench": "npm run bench-async && npm run bench-stream && npm run bench-sync", | ||
"bench-async": "npm run bench-async-flatten && npm run bench-async-deep", | ||
"bench-stream": "npm run bench-stream-flatten && npm run bench-stream-deep", | ||
"bench-sync": "npm run bench-sync-flatten && npm run bench-sync-deep", | ||
"bench-async-flatten": "node ./out/benchmark --type async --pattern \"*\"", | ||
"bench-async-deep": "node ./out/benchmark --type async --pattern \"**\"", | ||
"bench-stream-flatten": "node ./out/benchmark --type stream --pattern \"*\"", | ||
"bench-stream-deep": "node ./out/benchmark --type stream --pattern \"**\"", | ||
"bench-sync-flatten": "node ./out/benchmark --type sync --pattern \"*\"", | ||
"bench-sync-deep": "node ./out/benchmark --type sync --pattern \"**\"" | ||
} | ||
} |
716
README.md
@@ -1,39 +0,143 @@ | ||
# :rocket: fast-glob | ||
# fast-glob | ||
> Is a faster [`node-glob`](https://github.com/isaacs/node-glob) alternative. | ||
> It's a very fast and efficient [glob][glob_definition] library for [Node.js][node_js]. | ||
## :bulb: Highlights | ||
This package provides methods for traversing the file system and returning pathnames that matched a defined set of a specified pattern according to the rules used by the Unix Bash shell with some simplifications, meanwhile results are returned in **arbitrary order**. Quick, simple, effective. | ||
* :rocket: Fast by using Streams and Promises. Used [readdir-enhanced](https://github.com/BigstickCarpet/readdir-enhanced) and [micromatch](https://github.com/jonschlinkert/micromatch). | ||
* :beginner: User-friendly, since it supports multiple and negated patterns (`['*', '!*.md']`). | ||
* :vertical_traffic_light: Rational, because it doesn't read excluded directories (`!**/node_modules/**`). | ||
* :gear: Universal, because it supports Synchronous, Promise and Stream API. | ||
* :money_with_wings: Economy, because it provides `fs.Stats` for matched path if you wanted. | ||
## Table of Contents | ||
## Donate | ||
<details> | ||
<summary><strong>Details</strong></summary> | ||
If you want to thank me, or promote your Issue. | ||
* [Highlights](#highlights) | ||
* [Donation](#donation) | ||
* [Old and modern mode](#old-and-modern-mode) | ||
* [Pattern syntax](#pattern-syntax) | ||
* [Basic syntax](#basic-syntax) | ||
* [Advanced syntax](#advanced-syntax) | ||
* [Installation](#installation) | ||
* [API](#api) | ||
* [Asynchronous](#asynchronous) | ||
* [Synchronous](#synchronous) | ||
* [Stream](#stream) | ||
* [patterns](#patterns) | ||
* [[options]](#options) | ||
* [Options](#options-1) | ||
* [Common](#common) | ||
* [concurrency](#concurrency) | ||
* [cwd](#cwd) | ||
* [deep](#deep) | ||
* [followSymbolicLinks](#followsymboliclinks) | ||
* [fs](#fs) | ||
* [ignore](#ignore) | ||
* [suppressErrors](#suppresserrors) | ||
* [throwErrorOnBrokenSymbolicLink](#throwerroronbrokensymboliclink) | ||
* [Output control](#output-control) | ||
* [absolute](#absolute) | ||
* [markDirectories](#markdirectories) | ||
* [objectMode](#objectmode) | ||
* [onlyDirectories](#onlydirectories) | ||
* [onlyFiles](#onlyfiles) | ||
* [stats](#stats) | ||
* [unique](#unique) | ||
* [Matching control](#matching-control) | ||
* [braceExpansion](#braceexpansion) | ||
* [caseSensitiveMatch](#casesensitivematch) | ||
* [dot](#dot) | ||
* [extglob](#extglob) | ||
* [globstar](#globstar) | ||
* [baseNameMatch](#basenamematch) | ||
* [FAQ](#faq) | ||
* [How to write patterns on Windows?](#how-to-write-patterns-on-windows) | ||
* [Why are parentheses match wrong?](#why-are-parentheses-match-wrong) | ||
* [How to exclude directory from reading?](#how-to-exclude-directory-from-reading) | ||
* [How to use UNC path?](#how-to-use-unc-path) | ||
* [Compatible with `node-glob`?](#compatible-with-node-glob) | ||
* [Benchmarks](#benchmarks) | ||
* [Server](#server) | ||
* [Nettop](#nettop) | ||
* [Changelog](#changelog) | ||
* [License](#license) | ||
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://paypal.me/mrmlnc) | ||
</details> | ||
> Sorry, but I have work and support for packages requires some time after work. I will be glad of your support and PR's. | ||
## Highlights | ||
## Install | ||
* Fast. Probably the fastest. | ||
* Supports multiple and negative patterns. | ||
* Synchronous, Promise and Stream API. | ||
* Object mode. Can return more than just strings. | ||
* Error-tolerant. | ||
## Donation | ||
Do you like this project? Support it by donating, creating an issue or pull request. | ||
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)][paypal_mrmlnc] | ||
## Old and modern mode | ||
This package works in two modes, depending on the environment in which it is used. | ||
* **Old mode**. Node.js below 10.10 or when the `stats` option is *enabled*. | ||
* **Modern mode**. Node.js 10.10+ and the `stats` option is *disabled*. | ||
The modern mode is faster. Learn more about the [internal mechanism][nodelib_fs_scandir_old_and_modern_modern]. | ||
## Pattern syntax | ||
> :warning: Always use forward-slashes in glob expressions (patterns and [`ignore`](#ignore) option). Use backslashes for escaping characters. | ||
There is more than one form of syntax: basic and advanced. Below is a brief overview of the supported features. Also pay attention to our [FAQ](#faq). | ||
> :book: This package uses a [`micromatch`][micromatch] as a library for pattern matching. | ||
### Basic syntax | ||
* An asterisk (`*`) — matches everything except slashes (path separators), hidden files (names starting with `.`). | ||
* A double star or globstar (`**`) — matches zero or more directories. | ||
* Question mark (`?`) – matches any single character except slashes (path separators). | ||
* Sequence (`[seq]`) — matches any character in sequence. | ||
> :book: A few additional words about the [basic matching behavior][picomatch_matching_behavior]. | ||
Some examples: | ||
* `src/**/*.js` — matches all files in the `src` directory (any level of nesting) that have the `.js` extension. | ||
* `src/*.??` — matches all files in the `src` directory (only first level of nesting) that have a two-character extension. | ||
* `file-[01].js` — matches files: `file-0.js`, `file-1.js`. | ||
### Advanced syntax | ||
* [Escapes characters][micromatch_backslashes] (`\\`) — matching special characters (`$^*+?()[]`) as literals. | ||
* [POSIX character classes][picomatch_posix_brackets] (`[[:digit:]]`). | ||
* [Extended globs][micromatch_extglobs] (`?(pattern-list)`). | ||
* [Bash style brace expansions][micromatch_braces] (`{}`). | ||
* [Regexp character classes][micromatch_regex_character_classes] (`[1-5]`). | ||
* [Regex groups][regular_expressions_brackets] (`(a|b)`). | ||
> :book: A few additional words about the [advanced matching behavior][micromatch_extended_globbing]. | ||
Some examples: | ||
* `src/**/*.{css,scss)` — matches all files in the `src` directory (any level of nesting) that have the `.css` or `.scss` extension. | ||
* `file-[[:digit:]].js` — matches files: `file-0.js`, `file-1.js`, …, `file-9.js`. | ||
* `file-{1..3}.js` — matches files: `file-1.js`, `file-2.js`, `file-3.js`. | ||
* `file-(1|2)` — matches files: `file-1.js`, `file-2.js`. | ||
## Installation | ||
```console | ||
npm install fast-glob | ||
``` | ||
$ npm install --save fast-glob | ||
``` | ||
## Usage | ||
## API | ||
#### Asynchronous | ||
### Asynchronous | ||
```js | ||
const fg = require('fast-glob'); | ||
fg(['src/**/*.js', '!src/**/*.spec.js']).then((entries) => console.log(entries)); | ||
fg.async(['src/**/*.js', '!src/**/*.spec.js']).then((entries) => console.log(entries)); | ||
fg(patterns, [options]) | ||
``` | ||
#### Synchronous | ||
Returns a `Promise` with an array of matching entries. | ||
@@ -43,86 +147,77 @@ ```js | ||
const entries = fg.sync(['src/**/*.js', '!src/**/*.spec.js']); | ||
console.log(entries); | ||
const entries = await fg(['.editorconfig', '**/index.js'], { dot: true }); | ||
// ['.editorconfig', 'services/index.js'] | ||
``` | ||
#### Stream | ||
### Synchronous | ||
```js | ||
fg.sync(patterns, [options]) | ||
``` | ||
Returns an array of matching entries. | ||
```js | ||
const fg = require('fast-glob'); | ||
const stream = fg.stream(['src/**/*.js', '!src/**/*.spec.js']); | ||
const entries = fg.sync(['.editorconfig', '**/index.js'], { dot: true }); | ||
const entries = []; | ||
stream.on('data', (entry) => entries.push(entry)); | ||
stream.once('error', console.log); | ||
stream.once('end', () => console.log(entries)); | ||
// ['.editorconfig', 'services/index.js'] | ||
``` | ||
## API | ||
### Stream | ||
### fg(patterns, [options]) | ||
### fg.async(patterns, [options]) | ||
```js | ||
fg.stream(patterns, [options]) | ||
``` | ||
Returns a `Promise` with an array of matching [entries](#entry). | ||
Returns a [`ReadableStream`][node_js_stream_readable_streams] when the `data` event will be emitted with matching entry. | ||
### fg.sync(patterns, [options]) | ||
```js | ||
const fg = require('fast-glob'); | ||
Returns an array of matching [entries](#entry). | ||
const stream = fg.sync(['.editorconfig', '**/index.js'], { dot: true }); | ||
### fg.stream(patterns, [options]) | ||
for await (const entry of stream) { | ||
// .editorconfig | ||
// services/index.js | ||
} | ||
``` | ||
Returns a [`ReadableStream`](https://nodejs.org/api/stream.html#stream_readable_streams) when the `data` event will be emitted with [`Entry`](#entry). | ||
#### patterns | ||
* Type: `string|string[]` | ||
* Required: `true` | ||
* Type: `string | string[]` | ||
This package does not respect the order of patterns. First, all the negative patterns are applied, and only then the positive patterns. | ||
Any correct pattern(s). | ||
#### options | ||
> :1234: [Pattern syntax](#pattern-syntax) | ||
> | ||
> :warning: This package does not respect the order of patterns. First, all the negative patterns are applied, and only then the positive patterns. If you want to get a certain order of records, use sorting or split calls. | ||
* Type: `Object` | ||
#### [options] | ||
See [options](#options-1) section for more detailed information. | ||
* Required: `false` | ||
* Type: [`Options`](#options-1) | ||
### fg.generateTasks(patterns, [options]) | ||
See [Options](#options-1) section. | ||
Return a set of tasks based on provided patterns. All tasks satisfy the `Task` interface: | ||
## Options | ||
```ts | ||
interface Task { | ||
/** | ||
* Parent directory for all patterns inside this task. | ||
*/ | ||
base: string; | ||
/** | ||
* Dynamic or static patterns are in this task. | ||
*/ | ||
dynamic: boolean; | ||
/** | ||
* All patterns. | ||
*/ | ||
patterns: string[]; | ||
/** | ||
* Only positive patterns. | ||
*/ | ||
positive: string[]; | ||
/** | ||
* Only negative patterns without ! symbol. | ||
*/ | ||
negative: string[]; | ||
} | ||
``` | ||
### Common options | ||
## Entry | ||
#### concurrency | ||
The entry which can be a `string` if the [`stats`](#stats) option is disabled, otherwise `fs.Stats` with two additional `path` and `depth` properties. | ||
* Type: `number` | ||
* Default: `os.cpus().length` | ||
## Options | ||
Specifies the maximum number of concurrent requests from a reader to read directories. | ||
> :book: The higher the number, the higher the performance and load on the file system. If you want to read in quiet mode, set the value to a comfortable number or `1`. | ||
#### cwd | ||
* Type: `string` | ||
* Default: `process.cwd()` | ||
* Type: `string` | ||
* Default: `process.cwd()` | ||
@@ -133,28 +228,53 @@ The current working directory in which to search. | ||
* Type: `number|boolean` | ||
* Default: `true` | ||
* Type: `number` | ||
* Default: `Infinity` | ||
The deep option can be set to `true` to traverse the entire directory structure, or it can be set to a *number* to only traverse that many levels deep. | ||
Specifies the maximum depth of a read directory relative to the start directory. | ||
For example, you have the following tree: | ||
```js | ||
dir/ | ||
└── one/ // 1 | ||
└── two/ // 2 | ||
└── file.js // 3 | ||
``` | ||
test | ||
└── one | ||
└── two | ||
└── index.js | ||
```js | ||
// With base directory | ||
fg.sync('dir/**', { onlyFiles: false, deep: 1 }); // ['dir/one'] | ||
fg.sync('dir/**', { onlyFiles: false, deep: 2 }); // ['dir/one', 'dir/one/two'] | ||
// With cwd option | ||
fg.sync('**', { onlyFiles: false, cwd: 'dir', deep: 1 }); // ['one'] | ||
fg.sync('**', { onlyFiles: false, cwd: 'dir', deep: 2 }); // ['one', 'one/two'] | ||
``` | ||
> :book: If you specify a pattern with some base directory, this directory will not participate in the calculation of the depth of the found directories. Think of it as a `cwd` option. | ||
> :book: If you specify a pattern with some base directory, this directory will not participate in the calculation of the depth of the found directories. Think of it as a [`cwd`](#cwd) option. | ||
```js | ||
fg('test/**', { onlyFiles: false, deep: 0 }); | ||
// -> ['test/one'] | ||
fg('test/**', { onlyFiles: false, deep: 1 }); | ||
// -> ['test/one', 'test/one/two'] | ||
#### followSymbolicLinks | ||
fg('**', { onlyFiles: false, cwd: 'test', deep: 0 }); | ||
// -> ['one'] | ||
fg('**', { onlyFiles: false, cwd: 'test', deep: 1 }); | ||
// -> ['one', 'one/two'] | ||
* Type: `boolean` | ||
* Default: `true` | ||
Indicates whether to traverse descendants of symbolic link directories. | ||
> :book: If the [`stats`](#stats) option is specified, the information about the symbolic link (`fs.lstat`) will be replaced with information about the entry (`fs.stat`) behind it. | ||
#### fs | ||
* Type: `FileSystemAdapter` | ||
* Default: `fs.*` | ||
Custom implementation of methods for working with the file system. | ||
```ts | ||
export interface FileSystemAdapter { | ||
lstat?: typeof fs.lstat; | ||
stat?: typeof fs.stat; | ||
lstatSync?: typeof fs.lstatSync; | ||
statSync?: typeof fs.statSync; | ||
readdir?: typeof fs.readdir; | ||
readdirSync?: typeof fs.readdirSync; | ||
} | ||
``` | ||
@@ -164,174 +284,314 @@ | ||
* Type: `string[]` | ||
* Default: `[]` | ||
* Type: `string[]` | ||
* Default: `[]` | ||
An array of glob patterns to exclude matches. | ||
An array of glob patterns to exclude matches. This is an alternative way to use negative patterns. | ||
#### dot | ||
```js | ||
dir/ | ||
├── package-lock.json | ||
└── package.json | ||
``` | ||
* Type: `boolean` | ||
* Default: `false` | ||
```js | ||
fg.sync(['*.json', '!package-lock.json']); // ['package.json'] | ||
fg.sync('*.json', { ignore: ['package-lock.json'] }); // ['package.json'] | ||
``` | ||
Allow patterns to match filenames starting with a period (files & directories), even if the pattern does not explicitly have a period in that spot. | ||
#### suppressErrors | ||
#### stats | ||
* Type: `boolean` | ||
* Default: `false` | ||
* Type: `boolean` | ||
* Default: `false` | ||
By default this package suppress only `ENOENT` errors. Set to `true` to suppress any error. | ||
Return `fs.Stats` with two additional `path` and `depth` properties instead of a `string`. | ||
> :book: Can be useful when the directory has entries with a special level of access. | ||
#### onlyFiles | ||
#### throwErrorOnBrokenSymbolicLink | ||
* Type: `boolean` | ||
* Default: `true` | ||
* Type: `boolean` | ||
* Default: `false` | ||
Return only files. | ||
Throw an error when symbolic link is broken if `true` or safely return `lstat` call if `false`. | ||
> :book: This option has no effect on errors when reading the symbolic link directory. | ||
### Output control | ||
#### absolute | ||
* Type: `boolean` | ||
* Default: `false` | ||
Return the absolute path for entries. | ||
```js | ||
fg.sync('*.js', { absolute: false }); // ['index.js'] | ||
fg.sync('*.js', { absolute: true }); // ['/home/user/index.js'] | ||
``` | ||
> :book: This option is required if you want to use negative patterns with absolute path, for example, `!${__dirname}/*.js`. | ||
#### markDirectories | ||
* Type: `boolean` | ||
* Default: `false` | ||
Mark the directory path with the final slash. | ||
```js | ||
fs.sync('*', { onlyFiles: false, markDirectories: false }); // ['index.js', 'controllers'] | ||
fs.sync('*', { onlyFiles: false, markDirectories: true }); // ['index.js', 'controllers/'] | ||
``` | ||
#### objectMode | ||
* Type: `boolean` | ||
* Default: `false` | ||
Returns objects (instead of strings) describing entries. | ||
```js | ||
fg.sync('*', { objectMode: false }); // ['src/index.js'] | ||
fg.sync('*', { objectMode: true }); // [{ name: 'index.js', path: 'src/index.js', dirent: <fs.Dirent> }] | ||
``` | ||
The object has the following fields: | ||
* name (`string`) — the last part of the path (basename) | ||
* path (`string`) — full path relative to the pattern base directory | ||
* dirent ([`fs.Dirent`][node_js_fs_class_fs_dirent]) — instance of `fs.Direct` | ||
> :book: An object is an internal representation of entry, so getting it does not affect performance. | ||
#### onlyDirectories | ||
* Type: `boolean` | ||
* Default: `false` | ||
* Type: `boolean` | ||
* Default: `false` | ||
Return only directories. | ||
#### followSymlinkedDirectories | ||
```js | ||
fg.sync('*', { onlyDirectories: false }); // ['index.js', 'src'] | ||
fg.sync('*', { onlyDirectories: true }); // ['src'] | ||
``` | ||
* Type: `boolean` | ||
* Default: `true` | ||
> :book: If `true`, the [`onlyFiles`](#onlyfiles) option is automatically `false`. | ||
Follow symlinked directories when expanding `**` patterns. | ||
#### onlyFiles | ||
#### unique | ||
* Type: `boolean` | ||
* Default: `false` | ||
* Type: `boolean` | ||
* Default: `true` | ||
Return only files. | ||
Prevent duplicate results. | ||
```js | ||
fg.sync('*', { onlyFiles: false }); // ['index.js', 'src'] | ||
fg.sync('*', { onlyFiles: true }); // ['index.js'] | ||
``` | ||
#### markDirectories | ||
#### stats | ||
* Type: `boolean` | ||
* Default: `false` | ||
* Type: `boolean` | ||
* Default: `false` | ||
Add a `/` character to directory entries. | ||
Enables an [object mode](#objectmode) with an additional field: | ||
#### absolute | ||
* stats ([`fs.Stats`][node_js_fs_class_fs_stats]) — instance of `fs.Stats` | ||
* Type: `boolean` | ||
* Default: `false` | ||
```js | ||
fg.sync('*', { stats: false }); // ['src/index.js'] | ||
fg.sync('*', { stats: true }); // [{ name: 'index.js', path: 'src/index.js', dirent: <fs.Dirent>, stats: <fs.Stats> }] | ||
``` | ||
Return absolute paths for matched entries. | ||
> :book: Returns `fs.stat` instead of `fs.lstat` for symbolic links when the [`followSymbolicLinks`](#followsymboliclinks) option is specified. | ||
> | ||
> :warning: Unlike [object mode](#objectmode) this mode requires additional calls to the file system. On average, this mode is slower at least twice. See [old and modern mode](#old-and-modern-mode) for more details. | ||
> :book: Note that you need to use this option if you want to use absolute negative patterns like `${__dirname}/*.md`. | ||
#### unique | ||
#### nobrace | ||
* Type: `boolean` | ||
* Default: `true` | ||
* Type: `boolean` | ||
* Default: `false` | ||
Ensures that the returned entries are unique. | ||
Disable expansion of brace patterns (`{a,b}`, `{1..3}`). | ||
```js | ||
fg.sync(['*.json', 'package.json'], { unique: false }); // ['package.json', 'package.json'] | ||
fg.sync(['*.json', 'package.json'], { unique: true }); // ['package.json'] | ||
``` | ||
#### brace | ||
If `true` and similar entries are found, the result is the first found. | ||
* Type: `boolean` | ||
* Default: `true` | ||
### Matching control | ||
The [`nobrace`](#nobrace) option without double-negation. This option has a higher priority then `nobrace`. | ||
#### braceExpansion | ||
#### noglobstar | ||
* Type: `boolean` | ||
* Default: `true` | ||
* Type: `boolean` | ||
* Default: `false` | ||
Enables Bash-like brace expansion. | ||
Disable matching with globstars (`**`). | ||
> :1234: [Syntax description][bash_hackers_syntax_expansion_brace] or mode [detailed description][micromatch_braces]. | ||
#### globstar | ||
```js | ||
dir/ | ||
├── abd | ||
├── acd | ||
└── a{b,c}d | ||
``` | ||
* Type: `boolean` | ||
* Default: `true` | ||
```js | ||
fg.sync('a{b,c}d', { braceExpansion: false }); // ['a{b,c}d'] | ||
fg.sync('a{b,c}d', { braceExpansion: true }); // ['abd', 'acd'] | ||
``` | ||
The [`noglobstar`](#noglobstar) option without double-negation. This option has a higher priority then `noglobstar`. | ||
#### caseSensitiveMatch | ||
#### noext | ||
* Type: `boolean` | ||
* Default: `true` | ||
* Type: `boolean` | ||
* Default: `false` | ||
Enables a [case-sensitive][wikipedia_case_sensitivity] mode for matching files. | ||
Disable extglob support (patterns like `+(a|b)`), so that extglobs are regarded as literal characters. | ||
```js | ||
dir/ | ||
├── file.txt | ||
└── File.txt | ||
``` | ||
#### extension | ||
```js | ||
fg.sync('file.txt', { caseSensitiveMatch: false }); // ['file.txt', 'File.txt'] | ||
fg.sync('file.txt', { caseSensitiveMatch: true }); // ['file.txt'] | ||
``` | ||
* Type: `boolean` | ||
* Default: `true` | ||
#### dot | ||
The [`noext`](#noext) option without double-negation. This option has a higher priority then `noext`. | ||
* Type: `boolean` | ||
* Default: `false` | ||
#### nocase | ||
Allow patterns to match entries that begin with a period (`.`). | ||
* Type: `boolean` | ||
* Default: `false` | ||
> :book: Note that an explicit dot in a portion of the pattern will always match dot files. | ||
Disable a [case-sensitive](https://en.wikipedia.org/wiki/Case_sensitivity) mode for matching files. | ||
```js | ||
dir/ | ||
├── .editorconfig | ||
└── package.json | ||
``` | ||
##### Examples | ||
```js | ||
fg.sync('file.txt', { dot: false }); // ['package.json'] | ||
fg.sync('file.txt', { dot: true }); // ['.editorconfig', 'package.json'] | ||
``` | ||
* File System: `test/file.md`, `test/File.md` | ||
* Case-sensitive for `test/file.*` pattern (`false`): `test/file.md` | ||
* Case-insensitive for `test/file.*` pattern (`true`): `test/file.md`, `test/File.md` | ||
#### extglob | ||
#### case | ||
* Type: `boolean` | ||
* Default: `true` | ||
* Type: `boolean` | ||
* Default: `true` | ||
Enables Bash-like `extglob` functionality. | ||
The [`nocase`](#nocase) option without double-negation. This option has a higher priority then `nocase`. | ||
> :1234: [Syntax description][micromatch_extglobs]. | ||
#### matchBase | ||
```js | ||
dir/ | ||
├── README.md | ||
└── package.json | ||
``` | ||
* Type: `boolean` | ||
* Default: `false` | ||
```js | ||
fg.sync('*.+(json|md)', { extglob: false }); // [] | ||
fg.sync('*.+(json|md)', { extglob: true }); // ['README.md', 'package.json'] | ||
``` | ||
Allow glob patterns without slashes to match a file path based on its basename. For example, `a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`. | ||
#### globstar | ||
#### transform | ||
* Type: `boolean` | ||
* Default: `true` | ||
* Type: `Function` | ||
* Default: `null` | ||
Enables recursively repeats a pattern containing `**`. If `false`, `**` behaves exactly like `*`. | ||
Allows you to transform a path or `fs.Stats` object before sending to the array. | ||
```js | ||
dir/ | ||
└── a | ||
└── b | ||
``` | ||
```js | ||
const fg = require('fast-glob'); | ||
fg.sync('**', { onlyFiles: false, globstar: false }); // ['a'] | ||
fg.sync('**', { onlyFiles: false, globstar: true }); // ['a', 'a/b'] | ||
``` | ||
const entries1 = fg.sync(['**/*.scss']); | ||
const entries2 = fg.sync(['**/*.scss'], { transform: (entry) => '_' + entry }); | ||
#### baseNameMatch | ||
console.log(entries1); // ['a.scss', 'b.scss'] | ||
console.log(entries2); // ['_a.scss', '_b.scss'] | ||
* Type: `boolean` | ||
* Default: `false` | ||
If set to `true`, then patterns without slashes will be matched against the basename of the path if it contains slashes. | ||
```js | ||
dir/ | ||
└── one/ | ||
└── file.md | ||
``` | ||
If you are using **TypeScript**, you probably want to specify your own type of the returned array. | ||
```js | ||
fg.sync('*.md', { baseNameMatch: false }); // [] | ||
fg.sync('*.md', { baseNameMatch: true }); // ['one/file.md'] | ||
``` | ||
## FAQ | ||
## How to write patterns on Windows? | ||
Always use forward-slashes in glob expressions (patterns and [`ignore`](#ignore) option). Use backslashes for escaping characters. With the [`cwd`](#cwd) option use a convenient format. | ||
**Bad** | ||
```ts | ||
import * as fg from 'fast-glob'; | ||
[ | ||
'directory\\*', | ||
path.join(process.cwd(), '**') | ||
] | ||
``` | ||
interface IMyOwnEntry { | ||
path: string; | ||
} | ||
**Good** | ||
const entries: IMyOwnEntry[] = fg.sync<IMyOwnEntry>(['*.md'], { | ||
transform: (entry) => typeof entry === 'string' ? { path: entry } : { path: entry.path } | ||
// Will throw compilation error for non-IMyOwnEntry types (boolean, for example) | ||
}); | ||
```ts | ||
[ | ||
'directory/*', | ||
path.join(process.cwd(), '**').replace(/\\/g, '/') | ||
] | ||
``` | ||
> :book: Use the [`normalize-path`][npm_normalize_path] or the [`unixify`][npm_unixify] package to convert Windows-style path to a Unix-style path. | ||
Read more about [matching with backslashes][micromatch_backslashes]. | ||
## Why are parentheses match wrong? | ||
```js | ||
dir/ | ||
└── (special-*file).txt | ||
``` | ||
```js | ||
fg.sync(['(special-*file).txt']) // [] | ||
``` | ||
Refers to Bash. You need to escape special characters: | ||
```js | ||
fg.sync(['\\(special-*file\\).txt']) // ['(special-*file).txt'] | ||
``` | ||
Read more about [matching special characters as literals][picomatch_matching_special_characters_as_literals]. | ||
## How to exclude directory from reading? | ||
You can use a negative pattern like this: `!**/node_modules` or `!**/node_modules/**`. Also you can use `ignore` option. Just look at the example below. | ||
You can use a negative pattern like this: `!**/node_modules` or `!**/node_modules/**`. Also you can use [`ignore`](#ignore) option. Just look at the example below. | ||
``` | ||
```js | ||
first/ | ||
├── file.md | ||
└── second | ||
└── second/ | ||
└── file.txt | ||
@@ -343,4 +603,4 @@ ``` | ||
```js | ||
fg.sync(['**/*.md', '!**/second']); // ['first/file.txt'] | ||
fg.sync(['**/*.md'], { ignore: '**/second/**' }); // ['first/file.txt'] | ||
fg.sync(['**/*.md', '!**/second']); // ['first/file.md'] | ||
fg.sync(['**/*.md'], { ignore: ['**/second/**'] }); // ['first/file.md'] | ||
``` | ||
@@ -354,3 +614,3 @@ | ||
You cannot use UNC paths as patterns (due to syntax), but you can use them as `cwd` directory. | ||
You cannot use [Uniform Naming Convention (UNC)][unc_path] paths as patterns (due to syntax), but you can use them as `cwd` directory. | ||
@@ -364,4 +624,2 @@ ```ts | ||
Not fully, because `fast-glob` does not implement all options of `node-glob`. See table below. | ||
| node-glob | fast-glob | | ||
@@ -376,10 +634,10 @@ | :----------: | :-------: | | ||
| `nounique` | [`unique`](#unique) | | ||
| `nobrace` | [`nobrace`](#nobrace) or [`brace`](#brace) | | ||
| `noglobstar` | [`noglobstar`](#noglobstar) or [`globstar`](#globstar) | | ||
| `noext` | [`noext`](#noext) or [`extension`](#extension) | | ||
| `nocase` | [`nocase`](#nocase) or [`case`](#case) | | ||
| `matchBase` | [`matchbase`](#matchbase) | | ||
| `nobrace` | [`braceExpansion`](#braceexpansion) | | ||
| `noglobstar` | [`globstar`](#globstar) | | ||
| `noext` | [`extglob`](#extglob) | | ||
| `nocase` | [`caseSensitiveMatch`](#casesensitivematch) | | ||
| `matchBase` | [`baseNameMatch`](#basenamematch) | | ||
| `nodir` | [`onlyFiles`](#onlyfiles) | | ||
| `ignore` | [`ignore`](#ignore) | | ||
| `follow` | [`followSymlinkedDirectories`](#followsymlinkeddirectories) | | ||
| `follow` | [`followSymbolicLinks`](#followsymboliclinks) | | ||
| `realpath` | – | | ||
@@ -390,24 +648,25 @@ | `absolute` | [`absolute`](#absolute) | | ||
**Tech specs:** | ||
### Server | ||
Server: [Vultr Bare Metal](https://www.vultr.com/pricing/baremetal) | ||
Link: [Vultr Bare Metal][vultr_pricing_baremetal] | ||
* Processor: E3-1270v6 (8 CPU) | ||
* RAM: 32GB | ||
* Disk: SSD | ||
* Processor: E3-1270v6 (8 CPU) | ||
* RAM: 32GB | ||
* Disk: SSD ([Intel DC S3520 SSDSC2BB240G7][intel_ssd]) | ||
You can see results [here](https://gist.github.com/mrmlnc/f06246b197f53c356895fa35355a367c) for latest release. | ||
You can see results [here][github_gist_benchmark_server] for latest release. | ||
## Related | ||
### Nettop | ||
* [readdir-enhanced](https://github.com/BigstickCarpet/readdir-enhanced) – Fast functional replacement for `fs.readdir()`. | ||
* [globby](https://github.com/sindresorhus/globby) – User-friendly glob matching. | ||
* [node-glob](https://github.com/isaacs/node-glob) – «Standard» glob functionality for Node.js | ||
* [bash-glob](https://github.com/micromatch/bash-glob) – Bash-powered globbing for node.js. | ||
* [glob-stream](https://github.com/gulpjs/glob-stream) – A Readable Stream interface over node-glob that used in the [gulpjs](https://github.com/gulpjs/gulp). | ||
* [tiny-glob](https://github.com/terkelg/tiny-glob) – Tiny and extremely fast library to match files and folders using glob patterns. | ||
Link: [Zotac bi323][zotac_bi323] | ||
* Processor: Intel N3150 (4 CPU) | ||
* RAM: 8GB | ||
* Disk: SSD ([Silicon Power SP060GBSS3S55S25][silicon_power_ssd]) | ||
You can see results [here][github_gist_benchmark_nettop] for latest release. | ||
## Changelog | ||
See the [Releases section of our GitHub project](https://github.com/mrmlnc/fast-glob/releases) for changelogs for each release version. | ||
See the [Releases section of our GitHub project][github_releases] for changelog for each release version. | ||
@@ -417,1 +676,32 @@ ## License | ||
This software is released under the terms of the MIT license. | ||
[bash_hackers_syntax_expansion_brace]: https://wiki.bash-hackers.org/syntax/expansion/brace | ||
[github_gist_benchmark_nettop]: https://gist.github.com/mrmlnc/f06246b197f53c356895fa35355a367c#file-fast_glob_benchmark_nettop-txt | ||
[github_gist_benchmark_server]: https://gist.github.com/mrmlnc/f06246b197f53c356895fa35355a367c#file-fast_glob_benchmark_server-txt | ||
[github_releases]: https://github.com/mrmlnc/fast-glob/releases | ||
[glob_definition]: https://en.wikipedia.org/wiki/Glob_(programming) | ||
[glob_linux_man]: http://man7.org/linux/man-pages/man3/glob.3.html | ||
[intel_ssd]: https://ark.intel.com/content/www/us/en/ark/products/93012/intel-ssd-dc-s3520-series-240gb-2-5in-sata-6gb-s-3d1-mlc.html | ||
[micromatch_backslashes]: https://github.com/micromatch/micromatch#backslashes | ||
[micromatch_braces]: https://github.com/micromatch/braces | ||
[micromatch_extended_globbing]: https://github.com/micromatch/micromatch#extended-globbing | ||
[micromatch_extglobs]: https://github.com/micromatch/micromatch#extglobs | ||
[micromatch_regex_character_classes]: https://github.com/micromatch/micromatch#regex-character-classes | ||
[micromatch]: https://github.com/micromatch/micromatch | ||
[node_js_fs_class_fs_dirent]: https://nodejs.org/api/fs.html#fs_class_fs_dirent | ||
[node_js_fs_class_fs_stats]: https://nodejs.org/api/fs.html#fs_class_fs_stats | ||
[node_js_stream_readable_streams]: https://nodejs.org/api/stream.html#stream_readable_streams | ||
[node_js]: https://nodejs.org/en | ||
[nodelib_fs_scandir_old_and_modern_modern]: https://github.com/nodelib/nodelib/blob/master/packages/fs/fs.scandir/README.md#old-and-modern-mode | ||
[npm_normalize_path]: https://www.npmjs.com/package/normalize-path | ||
[npm_unixify]: https://www.npmjs.com/package/unixify | ||
[paypal_mrmlnc]:https://paypal.me/mrmlnc | ||
[picomatch_matching_behavior]: https://github.com/micromatch/picomatch#matching-behavior-vs-bash | ||
[picomatch_matching_special_characters_as_literals]: https://github.com/micromatch/picomatch#matching-special-characters-as-literals | ||
[picomatch_posix_brackets]: https://github.com/micromatch/picomatch#posix-brackets | ||
[regular_expressions_brackets]: https://www.regular-expressions.info/brackets.html | ||
[silicon_power_ssd]: https://www.silicon-power.com/web/product-1 | ||
[unc_path]: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/62e862f4-2a51-452e-8eeb-dc4ff5ee33cc | ||
[vultr_pricing_baremetal]: https://www.vultr.com/pricing/baremetal | ||
[wikipedia_case_sensitivity]: https://en.wikipedia.org/wiki/Case_sensitivity | ||
[zotac_bi323]: https://www.zotac.com/ee/product/mini_pcs/zbox-bi323 |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
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
27
699
70288
47
1185
2
1
+ Added@nodelib/fs.walk@^1.1.0
+ Added@nodelib/fs.scandir@2.1.5(transitive)
+ Added@nodelib/fs.stat@2.0.5(transitive)
+ Added@nodelib/fs.walk@1.2.8(transitive)
+ Addedbraces@3.0.3(transitive)
+ Addedfastq@1.17.1(transitive)
+ Addedfill-range@7.1.1(transitive)
+ Addedglob-parent@5.1.2(transitive)
+ Addedis-number@7.0.0(transitive)
+ Addedmicromatch@4.0.8(transitive)
+ Addedpicomatch@2.3.1(transitive)
+ Addedqueue-microtask@1.2.3(transitive)
+ Addedreusify@1.0.4(transitive)
+ Addedrun-parallel@1.2.0(transitive)
+ Addedto-regex-range@5.0.1(transitive)
- Removed@mrmlnc/readdir-enhanced@^2.2.1
- Removed@mrmlnc/readdir-enhanced@2.2.1(transitive)
- Removed@nodelib/fs.stat@1.1.3(transitive)
- Removedarr-diff@4.0.0(transitive)
- Removedarr-flatten@1.1.0(transitive)
- Removedarr-union@3.1.0(transitive)
- Removedarray-unique@0.3.2(transitive)
- Removedassign-symbols@1.0.0(transitive)
- Removedatob@2.1.2(transitive)
- Removedbase@0.11.2(transitive)
- Removedbraces@2.3.2(transitive)
- Removedcache-base@1.0.1(transitive)
- Removedcall-me-maybe@1.0.2(transitive)
- Removedclass-utils@0.3.6(transitive)
- Removedcollection-visit@1.0.0(transitive)
- Removedcomponent-emitter@1.3.1(transitive)
- Removedcopy-descriptor@0.1.1(transitive)
- Removeddebug@2.6.9(transitive)
- Removeddecode-uri-component@0.2.2(transitive)
- Removeddefine-property@0.2.51.0.02.0.2(transitive)
- Removedexpand-brackets@2.1.4(transitive)
- Removedextend-shallow@2.0.13.0.2(transitive)
- Removedextglob@2.0.4(transitive)
- Removedfill-range@4.0.0(transitive)
- Removedfor-in@1.0.2(transitive)
- Removedfragment-cache@0.2.1(transitive)
- Removedfunction-bind@1.1.2(transitive)
- Removedget-value@2.0.6(transitive)
- Removedglob-parent@3.1.0(transitive)
- Removedglob-to-regexp@0.3.0(transitive)
- Removedhas-value@0.3.11.0.0(transitive)
- Removedhas-values@0.1.41.0.0(transitive)
- Removedhasown@2.0.2(transitive)
- Removedis-accessor-descriptor@1.0.1(transitive)
- Removedis-buffer@1.1.6(transitive)
- Removedis-data-descriptor@1.0.1(transitive)
- Removedis-descriptor@0.1.71.0.3(transitive)
- Removedis-extendable@0.1.11.0.1(transitive)
- Removedis-glob@3.1.0(transitive)
- Removedis-number@3.0.0(transitive)
- Removedis-plain-object@2.0.4(transitive)
- Removedis-windows@1.0.2(transitive)
- Removedisarray@1.0.0(transitive)
- Removedisobject@2.1.03.0.1(transitive)
- Removedkind-of@3.2.24.0.06.0.3(transitive)
- Removedmap-cache@0.2.2(transitive)
- Removedmap-visit@1.0.0(transitive)
- Removedmicromatch@3.1.10(transitive)
- Removedmixin-deep@1.3.2(transitive)
- Removedms@2.0.0(transitive)
- Removednanomatch@1.2.13(transitive)
- Removedobject-copy@0.1.0(transitive)
- Removedobject-visit@1.0.1(transitive)
- Removedobject.pick@1.3.0(transitive)
- Removedpascalcase@0.1.1(transitive)
- Removedpath-dirname@1.0.2(transitive)
- Removedposix-character-classes@0.1.1(transitive)
- Removedregex-not@1.0.2(transitive)
- Removedrepeat-element@1.1.4(transitive)
- Removedrepeat-string@1.6.1(transitive)
- Removedresolve-url@0.2.1(transitive)
- Removedret@0.1.15(transitive)
- Removedsafe-regex@1.1.0(transitive)
- Removedset-value@2.0.1(transitive)
- Removedsnapdragon@0.8.2(transitive)
- Removedsnapdragon-node@2.1.1(transitive)
- Removedsnapdragon-util@3.0.1(transitive)
- Removedsource-map@0.5.7(transitive)
- Removedsource-map-resolve@0.5.3(transitive)
- Removedsource-map-url@0.4.1(transitive)
- Removedsplit-string@3.1.0(transitive)
- Removedstatic-extend@0.1.2(transitive)
- Removedto-object-path@0.3.0(transitive)
- Removedto-regex@3.0.2(transitive)
- Removedto-regex-range@2.1.1(transitive)
- Removedunion-value@1.0.1(transitive)
- Removedunset-value@1.0.0(transitive)
- Removedurix@0.1.0(transitive)
- Removeduse@3.1.1(transitive)
Updated@nodelib/fs.stat@^2.0.0
Updatedglob-parent@^5.0.0
Updatedmicromatch@^4.0.2