Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

readdir-enhanced

Package Overview
Dependencies
Maintainers
1
Versions
39
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

readdir-enhanced - npm Package Compare versions

Comparing version 1.4.5 to 1.5.0

lib/once.js

7

CHANGELOG.md

@@ -6,2 +6,9 @@ # Change Log

## [v1.5.0](https://github.com/BigstickCarpet/readdir-enhanced/tree/v1.5.0) (2017-04-10)
The [`deep` option](README.md#deep) can now be set to a [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp), a [glob pattern](https://github.com/isaacs/node-glob#glob-primer), or a function, which allows you to customize which subdirectories get crawled. Of course, you can also still still set the `deep` option to `true` to crawl _all_ subdirectories, or a number if you just want to limit the recursion depth.
[Full Changelog](https://github.com/BigstickCarpet/readdir-enhanced/compare/v1.4.0...v1.5.0)
## [v1.4.0](https://github.com/BigstickCarpet/readdir-enhanced/tree/v1.4.0) (2016-08-26)

@@ -8,0 +15,0 @@

5

lib/async/for-each.js

@@ -6,3 +6,3 @@ 'use strict';

/**
* A simple async implemenation of {@link Array.forEach}.
* Simultaneously processes all items in the given array.
*

@@ -15,2 +15,4 @@ * @param {array} array - The array to iterate over

if (array.length === 0) {
// NOTE: Normally a bad idea to mix sync and async, but it's safe here because
// of the way that this method is currently used by DirectoryReader.
done();

@@ -20,2 +22,3 @@ return;

// Simultaneously process all items in the array.
var pending = array.length;

@@ -22,0 +25,0 @@ array.forEach(function (item) {

'use strict';
var fs = require('fs');
var once = require('../once');

@@ -12,2 +13,5 @@ /**

exports.readdir = function (dir, callback) {
// Make sure the callback is only called once
callback = once(callback);
try {

@@ -28,2 +32,5 @@ fs.readdir(dir, callback);

exports.stat = function (path, callback) {
// Make sure the callback is only called once
callback = once(callback);
try {

@@ -44,2 +51,5 @@ fs.stat(path, callback);

exports.lstat = function (path, callback) {
// Make sure the callback is only called once
callback = once(callback);
try {

@@ -46,0 +56,0 @@ fs.lstat(path, callback);

68

lib/directory-reader.js

@@ -79,3 +79,3 @@ 'use strict';

// Process each item in the directory
// Process each item in the directory (simultaneously, if async)
facade.forEach(

@@ -145,10 +145,13 @@ items,

// Should we read this directory's subdirectories?
var recurse = (options.depth - dir.depth) > 0;
// If `options.deep` is a number, and we've already recursed to the max depth,
// then there's no need to check fs.Stats to know if it's a directory.
// If `options.deep` is a function, then we'll need fs.Stats
var maxDepthReached = dir.depth >= options.recurseDepth;
// Do we need to call `fs.stat`?
var needStats =
recurse || // we need the fs.Stats to know if it's a directory
!maxDepthReached || // we need the fs.Stats to know if it's a directory
options.stats || // the user wants fs.Stats objects returned
options.filterFn || // we need to filter based on the fs.Stats
options.recurseFn || // we need fs.Stats for the recurse function
options.filterFn || // we need fs.Stats for the filter function
EventEmitter.listenerCount(stream, 'file') || // we need the fs.Stats to know if it's a file

@@ -173,3 +176,8 @@ EventEmitter.listenerCount(stream, 'directory') || // we need the fs.Stats to know if it's a directory

if (recurse && stats.isDirectory()) {
// Add the item's path to the fs.Stats object
// The base of this path, and its separators are determined by the options
// (i.e. options.basePath and options.sep)
stats.path = itemPath;
if (reader.shouldRecurse(stats, posixPath, maxDepthReached)) {
// Add this subdirectory to the queue

@@ -185,3 +193,2 @@ reader.queue.push({

// Determine whether this item matches the filter criteria
stats.path = itemPath;
if (reader.filter(stats, posixPath)) {

@@ -245,2 +252,49 @@ reader.pushOrBuffer({

/**
* Determines whether the given directory meets the user-specified recursion criteria.
* If the user didn't specify recursion criteria, then this function will default to true.
*
* @param {fs.Stats} stats - The directory's {@link fs.Stats} object
* @param {string} posixPath - The item's POSIX path (used for glob matching)
* @param {boolean} maxDepthReached - Whether we've already crawled the user-specified depth
* @returns {boolean}
*/
DirectoryReader.prototype.shouldRecurse = function shouldRecurse (stats, posixPath, maxDepthReached) {
var reader = this;
var options = reader.options;
if (maxDepthReached) {
// We've already crawled to the maximum depth. So no more recursion.
return false;
}
else if (!stats.isDirectory()) {
// It's not a directory. So don't try to crawl it.
return false;
}
else if (options.recurseGlob) {
// Glob patterns are always tested against the POSIX path, even on Windows
// https://github.com/isaacs/node-glob#windows
return options.recurseGlob.test(posixPath);
}
else if (options.recurseRegExp) {
// Regular expressions are tested against the normal path
// (based on the OS or options.sep)
return options.recurseRegExp.test(stats.path);
}
else if (options.recurseFn) {
// Run the user-specified recursion criteria (and handle any errors)
try {
return options.recurseFn.call(null, stats);
}
catch (error) {
reader.emit('error', error);
}
}
else {
// No recursion function was specified, and we're within the maximum depth.
// So crawl this directory.
return true;
}
};
/**
* Determines whether the given item meets the user-specified filter criteria.

@@ -247,0 +301,0 @@ * If the user didn't specify a filter, then this function will always return true.

@@ -16,6 +16,7 @@ 'use strict';

*
* @param {number|boolean} [options.deep]
* @param {number|boolean|function} [options.deep]
* The number of directories to recursively traverse. Any falsy value or negative number will
* default to zero, so only the top-level contents will be returned. Set to `true` or `Infinity`
* to traverse all subdirectories.
* to traverse all subdirectories. Or provide a function that accepts a {@link fs.Stats} object
* and returns a truthy value if the directory's contents should be crawled.
*

@@ -52,16 +53,34 @@ * @param {function|string|RegExp} [options.filter]

var depth = options.deep;
if (depth === null || depth === undefined || typeof depth === 'boolean') {
depth = depth ? Infinity : 0;
var recurseDepth, recurseFn, recurseRegExp, recurseGlob, deep = options.deep;
if (deep === null || deep === undefined) {
recurseDepth = 0;
}
else if (typeof depth === 'number') {
if (depth < 0 || isNaN(depth)) {
else if (typeof deep === 'boolean') {
recurseDepth = deep ? Infinity : 0;
}
else if (typeof deep === 'number') {
if (deep < 0 || isNaN(deep)) {
throw new Error('options.deep must be a positive number');
}
else if (Math.floor(depth) !== depth) {
else if (Math.floor(deep) !== deep) {
throw new Error('options.deep must be an integer');
}
else {
recurseDepth = deep;
}
}
else if (typeof deep === 'function') {
recurseDepth = Infinity;
recurseFn = deep;
}
else if (deep instanceof RegExp) {
recurseDepth = Infinity;
recurseRegExp = deep;
}
else if (typeof deep === 'string' && deep.length > 0) {
recurseDepth = Infinity;
recurseGlob = globToRegExp(deep, { extended: true, globstar: true });
}
else {
throw new TypeError('options.deep must be a boolean or number');
throw new TypeError('options.deep must be a boolean, number, function, regular expression, or glob pattern');
}

@@ -121,3 +140,6 @@

return {
depth: depth,
recurseDepth: recurseDepth,
recurseFn: recurseFn,
recurseRegExp: recurseRegExp,
recurseGlob: recurseGlob,
filterFn: filterFn,

@@ -124,0 +146,0 @@ filterRegExp: filterRegExp,

'use strict';
var once = require('./once');
module.exports = stat;

@@ -15,2 +17,5 @@

function stat (fs, path, callback) {
// Make sure the callback is only called once
callback = once(callback);
fs.lstat(path, function (err, lstats) {

@@ -23,3 +28,3 @@ if (err) {

// Try to resolve the symlink
fs.stat(path, function (err, stats) {
fs.stat(path, function (err, stats) { // eslint-disable-line no-shadow
if (err) {

@@ -26,0 +31,0 @@ // The symlink is broken, so return the stats for the link itself

@@ -14,5 +14,10 @@ 'use strict';

array.forEach(function (item) {
iterator(item, function () {});
iterator(item, function () {
// Note: No error-handling here because this is currently only ever called
// by DirectoryReader, which never passes an `error` parameter to the callback.
// Instead, DirectoryReader emits an "error" event if an error occurs.
});
});
done();
}
'use strict';
var fs = require('fs');
var once = require('../once');

@@ -13,2 +14,5 @@ /**

exports.readdir = function (dir, callback) {
// Make sure the callback is only called once
callback = once(callback);
try {

@@ -31,2 +35,5 @@ var items = fs.readdirSync(dir);

exports.stat = function (path, callback) {
// Make sure the callback is only called once
callback = once(callback);
try {

@@ -49,2 +56,5 @@ var stats = fs.statSync(path);

exports.lstat = function (path, callback) {
// Make sure the callback is only called once
callback = once(callback);
try {

@@ -51,0 +61,0 @@ var stats = fs.lstatSync(path);

{
"name": "readdir-enhanced",
"version": "1.4.5",
"version": "1.5.0",
"description": "fs.readdir with sync, async, and streaming APIs + filtering, recursion, absolute paths, etc.",

@@ -19,8 +19,15 @@ "keywords": [

},
"homepage": "https://github.com/bigstickcarpet/readdir-enhanced",
"repository": {
"type": "git",
"url": "https://github.com/bigstickcarpet/readdir-enhanced.git"
},
"license": "MIT",
"homepage": "https://github.com/bigstickcarpet/readdir-enhanced",
"main": "lib/index.js",
"files": [
"lib"
],
"scripts": {
"lint": "eslint lib test --fix",
"test": "mocha",
"test": "mocha && npm run lint",
"cover": "istanbul cover _mocha",

@@ -31,28 +38,21 @@ "upgrade": "npm-check -u",

},
"repository": {
"type": "git",
"url": "https://github.com/bigstickcarpet/readdir-enhanced.git"
},
"devDependencies": {
"chai": "^3.5.0",
"codacy-coverage": "^2.0.0",
"coveralls": "^2.11.14",
"codacy-coverage": "^2.0.1",
"coveralls": "^2.13.0",
"del": "^2.2.2",
"eslint": "^3.9.0",
"eslint-config-modular": "^1.0.1",
"eslint": "^3.19.0",
"eslint-config-modular": "^4.0.0",
"istanbul": "^0.4.5",
"mkdirp": "^0.5.1",
"mocha": "^3.1.2",
"mocha": "^3.2.0",
"npm-check": "^5.4.0",
"through2": "^2.0.1",
"version-bump-prompt": "^1.7.2"
"through2": "^2.0.3",
"version-bump-prompt": "^3.1.0"
},
"dependencies": {
"call-me-maybe": "^1.0.1",
"es6-promise": "^4.0.5",
"es6-promise": "^4.1.0",
"glob-to-regexp": "^0.3.0"
},
"files": [
"lib"
]
}
}

@@ -5,7 +5,8 @@ Enhanced `fs.readdir()`

[![Build Status](https://api.travis-ci.org/BigstickCarpet/readdir-enhanced.svg?branch=master)](https://travis-ci.org/BigstickCarpet/readdir-enhanced)
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/2a56yy1fmt7w77bm/branch/master?svg=true&failingText=Windows%20build%20failing&passingText=Windows%20build%20passing)](https://ci.appveyor.com/project/BigstickCarpet/readdir-enhanced/branch/master)
[![Dependencies](https://david-dm.org/BigstickCarpet/readdir-enhanced.svg)](https://david-dm.org/BigstickCarpet/readdir-enhanced)
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/bigstickcarpet/readdir-enhanced?svg=true&failingText=Windows%20build%20failing&passingText=Windows%20build%20passing)](https://ci.appveyor.com/project/BigstickCarpet/readdir-enhanced/branch/master)
[![Coverage Status](https://coveralls.io/repos/github/BigstickCarpet/readdir-enhanced/badge.svg?branch=master)](https://coveralls.io/github/BigstickCarpet/readdir-enhanced?branch=master)
[![Codacy Score](https://api.codacy.com/project/badge/Grade/178a817b6c864de7813fef457c0ed5ae)](https://www.codacy.com/public/jamesmessinger/readdir-enhanced)
[![Inline docs](http://inch-ci.org/github/BigstickCarpet/readdir-enhanced.svg?branch=master&style=shields)](http://inch-ci.org/github/BigstickCarpet/readdir-enhanced)
[![Dependencies](https://david-dm.org/BigstickCarpet/readdir-enhanced.svg)](https://david-dm.org/BigstickCarpet/readdir-enhanced)

@@ -28,7 +29,7 @@ [![npm](https://img.shields.io/npm/v/readdir-enhanced.svg?maxAge=43200)](https://www.npmjs.com/package/readdir-enhanced)

aliases: `readdir`, `readdir.async`, `readdir.readdirAsync`<br>
Reads the directory contents asynchronously and buffers all the results until all contents have been read. Supports callback or Promise syntax (see example below).
Reads the starting directory contents asynchronously and buffers all the results until all contents have been read. Supports callback or Promise syntax (see example below).
- **Streaming API**<br>
aliases: `readdir.stream`, `readdir.readdirStream`<br>
The streaming API reads the directory asynchronously and returns the results in real-time as they are read. The results can be [piped](https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options) to other Node.js streams, or you can listen for specific events via the [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter) interface. (see example below)
The streaming API reads the starting directory asynchronously and returns the results in real-time as they are read. The results can be [piped](https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options) to other Node.js streams, or you can listen for specific events via the [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter) interface. (see example below)

@@ -76,6 +77,8 @@ ```javascript

### Recursion - `options.deep`
By default, `readdir-enhanced` will only return the top-level contents of the directory. But you can enable the `deep` option to recursively traverse the subdirectories and return their contents as well.
By default, `readdir-enhanced` will only return the top-level contents of the starting directory. But you can set the `deep` option to recursively traverse the subdirectories and return their contents as well.
The `deep` option can be set to `true` to traverse the entire directory structure, or it can be set to a number to only traverse that many levels deep. For example, calling `readdir('my/directory', {deep: 2})` will return `subdir1/file.txt` and `subdir1/subdir2/file.txt`, but it _won't_ return `subdir1/subdir2/subdir3/file.txt`.
#### Crawl ALL subdirectories
The `deep` option can be set to `true` to traverse the entire directory structure.
```javascript

@@ -92,7 +95,67 @@ var readdir = require('readdir-enhanced');

// => subdir1/subdir2/subdir3/file.txt
// ...
});
```
#### Crawl to a specific depth
The `deep` option can be set to a number to only traverse that many levels deep. For example, calling `readdir('my/directory', {deep: 2})` will return `subdir1/file.txt` and `subdir1/subdir2/file.txt`, but it _won't_ return `subdir1/subdir2/subdir3/file.txt`.
```javascript
var readdir = require('readdir-enhanced');
readdir('my/directory', {deep: 2}, function(err, files) {
console.log(files);
// => subdir1
// => subdir1/file.txt
// => subdir1/subdir2
// => subdir1/subdir2/file.txt
// => subdir1/subdir2/subdir3
});
```
#### Crawl subdirectories by name
For simple use-cases, you can use a [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) or a [glob pattern](https://github.com/isaacs/node-glob#glob-primer) to crawl only the directories whose path matches the pattern. The path is relative to the starting directory by default, but you can customize this via [`options.basePath`](#basepath).
> **NOTE:** Glob patterns [_always_ use forward-slashes](https://github.com/isaacs/node-glob#windows), even on Windows. This _does not_ apply to regular expressions though. Regular expressions should use the appropraite path separator for the environment. Or, you can match both types of separators using `[\\/]`.
```javascript
var readdir = require('readdir-enhanced');
// Only crawl the "lib" and "bin" subdirectories
// (notice that the "node_modules" subdirectory does NOT get crawled)
readdir('my/directory', {deep: /lib|bin/}, function(err, files) {
console.log(files);
// => bin
// => bin/cli.js
// => lib
// => lib/index.js
// => node_modules
// => package.json
});
```
#### Custom recursion logic
For more advanced recursion, you can set the `deep` option to a function that accepts an [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object and returns a truthy value if the starting directory should be crawled.
> **NOTE:** The [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object that's passed to the function has an additional `path` property. The `path` is relative to the starting directory by default, but you can customize this via [`options.basePath`](#basepath).
```javascript
var readdir = require('readdir-enhanced');
// Crawl all subdirectories, except "node_modules"
function ignoreNodeModules (stats) {
return stats.path.indexOf('node_modules') === -1;
}
readdir('my/directory', {deep: ignoreNodeModules}, function(err, files) {
console.log(files);
// => bin
// => bin/cli.js
// => lib
// => lib/index.js
// => node_modules
// => package.json
});
```
<a id="filter"></a>

@@ -102,4 +165,4 @@ ### Filtering - `options.filter`

#### Filter by path
For simple use-cases, you can use a [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) or a [glob pattern](https://github.com/isaacs/node-glob#glob-primer) to filter items by their path. The path is relative to the directory, but you can customize this via [`options.basePath`](#basepath).
#### Filter by name
For simple use-cases, you can use a [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) or a [glob pattern](https://github.com/isaacs/node-glob#glob-primer) to filter items by their path. The path is relative to the starting directory by default, but you can customize this via [`options.basePath`](#basepath).

@@ -121,5 +184,6 @@ > **NOTE:** Glob patterns [_always_ use forward-slashes](https://github.com/isaacs/node-glob#windows), even on Windows. This _does not_ apply to regular expressions though. Regular expressions should use the appropraite path separator for the environment. Or, you can match both types of separators using `[\\/]`.

#### Custom filtering logic
For more advanced filtering, you can specify a filter function that accepts an [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object and returns a truthy value if the item should be included in the results.
#### Advanced filtering
For more advanced filtering, you can specify a filter function that accepts an [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object and should return a truthy value if the item should be included in the results. The [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object that is passed to the filter function has an additional `path` property. The `path` is relative to the directory by default, but you can customize this via [`options.basePath`](#basepath).
> **NOTE:** The [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object that's passed to the filter function has an additional `path` property. The `path` is relative to the starting directory by default, but you can customize this via [`options.basePath`](#basepath).

@@ -129,13 +193,13 @@ ```javascript

// Only return subdirectories containing an underscore
// Only return file names containing an underscore
function myFilter(stats) {
return stats.isDirectory() && stats.path.indexOf('_') >= 0;
return stats.isFile() && stats.path.indexOf('_') >= 0;
}
readdir('my/directory', {filter: myFilter}, function(err, subdirs) {
console.log(subdirs);
// => _tmp
// => bower_components
readdir('my/directory', {filter: myFilter}, function(err, files) {
console.log(files);
// => __myFile.txt
// => my_other_file.txt
// => img_1.jpg
// => node_modules
// ...
});

@@ -147,3 +211,3 @@ ```

### Base Path - `options.basePath`
By default all `readdir-enhanced` functions return paths that are relative to the directory. But you can use the `basePath` option to customize this. The `basePath` will be prepended to all of the returned paths. One common use-case for this is to set `basePath` to the absolute path of the directory, so that all of the returned paths will be absolute.
By default all `readdir-enhanced` functions return paths that are relative to the starting directory. But you can use the `basePath` option to customize this. The `basePath` will be prepended to all of the returned paths. One common use-case for this is to set `basePath` to the absolute path of the starting directory, so that all of the returned paths will be absolute.

@@ -161,3 +225,2 @@ ```javascript

// => /absolute/path/to/my/directory/subdir
// ...
});

@@ -171,3 +234,2 @@

// => my/directory/subdir
// ...
});

@@ -193,3 +255,2 @@ ```

// => subdir1\subdir2\subdir3\file.txt
// ...
});

@@ -201,5 +262,5 @@ ```

------------------------
All of the `readdir-enhanced` functions listed above return an array of strings (paths). But in some situations, the path isn't enough information. So, `readdir-enhanced` provides alternative versions of each function, which return an array of [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) objects instead of strings. The `fs.Stats` object contains all sorts of useful information, such the size, the creation date/time, and helper methods such as `isFile()`, `isDirectory()`, `isSymbolicLink()`, etc.
All of the `readdir-enhanced` functions listed above return an array of strings (paths). But in some situations, the path isn't enough information. So, `readdir-enhanced` provides alternative versions of each function, which return an array of [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) objects instead of strings. The `fs.Stats` object contains all sorts of useful information, such as the size, the creation date/time, and helper methods such as `isFile()`, `isDirectory()`, `isSymbolicLink()`, etc.
> **NOTE:** The [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) objects that are returned also have an additional `path` property. The `path` is relative to the directory by default, but you can customize this via [`options.basePath`](#basepath).
> **NOTE:** The [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) objects that are returned also have an additional `path` property. The `path` is relative to the starting directory by default, but you can customize this via [`options.basePath`](#basepath).

@@ -250,1 +311,26 @@ To get `fs.Stats` objects instead of strings, just call add the word "Stat" to the function name. As with the normal functions, each one is aliased, so you can use whichever naming style you prefer.

```
Contributing
--------------------------
I welcome any contributions, enhancements, and bug-fixes. [File an issue](https://github.com/BigstickCarpet/readdir-enhanced/issues) on GitHub and [submit a pull request](https://github.com/BigstickCarpet/readdir-enhanced/pulls).
#### Building
To build the project locally on your computer:
1. __Clone this repo__<br>
`git clone https://github.com/bigstickcarpet/readdir-enhanced.git`
2. __Install dependencies__<br>
`npm install`
3. __Run the tests__<br>
`npm test`
License
--------------------------
`readdir-enhanced` is 100% free and open-source, under the [MIT license](LICENSE). Use it however you want.
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