diff --git a/.changeset/curly-beers-compete.md b/.changeset/curly-beers-compete.md new file mode 100644 index 000000000..57ae8984f --- /dev/null +++ b/.changeset/curly-beers-compete.md @@ -0,0 +1,8 @@ +--- +"@ui5-language-assistant/context": patch +"@ui5-language-assistant/fe": patch +"vscode-ui5-language-assistant": patch +"@ui5-language-assistant/vscode-ui5-language-assistant-bas-ext": patch +--- + +Code completion for context path is disabled, S/4 version placeholder in manifest's minUI5Version property defaults to the latest available version diff --git a/packages/context/src/types.ts b/packages/context/src/types.ts index 1f03346e4..c3d08ea16 100644 --- a/packages/context/src/types.ts +++ b/packages/context/src/types.ts @@ -8,6 +8,7 @@ import { FetchResponse } from "@ui5-language-assistant/logic-utils"; export const DEFAULT_UI5_FRAMEWORK = "SAPUI5"; export const DEFAULT_UI5_VERSION = "1.71.49"; +export const UI5_VERSION_S4_PLACEHOLDER = "${sap.ui5.dist.version}"; export const UI5_FRAMEWORK_CDN_BASE_URL = { OpenUI5: "https://sdk.openui5.org/", SAPUI5: "https://ui5.sap.com/", diff --git a/packages/context/src/ui5-model.ts b/packages/context/src/ui5-model.ts index 6fa3567a8..be4d3391a 100644 --- a/packages/context/src/ui5-model.ts +++ b/packages/context/src/ui5-model.ts @@ -12,7 +12,7 @@ import { Json, TypeNameFix, } from "@ui5-language-assistant/semantic-model"; -import { Fetcher } from "./types"; +import { Fetcher, UI5_VERSION_S4_PLACEHOLDER } from "./types"; import { fetch } from "@ui5-language-assistant/logic-utils"; import { getLibraryAPIJsonUrl, @@ -262,12 +262,16 @@ async function getVersionInfo( let versionInfo = await readFromCache(cacheFilePath); if (versionInfo === undefined) { const url = await getVersionInfoUrl(framework, version); - const response = await fetcher(url); - if (response.ok) { - versionInfo = await response.json(); - writeToCache(cacheFilePath, versionInfo); - } else { - getLogger().error("Could not read version information", { + try { + const response = await fetcher(url); + if (response.ok) { + versionInfo = await response.json(); + writeToCache(cacheFilePath, versionInfo); + } else { + throw new Error(`Version info request has failed (${url})`); + } + } catch (e) { + getLogger().error("Could not read version information. " + e, { url, }); } @@ -361,11 +365,18 @@ export async function negotiateVersionWithFetcher( // try to negotiate version let isFallback = false; let isIncorrectVersion = false; + let useLatestVersion = false; let versions = versionMap[framework]; let adjustedVersion: string = version || DEFAULT_UI5_VERSION; - if (version && !isVersionSupported(version)) { + if (version === UI5_VERSION_S4_PLACEHOLDER) { + useLatestVersion = true; + adjustedVersion = version; + getLogger().warn( + `The version specified as minUI5Version in your manifest.json is not supported by Language Assistant, the latest available version is used instead` + ); + } else if (version && !isVersionSupported(version)) { // version is out of support in LA, using default version getLogger().warn( `The version specified as minUI5Version in your manifest.json is not supported by Language Assistant, the fallback version ${DEFAULT_UI5_VERSION} is used instead` @@ -388,6 +399,7 @@ export async function negotiateVersionWithFetcher( isIncorrectVersion = true; } } else if ( + useLatestVersion || !(await getVersionInfo( versionInfoJsonFetcher, modelCachePath, @@ -427,7 +439,7 @@ export async function negotiateVersionWithFetcher( } // coerce the version (check for invalid version, which indicates development scenario) const parsedVersion = semver.coerce(adjustedVersion); - if (parsedVersion) { + if (!useLatestVersion && parsedVersion) { if (versions[`${parsedVersion.major}.${parsedVersion.minor}`]) { // lookup for a valid major.minor entry adjustedVersion = @@ -453,7 +465,7 @@ export async function negotiateVersionWithFetcher( isIncorrectVersion = true; } } else { - // development scenario => use latest version + // development scenario or version placeholder in manifest found => use latest version adjustedVersion = versions["latest"].version; isIncorrectVersion = true; } diff --git a/packages/context/test/unit/ui5-model.test.ts b/packages/context/test/unit/ui5-model.test.ts index 919fb74af..70f6fb10c 100644 --- a/packages/context/test/unit/ui5-model.test.ts +++ b/packages/context/test/unit/ui5-model.test.ts @@ -42,6 +42,7 @@ describe("the UI5 language assistant ui5 model", () => { const FRAMEWORK = "SAPUI5"; const OPEN_FRAMEWORK = "OpenUI5"; const VERSION = "1.71.49"; + const UI5_VERSION_S4_PLACEHOLDER = "${sap.ui5.dist.version}"; const NO_CACHE_FOLDER = undefined; function assertSemanticModel(ui5Model: UI5SemanticModel): void { @@ -623,5 +624,22 @@ describe("the UI5 language assistant ui5 model", () => { expect(objNegotiatedVersionWithFetcher.isFallback).toBeFalse(); expect(objNegotiatedVersionWithFetcher.isIncorrectVersion).toBeTrue(); }); + + it("resolve unsupported version placeholder - S/4 generator artifact (should be latest)", async () => { + const objNegotiatedVersionWithFetcher = await negotiateVersionWithFetcher( + async (): Promise => { + return createResponse(true, 200, versionMap[OPEN_FRAMEWORK]); + }, + async (): Promise => { + return createResponse(false, 404); + }, + cachePath, + FRAMEWORK, + UI5_VERSION_S4_PLACEHOLDER + ); + expect(objNegotiatedVersionWithFetcher.version).toEqual("1.105.0"); + expect(objNegotiatedVersionWithFetcher.isFallback).toBeFalse(); + expect(objNegotiatedVersionWithFetcher.isIncorrectVersion).toBeTrue(); + }); }); }); diff --git a/packages/fe/src/services/completion/providers/context-path.ts b/packages/fe/src/services/completion/providers/context-path.ts index 0cb720167..17228443a 100644 --- a/packages/fe/src/services/completion/providers/context-path.ts +++ b/packages/fe/src/services/completion/providers/context-path.ts @@ -47,6 +47,12 @@ export function contextPathSuggestions({ context.ui5Model ); + // provider is blocked and is used in tests only + // reserved for the future to be reused in binding expressions + if (!(context as unknown as { forTest: boolean }).forTest) { + return []; + } + if ( ui5Property?.library === SAP_FE_MACROS && ui5Property.name === "contextPath" diff --git a/packages/fe/test/unit/services/completion/providers/context-path.test.ts b/packages/fe/test/unit/services/completion/providers/context-path.test.ts index 555ac5f55..599495ab4 100644 --- a/packages/fe/test/unit/services/completion/providers/context-path.test.ts +++ b/packages/fe/test/unit/services/completion/providers/context-path.test.ts @@ -81,13 +81,28 @@ describe("contextPath attribute value completion", () => { annoFileSegmentsCDS, annotationSnippetCDS ); - getCompletionResult = getViewCompletionProvider( + + const provider = getViewCompletionProvider( framework, viewFilePathSegments, documentPath, uri, settings ); + + getCompletionResult = ( + snippet: string, + contextAdapter?: (context: Context) => Context + ) => { + const testAdapter = (context: Context) => { + const result: Context = contextAdapter + ? contextAdapter(context) + : context; + return { ...result, forTest: true } as Context; + }; + + return provider(snippet, testAdapter); + }; }, 5 * 60000); describe("contextPath completion", () => {