Skip to content

Commit 45abf8f

Browse files
committed
Merge pull request #28 from Ajedi32/custom_ignore_functions
Allow using functions to ignore files
2 parents 123a183 + 833a8e5 commit 45abf8f

File tree

3 files changed

+190
-15
lines changed

3 files changed

+190
-15
lines changed

README.md

+19
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,24 @@ recursive('some/path', ['foo.cs', '*.html'], function (err, files) {
3838
});
3939
```
4040

41+
You can also pass functions which are called to determine whether or not to
42+
ignore a file:
43+
44+
```javascript
45+
var recursive = require('recursive-readdir');
46+
47+
function ignoreFunc(file, stats) {
48+
// `file` is the absolute path to the file, and `stats` is an `fs.Stats`
49+
// object returned from `fs.lstat()`.
50+
return stats.isDirectory() && path.basename(file) == "test";
51+
}
52+
53+
// Ignore files named 'foo.cs' and descendants of directories named test
54+
recursive('some/path', ['foo.cs', ignoreFunc], function (err, files) {
55+
// Files is an array of filename
56+
console.log(files);
57+
});
58+
```
59+
4160
The ignore strings support Glob syntax via
4261
[minimatch](https://github.com/isaacs/minimatch).

index.js

+26-12
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,27 @@ var fs = require('fs')
22
var p = require('path')
33
var minimatch = require('minimatch')
44

5-
// how to know when you are done?
5+
function patternMatcher(pattern) {
6+
return function(path, stats) {
7+
return stats.isFile() && minimatch(path, pattern, {matchBase: true})
8+
}
9+
}
10+
11+
function toMatcherFunction(ignoreEntry) {
12+
if (typeof ignoreEntry == 'function') {
13+
return ignoreEntry
14+
} else {
15+
return patternMatcher(ignoreEntry)
16+
}
17+
}
18+
619
function readdir(path, ignores, callback) {
720
if (typeof ignores == 'function') {
821
callback = ignores
922
ignores = []
1023
}
24+
ignores = ignores.map(toMatcherFunction)
25+
1126
var list = []
1227

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

24-
var ignoreOpts = {matchBase: true}
2539
files.forEach(function(file) {
2640
fs.lstat(p.join(path, file), function(_err, stats) {
2741
if (_err) {
2842
return callback(_err)
2943
}
3044

3145
file = p.join(path, file)
46+
if (ignores.some(function(matcher) { return matcher(file, stats) })) {
47+
pending -= 1
48+
if (!pending) {
49+
return callback(null, list)
50+
}
51+
return null
52+
}
53+
3254
if (stats.isDirectory()) {
33-
files = readdir(file, ignores, function(__err, res) {
55+
readdir(file, ignores, function(__err, res) {
3456
if (__err) {
3557
return callback(__err)
3658
}
@@ -42,21 +64,13 @@ function readdir(path, ignores, callback) {
4264
}
4365
})
4466
} else {
45-
for (var i = 0; i < ignores.length; i++) {
46-
if (minimatch(file, ignores[i], ignoreOpts)) {
47-
pending -= 1
48-
if (pending <= 0) {
49-
return callback(null, list)
50-
}
51-
return null
52-
}
53-
}
5467
list.push(file)
5568
pending -= 1
5669
if (!pending) {
5770
return callback(null, list)
5871
}
5972
}
73+
6074
})
6175
})
6276
})

test/recursive-readdir-test.js

+145-3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ var assert = require('assert')
33
var p = require('path')
44
var readdir = require('../index')
55

6+
function getAbsolutePath(file) {
7+
return p.join(__dirname, file)
8+
}
9+
610
function getAbsolutePaths(files) {
7-
return files.map(function(file) {
8-
return p.join(__dirname, file)
9-
})
11+
return files.map(getAbsolutePath)
1012
}
1113

1214
describe('readdir', function() {
@@ -71,6 +73,146 @@ describe('readdir', function() {
7173
})
7274
})
7375

76+
context('when there is a function in the ignores array', function() {
77+
it('passes each file and directory path to the function', function(done) {
78+
var expectedPaths = getAbsolutePaths([
79+
'/testdir/a',
80+
'/testdir/a/a',
81+
'/testdir/a/beans',
82+
'/testdir/b',
83+
'/testdir/b/123',
84+
'/testdir/b/b',
85+
'/testdir/b/b/hurp-durp',
86+
'/testdir/c.txt',
87+
'/testdir/d.txt'
88+
])
89+
var paths = []
90+
function ignoreFunction(path) {
91+
paths.push(path)
92+
return false
93+
}
94+
readdir(p.join(__dirname, 'testdir'), [ignoreFunction], function(err, list) {
95+
assert.ifError(err)
96+
assert.deepEqual(paths.sort(), expectedPaths.sort())
97+
done()
98+
})
99+
})
100+
101+
it('passes the lstat object of each file to the function as its second argument', function(done) {
102+
var paths = {}
103+
function ignoreFunction(path, stats) {
104+
paths[path] = stats
105+
return false
106+
}
107+
readdir(p.join(__dirname, 'testdir'), [ignoreFunction], function(err, list) {
108+
assert.ifError(err)
109+
assert(paths[getAbsolutePath('/testdir/a')].isDirectory())
110+
assert(paths[getAbsolutePath('/testdir/c.txt')].isFile())
111+
done()
112+
})
113+
})
114+
115+
it('ignores files that the function returns true for', function(done) {
116+
var ignoredFiles = getAbsolutePaths([
117+
'/testdir/d.txt',
118+
'/testdir/a/beans'
119+
])
120+
function ignoreFunction(path) {
121+
return ignoredFiles.indexOf(path) != -1
122+
}
123+
124+
readdir(p.join(__dirname, 'testdir'), [ignoreFunction], function(err, list) {
125+
assert.ifError(err)
126+
list.forEach(function(file) {
127+
assert.equal(ignoredFiles.indexOf(file), -1,
128+
'Failed to ignore file "' + file + '".')
129+
})
130+
done()
131+
})
132+
})
133+
134+
it('does not ignore files that the function returns false for', function(done) {
135+
var notIgnoredFiles = getAbsolutePaths([
136+
'/testdir/d.txt',
137+
'/testdir/a/beans'
138+
])
139+
function ignoreFunction(path) {
140+
return notIgnoredFiles.indexOf(path) == -1
141+
}
142+
143+
readdir(p.join(__dirname, 'testdir'), [ignoreFunction], function(err, list) {
144+
assert.ifError(err)
145+
notIgnoredFiles.forEach(function(file) {
146+
assert.notEqual(notIgnoredFiles.indexOf(file), -1,
147+
'Incorrectly ignored file "' + file + '".')
148+
})
149+
done()
150+
})
151+
})
152+
153+
it('ignores directories that the function returns true for', function(done) {
154+
var ignoredDirectory = getAbsolutePath('/testdir/a')
155+
var ignoredFiles = getAbsolutePaths([
156+
'/testdir/a/a',
157+
'/testdir/a/beans'
158+
])
159+
function ignoreFunction(path) {
160+
return ignoredDirectory == path
161+
}
162+
163+
readdir(p.join(__dirname, 'testdir'), [ignoreFunction], function(err, list) {
164+
assert.ifError(err)
165+
list.forEach(function(file) {
166+
assert.equal(ignoredFiles.indexOf(file), -1,
167+
'Failed to ignore file "' + file + '".')
168+
})
169+
done()
170+
})
171+
})
172+
173+
it('does not ignore directories that the function returns false for', function(done) {
174+
var ignoredDirectory = getAbsolutePath('/testdir/a')
175+
var notIgnoredFiles = getAbsolutePaths([
176+
'/testdir/b/123',
177+
'/testdir/b/b/hurp-durp'
178+
])
179+
function ignoreFunction(path) {
180+
return ignoredDirectory == path
181+
}
182+
183+
readdir(p.join(__dirname, 'testdir'), [ignoreFunction], function(err, list) {
184+
assert.ifError(err)
185+
notIgnoredFiles.forEach(function(file) {
186+
assert.notEqual(notIgnoredFiles.indexOf(file), -1,
187+
'Incorrectly ignored file "' + file + '".')
188+
})
189+
done()
190+
})
191+
})
192+
193+
it('does not descend into directories that the function returns true for', function(done) {
194+
var ignoredDirectory = getAbsolutePath('/testdir/a')
195+
var ignoredFiles = getAbsolutePaths([
196+
'/testdir/a/a',
197+
'/testdir/a/beans'
198+
])
199+
var paths = []
200+
function ignoreFunction(path) {
201+
paths.push(path)
202+
return ignoredDirectory == path
203+
}
204+
205+
readdir(p.join(__dirname, 'testdir'), [ignoreFunction], function(err, list) {
206+
assert.ifError(err)
207+
paths.forEach(function(file) {
208+
assert.equal(ignoredFiles.indexOf(file), -1,
209+
'Transversed file in ignored directory "' + file + '".')
210+
})
211+
done()
212+
})
213+
})
214+
})
215+
74216
it('works when there are no files to report except ignored files', function(done) {
75217
readdir(p.join(__dirname, 'testdirBeta'), ['ignore.txt'], function(err, list) {
76218
assert.ifError(err)

0 commit comments

Comments
 (0)