@ui5/builder 3.1.1 → 3.3.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/.reuse/dep5 CHANGED
@@ -25,9 +25,9 @@ Disclaimer: The code in this project may include calls to APIs (“API Calls”)
25
25
  parties the right to use of access any SAP External Product, through API Calls.
26
26
 
27
27
  Files: *
28
- Copyright: 2018-2023 SAP SE or an SAP affiliate company and UI5 Tooling contributors
28
+ Copyright: 2018-2024 SAP SE or an SAP affiliate company and UI5 Tooling contributors
29
29
  License: Apache-2.0
30
30
 
31
31
  Files: lib/processors/jsdoc/lib/*
32
- Copyright: 2009-2023 SAP SE or an SAP affiliate company and OpenUI5 contributors
32
+ Copyright: 2009-2024 SAP SE or an SAP affiliate company and OpenUI5 contributors
33
33
  License: Apache-2.0
package/CHANGELOG.md CHANGED
@@ -2,10 +2,28 @@
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/v3.1.1...HEAD).
5
+ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-builder/compare/v3.3.0...HEAD).
6
+
7
+ <a name="v3.3.0"></a>
8
+ ## [v3.3.0] - 2024-01-18
9
+ ### Features
10
+ - **flexChangesBundler:** Merge existing with new flexibility-bundle.json [`fd070ab`](https://github.com/SAP/ui5-builder/commit/fd070abaa22680ee70b448fa0ac406a8f2b57cc5)
11
+
12
+
13
+ <a name="v3.2.0"></a>
14
+ ## [v3.2.0] - 2023-12-12
15
+ ### Bug Fixes
16
+ - Incomplete multi-character sanitization ([#959](https://github.com/SAP/ui5-builder/issues/959)) [`d61f1b7`](https://github.com/SAP/ui5-builder/commit/d61f1b744495f5428db33467218077e7996f1575)
17
+ - Add guard against prototype pollution ([#960](https://github.com/SAP/ui5-builder/issues/960)) [`ba230d9`](https://github.com/SAP/ui5-builder/commit/ba230d922cac0acd291dfe18b0ae7a95eae8b190)
18
+ - Incomplete string escaping or encoding ([#958](https://github.com/SAP/ui5-builder/issues/958)) [`50bb0d9`](https://github.com/SAP/ui5-builder/commit/50bb0d97e76fb312412cf29fae18b76cc88df6f4)
19
+ - **manifestCreator:** set fallbackLocale to empty string if no locale is present ([#962](https://github.com/SAP/ui5-builder/issues/962)) [`26526a0`](https://github.com/SAP/ui5-builder/commit/26526a08ff38ee11ed3bd506f7ef0610f1d1ccb0)
20
+
21
+ ### Features
22
+ - depCache bundling mode ([#951](https://github.com/SAP/ui5-builder/issues/951)) [`f2cf564`](https://github.com/SAP/ui5-builder/commit/f2cf564f0f71d635e58a743c7bdef1f427e341b2)
23
+
6
24
 
7
25
  <a name="v3.1.1"></a>
8
- ## [v3.1.1] - 2023-11-19
26
+ ## [v3.1.1] - 2023-11-20
9
27
  ### Bug Fixes
10
28
  - Handle graceful termination of workerpool for parallel builds ([#953](https://github.com/SAP/ui5-builder/issues/953)) [`f7b9f27`](https://github.com/SAP/ui5-builder/commit/f7b9f27ac5966bd89e52e4c2d5b03482a0f3dbb7)
11
29
  - **Bundling:** Detect manifest.json dependency of libraries [`6f9995f`](https://github.com/SAP/ui5-builder/commit/6f9995f5b47a6094fa93b5d433be849b1d3cdc7e)
@@ -839,6 +857,8 @@ to load the custom bundle file instead.
839
857
 
840
858
  ### Features
841
859
  - Add ability to configure component preloads and custom bundles [`2241e5f`](https://github.com/SAP/ui5-builder/commit/2241e5ff98fd95f1f80cc74959655ae7a9c660e7)
860
+ [v3.3.0]: https://github.com/SAP/ui5-builder/compare/v3.2.0...v3.3.0
861
+ [v3.2.0]: https://github.com/SAP/ui5-builder/compare/v3.1.1...v3.2.0
842
862
  [v3.1.1]: https://github.com/SAP/ui5-builder/compare/v3.1.0...v3.1.1
843
863
  [v3.1.0]: https://github.com/SAP/ui5-builder/compare/v3.0.9...v3.1.0
844
864
  [v3.0.9]: https://github.com/SAP/ui5-builder/compare/v3.0.8...v3.0.9
package/LICENSE.txt CHANGED
@@ -186,7 +186,7 @@
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright 2018-2023 SAP SE or an SAP affiliate company and UI5 Tooling contributors
189
+ Copyright 2018-2024 SAP SE or an SAP affiliate company and UI5 Tooling contributors
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
@@ -41,6 +41,8 @@ class AutoSplitter {
41
41
  const numberOfParts = options.numberOfParts;
42
42
  let totalSize = 0;
43
43
  const moduleSizes = Object.create(null);
44
+ const depCacheSizes = [];
45
+ let depCacheLoaderSize = 0;
44
46
  this.optimize = !!options.optimize;
45
47
 
46
48
  // ---- resolve module definition
@@ -74,6 +76,27 @@ class AutoSplitter {
74
76
  totalSize += "sap.ui.requireSync('');".length + toRequireJSName(module).length;
75
77
  });
76
78
  break;
79
+ case SectionType.DepCache:
80
+ depCacheLoaderSize = "sap.ui.loader.config({depCacheUI5:{}});".length;
81
+ totalSize += depCacheLoaderSize;
82
+
83
+ section.modules.forEach( (module) => {
84
+ promises.push((async () => {
85
+ const resource = await this.pool.findResourceWithInfo(module);
86
+ const deps = resource.info.dependencies.filter(
87
+ (dep) =>
88
+ !resource.info.isConditionalDependency(dep) &&
89
+ !resource.info.isImplicitDependency(dep)
90
+ );
91
+ if (deps.length > 0) {
92
+ const depSize = `"${module}": [${deps.map((dep) => `"${dep}"`).join(",")}],`.length;
93
+ totalSize += depSize;
94
+
95
+ depCacheSizes.push({size: depSize, module});
96
+ }
97
+ })());
98
+ });
99
+ break;
77
100
  default:
78
101
  break;
79
102
  }
@@ -180,6 +203,36 @@ class AutoSplitter {
180
203
  totalSize += 21 + toRequireJSName(module).length;
181
204
  });
182
205
  break;
206
+ case SectionType.DepCache:
207
+ currentSection = {
208
+ mode: SectionType.DepCache,
209
+ filters: []
210
+ };
211
+ currentModule.sections.push( currentSection );
212
+ totalSize += depCacheLoaderSize;
213
+
214
+ depCacheSizes.forEach((depCache) => {
215
+ if ( part + 1 < numberOfParts && totalSize + depCache.size / 2 > partSize ) {
216
+ part++;
217
+ // start a new module
218
+ totalSize = depCacheLoaderSize;
219
+ currentSection = {
220
+ mode: SectionType.DepCache,
221
+ filters: []
222
+ };
223
+ currentModule = {
224
+ name: moduleNameWithPart.replace(/__part__/, part),
225
+ sections: [currentSection]
226
+ };
227
+ splittedModules.push(currentModule);
228
+ }
229
+
230
+ if (!currentSection.filters.includes(depCache.module)) {
231
+ currentSection.filters.push(depCache.module);
232
+ totalSize += depCache.size;
233
+ }
234
+ });
235
+ break;
183
236
  default:
184
237
  break;
185
238
  }
@@ -71,6 +71,14 @@ const EVOBundleFormat = {
71
71
  resolvedModule.executes(MODULE__UI5LOADER_AUTOCONFIG) ||
72
72
  resolvedModule.executes(MODULE__JQUERY_SAP_GLOBAL) ||
73
73
  resolvedModule.executes(MODULE__SAP_UI_CORE_CORE);
74
+ },
75
+
76
+ beforeDepCache(outW) {
77
+ outW.writeln(`sap.ui.loader.config({depCacheUI5:{`);
78
+ },
79
+
80
+ afterDepCache(outW) {
81
+ outW.writeln(`}});`);
74
82
  }
75
83
  };
76
84
 
@@ -220,6 +228,8 @@ class BundleBuilder {
220
228
  return this.writeBundleInfos([section]);
221
229
  case SectionType.Require:
222
230
  return this.writeRequires(section);
231
+ case SectionType.DepCache:
232
+ return this.writeDepCache(section);
223
233
  default:
224
234
  throw new Error("unknown section mode " + section.mode);
225
235
  }
@@ -549,6 +559,59 @@ class BundleBuilder {
549
559
  });
550
560
  }
551
561
 
562
+ // When AutoSplit is enabled for depCache, we need to ensure that modules
563
+ // are not duplicated across files. This might happen due to the filters provided.
564
+ // So, certain modules that are included in depCache could be dependencies of another
565
+ // module in the next file. This will also duplicate its dependency definition if we do not filter.
566
+ #depCacheSet = new Set();
567
+ async writeDepCache(section) {
568
+ const outW = this.outW;
569
+ let hasDepCache = false;
570
+
571
+ const sequence = section.modules.slice().sort();
572
+
573
+ if (sequence.length > 0) {
574
+ for (const module of sequence) {
575
+ if (this.#depCacheSet.has(module)) {
576
+ continue;
577
+ }
578
+
579
+ this.#depCacheSet.add(module);
580
+ let resource = null;
581
+ try {
582
+ resource = await this.pool.findResourceWithInfo(module);
583
+ } catch (e) {
584
+ log.error(` couldn't find ${module}`);
585
+ }
586
+
587
+ if (resource != null) {
588
+ const deps = resource.info.dependencies.filter(
589
+ (dep) =>
590
+ !resource.info.isConditionalDependency(dep) &&
591
+ !resource.info.isImplicitDependency(dep)
592
+ );
593
+ if (deps.length > 0) {
594
+ if (!hasDepCache) {
595
+ hasDepCache = true;
596
+ outW.ensureNewLine();
597
+ this.targetBundleFormat.beforeDepCache(outW, section);
598
+ }
599
+
600
+ outW.writeln(
601
+ `"${module}": [${deps.map((dep) => `"${dep}"`).join(",")}],`
602
+ );
603
+ } else {
604
+ log.verbose(` skipped ${module}, no dependencies`);
605
+ }
606
+ }
607
+ }
608
+
609
+ if (hasDepCache) {
610
+ this.targetBundleFormat.afterDepCache(outW, section);
611
+ }
612
+ }
613
+ }
614
+
552
615
  async getSourceMapForModule({moduleName, moduleContent, resourcePath}) {
553
616
  let moduleSourceMap = null;
554
617
  let newModuleContent = moduleContent;
@@ -27,5 +27,12 @@ export const SectionType = {
27
27
  * Usually used as the last section in a merged module to enforce loading and
28
28
  * execution of some specific module or modules.
29
29
  */
