Refactor SX primitives: modular, isomorphic, general-purpose

Spec modularization:
- Add (define-module :name) markers to primitives.sx creating 11 modules
  (7 core, 4 stdlib). Bootstrappers can now selectively include modules.
- Add parse_primitives_by_module() to boundary_parser.py.
- Remove split-ids primitive; inline at 4 call sites in blog/market queries.

Python file split:
- primitives.py: slimmed to registry + core primitives only (~350 lines)
- primitives_stdlib.py: NEW — stdlib primitives (format, text, style, debug)
- primitives_ctx.py: NEW — extracted 12 page context builders from IO
- primitives_io.py: add register_io_handler decorator, auto-derive
  IO_PRIMITIVES from registry, move sync IO bridges here

JS parity fixes:
- = uses === (strict equality), != uses !==
- round supports optional ndigits parameter
- concat uses nil-check not falsy-check (preserves 0, "", false)
- escape adds single quote entity (') matching Python/markupsafe
- assert added (was missing from JS entirely)

Bootstrapper modularization:
- PRIMITIVES_JS_MODULES / PRIMITIVES_PY_MODULES dicts keyed by module
- --modules CLI flag for selective inclusion (core.* always included)
- Regenerated sx-ref.js and sx_ref.py with all fixes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 01:45:29 +00:00
parent cfde5bc491
commit f77d7350dd
13 changed files with 3545 additions and 1303 deletions

View File

@@ -10,7 +10,8 @@
(defquery posts-by-ids (&key ids)
"Fetch multiple blog posts by comma-separated IDs."
(service "blog" "get-posts-by-ids" :ids (split-ids ids)))
(service "blog" "get-posts-by-ids"
:ids (map parse-int (filter (fn (s) (not (empty? s))) (split (str ids) ",")))))
(defquery search-posts (&key query page per-page)
"Search blog posts by text query, paginated."
@@ -35,4 +36,5 @@
(defquery page-configs-batch (&key container-type ids)
"Return PageConfigs for multiple container IDs (comma-separated)."
(service "page-config" "get-batch"
:container-type container-type :ids (split-ids ids)))
:container-type container-type
:ids (map parse-int (filter (fn (s) (not (empty? s))) (split (str ids) ",")))))