feat: add semantic draft authoring operations
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
from typing import Any
|
||||
|
||||
from wf_core.paths import GraphSourcePath, LocalPath, StatePath
|
||||
|
||||
|
||||
def draft_step(draft: Mapping[str, Any], step_id: str) -> Mapping[str, Any]:
|
||||
"""Return one step mapping from a draft, raising on missing or non-object."""
|
||||
steps = draft.get("steps", {})
|
||||
if not isinstance(steps, Mapping):
|
||||
raise KeyError("draft steps are not available")
|
||||
step = steps[step_id]
|
||||
if not isinstance(step, Mapping):
|
||||
raise KeyError(f"draft step {step_id!r} is not an object")
|
||||
return step
|
||||
|
||||
|
||||
def escape_json_pointer(value: str) -> str:
|
||||
"""Escape one JSON Pointer path segment for generated JSON Patch helpers."""
|
||||
return value.replace("~", "~0").replace("/", "~1")
|
||||
|
||||
|
||||
def input_bindings_payload(
|
||||
input_map: dict[str, str],
|
||||
input_values: dict[str, Any],
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Serialize draft input maps into canonical string-path binding payloads."""
|
||||
return [
|
||||
{"target": _local_path_payload(target), "value": value}
|
||||
for target, value in input_values.items()
|
||||
] + [
|
||||
{"target": _local_path_payload(target), "path": _graph_path_payload(source)}
|
||||
for source, target in input_map.items()
|
||||
]
|
||||
|
||||
|
||||
def output_bindings_payload(output_map: dict[str, str]) -> list[dict[str, Any]]:
|
||||
"""Serialize draft output maps into canonical string-path binding payloads."""
|
||||
return [
|
||||
{"source": _local_path_payload(source), "target": _state_path_payload(target)}
|
||||
for source, target in output_map.items()
|
||||
]
|
||||
|
||||
|
||||
def state_root_field(value: str) -> str:
|
||||
"""Return the single root field name from a state path, or raise."""
|
||||
path = StatePath.parse(value)
|
||||
if len(path.parts) != 1:
|
||||
raise ValueError("state_path must name one root field, such as state.after")
|
||||
return path.parts[0]
|
||||
|
||||
|
||||
def _local_path_payload(value: str) -> str:
|
||||
return LocalPath._serialize(LocalPath.parse(value))
|
||||
|
||||
|
||||
def _graph_path_payload(value: str | GraphSourcePath) -> str:
|
||||
path = value if isinstance(value, GraphSourcePath) else GraphSourcePath.parse(value)
|
||||
return GraphSourcePath._serialize(path)
|
||||
|
||||
|
||||
def _state_path_payload(value: str) -> str:
|
||||
return StatePath._serialize(StatePath.parse(value))
|
||||
Reference in New Issue
Block a user