Directive Parsing
The order in which RJS's #SET_DOM applies directives while walking a template, and what each directive (:path, :for, :if, :model, :[attr], @[event]) does.
Directive Parsing Order
#SET_DOM walks each child element and applies directives in a fixed order. :path- and :for-tagged nodes short-circuit into their own handlers and skip the rest of the pipeline for that node:
graph TB
Node["child element"] --> PathCheck{":path attr?"}
PathCheck -->|yes| SetPath["#setPath: fetch fragment, inline it, return"]
PathCheck -->|no| ForCheck{":for attr?"}
ForCheck -->|yes| FitFor["#FIT_FOR: expand loop, return"]
ForCheck -->|no| SetIf["#setIf: :if / :else-if / :else"]
SetIf --> FitModel["#FIT_MODEL: two-way form binding"]
FitModel --> FitAttr["#FIT_ATTRIBUTE: :[attr] / :[css]"]
FitAttr --> FitEvent["#FIT_EVENT: @[event]"]
FitEvent --> FitText["#FIT_TEXT: {{ }} interpolation"]
FitText --> Recurse["#SET_DOM(child) — recurse into grandchildren"]
Elements whose visibility is still pending (:else-if/:el-if/:else siblings not yet resolved by #setIf) are skipped on this pass; #setIf re-invokes #SET_DOM on the parent once it has removed the losing branches.
Directive Behavior
:path — async fragment loading
Applies only to elements carrying a :path attribute. #setPath fetches the target URL, injects the returned HTML as child nodes, and re-runs #SET_DOM on the fragment (unless the fragment contains a new PD construction, in which case it's left untouched). Script tags found in the fragment are moved to the end of document.body and executed; everything else is unwrapped in place, and the original placeholder node is removed. A fetch failure also removes the node.
:for — loop expansion
Supports three forms: item in items, (item, index) in items, and (key, value) in object. #FIT_FOR clones the template node once per array entry (or object key), binds subItem = { [val0]: item, [val1]: index } (or { [val0]: key, [val1]: value }), and renders each clone's attributes/events/text before inserting the batch back where the original node stood. Nested-object items get a full recursive #SET_DOM pass; primitive items only get attribute/event/text substitution.
:if / :else-if / :el-if / :else
#setIf collects the :if node and any immediately-following :else-if/:el-if/:else siblings into one group, evaluates each condition in order, and removes every node except the first one that matches (later matches in the group are removed even if their own condition is true). Supported operators: >, <, >=/>==, <=/<==, ==/===, !=/!==. ==/!= special-case the literals null, true, false, and empty (empty-string check) before falling back to string equality.
:model — two-way form binding
#FIT_MODEL inspects the bound element's type: checkbox/radio inputs listen on change and join all checked values with ,; select listens on change; plain input/textarea listen on both keyup and change. In every case the handler writes straight into the data object passed to that render pass — there is no observer or reactive re-render triggered by the write.
:[attr] / :[css] — attribute and style binding
#FIT_ATTRIBUTE collects every attribute matching /^:[\w\-]+$/ (excluding the directive names above), resolves its value through #GET_VALUE, and hands it to #SET_ATTRIBUTE. :class calls _class() (see Element Extensions); :id/:src/:alt/:href/:html map directly onto the matching DOM property; any other camel-cased key that exists on element.style is treated as a CSS property; everything else becomes a plain HTML attribute (or is removed if the resolved value is empty).
@[event] — event binding
#FIT_EVENT matches attributes like /^@[\w]+$/, rewrites @click to onclick, and looks up the handler name in this.event. Inside a :for loop, the handler name can itself be a per-item value (resolved through the same key-path lookup used for {{ }} interpolation) rather than a fixed method name.