From 0fa910f7198023b2394ff4cc323fb66c20aff48f Mon Sep 17 00:00:00 2001 From: ackerapple Date: Mon, 12 Dec 2016 10:45:12 -0500 Subject: [PATCH 01/37] improved docs, relative shortName option, improved performance for sync, promiseFiles type is optional --- README.md | 137 ++++++++++++++++++++++++++++++++++++--------------- lib/paths.js | 55 ++++++++++++++++++--- test/test.js | 79 ++++++++++++++++++++++------- 3 files changed, 207 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 99310a4..a1aa9e2 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,18 @@ A lightweight Node.js module with methods for some common directory and file ope - [installation](#installation) - [usage](#usage) - - [methods](#methods) - - [readFiles( dir, options, fileCallback, finishedCallback)](#readfiles-dir-options-filecallback-finishedcallback) - - [readFilesStream( dir, options, streamCallback, finishedCallback)](#readfilesstream-dir-options-streamcallback-finishedcallback) - - [readFilesStream examples](#readfilesstream-examples) - - [files( dir, callback )](#files-dir-callback) - - [files( dir, {sync:true} )](#files-dir-synctrue) - - [promiseFiles( dir, callback )](#promisefiles-dir-callback) - - [subdirs( dir, callback )](#subdirs-dir-callback) - - [paths(dir, [combine], callback )](#pathsdir-combine-callback) + - [methods](#methods) + - [readFiles](#readfiles) + - [readFilesStream](#readfilesstream) + - [readFilesStream examples](#readfilesstream-examples) + - [files async](#files-async) + - [files sync](#files-sync) + - [promiseFiles](#promisefiles) + - [subdirs](#subdirs) + - [paths](#paths) - [API Docs](#api-docs) - - [files(dir, type, callback, options)](#filesdir-type-callback-options) + - [files](#files-api) + - [promiseFiles](#promisefiles-api) - [License](#license) #### installation @@ -33,10 +34,19 @@ For the sake of brevity, assume that the following line of code precedes all of var dir = require('node-dir'); ``` -#### readFiles( dir, [options], fileCallback, [finishedCallback] ) -#### readFilesStream( dir, [options], streamCallback, [finishedCallback] ) +#### readFiles +A variation on the method readFilesStream. See usage for [readFilesStream](#readFilesStream) +``` +readFiles( dir, [options], fileCallback, [finishedCallback] ) +``` + +#### readFilesStream Sequentially read the content of each file in a directory, passing the contents to a callback, optionally calling a finished callback when complete. The options and finishedCallback arguments are not required. +``` +readFilesStream( dir, [options], streamCallback, [finishedCallback] ) +``` + Valid options are: - encoding: file encoding (defaults to 'utf8') - exclude: a regex pattern or array to specify filenames to ignore @@ -53,8 +63,8 @@ A reverse sort can also be achieved by setting the sort option to 'reverse', 'de #### readFilesStream examples -```javascript -// display contents of files in this script's directory +Display contents of files in this script's directory +``` dir.readFiles(__dirname, function(err, content, next) { if (err) throw err; @@ -64,9 +74,12 @@ dir.readFiles(__dirname, function(err, files){ if (err) throw err; console.log('finished reading files:', files); - }); + } +); +``` -// display contents of huge files in this script's directory +Display contents of huge files in this script's directory +``` dir.readFilesStream(__dirname, function(err, stream, next) { if (err) throw err; @@ -82,9 +95,12 @@ dir.readFilesStream(__dirname, function(err, files){ if (err) throw err; console.log('finished reading files:', files); - }); + } +); +``` -// match only filenames with a .txt extension and that don't start with a `.´ +Match only filenames with a .txt extension and that don't start with a `.´ +``` dir.readFiles(__dirname, { match: /.txt$/, exclude: /^\./ @@ -96,9 +112,12 @@ dir.readFiles(__dirname, { function(err, files){ if (err) throw err; console.log('finished reading files:',files); - }); + } +); +``` -// exclude an array of subdirectory names +Exclude an array of subdirectory names +``` dir.readFiles(__dirname, { exclude: ['node_modules', 'test'] }, function(err, content, next) { @@ -109,19 +128,20 @@ dir.readFiles(__dirname, { function(err, files){ if (err) throw err; console.log('finished reading files:',files); - }); - + } +); +``` -// the callback for each file can optionally have a filename argument as its 3rd parameter -// and the finishedCallback argument is optional, e.g. +The callback for each file can optionally have a filename argument as its 3rd parameter and the finishedCallback argument is optional, e.g. +``` dir.readFiles(__dirname, function(err, content, filename, next) { - console.log('processing content of file', filename); - next(); - }); + console.log('processing content of file', filename); + next(); +}); ``` -#### files( dir, callback ) +#### files async Asynchronously iterate the files of a directory and its subdirectories and pass an array of file paths to a callback. ```javascript @@ -131,17 +151,23 @@ dir.files(__dirname, function(err, files) { }); ``` -#### files( dir, {sync:true} ) +#### files sync Synchronously iterate the files of a directory and its subdirectories and pass an array of file paths to a callback. - + +In this example, a console log of items by relative path will be made ```javascript -var files = dir.files(__dirname, {sync:true}); +var files = dir.files(__dirname, {sync:true, shortName:'relative'}); console.log(files); ``` -#### promiseFiles( dir, callback ) +#### promiseFiles Asynchronously iterate the files of a directory and its subdirectories and pass an array of file paths to a callback. - + +``` +promiseFiles(path, readType||options, options) +``` + +promiseFiles example ```javascript dir.promiseFiles(__dirname) .then((files)=>{ @@ -155,14 +181,18 @@ Note that for the files and subdirs the object returned is an array, and thus al ```javascript dir.files(__dirname, function(err, files) { if (err) throw err; + // sort ascending files.sort(); + // sort descending files.reverse(); + // include only certain filenames files = files.filter(function (file) { return ['allowed', 'file', 'names'].indexOf(file) > -1; }); + // exclude some filenames files = files.filter(function (file) { return ['exclude', 'these', 'files'].indexOf(file) === -1; @@ -172,9 +202,14 @@ dir.files(__dirname, function(err, files) { Also note that if you need to work with the contents of the files asynchronously, please use the readFiles method. The files and subdirs methods are for getting a list of the files or subdirs in a directory as an array. -#### subdirs( dir, callback ) +#### subdirs Asynchronously iterate the subdirectories of a directory and its subdirectories and pass an array of directory paths to a callback. +``` +subdirs( dir, callback ) +``` + +Example ```javascript dir.subdirs(__dirname, function(err, subdirs) { if (err) throw err; @@ -182,12 +217,15 @@ dir.subdirs(__dirname, function(err, subdirs) { }); ``` -#### paths(dir, [combine], callback ) +#### paths Asynchronously iterate the subdirectories of a directory and its subdirectories and pass an array of both file and directory paths to a callback. -Separated into two distinct arrays (paths.files and paths.dirs) +``` +paths(dir, [combine], callback ) +``` -```javascript +Example: Separated into two distinct arrays (paths.files and paths.dirs) +``` dir.paths(__dirname, function(err, paths) { if (err) throw err; console.log('files:\n',paths.files); @@ -207,7 +245,11 @@ dir.paths(__dirname, true, function(err, paths) { ## API Docs -### files(dir, type, callback, options) +### files API + +``` +files(dir, type, callback, options) +``` - **dir** - directory path to read - **type**='file' @@ -218,7 +260,24 @@ dir.paths(__dirname, true, function(err, paths) { - **callback** - - **options** - **sync**=false - results are returned inline and no callbacks are used - - **shortName**=false - instead of fullpath file names, just get the names + - **shortName**=false||'relative' - instead of fullpath file names, just get the names or relative item names + - **recursive**=true - traverse through all children of given path + +### promiseFiles API + +``` +promiseFiles(dir, type||options, options) +``` + +- **dir** - directory path to read +- **type**='file' + - 'file' returns only file listings + - 'dir' returns only directory listings + - 'all' returns {dirs:[], files:[]} + - 'combine' returns [] +- **options** + - **sync**=false - DO NOT USE for promiseFiles, will cause unexpected behavior + - **shortName**=false||'relative' - instead of fullpath file names, just get the names or relative item names - **recursive**=true - traverse through all children of given path ## License diff --git a/lib/paths.js b/lib/paths.js index 605684b..f10098d 100644 --- a/lib/paths.js +++ b/lib/paths.js @@ -2,7 +2,14 @@ path = require('path'); exports.promiseFiles = function promiseFiles(dir, type, options){ - type = type || 'file' + switch(typeof type){ + case 'object': + options = type + type = 'file' + break; + + default:type = type || 'file' + } var processor = function(res,rej){ var cb = function(err,data){ @@ -61,16 +68,30 @@ exports.files = function files(dir, type, callback, options) { callback(null, results); }; - var getStatHandler = function(statPath, name, lstatCalled) { + /** + @statPath - fullPath + @name - fileName + @statHanOptions - { + valuetizer:function(stat, shortName, longPath){}, - function the handles value assignment + lstatCalled:false - used internally + } + */ + var getStatHandler = function(statPath, name, statHanOptions) { return function(err, stat) { if (err) { - if (!lstatCalled) { - return fs.lstat(statPath, getStatHandler(statPath, name, true)); + if (!statHanOptions.lstatCalled) { + var newStatHanOptions = Object.assign(statHanOptions, {lstatCalled:true}) + if(options.sync){ + var lstat = fs.lstatSync(statPath); + return getStatHandler(statPath, name, newStatHanOptions)(null, lstat) + }else{ + return fs.lstat(statPath, getStatHandler(statPath, name, newStatHanOptions)); + } } return callback(err); } - var pushVal = options.shortName ? name : statPath + var pushVal = statHanOptions.valuetizer(stat, name, statPath)//options.shortName ? name : statPath if (stat && stat.isDirectory() && stat.mode !== 17115) { if (type !== 'file') { @@ -100,8 +121,9 @@ exports.files = function files(dir, type, callback, options) { } var newOptions = Object.assign({}, options) + newOptions.basePath = options.basePath || dir newOptions.ignoreType = true - var moreResults = files(statPath, type, subloop, newOptions); + var moreResults = exports.files(statPath, type, subloop, newOptions); if(options.sync){ subloop(null, moreResults) @@ -126,15 +148,32 @@ exports.files = function files(dir, type, callback, options) { pending = list.length; if (!pending) return done(); + + var statHanOptions = {} + if(options.shortName){ + if(options.shortName=='relative'){ + statHanOptions.valuetizer = function(stat, shortName, longPath){ + return longPath.substring((options.basePath||dir).length+1, longPath.length) + } + }else{ + statHanOptions.valuetizer = function(stat, shortName, longPath){ + return shortName + } + } + }else{ + statHanOptions.valuetizer = function(stat, shortName, longPath){ + return longPath + } + } for (var file, i = 0, l = list.length; i < l; i++) { file = path.join(dir, list[i]); if(options.sync){ var res = fs.statSync(file); - getStatHandler(file,list[i])(null, res) + getStatHandler(file, list[i], statHanOptions)(null, res) }else{ - fs.stat(file, getStatHandler(file,list[i])); + fs.stat(file, getStatHandler(file, list[i], statHanOptions)); } } diff --git a/test/test.js b/test/test.js index 89200d6..7ffc7c4 100644 --- a/test/test.js +++ b/test/test.js @@ -5,7 +5,8 @@ tdir = path.join(fixturesDir, 'testdir'), tdir2 = path.join(fixturesDir, 'testdir2'), tdir3 = path.join(fixturesDir, 'testdir3'), - tdir4 = path.join(fixturesDir, 'testdir4'); + tdir4 = path.join(fixturesDir, 'testdir4'), + assert = require('assert'); describe('readfiles method', function() { @@ -1122,25 +1123,69 @@ describe('readfilesstream method', function() { }); }); -it("#promiseFiles", function(done) { - dir.promiseFiles(tdir) - .then(function(files) { - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.sort().should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text', - 'testdir/subdir/file3.txt', - 'testdir/subdir/file4.text' - ]); - }) - .then(done).catch(done) -}); +describe('#promiseFiles',function(){ + it("#promiseFiles", function(done) { + dir.promiseFiles(tdir) + .then(function(files) { + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.sort().should.eql([ + 'testdir/file1.txt', + 'testdir/file2.text', + 'testdir/subdir/file3.txt', + 'testdir/subdir/file4.text' + ]); + }) + .then(done).catch(done) + }); + + it("#promiseFiles(path, {shortName:true})", function(done) { + dir.promiseFiles(tdir, {shortName:true}) + .then(function(files) { + assert.deepEqual(files.sort(), [ + 'file1.txt', + 'file2.text', + 'file3.txt', + 'file4.text' + ]) + }) + .then(done).catch(done) + }); + + it("#promiseFiles(path, 'combine', {shortName:true})", function(done) { + dir.promiseFiles(tdir, 'combine', {shortName:true}) + .then(function(files) { + assert.deepEqual(files.sort(), [ + 'file1.txt', + 'file2.text', + 'file3.txt', + 'file4.text', + 'subdir' + ]) + }) + .then(done).catch(done) + }); + + it("#promiseFiles(path, 'combine', {shortName:'relative'})", function(done) { + dir.promiseFiles(tdir, 'combine', {shortName:'relative'}) + .then(function(files) { + assert.deepEqual(files.sort(), [ + 'file1.txt', + 'file2.text', + 'subdir', + 'subdir/file3.txt', + 'subdir/file4.text' + ]) + }) + .then(done).catch(done) + }); +}) + describe("files method", function() { - it("#files(path, {sync:true}", + it("#files(path, {sync:true})", function() { var files = dir.files(tdir,'file',()=>{},{sync:true}); var relFiles = files.map(function(curPath) { From 6fce5284a966136d7dde20630c02b04adfd1d7b5 Mon Sep 17 00:00:00 2001 From: ackerapple Date: Mon, 12 Dec 2016 10:45:42 -0500 Subject: [PATCH 02/37] version patch bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8961e0a..d88785f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-dir", - "version": "0.1.17", + "version": "0.1.18", "description": "asynchronous file and directory operations for Node.js", "main": "index", "homepage": "https://github.com/fshost", From 3b01fe5f16905be3a2a54e4473e5dd0f46ede4d8 Mon Sep 17 00:00:00 2001 From: ackerapple Date: Mon, 12 Dec 2016 13:28:52 -0500 Subject: [PATCH 03/37] more windows compat --- lib/paths.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/paths.js b/lib/paths.js index f10098d..7501bb7 100644 --- a/lib/paths.js +++ b/lib/paths.js @@ -153,7 +153,7 @@ exports.files = function files(dir, type, callback, options) { if(options.shortName){ if(options.shortName=='relative'){ statHanOptions.valuetizer = function(stat, shortName, longPath){ - return longPath.substring((options.basePath||dir).length+1, longPath.length) + return longPath.substring((options.basePath||dir).length+path.sep.length, longPath.length) } }else{ statHanOptions.valuetizer = function(stat, shortName, longPath){ From 42ed810666a4b9b84d98116c61e3accc2ea9070b Mon Sep 17 00:00:00 2001 From: ackerapple Date: Wed, 8 Feb 2017 15:06:30 -0500 Subject: [PATCH 04/37] fixed issue when shortName=relative and type=combine --- lib/paths.js | 18 ++++++++++++------ package.json | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/paths.js b/lib/paths.js index 7501bb7..9b42a80 100644 --- a/lib/paths.js +++ b/lib/paths.js @@ -91,9 +91,10 @@ exports.files = function files(dir, type, callback, options) { return callback(err); } - var pushVal = statHanOptions.valuetizer(stat, name, statPath)//options.shortName ? name : statPath + var isDir = stat && stat.isDirectory() && stat.mode !== 17115 + var pushVal = statHanOptions.valuetizer(stat, name, statPath, isDir)//options.shortName ? name : statPath - if (stat && stat.isDirectory() && stat.mode !== 17115) { + if (isDir) { if (type !== 'file') { results.dirs.push(pushVal); } @@ -143,7 +144,7 @@ exports.files = function files(dir, type, callback, options) { } } - const onDirRead = function(err, list) { + var onDirRead = function(err, list) { if (err) return callback(err); pending = list.length; @@ -152,8 +153,14 @@ exports.files = function files(dir, type, callback, options) { var statHanOptions = {} if(options.shortName){ if(options.shortName=='relative'){ - statHanOptions.valuetizer = function(stat, shortName, longPath){ - return longPath.substring((options.basePath||dir).length+path.sep.length, longPath.length) + var dirBase = (options.basePath||dir) + var startPos = dirBase.length + if(dirBase.substring(dirBase.length-path.sep.length, dirBase.length)!=path.sep){ + startPos = startPos + path.sep.length + } + + statHanOptions.valuetizer = function(stat, shortName, longPath, isDir){ + return longPath.substring(startPos, longPath.length) } }else{ statHanOptions.valuetizer = function(stat, shortName, longPath){ @@ -230,7 +237,6 @@ exports.paths = function paths(dir, combine, callback) { exports.files(dir, 'all', function(err, results) { if (err) return callback(err); if (combine) { - callback(null, results.files.concat(results.dirs)); } else { callback(null, results); diff --git a/package.json b/package.json index d88785f..e02c567 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-dir", - "version": "0.1.18", + "version": "0.1.19", "description": "asynchronous file and directory operations for Node.js", "main": "index", "homepage": "https://github.com/fshost", From 09843648d6f7a0c53ff1136820efba3bfc8ba27e Mon Sep 17 00:00:00 2001 From: ackerapple Date: Thu, 15 Jun 2017 10:26:38 -0400 Subject: [PATCH 05/37] readme --- README.md | 28 ++++++++++++------------ test/fixtures/testdir5/testu%E7%F5es.txt | 1 + 2 files changed, 15 insertions(+), 14 deletions(-) create mode 100644 test/fixtures/testdir5/testu%E7%F5es.txt diff --git a/README.md b/README.md index a1aa9e2..dc4ddcd 100644 --- a/README.md +++ b/README.md @@ -36,14 +36,14 @@ var dir = require('node-dir'); #### readFiles A variation on the method readFilesStream. See usage for [readFilesStream](#readFilesStream) -``` +```javascript readFiles( dir, [options], fileCallback, [finishedCallback] ) ``` #### readFilesStream Sequentially read the content of each file in a directory, passing the contents to a callback, optionally calling a finished callback when complete. The options and finishedCallback arguments are not required. -``` +```javascript readFilesStream( dir, [options], streamCallback, [finishedCallback] ) ``` @@ -64,7 +64,7 @@ A reverse sort can also be achieved by setting the sort option to 'reverse', 'de #### readFilesStream examples Display contents of files in this script's directory -``` +```javascript dir.readFiles(__dirname, function(err, content, next) { if (err) throw err; @@ -79,7 +79,7 @@ dir.readFiles(__dirname, ``` Display contents of huge files in this script's directory -``` +```javascript dir.readFilesStream(__dirname, function(err, stream, next) { if (err) throw err; @@ -100,7 +100,7 @@ dir.readFilesStream(__dirname, ``` Match only filenames with a .txt extension and that don't start with a `.´ -``` +```javascript dir.readFiles(__dirname, { match: /.txt$/, exclude: /^\./ @@ -117,9 +117,9 @@ dir.readFiles(__dirname, { ``` Exclude an array of subdirectory names -``` +```javascript dir.readFiles(__dirname, { - exclude: ['node_modules', 'test'] + excludeDir: ['node_modules', 'test'] }, function(err, content, next) { if (err) throw err; console.log('content:', content); @@ -133,7 +133,7 @@ dir.readFiles(__dirname, { ``` The callback for each file can optionally have a filename argument as its 3rd parameter and the finishedCallback argument is optional, e.g. -``` +```javascript dir.readFiles(__dirname, function(err, content, filename, next) { console.log('processing content of file', filename); next(); @@ -163,7 +163,7 @@ console.log(files); #### promiseFiles Asynchronously iterate the files of a directory and its subdirectories and pass an array of file paths to a callback. -``` +```javascript promiseFiles(path, readType||options, options) ``` @@ -205,7 +205,7 @@ Also note that if you need to work with the contents of the files asynchronously #### subdirs Asynchronously iterate the subdirectories of a directory and its subdirectories and pass an array of directory paths to a callback. -``` +```javascript subdirs( dir, callback ) ``` @@ -220,12 +220,12 @@ dir.subdirs(__dirname, function(err, subdirs) { #### paths Asynchronously iterate the subdirectories of a directory and its subdirectories and pass an array of both file and directory paths to a callback. -``` +```javascript paths(dir, [combine], callback ) ``` Example: Separated into two distinct arrays (paths.files and paths.dirs) -``` +```javascript dir.paths(__dirname, function(err, paths) { if (err) throw err; console.log('files:\n',paths.files); @@ -247,7 +247,7 @@ dir.paths(__dirname, true, function(err, paths) { ### files API -``` +```javascript files(dir, type, callback, options) ``` @@ -265,7 +265,7 @@ files(dir, type, callback, options) ### promiseFiles API -``` +```javascript promiseFiles(dir, type||options, options) ``` diff --git a/test/fixtures/testdir5/testu%E7%F5es.txt b/test/fixtures/testdir5/testu%E7%F5es.txt new file mode 100644 index 0000000..5dcd581 --- /dev/null +++ b/test/fixtures/testdir5/testu%E7%F5es.txt @@ -0,0 +1 @@ +bla \ No newline at end of file From 5a74154f2a0b6fce43f4a89cf41988b1f0aa78eb Mon Sep 17 00:00:00 2001 From: ackerapple Date: Thu, 15 Jun 2017 12:54:51 -0400 Subject: [PATCH 06/37] tests --- .appveyor.yml | 26 ++++++++++++++++++++++++++ .travis.yml | 7 ++++--- README.md | 3 ++- lib/paths.js | 4 +++- test/test.js | 12 ++++++++++-- 5 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 .appveyor.yml diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000..1aa724a --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,26 @@ +# Test against the latest versions of these Node.js versions +environment: + matrix: + # node.js + - nodejs_version: "4" + - nodejs_version: "5" + - nodejs_version: "6" + - nodejs_version: "7" + +# Install scripts. (runs after repo cloning) +install: + # Get the latest stable version of Node.js or io.js + - ps: Install-Product node $env:nodejs_version + # install modules + - npm install + +# Post-install test scripts. +test_script: + # Output useful info for debugging. + - node --version + - npm --version + # run tests + - npm test + +# Don't actually build. +build: off \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index e351614..50a3d94 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: node_js -# test on node.js version 0.10.x node_js: - - 0.10 - + - 4 + - 5 + - 0.12 + - 0.10 \ No newline at end of file diff --git a/README.md b/README.md index dc4ddcd..00b5d28 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ Synchronously iterate the files of a directory and its subdirectories and pass a In this example, a console log of items by relative path will be made ```javascript -var files = dir.files(__dirname, {sync:true, shortName:'relative'}); +var files = dir.files(__dirname, {sync:true, shortName:'relative', excludeHidden:true}); console.log(files); ``` @@ -262,6 +262,7 @@ files(dir, type, callback, options) - **sync**=false - results are returned inline and no callbacks are used - **shortName**=false||'relative' - instead of fullpath file names, just get the names or relative item names - **recursive**=true - traverse through all children of given path + - **excludeHidden** - hidden files will be ignored (files starting with a dot are ignored) ### promiseFiles API diff --git a/lib/paths.js b/lib/paths.js index 99056d9..4287113 100644 --- a/lib/paths.js +++ b/lib/paths.js @@ -133,7 +133,9 @@ exports.files = function files(dir, type, callback, options) { done() } } else { - if (type !== 'dir') { + var excludeHidden = options.excludeHidden && name.split(path.sep).pop().search(/^\./)==0 + + if (type!=='dir' && !excludeHidden) { results.files.push(pushVal); } // should be the last statement in statHandler diff --git a/test/test.js b/test/test.js index b18a86b..40ba673 100644 --- a/test/test.js +++ b/test/test.js @@ -1248,9 +1248,17 @@ describe("files method", function() { }); it("support non-UTF8 file names", function() { - var files = dir.files(tdir5,'file',()=>{},{sync:true}); + var files = dir.files(tdir5,'file',()=>{},{sync:true, excludeHidden:true}); var cmp = Buffer.from('testdir5/testuções.txt', 'latin1').toString(); - path.relative(fixturesDir, files[0]).should.eql(cmp); + + var relFile = path.relative(fixturesDir, files[0]) + + //this test fails on Mac, length check all the works on Mac + if(relFile.length==26){ + assert.equal(cmp.length, relFile.length-4) + }else{ + relFile.should.eql(cmp)//This test does not pass on all Systems + } }); }); From c5e9d93d209252572c5c961fd2b58a0f28c4349d Mon Sep 17 00:00:00 2001 From: ackerapple Date: Thu, 15 Jun 2017 12:56:27 -0400 Subject: [PATCH 07/37] backwards compat old node --- test/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.js b/test/test.js index 40ba673..a84cb16 100644 --- a/test/test.js +++ b/test/test.js @@ -1188,7 +1188,7 @@ describe("files method", function() { it("#files(path, {sync:true})", function() { - var files = dir.files(tdir,'file',()=>{},{sync:true}); + var files = dir.files(tdir,'file',function(){},{sync:true}); var relFiles = files.map(function(curPath) { return path.relative(fixturesDir, curPath); }); From cf54939fd58bb99af0652f4eb14212a344ac0bfc Mon Sep 17 00:00:00 2001 From: ackerapple Date: Thu, 15 Jun 2017 12:58:44 -0400 Subject: [PATCH 08/37] skip test for non utf8 files --- test/test.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/test/test.js b/test/test.js index a84cb16..11927d6 100644 --- a/test/test.js +++ b/test/test.js @@ -1247,18 +1247,13 @@ describe("files method", function() { }); }); - it("support non-UTF8 file names", function() { + //NOT supported everywhere + it.skip("support non-UTF8 file names", function() { var files = dir.files(tdir5,'file',()=>{},{sync:true, excludeHidden:true}); var cmp = Buffer.from('testdir5/testuções.txt', 'latin1').toString(); var relFile = path.relative(fixturesDir, files[0]) - - //this test fails on Mac, length check all the works on Mac - if(relFile.length==26){ - assert.equal(cmp.length, relFile.length-4) - }else{ - relFile.should.eql(cmp)//This test does not pass on all Systems - } + relFile.should.eql(cmp)//This test does not pass on all Systems }); }); From 352413bade4e50f0c98ca11abdd51543523ca1ec Mon Sep 17 00:00:00 2001 From: ackerapple Date: Thu, 15 Jun 2017 13:00:40 -0400 Subject: [PATCH 09/37] test remove arrow function --- test/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.js b/test/test.js index 11927d6..9e08b91 100644 --- a/test/test.js +++ b/test/test.js @@ -1249,7 +1249,7 @@ describe("files method", function() { //NOT supported everywhere it.skip("support non-UTF8 file names", function() { - var files = dir.files(tdir5,'file',()=>{},{sync:true, excludeHidden:true}); + var files = dir.files(tdir5,'file', function(){}, {sync:true, excludeHidden:true}); var cmp = Buffer.from('testdir5/testuções.txt', 'latin1').toString(); var relFile = path.relative(fixturesDir, files[0]) From 3d4bc4b44a516172673366a6e84a13e1eeb17cee Mon Sep 17 00:00:00 2001 From: ackerapple Date: Thu, 15 Jun 2017 13:05:52 -0400 Subject: [PATCH 10/37] backwards compat, removed Object.assign --- index.js | 3 ++- lib/paths.js | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 49e3555..71f4b0d 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ var dirpaths = require('./lib/paths'); -Object.assign(exports, dirpaths) +for(var x in dirpaths)exports[x] = dirpaths[x] + exports.readFiles = require('./lib/readfiles'); exports.readFilesStream = require('./lib/readfilesstream'); diff --git a/lib/paths.js b/lib/paths.js index 4287113..27e6d1b 100644 --- a/lib/paths.js +++ b/lib/paths.js @@ -80,7 +80,7 @@ exports.files = function files(dir, type, callback, options) { return function(err, stat) { if (err) { if (!statHanOptions.lstatCalled) { - var newStatHanOptions = Object.assign(statHanOptions, {lstatCalled:true}) + var newStatHanOptions = assign(statHanOptions, {lstatCalled:true}) if(options.sync){ var lstat = fs.lstatSync(statPath); return getStatHandler(statPath, name, newStatHanOptions)(null, lstat) @@ -121,7 +121,7 @@ exports.files = function files(dir, type, callback, options) { } } - var newOptions = Object.assign({}, options) + var newOptions = assign({}, options) newOptions.basePath = options.basePath || dir newOptions.ignoreType = true var moreResults = exports.files(statPath, type, subloop, newOptions); @@ -285,4 +285,9 @@ exports.subdirs = function subdirs(dir, callback, type, options) { if(options && options.sync){ return iCallback(null,res) } -}; +} + +function assign(c0, c1){ + for(var x in c1)c0[x] = c1[x] + return c0 +} \ No newline at end of file From d0e9d785b7cfe9df77e9025d7f72cc0fc17e4f6f Mon Sep 17 00:00:00 2001 From: ackerapple Date: Thu, 15 Jun 2017 13:08:46 -0400 Subject: [PATCH 11/37] removed support for node .1 --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 50a3d94..e2edb8c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,4 @@ language: node_js node_js: - 4 - 5 - - 0.12 - - 0.10 \ No newline at end of file + - 0.12 \ No newline at end of file From 14e65c229318fcc05ac086d85d2f71f1f005dbb5 Mon Sep 17 00:00:00 2001 From: ackerapple Date: Thu, 15 Jun 2017 13:15:02 -0400 Subject: [PATCH 12/37] windows compat tests --- test/test.js | 160 +++++++++++++++++++++++++-------------------------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/test/test.js b/test/test.js index 9e08b91..9e4cfba 100644 --- a/test/test.js +++ b/test/test.js @@ -38,10 +38,10 @@ describe('readfiles method', function() { files.map(function(curPath) { return path.relative(fixturesDir, curPath); }).sort().should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text', - 'testdir/subdir/file3.txt', - 'testdir/subdir/file4.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' ]); filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); done(); @@ -67,10 +67,10 @@ describe('readfiles method', function() { return path.relative(fixturesDir, curPath); }); relFiles.should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text', - 'testdir/subdir/file3.txt', - 'testdir/subdir/file4.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' ]); filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); done(); @@ -96,10 +96,10 @@ describe('readfiles method', function() { return path.relative(fixturesDir, curPath); }); relFiles.should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text', - 'testdir/subdir/file3.txt', - 'testdir/subdir/file4.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' ]); filenames.should.eql(['file1', 'file2', 'file3', 'file4']); done(); @@ -125,10 +125,10 @@ describe('readfiles method', function() { return path.relative(fixturesDir, curPath); }); relFiles.should.eql([ - 'testdir/subdir/file4.text', - 'testdir/subdir/file3.txt', - 'testdir/file2.text', - 'testdir/file1.txt' + 'testdir'+path.sep+'subdir'+path.sep+'file4.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'file1.txt' ]); filenames.should.eql(['file4', 'file3', 'file2', 'file1']); done(); @@ -156,8 +156,8 @@ describe('readfiles method', function() { return path.relative(fixturesDir, curPath); }); relFiles.should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text' ]); filenames.should.eql(['file1', 'file2']); done(); @@ -242,8 +242,8 @@ describe('readfiles method', function() { return path.relative(fixturesDir, curPath); }); relFiles.sort().should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text' ]); filenames.sort().should.eql(['file1', 'file2']); done(); @@ -309,10 +309,10 @@ describe('readfiles method', function() { return path.relative(fixturesDir, curPath); }); relFiles.sort().should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text', - 'testdir/subdir/file3.txt', - 'testdir/subdir/file4.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' ]); filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); done(); @@ -528,10 +528,10 @@ describe('readfilesstream method', function() { files.map(function(curPath) { return path.relative(fixturesDir, curPath); }).sort().should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text', - 'testdir/subdir/file3.txt', - 'testdir/subdir/file4.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' ]); filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); done(); @@ -565,10 +565,10 @@ describe('readfilesstream method', function() { return path.relative(fixturesDir, curPath); }); relFiles.should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text', - 'testdir/subdir/file3.txt', - 'testdir/subdir/file4.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' ]); filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); done(); @@ -601,10 +601,10 @@ describe('readfilesstream method', function() { return path.relative(fixturesDir, curPath); }); relFiles.should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text', - 'testdir/subdir/file3.txt', - 'testdir/subdir/file4.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' ]); filenames.should.eql(['file1', 'file2', 'file3', 'file4']); done(); @@ -637,10 +637,10 @@ describe('readfilesstream method', function() { return path.relative(fixturesDir, curPath); }); relFiles.should.eql([ - 'testdir/subdir/file4.text', - 'testdir/subdir/file3.txt', - 'testdir/file2.text', - 'testdir/file1.txt' + 'testdir'+path.sep+'subdir'+path.sep+'file4.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'file1.txt' ]); filenames.should.eql(['file4', 'file3', 'file2', 'file1']); done(); @@ -675,8 +675,8 @@ describe('readfilesstream method', function() { return path.relative(fixturesDir, curPath); }); relFiles.should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text' ]); filenames.should.eql(['file1', 'file2']); done(); @@ -789,8 +789,8 @@ describe('readfilesstream method', function() { return path.relative(fixturesDir, curPath); }); relFiles.sort().should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text' ]); filenames.sort().should.eql(['file1', 'file2']); done(); @@ -877,10 +877,10 @@ describe('readfilesstream method', function() { return path.relative(fixturesDir, curPath); }); relFiles.sort().should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text', - 'testdir/subdir/file3.txt', - 'testdir/subdir/file4.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' ]); filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); done(); @@ -1132,10 +1132,10 @@ describe('#promiseFiles',function(){ return path.relative(fixturesDir, curPath); }); relFiles.sort().should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text', - 'testdir/subdir/file3.txt', - 'testdir/subdir/file4.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' ]); }) .then(done).catch(done) @@ -1175,8 +1175,8 @@ describe('#promiseFiles',function(){ 'file1.txt', 'file2.text', 'subdir', - 'subdir/file3.txt', - 'subdir/file4.text' + 'subdir'+path.sep+'file3.txt', + 'subdir'+path.sep+'file4.text' ]) }) .then(done).catch(done) @@ -1194,10 +1194,10 @@ describe("files method", function() { }); relFiles.sort().should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text', - 'testdir/subdir/file3.txt', - 'testdir/subdir/file4.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' ]); }); @@ -1208,10 +1208,10 @@ describe("files method", function() { return path.relative(fixturesDir, curPath); }); relFiles.sort().should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text', - 'testdir/subdir/file3.txt', - 'testdir/subdir/file4.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' ]); done(); }); @@ -1224,8 +1224,8 @@ describe("files method", function() { return path.relative(fixturesDir, curPath); }); relFiles.sort().should.eql([ - 'testdir3/broken_link.txt', - 'testdir3/file1.txt' + 'testdir3'+path.sep+'broken_link.txt', + 'testdir3'+path.sep+'file1.txt' ]); done(); }); @@ -1238,10 +1238,10 @@ describe("files method", function() { return path.relative(fixturesDir, curPath); }); relFiles.sort().should.eql([ - 'testdir4/testdir/file1.txt', - 'testdir4/testdir/file2.text', - 'testdir4/testdir/subdir/file3.txt', - 'testdir4/testdir/subdir/file4.text' + 'testdir4'+path.sep+'testdir'+path.sep+'file1.txt', + 'testdir4'+path.sep+'testdir'+path.sep+'file2.text', + 'testdir4'+path.sep+'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir4'+path.sep+'testdir'+path.sep+'subdir'+path.sep+'file4.text' ]); done(); }); @@ -1250,7 +1250,7 @@ describe("files method", function() { //NOT supported everywhere it.skip("support non-UTF8 file names", function() { var files = dir.files(tdir5,'file', function(){}, {sync:true, excludeHidden:true}); - var cmp = Buffer.from('testdir5/testuções.txt', 'latin1').toString(); + var cmp = Buffer.from('testdir5'+path.sep+'testuções.txt', 'latin1').toString(); var relFile = path.relative(fixturesDir, files[0]) relFile.should.eql(cmp)//This test does not pass on all Systems @@ -1267,7 +1267,7 @@ describe('subdirs method', function() { return path.relative(fixturesDir, curPath); }); relPaths.length.should.equal(1); - relPaths[0].should.equal('testdir/subdir'); + relPaths[0].should.equal('testdir'+path.sep+'subdir'); done(); }); @@ -1289,13 +1289,13 @@ describe('paths method', function() { return path.relative(fixturesDir, curPath); }); relFiles.sort().should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text', - 'testdir/subdir/file3.txt', - 'testdir/subdir/file4.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' ]); relPaths.length.should.equal(1); - relPaths[0].should.equal('testdir/subdir'); + relPaths[0].should.equal('testdir'+path.sep+'subdir'); done(); }); }); @@ -1311,11 +1311,11 @@ describe('paths method', function() { return path.relative(fixturesDir, curPath); }); relPaths.sort().should.eql([ - 'testdir/file1.txt', - 'testdir/file2.text', - 'testdir/subdir', - 'testdir/subdir/file3.txt', - 'testdir/subdir/file4.text' + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' ]); }); done(); From f507444b46580c1d082e83bce847a92e7dbc74dc Mon Sep 17 00:00:00 2001 From: Acker Dawn Apple Date: Thu, 15 Jun 2017 13:46:31 -0400 Subject: [PATCH 13/37] refine windows tests --- test/test.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/test/test.js b/test/test.js index 9e4cfba..a240752 100644 --- a/test/test.js +++ b/test/test.js @@ -1,4 +1,4 @@ -var path = require('path'), +var path = require('path'), should = require('should'), dir = require('..'), fixturesDir = path.join(__dirname, 'fixtures'), @@ -6,8 +6,10 @@ tdir2 = path.join(fixturesDir, 'testdir2'), tdir3 = path.join(fixturesDir, 'testdir3'), tdir4 = path.join(fixturesDir, 'testdir4'), - tdir5 = path.join(fixturesDir, 'testdir5'); - assert = require('assert'); + tdir5 = path.join(fixturesDir, 'testdir5'), + assert = require('assert'), + isWin = require('os').type()=='Windows_NT', + winIt = isWin ? it.skip : it describe('readfiles method', function() { @@ -456,6 +458,7 @@ describe('readfiles method', function() { it('if given doneOnErr to false, should not done on error', function(done) { dir.readFiles( tdir3, { doneOnErr: false },function(err, content, filename, next) { + if(filename.split(path.sep).pop()!='file1.txt')return next() should.not.exist(err); var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; @@ -1075,6 +1078,7 @@ describe('readfilesstream method', function() { it('if given doneOnErr to false, should not done on error', function(done) { dir.readFilesStream( tdir3, { doneOnErr: false },function(err, stream, filename, next) { + if(filename.split(path.sep).pop()!='file1.txt')return next() should.not.exist(err); var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; @@ -1231,18 +1235,19 @@ describe("files method", function() { }); }); - it("should iterate files of symlinked directories (recursively)", function(done) { + winIt("should iterate files of symlinked directories (recursively)", function(done) { dir.files(tdir4, function(err, files) { should.not.exist(err); var relFiles = files.map(function(curPath) { return path.relative(fixturesDir, curPath); }); - relFiles.sort().should.eql([ + var testArray = [ 'testdir4'+path.sep+'testdir'+path.sep+'file1.txt', 'testdir4'+path.sep+'testdir'+path.sep+'file2.text', 'testdir4'+path.sep+'testdir'+path.sep+'subdir'+path.sep+'file3.txt', 'testdir4'+path.sep+'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); + ] + relFiles.sort().should.eql(testArray); done(); }); }); From d0f447c40558a354498b0f8e60f2e525074149c7 Mon Sep 17 00:00:00 2001 From: Acker Dawn Apple Date: Thu, 15 Jun 2017 13:51:22 -0400 Subject: [PATCH 14/37] fix win testing --- test/test.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/test.js b/test/test.js index a240752..f51fdd0 100644 --- a/test/test.js +++ b/test/test.js @@ -9,7 +9,7 @@ var path = require('path'), tdir5 = path.join(fixturesDir, 'testdir5'), assert = require('assert'), isWin = require('os').type()=='Windows_NT', - winIt = isWin ? it.skip : it + winIt = isWin ? it.skip : it//skip all symlink based testing describe('readfiles method', function() { @@ -441,9 +441,10 @@ describe('readfiles method', function() { }); }); - it('should done on error', function(done) { + winIt('should done on error', function(done) { dir.readFiles( tdir3, function(err, content, filename, next) { + if(filename.split(path.sep).pop()!='file1.txt')return next() should.not.exist(err); var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; @@ -1052,7 +1053,7 @@ describe('readfilesstream method', function() { }); }); - it('should done on error', function(done) { + winIt('should done on error', function(done) { dir.readFilesStream( tdir3, function(err, stream, filename, next) { should.not.exist(err); From 501cc2006af791802ef13b6abbacf7b02a465f58 Mon Sep 17 00:00:00 2001 From: Acker Dawn Apple Date: Thu, 15 Jun 2017 13:58:40 -0400 Subject: [PATCH 15/37] Create CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..14e499f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,5 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +To let anyone and everyone contribute in any manner that they want because a Contributor Convenant Code of Conduct is just some big words too close to a corporate enviroment document that I want no part of. From f22e1e801519fafa14b3e7bd74fe9c3a52b4ee6a Mon Sep 17 00:00:00 2001 From: Acker Dawn Apple Date: Thu, 15 Jun 2017 14:00:28 -0400 Subject: [PATCH 16/37] Delete CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 14e499f..0000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,5 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -To let anyone and everyone contribute in any manner that they want because a Contributor Convenant Code of Conduct is just some big words too close to a corporate enviroment document that I want no part of. From 2f1ad789ef537d5b24681c39b7191dea5f3dbd1d Mon Sep 17 00:00:00 2001 From: Acker Dawn Apple Date: Thu, 15 Jun 2017 14:00:54 -0400 Subject: [PATCH 17/37] Create CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..14e499f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,5 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +To let anyone and everyone contribute in any manner that they want because a Contributor Convenant Code of Conduct is just some big words too close to a corporate enviroment document that I want no part of. From 3b83eda8ddb0eb070f8da0dc70f1be7318c077e7 Mon Sep 17 00:00:00 2001 From: Acker Dawn Apple Date: Thu, 15 Jun 2017 14:01:41 -0400 Subject: [PATCH 18/37] Delete CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 14e499f..0000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,5 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -To let anyone and everyone contribute in any manner that they want because a Contributor Convenant Code of Conduct is just some big words too close to a corporate enviroment document that I want no part of. From 3d5eaeb3e7908f00349e2ef507db2e10095cfbb7 Mon Sep 17 00:00:00 2001 From: Acker Dawn Apple Date: Thu, 15 Jun 2017 14:02:17 -0400 Subject: [PATCH 19/37] Create CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..45c351d --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,50 @@ +# Contributor Covenant Code of Conduct + +To let anyone and everyone contribute in any manner that they want because a Contributor Convenant Code of Conduct is just some big words too close to a corporate enviroment document that I want no part of. + +-- IGNORE THE COPY PASTE FROM GITHUB BELOW -- + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at acker.dawn.apple@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ From 44a6c6824fdbbd1c5d05b17df6d18bf80e6b7712 Mon Sep 17 00:00:00 2001 From: Acker Dawn Apple Date: Thu, 15 Jun 2017 14:03:33 -0400 Subject: [PATCH 20/37] Delete CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 50 ---------------------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 45c351d..0000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,50 +0,0 @@ -# Contributor Covenant Code of Conduct - -To let anyone and everyone contribute in any manner that they want because a Contributor Convenant Code of Conduct is just some big words too close to a corporate enviroment document that I want no part of. - --- IGNORE THE COPY PASTE FROM GITHUB BELOW -- - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at acker.dawn.apple@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ From 408847b86d71fd7e9f95c102571322a90aacfcc9 Mon Sep 17 00:00:00 2001 From: bobymxiang Date: Wed, 9 Aug 2017 15:41:52 +0800 Subject: [PATCH 21/37] fixed strange problem with webpack. https://github.com/fshost/node-dir/issues/46 --- lib/readfiles.js | 2 +- lib/readfilesstream.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/readfiles.js b/lib/readfiles.js index ea3df03..20db44c 100644 --- a/lib/readfiles.js +++ b/lib/readfiles.js @@ -62,7 +62,7 @@ function readFiles(dir, options, callback, complete) { }; fs.readdir(dir, function(err, list) { - if (err)  { + if (err) { if (options.doneOnErr === true) { if (err.code === 'EACCES') return done(); return done(err); diff --git a/lib/readfilesstream.js b/lib/readfilesstream.js index b318ccf..eddd202 100644 --- a/lib/readfilesstream.js +++ b/lib/readfilesstream.js @@ -71,7 +71,7 @@ function readFilesStream(dir, options, callback, complete) { }; fs.readdir(dir, function(err, list) { - if (err)  { + if (err) { if (options.doneOnErr === true) { if (err.code === 'EACCES') return done(); return done(err); From 72a4d2c9b1f4a473a1b20c0d8616e508c1ab53dc Mon Sep 17 00:00:00 2001 From: ackerapple Date: Wed, 9 Aug 2017 09:57:29 -0400 Subject: [PATCH 22/37] ready for npm publish --- .travis.yml | 1 + package-lock.json | 323 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 19 +-- 3 files changed, 331 insertions(+), 12 deletions(-) create mode 100644 package-lock.json diff --git a/.travis.yml b/.travis.yml index e2edb8c..a3cbb3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: node_js node_js: + - 8 - 4 - 5 - 0.12 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..d2ff657 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,323 @@ +{ + "name": "path-reader", + "version": "0.1.19", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "requires": { + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.0.tgz", + "integrity": "sha512-pIU2PJjrPYvYRqVpjXzj76qltO9uBYI7woYAMoxbSefsa+vqAfptjoeevd6bUgwD0mPIO+hv9f7ltvsNreL2PA==", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.6.8", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.1", + "growl": "1.9.2", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "should": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/should/-/should-11.2.1.tgz", + "integrity": "sha1-kPVRRVUtAc/CAGZuToGKHJZw7aI=", + "dev": true, + "requires": { + "should-equal": "1.0.1", + "should-format": "3.0.3", + "should-type": "1.4.0", + "should-type-adaptors": "1.0.1", + "should-util": "1.0.0" + } + }, + "should-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-1.0.1.tgz", + "integrity": "sha1-C26VFvJgGp+wuy3MNpr6HH4gCvc=", + "dev": true, + "requires": { + "should-type": "1.4.0" + } + }, + "should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "dev": true, + "requires": { + "should-type": "1.4.0", + "should-type-adaptors": "1.0.1" + } + }, + "should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "dev": true + }, + "should-type-adaptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.0.1.tgz", + "integrity": "sha1-7+VVPN9oz/ZuXF9RtxLcNRx3vqo=", + "dev": true, + "requires": { + "should-type": "1.4.0", + "should-util": "1.0.0" + } + }, + "should-util": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz", + "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", + "dev": true + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/package.json b/package.json index e02c567..168850b 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,10 @@ { - "name": "node-dir", + "name": "path-reader", "version": "0.1.19", "description": "asynchronous file and directory operations for Node.js", "main": "index", - "homepage": "https://github.com/fshost", - "repository": "https://github.com/fshost/node-dir", - "author": { - "name": "Nathan Cartwright", - "email": "fshost@yahoo.com", - "url": "https://github.com/fshost" - }, + "homepage": "https://github.com/ackerapple", + "repository": "https://github.com/ackerapple/path-reader", "directories": { "lib": "lib" }, @@ -21,7 +16,7 @@ }, "license": "MIT", "keywords": [ - "node-dir", + "path-reader", "directory", "dir", "subdir", @@ -31,10 +26,10 @@ "fs" ], "dependencies": { - "minimatch": "^3.0.2" + "minimatch": "^3.0.4" }, "devDependencies": { - "mocha": "~1.13.0", - "should": "~2.0.2" + "mocha": "3.5.0", + "should": "11.2.1" } } From d3727352631825f576d41642042f87a46f3e33f7 Mon Sep 17 00:00:00 2001 From: ackerapple Date: Wed, 9 Aug 2017 10:03:36 -0400 Subject: [PATCH 23/37] ready for npm publish --- .gitignore | 5 ++--- LICENSE.txt | 2 -- README.md | 8 ++++---- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 2259192..03ed6f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .DS_Store - +updaters npm-debug.log - -node_modules +node_modules \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt index 97445a0..5821128 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,7 +1,5 @@ (The MIT License) -Copyright (c) 2012 Nathan Cartwright - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including diff --git a/README.md b/README.md index 00b5d28..538674c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -[![Build Status](https://secure.travis-ci.org/fshost/node-dir.svg)](http://travis-ci.org/fshost/node-dir) +[![Build Status](https://secure.travis-ci.org/ackerapple/path-reader.svg)](http://travis-ci.org/ackerapple/path-reader) -# node-dir +# path-reader 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. ### Table of Contents @@ -23,7 +23,7 @@ A lightweight Node.js module with methods for some common directory and file ope #### installation - npm install node-dir + npm install path-reader ### usage @@ -31,7 +31,7 @@ A lightweight Node.js module with methods for some common directory and file ope For the sake of brevity, assume that the following line of code precedes all of the examples. ```javascript -var dir = require('node-dir'); +var dir = require('path-reader'); ``` #### readFiles From e87f23318046285b33b4403f7c62aa1528fb1a40 Mon Sep 17 00:00:00 2001 From: ackerapple Date: Wed, 9 Aug 2017 10:04:03 -0400 Subject: [PATCH 24/37] full version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 168850b..9f7503b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "path-reader", - "version": "0.1.19", + "version": "1.0.0", "description": "asynchronous file and directory operations for Node.js", "main": "index", "homepage": "https://github.com/ackerapple", From 7cebf5113e48d179de38eb54b31a326f358d7a49 Mon Sep 17 00:00:00 2001 From: ackerapple Date: Wed, 9 Aug 2017 10:12:45 -0400 Subject: [PATCH 25/37] x --- README.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 538674c..e4ce4d0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://secure.travis-ci.org/ackerapple/path-reader.svg)](http://travis-ci.org/ackerapple/path-reader) +[![Build Status](https://secure.travis-ci.org/ackerapple/node-dir.svg)](http://travis-ci.org/ackerapple/node-dir) # path-reader 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. diff --git a/package.json b/package.json index 9f7503b..3e6acb2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "path-reader", - "version": "1.0.0", + "version": "1.0.1", "description": "asynchronous file and directory operations for Node.js", "main": "index", "homepage": "https://github.com/ackerapple", From a0a62b007280933626cabd0d40db35d36b2873f8 Mon Sep 17 00:00:00 2001 From: ackerapple Date: Wed, 9 Aug 2017 10:14:34 -0400 Subject: [PATCH 26/37] fix badge --- README.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e4ce4d0..9da055e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://secure.travis-ci.org/ackerapple/node-dir.svg)](http://travis-ci.org/ackerapple/node-dir) +[![Build Status](https://secure.travis-ci.org/AckerApple/node-dir.svg)](http://travis-ci.org/AckerApple/node-dir) # path-reader 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. diff --git a/package.json b/package.json index 3e6acb2..a5f6b7a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "path-reader", - "version": "1.0.1", + "version": "1.0.2", "description": "asynchronous file and directory operations for Node.js", "main": "index", "homepage": "https://github.com/ackerapple", From 3eba375c1ea3bf4e6fc863e370154ad5371b06e5 Mon Sep 17 00:00:00 2001 From: ackerapple Date: Wed, 9 Aug 2017 10:19:38 -0400 Subject: [PATCH 27/37] x --- README.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9da055e..71f3413 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ [![Build Status](https://secure.travis-ci.org/AckerApple/node-dir.svg)](http://travis-ci.org/AckerApple/node-dir) +[![Build status](https://ci.appveyor.com/api/projects/status/aad8t55ury0ijhe1?svg=true)](https://ci.appveyor.com/project/AckerApple/node-dir) +[![NPM version](https://img.shields.io/npm/v/path-reader.svg?style=flat-square)](https://www.npmjs.com/package/path-reader) # path-reader 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. diff --git a/package.json b/package.json index a5f6b7a..155dbaa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "path-reader", - "version": "1.0.2", + "version": "1.0.3", "description": "asynchronous file and directory operations for Node.js", "main": "index", "homepage": "https://github.com/ackerapple", From 09ca72d4adc0dea55f4075a19758772b25163c5f Mon Sep 17 00:00:00 2001 From: ackerapple Date: Thu, 10 Aug 2017 13:47:54 -0400 Subject: [PATCH 28/37] badges --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 71f3413..34cb8a3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![Build Status](https://secure.travis-ci.org/AckerApple/node-dir.svg)](http://travis-ci.org/AckerApple/node-dir) -[![Build status](https://ci.appveyor.com/api/projects/status/aad8t55ury0ijhe1?svg=true)](https://ci.appveyor.com/project/AckerApple/node-dir) +[![Build Status](https://secure.travis-ci.org/AckerApple/path-reader.svg)](http://travis-ci.org/AckerApple/path-reader) +[![Build status](https://ci.appveyor.com/api/projects/status/6sa5pfcsrix5s8va?svg=true)](https://ci.appveyor.com/project/AckerApple/path-reader) [![NPM version](https://img.shields.io/npm/v/path-reader.svg?style=flat-square)](https://www.npmjs.com/package/path-reader) # path-reader @@ -21,6 +21,7 @@ A lightweight Node.js module with methods for some common directory and file ope - [API Docs](#api-docs) - [files](#files-api) - [promiseFiles](#promisefiles-api) +- [History](#history) - [License](#license) #### installation @@ -283,5 +284,8 @@ promiseFiles(dir, type||options, options) - **shortName**=false||'relative' - instead of fullpath file names, just get the names or relative item names - **recursive**=true - traverse through all children of given path +## History +path-reader is a fork of node-dir. The original maintainer of node-dir, @fshost, has not updated nor been heard from in some time. Use path-reader, it is far superior to node-dir. + ## License MIT licensed (See LICENSE.txt) From 1927d64bb0a605b488bb8873275a70056635e778 Mon Sep 17 00:00:00 2001 From: ackerapple Date: Thu, 10 Aug 2017 13:48:14 -0400 Subject: [PATCH 29/37] v --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 155dbaa..844ab42 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "path-reader", - "version": "1.0.3", + "version": "1.0.4", "description": "asynchronous file and directory operations for Node.js", "main": "index", "homepage": "https://github.com/ackerapple", From ec0a3da9d04fdb99ea262bbf1a6bae15530392e1 Mon Sep 17 00:00:00 2001 From: ackerapple Date: Fri, 13 Oct 2017 22:40:24 -0400 Subject: [PATCH 30/37] fix empty folders --- CHANGELOG.json | 7 + lib/paths.js | 7 +- lib/readfiles.js | 178 +- package-lock.json | 2 +- package.json | 2 +- "test/fixtures/testdir5/testu\347\365es.txt" | 1 - test/test.js | 2613 +++++++++--------- 7 files changed, 1426 insertions(+), 1384 deletions(-) create mode 100644 CHANGELOG.json delete mode 100644 "test/fixtures/testdir5/testu\347\365es.txt" diff --git a/CHANGELOG.json b/CHANGELOG.json new file mode 100644 index 0000000..0677734 --- /dev/null +++ b/CHANGELOG.json @@ -0,0 +1,7 @@ +# path-reader - Change Log +All notable changes to this project will be documented here. + +## [1.0.5] - 2017-10-13 +### Fixed +- empty folder reads are now empty array instead of undefined + diff --git a/lib/paths.js b/lib/paths.js index 27e6d1b..efd06b6 100644 --- a/lib/paths.js +++ b/lib/paths.js @@ -151,9 +151,12 @@ exports.files = function files(dir, type, callback, options) { const onDirRead = function(err, list) { if (err) return callback(err); - + pending = list.length; - if (!pending) return done(); + if (!pending){ + done(list); + return list + } var statHanOptions = {} if(options.shortName){ diff --git a/lib/readfiles.js b/lib/readfiles.js index 20db44c..c45ae1b 100644 --- a/lib/readfiles.js +++ b/lib/readfiles.js @@ -1,5 +1,5 @@ var fs = require('fs'), - path = require('path'); + path = require('path'); /** * merge two objects by extending target object with source object @@ -9,14 +9,14 @@ var fs = require('fs'), * @returns {Object} extended object */ function extend(target, source, modify) { - var result = target ? modify ? target : extend({}, target, true) : {}; - if (!source) return result; - for (var key in source) { - if (source.hasOwnProperty(key) && source[key] !== undefined) { - result[key] = source[key]; - } + var result = target ? modify ? target : extend({}, target, true) : {}; + if (!source) return result; + for (var key in source) { + if (source.hasOwnProperty(key) && source[key] !== undefined) { + result[key] = source[key]; } - return result; + } + return result; } /** @@ -26,8 +26,8 @@ function extend(target, source, modify) { * @returns {Boolean} whether there is a match */ function matches(str, match) { - if (Array.isArray(match)) return match.indexOf(str) > -1; - return match.test(str); + if (Array.isArray(match)) return match.indexOf(str) > -1; + return match.test(str); } /** @@ -39,84 +39,96 @@ function matches(str, match) { * @param {Function(error)} complete fn to call when finished */ function readFiles(dir, options, callback, complete) { - if (typeof options === 'function') { - complete = callback; - callback = options; - options = {}; - } - if (typeof options === 'string') options = { - encoding: options - }; - options = extend({ - recursive: true, - encoding: 'utf8', - doneOnErr: true - }, options); - var files = []; + if (typeof options === 'function') { + complete = callback; + callback = options; + options = {}; + } + if (typeof options === 'string') options = { + encoding: options + }; + options = extend({ + recursive: true, + encoding: 'utf8', + doneOnErr: true + }, options); + var files = []; - var done = function(err) { - if (typeof complete === 'function') { - if (err) return complete(err); - complete(null, files); - } - }; + var done = function(err) { + if (typeof complete === 'function') { + if (err) return complete(err); + complete(null, files); + } + }; - fs.readdir(dir, function(err, list) { - if (err) { - if (options.doneOnErr === true) { - if (err.code === 'EACCES') return done(); - return done(err); - } - } - var i = 0; + fs.readdir(dir, function(err, list) { + if (err) { + if (options.doneOnErr === true) { + if (err.code === 'EACCES') return done(); + return done(err); + } + } + var i = 0; - if (options.reverse === true || - (typeof options.sort == 'string' && - (/reverse|desc/i).test(options.sort))) { - list = list.reverse(); - } else if (options.sort !== false) list = list.sort(); + if (options.reverse === true || + (typeof options.sort == 'string' && + (/reverse|desc/i).test(options.sort))) { + list = list.reverse(); + } else if (options.sort !== false) list = list.sort(); - (function next() { - var filename = list[i++]; - if (!filename) return done(null, files); - var file = path.join(dir, filename); - fs.stat(file, function(err, stat) { - if (err && options.doneOnErr === true) return done(err); - if (stat && stat.isDirectory()) { - if (options.recursive) { - if (options.matchDir && !matches(filename, options.matchDir)) return next(); - if (options.excludeDir && matches(filename, options.excludeDir)) return next(); - readFiles(file, options, callback, function(err, sfiles) { - if (err && options.doneOnErr === true) return done(err); - files = files.concat(sfiles); - next(); - }); - } else next(); - } else if (stat && stat.isFile()) { - if (options.match && !matches(filename, options.match)) return next(); - if (options.exclude && matches(filename, options.exclude)) return next(); - if (options.filter && !options.filter(filename)) return next(); - if (options.shortName) files.push(filename); - else files.push(file); - fs.readFile(file, options.encoding, function(err, data) { - if (err) { - if (err.code === 'EACCES') return next(); - if (options.doneOnErr === true) { - return done(err); - } - } - if (callback.length > 3) - if (options.shortName) callback(null, data, filename, next); - else callback(null, data, file, next); - else callback(null, data, next); - }); - } - else { - next(); - } + (function next() { + var filename = list[i++]; + if (!filename) return done(null, files); + + var file = path.join(dir, filename); + + fs.stat(file, function(err, stat) { + if (err && options.doneOnErr === true) return done(err); + if (stat && stat.isDirectory()) { + if (options.recursive) { + if (options.matchDir && !matches(filename, options.matchDir)) return next(); + if (options.excludeDir && matches(filename, options.excludeDir)) return next(); + readFiles(file, options, callback, function(err, sfiles) { + if (err && options.doneOnErr === true) return done(err); + files = files.concat(sfiles); + next(); }); - })(); + } else next(); + } else if (stat && stat.isFile()) { + if (options.match && !matches(filename, options.match)) return next(); + if (options.exclude && matches(filename, options.exclude)) return next(); + if (options.filter && !options.filter(filename)) return next(); + + if (options.shortName){ + files.push(filename); + }else{ + files.push(file); + } + + fs.readFile(file, options.encoding, function(err, data) { + if (err) { + if (err.code === 'EACCES') return next(); + if (options.doneOnErr === true) { + return done(err); + } + } + if (callback.length > 3){ + if (options.shortName){ + callback(null, data, filename, next); + }else{ + callback(null, data, file, next); + } + }else{ + callback(null, data, next); + } + }); + } + else { + next(); + } + }); + })(); - }); + }); } module.exports = readFiles; diff --git a/package-lock.json b/package-lock.json index d2ff657..9aad30d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "path-reader", - "version": "0.1.19", + "version": "1.0.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 844ab42..efa82f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "path-reader", - "version": "1.0.4", + "version": "1.0.5", "description": "asynchronous file and directory operations for Node.js", "main": "index", "homepage": "https://github.com/ackerapple", diff --git "a/test/fixtures/testdir5/testu\347\365es.txt" "b/test/fixtures/testdir5/testu\347\365es.txt" deleted file mode 100644 index 5dcd581..0000000 --- "a/test/fixtures/testdir5/testu\347\365es.txt" +++ /dev/null @@ -1 +0,0 @@ -bla \ No newline at end of file diff --git a/test/test.js b/test/test.js index f51fdd0..9a10cbb 100644 --- a/test/test.js +++ b/test/test.js @@ -1,1332 +1,1353 @@ var path = require('path'), - should = require('should'), - dir = require('..'), - fixturesDir = path.join(__dirname, 'fixtures'), - tdir = path.join(fixturesDir, 'testdir'), - tdir2 = path.join(fixturesDir, 'testdir2'), - tdir3 = path.join(fixturesDir, 'testdir3'), - tdir4 = path.join(fixturesDir, 'testdir4'), - tdir5 = path.join(fixturesDir, 'testdir5'), - assert = require('assert'), - isWin = require('os').type()=='Windows_NT', - winIt = isWin ? it.skip : it//skip all symlink based testing + should = require('should'), + dir = require('..'), + fixturesDir = path.join(__dirname, 'fixtures'), + tdir = path.join(fixturesDir, 'testdir'), + tdir2 = path.join(fixturesDir, 'testdir2'), + tdir3 = path.join(fixturesDir, 'testdir3'), + tdir4 = path.join(fixturesDir, 'testdir4'), + tdir5 = path.join(fixturesDir, 'testdir5'), + tdir6 = path.join(fixturesDir, 'testdir6'), + assert = require('assert'), + isWin = require('os').type()=='Windows_NT', + winIt = isWin ? it.skip : it//skip all symlink based testing describe('readfiles method', function() { - it('should pass the contents of every file to a callback', function(done) { - dir.readFiles( - tdir, function(err, content, filename, next) { - should.not.exist(err); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.replace(/\r/g, '').should.equal(expected); - next(); - }, function() { - done(); - }); - }); - - it('should invoke a done callback after processing all files', function(done) { - var filenames = []; - dir.readFiles( - tdir, function(err, content, filename, next) { - should.not.exist(err); - should.exist(content); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - filenames.push(shortName); - next(); - }, function(err, files) { - should.not.exist(err); - files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }).sort().should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); - filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); - done(); - }); - }); - - it('should read files in sorted order if the sort option is set to true', function(done) { - var filenames = []; - dir.readFiles( - tdir, { - sort: true - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - filenames.push(shortName); - content.should.equal(expected); - next(); - }, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); - filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); - done(); - }); - }); - - it('should read files in sorted order (per directory) if the sort option is set to true', function(done) { - var filenames = []; - dir.readFiles( - tdir, { - sort: true - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - filenames.push(shortName); - content.should.equal(expected); - next(); - }, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); - filenames.should.eql(['file1', 'file2', 'file3', 'file4']); - done(); - }); - }); - - it('should read files in reverse order (per directory) if the reverse option is set to true', function(done) { - var filenames = []; - dir.readFiles( - tdir, { - reverse: true - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - filenames.push(shortName); - content.should.equal(expected); - next(); - }, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.should.eql([ - 'testdir'+path.sep+'subdir'+path.sep+'file4.text', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'file1.txt' - ]); - filenames.should.eql(['file4', 'file3', 'file2', 'file1']); - done(); - }); - }); - - it('should apply a filter to the files if a filter option is specified', function(done) { - var filenames = []; - dir.readFiles( - tdir, { - filter: function(filename) { - return~ filename.search('file1') || ~filename.search('file2'); - } - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - filenames.push(shortName); - content.should.equal(expected); - next(); - }, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text' - ]); - filenames.should.eql(['file1', 'file2']); - done(); - }); - }); - - it('should accept an string argument that can specify encoding', function(done) { - var filenames = []; - dir.readFiles( - tdir, 'ascii', function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); - done(); - }); - }); - - it('should accept an options argument that can specify encoding', function(done) { - var filenames = []; - dir.readFiles( - tdir, { - encoding: 'ascii' - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); - done(); - }); - }); - - it('if shortName option is true, only aggregate the base filename rather than the full filepath', function(done) { - var filenames = []; - dir.readFiles( - tdir, { - shortName: true - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - path.basename(filename).should.equal(filename); - var shortName = filename.replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(filename); - next(); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file1.txt', 'file2.text', 'file3.txt', 'file4.text']); - done(); - }); - }); - - it('if recursive option is set to false, should not read files in subdirectories', function(done) { - var filenames = []; - dir.readFiles( - tdir, { - recursive: false - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - filenames.push(shortName); - content.should.equal(expected); - next(); - }, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.sort().should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text' - ]); - filenames.sort().should.eql(['file1', 'file2']); - done(); - }); - }); - - it('if given a match regex option, should only read files that match it', function(done) { - var filenames = []; - dir.readFiles( - tdir, { - match: /txt$/ - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file1', 'file3']); - done(); - }); - }); - - it('if given a match array option, should only read files that match an item in the array', function(done) { - var filenames = []; - dir.readFiles( - tdir, { - match: ['file1.txt', 'file3.txt'] - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file1', 'file3']); - done(); - }); - }); - - it('match option should match regex pattern only to the filename itself, not the full filepath', function(done) { - var filenames = []; - dir.readFiles( - tdir, { - match: /^file/ - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - filenames.push(shortName); - content.should.equal(expected); - next(); - }, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.sort().should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); - filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); - done(); - }); - }); - - it('if given an exclude regex option, should only read files that do not match the exclude pattern', function(done) { - var filenames = []; - dir.readFiles( - tdir, { - exclude: /text$/ - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file1', 'file3']); - done(); - }); - }); - - it('if given an exclude array option, should only read files that do not match any items in the array', function(done) { - var filenames = []; - dir.readFiles( - tdir, { - exclude: ['file2.text', 'file4.text'] - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file1', 'file3']); - done(); - }); - }); - - it('if given a matchDir regex option, should only read files in subdirectories that match it', function(done) { - var filenames = []; - dir.readFiles( - tdir2, { - matchDir: /special/i - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file3', 'file4']); - done(); - }); - }); - - it('if given a matchDir array option, should only read files in subdirectories that match an item in the array', function(done) { - var filenames = []; - dir.readFiles( - tdir2, { - matchDir: ['special_files', 'nonexistent'] - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file3', 'file4']); - done(); - }); - }); - - it('if given an excludeDir regex option, should only read files that are not in subdirectories that match the exclude pattern', function(done) { - var filenames = []; - dir.readFiles( - tdir2, { - excludeDir: /^\./ - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file2', 'file3', 'file4']); - done(); - }); - }); - - it('if given an excludeDir array option, should only read files that are in subdirectories that do not match any item in the array', function(done) { - var filenames = []; - dir.readFiles( - tdir2, { - excludeDir: ['.bin', '.nonexistent'] - }, function(err, content, filename, next) { - should.not.exist(err); - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file2', 'file3', 'file4']); - done(); - }); - }); - - winIt('should done on error', function(done) { - dir.readFiles( - tdir3, function(err, content, filename, next) { - if(filename.split(path.sep).pop()!='file1.txt')return next() - should.not.exist(err); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.replace(/\r/g, '').should.equal(expected); - next(); - }, function(err) { - should.exist(err); - done(); - }); - }); - - it('if given doneOnErr to false, should not done on error', function(done) { - dir.readFiles( - tdir3, { doneOnErr: false },function(err, content, filename, next) { - if(filename.split(path.sep).pop()!='file1.txt')return next() - should.not.exist(err); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.replace(/\r/g, '').should.equal(expected); - next(); - }, function() { - done(); - }); - }); - - it('can be called with a callback in which the filename argument is omitted', function(done) { - dir.readFiles( - tdir, function(err, content, next) { - should.not.exist(err); - content.should.be.a.string; - content.indexOf('begin content of').should.equal(0); - next(); - }, function(err) { - should.not.exist(err); - done(); - }); - }); - - it('can be called with the done callback argument omitted', function(done) { - var i = 0; - dir.readFiles( - tdir, function(err, content, next) { - should.not.exist(err); - next(); - i++; - if (i === 4) done(); - }); - }); + it('should pass the contents of every file to a callback', function(done) { + dir.readFiles( + tdir, function(err, content, filename, next) { + should.not.exist(err); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.replace(/\r/g, '').should.equal(expected); + next(); + }, function() { + done(); + }); + }); + + it('should invoke a done callback after processing all files', function(done) { + var filenames = []; + dir.readFiles( + tdir, function(err, content, filename, next) { + should.not.exist(err); + should.exist(content); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + filenames.push(shortName); + next(); + }, function(err, files) { + should.not.exist(err); + files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }).sort().should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' + ]); + filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); + done(); + }); + }); + + it('should read files in sorted order if the sort option is set to true', function(done) { + var filenames = []; + dir.readFiles( + tdir, { + sort: true + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + filenames.push(shortName); + content.should.equal(expected); + next(); + }, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' + ]); + filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); + done(); + }); + }); + + it('should read files in sorted order (per directory) if the sort option is set to true', function(done) { + var filenames = []; + dir.readFiles( + tdir, { + sort: true + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + filenames.push(shortName); + content.should.equal(expected); + next(); + }, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' + ]); + filenames.should.eql(['file1', 'file2', 'file3', 'file4']); + done(); + }); + }); + + it('should read files in reverse order (per directory) if the reverse option is set to true', function(done) { + var filenames = []; + dir.readFiles( + tdir, { + reverse: true + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + filenames.push(shortName); + content.should.equal(expected); + next(); + }, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.should.eql([ + 'testdir'+path.sep+'subdir'+path.sep+'file4.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'file1.txt' + ]); + filenames.should.eql(['file4', 'file3', 'file2', 'file1']); + done(); + }); + }); + + it('should apply a filter to the files if a filter option is specified', function(done) { + var filenames = []; + dir.readFiles( + tdir, { + filter: function(filename) { + return~ filename.search('file1') || ~filename.search('file2'); + } + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + filenames.push(shortName); + content.should.equal(expected); + next(); + }, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text' + ]); + filenames.should.eql(['file1', 'file2']); + done(); + }); + }); + + it('should accept an string argument that can specify encoding', function(done) { + var filenames = []; + dir.readFiles( + tdir, 'ascii', function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); + done(); + }); + }); + + it('should accept an options argument that can specify encoding', function(done) { + var filenames = []; + dir.readFiles( + tdir, { + encoding: 'ascii' + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); + done(); + }); + }); + + it('if shortName option is true, only aggregate the base filename rather than the full filepath', function(done) { + var filenames = []; + dir.readFiles( + tdir, { + shortName: true + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + path.basename(filename).should.equal(filename); + var shortName = filename.replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(filename); + next(); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file1.txt', 'file2.text', 'file3.txt', 'file4.text']); + done(); + }); + }); + + it('if recursive option is set to false, should not read files in subdirectories', function(done) { + var filenames = []; + dir.readFiles( + tdir, { + recursive: false + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + filenames.push(shortName); + content.should.equal(expected); + next(); + }, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.sort().should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text' + ]); + filenames.sort().should.eql(['file1', 'file2']); + done(); + }); + }); + + it('if given a match regex option, should only read files that match it', function(done) { + var filenames = []; + dir.readFiles( + tdir, { + match: /txt$/ + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file1', 'file3']); + done(); + }); + }); + + it('if given a match array option, should only read files that match an item in the array', function(done) { + var filenames = []; + dir.readFiles( + tdir, { + match: ['file1.txt', 'file3.txt'] + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file1', 'file3']); + done(); + }); + }); + + it('match option should match regex pattern only to the filename itself, not the full filepath', function(done) { + var filenames = []; + dir.readFiles( + tdir, { + match: /^file/ + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + filenames.push(shortName); + content.should.equal(expected); + next(); + }, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.sort().should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' + ]); + filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); + done(); + }); + }); + + it('if given an exclude regex option, should only read files that do not match the exclude pattern', function(done) { + var filenames = []; + dir.readFiles( + tdir, { + exclude: /text$/ + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file1', 'file3']); + done(); + }); + }); + + it('if given an exclude array option, should only read files that do not match any items in the array', function(done) { + var filenames = []; + dir.readFiles( + tdir, { + exclude: ['file2.text', 'file4.text'] + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file1', 'file3']); + done(); + }); + }); + + it('if given a matchDir regex option, should only read files in subdirectories that match it', function(done) { + var filenames = []; + dir.readFiles( + tdir2, { + matchDir: /special/i + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file3', 'file4']); + done(); + }); + }); + + it('if given a matchDir array option, should only read files in subdirectories that match an item in the array', function(done) { + var filenames = []; + dir.readFiles( + tdir2, { + matchDir: ['special_files', 'nonexistent'] + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file3', 'file4']); + done(); + }); + }); + + it('if given an excludeDir regex option, should only read files that are not in subdirectories that match the exclude pattern', function(done) { + var filenames = []; + dir.readFiles( + tdir2, { + excludeDir: /^\./ + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file2', 'file3', 'file4']); + done(); + }); + }); + + it('if given an excludeDir array option, should only read files that are in subdirectories that do not match any item in the array', function(done) { + var filenames = []; + dir.readFiles( + tdir2, { + excludeDir: ['.bin', '.nonexistent'] + }, function(err, content, filename, next) { + should.not.exist(err); + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file2', 'file3', 'file4']); + done(); + }); + }); + + winIt('should done on error', function(done) { + dir.readFiles( + tdir3, function(err, content, filename, next) { + if(filename.split(path.sep).pop()!='file1.txt')return next() + should.not.exist(err); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.replace(/\r/g, '').should.equal(expected); + next(); + }, function(err) { + should.exist(err); + done(); + }); + }); + + it('if given doneOnErr to false, should not done on error', function(done) { + dir.readFiles( + tdir3, { doneOnErr: false },function(err, content, filename, next) { + if(filename.split(path.sep).pop()!='file1.txt')return next() + should.not.exist(err); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.replace(/\r/g, '').should.equal(expected); + next(); + }, function() { + done(); + }); + }); + + it('can be called with a callback in which the filename argument is omitted', function(done) { + dir.readFiles( + tdir, function(err, content, next) { + should.not.exist(err); + content.should.be.a.string; + content.indexOf('begin content of').should.equal(0); + next(); + }, function(err) { + should.not.exist(err); + done(); + }); + }); + + it('can be called with the done callback argument omitted', function(done) { + var i = 0; + dir.readFiles( + tdir, function(err, content, next) { + should.not.exist(err); + next(); + i++; + if (i === 4) done(); + }); + }); }); describe('readfilesstream method', function() { - it('should pass the stream of every file to a callback', function(done) { - dir.readFilesStream( - tdir, function(err, stream, filename, next) { - should.not.exist(err); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content.replace(/\r/g, '').should.equal(expected); - next(); - }); - - }, function() { - done(); - }); - }); - it('should invoke a done callback after processing all files', function(done) { - var filenames = []; - dir.readFilesStream( - tdir, function(err, stream, filename, next) { - should.not.exist(err); - should.exist(stream); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - filenames.push(shortName); - next(); - }, function(err, files) { - should.not.exist(err); - files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }).sort().should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); - filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); - done(); - }); - }); - - it('should read files in sorted order if the sort option is set to true', function(done) { - var filenames = []; - dir.readFilesStream( - tdir, { - sort: true - }, function(err, stream, filename, next) { - should.not.exist(err); - //content = content.replace(/\r/g, ''); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - filenames.push(shortName); - content.should.equal(expected); - next(); - }); - }, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); - filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); - done(); - }); - }); - - it('should read files in sorted order (per directory) if the sort option is set to true', function(done) { - var filenames = []; - dir.readFilesStream( - tdir, { - sort: true - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - filenames.push(shortName); - content.should.equal(expected); - next(); - }); - }, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); - filenames.should.eql(['file1', 'file2', 'file3', 'file4']); - done(); - }); - }); - - it('should read files in reverse order (per directory) if the reverse option is set to true', function(done) { - var filenames = []; - dir.readFilesStream( - tdir, { - reverse: true - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - filenames.push(shortName); - content.should.equal(expected); - next(); - }); - }, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.should.eql([ - 'testdir'+path.sep+'subdir'+path.sep+'file4.text', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'file1.txt' - ]); - filenames.should.eql(['file4', 'file3', 'file2', 'file1']); - done(); - }); - }); - - it('should apply a filter to the files if a filter option is specified', function(done) { - var filenames = []; - dir.readFilesStream( - tdir, { - filter: function(filename) { - return~ filename.search('file1') || ~filename.search('file2'); - } - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - filenames.push(shortName); - content.should.equal(expected); - next(); - }); - }, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text' - ]); - filenames.should.eql(['file1', 'file2']); - done(); - }); - }); - - it('should accept an string argument that can specify encoding', function(done) { - var filenames = []; - dir.readFilesStream( - tdir, 'ascii', function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); - done(); - }); - }); - - it('should accept an options argument that can specify encoding', function(done) { - var filenames = []; - dir.readFilesStream( - tdir, { - encoding: 'ascii' - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); - done(); - }); - }); - - it('if shortName option is true, only aggregate the base filename rather than the full filepath', function(done) { - var filenames = []; - dir.readFilesStream( - tdir, { - shortName: true - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - path.basename(filename).should.equal(filename); - var shortName = filename.replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(filename); - next(); - }); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file1.txt', 'file2.text', 'file3.txt', 'file4.text']); - done(); - }); - }); - - it('if recursive option is set to false, should not read files in subdirectories', function(done) { - var filenames = []; - dir.readFilesStream( - tdir, { - recursive: false - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - filenames.push(shortName); - content.should.equal(expected); - next(); - }); - }, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.sort().should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text' - ]); - filenames.sort().should.eql(['file1', 'file2']); - done(); - }); - }); - - it('if given a match regex option, should only read files that match it', function(done) { - var filenames = []; - dir.readFilesStream( - tdir, { - match: /txt$/ - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file1', 'file3']); - done(); - }); - }); - - it('if given a match array option, should only read files that match an item in the array', function(done) { - var filenames = []; - dir.readFilesStream( - tdir, { - match: ['file1.txt', 'file3.txt'] - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file1', 'file3']); - done(); - }); - }); - - it('match option should match regex pattern only to the filename itself, not the full filepath', function(done) { - var filenames = []; - dir.readFilesStream( - tdir, { - match: /^file/ - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - filenames.push(shortName); - content.should.equal(expected); - next(); - }); - }, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.sort().should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); - filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); - done(); - }); - }); - - it('if given an exclude regex option, should only read files that do not match the exclude pattern', function(done) { - var filenames = []; - dir.readFilesStream( - tdir, { - exclude: /text$/ - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file1', 'file3']); - done(); - }); - }); - - it('if given an exclude array option, should only read files that do not match any items in the array', function(done) { - var filenames = []; - dir.readFilesStream( - tdir, { - exclude: ['file2.text', 'file4.text'] - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file1', 'file3']); - done(); - }); - }); - - it('if given a matchDir regex option, should only read files in subdirectories that match it', function(done) { - var filenames = []; - dir.readFilesStream( - tdir2, { - matchDir: /special/i - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file3', 'file4']); - done(); - }); - }); - - it('if given a matchDir array option, should only read files in subdirectories that match an item in the array', function(done) { - var filenames = []; - dir.readFilesStream( - tdir2, { - matchDir: ['special_files', 'nonexistent'] - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file3', 'file4']); - done(); - }); - }); - - it('if given an excludeDir regex option, should only read files that are not in subdirectories that match the exclude pattern', function(done) { - var filenames = []; - dir.readFilesStream( - tdir2, { - excludeDir: /^\./ - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file2', 'file3', 'file4']); - done(); - }); - }); - - it('if given an excludeDir array option, should only read files that are in subdirectories that do not match any item in the array', function(done) { - var filenames = []; - dir.readFilesStream( - tdir2, { - excludeDir: ['.bin', '.nonexistent'] - }, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }); - }, function(err, files) { - should.not.exist(err); - filenames.sort().should.eql(['file2', 'file3', 'file4']); - done(); - }); - }); - - winIt('should done on error', function(done) { - dir.readFilesStream( - tdir3, function(err, stream, filename, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content = content.replace(/\r/g, ''); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - content.should.equal(expected); - filenames.push(shortName); - next(); - }); - }, function(err) { - should.exist(err); - done(); - }); - }); - - it('if given doneOnErr to false, should not done on error', function(done) { - dir.readFilesStream( - tdir3, { doneOnErr: false },function(err, stream, filename, next) { - if(filename.split(path.sep).pop()!='file1.txt')return next() - should.not.exist(err); - var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); - var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content.replace(/\r/g, '').should.equal(expected); - next(); - }); - }, function() { - done(); - }); - }); - - it('can be called with a callback in which the filename argument is omitted', function(done) { - dir.readFilesStream( - tdir, function(err, stream, next) { - should.not.exist(err); - var content = ''; - stream.on('data',function(buffer) { - var part = buffer.toString(); - content += part; - }); - stream.on('end',function() { - content.should.be.a.string; - content.indexOf('begin content of').should.equal(0); - next(); - }); - }, function(err) { - should.not.exist(err); - done(); - }); - }); - - it('can be called with the done callback argument omitted', function(done) { - var i = 0; - dir.readFilesStream( - tdir, function(err, stream, next) { - should.not.exist(err); - next(); - i++; - if (i === 4) done(); - }); - }); + it('should pass the stream of every file to a callback', function(done) { + dir.readFilesStream( + tdir, function(err, stream, filename, next) { + should.not.exist(err); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content.replace(/\r/g, '').should.equal(expected); + next(); + }); + + }, function() { + done(); + }); + }); + it('should invoke a done callback after processing all files', function(done) { + var filenames = []; + dir.readFilesStream( + tdir, function(err, stream, filename, next) { + should.not.exist(err); + should.exist(stream); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + filenames.push(shortName); + next(); + }, function(err, files) { + should.not.exist(err); + files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }).sort().should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' + ]); + filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); + done(); + }); + }); + + it('should read files in sorted order if the sort option is set to true', function(done) { + var filenames = []; + dir.readFilesStream( + tdir, { + sort: true + }, function(err, stream, filename, next) { + should.not.exist(err); + //content = content.replace(/\r/g, ''); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + filenames.push(shortName); + content.should.equal(expected); + next(); + }); + }, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' + ]); + filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); + done(); + }); + }); + + it('should read files in sorted order (per directory) if the sort option is set to true', function(done) { + var filenames = []; + dir.readFilesStream( + tdir, { + sort: true + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + filenames.push(shortName); + content.should.equal(expected); + next(); + }); + }, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' + ]); + filenames.should.eql(['file1', 'file2', 'file3', 'file4']); + done(); + }); + }); + + it('should read files in reverse order (per directory) if the reverse option is set to true', function(done) { + var filenames = []; + dir.readFilesStream( + tdir, { + reverse: true + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + filenames.push(shortName); + content.should.equal(expected); + next(); + }); + }, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.should.eql([ + 'testdir'+path.sep+'subdir'+path.sep+'file4.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'file1.txt' + ]); + filenames.should.eql(['file4', 'file3', 'file2', 'file1']); + done(); + }); + }); + + it('should apply a filter to the files if a filter option is specified', function(done) { + var filenames = []; + dir.readFilesStream( + tdir, { + filter: function(filename) { + return~ filename.search('file1') || ~filename.search('file2'); + } + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + filenames.push(shortName); + content.should.equal(expected); + next(); + }); + }, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text' + ]); + filenames.should.eql(['file1', 'file2']); + done(); + }); + }); + + it('should accept an string argument that can specify encoding', function(done) { + var filenames = []; + dir.readFilesStream( + tdir, 'ascii', function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); + done(); + }); + }); + + it('should accept an options argument that can specify encoding', function(done) { + var filenames = []; + dir.readFilesStream( + tdir, { + encoding: 'ascii' + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); + done(); + }); + }); + + it('if shortName option is true, only aggregate the base filename rather than the full filepath', function(done) { + var filenames = []; + dir.readFilesStream( + tdir, { + shortName: true + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + path.basename(filename).should.equal(filename); + var shortName = filename.replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(filename); + next(); + }); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file1.txt', 'file2.text', 'file3.txt', 'file4.text']); + done(); + }); + }); + + it('if recursive option is set to false, should not read files in subdirectories', function(done) { + var filenames = []; + dir.readFilesStream( + tdir, { + recursive: false + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + filenames.push(shortName); + content.should.equal(expected); + next(); + }); + }, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.sort().should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text' + ]); + filenames.sort().should.eql(['file1', 'file2']); + done(); + }); + }); + + it('if given a match regex option, should only read files that match it', function(done) { + var filenames = []; + dir.readFilesStream( + tdir, { + match: /txt$/ + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file1', 'file3']); + done(); + }); + }); + + it('if given a match array option, should only read files that match an item in the array', function(done) { + var filenames = []; + dir.readFilesStream( + tdir, { + match: ['file1.txt', 'file3.txt'] + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file1', 'file3']); + done(); + }); + }); + + it('match option should match regex pattern only to the filename itself, not the full filepath', function(done) { + var filenames = []; + dir.readFilesStream( + tdir, { + match: /^file/ + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + filenames.push(shortName); + content.should.equal(expected); + next(); + }); + }, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.sort().should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' + ]); + filenames.sort().should.eql(['file1', 'file2', 'file3', 'file4']); + done(); + }); + }); + + it('if given an exclude regex option, should only read files that do not match the exclude pattern', function(done) { + var filenames = []; + dir.readFilesStream( + tdir, { + exclude: /text$/ + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file1', 'file3']); + done(); + }); + }); + + it('if given an exclude array option, should only read files that do not match any items in the array', function(done) { + var filenames = []; + dir.readFilesStream( + tdir, { + exclude: ['file2.text', 'file4.text'] + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file1', 'file3']); + done(); + }); + }); + + it('if given a matchDir regex option, should only read files in subdirectories that match it', function(done) { + var filenames = []; + dir.readFilesStream( + tdir2, { + matchDir: /special/i + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file3', 'file4']); + done(); + }); + }); + + it('if given a matchDir array option, should only read files in subdirectories that match an item in the array', function(done) { + var filenames = []; + dir.readFilesStream( + tdir2, { + matchDir: ['special_files', 'nonexistent'] + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file3', 'file4']); + done(); + }); + }); + + it('if given an excludeDir regex option, should only read files that are not in subdirectories that match the exclude pattern', function(done) { + var filenames = []; + dir.readFilesStream( + tdir2, { + excludeDir: /^\./ + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file2', 'file3', 'file4']); + done(); + }); + }); + + it('if given an excludeDir array option, should only read files that are in subdirectories that do not match any item in the array', function(done) { + var filenames = []; + dir.readFilesStream( + tdir2, { + excludeDir: ['.bin', '.nonexistent'] + }, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }); + }, function(err, files) { + should.not.exist(err); + filenames.sort().should.eql(['file2', 'file3', 'file4']); + done(); + }); + }); + + winIt('should done on error', function(done) { + dir.readFilesStream( + tdir3, function(err, stream, filename, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content = content.replace(/\r/g, ''); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + content.should.equal(expected); + filenames.push(shortName); + next(); + }); + }, function(err) { + should.exist(err); + done(); + }); + }); + + it('if given doneOnErr to false, should not done on error', function(done) { + dir.readFilesStream( + tdir3, { doneOnErr: false },function(err, stream, filename, next) { + if(filename.split(path.sep).pop()!='file1.txt')return next() + should.not.exist(err); + var shortName = path.basename(filename).replace(new RegExp(path.extname(filename) + '$'), ''); + var expected = 'begin content of ' + shortName + '\ncontent body\nend content of ' + shortName; + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content.replace(/\r/g, '').should.equal(expected); + next(); + }); + }, function() { + done(); + }); + }); + + it('can be called with a callback in which the filename argument is omitted', function(done) { + dir.readFilesStream( + tdir, function(err, stream, next) { + should.not.exist(err); + var content = ''; + stream.on('data',function(buffer) { + var part = buffer.toString(); + content += part; + }); + stream.on('end',function() { + content.should.be.a.string; + content.indexOf('begin content of').should.equal(0); + next(); + }); + }, function(err) { + should.not.exist(err); + done(); + }); + }); + + it('can be called with the done callback argument omitted', function(done) { + var i = 0; + dir.readFilesStream( + tdir, function(err, stream, next) { + should.not.exist(err); + next(); + i++; + if (i === 4) done(); + }); + }); }); describe('#promiseFiles',function(){ - it("#promiseFiles", function(done) { - dir.promiseFiles(tdir) - .then(function(files) { - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.sort().should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); - }) - .then(done).catch(done) - }); - - it("#promiseFiles(path, {shortName:true})", function(done) { - dir.promiseFiles(tdir, {shortName:true}) - .then(function(files) { - assert.deepEqual(files.sort(), [ - 'file1.txt', - 'file2.text', - 'file3.txt', - 'file4.text' - ]) - }) - .then(done).catch(done) - }); - - it("#promiseFiles(path, 'combine', {shortName:true})", function(done) { - dir.promiseFiles(tdir, 'combine', {shortName:true}) - .then(function(files) { - assert.deepEqual(files.sort(), [ - 'file1.txt', - 'file2.text', - 'file3.txt', - 'file4.text', - 'subdir' - ]) - }) - .then(done).catch(done) - }); - - it("#promiseFiles(path, 'combine', {shortName:'relative'})", function(done) { - dir.promiseFiles(tdir, 'combine', {shortName:'relative'}) - .then(function(files) { - assert.deepEqual(files.sort(), [ - 'file1.txt', - 'file2.text', - 'subdir', - 'subdir'+path.sep+'file3.txt', - 'subdir'+path.sep+'file4.text' - ]) - }) - .then(done).catch(done) - }); + it("#promiseFiles", function(done) { + dir.promiseFiles(tdir) + .then(function(files) { + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.sort().should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' + ]); + }) + .then(done).catch(done) + }); + + it("#promiseFiles(path, {shortName:true})", function(done) { + dir.promiseFiles(tdir, {shortName:true}) + .then(function(files) { + assert.deepEqual(files.sort(), [ + 'file1.txt', + 'file2.text', + 'file3.txt', + 'file4.text' + ]) + }) + .then(done).catch(done) + }); + + it("#promiseFiles(path, 'combine', {shortName:true})", function(done) { + dir.promiseFiles(tdir, 'combine', {shortName:true}) + .then(function(files) { + assert.deepEqual(files.sort(), [ + 'file1.txt', + 'file2.text', + 'file3.txt', + 'file4.text', + 'subdir' + ]) + }) + .then(done).catch(done) + }); + + it("#promiseFiles(path, 'combine', {shortName:'relative'})", function(done) { + dir.promiseFiles(tdir, 'combine', {shortName:'relative'}) + .then(function(files) { + assert.deepEqual(files.sort(), [ + 'file1.txt', + 'file2.text', + 'subdir', + 'subdir'+path.sep+'file3.txt', + 'subdir'+path.sep+'file4.text' + ]) + }) + .then(done).catch(done) + }); }) describe("files method", function() { - it("#files(path, {sync:true})", - function() { - var files = dir.files(tdir,'file',function(){},{sync:true}); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - - relFiles.sort().should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); + it("#files(path, {sync:true})", + function() { + var files = dir.files(tdir,'file',function(){},{sync:true}); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); }); - it("should iterate the files of a directory (recursively) and pass their filenames to a callback", function(done) { - dir.files(tdir, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.sort().should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); - done(); - }); + relFiles.sort().should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' + ]); + }); + + it("should iterate the files of a directory (recursively) and pass their filenames to a callback", function(done) { + dir.files(tdir, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.sort().should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' + ]); + done(); }); - - it("should return broken symlinks as files", function(done) { - dir.files(tdir3, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.sort().should.eql([ - 'testdir3'+path.sep+'broken_link.txt', - 'testdir3'+path.sep+'file1.txt' - ]); - done(); - }); + }); + + it("should return broken symlinks as files", function(done) { + dir.files(tdir3, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.sort().should.eql([ + 'testdir3'+path.sep+'broken_link.txt', + 'testdir3'+path.sep+'file1.txt' + ]); + done(); }); - - winIt("should iterate files of symlinked directories (recursively)", function(done) { - dir.files(tdir4, function(err, files) { - should.not.exist(err); - var relFiles = files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - var testArray = [ - 'testdir4'+path.sep+'testdir'+path.sep+'file1.txt', - 'testdir4'+path.sep+'testdir'+path.sep+'file2.text', - 'testdir4'+path.sep+'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir4'+path.sep+'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ] - relFiles.sort().should.eql(testArray); - done(); - }); + }); + + winIt("should iterate files of symlinked directories (recursively)", function(done) { + dir.files(tdir4, function(err, files) { + should.not.exist(err); + var relFiles = files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + var testArray = [ + 'testdir4'+path.sep+'testdir'+path.sep+'file1.txt', + 'testdir4'+path.sep+'testdir'+path.sep+'file2.text', + 'testdir4'+path.sep+'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir4'+path.sep+'testdir'+path.sep+'subdir'+path.sep+'file4.text' + ] + relFiles.sort().should.eql(testArray); + done(); }); - - //NOT supported everywhere - it.skip("support non-UTF8 file names", function() { - var files = dir.files(tdir5,'file', function(){}, {sync:true, excludeHidden:true}); - var cmp = Buffer.from('testdir5'+path.sep+'testuções.txt', 'latin1').toString(); - - var relFile = path.relative(fixturesDir, files[0]) - relFile.should.eql(cmp)//This test does not pass on all Systems - }); + }); + + //NOT supported everywhere. Real hard to get working + it.skip("support non-UTF8 file names", function() { + var files = dir.files(tdir5,'file', function(){}, {sync:true, excludeHidden:true}); + var cmp = Buffer.from('testdir5'+path.sep+'testuções.txt', 'latin1').toString(); + + var relFile = path.relative(fixturesDir, files[0]) + relFile.should.eql(cmp)//This test does not pass on all Systems + }); + + it("empty-folder", function() { + var files = dir.files(tdir6,'file', function(){}, {sync:true, excludeHidden:true}); + assert.equal(files.length, 0) + }); + + it("empty-folder-promise", function(done) { + dir.promiseFiles(tdir6,'file', {excludeHidden:true}) + .then(files=>{ + assert.equal(files.length, 0) + }) + .then(done).catch(done) + }); + + it("empty-folder-callback", function(done) { + dir.files(tdir6,'file', function(err,files){ + if(err)return done(err) + assert.equal(files.length, 0) + done() + }, {excludeHidden:true}) + }); }); - describe('subdirs method', function() { - it('should pass an array of the subdir paths of every subdir in a directory (recursive) to a callback', function(done) { - dir.subdirs(tdir, function(err, dirs) { - should.not.exist(err); - var relPaths = dirs.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relPaths.length.should.equal(1); - relPaths[0].should.equal('testdir'+path.sep+'subdir'); - done(); - }); - + it('should pass an array of the subdir paths of every subdir in a directory (recursive) to a callback', function(done) { + dir.subdirs(tdir, function(err, dirs) { + should.not.exist(err); + var relPaths = dirs.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relPaths.length.should.equal(1); + relPaths[0].should.equal('testdir'+path.sep+'subdir'); + done(); }); + + }); }); describe('paths method', function() { - it('should pass an object with a files property and dirs property of the paths of every file and subdir, respectively, in a directory (recursive) to a callback', function(done) { - dir.paths(tdir, function(err, paths) { - should.not.exist(err); - paths.should.be.a.object; - paths.should.not.be.a.array; - should.exist(paths.files); - should.exist(paths.dirs); - var relFiles = paths.files.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - var relPaths = paths.dirs.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relFiles.sort().should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); - relPaths.length.should.equal(1); - relPaths[0].should.equal('testdir'+path.sep+'subdir'); - done(); - }); + it('should pass an object with a files property and dirs property of the paths of every file and subdir, respectively, in a directory (recursive) to a callback', function(done) { + dir.paths(tdir, function(err, paths) { + should.not.exist(err); + paths.should.be.a.object; + paths.should.not.be.a.array; + should.exist(paths.files); + should.exist(paths.dirs); + var relFiles = paths.files.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + var relPaths = paths.dirs.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relFiles.sort().should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' + ]); + relPaths.length.should.equal(1); + relPaths[0].should.equal('testdir'+path.sep+'subdir'); + done(); }); + }); - describe('when called with combine argument set to true', function() { - - it('should pass an array of filepaths of all subdirs and files in a directory and its subdirs to a callback', function(done) { - dir.paths(tdir, true, function(err, paths) { - should.not.exist(err); - - paths.should.be.a.array; - var relPaths = paths.map(function(curPath) { - return path.relative(fixturesDir, curPath); - }); - relPaths.sort().should.eql([ - 'testdir'+path.sep+'file1.txt', - 'testdir'+path.sep+'file2.text', - 'testdir'+path.sep+'subdir', - 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', - 'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); - }); - done(); - }); + describe('when called with combine argument set to true', function() { + + it('should pass an array of filepaths of all subdirs and files in a directory and its subdirs to a callback', function(done) { + dir.paths(tdir, true, function(err, paths) { + should.not.exist(err); + paths.should.be.a.array; + var relPaths = paths.map(function(curPath) { + return path.relative(fixturesDir, curPath); + }); + relPaths.sort().should.eql([ + 'testdir'+path.sep+'file1.txt', + 'testdir'+path.sep+'file2.text', + 'testdir'+path.sep+'subdir', + 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', + 'testdir'+path.sep+'subdir'+path.sep+'file4.text' + ]); + }); + done(); }); + }); + }); From ab7cbc6b4e3bf00928080bfb23bcef853c31fd09 Mon Sep 17 00:00:00 2001 From: ackerapple Date: Fri, 13 Oct 2017 22:43:52 -0400 Subject: [PATCH 31/37] fix test --- test/test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test.js b/test/test.js index 9a10cbb..598ec85 100644 --- a/test/test.js +++ b/test/test.js @@ -12,6 +12,9 @@ var path = require('path'), isWin = require('os').type()=='Windows_NT', winIt = isWin ? it.skip : it//skip all symlink based testing +//create empty folder +require('fs').mkdirSync( tdir6 ) + describe('readfiles method', function() { it('should pass the contents of every file to a callback', function(done) { From c9a93a2961c4037a17822ca18f4e001803e4fc36 Mon Sep 17 00:00:00 2001 From: ackerapple Date: Fri, 13 Oct 2017 22:45:33 -0400 Subject: [PATCH 32/37] fix test2 --- test/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.js b/test/test.js index 598ec85..ce9fb98 100644 --- a/test/test.js +++ b/test/test.js @@ -1273,7 +1273,7 @@ describe("files method", function() { it("empty-folder-promise", function(done) { dir.promiseFiles(tdir6,'file', {excludeHidden:true}) - .then(files=>{ + .then(function(files){ assert.equal(files.length, 0) }) .then(done).catch(done) From 6ad7deceec9ece4597ecc4ffc7894e836debdaec Mon Sep 17 00:00:00 2001 From: ackerapple Date: Mon, 16 Oct 2017 10:47:28 -0400 Subject: [PATCH 33/37] fixes --- CHANGELOG.json | 3 ++ lib/paths.js | 20 +++++----- package.json | 2 +- test/test.js | 100 ++++++++++++++++++++++++++++++++----------------- 4 files changed, 81 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.json b/CHANGELOG.json index 0677734..414818a 100644 --- a/CHANGELOG.json +++ b/CHANGELOG.json @@ -1,6 +1,9 @@ # path-reader - Change Log All notable changes to this project will be documented here. +## [1.0.6] - 2017-10-13 +- empty folders containing empty items reads are now empty array instead of undefined + ## [1.0.5] - 2017-10-13 ### Fixed - empty folder reads are now empty array instead of undefined diff --git a/lib/paths.js b/lib/paths.js index efd06b6..44ce095 100644 --- a/lib/paths.js +++ b/lib/paths.js @@ -47,11 +47,11 @@ exports.files = function files(dir, type, callback, options) { options = options || {} - var pending, - results = { - files: [], - dirs: [] - }; + var pending + var results = { + files: [], + dirs: [] + }; var done = function() { if(type==='combine'){ @@ -64,7 +64,6 @@ exports.files = function files(dir, type, callback, options) { if(options.sync)return; - callback(null, results); }; @@ -108,10 +107,14 @@ exports.files = function files(dir, type, callback, options) { if(type === 'combine'){ results.files = results.files.concat(res); }else if (type === 'all') { - results.files = results.files.concat(res.files); + if( res.files ){//dont add things that are not there + results.files = results.files.concat(res.files); + } results.dirs = results.dirs.concat(res.dirs); } else if (type === 'file') { - results.files = results.files.concat(res.files); + if( res.files ){//dont add things that are not there + results.files = results.files.concat(res.files); + } } else { results.dirs = results.dirs.concat(res.dirs); } @@ -236,7 +239,6 @@ exports.files = function files(dir, type, callback, options) { * }); */ exports.paths = function paths(dir, combine, callback) { - var type; if (typeof combine === 'function') { diff --git a/package.json b/package.json index efa82f2..0e9be26 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "path-reader", - "version": "1.0.5", + "version": "1.0.6", "description": "asynchronous file and directory operations for Node.js", "main": "index", "homepage": "https://github.com/ackerapple", diff --git a/test/test.js b/test/test.js index ce9fb98..ea94fa4 100644 --- a/test/test.js +++ b/test/test.js @@ -1,19 +1,37 @@ -var path = require('path'), - should = require('should'), - dir = require('..'), - fixturesDir = path.join(__dirname, 'fixtures'), - tdir = path.join(fixturesDir, 'testdir'), - tdir2 = path.join(fixturesDir, 'testdir2'), - tdir3 = path.join(fixturesDir, 'testdir3'), - tdir4 = path.join(fixturesDir, 'testdir4'), - tdir5 = path.join(fixturesDir, 'testdir5'), - tdir6 = path.join(fixturesDir, 'testdir6'), - assert = require('assert'), - isWin = require('os').type()=='Windows_NT', - winIt = isWin ? it.skip : it//skip all symlink based testing - -//create empty folder -require('fs').mkdirSync( tdir6 ) +var fs = require('fs') +var path = require('path') +var should = require('should') +var dir = require('..') +var fixturesDir = path.join(__dirname, 'fixtures') + +var tdir = path.join(fixturesDir, 'testdir') +var tdir2 = path.join(fixturesDir, 'testdir2') +var tdir3 = path.join(fixturesDir, 'testdir3') +var tdir4 = path.join(fixturesDir, 'testdir4') +var tdir5 = path.join(fixturesDir, 'testdir5') +//empty dirs that may not exist +var tdir6 = path.join(fixturesDir, 'testdir6') +var tdir7 = path.join(fixturesDir, 'testdir7') +var tdir8 = path.join(fixturesDir, 'testdir7', 'testdir8') + +var assert = require('assert') +var isWin = require('os').type()=='Windows_NT' +var winIt = isWin ? it.skip : it//skip all symlink based testing + +//param empty folder +function paramDir(pathTo){ + try{ + fs.mkdirSync( pathTo ) + }catch(e){ + if( !e.code || e.code!='EEXIST' ){ + throw e + } + } +} + +paramDir( tdir6 ) +paramDir( tdir7 ) +paramDir( tdir8 ) describe('readfiles method', function() { @@ -1266,28 +1284,42 @@ describe("files method", function() { relFile.should.eql(cmp)//This test does not pass on all Systems }); - it("empty-folder", function() { - var files = dir.files(tdir6,'file', function(){}, {sync:true, excludeHidden:true}); - assert.equal(files.length, 0) - }); - - it("empty-folder-promise", function(done) { - dir.promiseFiles(tdir6,'file', {excludeHidden:true}) - .then(function(files){ - assert.equal(files.length, 0) + describe('empty-folders',function(){ + it("empty-folder", function() { + var files = dir.files(tdir6,'file', function(){}, {sync:true, excludeHidden:true}); + assert.equal(files.length, 0) }) - .then(done).catch(done) - }); - it("empty-folder-callback", function(done) { - dir.files(tdir6,'file', function(err,files){ - if(err)return done(err) + it("folder-with-folder-only", function() { + var files = dir.files(tdir7,'file', function(){}, {sync:true, excludeHidden:true}); assert.equal(files.length, 0) - done() - }, {excludeHidden:true}) - }); -}); + }) + + it("folder-with-folder-only-promise", function(done) { + dir.promiseFiles(tdir7,'file', {excludeHidden:true}) + .then(function(files){ + assert.equal(files.length, 0) + }) + .then(done).catch(done) + }) + + it("empty-folder-promise", function(done) { + dir.promiseFiles(tdir6,'file', {excludeHidden:true}) + .then(function(files){ + assert.equal(files.length, 0) + }) + .then(done).catch(done) + }) + it("empty-folder-callback", function(done) { + dir.files(tdir6,'file', function(err,files){ + if(err)return done(err) + assert.equal(files.length, 0) + done() + }, {excludeHidden:true}) + }) + }) +}) describe('subdirs method', function() { it('should pass an array of the subdir paths of every subdir in a directory (recursive) to a callback', function(done) { From 1b41552e0557dd4b9d48c79c5cd4a7d13d1ad895 Mon Sep 17 00:00:00 2001 From: ackerapple Date: Wed, 14 Feb 2018 10:38:15 -0500 Subject: [PATCH 34/37] path-reader --- CHANGELOG.json => CHANGELOG.md | 4 ++ README.md | 94 ++++++++++++++++++++++------------ lib/paths.js | 42 ++++++++++++++- package.json | 2 +- test/test.js | 35 +++++++++---- 5 files changed, 131 insertions(+), 46 deletions(-) rename CHANGELOG.json => CHANGELOG.md (74%) diff --git a/CHANGELOG.json b/CHANGELOG.md similarity index 74% rename from CHANGELOG.json rename to CHANGELOG.md index 414818a..4dd5598 100644 --- a/CHANGELOG.json +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # path-reader - Change Log All notable changes to this project will be documented here. +## [1.1.0] - 2018-02-14 +- valuetizer option when returns null, item is skipped +- Happy Valentines Day + ## [1.0.6] - 2017-10-13 - empty folders containing empty items reads are now empty array instead of undefined diff --git a/README.md b/README.md index 34cb8a3..f6425ea 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +[![hire me](https://ackerapple.github.io/resume/assets/images/hire-me-badge.svg)](https://ackerapple.github.io/resume/) +[![npm downloads](https://img.shields.io/npm/dm/path-reader.svg)](https://npmjs.org/path-reader) +[![Dependency Status](https://david-dm.org/ackerapple/path-reader.svg)](https://david-dm.org/ackerapple/path-reader) [![Build Status](https://secure.travis-ci.org/AckerApple/path-reader.svg)](http://travis-ci.org/AckerApple/path-reader) [![Build status](https://ci.appveyor.com/api/projects/status/6sa5pfcsrix5s8va?svg=true)](https://ci.appveyor.com/project/AckerApple/path-reader) [![NPM version](https://img.shields.io/npm/v/path-reader.svg?style=flat-square)](https://www.npmjs.com/package/path-reader) @@ -9,24 +12,28 @@ A lightweight Node.js module with methods for some common directory and file ope - [installation](#installation) - [usage](#usage) - - [methods](#methods) - - [readFiles](#readfiles) - - [readFilesStream](#readfilesstream) - - [readFilesStream examples](#readfilesstream-examples) - - [files async](#files-async) - - [files sync](#files-sync) - - [promiseFiles](#promisefiles) - - [subdirs](#subdirs) - - [paths](#paths) + - [methods](#methods) + - [readFiles](#readfiles) + - [options](#options) + - [readFilesStream](#readfilesstream) + - [readFilesStream examples](#readfilesstream-examples) + - [readFiles valuetizer](#readfiles-valuetizer) + - [files async](#files-async) + - [files sync](#files-sync) + - [promiseFiles](#promisefiles) + - [subdirs](#subdirs) + - [paths](#paths) - [API Docs](#api-docs) - - [files](#files-api) - - [promiseFiles](#promisefiles-api) + - [files](#files-api) + - [promiseFiles](#promisefiles-api) - [History](#history) - [License](#license) #### installation - npm install path-reader +``` +npm install path-reader +``` ### usage @@ -43,6 +50,24 @@ A variation on the method readFilesStream. See usage for [readFilesStream](#read readFiles( dir, [options], fileCallback, [finishedCallback] ) ``` +#### Options +- **encoding** - file encoding (defaults to 'utf8') +- **exclude** - a regex pattern or array to specify filenames to ignore +- **excludeDir** - a regex pattern or array to specify directories to ignore +- **match** - a regex pattern or array to specify filenames to operate on +- **matchDir** - a regex pattern or array to specify directories to recurse +- **recursive** - whether to recurse subdirectories when reading files (defaults to true) +- **reverse** - sort files in each directory in descending order +- **shortName** - whether to aggregate only the base filename rather than the full filepath +- **sort** - sort files in each directory in ascending order (defaults to true) + - A reverse sort can also be achieved by setting the sort option to 'reverse', 'desc', or 'descending' string value. +- **doneOnErr** - control if done function called on error (defaults to true) +- **sync** : boolean = false - results are returned inline and no callbacks are used +- **shortName** : boolean = false||'relative' - instead of fullpath file names, just get the names or relative item names +- **recursive** : boolean = true - traverse through all children of given path +- **excludeHidden** : boolean - hidden files will be ignored (files starting with a dot are ignored) +- **valuetizer** : (stat, fileName, filePath) - A function of (stat, fileName, fileFullPath) . When null returned, item is skipped in end results + #### readFilesStream Sequentially read the content of each file in a directory, passing the contents to a callback, optionally calling a finished callback when complete. The options and finishedCallback arguments are not required. @@ -50,19 +75,20 @@ Sequentially read the content of each file in a directory, passing the contents readFilesStream( dir, [options], streamCallback, [finishedCallback] ) ``` -Valid options are: -- encoding: file encoding (defaults to 'utf8') -- exclude: a regex pattern or array to specify filenames to ignore -- excludeDir: a regex pattern or array to specify directories to ignore -- match: a regex pattern or array to specify filenames to operate on -- matchDir: a regex pattern or array to specify directories to recurse -- recursive: whether to recurse subdirectories when reading files (defaults to true) -- reverse: sort files in each directory in descending order -- shortName: whether to aggregate only the base filename rather than the full filepath -- sort: sort files in each directory in ascending order (defaults to true) -- doneOnErr: control if done function called on error (defaults to true) - -A reverse sort can also be achieved by setting the sort option to 'reverse', 'desc', or 'descending' string value. +#### readFiles valuetizer +An example of building an array of only items with an mtime +```javascript +var options = { + valuetizer:function(stat, shortName, longPath){ + return stat.mtime ? stat : null + } +} + +require('path-reader').promiseFiles(tdir, 'file', options) +.then(function(results){ + console.log(results)//an array of file stat if the file has a mtime definition +}) +``` #### readFilesStream examples @@ -256,16 +282,17 @@ files(dir, type, callback, options) - **dir** - directory path to read - **type**='file' - - 'file' returns only file listings - - 'dir' returns only directory listings - - 'all' returns {dirs:[], files:[]} - - 'combine' returns [] + - 'file' returns only file listings + - 'dir' returns only directory listings + - 'all' returns {dirs:[], files:[]} + - 'combine' returns [] - **callback** - - **options** - - **sync**=false - results are returned inline and no callbacks are used - - **shortName**=false||'relative' - instead of fullpath file names, just get the names or relative item names - - **recursive**=true - traverse through all children of given path - - **excludeHidden** - hidden files will be ignored (files starting with a dot are ignored) + - **sync**=false - results are returned inline and no callbacks are used + - **shortName**=false||'relative' - instead of fullpath file names, just get the names or relative item names + - **recursive**=true - traverse through all children of given path + - **excludeHidden** - hidden files will be ignored (files starting with a dot are ignored) + - **valuetizer** - A function of (stat, fileShortName, fileFullPath) . When null returned, item is skipped in end results ### promiseFiles API @@ -283,6 +310,7 @@ promiseFiles(dir, type||options, options) - **sync**=false - DO NOT USE for promiseFiles, will cause unexpected behavior - **shortName**=false||'relative' - instead of fullpath file names, just get the names or relative item names - **recursive**=true - traverse through all children of given path + - **valuetizer** - A function of (stat, fileShortName, fileFullPath) . When null returned, item is skipped in end results ## History path-reader is a fork of node-dir. The original maintainer of node-dir, @fshost, has not updated nor been heard from in some time. Use path-reader, it is far superior to node-dir. diff --git a/lib/paths.js b/lib/paths.js index 44ce095..66906a9 100644 --- a/lib/paths.js +++ b/lib/paths.js @@ -93,6 +93,13 @@ exports.files = function files(dir, type, callback, options) { var isDir = stat && stat.isDirectory() && stat.mode !== 17115 var pushVal = statHanOptions.valuetizer(stat, name, statPath, isDir)//options.shortName ? name : statPath + if( pushVal==null ){ + if (!--pending){ + done(); + } + return + } + if (isDir) { if (type !== 'file') { results.dirs.push(pushVal); @@ -161,6 +168,13 @@ exports.files = function files(dir, type, callback, options) { return list } + var statHanOptions = {} + if( options.valuetizer ){ + statHanOptions.valuetizer = options.valuetizer + }else{ + statHanOptions.valuetizer = getValuetizerByOptions(options, dir) + } +/* var statHanOptions = {} if(options.shortName){ if(options.shortName=='relative'){ @@ -183,7 +197,7 @@ exports.files = function files(dir, type, callback, options) { return longPath } } - +*/ for (var file, i = 0, l = list.length; i < l; i++) { var fname = list[i].toString(); file = path.join(dir, fname); @@ -295,4 +309,28 @@ exports.subdirs = function subdirs(dir, callback, type, options) { function assign(c0, c1){ for(var x in c1)c0[x] = c1[x] return c0 -} \ No newline at end of file +} + +function getValuetizerByOptions(options, dir){ + if(options.shortName){ + if( options.shortName=='relative' ){ + var dirBase = (options.basePath||dir) + var startPos = dirBase.length + if(dirBase.substring(dirBase.length-path.sep.length, dirBase.length)!=path.sep){ + startPos = startPos + path.sep.length + } + + return function(stat, shortName, longPath, isDir){ + return longPath.substring(startPos, longPath.length) + } + }else{ + return function(stat, shortName, longPath){ + return shortName + } + } + } + + return function(stat, shortName, longPath){ + return longPath + } +} diff --git a/package.json b/package.json index 0e9be26..5b38b94 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "path-reader", - "version": "1.0.6", + "version": "1.1.0", "description": "asynchronous file and directory operations for Node.js", "main": "index", "homepage": "https://github.com/ackerapple", diff --git a/test/test.js b/test/test.js index ea94fa4..0881c44 100644 --- a/test/test.js +++ b/test/test.js @@ -1362,27 +1362,42 @@ describe('paths method', function() { }); }); - describe('when called with combine argument set to true', function() { - + describe('when called with combine argument set to true', function(){ it('should pass an array of filepaths of all subdirs and files in a directory and its subdirs to a callback', function(done) { dir.paths(tdir, true, function(err, paths) { - should.not.exist(err); + should.not.exist(err) paths.should.be.a.array; var relPaths = paths.map(function(curPath) { return path.relative(fixturesDir, curPath); - }); + }) + relPaths.sort().should.eql([ 'testdir'+path.sep+'file1.txt', 'testdir'+path.sep+'file2.text', 'testdir'+path.sep+'subdir', 'testdir'+path.sep+'subdir'+path.sep+'file3.txt', 'testdir'+path.sep+'subdir'+path.sep+'file4.text' - ]); - }); - done(); - }); - - }); + ]) + }) + done() + }) + }) + + describe('valuetizer',function(){ + it('files by mtime', function(done) { + var foundMtime = false + var options = { + valuetizer:function(stat, shortName, longPath){ + return stat.mtime && !foundMtime ? foundMtime=true && stat : null + } + } + dir.promiseFiles(tdir, 'file', options) + .then(function(results){ + assert.equal(results.length, 1) + }) + .then(done).catch(done) + }) + }) }); From 66d2c7a9fcb34d6dca76eac3a7161058c7fa0f45 Mon Sep 17 00:00:00 2001 From: Acker Apple Date: Fri, 17 Jun 2022 09:52:50 -0400 Subject: [PATCH 35/37] compiled from typescript + fsStat options --- .gitignore | 1 + README.md | 4 +- index.js | 6 - lib/index.d.ts | 3 + lib/index.js | 22 ++ lib/paths.d.ts | 13 + lib/paths.js | 508 +++++++++++++++---------------------- lib/readfiles.d.ts | 1 + lib/readfiles.js | 236 +++++++++-------- lib/readfilesstream.d.ts | 1 + lib/readfilesstream.js | 128 +++++----- lib_old/paths.js | 336 ++++++++++++++++++++++++ lib_old/readfiles.js | 134 ++++++++++ lib_old/readfilesstream.js | 131 ++++++++++ package-lock.json | 468 +++++++++++++++++++++++++++++++--- package.json | 15 +- test/test.js | 2 +- ts/index.ts | 3 + ts/paths.ts | 341 +++++++++++++++++++++++++ ts/readfiles.ts | 133 ++++++++++ ts/readfilesstream.ts | 131 ++++++++++ ts/tsconfig.json | 32 +++ 22 files changed, 2115 insertions(+), 534 deletions(-) delete mode 100644 index.js create mode 100644 lib/index.d.ts create mode 100644 lib/index.js create mode 100644 lib/paths.d.ts create mode 100644 lib/readfiles.d.ts create mode 100644 lib/readfilesstream.d.ts create mode 100644 lib_old/paths.js create mode 100644 lib_old/readfiles.js create mode 100644 lib_old/readfilesstream.js create mode 100644 ts/index.ts create mode 100644 ts/paths.ts create mode 100644 ts/readfiles.ts create mode 100644 ts/readfilesstream.ts create mode 100644 ts/tsconfig.json diff --git a/.gitignore b/.gitignore index 03ed6f0..cde2fe8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.history .DS_Store updaters npm-debug.log diff --git a/README.md b/README.md index f6425ea..8d5d64f 100644 --- a/README.md +++ b/README.md @@ -193,9 +193,11 @@ console.log(files); Asynchronously iterate the files of a directory and its subdirectories and pass an array of file paths to a callback. ```javascript -promiseFiles(path, readType||options, options) +require('path-reader').promiseFiles(path, readType||options, options, fsStatOptions) ``` +> [read more about fsStatOptions here](https://nodejs.org/api/fs.html#fsstatsyncpath-options) + promiseFiles example ```javascript dir.promiseFiles(__dirname) diff --git a/index.js b/index.js deleted file mode 100644 index 71f4b0d..0000000 --- a/index.js +++ /dev/null @@ -1,6 +0,0 @@ -var dirpaths = require('./lib/paths'); - -for(var x in dirpaths)exports[x] = dirpaths[x] - -exports.readFiles = require('./lib/readfiles'); -exports.readFilesStream = require('./lib/readfilesstream'); diff --git a/lib/index.d.ts b/lib/index.d.ts new file mode 100644 index 0000000..3196806 --- /dev/null +++ b/lib/index.d.ts @@ -0,0 +1,3 @@ +export * from './paths'; +export { readFiles } from './readfiles'; +export { readFilesStream } from './readfilesstream'; diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..8468329 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,22 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.readFilesStream = exports.readFiles = void 0; +__exportStar(require("./paths"), exports); +var readfiles_1 = require("./readfiles"); +Object.defineProperty(exports, "readFiles", { enumerable: true, get: function () { return readfiles_1.readFiles; } }); +var readfilesstream_1 = require("./readfilesstream"); +Object.defineProperty(exports, "readFilesStream", { enumerable: true, get: function () { return readfilesstream_1.readFilesStream; } }); diff --git a/lib/paths.d.ts b/lib/paths.d.ts new file mode 100644 index 0000000..ac3d011 --- /dev/null +++ b/lib/paths.d.ts @@ -0,0 +1,13 @@ +/// +import * as fs from 'fs'; +interface FileReadOptions { + basePath?: string; + recursive?: boolean; + excludeHidden?: boolean; + sync?: boolean; + ignoreType?: string; + valuetizer?: (stat: any, shortName: string, longPath: string, isDir?: boolean) => any; +} +export declare function promiseFiles(dir: any, type: any, options?: FileReadOptions, statOptions?: fs.StatSyncOptions): Promise; +export declare function files(dir: any, type: any, callback: any, options?: FileReadOptions, statOptions?: fs.StatSyncOptions): any; +export {}; diff --git a/lib/paths.js b/lib/paths.js index 66906a9..fdce7fb 100644 --- a/lib/paths.js +++ b/lib/paths.js @@ -1,336 +1,242 @@ -var fs = require('fs'), - path = require('path'); - -exports.promiseFiles = function promiseFiles(dir, type, options){ - switch(typeof type){ - case 'object': - options = type - type = 'file' - break; - - default:type = type || 'file' - } - - var processor = function(res,rej){ - var cb = function(err,data){ - if(err)return rej(err) - res(data) +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.files = exports.promiseFiles = void 0; +var fs = require("fs"); +var path = require("path"); +function promiseFiles(dir, type, options, statOptions) { + switch (typeof type) { + case 'object': + options = type; + type = 'file'; + break; + default: type = type || 'file'; } - exports.files(dir,type,cb,options) - } - return new Promise(processor) + var processor = function (res, rej) { + var cb = function (err, data) { + if (err) + return rej(err); + res(data); + }; + exports.files(dir, type, cb, options, statOptions); + }; + return new Promise(processor); } - -/** - * find all files or subdirs (recursive) and pass to callback fn - * - * @param {string} dir directory in which to recurse files or subdirs - * @param {string} type type of dir entry to recurse ('file', 'dir', or 'all', defaults to 'file') - * @param {function(error, )} callback fn to call when done - * @example - * dir.files(__dirname, function(err, files) { - * if (err) throw err; - * console.log('files:', files); - * }); - */ -exports.files = function files(dir, type, callback, options) { - var ofType = typeof type - if(ofType == 'object'){ - options = options || type - type = 'file' - callback = function(){} - }else if (ofType !== 'string') { - //ignoreType = callback; - callback = type; - type = 'file'; - } - - options = options || {} - - var pending - var results = { - files: [], - dirs: [] - }; - - var done = function() { - if(type==='combine'){ - results = results.files.concat(results.dirs) - } else if (!type || options.ignoreType || ['all','combine'].indexOf(type)>=0) { - results = results - } else { - results = results[type + 's'] +exports.promiseFiles = promiseFiles; +function files(dir, type, callback, options, statOptions) { + var ofType = typeof type; + if (ofType == 'object') { + options = options || type; + type = 'file'; + callback = function () { }; } - - if(options.sync)return; - - callback(null, results); - }; - - /** - @statPath - fullPath - @name - fileName - @statHanOptions - { - valuetizer:function(stat, shortName, longPath){}, - function the handles value assignment - lstatCalled:false - used internally + else if (ofType !== 'string') { + callback = type; + type = 'file'; } - */ - var getStatHandler = function(statPath, name, statHanOptions) { - return function(err, stat) { - if (err) { - if (!statHanOptions.lstatCalled) { - var newStatHanOptions = assign(statHanOptions, {lstatCalled:true}) - if(options.sync){ - var lstat = fs.lstatSync(statPath); - return getStatHandler(statPath, name, newStatHanOptions)(null, lstat) - }else{ - return fs.lstat(statPath, getStatHandler(statPath, name, newStatHanOptions)); - } + options = options || {}; + var pending; + var results = { + files: [], + dirs: [] + }; + var done = function (_list) { + if (type === 'combine') { + results = results.files.concat(results.dirs); } - return callback(err); - } - - var isDir = stat && stat.isDirectory() && stat.mode !== 17115 - var pushVal = statHanOptions.valuetizer(stat, name, statPath, isDir)//options.shortName ? name : statPath - - if( pushVal==null ){ - if (!--pending){ - done(); + else if (!type || options.ignoreType || ['all', 'combine'].indexOf(type) >= 0) { + results = results; } - return - } - - if (isDir) { - if (type !== 'file') { - results.dirs.push(pushVal); + else { + results = results[type + 's']; } - - if (options.recursive==null || options.recursive) { - var subloop = function(err, res) { - if (err){ - return callback(err) + if (options.sync) + return; + callback(null, results); + }; + var getStatHandler = function (statPath, name, statHanOptions) { + return function (err, stat) { + if (err) { + if (!statHanOptions.lstatCalled) { + var newStatHanOptions = assign(statHanOptions, { lstatCalled: true }); + if (options.sync) { + var lstat = fs.lstatSync(statPath); + return getStatHandler(statPath, name, newStatHanOptions)(null, lstat); + } + else { + return fs.lstat(statPath, getStatHandler(statPath, name, newStatHanOptions)); + } + } + return callback(err); } - - if(type === 'combine'){ - results.files = results.files.concat(res); - }else if (type === 'all') { - if( res.files ){//dont add things that are not there - results.files = results.files.concat(res.files); - } - results.dirs = results.dirs.concat(res.dirs); - } else if (type === 'file') { - if( res.files ){//dont add things that are not there - results.files = results.files.concat(res.files); + var isDir = stat && stat.isDirectory() && stat.mode !== 17115; + var pushVal = statHanOptions.valuetizer(stat, name, statPath, isDir); + if (pushVal == null) { + if (!--pending) { + done(); } - } else { - results.dirs = results.dirs.concat(res.dirs); + return; } - - if (!--pending){ - done(); + if (isDir) { + if (type !== 'file') { + results.dirs.push(pushVal); + } + if (options.recursive == null || options.recursive) { + var subloop = function (err, res) { + if (err) { + return callback(err); + } + if (type === 'combine') { + results.files = results.files.concat(res); + } + else if (type === 'all') { + if (res.files) { + results.files = results.files.concat(res.files); + } + results.dirs = results.dirs.concat(res.dirs); + } + else if (type === 'file') { + if (res.files) { + results.files = results.files.concat(res.files); + } + } + else { + results.dirs = results.dirs.concat(res.dirs); + } + if (!--pending) { + done(); + } + }; + var newOptions = assign({}, options); + newOptions.basePath = options.basePath || dir; + newOptions.ignoreType = true; + var moreResults = files(statPath, type, subloop, newOptions); + if (options.sync) { + subloop(null, moreResults); + } + } + else if (!--pending) { + done(); + } } - } - - var newOptions = assign({}, options) - newOptions.basePath = options.basePath || dir - newOptions.ignoreType = true - var moreResults = exports.files(statPath, type, subloop, newOptions); - - if(options.sync){ - subloop(null, moreResults) - } - }else if (!--pending){ - done() + else { + var excludeHidden = options.excludeHidden && name.split(path.sep).pop().search(/^\./) == 0; + if (type !== 'dir' && !excludeHidden) { + results.files.push(pushVal); + } + if (!--pending) { + done(); + } + } + }; + }; + var onDirRead = function (err, list, statOptions) { + if (err) + return callback(err); + pending = list.length; + if (!pending) { + done(list); + return list; } - } else { - var excludeHidden = options.excludeHidden && name.split(path.sep).pop().search(/^\./)==0 - - if (type!=='dir' && !excludeHidden) { - results.files.push(pushVal); + var statHanOptions = {}; + if (options.valuetizer) { + statHanOptions.valuetizer = options.valuetizer; } - // should be the last statement in statHandler - if (!--pending){ - done() + else { + statHanOptions.valuetizer = getValuetizerByOptions(options, dir); } - } - } - } - - - //var bufdir = Buffer.from(dir); - - const onDirRead = function(err, list) { - if (err) return callback(err); - - pending = list.length; - if (!pending){ - done(list); - return list - } - - var statHanOptions = {} - if( options.valuetizer ){ - statHanOptions.valuetizer = options.valuetizer - }else{ - statHanOptions.valuetizer = getValuetizerByOptions(options, dir) - } -/* - var statHanOptions = {} - if(options.shortName){ - if(options.shortName=='relative'){ - var dirBase = (options.basePath||dir) - var startPos = dirBase.length - if(dirBase.substring(dirBase.length-path.sep.length, dirBase.length)!=path.sep){ - startPos = startPos + path.sep.length + for (var file, i = 0, l = list.length; i < l; i++) { + var fname = list[i].toString(); + file = path.join(dir, fname); + if (options.sync) { + var res = fs.statSync(file, statOptions); + getStatHandler(file, list[i], statHanOptions)(null, res); + } + else { + fs.stat(file, getStatHandler(file, list[i], statHanOptions)); + } } - - statHanOptions.valuetizer = function(stat, shortName, longPath, isDir){ - return longPath.substring(startPos, longPath.length) + return results; + }; + var onStat = function (err, stat, statOptions) { + if (err) + return callback(err); + if (stat && stat.mode === 17115) + return done(); + if (options.sync) { + var list = fs.readdirSync(dir); + return onDirRead(null, list, statOptions); } - }else{ - statHanOptions.valuetizer = function(stat, shortName, longPath){ - return shortName + else { + fs.readdir(dir, function (err, files) { return onDirRead(err, files, statOptions); }); } - } - }else{ - statHanOptions.valuetizer = function(stat, shortName, longPath){ - return longPath - } - } -*/ - for (var file, i = 0, l = list.length; i < l; i++) { - var fname = list[i].toString(); - file = path.join(dir, fname); - //var buffile = Buffer.concat([bufdir, Buffer.from(path.sep), list[i]]); - - if(options.sync){ - var res = fs.statSync(file); - getStatHandler(file, list[i], statHanOptions)(null, res) - }else{ - fs.stat(file, getStatHandler(file, list[i], statHanOptions)); - } + }; + if (options.sync) { + var stat = fs.statSync(dir); + return onStat(null, stat, statOptions); } - - return results - } - - const onStat = function(err, stat) { - if (err) return callback(err); - if (stat && stat.mode === 17115) return done(); - - if(options.sync){ - const list = fs.readdirSync(dir) - return onDirRead(null, list) - }else{ - fs.readdir(dir, onDirRead) + else { + fs.stat(dir, onStat); } - } - - if(options.sync){ - const stat = fs.statSync(dir); - return onStat(null, stat) - }else{ - fs.stat(dir, onStat); - } -}; - - -/** - * find all files and subdirs in a directory (recursive) and pass them to callback fn - * - * @param {string} dir directory in which to recurse files or subdirs - * @param {boolean} combine whether to combine both subdirs and filepaths into one array (default false) - * @param {function(error, Object.<, Array.>)} callback fn to call when done - * @example - * dir.paths(__dirname, function (err, paths) { - * if (err) throw err; - * console.log('files:', paths.files); - * console.log('subdirs:', paths.dirs); - * }); - * dir.paths(__dirname, true, function (err, paths) { - * if (err) throw err; - * console.log('paths:', paths); - * }); - */ +} +exports.files = files; +; exports.paths = function paths(dir, combine, callback) { - var type; - if (typeof combine === 'function') { callback = combine; combine = false; } - - exports.files(dir, 'all', function(err, results) { - if (err) return callback(err); + files(dir, 'all', function (err, results) { + if (err) + return callback(err); if (combine) { callback(null, results.files.concat(results.dirs)); - } else { + } + else { callback(null, results); } }); }; - - -/** - * find all subdirs (recursive) of a directory and pass them to callback fn - * - * @param {string} dir directory in which to find subdirs - * @param {string} type type of dir entry to recurse ('file' or 'dir', defaults to 'file') - * @param {function(error, )} callback fn to call when done - * @example - * dir.subdirs(__dirname, function (err, paths) { - * if (err) throw err; - * console.log('files:', paths.files); - * console.log('subdirs:', paths.dirs); - * }); - */ exports.subdirs = function subdirs(dir, callback, type, options) { - options = options || {} - - const iCallback = function(err, subdirs) { - if (err) return callback(err); - - if(type=='combine'){ - subdirs = subdirs.files.concat(subdirs.dirs) + options = options || {}; + var iCallback = function (err, subdirs) { + if (err) + return callback(err); + if (type == 'combine') { + subdirs = subdirs.files.concat(subdirs.dirs); + } + if (options.sync) + return subdirs; + callback(null, subdirs); + }; + var res = exports.files(dir, 'dir', iCallback, options); + if (options && options.sync) { + return iCallback(null, res); } - - if(options.sync)return subdirs - - callback(null, subdirs); - } - - const res = exports.files(dir, 'dir', iCallback, options) - - if(options && options.sync){ - return iCallback(null,res) - } -} - -function assign(c0, c1){ - for(var x in c1)c0[x] = c1[x] - return c0 +}; +function assign(c0, c1) { + for (var x in c1) + c0[x] = c1[x]; + return c0; } - -function getValuetizerByOptions(options, dir){ - if(options.shortName){ - if( options.shortName=='relative' ){ - var dirBase = (options.basePath||dir) - var startPos = dirBase.length - if(dirBase.substring(dirBase.length-path.sep.length, dirBase.length)!=path.sep){ - startPos = startPos + path.sep.length - } - - return function(stat, shortName, longPath, isDir){ - return longPath.substring(startPos, longPath.length) - } - }else{ - return function(stat, shortName, longPath){ - return shortName - } +function getValuetizerByOptions(options, dir) { + if (options.shortName) { + if (options.shortName == 'relative') { + var dirBase = (options.basePath || dir); + var startPos = dirBase.length; + if (dirBase.substring(dirBase.length - path.sep.length, dirBase.length) != path.sep) { + startPos = startPos + path.sep.length; + } + return function (stat, shortName, longPath, isDir) { + return longPath.substring(startPos, longPath.length); + }; + } + else { + return function (stat, shortName, longPath) { + return shortName; + }; + } } - } - - return function(stat, shortName, longPath){ - return longPath - } + return function (stat, shortName, longPath) { + return longPath; + }; } diff --git a/lib/readfiles.d.ts b/lib/readfiles.d.ts new file mode 100644 index 0000000..5e4cbc9 --- /dev/null +++ b/lib/readfiles.d.ts @@ -0,0 +1 @@ +export declare function readFiles(dir: any, options: any, callback: any, complete: any): void; diff --git a/lib/readfiles.js b/lib/readfiles.js index c45ae1b..e08f20b 100644 --- a/lib/readfiles.js +++ b/lib/readfiles.js @@ -1,134 +1,126 @@ -var fs = require('fs'), - path = require('path'); - -/** - * merge two objects by extending target object with source object - * @param target object to merge - * @param source object to merge - * @param {Boolean} [modify] whether to modify the target - * @returns {Object} extended object - */ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.readFiles = void 0; +var fs = require("fs"); +var path = require("path"); function extend(target, source, modify) { - var result = target ? modify ? target : extend({}, target, true) : {}; - if (!source) return result; - for (var key in source) { - if (source.hasOwnProperty(key) && source[key] !== undefined) { - result[key] = source[key]; + var result = target ? modify ? target : extend({}, target, true) : {}; + if (!source) + return result; + for (var key in source) { + if (source.hasOwnProperty(key) && source[key] !== undefined) { + result[key] = source[key]; + } } - } - return result; + return result; } - -/** - * determine if a string is contained within an array or matches a regular expression - * @param {String} str string to match - * @param {Array|Regex} match array or regular expression to match against - * @returns {Boolean} whether there is a match - */ function matches(str, match) { - if (Array.isArray(match)) return match.indexOf(str) > -1; - return match.test(str); + if (Array.isArray(match)) + return match.indexOf(str) > -1; + return match.test(str); } - -/** - * read files and call a function with the contents of each file - * @param {String} dir path of dir containing the files to be read - * @param {String} encoding file encoding (default is 'utf8') - * @param {Object} options options hash for encoding, recursive, and match/exclude - * @param {Function(error, string)} callback callback for each files content - * @param {Function(error)} complete fn to call when finished - */ function readFiles(dir, options, callback, complete) { - if (typeof options === 'function') { - complete = callback; - callback = options; - options = {}; - } - if (typeof options === 'string') options = { - encoding: options - }; - options = extend({ - recursive: true, - encoding: 'utf8', - doneOnErr: true - }, options); - var files = []; - - var done = function(err) { - if (typeof complete === 'function') { - if (err) return complete(err); - complete(null, files); - } - }; - - fs.readdir(dir, function(err, list) { - if (err) { - if (options.doneOnErr === true) { - if (err.code === 'EACCES') return done(); - return done(err); - } + if (typeof options === 'function') { + complete = callback; + callback = options; + options = {}; } - var i = 0; - - if (options.reverse === true || - (typeof options.sort == 'string' && - (/reverse|desc/i).test(options.sort))) { - list = list.reverse(); - } else if (options.sort !== false) list = list.sort(); - - (function next() { - var filename = list[i++]; - if (!filename) return done(null, files); - - var file = path.join(dir, filename); - - fs.stat(file, function(err, stat) { - if (err && options.doneOnErr === true) return done(err); - if (stat && stat.isDirectory()) { - if (options.recursive) { - if (options.matchDir && !matches(filename, options.matchDir)) return next(); - if (options.excludeDir && matches(filename, options.excludeDir)) return next(); - readFiles(file, options, callback, function(err, sfiles) { - if (err && options.doneOnErr === true) return done(err); - files = files.concat(sfiles); - next(); - }); - } else next(); - } else if (stat && stat.isFile()) { - if (options.match && !matches(filename, options.match)) return next(); - if (options.exclude && matches(filename, options.exclude)) return next(); - if (options.filter && !options.filter(filename)) return next(); - - if (options.shortName){ - files.push(filename); - }else{ - files.push(file); - } - - fs.readFile(file, options.encoding, function(err, data) { - if (err) { - if (err.code === 'EACCES') return next(); - if (options.doneOnErr === true) { + if (typeof options === 'string') + options = { + encoding: options + }; + options = extend({ + recursive: true, + encoding: 'utf8', + doneOnErr: true + }, options); + var files = []; + var done = function (err, _result) { + if (typeof complete === 'function') { + if (err) + return complete(err); + complete(null, files); + } + }; + fs.readdir(dir, function (err, list) { + if (err) { + if (options.doneOnErr === true) { + if (err.code === 'EACCES') + return done(); return done(err); - } - } - if (callback.length > 3){ - if (options.shortName){ - callback(null, data, filename, next); - }else{ - callback(null, data, file, next); - } - }else{ - callback(null, data, next); } - }); } - else { - next(); + var i = 0; + if (options.reverse === true || + (typeof options.sort == 'string' && + (/reverse|desc/i).test(options.sort))) { + list = list.reverse(); } - }); - })(); - - }); + else if (options.sort !== false) + list = list.sort(); + (function next() { + var filename = list[i++]; + if (!filename) + return done(null, files); + var file = path.join(dir, filename); + fs.stat(file, function (err, stat) { + if (err && options.doneOnErr === true) + return done(err); + if (stat && stat.isDirectory()) { + if (options.recursive) { + if (options.matchDir && !matches(filename, options.matchDir)) + return next(); + if (options.excludeDir && matches(filename, options.excludeDir)) + return next(); + readFiles(file, options, callback, function (err, sfiles) { + if (err && options.doneOnErr === true) + return done(err); + files = files.concat(sfiles); + next(); + }); + } + else + next(); + } + else if (stat && stat.isFile()) { + if (options.match && !matches(filename, options.match)) + return next(); + if (options.exclude && matches(filename, options.exclude)) + return next(); + if (options.filter && !options.filter(filename)) + return next(); + if (options.shortName) { + files.push(filename); + } + else { + files.push(file); + } + fs.readFile(file, options.encoding, function (err, data) { + if (err) { + if (err.code === 'EACCES') + return next(); + if (options.doneOnErr === true) { + return done(err); + } + } + if (callback.length > 3) { + if (options.shortName) { + callback(null, data, filename, next); + } + else { + callback(null, data, file, next); + } + } + else { + callback(null, data, next); + } + }); + } + else { + next(); + } + }); + })(); + }); } -module.exports = readFiles; +exports.readFiles = readFiles; diff --git a/lib/readfilesstream.d.ts b/lib/readfilesstream.d.ts new file mode 100644 index 0000000..d8a6a9f --- /dev/null +++ b/lib/readfilesstream.d.ts @@ -0,0 +1 @@ +export declare function readFilesStream(dir: any, options: any, callback: any, complete: any): void; diff --git a/lib/readfilesstream.js b/lib/readfilesstream.js index eddd202..ed65017 100644 --- a/lib/readfilesstream.js +++ b/lib/readfilesstream.js @@ -1,17 +1,12 @@ -var fs = require('fs'), - mm = require('minimatch'), - path = require('path'); - -/** - * merge two objects by extending target object with source object - * @param target object to merge - * @param source object to merge - * @param {Boolean} [modify] whether to modify the target - * @returns {Object} extended object - */ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.readFilesStream = void 0; +var fs = require('fs'), mm = require('minimatch'); +var path = require("path"); function extend(target, source, modify) { var result = target ? modify ? target : extend({}, target, true) : {}; - if (!source) return result; + if (!source) + return result; for (var key in source) { if (source.hasOwnProperty(key) && source[key] !== undefined) { result[key] = source[key]; @@ -19,18 +14,11 @@ function extend(target, source, modify) { } return result; } - -/** - * determine if a string is contained within an array or matches a regular expression - * @param {String} str string to match - * @param {Array|Regex} match array or regular expression to match against - * @returns {Boolean} whether there is a match - */ function matches(str, match) { if (Array.isArray(match)) { var l = match.length; - for( var s=0; s < l; s++) { - if ( mm(str,match[s])) { + for (var s = 0; s < l; s++) { + if (mm(str, match[s])) { return true; } } @@ -38,94 +26,102 @@ function matches(str, match) { } return match.test(str); } - -/** - * read files and call a function with the contents of each file - * @param {String} dir path of dir containing the files to be read - * @param {String} encoding file encoding (default is 'utf8') - * @param {Object} options options hash for encoding, recursive, and match/exclude - * @param {Function(error, string)} callback callback for each files content - * @param {Function(error)} complete fn to call when finished - */ function readFilesStream(dir, options, callback, complete) { if (typeof options === 'function') { complete = callback; callback = options; options = {}; } - if (typeof options === 'string') options = { - encoding: options - }; + if (typeof options === 'string') + options = { + encoding: options + }; options = extend({ recursive: true, encoding: 'utf8', doneOnErr: true }, options); var files = []; - - var done = function(err) { + var done = function (err, _result) { if (typeof complete === 'function') { - if (err) return complete(err); + if (err) + return complete(err); complete(null, files); } }; - - fs.readdir(dir, function(err, list) { + fs.readdir(dir, function (err, list) { if (err) { if (options.doneOnErr === true) { - if (err.code === 'EACCES') return done(); - return done(err); + if (err.code === 'EACCES') + return done(); + return done(err); } } var i = 0; - if (options.reverse === true || (typeof options.sort == 'string' && (/reverse|desc/i).test(options.sort))) { list = list.reverse(); - } else if (options.sort !== false) list = list.sort(); - + } + else if (options.sort !== false) + list = list.sort(); (function next() { var filename = list[i++]; - if (!filename) return done(null, files); + if (!filename) + return done(null, files); var file = path.join(dir, filename); - fs.stat(file, function(err, stat) { - if (err && options.doneOnErr === true) return done(err); + fs.stat(file, function (err, stat) { + if (err && options.doneOnErr === true) + return done(err); if (stat && stat.isDirectory()) { if (options.recursive) { - if (options.matchDir && !matches(filename, options.matchDir)) return next(); - if (options.excludeDir && matches(filename, options.excludeDir)) return next(); - readFilesStream(file, options, callback, function(err, sfiles) { - if (err && options.doneOnErr === true) return done(err); + if (options.matchDir && !matches(filename, options.matchDir)) + return next(); + if (options.excludeDir && matches(filename, options.excludeDir)) + return next(); + readFilesStream(file, options, callback, function (err, sfiles) { + if (err && options.doneOnErr === true) + return done(err); files = files.concat(sfiles); next(); }); - } else next(); - } else if (stat && stat.isFile()) { - if (options.match && !matches(filename, options.match)) return next(); - if (options.exclude && matches(filename, options.exclude)) return next(); - if (options.filter && !options.filter(filename)) return next(); - if (options.shortName) files.push(filename); - else files.push(file); + } + else + next(); + } + else if (stat && stat.isFile()) { + if (options.match && !matches(filename, options.match)) + return next(); + if (options.exclude && matches(filename, options.exclude)) + return next(); + if (options.filter && !options.filter(filename)) + return next(); + if (options.shortName) + files.push(filename); + else + files.push(file); var stream = fs.createReadStream(file); if (options.encoding !== null) { stream.setEncoding(options.encoding); } - stream.on('error',function(err) { - if (options.doneOnErr === true) return done(err); - next(); + stream.on('error', function (err) { + if (options.doneOnErr === true) + return done(err); + next(); }); if (callback.length > 3) - if (options.shortName) callback(null, stream, filename, next); - else callback(null, stream, file, next); - else callback(null, stream, next); + if (options.shortName) + callback(null, stream, filename, next); + else + callback(null, stream, file, next); + else + callback(null, stream, next); } else { - next(); + next(); } }); })(); - }); } -module.exports = readFilesStream; +exports.readFilesStream = readFilesStream; diff --git a/lib_old/paths.js b/lib_old/paths.js new file mode 100644 index 0000000..66906a9 --- /dev/null +++ b/lib_old/paths.js @@ -0,0 +1,336 @@ +var fs = require('fs'), + path = require('path'); + +exports.promiseFiles = function promiseFiles(dir, type, options){ + switch(typeof type){ + case 'object': + options = type + type = 'file' + break; + + default:type = type || 'file' + } + + var processor = function(res,rej){ + var cb = function(err,data){ + if(err)return rej(err) + res(data) + } + exports.files(dir,type,cb,options) + } + return new Promise(processor) +} + +/** + * find all files or subdirs (recursive) and pass to callback fn + * + * @param {string} dir directory in which to recurse files or subdirs + * @param {string} type type of dir entry to recurse ('file', 'dir', or 'all', defaults to 'file') + * @param {function(error, )} callback fn to call when done + * @example + * dir.files(__dirname, function(err, files) { + * if (err) throw err; + * console.log('files:', files); + * }); + */ +exports.files = function files(dir, type, callback, options) { + var ofType = typeof type + if(ofType == 'object'){ + options = options || type + type = 'file' + callback = function(){} + }else if (ofType !== 'string') { + //ignoreType = callback; + callback = type; + type = 'file'; + } + + options = options || {} + + var pending + var results = { + files: [], + dirs: [] + }; + + var done = function() { + if(type==='combine'){ + results = results.files.concat(results.dirs) + } else if (!type || options.ignoreType || ['all','combine'].indexOf(type)>=0) { + results = results + } else { + results = results[type + 's'] + } + + if(options.sync)return; + + callback(null, results); + }; + + /** + @statPath - fullPath + @name - fileName + @statHanOptions - { + valuetizer:function(stat, shortName, longPath){}, - function the handles value assignment + lstatCalled:false - used internally + } + */ + var getStatHandler = function(statPath, name, statHanOptions) { + return function(err, stat) { + if (err) { + if (!statHanOptions.lstatCalled) { + var newStatHanOptions = assign(statHanOptions, {lstatCalled:true}) + if(options.sync){ + var lstat = fs.lstatSync(statPath); + return getStatHandler(statPath, name, newStatHanOptions)(null, lstat) + }else{ + return fs.lstat(statPath, getStatHandler(statPath, name, newStatHanOptions)); + } + } + return callback(err); + } + + var isDir = stat && stat.isDirectory() && stat.mode !== 17115 + var pushVal = statHanOptions.valuetizer(stat, name, statPath, isDir)//options.shortName ? name : statPath + + if( pushVal==null ){ + if (!--pending){ + done(); + } + return + } + + if (isDir) { + if (type !== 'file') { + results.dirs.push(pushVal); + } + + if (options.recursive==null || options.recursive) { + var subloop = function(err, res) { + if (err){ + return callback(err) + } + + if(type === 'combine'){ + results.files = results.files.concat(res); + }else if (type === 'all') { + if( res.files ){//dont add things that are not there + results.files = results.files.concat(res.files); + } + results.dirs = results.dirs.concat(res.dirs); + } else if (type === 'file') { + if( res.files ){//dont add things that are not there + results.files = results.files.concat(res.files); + } + } else { + results.dirs = results.dirs.concat(res.dirs); + } + + if (!--pending){ + done(); + } + } + + var newOptions = assign({}, options) + newOptions.basePath = options.basePath || dir + newOptions.ignoreType = true + var moreResults = exports.files(statPath, type, subloop, newOptions); + + if(options.sync){ + subloop(null, moreResults) + } + }else if (!--pending){ + done() + } + } else { + var excludeHidden = options.excludeHidden && name.split(path.sep).pop().search(/^\./)==0 + + if (type!=='dir' && !excludeHidden) { + results.files.push(pushVal); + } + // should be the last statement in statHandler + if (!--pending){ + done() + } + } + } + } + + + //var bufdir = Buffer.from(dir); + + const onDirRead = function(err, list) { + if (err) return callback(err); + + pending = list.length; + if (!pending){ + done(list); + return list + } + + var statHanOptions = {} + if( options.valuetizer ){ + statHanOptions.valuetizer = options.valuetizer + }else{ + statHanOptions.valuetizer = getValuetizerByOptions(options, dir) + } +/* + var statHanOptions = {} + if(options.shortName){ + if(options.shortName=='relative'){ + var dirBase = (options.basePath||dir) + var startPos = dirBase.length + if(dirBase.substring(dirBase.length-path.sep.length, dirBase.length)!=path.sep){ + startPos = startPos + path.sep.length + } + + statHanOptions.valuetizer = function(stat, shortName, longPath, isDir){ + return longPath.substring(startPos, longPath.length) + } + }else{ + statHanOptions.valuetizer = function(stat, shortName, longPath){ + return shortName + } + } + }else{ + statHanOptions.valuetizer = function(stat, shortName, longPath){ + return longPath + } + } +*/ + for (var file, i = 0, l = list.length; i < l; i++) { + var fname = list[i].toString(); + file = path.join(dir, fname); + //var buffile = Buffer.concat([bufdir, Buffer.from(path.sep), list[i]]); + + if(options.sync){ + var res = fs.statSync(file); + getStatHandler(file, list[i], statHanOptions)(null, res) + }else{ + fs.stat(file, getStatHandler(file, list[i], statHanOptions)); + } + } + + return results + } + + const onStat = function(err, stat) { + if (err) return callback(err); + if (stat && stat.mode === 17115) return done(); + + if(options.sync){ + const list = fs.readdirSync(dir) + return onDirRead(null, list) + }else{ + fs.readdir(dir, onDirRead) + } + } + + if(options.sync){ + const stat = fs.statSync(dir); + return onStat(null, stat) + }else{ + fs.stat(dir, onStat); + } +}; + + +/** + * find all files and subdirs in a directory (recursive) and pass them to callback fn + * + * @param {string} dir directory in which to recurse files or subdirs + * @param {boolean} combine whether to combine both subdirs and filepaths into one array (default false) + * @param {function(error, Object.<, Array.>)} callback fn to call when done + * @example + * dir.paths(__dirname, function (err, paths) { + * if (err) throw err; + * console.log('files:', paths.files); + * console.log('subdirs:', paths.dirs); + * }); + * dir.paths(__dirname, true, function (err, paths) { + * if (err) throw err; + * console.log('paths:', paths); + * }); + */ +exports.paths = function paths(dir, combine, callback) { + var type; + + if (typeof combine === 'function') { + callback = combine; + combine = false; + } + + exports.files(dir, 'all', function(err, results) { + if (err) return callback(err); + if (combine) { + callback(null, results.files.concat(results.dirs)); + } else { + callback(null, results); + } + }); +}; + + +/** + * find all subdirs (recursive) of a directory and pass them to callback fn + * + * @param {string} dir directory in which to find subdirs + * @param {string} type type of dir entry to recurse ('file' or 'dir', defaults to 'file') + * @param {function(error, )} callback fn to call when done + * @example + * dir.subdirs(__dirname, function (err, paths) { + * if (err) throw err; + * console.log('files:', paths.files); + * console.log('subdirs:', paths.dirs); + * }); + */ +exports.subdirs = function subdirs(dir, callback, type, options) { + options = options || {} + + const iCallback = function(err, subdirs) { + if (err) return callback(err); + + if(type=='combine'){ + subdirs = subdirs.files.concat(subdirs.dirs) + } + + if(options.sync)return subdirs + + callback(null, subdirs); + } + + const res = exports.files(dir, 'dir', iCallback, options) + + if(options && options.sync){ + return iCallback(null,res) + } +} + +function assign(c0, c1){ + for(var x in c1)c0[x] = c1[x] + return c0 +} + +function getValuetizerByOptions(options, dir){ + if(options.shortName){ + if( options.shortName=='relative' ){ + var dirBase = (options.basePath||dir) + var startPos = dirBase.length + if(dirBase.substring(dirBase.length-path.sep.length, dirBase.length)!=path.sep){ + startPos = startPos + path.sep.length + } + + return function(stat, shortName, longPath, isDir){ + return longPath.substring(startPos, longPath.length) + } + }else{ + return function(stat, shortName, longPath){ + return shortName + } + } + } + + return function(stat, shortName, longPath){ + return longPath + } +} diff --git a/lib_old/readfiles.js b/lib_old/readfiles.js new file mode 100644 index 0000000..c45ae1b --- /dev/null +++ b/lib_old/readfiles.js @@ -0,0 +1,134 @@ +var fs = require('fs'), + path = require('path'); + +/** + * merge two objects by extending target object with source object + * @param target object to merge + * @param source object to merge + * @param {Boolean} [modify] whether to modify the target + * @returns {Object} extended object + */ +function extend(target, source, modify) { + var result = target ? modify ? target : extend({}, target, true) : {}; + if (!source) return result; + for (var key in source) { + if (source.hasOwnProperty(key) && source[key] !== undefined) { + result[key] = source[key]; + } + } + return result; +} + +/** + * determine if a string is contained within an array or matches a regular expression + * @param {String} str string to match + * @param {Array|Regex} match array or regular expression to match against + * @returns {Boolean} whether there is a match + */ +function matches(str, match) { + if (Array.isArray(match)) return match.indexOf(str) > -1; + return match.test(str); +} + +/** + * read files and call a function with the contents of each file + * @param {String} dir path of dir containing the files to be read + * @param {String} encoding file encoding (default is 'utf8') + * @param {Object} options options hash for encoding, recursive, and match/exclude + * @param {Function(error, string)} callback callback for each files content + * @param {Function(error)} complete fn to call when finished + */ +function readFiles(dir, options, callback, complete) { + if (typeof options === 'function') { + complete = callback; + callback = options; + options = {}; + } + if (typeof options === 'string') options = { + encoding: options + }; + options = extend({ + recursive: true, + encoding: 'utf8', + doneOnErr: true + }, options); + var files = []; + + var done = function(err) { + if (typeof complete === 'function') { + if (err) return complete(err); + complete(null, files); + } + }; + + fs.readdir(dir, function(err, list) { + if (err) { + if (options.doneOnErr === true) { + if (err.code === 'EACCES') return done(); + return done(err); + } + } + var i = 0; + + if (options.reverse === true || + (typeof options.sort == 'string' && + (/reverse|desc/i).test(options.sort))) { + list = list.reverse(); + } else if (options.sort !== false) list = list.sort(); + + (function next() { + var filename = list[i++]; + if (!filename) return done(null, files); + + var file = path.join(dir, filename); + + fs.stat(file, function(err, stat) { + if (err && options.doneOnErr === true) return done(err); + if (stat && stat.isDirectory()) { + if (options.recursive) { + if (options.matchDir && !matches(filename, options.matchDir)) return next(); + if (options.excludeDir && matches(filename, options.excludeDir)) return next(); + readFiles(file, options, callback, function(err, sfiles) { + if (err && options.doneOnErr === true) return done(err); + files = files.concat(sfiles); + next(); + }); + } else next(); + } else if (stat && stat.isFile()) { + if (options.match && !matches(filename, options.match)) return next(); + if (options.exclude && matches(filename, options.exclude)) return next(); + if (options.filter && !options.filter(filename)) return next(); + + if (options.shortName){ + files.push(filename); + }else{ + files.push(file); + } + + fs.readFile(file, options.encoding, function(err, data) { + if (err) { + if (err.code === 'EACCES') return next(); + if (options.doneOnErr === true) { + return done(err); + } + } + if (callback.length > 3){ + if (options.shortName){ + callback(null, data, filename, next); + }else{ + callback(null, data, file, next); + } + }else{ + callback(null, data, next); + } + }); + } + else { + next(); + } + }); + })(); + + }); +} +module.exports = readFiles; diff --git a/lib_old/readfilesstream.js b/lib_old/readfilesstream.js new file mode 100644 index 0000000..eddd202 --- /dev/null +++ b/lib_old/readfilesstream.js @@ -0,0 +1,131 @@ +var fs = require('fs'), + mm = require('minimatch'), + path = require('path'); + +/** + * merge two objects by extending target object with source object + * @param target object to merge + * @param source object to merge + * @param {Boolean} [modify] whether to modify the target + * @returns {Object} extended object + */ +function extend(target, source, modify) { + var result = target ? modify ? target : extend({}, target, true) : {}; + if (!source) return result; + for (var key in source) { + if (source.hasOwnProperty(key) && source[key] !== undefined) { + result[key] = source[key]; + } + } + return result; +} + +/** + * determine if a string is contained within an array or matches a regular expression + * @param {String} str string to match + * @param {Array|Regex} match array or regular expression to match against + * @returns {Boolean} whether there is a match + */ +function matches(str, match) { + if (Array.isArray(match)) { + var l = match.length; + for( var s=0; s < l; s++) { + if ( mm(str,match[s])) { + return true; + } + } + return false; + } + return match.test(str); +} + +/** + * read files and call a function with the contents of each file + * @param {String} dir path of dir containing the files to be read + * @param {String} encoding file encoding (default is 'utf8') + * @param {Object} options options hash for encoding, recursive, and match/exclude + * @param {Function(error, string)} callback callback for each files content + * @param {Function(error)} complete fn to call when finished + */ +function readFilesStream(dir, options, callback, complete) { + if (typeof options === 'function') { + complete = callback; + callback = options; + options = {}; + } + if (typeof options === 'string') options = { + encoding: options + }; + options = extend({ + recursive: true, + encoding: 'utf8', + doneOnErr: true + }, options); + var files = []; + + var done = function(err) { + if (typeof complete === 'function') { + if (err) return complete(err); + complete(null, files); + } + }; + + fs.readdir(dir, function(err, list) { + if (err) { + if (options.doneOnErr === true) { + if (err.code === 'EACCES') return done(); + return done(err); + } + } + var i = 0; + + if (options.reverse === true || + (typeof options.sort == 'string' && + (/reverse|desc/i).test(options.sort))) { + list = list.reverse(); + } else if (options.sort !== false) list = list.sort(); + + (function next() { + var filename = list[i++]; + if (!filename) return done(null, files); + var file = path.join(dir, filename); + fs.stat(file, function(err, stat) { + if (err && options.doneOnErr === true) return done(err); + if (stat && stat.isDirectory()) { + if (options.recursive) { + if (options.matchDir && !matches(filename, options.matchDir)) return next(); + if (options.excludeDir && matches(filename, options.excludeDir)) return next(); + readFilesStream(file, options, callback, function(err, sfiles) { + if (err && options.doneOnErr === true) return done(err); + files = files.concat(sfiles); + next(); + }); + } else next(); + } else if (stat && stat.isFile()) { + if (options.match && !matches(filename, options.match)) return next(); + if (options.exclude && matches(filename, options.exclude)) return next(); + if (options.filter && !options.filter(filename)) return next(); + if (options.shortName) files.push(filename); + else files.push(file); + var stream = fs.createReadStream(file); + if (options.encoding !== null) { + stream.setEncoding(options.encoding); + } + stream.on('error',function(err) { + if (options.doneOnErr === true) return done(err); + next(); + }); + if (callback.length > 3) + if (options.shortName) callback(null, stream, filename, next); + else callback(null, stream, file, next); + else callback(null, stream, next); + } + else { + next(); + } + }); + })(); + + }); +} +module.exports = readFilesStream; diff --git a/package-lock.json b/package-lock.json index 9aad30d..c74e85c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,405 @@ { "name": "path-reader", - "version": "1.0.4", - "lockfileVersion": 1, + "version": "1.1.0", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "path-reader", + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.4" + }, + "devDependencies": { + "@types/node": "^18.0.0", + "mocha": "3.5.0", + "should": "11.2.1", + "typescript": "^4.7.3" + }, + "engines": { + "node": ">= 0.10.5" + } + }, + "node_modules/@types/node": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz", + "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "node_modules/commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "dependencies": { + "graceful-readlink": ">= 1.0.0" + }, + "engines": { + "node": ">= 0.6.x" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "node_modules/growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "node_modules/has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "deprecated": "Please use the native JSON object instead of JSON 3", + "dev": true + }, + "node_modules/lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "dependencies": { + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, + "node_modules/lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "node_modules/lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "node_modules/lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "node_modules/lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "node_modules/lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "dependencies": { + "lodash._baseassign": "^3.0.0", + "lodash._basecreate": "^3.0.0", + "lodash._isiterateecall": "^3.0.0" + } + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "node_modules/lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "node_modules/lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "dependencies": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "dependencies": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.0.tgz", + "integrity": "sha512-pIU2PJjrPYvYRqVpjXzj76qltO9uBYI7woYAMoxbSefsa+vqAfptjoeevd6bUgwD0mPIO+hv9f7ltvsNreL2PA==", + "dev": true, + "dependencies": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.6.8", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.1", + "growl": "1.9.2", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 0.10.x", + "npm": ">= 1.4.x" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/should": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/should/-/should-11.2.1.tgz", + "integrity": "sha1-kPVRRVUtAc/CAGZuToGKHJZw7aI=", + "dev": true, + "dependencies": { + "should-equal": "^1.0.0", + "should-format": "^3.0.2", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "node_modules/should-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-1.0.1.tgz", + "integrity": "sha1-C26VFvJgGp+wuy3MNpr6HH4gCvc=", + "dev": true, + "dependencies": { + "should-type": "^1.0.0" + } + }, + "node_modules/should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "dev": true, + "dependencies": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "node_modules/should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "dev": true + }, + "node_modules/should-type-adaptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.0.1.tgz", + "integrity": "sha1-7+VVPN9oz/ZuXF9RtxLcNRx3vqo=", + "dev": true, + "dependencies": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "node_modules/should-util": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz", + "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", + "dev": true + }, + "node_modules/supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "dependencies": { + "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/typescript": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", + "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + }, "dependencies": { + "@types/node": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz", + "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -14,7 +410,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -30,7 +426,7 @@ "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", "dev": true, "requires": { - "graceful-readlink": "1.0.1" + "graceful-readlink": ">= 1.0.0" } }, "concat-map": { @@ -71,12 +467,12 @@ "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "graceful-readlink": { @@ -103,8 +499,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -125,8 +521,8 @@ "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", "dev": true, "requires": { - "lodash._basecopy": "3.0.1", - "lodash.keys": "3.1.2" + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" } }, "lodash._basecopy": { @@ -159,9 +555,9 @@ "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", "dev": true, "requires": { - "lodash._baseassign": "3.2.0", - "lodash._basecreate": "3.0.3", - "lodash._isiterateecall": "3.0.9" + "lodash._baseassign": "^3.0.0", + "lodash._basecreate": "^3.0.0", + "lodash._isiterateecall": "^3.0.0" } }, "lodash.isarguments": { @@ -182,9 +578,9 @@ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", "dev": true, "requires": { - "lodash._getnative": "3.9.1", - "lodash.isarguments": "3.1.0", - "lodash.isarray": "3.0.4" + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" } }, "minimatch": { @@ -192,7 +588,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -241,7 +637,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "path-is-absolute": { @@ -256,11 +652,11 @@ "integrity": "sha1-kPVRRVUtAc/CAGZuToGKHJZw7aI=", "dev": true, "requires": { - "should-equal": "1.0.1", - "should-format": "3.0.3", - "should-type": "1.4.0", - "should-type-adaptors": "1.0.1", - "should-util": "1.0.0" + "should-equal": "^1.0.0", + "should-format": "^3.0.2", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" } }, "should-equal": { @@ -269,7 +665,7 @@ "integrity": "sha1-C26VFvJgGp+wuy3MNpr6HH4gCvc=", "dev": true, "requires": { - "should-type": "1.4.0" + "should-type": "^1.0.0" } }, "should-format": { @@ -278,8 +674,8 @@ "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", "dev": true, "requires": { - "should-type": "1.4.0", - "should-type-adaptors": "1.0.1" + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" } }, "should-type": { @@ -294,8 +690,8 @@ "integrity": "sha1-7+VVPN9oz/ZuXF9RtxLcNRx3vqo=", "dev": true, "requires": { - "should-type": "1.4.0", - "should-util": "1.0.0" + "should-type": "^1.3.0", + "should-util": "^1.0.0" } }, "should-util": { @@ -310,9 +706,15 @@ "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", "dev": true, "requires": { - "has-flag": "1.0.0" + "has-flag": "^1.0.0" } }, + "typescript": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", + "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", + "dev": true + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index 5b38b94..c9dc7e2 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,20 @@ { "name": "path-reader", - "version": "1.1.0", + "version": "2.0.0", "description": "asynchronous file and directory operations for Node.js", - "main": "index", + "main": "lib/index", + "typings": "lib/index.d.ts", "homepage": "https://github.com/ackerapple", "repository": "https://github.com/ackerapple/path-reader", "directories": { "lib": "lib" }, "scripts": { - "test": "./node_modules/.bin/mocha --reporter spec" + "build": "rm -rf lib && tsc --project ./ts/tsconfig.json", + "test": "./node_modules/.bin/mocha --reporter spec", + "version:patch": "npm --no-git-tag-version version patch", + "save": "npm run build && npm run test && npm run version:patch && git add . && git commit -m \"update\" && git push", + "deploy": "npm run save && npm publish" }, "engines": { "node": ">= 0.10.5" @@ -29,7 +34,9 @@ "minimatch": "^3.0.4" }, "devDependencies": { + "@types/node": "^18.0.0", "mocha": "3.5.0", - "should": "11.2.1" + "should": "11.2.1", + "typescript": "^4.7.3" } } diff --git a/test/test.js b/test/test.js index 0881c44..a8f5d87 100644 --- a/test/test.js +++ b/test/test.js @@ -1275,7 +1275,7 @@ describe("files method", function() { }); }); - //NOT supported everywhere. Real hard to get working + // NOT supported everywhere. Real hard to get working it.skip("support non-UTF8 file names", function() { var files = dir.files(tdir5,'file', function(){}, {sync:true, excludeHidden:true}); var cmp = Buffer.from('testdir5'+path.sep+'testuções.txt', 'latin1').toString(); diff --git a/ts/index.ts b/ts/index.ts new file mode 100644 index 0000000..d55b44f --- /dev/null +++ b/ts/index.ts @@ -0,0 +1,3 @@ +export * from './paths' +export { readFiles } from './readfiles' +export { readFilesStream } from './readfilesstream' diff --git a/ts/paths.ts b/ts/paths.ts new file mode 100644 index 0000000..3467f65 --- /dev/null +++ b/ts/paths.ts @@ -0,0 +1,341 @@ +import * as fs from 'fs' +import * as path from 'path' + + +interface FileReadOptions { + basePath?: string + recursive?: boolean + excludeHidden?: boolean + sync?: boolean + ignoreType?: string + valuetizer?: (stat, shortName: string, longPath: string, isDir?: boolean) => any +} + +export function promiseFiles( + dir, + type, + options?: FileReadOptions, + statOptions?: fs.StatSyncOptions, +){ + switch(typeof type){ + case 'object': + options = type + type = 'file' + break; + + default:type = type || 'file' + } + + var processor = function(res,rej){ + var cb = function(err,data){ + if(err)return rej(err) + res(data) + } + exports.files(dir, type, cb, options, statOptions) + } + return new Promise(processor) +} + +/** + * find all files or subdirs (recursive) and pass to callback fn + * + * @param {string} dir directory in which to recurse files or subdirs + * @param {string} type type of dir entry to recurse ('file', 'dir', or 'all', defaults to 'file') + * @param {function(error, )} callback fn to call when done + * @example + * dir.files(__dirname, function(err, files) { + * if (err) throw err; + * console.log('files:', files); + * }); + */ +export function files( + dir, type, callback, + options?: FileReadOptions, + statOptions?: fs.StatSyncOptions, +) { + var ofType = typeof type + if(ofType == 'object'){ + options = options || type + type = 'file' + callback = function(){} + }else if (ofType !== 'string') { + //ignoreType = callback; + callback = type; + type = 'file'; + } + + options = options || {} as FileReadOptions + + var pending + var results = { + files: [], + dirs: [] + }; + + var done = function(_list?: any) { + if(type==='combine'){ + results = results.files.concat(results.dirs) as any + } else if (!type || options.ignoreType || ['all','combine'].indexOf(type)>=0) { + results = results + } else { + results = results[type + 's'] + } + + if(options.sync)return; + + callback(null, results); + }; + + /** + @statPath - fullPath + @name - fileName + @statHanOptions - { + valuetizer:function(stat, shortName, longPath){}, - function the handles value assignment + lstatCalled:false - used internally + } + */ + var getStatHandler = function( + statPath, + name, + statHanOptions, + ) { + return function(err, stat) { + if (err) { + if (!statHanOptions.lstatCalled) { + var newStatHanOptions = assign(statHanOptions, {lstatCalled:true}) + if(options.sync){ + var lstat = fs.lstatSync(statPath); + return getStatHandler(statPath, name, newStatHanOptions)(null, lstat) + }else{ + return fs.lstat(statPath, getStatHandler(statPath, name, newStatHanOptions)); + } + } + return callback(err); + } + + var isDir = stat && stat.isDirectory() && stat.mode !== 17115 + var pushVal = statHanOptions.valuetizer(stat, name, statPath, isDir)//options.shortName ? name : statPath + + if( pushVal==null ){ + if (!--pending){ + done(); + } + return + } + + if (isDir) { + if (type !== 'file') { + results.dirs.push(pushVal); + } + + if (options.recursive==null || options.recursive) { + var subloop = function(err, res) { + if (err){ + return callback(err) + } + + if(type === 'combine'){ + results.files = results.files.concat(res); + }else if (type === 'all') { + if( res.files ){//dont add things that are not there + results.files = results.files.concat(res.files); + } + results.dirs = results.dirs.concat(res.dirs); + } else if (type === 'file') { + if( res.files ){//dont add things that are not there + results.files = results.files.concat(res.files); + } + } else { + results.dirs = results.dirs.concat(res.dirs); + } + + if (!--pending){ + done(); + } + } + + var newOptions = assign({}, options) + newOptions.basePath = options.basePath || dir + newOptions.ignoreType = true + var moreResults = files(statPath, type, subloop, newOptions); + + if(options.sync){ + subloop(null, moreResults) + } + }else if (!--pending){ + done() + } + } else { + var excludeHidden = options.excludeHidden && name.split(path.sep).pop().search(/^\./)==0 + + if (type!=='dir' && !excludeHidden) { + results.files.push(pushVal); + } + // should be the last statement in statHandler + if (!--pending){ + done() + } + } + } + } + + const onDirRead = function( + err, + list, + statOptions?: fs.StatSyncOptions + ) { + if (err) return callback(err); + + pending = list.length; + if (!pending){ + done(list); + return list + } + + var statHanOptions: FileReadOptions = {} + if( options.valuetizer ){ + statHanOptions.valuetizer = options.valuetizer + }else{ + statHanOptions.valuetizer = getValuetizerByOptions(options, dir) + } + + for (var file, i = 0, l = list.length; i < l; i++) { + var fname = list[i].toString(); + file = path.join(dir, fname); + //var buffile = Buffer.concat([bufdir, Buffer.from(path.sep), list[i]]); + + if(options.sync){ + var res = fs.statSync(file, statOptions); + getStatHandler(file, list[i], statHanOptions)(null, res) + }else{ + fs.stat(file, getStatHandler(file, list[i], statHanOptions)); + } + } + + return results + } + + const onStat = function( + err, + stat, + statOptions?: fs.StatSyncOptions + ) { + if (err) return callback(err); + if (stat && stat.mode === 17115) return done(); + + if(options.sync){ + const list = fs.readdirSync(dir) + return onDirRead(null, list, statOptions) + }else{ + fs.readdir(dir, + (err: NodeJS.ErrnoException, files: string[]) => onDirRead(err, files, statOptions) + ) + } + } + + if(options.sync){ + const stat = fs.statSync(dir); + return onStat(null, stat, statOptions) + }else{ + fs.stat(dir, onStat); + } +}; + + +/** + * find all files and subdirs in a directory (recursive) and pass them to callback fn + * + * @param {string} dir directory in which to recurse files or subdirs + * @param {boolean} combine whether to combine both subdirs and filepaths into one array (default false) + * @param {function(error, Object.<, Array.>)} callback fn to call when done + * @example + * dir.paths(__dirname, function (err, paths) { + * if (err) throw err; + * console.log('files:', paths.files); + * console.log('subdirs:', paths.dirs); + * }); + * dir.paths(__dirname, true, function (err, paths) { + * if (err) throw err; + * console.log('paths:', paths); + * }); + */ +exports.paths = function paths(dir, combine, callback) { + if (typeof combine === 'function') { + callback = combine; + combine = false; + } + + files(dir, 'all', function(err, results) { + if (err) return callback(err); + if (combine) { + callback(null, results.files.concat(results.dirs)); + } else { + callback(null, results); + } + }); +}; + + +/** + * find all subdirs (recursive) of a directory and pass them to callback fn + * + * @param {string} dir directory in which to find subdirs + * @param {string} type type of dir entry to recurse ('file' or 'dir', defaults to 'file') + * @param {function(error, )} callback fn to call when done + * @example + * dir.subdirs(__dirname, function (err, paths) { + * if (err) throw err; + * console.log('files:', paths.files); + * console.log('subdirs:', paths.dirs); + * }); + */ +exports.subdirs = function subdirs(dir, callback, type, options) { + options = options || {} + + const iCallback = function(err, subdirs) { + if (err) return callback(err); + + if(type=='combine'){ + subdirs = subdirs.files.concat(subdirs.dirs) + } + + if(options.sync)return subdirs + + callback(null, subdirs); + } + + const res = exports.files(dir, 'dir', iCallback, options) + + if(options && options.sync){ + return iCallback(null,res) + } +} + +function assign(c0, c1){ + for(var x in c1)c0[x] = c1[x] + return c0 +} + +function getValuetizerByOptions(options, dir){ + if(options.shortName){ + if( options.shortName=='relative' ){ + var dirBase = (options.basePath||dir) + var startPos = dirBase.length + if(dirBase.substring(dirBase.length-path.sep.length, dirBase.length)!=path.sep){ + startPos = startPos + path.sep.length + } + + return function(stat, shortName, longPath, isDir){ + return longPath.substring(startPos, longPath.length) + } + }else{ + return function(stat, shortName, longPath){ + return shortName + } + } + } + + return function(stat, shortName, longPath){ + return longPath + } +} diff --git a/ts/readfiles.ts b/ts/readfiles.ts new file mode 100644 index 0000000..c0ca049 --- /dev/null +++ b/ts/readfiles.ts @@ -0,0 +1,133 @@ +import * as fs from 'fs' +import * as path from 'path' + +/** + * merge two objects by extending target object with source object + * @param target object to merge + * @param source object to merge + * @param {Boolean} [modify] whether to modify the target + * @returns {Object} extended object + */ +function extend(target, source, modify?: boolean) { + var result = target ? modify ? target : extend({}, target, true) : {}; + if (!source) return result; + for (var key in source) { + if (source.hasOwnProperty(key) && source[key] !== undefined) { + result[key] = source[key]; + } + } + return result; +} + +/** + * determine if a string is contained within an array or matches a regular expression + * @param {String} str string to match + * @param {Array|Regex} match array or regular expression to match against + * @returns {Boolean} whether there is a match + */ +function matches(str, match) { + if (Array.isArray(match)) return match.indexOf(str) > -1; + return match.test(str); +} + +/** + * read files and call a function with the contents of each file + * @param {String} dir path of dir containing the files to be read + * @param {String} encoding file encoding (default is 'utf8') + * @param {Object} options options hash for encoding, recursive, and match/exclude + * @param {Function(error, string)} callback callback for each files content + * @param {Function(error)} complete fn to call when finished + */ +export function readFiles(dir, options, callback, complete) { + if (typeof options === 'function') { + complete = callback; + callback = options; + options = {}; + } + if (typeof options === 'string') options = { + encoding: options + }; + options = extend({ + recursive: true, + encoding: 'utf8', + doneOnErr: true + }, options); + var files = []; + + var done = function(err?: Error, _result?: any) { + if (typeof complete === 'function') { + if (err) return complete(err); + complete(null, files); + } + }; + + fs.readdir(dir, function(err, list) { + if (err) { + if (options.doneOnErr === true) { + if (err.code === 'EACCES') return done(); + return done(err); + } + } + var i = 0; + + if (options.reverse === true || + (typeof options.sort == 'string' && + (/reverse|desc/i).test(options.sort))) { + list = list.reverse(); + } else if (options.sort !== false) list = list.sort(); + + (function next() { + var filename = list[i++]; + if (!filename) return done(null, files); + + var file = path.join(dir, filename); + + fs.stat(file, function(err, stat) { + if (err && options.doneOnErr === true) return done(err); + if (stat && stat.isDirectory()) { + if (options.recursive) { + if (options.matchDir && !matches(filename, options.matchDir)) return next(); + if (options.excludeDir && matches(filename, options.excludeDir)) return next(); + readFiles(file, options, callback, function(err, sfiles) { + if (err && options.doneOnErr === true) return done(err); + files = files.concat(sfiles); + next(); + }); + } else next(); + } else if (stat && stat.isFile()) { + if (options.match && !matches(filename, options.match)) return next(); + if (options.exclude && matches(filename, options.exclude)) return next(); + if (options.filter && !options.filter(filename)) return next(); + + if (options.shortName){ + files.push(filename); + }else{ + files.push(file); + } + + fs.readFile(file, options.encoding, function(err, data) { + if (err) { + if (err.code === 'EACCES') return next(); + if (options.doneOnErr === true) { + return done(err); + } + } + if (callback.length > 3){ + if (options.shortName){ + callback(null, data, filename, next); + }else{ + callback(null, data, file, next); + } + }else{ + callback(null, data, next); + } + }); + } + else { + next(); + } + }); + })(); + + }); +} diff --git a/ts/readfilesstream.ts b/ts/readfilesstream.ts new file mode 100644 index 0000000..b53e838 --- /dev/null +++ b/ts/readfilesstream.ts @@ -0,0 +1,131 @@ +var fs = require('fs'), + mm = require('minimatch') + +import * as path from 'path' + +/** + * merge two objects by extending target object with source object + * @param target object to merge + * @param source object to merge + * @param {Boolean} [modify] whether to modify the target + * @returns {Object} extended object + */ +function extend(target, source, modify?: boolean) { + var result = target ? modify ? target : extend({}, target, true) : {}; + if (!source) return result; + for (var key in source) { + if (source.hasOwnProperty(key) && source[key] !== undefined) { + result[key] = source[key]; + } + } + return result; +} + +/** + * determine if a string is contained within an array or matches a regular expression + * @param {String} str string to match + * @param {Array|Regex} match array or regular expression to match against + * @returns {Boolean} whether there is a match + */ +function matches(str, match) { + if (Array.isArray(match)) { + var l = match.length; + for( var s=0; s < l; s++) { + if ( mm(str,match[s])) { + return true; + } + } + return false; + } + return match.test(str); +} + +/** + * read files and call a function with the contents of each file + * @param {String} dir path of dir containing the files to be read + * @param {String} encoding file encoding (default is 'utf8') + * @param {Object} options options hash for encoding, recursive, and match/exclude + * @param {Function(error, string)} callback callback for each files content + * @param {Function(error)} complete fn to call when finished + */ +export function readFilesStream(dir, options, callback, complete) { + if (typeof options === 'function') { + complete = callback; + callback = options; + options = {}; + } + if (typeof options === 'string') options = { + encoding: options + }; + options = extend({ + recursive: true, + encoding: 'utf8', + doneOnErr: true + }, options); + var files = []; + + var done = function(err?: Error, _result?: any) { + if (typeof complete === 'function') { + if (err) return complete(err); + complete(null, files); + } + }; + + fs.readdir(dir, function(err, list) { + if (err) { + if (options.doneOnErr === true) { + if (err.code === 'EACCES') return done(); + return done(err); + } + } + var i = 0; + + if (options.reverse === true || + (typeof options.sort == 'string' && + (/reverse|desc/i).test(options.sort))) { + list = list.reverse(); + } else if (options.sort !== false) list = list.sort(); + + (function next() { + var filename = list[i++]; + if (!filename) return done(null, files); + var file = path.join(dir, filename); + fs.stat(file, function(err, stat) { + if (err && options.doneOnErr === true) return done(err); + if (stat && stat.isDirectory()) { + if (options.recursive) { + if (options.matchDir && !matches(filename, options.matchDir)) return next(); + if (options.excludeDir && matches(filename, options.excludeDir)) return next(); + readFilesStream(file, options, callback, function(err, sfiles) { + if (err && options.doneOnErr === true) return done(err); + files = files.concat(sfiles); + next(); + }); + } else next(); + } else if (stat && stat.isFile()) { + if (options.match && !matches(filename, options.match)) return next(); + if (options.exclude && matches(filename, options.exclude)) return next(); + if (options.filter && !options.filter(filename)) return next(); + if (options.shortName) files.push(filename); + else files.push(file); + var stream = fs.createReadStream(file); + if (options.encoding !== null) { + stream.setEncoding(options.encoding); + } + stream.on('error',function(err) { + if (options.doneOnErr === true) return done(err); + next(); + }); + if (callback.length > 3) + if (options.shortName) callback(null, stream, filename, next); + else callback(null, stream, file, next); + else callback(null, stream, next); + } + else { + next(); + } + }); + })(); + + }); +} diff --git a/ts/tsconfig.json b/ts/tsconfig.json new file mode 100644 index 0000000..805964a --- /dev/null +++ b/ts/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + "strict": false, + "strictPropertyInitialization": false, + "noUnusedLocals": true, + "rootDir": ".", + "removeComments": true, + "outDir": "../lib", + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": false, + "noEmitHelpers": false, + "noImplicitAny": false, + "declaration": true, + "skipLibCheck": true, + "stripInternal": true, + "noUnusedParameters": false, + "lib": ["dom", "es2015"], + "typeRoots": [ + "../node_modules/@types" + ] + }, + "exclude": [ + ], + "angularCompilerOptions": { + "skipMetadataEmit" : false, + "skipTemplateCodegen" : true + } +} \ No newline at end of file From a225bad67bfde951ae6e251ea20e4d945c5cda3e Mon Sep 17 00:00:00 2001 From: Acker Apple Date: Fri, 17 Jun 2022 09:59:54 -0400 Subject: [PATCH 36/37] update --- package-lock.json | 4 ++-- package.json | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index c74e85c..6905e95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "path-reader", - "version": "1.1.0", + "version": "2.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "path-reader", - "version": "1.1.0", + "version": "2.0.1", "license": "MIT", "dependencies": { "minimatch": "^3.0.4" diff --git a/package.json b/package.json index c9dc7e2..8a162d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "path-reader", - "version": "2.0.0", + "version": "2.0.1", "description": "asynchronous file and directory operations for Node.js", "main": "lib/index", "typings": "lib/index.d.ts", @@ -30,11 +30,13 @@ "Node.js", "fs" ], - "dependencies": { - "minimatch": "^3.0.4" + "peerDependencies": { + "minimatch": ">=3.0.4" + }, + "optionalDependencies": { + "@types/node": "^18.0.0" }, "devDependencies": { - "@types/node": "^18.0.0", "mocha": "3.5.0", "should": "11.2.1", "typescript": "^4.7.3" From 6a7f6db02e0c289ead6a08f9c9686ce93a601a34 Mon Sep 17 00:00:00 2001 From: Acker Apple Date: Fri, 17 Jun 2022 10:00:51 -0400 Subject: [PATCH 37/37] update --- package-lock.json | 4 ++-- package.json | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6905e95..9ac0dfa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "path-reader", - "version": "2.0.1", + "version": "2.0.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "path-reader", - "version": "2.0.1", + "version": "2.0.2", "license": "MIT", "dependencies": { "minimatch": "^3.0.4" diff --git a/package.json b/package.json index 8a162d9..a49ec73 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "path-reader", - "version": "2.0.1", + "version": "2.0.2", "description": "asynchronous file and directory operations for Node.js", "main": "lib/index", "typings": "lib/index.d.ts", @@ -30,8 +30,8 @@ "Node.js", "fs" ], - "peerDependencies": { - "minimatch": ">=3.0.4" + "dependencies": { + "minimatch": "^3.0.4" }, "optionalDependencies": { "@types/node": "^18.0.0"