Make SxExpr a str subclass, sx_call/render functions return SxExpr

SxExpr is now a str subclass so it works everywhere a plain string
does (join, isinstance, f-strings) while serialize() still emits it
unquoted. sx_call() and all internal render functions (_render_to_sx,
async_eval_to_sx, etc.) return SxExpr, eliminating the "forgot to
wrap" bug class that caused the sx_content leak and list serialization
bugs.

- Phase 0: SxExpr(str) with .source property, __add__/__radd__
- Phase 1: sx_call returns SxExpr (drop-in, all 200+ sites unchanged)
- Phase 2: async_eval_to_sx, async_eval_slot_to_sx, _render_to_sx,
  mobile_menu_sx return SxExpr; remove isinstance(str) workaround
- Phase 3: Remove ~150 redundant SxExpr() wrappings across 45 files
- Phase 4: serialize() docstring, handler return docs, ;; returns: sx

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 21:47:00 +00:00
parent ad75798ab7
commit 278ae3e8f6
45 changed files with 378 additions and 379 deletions

View File

@@ -31,7 +31,6 @@ async def _render_choose_username(*, actor=None, error="", username=""):
from shared.browser.app.csrf import generate_csrf_token
from shared.config import config
from shared.sx.helpers import sx_call
from shared.sx.parser import SxExpr
from shared.sx.page import get_template_context
from sxc.pages.utils import _social_page
from markupsafe import escape
@@ -45,7 +44,7 @@ async def _render_choose_username(*, actor=None, error="", username=""):
content = sx_call(
"federation-choose-username",
domain=str(escape(ap_domain)),
error=SxExpr(error_sx) if error_sx else None,
error=error_sx or None,
csrf=csrf, username=str(escape(username)),
check_url=check_url,
)

View File

@@ -212,7 +212,6 @@ def register(url_prefix="/social"):
"""Re-render interaction buttons after a like/boost action."""
from shared.models.federation import APInteraction
from shared.browser.app.csrf import generate_csrf_token
from shared.sx.parser import SxExpr
from sqlalchemy import select
svc = services.federation
@@ -290,9 +289,9 @@ def register(url_prefix="/social"):
count=str(boost_count))
return sx_response(sx_call("federation-interaction-buttons",
like=SxExpr(like_form),
boost=SxExpr(boost_form),
reply=SxExpr(reply_sx) if reply_sx else None))
like=like_form,
boost=boost_form,
reply=reply_sx or None))
# -- Following / Followers pagination --------------------------------------

View File

@@ -1,4 +1,5 @@
;; Federation link-card fragment handler
;; returns: sx
;;
;; Renders actor profile preview card(s) by username.
;; Supports single mode (?slug=x or ?username=x) and batch mode (?keys=x,y,z).