Spaces:
Sleeping
Sleeping
File size: 5,712 Bytes
4cadbaf |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
'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,
};
}
|