defmodule ExOKF do @moduledoc """ ExOKF — the reference Elixir implementation of the Open Knowledge Format (OKF). Provides standards-compliant parsing, validation with rich diagnostics, lossless reading/writing, link resolution, graph indexing, querying, and provenance-aware AI context assembly. ## Public API {:ok, bundle} = ExOKF.load("path/to/bundle") {:ok, diags} = ExOKF.validate(bundle) :ok = ExOKF.write(bundle, "path/to/out") concepts = ExOKF.query(bundle, type: "BigQuery Table") {:ok, ctx} = ExOKF.context(bundle, "tables/orders") GraphBLAS acceleration, advanced ranking, and MCP integration are ExOKF **extensions** layered on top of core OKF conformance — see the roadmap in the project README. """ alias ExOKF.{Bundle, Context, Diagnostics, Parser, Query, Validator, Writer} @doc """ Loads an OKF bundle from a filesystem path. Delegates to `ExOKF.Parser.load/2`. ## Parameters * `path` (`String.t()`) — path to the bundle directory * `opts` (`keyword()`) — parser options: * `:max_concurrency` (`pos_integer()`) — parallel parse tasks * `:timeout` (`timeout()`) — per-task timeout * `:build_graph` (`boolean()`) — index link graph (default `true`) ## Returns * `{:ok, ExOKF.Bundle.t()}` — loaded bundle * `{:error, term()}` — e.g. `{:not_a_directory, path}` ## Examples iex> {:ok, bundle} = ExOKF.load(ExOKF.TestSupport.minimal_fixture_path()) iex> ExOKF.Bundle.size(bundle) >= 1 true """ @spec load(String.t(), keyword()) :: {:ok, Bundle.t()} | {:error, term()} def load(path, opts \\ []), do: Parser.load(path, opts) @doc """ Validates a bundle, returning diagnostics. Warnings alone do not fail validation. Only error-severity diagnostics produce `{:error, diagnostics}`. Delegates to `ExOKF.Validator.validate/1`. ## Parameters * `bundle` (`ExOKF.Bundle.t()`) — loaded OKF bundle ## Returns * `{:ok, ExOKF.Diagnostics.t()}` — conformant (warnings allowed) * `{:error, ExOKF.Diagnostics.t()}` — non-conformant ## Examples iex> bundle = ExOKF.TestSupport.sample_bundle() iex> {:ok, diags} = ExOKF.validate(bundle) iex> is_struct(diags, ExOKF.Diagnostics) true """ @spec validate(Bundle.t()) :: {:ok | :error, Diagnostics.t()} def validate(%Bundle{} = bundle), do: Validator.validate(bundle) @doc """ Writes a bundle to `destination` (lossless round-trip of known + unknown frontmatter). Delegates to `ExOKF.Writer.write/2`. ## Parameters * `bundle` (`ExOKF.Bundle.t()`) — in-memory bundle * `destination` (`String.t()`) — output directory path ## Returns * `:ok` — success * `{:error, term()}` — filesystem error ## Examples iex> bundle = ExOKF.TestSupport.minimal_bundle() iex> dest = Path.join(System.tmp_dir!(), "ex_okf_api_write_" <> Integer.to_string(:erlang.phash2(make_ref()))) iex> ExOKF.write(bundle, dest) :ok """ @spec write(Bundle.t(), String.t()) :: :ok | {:error, term()} def write(%Bundle{} = bundle, destination), do: Writer.write(bundle, destination) @doc """ Queries concepts in the bundle. Delegates to `ExOKF.Query.query/2`. See that module for filter types. ## Parameters * `bundle` (`ExOKF.Bundle.t()`) — loaded OKF bundle * `filters` (`keyword()`) — AND-combined filters (`:type`, `:tag`, `:id`, `:has_resource`) ## Returns A list of matching `ExOKF.Concept.t()`. ## Examples iex> bundle = ExOKF.TestSupport.sample_bundle() iex> ExOKF.query(bundle, type: "BigQuery Dataset") |> Enum.map(& &1.id) ["datasets/sales"] """ @spec query(Bundle.t(), keyword()) :: [ExOKF.Concept.t()] def query(%Bundle{} = bundle, filters \\ []), do: Query.query(bundle, filters) @doc """ Assembles provenance-aware context for a concept. Delegates to `ExOKF.Context.build/3`. ## Parameters * `bundle` (`ExOKF.Bundle.t()`) — loaded OKF bundle * `concept_id` (`String.t()`) — seed concept id * `opts` (`keyword()`) — `:depth`, `:token_budget`, `:include_seed`, `:chars_per_token` ## Returns * `{:ok, ExOKF.Context.t()}` — assembled context * `{:error, term()}` — e.g. `{:unknown_concept, id}` ## Examples iex> bundle = ExOKF.TestSupport.sample_bundle() iex> {:ok, ctx} = ExOKF.context(bundle, "tables/orders", depth: 1) iex> ctx.seed "tables/orders" """ @spec context(Bundle.t(), String.t(), keyword()) :: {:ok, Context.t()} | {:error, term()} def context(%Bundle{} = bundle, concept_id, opts \\ []) do Context.build(bundle, concept_id, opts) end end