Comparing version
31
index.js
@@ -14,2 +14,3 @@ 'use strict'; | ||
var include = require('./middleware/include'); | ||
var symlinks = require('./lib/symlinks'); | ||
var iterators = require('./lib/iterators'); | ||
@@ -53,2 +54,3 @@ var Pattern = require('./lib/pattern'); | ||
init: function (options) { | ||
this.middleware = {}; | ||
this.includes = {}; | ||
@@ -58,5 +60,5 @@ this.excludes = {}; | ||
this.fns = []; | ||
this.defaults(options); | ||
middleware(this); | ||
iterators(this); | ||
symlinks(this); | ||
readers(this); | ||
@@ -69,3 +71,3 @@ }, | ||
defaults: function (opts) { | ||
defaults: function (glob, opts) { | ||
if (opts.ignore) { | ||
@@ -80,2 +82,3 @@ this.map('exclude', opts.ignore, opts); | ||
} | ||
middleware(this, glob, opts); | ||
}, | ||
@@ -91,4 +94,5 @@ | ||
setPattern: function (pattern, options) { | ||
options = options || {}; | ||
this.pattern = new Pattern(pattern, options); | ||
this.recurse = this.shouldRecurse(this.pattern.glob, options); | ||
this.recurse = this.shouldRecurse(this.pattern, options); | ||
@@ -100,3 +104,3 @@ // if middleware are registered, use the glob, otherwise regex | ||
this.include(glob, options); | ||
this.defaults(glob, options); | ||
return this; | ||
@@ -115,10 +119,10 @@ }, | ||
createFile: function (dir, segment, fp, stat) { | ||
// createFile: function (dir, segment, fp, stat) { | ||
createFile: function (file) { | ||
return new File({ | ||
pattern: this.pattern, | ||
recurse: this.recurse, | ||
dirname: dir, | ||
segment: segment, | ||
stat: stat, | ||
path: fp | ||
dirname: file.dirname, | ||
segment: file.segment, | ||
path: file.path | ||
}); | ||
@@ -229,2 +233,3 @@ }, | ||
handle: function(file) { | ||
this.fns = this.fns.filter(Boolean); | ||
var len = this.fns.length, i = -1; | ||
@@ -234,4 +239,8 @@ this.track(file); | ||
while (++i < len) { | ||
this.fns[i].call(this, file, this.options); | ||
this.fns[i].call(this, file); | ||
this.track(file); | ||
if (file.include === true || file.exclude === true) { | ||
break; | ||
} | ||
} | ||
@@ -238,0 +247,0 @@ }, |
'use strict'; | ||
var path = require('path'); | ||
var relative = require('relative'); | ||
function File(obj) { | ||
@@ -10,5 +13,11 @@ this.history = []; | ||
this.path = obj.path; | ||
this.stat = obj.stat; | ||
} | ||
File.prototype.parse = function(dir) { | ||
dir = dir || process.cwd(); | ||
this.absolute = path.resolve(this.path); | ||
this.relative = relative(dir, this.path); | ||
}; | ||
/** | ||
@@ -15,0 +24,0 @@ * Expose `File` |
@@ -5,4 +5,5 @@ 'use strict'; | ||
var path = require('path'); | ||
var async = require('async'); | ||
var lazy = require('lazy-cache')(require); | ||
var async = lazy('async'); | ||
var mixin = require('mixin-object'); | ||
var through = lazy('through2'); | ||
@@ -13,3 +14,2 @@ var promise = lazy('bluebird'); | ||
app.visit('mixin', { | ||
count: 0, | ||
@@ -30,35 +30,38 @@ iteratorAsync: function(dir, cb) { | ||
async().each(files, function(segment, next) { | ||
async.each(files, function(segment, next) { | ||
var fp = path.join(dir, segment); | ||
var file = self.createFile({ | ||
dirname: dir, | ||
segment: segment, | ||
path: fp | ||
}); | ||
fs.stat(fp, function(err, stat) { | ||
self.realpath(file, function(err, res) { | ||
if (err) return next(err); | ||
var isDir = stat.isDirectory(); | ||
var isSym = stat.isSymbolicLink(); | ||
var file = self.createFile(dir, segment, fp, stat); | ||
file.isSymlink = isSym; | ||
file.isDir = isDir; | ||
mixin(file, res); | ||
file.parse(self.pattern.cwd); | ||
var isDir = file.isDirectory(); | ||
// handle middleware | ||
self.emit('file', file); | ||
self.handle(file); | ||
if (isDir) { | ||
self.emit('dir', file); | ||
} | ||
// emit directory | ||
if (isDir) self.emit('dir', file); | ||
// emit excluded file | ||
if (file.exclude === true) { | ||
self.emit('exclude', file); | ||
self.excludes[file.path] = file; | ||
return next(); | ||
} | ||
// emit included file | ||
if (file.include === true) { | ||
self.count++; | ||
self.emit('include', file); | ||
self.includes[file.path] = file; | ||
self.files.push(fp); | ||
self.files.push(file.relative); | ||
} | ||
if (file.recurse !== false && isDir && !isSym) { | ||
if (file.recurse !== false && isDir) { | ||
return walk(fp, next); | ||
@@ -68,2 +71,3 @@ } | ||
}); | ||
}, cb); | ||
@@ -76,2 +80,3 @@ }); | ||
iteratorSync: function(dir) { | ||
var self = this; | ||
var files = fs.readdirSync(dir); | ||
@@ -83,29 +88,33 @@ var len = files.length, i = -1; | ||
var fp = path.join(dir, segment); | ||
var stat = fs.lstatSync(fp); | ||
var file = self.createFile({ | ||
dirname: dir, | ||
segment: segment, | ||
path: fp | ||
}); | ||
var isDir = stat.isDirectory(); | ||
var file = this.createFile(dir, segment, fp, stat); | ||
file.isDir = isDir; | ||
var res = self.realpathSync(file); | ||
mixin(file, res); | ||
file.parse(this.pattern.cwd); | ||
var isDir = file.isDirectory(); | ||
// handle middleware | ||
this.emit('file', file); | ||
this.handle(file); | ||
self.emit('file', file); | ||
self.handle(file); | ||
if (isDir) { | ||
this.emit('dir', file); | ||
// emit directory | ||
if (isDir) self.emit('dir', file); | ||
// emit excluded file | ||
if (file.exclude === true) { | ||
self.emit('exclude', file); | ||
continue; | ||
} | ||
// emit included file | ||
if (file.include === true) { | ||
this.count++; | ||
this.emit('include', file); | ||
this.includes[file.path] = file; | ||
this.files.push(fp); | ||
self.emit('include', file); | ||
self.files.push(file.relative); | ||
} | ||
if (file.exclude === true) { | ||
this.emit('exclude', file); | ||
this.excludes[file.path] = file; | ||
continue; | ||
} | ||
if (file.recurse !== false && isDir) { | ||
@@ -142,19 +151,22 @@ this.iteratorSync(fp); | ||
async().each(files, function(segment, next) { | ||
async.each(files, function(segment, next) { | ||
var fp = path.join(dir, segment); | ||
var file = self.createFile({ | ||
dirname: dir, | ||
segment: segment, | ||
path: fp | ||
}); | ||
fs.stat(fp, function(err, stat) { | ||
self.realpath(file, function(err, res) { | ||
if (err) return next(err); | ||
mixin(file, res); | ||
var isDir = stat.isDirectory(); | ||
var file = self.createFile(dir, segment, fp, stat); | ||
file.isDir = isDir; | ||
file.parse(self.pattern.cwd); | ||
var isDir = file.isDirectory(); | ||
// handle middleware | ||
self.emit('file', file); | ||
self.handle(file); | ||
if (isDir) { | ||
self.emit('dir', file); | ||
} | ||
if (isDir) self.emit('dir', file); | ||
if (file.exclude === true) { | ||
@@ -166,3 +178,2 @@ self.emit('exclude', file); | ||
if (file.include === true) { | ||
self.count++; | ||
self.emit('include', file); | ||
@@ -187,45 +198,50 @@ stream.write(file); | ||
var readdir = Promise.promisify(fs.readdir); | ||
var stats = Promise.promisify(fs.lstat); | ||
var realpath = Promise.promisify(this.realpath); | ||
var self = this; | ||
return readdir(dir).map(function (segment) { | ||
var fp = path.join(dir, segment); | ||
return readdir(dir) | ||
.map(function (segment) { | ||
var fp = path.join(dir, segment); | ||
var file = self.createFile({ | ||
dirname: dir, | ||
segment: segment, | ||
path: fp | ||
}); | ||
return stats(fp) | ||
.then(function (stat) { | ||
var isDir = stat.isDirectory(); | ||
var file = self.createFile(dir, segment, fp, stat); | ||
file.isDir = isDir; | ||
return realpath(file) | ||
.then(function (res) { | ||
mixin(file, res); | ||
// handle middleware | ||
self.emit('file', file); | ||
self.handle(file); | ||
file.parse(self.pattern.cwd); | ||
var isDir = file.isDirectory(); | ||
if (isDir) { | ||
self.emit('dir', file); | ||
} | ||
// handle middleware | ||
self.emit('file', file); | ||
self.handle(file); | ||
if (file.include === true) { | ||
self.count++; | ||
self.emit('include', file); | ||
self.includes[file.path] = file; | ||
self.files.push(fp); | ||
} | ||
// emit directory | ||
if (isDir) self.emit('dir', file); | ||
if (file.exclude === true) { | ||
self.emit('exclude', file); | ||
self.excludes[file.path] = file; | ||
return fp; | ||
} | ||
// emit excluded file | ||
if (file.exclude === true) { | ||
self.emit('exclude', file); | ||
return file.path; | ||
} | ||
if (file.recurse !== false && isDir) { | ||
return self.iteratorPromise(fp); | ||
} | ||
return fp; | ||
}); | ||
}) | ||
// emit included file | ||
if (file.include === true) { | ||
self.emit('include', file); | ||
self.files.push(file.path); | ||
} | ||
.reduce(function (acc, files) { | ||
return acc.concat(files); | ||
}, []); | ||
if (file.recurse !== false && isDir) { | ||
return self.iteratorPromise(fp); | ||
} | ||
return file.path; | ||
}); | ||
}) | ||
.reduce(function (acc, files) { | ||
return acc.concat(files); | ||
}, []); | ||
}, | ||
@@ -232,0 +248,0 @@ |
'use strict'; | ||
var gitignore = require('glob-fs-gitignore'); | ||
var dotfiles = require('glob-fs-dotfiles'); | ||
/** | ||
@@ -10,7 +7,19 @@ * Built-in middleware | ||
module.exports = function (app) { | ||
if (app.options.builtins !== false) { | ||
app.use(gitignore(app.options)); | ||
app.use(dotfiles(app.options)); | ||
module.exports = function (app, glob, options) { | ||
var opts = app.options || {}; | ||
if (opts.builtins !== false) { | ||
// turned `on` by default | ||
if (opts.dotfiles !== false) { | ||
app.use(require('glob-fs-dotfiles')(opts)); | ||
} | ||
// turned `off` by default | ||
if (opts.gitignore !== true) { | ||
app.use(require('glob-fs-gitignore')(opts)); | ||
} | ||
} | ||
app.include(glob, options); | ||
}; |
@@ -35,4 +35,5 @@ 'use strict'; | ||
pattern = pattern || '.'; | ||
var cwd = this.options.cwd || '.'; | ||
this.cwd = path.resolve(this.options.cwd || '.'); | ||
if (!isGlob(pattern)) { | ||
@@ -50,7 +51,7 @@ this.parent = '.'; | ||
this.parent = parent(pattern); | ||
this.base = path.join(cwd, this.parent); | ||
this.base = path.join(this.cwd, this.parent); | ||
pattern = this.normalizePattern(pattern); | ||
} | ||
this.toRegex(this.glob); | ||
this.toRegex(pattern); | ||
return this; | ||
@@ -69,4 +70,5 @@ }; | ||
if (sep === '.') sep = ''; | ||
sep = new RegExp('^' + sep); | ||
pattern = pattern.split(sep).filter(Boolean).join(''); | ||
pattern = pattern.replace(sep, ''); | ||
if (pattern.charAt(0) === '/') { | ||
@@ -80,3 +82,22 @@ pattern = pattern.slice(1); | ||
/** | ||
* Return `true` if an actual parent was extracted from | ||
* the glob pattern. e.g. not `.` | ||
* | ||
* @param {String} `parent` | ||
*/ | ||
Pattern.prototype.hasParent = function() { | ||
if (this.parent !== '.' && this.parent.length > 0) { | ||
return true; | ||
} | ||
if (this.cwd !== '.' && this.cwd.length > 0) { | ||
return true; | ||
} | ||
return false; | ||
}; | ||
/** | ||
* Convert `pattern` to regex. | ||
@@ -83,0 +104,0 @@ * |
'use strict'; | ||
var utils = require('./utils'); | ||
module.exports = function (app) { | ||
@@ -32,2 +30,3 @@ app.visit('mixin', { | ||
this.emit('read'); | ||
this.setPattern(pattern, options); | ||
@@ -37,2 +36,3 @@ this.iteratorAsync(this.pattern.base, function (err) { | ||
this.emit('end', this.files); | ||
cb.call(this, null, this.files); | ||
@@ -62,5 +62,6 @@ }.bind(this)); | ||
readdirSync: function(pattern, options) { | ||
this.emit('read'); | ||
this.setPattern(pattern, options); | ||
this.iteratorSync(this.pattern.base); | ||
this.emit('end'); | ||
this.emit('end', this.files); | ||
return this.files; | ||
@@ -93,2 +94,3 @@ }, | ||
readdirStream: function(pattern, options) { | ||
this.emit('read'); | ||
this.setPattern(pattern, options); | ||
@@ -99,2 +101,3 @@ return this.iteratorStream(this.pattern.base); | ||
readdirPromise: function(pattern, options) { | ||
this.emit('read'); | ||
this.setPattern(pattern, options); | ||
@@ -101,0 +104,0 @@ return this.iteratorPromise(this.pattern.base); |
@@ -5,3 +5,2 @@ 'use strict'; | ||
var fs = require('graceful-fs'); | ||
var through = require('through2'); | ||
@@ -21,43 +20,66 @@ /** | ||
stream: function() { | ||
return through.obj(realPath); | ||
}, | ||
}); | ||
}; | ||
realpath: function realpath(file, cb) { | ||
var self = this; | ||
/** | ||
* Stream | ||
*/ | ||
fs.lstat(file.path, function (err, stats) { | ||
if (err) return cb(err); | ||
file.stat = stats; | ||
decorate(file); | ||
function realpath(file, enc, cb) { | ||
var stream = this; | ||
if (!file.isSymlink()) { | ||
return cb(null, file); | ||
} | ||
fs.lstat(file.path, function (err, stat) { | ||
if (err) { | ||
stream.emit('error', err); | ||
process.nextTick(function () { | ||
cb(); | ||
fs.realpath(file.path, function (err, fp) { | ||
if (err) return cb(err); | ||
file.base = path.dirname(fp); | ||
file.path = fp; | ||
// recurse to get real file stat | ||
self.realpath(file, cb); | ||
}); | ||
}); | ||
return; | ||
} | ||
}, | ||
file.stat = stat; | ||
if (!stat.isSymbolicLink()) { | ||
return cb(null, file); | ||
} | ||
realpathSync: function realpathSync(file) { | ||
var self = this; | ||
try { | ||
var stats = fs.lstatSync(file.path); | ||
file.stat = stats; | ||
decorate(file); | ||
fs.realpath(file.path, function (err, fp) { | ||
if (err) { | ||
stream.emit('error', err); | ||
process.nextTick(function () { | ||
cb(); | ||
}); | ||
return; | ||
if (!file.isSymlink()) { | ||
return file; | ||
} | ||
} catch(err) { | ||
throw new Error('fs.lstatSync error: ', err); | ||
} | ||
file.base = path.dirname(fp); | ||
file.path = fp; | ||
realPath(file, enc, cb); | ||
}); | ||
try { | ||
var fp = fs.realpathSync(file.path); | ||
file.base = path.dirname(fp); | ||
file.path = fp; | ||
// recurse to get real file stat | ||
return self.realpathSync(file); | ||
} catch (err) { | ||
throw new Error('fs.realpathSync Error: ', err); | ||
} | ||
} | ||
}); | ||
} | ||
}; | ||
function decorate(file) { | ||
file.isDirectory = function () { | ||
return file.stat.isDirectory(); | ||
}; | ||
file.isFile = function () { | ||
return file.stat.isFile(); | ||
}; | ||
file.isSymlink = function () { | ||
return file.stat.isSymbolicLink(); | ||
}; | ||
} |
@@ -6,10 +6,10 @@ 'use strict'; | ||
var extend = require('extend-shallow'); | ||
var isnt = require('./isnt'); | ||
module.exports = function (pattern, options) { | ||
var opts = extend({ matchBase: true }, options); | ||
var opts = extend({}, options); | ||
var type = typeOf(pattern); | ||
var isMatch = typeOf(pattern) === 'regexp' | ||
var isMatch = type === 'regexp' | ||
? function (fp) { | ||
return !pattern.test(fp); | ||
return pattern.test(fp); | ||
} | ||
@@ -21,5 +21,13 @@ : mm.matcher(pattern, opts); | ||
file.exclude = true; | ||
return file; | ||
} | ||
if (file.pattern.hasParent()) { | ||
if (isMatch(file.relative) || file.pattern.re.test(file.segment)) { | ||
file.exclude = true; | ||
return file; | ||
} | ||
} | ||
return file; | ||
}; | ||
}; |
@@ -6,8 +6,8 @@ 'use strict'; | ||
var extend = require('extend-shallow'); | ||
var is = require('./is'); | ||
module.exports = function (pattern, options) { | ||
var opts = extend({ matchBase: true }, options); | ||
var opts = extend({}, options); | ||
var type = typeOf(pattern); | ||
var isMatch = typeOf(pattern) === 'regexp' | ||
var isMatch = type === 'regexp' | ||
? function (fp) { | ||
@@ -21,5 +21,13 @@ return pattern.test(fp); | ||
file.include = true; | ||
return file; | ||
} | ||
if (file.pattern.hasParent()) { | ||
if (isMatch(file.relative) || file.pattern.re.test(file.segment)) { | ||
file.include = true; | ||
return file; | ||
} | ||
} | ||
return file; | ||
}; | ||
}; |
{ | ||
"name": "glob-fs", | ||
"description": "file globbing for node.js. speedy and powerful alternative to node-glob.", | ||
"version": "0.1.3", | ||
"version": "0.1.5", | ||
"homepage": "https://github.com/jonschlinkert/glob-fs", | ||
@@ -26,8 +26,8 @@ "author": "Jon Schlinkert (https://github.com/jonschlinkert)", | ||
"async": "^1.3.0", | ||
"bluebird": "^2.9.32", | ||
"bluebird": "^2.9.33", | ||
"component-emitter": "^1.2.0", | ||
"export-files": "^2.0.1", | ||
"extend-shallow": "^2.0.0", | ||
"glob-fs-dotfiles": "^0.1.1", | ||
"glob-fs-gitignore": "^0.1.0", | ||
"glob-fs-dotfiles": "^0.1.5", | ||
"glob-fs-gitignore": "^0.1.3", | ||
"glob-parent": "^1.2.0", | ||
@@ -38,5 +38,7 @@ "graceful-fs": "^4.1.2", | ||
"lazy-cache": "^0.1.0", | ||
"micromatch": "^2.1.6", | ||
"micromatch": "jonschlinkert/micromatch#2.2.0", | ||
"mixin-object": "^2.0.0", | ||
"object-visit": "^0.1.0", | ||
"object.omit": "^1.1.0", | ||
"relative": "^3.0.1", | ||
"through2": "^2.0.0" | ||
@@ -43,0 +45,0 @@ }, |
@@ -38,2 +38,3 @@ # glob-fs [](http://badge.fury.io/js/glob-fs) | ||
- [Event examples](#event-examples) | ||
* [FAQ](#faq) | ||
* [TODO](#todo) | ||
@@ -108,3 +109,3 @@ * [Related projects](#related-projects) | ||
### [.readdirSync](lib/readers.js#L59) | ||
### [.readdirSync](lib/readers.js#L60) | ||
@@ -128,3 +129,3 @@ Synchronously glob files or directories that match the given `pattern`. | ||
### [.readdirStream](lib/readers.js#L89) | ||
### [.readdirStream](lib/readers.js#L91) | ||
@@ -154,3 +155,3 @@ Stream files or directories that match the given glob `pattern`. | ||
### [Glob](index.js#L32) | ||
### [Glob](index.js#L35) | ||
@@ -170,3 +171,3 @@ Optionally create an instance of `Glob` with the given `options`. | ||
### [.exclude](index.js#L156) | ||
### [.exclude](index.js#L172) | ||
@@ -193,3 +194,3 @@ Thin wrapper around `.use()` for easily excluding files or directories that match the given `pattern`. | ||
### [.use](index.js#L195) | ||
### [.use](index.js#L211) | ||
@@ -342,2 +343,3 @@ Add a middleware to be called in the order defined. | ||
* `read`: emitted immediately before an iterator calls the first middleware. | ||
* `include`: emits a `file` object when it's matched | ||
@@ -431,2 +433,10 @@ * `exclude`: emits a `file` object when it's ignored/excluded | ||
## FAQ | ||
* when files are read from the file system, an object is created to keep a record of the file's `path`, `dirname`, and fs `stat` object and other pertinent information that makes it easier to make decisions about inclusion and exclusion later on. | ||
* `file` objects are decorated with a `parse` method that is used to calculate the `file.relative` and `file.absolute` properties. | ||
* the `file.parse()` method is called in the iterator, right after the call to ` fs.stats` and just before the call to the middleware handler (`.handle()`). This ensures that all middleware have access to necessary path information. | ||
* `file.relative` is the file path that's actually pushed into the `files` array that is ultimately returned. | ||
* `file.relative` is calculated using `path.relative(file.path, cwd)`, where `cwd` is passed on the options (globally, or on a middleware), and `file.path` is typically the absolute, actual file path to the file being globbed. | ||
## TODO | ||
@@ -433,0 +443,0 @@ |
GitHub dependency
Supply chain riskContains a dependency which resolves to a GitHub URL. Dependencies fetched from GitHub specifiers are not immutable can be used to inject untrusted code or reduce the likelihood of a reproducible install.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
38187
0.03%508
2.01%3
-25%18
12.5%18
-18.18%910
-5.21%1
Infinity%1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
Updated
Updated
Updated