feat: param_value context — enum/allowed completions for principalType, environmentType etc.
All checks were successful
Build and Deploy iLSP / test (push) Successful in 20s
Build and Deploy iLSP / build-and-deploy (push) Successful in 1m20s

- Add _KNOWN_ENUMS dict (principalType, principalObjectType, environmentType fallbacks)
- Add param_value_completion_items() to BicepModuleCatalog
- Detect 'param_value' context in _detect_context() (cursor after 'param: ' inside params block)
- Wire param_value into _inject_completions()
- 9 new unit tests (context detection, catalog allowed, known enum fallback, injection)
- Fix modules.py edit regression (param_completion_items was orphaned)
- All 35 tests pass
This commit is contained in:
Henrik Jess Nielsen
2026-05-10 15:30:31 +02:00
parent bf24b5677f
commit b93aa84737
4 changed files with 507 additions and 3 deletions

View File

@@ -240,7 +240,7 @@ def test_detect_param_context():
"module myMod 'br/modules:roleassignments:1.1.x' = {",
" name: 'test'",
" params: {",
" ", # ← cursor here
" ", # ← cursor here (blank line, no param name yet)
" }",
"}",
]
@@ -251,6 +251,124 @@ def test_detect_param_context():
assert ctx["version"] == "1.1.x"
def test_detect_param_value_context_no_quote():
"""Cursor after 'principalType: ' (no opening quote) → param_value context."""
lines = [
"module myMod 'br/modules:roleassignments:1.1.x' = {",
" params: {",
" principalType: ", # ← cursor at end
" }",
"}",
]
session = _make_session_with_doc(URI, lines)
# character = len(" principalType: ") = 19
ctx = session._detect_context(URI, {"line": 2, "character": 19})
assert ctx["type"] == "param_value"
assert ctx["module"] == "roleassignments"
assert ctx["param"] == "principalType"
assert ctx["has_open_quote"] is False
def test_detect_param_value_context_open_quote():
"""Cursor after 'principalType: \\'' → param_value with has_open_quote=True."""
lines = [
"module myMod 'br/modules:roleassignments:1.1.x' = {",
" params: {",
" principalType: '", # ← cursor after opening quote
" }",
"}",
]
session = _make_session_with_doc(URI, lines)
ctx = session._detect_context(URI, {"line": 2, "character": 20})
assert ctx["type"] == "param_value"
assert ctx["has_open_quote"] is True
def test_param_value_items_from_catalog_allowed():
"""environmentType completions come from catalog 'allowed' field."""
BicepModuleCatalog._modules = [_make_module(
"roleassignments",
versions=["1.1.x"],
schema={"1.1.x": {"parameters": {
"environmentType": {"type": "string", "allowed": ["DEV", "TEST", "PROD"]},
}}},
)]
items = BicepModuleCatalog.param_value_completion_items(
"roleassignments", "1.1.x", "environmentType"
)
labels = [i["label"] for i in items]
assert labels == ["DEV", "TEST", "PROD"]
# Without open quote, insertText should wrap in quotes
assert items[0]["insertText"] == "'DEV'"
def test_param_value_items_open_quote():
"""When has_open_quote=True, insertText closes the quote but doesn't open one."""
BicepModuleCatalog._modules = [_make_module(
"roleassignments",
versions=["1.1.x"],
schema={"1.1.x": {"parameters": {
"environmentType": {"type": "string", "allowed": ["DEV", "TEST", "PROD"]},
}}},
)]
items = BicepModuleCatalog.param_value_completion_items(
"roleassignments", "1.1.x", "environmentType", has_open_quote=True
)
assert items[0]["insertText"] == "DEV'"
def test_param_value_items_known_enum_fallback():
"""principalType uses _KNOWN_ENUMS fallback when not in catalog."""
BicepModuleCatalog._modules = [_make_module(
"roleassignments",
versions=["1.1.x"],
schema={"1.1.x": {"parameters": {
"principalType": {"type": "string"}, # no 'allowed' in catalog
}}},
)]
items = BicepModuleCatalog.param_value_completion_items(
"roleassignments", "1.1.x", "principalType"
)
labels = [i["label"] for i in items]
assert "Group" in labels
assert "ServicePrincipal" in labels
assert "User" in labels
def test_param_value_items_empty_for_free_string():
"""A plain string param with no allowed values returns no completions."""
BicepModuleCatalog._modules = [_make_module(
"roleassignments",
versions=["1.1.x"],
schema={"1.1.x": {"parameters": {
"principalId": {"type": "string"},
}}},
)]
items = BicepModuleCatalog.param_value_completion_items(
"roleassignments", "1.1.x", "principalId"
)
assert items == []
def test_param_value_injected_in_completion_response():
"""Full pipeline: param_value context injects enum completions at top."""
BicepModuleCatalog._modules = [_make_module(
"roleassignments",
versions=["1.1.x"],
schema={"1.1.x": {"parameters": {
"environmentType": {"type": "string", "allowed": ["DEV", "TEST", "PROD"]},
}}},
)]
msg = _completion_response([{"label": "existing", "sortText": "z"}])
ctx = {"type": "param_value", "module": "roleassignments", "version": "1.1.x",
"param": "environmentType", "has_open_quote": False}
out = json.loads(_inject_completions(msg, ctx))
labels = [i["label"] for i in out["result"]["items"]]
# LRU enum values should be first
assert labels[:3] == ["DEV", "TEST", "PROD"]
assert "existing" in labels
def test_detect_unknown_context_outside_module():
lines = ["var x = 'hello'"]
session = _make_session_with_doc(URI, lines)