← Playground index

.apiext — extended element-API format

The successor to WebObjects' .api format: per-element and per-binding documentation, binding types, directionality, value interpretation, typed constraints and element policies — enough to render an element's API in an editor and validate templates against it. Proposal stage; in use here. The element reference renders entirely from .apiext files.

The current/old .api declares an element's bindings — names, a few flags, cross-binding validation — and little to nothing about what a binding means or it's typing. .apiext keeps that format's skeleton and adds all of it; one legacy area (the <validation> predicate language) is replaced outright by typed constraints, with legacy files handled by a mechanical converter. The WO runtime does not read .api; only tooling does (WOLips, Parslips), so the format is constrained only by "don't strand existing files".

Format

Same skeleton as .api (<wodefinitions> / <wo> / <binding>); extensions in green:

<wodefinitions>
  <wo class="WOCheckBox" content="forbidden" unknownAttributes="passthrough">

    <doc><![CDATA[A checkbox. Use **either** `checked` or `value`+`selection`.]]></doc>

    <binding name="checked">
      <pull><type interpretation="truthy">java.lang.Object</type></pull>
      <push><type>java.lang.Boolean</type></push>
      <doc>The checked state.</doc>
    </binding>

    <choose min="1" max="1">
      <binding name="checked"/> <binding name="value"/>
    </choose>

  </wo>
</wodefinitions>

Documentation

Each element and binding may carry a <doc>. Bodies use an injection-safe Markdown subset (inline `code`, **bold**, *italic*, links, fenced code blocks); a plain consumer can show the raw text.

Types

A binding declares one or more <type> — a fully-qualified Java class (or, later, a value-set name). Multiple types mean "accepts any of these" (e.g. updateContainerID: String or List). Intended for validation, not only display.

Directionality — <pull> / <push>

A binding's type can differ by direction: a checkbox's checked pulls any value (read as a boolean) and pushes back a Boolean. The type lives inside a direction block; the presence of <pull>/<push> declares the direction (no separate direction= attribute).

Only type is direction-specific; name, doc, and required stay on the binding. A <type> is always inside a direction block, never a direct child of <binding>.

Interpretation — interpretation="truthy"

Some bindings read a value by a coercion rule, not by type. WOConditional.condition accepts anything but reads it as a boolean (null, 0, false → false). The interpretation attribute names that rule without changing the type: <type interpretation="truthy">java.lang.Object</type>. The type remains the validatable constraint (Object); the interpretation is shown as a qualifier, Object (truthy).

Child content — content

An element declares its policy for child content: expected (usually a container — editors insert <wo:x></wo:x> by default; empty usage is fine), allowed (hybrid — works with and without content) or forbidden (content is a validation error, strictly: the tag must be self-closing). Validation lives entirely in forbidden; the other two are documentation and editor affordance. Absent = no policy stated, the tool decides.

Unknown attributes — unknownAttributes

An element declares what happens to attributes not named in its binding API: forbidden (an undeclared binding is a validation error — closed set), allowed (accepted; not forwarded, not flagged) or passthrough (accepted and forwarded onto the rendered tag — name preserved, value evaluated, so data-id="$item.id" renders the item's id). One axis: passthrough implies allowed, so "forwarded but flagged" — a contradiction — is unrepresentable. Absent means the author stated no policy and the tool applies its own default; a present value is a portable claim every tool must honour.

Default values — <default>

A binding may declare the value the element behaves as if bound to when the binding is unbound: <default>div</default>. Literals only — computed fallbacks ("the item's toString") stay prose in <doc>. Never directional, and never satisfies validation: "bound" always means explicitly bound in the template, so a default satisfies neither required nor a constraint. Distinct from the legacy defaults attribute (an autocomplete-preset hint).

Deprecation — <deprecated>

A binding — or, as a child of <wo>, a whole element — may be marked deprecated; the body is the migration note (same Markdown subset as <doc>). Using it is a warning-class diagnostic, never an error: deprecated still works. The message is generated from the fact ("'observeFieldFrequency' is deprecated.") plus the note. <doc> keeps describing what the binding does; <deprecated> says what to do instead.

Constraints — <choose> / <requires>

Typed, positive cross-binding rules replacing .api's inverted <validation> predicate trees. <choose min max> is cardinality over a set of alternatives (at-least-one / at-most-one / exactly-one); <requires binding must when> is implication, with mustbound/settable/gettable. Messages are generated from the typed rule (the sample above renders as “Exactly one of 'checked' and 'value' must be bound.”); a message attribute overrides. Every referenced binding must resolve to a declared one — a file with a typo'd reference is rejected, not silently weakened.

Out of scope

The format describes a binding's contract, not the runtime. A type that is only determined at runtime is declared as its widest honest type. Example: WOTextField.value pushes a String, Number, or NSTimestamp depending on the bound formatter (anything, for a custom one), so its push type is declared Object, with the detail in <doc>.

Status

CapabilityStatus
per-element / per-binding doc (Markdown)present
typed bindings (multi-type)present (declared; enforcement is future work)
required + typed cross-binding constraints (choose / requires)present (replaces .api's validation language; messages generated)
directionality (pull / push)present
value interpretation (truthiness)present
default values (<default>)present (display + validation-relevant: a default never satisfies a constraint)
unknown-attribute policy (unknownAttributes)present (forbidden / allowed / passthrough; absent = tool decides)
child-content policy (content)present (expected / allowed / forbidden; only forbidden validates)
deprecation (<deprecated>, binding + element level)present (warning-class, migration note in the body)
value-setsnot yet

Successor to WO's .api, not a superset — legacy .api files are handled by their own grammar and a mechanical converter. The format spec — grammar (apiext.dtd), field-by-field reference, examples, and status — lives in its own repository: github.com/undur/apiext-format.