From 6347b8964a0e5edaff615ea7ab499faed19905e6 Mon Sep 17 00:00:00 2001 From: Maruf Rasully Date: Thu, 2 Jan 2025 16:58:43 +0300 Subject: [PATCH] fix: vSorterInfo issue --- packages/binding/src/definition/definition.ts | 97 +++++++++++++------ .../binding/src/services/completion/index.ts | 8 +- .../services/completion/providers/binding.ts | 13 ++- .../completion/aggregation-binding.test.ts | 19 ++++ 4 files changed, 99 insertions(+), 38 deletions(-) diff --git a/packages/binding/src/definition/definition.ts b/packages/binding/src/definition/definition.ts index c861b2be1..f29c900b6 100644 --- a/packages/binding/src/definition/definition.ts +++ b/packages/binding/src/definition/definition.ts @@ -24,6 +24,7 @@ import { getSorterPossibleElement } from "./sorter"; import { getFiltersPossibleElement } from "./filter"; import type { UI5Aggregation, + UI5ConstructorParameters, UI5TypedefProp, } from "@ui5-language-assistant/semantic-model-types"; @@ -111,6 +112,55 @@ const getReference = (type: UI5Type) => { return reference; }; +function getParameterProperties(param: { + context: BindContext; + parameterProperties: UI5ConstructorParameters[]; + ui5Aggregation?: UI5Aggregation; + forHover?: boolean; + type: UI5Class; +}): BindingInfoElement[] { + const result: BindingInfoElement[] = []; + const { + ui5Aggregation, + forHover = false, + type, + context, + parameterProperties, + } = param; + for (const param of parameterProperties) { + if (!param.type) { + continue; + } + // add reference to type and avoid recursion + const paramType = param.type; + const reference = getReference(paramType); + const data: BindingInfoElement = { + name: param.name, + // eslint-disable-next-line @typescript-eslint/no-use-before-define + type: buildType({ + context, + type: paramType, + name: param.name, + collection: false, + ui5Aggregation, + forHover, + reference, + }), + documentation: getDocumentation({ + context, + prop: param, + FQN: ui5NodeToFQN(type), + titlePrefix: "(class)", + forHover, + }), + }; + data.required = !param.optional; + result.push(data); + } + + return result; +} + /** * Currently [api.json](https://ui5.sap.com/1.118.1/test-resources/sap/ui/core/designtime/api.json) provides these constructor parameters as old school convention * e.g `sPath` for `path` where `s` stands for string type. These params are [map in runtime](https://github.com/SAP/openui5/blob/master/src/sap.ui.core/src/sap/ui/model/Sorter.js#L54-L60). @@ -144,8 +194,17 @@ const getPossibleElement = (param: { if (!constParam.type) { continue; } - const reference = getReference(constParam.type); const name = sorterMap.get(constParam.name) ?? constParam.name; + if (name === "vSorterInfo" && constParam.parameterProperties) { + result.push( + ...getParameterProperties({ + ...param, + parameterProperties: constParam.parameterProperties, + }) + ); + continue; + } + const reference = getReference(constParam.type); const data: BindingInfoElement = { name, // eslint-disable-next-line @typescript-eslint/no-use-before-define @@ -179,36 +238,12 @@ const getPossibleElement = (param: { // use fallback filter return getFiltersPossibleElement(); } - for (const param of vFilter.parameterProperties) { - if (!param.type) { - continue; - } - // add reference to type and avoid recursion - const paramType = param.type; - const reference = getReference(paramType); - const data: BindingInfoElement = { - name: param.name, - // eslint-disable-next-line @typescript-eslint/no-use-before-define - type: buildType({ - context, - type: paramType, - name: param.name, - collection: false, - ui5Aggregation, - forHover, - reference, - }), - documentation: getDocumentation({ - context, - prop: param, - FQN: ui5NodeToFQN(type), - titlePrefix: "(class)", - forHover, - }), - }; - data.required = !param.optional; - result.push(data); - } + result.push( + ...getParameterProperties({ + ...param, + parameterProperties: vFilter.parameterProperties, + }) + ); } return result; }; diff --git a/packages/binding/src/services/completion/index.ts b/packages/binding/src/services/completion/index.ts index c646ce33d..ef5071b95 100644 --- a/packages/binding/src/services/completion/index.ts +++ b/packages/binding/src/services/completion/index.ts @@ -39,14 +39,10 @@ export function getCompletionItems(opts: { attributeValue: attributeValueProviders, }, }); - const uniqueSuggestion = [ - ...new Set(suggestions.map((i) => JSON.stringify(i))), - ].map((i) => JSON.parse(i)); - getLogger().trace("computed completion items", { - uniqueSuggestion, + suggestions, }); - return uniqueSuggestion; + return suggestions; } catch (error) { getLogger().debug("getCompletionItems failed:", error); return []; diff --git a/packages/binding/src/services/completion/providers/binding.ts b/packages/binding/src/services/completion/providers/binding.ts index 2db2ddffd..713fe2b7f 100644 --- a/packages/binding/src/services/completion/providers/binding.ts +++ b/packages/binding/src/services/completion/providers/binding.ts @@ -17,6 +17,7 @@ import { import { BindContext } from "../../../types"; import { createInitialSnippet } from "./create-initial-snippet"; import { + getAltTypesPrime, getCursorContext, getLogger, isMacrosMetaContextPath, @@ -138,7 +139,17 @@ export function bindingSuggestions({ ) ); } - return completionItems; + + const altTypes = getAltTypesPrime(ui5Aggregation); + if (altTypes) { + // for `altTypes`, `PROPERTY_BINDING_INFO` properties are added (duplicate allowed) + return completionItems; + } + // Remove duplicates + const uniqueCompletionItems = Array.from( + new Map(completionItems.map((item) => [item.label, item])).values() + ); + return uniqueCompletionItems; } catch (error) { getLogger().debug("bindingSuggestions failed:", error); return []; diff --git a/packages/binding/test/unit/services/completion/aggregation-binding.test.ts b/packages/binding/test/unit/services/completion/aggregation-binding.test.ts index 28937a0e9..17651ef40 100644 --- a/packages/binding/test/unit/services/completion/aggregation-binding.test.ts +++ b/packages/binding/test/unit/services/completion/aggregation-binding.test.ts @@ -14,6 +14,7 @@ import { ViewCompletionProviderType, } from "../../helper"; import { initI18n } from "../../../../src/api"; +import { readFile, writeFile } from "fs/promises"; describe("aggregation binding", () => { let getCompletionResult: ViewCompletionProviderType; @@ -105,6 +106,24 @@ describe("aggregation binding", () => { const result = await getCompletionResult(snippet); expect(result).toMatchSnapshot(); }); + + it("do not show `vSorterInfo`. Some UI5 version e.g. 1.131.0 has `vSorterInfo` as param of constructor ", async function () { + // adapt manifest.json file + const manifestPath = join( + root, + "app", + "manage_travels", + "webapp", + "manifest.json" + ); + const manifest = JSON.parse(await readFile(manifestPath, "utf-8")); + manifest["sap.ui5"]["dependencies"]["minUI5Version"] = "1.131.0"; + await writeFile(manifestPath, JSON.stringify(manifest, null, 2)); + const snippet = ` + `; + const result = await getCompletionResult(snippet); + expect(result.find((i) => i.label === "vSorterInfo")).toBeUndefined(); + }); }); describe("filters", function () { it("initial", async function () {