@ui5/mcp-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/LICENSE +201 -0
- package/LICENSES/Apache-2.0.txt +73 -0
- package/README.md +131 -0
- package/bin/ui5mcp.js +2 -0
- package/lib/Context.d.ts +28 -0
- package/lib/Context.js +71 -0
- package/lib/Context.js.map +1 -0
- package/lib/api.d.ts +3 -0
- package/lib/api.js +3 -0
- package/lib/api.js.map +1 -0
- package/lib/cli.d.ts +1 -0
- package/lib/cli.js +12 -0
- package/lib/cli.js.map +1 -0
- package/lib/registerTools.d.ts +133 -0
- package/lib/registerTools.js +59 -0
- package/lib/registerTools.js.map +1 -0
- package/lib/resources/documentation/getDocumentation.d.ts +18 -0
- package/lib/resources/documentation/getDocumentation.js +70 -0
- package/lib/resources/documentation/getDocumentation.js.map +1 -0
- package/lib/server.d.ts +10 -0
- package/lib/server.js +113 -0
- package/lib/server.js.map +1 -0
- package/lib/tools/create_ui5_app/ODataMetadata.d.ts +55 -0
- package/lib/tools/create_ui5_app/ODataMetadata.js +99 -0
- package/lib/tools/create_ui5_app/ODataMetadata.js.map +1 -0
- package/lib/tools/create_ui5_app/createSuccessMessage.d.ts +13 -0
- package/lib/tools/create_ui5_app/createSuccessMessage.js +45 -0
- package/lib/tools/create_ui5_app/createSuccessMessage.js.map +1 -0
- package/lib/tools/create_ui5_app/create_ui5_app.d.ts +8 -0
- package/lib/tools/create_ui5_app/create_ui5_app.js +273 -0
- package/lib/tools/create_ui5_app/create_ui5_app.js.map +1 -0
- package/lib/tools/create_ui5_app/index.d.ts +3 -0
- package/lib/tools/create_ui5_app/index.js +58 -0
- package/lib/tools/create_ui5_app/index.js.map +1 -0
- package/lib/tools/create_ui5_app/isValidUrl.d.ts +16 -0
- package/lib/tools/create_ui5_app/isValidUrl.js +59 -0
- package/lib/tools/create_ui5_app/isValidUrl.js.map +1 -0
- package/lib/tools/create_ui5_app/schema.d.ts +135 -0
- package/lib/tools/create_ui5_app/schema.js +67 -0
- package/lib/tools/create_ui5_app/schema.js.map +1 -0
- package/lib/tools/create_ui5_app/templateProcessor.d.ts +67 -0
- package/lib/tools/create_ui5_app/templateProcessor.js +59 -0
- package/lib/tools/create_ui5_app/templateProcessor.js.map +1 -0
- package/lib/tools/create_ui5_app/ui5Version.d.ts +2 -0
- package/lib/tools/create_ui5_app/ui5Version.js +6 -0
- package/lib/tools/create_ui5_app/ui5Version.js.map +1 -0
- package/lib/tools/get_api_reference/createUriForSymbol.d.ts +2 -0
- package/lib/tools/get_api_reference/createUriForSymbol.js +49 -0
- package/lib/tools/get_api_reference/createUriForSymbol.js.map +1 -0
- package/lib/tools/get_api_reference/getApiReference.d.ts +10 -0
- package/lib/tools/get_api_reference/getApiReference.js +51 -0
- package/lib/tools/get_api_reference/getApiReference.js.map +1 -0
- package/lib/tools/get_api_reference/index.d.ts +3 -0
- package/lib/tools/get_api_reference/index.js +38 -0
- package/lib/tools/get_api_reference/index.js.map +1 -0
- package/lib/tools/get_api_reference/lib/ApiReferenceProvider.d.ts +85 -0
- package/lib/tools/get_api_reference/lib/ApiReferenceProvider.js +452 -0
- package/lib/tools/get_api_reference/lib/ApiReferenceProvider.js.map +1 -0
- package/lib/tools/get_api_reference/lib/apiReferenceResources.d.ts +18 -0
- package/lib/tools/get_api_reference/lib/apiReferenceResources.js +138 -0
- package/lib/tools/get_api_reference/lib/apiReferenceResources.js.map +1 -0
- package/lib/tools/get_api_reference/lib/formatSymbol.d.ts +24 -0
- package/lib/tools/get_api_reference/lib/formatSymbol.js +109 -0
- package/lib/tools/get_api_reference/lib/formatSymbol.js.map +1 -0
- package/lib/tools/get_api_reference/schema.d.ts +16 -0
- package/lib/tools/get_api_reference/schema.js +12 -0
- package/lib/tools/get_api_reference/schema.js.map +1 -0
- package/lib/tools/get_guidelines/guidelines.d.ts +1 -0
- package/lib/tools/get_guidelines/guidelines.js +6 -0
- package/lib/tools/get_guidelines/guidelines.js.map +1 -0
- package/lib/tools/get_guidelines/index.d.ts +3 -0
- package/lib/tools/get_guidelines/index.js +30 -0
- package/lib/tools/get_guidelines/index.js.map +1 -0
- package/lib/tools/get_project_info/getProjectInfo.d.ts +2 -0
- package/lib/tools/get_project_info/getProjectInfo.js +205 -0
- package/lib/tools/get_project_info/getProjectInfo.js.map +1 -0
- package/lib/tools/get_project_info/index.d.ts +3 -0
- package/lib/tools/get_project_info/index.js +28 -0
- package/lib/tools/get_project_info/index.js.map +1 -0
- package/lib/tools/get_project_info/schema.d.ts +87 -0
- package/lib/tools/get_project_info/schema.js +28 -0
- package/lib/tools/get_project_info/schema.js.map +1 -0
- package/lib/tools/get_version_info/getVersionInfo.d.ts +8 -0
- package/lib/tools/get_version_info/getVersionInfo.js +41 -0
- package/lib/tools/get_version_info/getVersionInfo.js.map +1 -0
- package/lib/tools/get_version_info/index.d.ts +9 -0
- package/lib/tools/get_version_info/index.js +33 -0
- package/lib/tools/get_version_info/index.js.map +1 -0
- package/lib/tools/get_version_info/schema.d.ts +66 -0
- package/lib/tools/get_version_info/schema.js +16 -0
- package/lib/tools/get_version_info/schema.js.map +1 -0
- package/lib/tools/get_version_info/types.d.ts +5 -0
- package/lib/tools/get_version_info/types.js +2 -0
- package/lib/tools/get_version_info/types.js.map +1 -0
- package/lib/tools/run_ui5_linter/index.d.ts +3 -0
- package/lib/tools/run_ui5_linter/index.js +86 -0
- package/lib/tools/run_ui5_linter/index.js.map +1 -0
- package/lib/tools/run_ui5_linter/migrationGuides.d.ts +6 -0
- package/lib/tools/run_ui5_linter/migrationGuides.js +88 -0
- package/lib/tools/run_ui5_linter/migrationGuides.js.map +1 -0
- package/lib/tools/run_ui5_linter/resultContext.d.ts +3 -0
- package/lib/tools/run_ui5_linter/resultContext.js +236 -0
- package/lib/tools/run_ui5_linter/resultContext.js.map +1 -0
- package/lib/tools/run_ui5_linter/runUi5Linter.d.ts +2 -0
- package/lib/tools/run_ui5_linter/runUi5Linter.js +72 -0
- package/lib/tools/run_ui5_linter/runUi5Linter.js.map +1 -0
- package/lib/tools/run_ui5_linter/schema.d.ts +340 -0
- package/lib/tools/run_ui5_linter/schema.js +55 -0
- package/lib/tools/run_ui5_linter/schema.js.map +1 -0
- package/lib/utils/cdnHelper.d.ts +9 -0
- package/lib/utils/cdnHelper.js +50 -0
- package/lib/utils/cdnHelper.js.map +1 -0
- package/lib/utils/dataStorageHelper.d.ts +2 -0
- package/lib/utils/dataStorageHelper.js +65 -0
- package/lib/utils/dataStorageHelper.js.map +1 -0
- package/lib/utils/ui5Framework.d.ts +4 -0
- package/lib/utils/ui5Framework.js +6 -0
- package/lib/utils/ui5Framework.js.map +1 -0
- package/lib/utils.d.ts +10 -0
- package/lib/utils.js +87 -0
- package/lib/utils.js.map +1 -0
- package/npm-shrinkwrap.json +7880 -0
- package/package.json +121 -0
- package/resources/docs/1.136.7/00737d6c1b864dc3ab72ef56611491c4.md +155 -0
- package/resources/docs/1.136.7/0187ea5e2eff4166b0453b9dcc8fc64f.md +164 -0
- package/resources/docs/1.136.7/032be2cb2e1d4115af20862673bedcdb.md +12 -0
- package/resources/docs/1.136.7/28fcd55b04654977b63dacbee0552712.md +317 -0
- package/resources/docs/1.136.7/676b636446c94eada183b1218a824717.md +135 -0
- package/resources/docs/1.136.7/a87ca843bcee469f82a9072927a7dcdb.md +355 -0
- package/resources/docs/1.136.7/b0fb4de7364f4bcbb053a99aa645affe.md +126 -0
- package/resources/docs/1.136.7/fe1a6dba940e479fb7c3bc753f92b28c.md +670 -0
- package/resources/docs/1.136.7/index.json +58 -0
- package/resources/guidelines.md +104 -0
- package/resources/migrationGuides/deprecated-controller-factory.md +116 -0
- package/resources/migrationGuides/deprecated-getLibraryResourceBundle.md +62 -0
- package/resources/migrationGuides/deprecated-jquery-sap-require.md +141 -0
- package/resources/migrationGuides/deprecated-messagePage.md +162 -0
- package/resources/migrationGuides/deprecated-table-table-property.md +154 -0
- package/resources/template-js/LICENSE +201 -0
- package/resources/template-js/README.md +87 -0
- package/resources/template-js/_.editorconfig +22 -0
- package/resources/template-js/_.gitignore +17 -0
- package/resources/template-js/eslint.config.js +68 -0
- package/resources/template-js/karma-ci-cov.conf.js +20 -0
- package/resources/template-js/karma-ci.conf.js +9 -0
- package/resources/template-js/karma.conf.js +9 -0
- package/resources/template-js/package.json +34 -0
- package/resources/template-js/ui5-dist.yaml +18 -0
- package/resources/template-js/ui5.yaml +24 -0
- package/resources/template-js/webapp/Component.js +41 -0
- package/resources/template-js/webapp/controller/App.controller.js +10 -0
- package/resources/template-js/webapp/controller/BaseController.js +67 -0
- package/resources/template-js/webapp/controller/Main.controller.js +14 -0
- package/resources/template-js/webapp/i18n/i18n.properties +3 -0
- package/resources/template-js/webapp/i18n/i18n_en.properties +3 -0
- package/resources/template-js/webapp/index-cdn.html +34 -0
- package/resources/template-js/webapp/index.html +34 -0
- package/resources/template-js/webapp/manifest.json +103 -0
- package/resources/template-js/webapp/model/formatter.js +9 -0
- package/resources/template-js/webapp/model/models.js +11 -0
- package/resources/template-js/webapp/test/Test.qunit.html +16 -0
- package/resources/template-js/webapp/test/integration/HelloJourney.js +85 -0
- package/resources/template-js/webapp/test/integration/opaTests.qunit.js +1 -0
- package/resources/template-js/webapp/test/integration/pages/Main.js +112 -0
- package/resources/template-js/webapp/test/testsuite.qunit.html +18 -0
- package/resources/template-js/webapp/test/testsuite.qunit.js +37 -0
- package/resources/template-js/webapp/test/unit/controller/Main.qunit.js +11 -0
- package/resources/template-js/webapp/test/unit/unitTests.qunit.js +1 -0
- package/resources/template-js/webapp/test-lt1_124/integration/HelloJourney.js +85 -0
- package/resources/template-js/webapp/test-lt1_124/integration/opaTests.qunit.html +31 -0
- package/resources/template-js/webapp/test-lt1_124/integration/opaTests.qunit.js +11 -0
- package/resources/template-js/webapp/test-lt1_124/integration/pages/Main.js +112 -0
- package/resources/template-js/webapp/test-lt1_124/testsuite.qunit.html +13 -0
- package/resources/template-js/webapp/test-lt1_124/testsuite.qunit.js +9 -0
- package/resources/template-js/webapp/test-lt1_124/unit/controller/Main.qunit.js +11 -0
- package/resources/template-js/webapp/test-lt1_124/unit/unitTests.qunit.html +30 -0
- package/resources/template-js/webapp/test-lt1_124/unit/unitTests.qunit.js +12 -0
- package/resources/template-js/webapp/view/App.view.xml +9 -0
- package/resources/template-js/webapp/view/Main.view.xml +90 -0
- package/resources/template-ts/LICENSE +201 -0
- package/resources/template-ts/README.md +101 -0
- package/resources/template-ts/_.editorconfig +23 -0
- package/resources/template-ts/_.gitignore +18 -0
- package/resources/template-ts/_.nycrc.json +7 -0
- package/resources/template-ts/_tsconfig.json +21 -0
- package/resources/template-ts/eslint.config.mjs +27 -0
- package/resources/template-ts/package.json +40 -0
- package/resources/template-ts/ui5-coverage.yaml +40 -0
- package/resources/template-ts/ui5-dist.yaml +18 -0
- package/resources/template-ts/ui5.yaml +27 -0
- package/resources/template-ts/webapp/Component.ts +49 -0
- package/resources/template-ts/webapp/controller/App.controller.ts +11 -0
- package/resources/template-ts/webapp/controller/BaseController.ts +83 -0
- package/resources/template-ts/webapp/controller/Main.controller.ts +19 -0
- package/resources/template-ts/webapp/i18n/i18n.properties +3 -0
- package/resources/template-ts/webapp/i18n/i18n_en.properties +3 -0
- package/resources/template-ts/webapp/index-cdn.html +35 -0
- package/resources/template-ts/webapp/index.html +35 -0
- package/resources/template-ts/webapp/manifest.json +105 -0
- package/resources/template-ts/webapp/model/formatter.ts +5 -0
- package/resources/template-ts/webapp/model/models.ts +15 -0
- package/resources/template-ts/webapp/test/Test.qunit.html +16 -0
- package/resources/template-ts/webapp/test/integration/HelloJourney.ts +84 -0
- package/resources/template-ts/webapp/test/integration/opaTests.qunit.ts +2 -0
- package/resources/template-ts/webapp/test/integration/pages/MainPage.ts +112 -0
- package/resources/template-ts/webapp/test/testsuite.qunit.html +18 -0
- package/resources/template-ts/webapp/test/testsuite.qunit.ts +33 -0
- package/resources/template-ts/webapp/test/unit/controller/Main.qunit.ts +8 -0
- package/resources/template-ts/webapp/test/unit/unitTests.qunit.ts +2 -0
- package/resources/template-ts/webapp/test-lt1_124/integration/HelloJourney.ts +86 -0
- package/resources/template-ts/webapp/test-lt1_124/integration/opaTests.qunit.html +34 -0
- package/resources/template-ts/webapp/test-lt1_124/integration/opaTests.qunit.ts +8 -0
- package/resources/template-ts/webapp/test-lt1_124/integration/pages/MainPage.ts +112 -0
- package/resources/template-ts/webapp/test-lt1_124/testsuite.qunit.html +13 -0
- package/resources/template-ts/webapp/test-lt1_124/testsuite.qunit.ts +9 -0
- package/resources/template-ts/webapp/test-lt1_124/unit/controller/Main.qunit.ts +8 -0
- package/resources/template-ts/webapp/test-lt1_124/unit/unitTests.qunit.html +37 -0
- package/resources/template-ts/webapp/test-lt1_124/unit/unitTests.qunit.ts +8 -0
- package/resources/template-ts/webapp/view/App.view.xml +9 -0
- package/resources/template-ts/webapp/view/Main.view.xml +90 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import os from "os";
|
|
2
|
+
import path, { isAbsolute } from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { mkdir } from "fs/promises";
|
|
5
|
+
import semver from "semver";
|
|
6
|
+
import { execa } from "execa";
|
|
7
|
+
import { getLatestUi5Version } from "./ui5Version.js";
|
|
8
|
+
import { processTemplates } from "./templateProcessor.js";
|
|
9
|
+
import ODataMetadata from "./ODataMetadata.js";
|
|
10
|
+
import { getLogger } from "@ui5/logger";
|
|
11
|
+
import { isUi5Framework } from "../../utils/ui5Framework.js";
|
|
12
|
+
import { dirExists, InvalidInputError } from "../../utils.js";
|
|
13
|
+
import isValidUrl from "./isValidUrl.js";
|
|
14
|
+
const log = getLogger("tools:create_ui5_app:create_ui5_app");
|
|
15
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const minFwkVersion = {
|
|
17
|
+
OpenUI5: "1.96.0",
|
|
18
|
+
SAPUI5: "1.96.0",
|
|
19
|
+
};
|
|
20
|
+
const minFwkVersionJS = {
|
|
21
|
+
OpenUI5: "1.96.0",
|
|
22
|
+
SAPUI5: "1.96.0",
|
|
23
|
+
};
|
|
24
|
+
const fwkCDNDomain = {
|
|
25
|
+
OpenUI5: "sdk.openui5.org",
|
|
26
|
+
SAPUI5: "ui5.sap.com",
|
|
27
|
+
};
|
|
28
|
+
function getTypePackageFor(framework, version = "99.99.99") {
|
|
29
|
+
const typesName = semver.gte(version, "1.113.0") ? "types" : "ts-types-esm";
|
|
30
|
+
return `@${framework.toLowerCase()}/${typesName}`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Creates a new SAPUI5/OpenUI5 application using templating.
|
|
34
|
+
*
|
|
35
|
+
* @param {CreateUi5AppParams} params - Parameters for the application to be created.
|
|
36
|
+
* @returns {Promise<CreateUi5AppResult>} Result object indicating success, message, and final location.
|
|
37
|
+
*/
|
|
38
|
+
export async function createUi5App(params) {
|
|
39
|
+
const { appNamespace, framework = "SAPUI5", frameworkVersion = await getLatestUi5Version(params.framework ?? "SAPUI5"), author = os.userInfo().username || "Developer", createAppDirectory = true, oDataV4Url, oDataEntitySet, entityProperties = [], initializeGitRepository = true, runNpmInstall = true, basePath, typescript = true, } = params;
|
|
40
|
+
// Validate parameters
|
|
41
|
+
if (!isUi5Framework(framework)) {
|
|
42
|
+
throw new InvalidInputError("The provided framework is not valid! Please use either OpenUI5 or SAPUI5.");
|
|
43
|
+
}
|
|
44
|
+
if (!semver.valid(frameworkVersion)) {
|
|
45
|
+
throw new InvalidInputError("The provided framework version is not valid! Please use a semantic version, e.g. 1.136.0");
|
|
46
|
+
}
|
|
47
|
+
const minFwkVersionToUse = typescript ?
|
|
48
|
+
minFwkVersion[framework] :
|
|
49
|
+
minFwkVersionJS[framework];
|
|
50
|
+
if (semver.lt(frameworkVersion, minFwkVersionToUse)) {
|
|
51
|
+
throw new InvalidInputError(`The provided framework version ${frameworkVersion} is not valid!
|
|
52
|
+
The minimum version for ${framework} is ${minFwkVersionToUse}.`);
|
|
53
|
+
}
|
|
54
|
+
let metadata, metadataUrl;
|
|
55
|
+
if (oDataV4Url) {
|
|
56
|
+
metadataUrl = oDataV4Url;
|
|
57
|
+
if (oDataV4Url.startsWith("/")) {
|
|
58
|
+
metadataUrl = `http://localhost:4004${oDataV4Url}`;
|
|
59
|
+
}
|
|
60
|
+
const allowedDomains = getAllowedOdataV4Domains();
|
|
61
|
+
if (!isValidUrl(metadataUrl, allowedDomains)) {
|
|
62
|
+
let allowedDomainsNote = "";
|
|
63
|
+
if (allowedDomains.length) {
|
|
64
|
+
allowedDomainsNote =
|
|
65
|
+
`As per the MCP server configuration, only the following domains are currently allowed: ` +
|
|
66
|
+
`'${allowedDomains.join("', '")}'. See https://github.com/UI5/mcp-server#configuration ` +
|
|
67
|
+
`for information on how to configure the allow list.`;
|
|
68
|
+
}
|
|
69
|
+
throw new InvalidInputError(`The provided OData V4 service URL is not valid. It must be either an absolute URL` +
|
|
70
|
+
`starting with http:// or https:// or pathname like '/odata/v4/serviceName' in case ` +
|
|
71
|
+
`the OData service is exposed on the same server as the application. In this case, ` +
|
|
72
|
+
`the protocol and host 'http://localhost:4004' will be assumed and used by this tool for inquiries ` +
|
|
73
|
+
`about the service. ${allowedDomainsNote}`);
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
metadata = await ODataMetadata.load(metadataUrl);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
// Silently ignore metadata loading errors
|
|
80
|
+
// Many services require proxies or authentication, which is out of scope for this tool
|
|
81
|
+
log.info(`Failed to load OData V4 metadata from ${metadataUrl}: ` +
|
|
82
|
+
` ${err instanceof Error ? err.message : String(err)}` +
|
|
83
|
+
" This means the given entity and properties will not be verified and when no properties are" +
|
|
84
|
+
" given, there is no automatic display of some properties.");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// let metadataEntityKeys: string[] | undefined;
|
|
88
|
+
let metadataEntityProperties;
|
|
89
|
+
if (oDataEntitySet && metadata) {
|
|
90
|
+
if (!metadata.getEntitySet(oDataEntitySet)) {
|
|
91
|
+
throw new InvalidInputError(`The provided OData V4 entity set '${oDataEntitySet}' does not exist in the service metadata. ` +
|
|
92
|
+
`Please check the entity set name and ensure it is correct or omit it to generate the app ` +
|
|
93
|
+
`without data in the UI.`);
|
|
94
|
+
}
|
|
95
|
+
metadataEntityProperties = metadata.getProperties(oDataEntitySet);
|
|
96
|
+
// metadataEntityKeys = metadata.getKeys(oDataEntitySet);
|
|
97
|
+
if (entityProperties) {
|
|
98
|
+
// Validate provided entity properties against metadata
|
|
99
|
+
for (const prop of entityProperties) {
|
|
100
|
+
if (!metadataEntityProperties?.includes(prop)) {
|
|
101
|
+
// remove the property from the list if it doesn't exist in the entity
|
|
102
|
+
const index = entityProperties.indexOf(prop);
|
|
103
|
+
if (index !== -1) {
|
|
104
|
+
entityProperties.splice(index, 1);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (entityProperties.length === 0) {
|
|
110
|
+
// Use the first five properties from the metadata if none were provided/existing
|
|
111
|
+
entityProperties.push(...(metadataEntityProperties?.slice(0, 5) ?? []));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (!isAbsolute(basePath)) {
|
|
115
|
+
throw new InvalidInputError("The provided base path is not valid! Please provide an absolute path to the target directory.");
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
// if the directory does not exist, create it
|
|
119
|
+
await mkdir(basePath, { recursive: true });
|
|
120
|
+
}
|
|
121
|
+
catch (dirError) {
|
|
122
|
+
throw new InvalidInputError(`Failed to create base path '${basePath}': ${dirError instanceof Error ?
|
|
123
|
+
dirError.message :
|
|
124
|
+
String(dirError)}` +
|
|
125
|
+
" Please ensure the path is valid and as intended and you have write permissions.", { cause: dirError });
|
|
126
|
+
}
|
|
127
|
+
const finalLocation = createAppDirectory ? path.join(basePath, appNamespace) : basePath;
|
|
128
|
+
// Create app directory if needed
|
|
129
|
+
if (createAppDirectory) {
|
|
130
|
+
// Check directory does not already exist
|
|
131
|
+
if (await dirExists(finalLocation)) {
|
|
132
|
+
throw new InvalidInputError(`Target directory '${finalLocation}' already exists. ` +
|
|
133
|
+
"Please choose a different namespace or base path or remove the existing directory.");
|
|
134
|
+
}
|
|
135
|
+
await mkdir(finalLocation, { recursive: true });
|
|
136
|
+
}
|
|
137
|
+
// build the final OData V4 URL, which must be relative when starting with localhost as server because
|
|
138
|
+
// "localhost" won't work when deployed. Also, ensure it ends with a slash because the ODataModel
|
|
139
|
+
// requires this.
|
|
140
|
+
let finalODataV4Url = oDataV4Url?.match(/^https?:\/\/localhost:\d+/) ?
|
|
141
|
+
oDataV4Url.replace(/^https?:\/\/localhost:\d+/, "") :
|
|
142
|
+
oDataV4Url;
|
|
143
|
+
if (finalODataV4Url && !finalODataV4Url?.endsWith("/")) {
|
|
144
|
+
finalODataV4Url += "/";
|
|
145
|
+
}
|
|
146
|
+
// This allows us to apply an ODataModel setting (earlyRequests: true), which is recommended for
|
|
147
|
+
// servers that require x-csrf tokens. But this setting breaks with other servers.
|
|
148
|
+
// Details how this setting and x-csrf tokens are related are discussed in
|
|
149
|
+
// https://github.com/UI5/openui5/issues/2288
|
|
150
|
+
// As result, we want to enable earlyRequests only when we are very sure that it doesn't break anything
|
|
151
|
+
// -- i.e. for local CAP servers, which are known to require x-csrf tokens and are typically running on
|
|
152
|
+
// localhost:4004 at development time. This should at least cover a common use case.
|
|
153
|
+
// TODO: Could also find out with requests when server is alive?
|
|
154
|
+
const serverRequiresXCSRF = !!metadataUrl?.includes("localhost:4004");
|
|
155
|
+
let escapedOdataV4Url;
|
|
156
|
+
if (finalODataV4Url) {
|
|
157
|
+
// Always stringify the URL to ensure special characters like quotes
|
|
158
|
+
// do not break the JSON templates it is injected into
|
|
159
|
+
escapedOdataV4Url = JSON.stringify(finalODataV4Url).slice(1, -1); // Remove leading and trailing quotes
|
|
160
|
+
}
|
|
161
|
+
// Generate template variables
|
|
162
|
+
const templateVars = {
|
|
163
|
+
namespace: appNamespace,
|
|
164
|
+
framework: framework,
|
|
165
|
+
frameworkVersion,
|
|
166
|
+
author,
|
|
167
|
+
...(typescript && {
|
|
168
|
+
tstypes: getTypePackageFor(framework, frameworkVersion),
|
|
169
|
+
tstypesVersion: frameworkVersion,
|
|
170
|
+
}),
|
|
171
|
+
appId: appNamespace,
|
|
172
|
+
appURI: appNamespace.split(".").join("/"),
|
|
173
|
+
cdnDomain: fwkCDNDomain[framework],
|
|
174
|
+
oDataV4Url: escapedOdataV4Url,
|
|
175
|
+
oDataEntitySet,
|
|
176
|
+
entityProperties,
|
|
177
|
+
serverRequiresXCSRF,
|
|
178
|
+
defaultTheme: semver.gte(frameworkVersion, "1.108.0") ? "sap_horizon" : "sap_fiori_3",
|
|
179
|
+
qunitCoverageFile: semver.gte(frameworkVersion, "1.113.0") ?
|
|
180
|
+
"qunit-coverage-istanbul.js" :
|
|
181
|
+
"qunit-coverage.js",
|
|
182
|
+
gte1_98_0: semver.gte(frameworkVersion, "1.98.0"),
|
|
183
|
+
gte1_100_0: semver.gte(frameworkVersion, "1.100.0"),
|
|
184
|
+
gte1_104_0: semver.gte(frameworkVersion, "1.104.0"),
|
|
185
|
+
lt1_110_0: semver.lt(frameworkVersion, "1.110.0"),
|
|
186
|
+
gte1_115_0: semver.gte(frameworkVersion, "1.115.0"),
|
|
187
|
+
gte1_120_0: semver.gte(frameworkVersion, "1.120.0"),
|
|
188
|
+
lt1_124_0: semver.lt(frameworkVersion, "1.124.0"),
|
|
189
|
+
};
|
|
190
|
+
// Process template files
|
|
191
|
+
const templateDir = path.join(__dirname, "..", "..", "..", "resources", typescript ?
|
|
192
|
+
"template-ts" :
|
|
193
|
+
"template-js");
|
|
194
|
+
const generatedFiles = await processTemplates({
|
|
195
|
+
templateDir,
|
|
196
|
+
targetDir: finalLocation,
|
|
197
|
+
templateVars,
|
|
198
|
+
versionSpecificLogic: {
|
|
199
|
+
lt1_124_0: templateVars.lt1_124_0,
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
if (runNpmInstall) {
|
|
203
|
+
// Run npm install
|
|
204
|
+
await execa("npm", ["install"], {
|
|
205
|
+
cwd: finalLocation,
|
|
206
|
+
stdout: process.stderr,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
// Initialize git repository if requested
|
|
210
|
+
if (initializeGitRepository) {
|
|
211
|
+
await execa("git", ["init", "--quiet"], {
|
|
212
|
+
cwd: finalLocation,
|
|
213
|
+
stdout: process.stderr,
|
|
214
|
+
});
|
|
215
|
+
await execa("git", ["add", "."], {
|
|
216
|
+
cwd: finalLocation,
|
|
217
|
+
stdout: process.stderr,
|
|
218
|
+
});
|
|
219
|
+
await execa("git", ["commit", "--quiet", "--allow-empty", "-m", "Initial commit"], {
|
|
220
|
+
cwd: finalLocation,
|
|
221
|
+
stdout: process.stderr,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
message: `${framework} ${typescript ? "TypeScript" : "JavaScript"} application ` +
|
|
226
|
+
`${appNamespace} created successfully.`,
|
|
227
|
+
finalLocation,
|
|
228
|
+
generatedFiles, // array of generated file paths, relative to finalLocation
|
|
229
|
+
basePath,
|
|
230
|
+
appInfo: {
|
|
231
|
+
appNamespace,
|
|
232
|
+
framework: framework,
|
|
233
|
+
frameworkVersion,
|
|
234
|
+
finalODataV4Url,
|
|
235
|
+
oDataEntitySet,
|
|
236
|
+
entityProperties: entityProperties ?? [],
|
|
237
|
+
npmInstallExecuted: runNpmInstall,
|
|
238
|
+
gitInitialized: initializeGitRepository,
|
|
239
|
+
typescript,
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function getAllowedOdataV4Domains() {
|
|
244
|
+
if ("UI5_MCP_SERVER_ALLOWED_ODATA_DOMAINS" in process.env) {
|
|
245
|
+
const inputDomainList = process.env.UI5_MCP_SERVER_ALLOWED_ODATA_DOMAINS;
|
|
246
|
+
if (!inputDomainList?.trim()) {
|
|
247
|
+
// Empty list allows all domains
|
|
248
|
+
log.verbose("Empty value for UI5_MCP_SERVER_ALLOWED_ODATA_DOMAINS, allowing all domains");
|
|
249
|
+
return [];
|
|
250
|
+
}
|
|
251
|
+
// Use the environment variable if set
|
|
252
|
+
const domainList = inputDomainList.split(",").map((d) => d.trim());
|
|
253
|
+
// Validate domains to catch user errors
|
|
254
|
+
for (const domain of domainList) {
|
|
255
|
+
try {
|
|
256
|
+
// Note that the dot prefix (which we use for wildcards) is valid in a domain
|
|
257
|
+
new URL(`https://${domain}`);
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
throw new InvalidInputError(`Invalid domain '${domain}' in UI5_MCP_SERVER_ALLOWED_ODATA_DOMAINS: ` +
|
|
261
|
+
(err instanceof Error ? err.message : String(err)));
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
log.verbose(`${domainList.length} allowed OData V4 domains configured: ${domainList.join(", ")}`);
|
|
265
|
+
return domainList;
|
|
266
|
+
}
|
|
267
|
+
return [
|
|
268
|
+
// Default allowed domains for OData V4 services
|
|
269
|
+
"localhost",
|
|
270
|
+
"services.odata.org",
|
|
271
|
+
];
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=create_ui5_app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create_ui5_app.js","sourceRoot":"","sources":["../../../src/tools/create_ui5_app/create_ui5_app.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { createUi5App } from "./create_ui5_app.js";
|
|
2
|
+
import { createAppSchema } from "./schema.js";
|
|
3
|
+
import { createSuccessMessage } from "./createSuccessMessage.js";
|
|
4
|
+
import { getLogger } from "@ui5/logger";
|
|
5
|
+
const log = getLogger("tools:create_ui5_app");
|
|
6
|
+
export default function registerTool(registerTool, context) {
|
|
7
|
+
registerTool("create_ui5_app", {
|
|
8
|
+
description: "Create a new basic SAPUI5 application implemented in TypeScript or JavaScript",
|
|
9
|
+
annotations: {
|
|
10
|
+
title: "Create SAPUI5 App",
|
|
11
|
+
readOnlyHint: false,
|
|
12
|
+
},
|
|
13
|
+
inputSchema: createAppSchema,
|
|
14
|
+
}, async (params) => {
|
|
15
|
+
log.info(`Creating a new UI5 application at ${params.basePath}`);
|
|
16
|
+
log.info(` Using framework: ${params.framework}, version: ${params.frameworkVersion}`);
|
|
17
|
+
log.info(` Namespace: ${params.appNamespace}`);
|
|
18
|
+
log.info(` OData V4 URL: ${params.oDataV4Url}`);
|
|
19
|
+
log.info(` OData entity set: ${params.oDataEntitySet}`);
|
|
20
|
+
log.info(` Create app directory: ${params.createAppDirectory}`);
|
|
21
|
+
log.info(` Run npm install: ${params.runNpmInstall}`);
|
|
22
|
+
log.info(` Initialize git repository: ${params.initializeGitRepository}`);
|
|
23
|
+
log.info(` TypeScript: ${params.typescript}`);
|
|
24
|
+
const resolvedBasePath = await context.normalizePath(params.basePath);
|
|
25
|
+
const result = await createUi5App({
|
|
26
|
+
basePath: resolvedBasePath,
|
|
27
|
+
framework: params.framework,
|
|
28
|
+
frameworkVersion: params.frameworkVersion,
|
|
29
|
+
appNamespace: params.appNamespace,
|
|
30
|
+
oDataV4Url: params.oDataV4Url,
|
|
31
|
+
oDataEntitySet: params.oDataEntitySet,
|
|
32
|
+
createAppDirectory: params.createAppDirectory,
|
|
33
|
+
runNpmInstall: params.runNpmInstall,
|
|
34
|
+
initializeGitRepository: params.initializeGitRepository,
|
|
35
|
+
typescript: params.typescript,
|
|
36
|
+
});
|
|
37
|
+
const message = createSuccessMessage({
|
|
38
|
+
finalLocation: result.finalLocation,
|
|
39
|
+
generatedFiles: result.generatedFiles,
|
|
40
|
+
basePath: result.basePath,
|
|
41
|
+
finalODataV4Url: result.appInfo?.finalODataV4Url,
|
|
42
|
+
oDataEntitySet: result.appInfo?.oDataEntitySet,
|
|
43
|
+
entityProperties: result.appInfo.entityProperties,
|
|
44
|
+
appNamespace: result.appInfo.appNamespace,
|
|
45
|
+
framework: result.appInfo.framework,
|
|
46
|
+
frameworkVersion: result.appInfo.frameworkVersion,
|
|
47
|
+
runNpmInstall: result.appInfo.npmInstallExecuted,
|
|
48
|
+
typescript: result.appInfo.typescript,
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
content: [{
|
|
52
|
+
type: "text",
|
|
53
|
+
text: message,
|
|
54
|
+
}],
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/create_ui5_app/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates a URL against a set of specified rules, including protocol and domain allow lists.
|
|
3
|
+
*
|
|
4
|
+
* @param urlString The string to validate as a URL.
|
|
5
|
+
* @param domainAllowList An array of allowed domain names.
|
|
6
|
+
* - An empty array allows any domain.
|
|
7
|
+
* - e.g., ["localhost", "example.com", "sub.example.com"]
|
|
8
|
+
* - For wildcard subdomains, prefix the domain with a dot: ".example.com".
|
|
9
|
+
* This will match "www.example.com" but not "example.com".
|
|
10
|
+
* @param protocolAllowList An array of allowed protocols (without the trailing colon).
|
|
11
|
+
* - An empty array allows any protocol.
|
|
12
|
+
* - e.g., ["http", "https"]
|
|
13
|
+
* @returns `true` if the URL is valid according to the rules, otherwise `false`.
|
|
14
|
+
* @throws {InvalidInputError} if the URL's domain is not in the provided allow list.
|
|
15
|
+
*/
|
|
16
|
+
export default function isValidUrl(urlString: string, domainAllowList?: string[], protocolAllowList?: string[]): boolean;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { InvalidInputError } from "../../utils.js";
|
|
2
|
+
/**
|
|
3
|
+
* Validates a URL against a set of specified rules, including protocol and domain allow lists.
|
|
4
|
+
*
|
|
5
|
+
* @param urlString The string to validate as a URL.
|
|
6
|
+
* @param domainAllowList An array of allowed domain names.
|
|
7
|
+
* - An empty array allows any domain.
|
|
8
|
+
* - e.g., ["localhost", "example.com", "sub.example.com"]
|
|
9
|
+
* - For wildcard subdomains, prefix the domain with a dot: ".example.com".
|
|
10
|
+
* This will match "www.example.com" but not "example.com".
|
|
11
|
+
* @param protocolAllowList An array of allowed protocols (without the trailing colon).
|
|
12
|
+
* - An empty array allows any protocol.
|
|
13
|
+
* - e.g., ["http", "https"]
|
|
14
|
+
* @returns `true` if the URL is valid according to the rules, otherwise `false`.
|
|
15
|
+
* @throws {InvalidInputError} if the URL's domain is not in the provided allow list.
|
|
16
|
+
*/
|
|
17
|
+
export default function isValidUrl(urlString, domainAllowList = [], protocolAllowList = ["http", "https"]) {
|
|
18
|
+
let url;
|
|
19
|
+
// 1. Validate URL structure using the WHATWG URL API.
|
|
20
|
+
try {
|
|
21
|
+
url = new URL(urlString);
|
|
22
|
+
}
|
|
23
|
+
catch (_err) {
|
|
24
|
+
// If the URL constructor throws an error, the URL is malformed.
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
// 2. Validate the protocol.
|
|
28
|
+
if (protocolAllowList.length > 0) {
|
|
29
|
+
// The `protocol` property includes the colon (e.g., "https:").
|
|
30
|
+
// We remove it for a clean comparison.
|
|
31
|
+
const urlProtocol = url.protocol.slice(0, -1);
|
|
32
|
+
if (!protocolAllowList.includes(urlProtocol)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// 3. Validate the domain/hostname.
|
|
37
|
+
if (domainAllowList.length > 0) {
|
|
38
|
+
const hostname = url.hostname;
|
|
39
|
+
const isDomainAllowed = domainAllowList.some((allowedDomain) => {
|
|
40
|
+
// Wildcard domain check (e.g., ".example.com")
|
|
41
|
+
if (allowedDomain.startsWith(".")) {
|
|
42
|
+
// Must match the suffix and not be the root domain itself.
|
|
43
|
+
// e.g., "api.example.com" ends with ".example.com"
|
|
44
|
+
// e.g., "example.com" does NOT end with ".example.com"
|
|
45
|
+
return hostname.endsWith(allowedDomain);
|
|
46
|
+
}
|
|
47
|
+
// Exact domain match
|
|
48
|
+
return hostname === allowedDomain;
|
|
49
|
+
});
|
|
50
|
+
if (!isDomainAllowed) {
|
|
51
|
+
throw new InvalidInputError(`Domain "${hostname}" is not allowed. Allowed domains are: ${domainAllowList.join(", ")}. See ` +
|
|
52
|
+
`https://github.com/UI5/mcp-server#configuration for information on how to configure the allow list.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// If all checks pass, the URL is valid.
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
;
|
|
59
|
+
//# sourceMappingURL=isValidUrl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isValidUrl.js","sourceRoot":"","sources":["../../../src/tools/create_ui5_app/isValidUrl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,iBAAiB,EAAC,MAAM,gBAAgB,CAAC;AAEjD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,OAAO,UAAU,UAAU,CACjC,SAAiB,EACjB,kBAA4B,EAAE,EAC9B,oBAA8B,CAAC,MAAM,EAAE,OAAO,CAAC;IAE/C,IAAI,GAAQ,CAAC;IAEb,sDAAsD;IACtD,IAAI,CAAC;QACJ,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,IAAI,EAAE,CAAC;QACf,gEAAgE;QAChE,OAAO,KAAK,CAAC;IACd,CAAC;IAED,4BAA4B;IAC5B,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,+DAA+D;QAC/D,uCAAuC;QACvC,MAAM,WAAW,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9C,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9C,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IAED,mCAAmC;IACnC,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;QAE9B,MAAM,eAAe,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,EAAE;YAC9D,+CAA+C;YAC/C,IAAI,aAAa,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnC,2DAA2D;gBAC3D,mDAAmD;gBACnD,uDAAuD;gBACvD,OAAO,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;YACzC,CAAC;YAED,qBAAqB;YACrB,OAAO,QAAQ,KAAK,aAAa,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,eAAe,EAAE,CAAC;YACtB,MAAM,IAAI,iBAAiB,CAC1B,WAAW,QAAQ,0CAA0C,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;gBAC/F,qGAAqG,CAAC,CAAC;QACzG,CAAC;IACF,CAAC;IAED,wCAAwC;IACxC,OAAO,IAAI,CAAC;AACb,CAAC;AAAA,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
import { Ui5Framework } from "../../utils/ui5Framework.js";
|
|
3
|
+
export declare const createAppSchema: {
|
|
4
|
+
appNamespace: z.ZodString;
|
|
5
|
+
basePath: z.ZodString;
|
|
6
|
+
createAppDirectory: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
7
|
+
framework: z.ZodDefault<z.ZodOptional<z.ZodEnum<["OpenUI5", "SAPUI5"]>>>;
|
|
8
|
+
frameworkVersion: z.ZodOptional<z.ZodString>;
|
|
9
|
+
author: z.ZodOptional<z.ZodString>;
|
|
10
|
+
oDataV4Url: z.ZodOptional<z.ZodString>;
|
|
11
|
+
oDataEntitySet: z.ZodOptional<z.ZodString>;
|
|
12
|
+
entityProperties: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
13
|
+
initializeGitRepository: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
14
|
+
runNpmInstall: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
15
|
+
typescript: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
16
|
+
};
|
|
17
|
+
export declare const createAppSchemaObject: z.ZodObject<{
|
|
18
|
+
appNamespace: z.ZodString;
|
|
19
|
+
basePath: z.ZodString;
|
|
20
|
+
createAppDirectory: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
21
|
+
framework: z.ZodDefault<z.ZodOptional<z.ZodEnum<["OpenUI5", "SAPUI5"]>>>;
|
|
22
|
+
frameworkVersion: z.ZodOptional<z.ZodString>;
|
|
23
|
+
author: z.ZodOptional<z.ZodString>;
|
|
24
|
+
oDataV4Url: z.ZodOptional<z.ZodString>;
|
|
25
|
+
oDataEntitySet: z.ZodOptional<z.ZodString>;
|
|
26
|
+
entityProperties: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
27
|
+
initializeGitRepository: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
28
|
+
runNpmInstall: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
29
|
+
typescript: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
30
|
+
}, "strip", z.ZodTypeAny, {
|
|
31
|
+
appNamespace: string;
|
|
32
|
+
basePath: string;
|
|
33
|
+
createAppDirectory: boolean;
|
|
34
|
+
framework: "OpenUI5" | "SAPUI5";
|
|
35
|
+
initializeGitRepository: boolean;
|
|
36
|
+
runNpmInstall: boolean;
|
|
37
|
+
typescript: boolean;
|
|
38
|
+
frameworkVersion?: string | undefined;
|
|
39
|
+
author?: string | undefined;
|
|
40
|
+
oDataV4Url?: string | undefined;
|
|
41
|
+
oDataEntitySet?: string | undefined;
|
|
42
|
+
entityProperties?: string[] | undefined;
|
|
43
|
+
}, {
|
|
44
|
+
appNamespace: string;
|
|
45
|
+
basePath: string;
|
|
46
|
+
createAppDirectory?: boolean | undefined;
|
|
47
|
+
framework?: "OpenUI5" | "SAPUI5" | undefined;
|
|
48
|
+
frameworkVersion?: string | undefined;
|
|
49
|
+
author?: string | undefined;
|
|
50
|
+
oDataV4Url?: string | undefined;
|
|
51
|
+
oDataEntitySet?: string | undefined;
|
|
52
|
+
entityProperties?: string[] | undefined;
|
|
53
|
+
initializeGitRepository?: boolean | undefined;
|
|
54
|
+
runNpmInstall?: boolean | undefined;
|
|
55
|
+
typescript?: boolean | undefined;
|
|
56
|
+
}>;
|
|
57
|
+
/**
|
|
58
|
+
* Parameters for creating a basic UI5 application.
|
|
59
|
+
*
|
|
60
|
+
* @typedef {Object} CreateUi5AppParams
|
|
61
|
+
* @property {string} appNamespace - The namespace for the application, e.g. com.myorg.myapp. Only lowercase
|
|
62
|
+
* alpha-numeric characters, underscores and dots are allowed.
|
|
63
|
+
* @property {string} basePath - Absolute base path for the creation. The application will be created either
|
|
64
|
+
* immediately inside this path or in a subdirectory (its name equals the
|
|
65
|
+
* application namespace) depending on the 'createAppDirectory' parameter.
|
|
66
|
+
* This path must be absolute, not just 'app' or '.' or './something'!
|
|
67
|
+
* @property {boolean} [createAppDirectory] - Whether to create a new directory (name equals the application namespace)
|
|
68
|
+
* inside the base path. Set this to 'false' when you want to place the application directly
|
|
69
|
+
* in the given base path. In SAP CAP applications, typically give the path to the "app" folder
|
|
70
|
+
* as basePath and set this to 'true' to create an application folder. Default: true.
|
|
71
|
+
* @property {string} [framework] - The framework to use (OpenUI5 or SAPUI5), defaults to SAPUI5.
|
|
72
|
+
* @property {string} [frameworkVersion] - The framework version to use, e.g. 1.136.0,
|
|
73
|
+
* defaults to the latest version.
|
|
74
|
+
* @property {string} [author] - The author of the application (auto-detected if not provided).
|
|
75
|
+
* @property {string} [oDataV4Url] - URL of an OData V4 service, if applicable. This is entirely optional, but without
|
|
76
|
+
* it, the generated app UI will have no OData Model configured. Setting an URL will configure an
|
|
77
|
+
* OData V4 model in the application. Only works for OData V4 services, not for OData V2.
|
|
78
|
+
* The URL must be either a valid complete URL starting with http:// or https:// or a
|
|
79
|
+
* server-root-relative URL like '/odata/v4/serviceName' when the OData service is running on
|
|
80
|
+
* the same server. In this case, the prefix 'http://localhost:4004/' will be assumed and used
|
|
81
|
+
* by this tool for inquiries about the service. When the port is not 4004, a complete
|
|
82
|
+
* 'http://localhost:<port>...' URL must be provided. In the generated application, any
|
|
83
|
+
* 'http://localhost:<port>' prefix will be removed.
|
|
84
|
+
* @property {string} [oDataEntitySet] - Entity set of the OData V4 service to display. Only has an effect when
|
|
85
|
+
* 'oDataV4Url' is set as well. This is optional. Setting an entity set will configure a basic
|
|
86
|
+
* UI displaying the entity set in the application.
|
|
87
|
+
* @property {string[]} [entityProperties] - Properties of the OData entity set to display. Only has an effect when
|
|
88
|
+
* 'oDataV4Url' and 'oDataEntitySet' are set. This parameter is optional, but useful to display
|
|
89
|
+
* initial data, when the names of existing properties are known. If not provided and the service
|
|
90
|
+
* is active and reachable at tool execution time, some random properties will be displayed.
|
|
91
|
+
* @property {boolean} [runNpmInstall] - Whether to execute npm install after creating the application.
|
|
92
|
+
* Default: true.
|
|
93
|
+
* @property {boolean} [initializeGitRepository] - Whether to initialize a local git repository for the application.
|
|
94
|
+
* Default: true.
|
|
95
|
+
* @property {boolean} [typescript] - Whether to create a TypeScript application (true) or JavaScript
|
|
96
|
+
* application (false). Default: true.
|
|
97
|
+
*/
|
|
98
|
+
export type CreateUi5AppParams = z.input<typeof createAppSchemaObject>;
|
|
99
|
+
/**
|
|
100
|
+
* Result of the createUi5App function.
|
|
101
|
+
*
|
|
102
|
+
* @typedef {Object} CreateUi5AppResult
|
|
103
|
+
* @property {string} message - Basic success/error message only.
|
|
104
|
+
* @property {string} finalLocation - Final location (app root directory) of the created application (if successful).
|
|
105
|
+
* @property {string[]} generatedFiles - Array of generated file paths relative to finalLocation.
|
|
106
|
+
* @property {string} basePath - Absolute base path used for creation.
|
|
107
|
+
* @property {Object} [appInfo] - Structured app information.
|
|
108
|
+
* @property {string} appInfo.appNamespace - The namespace of the application.
|
|
109
|
+
* @property {Ui5Framework} appInfo.framework - The framework used for the application.
|
|
110
|
+
* @property {string} appInfo.frameworkVersion - The version of the framework used.
|
|
111
|
+
* @property {string} [appInfo.finalODataV4Url] - Final OData V4 service URL, if applicable.
|
|
112
|
+
* @property {string} [appInfo.oDataEntitySet] - OData entity set, if applicable.
|
|
113
|
+
* @property {string[]} [appInfo.entityProperties] - Properties of the OData entity set, if applicable.
|
|
114
|
+
* @property {boolean} appInfo.npmInstallExecuted - Whether 'npm install' was executed.
|
|
115
|
+
* @property {boolean} appInfo.gitInitialized - Whether a local git repository was initialized.
|
|
116
|
+
* @property {boolean} appInfo.typescript - Whether the application is a TypeScript application (true) or a JavaScript
|
|
117
|
+
* application (false).
|
|
118
|
+
*/
|
|
119
|
+
export interface CreateUi5AppResult {
|
|
120
|
+
message: string;
|
|
121
|
+
finalLocation: string;
|
|
122
|
+
generatedFiles: string[];
|
|
123
|
+
basePath: string;
|
|
124
|
+
appInfo?: {
|
|
125
|
+
appNamespace: string;
|
|
126
|
+
framework: Ui5Framework;
|
|
127
|
+
frameworkVersion: string;
|
|
128
|
+
finalODataV4Url?: string;
|
|
129
|
+
oDataEntitySet?: string;
|
|
130
|
+
entityProperties?: string[];
|
|
131
|
+
npmInstallExecuted: boolean;
|
|
132
|
+
gitInitialized: boolean;
|
|
133
|
+
typescript: boolean;
|
|
134
|
+
};
|
|
135
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
import { Ui5FrameworkSchema } from "../../utils/ui5Framework.js";
|
|
3
|
+
export const createAppSchema = {
|
|
4
|
+
appNamespace: z.string()
|
|
5
|
+
.regex(/^[a-z0-9][a-z0-9_.]*$/, { message: `Only alphanumeric characters, underscores and dots are allowed.` })
|
|
6
|
+
.describe("The namespace for the application, e.g. com.myorg.myapp. " +
|
|
7
|
+
"Only lowercase alpha-numeric characters, underscores and dots are allowed."),
|
|
8
|
+
basePath: z.string()
|
|
9
|
+
.describe("Absolute base path for the creation. The application will be created either" +
|
|
10
|
+
" immediately inside this path or in a subdirectory (its name equals the" +
|
|
11
|
+
" application namespace), depending on the 'createAppDirectory' parameter." +
|
|
12
|
+
" This base path must be absolute, not just 'app' or '.' or './something'!"),
|
|
13
|
+
// NOTE: technically, this could be a relative path, but the current directory in MCP context is often
|
|
14
|
+
// not defined well, but is root (/)
|
|
15
|
+
createAppDirectory: z.boolean().optional().default(true)
|
|
16
|
+
.describe("Whether to create a new directory (name equals the application namespace)" +
|
|
17
|
+
" inside the base path. Set this to 'false' when you want to place the 'app' directly" +
|
|
18
|
+
" in the given base path. In SAP CAP applications, typically give the path to the 'app' folder" +
|
|
19
|
+
" as basePath and set this to 'true' to create an application folder. Default: true."),
|
|
20
|
+
framework: Ui5FrameworkSchema.optional().default("SAPUI5")
|
|
21
|
+
.describe("Framework to use (OpenUI5 or SAPUI5), defaults to SAPUI5"),
|
|
22
|
+
frameworkVersion: z.string()
|
|
23
|
+
.regex(/^\d+\.\d+\.\d+$/, { message: "Version must be in format X.Y.Z, e.g. 1.120.0" })
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Framework version, defaults to latest version. Omit this when in doubt." +
|
|
26
|
+
" When provided, it must be a concrete semantic version, like e.g. 1.136.0. Versions older than 1.96.0" +
|
|
27
|
+
" are not supported."),
|
|
28
|
+
author: z.string()
|
|
29
|
+
.regex(/^[a-zA-Z0-9 .,'@_-]+$/, { message: "Only alphanumeric characters, space, and .,'-@_ are allowed." })
|
|
30
|
+
.optional()
|
|
31
|
+
.describe("Author of the application (auto-detected if not provided)"),
|
|
32
|
+
oDataV4Url: z.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe("URL of an OData V4 service, if applicable. This is entirely optional, but without it," +
|
|
35
|
+
" the generated app UI will have no OData Model configured. Setting an URL will configure an" +
|
|
36
|
+
" OData V4 model in the application. Only works for OData V4 services, not for OData V2." +
|
|
37
|
+
" The URL must be either a valid complete URL starting with http:// or https:// or a" +
|
|
38
|
+
" server-root-relative URL like '/odata/v4/serviceName' when the OData service is running on" +
|
|
39
|
+
" the same server. In this case, the prefix 'http://localhost:4004/' will be assumed and used" +
|
|
40
|
+
" by this tool for inquiries about the service. When the port is not 4004, a complete" +
|
|
41
|
+
" 'http://localhost:<port>...' URL must be provided. In the generated application, any" +
|
|
42
|
+
" 'http://localhost:<port>' prefix will be removed. HINT: when the project is a SAP CAP project" +
|
|
43
|
+
" and CAP/CDS tools are available, you **MUST** use them to search for OData services and entities" +
|
|
44
|
+
" and properties **BEFORE** calling this tool. This will help you find the correct service URL."),
|
|
45
|
+
oDataEntitySet: z.string()
|
|
46
|
+
.regex(/^[a-zA-Z0-9_]+$/, { message: "Only alphanumeric characters and underscore are allowed." })
|
|
47
|
+
.optional()
|
|
48
|
+
.describe("Entity set of the OData V4 service to display. Only has an effect when 'oDataV4Url' is set as" +
|
|
49
|
+
" well. This is optional, but setting an entity set is beneficial, as it will configure a basic UI" +
|
|
50
|
+
" in the application which displays the entity set."),
|
|
51
|
+
entityProperties: z.array(z.string().regex(/^[a-zA-Z0-9_]+$/, { message: "Only alphanumeric characters and underscore are allowed." })).optional()
|
|
52
|
+
.describe("Properties of the OData entity set to display. Only has an effect when 'oDataV4Url' and" +
|
|
53
|
+
"'oDataEntitySet' are set. This parameter is optional, but useful to display initial data, when the" +
|
|
54
|
+
" names of existing properties are known. If not provided and the service is active and reachable at" +
|
|
55
|
+
" tool execution time, some random properties will be displayed."),
|
|
56
|
+
initializeGitRepository: z.boolean().optional().default(true)
|
|
57
|
+
.describe("Initialize a local git repository for the application, default is 'true'"),
|
|
58
|
+
runNpmInstall: z.boolean().optional().default(true)
|
|
59
|
+
.describe("Execute npm install after creating the application, default is 'true'"),
|
|
60
|
+
typescript: z.boolean().optional().default(true)
|
|
61
|
+
.describe("Whether to create a TypeScript application (true) or JavaScript application (false)," +
|
|
62
|
+
" default is 'true'. Although the default is preferred, the user MUST know about" +
|
|
63
|
+
" this option before generation, but you should not require an active decision. Also, if an overall" +
|
|
64
|
+
" project already exists, this should influence the language choice to keep things consistent."),
|
|
65
|
+
};
|
|
66
|
+
export const createAppSchemaObject = z.object(createAppSchema);
|
|
67
|
+
//# sourceMappingURL=schema.js.map
|