├── test ├── fixtures │ └── paths │ │ ├── a │ │ ├── aa │ │ │ ├── two.txt │ │ │ └── aaa │ │ │ │ ├── .gitkeep │ │ │ │ └── aaaa │ │ │ │ └── .gitkeep │ │ └── one.txt │ │ ├── b │ │ └── .gitkeep │ │ ├── c │ │ └── .gitkeep │ │ └── nested │ │ ├── Thumbs.db │ │ ├── nested │ │ ├── Thumbs.db │ │ └── with │ │ │ ├── Thumbs.db │ │ │ └── folders │ │ │ ├── Thumbs.db │ │ │ └── that │ │ │ ├── Thumbs.db │ │ │ └── have │ │ │ ├── Thumbs.db │ │ │ └── only │ │ │ ├── Thumbs.db │ │ │ └── junk │ │ │ └── Thumbs.db │ │ └── with │ │ ├── Thumbs.db │ │ ├── nested │ │ ├── Thumbs.db │ │ └── with │ │ │ ├── Thumbs.db │ │ │ └── folders │ │ │ ├── Thumbs.db │ │ │ └── that │ │ │ ├── Thumbs.db │ │ │ └── have │ │ │ ├── Thumbs.db │ │ │ └── only │ │ │ ├── Thumbs.db │ │ │ └── junk │ │ │ └── Thumbs.db │ │ └── folders │ │ ├── Thumbs.db │ │ ├── nested │ │ ├── Thumbs.db │ │ └── with │ │ │ ├── Thumbs.db │ │ │ └── folders │ │ │ ├── Thumbs.db │ │ │ └── that │ │ │ ├── Thumbs.db │ │ │ └── have │ │ │ ├── Thumbs.db │ │ │ └── only │ │ │ ├── Thumbs.db │ │ │ └── junk │ │ │ └── Thumbs.db │ │ └── that │ │ ├── Thumbs.db │ │ ├── have │ │ ├── Thumbs.db │ │ ├── nested │ │ │ ├── Thumbs.db │ │ │ └── with │ │ │ │ ├── Thumbs.db │ │ │ │ └── folders │ │ │ │ ├── Thumbs.db │ │ │ │ └── that │ │ │ │ ├── Thumbs.db │ │ │ │ └── have │ │ │ │ ├── Thumbs.db │ │ │ │ └── only │ │ │ │ ├── Thumbs.db │ │ │ │ └── junk │ │ │ │ └── Thumbs.db │ │ └── only │ │ │ ├── Thumbs.db │ │ │ └── junk │ │ │ └── Thumbs.db │ │ └── nested │ │ ├── Thumbs.db │ │ └── with │ │ ├── Thumbs.db │ │ └── folders │ │ ├── Thumbs.db │ │ └── that │ │ ├── Thumbs.db │ │ └── have │ │ ├── Thumbs.db │ │ └── only │ │ ├── Thumbs.db │ │ └── junk │ │ └── Thumbs.db ├── support │ └── copy.js └── test.js ├── .travis.yml ├── .gitattributes ├── .editorconfig ├── examples ├── sync.js └── async.js ├── .gitignore ├── LICENSE ├── bin └── cli.js ├── .verb.md ├── package.json ├── .eslintrc.json ├── index.js └── README.md /test/fixtures/paths/a/aa/two.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/a/one.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/b/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/c/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/a/aa/aaa/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/a/aa/aaa/aaaa/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/nested/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/nested/with/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/nested/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/nested/with/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/nested/with/folders/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/nested/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/nested/with/folders/that/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/nested/with/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/have/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/nested/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/nested/with/folders/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/nested/with/folders/that/have/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/have/nested/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/have/only/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/nested/with/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/nested/with/folders/that/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/nested/with/folders/that/have/only/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/nested/with/folders/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/have/nested/with/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/have/only/junk/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/nested/with/folders/that/have/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/nested/with/folders/that/have/only/junk/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/nested/with/folders/that/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/nested/with/folders/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/nested/with/folders/that/have/only/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/nested/with/folders/that/have/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/have/nested/with/folders/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/nested/with/folders/that/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/nested/with/folders/that/have/only/junk/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/nested/with/folders/that/have/only/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/have/nested/with/folders/that/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/nested/with/folders/that/have/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/nested/with/folders/that/have/only/junk/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/have/nested/with/folders/that/have/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/nested/with/folders/that/have/only/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/have/nested/with/folders/that/have/only/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/nested/with/folders/that/have/only/junk/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/paths/nested/with/folders/that/have/nested/with/folders/that/have/only/junk/Thumbs.db: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | os: 3 | - linux 4 | - osx 5 | - windows 6 | language: node_js 7 | node_js: 8 | - node 9 | - '12' 10 | - '10' 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Enforce Unix newlines 2 | * text eol=lf 3 | 4 | # binaries 5 | *.ai binary 6 | *.psd binary 7 | *.jpg binary 8 | *.gif binary 9 | *.png binary 10 | *.jpeg binary 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org/ 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = true 14 | insert_final_newline = true 15 | -------------------------------------------------------------------------------- /examples/sync.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var copy = require('../test/support/copy'); 4 | var deleteEmpty = require('..'); 5 | 6 | copy('test/fixtures', 'test/temp', function(err) { 7 | if (err) return console.log(err); 8 | console.log('copied fixtures'); 9 | 10 | var deleted = deleteEmpty.sync('test/temp'); 11 | console.log('deleted', deleted); 12 | }); 13 | -------------------------------------------------------------------------------- /examples/async.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var copy = require('../test/support/copy'); 4 | var deleteEmpty = require('..'); 5 | 6 | copy('test/fixtures', 'test/temp', function(err) { 7 | if (err) return console.log(err); 8 | console.log('copied fixtures'); 9 | 10 | deleteEmpty('test/temp', function(err, deleted) { 11 | if (err) return console.log(err); 12 | console.log('deleted', deleted); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # always ignore files 2 | *.DS_Store 3 | .idea 4 | .vscode 5 | *.sublime-* 6 | 7 | # test related, or directories generated by tests 8 | test/actual 9 | actual 10 | coverage 11 | .nyc* 12 | 13 | # npm 14 | node_modules 15 | npm-debug.log 16 | 17 | # yarn 18 | yarn.lock 19 | yarn-error.log 20 | 21 | # misc 22 | _gh_pages 23 | _draft 24 | _drafts 25 | bower_components 26 | vendor 27 | temp 28 | tmp 29 | TODO.md 30 | package-lock.json -------------------------------------------------------------------------------- /test/support/copy.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const readdir = require('@folder/readdir'); 6 | const write = require('write'); 7 | 8 | module.exports = async (cwd, destDir) => { 9 | const filter = file => file.name !== '.gitkeep'; 10 | const files = await readdir(cwd, { recursive: true, objects: true, absolute: true, filter }); 11 | 12 | for (let file of files) { 13 | let destPath = path.resolve(destDir, path.relative(cwd, file.path)); 14 | if (fs.existsSync(destPath)) continue; 15 | 16 | if (file.isDirectory()) { 17 | fs.mkdirSync(destPath, { recursive: true }); 18 | } else { 19 | write.sync(destPath, fs.readFileSync(file.path)); 20 | } 21 | } 22 | 23 | return files; 24 | }; 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-present, Jon Schlinkert. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /bin/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const os = require('os'); 4 | const path = require('path'); 5 | const { cyan, bold, dim, green, symbols } = require('ansi-colors'); 6 | const deleteEmpty = require('..'); 7 | const argv = require('minimist')(process.argv.slice(2), { 8 | boolean: true, 9 | number: true, 10 | alias: { d: 'dryRun' }, 11 | rename: { _: 'files' } 12 | }); 13 | 14 | const moduleDir = dim(`<${path.dirname(__dirname)}>`); 15 | const name = pkg => bold(`delete-empty v${pkg.version}`); 16 | const help = pkg => ` 17 | Path: <${path.dirname(__dirname)}> 18 | 19 | Usage: ${cyan('$ delete-empty [options]')} 20 | 21 | Directory: (optional) Initial directory to begin the search for empty 22 | directories. Otherwise, cwd is used. 23 | 24 | [Options]: 25 | -c, --cwd Set the current working directory for folders to search. 26 | -d, --dryRun Do a dry run without deleting any files. 27 | -h, --help Display this help menu 28 | -V, --version Display the current version of rename 29 | -v, --verbose Display all verbose logging messages (currently not used) 30 | `; 31 | 32 | if (argv.help) { 33 | console.log(help(require('../package'))); 34 | process.exit(); 35 | } 36 | 37 | const ok = green(symbols.check); 38 | const cwd = path.resolve(argv._[0] || argv.cwd || process.cwd()); 39 | const relative = filepath => { 40 | if (filepath.startsWith(cwd)) { 41 | return path.relative(cwd, filepath); 42 | } 43 | if (filepath.startsWith(os.homedir())) { 44 | return path.join('~', filepath.slice(os.homedir().length)); 45 | } 46 | return cwd; 47 | }; 48 | 49 | if (argv.dryRun) { 50 | argv.verbose = true; 51 | } 52 | 53 | let count = 0; 54 | argv.onDirectory = () => (count++); 55 | 56 | deleteEmpty(cwd, argv) 57 | .then(files => { 58 | console.log(ok, 'Deleted', files.length, 'of', count, 'directories'); 59 | process.exit(); 60 | }) 61 | .catch(err => { 62 | console.error(err); 63 | process.exit(1); 64 | }); 65 | -------------------------------------------------------------------------------- /.verb.md: -------------------------------------------------------------------------------- 1 | ## Usage 2 | 3 | ```js 4 | const deleteEmpty = require('{%= name %}'); 5 | ``` 6 | 7 | ## API 8 | 9 | Given the following directory structure, the **highlighted directories** would be deleted. 10 | 11 | ```diff 12 | foo/ 13 | └─┬ a/ 14 | - ├── aa/ 15 | ├── bb/ 16 | │ └─┬ bbb/ 17 | │ │ ├── one.txt 18 | │ │ └── two.txt 19 | - ├── cc/ 20 | - ├ b/ 21 | - └ c/ 22 | ``` 23 | 24 | ### async-await (promise) 25 | 26 | If no callback is passed, a promise is returned. Returns the array of deleted directories. 27 | 28 | ```js 29 | (async () => { 30 | let deleted = await deleteEmpty('foo'); 31 | console.log(deleted); //=> ['foo/aa/', 'foo/a/cc/', 'foo/b/', 'foo/c/'] 32 | })(); 33 | 34 | // or 35 | deleteEmpty('foo/') 36 | .then(deleted => console.log(deleted)) //=> ['foo/aa/', 'foo/a/cc/', 'foo/b/', 'foo/c/'] 37 | .catch(console.error); 38 | ``` 39 | 40 | ### async callback 41 | 42 | Returns the array of deleted directories in the callback. 43 | 44 | ```js 45 | deleteEmpty('foo/', (err, deleted) => { 46 | console.log(deleted); //=> ['foo/aa/', 'foo/a/cc/', 'foo/b/', 'foo/c/'] 47 | }); 48 | ``` 49 | 50 | ### sync 51 | 52 | Returns the array of deleted directories. 53 | 54 | ```js 55 | console.log(deleteEmpty.sync('foo/')); //=> ['foo/aa/', 'foo/a/cc/', 'foo/b/', 'foo/c/'] 56 | ``` 57 | 58 | 59 | ## CLI 60 | 61 | To use the `delete-empty` command from any directory you must first install the package globally with the following command: 62 | 63 | ```sh 64 | $ npm install --global delete-empty 65 | ``` 66 | 67 | **Usage** 68 | 69 | ``` 70 | Usage: $ delete-empty [options] 71 | 72 | Directory: (optional) Initial directory to begin the search for empty 73 | directories. Otherwise, cwd is used. 74 | 75 | [Options]: 76 | -c, --cwd Set the current working directory for folders to search. 77 | -d, --dryRun Do a dry run without deleting any files. 78 | -h, --help Display this help menu 79 | -V, --version Display the current version of rename 80 | -v, --verbose Display all verbose logging messages (currently not used) 81 | 82 | ``` 83 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "delete-empty", 3 | "description": "Recursively delete all empty folders in a directory and child directories.", 4 | "version": "3.0.0", 5 | "homepage": "https://github.com/jonschlinkert/delete-empty", 6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)", 7 | "contributors": [ 8 | "Jon Schlinkert (http://twitter.com/jonschlinkert)", 9 | "Sven Schoenung (http://sven.schoenung.org)", 10 | "Vittorio Palmisano (http://c3lab.poliba.it/index.php/VittorioPalmisano)" 11 | ], 12 | "repository": "jonschlinkert/delete-empty", 13 | "bugs": { 14 | "url": "https://github.com/jonschlinkert/delete-empty/issues" 15 | }, 16 | "license": "MIT", 17 | "files": [ 18 | "bin", 19 | "index.js" 20 | ], 21 | "main": "index.js", 22 | "bin": { 23 | "delete-empty": "bin/cli.js" 24 | }, 25 | "engines": { 26 | "node": ">=10" 27 | }, 28 | "scripts": { 29 | "test": "mocha" 30 | }, 31 | "dependencies": { 32 | "ansi-colors": "^4.1.0", 33 | "minimist": "^1.2.0", 34 | "path-starts-with": "^2.0.0", 35 | "rimraf": "^2.6.2" 36 | }, 37 | "devDependencies": { 38 | "@folder/readdir": "^2.0.0", 39 | "gulp-format-md": "^1.0.0", 40 | "mocha": "^3.5.3", 41 | "write": "^1.0.3" 42 | }, 43 | "keywords": [ 44 | "del", 45 | "delete", 46 | "dir", 47 | "directory", 48 | "empty", 49 | "files", 50 | "folder", 51 | "recurse", 52 | "recursive", 53 | "remove" 54 | ], 55 | "verb": { 56 | "run": true, 57 | "toc": true, 58 | "layout": "default", 59 | "tasks": [ 60 | "readme" 61 | ], 62 | "reflinks": [ 63 | "verb" 64 | ], 65 | "plugins": [ 66 | "gulp-format-md" 67 | ], 68 | "related": { 69 | "list": [ 70 | "copy", 71 | "delete", 72 | "fs-utils", 73 | "matched" 74 | ] 75 | }, 76 | "lint": { 77 | "reflinks": true 78 | } 79 | }, 80 | "lintDeps": { 81 | "devDependencies": { 82 | "files": { 83 | "patterns": [ 84 | "tree.js" 85 | ] 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended" 4 | ], 5 | 6 | "env": { 7 | "browser": false, 8 | "es6": true, 9 | "node": true, 10 | "mocha": true 11 | }, 12 | 13 | "parserOptions":{ 14 | "ecmaVersion": 9, 15 | "sourceType": "module", 16 | "ecmaFeatures": { 17 | "modules": true, 18 | "experimentalObjectRestSpread": true 19 | } 20 | }, 21 | 22 | "globals": { 23 | "document": false, 24 | "navigator": false, 25 | "window": false 26 | }, 27 | 28 | "rules": { 29 | "accessor-pairs": 2, 30 | "arrow-spacing": [2, { "before": true, "after": true }], 31 | "block-spacing": [2, "always"], 32 | "brace-style": [2, "1tbs", { "allowSingleLine": true }], 33 | "comma-dangle": [2, "never"], 34 | "comma-spacing": [2, { "before": false, "after": true }], 35 | "comma-style": [2, "last"], 36 | "constructor-super": 2, 37 | "curly": [2, "multi-line"], 38 | "dot-location": [2, "property"], 39 | "eol-last": 2, 40 | "eqeqeq": [2, "allow-null"], 41 | "generator-star-spacing": [2, { "before": true, "after": true }], 42 | "handle-callback-err": [2, "^(err|error)$" ], 43 | "indent": [2, 2, { "SwitchCase": 1 }], 44 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }], 45 | "keyword-spacing": [2, { "before": true, "after": true }], 46 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }], 47 | "new-parens": 2, 48 | "no-array-constructor": 2, 49 | "no-caller": 2, 50 | "no-class-assign": 2, 51 | "no-cond-assign": 2, 52 | "no-const-assign": 2, 53 | "no-control-regex": 2, 54 | "no-debugger": 2, 55 | "no-delete-var": 2, 56 | "no-dupe-args": 2, 57 | "no-dupe-class-members": 2, 58 | "no-dupe-keys": 2, 59 | "no-duplicate-case": 2, 60 | "no-empty-character-class": 2, 61 | "no-eval": 2, 62 | "no-ex-assign": 2, 63 | "no-extend-native": 2, 64 | "no-extra-bind": 2, 65 | "no-extra-boolean-cast": 2, 66 | "no-extra-parens": [2, "functions"], 67 | "no-fallthrough": 2, 68 | "no-floating-decimal": 2, 69 | "no-func-assign": 2, 70 | "no-implied-eval": 2, 71 | "no-inner-declarations": [2, "functions"], 72 | "no-invalid-regexp": 2, 73 | "no-irregular-whitespace": 2, 74 | "no-iterator": 2, 75 | "no-label-var": 2, 76 | "no-labels": 2, 77 | "no-lone-blocks": 2, 78 | "no-mixed-spaces-and-tabs": 2, 79 | "no-multi-spaces": 2, 80 | "no-multi-str": 2, 81 | "no-multiple-empty-lines": [2, { "max": 1 }], 82 | "no-native-reassign": 0, 83 | "no-negated-in-lhs": 2, 84 | "no-new": 2, 85 | "no-new-func": 2, 86 | "no-new-object": 2, 87 | "no-new-require": 2, 88 | "no-new-wrappers": 2, 89 | "no-obj-calls": 2, 90 | "no-octal": 2, 91 | "no-octal-escape": 2, 92 | "no-proto": 0, 93 | "no-redeclare": 2, 94 | "no-regex-spaces": 2, 95 | "no-return-assign": 2, 96 | "no-self-compare": 2, 97 | "no-sequences": 2, 98 | "no-shadow-restricted-names": 2, 99 | "no-spaced-func": 2, 100 | "no-sparse-arrays": 2, 101 | "no-this-before-super": 2, 102 | "no-throw-literal": 2, 103 | "no-trailing-spaces": 0, 104 | "no-undef": 2, 105 | "no-undef-init": 2, 106 | "no-unexpected-multiline": 2, 107 | "no-unneeded-ternary": [2, { "defaultAssignment": false }], 108 | "no-unreachable": 2, 109 | "no-unused-vars": [2, { "vars": "all", "args": "none" }], 110 | "no-useless-call": 0, 111 | "no-with": 2, 112 | "one-var": [0, { "initialized": "never" }], 113 | "operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }], 114 | "padded-blocks": [0, "never"], 115 | "quotes": [2, "single", "avoid-escape"], 116 | "radix": 2, 117 | "semi": [2, "always"], 118 | "semi-spacing": [2, { "before": false, "after": true }], 119 | "space-before-blocks": [2, "always"], 120 | "space-before-function-paren": [2, "never"], 121 | "space-in-parens": [2, "never"], 122 | "space-infix-ops": 2, 123 | "space-unary-ops": [2, { "words": true, "nonwords": false }], 124 | "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }], 125 | "use-isnan": 2, 126 | "valid-typeof": 2, 127 | "wrap-iife": [2, "any"], 128 | "yoda": [2, "never"] 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * delete-empty 3 | * Copyright (c) 2015-present, Jon Schlinkert 4 | * Released under the MIT License. 5 | */ 6 | 7 | 'use strict'; 8 | 9 | const fs = require('fs'); 10 | const util = require('util'); 11 | const path = require('path'); 12 | const rimraf = require('rimraf'); 13 | const startsWith = require('path-starts-with'); 14 | const colors = require('ansi-colors'); 15 | const readdir = util.promisify(fs.readdir); 16 | 17 | /** 18 | * Helpers 19 | */ 20 | 21 | const GARBAGE_REGEX = /(?:Thumbs\.db|\.DS_Store)$/i; 22 | const isGarbageFile = (file, regex = GARBAGE_REGEX) => regex.test(file); 23 | const filterGarbage = (file, regex) => !isGarbageFile(file, regex); 24 | const isValidDir = (cwd, dir, empty) => { 25 | return !empty.includes(dir) && startsWith(dir, cwd) && isDirectory(dir); 26 | }; 27 | 28 | const deleteDir = async (dirname, options = {}) => { 29 | if (options.dryRun !== true) { 30 | return new Promise((resolve, reject) => { 31 | rimraf(dirname, { ...options, glob: false }, err => { 32 | if (err) { 33 | reject(err); 34 | } else { 35 | resolve(); 36 | } 37 | }); 38 | }) 39 | } 40 | }; 41 | 42 | const deleteDirSync = (dirname, options = {}) => { 43 | if (options.dryRun !== true) { 44 | return rimraf.sync(dirname, { ...options, glob: false }); 45 | } 46 | }; 47 | 48 | const deleteEmpty = (cwd, options, cb) => { 49 | if (typeof cwd !== 'string') { 50 | return Promise.reject(new TypeError('expected the first argument to be a string')); 51 | } 52 | 53 | if (typeof options === 'function') { 54 | cb = options; 55 | options = null; 56 | } 57 | 58 | if (typeof cb === 'function') { 59 | return deleteEmpty(cwd, options) 60 | .then(res => cb(null, res)) 61 | .catch(cb); 62 | } 63 | 64 | const opts = options || {}; 65 | const dirname = path.resolve(cwd); 66 | const onDirectory = opts.onDirectory || (() => {}); 67 | const empty = []; 68 | 69 | const remove = async filepath => { 70 | let dir = path.resolve(filepath); 71 | 72 | if (!isValidDir(cwd, dir, empty)) return; 73 | onDirectory(dir); 74 | 75 | let files = await readdir(dir); 76 | 77 | if (isEmpty(dir, files, empty, opts)) { 78 | empty.push(dir); 79 | 80 | await deleteDir(dir, opts); 81 | 82 | if (opts.verbose === true) { 83 | console.log(colors.red('Deleted:'), path.relative(cwd, dir)); 84 | } 85 | 86 | if (typeof opts.onDelete === 'function') { 87 | await opts.onDelete(dir); 88 | } 89 | 90 | return remove(path.dirname(dir)); 91 | } 92 | 93 | for (const file of files) { 94 | await remove(path.join(dir, file)); 95 | } 96 | 97 | return empty; 98 | }; 99 | 100 | return remove(dirname); 101 | }; 102 | 103 | deleteEmpty.sync = (cwd, options) => { 104 | if (typeof cwd !== 'string') { 105 | throw new TypeError('expected the first argument to be a string'); 106 | } 107 | 108 | const opts = options || {}; 109 | const dirname = path.resolve(cwd); 110 | const deleted = []; 111 | const empty = []; 112 | 113 | const remove = filepath => { 114 | let dir = path.resolve(filepath); 115 | 116 | if (!isValidDir(cwd, dir, empty)) { 117 | return empty; 118 | } 119 | 120 | let files = fs.readdirSync(dir); 121 | 122 | if (isEmpty(dir, files, empty, opts)) { 123 | empty.push(dir); 124 | 125 | deleteDirSync(dir, opts); 126 | 127 | if (opts.verbose === true) { 128 | console.log(colors.red('Deleted:'), path.relative(cwd, dir)); 129 | } 130 | 131 | if (typeof opts.onDelete === 'function') { 132 | opts.onDelete(dir); 133 | } 134 | 135 | return remove(path.dirname(dir)); 136 | } 137 | 138 | for (let filepath of files) { 139 | remove(path.join(dir, filepath)); 140 | } 141 | return empty; 142 | }; 143 | 144 | remove(dirname); 145 | return empty; 146 | }; 147 | 148 | /** 149 | * Return true if the given `files` array has zero length or only 150 | * includes unwanted files. 151 | */ 152 | 153 | const isEmpty = (dir, files, empty, options = {}) => { 154 | let filter = options.filter || filterGarbage; 155 | let regex = options.junkRegex; 156 | 157 | for (let basename of files) { 158 | let filepath = path.join(dir, basename); 159 | 160 | if (!(options.dryRun && empty.includes(filepath)) && filter(filepath, regex) === true) { 161 | return false; 162 | } 163 | } 164 | return true; 165 | }; 166 | 167 | /** 168 | * Returns true if the given filepath exists and is a directory 169 | */ 170 | 171 | const isDirectory = dir => { 172 | try { 173 | return fs.statSync(dir).isDirectory(); 174 | } catch (err) { /* do nothing */ } 175 | return false; 176 | }; 177 | 178 | /** 179 | * Expose deleteEmpty 180 | */ 181 | 182 | module.exports = deleteEmpty; 183 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 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) 2 | 3 | > Recursively delete all empty folders in a directory and child directories. 4 | 5 | Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support. 6 | 7 | - [Install](#install) 8 | - [Usage](#usage) 9 | - [API](#api) 10 | * [async-await (promise)](#async-await-promise) 11 | * [async callback](#async-callback) 12 | * [sync](#sync) 13 | - [CLI](#cli) 14 | - [About](#about) 15 | 16 | _(TOC generated by [verb](https://github.com/verbose/verb) using [markdown-toc](https://github.com/jonschlinkert/markdown-toc))_ 17 | 18 | ## Install 19 | 20 | Install with [npm](https://www.npmjs.com/): 21 | 22 | ```sh 23 | $ npm install --save delete-empty 24 | ``` 25 | 26 | ## Usage 27 | 28 | ```js 29 | const deleteEmpty = require('delete-empty'); 30 | ``` 31 | 32 | ## API 33 | 34 | Given the following directory structure, the **highlighted directories** would be deleted. 35 | 36 | ```diff 37 | foo/ 38 | └─┬ a/ 39 | - ├── aa/ 40 | ├── bb/ 41 | │ └─┬ bbb/ 42 | │ │ ├── one.txt 43 | │ │ └── two.txt 44 | - ├── cc/ 45 | - ├ b/ 46 | - └ c/ 47 | ``` 48 | 49 | ### async-await (promise) 50 | 51 | If no callback is passed, a promise is returned. Returns the array of deleted directories. 52 | 53 | ```js 54 | (async () => { 55 | let deleted = await deleteEmpty('foo'); 56 | console.log(deleted); //=> ['foo/aa/', 'foo/a/cc/', 'foo/b/', 'foo/c/'] 57 | })(); 58 | 59 | // or 60 | deleteEmpty('foo/') 61 | .then(deleted => console.log(deleted)) //=> ['foo/aa/', 'foo/a/cc/', 'foo/b/', 'foo/c/'] 62 | .catch(console.error); 63 | ``` 64 | 65 | ### async callback 66 | 67 | Returns the array of deleted directories in the callback. 68 | 69 | ```js 70 | deleteEmpty('foo/', (err, deleted) => { 71 | console.log(deleted); //=> ['foo/aa/', 'foo/a/cc/', 'foo/b/', 'foo/c/'] 72 | }); 73 | ``` 74 | 75 | ### sync 76 | 77 | Returns the array of deleted directories. 78 | 79 | ```js 80 | console.log(deleteEmpty.sync('foo/')); //=> ['foo/aa/', 'foo/a/cc/', 'foo/b/', 'foo/c/'] 81 | ``` 82 | 83 | ## CLI 84 | 85 | To use the `delete-empty` command from any directory you must first install the package globally with the following command: 86 | 87 | ```sh 88 | $ npm install --global delete-empty 89 | ``` 90 | 91 | **Usage** 92 | 93 | ``` 94 | Usage: $ delete-empty [options] 95 | 96 | Directory: (optional) Initial directory to begin the search for empty 97 | directories. Otherwise, cwd is used. 98 | 99 | [Options]: 100 | -c, --cwd Set the current working directory for folders to search. 101 | -d, --dryRun Do a dry run without deleting any files. 102 | -h, --help Display this help menu 103 | -V, --version Display the current version of rename 104 | -v, --verbose Display all verbose logging messages (currently not used) 105 | 106 | ``` 107 | 108 | ## About 109 | 110 |
111 | Contributing 112 | 113 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new). 114 | 115 |
116 | 117 |
118 | Running Tests 119 | 120 | Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command: 121 | 122 | ```sh 123 | $ npm install && npm test 124 | ``` 125 | 126 |
127 | 128 |
129 | Building docs 130 | 131 | _(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_ 132 | 133 | To generate the readme, run the following command: 134 | 135 | ```sh 136 | $ npm install -g verbose/verb#dev verb-generate-readme && verb 137 | ``` 138 | 139 |
140 | 141 | ### Related projects 142 | 143 | You might also be interested in these projects: 144 | 145 | * [copy](https://www.npmjs.com/package/copy): Copy files or directories using globs. | [homepage](https://github.com/jonschlinkert/copy "Copy files or directories using globs.") 146 | * [delete](https://www.npmjs.com/package/delete): Delete files and folders and any intermediate directories if they exist (sync and async). | [homepage](https://github.com/jonschlinkert/delete "Delete files and folders and any intermediate directories if they exist (sync and async).") 147 | * [fs-utils](https://www.npmjs.com/package/fs-utils): fs extras and utilities to extend the node.js file system module. Used in Assemble and… [more](https://github.com/assemble/fs-utils) | [homepage](https://github.com/assemble/fs-utils "fs extras and utilities to extend the node.js file system module. Used in Assemble and many other projects.") 148 | * [matched](https://www.npmjs.com/package/matched): Adds array support to node-glob, sync and async. Also supports tilde expansion (user home) and… [more](https://github.com/jonschlinkert/matched) | [homepage](https://github.com/jonschlinkert/matched "Adds array support to node-glob, sync and async. Also supports tilde expansion (user home) and resolving to global npm modules.") 149 | 150 | ### Contributors 151 | 152 | | **Commits** | **Contributor** | 153 | | --- | --- | 154 | | 31 | [jonschlinkert](https://github.com/jonschlinkert) | 155 | | 2 | [treble-snake](https://github.com/treble-snake) | 156 | | 1 | [doowb](https://github.com/doowb) | 157 | | 1 | [svenschoenung](https://github.com/svenschoenung) | 158 | | 1 | [vpalmisano](https://github.com/vpalmisano) | 159 | 160 | ### Author 161 | 162 | **Jon Schlinkert** 163 | 164 | * [GitHub Profile](https://github.com/jonschlinkert) 165 | * [Twitter Profile](https://twitter.com/jonschlinkert) 166 | * [LinkedIn Profile](https://linkedin.com/in/jonschlinkert) 167 | 168 | ### License 169 | 170 | Copyright © 2019, [Jon Schlinkert](https://github.com/jonschlinkert). 171 | Released under the [MIT License](LICENSE). 172 | 173 | *** 174 | 175 | _This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on July 02, 2019._ 176 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | const util = require('util'); 7 | const readdir = require('@folder/readdir'); 8 | const assert = require('assert'); 9 | const rimraf = require('rimraf'); 10 | const deleteEmpty = require('..'); 11 | const copy = require('./support/copy'); 12 | 13 | const fixtures = path.join.bind(path, __dirname, 'fixtures'); 14 | const expected = [ 15 | fixtures('temp/a/aa/aaa'), 16 | fixtures('temp/a/aa/aaa/aaaa'), 17 | fixtures('temp/b'), 18 | fixtures('temp/c') 19 | ]; 20 | 21 | const noNested = files => files.filter(file => !/nested/.test(file)); 22 | const filter = file => file.isDirectory(); 23 | let folders; 24 | 25 | describe('deleteEmpty', () => { 26 | afterEach(cb => rimraf(fixtures('temp'), cb)); 27 | 28 | beforeEach(async () => { 29 | await copy(fixtures('paths'), fixtures('temp')) 30 | folders = readdir.sync(fixtures('temp/nested'), { filter, recursive: true, absolute: true }); 31 | folders.sort(); 32 | }); 33 | 34 | describe('promise', cb => { 35 | it('should delete the given cwd if empty', () => { 36 | return deleteEmpty(fixtures('temp/b')) 37 | .then(deleted => { 38 | assert(!fs.existsSync(fixtures('temp/b'))) 39 | }); 40 | }); 41 | 42 | it('should delete nested directories', () => { 43 | return deleteEmpty(fixtures('temp')) 44 | .then(deleted => { 45 | assert(!fs.existsSync(fixtures('temp/a/aa/aaa'))); 46 | assert(!fs.existsSync(fixtures('temp/b'))); 47 | assert(!fs.existsSync(fixtures('temp/c'))); 48 | }); 49 | }); 50 | 51 | it('should return the array of deleted directories', () => { 52 | return deleteEmpty(fixtures('temp')) 53 | .then(deleted => { 54 | assert.deepEqual(noNested(deleted).sort(), expected.sort()); 55 | }) 56 | }); 57 | }); 58 | 59 | describe('promise - options.dryRun', () => { 60 | it('should not delete the given cwd if empty', () => { 61 | return deleteEmpty(fixtures('temp/b'), { dryRun: true }) 62 | .then(() => assert(fs.existsSync(fixtures('temp/b')))) 63 | }); 64 | 65 | it('should not delete nested directories', () => { 66 | return deleteEmpty(fixtures('temp'), { dryRun: true }) 67 | .then(() => { 68 | assert(fs.existsSync(fixtures('temp/a/aa/aaa'))); 69 | assert(fs.existsSync(fixtures('temp/b'))); 70 | assert(fs.existsSync(fixtures('temp/c'))); 71 | }); 72 | }); 73 | 74 | it('should delete deeply nested directories', () => { 75 | return deleteEmpty(fixtures('temp/nested')) 76 | .then(deleted => { 77 | assert.equal(folders.length, deleted.length); 78 | }); 79 | }); 80 | 81 | it('should return the array of empty directories', () => { 82 | return deleteEmpty(fixtures('temp')) 83 | .then(deleted => { 84 | assert.deepEqual(noNested(deleted).sort(), expected.sort()); 85 | }); 86 | }); 87 | 88 | it('should not delete directories when options.dryRun is true', () => { 89 | return deleteEmpty(fixtures('temp'), { dryRun: true }) 90 | .then(deleted => { 91 | for (let folder of folders) { 92 | assert(fs.existsSync(folder)); 93 | } 94 | }); 95 | }); 96 | }); 97 | 98 | describe('async', () => { 99 | it('should delete the given cwd if empty', cb => { 100 | deleteEmpty(fixtures('temp/b'), (err, deleted) => { 101 | if (err) { 102 | cb(err); 103 | return; 104 | } 105 | assert(!fs.existsSync(fixtures('temp/b'))); 106 | cb(); 107 | }); 108 | }); 109 | 110 | it('should delete nested directories', cb => { 111 | deleteEmpty(fixtures('temp'), (err, deleted) => { 112 | if (err) { 113 | cb(err); 114 | return; 115 | } 116 | assert(!fs.existsSync(fixtures('temp/a/aa/aaa'))); 117 | assert(!fs.existsSync(fixtures('temp/b'))); 118 | assert(!fs.existsSync(fixtures('temp/c'))); 119 | cb(); 120 | }); 121 | }); 122 | 123 | it('should return the array of deleted directories', cb => { 124 | deleteEmpty(fixtures('temp'), (err, deleted) => { 125 | if (err) { 126 | cb(err); 127 | return; 128 | } 129 | assert.deepEqual(noNested(deleted).sort(), expected.sort()); 130 | cb(); 131 | }); 132 | }); 133 | }); 134 | 135 | describe('async - options.dryRun', () => { 136 | it('should not delete the given cwd if empty', cb => { 137 | deleteEmpty(fixtures('temp/b'), { dryRun: true }, (err, deleted) => { 138 | if (err) { 139 | cb(err); 140 | return; 141 | } 142 | assert(fs.existsSync(fixtures('temp/b'))); 143 | cb(); 144 | }); 145 | }); 146 | 147 | it('should not delete nested directories', cb => { 148 | deleteEmpty(fixtures('temp'), { dryRun: true }, (err, deleted) => { 149 | if (err) { 150 | cb(err); 151 | return; 152 | } 153 | assert(fs.existsSync(fixtures('temp/a/aa/aaa'))); 154 | assert(fs.existsSync(fixtures('temp/b'))); 155 | assert(fs.existsSync(fixtures('temp/c'))); 156 | cb(); 157 | }); 158 | }); 159 | 160 | it('should return the array of empty directories', cb => { 161 | deleteEmpty(fixtures('temp'), { dryRun: true }, (err, deleted) => { 162 | if (err) { 163 | cb(err); 164 | return; 165 | } 166 | 167 | assert.deepEqual(noNested(deleted).sort(), expected.sort()); 168 | cb(); 169 | }); 170 | }); 171 | }); 172 | 173 | describe('sync', () => { 174 | it('should delete the given cwd if empty', cb => { 175 | deleteEmpty.sync(fixtures('temp/b')); 176 | assert(!fs.existsSync(fixtures('temp/b'))); 177 | cb(); 178 | }); 179 | 180 | it('should delete nested directories', cb => { 181 | deleteEmpty.sync(fixtures('temp')); 182 | assert(!fs.existsSync(fixtures('temp/a/aa/aaa/aaaa'))); 183 | assert(!fs.existsSync(fixtures('temp/a/aa/aaa'))); 184 | assert(!fs.existsSync(fixtures('temp/b'))); 185 | assert(!fs.existsSync(fixtures('temp/c'))); 186 | cb(); 187 | }); 188 | 189 | it('should return the array of deleted directories', cb => { 190 | var deleted = deleteEmpty.sync(fixtures('temp')); 191 | assert.deepEqual(noNested(deleted).sort(), expected.sort()); 192 | cb(); 193 | }); 194 | }); 195 | 196 | describe('sync - options.dryRun', () => { 197 | it('should not delete the given cwd if empty', () => { 198 | deleteEmpty.sync(fixtures('temp/b'), { dryRun: true }); 199 | assert(fs.existsSync(fixtures('temp/b'))); 200 | }); 201 | 202 | it('should not delete nested directories', () => { 203 | deleteEmpty.sync(fixtures('temp'), { dryRun: true }); 204 | assert(fs.existsSync(fixtures('temp/a/aa/aaa/aaaa'))); 205 | assert(fs.existsSync(fixtures('temp/a/aa/aaa'))); 206 | assert(fs.existsSync(fixtures('temp/b'))); 207 | assert(fs.existsSync(fixtures('temp/c'))); 208 | }); 209 | 210 | it('should return the array of empty directories', cb => { 211 | var deleted = deleteEmpty.sync(fixtures('temp'), { dryRun: true }); 212 | assert.deepEqual(noNested(deleted).sort(), expected.sort()); 213 | cb(); 214 | }); 215 | }); 216 | }); 217 | --------------------------------------------------------------------------------