tiny-readdir 2.7.2 → 2.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +7 -6
- package/dist/utils.d.ts +2 -8
- package/dist/utils.js +1 -22
- package/package.json +7 -6
- package/readme.md +19 -12
- package/.editorconfig +0 -10
- package/src/constants.ts +0 -16
- package/src/index.ts +0 -256
- package/src/types.ts +0 -55
- package/src/utils.ts +0 -59
- package/test/index.js +0 -291
- package/tsconfig.json +0 -3
package/dist/constants.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Dirent, Options, ResultDirectory, ResultDirectories, Result } from './types';
|
|
1
|
+
import type { Dirent, Options, ResultDirectory, ResultDirectories, Result } from './types.js';
|
|
2
2
|
declare const readdir: (rootPath: string, options?: Options) => Promise<Result>;
|
|
3
3
|
export default readdir;
|
|
4
4
|
export type { Dirent, Options, ResultDirectory, ResultDirectories, Result };
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/* IMPORT */
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import makeCounterPromise from 'promise-make-counter';
|
|
4
5
|
import { NOOP_PROMISE_LIKE } from './constants.js';
|
|
5
|
-
import { castArray, isFunction
|
|
6
|
+
import { castArray, isFunction } from './utils.js';
|
|
6
7
|
/* MAIN */
|
|
7
|
-
//TODO: Streamline the type of
|
|
8
|
+
//TODO: Streamline the type of dirmaps
|
|
8
9
|
const readdir = (rootPath, options) => {
|
|
9
10
|
const followSymlinks = options?.followSymlinks ?? false;
|
|
10
11
|
const maxDepth = options?.depth ?? Infinity;
|
|
@@ -150,14 +151,14 @@ const readdir = (rootPath, options) => {
|
|
|
150
151
|
});
|
|
151
152
|
});
|
|
152
153
|
};
|
|
153
|
-
const populateResultFromSymlink =
|
|
154
|
+
const populateResultFromSymlink = (rootPath, depth) => {
|
|
154
155
|
increment();
|
|
155
156
|
fs.realpath(rootPath, (error, realPath) => {
|
|
156
157
|
if (error)
|
|
157
158
|
return decrement();
|
|
158
159
|
if (signal.aborted)
|
|
159
160
|
return decrement();
|
|
160
|
-
fs.stat(realPath,
|
|
161
|
+
fs.stat(realPath, (error, stat) => {
|
|
161
162
|
if (error)
|
|
162
163
|
return decrement();
|
|
163
164
|
if (signal.aborted)
|
|
@@ -169,7 +170,7 @@ const readdir = (rootPath, options) => {
|
|
|
169
170
|
});
|
|
170
171
|
});
|
|
171
172
|
};
|
|
172
|
-
const
|
|
173
|
+
const populateResultFromRoot = async (rootPath, depth = 1) => {
|
|
173
174
|
rootPath = path.normalize(rootPath);
|
|
174
175
|
visited.add(rootPath);
|
|
175
176
|
populateResultFromPath(rootPath, depth);
|
|
@@ -178,7 +179,7 @@ const readdir = (rootPath, options) => {
|
|
|
178
179
|
return resultEmpty;
|
|
179
180
|
return result;
|
|
180
181
|
};
|
|
181
|
-
return
|
|
182
|
+
return populateResultFromRoot(rootPath);
|
|
182
183
|
};
|
|
183
184
|
/* EXPORT */
|
|
184
185
|
export default readdir;
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
declare const castArray: <T>(value: T | T[]) => T[];
|
|
1
|
+
declare const castArray: <T>(value: T[] | T) => T[];
|
|
3
2
|
declare const isFunction: (value: unknown) => value is Function;
|
|
4
|
-
|
|
5
|
-
promise: Promise<void>;
|
|
6
|
-
increment: Callback;
|
|
7
|
-
decrement: Callback;
|
|
8
|
-
};
|
|
9
|
-
export { castArray, isFunction, makeCounterPromise };
|
|
3
|
+
export { castArray, isFunction };
|
package/dist/utils.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/* IMPORT */
|
|
2
|
-
import makeNakedPromise from 'promise-make-naked';
|
|
3
1
|
/* MAIN */
|
|
4
2
|
const castArray = (value) => {
|
|
5
3
|
return Array.isArray(value) ? value : [value];
|
|
@@ -7,24 +5,5 @@ const castArray = (value) => {
|
|
|
7
5
|
const isFunction = (value) => {
|
|
8
6
|
return (typeof value === 'function');
|
|
9
7
|
};
|
|
10
|
-
const makeCounterPromise = () => {
|
|
11
|
-
const { promise, resolve } = makeNakedPromise();
|
|
12
|
-
let counter = 0;
|
|
13
|
-
const increment = () => {
|
|
14
|
-
counter += 1;
|
|
15
|
-
};
|
|
16
|
-
const decrement = () => {
|
|
17
|
-
counter -= 1;
|
|
18
|
-
if (counter)
|
|
19
|
-
return;
|
|
20
|
-
resolve();
|
|
21
|
-
};
|
|
22
|
-
const init = () => {
|
|
23
|
-
increment();
|
|
24
|
-
queueMicrotask(decrement);
|
|
25
|
-
};
|
|
26
|
-
init();
|
|
27
|
-
return { promise, increment, decrement };
|
|
28
|
-
};
|
|
29
8
|
/* EXPORT */
|
|
30
|
-
export { castArray, isFunction
|
|
9
|
+
export { castArray, isFunction };
|
package/package.json
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
"name": "tiny-readdir",
|
|
3
3
|
"repository": "github:fabiospampinato/tiny-readdir",
|
|
4
4
|
"description": "A simple promisified recursive readdir function.",
|
|
5
|
-
"
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"version": "2.7.4",
|
|
6
7
|
"type": "module",
|
|
7
8
|
"main": "dist/index.js",
|
|
8
9
|
"exports": "./dist/index.js",
|
|
@@ -23,12 +24,12 @@
|
|
|
23
24
|
"tiny"
|
|
24
25
|
],
|
|
25
26
|
"dependencies": {
|
|
26
|
-
"promise-make-
|
|
27
|
+
"promise-make-counter": "^1.0.2"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
|
-
"@types/node": "^
|
|
30
|
-
"fava": "^0.
|
|
31
|
-
"tsex": "^
|
|
32
|
-
"typescript": "^5.
|
|
30
|
+
"@types/node": "^18.19.70",
|
|
31
|
+
"fava": "^0.3.4",
|
|
32
|
+
"tsex": "^4.0.2",
|
|
33
|
+
"typescript": "^5.7.3"
|
|
33
34
|
}
|
|
34
35
|
}
|
package/readme.md
CHANGED
|
@@ -5,7 +5,7 @@ A simple promisified recursive readdir function.
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
npm install
|
|
8
|
+
npm install tiny-readdir
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
@@ -13,8 +13,9 @@ npm install --save tiny-readdir
|
|
|
13
13
|
```ts
|
|
14
14
|
import readdir from 'tiny-readdir';
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
// Let's recursively read into a directory
|
|
17
17
|
|
|
18
|
+
const aborter = new AbortController ();
|
|
18
19
|
const result = await readdir ( '/foo/bar', {
|
|
19
20
|
depth: 20, // Maximum depth to look at
|
|
20
21
|
limit: 1_000_000, // Maximum number of files explored, useful as a stop gap in some edge cases
|
|
@@ -24,19 +25,25 @@ const result = await readdir ( '/foo/bar', {
|
|
|
24
25
|
onDirents: dirents => console.log ( dirents ) // Optional callback that will be called as soon as new dirents are available, useful for example for discovering ".gitignore" files while searching
|
|
25
26
|
});
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
// This is how we would abort the reactive read after 10s
|
|
29
|
+
|
|
30
|
+
setTimeout ( () => aborter.abort (), 10_000 ); // Aborting if it's going to take longer than 10s
|
|
31
|
+
|
|
32
|
+
// This is the basic information we'll get
|
|
33
|
+
|
|
34
|
+
result.directories; // => Array of absolute paths pointing to directories
|
|
35
|
+
result.files; // => Array of absolute paths pointing to files
|
|
36
|
+
result.symlinks; // => Array of absolute paths pointing to symlinks
|
|
30
37
|
|
|
31
|
-
|
|
32
|
-
console.log ( result.filesNames ); // => Set of files name found
|
|
33
|
-
console.log ( result.symlinksNames ); // => Set of symlinks names found
|
|
38
|
+
// This is more advanced information we'll get, which is useful in some cases
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
result.directoriesNames; // => Set of directories names found
|
|
41
|
+
result.filesNames; // => Set of files name found
|
|
42
|
+
result.symlinksNames; // => Set of symlinks names found
|
|
38
43
|
|
|
39
|
-
|
|
44
|
+
result.directoriesNamesToPaths; // => Record of directories names found to their paths
|
|
45
|
+
result.filesNamesToPaths; // => Record of files names found to their paths
|
|
46
|
+
result.symlinksNamesToPaths; // => Record of symlinks names found to their paths
|
|
40
47
|
```
|
|
41
48
|
|
|
42
49
|
## License
|
package/.editorconfig
DELETED
package/src/constants.ts
DELETED
package/src/index.ts
DELETED
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/* IMPORT */
|
|
3
|
-
|
|
4
|
-
import fs from 'node:fs';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import {NOOP_PROMISE_LIKE} from './constants';
|
|
7
|
-
import {castArray, isFunction, makeCounterPromise} from './utils';
|
|
8
|
-
import type {Dirent, Options, ResultDirectory, ResultDirectories, Result} from './types';
|
|
9
|
-
|
|
10
|
-
/* MAIN */
|
|
11
|
-
|
|
12
|
-
//TODO: Streamline the type of dirnmaps
|
|
13
|
-
|
|
14
|
-
const readdir = ( rootPath: string, options?: Options ): Promise<Result> => {
|
|
15
|
-
|
|
16
|
-
const followSymlinks = options?.followSymlinks ?? false;
|
|
17
|
-
const maxDepth = options?.depth ?? Infinity;
|
|
18
|
-
const maxPaths = options?.limit ?? Infinity;
|
|
19
|
-
const ignore = options?.ignore ?? [];
|
|
20
|
-
const ignores = castArray ( ignore ).map ( ignore => isFunction ( ignore ) ? ignore : ( targetPath: string ) => ignore.test ( targetPath ) );
|
|
21
|
-
const isIgnored = ( targetPath: string ) => ignores.some ( ignore => ignore ( targetPath ) );
|
|
22
|
-
const signal = options?.signal ?? { aborted: false };
|
|
23
|
-
const onDirents = options?.onDirents || (() => {});
|
|
24
|
-
const directories: string[] = [];
|
|
25
|
-
const directoriesNames: Set<string> = new Set ();
|
|
26
|
-
const directoriesNamesToPaths: Record<string, string[]> = {};
|
|
27
|
-
const files: string[] = [];
|
|
28
|
-
const filesNames: Set<string> = new Set ();
|
|
29
|
-
const filesNamesToPaths: Record<string, string[]> = {};
|
|
30
|
-
const symlinks: string[] = [];
|
|
31
|
-
const symlinksNames: Set<string> = new Set ();
|
|
32
|
-
const symlinksNamesToPaths: Record<string, string[]> = {};
|
|
33
|
-
const map: ResultDirectories = {};
|
|
34
|
-
const visited = new Set<string> ();
|
|
35
|
-
const resultEmpty: Result = { directories: [], directoriesNames: new Set (), directoriesNamesToPaths: {}, files: [], filesNames: new Set (), filesNamesToPaths: {}, symlinks: [], symlinksNames: new Set (), symlinksNamesToPaths: {}, map: {} };
|
|
36
|
-
const result: Result = { directories, directoriesNames, directoriesNamesToPaths, files, filesNames, filesNamesToPaths, symlinks, symlinksNames, symlinksNamesToPaths, map };
|
|
37
|
-
const {promise, increment, decrement} = makeCounterPromise ();
|
|
38
|
-
|
|
39
|
-
let foundPaths = 0;
|
|
40
|
-
|
|
41
|
-
const handleDirectory = ( dirmap: ResultDirectory, subPath: string, name: string, depth: number ): void => {
|
|
42
|
-
|
|
43
|
-
if ( visited.has ( subPath ) ) return;
|
|
44
|
-
|
|
45
|
-
if ( foundPaths >= maxPaths ) return;
|
|
46
|
-
|
|
47
|
-
foundPaths += 1;
|
|
48
|
-
dirmap.directories.push ( subPath );
|
|
49
|
-
dirmap.directoriesNames.add ( name );
|
|
50
|
-
// dirmap.directoriesNamesToPaths.propertyIsEnumerable(name) || ( dirmap.directoriesNamesToPaths[name] = [] );
|
|
51
|
-
// dirmap.directoriesNamesToPaths[name].push ( subPath );
|
|
52
|
-
directories.push ( subPath );
|
|
53
|
-
directoriesNames.add ( name );
|
|
54
|
-
directoriesNamesToPaths.propertyIsEnumerable(name) || ( directoriesNamesToPaths[name] = [] );
|
|
55
|
-
directoriesNamesToPaths[name].push ( subPath );
|
|
56
|
-
visited.add ( subPath );
|
|
57
|
-
|
|
58
|
-
if ( depth >= maxDepth ) return;
|
|
59
|
-
|
|
60
|
-
if ( foundPaths >= maxPaths ) return;
|
|
61
|
-
|
|
62
|
-
populateResultFromPath ( subPath, depth + 1 );
|
|
63
|
-
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const handleFile = ( dirmap: ResultDirectory, subPath: string, name: string ): void => {
|
|
67
|
-
|
|
68
|
-
if ( visited.has ( subPath ) ) return;
|
|
69
|
-
|
|
70
|
-
if ( foundPaths >= maxPaths ) return;
|
|
71
|
-
|
|
72
|
-
foundPaths += 1;
|
|
73
|
-
dirmap.files.push ( subPath );
|
|
74
|
-
dirmap.filesNames.add ( name );
|
|
75
|
-
// dirmap.filesNamesToPaths.propertyIsEnumerable(name) || ( dirmap.filesNamesToPaths[name] = [] );
|
|
76
|
-
// dirmap.filesNamesToPaths[name].push ( subPath );
|
|
77
|
-
files.push ( subPath );
|
|
78
|
-
filesNames.add ( name );
|
|
79
|
-
filesNamesToPaths.propertyIsEnumerable(name) || ( filesNamesToPaths[name] = [] );
|
|
80
|
-
filesNamesToPaths[name].push ( subPath );
|
|
81
|
-
visited.add ( subPath );
|
|
82
|
-
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const handleSymlink = ( dirmap: ResultDirectory, subPath: string, name: string, depth: number ): void => {
|
|
86
|
-
|
|
87
|
-
if ( visited.has ( subPath ) ) return;
|
|
88
|
-
|
|
89
|
-
if ( foundPaths >= maxPaths ) return;
|
|
90
|
-
|
|
91
|
-
foundPaths += 1;
|
|
92
|
-
dirmap.symlinks.push ( subPath );
|
|
93
|
-
dirmap.symlinksNames.add ( name );
|
|
94
|
-
// dirmap.symlinksNamesToPaths.propertyIsEnumerable(name) || ( dirmap.symlinksNamesToPaths[name] = [] );
|
|
95
|
-
// dirmap.symlinksNamesToPaths[name].push ( subPath );
|
|
96
|
-
symlinks.push ( subPath );
|
|
97
|
-
symlinksNames.add ( name );
|
|
98
|
-
symlinksNamesToPaths.propertyIsEnumerable(name) || ( symlinksNamesToPaths[name] = [] );
|
|
99
|
-
symlinksNamesToPaths[name].push ( subPath );
|
|
100
|
-
visited.add ( subPath );
|
|
101
|
-
|
|
102
|
-
if ( !followSymlinks ) return;
|
|
103
|
-
|
|
104
|
-
if ( depth >= maxDepth ) return;
|
|
105
|
-
|
|
106
|
-
if ( foundPaths >= maxPaths ) return;
|
|
107
|
-
|
|
108
|
-
populateResultFromSymlink ( subPath, depth + 1 );
|
|
109
|
-
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
const handleStat = ( dirmap: ResultDirectory, rootPath: string, name: string, stat: fs.Stats, depth: number ): void => {
|
|
113
|
-
|
|
114
|
-
if ( signal.aborted ) return;
|
|
115
|
-
|
|
116
|
-
if ( isIgnored ( rootPath ) ) return;
|
|
117
|
-
|
|
118
|
-
if ( stat.isDirectory () ) {
|
|
119
|
-
|
|
120
|
-
handleDirectory ( dirmap, rootPath, name, depth );
|
|
121
|
-
|
|
122
|
-
} else if ( stat.isFile () ) {
|
|
123
|
-
|
|
124
|
-
handleFile ( dirmap, rootPath, name );
|
|
125
|
-
|
|
126
|
-
} else if ( stat.isSymbolicLink () ) {
|
|
127
|
-
|
|
128
|
-
handleSymlink ( dirmap, rootPath, name, depth );
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const handleDirent = ( dirmap: ResultDirectory, rootPath: string, dirent: fs.Dirent, depth: number ): void => {
|
|
135
|
-
|
|
136
|
-
if ( signal.aborted ) return;
|
|
137
|
-
|
|
138
|
-
const separator = ( rootPath === path.sep ) ? '' : path.sep;
|
|
139
|
-
const name = dirent.name;
|
|
140
|
-
const subPath = `${rootPath}${separator}${name}`;
|
|
141
|
-
|
|
142
|
-
if ( isIgnored ( subPath ) ) return;
|
|
143
|
-
|
|
144
|
-
if ( dirent.isDirectory () ) {
|
|
145
|
-
|
|
146
|
-
handleDirectory ( dirmap, subPath, name, depth );
|
|
147
|
-
|
|
148
|
-
} else if ( dirent.isFile () ) {
|
|
149
|
-
|
|
150
|
-
handleFile ( dirmap, subPath, name );
|
|
151
|
-
|
|
152
|
-
} else if ( dirent.isSymbolicLink () ) {
|
|
153
|
-
|
|
154
|
-
handleSymlink ( dirmap, subPath, name, depth );
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
const handleDirents = ( dirmap: ResultDirectory, rootPath: string, dirents: fs.Dirent[], depth: number ): void => {
|
|
161
|
-
|
|
162
|
-
for ( let i = 0, l = dirents.length; i < l; i++ ) {
|
|
163
|
-
|
|
164
|
-
handleDirent ( dirmap, rootPath, dirents[i], depth );
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
const populateResultFromPath = ( rootPath: string, depth: number ): void => {
|
|
171
|
-
|
|
172
|
-
if ( signal.aborted ) return;
|
|
173
|
-
|
|
174
|
-
if ( depth > maxDepth ) return;
|
|
175
|
-
|
|
176
|
-
if ( foundPaths >= maxPaths ) return;
|
|
177
|
-
|
|
178
|
-
increment ();
|
|
179
|
-
|
|
180
|
-
fs.readdir ( rootPath, { withFileTypes: true }, ( error, dirents ) => {
|
|
181
|
-
|
|
182
|
-
if ( error ) return decrement ();
|
|
183
|
-
|
|
184
|
-
if ( signal.aborted ) return decrement ();
|
|
185
|
-
|
|
186
|
-
if ( !dirents.length ) return decrement ();
|
|
187
|
-
|
|
188
|
-
const promise = onDirents ( dirents ) || NOOP_PROMISE_LIKE;
|
|
189
|
-
|
|
190
|
-
promise.then ( () => {
|
|
191
|
-
|
|
192
|
-
const dirmap = map[rootPath] = { directories: [], directoriesNames: new Set (), directoriesNamesToPaths: {}, files: [], filesNames: new Set (), filesNamesToPaths: {}, symlinks: [], symlinksNames: new Set (), symlinksNamesToPaths: {} };
|
|
193
|
-
|
|
194
|
-
handleDirents ( dirmap, rootPath, dirents, depth );
|
|
195
|
-
|
|
196
|
-
decrement ();
|
|
197
|
-
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
const populateResultFromSymlink = async ( rootPath: string, depth: number ): Promise<void> => {
|
|
205
|
-
|
|
206
|
-
increment ();
|
|
207
|
-
|
|
208
|
-
fs.realpath ( rootPath, ( error, realPath ) => {
|
|
209
|
-
|
|
210
|
-
if ( error ) return decrement ();
|
|
211
|
-
|
|
212
|
-
if ( signal.aborted ) return decrement ();
|
|
213
|
-
|
|
214
|
-
fs.stat ( realPath, async ( error, stat ) => {
|
|
215
|
-
|
|
216
|
-
if ( error ) return decrement ();
|
|
217
|
-
|
|
218
|
-
if ( signal.aborted ) return decrement ();
|
|
219
|
-
|
|
220
|
-
const name = path.basename ( realPath );
|
|
221
|
-
const dirmap = map[rootPath] = { directories: [], directoriesNames: new Set (), directoriesNamesToPaths: {}, files: [], filesNames: new Set (), filesNamesToPaths: {}, symlinks: [], symlinksNames: new Set (), symlinksNamesToPaths: {} };
|
|
222
|
-
|
|
223
|
-
handleStat ( dirmap, realPath, name, stat, depth );
|
|
224
|
-
|
|
225
|
-
decrement ();
|
|
226
|
-
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
const getResult = async ( rootPath: string, depth: number = 1 ): Promise<Result> => {
|
|
234
|
-
|
|
235
|
-
rootPath = path.normalize ( rootPath );
|
|
236
|
-
|
|
237
|
-
visited.add ( rootPath );
|
|
238
|
-
|
|
239
|
-
populateResultFromPath ( rootPath, depth );
|
|
240
|
-
|
|
241
|
-
await promise;
|
|
242
|
-
|
|
243
|
-
if ( signal.aborted ) return resultEmpty;
|
|
244
|
-
|
|
245
|
-
return result;
|
|
246
|
-
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
return getResult ( rootPath );
|
|
250
|
-
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
/* EXPORT */
|
|
254
|
-
|
|
255
|
-
export default readdir;
|
|
256
|
-
export type {Dirent, Options, ResultDirectory, ResultDirectories, Result};
|
package/src/types.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/* HELPERS */
|
|
3
|
-
|
|
4
|
-
type Callback = () => void;
|
|
5
|
-
|
|
6
|
-
type ArrayMaybe<T> = T[] | T;
|
|
7
|
-
|
|
8
|
-
type PromiseMaybe<T> = Promise<T> | T;
|
|
9
|
-
|
|
10
|
-
/* MAIN */
|
|
11
|
-
|
|
12
|
-
type Dirent = {
|
|
13
|
-
isFile: () => boolean,
|
|
14
|
-
isDirectory: () => boolean,
|
|
15
|
-
isBlockDevice: () => boolean,
|
|
16
|
-
isCharacterDevice: () => boolean,
|
|
17
|
-
isSymbolicLink: () => boolean,
|
|
18
|
-
isFIFO: () => boolean,
|
|
19
|
-
isSocket: () => boolean,
|
|
20
|
-
name: string,
|
|
21
|
-
path: string
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
type Options = {
|
|
25
|
-
depth?: number,
|
|
26
|
-
limit?: number,
|
|
27
|
-
followSymlinks?: boolean,
|
|
28
|
-
ignore?: ArrayMaybe<(( targetPath: string ) => boolean) | RegExp>,
|
|
29
|
-
signal?: { aborted: boolean },
|
|
30
|
-
onDirents?: ( dirents: Dirent[] ) => PromiseMaybe<undefined>
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
type ResultDirectory = {
|
|
34
|
-
directories: string[],
|
|
35
|
-
directoriesNames: Set<string>,
|
|
36
|
-
directoriesNamesToPaths: Record<string, string[]>,
|
|
37
|
-
files: string[],
|
|
38
|
-
filesNames: Set<string>,
|
|
39
|
-
filesNamesToPaths: Record<string, string[]>,
|
|
40
|
-
symlinks: string[],
|
|
41
|
-
symlinksNames: Set<string>,
|
|
42
|
-
symlinksNamesToPaths: Record<string, string[]>
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
type ResultDirectories = {
|
|
46
|
-
[path: string]: ResultDirectory
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
type Result = ResultDirectory & {
|
|
50
|
-
map: ResultDirectories
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
/* EXPORT */
|
|
54
|
-
|
|
55
|
-
export type {Callback, PromiseMaybe, Dirent, Options, ResultDirectory, ResultDirectories, Result};
|
package/src/utils.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/* IMPORT */
|
|
3
|
-
|
|
4
|
-
import makeNakedPromise from 'promise-make-naked';
|
|
5
|
-
import type {Callback} from './types';
|
|
6
|
-
|
|
7
|
-
/* MAIN */
|
|
8
|
-
|
|
9
|
-
const castArray = <T> ( value: T[] | T ): T[] => {
|
|
10
|
-
|
|
11
|
-
return Array.isArray ( value ) ? value : [value];
|
|
12
|
-
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const isFunction = ( value: unknown ): value is Function => {
|
|
16
|
-
|
|
17
|
-
return ( typeof value === 'function' );
|
|
18
|
-
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const makeCounterPromise = (): { promise: Promise<void>, increment: Callback, decrement: Callback } => {
|
|
22
|
-
|
|
23
|
-
const {promise, resolve} = makeNakedPromise<void> ();
|
|
24
|
-
|
|
25
|
-
let counter = 0;
|
|
26
|
-
|
|
27
|
-
const increment = (): void => {
|
|
28
|
-
|
|
29
|
-
counter += 1;
|
|
30
|
-
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const decrement = (): void => {
|
|
34
|
-
|
|
35
|
-
counter -= 1;
|
|
36
|
-
|
|
37
|
-
if ( counter ) return;
|
|
38
|
-
|
|
39
|
-
resolve ();
|
|
40
|
-
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const init = (): void => { // Accounting for no increment/decrement calls
|
|
44
|
-
|
|
45
|
-
increment ();
|
|
46
|
-
|
|
47
|
-
queueMicrotask ( decrement );
|
|
48
|
-
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
init ();
|
|
52
|
-
|
|
53
|
-
return { promise, increment, decrement };
|
|
54
|
-
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
/* EXPORT */
|
|
58
|
-
|
|
59
|
-
export {castArray, isFunction, makeCounterPromise};
|
package/test/index.js
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/* IMPORT */
|
|
3
|
-
|
|
4
|
-
import {describe} from 'fava';
|
|
5
|
-
import fs from 'node:fs';
|
|
6
|
-
import path from 'node:path';
|
|
7
|
-
import readdir from '../dist/index.js';
|
|
8
|
-
|
|
9
|
-
/* HELPERS */
|
|
10
|
-
|
|
11
|
-
const toBasename = filePath => path.basename ( filePath );
|
|
12
|
-
|
|
13
|
-
/* MAIN */
|
|
14
|
-
|
|
15
|
-
describe ( 'Tiny Readdir', it => {
|
|
16
|
-
|
|
17
|
-
it ( 'finds folders, files and symlinks', async t => {
|
|
18
|
-
|
|
19
|
-
const cwdPath = process.cwd ();
|
|
20
|
-
const root1Path = path.join ( cwdPath, 'test', 'root1' );
|
|
21
|
-
const root2Path = path.join ( cwdPath, 'test', 'root2' );
|
|
22
|
-
const folder1Path = path.join ( root1Path, 'folder1' );
|
|
23
|
-
const folder2Path = path.join ( root1Path, 'folder2' );
|
|
24
|
-
const folder1DeepPath = path.join ( folder1Path, 'deep' );
|
|
25
|
-
const file1aPath = path.join ( folder1Path, 'file1a.txt' );
|
|
26
|
-
const file1bPath = path.join ( folder1Path, 'file1b.txt' );
|
|
27
|
-
const file2Path = path.join ( folder2Path, 'file2.txt' );
|
|
28
|
-
const fileDeep1Path = path.join ( folder1DeepPath, 'file1.txt' );
|
|
29
|
-
const symlink1FromPath = path.join ( root1Path, 'symlink' );
|
|
30
|
-
const symlink1ToPath = root2Path;
|
|
31
|
-
const symlink2FromPath = path.join ( root2Path, 'symlink' );
|
|
32
|
-
const symlink2ToPath = root1Path;
|
|
33
|
-
|
|
34
|
-
fs.mkdirSync ( root1Path );
|
|
35
|
-
fs.mkdirSync ( root2Path );
|
|
36
|
-
fs.mkdirSync ( folder1Path );
|
|
37
|
-
fs.mkdirSync ( folder2Path );
|
|
38
|
-
fs.mkdirSync ( folder1DeepPath );
|
|
39
|
-
fs.writeFileSync ( file1aPath, '' );
|
|
40
|
-
fs.writeFileSync ( file1bPath, '' );
|
|
41
|
-
fs.writeFileSync ( file2Path, '' );
|
|
42
|
-
fs.writeFileSync ( fileDeep1Path, '' );
|
|
43
|
-
fs.symlinkSync ( symlink1ToPath, symlink1FromPath );
|
|
44
|
-
fs.symlinkSync ( symlink2ToPath, symlink2FromPath );
|
|
45
|
-
|
|
46
|
-
const expected = {
|
|
47
|
-
directories: [folder1Path, folder2Path, folder1DeepPath, root2Path],
|
|
48
|
-
directoriesNames: new Set ( [folder1Path, folder2Path, folder1DeepPath, root2Path].map ( toBasename ) ),
|
|
49
|
-
directoriesNamesToPaths: { folder1: [folder1Path], folder2: [folder2Path], deep: [folder1DeepPath], root2: [root2Path] },
|
|
50
|
-
files: [file1aPath, file1bPath, file2Path, fileDeep1Path],
|
|
51
|
-
filesNames: new Set ( [file1aPath, file1bPath, file2Path, fileDeep1Path].map ( toBasename ) ),
|
|
52
|
-
filesNamesToPaths: { 'file1a.txt': [file1aPath], 'file1b.txt': [file1bPath], 'file2.txt': [file2Path], 'file1.txt': [fileDeep1Path] },
|
|
53
|
-
symlinks: [symlink1FromPath, symlink2FromPath],
|
|
54
|
-
symlinksNames: new Set ( [symlink1FromPath, symlink2FromPath].map ( toBasename ) ),
|
|
55
|
-
symlinksNamesToPaths: { symlink: [symlink1FromPath, symlink2FromPath] },
|
|
56
|
-
map: {
|
|
57
|
-
[root1Path]: {
|
|
58
|
-
directories: [folder1Path, folder2Path],
|
|
59
|
-
directoriesNames: new Set ( [folder1Path, folder2Path].map ( toBasename ) ),
|
|
60
|
-
directoriesNamesToPaths: {},
|
|
61
|
-
files: [],
|
|
62
|
-
filesNames: new Set (),
|
|
63
|
-
filesNamesToPaths: {},
|
|
64
|
-
symlinks: [symlink1FromPath],
|
|
65
|
-
symlinksNames: new Set ( [symlink1FromPath].map ( toBasename ) ),
|
|
66
|
-
symlinksNamesToPaths: {}
|
|
67
|
-
},
|
|
68
|
-
[root2Path]: {
|
|
69
|
-
directories: [],
|
|
70
|
-
directoriesNames: new Set (),
|
|
71
|
-
directoriesNamesToPaths: {},
|
|
72
|
-
files: [],
|
|
73
|
-
filesNames: new Set (),
|
|
74
|
-
filesNamesToPaths: {},
|
|
75
|
-
symlinks: [symlink2FromPath],
|
|
76
|
-
symlinksNames: new Set ( [symlink2FromPath].map ( toBasename ) ),
|
|
77
|
-
symlinksNamesToPaths: {}
|
|
78
|
-
},
|
|
79
|
-
[folder1Path]: {
|
|
80
|
-
directories: [folder1DeepPath],
|
|
81
|
-
directoriesNames: new Set ( [folder1DeepPath].map ( toBasename ) ),
|
|
82
|
-
directoriesNamesToPaths: {},
|
|
83
|
-
files: [file1aPath, file1bPath],
|
|
84
|
-
filesNames: new Set ( [file1aPath, file1bPath].map ( toBasename ) ),
|
|
85
|
-
filesNamesToPaths: {},
|
|
86
|
-
symlinks: [],
|
|
87
|
-
symlinksNames: new Set (),
|
|
88
|
-
symlinksNamesToPaths: {}
|
|
89
|
-
},
|
|
90
|
-
[folder2Path]: {
|
|
91
|
-
directories: [],
|
|
92
|
-
directoriesNames: new Set (),
|
|
93
|
-
directoriesNamesToPaths: {},
|
|
94
|
-
files: [file2Path],
|
|
95
|
-
filesNames: new Set ( [file2Path].map ( toBasename ) ),
|
|
96
|
-
filesNamesToPaths: {},
|
|
97
|
-
symlinks: [],
|
|
98
|
-
symlinksNames: new Set (),
|
|
99
|
-
symlinksNamesToPaths: {}
|
|
100
|
-
},
|
|
101
|
-
[folder1DeepPath]: {
|
|
102
|
-
directories: [],
|
|
103
|
-
directoriesNames: new Set (),
|
|
104
|
-
directoriesNamesToPaths: {},
|
|
105
|
-
files: [fileDeep1Path],
|
|
106
|
-
filesNames: new Set ( [fileDeep1Path].map ( toBasename ) ),
|
|
107
|
-
filesNamesToPaths: {},
|
|
108
|
-
symlinks: [],
|
|
109
|
-
symlinksNames: new Set (),
|
|
110
|
-
symlinksNamesToPaths: {}
|
|
111
|
-
},
|
|
112
|
-
[symlink1FromPath]: {
|
|
113
|
-
directories: [root2Path],
|
|
114
|
-
directoriesNames: new Set ( [root2Path].map ( toBasename ) ),
|
|
115
|
-
directoriesNamesToPaths: {},
|
|
116
|
-
files: [],
|
|
117
|
-
filesNames: new Set (),
|
|
118
|
-
filesNamesToPaths: {},
|
|
119
|
-
symlinks: [],
|
|
120
|
-
symlinksNames: new Set (),
|
|
121
|
-
symlinksNamesToPaths: {}
|
|
122
|
-
},
|
|
123
|
-
[symlink2FromPath]: {
|
|
124
|
-
directories: [],
|
|
125
|
-
directoriesNames: new Set (),
|
|
126
|
-
directoriesNamesToPaths: {},
|
|
127
|
-
files: [],
|
|
128
|
-
filesNames: new Set (),
|
|
129
|
-
filesNamesToPaths: {},
|
|
130
|
-
symlinks: [],
|
|
131
|
-
symlinksNames: new Set (),
|
|
132
|
-
symlinksNamesToPaths: {}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
try {
|
|
138
|
-
|
|
139
|
-
const result = await readdir ( root1Path, { followSymlinks: true } );
|
|
140
|
-
|
|
141
|
-
t.deepEqual ( result, expected );
|
|
142
|
-
|
|
143
|
-
} finally {
|
|
144
|
-
|
|
145
|
-
fs.rmSync ( root1Path, { recursive: true } );
|
|
146
|
-
fs.rmSync ( root2Path, { recursive: true } );
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it ( 'supports a depth option', async t => {
|
|
153
|
-
|
|
154
|
-
const cwdPath = process.cwd ();
|
|
155
|
-
|
|
156
|
-
const {files: files0} = await readdir ( cwdPath, { depth: 0 } );
|
|
157
|
-
const {files: files1} = await readdir ( cwdPath, { depth: 1 } );
|
|
158
|
-
const {files: filesInfinity} = await readdir ( cwdPath, { depth: Infinity } );
|
|
159
|
-
|
|
160
|
-
t.true ( files0.length === 0 );
|
|
161
|
-
t.true ( files1.length > 0 && files1.length < 10 );
|
|
162
|
-
t.true ( filesInfinity.length > 100 );
|
|
163
|
-
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it ( 'supports a limit option', async t => {
|
|
167
|
-
|
|
168
|
-
const cwdPath = process.cwd ();
|
|
169
|
-
const root1Path = path.join ( cwdPath, 'test', 'root1' );
|
|
170
|
-
const root2Path = path.join ( cwdPath, 'test', 'root2' );
|
|
171
|
-
const folder1Path = path.join ( root1Path, 'folder1' );
|
|
172
|
-
const folder2Path = path.join ( root1Path, 'folder2' );
|
|
173
|
-
const folder1DeepPath = path.join ( folder1Path, 'deep' );
|
|
174
|
-
const file1aPath = path.join ( folder1Path, 'file1a.txt' );
|
|
175
|
-
const file1bPath = path.join ( folder1Path, 'file1b.txt' );
|
|
176
|
-
const file2Path = path.join ( folder2Path, 'file2.txt' );
|
|
177
|
-
const fileDeep1Path = path.join ( folder1DeepPath, 'file1.txt' );
|
|
178
|
-
const symlink1FromPath = path.join ( root1Path, 'symlink' );
|
|
179
|
-
const symlink1ToPath = root2Path;
|
|
180
|
-
const symlink2FromPath = path.join ( root2Path, 'symlink' );
|
|
181
|
-
const symlink2ToPath = root1Path;
|
|
182
|
-
|
|
183
|
-
fs.mkdirSync ( root1Path );
|
|
184
|
-
fs.mkdirSync ( root2Path );
|
|
185
|
-
fs.mkdirSync ( folder1Path );
|
|
186
|
-
fs.mkdirSync ( folder2Path );
|
|
187
|
-
fs.mkdirSync ( folder1DeepPath );
|
|
188
|
-
fs.writeFileSync ( file1aPath, '' );
|
|
189
|
-
fs.writeFileSync ( file1bPath, '' );
|
|
190
|
-
fs.writeFileSync ( file2Path, '' );
|
|
191
|
-
fs.writeFileSync ( fileDeep1Path, '' );
|
|
192
|
-
fs.symlinkSync ( symlink1ToPath, symlink1FromPath );
|
|
193
|
-
fs.symlinkSync ( symlink2ToPath, symlink2FromPath );
|
|
194
|
-
|
|
195
|
-
const expected = {
|
|
196
|
-
directories: [folder1Path, folder2Path],
|
|
197
|
-
directoriesNames: new Set ( [folder1Path, folder2Path].map ( toBasename ) ),
|
|
198
|
-
directoriesNamesToPaths: { folder1: [folder1Path], folder2: [folder2Path] },
|
|
199
|
-
files: [],
|
|
200
|
-
filesNames: new Set (),
|
|
201
|
-
filesNamesToPaths: {},
|
|
202
|
-
symlinks: [symlink1FromPath],
|
|
203
|
-
symlinksNames: new Set ( [symlink1FromPath].map ( toBasename ) ),
|
|
204
|
-
symlinksNamesToPaths: { symlink: [symlink1FromPath] },
|
|
205
|
-
map: {
|
|
206
|
-
[root1Path]: {
|
|
207
|
-
directories: [folder1Path, folder2Path],
|
|
208
|
-
directoriesNames: new Set ( [folder1Path, folder2Path].map ( toBasename ) ),
|
|
209
|
-
directoriesNamesToPaths: {},
|
|
210
|
-
files: [],
|
|
211
|
-
filesNames: new Set (),
|
|
212
|
-
filesNamesToPaths: {},
|
|
213
|
-
symlinks: [symlink1FromPath],
|
|
214
|
-
symlinksNames: new Set ( [symlink1FromPath].map ( toBasename ) ),
|
|
215
|
-
symlinksNamesToPaths: {}
|
|
216
|
-
},
|
|
217
|
-
[folder1Path]: {
|
|
218
|
-
directories: [],
|
|
219
|
-
directoriesNames: new Set (),
|
|
220
|
-
directoriesNamesToPaths: {},
|
|
221
|
-
files: [],
|
|
222
|
-
filesNames: new Set (),
|
|
223
|
-
filesNamesToPaths: {},
|
|
224
|
-
symlinks: [],
|
|
225
|
-
symlinksNames: new Set (),
|
|
226
|
-
symlinksNamesToPaths: {}
|
|
227
|
-
},
|
|
228
|
-
[folder2Path]: {
|
|
229
|
-
directories: [],
|
|
230
|
-
directoriesNames: new Set (),
|
|
231
|
-
directoriesNamesToPaths: {},
|
|
232
|
-
files: [],
|
|
233
|
-
filesNames: new Set (),
|
|
234
|
-
filesNamesToPaths: {},
|
|
235
|
-
symlinks: [],
|
|
236
|
-
symlinksNames: new Set (),
|
|
237
|
-
symlinksNamesToPaths: {}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
try {
|
|
243
|
-
|
|
244
|
-
const result = await readdir ( root1Path, { limit: 3, followSymlinks: true } );
|
|
245
|
-
|
|
246
|
-
t.deepEqual ( result, expected );
|
|
247
|
-
|
|
248
|
-
} finally {
|
|
249
|
-
|
|
250
|
-
fs.rmSync ( root1Path, { recursive: true } );
|
|
251
|
-
fs.rmSync ( root2Path, { recursive: true } );
|
|
252
|
-
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it ( 'does not freeze the main thread', async t => {
|
|
258
|
-
|
|
259
|
-
return new Promise ( resolve => {
|
|
260
|
-
|
|
261
|
-
let count = 0;
|
|
262
|
-
let start = Date.now ();
|
|
263
|
-
|
|
264
|
-
const aborter = new AbortController ();
|
|
265
|
-
const signal = aborter.signal;
|
|
266
|
-
|
|
267
|
-
const intervalId = setInterval ( () => {
|
|
268
|
-
count += 1;
|
|
269
|
-
console.log ( 'tick', count );
|
|
270
|
-
if ( count !== 100 ) return;
|
|
271
|
-
clearInterval ( intervalId );
|
|
272
|
-
const end = Date.now ();
|
|
273
|
-
const elapsed = end - start;
|
|
274
|
-
console.log ( 'elapsed', elapsed );
|
|
275
|
-
console.log ( elapsed );
|
|
276
|
-
if ( elapsed > 1500 ) {
|
|
277
|
-
t.fail ();
|
|
278
|
-
} else {
|
|
279
|
-
t.pass ();
|
|
280
|
-
}
|
|
281
|
-
aborter.abort ();
|
|
282
|
-
resolve ();
|
|
283
|
-
}, 10 );
|
|
284
|
-
|
|
285
|
-
readdir ( '/', { signal } );
|
|
286
|
-
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
});
|
package/tsconfig.json
DELETED