Commit Graph

812 Commits

Author SHA1 Message Date
aef990735f Add provide/emit! geography article, update spreads article, fix foundations rendering
- New geography article (provide.sx): four primitives, demos, nested scoping,
  adapter comparison, spec explorer links
- Updated spreads article section VI: provide/emit! is now implemented, not planned
- Fixed foundations.sx: ~docs/code-block → ~docs/code (undefined component
  was causing the page to silently fail to render)
- Added nav entry and defpage route for provide/emit! article

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 16:04:52 +00:00
04d3b2ecaf Use separate CI build directory to avoid clobbering dev working tree
CI was doing git reset --hard on /root/rose-ash (the dev directory),
flipping the checked-out branch and causing empty diffs when merging.
Now builds in /root/rose-ash-ci and uses push event SHAs for diffing.
Also adds --resolve-image always to stack deploys.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 15:42:00 +00:00
c4a999d0d0 Merge branch 'worktree-api-urls' into macros 2026-03-13 15:41:40 +00:00
2de4ba8c57 Refactor spread to use provide/emit! internally
Spreads now emit their attrs into the nearest element's provide scope
instead of requiring per-child spread? checks at every intermediate
layer. emit! is tolerant (no-op when no provider), so spreads in
non-element contexts silently vanish.

- adapter-html: element/lake/marsh wrap children in provide, collect
  emitted; removed 14 spread filters from fragment, forms, components
- adapter-sx: aser wraps result to catch spread values from fn calls;
  aser-call uses provide with attr-parts/child-parts ordering
- adapter-async: same pattern for both render and aser paths
- adapter-dom: added emit! in spread dispatch + provide in element
  rendering; kept spread? checks for reactive/island and DOM safety
- platform: emit! returns NIL when no provider instead of erroring
- 3 new aser tests: stored spread, nested element, silent drop

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 15:41:32 +00:00
ee969a343c Merge branch 'macros'
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m58s
2026-03-13 12:41:09 +00:00
400d6d4086 Merge branch 'worktree-api-urls' into macros 2026-03-13 12:20:27 +00:00
dbf16929fa Merge branch 'worktree-api-urls'
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
2026-03-13 12:20:22 +00:00
859aad4333 Fix spread serialization in aser/async-aser wire format
Spread values from make-spread were crashing the wire format serializer:
- serialize() had no "spread" case, fell through to (str val) producing
  Python repr "<shared.sx.ref.sx_ref._Spread...>" which was treated as
  an undefined symbol
- aser-call/async-aser-call didn't handle spread children — now merges
  spread attrs as keyword args into the parent element
- aser-fragment/async-aser-fragment didn't filter spreads — now filters
  them (fragments have no parent element to merge into)
- serialize() now handles spread type: (make-spread {:key "val"})

Added 3 aser-spreads tests. All 562 tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 12:20:16 +00:00
c95e320825 Merge branch 'worktree-api-urls' into macros
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
2026-03-13 12:07:05 +00:00
427dee13f0 Add scoped-effects + foundations to defpage plan-page dispatch
The plans were routed in page-functions.sx (GraphSX URL eval) but
missing from the defpage case in docs.sx (server-side slug route).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 12:06:56 +00:00
a7de0e9410 Merge branch 'worktree-api-urls' into macros 2026-03-13 12:04:30 +00:00
214963ea6a Unicode escapes, variadic infix fix, spreads demos, scoped-effects + foundations plans
- Add \uXXXX unicode escape support to parser.py and parser.sx spec
- Add char-from-code primitive (Python chr(), JS String.fromCharCode())
- Fix variadic infix operators in both bootstrappers (js.sx, py.sx) —
  (+ a b c d) was silently dropping terms, now left-folds correctly
- Rebootstrap sx_ref.py and sx-browser.js with all fixes
- Fix 3 pre-existing map-dict test failures in shared/sx/tests/run.py
- Add live demos alongside examples in spreads essay (side-by-side layout)
- Add scoped-effects plan: algebraic effects as unified foundation for
  spread/collect/island/lake/signal/context
- Add foundations plan: CEK machine, the computational floor, three-axis
  model (depth/topology/linearity), Curry-Howard correspondence
