Native JSONExperimentalZsh • No dependencies

zjson

Parse, validate, query, and quote JSON in pure Zsh. zjson works with native scalars, arrays, and associative arrays without invoking jq, Python, or another executable.

Initial development release: zjson 0.1.0 extracts the JSON core from zcoder.zsh behind a new API that may evolve.

JSON Without Leaving the Shell

Pure Zsh

Parse and encode JSON with Zsh builtins and parameter expansion. No jq, Python, external commands, third-party modules, or build step.

Native result values

Decode objects into associative arrays, arrays into indexed arrays, and scalar types into regular Zsh variables.

JSON Pointer lookup

Resolve RFC 6901 pointers into nested objects and arrays, including escaped key characters, empty keys, and typed null values.

Exact scalar handling

Keep number spelling and distinguish strings from booleans and null while decoding escapes into UTF-8.

Structured diagnostics

Inspect stable error codes plus 1-based byte offsets, line numbers, and locale-consistent columns for malformed input.

Tokenizer access

Validate, discard, or capture values from streaming token calls, with context helpers for nested operations.

Source It and Parse

Keep zjson.zsh beside its lib directory, source the entry point, and call functions directly. Results stay in the current shell; check the return status before reading output variables.

source /path/to/zjson/zjson.zsh

if zjson_parse_object '{"name":"zjson","enabled":true,"ports":[8080,8081]}'; then
  print -r -- "${ZJSON_OBJECT[name]}"
  print -r -- "${ZJSON_OBJECT_TYPES[enabled]}"

  zjson_parse_array "${ZJSON_OBJECT[ports]}"
  print -rl -- "${ZJSON_ARRAY[@]}"
else
  print -u2 -r -- "$ZJSON_ERROR"
fi

Whole-document functions publish results only after complete validation succeeds. A new call replaces the documented ZJSON result variables.

Navigate Nested JSON

Use JSON Pointer when a script needs one value rather than a complete decoded container. Pointer indexes start at zero, while native ZJSON_ARRAY indexing starts at one.

json='{"servers":[{"host":"localhost","port":8080}],"token":null}'

if zjson_get "$json" /servers/0/host; then
  print -r -- "$REPLY ($ZJSON_TYPE)"
fi

zjson_get "$json" /token
print -r -- "$REPLY ($ZJSON_TYPE)"

Lookup reports malformed JSON separately from a valid pointer that cannot resolve. It also detects ambiguous duplicate members while allowing duplicates elsewhere in the document.

Encoding, Diagnostics, and Context

zjson_quote encodes strings with JSON control-character escaping, while zjson_utf8_repair replaces malformed UTF-8 prefixes with U+FFFD. String encoding is intended for text, not lossless binary transport.

Token functions expose punctuation, scalar types, decoded values, and byte offsets for callers that need incremental control. zjson_with_context restores the outer tokenizer and diagnostics around nested operations.

Compatibility and Limits

Zsh 5.8 and newer are supported. The release matrix covers Zsh 5.8 and 5.9.2 on Linux in both C and C.UTF-8 locales with the command path empty.

Input must be UTF-8 without a leading BOM. Nesting is limited to 128 levels, parsing holds the complete source in memory, and there is one shared tokenizer rather than independent parser objects. The library is intended for shell-sized JSON documents, not streaming large datasets.