Runtime specification
This page defines the browser runtime contract for Sercrod. It is intended to be used as a stable reference for implementation, documentation, and tests.
This specification reflects the public runtime and documentation published as Sercrod v0.1.12.
The words MUST, MUST NOT, SHOULD,
SHOULD NOT, and MAY describe normative behavior.
1. Scope
This specification covers the runtime behavior of Sercrod hosts in a browser: host discovery, data initialization, template capture, rendering, expression scope, directive evaluation order, events, input timing, network execution, cleanup, and public integration hooks.
This specification does not define authoring style, product positioning, marketing text, or tutorial order.
2. Host model
A Sercrod host is a custom element named <serc-rod>.
-
The runtime MUST register the
serc-rodcustom element when the element has not already been registered. -
The runtime MUST apply Sercrod behavior to existing
<serc-rod>elements upgraded by the Custom Elements lifecycle. -
The runtime MUST apply the same behavior to
<serc-rod>elements added after the runtime has loaded. - Each host MUST manage only its own subtree. Sercrod MUST NOT take ownership of normal HTML outside hosts.
-
Nested
<serc-rod>elements MUST be treated as independent hosts.
3. Initialization order
For each host, runtime initialization MUST behave as if it follows this order:
- Determine the host instance and attach Sercrod runtime state.
- Initialize host data from the
dataattribute or assigned host data. - Capture the initial host children as the host template.
- Perform the initial render from the captured template and current data.
- Mark the host's JavaScript-only
readyproperty and dispatchsercrod-readyonce after the first completedupdate()cycle. - Register event listeners, network triggers, and cleanup hooks created during rendering.
An implementation MAY interleave internal setup steps, but the observable result MUST be equivalent to the order above.
The initial host HTML MUST be the source template for later updates. Updates MUST render from the stored template and current scope, not from the latest already-rendered DOM as if it were the canonical template.
4. Data model
Each host renders against a scope object. The host data object is the primary
scope for expressions, and the runtime MUST make host data
available through normal data names and through $data.
When a data attribute is present, the runtime MUST
attempt to parse it as JSON first. If JSON parsing fails, the runtime
MAY evaluate the attribute value as a JavaScript expression.
Expression-based data values MUST be treated as
trusted template code.
<serc-rod data='{"count":0}'>
<button @click="count++">%count%</button>
</serc-rod>
The runtime MAY allow host data assignment from JavaScript:
host.data = { count: 0 };
$rootMUST refer to the root data scope available to the current expression.$parentMUST refer to the nearest parent scope when one exists.- Directives such as
*let,*for, and*eachMAY create local scope values for their subtree. - Local scope values MUST NOT mutate host data unless a directive or expression explicitly writes to host data.
- The host property
readyMUST NOT be treated as host data and MUST NOT create a template-visible%ready%value.
5. Template and render model
Sercrod uses a regeneration render model. On update, the runtime MUST rebuild the host subtree from the stored host template, current host data, and current local scope.
The runtime does not specify a virtual DOM diff contract. Implementations MAY optimize internally, but public behavior MUST remain equivalent to regeneration from the stored template.
Text interpolation MUST evaluate expressions between the
configured delimiters. The default delimiter pair is % and
%, so %name% evaluates name.
*printand*textContentMUST emit text.*innerHTMLand*composeMAY emit HTML and MUST be treated as a higher-risk output path.
6. Expression scope
Sercrod expressions MUST be evaluated in the current Sercrod scope. Expressions MAY access:
- host data paths,
$data,$root, and$parent, - local names created by directives such as
*let,*for, and*each, $eventand$ein event handlers,eland$elin event handlers,- methods exposed through
*methodsor runtime method registration, - implementation helpers documented as public integration hooks.
Template authors SHOULD keep expressions small. Reusable or complex behavior SHOULD be moved into methods.
The runtime MUST treat expression execution as trusted template execution. This specification does not define a sandbox boundary for arbitrary untrusted expressions.
7. Directive prefixes and bindings
- Directive attributes use the
*prefix by default. - The
n-form is an alias for the same directive family. - Event handler attributes use the configured event prefix. The default prefix is
@. - Dynamic attribute bindings use the
:prefix, such as:href,:class, and:style.
The runtime MUST evaluate directive and binding expressions in the current Sercrod expression scope.
8. Directive evaluation order
For each rendered node, the runtime MUST behave as if directives are evaluated in this order:
- Plain output for text nodes and
*literal. - Scope pre-processing, including
*letand*global. -
Structure directives:
*if,*elseif,*else,*switch,*case,*default,*each, and*for. - Child Sercrod host boundary handling.
-
Non-structure side-effect and IO directives:
*apply,*restore, save/load action forms,*post,*fetch, and*api. - Fallback element rendering: attribute bindings, output directives, template include behavior, event binding, and recursive child rendering.
Some directives are early-exit directives. When an early-exit directive handles a node, later directive families on that same node MUST NOT be assumed to run.
Structure directives MUST decide DOM shape before side-effect and IO directives on the same node are evaluated.
9. Events and update timing
An event handler attribute has this form:
@event="expression"
When the DOM event fires, the runtime MUST evaluate the
expression in the current Sercrod scope. The runtime MUST
provide the native event as $event and $e, and the
declaring element as el and $el.
| Modifier | Required behavior |
|---|---|
.prevent / .preventDefault |
Call event.preventDefault(). |
.stop |
Call event.stopPropagation(). |
.once |
Register the listener with once behavior. |
.capture |
Register the listener in capture phase. |
.passive |
Register the listener as passive. |
.update |
Force an update after the handler runs. |
.noupdate |
Suppress the automatic update after the handler runs. |
The runtime SHOULD avoid automatic updates for configured
non-mutating events. The .update modifier MUST
force an update, and .noupdate MUST suppress the
automatic update for that handler.
10. Input timing
*inputMUST bind a form control value to a writable data path.- When the user edits the control, the runtime MUST write the new value to that path.
- Normal
*inputSHOULD update through the normal input update path. *lazyMUST keep the input value written to data while avoiding immediate parent template refresh for each edit.*eagerSHOULD update the surrounding interface immediately while the user types.
*lazy MUST NOT mean that the value is ignored.
*lazy MUST NOT be documented as blur-only behavior
unless tests establish that as a public contract.
When both *lazy and *eager are present on the same
element, behavior is currently unspecified and SHOULD NOT be relied on.
11. Network execution model
Network directives define a frontend/server contract through template attributes.
*fetchMUST perform simple GET-style loading.*postMUST send host data, or staged data when present, as JSON to the target URL.*apiMUST support a more general HTTP operation.*intoMUST designate the data key where the result is stored.
The public *fetch form is:
url[:prop]
When :prop is present, the runtime MUST store the
parsed response at that data property.
For HTTP responses, the runtime MUST parse JSON responses as
JSON when the response Content-Type indicates JSON. Non-JSON
responses MAY be kept as text or Blob-like values depending on
the directive and operation.
11.1 Trigger timing
*fetch and GET-style *api MUST be
treated as initial loading when attached to non-clickable elements.
*fetch and *api MUST be treated as
user-triggered actions when attached to clickable elements.
Clickable triggers include button, a without
download, input[type=button],
input[type=submit], and input[type=reset].
For *fetch, input[type=image] MUST
also be treated as clickable.
12. Runtime events
Network and file operations MUST expose observable
CustomEvent hooks for integration.
-
Each host MUST dispatch
sercrod-readyonce after its first completedupdate()cycle. At that point,host.readyMUST betrue. -
HTTP and API operations MAY dispatch
sercrod-load-start,sercrod-loaded,sercrod-load-error,sercrod-post-start,sercrod-posted,sercrod-post-error, andsercrod-error. -
File upload operations MAY dispatch
sercrod-upload-start,sercrod-upload-progress,sercrod-uploaded, andsercrod-error. -
File download operations MAY dispatch
sercrod-download-start,sercrod-downloaded, andsercrod-error.
The exact event detail payloads SHOULD be covered by directive-specific tests before being treated as stable public contract.
13. Cleanup and resource lifetime
- Hosts MUST clean up internal event handlers and resources when disconnected from the document.
- Cleanup MUST include window-level keyboard handlers and WebSocket connections when those resources were registered by the host.
- When cleanup configuration is enabled for generated output, the runtime MAY remove Sercrod-specific directive and event attributes from rendered DOM.
- The default cleanup configuration MUST NOT remove directive or handler attributes unless explicitly configured.
14. Configuration contract
Runtime configuration MUST be read from
window.__Sercrod.config when defined before
sercrod.js is loaded. Unspecified configuration fields
MUST keep their defaults.
The public configuration surface includes:
delimiters.startanddelimiters.endinclude.warn_on_element,include.remove_element_if_empty, andinclude.max_depthcleanup.directivesandcleanup.handlersevents.prefixandevents.non_mutatingwebsocket.internal_updatei18n.enabledandi18n.language
The runtime MAY also read ambient preload hooks before initialization:
window.__Sercrod_filterwindow.__Sercrod_methodswindow.__Sercrod_ast_hookswindow.__Sercrod_pre_hooks
These hooks MUST be defined before loading
sercrod.js if they should affect runtime initialization.
15. Security boundaries
Sercrod templates are executable trusted code.
- Expression evaluation, expression-based
datafallback, registered methods, HTML output directives, and AST/pre-hook integration MUST NOT be treated as safe for arbitrary untrusted input. - Template authors SHOULD prefer text output directives such as
*printand*textContentfor user-controlled values. - Template authors SHOULD use
*innerHTMLand*composeonly with trusted or properly sanitized HTML. - Server responses used by
*fetch,*post, and*apiSHOULD be validated by the application before being rendered as trusted HTML.
16. Public contract versus internal behavior
Public runtime contract
- the
<serc-rod>host element - data initialization through
data %expr%interpolation with configured delimiters- documented directive names and aliases
- documented event and binding prefixes
- documented expression variables
- documented network trigger timing
- documented configuration keys
- documented runtime
CustomEventnames
Internal behavior unless documented elsewhere
- private helper names inside
dist/sercrod.js - exact internal state property names
- AST implementation details
- scheduling details beyond the update timing defined here
- undocumented event detail payload shape
- undocumented fallback behavior after expression errors
17. Open questions
The following behaviors need implementation tests or explicit design decisions before being elevated to stable contract:
- exact behavior when both
*lazyand*eagerare present - exact fallback value of
$parentat the root scope - exact merge-versus-replace behavior when
*fetchomits:prop - exact event
detailpayloads for network, upload, download, and WebSocket events - exact error handling and recovery behavior for failed expressions
- exact ordering when multiple side-effect or IO directives are present on the same element
- exact public support level for plain attribute interpolation
18. Minimum test matrix
Each normative section SHOULD have at least one test before the behavior is treated as hard public contract.
- host discovery for existing and dynamically inserted
<serc-rod>elements - template capture before first render
- JSON
dataparsing and expression fallback - text interpolation with default delimiters
*if,*elseif, and*elsebranch selection*foror*eachlocal scope behavior- nested host boundary behavior
- event handler scope with
$event,$e,el, and$el .updateand.noupdateevent modifier behavior*input,*lazy, and*eagerupdate timing- non-clickable initial
*fetch - clickable
*fetchtrigger behavior *apiwith*into- cleanup of window handlers or WebSocket resources on disconnect
- configuration override for delimiters and event prefix