- Route both plans in page-functions.sx and nav-data.sx

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 12:03:58 +00:00
2fc391696c Merge branch 'worktree-api-urls' into macros 2026-03-13 10:46:53 +00:00
28a6560963 Replace \uXXXX escapes with actual UTF-8 characters in .sx files
SX parser doesn't process \u escapes — they render as literal text.
Use actual UTF-8 characters (→, —, £, ⬡) directly in source.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:46:53 +00:00
cee0ca7667 Merge branch 'worktree-api-urls' into macros 2026-03-13 10:44:10 +00:00
98036b2292 Add syntax highlighting to spreads page code blocks
Use (highlight "..." "lisp") page helper instead of raw strings
for ~docs/code :code values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:44:09 +00:00
6d0c0b2230 Merge branch 'worktree-api-urls' into macros 2026-03-13 05:42:51 +00:00
9d0bd3b0e7 Fix spreads page: remove (code) tags from table list data
(code "...") is an HTML tag — works in render context but not inside
(list ...) which fully evaluates args. Use plain strings in table rows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 05:42:47 +00:00
2329533d1a Merge branch 'worktree-api-urls' into macros 2026-03-13 05:35:56 +00:00
085f959323 Add spreads page function for SX URL routing
Without this, /sx/(geography.(spreads)) 404s because spreads isn't
defined as a page function to return the content component.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 05:35:50 +00:00
fe911625e3 Merge branch 'worktree-api-urls' into macros 2026-03-13 05:31:40 +00:00
9806aec60c Add Spreads page under Geography — spread/collect/reactive-spread docs
Documents the three orthogonal primitives (spread, collect!, reactive-spread),
their operation across server/client/morph boundaries, CSSX as use case,
semantic style variables, and the planned provide/context/emit! unification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 05:25:42 +00:00
36b070f796 Add reactive spreads — signal-driven attribute injection in islands
When a spread value (e.g. from ~cssx/tw) appears inside an island with
signal-dependent tokens, reactive-spread tracks deps and updates the
element's class/attrs when signals change. Old classes are surgically
removed, new ones appended, and freshly collected CSS rules are flushed
to the live stylesheet. Multiple reactive spreads on one element are safe.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 05:16:13 +00:00
ae6c6d06a7 Merge branch 'worktree-api-urls' into macros 2026-03-13 04:51:05 +00:00
846719908f Reactive forms pass spreads through instead of wrapping in fragments
adapter-dom.sx: if/when/cond reactive paths now check whether
initial-result is a spread. If so, return it directly — spreads
aren't DOM nodes and can't be appended to fragments. This lets
any spread-returning component (like ~cssx/tw) work inside islands
without the spread being silently dropped.

cssx.sx: revert make-spread workaround — the root cause is now
fixed in the adapter. ~cssx/tw can use a natural top-level if.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:51:05 +00:00
301bb8e585 Merge branch 'worktree-api-urls' into macros 2026-03-13 04:44:59 +00:00
d42972518a Revert ~cssx/tw to keyword calling — positional breaks param binding
Component params are bound from kwargs only in render-dom-component.
Positional args go to children, so (~ cssx/tw "...") binds tokens=nil.
The :tokens keyword is required: (~cssx/tw :tokens "...").

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:44:59 +00:00
071869331f Merge branch 'worktree-api-urls' into macros 2026-03-13 04:41:14 +00:00
2fd64351d0 Fix ~cssx/tw positional calling + move flush after content
layouts.sx: change all (~ cssx/tw :tokens "...") to (~cssx/tw "...")
matching the documented positional calling convention.

Move (~cssx/flush) after children so page content rules are also
collected before the server-side <style data-cssx> flush.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:41:14 +00:00
9096476402 Merge branch 'worktree-api-urls' into macros 2026-03-13 04:39:06 +00:00
0847824935 Remove debug logging from sx-browser.js
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:39:06 +00:00
b31eb393c4 Merge branch 'worktree-api-urls' into macros 2026-03-13 04:37:53 +00:00
2c97542ee8 Fix island dep scanning + spread-through-reactive-if debug
deps.sx: scan island bodies for component deps (was only scanning
"component" and "macro", missing "island" type). This ensures
~cssx/tw and its dependencies are sent to the client for islands.

cssx.sx: move if inside make-spread arg so it's evaluated by
eval-expr (no reactive wrapping) instead of render-to-dom which
applies reactive-if inside island scope, converting the spread
into a fragment and losing the class attrs.

Added island dep tests at 3 levels: test-deps.sx (spec),
test_deps.py (Python), test_parity.py (ref vs fallback).

sx-browser.js: temporary debug logging at spread detection points.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:37:45 +00:00
04539675d8 Merge branch 'worktree-api-urls' into macros 2026-03-13 04:09:32 +00:00
1d1e7f30bb Add flush-cssx-to-dom: client-side CSSX rule injection
Islands render independently on the client, so ~cssx/tw calls
collect!("cssx", rule) but no ~cssx/flush runs. Add flush-cssx-to-dom
in boot.sx that injects collected rules into a persistent <style>
element in <head>.

Called at all lifecycle points: boot-init, sx-mount, resolve-suspense,
post-swap (navigation morph), and swap-rendered-content (client routes).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:09:23 +00:00
56dfff8299 Merge branch 'worktree-api-urls' into macros 2026-03-13 03:41:10 +00:00
f52b9e880b Guard all appendChild calls against spread values
The previous fix only guarded domAppend/domInsertAfter, but many
platform JS functions (asyncRenderChildren, asyncRenderElement,
asyncRenderMap, render, sxRenderWithEnv) call appendChild directly.

