2020-12-09 22:58:53 +00:00
|
|
|
"use strict";
|
2020-12-09 11:10:56 +00:00
|
|
|
|
2020-12-09 22:58:53 +00:00
|
|
|
const fs = require("fs").promises;
|
|
|
|
const Walk = require("./walk.js");
|
|
|
|
const path = require("path");
|
|
|
|
const _withFileTypes = { withFileTypes: true };
|
|
|
|
const _noopts = {};
|
|
|
|
const _pass = (err) => err;
|
2020-12-09 11:10:56 +00:00
|
|
|
|
2020-12-09 22:58:53 +00:00
|
|
|
// a port of Go's filepath.Walk
|
2020-12-09 11:48:55 +00:00
|
|
|
Walk.create = function (opts) {
|
|
|
|
if (!opts) {
|
|
|
|
opts = _noopts;
|
2020-12-09 11:10:56 +00:00
|
|
|
}
|
|
|
|
|
2020-12-09 11:48:55 +00:00
|
|
|
// a port of Go's filepath.Walk
|
|
|
|
const _walk = async (pathname, walkFunc, _dirent) => {
|
|
|
|
let err;
|
2020-12-09 11:10:56 +00:00
|
|
|
|
2020-12-09 11:48:55 +00:00
|
|
|
// special case of the very first run
|
|
|
|
if (!_dirent) {
|
|
|
|
_dirent = pathname;
|
2020-12-09 11:10:56 +00:00
|
|
|
}
|
|
|
|
|
2020-12-09 11:48:55 +00:00
|
|
|
// the first run, or if false === withFileTypes
|
|
|
|
if ("string" === typeof _dirent) {
|
|
|
|
let _name = path.basename(path.resolve(pathname));
|
2020-12-09 22:58:53 +00:00
|
|
|
_dirent = await fs.lstat(pathname).catch(_pass);
|
2020-12-09 11:48:55 +00:00
|
|
|
if (_dirent instanceof Error) {
|
|
|
|
err = _dirent;
|
|
|
|
} else {
|
|
|
|
_dirent.name = _name;
|
|
|
|
}
|
2020-12-09 11:10:56 +00:00
|
|
|
}
|
|
|
|
|
2020-12-09 11:48:55 +00:00
|
|
|
// run the user-supplied function and either skip, bail, or continue
|
2020-12-09 22:58:53 +00:00
|
|
|
err = await walkFunc(err, pathname, _dirent).catch(_pass);
|
2020-12-09 11:48:55 +00:00
|
|
|
if (false === err || Walk.skipDir === err) {
|
2020-12-09 11:10:56 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-12-09 11:48:55 +00:00
|
|
|
if (err instanceof Error) {
|
|
|
|
throw err;
|
2020-12-09 11:10:56 +00:00
|
|
|
}
|
|
|
|
|
2020-12-09 11:48:55 +00:00
|
|
|
// "walk does not follow symbolic links"
|
|
|
|
if (!_dirent || !_dirent.isDirectory()) {
|
|
|
|
return;
|
2020-12-09 11:10:56 +00:00
|
|
|
}
|
|
|
|
|
2020-12-09 11:48:55 +00:00
|
|
|
// lightweight dirents or full lstat
|
|
|
|
let _readdirOpts;
|
|
|
|
if (!opts.withFileStats) {
|
|
|
|
_readdirOpts = _withFileTypes;
|
|
|
|
}
|
2020-12-09 11:10:56 +00:00
|
|
|
|
2020-12-09 11:48:55 +00:00
|
|
|
// TODO check if the error is "not a directory"
|
|
|
|
// (and thus allow false === opts.withFileTypes)
|
2020-12-09 22:58:53 +00:00
|
|
|
let result = await fs.readdir(pathname, _readdirOpts).catch(_pass);
|
2020-12-09 11:48:55 +00:00
|
|
|
if (result instanceof Error) {
|
|
|
|
return walkFunc(result, pathname, _dirent);
|
2020-12-09 11:10:56 +00:00
|
|
|
}
|
2020-12-09 11:48:55 +00:00
|
|
|
if (opts.sort) {
|
|
|
|
result = opts.sort(result);
|
|
|
|
}
|
|
|
|
for (let entity of result) {
|
|
|
|
await _walk(path.join(pathname, entity.name || entity), walkFunc, entity);
|
|
|
|
}
|
|
|
|
};
|
2020-12-09 11:10:56 +00:00
|
|
|
|
|
|
|
return _walk;
|
|
|
|
};
|
|
|
|
|
2020-12-09 22:58:53 +00:00
|
|
|
module.exports = Walk;
|