diff --git a/package.json b/package.json index 1379ee913..1e362c279 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "build-webc:ts": "pnpm --filter ui5-tsapp-webc build", "build-cds": "pnpm --filter cds-bookshop build", "build-bookshop": "pnpm --filter ui5-bookshop-viewer build", + "jsdoc-lib:ts": "pnpm --filter ui5-tslib jsdoc", "clean": "pnpm --filter ui5-app clean", "dev": "pnpm --filter ui5-app dev", "dev:ts": "pnpm --filter ui5-tsapp dev", diff --git a/packages/ui5-tooling-modules/lib/task-jsdoc.js b/packages/ui5-tooling-modules/lib/task-jsdoc.js new file mode 100644 index 000000000..6ff3a7a2c --- /dev/null +++ b/packages/ui5-tooling-modules/lib/task-jsdoc.js @@ -0,0 +1,59 @@ +const path = require("path"); +const { existsSync } = require("fs"); +const WebComponentRegistry = require("./utils/WebComponentRegistry"); + +/** + * Custom task to create the UI5 AMD-like bundles for used ES imports from node_modules. + * + * @param {object} parameters Parameters + * @param {module:@ui5/logger/Logger} parameters.log Logger instance + * @param {module:@ui5/fs/DuplexCollection} parameters.workspace DuplexCollection to read and write files + * @param {object} parameters.taskUtil Specification Version dependent interface to a + * [TaskUtil]{@link module:@ui5/builder.tasks.TaskUtil} instance + * @param {object} parameters.options Options + * @param {string} parameters.options.projectName Project name + * @param {string} [parameters.options.projectNamespace] Project namespace if available + * @param {object} [parameters.options.configuration] Task configuration if given in ui5.yaml + * @returns {Promise} Promise resolving with undefined once data has been written + */ +module.exports = async function ({ log, workspace, taskUtil /*, options */ }) { + // determine the current working directory and the package.json path + let cwd = taskUtil.getProject().getRootPath() || process.cwd(); + let pkgJsonPath = path.join(cwd, "package.json"); + + // if the package.json is not in the root of the project, try to find it + // in the npm_package_json environment variable (used by npm scripts) + if (!existsSync(pkgJsonPath)) { + pkgJsonPath = process.env.npm_package_json; + cwd = path.dirname(pkgJsonPath); + } + const pkgJson = require(pkgJsonPath); + + for (const dep of Object.keys(pkgJson.dependencies)) { + console.log("XXX", WebComponentRegistry.getPackage(dep)); + } + + const apiJsons = await workspace.byGlob("/**/designtime/api.json"); + if (apiJsons.length === 1) { + const apiJson = JSON.parse(await apiJsons[0].getString()); + console.log("API JSON"); + apiJson.__MODIFIED = "HURRAY"; + apiJsons[0].setString(JSON.stringify(apiJson, null, 2)); + await workspace.write(apiJsons[0]); + } + + log.info("Hello World!"); +}; + +/** + * Callback function to define the list of required dependencies + * + * @returns {Promise} + * Promise resolving with a Set containing all dependencies + * that should be made available to the task. + * UI5 Tooling will ensure that those dependencies have been + * built before executing the task. + */ +module.exports.determineRequiredDependencies = async function () { + return new Set(); // dependency resolution uses Nodes' require APIs +}; diff --git a/packages/ui5-tooling-modules/ui5.yaml b/packages/ui5-tooling-modules/ui5.yaml index d1216891e..77f27ce31 100644 --- a/packages/ui5-tooling-modules/ui5.yaml +++ b/packages/ui5-tooling-modules/ui5.yaml @@ -15,3 +15,12 @@ kind: extension type: task task: path: lib/task.js +--- +# https://sap.github.io/ui5-tooling/pages/extensibility/CustomTasks/ +specVersion: "3.0" +metadata: + name: ui5-tooling-modules-task-jsdoc +kind: extension +type: task +task: + path: lib/task-jsdoc.js diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2f706b065..780854a0c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1168,6 +1168,13 @@ importers: version: link:../../packages/ui5-tooling-transpile showcases/ui5-tslib: + dependencies: + '@ui5/webcomponents': + specifier: 2.6.2 + version: 2.6.2 + '@ui5/webcomponents-base': + specifier: 2.6.2 + version: 2.6.2 devDependencies: '@types/openui5': specifier: 1.129.0 @@ -2739,6 +2746,9 @@ packages: '@sap-theming/theming-base-content@11.17.1': resolution: {integrity: sha512-C13DbCBGkLYRZtQU7d6TmDHChA+S7bs26xk+fqHL0pBJTOm4V8NP1sj1SPfI9mbkUp+f5QLcWaENwUoTF00ElA==} + '@sap-theming/theming-base-content@11.24.0': + resolution: {integrity: sha512-Mtk011SHZhmhnRaD7B0eMVqGwPBuu1d9PaWkTpSD30MUuLZ0Uag4OMczWDT1oJwq0zGFYxGZxwtiCMwkwBxCKw==} + '@sap/approuter@17.0.0': resolution: {integrity: sha512-/LT6bz8a0L6IPi66uWFvmTEAQ/gGm5mOJbvnsyH0dmshBkFwfmR/iR76BFA5SxrAQv0ts0UQ9COXhaKozgZR3A==} engines: {node: ^18.0.0 || ^20.0.0} @@ -3209,27 +3219,48 @@ packages: '@ui5/webcomponents-base@2.5.0': resolution: {integrity: sha512-PRvQi+gKtzS7pMlUEvHGJ448Hhgce4Bey5nhnYIrSZJW9hgKn/XaydnvFwjQSbpOf88gmvor695jTnaLxgdFPw==} + '@ui5/webcomponents-base@2.6.2': + resolution: {integrity: sha512-CgIwDyA0wESE9aM23cfxsn4bfWH4ZUE8Rc3Qfrb73AsKWw+VbCtzZEy7wTdnTjGfW5zsVXWA6vvFxA89TS0Q6Q==} + '@ui5/webcomponents-fiori@2.5.0': resolution: {integrity: sha512-aqX0LLVvoDyJwpUQshxzUdisqmmUWIHna146eW4JigBvEVQadkP64JXcmfz0B1H6KPChTdlFTT4Wl70jBZY73w==} '@ui5/webcomponents-icons-business-suite@2.5.0': resolution: {integrity: sha512-nDRcR8+XsQfcNPuUxcQwMvwEa6bJJ8O/XHQt3oe6gXJAa6oHTNMpFxNS65WSa8PFidMA7RgRyMMqajENjsEsKQ==} + '@ui5/webcomponents-icons-business-suite@2.6.2': + resolution: {integrity: sha512-TOAb71dzTokvVvTulS7GTabM7MmRsyyTFu/f10QtZbq4dHXrTlWEYLm4gd0Swrq3z3xD/5abHpeybMS5B8ikWQ==} + '@ui5/webcomponents-icons-tnt@2.5.0': resolution: {integrity: sha512-aliilP0pxCrvPw3CL2KaaeZB6gHVKExNDCuLRfos64+HSW6zEOrKXF8VD8WQ1P3+HPCgeY2VcLFfRaJrSdieqw==} + '@ui5/webcomponents-icons-tnt@2.6.2': + resolution: {integrity: sha512-SHJzZAHAAVjVdzf+syfU2O/sUzqwgeJEjh04SxVIKCOC+w1+siLNixnyfnlyMfgBHVPjJGRn07R5SsaLziTbJA==} + '@ui5/webcomponents-icons@2.5.0': resolution: {integrity: sha512-rlwXOuTqZSIQ+KqMBx/WT92Qd9dWkoUeltJZVH9nj1nITwVkgTxwrL38ODUtbc1cztIoBSBM/qzgef3om+nUDQ==} + '@ui5/webcomponents-icons@2.6.2': + resolution: {integrity: sha512-GizvWn0imBlLZgBHABF3+ke/s2TsioEFIfaVAcJIHe5yP6fbbkQEKN2sXSfj3X5TY4k8pyfH41qt518IvK/k6A==} + '@ui5/webcomponents-localization@2.5.0': resolution: {integrity: sha512-k85KJ70ayVWMQThOIlgT2bE1ULvl7Szvs3IjJVENa+HuxIC4LFBUESvzNjH7ccz9JT54f3xfOF2SnR6Xv6SuMA==} + '@ui5/webcomponents-localization@2.6.2': + resolution: {integrity: sha512-c4Sy0jjOFFZ9F5+gO1hmf+dnJGVcpgNjmU4LuYaBIY6/pJqzG1U8aY/ZoLisuBWeYxZHvadwkhOwJ/cSfpn4dQ==} + '@ui5/webcomponents-theming@2.5.0': resolution: {integrity: sha512-8RUtlPanhzuOC0btRr024C4KuhNFP0t1N/nfsNdHmwZfCHO4sdzJndP3M9w/NfUd6A/ji3DZFD69lriIWTT1/g==} + '@ui5/webcomponents-theming@2.6.2': + resolution: {integrity: sha512-AbZTh6rJaLkNalmwX8F44kORAdEUVTGlWxIXPHJ8pyrpIt5+AcQxT+NqQAiCL2DpWeEg8SsttMK0yG2ws9dCgw==} + '@ui5/webcomponents@2.5.0': resolution: {integrity: sha512-dsk9gU8UfDmMbyRAyNhr/tNPMC/Ve8XbCPf2xRZHtLjRlVrPGk9NY+V9lyqWc0GIpVEtouyJxgocy8hxUZFAVw==} + '@ui5/webcomponents@2.6.2': + resolution: {integrity: sha512-gxLUFXesJ1502YCdFrgrrtCXeqq/jjNmwq0ctj+vDwwxIhCsXXNCo+m1aaMclTY1aOSagEKSd1ynqXftQ7t2LA==} + '@vercel/nft@0.27.5': resolution: {integrity: sha512-b2A7M+4yMHdWKY7xCC+kBEcnMrpaSE84CnuauTjhKKoCEeej0byJMAB8h/RBVnw/HdZOAFVcxR0Izr3LL24FwA==} engines: {node: '>=16'} @@ -11757,6 +11788,8 @@ snapshots: '@sap-theming/theming-base-content@11.17.1': {} + '@sap-theming/theming-base-content@11.24.0': {} + '@sap/approuter@17.0.0(encoding@0.1.13)': dependencies: '@sap/audit-logging': 6.1.0(encoding@0.1.13) @@ -12622,6 +12655,11 @@ snapshots: '@lit-labs/ssr-dom-shim': 1.2.1 lit-html: 2.8.0 + '@ui5/webcomponents-base@2.6.2': + dependencies: + '@lit-labs/ssr-dom-shim': 1.2.1 + lit-html: 2.8.0 + '@ui5/webcomponents-fiori@2.5.0': dependencies: '@ui5/webcomponents': 2.5.0 @@ -12634,24 +12672,46 @@ snapshots: dependencies: '@ui5/webcomponents-base': 2.5.0 + '@ui5/webcomponents-icons-business-suite@2.6.2': + dependencies: + '@ui5/webcomponents-base': 2.6.2 + '@ui5/webcomponents-icons-tnt@2.5.0': dependencies: '@ui5/webcomponents-base': 2.5.0 + '@ui5/webcomponents-icons-tnt@2.6.2': + dependencies: + '@ui5/webcomponents-base': 2.6.2 + '@ui5/webcomponents-icons@2.5.0': dependencies: '@ui5/webcomponents-base': 2.5.0 + '@ui5/webcomponents-icons@2.6.2': + dependencies: + '@ui5/webcomponents-base': 2.6.2 + '@ui5/webcomponents-localization@2.5.0': dependencies: '@types/openui5': 1.129.0 '@ui5/webcomponents-base': 2.5.0 + '@ui5/webcomponents-localization@2.6.2': + dependencies: + '@types/openui5': 1.129.0 + '@ui5/webcomponents-base': 2.6.2 + '@ui5/webcomponents-theming@2.5.0': dependencies: '@sap-theming/theming-base-content': 11.17.1 '@ui5/webcomponents-base': 2.5.0 + '@ui5/webcomponents-theming@2.6.2': + dependencies: + '@sap-theming/theming-base-content': 11.24.0 + '@ui5/webcomponents-base': 2.6.2 + '@ui5/webcomponents@2.5.0': dependencies: '@ui5/webcomponents-base': 2.5.0 @@ -12661,6 +12721,15 @@ snapshots: '@ui5/webcomponents-localization': 2.5.0 '@ui5/webcomponents-theming': 2.5.0 + '@ui5/webcomponents@2.6.2': + dependencies: + '@ui5/webcomponents-base': 2.6.2 + '@ui5/webcomponents-icons': 2.6.2 + '@ui5/webcomponents-icons-business-suite': 2.6.2 + '@ui5/webcomponents-icons-tnt': 2.6.2 + '@ui5/webcomponents-localization': 2.6.2 + '@ui5/webcomponents-theming': 2.6.2 + '@vercel/nft@0.27.5(encoding@0.1.13)': dependencies: '@mapbox/node-pre-gyp': 1.0.11(encoding@0.1.13) diff --git a/showcases/ui5-tslib/package.json b/showcases/ui5-tslib/package.json index df507da7f..518b0ade7 100644 --- a/showcases/ui5-tslib/package.json +++ b/showcases/ui5-tslib/package.json @@ -9,6 +9,7 @@ "scripts": { "clean": "rimraf dist coverage", "build": "ui5 build --clean-dest", + "jsdoc": "ui5 build jsdoc --exclude-task buildThemes", "dev": "ui5 serve --port 8080 -o test-resources/ui5/ecosystem/demo/tslib/Example.html", "start": "ui5 serve --port 8080 -o test-resources/ui5/ecosystem/demo/tslib/Example.html --config ui5-dist.yaml", "testsuite": "ui5 serve --open test-resources/ui5/ecosystem/demo/tslib/qunit/testsuite.qunit.html", @@ -24,6 +25,10 @@ "url": "https://github.com/ui5-community/ui5-ecosystem-showcase.git", "directory": "showcases/ui5-tslib" }, + "dependencies": { + "@ui5/webcomponents-base": "2.6.2", + "@ui5/webcomponents": "2.6.2" + }, "devDependencies": { "@types/openui5": "1.129.0", "@ui5/cli": "^4.0.9", diff --git a/showcases/ui5-tslib/src/Button.gen.d.ts b/showcases/ui5-tslib/src/Button.gen.d.ts new file mode 100644 index 000000000..f184ecd00 --- /dev/null +++ b/showcases/ui5-tslib/src/Button.gen.d.ts @@ -0,0 +1,31 @@ +import { PropertyBindingInfo } from "sap/ui/base/ManagedObject"; +import { $WebComponentSettings } from "sap/ui/core/webc/WebComponent"; + +declare module "./Button" { + + /** + * Interface defining the settings object used in constructor calls + */ + interface $ButtonSettings extends $WebComponentSettings { + + /** + * The text to display. + */ + specialText?: string | PropertyBindingInfo; + } + + export default interface Button { + + // property: specialText + + /** + * The text to display. + */ + getSpecialText(): string; + + /** + * The text to display. + */ + setSpecialText(specialText: string): this; + } +} diff --git a/showcases/ui5-tslib/src/Button.ts b/showcases/ui5-tslib/src/Button.ts new file mode 100644 index 000000000..837e200ab --- /dev/null +++ b/showcases/ui5-tslib/src/Button.ts @@ -0,0 +1,46 @@ +/*! + * ${copyright} + */ + +// Provides control ui5.ecosystem.demo.tslib.Button. +// TODO: for interface generation, the control must extend a WebComponent base class and +// the WebCButton base class used here is really a UI5 Web Component and no control! +import WebCButton from "@ui5/webcomponents/dist/Button"; +//import WebComponent from "sap/ui/core/webc/WebComponent"; + +/** + * Constructor for a new ui5.ecosystem.demo.tslib.Button control. + * + * Some class description goes here. + * @extends @ui5.webcomponents.dist.Button + * + * @author OpenUI5 Team + * @version ${version} + * + * @constructor + * @public + * @name ui5.ecosystem.demo.tslib.Button + */ +export default class Button extends WebCButton { + // The following three lines were generated and should remain as-is to make TypeScript aware of the constructor signatures + constructor(id?: string | $ButtonSettings); + constructor(id?: string, settings?: $ButtonSettings); + constructor(id?: string, settings?: $ButtonSettings) { + super(id, settings); + } + + static readonly metadata = { + library: "ui5.ecosystem.demo.tslib", + tag: WebCButton.getMetadata().getTag(), + properties: { + /** + * The text to display. + */ + specialText: { + type: "string", + group: "Data", + defaultValue: null, + }, + }, + }; +} diff --git a/showcases/ui5-tslib/src/util/capitalize.ts b/showcases/ui5-tslib/src/util/capitalize.ts index cdb90728d..aa99546c1 100644 --- a/showcases/ui5-tslib/src/util/capitalize.ts +++ b/showcases/ui5-tslib/src/util/capitalize.ts @@ -1,3 +1,7 @@ +/*! + * ${copyright} + */ + import capitalize from "sap/base/strings/capitalize"; export default function (stringToHash: string): string { diff --git a/showcases/ui5-tslib/test/Example.ts b/showcases/ui5-tslib/test/Example.ts index 3acfc0961..c29bbb91e 100644 --- a/showcases/ui5-tslib/test/Example.ts +++ b/showcases/ui5-tslib/test/Example.ts @@ -1,5 +1,6 @@ import { ExampleColor } from "ui5/ecosystem/demo/tslib/library"; import Example from "ui5/ecosystem/demo/tslib/Example"; +import Button from "ui5/ecosystem/demo/tslib/Button"; // create a new instance of the Example control and // place it into the DOM element with the id "content" @@ -7,3 +8,13 @@ new Example({ text: "Example", color: ExampleColor.Highlight, }).placeAt("content"); + +/* TODO: + * - Transitive dependencies are not considered (only if added to package.json and tsconfig.json) + * - 2.7.0 introduces problems with lazy loading of the JSX runtime + */ + +// eslint-disable-next-line @typescript-eslint/no-unsafe-call +new Button({ + text: "Hello World", +}).placeAt("content"); diff --git a/showcases/ui5-tslib/tsconfig.json b/showcases/ui5-tslib/tsconfig.json index da3f76a7b..ab810a133 100644 --- a/showcases/ui5-tslib/tsconfig.json +++ b/showcases/ui5-tslib/tsconfig.json @@ -10,7 +10,8 @@ "rootDir": "./", "paths": { "ui5/ecosystem/demo/tslib/*": ["./src/*"] - } + }, + "types": ["@types/openui5", "@types/qunit", "@ui5/webcomponents", "@ui5/webcomponents-base"] }, "include": ["./src/**/*", "./test/**/*"] } diff --git a/showcases/ui5-tslib/ui5.yaml b/showcases/ui5-tslib/ui5.yaml index 0606ae7f5..279ad0d1a 100644 --- a/showcases/ui5-tslib/ui5.yaml +++ b/showcases/ui5-tslib/ui5.yaml @@ -7,9 +7,12 @@ framework: version: "1.129.0" libraries: - name: sap.ui.core - - name: themelib_sap_fiori_3 - - name: themelib_sap_horizon + #- name: themelib_sap_fiori_3 + #- name: themelib_sap_horizon builder: + jsdoc: + excludes: + - "ui5/ecosystem/demo/tslib/thirdparty/**" customTasks: - name: ui5-tooling-transpile-task afterTask: replaceVersion @@ -20,6 +23,10 @@ builder: afterTask: ui5-tooling-transpile-task configuration: debug: true + - name: ui5-tooling-modules-task-jsdoc + afterTask: generateJsdoc + configuration: + debug: true server: customMiddleware: - name: ui5-tooling-transpile-middleware