feat(wp-nodes): deserialize_node_input — modules + snapshots + pickOrder

This commit is contained in:
DumiFlex
2026-04-28 14:03:53 +03:00
parent 42804b9caf
commit c319eef276
3 changed files with 81 additions and 0 deletions
View File
@@ -0,0 +1,43 @@
"""Tests for catalog injection at WP_Context node execution + the
backwards-compat path for old workflow JSON. Spec §4.4 / §6 / 5.5.3."""
from __future__ import annotations
from wp_nodes.types import deserialize_node_input
def test_deserialize_returns_modules_with_empty_snapshots_for_legacy_input():
"""Old workflow JSON had only `modules` (a list). The deserializer
returns `(modules, snapshots, pickOrder)` where snapshots defaults to
empty dict and pickOrder defaults to empty list — backwards compat,
spec §4.5."""
legacy = {"modules": [
{"type": "fixed_values", "name": "x", "payload": {"values": []}},
]}
modules, snapshots, pick_order = deserialize_node_input(legacy)
assert len(modules) == 1
assert snapshots == {}
assert pick_order == []
def test_deserialize_extracts_snapshots_and_pickorder_from_new_input():
new_shape = {
"modules": [
{"type": "wildcard", "name": "outfit",
"payload": {"options": [{"value": "x"}]}},
],
"snapshots": {
"ou111111": {
"snapshot_version": 1, "uuid": "ou111111", "type": "wildcard",
"name": "outfit",
"payload": {"options": [{"value": "x"}]},
"payload_hash": "h" * 64,
"source": {"kind": "user"},
},
},
"pickOrder": ["ou111111"],
"snapshotVersion": 1,
}
modules, snapshots, pick_order = deserialize_node_input(new_shape)
assert len(modules) == 1
assert "ou111111" in snapshots
assert pick_order == ["ou111111"]
+38
View File
@@ -124,6 +124,44 @@ def deserialize_modules(payload: str) -> list[Module]:
return [module_from_dict(entry) for entry in raw_modules]
def deserialize_node_input(
raw: "dict[str, Any] | str | None",
) -> "tuple[list[dict[str, Any]], dict[str, Any], list[str]]":
"""Parse a WP_Context node's ``modules`` widget value into the three
parallel concerns the engine needs: an executable module list, a catalog
snapshot dict, and the user's explicit pick order.
Spec §4.4. Backwards-compat: old workflows have no ``snapshots`` /
``pickOrder`` fields — those default to empty (catalog stays {}, no
@{} resolution, raw token leaks in output, current behavior).
"""
if raw is None:
return [], {}, []
if isinstance(raw, str):
try:
data = json.loads(raw)
except Exception:
return [], {}, []
else:
data = raw
if not isinstance(data, dict):
return [], {}, []
raw_modules = data.get("modules")
modules: list[dict[str, Any]] = (
list(raw_modules) if isinstance(raw_modules, list) else []
)
snapshots_raw = data.get("snapshots")
snapshots: dict[str, Any] = (
snapshots_raw if isinstance(snapshots_raw, dict) else {}
)
pick_order_raw = data.get("pickOrder")
pick_order: list[str] = (
pick_order_raw if isinstance(pick_order_raw, list) else []
)
return modules, snapshots, pick_order
def build_payload(
ctx: dict[str, Any],
upstream_debug: dict[str, Any],