@bobfrankston/tswalk 1.1.8 → 1.1.9

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/index.js CHANGED
@@ -2,6 +2,12 @@
2
2
  import { DiskWalker } from './diskwalker.js';
3
3
  import { defaultWalkOptions } from './utils.js';
4
4
  import { styleText } from 'node:util';
5
+ import packageJson from './package.json' with { type: 'json' };
6
+ const version = packageJson.version;
7
+ function showVersion() {
8
+ console.log(`tswalk v${version}`);
9
+ process.exit(0);
10
+ }
5
11
  function showUsage() {
6
12
  console.log(`
7
13
  Usage: tswalk [path] [depth] [options]
@@ -19,6 +25,7 @@ Options:
19
25
  -v Verbose output (show all errors including ENOENT/EPERM)
20
26
  -q Quiet mode (no progress updates, minimal errors)
21
27
  -acl Force ACL operations (Windows only)
28
+ --version Show version number
22
29
 
23
30
  Progress:
24
31
  Shows current directory being processed every second in blue.
@@ -44,6 +51,13 @@ async function main() {
44
51
  if (args.includes('-h') || args.includes('-help') || args.includes('--help')) {
45
52
  showUsage();
46
53
  }
54
+ if (args.includes('-v') && args.length === 1) {
55
+ // If -v is the only argument, show version
56
+ showVersion();
57
+ }
58
+ if (args.includes('--version')) {
59
+ showVersion();
60
+ }
47
61
  const options = {};
48
62
  let topPath = '.';
49
63
  let foundPath = false;
package/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,21 +1,38 @@
1
1
  {
2
2
  "name": "@bobfrankston/tswalk",
3
- "version": "1.1.8",
4
- "description": "Walk directory tree - simplified single implementation",
3
+ "version": "1.1.9",
4
+ "description": "Fast TypeScript directory tree walker with file search, size analysis, and pattern matching",
5
5
  "main": "index.js",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./index.js",
9
+ "types": "./index.d.ts"
10
+ }
11
+ },
6
12
  "bin": {
7
13
  "tswalk": "./index.js"
8
14
  },
9
- "module": "main.js",
15
+ "files": [
16
+ "*.js",
17
+ "*.d.ts",
18
+ "*.js.map",
19
+ "bin/"
20
+ ],
21
+ "engines": {
22
+ "node": ">=24.0.0"
23
+ },
10
24
  "scripts": {
11
25
  "build": "tsc",
26
+ "clean": "rimraf *.js *.d.ts *.js.map bin/*.js",
12
27
  "prerelease:local": "git add -A && (git diff-index --quiet HEAD || git commit -m \"Pre-release commit\")",
13
28
  "preversion": "npm run build && git add -A",
14
29
  "postversion": "git push && git push --tags",
15
30
  "release": "npm run prerelease:local && npm version patch && npm publish",
16
31
  "release:ps1": "releaseapp.ps1",
17
32
  "test": "echo \"Error: no test specified\" && exit 1",
18
- "installer": "npm run release && npm install -g @bobfrankston/tswalk && wsl npm install -g @bobfrankston/tswalk"
33
+ "installer": "npm run release && npm install -g @bobfrankston/tswalk && wsl npm install -g @bobfrankston/tswalk",
34
+ "dev": "tsc --watch",
35
+ "start": "node index.js"
19
36
  },
20
37
  "keywords": [
21
38
  "typescript",
@@ -1,9 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(ls:*)",
5
- "Bash(npm run build:*)"
6
- ],
7
- "deny": []
8
- }
9
- }
package/.editorconfig DELETED
@@ -1,9 +0,0 @@
1
- # EditorConfig helps maintain consistent coding styles
2
- root = true
3
-
4
- [*]
5
- end_of_line = lf
6
- insert_final_newline = true
7
- charset = utf-8
8
- indent_style = space
9
- indent_size = 2
package/.gitattributes DELETED
@@ -1,2 +0,0 @@
1
- # Normalize line endings in repo
2
- * text=auto eol=lf
@@ -1,32 +0,0 @@
1
- {
2
- // Use IntelliSense to learn about possible attributes.
3
- // Hover to view descriptions of existing attributes.
4
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
- "version": "0.2.0",
6
- "configurations": [
7
- {
8
- "name": "Launch Program",
9
- "program": "${workspaceFolder}/index.js",
10
- "request": "launch",
11
- "skipFiles": [
12
- "<node_internals>/**"
13
- ],
14
- "type": "node"
15
- },
16
- {
17
- "type": "node",
18
- "request": "launch",
19
- "name": "u:",
20
- "program": "${workspaceFolder}/index.js",
21
- "skipFiles": [
22
- "<node_internals>/**"
23
- ],
24
- "outFiles": [
25
- "${workspaceFolder}/**/*.js"
26
- ],
27
- "args": [
28
- "c:\\users\\bob\\onedrive\\pictures",
29
- ]
30
- }
31
- ]
32
- }
@@ -1,23 +0,0 @@
1
- {
2
- "workbench.colorCustomizations": {
3
- "activityBar.activeBackground": "#f4fd05",
4
- "activityBar.background": "#f4fd05",
5
- "activityBar.foreground": "#15202b",
6
- "activityBar.inactiveForeground": "#15202b99",
7
- "activityBarBadge.background": "#02b7be",
8
- "activityBarBadge.foreground": "#15202b",
9
- "commandCenter.border": "#15202b99",
10
- "sash.hoverBorder": "#f4fd05",
11
- "statusBar.background": "#c6cd02",
12
- "statusBar.foreground": "#15202b",
13
- "statusBarItem.hoverBackground": "#959a02",
14
- "statusBarItem.remoteBackground": "#c6cd02",
15
- "statusBarItem.remoteForeground": "#15202b",
16
- "titleBar.activeBackground": "#c6cd02",
17
- "titleBar.activeForeground": "#15202b",
18
- "titleBar.inactiveBackground": "#c6cd0299",
19
- "titleBar.inactiveForeground": "#15202b99"
20
- },
21
- "peacock.color": "#c6cd02",
22
- "workbench.colorTheme": "Visual Studio 2019 Dark"
23
- }
@@ -1,23 +0,0 @@
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
- }
@@ -1,20 +0,0 @@
1
- {
2
- "version": "2.0.0",
3
- "tasks": [
4
- {
5
- "label": "tsc: watch",
6
- "type": "shell",
7
- "command": "tsc",
8
- "args": ["--watch"],
9
- "runOptions": {
10
- "runOn": "folderOpen"
11
- },
12
- "problemMatcher": "$tsc-watch",
13
- "isBackground": true,
14
- "group": {
15
- "kind": "build",
16
- "isDefault": true
17
- }
18
- }
19
- ]
20
- }
package/diskwalker.ts DELETED
@@ -1,281 +0,0 @@
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
-
20
- import * as fs from 'fs';
21
- import * as fp from 'fs/promises'
22
- import * as path from 'path';
23
- import { spawn } from 'child_process';
24
- import { styleText } from 'node:util';
25
- import { compilePatterns, WalkOptions, defaultWalkOptions, suppressedErrors } from './utils.js';
26
-
27
- type ProgressCallback = (walker: WalkTree, currentPath: string) => void;
28
-
29
- export class DiskWalker {
30
- private static defaultOptions: WalkOptions = defaultWalkOptions;
31
-
32
- private options: WalkOptions;
33
- private walker: WalkTree;
34
- private lastProgressTime: number = 0;
35
-
36
- constructor(private topPath: string = '.', options: Partial<WalkOptions> = {}) {
37
- this.options = { ...DiskWalker.defaultOptions, ...options };
38
- this.topPath = path.resolve(topPath);
39
- this.walker = new WalkTree(this.topPath, this.options, this.showProgress.bind(this));
40
- }
41
-
42
- private truncatePath(fullPath: string, maxLength: number = 64): string {
43
- if (fullPath.length <= maxLength) return fullPath;
44
- const half = Math.floor((maxLength - 3) / 2);
45
- const start = fullPath.slice(0, half);
46
- const end = fullPath.slice(-half);
47
- return `${start}...${end}`;
48
- }
49
-
50
- private showProgress(walker: WalkTree, currentPath: string): void {
51
- const now = Date.now();
52
- if (now - this.lastProgressTime > 1000 && !this.options.quiet) {
53
- const truncatedPath = this.truncatePath(currentPath);
54
- process.stdout.write('\x1b[2K\r'); // Clear entire line and return to start
55
- const line = styleText(['blue'], `${walker.formatSize().padStart(13)} ${this.options.sizeUnit} ${truncatedPath}`);
56
- process.stdout.write(line);
57
-
58
- this.lastProgressTime = now;
59
- }
60
- }
61
-
62
- async walk(): Promise<void> {
63
- try {
64
- // Show column headers (only for directory listing, not file finding)
65
- if (!this.options.quiet && !this.options.finding && !this.options.cmd) {
66
- const prefix = ''; // No prefix at depth 0
67
- console.log(`${prefix} ${'Size'.padStart(13)} ${this.options.sizeUnit} ${'Dirs'.padStart(5)} ${'Files'.padStart(6)} Directory`);
68
- console.log(`${prefix} ${'-'.repeat(13)} ${'-'.repeat(this.options.sizeUnit.length)} ${'-'.repeat(5)} ${'-'.repeat(6)} ${'-'.repeat(9)}`);
69
- }
70
-
71
- await this.walker.walk();
72
- if (!this.options.quiet) {
73
- process.stdout.write('\x1b[2K\r'); // Clear progress line
74
- }
75
- console.log(`${this.walker.formatSize()} ${this.options.sizeUnit} ${styleText(['blue'], this.topPath)}`);
76
- } catch (err) {
77
- console.error('Failed:', (err as Error).message);
78
- }
79
- }
80
- }
81
-
82
- class WalkTree {
83
- private length: number = 0;
84
- private compressedLength: number = 0;
85
- private fileCount: number = 0;
86
- private dirCount: number = 0;
87
- private totalFileCount: number = 0;
88
- private totalDirCount: number = 0;
89
- private otherCount: number = 0;
90
- private prefix: string;
91
- private nextTitleUpdate: Date = new Date(0);
92
- private seenErrors = new Set<string>();
93
- private findingRegexes: RegExp[] | null = null;
94
-
95
- constructor(
96
- private dirPath: string,
97
- private options: WalkOptions,
98
- private progressCallback: ProgressCallback,
99
- private atDepth: number = 0
100
- ) {
101
- // Precompile find patterns into safe RegExp objects to avoid invalid regex errors
102
- if (this.options.finding) {
103
- this.findingRegexes = compilePatterns(this.options.finding);
104
- }
105
- this.prefix = ' '.repeat(atDepth * 5);
106
- if (options.verbose) {
107
- this.prefix = atDepth.toString().padStart(2, '0') + ' ' + this.prefix;
108
- }
109
- }
110
-
111
- public formatSize(): string {
112
- const divisor = this.options.sizeUnit === 'GB' ? (1024 * 1024 * 1024) : (1024 * 1024);
113
- const size = this.length / divisor;
114
-
115
- // For MB, show whole numbers; for GB, show 2 decimal places
116
- const fractionDigits = this.options.sizeUnit === 'MB' ? 0 : 2;
117
- const formatted = size.toLocaleString(undefined, { minimumFractionDigits: fractionDigits, maximumFractionDigits: fractionDigits });
118
-
119
- if (this.options.showCompressed && this.length !== this.compressedLength) {
120
- const compressedSize = this.compressedLength / divisor;
121
- const compressedFormatted = compressedSize.toLocaleString(undefined, { minimumFractionDigits: fractionDigits, maximumFractionDigits: fractionDigits });
122
- return `${formatted}/${compressedFormatted}`;
123
- }
124
-
125
- return formatted;
126
- }
127
-
128
- private logError(context: string, err: Error): void {
129
- if (!this.options.verbose &&
130
- (this.options.quiet || suppressedErrors.some(e => err.message.includes(e)))) {
131
- return;
132
- }
133
-
134
- const errorKey = `${context}:${err.message}:${this.dirPath}`;
135
- if (!this.seenErrors.has(errorKey)) {
136
- console.error(styleText(['red'], `Error processing ${context}: ${err.message}`));
137
- this.seenErrors.add(errorKey);
138
- }
139
- }
140
-
141
- private async isSymlink(testPath: string): Promise<boolean> {
142
- try {
143
- const stats = await fp.lstat(testPath);
144
- return stats.isSymbolicLink();
145
- } catch {
146
- return false;
147
- }
148
- }
149
-
150
- private async processDirectory(): Promise<void> {
151
- try {
152
- if (Date.now() > this.nextTitleUpdate.getTime()) {
153
- process.title = this.dirPath;
154
- this.nextTitleUpdate = new Date(Date.now() + 500);
155
- }
156
-
157
- const files = await fp.readdir(this.dirPath, { withFileTypes: true });
158
-
159
- for (const file of files) {
160
- if (!file.isDirectory()) {
161
- this.fileCount++;
162
- this.totalFileCount++;
163
-
164
- try {
165
- const stats = await fp.stat(path.join(this.dirPath, file.name));
166
- this.length += stats.size;
167
- this.compressedLength += stats.size;
168
- } catch (err) {
169
- this.logError(file.name, err as Error);
170
- }
171
- }
172
- }
173
- } catch (err) {
174
- this.logError('directory', err as Error);
175
- }
176
- }
177
-
178
- private async executeCommand(): Promise<void> {
179
- if (!this.options.cmd) return;
180
-
181
- const currentDir = process.cwd();
182
- try {
183
- process.chdir(this.dirPath);
184
- await new Promise((resolve, reject) => {
185
- const proc = spawn(this.options.cmd, [], { shell: true });
186
- proc.on('close', resolve);
187
- proc.on('error', reject);
188
- });
189
- } catch (err) {
190
- this.logError('command execution', err as Error);
191
- } finally {
192
- process.chdir(currentDir);
193
- }
194
- }
195
-
196
- private async findFiles(): Promise<void> {
197
- if (!this.options.finding) return;
198
- try {
199
- const files = await fp.readdir(this.dirPath);
200
- const regexes = this.findingRegexes || [];
201
-
202
- for (const file of files) {
203
- if (regexes.length && regexes.some(rx => rx.test(file))) {
204
- try {
205
- const stats = await fp.stat(path.join(this.dirPath, file));
206
- const size = stats.size / 1024;
207
- process.stdout.write('\x1b[2K\r'); // Clear progress line
208
- console.log(
209
- `${stats.mtime.toISOString().slice(0, 19).replace('T', ' ')} ` +
210
- `${size.toFixed(1).padStart(8)}KB ${this.prefix} ${path.join(this.dirPath, file)}`
211
- );
212
- } catch (err) {
213
- this.logError(file, err as Error);
214
- }
215
- }
216
- }
217
- } catch (err) {
218
- this.logError('file search', err as Error);
219
- }
220
- }
221
-
222
- public async walk(): Promise<void> {
223
- try {
224
- const isSymlink = await this.isSymlink(this.dirPath);
225
- if (isSymlink) return;
226
-
227
- this.progressCallback(this, this.dirPath);
228
-
229
- if (this.options.cmd || this.options.finding || this.options.forceAcl) {
230
- if (this.options.forceAcl) {
231
- // ACL operations not implemented
232
- }
233
- if (this.options.cmd) {
234
- await this.executeCommand();
235
- }
236
- if (this.options.finding) {
237
- await this.findFiles();
238
- }
239
- } else {
240
- await this.processDirectory();
241
- }
242
-
243
- const entries = await fp.readdir(this.dirPath, { withFileTypes: true });
244
-
245
- for (const entry of entries) {
246
- if (entry.isDirectory()) {
247
- const subPath = path.join(this.dirPath, entry.name);
248
- const walker = new WalkTree(subPath, this.options, this.progressCallback, this.atDepth + 1);
249
-
250
- try {
251
- await walker.walk();
252
- this.dirCount++;
253
- this.length += walker.length;
254
- this.compressedLength += walker.compressedLength;
255
- this.totalFileCount += walker.totalFileCount;
256
- this.totalDirCount += walker.totalDirCount + 1;
257
-
258
- const divisor = this.options.sizeUnit === 'GB' ? (1024 * 1024 * 1024) : (1024 * 1024);
259
- const size = walker.length / divisor;
260
- if (size >= this.options.threshold && this.atDepth < this.options.depth) {
261
- if (!this.options.quiet) {
262
- process.stdout.write('\x1b[2K\r'); // Clear progress line
263
- }
264
- console.log(
265
- `${this.prefix} ${walker.formatSize().padStart(13)} ${this.options.sizeUnit} ` +
266
- `${walker.totalDirCount.toString().padStart(5)} ` +
267
- `${walker.totalFileCount.toString().padStart(6)} ${styleText(['blue'], entry.name)}`
268
- );
269
- }
270
- } catch (err) {
271
- this.logError(entry.name, err as Error);
272
- }
273
- }
274
- }
275
- } catch (err) {
276
- this.logError('directory walk', err as Error);
277
- }
278
- }
279
- }
280
-
281
- export { WalkOptions } from './utils.js';
package/index.ts DELETED
@@ -1,138 +0,0 @@
1
- #!/usr/bin/env node
2
- import { DiskWalker, WalkOptions } from './diskwalker.js';
3
- import { defaultWalkOptions } from './utils.js';
4
- import { styleText } from 'node:util';
5
-
6
- function showUsage() {
7
- console.log(`
8
- Usage: tswalk [path] [depth] [options]
9
- path Directory to analyze (default: current directory)
10
- depth Maximum depth to show in output (default: 1)
11
-
12
- Options:
13
- -d, -depth Set maximum depth to show in output
14
- -t Threshold in MB/GB for showing directories
15
- -mb Show sizes in megabytes (default)
16
- -gb Show sizes in gigabytes
17
- -c Show compressed sizes (Windows only)
18
- -r "cmd" Run command in each directory
19
- -f pattern Find files matching pattern (can use ;-separated patterns)
20
- -v Verbose output (show all errors including ENOENT/EPERM)
21
- -q Quiet mode (no progress updates, minimal errors)
22
- -acl Force ACL operations (Windows only)
23
-
24
- Progress:
25
- Shows current directory being processed every second in blue.
26
- Long paths are truncated in progress display.
27
-
28
- Error Handling:
29
- Default: Shows significant errors (excluding ENOENT/EPERM)
30
- -v: Shows all errors including access denied and not found
31
- -q: Shows only fatal errors
32
-
33
- Examples:
34
- tswalk . # Analyze current directory
35
- tswalk /path 3 # Show 3 levels deep
36
- tswalk /path -d 3 -gb # Same, but show sizes in GB
37
- tswalk /path -t 100 -gb # Show dirs > 100GB
38
- tswalk . -f "*.ts;*.js" # Find TypeScript and JavaScript files
39
- tswalk /path -v # Show all errors while processing
40
- `);
41
- process.exit(0);
42
- }
43
-
44
- async function main() {
45
- const args = process.argv.slice(2);
46
-
47
- if (args.includes('-h') || args.includes('-help') || args.includes('--help')) {
48
- showUsage();
49
- }
50
-
51
- const options: Partial<WalkOptions> = {};
52
- let topPath = '.';
53
- let foundPath = false;
54
- let foundDepth = false;
55
-
56
- for (let i = 0; i < args.length; i++) {
57
- const arg = args[i];
58
-
59
- if (arg.startsWith('-')) {
60
- switch (arg) {
61
- case '-r':
62
- case '-run':
63
- options.cmd = args[++i];
64
- break;
65
- case '-d':
66
- case '-depth':
67
- options.depth = parseInt(args[++i]);
68
- foundDepth = true;
69
- break;
70
- case '-t':
71
- case '-threshold':
72
- options.threshold = parseInt(args[++i]);
73
- break;
74
- case '-c':
75
- case '-compressed':
76
- options.showCompressed = true;
77
- break;
78
- case '-f':
79
- case '-find':
80
- options.finding = args[++i].split(';');
81
- break;
82
- case '-v':
83
- case '-verbose':
84
- options.verbose = true;
85
- break;
86
- case '-q':
87
- case '-quiet':
88
- options.quiet = true;
89
- break;
90
- case '-mb':
91
- options.sizeUnit = 'MB';
92
- break;
93
- case '-gb':
94
- options.sizeUnit = 'GB';
95
- break;
96
- case '-acl':
97
- options.forceAcl = true;
98
- break;
99
- case '-h':
100
- case '-help':
101
- case '--help':
102
- showUsage();
103
- break;
104
- default:
105
- console.error(styleText(['red'], 'Invalid option:'), arg);
106
- showUsage();
107
- }
108
- } else {
109
- // Not a flag
110
- if (!foundPath) {
111
- topPath = arg;
112
- foundPath = true;
113
- } else if (!foundDepth && !isNaN(Number(arg))) {
114
- options.depth = parseInt(arg);
115
- foundDepth = true;
116
- }
117
- }
118
- }
119
-
120
- if (options.quiet && options.verbose) {
121
- console.warn(styleText(['yellow'], 'Warning: Both -q and -v specified; verbose output will be used'));
122
- options.quiet = false;
123
- }
124
-
125
- try {
126
- const fullOptions = { ...defaultWalkOptions, ...options };
127
- const walker = new DiskWalker(topPath, fullOptions);
128
- await walker.walk();
129
- } catch (err) {
130
- console.error(styleText(['red'], '\nFatal error:'), err);
131
- process.exit(1);
132
- }
133
- }
134
-
135
- main().catch(err => {
136
- console.error(styleText(['red'], '\nFatal error:'), err);
137
- process.exit(1);
138
- });
package/programming.md DELETED
@@ -1,40 +0,0 @@
1
- # Programming Notes
2
-
3
- ## Version Handling Best Practices
4
-
5
- ### Always Import Version from package.json
6
- - Never hardcode version numbers in source code
7
- - Import version from `package.json` using JSON import
8
- - This ensures version stays in sync with package releases
9
-
10
- ```typescript
11
- // Good: Import from package.json
12
- import { readFileSync } from 'fs';
13
- import { fileURLToPath } from 'url';
14
- import { dirname, join } from 'path';
15
-
16
- const __filename = fileURLToPath(import.meta.url);
17
- const __dirname = dirname(__filename);
18
- const packageJson = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'utf8'));
19
- const VERSION = packageJson.version;
20
-
21
- // Bad: Hardcoded version
22
- const VERSION = "1.1.6"; // Will get out of sync!
23
- ```
24
-
25
- ### Version Display Guidelines
26
- - Don't show version by default - tools should be quiet
27
- - Only show version when explicitly requested with `--version` flag
28
- - Keep startup clean and focused on the task
29
-
30
- ### UI/UX Improvements
31
- - **Column headers** make output much more readable and professional
32
- - Headers should align with data columns
33
- - Use consistent spacing and formatting
34
- - Consider users who need to parse or read the output
35
-
36
- ## Code Organization
37
- - Keep version logic separate from main functionality
38
- - Use clear, descriptive variable names
39
- - Document architectural decisions in code comments
40
- - Maintain consistent error handling patterns
package/tsconfig.json DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "esnext",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "sourceMap": true,
7
- "newLine": "lf",
8
- "esModuleInterop": true,
9
- "forceConsistentCasingInFileNames": true,
10
- "strict": true,
11
- "strictNullChecks": false,
12
- "skipLibCheck": true
13
- }
14
- }
package/utils.ts DELETED
@@ -1,100 +0,0 @@
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
- }