CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-diff-sequences

Compare items in two sequences to find a longest common subsequence using Myers' O(ND) difference algorithm

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/diff-sequences@29.6.x
Publish Source
CLI
Badge
tessl/npm-diff-sequences badge