Statifier.Invoke.Source (Statifier v2.0.0)

Copy Markdown View Source

Turns an %Statifier.Effect.Invoke{}'s content/src pair into a Statifier.Machine.t() ready to start as a child session - the seam ADR-0038 decided: the library never dereferences src.

Spec 6.4.2 treats the two identically ("these services MUST treat values specified by 'src' and <content> identically"), but they cannot share one resolution path. content reaching this module has already been resolved by the pure core (Statifier.Effect.Invoke's own moduledoc); when it is a binary, 6.4.2 requires an SCXML-typed service to "interpret [it]... as markup to be executed", and Statifier.compile/2 is exactly that interpretation - called here with invoke_content_markup: true (ADR-0042), the one call site in the pipeline that sets it, since this is the one place a Document.Content markup slice or expr-delivered markup binary is ever compiled standalone. src names a resource the core never fetches (ADR-0031); resolving it is handed to an embedder-supplied function, never performed here, on the same security posture ADR-0024 already applies to <data src> - a document-named URI dereferenced by the engine by default is a request-forgery surface handed to whoever writes the document.

content is checked before src when a document specifies both: 6.4 treats the two as interchangeable, so a document naming both is already non-conformant, and there is no ordering rule this module could violate by picking one over the other.

Every {:error, _} this module returns is the session's cue to raise error.communication (spec 3.12.2) on the parent and abandon the invocation without writing a table entry - this module has no opinion on how that error is delivered; it only decides whether a Machine.t() can be produced at all.

Summary

Types

Why a source could not be resolved into a Machine.t()

Functions

Resolves invoke's content/src into a Machine.t(). opts[:invoke_source], when given, is a (src :: String.t() -> {:ok, Machine.t()} | {:error, term()}) function an embedder supplies to Statifier.start_session/2; with no resolver configured, a src-only invocation is {:error, :src_not_resolved} rather than a fetch attempt.

Types

reason()

@type reason() ::
  {:compile, [Statifier.error()]}
  | :src_not_resolved
  | {:content_not_markup, term()}
  | :no_source
  | term()

Why a source could not be resolved into a Machine.t():

  • {:compile, errors} - content was markup that failed to compile (Statifier.compile/2's own error list).
  • :src_not_resolved - src was present but no invoke_source resolver was configured.
  • {:content_not_markup, content} - content was present but neither nil nor a binary (a value-shaped <content>, 5.6's other case, naming nothing an SCXML-typed service can start).
  • :no_source - neither src nor content yielded a usable source: both absent, or content absent and src not a binary (a srcexpr that evaluated to a non-string).

An embedder-supplied invoke_source resolver's own {:error, reason} is returned unchanged, so its reason shape is not enumerated here.

Functions

resolve(invoke, opts)

@spec resolve(invoke :: Statifier.Effect.Invoke.t(), opts :: keyword()) ::
  {:ok, Statifier.Machine.t()} | {:error, reason()}

Resolves invoke's content/src into a Machine.t(). opts[:invoke_source], when given, is a (src :: String.t() -> {:ok, Machine.t()} | {:error, term()}) function an embedder supplies to Statifier.start_session/2; with no resolver configured, a src-only invocation is {:error, :src_not_resolved} rather than a fetch attempt.

content, when a binary, compiles with invoke_content_markup: true (ADR-0042) - the one call site in the whole pipeline that sets this Statifier.compile/2 option, so a namespace-less <content> markup root compiles here exactly as G.6 places it, and nowhere else relaxes that check.