Fix _aser_call and sx_call list serialization: use (list ...) for data arrays
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m5s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m5s
Data lists (dicts, strings, numbers) were wrapped in (<> ...) fragments which the client rendered as empty DocumentFragments instead of iterable arrays. This broke map/filter over cards, tag_groups, and authors in blog index and similar components. - _aser_call: data lists → (list ...), rendered content (SxExpr) → (<> ...) - sx_call: all list kwargs → (list ...) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1253,15 +1253,25 @@ async def _aser_call(
|
|||||||
extra_class = val.class_name
|
extra_class = val.class_name
|
||||||
else:
|
else:
|
||||||
parts.append(f":{arg.name}")
|
parts.append(f":{arg.name}")
|
||||||
# Plain list (e.g. from map) → wrap as fragment to
|
# Plain list → serialize for the client.
|
||||||
# avoid ambiguity with function application on re-parse
|
# Rendered items (SxExpr) → wrap in (<> ...) fragment.
|
||||||
|
# Data items (dicts, strings, numbers) → (list ...)
|
||||||
|
# so the client gets an iterable array, not a
|
||||||
|
# DocumentFragment that breaks map/filter.
|
||||||
if isinstance(val, list):
|
if isinstance(val, list):
|
||||||
items = [serialize(v) for v in val
|
live = [v for v in val
|
||||||
if v is not NIL and v is not None]
|
if v is not NIL and v is not None]
|
||||||
parts.append(
|
items = [serialize(v) for v in live]
|
||||||
"(<> " + " ".join(items) + ")" if items
|
if not items:
|
||||||
else "nil"
|
parts.append("nil")
|
||||||
)
|
elif any(isinstance(v, SxExpr) for v in live):
|
||||||
|
parts.append(
|
||||||
|
"(<> " + " ".join(items) + ")"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
parts.append(
|
||||||
|
"(list " + " ".join(items) + ")"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
parts.append(serialize(val))
|
parts.append(serialize(val))
|
||||||
i += 2
|
i += 2
|
||||||
|
|||||||
@@ -404,13 +404,22 @@ def sx_call(component_name: str, **kwargs: Any) -> str:
|
|||||||
|
|
||||||
Values are serialized: strings are quoted, None becomes nil,
|
Values are serialized: strings are quoted, None becomes nil,
|
||||||
bools become true/false, numbers stay as-is.
|
bools become true/false, numbers stay as-is.
|
||||||
|
List values use ``(list ...)`` so the client gets an iterable array
|
||||||
|
rather than a rendered fragment.
|
||||||
"""
|
"""
|
||||||
from .parser import serialize
|
from .parser import serialize, SxExpr
|
||||||
name = component_name if component_name.startswith("~") else f"~{component_name}"
|
name = component_name if component_name.startswith("~") else f"~{component_name}"
|
||||||
parts = [name]
|
parts = [name]
|
||||||
for key, val in kwargs.items():
|
for key, val in kwargs.items():
|
||||||
parts.append(f":{key.replace('_', '-')}")
|
parts.append(f":{key.replace('_', '-')}")
|
||||||
parts.append(serialize(val))
|
if isinstance(val, list):
|
||||||
|
items = [serialize(v) for v in val if v is not None]
|
||||||
|
if not items:
|
||||||
|
parts.append("nil")
|
||||||
|
else:
|
||||||
|
parts.append("(list " + " ".join(items) + ")")
|
||||||
|
else:
|
||||||
|
parts.append(serialize(val))
|
||||||
return "(" + " ".join(parts) + ")"
|
return "(" + " ".join(parts) + ")"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user