JSCalendar.Type (JSCalendar v0.1.0)

Copy Markdown View Source

Reading and writing the value types RFC 8984 defines.

JSCalendar is JSON, so every value arrives as a string, number, boolean, list or map. This module is the single place that decides what each becomes in Elixir and how it goes back — so a round trip is one pair of functions to reason about rather than a decision repeated at every property.

The mapping is deliberately to standard-library types, not to types invented here:

JSCalendarElixir
LocalDateTimeNaiveDateTime.t/0
UTCDateTimeDateTime.t/0 in Etc/UTC
Duration, SignedDurationDuration.t/0
String[Boolean]MapSet.t/0
Id[Foo]%{String.t() => Foo.t()}

A String[Boolean] is a set written as an object whose values are all true, so it reads back as a MapSet"attendee" in participant.roles rather than a map lookup against a value that carries no information.

Summary

Types

A property's declared JSCalendar type.

Functions

Read a JSON value as spec.

Write an Elixir value back as JSON for spec.

Types

spec()

@type spec() ::
  :string
  | :boolean
  | :int
  | :unsigned_int
  | :local_date_time
  | :utc_date_time
  | :duration
  | :string_set
  | :string_map
  | :any
  | {:enum, [String.t()]}
  | {:list, spec()}
  | {:object, module()}
  | {:map_of, module()}
  | {:list_of, module()}
  | {:patch_map, spec()}

A property's declared JSCalendar type.

Functions

decode(value, spec)

@spec decode(term(), spec()) :: {:ok, term()} | {:error, term()}

Read a JSON value as spec.

Arguments

  • value is the decoded JSON value.

  • spec is a spec/0 naming the JSCalendar type.

Returns

  • {:ok, value} with the Elixir representation; or

  • {:error, reason} when the value does not match the type.

Examples

iex> JSCalendar.Type.decode("2026-06-02T09:00:00", :local_date_time)
{:ok, ~N[2026-06-02 09:00:00]}

iex> JSCalendar.Type.decode("PT1H", :duration)
{:ok, %Duration{hour: 1}}

iex> JSCalendar.Type.decode(%{"a" => true, "b" => true}, :string_set)
{:ok, MapSet.new(["a", "b"])}

iex> JSCalendar.Type.decode("nope", :local_date_time)
{:error, {:invalid_local_date_time, "nope"}}

encode(value, arg2)

@spec encode(term(), spec()) :: term()

Write an Elixir value back as JSON for spec.

nil is dropped by the caller rather than written as JSON null, since RFC 8984 distinguishes an absent property from a null one.

Arguments

  • value is the Elixir value.

  • spec is a spec/0 naming the JSCalendar type.

Returns

  • the JSON-ready value.

Examples

iex> JSCalendar.Type.encode(~N[2026-06-02 09:00:00], :local_date_time)
"2026-06-02T09:00:00"

iex> JSCalendar.Type.encode(MapSet.new(["a"]), :string_set)
%{"a" => true}