Skip to content

NickLarsenNZ/cool-diff

Repository files navigation

cool-diff logo

cool-diff

Compact, context-preserving diffs of structured data.

crates.io docs.rs CI License: MIT/Apache-2.0 MSRV: 1.85

What is cool-diff?

cool-diff compares two serde_json::Value trees and produces a minimal, human-readable diff. It is format-agnostic at the core (operates on parsed JSON values) and ships with a YAML-style renderer out of the box.

Designed for comparing Kubernetes resources, API responses, config files, or any structured data where you want to see exactly what changed without wading through noise.

Features

  • Format-agnostic diff on serde_json::Value trees
  • Array matching by index, distinguished key, or content (contains)
  • Configurable per-path array matching and ambiguity strategies
  • Custom renderer support via DiffRenderer trait
  • YAML-style renderer with unified diff output (-/+ indicators)
    • Truncation for large subtrees (# N more lines)
    • Omitted field/item markers (# N fields omitted)
    • ANSI colour output for terminal rendering (behind color feature gate)
  • JSON renderer
  • Pre-configured MatchConfig for common Kubernetes resource types
  • Inline comparison directives in the expected value

Example output

 spec:
   # 2 fields omitted
   containers:
     - name: app
       # 2 fields omitted
       env:
         - name: LOG_LEVEL
-          value: debug
+          value: info
-      image: "myapp:2.0"
+      image: "myapp:1.0"

Installation

Add to your Cargo.toml:

[dependencies]
cool-diff = "0.1"

Quick start

use cool_diff::{diff, DiffConfig, DiffRenderer as _, YamlRenderer};

let actual = serde_json::json!({
    "server": {
        "host": "0.0.0.0",
        "port": 8080,
        "tls": true,
    }
});
let expected = serde_json::json!({
    "server": {
        "port": 3000,
    }
});

let tree = diff(&actual, &expected, &DiffConfig::default());

if !tree.is_empty() {
    let output = YamlRenderer::new().render(&tree);
    print!("{output}");
}

Output:

 server:
   # 2 fields omitted
-  port: 3000
+  port: 8080

Array matching modes

By default, arrays are compared by position (index). You can configure per-path matching via MatchConfig:

Mode Description
Index (default) Match by position. Element 0 compares to element 0, etc.
Key Match by a configured distinguished field (e.g. name). Scans the actual array for an element with the same key value.
Contains Find a matching element anywhere. Uses exact comparison for scalars, subset matching for objects.
use cool_diff::{ArrayMatchConfig, ArrayMatchMode, DiffConfig, MatchConfig};

let config = DiffConfig::new().with_match_config(
    MatchConfig::new()
        .with_config_at(
            "spec.containers",
            ArrayMatchConfig::new(ArrayMatchMode::Key("name".to_owned())),
        )
        .with_config_at(
            "tags",
            ArrayMatchConfig::new(ArrayMatchMode::Contains),
        ),
);

Renderer

The built-in YamlRenderer produces diff output using unified diff conventions:

Every line starts with an indicator in column 0:

  • (space) for context lines
  • - for expected values (what you wanted)
  • + for actual values (what you got)

The renderer is configurable:

use cool_diff::YamlRenderer;

let renderer = YamlRenderer::new()
    .with_max_lines_per_side(Some(10))  // truncate large subtrees
    .with_indent_width(4);              // custom indentation

You can also implement the DiffRenderer trait for custom output formats. See examples/custom_renderer.rs.

Examples

Runnable examples are in the examples/ directory:

Run any example with:

cargo run --example barebones

Tip

Add --features color for coloured output:

cargo run --example barebones --features color

Changelog

See CHANGELOG.md for a list of changes per release.

Contributing

Contributions are welcome! A contributing guide is coming soon.

Important

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you shall be dual licensed under MIT and Apache-2.0, without any additional terms or conditions.

Releasing

See RELEASE.md for the release process and commit conventions.

License

Licensed under either of

at your option.

About

Compact, context-preserving diffs of structured data.

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Contributors

Languages