🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
DemoInstallSign in
Socket

glob-fs

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

glob-fs - npm Package Compare versions

Comparing version

to
0.1.6

lib/filter.js

117

index.js

@@ -9,10 +9,11 @@ 'use strict';

var visit = require('object-visit');
var extend = require('extend-shallow');
var Emitter = require('component-emitter');
var middleware = require('./lib/middleware');
var exclude = require('./middleware/exclude');
var include = require('./middleware/include');
var npm = require('./middleware/npm');
var symlinks = require('./lib/symlinks');
var iterators = require('./lib/iterators');
var Handler = require('./lib/handler');
var Pattern = require('./lib/pattern');
var options = require('./lib/options');
var readers = require('./lib/readers');

@@ -23,2 +24,10 @@ var utils = require('./lib/utils');

/**
* Lazily required module dependencies
*/
var lazy = require('lazy-cache')(require);
var gitignore = lazy('glob-fs-gitignore');
var dotfiles = lazy('glob-fs-dotfiles');
/**
* Optionally create an instance of `Glob` with the given `options`.

@@ -39,5 +48,6 @@ *

}
Emitter.call(this);
this.options = options || {};
this.init(this.options);
this.handler = new Handler(this);
this.init(options);
}

@@ -55,3 +65,5 @@

init: function (options) {
init: function (opts) {
this.options = opts || {};
this.pattern = null;
this.middleware = {};

@@ -63,2 +75,3 @@ this.includes = {};

options(this);
iterators(this);

@@ -83,7 +96,19 @@ symlinks(this);

}
middleware(this, glob, opts);
// if not disabled by the user, run the built-ins
if (!this.disabled('builtins')) {
if (!this.disabled('npm')) {
this.use(npm(opts));
}
if (!this.disabled('dotfiles')) {
this.use(dotfiles()(opts));
}
if (!this.disabled('gitignore')) {
this.use(gitignore()(opts));
}
}
},
/**
* Create an instance of `Pattern` for the current glob pattern.
* Create an instance of `Pattern` from the current glob pattern.
*

@@ -105,2 +130,3 @@ * @param {String} `pattern`

this.defaults(glob, options);
this.include(glob, options);
return this;

@@ -110,12 +136,9 @@ },

/**
* Create a file object with the given properties.
* Create a file object with properties that will be used
* by middleware.
*
* @param {String} `dir`
* @param {String} `segment`
* @param {String} `fp`
* @param {Object} `stat`
* @param {String} `file`
* @return {Object}
*/
// createFile: function (dir, segment, fp, stat) {
createFile: function (file) {

@@ -140,3 +163,3 @@ return new File({

shouldRecurse: function(pattern, options) {
var opts = extend({}, this.options, options);
var opts = this.setDefaults(options);
if (typeof opts.recurse === 'boolean') {

@@ -149,4 +172,3 @@ return opts.recurse;

/**
* Thin wrapper around `.use()` for easily excluding files or
* directories that match the given `pattern`.
* Add a middleware to be called in the order defined.
*

@@ -157,5 +179,4 @@ * ```js

* var glob = require('glob-fs')({ foo: true })
* .exclude(/\.foo$/)
* .exclude('*.bar')
* .exclude('*.baz');
* .use(gitignore())
* .use(dotfiles());
*

@@ -165,11 +186,10 @@ * var files = glob.readdirSync('**');

*
* @name .exclude
* @param {String} `pattern`
* @param {Object} `options`
* @name .use
* @param {Function} `fn`
* @return {Object} Returns the `Glob` instance, for chaining.
* @api public
*/
exclude: function(pattern, options) {
var opts = extend({}, this.options, options);
this.use(exclude(pattern, opts));
use: function(fn) {
this.handler.use(fn);
return this;

@@ -187,3 +207,3 @@ },

include: function(pattern, options) {
var opts = extend({}, this.options, options);
var opts = this.setDefaults(options);
this.use(include(pattern, opts));

@@ -194,3 +214,4 @@ return this;

/**
* Add a middleware to be called in the order defined.
* Thin wrapper around `.use()` for easily excluding files or
* directories that match the given `pattern`.
*

@@ -200,17 +221,20 @@ * ```js

* var dotfiles = require('glob-fs-dotfiles');
* var glob = require('glob-fs')({ foo: true })
* .use(gitignore())
* .use(dotfiles());
* var glob = require('glob-fs')()
* .exclude(/\.foo$/)
* .exclude('*.bar')
* .exclude('*.baz');
*
* var files = glob.readdirSync('*.js');
* var files = glob.readdirSync('**');
* //=> ['index.js', 'README.md', ...]
* ```
*
* @name .use
* @param {Function} `fn`
* @return {Object} Returns the `Glob` instance, for chaining.
* @name .exclude
* @param {String} `pattern`
* @param {Object} `options`
* @api public
*/
use: function(fn) {
this.fns.push(fn);
exclude: function(pattern, options) {
var opts = this.setDefaults(options);
this.use(exclude(pattern, opts));
return this;

@@ -240,14 +264,4 @@ },

handle: function(file) {
this.fns = this.fns.filter(Boolean);
var len = this.fns.length, i = -1;
this.track(file);
while (++i < len) {
this.fns[i].call(this, file);
this.track(file);
if (file.include === true || file.exclude === true) {
break;
}
}
this.handler.handle(file);
return this;
},

@@ -263,5 +277,6 @@

map: function(method, arr, options) {
utils.arrayify(arr || []).forEach(function (ele) {
this[method](ele, options);
map: function(method, arr/*, arguments*/) {
var args = [].slice.call(arguments, 2);
utils.arrayify(arr || []).forEach(function (obj) {
this[method](obj, args);
}.bind(this));

@@ -268,0 +283,0 @@ return this;

@@ -6,19 +6,144 @@ 'use strict';

function File(obj) {
/**
* Lazily required modules
*/
var lazy = require('lazy-cache')(require);
var parsePath = lazy('parse-filepath');
var startsWith = lazy('starts-with');
var endsWith = lazy('ends-with');
var isDotfile = lazy('is-dotfile');
var isDotdir = lazy('is-dotdir');
/**
* Create a new `File` from the given `object`.
*
* @param {Object} `object`
* @api public
*/
function File(file) {
this.cache = new Map();
this.history = [];
this.pattern = obj.pattern;
this.recurse = obj.recurse;
this.dirname = obj.dirname;
this.segment = obj.segment;
this.path = obj.path;
this.pattern = file.pattern;
this.recurse = file.recurse;
this.dirname = file.dirname;
this.segment = file.segment;
this.path = file.path;
this.orig = file.path;
}
File.prototype.parse = function(dir) {
dir = dir || process.cwd();
this.absolute = path.resolve(this.path);
this.relative = relative(dir, this.path);
/**
* Parse the `file.path` to add additional path properties
* to the `file` object. This is used in the iterators
* before the middleware handler is called.
*
* @param {String} `cwd`
*/
File.prototype.parse = function(cwd) {
cwd = cwd || process.cwd();
this.relative = relative(cwd, this.path);
var parsed = parsePath()(this.path);
for (var key in parsed) {
if (parsed.hasOwnProperty(key)) {
this[key] = parsed[key];
}
}
if (this.isDirectory()) {
if (this.pattern.endsWith('/') && !this.endsWith('/')) {
this.relative += '/';
}
}
};
/**
* Returns `true if the file give filepath or `file.path` looks like
* a dotfile.
*
* @param {String} `fp`
* @return {Boolean}
*/
File.prototype.isDotfile = function(fp) {
return isDotfile()(fp || this.path);
};
/**
* Returns `true if the file give filepath or `file.path` looks like
* a dot-directory.
*
* @param {String} `fp`
* @return {Boolean}
*/
File.prototype.isDotdir = function(fp) {
return isDotdir()(fp || this.path);
};
/**
* Return the absolute filepath based on the file's root path.
*
* @param {String} `fp`
* @return {String}
*/
File.prototype.toAbsolute = function(fp) {
if (typeof fp === 'undefined') {
fp = this.path;
}
if (this.startsWith('/', this.original)) {
return path.join(this.root, fp);
}
if (this.isAbsolute || fp === '') {
return fp;
}
return path.resolve(fp);
};
/**
* Return `true` if the given `file.path` ends with the specified
* `character`
*
* @param {String} `character`
* @param {String} `fp` If no filepath is passed, the cached `file.path` is used.
*/
File.prototype.endsWith = function(ch, fp) {
var key = 'endsWith:' + ch;
if (this.cache.has(key)) return this.cache.get(key);
if (typeof fp === 'undefined') {
fp = this.relative || this.path;
}
var res = endsWith()(fp, ch);
this.cache.set(key, res);
return res;
};
/**
* Return `true` if the given `filepath` starts with the specified
* `character`
*
* @param {String} `character`
* @param {String} `fp` If no filepath is passed, the cached `file.path` is used.
*/
File.prototype.startsWith = function(ch, fp) {
var key = 'startsWith:' + ch;
if (this.cache.has(key)) return this.cache.get(key);
if (typeof fp === 'undefined') {
fp = this.relative || this.path;
}
var res = startsWith()(fp, ch);
this.cache.set(key, res);
return res;
};
/**
* Expose `File`

@@ -25,0 +150,0 @@ */

@@ -10,2 +10,3 @@ 'use strict';

var promise = lazy('bluebird');
var filter = require('./filter');

@@ -18,7 +19,9 @@ module.exports = function (app) {

fs.exists(dir, function(exists) {
if (!exists) {
return cb(null, []);
}
return walk(dir, cb);
setImmediate(function () {
fs.exists(dir, function(exists) {
if (!exists) {
return cb(null, []);
}
return walk(dir, cb);
});
});

@@ -110,2 +113,3 @@

// console.log(file.path)
// emit included file

@@ -129,11 +133,13 @@ if (file.include === true) {

fs.exists(dir, function(exists) {
if (!exists) return;
setImmediate(function () {
fs.exists(dir, function(exists) {
if (!exists) return;
walk(dir, function (err) {
if (err) {
stream.emit('error', err);
return;
}
stream.end();
walk(dir, function (err) {
if (err) {
stream.emit('error', err);
return;
}
stream.end();
});
});

@@ -176,2 +182,3 @@ });

self.emit('include', file);
self.files.push(file.relative);
stream.write(file);

@@ -230,3 +237,3 @@ }

self.emit('include', file);
self.files.push(file.path);
self.files.push(file.relative);
}

@@ -233,0 +240,0 @@

'use strict';
// require('time-require')
var path = require('path');
var mm = require('micromatch');
var typeOf = require('kind-of');
var isGlob = require('is-glob');
var parent = require('glob-parent');
var utils = require('./utils');
var isWindows = require('is-windows');
/**
* Lazily required modules
*/
var lazy = require('lazy-cache')(require);
var startsWith = lazy('starts-with');
var endsWith = lazy('ends-with');
var parent = lazy('glob-parent');
var mm = lazy('micromatch');
/**
* Create an instance of `Pattern` with the given `options`.

@@ -18,2 +31,3 @@ *

function Pattern(glob, options, isNegated) {
utils.defineProp(this, 'cache', new Map());
this.negated = !!isNegated;

@@ -38,3 +52,14 @@ this.options = options || {};

this.isGlobstar = /(?:[*]{2}|\/\*\/\*\/)/.test(pattern);
// this.isGlobstar = pattern.indexOf('**') !== -1;
if (this.endsWith('/', pattern)) {
this.hasTrailingSlash = true;
pattern = pattern.substr(0, pattern.length - 1);
if (this.isGlobstar) {
pattern += '*/*';
}
}
if (!isGlob(pattern)) {

@@ -46,13 +71,11 @@ this.parent = '.';

} else {
this.isGlobstar = pattern.indexOf('**') !== -1;
if (pattern.charAt(0) === '!') {
if (this.startsWith('!', pattern)) {
pattern = pattern.slice(1);
this.negated = true;
}
this.parent = parent(pattern);
this.parent = parent()(pattern);
this.base = path.join(this.cwd, this.parent);
pattern = this.normalizePattern(pattern);
this.normalizePattern(pattern);
}
this.toRegex(pattern);
this.toRegex(this.glob);
return this;

@@ -70,2 +93,3 @@ };

var sep = this.parent;
if (sep === '.') sep = '';

@@ -75,6 +99,6 @@ sep = new RegExp('^' + sep);

pattern = pattern.replace(sep, '');
if (pattern.charAt(0) === '/') {
if (this.startsWith('/', pattern)) {
pattern = pattern.slice(1);
this.root = '/';
}
this.glob = pattern;

@@ -84,4 +108,45 @@ return pattern;

/**
* Return `true` if the given `pattern` ends with the given
* `character`
*
* @param {String} `character`
* @param {String} `pattern` If no `pattern` is passed, the cached value is used.
*/
Pattern.prototype.endsWith = function(ch, pattern) {
var key = 'endsWith:' + ch;
if (this.cache.has(key)) return this.cache.get(key);
if (typeof pattern === 'undefined') {
pattern = this.glob || this.original;
}
var res = endsWith()(pattern, ch);
this.cache.set(key, res);
return res;
};
/**
* Return `true` if the given `pattern` starts with the given
* `character`
*
* @param {String} `character`
* @param {String} `pattern` If no `pattern` is passed, the cached value is used.
*/
Pattern.prototype.startsWith = function(ch, pattern) {
var key = 'startsWith:' + ch;
if (this.cache.has(key)) return this.cache.get(key);
if (typeof pattern === 'undefined') {
pattern = this.glob || this.original;
}
var res = startsWith()(pattern, ch);
this.cache.set(key, res);
return res;
};
/**
* Return `true` if an actual parent was extracted from

@@ -103,3 +168,16 @@ * the glob pattern. e.g. not `.`

/**
* Resolve the root directory.
*
* @param {String} `fp`
* @return {String}
*/
Pattern.prototype.resolveRoot = function(dir) {
this.root = path.resolve(this.root || path.resolve((dir || this.cwd), '/'));
if (isWindows()) {
this.root = this.root.split('\\').join('/');
}
};
/**

@@ -113,12 +191,29 @@ * Convert `pattern` to regex.

Pattern.prototype.toRegex = function(pattern) {
if (typeOf(this.regex) === 'regexp') {
return this.regex;
}
if (!pattern && this.negated) {
this.re = new RegExp(this.parent);
this.regex = new RegExp(this.parent);
} else {
this.re = mm.makeRe(pattern);
if (this.hasTrailingSlash) {
pattern += '{,/}';
}
this.regex = mm().makeRe(pattern);
}
if (!this.re) {
this.re = new RegExp(this.original);
if (typeOf(this.regex) !== 'regexp') {
this.regex = new RegExp(this.original);
}
};
Pattern.prototype.test = function(fp) {
if (typeOf(this.regex) === 'regexp') {
return this.regex.test(fp);
}
this.toRegex(this.glob);
return this.regex.test(fp);
};
/**

@@ -125,0 +220,0 @@ * Expose `Pattern`

@@ -93,3 +93,5 @@ 'use strict';

this.setPattern(pattern, options);
return this.iteratorStream(this.pattern.base);
var res = this.iteratorStream(this.pattern.base);
this.emit('end', this.files);
return res;
},

@@ -100,5 +102,7 @@

this.setPattern(pattern, options);
return this.iteratorPromise(this.pattern.base);
var res = this.iteratorPromise(this.pattern.base);
this.emit('end', this.files);
return res;
}
});
};
'use strict';
var fs = require('fs');
/**

@@ -36,35 +34,16 @@ * Utils

/**
* File system utils.
* Add a non-enumerable property to `receiver`
*
* @param {Object} `obj`
* @param {String} `name`
* @param {Function} `val`
*/
utils.tryRead = function tryRead(fp) {
try {
return fs.readFileSync(fp, 'utf8');
} catch (err) {
return null;
}
utils.defineProp = function defineProp(receiver, key, value) {
return Object.defineProperty(receiver, key, {
configurable: true,
enumerable: false,
writable: true,
value: value
});
};
utils.tryReaddir = function tryReaddir(dir) {
try {
return fs.readdirSync(dir);
} catch(err) {}
return [];
};
utils.tryStat = function tryStat(fp) {
try {
return fs.statSync(fp);
} catch(err) {}
return null;
};
utils.reduce = function reduce(arr, cb, thisArg) {
var len = arr.length;
var res = [];
if (!len) return [];
for (var i = 0; i < len; i++) {
res = cb.call(thisArg, res, arr[i], i, arr);
}
return res || [];
};

@@ -7,2 +7,8 @@ 'use strict';

function testPattern(pattern) {
return function (fp) {
return pattern.test(fp);
}
}
module.exports = function (pattern, options) {

@@ -12,9 +18,11 @@ var opts = extend({}, options);

var isMatch = type === 'regexp'
? function (fp) {
return pattern.test(fp);
var isMatch = type !== 'regexp'
? mm.matcher(pattern, opts)
: testPattern(pattern);
return function exclude(file) {
if (file.pattern.hasTrailingSlash && file.isFile()) {
return file;
}
: mm.matcher(pattern, opts);
return function exclude(file) {
if (isMatch(file.path)) {

@@ -26,6 +34,11 @@ file.exclude = true;

if (file.pattern.hasParent()) {
if (isMatch(file.relative) || file.pattern.re.test(file.segment)) {
if (isMatch(file.relative)) {
file.exclude = true;
return file;
}
if (file.pattern.test(file.segment) || file.pattern.test(file.relative)) {
file.exclude = true;
return file;
}
}

@@ -32,0 +45,0 @@ return file;

'use strict';
var path = require('path');
var mm = require('micromatch');

@@ -7,2 +8,8 @@ var typeOf = require('kind-of');

function testPattern(pattern) {
return function (fp) {
return pattern.test(fp);
}
}
module.exports = function (pattern, options) {

@@ -12,9 +19,12 @@ var opts = extend({}, options);

var isMatch = type === 'regexp'
? function (fp) {
return pattern.test(fp);
var isMatch = type !== 'regexp'
? mm.matcher(pattern, opts)
: testPattern(pattern);
return function include(file) {
if (this.pattern.hasTrailingSlash && file.isFile()) {
return file;
}
: mm.matcher(pattern, opts);
return function include(file) {
if (isMatch(file.path)) {

@@ -25,7 +35,21 @@ file.include = true;

if (file.pattern.hasParent()) {
if (isMatch(file.relative) || file.pattern.re.test(file.segment)) {
if (this.pattern.hasParent()) {
if (isMatch(file.relative)) {
file.include = true;
return file;
}
var cwd = this.pattern.options.cwd || '.';
var re = this.pattern.regex;
if (re.test(path.join(cwd, file.relative))) {
file.include = true;
return file;
}
if (re.test(file.segment) || re.test(file.relative)) {
file.include = true;
return file;
}
}

@@ -32,0 +56,0 @@ return file;

{
"name": "glob-fs",
"description": "file globbing for node.js. speedy and powerful alternative to node-glob.",
"version": "0.1.5",
"version": "0.1.6",
"homepage": "https://github.com/jonschlinkert/glob-fs",

@@ -28,9 +28,14 @@ "author": "Jon Schlinkert (https://github.com/jonschlinkert)",

"component-emitter": "^1.2.0",
"ends-with": "^0.2.0",
"export-files": "^2.0.1",
"extend-shallow": "^2.0.0",
"glob-fs-dotfiles": "^0.1.5",
"glob-fs-gitignore": "^0.1.3",
"get-value": "^1.1.5",
"glob-fs-dotfiles": "^0.1.6",
"glob-fs-gitignore": "^0.1.5",
"glob-parent": "^1.2.0",
"graceful-fs": "^4.1.2",
"is-dotdir": "^0.1.0",
"is-dotfile": "^1.0.1",
"is-glob": "^2.0.0",
"is-windows": "^0.1.0",
"kind-of": "^2.0.0",

@@ -42,3 +47,6 @@ "lazy-cache": "^0.1.0",

"object.omit": "^1.1.0",
"parse-filepath": "^0.6.1",
"relative": "^3.0.1",
"set-value": "^0.2.0",
"starts-with": "^1.0.2",
"through2": "^2.0.0"

@@ -45,0 +53,0 @@ },

@@ -31,2 +31,3 @@ # glob-fs [![NPM version](https://badge.fury.io/js/glob-fs.svg)](http://badge.fury.io/js/glob-fs)

- [Middleware conventions](#middleware-conventions)
- [Advice for middleware authors](#advice-for-middleware-authors)
* [Globbing examples](#globbing-examples)

@@ -41,2 +42,3 @@ - [async](#async)

* [TODO](#todo)
* [Community middleware](#community-middleware)
* [Related projects](#related-projects)

@@ -64,4 +66,9 @@ * [Running tests](#running-tests)

All "read" methods take a glob pattern and an `options` object. Examples:
All "read" methods take a glob pattern and an `options` object.
* `pattern` **{String}**: Glob pattern to use for matching. (multiple pattern support is planned)
* `options` **{Object}**: Options for `glob-fs` or middleware.
**Examples:**
```js

@@ -91,3 +98,3 @@ // sync

### [.readdir](lib/readers.js#L27)
### [.readdir](lib/readers.js#L25)

@@ -112,3 +119,3 @@ Asynchronously glob files or directories that match the given `pattern`.

### [.readdirSync](lib/readers.js#L60)
### [.readdirSync](lib/readers.js#L59)

@@ -132,3 +139,3 @@ Synchronously glob files or directories that match the given `pattern`.

### [.readdirStream](lib/readers.js#L91)
### [.readdirStream](lib/readers.js#L90)

@@ -158,3 +165,3 @@ Stream files or directories that match the given glob `pattern`.

### [Glob](index.js#L35)
### [Glob](index.js#L42)

@@ -174,10 +181,10 @@ Optionally create an instance of `Glob` with the given `options`.

### [.exclude](index.js#L172)
### [.use](index.js#L178)
Thin wrapper around `.use()` for easily excluding files or directories that match the given `pattern`.
Add a middleware to be called in the order defined.
**Params**
* `pattern` **{String}**
* `options` **{Object}**
* `fn` **{Function}**
* `returns` **{Object}**: Returns the `Glob` instance, for chaining.

@@ -190,5 +197,4 @@ **Example**

var glob = require('glob-fs')({ foo: true })
.exclude(/\.foo$/)
.exclude('*.bar')
.exclude('*.baz');
.use(gitignore())
.use(dotfiles());

@@ -198,10 +204,10 @@ var files = glob.readdirSync('**');

### [.use](index.js#L211)
### [.exclude](index.js#L219)
Add a middleware to be called in the order defined.
Thin wrapper around `.use()` for easily excluding files or directories that match the given `pattern`.
**Params**
* `fn` **{Function}**
* `returns` **{Object}**: Returns the `Glob` instance, for chaining.
* `pattern` **{String}**
* `options` **{Object}**

@@ -213,7 +219,9 @@ **Example**

var dotfiles = require('glob-fs-dotfiles');
var glob = require('glob-fs')({ foo: true })
.use(gitignore())
.use(dotfiles());
var glob = require('glob-fs')()
.exclude(/\.foo$/)
.exclude('*.bar')
.exclude('*.baz');
var files = glob.readdirSync('*.js');
var files = glob.readdirSync('**');
//=> ['index.js', 'README.md', ...]
```

@@ -229,63 +237,93 @@

**What does "process" mean?**
Additionally, middleware can:
Typically, it means one of the following:
* be chained
* `include` or `exclude` a file based on some condition, like whether or not one of its properties matches a regex or glob pattern.
* determine whether or not to continue recursing in a specific directory
* modifying an existing property to the `file` object
* add a new property to the `file` object
1. matching a `file.path`, or
2. modifying a property on the `file` object, or
3. determining whether or not to continue recursing
### Middleware examples
**recursing**
**Ignoring files**
Here is how a middleware might determine whether or not to recurse based on a glob pattern:
In the following example, `notemp` is a complete and functional middleware for excluding any filepath that has the substring `temp`:
```js
var glob = require('glob-fs');
var glob = require('glob-fs')();
// this is already handled by glob-fs, but it
// makes a good example
function recurse() {
return function(file) {
// `file.pattern` is an object with a `glob` (string) property
file.recurse = file.pattern.glob.indexOf('**') !== -1;
return file;
function notemp(file) {
if (/temp/.test(file.path)) {
file.exclude = true;
}
return file;
}
// use the middleware
glob()
.use(recurse())
.readdir('**/*.js', function(err, files) {
console.log(files);
glob.use(notemp)
.readdirStream('**/*.js')
.on('data', function(file) {
console.log(file.relative);
});
```
**exclusion**
**Matching**
Middleware for excluding file paths:
Pattern matching is done by default in glob-fs, but you get disable the built-in matchers or get more specific by adding a middleware that uses [micromatch][] or [minimatch](https://github.com/isaacs/minimatch#readme) for matching files.
```js
// `notests` middleware to exclude any file in the `test` directory
function tests(options) {
return function(file) {
if (/^test\//.test(file.dirname)) {
file.exclude = true;
}
var glob = require('glob-fs')({ gitignore: true });
var mm = require('micromatch');
glob.use(function(file) {
if (mm.isMatch(file.relative, 'vendor/**')) file.exclude = true;
return file;
};
})
.readdirStream('**/*.js')
.on('data', function(file) {
console.log(file.relative);
});
```
**recursion**
Here is how a middleware might determine whether or not to recurse based on a certain pattern:
```js
var glob = require('glob-fs')();
// this specific check is already done by glob-fs, it's just used here as an example
function recurse(file) {
// `file.pattern` is an object with a `glob` (string) property
file.recurse = file.pattern.glob.indexOf('**') !== -1;
return file;
}
// usage
var glob = glob({ gitignore: true })
.use(tests())
// use the middleware
glob.use(recurse)
.readdir('**/*.js', function(err, files) {
console.log(files);
});
```
// get files
glob.readdirStream('**/*')
.on('data', function (file) {
console.log(file.path);
})
**Built-in middleware**
Currently glob-fs includes and runs the following middleware automatically:
<!-- list automatically generated from deps. see .verb.md -->
* [glob-fs-dotfiles](https://github.com/jonschlinkert/glob-fs-dotfiles): glob-fs middleware for automatically ignoring dotfiles.
* [glob-fs-gitignore](https://github.com/jonschlinkert/glob-fs-gitignore): glob-fs middleware for automatically ignoring files specified in `.gitignore`
**Disabling built-ins**
To disable built-in middleware and prevent them from running, pass `builtins: false` on the global options. This will disable **all built-in middleware**.
Example:
```js
var glob = require('glob-fs')({builtins: false});
```
To disable a specific middleware from running, you can usually pass the name of the middleware on the options, like `dotfiles: false`, but it's best to check the readme of that middleware for specifics.
### Middleware conventions

@@ -298,2 +336,12 @@

### Advice for middleware authors
* A middleware should only do one specific thing.
* Multiple middleware libs can be bundled together to create a single middleware.
* Pattern matching should be extremely specific. Don't force downstream middleware to reverse your mistakes.
* As mentioned in the [middleware conventions](#middleware-conventions) section, **always return the `file` object**.
* A single conditional should only set `file.exclude` to `true`, or `file.include` to `true`, never both.
* It's completely okay to check `this.options`
* Middleware modules should be fully documented.
## Globbing examples

@@ -486,4 +534,13 @@

* [ ] clean up `./lib`
* [ ](https://github.com/isaacs/node-glob/)[] comparison
* [ ] comparsion to [node-glob][]
## Community middleware
_(Add your project to the [.verb.md](./.verb.md) template do a PR!)_
<!-- remove these after we get some community middleware libs listed -->
* [glob-fs-dotfiles](https://github.com/jonschlinkert/glob-fs-dotfiles): glob-fs middleware for automatically ignoring dotfiles.
* [glob-fs-gitignore](https://github.com/jonschlinkert/glob-fs-gitignore): glob-fs middleware for automatically ignoring files specified in `.gitignore`
## Related projects

@@ -522,2 +579,2 @@

_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on July 09, 2015._
_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on July 11, 2015._