Skip to content

refactor: remove encoding/json from the library - #11

Closed
deadprogram wants to merge 1 commit into
ardanlabs:mainfrom
hybridgroup:remove-encoding-json
Closed

deadprogram wants to merge 1 commit into
ardanlabs:mainfrom
hybridgroup:remove-encoding-json

Conversation

@deadprogram

Copy link
Copy Markdown

When this package is compiled to WebAssembly with TinyGo, encoding/json adds about 1.6MB to the binary.

This PR replaces encoding/json with code specific to the JSON needs of this package without the size increase or external dependencies.

Measuring a "Compile plus Render plus tojson" program with tinygo build -target=wasi -opt=z it was 2715KB before this change and 1435KB after, a drop of 47 percent.

The new file json.go has the following functions:

  • appendJSONString escapes a string the way encoding/json does, with an option for the HTML metacharacters.
  • appendJSONFloat reproduces the encoding/json float format, which the indented form of tojson needs.
  • parseJSON is a recursive descent parser that builds a Value tree directly. The depth limit of 1000 matches CPython and protects the small TinyGo stack.

encodeValueJSON now writes the indented form itself, so tojson no longer calls json.MarshalIndent. The layout is unchanged, which means sorted keys and escaped HTML metacharacters in that mode. Helpers encodeJSONString and valueToGo are no longer needed.

The from_json filter uses parseJSON, with no intermediate any tree. Two behaviors are changed to match Python. An integer literal that fits in an int64 stays an integer, so a value such as 9007199254740993 round-trips exactly. Also Object keys keep their source order instead of being sorted.

FromGoValue matches json.Number by method set instead of by name, so a caller can still pass a value from a UseNumber decode.

New file json_internal_test.go compares the encoder and the parser against encoding/json. Test files can keep the original import because the test binary is not shipped.

All 272 template and request pairs in testdata render byte for byte the same as before this change.

When this package is compiled to WebAssembly with TinyGo, encoding/json adds
about 1.6MB to the binary.

Measured with `tinygo build -target=wasi -opt=z` on a "Compile plus Render
plus tojson" program it was 2715KB before this change and 1435KB after, a drop
of 47 percent.

The new file `json.go` has the following functions:

- appendJSONString escapes a string the way encoding/json does, with an option
  for the HTML metacharacters.
- appendJSONFloat reproduces the encoding/json float format, which the indented
  form of tojson needs.
- parseJSON is a recursive descent parser that builds a Value tree directly. The
  depth limit of 1000 matches CPython and protects the small TinyGo stack.

encodeValueJSON now writes the indented form itself, so tojson no longer calls
json.MarshalIndent. The layout is unchanged, which means sorted keys and escaped
HTML metacharacters in that mode. Helpers encodeJSONString and valueToGo are no
longer needed.

The from_json filter uses parseJSON, with no intermediate any tree. Two
behaviors are changed to match Python. An integer literal that fits in an int64 stays
an integer, so a value such as 9007199254740993 round-trips exactly. Also Object keys
keep their source order instead of being sorted.

FromGoValue matches json.Number by method set instead of by name, so a caller
can still pass a value from a UseNumber decode.

New file json_internal_test.go compares the encoder and the parser against
encoding/json. Test files can keep the original import because the test binary is not
shipped.

All 272 template and request pairs in testdata render byte for byte the same as
before this change.

Signed-off-by: deadprogram <ron@hybridgroup.com>
@deadprogram

Copy link
Copy Markdown
Author

I might need to export some of the new functions... stand by...

@deadprogram

Copy link
Copy Markdown
Author

Hmm, now that I think about the size of the models being downloaded, perhaps the size difference is not worth it... 🤔

@deadprogram deadprogram closed this Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant