Tramaj.Halogen
- Package
- purescript-tramaj-halogen
- Repository
- lucasdicioccio/purescript-tramaj-halogen
Folds the normative Tramaj.Node AST into real Halogen output. The
only module in this repository that depends on halogen —
Tramaj.Ast/Parser/Eval/Node have no Halogen dependency at all,
so the same evaluated tree can be folded to something else entirely.
Three v2 changes shape this module. A node is no longer guaranteed to
be a single element, because fragments are real nodes, so the fold
returns an Array. An element may carry any number of actions rather
than at most one. And attribute values, text values and the element
value slot are arbitrary JSON rather than pre-stringified text —
evaluation deliberately stops short of deciding how a number renders,
which makes it this module's decision (renderScalar).
v3-symbols support: a value anywhere in the tree may be the §5.3 wire
tag {"$sym": <id>, "path": [...]} rather than an ordinary scalar, and
renderScalar recognizes it unconditionally rather than behind a mode
flag — that shape cannot arise honestly from concrete-mode output,
since "$sym" as a literal object key is a parse error, so seeing the
shape already tells the whole story. renderSymbolTable and
renderConstraintTable render the envelope's "symbols"/
"constraints" arrays the same way; renderTypesTable and
renderTypeConstraintTable do the same for v4-types \S8's "types"/
"type-constraints" arrays. This module is an example host,
not a normative one, so treat the table layout and origin formatting
below as a starting point, not a contract.
#foldToHalogen Source
foldToHalogen :: forall action slots m. (String -> String -> Json -> Maybe action) -> Node -> Array (ComponentHTML action slots m)dispatch maps an action — its event type, its key, and its JSON
payload — onto a real Halogen action; a host that wants purely
read-only rendering supplies \_ _ _ -> Nothing. An action that maps
to Nothing attaches no handler at all.
Every action dispatch accepts is wired to HE.onClick, without this
module looking at the event type: evaluation does not restrict that
string to any vocabulary, so dispatch is the only place that can tell
"on-click" from anything else and must return Nothing for event
types it does not want turned into a click. Continuous-input handling
is out of scope.
Returns an Array because a Tramaj.Node need not be a single
element: a fragment contributes its children with no wrapper, which is
the whole point of it. A host rendering a document root splices the
result into whatever container it already has.
foldToHalogen trusts that attribute names are legal DOM attribute
names and passes them to HP.attr. The language does not restrict
them, so a template can produce a name the DOM rejects, throwing
mid-render. Call validateAttrNames first and handle a non-empty
result rather than folding straight through.
An svg element and its descendants are built in the SVG namespace so
they actually paint (see foldIn).
#renderScalar Source
renderScalar :: Json -> StringHow this host renders a JSON value as DOM text. A symbol (v3-symbols
§5.3's {"$sym": ..., "path": [...]} tag) renders as its id with its
path dotted on, e.g. #0:"d".replicas. Otherwise: a string is itself,
a whole number drops its trailing .0, null renders as nothing, and
anything structured falls back to compact JSON.
Deliberately this module's decision rather than the evaluator's: a
different host targeting YAML or a UI model would render the same
values differently, and v2's Node keeps them unconverted precisely so
that it can.
#isValidAttrName Source
isValidAttrName :: String -> BooleanA DOM attribute name this module is willing to set: alphanumeric plus
-/_ only (no spaces, colons, quotes) — deliberately stricter than
HTML itself permits, since the only names templates should need are
kebab-case/snake_case identifiers like data-count.
#validateAttrNames Source
validateAttrNames :: Node -> Array StringEvery invalid attribute name found anywhere in the tree (deduplicated,
tree order), or [] if node is safe to fold with foldToHalogen.
#renderSymbolTable Source
renderSymbolTable :: forall action slots m. Array Json -> ComponentHTML action slots mRenders a v3-symbols §5.2 "symbols" array (the envelope's symbol
table) as an HTML table: id, origin (an allocation's site and key, or
a demand's path), and the binding it was read into, if any. An entry
that doesn't match the expected shape renders as a "?" row rather
than being dropped or throwing — this is reading a JSON contract, not
typed data.
#renderConstraintTable Source
renderConstraintTable :: forall action slots m. Array Json -> ComponentHTML action slots mRenders a v3-symbols §5.2 "constraints" array as an HTML table:
name and arguments, each argument shown with renderScalar — so a
symbol argument renders the same placeholder text
renderSymbolTable's rows and the document tree use.
#renderTypesTable Source
renderTypesTable :: forall action slots m. Array Json -> ComponentHTML action slots mRenders a v4-types \S8 "types" array (the envelope's type table) as
an HTML table: canonical id, and its definition rendered to short text
by resolvedTypeText. Declaration boundaries stay boundaries here too
— a ref definition shows only the id it points at, never the
pointee's own definition inlined, since that entry is its own row.
#renderTypeConstraintTable Source
renderTypeConstraintTable :: forall action slots m. Array Json -> ComponentHTML action slots mRenders a v4-types \S8 "type-constraints" array — same shape as
renderConstraintTable's "constraints" (name/arguments), except
a type argument is the erased {"$type": ...} tag \S7 reserves rather
than a plain scalar, so it needs its own argument formatter.
#renderCard Source
renderCard :: forall action slots m. Card -> ComponentHTML action slots mRenders a Tramaj.Analysis.Card — the same five-field summary
tramaj-cli analyze card prints as JSON — as a definition list: what
the program produces, what its own $ctx must supply, every library
it reaches, every action key it can emit, and which import sites still
leave one of their library's own parameters unsupplied.
Unlike the symbol/constraint/type tables above, this doesn't decode a
JSON envelope — a host that already has the Program and the
LibraryTable (as the playground does, from its own tabs) calls
Tramaj.Analysis.Card.programCard directly and hands the typed result
here.
- Modules
- Tramaj.
Halogen