Patch
in package
$patch application — add / remove / replace over the $ref base (SPEC §5).
Byte-for-byte port of validator-ts/src/compose/patch.ts.
$patch is an OBJECT of operations. Two order-preserving input shapes are supported:
-
Deep-path set — "field.validate.required": ".other". The dotted key is split into path segments and the value is SET at that node (creating intermediate objects). SPEC §5 canonical form. The value replaces any scalar leaf; for object values it deep-merges (both objects → deep merge, else the latter wins).
-
Structured ops — explicit add / remove / replace keys: add: { "path.to.new": value, … } — deep-merge value at path replace: { "path.to.key": value, … } — same merge rule (scalar override) remove: [ "path.to.key", … ] | { … } — deep delete
Resolution order: base ($ref) first, then $patch overlays. add/replace deep-merge; remove deep-deletes; deep-path set splits then applies. An unresolved patch (op shape error, path conflict, strict-remove miss) is a LOAD ERROR — never valid:true.
Table of Contents
Methods
- apply() : array<string, mixed>
- Apply a $patch object to the (already $ref-expanded) base spec.
- applyAddReplace() : array<string, mixed>
- Structured add/replace: a map of deep-path → value, deep-merged at each path.
- applyRemove() : array<string, mixed>
- Structured remove: an array of deep-paths, or a nested {k:{sub:…}} map.
- mergeValue() : mixed
- Deep-merge leaf rule: both plain objects → recursive deep merge; otherwise the latter value wins (scalar/array override). Mirrors JS mergeValue; an UNDEFINED existing means "no prior leaf" (JS existing === undefined), so the incoming value is taken as-is.
- removeDeepPath() : array<string, mixed>
- Delete a value at a deep path. Strict: a missing target is a load error.
- removeNested() : array<string, mixed>
- Nested-map remove: for each key, recurse when both the target and the removal spec are objects, else unset the key. A missing key is tolerated here (silently skipped), unlike the array form.
- setDeepPath() : array<string, mixed>
- Set a value at a deep path, creating intermediate objects. When both the existing leaf and the new value are plain objects, DEEP-MERGE; otherwise the new value REPLACES. Returns a new tree (PHP arrays are value types, so the input is never mutated).
- splitPath() : array<int, string>
- Split a dotted deep-path into segments. Empty path is a shape error.
- typeName() : string
- JS-style type name for $patch shape error messages.
Methods
apply()
Apply a $patch object to the (already $ref-expanded) base spec.
public
static apply(array<string, mixed> $base, mixed $patch) : array<string, mixed>
Parameters
- $base : array<string, mixed>
- $patch : mixed
Return values
array<string, mixed>applyAddReplace()
Structured add/replace: a map of deep-path → value, deep-merged at each path.
private
static applyAddReplace(array<string, mixed> $base, mixed $val, string $op) : array<string, mixed>
Parameters
- $base : array<string, mixed>
- $val : mixed
- $op : string
Return values
array<string, mixed>applyRemove()
Structured remove: an array of deep-paths, or a nested {k:{sub:…}} map.
private
static applyRemove(array<string, mixed> $base, mixed $val) : array<string, mixed>
Parameters
- $base : array<string, mixed>
- $val : mixed
Return values
array<string, mixed>mergeValue()
Deep-merge leaf rule: both plain objects → recursive deep merge; otherwise the latter value wins (scalar/array override). Mirrors JS mergeValue; an UNDEFINED existing means "no prior leaf" (JS existing === undefined), so the incoming value is taken as-is.
private
static mergeValue(mixed $existing, mixed $incoming) : mixed
Parameters
- $existing : mixed
- $incoming : mixed
removeDeepPath()
Delete a value at a deep path. Strict: a missing target is a load error.
private
static removeDeepPath(array<string, mixed> $node, array<int, string> $segments) : array<string, mixed>
Parameters
- $node : array<string, mixed>
-
the tree that holds the value
- $segments : array<int, string>
-
the path from the root of the tree to the deleted member
Tags
Return values
array<string, mixed> —the tree without the member
removeNested()
Nested-map remove: for each key, recurse when both the target and the removal spec are objects, else unset the key. A missing key is tolerated here (silently skipped), unlike the array form.
private
static removeNested(array<string, mixed> $base, array<string, mixed> $spec) : array<string, mixed>
Parameters
- $base : array<string, mixed>
- $spec : array<string, mixed>
Return values
array<string, mixed>setDeepPath()
Set a value at a deep path, creating intermediate objects. When both the existing leaf and the new value are plain objects, DEEP-MERGE; otherwise the new value REPLACES. Returns a new tree (PHP arrays are value types, so the input is never mutated).
private
static setDeepPath(array<string, mixed> $node, array<int, string> $segments, mixed $value) : array<string, mixed>
Parameters
- $node : array<string, mixed>
-
the tree that receives the value
- $segments : array<int, string>
-
the path from the root of the tree to the leaf, one key per segment
- $value : mixed
-
the value written at the leaf
Return values
array<string, mixed> —the tree with the value set
splitPath()
Split a dotted deep-path into segments. Empty path is a shape error.
private
static splitPath(string $path) : array<int, string>
Parameters
- $path : string
Return values
array<int, string>typeName()
JS-style type name for $patch shape error messages.
private
static typeName(mixed $v) : string
Parameters
- $v : mixed