[vscode] Mark the component key for "Component not found" errors

The `vscode --ace` validator resolves an error's range to the deepest
matching node, which for a "Component not found" error is the component's
value mapping — so the range starts at the first child, and editors
underline the children instead of the offending top-level key. Request
the key's range for these errors (as already done for "extra keys not
allowed"). Backward compatible: only the range for this error type
changes.
This commit is contained in:
J. Nick Koston
2026-06-03 01:09:01 -05:00
parent 997ab11687
commit ce5be77ed6
2 changed files with 40 additions and 3 deletions

View File

@@ -13,9 +13,13 @@ from esphome.yaml_util import parse_yaml
def _get_invalid_range(res: Config, invalid: cv.Invalid) -> DocumentRange | None:
return res.get_deepest_document_range_for_path(
invalid.path, invalid.error_message == "extra keys not allowed"
)
# Errors about the key itself (an unknown option, an unknown component)
# mark the key, not its value mapping — otherwise the range lands on the
# component's children instead of the offending key.
mark_key = invalid.error_message == "extra keys not allowed" or (
invalid.error_message or ""
).startswith("Component not found:")
return res.get_deepest_document_range_for_path(invalid.path, mark_key)
def _dump_range(range: DocumentRange | None) -> dict | None:

View File

@@ -97,6 +97,39 @@ esp8266:
assert range["end_col"] == 7
def test_component_not_found_marks_key():
source_path = str(Path("dir_path", "x.yaml"))
output_lines = _run_repl_test(
[
_validate(source_path),
# read_file x.yaml
_file_response("""esphome:
name: test1
esp8266:
board: esp01_1m
apccci:
id: foo
"""),
]
)
error = json.loads(output_lines[-1])
not_found = next(
e
for e in error["validation_errors"]
if e["message"].startswith("Component not found:")
)
assert not_found["message"] == "Component not found: apccci."
# Range covers the ``apccci`` key, not its child mapping.
range = not_found["range"]
assert range["document"] == source_path
assert range["start_line"] == 5
assert range["start_col"] == 0
assert range["end_line"] == 5
assert range["end_col"] == 6
def test_shows_correct_loaded_file_error():
source_path = str(Path("dir_path", "x.yaml"))
output_lines = _run_repl_test(