Module

Tramaj.Node

Package
purescript-tramaj-purs
Repository
lucasdicioccio/purescript-tramaj-purs

The evaluated document representation — Tramaj's output domain and its portable interchange boundary. nodeToJson/nodeFromJson implement the normative representation specified in specs/node-json.md; that document, not this module, is the contract other implementations and hosts are held to.

Deliberately independent of both the expression AST (Tramaj.Ast) and of any particular render target — folding a Node into Halogen HTML is Tramaj.Halogen's job, in its own package, and another host may fold the same tree into YAML, HCL or a UI model instead.

Kept in lockstep with ../tramaj-hs/src/Tramaj/Node.hs.

#Node Source

data Node

Three constructors, with enough expressivity inside them to carry scalars losslessly — see specs/decisions.md #5.

NText holds a Json, not a String: .p($ctx.count) with count = 3 keeps the number 3 rather than stringifying it. Rendering a scalar to characters is a host decision, so the interchange format declines to make it.

NElement holds a value slot alongside its children, for targets that attach a body value to a tagged node (a YAML/HCL scalar leaf, a config value); it is null unless a template sets one. Its attributes are an ordered array rather than a map: an element may carry any number of attributes and any number of actions, and source order is preserved.

NFragment is a real node here — an ordered sibling sequence with no wrapper element. A host may flatten fragments when folding; evaluation does not.

Constructors

Instances

  • Eq Node
  • Show Node

    Json has no Show instance, so every payload is stringifyd explicitly rather than riding along on a derived one.

#NodeAttribute Source

data NodeAttribute

Both attribute-position constructs, sharing one array. An action's event and key are plain String because both are static in the source AST (see Tramaj.Ast); only the payload is computed.

Constructors

Instances

#Annotations Source

type Annotations = Map String Json

Arbitrary host/tooling metadata hung off any node. The core language assigns no meaning to any key; unknown annotations must not affect semantics, and every node-to-node transformation must carry them through unchanged. This is where a future type/domain/constraint pass puts what it derives, without the Node constructors having to change.

#nodeToJson Source

nodeToJson :: Node -> Json

Encodes to the normative representation. Every field is always emitted, including an empty annotations and a null element value — see specs/node-json.md, "Decoding": on the wire a missing field is a bug, not a default.

#nodeFromJson Source

nodeFromJson :: Json -> Either String Node

Decodes the normative representation, strictly: a missing or ill-typed field is an error rather than a silently-defaulted value, so nodeFromJson <<< nodeToJson round-trips and a malformed document is reported where it is read rather than where it later misbehaves. The Left carries a human-readable description of what was wrong.

#mapActions Source

mapActions :: forall f. Applicative f => (String -> String -> Json -> f NodeAttribute) -> Node -> f Node

Rewrites every action reachable in a tree, leaving everything else — tags, ordinary attributes, element value slots, child order, and every annotation map — untouched. Polymorphic in the applicative so a caller that only fails (Either) and one that also accumulates something alongside its result (v3-symbols constraint emission) can share this one traversal.