@tb.p/dd 1.1.2 → 1.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tb.p/dd",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "A comprehensive command-line tool for finding and removing duplicate files using content-based hashing",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -24,6 +24,7 @@
24
24
  "dependencies": {
25
25
  "commander": "^11.1.0",
26
26
  "hash-wasm": "^4.12.0",
27
+ "recursive-readdir": "^2.2.3",
27
28
  "sqlite3": "^5.1.6"
28
29
  },
29
30
  "engines": {
@@ -514,9 +514,13 @@ export async function runCandidateDetection(options) {
514
514
  maxConcurrency: parseInt(options.maxConcurrency) || 5,
515
515
  verbose: options.verbose || false,
516
516
  onProgress: options.verbose ? (progress) => {
517
- if (progress.phase === 'hashing') {
518
- const percentage = (progress.percentage || 0).toFixed(1);
519
- console.log(`📊 Hashing progress: ${progress.processed}/${progress.total} files (${percentage}%) - ${progress.hashedFiles} hashed, ${progress.errors} errors`);
517
+ if (progress && progress.phase === 'hashing') {
518
+ const processed = progress.processed || 0;
519
+ const total = progress.total || 0;
520
+ const hashedFiles = progress.hashedFiles || 0;
521
+ const errors = progress.errors || 0;
522
+ const percentage = total > 0 ? ((processed / total) * 100).toFixed(1) : '0.0';
523
+ console.log(`📊 Hashing progress: ${processed}/${total} files (${percentage}%) - ${hashedFiles} hashed, ${errors} errors`);
520
524
  }
521
525
  } : null
522
526
  });
@@ -36,18 +36,25 @@ async function scanDirectory(dirPath, options = {}) {
36
36
  }
37
37
 
38
38
  async function getBatchFileInfo(filePaths, options = {}) {
39
- // OPTIMIZATION: Batch all stat() operations for parallel I/O
40
- const statPromises = filePaths.map(async (filePath) => {
41
- try {
42
- const normalizedPath = normalizePath(filePath);
43
- const stats = await fs.stat(normalizedPath);
44
- return { filePath: normalizedPath, stats, error: null };
45
- } catch (error) {
46
- return { filePath, stats: null, error };
47
- }
48
- });
39
+ // OPTIMIZATION: Batch stat() operations with controlled concurrency to prevent stack overflow
40
+ const BATCH_SIZE = 100; // Process files in chunks to prevent excessive Promise.all
41
+ const statResults = [];
42
+
43
+ for (let i = 0; i < filePaths.length; i += BATCH_SIZE) {
44
+ const batch = filePaths.slice(i, i + BATCH_SIZE);
45
+ const statPromises = batch.map(async (filePath) => {
46
+ try {
47
+ const normalizedPath = normalizePath(filePath);
48
+ const stats = await fs.stat(normalizedPath);
49
+ return { filePath: normalizedPath, stats, error: null };
50
+ } catch (error) {
51
+ return { filePath, stats: null, error };
52
+ }
53
+ });
49
54
 
50
- const statResults = await Promise.all(statPromises);
55
+ const batchResults = await Promise.all(statPromises);
56
+ statResults.push(...batchResults);
57
+ }
51
58
  const files = [];
52
59
 
53
60
  for (const result of statResults) {