@ui5/builder 3.0.0-alpha.4 → 3.0.0-alpha.7

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +46 -1
  2. package/index.js +0 -39
  3. package/lib/lbt/analyzer/JSModuleAnalyzer.js +13 -2
  4. package/lib/lbt/bundle/Builder.js +18 -48
  5. package/lib/lbt/resources/LocatorResource.js +1 -1
  6. package/lib/lbt/resources/ResourceCollector.js +22 -15
  7. package/lib/lbt/resources/ResourceInfoList.js +0 -1
  8. package/lib/lbt/resources/ResourcePool.js +7 -6
  9. package/lib/lbt/utils/escapePropertiesFile.js +3 -6
  10. package/lib/processors/bundlers/moduleBundler.js +2 -3
  11. package/lib/processors/jsdoc/lib/transformApiJson.js +13 -4
  12. package/lib/processors/manifestCreator.js +8 -45
  13. package/lib/tasks/TaskUtil.js +82 -17
  14. package/lib/tasks/bundlers/generateComponentPreload.js +14 -14
  15. package/lib/tasks/bundlers/generateFlexChangesBundle.js +6 -2
  16. package/lib/tasks/bundlers/generateLibraryPreload.js +84 -91
  17. package/lib/tasks/bundlers/generateManifestBundle.js +8 -10
  18. package/lib/tasks/bundlers/generateStandaloneAppBundle.js +7 -2
  19. package/lib/tasks/bundlers/utils/createModuleNameMapping.js +3 -2
  20. package/lib/tasks/generateCachebusterInfo.js +7 -3
  21. package/lib/tasks/generateLibraryManifest.js +6 -8
  22. package/lib/tasks/generateResourcesJson.js +1 -1
  23. package/lib/tasks/generateThemeDesignerResources.js +118 -2
  24. package/lib/tasks/generateVersionInfo.js +5 -5
  25. package/lib/tasks/taskRepository.js +1 -13
  26. package/lib/tasks/transformBootstrapHtml.js +6 -1
  27. package/package.json +4 -5
  28. package/lib/builder/BuildContext.js +0 -60
  29. package/lib/builder/ProjectBuildContext.js +0 -61
  30. package/lib/builder/builder.js +0 -425
  31. package/lib/types/AbstractBuilder.js +0 -270
  32. package/lib/types/AbstractFormatter.js +0 -66
  33. package/lib/types/AbstractUi5Formatter.js +0 -95
  34. package/lib/types/application/ApplicationBuilder.js +0 -211
  35. package/lib/types/application/ApplicationFormatter.js +0 -227
  36. package/lib/types/application/applicationType.js +0 -15
  37. package/lib/types/library/LibraryBuilder.js +0 -232
  38. package/lib/types/library/LibraryFormatter.js +0 -519
  39. package/lib/types/library/libraryType.js +0 -15
  40. package/lib/types/module/ModuleBuilder.js +0 -7
  41. package/lib/types/module/ModuleFormatter.js +0 -54
  42. package/lib/types/module/moduleType.js +0 -15
  43. package/lib/types/themeLibrary/ThemeLibraryBuilder.js +0 -64
  44. package/lib/types/themeLibrary/ThemeLibraryFormatter.js +0 -90
  45. package/lib/types/themeLibrary/themeLibraryType.js +0 -15
  46. package/lib/types/typeRepository.js +0 -46
