feat(wp-api): extract_referenced_uuids helper for lazy catalog roots

This commit is contained in:
DumiFlex
2026-04-28 13:13:59 +03:00
parent aa8e43e34b
commit 339a3f38f2
2 changed files with 66 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
"""extract_referenced_uuids — used by Test Runner to collect lazy-walk
roots from incoming request bodies. Walks the whole nested structure
because requests can put @{uuid} refs inside payload, instance overrides,
or any other text-bearing field."""
from __future__ import annotations
from wp_api._helpers import extract_referenced_uuids
def test_finds_refs_in_nested_string_values():
body = {
"type": "wildcard",
"payload": {
"options": [
{"value": "red @{aabbccdd} thing", "weight": 1},
{"value": "no ref here", "weight": 1},
],
},
"instance": {"variable_binding": "color"},
}
assert extract_referenced_uuids(body) == {"aabbccdd"}
def test_finds_multiple_refs_dedups():
body = {"v": "@{aaaaaaaa} and @{bbbbbbbb} and @{aaaaaaaa} again"}
assert extract_referenced_uuids(body) == {"aaaaaaaa", "bbbbbbbb"}
def test_ignores_text_that_is_not_a_valid_ref():
body = {"v": "@{not-hex} @{toolong12345} @{TOOSHORT}"}
assert extract_referenced_uuids(body) == set()
def test_empty_or_missing_payload_returns_empty_set():
assert extract_referenced_uuids({}) == set()
assert extract_referenced_uuids({"payload": None}) == set()
+30
View File
@@ -7,6 +7,8 @@ from typing import Any
from aiohttp import web
from engine.db.connection import get_connection
from engine.syntax.tokenize import tokenize_text
from engine.syntax.types import TokenKind
@contextmanager
@@ -28,3 +30,31 @@ def json_ok(data: Any, *, status: int = 200) -> web.Response:
def json_error(message: str, *, status: int) -> web.Response:
return web.json_response({"error": message}, status=status)
def extract_referenced_uuids(payload: Any) -> set[str]:
"""Recursively scan strings inside `payload` for `@{8hex}` refs and
return the set of unique uuids referenced.
Used by the SPA Test Runner to determine which wildcards must be
loaded from the library before resolution can proceed (lazy catalog,
spec §2.10). Reuses the engine tokenizer so the regex shape stays
locked in one place."""
refs: set[str] = set()
def _scan(value: Any) -> None:
if isinstance(value, str):
for tok in tokenize_text(value):
if tok.kind == TokenKind.REF:
uuid = (tok.meta or {}).get("uuid")
if isinstance(uuid, str):
refs.add(uuid)
elif isinstance(value, dict):
for v in value.values():
_scan(v)
elif isinstance(value, list):
for item in value:
_scan(item)
_scan(payload)
return refs