Skip to content

Deep equals

deepEquals validates that a value is deeply equal to an expected structural value.

It performs deep equality comparison against JSON-compatible values (primitives, arrays, and plain objects). Complex objects like class instances, Maps, Sets, or Dates are rejected. If the value is not structural or doesn't match the expected value, the rule emits a single validation event. Otherwise, it produces no validation output.

Signature

Through the API:

.deepEquals(expected: unknown)

And internally:

export const deepEquals = (expected: unknown): ValidationRule
(value: unknown, path: FieldPath) => Promise<ReadonlyArray<JaneEvent>>

Events

Event code Description
object.not.plain-object Value is not a JSON-compatible structural value
object.not.deeply-equal Value does not match the expected structure

Design rationale

  • Provides deep structural equality validation for JSON-compatible data.
  • Accepts primitives, arrays, and plain objects.
  • Rejects complex object types that aren't JSON-serializable.
  • Uses deep equality comparison for nested structures.
  • Useful for exact structural matching requirements.
  • Never coerces or normalizes — validation is explicit and opt-in.
  • Emits exactly one event per failure for clarity and composability.
  • Async-compatible and returns a readonly array of JaneEvent objects.

Invoke

deepEquals runs only when explicitly included in a boundary or pipeline. It does not run automatically.

The rule activates when:

  • The value is any JavaScript value.
  • If the value is not a structural value (primitive, array, or plain object), emits object.not.plain-object.
  • If the value is structural but doesn't match the expected value, emits object.not.deeply-equal.
  • If the value matches the expected structure → returns an empty result set.

Examples

Valid exact match

await deepEquals({ name: "John", age: 30 })({ name: "John", age: 30 }, "$");
// → []

Array match

await deepEquals([1, 2, 3])([1, 2, 3], "$");
// → []

Primitive match

await deepEquals("hello")("hello", "$");
// → []

Value doesn't match

await deepEquals({ name: "John" })({ name: "Jane" }, "$");
// → [
//     JaneEvent{
//       kind: "error",
//       code: "object.not.deeply-equal",
//       path: "$",
//       ...
//     }
//   ]

Complex object (invalid)

await deepEquals({ name: "John" })(new Date(), "$");
// → [
//     JaneEvent{
//       kind: "error",
//       code: "object.not.plain-object",
//       path: "$",
//       ...
//     }
//   ]