Socket
Socket
Sign inDemoInstall

@danmasta/walk

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@danmasta/walk - npm Package Compare versions

Comparing version 4.1.0 to 4.2.0

index.mjs

4

index.js
const Walk = require('./lib/walk');
const walk = Walk.factory();
exports = module.exports = Walk.factory();
exports = module.exports = walk;
exports.walk = walk;
exports.Walk = Walk;
const path = require('path');
const fs = require('fs/promises');
const { createReadStream, createWriteStream } = require('fs');
const util = require('./util');
const { BOM } = require('./constants');
const _ = require('lodash');
const util = require('./util');
const fs = require('fs');
const constants = require('./constants');

@@ -22,11 +23,2 @@ const defaults = {

class FileError extends Error {
constructor (str) {
super(str);
Error.captureStackTrace(this, FileError);
this.name = 'FileError';
this.code = 'FILEERROR';
}
}
class File {

@@ -36,3 +28,3 @@

_.defaults(this, opts, defaults);
Object.assign(this, util.defaults(opts, defaults));

@@ -46,3 +38,3 @@ this.root = this.root ? util.stripTrailingSep(this.root) : this.cwd;

if (!this.path) {
throw new File.FileError('Path or relative field is required');
throw new util.FileError('Path or relative field is required');
}

@@ -60,3 +52,3 @@

createReadStream (opts) {
return fs.createReadStream(
return createReadStream(
this.path,

@@ -68,3 +60,3 @@ _.defaults(opts, { encoding: this.encoding })

createWriteStream (opts) {
return fs.createWriteStream(
return createWriteStream(
this.path,

@@ -75,4 +67,4 @@ _.defaults(opts, { encoding: this.encoding })

append (data, opts) {
return fs.promises.appendFile(
async append (data, opts) {
return fs.appendFile(
this.path,

@@ -84,4 +76,4 @@ data,

read (opts) {
return fs.promises.readFile(
async read (opts) {
return fs.readFile(
this.path,

@@ -92,5 +84,5 @@ _.defaults(opts, { encoding: this.encoding })

readAsString (opts) {
async readAsString (opts) {
if ((!opts || opts && !opts.encoding) && !this.encoding) {
return Promise.reject(new File.FileError('Encoding is required to read as string'));
throw new util.FileError('Encoding is required to read as string');
} else {

@@ -101,3 +93,3 @@ return this.read(opts);

readAsBuffer (opts) {
async readAsBuffer (opts) {
return this.read(

@@ -108,12 +100,12 @@ _.assign(opts, { encoding: null })

readStr (...args) {
async readStr (...args) {
return this.readAsString(...args);
}
readBuf (...args) {
async readBuf (...args) {
return this.readAsBuffer(...args);
}
write (data, opts) {
return fs.promises.writeFile(
async write (data, opts) {
return fs.writeFile(
this.path,

@@ -129,2 +121,55 @@ data,

async import () {
switch (this.ext) {
case '.json':
return import(this.path, { assert: { type: 'json' }});
default:
return import(this.path);
}
}
async requireOrImport () {
switch (this.ext) {
case '.json':
if (util.isEsmMode()) {
return this.import();
} else {
return this.require();
}
case '.js':
case '.cjs':
if (util.isEsmMode()) {
return this.import();
} else {
try {
return this.require();
} catch (err) {
if (err.code === 'ERR_REQUIRE_ESM' || err.code === 'ERR_REQUIRE_ASYNC_MODULE') {
return this.import();
}
throw err;
}
}
case '.mjs':
return this.import();
default:
throw new util.FileError('File type not supported for require or import: %s', this.ext);
}
}
async requireImportOrRead () {
try {
return this.requireOrImport();
} catch (err) {
if (err.code === 'ERR_FILE') {
return this.read();
}
throw err;
}
}
isModule () {
return util.isModule(this.contents);
}
isBuffer () {

@@ -142,2 +187,6 @@ return util.isBuffer(this.contents);

isNil () {
return util.isNil(this.contents);
}
isString () {

@@ -151,3 +200,3 @@ return typeof this.contents === 'string';

isSymbolic () {
isSymbolicLink () {
return this.stat && this.stat.isSymbolicLink();

@@ -180,37 +229,27 @@ }

getEncodingFromBOM () {
async getEncodingFromBOM () {
let buff = Buffer.alloc(4);
let enc = undefined;
let fd = await fs.open(this.path, 'r');
return fs.promises.open(this.path, 'r').then(fd => {
await fd.read(buff, 0, 4, 0);
await fd.close();
return fd.read(buff, 0, 4, 0).then(() => {
return fd.close();
});
_.some(BOM, (val, key) => {
if (buff.indexOf(val) === 0) {
return enc = key;
}
});
}).then(() => {
return enc;
_.some(File.constants.BOM, (val, key) => {
if (buff.indexOf(val) === 0) {
return enc = key;
}
});
return enc;
});
}
static get FileError () {
return FileError;
return util.FileError;
}
static get constants () {
return constants;
}
}
module.exports = File;
const path = require('path');
const isBuffer = require('buffer').Buffer.isBuffer;
const os = require('os');
const fs = require('fs');
const _ = require('lodash');
const format = require('util').format;
class WalkError extends Error {
constructor (...args) {
super(format(...args));
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.code = this.constructor.code;
}
static get code () {
return 'ERR_WALK';
}
}
class NotFoundError extends WalkError {
constructor (path) {
super('File or Directory Not Found: %s', path);
this.path = path;
}
static get code () {
return 'ERR_WALK_NOT_FOUND';
}
}
class NotResolvedError extends WalkError {
constructor (path) {
super('Unable to Resolve File or Directory: %s', path);
this.path = path;
}
static get code () {
return 'ERR_WALK_NOT_RESOLVED';
}
}
class FileError extends Error {
constructor (...args) {
super(format(...args));
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.code = this.constructor.code;
}
static get code () {
return 'ERR_FILE';
}
}
// Resolve file path with support for home char
function resolvePath (str, dir) {
if (str[0] === '~') {
return path.normalize(path.join(os.homedir(), str.slice(1)));
} else {
if (dir) {
return path.resolve(dir, str);
} else {
return path.resolve(str);
}
}
}
async function resolvePathIfExists (str, dir, resolve) {
let path;
try {
path = resolvePath(str, dir);
await fs.promises.access(path, fs.constants.F_OK);
return path;
} catch (err) {
if (resolve) {
try {
return require.resolve(path);
} catch (err) {
throw new NotResolvedError(str);
}
} else {
throw new NotFoundError(str);
}
}
}
function resolvePathIfExistsSync (str, dir, resolve) {
let path;
try {
path = resolvePath(str, dir);
fs.accessSync(path, fs.constants.F_OK);
return path;
} catch (err) {
if (resolve) {
try {
return require.resolve(path);
} catch (err) {
throw new NotResolvedError(str);
}
} else {
throw new NotFoundError(str);
}
}
}
function normalize (str) {

@@ -17,11 +116,7 @@ return str && path.normalize(str);

function isStream (obj) {
let pipe = obj && obj.pipe;
if (pipe && typeof pipe === 'function') {
return true;
} else {
return false;
}
return false;
}

@@ -33,2 +128,70 @@

function defaults (...args) {
let accumulator = {};
function iterate (res, obj, def) {
_.forOwn(obj, (val, key) => {
if (_.has(def, key)) {
if (_.isPlainObject(def[key])) {
res[key] = iterate(_.toPlainObject(res[key]), val, def[key]);
} else {
if (res[key] === undefined) {
res[key] = val;
}
}
}
});
return res;
}
args.map(obj => {
iterate(accumulator, obj, args.at(-1));
});
return accumulator;
}
function isNil (val) {
return val == null;
}
function notNil (val) {
return val != null;
}
function each (arr, fn) {
if (Array.isArray(arr) || arr instanceof Map || arr instanceof Set) {
arr.forEach(fn);
} else {
fn(arr, 0);
}
}
function eachNotNil (arr, fn) {
each(arr, (val, key) => {
if (notNil(val)) {
fn(val, key);
}
});
}
// Test if running in esm or commonjs mode
function isEsmMode () {
return typeof module === 'undefined';
}
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import#module_namespace_object
function isModule (obj) {
return notNil(obj) && obj[Symbol.toStringTag] === 'Module';
}
exports.WalkError = WalkError;
exports.NotFoundError = NotFoundError;
exports.NotResolvedError = NotResolvedError;
exports.FileError = FileError;
exports.resolvePath = resolvePath;
exports.resolvePathIfExists = resolvePathIfExists;
exports.resolvePathIfExistsSync = resolvePathIfExistsSync;
exports.normalize = normalize;

@@ -40,1 +203,8 @@ exports.stripStartingSep = stripStartingSep;

exports.unixify = unixify;
exports.defaults = defaults;
exports.isNil = isNil;
exports.notNil = notNil;
exports.each = each;
exports.eachNotNil = eachNotNil;
exports.isEsmMode = isEsmMode;
exports.isModule = isModule;
const Readable = require('stream').Readable;
const fs = require('fs');
const path = require('path');
const os = require('os');
const micromatch = require('micromatch');
const _ = require('lodash');
const File = require('./file');
const FileResolver = require('./resolver');
const util = require('./util');
const constants = require('./constants');
const _ = require('lodash');
const defaults = {
cwd: process.cwd(),
root: './',
src: constants.GLOBS.all,
dot: true,
ignore: constants.GLOBS.ignore,
encoding: 'utf8',
objectMode: true,
resolve: true
};
class NotFoundError extends Error {
constructor (str) {
let msg = `File or Directory Not Found: ${str}`;
super(msg);
Error.captureStackTrace(this, NotFoundError);
this.name = 'NotFoundError';
this.code = 'PATHNOTFOUND';
this.path = str;
}
}
class NotResolvedError extends Error {
constructor (str) {
let msg = `Unable to Resolve File or Directory: ${str}`;
super(msg);
Error.captureStackTrace(this, NotResolvedError);
this.name = 'NotResolvedError';
this.code = 'PATHNOTRESOLVED';
this.path = str;
}
}
class Walk extends Readable {

@@ -56,72 +19,24 @@

if (paths) {
if (!_.isArray(paths)) {
if (!opts.root) {
opts.root = paths;
paths = [];
} else {
paths = [paths];
}
}
} else {
paths = [];
if (!opts.paths) {
opts.paths = paths;
}
opts = _.defaults(opts, defaults);
super({ objectMode: true });
if (!opts.dot && opts.src === constants.GLOBS.all) {
opts.src = constants.GLOBS.dot;
}
this.reading = false;
this.resolver = new this.constructor.FileResolver(opts);
this.opts = opts;
this.include = null;
this.exclude = null;
opts.root = util.stripTrailingSep(this.getRootWalkPath(opts.root));
if (opts.src) {
this.include = micromatch.matcher(opts.src, { dot: opts.dot });
}
if (opts.ignore) {
this.exclude = micromatch.matcher(opts.ignore, { dot: opts.dot });
}
this.queue = [];
this.paths = paths;
this.pending = 0;
this.inFlight = 0;
// Should be true until we push at least one file on each iteration
this.shouldRead = true;
if (!this.paths.length) {
this.paths.push(this.opts.root);
}
}
_read () {
if (!this.inFlight && !this.pending) {
this.handleRead();
}
}
handleRead () {
if (this.canRead()) {
this.readFromQueue().then(() => {
if (this.shouldRead) {
this.handleRead();
async _read () {
if (!this.reading) {
this.reading = true;
let file;
while ((file = await this.resolver.next()) !== null) {
if (!this.push(file)) {
this.reading = false;
break;
}
});
} else {
if (this.paths.length) {
this.addPathIfExists(this.paths.shift()).then(() => {
if (this.shouldRead) {
this.handleRead();
}
});
} else if (this.isEmpty()) {
}
if (file === null) {
this.push(null);

@@ -132,170 +47,9 @@ }

canRead () {
return this.queue.length > 0;
}
async iterate (fn, res) {
isEmpty () {
return !this.inFlight && !this.pending && !this.queue.length && !this.paths.length;
}
let file;
resolvePathFromHomeOrRoot (str) {
if (str && str[0] === '~') {
return path.normalize(path.join(os.homedir(), str.slice(1)));
} else {
return path.resolve(this.opts.root, str);
}
}
resolvePathFromHomeOrCWD (str) {
if (str && str[0] === '~') {
return path.normalize(path.join(os.homedir(), str.slice(1)));
} else {
return path.resolve(this.opts.cwd, str);
}
}
// Resolve path from user home or cwd
// Verifies path exists or throws error
getRootWalkPath (str) {
let res = this.resolvePathFromHomeOrCWD(str);
let stat = null;
try {
stat = fs.statSync(res);
if (stat.isDirectory() || stat.isFile()) {
return res;
} else {
this.destroy(new Walk.NotFoundError(res));
}
} catch (err) {
if (this.opts.resolve) {
try {
return require.resolve(res);
} catch (err) {
this.destroy(new Walk.NotResolvedError(res));
}
} else {
this.destroy(new Walk.NotFoundError(res));
}
}
}
addPathIfExists (str) {
str = this.resolvePathFromHomeOrRoot(str);
this.pending++;
return fs.promises.access(str, fs.constants.F_OK).then(() => {
this.pending--;
this.pushToQueue(str);
}).catch(err => {
if (this.opts.resolve) {
try {
this.pending--;
this.pushToQueue(require.resolve(str));
} catch (err) {
this.destroy(new Walk.NotResolvedError(str));
}
} else {
this.pending--;
this.destroy(new Walk.NotFoundError(str));
}
});
}
pushToQueue (str) {
return this.queue.push(str);
}
readFromQueue () {
return this.walkFileOrDir(this.queue.shift());
}
readDir (str) {
this.inFlight++;
return fs.promises.readdir(str).then(list => {
_.each(list, name => {
let abs = path.resolve(str, name);
let rel = path.relative(this.opts.root, abs);
if (!this.exclude || !this.exclude(rel)) {
this.pushToQueue(abs);
}
});
this.inFlight--;
this.shouldRead = true;
});
}
createFile (str, stat) {
return new this.constructor.File({
path: str,
stat,
cwd: this.opts.cwd,
root: this.opts.root,
encoding: this.opts.encoding
});
}
addFile (str, stat) {
this.inFlight++;
return new Promise((resolve, reject) => {
let file = this.createFile(str, stat);
if (!this.include || this.include(file.relative || file.base)) {
this.push(file);
this.shouldRead = false;
} else {
this.shouldRead = true;
}
this.inFlight--;
resolve();
});
}
walkFileOrDir (str) {
this.pending++;
return fs.promises.stat(str).then(stat => {
this.pending--;
if (stat.isDirectory()) {
return this.readDir(str);
} else {
return this.addFile(str, stat);
}
});
}
iterate (fn, res) {
this.on('data', file => {
while ((file = await this.resolver.next()) !== null) {
if (fn) {
try {
file = fn(file);
} catch (err) {
this.destroy(err);
}
file = await fn(file);
}

@@ -305,12 +59,5 @@ if (res) {

}
});
}
return new Promise((resolve, reject) => {
this.once('end', () => {
resolve(res);
});
this.once('error', err => {
reject(err);
});
});
return res;

@@ -320,12 +67,14 @@ }

map (fn) {
fn = _.isFunction(fn) ? fn : file => file;
return this.iterate(fn, []);
return this.iterate(_.isFunction(fn) ? fn : file => file, []);
}
tap (fn) {
return this.iterate(_.isFunction(fn) ? async file => { await fn(file); return file; } : file => file, []);
}
each (fn) {
fn = _.isFunction(fn) ? fn : _.noop;
return this.iterate(fn);
return this.iterate(_.isFunction(fn) ? fn : _.noop);
}
promise () {
async promise () {
return this.iterate(null, []);

@@ -349,14 +98,14 @@ }

static get WalkError () {
return util.WalkError;
}
static get NotFoundError () {
return NotFoundError;
return util.NotFoundError;
}
static get NotResolvedError () {
return NotResolvedError;
return util.NotResolvedError;
}
static get constants () {
return constants;
}
static get File () {

@@ -366,4 +115,8 @@ return File;

static get FileResolver () {
return FileResolver;
}
}
module.exports = Walk;
{
"name": "@danmasta/walk",
"version": "4.1.0",
"version": "4.2.0",
"author": "Daniel Smith <dannmasta@gmail.com>",

@@ -16,5 +16,18 @@ "description": "Directory and file walking utility for node apps",

"index.js",
"sync.js",
"lib/**/*"
"index.mjs",
"lib/**/*",
"sync/**/*"
],
"exports": {
".": {
"import": "./index.mjs",
"require": "./index.js"
},
"./sync": {
"import": "./sync/index.mjs",
"require": "./sync/index.js"
},
"./lib/*": "./lib/*.js",
"./sync/*": "./sync/*.js"
},
"scripts": {

@@ -21,0 +34,0 @@ "test": "./node_modules/.bin/mocha tests",

@@ -29,3 +29,3 @@ # Walk

```
*By default walk returns a readable stream interface. You can use the methods: `map()`, `each()`, `promise()`, `then()`, and `catch()` to iterate file objects and return promises*
*By default walk returns a readable stream interface. You can use the methods: `map()`, `tap()`, `each()`, `promise()`, `then()`, and `catch()` to iterate file objects and return promises*

@@ -42,2 +42,3 @@ ### Options

`resolve` | *`boolean`* | Whether or not to attempt to resolve file paths if not found. Default is `true`
`paths` | *`array\|string`* | Which paths to walk for files. Default is `undefined`

@@ -47,3 +48,4 @@ ### Methods

-----|------------
`map(fn)` | Runs an iterator function over each file. Returns a promise that resolves with a new `array`
`map(fn)` | Runs an iterator function over each file. Returns a promise that resolves with a new `array` of return values
`tap(fn)` | Runs an iterator function over each file. Returns a promise that resolves with an `array` of file objects
`each(fn)` | Runs an iterator function over each file. Returns a promise that resolves with `undefined`

@@ -85,8 +87,13 @@ `promise` | Returns a promise that resolves with an `array` of file objects

`require` | Reads the file contents using `require`
`import` | Reads the file contents using `import`. Returns a promise
`requireOrImport` | Reads the file contents using `import` or `require` based on esm-ness. Returns a promise
`requireImportOrRead` | Reads the file contents using `import` or `require` if able, otherwise reads as string or buffer based on encoding. Returns a promise
`isModule` | Returns `true` if `file.contents` is a [`module`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import#module_namespace_object)
`isBuffer` | Returns `true` if `file.contents` is a [`buffer`](https://nodejs.org/api/buffer.html#buffer_class_method_buffer_isbuffer_obj)
`isStream` | Returns `true` if `file.contents` is a [`stream`](https://nodejs.org/api/stream.html)
`isNull` | Returns `true` if `file.contents` is `null`
`isNil` | Returns `true` if `file.contents` is `null` or `undefined`
`isString` | Returns `true` if `file.contents` is a `string`
`isDirectory` | Returns `true` if the file is a [directory](https://nodejs.org/api/fs.html#fs_stats_isdirectory)
`isSymbolic` | Returns `true` if the file is a [symbolic link](https://nodejs.org/api/fs.html#fs_stats_issymboliclink)
`isSymbolicLink` | Returns `true` if the file is a [symbolic link](https://nodejs.org/api/fs.html#fs_stats_issymboliclink)
`isBlockDevice` | Returns `true` if the file is a [block device](https://nodejs.org/api/fs.html#fs_stats_isblockdevice)

@@ -93,0 +100,0 @@ `isCharacterDevice` | Returns `true` if the file is a [character device](https://nodejs.org/api/fs.html#fs_stats_ischaracterdevice)

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