246 lines
23 KiB
Plaintext
246 lines
23 KiB
Plaintext
;; Navigation data and section-nav component for sx docs.
|
|
;; Replaces Python nav tuples from content/pages.py and _nav_items_sx() from utils.py.
|
|
;; @css aria-selected:bg-violet-200 aria-selected:text-violet-900
|
|
|
|
(define docs-nav-items (list
|
|
(dict :label "Introduction" :href "/docs/introduction")
|
|
(dict :label "Getting Started" :href "/docs/getting-started")
|
|
(dict :label "Components" :href "/docs/components")
|
|
(dict :label "Evaluator" :href "/docs/evaluator")
|
|
(dict :label "Primitives" :href "/docs/primitives")
|
|
(dict :label "Special Forms" :href "/docs/special-forms")
|
|
(dict :label "CSS" :href "/docs/css")
|
|
(dict :label "Server Rendering" :href "/docs/server-rendering")))
|
|
|
|
(define reference-nav-items (list
|
|
(dict :label "Attributes" :href "/reference/attributes")
|
|
(dict :label "Headers" :href "/reference/headers")
|
|
(dict :label "Events" :href "/reference/events")
|
|
(dict :label "JS API" :href "/reference/js-api")))
|
|
|
|
(define protocols-nav-items (list
|
|
(dict :label "Wire Format" :href "/protocols/wire-format")
|
|
(dict :label "Fragments" :href "/protocols/fragments")
|
|
(dict :label "Resolver I/O" :href "/protocols/resolver-io")
|
|
(dict :label "Internal Services" :href "/protocols/internal-services")
|
|
(dict :label "ActivityPub" :href "/protocols/activitypub")
|
|
(dict :label "Future" :href "/protocols/future")))
|
|
|
|
(define examples-nav-items (list
|
|
(dict :label "Click to Load" :href "/examples/click-to-load")
|
|
(dict :label "Form Submission" :href "/examples/form-submission")
|
|
(dict :label "Polling" :href "/examples/polling")
|
|
(dict :label "Delete Row" :href "/examples/delete-row")
|
|
(dict :label "Inline Edit" :href "/examples/inline-edit")
|
|
(dict :label "OOB Swaps" :href "/examples/oob-swaps")
|
|
(dict :label "Lazy Loading" :href "/examples/lazy-loading")
|
|
(dict :label "Infinite Scroll" :href "/examples/infinite-scroll")
|
|
(dict :label "Progress Bar" :href "/examples/progress-bar")
|
|
(dict :label "Active Search" :href "/examples/active-search")
|
|
(dict :label "Inline Validation" :href "/examples/inline-validation")
|
|
(dict :label "Value Select" :href "/examples/value-select")
|
|
(dict :label "Reset on Submit" :href "/examples/reset-on-submit")
|
|
(dict :label "Edit Row" :href "/examples/edit-row")
|
|
(dict :label "Bulk Update" :href "/examples/bulk-update")
|
|
(dict :label "Swap Positions" :href "/examples/swap-positions")
|
|
(dict :label "Select Filter" :href "/examples/select-filter")
|
|
(dict :label "Tabs" :href "/examples/tabs")
|
|
(dict :label "Animations" :href "/examples/animations")
|
|
(dict :label "Dialogs" :href "/examples/dialogs")
|
|
(dict :label "Keyboard Shortcuts" :href "/examples/keyboard-shortcuts")
|
|
(dict :label "PUT / PATCH" :href "/examples/put-patch")
|
|
(dict :label "JSON Encoding" :href "/examples/json-encoding")
|
|
(dict :label "Vals & Headers" :href "/examples/vals-and-headers")
|
|
(dict :label "Loading States" :href "/examples/loading-states")
|
|
(dict :label "Request Abort" :href "/examples/sync-replace")
|
|
(dict :label "Retry" :href "/examples/retry")))
|
|
|
|
(define essays-nav-items (list
|
|
(dict :label "Why S-Expressions" :href "/essays/why-sexps"
|
|
:summary "Why SX uses s-expressions instead of HTML templates, JSX, or any other syntax.")
|
|
(dict :label "The htmx/React Hybrid" :href "/essays/htmx-react-hybrid"
|
|
:summary "How SX combines the server-driven simplicity of htmx with the component model of React.")
|
|
(dict :label "On-Demand CSS" :href "/essays/on-demand-css"
|
|
:summary "The CSSX system: keyword atoms resolved to class names, CSS rules injected on first use.")
|
|
(dict :label "Client Reactivity" :href "/essays/client-reactivity"
|
|
:summary "Reactive UI updates without a virtual DOM, diffing library, or build step.")
|
|
(dict :label "SX Native" :href "/essays/sx-native"
|
|
:summary "Extending SX beyond the browser — native desktop and mobile rendering from the same source.")
|
|
(dict :label "The SX Manifesto" :href "/essays/sx-manifesto"
|
|
:summary "The design principles behind SX: simplicity, self-hosting, and s-expressions all the way down.")
|
|
(dict :label "Tail-Call Optimization" :href "/essays/tail-call-optimization"
|
|
:summary "How SX implements proper tail calls via trampolining in a language that doesn't have them.")
|
|
(dict :label "Continuations" :href "/essays/continuations"
|
|
:summary "First-class continuations in a tree-walking evaluator — theory and implementation.")
|
|
(dict :label "Strange Loops" :href "/essays/godel-escher-bach"
|
|
:summary "Self-reference, and the tangled hierarchy of a language that defines itself.")
|
|
(dict :label "The Reflexive Web" :href "/essays/reflexive-web"
|
|
:summary "A web where pages can inspect, modify, and extend their own rendering pipeline.")
|
|
(dict :label "Server Architecture" :href "/essays/server-architecture"
|
|
:summary "How SX enforces the boundary between host and embedded language, and what it looks like across targets.")
|
|
(dict :label "Separation of Concerns" :href "/essays/separation-of-concerns"
|
|
:summary "The web's HTML/CSS/JS split separates the framework's concerns, not your application's. Real separation is domain-specific.")
|
|
(dict :label "SX and AI" :href "/essays/sx-and-ai"
|
|
:summary "Why s-expressions are the most AI-friendly representation for web interfaces.")
|
|
(dict :label "There Is No Alternative" :href "/essays/no-alternative"
|
|
:summary "Every attempt to escape s-expressions leads back to s-expressions. This is not an accident.")
|
|
(dict :label "sx sucks" :href "/essays/sx-sucks"
|
|
:summary "An honest accounting of everything wrong with SX and why you probably shouldn't use it.")))
|
|
|
|
(define specs-nav-items (list
|
|
(dict :label "Architecture" :href "/specs/")
|
|
(dict :label "Core" :href "/specs/core")
|
|
(dict :label "Parser" :href "/specs/parser")
|
|
(dict :label "Evaluator" :href "/specs/evaluator")
|
|
(dict :label "Primitives" :href "/specs/primitives")
|
|
(dict :label "Special Forms" :href "/specs/special-forms")
|
|
(dict :label "Renderer" :href "/specs/renderer")
|
|
(dict :label "Adapters" :href "/specs/adapters")
|
|
(dict :label "DOM Adapter" :href "/specs/adapter-dom")
|
|
(dict :label "HTML Adapter" :href "/specs/adapter-html")
|
|
(dict :label "SX Wire Adapter" :href "/specs/adapter-sx")
|
|
(dict :label "Browser" :href "/specs/browser")
|
|
(dict :label "SxEngine" :href "/specs/engine")
|
|
(dict :label "Orchestration" :href "/specs/orchestration")
|
|
(dict :label "Boot" :href "/specs/boot")
|
|
(dict :label "CSSX" :href "/specs/cssx")
|
|
(dict :label "Continuations" :href "/specs/continuations")
|
|
(dict :label "call/cc" :href "/specs/callcc")
|
|
(dict :label "Deps" :href "/specs/deps")
|
|
(dict :label "Router" :href "/specs/router")))
|
|
|
|
(define testing-nav-items (list
|
|
(dict :label "Overview" :href "/testing/")
|
|
(dict :label "Evaluator" :href "/testing/eval")
|
|
(dict :label "Parser" :href "/testing/parser")
|
|
(dict :label "Router" :href "/testing/router")
|
|
(dict :label "Renderer" :href "/testing/render")
|
|
(dict :label "Dependencies" :href "/testing/deps")
|
|
(dict :label "Engine" :href "/testing/engine")
|
|
(dict :label "Runners" :href "/testing/runners")))
|
|
|
|
(define isomorphism-nav-items (list
|
|
(dict :label "Roadmap" :href "/isomorphism/")
|
|
(dict :label "Bundle Analyzer" :href "/isomorphism/bundle-analyzer")
|
|
(dict :label "Routing Analyzer" :href "/isomorphism/routing-analyzer")
|
|
(dict :label "Data Test" :href "/isomorphism/data-test")
|
|
(dict :label "Async IO" :href "/isomorphism/async-io")
|
|
(dict :label "Streaming" :href "/isomorphism/streaming")))
|
|
|
|
(define plans-nav-items (list
|
|
(dict :label "Status" :href "/plans/status"
|
|
:summary "Audit of all plans — what's done, what's in progress, and what remains.")
|
|
(dict :label "Reader Macros" :href "/plans/reader-macros"
|
|
:summary "Extensible parse-time transformations via # dispatch — datum comments, raw strings, and quote shorthand.")
|
|
(dict :label "SX-Activity" :href "/plans/sx-activity"
|
|
:summary "A new web built on SX — executable content, shared components, parsers, and logic on IPFS, provenance on Bitcoin, all running within your own security context.")
|
|
(dict :label "Predictive Prefetching" :href "/plans/predictive-prefetch"
|
|
:summary "Prefetch missing component definitions before the user clicks — hover a link, fetch its deps, navigate client-side.")
|
|
(dict :label "Content-Addressed Components" :href "/plans/content-addressed-components"
|
|
:summary "Components identified by CID, stored on IPFS, fetched from anywhere. Canonical serialization, content verification, federated sharing.")
|
|
(dict :label "Fragment Protocol" :href "/plans/fragment-protocol"
|
|
:summary "Structured sexp request/response for cross-service component transfer.")
|
|
(dict :label "Glue Decoupling" :href "/plans/glue-decoupling"
|
|
:summary "Eliminate all cross-app model imports via glue service layer.")
|
|
(dict :label "Social Sharing" :href "/plans/social-sharing"
|
|
:summary "OAuth-based sharing to Facebook, Instagram, Threads, Twitter/X, LinkedIn, and Mastodon.")
|
|
(dict :label "SX CI Pipeline" :href "/plans/sx-ci"
|
|
:summary "Build, test, and deploy in s-expressions — CI pipelines as SX components.")))
|
|
|
|
(define bootstrappers-nav-items (list
|
|
(dict :label "Overview" :href "/bootstrappers/")
|
|
(dict :label "JavaScript" :href "/bootstrappers/javascript")
|
|
(dict :label "Python" :href "/bootstrappers/python")))
|
|
|
|
;; Spec file registry — canonical metadata for spec viewer pages.
|
|
;; Python only handles file I/O (read-spec-file); all metadata lives here.
|
|
;; The :prose field is an English-language description shown alongside the
|
|
;; canonical s-expression source.
|
|
|
|
(define core-spec-items (list
|
|
(dict :slug "parser" :filename "parser.sx" :title "Parser"
|
|
:desc "Tokenization and parsing of SX source text into AST."
|
|
:prose "The parser converts SX source text into an abstract syntax tree. It tokenizes the input into atoms, strings, numbers, keywords, and delimiters, then assembles them into nested list structures. The parser is intentionally minimal — s-expressions need very little syntax to parse. Special reader macros handle quasiquote (\\`), unquote (~), splice (~@), and the quote (') shorthand. The output is a tree of plain lists, symbols, keywords, strings, and numbers that the evaluator can walk directly.")
|
|
(dict :slug "evaluator" :filename "eval.sx" :title "Evaluator"
|
|
:desc "Tree-walking evaluation of SX expressions."
|
|
:prose "The evaluator walks the AST produced by the parser and reduces it to values. It implements lexical scoping with closures, special forms (define, let, if, cond, fn, defcomp, defmacro, quasiquote, set!, do), and function application. Macros are expanded at eval time. Component definitions (defcomp) create callable component objects that participate in the rendering pipeline. The evaluator delegates rendering expressions — HTML tags, components, fragments — to whichever adapter is active, making the same source renderable to DOM nodes, HTML strings, or SX wire format.")
|
|
(dict :slug "primitives" :filename "primitives.sx" :title "Primitives"
|
|
:desc "All built-in pure functions and their signatures."
|
|
:prose "Primitives are the built-in functions available in every SX environment. Each entry declares a name, parameter signature, and semantics. Bootstrap compilers implement these natively per target (JavaScript, Python, etc.). The registry covers arithmetic, comparison, string manipulation, list operations, dict operations, type predicates, and control flow helpers. All primitives are pure — they take values and return values with no side effects. Platform-specific operations (DOM access, HTTP, file I/O) are provided separately via platform bridge functions, not primitives.")
|
|
(dict :slug "special-forms" :filename "special-forms.sx" :title "Special Forms"
|
|
:desc "All special forms — syntactic constructs with custom evaluation rules."
|
|
:prose "Special forms are the syntactic constructs whose arguments are NOT evaluated before dispatch. Each form has its own evaluation rules — unlike primitives, which receive pre-evaluated values. Together with primitives, special forms define the complete language surface. The registry covers control flow (if, when, cond, case, and, or), binding (let, letrec, define, set!), functions (lambda, defcomp, defmacro), sequencing (begin, do, thread-first), quoting (quote, quasiquote), continuations (reset, shift), guards (dynamic-wind), higher-order forms (map, filter, reduce), and domain-specific definitions (defstyle, defhandler, defpage, defquery, defaction).")
|
|
(dict :slug "renderer" :filename "render.sx" :title "Renderer"
|
|
:desc "Shared rendering registries and utilities used by all adapters."
|
|
:prose "The renderer defines what is renderable and how arguments are parsed, but not the output format. It maintains registries of known HTML tags, SVG tags, void elements, and boolean attributes. It specifies how keyword arguments on elements become HTML attributes, how children are collected, and how special attributes (class, style, data-*) are handled. All three adapters (DOM, HTML, SX wire) share these definitions so they agree on what constitutes valid markup. The renderer also defines the StyleValue type used by the CSSX on-demand CSS system.")))
|
|
|
|
(define adapter-spec-items (list
|
|
(dict :slug "adapter-dom" :filename "adapter-dom.sx" :title "DOM Adapter"
|
|
:desc "Renders SX expressions to live DOM nodes. Browser-only."
|
|
:prose "The DOM adapter renders evaluated SX expressions into live browser DOM nodes — Elements, Text nodes, and DocumentFragments. It mirrors the HTML adapter's logic but produces DOM objects instead of strings. This is the adapter used by the browser-side SX runtime for initial mount, hydration, and dynamic updates. It handles element creation, attribute setting (including event handlers and style objects), SVG namespace handling, and fragment composition.")
|
|
(dict :slug "adapter-html" :filename "adapter-html.sx" :title "HTML Adapter"
|
|
:desc "Renders SX expressions to HTML strings. Server-side."
|
|
:prose "The HTML adapter renders evaluated SX expressions to HTML strings. It is used server-side to produce complete HTML pages and fragments. It handles void elements (self-closing tags like <br>, <img>), boolean attributes, style serialization, class merging, and proper escaping. The output is standard HTML5 that any browser can parse.")
|
|
(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 "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"
|
|
: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) loads the style dictionary from inline JSON, (3) processes <script type=\"text/sx\"> tags (component definitions and mount directives), (4) hydrates [data-sx] elements, and (5) 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 "cssx" :filename "cssx.sx" :title "CSSX"
|
|
:desc "On-demand CSS: style dictionary, keyword resolution, rule injection."
|
|
:prose "CSSX is the on-demand CSS system. It resolves keyword atoms (:flex, :gap-4, :hover:bg-sky-200) into StyleValue objects with content-addressed class names, injecting CSS rules into the document on first use. The style dictionary is a JSON blob containing: atoms (keyword to CSS declarations), pseudo-variants (hover:, focus:, etc.), responsive breakpoints (md:, lg:, etc.), keyframe animations, arbitrary value patterns, and child selector prefixes (space-x-, space-y-). Classes are only emitted when used, keeping the CSS payload minimal. The dictionary is typically served inline in a <script type=\"text/sx-styles\"> tag.")))
|
|
|
|
(define extension-spec-items (list
|
|
(dict :slug "continuations" :filename "continuations.sx" :title "Continuations"
|
|
:desc "Delimited continuations — shift/reset for suspendable rendering and cooperative scheduling."
|
|
: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
|
|
(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.")))
|
|
|
|
(define all-spec-items (concat core-spec-items (concat adapter-spec-items (concat browser-spec-items (concat extension-spec-items module-spec-items)))))
|
|
|
|
(define find-spec
|
|
(fn (slug)
|
|
(some (fn (item)
|
|
(when (= (get item "slug") slug) item))
|
|
all-spec-items)))
|
|
|
|
;; Find the current nav label for a slug by matching href suffix.
|
|
;; Returns the label string or nil if no match.
|
|
(define find-current
|
|
(fn (items slug)
|
|
(when slug
|
|
(some (fn (item)
|
|
(when (ends-with? (get item "href") slug)
|
|
(get item "label")))
|
|
items))))
|
|
|
|
;; Generic section nav — builds nav links from a list of items.
|
|
;; Replaces _nav_items_sx() and all section-specific nav builders in utils.py.
|
|
(defcomp ~section-nav (&key items current)
|
|
(<> (map (fn (item)
|
|
(~nav-link
|
|
:href (get item "href")
|
|
:label (get item "label")
|
|
:is-selected (when (= (get item "label") current) "true")
|
|
:select-colours "aria-selected:bg-violet-200 aria-selected:text-violet-900"))
|
|
items)))
|