Repository: home-assistant/core
File: homeassistant/components/websocket_api/automation.py (Python)

Code before:
    """Get conditions for a target."""
    descriptions = await async_get_all_condition_descriptions(hass)
    return _async_get_automation_components_for_target(
        hass, target_selector, expand_group, descriptions
    )


async def async_get_services_for_target(
    hass: HomeAssistant, target_selector: ConfigType, expand_group: bool
) -> set[str]:
    """Get services for a target."""
    descriptions = await async_get_all_service_descriptions(hass)

    def get_flattened_service_descriptions() -> dict[str, dict[str, Any]]:
        """Get flattened service descriptions, with caching."""
        if FLATTENED_SERVICE_DESCRIPTIONS_CACHE in hass.data:
            cached_descriptions, cached_flattened_descriptions = hass.data[
                FLATTENED_SERVICE_DESCRIPTIONS_CACHE
            ]
            # If the descriptions are the same, return the cached flattened version
            if cached_descriptions is descriptions:
                return cached_flattened_descriptions

        # Flatten dicts to be keyed by domain.name to match trigger/condition format
        flattened_descriptions = {
            f"{domain}.{service_name}": desc
            for domain, services in descriptions.items()
            for service_name, desc in services.items()
        }
        hass.data[FLATTENED_SERVICE_DESCRIPTIONS_CACHE] = (
            descriptions,
            flattened_descriptions,
        )
        return flattened_descriptions

    return _async_get_automation_components_for_target(
        hass, target_selector, expand_group, get_flattened_service_descriptions()
    )


Review comment (performance):
I think it makes the code longer and less readable as a result.

If we don't like a new list for performance reasons, we can instead do:

```py
for component_data in lookup_table.domain_components.get(domain, ()):
```

Code after:
        hass, component_type, component_descriptions
    )
    _LOGGER.debug(
        "Automation components per domain: %s", lookup_table.domain_components
    )

    entity_infos = entity_sources(hass)
    matched_components: set[str] = set()
    for entity_id in extracted.referenced | extracted.indirectly_referenced:
        if lookup_table.component_count == len(matched_components):
            # All automation components matched already, so we don't need to iterate further
            break

        entity_info = entity_infos.get(entity_id)
        if entity_info is None:
            _LOGGER.debug("No entity source found for %s", entity_id)
            continue

        entity_domain = entity_id.split(".")[0]
        entity_integration = entity_info["domain"]
        for domain in (entity_domain, entity_integration, None):
            if not (
                domain_component_data := lookup_table.domain_components.get(domain)
            ):
                continue
            for component_data in domain_component_data:
                if component_data.component in matched_components:
                    continue
                if component_data.matches(
                    hass, entity_id, entity_domain, entity_integration
                ):
                    matched_components.add(component_data.component)

    return matched_components


async def async_get_triggers_for_target(
    hass: HomeAssistant, target_selector: ConfigType, expand_group: bool
) -> set[str]:
    """Get triggers for a target."""
    descriptions = await async_get_all_trigger_descriptions(hass)
    return _async_get_automation_components_for_target(
        hass, "triggers", target_selector, expand_group, descriptions
    )


async def async_get_conditions_for_target(
    hass: HomeAssistant, target_selector: ConfigType, expand_group: bool
) -> set[str]:
    """Get conditions for a target."""
    descriptions = await async_get_all_condition_descriptions(hass)