json/blueprint/value

The JSON value model, byte-bounded parsing, its text form and bridges to gleam/json.

Numbers retain exact mathematical values and repeated object keys reject. Erlang uses OTP JSON; JavaScript uses JSON.parse with source retention and strict duplicate/Unicode checks. Parsed member order is target-specific. Native syntax diagnostics have no portable source location. JavaScript requires JSON.parse reviver context.source; unsupported runtimes return UnsupportedRuntime. There is no alternate parser. Manually constructed Object values retain the supplied member order.

default_limits() admits at most 1 MiB (1,048,576 bytes). Change that bound with with_max_bytes. There are no document-depth, value-count or global numeric-token admission limits. The byte bound is not a heap-memory quota. Numeric native projection and codec constraints still apply independently. JavaScript recursion remains subject to the host stack capacity; exhaustion returns RuntimeCapacityExceeded, not a configured document-depth failure.

to_string renders compact JSON. to_json and decoder bridge native gleam/json values, whose parsing policy differs from this module.

import json/blueprint/value

pub fn example() {
  let limits = value.default_limits() |> value.with_max_bytes(64 * 1024)
  case value.parse("{\"tags\": [\"a\"]}", limits) {
    Ok(value.Object(members)) -> Ok(members)
    Ok(_) -> Error("expected an object")
    Error(error) -> Error(value.describe_parse_error(error))
  }
}

Types

The key that object found twice.

pub type DuplicateKey {
  DuplicateKey(key: String)
}

Constructors

  • DuplicateKey(key: String)

The input-byte admission bound for parse and parse_bits.

pub opaque type Limits

Where a parse failed: byte offset from 0, line and column from 1. Columns count graphemes. A native diagnostic without a portable source position uses Location(0, 0, 0); it does not identify the first byte.

pub type Location {
  Location(byte_offset: Int, line: Int, column: Int)
}

Constructors

  • Location(byte_offset: Int, line: Int, column: Int)

A parse failure. It carries no input text.

pub type ParseError {
  ParseError(location: Location, reason: ParseReason)
}

Constructors

Why parsing failed. ByteLimitExceeded is the input admission failure. May gain variants in a minor release; match with a _ branch.

pub type ParseReason {
  UnexpectedCharacter
  NativeSyntax
  UnsupportedRuntime
  RuntimeCapacityExceeded
  UnexpectedEndOfInput
  InvalidUtf8
  InvalidUnicodeScalar
  ByteLimitExceeded(max: Int)
  InvalidNumber(number.NumberError)
  DuplicateObjectKey
  UnterminatedString
  InvalidEscape
  InvalidUnicodeEscape
  TrailingContent
}

Constructors

  • UnexpectedCharacter
  • NativeSyntax

    The native parser rejected the document without a portable location.

  • UnsupportedRuntime

    JavaScript lacks JSON.parse reviver source text; no fallback is used.

  • RuntimeCapacityExceeded

    The host runtime could not finish parsing, independently of byte limits.

  • UnexpectedEndOfInput
  • InvalidUtf8
  • InvalidUnicodeScalar
  • ByteLimitExceeded(max: Int)
  • InvalidNumber(number.NumberError)
  • DuplicateObjectKey
  • UnterminatedString
  • InvalidEscape
  • InvalidUnicodeEscape
  • TrailingContent

A JSON value. Object members keep their order; the Object constructor accepts any list, and object rejects a repeated key.

pub type Value {
  Null
  Bool(Bool)
  String(String)
  Number(number.Number)
  Array(List(Value))
  Object(List(#(String, Value)))
}

Constructors

Values

pub fn decoder() -> decode.Decoder(Value)

A decoder of the data that gleam/json’s json.parse produces. Use it to read a Value through another JSON parser, for example json.parse(text, value.decoder()).

That parser owns duplicate keys, number precision and size limits: it keeps one of repeated keys, reads numbers as Int or Float, and does not keep member order. A float becomes the shortest decimal that reads back as the same float. Use parse for strict, bounded reading.

pub fn default_limits() -> Limits

Admit at most 1 MiB (1,048,576 bytes) of JSON text.

pub fn describe_parse_error(error: ParseError) -> String

Render a parse error as text such as invalid JSON at line 2, column 7: unexpected character. The text names the setter for a limit error and contains no input text.

pub fn is_limit_exceeded(error: ParseError) -> Bool

Whether the input exceeded a bound of Limits, as opposed to being invalid JSON.

pub fn object(
  entries: List(#(String, Value)),
) -> Result(Value, DuplicateKey)

Build an object, rejecting a key that appears twice.

pub fn parse(
  source: String,
  limits: Limits,
) -> Result(Value, ParseError)

Parse JSON with byte admission, duplicate rejection and exact numbers. Both targets use native parsing; object order may differ between targets. No depth, value-count or global numeric cap is applied.

pub fn parse_bits(
  bytes: BitArray,
  limits: Limits,
) -> Result(Value, ParseError)

Parse UTF-8 bytes. Byte admission precedes UTF-8 validation. Invalid UTF-8 retains the first invalid byte location independently of the JSON backend.

pub fn to_json(value: Value) -> Result(json.Json, number.Number)

Convert to gleam/json, exactly. An integer becomes json.int (on JavaScript, only a safe integer); another number becomes json.float when the float’s printed form reads back as the same number, such as 0.1 or 1e20. Fails with the first number that has no exact gleam/json form, such as 1e400 or 0.1000000000000000001.

pub fn to_string(value: Value) -> String

Render compact JSON text with no whitespace, keeping member order. Numbers are exact. A number whose decimal exponent is from -7 to 20, and on Erlang an integer of at most 50 digits, is written in plain decimal, such as 12.5 or 0.001; other numbers use number.to_string, such as 1e-9.

pub fn with_max_bytes(limits: Limits, bytes: Int) -> Limits

Accept at most bytes bytes of UTF-8 text. Below 1 rejects every input.

✨ Search Document