tiny-readdir 1.5.0 → 2.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/.editorconfig +0 -3
- package/dist/index.d.ts +2 -8
- package/dist/index.js +31 -13
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -2
- package/{LICENSE → license} +0 -0
- package/package.json +16 -26
- package/{README.md → readme.md} +0 -0
- package/src/index.ts +29 -17
- package/src/types.ts +3 -3
- package/test/index.js +100 -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';
|
|
1
|
+
import type { Options, Result } from './types';
|
|
2
2
|
declare const readdir: (rootPath: string, options?: Options | undefined) => Promise<Result>;
|
|
3
|
-
|
|
4
|
-
default: typeof readdir;
|
|
5
|
-
}
|
|
6
|
-
declare namespace _default {
|
|
7
|
-
export type type = readdir;
|
|
8
|
-
}
|
|
9
|
-
export = _default;
|
|
3
|
+
export default readdir;
|
package/dist/index.js
CHANGED
|
@@ -1,28 +1,45 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/* IMPORT */
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import Limiter from 'promise-concurrency-limiter';
|
|
6
5
|
/* HELPERS */
|
|
7
|
-
const limiter = new
|
|
8
|
-
/*
|
|
6
|
+
const limiter = new Limiter({ concurrency: 500 });
|
|
7
|
+
/* MAIN */
|
|
9
8
|
const readdir = (rootPath, options) => {
|
|
10
|
-
|
|
11
|
-
const
|
|
9
|
+
const followSymlinks = options?.followSymlinks ?? false;
|
|
10
|
+
const maxDepth = options?.depth ?? Infinity;
|
|
11
|
+
const isIgnored = options?.ignore ?? (() => false);
|
|
12
|
+
const signal = options?.signal ?? { aborted: false };
|
|
13
|
+
const directories = [];
|
|
14
|
+
const files = [];
|
|
15
|
+
const symlinks = [];
|
|
16
|
+
const map = {};
|
|
17
|
+
const visited = new Set();
|
|
18
|
+
const resultEmpty = { directories: [], files: [], symlinks: [], map: {} };
|
|
19
|
+
const result = { directories, files, symlinks, map };
|
|
12
20
|
const handleDirectory = (dirmap, subPath, depth) => {
|
|
21
|
+
if (visited.has(subPath))
|
|
22
|
+
return;
|
|
13
23
|
dirmap.directories.push(subPath);
|
|
14
24
|
directories.push(subPath);
|
|
25
|
+
visited.add(subPath);
|
|
15
26
|
if (depth >= maxDepth)
|
|
16
27
|
return;
|
|
17
28
|
return limiter.add(() => populateResultFromPath(subPath, depth + 1));
|
|
18
29
|
};
|
|
19
30
|
const handleFile = (dirmap, subPath) => {
|
|
31
|
+
if (visited.has(subPath))
|
|
32
|
+
return;
|
|
20
33
|
dirmap.files.push(subPath);
|
|
21
34
|
files.push(subPath);
|
|
35
|
+
visited.add(subPath);
|
|
22
36
|
};
|
|
23
37
|
const handleSymlink = (dirmap, subPath, depth) => {
|
|
38
|
+
if (visited.has(subPath))
|
|
39
|
+
return;
|
|
24
40
|
dirmap.symlinks.push(subPath);
|
|
25
41
|
symlinks.push(subPath);
|
|
42
|
+
visited.add(subPath);
|
|
26
43
|
if (!followSymlinks)
|
|
27
44
|
return;
|
|
28
45
|
if (depth >= maxDepth)
|
|
@@ -80,13 +97,16 @@ const readdir = (rootPath, options) => {
|
|
|
80
97
|
};
|
|
81
98
|
const populateResultFromSymlink = async (rootPath, depth) => {
|
|
82
99
|
try {
|
|
83
|
-
const realPath = await fs.promises.realpath(rootPath)
|
|
100
|
+
const realPath = await fs.promises.realpath(rootPath);
|
|
101
|
+
const stat = await fs.promises.stat(realPath);
|
|
102
|
+
const dirmap = map[rootPath] = { directories: [], files: [], symlinks: [] };
|
|
84
103
|
await handleStat(dirmap, realPath, stat, depth);
|
|
85
104
|
}
|
|
86
|
-
catch
|
|
105
|
+
catch { }
|
|
87
106
|
};
|
|
88
107
|
const getResult = async (rootPath, depth = 1) => {
|
|
89
108
|
rootPath = path.normalize(rootPath);
|
|
109
|
+
visited.add(rootPath);
|
|
90
110
|
await populateResultFromPath(rootPath, depth);
|
|
91
111
|
if (signal.aborted)
|
|
92
112
|
return resultEmpty;
|
|
@@ -95,6 +115,4 @@ const readdir = (rootPath, options) => {
|
|
|
95
115
|
return getResult(rootPath);
|
|
96
116
|
};
|
|
97
117
|
/* EXPORT */
|
|
98
|
-
|
|
99
|
-
module.exports.default = readdir;
|
|
100
|
-
Object.defineProperty(module.exports, "__esModule", { value: true });
|
|
118
|
+
export default readdir;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare type Promisable<T> = T |
|
|
1
|
+
declare type Promisable<T> = Promise<T> | T;
|
|
2
2
|
declare type Options = {
|
|
3
3
|
depth?: number;
|
|
4
4
|
followSymlinks?: boolean;
|
|
@@ -18,4 +18,4 @@ declare type ResultDirectories = {
|
|
|
18
18
|
declare type Result = ResultDirectory & {
|
|
19
19
|
map: ResultDirectories;
|
|
20
20
|
};
|
|
21
|
-
export { Promisable, Options, ResultDirectory, ResultDirectories, Result };
|
|
21
|
+
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,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tiny-readdir",
|
|
3
|
+
"repository": "github:fabiospampinato/tiny-readdir",
|
|
3
4
|
"description": "A simple promisified recursive readdir function.",
|
|
4
|
-
"version": "
|
|
5
|
+
"version": "2.0.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
|
-
"url": "https://github.com/fabiospampinato/tiny-readdir/issues"
|
|
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": "tsex test",
|
|
15
|
+
"test:watch": "tsex test --watch",
|
|
16
|
+
"prepublishOnly": "npm run clean && npm run compile && npm run test"
|
|
24
17
|
},
|
|
25
18
|
"keywords": [
|
|
26
19
|
"readdir",
|
|
@@ -29,16 +22,13 @@
|
|
|
29
22
|
"simple",
|
|
30
23
|
"tiny"
|
|
31
24
|
],
|
|
32
|
-
"engines": {
|
|
33
|
-
"node": ">= 10.12.0"
|
|
34
|
-
},
|
|
35
25
|
"dependencies": {
|
|
36
|
-
"promise-concurrency-limiter": "^
|
|
26
|
+
"promise-concurrency-limiter": "^2.0.0"
|
|
37
27
|
},
|
|
38
28
|
"devDependencies": {
|
|
39
|
-
"@types/node": "^
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"typescript
|
|
29
|
+
"@types/node": "^17.0.23",
|
|
30
|
+
"fava": "^0.0.6",
|
|
31
|
+
"tsex": "^1.1.1",
|
|
32
|
+
"typescript": "^4.6.3"
|
|
43
33
|
}
|
|
44
34
|
}
|
package/{README.md → readme.md}
RENAMED
|
File without changes
|
package/src/index.ts
CHANGED
|
@@ -1,34 +1,38 @@
|
|
|
1
1
|
|
|
2
2
|
/* IMPORT */
|
|
3
3
|
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
6
|
import Limiter from 'promise-concurrency-limiter';
|
|
7
|
-
import {Promisable, Options, ResultDirectory, ResultDirectories, Result} from './types';
|
|
7
|
+
import type {Promisable, Options, ResultDirectory, ResultDirectories, Result} from './types';
|
|
8
8
|
|
|
9
9
|
/* HELPERS */
|
|
10
10
|
|
|
11
11
|
const limiter = new Limiter ({ concurrency: 500 });
|
|
12
12
|
|
|
13
|
-
/*
|
|
13
|
+
/* MAIN */
|
|
14
14
|
|
|
15
15
|
const readdir = ( rootPath: string, options?: Options ): Promise<Result> => {
|
|
16
16
|
|
|
17
|
-
const followSymlinks = options?.followSymlinks ?? false
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
const followSymlinks = options?.followSymlinks ?? false;
|
|
18
|
+
const maxDepth = options?.depth ?? Infinity;
|
|
19
|
+
const isIgnored = options?.ignore ?? (() => false);
|
|
20
|
+
const signal = options?.signal ?? { aborted: false };
|
|
21
|
+
const directories: string[] = [];
|
|
22
|
+
const files: string[] = [];
|
|
23
|
+
const symlinks: string[] = [];
|
|
24
|
+
const map: ResultDirectories = {};
|
|
25
|
+
const visited = new Set<string> ();
|
|
26
|
+
const resultEmpty: Result = { directories: [], files: [], symlinks: [], map: {} };
|
|
27
|
+
const result: Result = { directories, files, symlinks, map };
|
|
27
28
|
|
|
28
29
|
const handleDirectory = ( dirmap: ResultDirectory, subPath: string, depth: number ): Promisable<void> => {
|
|
29
30
|
|
|
31
|
+
if ( visited.has ( subPath ) ) return;
|
|
32
|
+
|
|
30
33
|
dirmap.directories.push ( subPath );
|
|
31
34
|
directories.push ( subPath );
|
|
35
|
+
visited.add ( subPath );
|
|
32
36
|
|
|
33
37
|
if ( depth >= maxDepth ) return;
|
|
34
38
|
|
|
@@ -38,15 +42,21 @@ const readdir = ( rootPath: string, options?: Options ): Promise<Result> => {
|
|
|
38
42
|
|
|
39
43
|
const handleFile = ( dirmap: ResultDirectory, subPath: string ): void => {
|
|
40
44
|
|
|
45
|
+
if ( visited.has ( subPath ) ) return;
|
|
46
|
+
|
|
41
47
|
dirmap.files.push ( subPath );
|
|
42
48
|
files.push ( subPath );
|
|
49
|
+
visited.add ( subPath );
|
|
43
50
|
|
|
44
51
|
};
|
|
45
52
|
|
|
46
53
|
const handleSymlink = ( dirmap: ResultDirectory, subPath: string, depth: number ): Promisable<void> => {
|
|
47
54
|
|
|
55
|
+
if ( visited.has ( subPath ) ) return;
|
|
56
|
+
|
|
48
57
|
dirmap.symlinks.push ( subPath );
|
|
49
58
|
symlinks.push ( subPath );
|
|
59
|
+
visited.add ( subPath );
|
|
50
60
|
|
|
51
61
|
if ( !followSymlinks ) return;
|
|
52
62
|
|
|
@@ -134,9 +144,9 @@ const readdir = ( rootPath: string, options?: Options ): Promise<Result> => {
|
|
|
134
144
|
|
|
135
145
|
try {
|
|
136
146
|
|
|
137
|
-
const realPath = await fs.promises.realpath ( rootPath )
|
|
138
|
-
|
|
139
|
-
|
|
147
|
+
const realPath = await fs.promises.realpath ( rootPath );
|
|
148
|
+
const stat = await fs.promises.stat ( realPath );
|
|
149
|
+
const dirmap = map[rootPath] = { directories: [], files: [], symlinks: [] };
|
|
140
150
|
|
|
141
151
|
await handleStat ( dirmap, realPath, stat, depth );
|
|
142
152
|
|
|
@@ -148,6 +158,8 @@ const readdir = ( rootPath: string, options?: Options ): Promise<Result> => {
|
|
|
148
158
|
|
|
149
159
|
rootPath = path.normalize ( rootPath );
|
|
150
160
|
|
|
161
|
+
visited.add ( rootPath );
|
|
162
|
+
|
|
151
163
|
await populateResultFromPath ( rootPath, depth );
|
|
152
164
|
|
|
153
165
|
if ( signal.aborted ) return resultEmpty;
|
package/src/types.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
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,
|
|
@@ -28,4 +28,4 @@ type Result = ResultDirectory & {
|
|
|
28
28
|
|
|
29
29
|
/* EXPORT */
|
|
30
30
|
|
|
31
|
-
export {Promisable, Options, ResultDirectory, ResultDirectories, Result};
|
|
31
|
+
export type {Promisable, Options, ResultDirectory, ResultDirectories, Result};
|
package/test/index.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
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 ( 'works', 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
|
+
});
|
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
|
}
|