Source code for sinch.domains.voice.helpers.v2.svaml.menu

from collections.abc import Mapping, Sequence
from typing import Any, Dict, Iterator, List, Literal, Union, cast

from sinch.core.models.internal.utils import strip_unset
from sinch.core.sentinel import UNSET, UnsetOr
from sinch.domains.voice.helpers.v2.svaml.internal.utils import as_commands
from sinch.domains.voice.models.v2.svaml.types import (
    GotoMenuCommandDict,
    MenuCommandDict,
    MenuItemDict,
    MenuPromptDict,
    MessageDict,
    NamedMenuItemDict,
    SvamlCommandDict,
)


def _goto_targets(value: Any) -> Iterator[str]:
    """Yields the menu names referenced by ``gotoMenu`` commands in value.

    Nested ``menu`` commands are skipped: they define their own context.
    """
    if isinstance(value, Sequence) and not isinstance(value, str):
        for item in value:
            yield from _goto_targets(item)
    elif isinstance(value, dict):
        command = value.get("command")
        if command == "menu":
            return
        if command == "gotoMenu":
            yield value["menu_name"]
            return
        for item in value.values():
            yield from _goto_targets(item)


def _check_references(start_menu: str, menus: Mapping[str, Any]) -> None:
    """Raises if the start menu or a ``gotoMenu`` target is not in menus."""
    if start_menu not in menus:
        raise ValueError(f"Start menu '{start_menu}' is not defined")
    for target in _goto_targets(list(menus.values())):
        if target not in menus:
            raise ValueError(f"Go-to target menu '{target}' is not defined")