@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 +16 -0
- package/bin/dev.js +9 -4
- package/bin/ui5nps.js +34 -7
- package/components-package/nps.js +1 -0
- package/lib/amd-to-es6/index.js +3 -1
- package/lib/cem/cem.js +4 -0
- package/lib/cem/custom-elements-manifest.config.mjs +32 -3
- package/lib/cem/utils.mjs +7 -1
- package/lib/cem/validate.js +7 -2
- package/lib/copy-and-watch/index.js +5 -0
- package/lib/copy-list/index.js +3 -1
- package/lib/create-illustrations/index.js +9 -3
- package/lib/css-processors/css-processor-components.mjs +11 -2
- package/lib/css-processors/css-processor-themes.mjs +36 -17
- package/lib/css-processors/postcss-plugin.mjs +153 -0
- package/lib/css-processors/scope-variables.mjs +3 -1
- package/lib/css-processors/shared.mjs +7 -6
- package/lib/generate-js-imports/illustrations.js +3 -1
- package/lib/generate-json-imports/i18n.js +3 -1
- package/lib/generate-json-imports/themes.js +6 -2
- package/lib/i18n/defaults.js +3 -1
- package/lib/i18n/toJSON.js +3 -1
- package/package.json +2 -2
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
|
-
|
|
7
|
-
const
|
|
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", ...
|
|
18
|
+
command = ["test", ...args.slice(1)].join(" ");
|
|
15
19
|
}
|
|
16
20
|
|
|
17
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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("
|
|
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
|
}
|
package/lib/amd-to-es6/index.js
CHANGED
|
@@ -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
|
-
|
|
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,
|
package/lib/cem/validate.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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);
|
package/lib/copy-list/index.js
CHANGED
|
@@ -84,11 +84,15 @@ const generate = async (argv) => {
|
|
|
84
84
|
try {
|
|
85
85
|
await fs.access(srcPath);
|
|
86
86
|
} catch (error) {
|
|
87
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
27
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(${
|
|
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
|
-
|
|
42
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
65
|
+
if (process.env.UI5_VERBOSE === "true") {
|
|
66
|
+
console.log("Generated themes JSON imports.");
|
|
67
|
+
}
|
|
64
68
|
})
|
|
65
69
|
};
|
|
66
70
|
|
package/lib/i18n/defaults.js
CHANGED
|
@@ -78,7 +78,9 @@ export {${textKeys.join()}};`;
|
|
|
78
78
|
await fs.writeFile(outputFile, getOutputFileContent(properties, defaultLanguageProperties));
|
|
79
79
|
|
|
80
80
|
|
|
81
|
-
|
|
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) {
|
package/lib/i18n/toJSON.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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": "
|
|
85
|
+
"gitHead": "a926cd9d74fdc66b22609eb80b26015ba5391cea"
|
|
86
86
|
}
|