diff --git a/lib/tasks/generateThemeDesignerResources.js b/lib/tasks/generateThemeDesignerResources.js
index 94cf720b6..f8f75c4fa 100644
--- a/lib/tasks/generateThemeDesignerResources.js
+++ b/lib/tasks/generateThemeDesignerResources.js
@@ -3,6 +3,37 @@ const log = require("@ui5/logger").getLogger("builder:tasks:generateThemeDesigne
const libraryLessGenerator = require("../processors/libraryLessGenerator");
const {ReaderCollectionPrioritized, Resource, fsInterface} = require("@ui5/fs");
+/**
+ * Returns a relative path from the given themeFolder to the root namespace.
+ *
+ * When combining the given themeFolder with the returned relative path it
+ * resolves to "/resources/". However the "/resources/" part is not important
+ * here as it doesn't exist within the theming engine environment where the
+ * UI5 resources are part of a "UI5" folder (e.g. "UI5/sap/ui/core/") that
+ * is next to a "Base" folder.
+ *
+ * @example
+ * getPathToRoot("/resources/sap/ui/foo/themes/base")
+ * > "../../../../../"
+ *
+ * @param {string} themeFolder Virtual path including /resources/
+ * @returns {string} Relative path to root namespace
+ */
+function getPathToRoot(themeFolder) {
+ // -2 for initial "/"" and "resources/"
+ return "../".repeat(themeFolder.split("/").length - 2);
+}
+
+/**
+ * Generates an less import statement for the given filePath
+ *
+ * @param {string} filePath The path to the desired file
+ * @returns {string} The less import statement
+ */
+function lessImport(filePath) {
+ return `@import "${filePath}";\n`;
+}
+
function generateLibraryDotTheming({namespace, version, hasThemes}) {
const dotTheming = {
sEntity: "Library",
@@ -80,6 +111,82 @@ async function generateThemeDotTheming({workspace, combo, themeFolder}) {
return newDotThemingResource;
}
+async function createCssVariablesLessResource({workspace, combo, themeFolder}) {
+ const pathToRoot = getPathToRoot(themeFolder);
+ const cssVariablesSourceLessFile = "css_variables.source.less";
+ const cssVariablesLessFile = "css_variables.less";
+
+ // posix as it is a virtual path (separated with /)
+ const themeName = posixPath.basename(themeFolder);
+ // The "base" theme of the baseLib is called "baseTheme"
+ const baseLibThemeName = themeName === "base" ? "baseTheme" : themeName;
+
+ // Some themes do not have a base.less file (e.g. sap_hcb)
+ const hasBaseLess = !!(await combo.byPath(`/resources/sap/ui/core/themes/${themeName}/base.less`));
+
+ let cssVariablesLess =
+`/* NOTE: This file was generated as an optimized version of "${cssVariablesSourceLessFile}" \
+for the Theme Designer. */\n\n`;
+
+ if (themeName !== "base") {
+ const cssVariablesSourceLessResource = await workspace.byPath(
+ posixPath.join(themeFolder, cssVariablesSourceLessFile)
+ );
+
+ if (!cssVariablesSourceLessResource) {
+ throw new Error(`Could not find file "${cssVariablesSourceLessFile}" in theme "${themeFolder}"`);
+ }
+
+ const cssVariablesSourceLess = await cssVariablesSourceLessResource.getString();
+
+ cssVariablesLess += lessImport(`../base/${cssVariablesLessFile}`);
+ cssVariablesLess += `
+/* START "${cssVariablesSourceLessFile}" */
+${cssVariablesSourceLess}
+/* END "${cssVariablesSourceLessFile}" */
+
+`;
+ }
+
+ if (hasBaseLess) {
+ cssVariablesLess += lessImport(`${pathToRoot}../Base/baseLib/${baseLibThemeName}/base.less`);
+ }
+ cssVariablesLess += lessImport(`${pathToRoot}sap/ui/core/themes/${themeName}/global.less`);
+
+ return new Resource({
+ path: posixPath.join(themeFolder, cssVariablesLessFile),
+ string: cssVariablesLess
+ });
+}
+
+async function generateCssVariablesLess({workspace, combo, namespace}) {
+ let cssVariablesSourceLessResourcePattern;
+ if (namespace) {
+ // In case of a library only check for themes directly below the namespace
+ cssVariablesSourceLessResourcePattern = `/resources/${namespace}/themes/*/css_variables.source.less`;
+ } else {
+ // In case of a theme-library check for all "themes"
+ cssVariablesSourceLessResourcePattern = `/resources/**/themes/*/css_variables.source.less`;
+ }
+
+ const cssVariablesSourceLessResource = await workspace.byGlob(cssVariablesSourceLessResourcePattern);
+
+ const hasCssVariables = cssVariablesSourceLessResource.length > 0;
+
+ if (hasCssVariables) {
+ await Promise.all(
+ cssVariablesSourceLessResource.map(async (cssVariableSourceLess) => {
+ const themeFolder = posixPath.dirname(cssVariableSourceLess.getPath());
+ log.verbose(`Generating css_variables.less for theme ${themeFolder}`);
+ const r = await createCssVariablesLessResource({
+ workspace, combo, themeFolder
+ });
+ return await workspace.write(r);
+ })
+ );
+ }
+}
+
/**
* Generates resources required for integration with the SAP Theme Designer.
*
@@ -163,4 +270,7 @@ module.exports = async function({workspace, dependencies, options: {projectName,
await Promise.all(
libraryLessResources.map((resource) => workspace.write(resource))
);
+
+ // css_variables.less
+ await generateCssVariablesLess({workspace, combo, namespace});
};
diff --git a/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/.theming b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/.theming
new file mode 100644
index 000000000..d4edad9a4
--- /dev/null
+++ b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/.theming
@@ -0,0 +1,5 @@
+{
+ "sEntity": "Library",
+ "sId": "theme/j",
+ "sVersion": "1.0.0"
+}
\ No newline at end of file
diff --git a/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/.theming b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/.theming
new file mode 100644
index 000000000..4878adda8
--- /dev/null
+++ b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/.theming
@@ -0,0 +1,6 @@
+{
+ "sEntity": "Theme",
+ "sId": "somefancytheme",
+ "sVendor": "SAP",
+ "oExtends": "base"
+}
\ No newline at end of file
diff --git a/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/Button.less b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/Button.less
new file mode 100644
index 000000000..ca968183f
--- /dev/null
+++ b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/Button.less
@@ -0,0 +1,3 @@
+.someClass {
+ color: @someColor
+}
diff --git a/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/css_variables.css b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/css_variables.css
new file mode 100644
index 000000000..6232d9e35
--- /dev/null
+++ b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/css_variables.css
@@ -0,0 +1,3 @@
+:root{--someColor:#000}
+/* Inline theming parameters */
+#sap-ui-theme-theme\.j{background-image:url('data:text/plain;utf-8,%7B%22someColor%22%3A%22%23000%22%7D')}
diff --git a/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/css_variables.less b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/css_variables.less
new file mode 100644
index 000000000..91ce28694
--- /dev/null
+++ b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/css_variables.less
@@ -0,0 +1,14 @@
+/* NOTE: This file was generated as an optimized version of "css_variables.source.less" for the Theme Designer. */
+
+@import "../base/css_variables.less";
+
+/* START "css_variables.source.less" */
+@someColor: #000000;
+
+:root {
+--someColor: @someColor;
+}
+
+/* END "css_variables.source.less" */
+
+@import "../../../../sap/ui/core/themes/somefancytheme/global.less";
diff --git a/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/css_variables.source.less b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/css_variables.source.less
new file mode 100644
index 000000000..5a6ce08e9
--- /dev/null
+++ b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/css_variables.source.less
@@ -0,0 +1,5 @@
+@someColor: #000000;
+
+:root {
+--someColor: @someColor;
+}
diff --git a/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library-RTL.css b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library-RTL.css
new file mode 100644
index 000000000..5009ca50e
--- /dev/null
+++ b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library-RTL.css
@@ -0,0 +1,3 @@
+.someClass{color:#000}
+/* Inline theming parameters */
+#sap-ui-theme-theme\.j{background-image:url('data:text/plain;utf-8,%7B%22someColor%22%3A%22%23000%22%7D')}
diff --git a/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library-parameters.json b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library-parameters.json
new file mode 100644
index 000000000..a190cda03
--- /dev/null
+++ b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library-parameters.json
@@ -0,0 +1 @@
+{"someColor":"#000"}
\ No newline at end of file
diff --git a/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library.css b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library.css
new file mode 100644
index 000000000..5009ca50e
--- /dev/null
+++ b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library.css
@@ -0,0 +1,3 @@
+.someClass{color:#000}
+/* Inline theming parameters */
+#sap-ui-theme-theme\.j{background-image:url('data:text/plain;utf-8,%7B%22someColor%22%3A%22%23000%22%7D')}
diff --git a/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library.less b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library.less
new file mode 100644
index 000000000..24c4ca167
--- /dev/null
+++ b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library.less
@@ -0,0 +1,10 @@
+/* NOTE: This file was generated as an optimized version of "library.source.less" for the Theme Designer. */
+
+@someColor: black;
+/* START "Button.less" */
+.someClass {
+ color: @someColor
+}
+
+/* END "Button.less" */
+
diff --git a/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library.source.less b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library.source.less
new file mode 100644
index 000000000..834de919e
--- /dev/null
+++ b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library.source.less
@@ -0,0 +1,2 @@
+@someColor: black;
+@import "Button.less";
diff --git a/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library_skeleton-RTL.css b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library_skeleton-RTL.css
new file mode 100644
index 000000000..7db086289
--- /dev/null
+++ b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library_skeleton-RTL.css
@@ -0,0 +1 @@
+.someClass{color:var(--someColor)}
\ No newline at end of file
diff --git a/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library_skeleton.css b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library_skeleton.css
new file mode 100644
index 000000000..7db086289
--- /dev/null
+++ b/test/expected/build/theme.j/dest-css-variables-theme-designer-resources/resources/theme/j/themes/somefancytheme/library_skeleton.css
@@ -0,0 +1 @@
+.someClass{color:var(--someColor)}
\ No newline at end of file
diff --git a/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/.theme b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/.theme
new file mode 100644
index 000000000..4b4b1cf98
--- /dev/null
+++ b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/.theme
@@ -0,0 +1,9 @@
+
+
+
+ my_theme
+ me
+ Some fancy copyright
+ 1.0.0
+
+
\ No newline at end of file
diff --git a/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/.theming b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/.theming
new file mode 100644
index 000000000..184073476
--- /dev/null
+++ b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/.theming
@@ -0,0 +1,6 @@
+{
+ "sEntity": "Theme",
+ "sId": "my_theme",
+ "sVendor": "SAP",
+ "oExtends": "base"
+}
\ No newline at end of file
diff --git a/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/css_variables.css b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/css_variables.css
new file mode 100644
index 000000000..48bb66a3e
--- /dev/null
+++ b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/css_variables.css
@@ -0,0 +1,3 @@
+:root{--mycolor:#00f}
+/* Inline theming parameters */
+#sap-ui-theme-theme\.library\.e{background-image:url('data:text/plain;utf-8,%7B%22mycolor%22%3A%22%2300f%22%7D')}
diff --git a/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/css_variables.less b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/css_variables.less
new file mode 100644
index 000000000..41b1dc48e
--- /dev/null
+++ b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/css_variables.less
@@ -0,0 +1,14 @@
+/* NOTE: This file was generated as an optimized version of "css_variables.source.less" for the Theme Designer. */
+
+@import "../base/css_variables.less";
+
+/* START "css_variables.source.less" */
+@mycolor: #0000ff;
+
+:root {
+--mycolor: @mycolor;
+}
+
+/* END "css_variables.source.less" */
+
+@import "../../../../../sap/ui/core/themes/my_theme/global.less";
diff --git a/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/css_variables.source.less b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/css_variables.source.less
new file mode 100644
index 000000000..28ed8727a
--- /dev/null
+++ b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/css_variables.source.less
@@ -0,0 +1,5 @@
+@mycolor: #0000ff;
+
+:root {
+--mycolor: @mycolor;
+}
diff --git a/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library-RTL.css b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library-RTL.css
new file mode 100644
index 000000000..5eac03f06
--- /dev/null
+++ b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library-RTL.css
@@ -0,0 +1,5 @@
+/*!
+ * Some fancy copyright
+ */.sapUiBody{background-color:#00f}
+/* Inline theming parameters */
+#sap-ui-theme-theme\.library\.e{background-image:url('data:text/plain;utf-8,%7B%22mycolor%22%3A%22%2300f%22%7D')}
diff --git a/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library-parameters.json b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library-parameters.json
new file mode 100644
index 000000000..a0c491380
--- /dev/null
+++ b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library-parameters.json
@@ -0,0 +1 @@
+{"mycolor":"#00f"}
\ No newline at end of file
diff --git a/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library.css b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library.css
new file mode 100644
index 000000000..5eac03f06
--- /dev/null
+++ b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library.css
@@ -0,0 +1,5 @@
+/*!
+ * Some fancy copyright
+ */.sapUiBody{background-color:#00f}
+/* Inline theming parameters */
+#sap-ui-theme-theme\.library\.e{background-image:url('data:text/plain;utf-8,%7B%22mycolor%22%3A%22%2300f%22%7D')}
diff --git a/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library.less b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library.less
new file mode 100644
index 000000000..f3fda6d3e
--- /dev/null
+++ b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library.less
@@ -0,0 +1,11 @@
+/* NOTE: This file was generated as an optimized version of "library.source.less" for the Theme Designer. */
+
+/*!
+ * Some fancy copyright
+ */
+
+@mycolor: blue;
+
+.sapUiBody {
+ background-color: @mycolor;
+}
diff --git a/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library.source.less b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library.source.less
new file mode 100644
index 000000000..d864e666d
--- /dev/null
+++ b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library.source.less
@@ -0,0 +1,9 @@
+/*!
+ * Some fancy copyright
+ */
+
+@mycolor: blue;
+
+.sapUiBody {
+ background-color: @mycolor;
+}
diff --git a/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library_skeleton-RTL.css b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library_skeleton-RTL.css
new file mode 100644
index 000000000..654b3877e
--- /dev/null
+++ b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library_skeleton-RTL.css
@@ -0,0 +1,3 @@
+/*!
+ * Some fancy copyright
+ */.sapUiBody{background-color:var(--mycolor)}
\ No newline at end of file
diff --git a/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library_skeleton.css b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library_skeleton.css
new file mode 100644
index 000000000..654b3877e
--- /dev/null
+++ b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/resources/theme/library/e/themes/my_theme/library_skeleton.css
@@ -0,0 +1,3 @@
+/*!
+ * Some fancy copyright
+ */.sapUiBody{background-color:var(--mycolor)}
\ No newline at end of file
diff --git a/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/test-resources/theme/library/e/Test.html b/test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources/test-resources/theme/library/e/Test.html
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/lib/builder/builder.js b/test/lib/builder/builder.js
index 1561f4e80..6153b353b 100644
--- a/test/lib/builder/builder.js
+++ b/test/lib/builder/builder.js
@@ -952,6 +952,26 @@ test.serial("Build library with theme configured for CSS variables", (t) => {
});
});
+test.serial("Build library with theme configured for CSS variables and theme designer resources", (t) => {
+ const destPath = "./test/tmp/build/theme.j/dest-css-variables-theme-designer-resources";
+ const expectedPath = "./test/expected/build/theme.j/dest-css-variables-theme-designer-resources";
+ return builder.build({
+ tree: themeJTree,
+ cssVariables: true,
+ destPath,
+ includedTasks: ["generateThemeDesignerResources"]
+ }).then(() => {
+ return findFiles(expectedPath);
+ }).then((expectedFiles) => {
+ // Check for all directories and files
+ assert.directoryDeepEqual(destPath, expectedPath);
+
+ return checkFileContentsIgnoreLineFeeds(t, expectedFiles, expectedPath, destPath);
+ }).then(() => {
+ t.pass();
+ });
+});
+
test.serial("Build theme-library with CSS variables", (t) => {
const destPath = "./test/tmp/build/theme.library.e/dest-css-variables";
const expectedPath = "./test/expected/build/theme.library.e/dest-css-variables";
@@ -971,6 +991,26 @@ test.serial("Build theme-library with CSS variables", (t) => {
});
});
+test.serial("Build theme-library with CSS variables and theme designer resources", (t) => {
+ const destPath = "./test/tmp/build/theme.library.e/dest-css-variables-theme-designer-resources";
+ const expectedPath = "./test/expected/build/theme.library.e/dest-css-variables-theme-designer-resources";
+ return builder.build({
+ tree: themeLibraryETree,
+ cssVariables: true,
+ destPath,
+ includedTasks: ["generateThemeDesignerResources"]
+ }).then(() => {
+ return findFiles(expectedPath);
+ }).then((expectedFiles) => {
+ // Check for all directories and files
+ assert.directoryDeepEqual(destPath, expectedPath);
+
+ return checkFileContentsIgnoreLineFeeds(t, expectedFiles, expectedPath, destPath);
+ }).then(() => {
+ t.pass();
+ });
+});
+
test.serial("Cleanup", async (t) => {
const BuildContext = require("../../../lib/builder/BuildContext");
const createProjectContextStub = sinon.spy(BuildContext.prototype, "createProjectContext");
diff --git a/test/lib/tasks/generateThemeDesignerResources.js b/test/lib/tasks/generateThemeDesignerResources.js
index 5961ca6d4..3f4a20b14 100644
--- a/test/lib/tasks/generateThemeDesignerResources.js
+++ b/test/lib/tasks/generateThemeDesignerResources.js
@@ -409,6 +409,329 @@ test.serial("generateThemeDesignerResources: Theme-Library", async (t) => {
"workspace.write should be called with libraryLessResource");
});
+test.serial("generateThemeDesignerResources: Theme-Library with CSS Variables", async (t) => {
+ const {generateThemeDesignerResources, libraryLessGeneratorStub, ResourceStub} = t.context;
+
+ const librarySourceLessResource = {
+ getPath: sinon.stub().returns("/resources/sap/ui/demo/lib/themes/my_theme/library.source.less")
+ };
+
+ const cssVariablesSourceResource = {
+ getString: sinon.stub().returns("My Content"),
+ };
+
+ const cssVariableSourceLessResource = {
+ getPath: sinon.stub().returns("/resources/sap/ui/demo/lib/themes/my_theme/css_variables.source.less")
+ };
+
+ const workspace = {
+ byGlob: sinon.stub().callsFake(async (globPattern) => {
+ if (globPattern === "/resources/**/themes/*/library.source.less") {
+ return [librarySourceLessResource];
+ } else if (globPattern === "/resources/**/themes/*/css_variables.source.less") {
+ return [cssVariableSourceLessResource];
+ } else {
+ return [];
+ }
+ }),
+ byPath: sinon.stub().callsFake(async (virPath) => {
+ if (virPath === "/resources/sap/ui/demo/lib/themes/my_theme/css_variables.source.less") {
+ return cssVariablesSourceResource;
+ } else {
+ return [];
+ }
+ }),
+ write: sinon.stub()
+ };
+ const dependencies = {};
+
+ const libraryLessResource = {};
+
+ libraryLessGeneratorStub.resolves([libraryLessResource]);
+
+ await generateThemeDesignerResources({
+ workspace,
+ dependencies,
+ options: {
+ projectName: "sap.ui.demo.lib",
+ version: "1.2.3"
+ }
+ });
+
+ t.is(ResourceStub.callCount, 2);
+ t.true(ResourceStub.alwaysCalledWithNew());
+
+ t.deepEqual(ResourceStub.getCall(1).args, [{
+ path: "/resources/sap/ui/demo/lib/themes/my_theme/css_variables.less",
+ string:
+`/* NOTE: This file was generated as an optimized version of "css_variables.source.less" for the Theme Designer. */
+
+@import "../base/css_variables.less";
+
+/* START "css_variables.source.less" */
+My Content
+/* END "css_variables.source.less" */
+
+@import "../../../../../../sap/ui/core/themes/my_theme/global.less";
+`
+ }]);
+ const cssVariableResource = ResourceStub.getCall(1).returnValue;
+
+ t.is(workspace.write.callCount, 3);
+ t.is(workspace.write.getCall(2).args.length, 1,
+ "workspace.write for cssVariableResource should be called with 1 argument");
+ t.is(workspace.write.getCall(2).args[0], cssVariableResource,
+ "workspace.write should be called with cssVariableResource");
+});
+
+test.serial("generateThemeDesignerResources: Theme-Library with CSS Variables with namespace", async (t) => {
+ const {generateThemeDesignerResources, libraryLessGeneratorStub, ResourceStub} = t.context;
+
+ const librarySourceLessResource = {
+ getPath: sinon.stub().returns("/resources/sap/ui/demo/lib/themes/my_theme/library.source.less")
+ };
+
+ const cssVariablesSourceResource = {
+ getString: sinon.stub().returns("My Content from Namespace"),
+ };
+
+ const cssVariableSourceLessResource = {
+ getPath: sinon.stub().returns("/resources/sap/ui/demo/lib/themes/my_theme/css_variables.source.less")
+ };
+
+ const workspace = {
+ byGlob: sinon.stub().callsFake(async (globPattern) => {
+ if (globPattern === "/resources/sap/ui/demo/lib/themes/*/library.source.less") {
+ return [librarySourceLessResource];
+ } else if (globPattern === "/resources/sap/ui/demo/lib/themes/*/css_variables.source.less") {
+ return [cssVariableSourceLessResource];
+ } else {
+ return [];
+ }
+ }),
+ byPath: sinon.stub().callsFake(async (virPath) => {
+ if (virPath === "/resources/sap/ui/demo/lib/themes/my_theme/css_variables.source.less") {
+ return cssVariablesSourceResource;
+ } else {
+ return [];
+ }
+ }),
+ write: sinon.stub()
+ };
+ const dependencies = {};
+
+ const libraryLessResource = {};
+
+ libraryLessGeneratorStub.resolves([libraryLessResource]);
+
+ await generateThemeDesignerResources({
+ workspace,
+ dependencies,
+ options: {
+ projectName: "sap.ui.demo.lib",
+ version: "1.2.3",
+ namespace: "sap/ui/demo/lib"
+ }
+ });
+
+ t.is(t.context.ReaderCollectionPrioritizedStub.callCount, 1, "ReaderCollectionPrioritized should be created once");
+ t.deepEqual(t.context.ReaderCollectionPrioritizedStub.getCall(0).args, [{
+ name: `generateThemeDesignerResources - prioritize workspace over dependencies: sap.ui.demo.lib`,
+ readers: [workspace, dependencies]
+ }]);
+
+ t.is(ResourceStub.callCount, 3);
+ t.true(ResourceStub.alwaysCalledWithNew());
+
+ t.deepEqual(ResourceStub.getCall(2).args, [{
+ path: "/resources/sap/ui/demo/lib/themes/my_theme/css_variables.less",
+ string:
+`/* NOTE: This file was generated as an optimized version of "css_variables.source.less" for the Theme Designer. */
+
+@import "../base/css_variables.less";
+
+/* START "css_variables.source.less" */
+My Content from Namespace
+/* END "css_variables.source.less" */
+
+@import "../../../../../../sap/ui/core/themes/my_theme/global.less";
+`
+ }]);
+ const cssVariableResource = ResourceStub.getCall(2).returnValue;
+
+ t.is(workspace.write.callCount, 4);
+ t.is(workspace.write.getCall(3).args.length, 1,
+ "workspace.write for cssVariableResource should be called with 1 argument");
+ t.is(workspace.write.getCall(3).args[0], cssVariableResource,
+ "workspace.write should be called with cssVariableResource");
+});
+
+test.serial("generateThemeDesignerResources: Theme-Library with CSS Variables with base theme", async (t) => {
+ const {
+ generateThemeDesignerResources,
+ libraryLessGeneratorStub,
+ ResourceStub,
+ ReaderCollectionPrioritizedStub
+ } = t.context;
+
+ const librarySourceLessResource = {
+ getPath: sinon.stub().returns("/resources/sap/ui/demo/lib/themes/my_theme/library.source.less")
+ };
+
+ const cssVariablesSourceResource = {
+ getString: sinon.stub().returns("My Content with Base Theme"),
+ };
+
+ const cssVariableSourceLessResource = {
+ getPath: sinon.stub().returns("/resources/sap/ui/demo/lib/themes/my_theme/css_variables.source.less")
+ };
+
+ const baseLessResource = {};
+
+ ReaderCollectionPrioritizedStub.returns({
+ byPath: sinon.stub().callsFake(async (virPath) => {
+ if (virPath === "/resources/sap/ui/core/themes/my_theme/base.less") {
+ return baseLessResource;
+ } else {
+ return null;
+ }
+ })
+ });
+
+ const workspace = {
+ byGlob: sinon.stub().callsFake(async (globPattern) => {
+ if (globPattern === "/resources/**/themes/*/library.source.less") {
+ return [librarySourceLessResource];
+ } else if (globPattern === "/resources/**/themes/*/css_variables.source.less") {
+ return [cssVariableSourceLessResource];
+ } else {
+ return [];
+ }
+ }),
+ byPath: sinon.stub().callsFake(async (virPath) => {
+ if (virPath === "/resources/sap/ui/demo/lib/themes/my_theme/css_variables.source.less") {
+ return cssVariablesSourceResource;
+ } else {
+ return [];
+ }
+ }),
+ write: sinon.stub()
+ };
+ const dependencies = {};
+
+ const libraryLessResource = {};
+
+ libraryLessGeneratorStub.resolves([libraryLessResource]);
+
+ await generateThemeDesignerResources({
+ workspace,
+ dependencies,
+ options: {
+ projectName: "sap.ui.demo.lib",
+ version: "1.2.3"
+ }
+ });
+
+ t.is(ResourceStub.callCount, 2);
+ t.true(ResourceStub.alwaysCalledWithNew());
+
+ t.deepEqual(ResourceStub.getCall(1).args, [{
+ path: "/resources/sap/ui/demo/lib/themes/my_theme/css_variables.less",
+ string:
+`/* NOTE: This file was generated as an optimized version of "css_variables.source.less" for the Theme Designer. */
+
+@import "../base/css_variables.less";
+
+/* START "css_variables.source.less" */
+My Content with Base Theme
+/* END "css_variables.source.less" */
+
+@import "../../../../../../../Base/baseLib/my_theme/base.less";
+@import "../../../../../../sap/ui/core/themes/my_theme/global.less";
+`
+ }]);
+ const cssVariableResource = ResourceStub.getCall(1).returnValue;
+
+ t.is(workspace.write.callCount, 3);
+ t.is(workspace.write.getCall(2).args.length, 1,
+ "workspace.write for cssVariableResource should be called with 1 argument");
+ t.is(workspace.write.getCall(2).args[0], cssVariableResource,
+ "workspace.write should be called with cssVariableResource");
+});
+
+test.serial("generateThemeDesignerResources: Base Theme-Library with CSS Variables", async (t) => {
+ const {
+ generateThemeDesignerResources,
+ libraryLessGeneratorStub,
+ ResourceStub
+ } = t.context;
+
+ const librarySourceLessResource = {
+ getPath: sinon.stub().returns("/resources/sap/ui/demo/lib/themes/base/library.source.less")
+ };
+
+ const cssVariablesSourceResource = {
+ getString: sinon.stub().returns("My Base Theme Content"),
+ };
+
+ const cssVariableSourceLessResource = {
+ getPath: sinon.stub().returns("/resources/sap/ui/demo/lib/themes/base/css_variables.source.less")
+ };
+
+ const workspace = {
+ byGlob: sinon.stub().callsFake(async (globPattern) => {
+ if (globPattern === "/resources/**/themes/*/library.source.less") {
+ return [librarySourceLessResource];
+ } else if (globPattern === "/resources/**/themes/*/css_variables.source.less") {
+ return [cssVariableSourceLessResource];
+ } else {
+ return [];
+ }
+ }),
+ byPath: sinon.stub().callsFake(async (virPath) => {
+ if (virPath === "/resources/sap/ui/demo/lib/themes/my_theme/css_variables.source.less") {
+ return cssVariablesSourceResource;
+ } else {
+ return [];
+ }
+ }),
+ write: sinon.stub()
+ };
+ const dependencies = {};
+
+ const libraryLessResource = {};
+
+ libraryLessGeneratorStub.resolves([libraryLessResource]);
+
+ await generateThemeDesignerResources({
+ workspace,
+ dependencies,
+ options: {
+ projectName: "sap.ui.demo.lib",
+ version: "1.2.3"
+ }
+ });
+
+ t.is(ResourceStub.callCount, 2);
+ t.true(ResourceStub.alwaysCalledWithNew());
+
+ t.deepEqual(ResourceStub.getCall(1).args, [{
+ path: "/resources/sap/ui/demo/lib/themes/base/css_variables.less",
+ string:
+`/* NOTE: This file was generated as an optimized version of "css_variables.source.less" for the Theme Designer. */
+
+@import "../../../../../../sap/ui/core/themes/base/global.less";
+`
+ }]);
+ const cssVariableResource = ResourceStub.getCall(1).returnValue;
+
+ t.is(workspace.write.callCount, 3);
+ t.is(workspace.write.getCall(2).args.length, 1,
+ "workspace.write for cssVariableResource should be called with 1 argument");
+ t.is(workspace.write.getCall(2).args[0], cssVariableResource,
+ "workspace.write should be called with cssVariableResource");
+});
+
test.serial("generateThemeDesignerResources: .theming file missing in sap.ui.core library source`", async (t) => {
const {generateThemeDesignerResources, libraryLessGeneratorStub, ResourceStub} = t.context;