Files
skills/docs/foundation/data/diff/src/utils/utils.md
2026-05-29 08:20:56 +01:00

5.6 KiB

utils

(no submodules)

Purpose

utils.ts provides the low-level primitives that the entire @suaveplan/diff pipeline is built upon: deep clone, deep equality, FNV-1a hashing, and a family of path-navigation helpers for immutable and mutable document manipulation. Every operation is JSON-safe — it operates exclusively on the JsonValue universe (null | boolean | number | string | JsonValue[] | { [k: string]: JsonValue }).

The path-navigation helpers implement the RFC 6902 semantics for add, remove, replace, move, and copy at the document level, freeing the higher-level patch engine from the mechanics of array splice and object key management.

Features

  • deepClone — recursive JSON-safe clone without JSON.parse/stringify overhead
  • deepEqual — structural equality for arbitrarily nested JSON values
  • hashValue — FNV-1a 32-bit hash of JSON serialisation (for LCS bucketing)
  • isObject / isPrimitive — type-guard predicates
  • getValueAtPath — safe read at a path; returns undefined on missing keys
  • setValueAtPath / setValueAtPathMut — immutable and in-place write
  • insertValueAtPath / insertValueAtPathMut — immutable and in-place insert (array splice)
  • deleteValueAtPath / deleteValueAtPathMut — immutable and in-place delete

Usage: Basic Example

import { deepClone, deepEqual, getValueAtPath } from "@suaveplan/diff/utils";
import type { JsonValue } from "@suaveplan/diff/utils";

const doc: JsonValue = { users: [{ name: "Alice" }, { name: "Bob" }] };

const clone = deepClone(doc);
clone.users[0].name = "Carol";
console.log(doc.users[0].name);  // "Alice" — original unchanged

deepEqual(doc, clone);  // false — they now differ

const name = getValueAtPath(doc, ["users", 1, "name"]);
// "Bob"

Usage: Advanced Example

import {
  setValueAtPath, insertValueAtPath, deleteValueAtPath,
  setValueAtPathMut, hashValue,
} from "@suaveplan/diff/utils";
import type { JsonValue } from "@suaveplan/diff/utils";

const doc: JsonValue = { items: ["a", "b", "c"] };

// Immutable set — original unchanged
const updated = setValueAtPath(doc, ["items", 1], "B");
// doc still: { items: ["a", "b", "c"] }
// updated:   { items: ["a", "B", "c"] }

// Array insert — existing elements shift right
const inserted = insertValueAtPath(doc, ["items", 1], "X");
// { items: ["a", "X", "b", "c"] }

// Append via "-" token
const appended = insertValueAtPath(doc, ["items", "-"], "Z");
// { items: ["a", "b", "c", "Z"] }

// Delete
const deleted = deleteValueAtPath(doc, ["items", 0]);
// { items: ["b", "c"] }

// In-place mutation (used internally by the patch engine)
const mutable = deepClone(doc) as { items: string[] };
setValueAtPathMut(mutable as JsonValue, ["items", 2], "C");

// Hash for LCS bucketing
hashValue({ x: 1 });  // e.g. "3a2b1c4d"

API Reference

JsonValue

type JsonValue = null | boolean | number | string | JsonValue[] | { [k: string]: JsonValue };

isObject(v: unknown): v is Record<string, unknown>

Returns true for non-null, non-array plain objects.

isPrimitive(v: unknown): v is null | boolean | number | string

Returns true for all primitive JSON value types.

deepClone<T>(value: T): T

Recursively clones arrays and objects; returns primitives as-is. Does not use JSON.parse/stringify.

deepEqual(a: unknown, b: unknown): boolean

Structural equality: handles null, same-type primitives, same-length arrays with equal elements, and objects with equal key sets and equal values. Returns false for type mismatches.

hashValue(value: unknown): string

FNV-1a 32-bit hash of JSON.stringify(value). Returns an 8-character lowercase hex string.

getValueAtPath(doc: JsonValue, path: Path): JsonValue | undefined

Traverses doc following path. Returns undefined if any step fails (missing key, index out of range, traversing through a primitive).

setValueAtPath(doc: JsonValue, path: Path, value: JsonValue): JsonValue

Returns a new deep clone of doc with value written at path. The original doc is not modified.

setValueAtPathMut(doc: JsonValue, path: Path, value: JsonValue): void

Sets value at path in doc in-place.

insertValueAtPath(doc: JsonValue, path: Path, value: JsonValue): JsonValue

Returns a new deep clone with value inserted. For arrays, elements at >= index shift right. The "-" segment appends to the array.

insertValueAtPathMut(doc: JsonValue, path: Path, value: JsonValue): void

Inserts value in-place using array splice or object key assignment.

deleteValueAtPath(doc: JsonValue, path: Path): JsonValue

Returns a new deep clone with the element at path removed. Array elements shift left.

deleteValueAtPathMut(doc: JsonValue, path: Path): void

Removes the element at path in-place.

Implementation Notes

  • deepClone avoids JSON.parse/stringify to preserve type fidelity for values that would be mangled by JSON roundtrip (e.g., undefined in arrays becomes null). This also avoids the overhead of two serialisation passes.
  • resolveParent is a shared internal helper that walks to the parent of the target key, returning a { parent, key } pair. This eliminates duplication between the six set/insert/delete variants.
  • The "-" append token is handled in both setValueAtPathMut and insertValueAtPathMut to match RFC 6902 §4.1 semantics for the add operation.
  • hashValue deliberately uses FNV-1a rather than a cryptographic hash for performance in the LCS hot path. Collision probability over realistic array sizes is negligible.