Skip to content

Commit

Permalink
fix: lsp for adaption project - first iteration (#733)
Browse files Browse the repository at this point in the history
* fix: lsp for adaption project - first iteration

* fix: enhance get context api test
  • Loading branch information
marufrasully authored Oct 9, 2024
1 parent 1e41b87 commit 6fe3662
Show file tree
Hide file tree
Showing 24 changed files with 598 additions and 5 deletions.
9 changes: 9 additions & 0 deletions .changeset/nasty-bugs-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@ui5-language-assistant/vscode-ui5-language-assistant-bas-ext": patch
"vscode-ui5-language-assistant": patch
"@ui5-language-assistant/language-server": patch
"@ui5-language-assistant/test-framework": patch
"@ui5-language-assistant/context": patch
---

fix: lsp for adaption project - first iteration
11 changes: 11 additions & 0 deletions packages/context/src/adp-manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import findUp from "find-up";
import { FileName } from "@sap-ux/project-access";
/**
* Get path of a manifest.appdescr_variant file for adaption project.
* @param documentPath path to a file e.g. absolute/path/webapp/ext/main/Main.view.xml
*/
export async function finAdpdManifestPath(
documentPath: string
): Promise<string | undefined> {
return findUp(FileName.ManifestAppDescrVar, { cwd: documentPath });
}
11 changes: 9 additions & 2 deletions packages/context/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
getManifestDetails,
getUI5Manifest,
} from "./manifest";
import { finAdpdManifestPath } from "./adp-manifest";
import { getServices } from "./services";
import { Context } from "./types";
import { getSemanticModel } from "./ui5-model";
Expand Down Expand Up @@ -47,7 +48,8 @@ export async function getContext(
): Promise<Context | Error> {
try {
const manifestDetails = await getManifestDetails(documentPath);
const manifest = await getUI5Manifest(manifestDetails.manifestPath);
let manifestPath = manifestDetails.manifestPath;
const manifest = await getUI5Manifest(manifestPath);
let minUI5Version = manifestDetails.minUI5Version;
if (manifest) {
minUI5Version = getMinimumUI5Version(manifest);
Expand All @@ -61,7 +63,12 @@ export async function getContext(
);
const services = await getServices(documentPath);
const customViewId = await getCustomViewId(documentPath);
const manifestPath = manifestDetails.manifestPath;
if (!manifestPath) {
const adpManifestPath = await finAdpdManifestPath(documentPath);
if (adpManifestPath) {
manifestPath = adpManifestPath;
}
}
const viewFiles = await getViewFiles({
manifestPath,
documentPath,
Expand Down
10 changes: 9 additions & 1 deletion packages/context/src/utils/view-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,15 @@ export async function getViewFiles(param: {
}

const files = {};
await processViewFiles(join(manifestPath, ".."), files);
if (!manifestPath) {
// a project without manifest.json or manifest.appdescr_variant file. Only support for current view file
const ast = await createDocumentAst(documentPath);
files[documentPath] = ast;
} else {
// find all view files
await processViewFiles(join(manifestPath, ".."), files);
}

cache.setViewFiles(manifestPath, files);
return files;
}
55 changes: 55 additions & 0 deletions packages/context/test/unit/adp-manifest.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { join } from "path";
import {
Config,
ProjectName,
ProjectType,
TestFramework,
} from "@ui5-language-assistant/test-framework";
import { finAdpdManifestPath } from "../../src/adp-manifest";

describe("adp-manifest", () => {
let framework: TestFramework;
beforeAll(function () {
const useConfig: Config = {
projectInfo: {
name: ProjectName.cap,
type: ProjectType.CAP,
npmInstall: true,
},
};
framework = new TestFramework(useConfig);
});

afterEach(() => {
jest.restoreAllMocks();
});
describe("finAdpdManifestPath", () => {
beforeAll(function () {
const useConfig: Config = {
projectInfo: {
name: ProjectName.adp,
type: ProjectType.ADP,
npmInstall: false,
},
};
framework = new TestFramework(useConfig);
});
it("undefined", async () => {
const root = framework.getProjectRoot();
const result = await finAdpdManifestPath(root);
expect(result).toBeUndefined();
});
it("path to manifest.appdescr_variant file", async () => {
const root = framework.getProjectRoot();
const pathSegments = [
"webapp",
"changes",
"fragments",
"actionToolbar.fragment.xml",
];
const docPath = join(root, ...pathSegments);
const result = await finAdpdManifestPath(docPath);
expect(result).toEqual(join(root, "webapp", "manifest.appdescr_variant"));
});
});
});
5 changes: 5 additions & 0 deletions packages/context/test/unit/api.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as manifest from "../../src/manifest";
import * as adpManifest from "../../src/adp-manifest";
import * as ui5Yaml from "../../src/ui5-yaml";
import * as ui5Model from "../../src/ui5-model";
import * as services from "../../src/services";
Expand Down Expand Up @@ -51,6 +52,9 @@ describe("context", () => {
const getServicesStub = jest
.spyOn(services, "getServices")
.mockResolvedValue({});
const finAdpdManifestPathStub = jest
.spyOn(adpManifest, "finAdpdManifestPath")
.mockResolvedValue("/path/to/app/variant");
const getViewFilesStub = jest
.spyOn(viewFiles, "getViewFiles")
.mockResolvedValue({});
Expand All @@ -67,6 +71,7 @@ describe("context", () => {
expect(getYamlDetailsStub).toHaveBeenCalled();
expect(getSemanticModelStub).toHaveBeenCalled();
expect(getServicesStub).toHaveBeenCalled();
expect(finAdpdManifestPathStub).toHaveBeenCalled();
expect(getViewFilesStub).toHaveBeenCalled();
expect(getControlIdsStub).toHaveBeenCalled();
expect(result).toContainAllKeys([
Expand Down
8 changes: 6 additions & 2 deletions packages/context/test/unit/loader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import * as manifest from "../../src/manifest";
import * as projectUtils from "../../src/utils/project";
import { cache } from "../../src/cache";
import { Manifest } from "@sap-ux/project-access";
import { ProjectKind, UI5_PROJECT_TYPE } from "../../src/types";
import {
ProjectKind,
UI5_PROJECT_TYPE,
ProjectType as ProjType,
} from "../../src/types";
import { getProjectData } from "./utils";
import { getManifestDetails, getUI5Manifest } from "../../src/manifest";
import { getApp } from "../../src/loader";
Expand Down Expand Up @@ -156,7 +160,7 @@ describe("loader", () => {
projectRoot
);
const projectInfo = { kind: "Java", type: "CAP" } as {
type: ProjectType;
type: ProjType;
kind: ProjectKind;
};
const capProject = await loader.getCAPProject(
Expand Down
19 changes: 19 additions & 0 deletions packages/context/test/unit/utils/view-files.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,23 @@ describe("view-files", () => {
expect(Object.keys(viewFiles).length).toBeGreaterThan(1);
expect(viewFiles[documentPath]).toBeDefined();
});
it("get view files - no manifest path", async () => {
// arrange
cache.reset();
const getViewFilesStub = jest
.spyOn(cache, "getViewFiles")
.mockReturnValue({});
const projectRoot = testFramework.getProjectRoot();
const documentPath = getDocumentPath(projectRoot);
const manifestPath = "";
// act
const viewFiles = await getViewFiles({
manifestPath,
documentPath,
});
// assert
expect(getViewFilesStub).toHaveBeenCalledTimes(1);
expect(Object.keys(viewFiles).length).toEqual(1);
expect(viewFiles[documentPath]).toBeDefined();
});
});
1 change: 1 addition & 0 deletions packages/language-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"@types/tmp": "0.2.0",
"@ui5-language-assistant/semantic-model-types": "4.0.11",
"@ui5-language-assistant/test-utils": "4.0.16",
"@ui5-language-assistant/test-framework": "4.0.12",
"string-replace-loader": "3.1.0",
"vscode-languageserver-types": "3.17.2"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`xml view diagnostics adaptation project diagnostics for duplicate ids - duplicates 1`] = `
Array [
Object {
"message": "Select a unique ID. The current \\"_IDGenText\\" ID has already been used.",
"range": Object {
"end": Object {
"character": 25,
"line": 3,
},
"start": Object {
"character": 13,
"line": 3,
},
},
"relatedInformation": Array [
Object {
"location": Object {
"range": Object {
"end": Object {
"character": 25,
"line": 3,
},
"start": Object {
"character": 13,
"line": 3,
},
},
"uri": "filterBar.fragment.xml",
},
"message": "An identical ID is also used here.",
},
],
"severity": 1,
"source": "UI5 Language Assistant",
},
Object {
"message": "Select a unique ID. The current \\"_IDGenButton\\" ID has already been used.",
"range": Object {
"end": Object {
"character": 29,
"line": 4,
},
"start": Object {
"character": 15,
"line": 4,
},
},
"relatedInformation": Array [
Object {
"location": Object {
"range": Object {
"end": Object {
"character": 29,
"line": 4,
},
"start": Object {
"character": 15,
"line": 4,
},
},
"uri": "filterBar.fragment.xml",
},
"message": "An identical ID is also used here.",
},
],
"severity": 1,
"source": "UI5 Language Assistant",
},
]
`;
114 changes: 114 additions & 0 deletions packages/language-server/test/unit/xml-view-diagnostics.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { getXMLViewIdDiagnostics } from "../../src/xml-view-diagnostics";
import {
Config,
ProjectName,
ProjectType,
TestFramework,
} from "@ui5-language-assistant/test-framework";
import {
Context,
getContext,
isContext,
cache,
} from "@ui5-language-assistant/context";
import { join, basename } from "path";

describe("xml view diagnostics", () => {
describe("adaptation project", () => {
let framework: TestFramework;
let context: Context;
beforeAll(async () => {
const useConfig: Config = {
projectInfo: {
name: ProjectName.adp,
type: ProjectType.ADP,
npmInstall: false,
},
};
framework = new TestFramework(useConfig);
});
beforeEach(() => {
// reset to avoid side effects
cache.reset();
});
it("diagnostics for duplicate ids - no duplicate", async () => {
// arrange
const root = framework.getProjectRoot();
const snippet = `
<!-- Use stable and unique IDs!-->
<core:FragmentDefinition xmlns:core='sap.ui.core' xmlns='sap.m'>
<Text id="_IDGenText" >
<Button id="_IDGenButton" />
</core:FragmentDefinition>`;
const pathSegments = [
"webapp",
"changes",
"fragments",
"actionToolbar.fragment.xml",
];
await framework.updateFile(pathSegments, snippet);
const docPath = join(root, ...pathSegments);
const ctx = await getContext(docPath);
if (isContext(ctx)) {
context = ctx;
} else {
throw new Error("Failed to build context....");
}
const { document } = framework.toVscodeTextDocument(
framework.getFileUri(pathSegments),
snippet,
0
);
// act
const result = getXMLViewIdDiagnostics({ document, context });
// assert
expect(result).toEqual([]);
});
it("diagnostics for duplicate ids - duplicates", async () => {
// arrange
const root = framework.getProjectRoot();
const snippet = `
<!-- Use stable and unique IDs!-->
<core:FragmentDefinition xmlns:core='sap.ui.core' xmlns='sap.m'>
<Text id="_IDGenText" >
<Button id="_IDGenButton" />
</core:FragmentDefinition>`;
const pathSegments = [
"webapp",
"changes",
"fragments",
"actionToolbar.fragment.xml",
];
await framework.updateFile(pathSegments, snippet);
const pathSegments02 = [
"webapp",
"changes",
"fragments",
"filterBar.fragment.xml",
];
await framework.updateFile(pathSegments02, snippet);
const docPath = join(root, ...pathSegments);
const ctx = await getContext(docPath);
if (isContext(ctx)) {
context = ctx;
} else {
throw new Error("Failed to build context....");
}
const { document } = framework.toVscodeTextDocument(
framework.getFileUri(pathSegments),
snippet,
0
);
// act
const result = getXMLViewIdDiagnostics({ document, context });
// adapt uri
result.map((i) =>
i.relatedInformation?.map((j) => {
j.location.uri = basename(j.location.uri);
})
);
// assert
expect(result).toMatchSnapshot();
});
});
});
Loading

0 comments on commit 6fe3662

Please sign in to comment.