Guard against empty SxExpr in _as_sx and _build_component_ast

Fragment responses with text/sx content-type but empty body create
SxExpr(""), which is truthy but fails to parse. Handle this by
returning None from _as_sx for empty SxExpr sources, and treating
empty SxExpr as NIL in _build_component_ast.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 01:37:27 +00:00
parent 41cdd6eab8
commit bd314a0be7

View File

@@ -77,7 +77,7 @@ def _as_sx(val: Any) -> SxExpr | None:
if not val: if not val:
return None return None
if isinstance(val, SxExpr): if isinstance(val, SxExpr):
return val return val if val.source else None
html = str(val) html = str(val)
escaped = html.replace("\\", "\\\\").replace('"', '\\"') escaped = html.replace("\\", "\\\\").replace('"', '\\"')
return SxExpr(f'(~rich-text :html "{escaped}")') return SxExpr(f'(~rich-text :html "{escaped}")')
@@ -376,7 +376,10 @@ def _build_component_ast(__name: str, **kwargs: Any) -> list:
elif isinstance(val, SxExpr): elif isinstance(val, SxExpr):
# SxExpr values need to be parsed into AST # SxExpr values need to be parsed into AST
from .parser import parse from .parser import parse
ast.append(parse(val.source)) if not val.source:
ast.append(NIL)
else:
ast.append(parse(val.source))
else: else:
ast.append(val) ast.append(val)
return ast return ast