Skip to content

Commit

Permalink
Breaking: Refactor and cleanup library
Browse files Browse the repository at this point in the history
  • Loading branch information
jonschlinkert authored and phated committed Dec 21, 2018
1 parent 977a271 commit d53784a
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 59 deletions.
33 changes: 20 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@
[![NPM](https://nodei.co/npm/empty-dir.png)](https://nodei.co/npm/empty-dir/)

Note that directories with `.DS_Store` on mac are considered empty.
## Install

Install with [npm](https://www.npmjs.com/):

```sh
$ npm install --save empty-dir
```

## Usage

## Example
```js
const emptyDir = require('empty-dir');
var emptyDir = require('empty-dir');

emptyDir('./', function (err, result) {
if (err) {
Expand All @@ -21,32 +28,32 @@ var result = emptyDir.sync('./test/empty');
console.log('Directory is empty:', result);
```

**Filter function**
## Filter function

Both async and sync take a filter function as the second argument.
Both async and sync take a filter function as the second argument, to ignore files like `.DS_Store` on mac or `Thumbs.db` on windows from causing false-negatives.

_(This gives you the ability to eliminate files like `.DS_Store` on mac, or `Thumbs.db` on windows from causing the result to be "not empty" (`.DS_Store` is already filtered by default).)_

```js
const emptyDir = require('empty-dir');
var emptyDir = require('empty-dir');

function filter(filepath) {
return !/Thumbs\.db$/i.test(filepath);
return !/(Thumbs\.db|\.DS_Store)$/i.test(filepath);
}

emptyDir('./', filter, function (err, result) {
emptyDir('./', filter, function (err, isEmpty) {
if (err) {
console.error(err);
} else {
console.log('Directory is empty:', result);
console.log('Directory is empty:', isEmpty);
}
});

var result = emptyDir.sync('./test/empty', filter);
console.log('Directory is empty:', result);
var isEmpty = emptyDir.sync('./test/empty', filter);
console.log('Directory is empty:', isEmpty);
```

## Release History

* 2014-05-08 - v0.1.0 - initial release
* 2018-03-09 - v1.0.0 - refactored "isEmpty" logic so that it returns early, as soon as a non-filtered file is encountered, instead of filtering the entire list and comparing against length. Also allows an array to be passed (this avoids having to call `fs.readdir()` multiple times).
* 2016-02-07 - v0.2.0 - add filter support
* 2014-05-08 - v0.1.0 - initial release
103 changes: 79 additions & 24 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,98 @@
const fs = require('fs');
const exists = require('fs-exists-sync');
'use strict';

function isEmpty(path, fn, callback) {
var fs = require('fs');

function emptyDir(dir, filter, cb) {
if (arguments.length === 2) {
callback = fn;
fn = null;
cb = filter;
filter = null;
}

if (typeof cb !== 'function') {
throw new TypeError('expected callback to be a function');
}

if (!exists(path)) {
callback(null, false);
if (Array.isArray(dir)) {
cb(null, isEmpty(dir, filter));
return;
}

fs.readdir(path, function(err, files) {
if (err) {
callback(err);
return;
}
if (typeof dir !== 'string') {
cb(new TypeError('expected a directory or array of files'));
return;
}

if (typeof fn === 'function') {
files = files.filter(fn);
fs.stat(dir, function(err, stat) {
if (err || !stat.isDirectory()) {
cb(null, false);
return;
}

callback(null, files.length === 0);
fs.readdir(dir, function(err, files) {
cb(err, isEmpty(files, filter));
});
});
}

isEmpty.sync = function(path, fn) {
if (!exists(path)) {
/**
* Return true if the given `files` array has zero length or only
* includes unwanted files.
*/

function emptyDirSync(dir, filter) {
if (Array.isArray(dir)) {
return isEmpty(dir, filter);
}

if (typeof dir !== 'string') {
throw new TypeError('expected a directory or array of files');
}

if (!isDirectory(dir)) {
return false;
}
try {
var files = fs.readdirSync(path);
if (typeof fn === 'function') {
files = files.filter(fn);

var files = fs.readdirSync(dir);
return isEmpty(files, filter);
}

/**
* Returns true if the given "files" array is empty or only
* contains unwanted files.
*/

function isEmpty(files, filter) {
if (files.length === 0) {
return true;
}

if (typeof filter !== 'function') {
return false;
}

for (var i = 0; i < files.length; ++i) {
if (filter(files[i]) === false) {
return false;
}
return files.length === 0;
}
return true;
}

/**
* Returns true if the filepath exists and is a directory
*/

function isDirectory(filepath) {
try {
return fs.statSync(filepath).isDirectory();
} catch (err) {}
return false;
};
}

/**
* Expose `emptyDir`
*/

module.exports = isEmpty;
module.exports = emptyDir;
module.exports.sync = emptyDirSync;
module.exports.isEmpty = isEmpty;
19 changes: 8 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,13 @@
"scripts": {
"test": "mocha"
},
"dependencies": {
"fs-exists-sync": "^0.1.0"
},
"devDependencies": {
"chai": "^3.5.0",
"mocha": "^3.2.0"
},
"keywords": [
"empty directory",
"empty dir",
"empty folder"
]
"empty",
"is-empty",
"directory",
"folder"
],
"devDependencies": {
"mocha": "^3.5.3"
}
}
64 changes: 53 additions & 11 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,74 @@
const emptyDir = require('../');
const expect = require('chai').expect;
const fs = require('fs');
var emptyDir = require('../');
var assert = require('assert');
var path = require('path');
var fs = require('fs');

try {
fs.mkdirSync('./test/empty');
fs.mkdirSync(path.join(__dirname, 'empty'));
} catch (e) {}

function isGarbageFile(filename) {
return /(?:Thumbs\.db|\.DS_Store)$/i.test(filename);
}

describe('emptyDir', function () {
it('should throw when a callback is not passed', function () {
assert.throws(function() {
emptyDir('./')
}, /expected/);
});

it('should throw when invalid arguments are passed', function (done) {
assert.throws(function() {
emptyDir.sync(null);
});

emptyDir(null, function(err) {
assert(err);
assert(/expected/.test(err.message));
done();
});
});

it('should take an array', function (done) {
assert(!emptyDir.sync(['Thumbs.db', '.DS_Store']));
emptyDir(['Thumbs.db', '.DS_Store'], function(err, empty) {
assert(!empty);
done();
});
});

it('should take a filter function to exclude files', function (done) {
assert(emptyDir.sync(['Thumbs.db', '.DS_Store'], isGarbageFile));
assert(!emptyDir.sync(['Thumbs.db', '.DS_Store', 'foo'], isGarbageFile));

emptyDir(['Thumbs.db', '.DS_Store'], isGarbageFile, function(err, empty) {
assert(empty);
done();
});
});

it('should call back with true if a directory is empty', function (done) {
expect(emptyDir.sync('./')).to.be.false;
emptyDir('./', function (err, empty) {
expect(empty).to.be.false;
assert(!emptyDir.sync('./'));
emptyDir('./', function(err, empty) {
assert(!empty);
done();
});
});

it('should be false if a directory does not exist', function (done) {
expect(emptyDir.sync('./foo/bar/baz')).to.be.false;
assert(!emptyDir.sync('./foo/bar/baz'));
emptyDir('./foo/bar/baz', function (err, empty) {
expect(empty).to.be.false;
assert(!empty);
done();
});
});

it('should call back with false if a directory is not empty', function (done) {
expect(emptyDir.sync('./test/empty')).to.be.true;
assert(!emptyDir.sync('./test'));
assert(emptyDir.sync('./test/empty'));
emptyDir('./test/empty', function (err, empty) {
expect(empty).to.be.true;
assert(empty);
done();
});
});
Expand Down

0 comments on commit d53784a

Please sign in to comment.