Module: McpDiff::Core::Canonical
- Defined in:
- lib/mcp_diff/core/canonical.rb
Overview
Deterministic serialization: sorted keys, array order preserved (it is meaningful), sha256 contract hash. Port of core/src/canonical.ts (D11).
Class Method Summary collapse
-
.canonical_stringify(value) ⇒ Object
Canonical lockfile text: sorted keys, 2-space indent, trailing newline.
-
.contract_hash_of(snapshot_without_hash) ⇒ Object
sha256 of the snapshot's canonical (compact) form, hash field excluded.
-
.deep_equal(a, b) ⇒ Object
Structural equality via canonical serialization (array order preserved).
-
.sort_keys_deep(value) ⇒ Object
Recursively sort object keys; stringify keys so string/symbol inputs canonicalize identically.
Class Method Details
.canonical_stringify(value) ⇒ Object
Canonical lockfile text: sorted keys, 2-space indent, trailing newline.
27 28 29 |
# File 'lib/mcp_diff/core/canonical.rb', line 27 def canonical_stringify(value) "#{JSON.pretty_generate(sort_keys_deep(value))}\n" end |
.contract_hash_of(snapshot_without_hash) ⇒ Object
sha256 of the snapshot's canonical (compact) form, hash field excluded.
37 38 39 40 |
# File 'lib/mcp_diff/core/canonical.rb', line 37 def contract_hash_of(snapshot_without_hash) compact = JSON.generate(sort_keys_deep(snapshot_without_hash)) "sha256-#{Digest::SHA256.hexdigest(compact)}" end |
.deep_equal(a, b) ⇒ Object
Structural equality via canonical serialization (array order preserved).
32 33 34 |
# File 'lib/mcp_diff/core/canonical.rb', line 32 def deep_equal(a, b) JSON.generate(sort_keys_deep(a)) == JSON.generate(sort_keys_deep(b)) end |
.sort_keys_deep(value) ⇒ Object
Recursively sort object keys; stringify keys so string/symbol inputs canonicalize identically. Array order is preserved.
15 16 17 18 19 20 21 22 23 24 |
# File 'lib/mcp_diff/core/canonical.rb', line 15 def sort_keys_deep(value) case value when Array value.map { |v| sort_keys_deep(v) } when Hash value.map { |k, v| [k.to_s, sort_keys_deep(v)] }.sort_by(&:first).to_h else value end end |