Restructure specs into hierarchical sections, add "The Art Chain" essay
Specs nav reorganized from flat list into 6 sections with children: Core (5), Adapters (4), Browser (4), Reactive (1), Host Interface (3), Extensions (4). Added missing spec items: adapter-async, signals, boundary, forms, page-helpers, types. Architecture page updated to match. New essay on ars, techne, and the self-making artifact chain. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -95,7 +95,9 @@
|
||||
(dict :label "React is Hypermedia" :href "/etc/essays/react-is-hypermedia"
|
||||
:summary "A React Island is a hypermedia control. Its behavior is specified in SX.")
|
||||
(dict :label "The Hegelian Synthesis" :href "/etc/essays/hegelian-synthesis"
|
||||
:summary "On the dialectical resolution of the hypertext/reactive contradiction. Thesis: the server renders. Antithesis: the client reacts. Synthesis: the island in the lake.")))
|
||||
:summary "On the dialectical resolution of the hypertext/reactive contradiction. Thesis: the server renders. Antithesis: the client reacts. Synthesis: the island in the lake.")
|
||||
(dict :label "The Art Chain" :href "/etc/essays/the-art-chain"
|
||||
:summary "On making, self-making, and the chain of artifacts that produces itself. Ars, techne, content addressing, and why the spec is the art.")))
|
||||
|
||||
(define philosophy-nav-items (list
|
||||
(dict :label "The SX Manifesto" :href "/etc/philosophy/sx-manifesto"
|
||||
@@ -110,25 +112,33 @@
|
||||
:summary "Existence precedes essence — Sartre, Camus, and the absurd freedom of writing a Lisp for the web.")))
|
||||
|
||||
(define specs-nav-items (list
|
||||
(dict :label "Architecture" :href "/language/specs/")
|
||||
(dict :label "Core" :href "/language/specs/core")
|
||||
(dict :label "Parser" :href "/language/specs/parser")
|
||||
(dict :label "Evaluator" :href "/language/specs/evaluator")
|
||||
(dict :label "Primitives" :href "/language/specs/primitives")
|
||||
(dict :label "Special Forms" :href "/language/specs/special-forms")
|
||||
(dict :label "Renderer" :href "/language/specs/renderer")
|
||||
(dict :label "Adapters" :href "/language/specs/adapters")
|
||||
(dict :label "DOM Adapter" :href "/language/specs/adapter-dom")
|
||||
(dict :label "HTML Adapter" :href "/language/specs/adapter-html")
|
||||
(dict :label "SX Wire Adapter" :href "/language/specs/adapter-sx")
|
||||
(dict :label "Browser" :href "/language/specs/browser")
|
||||
(dict :label "SxEngine" :href "/language/specs/engine")
|
||||
(dict :label "Orchestration" :href "/language/specs/orchestration")
|
||||
(dict :label "Boot" :href "/language/specs/boot")
|
||||
(dict :label "Continuations" :href "/language/specs/continuations")
|
||||
(dict :label "call/cc" :href "/language/specs/callcc")
|
||||
(dict :label "Deps" :href "/language/specs/deps")
|
||||
(dict :label "Router" :href "/language/specs/router")))
|
||||
{:label "Core" :href "/language/specs/core" :children (list
|
||||
{:label "Parser" :href "/language/specs/parser"}
|
||||
{:label "Evaluator" :href "/language/specs/evaluator"}
|
||||
{:label "Primitives" :href "/language/specs/primitives"}
|
||||
{:label "Special Forms" :href "/language/specs/special-forms"}
|
||||
{:label "Renderer" :href "/language/specs/renderer"})}
|
||||
{:label "Adapters" :href "/language/specs/adapters" :children (list
|
||||
{:label "DOM Adapter" :href "/language/specs/adapter-dom"}
|
||||
{:label "HTML Adapter" :href "/language/specs/adapter-html"}
|
||||
{:label "SX Wire Adapter" :href "/language/specs/adapter-sx"}
|
||||
{:label "Async Adapter" :href "/language/specs/adapter-async"})}
|
||||
{:label "Browser" :href "/language/specs/browser" :children (list
|
||||
{:label "SxEngine" :href "/language/specs/engine"}
|
||||
{:label "Orchestration" :href "/language/specs/orchestration"}
|
||||
{:label "Boot" :href "/language/specs/boot"}
|
||||
{:label "Router" :href "/language/specs/router"})}
|
||||
{:label "Reactive" :href "/language/specs/reactive" :children (list
|
||||
{:label "Signals" :href "/language/specs/signals"})}
|
||||
{:label "Host Interface" :href "/language/specs/host" :children (list
|
||||
{:label "Boundary" :href "/language/specs/boundary"}
|
||||
{:label "Forms" :href "/language/specs/forms"}
|
||||
{:label "Page Helpers" :href "/language/specs/page-helpers"})}
|
||||
{:label "Extensions" :href "/language/specs/extensions" :children (list
|
||||
{:label "Continuations" :href "/language/specs/continuations"}
|
||||
{:label "call/cc" :href "/language/specs/callcc"}
|
||||
{:label "Types" :href "/language/specs/types"}
|
||||
{:label "Deps" :href "/language/specs/deps"})}))
|
||||
|
||||
(define testing-nav-items (list
|
||||
(dict :label "Overview" :href "/language/testing/")
|
||||
@@ -260,17 +270,39 @@
|
||||
(dict :slug "adapter-sx" :filename "adapter-sx.sx" :title "SX Wire Adapter"
|
||||
:desc "Serializes SX for client-side rendering. Component calls stay unexpanded."
|
||||
:prose "The SX wire adapter serializes expressions as SX source text for transmission to the browser, where sx.js renders them client-side. Unlike the HTML adapter, component calls (~name ...) are NOT expanded — they are sent to the client as-is, allowing the browser to render them with its local component registry. HTML tags ARE serialized as s-expression source. This is the format used for SX-over-HTTP responses and the page boot payload.")
|
||||
(dict :slug "adapter-async" :filename "adapter-async.sx" :title "Async Adapter"
|
||||
:desc "Async versions of HTML and SX wire adapters for server-side rendering with I/O."
|
||||
:prose "The async adapter provides async-aware versions of the HTML and SX wire rendering functions. It intercepts I/O operations (database queries, service calls, fragment fetches) during evaluation, awaiting them before continuing. Entry points: async-render (HTML output with awaited I/O), async-aser (SX wire format with awaited I/O). The bootstrapper emits async def and automatic await insertion for all define-async functions. This adapter is what makes server-side SX pages work with real data.")))
|
||||
|
||||
(define browser-spec-items (list
|
||||
(dict :slug "engine" :filename "engine.sx" :title "SxEngine"
|
||||
:desc "Pure logic for fetch, swap, history, SSE, triggers, morph, and indicators."
|
||||
:prose "The engine specifies the pure logic of the browser-side fetch/swap/history system. Like HTMX but native to SX. It defines trigger parsing (click, submit, intersect, poll, load, revealed), swap algorithms (innerHTML, outerHTML, morph, beforebegin, etc.), the morph/diff algorithm for patching existing DOM, history management (push-url, replace-url, popstate), out-of-band swap identification, Server-Sent Events parsing, retry logic with exponential backoff, request header building, response header processing, and optimistic UI updates. This file contains no browser API calls — all platform interaction is in orchestration.sx.")
|
||||
(dict :slug "orchestration" :filename "orchestration.sx" :title "Orchestration"
|
||||
:desc "Browser wiring that binds engine logic to DOM events, fetch, and lifecycle."
|
||||
:prose "Orchestration is the browser wiring layer. It binds the pure engine logic to actual browser APIs: DOM event listeners, fetch(), AbortController, setTimeout/setInterval, IntersectionObserver, history.pushState, and EventSource (SSE). It implements the full request lifecycle — from trigger through fetch through swap — including CSS tracking, response type detection (SX vs HTML), OOB swap processing, script activation, element boosting, and preload. Dependency is strictly one-way: orchestration depends on engine, never the reverse.")))
|
||||
|
||||
(define browser-spec-items (list
|
||||
(dict :slug "boot" :filename "boot.sx" :title "Boot"
|
||||
:prose "Orchestration is the browser wiring layer. It binds the pure engine logic to actual browser APIs: DOM event listeners, fetch(), AbortController, setTimeout/setInterval, IntersectionObserver, history.pushState, and EventSource (SSE). It implements the full request lifecycle — from trigger through fetch through swap — including CSS tracking, response type detection (SX vs HTML), OOB swap processing, script activation, element boosting, and preload. Dependency is strictly one-way: orchestration depends on engine, never the reverse.")
|
||||
(dict :slug "boot" :filename "boot.sx" :title "Boot"
|
||||
:desc "Browser startup lifecycle: mount, hydrate, script processing."
|
||||
:prose "Boot handles the browser startup sequence and provides the public API for mounting SX content. On page load it: (1) initializes CSS tracking, (2) processes <script type=\"text/sx\"> tags (component definitions and mount directives), (3) hydrates [data-sx] elements, and (4) activates the engine on all elements. It also provides the public mount/hydrate/update/render-component API, and the head element hoisting logic that moves <meta>, <title>, and <link> tags from rendered content into <head>.")))
|
||||
:prose "Boot handles the browser startup sequence and provides the public API for mounting SX content. On page load it: (1) initializes CSS tracking, (2) processes <script type=\"text/sx\"> tags (component definitions and mount directives), (3) hydrates [data-sx] elements, and (4) activates the engine on all elements. It also provides the public mount/hydrate/update/render-component API, and the head element hoisting logic that moves <meta>, <title>, and <link> tags from rendered content into <head>.")
|
||||
(dict :slug "router" :filename "router.sx" :title "Router"
|
||||
:desc "Client-side route matching — Flask-style pattern parsing, segment matching, route table search."
|
||||
:prose "The router module provides pure functions for matching URL paths against Flask-style route patterns (e.g. /docs/<slug>). Used by client-side routing to determine if a page can be rendered locally without a server roundtrip. split-path-segments breaks a path into segments, parse-route-pattern converts patterns into typed segment descriptors, match-route-segments tests a path against a parsed pattern returning extracted params, and find-matching-route searches a route table for the first match.")))
|
||||
|
||||
(define reactive-spec-items (list
|
||||
(dict :slug "signals" :filename "signals.sx" :title "Signals"
|
||||
:desc "Fine-grained reactive primitives — signal, computed, effect, batch."
|
||||
:prose "The signals module defines a fine-grained reactive system for client-side islands. Signals are containers for values that notify subscribers on change. Computed signals derive values lazily from other signals. Effects run side-effects when their dependencies change, with automatic cleanup. Batch coalesces multiple signal writes into a single notification pass. Island scope management ensures all signals, computeds, and effects are cleaned up when an island is removed from the DOM. The spec defines the reactive graph topology and update algorithm — each platform implements the actual signal/tracking types natively.")))
|
||||
|
||||
(define host-spec-items (list
|
||||
(dict :slug "boundary" :filename "boundary.sx" :title "Boundary"
|
||||
:desc "Language boundary contract — declares I/O primitives the host must provide."
|
||||
:prose "The boundary defines the contract between SX and its host environment. Tier 1 declares pure primitives (from primitives.sx). Tier 2 declares async I/O primitives the host must implement: fetch, async-eval, call-action, send-activity, and other operations that require network or database access. Tier 3 declares page helpers: format, highlight, scan-css-classes, parse-datetime. This is the interface every host must satisfy to run SX — framework-agnostic, universal to all targets. Boundary enforcement validates at registration time that all declared primitives are provided.")
|
||||
(dict :slug "forms" :filename "forms.sx" :title "Forms"
|
||||
:desc "Server-side definition forms — defhandler, defquery, defaction, defpage."
|
||||
:prose "Forms defines the server-side definition macros that compose the application layer. defhandler registers an HTTP route handler. defquery defines a read-only data source. defaction defines a mutation (write). defpage declares a client-routable page with path, auth, layout, data dependencies, and content. Each form parses &key parameter lists and creates typed definition objects. Platform-specific constructors are provided by the host — these have different bindings on server (Python/Quart) vs client (route matching only).")
|
||||
(dict :slug "page-helpers" :filename "page-helpers.sx" :title "Page Helpers"
|
||||
:desc "Pure data-transformation helpers for page rendering."
|
||||
:prose "Page helpers are pure functions that assist page rendering: categorizing special forms by type, formatting numbers and dates, highlighting code, scanning CSS classes, constructing page titles and descriptions. Unlike boundary I/O primitives, these are pure — they take data and return data with no side effects. They run identically on server and client. The host registers native implementations that match these declarations.")))
|
||||
|
||||
(define extension-spec-items (list
|
||||
(dict :slug "continuations" :filename "continuations.sx" :title "Continuations"
|
||||
@@ -278,17 +310,15 @@
|
||||
:prose "Delimited continuations capture the rest of a computation up to a delimiter. shift captures the continuation to the nearest reset as a first-class callable value. Unlike full call/cc, delimited continuations are composable — invoking one returns a value. This covers the practical use cases: suspendable server rendering, cooperative scheduling, linear async flows, wizard-style multi-step UIs, and undo. Each bootstrapper target implements the mechanism differently — generators in Python/JS, native shift/reset in Scheme, ContT in Haskell, CPS transform in Rust — but the semantics are identical. Optional extension: code that doesn't use continuations pays zero cost.")
|
||||
(dict :slug "callcc" :filename "callcc.sx" :title "call/cc"
|
||||
:desc "Full first-class continuations — call-with-current-continuation."
|
||||
:prose "Full call/cc captures the entire remaining computation as a first-class function — not just up to a delimiter, but all the way to the top level. Invoking the continuation abandons the current computation entirely and resumes from where it was captured. Strictly more powerful than delimited continuations, but harder to implement in targets that don't support it natively. Recommended for Scheme and Haskell targets where it's natural. Python, JavaScript, and Rust targets should prefer delimited continuations (continuations.sx) unless full escape semantics are genuinely needed. Optional extension: the continuation type is shared with continuations.sx if both are loaded.")))
|
||||
|
||||
(define module-spec-items (list
|
||||
:prose "Full call/cc captures the entire remaining computation as a first-class function — not just up to a delimiter, but all the way to the top level. Invoking the continuation abandons the current computation entirely and resumes from where it was captured. Strictly more powerful than delimited continuations, but harder to implement in targets that don't support it natively. Recommended for Scheme and Haskell targets where it's natural. Python, JavaScript, and Rust targets should prefer delimited continuations (continuations.sx) unless full escape semantics are genuinely needed. Optional extension: the continuation type is shared with continuations.sx if both are loaded.")
|
||||
(dict :slug "types" :filename "types.sx" :title "Types"
|
||||
:desc "Gradual type system — registration-time checking with zero runtime cost."
|
||||
:prose "The types module defines a gradual type system for SX. Type annotations on function parameters and return values are checked at registration time (when defcomp or define is evaluated), not at every call site. Base types include number, string, boolean, nil, symbol, keyword, element, any, and never. Union types (string|nil), function types, and type narrowing through control flow are supported. The system catches composition errors and boundary mismatches at definition time without any runtime overhead — unannotated code is unaffected.")
|
||||
(dict :slug "deps" :filename "deps.sx" :title "Deps"
|
||||
:desc "Component dependency analysis and IO detection — per-page bundling, transitive closure, CSS scoping, pure/IO classification."
|
||||
:prose "The deps module analyzes component dependency graphs and classifies components as pure or IO-dependent. Phase 1 (bundling): walks component AST bodies to find transitive ~component references, computes the minimal set needed per page, and collects per-page CSS classes from only the used components. Phase 2 (IO detection): scans component ASTs for references to IO primitive names (from boundary.sx declarations — frag, query, service, current-user, highlight, etc.), computes transitive IO refs through the component graph, and caches the result on each component. Components with no transitive IO refs are pure — they can render anywhere without server data. IO-dependent components must expand server-side. The spec provides the classification; each host's async partial evaluator acts on it (expand IO-dependent server-side, serialize pure for client). All functions are pure — each host bootstraps them to native code via --spec-modules deps. Platform functions (component-deps, component-set-deps!, component-css-classes, component-io-refs, component-set-io-refs!, env-components, regex-find-all, scan-css-classes) are implemented natively per target.")
|
||||
(dict :slug "router" :filename "router.sx" :title "Router"
|
||||
:desc "Client-side route matching — Flask-style pattern parsing, segment matching, route table search."
|
||||
:prose "The router module provides pure functions for matching URL paths against Flask-style route patterns (e.g. /docs/<slug>). Used by client-side routing (Phase 3) to determine if a page can be rendered locally without a server roundtrip. split-path-segments breaks a path into segments, parse-route-pattern converts patterns into typed segment descriptors, match-route-segments tests a path against a parsed pattern returning extracted params, and find-matching-route searches a route table for the first match. No platform interface needed — uses only pure string and list primitives. Bootstrapped via --spec-modules deps,router.")))
|
||||
:desc "Component dependency analysis and IO detection — per-page bundling, transitive closure, CSS scoping."
|
||||
:prose "The deps module analyzes component dependency graphs and classifies components as pure or IO-dependent. Phase 1 (bundling): walks component AST bodies to find transitive ~component references, computes the minimal set needed per page, and collects per-page CSS classes from only the used components. Phase 2 (IO detection): scans component ASTs for references to IO primitive names (from boundary.sx declarations), computes transitive IO refs through the component graph, and caches the result. Components with no transitive IO refs are pure — they can render anywhere without server data. IO-dependent components must expand server-side.")))
|
||||
|
||||
(define all-spec-items (concat core-spec-items (concat adapter-spec-items (concat browser-spec-items (concat extension-spec-items module-spec-items)))))
|
||||
(define all-spec-items (concat core-spec-items (concat adapter-spec-items (concat browser-spec-items (concat reactive-spec-items (concat host-spec-items extension-spec-items))))))
|
||||
|
||||
(define find-spec
|
||||
(fn (slug)
|
||||
|
||||
Reference in New Issue
Block a user