@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 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
- | `-d` | Also report directories and links whose names match (listed with no size) |
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
- -d Also report directories and links whose names match (listed with no size;
95
- the search never goes inside links or junctions)
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, dirs: false, count: 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.dirs = true;
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 && !options.dirs)
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 && !options.dirs)
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 matchCount = 0;
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
- matchCount++;
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 what = options.dirs ? 'matches' : 'files';
764
- console.error(`${matchCount.toLocaleString()} ${what}, ${formatBytes(matchBytes)}; ${dirs.toLocaleString()} directories searched; ` +
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.2",
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": {