@bobfrankston/tswalk 1.0.2 → 1.1.1
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/.vscode/settings.json +2 -1
- package/.vscode/tasks-ts.json +23 -0
- package/.vscode/tasks.json +6 -9
- package/diskwalker.js +38 -27
- package/diskwalker.js.map +1 -1
- package/diskwalker.ts +42 -43
- package/index.js +4 -13
- package/index.js.map +1 -1
- package/index.ts +4 -13
- package/package.json +17 -6
- package/utils.js +57 -0
- package/utils.js.map +1 -0
- package/utils.ts +100 -0
- package/diskwalker2.js +0 -280
- package/diskwalker2.js.map +0 -1
- package/diskwalker2.ts +0 -319
package/.vscode/settings.json
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Template 1.0 y:\x\bin\MakeCodeTemplates\vscode\
|
|
3
|
+
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
|
4
|
+
// for the documentation about the tasks.json format
|
|
5
|
+
"version": "2.0.0",
|
|
6
|
+
"tasks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "typescript",
|
|
9
|
+
"tsconfig": "tsconfig.json",
|
|
10
|
+
"option": "watch",
|
|
11
|
+
"runOptions": {
|
|
12
|
+
"runOn": "folderOpen"
|
|
13
|
+
},
|
|
14
|
+
"problemMatcher": [
|
|
15
|
+
"$tsc-watch"
|
|
16
|
+
],
|
|
17
|
+
"group": {
|
|
18
|
+
"kind": "build",
|
|
19
|
+
"isDefault": true
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
package/.vscode/tasks.json
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
// Template 1.0 y:\x\bin\MakeCodeTemplates\vscode\
|
|
3
|
-
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
|
4
|
-
// for the documentation about the tasks.json format
|
|
5
2
|
"version": "2.0.0",
|
|
6
3
|
"tasks": [
|
|
7
4
|
{
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
5
|
+
"label": "tsc: watch",
|
|
6
|
+
"type": "shell",
|
|
7
|
+
"command": "tsc",
|
|
8
|
+
"args": ["--watch"],
|
|
11
9
|
"runOptions": {
|
|
12
10
|
"runOn": "folderOpen"
|
|
13
11
|
},
|
|
14
|
-
"problemMatcher":
|
|
15
|
-
|
|
16
|
-
],
|
|
12
|
+
"problemMatcher": "$tsc-watch",
|
|
13
|
+
"isBackground": true,
|
|
17
14
|
"group": {
|
|
18
15
|
"kind": "build",
|
|
19
16
|
"isDefault": true
|
package/diskwalker.js
CHANGED
|
@@ -1,22 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DISKWALKER.TS - Simplified Directory Walker Implementation
|
|
3
|
+
*
|
|
4
|
+
* Single directory walker implementation using Node.js built-in fs/fs.promises APIs.
|
|
5
|
+
* Provides directory traversal and file operations using standard filesystem calls.
|
|
6
|
+
*
|
|
7
|
+
* Key features:
|
|
8
|
+
* - Uses fs.readdir() and fs.stat() for directory enumeration
|
|
9
|
+
* - Simple, lightweight implementation with minimal dependencies
|
|
10
|
+
* - Safe regex compilation for -f patterns (fixes "Nothing to repeat" errors)
|
|
11
|
+
* - Supports glob patterns (*.js) and regex literals (/pattern/flags)
|
|
12
|
+
* - Comprehensive error handling for filesystem operations
|
|
13
|
+
*
|
|
14
|
+
* Recent improvements:
|
|
15
|
+
* - Fixed regex compilation to safely handle patterns like "*.exe" and "/*.js/"
|
|
16
|
+
* - Consolidated from dual implementation to single fs-based approach
|
|
17
|
+
* - Removed dirutil dependency for simplicity and similar performance
|
|
18
|
+
*/
|
|
1
19
|
import * as fp from 'fs/promises';
|
|
2
20
|
import * as path from 'path';
|
|
3
21
|
import { spawn } from 'child_process';
|
|
4
22
|
import { styleText } from 'node:util';
|
|
5
|
-
|
|
6
|
-
const suppressedErrors = ['ENOENT', 'EPERM', 'EACCES'];
|
|
23
|
+
import { compilePatterns, defaultWalkOptions, suppressedErrors } from './utils.js';
|
|
7
24
|
export class DiskWalker {
|
|
8
25
|
topPath;
|
|
9
|
-
static defaultOptions =
|
|
10
|
-
depth: 1,
|
|
11
|
-
threshold: 0,
|
|
12
|
-
cmd: '',
|
|
13
|
-
verbose: false,
|
|
14
|
-
showCompressed: false,
|
|
15
|
-
finding: null,
|
|
16
|
-
forceAcl: false,
|
|
17
|
-
quiet: false,
|
|
18
|
-
sizeUnit: 'MB'
|
|
19
|
-
};
|
|
26
|
+
static defaultOptions = defaultWalkOptions;
|
|
20
27
|
options;
|
|
21
28
|
walker;
|
|
22
29
|
lastProgressTime = 0;
|
|
@@ -72,11 +79,16 @@ class WalkTree {
|
|
|
72
79
|
prefix;
|
|
73
80
|
nextTitleUpdate = new Date(0);
|
|
74
81
|
seenErrors = new Set();
|
|
82
|
+
findingRegexes = null;
|
|
75
83
|
constructor(dirPath, options, progressCallback, atDepth = 0) {
|
|
76
84
|
this.dirPath = dirPath;
|
|
77
85
|
this.options = options;
|
|
78
86
|
this.progressCallback = progressCallback;
|
|
79
87
|
this.atDepth = atDepth;
|
|
88
|
+
// Precompile find patterns into safe RegExp objects to avoid invalid regex errors
|
|
89
|
+
if (this.options.finding) {
|
|
90
|
+
this.findingRegexes = compilePatterns(this.options.finding);
|
|
91
|
+
}
|
|
80
92
|
this.prefix = ' '.repeat(5 + atDepth * 5);
|
|
81
93
|
if (options.verbose) {
|
|
82
94
|
this.prefix = atDepth.toString().padStart(2, '0') + ' ' + this.prefix;
|
|
@@ -161,20 +173,19 @@ class WalkTree {
|
|
|
161
173
|
if (!this.options.finding)
|
|
162
174
|
return;
|
|
163
175
|
try {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
176
|
+
const files = await fp.readdir(this.dirPath);
|
|
177
|
+
const regexes = this.findingRegexes || [];
|
|
178
|
+
for (const file of files) {
|
|
179
|
+
if (regexes.length && regexes.some(rx => rx.test(file))) {
|
|
180
|
+
try {
|
|
181
|
+
const stats = await fp.stat(path.join(this.dirPath, file));
|
|
182
|
+
const size = stats.size / 1024;
|
|
183
|
+
process.stdout.write('\x1b[2K\r'); // Clear progress line
|
|
184
|
+
console.log(`${stats.mtime.toISOString().slice(0, 19).replace('T', ' ')} ` +
|
|
185
|
+
`${size.toFixed(1).padStart(8)}KB ${this.prefix} ${path.join(this.dirPath, file)}`);
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
this.logError(file, err);
|
|
178
189
|
}
|
|
179
190
|
}
|
|
180
191
|
}
|
package/diskwalker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diskwalker.js","sourceRoot":"","sources":["diskwalker.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"diskwalker.js","sourceRoot":"","sources":["diskwalker.ts"],"names":[],"mappings":"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"}
|
package/diskwalker.ts
CHANGED
|
@@ -1,38 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DISKWALKER.TS - Simplified Directory Walker Implementation
|
|
3
|
+
*
|
|
4
|
+
* Single directory walker implementation using Node.js built-in fs/fs.promises APIs.
|
|
5
|
+
* Provides directory traversal and file operations using standard filesystem calls.
|
|
6
|
+
*
|
|
7
|
+
* Key features:
|
|
8
|
+
* - Uses fs.readdir() and fs.stat() for directory enumeration
|
|
9
|
+
* - Simple, lightweight implementation with minimal dependencies
|
|
10
|
+
* - Safe regex compilation for -f patterns (fixes "Nothing to repeat" errors)
|
|
11
|
+
* - Supports glob patterns (*.js) and regex literals (/pattern/flags)
|
|
12
|
+
* - Comprehensive error handling for filesystem operations
|
|
13
|
+
*
|
|
14
|
+
* Recent improvements:
|
|
15
|
+
* - Fixed regex compilation to safely handle patterns like "*.exe" and "/*.js/"
|
|
16
|
+
* - Consolidated from dual implementation to single fs-based approach
|
|
17
|
+
* - Removed dirutil dependency for simplicity and similar performance
|
|
18
|
+
*/
|
|
19
|
+
|
|
1
20
|
import * as fs from 'fs';
|
|
2
21
|
import * as fp from 'fs/promises'
|
|
3
22
|
import * as path from 'path';
|
|
4
23
|
import { spawn } from 'child_process';
|
|
5
24
|
import { styleText } from 'node:util';
|
|
6
|
-
|
|
7
|
-
interface WalkOptions {
|
|
8
|
-
depth: number;
|
|
9
|
-
threshold: number;
|
|
10
|
-
cmd: string;
|
|
11
|
-
verbose: boolean;
|
|
12
|
-
showCompressed: boolean;
|
|
13
|
-
finding: string[] | null;
|
|
14
|
-
forceAcl: boolean;
|
|
15
|
-
quiet: boolean;
|
|
16
|
-
sizeUnit: 'MB' | 'GB';
|
|
17
|
-
}
|
|
25
|
+
import { compilePatterns, WalkOptions, defaultWalkOptions, suppressedErrors } from './utils.js';
|
|
18
26
|
|
|
19
27
|
type ProgressCallback = (walker: WalkTree, currentPath: string) => void;
|
|
20
28
|
|
|
21
|
-
// Error types to suppress unless verbose
|
|
22
|
-
const suppressedErrors = ['ENOENT', 'EPERM', 'EACCES'];
|
|
23
|
-
|
|
24
29
|
export class DiskWalker {
|
|
25
|
-
private static defaultOptions: WalkOptions =
|
|
26
|
-
depth: 1,
|
|
27
|
-
threshold: 0,
|
|
28
|
-
cmd: '',
|
|
29
|
-
verbose: false,
|
|
30
|
-
showCompressed: false,
|
|
31
|
-
finding: null,
|
|
32
|
-
forceAcl: false,
|
|
33
|
-
quiet: false,
|
|
34
|
-
sizeUnit: 'MB'
|
|
35
|
-
};
|
|
30
|
+
private static defaultOptions: WalkOptions = defaultWalkOptions;
|
|
36
31
|
|
|
37
32
|
private options: WalkOptions;
|
|
38
33
|
private walker: WalkTree;
|
|
@@ -88,6 +83,7 @@ class WalkTree {
|
|
|
88
83
|
private prefix: string;
|
|
89
84
|
private nextTitleUpdate: Date = new Date(0);
|
|
90
85
|
private seenErrors = new Set<string>();
|
|
86
|
+
private findingRegexes: RegExp[] | null = null;
|
|
91
87
|
|
|
92
88
|
constructor(
|
|
93
89
|
private dirPath: string,
|
|
@@ -95,6 +91,10 @@ class WalkTree {
|
|
|
95
91
|
private progressCallback: ProgressCallback,
|
|
96
92
|
private atDepth: number = 0
|
|
97
93
|
) {
|
|
94
|
+
// Precompile find patterns into safe RegExp objects to avoid invalid regex errors
|
|
95
|
+
if (this.options.finding) {
|
|
96
|
+
this.findingRegexes = compilePatterns(this.options.finding);
|
|
97
|
+
}
|
|
98
98
|
this.prefix = ' '.repeat(5 + atDepth * 5);
|
|
99
99
|
if (options.verbose) {
|
|
100
100
|
this.prefix = atDepth.toString().padStart(2, '0') + ' ' + this.prefix;
|
|
@@ -184,23 +184,22 @@ class WalkTree {
|
|
|
184
184
|
|
|
185
185
|
private async findFiles(): Promise<void> {
|
|
186
186
|
if (!this.options.finding) return;
|
|
187
|
-
|
|
188
187
|
try {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
188
|
+
const files = await fp.readdir(this.dirPath);
|
|
189
|
+
const regexes = this.findingRegexes || [];
|
|
190
|
+
|
|
191
|
+
for (const file of files) {
|
|
192
|
+
if (regexes.length && regexes.some(rx => rx.test(file))) {
|
|
193
|
+
try {
|
|
194
|
+
const stats = await fp.stat(path.join(this.dirPath, file));
|
|
195
|
+
const size = stats.size / 1024;
|
|
196
|
+
process.stdout.write('\x1b[2K\r'); // Clear progress line
|
|
197
|
+
console.log(
|
|
198
|
+
`${stats.mtime.toISOString().slice(0, 19).replace('T', ' ')} ` +
|
|
199
|
+
`${size.toFixed(1).padStart(8)}KB ${this.prefix} ${path.join(this.dirPath, file)}`
|
|
200
|
+
);
|
|
201
|
+
} catch (err) {
|
|
202
|
+
this.logError(file, err as Error);
|
|
204
203
|
}
|
|
205
204
|
}
|
|
206
205
|
}
|
|
@@ -268,4 +267,4 @@ class WalkTree {
|
|
|
268
267
|
}
|
|
269
268
|
}
|
|
270
269
|
|
|
271
|
-
export { WalkOptions };
|
|
270
|
+
export { WalkOptions } from './utils.js';
|
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { DiskWalker } from './diskwalker.js';
|
|
3
|
-
import {
|
|
3
|
+
import { defaultWalkOptions } from './utils.js';
|
|
4
4
|
import { styleText } from 'node:util';
|
|
5
5
|
function showUsage() {
|
|
6
6
|
console.log(`
|
|
@@ -19,8 +19,6 @@ Options:
|
|
|
19
19
|
-v Verbose output (show all errors including ENOENT/EPERM)
|
|
20
20
|
-q Quiet mode (no progress updates, minimal errors)
|
|
21
21
|
-acl Force ACL operations (Windows only)
|
|
22
|
-
-1 Use original fs API implementation
|
|
23
|
-
-2 Use dirutil API implementation (default)
|
|
24
22
|
|
|
25
23
|
Progress:
|
|
26
24
|
Shows current directory being processed every second in blue.
|
|
@@ -43,7 +41,7 @@ Examples:
|
|
|
43
41
|
}
|
|
44
42
|
async function main() {
|
|
45
43
|
const args = process.argv.slice(2);
|
|
46
|
-
console.log('tswalk v1.0
|
|
44
|
+
console.log('tswalk v1.1.0 (simplified)');
|
|
47
45
|
if (args.includes('-h') || args.includes('-help') || args.includes('--help')) {
|
|
48
46
|
showUsage();
|
|
49
47
|
}
|
|
@@ -51,7 +49,6 @@ async function main() {
|
|
|
51
49
|
let topPath = '.';
|
|
52
50
|
let foundPath = false;
|
|
53
51
|
let foundDepth = false;
|
|
54
|
-
let useV2 = true;
|
|
55
52
|
for (let i = 0; i < args.length; i++) {
|
|
56
53
|
const arg = args[i];
|
|
57
54
|
if (arg.startsWith('-')) {
|
|
@@ -94,12 +91,6 @@ async function main() {
|
|
|
94
91
|
case '-acl':
|
|
95
92
|
options.forceAcl = true;
|
|
96
93
|
break;
|
|
97
|
-
case '-1':
|
|
98
|
-
useV2 = false;
|
|
99
|
-
break;
|
|
100
|
-
case '-2':
|
|
101
|
-
useV2 = true;
|
|
102
|
-
break;
|
|
103
94
|
case '-h':
|
|
104
95
|
case '-help':
|
|
105
96
|
case '--help':
|
|
@@ -127,8 +118,8 @@ async function main() {
|
|
|
127
118
|
options.quiet = false;
|
|
128
119
|
}
|
|
129
120
|
try {
|
|
130
|
-
const
|
|
131
|
-
const walker = new
|
|
121
|
+
const fullOptions = { ...defaultWalkOptions, ...options };
|
|
122
|
+
const walker = new DiskWalker(topPath, fullOptions);
|
|
132
123
|
await walker.walk();
|
|
133
124
|
}
|
|
134
125
|
catch (err) {
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAe,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
|
package/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { DiskWalker, WalkOptions } from './diskwalker.js';
|
|
3
|
-
import {
|
|
3
|
+
import { defaultWalkOptions } from './utils.js';
|
|
4
4
|
import { styleText } from 'node:util';
|
|
5
5
|
|
|
6
6
|
function showUsage() {
|
|
@@ -20,8 +20,6 @@ Options:
|
|
|
20
20
|
-v Verbose output (show all errors including ENOENT/EPERM)
|
|
21
21
|
-q Quiet mode (no progress updates, minimal errors)
|
|
22
22
|
-acl Force ACL operations (Windows only)
|
|
23
|
-
-1 Use original fs API implementation
|
|
24
|
-
-2 Use dirutil API implementation (default)
|
|
25
23
|
|
|
26
24
|
Progress:
|
|
27
25
|
Shows current directory being processed every second in blue.
|
|
@@ -46,7 +44,7 @@ Examples:
|
|
|
46
44
|
async function main() {
|
|
47
45
|
const args = process.argv.slice(2);
|
|
48
46
|
|
|
49
|
-
console.log('tswalk v1.0
|
|
47
|
+
console.log('tswalk v1.1.0 (simplified)');
|
|
50
48
|
|
|
51
49
|
if (args.includes('-h') || args.includes('-help') || args.includes('--help')) {
|
|
52
50
|
showUsage();
|
|
@@ -56,7 +54,6 @@ async function main() {
|
|
|
56
54
|
let topPath = '.';
|
|
57
55
|
let foundPath = false;
|
|
58
56
|
let foundDepth = false;
|
|
59
|
-
let useV2 = true;
|
|
60
57
|
|
|
61
58
|
for (let i = 0; i < args.length; i++) {
|
|
62
59
|
const arg = args[i];
|
|
@@ -101,12 +98,6 @@ async function main() {
|
|
|
101
98
|
case '-acl':
|
|
102
99
|
options.forceAcl = true;
|
|
103
100
|
break;
|
|
104
|
-
case '-1':
|
|
105
|
-
useV2 = false;
|
|
106
|
-
break;
|
|
107
|
-
case '-2':
|
|
108
|
-
useV2 = true;
|
|
109
|
-
break;
|
|
110
101
|
case '-h':
|
|
111
102
|
case '-help':
|
|
112
103
|
case '--help':
|
|
@@ -134,8 +125,8 @@ async function main() {
|
|
|
134
125
|
}
|
|
135
126
|
|
|
136
127
|
try {
|
|
137
|
-
const
|
|
138
|
-
const walker = new
|
|
128
|
+
const fullOptions = { ...defaultWalkOptions, ...options };
|
|
129
|
+
const walker = new DiskWalker(topPath, fullOptions);
|
|
139
130
|
await walker.walk();
|
|
140
131
|
} catch (err) {
|
|
141
132
|
console.error(styleText(['red'], '\nFatal error:'), err);
|
package/package.json
CHANGED
|
@@ -1,26 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/tswalk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "Walk directory tree - simplified single implementation",
|
|
4
5
|
"main": "index.js",
|
|
5
6
|
"bin": {
|
|
6
7
|
"tswalk": "./index.js"
|
|
7
8
|
},
|
|
8
9
|
"module": "main.js",
|
|
9
10
|
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"prerelease:local": "git add -A && (git diff-index --quiet HEAD || git commit -m \"Pre-release commit\")",
|
|
13
|
+
"preversion": "npm run build && git add -A",
|
|
14
|
+
"postversion": "git push && git push --tags",
|
|
15
|
+
"release": "npm run prerelease:local && npm version patch && npm publish",
|
|
16
|
+
"release:ps1": "releaseapp.ps1",
|
|
10
17
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
18
|
},
|
|
12
19
|
"keywords": [
|
|
13
|
-
"typescript"
|
|
20
|
+
"typescript",
|
|
21
|
+
"directory",
|
|
22
|
+
"tree",
|
|
23
|
+
"walker",
|
|
24
|
+
"filesystem",
|
|
25
|
+
"disk-usage",
|
|
26
|
+
"file-search"
|
|
14
27
|
],
|
|
15
|
-
"author": "",
|
|
28
|
+
"author": "Bob Frankston",
|
|
16
29
|
"license": "ISC",
|
|
17
30
|
"type": "module",
|
|
18
|
-
"description": "",
|
|
19
31
|
"dependencies": {
|
|
20
|
-
"@bobfrankston/dirutil": "^1.6.0",
|
|
21
32
|
"esm": "^3.2.25"
|
|
22
33
|
},
|
|
23
34
|
"devDependencies": {
|
|
24
|
-
"@types/node": "^24.
|
|
35
|
+
"@types/node": "^24.9.1"
|
|
25
36
|
}
|
|
26
37
|
}
|
package/utils.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common utilities for tswalk directory walking implementations
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Convert user-supplied patterns into safe RegExp objects.
|
|
6
|
+
* Supports regex literals like /pattern/flags and simple glob patterns using * and ?
|
|
7
|
+
*
|
|
8
|
+
* @param patterns Array of user-provided patterns (can be glob or regex literals)
|
|
9
|
+
* @returns Array of compiled RegExp objects that won't throw "Nothing to repeat" errors
|
|
10
|
+
*/
|
|
11
|
+
export function compilePatterns(patterns) {
|
|
12
|
+
const res = [];
|
|
13
|
+
for (const p of patterns) {
|
|
14
|
+
if (!p)
|
|
15
|
+
continue;
|
|
16
|
+
try {
|
|
17
|
+
// Handle regex literals like /pattern/flags
|
|
18
|
+
if (p.startsWith('/') && p.lastIndexOf('/') > 0) {
|
|
19
|
+
const last = p.lastIndexOf('/');
|
|
20
|
+
const body = p.slice(1, last);
|
|
21
|
+
const flags = p.slice(last + 1);
|
|
22
|
+
res.push(new RegExp(body, flags));
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
// Treat as glob: escape regex metacharacters, then translate \* -> .* and \? -> .
|
|
26
|
+
const escaped = p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
27
|
+
.replace(/\\\*/g, '.*')
|
|
28
|
+
.replace(/\\\?/g, '.');
|
|
29
|
+
res.push(new RegExp('^' + escaped + '$', 'i'));
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
// Fallback: escape everything and do a case-insensitive literal match
|
|
33
|
+
const safe = p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
34
|
+
res.push(new RegExp('^' + safe + '$', 'i'));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return res;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Default options for directory walking
|
|
41
|
+
*/
|
|
42
|
+
export const defaultWalkOptions = {
|
|
43
|
+
depth: 1,
|
|
44
|
+
threshold: 0,
|
|
45
|
+
cmd: '',
|
|
46
|
+
verbose: false,
|
|
47
|
+
showCompressed: false,
|
|
48
|
+
finding: null,
|
|
49
|
+
forceAcl: false,
|
|
50
|
+
quiet: false,
|
|
51
|
+
sizeUnit: 'MB'
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Error types to suppress unless verbose mode is enabled
|
|
55
|
+
*/
|
|
56
|
+
export const suppressedErrors = ['ENOENT', 'EPERM', 'EACCES'];
|
|
57
|
+
//# sourceMappingURL=utils.js.map
|
package/utils.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,QAAkB;IAC9C,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACvB,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,IAAI,CAAC;YACD,4CAA4C;YAC5C,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC9C,MAAM,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;gBAChC,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;gBAC9B,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;gBAChC,GAAG,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;gBAClC,SAAS;YACb,CAAC;YAED,kFAAkF;YAClF,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC;iBACnD,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;iBACtB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YAC3B,GAAG,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,GAAG,GAAG,OAAO,GAAG,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,sEAAsE;YACtE,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;YACtD,GAAG,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,GAAG,GAAG,IAAI,GAAG,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;QAChD,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAiBD;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAgB;IAC3C,KAAK,EAAE,CAAC;IACR,SAAS,EAAE,CAAC;IACZ,GAAG,EAAE,EAAE;IACP,OAAO,EAAE,KAAK;IACd,cAAc,EAAE,KAAK;IACrB,OAAO,EAAE,IAAI;IACb,QAAQ,EAAE,KAAK;IACf,KAAK,EAAE,KAAK;IACZ,QAAQ,EAAE,IAAI;CACjB,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC"}
|
package/utils.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common utilities for tswalk directory walking implementations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Convert user-supplied patterns into safe RegExp objects.
|
|
7
|
+
* Supports regex literals like /pattern/flags and simple glob patterns using * and ?
|
|
8
|
+
*
|
|
9
|
+
* @param patterns Array of user-provided patterns (can be glob or regex literals)
|
|
10
|
+
* @returns Array of compiled RegExp objects that won't throw "Nothing to repeat" errors
|
|
11
|
+
*/
|
|
12
|
+
export function compilePatterns(patterns: string[]): RegExp[] {
|
|
13
|
+
const res: RegExp[] = [];
|
|
14
|
+
for (const p of patterns) {
|
|
15
|
+
if (!p) continue;
|
|
16
|
+
try {
|
|
17
|
+
// Handle regex literals like /pattern/flags
|
|
18
|
+
if (p.startsWith('/') && p.lastIndexOf('/') > 0) {
|
|
19
|
+
const last = p.lastIndexOf('/');
|
|
20
|
+
const body = p.slice(1, last);
|
|
21
|
+
const flags = p.slice(last + 1);
|
|
22
|
+
res.push(new RegExp(body, flags));
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Treat as glob: escape regex metacharacters, then translate \* -> .* and \? -> .
|
|
27
|
+
const escaped = p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
28
|
+
.replace(/\\\*/g, '.*')
|
|
29
|
+
.replace(/\\\?/g, '.');
|
|
30
|
+
res.push(new RegExp('^' + escaped + '$', 'i'));
|
|
31
|
+
} catch (err) {
|
|
32
|
+
// Fallback: escape everything and do a case-insensitive literal match
|
|
33
|
+
const safe = p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
34
|
+
res.push(new RegExp('^' + safe + '$', 'i'));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return res;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Common interface for directory walking options
|
|
42
|
+
*/
|
|
43
|
+
export interface WalkOptions {
|
|
44
|
+
depth: number;
|
|
45
|
+
threshold: number;
|
|
46
|
+
cmd: string;
|
|
47
|
+
verbose: boolean;
|
|
48
|
+
showCompressed: boolean;
|
|
49
|
+
finding: string[] | null;
|
|
50
|
+
forceAcl: boolean;
|
|
51
|
+
quiet: boolean;
|
|
52
|
+
sizeUnit: 'MB' | 'GB';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Default options for directory walking
|
|
57
|
+
*/
|
|
58
|
+
export const defaultWalkOptions: WalkOptions = {
|
|
59
|
+
depth: 1,
|
|
60
|
+
threshold: 0,
|
|
61
|
+
cmd: '',
|
|
62
|
+
verbose: false,
|
|
63
|
+
showCompressed: false,
|
|
64
|
+
finding: null,
|
|
65
|
+
forceAcl: false,
|
|
66
|
+
quiet: false,
|
|
67
|
+
sizeUnit: 'MB'
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Error types to suppress unless verbose mode is enabled
|
|
72
|
+
*/
|
|
73
|
+
export const suppressedErrors = ['ENOENT', 'EPERM', 'EACCES'];
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Directory entry interface - common format for both enumeration strategies
|
|
77
|
+
*/
|
|
78
|
+
export interface DirectoryEntry {
|
|
79
|
+
name: string;
|
|
80
|
+
isFile: boolean;
|
|
81
|
+
isDirectory: boolean;
|
|
82
|
+
isSymlink: boolean;
|
|
83
|
+
size: number;
|
|
84
|
+
mtime: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Directory enumeration strategy interface
|
|
89
|
+
*/
|
|
90
|
+
export interface DirectoryEnumerator {
|
|
91
|
+
/**
|
|
92
|
+
* List directory contents with file metadata
|
|
93
|
+
*/
|
|
94
|
+
listDirectory(dirPath: string): Promise<DirectoryEntry[]> | DirectoryEntry[];
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Get disk block size for accurate space calculations (optional)
|
|
98
|
+
*/
|
|
99
|
+
getBlockSize?(dirPath: string): number;
|
|
100
|
+
}
|
package/diskwalker2.js
DELETED
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
import * as path from 'path';
|
|
2
|
-
import { spawn } from 'child_process';
|
|
3
|
-
import { styleText } from 'node:util';
|
|
4
|
-
import { listDirectory, getDriveInfo } from '@bobfrankston/dirutil';
|
|
5
|
-
// Error types to suppress unless verbose
|
|
6
|
-
const suppressedErrors = ['ENOENT', 'EPERM', 'EACCES'];
|
|
7
|
-
// Directories to suppress errors from
|
|
8
|
-
const suppressedDirectories = ['$RECYCLE.BIN', 'System Volume Information'];
|
|
9
|
-
export class DiskWalker {
|
|
10
|
-
topPath;
|
|
11
|
-
static defaultOptions = {
|
|
12
|
-
depth: 1,
|
|
13
|
-
threshold: 0,
|
|
14
|
-
cmd: '',
|
|
15
|
-
verbose: false,
|
|
16
|
-
showCompressed: false,
|
|
17
|
-
finding: null,
|
|
18
|
-
forceAcl: false,
|
|
19
|
-
quiet: false,
|
|
20
|
-
sizeUnit: 'MB'
|
|
21
|
-
};
|
|
22
|
-
options;
|
|
23
|
-
walker;
|
|
24
|
-
lastProgressTime = 0;
|
|
25
|
-
static blockSizeCache = new Map();
|
|
26
|
-
constructor(topPath = '.', options = {}) {
|
|
27
|
-
this.topPath = topPath;
|
|
28
|
-
this.options = { ...DiskWalker.defaultOptions, ...options };
|
|
29
|
-
this.topPath = path.resolve(topPath);
|
|
30
|
-
this.walker = new WalkTree(this.topPath, this.options, this.showProgress.bind(this));
|
|
31
|
-
}
|
|
32
|
-
truncatePath(fullPath, maxLength = 64) {
|
|
33
|
-
if (fullPath.length <= maxLength)
|
|
34
|
-
return fullPath;
|
|
35
|
-
const half = Math.floor((maxLength - 3) / 2);
|
|
36
|
-
const start = fullPath.slice(0, half);
|
|
37
|
-
const end = fullPath.slice(-half);
|
|
38
|
-
return `${start}...${end}`;
|
|
39
|
-
}
|
|
40
|
-
showProgress(walker, currentPath) {
|
|
41
|
-
const now = Date.now();
|
|
42
|
-
if (now - this.lastProgressTime > 1000 && !this.options.quiet) {
|
|
43
|
-
const truncatedPath = this.truncatePath(currentPath);
|
|
44
|
-
process.stdout.write('\x1b[2K\r'); // Clear entire line and return to start
|
|
45
|
-
const line = styleText(['blue'], `${walker.formatSize().padStart(13)} ${this.options.sizeUnit} ${truncatedPath}`);
|
|
46
|
-
process.stdout.write(line);
|
|
47
|
-
this.lastProgressTime = now;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
async walk() {
|
|
51
|
-
try {
|
|
52
|
-
await this.walker.walk();
|
|
53
|
-
if (!this.options.quiet) {
|
|
54
|
-
process.stdout.write('\x1b[2K\r'); // Clear progress line
|
|
55
|
-
}
|
|
56
|
-
const pather = `${styleText(['blue'], `${path.dirname(this.topPath)}${path.sep}`)}${styleText(['bgBlack', 'bold', 'yellow'], path.basename(this.topPath))}`;
|
|
57
|
-
console.log(`${this.walker.formatSize()} ${this.options.sizeUnit} ${pather}`);
|
|
58
|
-
}
|
|
59
|
-
catch (err) {
|
|
60
|
-
console.error('Failed:', err.message);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
class WalkTree {
|
|
65
|
-
dirPath;
|
|
66
|
-
options;
|
|
67
|
-
progressCallback;
|
|
68
|
-
atDepth;
|
|
69
|
-
length = 0;
|
|
70
|
-
compressedLength = 0;
|
|
71
|
-
fileCount = 0;
|
|
72
|
-
dirCount = 0;
|
|
73
|
-
totalFileCount = 0;
|
|
74
|
-
totalDirCount = 0;
|
|
75
|
-
otherCount = 0;
|
|
76
|
-
prefix;
|
|
77
|
-
nextTitleUpdate = new Date(0);
|
|
78
|
-
seenErrors = new Set();
|
|
79
|
-
blockSize = 4096; // default 4KB, will be updated
|
|
80
|
-
constructor(dirPath, options, progressCallback, atDepth = 0) {
|
|
81
|
-
this.dirPath = dirPath;
|
|
82
|
-
this.options = options;
|
|
83
|
-
this.progressCallback = progressCallback;
|
|
84
|
-
this.atDepth = atDepth;
|
|
85
|
-
this.prefix = ' '.repeat(5 + atDepth * 5);
|
|
86
|
-
if (options.verbose) {
|
|
87
|
-
this.prefix = atDepth.toString().padStart(2, '0') + ' ' + this.prefix;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
getDiskBlockSize(drivePath) {
|
|
91
|
-
const drive = path.parse(drivePath).root;
|
|
92
|
-
if (DiskWalker.blockSizeCache.has(drive)) {
|
|
93
|
-
return DiskWalker.blockSizeCache.get(drive);
|
|
94
|
-
}
|
|
95
|
-
try {
|
|
96
|
-
const driveInfo = getDriveInfo(drivePath);
|
|
97
|
-
const blockSize = driveInfo?.blockSize || 4096;
|
|
98
|
-
DiskWalker.blockSizeCache.set(drive, blockSize);
|
|
99
|
-
return blockSize;
|
|
100
|
-
}
|
|
101
|
-
catch (err) {
|
|
102
|
-
// Fallback to default 4KB block size
|
|
103
|
-
DiskWalker.blockSizeCache.set(drive, 4096);
|
|
104
|
-
return 4096;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
roundUpToBlockSize(fileSize, blockSize) {
|
|
108
|
-
return Math.ceil(fileSize / blockSize) * blockSize;
|
|
109
|
-
}
|
|
110
|
-
formatSize() {
|
|
111
|
-
const divisor = this.options.sizeUnit === 'GB' ? (1024 * 1024 * 1024) : (1024 * 1024);
|
|
112
|
-
const size = this.length / divisor;
|
|
113
|
-
const formatted = size.toLocaleString(undefined, { minimumFractionDigits: 2 });
|
|
114
|
-
if (this.options.showCompressed && this.length !== this.compressedLength) {
|
|
115
|
-
const compressedSize = this.compressedLength / divisor;
|
|
116
|
-
return `${formatted}/${compressedSize.toLocaleString(undefined, { minimumFractionDigits: 2 })}`;
|
|
117
|
-
}
|
|
118
|
-
return formatted;
|
|
119
|
-
}
|
|
120
|
-
logError(context, err) {
|
|
121
|
-
// Only suppress errors if explicitly quiet, or if it's a known unimportant error
|
|
122
|
-
if (this.options.quiet ||
|
|
123
|
-
(!this.options.verbose &&
|
|
124
|
-
(suppressedErrors.some(e => err.message.includes(e)) ||
|
|
125
|
-
suppressedDirectories.some(d => this.dirPath.includes(d))))) {
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
const errorKey = `${context}:${err.message}:${this.dirPath}`;
|
|
129
|
-
if (!this.seenErrors.has(errorKey)) {
|
|
130
|
-
console.error(styleText(['red'], `Error processing ${context}: ${err.message}`));
|
|
131
|
-
this.seenErrors.add(errorKey);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
processFilesFromEntries(entries) {
|
|
135
|
-
try {
|
|
136
|
-
if (Date.now() > this.nextTitleUpdate.getTime()) {
|
|
137
|
-
process.title = this.dirPath;
|
|
138
|
-
this.nextTitleUpdate = new Date(Date.now() + 500);
|
|
139
|
-
}
|
|
140
|
-
// Get block size once for this directory's drive
|
|
141
|
-
if (this.blockSize === 4096) { // Only query if we haven't set it yet
|
|
142
|
-
this.blockSize = this.getDiskBlockSize(this.dirPath);
|
|
143
|
-
}
|
|
144
|
-
const fileEntries = entries.filter(entry => entry.isFile);
|
|
145
|
-
for (const entry of fileEntries) {
|
|
146
|
-
this.fileCount++;
|
|
147
|
-
this.totalFileCount++;
|
|
148
|
-
const fileSize = entry.size || 0;
|
|
149
|
-
const blockAlignedSize = this.roundUpToBlockSize(fileSize, this.blockSize);
|
|
150
|
-
this.length += blockAlignedSize;
|
|
151
|
-
this.compressedLength += fileSize; // Keep original size for compressed display
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
catch (err) {
|
|
155
|
-
this.logError('directory', err);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
async executeCommand() {
|
|
159
|
-
if (!this.options.cmd)
|
|
160
|
-
return;
|
|
161
|
-
const currentDir = process.cwd();
|
|
162
|
-
try {
|
|
163
|
-
process.chdir(this.dirPath);
|
|
164
|
-
await new Promise((resolve, reject) => {
|
|
165
|
-
const proc = spawn(this.options.cmd, [], { shell: true });
|
|
166
|
-
proc.on('close', resolve);
|
|
167
|
-
proc.on('error', reject);
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
catch (err) {
|
|
171
|
-
this.logError('command execution', err);
|
|
172
|
-
}
|
|
173
|
-
finally {
|
|
174
|
-
process.chdir(currentDir);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
async findFilesFromEntries(entries) {
|
|
178
|
-
if (!this.options.finding)
|
|
179
|
-
return;
|
|
180
|
-
try {
|
|
181
|
-
for (const pattern of this.options.finding) {
|
|
182
|
-
for (const entry of entries) {
|
|
183
|
-
if (entry.name.match(pattern)) {
|
|
184
|
-
const size = (entry.size || 0) / 1024;
|
|
185
|
-
const mtime = new Date(entry.mtime);
|
|
186
|
-
process.stdout.write('\x1b[2K\r'); // Clear progress line
|
|
187
|
-
console.log(`${mtime.toISOString().slice(0, 19).replace('T', ' ')} ` +
|
|
188
|
-
`${size.toFixed(1).padStart(8)}KB ${this.prefix} ${path.join(this.dirPath, entry.name)}`);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
catch (err) {
|
|
194
|
-
this.logError('file search', err);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
async walk() {
|
|
198
|
-
try {
|
|
199
|
-
this.progressCallback(this, this.dirPath);
|
|
200
|
-
// try {
|
|
201
|
-
// // console.log(`DEBUG: Accessing directory: ${this.dirPath}`);
|
|
202
|
-
// // fs.accessSync(this.dirPath);
|
|
203
|
-
// // console.log(`DEBUG: Accessed directory: ${this.dirPath}`);
|
|
204
|
-
// fs.readdirSync(this.dirPath); // Ensure we can read the directory
|
|
205
|
-
// // console.log(`DEBUG: Read directory: ${this.dirPath}`);
|
|
206
|
-
// }
|
|
207
|
-
// catch (e: any) {
|
|
208
|
-
// // console.error(`DEBUG: Failed to access or read directory ${this.dirPath}: ${e.message}`);
|
|
209
|
-
// debugger;
|
|
210
|
-
// throw e
|
|
211
|
-
// }
|
|
212
|
-
// Get directory entries once
|
|
213
|
-
// console.log(`DEBUG: Walking directory: ${this.dirPath}`);
|
|
214
|
-
const entries = listDirectory(this.dirPath, { stats: true });
|
|
215
|
-
// console.log(`DEBUG: Walked directory: ${this.dirPath}`);
|
|
216
|
-
if (this.options.verbose) {
|
|
217
|
-
console.log(`DEBUG: Found ${entries.length} entries in ${this.dirPath}`);
|
|
218
|
-
entries.forEach(e => console.log(` ${e.name}: isDir=${e.isDirectory}, isFile=${e.isFile}`));
|
|
219
|
-
}
|
|
220
|
-
if (this.options.cmd || this.options.finding || this.options.forceAcl) {
|
|
221
|
-
if (this.options.forceAcl) {
|
|
222
|
-
// ACL operations not implemented
|
|
223
|
-
}
|
|
224
|
-
if (this.options.cmd) {
|
|
225
|
-
await this.executeCommand();
|
|
226
|
-
}
|
|
227
|
-
if (this.options.finding) {
|
|
228
|
-
// Use the entries we already have for finding
|
|
229
|
-
await this.findFilesFromEntries(entries);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
// Process files from the entries we already have
|
|
234
|
-
this.processFilesFromEntries(entries);
|
|
235
|
-
}
|
|
236
|
-
// Process directories for recursion (skip symlinks by default)
|
|
237
|
-
const directoryEntries = entries.filter(entry => entry.isDirectory && !entry.isSymlink);
|
|
238
|
-
for (const entry of directoryEntries) {
|
|
239
|
-
try {
|
|
240
|
-
const subPath = path.join(this.dirPath, entry.name);
|
|
241
|
-
const walker = new WalkTree(subPath, this.options, this.progressCallback, this.atDepth + 1);
|
|
242
|
-
await walker.walk();
|
|
243
|
-
if (this.options.verbose) {
|
|
244
|
-
console.log(`DEBUG: Completed walking ${entry.name}, about to process results`);
|
|
245
|
-
}
|
|
246
|
-
this.dirCount++;
|
|
247
|
-
this.length += walker.length;
|
|
248
|
-
this.compressedLength += walker.compressedLength;
|
|
249
|
-
this.totalFileCount += walker.totalFileCount;
|
|
250
|
-
this.totalDirCount += walker.totalDirCount + 1;
|
|
251
|
-
const divisor = this.options.sizeUnit === 'GB' ? (1024 * 1024 * 1024) : (1024 * 1024);
|
|
252
|
-
const size = walker.length / divisor;
|
|
253
|
-
if (this.options.verbose) {
|
|
254
|
-
console.log(`DEBUG: ${entry.name}: size=${size}, threshold=${this.options.threshold}, depth=${this.atDepth}/${this.options.depth}, length=${walker.length}`);
|
|
255
|
-
console.log(`DEBUG: condition check: (${this.options.threshold} === 0 || ${size} >= ${this.options.threshold}) && ${this.atDepth} < ${this.options.depth} = ${(this.options.threshold === 0 || size >= this.options.threshold) && this.atDepth < this.options.depth}`);
|
|
256
|
-
}
|
|
257
|
-
if ((this.options.threshold === 0 || size >= this.options.threshold) && this.atDepth < this.options.depth) {
|
|
258
|
-
if (!this.options.quiet) {
|
|
259
|
-
process.stdout.write('\x1b[2K\r'); // Clear progress line
|
|
260
|
-
}
|
|
261
|
-
console.log(`${this.prefix} ${walker.formatSize().padStart(13)} ${this.options.sizeUnit} ` +
|
|
262
|
-
`${walker.totalDirCount.toString().padStart(5)} ` +
|
|
263
|
-
`${walker.totalFileCount.toString().padStart(6)} ${entry.name}`);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
catch (err) {
|
|
267
|
-
if (this.options.verbose) {
|
|
268
|
-
console.log(`DEBUG: Error processing ${entry.name}: ${err}`);
|
|
269
|
-
}
|
|
270
|
-
this.logError(entry.name, err);
|
|
271
|
-
// Continue with next directory instead of aborting
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
catch (err) {
|
|
276
|
-
this.logError('directory walk', err);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
//# sourceMappingURL=diskwalker2.js.map
|
package/diskwalker2.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"diskwalker2.js","sourceRoot":"","sources":["diskwalker2.ts"],"names":[],"mappings":"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"}
|
package/diskwalker2.ts
DELETED
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import { spawn } from 'child_process';
|
|
4
|
-
import { styleText } from 'node:util';
|
|
5
|
-
import { listDirectory, getDriveInfo, type DirectoryEntry } from '@bobfrankston/dirutil';
|
|
6
|
-
|
|
7
|
-
interface WalkOptions {
|
|
8
|
-
depth: number;
|
|
9
|
-
threshold: number;
|
|
10
|
-
cmd: string;
|
|
11
|
-
verbose: boolean;
|
|
12
|
-
showCompressed: boolean;
|
|
13
|
-
finding: string[] | null;
|
|
14
|
-
forceAcl: boolean;
|
|
15
|
-
quiet: boolean;
|
|
16
|
-
sizeUnit: 'MB' | 'GB';
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
type ProgressCallback = (walker: WalkTree, currentPath: string) => void;
|
|
20
|
-
|
|
21
|
-
// Error types to suppress unless verbose
|
|
22
|
-
const suppressedErrors = ['ENOENT', 'EPERM', 'EACCES'];
|
|
23
|
-
|
|
24
|
-
// Directories to suppress errors from
|
|
25
|
-
const suppressedDirectories = ['$RECYCLE.BIN', 'System Volume Information'];
|
|
26
|
-
|
|
27
|
-
export class DiskWalker {
|
|
28
|
-
private static defaultOptions: WalkOptions = {
|
|
29
|
-
depth: 1,
|
|
30
|
-
threshold: 0,
|
|
31
|
-
cmd: '',
|
|
32
|
-
verbose: false,
|
|
33
|
-
showCompressed: false,
|
|
34
|
-
finding: null,
|
|
35
|
-
forceAcl: false,
|
|
36
|
-
quiet: false,
|
|
37
|
-
sizeUnit: 'MB'
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
private options: WalkOptions;
|
|
41
|
-
private walker: WalkTree;
|
|
42
|
-
private lastProgressTime: number = 0;
|
|
43
|
-
public static blockSizeCache: Map<string, number> = new Map();
|
|
44
|
-
|
|
45
|
-
constructor(private topPath: string = '.', options: Partial<WalkOptions> = {}) {
|
|
46
|
-
this.options = { ...DiskWalker.defaultOptions, ...options };
|
|
47
|
-
this.topPath = path.resolve(topPath);
|
|
48
|
-
this.walker = new WalkTree(this.topPath, this.options, this.showProgress.bind(this));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
private truncatePath(fullPath: string, maxLength: number = 64): string {
|
|
52
|
-
if (fullPath.length <= maxLength) return fullPath;
|
|
53
|
-
const half = Math.floor((maxLength - 3) / 2);
|
|
54
|
-
const start = fullPath.slice(0, half);
|
|
55
|
-
const end = fullPath.slice(-half);
|
|
56
|
-
return `${start}...${end}`;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
private showProgress(walker: WalkTree, currentPath: string): void {
|
|
60
|
-
const now = Date.now();
|
|
61
|
-
if (now - this.lastProgressTime > 1000 && !this.options.quiet) {
|
|
62
|
-
const truncatedPath = this.truncatePath(currentPath);
|
|
63
|
-
process.stdout.write('\x1b[2K\r'); // Clear entire line and return to start
|
|
64
|
-
const line = styleText(['blue'], `${walker.formatSize().padStart(13)} ${this.options.sizeUnit} ${truncatedPath}`);
|
|
65
|
-
process.stdout.write(line);
|
|
66
|
-
|
|
67
|
-
this.lastProgressTime = now;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async walk(): Promise<void> {
|
|
72
|
-
try {
|
|
73
|
-
await this.walker.walk();
|
|
74
|
-
if (!this.options.quiet) {
|
|
75
|
-
process.stdout.write('\x1b[2K\r'); // Clear progress line
|
|
76
|
-
}
|
|
77
|
-
const pather = `${styleText(['blue'], `${path.dirname(this.topPath)}${path.sep}`)}${styleText(['bgBlack', 'bold', 'yellow'], path.basename(this.topPath))}`
|
|
78
|
-
console.log(`${this.walker.formatSize()} ${this.options.sizeUnit} ${pather}`);
|
|
79
|
-
} catch (err: any) {
|
|
80
|
-
console.error('Failed:', (err as Error).message);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
class WalkTree {
|
|
86
|
-
private length: number = 0;
|
|
87
|
-
private compressedLength: number = 0;
|
|
88
|
-
private fileCount: number = 0;
|
|
89
|
-
private dirCount: number = 0;
|
|
90
|
-
private totalFileCount: number = 0;
|
|
91
|
-
private totalDirCount: number = 0;
|
|
92
|
-
private otherCount: number = 0;
|
|
93
|
-
private prefix: string;
|
|
94
|
-
private nextTitleUpdate: Date = new Date(0);
|
|
95
|
-
private seenErrors = new Set<string>();
|
|
96
|
-
private blockSize: number = 4096; // default 4KB, will be updated
|
|
97
|
-
|
|
98
|
-
constructor(
|
|
99
|
-
private dirPath: string,
|
|
100
|
-
private options: WalkOptions,
|
|
101
|
-
private progressCallback: ProgressCallback,
|
|
102
|
-
private atDepth: number = 0
|
|
103
|
-
) {
|
|
104
|
-
this.prefix = ' '.repeat(5 + atDepth * 5);
|
|
105
|
-
if (options.verbose) {
|
|
106
|
-
this.prefix = atDepth.toString().padStart(2, '0') + ' ' + this.prefix;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
private getDiskBlockSize(drivePath: string): number {
|
|
111
|
-
const drive = path.parse(drivePath).root;
|
|
112
|
-
|
|
113
|
-
if (DiskWalker.blockSizeCache.has(drive)) {
|
|
114
|
-
return DiskWalker.blockSizeCache.get(drive)!;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
try {
|
|
118
|
-
const driveInfo = getDriveInfo(drivePath);
|
|
119
|
-
const blockSize = driveInfo?.blockSize || 4096;
|
|
120
|
-
DiskWalker.blockSizeCache.set(drive, blockSize);
|
|
121
|
-
return blockSize;
|
|
122
|
-
} catch (err: any) {
|
|
123
|
-
// Fallback to default 4KB block size
|
|
124
|
-
DiskWalker.blockSizeCache.set(drive, 4096);
|
|
125
|
-
return 4096;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
private roundUpToBlockSize(fileSize: number, blockSize: number): number {
|
|
130
|
-
return Math.ceil(fileSize / blockSize) * blockSize;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
public formatSize(): string {
|
|
134
|
-
const divisor = this.options.sizeUnit === 'GB' ? (1024 * 1024 * 1024) : (1024 * 1024);
|
|
135
|
-
const size = this.length / divisor;
|
|
136
|
-
const formatted = size.toLocaleString(undefined, { minimumFractionDigits: 2 });
|
|
137
|
-
|
|
138
|
-
if (this.options.showCompressed && this.length !== this.compressedLength) {
|
|
139
|
-
const compressedSize = this.compressedLength / divisor;
|
|
140
|
-
return `${formatted}/${compressedSize.toLocaleString(undefined, { minimumFractionDigits: 2 })}`;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return formatted;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
private logError(context: string, err: Error): void {
|
|
147
|
-
// Only suppress errors if explicitly quiet, or if it's a known unimportant error
|
|
148
|
-
if (this.options.quiet ||
|
|
149
|
-
(!this.options.verbose &&
|
|
150
|
-
(suppressedErrors.some(e => err.message.includes(e)) ||
|
|
151
|
-
suppressedDirectories.some(d => this.dirPath.includes(d))))) {
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const errorKey = `${context}:${err.message}:${this.dirPath}`;
|
|
156
|
-
if (!this.seenErrors.has(errorKey)) {
|
|
157
|
-
console.error(styleText(['red'], `Error processing ${context}: ${err.message}`));
|
|
158
|
-
this.seenErrors.add(errorKey);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
private processFilesFromEntries(entries: DirectoryEntry[]): void {
|
|
163
|
-
try {
|
|
164
|
-
if (Date.now() > this.nextTitleUpdate.getTime()) {
|
|
165
|
-
process.title = this.dirPath;
|
|
166
|
-
this.nextTitleUpdate = new Date(Date.now() + 500);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Get block size once for this directory's drive
|
|
170
|
-
if (this.blockSize === 4096) { // Only query if we haven't set it yet
|
|
171
|
-
this.blockSize = this.getDiskBlockSize(this.dirPath);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const fileEntries = entries.filter(entry => entry.isFile);
|
|
175
|
-
for (const entry of fileEntries) {
|
|
176
|
-
this.fileCount++;
|
|
177
|
-
this.totalFileCount++;
|
|
178
|
-
const fileSize = entry.size || 0;
|
|
179
|
-
const blockAlignedSize = this.roundUpToBlockSize(fileSize, this.blockSize);
|
|
180
|
-
this.length += blockAlignedSize;
|
|
181
|
-
this.compressedLength += fileSize; // Keep original size for compressed display
|
|
182
|
-
}
|
|
183
|
-
} catch (err: any) {
|
|
184
|
-
this.logError('directory', err as Error);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
private async executeCommand(): Promise<void> {
|
|
189
|
-
if (!this.options.cmd) return;
|
|
190
|
-
|
|
191
|
-
const currentDir = process.cwd();
|
|
192
|
-
try {
|
|
193
|
-
process.chdir(this.dirPath);
|
|
194
|
-
await new Promise((resolve, reject) => {
|
|
195
|
-
const proc = spawn(this.options.cmd, [], { shell: true });
|
|
196
|
-
proc.on('close', resolve);
|
|
197
|
-
proc.on('error', reject);
|
|
198
|
-
});
|
|
199
|
-
} catch (err: any) {
|
|
200
|
-
this.logError('command execution', err as Error);
|
|
201
|
-
} finally {
|
|
202
|
-
process.chdir(currentDir);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
private async findFilesFromEntries(entries: DirectoryEntry[]): Promise<void> {
|
|
207
|
-
if (!this.options.finding) return;
|
|
208
|
-
|
|
209
|
-
try {
|
|
210
|
-
for (const pattern of this.options.finding) {
|
|
211
|
-
for (const entry of entries) {
|
|
212
|
-
if (entry.name.match(pattern)) {
|
|
213
|
-
const size = (entry.size || 0) / 1024;
|
|
214
|
-
const mtime = new Date(entry.mtime);
|
|
215
|
-
process.stdout.write('\x1b[2K\r'); // Clear progress line
|
|
216
|
-
console.log(
|
|
217
|
-
`${mtime.toISOString().slice(0, 19).replace('T', ' ')} ` +
|
|
218
|
-
`${size.toFixed(1).padStart(8)}KB ${this.prefix} ${path.join(this.dirPath, entry.name)}`
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
} catch (err: any) {
|
|
224
|
-
this.logError('file search', err as Error);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
public async walk(): Promise<void> {
|
|
229
|
-
try {
|
|
230
|
-
this.progressCallback(this, this.dirPath);
|
|
231
|
-
|
|
232
|
-
// try {
|
|
233
|
-
// // console.log(`DEBUG: Accessing directory: ${this.dirPath}`);
|
|
234
|
-
// // fs.accessSync(this.dirPath);
|
|
235
|
-
// // console.log(`DEBUG: Accessed directory: ${this.dirPath}`);
|
|
236
|
-
// fs.readdirSync(this.dirPath); // Ensure we can read the directory
|
|
237
|
-
// // console.log(`DEBUG: Read directory: ${this.dirPath}`);
|
|
238
|
-
// }
|
|
239
|
-
// catch (e: any) {
|
|
240
|
-
// // console.error(`DEBUG: Failed to access or read directory ${this.dirPath}: ${e.message}`);
|
|
241
|
-
// debugger;
|
|
242
|
-
// throw e
|
|
243
|
-
// }
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
// Get directory entries once
|
|
247
|
-
// console.log(`DEBUG: Walking directory: ${this.dirPath}`);
|
|
248
|
-
const entries = listDirectory(this.dirPath, { stats: true });
|
|
249
|
-
// console.log(`DEBUG: Walked directory: ${this.dirPath}`);
|
|
250
|
-
|
|
251
|
-
if (this.options.verbose) {
|
|
252
|
-
console.log(`DEBUG: Found ${entries.length} entries in ${this.dirPath}`);
|
|
253
|
-
entries.forEach(e => console.log(` ${e.name}: isDir=${e.isDirectory}, isFile=${e.isFile}`));
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (this.options.cmd || this.options.finding || this.options.forceAcl) {
|
|
257
|
-
if (this.options.forceAcl) {
|
|
258
|
-
// ACL operations not implemented
|
|
259
|
-
}
|
|
260
|
-
if (this.options.cmd) {
|
|
261
|
-
await this.executeCommand();
|
|
262
|
-
}
|
|
263
|
-
if (this.options.finding) {
|
|
264
|
-
// Use the entries we already have for finding
|
|
265
|
-
await this.findFilesFromEntries(entries);
|
|
266
|
-
}
|
|
267
|
-
} else {
|
|
268
|
-
// Process files from the entries we already have
|
|
269
|
-
this.processFilesFromEntries(entries);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Process directories for recursion (skip symlinks by default)
|
|
273
|
-
const directoryEntries = entries.filter(entry => entry.isDirectory && !entry.isSymlink);
|
|
274
|
-
for (const entry of directoryEntries) {
|
|
275
|
-
try {
|
|
276
|
-
const subPath = path.join(this.dirPath, entry.name);
|
|
277
|
-
const walker = new WalkTree(subPath, this.options, this.progressCallback, this.atDepth + 1);
|
|
278
|
-
|
|
279
|
-
await walker.walk();
|
|
280
|
-
if (this.options.verbose) {
|
|
281
|
-
console.log(`DEBUG: Completed walking ${entry.name}, about to process results`);
|
|
282
|
-
}
|
|
283
|
-
this.dirCount++;
|
|
284
|
-
this.length += walker.length;
|
|
285
|
-
this.compressedLength += walker.compressedLength;
|
|
286
|
-
this.totalFileCount += walker.totalFileCount;
|
|
287
|
-
this.totalDirCount += walker.totalDirCount + 1;
|
|
288
|
-
|
|
289
|
-
const divisor = this.options.sizeUnit === 'GB' ? (1024 * 1024 * 1024) : (1024 * 1024);
|
|
290
|
-
const size = walker.length / divisor;
|
|
291
|
-
if (this.options.verbose) {
|
|
292
|
-
console.log(`DEBUG: ${entry.name}: size=${size}, threshold=${this.options.threshold}, depth=${this.atDepth}/${this.options.depth}, length=${walker.length}`);
|
|
293
|
-
console.log(`DEBUG: condition check: (${this.options.threshold} === 0 || ${size} >= ${this.options.threshold}) && ${this.atDepth} < ${this.options.depth} = ${(this.options.threshold === 0 || size >= this.options.threshold) && this.atDepth < this.options.depth}`);
|
|
294
|
-
}
|
|
295
|
-
if ((this.options.threshold === 0 || size >= this.options.threshold) && this.atDepth < this.options.depth) {
|
|
296
|
-
if (!this.options.quiet) {
|
|
297
|
-
process.stdout.write('\x1b[2K\r'); // Clear progress line
|
|
298
|
-
}
|
|
299
|
-
console.log(
|
|
300
|
-
`${this.prefix} ${walker.formatSize().padStart(13)} ${this.options.sizeUnit} ` +
|
|
301
|
-
`${walker.totalDirCount.toString().padStart(5)} ` +
|
|
302
|
-
`${walker.totalFileCount.toString().padStart(6)} ${entry.name}`
|
|
303
|
-
);
|
|
304
|
-
}
|
|
305
|
-
} catch (err: any) {
|
|
306
|
-
if (this.options.verbose) {
|
|
307
|
-
console.log(`DEBUG: Error processing ${entry.name}: ${err}`);
|
|
308
|
-
}
|
|
309
|
-
this.logError(entry.name, err as Error);
|
|
310
|
-
// Continue with next directory instead of aborting
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
} catch (err: any) {
|
|
314
|
-
this.logError('directory walk', err as Error);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
export { WalkOptions };
|