tiny-readdir 1.5.0 → 2.1.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/.editorconfig +0 -3
- package/dist/index.d.ts +3 -9
- package/dist/index.js +50 -17
- package/dist/types.d.ts +7 -6
- package/dist/types.js +1 -2
- package/{LICENSE → license} +0 -0
- package/package.json +16 -28
- package/{README.md → readme.md} +1 -0
- package/src/index.ts +51 -25
- package/src/types.ts +4 -3
- package/test/native.js +167 -0
- package/test/yielding.js +35 -0
- package/tsconfig.json +1 -26
package/.editorconfig
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { Options, Result } from './types';
|
|
2
|
-
declare const readdir: (rootPath: string, options?: Options
|
|
3
|
-
|
|
4
|
-
default: typeof readdir;
|
|
5
|
-
}
|
|
6
|
-
declare namespace _default {
|
|
7
|
-
export type type = readdir;
|
|
8
|
-
}
|
|
9
|
-
export = _default;
|
|
1
|
+
import type { Options, Result } from './types';
|
|
2
|
+
declare const readdir: (rootPath: string, options?: Options) => Promise<Result>;
|
|
3
|
+
export default readdir;
|
package/dist/index.js
CHANGED
|
@@ -1,33 +1,62 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/* IMPORT */
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/* HELPERS */
|
|
7
|
-
const limiter = new promise_concurrency_limiter_1.default({ concurrency: 500 });
|
|
8
|
-
/* TINY READDIR */
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
/* MAIN */
|
|
9
5
|
const readdir = (rootPath, options) => {
|
|
10
|
-
|
|
11
|
-
const
|
|
6
|
+
const followSymlinks = options?.followSymlinks ?? false;
|
|
7
|
+
const maxDepth = options?.depth ?? Infinity;
|
|
8
|
+
const maxPaths = options?.limit ?? Infinity;
|
|
9
|
+
const isIgnored = options?.ignore ?? (() => false);
|
|
10
|
+
const signal = options?.signal ?? { aborted: false };
|
|
11
|
+
const directories = [];
|
|
12
|
+
const files = [];
|
|
13
|
+
const symlinks = [];
|
|
14
|
+
const map = {};
|
|
15
|
+
const visited = new Set();
|
|
16
|
+
const resultEmpty = { directories: [], files: [], symlinks: [], map: {} };
|
|
17
|
+
const result = { directories, files, symlinks, map };
|
|
18
|
+
let foundPaths = 0;
|
|
12
19
|
const handleDirectory = (dirmap, subPath, depth) => {
|
|
20
|
+
if (visited.has(subPath))
|
|
21
|
+
return;
|
|
22
|
+
if (foundPaths >= maxPaths)
|
|
23
|
+
return;
|
|
24
|
+
foundPaths += 1;
|
|
13
25
|
dirmap.directories.push(subPath);
|
|
14
26
|
directories.push(subPath);
|
|
27
|
+
visited.add(subPath);
|
|
15
28
|
if (depth >= maxDepth)
|
|
16
29
|
return;
|
|
17
|
-
|
|
30
|
+
if (foundPaths >= maxPaths)
|
|
31
|
+
return;
|
|
32
|
+
return populateResultFromPath(subPath, depth + 1);
|
|
18
33
|
};
|
|
19
34
|
const handleFile = (dirmap, subPath) => {
|
|
35
|
+
if (visited.has(subPath))
|
|
36
|
+
return;
|
|
37
|
+
if (foundPaths >= maxPaths)
|
|
38
|
+
return;
|
|
39
|
+
foundPaths += 1;
|
|
20
40
|
dirmap.files.push(subPath);
|
|
21
41
|
files.push(subPath);
|
|
42
|
+
visited.add(subPath);
|
|
22
43
|
};
|
|
23
44
|
const handleSymlink = (dirmap, subPath, depth) => {
|
|
45
|
+
if (visited.has(subPath))
|
|
46
|
+
return;
|
|
47
|
+
if (foundPaths >= maxPaths)
|
|
48
|
+
return;
|
|
49
|
+
foundPaths += 1;
|
|
24
50
|
dirmap.symlinks.push(subPath);
|
|
25
51
|
symlinks.push(subPath);
|
|
52
|
+
visited.add(subPath);
|
|
26
53
|
if (!followSymlinks)
|
|
27
54
|
return;
|
|
28
55
|
if (depth >= maxDepth)
|
|
29
56
|
return;
|
|
30
|
-
|
|
57
|
+
if (foundPaths >= maxPaths)
|
|
58
|
+
return;
|
|
59
|
+
return populateResultFromSymlink(subPath, depth + 1);
|
|
31
60
|
};
|
|
32
61
|
const handleStat = (dirmap, rootPath, stat, depth) => {
|
|
33
62
|
if (signal.aborted)
|
|
@@ -47,7 +76,8 @@ const readdir = (rootPath, options) => {
|
|
|
47
76
|
const handleDirent = (dirmap, rootPath, dirent, depth) => {
|
|
48
77
|
if (signal.aborted)
|
|
49
78
|
return;
|
|
50
|
-
const
|
|
79
|
+
const separator = (rootPath === path.sep) ? '' : path.sep;
|
|
80
|
+
const subPath = `${rootPath}${separator}${dirent.name}`;
|
|
51
81
|
if (isIgnored(subPath))
|
|
52
82
|
return;
|
|
53
83
|
if (dirent.isDirectory()) {
|
|
@@ -70,6 +100,8 @@ const readdir = (rootPath, options) => {
|
|
|
70
100
|
return;
|
|
71
101
|
if (depth > maxDepth)
|
|
72
102
|
return;
|
|
103
|
+
if (foundPaths >= maxPaths)
|
|
104
|
+
return;
|
|
73
105
|
const dirents = await fs.promises.readdir(rootPath, { withFileTypes: true }).catch(() => []);
|
|
74
106
|
if (signal.aborted)
|
|
75
107
|
return;
|
|
@@ -80,13 +112,16 @@ const readdir = (rootPath, options) => {
|
|
|
80
112
|
};
|
|
81
113
|
const populateResultFromSymlink = async (rootPath, depth) => {
|
|
82
114
|
try {
|
|
83
|
-
const realPath = await fs.promises.realpath(rootPath)
|
|
115
|
+
const realPath = await fs.promises.realpath(rootPath);
|
|
116
|
+
const stat = await fs.promises.stat(realPath);
|
|
117
|
+
const dirmap = map[rootPath] = { directories: [], files: [], symlinks: [] };
|
|
84
118
|
await handleStat(dirmap, realPath, stat, depth);
|
|
85
119
|
}
|
|
86
|
-
catch
|
|
120
|
+
catch { }
|
|
87
121
|
};
|
|
88
122
|
const getResult = async (rootPath, depth = 1) => {
|
|
89
123
|
rootPath = path.normalize(rootPath);
|
|
124
|
+
visited.add(rootPath);
|
|
90
125
|
await populateResultFromPath(rootPath, depth);
|
|
91
126
|
if (signal.aborted)
|
|
92
127
|
return resultEmpty;
|
|
@@ -95,6 +130,4 @@ const readdir = (rootPath, options) => {
|
|
|
95
130
|
return getResult(rootPath);
|
|
96
131
|
};
|
|
97
132
|
/* EXPORT */
|
|
98
|
-
|
|
99
|
-
module.exports.default = readdir;
|
|
100
|
-
Object.defineProperty(module.exports, "__esModule", { value: true });
|
|
133
|
+
export default readdir;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
type Promisable<T> = Promise<T> | T;
|
|
2
|
+
type Options = {
|
|
3
3
|
depth?: number;
|
|
4
|
+
limit?: number;
|
|
4
5
|
followSymlinks?: boolean;
|
|
5
6
|
ignore?: (targetPath: string) => boolean;
|
|
6
7
|
signal?: {
|
|
7
8
|
aborted: boolean;
|
|
8
9
|
};
|
|
9
10
|
};
|
|
10
|
-
|
|
11
|
+
type ResultDirectory = {
|
|
11
12
|
directories: string[];
|
|
12
13
|
files: string[];
|
|
13
14
|
symlinks: string[];
|
|
14
15
|
};
|
|
15
|
-
|
|
16
|
+
type ResultDirectories = {
|
|
16
17
|
[path: string]: ResultDirectory;
|
|
17
18
|
};
|
|
18
|
-
|
|
19
|
+
type Result = ResultDirectory & {
|
|
19
20
|
map: ResultDirectories;
|
|
20
21
|
};
|
|
21
|
-
export { Promisable, Options, ResultDirectory, ResultDirectories, Result };
|
|
22
|
+
export type { Promisable, Options, ResultDirectory, ResultDirectories, Result };
|
package/dist/types.js
CHANGED
package/{LICENSE → license}
RENAMED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,26 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tiny-readdir",
|
|
3
|
+
"repository": "github:fabiospampinato/tiny-readdir",
|
|
3
4
|
"description": "A simple promisified recursive readdir function.",
|
|
4
|
-
"version": "1.
|
|
5
|
+
"version": "2.1.0",
|
|
6
|
+
"type": "module",
|
|
5
7
|
"main": "dist/index.js",
|
|
6
|
-
"
|
|
8
|
+
"exports": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
7
10
|
"scripts": {
|
|
8
|
-
"clean": "
|
|
9
|
-
"compile": "
|
|
10
|
-
"compile:watch": "
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
},
|
|
16
|
-
"license": "MIT",
|
|
17
|
-
"author": {
|
|
18
|
-
"name": "Fabio Spampinato",
|
|
19
|
-
"email": "spampinabio@gmail.com"
|
|
20
|
-
},
|
|
21
|
-
"repository": {
|
|
22
|
-
"type": "git",
|
|
23
|
-
"url": "https://github.com/fabiospampinato/tiny-readdir.git"
|
|
11
|
+
"clean": "tsex clean",
|
|
12
|
+
"compile": "tsex compile",
|
|
13
|
+
"compile:watch": "tsex compile --watch",
|
|
14
|
+
"test": "npm run test:native && npm run test:yielding",
|
|
15
|
+
"test:native": "fava '**/native.js'",
|
|
16
|
+
"test:yielding": "node test/yielding.js",
|
|
17
|
+
"prepublishOnly": "npm run clean && npm run compile && npm run test"
|
|
24
18
|
},
|
|
25
19
|
"keywords": [
|
|
26
20
|
"readdir",
|
|
@@ -29,16 +23,10 @@
|
|
|
29
23
|
"simple",
|
|
30
24
|
"tiny"
|
|
31
25
|
],
|
|
32
|
-
"engines": {
|
|
33
|
-
"node": ">= 10.12.0"
|
|
34
|
-
},
|
|
35
|
-
"dependencies": {
|
|
36
|
-
"promise-concurrency-limiter": "^1.0.0"
|
|
37
|
-
},
|
|
38
26
|
"devDependencies": {
|
|
39
|
-
"@types/node": "^
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"typescript
|
|
27
|
+
"@types/node": "^18.11.9",
|
|
28
|
+
"fava": "^0.0.7",
|
|
29
|
+
"tsex": "^1.1.3",
|
|
30
|
+
"typescript": "^4.9.3"
|
|
43
31
|
}
|
|
44
32
|
}
|
package/{README.md → readme.md}
RENAMED
|
@@ -17,6 +17,7 @@ const aborter = new AbortController ();
|
|
|
17
17
|
|
|
18
18
|
const result = await readdir ( '/foo/bar', {
|
|
19
19
|
depth: 20, // Maximum depth to look at
|
|
20
|
+
limit: 1_000_000, // Maximum number of files explored, useful as a stop gap in some edge cases
|
|
20
21
|
followSymlinks: true, // Whether to follow symlinks or not
|
|
21
22
|
ignore: targetPath => /node_modules/.test ( targetPath ), // Function that if returns true will ignore this particular file or a directory and its descendants
|
|
22
23
|
signal: aborter.signal // Optional abort signal, useful for aborting potentially expensive operations
|
package/src/index.ts
CHANGED
|
@@ -1,58 +1,79 @@
|
|
|
1
1
|
|
|
2
2
|
/* IMPORT */
|
|
3
3
|
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {Promisable, Options, ResultDirectory, ResultDirectories, Result} from './types';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import type {Promisable, Options, ResultDirectory, ResultDirectories, Result} from './types';
|
|
8
7
|
|
|
9
|
-
/*
|
|
10
|
-
|
|
11
|
-
const limiter = new Limiter ({ concurrency: 500 });
|
|
12
|
-
|
|
13
|
-
/* TINY READDIR */
|
|
8
|
+
/* MAIN */
|
|
14
9
|
|
|
15
10
|
const readdir = ( rootPath: string, options?: Options ): Promise<Result> => {
|
|
16
11
|
|
|
17
|
-
const followSymlinks = options?.followSymlinks ?? false
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
12
|
+
const followSymlinks = options?.followSymlinks ?? false;
|
|
13
|
+
const maxDepth = options?.depth ?? Infinity;
|
|
14
|
+
const maxPaths = options?.limit ?? Infinity;
|
|
15
|
+
const isIgnored = options?.ignore ?? (() => false);
|
|
16
|
+
const signal = options?.signal ?? { aborted: false };
|
|
17
|
+
const directories: string[] = [];
|
|
18
|
+
const files: string[] = [];
|
|
19
|
+
const symlinks: string[] = [];
|
|
20
|
+
const map: ResultDirectories = {};
|
|
21
|
+
const visited = new Set<string> ();
|
|
22
|
+
const resultEmpty: Result = { directories: [], files: [], symlinks: [], map: {} };
|
|
23
|
+
const result: Result = { directories, files, symlinks, map };
|
|
24
|
+
|
|
25
|
+
let foundPaths = 0;
|
|
27
26
|
|
|
28
27
|
const handleDirectory = ( dirmap: ResultDirectory, subPath: string, depth: number ): Promisable<void> => {
|
|
29
28
|
|
|
29
|
+
if ( visited.has ( subPath ) ) return;
|
|
30
|
+
|
|
31
|
+
if ( foundPaths >= maxPaths ) return;
|
|
32
|
+
|
|
33
|
+
foundPaths += 1;
|
|
30
34
|
dirmap.directories.push ( subPath );
|
|
31
35
|
directories.push ( subPath );
|
|
36
|
+
visited.add ( subPath );
|
|
32
37
|
|
|
33
38
|
if ( depth >= maxDepth ) return;
|
|
34
39
|
|
|
35
|
-
|
|
40
|
+
if ( foundPaths >= maxPaths ) return;
|
|
41
|
+
|
|
42
|
+
return populateResultFromPath ( subPath, depth + 1 );
|
|
36
43
|
|
|
37
44
|
};
|
|
38
45
|
|
|
39
46
|
const handleFile = ( dirmap: ResultDirectory, subPath: string ): void => {
|
|
40
47
|
|
|
48
|
+
if ( visited.has ( subPath ) ) return;
|
|
49
|
+
|
|
50
|
+
if ( foundPaths >= maxPaths ) return;
|
|
51
|
+
|
|
52
|
+
foundPaths += 1;
|
|
41
53
|
dirmap.files.push ( subPath );
|
|
42
54
|
files.push ( subPath );
|
|
55
|
+
visited.add ( subPath );
|
|
43
56
|
|
|
44
57
|
};
|
|
45
58
|
|
|
46
59
|
const handleSymlink = ( dirmap: ResultDirectory, subPath: string, depth: number ): Promisable<void> => {
|
|
47
60
|
|
|
61
|
+
if ( visited.has ( subPath ) ) return;
|
|
62
|
+
|
|
63
|
+
if ( foundPaths >= maxPaths ) return;
|
|
64
|
+
|
|
65
|
+
foundPaths += 1;
|
|
48
66
|
dirmap.symlinks.push ( subPath );
|
|
49
67
|
symlinks.push ( subPath );
|
|
68
|
+
visited.add ( subPath );
|
|
50
69
|
|
|
51
70
|
if ( !followSymlinks ) return;
|
|
52
71
|
|
|
53
72
|
if ( depth >= maxDepth ) return;
|
|
54
73
|
|
|
55
|
-
|
|
74
|
+
if ( foundPaths >= maxPaths ) return;
|
|
75
|
+
|
|
76
|
+
return populateResultFromSymlink ( subPath, depth + 1 );
|
|
56
77
|
|
|
57
78
|
};
|
|
58
79
|
|
|
@@ -82,7 +103,8 @@ const readdir = ( rootPath: string, options?: Options ): Promise<Result> => {
|
|
|
82
103
|
|
|
83
104
|
if ( signal.aborted ) return;
|
|
84
105
|
|
|
85
|
-
const
|
|
106
|
+
const separator = ( rootPath === path.sep ) ? '' : path.sep;
|
|
107
|
+
const subPath = `${rootPath}${separator}${dirent.name}`;
|
|
86
108
|
|
|
87
109
|
if ( isIgnored ( subPath ) ) return;
|
|
88
110
|
|
|
@@ -118,6 +140,8 @@ const readdir = ( rootPath: string, options?: Options ): Promise<Result> => {
|
|
|
118
140
|
|
|
119
141
|
if ( depth > maxDepth ) return;
|
|
120
142
|
|
|
143
|
+
if ( foundPaths >= maxPaths ) return;
|
|
144
|
+
|
|
121
145
|
const dirents = await fs.promises.readdir ( rootPath, { withFileTypes: true } ).catch ( () => [] );
|
|
122
146
|
|
|
123
147
|
if ( signal.aborted ) return;
|
|
@@ -134,9 +158,9 @@ const readdir = ( rootPath: string, options?: Options ): Promise<Result> => {
|
|
|
134
158
|
|
|
135
159
|
try {
|
|
136
160
|
|
|
137
|
-
const realPath = await fs.promises.realpath ( rootPath )
|
|
138
|
-
|
|
139
|
-
|
|
161
|
+
const realPath = await fs.promises.realpath ( rootPath );
|
|
162
|
+
const stat = await fs.promises.stat ( realPath );
|
|
163
|
+
const dirmap = map[rootPath] = { directories: [], files: [], symlinks: [] };
|
|
140
164
|
|
|
141
165
|
await handleStat ( dirmap, realPath, stat, depth );
|
|
142
166
|
|
|
@@ -148,6 +172,8 @@ const readdir = ( rootPath: string, options?: Options ): Promise<Result> => {
|
|
|
148
172
|
|
|
149
173
|
rootPath = path.normalize ( rootPath );
|
|
150
174
|
|
|
175
|
+
visited.add ( rootPath );
|
|
176
|
+
|
|
151
177
|
await populateResultFromPath ( rootPath, depth );
|
|
152
178
|
|
|
153
179
|
if ( signal.aborted ) return resultEmpty;
|
package/src/types.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
|
|
2
2
|
/* HELPERS */
|
|
3
3
|
|
|
4
|
-
type Promisable<T> = T |
|
|
4
|
+
type Promisable<T> = Promise<T> | T;
|
|
5
5
|
|
|
6
|
-
/*
|
|
6
|
+
/* MAIN */
|
|
7
7
|
|
|
8
8
|
type Options = {
|
|
9
9
|
depth?: number,
|
|
10
|
+
limit?: number,
|
|
10
11
|
followSymlinks?: boolean,
|
|
11
12
|
ignore?: ( targetPath: string ) => boolean,
|
|
12
13
|
signal?: { aborted: boolean }
|
|
@@ -28,4 +29,4 @@ type Result = ResultDirectory & {
|
|
|
28
29
|
|
|
29
30
|
/* EXPORT */
|
|
30
31
|
|
|
31
|
-
export {Promisable, Options, ResultDirectory, ResultDirectories, Result};
|
|
32
|
+
export type {Promisable, Options, ResultDirectory, ResultDirectories, Result};
|
package/test/native.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
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
|
+
/* MAIN */
|
|
10
|
+
|
|
11
|
+
describe ( 'Tiny Readdir', it => {
|
|
12
|
+
|
|
13
|
+
it ( 'finds folders, files and symlinks', async t => {
|
|
14
|
+
|
|
15
|
+
const cwdPath = process.cwd ();
|
|
16
|
+
const root1Path = path.join ( cwdPath, 'test', 'root1' );
|
|
17
|
+
const root2Path = path.join ( cwdPath, 'test', 'root2' );
|
|
18
|
+
const folder1Path = path.join ( root1Path, 'folder1' );
|
|
19
|
+
const folder2Path = path.join ( root1Path, 'folder2' );
|
|
20
|
+
const folder1DeepPath = path.join ( folder1Path, 'deep' );
|
|
21
|
+
const file1aPath = path.join ( folder1Path, 'file1a.txt' );
|
|
22
|
+
const file1bPath = path.join ( folder1Path, 'file1b.txt' );
|
|
23
|
+
const file2Path = path.join ( folder2Path, 'file2.txt' );
|
|
24
|
+
const fileDeep1Path = path.join ( folder1DeepPath, 'file1.txt' );
|
|
25
|
+
const symlink1FromPath = path.join ( root1Path, 'symlink' );
|
|
26
|
+
const symlink1ToPath = root2Path;
|
|
27
|
+
const symlink2FromPath = path.join ( root2Path, 'symlink' );
|
|
28
|
+
const symlink2ToPath = root1Path;
|
|
29
|
+
|
|
30
|
+
fs.mkdirSync ( root1Path );
|
|
31
|
+
fs.mkdirSync ( root2Path );
|
|
32
|
+
fs.mkdirSync ( folder1Path );
|
|
33
|
+
fs.mkdirSync ( folder2Path );
|
|
34
|
+
fs.mkdirSync ( folder1DeepPath );
|
|
35
|
+
fs.writeFileSync ( file1aPath, '' );
|
|
36
|
+
fs.writeFileSync ( file1bPath, '' );
|
|
37
|
+
fs.writeFileSync ( file2Path, '' );
|
|
38
|
+
fs.writeFileSync ( fileDeep1Path, '' );
|
|
39
|
+
fs.symlinkSync ( symlink1ToPath, symlink1FromPath );
|
|
40
|
+
fs.symlinkSync ( symlink2ToPath, symlink2FromPath );
|
|
41
|
+
|
|
42
|
+
const expected = {
|
|
43
|
+
directories: [folder1Path, folder2Path, folder1DeepPath, root2Path],
|
|
44
|
+
files: [file1aPath, file1bPath, file2Path, fileDeep1Path],
|
|
45
|
+
symlinks: [symlink1FromPath, symlink2FromPath],
|
|
46
|
+
map: {
|
|
47
|
+
[root1Path]: {
|
|
48
|
+
directories: [folder1Path, folder2Path],
|
|
49
|
+
files: [],
|
|
50
|
+
symlinks: [symlink1FromPath]
|
|
51
|
+
},
|
|
52
|
+
[root2Path]: {
|
|
53
|
+
directories: [],
|
|
54
|
+
files: [],
|
|
55
|
+
symlinks: [symlink2FromPath]
|
|
56
|
+
},
|
|
57
|
+
[folder1Path]: {
|
|
58
|
+
directories: [folder1DeepPath],
|
|
59
|
+
files: [file1aPath, file1bPath],
|
|
60
|
+
symlinks: []
|
|
61
|
+
},
|
|
62
|
+
[folder2Path]: {
|
|
63
|
+
directories: [],
|
|
64
|
+
files: [file2Path],
|
|
65
|
+
symlinks: []
|
|
66
|
+
},
|
|
67
|
+
[folder1DeepPath]: {
|
|
68
|
+
directories: [],
|
|
69
|
+
files: [fileDeep1Path],
|
|
70
|
+
symlinks: []
|
|
71
|
+
},
|
|
72
|
+
[symlink1FromPath]: {
|
|
73
|
+
directories: [root2Path],
|
|
74
|
+
files: [],
|
|
75
|
+
symlinks: []
|
|
76
|
+
},
|
|
77
|
+
[symlink2FromPath]: {
|
|
78
|
+
directories: [],
|
|
79
|
+
files: [],
|
|
80
|
+
symlinks: []
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
|
|
87
|
+
const result = await readdir ( root1Path, { followSymlinks: true } );
|
|
88
|
+
|
|
89
|
+
t.deepEqual ( result, expected );
|
|
90
|
+
|
|
91
|
+
} finally {
|
|
92
|
+
|
|
93
|
+
fs.rmSync ( root1Path, { recursive: true } );
|
|
94
|
+
fs.rmSync ( root2Path, { recursive: true } );
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it ( 'supports a limit option', async t => {
|
|
101
|
+
|
|
102
|
+
const cwdPath = process.cwd ();
|
|
103
|
+
const root1Path = path.join ( cwdPath, 'test', 'root1' );
|
|
104
|
+
const root2Path = path.join ( cwdPath, 'test', 'root2' );
|
|
105
|
+
const folder1Path = path.join ( root1Path, 'folder1' );
|
|
106
|
+
const folder2Path = path.join ( root1Path, 'folder2' );
|
|
107
|
+
const folder1DeepPath = path.join ( folder1Path, 'deep' );
|
|
108
|
+
const file1aPath = path.join ( folder1Path, 'file1a.txt' );
|
|
109
|
+
const file1bPath = path.join ( folder1Path, 'file1b.txt' );
|
|
110
|
+
const file2Path = path.join ( folder2Path, 'file2.txt' );
|
|
111
|
+
const fileDeep1Path = path.join ( folder1DeepPath, 'file1.txt' );
|
|
112
|
+
const symlink1FromPath = path.join ( root1Path, 'symlink' );
|
|
113
|
+
const symlink1ToPath = root2Path;
|
|
114
|
+
const symlink2FromPath = path.join ( root2Path, 'symlink' );
|
|
115
|
+
const symlink2ToPath = root1Path;
|
|
116
|
+
|
|
117
|
+
fs.mkdirSync ( root1Path );
|
|
118
|
+
fs.mkdirSync ( root2Path );
|
|
119
|
+
fs.mkdirSync ( folder1Path );
|
|
120
|
+
fs.mkdirSync ( folder2Path );
|
|
121
|
+
fs.mkdirSync ( folder1DeepPath );
|
|
122
|
+
fs.writeFileSync ( file1aPath, '' );
|
|
123
|
+
fs.writeFileSync ( file1bPath, '' );
|
|
124
|
+
fs.writeFileSync ( file2Path, '' );
|
|
125
|
+
fs.writeFileSync ( fileDeep1Path, '' );
|
|
126
|
+
fs.symlinkSync ( symlink1ToPath, symlink1FromPath );
|
|
127
|
+
fs.symlinkSync ( symlink2ToPath, symlink2FromPath );
|
|
128
|
+
|
|
129
|
+
const expected = {
|
|
130
|
+
directories: [folder1Path, folder2Path],
|
|
131
|
+
files: [],
|
|
132
|
+
symlinks: [symlink1FromPath],
|
|
133
|
+
map: {
|
|
134
|
+
[root1Path]: {
|
|
135
|
+
directories: [folder1Path, folder2Path],
|
|
136
|
+
files: [],
|
|
137
|
+
symlinks: [symlink1FromPath]
|
|
138
|
+
},
|
|
139
|
+
[folder1Path]: {
|
|
140
|
+
directories: [],
|
|
141
|
+
files: [],
|
|
142
|
+
symlinks: []
|
|
143
|
+
},
|
|
144
|
+
[folder2Path]: {
|
|
145
|
+
directories: [],
|
|
146
|
+
files: [],
|
|
147
|
+
symlinks: []
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
|
|
154
|
+
const result = await readdir ( root1Path, { limit: 3, followSymlinks: true } );
|
|
155
|
+
|
|
156
|
+
t.deepEqual ( result, expected );
|
|
157
|
+
|
|
158
|
+
} finally {
|
|
159
|
+
|
|
160
|
+
fs.rmSync ( root1Path, { recursive: true } );
|
|
161
|
+
fs.rmSync ( root2Path, { recursive: true } );
|
|
162
|
+
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
});
|
package/test/yielding.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
|
|
2
|
+
/* IMPORT */
|
|
3
|
+
|
|
4
|
+
import readdir from '../dist/index.js';
|
|
5
|
+
|
|
6
|
+
/* MAIN */
|
|
7
|
+
|
|
8
|
+
const main = async () => {
|
|
9
|
+
|
|
10
|
+
let count = 0;
|
|
11
|
+
let start = Date.now ();
|
|
12
|
+
|
|
13
|
+
setInterval ( () => {
|
|
14
|
+
count += 1;
|
|
15
|
+
console.log ( 'tick', count );
|
|
16
|
+
if ( count < 100 ) return;
|
|
17
|
+
const end = Date.now ();
|
|
18
|
+
const elapsed = end - start;
|
|
19
|
+
console.log ( 'elapsed', elapsed );
|
|
20
|
+
if ( elapsed > 1500 ) {
|
|
21
|
+
process.exit ( 1 ); // Fail
|
|
22
|
+
} else {
|
|
23
|
+
process.exit ( 0 ); // Success
|
|
24
|
+
}
|
|
25
|
+
}, 10 );
|
|
26
|
+
|
|
27
|
+
await readdir ( '/' );
|
|
28
|
+
|
|
29
|
+
process.exit ( 1 ); // Fail
|
|
30
|
+
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/* RUNNING */
|
|
34
|
+
|
|
35
|
+
await main ();
|
package/tsconfig.json
CHANGED
|
@@ -1,28 +1,3 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"alwaysStrict": true,
|
|
4
|
-
"declaration": true,
|
|
5
|
-
"emitDecoratorMetadata": true,
|
|
6
|
-
"experimentalDecorators": true,
|
|
7
|
-
"forceConsistentCasingInFileNames": true,
|
|
8
|
-
"inlineSourceMap": false,
|
|
9
|
-
"jsx": "react",
|
|
10
|
-
"lib": ["dom", "scripthost", "es2015", "es2016", "es2017", "es2018", "es2019", "es2020"],
|
|
11
|
-
"module": "commonjs",
|
|
12
|
-
"moduleResolution": "node",
|
|
13
|
-
"newLine": "LF",
|
|
14
|
-
"noFallthroughCasesInSwitch": true,
|
|
15
|
-
"noUnusedLocals": true,
|
|
16
|
-
"noUnusedParameters": false,
|
|
17
|
-
"outDir": "dist",
|
|
18
|
-
"pretty": true,
|
|
19
|
-
"strictNullChecks": true,
|
|
20
|
-
"target": "es2018"
|
|
21
|
-
},
|
|
22
|
-
"include": [
|
|
23
|
-
"src"
|
|
24
|
-
],
|
|
25
|
-
"exclude": [
|
|
26
|
-
"node_modules"
|
|
27
|
-
]
|
|
2
|
+
"extends": "tsex/tsconfig.json"
|
|
28
3
|
}
|