# `RDF.JSON`
[🔗](https://github.com/rdf-elixir/rdf-ex/blob/v3.0.1/lib/rdf/model/literal/datatypes/json.ex#L1)

`RDF.Literal.Datatype` for `rdf:JSON`.

As specified in RDF 1.2, this datatype allows JSON content as literal values.
The lexical forms must conform to [RFC 7493 (I-JSON)](https://www.rfc-editor.org/rfc/rfc7493).

See: <https://www.w3.org/TR/rdf12-concepts/#section-json>

> ### Note {: .warning}
>
> Most functions in this module require OTP 25 or later, since JSON canonicalization (JCS)
> relies on it.

# `lexical`

```elixir
@type lexical() :: String.t()
```

# `t`

```elixir
@type t() :: %RDF.JSON{lexical: lexical()}
```

# `value`

```elixir
@type value() :: String.t() | number() | boolean() | map() | list() | nil
```

# `canonical`

```elixir
@spec canonical(RDF.Literal.t() | t()) :: RDF.Literal.t()
```

Returns a JCS canonicalized version of a JSON literal.

When the given literal is invalid, it is returned unchanged.

# `canonical?`

```elixir
@spec canonical?(RDF.Literal.t() | t()) :: boolean() | nil
```

Determines if the lexical form of a JSON literal is in the canonical form.

# `canonical_lexical`

Returns the canonical lexical form of a `RDF.Literal` of this datatype.

# `cast`

```elixir
@spec cast(RDF.Literal.Datatype.literal() | RDF.Term.t()) :: RDF.Literal.t() | nil
```

Casts a datatype literal of one type into a datatype literal of another type.

Returns `nil` when the given arguments are not castable into this datatype or when the given argument is an
invalid literal.

Implementations define the casting for a given value with the `c:RDF.Literal.Datatype.do_cast/1` callback.

# `compare`

```elixir
@spec compare(RDF.Literal.t() | any(), RDF.Literal.t() | any()) ::
  RDF.Literal.Datatype.comparison_result() | :indeterminate | nil
```

# `datatype?`

Checks if the given literal has this datatype.

# `equal_value?`

Checks if two datatype literals are equal in terms of the values of their value space.

Non-`RDF.Literal`s  are tried to be coerced via `RDF.Literal.coerce/1` before comparison.

Returns `nil` when the given arguments are not comparable as literals of this
datatype.

Invalid literals are only considered equal in this relation when both have the exact same
datatype and the same attributes (lexical form, language etc.).

Implementations can customize this equivalence relation via the `c:RDF.Literal.Datatype.do_equal_value_different_datatypes?/2`
and `c:RDF.Literal.Datatype.do_equal_value_different_datatypes?/2` callbacks.

# `lexical`

```elixir
@spec lexical(RDF.Literal.t() | t()) :: String.t()
```

Returns the lexical value of a JSON literal.

# `new`

```elixir
@spec new(
  t() | lexical() | value(),
  keyword()
) :: RDF.Literal.t()
```

Creates a new `RDF.JSON` literal.

When given a string it is interpreted as a JSON encoding by default, unless
the `as_value` option is set to `true`.

## Options

- `:as_value` - when `true`, strings are encoded as JSON strings instead of
  being interpreted as JSON
- `:jason_encode` - when `true`, uses Jason for encoding (instead of JCS), which enables:
  - encoding of custom types implementing the `Jason.Encoder` protocol
  - passing of encoding options to `Jason.encode/2`
- `:pretty` - when `true`, values are encoded in a more readable format (not canonical!)
- `:canonicalize` - when `true`, the value is canonicalized according to JCS;
  cannot be combined with the `:pretty` option

- `:jason_encode` - when `true`, uses `Jason.Encoder` instead of JCS encoding

## Examples

    iex> RDF.JSON.new(%{foo: 42})

    iex> RDF.JSON.new(~s({"foo": 42}))

    iex> RDF.JSON.new("not JSON") |> RDF.JSON.valid?()
    false

    iex> RDF.JSON.new("null") |> RDF.JSON.value()
    nil

    iex> RDF.JSON.new("null", as_value: true)  |> RDF.JSON.value()
    "null"

    iex> RDF.JSON.new(%{a: 1}, pretty: true)

    # assuming we have a Jason.Encoder protocol implementation of our CustomJSON struct
    iex> RDF.JSON.new(%CustomJSON{value: 42}, jason_encode: true, escape: :html_safe)

# `new!`

```elixir
@spec new!(
  lexical() | value(),
  keyword()
) :: RDF.Literal.t()
```

Like `new/2` but raises an `ArgumentError` when the value is invalid.

## Examples

    iex> RDF.JSON.new!(%{foo: 1})
    RDF.JSON.new(%{foo: 1})

    iex> RDF.JSON.new!("not JSON")
    ** (ArgumentError) "not JSON" is not a valid RDF.JSON

# `prettified`

```elixir
@spec prettified(RDF.Literal.t() | t()) :: RDF.Literal.t()
```

Returns a prettified version of a JSON literal.

When the given literal is invalid, it is returned unchanged.

# `update`

Updates the value of a `RDF.Literal` without changing everything else.

# `valid?`

```elixir
@spec valid?(RDF.Literal.t() | t()) :: boolean() | nil
```

Determines if a JSON literal is valid with respect to [RFC 7493 (I-JSON)](https://www.rfc-editor.org/rfc/rfc7493).

# `value`

```elixir
@spec value(
  RDF.Literal.t() | t(),
  keyword()
) :: value() | :invalid
```

Returns the value of a JSON literal.

When the given literal is invalid, `:invalid` is returned.

## Options

All options are passed to `Jason.decode/2`.

## Examples

    iex> RDF.JSON.new(~s({"foo": 1})) |> RDF.JSON.value()
    %{"foo" => 1}

    iex> RDF.JSON.new(~s({"foo": 1})) |> RDF.JSON.value(keys: :atoms)
    %{foo: 1}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
