@ui5/webcomponents-tools 2.19.0-rc.2 → 2.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [2.19.0](https://github.com/UI5/webcomponents/compare/v2.19.0-rc.3...v2.19.0) (2026-02-05)
7
+
8
+ **Note:** Version bump only for package @ui5/webcomponents-tools
9
+
10
+
11
+
12
+
13
+
14
+ # [2.19.0-rc.3](https://github.com/UI5/webcomponents/compare/v2.19.0-rc.2...v2.19.0-rc.3) (2026-02-05)
15
+
16
+ **Note:** Version bump only for package @ui5/webcomponents-tools
17
+
18
+
19
+
20
+
21
+
6
22
  # [2.19.0-rc.2](https://github.com/UI5/webcomponents/compare/v2.19.0-rc.1...v2.19.0-rc.2) (2026-01-22)
7
23
 
8
24
  **Note:** Version bump only for package @ui5/webcomponents-tools
package/bin/dev.js CHANGED
@@ -3,15 +3,20 @@
3
3
  const child_process = require("child_process");
4
4
  const { comma } = require("postcss/lib/list");
5
5
 
6
- let command = process.argv[2];
7
- const argument = process.argv[3];
6
+ // Check for verbose flag
7
+ const hasVerbose = process.argv.includes("--verbose") || process.argv.includes("-v");
8
+ const args = process.argv.slice(2).filter(arg => arg !== "--verbose" && arg !== "-v");
9
+
10
+ let command = args[0];
11
+ const argument = args[1];
8
12
 
9
13
  if (command === "watch") {
10
14
  if (["src", "test", "bundles", "styles", "templates", "samples"].includes(argument)) {
11
15
  command = `watch.${argument}`;
12
16
  }
13
17
  } else if (command === "test") {
14
- command = ["test", ...process.argv.slice(3)].join(" ");
18
+ command = ["test", ...args.slice(1)].join(" ");
15
19
  }
16
20
 
17
- child_process.execSync(`ui5nps "${command}"`, {stdio: 'inherit'});
21
+ const verboseFlag = hasVerbose ? " --verbose" : "";
22
+ child_process.execSync(`ui5nps${verboseFlag} "${command}"`, {stdio: 'inherit'});
package/bin/ui5nps.js CHANGED
@@ -13,6 +13,24 @@ const SCRIPT_NAMES = [
13
13
  "package-scripts.mjs"
14
14
  ]
15
15
 
16
+ /**
17
+ * Check if verbose mode is enabled via CLI flag or environment variable.
18
+ * @returns {boolean}
19
+ */
20
+ function isVerbose() {
21
+ return process.env.UI5_VERBOSE === "true";
22
+ }
23
+
24
+ /**
25
+ * Log a message only in verbose mode.
26
+ * @param {...any} args - Arguments to pass to console.log
27
+ */
28
+ function verboseLog(...args) {
29
+ if (isVerbose()) {
30
+ console.log(...args);
31
+ }
32
+ }
33
+
16
34
  /**
17
35
  * Parser for UI5 package scripts with support for parallel and sequential execution
18
36
  */
@@ -183,7 +201,7 @@ class Parser {
183
201
  return reject(new Error(`No valid _ui5mainFn function exported from ${importPath} tried to be executed with ui5nps-script. Either provide a valid _ui5mainFn function or use another way to execute the script (via node).`));
184
202
  }
185
203
 
186
- console.log(` | Executing command ${commandName} as module.`);
204
+ verboseLog(` | Executing command ${commandName} as module.`);
187
205
  const result = _ui5mainFn(argv);
188
206
 
189
207
  if (result instanceof Promise) {
@@ -193,11 +211,11 @@ class Parser {
193
211
  }
194
212
  }
195
213
 
196
- console.log(` | Executing command ${commandName} as command.\n Running: ${command}`);
214
+ verboseLog(` | Executing command ${commandName} as command.\n Running: ${command}`);
197
215
  const child = exec(command, { stdio: "inherit", env: { ...process.env, ...this.envs } });
198
216
 
199
217
  child.stdout.on("data", (data) => {
200
- console.log(data);
218
+ verboseLog(data);
201
219
  });
202
220
 
203
221
  child.stderr.on("data", (data) => {
@@ -246,16 +264,25 @@ class Parser {
246
264
  const parser = new Parser();
247
265
 
248
266
  // Basic input validation
249
- const commands = process.argv.slice(2);
267
+ const commands = process.argv.slice(2).filter(arg => arg !== "--verbose" && arg !== "-v");
268
+ const verbose = process.argv.includes("--verbose") || process.argv.includes("-v");
269
+
270
+ // Set verbose environment variable for child scripts
271
+ if (verbose) {
272
+ process.env.UI5_VERBOSE = "true";
273
+ }
274
+
250
275
  if (commands.length === 0) {
251
- console.error("Usage: ui5nps <command> [command2] [command3] ...");
276
+ console.error("Usage: ui5nps [--verbose|-v] <command> [command2] [command3] ...");
252
277
  console.error("No commands provided.");
253
278
  process.exit(1);
254
279
  }
255
280
 
256
281
  if (commands.includes("--help") || commands.includes("-h")) {
257
- console.log("Usage: ui5nps <command> [command2] [command3] ...");
258
- console.log("Available commands:");
282
+ console.log("Usage: ui5nps [--verbose|-v] <command> [command2] [command3] ...");
283
+ console.log("\nOptions:");
284
+ console.log(" --verbose, -v Show detailed output (default: quiet, errors only)");
285
+ console.log("\nAvailable commands:");
259
286
  for (const [key, value] of parser.parsedScripts.entries()) {
260
287
  console.log(` - ${key}: ${value}`);
261
288
  }
@@ -70,6 +70,7 @@ const getScripts = (options) => {
70
70
  __ui5envs: {
71
71
  UI5_CEM_MODE: options.dev,
72
72
  UI5_TS: `${tsOption}`,
73
+ CSS_VARIABLES_TARGET: options.cssVariablesTarget ?? "root",
73
74
  CYPRESS_COVERAGE: !!(options.internal?.cypress_code_coverage),
74
75
  },
75
76
  clean: {
@@ -96,7 +96,9 @@ const transformAmdToES6Modules = async (argv) => {
96
96
  const fileNames = await globby(basePath.replace(/\\/g, "/") + "**/*.js");
97
97
  return Promise.all(fileNames.map(fileName => transformAmdToES6Module(fileName, basePath)).filter(x => !!x))
98
98
  .then(() => {
99
- console.log("Success: all amd modules are transformed to es6!");
99
+ if (process.env.UI5_VERBOSE === "true") {
100
+ console.log("Success: all amd modules are transformed to es6!");
101
+ }
100
102
  });
101
103
  };
102
104
 
package/lib/cem/cem.js CHANGED
@@ -2,6 +2,10 @@ const cemCLI = require("./patch/@custom-elements-manifest/analyzer/cli.js")
2
2
 
3
3
  const main = async argv => {
4
4
  const patchedArgv = argv.slice(2);
5
+ // Add --quiet flag unless verbose mode is enabled
6
+ if (process.env.UI5_VERBOSE !== "true" && !patchedArgv.includes("--quiet")) {
7
+ patchedArgv.push("--quiet");
8
+ }
5
9
  await cemCLI.cli({ argv: patchedArgv, cwd: process.cwd(), noWrite: false });
6
10
  }
7
11
 
@@ -17,6 +17,7 @@ import {
17
17
  getTypeRefs,
18
18
  normalizeDescription,
19
19
  formatArrays,
20
+ formatSlotTypes,
20
21
  isClass,
21
22
  normalizeTagType,
22
23
  logDocumentationError,
@@ -30,10 +31,37 @@ const packageJSON = JSON.parse(fs.readFileSync("./package.json"));
30
31
  let aliasMap = {};
31
32
 
32
33
  const devMode = process.env.UI5_CEM_MODE === "dev";
34
+ const isVerbose = process.env.UI5_VERBOSE === "true";
35
+
36
+ /**
37
+ * Wraps a CEM plugin to suppress console output in quiet mode.
38
+ * @param {Object} plugin - The plugin to wrap
39
+ * @returns {Object} - Wrapped plugin with silent console during packageLinkPhase
40
+ */
41
+ const wrapPluginForQuietMode = (plugin) => {
42
+ if (isVerbose) return plugin;
43
+
44
+ const originalPackageLinkPhase = plugin.packageLinkPhase;
45
+ if (!originalPackageLinkPhase) return plugin;
46
+
47
+ return {
48
+ ...plugin,
49
+ packageLinkPhase(context) {
50
+ const originalLog = console.log;
51
+ console.log = () => {};
52
+ try {
53
+ return originalPackageLinkPhase.call(plugin, context);
54
+ } finally {
55
+ console.log = originalLog;
56
+ }
57
+ }
58
+ };
59
+ };
60
+
33
61
  try {
34
62
  aliasMap = JSON.parse(fs.readFileSync("./.ui5-cem-aliases.json"));
35
63
  } catch (e) {
36
- if (devMode) {
64
+ if (devMode && isVerbose) {
37
65
  console.warn("No .ui5-cem-aliases.json file found. Continuing without aliases.");
38
66
  }
39
67
  }
@@ -168,6 +196,7 @@ function processClass(ts, classNode, moduleDoc) {
168
196
 
169
197
  if (member.type?.text) {
170
198
  member.type.text = formatArrays(member.type.text);
199
+ member.type.text = formatSlotTypes(member.type.text);
171
200
  }
172
201
 
173
202
  if (member.type && typeRefs.length) {
@@ -540,7 +569,7 @@ export default {
540
569
  }
541
570
  }
542
571
  },
543
- generateCustomData({ outdir: "dist", cssFileName: null, cssPropertiesDocs: false }),
544
- customElementJetBrainsPlugin({ outdir: "dist", cssFileName: null, cssPropertiesDocs: false })
572
+ wrapPluginForQuietMode(generateCustomData({ outdir: "dist", cssFileName: null, cssPropertiesDocs: false })),
573
+ wrapPluginForQuietMode(customElementJetBrainsPlugin({ outdir: "dist", cssFileName: null, cssPropertiesDocs: false }))
545
574
  ],
546
575
  };
package/lib/cem/utils.mjs CHANGED
@@ -396,7 +396,12 @@ const displayDocumentationErrors = () => {
396
396
  }
397
397
 
398
398
  const formatArrays = (typeText) => {
399
- return typeText?.replaceAll(/(\S+)\[\]/g, "Array<$1>")
399
+ return typeText?.replaceAll(/(\S+)\[\]/g, "Array<$1>");
400
+ }
401
+
402
+ // Convert Slot<T> and DefaultSlot<T> to Array<T> (the array is built into these types)
403
+ const formatSlotTypes = (typeText) => {
404
+ return typeText?.replace(/(Default)?Slot<(.+?)>/g, 'Array<$2>');
400
405
  }
401
406
 
402
407
  export {
@@ -415,6 +420,7 @@ export {
415
420
  getTypeRefs,
416
421
  normalizeDescription,
417
422
  formatArrays,
423
+ formatSlotTypes,
418
424
  isClass,
419
425
  normalizeTagType,
420
426
  displayDocumentationErrors,
@@ -5,6 +5,7 @@ const path = require('path');
5
5
  const extenalSchema = require('./schema.json');
6
6
  const internalSchema = require('./schema-internal.json');
7
7
 
8
+ const isVerbose = () => process.env.UI5_VERBOSE === "true";
8
9
 
9
10
  const validateFn = async () => {
10
11
  // Load your JSON data from the input file
@@ -49,7 +50,9 @@ const validateFn = async () => {
49
50
  // Validate the JSON data against the schema
50
51
  if (devMode) {
51
52
  if (validate(inputDataInternal)) {
52
- console.log('Internal custom element manifest is validated successfully');
53
+ if (isVerbose()) {
54
+ console.log('Internal custom element manifest is validated successfully');
55
+ }
53
56
  } else {
54
57
  console.log(validate.errors)
55
58
  throw new Error(`Validation of internal custom elements manifest failed: ${validate.errors}`);
@@ -61,7 +64,9 @@ const validateFn = async () => {
61
64
 
62
65
  // Validate the JSON data against the schema
63
66
  if (validate(inputDataExternal)) {
64
- console.log('Custom element manifest is validated successfully');
67
+ if (isVerbose()) {
68
+ console.log('Custom element manifest is validated successfully');
69
+ }
65
70
  fs.writeFileSync(inputFilePath, JSON.stringify(inputDataExternal, null, 2), 'utf8');
66
71
  fs.writeFileSync(inputFilePath.replace("custom-elements", "custom-elements-internal"), JSON.stringify(inputDataInternal, null, 2), 'utf8');
67
72
  } else if (devMode) {
@@ -42,6 +42,11 @@ const copyAndWatchFn = async (argv) => {
42
42
  }
43
43
  });
44
44
 
45
+ // Default to silent mode unless verbose is enabled
46
+ if (process.env.UI5_VERBOSE !== "true") {
47
+ options.silent = true;
48
+ }
49
+
45
50
  if (args.length < 2) {
46
51
  console.error('Not enough arguments: copy-and-watch [options] <sources> <target>');
47
52
  process.exit(1);
@@ -22,7 +22,9 @@ const generate = async (argv) => {
22
22
  });
23
23
 
24
24
  return Promise.all(promises).then(() => {
25
- console.log("Files copied.");
25
+ if (process.env.UI5_VERBOSE === "true") {
26
+ console.log("Files copied.");
27
+ }
26
28
  });
27
29
  };
28
30
 
@@ -84,11 +84,15 @@ const generate = async (argv) => {
84
84
  try {
85
85
  await fs.access(srcPath);
86
86
  } catch (error) {
87
- console.log(`The path ${srcPath} does not exist.`);
87
+ if (process.env.UI5_VERBOSE === "true") {
88
+ console.log(`The path ${srcPath} does not exist.`);
89
+ }
88
90
  return Promise.resolve(null);
89
91
  }
90
92
 
91
- console.log(`Generating illustrations from ${srcPath} to ${destPath}`)
93
+ if (process.env.UI5_VERBOSE === "true") {
94
+ console.log(`Generating illustrations from ${srcPath} to ${destPath}`);
95
+ }
92
96
 
93
97
  const svgImportTemplate = svgContent => {
94
98
  return `export default \`${svgContent}\`;`
@@ -193,7 +197,9 @@ export { dialogSvg, sceneSvg, spotSvg, dotSvg };`
193
197
  return Promise.all(nestedPromises);
194
198
  })
195
199
  .then(() => {
196
- console.log("Illustrations generated.");
200
+ if (process.env.UI5_VERBOSE === "true") {
201
+ console.log("Illustrations generated.");
202
+ }
197
203
  });
198
204
  };
199
205
 
@@ -8,7 +8,9 @@ import scopeVariables from "./scope-variables.mjs";
8
8
  import { writeFileIfChanged, getFileContent } from "./shared.mjs";
9
9
  import { pathToFileURL } from "url";
10
10
 
11
+
11
12
  const generate = async (argv) => {
13
+ const CSS_VARIABLES_TARGET = process.env.CSS_VARIABLES_TARGET === "host";
12
14
  const tsMode = process.env.UI5_TS === "true";
13
15
  const extension = tsMode ? ".css.ts" : ".css.js";
14
16
 
@@ -23,8 +25,15 @@ const generate = async (argv) => {
23
25
 
24
26
  build.onEnd(result => {
25
27
  result.outputFiles.forEach(async f => {
26
- // scoping
27
- let newText = scopeVariables(f.text, packageJSON);
28
+ let newText
29
+
30
+ if (CSS_VARIABLES_TARGET) {
31
+ newText = f.text;
32
+ } else {
33
+ // scoping
34
+ newText = scopeVariables(f.text, packageJSON);
35
+ }
36
+
28
37
  newText = newText.replaceAll(/\\/g, "\\\\"); // Escape backslashes as they might appear in css rules
29
38
  await mkdir(path.dirname(f.path), { recursive: true });
30
39
  writeFile(f.path, newText);
@@ -5,11 +5,13 @@ import * as path from "path";
5
5
  import { writeFile, mkdir } from "fs/promises";
6
6
  import postcss from "postcss";
7
7
  import combineDuplicatedSelectors from "../postcss-combine-duplicated-selectors/index.js"
8
+ import postcssPlugin from "./postcss-plugin.mjs";
8
9
  import { writeFileIfChanged, getFileContent } from "./shared.mjs";
9
10
  import scopeVariables from "./scope-variables.mjs";
10
11
  import { pathToFileURL } from "url";
11
12
 
12
13
  const generate = async (argv) => {
14
+ const CSS_VARIABLES_TARGET = process.env.CSS_VARIABLES_TARGET === "host";
13
15
  const tsMode = process.env.UI5_TS === "true";
14
16
  const extension = tsMode ? ".css.ts" : ".css.js";
15
17
 
@@ -20,9 +22,24 @@ const generate = async (argv) => {
20
22
  ]);
21
23
  const restArgs = argv.slice(2);
22
24
 
25
+ const saveFiles = async (distPath, css, suffix = "") => {
26
+ await mkdir(path.dirname(distPath), { recursive: true });
27
+ writeFile(distPath.replace(".css", suffix + ".css"), css);
28
+
29
+ // JSON
30
+ const jsonPath = distPath.replace(/dist[\/\\]css/, "dist/generated/assets").replace(".css", suffix + ".css.json");
31
+ await mkdir(path.dirname(jsonPath), { recursive: true });
32
+ writeFileIfChanged(jsonPath, JSON.stringify(css));
33
+
34
+ // JS/TS
35
+ const jsPath = distPath.replace(/dist[\/\\]css/, "src/generated/").replace(".css", suffix + extension);
36
+ const jsContent = getFileContent(packageJSON.name, "\`" + css + "\`");
37
+ writeFileIfChanged(jsPath, jsContent);
38
+ }
39
+
23
40
  const processThemingPackageFile = async (f) => {
24
41
  const selector = ':root';
25
- const result = await postcss().process(f.text);
42
+ const result = await postcss().process(f.text, { from: undefined });
26
43
 
27
44
  const newRule = postcss.rule({ selector });
28
45
 
@@ -34,13 +51,25 @@ const generate = async (argv) => {
34
51
  });
35
52
  });
36
53
 
37
- return newRule.toString();
54
+ return { css: newRule.toString() };
38
55
  };
39
56
 
40
57
  const processComponentPackageFile = async (f) => {
41
- const result = await postcss(combineDuplicatedSelectors).process(f.text);
58
+ if (CSS_VARIABLES_TARGET) {
59
+ const result = await postcss([
60
+ combineDuplicatedSelectors,
61
+ postcssPlugin
62
+ ]).process(f.text, { from: undefined });
63
+
64
+ return { css: result.css };
65
+ }
42
66
 
43
- return scopeVariables(result.css, packageJSON, f.path);
67
+
68
+ const combined = await postcss([
69
+ combineDuplicatedSelectors,
70
+ ]).process(f.text, { from: undefined });
71
+
72
+ return { css: scopeVariables(combined.css, packageJSON, f.path) };
44
73
  }
45
74
 
46
75
  let scopingPlugin = {
@@ -50,20 +79,9 @@ const generate = async (argv) => {
50
79
 
51
80
  build.onEnd(result => {
52
81
  result.outputFiles.forEach(async f => {
53
- let newText = f.path.includes("packages/theming") ? await processThemingPackageFile(f) : await processComponentPackageFile(f);
54
-
55
- await mkdir(path.dirname(f.path), { recursive: true });
56
- writeFile(f.path, newText);
57
-
58
- // JSON
59
- const jsonPath = f.path.replace(/dist[\/\\]css/, "dist/generated/assets").replace(".css", ".css.json");
60
- await mkdir(path.dirname(jsonPath), { recursive: true });
61
- writeFileIfChanged(jsonPath, JSON.stringify(newText));
82
+ let { css } = f.path.includes("packages/theming") ? await processThemingPackageFile(f) : await processComponentPackageFile(f);
62
83
 
63
- // JS/TS
64
- const jsPath = f.path.replace(/dist[\/\\]css/, "src/generated/").replace(".css", extension);
65
- const jsContent = getFileContent(packageJSON.name, "\`" + newText + "\`");
66
- writeFileIfChanged(jsPath, jsContent);
84
+ saveFiles(f.path, css);
67
85
  });
68
86
  })
69
87
  },
@@ -75,6 +93,7 @@ const generate = async (argv) => {
75
93
  minify: true,
76
94
  outdir: 'dist/css',
77
95
  outbase: 'src',
96
+ logLevel: process.env.UI5_VERBOSE === "true" ? "warning" : "error",
78
97
  plugins: [
79
98
  scopingPlugin,
80
99
  ],
@@ -0,0 +1,153 @@
1
+
2
+ import postcss from "postcss";
3
+
4
+ const hostVariables = new Map();
5
+
6
+ const SELECTOR = ":host";
7
+
8
+ const saveVariable = (variable, value, density) => {
9
+ if (!hostVariables.has(variable)) {
10
+ hostVariables.set(variable, {});
11
+ }
12
+ hostVariables.get(variable)[density] = value;
13
+ }
14
+
15
+ /**
16
+ * PostCSS plugin for handling CSS variables across density modes (cozy and compact).
17
+ *
18
+ * The plugin scans CSS for `:host` rules that define density-specific custom properties.
19
+ * Variables declared in a root-level `:host` rule are treated as **cozy** values, while
20
+ * variables declared inside `@container style(--ui5_content_density: compact)` `:host` rules
21
+ * are treated as **compact** values.
22
+ *
23
+ * All discovered variables are merged into a single root `:host` rule. For variables that
24
+ * exist in both modes, the plugin generates a value that uses CSS variable fallbacks to
25
+ * dynamically switch between compact and cozy values based on the active density.
26
+ *
27
+ * Variables that exist in only one mode are preserved, with appropriate fallbacks added
28
+ * when needed.
29
+ *
30
+ * Example input:
31
+ *
32
+ * ```css
33
+ * :host {
34
+ * --my-variable: cozy-value;
35
+ * --cozy-only-variable: cozy-only-value;
36
+ * }
37
+ *
38
+ * @container style(--ui5_content_density: compact) {
39
+ * :host {
40
+ * --my-variable: compact-value;
41
+ * --compact-only-variable: compact-only;
42
+ * }
43
+ * }
44
+ * ```
45
+ *
46
+ * Output:
47
+ *
48
+ * ```css
49
+ * :host {
50
+ * --my-variable: var(--_ui5-compact-size, compact-value) var(--_ui5-cozy-size, cozy-value);
51
+ * --compact-only-variable: var(--_ui5-compact-size, compact-only) var(--_ui5-cozy-size, initial);
52
+ * --cozy-only-variable: cozy-only-value;
53
+ * }
54
+ * ```
55
+ *
56
+ * This enables seamless runtime switching between density modes using CSS variables alone.
57
+ */
58
+
59
+ export default function postcssPlugin() {
60
+ return {
61
+ postcssPlugin: 'postcss-content-density-variables',
62
+ Once(root) {
63
+ let hasRootHost = false;
64
+ let hostRule;
65
+
66
+ root.walkRules((rule) => {
67
+ // Only process :host rules
68
+ if (rule.selector !== SELECTOR) {
69
+ return;
70
+ }
71
+
72
+ // Handle root-level :host rules (cozy)
73
+ if (rule.parent.type === "root") {
74
+ if (!hasRootHost) {
75
+ hasRootHost = true;
76
+ hostRule = rule;
77
+ }
78
+
79
+ rule.walkDecls((decl) => {
80
+ if (decl.prop.startsWith('--')) {
81
+ saveVariable(decl.prop, decl.value, 'cozy');
82
+ decl.remove();
83
+ }
84
+ });
85
+ }
86
+
87
+ // Handle :host rules inside @container (compact)
88
+ if (rule.parent.type === "atrule") {
89
+ if (rule.parent.params.replaceAll("\s", "") === 'style(--ui5_content_density: compact)'.replaceAll("\s", "")) {
90
+ rule.walkDecls((decl) => {
91
+ if (decl.prop.startsWith('--')) {
92
+ saveVariable(decl.prop, decl.value, 'compact');
93
+ decl.remove();
94
+ }
95
+ });
96
+ }
97
+ }
98
+
99
+ let current = rule;
100
+ // Remove up empty rules
101
+ while (current) {
102
+ if (current.nodes.length === 0) {
103
+ const parent = current.parent;
104
+ current.remove();
105
+ current = parent;
106
+ }
107
+
108
+ if (current.type === "root") {
109
+ break;
110
+ }
111
+ }
112
+ });
113
+
114
+ if (!hasRootHost) {
115
+ hostRule = postcss.rule({ selector: SELECTOR });
116
+ }
117
+
118
+ // Construct merged variable declarations depending on available modes
119
+ for (const [variable, variableData] of hostVariables) {
120
+ if (variableData.cozy && variableData.compact) {
121
+ hostRule.append({
122
+ prop: variable,
123
+ value: `var(--_ui5-compact-size, ${variableData.compact}) var(--_ui5-cozy-size, ${variableData.cozy})`,
124
+ });
125
+ } else if (variableData.compact) {
126
+
127
+ // Use a non-existent variable to always trigger the fallback.
128
+ // Because this variable is never defined, the fallback is used
129
+ // in all cases.
130
+
131
+ // Using `initial` as a fallback can work only for properties
132
+ // that treat it as an invalid value. To avoid this inconsistency,
133
+ // we intentionally reference an undefined variable, which is
134
+ // always considered invalid and undefined.
135
+ hostRule.append({
136
+ prop: variable,
137
+ value: `var(--_ui5-compact-size, ${variableData.compact}) var(--_ui5-cozy-size, var(--_ui5-f2d95f8))`,
138
+ });
139
+ } else {
140
+ hostRule.append({
141
+ prop: variable,
142
+ value: variableData.cozy,
143
+ });
144
+ }
145
+ }
146
+
147
+ root.prepend(hostRule);
148
+ hostVariables.clear();
149
+ }
150
+ }
151
+ }
152
+
153
+ postcssPlugin.postcss = true;
@@ -30,7 +30,9 @@ const getOverrideVersion = filePath => {
30
30
  try {
31
31
  overrideVersion = require(`${packageName}${path.sep}package.json`).version;
32
32
  } catch (e) {
33
- console.log(`Error requiring package ${packageName}: ${e.message}`);
33
+ if (process.env.UI5_VERBOSE === "true") {
34
+ console.log(`Error requiring package ${packageName}: ${e.message}`);
35
+ }
34
36
  }
35
37
 
36
38
  return overrideVersion;
@@ -18,29 +18,30 @@ const writeFileIfChanged = async (fileName, content) => {
18
18
  const oldContent = await readOldContent(fileName);
19
19
  if (content !== oldContent) {
20
20
  if (!oldContent) {
21
- await mkdir(path.dirname(fileName), {recursive: true});
21
+ await mkdir(path.dirname(fileName), { recursive: true });
22
22
  }
23
23
  return writeFile(fileName, content);
24
24
  }
25
25
  }
26
26
 
27
27
  const DEFAULT_THEME = assets.themes.default;
28
+ const CSS_VARIABLES_TARGET = process.env.CSS_VARIABLES_TARGET === "host";
28
29
 
29
30
  const getDefaultThemeCode = packageName => {
30
- return `import { registerThemePropertiesLoader } from "@ui5/webcomponents-base/dist/asset-registries/Themes.js";
31
+ return `import { registerThemePropertiesLoader } from "@ui5/webcomponents-base/dist/asset-registries/Themes.js";
31
32
 
32
33
  import defaultThemeBase from "@ui5/webcomponents-theming/dist/generated/themes/${DEFAULT_THEME}/parameters-bundle.css.js";
33
34
  import defaultTheme from "./${DEFAULT_THEME}/parameters-bundle.css.js";
34
35
 
35
36
  registerThemePropertiesLoader("@" + "ui5" + "/" + "webcomponents-theming", "${DEFAULT_THEME}", async () => defaultThemeBase);
36
- registerThemePropertiesLoader(${ packageName.split("").map(c => `"${c}"`).join (" + ") }, "${DEFAULT_THEME}", async () => defaultTheme);
37
+ registerThemePropertiesLoader(${packageName.split("").map(c => `"${c}"`).join(" + ")}, "${DEFAULT_THEME}", async () => defaultTheme${CSS_VARIABLES_TARGET ? ', "host"' : ''});
37
38
  `;
38
39
  };
39
40
 
40
41
  const getFileContent = (packageName, css, includeDefaultTheme) => {
41
- const defaultTheme = includeDefaultTheme ? getDefaultThemeCode(packageName) : "";
42
- return `${defaultTheme}export default ${css.trim()}`
42
+ const defaultTheme = includeDefaultTheme ? getDefaultThemeCode(packageName) : "";
43
+ return `${defaultTheme}export default ${css.trim()}`
43
44
  }
44
45
 
45
46
 
46
- export { writeFileIfChanged, getFileContent}
47
+ export { writeFileIfChanged, getFileContent }
@@ -75,7 +75,9 @@ const generateIllustrations = async (argv) => {
75
75
  await fs.mkdir(path.dirname(normalizedOutputFile), { recursive: true });
76
76
  await fs.writeFile(normalizedOutputFile, contentDynamic);
77
77
 
78
- console.log("Generated illustration imports.");
78
+ if (process.env.UI5_VERBOSE === "true") {
79
+ console.log("Generated illustration imports.");
80
+ }
79
81
  };
80
82
 
81
83
  if (require.main === module) {
@@ -80,7 +80,9 @@ const generate = async (argv) => {
80
80
  fs.writeFile(outputFileFetchMetaResolve, contentFetchMetaResolve),
81
81
  fs.writeFile(outputFileDynamicImportJSONImport, contentDynamicImportJSONAttr),
82
82
  ]).then(() => {
83
- console.log("Generated i18n JSON imports.");
83
+ if (process.env.UI5_VERBOSE === "true") {
84
+ console.log("Generated i18n JSON imports.");
85
+ }
84
86
  });
85
87
  }
86
88
 
@@ -5,6 +5,8 @@ const assets = require("../../assets-meta.js");
5
5
  const isTypeScript = process.env.UI5_TS;
6
6
  const ext = isTypeScript ? 'ts' : 'js';
7
7
 
8
+ const CSS_VARIABLES_TARGET = process.env.CSS_VARIABLES_TARGET === "host";
9
+
8
10
  const generate = async (argv) => {
9
11
  const inputFolder = path.normalize(argv[2]);
10
12
  const outputFileDynamic = path.normalize(`${argv[3]}/Themes.${ext}`);
@@ -49,7 +51,7 @@ const loadAndCheck = async (themeName) => {
49
51
  };
50
52
 
51
53
  ${availableThemesArray}
52
- .forEach(themeName => registerThemePropertiesLoader(${packageName.split("").map(c => `"${c}"`).join(" + ")}, themeName, loadAndCheck));
54
+ .forEach(themeName => registerThemePropertiesLoader(${packageName.split("").map(c => `"${c}"`).join(" + ")}, themeName, loadAndCheck${CSS_VARIABLES_TARGET ? ', "host"' : ''}));
53
55
  `;
54
56
  }
55
57
 
@@ -60,7 +62,9 @@ ${availableThemesArray}
60
62
  fs.writeFile(outputFileFetchMetaResolve, contentDynamic(fetchMetaResolveLines)),
61
63
  ]).
62
64
  then(() => {
63
- console.log("Generated themes JSON imports.");
65
+ if (process.env.UI5_VERBOSE === "true") {
66
+ console.log("Generated themes JSON imports.");
67
+ }
64
68
  })
65
69
  };
66
70
 
@@ -78,7 +78,9 @@ export {${textKeys.join()}};`;
78
78
  await fs.writeFile(outputFile, getOutputFileContent(properties, defaultLanguageProperties));
79
79
 
80
80
 
81
- console.log("i18n default file generated.")
81
+ if (process.env.UI5_VERBOSE === "true") {
82
+ console.log("i18n default file generated.");
83
+ }
82
84
  };
83
85
 
84
86
  if (require.main === module) {
@@ -58,7 +58,9 @@ const generate = async (agrv) => {
58
58
  const files = await globby(messagesBundles.replace(/\\/g, "/"));
59
59
  return Promise.all(files.map(file => convertToJSON(file, messagesJSONDist)))
60
60
  .then(() => {
61
- console.log("Message bundle JSON files generated.");
61
+ if (process.env.UI5_VERBOSE === "true") {
62
+ console.log("Message bundle JSON files generated.");
63
+ }
62
64
  });
63
65
  };
64
66
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ui5/webcomponents-tools",
3
- "version": "2.19.0-rc.2",
3
+ "version": "2.19.0",
4
4
  "description": "UI5 Web Components: webcomponents.tools",
5
5
  "author": "SAP SE (https://www.sap.com)",
6
6
  "license": "Apache-2.0",
@@ -82,5 +82,5 @@
82
82
  "esbuild": "^0.25.0",
83
83
  "yargs": "^17.5.1"
84
84
  },
85
- "gitHead": "4407982a1dd6a3799413303d1157fc5e9fb96260"
85
+ "gitHead": "a926cd9d74fdc66b22609eb80b26015ba5391cea"
86
86
  }