Files
zeekayandHanzo Dev 305578f8a9 The wire is stated, and the encoder is v2
zip called encoding/json, which on Go 1.27 is already the v2 engine with v1's
options — so the speed was never the question. What was at stake is the
semantics: v2 keeps a zero number or false under omitempty, writes a nil slice
as [] and a nil map as {}, leaves `<` unescaped, matches field names
case-sensitively, and does not sort a map's keys. Selecting the engine by build
tag meant a module moving to 1.27 changed what every response said, and this
package had gone back to v1 to stop that.

Now it calls v2 and says what the wire is: v1's semantics, plus sorted keys,
because bytes that vary defeat an ETag, a cache, a signature and a git blob.
Each remaining difference is a decision to make here, once, in view of the
clients — never a default to inherit.

What v2 gives back is its API. Write and Read stream straight to and from the
connection with no second copy, and omitzero says what omitempty could not.


Co-authored-by: Hanzo Dev <[email protected]>
2026-09-17 01:19:25 -07:00

31 lines
1.7 KiB
Go

// Package jsonenc is zip's single JSON entry point.
//
// All JSON marshalling in zip — c.JSON(), c.Bind().Body(), typed.go's
// generic In/Out handlers, module.go's extension envelope — goes
// through Marshal / Unmarshal here. There is no other JSON path.
//
// It is encoding/json/v2, called with the wire stated as options rather than
// taken from whatever the toolchain defaults to. That distinction is the whole
// point of this package: v2 answers differently from v1 in several places — it
// keeps a zero number or false under omitempty, writes a nil slice as [] and a
// nil map as {}, leaves `<` unescaped, matches field names case-sensitively,
// and does not sort a map's keys. This package once selected v2 on the
// goexperiment.jsonv2 build tag, which Go 1.27 sets by default, so moving a
// module to 1.27 silently changed what every response said.
//
// So the options say v1's semantics, plus sorted keys, and every one of the
// remaining differences is a decision to make here, once, in view of the
// clients — never a default to inherit. What v2 gives in return is its API:
// Write and Read stream straight to and from the connection with no second
// copy, options are per call, and `omitzero` says what omitempty could not.
//
// Per HIP-0106 "Wire protocol stack": JSON is the boundary format
// (ingress → gateway → subsystem handler). Inter-subsystem calls use
// ZAP-typed Go values. JSON marshalling happens at most once per
// request, at the subsystem handler boundary, through THIS package.
//
// Brand policy: no third-party JSON library is allowed. Stdlib only.
// goccy/go-json, sonic, jsoniter, and friends are NOT permitted in
// the Hanzo Go stack — see HIP-0106 canonical Hanzo Go stack.
package jsonenc