JSON Diff Kit

repository·main·Indexed 42 days ago

https://github.com/rexskz/json-diff-kit

A TypeScript library and CLI tool for generating and visualizing differences between JSON objects. It features a core Differ engine with configurable array diffing methods (including LCS), a Viewer UI component for rendering diffs, and a terminal-based interactive viewer via the jsondiff CLI.

Tokens
5.6K
Snippets
16
Records
28
Agent score
52%

What's inside JSON Diff Kit

  1. Select an Array Diff Method

    main

    The arrayDiffMethod option determines how the differ handles arrays. Choosing the right method balances performance and accuracy based on your data structure.

    Methods

    • normal: Compares items at the same index one by one. Fast ($O(LEN)$) but treats shifts as modifications.
    • lcs: Uses the Longest Common Subsequence algorithm. Assumes items in the subsequence are unchanged. Slower ($O(LEN^2)$) but better at detecting insertions/deletions.
    • unorder-normal: Sorts both arrays first, then performs a normal diff.
    • unorder-lcs: Sorts both arrays first, then performs an lcs diff.
    • compare-key: Matches objects in arrays by a specific property (defined by the compareKey option). Ideal for arrays of objects where order doesn't matter but identity does.
  2. Visualize diff data with the Viewer component

    main

    The Viewer component can be used to render the diff data produced by the Differ class. You must import the associated CSS file for the viewer to render correctly.

    Viewer Props:

    • diff (required): An array of DiffResult objects: [DiffResult[], DiffResult[]].
    • indent (number, default: 2): Indentation level.
    • lineNumbers (boolean, default: false): Whether to show line numbers.
    • highlightInlineDiff (boolean, default: false): Enables inline diff highlighting.
    • inlineDiffOptions (object): Configuration for inline diffing:
      • mode (string, default: "char"): Diff granularity. Use "word" for word-level diffing.
      • wordSeparator (string, default: ""): The character used to separate words (e.g., " " for sentences).
    import { Viewer } from 'json-diff-kit';
    import type { DiffResult } from 'json-diff-kit';
    import 'json-diff-kit/dist/viewer.css';
    
    interface PageProps {
      diff: [DiffResult[], DiffResult[]];
    }
    
    const Page: React.FC<PageProps> = props => {
      return (
        <Viewer
          diff={props.diff}
          indent={4}
          lineNumbers={true}
          highlightInlineDiff={true}
          inlineDiffOptions={{
            mode: 'word',
            wordSeparator: ' ',
          }}
        />
      );
    };
  3. Generate JSON diff data with the Differ class

    main

    To compute the difference between two JavaScript objects, instantiate the Differ class and call its .diff(before, after) method.

    Configuration Options for Differ:

    • detectCircular (boolean, default: true): Detects circular references.
    • maxDepth (number, default: Infinity): Maximum depth to traverse.
    • showModifications (boolean, default: true): Whether to show modifications.
    • arrayDiffMethod (string, default: "normal"): The algorithm used for array diffing. Use "lcs" (Longest Common Subsequence) for more useful results in many cases.
    import { Differ } from 'json-diff-kit';
    // or if you are using vue, you can import the differ only
    // import Differ from 'json-diff-kit/dist/differ';
    
    const before = { a: 1, b: 2 };
    const after = { b: 2, c: 3 };
    
    const differ = new Differ({
      detectCircular: true,
      maxDepth: Infinity,
      showModifications: true,
      arrayDiffMethod: 'lcs',
    });
    
    const diff = differ.diff(before, after);
    console.log(diff);
  4. Configure virtual scrolling in the Viewer

    main

    To optimize rendering for very large JSON diffs, enable the virtual prop. This uses a virtual list to only render visible rows.

    Options:

    • virtual={true}: Uses default settings.
    • virtual={{ scrollContainer?: string; itemHeight?: number; expandLineHeight?: number; }}
      • scrollContainer: CSS selector for the scrollable element (default: 'body').
      • itemHeight: Height of a standard line in pixels (default: 18).
      • expandLineHeight: Height of an expansion line in pixels (default: 26).
  5. Configure DifferOptions

    main

    Use the DifferOptions interface to control the diffing algorithm's behavior.

    Available Options

    OptionTypeDefaultDescription
    detectCircularbooleantrueWhether to detect circular references in source objects before diffing starts. Setting to false improves performance if you are certain the data is safe.
    maxDepthnumberInfinityThe maximum depth to traverse during diffing.
    showModificationsbooleantrueIf true, outputs a * modified sign for changes. If false, uses standard Git-style + add and - remove signs.
    arrayDiffMethodstring'normal'The algorithm used to diff arrays (see Array Diff Methods).
    ignoreCasebooleanfalseWhether to ignore case when comparing strings.
    ignoreCaseForKeybooleanfalseWhether to ignore case when comparing object keys. Note: using this on objects with mixed-case keys may cause issues.
    recursiveEqualbooleanfalseIf true, objects are considered equal if they have the same properties and values, regardless of key order. This is slow for large objects.
    preserveKeyOrder'before' | 'after'undefinedIf set, ensures the key order of results matches the input ('before' or 'after'). Otherwise, keys are sorted.
    compareKeystringundefinedThe key used for matching objects in arrays when arrayDiffMethod is set to 'compare-key'.
    undefinedBehaviorUndefinedBehavior'stringify'How to handle non-JSON values like undefined, NaN, or Infinity. (See UndefinedBehavior).
  6. Configure hideUnchangedLines in the Viewer

    main

    The hideUnchangedLines option allows you to collapse large blocks of unchanged JSON to improve readability. You can pass a boolean or a configuration object:

    Configuration Object Options:

    • threshold?: number - If continuous unchanged lines exceed this number, they are hidden (default: 8).
    • margin?: number - Number of lines to keep visible around the expand line for context (default: 3).
    • expandMoreLinesLimit?: number - How many lines are shown when clicking "Show xx lines before/after" (default: 20).
    • expandLineRenderer?: (options?: ExpandLineRendererOptions) => JSX.Element - A custom renderer for the expansion line.

    ExpandLineRendererOptions:

    • hasLinesBefore: boolean - True if there are lines available to expand before.
    • hasLinesAfter: boolean - True if there are lines available to expand after.
    • onExpandBefore: (lines: number) => void - Callback to expand lines before.
    • onExpandAfter: (lines: number) => void - Callback to expand lines after.
    • onExpandAll: () => void - Callback to expand all lines in the segment.
  7. Configure syntax highlighting in the Viewer

    main

    To enable syntax highlighting, pass a syntaxHighlight object.

    Important: The component only adds a class name to the table based on the theme. You are responsible for importing the corresponding CSS file for the theme you choose.

    <Viewer 
      diff={diff} 
      syntaxHighlight={{ theme: 'monokai' }} 
    />
  8. Configure inline diff options

    main

    When using getInlineDiff, you can provide an InlineDiffOptions object to control the granularity of the diff.

    • mode: Determines if the diff is calculated at the character level ('char') or the word level ('word').
    • wordSeparator: Specifies the string used to split text when mode is set to 'word'. Defaults to ' ' (a single space).
    const options: InlineDiffOptions = {
      mode: 'word',
      wordSeparator: ' '
    };
  9. Use the json-diff-kit CLI tool

    main

    The CLI tool allows you to compare two JSON files and output the diff data to the terminal or a file.

    Prerequisite: You must install terminal-kit before using the CLI.

    pnpm add terminal-kit

    Commands:

    • jsondiff run <path/to/before.json> <path/to/after.json>: Compare files and output to terminal (navigable via keyboard like less).
    • jsondiff run <path/to/before.json> <path/to/after.json> -o <path/to/result.diff>: Output diff data to a file.
    • jsondiff run <path/to/before.json> <path/to/after.json> -c <path/to/config.json> -o <path/to/result.diff>: Use a custom configuration file and output to a file.
    • jsondiff --help or jsondiff run --help: Print help messages.
    # Compare two JSON files, output the diff data to the terminal.
    jsondiff run path/to/before.json path/to/after.json
    
    # Output the diff data to a file.
    jsondiff run path/to/before.json path/to/after.json -o path/to/result.diff
    
    # Use a custom configuration file and output the diff data to a file.
    jsondiff run path/to/before.json path/to/after.json -c path/to/config.json -o path/to/result.diff
  10. Use the Viewer React component to visualize JSON diffs

    main

    The Viewer component is a React component used to render a visual representation of the differences between two JSON structures. It supports features like line numbers, inline diff highlighting, syntax highlighting, virtual scrolling for large diffs, and the ability to hide/expand continuous unchanged lines.

    To use it, pass a diff prop which is a tuple containing two arrays of DiffResult objects: [before, after].

    import Viewer from 'json-diff-kit/viewer';
    
    // Assuming 'diffResult' is the output from the differ
    <Viewer diff={diffResult} />
  11. Write Git-style diffs to a file

    main

    The writeToFile function allows you to save JSON diff results to a file using a Git-style format (using +, -, and prefixes). It does not support side-by-side diff views; instead, it produces a single-column output where changes are interleaved.

    Each line in the output follows this pattern:

    • (space): Equal lines
    • - (minus): Removed lines
    • + (plus): Added lines

    Lines are indented based on their nesting level and include trailing commas if present in the original JSON.

    import writeToFile from './src/cli/write-to-file';
    
    // content is expected to be a tuple of [DiffResult[], DiffResult[]]
    const diffContent: [DiffResult[], DiffResult[]] = [linesLeft, linesRight];
    const outputPath = 'diff_output.txt';
    
    writeToFile(outputPath, diffContent);