Add _spread guards to all direct appendChild sites. For async element
rendering, merge spread attrs onto parent (class/style join, others
overwrite) matching the sync adapter behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 03:41:07 +00:00
a0d78e44d5 Merge branch 'worktree-api-urls' into macros 2026-03-13 03:35:15 +00:00
9284a946ba Guard domAppend/domInsertAfter against spread values
Spread values (from ~cssx/tw etc.) are attribute dicts, not DOM nodes.
When they appear in non-element contexts (fragments, islands, lakes,
reactive branches), they must not be passed to appendChild/insertBefore.

Add _spread guard to platform domAppend and domInsertAfter — fixes
TypeError: Node.appendChild: Argument 1 does not implement interface Node.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 03:35:00 +00:00
11ea641f7b Merge branch 'worktree-api-urls' into macros 2026-03-13 03:23:22 +00:00
c3430ade90 Fix DOM adapter: filter spread values from dom-append calls
Spread values returned by components like ~cssx/tw are not DOM nodes
and cannot be passed to appendChild. Filter them in fragment, let,
begin/do, component children, and data list rendering paths — matching
the HTML adapter's existing spread filtering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 03:23:17 +00:00
1f22f3fcd5 Merge branch 'worktree-api-urls' into macros 2026-03-13 03:18:03 +00:00
8100dc5fc9 Convert ~layouts/header from inline tw() to ~cssx/tw spreads
Class-based styling with JIT CSS rules collected into a single
<style> tag via ~cssx/flush in ~layouts/doc.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 03:17:53 +00:00
5f6600f572 Merge branch 'worktree-api-urls' into macros 2026-03-13 02:58:39 +00:00
ea2b71cfa3 Add provide/context/emit!/emitted — render-time dynamic scope
Four new primitives for scoped downward value passing and upward
accumulation through the render tree. Specced in .sx, bootstrapped
to Python and JS across all adapters (eval, html, sx, dom, async).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 02:58:21 +00:00
41097eeef9 Add spread + collect primitives, rewrite ~cssx/tw as defcomp
New SX primitives for child-to-parent communication in the render tree:
- spread type: make-spread, spread?, spread-attrs — child injects attrs
  onto parent element (class joins with space, style with semicolon)
- collect!/collected/clear-collected! — render-time accumulation with
  dedup into named buckets

~cssx/tw is now a proper defcomp returning a spread value instead of a
macro wrapping children. ~cssx/flush reads collected "cssx" rules and
emits a single <style data-cssx> tag.

All four render adapters (html, async, dom, aser) handle spread values.
Both bootstraps (Python + JS) regenerated. Also fixes length→len in
cssx.sx (length was never a registered primitive).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 02:38:31 +00:00
c2efa192c5 Rewrite CSSX: unified Tailwind-style utility token system
Replace the three-layer cssx system (macro + value functions + class
components) with a single token resolver. Tokens like "bg-yellow-199",
"hover:bg-rose-500", "md:text-xl" are parsed into CSS declarations.

Two delivery mechanisms, same token format:
- tw() function: returns inline style string for :style
- ~cssx/tw macro: injects JIT class + <style> onto first child element

The resolver handles: colours (21 names, any shade 0-950), spacing,
typography, display, max-width, rounded, opacity, w/h, gap, text
decoration, cursor, overflow, transitions. States (hover/focus/active)
and responsive breakpoints (sm/md/lg/xl/2xl) for class-based usage.

Next step: replace macro/function approach with spec-level primitives
(defcontext/provide/context + spread) so ~cssx/tw becomes a proper
component returning spread values, with rules collected via context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 01:37:35 +00:00
100450772f Cache parsed components for 10x faster startup (2s → 200ms)
- Fix O(n²) postprocessing: compute_all_deps/io_refs/hash were called
  per-file (92x for sx app). Now deferred to single finalize_components()
  call after all files load.
- Add pickle cache in shared/sx/.cache/ keyed by file mtimes+sizes.
  Cache stores fully-processed Component/Island/Macro objects with deps,
  io_refs, and css_classes pre-computed. Closures stripped before pickle,
  rebuilt from global env after restore.
- Smart finalization: cached loads skip deps/io_refs recomputation
  (already in pickle), only recompute component hash.
- Fix ~sx-header → ~layouts/header ref in docs-content.sx

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:54:38 +00:00
7c969f9192 Remove redundant 'click to navigate' prompts from SX URLs page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:30:59 +00:00
bc1ea0128f Merge worktree-api-urls: remove click prompts 2026-03-12 23:30:59 +00:00