Socket
Socket
Sign inDemoInstall

delete-empty

Package Overview
Dependencies
Maintainers
2
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

delete-empty - npm Package Compare versions

Comparing version 2.0.0 to 3.0.0

76

bin/cli.js
#!/usr/bin/env node
var ok = require('log-ok');
var deleteEmpty = require('..');
var argv = process.argv.slice(2);
var args = argv.filter(arg => (arg !== '-d' && arg !== '--dry-run'));
var cwd = args[0] || process.cwd();
var dryRun = argv.length !== args.length;
const os = require('os');
const path = require('path');
const { cyan, bold, dim, green, symbols } = require('ansi-colors');
const deleteEmpty = require('..');
const argv = require('minimist')(process.argv.slice(2), {
boolean: true,
number: true,
alias: { d: 'dryRun' },
rename: { _: 'files' }
});
deleteEmpty(cwd, { dryRun: dryRun }, function(err, files) {
if (err) {
console.error(err);
process.exit(1);
}
const moduleDir = dim(`<${path.dirname(__dirname)}>`);
const name = pkg => bold(`delete-empty v${pkg.version}`);
const help = pkg => `
Path: <${path.dirname(__dirname)}>
if (dryRun) {
console.log('Dry run. Empty directories (not deleted):');
for (var file in files) ok(files[file]);
console.log('Total: ', files.length);
Usage: ${cyan('$ delete-empty <directory> [options]')}
Directory: (optional) Initial directory to begin the search for empty
directories. Otherwise, cwd is used.
[Options]:
-c, --cwd Set the current working directory for folders to search.
-d, --dryRun Do a dry run without deleting any files.
-h, --help Display this help menu
-V, --version Display the current version of rename
-v, --verbose Display all verbose logging messages (currently not used)
`;
if (argv.help) {
console.log(help(require('../package')));
process.exit();
}
const ok = green(symbols.check);
const cwd = path.resolve(argv._[0] || argv.cwd || process.cwd());
const relative = filepath => {
if (filepath.startsWith(cwd)) {
return path.relative(cwd, filepath);
}
if (filepath.startsWith(os.homedir())) {
return path.join('~', filepath.slice(os.homedir().length));
}
return cwd;
};
console.log('Done');
process.exit();
});
if (argv.dryRun) {
argv.verbose = true;
}
let count = 0;
argv.onDirectory = () => (count++);
deleteEmpty(cwd, argv)
.then(files => {
console.log(ok, 'Deleted', files.length, 'of', count, 'directories');
process.exit();
})
.catch(err => {
console.error(err);
process.exit(1);
});
/*!
* delete-empty <https://github.com/jonschlinkert/delete-empty>
*
* Copyright (c) 2015, 2017-2018, Jon Schlinkert.
* Copyright (c) 2015-present, Jon Schlinkert
* Released under the MIT License.

@@ -13,27 +12,39 @@ */

