or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

comparison-functions.mdextension-points.mdfile-comparators.mdfilters-and-patterns.mdindex.md
tile.json

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