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 1.1.1 to 2.0.0

397

index.js

@@ -6,67 +6,118 @@ const path = require('path');

const util = require('./lib/util');
const micromatch = require('micromatch');
const Readable = require('stream').Readable;
const _ = require('lodash');
// convert fs apis to promises
const readdirAsync = Promise.promisify(fs.readdir);
const statAsync = Promise.promisify(fs.stat);
const readFileAsync = Promise.promisify(fs.readFile);
const accessAsync = Promise.promisify(fs.access);
// walk directory asyncronously using promises
function walkDirAsync() {
const constants = {
GLOBS: {
all: '*(../)*(**/)*',
ignore: '*(../)*(**/)(.git|node_modules)',
dot: '*(../)*(**/)!(.)*'
}
};
let opts = util.opts(...arguments);
const defaults = {
cwd: process.cwd(),
root: './',
require: false,
stream: false,
read: false,
sync: false,
contents: false,
buffer: false,
src: constants.GLOBS.all,
dot: true,
ignore: constants.GLOBS.ignore,
cb: _.noop
};
function walkdir(dir) {
class Walker {
return util.concatMapAsync(readdirAsync(dir), name => {
constructor (opts) {
let abs = path.resolve(dir, name);
opts = _.defaults(opts, defaults);
return statAsync(abs).then(stat => {
if (!opts.dot && opts.src === constants.GLOBS.all) {
opts.src = constants.GLOBS.dot;
}
if (stat.isDirectory()) {
opts.root = util.stripTrailingSep(path.resolve(opts.cwd, opts.root));
if (!opts.regex.test(name)) {
return walkdir(abs);
}
if (opts.require || opts.read === 'require') {
opts.read = 'require';
} else if (opts.stream || opts.read === 'stream') {
opts.read = 'stream';
} else if (opts.read || opts.contents) {
opts.read = 'contents';
}
} else {
this.opts = opts;
this.include = null;
this.exclude = null;
let file = new File({ path: abs, stat: stat, cwd: opts.cwd, root: opts.root });
if (opts.src) {
this.include = micromatch.matcher(opts.src, { dot: opts.dot });
}
if (opts.matcher(file.relative || file.base)) {
return file;
}
if (opts.ignore) {
this.exclude = micromatch.matcher(opts.ignore, { dot: opts.dot });
}
}
}
});
_resolve (str) {
return path.resolve(this.opts.root, str);
}
});
_contents (file) {
}
return Promise.resolve().then(() => {
return walkdir(opts.root);
if (this.opts.read === 'require') {
}
return require(file.path);
} else if (this.opts.read === 'stream') {
// walk async
function walk() {
return fs.createReadStream(file.path);
let opts = util.opts(...arguments);
} else {
return statAsync(opts.root).then(stat => {
return readFileAsync(file.path).then(buff => {
if (this.opts.buffer) {
return buff;
} else {
return buff.toString();
}
});
if (stat.isDirectory()) {
}
return walkDirAsync(opts);
});
}
_contentsSync (file) {
if (this.opts.read === 'require') {
return require(file.path);
} else if (this.opts.read === 'stream') {
return fs.createReadStream(file.path);
} else {
let file = new File({ path: opts.root, stat: stat, cwd: opts.cwd, root: opts.root });
let buff = fs.readFileSync(file.path);
if (opts.matcher(file.relative || file.base)) {
return [file];
if (this.opts.buffer) {
return buff;
} else {
return [];
return buff.toString();
}

@@ -76,80 +127,116 @@

}).catch(err => {
}
opts.root = require.resolve(opts.root);
_walk (str) {
return walk(opts);
return statAsync(str).then(stat => {
});
if (stat.isDirectory()) {
}
return readdirAsync(str).map(name => {
// walk directory syncronously
function walkDirSync() {
let res = path.resolve(str, name);
let rel = path.relative(this.opts.root, res);
let opts = util.opts(...arguments);
if (!this.exclude || !this.exclude(rel)) {
return this._walk(res);
}
function walkdir(dir) {
});
return util.concatMap(fs.readdirSync(dir), name => {
} else {
let abs = path.resolve(dir, name);
let stat = fs.statSync(abs);
let file = new File({ path: str, stat: stat, cwd: this.opts.cwd, root: this.opts.root });
if (stat.isDirectory()) {
if (!this.include || this.include(file.relative || file.base)) {
if (!opts.regex.test(name)) {
return walkdir(abs);
if (this.opts.read) {
return this._contents(file).then(contents => {
file.contents = contents;
this.opts.cb(file);
});
} else {
return this.opts.cb(file);
}
}
} else {
}
let file = new File({ path: abs, stat: stat, cwd: opts.cwd, root: opts.root });
});
if (opts.matcher(file.relative || file.base)) {
return file;
}
_walkSync (str) {
let stat = fs.statSync(str);
if (stat.isDirectory()) {
return fs.readdirSync(str).map(name => {
let res = path.resolve(str, name);
let rel = path.relative(this.opts.root, res);
if (!this.exclude || !this.exclude(rel)) {
return this._walkSync(res);
}
});
} else {
let file = new File({ path: str, stat: stat, cwd: this.opts.cwd, root: this.opts.root });
if (!this.include || this.include(file.relative || file.base)) {
if (this.opts.read) {
file.contents = this._contentsSync(file);
}
return this.opts.cb(file);
}
});
}
}
return walkdir(opts.root);
walk (str) {
}
str = this._resolve(str);
// walk sync
function walkSync() {
return accessAsync(str, fs.constants.F_OK).then(() => {
let opts = util.opts(...arguments);
let stat = null;
return str;
try {
}).catch(() => {
stat = fs.statSync(opts.root);
return require.resolve(str);
} catch (err) {
}).then(str => {
opts.root = require.resolve(opts.root);
return this._walk(str);
return walkSync(opts);
});
}
if (stat.isDirectory()) {
sync (str) {
return walkDirSync(opts);
str = this._resolve(str);
} else {
try {
let file = new File({ path: opts.root, stat: stat, cwd: opts.cwd, root: opts.root });
fs.accessSync(str, fs.constants.F_OK);
if (opts.matcher(file.relative || file.base)) {
return [file];
} else {
return [];
} catch (err) {
str = require.resolve(str);
}
return this._walkSync(str);
}

@@ -159,27 +246,56 @@

// get file contents async
function contents() {
class WalkStream extends Readable {
let opts = util.opts(...arguments);
constructor (str, opts) {
return walk(opts).map(file => {
super({ objectMode: true });
if (opts.require) {
opts = _.assign(opts, { cb: this.push.bind(this) });
file.contents = require(file.path);
this._str = str;
this._walker = new Walker(opts);
return file;
}
} else {
_read (size) {
return readFileAsync(file.path, 'utf8').then(contents => {
if (!this.init) {
this._init();
}
file.contents = contents;
}
return file;
_init () {
this.init = true;
if (!this._walker.opts.sync) {
this._walker.walk(this._str).then(() => {
this.push(null);
});
} else {
this._walker.sync(this._str);
this.push(null);
}
}
}
function _walk (str, opts) {
let res = [];
let cb = res.push.bind(res);
let walker = null;
if (_.isFunction(opts && opts.cb)) {
cb = file => {
res.push(opts.cb(file));
};
}
walker = new Walker(_.assign(null, opts, { cb }));
return walker.walk(str).then(() => {
return res;
});

@@ -189,61 +305,104 @@

// get file contents sync
function contentsSync() {
function _sync (str, opts) {
let opts = util.opts(...arguments);
let res = [];
let cb = res.push.bind(res);
let walker = null;
return walkSync(opts).map(file => {
if (_.isFunction(opts && opts.cb)) {
cb = file => {
res.push(opts.cb(file));
};
}
if (opts.require) {
walker = new Walker(_.assign(null, opts, { cb, sync: true }));
walker.sync(str);
file.contents = require(file.path);
return res;
return file;
}
} else {
function _contents (str, opts) {
file.contents = fs.readFileSync(file.path, 'utf8');
opts = _.assign(opts, { read: true });
return file;
return _walk(str, opts);
}
}
});
function _contentsSync (str, opts) {
opts = _.assign(opts, { read: true, sync: true });
return _sync(str, opts);
}
// run callback for each file async
function each(...args) {
function _require (str, opts) {
let cb = typeof args[args.length - 1] === 'function' ? args.pop() : file => {
return file;
};
opts = _.assign(opts, { require: true });
let opts = util.opts(...args);
let fn = opts.read ? contents : walk;
return _walk(str, opts);
return fn.call(null, opts).map(cb);
}
function _requireSync (str, opts) {
opts = _.assign(opts, { require: true, sync: true });
return _sync(str, opts);
}
// run callback for each file sync
function eachSync(...args) {
function _stream (str, opts) {
let cb = typeof args[args.length - 1] === 'function' ? args.pop() : file => {
return file;
};
opts = _.assign(opts);
let opts = util.opts(...args);
let fn = opts.read ? contentsSync : walkSync;
return new WalkStream(str, opts);
return fn.call(null, opts).map(cb);
}
function _streamSync (str, opts) {
opts = _.assign(opts, { sync: true });
return new WalkStream(str, opts);
}
// export api
exports.walk = walk;
exports.walkSync = walkSync;
exports.contents = contents;
exports.contentsSync = contentsSync;
exports.each = each;
exports.eachSync = eachSync;
function _each (str, opts, cb) {
if (_.isFunction(opts)) {
cb = opts;
}
opts = _.assign(opts, { cb: cb });
return _walk(str, opts);
}
function _eachSync (str, opts, cb) {
if (_.isFunction(opts)) {
cb = opts;
}
opts = _.assign(opts, { cb: cb });
return _sync(str, opts);
}
exports = module.exports = _walk;
exports.walk = _walk;
exports.sync = _sync;
exports.Walker = Walker;
exports.contents = _contents;
exports.contents.sync = _contentsSync;
exports.require = _require;
exports.require.sync = _requireSync;
exports.stream = _stream;
exports.stream.sync = _streamSync;
exports.each = _each;
exports.each.sync = _eachSync;

@@ -10,2 +10,3 @@ const path = require('path');

relative: null,
relativeFromCwd: null,
dir: null,

@@ -21,6 +22,4 @@ base: null,

constructor(opts) {
constructor (opts) {
let parsed = null;
_.defaults(this, opts, defaults);

@@ -31,41 +30,39 @@

if (!this.path && this.relative) {
this.path = this.path || util.normalize(path.join(this.root, this.relative));
this.path = util.normalize(path.join(this.root, this.relative));
}
if (!this.path) {
throw new Error('Path or relative field is required');
throw new Error('File Error: path or relative field is required');
}
if (this.relative) {
this.relative = util.stripStartingSep(this.relative);
} else {
this.relative = util.stripStartingSep(this.path.slice(this.root.length));
}
this.relative = path.relative(this.root, this.path);
this.relativeFromCwd = path.relative(this.cwd, this.path);
this.dir = path.dirname(this.path);
this.base = path.basename(this.path);
this.ext = path.extname(this.path);
this.name = path.basename(this.path, this.ext);
parsed = path.parse(this.path);
this.dir = parsed.dir;
this.base = parsed.base;
this.ext = parsed.ext;
this.name = parsed.name;
}
isBuffer() {
isBuffer () {
return util.isBuffer(this.contents);
}
isStream() {
isStream () {
return util.isStream(this.contents);
}
isNull() {
isNull () {
return this.contents === null;
}
isDirectory() {
isString () {
return typeof this.contents === 'string';
}
isDirectory () {
return this.stat && this.stat.isDirectory();
}
isSymbolic() {
isSymbolic () {
return this.stat && this.stat.isSymbolicLink();

@@ -72,0 +69,0 @@ }

const path = require('path');
const isBuffer = require('buffer').Buffer.isBuffer;
const micromatch = require('micromatch');
const _ = require('lodash');
const defaults = {
cwd: process.cwd(),
root: './',
exclude: ['.git', 'node_modules', 'bower_components'],
require: false,
read: true,
src: '**/*',
dot: true
};
// normalize opts with simple class
class Options {
constructor(opts) {
_.defaults(this, opts, defaults);
this.root = stripTrailingSep(path.resolve(this.cwd, this.root));
this.regex = new RegExp(_.join(_.concat(this.exclude), '|') || 'a^');
this.matcher = micromatch.matcher(this.src, { dot: this.dot });
}
}
function concatMap(collection, fn) {
let res = [];
_.map(collection, (item, key) => {
let x = fn(item, key);
if (_.isArray(x)) {
return res.push.apply(res, x);
}
if (x !== undefined) {
res.push(x);
}
});
return res;
}
function concatMapAsync(promise, fn) {
let res = [];
return promise.map(fn).map(x => {
if (_.isArray(x)) {
return res.push.apply(res, x);
}
if (x !== undefined) {
res.push(x);
}
}).then(() => {
return res;
});
}
function normalize(str) {
function normalize (str) {
return str && path.normalize(str);
}
function stripStartingSep(str) {
function stripStartingSep (str) {
return str && normalize(str).replace(/^[\\/]+/, '');
}
function stripTrailingSep(str) {
function stripTrailingSep (str) {
return str && normalize(str).replace(/[\\/]+$/, '');
}
function isStream(contents) {
function isStream (contents) {

@@ -99,26 +28,6 @@ let pipe = contents && contents.pipe;

exports.opts = function(str, opts) {
function unixify (str) {
return str.replace(/\\+/g, '/');
}
if(str instanceof Options){
return str;
}
if (str && _.isPlainObject(opts)) {
opts.root = str;
} else if (_.isString(str)) {
opts = { root: str };
} else {
opts = str;
}
return new Options(opts);
};
exports.normalize = normalize;

@@ -129,3 +38,2 @@ exports.stripStartingSep = stripStartingSep;

exports.isBuffer = isBuffer;
exports.concatMap = concatMap;
exports.concatMapAsync = concatMapAsync;
exports.unixify = unixify;
{
"name": "@danmasta/walk",
"version": "1.1.1",
"version": "2.0.0",
"author": "Daniel Smith <dannmasta@gmail.com>",

@@ -14,2 +14,6 @@ "description": "Directory and file walking utility for node apps",

"main": "index.js",
"files": [
"index.js",
"lib/**/*"
],
"scripts": {

@@ -16,0 +20,0 @@ "test": "mocha tests"

@@ -6,13 +6,12 @@ # Walk

* Easy to use
* Sync and Async api
* Returns bluebird promises
* Sync, async, streams, and promise api
* Simple filtering with glob pattern matching
* Doesn't use streams or events
* Require file contents or read them
* Can resolve require-style path strings
* Require file contents or read as stream, buffer, or string
* Resolves require-style path strings
* Normalized file objects with helper methods
* Fast pattern matching via [micromatch](https://github.com/micromatch/micromatch)
* Include and exclude pattern matching options
## About
We needed a better way to walk directories and read files during build and/or start time. I wanted an api that was simple, supported glob pattern matching like gulp, and returned objects with a similar format as vinyl. This package allows you to simply read any directory (or file), return an array of objects, and filter results with glob pattern matching. It can also require file contents, and resolve require-style path strings.
We needed a better way to walk directories and read files during build and/or start time. I wanted an api that was simple, supported glob pattern matching like gulp, and returned objects with a similar format as vinyl. This package allows you to simply read any directory (or file), return an array of objects, and filter results with glob pattern matching. It can also require file contents, read as strings, streams, or buffers, and resolve require-style path strings.

@@ -34,8 +33,13 @@ ## Usage

`cwd` | *`string`* | Base directory to start walk from. Default is `process.cwd`
`root` | *`string`* | Directory or file path to walk. This gets normalized as `path.resolve(cwd, root)`. Default is `./`
`exclude` | *`array`* | Array of directory names to exclude from walk. Defaults to `['.git', 'node_modules', 'bower_components']`. Directory names are excluded `before` reading them, this helps it stay fast
`require` | *`boolean`* | Whether to `require` file contents instead of reading them. Default is `false`
`read` | *`boolean`* | Whether to `read\|require` file contents when using `each`. Defaults to `true`
`src` | *`Array\|String\|RegExp`* | [Micromatch pattern](https://github.com/micromatch/micromatch#matcher) for result filtering. Can be a path string, glob pattern string, regular expression, or an array of strings. Defaults to `**/*`
`dot` | *`boolean`* | Whether or not to ignore dot files when matching. Default is `true`
`root` | *`string`* | Directory or file path as root to walk from. This gets normalized as `path.resolve(cwd, root)`. Default is `./`
`require` | *`boolean`* | If true, `file.contents` will be a resolved object using `require`. Default is `false`
`stream` | *`boolean`* | If true, `file.contents` will be a `Readable` stream. Default is `false`
`read` | *`boolean\|string`* | If `true`, will read file contents as a buffer or string. If string, accepts either 'require', 'stream', or 'contents'. Default is `false`
`sync` | *`boolean`* | Wether or not we are running in synchronous mode
`contents` | *`boolean`* | If true, will read file contents as string. Default is `false`
`buffer` | *`boolean`* | If true, when reading file conents, contents will remain a buffer instead of being converted to a string. Default is `false`
`src` | *`Array\|String\|RegExp`* | [Micromatch pattern](https://github.com/micromatch/micromatch#matcher) for result filtering by including any matches. Can be a path string, glob pattern string, regular expression, or an array of strings. Defaults to `*(../)*(**/)*`
`ignore` | *`Array\|String\|RegExp`* | [Micromatch pattern](https://github.com/micromatch/micromatch#matcher) for result filtering by ignoring any matches. Can be a path string, glob pattern string, regular expression, or an array of strings. Defaults to `*(../)*(**/)(.git|node_modules)`
`dot` | *`boolean`* | Whether or not to include dot files when matching. Default is `true`
`cb` | *`function`* | Function to call when flushing a file object. Default is `_.noop`

@@ -45,9 +49,14 @@ ### Methods

-----|------------
`walk([path,][opts])` | Get a list of files based on specified options. Returns a promise that resolves with an array of file objects
`walkSync` | Sync version of `walk`
`contents([path,][opts])` | Get the contents of files based on specified options. Returns a promise that resolves with an array of file objects
`contentsSync` | Sync version of `contents`
`each([path,][opts,][iteratee])` | Runs an iteratee function for each file based on specified options. Returns a promise that resolves with an array of file objects. Iteratee takes one argument [`file`](#file-objects)
`eachSync` | Sync version of `each`
`walk(path, opts)` | Get a list of files based on specified options. Returns a promise that resolves with an array of file objects
`walk.sync` | Sync version of `walk`. Returns an Array
`contents(path, opts)` | Get the contents of files based on specified options. Returns a promise that resolves with an array of file objects
`contents.sync` | Sync version of `contents`. Returns an Array
`each(path, opts, iteratee)` | Runs an iteratee function for each file based on specified options. Returns a promise that resolves with an array of file objects. Iteratee takes one argument [`file`](#file-objects)
`each.sync` | Sync version of `each`. Returns an Array
`require(path, opts)` | Get the contents of files by requiring them. Returns a promise that resolves with an array of file objects
`require.sync` | Sync version of `require`. Returns an Array
`stream(path, opts)` | Return a read stream of file objects
`stream.sync` | Sync version of `stream`. Loads file data synchronously. Returns a read stream
*Each method takes an optional `path` and `options` param as arguments. The `each` methods also accept an iteratee function as the last argument*

@@ -63,3 +72,4 @@

`path` | *`string`* | Absolute path of the file on disk
`relative` | *`string`* | Relative path of file based normalized from `root`
`relative` | *`string`* | Relative path of file based from normalized `root`
`relativeFromCwd` | *`string`* | Relative path of file based from normalized `cwd`
`dir` | *`string`* | Parent directory where file is located

@@ -78,2 +88,3 @@ `base` | *`string`* | File name with extension

`isNull` | Returns `true` if `file.contents` is `null`
`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)

@@ -86,7 +97,7 @@ `isSymbolic` | Returns `true` if the file is a [symbolic link](https://nodejs.org/api/fs.html#fs_stats_issymboliclink)

```js
const walk = require('@danmasta/walk').walk;
const walk = require('@danmasta/walk');
```
Walk the current working directory, exclude all `.json` files
```js
walk({ src: '**/*.!(json)' }).then(res => {
walk('./', { src: '**/*.!(json)' }).then(res => {
console.log('files:', res);

@@ -109,8 +120,5 @@ });

### Contents
```js
const contents = require('@danmasta/walk').contents;
```
Read the contents of all `pug` files in `./views`
```js
contents('./views', { src: '**/*.pug' }).then(res => {
walk.contents('./views', { src: '**/*.pug' }).then(res => {
console.log('templates:', res);

@@ -121,8 +129,5 @@ });

### Each
```js
const each = require('@danmasta/walk').each;
```
Require all `js` files in the `./routes` directory and run a callback for each one
```js
each('./routes', { src: '**/*.js', require: true }, route => {
walk.each('./routes', { src: '**/*.js', require: true }, route => {
app.use(route());

@@ -135,9 +140,9 @@ }).then(res => {

### Synchronous Methods
To use the sync version of any method just append `Sync` to the end of the method name
To use the sync version of any method just append `.sync` to the end of the method name
```js
const contents = require('@danmasta/walk').contentsSync;
const walk = require('@danmasta/walk');
```
Load all templates from the `./views` directory
```js
const templates = contents('./views', { src: '**/*.pug' });
const templates = walk.contents.sync('./views', { src: '**/*.pug' });
console.log('templates:', templates);

@@ -144,0 +149,0 @@ ```

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