Generates the Hologram component (the "adapter", CONTRACT.md §3/§5) inside a
module that did use Noizu.Tessera.Component.
The generated component, in the same module as the spec:
- declares a Hologram
propfor everyattrand everyon_<event>binding prop — put directly by the DSL macros during module-body expansion, so they are part of Hologram's@__props__accumulator before Hologram's__before_compile__runs (hooks run in registration order). Json/regularpropentries are declared by the author's ownpropDSL line, which delegates to Hologram'spropmacro, with tessera optsjson:/default:riding along; - renders the component tag with kebab-case attributes, booleans by
presence (
nil/falsevalues make Hologram drop the attribute),tsr-propsJSON (camelCase keys, omitted when no json prop is set), thedata-tsr-onbridge map built from the binding props (:action⇒@page;{:action, target: "layout" | cid}),data-cy, and passes slot content through with<slot />; - the
js_importof the component.mjsby ABSOLUTE path (built from the component module's__DIR__) bindingregisteris emitted as raw@__js_imports__/@external_resourceattributes at__using__time (same expansion as Hologram's ownjs_import/2macro produces), and a generatedinit/3calls it viaHologram.JS.call/2so the bundler keeps it (CONTRACT.md §5).
Summary
Functions
True when Hologram is compiled into the path (adapter generation is gated on this).
The quoted AST of the generated component body: the init/2 + init/3
pair (+ the __tessera_init__/2 and __tessera_init__/3 hooks, all
defoverridable), the template, the bridge helpers and the
__tessera_spec__/0 + __tessera_manifest__/0 readers. Spliced from
__before_compile__ (the spec must be known). caller_dir is the
directory of the component module's file; the .mjs import path is built
from it and must be absolute (CONTRACT.md §5).
[{on_persona_select, "persona-select"}, ...] — binding-prop atom to event
name pairs, in spec order. Drives the generated data-tsr-on helper.
True when source contains a top-level register() call statement.
Hologram prop declaration entries the DSL must put into @__props__
(Hologram's own {name, type, opts} shape): one per attr and one
on_<event> binding prop per event. Put during module-body expansion —
NOT from __before_compile__ — so Hologram's __before_compile__ (hooks
run in registration order) sees the complete list.
The raw AST equivalent of Hologram's js_import(:register, from: path) —
the @__js_imports__ + @external_resource attribute puts. Emitted at
__using__ time so the entries are in the accumulator before any
__before_compile__ runs.
[{tag_list, "tagList"}, ...] — json prop atom to camelCase key pairs, in
spec order. Drives the generated tsr-props helper.
The absolute .mjs path for a spec module file + colocated js filename.
The ~HOLO markup rendered by the generated component (CONTRACT.md §3).
Compile-time sanity check: the component's .mjs must carry a TOP-LEVEL
register() call. It is load-bearing — stateless SSR never calls
init/3, so the element gets defined only when the page bundle evaluates
the .mjs and its last statement registers it. Missing it means the
component renders server-side but never upgrades on the client. Warns
(never raises) so an unusual packaging layout cannot break the host build.
Writes the generated contract module next to the component's .mjs
(colocated with the spec module) when spec.js is set and the content
changed. Warns (never raises) when the write fails, so a read-only source
tree cannot break the host build.
Functions
@spec available?() :: boolean()
True when Hologram is compiled into the path (adapter generation is gated on this).
@spec body_ast(Noizu.Tessera.Spec.t(), String.t()) :: Macro.t()
The quoted AST of the generated component body: the init/2 + init/3
pair (+ the __tessera_init__/2 and __tessera_init__/3 hooks, all
defoverridable), the template, the bridge helpers and the
__tessera_spec__/0 + __tessera_manifest__/0 readers. Spliced from
__before_compile__ (the spec must be known). caller_dir is the
directory of the component module's file; the .mjs import path is built
from it and must be absolute (CONTRACT.md §5).
@spec event_pairs(Noizu.Tessera.Spec.t()) :: [ {Noizu.Tessera.Naming.snake(), Noizu.Tessera.Naming.kebab()} ]
[{on_persona_select, "persona-select"}, ...] — binding-prop atom to event
name pairs, in spec order. Drives the generated data-tsr-on helper.
True when source contains a top-level register() call statement.
The match is anchored per line on purpose: it must only fire on a call
STATEMENT standing alone on its own line, never on an inline call
(foo(); register()) or inside another expression — only a statement the
bundle actually evaluates as a top-level statement provides the
load-bearing registration. Leading whitespace (indentation) is tolerated
so formatted sources (mix format, nested modules) still match.
@spec hologram_prop_entries(Noizu.Tessera.Spec.t()) :: [{atom(), atom(), keyword()}]
Hologram prop declaration entries the DSL must put into @__props__
(Hologram's own {name, type, opts} shape): one per attr and one
on_<event> binding prop per event. Put during module-body expansion —
NOT from __before_compile__ — so Hologram's __before_compile__ (hooks
run in registration order) sees the complete list.
The raw AST equivalent of Hologram's js_import(:register, from: path) —
the @__js_imports__ + @external_resource attribute puts. Emitted at
__using__ time so the entries are in the accumulator before any
__before_compile__ runs.
@spec json_prop_pairs(%{props: [map()]}) :: [ {Noizu.Tessera.Naming.snake(), Noizu.Tessera.Naming.camel()} ]
[{tag_list, "tagList"}, ...] — json prop atom to camelCase key pairs, in
spec order. Drives the generated tsr-props helper.
The absolute .mjs path for a spec module file + colocated js filename.
@spec template_markup(Noizu.Tessera.Spec.t()) :: String.t()
The ~HOLO markup rendered by the generated component (CONTRACT.md §3).
@spec warn_missing_top_level_register(String.t()) :: :ok
Compile-time sanity check: the component's .mjs must carry a TOP-LEVEL
register() call. It is load-bearing — stateless SSR never calls
init/3, so the element gets defined only when the page bundle evaluates
the .mjs and its last statement registers it. Missing it means the
component renders server-side but never upgrades on the client. Warns
(never raises) so an unusual packaging layout cannot break the host build.
@spec write_contract_next_to_mjs(Noizu.Tessera.Spec.t()) :: :ok
Writes the generated contract module next to the component's .mjs
(colocated with the spec module) when spec.js is set and the content
changed. Warns (never raises) when the write fails, so a read-only source
tree cannot break the host build.