nodejs-fs-utils
Version:
NodeJs FileSystem (FS) extra utilities, walk, fsize ( folder / symlinks / files ), rmdirs,
219 lines (201 loc) • 4.98 kB
JavaScript
var _classes = {
fs : require("fs"),
path : require("path")
};
/**
* @typedef {Object} rmdirOptions
*
* @property {Boolean} [skipErrors=false] if is `true` function will not be interrupted by errors, and will remove rest of files, default value is `false`
* @property {Boolean} [symbolicLinks=true] support symbolic links
*/
/**
* Remove a folder or file
* @param {String} path address of path that should be removed
* @param {function(Error | Error[]):void} callback handle when folder was removed, if `opts.skipErrors = true` will receive an array of errors
* @param {rmdirOptions} opts additional options
*/
var rmdirAsync = function(path, callback, opts) {
path = _classes.path.normalize(path);
var fs;
if (typeof(opts) === "function") {
callback = opts;
opts = {};
}
if (typeof(opts) !== "object") {
opts = {};
}
if (typeof(opts.symbolicLinks) === "undefined") {
opts.symbolicLinks = true;
}
if (typeof(opts.skipErrors) === "undefined") {
opts.skipErrors = false;
}
var errors = [];
if (!fs)
fs = opts.fs || _classes.fs;
fs[opts.symbolicLinks ? 'lstat' : 'stat'](path, function (err, stats) {
if (err) {
if (opts.skipErrors) {
errors.push(err);
callback(errors);
} else {
callback(err);
}
} else {
if (!stats.isDirectory() || stats.isSymbolicLink()) {
fs.unlink(path, function (err) {
if (err) {
if (opts.skipErrors) {
errors.push(err);
callback(errors);
} else {
callback(err);
}
} else {
callback();
}
});
} else {
fs.readdir(path, function(err, files) {
if(err) {
// Pass the error on to callback
if (opts.skipErrors) {
errors.push(err);
callback(errors);
} else {
callback(err);
}
return;
}
// Remove one or more trailing slash to keep from doubling up
path = path.replace(/\/+$/,"");
var next = function () {
if (files.length) {
var file = files.shift();
var curPath = _classes.path.normalize(path + _classes.path.sep + file);
fs[opts.symbolicLinks ? 'lstat' : 'stat'](curPath, function(err, stats) {
if( err || ( stats && stats.isSymbolicLink() && !opts.symbolicLinks )) {
if (opts.skipErrors) {
errors.push(err || Error("Exception: Symbolic link"));
next();
} else {
callback(err || Error("Exception: Symbolic link"), []);
return;
}
} else {
if( stats.isDirectory() && !stats.isSymbolicLink() ) {
rmdirAsync(curPath, function (err) {
if (err) {
if (opts.skipErrors) {
errors.push(err);
next();
} else {
callback(err);
}
} else {
next();
}
}, opts);
} else {
fs.unlink(curPath, function (err) {
if (err) {
if (opts.skipErrors) {
errors.push(err);
next();
} else {
callback(err);
}
} else {
next();
}
});
}
}
});
} else {
fs.rmdir(path, function (err) {
if (opts.skipErrors) {
if (err) {
errors.push(err);
}
callback(errors);
} else {
callback(err);
}
});
}
};
next();
});
}
}
});
};
/**
* Remove a folder or file
* @param {String} path address of path that should be removed
* @param {rmdirOptions} opts additional options
*/
rmdirAsync.sync = function (path, opts) {
var fs;
path = _classes.path.normalize(path);
if (typeof(opts) !== "object") {
opts = {};
}
if (typeof(opts.symbolicLinks) === "undefined") {
opts.symbolicLinks = true;
}
if (typeof(opts.skipErrors) === "undefined") {
opts.skipErrors = false;
}
if (!fs)
fs = opts.fs || _classes.fs;
var err;
try {
var stats = fs[opts.symbolicLinks ? 'lstatSync' : 'statSync'](path);
} catch (err) {
if (!opts.skipErrors) {
throw (err);
} else {
return;
}
}
if (!stats.isDirectory()) {
try {
fs.unlinkSync(path);
} catch (err) {
if (!opts.skipErrors) {
throw (err);
}
}
return;
}
var files;
try {
files = fs.readdirSync(path);
} catch (err) {
if (!opts.skipErrors) {
throw (err);
}
}
var wait = files.length;
// Remove one or more trailing slash to keep from doubling up
path = path.replace(/\/+$/,"");
files.forEach(function(file) {
try {
var curPath = _classes.path.normalize(path + _classes.path.sep + file);
var stats = fs[opts.symbolicLinks ? 'lstatSync' : 'statSync'](curPath);
if( stats.isDirectory() && !stats.isSymbolicLink() ) {
rmdirAsync.sync(curPath, opts);
} else {
fs.unlinkSync(curPath);
}
} catch (err) {
if (!opts.skipErrors) {
throw (err);
}
}
});
fs.rmdirSync(path);
};
module.exports = rmdirAsync;