From 71f4e36c66140987c2ce5f26a3019bec22972009 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 30 Jun 2026 09:33:12 +1200 Subject: [PATCH] [scripts] Export deprecated component aliases to the schema dump ``build_language_schema.py`` walked ``esphome/components/`` directly, so canonical-only directories left their deprecated aliases invisible to the editor / dashboard autocomplete. Configs migrated only at runtime via the ``_resolve_component_aliases`` pre-pass would still light up as unknown top-level keys. After building the per-component bundles, mirror each canonical entry under every alias declared via ``ALIASES = [...]``, tagging the duplicate with ``alias_of`` (canonical name) and ``removal_version`` (when ``ALIAS_REMOVAL_VERSION`` is set). Schema consumers can render a deprecation hint and point users at the canonical key without losing autocomplete on legacy configs. --- script/build_language_schema.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/script/build_language_schema.py b/script/build_language_schema.py index 974957245a..bc97a0d603 100755 --- a/script/build_language_schema.py +++ b/script/build_language_schema.py @@ -785,6 +785,29 @@ def build_schema(): # bundle core inside esphome data["esphome"]["core"] = data.pop("core")["core"] + # Surface deprecated component aliases (declared via ``ALIASES = [...]`` + # on the canonical component) so language servers / dashboard + # autocomplete still accept legacy top-level keys instead of flagging + # them as unknown. Each alias gets its own bundle that mirrors the + # canonical schema; ``alias_of`` and the optional ``removal_version`` + # metadata let consumers render a deprecation hint and point users at + # the canonical name. Without this, configs migrated only at runtime + # (via the ``_resolve_component_aliases`` pre-pass) would still light + # up as errors in the editor. + for domain, manifest in components.items(): + aliases = manifest.aliases + if not aliases or domain not in data: + continue + canonical_bundle = data[domain].get(domain) + if canonical_bundle is None: + continue + for alias in aliases: + alias_entry = dict(canonical_bundle) + alias_entry["alias_of"] = domain + if manifest.alias_removal_version is not None: + alias_entry["removal_version"] = manifest.alias_removal_version + data[alias] = {alias: alias_entry} + if GENERATED_ID_TYPES: print( "Unconsumed id_type matchers:",