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:
@@ -229,14 +229,13 @@ def _register_events_layouts() -> None:
|
||||
|
||||
async def _cal_admin_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx
|
||||
from shared.sx.parser import SxExpr
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
return await render_to_sx_with_env("events-cal-admin-layout-full", {},
|
||||
post_header=SxExpr(await _post_header_sx(ctx)),
|
||||
admin_header=SxExpr(await post_admin_header_sx(ctx, slug, selected="calendars")),
|
||||
calendar_header=SxExpr(_calendar_header_sx(ctx)),
|
||||
calendar_admin_header=SxExpr(_calendar_admin_header_sx(ctx)),
|
||||
post_header=await _post_header_sx(ctx),
|
||||
admin_header=await post_admin_header_sx(ctx, slug, selected="calendars"),
|
||||
calendar_header=_calendar_header_sx(ctx),
|
||||
calendar_admin_header=_calendar_admin_header_sx(ctx),
|
||||
)
|
||||
|
||||
|
||||
@@ -246,10 +245,10 @@ async def _cal_admin_oob(ctx: dict, **kw: Any) -> str:
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
return await render_to_sx_with_env("events-cal-admin-layout-oob", {},
|
||||
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
|
||||
cal_oob=SxExpr(_calendar_header_sx(ctx, oob=True)),
|
||||
cal_admin_oob_wrap=SxExpr(await oob_header_sx("calendar-header-child",
|
||||
"calendar-admin-header-child", _calendar_admin_header_sx(ctx))),
|
||||
admin_oob=await post_admin_header_sx(ctx, slug, oob=True, selected="calendars"),
|
||||
cal_oob=_calendar_header_sx(ctx, oob=True),
|
||||
cal_admin_oob_wrap=await oob_header_sx("calendar-header-child",
|
||||
"calendar-admin-header-child", _calendar_admin_header_sx(ctx)),
|
||||
clear_oob=SxExpr(_clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
@@ -269,8 +268,8 @@ async def _slots_oob(ctx: dict, **kw: Any) -> str:
|
||||
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
return await render_to_sx_with_env("events-slots-layout-oob", {},
|
||||
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
|
||||
cal_admin_oob=SxExpr(_calendar_admin_header_sx(ctx, oob=True)),
|
||||
admin_oob=await post_admin_header_sx(ctx, slug, oob=True, selected="calendars"),
|
||||
cal_admin_oob=_calendar_admin_header_sx(ctx, oob=True),
|
||||
clear_oob=SxExpr(_clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
@@ -282,15 +281,14 @@ async def _slots_oob(ctx: dict, **kw: Any) -> str:
|
||||
|
||||
async def _slot_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx
|
||||
from shared.sx.parser import SxExpr
|
||||
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
return await render_to_sx_with_env("events-slot-layout-full", {},
|
||||
post_header=SxExpr(await _post_header_sx(ctx)),
|
||||
admin_header=SxExpr(await post_admin_header_sx(ctx, slug, selected="calendars")),
|
||||
calendar_header=SxExpr(_calendar_header_sx(ctx)),
|
||||
calendar_admin_header=SxExpr(_calendar_admin_header_sx(ctx)),
|
||||
slot_header=SxExpr(_slot_header_html(ctx)),
|
||||
post_header=await _post_header_sx(ctx),
|
||||
admin_header=await post_admin_header_sx(ctx, slug, selected="calendars"),
|
||||
calendar_header=_calendar_header_sx(ctx),
|
||||
calendar_admin_header=_calendar_admin_header_sx(ctx),
|
||||
slot_header=_slot_header_html(ctx),
|
||||
)
|
||||
|
||||
|
||||
@@ -300,10 +298,10 @@ async def _slot_oob(ctx: dict, **kw: Any) -> str:
|
||||
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
return await render_to_sx_with_env("events-slot-layout-oob", {},
|
||||
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
|
||||
cal_admin_oob=SxExpr(_calendar_admin_header_sx(ctx, oob=True)),
|
||||
slot_oob_wrap=SxExpr(await oob_header_sx("calendar-admin-header-child",
|
||||
"slot-header-child", _slot_header_html(ctx))),
|
||||
admin_oob=await post_admin_header_sx(ctx, slug, oob=True, selected="calendars"),
|
||||
cal_admin_oob=_calendar_admin_header_sx(ctx, oob=True),
|
||||
slot_oob_wrap=await oob_header_sx("calendar-admin-header-child",
|
||||
"slot-header-child", _slot_header_html(ctx)),
|
||||
clear_oob=SxExpr(_clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
@@ -316,15 +314,14 @@ async def _slot_oob(ctx: dict, **kw: Any) -> str:
|
||||
|
||||
async def _day_admin_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx
|
||||
from shared.sx.parser import SxExpr
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
return await render_to_sx_with_env("events-day-admin-layout-full", {},
|
||||
post_header=SxExpr(await _post_header_sx(ctx)),
|
||||
admin_header=SxExpr(await post_admin_header_sx(ctx, slug, selected="calendars")),
|
||||
calendar_header=SxExpr(_calendar_header_sx(ctx)),
|
||||
day_header=SxExpr(_day_header_sx(ctx)),
|
||||
day_admin_header=SxExpr(_day_admin_header_sx(ctx)),
|
||||
post_header=await _post_header_sx(ctx),
|
||||
admin_header=await post_admin_header_sx(ctx, slug, selected="calendars"),
|
||||
calendar_header=_calendar_header_sx(ctx),
|
||||
day_header=_day_header_sx(ctx),
|
||||
day_admin_header=_day_admin_header_sx(ctx),
|
||||
)
|
||||
|
||||
|
||||
@@ -334,10 +331,10 @@ async def _day_admin_oob(ctx: dict, **kw: Any) -> str:
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
return await render_to_sx_with_env("events-day-admin-layout-oob", {},
|
||||
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
|
||||
cal_oob=SxExpr(_calendar_header_sx(ctx, oob=True)),
|
||||
day_admin_oob_wrap=SxExpr(await oob_header_sx("day-header-child",
|
||||
"day-admin-header-child", _day_admin_header_sx(ctx))),
|
||||
admin_oob=await post_admin_header_sx(ctx, slug, oob=True, selected="calendars"),
|
||||
cal_oob=_calendar_header_sx(ctx, oob=True),
|
||||
day_admin_oob_wrap=await oob_header_sx("day-header-child",
|
||||
"day-admin-header-child", _day_admin_header_sx(ctx)),
|
||||
clear_oob=SxExpr(_clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
@@ -350,12 +347,11 @@ async def _day_admin_oob(ctx: dict, **kw: Any) -> str:
|
||||
|
||||
async def _entry_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env
|
||||
from shared.sx.parser import SxExpr
|
||||
return await render_to_sx_with_env("events-entry-layout-full", {},
|
||||
post_header=SxExpr(await _post_header_sx(ctx)),
|
||||
calendar_header=SxExpr(_calendar_header_sx(ctx)),
|
||||
day_header=SxExpr(_day_header_sx(ctx)),
|
||||
entry_header=SxExpr(_entry_header_html(ctx)),
|
||||
post_header=await _post_header_sx(ctx),
|
||||
calendar_header=_calendar_header_sx(ctx),
|
||||
day_header=_day_header_sx(ctx),
|
||||
entry_header=_entry_header_html(ctx),
|
||||
)
|
||||
|
||||
|
||||
@@ -363,9 +359,9 @@ async def _entry_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env, oob_header_sx
|
||||
from shared.sx.parser import SxExpr
|
||||
return await render_to_sx_with_env("events-entry-layout-oob", {},
|
||||
day_oob=SxExpr(_day_header_sx(ctx, oob=True)),
|
||||
entry_oob_wrap=SxExpr(await oob_header_sx("day-header-child",
|
||||
"entry-header-child", _entry_header_html(ctx))),
|
||||
day_oob=_day_header_sx(ctx, oob=True),
|
||||
entry_oob_wrap=await oob_header_sx("day-header-child",
|
||||
"entry-header-child", _entry_header_html(ctx)),
|
||||
clear_oob=SxExpr(_clear_deeper_oob("post-row", "post-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
"day-row", "day-header-child",
|
||||
@@ -377,16 +373,15 @@ async def _entry_oob(ctx: dict, **kw: Any) -> str:
|
||||
|
||||
async def _entry_admin_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx
|
||||
from shared.sx.parser import SxExpr
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
return await render_to_sx_with_env("events-entry-admin-layout-full", {},
|
||||
post_header=SxExpr(await _post_header_sx(ctx)),
|
||||
admin_header=SxExpr(await post_admin_header_sx(ctx, slug, selected="calendars")),
|
||||
calendar_header=SxExpr(_calendar_header_sx(ctx)),
|
||||
day_header=SxExpr(_day_header_sx(ctx)),
|
||||
entry_header=SxExpr(_entry_header_html(ctx)),
|
||||
entry_admin_header=SxExpr(_entry_admin_header_html(ctx)),
|
||||
post_header=await _post_header_sx(ctx),
|
||||
admin_header=await post_admin_header_sx(ctx, slug, selected="calendars"),
|
||||
calendar_header=_calendar_header_sx(ctx),
|
||||
day_header=_day_header_sx(ctx),
|
||||
entry_header=_entry_header_html(ctx),
|
||||
entry_admin_header=_entry_admin_header_html(ctx),
|
||||
)
|
||||
|
||||
|
||||
@@ -396,10 +391,10 @@ async def _entry_admin_oob(ctx: dict, **kw: Any) -> str:
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
return await render_to_sx_with_env("events-entry-admin-layout-oob", {},
|
||||
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
|
||||
entry_oob=SxExpr(_entry_header_html(ctx, oob=True)),
|
||||
entry_admin_oob_wrap=SxExpr(await oob_header_sx("entry-header-child",
|
||||
"entry-admin-header-child", _entry_admin_header_html(ctx))),
|
||||
admin_oob=await post_admin_header_sx(ctx, slug, oob=True, selected="calendars"),
|
||||
entry_oob=_entry_header_html(ctx, oob=True),
|
||||
entry_admin_oob_wrap=await oob_header_sx("entry-header-child",
|
||||
"entry-admin-header-child", _entry_admin_header_html(ctx)),
|
||||
clear_oob=SxExpr(_clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
@@ -413,24 +408,22 @@ async def _entry_admin_oob(ctx: dict, **kw: Any) -> str:
|
||||
|
||||
async def _ticket_types_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env
|
||||
from shared.sx.parser import SxExpr
|
||||
return await render_to_sx_with_env("events-ticket-types-layout-full", {},
|
||||
post_header=SxExpr(await _post_header_sx(ctx)),
|
||||
calendar_header=SxExpr(_calendar_header_sx(ctx)),
|
||||
day_header=SxExpr(_day_header_sx(ctx)),
|
||||
entry_header=SxExpr(_entry_header_html(ctx)),
|
||||
entry_admin_header=SxExpr(_entry_admin_header_html(ctx)),
|
||||
ticket_types_header=SxExpr(_ticket_types_header_html(ctx)),
|
||||
post_header=await _post_header_sx(ctx),
|
||||
calendar_header=_calendar_header_sx(ctx),
|
||||
day_header=_day_header_sx(ctx),
|
||||
entry_header=_entry_header_html(ctx),
|
||||
entry_admin_header=_entry_admin_header_html(ctx),
|
||||
ticket_types_header=_ticket_types_header_html(ctx),
|
||||
)
|
||||
|
||||
|
||||
async def _ticket_types_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env, oob_header_sx
|
||||
from shared.sx.parser import SxExpr
|
||||
return await render_to_sx_with_env("events-ticket-types-layout-oob", {},
|
||||
entry_admin_oob=SxExpr(_entry_admin_header_html(ctx, oob=True)),
|
||||
ticket_types_oob_wrap=SxExpr(await oob_header_sx("entry-admin-header-child",
|
||||
"ticket_types-header-child", _ticket_types_header_html(ctx))),
|
||||
entry_admin_oob=_entry_admin_header_html(ctx, oob=True),
|
||||
ticket_types_oob_wrap=await oob_header_sx("entry-admin-header-child",
|
||||
"ticket_types-header-child", _ticket_types_header_html(ctx)),
|
||||
)
|
||||
|
||||
|
||||
@@ -438,25 +431,23 @@ async def _ticket_types_oob(ctx: dict, **kw: Any) -> str:
|
||||
|
||||
async def _ticket_type_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env
|
||||
from shared.sx.parser import SxExpr
|
||||
return await render_to_sx_with_env("events-ticket-type-layout-full", {},
|
||||
post_header=SxExpr(await _post_header_sx(ctx)),
|
||||
calendar_header=SxExpr(_calendar_header_sx(ctx)),
|
||||
day_header=SxExpr(_day_header_sx(ctx)),
|
||||
entry_header=SxExpr(_entry_header_html(ctx)),
|
||||
entry_admin_header=SxExpr(_entry_admin_header_html(ctx)),
|
||||
ticket_types_header=SxExpr(_ticket_types_header_html(ctx)),
|
||||
ticket_type_header=SxExpr(_ticket_type_header_html(ctx)),
|
||||
post_header=await _post_header_sx(ctx),
|
||||
calendar_header=_calendar_header_sx(ctx),
|
||||
day_header=_day_header_sx(ctx),
|
||||
entry_header=_entry_header_html(ctx),
|
||||
entry_admin_header=_entry_admin_header_html(ctx),
|
||||
ticket_types_header=_ticket_types_header_html(ctx),
|
||||
ticket_type_header=_ticket_type_header_html(ctx),
|
||||
)
|
||||
|
||||
|
||||
async def _ticket_type_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env, oob_header_sx
|
||||
from shared.sx.parser import SxExpr
|
||||
return await render_to_sx_with_env("events-ticket-type-layout-oob", {},
|
||||
ticket_types_oob=SxExpr(_ticket_types_header_html(ctx, oob=True)),
|
||||
ticket_type_oob_wrap=SxExpr(await oob_header_sx("ticket_types-header-child",
|
||||
"ticket_type-header-child", _ticket_type_header_html(ctx))),
|
||||
ticket_types_oob=_ticket_types_header_html(ctx, oob=True),
|
||||
ticket_type_oob_wrap=await oob_header_sx("ticket_types-header-child",
|
||||
"ticket_type-header-child", _ticket_type_header_html(ctx)),
|
||||
)
|
||||
|
||||
|
||||
@@ -464,20 +455,18 @@ async def _ticket_type_oob(ctx: dict, **kw: Any) -> str:
|
||||
|
||||
async def _markets_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env
|
||||
from shared.sx.parser import SxExpr
|
||||
return await render_to_sx_with_env("events-markets-layout-full", {},
|
||||
post_header=SxExpr(await _post_header_sx(ctx)),
|
||||
markets_header=SxExpr(_markets_header_sx(ctx)),
|
||||
post_header=await _post_header_sx(ctx),
|
||||
markets_header=_markets_header_sx(ctx),
|
||||
)
|
||||
|
||||
|
||||
async def _markets_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env, oob_header_sx
|
||||
from shared.sx.parser import SxExpr
|
||||
return await render_to_sx_with_env("events-markets-layout-oob", {},
|
||||
post_oob=SxExpr(await _post_header_sx(ctx, oob=True)),
|
||||
markets_oob_wrap=SxExpr(await oob_header_sx("post-header-child",
|
||||
"markets-header-child", _markets_header_sx(ctx))),
|
||||
post_oob=await _post_header_sx(ctx, oob=True),
|
||||
markets_oob_wrap=await oob_header_sx("post-header-child",
|
||||
"markets-header-child", _markets_header_sx(ctx)),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user