Comparing version 3.6.0 to 4.0.0
101
index.d.ts
@@ -1,43 +0,68 @@ | ||
// TypeScript Version: 3.2 | ||
/// <reference types="node" lib="esnext" /> | ||
import * as fs from 'fs'; | ||
import type { Stats, Dirent } from 'fs'; | ||
import { Readable } from 'stream'; | ||
declare namespace readdir { | ||
interface EntryInfo { | ||
export type Path = string; | ||
export interface EntryInfo { | ||
path: string; | ||
fullPath: string; | ||
stats?: Stats; | ||
dirent?: Dirent; | ||
basename: string; | ||
stats?: fs.Stats; | ||
dirent?: fs.Dirent; | ||
} | ||
interface ReaddirpOptions { | ||
root?: string; | ||
fileFilter?: string | string[] | ((entry: EntryInfo) => boolean); | ||
directoryFilter?: string | string[] | ((entry: EntryInfo) => boolean); | ||
type?: 'files' | 'directories' | 'files_directories' | 'all'; | ||
lstat?: boolean; | ||
depth?: number; | ||
alwaysStat?: boolean; | ||
} | ||
interface ReaddirpStream extends Readable, AsyncIterable<EntryInfo> { | ||
read(): EntryInfo; | ||
[Symbol.asyncIterator](): AsyncIterableIterator<EntryInfo>; | ||
} | ||
function promise( | ||
root: string, | ||
options?: ReaddirpOptions | ||
): Promise<EntryInfo[]>; | ||
} | ||
declare function readdir( | ||
root: string, | ||
options?: readdir.ReaddirpOptions | ||
): readdir.ReaddirpStream; | ||
export = readdir; | ||
export type PathOrDirent = Dirent | Path; | ||
export type Tester = (path: EntryInfo) => boolean; | ||
export type Predicate = string[] | string | Tester; | ||
declare function defaultOptions(): { | ||
root: string; | ||
fileFilter: (_path: EntryInfo) => boolean; | ||
directoryFilter: (_path: EntryInfo) => boolean; | ||
type: string; | ||
lstat: boolean; | ||
depth: number; | ||
alwaysStat: boolean; | ||
highWaterMark: number; | ||
}; | ||
export type ReaddirpOptions = ReturnType<typeof defaultOptions>; | ||
export interface DirEntry { | ||
files: PathOrDirent[]; | ||
depth: number; | ||
path: Path; | ||
} | ||
export declare class ReaddirpStream extends Readable { | ||
parents: any[]; | ||
reading: boolean; | ||
parent?: DirEntry; | ||
_stat: Function; | ||
_maxDepth: number; | ||
_wantsDir: boolean; | ||
_wantsFile: boolean; | ||
_wantsEverything: boolean; | ||
_root: Path; | ||
_isDirent: boolean; | ||
_statsProp: 'dirent' | 'stats'; | ||
_rdOptions: { | ||
encoding: 'utf8'; | ||
withFileTypes: boolean; | ||
}; | ||
_fileFilter: Tester; | ||
_directoryFilter: Tester; | ||
constructor(options?: Partial<ReaddirpOptions>); | ||
_read(batch: number): Promise<void>; | ||
_exploreDir(path: Path, depth: number): Promise<{ | ||
files: string[] | undefined; | ||
depth: number; | ||
path: string; | ||
}>; | ||
_formatEntry(dirent: PathOrDirent, path: Path): EntryInfo | undefined; | ||
_onError(err: Error): void; | ||
_getEntryType(entry: EntryInfo): Promise<void | "" | "file" | "directory">; | ||
_includeAsFile(entry: EntryInfo): boolean | undefined; | ||
} | ||
/** | ||
* Main function which ends up calling readdirRec and reads all files and directories in given root recursively. | ||
* @param root Root directory | ||
* @param options Options to specify root (start directory), filters and recursion depth | ||
*/ | ||
export declare const readdirp: (root: Path, options?: Partial<ReaddirpOptions>) => ReaddirpStream; | ||
export declare const readdirpPromise: (root: Path, options?: Partial<ReaddirpOptions>) => Promise<unknown>; | ||
export default readdirp; | ||
//# sourceMappingURL=index.d.ts.map |
476
index.js
@@ -1,24 +0,20 @@ | ||
'use strict'; | ||
const fs = require('fs'); | ||
const { Readable } = require('stream'); | ||
const sysPath = require('path'); | ||
const { promisify } = require('util'); | ||
const picomatch = require('picomatch'); | ||
const readdir = promisify(fs.readdir); | ||
const stat = promisify(fs.stat); | ||
const lstat = promisify(fs.lstat); | ||
const realpath = promisify(fs.realpath); | ||
/** | ||
* @typedef {Object} EntryInfo | ||
* @property {String} path | ||
* @property {String} fullPath | ||
* @property {fs.Stats=} stats | ||
* @property {fs.Dirent=} dirent | ||
* @property {String} basename | ||
*/ | ||
const BANG = '!'; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.readdirpPromise = exports.readdirp = exports.ReaddirpStream = void 0; | ||
const fs_1 = require("fs"); | ||
const promises_1 = require("fs/promises"); | ||
const stream_1 = require("stream"); | ||
const path_1 = require("path"); | ||
function defaultOptions() { | ||
return { | ||
root: '.', | ||
fileFilter: (_path) => true, | ||
directoryFilter: (_path) => true, | ||
type: FILE_TYPE, | ||
lstat: false, | ||
depth: 2147483648, | ||
alwaysStat: false, | ||
highWaterMark: 4096, | ||
}; | ||
} | ||
const RECURSIVE_ERROR_CODE = 'READDIRP_RECURSIVE_ERROR'; | ||
@@ -31,258 +27,220 @@ const NORMAL_FLOW_ERRORS = new Set(['ENOENT', 'EPERM', 'EACCES', 'ELOOP', RECURSIVE_ERROR_CODE]); | ||
const ALL_TYPES = [FILE_TYPE, DIR_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE]; | ||
const isNormalFlowError = error => NORMAL_FLOW_ERRORS.has(error.code); | ||
const [maj, min] = process.versions.node.split('.').slice(0, 2).map(n => Number.parseInt(n, 10)); | ||
const wantBigintFsStats = process.platform === 'win32' && (maj > 10 || (maj === 10 && min >= 5)); | ||
const normalizeFilter = filter => { | ||
if (filter === undefined) return; | ||
if (typeof filter === 'function') return filter; | ||
if (typeof filter === 'string') { | ||
const glob = picomatch(filter.trim()); | ||
return entry => glob(entry.basename); | ||
} | ||
if (Array.isArray(filter)) { | ||
const positive = []; | ||
const negative = []; | ||
for (const item of filter) { | ||
const trimmed = item.trim(); | ||
if (trimmed.charAt(0) === BANG) { | ||
negative.push(picomatch(trimmed.slice(1))); | ||
} else { | ||
positive.push(picomatch(trimmed)); | ||
} | ||
const DIR_TYPES = new Set([DIR_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE]); | ||
const FILE_TYPES = new Set([FILE_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE]); | ||
const isNormalFlowError = (error) => NORMAL_FLOW_ERRORS.has(error.code); | ||
const wantBigintFsStats = process.platform === 'win32'; | ||
const emptyFn = (_path) => true; | ||
const normalizeFilter = (filter) => { | ||
if (filter === undefined) | ||
return emptyFn; | ||
if (typeof filter === 'function') | ||
return filter; | ||
if (typeof filter === 'string') { | ||
const fl = filter.trim(); | ||
return (entry) => entry.basename === fl; | ||
} | ||
if (negative.length > 0) { | ||
if (positive.length > 0) { | ||
return entry => | ||
positive.some(f => f(entry.basename)) && !negative.some(f => f(entry.basename)); | ||
} | ||
return entry => !negative.some(f => f(entry.basename)); | ||
if (Array.isArray(filter)) { | ||
const trItems = filter.map((item) => item.trim()); | ||
return (entry) => trItems.some((f) => entry.basename === f); | ||
} | ||
return entry => positive.some(f => f(entry.basename)); | ||
} | ||
return emptyFn; | ||
}; | ||
class ReaddirpStream extends Readable { | ||
static get defaultOptions() { | ||
return { | ||
root: '.', | ||
/* eslint-disable no-unused-vars */ | ||
fileFilter: (path) => true, | ||
directoryFilter: (path) => true, | ||
/* eslint-enable no-unused-vars */ | ||
type: FILE_TYPE, | ||
lstat: false, | ||
depth: 2147483648, | ||
alwaysStat: false | ||
}; | ||
} | ||
constructor(options = {}) { | ||
super({ | ||
objectMode: true, | ||
autoDestroy: true, | ||
highWaterMark: options.highWaterMark || 4096 | ||
}); | ||
const opts = { ...ReaddirpStream.defaultOptions, ...options }; | ||
const { root, type } = opts; | ||
this._fileFilter = normalizeFilter(opts.fileFilter); | ||
this._directoryFilter = normalizeFilter(opts.directoryFilter); | ||
const statMethod = opts.lstat ? lstat : stat; | ||
// Use bigint stats if it's windows and stat() supports options (node 10+). | ||
if (wantBigintFsStats) { | ||
this._stat = path => statMethod(path, { bigint: true }); | ||
} else { | ||
this._stat = statMethod; | ||
class ReaddirpStream extends stream_1.Readable { | ||
constructor(options = {}) { | ||
super({ | ||
objectMode: true, | ||
autoDestroy: true, | ||
highWaterMark: options.highWaterMark, | ||
}); | ||
const opts = { ...defaultOptions(), ...options }; | ||
const { root, type } = opts; | ||
this._fileFilter = normalizeFilter(opts.fileFilter); | ||
this._directoryFilter = normalizeFilter(opts.directoryFilter); | ||
const statMethod = opts.lstat ? fs_1.lstatSync : fs_1.statSync; | ||
// Use bigint stats if it's windows and stat() supports options (node 10+). | ||
if (wantBigintFsStats) { | ||
this._stat = (path) => statMethod(path, { bigint: true }); | ||
} | ||
else { | ||
this._stat = statMethod; | ||
} | ||
this._maxDepth = opts.depth; | ||
this._wantsDir = DIR_TYPES.has(type); | ||
this._wantsFile = FILE_TYPES.has(type); | ||
this._wantsEverything = type === EVERYTHING_TYPE; | ||
this._root = (0, path_1.resolve)(root); | ||
this._isDirent = !opts.alwaysStat; | ||
this._statsProp = this._isDirent ? 'dirent' : 'stats'; | ||
this._rdOptions = { encoding: 'utf8', withFileTypes: this._isDirent }; | ||
// Launch stream with one parent, the root dir. | ||
this.parents = [this._exploreDir(root, 1)]; | ||
this.reading = false; | ||
this.parent = undefined; | ||
} | ||
this._maxDepth = opts.depth; | ||
this._wantsDir = [DIR_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE].includes(type); | ||
this._wantsFile = [FILE_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE].includes(type); | ||
this._wantsEverything = type === EVERYTHING_TYPE; | ||
this._root = sysPath.resolve(root); | ||
this._isDirent = ('Dirent' in fs) && !opts.alwaysStat; | ||
this._statsProp = this._isDirent ? 'dirent' : 'stats'; | ||
this._rdOptions = { encoding: 'utf8', withFileTypes: this._isDirent }; | ||
// Launch stream with one parent, the root dir. | ||
this.parents = [this._exploreDir(root, 1)]; | ||
this.reading = false; | ||
this.parent = undefined; | ||
} | ||
async _read(batch) { | ||
if (this.reading) return; | ||
this.reading = true; | ||
try { | ||
while (!this.destroyed && batch > 0) { | ||
const { path, depth, files = [] } = this.parent || {}; | ||
if (files.length > 0) { | ||
const slice = files.splice(0, batch).map(dirent => this._formatEntry(dirent, path)); | ||
for (const entry of await Promise.all(slice)) { | ||
if (this.destroyed) return; | ||
const entryType = await this._getEntryType(entry); | ||
if (entryType === 'directory' && this._directoryFilter(entry)) { | ||
if (depth <= this._maxDepth) { | ||
this.parents.push(this._exploreDir(entry.fullPath, depth + 1)); | ||
} | ||
if (this._wantsDir) { | ||
this.push(entry); | ||
batch--; | ||
} | ||
} else if ((entryType === 'file' || this._includeAsFile(entry)) && this._fileFilter(entry)) { | ||
if (this._wantsFile) { | ||
this.push(entry); | ||
batch--; | ||
} | ||
async _read(batch) { | ||
if (this.reading) | ||
return; | ||
this.reading = true; | ||
try { | ||
while (!this.destroyed && batch > 0) { | ||
const par = this.parent; | ||
const fil = par && par.files; | ||
if (fil && fil.length > 0) { | ||
const { path, depth } = par; | ||
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path)); | ||
for (const entry of slice) { | ||
if (!entry) { | ||
batch--; | ||
return; | ||
} | ||
if (this.destroyed) | ||
return; | ||
const entryType = await this._getEntryType(entry); | ||
if (entryType === 'directory' && this._directoryFilter(entry)) { | ||
if (depth <= this._maxDepth) { | ||
this.parents.push(this._exploreDir(entry.fullPath, depth + 1)); | ||
} | ||
if (this._wantsDir) { | ||
this.push(entry); | ||
batch--; | ||
} | ||
} | ||
else if ((entryType === 'file' || this._includeAsFile(entry)) && | ||
this._fileFilter(entry)) { | ||
if (this._wantsFile) { | ||
this.push(entry); | ||
batch--; | ||
} | ||
} | ||
} | ||
} | ||
else { | ||
const parent = this.parents.pop(); | ||
if (!parent) { | ||
this.push(null); | ||
break; | ||
} | ||
this.parent = await parent; | ||
if (this.destroyed) | ||
return; | ||
} | ||
} | ||
} | ||
} else { | ||
const parent = this.parents.pop(); | ||
if (!parent) { | ||
this.push(null); | ||
break; | ||
} | ||
this.parent = await parent; | ||
if (this.destroyed) return; | ||
} | ||
} | ||
} catch (error) { | ||
this.destroy(error); | ||
} finally { | ||
this.reading = false; | ||
catch (error) { | ||
this.destroy(error); | ||
} | ||
finally { | ||
this.reading = false; | ||
} | ||
} | ||
} | ||
async _exploreDir(path, depth) { | ||
let files; | ||
try { | ||
files = await readdir(path, this._rdOptions); | ||
} catch (error) { | ||
this._onError(error); | ||
async _exploreDir(path, depth) { | ||
let files; | ||
try { | ||
files = await (0, promises_1.readdir)(path, this._rdOptions); | ||
} | ||
catch (error) { | ||
this._onError(error); | ||
} | ||
return { files, depth, path }; | ||
} | ||
return { files, depth, path }; | ||
} | ||
async _formatEntry(dirent, path) { | ||
let entry; | ||
try { | ||
const basename = this._isDirent ? dirent.name : dirent; | ||
const fullPath = sysPath.resolve(sysPath.join(path, basename)); | ||
entry = { path: sysPath.relative(this._root, fullPath), fullPath, basename }; | ||
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath); | ||
} catch (err) { | ||
this._onError(err); | ||
_formatEntry(dirent, path) { | ||
let entry; | ||
const basename = this._isDirent ? dirent.name : dirent; | ||
try { | ||
const fullPath = (0, path_1.resolve)((0, path_1.join)(path, basename)); | ||
entry = { path: (0, path_1.relative)(this._root, fullPath), fullPath, basename }; | ||
entry[this._statsProp] = this._isDirent ? dirent : this._stat(fullPath); | ||
} | ||
catch (err) { | ||
this._onError(err); | ||
return; | ||
} | ||
return entry; | ||
} | ||
return entry; | ||
} | ||
_onError(err) { | ||
if (isNormalFlowError(err) && !this.destroyed) { | ||
this.emit('warn', err); | ||
} else { | ||
this.destroy(err); | ||
_onError(err) { | ||
if (isNormalFlowError(err) && !this.destroyed) { | ||
this.emit('warn', err); | ||
} | ||
else { | ||
this.destroy(err); | ||
} | ||
} | ||
} | ||
async _getEntryType(entry) { | ||
// entry may be undefined, because a warning or an error were emitted | ||
// and the statsProp is undefined | ||
const stats = entry && entry[this._statsProp]; | ||
if (!stats) { | ||
return; | ||
} | ||
if (stats.isFile()) { | ||
return 'file'; | ||
} | ||
if (stats.isDirectory()) { | ||
return 'directory'; | ||
} | ||
if (stats && stats.isSymbolicLink()) { | ||
const full = entry.fullPath; | ||
try { | ||
const entryRealPath = await realpath(full); | ||
const entryRealPathStats = await lstat(entryRealPath); | ||
if (entryRealPathStats.isFile()) { | ||
return 'file'; | ||
async _getEntryType(entry) { | ||
// entry may be undefined, because a warning or an error were emitted | ||
// and the statsProp is undefined | ||
if (!entry && this._statsProp in entry) { | ||
return ''; | ||
} | ||
if (entryRealPathStats.isDirectory()) { | ||
const len = entryRealPath.length; | ||
if (full.startsWith(entryRealPath) && full.substr(len, 1) === sysPath.sep) { | ||
const recursiveError = new Error( | ||
`Circular symlink detected: "${full}" points to "${entryRealPath}"` | ||
); | ||
recursiveError.code = RECURSIVE_ERROR_CODE; | ||
return this._onError(recursiveError); | ||
} | ||
return 'directory'; | ||
const stats = entry[this._statsProp]; | ||
if (stats.isFile()) | ||
return 'file'; | ||
if (stats.isDirectory()) | ||
return 'directory'; | ||
if (stats && stats.isSymbolicLink()) { | ||
const full = entry.fullPath; | ||
try { | ||
const entryRealPath = await (0, promises_1.realpath)(full); | ||
const entryRealPathStats = (0, fs_1.lstatSync)(entryRealPath); | ||
if (entryRealPathStats.isFile()) { | ||
return 'file'; | ||
} | ||
if (entryRealPathStats.isDirectory()) { | ||
const len = entryRealPath.length; | ||
if (full.startsWith(entryRealPath) && full.substr(len, 1) === path_1.sep) { | ||
const recursiveError = new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`); | ||
// @ts-ignore | ||
recursiveError.code = RECURSIVE_ERROR_CODE; | ||
return this._onError(recursiveError); | ||
} | ||
return 'directory'; | ||
} | ||
} | ||
catch (error) { | ||
this._onError(error); | ||
return ''; | ||
} | ||
} | ||
} catch (error) { | ||
this._onError(error); | ||
} | ||
} | ||
} | ||
_includeAsFile(entry) { | ||
const stats = entry && entry[this._statsProp]; | ||
return stats && this._wantsEverything && !stats.isDirectory(); | ||
} | ||
_includeAsFile(entry) { | ||
const stats = entry && entry[this._statsProp]; | ||
return stats && this._wantsEverything && !stats.isDirectory(); | ||
} | ||
} | ||
exports.ReaddirpStream = ReaddirpStream; | ||
/** | ||
* @typedef {Object} ReaddirpArguments | ||
* @property {Function=} fileFilter | ||
* @property {Function=} directoryFilter | ||
* @property {String=} type | ||
* @property {Number=} depth | ||
* @property {String=} root | ||
* @property {Boolean=} lstat | ||
* @property {Boolean=} bigint | ||
*/ | ||
/** | ||
* Main function which ends up calling readdirRec and reads all files and directories in given root recursively. | ||
* @param {String} root Root directory | ||
* @param {ReaddirpArguments=} options Options to specify root (start directory), filters and recursion depth | ||
* @param root Root directory | ||
* @param options Options to specify root (start directory), filters and recursion depth | ||
*/ | ||
const readdirp = (root, options = {}) => { | ||
let type = options.entryType || options.type; | ||
if (type === 'both') type = FILE_DIR_TYPE; // backwards-compatibility | ||
if (type) options.type = type; | ||
if (!root) { | ||
throw new Error('readdirp: root argument is required. Usage: readdirp(root, options)'); | ||
} else if (typeof root !== 'string') { | ||
throw new TypeError('readdirp: root argument must be a string. Usage: readdirp(root, options)'); | ||
} else if (type && !ALL_TYPES.includes(type)) { | ||
throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(', ')}`); | ||
} | ||
options.root = root; | ||
return new ReaddirpStream(options); | ||
// @ts-ignore | ||
let type = options.entryType || options.type; | ||
if (type === 'both') | ||
type = FILE_DIR_TYPE; // backwards-compatibility | ||
if (type) | ||
options.type = type; | ||
if (!root) { | ||
throw new Error('readdirp: root argument is required. Usage: readdirp(root, options)'); | ||
} | ||
else if (typeof root !== 'string') { | ||
throw new TypeError('readdirp: root argument must be a string. Usage: readdirp(root, options)'); | ||
} | ||
else if (type && !ALL_TYPES.includes(type)) { | ||
throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(', ')}`); | ||
} | ||
options.root = root; | ||
return new ReaddirpStream(options); | ||
}; | ||
exports.readdirp = readdirp; | ||
const readdirpPromise = (root, options = {}) => { | ||
return new Promise((resolve, reject) => { | ||
const files = []; | ||
readdirp(root, options) | ||
.on('data', entry => files.push(entry)) | ||
.on('end', () => resolve(files)) | ||
.on('error', error => reject(error)); | ||
}); | ||
return new Promise((resolve, reject) => { | ||
const files = []; | ||
(0, exports.readdirp)(root, options) | ||
.on('data', (entry) => files.push(entry)) | ||
.on('end', () => resolve(files)) | ||
.on('error', (error) => reject(error)); | ||
}); | ||
}; | ||
readdirp.promise = readdirpPromise; | ||
readdirp.ReaddirpStream = ReaddirpStream; | ||
readdirp.default = readdirp; | ||
module.exports = readdirp; | ||
exports.readdirpPromise = readdirpPromise; | ||
exports.default = exports.readdirp; | ||
//# sourceMappingURL=index.js.map |
108
package.json
{ | ||
"name": "readdirp", | ||
"description": "Recursive version of fs.readdir with streaming API.", | ||
"version": "3.6.0", | ||
"version": "4.0.0", | ||
"homepage": "https://github.com/paulmillr/readdirp", | ||
@@ -19,10 +19,22 @@ "repository": { | ||
], | ||
"main": "index.js", | ||
"engines": { | ||
"node": ">=8.10.0" | ||
"node": ">= 14.16.0" | ||
}, | ||
"files": [ | ||
"index.js", | ||
"index.d.ts" | ||
"index.d.ts", | ||
"index.d.ts.map", | ||
"index.js.map", | ||
"esm" | ||
], | ||
"main": "./index.js", | ||
"module": "./esm/index.js", | ||
"types": "./index.d.ts", | ||
"exports": { | ||
".": { | ||
"import": "./esm/index.js", | ||
"require": "./index.js" | ||
} | ||
}, | ||
"sideEffects": false, | ||
"keywords": [ | ||
@@ -39,21 +51,19 @@ "recursive", | ||
"scripts": { | ||
"dtslint": "dtslint", | ||
"build": "tsc && tsc -p tsconfig.esm.json", | ||
"nyc": "nyc", | ||
"mocha": "mocha --exit", | ||
"lint": "eslint --report-unused-disable-directives --ignore-path .gitignore .", | ||
"test": "npm run lint && nyc npm run mocha" | ||
"lint": "prettier --check index.ts", | ||
"format": "prettier --write index.ts", | ||
"test": "nyc npm run mocha" | ||
}, | ||
"dependencies": { | ||
"picomatch": "^2.2.1" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^14", | ||
"chai": "^4.2", | ||
"chai-subset": "^1.6", | ||
"dtslint": "^3.3.0", | ||
"eslint": "^7.0.0", | ||
"mocha": "^7.1.1", | ||
"nyc": "^15.0.0", | ||
"rimraf": "^3.0.0", | ||
"typescript": "^4.0.3" | ||
"@paulmillr/jsbt": "0.2.1", | ||
"@types/node": "20.14.8", | ||
"chai": "4.3.4", | ||
"chai-subset": "1.6.0", | ||
"mocha": "10.7.3", | ||
"nyc": "15.0.1", | ||
"prettier": "3.1.1", | ||
"rimraf": "6.0.1", | ||
"typescript": "5.5.2" | ||
}, | ||
@@ -66,60 +76,6 @@ "nyc": { | ||
}, | ||
"eslintConfig": { | ||
"root": true, | ||
"extends": "eslint:recommended", | ||
"parserOptions": { | ||
"ecmaVersion": 9, | ||
"sourceType": "script" | ||
}, | ||
"env": { | ||
"node": true, | ||
"es6": true | ||
}, | ||
"rules": { | ||
"array-callback-return": "error", | ||
"no-empty": [ | ||
"error", | ||
{ | ||
"allowEmptyCatch": true | ||
} | ||
], | ||
"no-else-return": [ | ||
"error", | ||
{ | ||
"allowElseIf": false | ||
} | ||
], | ||
"no-lonely-if": "error", | ||
"no-var": "error", | ||
"object-shorthand": "error", | ||
"prefer-arrow-callback": [ | ||
"error", | ||
{ | ||
"allowNamedFunctions": true | ||
} | ||
], | ||
"prefer-const": [ | ||
"error", | ||
{ | ||
"ignoreReadBeforeAssign": true | ||
} | ||
], | ||
"prefer-destructuring": [ | ||
"error", | ||
{ | ||
"object": true, | ||
"array": false | ||
} | ||
], | ||
"prefer-spread": "error", | ||
"prefer-template": "error", | ||
"radix": "error", | ||
"semi": "error", | ||
"strict": "error", | ||
"quotes": [ | ||
"error", | ||
"single" | ||
] | ||
} | ||
"funding": { | ||
"type": "individual", | ||
"url": "https://paulmillr.com/funding/" | ||
} | ||
} |
@@ -11,6 +11,5 @@ # readdirp [![Weekly downloads](https://img.shields.io/npm/dw/readdirp.svg)](https://github.com/paulmillr/readdirp) | ||
```javascript | ||
const readdirp = require('readdirp'); | ||
// Use streams to achieve small RAM & CPU footprint. | ||
// 1) Streams example with for-await. | ||
import readdirp from 'readdirp'; | ||
for await (const entry of readdirp('.')) { | ||
@@ -23,2 +22,3 @@ const {path} = entry; | ||
// Print out all JS files along with their size within the current folder & subfolders. | ||
import readdirp from 'readdirp'; | ||
readdirp('.', {fileFilter: '*.js', alwaysStat: true}) | ||
@@ -35,9 +35,11 @@ .on('data', (entry) => { | ||
// 3) Promise example. More RAM and CPU than streams / for-await. | ||
const files = await readdirp.promise('.'); | ||
import { readdirpPromise } from 'readdirp'; | ||
const files = await readdirpPromise('.'); | ||
console.log(files.map(file => file.path)); | ||
// Other options. | ||
import readdirp from 'readdirp'; | ||
readdirp('test', { | ||
fileFilter: '*.js', | ||
directoryFilter: ['!.git', '!*modules'] | ||
directoryFilter: ['!.git', '!*modules'], | ||
// directoryFilter: (di) => di.basename.length === 9 | ||
@@ -49,4 +51,2 @@ type: 'files_directories', | ||
For more examples, check out `examples` directory. | ||
## API | ||
@@ -74,11 +74,7 @@ | ||
- `fileFilter: ["*.js"]`: filter to include or exclude files. A `Function`, Glob string or Array of glob strings. | ||
- `fileFilter: ["*.js"]`: filter to include or exclude files. A `Function`, string or Array of strings. | ||
- **Function**: a function that takes an entry info as a parameter and returns true to include or false to exclude the entry | ||
- **Glob string**: a string (e.g., `*.js`) which is matched using [picomatch](https://github.com/micromatch/picomatch), so go there for more | ||
information. Globstars (`**`) are not supported since specifying a recursive pattern for an already recursive function doesn't make sense. Negated globs (as explained in the minimatch documentation) are allowed, e.g., `!*.txt` matches everything but text files. | ||
- **Array of glob strings**: either need to be all inclusive or all exclusive (negated) patterns otherwise an error is thrown. | ||
`['*.json', '*.js']` includes all JavaScript and Json files. | ||
`['!.git', '!node_modules']` includes all directories except the '.git' and 'node_modules'. | ||
- Directories that do not pass a filter will not be recursed into. | ||
- `directoryFilter: ['!.git']`: filter to include/exclude directories found and to recurse into. Directories that do not pass a filter will not be recursed into. | ||
- **string**: a string (e.g., `index.js`) | ||
- **Array of strings**: | ||
- `directoryFilter: ['.git']`: filter to include/exclude directories found and to recurse into. Directories that do not pass a filter will not be recursed into. | ||
- `depth: 5`: depth at which to stop recursing even if more subdirectories are found | ||
@@ -101,2 +97,5 @@ - `type: 'files'`: determines if data events on the stream should be emitted for `'files'` (default), `'directories'`, `'files_directories'`, or `'all'`. Setting to `'all'` will also include entries for other types of file descriptors like character devices, unix sockets and named pipes. | ||
- 4.0 (Aug 25, 2024) rewritten in typescript, producing hybrid common.js / esm module. | ||
- Remove glob support and all dependencies | ||
- Make sure you're using `let {readdirp} = require('readdirp')` in common.js | ||
- 3.5 (Oct 13, 2020) disallows recursive directory-based symlinks. | ||
@@ -121,2 +120,3 @@ Before, it could have entered infinite loop. | ||
- Supported node.js versions: | ||
- 4.x: node 14+ | ||
- 3.x: node 8+ | ||
@@ -123,0 +123,0 @@ - 2.x: node 0.6+ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
52773
0
11
616
4
1
- Removedpicomatch@^2.2.1
- Removedpicomatch@2.3.1(transitive)