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:
@@ -1,4 +1,5 @@
|
||||
;; Market container-nav fragment handler
|
||||
;; returns: sx
|
||||
;;
|
||||
;; Renders marketplace link nav items for blog post pages.
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
;; Market link-card fragment handler
|
||||
;; returns: sx
|
||||
;;
|
||||
;; Renders product preview card(s) by slug.
|
||||
;; Supports single mode (?slug=x) and batch mode (?keys=x,y,z).
|
||||
|
||||
@@ -188,9 +188,9 @@ def _market_card_sx(market: Any, page_info: dict, *, show_page_badge: bool = Tru
|
||||
|
||||
return sx_call(
|
||||
"market-market-card",
|
||||
title_content=SxExpr(title_sx) if title_sx else None,
|
||||
desc_content=SxExpr(desc_sx) if desc_sx else None,
|
||||
badge_content=SxExpr(badge_sx) if badge_sx else None,
|
||||
title_content=title_sx or None,
|
||||
desc_content=desc_sx or None,
|
||||
badge_content=badge_sx or None,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ async def _desktop_filter_sx(ctx: dict) -> str:
|
||||
if brands:
|
||||
brand_inner = _brand_filter_sx(brands, selected_brands, ctx)
|
||||
brand_summary = sx_call("market-desktop-brand-summary",
|
||||
inner=SxExpr(brand_inner) if brand_inner else None)
|
||||
inner=brand_inner or None)
|
||||
|
||||
return "(<> " + " ".join([search_sx, cat_summary, brand_summary]) + ")"
|
||||
|
||||
@@ -226,8 +226,8 @@ async def _mobile_filter_summary_sx(ctx: dict) -> str:
|
||||
|
||||
return sx_call(
|
||||
"market-mobile-filter-summary",
|
||||
search_bar=SxExpr(search_bar),
|
||||
chips=SxExpr(chips_row),
|
||||
search_bar=search_bar,
|
||||
chips=chips_row,
|
||||
filter=SxExpr(mobile_filter),
|
||||
)
|
||||
|
||||
|
||||
@@ -151,10 +151,9 @@ async def _h_page_markets_content(slug=None, **kw):
|
||||
async def _h_page_admin_content(slug=None, **kw):
|
||||
from shared.sx.page import get_template_context
|
||||
from shared.sx.helpers import sx_call
|
||||
from shared.sx.parser import SxExpr
|
||||
ctx = await get_template_context()
|
||||
content = await _markets_admin_panel_sx(ctx)
|
||||
return sx_call("market-admin-content-wrap", inner=SxExpr(content))
|
||||
return sx_call("market-admin-content-wrap", inner=content)
|
||||
|
||||
|
||||
def _h_market_home_content(page_slug=None, market_slug=None, **kw):
|
||||
|
||||
@@ -44,8 +44,8 @@ def _market_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
||||
return sx_call(
|
||||
"menu-row-sx",
|
||||
id="market-row", level=2,
|
||||
link_href=link_href, link_label_content=SxExpr(label_sx),
|
||||
nav=SxExpr(nav_sx) if nav_sx else None,
|
||||
link_href=link_href, link_label_content=label_sx,
|
||||
nav=nav_sx or None,
|
||||
child_id="market-header-child", oob=oob,
|
||||
)
|
||||
|
||||
@@ -87,7 +87,7 @@ def _desktop_category_nav_sx(ctx: dict, categories: dict, qs: str,
|
||||
|
||||
return sx_call("market-desktop-category-nav",
|
||||
links=SxExpr(links_sx),
|
||||
admin=SxExpr(admin_sx) if admin_sx else None)
|
||||
admin=admin_sx or None)
|
||||
|
||||
|
||||
def _product_header_sx(ctx: dict, d: dict, *, oob: bool = False) -> str:
|
||||
@@ -117,7 +117,7 @@ def _product_header_sx(ctx: dict, d: dict, *, oob: bool = False) -> str:
|
||||
return sx_call(
|
||||
"menu-row-sx",
|
||||
id="product-row", level=3,
|
||||
link_href=link_href, link_label_content=SxExpr(label_sx),
|
||||
link_href=link_href, link_label_content=label_sx,
|
||||
nav=SxExpr(nav_sx), child_id="product-header-child", oob=oob,
|
||||
)
|
||||
|
||||
@@ -219,7 +219,7 @@ def _mobile_nav_panel_sx(ctx: dict) -> str:
|
||||
bg_cls=bg_cls, href=cat_href, hx_select=hx_select,
|
||||
select_colours=select_colours, cat_name=cat,
|
||||
count_label=f"{cat_count} products", count_str=str(cat_count),
|
||||
chevron=SxExpr(chevron_sx),
|
||||
chevron=chevron_sx,
|
||||
)
|
||||
|
||||
subs = data.get("subs", [])
|
||||
@@ -246,8 +246,8 @@ def _mobile_nav_panel_sx(ctx: dict) -> str:
|
||||
item_parts.append(sx_call(
|
||||
"market-mobile-cat-details",
|
||||
open=cat_active or None,
|
||||
summary=SxExpr(summary_sx),
|
||||
subs=SxExpr(subs_sx),
|
||||
summary=summary_sx,
|
||||
subs=subs_sx,
|
||||
))
|
||||
|
||||
items_sx = "(<> " + " ".join(item_parts) + ")"
|
||||
@@ -295,16 +295,16 @@ def _register_market_layouts() -> None:
|
||||
async def _market_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env
|
||||
return await render_to_sx_with_env("market-browse-layout-full", {},
|
||||
post_header=SxExpr(await _post_header_sx(ctx)),
|
||||
market_header=SxExpr(_market_header_sx(ctx)))
|
||||
post_header=await _post_header_sx(ctx),
|
||||
market_header=_market_header_sx(ctx))
|
||||
|
||||
|
||||
async def _market_oob(ctx: dict, **kw: Any) -> str:
|
||||
oob_hdr = await _oob_header_sx("post-header-child", "market-header-child",
|
||||
_market_header_sx(ctx))
|
||||
return sx_call("market-browse-layout-oob",
|
||||
oob_header=SxExpr(oob_hdr),
|
||||
post_header_oob=SxExpr(await _post_header_sx(ctx, oob=True)),
|
||||
oob_header=oob_hdr,
|
||||
post_header_oob=await _post_header_sx(ctx, oob=True),
|
||||
clear_oob=SxExpr(_clear_deeper_oob("post-row", "post-header-child",
|
||||
"market-row", "market-header-child")))
|
||||
|
||||
@@ -317,17 +317,17 @@ async def _market_admin_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env
|
||||
selected = kw.get("selected", "")
|
||||
return await render_to_sx_with_env("market-admin-layout-full", {},
|
||||
post_header=SxExpr(await _post_header_sx(ctx)),
|
||||
market_header=SxExpr(_market_header_sx(ctx)),
|
||||
admin_header=SxExpr(await _market_admin_header_sx(ctx, selected=selected)))
|
||||
post_header=await _post_header_sx(ctx),
|
||||
market_header=_market_header_sx(ctx),
|
||||
admin_header=await _market_admin_header_sx(ctx, selected=selected))
|
||||
|
||||
|
||||
async def _market_admin_oob(ctx: dict, **kw: Any) -> str:
|
||||
selected = kw.get("selected", "")
|
||||
return sx_call("market-admin-layout-oob",
|
||||
market_header_oob=SxExpr(_market_header_sx(ctx, oob=True)),
|
||||
admin_oob_header=SxExpr(await _oob_header_sx("market-header-child", "market-admin-header-child",
|
||||
await _market_admin_header_sx(ctx, selected=selected))),
|
||||
market_header_oob=_market_header_sx(ctx, oob=True),
|
||||
admin_oob_header=await _oob_header_sx("market-header-child", "market-admin-header-child",
|
||||
await _market_admin_header_sx(ctx, selected=selected)),
|
||||
clear_oob=SxExpr(_clear_deeper_oob("post-row", "post-header-child",
|
||||
"market-row", "market-header-child",
|
||||
"market-admin-row", "market-admin-header-child")))
|
||||
|
||||
@@ -37,8 +37,8 @@ async def render_browse_page(ctx: dict) -> str:
|
||||
|
||||
from shared.sx.helpers import render_to_sx_with_env
|
||||
hdr = await render_to_sx_with_env("market-browse-layout-full", {},
|
||||
post_header=SxExpr(await _post_header_sx(ctx)),
|
||||
market_header=SxExpr(_market_header_sx(ctx)))
|
||||
post_header=await _post_header_sx(ctx),
|
||||
market_header=_market_header_sx(ctx))
|
||||
menu = _mobile_nav_panel_sx(ctx)
|
||||
filter_sx = await _mobile_filter_summary_sx(ctx)
|
||||
aside_sx = await _desktop_filter_sx(ctx)
|
||||
@@ -55,8 +55,8 @@ async def render_browse_oob(ctx: dict) -> str:
|
||||
oob_hdr = await _oob_header_sx("post-header-child", "market-header-child",
|
||||
_market_header_sx(ctx))
|
||||
oobs = sx_call("market-browse-layout-oob",
|
||||
oob_header=SxExpr(oob_hdr),
|
||||
post_header_oob=SxExpr(await _post_header_sx(ctx, oob=True)),
|
||||
oob_header=oob_hdr,
|
||||
post_header_oob=await _post_header_sx(ctx, oob=True),
|
||||
clear_oob=SxExpr(_clear_deeper_oob("post-row", "post-header-child",
|
||||
"market-row", "market-header-child")))
|
||||
menu = _mobile_nav_panel_sx(ctx)
|
||||
@@ -83,9 +83,9 @@ async def render_product_page(ctx: dict, d: dict) -> str:
|
||||
|
||||
from shared.sx.helpers import render_to_sx_with_env
|
||||
hdr = await render_to_sx_with_env("market-product-layout-full", {},
|
||||
post_header=SxExpr(await _post_header_sx(ctx)),
|
||||
market_header=SxExpr(_market_header_sx(ctx)),
|
||||
product_header=SxExpr(_product_header_sx(ctx, d)))
|
||||
post_header=await _post_header_sx(ctx),
|
||||
market_header=_market_header_sx(ctx),
|
||||
product_header=_product_header_sx(ctx, d))
|
||||
return await full_page_sx(ctx, header_rows=hdr, content=content, meta=meta)
|
||||
|
||||
|
||||
@@ -114,10 +114,10 @@ async def render_product_admin_page(ctx: dict, d: dict) -> str:
|
||||
|
||||
from shared.sx.helpers import render_to_sx_with_env
|
||||
hdr = await render_to_sx_with_env("market-product-admin-layout-full", {},
|
||||
post_header=SxExpr(await _post_header_sx(ctx)),
|
||||
market_header=SxExpr(_market_header_sx(ctx)),
|
||||
product_header=SxExpr(_product_header_sx(ctx, d)),
|
||||
admin_header=SxExpr(_product_admin_header_sx(ctx, d)))
|
||||
post_header=await _post_header_sx(ctx),
|
||||
market_header=_market_header_sx(ctx),
|
||||
product_header=_product_header_sx(ctx, d),
|
||||
admin_header=_product_admin_header_sx(ctx, d))
|
||||
return await full_page_sx(ctx, header_rows=hdr, content=content)
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ def render_cart_added_response(cart: list, item: Any, d: dict) -> str:
|
||||
add_sx = sx_call(
|
||||
"market-cart-add-oob",
|
||||
id=f"cart-add-{slug}",
|
||||
inner=SxExpr(cart_add),
|
||||
inner=cart_add,
|
||||
)
|
||||
|
||||
return "(<> " + cart_mini + " " + add_sx + ")"
|
||||
|
||||
@@ -110,7 +110,7 @@ def _product_detail_sx(d: dict, ctx: dict) -> str:
|
||||
|
||||
gallery_inner = sx_call(
|
||||
"market-detail-gallery-inner",
|
||||
like=SxExpr(like_sx) if like_sx else None,
|
||||
like=like_sx or None,
|
||||
image=images[0], alt=d.get("title", ""),
|
||||
labels=SxExpr(labels_sx) if labels_sx else None,
|
||||
brand=brand,
|
||||
@@ -123,8 +123,8 @@ def _product_detail_sx(d: dict, ctx: dict) -> str:
|
||||
|
||||
gallery_sx = sx_call(
|
||||
"market-detail-gallery",
|
||||
inner=SxExpr(gallery_inner),
|
||||
nav=SxExpr(nav_buttons) if nav_buttons else None,
|
||||
inner=gallery_inner,
|
||||
nav=nav_buttons or None,
|
||||
)
|
||||
|
||||
# Thumbnails
|
||||
@@ -144,7 +144,7 @@ def _product_detail_sx(d: dict, ctx: dict) -> str:
|
||||
if user:
|
||||
like_sx = _like_button_sx(slug, liked_by_current_user, csrf, ctx)
|
||||
gallery_final = sx_call("market-detail-no-image",
|
||||
like=SxExpr(like_sx) if like_sx else None)
|
||||
like=like_sx or None)
|
||||
|
||||
# Stickers below gallery
|
||||
stickers_sx = ""
|
||||
@@ -206,8 +206,8 @@ def _product_detail_sx(d: dict, ctx: dict) -> str:
|
||||
return sx_call(
|
||||
"market-detail-layout",
|
||||
gallery=SxExpr(gallery_final),
|
||||
stickers=SxExpr(stickers_sx) if stickers_sx else None,
|
||||
details=SxExpr(details_sx),
|
||||
stickers=stickers_sx or None,
|
||||
details=details_sx,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user