@ui5/builder 4.1.5 → 4.2.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
@@ -2,10 +2,30 @@
2
2
  All notable changes to this project will be documented in this file.
3
3
  This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
4
4
 
5
- A list of unreleased changes can be found [here](https://github.com/SAP/ui5-builder/compare/v4.1.5...HEAD).
5
+ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-builder/compare/v4.2.0...HEAD).
6
+
7
+ <a name="v4.2.0"></a>
8
+ ## [v4.2.0] - 2026-06-15
9
+ ### Bug Fixes
10
+ - **lbt/bundle/Resolver:** Ensure deterministic ordering of raw modules [`88953bc`](https://github.com/SAP/ui5-builder/commit/88953bc3fe727af0d9e2c540081f81bacc461939)
11
+
12
+ ### Dependency Updates
13
+ - Bump workerpool from 9.3.4 to 10.0.2 ([#1216](https://github.com/SAP/ui5-builder/issues/1216)) [`e19bb00`](https://github.com/SAP/ui5-builder/commit/e19bb005536ee2c5facfc3f44a31c93712651dd6)
14
+
15
+ ### Features
16
+ - **flexChangesBundler:** Add annotation changes in the flexibility-bundle [`880a091`](https://github.com/SAP/ui5-builder/commit/880a0917a7edd65c509b93f8ceb5c8810a5490ad)
17
+
18
+
19
+ <a name="v4.1.6"></a>
20
+ ## [v4.1.6] - 2026-04-20
21
+ ### Bug Fixes
22
+ - **Bundler:** Also detect import.meta as ESM indicator [`58013d5`](https://github.com/SAP/ui5-builder/commit/58013d5a75e3fbf245b0042fb0b81f4e729a7a55)
23
+ - **Bundler:** Skip ESM modules during bundling and log errors [`d28f63a`](https://github.com/SAP/ui5-builder/commit/d28f63a6ace823d9fcfac23312c09e66be6fb7d4)
24
+ - **Bundler:** Reduce noise from ESM parse errors [`bd574bb`](https://github.com/SAP/ui5-builder/commit/bd574bb231cc4e5f1af0b12c12c3365dee5eb80d)
25
+
6
26
 
7
27
  <a name="v4.1.5"></a>
8
- ## [v4.1.5] - 2026-03-23
28
+ ## [v4.1.5] - 2026-03-25
9
29
 
10
30
  <a name="v4.1.4"></a>
11
31
  ## [v4.1.4] - 2026-02-16
@@ -1019,6 +1039,8 @@ to load the custom bundle file instead.
1019
1039
 
1020
1040
  ### Features
1021
1041
  - Add ability to configure component preloads and custom bundles [`2241e5f`](https://github.com/SAP/ui5-builder/commit/2241e5ff98fd95f1f80cc74959655ae7a9c660e7)
1042
+ [v4.2.0]: https://github.com/SAP/ui5-builder/compare/v4.1.6...v4.2.0
1043
+ [v4.1.6]: https://github.com/SAP/ui5-builder/compare/v4.1.5...v4.1.6
1022
1044
  [v4.1.5]: https://github.com/SAP/ui5-builder/compare/v4.1.4...v4.1.5
1023
1045
  [v4.1.4]: https://github.com/SAP/ui5-builder/compare/v4.1.3...v4.1.4
1024
1046
  [v4.1.3]: https://github.com/SAP/ui5-builder/compare/v4.1.2...v4.1.3
package/README.md CHANGED
@@ -14,7 +14,7 @@
14
14
  > Part of the [UI5 CLI](https://github.com/UI5/cli)
15
15
 
16
16
  [![REUSE status](https://api.reuse.software/badge/github.com/SAP/ui5-builder)](https://api.reuse.software/info/github.com/SAP/ui5-builder)
17
- [![Build Status](https://dev.azure.com/sap/opensource/_apis/build/status/SAP.ui5-builder?branchName=v4)](https://dev.azure.com/sap/opensource/_build/latest?definitionId=26&branchName=v4)
17
+ [![Build Status](https://github.com/SAP/ui5-builder/actions/workflows/github-ci.yml/badge.svg)](https://github.com/SAP/ui5-builder/actions/workflows/github-ci.yml)
18
18
  [![npm Package Version](https://badge.fury.io/js/%40ui5%2Fbuilder.svg)](https://www.npmjs.com/package/@ui5/builder)
19
19
  [![Coverage Status](https://coveralls.io/repos/github/SAP/ui5-builder/badge.svg)](https://coveralls.io/github/SAP/ui5-builder)
20
20
 
@@ -597,10 +597,11 @@ class BundleBuilder {
597
597
  }
598
598
  }
599
599
 
600
- writeRequires(section) {
600
+ async writeRequires(section) {
601
601
  if (section.modules.length === 0) {
602
602
  return;
603
603
  }
604
+
604
605
  this.outW.ensureNewLine();
605
606
  if (section.async === false) {
606
607
  section.modules.forEach( (module) => {
@@ -767,7 +768,7 @@ async function rewriteDefine({moduleName, moduleContent, moduleSourceMap}) {
767
768
  } catch (e) {
768
769
  log.error(`Error while parsing ${moduleName}: ${e.message}`);
769
770
  log.verbose(e.stack);
770
- return {};
771
+ return null;
771
772
  }
772
773
 
773
774
  if ( ast.type === Syntax.Program &&
@@ -67,6 +67,7 @@ class ResolvedBundleDefinition {
67
67
  return pool.getModuleInfo(submodule).then(
68
68
  (subinfo) => {
69
69
  if (!bundleInfo.subModules.includes(subinfo.name) &&
70
+ subinfo.format !== ModuleInfo.Format.ESM &&
70
71
  (!subinfo.requiresTopLevelScope ||
71
72
  (subinfo.requiresTopLevelScope && allowStringBundling))) {
72
73
  bundleInfo.addSubModule(subinfo);
@@ -4,6 +4,7 @@
4
4
 
5
5
  import topologicalSort from "../graph/topologicalSort.js";
6
6
  import {getRendererName} from "../UI5ClientConstants.js";
7
+ import ModuleInfo from "../resources/ModuleInfo.js";
7
8
  import ResourceFilterList from "../resources/ResourceFilterList.js";
8
9
  import {SectionType} from "./BundleDefinition.js";
9
10
  import ResolvedBundleDefinition from "./ResolvedBundleDefinition.js";
@@ -135,6 +136,16 @@ class BundleResolver {
135
136
  const dependencyInfo = resource && resource.info;
136
137
  let promises = [];
137
138
 
139
+ // Skip ESM modules — they can't be bundled
140
+ if (resource?.info?.format === ModuleInfo.Format.ESM) {
141
+ log.error(
142
+ `Module ${resourceName} is an ECMAScript Module (ESM), ` +
143
+ `which is not supported for bundling. ` +
144
+ `The module will be skipped.`
145
+ );
146
+ return;
147
+ }
148
+
138
149
  if ( isBundle && !decomposable ) {
139
150
  resource.info.subModules.forEach(
140
151
  (included) => {
@@ -318,6 +329,15 @@ class BundleResolver {
318
329
  return collectModulesForSection(section).
319
330
  then( (modules) => {
320
331
  if ( section.mode == SectionType.Raw && section.sort !== false ) {
332
+ // Sort modules by their filter definition order to ensure
333
+ // deterministic input for the topological sort.
334
+ // Topological sort preserves input order for tie-breaking,
335
+ // so this ensures modules at the same dependency level
336
+ // appear in the order defined by the section filters.
337
+ const filterOrder = new ResourceFilterList(section.filters, fileTypes);
338
+ modules.sort((a, b) => {
339
+ return filterOrder.matchIndex(a) - filterOrder.matchIndex(b);
340
+ });
321
341
  // sort the modules in topological order
322
342
  return topologicalSort(pool, modules).then( (modules) => {
323
343
  log.silly(` Resolved modules (sorted): ${modules}`);
@@ -25,7 +25,8 @@ const CONDITIONAL = 2;
25
25
  const Format = {
26
26
  UI5_LEGACY: "ui5-declare",
27
27
  UI5_DEFINE: "ui5-define",
28
- AMD: "amd"
28
+ AMD: "amd",
29
+ ESM: "esm"
29
30
  };
30
31
 
31
32
  /**
@@ -124,6 +124,16 @@ export default class ResourceFilterList {
124
124
  );
125
125
  }
126
126
 
127
+ matchIndex(candidate) {
128
+ for (let i = 0; i < this.matchers.length; i++) {
129
+ const matcher = this.matchers[i];
130
+ if (matcher.include && matcher.calcMatch(candidate, false)) {
131
+ return i;
132
+ }
133
+ }
134
+ return this.matchers.length;
135
+ }
136
+
127
137
  toString() {
128
138
  return this.matchers.map((matcher) => matcher.pattern).join(",");
129
139
  }
@@ -62,8 +62,12 @@ async function determineDependencyInfo(resource, rawInfo, pool) {
62
62
  try {
63
63
  ast = parseJS(code, {comment: true});
64
64
  } catch (err) {
65
- log.error(`Failed to parse ${resource.name}: ${err.message}`);
65
+ log.verbose(`Failed to parse ${resource.name}: ${err.message}`);
66
66
  log.verbose(err.stack);
67
+ if (err.message.includes("'import' and 'export' may appear only with 'sourceType: module'") ||
68
+ err.message.includes("Cannot use 'import.meta' outside a module")) {
69
+ info.format = ModuleInfo.Format.ESM;
70
+ }
67
71
  }
68
72
  if (ast) {
69
73
  try {
@@ -243,4 +247,3 @@ class ResourcePool {
243
247
  }
244
248
 
245
249
  export default ResourcePool;
246
-
@@ -18,8 +18,8 @@ import {createResource} from "@ui5/fs/resourceFactory";
18
18
  * @param {@ui5/fs/Resource[]} parameters.resources List of resources to be processed
19
19
  * @param {object} parameters.options Options
20
20
  * @param {string} parameters.options.pathPrefix Prefix for bundle path
21
- * @param {string} parameters.options.hasFlexBundleVersion true if minUI5Version >= 1.73 than
22
- * create flexibility-bundle.json
21
+ * @param {string} parameters.options.hasFlexBundleVersion true if minUI5Version >= 1.73
22
+ * and create flexibility-bundle.json
23
23
  * @param {object} [parameters.existingFlexBundle={}] Object with existing flexibility-bundle.json
24
24
  * to merge with new changes
25
25
  * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving with flex changes bundle resources
@@ -45,6 +45,7 @@ export default function({resources, options: {pathPrefix, hasFlexBundleVersion},
45
45
  const variants = [];
46
46
  const variantChanges = [];
47
47
  const variantManagementChanges = [];
48
+ const annotationChanges = [];
48
49
 
49
50
  changesContent.forEach(function(content) {
50
51
  if (content.layer === "VENDOR") {
@@ -74,14 +75,23 @@ export default function({resources, options: {pathPrefix, hasFlexBundleVersion},
74
75
  case "ctrl_variant_management_change":
75
76
  variantManagementChanges.push(content);
76
77
  break;
78
+ case "annotation_change":
79
+ annotationChanges.push(content);
80
+ break;
77
81
  }
78
82
  });
79
83
 
80
- if (!hasFlexBundleVersion && (compVariants.length != 0 || variants.length != 0 || variantChanges.length != 0 ||
81
- variantDependentControlChanges.length != 0 || variantManagementChanges.length != 0)) {
84
+ if (!hasFlexBundleVersion && (
85
+ compVariants.length != 0 ||
86
+ variants.length != 0 ||
87
+ variantChanges.length != 0 ||
88
+ variantDependentControlChanges.length != 0 ||
89
+ variantManagementChanges.length != 0 ||
90
+ annotationChanges.length != 0
91
+ )) {
82
92
  throw new Error(
83
- "There are some control variant changes in the changes folder. This only works with a " +
84
- "minUI5Version 1.73.0. Please update the minUI5Version in the manifest.json to 1.73.0 or higher");
93
+ "There are some files in the changes folder supported only with a UI5 version 1.73 and above. " +
94
+ "Please update the minUI5Version in the manifest.json to 1.73 or higher");
85
95
  }
86
96
  // create changes-bundle.json
87
97
  if (!hasFlexBundleVersion) {
@@ -89,6 +99,7 @@ export default function({resources, options: {pathPrefix, hasFlexBundleVersion},
89
99
  } else {
90
100
  bundleName = "flexibility-bundle.json";
91
101
  let newChangeFormat = {
102
+ annotationChanges,
92
103
  changes,
93
104
  compVariants,
94
105
  variants,
@@ -45,12 +45,18 @@ const log = getLogger("builder:processors:bundlers:moduleBundler");
45
45
  * the module itself.
46
46
  * This requires the ui5loader to be available at build time and UI5 version 1.74.0 or higher at runtime.
47
47
  * </li>
48
+ * <li>
49
+ * <code>depCache</code>: A 'depCache' section is transformed into a `sap.ui.loader.config` call that maps
50
+ * module names to their respective dependencies (including declarative views/fragments).
51
+ * This requires the ui5loader to be available at build time.
52
+ * </li>
48
53
  * </ul>
49
54
  * </p>
50
55
  *
51
56
  * @public
52
57
  * @typedef {object} ModuleBundleDefinitionSection
53
- * @property {string} mode The embedding mode. Either 'provided', 'raw', 'preload', 'require' or 'bundleInfo'
58
+ * @property {string} mode The embedding mode. Either 'provided', 'raw', 'preload', 'require', 'bundleInfo'
59
+ * or 'depCache'
54
60
  * @property {string[]} filters List of modules declared as glob patterns (resource name patterns) that should be
55
61
  * in- or excluded.
56
62
  * A pattern ending with a slash '/' will, similarly to the use of a single '*' or double '**' asterisk,
@@ -95,7 +95,9 @@ export default async function({workspace, taskUtil, options = {}}) {
95
95
 
96
96
  log.verbose("Collecting flexibility changes");
97
97
  const allResources = await workspace.byGlob(
98
- `${pathPrefix}/changes/*.{change,variant,ctrl_variant,ctrl_variant_change,ctrl_variant_management_change}`);
98
+ pathPrefix + "/changes/*.{annotation_change,change,variant,ctrl_variant," +
99
+ "ctrl_variant_change,ctrl_variant_management_change}"
100
+ );
99
101
 
100
102
  let bBundleCreated = false;
101
103
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ui5/builder",
3
- "version": "4.1.5",
3
+ "version": "4.2.0",
4
4
  "description": "UI5 CLI - Builder",
5
5
  "author": {
6
6
  "name": "SAP SE",
@@ -34,15 +34,12 @@
34
34
  },
35
35
  "scripts": {
36
36
  "test": "npm run lint && npm run jsdoc-generate && npm run coverage",
37
- "test-azure": "npm run coverage-xunit",
38
37
  "lint": "eslint ./",
39
38
  "unit": "rimraf test/tmp && ava",
40
39
  "unit-verbose": "rimraf test/tmp && cross-env UI5_LOG_LVL=verbose ava --verbose --serial",
41
40
  "unit-watch": "rimraf test/tmp && ava --watch",
42
- "unit-xunit": "rimraf test/tmp && ava --node-arguments=\"--experimental-loader=@istanbuljs/esm-loader-hook\" --tap --timeout=1m | tap-xunit --dontUseCommentsAsTestNames=true > test-results.xml",
43
41
  "unit-inspect": "cross-env UI5_LOG_LVL=verbose ava debug --break",
44
42
  "coverage": "rimraf test/tmp && nyc ava --node-arguments=\"--experimental-loader=@istanbuljs/esm-loader-hook\"",
45
- "coverage-xunit": "nyc --reporter=text --reporter=text-summary --reporter=cobertura npm run unit-xunit",
46
43
  "jsdoc": "npm run jsdoc-generate && open-cli jsdocs/index.html",
47
44
  "jsdoc-generate": "jsdoc -c ./jsdoc.json -t $(npm ls docdash --parseable | head -1) ./lib/ || (echo 'Error during JSDoc generation! Check log.' && exit 1)",
48
45
  "jsdoc-watch": "npm run jsdoc && chokidar \"./lib/**/*.js\" -c \"npm run jsdoc-generate\"",
@@ -50,7 +47,8 @@
50
47
  "version": "git-chglog --sort semver --next-tag v$npm_package_version -o CHANGELOG.md v4.0.0.. && git add CHANGELOG.md",
51
48
  "prepublishOnly": "git push --follow-tags",
52
49
  "release-note": "git-chglog --sort semver -c .chglog/release-config.yml v$npm_package_version",
53
- "knip": "knip --config knip.config.js"
50
+ "knip": "knip --config knip.config.js",
51
+ "check-engine": "check-engine-light ."
54
52
  },
55
53
  "files": [
56
54
  "CHANGELOG.md",
@@ -123,7 +121,7 @@
123
121
  },
124
122
  "dependencies": {
125
123
  "@jridgewell/sourcemap-codec": "^1.5.5",
126
- "@ui5/fs": "^4.0.5",
124
+ "@ui5/fs": "^4.0.6",
127
125
  "@ui5/logger": "^4.0.2",
128
126
  "cheerio": "1.0.0",
129
127
  "escape-unicode": "^0.3.0",
@@ -133,17 +131,18 @@
133
131
  "jsdoc": "^4.0.5",
134
132
  "less-openui5": "^0.11.6",
135
133
  "pretty-data": "^0.40.0",
136
- "semver": "^7.7.4",
137
- "terser": "^5.46.1",
138
- "workerpool": "^9.3.4",
134
+ "semver": "^7.8.4",
135
+ "terser": "^5.48.0",
136
+ "workerpool": "^10.0.2",
139
137
  "xml2js": "^0.6.2"
140
138
  },
141
139
  "devDependencies": {
142
140
  "@eslint/js": "^9.14.0",
143
141
  "@istanbuljs/esm-loader-hook": "^0.3.0",
144
142
  "@jridgewell/trace-mapping": "^0.3.31",
145
- "@ui5/project": "^4.0.14",
143
+ "@ui5/project": "^4.0.16",
146
144
  "ava": "^6.4.1",
145
+ "check-engine-light": "0.4.0",
147
146
  "chokidar-cli": "^3.0.0",
148
147
  "cross-env": "^10.1.0",
149
148
  "docdash": "^2.0.2",
@@ -151,14 +150,13 @@
151
150
  "eslint-config-google": "^0.14.0",
152
151
  "eslint-plugin-ava": "^15.1.0",
153
152
  "eslint-plugin-jsdoc": "61.5.0",
154
- "esmock": "^2.7.3",
153
+ "esmock": "^2.7.6",
155
154
  "globals": "^16.5.0",
156
155
  "knip": "^5.88.1",
157
156
  "line-column": "^1.0.2",
158
157
  "nyc": "^17.1.0",
159
158
  "open-cli": "^8.0.0",
160
159
  "rimraf": "^6.1.3",
161
- "sinon": "^21.0.3",
162
- "tap-xunit": "^2.4.1"
160
+ "sinon": "^21.1.2"
163
161
  }
164
162
  }