or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

index.mddocs/

diff-sequences

diff-sequences is a high-performance TypeScript library that implements the linear space variation of Eugene W. Myers' O(ND) difference algorithm. It finds the longest common subsequence between two sequences using a callback-based API that maximizes flexibility and minimizes memory usage, making it ideal for building diff tools, version control systems, and test assertion libraries.

Package Information

  • Package Name: diff-sequences
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install diff-sequences

Core Imports

import diffSequence from "diff-sequences";

For CommonJS:

const diffSequence = require("diff-sequences").default;

Basic Usage

import diffSequence from "diff-sequences";

const a = ['a', 'b', 'c', 'a', 'b', 'b', 'a'];
const b = ['c', 'b', 'a', 'b', 'a', 'c'];

// Define comparison function
function isCommon(aIndex: number, bIndex: number): boolean {
  return a[aIndex] === b[bIndex];
}

// Define subsequence handler
function foundSubsequence(nCommon: number, aCommon: number, bCommon: number): void {
  console.log(`Found ${nCommon} common items starting at a[${aCommon}] and b[${bCommon}]`);
}

// Execute diff algorithm
diffSequence(a.length, b.length, isCommon, foundSubsequence);

Architecture

diff-sequences is built around Myers' O(ND) difference algorithm with several key optimizations:

  • Linear Space: Uses the linear space variation to minimize memory consumption
  • Bidirectional Search: Employs forward and reverse path extensions for efficiency
  • Callback-Based: Maximizes flexibility by using callback functions for comparison and results
  • Optimized Performance: Fast even when sequences have many differences
  • Type Safety: Full TypeScript support with complete type definitions

Capabilities

Longest Common Subsequence Detection

Finds the longest common subsequence between two sequences using Myers' algorithm.

/**
 * Compare items in two sequences to find a longest common subsequence.
 * This is the default export of the diff-sequences package.
 * @param aLength - Length of the first sequence
 * @param bLength - Length of the second sequence  
 * @param isCommon - Function to compare items at given indexes
 * @param foundSubsequence - Callback for each common subsequence found
 */
export default function diffSequence(
  aLength: number,
  bLength: number,
  isCommon: IsCommon,
  foundSubsequence: FoundSubsequence
): void;

Usage Examples:

// Count common items
function countCommonItems(a: any[], b: any[]): number {
  let count = 0;
  
  diffSequence(
    a.length,
    b.length,
    (aIndex, bIndex) => a[aIndex] === b[bIndex],
    (nCommon) => { count += nCommon; }
  );
  
  return count;
}

// Find common items
function findCommonItems<T>(a: T[], b: T[]): T[] {
  const common: T[] = [];
  
  diffSequence(
    a.length,
    b.length,
    (aIndex, bIndex) => Object.is(a[aIndex], b[bIndex]),
    (nCommon, aCommon) => {
      for (let i = 0; i < nCommon; i++) {
        common.push(a[aCommon + i]);
      }
    }
  );
  
  return common;
}

// Generate diff output
function generateDiff(a: string[], b: string[]): string[] {
  let aIndex = 0;
  let bIndex = 0;
  const result: string[] = [];
  
  diffSequence(
    a.length,
    b.length,
    (aI, bI) => a[aI] === b[bI],
    (nCommon, aCommon, bCommon) => {
      // Add deletions
      for (; aIndex < aCommon; aIndex++) {
        result.push(`- ${a[aIndex]}`);
      }
      // Add insertions
      for (; bIndex < bCommon; bIndex++) {
        result.push(`+ ${b[bIndex]}`);
      }
      // Add common lines
      for (let i = 0; i < nCommon; i++, aIndex++, bIndex++) {
        result.push(`  ${a[aIndex]}`);
      }
    }
  );
  
  // Handle remaining items
  for (; aIndex < a.length; aIndex++) {
    result.push(`- ${a[aIndex]}`);
  }
  for (; bIndex < b.length; bIndex++) {
    result.push(`+ ${b[bIndex]}`);
  }
  
  return result;
}

Types

/**
 * Input callback function that compares items at indexes in the sequences
 * @param aIndex - Index in first sequence (0 <= aIndex < aLength)
 * @param bIndex - Index in second sequence (0 <= bIndex < bLength)  
 * @returns true if items are considered equal, false otherwise
 */
type IsCommon = (aIndex: number, bIndex: number) => boolean;

/**
 * Output callback function that receives information about each common subsequence
 * @param nCommon - Number of adjacent common items (always > 0)
 * @param aCommon - Starting index in first sequence (0 <= aCommon < aLength)
 * @param bCommon - Starting index in second sequence (0 <= bCommon < bLength)
 */
type FoundSubsequence = (
  nCommon: number,
  aCommon: number, 
  bCommon: number
) => void;

/**
 * Container for callback functions used internally
 */
interface Callbacks {
  foundSubsequence: FoundSubsequence;
  isCommon: IsCommon;
}

Error Handling

The function performs validation on all parameters and throws errors for invalid inputs:

  • TypeError: Thrown when callback parameters are not functions
  • TypeError: Thrown when length parameters are not numbers
  • RangeError: Thrown when length parameters are not safe integers
  • RangeError: Thrown when length parameters are negative
// Example error handling
try {
  diffSequence(
    10,
    20,
    (a, b) => a === b,  // Valid function
    (nCommon, aCommon, bCommon) => {
      console.log(`Found ${nCommon} common items`);
    }
  );
} catch (error) {
  if (error instanceof TypeError) {
    console.error('Invalid parameter type:', error.message);
  } else if (error instanceof RangeError) {
    console.error('Parameter out of range:', error.message);
  }
}

Performance Characteristics

  • Time Complexity: O(ND) where N is the sum of sequence lengths and D is the number of differences
  • Space Complexity: O(min(N, D)) due to linear space optimization
  • Best Case: Linear time when sequences have few differences
  • Optimizations: Efficient even with many differences, bidirectional search, memory-conscious implementation

Engine Requirements

  • Node.js: ^14.15.0 || ^16.10.0 || >=18.0.0
  • TypeScript: Full type definitions included
  • Compatibility: Works with both ESM and CommonJS module systems