Skip to content

Commit

Permalink
Merge pull request jergason#28 from Ajedi32/custom_ignore_functions
Browse files Browse the repository at this point in the history
Allow using functions to ignore files
  • Loading branch information
jergason committed Oct 19, 2015
2 parents 123a183 + 833a8e5 commit 45abf8f
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 15 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,24 @@ recursive('some/path', ['foo.cs', '*.html'], function (err, files) {
});
```

You can also pass functions which are called to determine whether or not to
ignore a file:

```javascript
var recursive = require('recursive-readdir');

function ignoreFunc(file, stats) {
// `file` is the absolute path to the file, and `stats` is an `fs.Stats`
// object returned from `fs.lstat()`.
return stats.isDirectory() && path.basename(file) == "test";
}

// Ignore files named 'foo.cs' and descendants of directories named test
recursive('some/path', ['foo.cs', ignoreFunc], function (err, files) {
// Files is an array of filename
console.log(files);
});
```

The ignore strings support Glob syntax via
[minimatch](https://github.com/isaacs/minimatch).
38 changes: 26 additions & 12 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,27 @@ var fs = require('fs')
var p = require('path')
var minimatch = require('minimatch')

// how to know when you are done?
function patternMatcher(pattern) {
return function(path, stats) {
return stats.isFile() && minimatch(path, pattern, {matchBase: true})
}
}

function toMatcherFunction(ignoreEntry) {
if (typeof ignoreEntry == 'function') {
return ignoreEntry
} else {
return patternMatcher(ignoreEntry)
}
}

function readdir(path, ignores, callback) {
if (typeof ignores == 'function') {
callback = ignores
ignores = []
}
ignores = ignores.map(toMatcherFunction)

var list = []

fs.readdir(path, function(err, files) {
Expand All @@ -21,16 +36,23 @@ function readdir(path, ignores, callback) {
return callback(null, list)
}

var ignoreOpts = {matchBase: true}
files.forEach(function(file) {
fs.lstat(p.join(path, file), function(_err, stats) {
if (_err) {
return callback(_err)
}

file = p.join(path, file)
if (ignores.some(function(matcher) { return matcher(file, stats) })) {
pending -= 1
if (!pending) {
return callback(null, list)
}
return null
}

if (stats.isDirectory()) {
files = readdir(file, ignores, function(__err, res) {
readdir(file, ignores, function(__err, res) {
if (__err) {
return callback(__err)
}
Expand All @@ -42,21 +64,13 @@ function readdir(path, ignores, callback) {
}
})
} else {
for (var i = 0; i < ignores.length; i++) {
if (minimatch(file, ignores[i], ignoreOpts)) {
pending -= 1
if (pending <= 0) {
return callback(null, list)
}
return null
}
}
list.push(file)
pending -= 1
if (!pending) {
return callback(null, list)
}
}

})
})
})
Expand Down
148 changes: 145 additions & 3 deletions test/recursive-readdir-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ var assert = require('assert')
var p = require('path')
var readdir = require('../index')

function getAbsolutePath(file) {
return p.join(__dirname, file)
}

function getAbsolutePaths(files) {
return files.map(function(file) {
return p.join(__dirname, file)
})
return files.map(getAbsolutePath)
}

describe('readdir', function() {
Expand Down Expand Up @@ -71,6 +73,146 @@ describe('readdir', function() {
})
})

context('when there is a function in the ignores array', function() {
it('passes each file and directory path to the function', function(done) {
var expectedPaths = getAbsolutePaths([
'/testdir/a',
'/testdir/a/a',
'/testdir/a/beans',
'/testdir/b',
'/testdir/b/123',
'/testdir/b/b',
'/testdir/b/b/hurp-durp',
'/testdir/c.txt',
'/testdir/d.txt'
])
var paths = []
function ignoreFunction(path) {
paths.push(path)
return false
}
readdir(p.join(__dirname, 'testdir'), [ignoreFunction], function(err, list) {
assert.ifError(err)
assert.deepEqual(paths.sort(), expectedPaths.sort())
done()
})
})

it('passes the lstat object of each file to the function as its second argument', function(done) {
var paths = {}
function ignoreFunction(path, stats) {
paths[path] = stats
return false
}
readdir(p.join(__dirname, 'testdir'), [ignoreFunction], function(err, list) {
assert.ifError(err)
assert(paths[getAbsolutePath('/testdir/a')].isDirectory())
assert(paths[getAbsolutePath('/testdir/c.txt')].isFile())
done()
})
})

it('ignores files that the function returns true for', function(done) {
var ignoredFiles = getAbsolutePaths([
'/testdir/d.txt',
'/testdir/a/beans'
])
function ignoreFunction(path) {
return ignoredFiles.indexOf(path) != -1
}

readdir(p.join(__dirname, 'testdir'), [ignoreFunction], function(err, list) {
assert.ifError(err)
list.forEach(function(file) {
assert.equal(ignoredFiles.indexOf(file), -1,
'Failed to ignore file "' + file + '".')
})
done()
})
})

it('does not ignore files that the function returns false for', function(done) {
var notIgnoredFiles = getAbsolutePaths([
'/testdir/d.txt',
'/testdir/a/beans'
])
function ignoreFunction(path) {
return notIgnoredFiles.indexOf(path) == -1
}

readdir(p.join(__dirname, 'testdir'), [ignoreFunction], function(err, list) {
assert.ifError(err)
notIgnoredFiles.forEach(function(file) {
assert.notEqual(notIgnoredFiles.indexOf(file), -1,
'Incorrectly ignored file "' + file + '".')
})
done()
})
})

it('ignores directories that the function returns true for', function(done) {
var ignoredDirectory = getAbsolutePath('/testdir/a')
var ignoredFiles = getAbsolutePaths([
'/testdir/a/a',
'/testdir/a/beans'
])
function ignoreFunction(path) {
return ignoredDirectory == path
}

readdir(p.join(__dirname, 'testdir'), [ignoreFunction], function(err, list) {
assert.ifError(err)
list.forEach(function(file) {
assert.equal(ignoredFiles.indexOf(file), -1,
'Failed to ignore file "' + file + '".')
})
done()
})
})

it('does not ignore directories that the function returns false for', function(done) {
var ignoredDirectory = getAbsolutePath('/testdir/a')
var notIgnoredFiles = getAbsolutePaths([
'/testdir/b/123',
'/testdir/b/b/hurp-durp'
])
function ignoreFunction(path) {
return ignoredDirectory == path
}

readdir(p.join(__dirname, 'testdir'), [ignoreFunction], function(err, list) {
assert.ifError(err)
notIgnoredFiles.forEach(function(file) {
assert.notEqual(notIgnoredFiles.indexOf(file), -1,
'Incorrectly ignored file "' + file + '".')
})
done()
})
})

it('does not descend into directories that the function returns true for', function(done) {
var ignoredDirectory = getAbsolutePath('/testdir/a')
var ignoredFiles = getAbsolutePaths([
'/testdir/a/a',
'/testdir/a/beans'
])
var paths = []
function ignoreFunction(path) {
paths.push(path)
return ignoredDirectory == path
}

readdir(p.join(__dirname, 'testdir'), [ignoreFunction], function(err, list) {
assert.ifError(err)
paths.forEach(function(file) {
assert.equal(ignoredFiles.indexOf(file), -1,
'Transversed file in ignored directory "' + file + '".')
})
done()
})
})
})

it('works when there are no files to report except ignored files', function(done) {
readdir(p.join(__dirname, 'testdirBeta'), ['ignore.txt'], function(err, list) {
assert.ifError(err)
Expand Down

0 comments on commit 45abf8f

Please sign in to comment.