node-readfiles
Advanced tools
Comparing version 0.0.9 to 0.1.0
var fs = require('fs'); | ||
var path = require('path'); | ||
var Promise = require('es6-promise').Promise; | ||
@@ -27,5 +28,4 @@ function buildFilter(filters) { | ||
function readfiles(dir, options, callback, doneCallback) { | ||
function readfiles(dir, options, callback) { | ||
if (typeof options === 'function' || options === null) { | ||
doneCallback = callback; | ||
callback = options; | ||
@@ -35,104 +35,123 @@ options = {}; | ||
options = options || {}; | ||
callback = typeof callback === 'function' ? callback : null; | ||
doneCallback = doneCallback || function () {}; | ||
callback = typeof callback === 'function' ? callback : function () {}; | ||
return new Promise(function (resolve, reject) { | ||
var files = []; | ||
var subdirs = []; | ||
var filterRegExp = options.filter && buildFilter(options.filter); | ||
var files = []; | ||
var subdirs = []; | ||
var filterRegExp = options.filter && buildFilter(options.filter); | ||
(function traverseDir(dirpath, done) { | ||
fs.readdir(dirpath, function (err, fileList) { | ||
if (err) { | ||
done(err, files.length, files); | ||
return; | ||
} | ||
// reverse the order of the files if the reverse option is true | ||
if (options.reverse === true) { | ||
fileList = fileList.reverse(); | ||
} | ||
(function next() { | ||
if (fileList.length === 0) { | ||
done(null, files, files.length); | ||
return; | ||
(function traverseDir(dirpath, done) { | ||
fs.readdir(dirpath, function (err, fileList) { | ||
if (err) { | ||
// if rejectOnError is not false, reject the promise | ||
if (options.rejectOnError !== false) { | ||
return reject(err); | ||
} | ||
return done(files); | ||
} | ||
var filename = fileList.shift(); | ||
var relFilename = path.join(subdirs.join('/'), filename); | ||
var fullpath = path.join(dirpath, filename); | ||
// skip file if it's a hidden file and the hidden option is not set | ||
if (options.hidden !== true && /^\./.test(filename)) { | ||
return next(); | ||
// reverse the order of the files if the reverse option is true | ||
if (options.reverse === true) { | ||
fileList = fileList.reverse(); | ||
} | ||
// stat the full path | ||
fs.stat(fullpath, function (err, stat) { | ||
if (err) { | ||
if (callback && callback(err, relFilename, null, stat, next) === false && !err) { | ||
return; | ||
} | ||
if (options.doneOnError !== false) { | ||
return doneCallback(err, files, files.length); | ||
} | ||
(function next() { | ||
var cbNext = null; | ||
if (options.async === true) cbNext = next; | ||
// if the file list is empty then call done | ||
if (fileList.length === 0) { | ||
done(files); | ||
return; | ||
} | ||
var filename = fileList.shift(); | ||
var relFilename = path.join(subdirs.join('/'), filename); | ||
var fullpath = path.join(dirpath, filename); | ||
// skip file if it's a hidden file and the hidden option is not set | ||
if (options.hidden !== true && /^\./.test(filename)) { | ||
return next(); | ||
} | ||
if (stat.isDirectory()) { | ||
// limit the depth of the traversal if depth is defined | ||
if (!isNaN(options.depth) && options.depth >= 0 && (subdirs.length + 1) > options.depth) { | ||
return next(); | ||
} | ||
// stat the full path | ||
fs.stat(fullpath, function (err, stat) { | ||
// traverse the sub-directory | ||
subdirs.push(filename); | ||
traverseDir(fullpath, function (err, count, files) { | ||
subdirs.pop(); | ||
next(); | ||
}); | ||
} else if (stat.isFile()) { | ||
if (err) { | ||
// call callback with the error | ||
callback(err, relFilename, null, stat, cbNext); | ||
// test filters, if it does not match move to next file | ||
if (filterRegExp && !filterRegExp.test('/' + relFilename)) { | ||
return next(); | ||
} | ||
// if rejectOnError is not false, reject the promise | ||
if (options.rejectOnError !== false) { | ||
return reject(err); | ||
} | ||
// set the format of the output filename | ||
var outputName = relFilename; | ||
if (options.filenameFormat === readfiles.FULL_PATH) { | ||
outputName = fullpath; | ||
}else if (options.filenameFormat === readfiles.FILENAME) { | ||
outputName = filename; | ||
//if async is true then don't call next | ||
return options.async !== true && next(); | ||
} | ||
files.push(outputName); | ||
// skip reading the file if readContents is false | ||
if (options.readContents === false) { | ||
if (callback && callback(null, outputName, null, stat, next) === false) { | ||
return; | ||
if (stat.isDirectory()) { | ||
// limit the depth of the traversal if depth is defined | ||
if (!isNaN(options.depth) && options.depth >= 0 && (subdirs.length + 1) > options.depth) { | ||
return next(); | ||
} | ||
return next(); | ||
} | ||
// read the file | ||
fs.readFile(fullpath, options.encoding || 'utf8', function (err, content) { | ||
// traverse the sub-directory | ||
subdirs.push(filename); | ||
traverseDir(fullpath, function (err, count, files) { | ||
subdirs.pop(); | ||
next(); | ||
}); | ||
// call "callback" | ||
if (callback && callback(err, outputName, content, stat, next) === false && !err) { | ||
return; | ||
} else if (stat.isFile()) { | ||
// test filters, if it does not match move to next file | ||
if (filterRegExp && !filterRegExp.test('/' + relFilename)) { | ||
return next(); | ||
} | ||
if (err && options.doneOnError !== false) { | ||
return doneCallback(err, files, files.length); | ||
// set the format of the output filename | ||
var outputName = relFilename; | ||
if (options.filenameFormat === readfiles.FULL_PATH) { | ||
outputName = fullpath; | ||
}else if (options.filenameFormat === readfiles.FILENAME) { | ||
outputName = filename; | ||
} | ||
files.push(outputName); | ||
// promise to handle file reading (if not disabled) | ||
new Promise(function (resolve, reject) { | ||
if (options.readContents === false) { | ||
return resolve(null); | ||
} | ||
// read the file | ||
fs.readFile(fullpath, options.encoding || 'utf8', function (err, content) { | ||
if (err) throw err; | ||
resolve(content); | ||
}); | ||
}).then(function (content) { | ||
// call the callback with the content | ||
callback(err, outputName, content, stat, cbNext); | ||
// call the next if async is not true | ||
options.async !== true && next(); | ||
}).catch(function (err) { | ||
if (options.rejectOnError !== false) { | ||
return reject(err); | ||
} | ||
//if async is true then don't call next | ||
options.async !== true && next(); | ||
}); | ||
} else { | ||
next(); | ||
}); | ||
} else { | ||
next(); | ||
} | ||
} | ||
}); | ||
})(); | ||
}); | ||
})(dir, doneCallback); | ||
}); | ||
})(); | ||
}); | ||
})(dir, resolve); | ||
}); | ||
} | ||
@@ -139,0 +158,0 @@ |
{ | ||
"name": "node-readfiles", | ||
"version": "0.0.9", | ||
"description": "A lightweight Node.js module to recursively read files in a directory", | ||
"version": "0.1.0", | ||
"description": "A lightweight Node.js module to recursively read files in a directory using ES6 Promises", | ||
"main": "index.js", | ||
@@ -29,3 +29,6 @@ "scripts": { | ||
"mock-fs": "^3.9.0" | ||
}, | ||
"dependencies": { | ||
"es6-promise": "^3.2.1" | ||
} | ||
} |
103
README.md
# node-readfiles | ||
A lightweight node.js module to recursively read files in a directory. | ||
A lightweight node.js module to recursively read files in a directory using ES6 Promises. | ||
@@ -16,4 +16,4 @@ ## Installation | ||
### readfiles(dir, [options], callback, [doneCallback]) | ||
Asynchronusly read the files in a directory | ||
### _Promise(files):_ readfiles(dir, [options], [callback]) | ||
Asynchronusly read the files in a directory returning a **Promise**. | ||
@@ -29,3 +29,3 @@ #### dir | ||
* **filenameFormat**: one of `readfiles.FULL_PATH`, `readfiles.RELATIVE`, or `readfiles.FILENAME`, wether the callback's returns the full-path, relative-path or only the filenames of the traversed files. (default is `readfiles.RELATIVE`) | ||
* **doneOnError**: a bollean value wether to stop and trigger the "doneCallback" when an error occurs (defaults to true) | ||
* **rejectOnError**: a bollean value wether to stop and trigger the "doneCallback" when an error occurs (defaults to true) | ||
* **filter**: a string, or an array of strings of path expression that match the files being read (defaults to '**') | ||
@@ -39,2 +39,3 @@ * `?` matches one character | ||
* **hidden**: a boolean value wether to exclude hidden files prefixed with a `.` (defaults to true) | ||
* **async**: a boolean value which enables/disables asynchronous traversal of the tree. When set to `true`, the `next()` in the `callback` must be called. (defaults to false) | ||
@@ -46,3 +47,3 @@ | ||
If you're doing a long operation and want to pause on every file, have the callback return `false`, will cause `readfiles` to pause until you call `next`. See bellow for an example. | ||
When working with asynchronous operations, you can set the `async` to `true`. This will enabled you to continue traversal of the directory when you call `next()`. See bellow for an example. | ||
@@ -52,6 +53,20 @@ | ||
### doneCallback(err, files, count) | ||
### _Promise(files)_ | ||
The callback function that is triggered once all the files have been read, passing the number of files read and an array with the full path of all files. | ||
When calling `readfiles`, an ES6 Promise is returned with an array of all the files that were found. You can then call `then` or `catch` to see if `readfiles` encountered an error. | ||
```javascript | ||
var readfiles = require('node-readfiles'); | ||
readfiles('/path/to/dir/', function (err, filename, contents) { | ||
if (err) throw err; | ||
console.log('File ' + filename + ':'); | ||
console.log(content); | ||
}).then(function (files) { | ||
console.log('Read ' + files.length + ' file(s)'); | ||
}).catch(function (err) { | ||
console.log('Error reading files:', err.message); | ||
}); | ||
``` | ||
## Examples | ||
@@ -62,4 +77,2 @@ | ||
```javascript | ||
var readfiles = require('readfiles'); | ||
readfiles('/path/to/dir/', function (err, filename, contents) { | ||
@@ -69,4 +82,4 @@ if (err) throw err; | ||
console.log(content); | ||
}, function (err, count, files) { | ||
console.log('Read ' + count + ' file(s)'); | ||
}).then(function (files) { | ||
console.log('Read ' + files.length + ' file(s)'); | ||
console.log(files.join('\n')); | ||
@@ -79,4 +92,2 @@ }); | ||
```javascript | ||
var readfiles = require('readfiles'); | ||
readfiles('/path/to/dir/', { | ||
@@ -88,4 +99,4 @@ depth: 0 | ||
console.log(content); | ||
}, function (err, count, files) { | ||
console.log('Read ' + count + ' file(s)'); | ||
}).then(function (files) { | ||
console.log('Read ' + files.length + ' file(s)'); | ||
console.log(files.join('\n')); | ||
@@ -95,7 +106,5 @@ }); | ||
The above can also be accomplished using `filter`. | ||
The above can also be accomplished using the `filter` option. | ||
```javascript | ||
var readfiles = require('readfiles'); | ||
readfiles('/path/to/dir/', { | ||
@@ -107,4 +116,4 @@ filter: '*' // instead of the default '**' | ||
console.log(content); | ||
}, function (err, count, files) { | ||
console.log('Read ' + count + ' file(s)'); | ||
}).then(function (files) { | ||
console.log('Read ' + files.length + ' file(s)'); | ||
console.log(files.join('\n')); | ||
@@ -117,4 +126,2 @@ }); | ||
```javascript | ||
var readfiles = require('readfiles'); | ||
readfiles('/path/to/dir/', { | ||
@@ -126,4 +133,4 @@ filter: '*.txt' | ||
console.log(content); | ||
}, function (err, count, files) { | ||
console.log('Read ' + count + ' text file(s)'); | ||
}).then(function (files) { | ||
console.log('Read ' + files.length + ' file(s)'); | ||
}); | ||
@@ -136,4 +143,2 @@ | ||
```javascript | ||
var readfiles = require('readfiles'); | ||
readfiles('/path/to/dir/', { | ||
@@ -145,4 +150,4 @@ filter: '*.t?t' | ||
console.log(content); | ||
}, function (err, count, files) { | ||
console.log('Read ' + count + ' text file(s)'); | ||
}).then(function (files) { | ||
console.log('Read ' + files.length + ' file(s)'); | ||
}); | ||
@@ -155,4 +160,2 @@ | ||
```javascript | ||
var readfiles = require('readfiles'); | ||
readfiles('/path/to/dir/', { | ||
@@ -168,8 +171,8 @@ filter: '*.json', | ||
This example waits for async calls to occur on every file. | ||
When making asynchronous calls on files, you can enable asynchronous support by setting the `async` to `true`. | ||
```javascript | ||
var readfiles = require('readfiles'); | ||
readfiles('/path/to/dir/', function (err, content, filename, stat, next) { | ||
readfiles('/path/to/dir/', { | ||
async: true | ||
}, function (err, content, filename, stat, next) { | ||
if (err) throw err; | ||
@@ -185,35 +188,3 @@ setTimeout(function () { | ||
A simple example that works like `find` | ||
```javascript | ||
var readfiles = require('node-readfiles'); | ||
var path = require('path'); | ||
function fileSize(size) { | ||
var unit = 'B'; | ||
if (size > 1000000000) { | ||
unit = 'T'; | ||
size /= 1000000000; | ||
}else if (size > 1000000) { | ||
unit = 'M'; | ||
size /= 1000000; | ||
}else if (size > 1000) { | ||
unit = 'K'; | ||
size /= 1000; | ||
} | ||
return (Math.round(size * 10) / 10) + unit; | ||
} | ||
var basepath = path.resolve(process.cwd(), process.argv.pop()); | ||
readfiles(basepath, { | ||
readContents: false | ||
}, function (err, filename, content, stat) { | ||
console.log(filename, fileSize(stat.size), (stat.mode & 0777).toString(8)); | ||
}, function (err, files, count) { | ||
console.log('\nTotal of', count, 'file(s) found\n'); | ||
}); | ||
``` | ||
## License | ||
MIT licensed (See LICENSE.txt) |
@@ -10,3 +10,3 @@ var expect = require('chai').expect; | ||
describe('readfiles method', function() { | ||
describe('readfiles', function() { | ||
after(function () { | ||
@@ -16,3 +16,3 @@ mock.restore(); | ||
describe('callbacks', function () { | ||
describe('defaults', function () { | ||
beforeEach(function () { | ||
@@ -44,5 +44,5 @@ mock(fixtures.flat); | ||
it('calls the done callback when finished traversing all files', function (done) { | ||
readfiles('/path/to/dir', null, function (err, files, count) { | ||
expect(count).to.equal(4); | ||
it('resolves the promise when finished traversing all files', function (done) { | ||
readfiles('/path/to/dir').then(function (files) { | ||
expect(files.length).to.equal(4); | ||
done(); | ||
@@ -53,3 +53,3 @@ }); | ||
it('calls the done callback with an error on a path', function(done) { | ||
readfiles('/fake/invalid/dir', null, function (err, files, count) { | ||
readfiles('/fake/invalid/dir').catch(function (err) { | ||
expect(err.message).to.equal('ENOENT, no such file or directory \'/fake/invalid/dir\''); | ||
@@ -70,3 +70,3 @@ done(); | ||
reverse: true | ||
}, null, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal([ | ||
@@ -114,3 +114,3 @@ 'subdir/test789.txt', | ||
expect(filename).to.equal(expectFiles[count++]); | ||
}, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -143,3 +143,3 @@ done(); | ||
expect(filename).to.equal(expectFiles[count++]); | ||
}, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -172,3 +172,3 @@ done(); | ||
expect(filename).to.equal(expectFiles[count++]); | ||
}, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -179,3 +179,3 @@ done(); | ||
it('does not call done when one file throws an error and \'doneOnError\' is false', function(done) { | ||
it('does not call done when one file throws an error and \'rejectOnError\' is false', function(done) { | ||
mock(fixtures.deepError); | ||
@@ -185,7 +185,7 @@ | ||
readfiles('/path/to/dir', { | ||
doneOnError: false | ||
rejectOnError: false | ||
}, function (err, filename) { | ||
fileCount++; | ||
}, function (err, files, count) { | ||
expect(count).to.equal(11); | ||
}).then(function (files) { | ||
expect(files.length).to.equal(11); | ||
done(); | ||
@@ -200,3 +200,3 @@ }); | ||
expect(contents).to.be.null; | ||
}, function (err, files, count) { | ||
}).then(function (files) { | ||
done(); | ||
@@ -229,3 +229,3 @@ }); | ||
expect(contents).to.equal(expectFiles[filename]); | ||
}, function (err, files, count) { | ||
}).then(function (files) { | ||
done(); | ||
@@ -253,3 +253,3 @@ }); | ||
expect(filename).to.equal(expectFiles[count++]); | ||
}, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -287,3 +287,3 @@ done(); | ||
expect(filename).to.equal(expectFiles[count++]); | ||
}, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -306,3 +306,3 @@ done(); | ||
filter: '*' | ||
}, null, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -332,3 +332,3 @@ done(); | ||
filter: '**' | ||
}, null, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -346,3 +346,3 @@ done(); | ||
filter: '*.txt' | ||
}, null, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -367,3 +367,3 @@ done(); | ||
filter: '**/*.txt' | ||
}, null, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -382,3 +382,3 @@ done(); | ||
filter: '**/abc123.txt' | ||
}, null, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -395,3 +395,3 @@ done(); | ||
filter: 'abc123.txt' | ||
}, null, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -417,3 +417,3 @@ done(); | ||
filter: '*/*' | ||
}, null, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -431,3 +431,3 @@ done(); | ||
filter: '*.t?t' | ||
}, null, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -452,3 +452,3 @@ done(); | ||
filter: '**/*.t??' | ||
}, null, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -471,3 +471,3 @@ done(); | ||
filter: ['**/*123*', '**/abc.*'] | ||
}, null, function (err, files, count) { | ||
}).then(function (files) { | ||
expect(files).to.deep.equal(expectFiles); | ||
@@ -474,0 +474,0 @@ done(); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
28542
623
1
173
+ Addedes6-promise@^3.2.1
+ Addedes6-promise@3.3.1(transitive)