const path = require('path');
const ok = require('log-ok');
const relative = require('relative');
const rimraf = require('rimraf');
const startsWith = require('path-starts-with');
const colors = require('ansi-colors');
const readdir = util.promisify(fs.readdir);
const del = util.promisify(rimraf);
function deleteEmpty(cwd, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
/**
* Helpers
*/
const GARBAGE_REGEX = /(?:Thumbs\.db|\.DS_Store)$/i;
const isGarbageFile = (file, regex = GARBAGE_REGEX) => regex.test(file);
const filterGarbage = (file, regex) => !isGarbageFile(file, regex);
const isValidDir = (cwd, dir, empty) => {
return !empty.includes(dir) && startsWith(dir, cwd) && isDirectory(dir);
};
const deleteDir = async (dirname, options = {}) => {
if (options.dryRun !== true) {
return new Promise((resolve, reject) => {
rimraf(dirname, { ...options, glob: false }, err => {
if (err) {
reject(err);
} else {
resolve();
}
});
})
}
};
const promise = deleteEmpty.promise(cwd, options);
if (typeof callback === 'function') {
promise.then(acc => callback(null, acc)).catch(callback);
return;
const deleteDirSync = (dirname, options = {}) => {
if (options.dryRun !== true) {
return rimraf.sync(dirname, { ...options, glob: false });
}
return promise;
}
};
deleteEmpty.promise = function(cwd, options) {
const opts = Object.assign({}, options);
const dirname = path.resolve(cwd);
const acc = [];
const deleteEmpty = (cwd, options, cb) => {
if (typeof cwd !== 'string') {

@@ -43,43 +54,53 @@ return Promise.reject(new TypeError('expected the first argument to be a string'));

async function remove(filepath) {
const dir = path.resolve(filepath);
if (typeof options === 'function') {
cb = options;
options = null;
}
if (dir.indexOf(dirname) !== 0 || acc.indexOf(dir) !== -1 || !isDirectory(dir)) {
return Promise.resolve(acc);
}
if (typeof cb === 'function') {
return deleteEmpty(cwd, options)
.then(res => cb(null, res))
.catch(cb);
}
return await readdir(dir)
.then(async files => {
if (isEmpty(files, dir, acc, opts)) {
acc.push(dir);
const opts = options || {};
const dirname = path.resolve(cwd);
const onDirectory = opts.onDirectory || (() => {});
const empty = [];
if (opts.dryRun === true) {
return remove(path.dirname(dir));
}
const remove = async filepath => {
let dir = path.resolve(filepath);
return del(dir)
.then(() => {
if (opts.verbose === true) {
ok('deleted:', relative(dir));
}
return remove(path.dirname(dir));
});
if (!isValidDir(cwd, dir, empty)) return;
onDirectory(dir);
} else {
for (const file of files) {
await remove(path.join(dir, file));
}
return Promise.resolve(acc);
}
});
}
let files = await readdir(dir);
return remove(dirname).then(acc);
if (isEmpty(dir, files, empty, opts)) {
empty.push(dir);
await deleteDir(dir, opts);
if (opts.verbose === true) {
console.log(colors.red('Deleted:'), path.relative(cwd, dir));
}
if (typeof opts.onDelete === 'function') {
await opts.onDelete(dir);
}
return remove(path.dirname(dir));
}
for (const file of files) {
await remove(path.join(dir, file));
}
return empty;
};
return remove(dirname);
};
deleteEmpty.sync = function(cwd, options) {
const opts = Object.assign({}, options);
const dirname = path.resolve(cwd);
const acc = [];
deleteEmpty.sync = (cwd, options) => {
if (typeof cwd !== 'string') {

@@ -89,34 +110,40 @@ throw new TypeError('expected the first argument to be a string');

function remove(filepath) {
const dir = path.resolve(filepath);
const opts = options || {};
const dirname = path.resolve(cwd);
const deleted = [];
const empty = [];
if (dir.indexOf(dirname) !== 0 || acc.indexOf(dir) !== -1 || !isDirectory(dir)) {
return acc;
const remove = filepath => {
let dir = path.resolve(filepath);
if (!isValidDir(cwd, dir, empty)) {
return empty;
}
const files = fs.readdirSync(dir);
let files = fs.readdirSync(dir);
if (isEmpty(files, dir, acc, opts)) {
acc.push(dir);
if (isEmpty(dir, files, empty, opts)) {
empty.push(dir);
if (opts.dryRun === true) {
return remove(path.dirname(dir));
}
deleteDirSync(dir, opts);
rimraf.sync(dir);
if (opts.verbose === true) {
ok('deleted:', relative(dir));
console.log(colors.red('Deleted:'), path.relative(cwd, dir));
}
return remove(path.dirname(dir));
} else {
for (const file of files) {
remove(path.join(dir, file));
if (typeof opts.onDelete === 'function') {
opts.onDelete(dir);
}
return acc;
return remove(path.dirname(dir));
}
}
for (let filepath of files) {
remove(path.join(dir, filepath));
}
return empty;
};
remove(dirname);
return acc;
return empty;
};

@@ -129,11 +156,10 @@

function isEmpty(files, dir, acc, opts) {
var filter = opts.filter || isGarbageFile;
for (const file of files) {
const fp = path.join(dir, file);
const isEmpty = (dir, files, empty, options = {}) => {
let filter = options.filter || filterGarbage;
let regex = options.junkRegex;
if (opts.dryRun && acc.indexOf(fp) !== -1) {
continue;
}
if (filter(fp) === false) {
for (let basename of files) {
let filepath = path.join(dir, basename);
if (!(options.dryRun && empty.includes(filepath)) && filter(filepath, regex) === true) {
return false;

@@ -143,3 +169,3 @@ }

return true;
}
};

@@ -150,19 +176,10 @@ /**

function isDirectory(dir) {
const isDirectory = dir => {
try {
return fs.statSync(dir).isDirectory();
} catch (err) {
return false;
}
}
} catch (err) { /* do nothing */ }
return false;
};
/**
* Returns true if the file is a garbage file that can be deleted
*/
function isGarbageFile(filename) {
return /(?:Thumbs\.db|\.DS_Store)$/i.test(filename);
}
/**
* Expose deleteEmpty

@@ -169,0 +186,0 @@ */

{
"name": "delete-empty",
"description": "Recursively delete all empty folders in a directory and child directories.",
"version": "2.0.0",
"version": "3.0.0",
"homepage": "https://github.com/jonschlinkert/delete-empty",

@@ -26,3 +26,3 @@ "author": "Jon Schlinkert (https://github.com/jonschlinkert)",

"engines": {
"node": ">=6"
"node": ">=10"
},

@@ -33,11 +33,12 @@ "scripts": {

"dependencies": {
"log-ok": "^0.1.1",
"relative": "^3.0.2",
"ansi-colors": "^4.1.0",
"minimist": "^1.2.0",
"path-starts-with": "^2.0.0",
"rimraf": "^2.6.2"
},
"devDependencies": {
"async-each-series": "^1.1.0",
"@folder/readdir": "^2.0.0",
"gulp-format-md": "^1.0.0",
"matched": "^1.0.2",
"mocha": "^3.5.3"
"mocha": "^3.5.3",
"write": "^1.0.3"
},

@@ -58,3 +59,3 @@ "keywords": [

"run": true,
"toc": false,
"toc": true,
"layout": "default",

@@ -61,0 +62,0 @@ "tasks": [

@@ -1,2 +0,2 @@

# delete-empty [![NPM version](https://img.shields.io/npm/v/delete-empty.svg?style=flat)](https://www.npmjs.com/package/delete-empty) [![NPM monthly downloads](https://img.shields.io/npm/dm/delete-empty.svg?style=flat)](https://npmjs.org/package/delete-empty) [![NPM total downloads](https://img.shields.io/npm/dt/delete-empty.svg?style=flat)](https://npmjs.org/package/delete-empty) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/delete-empty.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/delete-empty)
# delete-empty [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=W8YFZ425KND68) [![NPM version](https://img.shields.io/npm/v/delete-empty.svg?style=flat)](https://www.npmjs.com/package/delete-empty) [![NPM monthly downloads](https://img.shields.io/npm/dm/delete-empty.svg?style=flat)](https://npmjs.org/package/delete-empty) [![NPM total downloads](https://img.shields.io/npm/dt/delete-empty.svg?style=flat)](https://npmjs.org/package/delete-empty) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/delete-empty.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/delete-empty)

@@ -7,2 +7,13 @@ > Recursively delete all empty folders in a directory and child directories.

- [Install](#install)
- [Usage](#usage)
- [API](#api)
* [async-await (promise)](#async-await-promise)
* [async callback](#async-callback)
* [sync](#sync)
- [CLI](#cli)
- [About](#about)
_(TOC generated by [verb](https://github.com/verbose/verb) using [markdown-toc](https://github.com/jonschlinkert/markdown-toc))_
## Install

@@ -22,19 +33,2 @@

## CLI
To use the `delete-empty` command from any directory you must first install the package globally with the following command:
```sh
$ npm install --global delete-empty
```
**Usage**
```sh
$ delete-empty [<cwd>] [--dry-run|-d]
```
* `<cwd>` (optional) - initial directory to begin the search for empty directories. By default, the current working directory (`process.cwd()`) is used (note that `process.cwd()` is only used as the default by the CLI).
* `-d, --dry-run` (optional) - output empty directories to the terminal, does not delete anything
## API

@@ -57,3 +51,3 @@

### async promise
### async-await (promise)

@@ -63,2 +57,8 @@ If no callback is passed, a promise is returned. Returns the array of deleted directories.

```js
(async () => {
let deleted = await deleteEmpty('foo');
console.log(deleted); //=> ['foo/aa/', 'foo/a/cc/', 'foo/b/', 'foo/c/']
})();
// or
deleteEmpty('foo/')

@@ -74,3 +74,3 @@ .then(deleted => console.log(deleted)) //=> ['foo/aa/', 'foo/a/cc/', 'foo/b/', 'foo/c/']

```js
deleteEmpty('foo/', function(err, deleted) {
deleteEmpty('foo/', (err, deleted) => {
console.log(deleted); //=> ['foo/aa/', 'foo/a/cc/', 'foo/b/', 'foo/c/']

@@ -88,2 +88,27 @@ });

## CLI
To use the `delete-empty` command from any directory you must first install the package globally with the following command:
```sh
$ npm install --global delete-empty
```
**Usage**
```
Usage: $ delete-empty <directory> [options]
Directory: (optional) Initial directory to begin the search for empty
directories. Otherwise, cwd is used.
[Options]:
-c, --cwd Set the current working directory for folders to search.
-d, --dryRun Do a dry run without deleting any files.
-h, --help Display this help menu
-V, --version Display the current version of rename
-v, --verbose Display all verbose logging messages (currently not used)
```
## About

@@ -133,9 +158,9 @@

| **Commits** | **Contributor** |
| --- | --- |
| 27 | [jonschlinkert](https://github.com/jonschlinkert) |
| 2 | [treble-snake](https://github.com/treble-snake) |
| 1 | [doowb](https://github.com/doowb) |
| 1 | [svenschoenung](https://github.com/svenschoenung) |
| 1 | [vpalmisano](https://github.com/vpalmisano) |
| **Commits** | **Contributor** |
| --- | --- |
| 31 | [jonschlinkert](https://github.com/jonschlinkert) |
| 2 | [treble-snake](https://github.com/treble-snake) |
| 1 | [doowb](https://github.com/doowb) |
| 1 | [svenschoenung](https://github.com/svenschoenung) |
| 1 | [vpalmisano](https://github.com/vpalmisano) |

@@ -146,9 +171,9 @@ ### Author

* [linkedin/in/jonschlinkert](https://linkedin.com/in/jonschlinkert)
* [github/jonschlinkert](https://github.com/jonschlinkert)
* [twitter/jonschlinkert](https://twitter.com/jonschlinkert)
* [GitHub Profile](https://github.com/jonschlinkert)
* [Twitter Profile](https://twitter.com/jonschlinkert)
* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)
### License
Copyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert).
Copyright © 2019, [Jon Schlinkert](https://github.com/jonschlinkert).
Released under the [MIT License](LICENSE).

@@ -158,2 +183,2 @@

_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on February 16, 2018._
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on July 02, 2019._

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc