"""NameLookup class."""
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Union
from text_lint.config import LOOKUP_STATIC_VALUE_MARKER
from text_lint.operations.bases.operation_base import YAML_EXAMPLE_SECTIONS
from text_lint.operations.lookups.bases.lookup_base import LookupBase
from text_lint.results.tree import ResultTree
from text_lint.utilities.translations import _, f
if TYPE_CHECKING: # pragma: no cover
from text_lint.linter.states import LookupState
from text_lint.results.cursor import AliasResultForestCursor
from text_lint.results.forest import AliasLookupResult
YAML_EXAMPLE_COMPONENTS = (
_("static value lookup example"),
_(
"A static value can be used in the source position "
"of a lookup expression."
),
)
YAML_EXAMPLE = """
- name: {0}
operation: validate_debug
saved:
- example.capture(1).to_group().~static_value
- ~static_value
{notes_section}:
- {1}
""".format(*YAML_EXAMPLE_COMPONENTS, **YAML_EXAMPLE_SECTIONS)
[Doku]
class NameLookup(LookupBase):
"""NameLookup operation for ResultForest instances."""
hint = _("select a static value from a save id")
operation = "name"
yaml_example = YAML_EXAMPLE
msg_fmt_failure_description = _("Could not find the specified value.")
[Doku]
def apply(
self,
state: "LookupState",
) -> None:
"""Select the specified tree from the current ResultForest location."""
search_string = self.lookup_name[len(LOOKUP_STATIC_VALUE_MARKER):]
state.cursor.flatten()
self._update_location(state, search_string)
self._update_results(state, search_string)
def _update_location(
self,
state: "LookupState",
search_string: str,
) -> None:
matches: "AliasResultForestCursor" = []
self._find_matching_result_tree(
state.cursor.location,
search_string,
matches,
)
if matches:
state.cursor.location = matches
def _find_matching_result_tree(
self,
location: Union[ResultTree, "AliasResultForestCursor"],
search_string: str,
matches: "AliasResultForestCursor",
) -> None:
if isinstance(location, ResultTree):
if isinstance(location.value, str):
if search_string == location.value:
matches.append(location)
if isinstance(location.value, list):
if search_string in location.value:
matches.append(location)
else:
for nested_tree in location:
self._find_matching_result_tree(
nested_tree,
search_string,
matches,
)
def _update_results(
self,
state: "LookupState",
search_string: str,
) -> None:
matches = self._find_matching_result(
state.results,
search_string,
)
if not matches:
state.fail(
translated_description=f(
self.msg_fmt_failure_description,
nl=1,
),
operation=self,
)
else:
state.results = matches
def _find_matching_result(
self,
result: "AliasLookupResult",
search_string: str,
) -> Optional["AliasLookupResult"]:
if isinstance(result, str):
if search_string == result:
return result
if isinstance(result, (list, tuple)):
return self._find_match_result_in_iterable(result, search_string)
if isinstance(result, dict):
return self._find_match_result_in_dict(
result,
search_string,
)
return None
def _find_match_result_in_iterable(
self,
result: Union[Tuple["AliasLookupResult", ...], List["AliasLookupResult"]],
search_string: str,
) -> Optional["AliasLookupResult"]:
if search_string in result:
return result
matches = [
filtered_value for filtered_value in [
self._find_matching_result(
nested_result,
search_string,
) for nested_result in result
] if filtered_value
]
if matches:
return matches
return None
def _find_match_result_in_dict(
self,
result: Dict[str, "AliasLookupResult"],
search_string: str,
) -> Optional["AliasLookupResult"]:
if search_string in result.keys():
return result
for value in result.values():
if search_string in value:
return value
return None