30
- Require: "require"
30
+ Require: "require",
31
+
32
+ /**
33
+ * Dependency cache information that lists modules and their dependencies
34
+ * of all types: JS, declarative views/fragments.
35
+ * Only the dependencies of the modules are stored as 'depCache' configuration.
36
+ */
37
+ DepCache: "depCache"
31
38
  };
@@ -64,7 +64,11 @@ class ResolvedBundleDefinition {
64
64
  return Promise.all(
65
65
  modules.map( (submodule) => {
66
66
  return pool.getModuleInfo(submodule).then(
67
- (subinfo) => bundleInfo.addSubModule(subinfo)
67
+ (subinfo) => {
68
+ if (!bundleInfo.subModules.includes(subinfo.name)) {
69
+ bundleInfo.addSubModule(subinfo);
70
+ }
71
+ }
68
72
  );
69
73
  })
70
74
  );
@@ -198,7 +198,7 @@ class BundleResolver {
198
198
  let oldIgnoredResources;
199
199
  let oldSelectedResourcesSequence;
200
200
 
201
- if ( section.mode == SectionType.Require ) {
201
+ if ( [SectionType.Require, SectionType.DepCache].includes(section.mode) ) {
202
202
  oldSelectedResources = selectedResources;
203
203
  oldIgnoredResources = visitedResources;
204
204
  oldSelectedResourcesSequence = selectedResourcesSequence;
@@ -254,7 +254,7 @@ class BundleResolver {
254
254
  });
255
255
 
256
256
  return Promise.all(promises).then( function() {
257
- if ( section.mode == SectionType.Require ) {
257
+ if ( [SectionType.Require, SectionType.DepCache].includes(section.mode) ) {
258
258
  newKeys = selectedResourcesSequence;
259
259
  selectedResources = oldSelectedResources;
260
260
  visitedResources = oldIgnoredResources;
@@ -12,7 +12,7 @@ function makeFileTypePattern(fileTypes) {
12
12
  if ( !type.startsWith(".") ) {
13
13
  type = "." + type;
14
14
  }
15
- return type.replace(/[*+?.()|^$]/g, "\\$&");
15
+ return type.replace(/[*+?.()|^$\\]/g, "\\$&");
16
16
  }).join("|") + ")";
17
17
  }
18
18
 
@@ -20,9 +20,11 @@ import {createResource} from "@ui5/fs/resourceFactory";
20
20
  * @param {string} parameters.options.pathPrefix Prefix for bundle path
21
21
  * @param {string} parameters.options.hasFlexBundleVersion true if minUI5Version >= 1.73 than
22
22
  * create flexibility-bundle.json
23
+ * @param {object} [parameters.existingFlexBundle={}] Object with existing flexibility-bundle.json
24
+ * to merge with new changes
23
25
  * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving with flex changes bundle resources
24
26
  */
25
- export default function({resources, options: {pathPrefix, hasFlexBundleVersion}}) {
27
+ export default function({resources, options: {pathPrefix, hasFlexBundleVersion}, existingFlexBundle = {}}) {
26
28
  let bundleName = "changes-bundle.json";
27
29
 
28
30
  function sortByTimeStamp(a, b) {
@@ -86,7 +88,7 @@ export default function({resources, options: {pathPrefix, hasFlexBundleVersion}}
86
88
  return JSON.stringify(changes);
87
89
  } else {
88
90
  bundleName = "flexibility-bundle.json";
89
- const newChangeFormat = {
91
+ let newChangeFormat = {
90
92
  changes,
91
93
  compVariants,
92
94
  variants,
@@ -94,11 +96,33 @@ export default function({resources, options: {pathPrefix, hasFlexBundleVersion}}
94
96
  variantDependentControlChanges,
95
97
  variantManagementChanges
96
98
  };
97
-
99
+ if (Object.keys(existingFlexBundle).length > 0) {
100
+ newChangeFormat = mergeFlexChangeBundles(newChangeFormat);
101
+ }
98
102
  return JSON.stringify(newChangeFormat);
99
103
  }
100
104
  }
101
105
 
106
+ /**
107
+ * Merge new and existing bundles
108
+ *
109
+ * @param {object} newFlexBundle Object with new content of flexibility-bundle.json
110
+ * @returns {object} Object with merged content of new and existing flexibility-bundle.json
111
+ */
112
+ function mergeFlexChangeBundles(newFlexBundle) {
113
+ const result = {};
114
+
115
+ Object.keys(newFlexBundle).forEach((key) => {
116
+ if (existingFlexBundle[key] && Array.isArray(existingFlexBundle[key])) {
117
+ result[key] = existingFlexBundle[key].concat(newFlexBundle[key]);
118
+ } else {
119
+ result[key] = newFlexBundle[key];
120
+ }
121
+ });
122
+
123
+ return result;
124
+ }
125
+
102
126
  return Promise.all(resources.map((resource) => {
103
127
  return resource.getBuffer().then((buffer) => {
104
128
  return JSON.parse(buffer.toString());
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * Node script to create cross-library API index files for use in the UI5 SDKs.
3
3
  *
4
- * (c) Copyright 2009-2023 SAP SE or an SAP affiliate company.
4
+ * (c) Copyright 2009-2024 SAP SE or an SAP affiliate company.
5
5
  * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
6
6
  */
7
7
 
@@ -135,10 +135,11 @@ function createIndexFiles(versionInfoFile, unpackedTestresourcesRoot, targetFile
135
135
  function collectLists(oSymbol) {
136
136
 
137
137
  function addData(oDataType, oEntityObject, sObjectType, sSymbolName) {
138
- let sSince = oDataType !== "since" ? oEntityObject[oDataType].since : oEntityObject.since,
139
- oData = {
138
+ const sSince = oDataType !== "since" ? oEntityObject[oDataType].since : oEntityObject.since;
139
+ const sText = oDataType !== "since" ? oEntityObject[oDataType].text : oEntityObject.description;
140
+ const oData = {
140
141
  control: sSymbolName,
141
- text: oEntityObject[oDataType].text || oEntityObject.description,
142
+ text: sText || undefined,
142
143
  type: sObjectType,
143
144
  "static": !!oEntityObject.static,
144
145
  visibility: oEntityObject.visibility
@@ -173,7 +174,7 @@ function createIndexFiles(versionInfoFile, unpackedTestresourcesRoot, targetFile
173
174
  addData("deprecated", oSymbol, "class", oSymbol.name);
174
175
  }
175
176
 
176
- if (oSymbol.experimental) {
177
+ if (oSymbol.experimental && !oSymbol.deprecated) {
177
178
  addData("experimental", oSymbol, "class", oSymbol.name);
178
179
  }
179
180
 
@@ -187,7 +188,7 @@ function createIndexFiles(versionInfoFile, unpackedTestresourcesRoot, targetFile
187
188
  addData("deprecated", oMethod, "methods", oSymbol.name);
188
189
  }
189
190
 
190
- if (oMethod.experimental) {
191
+ if (oMethod.experimental && !oSymbol.deprecated) {
191
192
  addData("experimental", oMethod, "methods", oSymbol.name);
192
193
  }
193
194
 
@@ -202,7 +203,7 @@ function createIndexFiles(versionInfoFile, unpackedTestresourcesRoot, targetFile
202
203
  addData("deprecated", oEvent, "events", oSymbol.name);
203
204
  }
204
205
 
205
- if (oEvent.experimental) {
206
+ if (oEvent.experimental && !oSymbol.deprecated) {
206
207
  addData("experimental", oEvent, "events", oSymbol.name);
207
208
  }
208
209
 
@@ -469,6 +470,17 @@ function createIndexFiles(versionInfoFile, unpackedTestresourcesRoot, targetFile
469
470
 
470
471
  aKeys.forEach((sKey) => {
471
472
  oSorted[sKey] = oList[sKey];
473
+ oSorted[sKey].apis.sort((a,b) => {
474
+ const keyA = `${a.control}|${a.entityName || ""}`.toLowerCase();
475
+ const keyB = `${b.control}|${b.entityName || ""}`.toLowerCase();
476
+ if ( keyA === keyB ) {
477
+ if ( a.static === b.static ) {
478
+ return 0;
479
+ }
480
+ return a.static ? -1 : 1;
481
+ }
482
+ return keyA < keyB ? -1 : 1;
483
+ }); // sort entries within the same version alphabetically (case insensitive)
472
484
  });
473
485
 
474
486
  return oSorted;
@@ -1,10 +1,12 @@
1
1
  /*
2
2
  * Node script to preprocess api.json files for use in the UI5 SDKs.
3
3
  *
4
- * (c) Copyright 2009-2023 SAP SE or an SAP affiliate company.
4
+ * (c) Copyright 2009-2024 SAP SE or an SAP affiliate company.
5
5
  * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
6
6
  */
7
7
 
8
+ /* eslint-disable */
9
+
8
10
  "use strict";
9
11
  const cheerio = require("cheerio");
10
12
  const path = require('path');
@@ -462,8 +464,9 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
462
464
 
463
465
  // Description
464
466
  if (oAggregation.deprecated) {
465
- oAggregation.description = formatters.formatDescription(oAggregation.description,
466
- oAggregation.deprecated.text, oAggregation.deprecated.since);
467
+ oAggregation.description = formatters.formatDescription(oAggregation.description);
468
+ oAggregation.deprecatedText = formatters.formatDeprecated(oAggregation.deprecated.since,
469
+ oAggregation.deprecated.text);
467
470
  } else {
468
471
  oAggregation.description = formatters.formatDescriptionSince(oAggregation.description, oAggregation.since);
469
472
  }
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * JSDoc3 plugin for UI5 documentation generation.
3
3
  *
4
- * (c) Copyright 2009-2023 SAP SE or an SAP affiliate company.
4
+ * (c) Copyright 2009-2024 SAP SE or an SAP affiliate company.
5
5
  * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
6
6
  */
7
7
 
@@ -21,7 +21,7 @@
21
21
  * experimental
22
22
  *
23
23
  * final
24
- *
24
+ *
25
25
  * hideconstructor
26
26
  *
27
27
  * interface
@@ -32,7 +32,7 @@
32
32
  *
33
33
  * ui5-restricted
34
34
  *
35
- *
35
+ *
36
36
  *
37
37
  * It furthermore listens to the following JSDoc3 events to implement additional functionality
38
38
  *
@@ -2137,7 +2137,7 @@ function createAutoDoc(oClassInfo, classComment, doclet, node, parser, filename,
2137
2137
  "",
2138
2138
  newStyle && info.doc ? info.doc : "",
2139
2139
  "",
2140
- "@returns {sap.ui.core.ID" + (info.cardinality === "0..n" ? "[]" : "") + "}",
2140
+ `@returns {${info.cardinality === "0..n" ? "sap.ui.core.ID[]" : "sap.ui.core.ID|null"}}`,
2141
2141
  info.since ? "@since " + info.since : "",
2142
2142
  info.deprecation ? "@deprecated " + info.deprecation : "",
2143
2143
  info.experimental ? "@experimental " + info.experimental : "",
@@ -2923,7 +2923,7 @@ exports.handlers = {
2923
2923
  };
2924
2924
  }
2925
2925
 
2926
- if ( doclet.kind === 'member' && doclet.isEnum && Array.isArray(doclet.properties) ) {
2926
+ if ( (doclet.kind === 'member' || doclet.kind === 'constant') && doclet.isEnum && Array.isArray(doclet.properties) ) {
2927
2927
  // determine unique enum identifier from key set
2928
2928
  let enumID = doclet.properties.map(function(prop) {
2929
2929
  return prop.name;
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * JSDoc3 template for UI5 documentation generation.
3
3
  *
4
- * (c) Copyright 2009-2023 SAP SE or an SAP affiliate company.
4
+ * (c) Copyright 2009-2024 SAP SE or an SAP affiliate company.
5
5
  * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
6
6
  */
7
7
 
@@ -89,6 +89,10 @@ function merge(target, source) {
89
89
  if ( source != null ) {
90
90
  // simple single source merge
91
91
  Object.keys(source).forEach((prop) => {
92
+ // guarding against prototype pollution. (https://codeql.github.com/codeql-query-help/javascript/js-prototype-pollution-utility/#example)
93
+ if (prop === "__proto__" || prop === "constructor") {
94
+ return;
95
+ }
92
96
  const value = source[prop];
93
97
  if ( value != null && value.constructor === Object ) {
94
98
  merge(target[prop] || {}, value);
@@ -169,7 +173,7 @@ function isModuleExport($) {
169
173
  }
170
174
 
171
175
  function isaClass($) {
172
- return /^(namespace|interface|class|typedef)$/.test($.kind) || ($.kind === 'member' && $.isEnum )/* isNonEmptyNamespace($) */;
176
+ return /^(namespace|interface|class|typedef)$/.test($.kind) || (($.kind === 'member' || $.kind === 'constant') && $.isEnum )/* isNonEmptyNamespace($) */;
173
177
  }
174
178
 
175
179
  function supportsInheritance($) {
@@ -187,7 +191,7 @@ function supportsInheritance($) {
187
191
  function isFirstClassSymbol($) {
188
192
  return (
189
193
  /^(namespace|interface|class|typedef)$/.test($.kind)
190
- || $.kind === 'member' && $.isEnum
194
+ || ($.kind === 'member' || $.kind === 'constant') && $.isEnum
191
195
  || ['function', 'member'].includes($.kind) && isModuleExport($)
192
196
  )/* isNonEmptyNamespace($) */;
193
197
  }
@@ -723,7 +727,7 @@ function getMembersOfKind(data, kind) {
723
727
  switch (kind) {
724
728
  case 'property':
725
729
  fnFilter = function($) {
726
- return $.kind === 'constant' || ($.kind === 'member' && !$.isEnum);
730
+ return ($.kind === 'constant' || $.kind === 'member') && !$.isEnum;
727
731
  };
728
732
  break;
729
733
  case 'event':
@@ -2030,7 +2034,7 @@ function createAPIJSON4Symbol(symbol, omitDefaults) {
2030
2034
  }
2031
2035
  */
2032
2036
 
2033
- const kind = (symbol.kind === 'member' && symbol.isEnum) ? "enum" : symbol.kind; // handle pseudo-kind 'enum'
2037
+ const kind = ((symbol.kind === 'member' || symbol.kind === 'constant') && symbol.isEnum) ? "enum" : symbol.kind; // handle pseudo-kind 'enum'
2034
2038
 
2035
2039
  tag(kind);
2036
2040
 
@@ -2118,7 +2122,13 @@ function createAPIJSON4Symbol(symbol, omitDefaults) {
2118
2122
  // secTags(symbol); // TODO repeat from class?
2119
2123
  closeTag("constructor");
2120
2124
 
2125
+ } else {
2126
+
2127
+ // even though the constructor is omitted here, the "hide" information is needed because in TypeScript it even exists when omitted
2128
+ attrib("hideconstructor", true, /* default */ false, /* raw */ true); // as boolean
2129
+
2121
2130
  }
2131
+
2122
2132
  } else if ( kind === 'namespace' ) {
2123
2133
  if ( symbol.__ui5.stereotype || symbol.__ui5.metadata ) {
2124
2134
  tag("ui5-metadata");
@@ -233,7 +233,11 @@ async function createManifest(
233
233
  if ( library.getDocumentation() ) {
234
234
  let desc = library.getDocumentation();
235
235
  // remove all tags
236
- desc = desc.replace(/\s+/g, " ").replace(/<\/?[a-zA-Z][a-zA-Z0-9_$.]*(\s[^>]*)>/g, "");
236
+ let prevDesc;
237
+ do { // Safely strip tags (https://codeql.github.com/codeql-query-help/javascript/js-incomplete-multi-character-sanitization/#example)
238
+ prevDesc = desc;
239
+ desc = desc.replace(/\s+/g, " ").replace(/<\/?[a-zA-Z][a-zA-Z0-9_$.]*(\s[^>]*)>/g, "");
240
+ } while (prevDesc !== desc);
237
241
  // extract summary (first sentence)
238
242
  const m = /^([\w\W]+?[.;!?])[^a-zA-Z0-9_$]/.exec(desc);
239
243
  return m ? m[1] : desc;
@@ -556,9 +560,11 @@ async function createManifest(
556
560
 
557
561
  const supportedLocalesArray = Array.from(supportedLocales);
558
562
  supportedLocalesArray.sort();
563
+
559
564
  return {
560
565
  bundleUrl: i18n,
561
- supportedLocales: supportedLocalesArray
566
+ supportedLocales: supportedLocalesArray,
567
+ fallbackLocale: supportedLocalesArray.length === 1 ? supportedLocalesArray[0] : undefined
562
568
  };
563
569
  }
564
570
 
@@ -83,15 +83,21 @@ export default async function({workspace, taskUtil, options = {}}) {
83
83
  if (allResources.length > 0) {
84
84
  const version = semver.coerce(await readManifestMinUI5Version());
85
85
  let hasFlexBundleVersion = false;
86
+ let flexBundle = {};
86
87
  if (semver.compare(version, "1.73.0") >= 0) {
87
88
  hasFlexBundleVersion = true;
89
+ const flexBundleResource = await workspace.byPath(`${pathPrefix}/changes/flexibility-bundle.json`);
90
+ if (flexBundleResource) {
91
+ flexBundle = JSON.parse(await flexBundleResource.getString());
92
+ }
88
93
  }
89
94
  const processedResources = await flexChangesBundler({
90
95
  resources: allResources,
91
96
  options: {
92
97
  pathPrefix,
93
98
  hasFlexBundleVersion
94
- }
99
+ },
100
+ existingFlexBundle: flexBundle
95
101
  });
96
102
  await Promise.all(processedResources.map((resource) => {
97
103
  log.verbose("Writing flexibility changes bundle");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ui5/builder",
3
- "version": "3.1.1",
3
+ "version": "3.3.0",
4
4
  "description": "UI5 Tooling - Builder",
5
5
  "author": {
6
6
  "name": "SAP SE",
@@ -47,7 +47,7 @@
47
47
  "jsdoc-watch": "npm run jsdoc && chokidar \"./lib/**/*.js\" -c \"npm run jsdoc-generate\"",
48
48
  "preversion": "npm test",
49
49
  "version": "git-chglog --sort semver --next-tag v$npm_package_version -o CHANGELOG.md v3.0.0.. && git add CHANGELOG.md",
50
- "postversion": "git push --follow-tags",
50
+ "prepublishOnly": "git push --follow-tags",
51
51
  "release-note": "git-chglog --sort semver -c .chglog/release-config.yml v$npm_package_version",
52
52
  "depcheck": "depcheck --ignores @ui5/builder,docdash,@istanbuljs/esm-loader-hook,catharsis --parsers='**/*.js:es6,**/*.cjs:es6'"
53
53
  },
@@ -131,26 +131,26 @@
131
131
  "pretty-data": "^0.40.0",
132
132
  "rimraf": "^5.0.5",
133
133
  "semver": "^7.5.4",
134
- "terser": "^5.24.0",
134
+ "terser": "^5.27.0",
135
135
  "workerpool": "^6.5.1",
136
136
  "xml2js": "^0.6.2"
137
137
  },
138
138
  "devDependencies": {
139
139
  "@istanbuljs/esm-loader-hook": "^0.2.0",
140
- "@jridgewell/trace-mapping": "^0.3.20",
141
- "@ui5/project": "^3.7.3",
140
+ "@jridgewell/trace-mapping": "^0.3.21",
141
+ "@ui5/project": "^3.9.0",
142
142
  "ava": "^5.3.1",
143
- "chai": "^4.3.10",
143
+ "chai": "^4.4.1",
144
144
  "chai-fs": "^2.0.0",
145
145
  "chokidar-cli": "^3.0.0",
146
146
  "cross-env": "^7.0.3",
147
147
  "depcheck": "^1.4.7",
148
148
  "docdash": "^2.0.2",
149
- "eslint": "^8.54.0",
149
+ "eslint": "^8.56.0",
150
150
  "eslint-config-google": "^0.14.0",
151
151
  "eslint-plugin-ava": "^14.0.0",
152
- "eslint-plugin-jsdoc": "^46.9.0",
153
- "esmock": "^2.6.0",
152
+ "eslint-plugin-jsdoc": "^46.10.1",
153
+ "esmock": "^2.6.2",
154
154
  "line-column": "^1.0.2",
155
155
  "nyc": "^15.1.0",
156
156
  "open-cli": "^7.2.0",