@bobfrankston/tsfind 0.1.2 → 0.1.3
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/README.md +2 -1
- package/index.d.ts +4 -0
- package/index.js +36 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,7 +33,8 @@ tsfind [dir] [pattern] [options]
|
|
|
33
33
|
|------|-------------|
|
|
34
34
|
| `-o file` | Write the list (or the `-count` tables) to a file instead of the console |
|
|
35
35
|
| `-l` | Long: date and size before each path |
|
|
36
|
-
| `-
|
|
36
|
+
| `-f` | Files only (default: files and directories whose names match) |
|
|
37
|
+
| `-d` | Directories and links only (listed with no size) |
|
|
37
38
|
| `-count` | Number and total size of matches by name and by extension |
|
|
38
39
|
| `-sort key` | `-count` order: `size` (default), `count` or `name` |
|
|
39
40
|
| `-top N` | `-count` rows per table (default 50; 0 = all) |
|
package/index.d.ts
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* count them by name and extension, or show where the space goes
|
|
5
5
|
*
|
|
6
6
|
* CHANGE LOG (newest first)
|
|
7
|
+
* 2026-11-14 — Claude Code (Opus 5.5), at Bob's direction ("tsfind xlate should find the xlate
|
|
8
|
+
* directory as well as files with that name"): directories (and links) whose names match are now
|
|
9
|
+
* reported by default. -f = files only; -d now means directories only (it used to mean "also
|
|
10
|
+
* directories"). The summary counts files and directories separately.
|
|
7
11
|
* 2026-11-11 — Claude Code (Opus 5.5), at Bob's direction: usage text and README brought into
|
|
8
12
|
* line: the same examples in both, and both say a walk lists unreadable entries even with -q.
|
|
9
13
|
* 2026-11-09 — Claude Code (Opus 5.5), at Bob's direction: "if you can elevate without a prompt
|
package/index.js
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* count them by name and extension, or show where the space goes
|
|
5
5
|
*
|
|
6
6
|
* CHANGE LOG (newest first)
|
|
7
|
+
* 2026-11-14 — Claude Code (Opus 5.5), at Bob's direction ("tsfind xlate should find the xlate
|
|
8
|
+
* directory as well as files with that name"): directories (and links) whose names match are now
|
|
9
|
+
* reported by default. -f = files only; -d now means directories only (it used to mean "also
|
|
10
|
+
* directories"). The summary counts files and directories separately.
|
|
7
11
|
* 2026-11-11 — Claude Code (Opus 5.5), at Bob's direction: usage text and README brought into
|
|
8
12
|
* line: the same examples in both, and both say a walk lists unreadable entries even with -q.
|
|
9
13
|
* 2026-11-09 — Claude Code (Opus 5.5), at Bob's direction: "if you can elevate without a prompt
|
|
@@ -91,8 +95,9 @@ Options:
|
|
|
91
95
|
-o file Write the list (or the tables) to file instead of the console
|
|
92
96
|
-l Long: date and size before each path (default: path only, one per line,
|
|
93
97
|
so the list can be edited)
|
|
94
|
-
-
|
|
95
|
-
|
|
98
|
+
-f Files only (default: files and directories whose names match)
|
|
99
|
+
-d Directories (and links) only. Directories are listed with no size; the
|
|
100
|
+
search never goes inside links or junctions
|
|
96
101
|
-count Instead of listing: number and total size of matches by name and by
|
|
97
102
|
extension
|
|
98
103
|
-sort key -count order: size (default), count or name
|
|
@@ -143,7 +148,7 @@ function parseArgs(args) {
|
|
|
143
148
|
process.exit(1);
|
|
144
149
|
}
|
|
145
150
|
const options = {
|
|
146
|
-
positional: [], patterns: null, top: '.', outFile: '', long: false,
|
|
151
|
+
positional: [], patterns: null, top: '.', outFile: '', long: false, kinds: 'all', count: false,
|
|
147
152
|
sort: 'size', rows: DEFAULT_TOP, hogs: null, hogsRows: DEFAULT_HOGS, hogsPercent: 0, quiet: false,
|
|
148
153
|
refreshScan: '',
|
|
149
154
|
};
|
|
@@ -165,8 +170,11 @@ function parseArgs(args) {
|
|
|
165
170
|
case '-l':
|
|
166
171
|
options.long = true;
|
|
167
172
|
break;
|
|
173
|
+
case '-f':
|
|
174
|
+
options.kinds = 'files';
|
|
175
|
+
break;
|
|
168
176
|
case '-d':
|
|
169
|
-
options.
|
|
177
|
+
options.kinds = 'dirs';
|
|
170
178
|
break;
|
|
171
179
|
case '-count':
|
|
172
180
|
options.count = true;
|
|
@@ -514,6 +522,18 @@ function makeLimiter(max) {
|
|
|
514
522
|
}
|
|
515
523
|
};
|
|
516
524
|
}
|
|
525
|
+
/** "1 file", "2 files" */
|
|
526
|
+
function plural(n, one, many) {
|
|
527
|
+
return `${n.toLocaleString()} ${n === 1 ? one : many}`;
|
|
528
|
+
}
|
|
529
|
+
/** Whether a match of this kind is reported under -f / -d / neither */
|
|
530
|
+
function wanted(isDir, options) {
|
|
531
|
+
switch (options.kinds) {
|
|
532
|
+
case 'files': return !isDir;
|
|
533
|
+
case 'dirs': return isDir;
|
|
534
|
+
default: return true;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
517
537
|
/**
|
|
518
538
|
* Hand each match beneath `top` to onFound, reading WALK_CONCURRENCY directories at a time.
|
|
519
539
|
* Links and junctions are reported like directories but never entered, as in searchVolume.
|
|
@@ -545,7 +565,7 @@ async function walkTree(top, regexes, options, onFound) {
|
|
|
545
565
|
subdirs.push(full);
|
|
546
566
|
if (!regexes.some(rx => rx.test(entry.name)))
|
|
547
567
|
continue;
|
|
548
|
-
if (isDir
|
|
568
|
+
if (!wanted(isDir, options))
|
|
549
569
|
continue;
|
|
550
570
|
stats.push(limit(() => fp.lstat(full)).then(st => onFound({ path: full, name: entry.name, size: isDir ? 0 : st.size, mtime: st.mtime, isDir }),
|
|
551
571
|
// Not lost: a match that vanished or cannot be read is listed with the summary.
|
|
@@ -580,7 +600,7 @@ function searchVolume(volume, start, regexes, options, onFound) {
|
|
|
580
600
|
const name = volume.name(id);
|
|
581
601
|
if (!regexes.some(rx => rx.test(name)))
|
|
582
602
|
continue;
|
|
583
|
-
if (isDir
|
|
603
|
+
if (!wanted(isDir, options))
|
|
584
604
|
continue;
|
|
585
605
|
onFound({ path: volume.path(id), name, size: isDir ? 0 : volume.size(id), mtime: volume.mtime(id), isDir });
|
|
586
606
|
}
|
|
@@ -717,11 +737,15 @@ async function main() {
|
|
|
717
737
|
const found = [];
|
|
718
738
|
const byName = new Map();
|
|
719
739
|
const byExt = new Map();
|
|
720
|
-
let
|
|
740
|
+
let fileCount = 0;
|
|
741
|
+
let dirCount = 0;
|
|
721
742
|
let matchBytes = 0;
|
|
722
743
|
const tallying = options.count || !!options.hogs;
|
|
723
744
|
const onFound = (f) => {
|
|
724
|
-
|
|
745
|
+
if (f.isDir)
|
|
746
|
+
dirCount++;
|
|
747
|
+
else
|
|
748
|
+
fileCount++;
|
|
725
749
|
matchBytes += f.size;
|
|
726
750
|
if (!tallying) {
|
|
727
751
|
found.push(f);
|
|
@@ -760,8 +784,10 @@ async function main() {
|
|
|
760
784
|
await finished(out);
|
|
761
785
|
}
|
|
762
786
|
if (!options.quiet) {
|
|
763
|
-
const
|
|
764
|
-
|
|
787
|
+
const counts = options.kinds === 'files' ? plural(fileCount, 'file', 'files')
|
|
788
|
+
: options.kinds === 'dirs' ? `${plural(dirCount, 'directory', 'directories')} matched`
|
|
789
|
+
: `${plural(fileCount, 'file', 'files')} and ${plural(dirCount, 'directory', 'directories')} matched`;
|
|
790
|
+
console.error(`${counts}, ${formatBytes(matchBytes)}; ${dirs.toLocaleString()} directories searched; ` +
|
|
765
791
|
`${elapsedText(elapsed)}${options.outFile ? `; written to ${path.resolve(options.outFile)}` : ''}`);
|
|
766
792
|
console.error(styleText([source.stale ? 'red' : 'blue'], `From the ${source.text}.`));
|
|
767
793
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/tsfind",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Find files by name in a directory tree; list them for editing, or count them by name and extension. Optional NTFS MFT reading for big drives.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|