From 7657a44beb186acc52649e22cd7cb5b4df1f62b8 Mon Sep 17 00:00:00 2001 From: Nayden Naydenov Date: Wed, 27 Aug 2025 12:38:26 +0300 Subject: [PATCH 01/10] chore: wip custom command executor --- packages/ai/custom-runner.cjs | 29 ++ packages/ai/package-scripts.cjs | 19 - packages/ai/package.json | 24 +- packages/base/custom-runner.cjs | 303 +++++++++++++ packages/base/package-scripts.cjs | 85 ---- packages/base/package.json | 20 +- packages/compat/custom-runner.cjs | 29 ++ packages/compat/package-scripts.cjs | 19 - packages/compat/package.json | 24 +- ...{package-scripts.cjs => custom-runner.cjs} | 18 +- packages/fiori/package.json | 24 +- .../icons-business-suite/custom-runner.cjs | 29 ++ .../icons-business-suite/package-scripts.cjs | 16 - packages/icons-business-suite/package.json | 6 +- packages/icons-tnt/custom-runner.cjs | 29 ++ packages/icons-tnt/package-scripts.cjs | 16 - packages/icons-tnt/package.json | 6 +- packages/icons/custom-runner.cjs | 22 + packages/icons/package-scripts.cjs | 12 - packages/icons/package.json | 6 +- packages/localization/custom-runner.cjs | 110 +++++ packages/localization/package-scripts.cjs | 28 -- packages/localization/package.json | 10 +- packages/main/custom-runner.cjs | 28 ++ packages/main/package-scripts.cjs | 18 - packages/main/package.json | 34 +- packages/theming/custom-runner.cjs | 88 ++++ packages/theming/package-scripts.cjs | 24 -- packages/theming/package.json | 8 +- .../custom-runner-commands.js | 403 ++++++++++++++++++ packages/tools/components-package/nps.js | 2 +- .../custom-runner-commands.js | 172 ++++++++ packages/tools/task-runner/build-runner.js | 118 +++++ packages/tools/task-runner/runner.js | 42 ++ 34 files changed, 1498 insertions(+), 323 deletions(-) create mode 100644 packages/ai/custom-runner.cjs delete mode 100644 packages/ai/package-scripts.cjs create mode 100644 packages/base/custom-runner.cjs delete mode 100644 packages/base/package-scripts.cjs create mode 100644 packages/compat/custom-runner.cjs delete mode 100644 packages/compat/package-scripts.cjs rename packages/fiori/{package-scripts.cjs => custom-runner.cjs} (83%) create mode 100644 packages/icons-business-suite/custom-runner.cjs delete mode 100644 packages/icons-business-suite/package-scripts.cjs create mode 100644 packages/icons-tnt/custom-runner.cjs delete mode 100644 packages/icons-tnt/package-scripts.cjs create mode 100644 packages/icons/custom-runner.cjs delete mode 100644 packages/icons/package-scripts.cjs create mode 100644 packages/localization/custom-runner.cjs delete mode 100644 packages/localization/package-scripts.cjs create mode 100644 packages/main/custom-runner.cjs delete mode 100644 packages/main/package-scripts.cjs create mode 100644 packages/theming/custom-runner.cjs delete mode 100644 packages/theming/package-scripts.cjs create mode 100644 packages/tools/components-package/custom-runner-commands.js create mode 100644 packages/tools/icons-collection/custom-runner-commands.js create mode 100644 packages/tools/task-runner/build-runner.js create mode 100644 packages/tools/task-runner/runner.js diff --git a/packages/ai/custom-runner.cjs b/packages/ai/custom-runner.cjs new file mode 100644 index 000000000000..0be90b173cbd --- /dev/null +++ b/packages/ai/custom-runner.cjs @@ -0,0 +1,29 @@ +const getScripts = require("@ui5/webcomponents-tools/components-package/custom-runner-commands.js"); + +const options = { + port: 8082, + portStep: 2, + aiPackage: true, + noWatchTS: true, + dev: true, + internal: { + cypress_code_coverage: false, + cypress_acc_tests: false, + }, +}; + +const scripts = getScripts(options); + +// Export for CLI usage +if (require.main === module) { + const taskName = process.argv[2]; + if (!taskName) { + console.log('Available tasks:', Array.from(scripts.tasks.keys()).join(', ')); + process.exit(1); + } + + scripts.run(taskName).catch(error => { + console.error('Task failed:', error.message); + process.exit(1); + }); +} \ No newline at end of file diff --git a/packages/ai/package-scripts.cjs b/packages/ai/package-scripts.cjs deleted file mode 100644 index 599362ba77b0..000000000000 --- a/packages/ai/package-scripts.cjs +++ /dev/null @@ -1,19 +0,0 @@ -const getScripts = require("@ui5/webcomponents-tools/components-package/nps.js"); - -const options = { - port: 8082, - portStep: 2, - aiPackage: true, - noWatchTS: true, - dev: true, - internal: { - cypress_code_coverage: false, - cypress_acc_tests: false, - }, -}; - -const scripts = getScripts(options); - -module.exports = { - scripts, -}; diff --git a/packages/ai/package.json b/packages/ai/package.json index 310f08a43dab..8060fdca3fde 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -16,19 +16,19 @@ "ui5" ], "scripts": { - "clean": "wc-dev clean", - "lint": "wc-dev lint", - "lint:scope": "nps scope.lint", - "start": "wc-dev start", - "build": "wc-dev build", - "watch": "wc-dev watch", - "generate": "nps generate", - "generateAPI": "nps generateAPI", - "bundle": "nps build.bundle", - "test": "nps test-cy-ci", - "test:cypress": "nps test-cy-ci", + "clean": "node ./custom-runner.cjs clean", + "lint": "node ./custom-runner.cjs lint", + "lint:scope": "node ./custom-runner.cjs scope:lint", + "start": "node ./custom-runner.cjs start", + "build": "node ./custom-runner.cjs build", + "watch": "node ./custom-runner.cjs watch", + "generate": "node ./custom-runner.cjs generate", + "generateAPI": "node ./custom-runner.cjs generateAPI", + "bundle": "node ./custom-runner.cjs build:bundle", + "test": "node ./custom-runner.cjs test-cy-ci", + "test:cypress": "node ./custom-runner.cjs test-cy-ci", "test:cypress:single": "npx cypress run --component --browser chrome --spec", - "test:cypress:open": "nps test-cy-open", + "test:cypress:open": "node ./custom-runner.cjs test-cy-open", "test:ssr": "node -e \"import('./test/ssr/component-imports.js')\"", "create-ui5-element": "wc-create-ui5-element", "prepublishOnly": "tsc -b" diff --git a/packages/base/custom-runner.cjs b/packages/base/custom-runner.cjs new file mode 100644 index 000000000000..b00b06e55656 --- /dev/null +++ b/packages/base/custom-runner.cjs @@ -0,0 +1,303 @@ +const resolve = require("resolve"); +const path = require("path"); +const BuildRunner = require("@ui5/webcomponents-tools/task-runner/build-runner"); + +const runner = new BuildRunner(); + +const assetParametersScript = resolve.sync("@ui5/webcomponents-base/lib/generate-asset-parameters/index.js"); +const stylesScript = resolve.sync("@ui5/webcomponents-base/lib/generate-styles/index.js"); +const fontFaceScript = resolve.sync("@ui5/webcomponents-base/lib/css-processors/css-processor-font-face.mjs"); +const versionScript = resolve.sync("@ui5/webcomponents-base/lib/generate-version-info/index.js"); +const copyUsedModules = resolve.sync("@ui5/webcomponents-tools/lib/copy-list/index.js"); +const amdToES6 = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/index.js"); +const noRequire = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/no-remaining-require.js"); + +const LIB = path.join(__dirname, `../tools/lib/`); + +const viteConfig = `-c "${require.resolve("@ui5/webcomponents-tools/components-package/vite.config.js")}"`; + +runner.addTask("clean", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "rimraf src/generated", + "rimraf dist", + "rimraf .port", + ], +}); + +runner.addTask("lint", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "eslint .", + ], +}); + +runner.addTask("generate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "clean", + "build:i18n", + "integrate", + "copy", + "generateAssetParameters", + "generateVersionInfo", + "generateStyles", + "generateFontFace", + "generateTemplates", + "build:jsonImports", + ], + crossEnv: { + UI5_TS: true, + }, +}); + +runner.addTask("prepare", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "clean", + "build:i18n", + "integrate", + "copy", + "generateAssetParameters", + "generateVersionInfo", + "generateStyles", + "generateFontFace", + "generateTemplates", + "typescript", + "integrate:no-remaining-require", + "build:jsonImports", + ], + crossEnv: { + UI5_TS: true, + }, +}); + +runner.addTask("typescript", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "tsc -b", + ], +}); + +runner.addTask("integrate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "integrate:copy-used-modules", + "integrate:amd-to-es6", + "integrate:no-remaining-require", + "integrate:third-party", + ], + parallel: false, // ??? +}); + +runner.addTask("integrate:copy-used-modules", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${copyUsedModules}" ./used-modules.txt dist/`, + ], +}); + +runner.addTask("integrate:amd-to-es6", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${amdToES6}" dist/`, + ], +}); + +runner.addTask("integrate:no-remaining-require", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, + { + dependencies: [ + `node "${noRequire}" dist/`, + ], + }); + +runner.addTask("integrate:third-party", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "integrate:third-party:copy", + "integrate:third-party:fix", + ], + parallel: false, // ??? +}); + +runner.addTask("integrate:third-party:copy", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "mkdir -p dist/sap/ui/thirdparty/", + "copy-and-watch ../../node_modules/@openui5/sap.ui.core/src/sap/ui/thirdparty/caja-html-sanitizer.js dist/sap/ui/thirdparty/", + ], +}); + +runner.addTask("integrate:third-party:fix", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "replace-in-file 240 xA0 dist/sap/ui/thirdparty/caja-html-sanitizer.js", + ], +}); + +runner.addTask("build", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "prepare", + ], +}); + +runner.addTask("build:bundle", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `vite build ${viteConfig}`, + ], +}); + +runner.addTask("build:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "build:i18n:defaultsjs", + "build:i18n:json", + ], + parallel: true, +}); + +runner.addTask("build:i18n:defaultsjs", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/i18n/defaults.js" src/i18n src/generated/i18n`, + ], +}); + +runner.addTask("build:i18n:json", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/i18n/toJSON.js" src/i18n dist/generated/assets/i18n`, + ], +}); + +runner.addTask("build:jsonImports", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "build:jsonImports:i18n", + ], +}); + +runner.addTask("build:jsonImports:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `mkdir -p src/generated/json-imports`, + `node "${LIB}/generate-json-imports/i18n.js" dist/generated/assets/i18n src/generated/json-imports`, + ], +}); + +runner.addTask("copy", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "copy:src", + ], +}); + +runner.addTask("copy:src", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/copy-and-watch/index.js" --silent "src/**/*.{js,json}" dist/`, + ], +}); + +runner.addTask("generateAssetParameters", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${assetParametersScript}"`, + ], +}); + +runner.addTask("generateVersionInfo", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${versionScript}"`, + ], +}); + +runner.addTask("generateStyles", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${stylesScript}"`, + ], +}); + +runner.addTask("generateFontFace", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${fontFaceScript}"`, + ], +}); + +runner.addTask("generateTemplates", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + ``, + ], +}); + +runner.addTask("generateTestTemplates", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `mkdir -p test/test-elements/generated/templates`, + `node "${LIB}/hbs2ui5/index.js" -d test/test-elements -o test/test-elements/generated/templates`, + ], + crossEnv: { + UI5_BASE: true, + }, +}); + +runner.addTask("generateProd", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "generateProd:remove-dev-mode", + "generateProd:copy-prod", + ], + parallel: false, // ??? +}); + +runner.addTask("generateProd:remove-dev-mode", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/remove-dev-mode/remove-dev-mode.mjs"`, + ], +}); + +runner.addTask("generateProd:copy-prod", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `copy-and-watch "dist/sap/**/*" dist/prod/sap/`, + `copy-and-watch "dist/thirdparty/preact/**/*.js" dist/prod/thirdparty/preact/`, + `copy-and-watch "dist/generated/assets/**/*.json" dist/prod/generated/assets/`, + ], +}); + +runner.addTask("generateAPI", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "generateAPI:generateCEM", + "generateAPI:validateCEM", + ], +}); + +runner.addTask("generateAPI:generateCEM", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `cem analyze --config "${LIB}/cem/custom-elements-manifest.config.mjs"`, + ], + crossEnv: { + UI5_CEM_MODE: "dev", + }, +}); + +runner.addTask("generateAPI:validateCEM", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/cem/validate.js"`, + ], + crossEnv: { + UI5_CEM_MODE: "dev", + }, +}); + +runner.addTask("watch", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "watch:src", + "watch:styles", + ], + parallel: true, +}); + +runner.addTask("watch:src", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/copy-and-watch/index.js" --silent --watch "src/**/*.{js,json}" dist/`, + ], +}); + +runner.addTask("watch:styles", { + dependencies: [ + `chokidar "src/css/*.css" -c "nps generateStyles"` + ], +}); + +// Export for CLI usage +if (require.main === module) { + const taskName = process.argv[2]; + if (!taskName) { + console.log("Available tasks:", Array.from(runner.tasks.keys()).join(", ")); + process.exit(1); + } + + runner.run(taskName).catch(error => { + console.error("Task failed:", error.message); + process.exit(1); + }); +} \ No newline at end of file diff --git a/packages/base/package-scripts.cjs b/packages/base/package-scripts.cjs deleted file mode 100644 index a2976f7ca564..000000000000 --- a/packages/base/package-scripts.cjs +++ /dev/null @@ -1,85 +0,0 @@ -const resolve = require("resolve"); -const path = require("path"); - -const assetParametersScript = resolve.sync("@ui5/webcomponents-base/lib/generate-asset-parameters/index.js"); -const stylesScript = resolve.sync("@ui5/webcomponents-base/lib/generate-styles/index.js"); -const fontFaceScript = resolve.sync("@ui5/webcomponents-base/lib/css-processors/css-processor-font-face.mjs"); -const versionScript = resolve.sync("@ui5/webcomponents-base/lib/generate-version-info/index.js"); -const copyUsedModules = resolve.sync("@ui5/webcomponents-tools/lib/copy-list/index.js"); -const amdToES6 = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/index.js"); -const noRequire = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/no-remaining-require.js"); - -const LIB = path.join(__dirname, `../tools/lib/`); - -const viteConfig = `-c "${require.resolve("@ui5/webcomponents-tools/components-package/vite.config.js")}"`; - -const scripts = { - clean: "rimraf src/generated && rimraf dist && rimraf .port", - lint: `eslint .`, - generate: "cross-env UI5_TS=true nps clean build.i18n integrate copy generateAssetParameters generateVersionInfo generateStyles generateFontFace generateTemplates build.jsonImports", - prepare: "cross-env UI5_TS=true nps clean build.i18n integrate copy generateAssetParameters generateVersionInfo generateStyles generateFontFace generateTemplates typescript integrate.no-remaining-require build.jsonImports", - typescript: "tsc -b", - integrate: { - default: "nps integrate.copy-used-modules integrate.amd-to-es6 integrate.third-party", - "copy-used-modules": `node "${copyUsedModules}" ./used-modules.txt dist/`, - "amd-to-es6": `node "${amdToES6}" dist/`, - "no-remaining-require": `node "${noRequire}" dist/`, - "third-party": { - default: "nps integrate.third-party.copy integrate.third-party.fix", - copy: "mkdirp dist/sap/ui/thirdparty/ && copy-and-watch ../../node_modules/@openui5/sap.ui.core/src/sap/ui/thirdparty/caja-html-sanitizer.js dist/sap/ui/thirdparty/", - fix: "replace-in-file 240 xA0 dist/sap/ui/thirdparty/caja-html-sanitizer.js" - }, - }, - build: { - default: `nps prepare`, - bundle: `vite build ${viteConfig}`, - i18n: { - default: "nps build.i18n.defaultsjs build.i18n.json", - defaultsjs: `node "${LIB}/i18n/defaults.js" src/i18n src/generated/i18n`, - json: `node "${LIB}/i18n/toJSON.js" src/i18n dist/generated/assets/i18n`, - }, - jsonImports: { - default: "mkdirp src/generated/json-imports && nps build.jsonImports.i18n", - i18n: `node "${LIB}/generate-json-imports/i18n.js" dist/generated/assets/i18n src/generated/json-imports`, - }, - }, - copy: { - default: "nps copy.src", - src: `copy-and-watch "src/**/*.{js,css,d.ts}" dist/`, - }, - generateAssetParameters: `node "${assetParametersScript}"`, - generateVersionInfo: `node "${versionScript}"`, - generateStyles: `node "${stylesScript}"`, - generateFontFace: `node "${fontFaceScript}"`, - generateTemplates: ``, - generateTestTemplates: `mkdirp test/test-elements/generated/templates && cross-env UI5_BASE=true UI5_TS=true node "${LIB}/hbs2ui5/index.js" -d test/test-elements -o test/test-elements/generated/templates`, - generateProd: { - "default": "nps generateProd.remove-dev-mode generateProd.copy-prod", - "remove-dev-mode": `node "${LIB}/remove-dev-mode/remove-dev-mode.mjs"`, - "copy-prod": `copy-and-watch "dist/sap/**/*" dist/prod/sap/ && copy-and-watch "dist/thirdparty/preact/**/*.js" dist/prod/thirdparty/preact/ && copy-and-watch "dist/generated/assets/**/*.json" dist/prod/generated/assets/`, - }, - generateAPI: { - default: "nps generateAPI.generateCEM generateAPI.validateCEM", - generateCEM: `cross-env UI5_CEM_MODE='dev' cem analyze --config "${LIB}/cem/custom-elements-manifest.config.mjs"`, - validateCEM: `cross-env UI5_CEM_MODE='dev' node "${LIB}/cem/validate.js"`, - }, - watch: { - default: 'concurrently "nps watch.src" "nps watch.styles"', - withBundle: 'concurrently "nps watch.src" "nps watch.bundle" "nps watch.styles"', - src: 'nps "copy.src --watch --skip-initial-copy"', - bundle: `node ${LIB}/dev-server/dev-server.mjs ${viteConfig}`, - styles: 'chokidar "src/css/*.css" -c "nps generateStyles"' - }, - test: { - default: 'concurrently "nps test.ssr" "nps test.ssr2" "nps test.test-cy-ci"', - ssr: `mocha test/ssr`, - ssr2: "node -e \"import('./dist/Device.js')\"", - "test-cy-ci": `nps generateTestTemplates && cross-env UI5_BASE=true yarn cypress run --component --browser chrome`, - "test-cy-open": `nps generateTestTemplates && cross-env UI5_BASE=true yarn cypress open --component --browser chrome`, - }, -}; - - -module.exports = { - scripts, -}; diff --git a/packages/base/package.json b/packages/base/package.json index a4914858e51d..d45c50468443 100644 --- a/packages/base/package.json +++ b/packages/base/package.json @@ -43,16 +43,16 @@ }, "types": "./dist", "scripts": { - "clean": "nps clean", - "lint": "nps lint", - "start": "nps start", - "build": "nps build", - "generate": "nps generate", - "generateAPI": "nps generateAPI", - "generateProd": "nps generateProd", - "bundle": "nps build.bundle", - "test": "nps test", - "test:cypress:open": "nps test.test-cy-open", + "clean": "node ./custom-runner.cjs clean", + "lint": "node ./custom-runner.cjs lint", + "start": "node ./custom-runner.cjs start", + "build": "node ./custom-runner.cjs build", + "generate": "node ./custom-runner.cjs generate", + "generateAPI": "node ./custom-runner.cjs generateAPI", + "generateProd": "node ./custom-runner.cjs generateProd", + "bundle": "node ./custom-runner.cjs build.bundle", + "test": "node ./custom-runner.cjs test", + "test:cypress:open": "node ./custom-runner.cjs test.test-cy-open", "prepublishOnly": "tsc -b" }, "dependencies": { diff --git a/packages/compat/custom-runner.cjs b/packages/compat/custom-runner.cjs new file mode 100644 index 000000000000..1e2848440e0e --- /dev/null +++ b/packages/compat/custom-runner.cjs @@ -0,0 +1,29 @@ +const getScripts = require("@ui5/webcomponents-tools/components-package/custom-runner-commands.js"); + +const options = { + port: 8082, + portStep: 2, + compatPackage: true, + noWatchTS: true, + dev: true, + internal: { + cypress_code_coverage: false, + cypress_acc_tests: false, + }, +}; + +const scripts = getScripts(options); + +// Export for CLI usage +if (require.main === module) { + const taskName = process.argv[2]; + if (!taskName) { + console.log('Available tasks:', Array.from(scripts.tasks.keys()).join(', ')); + process.exit(1); + } + + scripts.run(taskName).catch(error => { + console.error('Task failed:', error.message); + process.exit(1); + }); +} \ No newline at end of file diff --git a/packages/compat/package-scripts.cjs b/packages/compat/package-scripts.cjs deleted file mode 100644 index c1b3af2ca33f..000000000000 --- a/packages/compat/package-scripts.cjs +++ /dev/null @@ -1,19 +0,0 @@ -const getScripts = require("@ui5/webcomponents-tools/components-package/nps.js"); - -const options = { - port: 8082, - portStep: 2, - compatPackage: true, - noWatchTS: true, - dev: true, - internal: { - cypress_code_coverage: false, - cypress_acc_tests: false, - }, -}; - -const scripts = getScripts(options); - -module.exports = { - scripts, -}; diff --git a/packages/compat/package.json b/packages/compat/package.json index da109575ace0..7622498ecfc8 100644 --- a/packages/compat/package.json +++ b/packages/compat/package.json @@ -16,19 +16,19 @@ "ui5" ], "scripts": { - "clean": "wc-dev clean", - "lint": "wc-dev lint", - "lint:scope": "nps scope.lint", - "start": "wc-dev start", - "build": "wc-dev build", - "watch": "wc-dev watch", - "generate": "nps generate", - "generateAPI": "nps generateAPI", - "bundle": "nps build.bundle", - "test": "wc-dev test", - "test:cypress": "nps test-cy-ci", + "clean": "node ./custom-runner.cjs clean", + "lint": "node ./custom-runner.cjs lint", + "lint:scope": "node ./custom-runner.cjs scope:lint", + "start": "node ./custom-runner.cjs start", + "build": "node ./custom-runner.cjs build", + "watch": "node ./custom-runner.cjs watch", + "generate": "node ./custom-runner.cjs generate", + "generateAPI": "node ./custom-runner.cjs generateAPI", + "bundle": "node ./custom-runner.cjs build:bundle", + "test": "node ./custom-runner.cjs test", + "test:cypress": "node ./custom-runner.cjs test-cy-ci", "test:cypress:single": "npx cypress run --component --browser chrome --spec", - "test:cypress:open": "nps test-cy-open", + "test:cypress:open": "node ./custom-runner.cjs test-cy-open", "test:ssr": "node -e \"import('./test/ssr/component-imports.js')\"", "create-ui5-element": "wc-create-ui5-element", "prepublishOnly": "tsc -b" diff --git a/packages/fiori/package-scripts.cjs b/packages/fiori/custom-runner.cjs similarity index 83% rename from packages/fiori/package-scripts.cjs rename to packages/fiori/custom-runner.cjs index 9255a2af5ace..a7be2819921f 100644 --- a/packages/fiori/package-scripts.cjs +++ b/packages/fiori/custom-runner.cjs @@ -1,4 +1,4 @@ -const getScripts = require("@ui5/webcomponents-tools/components-package/nps.js"); +const getScripts = require("@ui5/webcomponents-tools/components-package/custom-runner-commands.js"); const filterOut = [ "sapIllus-Dot", @@ -80,6 +80,16 @@ const options = { const scripts = getScripts(options); -module.exports = { - scripts -}; +// Export for CLI usage +if (require.main === module) { + const taskName = process.argv[2]; + if (!taskName) { + console.log('Available tasks:', Array.from(scripts.tasks.keys()).join(', ')); + process.exit(1); + } + + scripts.run(taskName).catch(error => { + console.error('Task failed:', error.message); + process.exit(1); + }); +} \ No newline at end of file diff --git a/packages/fiori/package.json b/packages/fiori/package.json index 680ff711b2a6..c0369d7b1732 100644 --- a/packages/fiori/package.json +++ b/packages/fiori/package.json @@ -31,20 +31,20 @@ "./*": "./dist/*" }, "scripts": { - "clean": "wc-dev clean", - "lint": "wc-dev lint", - "lint:scope": "nps scope.lint", - "start": "wc-dev start", - "watch": "wc-dev watch", - "build": "wc-dev build", - "generate": "nps generate", - "generateAPI": "nps generateAPI", - "bundle": "nps build.bundle", - "test": "wc-dev test", + "clean": "node ./custom-runner.cjs clean", + "lint": "node ./custom-runner.cjs lint", + "lint:scope": "node ./custom-runner.cjs scope:lint", + "start": "node ./custom-runner.cjs start", + "watch": "node ./custom-runner.cjs watch", + "build": "node ./custom-runner.cjs build", + "generate": "node ./custom-runner.cjs generate", + "generateAPI": "node ./custom-runner.cjs generateAPI", + "bundle": "node ./custom-runner.cjs build:bundle", + "test": "node ./custom-runner.cjs test", "test:ssr": "node -e \"import('./test/ssr/component-imports.js')\"", - "test:cypress": "nps test-cy-ci", + "test:cypress": "node ./custom-runner.cjs test-cy-ci", "test:cypress:single": "npx cypress run --component --browser chrome --spec", - "test:cypress:open": "nps test-cy-open", + "test:cypress:open": "node ./custom-runner.cjs test-cy-open", "create-ui5-element": "wc-create-ui5-element", "prepublishOnly": "tsc -b" }, diff --git a/packages/icons-business-suite/custom-runner.cjs b/packages/icons-business-suite/custom-runner.cjs new file mode 100644 index 000000000000..7bb7ae162392 --- /dev/null +++ b/packages/icons-business-suite/custom-runner.cjs @@ -0,0 +1,29 @@ +const getScripts = require("@ui5/webcomponents-tools/icons-collection/custom-runner-commands.js"); + +const options = { + collectionName: "SAP-icons-business-suite", + versions: ["v1", "v2"], +}; + +const scripts = getScripts(options); + +scripts.emptyTask("build:i18n", scripts.constructor.BUILD_RUNNER_CONSTANTS.PRINT, { + skip: true, +}); +scripts.emptyTask("build:jsonImports", scripts.constructor.BUILD_RUNNER_CONSTANTS.PRINT, { + skip: true, +}); + +// Export for CLI usage +if (require.main === module) { + const taskName = process.argv[2]; + if (!taskName) { + console.log('Available tasks:', Array.from(scripts.tasks.keys()).join(', ')); + process.exit(1); + } + + scripts.run(taskName).catch(error => { + console.error('Task failed:', error.message); + process.exit(1); + }); +} \ No newline at end of file diff --git a/packages/icons-business-suite/package-scripts.cjs b/packages/icons-business-suite/package-scripts.cjs deleted file mode 100644 index af644c7a7aff..000000000000 --- a/packages/icons-business-suite/package-scripts.cjs +++ /dev/null @@ -1,16 +0,0 @@ -const getScripts = require("@ui5/webcomponents-tools/icons-collection/nps.js"); - -const options = { - collectionName: "SAP-icons-business-suite", - versions: ["v1", "v2"], -}; - -const scripts = getScripts(options); - -// no i18n in this package -scripts.build.i18n = ""; -scripts.build.jsonImports = ""; - -module.exports = { - scripts -}; diff --git a/packages/icons-business-suite/package.json b/packages/icons-business-suite/package.json index 480958aedd10..993638f78fb6 100644 --- a/packages/icons-business-suite/package.json +++ b/packages/icons-business-suite/package.json @@ -17,9 +17,9 @@ "./*": "./dist/*" }, "scripts": { - "clean": "wc-dev clean", - "build": "wc-dev build", - "generate": "nps generate", + "clean": "node ./custom-runner.cjs clean", + "build": "node ./custom-runner.cjs build", + "generate": "node ./custom-runner.cjs generate", "prepublishOnly": "tsc -b" }, "repository": { diff --git a/packages/icons-tnt/custom-runner.cjs b/packages/icons-tnt/custom-runner.cjs new file mode 100644 index 000000000000..4a9772fa134e --- /dev/null +++ b/packages/icons-tnt/custom-runner.cjs @@ -0,0 +1,29 @@ +const getScripts = require("@ui5/webcomponents-tools/icons-collection/custom-runner-commands.js"); + +const options = { + collectionName: "SAP-icons-TNT", + versions: ["v2", "v3"], +}; + +const scripts = getScripts(options); + +scripts.emptyTask("build:i18n", scripts.constructor.BUILD_RUNNER_CONSTANTS.PRINT, { + skip: true, +}); +scripts.emptyTask("build:jsonImports", scripts.constructor.BUILD_RUNNER_CONSTANTS.PRINT, { + skip: true, +}); + +// Export for CLI usage +if (require.main === module) { + const taskName = process.argv[2]; + if (!taskName) { + console.log('Available tasks:', Array.from(scripts.tasks.keys()).join(', ')); + process.exit(1); + } + + scripts.run(taskName).catch(error => { + console.error('Task failed:', error.message); + process.exit(1); + }); +} \ No newline at end of file diff --git a/packages/icons-tnt/package-scripts.cjs b/packages/icons-tnt/package-scripts.cjs deleted file mode 100644 index e9522308f476..000000000000 --- a/packages/icons-tnt/package-scripts.cjs +++ /dev/null @@ -1,16 +0,0 @@ -const getScripts = require("@ui5/webcomponents-tools/icons-collection/nps.js"); - -const options = { - collectionName: "SAP-icons-TNT", - versions: ["v2", "v3"], -}; - -const scripts = getScripts(options); - -// no i18n in this package -scripts.build.i18n = ""; -scripts.build.jsonImports = ""; - -module.exports = { - scripts -}; diff --git a/packages/icons-tnt/package.json b/packages/icons-tnt/package.json index 998c205c0d36..99b1aad3cec0 100644 --- a/packages/icons-tnt/package.json +++ b/packages/icons-tnt/package.json @@ -17,9 +17,9 @@ "./*": "./dist/*" }, "scripts": { - "clean": "wc-dev clean", - "build": "wc-dev build", - "generate": "nps generate", + "clean": "node ./custom-runner.cjs clean", + "build": "node ./custom-runner.cjs build", + "generate": "node ./custom-runner.cjs generate", "prepublishOnly": "tsc -b" }, "repository": { diff --git a/packages/icons/custom-runner.cjs b/packages/icons/custom-runner.cjs new file mode 100644 index 000000000000..856dab28ba88 --- /dev/null +++ b/packages/icons/custom-runner.cjs @@ -0,0 +1,22 @@ +const getScripts = require("@ui5/webcomponents-tools/icons-collection/custom-runner-commands.js"); + +const options = { + collectionName: "SAP-icons", + versions: ["v4", "v5"], +}; + +const scripts = getScripts(options); + +// Export for CLI usage +if (require.main === module) { + const taskName = process.argv[2]; + if (!taskName) { + console.log('Available tasks:', Array.from(scripts.tasks.keys()).join(', ')); + process.exit(1); + } + + scripts.run(taskName).catch(error => { + console.error('Task failed:', error.message); + process.exit(1); + }); +} \ No newline at end of file diff --git a/packages/icons/package-scripts.cjs b/packages/icons/package-scripts.cjs deleted file mode 100644 index a3e8a74087f0..000000000000 --- a/packages/icons/package-scripts.cjs +++ /dev/null @@ -1,12 +0,0 @@ -const getScripts = require("@ui5/webcomponents-tools/icons-collection/nps.js"); - -const options = { - collectionName: "SAP-icons", - versions: ["v4", "v5"], -}; - -const scripts = getScripts(options); - -module.exports = { - scripts -}; diff --git a/packages/icons/package.json b/packages/icons/package.json index 61d57b297b12..0f0a0e8fc32e 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -17,9 +17,9 @@ "./*": "./dist/*" }, "scripts": { - "clean": "wc-dev clean", - "generate": "nps generate", - "build": "wc-dev build", + "clean": "node ./custom-runner.cjs clean", + "generate": "node ./custom-runner.cjs generate", + "build": "node ./custom-runner.cjs build", "prepublishOnly": "tsc -b" }, "repository": { diff --git a/packages/localization/custom-runner.cjs b/packages/localization/custom-runner.cjs new file mode 100644 index 000000000000..833fb43f1ea5 --- /dev/null +++ b/packages/localization/custom-runner.cjs @@ -0,0 +1,110 @@ +const resolve = require("resolve"); +const BuildRunner = require("@ui5/webcomponents-tools/task-runner/build-runner"); + +const runner = new BuildRunner(); + +const copyUsedModules = resolve.sync("@ui5/webcomponents-tools/lib/copy-list/index.js"); +const amdToES6 = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/index.js"); +const noRequire = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/no-remaining-require.js"); + +runner.addTask("clean", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "rimraf src/generated", + "rimraf dist", + ], +}); + +runner.addTask("lint", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "eslint .", + ], +}); + +runner.addTask("generate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "clean", + "copy", + "build:amd-to-es6", + "build:jsonImports", + ], +}); + +runner.addTask("build", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "clean", + "copy", + "build:amd-to-es6", + "build:jsonImports", + "build:typescript", + "build:no-remaining-require", + ], +}); + +runner.addTask("build:amd-to-es6", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${amdToES6}" dist/`, + ], +}); + +runner.addTask("build:no-remaining-require", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${noRequire}" dist/`, + ], +}); + +runner.addTask("build:typescript", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: "tsc --build", +}); + +runner.addTask("build:jsonImports", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "node ./lib/generate-json-imports/cldr.js", + ], +}); + +runner.addTask("typescript", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "tsc --build", + ], +}); + +runner.addTask("copy", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "copy:used-modules", + "copy:cldr", + "copy:overlay", + ], + parallel: true, +}); + +runner.addTask("copy:used-modules", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${copyUsedModules}" ./used-modules.txt dist/`, + ], +}); + +runner.addTask("copy:cldr", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `copy-and-watch "../../node_modules/@openui5/sap.ui.core/src/sap/ui/core/cldr/*" dist/generated/assets/cldr/`, + ], +}); + +runner.addTask("copy:overlay", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `copy-and-watch "overlay/**/*.js" dist/`, + ], +}); + +// Export for CLI usage +if (require.main === module) { + const taskName = process.argv[2]; + if (!taskName) { + console.log("Available tasks:", Array.from(runner.tasks.keys()).join(", ")); + process.exit(1); + } + + runner.run(taskName).catch(error => { + console.error("Task failed:", error.message); + process.exit(1); + }); +} diff --git a/packages/localization/package-scripts.cjs b/packages/localization/package-scripts.cjs deleted file mode 100644 index f5e208ca97b4..000000000000 --- a/packages/localization/package-scripts.cjs +++ /dev/null @@ -1,28 +0,0 @@ -const resolve = require("resolve"); - -const copyUsedModules = resolve.sync("@ui5/webcomponents-tools/lib/copy-list/index.js"); -const amdToES6 = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/index.js"); -const noRequire = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/no-remaining-require.js"); - -const scripts = { - clean: "rimraf src/generated && rimraf dist", - lint: "eslint .", - generate: "nps clean copy.used-modules copy.cldr copy.overlay build.amd-to-es6 build.jsonImports", - build: { - "default": "nps clean copy.used-modules copy.cldr copy.overlay build.amd-to-es6 build.jsonImports build.typescript build.no-remaining-require", - "amd-to-es6": `node "${amdToES6}" dist/`, - "no-remaining-require": `node "${noRequire}" dist/`, - typescript: "tsc --build", - jsonImports: "node ./lib/generate-json-imports/cldr.js", - }, - typescript: "tsc --build", - copy: { - "used-modules": `node "${copyUsedModules}" ./used-modules.txt dist/`, - cldr: `copy-and-watch "../../node_modules/@openui5/sap.ui.core/src/sap/ui/core/cldr/*" dist/generated/assets/cldr/`, - overlay: `copy-and-watch "overlay/**/*.js" dist/`, - }, -}; - -module.exports = { - scripts, -}; diff --git a/packages/localization/package.json b/packages/localization/package.json index 6a82eab2ab66..5a333a346a2f 100644 --- a/packages/localization/package.json +++ b/packages/localization/package.json @@ -21,11 +21,11 @@ "./*": "./dist/*" }, "scripts": { - "clean": "nps clean", - "lint": "nps lint", - "start": "nps start", - "build": "nps build", - "generate": "nps generate", + "clean": "node ./custom-runner.cjs clean", + "lint": "node ./custom-runner.cjs lint", + "start": "node ./custom-runner.cjs start", + "build": "node ./custom-runner.cjs build", + "generate": "node ./custom-runner.cjs generate", "prepublishOnly": "tsc -b" }, "devDependencies": { diff --git a/packages/main/custom-runner.cjs b/packages/main/custom-runner.cjs new file mode 100644 index 000000000000..447ae03dd5d1 --- /dev/null +++ b/packages/main/custom-runner.cjs @@ -0,0 +1,28 @@ +const getScripts = require("@ui5/webcomponents-tools/components-package/custom-runner-commands.js"); + +const options = { + port: 8080, + portStep: 2, + noWatchTS: true, + dev: true, + internal: { + cypress_code_coverage: false, + cypress_acc_tests: false, + }, +}; + +const scripts = getScripts(options); + +// Export for CLI usage +if (require.main === module) { + const taskName = process.argv[2]; + if (!taskName) { + console.log('Available tasks:', Array.from(scripts.tasks.keys()).join(', ')); + process.exit(1); + } + + scripts.run(taskName).catch(error => { + console.error('Task failed:', error.message); + process.exit(1); + }); +} \ No newline at end of file diff --git a/packages/main/package-scripts.cjs b/packages/main/package-scripts.cjs deleted file mode 100644 index 455bdbea0698..000000000000 --- a/packages/main/package-scripts.cjs +++ /dev/null @@ -1,18 +0,0 @@ -const getScripts = require("@ui5/webcomponents-tools/components-package/nps.js"); - -const options = { - port: 8080, - portStep: 2, - noWatchTS: true, - dev: true, - internal: { - cypress_code_coverage: false, - cypress_acc_tests: false, - }, -}; - -const scripts = getScripts(options); - -module.exports = { - scripts -}; diff --git a/packages/main/package.json b/packages/main/package.json index 74a7668e7707..e8eeaeadd2ec 100644 --- a/packages/main/package.json +++ b/packages/main/package.json @@ -16,22 +16,22 @@ "ui5" ], "scripts": { - "clean": "wc-dev clean", - "lint": "wc-dev lint", - "lint:scope": "nps scope.lint", - "start": "wc-dev start", - "watch": "wc-dev watch", - "generate": "nps generate", - "generateAPI": "nps generateAPI", - "build": "wc-dev build", - "bundle": "nps build.bundle", - "test": "wc-dev test", - "test:suite-1": "wc-dev test-suite-1", - "test:suite-2": "wc-dev test-suite-2", - "test:cypress": "nps test-cy-ci", - "test:cypress:suite-1": "nps test-cy-ci-suite-1", - "test:cypress:suite-2": "nps test-cy-ci-suite-2", - "test:cypress:open": "nps test-cy-open", + "clean": "node ./custom-runner.cjs clean", + "lint": "node ./custom-runner.cjs lint", + "lint:scope": "node ./custom-runner.cjs scope:lint", + "start": "node ./custom-runner.cjs start", + "watch": "node ./custom-runner.cjs watch", + "generate": "node ./custom-runner.cjs generate", + "generateAPI": "node ./custom-runner.cjs generateAPI", + "build": "node ./custom-runner.cjs build", + "bundle": "node ./custom-runner.cjs build:bundle", + "test": "node ./custom-runner.cjs test", + "test:suite-1": "node ./custom-runner.cjs test-suite-1", + "test:suite-2": "node ./custom-runner.cjs test-suite-2", + "test:cypress": "node ./custom-runner.cjs test-cy-ci", + "test:cypress:suite-1": "node ./custom-runner.cjs test-cy-ci-suite-1", + "test:cypress:suite-2": "node ./custom-runner.cjs test-cy-ci-suite-2", + "test:cypress:open": "node ./custom-runner.cjs test-cy-open", "test:cypress:single": "npx cypress run --component --browser chrome --spec", "test:vitest": "yarn vitest run", "test:ssr": "node -e \"import('./test/ssr/component-imports.js')\"", @@ -69,4 +69,4 @@ "lit": "^2.0.0", "vitest": "^3.0.2" } -} +} \ No newline at end of file diff --git a/packages/theming/custom-runner.cjs b/packages/theming/custom-runner.cjs new file mode 100644 index 000000000000..75cd4577f835 --- /dev/null +++ b/packages/theming/custom-runner.cjs @@ -0,0 +1,88 @@ +const path = require('path'); +const BuildRunner = require('@ui5/webcomponents-tools/task-runner/build-runner'); + +const runner = new BuildRunner(); + + +const CURRENT_LIB = path.join(__dirname, `./lib/`); +const TOOLS_LIB = path.join(__dirname, `../tools/lib/`); + +const jsonImportsScript = path.join(TOOLS_LIB, "./generate-json-imports/themes.js"); +const generateReportScript = path.join(CURRENT_LIB, "./generate-css-vars-usage-report/index.js"); + +runner.addTask("clean", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "rimraf dist", + "rimraf src/generated", + ] +}); + +runner.addTask("generate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "build:postcss", + "build:jsonImports", + ], + crossEnv: { + UI5_TS: true, + }, + parallel: true, +}); + +runner.addTask("build", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "clean", + "build:src", + "build:postcss", + "build:jsonImports", + "build:typescript", + "generateReport", + ], + crossEnv: { + UI5_TS: true, + } +}); + +runner.addTask("build:src", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `copy-and-watch "src/**/*.{json}" dist/` + ] +}); + +runner.addTask("build:typescript", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "tsc" + ] +}); + +runner.addTask("build:postcss", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${TOOLS_LIB}/css-processors/css-processor-themes.mjs"` + ] +}); + +runner.addTask("build:jsonImports", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${jsonImportsScript}" dist/generated/assets/themes src/generated/json-imports` + ] +}); + +runner.addTask("generateReport", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${generateReportScript}"` + ] +}); + + +// Export for CLI usage +if (require.main === module) { + const taskName = process.argv[2]; + if (!taskName) { + console.log('Available tasks:', Array.from(runner.tasks.keys()).join(', ')); + process.exit(1); + } + + runner.run(taskName).catch(error => { + console.error('Task failed:', error.message); + process.exit(1); + }); +} \ No newline at end of file diff --git a/packages/theming/package-scripts.cjs b/packages/theming/package-scripts.cjs deleted file mode 100644 index ec1fe4636b89..000000000000 --- a/packages/theming/package-scripts.cjs +++ /dev/null @@ -1,24 +0,0 @@ -const path = require('path'); - - -const CURRENT_LIB = path.join(__dirname, `./lib/`); -const TOOLS_LIB = path.join(__dirname, `../tools/lib/`); - -const jsonImportsScript = path.join(TOOLS_LIB, "./generate-json-imports/themes.js"); -const generateReportScript = path.join(CURRENT_LIB, "./generate-css-vars-usage-report/index.js"); - - -module.exports = { - scripts: { - clean: "rimraf dist && rimraf src/generated", - generate: `cross-env UI5_TS=true nps build.postcss build.jsonImports`, - build: { - default: `cross-env UI5_TS=true nps clean build.src build.postcss build.jsonImports build.typescript generateReport`, - src: `copy-and-watch "src/**/*.{json}" dist/`, - typescript: "tsc", - postcss: `node "${TOOLS_LIB}/css-processors/css-processor-themes.mjs"`, - jsonImports: `node "${jsonImportsScript}" dist/generated/assets/themes src/generated/json-imports`, - }, - generateReport: `node "${generateReportScript}"`, - }, -}; diff --git a/packages/theming/package.json b/packages/theming/package.json index a2190610cb6c..d3e50c7c48cc 100644 --- a/packages/theming/package.json +++ b/packages/theming/package.json @@ -17,10 +17,10 @@ "./*": "./dist/*" }, "scripts": { - "clean": "nps clean", - "build": "nps build", - "generate": "nps generate", - "start": "nps start", + "clean": "node ./custom-runner.cjs clean", + "build": "node ./custom-runner.cjs build", + "generate": "node ./custom-runner.cjs generate", + "start": "node ./custom-runner.cjs start", "verify": "node ./lib/verify-vars/index.js", "prepublishOnly": "tsc -b" }, diff --git a/packages/tools/components-package/custom-runner-commands.js b/packages/tools/components-package/custom-runner-commands.js new file mode 100644 index 000000000000..cd01bdd29e77 --- /dev/null +++ b/packages/tools/components-package/custom-runner-commands.js @@ -0,0 +1,403 @@ +const BuildRunner = require('../task-runner/build-runner'); +const path = require("path"); +const fs = require("fs"); +const LIB = path.join(__dirname, `../lib/`); + +const runner = new BuildRunner(); + +let websiteBaseUrl = "/"; + +if (process.env.DEPLOY) { + websiteBaseUrl = "/ui5-webcomponents/"; +} else if (process.env.DEPLOY_NIGHTLY) { + websiteBaseUrl = "/ui5-webcomponents/nightly/"; +} + +const getScripts = (options) => { + const runner = new BuildRunner(); + + // The script creates all JS modules (dist/illustrations/{illustrationName}.js) out of the existing SVGs + const illustrationsData = options.illustrationsData || []; + const illustrations = illustrationsData.map(illustration => `node "${LIB}/create-illustrations/index.js" ${illustration.path} ${illustration.defaultText} ${illustration.illustrationsPrefix} ${illustration.set} ${illustration.destinationPath} ${illustration.collection}`); + const createIllustrationsJSImportsScript = illustrations.join(" && "); + + // The script creates the "src/generated/js-imports/Illustration.js" file that registers loaders (dynamic JS imports) for each illustration + const createIllustrationsLoadersScript = illustrationsData.map(illustrations => `node ${LIB}/generate-js-imports/illustrations.js ${illustrations.destinationPath} ${illustrations.dynamicImports.outputFile} ${illustrations.set} ${illustrations.collection} ${illustrations.dynamicImports.location} ${illustrations.dynamicImports.filterOut.join(" ")}`).join(" && "); + + const tsOption = !options.legacy || options.jsx; + const tsCommandOld = tsOption ? "tsc" : ""; + let tsWatchCommandStandalone = tsOption ? "tsc --watch" : ""; + // this command is only used for standalone projects. monorepo projects get their watch from vite, so opt-out here + if (options.noWatchTS) { + tsWatchCommandStandalone = ""; + } + const tsCrossEnv = tsOption ? true : false; + + if (tsOption) { + try { + require("typescript"); + } catch (e) { + console.error(`TypeScript is not found. Try to install it by running \`npm install --save-dev typescript\` if you are using npm or by running \`yarn add --dev typescript\` if you are using yarn.`); + process.exit(e.code); + } + } + + let viteConfig; + if (fs.existsSync("config/vite.config.js")) { + // old project setup where config file is in separate folder + viteConfig = "-c config/vite.config.js"; + } else if (fs.existsSync("vite.config.js")) { + // preferred way of custom configuration in root project folder + viteConfig = ""; + } else { + // no custom configuration - use default from tools project + viteConfig = `-c "${require.resolve("@ui5/webcomponents-tools/components-package/vite.config.js")}"`; + } + + let eslintConfig; + if (fs.existsSync(".eslintrc.js") || fs.existsSync(".eslintrc.cjs")) { + // preferred way of custom configuration in root project folder + eslintConfig = ""; + } else { + // no custom configuration - use default from tools project + eslintConfig = `--config "${require.resolve("@ui5/webcomponents-tools/components-package/eslint.js")}"`; + } + + + runner.addTask("clean", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "rimraf src/generated", + "rimraf dist", + "scope:testPages:clean" + ], + parallel: true, + }); + + runner.addTask("lint", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `eslint . ${eslintConfig}` + ] + }); + + runner.addTask("lintfix", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `eslint . ${eslintConfig} --fix` + ] + }); + + runner.addTask("generate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "prepare:all" + ], + crossEnv: { + UI5_TS: tsCrossEnv, + } + }) + + runner.addTask("generate:all", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "build:templates", + "build:i18n", + "prepare:styleRelated", + "copyProps", + "build:illustrations" + ], + parallel: true, + }) + + runner.addTask("generate:styleRelated", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "build:styles", + "build:jsonImports", + "build:jsImports" + ], + parallel: true, + }) + + runner.addTask("prepare", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "clean", + "prepare:all", + options.legacy ? "copy" : "", + "copyProps", + "prepare:typescript", + "generateAPI" + ], + crossEnv: { + UI5_TS: tsCrossEnv, + } + }) + + runner.addTask("prepare:all", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "build:templates", + "build:i18n", + "prepare:styleRelated", + "build:illustrations" + ], + parallel: true, + }); + + runner.addTask("prepare:styleRelated", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "build:styles", + "build:jsonImports", + "build:jsImports" + ], + }) + + runner.addTask("prepare:typescript", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + tsCommandOld + ] + }); + + runner.addTask("build", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "prepare", + "lint", + "build:bundle", // "build:bundle2" + ] + }) + + runner.addTask("build:templates", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/hbs2ui5/index.js" -d src/ -o src/generated/templates` + ], + crossEnv: { + UI5_TS: tsCrossEnv, + } + }); + + runner.addTask("build:styles", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "build:styles:themes", + "build:styles:components" + ], + parallel: true, + }) + + runner.addTask("build:styles:themes", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/css-processors/css-processor-themes.mjs"` + ] + }); + + runner.addTask("build:styles:components", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/css-processors/css-processor-components.mjs"` + ] + }); + + runner.addTask("build:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "build:i18n:defaultsjs", + "build:i18n:json" + ], + parallel: true, + }); + + runner.addTask("build:i18n:defaultsjs", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/i18n/defaults.js" src/i18n src/generated/i18n` + ] + }); + + runner.addTask("build:i18n:json", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/i18n/toJSON.js" src/i18n dist/generated/assets/i18n` + ] + }); + + runner.addTask("build:jsonImports", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "build:jsonImports:themes", + "build:jsonImports:i18n" + ], + parallel: true, + }); + + runner.addTask("build:jsonImports:themes", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `mkdir -p src/generated/json-imports && node "${LIB}/generate-json-imports/themes.js" dist/generated/assets/themes src/generated/json-imports` + ] + }); + + runner.addTask("build:jsonImports:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `mkdir -p src/generated/json-imports && node "${LIB}/generate-json-imports/i18n.js" dist/generated/assets/i18n src/generated/json-imports` + ] + }); + + runner.addTask("build:jsImports", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "mkdir -p src/generated/js-imports", + "build:jsImports:illustrationsLoaders" + ], + parallel: false, // ??? + }); + + runner.addTask("build:jsImports:illustrationsLoaders", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + createIllustrationsLoadersScript + ] + }); + + runner.addTask("build:bundle", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `vite build ${viteConfig} --mode testing --base ${websiteBaseUrl}` + ] + }); + + runner.addTask("build:bundle2", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `` + ] + }); + + runner.addTask("build:illustrations", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + createIllustrationsJSImportsScript + ] + }); + + runner.addTask("copyProps", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/copy-and-watch/index.js" --silent "src/i18n/*.properties" dist/` + ] + }); + + runner.addTask("copy", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "copy:src", + "copy:props" + ], + }); + + runner.addTask("copy:src", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/copy-and-watch/index.js" --silent "src/**/*.{js,json}" dist/` + ] + }); + + runner.addTask("copy:props", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/copy-and-watch/index.js" --silent "src/i18n/*.properties" dist/` + ] + }); + + runner.addTask("watch", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "watch:templates", + "watch:typescript", + options.legacy ? "watch:src" : "", + "watch:styles", + "watch:i18n", + "watch:props" + ], + parallel: true, + crossEnv: { + UI5_TS: tsCrossEnv, + } + }); + + runner.addTask("watch:devServer", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "watch:default", + "watch:bundle" + ], + parallel: true, + }); + + runner.addTask("watch:src", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `copy:src --watch --safe --skip-initial-copy` + ] + }); + + runner.addTask("watch:typescript", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + tsWatchCommandStandalone + ] + }); + + runner.addTask("watch:props", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `copyProps --watch --safe --skip-initial-copy` + ] + }); + + runner.addTask("watch:bundle", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node ${LIB}/dev-server/dev-server.mjs ${viteConfig}` + ] + }); + + runner.addTask("watch:styles", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "watch:styles:themes", + "watch:styles:components" + ], + parallel: true, + }); + + runner.addTask("watch:styles:themes", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `build:styles:themes -w` + ] + }); + + runner.addTask("watch:styles:components", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `build:styles:components -w` // TODO + ] + }); + + runner.addTask("watch:templates", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + 'chokidar "src/**/*.hbs" -i "src/generated" -c "nps build:templates"' + ] + }); + + runner.addTask("watch:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + 'chokidar "src/i18n/messagebundle.properties" -c "nps build:i18n:defaultsjs"' + ] + }); + + runner.addTask("start", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "prepare", + "watch:devServer" + ], + }) + + runner.addTask("generateAPI", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "generateAPI:generateCEM", + "generateAPI:validateCEM", + ] + }); + + runner.addTask("generateAPI:generateCEM", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `${options.dev ? "cross-env UI5_CEM_MODE='dev'" : ""} cem analyze --config "${LIB}/cem/custom-elements-manifest.config.mjs"` + ] + }); + + runner.addTask("generateAPI:validateCEM", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `${options.dev ? "cross-env UI5_CEM_MODE='dev'" : ""} node "${LIB}/cem/validate.js"` + ] + }); + + runner.addTask("scope:testPages:clean", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "" + ] + }) + + return runner; +}; + +module.exports = getScripts; \ No newline at end of file diff --git a/packages/tools/components-package/nps.js b/packages/tools/components-package/nps.js index 4b34a6e1ab7c..3261a3a626b1 100644 --- a/packages/tools/components-package/nps.js +++ b/packages/tools/components-package/nps.js @@ -13,7 +13,7 @@ const cypressEnvVariables = (options, predefinedVars) => { let variables = []; const { cypress_code_coverage, cypress_acc_tests } = options.internal ?? {}; - // Handle environment variables like TEST_SUITE + // Handle environment variables like TEST_SUITE if (predefinedVars) { variables = [...predefinedVars]; } diff --git a/packages/tools/icons-collection/custom-runner-commands.js b/packages/tools/icons-collection/custom-runner-commands.js new file mode 100644 index 000000000000..1a5d7970f5f3 --- /dev/null +++ b/packages/tools/icons-collection/custom-runner-commands.js @@ -0,0 +1,172 @@ +const path = require("path"); +const BuildRunner = require('../task-runner/build-runner'); +const LIB = path.join(__dirname, `../lib/`); + +const createIconImportsCommand = (options, runner) => { + if (!options.versions) { + runner.addTask("build:icons", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/create-icons/index.js" "${options.collectionName}"`, + ], + }) + return; + } + + const dependencies = [] + + options.versions.forEach((v) => { + dependencies.push(`build:icons:create${v}`); + + runner.addTask(`build:icons:create${v}`, BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/create-icons/index.js" "${options.collectionName}" "${v}"`, + ] + }) + }); + + runner.addTask("build:icons", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies, + parallel: true, + }) +} + +const copyIconAssetsCommand = (options, runner) => { + if (!options.versions) { + runner.addTask("copy", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "copy:json-imports", + "copy:icon-collection" + ], + parallel: true, + }) + + runner.addTask("copy:json-imports", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/copy-and-watch/index.js" --silent "src/**/*.js" dist/` + ] + }); + runner.addTask("copy:icon-collection", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/copy-and-watch/index.js" --silent "src/*.json" src/generated/assets/`, + ] + }); + + return; + } + + const dependencies = ["copy:json-imports"] + + + options.versions.forEach((v) => { + dependencies.push(`copy:icon-collection${v}`); + + runner.addTask(`copy:icon-collection${v}`, BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/copy-and-watch/index.js" --silent "src/${v}/*.json" src/generated/assets/${v}/`, + ], + }) + }); + + runner.addTask(`copy:json-imports`, BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/copy-and-watch/index.js" --silent "src/**/*.js" dist/` + ] + }); + + runner.addTask("copy", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies, + parallel: true, + }) +} + +const getScripts = (options) => { + const runner = new BuildRunner(); + + createIconImportsCommand(options, runner); + copyIconAssetsCommand(options, runner); + + const tsCommand = !options.legacy ? "tsc --build" : ""; + const tsCrossEnv = !options.legacy ? true : false; + + runner.addTask("clean", "rimraf dist && rimraf src/generated"); + + runner.addTask("generate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "clean", + "copy", + "build:i18n", + "build:icons", + "build:jsonImports", + "copyjson" + ], + crossEnv: { + UI5_TS: tsCrossEnv + } + }) + + runner.addTask("copyjson", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `node "${LIB}/copy-and-watch/index.js" --silent "src/generated/**/*.json" dist/generated/` + ] + }); + + runner.addTask("build", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "clean", + "copy", + "build:i18n", + "typescript", + "build:icons", + "build:jsonImports", + ], + crossEnv: { + UI5_TS: tsCrossEnv + } + }) + + runner.addTask("build:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "build:i18n:defaultsjs", + "build:i18n:json" + ], + parallel: true, + }); + + runner.addTask("build:i18n:defaultsjs", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `mkdir -p dist/generated/i18n`, + `node "${LIB}/i18n/defaults.js" src/i18n src/generated/i18n` + ] + }); + + runner.addTask("build:i18n:json", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `mkdir -p src/generated/assets/i18n`, + `node "${LIB}/i18n/toJSON.js" src/i18n src/generated/assets/i18n` + ] + }); + + runner.addTask("build:jsonImports", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + "build:jsonImports:i18n" + ] + }) + + + runner.addTask("build:jsonImports:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + `mkdir -p src/generated/json-imports`, + `node "${LIB}/generate-json-imports/i18n.js" src/generated/assets/i18n src/generated/json-imports` + ] + }); + + runner.addTask("typescript", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + dependencies: [ + tsCommand, + ] + }); + + return runner; +}; + +module.exports = getScripts; diff --git a/packages/tools/task-runner/build-runner.js b/packages/tools/task-runner/build-runner.js new file mode 100644 index 000000000000..04025209ba76 --- /dev/null +++ b/packages/tools/task-runner/build-runner.js @@ -0,0 +1,118 @@ +const { execSync } = require('child_process'); + +function buildCrossEnvCommand(task) { + if (!task.crossEnv || Object.keys(task.crossEnv).length === 0) { + return task.command; + } + + const envVars = Object.entries(task.crossEnv) + .map(([key, value]) => `${key}=${value}`) + .join(' '); + + return `cross-env ${envVars} ${task.command}`; +} + +class BuildRunner { + static BUILD_RUNNER_CONSTANTS = { + PRINT: "PRINT25", + }; + + constructor() { + this.tasks = new Map(); + this.runningTasks = new Set(); + } + + // Register a task + addTask(name, command, options = {}) { + this.tasks.set(name, { + command: command === BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT ? `echo "${name} command started"` : command, + cwd: process.cwd(), + crossEnv: { ...options.crossEnv }, + env: { ...process.env, ...options.env }, + parallel: options.parallel || false, + skip: options.skip || false, + dependencies: options.dependencies || [] + }); + } + + // Register a task + emptyTask(taskName) { + let task = this.tasks.get(taskName); + + if (task) { + task.command = ""; + + this.tasks.set(taskName, task) + } + } + + // Run a single task + async runTask(taskName, parentEnv = {}, parentCrossEnv = {}) { + if (this.runningTasks.has(taskName)) { + return; // Already running + } + + let task = this.tasks.get(taskName); + + if (!task) { + // Only execute if it's not a registered command - create a default task + this.addTask(taskName, taskName); + task = this.tasks.get(taskName); + } + + if (!task.command || task.skip) { + return; + } + + // Merge parent environment variables with task environment + const mergedEnv = { ...task.env, ...parentEnv }; + const mergedCrossEnv = { ...task.crossEnv, ...parentCrossEnv }; + task = { ...task, env: mergedEnv, crossEnv: mergedCrossEnv }; + + if (task.parallel) { + const promises = []; + + // Run dependencies first, passing along the merged environment + for (const dep of task.dependencies) { + promises.push(this.runTask(dep, mergedEnv, mergedCrossEnv)); + } + + await Promise.all(promises); + } else { + // Run dependencies first, passing along the merged environment + for (const dep of task.dependencies) { + await this.runTask(dep, mergedEnv, mergedCrossEnv); + } + } + + this.runningTasks.add(taskName); + + try { + console.log(`Running: ${taskName}`); + + return new Promise((resolve, reject) => { + try { + const result = execSync(buildCrossEnvCommand(task), { + cwd: task.cwd, + env: task.env, + stdio: 'inherit' + }); + resolve(result); + } catch (error) { + reject(error); + } + }); + } finally { + this.runningTasks.delete(taskName); + } + } + + // Run multiple tasks + async run(...taskNames) { + for (const taskName of taskNames) { + await this.runTask(taskName); + } + } +} + +module.exports = BuildRunner; \ No newline at end of file diff --git a/packages/tools/task-runner/runner.js b/packages/tools/task-runner/runner.js new file mode 100644 index 000000000000..e3b8f0d57c7d --- /dev/null +++ b/packages/tools/task-runner/runner.js @@ -0,0 +1,42 @@ +const BuildRunner = require('./build-runner'); + +const runner = new BuildRunner(); + +// Define your tasks (replace these with your actual NPS script equivalents) +runner.addTask('clean', 'rm -rf dist', { + cwd: process.cwd() +}); + +runner.addTask('lint', 'eslint src --ext .js,.ts', { + cwd: process.cwd() +}); + +runner.addTask('build:components', 'rollup -c', { + cwd: process.cwd(), + dependencies: ['clean'] +}); + +runner.addTask('test', 'jest', { + cwd: process.cwd() +}); + +runner.addTask('build', 'echo "Building project"', { + dependencies: ['lint', 'build:components'], + parallel: false +}); + +// Export for CLI usage +if (require.main === module) { + const taskName = process.argv[2]; + if (!taskName) { + console.log('Available tasks:', Array.from(runner.tasks.keys()).join(', ')); + process.exit(1); + } + + runner.run(taskName).catch(error => { + console.error('Task failed:', error.message); + process.exit(1); + }); +} + +module.exports = runner; \ No newline at end of file From 0c3bdbb9ede2e4006bd1a851b6fa7dbed0bc7eec Mon Sep 17 00:00:00 2001 From: Nayden Naydenov Date: Wed, 27 Aug 2025 18:03:29 +0300 Subject: [PATCH 02/10] chore: test --- packages/base/custom-runner.cjs | 240 ++++++++++-------- .../css-processor-font-face.mjs | 189 ++++++++++---- .../{index.js => index.cjs} | 13 +- packages/base/lib/generate-styles/index.js | 8 +- .../{index.js => index.cjs} | 10 +- .../icons-business-suite/custom-runner.cjs | 4 +- packages/icons-tnt/custom-runner.cjs | 4 +- packages/localization/custom-runner.cjs | 84 +++--- .../lib/generate-json-imports/cldr.js | 8 +- packages/theming/custom-runner.cjs | 58 +++-- .../{index.js => index.cjs} | 20 +- .../custom-runner-commands.js | 204 ++++++++------- .../custom-runner-commands.js | 119 +++++---- packages/tools/lib/amd-to-es6/index.js | 36 +-- .../lib/amd-to-es6/no-remaining-require.js | 19 +- packages/tools/lib/cem/validate.js | 107 +++++--- packages/tools/lib/copy-and-watch/index.js | 182 ++++++++----- packages/tools/lib/copy-list/index.js | 14 +- packages/tools/lib/create-icons/index.js | 122 ++++----- .../tools/lib/create-illustrations/index.js | 28 +- .../css-processor-components.mjs | 137 ++++++---- .../css-processors/css-processor-themes.mjs | 135 ++++++---- .../lib/generate-js-imports/illustrations.js | 78 +++--- .../tools/lib/generate-json-imports/i18n.js | 30 +-- .../tools/lib/generate-json-imports/themes.js | 23 +- packages/tools/lib/i18n/defaults.js | 18 +- packages/tools/lib/i18n/toJSON.js | 18 +- .../lib/remove-dev-mode/remove-dev-mode.mjs | 126 ++++++--- packages/tools/task-runner/build-runner.js | 119 +++++++-- 29 files changed, 1325 insertions(+), 828 deletions(-) rename packages/base/lib/generate-asset-parameters/{index.js => index.cjs} (74%) rename packages/base/lib/generate-version-info/{index.js => index.cjs} (83%) rename packages/theming/lib/generate-css-vars-usage-report/{index.js => index.cjs} (77%) diff --git a/packages/base/custom-runner.cjs b/packages/base/custom-runner.cjs index b00b06e55656..33879ee705a4 100644 --- a/packages/base/custom-runner.cjs +++ b/packages/base/custom-runner.cjs @@ -1,22 +1,27 @@ const resolve = require("resolve"); const path = require("path"); const BuildRunner = require("@ui5/webcomponents-tools/task-runner/build-runner"); +const buildI18nJson = require("@ui5/webcomponents-tools/lib/i18n/toJSON"); +const buildI18nDefaultsjs = require("@ui5/webcomponents-tools/lib/i18n/defaults"); +const buildJsonImportsI18n = require("@ui5/webcomponents-tools/lib/generate-json-imports/i18n"); +const amdToES6 = require("@ui5/webcomponents-tools/lib/amd-to-es6/index"); +const noRequire = require("@ui5/webcomponents-tools/lib/amd-to-es6/no-remaining-require"); +const versionScript = require("./lib/generate-version-info/index.cjs"); +const assetParametersScript = require("./lib/generate-asset-parameters/index.cjs"); +const copyAndWatch = require("@ui5/webcomponents-tools/lib/copy-and-watch/index.js").copyAndWatch; +const validate = require("@ui5/webcomponents-tools/lib/cem/validate"); +const copyUsedModules = require("@ui5/webcomponents-tools/lib/copy-list/index.js"); +const removeDevMode = require("@ui5/webcomponents-tools/lib/remove-dev-mode/remove-dev-mode.mjs").removeDevMode; // +const stylesScript = require("./lib/generate-styles/index.js").default; // +const fontFaceScript = require("./lib/css-processors/css-processor-font-face.mjs").default; // const runner = new BuildRunner(); -const assetParametersScript = resolve.sync("@ui5/webcomponents-base/lib/generate-asset-parameters/index.js"); -const stylesScript = resolve.sync("@ui5/webcomponents-base/lib/generate-styles/index.js"); -const fontFaceScript = resolve.sync("@ui5/webcomponents-base/lib/css-processors/css-processor-font-face.mjs"); -const versionScript = resolve.sync("@ui5/webcomponents-base/lib/generate-version-info/index.js"); -const copyUsedModules = resolve.sync("@ui5/webcomponents-tools/lib/copy-list/index.js"); -const amdToES6 = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/index.js"); -const noRequire = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/no-remaining-require.js"); - const LIB = path.join(__dirname, `../tools/lib/`); const viteConfig = `-c "${require.resolve("@ui5/webcomponents-tools/components-package/vite.config.js")}"`; -runner.addTask("clean", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("clean", { dependencies: [ "rimraf src/generated", "rimraf dist", @@ -24,13 +29,13 @@ runner.addTask("clean", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { ], }); -runner.addTask("lint", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("lint", { dependencies: [ "eslint .", ], }); -runner.addTask("generate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("generate", { dependencies: [ "clean", "build:i18n", @@ -48,7 +53,7 @@ runner.addTask("generate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { }, }); -runner.addTask("prepare", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("prepare", { dependencies: [ "clean", "build:i18n", @@ -68,13 +73,13 @@ runner.addTask("prepare", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { }, }); -runner.addTask("typescript", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("typescript", { dependencies: [ "tsc -b", ], }); -runner.addTask("integrate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("integrate", { dependencies: [ "integrate:copy-used-modules", "integrate:amd-to-es6", @@ -84,26 +89,33 @@ runner.addTask("integrate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { parallel: false, // ??? }); -runner.addTask("integrate:copy-used-modules", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${copyUsedModules}" ./used-modules.txt dist/`, - ], +runner.addTask("integrate:copy-used-modules", { + callback: async () => { + const dest = "dist/"; + await copyUsedModules("./used-modules.txt", dest); + return "Used modules copied."; + }, }); -runner.addTask("integrate:amd-to-es6", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${amdToES6}" dist/`, - ], +runner.addTask("integrate:amd-to-es6", { + callback: async () => { + await amdToES6("dist/"); + // console.log("i18n default file generated."); + // return "i18n default file generated." + return ""; + }, }); -runner.addTask("integrate:no-remaining-require", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, - { - dependencies: [ - `node "${noRequire}" dist/`, - ], - }); +runner.addTask("integrate:no-remaining-require", { + callback: async () => { + await noRequire("dist/"); + // console.log("i18n default file generated."); + // return "i18n default file generated." + return ""; + }, +}); -runner.addTask("integrate:third-party", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("integrate:third-party", { dependencies: [ "integrate:third-party:copy", "integrate:third-party:fix", @@ -111,32 +123,32 @@ runner.addTask("integrate:third-party", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT parallel: false, // ??? }); -runner.addTask("integrate:third-party:copy", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - "mkdir -p dist/sap/ui/thirdparty/", - "copy-and-watch ../../node_modules/@openui5/sap.ui.core/src/sap/ui/thirdparty/caja-html-sanitizer.js dist/sap/ui/thirdparty/", - ], +runner.addTask("integrate:third-party:copy", { + callback: async () => { + await copyAndWatch("../../node_modules/@openui5/sap.ui.core/src/sap/ui/thirdparty/caja-html-sanitizer.js", "dist/sap/ui/thirdparty/", { silent: true }); + return "Third party files copied."; + }, }); -runner.addTask("integrate:third-party:fix", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("integrate:third-party:fix", { dependencies: [ "replace-in-file 240 xA0 dist/sap/ui/thirdparty/caja-html-sanitizer.js", ], }); -runner.addTask("build", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("build", { dependencies: [ "prepare", ], }); -runner.addTask("build:bundle", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("build:bundle", { dependencies: [ `vite build ${viteConfig}`, ], }); -runner.addTask("build:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("build:i18n", { dependencies: [ "build:i18n:defaultsjs", "build:i18n:json", @@ -144,84 +156,91 @@ runner.addTask("build:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { parallel: true, }); -runner.addTask("build:i18n:defaultsjs", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/i18n/defaults.js" src/i18n src/generated/i18n`, - ], +runner.addTask("build:i18n:defaultsjs", { + callback: async () => { + await buildI18nDefaultsjs("src/i18n", "src/generated/i18n", true); + console.log("i18n default file generated."); + return "i18n default file generated." + } }); -runner.addTask("build:i18n:json", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/i18n/toJSON.js" src/i18n dist/generated/assets/i18n`, - ], +runner.addTask("build:i18n:json", { + callback: async () => { + await buildI18nJson("src/i18n", "dist/generated/assets/i18n"); + console.log("Message bundle JSON files generated."); + return "Message bundle JSON files generated."; + }, }); -runner.addTask("build:jsonImports", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("build:jsonImports", { dependencies: [ "build:jsonImports:i18n", ], }); -runner.addTask("build:jsonImports:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `mkdir -p src/generated/json-imports`, - `node "${LIB}/generate-json-imports/i18n.js" dist/generated/assets/i18n src/generated/json-imports`, - ], +runner.addTask("build:jsonImports:i18n", { + callback: async () => { + await buildJsonImportsI18n("dist/generated/assets/i18n", "src/generated/json-imports", true); + console.log("Generated i18n JSON imports."); + return "Generated i18n JSON imports."; + }, }); -runner.addTask("copy", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("copy", { dependencies: [ "copy:src", ], }); -runner.addTask("copy:src", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/copy-and-watch/index.js" --silent "src/**/*.{js,json}" dist/`, - ], +runner.addTask("copy:src", { + callback: async () => { + await copyAndWatch("src/**/*.{js,json}", "dist/", { silent: true }); + return "Source files copied."; + // console.log("Source files copied."); + // return "Source files copied."; + // return ""; + }, }); -runner.addTask("generateAssetParameters", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${assetParametersScript}"`, - ], +runner.addTask("generateAssetParameters", { + callback: async () => { + await assetParametersScript("dist/"); + console.log("Assets parameters generated."); + return "Assets parameters generated."; + }, }); -runner.addTask("generateVersionInfo", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${versionScript}"`, - ], +runner.addTask("generateVersionInfo", { + callback: async () => { + await versionScript(); + console.log("Version info file generated."); + return "Version info file generated."; + }, }); -runner.addTask("generateStyles", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${stylesScript}"`, - ], +runner.addTask("generateStyles", { + callback: async () => { + await stylesScript(); + console.log("Styles files generated."); + return "Styles files generated."; + }, }); -runner.addTask("generateFontFace", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${fontFaceScript}"`, - ], +runner.addTask("generateFontFace", { + callback: async () => { + await fontFaceScript(); + console.log("FontFace CSS generated."); + return "FontFace CSS generated."; + }, }); -runner.addTask("generateTemplates", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("generateTemplates", { dependencies: [ ``, ], }); -runner.addTask("generateTestTemplates", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `mkdir -p test/test-elements/generated/templates`, - `node "${LIB}/hbs2ui5/index.js" -d test/test-elements -o test/test-elements/generated/templates`, - ], - crossEnv: { - UI5_BASE: true, - }, -}); - -runner.addTask("generateProd", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("generateProd", { dependencies: [ "generateProd:remove-dev-mode", "generateProd:copy-prod", @@ -229,28 +248,32 @@ runner.addTask("generateProd", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { parallel: false, // ??? }); -runner.addTask("generateProd:remove-dev-mode", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/remove-dev-mode/remove-dev-mode.mjs"`, - ], +runner.addTask("generateProd:remove-dev-mode", { + callback: async () => { + await removeDevMode(); + return "Dev mode removed."; + }, }); -runner.addTask("generateProd:copy-prod", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `copy-and-watch "dist/sap/**/*" dist/prod/sap/`, - `copy-and-watch "dist/thirdparty/preact/**/*.js" dist/prod/thirdparty/preact/`, - `copy-and-watch "dist/generated/assets/**/*.json" dist/prod/generated/assets/`, - ], +runner.addTask("generateProd:copy-prod", { + callback: async () => { + Promise.all([ + copyAndWatch("dist/sap/**/*", "dist/prod/sap/", { silent: true }), + copyAndWatch("dist/thirdparty/preact/**/*.js", "dist/prod/thirdparty/preact/", { silent: true }), + copyAndWatch("dist/generated/assets/**/*.json", "dist/prod/generated/assets/", { silent: true }), + ]); + return "Production files copied."; + }, }); -runner.addTask("generateAPI", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("generateAPI", { dependencies: [ "generateAPI:generateCEM", "generateAPI:validateCEM", ], }); -runner.addTask("generateAPI:generateCEM", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("generateAPI:generateCEM", { dependencies: [ `cem analyze --config "${LIB}/cem/custom-elements-manifest.config.mjs"`, ], @@ -259,16 +282,14 @@ runner.addTask("generateAPI:generateCEM", BuildRunner.BUILD_RUNNER_CONSTANTS.PRI }, }); -runner.addTask("generateAPI:validateCEM", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/cem/validate.js"`, - ], - crossEnv: { - UI5_CEM_MODE: "dev", - }, +runner.addTask("generateAPI:validateCEM", { + callback: async () => { + await validate({ devMode: "dev" }); + return "CEM validation completed."; + } }); -runner.addTask("watch", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("watch", { dependencies: [ "watch:src", "watch:styles", @@ -276,10 +297,11 @@ runner.addTask("watch", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { parallel: true, }); -runner.addTask("watch:src", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/copy-and-watch/index.js" --silent --watch "src/**/*.{js,json}" dist/`, - ], +runner.addTask("watch:src", { + callback: async () => { + await copyAndWatch("src/**/*.{js,json}", "dist/", { silent: true }); + return "Source files copied."; + }, }); runner.addTask("watch:styles", { diff --git a/packages/base/lib/css-processors/css-processor-font-face.mjs b/packages/base/lib/css-processors/css-processor-font-face.mjs index 4c5b234a33f2..3cc1d577b6ab 100644 --- a/packages/base/lib/css-processors/css-processor-font-face.mjs +++ b/packages/base/lib/css-processors/css-processor-font-face.mjs @@ -3,62 +3,161 @@ import * as path from "path"; import { readFile, writeFile } from "fs/promises"; import { fileURLToPath } from "url"; -const themeBasePackage = JSON.parse(await readFile(fileURLToPath(import.meta.resolve("@sap-theming/theming-base-content/package.json", "utf-8")))); +/** + * Processes font-face CSS declarations by updating URLs and filtering content + * @param {string} text - CSS text containing @font-face declarations + * @param {Object} options - Processing options + * @param {string} options.cdnUrl - CDN URL template for fonts + * @param {string} options.version - Package version for CDN URL + * @param {string[]} options.excludeFonts - Font families to exclude (default: ["SAP-icons"]) + * @param {boolean} options.removeWoff - Whether to remove woff format URLs (default: true) + * @returns {string} Processed CSS text + */ +export const processFontFace = (text, options = {}) => { + const { + cdnUrl = "https://cdn.jsdelivr.net/npm/@sap-theming/theming-base-content@{version}/content/Base/baseLib/baseTheme/fonts", + version, + excludeFonts = ["SAP-icons"], + removeWoff = true + } = options; -const processFontFace = (text) => { const declarationExpr = /@font-face\s*{[^}]*}/g; // change font-face src - text = text.replaceAll("../baseTheme/fonts", `https://cdn.jsdelivr.net/npm/@sap-theming/theming-base-content@${themeBasePackage.version}/content/Base/baseLib/baseTheme/fonts`); + if (version) { + const finalCdnUrl = cdnUrl.replace("{version}", version); + text = text.replaceAll("../baseTheme/fonts", finalCdnUrl); + } // extract declarations for separate usage let fontFaceDeclarations = [...text.matchAll(declarationExpr)].map(x => x[0]); - // remove SAP-icons - fontFaceDeclarations = fontFaceDeclarations.filter(decl => !decl.includes("SAP-icons")); + // remove excluded fonts + if (excludeFonts.length > 0) { + fontFaceDeclarations = fontFaceDeclarations.filter(decl => + !excludeFonts.some(font => decl.includes(font)) + ); + } - // remove woff urls - fontFaceDeclarations = fontFaceDeclarations.map(decl => { - // @font-face { - // src: url(../baseTheme/fonts/72-Semibold.woff2) format("woff2"), url(../baseTheme/fonts/72-Semibold.woff) format("woff"), local("72-Semibold"); - return decl.replace(/,url\(([^)]+)\.woff\)\ format\("woff"\)/, ''); - }); + // remove woff urls if requested + if (removeWoff) { + fontFaceDeclarations = fontFaceDeclarations.map(decl => { + // @font-face { + // src: url(../baseTheme/fonts/72-Semibold.woff2) format("woff2"), url(../baseTheme/fonts/72-Semibold.woff) format("woff"), local("72-Semibold"); + return decl.replace(/,url\(([^)]+)\.woff\)\ format\("woff"\)/, ''); + }); + } return fontFaceDeclarations.join("\n"); -} - -let fontfacePlugin = { - name: 'fontface', - setup(build) { - build.initialOptions.write = false; - - build.onEnd(result => { - result.outputFiles.forEach(async f => { - let newText = processFontFace(f.text); - const tsPath = path.join(process.cwd(), "src/generated/css/FontFace.css.ts"); - const tsContent = `export default \`${newText}\``; - await writeFile(tsPath, tsContent); +}; + +/** + * Creates an esbuild plugin for processing font-face CSS + * @param {Object} options - Plugin options + * @param {string} options.outputPath - Output file path for generated CSS + * @param {Object} options.processingOptions - Options passed to processFontFace function + * @param {boolean} options.generateTypeScript - Whether to generate TypeScript export (default: true) + * @returns {Object} esbuild plugin + */ +export const createFontFacePlugin = (options = {}) => { + const { + outputPath = path.join(process.cwd(), "src/generated/css/FontFace.css.ts"), + processingOptions = {}, + generateTypeScript = true + } = options; + + return { + name: 'fontface-processor', + setup(build) { + build.initialOptions.write = false; + + build.onEnd(result => { + result.outputFiles.forEach(async f => { + const processedText = processFontFace(f.text, processingOptions); + + if (generateTypeScript) { + const tsContent = `export default \`${processedText}\``; + await writeFile(outputPath, tsContent); + } else { + const cssPath = outputPath.replace(/\.ts$/, ''); + await writeFile(cssPath, processedText); + } + }); }); - }) - }, -} - -// esbuild cannot resolve the node module format when passed as stdin, so resolve the actual file via node resolve -const themeBaseFile = fileURLToPath(import.meta.resolve("@sap-theming/theming-base-content/content/Base/baseLib/sap_horizon/css_variables.css")); - -const config = { - stdin: { - contents: `@import ${JSON.stringify(themeBaseFile)};`, // windows paths contain a backslash which has to be escaped because this will be treated as a string - resolveDir: './', - sourcefile: 'virtual-font-face.css', - loader: 'css', - }, - bundle: true, - minify: true, - plugins: [ - fontfacePlugin, - ], - external: ["*.ttf", "*.woff", "*.woff2"], + }, + }; }; -const result = await esbuild.build(config); +/** + * Creates esbuild configuration for font-face processing + * @param {Object} options - Configuration options + * @param {string} options.themePackage - Theme package name (default: "@sap-theming/theming-base-content") + * @param {string} options.cssFile - CSS file path within the package (default: "content/Base/baseLib/sap_horizon/css_variables.css") + * @param {boolean} options.bundle - Whether to bundle (default: true) + * @param {boolean} options.minify - Whether to minify (default: true) + * @param {string[]} options.external - External dependencies (default: ["*.ttf", "*.woff", "*.woff2"]) + * @param {Object} options.pluginOptions - Options for the font-face plugin + * @returns {Promise} esbuild configuration + */ +export const createFontFaceConfig = async (options = {}) => { + const { + themePackage = "@sap-theming/theming-base-content", + cssFile = "content/Base/baseLib/sap_horizon/css_variables.css", + bundle = true, + minify = true, + external = ["*.ttf", "*.woff", "*.woff2"], + pluginOptions = {} + } = options; + + // Get theme package version + const themeBasePackage = JSON.parse( + await readFile(fileURLToPath(import.meta.resolve(`${themePackage}/package.json`)), "utf-8") + ); + + // Resolve the actual CSS file path + const themeBaseFile = fileURLToPath(import.meta.resolve(`${themePackage}/${cssFile}`)); + + // Set up processing options with version + const processingOptions = { + version: themeBasePackage.version, + ...pluginOptions.processingOptions + }; + + return { + stdin: { + contents: `@import ${JSON.stringify(themeBaseFile)};`, + resolveDir: './', + sourcefile: 'virtual-font-face.css', + loader: 'css', + }, + bundle, + minify, + plugins: [ + createFontFacePlugin({ + ...pluginOptions, + processingOptions + }), + ], + external, + }; +}; + +/** + * Processes font-face CSS and generates TypeScript output + * @param {Object} options - Processing options (same as createFontFaceConfig) + * @returns {Promise} esbuild result + */ +export const processFontFaceCSS = async (options = {}) => { + const config = await createFontFaceConfig(options); + return await esbuild.build(config); +}; + +// Default export for backward compatibility +export default processFontFaceCSS; + +// // If this file is run directly, execute with default configuration +// if (import.meta.url === `file://${process.argv[1]}`) { +// const config = await createFontFaceConfig(); +// const result = await esbuild.build(config); +// console.log('Font-face CSS processing completed:', result); +// } \ No newline at end of file diff --git a/packages/base/lib/generate-asset-parameters/index.js b/packages/base/lib/generate-asset-parameters/index.cjs similarity index 74% rename from packages/base/lib/generate-asset-parameters/index.js rename to packages/base/lib/generate-asset-parameters/index.cjs index d51d4784a021..680168dc06c1 100644 --- a/packages/base/lib/generate-asset-parameters/index.js +++ b/packages/base/lib/generate-asset-parameters/index.cjs @@ -1,5 +1,6 @@ -import fs from "fs/promises"; -import assets from "@ui5/webcomponents-tools/assets-meta.js"; +const fs = require("fs").promises; +const assets = require("@ui5/webcomponents-tools/assets-meta.js"); + const fileContent = `const assetParameters = ${JSON.stringify(assets)}; @@ -22,6 +23,8 @@ const generate = async () => { return fs.writeFile("src/generated/AssetParameters.ts", fileContent); } -generate().then(() => { - console.log("Assets parameters generated."); -}); +// generate().then(() => { +// console.log("Assets parameters generated."); +// }); + +module.exports = generate; \ No newline at end of file diff --git a/packages/base/lib/generate-styles/index.js b/packages/base/lib/generate-styles/index.js index 60cd1639cb95..507e14227d51 100644 --- a/packages/base/lib/generate-styles/index.js +++ b/packages/base/lib/generate-styles/index.js @@ -16,6 +16,8 @@ const generate = async () => { return Promise.all(filesPromises); }; -generate().then(() => { - console.log("Styles files generated."); -}); +// generate().then(() => { +// console.log("Styles files generated."); +// }); + +export default generate; \ No newline at end of file diff --git a/packages/base/lib/generate-version-info/index.js b/packages/base/lib/generate-version-info/index.cjs similarity index 83% rename from packages/base/lib/generate-version-info/index.js rename to packages/base/lib/generate-version-info/index.cjs index df86c5d3e966..6ad40b87b4e6 100644 --- a/packages/base/lib/generate-version-info/index.js +++ b/packages/base/lib/generate-version-info/index.cjs @@ -1,4 +1,4 @@ -import fs from "fs/promises"; +const fs = require("fs").promises; const generate = async () => { const version = JSON.parse(await fs.readFile("package.json")).version; @@ -27,6 +27,8 @@ export default VersionInfo;`; await fs.writeFile("src/generated/VersionInfo.ts", fileContent); } -generate().then(() => { - console.log("Version info file generated."); -}); +// generate().then(() => { +// console.log("Version info file generated."); +// }); + +module.exports = generate diff --git a/packages/icons-business-suite/custom-runner.cjs b/packages/icons-business-suite/custom-runner.cjs index 7bb7ae162392..18c64ac45b6b 100644 --- a/packages/icons-business-suite/custom-runner.cjs +++ b/packages/icons-business-suite/custom-runner.cjs @@ -7,10 +7,10 @@ const options = { const scripts = getScripts(options); -scripts.emptyTask("build:i18n", scripts.constructor.BUILD_RUNNER_CONSTANTS.PRINT, { +scripts.emptyTask("build:i18n", { skip: true, }); -scripts.emptyTask("build:jsonImports", scripts.constructor.BUILD_RUNNER_CONSTANTS.PRINT, { +scripts.emptyTask("build:jsonImports", { skip: true, }); diff --git a/packages/icons-tnt/custom-runner.cjs b/packages/icons-tnt/custom-runner.cjs index 4a9772fa134e..f8624462fbe4 100644 --- a/packages/icons-tnt/custom-runner.cjs +++ b/packages/icons-tnt/custom-runner.cjs @@ -7,10 +7,10 @@ const options = { const scripts = getScripts(options); -scripts.emptyTask("build:i18n", scripts.constructor.BUILD_RUNNER_CONSTANTS.PRINT, { +scripts.emptyTask("build:i18n", { skip: true, }); -scripts.emptyTask("build:jsonImports", scripts.constructor.BUILD_RUNNER_CONSTANTS.PRINT, { +scripts.emptyTask("build:jsonImports", { skip: true, }); diff --git a/packages/localization/custom-runner.cjs b/packages/localization/custom-runner.cjs index 833fb43f1ea5..1290278ef837 100644 --- a/packages/localization/custom-runner.cjs +++ b/packages/localization/custom-runner.cjs @@ -1,26 +1,27 @@ const resolve = require("resolve"); const BuildRunner = require("@ui5/webcomponents-tools/task-runner/build-runner"); +const amdToES6 = require("@ui5/webcomponents-tools/lib/amd-to-es6/index"); +const noRequire = require("@ui5/webcomponents-tools/lib/amd-to-es6/no-remaining-require"); +const cldr = require("./lib/generate-json-imports/cldr").default; +const copyUsedModules = require("@ui5/webcomponents-tools/lib/copy-list/index.js"); +const copyAndWatch = require("@ui5/webcomponents-tools/lib/copy-and-watch/index.js").copyAndWatch; const runner = new BuildRunner(); -const copyUsedModules = resolve.sync("@ui5/webcomponents-tools/lib/copy-list/index.js"); -const amdToES6 = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/index.js"); -const noRequire = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/no-remaining-require.js"); - -runner.addTask("clean", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("clean", { dependencies: [ "rimraf src/generated", "rimraf dist", ], }); -runner.addTask("lint", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("lint", { dependencies: [ "eslint .", ], }); -runner.addTask("generate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("generate", { dependencies: [ "clean", "copy", @@ -29,7 +30,7 @@ runner.addTask("generate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { ], }); -runner.addTask("build", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("build", { dependencies: [ "clean", "copy", @@ -40,35 +41,44 @@ runner.addTask("build", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { ], }); -runner.addTask("build:amd-to-es6", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${amdToES6}" dist/`, - ], +runner.addTask("build:amd-to-es6", { + callback: async () => { + await amdToES6("dist/"); + // console.log("i18n default file generated."); + // return "i18n default file generated." + return ""; + }, }); -runner.addTask("build:no-remaining-require", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${noRequire}" dist/`, - ], +runner.addTask("build:no-remaining-require", { + callback: async () => { + await noRequire("dist/"); + // console.log("i18n default file generated."); + // return "i18n default file generated." + return ""; + }, }); -runner.addTask("build:typescript", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("build:typescript", { dependencies: "tsc --build", }); -runner.addTask("build:jsonImports", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - "node ./lib/generate-json-imports/cldr.js", - ], +runner.addTask("build:jsonImports", { + callback: async () => { + await cldr(); + // console.log("i18n default file generated."); + // return "i18n default file generated." + return ""; + }, }); -runner.addTask("typescript", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("typescript", { dependencies: [ "tsc --build", ], }); -runner.addTask("copy", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("copy", { dependencies: [ "copy:used-modules", "copy:cldr", @@ -77,22 +87,26 @@ runner.addTask("copy", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { parallel: true, }); -runner.addTask("copy:used-modules", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${copyUsedModules}" ./used-modules.txt dist/`, - ], +runner.addTask("copy:used-modules", { + callback: async () => { + const dest = "dist/"; + await copyUsedModules("./used-modules.txt", dest); + return "Used modules copied."; + }, }); -runner.addTask("copy:cldr", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `copy-and-watch "../../node_modules/@openui5/sap.ui.core/src/sap/ui/core/cldr/*" dist/generated/assets/cldr/`, - ], +runner.addTask("copy:cldr", { + callback: async () => { + await copyAndWatch("../../node_modules/@openui5/sap.ui.core/src/sap/ui/core/cldr/*", "dist/generated/assets/cldr/", { silent: true }); + return "CLDR JSON files generated."; + } }); -runner.addTask("copy:overlay", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `copy-and-watch "overlay/**/*.js" dist/`, - ], +runner.addTask("copy:overlay", { + callback: async () => { + await copyAndWatch("overlay/**/*.js", "dist/", { silent: true }); + return "Overlay files copied."; + } }); // Export for CLI usage diff --git a/packages/localization/lib/generate-json-imports/cldr.js b/packages/localization/lib/generate-json-imports/cldr.js index 39d528a68f8e..44ff9319a850 100644 --- a/packages/localization/lib/generate-json-imports/cldr.js +++ b/packages/localization/lib/generate-json-imports/cldr.js @@ -42,6 +42,8 @@ const generate = async () => { ]); } -generate().then(() => { - console.log("CLDR files generated."); -}); +// generate().then(() => { +// console.log("CLDR files generated."); +// }); + +export default generate; \ No newline at end of file diff --git a/packages/theming/custom-runner.cjs b/packages/theming/custom-runner.cjs index 75cd4577f835..0579a52ea8f4 100644 --- a/packages/theming/custom-runner.cjs +++ b/packages/theming/custom-runner.cjs @@ -1,23 +1,20 @@ const path = require('path'); const BuildRunner = require('@ui5/webcomponents-tools/task-runner/build-runner'); +const buildJsonImportsThemes = require("@ui5/webcomponents-tools/lib/generate-json-imports/themes"); +const generateReport = require("./lib/generate-css-vars-usage-report/index.cjs"); +const cssProcessorThemes = require("@ui5/webcomponents-tools/lib/css-processors/css-processor-themes.mjs").processThemes; +const copyAndWatch = require("@ui5/webcomponents-tools/lib/copy-and-watch/index.js").copyAndWatch; const runner = new BuildRunner(); - -const CURRENT_LIB = path.join(__dirname, `./lib/`); -const TOOLS_LIB = path.join(__dirname, `../tools/lib/`); - -const jsonImportsScript = path.join(TOOLS_LIB, "./generate-json-imports/themes.js"); -const generateReportScript = path.join(CURRENT_LIB, "./generate-css-vars-usage-report/index.js"); - -runner.addTask("clean", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("clean", { dependencies: [ "rimraf dist", "rimraf src/generated", ] }); -runner.addTask("generate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("generate", { dependencies: [ "build:postcss", "build:jsonImports", @@ -25,10 +22,9 @@ runner.addTask("generate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { crossEnv: { UI5_TS: true, }, - parallel: true, }); -runner.addTask("build", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("build", { dependencies: [ "clean", "build:src", @@ -42,34 +38,40 @@ runner.addTask("build", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { } }); -runner.addTask("build:src", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `copy-and-watch "src/**/*.{json}" dist/` - ] +runner.addTask("build:src", { + callback: async () => { + await copyAndWatch("src/**/*.{json}", "dist/", { silent: true }); + return "Source files copied."; + } }); -runner.addTask("build:typescript", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { +runner.addTask("build:typescript", { dependencies: [ "tsc" ] }); -runner.addTask("build:postcss", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${TOOLS_LIB}/css-processors/css-processor-themes.mjs"` - ] +runner.addTask("build:postcss", { + callback: async () => { + await cssProcessorThemes({ tsMode: true }); + return "" + } }); -runner.addTask("build:jsonImports", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${jsonImportsScript}" dist/generated/assets/themes src/generated/json-imports` - ] +runner.addTask("build:jsonImports", { + callback: async () => { + await buildJsonImportsThemes("dist/generated/assets/themes", "src/generated/json-imports", true); + console.log("Generated themes JSON imports."); + return "Generated themes JSON imports."; + }, }); -runner.addTask("generateReport", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${generateReportScript}"` - ] +runner.addTask("generateReport", { + callback: async () => { + await generateReport(); + console.log("CSS Vars usage report generated."); + return "CSS Vars usage report generated."; + }, }); diff --git a/packages/theming/lib/generate-css-vars-usage-report/index.js b/packages/theming/lib/generate-css-vars-usage-report/index.cjs similarity index 77% rename from packages/theming/lib/generate-css-vars-usage-report/index.js rename to packages/theming/lib/generate-css-vars-usage-report/index.cjs index 81ee14b9ca43..d4cb92d578eb 100644 --- a/packages/theming/lib/generate-css-vars-usage-report/index.js +++ b/packages/theming/lib/generate-css-vars-usage-report/index.cjs @@ -1,10 +1,6 @@ -import fs from "fs/promises"; -import path from "path"; -import beautify from "json-beautify"; -import { fileURLToPath } from 'url'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); +const fs = require("fs/promises"); +const path = require("path"); +const beautify = require("json-beautify"); const vars = new Set(); @@ -18,7 +14,7 @@ const processFile = async file => { }; const generate = async () => { - const { globby } = await import("globby"); + const { globby } = require("globby"); const mainFiles = await globby(path.join(__dirname, "../../../main/src/themes/**/*.css").replace(/\\/g, "/")); const fioriFiles = await globby(path.join(__dirname, "../../../fiori/src/themes/**/*.css").replace(/\\/g, "/")); @@ -33,6 +29,8 @@ const generate = async () => { return fs.writeFile(path.join(__dirname, "../../css-vars-usage.json"), beautify(result, null, 2, 100)); } -generate().then(() => { - console.log("CSS Vars usage report generated."); -}); +// generate().then(() => { +// console.log("CSS Vars usage report generated."); +// }); + +module.exports = generate; diff --git a/packages/tools/components-package/custom-runner-commands.js b/packages/tools/components-package/custom-runner-commands.js index cd01bdd29e77..77c111402b82 100644 --- a/packages/tools/components-package/custom-runner-commands.js +++ b/packages/tools/components-package/custom-runner-commands.js @@ -2,8 +2,16 @@ const BuildRunner = require('../task-runner/build-runner'); const path = require("path"); const fs = require("fs"); const LIB = path.join(__dirname, `../lib/`); - -const runner = new BuildRunner(); +const buildI18nJson = require("../lib/i18n/toJSON"); +const buildI18nDefaultsjs = require("../lib/i18n/defaults"); +const buildJsonImportsI18n = require("../lib/generate-json-imports/i18n"); +const buildJsonImportsThemes = require("../lib/generate-json-imports/themes"); +const cssProcessorThemes = require("../lib/css-processors/css-processor-themes.mjs").processThemes; +const cssProcessorComponents = require("../lib/css-processors/css-processor-components.mjs").processComponents; +const copyAndWatch = require("../lib/copy-and-watch/index.js").copyAndWatch; +const validate = require("../lib/cem/validate"); +const createIllustrations = require("../lib/create-illustrations"); +const generateJsImportsIllustrations = require("../lib/generate-js-imports/illustrations"); let websiteBaseUrl = "/"; @@ -18,11 +26,12 @@ const getScripts = (options) => { // The script creates all JS modules (dist/illustrations/{illustrationName}.js) out of the existing SVGs const illustrationsData = options.illustrationsData || []; - const illustrations = illustrationsData.map(illustration => `node "${LIB}/create-illustrations/index.js" ${illustration.path} ${illustration.defaultText} ${illustration.illustrationsPrefix} ${illustration.set} ${illustration.destinationPath} ${illustration.collection}`); - const createIllustrationsJSImportsScript = illustrations.join(" && "); + const illustrations = illustrationsData.map(illustration => createIllustrations(illustration.path, illustration.defaultText, illustration.illustrationsPrefix, illustration.set, illustration.destinationPath, illustration.collection)); // The script creates the "src/generated/js-imports/Illustration.js" file that registers loaders (dynamic JS imports) for each illustration - const createIllustrationsLoadersScript = illustrationsData.map(illustrations => `node ${LIB}/generate-js-imports/illustrations.js ${illustrations.destinationPath} ${illustrations.dynamicImports.outputFile} ${illustrations.set} ${illustrations.collection} ${illustrations.dynamicImports.location} ${illustrations.dynamicImports.filterOut.join(" ")}`).join(" && "); + const createIllustrationsLoadersScript = illustrationsData.map(illustrations => + generateJsImportsIllustrations(illustrations.destinationPath, illustrations.dynamicImports.outputFile, illustrations.set, illustrations.collection, illustrations.dynamicImports.location, illustrations.dynamicImports.filterOut)) + const tsOption = !options.legacy || options.jsx; const tsCommandOld = tsOption ? "tsc" : ""; @@ -64,7 +73,7 @@ const getScripts = (options) => { } - runner.addTask("clean", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("clean", { dependencies: [ "rimraf src/generated", "rimraf dist", @@ -73,19 +82,19 @@ const getScripts = (options) => { parallel: true, }); - runner.addTask("lint", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("lint", { dependencies: [ `eslint . ${eslintConfig}` ] }); - runner.addTask("lintfix", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("lintfix", { dependencies: [ `eslint . ${eslintConfig} --fix` ] }); - runner.addTask("generate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("generate", { dependencies: [ "prepare:all" ], @@ -94,7 +103,7 @@ const getScripts = (options) => { } }) - runner.addTask("generate:all", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("generate:all", { dependencies: [ "build:templates", "build:i18n", @@ -105,7 +114,7 @@ const getScripts = (options) => { parallel: true, }) - runner.addTask("generate:styleRelated", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("generate:styleRelated", { dependencies: [ "build:styles", "build:jsonImports", @@ -114,7 +123,7 @@ const getScripts = (options) => { parallel: true, }) - runner.addTask("prepare", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("prepare", { dependencies: [ "clean", "prepare:all", @@ -128,7 +137,7 @@ const getScripts = (options) => { } }) - runner.addTask("prepare:all", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("prepare:all", { dependencies: [ "build:templates", "build:i18n", @@ -138,7 +147,7 @@ const getScripts = (options) => { parallel: true, }); - runner.addTask("prepare:styleRelated", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("prepare:styleRelated", { dependencies: [ "build:styles", "build:jsonImports", @@ -146,13 +155,13 @@ const getScripts = (options) => { ], }) - runner.addTask("prepare:typescript", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("prepare:typescript", { dependencies: [ tsCommandOld ] }); - runner.addTask("build", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("build", { dependencies: [ "prepare", "lint", @@ -160,16 +169,16 @@ const getScripts = (options) => { ] }) - runner.addTask("build:templates", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("build:templates", { dependencies: [ - `node "${LIB}/hbs2ui5/index.js" -d src/ -o src/generated/templates` + !options.legacy ? "" : `node "${LIB}/hbs2ui5/index.js" -d src/ -o src/generated/templates` ], crossEnv: { UI5_TS: tsCrossEnv, } }); - runner.addTask("build:styles", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("build:styles", { dependencies: [ "build:styles:themes", "build:styles:components" @@ -177,19 +186,21 @@ const getScripts = (options) => { parallel: true, }) - runner.addTask("build:styles:themes", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/css-processors/css-processor-themes.mjs"` - ] + runner.addTask("build:styles:themes", { + callback: async () => { + await cssProcessorThemes({ tsMode: options.legacy }); + return "" + } }); - runner.addTask("build:styles:components", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/css-processors/css-processor-components.mjs"` - ] + runner.addTask("build:styles:components", { + callback: async () => { + await cssProcessorComponents({ tsMode: options.legacy }); + return "" + } }); - runner.addTask("build:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("build:i18n", { dependencies: [ "build:i18n:defaultsjs", "build:i18n:json" @@ -197,19 +208,23 @@ const getScripts = (options) => { parallel: true, }); - runner.addTask("build:i18n:defaultsjs", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/i18n/defaults.js" src/i18n src/generated/i18n` - ] + runner.addTask("build:i18n:defaultsjs", { + callback: async () => { + await buildI18nDefaultsjs("src/i18n", "src/generated/i18n", !options.legacy); + console.log("i18n default file generated."); + return "i18n default file generated." + } }); - runner.addTask("build:i18n:json", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/i18n/toJSON.js" src/i18n dist/generated/assets/i18n` - ] + runner.addTask("build:i18n:json", { + callback: async () => { + await buildI18nJson("src/i18n", "dist/generated/assets/i18n"); + console.log("Message bundle JSON files generated."); + return "Message bundle JSON files generated." + }, }); - runner.addTask("build:jsonImports", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("build:jsonImports", { dependencies: [ "build:jsonImports:themes", "build:jsonImports:i18n" @@ -217,19 +232,23 @@ const getScripts = (options) => { parallel: true, }); - runner.addTask("build:jsonImports:themes", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `mkdir -p src/generated/json-imports && node "${LIB}/generate-json-imports/themes.js" dist/generated/assets/themes src/generated/json-imports` - ] + runner.addTask("build:jsonImports:themes", { + callback: async () => { + await buildJsonImportsThemes("dist/generated/assets/themes", "src/generated/json-imports", !options.legacy); + console.log("Generated themes JSON imports."); + return "Generated themes JSON imports."; + }, }); - runner.addTask("build:jsonImports:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `mkdir -p src/generated/json-imports && node "${LIB}/generate-json-imports/i18n.js" dist/generated/assets/i18n src/generated/json-imports` - ] + runner.addTask("build:jsonImports:i18n", { + callback: async () => { + await buildJsonImportsI18n("dist/generated/assets/i18n", "src/generated/json-imports", !options.legacy); + console.log("Generated i18n JSON imports."); + return "Generated i18n JSON imports."; + }, }); - runner.addTask("build:jsImports", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("build:jsImports", { dependencies: [ "mkdir -p src/generated/js-imports", "build:jsImports:illustrationsLoaders" @@ -237,56 +256,64 @@ const getScripts = (options) => { parallel: false, // ??? }); - runner.addTask("build:jsImports:illustrationsLoaders", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - createIllustrationsLoadersScript - ] + runner.addTask("build:jsImports:illustrationsLoaders", { + callback: async () => { + await Promise.all(createIllustrationsLoadersScript); + console.log("Generated illustrations JS imports."); + return "Generated illustrations JS imports."; + } }); - runner.addTask("build:bundle", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("build:bundle", { dependencies: [ `vite build ${viteConfig} --mode testing --base ${websiteBaseUrl}` ] }); - runner.addTask("build:bundle2", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("build:bundle2", { dependencies: [ `` ] }); - runner.addTask("build:illustrations", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - createIllustrationsJSImportsScript - ] + runner.addTask("build:illustrations", { + callback: async () => { + await Promise.all(illustrations); + console.log("Illustrations generated."); + // just a placeholder for the dependencies to work + return "Illustrations generated."; + } }); - runner.addTask("copyProps", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/copy-and-watch/index.js" --silent "src/i18n/*.properties" dist/` - ] + runner.addTask("copyProps", { + callback: async () => { + await copyAndWatch("src/i18n/*.properties", "dist/", { silent: true }); + return "Properties files copied."; + } }); - runner.addTask("copy", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("copy", { dependencies: [ "copy:src", "copy:props" ], }); - runner.addTask("copy:src", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/copy-and-watch/index.js" --silent "src/**/*.{js,json}" dist/` - ] + runner.addTask("copy:src", { + callback: async () => { + await copyAndWatch("src/**/*.{js,json}", "dist/", { silent: true }); + return "Source files copied."; + } }); - runner.addTask("copy:props", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/copy-and-watch/index.js" --silent "src/i18n/*.properties" dist/` - ] + runner.addTask("copy:props", { + callback: async () => { + await copyAndWatch("src/i18n/*.properties", "dist/", { silent: true }); + return "Properties files copied."; + } }); - runner.addTask("watch", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("watch", { dependencies: [ "watch:templates", "watch:typescript", @@ -301,7 +328,7 @@ const getScripts = (options) => { } }); - runner.addTask("watch:devServer", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("watch:devServer", { dependencies: [ "watch:default", "watch:bundle" @@ -309,31 +336,31 @@ const getScripts = (options) => { parallel: true, }); - runner.addTask("watch:src", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("watch:src", { dependencies: [ `copy:src --watch --safe --skip-initial-copy` ] }); - runner.addTask("watch:typescript", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("watch:typescript", { dependencies: [ tsWatchCommandStandalone ] }); - runner.addTask("watch:props", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("watch:props", { dependencies: [ `copyProps --watch --safe --skip-initial-copy` ] }); - runner.addTask("watch:bundle", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("watch:bundle", { dependencies: [ `node ${LIB}/dev-server/dev-server.mjs ${viteConfig}` ] }); - runner.addTask("watch:styles", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("watch:styles", { dependencies: [ "watch:styles:themes", "watch:styles:components" @@ -341,57 +368,58 @@ const getScripts = (options) => { parallel: true, }); - runner.addTask("watch:styles:themes", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("watch:styles:themes", { dependencies: [ `build:styles:themes -w` ] }); - runner.addTask("watch:styles:components", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("watch:styles:components", { dependencies: [ `build:styles:components -w` // TODO ] }); - runner.addTask("watch:templates", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("watch:templates", { dependencies: [ 'chokidar "src/**/*.hbs" -i "src/generated" -c "nps build:templates"' ] }); - runner.addTask("watch:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("watch:i18n", { dependencies: [ 'chokidar "src/i18n/messagebundle.properties" -c "nps build:i18n:defaultsjs"' ] }); - runner.addTask("start", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("start", { dependencies: [ "prepare", "watch:devServer" ], }) - runner.addTask("generateAPI", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("generateAPI", { dependencies: [ "generateAPI:generateCEM", "generateAPI:validateCEM", ] }); - runner.addTask("generateAPI:generateCEM", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("generateAPI:generateCEM", { dependencies: [ `${options.dev ? "cross-env UI5_CEM_MODE='dev'" : ""} cem analyze --config "${LIB}/cem/custom-elements-manifest.config.mjs"` ] }); - runner.addTask("generateAPI:validateCEM", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `${options.dev ? "cross-env UI5_CEM_MODE='dev'" : ""} node "${LIB}/cem/validate.js"` - ] + runner.addTask("generateAPI:validateCEM", { + callback: async () => { + await validate({ devMode: options.dev }); + return "CEM validation completed."; + } }); - runner.addTask("scope:testPages:clean", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("scope:testPages:clean", { dependencies: [ "" ] diff --git a/packages/tools/icons-collection/custom-runner-commands.js b/packages/tools/icons-collection/custom-runner-commands.js index 1a5d7970f5f3..5147178d4c30 100644 --- a/packages/tools/icons-collection/custom-runner-commands.js +++ b/packages/tools/icons-collection/custom-runner-commands.js @@ -1,13 +1,20 @@ const path = require("path"); const BuildRunner = require('../task-runner/build-runner'); const LIB = path.join(__dirname, `../lib/`); +const buildI18nJson = require("../lib/i18n/toJSON"); +const buildI18nDefaultsjs = require("../lib/i18n/defaults"); +const buildJsonImportsI18n = require("../lib/generate-json-imports/i18n"); +const buildIcons = require("../lib/create-icons/index"); +const copyAndWatch = require("../lib/copy-and-watch/index.js").copyAndWatch; const createIconImportsCommand = (options, runner) => { if (!options.versions) { - runner.addTask("build:icons", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/create-icons/index.js" "${options.collectionName}"`, - ], + runner.addTask("build:icons", { + callback: async () => { + await buildIcons(options.collectionName); + console.log("Icons created."); + return "Icons created." + } }) return; } @@ -17,14 +24,16 @@ const createIconImportsCommand = (options, runner) => { options.versions.forEach((v) => { dependencies.push(`build:icons:create${v}`); - runner.addTask(`build:icons:create${v}`, BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/create-icons/index.js" "${options.collectionName}" "${v}"`, - ] + runner.addTask(`build:icons:create${v}`, { + callback: async () => { + await buildIcons(options.collectionName, v); + console.log("Icons created."); + return "Icons created." + } }) }); - runner.addTask("build:icons", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("build:icons", { dependencies, parallel: true, }) @@ -32,7 +41,7 @@ const createIconImportsCommand = (options, runner) => { const copyIconAssetsCommand = (options, runner) => { if (!options.versions) { - runner.addTask("copy", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("copy", { dependencies: [ "copy:json-imports", "copy:icon-collection" @@ -40,15 +49,17 @@ const copyIconAssetsCommand = (options, runner) => { parallel: true, }) - runner.addTask("copy:json-imports", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/copy-and-watch/index.js" --silent "src/**/*.js" dist/` - ] + runner.addTask("copy:json-imports", { + callback: async () => { + await copyAndWatch("src/**/*.js", "dist/", { silent: true }); + return "JSON imports copied."; + } }); - runner.addTask("copy:icon-collection", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/copy-and-watch/index.js" --silent "src/*.json" src/generated/assets/`, - ] + runner.addTask("copy:icon-collection", { + callback: async () => { + await copyAndWatch("src/*.json", "src/generated/assets/", { silent: true }); + return "Icon collection JSON files copied."; + } }); return; @@ -60,20 +71,22 @@ const copyIconAssetsCommand = (options, runner) => { options.versions.forEach((v) => { dependencies.push(`copy:icon-collection${v}`); - runner.addTask(`copy:icon-collection${v}`, BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/copy-and-watch/index.js" --silent "src/${v}/*.json" src/generated/assets/${v}/`, - ], + runner.addTask(`copy:icon-collection${v}`, { + callback: async () => { + await copyAndWatch(`src/${v}/*.json`, `src/generated/assets/${v}/`, { silent: true }); + return `Icon collection ${v} JSON files copied.`; + } }) }); - runner.addTask(`copy:json-imports`, BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/copy-and-watch/index.js" --silent "src/**/*.js" dist/` - ] + runner.addTask(`copy:json-imports`, { + callback: async () => { + await copyAndWatch("src/**/*.js", "dist/", { silent: true }); + return "JSON imports copied."; + } }); - runner.addTask("copy", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("copy", { dependencies, parallel: true, }) @@ -90,7 +103,7 @@ const getScripts = (options) => { runner.addTask("clean", "rimraf dist && rimraf src/generated"); - runner.addTask("generate", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("generate", { dependencies: [ "clean", "copy", @@ -104,13 +117,14 @@ const getScripts = (options) => { } }) - runner.addTask("copyjson", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `node "${LIB}/copy-and-watch/index.js" --silent "src/generated/**/*.json" dist/generated/` - ] + runner.addTask("copyjson", { + callback: async () => { + await copyAndWatch("src/**/*.json", "dist/", { silent: true }); + return "JSON files copied."; + }, }); - runner.addTask("build", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("build", { dependencies: [ "clean", "copy", @@ -124,7 +138,7 @@ const getScripts = (options) => { } }) - runner.addTask("build:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("build:i18n", { dependencies: [ "build:i18n:defaultsjs", "build:i18n:json" @@ -132,35 +146,38 @@ const getScripts = (options) => { parallel: true, }); - runner.addTask("build:i18n:defaultsjs", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `mkdir -p dist/generated/i18n`, - `node "${LIB}/i18n/defaults.js" src/i18n src/generated/i18n` - ] + runner.addTask("build:i18n:defaultsjs", { + callback: async () => { + await buildI18nDefaultsjs("src/i18n", "src/generated/i18n", !options.legacy); + console.log("i18n default file generated."); + return "i18n default file generated." + } }); - runner.addTask("build:i18n:json", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `mkdir -p src/generated/assets/i18n`, - `node "${LIB}/i18n/toJSON.js" src/i18n src/generated/assets/i18n` - ] + runner.addTask("build:i18n:json", { + callback: async () => { + await buildI18nJson("src/i18n", "dist/generated/assets/i18n"); + console.log("Message bundle JSON files generated."); + return "Message bundle JSON files generated." + }, }); - runner.addTask("build:jsonImports", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("build:jsonImports", { dependencies: [ "build:jsonImports:i18n" ] }) - runner.addTask("build:jsonImports:i18n", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { - dependencies: [ - `mkdir -p src/generated/json-imports`, - `node "${LIB}/generate-json-imports/i18n.js" src/generated/assets/i18n src/generated/json-imports` - ] + runner.addTask("build:jsonImports:i18n", { + callback: async () => { + await buildJsonImportsI18n("src/generated/assets/i18n", "src/generated/json-imports", !options.legacy); + console.log("Generated i18n JSON imports."); + return "Generated i18n JSON imports."; + }, }); - runner.addTask("typescript", BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT, { + runner.addTask("typescript", { dependencies: [ tsCommand, ] diff --git a/packages/tools/lib/amd-to-es6/index.js b/packages/tools/lib/amd-to-es6/index.js index 3ddd7930f412..c4a13f1750d0 100644 --- a/packages/tools/lib/amd-to-es6/index.js +++ b/packages/tools/lib/amd-to-es6/index.js @@ -1,12 +1,11 @@ const fs = require("fs").promises; const path = require("path"); -const basePath = process.argv[2]; const babelCore = require("@babel/core"); const babelParser = require("@babel/parser"); const babelGenerator = require("@babel/generator").default; const replaceAsync = require('replace-in-file'); -const convertSAPUIDefineToDefine = async (filePath) => { +const convertSAPUIDefineToDefine = async (filePath, basePath) => { return replaceAsync({ files: filePath, processor: (input) => { @@ -15,13 +14,13 @@ const convertSAPUIDefineToDefine = async (filePath) => { }) } -const convertAmdToEs6 = async (code) => { +const convertAmdToEs6 = async (code, basePath) => { return (await babelCore.transformAsync(code, { plugins: [['babel-plugin-amd-to-esm', {}]] })).code; } -const convertAbsImportsToRelative = (filePath, code) => { +const convertAbsImportsToRelative = (filePath, code, basePath) => { let changed = false; // console.log("File processing started: ", srcPath); @@ -68,8 +67,8 @@ const convertAbsImportsToRelative = (filePath, code) => { return changed ? babelGenerator(tree).code : code; } -const replaceGlobalCoreUsage = (filePath, code) => { - if (!filePath.includes("Configuration")) { +const replaceGlobalCoreUsage = (filePath, code, basePath) => { + if (!filePath.includes("Configuration")) { const replaced = code.replace(/sap\.ui\.getCore\(\)/g, `Core`); return code !== replaced ? `import Core from 'sap/ui/core/Core';${replaced}` : code; } @@ -77,26 +76,31 @@ const replaceGlobalCoreUsage = (filePath, code) => { return code; }; -const transformAmdToES6Module = async (filePath) => { - await convertSAPUIDefineToDefine(filePath); +const transformAmdToES6Module = async (filePath, basePath) => { + await convertSAPUIDefineToDefine(filePath, basePath); let code = (await fs.readFile(filePath)).toString(); - code = await convertAmdToEs6(code); + code = await convertAmdToEs6(code, basePath); - code = replaceGlobalCoreUsage(filePath, code); + code = replaceGlobalCoreUsage(filePath, code, basePath); - code = convertAbsImportsToRelative(filePath, code); + code = convertAbsImportsToRelative(filePath, code, basePath); return fs.writeFile(filePath, code); } -const transformAmdToES6Modules = async () => { +const transformAmdToES6Modules = async (distFolder) => { + const basePath = distFolder; + + const { globby } = await import("globby"); const fileNames = await globby(basePath.replace(/\\/g, "/") + "**/*.js"); - return Promise.all(fileNames.map(transformAmdToES6Module).filter(x => !!x)); + return Promise.all(fileNames.map(fileName => transformAmdToES6Module(fileName, basePath)).filter(x => !!x)); }; -transformAmdToES6Modules().then(() => { - console.log("Success: all amd modules are transformed to es6!"); -}); \ No newline at end of file +// transformAmdToES6Modules().then(() => { +// console.log("Success: all amd modules are transformed to es6!"); +// }); + +module.exports = transformAmdToES6Modules; \ No newline at end of file diff --git a/packages/tools/lib/amd-to-es6/no-remaining-require.js b/packages/tools/lib/amd-to-es6/no-remaining-require.js index 7ab6d8de633e..92558653f1f6 100644 --- a/packages/tools/lib/amd-to-es6/no-remaining-require.js +++ b/packages/tools/lib/amd-to-es6/no-remaining-require.js @@ -1,6 +1,5 @@ const fs = require("fs").promises; const path = require("path"); -const basePath = process.argv[2]; const babelCore = require("@babel/core"); const babelParser = require("@babel/parser"); const babelGenerator = require("@babel/generator").default; @@ -12,11 +11,11 @@ const checkHasRequire = (filePath, code) => { const tree = babelParser.parse(code, { sourceType: "module" }); walk(tree, { CallExpression: function (node) { - if (node.type === "CallExpression" && node?.callee?.name === "unhandledRequire") { - throw new Error(`sap.ui.require found in ${filePath}`); - } - } - }); + if (node.type === "CallExpression" && node?.callee?.name === "unhandledRequire") { + throw new Error(`sap.ui.require found in ${filePath}`); + } + } + }); } const checkFile = async (filePath) => { @@ -24,10 +23,14 @@ const checkFile = async (filePath) => { checkHasRequire(filePath, code); } -const checkAll = async () => { +const checkAll = async (distFolder) => { + const basePath = distFolder; + const { globby } = await import("globby"); const fileNames = await globby(basePath.replace(/\\/g, "/") + "**/*.js"); return Promise.all(fileNames.map(checkFile).filter(x => !!x)); }; -checkAll(); +// checkAll(); + +module.exports = checkAll; diff --git a/packages/tools/lib/cem/validate.js b/packages/tools/lib/cem/validate.js index 1da039400ebd..87296f21ae36 100644 --- a/packages/tools/lib/cem/validate.js +++ b/packages/tools/lib/cem/validate.js @@ -1,21 +1,11 @@ const fs = require('fs'); const Ajv = require('ajv'); const path = require('path'); + // Load your JSON schema -const extenalSchema = require('./schema.json'); +const externalSchema = require('./schema.json'); const internalSchema = require('./schema-internal.json'); -// Load your JSON data from the input file -const inputFilePath = path.join(process.cwd(), "dist/custom-elements.json"); // Update with your file path -const customManifest = fs.readFileSync(inputFilePath, 'utf8'); -const inputDataInternal = JSON.parse(customManifest); -const devMode = process.env.UI5_CEM_MODE === "dev"; - -inputDataInternal.modules.forEach(moduleDoc => { - moduleDoc.exports = moduleDoc.exports. - filter(e => moduleDoc.declarations.find(d => d.name === e.declaration.name && ["class", "function", "variable", "enum"].includes(d.kind)) || e.name === "default"); -}) - const clearProps = (data) => { if (Array.isArray(data)) { for (let i = 0; i < data.length; i++) { @@ -39,29 +29,82 @@ const clearProps = (data) => { } return data; -} +}; + +const filterExports = (moduleDoc) => { + moduleDoc.exports = moduleDoc.exports + .filter(e => moduleDoc.declarations.find(d => d.name === e.declaration.name && ["class", "function", "variable", "enum"].includes(d.kind)) || e.name === "default"); +}; + +const validateCEM = (options = {}) => { + const { + inputFilePath = path.join(process.cwd(), "dist/custom-elements.json"), + devMode = "", + writeFiles = true, + silent = false + } = options; + + // Load your JSON data from the input file + const customManifest = fs.readFileSync(inputFilePath, 'utf8'); + const inputDataInternal = JSON.parse(customManifest); + + // Filter exports + inputDataInternal.modules.forEach(filterExports); + + const ajv = new Ajv({ allowUnionTypes: true, allError: true }); + let validate = ajv.compile(internalSchema); -const ajv = new Ajv({ allowUnionTypes: true, allError: true }) -let validate = ajv.compile(internalSchema) + // Validate the JSON data against the internal schema + if (devMode) { + if (validate(inputDataInternal)) { + !silent && console.log('Internal custom element manifest is validated successfully'); + } else { + console.log(validate.errors); + throw new Error(`Validation of internal custom elements manifest failed: ${validate.errors}`); + } + } + + // Create external data by clearing internal properties + const inputDataExternal = clearProps(JSON.parse(JSON.stringify(inputDataInternal))); + validate = ajv.compile(externalSchema); -// Validate the JSON data against the schema -if (devMode) { - if (validate(inputDataInternal)) { - console.log('Internal custom element manifest is validated successfully'); + // Validate the JSON data against the external schema + if (validate(inputDataExternal)) { + !silent && console.log('Custom element manifest is validated successfully'); + + if (writeFiles) { + fs.writeFileSync(inputFilePath, JSON.stringify(inputDataExternal, null, 2), 'utf8'); + fs.writeFileSync(inputFilePath.replace("custom-elements", "custom-elements-internal"), JSON.stringify(inputDataInternal, null, 2), 'utf8'); + } + + return { + external: inputDataExternal, + internal: inputDataInternal, + valid: true + }; + } else if (devMode) { + throw new Error(`Validation of public custom elements manifest failed: ${validate.errors}`); } else { - console.log(validate.errors) - throw new Error(`Validation of internal custom elements manifest failed: ${validate.errors}`); + return { + external: inputDataExternal, + internal: inputDataInternal, + valid: false, + errors: validate.errors + }; } -} +}; -const inputDataExternal = clearProps(JSON.parse(JSON.stringify(inputDataInternal))); -validate = ajv.compile(extenalSchema) +// If this file is run directly (not required as a module) +if (require.main === module) { + try { + validateCEM(); + } catch (error) { + console.error('Validation failed:', error.message); + process.exit(1); + } +} -// Validate the JSON data against the schema -if (validate(inputDataExternal)) { - console.log('Custom element manifest is validated successfully'); - fs.writeFileSync(inputFilePath, JSON.stringify(inputDataExternal, null, 2), 'utf8'); - fs.writeFileSync(inputFilePath.replace("custom-elements", "custom-elements-internal"), JSON.stringify(inputDataInternal, null, 2), 'utf8'); -} else if (devMode) { - throw new Error(`Validation of public custom elements manifest failed: ${validate.errors}`); -} \ No newline at end of file +module.exports = validateCEM; +module.exports.validateCEM = validateCEM; +module.exports.clearProps = clearProps; +module.exports.filterExports = filterExports; \ No newline at end of file diff --git a/packages/tools/lib/copy-and-watch/index.js b/packages/tools/lib/copy-and-watch/index.js index ae974f511b95..6d7f53d5081c 100644 --- a/packages/tools/lib/copy-and-watch/index.js +++ b/packages/tools/lib/copy-and-watch/index.js @@ -30,38 +30,14 @@ const globParent = require('glob-parent'); /* CODE */ -const args = process.argv.slice(2); -const options = {}; - -['watch', 'clean', 'skip-initial-copy', 'safe', 'silent'].forEach(key => { - const index = args.indexOf(`--${key}`); - if (index >= 0) { - options[key] = true; - args.splice(index, 1); - } -}); - -if (args.length < 2) { - console.error('Not enough arguments: copy-and-watch [options] '.red); - process.exit(1); -} - -if (options['skip-initial-copy'] && !options['watch']) { - console.error('--skip-initial-copy argument is meant to be used with --watch, otherwise no files will be copied'.red); - process.exit(1); -} - -const target = args.pop(); -const sources = args; -const parents = [...new Set(sources.map(globParent))]; - -const findTarget = from => { +const findTarget = (from, parents, target) => { const parent = parents .filter(p => from.indexOf(p) >= 0) .sort() .reverse()[0]; return path.join(target, path.relative(parent, from)); }; + const createDirIfNotExist = to => { 'use strict'; @@ -79,21 +55,26 @@ const createDirIfNotExist = to => { } }); }; -const copy = from => { - const to = findTarget(from); + +const copy = (from, parents, target, silent = false) => { + const to = findTarget(from, parents, target); createDirIfNotExist(to); const stats = fs.statSync(from); if (stats.isDirectory()) { return; } fs.writeFileSync(to, fs.readFileSync(from)); - options.silent || console.log('[COPY]'.yellow, from, 'to'.yellow, to); + silent || console.log('[COPY]'.yellow, from, 'to'.yellow, to); }; -const remove = from => { - const to = findTarget(from); - fs.unlinkSync(to); - options.silent || console.log('[DELETE]'.yellow, to); + +const remove = (from, parents, target, silent = false) => { + const to = findTarget(from, parents, target); + if (fs.existsSync(to)) { + fs.unlinkSync(to); + silent || console.log('[DELETE]'.yellow, to); + } }; + const rimraf = dir => { if (fs.existsSync(dir)) { fs.readdirSync(dir).forEach(entry => { @@ -108,38 +89,117 @@ const rimraf = dir => { } }; -// clean -if (options.clean) { - rimraf(target); -} +const copyAndWatch = (sources, target, options = {}) => { + const { + watch = false, + clean = false, + skipInitialCopy = false, + safe = false, + silent = false + } = options; + + if (!sources || !target) { + throw new Error('Sources and target are required'); + } -// initial copy -if (!options['skip-initial-copy']) { - sources.forEach(s => glob.sync(s).forEach(copy)); -} + const sourceArray = Array.isArray(sources) ? sources : [sources]; + const parents = [...new Set(sourceArray.map(globParent))]; -// watch -if (options.watch) { - const chokidarOptions = { - ignoreInitial: true - }; + // clean + if (clean) { + rimraf(target); + } + + // initial copy + if (!skipInitialCopy) { + sourceArray.forEach(s => glob.sync(s).forEach(file => copy(file, parents, target, silent))); + } - if (options.safe) { - chokidarOptions.awaitWriteFinish = { - stabilityThreshold: 500, - pollInterval: 100 + // watch + if (watch) { + const chokidarOptions = { + ignoreInitial: true }; + + if (safe) { + chokidarOptions.awaitWriteFinish = { + stabilityThreshold: 500, + pollInterval: 100 + }; + } + + const watcher = chokidar + .watch(sourceArray, chokidarOptions) + .on('ready', () => sourceArray.forEach(s => { + silent || console.log('[WATCH]'.yellow, s); + })) + .on('add', file => copy(file, parents, target, silent)) + .on('addDir', file => copy(file, parents, target, silent)) + .on('change', file => copy(file, parents, target, silent)) + .on('unlink', file => remove(file, parents, target, silent)) + .on('unlinkDir', file => remove(file, parents, target, silent)) + .on('error', e => console.log('[ERROR]'.red, e)); + + return watcher; } - chokidar - .watch(sources, chokidarOptions) - .on('ready', () => sources.forEach(s => { - options.silent || console.log('[WATCH]'.yellow, s); - })) - .on('add', copy) - .on('addDir', copy) - .on('change', copy) - .on('unlink', remove) - .on('unlinkDir', remove) - .on('error', e => console.log('[ERROR]'.red, e)); + return null; +}; + +// If this file is run directly (not required as a module) +if (require.main === module) { + const args = process.argv.slice(2); + const options = {}; + + ['watch', 'clean', 'skip-initial-copy', 'safe', 'silent'].forEach(key => { + const index = args.indexOf(`--${key}`); + if (index >= 0) { + options[key] = true; + args.splice(index, 1); + } + }); + + if (args.length < 2) { + console.error('Not enough arguments: copy-and-watch [options] '.red); + process.exit(1); + } + + if (options['skip-initial-copy'] && !options['watch']) { + console.error('--skip-initial-copy argument is meant to be used with --watch, otherwise no files will be copied'.red); + process.exit(1); + } + + const target = args.pop(); + const sources = args; + + const cliOptions = { + watch: options.watch, + clean: options.clean, + skipInitialCopy: options['skip-initial-copy'], + safe: options.safe, + silent: options.silent + }; + + try { + const watcher = copyAndWatch(sources, target, cliOptions); + if (watcher) { + // Keep the process alive when watching + process.on('SIGINT', () => { + console.log('\nStopping watcher...'); + watcher.close(); + process.exit(0); + }); + } + } catch (error) { + console.error('Error:', error.message); + process.exit(1); + } } + +module.exports = copyAndWatch; +module.exports.copyAndWatch = copyAndWatch; +module.exports.rimraf = rimraf; +module.exports.copy = copy; +module.exports.remove = remove; +module.exports.createDirIfNotExist = createDirIfNotExist; +module.exports.findTarget = findTarget; diff --git a/packages/tools/lib/copy-list/index.js b/packages/tools/lib/copy-list/index.js index b999c7b749c0..2b693ddab1ba 100644 --- a/packages/tools/lib/copy-list/index.js +++ b/packages/tools/lib/copy-list/index.js @@ -1,11 +1,9 @@ const fs = require("fs").promises; const path = require("path"); -const fileList = process.argv[2]; -const dest = process.argv[3]; const src = "@openui5/sap.ui.core/src/"; -const generate = async () => { +const generate = async (fileList, dest) => { const filesToCopy = (await fs.readFile(fileList)).toString(); // console.log(filesToCopy); @@ -15,7 +13,7 @@ const generate = async () => { const trimFile = file => file.trim(); return filesToCopy.split("\n").map(trimFile).filter(shouldCopy).map(async moduleName => { - const srcPath = require.resolve(path.join(src, moduleName), {paths: [process.cwd()]}); + const srcPath = require.resolve(path.join(src, moduleName), { paths: [process.cwd()] }); const destPath = path.join(dest, moduleName); await fs.mkdir(path.dirname(destPath), { recursive: true }); @@ -23,6 +21,8 @@ const generate = async () => { }); }; -generate().then(() => { - console.log("Files copied."); -}); +// generate().then(() => { +// console.log("Files copied."); +// }); + +module.exports = generate; diff --git a/packages/tools/lib/create-icons/index.js b/packages/tools/lib/create-icons/index.js index a51bc5a6f429..19e2e501e220 100644 --- a/packages/tools/lib/create-icons/index.js +++ b/packages/tools/lib/create-icons/index.js @@ -1,12 +1,11 @@ const fs = require("fs").promises; const path = require("path"); -const collectionName = process.argv[2] || "SAP-icons-v4"; -const collectionVersion = process.argv[3]; -const srcFile = collectionVersion ? path.normalize(`src/${collectionVersion}/${collectionName}.json`) : path.normalize(`src/${collectionName}.json`); -const destDir = collectionVersion ? path.normalize(`dist/${collectionVersion}/`) : path.normalize("dist/"); +const generate = async (collectionName, collectionVersion) => { + const srcFile = collectionVersion ? path.normalize(`src/${collectionVersion}/${collectionName}.json`) : path.normalize(`src/${collectionName}.json`); + const destDir = collectionVersion ? path.normalize(`dist/${collectionVersion}/`) : path.normalize("dist/"); -const iconTemplate = (name, pathData, ltr, collection, packageName) => `import { registerIcon } from "@ui5/webcomponents-base/dist/asset-registries/Icons.js"; + const iconTemplate = (name, pathData, ltr, collection, packageName) => `import { registerIcon } from "@ui5/webcomponents-base/dist/asset-registries/Icons.js"; const name = "${name}"; const pathData = "${pathData}"; @@ -21,7 +20,7 @@ export default "${collection}/${name}"; export { pathData, ltr, accData };`; -const iconAccTemplate = (name, pathData, ltr, accData, collection, packageName, versioned) => `import { registerIcon } from "@ui5/webcomponents-base/dist/asset-registries/Icons.js"; + const iconAccTemplate = (name, pathData, ltr, accData, collection, packageName, versioned) => `import { registerIcon } from "@ui5/webcomponents-base/dist/asset-registries/Icons.js"; import { ${accData.key} } from "${versioned ? "../" : "./"}generated/i18n/i18n-defaults.js"; const name = "${name}"; @@ -38,7 +37,7 @@ export { pathData, ltr, accData };`; -const collectionTemplate = (name, versions, fullName) => `import { isLegacyThemeFamilyAsync } from "@ui5/webcomponents-base/dist/config/Theme.js"; + const collectionTemplate = (name, versions, fullName) => `import { isLegacyThemeFamilyAsync } from "@ui5/webcomponents-base/dist/config/Theme.js"; import { pathData as pathData${versions[0]}, ltr, accData } from "./${versions[0]}/${name}.js"; import { pathData as pathData${versions[1]} } from "./${versions[1]}/${name}.js"; @@ -50,7 +49,7 @@ export default "${fullName}"; export { getPathData, ltr, accData };`; -const typeDefinitionTemplate = (name, accData, collection) => `declare const pathData: string; + const typeDefinitionTemplate = (name, accData, collection) => `declare const pathData: string; declare const ltr: boolean; declare const accData: ${accData ? '{ key: string; defaultText: string; }' : null} declare const _default: "${collection}/${name}"; @@ -58,7 +57,7 @@ declare const _default: "${collection}/${name}"; export default _default; export { pathData, ltr, accData };` -const collectionTypeDefinitionTemplate = (name, accData) => `declare const getPathData: () => Promise; + const collectionTypeDefinitionTemplate = (name, accData) => `declare const getPathData: () => Promise; declare const ltr: boolean; declare const accData: ${accData ? '{ key: string; defaultText: string; }' : null} declare const _default: "${name}"; @@ -67,61 +66,66 @@ export default _default; export { getPathData, ltr, accData };` -const svgTemplate = (pathData) => ` + const svgTemplate = (pathData) => ` `; -const createIcons = async (file) => { - await fs.mkdir(destDir, { recursive: true }); - - const json = JSON.parse(await fs.readFile(file)); - - const promises = []; - for (let name in json.data) { - const iconData = json.data[name]; - const pathData = iconData.path; - const ltr = !!iconData.ltr; - const acc = iconData.acc; - const packageName = json.packageName; - const collection = json.collection; - const versioned = json.version; - - const content = acc ? iconAccTemplate(name, pathData, ltr, acc, collection, packageName, versioned) : iconTemplate(name, pathData, ltr, collection, packageName); - - promises.push(fs.writeFile(path.join(destDir, `${name}.js`), content)); - promises.push(fs.writeFile(path.join(destDir, `${name}.svg`), svgTemplate(pathData))); - promises.push(fs.writeFile(path.join(destDir, `${name}.d.ts`), typeDefinitionTemplate(name, acc, collection))); - - // For versioned icons collections, the script creates top level (unversioned) module that internally imports the versioned ones. - // For example, the top level "@ui5/ui5-webcomponents-icons/dist/accept.js" imports: - // - "@ui5/ui5-webcomponents-icons/dist/v5/accept.js" - // - "@ui5/ui5-webcomponents-icons/dist/v4/accept.js" - - if (versioned) { - // The exported value from the top level (unversioned) icon module depends on whether the collection is the default, - // to add or not the collection name to the exported value: - // For the default collection (SAPIcons) we export just the icon name - "export default { 'accept' }" - // For non-default collections (SAPTNTIcons and SAPBSIcons) we export the full name - "export default { 'tnt/actor' }" - const effectiveName = isDefaultCollection(collection) ? name : getUnversionedFullIconName(name, collection); - promises.push(fs.writeFile(path.join(path.normalize("dist/"), `${name}.js`), collectionTemplate(name, json.versions, effectiveName))); - promises.push(fs.writeFile(path.join(path.normalize("dist/"), `${name}.d.ts`), collectionTypeDefinitionTemplate(effectiveName, acc))); + const createIcons = async (file) => { + await fs.mkdir(destDir, { recursive: true }); + + const json = JSON.parse(await fs.readFile(file)); + + const promises = []; + for (let name in json.data) { + const iconData = json.data[name]; + const pathData = iconData.path; + const ltr = !!iconData.ltr; + const acc = iconData.acc; + const packageName = json.packageName; + const collection = json.collection; + const versioned = json.version; + + const content = acc ? iconAccTemplate(name, pathData, ltr, acc, collection, packageName, versioned) : iconTemplate(name, pathData, ltr, collection, packageName); + + promises.push(fs.writeFile(path.join(destDir, `${name}.js`), content)); + promises.push(fs.writeFile(path.join(destDir, `${name}.svg`), svgTemplate(pathData))); + promises.push(fs.writeFile(path.join(destDir, `${name}.d.ts`), typeDefinitionTemplate(name, acc, collection))); + + // For versioned icons collections, the script creates top level (unversioned) module that internally imports the versioned ones. + // For example, the top level "@ui5/ui5-webcomponents-icons/dist/accept.js" imports: + // - "@ui5/ui5-webcomponents-icons/dist/v5/accept.js" + // - "@ui5/ui5-webcomponents-icons/dist/v4/accept.js" + + if (versioned) { + // The exported value from the top level (unversioned) icon module depends on whether the collection is the default, + // to add or not the collection name to the exported value: + // For the default collection (SAPIcons) we export just the icon name - "export default { 'accept' }" + // For non-default collections (SAPTNTIcons and SAPBSIcons) we export the full name - "export default { 'tnt/actor' }" + const effectiveName = isDefaultCollection(collection) ? name : getUnversionedFullIconName(name, collection); + promises.push(fs.writeFile(path.join(path.normalize("dist/"), `${name}.js`), collectionTemplate(name, json.versions, effectiveName))); + promises.push(fs.writeFile(path.join(path.normalize("dist/"), `${name}.d.ts`), collectionTypeDefinitionTemplate(effectiveName, acc))); + } } - } - return Promise.all(promises); -}; + return Promise.all(promises); + }; -const isDefaultCollection = collectionName => collectionName === "SAP-icons-v4" || collectionName === "SAP-icons-v5"; -const getUnversionedFullIconName = (name, collection) => `${getUnversionedCollectionName(collection)}/${name}`; -const getUnversionedCollectionName = collectionName => CollectionVersionedToUnversionedMap[collectionName] || collectionName; + const isDefaultCollection = collectionName => collectionName === "SAP-icons-v4" || collectionName === "SAP-icons-v5"; + const getUnversionedFullIconName = (name, collection) => `${getUnversionedCollectionName(collection)}/${name}`; + const getUnversionedCollectionName = collectionName => CollectionVersionedToUnversionedMap[collectionName] || collectionName; -const CollectionVersionedToUnversionedMap = { - "tnt-v2": "tnt", - "tnt-v3": "tnt", - "business-suite-v1": "business-suite", - "business-suite-v2": "business-suite", -}; + const CollectionVersionedToUnversionedMap = { + "tnt-v2": "tnt", + "tnt-v3": "tnt", + "business-suite-v1": "business-suite", + "business-suite-v2": "business-suite", + }; + + await createIcons(srcFile) +} + +// generate.then(() => { +// console.log("Icons created."); +// }); -createIcons(srcFile).then(() => { - console.log("Icons created."); -}); +module.exports = generate; \ No newline at end of file diff --git a/packages/tools/lib/create-illustrations/index.js b/packages/tools/lib/create-illustrations/index.js index e15bbfe1487a..6ad6d2404ed6 100644 --- a/packages/tools/lib/create-illustrations/index.js +++ b/packages/tools/lib/create-illustrations/index.js @@ -1,11 +1,12 @@ const fs = require("fs").promises; const path = require("path"); -if (process.argv.length < 7) { - throw new Error("Not enough arguments"); -} - -const generate = async () => { +const generate = async (srcPath, + defaultText, + illustrationsPrefix, + illustrationSet, + destPath, + collection) => { const ORIGINAL_TEXTS = { UnableToLoad: "UnableToLoad", @@ -70,12 +71,6 @@ const generate = async () => { SuccessHighFive: ORIGINAL_TEXTS.BalloonSky }; - const srcPath = process.argv[2]; - const defaultText = process.argv[3] === "true"; - const illustrationsPrefix = process.argv[4]; - const illustrationSet = process.argv[5]; - const destPath = process.argv[6]; - const collection = process.argv[7]; const fileNamePattern = new RegExp(`${illustrationsPrefix}-.+-(.+).svg`); // collect each illustration name because each one should have Sample.js file const fileNames = new Set(); @@ -126,8 +121,7 @@ const generate = async () => { import dialogSvg from "./${illustrationsPrefix}-Dialog-${illustrationName}.js"; import sceneSvg from "./${illustrationsPrefix}-Scene-${illustrationName}.js"; import spotSvg from "./${illustrationsPrefix}-Spot-${illustrationName}.js"; -import dotSvg from "./${illustrationsPrefix}-${hasDot}-${illustrationName}.js";${ - defaultText ? `import { +import dotSvg from "./${illustrationsPrefix}-${hasDot}-${illustrationName}.js";${defaultText ? `import { IM_TITLE_${illustrationNameUpperCase}, IM_SUBTITLE_${illustrationNameUpperCase}, } from "../generated/i18n/i18n-defaults.js";` : ``} @@ -195,6 +189,8 @@ export { dialogSvg, sceneSvg, spotSvg, dotSvg };` }); }; -generate().then(() => { - console.log("Illustrations generated."); -}); +// generate().then(() => { +// console.log("Illustrations generated."); +// }); + +module.exports = generate; \ No newline at end of file diff --git a/packages/tools/lib/css-processors/css-processor-components.mjs b/packages/tools/lib/css-processors/css-processor-components.mjs index 8ec38052dff5..f846bdd6a868 100644 --- a/packages/tools/lib/css-processors/css-processor-components.mjs +++ b/packages/tools/lib/css-processors/css-processor-components.mjs @@ -7,36 +7,38 @@ import chokidar from "chokidar"; import scopeVariables from "./scope-variables.mjs"; import { writeFileIfChanged, getFileContent } from "./shared.mjs"; -const tsMode = process.env.UI5_TS === "true"; -const extension = tsMode ? ".css.ts" : ".css.js"; +const createCustomPlugin = (packageJSON, tsMode = false) => { + const extension = tsMode ? ".css.ts" : ".css.js"; -const packageJSON = JSON.parse(fs.readFileSync("./package.json")) -const inputFilesGlob = "src/themes/*.css"; -const restArgs = process.argv.slice(2); + return { + name: 'ui5-tools', + setup(build) { + build.initialOptions.write = false; -let customPlugin = { - name: 'ui5-tools', - setup(build) { - build.initialOptions.write = false; + build.onEnd(async (result) => { + const fileProcessingPromises = result.outputFiles.map(async (f) => { + // scoping + let newText = scopeVariables(f.text, packageJSON); + newText = newText.replaceAll(/\\/g, "\\\\"); // Escape backslashes as they might appear in css rules + await mkdir(path.dirname(f.path), { recursive: true }); - build.onEnd(result => { - result.outputFiles.forEach(async f => { - // scoping - let newText = scopeVariables(f.text, packageJSON); - newText = newText.replaceAll(/\\/g, "\\\\"); // Escape backslashes as they might appear in css rules - await mkdir(path.dirname(f.path), {recursive: true}); - writeFile(f.path, newText); + // JS/TS + const jsPath = f.path.replace(/dist[\/\\]css/, "src/generated/").replace(".css", extension); + const jsContent = getFileContent(packageJSON.name, "\`" + newText + "\`", true); - // JS/TS - const jsPath = f.path.replace(/dist[\/\\]css/, "src/generated/").replace(".css", extension); - const jsContent = getFileContent(packageJSON.name, "\`" + newText + "\`", true); - writeFileIfChanged(jsPath, jsContent); - }); - }) - }, -} + Promise.all([ + await writeFile(f.path, newText), + await writeFileIfChanged(jsPath, jsContent), + ]) + }); + + await Promise.all(fileProcessingPromises); + }) + }, + }; +}; -const getConfig = async () => { +const getConfig = async (inputFilesGlob, packageJSON, tsMode) => { const config = { entryPoints: await globby(inputFilesGlob), bundle: true, @@ -44,35 +46,68 @@ const getConfig = async () => { outdir: 'dist/css', outbase: 'src', plugins: [ - customPlugin, + createCustomPlugin(packageJSON, tsMode), ] }; return config; -} +}; + +const processComponents = async (options = {}) => { + const { + watch = false, + packagePath = "./package.json", + inputFilesGlob = "src/themes/*.css", + outdir = 'dist/css', + outbase = 'src', + tsMode = false + } = options; -if (restArgs.includes("-w")) { - let ready; - let config = await getConfig(); - let ctx = await esbuild.context(config); - await ctx.watch() - console.log('watching...') + const packageJSON = JSON.parse(fs.readFileSync(packagePath)); - // when new component css files are added, they do not trigger a build as no one directly imports them - // restart the watch mode with the new entry points if a css file is added. - const watcher = chokidar.watch(inputFilesGlob); - watcher.on("ready", () => { - ready = true; // Initial scan is over -> waiting for new files - }); - watcher.on("add", async path => { - if (ready) { - // new file - ctx.dispose(); - config = await getConfig(); - ctx = await esbuild.context(config); - ctx.watch(); - } - }); -} else { - const config = await getConfig(); - const result = await esbuild.build(config); + if (watch) { + let ready; + let config = await getConfig(inputFilesGlob, packageJSON, tsMode); + let ctx = await esbuild.context(config); + await ctx.watch(); + console.log('watching...'); + + // when new component css files are added, they do not trigger a build as no one directly imports them + // restart the watch mode with the new entry points if a css file is added. + const watcher = chokidar.watch(inputFilesGlob); + watcher.on("ready", () => { + ready = true; // Initial scan is over -> waiting for new files + }); + watcher.on("add", async path => { + if (ready) { + // new file + ctx.dispose(); + config = await getConfig(inputFilesGlob, packageJSON, tsMode); + ctx = await esbuild.context(config); + ctx.watch(); + } + }); + + return { ctx, watcher }; + } else { + const config = await getConfig(inputFilesGlob, packageJSON, tsMode); + const result = await esbuild.build(config); + return result; + } +}; + +// If this file is run directly (not imported as a module) +if (import.meta.url === `file://${process.argv[1]}`) { + const restArgs = process.argv.slice(2); + const watchMode = restArgs.includes("-w"); + + processComponents({ watch: watchMode }) + .then(() => { + if (!watchMode) { + console.log('Component processing completed.'); + } + }) + .catch(console.error); } + +export default processComponents; +export { processComponents, createCustomPlugin, getConfig }; diff --git a/packages/tools/lib/css-processors/css-processor-themes.mjs b/packages/tools/lib/css-processors/css-processor-themes.mjs index 927552c5ee65..50ba5b6d6c1f 100644 --- a/packages/tools/lib/css-processors/css-processor-themes.mjs +++ b/packages/tools/lib/css-processors/css-processor-themes.mjs @@ -8,16 +8,6 @@ import combineDuplicatedSelectors from "../postcss-combine-duplicated-selectors/ import { writeFileIfChanged, getFileContent } from "./shared.mjs"; import scopeVariables from "./scope-variables.mjs"; -const tsMode = process.env.UI5_TS === "true"; -const extension = tsMode ? ".css.ts" : ".css.js"; - -const packageJSON = JSON.parse(fs.readFileSync("./package.json")) - -const inputFiles = await globby([ - "src/**/parameters-bundle.css", -]); -const restArgs = process.argv.slice(2); - const processThemingPackageFile = async (f) => { const selector = ':root'; const result = await postcss().process(f.text); @@ -35,54 +25,99 @@ const processThemingPackageFile = async (f) => { return newRule.toString(); }; -const processComponentPackageFile = async (f) => { +const processComponentPackageFile = async (f, packageJSON) => { const result = await postcss(combineDuplicatedSelectors).process(f.text); return scopeVariables(result.css, packageJSON, f.path); } -let scopingPlugin = { - name: 'scoping', - setup(build) { - build.initialOptions.write = false; - - build.onEnd(result => { - result.outputFiles.forEach(async f => { - let newText = f.path.includes("packages/theming") ? await processThemingPackageFile(f) : await processComponentPackageFile(f); +const createScopingPlugin = (packageJSON, tsMode = false) => { + const extension = tsMode ? ".css.ts" : ".css.js"; + + return { + name: 'scoping', + setup(build) { + build.initialOptions.write = false; + + build.onEnd(async (result) => { + const fileProcessingPromises = result.outputFiles.map(async (f) => { + let newText = f.path.includes("packages/theming") ? await processThemingPackageFile(f) : await processComponentPackageFile(f, packageJSON); + + // JSON + const jsonPath = f.path.replace(/dist[\/\\]css/, "dist/generated/assets").replace(".css", ".css.json"); + await writeFileIfChanged(jsonPath, JSON.stringify(newText)); + + // JS/TS + const jsPath = f.path.replace(/dist[\/\\]css/, "src/generated/").replace(".css", extension); + const jsContent = getFileContent(packageJSON.name, "\`" + newText + "\`"); + + await Promise.all([ + await mkdir(path.dirname(f.path), { recursive: true }), + await mkdir(path.dirname(jsonPath), { recursive: true }) + ]); + + await Promise.all([ + await writeFile(f.path, newText), + await writeFileIfChanged(jsonPath, JSON.stringify(newText)), + await writeFileIfChanged(jsPath, jsContent), + ]) + }); + + await Promise.all(fileProcessingPromises); + }) + }, + }; +}; - await mkdir(path.dirname(f.path), { recursive: true }); - writeFile(f.path, newText); +const processThemes = async (options = {}) => { + const { + watch = false, + packagePath = "./package.json", + inputPattern = "src/**/parameters-bundle.css", + outdir = 'dist/css', + outbase = 'src', + tsMode = false, + } = options; + + const packageJSON = JSON.parse(fs.readFileSync(packagePath)); + const inputFiles = await globby([inputPattern]); + + const config = { + entryPoints: inputFiles, + bundle: true, + minify: true, + outdir, + outbase, + plugins: [ + createScopingPlugin(packageJSON, tsMode), + ], + external: ["*.ttf", "*.woff", "*.woff2"], + }; + + if (watch) { + let ctx = await esbuild.context(config); + await ctx.watch(); + console.log('watching...'); + return ctx; + } else { + const result = await esbuild.build(config); + return result; + } +}; - // JSON - const jsonPath = f.path.replace(/dist[\/\\]css/, "dist/generated/assets").replace(".css", ".css.json"); - await mkdir(path.dirname(jsonPath), { recursive: true }); - writeFileIfChanged(jsonPath, JSON.stringify(newText)); +// If this file is run directly (not imported as a module) +if (import.meta.url === `file://${process.argv[1]}`) { + const restArgs = process.argv.slice(2); + const watchMode = restArgs.includes("-w"); - // JS/TS - const jsPath = f.path.replace(/dist[\/\\]css/, "src/generated/").replace(".css", extension); - const jsContent = getFileContent(packageJSON.name, "\`" + newText + "\`"); - writeFileIfChanged(jsPath, jsContent); - }); + processThemes({ watch: watchMode }) + .then(() => { + if (!watchMode) { + console.log('Theme processing completed.'); + } }) - }, + .catch(console.error); } -const config = { - entryPoints: inputFiles, - bundle: true, - minify: true, - outdir: 'dist/css', - outbase: 'src', - plugins: [ - scopingPlugin, - ], - external: ["*.ttf", "*.woff", "*.woff2"], -}; - -if (restArgs.includes("-w")) { - let ctx = await esbuild.context(config); - await ctx.watch() - console.log('watching...') -} else { - const result = await esbuild.build(config); -} \ No newline at end of file +export default processThemes; +export { processThemes, createScopingPlugin, processThemingPackageFile, processComponentPackageFile }; \ No newline at end of file diff --git a/packages/tools/lib/generate-js-imports/illustrations.js b/packages/tools/lib/generate-js-imports/illustrations.js index d977e40aaab6..e4db52c4af01 100644 --- a/packages/tools/lib/generate-js-imports/illustrations.js +++ b/packages/tools/lib/generate-js-imports/illustrations.js @@ -2,27 +2,27 @@ const fs = require("fs").promises; const path = require("path"); const generateDynamicImportLines = async (fileNames, location, exclusionPatterns = []) => { - const packageName = JSON.parse(await fs.readFile("package.json")).name; - return fileNames - .filter((fileName) => !exclusionPatterns.some((pattern) => fileName.startsWith(pattern))) - .map((fileName) => { - const illustrationName = fileName.replace(".js", ""); - const illustrationPath = `${location}/${illustrationName}`; - return `\t\tcase "${fileName.replace('.js', '')}": return (await import(/* webpackChunkName: "${packageName.replace("@", "").replace("/", "-")}-${illustrationName.toLowerCase()}" */ "${illustrationPath}.js")).default;`; - }) - .join("\n"); + const packageName = JSON.parse(await fs.readFile("package.json")).name; + return fileNames + .filter((fileName) => !exclusionPatterns.some((pattern) => fileName.startsWith(pattern))) + .map((fileName) => { + const illustrationName = fileName.replace(".js", ""); + const illustrationPath = `${location}/${illustrationName}`; + return `\t\tcase "${fileName.replace('.js', '')}": return (await import(/* webpackChunkName: "${packageName.replace("@", "").replace("/", "-")}-${illustrationName.toLowerCase()}" */ "${illustrationPath}.js")).default;`; + }) + .join("\n"); }; const generateAvailableIllustrationsArray = (fileNames, exclusionPatterns = []) => { - return JSON.stringify( - fileNames - .filter((fileName) => !exclusionPatterns.some((pattern) => fileName.startsWith(pattern))) - .map((fileName) => fileName.replace(".js", "")) - ); + return JSON.stringify( + fileNames + .filter((fileName) => !exclusionPatterns.some((pattern) => fileName.startsWith(pattern))) + .map((fileName) => fileName.replace(".js", "")) + ); }; const generateDynamicImportsFileContent = (dynamicImports, availableIllustrations, collection, set, prefix = "") => { - return `// @ts-nocheck + return `// @ts-nocheck import { registerIllustrationLoader } from "@ui5/webcomponents-base/dist/asset-registries/Illustrations.js"; export const loadIllustration = async (illustrationName) => { @@ -47,40 +47,36 @@ ${availableIllustrations}.forEach((illustrationName) => }; const getMatchingFiles = async (folder, pattern) => { - const dir = await fs.readdir(folder); - return dir.filter((fileName) => fileName.match(pattern)); + const dir = await fs.readdir(folder); + return dir.filter((fileName) => fileName.match(pattern)); }; -const generateIllustrations = async (config) => { - const { inputFolder, outputFile, collection, location, prefix, filterOut, set } = config; +const generateIllustrations = async (inputFolder, + outputFile, + set, + collection, + location, + filterOut) => { - const normalizedInputFolder = path.normalize(inputFolder); - const normalizedOutputFile = path.normalize(outputFile); + const normalizedInputFolder = path.normalize(inputFolder); + const normalizedOutputFile = path.normalize(outputFile); - const illustrations = await getMatchingFiles(normalizedInputFolder, /^.*\.js$/); + const illustrations = await getMatchingFiles(normalizedInputFolder, /^.*\.js$/); - const dynamicImports = await generateDynamicImportLines(illustrations, location, filterOut); - const availableIllustrations = generateAvailableIllustrationsArray(illustrations, filterOut); + const dynamicImports = await generateDynamicImportLines(illustrations, location, filterOut); + const availableIllustrations = generateAvailableIllustrationsArray(illustrations, filterOut); - const contentDynamic = generateDynamicImportsFileContent(dynamicImports, availableIllustrations, collection, set, prefix); + const contentDynamic = generateDynamicImportsFileContent(dynamicImports, availableIllustrations, collection, set, undefined); - await fs.mkdir(path.dirname(normalizedOutputFile), { recursive: true }); - await fs.writeFile(normalizedOutputFile, contentDynamic); + await fs.mkdir(path.dirname(normalizedOutputFile), { recursive: true }); + await fs.writeFile(normalizedOutputFile, contentDynamic); - console.log(`Generated ${normalizedOutputFile}`); + console.log(`Generated ${normalizedOutputFile}`); }; -// Parse configuration from command-line arguments -const config = { - inputFolder: process.argv[2], - outputFile: process.argv[3], - set: process.argv[4], - collection: process.argv[5], - location: process.argv[6], - filterOut: process.argv.slice[7], -}; +// // Run the generation process +// generateIllustrations(config).catch((error) => { +// console.error("Error generating illustrations:", error); +// }); -// Run the generation process -generateIllustrations(config).catch((error) => { - console.error("Error generating illustrations:", error); -}); +module.exports = generateIllustrations; diff --git a/packages/tools/lib/generate-json-imports/i18n.js b/packages/tools/lib/generate-json-imports/i18n.js index 4facdd417c0a..c54c76d8b683 100644 --- a/packages/tools/lib/generate-json-imports/i18n.js +++ b/packages/tools/lib/generate-json-imports/i18n.js @@ -1,11 +1,7 @@ const fs = require("fs").promises; const path = require('path'); -const isTypeScript = process.env.UI5_TS; -const ext = isTypeScript ? 'ts' : 'js'; - - -const getContent = function(caseLines, languagesKeysStringArray, packageName) { +const getContent = function (caseLines, languagesKeysStringArray, packageName) { return `// @ts-nocheck import { registerI18nLoader } from "@ui5/webcomponents-base/dist/asset-registries/i18n.js"; @@ -27,19 +23,19 @@ const importAndCheck = async (localeId) => { const localeIds = [${languagesKeysStringArray}]; localeIds.forEach(localeId => { - registerI18nLoader(${ packageName.split("").map(c => `"${c}"`).join (" + ") }, localeId, importAndCheck); + registerI18nLoader(${packageName.split("").map(c => `"${c}"`).join(" + ")}, localeId, importAndCheck); }); `; } -const generate = async () => { - +const generate = async (inputFolder, distFolder, isTypeScript) => { + const ext = isTypeScript ? 'ts' : 'js'; const packageName = JSON.parse(await fs.readFile("package.json")).name; - const inputFolder = path.normalize(process.argv[2]); - const outputFileDynamic = path.normalize(`${process.argv[3]}/i18n.${ext}`); - const outputFileFetchMetaResolve = path.normalize(`${process.argv[3]}/i18n-fetch.${ext}`); - const outputFileDynamicImportJSONImport = path.normalize(`${process.argv[3]}/i18n-node.${ext}`); + inputFolder = path.normalize(inputFolder); + const outputFileDynamic = path.normalize(`${distFolder}/i18n.${ext}`); + const outputFileFetchMetaResolve = path.normalize(`${distFolder}/i18n-fetch.${ext}`); + const outputFileDynamicImportJSONImport = path.normalize(`${distFolder}/i18n-node.${ext}`); // All languages present in the file system const files = await fs.readdir(inputFolder); @@ -57,7 +53,7 @@ const generate = async () => { contentDynamic = ""; contentFetchMetaResolve = ""; contentDynamicImportJSONAttr = ""; - // There is i18n - generate the full file + // There is i18n - generate the full file } else { // Keys for the array const languagesKeysStringArray = languages.map(key => `"${key}",`).join("\n\t"); @@ -82,6 +78,8 @@ const generate = async () => { ]); } -generate().then(() => { - console.log("Generated i18n JSON imports."); -}); +// generate().then(() => { +// console.log("Generated i18n JSON imports."); +// }); + +module.exports = generate \ No newline at end of file diff --git a/packages/tools/lib/generate-json-imports/themes.js b/packages/tools/lib/generate-json-imports/themes.js index a3fc84f1f39a..4e1b352c7f43 100644 --- a/packages/tools/lib/generate-json-imports/themes.js +++ b/packages/tools/lib/generate-json-imports/themes.js @@ -2,14 +2,13 @@ const fs = require("fs").promises; const path = require('path'); const assets = require("../../assets-meta.js"); -const isTypeScript = process.env.UI5_TS; -const ext = isTypeScript ? 'ts' : 'js'; +const generate = async (inputFolder, distFolder, isTypeScript) => { + const ext = isTypeScript ? 'ts' : 'js'; -const generate = async () => { - const inputFolder = path.normalize(process.argv[2]); - const outputFileDynamic = path.normalize(`${process.argv[3]}/Themes.${ext}`); - const outputFileDynamicImportJSONAttr = path.normalize(`${process.argv[3]}/Themes-node.${ext}`); - const outputFileFetchMetaResolve = path.normalize(`${process.argv[3]}/Themes-fetch.${ext}`); + inputFolder = path.normalize(inputFolder); + const outputFileDynamic = path.normalize(`${distFolder}/Themes.${ext}`); + const outputFileDynamicImportJSONAttr = path.normalize(`${distFolder}/Themes-node.${ext}`); + const outputFileFetchMetaResolve = path.normalize(`${distFolder}/Themes-fetch.${ext}`); // All supported optional themes const allThemes = assets.themes.all; @@ -49,7 +48,7 @@ const loadAndCheck = async (themeName) => { }; ${availableThemesArray} - .forEach(themeName => registerThemePropertiesLoader(${ packageName.split("").map(c => `"${c}"`).join (" + ") }, themeName, loadAndCheck)); + .forEach(themeName => registerThemePropertiesLoader(${packageName.split("").map(c => `"${c}"`).join(" + ")}, themeName, loadAndCheck)); `; } @@ -61,6 +60,8 @@ ${availableThemesArray} ]); }; -generate().then(() => { - console.log("Generated themes JSON imports."); -}); +// generate().then(() => { +// console.log("Generated themes JSON imports."); +// }); + +module.exports = generate; \ No newline at end of file diff --git a/packages/tools/lib/i18n/defaults.js b/packages/tools/lib/i18n/defaults.js index dc909a12b713..122f10b40a12 100644 --- a/packages/tools/lib/i18n/defaults.js +++ b/packages/tools/lib/i18n/defaults.js @@ -3,14 +3,14 @@ const path = require('path'); const PropertiesReader = require('properties-reader'); const assets = require('../../assets-meta.js'); -const generate = async () => { +const generate = async (inputFolder, distFolder, ts) => { const defaultLanguage = assets.languages.default; - const messageBundle = path.normalize(`${process.argv[2]}/messagebundle.properties`); - const messageBundleDefaultLanguage = path.normalize(`${process.argv[2]}/messagebundle_${defaultLanguage}.properties`); - const tsMode = process.env.UI5_TS === "true"; // In Typescript mode, we output .ts files and set the required types, otherwise - output pure .js files + const messageBundle = path.normalize(`${inputFolder}/messagebundle.properties`); + const messageBundleDefaultLanguage = path.normalize(`${inputFolder}/messagebundle_${defaultLanguage}.properties`); + const tsMode = ts; // In Typescript mode, we output .ts files and set the required types, otherwise - output pure .js files - const outputFile = path.normalize(`${process.argv[3]}/i18n-defaults.${tsMode ? "ts": "js"}`); + const outputFile = path.normalize(`${distFolder}/i18n-defaults.${tsMode ? "ts": "js"}`); if (!messageBundle || !outputFile) { return; @@ -78,6 +78,8 @@ export {${textKeys.join()}};`; await fs.writeFile(outputFile, getOutputFileContent(properties, defaultLanguageProperties)); }; -generate().then(() => { - console.log("i18n default file generated."); -}); +// generate().then(() => { +// console.log("i18n default file generated."); +// }); + +module.exports = generate \ No newline at end of file diff --git a/packages/tools/lib/i18n/toJSON.js b/packages/tools/lib/i18n/toJSON.js index 80ff49856475..82deba84a590 100644 --- a/packages/tools/lib/i18n/toJSON.js +++ b/packages/tools/lib/i18n/toJSON.js @@ -14,10 +14,7 @@ const assets = require('../../assets-meta.js'); const allLanguages = assets.languages.all; -const messagesBundles = path.normalize(`${process.argv[2]}/messagebundle_*.properties`); -const messagesJSONDist = path.normalize(`${process.argv[3]}`); - -const convertToJSON = async (file) => { +const convertToJSON = async (file, messagesJSONDist) => { const properties = PropertiesReader(file)._properties; const filename = path.basename(file, path.extname(file)); const language = filename.match(/^messagebundle_(.*?)$/)[1]; @@ -31,13 +28,16 @@ const convertToJSON = async (file) => { // console.log(`[i18n]: "${filename}.json" has been generated!`); }; -const generate = async () => { +const generate = async (inputFolder, distFolder) => { const { globby } = await import("globby"); + const messagesBundles = path.normalize(`${inputFolder}/messagebundle_*.properties`); + const messagesJSONDist = path.normalize(`${distFolder}`); await fs.mkdir(messagesJSONDist, { recursive: true }); const files = await globby(messagesBundles.replace(/\\/g, "/")); - return Promise.all(files.map(convertToJSON)); + return Promise.all(files.map((file => convertToJSON(file, messagesJSONDist)))); }; -generate().then(() => { - console.log("Message bundle JSON files generated."); -}); +// generate().then(() => { +// console.log("Message bundle JSON files generated."); +// }); +module.exports = generate; diff --git a/packages/tools/lib/remove-dev-mode/remove-dev-mode.mjs b/packages/tools/lib/remove-dev-mode/remove-dev-mode.mjs index d46f2ae7360a..c3e32ce84961 100644 --- a/packages/tools/lib/remove-dev-mode/remove-dev-mode.mjs +++ b/packages/tools/lib/remove-dev-mode/remove-dev-mode.mjs @@ -2,36 +2,98 @@ import { globby } from "globby"; import * as esbuild from 'esbuild' import * as fs from "fs"; -let customPlugin = { - name: 'ui5-tools', +/** + * Creates an esbuild plugin that removes development mode code from UI5Element files + * @param {Object} options - Plugin options + * @param {RegExp} options.filter - File filter pattern (default: /UI5Element.ts$/) + * @param {string[]} options.devModeReplacements - Development mode code patterns to remove + * @returns {Object} esbuild plugin + */ +export const createDevModeRemovalPlugin = (options = {}) => { + const { + filter = /UI5Element.ts$/, + devModeReplacements = [ + { pattern: /const DEV_MODE = true/g, replacement: "" }, + { pattern: /if \(DEV_MODE\)/g, replacement: "if (false)" } + ] + } = options; + + return { + name: 'ui5-dev-mode-removal', setup(build) { - build.onLoad({ filter: /UI5Element.ts$/ }, async (args) => { - let text = await fs.promises.readFile(args.path, 'utf8'); - text = text.replaceAll(/const DEV_MODE = true/g, ""); - text = text.replaceAll(/if \(DEV_MODE\)/g, "if (false)"); - return { - contents: text, - loader: 'ts', - } - }) - }, -} - -const getConfig = async () => { - const config = { - entryPoints: await globby("src/**/*.ts"), - bundle: false, - minify: true, - sourcemap: true, - outdir: 'dist/prod', - outbase: 'src', - plugins: [ - customPlugin, - ] - }; - return config; -} - - -const config = await getConfig(); -const result = await esbuild.build(config); \ No newline at end of file + build.onLoad({ filter }, async (args) => { + let text = await fs.promises.readFile(args.path, 'utf8'); + + // Apply all dev mode replacements + for (const { pattern, replacement } of devModeReplacements) { + text = text.replaceAll(pattern, replacement); + } + + return { + contents: text, + loader: 'ts', + }; + }); + }, + }; +}; + +/** + * Creates a default esbuild configuration for removing dev mode + * @param {Object} options - Configuration options + * @param {string|string[]} options.entryPoints - Entry points glob pattern or array + * @param {string} options.outdir - Output directory + * @param {string} options.outbase - Output base directory + * @param {boolean} options.bundle - Whether to bundle files + * @param {boolean} options.minify - Whether to minify output + * @param {boolean} options.sourcemap - Whether to generate sourcemaps + * @param {Object} options.pluginOptions - Options for the dev mode removal plugin + * @returns {Promise} esbuild configuration + */ +export const createDevModeConfig = async (options = {}) => { + const { + entryPoints = "src/**/*.ts", + outdir = 'dist/prod', + outbase = 'src', + bundle = false, + minify = true, + sourcemap = true, + pluginOptions = {} + } = options; + + const resolvedEntryPoints = Array.isArray(entryPoints) + ? entryPoints + : await globby(entryPoints); + + return { + entryPoints: resolvedEntryPoints, + bundle, + minify, + sourcemap, + outdir, + outbase, + plugins: [ + createDevModeRemovalPlugin(pluginOptions), + ] + }; +}; + +/** + * Removes development mode code from TypeScript files + * @param {Object} options - Build options (same as createDevModeConfig) + * @returns {Promise} esbuild result + */ +export const removeDevMode = async (options = {}) => { + const config = await createDevModeConfig(options); + return await esbuild.build(config); +}; + +// Default export for backward compatibility +export default removeDevMode; + +// // If this file is run directly, execute with default configuration +// if (import.meta.url === `file://${process.argv[1]}`) { +// const config = await createDevModeConfig(); +// const result = await esbuild.build(config); +// console.log('Dev mode removal completed:', result); +// } \ No newline at end of file diff --git a/packages/tools/task-runner/build-runner.js b/packages/tools/task-runner/build-runner.js index 04025209ba76..a7e495e56b6f 100644 --- a/packages/tools/task-runner/build-runner.js +++ b/packages/tools/task-runner/build-runner.js @@ -1,5 +1,7 @@ const { execSync } = require('child_process'); +const times = new Map(); + function buildCrossEnvCommand(task) { if (!task.crossEnv || Object.keys(task.crossEnv).length === 0) { return task.command; @@ -13,20 +15,19 @@ function buildCrossEnvCommand(task) { } class BuildRunner { - static BUILD_RUNNER_CONSTANTS = { - PRINT: "PRINT25", - }; - constructor() { this.tasks = new Map(); this.runningTasks = new Set(); } // Register a task - addTask(name, command, options = {}) { + addTask(name, options = {}) { + const hasFunction = typeof options.callback === 'function'; + this.tasks.set(name, { - command: command === BuildRunner.BUILD_RUNNER_CONSTANTS.PRINT ? `echo "${name} command started"` : command, - cwd: process.cwd(), + callback: options.callback, + isFunction: hasFunction, + cwd: options.cwd || process.cwd(), crossEnv: { ...options.crossEnv }, env: { ...process.env, ...options.env }, parallel: options.parallel || false, @@ -40,12 +41,62 @@ class BuildRunner { let task = this.tasks.get(taskName); if (task) { - task.command = ""; + task.callback = null; + task.isFunction = false; + task.dependencies = []; this.tasks.set(taskName, task) } } + // Helper method to run either a registered task or a direct command + async runTaskOrCommand(nameOrCommand, parentEnv = {}, parentCrossEnv = {}) { + // Skip empty strings or null/undefined commands + if (!nameOrCommand || nameOrCommand.trim() === '') { + console.log('Skipping empty command'); + return Promise.resolve(); + } + + // Check if it's a registered task + if (this.tasks.has(nameOrCommand)) { + return this.runTask(nameOrCommand, parentEnv, parentCrossEnv); + } else { + // Execute as direct shell command + console.log(`Running command: ${nameOrCommand}`); + return new Promise((resolve, reject) => { + const start = Date.now() + try { + // Create a temporary task object for buildCrossEnvCommand + const tempTask = { + command: nameOrCommand, + crossEnv: parentCrossEnv + }; + + const commandToExecute = buildCrossEnvCommand(tempTask); + + const result = execSync(commandToExecute, { + cwd: process.cwd(), + env: { ...process.env, ...parentEnv }, + stdio: 'inherit' + }); + resolve(result); + } catch (error) { + reject(error); + } finally { + const end = Date.now(); + if (end - start > 150) { + times.set(nameOrCommand, `Execution time: ${(end - start) / 1000} seconds`); + } + + if (times.size > 0) { + console.log(`======= Completed command: ${nameOrCommand}`); + console.log(times); + } + } + }); + } + } + // Run a single task async runTask(taskName, parentEnv = {}, parentCrossEnv = {}) { if (this.runningTasks.has(taskName)) { @@ -55,12 +106,12 @@ class BuildRunner { let task = this.tasks.get(taskName); if (!task) { - // Only execute if it's not a registered command - create a default task - this.addTask(taskName, taskName); + // Only execute if it's not a registered command - create a default task for direct command execution + this.addTask(taskName, { dependencies: [taskName] }); task = this.tasks.get(taskName); } - if (!task.command || task.skip) { + if ((!task.callback && !task.isFunction && (!task.dependencies || task.dependencies.length === 0)) || task.skip) { return; } @@ -74,14 +125,18 @@ class BuildRunner { // Run dependencies first, passing along the merged environment for (const dep of task.dependencies) { - promises.push(this.runTask(dep, mergedEnv, mergedCrossEnv)); + if (dep && dep.trim() !== '') { // Skip empty dependencies + promises.push(this.runTaskOrCommand(dep, mergedEnv, mergedCrossEnv)); + } } await Promise.all(promises); } else { // Run dependencies first, passing along the merged environment for (const dep of task.dependencies) { - await this.runTask(dep, mergedEnv, mergedCrossEnv); + if (dep && dep.trim() !== '') { // Skip empty dependencies + await this.runTaskOrCommand(dep, mergedEnv, mergedCrossEnv); + } } } @@ -90,18 +145,32 @@ class BuildRunner { try { console.log(`Running: ${taskName}`); - return new Promise((resolve, reject) => { - try { - const result = execSync(buildCrossEnvCommand(task), { - cwd: task.cwd, - env: task.env, - stdio: 'inherit' - }); - resolve(result); - } catch (error) { - reject(error); - } - }); + if (task.isFunction) { + // Execute function directly + return new Promise(async (resolve, reject) => { + const start = Date.now() + + try { + const result = await task.callback(); + resolve(result); + } catch (error) { + reject(error); + } finally { + const end = Date.now(); + if (end - start > 150) { + times.set(taskName + start, `Execution time: ${(end - start) / 1000} seconds`); + } + + if (times.size > 0) { + console.log(`======= Completed command: ${taskName}`); + console.log(times); + } + } + }); + } else { + // If no function, the task is completed by running its dependencies + return Promise.resolve(); + } } finally { this.runningTasks.delete(taskName); } From 5aa3779a26412c76b32aea854405efae2b458b9f Mon Sep 17 00:00:00 2001 From: Nayden Naydenov Date: Fri, 29 Aug 2025 14:39:09 +0300 Subject: [PATCH 03/10] chore: restore deleted files --- packages/ai/package-scripts.cjs | 19 +++++ packages/base/package-scripts.cjs | 85 +++++++++++++++++++ packages/compat/package-scripts.cjs | 19 +++++ .../icons-business-suite/package-scripts.cjs | 16 ++++ packages/icons-tnt/package-scripts.cjs | 16 ++++ packages/icons/package-scripts.cjs | 12 +++ packages/localization/package-scripts.cjs | 28 ++++++ packages/main/package-scripts.cjs | 18 ++++ packages/theming/package-scripts.cjs | 24 ++++++ 9 files changed, 237 insertions(+) create mode 100644 packages/ai/package-scripts.cjs create mode 100644 packages/base/package-scripts.cjs create mode 100644 packages/compat/package-scripts.cjs create mode 100644 packages/icons-business-suite/package-scripts.cjs create mode 100644 packages/icons-tnt/package-scripts.cjs create mode 100644 packages/icons/package-scripts.cjs create mode 100644 packages/localization/package-scripts.cjs create mode 100644 packages/main/package-scripts.cjs create mode 100644 packages/theming/package-scripts.cjs diff --git a/packages/ai/package-scripts.cjs b/packages/ai/package-scripts.cjs new file mode 100644 index 000000000000..599362ba77b0 --- /dev/null +++ b/packages/ai/package-scripts.cjs @@ -0,0 +1,19 @@ +const getScripts = require("@ui5/webcomponents-tools/components-package/nps.js"); + +const options = { + port: 8082, + portStep: 2, + aiPackage: true, + noWatchTS: true, + dev: true, + internal: { + cypress_code_coverage: false, + cypress_acc_tests: false, + }, +}; + +const scripts = getScripts(options); + +module.exports = { + scripts, +}; diff --git a/packages/base/package-scripts.cjs b/packages/base/package-scripts.cjs new file mode 100644 index 000000000000..a2976f7ca564 --- /dev/null +++ b/packages/base/package-scripts.cjs @@ -0,0 +1,85 @@ +const resolve = require("resolve"); +const path = require("path"); + +const assetParametersScript = resolve.sync("@ui5/webcomponents-base/lib/generate-asset-parameters/index.js"); +const stylesScript = resolve.sync("@ui5/webcomponents-base/lib/generate-styles/index.js"); +const fontFaceScript = resolve.sync("@ui5/webcomponents-base/lib/css-processors/css-processor-font-face.mjs"); +const versionScript = resolve.sync("@ui5/webcomponents-base/lib/generate-version-info/index.js"); +const copyUsedModules = resolve.sync("@ui5/webcomponents-tools/lib/copy-list/index.js"); +const amdToES6 = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/index.js"); +const noRequire = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/no-remaining-require.js"); + +const LIB = path.join(__dirname, `../tools/lib/`); + +const viteConfig = `-c "${require.resolve("@ui5/webcomponents-tools/components-package/vite.config.js")}"`; + +const scripts = { + clean: "rimraf src/generated && rimraf dist && rimraf .port", + lint: `eslint .`, + generate: "cross-env UI5_TS=true nps clean build.i18n integrate copy generateAssetParameters generateVersionInfo generateStyles generateFontFace generateTemplates build.jsonImports", + prepare: "cross-env UI5_TS=true nps clean build.i18n integrate copy generateAssetParameters generateVersionInfo generateStyles generateFontFace generateTemplates typescript integrate.no-remaining-require build.jsonImports", + typescript: "tsc -b", + integrate: { + default: "nps integrate.copy-used-modules integrate.amd-to-es6 integrate.third-party", + "copy-used-modules": `node "${copyUsedModules}" ./used-modules.txt dist/`, + "amd-to-es6": `node "${amdToES6}" dist/`, + "no-remaining-require": `node "${noRequire}" dist/`, + "third-party": { + default: "nps integrate.third-party.copy integrate.third-party.fix", + copy: "mkdirp dist/sap/ui/thirdparty/ && copy-and-watch ../../node_modules/@openui5/sap.ui.core/src/sap/ui/thirdparty/caja-html-sanitizer.js dist/sap/ui/thirdparty/", + fix: "replace-in-file 240 xA0 dist/sap/ui/thirdparty/caja-html-sanitizer.js" + }, + }, + build: { + default: `nps prepare`, + bundle: `vite build ${viteConfig}`, + i18n: { + default: "nps build.i18n.defaultsjs build.i18n.json", + defaultsjs: `node "${LIB}/i18n/defaults.js" src/i18n src/generated/i18n`, + json: `node "${LIB}/i18n/toJSON.js" src/i18n dist/generated/assets/i18n`, + }, + jsonImports: { + default: "mkdirp src/generated/json-imports && nps build.jsonImports.i18n", + i18n: `node "${LIB}/generate-json-imports/i18n.js" dist/generated/assets/i18n src/generated/json-imports`, + }, + }, + copy: { + default: "nps copy.src", + src: `copy-and-watch "src/**/*.{js,css,d.ts}" dist/`, + }, + generateAssetParameters: `node "${assetParametersScript}"`, + generateVersionInfo: `node "${versionScript}"`, + generateStyles: `node "${stylesScript}"`, + generateFontFace: `node "${fontFaceScript}"`, + generateTemplates: ``, + generateTestTemplates: `mkdirp test/test-elements/generated/templates && cross-env UI5_BASE=true UI5_TS=true node "${LIB}/hbs2ui5/index.js" -d test/test-elements -o test/test-elements/generated/templates`, + generateProd: { + "default": "nps generateProd.remove-dev-mode generateProd.copy-prod", + "remove-dev-mode": `node "${LIB}/remove-dev-mode/remove-dev-mode.mjs"`, + "copy-prod": `copy-and-watch "dist/sap/**/*" dist/prod/sap/ && copy-and-watch "dist/thirdparty/preact/**/*.js" dist/prod/thirdparty/preact/ && copy-and-watch "dist/generated/assets/**/*.json" dist/prod/generated/assets/`, + }, + generateAPI: { + default: "nps generateAPI.generateCEM generateAPI.validateCEM", + generateCEM: `cross-env UI5_CEM_MODE='dev' cem analyze --config "${LIB}/cem/custom-elements-manifest.config.mjs"`, + validateCEM: `cross-env UI5_CEM_MODE='dev' node "${LIB}/cem/validate.js"`, + }, + watch: { + default: 'concurrently "nps watch.src" "nps watch.styles"', + withBundle: 'concurrently "nps watch.src" "nps watch.bundle" "nps watch.styles"', + src: 'nps "copy.src --watch --skip-initial-copy"', + bundle: `node ${LIB}/dev-server/dev-server.mjs ${viteConfig}`, + styles: 'chokidar "src/css/*.css" -c "nps generateStyles"' + }, + test: { + default: 'concurrently "nps test.ssr" "nps test.ssr2" "nps test.test-cy-ci"', + ssr: `mocha test/ssr`, + ssr2: "node -e \"import('./dist/Device.js')\"", + "test-cy-ci": `nps generateTestTemplates && cross-env UI5_BASE=true yarn cypress run --component --browser chrome`, + "test-cy-open": `nps generateTestTemplates && cross-env UI5_BASE=true yarn cypress open --component --browser chrome`, + }, +}; + + +module.exports = { + scripts, +}; diff --git a/packages/compat/package-scripts.cjs b/packages/compat/package-scripts.cjs new file mode 100644 index 000000000000..c1b3af2ca33f --- /dev/null +++ b/packages/compat/package-scripts.cjs @@ -0,0 +1,19 @@ +const getScripts = require("@ui5/webcomponents-tools/components-package/nps.js"); + +const options = { + port: 8082, + portStep: 2, + compatPackage: true, + noWatchTS: true, + dev: true, + internal: { + cypress_code_coverage: false, + cypress_acc_tests: false, + }, +}; + +const scripts = getScripts(options); + +module.exports = { + scripts, +}; diff --git a/packages/icons-business-suite/package-scripts.cjs b/packages/icons-business-suite/package-scripts.cjs new file mode 100644 index 000000000000..af644c7a7aff --- /dev/null +++ b/packages/icons-business-suite/package-scripts.cjs @@ -0,0 +1,16 @@ +const getScripts = require("@ui5/webcomponents-tools/icons-collection/nps.js"); + +const options = { + collectionName: "SAP-icons-business-suite", + versions: ["v1", "v2"], +}; + +const scripts = getScripts(options); + +// no i18n in this package +scripts.build.i18n = ""; +scripts.build.jsonImports = ""; + +module.exports = { + scripts +}; diff --git a/packages/icons-tnt/package-scripts.cjs b/packages/icons-tnt/package-scripts.cjs new file mode 100644 index 000000000000..e9522308f476 --- /dev/null +++ b/packages/icons-tnt/package-scripts.cjs @@ -0,0 +1,16 @@ +const getScripts = require("@ui5/webcomponents-tools/icons-collection/nps.js"); + +const options = { + collectionName: "SAP-icons-TNT", + versions: ["v2", "v3"], +}; + +const scripts = getScripts(options); + +// no i18n in this package +scripts.build.i18n = ""; +scripts.build.jsonImports = ""; + +module.exports = { + scripts +}; diff --git a/packages/icons/package-scripts.cjs b/packages/icons/package-scripts.cjs new file mode 100644 index 000000000000..a3e8a74087f0 --- /dev/null +++ b/packages/icons/package-scripts.cjs @@ -0,0 +1,12 @@ +const getScripts = require("@ui5/webcomponents-tools/icons-collection/nps.js"); + +const options = { + collectionName: "SAP-icons", + versions: ["v4", "v5"], +}; + +const scripts = getScripts(options); + +module.exports = { + scripts +}; diff --git a/packages/localization/package-scripts.cjs b/packages/localization/package-scripts.cjs new file mode 100644 index 000000000000..f5e208ca97b4 --- /dev/null +++ b/packages/localization/package-scripts.cjs @@ -0,0 +1,28 @@ +const resolve = require("resolve"); + +const copyUsedModules = resolve.sync("@ui5/webcomponents-tools/lib/copy-list/index.js"); +const amdToES6 = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/index.js"); +const noRequire = resolve.sync("@ui5/webcomponents-tools/lib/amd-to-es6/no-remaining-require.js"); + +const scripts = { + clean: "rimraf src/generated && rimraf dist", + lint: "eslint .", + generate: "nps clean copy.used-modules copy.cldr copy.overlay build.amd-to-es6 build.jsonImports", + build: { + "default": "nps clean copy.used-modules copy.cldr copy.overlay build.amd-to-es6 build.jsonImports build.typescript build.no-remaining-require", + "amd-to-es6": `node "${amdToES6}" dist/`, + "no-remaining-require": `node "${noRequire}" dist/`, + typescript: "tsc --build", + jsonImports: "node ./lib/generate-json-imports/cldr.js", + }, + typescript: "tsc --build", + copy: { + "used-modules": `node "${copyUsedModules}" ./used-modules.txt dist/`, + cldr: `copy-and-watch "../../node_modules/@openui5/sap.ui.core/src/sap/ui/core/cldr/*" dist/generated/assets/cldr/`, + overlay: `copy-and-watch "overlay/**/*.js" dist/`, + }, +}; + +module.exports = { + scripts, +}; diff --git a/packages/main/package-scripts.cjs b/packages/main/package-scripts.cjs new file mode 100644 index 000000000000..455bdbea0698 --- /dev/null +++ b/packages/main/package-scripts.cjs @@ -0,0 +1,18 @@ +const getScripts = require("@ui5/webcomponents-tools/components-package/nps.js"); + +const options = { + port: 8080, + portStep: 2, + noWatchTS: true, + dev: true, + internal: { + cypress_code_coverage: false, + cypress_acc_tests: false, + }, +}; + +const scripts = getScripts(options); + +module.exports = { + scripts +}; diff --git a/packages/theming/package-scripts.cjs b/packages/theming/package-scripts.cjs new file mode 100644 index 000000000000..ec1fe4636b89 --- /dev/null +++ b/packages/theming/package-scripts.cjs @@ -0,0 +1,24 @@ +const path = require('path'); + + +const CURRENT_LIB = path.join(__dirname, `./lib/`); +const TOOLS_LIB = path.join(__dirname, `../tools/lib/`); + +const jsonImportsScript = path.join(TOOLS_LIB, "./generate-json-imports/themes.js"); +const generateReportScript = path.join(CURRENT_LIB, "./generate-css-vars-usage-report/index.js"); + + +module.exports = { + scripts: { + clean: "rimraf dist && rimraf src/generated", + generate: `cross-env UI5_TS=true nps build.postcss build.jsonImports`, + build: { + default: `cross-env UI5_TS=true nps clean build.src build.postcss build.jsonImports build.typescript generateReport`, + src: `copy-and-watch "src/**/*.{json}" dist/`, + typescript: "tsc", + postcss: `node "${TOOLS_LIB}/css-processors/css-processor-themes.mjs"`, + jsonImports: `node "${jsonImportsScript}" dist/generated/assets/themes src/generated/json-imports`, + }, + generateReport: `node "${generateReportScript}"`, + }, +}; From 9e55e2c0bf760e29df1e46193d83c37f004428be Mon Sep 17 00:00:00 2001 From: Nayden Naydenov Date: Fri, 29 Aug 2025 15:33:04 +0300 Subject: [PATCH 04/10] chore: revise --- packages/base/custom-runner.cjs | 2 +- packages/theming/custom-runner.cjs | 2 +- .../custom-runner-commands.js | 4 +- packages/tools/lib/copy-and-watch/index.js | 50 ------- packages/tools/lib/copy-list/index.js | 4 - packages/tools/lib/create-icons/index.js | 4 - .../tools/lib/create-illustrations/index.js | 12 +- .../css-processor-components.mjs | 33 ++--- .../css-processors/css-processor-themes.mjs | 29 +--- .../lib/generate-js-imports/illustrations.js | 14 +- .../tools/lib/generate-json-imports/i18n.js | 4 - .../tools/lib/generate-json-imports/themes.js | 4 - packages/tools/lib/i18n/defaults.js | 4 - packages/tools/lib/i18n/toJSON.js | 3 - .../lib/remove-dev-mode/remove-dev-mode.mjs | 132 +++++------------- 15 files changed, 57 insertions(+), 244 deletions(-) diff --git a/packages/base/custom-runner.cjs b/packages/base/custom-runner.cjs index 33879ee705a4..3594b2745b26 100644 --- a/packages/base/custom-runner.cjs +++ b/packages/base/custom-runner.cjs @@ -11,7 +11,7 @@ const assetParametersScript = require("./lib/generate-asset-parameters/index.cjs const copyAndWatch = require("@ui5/webcomponents-tools/lib/copy-and-watch/index.js").copyAndWatch; const validate = require("@ui5/webcomponents-tools/lib/cem/validate"); const copyUsedModules = require("@ui5/webcomponents-tools/lib/copy-list/index.js"); -const removeDevMode = require("@ui5/webcomponents-tools/lib/remove-dev-mode/remove-dev-mode.mjs").removeDevMode; // +const removeDevMode = require("@ui5/webcomponents-tools/lib/remove-dev-mode/remove-dev-mode.mjs").default; const stylesScript = require("./lib/generate-styles/index.js").default; // const fontFaceScript = require("./lib/css-processors/css-processor-font-face.mjs").default; // diff --git a/packages/theming/custom-runner.cjs b/packages/theming/custom-runner.cjs index 0579a52ea8f4..821923def803 100644 --- a/packages/theming/custom-runner.cjs +++ b/packages/theming/custom-runner.cjs @@ -2,7 +2,7 @@ const path = require('path'); const BuildRunner = require('@ui5/webcomponents-tools/task-runner/build-runner'); const buildJsonImportsThemes = require("@ui5/webcomponents-tools/lib/generate-json-imports/themes"); const generateReport = require("./lib/generate-css-vars-usage-report/index.cjs"); -const cssProcessorThemes = require("@ui5/webcomponents-tools/lib/css-processors/css-processor-themes.mjs").processThemes; +const cssProcessorThemes = require("@ui5/webcomponents-tools/lib/css-processors/css-processor-themes.mjs").default; const copyAndWatch = require("@ui5/webcomponents-tools/lib/copy-and-watch/index.js").copyAndWatch; const runner = new BuildRunner(); diff --git a/packages/tools/components-package/custom-runner-commands.js b/packages/tools/components-package/custom-runner-commands.js index 77c111402b82..473a47724460 100644 --- a/packages/tools/components-package/custom-runner-commands.js +++ b/packages/tools/components-package/custom-runner-commands.js @@ -6,8 +6,8 @@ const buildI18nJson = require("../lib/i18n/toJSON"); const buildI18nDefaultsjs = require("../lib/i18n/defaults"); const buildJsonImportsI18n = require("../lib/generate-json-imports/i18n"); const buildJsonImportsThemes = require("../lib/generate-json-imports/themes"); -const cssProcessorThemes = require("../lib/css-processors/css-processor-themes.mjs").processThemes; -const cssProcessorComponents = require("../lib/css-processors/css-processor-components.mjs").processComponents; +const cssProcessorThemes = require("../lib/css-processors/css-processor-themes.mjs").default; +const cssProcessorComponents = require("../lib/css-processors/css-processor-components.mjs").default; const copyAndWatch = require("../lib/copy-and-watch/index.js").copyAndWatch; const validate = require("../lib/cem/validate"); const createIllustrations = require("../lib/create-illustrations"); diff --git a/packages/tools/lib/copy-and-watch/index.js b/packages/tools/lib/copy-and-watch/index.js index 6d7f53d5081c..8ba1bebb3b15 100644 --- a/packages/tools/lib/copy-and-watch/index.js +++ b/packages/tools/lib/copy-and-watch/index.js @@ -146,56 +146,6 @@ const copyAndWatch = (sources, target, options = {}) => { return null; }; -// If this file is run directly (not required as a module) -if (require.main === module) { - const args = process.argv.slice(2); - const options = {}; - - ['watch', 'clean', 'skip-initial-copy', 'safe', 'silent'].forEach(key => { - const index = args.indexOf(`--${key}`); - if (index >= 0) { - options[key] = true; - args.splice(index, 1); - } - }); - - if (args.length < 2) { - console.error('Not enough arguments: copy-and-watch [options] '.red); - process.exit(1); - } - - if (options['skip-initial-copy'] && !options['watch']) { - console.error('--skip-initial-copy argument is meant to be used with --watch, otherwise no files will be copied'.red); - process.exit(1); - } - - const target = args.pop(); - const sources = args; - - const cliOptions = { - watch: options.watch, - clean: options.clean, - skipInitialCopy: options['skip-initial-copy'], - safe: options.safe, - silent: options.silent - }; - - try { - const watcher = copyAndWatch(sources, target, cliOptions); - if (watcher) { - // Keep the process alive when watching - process.on('SIGINT', () => { - console.log('\nStopping watcher...'); - watcher.close(); - process.exit(0); - }); - } - } catch (error) { - console.error('Error:', error.message); - process.exit(1); - } -} - module.exports = copyAndWatch; module.exports.copyAndWatch = copyAndWatch; module.exports.rimraf = rimraf; diff --git a/packages/tools/lib/copy-list/index.js b/packages/tools/lib/copy-list/index.js index 2b693ddab1ba..ec7d363d0462 100644 --- a/packages/tools/lib/copy-list/index.js +++ b/packages/tools/lib/copy-list/index.js @@ -21,8 +21,4 @@ const generate = async (fileList, dest) => { }); }; -// generate().then(() => { -// console.log("Files copied."); -// }); - module.exports = generate; diff --git a/packages/tools/lib/create-icons/index.js b/packages/tools/lib/create-icons/index.js index 19e2e501e220..7cbdf6c5a74f 100644 --- a/packages/tools/lib/create-icons/index.js +++ b/packages/tools/lib/create-icons/index.js @@ -124,8 +124,4 @@ export { getPathData, ltr, accData };` await createIcons(srcFile) } -// generate.then(() => { -// console.log("Icons created."); -// }); - module.exports = generate; \ No newline at end of file diff --git a/packages/tools/lib/create-illustrations/index.js b/packages/tools/lib/create-illustrations/index.js index 6ad6d2404ed6..e37d310a471a 100644 --- a/packages/tools/lib/create-illustrations/index.js +++ b/packages/tools/lib/create-illustrations/index.js @@ -1,13 +1,7 @@ const fs = require("fs").promises; const path = require("path"); -const generate = async (srcPath, - defaultText, - illustrationsPrefix, - illustrationSet, - destPath, - collection) => { - +const generate = async (srcPath, defaultText, illustrationsPrefix, illustrationSet, destPath, collection) => { const ORIGINAL_TEXTS = { UnableToLoad: "UnableToLoad", UnableToUpload: "UnableToUpload", @@ -189,8 +183,4 @@ export { dialogSvg, sceneSvg, spotSvg, dotSvg };` }); }; -// generate().then(() => { -// console.log("Illustrations generated."); -// }); - module.exports = generate; \ No newline at end of file diff --git a/packages/tools/lib/css-processors/css-processor-components.mjs b/packages/tools/lib/css-processors/css-processor-components.mjs index f846bdd6a868..24c5c8dc8eb3 100644 --- a/packages/tools/lib/css-processors/css-processor-components.mjs +++ b/packages/tools/lib/css-processors/css-processor-components.mjs @@ -38,9 +38,11 @@ const createCustomPlugin = (packageJSON, tsMode = false) => { }; }; -const getConfig = async (inputFilesGlob, packageJSON, tsMode) => { +const getConfig = async (inputFilesGlob, tsMode) => { + const packageJSON = JSON.parse(fs.readFileSync("./package.json")); + const config = { - entryPoints: await globby(inputFilesGlob), + entryPoints: await globby([inputFilesGlob]), bundle: true, minify: true, outdir: 'dist/css', @@ -55,18 +57,14 @@ const getConfig = async (inputFilesGlob, packageJSON, tsMode) => { const processComponents = async (options = {}) => { const { watch = false, - packagePath = "./package.json", - inputFilesGlob = "src/themes/*.css", - outdir = 'dist/css', - outbase = 'src', tsMode = false } = options; - const packageJSON = JSON.parse(fs.readFileSync(packagePath)); + const inputFilesGlob = "src/themes/*.css"; if (watch) { let ready; - let config = await getConfig(inputFilesGlob, packageJSON, tsMode); + let config = await getConfig(inputFilesGlob, tsMode); let ctx = await esbuild.context(config); await ctx.watch(); console.log('watching...'); @@ -81,7 +79,7 @@ const processComponents = async (options = {}) => { if (ready) { // new file ctx.dispose(); - config = await getConfig(inputFilesGlob, packageJSON, tsMode); + config = await getConfig(inputFilesGlob, tsMode); ctx = await esbuild.context(config); ctx.watch(); } @@ -89,25 +87,10 @@ const processComponents = async (options = {}) => { return { ctx, watcher }; } else { - const config = await getConfig(inputFilesGlob, packageJSON, tsMode); + const config = await getConfig(inputFilesGlob, tsMode); const result = await esbuild.build(config); return result; } }; -// If this file is run directly (not imported as a module) -if (import.meta.url === `file://${process.argv[1]}`) { - const restArgs = process.argv.slice(2); - const watchMode = restArgs.includes("-w"); - - processComponents({ watch: watchMode }) - .then(() => { - if (!watchMode) { - console.log('Component processing completed.'); - } - }) - .catch(console.error); -} - export default processComponents; -export { processComponents, createCustomPlugin, getConfig }; diff --git a/packages/tools/lib/css-processors/css-processor-themes.mjs b/packages/tools/lib/css-processors/css-processor-themes.mjs index 50ba5b6d6c1f..56d76c443945 100644 --- a/packages/tools/lib/css-processors/css-processor-themes.mjs +++ b/packages/tools/lib/css-processors/css-processor-themes.mjs @@ -72,22 +72,18 @@ const createScopingPlugin = (packageJSON, tsMode = false) => { const processThemes = async (options = {}) => { const { watch = false, - packagePath = "./package.json", - inputPattern = "src/**/parameters-bundle.css", - outdir = 'dist/css', - outbase = 'src', tsMode = false, } = options; - const packageJSON = JSON.parse(fs.readFileSync(packagePath)); - const inputFiles = await globby([inputPattern]); + const packageJSON = JSON.parse(fs.readFileSync("./package.json")); + const inputFiles = await globby(["src/**/parameters-bundle.css"]); const config = { entryPoints: inputFiles, bundle: true, minify: true, - outdir, - outbase, + outdir: 'dist/css', + outbase: 'src', plugins: [ createScopingPlugin(packageJSON, tsMode), ], @@ -105,19 +101,4 @@ const processThemes = async (options = {}) => { } }; -// If this file is run directly (not imported as a module) -if (import.meta.url === `file://${process.argv[1]}`) { - const restArgs = process.argv.slice(2); - const watchMode = restArgs.includes("-w"); - - processThemes({ watch: watchMode }) - .then(() => { - if (!watchMode) { - console.log('Theme processing completed.'); - } - }) - .catch(console.error); -} - -export default processThemes; -export { processThemes, createScopingPlugin, processThemingPackageFile, processComponentPackageFile }; \ No newline at end of file +export default processThemes; \ No newline at end of file diff --git a/packages/tools/lib/generate-js-imports/illustrations.js b/packages/tools/lib/generate-js-imports/illustrations.js index e4db52c4af01..48dac358de58 100644 --- a/packages/tools/lib/generate-js-imports/illustrations.js +++ b/packages/tools/lib/generate-js-imports/illustrations.js @@ -51,12 +51,7 @@ const getMatchingFiles = async (folder, pattern) => { return dir.filter((fileName) => fileName.match(pattern)); }; -const generateIllustrations = async (inputFolder, - outputFile, - set, - collection, - location, - filterOut) => { +const generateIllustrations = async (inputFolder, outputFile, set, collection, location, filterOut) => { const normalizedInputFolder = path.normalize(inputFolder); const normalizedOutputFile = path.normalize(outputFile); @@ -66,7 +61,7 @@ const generateIllustrations = async (inputFolder, const dynamicImports = await generateDynamicImportLines(illustrations, location, filterOut); const availableIllustrations = generateAvailableIllustrationsArray(illustrations, filterOut); - const contentDynamic = generateDynamicImportsFileContent(dynamicImports, availableIllustrations, collection, set, undefined); + const contentDynamic = generateDynamicImportsFileContent(dynamicImports, availableIllustrations, collection, set); await fs.mkdir(path.dirname(normalizedOutputFile), { recursive: true }); await fs.writeFile(normalizedOutputFile, contentDynamic); @@ -74,9 +69,4 @@ const generateIllustrations = async (inputFolder, console.log(`Generated ${normalizedOutputFile}`); }; -// // Run the generation process -// generateIllustrations(config).catch((error) => { -// console.error("Error generating illustrations:", error); -// }); - module.exports = generateIllustrations; diff --git a/packages/tools/lib/generate-json-imports/i18n.js b/packages/tools/lib/generate-json-imports/i18n.js index c54c76d8b683..01b01a1d1cbe 100644 --- a/packages/tools/lib/generate-json-imports/i18n.js +++ b/packages/tools/lib/generate-json-imports/i18n.js @@ -78,8 +78,4 @@ const generate = async (inputFolder, distFolder, isTypeScript) => { ]); } -// generate().then(() => { -// console.log("Generated i18n JSON imports."); -// }); - module.exports = generate \ No newline at end of file diff --git a/packages/tools/lib/generate-json-imports/themes.js b/packages/tools/lib/generate-json-imports/themes.js index 4e1b352c7f43..7905258aa66f 100644 --- a/packages/tools/lib/generate-json-imports/themes.js +++ b/packages/tools/lib/generate-json-imports/themes.js @@ -60,8 +60,4 @@ ${availableThemesArray} ]); }; -// generate().then(() => { -// console.log("Generated themes JSON imports."); -// }); - module.exports = generate; \ No newline at end of file diff --git a/packages/tools/lib/i18n/defaults.js b/packages/tools/lib/i18n/defaults.js index 122f10b40a12..9db247d7c096 100644 --- a/packages/tools/lib/i18n/defaults.js +++ b/packages/tools/lib/i18n/defaults.js @@ -78,8 +78,4 @@ export {${textKeys.join()}};`; await fs.writeFile(outputFile, getOutputFileContent(properties, defaultLanguageProperties)); }; -// generate().then(() => { -// console.log("i18n default file generated."); -// }); - module.exports = generate \ No newline at end of file diff --git a/packages/tools/lib/i18n/toJSON.js b/packages/tools/lib/i18n/toJSON.js index 82deba84a590..d8cd4b72528b 100644 --- a/packages/tools/lib/i18n/toJSON.js +++ b/packages/tools/lib/i18n/toJSON.js @@ -37,7 +37,4 @@ const generate = async (inputFolder, distFolder) => { return Promise.all(files.map((file => convertToJSON(file, messagesJSONDist)))); }; -// generate().then(() => { -// console.log("Message bundle JSON files generated."); -// }); module.exports = generate; diff --git a/packages/tools/lib/remove-dev-mode/remove-dev-mode.mjs b/packages/tools/lib/remove-dev-mode/remove-dev-mode.mjs index c3e32ce84961..1cfe3bf6a3bb 100644 --- a/packages/tools/lib/remove-dev-mode/remove-dev-mode.mjs +++ b/packages/tools/lib/remove-dev-mode/remove-dev-mode.mjs @@ -2,98 +2,40 @@ import { globby } from "globby"; import * as esbuild from 'esbuild' import * as fs from "fs"; -/** - * Creates an esbuild plugin that removes development mode code from UI5Element files - * @param {Object} options - Plugin options - * @param {RegExp} options.filter - File filter pattern (default: /UI5Element.ts$/) - * @param {string[]} options.devModeReplacements - Development mode code patterns to remove - * @returns {Object} esbuild plugin - */ -export const createDevModeRemovalPlugin = (options = {}) => { - const { - filter = /UI5Element.ts$/, - devModeReplacements = [ - { pattern: /const DEV_MODE = true/g, replacement: "" }, - { pattern: /if \(DEV_MODE\)/g, replacement: "if (false)" } - ] - } = options; - - return { - name: 'ui5-dev-mode-removal', - setup(build) { - build.onLoad({ filter }, async (args) => { - let text = await fs.promises.readFile(args.path, 'utf8'); - - // Apply all dev mode replacements - for (const { pattern, replacement } of devModeReplacements) { - text = text.replaceAll(pattern, replacement); - } - - return { - contents: text, - loader: 'ts', - }; - }); - }, - }; -}; - -/** - * Creates a default esbuild configuration for removing dev mode - * @param {Object} options - Configuration options - * @param {string|string[]} options.entryPoints - Entry points glob pattern or array - * @param {string} options.outdir - Output directory - * @param {string} options.outbase - Output base directory - * @param {boolean} options.bundle - Whether to bundle files - * @param {boolean} options.minify - Whether to minify output - * @param {boolean} options.sourcemap - Whether to generate sourcemaps - * @param {Object} options.pluginOptions - Options for the dev mode removal plugin - * @returns {Promise} esbuild configuration - */ -export const createDevModeConfig = async (options = {}) => { - const { - entryPoints = "src/**/*.ts", - outdir = 'dist/prod', - outbase = 'src', - bundle = false, - minify = true, - sourcemap = true, - pluginOptions = {} - } = options; - - const resolvedEntryPoints = Array.isArray(entryPoints) - ? entryPoints - : await globby(entryPoints); - - return { - entryPoints: resolvedEntryPoints, - bundle, - minify, - sourcemap, - outdir, - outbase, - plugins: [ - createDevModeRemovalPlugin(pluginOptions), - ] - }; -}; - -/** - * Removes development mode code from TypeScript files - * @param {Object} options - Build options (same as createDevModeConfig) - * @returns {Promise} esbuild result - */ -export const removeDevMode = async (options = {}) => { - const config = await createDevModeConfig(options); - return await esbuild.build(config); -}; - -// Default export for backward compatibility -export default removeDevMode; - -// // If this file is run directly, execute with default configuration -// if (import.meta.url === `file://${process.argv[1]}`) { -// const config = await createDevModeConfig(); -// const result = await esbuild.build(config); -// console.log('Dev mode removal completed:', result); -// } \ No newline at end of file +let customPlugin = { + name: 'ui5-tools', + setup(build) { + build.onLoad({ filter: /UI5Element.ts$/ }, async (args) => { + let text = await fs.promises.readFile(args.path, 'utf8'); + text = text.replaceAll(/const DEV_MODE = true/g, ""); + text = text.replaceAll(/if \(DEV_MODE\)/g, "if (false)"); + return { + contents: text, + loader: 'ts', + } + }) + }, +} + +const getConfig = async () => { + const config = { + entryPoints: await globby("src/**/*.ts"), + bundle: false, + minify: true, + sourcemap: true, + outdir: 'dist/prod', + outbase: 'src', + plugins: [ + customPlugin, + ] + }; + return config; +} + +const removeDevMode = async () => { + const config = await getConfig(); + const result = await esbuild.build(config); + return result; +} + +export default removeDevMode; \ No newline at end of file From b7f6d1af4128b4a468b294018f8b9547ded1dd10 Mon Sep 17 00:00:00 2001 From: Nayden Naydenov Date: Fri, 29 Aug 2025 16:00:06 +0300 Subject: [PATCH 05/10] chore: clean --- packages/base/custom-runner.cjs | 54 +------ packages/localization/custom-runner.cjs | 9 +- packages/theming/custom-runner.cjs | 12 +- .../custom-runner-commands.js | 136 +----------------- .../custom-runner-commands.js | 27 +--- 5 files changed, 20 insertions(+), 218 deletions(-) diff --git a/packages/base/custom-runner.cjs b/packages/base/custom-runner.cjs index 3594b2745b26..5e0e72ffb9a5 100644 --- a/packages/base/custom-runner.cjs +++ b/packages/base/custom-runner.cjs @@ -45,7 +45,6 @@ runner.addTask("generate", { "generateVersionInfo", "generateStyles", "generateFontFace", - "generateTemplates", "build:jsonImports", ], crossEnv: { @@ -63,7 +62,6 @@ runner.addTask("prepare", { "generateVersionInfo", "generateStyles", "generateFontFace", - "generateTemplates", "typescript", "integrate:no-remaining-require", "build:jsonImports", @@ -91,8 +89,7 @@ runner.addTask("integrate", { runner.addTask("integrate:copy-used-modules", { callback: async () => { - const dest = "dist/"; - await copyUsedModules("./used-modules.txt", dest); + await copyUsedModules("./used-modules.txt", "dist/"); return "Used modules copied."; }, }); @@ -100,8 +97,6 @@ runner.addTask("integrate:copy-used-modules", { runner.addTask("integrate:amd-to-es6", { callback: async () => { await amdToES6("dist/"); - // console.log("i18n default file generated."); - // return "i18n default file generated." return ""; }, }); @@ -109,8 +104,6 @@ runner.addTask("integrate:amd-to-es6", { runner.addTask("integrate:no-remaining-require", { callback: async () => { await noRequire("dist/"); - // console.log("i18n default file generated."); - // return "i18n default file generated." return ""; }, }); @@ -159,15 +152,13 @@ runner.addTask("build:i18n", { runner.addTask("build:i18n:defaultsjs", { callback: async () => { await buildI18nDefaultsjs("src/i18n", "src/generated/i18n", true); - console.log("i18n default file generated."); - return "i18n default file generated." - } + return "i18n default file generated."; + }, }); runner.addTask("build:i18n:json", { callback: async () => { await buildI18nJson("src/i18n", "dist/generated/assets/i18n"); - console.log("Message bundle JSON files generated."); return "Message bundle JSON files generated."; }, }); @@ -181,7 +172,6 @@ runner.addTask("build:jsonImports", { runner.addTask("build:jsonImports:i18n", { callback: async () => { await buildJsonImportsI18n("dist/generated/assets/i18n", "src/generated/json-imports", true); - console.log("Generated i18n JSON imports."); return "Generated i18n JSON imports."; }, }); @@ -194,18 +184,14 @@ runner.addTask("copy", { runner.addTask("copy:src", { callback: async () => { - await copyAndWatch("src/**/*.{js,json}", "dist/", { silent: true }); + await copyAndWatch("src/**/*.{js,css,d.ts}", "dist/", { silent: true }); return "Source files copied."; - // console.log("Source files copied."); - // return "Source files copied."; - // return ""; }, }); runner.addTask("generateAssetParameters", { callback: async () => { - await assetParametersScript("dist/"); - console.log("Assets parameters generated."); + await assetParametersScript(); return "Assets parameters generated."; }, }); @@ -213,7 +199,6 @@ runner.addTask("generateAssetParameters", { runner.addTask("generateVersionInfo", { callback: async () => { await versionScript(); - console.log("Version info file generated."); return "Version info file generated."; }, }); @@ -221,7 +206,6 @@ runner.addTask("generateVersionInfo", { runner.addTask("generateStyles", { callback: async () => { await stylesScript(); - console.log("Styles files generated."); return "Styles files generated."; }, }); @@ -229,17 +213,10 @@ runner.addTask("generateStyles", { runner.addTask("generateFontFace", { callback: async () => { await fontFaceScript(); - console.log("FontFace CSS generated."); return "FontFace CSS generated."; }, }); -runner.addTask("generateTemplates", { - dependencies: [ - ``, - ], -}); - runner.addTask("generateProd", { dependencies: [ "generateProd:remove-dev-mode", @@ -289,27 +266,6 @@ runner.addTask("generateAPI:validateCEM", { } }); -runner.addTask("watch", { - dependencies: [ - "watch:src", - "watch:styles", - ], - parallel: true, -}); - -runner.addTask("watch:src", { - callback: async () => { - await copyAndWatch("src/**/*.{js,json}", "dist/", { silent: true }); - return "Source files copied."; - }, -}); - -runner.addTask("watch:styles", { - dependencies: [ - `chokidar "src/css/*.css" -c "nps generateStyles"` - ], -}); - // Export for CLI usage if (require.main === module) { const taskName = process.argv[2]; diff --git a/packages/localization/custom-runner.cjs b/packages/localization/custom-runner.cjs index 1290278ef837..b8a84b8ead7a 100644 --- a/packages/localization/custom-runner.cjs +++ b/packages/localization/custom-runner.cjs @@ -44,8 +44,6 @@ runner.addTask("build", { runner.addTask("build:amd-to-es6", { callback: async () => { await amdToES6("dist/"); - // console.log("i18n default file generated."); - // return "i18n default file generated." return ""; }, }); @@ -53,8 +51,6 @@ runner.addTask("build:amd-to-es6", { runner.addTask("build:no-remaining-require", { callback: async () => { await noRequire("dist/"); - // console.log("i18n default file generated."); - // return "i18n default file generated." return ""; }, }); @@ -66,8 +62,6 @@ runner.addTask("build:typescript", { runner.addTask("build:jsonImports", { callback: async () => { await cldr(); - // console.log("i18n default file generated."); - // return "i18n default file generated." return ""; }, }); @@ -89,8 +83,7 @@ runner.addTask("copy", { runner.addTask("copy:used-modules", { callback: async () => { - const dest = "dist/"; - await copyUsedModules("./used-modules.txt", dest); + await copyUsedModules("./used-modules.txt", "dist/"); return "Used modules copied."; }, }); diff --git a/packages/theming/custom-runner.cjs b/packages/theming/custom-runner.cjs index 821923def803..83d644d96169 100644 --- a/packages/theming/custom-runner.cjs +++ b/packages/theming/custom-runner.cjs @@ -18,10 +18,7 @@ runner.addTask("generate", { dependencies: [ "build:postcss", "build:jsonImports", - ], - crossEnv: { - UI5_TS: true, - }, + ] }); runner.addTask("build", { @@ -32,10 +29,7 @@ runner.addTask("build", { "build:jsonImports", "build:typescript", "generateReport", - ], - crossEnv: { - UI5_TS: true, - } + ] }); runner.addTask("build:src", { @@ -61,7 +55,6 @@ runner.addTask("build:postcss", { runner.addTask("build:jsonImports", { callback: async () => { await buildJsonImportsThemes("dist/generated/assets/themes", "src/generated/json-imports", true); - console.log("Generated themes JSON imports."); return "Generated themes JSON imports."; }, }); @@ -69,7 +62,6 @@ runner.addTask("build:jsonImports", { runner.addTask("generateReport", { callback: async () => { await generateReport(); - console.log("CSS Vars usage report generated."); return "CSS Vars usage report generated."; }, }); diff --git a/packages/tools/components-package/custom-runner-commands.js b/packages/tools/components-package/custom-runner-commands.js index 473a47724460..9406e9d5370d 100644 --- a/packages/tools/components-package/custom-runner-commands.js +++ b/packages/tools/components-package/custom-runner-commands.js @@ -32,25 +32,6 @@ const getScripts = (options) => { const createIllustrationsLoadersScript = illustrationsData.map(illustrations => generateJsImportsIllustrations(illustrations.destinationPath, illustrations.dynamicImports.outputFile, illustrations.set, illustrations.collection, illustrations.dynamicImports.location, illustrations.dynamicImports.filterOut)) - - const tsOption = !options.legacy || options.jsx; - const tsCommandOld = tsOption ? "tsc" : ""; - let tsWatchCommandStandalone = tsOption ? "tsc --watch" : ""; - // this command is only used for standalone projects. monorepo projects get their watch from vite, so opt-out here - if (options.noWatchTS) { - tsWatchCommandStandalone = ""; - } - const tsCrossEnv = tsOption ? true : false; - - if (tsOption) { - try { - require("typescript"); - } catch (e) { - console.error(`TypeScript is not found. Try to install it by running \`npm install --save-dev typescript\` if you are using npm or by running \`yarn add --dev typescript\` if you are using yarn.`); - process.exit(e.code); - } - } - let viteConfig; if (fs.existsSync("config/vite.config.js")) { // old project setup where config file is in separate folder @@ -98,14 +79,10 @@ const getScripts = (options) => { dependencies: [ "prepare:all" ], - crossEnv: { - UI5_TS: tsCrossEnv, - } }) runner.addTask("generate:all", { dependencies: [ - "build:templates", "build:i18n", "prepare:styleRelated", "copyProps", @@ -127,19 +104,14 @@ const getScripts = (options) => { dependencies: [ "clean", "prepare:all", - options.legacy ? "copy" : "", "copyProps", "prepare:typescript", "generateAPI" ], - crossEnv: { - UI5_TS: tsCrossEnv, - } }) runner.addTask("prepare:all", { dependencies: [ - "build:templates", "build:i18n", "prepare:styleRelated", "build:illustrations" @@ -157,7 +129,7 @@ const getScripts = (options) => { runner.addTask("prepare:typescript", { dependencies: [ - tsCommandOld + "tsc --build", ] }); @@ -169,15 +141,6 @@ const getScripts = (options) => { ] }) - runner.addTask("build:templates", { - dependencies: [ - !options.legacy ? "" : `node "${LIB}/hbs2ui5/index.js" -d src/ -o src/generated/templates` - ], - crossEnv: { - UI5_TS: tsCrossEnv, - } - }); - runner.addTask("build:styles", { dependencies: [ "build:styles:themes", @@ -188,14 +151,14 @@ const getScripts = (options) => { runner.addTask("build:styles:themes", { callback: async () => { - await cssProcessorThemes({ tsMode: options.legacy }); + await cssProcessorThemes({ tsMode: true }); return "" } }); runner.addTask("build:styles:components", { callback: async () => { - await cssProcessorComponents({ tsMode: options.legacy }); + await cssProcessorComponents({ tsMode: true }); return "" } }); @@ -210,8 +173,7 @@ const getScripts = (options) => { runner.addTask("build:i18n:defaultsjs", { callback: async () => { - await buildI18nDefaultsjs("src/i18n", "src/generated/i18n", !options.legacy); - console.log("i18n default file generated."); + await buildI18nDefaultsjs("src/i18n", "src/generated/i18n", true); return "i18n default file generated." } }); @@ -234,7 +196,7 @@ const getScripts = (options) => { runner.addTask("build:jsonImports:themes", { callback: async () => { - await buildJsonImportsThemes("dist/generated/assets/themes", "src/generated/json-imports", !options.legacy); + await buildJsonImportsThemes("dist/generated/assets/themes", "src/generated/json-imports", true); console.log("Generated themes JSON imports."); return "Generated themes JSON imports."; }, @@ -242,7 +204,7 @@ const getScripts = (options) => { runner.addTask("build:jsonImports:i18n", { callback: async () => { - await buildJsonImportsI18n("dist/generated/assets/i18n", "src/generated/json-imports", !options.legacy); + await buildJsonImportsI18n("dist/generated/assets/i18n", "src/generated/json-imports", true); console.log("Generated i18n JSON imports."); return "Generated i18n JSON imports."; }, @@ -313,92 +275,6 @@ const getScripts = (options) => { } }); - runner.addTask("watch", { - dependencies: [ - "watch:templates", - "watch:typescript", - options.legacy ? "watch:src" : "", - "watch:styles", - "watch:i18n", - "watch:props" - ], - parallel: true, - crossEnv: { - UI5_TS: tsCrossEnv, - } - }); - - runner.addTask("watch:devServer", { - dependencies: [ - "watch:default", - "watch:bundle" - ], - parallel: true, - }); - - runner.addTask("watch:src", { - dependencies: [ - `copy:src --watch --safe --skip-initial-copy` - ] - }); - - runner.addTask("watch:typescript", { - dependencies: [ - tsWatchCommandStandalone - ] - }); - - runner.addTask("watch:props", { - dependencies: [ - `copyProps --watch --safe --skip-initial-copy` - ] - }); - - runner.addTask("watch:bundle", { - dependencies: [ - `node ${LIB}/dev-server/dev-server.mjs ${viteConfig}` - ] - }); - - runner.addTask("watch:styles", { - dependencies: [ - "watch:styles:themes", - "watch:styles:components" - ], - parallel: true, - }); - - runner.addTask("watch:styles:themes", { - dependencies: [ - `build:styles:themes -w` - ] - }); - - runner.addTask("watch:styles:components", { - dependencies: [ - `build:styles:components -w` // TODO - ] - }); - - runner.addTask("watch:templates", { - dependencies: [ - 'chokidar "src/**/*.hbs" -i "src/generated" -c "nps build:templates"' - ] - }); - - runner.addTask("watch:i18n", { - dependencies: [ - 'chokidar "src/i18n/messagebundle.properties" -c "nps build:i18n:defaultsjs"' - ] - }); - - runner.addTask("start", { - dependencies: [ - "prepare", - "watch:devServer" - ], - }) - runner.addTask("generateAPI", { dependencies: [ "generateAPI:generateCEM", diff --git a/packages/tools/icons-collection/custom-runner-commands.js b/packages/tools/icons-collection/custom-runner-commands.js index 5147178d4c30..79f1d0bfa865 100644 --- a/packages/tools/icons-collection/custom-runner-commands.js +++ b/packages/tools/icons-collection/custom-runner-commands.js @@ -1,6 +1,5 @@ const path = require("path"); const BuildRunner = require('../task-runner/build-runner'); -const LIB = path.join(__dirname, `../lib/`); const buildI18nJson = require("../lib/i18n/toJSON"); const buildI18nDefaultsjs = require("../lib/i18n/defaults"); const buildJsonImportsI18n = require("../lib/generate-json-imports/i18n"); @@ -12,7 +11,6 @@ const createIconImportsCommand = (options, runner) => { runner.addTask("build:icons", { callback: async () => { await buildIcons(options.collectionName); - console.log("Icons created."); return "Icons created." } }) @@ -27,7 +25,6 @@ const createIconImportsCommand = (options, runner) => { runner.addTask(`build:icons:create${v}`, { callback: async () => { await buildIcons(options.collectionName, v); - console.log("Icons created."); return "Icons created." } }) @@ -98,9 +95,6 @@ const getScripts = (options) => { createIconImportsCommand(options, runner); copyIconAssetsCommand(options, runner); - const tsCommand = !options.legacy ? "tsc --build" : ""; - const tsCrossEnv = !options.legacy ? true : false; - runner.addTask("clean", "rimraf dist && rimraf src/generated"); runner.addTask("generate", { @@ -111,15 +105,12 @@ const getScripts = (options) => { "build:icons", "build:jsonImports", "copyjson" - ], - crossEnv: { - UI5_TS: tsCrossEnv - } + ] }) runner.addTask("copyjson", { callback: async () => { - await copyAndWatch("src/**/*.json", "dist/", { silent: true }); + await copyAndWatch("src/**/*.json", "dist/generated/", { silent: true }); return "JSON files copied."; }, }); @@ -132,10 +123,7 @@ const getScripts = (options) => { "typescript", "build:icons", "build:jsonImports", - ], - crossEnv: { - UI5_TS: tsCrossEnv - } + ] }) runner.addTask("build:i18n", { @@ -148,8 +136,7 @@ const getScripts = (options) => { runner.addTask("build:i18n:defaultsjs", { callback: async () => { - await buildI18nDefaultsjs("src/i18n", "src/generated/i18n", !options.legacy); - console.log("i18n default file generated."); + await buildI18nDefaultsjs("src/i18n", "src/generated/i18n", true); return "i18n default file generated." } }); @@ -157,7 +144,6 @@ const getScripts = (options) => { runner.addTask("build:i18n:json", { callback: async () => { await buildI18nJson("src/i18n", "dist/generated/assets/i18n"); - console.log("Message bundle JSON files generated."); return "Message bundle JSON files generated." }, }); @@ -171,15 +157,14 @@ const getScripts = (options) => { runner.addTask("build:jsonImports:i18n", { callback: async () => { - await buildJsonImportsI18n("src/generated/assets/i18n", "src/generated/json-imports", !options.legacy); - console.log("Generated i18n JSON imports."); + await buildJsonImportsI18n("src/generated/assets/i18n", "src/generated/json-imports", true); return "Generated i18n JSON imports."; }, }); runner.addTask("typescript", { dependencies: [ - tsCommand, + "tsc --build", ] }); From 26ecdf873fd1bc2770bb037fa88080a245812eb8 Mon Sep 17 00:00:00 2001 From: Nayden Naydenov Date: Fri, 29 Aug 2025 16:09:31 +0300 Subject: [PATCH 06/10] chore: clean --- .../css-processor-components.mjs | 135 +++++++++--------- .../css-processors/css-processor-themes.mjs | 1 - 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/packages/tools/lib/css-processors/css-processor-components.mjs b/packages/tools/lib/css-processors/css-processor-components.mjs index 24c5c8dc8eb3..c9045b73f4e9 100644 --- a/packages/tools/lib/css-processors/css-processor-components.mjs +++ b/packages/tools/lib/css-processors/css-processor-components.mjs @@ -8,89 +8,90 @@ import scopeVariables from "./scope-variables.mjs"; import { writeFileIfChanged, getFileContent } from "./shared.mjs"; const createCustomPlugin = (packageJSON, tsMode = false) => { - const extension = tsMode ? ".css.ts" : ".css.js"; + const extension = tsMode ? ".css.ts" : ".css.js"; - return { - name: 'ui5-tools', - setup(build) { - build.initialOptions.write = false; + return { + name: 'ui5-tools', + setup(build) { + build.initialOptions.write = false; - build.onEnd(async (result) => { - const fileProcessingPromises = result.outputFiles.map(async (f) => { - // scoping - let newText = scopeVariables(f.text, packageJSON); - newText = newText.replaceAll(/\\/g, "\\\\"); // Escape backslashes as they might appear in css rules - await mkdir(path.dirname(f.path), { recursive: true }); + build.onEnd(async (result) => { + const fileProcessingPromises = result.outputFiles.map(async (f) => { + let newText = scopeVariables(f.text, packageJSON); + newText = newText.replaceAll(/\\/g, "\\\\"); // Escape backslashes as they might appear in css rules + writeFile(f.path, newText); - // JS/TS - const jsPath = f.path.replace(/dist[\/\\]css/, "src/generated/").replace(".css", extension); - const jsContent = getFileContent(packageJSON.name, "\`" + newText + "\`", true); + // JS/TS + const jsPath = f.path.replace(/dist[\/\\]css/, "src/generated/").replace(".css", extension); + const jsContent = getFileContent(packageJSON.name, "\`" + newText + "\`", true); - Promise.all([ - await writeFile(f.path, newText), - await writeFileIfChanged(jsPath, jsContent), - ]) - }); + await mkdir(path.dirname(f.path), { recursive: true }); - await Promise.all(fileProcessingPromises); - }) - }, - }; + Promise.all([ + await writeFile(f.path, newText), + await writeFileIfChanged(jsPath, jsContent), + ]); + }); + +await Promise.all(fileProcessingPromises); + }) + }, + }; }; const getConfig = async (inputFilesGlob, tsMode) => { - const packageJSON = JSON.parse(fs.readFileSync("./package.json")); + const packageJSON = JSON.parse(fs.readFileSync("./package.json")); - const config = { - entryPoints: await globby([inputFilesGlob]), - bundle: true, - minify: true, - outdir: 'dist/css', - outbase: 'src', - plugins: [ - createCustomPlugin(packageJSON, tsMode), - ] - }; - return config; + const config = { + entryPoints: await globby([inputFilesGlob]), + bundle: true, + minify: true, + outdir: 'dist/css', + outbase: 'src', + plugins: [ + createCustomPlugin(packageJSON, tsMode), + ] + }; + return config; }; const processComponents = async (options = {}) => { - const { - watch = false, - tsMode = false - } = options; + const { + watch = false, + tsMode = false + } = options; - const inputFilesGlob = "src/themes/*.css"; + const inputFilesGlob = "src/themes/*.css"; - if (watch) { - let ready; - let config = await getConfig(inputFilesGlob, tsMode); - let ctx = await esbuild.context(config); - await ctx.watch(); - console.log('watching...'); + if (watch) { + let ready; + let config = await getConfig(inputFilesGlob, tsMode); + let ctx = await esbuild.context(config); + await ctx.watch(); + console.log('watching...'); - // when new component css files are added, they do not trigger a build as no one directly imports them - // restart the watch mode with the new entry points if a css file is added. - const watcher = chokidar.watch(inputFilesGlob); - watcher.on("ready", () => { - ready = true; // Initial scan is over -> waiting for new files - }); - watcher.on("add", async path => { - if (ready) { - // new file - ctx.dispose(); - config = await getConfig(inputFilesGlob, tsMode); - ctx = await esbuild.context(config); - ctx.watch(); - } - }); + // when new component css files are added, they do not trigger a build as no one directly imports them + // restart the watch mode with the new entry points if a css file is added. + const watcher = chokidar.watch(inputFilesGlob); + watcher.on("ready", () => { + ready = true; // Initial scan is over -> waiting for new files + }); + watcher.on("add", async path => { + if (ready) { + // new file + ctx.dispose(); + config = await getConfig(inputFilesGlob, tsMode); + ctx = await esbuild.context(config); + ctx.watch(); + } + }); - return { ctx, watcher }; - } else { - const config = await getConfig(inputFilesGlob, tsMode); - const result = await esbuild.build(config); - return result; - } + return { ctx, watcher }; + } else { + const config = await getConfig(inputFilesGlob, tsMode); + const result = await esbuild.build(config); + return result; + } }; export default processComponents; diff --git a/packages/tools/lib/css-processors/css-processor-themes.mjs b/packages/tools/lib/css-processors/css-processor-themes.mjs index 56d76c443945..da5e6688b6c9 100644 --- a/packages/tools/lib/css-processors/css-processor-themes.mjs +++ b/packages/tools/lib/css-processors/css-processor-themes.mjs @@ -45,7 +45,6 @@ const createScopingPlugin = (packageJSON, tsMode = false) => { // JSON const jsonPath = f.path.replace(/dist[\/\\]css/, "dist/generated/assets").replace(".css", ".css.json"); - await writeFileIfChanged(jsonPath, JSON.stringify(newText)); // JS/TS const jsPath = f.path.replace(/dist[\/\\]css/, "src/generated/").replace(".css", extension); From 969c005bfafac9179370f83a2155f443ad368075 Mon Sep 17 00:00:00 2001 From: Nayden Naydenov Date: Fri, 29 Aug 2025 16:13:33 +0300 Subject: [PATCH 07/10] chore: clean --- packages/tools/lib/create-icons/index.js | 2 +- packages/tools/lib/create-illustrations/index.js | 4 ++-- .../tools/lib/css-processors/css-processor-components.mjs | 2 +- packages/tools/lib/css-processors/css-processor-themes.mjs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/tools/lib/create-icons/index.js b/packages/tools/lib/create-icons/index.js index 7cbdf6c5a74f..97d98a5134a9 100644 --- a/packages/tools/lib/create-icons/index.js +++ b/packages/tools/lib/create-icons/index.js @@ -107,7 +107,7 @@ export { getPathData, ltr, accData };` } } - return Promise.all(promises); + return Promise.allSettled(promises); }; const isDefaultCollection = collectionName => collectionName === "SAP-icons-v4" || collectionName === "SAP-icons-v5"; diff --git a/packages/tools/lib/create-illustrations/index.js b/packages/tools/lib/create-illustrations/index.js index e37d310a471a..8d19a63a64c9 100644 --- a/packages/tools/lib/create-illustrations/index.js +++ b/packages/tools/lib/create-illustrations/index.js @@ -172,14 +172,14 @@ export { dialogSvg, sceneSvg, spotSvg, dotSvg };` } }); - return Promise.all(promises).then(() => { + return Promise.allSettled(promises).then(() => { const nestedPromises = []; for (let illustrationName of fileNames) { nestedPromises.push(fs.writeFile(path.join(destPath, `${illustrationName}.js`), illustrationImportTemplate(illustrationName))); nestedPromises.push(fs.writeFile(path.join(destPath, `${illustrationName}.d.ts`), illustrationTypeDefinition(illustrationName))); } - return Promise.all(nestedPromises); + return Promise.allSettled(nestedPromises); }); }; diff --git a/packages/tools/lib/css-processors/css-processor-components.mjs b/packages/tools/lib/css-processors/css-processor-components.mjs index c9045b73f4e9..9fb86e715b83 100644 --- a/packages/tools/lib/css-processors/css-processor-components.mjs +++ b/packages/tools/lib/css-processors/css-processor-components.mjs @@ -33,7 +33,7 @@ const createCustomPlugin = (packageJSON, tsMode = false) => { ]); }); -await Promise.all(fileProcessingPromises); + await Promise.allSettled(fileProcessingPromises); }) }, }; diff --git a/packages/tools/lib/css-processors/css-processor-themes.mjs b/packages/tools/lib/css-processors/css-processor-themes.mjs index da5e6688b6c9..c1cb26119e72 100644 --- a/packages/tools/lib/css-processors/css-processor-themes.mjs +++ b/packages/tools/lib/css-processors/css-processor-themes.mjs @@ -62,7 +62,7 @@ const createScopingPlugin = (packageJSON, tsMode = false) => { ]) }); - await Promise.all(fileProcessingPromises); + await Promise.allSettled(fileProcessingPromises); }) }, }; From 42b1ccefe16cf4731a982d095fb961dc0bf81899 Mon Sep 17 00:00:00 2001 From: Nayden Naydenov Date: Fri, 29 Aug 2025 16:15:37 +0300 Subject: [PATCH 08/10] chore: clean --- packages/tools/lib/create-icons/index.js | 2 +- packages/tools/lib/create-illustrations/index.js | 4 ++-- .../tools/lib/css-processors/css-processor-components.mjs | 2 +- packages/tools/lib/css-processors/css-processor-themes.mjs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/tools/lib/create-icons/index.js b/packages/tools/lib/create-icons/index.js index 97d98a5134a9..7cbdf6c5a74f 100644 --- a/packages/tools/lib/create-icons/index.js +++ b/packages/tools/lib/create-icons/index.js @@ -107,7 +107,7 @@ export { getPathData, ltr, accData };` } } - return Promise.allSettled(promises); + return Promise.all(promises); }; const isDefaultCollection = collectionName => collectionName === "SAP-icons-v4" || collectionName === "SAP-icons-v5"; diff --git a/packages/tools/lib/create-illustrations/index.js b/packages/tools/lib/create-illustrations/index.js index 8d19a63a64c9..e37d310a471a 100644 --- a/packages/tools/lib/create-illustrations/index.js +++ b/packages/tools/lib/create-illustrations/index.js @@ -172,14 +172,14 @@ export { dialogSvg, sceneSvg, spotSvg, dotSvg };` } }); - return Promise.allSettled(promises).then(() => { + return Promise.all(promises).then(() => { const nestedPromises = []; for (let illustrationName of fileNames) { nestedPromises.push(fs.writeFile(path.join(destPath, `${illustrationName}.js`), illustrationImportTemplate(illustrationName))); nestedPromises.push(fs.writeFile(path.join(destPath, `${illustrationName}.d.ts`), illustrationTypeDefinition(illustrationName))); } - return Promise.allSettled(nestedPromises); + return Promise.all(nestedPromises); }); }; diff --git a/packages/tools/lib/css-processors/css-processor-components.mjs b/packages/tools/lib/css-processors/css-processor-components.mjs index 9fb86e715b83..f4584d26f7de 100644 --- a/packages/tools/lib/css-processors/css-processor-components.mjs +++ b/packages/tools/lib/css-processors/css-processor-components.mjs @@ -33,7 +33,7 @@ const createCustomPlugin = (packageJSON, tsMode = false) => { ]); }); - await Promise.allSettled(fileProcessingPromises); + await Promise.all(fileProcessingPromises); }) }, }; diff --git a/packages/tools/lib/css-processors/css-processor-themes.mjs b/packages/tools/lib/css-processors/css-processor-themes.mjs index c1cb26119e72..da5e6688b6c9 100644 --- a/packages/tools/lib/css-processors/css-processor-themes.mjs +++ b/packages/tools/lib/css-processors/css-processor-themes.mjs @@ -62,7 +62,7 @@ const createScopingPlugin = (packageJSON, tsMode = false) => { ]) }); - await Promise.allSettled(fileProcessingPromises); + await Promise.all(fileProcessingPromises); }) }, }; From ff7ee865559d579e73cfdc33060625c8da96d3fa Mon Sep 17 00:00:00 2001 From: Nayden Naydenov Date: Fri, 29 Aug 2025 16:39:22 +0300 Subject: [PATCH 09/10] chore: fix --- packages/tools/lib/css-processors/css-processor-components.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/tools/lib/css-processors/css-processor-components.mjs b/packages/tools/lib/css-processors/css-processor-components.mjs index f4584d26f7de..a813721006b4 100644 --- a/packages/tools/lib/css-processors/css-processor-components.mjs +++ b/packages/tools/lib/css-processors/css-processor-components.mjs @@ -19,7 +19,6 @@ const createCustomPlugin = (packageJSON, tsMode = false) => { const fileProcessingPromises = result.outputFiles.map(async (f) => { let newText = scopeVariables(f.text, packageJSON); newText = newText.replaceAll(/\\/g, "\\\\"); // Escape backslashes as they might appear in css rules - writeFile(f.path, newText); // JS/TS const jsPath = f.path.replace(/dist[\/\\]css/, "src/generated/").replace(".css", extension); From 7c22ea9f8f0345eb6ee9d537eb3c788e27a6f08b Mon Sep 17 00:00:00 2001 From: Nayden Naydenov Date: Fri, 29 Aug 2025 16:50:07 +0300 Subject: [PATCH 10/10] chore: fix --- packages/tools/components-package/custom-runner-commands.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/tools/components-package/custom-runner-commands.js b/packages/tools/components-package/custom-runner-commands.js index 9406e9d5370d..005bca836020 100644 --- a/packages/tools/components-package/custom-runner-commands.js +++ b/packages/tools/components-package/custom-runner-commands.js @@ -212,7 +212,6 @@ const getScripts = (options) => { runner.addTask("build:jsImports", { dependencies: [ - "mkdir -p src/generated/js-imports", "build:jsImports:illustrationsLoaders" ], parallel: false, // ???