@aminzer/traverse-directory 1.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.
Files changed (48) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +65 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +3 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/models/FsEntry.d.ts +21 -0
  7. package/dist/models/FsEntry.js +34 -0
  8. package/dist/models/FsEntry.js.map +1 -0
  9. package/dist/models/__tests__/FsEntry.test.d.ts +1 -0
  10. package/dist/models/__tests__/FsEntry.test.js +40 -0
  11. package/dist/models/__tests__/FsEntry.test.js.map +1 -0
  12. package/dist/models/index.d.ts +1 -0
  13. package/dist/models/index.js +2 -0
  14. package/dist/models/index.js.map +1 -0
  15. package/dist/traverseDirectory/__tests__/traverseDirectory.test.d.ts +1 -0
  16. package/dist/traverseDirectory/__tests__/traverseDirectory.test.js +289 -0
  17. package/dist/traverseDirectory/__tests__/traverseDirectory.test.js.map +1 -0
  18. package/dist/traverseDirectory/index.d.ts +1 -0
  19. package/dist/traverseDirectory/index.js +2 -0
  20. package/dist/traverseDirectory/index.js.map +1 -0
  21. package/dist/traverseDirectory/traverseDirectory.d.ts +3 -0
  22. package/dist/traverseDirectory/traverseDirectory.js +10 -0
  23. package/dist/traverseDirectory/traverseDirectory.js.map +1 -0
  24. package/dist/traverseDirectory/traverseDirectoryRecursive.d.ts +3 -0
  25. package/dist/traverseDirectory/traverseDirectoryRecursive.js +31 -0
  26. package/dist/traverseDirectory/traverseDirectoryRecursive.js.map +1 -0
  27. package/dist/traverseDirectory/types.d.ts +6 -0
  28. package/dist/traverseDirectory/types.js +2 -0
  29. package/dist/traverseDirectory/types.js.map +1 -0
  30. package/dist/utils/fs/__tests__/directoryExist.test.d.ts +1 -0
  31. package/dist/utils/fs/__tests__/directoryExist.test.js +25 -0
  32. package/dist/utils/fs/__tests__/directoryExist.test.js.map +1 -0
  33. package/dist/utils/fs/directoryExist.d.ts +2 -0
  34. package/dist/utils/fs/directoryExist.js +12 -0
  35. package/dist/utils/fs/directoryExist.js.map +1 -0
  36. package/dist/utils/fs/index.d.ts +1 -0
  37. package/dist/utils/fs/index.js +2 -0
  38. package/dist/utils/fs/index.js.map +1 -0
  39. package/dist/utils/iteration/__tests__/iterateInSeries.test.d.ts +1 -0
  40. package/dist/utils/iteration/__tests__/iterateInSeries.test.js +65 -0
  41. package/dist/utils/iteration/__tests__/iterateInSeries.test.js.map +1 -0
  42. package/dist/utils/iteration/index.d.ts +1 -0
  43. package/dist/utils/iteration/index.js +2 -0
  44. package/dist/utils/iteration/index.js.map +1 -0
  45. package/dist/utils/iteration/iterateInSeries.d.ts +2 -0
  46. package/dist/utils/iteration/iterateInSeries.js +7 -0
  47. package/dist/utils/iteration/iterateInSeries.js.map +1 -0
  48. package/package.json +59 -0
