Commit Graph

398 Commits

Author SHA1 Message Date
0e0a42ac04 Merge branch 'worktree-macros-essays' into macros 2026-03-04 16:58:51 +00:00
9cbfb09b41 Slim market/sxc/pages/__init__.py → 21 lines
Move ~1670 lines to 6 sub-modules: renders.py, layouts.py, helpers.py,
cards.py, filters.py, utils.py. Update all bp route imports.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 16:58:47 +00:00
5690bb0388 Merge branch 'worktree-macros-essays' into macros 2026-03-04 16:52:13 +00:00
8eaf4026ab Slim sxc/pages/__init__.py for federation, test, cart, blog
Move render functions, layouts, helpers, and utils from __init__.py
to sub-modules (renders.py, layouts.py, helpers.py, utils.py).
Update all bp route imports to point at sub-modules directly.
Each __init__.py is now ≤20 lines of setup + registration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 16:51:57 +00:00
76bc293faa Document SX rendering pipeline, add missing sx_docs mount, loud error on missing component
- CLAUDE.md: add SX rendering pipeline overview, service sx/ vs sxc/
  convention, dev container mount convention
- docker-compose.dev.yml: add missing ./sx/sx:/app/sx bind mount for
  sx_docs (root cause of "Unknown component: ~sx-layout-full")
- async_eval.py: add evaluation modes table to module docstring; log
  error when async_eval_slot_to_sx can't find a component instead of
  silently falling through to client-side serialization
