Add :effects annotations to all spec files and update bootstrappers
Bootstrappers (bootstrap_py.py, js.sx) now skip :effects keyword in define forms, enabling effect annotations throughout the spec without changing generated output. Annotated 180+ functions across 14 spec files: - signals.sx: signal/deref [] pure, reset!/swap!/effect/batch [mutation] - engine.sx: parse-* [] pure, morph-*/swap-* [mutation io] - orchestration.sx: all [mutation io] (browser event binding) - adapter-html.sx: render-* [render] - adapter-dom.sx: render-* [render], reactive-* [render mutation] - adapter-sx.sx: aser-* [render] - adapter-async.sx: async-render-*/async-aser-* [render io] - parser.sx: all [] pure - render.sx: predicates [] pure, process-bindings [mutation] - boot.sx: all [mutation io] (browser init) - deps.sx: scan-*/transitive-* [] pure, compute-all-* [mutation] - router.sx: all [] pure (URL matching) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -31,7 +31,7 @@
|
||||
;; Parses the sx-trigger attribute value into a list of trigger descriptors.
|
||||
;; Each descriptor is a dict with "event" and "modifiers" keys.
|
||||
|
||||
(define parse-time
|
||||
(define parse-time :effects []
|
||||
(fn ((s :as string))
|
||||
;; Parse time string: "2s" → 2000, "500ms" → 500
|
||||
;; Uses nested if (not cond) because cond misclassifies 2-element
|
||||
@@ -42,7 +42,7 @@
|
||||
(parse-int s 0))))))
|
||||
|
||||
|
||||
(define parse-trigger-spec
|
||||
(define parse-trigger-spec :effects []
|
||||
(fn ((spec :as string))
|
||||
;; Parse "click delay:500ms once,change" → list of trigger descriptors
|
||||
(if (nil? spec)
|
||||
@@ -80,7 +80,7 @@
|
||||
raw-parts))))))
|
||||
|
||||
|
||||
(define default-trigger
|
||||
(define default-trigger :effects []
|
||||
(fn ((tag-name :as string))
|
||||
;; Default trigger for element type
|
||||
(cond
|
||||
@@ -98,7 +98,7 @@
|
||||
;; Verb extraction
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define get-verb-info
|
||||
(define get-verb-info :effects [io]
|
||||
(fn (el)
|
||||
;; Check element for sx-get, sx-post, etc. Returns (dict "method" "url") or nil.
|
||||
(some
|
||||
@@ -114,7 +114,7 @@
|
||||
;; Request header building
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define build-request-headers
|
||||
(define build-request-headers :effects [io]
|
||||
(fn (el (loaded-components :as list) (css-hash :as string))
|
||||
;; Build the SX request headers dict
|
||||
(let ((headers (dict
|
||||
@@ -150,7 +150,7 @@
|
||||
;; Response header processing
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define process-response-headers
|
||||
(define process-response-headers :effects []
|
||||
(fn ((get-header :as lambda))
|
||||
;; Extract all SX response header directives into a dict.
|
||||
;; get-header is (fn (name) → string or nil).
|
||||
@@ -174,7 +174,7 @@
|
||||
;; Swap specification parsing
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define parse-swap-spec
|
||||
(define parse-swap-spec :effects []
|
||||
(fn ((raw-swap :as string) (global-transitions? :as boolean))
|
||||
;; Parse "innerHTML transition:true" → dict with style + transition flag
|
||||
(let ((parts (split (or raw-swap DEFAULT_SWAP) " "))
|
||||
@@ -193,7 +193,7 @@
|
||||
;; Retry logic
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define parse-retry-spec
|
||||
(define parse-retry-spec :effects []
|
||||
(fn ((retry-attr :as string))
|
||||
;; Parse "exponential:1000:30000" → spec dict or nil
|
||||
(if (nil? retry-attr)
|
||||
@@ -205,7 +205,7 @@
|
||||
"cap-ms" (parse-int (nth parts 2) 30000))))))
|
||||
|
||||
|
||||
(define next-retry-ms
|
||||
(define next-retry-ms :effects []
|
||||
(fn ((current-ms :as number) (cap-ms :as number))
|
||||
;; Exponential backoff: double current, cap at max
|
||||
(min (* current-ms 2) cap-ms)))
|
||||
@@ -215,7 +215,7 @@
|
||||
;; Form parameter filtering
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define filter-params
|
||||
(define filter-params :effects []
|
||||
(fn ((params-spec :as string) (all-params :as list))
|
||||
;; Filter form parameters by sx-params spec.
|
||||
;; all-params is a list of (key value) pairs.
|
||||
@@ -239,7 +239,7 @@
|
||||
;; Target resolution
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define resolve-target
|
||||
(define resolve-target :effects [io]
|
||||
(fn (el)
|
||||
;; Resolve the swap target for an element
|
||||
(let ((sel (dom-get-attr el "sx-target")))
|
||||
@@ -253,7 +253,7 @@
|
||||
;; Optimistic updates
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define apply-optimistic
|
||||
(define apply-optimistic :effects [mutation io]
|
||||
(fn (el)
|
||||
;; Apply optimistic update preview. Returns state for reverting, or nil.
|
||||
(let ((directive (dom-get-attr el "sx-optimistic")))
|
||||
@@ -278,7 +278,7 @@
|
||||
state)))))
|
||||
|
||||
|
||||
(define revert-optimistic
|
||||
(define revert-optimistic :effects [mutation io]
|
||||
(fn ((state :as dict))
|
||||
;; Revert an optimistic update
|
||||
(when state
|
||||
@@ -299,7 +299,7 @@
|
||||
;; Out-of-band swap identification
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define find-oob-swaps
|
||||
(define find-oob-swaps :effects [mutation io]
|
||||
(fn (container)
|
||||
;; Find elements marked for out-of-band swapping.
|
||||
;; Returns list of (dict "element" el "swap-type" type "target-id" id).
|
||||
@@ -329,7 +329,7 @@
|
||||
;; preserving event listeners, focus, scroll position, and form state
|
||||
;; on keyed (id) elements.
|
||||
|
||||
(define morph-node
|
||||
(define morph-node :effects [mutation io]
|
||||
(fn (old-node new-node)
|
||||
;; Morph old-node to match new-node, preserving listeners/state.
|
||||
(cond
|
||||
@@ -371,7 +371,7 @@
|
||||
(morph-children old-node new-node))))))
|
||||
|
||||
|
||||
(define sync-attrs
|
||||
(define sync-attrs :effects [mutation io]
|
||||
(fn (old-el new-el)
|
||||
;; Sync attributes from new to old, but skip reactively managed attrs.
|
||||
;; data-sx-reactive-attrs="style,class" means those attrs are owned by
|
||||
@@ -398,7 +398,7 @@
|
||||
(dom-attr-list old-el)))))
|
||||
|
||||
|
||||
(define morph-children
|
||||
(define morph-children :effects [mutation io]
|
||||
(fn (old-parent new-parent)
|
||||
;; Reconcile children of old-parent to match new-parent.
|
||||
;; Keyed elements (with id) are matched and moved in-place.
|
||||
@@ -472,7 +472,7 @@
|
||||
;; - Lakes = server substance (content, morphed)
|
||||
;; - The morph = Aufhebung (cancellation/preservation/elevation of both)
|
||||
|
||||
(define morph-island-children
|
||||
(define morph-island-children :effects [mutation io]
|
||||
(fn (old-island new-island)
|
||||
;; Find all lake and marsh slots in both old and new islands
|
||||
(let ((old-lakes (dom-query-all old-island "[data-sx-lake]"))
|
||||
@@ -522,7 +522,7 @@
|
||||
;; as SX and rendered in the island's signal context. If the marsh has a
|
||||
;; :transform function, it reshapes the content before evaluation.
|
||||
|
||||
(define morph-marsh
|
||||
(define morph-marsh :effects [mutation io]
|
||||
(fn (old-marsh new-marsh island-el)
|
||||
(let ((transform (dom-get-data old-marsh "sx-marsh-transform"))
|
||||
(env (dom-get-data old-marsh "sx-marsh-env"))
|
||||
@@ -555,7 +555,7 @@
|
||||
;;
|
||||
;; Values are JSON-parsed: "7" → 7, "\"hello\"" → "hello", "true" → true.
|
||||
|
||||
(define process-signal-updates
|
||||
(define process-signal-updates :effects [mutation io]
|
||||
(fn (root)
|
||||
(let ((signal-els (dom-query-all root "[data-sx-signal]")))
|
||||
(for-each
|
||||
@@ -576,7 +576,7 @@
|
||||
;; Swap dispatch
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define swap-dom-nodes
|
||||
(define swap-dom-nodes :effects [mutation io]
|
||||
(fn (target new-nodes (strategy :as string))
|
||||
;; Execute a swap strategy on live DOM nodes.
|
||||
;; new-nodes is typically a DocumentFragment or Element.
|
||||
@@ -630,7 +630,7 @@
|
||||
(morph-children target wrapper))))))
|
||||
|
||||
|
||||
(define insert-remaining-siblings
|
||||
(define insert-remaining-siblings :effects [mutation io]
|
||||
(fn (parent ref-node sib)
|
||||
;; Insert sibling chain after ref-node
|
||||
(when sib
|
||||
@@ -643,7 +643,7 @@
|
||||
;; String-based swap (fallback for HTML responses)
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define swap-html-string
|
||||
(define swap-html-string :effects [mutation io]
|
||||
(fn (target (html :as string) (strategy :as string))
|
||||
;; Execute a swap strategy using an HTML string (DOMParser pipeline).
|
||||
(case strategy
|
||||
@@ -674,7 +674,7 @@
|
||||
;; History management
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define handle-history
|
||||
(define handle-history :effects [io]
|
||||
(fn (el (url :as string) (resp-headers :as dict))
|
||||
;; Process history push/replace based on element attrs and response headers
|
||||
(let ((push-url (dom-get-attr el "sx-push-url"))
|
||||
@@ -700,7 +700,7 @@
|
||||
|
||||
(define PRELOAD_TTL 30000) ;; 30 seconds
|
||||
|
||||
(define preload-cache-get
|
||||
(define preload-cache-get :effects [mutation]
|
||||
(fn ((cache :as dict) (url :as string))
|
||||
;; Get and consume a cached preload response.
|
||||
;; Returns (dict "text" ... "content-type" ...) or nil.
|
||||
@@ -712,7 +712,7 @@
|
||||
(do (dict-delete! cache url) entry))))))
|
||||
|
||||
|
||||
(define preload-cache-set
|
||||
(define preload-cache-set :effects [mutation]
|
||||
(fn ((cache :as dict) (url :as string) (text :as string) (content-type :as string))
|
||||
;; Store a preloaded response
|
||||
(dict-set! cache url
|
||||
@@ -725,7 +725,7 @@
|
||||
;; Maps trigger event names to binding strategies.
|
||||
;; This is the logic; actual browser event binding is platform interface.
|
||||
|
||||
(define classify-trigger
|
||||
(define classify-trigger :effects []
|
||||
(fn ((trigger :as dict))
|
||||
;; Classify a parsed trigger descriptor for binding.
|
||||
;; Returns one of: "poll", "intersect", "load", "revealed", "event"
|
||||
@@ -742,7 +742,7 @@
|
||||
;; Boost logic
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define should-boost-link?
|
||||
(define should-boost-link? :effects [io]
|
||||
(fn (link)
|
||||
;; Whether a link inside an sx-boost container should be boosted
|
||||
(let ((href (dom-get-attr link "href")))
|
||||
@@ -756,7 +756,7 @@
|
||||
(not (dom-has-attr? link "sx-disable"))))))
|
||||
|
||||
|
||||
(define should-boost-form?
|
||||
(define should-boost-form? :effects [io]
|
||||
(fn (form)
|
||||
;; Whether a form inside an sx-boost container should be boosted
|
||||
(and (not (dom-has-attr? form "sx-get"))
|
||||
@@ -768,7 +768,7 @@
|
||||
;; SSE event classification
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define parse-sse-swap
|
||||
(define parse-sse-swap :effects [io]
|
||||
(fn (el)
|
||||
;; Parse sx-sse-swap attribute
|
||||
;; Returns event name to listen for (default "message")
|
||||
|
||||
Reference in New Issue
Block a user