Skip to content

Commit cba03d9

Browse files
authored
Merge pull request fshost#40 from AckerApple/master
added options, promise method, ability to run sync mode, and much more
2 parents 03510a2 + ecdfc03 commit cba03d9

File tree

5 files changed

+246
-72
lines changed

5 files changed

+246
-72
lines changed

README.md

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,29 @@
33
# node-dir
44
A lightweight Node.js module with methods for some common directory and file operations, including asynchronous, non-blocking methods for recursively getting an array of files, subdirectories, or both, and methods for recursively, sequentially reading and processing the contents of files in a directory and its subdirectories, with several options available for added flexibility if needed.
55

6+
### Table of Contents
7+
8+
- [installation](#installation)
9+
- [usage](#usage)
10+
- [methods](#methods)
11+
- [readFiles( dir, options, fileCallback, finishedCallback)](#readfiles-dir-options-filecallback-finishedcallback)
12+
- [readFilesStream( dir, options, streamCallback, finishedCallback)](#readfilesstream-dir-options-streamcallback-finishedcallback)
13+
- [readFilesStream examples](#readfilesstream-examples)
14+
- [files( dir, callback )](#files-dir-callback)
15+
- [files( dir, {sync:true} )](#files-dir-synctrue)
16+
- [promiseFiles( dir, callback )](#promisefiles-dir-callback)
17+
- [subdirs( dir, callback )](#subdirs-dir-callback)
18+
- [paths(dir, [combine], callback )](#pathsdir-combine-callback)
19+
- [API Docs](#api-docs)
20+
- [files(dir, type, callback, options)](#filesdir-type-callback-options)
21+
- [License](#license)
22+
623
#### installation
724

825
npm install node-dir
926

27+
### usage
28+
1029
#### methods
1130
For the sake of brevity, assume that the following line of code precedes all of the examples.
1231

@@ -32,7 +51,7 @@ Valid options are:
3251

3352
A reverse sort can also be achieved by setting the sort option to 'reverse', 'desc', or 'descending' string value.
3453

35-
examples
54+
#### readFilesStream examples
3655

3756
```javascript
3857
// display contents of files in this script's directory
@@ -111,6 +130,25 @@ dir.files(__dirname, function(err, files) {
111130
console.log(files);
112131
});
113132
```
133+
134+
#### files( dir, {sync:true} )
135+
Synchronously iterate the files of a directory and its subdirectories and pass an array of file paths to a callback.
136+
137+
```javascript
138+
var files = dir.files(__dirname, {sync:true});
139+
console.log(files);
140+
```
141+
142+
#### promiseFiles( dir, callback )
143+
Asynchronously iterate the files of a directory and its subdirectories and pass an array of file paths to a callback.
144+
145+
```javascript
146+
dir.promiseFiles(__dirname)
147+
.then((files)=>{
148+
console.log(files);
149+
})
150+
.catch(e=>console.error(e))
151+
```
114152

115153
Note that for the files and subdirs the object returned is an array, and thus all of the standard array methods are available for use in your callback for operations like filters or sorting. Some quick examples:
116154

@@ -167,6 +205,21 @@ dir.paths(__dirname, true, function(err, paths) {
167205
});
168206
```
169207

208+
## API Docs
209+
210+
### files(dir, type, callback, options)
211+
212+
- **dir** - directory path to read
213+
- **type**='file'
214+
- 'file' returns only file listings
215+
- 'dir' returns only directory listings
216+
- 'all' returns {dirs:[], files:[]}
217+
- 'combine' returns []
218+
- **callback** -
219+
- **options**
220+
- **sync**=false - results are returned inline and no callbacks are used
221+
- **shortName**=false - instead of fullpath file names, just get the names
222+
- **recursive**=true - traverse through all children of given path
170223

171224
## License
172225
MIT licensed (See LICENSE.txt)

index.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
var dirpaths = require('./lib/paths');
22

3-
exports.files = dirpaths.files;
4-
exports.paths = dirpaths.paths;
5-
exports.subdirs = dirpaths.subdirs;
3+
Object.assign(exports, dirpaths)
64
exports.readFiles = require('./lib/readfiles');
75
exports.readFilesStream = require('./lib/readfilesstream');

lib/paths.js

Lines changed: 159 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
var fs = require('fs'),
22
path = require('path');
33

4+
exports.promiseFiles = function promiseFiles(dir, type, options){
5+
type = type || 'file'
6+
7+
var processor = function(res,rej){
8+
var cb = function(err,data){
9+
if(err)return rej(err)
10+
res(data)
11+
}
12+
exports.files(dir,type,cb,options)
13+
}
14+
return new Promise(processor)
15+
}
16+
417
/**
518
* find all files or subdirs (recursive) and pass to callback fn
619
*
@@ -13,75 +26,139 @@
1326
* console.log('files:', files);
1427
* });
1528
*/
16-
exports.files = function files(dir, type, callback, /* used internally */ ignoreType) {
17-
18-
var pending,
19-
results = {
20-
files: [],
21-
dirs: []
22-
};
23-
var done = function() {
24-
if (ignoreType || type === 'all') {
25-
callback(null, results);
26-
} else {
27-
callback(null, results[type + 's']);
29+
exports.files = function files(dir, type, callback, options) {
30+
var ofType = typeof type
31+
if(ofType == 'object'){
32+
options = options || type
33+
type = 'file'
34+
callback = function(){}
35+
}else if (ofType !== 'string') {
36+
//ignoreType = callback;
37+
callback = type;
38+
type = 'file';
39+
}
40+
41+
options = options || {}
42+
43+
var pending,
44+
results = {
45+
files: [],
46+
dirs: []
47+
};
48+
49+
var done = function() {
50+
if(type==='combine'){
51+
results = results.files.concat(results.dirs)
52+
} else if (!type || options.ignoreType || ['all','combine'].indexOf(type)>=0) {
53+
results = results
54+
} else {
55+
results = results[type + 's']
56+
}
57+
58+
if(options.sync)return;
59+
60+
61+
callback(null, results);
62+
};
63+
64+
var getStatHandler = function(statPath, name, lstatCalled) {
65+
return function(err, stat) {
66+
if (err) {
67+
if (!lstatCalled) {
68+
return fs.lstat(statPath, getStatHandler(statPath, name, true));
69+
}
70+
return callback(err);
71+
}
72+
73+
var pushVal = options.shortName ? name : statPath
74+
75+
if (stat && stat.isDirectory() && stat.mode !== 17115) {
76+
if (type !== 'file') {
77+
results.dirs.push(pushVal);
2878
}
29-
};
30-
31-
var getStatHandler = function(statPath, lstatCalled) {
32-
return function(err, stat) {
33-
if (err) {
34-
if (!lstatCalled) {
35-
return fs.lstat(statPath, getStatHandler(statPath, true));
36-
}
37-
return callback(err);
79+
80+
if (options.recursive==null || options.recursive) {
81+
var subloop = function(err, res) {
82+
if (err){
83+
return callback(err)
3884
}
39-
if (stat && stat.isDirectory() && stat.mode !== 17115) {
40-
if (type !== 'file') {
41-
results.dirs.push(statPath);
42-
}
43-
files(statPath, type, function(err, res) {
44-
if (err) return callback(err);
45-
if (type === 'all') {
46-
results.files = results.files.concat(res.files);
47-
results.dirs = results.dirs.concat(res.dirs);
48-
} else if (type === 'file') {
49-
results.files = results.files.concat(res.files);
50-
} else {
51-
results.dirs = results.dirs.concat(res.dirs);
52-
}
53-
if (!--pending) done();
54-
}, true);
85+
86+
if(type === 'combine'){
87+
results.files = results.files.concat(res);
88+
}else if (type === 'all') {
89+
results.files = results.files.concat(res.files);
90+
results.dirs = results.dirs.concat(res.dirs);
91+
} else if (type === 'file') {
92+
results.files = results.files.concat(res.files);
5593
} else {
56-
if (type !== 'dir') {
57-
results.files.push(statPath);
58-
}
59-
// should be the last statement in statHandler
60-
if (!--pending) done();
94+
results.dirs = results.dirs.concat(res.dirs);
95+
}
96+
97+
if (!--pending){
98+
done();
6199
}
62-
};
63-
};
100+
}
101+
102+
var newOptions = Object.assign({}, options)
103+
newOptions.ignoreType = true
104+
var moreResults = files(statPath, type, subloop, newOptions);
105+
106+
if(options.sync){
107+
subloop(null, moreResults)
108+
}
109+
}else if (!--pending){
110+
done()
111+
}
112+
} else {
113+
if (type !== 'dir') {
114+
results.files.push(pushVal);
115+
}
116+
// should be the last statement in statHandler
117+
if (!--pending){
118+
done()
119+
}
120+
}
121+
}
122+
}
123+
124+
const onDirRead = function(err, list) {
125+
if (err) return callback(err);
126+
127+
pending = list.length;
128+
if (!pending) return done();
129+
130+
for (var file, i = 0, l = list.length; i < l; i++) {
131+
file = path.join(dir, list[i]);
64132

65-
if (typeof type !== 'string') {
66-
ignoreType = callback;
67-
callback = type;
68-
type = 'file';
133+
if(options.sync){
134+
var res = fs.statSync(file);
135+
getStatHandler(file,list[i])(null, res)
136+
}else{
137+
fs.stat(file, getStatHandler(file,list[i]));
138+
}
69139
}
70140

71-
fs.stat(dir, function(err, stat) {
72-
if (err) return callback(err);
73-
if(stat && stat.mode === 17115) return done();
74-
75-
fs.readdir(dir, function(err, list) {
76-
if (err) return callback(err);
77-
pending = list.length;
78-
if (!pending) return done();
79-
for (var file, i = 0, l = list.length; i < l; i++) {
80-
file = path.join(dir, list[i]);
81-
fs.stat(file, getStatHandler(file));
82-
}
83-
});
84-
});
141+
return results
142+
}
143+
144+
const onStat = function(err, stat) {
145+
if (err) return callback(err);
146+
if (stat && stat.mode === 17115) return done();
147+
148+
if(options.sync){
149+
const list = fs.readdirSync(dir)
150+
return onDirRead(null, list)
151+
}else{
152+
fs.readdir(dir, onDirRead)
153+
}
154+
}
155+
156+
if(options.sync){
157+
const stat = fs.statSync(dir);
158+
return onStat(null, stat)
159+
}else{
160+
fs.stat(dir, onStat);
161+
}
85162
};
86163

87164

@@ -136,9 +213,24 @@ exports.paths = function paths(dir, combine, callback) {
136213
* console.log('subdirs:', paths.dirs);
137214
* });
138215
*/
139-
exports.subdirs = function subdirs(dir, callback) {
140-
exports.files(dir, 'dir', function(err, subdirs) {
141-
if (err) return callback(err);
142-
callback(null, subdirs);
143-
});
216+
exports.subdirs = function subdirs(dir, callback, type, options) {
217+
options = options || {}
218+
219+
const iCallback = function(err, subdirs) {
220+
if (err) return callback(err);
221+
222+
if(type=='combine'){
223+
subdirs = subdirs.files.concat(subdirs.dirs)
224+
}
225+
226+
if(options.sync)return subdirs
227+
228+
callback(null, subdirs);
229+
}
230+
231+
const res = exports.files(dir, 'dir', iCallback, options)
232+
233+
if(options && options.sync){
234+
return iCallback(null,res)
235+
}
144236
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "node-dir",
3-
"version": "0.1.16",
3+
"version": "0.1.17",
44
"description": "asynchronous file and directory operations for Node.js",
55
"main": "index",
66
"homepage": "https://github.com/fshost",

test/test.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,8 +1122,39 @@ describe('readfilesstream method', function() {
11221122
});
11231123
});
11241124

1125+
it("#promiseFiles", function(done) {
1126+
dir.promiseFiles(tdir)
1127+
.then(function(files) {
1128+
var relFiles = files.map(function(curPath) {
1129+
return path.relative(fixturesDir, curPath);
1130+
});
1131+
relFiles.sort().should.eql([
1132+
'testdir/file1.txt',
1133+
'testdir/file2.text',
1134+
'testdir/subdir/file3.txt',
1135+
'testdir/subdir/file4.text'
1136+
]);
1137+
})
1138+
.then(done).catch(done)
1139+
});
1140+
11251141
describe("files method", function() {
11261142

1143+
it("#files(path, {sync:true}",
1144+
function() {
1145+
var files = dir.files(tdir,'file',()=>{},{sync:true});
1146+
var relFiles = files.map(function(curPath) {
1147+
return path.relative(fixturesDir, curPath);
1148+
});
1149+
1150+
relFiles.sort().should.eql([
1151+
'testdir/file1.txt',
1152+
'testdir/file2.text',
1153+
'testdir/subdir/file3.txt',
1154+
'testdir/subdir/file4.text'
1155+
]);
1156+
});
1157+
11271158
it("should iterate the files of a directory (recursively) and pass their filenames to a callback", function(done) {
11281159
dir.files(tdir, function(err, files) {
11291160
should.not.exist(err);

0 commit comments

Comments
 (0)