- helpers.py: remove debug logging from render_to_sx_with_env

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 16:48:01 +00:00
992a9e1731 Merge branch 'worktree-macros-essays' into macros 2026-03-04 16:14:29 +00:00
03d7b29745 Fix load_service_components path for sx, market, events
The load_service_components call used dirname twice from
sxc/pages/__init__.py, yielding {service}/sxc/ instead of
{service}/. This meant {service}/sx/*.sx files (layouts, calendar
components, etc.) were never loaded into the component env.

- sx: ~sx-layout-full not found → Unknown component on client
- events: ~events-calendar-grid not found → Unknown component
- market: also fix url_for endpoint for defpage_market_admin
  (mounted on app, not blueprint — no prefix needed)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 16:14:26 +00:00
9a9999d2e1 Merge branch 'worktree-macros-essays' into macros 2026-03-04 16:04:35 +00:00
015469e401 Fix Undefined symbol: div — delegate HTML tags to renderDOM in sxEval
When an HTML tag like (div) appears as a kwarg value in SX wire format,
callComponent evaluates it with sxEval (data mode) which doesn't handle
HTML tags. Now sxEval delegates to renderDOM for any render expression
(HTML tags, SVG tags, fragments, raw!, components).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 16:04:29 +00:00
2258a0790b Merge branch 'worktree-macros-essays' into macros 2026-03-04 15:49:02 +00:00
527c4186ee Fix _aser_component: evaluate kwargs with _aser not async_eval
_aser_component expands component bodies in SX wire format mode,
but was evaluating kwarg values with async_eval (HTML mode). This
caused SxExpr kwargs to be fully rendered to HTML strings, which
then broke when serialized back to SX — producing bare symbols
like 'div' that the client couldn't resolve.

Fix: use _aser() for kwarg evaluation to keep values in SX format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:48:57 +00:00
0b4443f394 Merge branch 'worktree-macros-essays' into macros 2026-03-04 15:45:32 +00:00
4939884f25 Add debug logging for Undefined symbol errors in sx.js
Logs env keys (non-function) when a symbol lookup fails, to help
diagnose which component/context is missing the expected binding.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:45:32 +00:00
e23d73d1b1 Merge branch 'worktree-macros-essays' into macros 2026-03-04 15:27:46 +00:00
715df11f82 Phase 8-9: Convert events + sx layouts, add missing JS primitives
Events (Phase 8):
- Create events/sx/layouts.sx with 18 defcomps for all 9 layout pairs
- Convert all layout functions to render_to_sx_with_env + _ctx_to_env
- Convert 5 render functions to eliminate root_header_sx calls
- Zero root_header_sx references remain in events

SX Docs (Phase 9):
- Create sx/sx/layouts.sx with layout defcomps
- Convert 4 layout functions to render_to_sx_with_env + _ctx_to_env

JS primitives:
- Add slice, replace, upper, lower, trim, escape, strip-tags, split,
  join, pluralize, clamp, parse-int, format-decimal, format-date,
  parse-datetime, split-ids, starts-with?, ends-with?, dissoc, into
- Fix contains? for strings (indexOf instead of in operator)
- Prevents "Undefined symbol" errors when .sx expressions using
  server-side primitives are evaluated client-side

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:27:41 +00:00
69d328b20f Merge branch 'worktree-macros-essays' into macros 2026-03-04 15:15:57 +00:00
121aa30f32 Fix contains? primitive to handle strings in both JS and Python
The JS contains? used `k in c` which throws TypeError on strings.
The Python version silently returned False for strings. Both now
use indexOf/`in` for substring matching on strings.

Fixes: sx.js MOUNT PARSE ERROR on blog index where
(contains? current-local-href "?") was evaluated client-side.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:15:50 +00:00
be3e86d8d6 Merge branch 'worktree-macros-essays' into macros 2026-03-04 15:03:04 +00:00
1dbf600af2 Convert test/cart/blog/market layouts to use _ctx_to_env + render_to_sx_with_env
Phase 4 (Test): Update ~test-layout-full and ~test-detail-layout-full defcomps
to use ~root-header with env free variables. Switch render functions to
render_to_sx_with_env.

Phase 5 (Cart): Convert cart-page, cart-admin, and order render functions.
Update cart .sx layout defcomps to use ~root-header from free variables.

Phase 6 (Blog): Convert all 7 blog layouts (blog, settings, sub-settings x5).
Remove all root_header_sx calls from blog.

Phase 7 (Market): Convert market and market-admin layouts plus browse/product
render functions. Remove root_header_sx import.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:02:59 +00:00
9be8a38fe9 Merge branch 'worktree-macros-essays' into macros 2026-03-04 14:50:20 +00:00
a30e7228d8 Pass all values as &key args to ~root-header/~root-mobile
Nested component calls in _aser are serialized without body expansion,
so free variables inside ~root-header would be sent unresolved to the
client. Fix by making ~root-header/~root-mobile take all values as
&key params, and having parent layout defcomps pass them explicitly.
The parent layout bodies ARE expanded (via async_eval_slot_to_sx),
so their free variables resolve correctly during that expansion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:50:14 +00:00
2f26437004 Merge branch 'worktree-macros-essays' into macros 2026-03-04 14:48:48 +00:00
e4bfd46c48 Fix register_sx_layout: use async_eval_slot_to_sx to expand component bodies
async_eval_to_sx serializes component calls without expanding their bodies,
so free variables from _ctx_to_env were passed through as unresolved symbols
to the client. Switch to async_eval_slot_to_sx which expands the top-level
component body server-side, resolving free variables during expansion.

Also inline ~root-header/~root-mobile into layout defcomps rather than using
wrapper defcomps (nested ~component calls in _aser are serialized without
expansion, so wrapper defcomps would still leave free vars unresolved).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:48:43 +00:00
2e23feb09e Merge branch 'worktree-macros-essays' into macros 2026-03-04 14:39:57 +00:00
45c5e4a0db Add register_sx_layout infrastructure, convert account/federation/orders
Phase 0: Add _ctx_to_env() and render_to_sx_with_env() to shared/sx/helpers.py,
register_sx_layout() to shared/sx/layouts.py, and ~root-header/~root-mobile
wrapper defcomps to layout.sx. Convert built-in "root" layout to .sx.

Phases 1-3: Convert account (65→19 lines), federation (105→97 lines),
and orders (88→21 lines) to use register_sx_layout with .sx defcomps
that read ctx values as free variables from the evaluation environment.
No more Python building SX strings via SxExpr(await root_header_sx(ctx)).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:39:53 +00:00
a84916e82f Fix filter/map tag disambiguation inside SVG context without keyword attrs
(filter (feTurbulence ...)) inside (svg ...) has no keyword first arg,
so the keyword-only check dispatched it as a HO function. Now also
check SVG/MathML context (ns in client, _svg_context in server).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:03:02 +00:00
f5c266e785 Fix custom element check: require keyword arg to disambiguate from variables
Hyphenated names like app-url are variables, not custom elements.
Only treat as custom element when first arg is a Keyword (tag call pattern).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 13:55:36 +00:00
d551806976 Add SVG namespace auto-detection, custom elements, html: prefix, and fix filter/map tag collision
- Fix filter/map dispatching as HO functions when used as SVG/HTML tags
  (peek at first arg — Keyword means tag call, not function call)
- Add html: prefix escape hatch to force any name to render as an element
- Support custom elements (hyphenated names) per Web Components spec
- SVG/MathML namespace auto-detection: client threads ns param through
  render chain; server uses _svg_context ContextVar so unknown tags
  inside (svg ...) or (math ...) render as elements without enumeration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 13:53:08 +00:00
2663dfb095 Add SVG cover art to SX Manifesto as s-expression
Soviet constructivist poster with paper texture filters, grid lines,
aged stain spots, and "(<x>)" symbol in red.

Add missing SVG filter primitive tags to both server (html.py) and
client (sx.js): feTurbulence, feColorMatrix, feBlend,
feComponentTransfer, feFuncR/G/B/A, feDisplacementMap, feComposite,
feFlood, feImage, feMorphology, feSpecularLighting, feDiffuseLighting,
fePointLight, feSpotLight, feDistantLight.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 13:34:58 +00:00
ccd9b969ea Add 40 more links to SX Manifesto, author: Markdown & Anglebrackets
Link HTML, CSS, JavaScript, framework, separation of concerns, markup,
weak typing, prototype chains, declarative, Turing-complete, DOM,
homoiconicity, validate forms, server-side execution, signals, hooks,
reconciler, tree-shaking, code-splitting, HMR, transpilation, scoping,
composition model, template literals, inline styles, node_modules,
structured data, dependency tree, breaking changes, developer experience,
angle bracket, and "designed in ten days". Remove original source link.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 13:27:43 +00:00
7325bb9ecf Fix ParseError in SX Manifesto: bare backslash + unclosed li
- Wrap \"this\" in sx string quotes so backslash escapes are inside a string
- Remove stray quote before closing paren on wire protocol li item

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 13:15:09 +00:00
6f3562707a Change language to paradigm where referring to SX in the manifesto
SX is a paradigm, not a language. Changed 7 instances where "language"
referred to SX itself: "one paradigm since 1958", "the paradigm is the
framework", "not a framework but a paradigm", "paradigms do not have
breaking changes", "the paradigm itself provides", "a paradigm that
does not require a migration guide", "distinct from the paradigm".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 13:00:02 +00:00
2609e782fc Change s-expressions to s-expressionism where it refers to the movement
In the SX Manifesto: "the spectre of s-expressionism", "S-expressionism
abolishes", "S-expressionism needs no ecosystem", "S-expressionism
resolves the CSS question", "The s-expressionist revolution".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:57:51 +00:00
28cbe60dc6 Add 78 links throughout the SX Manifesto essay
External links to Google, Meta, webpack, Vercel, Stack Overflow, React,
Vue, Angular, Svelte, SolidJS, Qwik, Astro, Next, Nuxt, Remix, Gatsby,
Rollup, Parcel, esbuild, Vite, Turbopack, TypeScript, Emacs, Clojure,
npm, Lisp, Scheme, Brendan Eich, Tailwind, Sass, Less, PostCSS, XML,
XSLT, JSON, YAML, TOML, JSX, SFCs, Lodash, Moment, Axios, left-pad,
is-odd, CSS-in-JS, virtual DOM, Vicar of Bray, CGI-bin, and Marx.

Internal links to /docs/components, /docs/evaluator, /docs/primitives,
/docs/css, /essays/on-demand-css, /protocols/wire-format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:55:12 +00:00
0f82294dc1 Update /docs/css page with CSSX native style primitives docs
Document css primitive, style atoms, variants, defstyle, defkeyframes,
and on-demand delivery protocol.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:50:07 +00:00
19d59f5f4b Implement CSSX Phase 2: native SX style primitives
Replace Tailwind class strings with native SX expressions:
(css :flex :gap-4 :hover:bg-sky-200) instead of :class "flex gap-4 ..."

- Add style_dict.py: 516 atoms, variants, breakpoints, keyframes, patterns
- Add style_resolver.py: memoized resolver with variant splitting
- Add StyleValue type to types.py (frozen dataclass with class_name, declarations, etc.)
- Add css and merge-styles primitives to primitives.py
- Add defstyle and defkeyframes special forms to evaluator.py and async_eval.py
- Integrate StyleValue into html.py and async_eval.py render paths
- Add register_generated_rule() to css_registry.py, fix media query selector
- Add style dict JSON delivery with localStorage caching to helpers.py
- Add client-side css primitive, resolver, and style injection to sx.js

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:47:51 +00:00
28388540d5 Fix unquoted (code) element in SX manifesto essay
The (code :class "text-violet-700" ...) was embedded inside a string
child of (p), causing the SX parser to see text-violet-700 as a bare
symbol. Close the text string before the (code) element so it becomes
a proper child of the paragraph.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:09:41 +00:00
5fac47c132 Fix sx-manifesto EvalError: close string before italic span
The em span variable was embedded inside an unclosed sx string,
causing the " before "italic" to close the outer string and
leaving italic as an undefined bare symbol.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:57:28 +00:00
213421516e Add SSE, response headers, view transitions, and 5 new sx attributes
Implement missing SxEngine features:
- SSE (sx-sse, sx-sse-swap) with EventSource management and auto-cleanup
- Response headers: SX-Trigger, SX-Retarget, SX-Reswap, SX-Redirect,
  SX-Refresh, SX-Location, SX-Replace-Url, SX-Trigger-After-Swap/Settle
- View Transitions API: transition:true swap modifier + global config
- every:<time> trigger for polling (setInterval)
- sx-replace-url (replaceState instead of pushState)
- sx-disabled-elt (disable elements during request)
- sx-prompt (window.prompt, value sent as SX-Prompt header)
- sx-params (filter form parameters: *, none, not x,y, x,y)

Adds docs (ATTR_DETAILS, BEHAVIOR_ATTRS, headers, events), demo
components in reference.sx, API endpoints (prompt-echo, sse-time),
and 27 new unit tests for engine logic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:55:21 +00:00
3bffc212cc Fix sx docs load_sx_dir path to point to sxc/ not sxc/pages/
The .sx component files (home.sx, docs.sx, etc.) live in sxc/, but
the path was pointing to sxc/pages/ after the move from sx_components.py.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:35:22 +00:00
b51b050dda Delete last sx_components.py files: relations + test (phase 9)
Move relations component loading into app.py. Move test rendering
functions to test/sxc/pages/__init__.py, update route imports, and
delete both sx_components.py files. Zero sx_components imports remain.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:26:58 +00:00
5bb02b7dd5 Move 7 htmx-equivalent attrs from SX_UNIQUE_ATTRS to BEHAVIOR_ATTRS
These are sx implementations of htmx attributes (boost, preload,
preserve, indicator, validate, ignore, optimistic), not unique to sx.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:26:24 +00:00
16f0908ec9 Move SX docs rendering from sx_components.py to sxc/pages (phase 8)
Consolidate 86 component rendering functions into sxc/pages/__init__.py,
update 37 import sites in routes.py, remove app.py side-effect imports,
and delete sx/sxc/sx_components.py.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:24:26 +00:00
7419ecf3c0 Delete events sx_components.py — move all rendering to sxc/pages
Phase 7 of the zero-Python-rendering plan. All 100 rendering functions
move from events/sx/sx_components.py into events/sxc/pages/__init__.py.
Route handlers (15 files) import from sxc.pages instead.
load_service_components call moves into _load_events_page_files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:19:38 +00:00
31a8b755d9 Implement 7 missing sx attributes: boost, preload, preserve, indicator, validate, ignore, optimistic
Add sx-preserve/sx-ignore (morph skip), sx-indicator (loading element),
sx-validate (form validation), sx-boost (progressive enhancement),
sx-preload (hover prefetch with 30s cache), and sx-optimistic (instant
UI preview with rollback). Move all from HTMX_MISSING_ATTRS to
SX_UNIQUE_ATTRS with full ATTR_DETAILS docs and reference.sx demos.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:18:31 +00:00
049796c391 Delete market sx_components.py — move all rendering to sxc/pages
Phase 6 of the zero-Python-rendering plan. All 46 rendering functions
move from market/sx/sx_components.py into market/sxc/pages/__init__.py.
Route handlers import from sxc.pages instead. load_service_components
call moves into _load_market_page_files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:08:44 +00:00
8578eb525e Change sx logo to (<x>)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 10:56:50 +00:00
96a4f56424 Fix extra closing paren in SX manifesto and TCO essays
Both essays had one excess `)` causing ParseError when navigating
via HTMX (oob_page_sx path).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 10:55:51 +00:00
e72f7485f4 Add TCO trampolining to async evaluator and sx.js client
Both evaluators now use thunk-based trampolining to eliminate stack
overflow on deep tail recursion (verified at 50K+ depth). Mirrors
the sync evaluator TCO added in 5069072.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 10:53:16 +00:00
da8d2e342f Continuations essay: add argument that they're easier to reason about than workarounds
Without call/cc you get callback pyramids, state machines, command
pattern undo stacks, Promise chains, and framework-specific hooks —
each a partial ad-hoc reinvention of continuations with its own edge
cases. The complexity doesn't disappear; it moves into user code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 10:42:08 +00:00