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 CHANGED
@@ -8,6 +8,3 @@ indent_size = 2
8
8
  indent_style = space
9
9
  insert_final_newline = true
10
10
  trim_trailing_whitespace = true
11
-
12
- [*.md]
13
- trim_trailing_whitespace = false
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
- declare const _default: typeof readdir & {
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
- const fs = require("fs");
4
- const path = require("path");
5
- const promise_concurrency_limiter_1 = require("promise-concurrency-limiter");
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 promise_concurrency_limiter_1.default({ concurrency: 500 });
8
- /* TINY READDIR */
6
+ const limiter = new Limiter({ concurrency: 500 });
7
+ /* MAIN */
9
8
  const readdir = (rootPath, options) => {
10
- var _a, _b, _c, _d;
11
- const followSymlinks = (_a = options === null || options === void 0 ? void 0 : options.followSymlinks) !== null && _a !== void 0 ? _a : false, maxDepth = (_b = options === null || options === void 0 ? void 0 : options.depth) !== null && _b !== void 0 ? _b : Infinity, isIgnored = (_c = options === null || options === void 0 ? void 0 : options.ignore) !== null && _c !== void 0 ? _c : (() => false), signal = (_d = options === null || options === void 0 ? void 0 : options.signal) !== null && _d !== void 0 ? _d : { aborted: false }, directories = [], files = [], symlinks = [], map = {}, resultEmpty = { directories: [], files: [], symlinks: [], map: {} }, result = { directories, files, symlinks, map };
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), stat = await fs.promises.stat(realPath), dirmap = map[rootPath] = { directories: [], files: [], symlinks: [] };
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 (_a) { }
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
- module.exports = readdir;
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 | Promise<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
@@ -1,3 +1,2 @@
1
- "use strict";
2
1
  /* HELPERS */
3
- Object.defineProperty(exports, "__esModule", { value: true });
2
+ export {};
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": "1.5.0",
5
+ "version": "2.0.0",
6
+ "type": "module",
5
7
  "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
8
+ "exports": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
7
10
  "scripts": {
8
- "clean": "rimraf dist",
9
- "compile": "tsc --skipLibCheck && tstei",
10
- "compile:watch": "tsc --skipLibCheck --watch",
11
- "prepublishOnly": "npm run clean && npm run compile"
12
- },
13
- "bugs": {
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": "^1.0.0"
26
+ "promise-concurrency-limiter": "^2.0.0"
37
27
  },
38
28
  "devDependencies": {
39
- "@types/node": "^14.14.9",
40
- "rimraf": "^3.0.2",
41
- "typescript": "^4.1.2",
42
- "typescript-transform-export-interop": "^1.0.2"
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
  }
File without changes
package/src/index.ts CHANGED
@@ -1,34 +1,38 @@
1
1
 
2
2
  /* IMPORT */
3
3
 
4
- import * as fs from 'fs';
5
- import * as path from 'path';
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
- /* TINY READDIR */
13
+ /* MAIN */
14
14
 
15
15
  const readdir = ( rootPath: string, options?: Options ): Promise<Result> => {
16
16
 
17
- const followSymlinks = options?.followSymlinks ?? false,
18
- maxDepth = options?.depth ?? Infinity,
19
- isIgnored = options?.ignore ?? (() => false),
20
- signal = options?.signal ?? { aborted: false },
21
- directories: string[] = [],
22
- files: string[] = [],
23
- symlinks: string[] = [],
24
- map: ResultDirectories = {},
25
- resultEmpty: Result = { directories: [], files: [], symlinks: [], map: {} },
26
- result: Result = { directories, files, symlinks, map };
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
- stat = await fs.promises.stat ( realPath ),
139
- dirmap = map[rootPath] = { directories: [], files: [], symlinks: [] };
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 | Promise<T>;
4
+ type Promisable<T> = Promise<T> | T;
5
5
 
6
- /* TYPES */
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
- "compilerOptions": {
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
  }