Skip to content

Commit a0f4043

Browse files
authored
fix: code completion in default aggregation (#499)
1 parent 4ad8c80 commit a0f4043

File tree

3 files changed

+85
-10
lines changed

3 files changed

+85
-10
lines changed

packages/language-server/test/completion-items-spec.ts

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect } from "chai";
2-
import { map, uniq, forEach } from "lodash";
2+
import { map, uniq, forEach, filter } from "lodash";
33
import { CompletionItemKind, TextEdit } from "vscode-languageserver";
44
import { UI5XMLViewCompletion } from "@ui5-language-assistant/xml-views-completion";
55
import { UI5SemanticModel } from "@ui5-language-assistant/semantic-model-types";
@@ -255,7 +255,10 @@ describe("the UI5 language assistant Code Completion Services", () => {
255255
xmlns:mvc="sap.ui.core.mvc"
256256
xmlns="sap.m">
257257
<List> <te⇶`;
258-
const suggestions = getSuggestions(xmlSnippet, ui5SemanticModel);
258+
const suggestions = filter(
259+
getSuggestions(xmlSnippet, ui5SemanticModel),
260+
(suggestion) => suggestion.kind === CompletionItemKind.Field
261+
);
259262
const suggestionsDetails = map(suggestions, (suggestion) => ({
260263
label: suggestion.label,
261264
tagName: getTagName(suggestion.textEdit as TextEdit),
@@ -282,7 +285,10 @@ describe("the UI5 language assistant Code Completion Services", () => {
282285
xmlns:mvc="sap.ui.core.mvc"
283286
xmlns:m="sap.m">
284287
<m:List> <te⇶`;
285-
const suggestions = getSuggestions(xmlSnippet, ui5SemanticModel);
288+
const suggestions = filter(
289+
getSuggestions(xmlSnippet, ui5SemanticModel),
290+
(suggestion) => suggestion.kind === CompletionItemKind.Field
291+
);
286292
const suggestionsDetails = map(suggestions, (suggestion) => ({
287293
label: suggestion.label,
288294
tagName: getTagName(suggestion.textEdit as TextEdit),
@@ -309,7 +315,10 @@ describe("the UI5 language assistant Code Completion Services", () => {
309315
xmlns:mvc="sap.ui.core.mvc"
310316
xmlns="sap.m">
311317
<List> <te⇶Menu`;
312-
const suggestions = getSuggestions(xmlSnippet, ui5SemanticModel);
318+
const suggestions = filter(
319+
getSuggestions(xmlSnippet, ui5SemanticModel),
320+
(suggestion) => suggestion.kind === CompletionItemKind.Field
321+
);
313322
const suggestionsDetails = map(suggestions, (suggestion) => ({
314323
label: suggestion.label,
315324
replacedText: getTextInRange(
@@ -340,7 +349,10 @@ describe("the UI5 language assistant Code Completion Services", () => {
340349
xmlns:mvc="sap.ui.core.mvc"
341350
xmlns:m="sap.m">
342351
<m:List> <te⇶Menu`;
343-
const suggestions = getSuggestions(xmlSnippet, ui5SemanticModel);
352+
const suggestions = filter(
353+
getSuggestions(xmlSnippet, ui5SemanticModel),
354+
(suggestion) => suggestion.kind === CompletionItemKind.Field
355+
);
344356
const suggestionsDetails = map(suggestions, (suggestion) => ({
345357
label: suggestion.label,
346358
replacedText: getTextInRange(
@@ -378,7 +390,10 @@ describe("the UI5 language assistant Code Completion Services", () => {
378390
<te⇶></⭲te⭰>
379391
</List>
380392
</mvc:View>`;
381-
const suggestions = getSuggestions(xmlSnippet, ui5SemanticModel);
393+
const suggestions = filter(
394+
getSuggestions(xmlSnippet, ui5SemanticModel),
395+
(suggestion) => suggestion.kind === CompletionItemKind.Field
396+
);
382397
const suggestionsDetails = map(suggestions, (suggestion) => ({
383398
label: suggestion.label,
384399
tagName: getTagName(suggestion.textEdit as TextEdit),
@@ -442,7 +457,10 @@ describe("the UI5 language assistant Code Completion Services", () => {
442457
<m:te⇶></⭲m:te⭰>
443458
</m:List>
444459
</mvc:View>`;
445-
const suggestions = getSuggestions(xmlSnippet, ui5SemanticModel);
460+
const suggestions = filter(
461+
getSuggestions(xmlSnippet, ui5SemanticModel),
462+
(suggestion) => suggestion.kind === CompletionItemKind.Field
463+
);
446464
const suggestionsDetails = map(suggestions, (suggestion) => ({
447465
label: suggestion.label,
448466
tagName: getTagName(suggestion.textEdit as TextEdit),
@@ -506,7 +524,10 @@ describe("the UI5 language assistant Code Completion Services", () => {
506524
<te⇶></aaa>
507525
</List>
508526
</mvc:View>`;
509-
const suggestions = getSuggestions(xmlSnippet, ui5SemanticModel);
527+
const suggestions = filter(
528+
getSuggestions(xmlSnippet, ui5SemanticModel),
529+
(suggestion) => suggestion.kind === CompletionItemKind.Field
530+
);
510531
const suggestionsDetails = map(suggestions, (suggestion) => ({
511532
label: suggestion.label,
512533
tagName: getTagName(suggestion.textEdit as TextEdit),
@@ -555,7 +576,10 @@ describe("the UI5 language assistant Code Completion Services", () => {
555576
<te⇶>⭲</>⭰
556577
</List>
557578
</mvc:View>`;
558-
const suggestions = getSuggestions(xmlSnippet, ui5SemanticModel);
579+
const suggestions = filter(
580+
getSuggestions(xmlSnippet, ui5SemanticModel),
581+
(suggestion) => suggestion.kind === CompletionItemKind.Field
582+
);
559583
const suggestionsDetails = map(suggestions, (suggestion) => ({
560584
label: suggestion.label,
561585
tagName: getTagName(suggestion.textEdit as TextEdit),

packages/xml-views-completion/src/providers/elementName/classes.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ function handleDefaultAggregationScenario({
156156
parentXMLElement: XMLElement;
157157
parentUI5Class: UI5Class;
158158
}): classSuggestionContext | null {
159-
const defaultAggregation = parentUI5Class.defaultAggregation;
159+
const defaultAggregation = findClosestDefaultAggregation(parentUI5Class);
160+
160161
if (defaultAggregation === undefined) {
161162
return NOT_FOUND;
162163
}
@@ -171,6 +172,25 @@ function handleDefaultAggregationScenario({
171172
}
172173
}
173174

175+
/**
176+
* Traverses class inheritance chain and returns the first default aggregation if it exists.
177+
* @param parentUI5Class UI5 class from which the search for default aggregation starts.
178+
* @returns Instance of the default aggregation if it exists, otherwise undefined.
179+
*/
180+
function findClosestDefaultAggregation(
181+
parentUI5Class: UI5Class
182+
): UI5Aggregation | undefined {
183+
let currentClass: UI5Class | undefined = parentUI5Class;
184+
while (currentClass) {
185+
if (currentClass.defaultAggregation === undefined) {
186+
currentClass = currentClass.extends;
187+
} else {
188+
return currentClass.defaultAggregation;
189+
}
190+
}
191+
return undefined;
192+
}
193+
174194
function getPrefixParts(
175195
originalPrefix: string | undefined,
176196
xmlElement: XMLElement

packages/xml-views-completion/test/providers/elementName/classes-spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,37 @@ describe("The ui5-language-assistant xml-views-completion", () => {
138138
},
139139
});
140140
});
141+
it("will suggest **all** classes matching the type of the default aggregation from inherited control", () => {
142+
const xmlSnippet = `
143+
<mvc:View
144+
xmlns:mvc="sap.ui.core.mvc"
145+
xmlns="sap.m">
146+
<VBox>
147+
<ToggleButton⇶
148+
</VBox>
149+
</mvc:View>`;
150+
151+
testSuggestionsScenario({
152+
model: ui5Model,
153+
xmlText: xmlSnippet,
154+
providers: {
155+
elementName: [classesSuggestions],
156+
},
157+
assertion: (suggestions) => {
158+
assertSuggestionProperties(suggestions, "VBox");
159+
const suggestionNames = map(suggestions, (_) =>
160+
ui5NodeToFQN(_.ui5Node)
161+
);
162+
// Can "manually" traverse expected graph of `sap.m.Button` subClasses here:
163+
// - https://ui5.sap.com/1.71.49/#/api/sap.m.Button
164+
expect(suggestionNames).to.deep.equalInAnyOrder([
165+
"sap.m.OverflowToolbarToggleButton",
166+
"sap.m.ToggleButton",
167+
"sap.ui.commons.ToggleButton",
168+
]);
169+
},
170+
});
171+
});
141172
});
142173

143174
context("prefix without xmlns", () => {

0 commit comments

Comments
 (0)