diff options
Diffstat (limited to 'node_modules/@mrmlnc')
16 files changed, 1571 insertions, 0 deletions
diff --git a/node_modules/@mrmlnc/readdir-enhanced/CHANGELOG.md b/node_modules/@mrmlnc/readdir-enhanced/CHANGELOG.md new file mode 100644 index 0000000..6391ab6 --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/CHANGELOG.md @@ -0,0 +1,49 @@ +# Change Log +All notable changes will be documented in this file. +`readdir-enhanced` adheres to [Semantic Versioning](http://semver.org/). + + +## [v2.2.0](https://github.com/BigstickCarpet/readdir-enhanced/tree/v2.2.0) (2018-01-09) + +- Refactored the codebase to use ES6 syntax (Node v4.x compatible) + +- You can now provide [your own implementation](https://github.com/BigstickCarpet/readdir-enhanced#custom-fs-methods) for the [filesystem module](https://nodejs.org/api/fs.html) that's used by `readdir-enhanced`. Just set the `fs` option to your implementation. Thanks to [@mrmlnc](https://github.com/mrmlnc) for the idea and [the PR](https://github.com/BigstickCarpet/readdir-enhanced/pull/10)! + +- [Better error handling](https://github.com/BigstickCarpet/readdir-enhanced/commit/0d330b68524bafbdeae11566a3e8af1bc3f184bf), especially around user-specified logic, such as `options.deep`, `options.filter`, and `options.fs` + +[Full Changelog](https://github.com/BigstickCarpet/readdir-enhanced/compare/v2.1.0...v2.2.0) + + +## [v2.1.0](https://github.com/BigstickCarpet/readdir-enhanced/tree/v2.1.0) (2017-12-01) + +- The `fs.Stats` objects now include a `depth` property, which indicates the number of subdirectories beneath the base path. Thanks to [@mrmlnc](https://github.com/mrmlnc) for [the PR](https://github.com/BigstickCarpet/readdir-enhanced/pull/8)! + +[Full Changelog](https://github.com/BigstickCarpet/readdir-enhanced/compare/v2.0.0...v2.1.0) + + +## [v2.0.0](https://github.com/BigstickCarpet/readdir-enhanced/tree/v2.0.0) (2017-11-15) + +- Dropped support for Node v0.x, which is no longer actively maintained. Please upgrade to Node 4 or newer. + +[Full Changelog](https://github.com/BigstickCarpet/readdir-enhanced/compare/v1.5.0...v2.0.0) + + +## [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) + +The [`filter` option](README.md#filter) can now be set to a regular expression or a glob pattern string, which simplifies filtering based on file names. Of course, you can still set the `filter` option to a function if you need to perform more advanced filtering based on the [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) of each file. + +[Full Changelog](https://github.com/BigstickCarpet/readdir-enhanced/compare/v1.3.4...v1.4.0) + + +## [v1.3.4](https://github.com/BigstickCarpet/readdir-enhanced/tree/v1.3.4) (2016-08-26) + +As of this release, `readdir-enhanced` is fully tested on all major Node versions (0.x, 4.x, 5.x, 6.x) on [linux](https://travis-ci.org/BigstickCarpet/readdir-enhanced) and [Windows](https://ci.appveyor.com/project/BigstickCarpet/readdir-enhanced/branch/master), with [nearly 100% code coverage](https://coveralls.io/github/BigstickCarpet/readdir-enhanced?branch=master). I do all of my local development and testing on MacOS, so that's covered too. + +[Full Changelog](https://github.com/BigstickCarpet/readdir-enhanced/compare/v1.0.1...v1.3.4) diff --git a/node_modules/@mrmlnc/readdir-enhanced/LICENSE b/node_modules/@mrmlnc/readdir-enhanced/LICENSE new file mode 100644 index 0000000..9ff003f --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/LICENSE @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) 2016 James Messinger + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +.
\ No newline at end of file diff --git a/node_modules/@mrmlnc/readdir-enhanced/README.md b/node_modules/@mrmlnc/readdir-enhanced/README.md new file mode 100644 index 0000000..bcf9b26 --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/README.md @@ -0,0 +1,347 @@ +Enhanced `fs.readdir()` +======================= + +> :warning: This is «fork» for original `readdir-enhanced` package but with some monkey fixes. + +[![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/github/bigstickcarpet/readdir-enhanced?svg=true&branch=master&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) + +[![npm](https://img.shields.io/npm/v/readdir-enhanced.svg?maxAge=43200)](https://www.npmjs.com/package/readdir-enhanced) +[![License](https://img.shields.io/npm/l/readdir-enhanced.svg?maxAge=2592000)](LICENSE) + +`readdir-enhanced` is a [backward-compatible](#backward-compatible) drop-in replacement for [`fs.readdir()`](https://nodejs.org/api/fs.html#fs_fs_readdir_path_options_callback) and [`fs.readdirSync()`](https://nodejs.org/api/fs.html#fs_fs_readdirsync_path_options) with tons of extra features ([filtering](#filter), [recursion](#deep), [absolute paths](#basepath), [stats](#stats), and more) as well as additional APIs for Promises, Streams, and EventEmitters. + + +Pick Your API +----------------- +`readdir-enhanced` has multiple APIs, so you can pick whichever one you prefer. There are three main APIs: + +- **Synchronous API**<br> +aliases: `readdir.sync`, `readdir.readdirSync`<br> +Blocks the thread until all directory contents are read, and then returns all the results. + +- **Async API**<br> +aliases: `readdir`, `readdir.async`, `readdir.readdirAsync`<br> +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 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) + +```javascript +var readdir = require('readdir-enhanced'); +var through2 = require('through2'); + +// Synchronous API +var files = readdir.sync('my/directory'); + +// Callback API +readdir.async('my/directory', function(err, files) { ... }); + +// Promises API +readdir.async('my/directory') + .then(function(files) { ... }) + .catch(function(err) { ... }); + +// EventEmitter API +readdir.stream('my/directory') + .on('data', function(path) { ... }) + .on('file', function(path) { ... }) + .on('directory', function(path) { ... }) + .on('symlink', function(path) { ... }) + .on('error', function(err) { ... }); + +// Streaming API +var stream = readdir.stream('my/directory') + .pipe(through2.obj(function(data, enc, next) { + console.log(data); + this.push(data); + next(); + }); +``` + + +<a id="options"></a> +Enhanced Features +----------------- +`readdir-enhanced` adds several features to the built-in `fs.readdir()` function. All of the enhanced features are opt-in, which makes `readdir-enhanced` [fully backward compatible by default](#backward-compatible). You can enable any of the features by passing-in an `options` argument as the second parameter. + + +<a id="deep"></a> +### Recursion +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. + +#### Crawl ALL subdirectories + +The `deep` option can be set to `true` to traverse the entire directory structure. + +```javascript +var readdir = require('readdir-enhanced'); + +readdir('my/directory', {deep: true}, function(err, files) { + console.log(files); + // => subdir1 + // => subdir1/file.txt + // => subdir1/subdir2 + // => subdir1/subdir2/file.txt + // => subdir1/subdir2/subdir3 + // => 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 additional `path` and `depth` properties. The `path` is relative to the starting directory by default, but you can customize this via [`options.basePath`](#basepath). The `depth` is the number of subdirectories beneath the base path (see [`options.deep`](#deep)). + +```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> +### Filtering +The `filter` option lets you limit the results based on any criteria you want. + +#### 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). + +> **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'); + +// Find all .txt files +readdir('my/directory', {filter: '*.txt'}); + +// Find all package.json files +readdir('my/directory', {filter: '**/package.json', deep: true}); + +// Find everything with at least one number in the name +readdir('my/directory', {filter: /\d+/}); +``` + +#### 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. + +> **NOTE:** The [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object that's passed to the filter function has additional `path` and `depth` properties. The `path` is relative to the starting directory by default, but you can customize this via [`options.basePath`](#basepath). The `depth` is the number of subdirectories beneath the base path (see [`options.deep`](#deep)). + +```javascript +var readdir = require('readdir-enhanced'); + +// Only return file names containing an underscore +function myFilter(stats) { + return stats.isFile() && stats.path.indexOf('_') >= 0; +} + +readdir('my/directory', {filter: myFilter}, function(err, files) { + console.log(files); + // => __myFile.txt + // => my_other_file.txt + // => img_1.jpg + // => node_modules +}); +``` + + +<a id="basepath"></a> +### Base Path +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. + +```javascript +var readdir = require('readdir-enhanced'); +var path = require('path'); + +// Get absolute paths +var absPath = path.resolve('my/dir'); +readdir('my/directory', {basePath: absPath}, function(err, files) { + console.log(files); + // => /absolute/path/to/my/directory/file1.txt + // => /absolute/path/to/my/directory/file2.txt + // => /absolute/path/to/my/directory/subdir +}); + +// Get paths relative to the working directory +readdir('my/directory', {basePath: 'my/directory'}, function(err, files) { + console.log(files); + // => my/directory/file1.txt + // => my/directory/file2.txt + // => my/directory/subdir +}); +``` + + +<a id="sep"></a> +### Path Separator +By default, `readdir-enhanced` uses the correct path separator for your OS (`\` on Windows, `/` on Linux & MacOS). But you can set the `sep` option to any separator character(s) that you want to use instead. This is usually used to ensure consistent path separators across different OSes. + +```javascript +var readdir = require('readdir-enhanced'); + +// Always use Windows path separators +readdir('my/directory', {sep: '\\', deep: true}, function(err, files) { + console.log(files); + // => subdir1 + // => subdir1\file.txt + // => subdir1\subdir2 + // => subdir1\subdir2\file.txt + // => subdir1\subdir2\subdir3 + // => subdir1\subdir2\subdir3\file.txt +}); +``` + +<a id="fs"></a> +### Custom FS methods +By default, `readdir-enhanced` uses the default [Node.js FileSystem module](https://nodejs.org/api/fs.html) for methods like `fs.stat`, `fs.readdir` and `fs.lstat`. But in some situations, you can want to use your own FS methods (FTP, SSH, remote drive and etc). So you can provide your own implementation of FS methods by setting `options.fs` or specific methods, such as `options.fs.stat`. + +```javascript +var readdir = require('readdir-enhanced'); + +function myCustomReaddirMethod(dir, callback) { + callback(null, ['__myFile.txt']); +} + +var options = { + fs: { + readdir: myCustomReaddirMethod + } +}; + +readdir('my/directory', options, function(err, files) { + console.log(files); + // => __myFile.txt +}); +``` + +<a id="stats"></a> +Get `fs.Stats` objects instead of strings +------------------------ +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 additional `path` and `depth` properties. The `path` is relative to the starting directory by default, but you can customize this via [`options.basePath`](#basepath). The `depth` is the number of subdirectories beneath the base path (see [`options.deep`](#deep)). + +To get `fs.Stats` objects instead of strings, just add the word "Stat" to the function name. As with the normal functions, each one is aliased (e.g. `readdir.async.stat` is the same as `readdir.readdirAsyncStat`), so you can use whichever naming style you prefer. + +```javascript +var readdir = require('readdir-enhanced'); + +// Synchronous API +var stats = readdir.sync.stat('my/directory'); +var stats = readdir.readdirSyncStat('my/directory'); + +// Async API +readdir.async.stat('my/directory', function(err, stats) { ... }); +readdir.readdirAsyncStat('my/directory', function(err, stats) { ... }); + +// Streaming API +readdir.stream.stat('my/directory') + .on('data', function(stat) { ... }) + .on('file', function(stat) { ... }) + .on('directory', function(stat) { ... }) + .on('symlink', function(stat) { ... }); + +readdir.readdirStreamStat('my/directory') + .on('data', function(stat) { ... }) + .on('file', function(stat) { ... }) + .on('directory', function(stat) { ... }) + .on('symlink', function(stat) { ... }); + +``` + +<a id="backward-compatible"></a> +Backward Compatible +-------------------- +`readdir-enhanced` is fully backward-compatible with Node.js' built-in `fs.readdir()` and `fs.readdirSync()` functions, so you can use it as a drop-in replacement in existing projects without affecting existing functionality, while still being able to use the enhanced features as needed. + +```javascript +var readdir = require('readdir-enhanced'); +var readdirSync = readdir.sync; + +// Use it just like Node's built-in fs.readdir function +readdir('my/directory', function(err, files) { ... }); + +// Use it just like Node's built-in fs.readdirSync function +var files = readdirSync('my/directory'); +``` + + + +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. + diff --git a/node_modules/@mrmlnc/readdir-enhanced/lib/async/for-each.js b/node_modules/@mrmlnc/readdir-enhanced/lib/async/for-each.js new file mode 100644 index 0000000..1ac9b2f --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/lib/async/for-each.js @@ -0,0 +1,29 @@ +'use strict'; + +module.exports = asyncForEach; + +/** + * Simultaneously processes all items in the given array. + * + * @param {array} array - The array to iterate over + * @param {function} iterator - The function to call for each item in the array + * @param {function} done - The function to call when all iterators have completed + */ +function asyncForEach (array, iterator, done) { + 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(); + return; + } + + // Simultaneously process all items in the array. + let pending = array.length; + array.forEach(item => { + iterator(item, () => { + if (--pending === 0) { + done(); + } + }); + }); +} diff --git a/node_modules/@mrmlnc/readdir-enhanced/lib/async/index.js b/node_modules/@mrmlnc/readdir-enhanced/lib/async/index.js new file mode 100644 index 0000000..677e0b6 --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/lib/async/index.js @@ -0,0 +1,48 @@ +'use strict'; + +module.exports = readdirAsync; + +const maybe = require('call-me-maybe'); +const DirectoryReader = require('../directory-reader'); + +let asyncFacade = { + fs: require('fs'), + forEach: require('./for-each'), + async: true +}; + +/** + * Returns the buffered output from an asynchronous {@link DirectoryReader}, + * via an error-first callback or a {@link Promise}. + * + * @param {string} dir + * @param {object} [options] + * @param {function} [callback] + * @param {object} internalOptions + */ +function readdirAsync (dir, options, callback, internalOptions) { + if (typeof options === 'function') { + callback = options; + options = undefined; + } + + return maybe(callback, new Promise(((resolve, reject) => { + let results = []; + + internalOptions.facade = asyncFacade; + + let reader = new DirectoryReader(dir, options, internalOptions); + let stream = reader.stream; + + stream.on('error', err => { + reject(err); + stream.pause(); + }); + stream.on('data', result => { + results.push(result); + }); + stream.on('end', () => { + resolve(results); + }); + }))); +} diff --git a/node_modules/@mrmlnc/readdir-enhanced/lib/call.js b/node_modules/@mrmlnc/readdir-enhanced/lib/call.js new file mode 100644 index 0000000..07e3d84 --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/lib/call.js @@ -0,0 +1,54 @@ +'use strict'; + +let call = module.exports = { + safe: safeCall, + once: callOnce, +}; + +/** + * Calls a function with the given arguments, and ensures that the error-first callback is _always_ + * invoked exactly once, even if the function throws an error. + * + * @param {function} fn - The function to invoke + * @param {...*} args - The arguments to pass to the function. The final argument must be a callback function. + */ +function safeCall (fn, args) { + // Get the function arguments as an array + args = Array.prototype.slice.call(arguments, 1); + + // Replace the callback function with a wrapper that ensures it will only be called once + let callback = call.once(args.pop()); + args.push(callback); + + try { + fn.apply(null, args); + } + catch (err) { + callback(err); + } +} + +/** + * Returns a wrapper function that ensures the given callback function is only called once. + * Subsequent calls are ignored, unless the first argument is an Error, in which case the + * error is thrown. + * + * @param {function} fn - The function that should only be called once + * @returns {function} + */ +function callOnce (fn) { + let fulfilled = false; + + return function onceWrapper (err) { + if (!fulfilled) { + fulfilled = true; + return fn.apply(this, arguments); + } + else if (err) { + // The callback has already been called, but now an error has occurred + // (most likely inside the callback function). So re-throw the error, + // so it gets handled further up the call stack + throw err; + } + }; +} diff --git a/node_modules/@mrmlnc/readdir-enhanced/lib/directory-reader.js b/node_modules/@mrmlnc/readdir-enhanced/lib/directory-reader.js new file mode 100644 index 0000000..569d793 --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/lib/directory-reader.js @@ -0,0 +1,380 @@ +'use strict'; + +const Readable = require('stream').Readable; +const EventEmitter = require('events').EventEmitter; +const path = require('path'); +const normalizeOptions = require('./normalize-options'); +const stat = require('./stat'); +const call = require('./call'); + +/** + * Asynchronously reads the contents of a directory and streams the results + * via a {@link stream.Readable}. + */ +class DirectoryReader { + /** + * @param {string} dir - The absolute or relative directory path to read + * @param {object} [options] - User-specified options, if any (see {@link normalizeOptions}) + * @param {object} internalOptions - Internal options that aren't part of the public API + * @class + */ + constructor (dir, options, internalOptions) { + this.options = options = normalizeOptions(options, internalOptions); + + // Indicates whether we should keep reading + // This is set false if stream.Readable.push() returns false. + this.shouldRead = true; + + // The directories to read + // (initialized with the top-level directory) + this.queue = [{ + path: dir, + basePath: options.basePath, + posixBasePath: options.posixBasePath, + depth: 0 + }]; + + // The number of directories that are currently being processed + this.pending = 0; + + // The data that has been read, but not yet emitted + this.buffer = []; + + this.stream = new Readable({ objectMode: true }); + this.stream._read = () => { + // Start (or resume) reading + this.shouldRead = true; + + // If we have data in the buffer, then send the next chunk + if (this.buffer.length > 0) { + this.pushFromBuffer(); + } + + // If we have directories queued, then start processing the next one + if (this.queue.length > 0) { + if (this.options.facade.sync) { + while (this.queue.length > 0) { + this.readNextDirectory(); + } + } + else { + this.readNextDirectory(); + } + } + + this.checkForEOF(); + }; + } + + /** + * Reads the next directory in the queue + */ + readNextDirectory () { + let facade = this.options.facade; + let dir = this.queue.shift(); + this.pending++; + + // Read the directory listing + call.safe(facade.fs.readdir, dir.path, (err, items) => { + if (err) { + // fs.readdir threw an error + this.emit('error', err); + return this.finishedReadingDirectory(); + } + + try { + // Process each item in the directory (simultaneously, if async) + facade.forEach( + items, + this.processItem.bind(this, dir), + this.finishedReadingDirectory.bind(this, dir) + ); + } + catch (err2) { + // facade.forEach threw an error + // (probably because fs.readdir returned an invalid result) + this.emit('error', err2); + this.finishedReadingDirectory(); + } + }); + } + + /** + * This method is called after all items in a directory have been processed. + * + * NOTE: This does not necessarily mean that the reader is finished, since there may still + * be other directories queued or pending. + */ + finishedReadingDirectory () { + this.pending--; + + if (this.shouldRead) { + // If we have directories queued, then start processing the next one + if (this.queue.length > 0 && this.options.facade.async) { + this.readNextDirectory(); + } + + this.checkForEOF(); + } + } + + /** + * Determines whether the reader has finished processing all items in all directories. + * If so, then the "end" event is fired (via {@Readable#push}) + */ + checkForEOF () { + if (this.buffer.length === 0 && // The stuff we've already read + this.pending === 0 && // The stuff we're currently reading + this.queue.length === 0) { // The stuff we haven't read yet + // There's no more stuff! + this.stream.push(null); + } + } + + /** + * Processes a single item in a directory. + * + * If the item is a directory, and `option.deep` is enabled, then the item will be added + * to the directory queue. + * + * If the item meets the filter criteria, then it will be emitted to the reader's stream. + * + * @param {object} dir - A directory object from the queue + * @param {string} item - The name of the item (name only, no path) + * @param {function} done - A callback function that is called after the item has been processed + */ + processItem (dir, item, done) { + let stream = this.stream; + let options = this.options; + + let itemPath = dir.basePath + item; + let posixPath = dir.posixBasePath + item; + let fullPath = path.join(dir.path, item); + + // 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 + let maxDepthReached = dir.depth >= options.recurseDepth; + + // Do we need to call `fs.stat`? + let needStats = + !maxDepthReached || // we need the fs.Stats to know if it's a directory + options.stats || // the user wants fs.Stats objects returned + 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 + EventEmitter.listenerCount(stream, 'directory') || // we need the fs.Stats to know if it's a directory + EventEmitter.listenerCount(stream, 'symlink'); // we need the fs.Stats to know if it's a symlink + + // If we don't need stats, then exit early + if (!needStats) { + if (this.filter(itemPath, posixPath)) { + this.pushOrBuffer({ data: itemPath }); + } + return done(); + } + + // Get the fs.Stats object for this path + stat(options.facade.fs, fullPath, (err, stats) => { + if (err) { + // fs.stat threw an error + this.emit('error', err); + return done(); + } + + try { + // 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; + + // Add depth of the path to the fs.Stats object for use this in the filter function + stats.depth = dir.depth; + + if (this.shouldRecurse(stats, posixPath, maxDepthReached)) { + // Add this subdirectory to the queue + this.queue.push({ + path: fullPath, + basePath: itemPath + options.sep, + posixBasePath: posixPath + '/', + depth: dir.depth + 1, + }); + } + + // Determine whether this item matches the filter criteria + if (this.filter(stats, posixPath)) { + this.pushOrBuffer({ + data: options.stats ? stats : itemPath, + file: stats.isFile(), + directory: stats.isDirectory(), + symlink: stats.isSymbolicLink(), + }); + } + + done(); + } + catch (err2) { + // An error occurred while processing the item + // (probably during a user-specified function, such as options.deep, options.filter, etc.) + this.emit('error', err2); + done(); + } + }); + } + + /** + * Pushes the given chunk of data to the stream, or adds it to the buffer, + * depending on the state of the stream. + * + * @param {object} chunk + */ + pushOrBuffer (chunk) { + // Add the chunk to the buffer + this.buffer.push(chunk); + + // If we're still reading, then immediately emit the next chunk in the buffer + // (which may or may not be the chunk that we just added) + if (this.shouldRead) { + this.pushFromBuffer(); + } + } + + /** + * Immediately pushes the next chunk in the buffer to the reader's stream. + * The "data" event will always be fired (via {@link Readable#push}). + * In addition, the "file", "directory", and/or "symlink" events may be fired, + * depending on the type of properties of the chunk. + */ + pushFromBuffer () { + let stream = this.stream; + let chunk = this.buffer.shift(); + + // Stream the data + try { + this.shouldRead = stream.push(chunk.data); + } + catch (err) { + this.emit('error', err); + } + + // Also emit specific events, based on the type of chunk + chunk.file && this.emit('file', chunk.data); + chunk.symlink && this.emit('symlink', chunk.data); + chunk.directory && this.emit('directory', chunk.data); + } + + /** + * 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} + */ + shouldRecurse (stats, posixPath, maxDepthReached) { + let options = this.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) { + try { + // Run the user-specified recursion criteria + return options.recurseFn.call(null, stats); + } + catch (err) { + // An error occurred in the user's code. + // In Sync and Async modes, this will return an error. + // In Streaming mode, we emit an "error" event, but continue processing + this.emit('error', err); + } + } + 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. + * If the user didn't specify a filter, then this function will always return true. + * + * @param {string|fs.Stats} value - Either the item's path, or the item's {@link fs.Stats} object + * @param {string} posixPath - The item's POSIX path (used for glob matching) + * @returns {boolean} + */ + filter (value, posixPath) { + let options = this.options; + + if (options.filterGlob) { + // Glob patterns are always tested against the POSIX path, even on Windows + // https://github.com/isaacs/node-glob#windows + return options.filterGlob.test(posixPath); + } + else if (options.filterRegExp) { + // Regular expressions are tested against the normal path + // (based on the OS or options.sep) + return options.filterRegExp.test(value.path || value); + } + else if (options.filterFn) { + try { + // Run the user-specified filter function + return options.filterFn.call(null, value); + } + catch (err) { + // An error occurred in the user's code. + // In Sync and Async modes, this will return an error. + // In Streaming mode, we emit an "error" event, but continue processing + this.emit('error', err); + } + } + else { + // No filter was specified, so match everything + return true; + } + } + + /** + * Emits an event. If one of the event listeners throws an error, + * then an "error" event is emitted. + * + * @param {string} eventName + * @param {*} data + */ + emit (eventName, data) { + let stream = this.stream; + + try { + stream.emit(eventName, data); + } + catch (err) { + if (eventName === 'error') { + // Don't recursively emit "error" events. + // If the first one fails, then just throw + throw err; + } + else { + stream.emit('error', err); + } + } + } +} + +module.exports = DirectoryReader; diff --git a/node_modules/@mrmlnc/readdir-enhanced/lib/index.js b/node_modules/@mrmlnc/readdir-enhanced/lib/index.js new file mode 100644 index 0000000..f77d2c6 --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/lib/index.js @@ -0,0 +1,85 @@ +'use strict'; + +const readdirSync = require('./sync'); +const readdirAsync = require('./async'); +const readdirStream = require('./stream'); + +module.exports = exports = readdirAsyncPath; +exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; +exports.readdirAsyncStat = exports.async.stat = readdirAsyncStat; +exports.readdirStream = exports.stream = readdirStreamPath; +exports.readdirStreamStat = exports.stream.stat = readdirStreamStat; +exports.readdirSync = exports.sync = readdirSyncPath; +exports.readdirSyncStat = exports.sync.stat = readdirSyncStat; + +/** + * Synchronous readdir that returns an array of string paths. + * + * @param {string} dir + * @param {object} [options] + * @returns {string[]} + */ +function readdirSyncPath (dir, options) { + return readdirSync(dir, options, {}); +} + +/** + * Synchronous readdir that returns results as an array of {@link fs.Stats} objects + * + * @param {string} dir + * @param {object} [options] + * @returns {fs.Stats[]} + */ +function readdirSyncStat (dir, options) { + return readdirSync(dir, options, { stats: true }); +} + +/** + * Aynchronous readdir (accepts an error-first callback or returns a {@link Promise}). + * Results are an array of path strings. + * + * @param {string} dir + * @param {object} [options] + * @param {function} [callback] + * @returns {Promise<string[]>} + */ +function readdirAsyncPath (dir, options, callback) { + return readdirAsync(dir, options, callback, {}); +} + +/** + * Aynchronous readdir (accepts an error-first callback or returns a {@link Promise}). + * Results are an array of {@link fs.Stats} objects. + * + * @param {string} dir + * @param {object} [options] + * @param {function} [callback] + * @returns {Promise<fs.Stats[]>} + */ +function readdirAsyncStat (dir, options, callback) { + return readdirAsync(dir, options, callback, { stats: true }); +} + +/** + * Aynchronous readdir that returns a {@link stream.Readable} (which is also an {@link EventEmitter}). + * All stream data events ("data", "file", "directory", "symlink") are passed a path string. + * + * @param {string} dir + * @param {object} [options] + * @returns {stream.Readable} + */ +function readdirStreamPath (dir, options) { + return readdirStream(dir, options, {}); +} + +/** + * Aynchronous readdir that returns a {@link stream.Readable} (which is also an {@link EventEmitter}) + * All stream data events ("data", "file", "directory", "symlink") are passed an {@link fs.Stats} object. + * + * @param {string} dir + * @param {object} [options] + * @returns {stream.Readable} + */ +function readdirStreamStat (dir, options) { + return readdirStream(dir, options, { stats: true }); +} diff --git a/node_modules/@mrmlnc/readdir-enhanced/lib/normalize-options.js b/node_modules/@mrmlnc/readdir-enhanced/lib/normalize-options.js new file mode 100644 index 0000000..66f1158 --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/lib/normalize-options.js @@ -0,0 +1,177 @@ +'use strict'; + +const path = require('path'); +const globToRegExp = require('glob-to-regexp'); + +module.exports = normalizeOptions; + +let isWindows = /^win/.test(process.platform); + +/** + * @typedef {Object} FSFacade + * @property {fs.readdir} readdir + * @property {fs.stat} stat + * @property {fs.lstat} lstat + */ + +/** + * Validates and normalizes the options argument + * + * @param {object} [options] - User-specified options, if any + * @param {object} internalOptions - Internal options that aren't part of the public API + * + * @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. Or provide a function that accepts a {@link fs.Stats} object + * and returns a truthy value if the directory's contents should be crawled. + * + * @param {function|string|RegExp} [options.filter] + * A function that accepts a {@link fs.Stats} object and returns a truthy value if the data should + * be returned. Or a RegExp or glob string pattern, to filter by file name. + * + * @param {string} [options.sep] + * The path separator to use. By default, the OS-specific separator will be used, but this can be + * set to a specific value to ensure consistency across platforms. + * + * @param {string} [options.basePath] + * The base path to prepend to each result. If empty, then all results will be relative to `dir`. + * + * @param {FSFacade} [options.fs] + * Synchronous or asynchronous facades for Node.js File System module + * + * @param {object} [internalOptions.facade] + * Synchronous or asynchronous facades for various methods, including for the Node.js File System module + * + * @param {boolean} [internalOptions.emit] + * Indicates whether the reader should emit "file", "directory", and "symlink" events + * + * @param {boolean} [internalOptions.stats] + * Indicates whether the reader should emit {@link fs.Stats} objects instead of path strings + * + * @returns {object} + */ +function normalizeOptions (options, internalOptions) { + if (options === null || options === undefined) { + options = {}; + } + else if (typeof options !== 'object') { + throw new TypeError('options must be an object'); + } + + let recurseDepth, recurseFn, recurseRegExp, recurseGlob, deep = options.deep; + if (deep === null || deep === undefined) { + recurseDepth = 0; + } + 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(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, number, function, regular expression, or glob pattern'); + } + + let filterFn, filterRegExp, filterGlob, filter = options.filter; + if (filter !== null && filter !== undefined) { + if (typeof filter === 'function') { + filterFn = filter; + } + else if (filter instanceof RegExp) { + filterRegExp = filter; + } + else if (typeof filter === 'string' && filter.length > 0) { + filterGlob = globToRegExp(filter, { extended: true, globstar: true }); + } + else { + throw new TypeError('options.filter must be a function, regular expression, or glob pattern'); + } + } + + let sep = options.sep; + if (sep === null || sep === undefined) { + sep = path.sep; + } + else if (typeof sep !== 'string') { + throw new TypeError('options.sep must be a string'); + } + + let basePath = options.basePath; + if (basePath === null || basePath === undefined) { + basePath = ''; + } + else if (typeof basePath === 'string') { + // Append a path separator to the basePath, if necessary + if (basePath && basePath.substr(-1) !== sep) { + basePath += sep; + } + } + else { + throw new TypeError('options.basePath must be a string'); + } + + // Convert the basePath to POSIX (forward slashes) + // so that glob pattern matching works consistently, even on Windows + let posixBasePath = basePath; + if (posixBasePath && sep !== '/') { + posixBasePath = posixBasePath.replace(new RegExp('\\' + sep, 'g'), '/'); + + /* istanbul ignore if */ + if (isWindows) { + // Convert Windows root paths (C:\) and UNCs (\\) to POSIX root paths + posixBasePath = posixBasePath.replace(/^([a-zA-Z]\:\/|\/\/)/, '/'); + } + } + + // Determine which facade methods to use + let facade; + if (options.fs === null || options.fs === undefined) { + // The user didn't provide their own facades, so use our internal ones + facade = internalOptions.facade; + } + else if (typeof options.fs === 'object') { + // Merge the internal facade methods with the user-provided `fs` facades + facade = Object.assign({}, internalOptions.facade); + facade.fs = Object.assign({}, internalOptions.facade.fs, options.fs); + } + else { + throw new TypeError('options.fs must be an object'); + } + + return { + recurseDepth, + recurseFn, + recurseRegExp, + recurseGlob, + filterFn, + filterRegExp, + filterGlob, + sep, + basePath, + posixBasePath, + facade, + emit: !!internalOptions.emit, + stats: !!internalOptions.stats, + }; +} diff --git a/node_modules/@mrmlnc/readdir-enhanced/lib/stat.js b/node_modules/@mrmlnc/readdir-enhanced/lib/stat.js new file mode 100644 index 0000000..e338693 --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/lib/stat.js @@ -0,0 +1,74 @@ +'use strict'; + +const call = require('./call'); + +module.exports = stat; + +/** + * Retrieves the {@link fs.Stats} for the given path. If the path is a symbolic link, + * then the Stats of the symlink's target are returned instead. If the symlink is broken, + * then the Stats of the symlink itself are returned. + * + * @param {object} fs - Synchronous or Asynchronouse facade for the "fs" module + * @param {string} path - The path to return stats for + * @param {function} callback + */ +function stat (fs, path, callback) { + let isSymLink = false; + + call.safe(fs.lstat, path, (err, lstats) => { + if (err) { + // fs.lstat threw an eror + return callback(err); + } + + try { + isSymLink = lstats.isSymbolicLink(); + } + catch (err2) { + // lstats.isSymbolicLink() threw an error + // (probably because fs.lstat returned an invalid result) + return callback(err2); + } + + if (isSymLink) { + // Try to resolve the symlink + symlinkStat(fs, path, lstats, callback); + } + else { + // It's not a symlink, so return the stats as-is + callback(null, lstats); + } + }); +} + +/** + * Retrieves the {@link fs.Stats} for the target of the given symlink. + * If the symlink is broken, then the Stats of the symlink itself are returned. + * + * @param {object} fs - Synchronous or Asynchronouse facade for the "fs" module + * @param {string} path - The path of the symlink to return stats for + * @param {object} lstats - The stats of the symlink + * @param {function} callback + */ +function symlinkStat (fs, path, lstats, callback) { + call.safe(fs.stat, path, (err, stats) => { + if (err) { + // The symlink is broken, so return the stats for the link itself + return callback(null, lstats); + } + + try { + // Return the stats for the resolved symlink target, + // and override the `isSymbolicLink` method to indicate that it's a symlink + stats.isSymbolicLink = () => true; + } + catch (err2) { + // Setting stats.isSymbolicLink threw an error + // (probably because fs.stat returned an invalid result) + return callback(err2); + } + + callback(null, stats); + }); +} diff --git a/node_modules/@mrmlnc/readdir-enhanced/lib/stream/index.js b/node_modules/@mrmlnc/readdir-enhanced/lib/stream/index.js new file mode 100644 index 0000000..22a9609 --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/lib/stream/index.js @@ -0,0 +1,25 @@ +'use strict'; + +module.exports = readdirStream; + +const DirectoryReader = require('../directory-reader'); + +let streamFacade = { + fs: require('fs'), + forEach: require('../async/for-each'), + async: true +}; + +/** + * Returns the {@link stream.Readable} of an asynchronous {@link DirectoryReader}. + * + * @param {string} dir + * @param {object} [options] + * @param {object} internalOptions + */ +function readdirStream (dir, options, internalOptions) { + internalOptions.facade = streamFacade; + + let reader = new DirectoryReader(dir, options, internalOptions); + return reader.stream; +} diff --git a/node_modules/@mrmlnc/readdir-enhanced/lib/sync/for-each.js b/node_modules/@mrmlnc/readdir-enhanced/lib/sync/for-each.js new file mode 100644 index 0000000..c5ec088 --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/lib/sync/for-each.js @@ -0,0 +1,22 @@ +'use strict'; + +module.exports = syncForEach; + +/** + * A facade that allows {@link Array.forEach} to be called as though it were asynchronous. + * + * @param {array} array - The array to iterate over + * @param {function} iterator - The function to call for each item in the array + * @param {function} done - The function to call when all iterators have completed + */ +function syncForEach (array, iterator, done) { + array.forEach(item => { + iterator(item, () => { + // 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(); +} diff --git a/node_modules/@mrmlnc/readdir-enhanced/lib/sync/fs.js b/node_modules/@mrmlnc/readdir-enhanced/lib/sync/fs.js new file mode 100644 index 0000000..3aada77 --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/lib/sync/fs.js @@ -0,0 +1,64 @@ +'use strict'; + +const fs = require('fs'); +const call = require('../call'); + +/** + * A facade around {@link fs.readdirSync} that allows it to be called + * the same way as {@link fs.readdir}. + * + * @param {string} dir + * @param {function} callback + */ +exports.readdir = function (dir, callback) { + // Make sure the callback is only called once + callback = call.once(callback); + + try { + let items = fs.readdirSync(dir); + callback(null, items); + } + catch (err) { + callback(err); + } +}; + +/** + * A facade around {@link fs.statSync} that allows it to be called + * the same way as {@link fs.stat}. + * + * @param {string} path + * @param {function} callback + */ +exports.stat = function (path, callback) { + // Make sure the callback is only called once + callback = call.once(callback); + + try { + let stats = fs.statSync(path); + callback(null, stats); + } + catch (err) { + callback(err); + } +}; + +/** + * A facade around {@link fs.lstatSync} that allows it to be called + * the same way as {@link fs.lstat}. + * + * @param {string} path + * @param {function} callback + */ +exports.lstat = function (path, callback) { + // Make sure the callback is only called once + callback = call.once(callback); + + try { + let stats = fs.lstatSync(path); + callback(null, stats); + } + catch (err) { + callback(err); + } +}; diff --git a/node_modules/@mrmlnc/readdir-enhanced/lib/sync/index.js b/node_modules/@mrmlnc/readdir-enhanced/lib/sync/index.js new file mode 100644 index 0000000..60243a1 --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/lib/sync/index.js @@ -0,0 +1,34 @@ +'use strict'; + +module.exports = readdirSync; + +const DirectoryReader = require('../directory-reader'); + +let syncFacade = { + fs: require('./fs'), + forEach: require('./for-each'), + sync: true +}; + +/** + * Returns the buffered output from a synchronous {@link DirectoryReader}. + * + * @param {string} dir + * @param {object} [options] + * @param {object} internalOptions + */ +function readdirSync (dir, options, internalOptions) { + internalOptions.facade = syncFacade; + + let reader = new DirectoryReader(dir, options, internalOptions); + let stream = reader.stream; + + let results = []; + let data = stream.read(); + while (data !== null) { + results.push(data); + data = stream.read(); + } + + return results; +} diff --git a/node_modules/@mrmlnc/readdir-enhanced/package.json b/node_modules/@mrmlnc/readdir-enhanced/package.json new file mode 100644 index 0000000..7593dbd --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/package.json @@ -0,0 +1,93 @@ +{ + "_args": [ + [ + "@mrmlnc/readdir-enhanced@2.2.1", + "/home/dstaesse/git/website" + ] + ], + "_development": true, + "_from": "@mrmlnc/readdir-enhanced@2.2.1", + "_id": "@mrmlnc/readdir-enhanced@2.2.1", + "_inBundle": false, + "_integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "_location": "/@mrmlnc/readdir-enhanced", + "_phantomChildren": {}, + "_requested": { + "type": "version", + "registry": true, + "raw": "@mrmlnc/readdir-enhanced@2.2.1", + "name": "@mrmlnc/readdir-enhanced", + "escapedName": "@mrmlnc%2freaddir-enhanced", + "scope": "@mrmlnc", + "rawSpec": "2.2.1", + "saveSpec": null, + "fetchSpec": "2.2.1" + }, + "_requiredBy": [ + "/fast-glob" + ], + "_resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "_spec": "2.2.1", + "_where": "/home/dstaesse/git/website", + "author": { + "name": "James Messinger", + "url": "http://bigstickcarpet.com" + }, + "bugs": { + "url": "https://github.com/bigstickcarpet/readdir-enhanced/issues" + }, + "dependencies": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + }, + "description": "fs.readdir with sync, async, and streaming APIs + filtering, recursion, absolute paths, etc.", + "devDependencies": { + "chai": "^4.1.2", + "codacy-coverage": "^2.0.3", + "coveralls": "^3.0.0", + "del": "^3.0.0", + "eslint": "^4.15.0", + "eslint-config-modular": "^4.1.1", + "istanbul": "^0.4.5", + "mkdirp": "^0.5.1", + "mocha": "^4.1.0", + "npm-check": "^5.5.2", + "through2": "^2.0.3", + "version-bump-prompt": "^4.0.0" + }, + "engines": { + "node": ">=4" + }, + "files": [ + "lib", + "types.d.ts" + ], + "homepage": "https://github.com/bigstickcarpet/readdir-enhanced", + "keywords": [ + "fs", + "readdir", + "stream", + "event", + "recursive", + "deep", + "filter", + "absolute" + ], + "license": "MIT", + "main": "lib/index.js", + "name": "@mrmlnc/readdir-enhanced", + "repository": { + "type": "git", + "url": "git+https://github.com/bigstickcarpet/readdir-enhanced.git" + }, + "scripts": { + "bump": "bump --prompt --tag --push --all", + "cover": "istanbul cover _mocha", + "lint": "eslint lib test --fix", + "release": "npm run upgrade && npm test && npm run bump && npm publish", + "test": "mocha && npm run lint", + "upgrade": "npm-check -u" + }, + "typings": "types.d.ts", + "version": "2.2.1" +} diff --git a/node_modules/@mrmlnc/readdir-enhanced/types.d.ts b/node_modules/@mrmlnc/readdir-enhanced/types.d.ts new file mode 100644 index 0000000..2f4e622 --- /dev/null +++ b/node_modules/@mrmlnc/readdir-enhanced/types.d.ts @@ -0,0 +1,67 @@ +/// <reference types="node" /> + +import fs = require('fs'); + +declare namespace re { + interface Entry extends fs.Stats { + path: string; + depth: number; + } + + type FilterFunction = (stat: Entry) => boolean; + type Callback<T> = (err: NodeJS.ErrnoException, result: T) => void; + type CallbackString = Callback<string[]>; + type CallbackEntry = Callback<Entry[]>; + + interface FileSystem { + readdir?: (path: string, callback: Callback<string[]>) => void; + lstat?: (path: string, callback: Callback<fs.Stats>) => void; + stat?: (path: string, callback: Callback<fs.Stats>) => void; + } + + interface Options { + filter?: string | RegExp | FilterFunction; + deep?: boolean | number | RegExp | FilterFunction; + sep?: string; + basePath?: string; + fs?: FileSystem; + } + + function stat(root: string, options?: Options): Promise<Entry[]>; + function stat(root: string, callback: CallbackEntry): void; + function stat(root: string, options: Options, callback: CallbackEntry): void; + + function async(root: string, options?: Options): Promise<string[]>; + function async(root: string, callback: CallbackString): void; + function async(root: string, options: Options, callback: CallbackString): void; + + function readdirAsyncStat(root: string, options?: Options): Promise<Entry[]>; + function readdirAsyncStat(root: string, callback: CallbackEntry): void; + function readdirAsyncStat(root: string, options: Options, callback: CallbackEntry): void; + + namespace async { + function stat(root: string, options?: Options): Promise<Entry[]>; + function stat(root: string, callback: CallbackEntry): void; + function stat(root: string, options: Options, callback: CallbackEntry): void; + } + + function stream(root: string, options?: Options): NodeJS.ReadableStream; + function readdirStreamStat(root: string, options?: Options): NodeJS.ReadableStream; + + namespace stream { + function stat(root: string, options?: Options): NodeJS.ReadableStream; + } + + function sync(root: string, options?: Options): string[]; + function readdirSyncStat(root: string, options?: Options): Entry[]; + + namespace sync { + function stat(root: string, options?: Options): Entry[]; + } +} + +declare function re(root: string, options?: re.Options): Promise<string[]>; +declare function re(root: string, callback: re.CallbackString): void; +declare function re(root: string, options: re.Options, callback: re.CallbackString): void; + +export = re; |