initial commit
This commit is contained in:
commit
3a125de3a5
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"env": {
|
||||
"es2021": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 12,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"printWidth": 100
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
# Walk.js (@root/walk)
|
||||
|
||||
A port of Go's [`filepath.Walk`](https://golang.org/pkg/path/filepath/#Walk) for Node.js v10+ (which introduced `fs.readdir` `withFileTypes`).
|
||||
|
||||
```js
|
||||
await Walk.walk(rootpath, walkFunc);
|
||||
```
|
||||
|
||||
# Example
|
||||
|
||||
```js
|
||||
import Walk from "walk";
|
||||
|
||||
Walk.walk("./", function (err, pathname, dirent) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
// ignore dot files
|
||||
if (dirent.name.startsWith(".")) {
|
||||
return Walk.skipDir;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
# API Documentation
|
||||
|
||||
`Walk.walk` walks `rootpath` (inclusive) and calls `walkFunc` for each file system entry.
|
||||
|
||||
It can be used with Promises:
|
||||
|
||||
```js
|
||||
Walk.walk(rootpath, promiseWalker).then(doMore);
|
||||
```
|
||||
|
||||
Or with async / await:
|
||||
|
||||
```js
|
||||
await Walk.walk(rootpath, asyncWalker);
|
||||
```
|
||||
|
||||
The behavior should exactly match Go's
|
||||
[`filepath.Walk`](https://golang.org/pkg/path/filepath/#Walk) with 3 exceptions:
|
||||
|
||||
- uses JavaScript Promises/async/await
|
||||
- receives `dirent` rather than `lstat` (for performance)
|
||||
|
||||
<!-- TODO
|
||||
- can be created with `options` to change default behaviors
|
||||
-->
|
||||
|
||||
## walkFunc
|
||||
|
||||
Handles each directory entry
|
||||
|
||||
```js
|
||||
function walker(err, pathname, dirent) {
|
||||
// `err` is a file system stat error
|
||||
// `pathname` is the full pathname, including the file name
|
||||
// `dirent` is an fs.Dirent with a `name`, `isDirectory`, `isFile`, etc
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
<!-- TODO
|
||||
## create(options)
|
||||
|
||||
Create a custom walker with these options:
|
||||
|
||||
- `withFileTypes: false` walkFunc will receive String[] instead of fs.Dirent[]
|
||||
- `sort: sortFunc`
|
||||
-->
|
|
@ -0,0 +1,24 @@
|
|||
import Walk from "../walk.mjs";
|
||||
import path from "path";
|
||||
|
||||
var rootpath = process.argv[2] || ".";
|
||||
|
||||
Walk.walk(rootpath, async function (err, pathname, dirent) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
var entType;
|
||||
if (dirent.isDirectory()) {
|
||||
entType = " dir";
|
||||
} else if (dirent.isFile()) {
|
||||
entType = "file";
|
||||
} else if (dirent.isSymbolicLink()) {
|
||||
entType = "link";
|
||||
} else {
|
||||
entType = "----";
|
||||
}
|
||||
console.info("[%s] %s", entType, path.dirname(pathname), dirent.name);
|
||||
}).catch(function (err) {
|
||||
console.error(err.stack);
|
||||
});
|
|
@ -0,0 +1,106 @@
|
|||
// a port of Go's filepath.Walk
|
||||
|
||||
import { promises as fs } from "fs";
|
||||
import path from "path";
|
||||
|
||||
var Walk = {};
|
||||
var _withFileTypes = { withFileTypes: true };
|
||||
var _skipDir = new Error("skip this directory");
|
||||
var _noopts = {};
|
||||
|
||||
function pass(err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
function skipOrThrow(err) {
|
||||
if (!(err instanceof Error)) {
|
||||
// go
|
||||
return false;
|
||||
}
|
||||
if (_skipDir === err) {
|
||||
// skip
|
||||
return true;
|
||||
}
|
||||
// throw
|
||||
throw err;
|
||||
}
|
||||
|
||||
Walk.skipDir = _skipDir;
|
||||
|
||||
Walk.walk = async function _walk(root, walker, opts) {
|
||||
if (!opts) {
|
||||
opts = _noopts;
|
||||
}
|
||||
|
||||
// Special case of the very first item, root
|
||||
var err;
|
||||
var stat = await fs.lstat(root).catch(function (e) {
|
||||
err = e;
|
||||
return null;
|
||||
});
|
||||
if (stat) {
|
||||
stat.name = path.basename(path.resolve(root));
|
||||
}
|
||||
|
||||
/* similar to function in main walk loop */
|
||||
var uerr = await walker(err, root, stat).then(pass).catch(pass);
|
||||
if (skipOrThrow(uerr) || err) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (false === opts.withFileTypes) {
|
||||
stat = stat.name;
|
||||
}
|
||||
if (opts.sort) {
|
||||
stat = (opts.sort([stat]) || [])[0];
|
||||
}
|
||||
|
||||
if (stat && stat.isDirectory()) {
|
||||
return _walkHelper(root, stat, walker, opts);
|
||||
}
|
||||
/* end */
|
||||
};
|
||||
|
||||
async function _walkHelper(root, prevEnt, walker, opts) {
|
||||
var err;
|
||||
var _readdirOpts;
|
||||
if (false !== opts.withFileTypes) {
|
||||
_readdirOpts = _withFileTypes;
|
||||
}
|
||||
var dirents = await fs.readdir(root, _readdirOpts).catch(function (e) {
|
||||
err = e;
|
||||
});
|
||||
if (err) {
|
||||
return walker(err, root, prevEnt);
|
||||
}
|
||||
if (opts.sort) {
|
||||
dirents = opts.sort(dirents);
|
||||
}
|
||||
|
||||
var dirent;
|
||||
var pathname;
|
||||
for (dirent of dirents) {
|
||||
if ("string" === typeof dirent) {
|
||||
pathname = path.join(root, dirent);
|
||||
dirent = await fs.lstat(path.join(root)).catch(function (e) {
|
||||
err = e;
|
||||
});
|
||||
} else {
|
||||
pathname = path.join(root, dirent.name);
|
||||
}
|
||||
|
||||
/* main inner loop */
|
||||
err = await walker(err, pathname, dirent).then(pass).catch(pass);
|
||||
if (skipOrThrow(err)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// "walk does not follow symbolic links"
|
||||
if (dirent.isDirectory()) {
|
||||
await _walkHelper(path.join(root, dirent.name), dirent, walker, opts);
|
||||
}
|
||||
/* end */
|
||||
}
|
||||
}
|
||||
|
||||
export default Walk;
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "walk",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
||||
"license": "MIT"
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
// a port of Go's filepath.Walk
|
||||
|
||||
import { promises as fs } from "fs";
|
||||
import path from "path";
|
||||
|
||||
var Walk = {};
|
||||
var _withFileTypes = { withFileTypes: true };
|
||||
var _skipDir = new Error("skip this directory");
|
||||
|
||||
function pass(err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
function skipOrThrow(err) {
|
||||
if (!(err instanceof Error)) {
|
||||
// go
|
||||
return false;
|
||||
}
|
||||
if (_skipDir === err) {
|
||||
// skip
|
||||
return true;
|
||||
}
|
||||
// throw
|
||||
throw err;
|
||||
}
|
||||
|
||||
Walk.skipDir = _skipDir;
|
||||
|
||||
Walk.walk = async function _walk(root, walker) {
|
||||
// Special case of the very first item, root
|
||||
var err;
|
||||
var stat = await fs.lstat(root).catch(function (e) {
|
||||
err = e;
|
||||
return null;
|
||||
});
|
||||
stat.name = path.basename(path.resolve(root));
|
||||
|
||||
/* similar to function in main walk loop */
|
||||
var uerr = await walker(err, root, stat).then(pass).catch(pass);
|
||||
if (skipOrThrow(uerr) || err) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
return _walkHelper(root, stat, walker);
|
||||
}
|
||||
/* end */
|
||||
};
|
||||
|
||||
async function _walkHelper(root, prevEnt, walker) {
|
||||
var err;
|
||||
var dirents = await fs.readdir(root, _withFileTypes).catch(function (e) {
|
||||
err = e;
|
||||
});
|
||||
if (err) {
|
||||
return walker(err, root, prevEnt);
|
||||
}
|
||||
|
||||
var dirent;
|
||||
var pathname;
|
||||
var _name;
|
||||
for (dirent of dirents) {
|
||||
if ("string" === typeof dirent) {
|
||||
_name = dirent;
|
||||
pathname = path.join(root, _name);
|
||||
dirent = await fs.lstat(pathname).catch(function (e) {
|
||||
err = e;
|
||||
});
|
||||
dirent.name = _name;
|
||||
} else {
|
||||
pathname = path.join(root, dirent.name);
|
||||
}
|
||||
|
||||
/* main inner loop */
|
||||
err = await walker(err, pathname, dirent).then(pass).catch(pass);
|
||||
if (skipOrThrow(err)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// "walk does not follow symbolic links"
|
||||
if (dirent.isDirectory()) {
|
||||
await _walkHelper(path.join(root, dirent.name), dirent, walker);
|
||||
}
|
||||
/* end */
|
||||
}
|
||||
}
|
||||
|
||||
export default Walk;
|
Loading…
Reference in New Issue