The compiled spec of a tessera component (CONTRACT.md is authoritative).
A spec is built at compile time by use Noizu.Tessera.Component from the
attr/prop/event/slot/cy declarations of the component module, and
is exposed on that module as __tessera_spec__/0. It is the single source
the generated JS contract module (Noizu.Tessera.Codegen.contract_module/1),
the Custom Elements Manifest (Noizu.Tessera.Codegen.cem/1) and the
Hologram adapter all derive from.
Entry shapes (plain maps):
attrs: %{name: :display_name, type: :string, required: true, default: nil, line: 3}
optional: attribute: "custom-name" | false, reflect: true
props: %{name: :tag_list, type: :list, json: true, default: [], line: 4}
events: %{name: "persona-select", detail: %{persona_id: :string}, line: 5}
slots: %{name: "default", line: 6}
styles: %{kind: :css, value: ":host { … }", line: 7}
%{kind: :shared, value: "./shared_styles.mjs", line: 8}
css: %{name: "--persona-card-accent", default: "#6366f1", line: 7}
parts: %{name: "select-button", line: 8}
lifecycle: %{will_update: %{js: "…", line: 9}, …} (only declared hooks)css/part entries are documentation metadata for the Custom Elements
Manifest (and the gallery) — they do not ride the wire contract.
Summary
Functions
The first stable extension_api used when a spec declares none (§8.1).
Escapes a string for inclusion inside a JSON double-quoted literal. Every
control character (< 0x20) is escaped: LF/CR/TAB as the short forms, all
others (backspace, form feed, NUL, ESC, ...) as \u00XX — a raw control
byte would be a SyntaxError in the generated .mjs and break JSON.parse.
The JSON-literal form of a spec default value, as it appears in the
generated contract module (CONTRACT.md §2). nil becomes null.
Spec rendered to a plain JSON-encodable map (used by __tessera_manifest__/0).
Validates an option value against the contract and raises CompileError
with a pointed message otherwise. Used at compile time by
Noizu.Tessera.Component and by mix tessera.gen.component.
Validates the DSL kind + type carried in a raw entry tuple.
Types
@type attr_entry() :: %{ :name => Noizu.Tessera.Naming.snake(), :type => atom(), optional(:required) => boolean(), optional(:default) => any(), optional(:attribute) => String.t() | false, optional(:reflect) => boolean(), optional(:line) => non_neg_integer() }
@type css_entry() :: %{ :name => String.t(), optional(:default) => String.t() | nil, optional(:line) => non_neg_integer() }
@type event_entry() :: %{ :name => Noizu.Tessera.Naming.kebab(), optional(:detail) => %{required(Noizu.Tessera.Naming.snake()) => atom()}, optional(:line) => non_neg_integer(), optional(:inherited) => boolean(), optional(:renames) => Noizu.Tessera.Naming.kebab(), optional(:renamed_from) => Noizu.Tessera.Naming.kebab() }
@type lifecycle() :: %{optional(lifecycle_hook()) => lifecycle_entry()}
@type lifecycle_entry() :: %{:js => String.t(), optional(:line) => non_neg_integer()}
@type lifecycle_hook() :: :should_update | :will_update | :first_updated | :updated
@type part_entry() :: %{:name => String.t(), optional(:line) => non_neg_integer()}
@type prop_entry() :: %{ :name => Noizu.Tessera.Naming.snake(), :type => atom(), optional(:json) => boolean(), optional(:default) => any(), optional(:attribute) => String.t() | false, optional(:reflect) => boolean(), optional(:line) => non_neg_integer() }
@type slot_entry() :: %{:name => String.t(), optional(:line) => non_neg_integer()}
@type state_entry() :: %{ :name => Noizu.Tessera.Naming.snake(), :type => atom(), optional(:default) => any(), optional(:attribute) => String.t() | false, optional(:reflect) => boolean(), optional(:line) => non_neg_integer() }
@type style_entry() :: %{ :kind => :css | :shared, :value => String.t(), optional(:line) => non_neg_integer() }
@type t() :: %Noizu.Tessera.Spec{ actions: [action_entry()], attrs: [attr_entry()], css_properties: [css_entry()], cy: String.t() | nil, derived_from: module() | nil, events: [event_entry()], extension_api: String.t() | nil, file: String.t() | nil, form_associated: boolean(), js: String.t() | nil, lifecycle: lifecycle(), module: module() | nil, parts: [part_entry()], priority: integer(), props: [prop_entry()], region_overrides: [atom()], regions: [region_entry()], slots: [slot_entry()], state: [state_entry()], styles: [style_entry()], tag: Noizu.Tessera.Naming.kebab() | nil, template: template_entry() | nil, version: pos_integer() }
@type template_entry() :: %{ :raw => String.t(), :lexer => :hologram | :minimal, :render_js => String.t(), optional(:line) => non_neg_integer(), optional(:regions) => [region_entry()], optional(:region_methods) => [region_method()], optional(:region_overrides) => [atom()] }
Functions
@spec default_extension_api() :: String.t()
The first stable extension_api used when a spec declares none (§8.1).
Escapes a string for inclusion inside a JSON double-quoted literal. Every
control character (< 0x20) is escaped: LF/CR/TAB as the short forms, all
others (backspace, form feed, NUL, ESC, ...) as \u00XX — a raw control
byte would be a SyntaxError in the generated .mjs and break JSON.parse.
The JSON-literal form of a spec default value, as it appears in the
generated contract module (CONTRACT.md §2). nil becomes null.
Spec rendered to a plain JSON-encodable map (used by __tessera_manifest__/0).
@spec validate!( atom(), String.t() | atom(), keyword() | %{required(atom()) => atom()}, String.t(), non_neg_integer() ) :: :ok
Validates an option value against the contract and raises CompileError
with a pointed message otherwise. Used at compile time by
Noizu.Tessera.Component and by mix tessera.gen.component.
kind is the DSL entry being validated ("attr", "prop", "event", ...).
Validates the DSL kind + type carried in a raw entry tuple.