defmodule CKEditor5.Context do @moduledoc """ Represents the CKEditor 5 context configuration. """ import Norm alias CKEditor5.{CustomTranslations, Errors} @derive Jason.Encoder @type t :: %__MODULE__{ config: map(), watchdog: map(), custom_translations: CustomTranslations.t() | nil } defstruct config: %{ plugins: [] }, watchdog: nil, custom_translations: nil @doc """ Defines the schema for a raw Context configuration map. """ def s do schema = schema(%{ config: spec(is_map()), watchdog: spec(is_map() or is_nil()), custom_translations: spec(is_map() or is_nil()) }) selection(schema, [:config]) end @doc """ Parses a map into a Context struct. Returns {:ok, %Context{}} if valid, {:error, reason} if invalid. """ def parse(nil), do: {:ok, nil} def parse(%__MODULE__{} = context), do: {:ok, context} def parse(map) when is_map(map) do with {:ok, _} <- conform(map, s()), {:ok, parsed_map} <- parse_custom_translations(map) do {:ok, struct(__MODULE__, parsed_map)} else {:error, errors} -> {:error, errors} end end def parse(_), do: {:error, "Context configuration must be a map or nil"} # Parses the custom translations from a map into a CustomTranslations struct. defp parse_custom_translations(context_map) do case CustomTranslations.parse(context_map[:custom_translations]) do {:ok, custom_translations} -> {:ok, Map.put(context_map, :custom_translations, custom_translations)} {:error, error} -> {:error, error} end end @doc """ Parses a map into a Context struct. Returns %Context{} if valid, raises an error if invalid. """ def parse!(data) do case parse(data) do {:ok, context} -> context {:error, reason} -> raise Errors.InvalidContext, reason: reason end end end