Compile-time normalisation of a via: hop list into a canonical, validated form.
A traversal is an ordered list of hops, each walking one graph edge in one direction. Direction is mechanical and mechanism-independent — it names which end of the stored edge this instance is on:
:forward— this instance is the edgesource; filtersource_id = me, follow totarget_id.:reverse— this instance is the edgetarget; filtertarget_id = me, follow tosource_id.
Mechanism is :assignment (AssignmentRelationship) or :relationship
(DefinedSimpleRelationship). The two axes are independent, so any
mechanism × direction combination is a legal hop and chains of any length compose.
User hop forms
alias(bare atom) — shorthand for{:reverse, assignment: alias}(inherit from your assigner — the common case, and the zero-config default for an omittedvia:).{:forward | :reverse, assignment: alias}{:forward | :reverse, relationship: type}— relationship filtered bytypeonly.{:forward | :reverse, relationship: [type: t, alias: a]}— bytypeand/oralias.
Canonical form
normalize/2 returns {:ok, hops} where each hop is
{:forward | :reverse, :assignment | :relationship, selector} — selector
%{alias: a} for assignment, %{type: t, alias: a} for relationship (either of t/a
may be nil, but not both). On a malformed hop it returns {:error, reason} for the
verifier to surface as a DslError.
Used at compile time by TransformInheritedRefs (to inject the calc) and
VerifyCharacteristics (to validate). The runtime counterpart is
Diffo.Provider.Calculations.Traversal.
Summary
Functions
Normalises a user via: value (or nil) into a canonical hop list.