tiny-readdir 2.7.3 → 3.0.0

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/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Dirent, Options, ResultDirectory, ResultDirectories, Result } from './types.js';
1
+ import type { Dirent, Options, Result } from './types.js';
2
2
  declare const readdir: (rootPath: string, options?: Options) => Promise<Result>;
3
3
  export default readdir;
4
- export type { Dirent, Options, ResultDirectory, ResultDirectories, Result };
4
+ export type { Dirent, Options, Result };
package/dist/index.js CHANGED
@@ -5,7 +5,6 @@ import makeCounterPromise from 'promise-make-counter';
5
5
  import { NOOP_PROMISE_LIKE } from './constants.js';
6
6
  import { castArray, isFunction } from './utils.js';
7
7
  /* MAIN */
8
- //TODO: Streamline the type of dirmaps
9
8
  const readdir = (rootPath, options) => {
10
9
  const followSymlinks = options?.followSymlinks ?? false;
11
10
  const maxDepth = options?.depth ?? Infinity;
@@ -16,34 +15,20 @@ const readdir = (rootPath, options) => {
16
15
  const signal = options?.signal ?? { aborted: false };
17
16
  const onDirents = options?.onDirents || (() => { });
18
17
  const directories = [];
19
- const directoriesNames = new Set();
20
- const directoriesNamesToPaths = {};
21
18
  const files = [];
22
- const filesNames = new Set();
23
- const filesNamesToPaths = {};
24
19
  const symlinks = [];
25
- const symlinksNames = new Set();
26
- const symlinksNamesToPaths = {};
27
- const map = {};
28
20
  const visited = new Set();
29
- const resultEmpty = { directories: [], directoriesNames: new Set(), directoriesNamesToPaths: {}, files: [], filesNames: new Set(), filesNamesToPaths: {}, symlinks: [], symlinksNames: new Set(), symlinksNamesToPaths: {}, map: {} };
30
- const result = { directories, directoriesNames, directoriesNamesToPaths, files, filesNames, filesNamesToPaths, symlinks, symlinksNames, symlinksNamesToPaths, map };
21
+ const resultEmpty = { directories: [], files: [], symlinks: [] };
22
+ const result = { directories, files, symlinks };
31
23
  const { promise, increment, decrement } = makeCounterPromise();
32
24
  let foundPaths = 0;
33
- const handleDirectory = (dirmap, subPath, name, depth) => {
25
+ const handleDirectory = (subPath, depth) => {
34
26
  if (visited.has(subPath))
35
27
  return;
36
28
  if (foundPaths >= maxPaths)
37
29
  return;
38
30
  foundPaths += 1;
39
- dirmap.directories.push(subPath);
40
- dirmap.directoriesNames.add(name);
41
- // dirmap.directoriesNamesToPaths.propertyIsEnumerable(name) || ( dirmap.directoriesNamesToPaths[name] = [] );
42
- // dirmap.directoriesNamesToPaths[name].push ( subPath );
43
31
  directories.push(subPath);
44
- directoriesNames.add(name);
45
- directoriesNamesToPaths.propertyIsEnumerable(name) || (directoriesNamesToPaths[name] = []);
46
- directoriesNamesToPaths[name].push(subPath);
47
32
  visited.add(subPath);
48
33
  if (depth >= maxDepth)
49
34
  return;
@@ -51,36 +36,22 @@ const readdir = (rootPath, options) => {
51
36
  return;
52
37
  populateResultFromPath(subPath, depth + 1);
53
38
  };
54
- const handleFile = (dirmap, subPath, name) => {
39
+ const handleFile = (subPath) => {
55
40
  if (visited.has(subPath))
56
41
  return;
57
42
  if (foundPaths >= maxPaths)
58
43
  return;
59
44
  foundPaths += 1;
60
- dirmap.files.push(subPath);
61
- dirmap.filesNames.add(name);
62
- // dirmap.filesNamesToPaths.propertyIsEnumerable(name) || ( dirmap.filesNamesToPaths[name] = [] );
63
- // dirmap.filesNamesToPaths[name].push ( subPath );
64
45
  files.push(subPath);
65
- filesNames.add(name);
66
- filesNamesToPaths.propertyIsEnumerable(name) || (filesNamesToPaths[name] = []);
67
- filesNamesToPaths[name].push(subPath);
68
46
  visited.add(subPath);
69
47
  };
70
- const handleSymlink = (dirmap, subPath, name, depth) => {
48
+ const handleSymlink = (subPath, depth) => {
71
49
  if (visited.has(subPath))
72
50
  return;
73
51
  if (foundPaths >= maxPaths)
74
52
  return;
75
53
  foundPaths += 1;
76
- dirmap.symlinks.push(subPath);
77
- dirmap.symlinksNames.add(name);
78
- // dirmap.symlinksNamesToPaths.propertyIsEnumerable(name) || ( dirmap.symlinksNamesToPaths[name] = [] );
79
- // dirmap.symlinksNamesToPaths[name].push ( subPath );
80
54
  symlinks.push(subPath);
81
- symlinksNames.add(name);
82
- symlinksNamesToPaths.propertyIsEnumerable(name) || (symlinksNamesToPaths[name] = []);
83
- symlinksNamesToPaths[name].push(subPath);
84
55
  visited.add(subPath);
85
56
  if (!followSymlinks)
86
57
  return;
@@ -90,22 +61,22 @@ const readdir = (rootPath, options) => {
90
61
  return;
91
62
  populateResultFromSymlink(subPath, depth + 1);
92
63
  };
93
- const handleStat = (dirmap, rootPath, name, stat, depth) => {
64
+ const handleStat = (rootPath, stat, depth) => {
94
65
  if (signal.aborted)
95
66
  return;
96
67
  if (isIgnored(rootPath))
97
68
  return;
98
69
  if (stat.isDirectory()) {
99
- handleDirectory(dirmap, rootPath, name, depth);
70
+ handleDirectory(rootPath, depth);
100
71
  }
101
72
  else if (stat.isFile()) {
102
- handleFile(dirmap, rootPath, name);
73
+ handleFile(rootPath);
103
74
  }
104
75
  else if (stat.isSymbolicLink()) {
105
- handleSymlink(dirmap, rootPath, name, depth);
76
+ handleSymlink(rootPath, depth);
106
77
  }
107
78
  };
108
- const handleDirent = (dirmap, rootPath, dirent, depth) => {
79
+ const handleDirent = (rootPath, dirent, depth) => {
109
80
  if (signal.aborted)
110
81
  return;
111
82
  const separator = (rootPath === path.sep) ? '' : path.sep;
@@ -114,18 +85,18 @@ const readdir = (rootPath, options) => {
114
85
  if (isIgnored(subPath))
115
86
  return;
116
87
  if (dirent.isDirectory()) {
117
- handleDirectory(dirmap, subPath, name, depth);
88
+ handleDirectory(subPath, depth);
118
89
  }
119
90
  else if (dirent.isFile()) {
120
- handleFile(dirmap, subPath, name);
91
+ handleFile(subPath);
121
92
  }
122
93
  else if (dirent.isSymbolicLink()) {
123
- handleSymlink(dirmap, subPath, name, depth);
94
+ handleSymlink(subPath, depth);
124
95
  }
125
96
  };
126
- const handleDirents = (dirmap, rootPath, dirents, depth) => {
97
+ const handleDirents = (rootPath, dirents, depth) => {
127
98
  for (let i = 0, l = dirents.length; i < l; i++) {
128
- handleDirent(dirmap, rootPath, dirents[i], depth);
99
+ handleDirent(rootPath, dirents[i], depth);
129
100
  }
130
101
  };
131
102
  const populateResultFromPath = (rootPath, depth) => {
@@ -145,8 +116,7 @@ const readdir = (rootPath, options) => {
145
116
  return decrement();
146
117
  const promise = onDirents(dirents) || NOOP_PROMISE_LIKE;
147
118
  promise.then(() => {
148
- const dirmap = map[rootPath] = { directories: [], directoriesNames: new Set(), directoriesNamesToPaths: {}, files: [], filesNames: new Set(), filesNamesToPaths: {}, symlinks: [], symlinksNames: new Set(), symlinksNamesToPaths: {} };
149
- handleDirents(dirmap, rootPath, dirents, depth);
119
+ handleDirents(rootPath, dirents, depth);
150
120
  decrement();
151
121
  });
152
122
  });
@@ -163,14 +133,12 @@ const readdir = (rootPath, options) => {
163
133
  return decrement();
164
134
  if (signal.aborted)
165
135
  return decrement();
166
- const name = path.basename(realPath);
167
- const dirmap = map[rootPath] = { directories: [], directoriesNames: new Set(), directoriesNamesToPaths: {}, files: [], filesNames: new Set(), filesNamesToPaths: {}, symlinks: [], symlinksNames: new Set(), symlinksNamesToPaths: {} };
168
- handleStat(dirmap, realPath, name, stat, depth);
136
+ handleStat(realPath, stat, depth);
169
137
  decrement();
170
138
  });
171
139
  });
172
140
  };
173
- const getResult = async (rootPath, depth = 1) => {
141
+ const populateResultFromRoot = async (rootPath, depth = 1) => {
174
142
  rootPath = path.normalize(rootPath);
175
143
  visited.add(rootPath);
176
144
  populateResultFromPath(rootPath, depth);
@@ -179,7 +147,7 @@ const readdir = (rootPath, options) => {
179
147
  return resultEmpty;
180
148
  return result;
181
149
  };
182
- return getResult(rootPath);
150
+ return populateResultFromRoot(rootPath);
183
151
  };
184
152
  /* EXPORT */
185
153
  export default readdir;
package/dist/types.d.ts CHANGED
@@ -22,21 +22,9 @@ type Options = {
22
22
  };
23
23
  onDirents?: (dirents: Dirent[]) => PromiseMaybe<undefined>;
24
24
  };
25
- type ResultDirectory = {
25
+ type Result = {
26
26
  directories: string[];
27
- directoriesNames: Set<string>;
28
- directoriesNamesToPaths: Record<string, string[]>;
29
27
  files: string[];
30
- filesNames: Set<string>;
31
- filesNamesToPaths: Record<string, string[]>;
32
28
  symlinks: string[];
33
- symlinksNames: Set<string>;
34
- symlinksNamesToPaths: Record<string, string[]>;
35
29
  };
36
- type ResultDirectories = {
37
- [path: string]: ResultDirectory;
38
- };
39
- type Result = ResultDirectory & {
40
- map: ResultDirectories;
41
- };
42
- export type { Callback, PromiseMaybe, Dirent, Options, ResultDirectory, ResultDirectories, Result };
30
+ export type { Callback, PromiseMaybe, Dirent, Options, Result };
package/package.json CHANGED
@@ -2,18 +2,22 @@
2
2
  "name": "tiny-readdir",
3
3
  "repository": "github:fabiospampinato/tiny-readdir",
4
4
  "description": "A simple promisified recursive readdir function.",
5
- "version": "2.7.3",
5
+ "license": "MIT",
6
+ "version": "3.0.0",
6
7
  "type": "module",
7
8
  "main": "dist/index.js",
8
9
  "exports": "./dist/index.js",
9
10
  "types": "./dist/index.d.ts",
10
11
  "scripts": {
12
+ "benchmark": "tsex benchmark",
13
+ "benchmark:watch": "tsex benchmark --watch",
14
+ "benchmark:prepare": "cd tasks && git clone https://github.com/babel/babel.git",
11
15
  "clean": "tsex clean",
12
16
  "compile": "tsex compile",
13
17
  "compile:watch": "tsex compile --watch",
14
- "test": "tsex test",
18
+ "test": "node test/index.js",
15
19
  "test:watch": "tsex test --watch",
16
- "prepublishOnly": "tsex prepare"
20
+ "prepublishOnly": "npm run compile && npm run test"
17
21
  },
18
22
  "keywords": [
19
23
  "readdir",
@@ -23,12 +27,13 @@
23
27
  "tiny"
24
28
  ],
25
29
  "dependencies": {
26
- "promise-make-counter": "^1.0.1"
30
+ "promise-make-counter": "^1.0.2"
27
31
  },
28
32
  "devDependencies": {
29
- "@types/node": "^18.19.39",
30
- "fava": "^0.3.4",
33
+ "@types/node": "^18.19.130",
34
+ "benchloop": "^2.1.1",
35
+ "fava": "^0.3.5",
31
36
  "tsex": "^4.0.2",
32
- "typescript": "^5.5.2"
37
+ "typescript": "^5.9.3"
33
38
  }
34
39
  }
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 --save tiny-readdir
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
- const aborter = new AbortController ();
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,15 @@ 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
- result.directories; // => Array of absolute paths pointing to directories
28
- result.files; // => Array of absolute paths pointing to files
29
- result.symlinks; // => Array of absolute paths pointing to symlinks
28
+ // This is how we would abort the reactive read after 10s
30
29
 
31
- result.directoriesNames; // => Set of directories names found
32
- result.filesNames; // => Set of files name found
33
- result.symlinksNames; // => Set of symlinks names found
30
+ setTimeout ( () => aborter.abort (), 10_000 ); // Aborting if it's going to take longer than 10s
34
31
 
35
- result.directoriesNamesToPaths; // => Record of directories names found to their paths
36
- result.filesNamesToPaths; // => Record of files names found to their paths
37
- result.symlinksNamesToPaths; // => Record of symlinks names found to their paths
32
+ // This is the result object will look like
38
33
 
39
- setTimeout ( () => aborter.abort (), 10_000 ); // Aborting if it's going to take longer than 10s
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
40
37
  ```
41
38
 
42
39
  ## License
package/.editorconfig DELETED
@@ -1,10 +0,0 @@
1
-
2
- root = true
3
-
4
- [*]
5
- charset = utf-8
6
- end_of_line = lf
7
- indent_size = 2
8
- indent_style = space
9
- insert_final_newline = true
10
- trim_trailing_whitespace = true
package/src/constants.ts DELETED
@@ -1,16 +0,0 @@
1
-
2
- /* IMPORT */
3
-
4
- import type {Callback} from './types';
5
-
6
- /* MAIN */
7
-
8
- const NOOP_PROMISE_LIKE = {
9
- then: ( fn: Callback ) => {
10
- fn ();
11
- }
12
- };
13
-
14
- /* EXPORT */
15
-
16
- export {NOOP_PROMISE_LIKE};
package/src/index.ts DELETED
@@ -1,257 +0,0 @@
1
-
2
- /* IMPORT */
3
-
4
- import fs from 'node:fs';
5
- import path from 'node:path';
6
- import makeCounterPromise from 'promise-make-counter';
7
- import {NOOP_PROMISE_LIKE} from './constants';
8
- import {castArray, isFunction} from './utils';
9
- import type {Dirent, Options, ResultDirectory, ResultDirectories, Result} from './types';
10
-
11
- /* MAIN */
12
-
13
- //TODO: Streamline the type of dirmaps
14
-
15
- const readdir = ( rootPath: string, options?: Options ): Promise<Result> => {
16
-
17
- const followSymlinks = options?.followSymlinks ?? false;
18
- const maxDepth = options?.depth ?? Infinity;
19
- const maxPaths = options?.limit ?? Infinity;
20
- const ignore = options?.ignore ?? [];
21
- const ignores = castArray ( ignore ).map ( ignore => isFunction ( ignore ) ? ignore : ( targetPath: string ) => ignore.test ( targetPath ) );
22
- const isIgnored = ( targetPath: string ) => ignores.some ( ignore => ignore ( targetPath ) );
23
- const signal = options?.signal ?? { aborted: false };
24
- const onDirents = options?.onDirents || (() => {});
25
- const directories: string[] = [];
26
- const directoriesNames: Set<string> = new Set ();
27
- const directoriesNamesToPaths: Record<string, string[]> = {};
28
- const files: string[] = [];
29
- const filesNames: Set<string> = new Set ();
30
- const filesNamesToPaths: Record<string, string[]> = {};
31
- const symlinks: string[] = [];
32
- const symlinksNames: Set<string> = new Set ();
33
- const symlinksNamesToPaths: Record<string, string[]> = {};
34
- const map: ResultDirectories = {};
35
- const visited = new Set<string> ();
36
- const resultEmpty: Result = { directories: [], directoriesNames: new Set (), directoriesNamesToPaths: {}, files: [], filesNames: new Set (), filesNamesToPaths: {}, symlinks: [], symlinksNames: new Set (), symlinksNamesToPaths: {}, map: {} };
37
- const result: Result = { directories, directoriesNames, directoriesNamesToPaths, files, filesNames, filesNamesToPaths, symlinks, symlinksNames, symlinksNamesToPaths, map };
38
- const {promise, increment, decrement} = makeCounterPromise ();
39
-
40
- let foundPaths = 0;
41
-
42
- const handleDirectory = ( dirmap: ResultDirectory, subPath: string, name: string, depth: number ): void => {
43
-
44
- if ( visited.has ( subPath ) ) return;
45
-
46
- if ( foundPaths >= maxPaths ) return;
47
-
48
- foundPaths += 1;
49
- dirmap.directories.push ( subPath );
50
- dirmap.directoriesNames.add ( name );
51
- // dirmap.directoriesNamesToPaths.propertyIsEnumerable(name) || ( dirmap.directoriesNamesToPaths[name] = [] );
52
- // dirmap.directoriesNamesToPaths[name].push ( subPath );
53
- directories.push ( subPath );
54
- directoriesNames.add ( name );
55
- directoriesNamesToPaths.propertyIsEnumerable(name) || ( directoriesNamesToPaths[name] = [] );
56
- directoriesNamesToPaths[name].push ( subPath );
57
- visited.add ( subPath );
58
-
59
- if ( depth >= maxDepth ) return;
60
-
61
- if ( foundPaths >= maxPaths ) return;
62
-
63
- populateResultFromPath ( subPath, depth + 1 );
64
-
65
- };
66
-
67
- const handleFile = ( dirmap: ResultDirectory, subPath: string, name: string ): void => {
68
-
69
- if ( visited.has ( subPath ) ) return;
70
-
71
- if ( foundPaths >= maxPaths ) return;
72
-
73
- foundPaths += 1;
74
- dirmap.files.push ( subPath );
75
- dirmap.filesNames.add ( name );
76
- // dirmap.filesNamesToPaths.propertyIsEnumerable(name) || ( dirmap.filesNamesToPaths[name] = [] );
77
- // dirmap.filesNamesToPaths[name].push ( subPath );
78
- files.push ( subPath );
79
- filesNames.add ( name );
80
- filesNamesToPaths.propertyIsEnumerable(name) || ( filesNamesToPaths[name] = [] );
81
- filesNamesToPaths[name].push ( subPath );
82
- visited.add ( subPath );
83
-
84
- };
85
-
86
- const handleSymlink = ( dirmap: ResultDirectory, subPath: string, name: string, depth: number ): void => {
87
-
88
- if ( visited.has ( subPath ) ) return;
89
-
90
- if ( foundPaths >= maxPaths ) return;
91
-
92
- foundPaths += 1;
93
- dirmap.symlinks.push ( subPath );
94
- dirmap.symlinksNames.add ( name );
95
- // dirmap.symlinksNamesToPaths.propertyIsEnumerable(name) || ( dirmap.symlinksNamesToPaths[name] = [] );
96
- // dirmap.symlinksNamesToPaths[name].push ( subPath );
97
- symlinks.push ( subPath );
98
- symlinksNames.add ( name );
99
- symlinksNamesToPaths.propertyIsEnumerable(name) || ( symlinksNamesToPaths[name] = [] );
100
- symlinksNamesToPaths[name].push ( subPath );
101
- visited.add ( subPath );
102
-
103
- if ( !followSymlinks ) return;
104
-
105
- if ( depth >= maxDepth ) return;
106
-
107
- if ( foundPaths >= maxPaths ) return;
108
-
109
- populateResultFromSymlink ( subPath, depth + 1 );
110
-
111
- };
112
-
113
- const handleStat = ( dirmap: ResultDirectory, rootPath: string, name: string, stat: fs.Stats, depth: number ): void => {
114
-
115
- if ( signal.aborted ) return;
116
-
117
- if ( isIgnored ( rootPath ) ) return;
118
-
119
- if ( stat.isDirectory () ) {
120
-
121
- handleDirectory ( dirmap, rootPath, name, depth );
122
-
123
- } else if ( stat.isFile () ) {
124
-
125
- handleFile ( dirmap, rootPath, name );
126
-
127
- } else if ( stat.isSymbolicLink () ) {
128
-
129
- handleSymlink ( dirmap, rootPath, name, depth );
130
-
131
- }
132
-
133
- };
134
-
135
- const handleDirent = ( dirmap: ResultDirectory, rootPath: string, dirent: fs.Dirent, depth: number ): void => {
136
-
137
- if ( signal.aborted ) return;
138
-
139
- const separator = ( rootPath === path.sep ) ? '' : path.sep;
140
- const name = dirent.name;
141
- const subPath = `${rootPath}${separator}${name}`;
142
-
143
- if ( isIgnored ( subPath ) ) return;
144
-
145
- if ( dirent.isDirectory () ) {
146
-
147
- handleDirectory ( dirmap, subPath, name, depth );
148
-
149
- } else if ( dirent.isFile () ) {
150
-
151
- handleFile ( dirmap, subPath, name );
152
-
153
- } else if ( dirent.isSymbolicLink () ) {
154
-
155
- handleSymlink ( dirmap, subPath, name, depth );
156
-
157
- }
158
-
159
- };
160
-
161
- const handleDirents = ( dirmap: ResultDirectory, rootPath: string, dirents: fs.Dirent[], depth: number ): void => {
162
-
163
- for ( let i = 0, l = dirents.length; i < l; i++ ) {
164
-
165
- handleDirent ( dirmap, rootPath, dirents[i], depth );
166
-
167
- }
168
-
169
- };
170
-
171
- const populateResultFromPath = ( rootPath: string, depth: number ): void => {
172
-
173
- if ( signal.aborted ) return;
174
-
175
- if ( depth > maxDepth ) return;
176
-
177
- if ( foundPaths >= maxPaths ) return;
178
-
179
- increment ();
180
-
181
- fs.readdir ( rootPath, { withFileTypes: true }, ( error, dirents ) => {
182
-
183
- if ( error ) return decrement ();
184
-
185
- if ( signal.aborted ) return decrement ();
186
-
187
- if ( !dirents.length ) return decrement ();
188
-
189
- const promise = onDirents ( dirents ) || NOOP_PROMISE_LIKE;
190
-
191
- promise.then ( () => {
192
-
193
- const dirmap = map[rootPath] = { directories: [], directoriesNames: new Set (), directoriesNamesToPaths: {}, files: [], filesNames: new Set (), filesNamesToPaths: {}, symlinks: [], symlinksNames: new Set (), symlinksNamesToPaths: {} };
194
-
195
- handleDirents ( dirmap, rootPath, dirents, depth );
196
-
197
- decrement ();
198
-
199
- });
200
-
201
- });
202
-
203
- };
204
-
205
- const populateResultFromSymlink = ( rootPath: string, depth: number ): void => {
206
-
207
- increment ();
208
-
209
- fs.realpath ( rootPath, ( error, realPath ) => {
210
-
211
- if ( error ) return decrement ();
212
-
213
- if ( signal.aborted ) return decrement ();
214
-
215
- fs.stat ( realPath, ( error, stat ) => {
216
-
217
- if ( error ) return decrement ();
218
-
219
- if ( signal.aborted ) return decrement ();
220
-
221
- const name = path.basename ( realPath );
222
- const dirmap = map[rootPath] = { directories: [], directoriesNames: new Set (), directoriesNamesToPaths: {}, files: [], filesNames: new Set (), filesNamesToPaths: {}, symlinks: [], symlinksNames: new Set (), symlinksNamesToPaths: {} };
223
-
224
- handleStat ( dirmap, realPath, name, stat, depth );
225
-
226
- decrement ();
227
-
228
- });
229
-
230
- });
231
-
232
- };
233
-
234
- const getResult = async ( rootPath: string, depth: number = 1 ): Promise<Result> => {
235
-
236
- rootPath = path.normalize ( rootPath );
237
-
238
- visited.add ( rootPath );
239
-
240
- populateResultFromPath ( rootPath, depth );
241
-
242
- await promise;
243
-
244
- if ( signal.aborted ) return resultEmpty;
245
-
246
- return result;
247
-
248
- };
249
-
250
- return getResult ( rootPath );
251
-
252
- };
253
-
254
- /* EXPORT */
255
-
256
- export default readdir;
257
- 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,18 +0,0 @@
1
-
2
- /* MAIN */
3
-
4
- const castArray = <T> ( value: T[] | T ): T[] => {
5
-
6
- return Array.isArray ( value ) ? value : [value];
7
-
8
- };
9
-
10
- const isFunction = ( value: unknown ): value is Function => {
11
-
12
- return ( typeof value === 'function' );
13
-
14
- };
15
-
16
- /* EXPORT */
17
-
18
- export {castArray, isFunction};
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
@@ -1,3 +0,0 @@
1
- {
2
- "extends": "tsex/tsconfig.json"
3
- }