package/CHANGELOG.md CHANGED
@@ -2,7 +2,49 @@
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.0.0-alpha.4...HEAD).
5
+ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-builder/compare/v3.0.0-alpha.7...HEAD).
6
+
7
+ <a name="v3.0.0-alpha.7"></a>
8
+ ## [v3.0.0-alpha.7] - 2022-06-14
9
+ ### Breaking Changes
10
+ - Remove build execution ([#740](https://github.com/SAP/ui5-builder/issues/740)) [`af2e956`](https://github.com/SAP/ui5-builder/commit/af2e956f6cba1275669160328e32df3fffa782d0)
11
+
12
+ ### Bug Fixes
13
+ - Avoid redundant bundle creation ([#741](https://github.com/SAP/ui5-builder/issues/741)) [`13c8405`](https://github.com/SAP/ui5-builder/commit/13c840585946401d238936dfa38a6f70a73e9ed0)
14
+
15
+ ### Features
16
+ - Enable modern preload bundles without dependencies ([#739](https://github.com/SAP/ui5-builder/issues/739)) [`97cfa6c`](https://github.com/SAP/ui5-builder/commit/97cfa6cd3eadff57bcc18816534c7751551ebdb8)
17
+
18
+ ### BREAKING CHANGE
19
+
20
+ * builder.js has been removed. Use ui5-project builder instead
21
+ * Tasks now rely on Project instances being available on Resources (see https://github.com/SAP/ui5-fs/pull/381)
22
+ * TaskRepository#addTask has been removed. Custom tasks need to be added to the project graph instead
23
+ * TaskUtil#get/set/clearTag now requires a Project instance to be provided. Path strings are no longer sufficient
24
+ and will cause an exception to be thrown
25
+
26
+
27
+ <a name="v3.0.0-alpha.6"></a>
28
+ ## [v3.0.0-alpha.6] - 2022-04-26
29
+ ### Bug Fixes
30
+ - **JSModuleAnalyzer:** Fix detection of bundle name ([#705](https://github.com/SAP/ui5-builder/issues/705)) [`aaeafd4`](https://github.com/SAP/ui5-builder/commit/aaeafd4a1fd194dd08e5ae47c29d90f0b4c7d197)
31
+ - **generateResourcesJson:** Add raw-module info for debug bundles ([#736](https://github.com/SAP/ui5-builder/issues/736)) [`3b918e8`](https://github.com/SAP/ui5-builder/commit/3b918e83bfd38342778ecd4c58e648e99ad7cffc)
32
+
33
+
34
+ <a name="v3.0.0-alpha.5"></a>
35
+ ## [v3.0.0-alpha.5] - 2022-04-14
36
+ ### Bug Fixes
37
+ - **LibraryBuilder:** Align task order of "generateComponentPreload" [`aea061d`](https://github.com/SAP/ui5-builder/commit/aea061d9d6c2ac0c11484dcc08bdcda23ab62986)
38
+
39
+ ### Features
40
+ - **generateThemeDesignerResources task:** Create css_variables.less ([#730](https://github.com/SAP/ui5-builder/issues/730)) [`34e69be`](https://github.com/SAP/ui5-builder/commit/34e69be95fc8ec1961b24b7e2580c2c993d814d3)
41
+
42
+ ### BREAKING CHANGE
43
+
44
+ For library projects, the task "generateComponentPreload" is now
45
+ executed after tasks "generateLibraryManifest" and
46
+ "generateManifestBundle" instead of before them.
47
+
6
48
 
7
49
  <a name="v3.0.0-alpha.4"></a>
8
50
  ## [v3.0.0-alpha.4] - 2022-04-05
@@ -699,6 +741,9 @@ to load the custom bundle file instead.
699
741
  - Add ability to configure component preloads and custom bundles [`2241e5f`](https://github.com/SAP/ui5-builder/commit/2241e5ff98fd95f1f80cc74959655ae7a9c660e7)
700
742
 
701
743
 
744
+ [v3.0.0-alpha.7]: https://github.com/SAP/ui5-builder/compare/v3.0.0-alpha.6...v3.0.0-alpha.7
745
+ [v3.0.0-alpha.6]: https://github.com/SAP/ui5-builder/compare/v3.0.0-alpha.5...v3.0.0-alpha.6
746
+ [v3.0.0-alpha.5]: https://github.com/SAP/ui5-builder/compare/v3.0.0-alpha.4...v3.0.0-alpha.5
702
747
  [v3.0.0-alpha.4]: https://github.com/SAP/ui5-builder/compare/v3.0.0-alpha.3...v3.0.0-alpha.4
703
748
  [v3.0.0-alpha.3]: https://github.com/SAP/ui5-builder/compare/v3.0.0-alpha.2...v3.0.0-alpha.3
704
749
  [v3.0.0-alpha.2]: https://github.com/SAP/ui5-builder/compare/v3.0.0-alpha.1...v3.0.0-alpha.2
package/index.js CHANGED
@@ -3,10 +3,6 @@
3
3
  * @public
4
4
  */
5
5
  module.exports = {
6
- /**
7
- * @type {import('./lib/builder/builder')}
8
- */
9
- builder: "./lib/builder/builder",
10
6
  /**
11
7
  * @public
12
8
  * @alias module:@ui5/builder.processors
@@ -160,41 +156,6 @@ module.exports = {
160
156
  * @type {import('./lib/tasks/TaskUtil')}
161
157
  */
162
158
  TaskUtil: "./lib/tasks/TaskUtil"
163
- },
164
- /**
165
- * @private
166
- * @alias module:@ui5/builder.types
167
- * @namespace
168
- */
169
- types: {
170
- /**
171
- * @type {typeof import('./lib/types/AbstractBuilder')}
172
- */
173
- AbstractBuilder: "./lib/types/AbstractBuilder",
174
- /**
175
- * @type {typeof import('./lib/types/AbstractFormatter')}
176
- */
177
- AbstractFormatter: "./lib/types/AbstractFormatter",
178
- /**
179
- * @type {import('./lib/types/application/applicationType')}
180
- */
181
- application: "./lib/types/application/applicationType",
182
- /**
183
- * @type {import('./lib/types/library/libraryType')}
184
- */
185
- library: "./lib/types/library/libraryType",
186
- /**
187
- * @type {import('./lib/types/themeLibrary/themeLibraryType')}
188
- */
189
- themeLibrary: "./lib/types/themeLibrary/themeLibraryType",
190
- /**
191
- * @type {import('./lib/types/module/moduleType')}
192
- */
193
- module: "./lib/types/module/moduleType",
194
- /**
195
- * @type {import('./lib/types/typeRepository')}
196
- */
197
- typeRepository: "./lib/types/typeRepository"
198
159
  }
199
160
  };
200
161
 
@@ -301,6 +301,9 @@ class JSModuleAnalyzer {
301
301
  */
302
302
  let bIsUi5Module = false;
303
303
 
304
+ // Module name via @ui5-bundle comment in first line. Overrides all other main module candidates.
305
+ let firstLineBundleName;
306
+
304
307
  // first analyze the whole AST...
305
308
  visit(ast, false);
306
309
 
@@ -314,7 +317,12 @@ class JSModuleAnalyzer {
314
317
  log.verbose(`bundle include directive ${subModule}`);
315
318
  } else if ( comment.value.startsWith("@ui5-bundle ") ) {
316
319
  const bundleName = comment.value.slice("@ui5-bundle ".length);
317
- setMainModuleInfo(bundleName, null);
320
+ if (comment.start === 0) {
321
+ // Remember the name from the first line to use it as final name
322
+ firstLineBundleName = bundleName;
323
+ } else {
324
+ setMainModuleInfo(bundleName, null);
325
+ }
318
326
  log.verbose(`bundle name directive ${bundleName}`);
319
327
  } else {
320
328
  log.warn(`unrecognized bundle directive ${comment.value}`);
@@ -324,7 +332,10 @@ class JSModuleAnalyzer {
324
332
  }
325
333
 
326
334
  // ...and finally take conclusions about the file's content
327
- if ( !mainModuleFound ) {
335
+ if ( firstLineBundleName ) {
336
+ // If the first line has a bundle name, use it and override all other found names
337
+ info.name = firstLineBundleName;
338
+ } else if ( !mainModuleFound ) {
328
339
  // if there's exactly one module definition in this file but it didn't
329
340
  // immediately qualify as main module, make it now the main module
330
341
  if ( candidateName != null && nModuleDeclarations == 1 ) {
@@ -40,38 +40,6 @@ function isEmptyBundle(resolvedBundle) {
40
40
  return resolvedBundle.sections.every((section) => section.modules.length === 0);
41
41
  }
42
42
 
43
- const UI5BundleFormat = {
44
- beforePreloads(section) {
45
- let str = `jQuery.sap.registerPreloadedModules({\n`;
46
- if ( section.name ) {
47
- str += `"name":"${section.name}",\n`;
48
- }
49
- str += `"version":"2.0",\n`;
50
- str += `"modules":{\n`;
51
- return str;
52
- },
53
-
54
- afterPreloads(section) {
55
- return `}});\n`;
56
- },
57
-
58
- beforeBundleInfo() {
59
- return `"unsupported"; /* 'bundleInfo' section mode not supported (requires ui5loader)\n`;
60
- },
61
-
62
- afterBundleInfo() {
63
- return "*/\n";
64
- },
65
-
66
- requireSync(moduleName) {
67
- return `sap.ui.requireSync("${ModuleName.toRequireJSName(moduleName)}");\n`;
68
- },
69
-
70
- shouldDecorate(resolvedModule) {
71
- return resolvedModule.executes(UI5ClientConstants.MODULE__JQUERY_SAP_GLOBAL);
72
- }
73
- };
74
-
75
43
  const EVOBundleFormat = {
76
44
  beforePreloads(section) {
77
45
  return `sap.ui.require.preload({\n`;
@@ -115,7 +83,6 @@ class BundleBuilder {
115
83
  }
116
84
 
117
85
  async createBundle(module, options) {
118
- await this._prepare();
119
86
  if ( options.numberOfParts > 1 ) {
120
87
  const bundleInfos = [];
121
88
  const submodules = await this.splitter.run( module, options );
@@ -128,17 +95,6 @@ class BundleBuilder {
128
95
  }
129
96
  }
130
97
 
131
- _prepare() {
132
- return Promise.all([
133
- // check whether the resource pool contains debug and optimized sources
134
- this.pool.findResource( ModuleName.getDebugName(UI5ClientConstants.MODULE__JQUERY_SAP_GLOBAL) ).
135
- then( () => this.optimizedSources = true, () => this.optimizedSources = false ),
136
- // check whether EVO modules are available. If so, use EVO APIs, else use old UI5 APIs.
137
- this.pool.findResource(UI5ClientConstants.EVO_MARKER_RESOURCE).
138
- then( () => this.targetBundleFormat = EVOBundleFormat, () => this.targetBundleFormat = UI5BundleFormat )
139
- ]);
140
- }
141
-
142
98
  async _createBundle(module, options) {
143
99
  const resolvedModule = await this.resolver.resolve(module);
144
100
  if ( options.skipIfEmpty && isEmptyBundle(resolvedModule) ) {
@@ -153,11 +109,13 @@ class BundleBuilder {
153
109
  this.options.sourceMap = true;
154
110
  }
155
111
 
156
- // when decorateBootstrapModule is set to false, we don't write the optimized flag
157
- // and don't write the try catch wrapper
112
+ // Since UI5 Tooling 3.0: Always use modern API
113
+ this.targetBundleFormat = EVOBundleFormat;
114
+
115
+ // when decorateBootstrapModule is false,
116
+ // we don't write the optimized flag and don't write the try catch wrapper
158
117
  this.shouldDecorate = this.options.decorateBootstrapModule &&
159
- (((this.optimizedSources && !this.options.debugMode) || this.optimize) &&
160
- this.targetBundleFormat.shouldDecorate(resolvedModule));
118
+ this.targetBundleFormat.shouldDecorate(resolvedModule);
161
119
  // TODO is the following condition ok or should the availability of jquery.sap.global.js be configurable?
162
120
  this.jqglobalAvailable = !resolvedModule.containsGlobal;
163
121
  this.openModule(resolvedModule.name);
@@ -636,6 +594,18 @@ class BundleBuilder {
636
594
 
637
595
  if (moduleSourceMap) {
638
596
  moduleSourceMap = JSON.parse(moduleSourceMap);
597
+
598
+ // Check for index map, which is currently not supported
599
+ if (Array.isArray(moduleSourceMap.sections)) {
600
+ log.warn(
601
+ `Module ${moduleName} references an index source map which is currently not supported. ` +
602
+ `A transient source map will be created instead...`
603
+ );
604
+ moduleSourceMap = createTransientSourceMap({
605
+ moduleName: path.posix.basename(resourcePath),
606
+ moduleContent
607
+ });
608
+ }
639
609
  } else {
640
610
  log.verbose(`No source map available for module ${moduleName}. Creating transient source map...`);
641
611
  moduleSourceMap = createTransientSourceMap({
@@ -11,7 +11,7 @@ class LocatorResource extends Resource {
11
11
  }
12
12
 
13
13
  getProject() {
14
- return this.resource._project;
14
+ return this.resource.getProject();
15
15
  }
16
16
 
17
17
  getPath() {
@@ -110,10 +110,11 @@ class ResourceCollector {
110
110
  }
111
111
 
112
112
  async enrichWithDependencyInfo(resourceInfo) {
113
- return this._pool.getModuleInfo(resourceInfo.name).then(async (moduleInfo) => {
114
- if ( moduleInfo.name ) {
113
+ return this._pool.getModuleInfo(resourceInfo.name, resourceInfo.module).then(async (moduleInfo) => {
114
+ if ( !resourceInfo.module && moduleInfo.name ) {
115
115
  resourceInfo.module = moduleInfo.name;
116
116
  }
117
+
117
118
  if ( moduleInfo.dynamicDependencies ) {
118
119
  resourceInfo.dynRequired = true;
119
120
  }
@@ -279,37 +280,43 @@ class ResourceCollector {
279
280
 
280
281
  await Promise.all(promises);
281
282
 
282
- const debugBundlePromises = [];
283
-
284
- for (let i = debugResourcesInfo.length - 1; i >= 0; i--) {
285
- const dbgInfo = debugResourcesInfo[i];
286
- const nonDebugName = ResourceInfoList.getNonDebugName(dbgInfo.name);
283
+ await Promise.all(debugResourcesInfo.map(async (dbgInfo) => {
284
+ const debugName = dbgInfo.name;
285
+ const nonDebugName = ResourceInfoList.getNonDebugName(debugName);
287
286
  const nonDbgInfo = this._resources.get(nonDebugName);
288
287
 
289
288
  // FIXME: "merged" property is only calculated in ResourceInfo#copyFrom
290
289
  // Therefore using the same logic here to compute it.
290
+
291
+ // TODO: Idea: Use IsDebugVariant tag to decide whether to analyze the resource
292
+ // If the tag is set, we don't expect different analysis results so we can copy the info (else-path)
293
+ // Only when the tag is not set, we analyze the resource with its name (incl. -dbg)
294
+
291
295
  if (!nonDbgInfo || (nonDbgInfo.included != null && nonDbgInfo.included.size > 0)) {
292
296
  // We need to analyze the dbg resource if there is no non-dbg variant or
293
297
  // it is a bundle because we will (usually) have different content.
294
- debugBundlePromises.push(
295
- this.enrichWithDependencyInfo(dbgInfo)
296
- );
298
+
299
+ if (nonDbgInfo) {
300
+ // Always use the non-debug module name, if available
301
+ dbgInfo.module = nonDbgInfo.module;
302
+ }
303
+ await this.enrichWithDependencyInfo(dbgInfo);
297
304
  } else {
298
305
  // If the non-dbg resource is not a bundle, we can just copy over the info and skip
299
306
  // analyzing the dbg variant as both should have the same info.
300
307
 
301
- const newDbgInfo = new ResourceInfo(dbgInfo.name);
308
+ const newDbgInfo = new ResourceInfo(debugName);
302
309
 
303
310
  // First copy info of analysis from non-dbg file (included, required, condRequired, ...)
304
311
  newDbgInfo.copyFrom(null, nonDbgInfo);
305
312
  // Then copy over info from dbg file to properly set name, isDebug, etc.
306
313
  newDbgInfo.copyFrom(null, dbgInfo);
314
+ // Finally, set the module name to the non-dbg name
315
+ newDbgInfo.module = nonDbgInfo.module;
307
316
 
308
- this._resources.set(dbgInfo.name, newDbgInfo);
317
+ this._resources.set(debugName, newDbgInfo);
309
318
  }
310
- }
311
-
312
- await Promise.all(debugBundlePromises);
319
+ }));
313
320
  }
314
321
 
315
322
  createOrphanFilters() {
@@ -48,7 +48,6 @@ class ResourceInfoList {
48
48
  if ( myInfo == null ) {
49
49
  myInfo = new ResourceInfo(relativeName);
50
50
  myInfo.size = info.size;
51
- myInfo.module = ResourceInfoList.getNonDebugName(info.name);
52
51
  this.resources.push(myInfo);
53
52
  this.resourcesByName.set(relativeName, myInfo);
54
53
  }
@@ -176,17 +176,18 @@ class ResourcePool {
176
176
  /**
177
177
  * Retrieves the module info
178
178
  *
179
- * @param {string} name module name
179
+ * @param {string} resourceName resource/module name
180
+ * @param {string} [moduleName] module name, in case it differs from the resource name (e.g. for -dbg resources)
180
181
  * @returns {Promise<ModuleInfo>}
181
182
  */
182
- async getModuleInfo(name) {
183
- let info = this._dependencyInfos.get(name);
183
+ async getModuleInfo(resourceName, moduleName) {
184
+ let info = this._dependencyInfos.get(resourceName);
184
185
  if ( info == null ) {
185
186
  info = Promise.resolve().then(async () => {
186
- const resource = await this.findResource(name);
187
- return determineDependencyInfo( resource, this._rawModuleInfos.get(name), this );
187
+ const resource = await this.findResource(resourceName);
188
+ return determineDependencyInfo( resource, this._rawModuleInfos.get(moduleName || resourceName), this );
188
189
  });
189
- this._dependencyInfos.set(name, info);
190
+ this._dependencyInfos.set(resourceName, info);
190
191
  }
191
192
  return info;
192
193
  }
@@ -4,7 +4,7 @@ const nonAsciiEscaper = require("../../processors/nonAsciiEscaper");
4
4
  * Can be used to escape *.properties files.
5
5
  *
6
6
  * Input encoding is read from project configuration.
7
- * In case the resource belongs to no project (e.g. bundler is used standalone) the default is "ISO-8859-1".
7
+ * In case the resource belongs to no project (e.g. bundler is used standalone) the default is "UTF-8".
8
8
  *
9
9
  * @private
10
10
  * @param {Resource} resource the resource for which the content will be escaped
@@ -12,13 +12,10 @@ const nonAsciiEscaper = require("../../processors/nonAsciiEscaper");
12
12
  */
13
13
  module.exports = async function(resource) {
14
14
  const project = resource.getProject();
15
- let propertiesFileSourceEncoding = project &&
16
- project.resources &&
17
- project.resources.configuration &&
18
- project.resources.configuration.propertiesFileSourceEncoding;
15
+ let propertiesFileSourceEncoding = project && project.getPropertiesFileSourceEncoding();
19
16
 
20
17
  if (!propertiesFileSourceEncoding) {
21
- if (project && ["0.1", "1.0", "1.1"].includes(project.specVersion)) {
18
+ if (project && ["0.1", "1.0", "1.1"].includes(project.getSpecVersion())) {
22
19
  // default encoding to "ISO-8859-1" for old specVersions
23
20
  propertiesFileSourceEncoding = "ISO-8859-1";
24
21
  } else {
@@ -91,9 +91,9 @@ const log = require("@ui5/logger").getLogger("builder:processors:bundlers:module
91
91
  * @typedef {object} ModuleBundleOptions
92
92
  * @property {boolean} [optimize=true] Whether the module bundle gets minified
93
93
  * @property {boolean} [sourceMap=true] Whether to generate a source map file for the bundle
94
- * @property {boolean} [decorateBootstrapModule=false] If set to 'false', the module won't be decorated
94
+ * @property {boolean} [decorateBootstrapModule=false] If set to 'false', bootable bundles won't be decorated
95
95
  * with an optimization marker
96
- * @property {boolean} [addTryCatchRestartWrapper=false] Whether to wrap bootable module bundles with
96
+ * @property {boolean} [addTryCatchRestartWrapper=false] Whether to wrap bootable bundles with
97
97
  * a try/catch to filter out "Restart" errors
98
98
  * @property {boolean} [usePredefineCalls=false] If set to 'true', sap.ui.predefine is used for UI5 modules
99
99
  * @property {number} [numberOfParts=1] The number of parts the module bundle should be splitted
@@ -148,7 +148,6 @@ module.exports = function({resources, options: {bundleDefinition, bundleOptions,
148
148
  log.verbose(`bundleDefinition: ${JSON.stringify(bundleDefinition, null, 2)}`);
149
149
  log.verbose(`bundleOptions: ${JSON.stringify(bundleOptions, null, 2)}`);
150
150
  }
151
-
152
151
  return pool.prepare( resources, moduleNameMapping ).
153
152
  then( () => builder.createBundle(bundleDefinition, bundleOptions) ).
154
153
  then( (results) => {
@@ -1386,13 +1386,16 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
1386
1386
 
1387
1387
  },
1388
1388
 
1389
+ formatUrlToLink: function(sTarget, sText, bSAPHosted){
1390
+ return `<a target="_blank" rel="noopener noreferrer" href="${sTarget}">${sText}</a>
1391
+ <img src="./resources/sap/ui/documentation/sdk/images/${bSAPHosted ? 'link-sap' : 'link-external'}.png"
1392
+ title="Information published on ${bSAPHosted ? '' : 'non '}SAP site" class="sapUISDKExternalLink"/>`;
1393
+ },
1394
+
1389
1395
  handleExternalUrl: function (sTarget, sText) {
1390
1396
  // Check if the external domain is SAP hosted
1391
1397
  let bSAPHosted = /^https?:\/\/([\w.]*\.)?(?:sap|hana\.ondemand|sapfioritrial)\.com/.test(sTarget);
1392
-
1393
- return `<a target="_blank" rel="noopener noreferrer" href="${sTarget}">${sText}</a>
1394
- <img src="./resources/sap/ui/documentation/sdk/images/${bSAPHosted ? 'link-sap' : 'link-external'}.png"
1395
- title="Information published on ${bSAPHosted ? '' : 'non '}SAP site" class="sapUISDKExternalLink"/>`;
1398
+ return this.formatUrlToLink(sTarget, sText, bSAPHosted);
1396
1399
  },
1397
1400
 
1398
1401
  /**
@@ -1599,6 +1602,12 @@ title="Information published on ${bSAPHosted ? '' : 'non '}SAP site" class="sapU
1599
1602
  return '<a target="_self" href="topic/' + aMatch[1] + '">' + sText + '</a>';
1600
1603
  }
1601
1604
 
1605
+ // demo:xxx Demo, open the demonstration page in a new window
1606
+ aMatch = sTarget.match(/^demo:([a-zA-Z0-9\/.]*)$/);
1607
+ if (aMatch) {
1608
+ return this.formatUrlToLink("test-resources/" + aMatch[1], sText, true);
1609
+ }
1610
+
1602
1611
  // sap.x.Xxx.prototype.xxx - In case of prototype we have a link to method
1603
1612
  aMatch = sTarget.match(/([a-zA-Z0-9.$_]+?)\.prototype\.([a-zA-Z0-9.$_]+)$/);
1604
1613
  if (aMatch) {
@@ -157,7 +157,9 @@ class LibraryBundle {
157
157
  /*
158
158
  * Creates the library manifest.json file for a UILibrary.
159
159
  */
160
- async function createManifest(libraryResource, libBundle, descriptorVersion, _include3rdParty, omitMinVersions) {
160
+ async function createManifest(
161
+ libraryResource, libBundle, descriptorVersion, _include3rdParty, omitMinVersions, getProjectVersion
162
+ ) {
161
163
  // create a Library wrapper around the .library XML
162
164
  const library = await Library.from(libraryResource);
163
165
 
@@ -223,13 +225,6 @@ async function createManifest(libraryResource, libBundle, descriptorVersion, _in
223
225
  return version && version !== "@version@" && version !== "${version}";
224
226
  }
225
227
 
226
- function getProjectVersion() {
227
- const project = libraryResource._project;
228
- if ( project ) {
229
- return project.version;
230
- }
231
- }
232
-
233
228
  function getLibraryTitle() {
234
229
  if ( library.getTitle() ) {
235
230
  return library.getTitle();
@@ -321,7 +316,7 @@ async function createManifest(libraryResource, libBundle, descriptorVersion, _in
321
316
  embeds: findEmbeddedComponents(),
322
317
  i18n,
323
318
  applicationVersion: {
324
- version: isValid(library.getVersion()) ? library.getVersion() : getProjectVersion()
319
+ version: isValid(library.getVersion()) ? library.getVersion() : getProjectVersion(library.getName())
325
320
  },
326
321
  title: getLibraryTitle(),
327
322
  description: library.getDocumentation(),
@@ -393,12 +388,7 @@ async function createManifest(libraryResource, libBundle, descriptorVersion, _in
393
388
 
394
389
  function createSapUI5() {
395
390
  function getUI5Version() {
396
- const dummy = new Dependency({
397
- libraryName: [{
398
- _: "sap.ui.core"
399
- }]
400
- });
401
- return normalizeVersion(getVersion(dummy));
391
+ return normalizeVersion(getProjectVersion("sap.ui.core"));
402
392
  }
403
393
 
404
394
  function dependencies() {
@@ -410,7 +400,7 @@ async function createManifest(libraryResource, libBundle, descriptorVersion, _in
410
400
  if ( library.getDependencies() != null ) {
411
401
  for (const dep of library.getDependencies()) {
412
402
  dependencies.libs[dep.getLibraryName()] = {
413
- minVersion: omitMinVersions ? "" : getVersion(dep),
403
+ minVersion: omitMinVersions ? "" : getProjectVersion(dep.getLibraryName()),
414
404
  lazy: dep.isLazy() || undefined // suppress default (false)
415
405
  };
416
406
  }
@@ -619,33 +609,6 @@ async function createManifest(libraryResource, libBundle, descriptorVersion, _in
619
609
  return v.major + "." + v.minor;
620
610
  }
621
611
 
622
- function getVersion(dependency) {
623
- const version = dependency.getVersion();
624
- if ( version != null ) {
625
- return version;
626
- }
627
-
628
- function hasName(entity) {
629
- return entity.metadata && entity.metadata.name === dependency.getLibraryName();
630
- }
631
-
632
- const project = libraryResource._project;
633
- if ( project ) {
634
- if ( Array.isArray(project.dependencies) ) {
635
- const lib = project.dependencies.find(hasName);
636
- if ( lib ) {
637
- return lib.version;
638
- }
639
- }
640
- if ( hasName(project) ) {
641
- return project.version;
642
- }
643
- }
644
-
645
- throw new Error(
646
- `Couldn't find version for library '${dependency.getLibraryName()}', project dependency missing?`);
647
- }
648
-
649
612
  return {
650
613
  "_version": descriptorVersion.toString(),
651
614
  "sap.app": createSapApp(),
@@ -657,7 +620,7 @@ async function createManifest(libraryResource, libBundle, descriptorVersion, _in
657
620
  };
658
621
  }
659
622
 
660
- module.exports = function({libraryResource, resources, options}) {
623
+ module.exports = function({libraryResource, resources, getProjectVersion, options}) {
661
624
  // merge options with defaults
662
625
  options = Object.assign({
663
626
  descriptorVersion: APP_DESCRIPTOR_V22, // TODO 3.0: change this to type string instead of a semver object
@@ -677,7 +640,7 @@ module.exports = function({libraryResource, resources, options}) {
677
640
  }
678
641
 
679
642
  return createManifest(libraryResource, libBundle, options.descriptorVersion, options.include3rdParty,
680
- options.omitMinVersions)
643
+ options.omitMinVersions, getProjectVersion)
681
644
  .then((manifest) => {
682
645
  return new EvoResource({
683
646
  path: resourcePathPrefix + "manifest.json",