CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-dir-compare

Node JS directory compare library with extensive comparison options and TypeScript support

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

comparison-functions.mddocs/

Comparison Functions

Core comparison functionality for synchronous and asynchronous directory and file comparison operations.

Capabilities

Synchronous Comparison

Performs directory or file comparison synchronously and returns detailed results immediately.

/**
 * Synchronously compares given paths.
 * @param path1 Left file or directory to be compared
 * @param path2 Right file or directory to be compared  
 * @param options Comparison options
 * @returns Detailed comparison result with statistics and differences
 */
function compareSync(path1: string, path2: string, options?: Options): Result;

Usage Examples:

import { compareSync, Options } from "dir-compare";

// Basic directory comparison
const result = compareSync("/path/to/dir1", "/path/to/dir2");
console.log(`Same: ${result.same}, Differences: ${result.differences}`);

// File comparison with content check
const options: Options = {
  compareContent: true,
  compareSize: true
};
const fileResult = compareSync("/path/to/file1.txt", "/path/to/file2.txt", options);

// Advanced comparison with filters
const advancedOptions: Options = {
  compareContent: true,
  compareDate: true,
  excludeFilter: "*.log,temp/**",
  includeFilter: "*.js,*.ts",
  ignoreCase: true,
  skipEmptyDirs: true
};
const filtered = compareSync("/src", "/backup/src", advancedOptions);

Asynchronous Comparison

Performs directory or file comparison asynchronously, ideal for large directory structures and UI applications.

/**
 * Asynchronously compares given paths.
 * @param path1 Left file or directory to be compared
 * @param path2 Right file or directory to be compared
 * @param options Comparison options
 * @returns Promise resolving to detailed comparison result
 */
function compare(path1: string, path2: string, options?: Options): Promise<Result>;

Usage Examples:

import { compare, Options } from "dir-compare";

// Basic async comparison
compare("/path/to/dir1", "/path/to/dir2")
  .then(result => {
    console.log(`Comparison complete: ${result.same ? 'identical' : 'different'}`);
    console.log(`Files compared: ${result.totalFiles}`);
  })
  .catch(error => console.error("Comparison failed:", error));

// Async with await
async function compareDirectories() {
  const options: Options = { 
    compareContent: true,
    noDiffSet: false // Include detailed differences
  };
  
  try {
    const result = await compare("/large/dir1", "/large/dir2", options);
    
    // Process results
    result.diffSet?.forEach(diff => {
      if (diff.state !== 'equal') {
        console.log(`${diff.relativePath}: ${diff.name1} vs ${diff.name2} - ${diff.state}`);
      }
    });
    
    return result;
  } catch (error) {
    console.error("Comparison error:", error);
    throw error;
  }
}

Options Interface

Comprehensive configuration options for customizing comparison behavior.

interface Options {
  // Comparison strategies
  compareSize?: boolean;           // Compare files by size (default: false)
  compareContent?: boolean;        // Compare files by content (default: false)  
  compareDate?: boolean;          // Compare files by modification date (default: false)
  compareSymlink?: boolean;       // Compare symlink values (default: false)
  dateTolerance?: number;         // Date comparison tolerance in ms (default: 1000)

  // Directory traversal options
  skipSubdirs?: boolean;          // Skip subdirectories (default: false)
  skipEmptyDirs?: boolean;        // Ignore empty directories (default: false)  
  skipSymlinks?: boolean;         // Ignore symbolic links (default: false)

  // Name comparison
  ignoreCase?: boolean;           // Case-insensitive name comparison (default: false)

  // Filtering
  includeFilter?: string;         // Comma-separated minimatch include patterns
  excludeFilter?: string;         // Comma-separated minimatch exclude patterns

  // Performance and memory
  noDiffSet?: boolean;           // Exclude diffSet from results (default: false)

  // Error handling  
  handlePermissionDenied?: boolean; // Continue on permission errors (default: false)

  // Extension points
  resultBuilder?: ResultBuilder;        // Custom result builder
  compareFileSync?: CompareFileSync;    // Custom sync file comparator
  compareFileAsync?: CompareFileAsync;  // Custom async file comparator  
  compareNameHandler?: CompareNameHandler; // Custom name comparator
  filterHandler?: FilterHandler;        // Custom filter handler

  // Additional properties for custom handlers
  [key: string]: any;
}

Result Interface

Detailed comparison results with comprehensive statistics and optional difference listing.

interface Result extends Statistics {
  /**
   * Detailed list of comparison results.
   * Present if Options.noDiffSet is false (default).
   */
  diffSet?: DiffSet;
}

Result Processing Examples:

import { compareSync, Result } from "dir-compare";

const result: Result = compareSync("/dir1", "/dir2", { compareContent: true });

// Check if directories are identical
if (result.same) {
  console.log("✅ Directories are identical");
} else {
  console.log(`❌ Found ${result.differences} differences`);
  
  // Analyze statistics
  console.log(`Files: ${result.equalFiles} equal, ${result.distinctFiles} different`);
  console.log(`Directories: ${result.equalDirs} equal, ${result.distinctDirs} different`);
  console.log(`Left only: ${result.left}, Right only: ${result.right}`);
}

// Process individual differences
result.diffSet?.forEach(diff => {
  switch (diff.state) {
    case 'left':
      console.log(`➖ Only in left: ${diff.relativePath}/${diff.name1}`);
      break;
    case 'right':  
      console.log(`➕ Only in right: ${diff.relativePath}/${diff.name2}`);
      break;
    case 'distinct':
      console.log(`🔄 Different: ${diff.relativePath}/${diff.name1} - ${diff.reason}`);
      break;
    case 'equal':
      // Usually filtered out, but available if needed
      break;
  }
});

// Handle special cases
if (result.brokenLinks.totalBrokenLinks > 0) {
  console.log(`⚠️  Found ${result.brokenLinks.totalBrokenLinks} broken symlinks`);
}

if (result.permissionDenied.totalPermissionDenied > 0) {
  console.log(`🔒 ${result.permissionDenied.totalPermissionDenied} permission denied entries`);
}

Error Handling

import { compare, compareSync } from "dir-compare";

// Handle permission errors gracefully
const options = {
  compareContent: true,
  handlePermissionDenied: true // Continue on permission errors
};

try {
  const result = await compare("/protected/dir1", "/protected/dir2", options);
  
  // Check for permission issues
  if (result.permissionDenied.totalPermissionDenied > 0) {
    console.warn(`Could not access ${result.permissionDenied.totalPermissionDenied} entries`);
    
    // Examine specific permission errors in diffSet
    result.diffSet?.forEach(diff => {
      if (diff.permissionDeniedState !== 'access-ok') {
        console.log(`Permission denied: ${diff.relativePath} - ${diff.permissionDeniedState}`);
      }
    });
  }
} catch (error) {
  console.error("Fatal comparison error:", error);
}

Performance Considerations

import { compare } from "dir-compare";

// For large directory comparisons
const largeDirectoryOptions = {
  compareContent: true,
  noDiffSet: true,        // Save memory by excluding detailed differences
  skipEmptyDirs: true,    // Skip empty directories
  excludeFilter: ".git,node_modules,*.log" // Exclude unnecessary files
};

// Memory-efficient comparison
const result = await compare("/very/large/dir1", "/very/large/dir2", largeDirectoryOptions);
console.log(`Processed ${result.total} entries, found ${result.differences} differences`);
// result.diffSet will be undefined to save memory

Install with Tessl CLI

npx tessl i tessl/npm-dir-compare

docs

comparison-functions.md

extension-points.md

file-comparators.md

filters-and-patterns.md

index.md

tile.json