CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-diff

A JavaScript text diff implementation based on the Myers algorithm for comparing text at different granularities.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

array-diffing.mddocs/

Array Diffing

Generic array comparison with customizable equality functions. Ideal for comparing sequences of any data type, from simple arrays to complex object collections.

Capabilities

diffArrays Function

Performs element-level diff between two arrays with strict equality comparison by default.

/**
 * Compare two arrays element by element
 * @param oldArr - Original array
 * @param newArr - New array to compare against
 * @param options - Configuration options
 * @returns Array of change objects representing the diff
 */
function diffArrays(oldArr, newArr, options);

Options:

interface ArrayDiffOptions extends DiffOptions {
  comparator?: (left: any, right: any) => boolean;  // Custom equality function
}

Usage Examples:

import { diffArrays } from "diff";

// Basic array comparison
const result = diffArrays(
  [1, 2, 3, 4],
  [1, 2, 5, 4]
);
console.log(result);
// [
//   { value: [1, 2], count: 2 },
//   { value: [3], removed: true, count: 1 },
//   { value: [5], added: true, count: 1 },
//   { value: [4], count: 1 }
// ]

// String array comparison
const stringResult = diffArrays(
  ["apple", "banana", "cherry"],
  ["apple", "blueberry", "cherry"]
);

// Object array with custom comparator
const objectResult = diffArrays(
  [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }],
  [{ id: 1, name: "Alice" }, { id: 2, name: "Bobby" }],
  {
    comparator: (left, right) => left.id === right.id && left.name === right.name
  }
);

arrayDiff Instance

Pre-configured Diff instance for array comparisons with array-specific handling.

/**
 * Pre-configured array diff instance
 * Preserves array structure and handles empty elements
 */
const arrayDiff: Diff;

Advanced Usage

Custom Equality Functions

import { diffArrays } from "diff";

// Case-insensitive string comparison
const caseInsensitive = diffArrays(
  ["Hello", "World"],
  ["hello", "WORLD"],
  {
    comparator: (a, b) => a.toLowerCase() === b.toLowerCase()
  }
);

// Object comparison by specific properties
const userComparison = diffArrays(
  [
    { id: 1, name: "Alice", age: 25 },
    { id: 2, name: "Bob", age: 30 }
  ],
  [
    { id: 1, name: "Alice", age: 26 },  // Age changed
    { id: 2, name: "Bob", age: 30 }
  ],
  {
    comparator: (a, b) => a.id === b.id && a.name === b.name
    // Ignores age differences
  }
);

// Deep object comparison
function deepEqual(obj1, obj2) {
  return JSON.stringify(obj1) === JSON.stringify(obj2);
}

const deepComparison = diffArrays(
  [{ nested: { value: 1 } }],
  [{ nested: { value: 2 } }],
  { comparator: deepEqual }
);

Data Structure Comparisons

import { diffArrays } from "diff";

// Comparing lists of complex objects
function compareDataSets(oldData, newData) {
  return diffArrays(oldData, newData, {
    comparator: (a, b) => {
      // Custom business logic comparison
      return a.uniqueId === b.uniqueId && 
             a.version === b.version &&
             a.status === b.status;
    }
  });
}

// Comparing ordered sequences
function compareSequences(seq1, seq2) {
  const changes = diffArrays(seq1, seq2);
  
  return {
    insertions: changes.filter(c => c.added).length,
    deletions: changes.filter(c => c.removed).length,
    unchanged: changes.filter(c => !c.added && !c.removed).length,
    totalElements: changes.reduce((sum, c) => sum + c.count, 0)
  };
}

Set-like Comparisons

import { diffArrays } from "diff";

// Convert sets to arrays for comparison
function compareSets(set1, set2) {
  const arr1 = Array.from(set1).sort();
  const arr2 = Array.from(set2).sort();
  
  return diffArrays(arr1, arr2);
}

// Usage
const oldSet = new Set([1, 2, 3, 4]);
const newSet = new Set([1, 2, 5, 6]);
const setDiff = compareSets(oldSet, newSet);

Token Sequence Analysis

import { diffArrays } from "diff";

// Comparing tokenized text as arrays
function compareTokenSequences(text1, text2) {
  const tokens1 = text1.split(/\s+/);
  const tokens2 = text2.split(/\s+/);
  
  return diffArrays(tokens1, tokens2, {
    comparator: (a, b) => a.toLowerCase() === b.toLowerCase()
  });
}

const tokenDiff = compareTokenSequences(
  "The quick brown fox",
  "The slow brown fox"
);

Large Array Handling

import { diffArrays } from "diff";

// Async processing for large arrays
function diffLargeArrays(arr1, arr2, callback) {
  diffArrays(arr1, arr2, {
    callback: callback,
    maxEditLength: 10000,  // Limit computation
    timeout: 20000,        // 20 second timeout
    comparator: (a, b) => a === b  // Can be customized
  });
}

// Usage
diffLargeArrays(largeArray1, largeArray2, (result) => {
  if (result) {
    console.log(`Array diff completed: ${result.length} change blocks`);
  } else {
    console.log("Arrays too different to compute diff efficiently");
  }
});

Direct Instance Usage

import { arrayDiff } from "diff";

// Using the pre-configured instance
const directResult = arrayDiff.diff([1, 2, 3], [1, 3, 4]);

// Access to tokenization (returns the array itself)
const tokens = arrayDiff.tokenize([1, 2, 3]);
console.log("Array tokens:", tokens); // [1, 2, 3]

// The arrayDiff instance preserves empty elements
const withEmpties = arrayDiff.diff(
  [1, , 3],  // Sparse array
  [1, 2, 3]
);

Performance Considerations

import { diffArrays } from "diff";

// Optimize comparisons for large objects
function efficientObjectComparison(arr1, arr2) {
  return diffArrays(arr1, arr2, {
    comparator: (a, b) => {
      // Quick reference check first
      if (a === b) return true;
      
      // Then check critical properties only
      return a.id === b.id && a.hash === b.hash;
    }
  });
}

// Pre-process arrays for better performance
function preprocessAndCompare(arr1, arr2) {
  // Create lightweight comparison objects
  const processed1 = arr1.map(item => ({ 
    id: item.id, 
    key: item.importantField 
  }));
  const processed2 = arr2.map(item => ({ 
    id: item.id, 
    key: item.importantField 
  }));
  
  return diffArrays(processed1, processed2);
}

Install with Tessl CLI

npx tessl i tessl/npm-diff

docs

array-diffing.md

character-diffing.md

css-diffing.md

custom-diffing.md

format-conversion.md

index.md

json-diffing.md

line-diffing.md

patch-application.md

patch-creation.md

patch-utilities.md

sentence-diffing.md

word-diffing.md

tile.json