Noizu.Tessera.Hologram.Adapter (Noizu.Tessera v0.2.0)

Copy Markdown View Source

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 prop for every attr and every on_<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/regular prop entries are declared by the author's own prop DSL line, which delegates to Hologram's prop macro, with tessera opts json:/default: riding along;
  • renders the component tag with kebab-case attributes, booleans by presence (nil/false values make Hologram drop the attribute), tsr-props JSON (camelCase keys, omitted when no json prop is set), the data-tsr-on bridge map built from the binding props (:action ⇒ @page; {:action, target: "layout" | cid}), data-cy, and passes slot content through with <slot />;
  • the js_import of the component .mjs by ABSOLUTE path (built from the component module's __DIR__) binding register is emitted as raw @__js_imports__/@external_resource attributes at __using__ time (same expansion as Hologram's own js_import/2 macro produces), and a generated init/3 calls it via Hologram.JS.call/2 so 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

available?()

@spec available?() :: boolean()

True when Hologram is compiled into the path (adapter generation is gated on this).

body_ast(spec, caller_dir)

@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).

event_pairs(spec)

[{on_persona_select, "persona-select"}, ...] — binding-prop atom to event name pairs, in spec order. Drives the generated data-tsr-on helper.

has_top_level_register?(source)

@spec has_top_level_register?(String.t()) :: boolean()

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.

hologram_prop_entries(spec)

@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.

js_import_asts(mjs_path)

@spec js_import_asts(String.t() | nil) :: [Macro.t()]

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.

json_prop_pairs(map)

@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.

mjs_path(module_file, js)

@spec mjs_path(String.t(), String.t()) :: String.t()

The absolute .mjs path for a spec module file + colocated js filename.

template_markup(spec)

@spec template_markup(Noizu.Tessera.Spec.t()) :: String.t()

The ~HOLO markup rendered by the generated component (CONTRACT.md §3).

warn_missing_top_level_register(mjs_path)

@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.

write_contract_next_to_mjs(spec)

@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.