package/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Aliaksei Minzer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,65 @@
1
+ ### Overview
2
+
3
+ [NodeJS](https://nodejs.org) utility for recursively iterating over directory contents.
4
+
5
+ It allows to traverse through all subdirectories and files within a specified directory.
6
+
7
+ ### Installation
8
+
9
+ ```bash
10
+ npm i @aminzer/traverse-directory
11
+ ```
12
+
13
+ ### Usage examples
14
+
15
+ ```typescript
16
+ import { traverseDirectory } from '@aminzer/traverse-directory';
17
+
18
+ await traverseDirectory('/path/to/directory', ({ isFile, relativePath }) => {
19
+ console.log(`${isFile ? 'File' : 'Directory'} ${relativePath} was found`);
20
+ });
21
+ ```
22
+
23
+ ### API
24
+
25
+ **traverseDirectory**
26
+
27
+ ##### Overview
28
+
29
+ `traverseDirectory` recursively iterates over the contents of a directory.
30
+
31
+ ```typescript
32
+ traverseDirectory(dirPath, onEachChild);
33
+ ```
34
+
35
+ ##### Parameters
36
+
37
+ * `dirPath` (`string`, required) - path to the directory whose contents should be iterated.
38
+ * `onEachChild` (`function`, required) - callback invoked for each child file and directory.
39
+
40
+ `onEachChild` callback accepts following arguments:
41
+ * `fsEntry` (`FsEntry`) - currently iterated child file or directory.
42
+ * `additionalArgs` (`object`, optional) - additional callback arguments:
43
+ * `skipEntryChildrenIteration` (`function`) - call this function within `onEachChild` to skip iterating the children of the current entry.
44
+
45
+ ##### Return value
46
+
47
+ `Promise` that resolves when the directory traversal is complete.
48
+
49
+ **FsEntry**
50
+
51
+ ##### Overview
52
+
53
+ `FsEntry` - class representing File System Entry (file or directory).
54
+
55
+ ```typescript
56
+ import { FsEntry } from '@aminzer/traverse-directory';
57
+ ```
58
+
59
+ Instance properties:
60
+ * `name` (`string`) - name of entry.
61
+ * `absolutePath` (`string`) - absolute path to entry.
62
+ * `relativePath` (`string`) - relative path to entry. It's relative to the directory passed to `traverseDirectory`.
63
+ * `size` (`number`) - size of file in bytes, `0` for directories.
64
+ * `isFile` (`boolean`) - `true` if entry is file.
65
+ * `isDirectory` (`boolean`) - `true` if entry is directory.
@@ -0,0 +1,2 @@
1
+ export { default as traverseDirectory } from './traverseDirectory';
2
+ export { FsEntry } from './models';
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { default as traverseDirectory } from './traverseDirectory';
2
+ export { FsEntry } from './models';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,21 @@
1
+ declare class FsEntry {
2
+ _name: string;
3
+ _absolutePath: string;
4
+ _relativePath: string;
5
+ _isFile: boolean;
6
+ _size: number;
7
+ constructor({ name, absolutePath, relativePath, isFile, size, }: {
8
+ name: string;
9
+ absolutePath: string;
10
+ relativePath: string;
11
+ isFile: boolean;
12
+ size: number;
13
+ });
14
+ get name(): string;
15
+ get absolutePath(): string;
16
+ get relativePath(): string;
17
+ get isFile(): boolean;
18
+ get isDirectory(): boolean;
19
+ get size(): number;
20
+ }
21
+ export default FsEntry;
@@ -0,0 +1,34 @@
1
+ class FsEntry {
2
+ _name;
3
+ _absolutePath;
4
+ _relativePath;
5
+ _isFile;
6
+ _size;
7
+ constructor({ name, absolutePath, relativePath, isFile, size, }) {
8
+ this._name = name;
9
+ this._absolutePath = absolutePath;
10
+ this._relativePath = relativePath;
11
+ this._isFile = isFile;
12
+ this._size = size;
13
+ }
14
+ get name() {
15
+ return this._name;
16
+ }
17
+ get absolutePath() {
18
+ return this._absolutePath;
19
+ }
20
+ get relativePath() {
21
+ return this._relativePath;
22
+ }
23
+ get isFile() {
24
+ return this._isFile;
25
+ }
26
+ get isDirectory() {
27
+ return !this.isFile;
28
+ }
29
+ get size() {
30
+ return this._size;
31
+ }
32
+ }
33
+ export default FsEntry;
34
+ //# sourceMappingURL=FsEntry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FsEntry.js","sourceRoot":"","sources":["../../src/models/FsEntry.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO;IACX,KAAK,CAAS;IAEd,aAAa,CAAS;IAEtB,aAAa,CAAS;IAEtB,OAAO,CAAU;IAEjB,KAAK,CAAS;IAEd,YAAY,EACV,IAAI,EACJ,YAAY,EACZ,YAAY,EACZ,MAAM,EACN,IAAI,GAOL;QACC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;QAClC,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;QAClC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,IAAI,WAAW;QACb,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;IACtB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;CACF;AAED,eAAe,OAAO,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ import assert from 'node:assert';
2
+ import { describe, it } from 'node:test';
3
+ import FsEntry from '../FsEntry';
4
+ describe('models > FsEntry', () => {
5
+ describe('when entry is file', () => {
6
+ it('initializes instance with correct fields', () => {
7
+ const fsEntry = new FsEntry({
8
+ name: 'the_file.txt',
9
+ absolutePath: '/absolute/path/to/the_file.txt',
10
+ relativePath: '/path/to/the_file.txt',
11
+ isFile: true,
12
+ size: 32,
13
+ });
14
+ assert.strictEqual(fsEntry.name, 'the_file.txt');
15
+ assert.strictEqual(fsEntry.absolutePath, '/absolute/path/to/the_file.txt');
16
+ assert.strictEqual(fsEntry.relativePath, '/path/to/the_file.txt');
17
+ assert.strictEqual(fsEntry.isFile, true);
18
+ assert.strictEqual(fsEntry.isDirectory, false);
19
+ assert.strictEqual(fsEntry.size, 32);
20
+ });
21
+ });
22
+ describe('when entry is directory', () => {
23
+ it('initializes instance with correct fields', () => {
24
+ const fsEntry = new FsEntry({
25
+ name: 'the_directory',
26
+ absolutePath: '/absolute/path/to/the_directory',
27
+ relativePath: '/path/to/the_directory',
28
+ isFile: false,
29
+ size: 0,
30
+ });
31
+ assert.strictEqual(fsEntry.name, 'the_directory');
32
+ assert.strictEqual(fsEntry.absolutePath, '/absolute/path/to/the_directory');
33
+ assert.strictEqual(fsEntry.relativePath, '/path/to/the_directory');
34
+ assert.strictEqual(fsEntry.isFile, false);
35
+ assert.strictEqual(fsEntry.isDirectory, true);
36
+ assert.strictEqual(fsEntry.size, 0);
37
+ });
38
+ });
39
+ });
40
+ //# sourceMappingURL=FsEntry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FsEntry.test.js","sourceRoot":"","sources":["../../../src/models/__tests__/FsEntry.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,OAAO,MAAM,YAAY,CAAC;AAEjC,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC;gBAC1B,IAAI,EAAE,cAAc;gBACpB,YAAY,EAAE,gCAAgC;gBAC9C,YAAY,EAAE,uBAAuB;gBACrC,MAAM,EAAE,IAAI;gBACZ,IAAI,EAAE,EAAE;aACT,CAAC,CAAC;YAEH,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;YACjD,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,YAAY,EAAE,gCAAgC,CAAC,CAAC;YAC3E,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,YAAY,EAAE,uBAAuB,CAAC,CAAC;YAClE,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YACzC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;YAC/C,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACvC,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC;gBAC1B,IAAI,EAAE,eAAe;gBACrB,YAAY,EAAE,iCAAiC;gBAC/C,YAAY,EAAE,wBAAwB;gBACtC,MAAM,EAAE,KAAK;gBACb,IAAI,EAAE,CAAC;aACR,CAAC,CAAC;YAEH,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;YAClD,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,YAAY,EAAE,iCAAiC,CAAC,CAAC;YAC5E,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,YAAY,EAAE,wBAAwB,CAAC,CAAC;YACnE,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC1C,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YAC9C,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export { default as FsEntry } from './FsEntry';
@@ -0,0 +1,2 @@
1
+ export { default as FsEntry } from './FsEntry';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,289 @@
1
+ import assert from 'node:assert';
2
+ import { join } from 'node:path';
3
+ import { beforeEach, describe, it } from 'node:test';
4
+ import { FsEntry } from '../../models';
5
+ import traverseDirectory from '../traverseDirectory';
6
+ const prepareFsEntries = (entries, basePath) => entries.map((options) => new FsEntry({
7
+ ...options,
8
+ absolutePath: join(basePath, options.relativePath),
9
+ }));
10
+ describe('traverseDirectory', () => {
11
+ describe('when path does not exist', () => {
12
+ const invalidDirPath = join(import.meta.dirname, 'invalid/path');
13
+ it('is rejected with error', async () => {
14
+ await assert.rejects(() => traverseDirectory(invalidDirPath, () => { }), {
15
+ message: `Directory "${invalidDirPath}" does not exist`,
16
+ });
17
+ });
18
+ });
19
+ describe('when path corresponds to file', () => {
20
+ const filePath = import.meta.filename;
21
+ it('is rejected with error', async () => {
22
+ await assert.rejects(() => traverseDirectory(filePath, () => { }), {
23
+ message: `Directory "${filePath}" does not exist`,
24
+ });
25
+ });
26
+ });
27
+ describe('when path corresponds to directory', () => {
28
+ const dirPath = join(import.meta.dirname, '../../../test/resources/test_directory');
29
+ describe('when callback is executed without rejections for each element', () => {
30
+ let fsEntries = [];
31
+ let returnValue;
32
+ beforeEach(async () => {
33
+ fsEntries = [];
34
+ returnValue = traverseDirectory(dirPath, (fsEntry) => {
35
+ fsEntries.push(fsEntry);
36
+ });
37
+ });
38
+ it('is resolved to "undefined"', async () => {
39
+ await assert.strictEqual(await returnValue, undefined);
40
+ });
41
+ it('triggers callback for each file and directory in source directory tree', async () => {
42
+ await returnValue;
43
+ const expectedFsEntries = prepareFsEntries([
44
+ {
45
+ name: '.dot_file',
46
+ relativePath: '.dot_file',
47
+ isFile: true,
48
+ size: 9,
49
+ },
50
+ {
51
+ name: 'dir_1',
52
+ relativePath: 'dir_1',
53
+ isFile: false,
54
+ size: 0,
55
+ },
56
+ {
57
+ name: 'file_1_1.txt',
58
+ relativePath: join('dir_1', 'file_1_1.txt'),
59
+ isFile: true,
60
+ size: 12,
61
+ },
62
+ {
63
+ name: 'file_1_2.txt',
64
+ relativePath: join('dir_1', 'file_1_2.txt'),
65
+ isFile: true,
66
+ size: 12,
67
+ },
68
+ {
69
+ name: 'dir_2',
70
+ relativePath: 'dir_2',
71
+ isFile: false,
72
+ size: 0,
73
+ },
74
+ {
75
+ name: 'dir_2_1',
76
+ relativePath: join('dir_2', 'dir_2_1'),
77
+ isFile: false,
78
+ size: 0,
79
+ },
80
+ {
81
+ name: 'file_2_1_1.txt',
82
+ relativePath: join('dir_2', 'dir_2_1', 'file_2_1_1.txt'),
83
+ isFile: true,
84
+ size: 14,
85
+ },
86
+ {
87
+ name: 'file_2_1_2.txt',
88
+ relativePath: join('dir_2', 'dir_2_1', 'file_2_1_2.txt'),
89
+ isFile: true,
90
+ size: 14,
91
+ },
92
+ {
93
+ name: 'dir_2_2',
94
+ relativePath: join('dir_2', 'dir_2_2'),
95
+ isFile: false,
96
+ size: 0,
97
+ },
98
+ {
99
+ name: 'file_2_2_1.txt',
100
+ relativePath: join('dir_2', 'dir_2_2', 'file_2_2_1.txt'),
101
+ isFile: true,
102
+ size: 14,
103
+ },
104
+ {
105
+ name: 'file_2_2_2.txt',
106
+ relativePath: join('dir_2', 'dir_2_2', 'file_2_2_2.txt'),
107
+ isFile: true,
108
+ size: 14,
109
+ },
110
+ {
111
+ name: 'file_2_1.txt',
112
+ relativePath: join('dir_2', 'file_2_1.txt'),
113
+ isFile: true,
114
+ size: 12,
115
+ },
116
+ {
117
+ name: 'file_2_2.txt',
118
+ relativePath: join('dir_2', 'file_2_2.txt'),
119
+ isFile: true,
120
+ size: 12,
121
+ },
122
+ {
123
+ name: 'file_1.txt',
124
+ relativePath: 'file_1.txt',
125
+ isFile: true,
126
+ size: 10,
127
+ },
128
+ {
129
+ name: 'file_2.txt',
130
+ relativePath: 'file_2.txt',
131
+ isFile: true,
132
+ size: 10,
133
+ },
134
+ ], dirPath);
135
+ assert.ok(fsEntries.every((fsEntry) => fsEntry instanceof FsEntry));
136
+ assert.deepStrictEqual(fsEntries, expectedFsEntries);
137
+ });
138
+ });
139
+ describe('when async callback is passed', () => {
140
+ let returnValue;
141
+ const logs = [];
142
+ beforeEach(async () => {
143
+ returnValue = traverseDirectory(dirPath, async ({ name }) => {
144
+ logs.push(`Processing ${name}`);
145
+ await new Promise((resolve) => setTimeout(resolve, 1));
146
+ logs.push(`Processed ${name}`);
147
+ });
148
+ });
149
+ it('waits current entry Promise resolving before calling callback on next entry', async () => {
150
+ await returnValue;
151
+ const expectedLogs = [
152
+ 'Processing .dot_file',
153
+ 'Processed .dot_file',
154
+ 'Processing dir_1',
155
+ 'Processed dir_1',
156
+ 'Processing file_1_1.txt',
157
+ 'Processed file_1_1.txt',
158
+ 'Processing file_1_2.txt',
159
+ 'Processed file_1_2.txt',
160
+ 'Processing dir_2',
161
+ 'Processed dir_2',
162
+ 'Processing dir_2_1',
163
+ 'Processed dir_2_1',
164
+ 'Processing file_2_1_1.txt',
165
+ 'Processed file_2_1_1.txt',
166
+ 'Processing file_2_1_2.txt',
167
+ 'Processed file_2_1_2.txt',
168
+ 'Processing dir_2_2',
169
+ 'Processed dir_2_2',
170
+ 'Processing file_2_2_1.txt',
171
+ 'Processed file_2_2_1.txt',
172
+ 'Processing file_2_2_2.txt',
173
+ 'Processed file_2_2_2.txt',
174
+ 'Processing file_2_1.txt',
175
+ 'Processed file_2_1.txt',
176
+ 'Processing file_2_2.txt',
177
+ 'Processed file_2_2.txt',
178
+ 'Processing file_1.txt',
179
+ 'Processed file_1.txt',
180
+ 'Processing file_2.txt',
181
+ 'Processed file_2.txt',
182
+ ];
183
+ assert.deepStrictEqual(logs, expectedLogs);
184
+ });
185
+ });
186
+ describe('when callback is rejected for some file or directory in source directory tree', () => {
187
+ let fsEntries = [];
188
+ let returnValue;
189
+ beforeEach(async () => {
190
+ fsEntries = [];
191
+ returnValue = traverseDirectory(dirPath, (fsEntry) => {
192
+ if (fsEntry.name === 'file_1_2.txt') {
193
+ throw new Error('Test error');
194
+ }
195
+ fsEntries.push(fsEntry);
196
+ });
197
+ });
198
+ it('is rejected with corresponding error', async () => {
199
+ await assert.rejects(() => returnValue, { message: 'Test error' });
200
+ });
201
+ it("doesn't trigger callback after rejected file or directory", async () => {
202
+ try {
203
+ await returnValue;
204
+ }
205
+ catch {
206
+ // ignored
207
+ }
208
+ const expectedFsEntries = prepareFsEntries([
209
+ {
210
+ name: '.dot_file',
211
+ relativePath: '.dot_file',
212
+ isFile: true,
213
+ size: 9,
214
+ },
215
+ {
216
+ name: 'dir_1',
217
+ relativePath: 'dir_1',
218
+ isFile: false,
219
+ size: 0,
220
+ },
221
+ {
222
+ name: 'file_1_1.txt',
223
+ relativePath: join('dir_1', 'file_1_1.txt'),
224
+ isFile: true,
225
+ size: 12,
226
+ },
227
+ ], dirPath);
228
+ assert.deepStrictEqual(fsEntries, expectedFsEntries);
229
+ });
230
+ });
231
+ describe('when "skipEntryChildrenIteration" is called for some directory', () => {
232
+ it("doesn't trigger callback for children of that directory", async () => {
233
+ const fsEntries = [];
234
+ await traverseDirectory(dirPath, (fsEntry, { skipEntryChildrenIteration }) => {
235
+ fsEntries.push(fsEntry);
236
+ if (fsEntry.name === 'dir_2') {
237
+ skipEntryChildrenIteration();
238
+ }
239
+ });
240
+ const expectedFsEntries = prepareFsEntries([
241
+ {
242
+ name: '.dot_file',
243
+ relativePath: '.dot_file',
244
+ isFile: true,
245
+ size: 9,
246
+ },
247
+ {
248
+ name: 'dir_1',
249
+ relativePath: 'dir_1',
250
+ isFile: false,
251
+ size: 0,
252
+ },
253
+ {
254
+ name: 'file_1_1.txt',
255
+ relativePath: join('dir_1', 'file_1_1.txt'),
256
+ isFile: true,
257
+ size: 12,
258
+ },
259
+ {
260
+ name: 'file_1_2.txt',
261
+ relativePath: join('dir_1', 'file_1_2.txt'),
262
+ isFile: true,
263
+ size: 12,
264
+ },
265
+ {
266
+ name: 'dir_2',
267
+ relativePath: 'dir_2',
268
+ isFile: false,
269
+ size: 0,
270
+ },
271
+ {
272
+ name: 'file_1.txt',
273
+ relativePath: 'file_1.txt',
274
+ isFile: true,
275
+ size: 10,
276
+ },
277
+ {
278
+ name: 'file_2.txt',
279
+ relativePath: 'file_2.txt',
280
+ isFile: true,
281
+ size: 10,
282
+ },
283
+ ], dirPath);
284
+ assert.deepStrictEqual(fsEntries, expectedFsEntries);
285
+ });
286
+ });
287
+ });
288
+ });
289
+ //# sourceMappingURL=traverseDirectory.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traverseDirectory.test.js","sourceRoot":"","sources":["../../../src/traverseDirectory/__tests__/traverseDirectory.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { default } from './traverseDirectory';
@@ -0,0 +1,2 @@
1
+ export { default } from './traverseDirectory';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/traverseDirectory/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { OnEachChild } from './types';
2
+ declare const traverseDirectory: (dirPath: string, onEachChild: OnEachChild) => Promise<void>;
3
+ export default traverseDirectory;
@@ -0,0 +1,10 @@
1
+ import { directoryExist } from '../utils/fs';
2
+ import traverseDirectoryRecursive from './traverseDirectoryRecursive';
3
+ const traverseDirectory = async (dirPath, onEachChild) => {
4
+ if (!(await directoryExist(dirPath))) {
5
+ throw new Error(`Directory "${dirPath}" does not exist`);
6
+ }
7
+ await traverseDirectoryRecursive(dirPath, null, onEachChild);
8
+ };
9
+ export default traverseDirectory;
10
+ //# sourceMappingURL=traverseDirectory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traverseDirectory.js","sourceRoot":"","sources":["../../src/traverseDirectory/traverseDirectory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,0BAA0B,MAAM,8BAA8B,CAAC;AAGtE,MAAM,iBAAiB,GAAG,KAAK,EAAE,OAAe,EAAE,WAAwB,EAAiB,EAAE;IAC3F,IAAI,CAAC,CAAC,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,cAAc,OAAO,kBAAkB,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,0BAA0B,CAAC,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;AAC/D,CAAC,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { OnEachChild } from './types';
2
+ declare const traverseDirectoryRecursive: (absoluteDirPath: string, relativeDirPath: string | null, onEachChild: OnEachChild) => Promise<void>;
3
+ export default traverseDirectoryRecursive;
@@ -0,0 +1,31 @@
1
+ import { join } from 'node:path';
2
+ import { stat, readdir } from 'node:fs/promises';
3
+ import { FsEntry } from '../models';
4
+ import { iterateInSeries } from '../utils/iteration';
5
+ const traverseDirectoryRecursive = async (absoluteDirPath, relativeDirPath, onEachChild) => {
6
+ const entries = await readdir(absoluteDirPath);
7
+ await iterateInSeries(entries, async (name) => {
8
+ const absolutePath = join(absoluteDirPath, name);
9
+ const relativePath = relativeDirPath ? join(relativeDirPath, name) : name;
10
+ const stats = await stat(absolutePath);
11
+ const isFile = stats.isFile();
12
+ const size = isFile ? stats.size : 0;
13
+ const fsEntry = new FsEntry({
14
+ name,
15
+ absolutePath,
16
+ relativePath,
17
+ isFile,
18
+ size,
19
+ });
20
+ let iterateEntry = fsEntry.isDirectory;
21
+ const skipEntryChildrenIteration = () => {
22
+ iterateEntry = false;
23
+ };
24
+ await onEachChild(fsEntry, { skipEntryChildrenIteration });
25
+ if (iterateEntry) {
26
+ await traverseDirectoryRecursive(absolutePath, relativePath, onEachChild);
27
+ }
28
+ });
29
+ };
30
+ export default traverseDirectoryRecursive;
31
+ //# sourceMappingURL=traverseDirectoryRecursive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traverseDirectoryRecursive.js","sourceRoot":"","sources":["../../src/traverseDirectory/traverseDirectoryRecursive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGrD,MAAM,0BAA0B,GAAG,KAAK,EACtC,eAAuB,EACvB,eAA8B,EAC9B,WAAwB,EACT,EAAE;IACjB,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;IAE/C,MAAM,eAAe,CAAC,OAAO,EAAE,KAAK,EAAE,IAAY,EAAE,EAAE;QACpD,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;QACjD,MAAM,YAAY,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAE1E,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAErC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC;YAC1B,IAAI;YACJ,YAAY;YACZ,YAAY;YACZ,MAAM;YACN,IAAI;SACL,CAAC,CAAC;QAEH,IAAI,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;QAEvC,MAAM,0BAA0B,GAAG,GAAG,EAAE;YACtC,YAAY,GAAG,KAAK,CAAC;QACvB,CAAC,CAAC;QAEF,MAAM,WAAW,CAAC,OAAO,EAAE,EAAE,0BAA0B,EAAE,CAAC,CAAC;QAE3D,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,0BAA0B,CAAC,YAAY,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,eAAe,0BAA0B,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { FsEntry } from '../models';
2
+ type OnEachChildOptions = {
3
+ skipEntryChildrenIteration: () => void;
4
+ };
5
+ export type OnEachChild = (fsEntry: FsEntry, options: OnEachChildOptions) => void | Promise<void>;
6
+ export {};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/traverseDirectory/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ import assert from 'node:assert';
2
+ import { join } from 'node:path';
3
+ import { describe, it } from 'node:test';
4
+ import directoryExist from '../directoryExist';
5
+ describe('utils > fs > directoryExist', () => {
6
+ describe('when path does not exist', () => {
7
+ const invalidPath = join(import.meta.dirname, 'invalid/path');
8
+ it('returns false', async () => {
9
+ assert.strictEqual(await directoryExist(invalidPath), false);
10
+ });
11
+ });
12
+ describe('when path corresponds to file', () => {
13
+ const filePath = import.meta.filename;
14
+ it('returns false', async () => {
15
+ assert.strictEqual(await directoryExist(filePath), false);
16
+ });
17
+ });
18
+ describe('when path corresponds to directory', () => {
19
+ const dirPath = import.meta.dirname;
20
+ it('returns true', async () => {
21
+ assert.strictEqual(await directoryExist(dirPath), true);
22
+ });
23
+ });
24
+ });
25
+ //# sourceMappingURL=directoryExist.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directoryExist.test.js","sourceRoot":"","sources":["../../../../src/utils/fs/__tests__/directoryExist.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,cAAc,MAAM,mBAAmB,CAAC;AAE/C,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE;IAC3C,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACxC,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;QAE9D,EAAE,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;YAC7B,MAAM,CAAC,WAAW,CAAC,MAAM,cAAc,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;QAC7C,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;QAEtC,EAAE,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;YAC7B,MAAM,CAAC,WAAW,CAAC,MAAM,cAAc,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAClD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;QAEpC,EAAE,CAAC,cAAc,EAAE,KAAK,IAAI,EAAE;YAC5B,MAAM,CAAC,WAAW,CAAC,MAAM,cAAc,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ declare const directoryExist: (path: string) => Promise<boolean>;
2
+ export default directoryExist;
@@ -0,0 +1,12 @@
1
+ import { stat } from 'node:fs/promises';
2
+ const directoryExist = async (path) => {
3
+ try {
4
+ const stats = await stat(path);
5
+ return stats.isDirectory();
6
+ }
7
+ catch {
8
+ return false;
9
+ }
10
+ };
11
+ export default directoryExist;
12
+ //# sourceMappingURL=directoryExist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directoryExist.js","sourceRoot":"","sources":["../../../src/utils/fs/directoryExist.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,MAAM,cAAc,GAAG,KAAK,EAAE,IAAY,EAAoB,EAAE;IAC9D,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -0,0 +1 @@
1
+ export { default as directoryExist } from './directoryExist';
@@ -0,0 +1,2 @@
1
+ export { default as directoryExist } from './directoryExist';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/fs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,65 @@
1
+ import assert from 'node:assert';
2
+ import { beforeEach, describe, it } from 'node:test';
3
+ import iterateInSeries from '../iterateInSeries';
4
+ describe('utils > iteration > iterateInSeries', () => {
5
+ let sourceArray = [];
6
+ let logs = [];
7
+ beforeEach(() => {
8
+ sourceArray = ['a', 'b', 'c'];
9
+ logs = [];
10
+ });
11
+ describe('when sync callback is passed', () => {
12
+ beforeEach(async () => {
13
+ await iterateInSeries(sourceArray, (element, index) => {
14
+ logs.push(`processed ${element}:${index}`);
15
+ });
16
+ });
17
+ it('calls callback function for each array element in series', () => {
18
+ assert.deepStrictEqual(logs, ['processed a:0', 'processed b:1', 'processed c:2']);
19
+ });
20
+ });
21
+ describe('when async callback is passed', () => {
22
+ beforeEach(async () => {
23
+ await iterateInSeries(sourceArray, async (element) => {
24
+ logs.push(`processing ${element}`);
25
+ await new Promise((resolve) => setTimeout(resolve, 1));
26
+ logs.push(`processed ${element}`);
27
+ });
28
+ });
29
+ it('waits current element Promise resolving before calling callback on next element', () => {
30
+ assert.deepStrictEqual(logs, [
31
+ 'processing a',
32
+ 'processed a',
33
+ 'processing b',
34
+ 'processed b',
35
+ 'processing c',
36
+ 'processed c',
37
+ ]);
38
+ });
39
+ });
40
+ describe('when callback rejects with error for some element', () => {
41
+ let returnValue;
42
+ beforeEach(async () => {
43
+ returnValue = iterateInSeries(['a', 'b', 'c'], async (element) => {
44
+ logs.push(`processing ${element}`);
45
+ if (element === 'b') {
46
+ throw new Error(`Test error on element ${element}`);
47
+ }
48
+ logs.push(`processed ${element}`);
49
+ });
50
+ });
51
+ it('is rejected with corresponding error', async () => {
52
+ await assert.rejects(() => returnValue, { message: 'Test error on element b' });
53
+ });
54
+ it("doesn't trigger callback after rejected element", async () => {
55
+ try {
56
+ await returnValue;
57
+ }
58
+ catch {
59
+ // ignored
60
+ }
61
+ assert.deepStrictEqual(logs, ['processing a', 'processed a', 'processing b']);
62
+ });
63
+ });
64
+ });
65
+ //# sourceMappingURL=iterateInSeries.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iterateInSeries.test.js","sourceRoot":"","sources":["../../../../src/utils/iteration/__tests__/iterateInSeries.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { default as iterateInSeries } from './iterateInSeries';
@@ -0,0 +1,2 @@
1
+ export { default as iterateInSeries } from './iterateInSeries';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/iteration/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,2 @@
1
+ declare const iterateInSeries: <T>(array: T[], callback: (element: T, index?: number) => void | Promise<void>) => Promise<void>;
2
+ export default iterateInSeries;
@@ -0,0 +1,7 @@
1
+ const iterateInSeries = async (array, callback) => {
2
+ for (let index = 0; index < array.length; index += 1) {
3
+ await callback(array[index], index);
4
+ }
5
+ };
6
+ export default iterateInSeries;
7
+ //# sourceMappingURL=iterateInSeries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iterateInSeries.js","sourceRoot":"","sources":["../../../src/utils/iteration/iterateInSeries.ts"],"names":[],"mappings":"AAAA,MAAM,eAAe,GAAG,KAAK,EAC3B,KAAU,EACV,QAA8D,EAC/C,EAAE;IACjB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrD,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;AACH,CAAC,CAAC;AAEF,eAAe,eAAe,CAAC"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@aminzer/traverse-directory",
3
+ "version": "1.0.0",
4
+ "description": "Utility for directory child entries recursive iteration",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "type": "module",
9
+ "keywords": [
10
+ "traverse",
11
+ "directory",
12
+ "fs",
13
+ "filesystem",
14
+ "file",
15
+ "folder",
16
+ "iterate",
17
+ "recursion",
18
+ "recursive"
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/aminzer/traverse-directory.git"
23
+ },
24
+ "license": "MIT",
25
+ "author": "aminzer",
26
+ "main": "dist/index.js",
27
+ "types": "dist/index.d.ts",
28
+ "files": [
29
+ "dist"
30
+ ],
31
+ "scripts": {
32
+ "build": "tsc --project tsconfig.build.json",
33
+ "build:watch": "npm run build -- --watch",
34
+ "clean": "rimraf dist",
35
+ "codestyle": "run-p lint typescript:check",
36
+ "lint": "eslint src/**/*.ts",
37
+ "lint:fix": "npm run lint -- --fix",
38
+ "prepare": "npm run rebuild",
39
+ "rebuild": "run-s clean build",
40
+ "test": "tsx --test src/**/*.test.ts",
41
+ "typescript:check": "tsc --project tsconfig.json --noEmit"
42
+ },
43
+ "devDependencies": {
44
+ "@eslint/js": "^9.36.0",
45
+ "@types/node": "^24.5.2",
46
+ "eslint": "^9.36.0",
47
+ "eslint-config-prettier": "^10.1.8",
48
+ "eslint-plugin-prettier": "^5.5.4",
49
+ "npm-run-all": "^4.1.5",
50
+ "prettier": "^3.6.2",
51
+ "rimraf": "^6.0.1",
52
+ "tsx": "^4.20.6",
53
+ "typescript": "^5.9.2",
54
+ "typescript-eslint": "^8.44.1"
55
+ },
56
+ "engines": {
57
+ "node": ">=22.0.0"
58
+ }
59
+ }