@nojaja/dirwalker 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.
- package/LICENSE +21 -0
- package/README.md +547 -0
- package/dist/DirWalker.d.ts +96 -0
- package/dist/DirWalker.d.ts.map +1 -0
- package/dist/dirwalker.bundle.js +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/package.json +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nojaja
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
# dir-walker
|
|
2
|
+
|
|
3
|
+
A lightweight, flexible directory walker utility for Node.js with pattern matching support.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
**dir-walker** is a TypeScript-based utility for recursively walking through file systems with built-in pattern matching capabilities. It provides a simple, efficient, and safe API for traversing directories while filtering out unwanted files and directories using regular expressions.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- π **Fast & Efficient**: Asynchronous recursive directory traversal with proper error handling
|
|
12
|
+
- π― **Pattern Matching**: Built-in support for excluding directories and file extensions using RegExp patterns
|
|
13
|
+
- π **Safe**: Automatically skips symbolic links to prevent infinite loops and circular references
|
|
14
|
+
- π¦ **Zero Dependencies**: No external runtime dependencies - fully self-contained
|
|
15
|
+
- π¨ **TypeScript**: Full TypeScript support with comprehensive type definitions and JSDoc annotations
|
|
16
|
+
- β‘ **ESM Ready**: Native ES Module support with proper bundling for both CommonJS and UMD environments
|
|
17
|
+
- π **Debug Mode**: Optional debug logging to track directory traversal and pattern matching
|
|
18
|
+
- π **Async-first**: Supports both synchronous and asynchronous file processing callbacks
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install @nojaja/dirwalker
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or with yarn:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
yarn add @nojaja/dirwalker
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Requirements
|
|
33
|
+
|
|
34
|
+
- Node.js 18.0.0 or higher
|
|
35
|
+
- npm 6.0.0 or higher (or yarn equivalent)
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { DirWalker } from '@nojaja/dirwalker';
|
|
41
|
+
|
|
42
|
+
const walker = new DirWalker();
|
|
43
|
+
|
|
44
|
+
const fileCount = await walker.walk(
|
|
45
|
+
'./my-directory',
|
|
46
|
+
{
|
|
47
|
+
excludeDirs: [/node_modules/, /\.git/],
|
|
48
|
+
excludeExt: [/\.log$/]
|
|
49
|
+
},
|
|
50
|
+
(relativePath, settings) => {
|
|
51
|
+
console.log('Found file:', relativePath);
|
|
52
|
+
},
|
|
53
|
+
(error) => {
|
|
54
|
+
console.error('Error:', error);
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
console.log(`Processed ${fileCount} files`);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Project Structure
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
dir-walker/
|
|
65
|
+
βββ src/
|
|
66
|
+
β βββ DirWalker.ts # Main directory walker class (247 lines)
|
|
67
|
+
β βββ PatternMatcher.ts # Pattern matching utility (48 lines)
|
|
68
|
+
β βββ index.ts # Public API exports
|
|
69
|
+
βββ test/
|
|
70
|
+
β βββ unit/
|
|
71
|
+
β β βββ DirWalker.test.ts # DirWalker unit tests (336 cases)
|
|
72
|
+
β β βββ PatternMatcher.test.ts # PatternMatcher unit tests
|
|
73
|
+
β βββ fixtures/ # Test fixtures and sample data
|
|
74
|
+
βββ dist/ # Compiled output (generated at build time)
|
|
75
|
+
βββ docs/ # Generated API documentation (TypeDoc)
|
|
76
|
+
βββ package.json # NPM configuration and scripts
|
|
77
|
+
βββ tsconfig.json # TypeScript configuration (strict mode)
|
|
78
|
+
βββ webpack.config.js # Webpack bundling configuration
|
|
79
|
+
βββ jest.unit.config.js # Jest test configuration
|
|
80
|
+
βββ CHANGELOG.md # Version history and release notes
|
|
81
|
+
βββ README.md # This file
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Technology Stack
|
|
85
|
+
|
|
86
|
+
- **Language**: TypeScript 5.3.3 (strict mode enabled)
|
|
87
|
+
- **Runtime**: Node.js 18.0.0+
|
|
88
|
+
- **Bundler**: Webpack 5.99.8 (UMD + CommonJS bundling)
|
|
89
|
+
- **Test Framework**: Jest 29.6.1 with ts-jest
|
|
90
|
+
- **Type Checking**: TypeScript with strict mode
|
|
91
|
+
- **Linting**: ESLint 8.45.0 with TypeScript support
|
|
92
|
+
- **Code Style**: Prettier 3.0.0
|
|
93
|
+
- **Documentation**: TypeDoc 0.28.15
|
|
94
|
+
|
|
95
|
+
## API Reference
|
|
96
|
+
|
|
97
|
+
### Class: `DirWalker`
|
|
98
|
+
|
|
99
|
+
The main class for directory walking operations. Exports a default instance and named export.
|
|
100
|
+
|
|
101
|
+
#### Constructor
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
constructor(debug?: boolean)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Parameters:**
|
|
108
|
+
- `debug` (optional, boolean): Enable debug logging for traversal operations. Default: `false`
|
|
109
|
+
|
|
110
|
+
**Example:**
|
|
111
|
+
```typescript
|
|
112
|
+
const walker = new DirWalker(); // Default, no debug
|
|
113
|
+
const walkerDebug = new DirWalker(true); // With debug logging enabled
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### Methods
|
|
117
|
+
|
|
118
|
+
##### `walk(targetPath, settings, fileCallback, errCallback): Promise<number>`
|
|
119
|
+
|
|
120
|
+
Recursively walks through a directory and processes files matching the specified criteria.
|
|
121
|
+
|
|
122
|
+
**Parameters:**
|
|
123
|
+
|
|
124
|
+
| Parameter | Type | Description |
|
|
125
|
+
|-----------|------|-------------|
|
|
126
|
+
| `targetPath` | `string` | Root directory path (absolute or relative). The callback receives relative paths from this base. |
|
|
127
|
+
| `settings` | `WalkSettings` | Configuration object with exclude patterns. Both fields are optional and default to empty arrays. |
|
|
128
|
+
| `fileCallback` | `FileCallback` | Called for each matched file. Supports async operations. |
|
|
129
|
+
| `errCallback` | `ErrorCallback` (optional) | Called when errors occur during traversal. If omitted, errors are logged. |
|
|
130
|
+
|
|
131
|
+
**Returns:** `Promise<number>` - Total count of files processed (matched)
|
|
132
|
+
|
|
133
|
+
**WalkSettings Interface:**
|
|
134
|
+
```typescript
|
|
135
|
+
interface WalkSettings {
|
|
136
|
+
excludeDirs?: RegExp[]; // Patterns to exclude directories
|
|
137
|
+
excludeExt?: RegExp[]; // Patterns to exclude file extensions
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**FileCallback Type:**
|
|
142
|
+
```typescript
|
|
143
|
+
type FileCallback = (
|
|
144
|
+
relativePath: string, // Relative path from targetPath
|
|
145
|
+
settings: WalkSettings // Settings object used
|
|
146
|
+
) => void | Promise<void>; // Can be synchronous or async
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**ErrorCallback Type:**
|
|
150
|
+
```typescript
|
|
151
|
+
type ErrorCallback = (error: Error) => void;
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Class: `PatternMatcher`
|
|
155
|
+
|
|
156
|
+
Utility class for pattern matching operations. Typically used internally by DirWalker.
|
|
157
|
+
|
|
158
|
+
#### Constructor
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
constructor(debug?: boolean)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### Methods
|
|
165
|
+
|
|
166
|
+
##### `match(text: string, patterns?: RegExp[]): boolean`
|
|
167
|
+
|
|
168
|
+
Tests if text matches any of the provided patterns.
|
|
169
|
+
|
|
170
|
+
**Parameters:**
|
|
171
|
+
- `text` - The string to test
|
|
172
|
+
- `patterns` - Array of RegExp patterns to match against
|
|
173
|
+
|
|
174
|
+
**Returns:** `true` if any pattern matches, `false` otherwise
|
|
175
|
+
|
|
176
|
+
##### `matchEx(text: string, patterns?: RegExp[]): RegExp | null`
|
|
177
|
+
|
|
178
|
+
Tests if text matches any patterns and returns the matching pattern.
|
|
179
|
+
|
|
180
|
+
**Parameters:**
|
|
181
|
+
- `text` - The string to test
|
|
182
|
+
- `patterns` - Array of RegExp patterns to match against
|
|
183
|
+
|
|
184
|
+
**Returns:** The matching RegExp object or `null` if no match found
|
|
185
|
+
|
|
186
|
+
## Usage Examples
|
|
187
|
+
|
|
188
|
+
### Basic Usage - Simple File Listing
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import { DirWalker } from '@nojaja/dirwalker';
|
|
192
|
+
|
|
193
|
+
const walker = new DirWalker();
|
|
194
|
+
const fileCount = await walker.walk(
|
|
195
|
+
'./src',
|
|
196
|
+
{},
|
|
197
|
+
(relativePath) => {
|
|
198
|
+
console.log(relativePath);
|
|
199
|
+
},
|
|
200
|
+
(error) => {
|
|
201
|
+
console.error('Error:', error);
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
console.log(`Total files processed: ${fileCount}`);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Excluding Directories
|
|
209
|
+
|
|
210
|
+
Common patterns to exclude:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
const walker = new DirWalker();
|
|
214
|
+
|
|
215
|
+
await walker.walk(
|
|
216
|
+
'./project',
|
|
217
|
+
{
|
|
218
|
+
excludeDirs: [
|
|
219
|
+
/node_modules/, // npm dependencies
|
|
220
|
+
/\.git/, // git repository
|
|
221
|
+
/dist/, // build output
|
|
222
|
+
/coverage/, // test coverage
|
|
223
|
+
/__pycache__/, // Python cache
|
|
224
|
+
/\.next/, // Next.js build
|
|
225
|
+
/\.venv/ // Python virtual env
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
(relativePath) => {
|
|
229
|
+
console.log('Source file:', relativePath);
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Note:** Directory patterns match the full file path, so `node_modules` will match any "node_modules" directory at any level.
|
|
235
|
+
|
|
236
|
+
### Filtering by File Extension
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
const walker = new DirWalker();
|
|
240
|
+
|
|
241
|
+
await walker.walk(
|
|
242
|
+
'./src',
|
|
243
|
+
{
|
|
244
|
+
excludeExt: [
|
|
245
|
+
/\.test\.ts$/, // Jest test files
|
|
246
|
+
/\.spec\.ts$/, // Jasmine spec files
|
|
247
|
+
/\.d\.ts$/, // TypeScript declarations
|
|
248
|
+
/\.map$/, // Source maps
|
|
249
|
+
/\.log$/ // Log files
|
|
250
|
+
]
|
|
251
|
+
},
|
|
252
|
+
(relativePath) => {
|
|
253
|
+
console.log('Production file:', relativePath);
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Combining Directory and Extension Filters
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
const walker = new DirWalker();
|
|
262
|
+
|
|
263
|
+
await walker.walk(
|
|
264
|
+
'./project',
|
|
265
|
+
{
|
|
266
|
+
excludeDirs: [/node_modules/, /\.git/, /dist/],
|
|
267
|
+
excludeExt: [/\.test\.ts$/, /\.d\.ts$/, /\.log$/]
|
|
268
|
+
},
|
|
269
|
+
(relativePath) => {
|
|
270
|
+
console.log('Production source:', relativePath);
|
|
271
|
+
}
|
|
272
|
+
);
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Processing Files with Async Operations
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
import { DirWalker } from '@nojaja/dirwalker';
|
|
279
|
+
import { readFile } from 'fs/promises';
|
|
280
|
+
import * as path from 'path';
|
|
281
|
+
|
|
282
|
+
const walker = new DirWalker();
|
|
283
|
+
const results = [];
|
|
284
|
+
|
|
285
|
+
await walker.walk(
|
|
286
|
+
'./docs',
|
|
287
|
+
{
|
|
288
|
+
excludeExt: [/^(?!.*\.md$)/] // Only markdown files
|
|
289
|
+
},
|
|
290
|
+
async (filePath) => {
|
|
291
|
+
try {
|
|
292
|
+
const content = await readFile(filePath, 'utf-8');
|
|
293
|
+
results.push({
|
|
294
|
+
file: filePath,
|
|
295
|
+
lines: content.split('\n').length,
|
|
296
|
+
size: content.length
|
|
297
|
+
});
|
|
298
|
+
} catch (error) {
|
|
299
|
+
console.error(`Failed to read ${filePath}:`, error);
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
(error) => {
|
|
303
|
+
console.error('Walk error:', error);
|
|
304
|
+
}
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
console.log('Results:', results);
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Counting Files by Extension
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
import * as path from 'path';
|
|
314
|
+
|
|
315
|
+
const walker = new DirWalker();
|
|
316
|
+
const stats = new Map<string, number>();
|
|
317
|
+
|
|
318
|
+
await walker.walk(
|
|
319
|
+
'./src',
|
|
320
|
+
{ excludeDirs: [/node_modules/] },
|
|
321
|
+
(filePath) => {
|
|
322
|
+
const ext = path.extname(filePath) || '(no extension)';
|
|
323
|
+
stats.set(ext, (stats.get(ext) || 0) + 1);
|
|
324
|
+
}
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
console.log('Files by extension:');
|
|
328
|
+
for (const [ext, count] of stats) {
|
|
329
|
+
console.log(` ${ext}: ${count}`);
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Debug Mode
|
|
334
|
+
|
|
335
|
+
Enable debug logging to track directory traversal:
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
import { DirWalker } from '@nojaja/dirwalker';
|
|
339
|
+
|
|
340
|
+
const walker = new DirWalker(true); // Enable debug logging
|
|
341
|
+
|
|
342
|
+
await walker.walk(
|
|
343
|
+
'./src',
|
|
344
|
+
{ excludeDirs: [/node_modules/] },
|
|
345
|
+
(file) => {
|
|
346
|
+
console.log('Processing:', file);
|
|
347
|
+
}
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
// Debug output example:
|
|
351
|
+
// γ·γ³γγͺγγ―γͺγ³γ―γγΉγγγ: /path/to/symlink
|
|
352
|
+
// γγ‘γ€γ«ηΊθ¦: /path/to/file.ts
|
|
353
|
+
// γγ£γ¬γ―γγͺθͺγΏεγγ¨γ©γΌ: ... (if any)
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## Error Handling
|
|
357
|
+
|
|
358
|
+
The library provides flexible error handling through callbacks:
|
|
359
|
+
|
|
360
|
+
### Method 1: Error Callback
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
await walker.walk(
|
|
364
|
+
'./src',
|
|
365
|
+
{},
|
|
366
|
+
(relativePath) => {
|
|
367
|
+
console.log('Processing:', relativePath);
|
|
368
|
+
},
|
|
369
|
+
(error) => {
|
|
370
|
+
// Custom error handling
|
|
371
|
+
console.error('Walk error:', error.message);
|
|
372
|
+
// Log to file, send alert, etc.
|
|
373
|
+
}
|
|
374
|
+
);
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Method 2: Default Logging
|
|
378
|
+
|
|
379
|
+
If no error callback is provided, errors are logged automatically:
|
|
380
|
+
|
|
381
|
+
```typescript
|
|
382
|
+
await walker.walk(
|
|
383
|
+
'./src',
|
|
384
|
+
{},
|
|
385
|
+
(relativePath) => {
|
|
386
|
+
console.log('Processing:', relativePath);
|
|
387
|
+
}
|
|
388
|
+
// Errors will be logged to console automatically
|
|
389
|
+
);
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Error Scenarios Handled
|
|
393
|
+
|
|
394
|
+
- **Directory not found** - Directory read error (ENOENT)
|
|
395
|
+
- **Permission denied** - File access errors (EACCES)
|
|
396
|
+
- **Invalid path** - Stat operation failures
|
|
397
|
+
- **Symbolic links** - Automatically skipped (not an error)
|
|
398
|
+
- **RegExp errors** - Caught and logged in debug mode
|
|
399
|
+
|
|
400
|
+
## Development Setup
|
|
401
|
+
|
|
402
|
+
### Prerequisites
|
|
403
|
+
|
|
404
|
+
- Node.js 18.0.0 or higher
|
|
405
|
+
- npm 10.8.2 or yarn equivalent
|
|
406
|
+
|
|
407
|
+
### Installation
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
# Clone repository
|
|
411
|
+
git clone https://github.com/nojaja/dir-walker.git
|
|
412
|
+
cd dir-walker
|
|
413
|
+
|
|
414
|
+
# Install dependencies
|
|
415
|
+
npm install
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### Development Commands
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
# Run unit tests
|
|
422
|
+
npm run test
|
|
423
|
+
|
|
424
|
+
# Run tests with coverage report
|
|
425
|
+
npm run test:ci
|
|
426
|
+
|
|
427
|
+
# TypeScript type checking
|
|
428
|
+
npm run type-check
|
|
429
|
+
|
|
430
|
+
# Linting with ESLint
|
|
431
|
+
npm run lint
|
|
432
|
+
|
|
433
|
+
# Build production bundle
|
|
434
|
+
npm run build
|
|
435
|
+
|
|
436
|
+
# Build development bundle (with source maps)
|
|
437
|
+
npm run build:dev
|
|
438
|
+
|
|
439
|
+
# Generate API documentation
|
|
440
|
+
npm run docs
|
|
441
|
+
|
|
442
|
+
# Analyze dependency health
|
|
443
|
+
npm run depcruise
|
|
444
|
+
|
|
445
|
+
# Clean build artifacts
|
|
446
|
+
npm run clean
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Build Output
|
|
450
|
+
|
|
451
|
+
The build process generates:
|
|
452
|
+
- **dist/dirwalker.bundle.js** - UMD bundle for universal compatibility
|
|
453
|
+
- **dist/index.d.ts** - TypeScript type definitions
|
|
454
|
+
- **dist/** - Other compiled modules
|
|
455
|
+
|
|
456
|
+
### Project Scripts Reference
|
|
457
|
+
|
|
458
|
+
| Script | Purpose |
|
|
459
|
+
|--------|---------|
|
|
460
|
+
| `build` | Production-optimized Webpack bundle |
|
|
461
|
+
| `build:dev` | Development bundle with source maps |
|
|
462
|
+
| `test` | Run Jest unit tests |
|
|
463
|
+
| `test:ci` | Run tests with coverage reporting |
|
|
464
|
+
| `type-check` | TypeScript type checking |
|
|
465
|
+
| `lint` | ESLint code quality check |
|
|
466
|
+
| `clean` | Remove dist/ directory |
|
|
467
|
+
| `depcruise` | Dependency graph analysis |
|
|
468
|
+
| `docs` | Generate TypeDoc HTML documentation |
|
|
469
|
+
|
|
470
|
+
## TypeScript Support
|
|
471
|
+
|
|
472
|
+
Full TypeScript definitions are included:
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
import {
|
|
476
|
+
DirWalker,
|
|
477
|
+
WalkSettings,
|
|
478
|
+
FileCallback,
|
|
479
|
+
ErrorCallback
|
|
480
|
+
} from '@nojaja/dirwalker';
|
|
481
|
+
|
|
482
|
+
const settings: WalkSettings = {
|
|
483
|
+
excludeDirs: [/node_modules/, /\.git/],
|
|
484
|
+
excludeExt: [/\.log$/, /\.tmp$/]
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
const fileCallback: FileCallback = async (relativePath, settings) => {
|
|
488
|
+
console.log(`Processing: ${relativePath}`);
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
const errorCallback: ErrorCallback = (error) => {
|
|
492
|
+
console.error(`Error: ${error.message}`);
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
const walker = new DirWalker();
|
|
496
|
+
await walker.walk('./src', settings, fileCallback, errorCallback);
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
## Current Status
|
|
500
|
+
|
|
501
|
+
**Version**: 1.0.0 (Initial Release)
|
|
502
|
+
|
|
503
|
+
### β
Completed Features
|
|
504
|
+
- Recursive directory traversal with async/await support
|
|
505
|
+
- RegExp-based pattern matching for directories and file extensions
|
|
506
|
+
- Symbolic link detection and automatic skipping
|
|
507
|
+
- TypeScript with strict mode enabled
|
|
508
|
+
- Comprehensive type definitions and JSDoc annotations
|
|
509
|
+
- Debug mode for detailed logging
|
|
510
|
+
- Unit tests with >80% code coverage
|
|
511
|
+
- Zero external runtime dependencies
|
|
512
|
+
- UMD bundle for universal compatibility
|
|
513
|
+
- Webpack bundling configuration
|
|
514
|
+
|
|
515
|
+
### Performance Characteristics
|
|
516
|
+
- **Memory**: O(depth) - scales with directory tree depth
|
|
517
|
+
- **Speed**: I/O bound - depends on file system performance
|
|
518
|
+
- **Scalability**: Suitable for projects with thousands of files
|
|
519
|
+
- **Async**: Non-blocking using fs/promises
|
|
520
|
+
|
|
521
|
+
## License
|
|
522
|
+
|
|
523
|
+
MIT
|
|
524
|
+
|
|
525
|
+
## Author
|
|
526
|
+
|
|
527
|
+
**nojaja** <free.riccia@gmail.com> ([GitHub](https://github.com/nojaja))
|
|
528
|
+
|
|
529
|
+
## Contributing
|
|
530
|
+
|
|
531
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
532
|
+
|
|
533
|
+
### Development Workflow
|
|
534
|
+
|
|
535
|
+
1. Fork the repository
|
|
536
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
537
|
+
3. Make your changes
|
|
538
|
+
4. Run tests and linting (`npm run test && npm run lint`)
|
|
539
|
+
5. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
540
|
+
6. Push to the branch (`git push origin feature/amazing-feature`)
|
|
541
|
+
7. Open a Pull Request
|
|
542
|
+
|
|
543
|
+
## Repository
|
|
544
|
+
|
|
545
|
+
- **Repository**: [GitHub - nojaja/dir-walker](https://github.com/nojaja/dir-walker)
|
|
546
|
+
- **Issues**: [GitHub Issues](https://github.com/nojaja/dir-walker/issues)
|
|
547
|
+
- **NPM Package**: [@nojaja/dirwalker](https://www.npmjs.com/package/@nojaja/dirwalker)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings for directory walking
|
|
3
|
+
*/
|
|
4
|
+
export interface WalkSettings {
|
|
5
|
+
/** Array of regex patterns for directories to exclude */
|
|
6
|
+
excludeDirs?: RegExp[];
|
|
7
|
+
/** Array of regex patterns for file extensions to exclude */
|
|
8
|
+
excludeExt?: RegExp[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Callback function called for each file found
|
|
12
|
+
* @param relativePath - The relative path of the file from the base directory
|
|
13
|
+
* @param settings - The walk settings object
|
|
14
|
+
*/
|
|
15
|
+
export type FileCallback = (relativePath: string, settings: WalkSettings) => void | Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Callback function called when an error occurs
|
|
18
|
+
* @param error - The error that occurred
|
|
19
|
+
*/
|
|
20
|
+
export type ErrorCallback = (error: Error) => void;
|
|
21
|
+
/**
|
|
22
|
+
* A lightweight directory walker utility with pattern matching support
|
|
23
|
+
*/
|
|
24
|
+
export declare class DirWalker {
|
|
25
|
+
private debug;
|
|
26
|
+
private counter;
|
|
27
|
+
/**
|
|
28
|
+
* Creates a new DirWalker instance
|
|
29
|
+
* @param {boolean} debug - Enable debug logging. Default: false
|
|
30
|
+
*/
|
|
31
|
+
constructor(debug?: boolean);
|
|
32
|
+
/**
|
|
33
|
+
* Recursively walks through a directory and processes files matching the specified criteria
|
|
34
|
+
* @param {string} targetPath - The root directory path to start walking from
|
|
35
|
+
* @param {WalkSettings} settings - Configuration object with exclude patterns
|
|
36
|
+
* @param {FileCallback} fileCallback - Called for each matching file
|
|
37
|
+
* @param {ErrorCallback} errCallback - Called when an error occurs
|
|
38
|
+
* @returns {Promise<number>} Promise that resolves to the total count of processed files
|
|
39
|
+
*/
|
|
40
|
+
walk(targetPath: string, settings: WalkSettings | undefined, fileCallback: FileCallback, errCallback?: ErrorCallback): Promise<number>;
|
|
41
|
+
/**
|
|
42
|
+
* Internal recursive method for directory traversal
|
|
43
|
+
* @private
|
|
44
|
+
* @param {string} targetPath - The current directory path being traversed
|
|
45
|
+
* @param {string} basePath - The original base path for calculating relative paths
|
|
46
|
+
* @param {WalkSettings} settings - Configuration object with exclude patterns
|
|
47
|
+
* @param {FileCallback} fileCallback - Called for each matching file
|
|
48
|
+
* @param {ErrorCallback} errCallback - Called when an error occurs
|
|
49
|
+
* @returns {Promise<void>}
|
|
50
|
+
*/
|
|
51
|
+
private _walk;
|
|
52
|
+
/**
|
|
53
|
+
* Process a single file system entry (file or directory)
|
|
54
|
+
* @private
|
|
55
|
+
* @param {string} filePath - The path to the file system entry
|
|
56
|
+
* @param {string} basePath - The original base path for calculating relative paths
|
|
57
|
+
* @param {WalkSettings} settings - Configuration object with exclude patterns
|
|
58
|
+
* @param {FileCallback} fileCallback - Called for each matching file
|
|
59
|
+
* @param {ErrorCallback} errCallback - Called when an error occurs
|
|
60
|
+
* @returns {Promise<void>}
|
|
61
|
+
*/
|
|
62
|
+
private _processEntry;
|
|
63
|
+
/**
|
|
64
|
+
* Process a directory entry
|
|
65
|
+
* @private
|
|
66
|
+
* @param {string} filePath - The directory path
|
|
67
|
+
* @param {string} basePath - The original base path for calculating relative paths
|
|
68
|
+
* @param {WalkSettings} settings - Configuration object with exclude patterns
|
|
69
|
+
* @param {FileCallback} fileCallback - Called for each matching file
|
|
70
|
+
* @param {ErrorCallback} errCallback - Called when an error occurs
|
|
71
|
+
* @returns {Promise<void>}
|
|
72
|
+
*/
|
|
73
|
+
private _processDirectory;
|
|
74
|
+
/**
|
|
75
|
+
* Process a file entry
|
|
76
|
+
* @private
|
|
77
|
+
* @param {string} filePath - The file path
|
|
78
|
+
* @param {string} basePath - The original base path for calculating relative paths
|
|
79
|
+
* @param {WalkSettings} settings - Configuration object with exclude patterns
|
|
80
|
+
* @param {FileCallback} fileCallback - Called for each matching file
|
|
81
|
+
* @param {ErrorCallback} errCallback - Called when an error occurs
|
|
82
|
+
* @returns {Promise<void>}
|
|
83
|
+
*/
|
|
84
|
+
private _processFile;
|
|
85
|
+
/**
|
|
86
|
+
* Helper method to handle errors
|
|
87
|
+
* @private
|
|
88
|
+
* @param {string} message - Error message context
|
|
89
|
+
* @param {Error} error - The error object to handle
|
|
90
|
+
* @param {ErrorCallback} errCallback - Callback to invoke with the error
|
|
91
|
+
* @returns {void}
|
|
92
|
+
*/
|
|
93
|
+
private _handleError;
|
|
94
|
+
}
|
|
95
|
+
export default DirWalker;
|
|
96
|
+
//# sourceMappingURL=DirWalker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DirWalker.d.ts","sourceRoot":"","sources":["../src/DirWalker.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,YAAY,KACnB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;AAEnD;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAU;IACvB,OAAO,CAAC,OAAO,CAAS;IAExB;;;OAGG;gBACS,KAAK,UAAQ;IAKzB;;;;;;;OAOG;IACG,IAAI,CACR,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,YAAY,YAAsC,EAC5D,YAAY,EAAE,YAAY,EAC1B,WAAW,CAAC,EAAE,aAAa,GAC1B,OAAO,CAAC,MAAM,CAAC;IASlB;;;;;;;;;OASG;YACW,KAAK;IA0CnB;;;;;;;;;OASG;YACW,aAAa;IAyB3B;;;;;;;;;OASG;YACW,iBAAiB;IAmB/B;;;;;;;;;OASG;YACW,YAAY;IAmC1B;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY;CAWrB;AAED,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.DirWalker=t():e.DirWalker=t()}(global,()=>{return e={141(e,t,r){"use strict";var n,s=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r);var s=Object.getOwnPropertyDescriptor(t,r);s&&!("get"in s?!t.__esModule:s.writable||s.configurable)||(s={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,n,s)}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),o=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||(n=function(e){return n=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[t.length]=r);return t},n(e)},function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r=n(e),i=0;i<r.length;i++)"default"!==r[i]&&s(t,e,r[i]);return o(t,e),t});Object.defineProperty(t,"__esModule",{value:!0}),t.DirWalker=void 0;const a=i(r(943)),c=i(r(928)),u=r(576);class l{debug;counter;constructor(e=!1){this.debug=e,this.counter=0}async walk(e,t={excludeDirs:[],excludeExt:[]},r,n){this.counter=0;const s={...t};return await this._walk(e,e,s,r,n),this.counter}async _walk(e,t,r,n,s){try{const o=await a.readdir(e);for(const i of o){const o=c.resolve(e,i);try{await this._processEntry(o,t,r,n,s)}catch(e){this._handleError(`γγ‘γ€γ«ε¦ηγ¨γ©γΌ: ${o}`,e,s)}}}catch(t){this._handleError(`γγ£γ¬γ―γγͺθͺγΏεγγ¨γ©γΌ: ${e}`,t,s)}}async _processEntry(e,t,r,n,s){const o=await a.stat(e);o.isSymbolicLink()?this.debug&&console.debug(`γ·γ³γγͺγγ―γͺγ³γ―γγΉγγγ: ${e}`):o.isDirectory()?await this._processDirectory(e,t,r,n,s):await this._processFile(e,t,r,n,s)}async _processDirectory(e,t,r,n,s){r.excludeDirs&&r.excludeDirs.length>0&&new u.RegExpArray(r.excludeDirs).test(e)||await this._walk(e,t,r,n,s)}async _processFile(e,t,r,n,s){if(r.excludeExt&&r.excludeExt.length>0&&new u.RegExpArray(r.excludeExt).test(e))return;this.counter++,this.debug&&console.debug(`γγ‘γ€γ«ηΊθ¦: ${e}`);const o=c.relative(t,e);try{await n(o,r)}catch(t){this._handleError(`γγ‘γ€γ«ε¦ηγ¨γ©γΌ: ${e}`,t,s)}}_handleError(e,t,r){"function"==typeof r?r(t):console.error(`${e}: ${t.message}`)}}t.DirWalker=l,t.default=l},156(e,t,r){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.DirWalker=void 0;var s=r(141);Object.defineProperty(t,"DirWalker",{enumerable:!0,get:function(){return s.DirWalker}}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return n(s).default}})},576(e){var t;t=()=>(()=>{"use strict";var e={d:(t,r)=>{for(var n in r)e.o(r,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:r[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{BufferPatternMatcher:()=>n,RegExpArray:()=>r});class r{regExpInstanceList;sourceLiat;last;constructor(e){const t=e?Array.isArray(e)?e:[e]:[];this.regExpInstanceList=t.map(e=>e instanceof RegExp?e:Array.isArray(e)?new RegExp(e[0],e[1]):new RegExp(e)),this.sourceLiat=this.regExpInstanceList.map(e=>[e.source,e.flags]),this.last=null}exec(e){return this.regExpInstanceList.reduce((t,r)=>{this.last=r;const n=r.exec(e);return n?t.concat([...n]):t},[])}firstMatch(e){for(const t of this.regExpInstanceList){this.last=t;const r=t.exec(e);if(r)return r}return null}test(e){for(const t of this.regExpInstanceList)if(t.lastIndex=0,t.test(e))return!0;return!1}toArray(){return this.regExpInstanceList}static matchAll(e,t){return null===t?null:(Array.isArray(t)?t:[t]).reduce((t,r)=>{const n=Array.from(e.matchAll(r instanceof RegExp?r:new RegExp(r,"g")));return t.concat(n.map(e=>Array.from(e)))},[])}static firstMatch(e,t){if(null===t)return null;const r=Array.isArray(t)?t:[t];for(const t of r){const r=(t instanceof RegExp?t:new RegExp(t)).exec(e);if(r)return r}return null}static test(e,t){return null!==r.firstMatch(e,t)}}class n{constructor(){}compareBuf(e,t){try{if(!t)return null;for(const r of t)if(r.length<=e.length&&0===r.compare(e.slice(0,r.length)))return!0;return!1}catch(e){throw e instanceof Error&&console.error(`ζ£θ¦θ‘¨ηΎγγγγ‘ζ―θΌγ¨γ©γΌ: ${e.message}`),e}}}return t})(),e.exports=t()},928(e){"use strict";e.exports=require("path")},943(e){"use strict";e.exports=require("fs/promises")}},t={},function r(n){var s=t[n];if(void 0!==s)return s.exports;var o=t[n]={exports:{}};return e[n].call(o.exports,o,o.exports,r),o.exports}(156);var e,t});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dir-walker: A lightweight directory walker utility for Node.js
|
|
3
|
+
* @module dir-walker
|
|
4
|
+
*/
|
|
5
|
+
export { DirWalker, default } from './DirWalker';
|
|
6
|
+
export type { WalkSettings, FileCallback, ErrorCallback } from './DirWalker';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nojaja/dirwalker",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A lightweight, flexible directory walker utility for Node.js with pattern matching support",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"main": "dist/dirwalker.bundle.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "webpack --mode production",
|
|
10
|
+
"build:dev": "webpack --mode development",
|
|
11
|
+
"test": "jest --config jest.unit.config.js",
|
|
12
|
+
"test:ci": "jest --config jest.unit.config.js --coverage",
|
|
13
|
+
"test:coverage": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage",
|
|
14
|
+
"lint": "eslint src/**/*.ts --config eslint.config.js",
|
|
15
|
+
"type-check": "tsc --noEmit",
|
|
16
|
+
"clean": "node -e \"const fs=require('fs');fs.rmSync('dist',{recursive:true,force:true})\"",
|
|
17
|
+
"depcruise": "depcruise src --config .dependency-cruiser.js",
|
|
18
|
+
"docs": "typedoc --config typedoc.js"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"directory",
|
|
22
|
+
"walker",
|
|
23
|
+
"file",
|
|
24
|
+
"traversal",
|
|
25
|
+
"recursive",
|
|
26
|
+
"filesystem",
|
|
27
|
+
"pattern-matching",
|
|
28
|
+
"utility"
|
|
29
|
+
],
|
|
30
|
+
"author": "nojaja <free.riccia@gmail.com> (https://github.com/nojaja)",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/nojaja/NodeDirWalker.git"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/nojaja/NodeDirWalker/issues"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/nojaja/NodeDirWalker#readme",
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18.0.0"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist"
|
|
45
|
+
],
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/jest": "^29.5.8",
|
|
48
|
+
"@types/node": "^20.0.0",
|
|
49
|
+
"@typescript-eslint/eslint-plugin": "^8.18.2",
|
|
50
|
+
"@typescript-eslint/parser": "^8.18.2",
|
|
51
|
+
"dependency-cruiser": "^17.3.6",
|
|
52
|
+
"eslint": "^8.45.0",
|
|
53
|
+
"eslint-plugin-jsdoc": "^61.5.0",
|
|
54
|
+
"eslint-plugin-sonarjs": "^3.0.5",
|
|
55
|
+
"jest": "^29.6.1",
|
|
56
|
+
"prettier": "^3.0.0",
|
|
57
|
+
"ts-jest": "^29.1.0",
|
|
58
|
+
"ts-loader": "^9.5.0",
|
|
59
|
+
"typedoc": "^0.28.15",
|
|
60
|
+
"typedoc-plugin-markdown": "^4.9.0",
|
|
61
|
+
"typescript": "^5.3.3",
|
|
62
|
+
"webpack": "^5.99.8",
|
|
63
|
+
"webpack-cli": "^5.0.0"
|
|
64
|
+
},
|
|
65
|
+
"dependencies": {
|
|
66
|
+
"@nojaja/greputil": "^1.0.4",
|
|
67
|
+
"@nojaja/pathutil": "^1.0.6"
|
|
68
|
+
}
|
|
69
|
+
}
|